pax_global_header00006660000000000000000000000064146432771260014526gustar00rootroot0000000000000052 comment=2b2d2ca103e016bcdb2a1c5a6c500593b9b195aa eureka-editor-eureka-2.0.2/000077500000000000000000000000001464327712600155415ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/.github/000077500000000000000000000000001464327712600171015ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/.github/workflows/000077500000000000000000000000001464327712600211365ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/.github/workflows/codeql-analysis.yml000066400000000000000000000054541464327712600247610ustar00rootroot00000000000000# For most projects, this workflow file will not need changing; you simply need # to commit it to your repository. # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. # # ******** NOTE ******** # We have attempted to detect the languages in your repository. Please check # the `language` matrix defined below to confirm you have the correct set of # supported CodeQL languages. # name: "CodeQL" on: push: branches: [ "master" ] pull_request: # The branches below must be a subset of the branches above branches: [ "master" ] schedule: - cron: '44 11 * * 4' jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ 'cpp', 'python' ] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support steps: - name: Checkout repository uses: actions/checkout@v3 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs # queries: security-extended,security-and-quality # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) # - name: Autobuild # uses: github/codeql-action/autobuild@v2 # ℹ️ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun # If the Autobuild fails above, remove it and uncomment the following three lines. # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. - run: sudo apt-get update && sudo apt-get install --fix-missing cmake libfltk1.3-dev libxpm-dev libz-dev python3 && mkdir build && cd build && cmake .. && make -j$(nproc) - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 with: category: "/language:${{matrix.language}}" eureka-editor-eureka-2.0.2/.github/workflows/ubuntu-compile-clang.yml000066400000000000000000000010741464327712600257150ustar00rootroot00000000000000name: C/C++ CI clang on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install Dependencies run: sudo apt-get update && sudo apt-get install --fix-missing clang cmake libfltk1.3-dev libxpm-dev libz-dev python3 - name: CMake run: export CC=/usr/bin/clang && export CXX=/usr/bin/clang++ && mkdir build-clang && cd build-clang && cmake .. && make -j$(nproc) - name: Test run: cd build-clang && ctest --output-on-failure eureka-editor-eureka-2.0.2/.github/workflows/ubuntu-compile.yml000066400000000000000000000007471464327712600246410ustar00rootroot00000000000000name: C/C++ CI gcc on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install Dependencies run: sudo apt-get update && sudo apt-get install --fix-missing cmake libfltk1.3-dev libxpm-dev libz-dev python3 - name: CMake run: mkdir build && cd build && cmake .. && make -j$(nproc) - name: Test run: cd build && ctest --output-on-failure eureka-editor-eureka-2.0.2/.gitignore000066400000000000000000000010401464327712600175240ustar00rootroot00000000000000/eureka Eureka.exe lib_win32 obj_win32 obj_linux _work WIP.txt # OS X stuff .DS_Store .DS_Store? ._* .Spotlight-V100 .Trashes ehthumbs.db Thumbs.db osx/Eureka Doom Editor.xcodeproj/project.xcworkspace/xcuserdata osx/Eureka Doom Editor.xcodeproj/xcuserdata osx/staticlib .vscode/ build/ prereqs/ osx/Eureka-Tests/Eureka-Tests.xcodeproj/project.xcworkspace/xcuserdata osx/Eureka-Tests/Eureka-Tests.xcodeproj/xcuserdata *.vcxproj.user .vs/ Debug/ win/Eureka/Release/ build2/ src/main.aps htdocs-ORIGINAL/ htdocs-OUTPUT/ build-intel venv htdocs eureka-editor-eureka-2.0.2/AUTHORS.md000066400000000000000000000032561464327712600172160ustar00rootroot00000000000000# CREDITS ## Creator Andrew Apted  I created this Doom map editor (based on an existing program) and developed it up to version 1.27. No longer active with the project. ## Developer Ioan Chera Ported the program to macOS, and is the current lead developer of the project. ## Contributors Fabian Greffrath * Debian packager Wesley Werner * User Manual Jason R. Johnston ([fiftyoars.com](fiftyoars.com)) * Eureka Logo Wesley Johnson * Doom Legacy definition file ## Earlier Work André Majorel created the [Yadex](http://www.teaser.fr/~amajorel/yadex/) editor. Eureka began as a fork of this editor, version 1.7.0 to be precise. Raphael Quinet and Brendon Wyber created DEU 5.21, which Yadex was derived from. Both Yadex and DEU had many contributors, a comprehensive list of them can be found in the Yadex documentation. ## Acknowledgements Eureka uses the [FLTK widget library](http://www.fltk.org). ## COPYRIGHT and LICENSE ``` Eureka DOOM Editor Copyright (C) 2014-2024 Ioan Chera Copyright (C) 2001-2020 Andrew Apted, et al Copyright (C) 1997-2003 Andre Majorel, et al Eureka is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Eureka is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ``` See [GNU General Public License](http://www.gnu.org/licenses/gpl.html) for the full text. eureka-editor-eureka-2.0.2/CMakeLists.txt000066400000000000000000000170471464327712600203120ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.13) set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "Minimum OS X deployment version") project(eureka-editor VERSION 2.0.2) # Why not use the latest C++ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED True) add_compile_definitions(_CRT_SECURE_NO_WARNINGS) # https://stackoverflow.com/a/66401708/11738219 function(add_path_resource target folder) file(GLOB_RECURSE resources "${CMAKE_CURRENT_SOURCE_DIR}/${folder}/*") target_sources(${target} PRIVATE ${resources}) foreach(resfile ${resources}) #Get the relative path from the data-folder to the particular file file(RELATIVE_PATH newfile "${CMAKE_CURRENT_SOURCE_DIR}/${folder}" ${resfile}) get_filename_component(newfilepath ${newfile} DIRECTORY) #Set its location inside the app package (under Resources) set_property(SOURCE ${resfile} PROPERTY MACOSX_PACKAGE_LOCATION "Resources/${folder}/${newfilepath}") endforeach() source_group("eureka-res-clutter" FILES ${resources}) endfunction() set(resource_common_dirs common games ports) set(resource_common_cfgs bindings.cfg defaults.cfg operations.cfg) set(resource_common_files ${resource_common_cfgs} misc/about_logo.png) set(resource_common ${resource_common_dirs} ${resource_common_files}) source_group("eureka-res" FILES ${resource_common}) set_source_files_properties(${resource_common} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) # This is the main program. MACOSX_BUNDLE is needed for Mac, dummywin for Windows add_executable(eureka MACOSX_BUNDLE ${resource_common} win/dummywin.cpp) foreach(dir ${resource_common_dirs}) add_path_resource(eureka common) add_path_resource(eureka games) add_path_resource(eureka ports) endforeach() if(WIN32) configure_file(src/main.rc.in src/main.rc) target_sources(eureka PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src/main.rc) set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT eureka) list(TRANSFORM resource_common_cfgs PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/") add_custom_command( TARGET eureka POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${resource_common_cfgs} $ ) foreach(dir ${resource_common_dirs}) add_custom_command( TARGET eureka POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/${dir}" "$/${dir}" ) endforeach() add_custom_command( TARGET eureka POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/misc/about_logo.png" "$/common" ) endif() if(NOT APPLE) target_sources(eureka PRIVATE mainroot.cc) endif() if(APPLE) set(exe_display_name "Eureka Doom Editor") set_target_properties(eureka PROPERTIES OUTPUT_NAME "${exe_display_name}") add_subdirectory(osx) target_link_libraries(eureka eurekamac) set_source_files_properties(${resource_mac} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) target_sources(eureka PRIVATE ${resource_mac}) # Use the same warnings as in the old manual project set(CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING YES) set(CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_BOOL_CONVERSION YES) set(CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_CONSTANT_CONVERSION YES) set(CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_EMPTY_BODY YES) set(CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_ENUM_CONVERSION YES) set(CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_FLOAT_CONVERSION NO) set(CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_INFINITE_RECURSION YES) set(CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_INT_CONVERSION YES) set(CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_NON_LITERAL_NULL_CONVERSION YES) set(CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_STRICT_PROTOTYPES YES) set(CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION YES) set(CMAKE_XCODE_ATTRIBUTE_GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS YES) set(CMAKE_XCODE_ATTRIBUTE_GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS YES) set(CMAKE_XCODE_ATTRIBUTE_GCC_WARN_64_TO_32_BIT_CONVERSION YES) set(CMAKE_XCODE_ATTRIBUTE_GCC_WARN_ABOUT_RETURN_TYPE YES) set(CMAKE_XCODE_ATTRIBUTE_GCC_WARN_MISSING_PARENTHESES NO) # do not want set(CMAKE_XCODE_ATTRIBUTE_GCC_WARN_SIGN_COMPARE YES) set(CMAKE_XCODE_ATTRIBUTE_GCC_WARN_UNINITIALIZED_AUTOS YES) set(CMAKE_XCODE_ATTRIBUTE_GCC_WARN_UNUSED_FUNCTION YES) set(CMAKE_XCODE_ATTRIBUTE_GCC_WARN_UNUSED_VARIABLE YES) set(CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_RANGE_LOOP_ANALYSIS YES) set(CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_SUSPICIOUS_MOVE YES) set_target_properties(eureka PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/osx/EurekaApp/Eureka Doom Editor-Info.plist.in" MACOSX_BUNDLE_BUNDLE_NAME "${exe_display_name}" MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION}" MACOSX_BUNDLE_COPYRIGHT "Copyright © The Eureka Team" MACOSX_BUNDLE_EXECUTABLE_NAME "${exe_display_name}" MACOSX_BUNDLE_GUI_IDENTIFIER "$(PRODUCT_BUNDLE_IDENTIFIER)" MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_VERSION}" MACOSX_BUNDLE_ICON_FILE "Eureka Doom EditorIcon" MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}" XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.eureka.Eureka-Doom-Editor" XCODE_ATTRIBUTE_INSTALL_PATH "/Applications" XCODE_ATTRIBUTE_SKIP_INSTALL "No" XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME "YES" XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS ${CMAKE_SOURCE_DIR}/osx/EurekaApp/eureka.entitlements XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS "YES" XCODE_ATTRIBUTE_STRIP_INSTALLED_PRODUCT "NO" XCODE_ATTRIBUTE_COPY_PHASE_STRIP "NO" ) else() set(exe_display_name "eureka") if(WIN32) add_subdirectory(win) endif() endif() add_subdirectory(src) if(APPLE) target_link_libraries(eurekasrc PRIVATE eurekamac) target_link_libraries(eurekamac PRIVATE eurekasrc) endif() if(WIN32) target_link_libraries(eurekasrc PRIVATE eurekawin) endif() target_link_libraries(eureka eurekasrc) option(ENABLE_UNIT_TESTS "Enable unit tests" ON) if(ENABLE_UNIT_TESTS) enable_testing() add_subdirectory(test) endif() # Currently, installing via CMake is only supported on GNU/Linux and similar systems if(UNIX AND NOT APPLE) # Linux set(eureka_install_dir "${CMAKE_INSTALL_PREFIX}/share/eureka") install(TARGETS eureka RUNTIME DESTINATION "${BIN_DIR}" ) install(DIRECTORY games DESTINATION "${eureka_install_dir}" PATTERN "freedoom.ugh" EXCLUDE) install(DIRECTORY common ports DESTINATION "${eureka_install_dir}") install(FILES bindings.cfg defaults.cfg misc/about_logo.png operations.cfg DESTINATION "${eureka_install_dir}" ) # The full-install sequence is here install(CODE "execute_process( COMMAND xdg-desktop-menu install --novendor ${CMAKE_CURRENT_SOURCE_DIR}/misc/eureka.desktop COMMAND xdg-icon-resource install --novendor --size 32 ${CMAKE_CURRENT_SOURCE_DIR}/misc/eureka.xpm )") # uninstall target if(NOT TARGET uninstall) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY ) add_custom_target( uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake ) endif() endif() eureka-editor-eureka-2.0.2/GPL.txt000066400000000000000000000432541464327712600167340ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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 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) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You 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. 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) year 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 Lesser General Public License instead of this License. eureka-editor-eureka-2.0.2/INSTALL.txt000066400000000000000000000102171464327712600174110ustar00rootroot00000000000000 COMPILING (Linux) ================= Note: this section deals with compiling the Linux binary. For information on compiling for Windows and macOS, see below. Dependencies: 1. C++ compiler (GNU's G++) and associated tools packages: g++ binutils 2. CMake package: cmake 3. FLTK 1.3 website: http://www.fltk.org/ package: libfltk1.3-dev You may also need: libxft-dev libxinerama-dev libfontconfig-dev libjpeg-dev libpng-dev 4. libXpm package: libxpm-dev 5. OpenGL (recommended but not strictly necessary, see below) 6. zlib website: http://www.zlib.net/ package: zlib1g-dev 7. XDG Utils (only needed for Linux, to install the desktop and icon files) package: xdg-utils Assuming all those dependencies are met, then the following shell commands will build the Eureka binary. (the '>' is just the prompt) > mkdir build > cd build > cmake .. > make Some systems may need additional CFLAGS and/or LDFLAGS in order to find the required libraries (especially FLTK). For example, the following is reported to work for Gentoo Linux: CFLAGS += -I/usr/include/fltk-1 LDFLAGS += -L/usr/lib64/fltk-1/ OpenGL is used to greatly speed up the 2D and 3D views, however Eureka still supports software-only rendering as a compile-time option. You will need to edit the Makefile and disable OpenGL support -- look for the line containing NO_OPENGL and uncomment that line, and remove all GL libraries from the build. INSTALLING (Linux) ================== First make sure the Eureka binary was compiled successfully. Then become root (via the 'sudo' or 'su' command) and enter the following shell command: > make install That will install the eureka binary, definition files for various games and source ports, and the desktop and icon files. COMPILING (macOS) ================= Use CMake. You can download and install CMake from their website, or use a third-party package manager such as Homebrew. Easiest to use is the graphical interface version of CMake (CMake GUI). Unlike on Linux, the CMake script will download and build FLTK from their website. You don't need to download it yourself. This is by design, so that the final built app is self-contained with all that it needs to run, and that it will always use the exact same dependencies without varying on how the user may have installed FLTK on their system. The generated Xcode project or Makefile will ultimately produce an "Eureka Doom Editor" graphical application. If you generated a Makefile, there's no "make install" stage. Simply open the produced app. DISTRIBUTING (macOS) ==================== To distribute a signed app of Eureka, you need to generate an Xcode project first -- signing and notarizing the app is currently not supported from the Makefile. You can also distribute the app generated by Makefile as-is, but users will be warned that the app isn't signed, and prompted to move it to Trash (unless they access the app from the right-click menu in Finder). COMPILING (Windows) =================== Use CMake, same as on macOS. Similarly, the FLTK project shall be downloaded and built. SETTING UP Eureka ================= Eureka requires an IWAD file from one of the supported games, for example "doom2.wad". Eureka will look for IWADs when it starts up, but if it cannot find any then the 'Manage Wads' dialog will open and you can browse for an IWAD file there, which will be remembered for next time. Places where Eureka looks for IWADs: 1. The "iwads" directory in Eureka's home directory. In Linux this will be "~/.eureka/iwads". It is created automatically the first time Eureka is run (though there is no harm in creating it yourself). 2. (a) In Linux: /usr/share/games/doom (b) In Windows: C:\DOOM and C:\DOOM2 3. If you run Eureka from the command line and have the DOOMWADDIR or DOOMWADPATH environment variables set, then Eureka should find it the specified directory. 4. If running from the command line, Eureka will look in the current directory for the IWAD. 5. You can specify the IWAD file directly with the --iwad option. eureka-editor-eureka-2.0.2/README.txt000066400000000000000000000156721464327712600172520ustar00rootroot00000000000000 Eureka README ============= INTRODUCTION Eureka is a map editor for the classic DOOM games, and a few related games such as Heretic, Hexen and Strife. The supported operating systems are Linux (and other Unix-likes), Windows and macOS. WEB SITE http://eureka-editor.sourceforge.net/ FEATURES - Undo/Redo (multiple levels) - 3D view with good lighting emulation - Editable panels for things, linedefs, sectors (etc) - Browser for textures, flats, things (etc) - Key binding system - Built-in nodes builder SUPPORTED GAMES - DOOM - DOOM 2 - Final Doom - FreeDoom - HacX - Heretic - Hexen REQUIREMENTS - 128 MB of computer memory - 1024x720 or higher screen resolution - 3D accelerated graphics card - a keyboard and a two-button mouse - the data (iwad) file from a supported game COMPILATION See the INSTALL.txt document (in source code) RUNNING Command line: You can run Eureka from the command line, or it can be run from the desktop menu (on Linux: if your OS handles .desktop files as per the XDG specs). Eureka will need to be able to find an IWAD to run, if it cannot find any then the "Manage Wads" dialog will open up, allowing you to "Find" one (which is remembered for next time). You can open a PWAD file using the File/Open menu command, or start a new map with File/New command. You can also specify the PWAD to edit on the command line, either on its own or with the -file option: eureka -file masterpiece.wad If that PWAD contains multiple maps, you may need to specify which one to edit using the -warp option: eureka -file masterpiece.wad -warp 14 For a summary of useful command line options, type: eureka --help KEYBOARD AND MOUSE CONTROLS All Modes --------- LMB * select an object, drag to move the object(s) * click in empty area to clear the selection * click + drag in empty area to select a group of objects RMB * begin/continue line drawing (in vertex mode) * merge sectors (in sectors mode) * with CTRL pressed: bring up operation menu MMB * scroll the map around (by dragging) wheel : zoom in or out cursor keys : scroll the map F1 : operation menu TAB : toggle the 3D preview on or off ESC : cancel the current operation t : enter Thing mode l : enter Linedef mode s : enter Sector mode v : enter Vertex mode b : toggle the Browser on or off 1..9 : select the grid size (smallest to largest) CTRL-Z : undo (can be used multiple times) CTRL-Y : redo (i.e. undo the previous undo) CTRL-A : select all CTRL-I : invert the selection CTRL-U : unselect all ` (backquote) : unselect all HOME : zoom 2D viewport to show the whole map END : move 2D viewport to camera location ' (quote) : move 3D camera to position of mouse pointer f : toggle free mode vs grid snapping g : toggle grid on / off N : open next map in the current wad P : open previous map in the current wad j : jump to object (by its numeric id) J : toggle object number display o : copy and paste the selected objects c : copy properties from selected --> highlighted object C : copy properties from highlighted --> selected objects H : mirror objects horizontally V : mirror objects vertically R : rotate objects 90 degrees clockwise W : rotate objects 90 degrees anti-clockwise a : scroll map with the mouse r : scale selected objects with the mouse R : scale selected objects, allow stretching CTRL-R : rotate the selected objects (with the mouse) K : skew (shear) the selected objects \ : toggle the RECENT category in the Browser u : popup menu to set ratio lock z : popup menu to set current scale B : popup menu to set browser mode F8 : popup menu to set sector rendering mode ; : make the next key pressed META META-N : load next file in given list META-P : load previous file in given list META-F : apply a fresh tag to the current objects META-L : apply the last (highest) tag to the current objects Things Mode ----------- SPACE : add a new thing d : disconnect things at the same location m : move selected things to occupy the same location w : rotate things 45 degrees anti-clockwise x : rotate things 45 degrees clockwise Vertex Mode ----------- SPACE * begin/continue line drawing * with SHIFT key: always continue line drawing * with CTRL key: inhibit creation of sectors d : disconnect all linedefs at the selected vertices m : merge selected vertices into a single one u : unlock any current ratio lock I : reshape selected vertices into a line O : reshape selected vertices into a circle D : reshape selected vertices into a half-circle C : reshape selected vertices into a 120-degree arc Q : reshape selected vertices into a 240-degree arc Linedef Mode ------------ e : select a chain of linedefs E : select a chain of linedefs with same textures w : flip linedefs k : split linedefs in two A : auto-align offsets on all selected linedefs d : disconnect selected linedefs from the rest m : merge two one-sided linedefs into a two-sided linedef Sector Mode ----------- SPACE * add a new sector to area around the mouse pointer * if a sector is selected, copy that sector instead of using defaults d : disconnect sector(s) from their neighbors m : merge all selected sectors into a single one w : swap floor and ceiling textures i : increase light level I : decrease light level e : select sectors with same floor height E : select sectors with same floor texture D : select sectors with same ceiling texture , and < : lower floor heights . and > : raise floor heights [ and { : lower ceiling heights ] and } : raise ceiling heights 3D View ------- (cursor keys will move forward and back, turn left and right) (the WASD keys can also be used to move the camera) LMB : select walls, floors or ceilings MMB : turn or move the camera (by dragging the mouse) wheel : move camera forwards or backwards PGUP and PGDN : move camera up and down g : toggle gravity (i.e. as if the player was on the ground) e : popup menu to set edit mode o : toggle objects on or off META-v : drop to the ground META-l : toggle lighting on or off META-t : toggle texturing on or off F11 : increase brightness (gamma) r : adjust offsets on highlighted wall (with the mouse) c : clear offsets on highlighted wall x : align X offset with wall to the left y : align Y offset with wall to the left z : align both X + Y offsets X : align X offset with wall to the right Y : align Y offset with wall to the right Z : align both X + Y offsets COPYRIGHT and LICENSE Eureka DOOM Editor Copyright (C) 2014-2024 Ioan Chera Copyright (C) 2001-2020 Andrew Apted, et al Copyright (C) 1997-2003 Andre Majorel et al Eureka is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Eureka is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. eureka-editor-eureka-2.0.2/TODO.txt000066400000000000000000000142221464327712600170500ustar00rootroot00000000000000 Eureka TODO / WISHLIST ====================== See also github.com/ioan-chera/eureka-editor list of issues. Slightly Possible ----------------- + support resources in PK3 files - linedef mode: '[' and ']' to adjust length of current line - Tools/Make Door - Tools/Make Lift - a way to clear the Browser recent lists - a dialog to restore a map from a backup - can import DWD (DoomEd) format maps - allow Game/Port definitions to specify the linedef/thing flags which can be used (rather than hard-coding them) - when dragging a shape next to existing geometry, highlight vertices and linedefs which would get merged, and implement that merging - Preferences window: - backup_max_files / backup_max_space - floor_bump_xxx values - ability to autosave to a hidden file, and if Eureka crashes or power fails, can detect it and allow user to restore from it - treat sprite UI_Pic in THING panel and DEFAULTS panel as a highlightable thing, and possible Copy/Paste target - Resource Dialog : when add a ".wad", check for same file with ".ugh" extension and automatically add it too when it exists - View/Place Camera command, cursor turns into '+' [ need an ACT_ASK_SPOT action, plus a /ask flag for command ] - Operation menu: for "ACT_XXX" commands, turn pointer into a '+' and wait for user to begin action (with MOUSE1..3 or SPACE key) - replace "Toggle XXX" in View menu with checkboxes - texture checks : warn about a 2S switch line with same switch in both the UPPER and LOWER textures - sector splitting: when choosing which side (left or right) will become NEW sector, prefer the loop which DOES NOT include any self-referencing linedefs - in Find/Replace panel, can filter things by CATEGORY - PRINT key makes a screenshot of 2D or 3D view - a sector rendering mode that shows floors which are same texture as the currently hilighted one. [ also for ceilings ] - for the "Edit -> Paste" menu, turn the cursor into crosshairs and wait until the user selects a spot to paste to OR: show the objects as the mouse move arounds, similar to dragging stuff but less intense - a key to copy properties TO defaults (e.g. 'y' for yank) - feature "tile_nonpow2" [ emulate tutti frutti when absent ] - draw the sky texture in 3D view - when browser opened by a click, jump to the texture/etc clicked on - MMB on sidedef/sector tex : open RECENT browser - BOOM colormaps in 3D view Rejected Ideas -------------- NO: a toolbar NO: a scripting language NO: Restore last window position and maximized state NO: un-hard-code menu shortcuts? NO: ability to use an external node builder NO: if a given pwad (from command line) does not exist, ask to create it perhaps: --create or --new option? NO: built-in cheat sheet for mouse buttons and common keys NO: document the config file syntax NO: when one vertex of a linedef is moved (and not the other) update the X offset on the appropriate side (right side for start, left side for end vertex) NO: support SPACE/INSERT in linedef mode (and line is highlighted or selected) split the line and put vertex where mouse is [ can do this in vertex mode easily enough ] NO: a proper "curve" tool for making a circle arc or bezier curve, and new vertices would be constrained to that curve, and you can move existing vertices onto the curve NO: merge vertex and linedef modes NO: nicer way to select map, render a small 2D version of each map and present them in a scrolling list NO: ability to drag the camera (on 2D viewport) NO: when moving a sector and the camera is inside it, move camera too NO: ability to edit Lua code for OBLIGE prefabs NO: 3D view: handle very tall/thin window, letter box with black NO: an auto-save feature (e.g. save every N minutes unless no changes occurred in the last N minutes) NO: a name-only mode for texture and flat browsers NO: exchange object numbers NO: check that current pwad has been externally modified NO: when highlighting a sector, draw the things in the same color but diimer, to show sector operators will affect things too NO: support Chex Quest 1 and 2 NO: ability to "remove line 271" (etc) in port definitions NO: "USED" category for the browser NO: speed up grid drawing when step is small and zoomed out NO: integrate Visplane Explorer NO: support DDF / LDF / EDF as (or in) a resource file NO: "fix" missing coop starts, place them near player #1 NO: a key to toggle "grab mouse" mode in 3D view NO: animation mode, render continuously and show any lighting effects and animated / scrolling textures and sprites NO: ability to hide the right-side panel NO: disconnect sectors : automatically include islands NO: quantization should prevent linedefs from overlapping / crossing NO: for quantizing a group of objects, try about 9 delta positions (x+0, x+step/4, x-step/4 etc...) and choose "best" quantization NO: autocomplete flat/texture names in Linedef and Sector panels NO: when building REJECT, support a simple distance check [ i.e. if distance between two sectors >= N, mark as cannot see ] NO: make read errors in BSP code more tolerant (DON'T call FatalError) NO: edit-key dialog has a button which opens a web browser to the documentation about the current command NO: a mode to show skill levels via color of drawn things [ draw sprites in 2D/3D view differently too ] NO: when get "Area not closed" error, show the place where it fails NO: Browser search box: allow ',' for OR --> split match into N pieces, perform normal match on each NO: a command to split-line-in-half-and-move-to-curve NO: able to drag stuff around in 3D view, raise/lower floors NO: large font mode, more readable on 1920x1080 monitors NO: support DECORATE as (or in) a resource file NO: support Windows 95/98/ME [running on Windows 98SE requires KernelEx] NO: conversion between Hexen <--> DOOM formats [ perhaps as a script ] NO: conversion from Boom --> vanilla DOOM NO: for DOOM have "Switch", "Grating", "Door" categories NO: add MBF things: 2016 "BETA Sceptre", 2017 "BETA Bible" eureka-editor-eureka-2.0.2/bindings.cfg000066400000000000000000000104751464327712600200260ustar00rootroot00000000000000# Eureka key bindings (installed) # vi:ts=16:noexpandtab # # ---- Mouse Buttons ------------ # general LAX-MOUSE1 ACT_Click general LAX-MOUSE2 NAV_MouseScroll 1.0 general CMD-MOUSE3 OpMenu vertex MOUSE3 Insert vertex SHIFT-MOUSE3 Insert /continue sector MOUSE3 Merge general WHEEL_UP Zoom +1 general WHEEL_DOWN Zoom -1 render LAX-WHEEL_UP 3D_WHEEL_Move 48 render LAX-WHEEL_DOWN 3D_WHEEL_Move 48 render SHIFT-MOUSE1 SelectNeighbors texture render CMD-MOUSE1 SelectNeighbors height # # ---- Browser only ------------ # browser CMD-k BR_ClearSearch browser PGUP BR_Scroll -3 browser PGDN BR_Scroll +3 # # ---- 3D View ------------ # render e OpMenu edit render w 3D_NAV_Forward 384 render s 3D_NAV_Back 384 render a 3D_NAV_Left 384 render d 3D_NAV_Right 384 render W 3D_NAV_Forward 128 render S 3D_NAV_Back 128 render A 3D_NAV_Left 128 render D 3D_NAV_Right 128 render LAX-UP 3D_NAV_Forward 384 render LAX-DOWN 3D_NAV_Back 384 render LAX-PGUP 3D_NAV_Up 256 render LAX-PGDN 3D_NAV_Down 256 render LAX-LEFT 3D_NAV_TurnLeft 150 render LAX-RIGHT 3D_NAV_TurnRight 150 render ALT-LEFT 3D_NAV_Left 384 render ALT-RIGHT 3D_NAV_Right 384 render LAX-r 3D_ACT_AdjustOfs 1.0 render META-v 3D_DropToFloor render o 3D_Toggle obj render META-t 3D_Toggle tex render META-l 3D_Toggle light render g 3D_Toggle grav render x 3D_Align /x render y 3D_Align /y render z 3D_Align /x /y render X 3D_Align /x /right render Y 3D_Align /y /right render Z 3D_Align /x /y /right render c 3D_Align /x /y /clear # # ---- Things mode ------------ # thing w TH_Spin +45 thing x TH_Spin -45 # # ---- LineDefs mode ------------ # line e LIN_SelectPath line E LIN_SelectPath /sametex line w LIN_Flip line k LIN_SplitHalf line A LIN_Align /x /y # # ---- Sectors mode ------------ # sector M Merge /keep sector e SEC_SelectGroup /floor_h sector E SEC_SelectGroup /floor_tex sector D SEC_SelectGroup /ceil_tex sector w SEC_SwapFlats sector , SEC_Floor -8 sector . SEC_Floor +8 sector SHIFT-, SEC_Floor -1 sector SHIFT-. SEC_Floor +1 sector CMD-, SEC_Floor -64 sector CMD-. SEC_Floor +64 sector [ SEC_Ceil -8 sector ] SEC_Ceil +8 sector SHIFT-[ SEC_Ceil -1 sector SHIFT-] SEC_Ceil +1 sector CMD-[ SEC_Ceil -64 sector CMD-] SEC_Ceil +64 sector i SEC_Light +16 sector I SEC_Light -16 # # ---- Vertices mode ------------ # vertex I VT_ShapeLine vertex O VT_ShapeArc 360 vertex Q VT_ShapeArc 240 vertex D VT_ShapeArc 180 vertex C VT_ShapeArc 120 # # ---- Any/All modes ------------ # general a NAV_MouseScroll 1.0 general LAX-UP NAV_Scroll_Up 120 general LAX-DOWN NAV_Scroll_Down 120 general LAX-LEFT NAV_Scroll_Left 120 general LAX-RIGHT NAV_Scroll_Right 120 general r ACT_Transform scale general R ACT_Transform stretch general CMD-r ACT_Transform rotate general K ACT_Transform skew general TAB Toggle 3d general b Toggle browser general ; MetaKey general META-; Nothing general O BrowserMode obj general T BrowserMode tex general F BrowserMode flat general L BrowserMode line general S BrowserMode sec general \ Toggle recent general SHIFT-\ BR_CycleCategory general = Zoom +1 general SHIFT-= Zoom +1 general - Zoom -1 general SHIFT-- Zoom -1 general HOME ZoomWholeMap general END GoToCamera general ' PlaceCamera general ` UnselectAll general g Toggle grid general f Toggle snap general l EditMode line general s EditMode sector general v EditMode vertex general t EditMode thing general N FlipMap next general P FlipMap prev general META-n GivenFile next general META-p GivenFile prev general SPACE Insert general INS Insert general SHIFT-SPACE Insert /continue general SHIFT-INS Insert /continue general CMD-SPACE Insert /nofill general CMD-INS Insert /nofill general DEL Delete general BS Delete general SHIFT-DEL Delete /keep general SHIFT-BS Delete /keep general d Disconnect general m Merge general q Quantize general j JumpToObject general o CopyAndPaste general H Mirror horiz general V Mirror vert general c CopyProperties general C CopyProperties /reverse general 1 GRID_Set 2 general 2 GRID_Set 4 general 3 GRID_Set 8 general 4 GRID_Set 16 general 5 GRID_Set 32 general 6 GRID_Set 64 general 7 GRID_Set 128 general 8 GRID_Set 256 general 9 GRID_Set 512 general 0 GRID_Set 1024 general MENU OpMenu general z OpMenu scale general u OpMenu ratio general B OpMenu browser general F8 OpMenu sec_render general META-f ApplyTag fresh general META-l ApplyTag last general META-r RecalcSectors eureka-editor-eureka-2.0.2/changelogs/000077500000000000000000000000001464327712600176535ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/changelogs/072.txt000066400000000000000000000023151464327712600207250ustar00rootroot00000000000000 CHANGES IN Eureka 0.72 ====================== (Main changes since 0.64 version) ++ the File menu is fully operational (albeit a bit clunky) ++ browser for textures, flats, thing types (etc) ++ can scale/rotate stuff with middle mouse button + grid snapping works again ('f' key to toggle) + quantization function ('q' key) which grid-snaps objects + disconnect function ('d' key) in vertex and linedef modes + automatic sector insertion when closing a line loop + automatic sector splitting when a line crosses a sector + the -iwad option works again - split linedefs by just inserting a vertex on a highlighted line - merge two linedefs by just deleting the vertex in-between - select linedef path function ('e' key) - correct sector function ('c' key) - new sectors get default flats/textures/etc - invert selection function (CTRL-I or Edit menu) - draw the camera on the map (a pink arrow) - move camera function (' key) and goto camera (END key) - can find an IWAD (doom2.wad only) in $DOOMWADDIR - the IWAD is opened in read-only mode - partial support for DOOM 1 and HERETIC (need -warp E1M1) - games/ directory for game definitions - ports/ directory for source port definitions eureka-editor-eureka-2.0.2/changelogs/074.txt000066400000000000000000000033541464327712600207330ustar00rootroot00000000000000 CHANGES IN Eureka 0.74 ====================== (Main changes since 0.72 version) + show the current WAD and map in the window title bar. + clipboard persists when changing maps, so you can copy-n-paste from one map/wad to another map/wad. + various user state (grid settings, camera, editing mode, etc..) persists when a map is saved, and is restored when the same map is loaded again. + improved SECTOR insertion: (a) copy properties from a selected sector, or try a neighboring sector if no selection. Use default value as last resort. (b) if CTRL is pressed, then new area BECOMES the same sector as the one selected. + new 'Sort' setting in Thing/Line/Sector type browsers. + new 'ADD' and 'DEL' sidedef buttons in the LineDef panel. + new -port option to select the source port. Defaults to boom. Other values currently supported are: vanilla, edge. - fixed problem where you could seemingly close a line loop, but due to grid snapping the vertex was merely placed on top of the existing one and it did not actually close the loop. - fixed bug where closing a line-loop around an existing shape did not apply the new sector to the outside of that shape. - new outside-of-map sectors now occupy a single grid square. - File/New does not ask for map slot unless there's a current PWAD, since that will be asked on the File/Save (== File/Export). - File/Export asks for the map slot _after_ the filename. - dynamic rotating (CTRL + middle button) no longer scales. - dragging/scaling/rotating vertices will draw the lines too. - fixed display of a certain flat (CEIL4_1 IIRC) which was showing bright cyan in parts that should be black (palette color #247). - better looking About box. eureka-editor-eureka-2.0.2/changelogs/081.txt000066400000000000000000000035151464327712600207300ustar00rootroot00000000000000 CHANGES IN Eureka 0.81 (r186) ============================= (Changes since 0.74 version) + support a proper unix-style installation + made a proper web-site (using PmWiki) + command to build nodes (via glBSP) and quit + texture browser can be resized by dragging the edge - log file is only created when --log is used - the --quiet option (-q) suppresses output to stdout - new --debug option (-d) enables debug messages - allow long options to begin with '-' or '--' - handle a pwad filename given without -file - more lax finding of patch lumps for textures - when no level is given, find first one in PWAD or IWAD - support plain numbers with -warp - look for iwads in the ~/.eureka/iwads directory - when searching for iwads, look for more names (e.g. "doom.wad") - if -iwad parameter is a bare name, look in iwad search path - if -iwad parameter has no extension, add ".wad" - using SPACE on a single selected vertex will unselect it - closing a simple vertex loop always makes a new sector inside it - can now split a line when one of its vertices is selected + new 'm' command for merging sectors + new 'c' command to copy sector/thing/line properties - added 'same_mode_clears_selection' config var (emulates Yadex behavior) - 3D view: support strafing with ALT or META key - initial support for Odamex - DOOM: fixed line types 33 and 34 (red and yellow locked doors) - DOOM: restored the 'Computer Map' pickup - DOOM: fixed "SW2xxx" textures not having the right category - EDGE: added slope line types - EDGE: added some missing things (jetpack, green keys, dog, stealth mons) - EDGE: fleshed out sector types - EDGE: fleshed out line types (hub exits, sliding doors, RTS) - TNT: assigned the new textures into categories (e.g. "Crates") - PLUTONIA: assigned the new textures into categories eureka-editor-eureka-2.0.2/changelogs/084.txt000066400000000000000000000035061464327712600207330ustar00rootroot00000000000000 CHANGES IN Eureka 0.84 (r304) ============================= (Changes since 0.81 version, r186) + multi-select : LMB toggles each object (no need for CTRL key) + can click on a texture in the LineDef or Sector panels, it becomes highlighted, the browser is opened (if not already), and only the selected parts are changed when clicking in the browser. + implemented a -merge option for resource wads + reload the wad/map after building the nodes (no longer exit) - ESC key no longer quits - plain MMB now inserts an object (like SPACE or INSERT key) - thing panel has radial arrow buttons for setting the angle - insert thing: if one already selected, copy its properties - improved line split highlighting when SNAP mode is active - limit size of drawn vertices when zooming right in - allow running locally (without a 'make install') - iwad search: check more places (like /usr/share/games/doom) - fixed possible fatal error with zero-length lines - fixed state persistence to ignore unused vertices (etc) - fixed inner sector getting defaults when closing simple loop - fixed pink-highlighted tagged sectors when line was off-screen - fixed CMD key on MacOS X to only trigger menu commands - config: can specify a boolean value on the command-line - config: new syntax for config files, no '=' required - config: added 'escape_key_quits' var - config: added 'leave_offsets_alone' var - config: added 'mouse_wheel_scrolls_map' var - config: added 'new_islands_are_void' var - Browser: faster scrolling with the mouse wheel - Heretic: fixed the default port (i.e. not BOOM) - 3D view: can use WASD keys in 3D mode to move around - 3D view: the 'g' key toggles gravity (walking on the ground) - 3D view: toggle sprites changed key to 'o' (objects) - 3D view: removed CTRL-L function, resync objects with 'o' key eureka-editor-eureka-2.0.2/changelogs/088.txt000066400000000000000000000037541464327712600207440ustar00rootroot00000000000000 CHANGES IN Eureka 0.88c (r605) ============================== (Changes since 0.84 version, r304) + large overhaul of file handling: - 'Manage Wads' dialog allows setting the IWAD, port and resource wads - 'Open Map' dialog, with buttons for easy map selection - 'Recent Files' dialog (CTRL-R or File menu) - the iwad/port/resource settings are saved in the PWAD - better 'Export Map' dialog - IWADs found by the user are remembered + new Default Properties panel (shown in vertex mode) + implemented picture mode for Thing browser + new Move/Scale/Rotate dialogs (via Edit menu) + support for Doom Legacy, courtesy Wesley Johnson + support for HACX (not quite finished, but usable) + 3D view: fixed the slime trails - added 'd' disconnect command for sectors - added 'm' merge command for vertices - added 'm' merge command for two linedefs ! the -iwad parameter can no longer be a directory name - shortcut key for 'File/Export Map' is now CTRL-E - swapped sector height keys: '.' ',' <---> '[' ']' - grid-snap button is easier to use (a toggle button now) - can disable multi-select ('multi_select_modifier' config var) - sectors created outside of map now have fixed size - show a '*' in window title when map has unsaved changes - got 'View/Jump to Object' command working ('j' key) - got 'View/Show Object Numbers' working (also on 'J' key) - new 'View/Whole Selection' command - new 'View/Toggle Grid Type' command - fixed rotating a group of things to update their angles too - fixed wrong color of a tagged linedef or sector - fixed zooming out on File/Open when map has persistent state - fixed middle texture when pasting and linedef lost a side - config: default grid size is now 64 (was: 128) - config: added 'default_grid_size' var - config: added 'default_grid_snap' var - config: added 'digits_set_zoom' var - config: added 'new_sector_size' var - config: added 'gui_scheme' and 'gui_color_set' vars - config: added some glBSP-related vars eureka-editor-eureka-2.0.2/changelogs/095.txt000066400000000000000000000025651464327712600207410ustar00rootroot00000000000000 CHANGES IN Eureka 0.95 (r922) ============================= (Changes since 0.88 version, r605) + Preferences dialog + Key binding system, with GUI in preferences + Windows port (32-bit), with an installer + Automatically back-up edited wads (multiple times) + Status area on info bar (replaces map name) + Log viewer - new 'Prune Unused' command removes unused stuff (sectors etc) - fixed explosion of wad size when saving repeatedly - fixed crash clicking a linedef flag when nothing was selected - fixed PGUP / PGDN keys to scroll the browser - fixed jerky RMB scrolling at large zoom factors - Scale Objects: implemented Z scaling for sectors - Default Props panel is now hidden by default - copy properties command ('c') now copies linedef textures - swapped grid keys: 'g' now makes the grid smaller, 'G' bigger - key for splitting lines in half is now 'k' (was 'x') - prevent making two lines overlap when merging vertices - merge: support one selected + one highlighted - merge command for things -- place them at same location - disconnect command for things at same location - when a resource cannot be found, look in same dir as PWAD and IWAD - when saving over a map, use existing location in the wad - command line options: '-m' is shorthand for '--merge' - preference setting to swap upper and lower in Linedef panel ! removed '192' grid size eureka-editor-eureka-2.0.2/changelogs/100.txt000066400000000000000000000044771464327712600207300ustar00rootroot00000000000000 CHANGES IN Eureka 1.00 (r1416) ============================== (Changes since 0.95 version, r922) + extensive map-checking functions + validate map data when loading a level + texture alignment commands for 3D view + splitting void islands now works as expected + improved grid, with configurable colors + scroll-bars for the map view (optional) - one sided linedefs show texture in the "Lower" spot - automatically unpack sidedefs when loading a map - support multiple filenames: new 'File/Given Files' menu - commands to visit the next or previous file - commands to open the next/previous map ('N' and 'P' keys) - changed 'File/Recent Files' to be a sub-menu - option to automatically open the most recent file - improved About dialog with Jason R. Johnston's logo - improved Log viewer, ability to save the logs to a file - improved dialog boxes - support Eureka config (.ugh) files as resource files - support $DOOMWADPATH for finding IWADs - implemented SEC_Light() binding command - commands for setting tags on linedefs/sectors - Edit / Move objects: implemented Z value for sectors - the ';' key waits for next key and makes it META - better drawing of selected sectors - better drawing of highlighted things and linedefs - better drawing of things (in THING mode) - show unknown/missing textures in the LineDef panel - show unknown/missing textures in the 3D preview - display the lengths of the last few linedefs - can modify the length of a line in the LineDef panel - improved behavior of vertices when grid-snap is on - option to limit grid toggle to a single kind - option to show grid in SNAP mode, hide it in FREE mode - option to set the default editing mode - option to set the default port - 3D View: option to set the aspect ratio - 3D View: option to prevent up/down moves when gravity is on - remember the browser width for a saved map - remember the 3D mode (the lack of it) for a map - fixed crash bug when loading or saving a map containing linedefs which have no right sidedef - fixed rare map saving problem (header lump in wrong position) - fixed possible crash not clearing selection after loading a map - fixed wrong linedef (etc) totals after loading another map - fixed key binding dialog: unable to remove a parameter - fixed the selection after a sector merge eureka-editor-eureka-2.0.2/changelogs/107.txt000066400000000000000000000104761464327712600207330ustar00rootroot00000000000000 CHANGES IN Eureka 1.07 (r1716) ============================== (Changes since 1.00 version, r1416) + implemented Find and Replace (as a panel), with support for stepping though each item or selecting them all, and filters to control which items to visit or ignore + added 'File / New Project' command as the proper way to create a brand new WAD file. The 'New Map' command requires a current pwad, and will save the fresh map immediately into it + new 'RECENT' category for Texture/Flat/Thing browsers, and rebound the '\' key to toggle this category on/off + new 'Rename Map' and 'Delete Map' commands in FILE menu + improvement to key binding system, support for "flags" which are parameters beginning with a forward slash, such as "/new" and "/clear". The 'EditKey' dialog is now much easier to use too + Windows package no longer uses an installer + vertex reshaping commands: - 'I' moves selected vertices onto a line - 'O' moves them into a circle shape - 'D' moves them into a half-circle - 'C' moves them into a 120-degree arc - 'Q' moves them into a 240-degree arc - a preference to show smaller textures in the browser - map checker can find unknown linedef and sector types - Linedef panel: swapped the 'Tag' and 'Length' positions - Linedef panel: always show a two-sided line panel when multiple lines are selected (allowing all texture parts to be edited) - Linedef panel: don't show rail/upper tex for one-sided lines (can be disabled with the 'show_full_one_sided' config var) - when loading a wad specified on the command line, and it contains settings for the iwad, port and/or resources, then allow command line arguments to override those values (and _add_ new resources) - new preference to maximize window on start (Linux, WIN32 only) - the Default Properties now has its own panel - Default Props: only a single wall texture now, and shows a sprite for the default thing which opens the browser when clicked on - added back the '192' grid size - browser: changed two key-bindings: 'T' now opens to Things and 'X' is used to open it to Textures (matching the menu shortcuts) - browser: changed key-binding for BR_CycleCategory to '|' - browser: the 'Sort' menu has been replaced with an 'Alpha' checkbox - browser: made sprites a bit smaller, can now show three columns when the browser is at minimum width - better way to show how a linedef will be split (esp. when snapping) - co-op player starts are now colored as in DOOM - 3D view: the low/high detail flag is now a preference setting (no longer toggleable with the F5 key) - added info bar for 3D view, shows current position, angle, etc... - added 'Toggle 3D View' command to View menu - support loading a read-only wad file - support data in a map header lump (such as MAP01), make sure to save it when saving the map (instead of removing it) - node builder: added work-around for "TOO SIMPLE" levels (i.e. a single convex sector), creating a dummy node and an extra subsector and seg for the back side - wrote a Unix man page - vanilla DOOM: do not show "friend", "coop" or "sp" thing flags - support -warp option being followed by two numeric arguments (episode and map number), compatible with vanilla DOOM - when checking textures, ignore ones beginning with '#' - show version _in_ the About box (not just the window title) Bug Fixes: - fixed not loading 'ASHWALL' texture for DOOM 1 - fixed bug when saving and using the 'ExMx' buttons (an erroneous newline was added into the map's lump name) - 3D view: fixed a vertical mis-alignment of textures (one pixel) in certain circumstances - fixed occasional false positives with sector mismatch test - fixed wrong focal point when zooming immediately after the 'j' (JumpToObject) command - fixed category of linetype #68 (should be a raising floor) - fixed clipping of mid-masked textures (e.g. the cage in E1M9) - fixed not reloading textures (etc) when opening a new wad file - fixed crash when trying to build nodes on an IWAD map which has some changes made to it, but has not been saved (exported) yet - fixed key binding list so that pressing 'Bind', 'Copy' etc on a non-visible line will scroll to that line (make it visible) - browser: fixed patterns like '4$' not working properly eureka-editor-eureka-2.0.2/changelogs/111.txt000066400000000000000000000043311464327712600207170ustar00rootroot00000000000000 CHANGES Eureka 1.11 =================== (Changes since 1.07 version) Games and Ports: + Hexen support! (thanks to printz for doing some of the heavy lifting) + Boom generalized lines and sectors + treat Freedoom Phase 1 and Phase 2 as separate games + added Eternity port definition, thanks to printz - Heretic: categorized the textures and flats - changed default port from Boom --> Vanilla Editing: + rendering of sector flats/lighting in the 2D window + easier vertex "drawing mode" using the LMB + when adding lines, automatically split crossed lines - inserting a vertex with SHIFT continues the drawing mode - inserting a vertex with CTRL inhibits creation of sectors - SHIFT + LMB in sectors mode always opens a selection box - better merging of linedefs when dragging a vertex - prevent overlapping lines when deleting 3rd vertex of a triangle - much less chance to accidentally drag an object - when a line splits a sector, use a consistent orientation - when creating a fresh map, add all four player starts - allow loading a map with no vertices, no linedefs (etc) UI: + fixed texture warping in 3D preview - sector panel: buttons for quickly setting the headroom - sector panel: MMB on the ceiling flat sets it to sky - right-click on a sidedef or sector texture sets it to default - various layout tweaks to the editing panels - added "Recent Textures" command (etc) to Browser menu - fixed RECENT category to show most recent items at the top - status bar lets you see full message via a tooltip Commands: - new "Last Selection" command, undo an accidental clearing - added /reverse flag for CopyProperties command - extended LIN_Flip command, avoid making lines with no right side Map checking: - find "dangling" vertices - detect the Medusa Effect on 2S lines - detect transparent tex on solid walls - find manual doors on 1S lines - don't consider teleport things to be stuck in monsters - ability to SHOW unused vertices Miscellaneous: - improved eureka.desktop file, courtesy Fabian Greffrath - have a fallback sprite for the MBF dog thing (id 888) - replaced "Aspect ratio" with "Pixel aspect ratio" in prefs - use absolute paths for resource filenames in __EUREKA lump eureka-editor-eureka-2.0.2/changelogs/121.txt000066400000000000000000000073521464327712600207260ustar00rootroot00000000000000 CHANGES IN Eureka 1.21 ====================== (Since version 1.11) Editing: + line drawing now done using RMB (MOUSE3) button + improved drag behavior, never modify the current selection + select/copy/paste textures in the 3D view + an operation menu, bound to F1 key or CTRL-RMB + undo/redo: show what was undone in the status area - improved ability to highlight/select very short linedefs - improved insertion of sectors, less "area not closed" errors - skew (shear) objects with the mouse, bound to 'K' key - "dotty" grid is a preference, rather than three-way toggle - default edit mode is now Vertices, and grid-snapping OFF - linedef/sector/thing descriptions update as the user types - arrow buttons in Vertex panel for fine adjustments - auto-align linedefs on the 2D map, bound to 'a' key - entering a negative "Length" in Linedef panel moves the start vertex of the line instead of the end vertex General: + improved BSP code, can build nodes for a map on each save, building all nodes no longer resets the undo/redo history, more preference settings, ability to disable GL nodes, and support for ZDoom uncompressed node format (XNOD) + "Test Map" command for testing your map in the game + sprite rendering on the 2D canvas (in Things mode) + a mode to show sound propagation - a new "File/Copy Map" command - a better dialog for "File / Open Map" command - a better dialog for "JumpToObject" command - a "Reset All Settings" button in the preferences dialog - find/replace: added a "Restrict to Selection" filter - find/replace: better way to choose textures/things - changing categories in the browser clears the search box - increased number of remembered recent files - better default directory for file chooser dialogs - more useful info bar in the 3D view Games and Ports: + properly limit which ports can be used with each game + ZDoom definition file (thanks to Slade3) + STRIFE support (based on the Slade3 config) + support TX_START/TX_END textures, including PNG and TGA format - find sprites outside of S_START/S_END (except in vanilla) - support for the Harmony TC - support for Doom-in-Hexen mapping - added "MBF" as a separate port Key System: + mouse buttons (and wheel) use the key binding system + smooth navigation for the 2D and 3D views - allow key bindings to override hard-coded menu shortcuts - bindable commands for all the functions in the menus - use F1..F10 function keys for various menu shortcuts - improved key binding dialog in the preferences - changed scaling and rotation to the 'r' key (was MOUSE2) - changed map panning to use MMB (MOUSE2) or the 'a' key - changed browse-textures back to 'T' key (was 'X') - changed grid toggle to the 'g' key - Zoom command supports a "/center" flag - LIN_Flip command was simplified with a "/force" flag - Enlarge and Shrink commands support fractional values - Gamma command removed, using "Toggle gamma" instead Bugs Fixed: + fixed problem of unable to split lines close to an end-point - fixed problem of deleting a loop of linedefs inside another sector could sometimes delete that outer sector too - fixed unwanted rail texture when splitting a sector and the texture name began with '_' or '#' (such as "_WALL"). - fixed inaccurate criss-cross linedef detection - fixed rendering of unpegged lowers under sky ceilings - fixed textures in Linedef panel not updating after undo or redo - fixed exporting to keep the iwad/port/resources of target wad - fixed panel stuck on a highlighted object when going to 3D view - fixed unknown texture "FIX" button to not change "-" textures - fixed bad sidedef fallback when loading a map with no sectors - fixed default pixel-aspect to be 0.83, matching original DOOM eureka-editor-eureka-2.0.2/changelogs/124.txt000066400000000000000000000042011464327712600207170ustar00rootroot00000000000000 CHANGES IN Eureka 1.24 ====================== (Since version 1.21) + new "Edit Text Lump" command for editing text lumps + moved some menu commands to new "Tools" menu + fixed wall sorting issue in 3D View which could cause a crash + fixed fatal "zero-length line" error when drawing lines + fixed sector merge to keep properties of first selected sector + fixed inserting things in Hexen having no SP/COOP/DM/class flags + faster drawing of plain map view under X windows + faster sector rendering on huge maps - new "fresh" tag button in the Sector panel - more ZDoom sector types and GZDoom point-light things - when changing grid size via keyboard, show grid if hidden - new "Add BEHAVIOR" command to support ACS scripting - show warning when port is not compatible with current game - handle text files containing a Unicode BOM (byte-order mark) - support Strife's new thing flags and linedef flags - open-map dialog has buttons for ALL maps (in a scrollable area) - hexen format: fixed wrong sector specials when game is DOOM - hexen format: show every arg value when special is not 0 - hexen format: support ZDoom generalized sectors - preferences: a setting to show sidedef ADD / DEL buttons - preferences: a setting for default sector rendering - preferences: a setting for default sprite rendering - map checker: look for unspawnable things - map checker: check usage of special 666 / 667 tags - map checker: find non-animating switch textures (on usable lines) - map checker: fixed merging multiple sets of overlapping verts - fixed Find/Replace to handle generalized sectors - fixed wall torch sprite in the Heretic game config - fixed closed sectors in 3D view having a see-through gap - fixed raising Eureka window when other windows have KB focus - fixed "View Logs" command to raise the logs window - fixed malformed warnings when linedefs contain an invalid vertex - fixed "Removed unused vertices" message to show correct number - handle some rare assertion failures more gracefully - various improvements to the Makefile, e.g. create the OBJ_DIR - added VIM syntax file for editing definition (.ugh) files eureka-editor-eureka-2.0.2/changelogs/127.txt000066400000000000000000000043051464327712600207270ustar00rootroot00000000000000 CHANGES IN Eureka 1.27 ====================== (Since version 1.24) + use OpenGL for faster rendering of 2D and 3D views + improved non-GL drawing of 2D view, much faster in Linux + support mixing textures and flats for ports that allow it + improved 3D mode, can move things and sector surfaces + ratio lock, makes producing lines at certain angles easier - a single status bar for both 2D and 3D views - new popup menus to set edit mode, browser mode, scaling - render sectors in the 2D view with both lighting and texturing - create void islands by drawing lines anti-clockwise in a sector - snap position indicator for 2D view (a light-blue cross) - added scale '-' and '+' buttons, show scale as percentage - ability to highlight/select railings in 3D view - beginning of support for UDMF maps (not usable yet...) - render BOOM's deep water effect (linetype 242) - render 3D Floors for EDGE, LEGACY and ZDOOM ports - render basic slopes for EDGE, ETERNITY, ODAMEX and ZDOOM - render things with a NULL sprite as a blue triangle - render Hexen map-spots as a green triangle - render unknown things with a smaller '?' sprite - preference to combine flats and textures in a single browser - preference to show all textures on a one-sided linedef - preference for linedef information (Length, Angle, Ratio) - support ESC key to cancel a current action (e.g. dragging) - support SHIFT and CTRL when using mouse-wheel to move in 3D view - support the FreeDM iwad - support TNT and Plutonia textures in FreeDoom2 iwad - support Hexen map format in the ETERNITY port - support PNG, JPEG and TGA images in sprite/flat/patch lumps - added portal specials 156 and 107 to the ZDOOM port - added missing specials 105, 106 and 130 to the ZDOOM port - improvements to the Makefile - improvements to the MacOS build files - fixed mode menu disappearing into Window's task bar when maximized - fixed not remembering test-in-game EXE when port is "vanilla" - fixed the 'Online Docs' command in the Help menu - fixed window title not showing correct map name - fixed Re-bind in key binding dialog to show new key as valid - fixed grid getting out-of-sync with the "hide in FREE mode" - fixed needless line flips when drawing clockwise within a sector eureka-editor-eureka-2.0.2/changelogs/2.0.0.md000066400000000000000000000055461464327712600206440ustar00rootroot00000000000000# CHANGES IN Eureka 2.0.0 (Since version 1.27b) ## Resource and project setup * Wads are now loaded fully in memory. **Note**: currently it still doesn't autodetect file changes, so take care not to open the level in other editors at the same time. * Resources can be loaded as folders, having the standard PK3/PKE layout. * Added Dehacked resource support, by contribution of Isaac Colón ([https://github.com/iccolon818](https://github.com/iccolon818)). * Fixed the EUREKA lump to store relative paths so that the user settings are portable between computers. * Removed the Hexen format support from Eternity. This format is only meant for vanilla Hexen wads and should not be used for new Eternity maps. * Do not throw a fatal error when loading invalid project resource files. ## Editing and interface * Dragging lines or sectors can also split other lines. Currently still no support for the dragged lines getting split by existing vertices. * Fixed a bug where dragging a vertex into a neighbouring linedef to split it resulted in two overlapping lines. * Testing map now opens the game without blocking Eureka, just like user would start another app. Also, for macOS you can now use app bundles. * Added tutti-frutti texture check * Now the tagged items (regardless of type) get highlighted properly, depending on the triggering special. * The tags check is now aware of the linedef special so it doesn't look for tagged sector if the special doesn't deal with sectors. * Now the Jump to Objects dialog allows you to choose multiple items. * Fixed so clicking a button while editing a panel field won't reset the field. * Fixed wrong labelling of sidedef texture boxes. * Now the menu commands show their actual shortcuts as set in user preferences. ## View * Sprites are displayed with rotations both in 2D and 3D views. * Spectral sprite view also shows up as such in the editor views, not just the sprite browser. * Fixed Heretic torches looking wrong in the 3D mode * Fixed the Strife klaxon things to hang from ceiling. * Fixed the Strife Sigil sprite not displaying correctly. * Fixed Heretic multiplayer sprite color translation * Fixed missing 'm' texture category from heretic.ugh. Added it and named it "magic". * Fixed failure to locate a patch if an equally named flat exists. ## Bug fixes * Fixed an access violation happening when starting a new ZDoom project. * Fixed a crash happening when starting a new project while a linedef is selected. * Fixed a crash happening when using R to change sidedef offset in 3D mode on a selected (but not highlighted) linedef. * Fixed a fatal error happening when deleting the last vertex. * Fixed the initial grid being set one step higher than intended in preferences. * Fixed an illegal operation being run when rendering 3D mode. ## Development * Project uses CMake * Deleted Makefile.xming. * Fixed failure to compile on SmartOS. eureka-editor-eureka-2.0.2/changelogs/2.0.1.md000066400000000000000000000006721464327712600206400ustar00rootroot00000000000000# CHANGES IN Eureka 2.0.1 (Since version 2.0.0) ## View * Corrected the copyright year for my contributions. ## Bug fixes * Fixed a crash happening when selecting neighbor sectors while no-sided linedefs are in the map. * Fixed a regression from 1.27b where selected 1-sided lines in 3D view wouldn't change texture unless the side panel texture thumbnail also gets selected. ## Development * Fixed some compilation errors on Linux. eureka-editor-eureka-2.0.2/changelogs/2.0.2.md000066400000000000000000000004561464327712600206410ustar00rootroot00000000000000# CHANGES IN Eureka 2.0.2 (Since version 2.0.1) ## Bug fixes * Fixed a crash happening when deleting all things from the map. * Fixed a crash happening when deleting a group of linedefs. * Fixed a bug where the linedef splitting hint wouldn't show up when in FREE grid mode (introduced by 2.0.0). eureka-editor-eureka-2.0.2/cmake_uninstall.cmake.in000066400000000000000000000017561464327712600223320ustar00rootroot00000000000000if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt") endif() file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files) string(REGEX REPLACE "\n" ";" files "${files}") foreach(file ${files}) message(STATUS "Uninstalling $ENV{DESTDIR}${file}") if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") exec_program( "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) if(NOT "${rm_retval}" STREQUAL 0) message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") endif() else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") message(STATUS "File $ENV{DESTDIR}${file} does not exist.") endif() endforeach() execute_process( COMMAND xdg-desktop-menu uninstall --novendor misc/eureka.desktop COMMAND xdg-icon-resource uninstall --novendor --size 32 eureka ) eureka-editor-eureka-2.0.2/common/000077500000000000000000000000001464327712600170315ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/common/doom_colors.ugh000066400000000000000000000017441464327712600220630ustar00rootroot00000000000000#------------------------------------------------------------------------ # DOOM 1/2 color stuff #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2013-2016 Andrew Apted # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ color sky 198 color wall 111 80 color floor 151 128 color invis 102 111 color missing 215 color unknown_tex 196 color unknown_flat 116 color unknown_thing 253 eureka-editor-eureka-2.0.2/common/doom_groups.ugh000066400000000000000000000023151464327712600220740ustar00rootroot00000000000000#------------------------------------------------------------------------ # DOOM LINE CATEGORIES #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2016 Andrew Apted # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ linegroup a "Animated" linegroup c "Ceiling" linegroup d "Door" linegroup e "Exit level" linegroup f "Floor (lower)" linegroup g "Floor (raise)" linegroup h "Crusher" linegroup k "Keyed Door" linegroup l "Light" linegroup m "Moving floor" linegroup n "Scripting" linegroup p "Lift" linegroup r "Renderer" linegroup s "Stairs" linegroup t "Teleport" linegroup v "Elevator" linegroup y "3D Floor" linegroup - "OTHER" eureka-editor-eureka-2.0.2/common/doom_lines.ugh000066400000000000000000000147311464327712600216740ustar00rootroot00000000000000#------------------------------------------------------------------------ # DOOM 1/2 line specials #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2017 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ # # Definition of linedef types # # Format is : line # line 0 - "-- NOTHING" line 9 - "S1 Donut (raise outer, lower inner)" :tag line 78 - "SR Floor Transfer /NXP" :tag line 48 a "-- Scroll Wall Left" line 77 h "WR Crusher" :tag line 6 h "W1 Crusher /fast" :tag line 25 h "W1 Crusher /slow" :tag line 73 h "WR Crusher /slow" :tag line 141 h "W1 Crusher /silent" :tag line 57 h "W1 Stop crusher" :tag line 74 h "WR Stop crusher" :tag line 24 g "G1 Floor up LIC" :tag line 47 g "G1 Floor up nhEF /TX" :tag line 101 g "S1 Floor up LIC" :tag line 55 g "S1 Floor up LIC-8 /cr" :tag line 18 g "S1 Floor up nhEF" :tag line 15 g "S1 Floor up 24 /TX" :tag line 14 g "S1 Floor up 32 /TX" :tag line 20 g "S1 Floor up nhEF /TX" :tag line 64 g "SR Floor up LIC" :tag line 65 g "SR Floor up LIC-8 /cr" :tag line 69 g "SR Floor up nhEF" :tag line 66 g "SR Floor up 24 /TX" :tag line 67 g "SR Floor up 32 /TX" :tag line 68 g "SR Floor up nhEF /TX" :tag line 59 g "W1 Floor up 24 /TXP" :tag line 58 g "W1 Floor up 24" :tag line 5 g "W1 Floor up LIC" :tag line 30 g "W1 Floor up lowest tex" :tag line 56 g "W1 Floor up LIC-8 /cr" :tag line 22 g "W1 Floor up nhEF /TX" :tag line 93 g "WR Floor up 24 /TXP" :tag line 92 g "WR Floor up 24" :tag line 91 g "WR Floor up LIC" :tag line 94 g "WR Floor up LIC-8 /cr" :tag line 96 g "WR Floor up lowest tex" :tag line 95 g "WR Floor up nhEF /TX" :tag line 119 g "W1 Floor up nhEF" :tag line 128 g "WR Floor up nhEF" :tag line 129 g "WR Floor UP nhEF /fast" :tag line 130 g "W1 Floor UP nhEF /fast" :tag line 131 g "S1 Floor UP nhEF /fast" :tag line 132 g "SR Floor UP nhEF /fast" :tag line 140 g "S1 Floor up 512" :tag line 13 l "W1 Light to 255" :tag line 81 l "WR Light to 255" :tag line 138 l "SR Light to 255" :tag line 35 l "W1 Light to 35" :tag line 79 l "WR Light to 35" :tag line 139 l "SR Light to 35" :tag line 12 l "W1 Light to highest nb" :tag line 80 l "WR Light to highest nb" :tag line 104 l "W1 Light to lowest nb" :tag line 17 l "W1 Light blink 1 Hz" :tag line 49 c "S1 Ceiling close flr+8" :tag line 41 c "S1 Ceiling close" :tag line 43 c "SR Ceiling close" :tag line 44 c "W1 Ceiling close flr+8" :tag line 72 c "WR Ceiling close flr+8" :tag line 40 c "W1 Ceiling up HEC" :tag line 31 d "D1 Open and stay open" line 1 d "DR Open door" line 46 d "GR Open and stay" :tag line 50 d "S1 Close door" :tag line 103 d "S1 Open and stay" :tag line 29 d "S1 Open door" :tag line 42 d "SR Close door" :tag line 61 d "SR Open and stay" :tag line 63 d "SR Open door" :tag line 3 d "W1 Close door" :tag line 16 d "W1 Close for 30s" :tag line 2 d "W1 Open and stay open" :tag line 4 d "W1 Open door" :tag line 75 d "WR Close door" :tag line 76 d "WR Close for 30s" :tag line 86 d "WR Open and stay" :tag line 90 d "WR Open door" :tag line 105 d "WR Open door /fast" :tag line 106 d "WR Open and stay /fast" :tag line 107 d "WR Close door /fast" :tag line 108 d "W1 Open door /fast" :tag line 109 d "W1 Open and stay /fast" :tag line 110 d "W1 Close door /fast" :tag line 111 d "S1 Open door /fast" :tag line 112 d "S1 Open and stay /fast" :tag line 113 d "S1 Close door /fast" :tag line 114 d "SR Open door /fast" :tag line 115 d "SR Open and stay /fast" :tag line 116 d "SR Close door /fast" :tag line 117 d "DR Open door /fast" line 118 d "D1 Open and stay /fast" line 26 k "DR Open blue door" line 27 k "DR Open yellow door" line 28 k "DR Open red door" line 32 k "D1 Open blue door (stay)" line 33 k "D1 Open red door (stay)" line 34 k "D1 Open yellow door (stay)" line 99 k "SR Open blue door /fast" :tag line 133 k "S1 Open blue door /fast" :tag line 134 k "SR Open red door /fast" :tag line 135 k "S1 Open red door /fast" :tag line 136 k "SR Open yellow door /fast" :tag line 137 k "S1 Open yellow door /fast" :tag # the "S1" and "W1" are lowercase here to inhibit the map checking # functions complaining about missing tag numbers. line 11 e "s1 Exit level" line 51 e "s1 Secret exit" line 52 e "w1 Exit level" line 124 e "w1 Secret exit" line 102 f "S1 Floor down HEF" :tag line 71 f "S1 Floor down HEF+8 /fast" :tag line 23 f "S1 Floor down LEF" :tag line 45 f "SR Floor down HEF" :tag line 70 f "SR Floor down HEF+8 /fast" :tag line 60 f "SR Floor down LEF" :tag line 19 f "W1 Floor down HEF" :tag line 36 f "W1 Floor down HEF+8" :tag line 37 f "W1 Floor down LEF /NXP" :tag line 38 f "W1 Floor down LEF" :tag line 98 f "WR Floor dn HEF+8 /fast" :tag line 83 f "WR Floor down HEF" :tag line 84 f "WR Floor down LEF /NXP" :tag line 82 f "WR Floor down LEF" :tag line 21 p "S1 Lift Lower" :tag line 62 p "SR Lift Lower" :tag line 10 p "W1 Lift Lower" :tag line 88 p "WR Lift Lower" :tag line 120 p "WR Lift Lower /fast" :tag line 121 p "W1 Lift Lower /fast" :tag line 122 p "S1 Lift Lower /fast" :tag line 123 p "SR Lift Lower /fast" :tag line 53 m "W1 Start Moving Floor" :tag line 87 m "WR Start Moving Floor" :tag line 54 m "W1 Stop Moving Floor" :tag line 89 m "WR Stop Moving Floor" :tag line 7 s "S1 Stair Raise 8" :tag line 100 s "W1 Stair Raise 16" :tag line 8 s "W1 Stair Raise 8" :tag line 127 s "S1 Stair Raise 16" :tag line 39 t "W1 Teleport" :tag line 97 t "WR Teleport" :tag line 125 t "W1 Teleport /mon" :tag line 126 t "WR Teleport /mon" :tag eureka-editor-eureka-2.0.2/common/doom_sectors.ugh000066400000000000000000000031211464327712600222330ustar00rootroot00000000000000#------------------------------------------------------------------------ # DOOM 1/2 sector types #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2017 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ # # Definition of sector types # # Format is : sector # sector 0 "NOTHING" sector 1 "Light Blinks Randomly" sector 2 "Light Flashes 2 Hz" sector 3 "Light Flashes 1 Hz" sector 4 "Flashes / 20% Damage" sector 5 "Damage 10%" sector 7 "Damage 5%" sector 8 "Light Oscillates" sector 9 "Secret Area" sector 10 "Close after 30 sec" sector 11 "End level / damage" sector 12 "Flashes 1 Hz sync" sector 13 "Flashes 2 Hz sync" sector 14 "Open after 5 minute" sector 16 "Damage 20%" sector 17 "Light Flickering" eureka-editor-eureka-2.0.2/common/doom_tex.ugh000066400000000000000000000161661464327712600213660ustar00rootroot00000000000000#------------------------------------------------------------------------ # DOOM 1/2 common textures #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2013 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ texturegroup h "Hell" texturegroup n "Natural" texturegroup t "Tech" texturegroup u "Urban" texturegroup - "OTHER" texture u STONE2 texture u STONE3 texture u SW1BRIK texture u SW2BRIK texture u SW1STON1 texture u SW2STON1 texture u CEMENT1 texture u CEMENT2 texture u CEMENT3 texture u CEMENT4 texture u CEMENT5 texture u CEMENT6 texture u SW1CMT texture u SW2CMT texture h BLODRIP1 texture h BLODRIP2 texture h BLODRIP3 texture h BLODRIP4 texture h DOORBLU2 texture h DOORRED2 texture h DOORYEL2 texture h FIREBLU1 texture h FIREBLU2 texture h FIRELAV2 texture h FIRELAV3 texture h FIRELAVA texture h FIREMAG1 texture h FIREMAG2 texture h FIREMAG3 texture h FIREWALA texture h FIREWALB texture h FIREWALL texture h PIPE1 texture h REDWALL texture h SK_LEFT texture h SK_RIGHT texture h SKIN2 texture h SKINCUT texture h SKINEDGE texture h SKINFACE texture h SKINLOW texture h SKINMET1 texture h SKINMET2 texture h SKINSCAB texture h SKINSYMB texture h SKSNAKE1 texture h SKSNAKE2 texture h SKSPINE1 texture h SKSPINE2 texture h SLOPPY1 texture h SLOPPY2 texture h SP_FACE1 texture h SP_FACE2 texture h SP_HOT1 texture h SW1HOT texture h SW2HOT texture h SW1SKIN texture h SW2SKIN texture h GSTFONT1 texture h GSTFONT2 texture h GSTFONT3 texture h GSTGARG texture h GSTLION texture h GSTONE1 texture h GSTONE2 texture h GSTSATYR texture h GSTVINE1 texture h GSTVINE2 texture h MARBFAC2 texture h MARBFAC3 texture h MARBFACE texture h MARBLE1 texture h MARBLE2 texture h MARBLE3 texture h MARBLOD1 texture h SP_DUDE1 texture h SP_DUDE2 texture h SP_DUDE4 texture h SP_DUDE5 texture h SW1GSTON texture h SW2GSTON texture h SW1MARB texture h SW2MARB texture t BIGDOOR2 texture t BIGDOOR3 texture t BIGDOOR4 texture t BRNPOIS texture t BRNSMAL1 texture t BRNSMAL2 texture t BRNSMALC texture t BRNSMALL texture t BRNSMALR texture t BROVINE2 texture t BROWN1 texture t BROWN144 texture t BROWN96 texture t BROWNGRN texture t BROWNHUG texture t BROWNPIP texture t CRATE1 texture t CRATE2 texture t CRATELIT texture t CRATINY texture t CRATWIDE texture t DOORBLU texture t DOORRED texture t DOORSTOP texture t DOORTRAK texture t DOORYEL texture t EXITDOOR texture t EXITSIGN texture t EXITSTON texture t GRAY1 texture t GRAY2 texture t GRAY4 texture t GRAY5 texture t GRAY7 texture t GRAYBIG texture t GRAYPOIS texture t GRAYTALL texture t GRAYVINE texture t ICKWALL1 texture t ICKWALL2 texture t ICKWALL3 texture t ICKWALL4 texture t ICKWALL5 texture t ICKWALL7 texture t NUKE24 texture t NUKEDGE1 texture t NUKEPOIS texture t PIPE2 texture t PIPE4 texture t PIPE6 texture t PLAT1 texture t SLADPOIS texture t SLADSKUL texture t SLADWALL texture t STEP2 texture t STEP3 texture t STEP4 texture t STEPTOP texture t SUPPORT3 texture t SW1BRCOM texture t SW2BRCOM texture t SW1BRN1 texture t SW2BRN1 texture t SW1BRN2 texture t SW2BRN2 texture t SW1BRNGN texture t SW2BRNGN texture t SW1BROWN texture t SW2BROWN texture t SW1DIRT texture t SW2DIRT texture t SW1EXIT texture t SW2EXIT texture t SW1GRAY texture t SW2GRAY texture t SW1GRAY1 texture t SW2GRAY1 texture t SW1PIPE texture t SW2PIPE texture t SW1SLAD texture t SW2SLAD texture t SW1STARG texture t SW2STARG texture t SW1STON2 texture t SW2STON2 texture t SW1STONE texture t SW2STONE texture t SW1VINE texture t SW2VINE texture t METAL texture t METAL1 texture t MIDBRN1 texture t MIDGRATE texture t SW1GARG texture t SW2GARG texture t SW1LION texture t SW2LION texture t SW1MET2 texture t SW2MET2 texture t SW1METAL texture t SW2METAL texture t SW1SATYR texture t SW2SATYR texture n ROCKRED1 texture n ROCKRED2 texture n ROCKRED3 texture n SP_ROCK1 texture n STONE texture n SW1STON6 texture n SW2STON6 texture t BIGDOOR1 texture t BLAKWAL1 texture t BLAKWAL2 texture t COMPBLUE texture t COMPSPAN texture t COMPSTA1 texture t COMPSTA2 texture t COMPTALL texture t COMPWERD texture t DOOR1 texture t DOOR3 texture t LITE3 texture t LITE5 texture t LITEBLU1 texture t LITEBLU4 texture t SHAWN1 texture t SHAWN2 texture t SHAWN3 texture t STARBR2 texture t STARG1 texture t STARG2 texture t STARG3 texture t STARGR1 texture t STARGR2 texture t STARTAN2 texture t STARTAN3 texture t STEP1 texture t STEP5 texture t STEP6 texture t STEPLAD1 texture t SUPPORT2 texture t SW1BLUE texture t SW2BLUE texture t SW1COMM texture t SW2COMM texture t SW1COMP texture t SW2COMP texture t SW1MOD1 texture t SW2MOD1 texture t SW1STRTN texture t SW2STRTN texture t TEKWALL1 texture t TEKWALL4 texture u BIGDOOR5 texture u BIGDOOR6 texture u BIGDOOR7 texture u SW1WOOD texture u SW2WOOD texture u WOOD1 texture u WOOD3 texture u WOOD4 texture u WOOD5 texture u WOODGARG flat h BLOOD1 flat h BLOOD2 flat h BLOOD3 flat u CEIL1_1 flat t CEIL1_2 flat t CEIL1_3 flat t CEIL3_1 flat t CEIL3_2 flat t CEIL3_3 flat t CEIL3_4 flat t CEIL3_5 flat t CEIL3_6 flat t CEIL4_1 flat t CEIL4_2 flat t CEIL4_3 flat t CEIL5_1 flat t CEIL5_2 flat t COMP01 flat t CONS1_1 flat t CONS1_5 flat t CONS1_7 flat t CRATOP1 flat t CRATOP2 flat h DEM1_1 flat h DEM1_2 flat h DEM1_3 flat h DEM1_4 flat h DEM1_5 flat h DEM1_6 flat t FLAT1 flat n FLAT10 flat u FLAT1_1 flat u FLAT1_2 flat u FLAT1_3 flat t FLAT14 flat t FLAT17 flat t FLAT18 flat t FLAT19 flat t FLAT2 flat t FLAT20 flat t FLAT22 flat t FLAT23 flat t FLAT3 flat t FLAT4 flat t FLAT5 flat u FLAT5_1 flat u FLAT5_2 flat h FLAT5_3 flat u FLAT5_4 flat u FLAT5_5 flat h FLAT5_6 flat n FLAT5_7 flat n FLAT5_8 flat u FLAT8 flat t FLAT9 flat t FLOOR0_1 flat t FLOOR0_2 flat t FLOOR0_3 flat t FLOOR0_5 flat t FLOOR0_6 flat t FLOOR0_7 flat t FLOOR1_1 flat t FLOOR1_6 flat t FLOOR1_7 flat t FLOOR3_3 flat t FLOOR4_1 flat t FLOOR4_5 flat t FLOOR4_6 flat t FLOOR4_8 flat t FLOOR5_1 flat t FLOOR5_2 flat t FLOOR5_3 flat u FLOOR5_4 flat h FLOOR6_1 flat n FLOOR6_2 flat t FLOOR7_1 flat h FLOOR7_2 flat n F_SKY1 flat n FWATER1 flat n FWATER2 flat n FWATER3 flat n FWATER4 flat t GATE1 flat t GATE2 flat t GATE3 flat t GATE4 flat h LAVA1 flat h LAVA2 flat h LAVA3 flat h LAVA4 flat u MFLR8_1 flat n MFLR8_2 flat n MFLR8_3 flat n MFLR8_4 flat t NUKAGE1 flat t NUKAGE2 flat t NUKAGE3 flat h SFLR6_1 flat h SFLR6_4 flat h SFLR7_1 flat h SFLR7_4 flat t STEP1 flat t STEP2 flat t TLITE6_1 flat t TLITE6_4 flat t TLITE6_5 flat t TLITE6_6 eureka-editor-eureka-2.0.2/common/doom_things.ugh000066400000000000000000000135231464327712600220540ustar00rootroot00000000000000#------------------------------------------------------------------------ # DOOM 1/2 common things #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2015 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ player_size 16 56 41 # # Definition of thing groups # Format is : thinggroup # thinggroup p 4F4 "Player" thinggroup m F00 "Monster" thinggroup w FA0 "Weapon" thinggroup a 850 "Ammunition" thinggroup h 280 "Health && Armor" thinggroup b 280 "Bonus" thinggroup k F0F "Key" thinggroup d 66C "Decoration" thinggroup l 66C "Light Source" thinggroup g 66C "Gore" thinggroup - 0BD "OTHER" # # Definition of things # Format is : thing # # should be NULL for things without any sprite # # can contain these letters: # i : invisible # c : on ceiling # l : lit up # n : non-blocking # v : can exist in void-space # t : teleport dest (can overlap certain things) # thing 1 p - 16 PLAY "Player 1 start" thing 2 p - 16 PLAY "Player 2 start" thing 3 p - 16 PLAY "Player 3 start" thing 4 p - 16 PLAY "Player 4 start" thing 11 p t 16 PLAYF1 "Deathmatch start" thing 14 p t 16 TFOG "Teleport exit" thing 2005 w n 20 CSAW "Chainsaw" thing 2001 w n 20 SHOT "Shotgun" thing 2002 w n 20 MGUN "Chaingun" thing 2003 w n 20 LAUN "Rocket launcher" thing 2004 w n 20 PLAS "Plasma gun" thing 2006 w n 20 BFUG "BFG9000" thing 2007 a n 20 CLIP "Clip" thing 2048 a n 20 AMMO "Box of bullets" thing 2008 a n 20 SHEL "Shells" thing 2049 a n 20 SBOX "Box of shells" thing 2010 a n 20 ROCK "Rocket" thing 2046 a n 20 BROK "Box of rockets" thing 2047 a n 20 CELL "Energy cell" thing 17 a n 20 CELP "Box of energy cells" thing 8 b n- 20 BPAK "Backpack of ammo" thing 2022 b nl 20 PINV "Invulnerability" thing 2023 b nl 20 PSTR "Berserk" thing 2024 b nl 20 PINS "Partial invisibility" thing 2025 b nl 20 SUIT "Radiation suit" thing 2026 b n- 20 PMAP "Computer map" thing 2045 b nl 20 PVIS "Light amp. goggles" thing 2011 h n- 20 STIM "Stimpack" thing 2012 h n- 20 MEDI "Medikit" thing 2013 h nl 20 SOUL "Supercharge" thing 2014 h n- 20 BON1 "Health bonus" thing 2015 h n- 20 BON2 "Armor bonus" thing 2018 h nl 20 ARM1 "Green Armor" thing 2019 h nl 20 ARM2 "Blue Armor" thing 5 k nl 20 BKEY "Blue keycard" thing 6 k nl 20 YKEY "Yellow keycard" thing 13 k nl 20 RKEY "Red keycard" thing 40 k nl 20 BSKU "Blue skull key" thing 39 k nl 20 YSKU "Yellow skull key" thing 38 k nl 20 RSKU "Red skull key" thing 15 g n 16 PLAYN "Dead player (green)" thing 18 g n 20 POSSL "Dead trooper" thing 19 g n 20 SPOSL "Dead sergeant" thing 20 g n 20 TROOM "Dead imp" thing 21 g n 16 SARGN "Dead demon" thing 22 g n 16 HEADL "Dead cacodemon" thing 23 g n 16 SKULK "Dead lost soul" thing 2035 d - 10 BAR1 "Barrel" thing 48 d - 16 ELEC "Technical column" thing 30 d - 16 COL1 "Tall green pillar" thing 32 d - 16 COL3 "Tall red pillar" thing 31 d - 16 COL2 "Short green pillar" thing 33 d - 16 COL4 "Short red pillar" thing 36 d - 16 COL5 "Pillar w/heart" thing 37 d - 16 COL6 "Red pillar w/skull" thing 41 d l 16 CEYE "Evil eye" thing 42 g l 16 FSKU "Floating skulls" thing 47 d - 16 SMIT "Brown stub" thing 54 d - 32 TRE2 "Brown tree" thing 43 d - 16 TRE1 "Grey tree" thing 10 g n 16 PLAYW "Mushed player" thing 12 g n 16 PLAYW "Mushed player 2" thing 24 g n 16 POL5 "Pool of blood" thing 27 g - 16 POL4 "Pole with skull" thing 28 g - 16 POL2 "Skewer with heads" thing 29 g l 16 POL3 "Pile of skulls" thing 25 g - 16 POL1 "Impaled body" thing 26 g - 16 POL6 "Impaled twitching" thing 49 g c 16 GOR1 "Swaying body" thing 63 g cn 16 GOR1 "Swaying body /n" thing 50 g c 16 GOR2 "Hanging arms out" thing 59 g cn 16 GOR2 "Hanging arms out /n" thing 53 g c 16 GOR5 "Hanging leg" thing 62 g cn 16 GOR5 "Hanging leg /n" thing 51 g c 16 GOR3 "Hanging one-legged" thing 61 g cn 16 GOR3 "Hanging one-legged /n" thing 52 g c 16 GOR4 "Hanging torso" thing 60 g cn 16 GOR4 "Hanging torso /n" thing 2028 l l 16 COLU "Lamp" thing 34 l ln 16 CAND "Candle" thing 35 l l 16 CBRA "Candelabra" thing 44 l l 16 TBLU "Tall blue torch" thing 45 l l 16 TGRN "Tall green torch" thing 46 l l 16 TRED "Tall red torch" thing 55 l l 16 SMBT "Short blue torch" thing 56 l l 16 SMGT "Short green torch" thing 57 l l 16 SMRT "Short red torch" thing 70 l l 16 FCAN "Burning barrel" thing 3004 m - 20 POSS "Trooper" thing 9 m - 20 SPOS "Sergeant" thing 3001 m - 20 TROO "Imp" thing 3002 m - 30 SARG "Demon" thing 3003 m - 24 BOSS "Baron of Hell" thing 58 m i 30 SARG "Spectre" thing 3006 m l 16 SKUL "Lost soul" thing 3005 m - 31 HEAD "Cacodemon" thing 7 m - 128 SPID "Spider Mastermind" thing 16 m - 40 CYBR "Cyberdemon" eureka-editor-eureka-2.0.2/common/gen_types.ugh000066400000000000000000000072121464327712600215350ustar00rootroot00000000000000#------------------------------------------------------------------------ # BOOM GENERALIZED TYPES #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2016 Andrew Apted # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ # # This information comes from the "BOOM reference v1.3" document. # #------------------------------------------------------------------------ gen_line d 0x3c00 0x0400 "DOOR" gen_field 3 0 7 "Trigger" W1 WR S1 SR G1 GR D1 DR gen_field 2 5 0 "Kind" "Normal" "STAY OPEN" "Close+Open" "Closes" gen_field 2 3 1 "Speed" SLOW Medium Fast Turbo gen_field 2 8 1 "Delay" "1 sec" "4 secs" "9 secs" "30 secs" gen_field 1 7 0 "Monsters" no MONSTER gen_line k 0x3800 0x0400 "KEYED DOOR" gen_field 3 0 6 "Trigger" W1 WR S1 SR G1 GR D1 DR gen_field 3 6 1 "Keys" "Any key" "Red Card" "Blue Card" "Yellow Card" "Red Skull" "Blue Skull" "Yellow Skull" "ALL KEYS" gen_field 1 9 1 "Matching" Precise skull=card gen_field 2 3 1 "Speed" SLOW Medium Fast Turbo gen_field 1 5 1 "Stay Mode" "Closes" "STAY OPEN" # Note: "Model" and "Monsters" share the same bit position. # The code takes care to enable the approprite one. gen_line f 0x6000 0x2000 "FLOOR" gen_field 3 0 0 "Trigger" W1 WR S1 SR G1 GR D1 DR gen_field 1 6 0 "Direction" Down UP gen_field 3 7 1 "Target" "Highest Floor" "Lowest Floor" "Next Floor" "Lowest CEIL" "CEILING" "By texture" "24 units" "32 units" gen_field 2 3 1 "Speed" SLOW Medium Fast Turbo gen_field 2 10 0 "Change" "NONE" "Tex+zero" "Texture" "Tex+type" gen_field 1 5 0 "Model" Trigger Numeric gen_field 1 5 0 "Monsters" no MONSTER gen_field 1 12 0 "Crush" no CRUSH gen_line c 0x4000 0x2000 "CEILING" gen_field 3 0 0 "Trigger" W1 WR S1 SR G1 GR D1 DR gen_field 1 6 1 "Direction" Down UP gen_field 3 7 0 "Target" "Highest Ceil" "Lowest Ceil" "Next Ceil" "Highest Floor" "FLOOR" "By texture" "24 units" "32 units" gen_field 2 3 1 "Speed" SLOW Medium Fast Turbo gen_field 2 10 0 "Change" "NONE" "Tex+zero" "Texture" "Tex+type" gen_field 1 5 0 "Model" Trigger Numeric gen_field 1 5 0 "Monsters" no MONSTER gen_field 1 12 0 "Crush" no CRUSH gen_line l 0x3400 0x0400 "LIFT" gen_field 3 0 1 "Trigger" W1 WR S1 SR G1 GR D1 DR gen_field 2 8 0 "Target" "Lowest Floor" "Next Floor" "Lowest CEIL" "PERPETUAL" gen_field 2 3 1 "Speed" SLOW Medium Fast Turbo gen_field 2 6 1 "Delay" "1 sec" "3 secs" "5 secs" "10 secs" gen_field 1 5 0 "Monsters" no MONSTER gen_line s 0x3000 0x0400 "STAIR" gen_field 3 0 2 "Trigger" W1 WR S1 SR G1 GR D1 DR gen_field 1 8 1 "Direction" Down UP gen_field 2 6 1 "Step" "4 units" "8 units" "16 units" "24 units" gen_field 2 3 1 "Speed" SLOW Medium Fast Turbo gen_field 1 5 0 "Monsters" no MONSTER gen_field 1 9 0 "Tex Match" "Same tex" "ANY TEX" gen_line r 0x2f80 0x0080 "CRUSHER" gen_field 3 0 0 "Trigger" W1 WR S1 SR G1 GR D1 DR gen_field 2 3 0 "Speed" SLOW Medium Fast Turbo gen_field 1 5 0 "Monsters" no MONSTER gen_field 1 6 0 "Silent" no SILENT eureka-editor-eureka-2.0.2/common/hexen_groups.ugh000066400000000000000000000022061464327712600222440ustar00rootroot00000000000000#------------------------------------------------------------------------ # HEXEN LINE CATEGORIES #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2016 Andrew Apted # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ linegroup a "Animated" linegroup c "Ceiling" linegroup d "Door" linegroup e "Elevator" linegroup f "Floor" linegroup g "Lift" linegroup k "Scripting" linegroup l "Lighting" linegroup p "Polyobj" linegroup q "Stairs" linegroup r "Renderer" linegroup s "Sector" linegroup t "Thing" linegroup u "Teleport" linegroup x "Exits" linegroup - "OTHER" eureka-editor-eureka-2.0.2/common/hexen_lines.ugh000066400000000000000000000130401464327712600220350ustar00rootroot00000000000000#------------------------------------------------------------------------ # HEXEN LINE and THING SPECIALS #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2015 Ioan Chera # Copyright (C) 2015-2016 Andrew Apted # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ # # Thanks to the the Official Hexen Specs by Ben Morris (et al). # See http://doomlegacy.sourceforge.net/hosted/hexenspec09.txt # #------------------------------------------------------------------------ # Floors and lifts special 20 f "Floor_Lower" :tag speed dist special 21 f "Floor_Lower /lowest" :tag speed special 22 f "Floor_Lower /nearest" :tag speed special 23 f "Floor_Raise" :tag speed dist special 24 f "Floor_Raise /highest" :tag speed special 25 f "Floor_Raise /nearest" :tag speed special 28 f "Floor_Raise /crush" :tag speed damage special 35 f "Floor_Raise x8" :tag speed dist_x8 special 36 f "Floor_Lower x8" :tag speed dist_x8 special 66 f "Floor_Lower /instant" :tag - dist special 67 f "Floor_Raise /instant" :tag - dist special 68 f "Floor_MoveTo x8" :tag speed height_x8 negate? special 46 f "Floor_CrushStop" :tag special 138 f "Floor_Waggle" :tag amp speed offset time special 62 g "Plat_DownWaitUp" :tag speed delay special 63 g "Plat_Down" :tag speed delay dist special 64 g "Plat_UpWaitDown" :tag speed delay special 65 g "Plat_Up" :tag speed delay dist special 60 g "Plat_Perpetual" :tag speed delay special 61 g "Plat_Stop" :tag special 26 q "Stairs_Down" :tag speed dist delay reset special 27 q "Stairs_Up" :tag speed dist delay reset special 31 q "Stairs_Down /sync" :tag speed dist reset special 32 q "Stairs_Up /sync" :tag speed dist reset # Ceiling and doors special 40 c "Ceiling_Lower" :tag speed dist special 41 c "Ceiling_Raise" :tag speed dist special 69 c "Ceiling_MoveTo x8" :tag speed height_x8 negate? special 42 c "Ceiling_Crush /perpet" :tag speed damage special 43 c "Ceiling_Crush " :tag speed damage special 45 c "Ceiling_CrushAndUp" :tag speed damage special 44 c "Ceiling_CrushStop" :tag special 10 d "Door_Close" :tag speed special 11 d "Door_Open" :tag speed special 12 d "Door_Raise" :tag speed delay special 13 d "Door_Locked" :tag speed delay lock # Lighting special 110 l "Light_Raise" :tag light special 111 l "Light_Lower" :tag light special 112 l "Light_Set" :tag light special 113 l "Light_Fade" :tag light time special 114 l "Light_Glow" :tag high low time special 115 l "Light_Flicker" :tag high low special 116 l "Light_Strobe" :tag high low hightime lowtime special 109 l "Force Lightning" mode # Thing specials special 72 t "Push Thing" angle dist special 73 t "Damage Thing" damage special 130 t "Thing_Activate" :tid special 131 t "Thing_Deactivate" :tid special 132 t "Thing_Remove" :tid special 133 t "Thing_Destroy" :tid special 134 t "Thing_Launch" :tid type angle speed vspeed special 136 t "Thing_Launch /grav" :tid type angle speed vspeed special 135 t "Thing_Spawn" :tid type angle special 137 t "Thing_Spawn /silent" :tid type angle # Polyobj specials special 1 p "Polyobj_Start" :po mirror:po sound_seq special 5 p "Polyobj_Explicit" :po order mirror:po sound_seq special 2 p "Polyobj_RotateL" :po speed angle special 3 p "Polyobj_RotateR" :po speed angle special 4 p "Polyobj_Move" :po speed angle dist special 6 p "Polyobj_Move x8" :po speed angle dist special 7 p "Polyobj_DoorSwing" :po speed angle delay special 8 p "Polyobj_DoorSlide" :po speed angle dist delay special 90 p "Polyobj_RotateL /OR" :po speed angle special 91 p "Polyobj_RotateR /OR" :po speed angle special 92 p "Polyobj_Move /OR" :po speed angle dist special 93 p "Polyobj_Move x8 /OR" :po speed angle dist # Miscellaneous special 0 - "NOTHING" special 29 e "Pillar_Build" :tag speed dist special 30 e "Pillar_Open" :tag speed f_dist c_dist special 94 e "Pillar_Crush" :tag speed dist damage special 95 e "Elevator_Lower" :tag speed dist special 96 e "Elevator_Raise" :tag speed dist special 80 k "ACS_Execute" script map param1 param2 param3 special 83 k "ACS_Execute /lock" script map param1 param2 lock special 81 k "ACS_Suspend" script map special 82 k "ACS_Terminate" script map special 121 - "Line_SetIdent" id_number:self_line_id special 100 a "Scroll_Left" speed special 101 a "Scroll_Right" speed special 102 a "Scroll_Up" speed special 103 a "Scroll_Down" speed special 129 - "UsePuzzleItem" item script param1 param2 param3 special 140 - "Change Sound" :tag sound_seq special 120 - "Earthquake" intensity duration damrad tremrad :tid special 70 u "Teleport" :tid special 71 u "Teleport /silent" :tid special 74 x "Exit_ToMap" map position special 75 x "End_Game" eureka-editor-eureka-2.0.2/common/hexen_sectors.ugh000066400000000000000000000046621464327712600224170ustar00rootroot00000000000000#------------------------------------------------------------------------ # HEXEN SECTOR TYPES #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2015 Ioan Chera # Copyright (C) 2015-2018 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ # # Thanks to the the Official Hexen Specs by Ben Morris (et al). # See http://doomlegacy.sourceforge.net/hosted/hexenspec09.txt # #------------------------------------------------------------------------ sector 0 "NOTHING" # NOTE: sector type #9 is allowed by the vanilla Hexen engine # but it is effectively inert. sector 1 "Phased Light" sector 2 "Light Seq Start" sector 3 "Light Seq Next 1" sector 4 "Light Seq Next 2" sector 26 "Next Stair 1" sector 27 "Next Stair 2" sector 40 "Wind E /slow" sector 41 "Wind E /med" sector 42 "Wind E /fast" sector 43 "Wind N /slow" sector 44 "Wind N /med" sector 45 "Wind N /fast" sector 46 "Wind S /slow" sector 47 "Wind S /med" sector 48 "Wind S /fast" sector 49 "Wind W /slow" sector 50 "Wind W /med" sector 51 "Wind W /fast" sector 198 "Indoor Lightning /64" sector 199 "Indoor Lightning /32" sector 200 "Alternate Sky" sector 201 "Scroll N /slow" sector 202 "Scroll N /med" sector 203 "Scroll N /fast" sector 204 "Scroll E /slow" sector 205 "Scroll E /med" sector 206 "Scroll E /fast" sector 207 "Scroll S /slow" sector 208 "Scroll S /med" sector 209 "Scroll S /fast" sector 210 "Scroll W /slow" sector 211 "Scroll W /med" sector 212 "Scroll W /fast" sector 213 "Scroll NW /slow" sector 214 "Scroll NW /med" sector 215 "Scroll NW /fast" sector 216 "Scroll NE /slow" sector 217 "Scroll NE /med" sector 218 "Scroll NE /fast" sector 219 "Scroll SE /slow" sector 220 "Scroll SE /med" sector 221 "Scroll SE /fast" sector 222 "Scroll SW /slow" sector 223 "Scroll SW /med" sector 224 "Scroll SW /fast" eureka-editor-eureka-2.0.2/common/plutonia_tex.ugh000066400000000000000000000042001464327712600222450ustar00rootroot00000000000000#------------------------------------------------------------------------ # PLUTONIA EXPERIMENT (Final Doom) textures #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2016 Andrew Apted # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ texture h A-ASKIN1 texture h A-ASKIN2 texture h A-ASKIN3 texture h A-ASKIN4 texture h A-ASKIN5 texture u A-BRBRK texture u A-BRBRK2 texture u A-BRICK1 texture u A-BRICK2 texture u A-BRICK3 texture u A-BROCK2 texture u A-BROWN1 texture u A-BROWN2 texture u A-BROWN3 texture u A-BROWN4 texture u A-BROWN5 texture u A-CONCTE texture u A-DBRI1 texture u A-DBRI2 texture u A-GRATE texture u A-MARBLE texture u A-MOSBRI texture u A-MYWOOD texture u A-TILE texture u A-VINE3 texture u A-WOOD1 texture u SLIME1 texture u SLIME2 texture u SLIME3 texture u SLIME4 texture u SLIME5 texture u SLIME8 texture n A-CAMO1 texture n A-CAMO2 texture n A-CAMO3 texture n A-CAMO4 texture n A-CAMO5 texture n A-DROCK1 texture n A-DROCK2 texture n A-MOSRK2 texture n A-MOSROK texture n A-MOULD texture n A-MUD texture n A-REDROK texture n A-ROCK texture n A-VINE1 texture n A-VINE2 texture n A-VINE4 texture n A-VINES texture n AROCK2 texture n AROCK3 texture n AROCK4 texture n AROCK5 texture n MC2 texture n MC3 texture n MC4 texture n MC5 texture n MC6 texture n MC7 texture n MC8 texture n MC10 texture n MC11 texture n MC12 texture n MC13 texture n MC14 texture n MC15 texture n MC16 texture n MC17 texture n MC18 texture n MC19 texture n WFALL1 texture n WFALL2 texture n WFALL3 texture n WFALL4 texture t A-POIS texture t A-RAIL1 texture t A-YELLOW eureka-editor-eureka-2.0.2/common/tnt_tex.ugh000066400000000000000000000062601464327712600212270ustar00rootroot00000000000000#------------------------------------------------------------------------ # TNT EVILUTION (Final Doom) textures #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2016 Andrew Apted # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ texturegroup c "Crates" texturegroup e "Egypt" texture c CR128HGB texture c CR128LB texture c CR128LG texture c CR64HBB texture c CR64HBBP texture c CR64HBG texture c CR64HBRM texture c CR64HGB texture c CR64HGBP texture c CR64HGG texture c CR64LB texture c CR64LG texture c CR64SLGB texture c CRAWHBP texture c CRAWLBP texture c CRBLWDH6 texture c CRBWDH64 texture c CRBWDL12 texture c CRBWHBP texture c CRBWLBP texture c CRLWDH6 texture c CRLWDH6B texture c CRLWDL12 texture c CRLWDL6 texture c CRLWDL6B texture c CRLWDL6C texture c CRLWDL6D texture c CRLWDL6E texture c CRLWDS6 texture c CRLWDT3 texture c CRLWDVS texture c CRSMB texture c CRTINYB texture c CRWDH64 texture c CRWDH64B texture c CRWDL128 texture c CRWDL64A texture c CRWDL64B texture c CRWDL64C texture c CRWDS64 texture c CRWDT32 texture e BIGMURAL texture e BIGWALL texture e DRFRONT texture e DRSIDE1 texture e DRSIDE2 texture e DRTOPFR texture e DRTOPSID texture e LONGWALL texture e MURAL1 texture e MURAL2 texture e PILLAR texture e SKIRTING texture h MTNT1 texture n ALTAQUA texture n ASPHALT texture n CARLLF1 texture n CARLLF2 texture n CARLRT1 texture n CARLRT2 texture n CAVERN1 texture n CAVERN4 texture n CAVERN5 texture n CAVERN6 texture n CAVERN7 texture n GRNOPEN texture n FALL3 texture n REDOPEN texture n WFALL1 texture n WFALL4 texture u BRNOPEN texture u CUBICLE texture u DISASTER texture u DOBWIRE texture u DOBWIRE2 texture u DOGLDIR texture u DOGLPANL texture u DOGRID texture u DOGRMSC texture u DOKGRIR texture u DOKODO1B texture u DOKODO2B texture u DOPUNK4 texture u DORED texture u DOWINDOW texture u GRNMEN texture u PNK4EXIT texture u SMGLASS1 texture u SMSTONE6 texture u STONEW1 texture u STONEW5 texture u STWALL texture u TYIRONLG texture u TYIRONSM texture u TYUNDER1 texture u TYWHEEL1 texture u WEBL texture u WEBR texture t BTNTMETL texture t BTNTSLVR texture t DOC1 texture t EGGREENI texture t EGREDI texture t EGSUPRT3 texture t LITEGRN1 texture t LITERED1 texture t LITERED2 texture t LITEYEL1 texture t LITEYEL2 texture t LITEYEL3 texture t METAL-BD texture t METAL-RM texture t METAL2BD texture t METALDR texture t M_RDOOR texture t M_TEC texture t M_YDOOR texture t SLAD2 texture t SLAD3 texture t SLAD4 texture t SLAD5 texture t SLAD6 texture t SLAD7 texture t SLAD8 texture t SLAD9 texture t SLAD10 texture t SLAD11 texture t SLADRIP1 texture t SLADRIP3 texture t TNTDOOR texture t YELMETAL eureka-editor-eureka-2.0.2/defaults.cfg000066400000000000000000000022551464327712600200350ustar00rootroot00000000000000# Eureka default configuration auto_load_recent 0 begin_maximized 0 backup_max_files 30 backup_max_space 60 browser_small_tex 0 bsp_on_save 1 bsp_fast 0 bsp_warnings 0 bsp_split_factor 11 bsp_gl_nodes 1 bsp_force_v5 0 bsp_force_zdoom 0 bsp_compressed 0 default_gamma 2 default_edit_mode 3 default_port vanilla dotty_axis_col 0080ff dotty_major_col 0000ee dotty_minor_col 0000bb dotty_point_col 0000ff floor_bump_small 1 floor_bump_medium 8 floor_bump_large 64 grid_default_mode 0 grid_default_size 64 grid_default_snap 0 grid_hide_in_free_mode 0 grid_style 0 gui_theme 1 gui_color_set 1 gui_custom_bg ccd5dd gui_custom_ig ffffff gui_custom_fg 000000 leave_offsets_alone 1 light_bump_small 4 light_bump_medium 16 light_bump_large 64 map_scroll_bars 1 minimum_drag_pixels 5 new_islands_are_void 0 new_sector_size 128 normal_axis_col 0080ff normal_main_col 0000ee normal_flat_col 3c3c78 normal_small_col 3c3c78 panel_gamma 2 render_pix_aspect 83 render_high_detail 0 render_lock_gravity 0 render_missing_bright 1 render_unknown_bright 1 same_mode_clears_selection 0 sector_render_default 1 show_full_one_sided 0 sidedef_add_del_buttons 0 thing_render_default 1 transparent_col 00ffff swap_sidedefs 0 eureka-editor-eureka-2.0.2/docs/000077500000000000000000000000001464327712600164715ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/docs/History.txt000066400000000000000000035071531464327712600207110ustar00rootroot00000000000000__________________ REPOSITORY HISTORY __________________ This file contains commit logs from several different repositories, in reverse chronological order (from newest to oldest). When I first created Eureka (forking from Yadex), I just made all the changes on my hard-drive -- without using any source control at all. Hence there are no change logs from that period. After a while, I developed the code on the EDGE SVN repository, and later moved the code to the AwwPorts repository and continued developing it there. Eventually I made a preview version available on the DoomWorld forums to see if there was any interest, and then registered a SourceForge project for it, and the code repository got moved yet again. In January 2016 the SVN repository was converted into a GIT repository (still on SourceForge though). ==================================================== CURRENT DEVELOPMENT (GIT) ==================================================== ------------------------------------------------------------------------ 805f280c4502 | Andrew Apted | 2018-08-05 20:10:14 +1000 CHANGELOG : added a missing item. ------------------------------------------------------------------------ ff3c215b9698 | Andrew Apted | 2018-08-05 19:44:21 +1000 README : updated the date. ------------------------------------------------------------------------ a8dc678a77da | Andrew Apted | 2018-08-05 19:39:59 +1000 CHANGELOG : tidied up for the release. ------------------------------------------------------------------------ 20809fa092e6 | Andrew Apted | 2018-08-05 19:30:27 +1000 honor defaults for sector/sprite rendering when opening new maps. ------------------------------------------------------------------------ e35bd815e310 | Andrew Apted | 2018-08-05 19:15:55 +1000 preferences : a setting for default sprite rendering (on/off). ------------------------------------------------------------------------ 181480403d86 | Andrew Apted | 2018-08-05 18:29:53 +1000 canvas : disable sector rendering when in error mode. ------------------------------------------------------------------------ b3179498cbda | Andrew Apted | 2018-08-05 18:22:01 +1000 CHANGELOG and TODO update. ------------------------------------------------------------------------ 686cc40428f9 | Andrew Apted | 2018-08-05 18:19:43 +1000 canvas : ensure the sector cache is invalidated when necessary. ------------------------------------------------------------------------ d23b8b0b8a63 | Andrew Apted | 2018-08-05 17:55:07 +1000 canvas : quickly reject off-screen sectors in RenderSector(). This uses the new sector_info cache. This test and the reduced linedef range to iterate over has already massively improved the sector rendering performace on huge maps (when the whole map is not in view, at least). ------------------------------------------------------------------------ 93c1f08fc392 | Andrew Apted | 2018-08-05 17:39:00 +1000 canvas : added a sector_info cache which remembers some sector info. So far the cache stores the linedef range used by sectors, and also the bounding box of each sector. RenderSector() will use the cache to help speed up sector rendering. ------------------------------------------------------------------------ 6747daff609a | Andrew Apted | 2018-08-05 15:59:41 +1000 CHANGELOG and TODO update. ------------------------------------------------------------------------ 8cbd07da0449 | Andrew Apted | 2018-08-05 15:51:17 +1000 canvas : speed up drawing selection when it has many sectors. This affected all OSes (not just X windows), especially in maps with a huge number of linedefs. The slowdown was caused by iterating over the selected sectors one-by-one, and for each sector we iterated over ALL the linedefs. This commit uses a better method when the selection mode is OBJ_SECTORS and the number of sectors is large. It performs just a single iteration over the linedefs. ------------------------------------------------------------------------ dd45516e3d87 | Andrew Apted | 2018-08-05 15:33:00 +1000 canvas : speed up drawing the selection under X windows. ------------------------------------------------------------------------ 7f2651e73f68 | Andrew Apted | 2018-08-05 15:19:43 +1000 canvas : moved fl_line_style() calls out of DrawMapVector(). This is preliminary work to speed up drawing of the selection, which is greatly slowed down under X windows by all the calls to fl_line_style(). ------------------------------------------------------------------------ 638b74924669 | Andrew Apted | 2018-08-05 14:44:47 +1000 canvas : reworked DrawHighlight() to minimize color changes. Includes splitting off some code --> DrawTagged() method. ------------------------------------------------------------------------ 0e9a99b631e0 | Andrew Apted | 2018-08-05 14:14:44 +1000 canvas : small speed up of DrawThings() and DrawThingBodies(). ------------------------------------------------------------------------ 08ed828a2231 | Andrew Apted | 2018-08-05 13:15:40 +1000 canvas : big speed up of DrawLinedefs() under X windows. It turned out that FLTK's fl_color() under X windows is very very slow. This commit works around that issue by iterating over the lines multiple times, drawing e.g. all LIGHTGREY lines in a single pass. ------------------------------------------------------------------------ 28117740dea9 | Andrew Apted | 2018-08-04 22:35:46 +1000 preferences : moved sector rendering setting --> Grid tab. ------------------------------------------------------------------------ 227054a4c2ff | Andrew Apted | 2018-08-04 22:22:00 +1000 wad code : in ReadDirectory, detect invalid lumps. In other words, detect lumps with where the start or length are negative or beyond the end of the wad file. When found, we log a warning message and clear the lump (make it empty), since an invalid position would lead to an error or assertion failure later on (e.g. when saving). ------------------------------------------------------------------------ 4f0f9d2746ae | Andrew Apted | 2018-08-04 16:06:39 +1000 TODO update. ------------------------------------------------------------------------ 7c8de6a554f9 | Andrew Apted | 2018-08-04 16:05:19 +1000 basic validation of the ACS bytecode for "Add BEHAVIOR" command. ------------------------------------------------------------------------ 74e3cb5ab9af | Andrew Apted | 2018-08-04 16:02:12 +1000 lib_file : fixed FileLoad() to handle zero-length files. ------------------------------------------------------------------------ ad2e7f803848 | Andrew Apted | 2018-08-04 15:32:13 +1000 implemented new "Add BEHAVIOR" command. This inserts a compiled ACS file as the BEHAVIOR lump of the current map. ------------------------------------------------------------------------ ab6fd9306e08 | Andrew Apted | 2018-08-03 14:51:29 +1000 wad code : better error message for "want_pos < total_size" assertion. ------------------------------------------------------------------------ 0cf8157eaad4 | Andrew Apted | 2018-08-03 13:36:08 +1000 ZDoom : render point-light things as a yellow ball sprite. These things use a fake sprite name "_LYT", and the sprite is generated by some code. ------------------------------------------------------------------------ 888ee2aba6ff | Andrew Apted | 2018-08-03 12:55:46 +1000 INSTALL.txt : describe compilation of the Windows binary. There is also a small section for MacOS X, which merely refers the reader to the documents in the osx/ folder. ------------------------------------------------------------------------ bdc27218d3b9 | Andrew Apted | 2018-08-02 23:48:15 +1000 TODO and CHANGELOG update. ------------------------------------------------------------------------ a9875d7be4e7 | Andrew Apted | 2018-08-02 23:43:54 +1000 Checks : improved fixer for non-animating switch textures. The fixer now takes into account whether the lower and/or upper texture is visible or not (due to sector heights), and prefers to clear the one(s) which are not visible. ------------------------------------------------------------------------ 5f1c21199f62 | Andrew Apted | 2018-07-22 20:35:17 +1000 Version bumped after recent WIP test package. ------------------------------------------------------------------------ 7b360b027f8b | Andrew Apted | 2018-07-22 20:30:38 +1000 View Logs : always show/raise the log viewer window. ------------------------------------------------------------------------ 26e85f719fd6 | Andrew Apted | 2018-07-22 19:06:07 +1000 fixed clumsiness in missing IWAD dialog (hide the Setup button). ------------------------------------------------------------------------ 6d743345bae2 | Andrew Apted | 2018-07-22 18:54:05 +1000 fixed spurious warning dialog about incompatible ports. For example, specifying --wad as "tnt" and --port "boom" would trigger the incompatible port warning dialog. The compatibility checking code was not handling game variants (e.g. "tnt" is marked as a variant of "doom2"). ------------------------------------------------------------------------ d109b4628cd7 | Andrew Apted | 2018-07-22 18:07:56 +1000 CHANGELOG : added recent changes (not yet prettified). ------------------------------------------------------------------------ d7484099f502 | Andrew Apted | 2018-07-22 18:07:00 +1000 grid : when changing size via keyboard, ensure grid is shown. ------------------------------------------------------------------------ 9178e56aa4ce | Andrew Apted | 2018-07-22 18:01:14 +1000 preferences : a setting for default sector rendering (on/off). ------------------------------------------------------------------------ bd1cbc6eed76 | Andrew Apted | 2018-07-22 17:09:26 +1000 removed config var "require_click_to_focus" + preference setting. This has been solved in a way not requiring an extra setting (see previous commit). ------------------------------------------------------------------------ 7fe0f9e5edd6 | Andrew Apted | 2018-07-22 17:01:36 +1000 Linux/X11 : detect when our main window has "true" focus. We do this by looking directly at the raw XEvents, because FLTK does not provide the functionality needed. When we don't have the true focus, then we never grab the focus when the mouse hovers over the canvas/render widget. This should fix ticket #22 once and for all. ------------------------------------------------------------------------ 00a18a8c9127 | Andrew Apted | 2018-07-22 16:01:11 +1000 Preferences : better name for add/del button setting. ------------------------------------------------------------------------ 5459891116ea | Andrew Apted | 2018-07-22 15:55:59 +1000 PORTS / ZDoom : added gzdoom PointLight things (9800-9824). ------------------------------------------------------------------------ 798927a3d21c | Andrew Apted | 2018-07-22 15:44:48 +1000 PORTS / ZDoom : added zdoom hexen-format sector specials. Specifically: the sector types 65-87, and 195-200. These are ZDoom-ism which don't exist in vanilla Hexen. ------------------------------------------------------------------------ 82c7390f8367 | Andrew Apted | 2018-07-04 16:30:17 +1000 moved several menu commands to a new "Tools" menu. The commands are: Preferences, Test Map, Build All Nodes, Edit Text Lump, and View Logs. ------------------------------------------------------------------------ 34b25c12059f | Andrew Apted | 2018-07-02 00:25:56 +1000 TODO update. ------------------------------------------------------------------------ 66d3a8f88755 | Andrew Apted | 2018-07-02 00:21:00 +1000 Merge branch 'master' of ssh://git.code.sf.net/p/eureka-editor/git ------------------------------------------------------------------------ 28bead6e36f5 | Andrew Apted | 2018-07-02 00:20:10 +1000 Sector panel : added a "fresh" button for getting the next free tag. ------------------------------------------------------------------------ 4186af94e186 | Ioan Chera | 2018-06-30 22:03:29 +0300 osx: fixed bad dependency on resolved symbolic link paths ------------------------------------------------------------------------ 51ff0cd2abb7 | Ioan Chera | 2018-06-30 21:44:26 +0300 Updated the osx app version and removed a year-dependend plist entry ------------------------------------------------------------------------ 25c17aee1c5b | Ioan Chera | 2018-06-30 21:44:06 +0300 Fixed Xcode developer ID settings ------------------------------------------------------------------------ 4a1f991ab1b4 | Ioan Chera | 2018-06-30 21:40:24 +0300 Cleared all warnings from Xcode project ------------------------------------------------------------------------ 735669adf8b6 | Ioan Chera | 2018-06-30 21:32:34 +0300 Ignore downloaded files in osx/ ------------------------------------------------------------------------ 511ff12a5526 | Ioan Chera | 2018-06-30 21:28:34 +0300 osx Xcode project now automatically downloads FLTK so you don't need to prepare dependencies yourself. ------------------------------------------------------------------------ e59b6a49891c | Ioan Chera | 2018-04-24 19:58:56 +0300 Updated debug settings for Xcode project ------------------------------------------------------------------------ a83bb431b7c8 | Andrew Apted | 2018-06-28 00:25:25 +1000 Checks : find and fix non-animating switch textures. These are linedefs where a switch texture won't animate because there is another switch texture in an unseed part (e.g. in the upper of a 1S wall) and the DOOM engine finds and changes that texture (and not the visible one). ------------------------------------------------------------------------ f9d36bb29140 | Andrew Apted | 2018-06-27 23:23:49 +1000 Checks : small fix for transparent-texture-on-solid-wall fixer. Previous we blindly used the default wall texture, assuming it was never transparent. This commit checks it, and if so falls back to something reasonable. ------------------------------------------------------------------------ 14f700f02326 | Andrew Apted | 2018-06-27 22:48:42 +1000 Makefiles : added --std=c++03 compiler flag. This specifies that the C++ standard of the code is the original C++ plus the amendments from 2003. I'm not sure this flag is truly needed, but it does serve as a reminder that the code may not live up to modern standards. ------------------------------------------------------------------------ a02df53871ae | Andrew Apted | 2018-06-27 19:12:00 +1000 misc : checked in my FLTK 1.3 patch for nicer menu dividers. ------------------------------------------------------------------------ cd030fa98211 | Andrew Apted | 2018-06-24 14:10:29 +1000 fixed version in Win32 RC file. ------------------------------------------------------------------------ 15e463f06566 | Andrew Apted | 2018-06-23 23:21:34 +1000 CHANGELOG : re-organized and made pretty. ------------------------------------------------------------------------ bac2d27a9f6d | Andrew Apted | 2018-06-23 22:54:29 +1000 handle text files containing a Unicode BOM (byte-order mark). The Unicode BOM is common under Windows, but rare under Linux or MacOSX. Previously the definition file parser (etc) would fatal error if a BOM was present. Now it is simply ignored. ------------------------------------------------------------------------ 5c4cacc4860d | Andrew Apted | 2018-06-23 22:40:31 +1000 EditLump : wrote new file reading code (for "Insert" command). ------------------------------------------------------------------------ 543c31b0032b | Andrew Apted | 2018-06-23 21:32:00 +1000 added M_ReadTextLine() function, automatically strips CR/LF. ------------------------------------------------------------------------ 5f69cc73b3ee | Andrew Apted | 2018-06-23 21:02:20 +1000 EditLump : wrote new file saving code, add a BOM under Windows. The BOM is only added if the document contains Unicode (UTF-8). Linux and MacOSX never need a BOM, since UTF-8 is the norm. ------------------------------------------------------------------------ 917a6984cf4d | Andrew Apted | 2018-06-23 18:46:00 +1000 Preferences : added checkbox for "require_click_to_focus". ------------------------------------------------------------------------ bdd65ffda1c6 | Andrew Apted | 2018-06-23 18:38:03 +1000 new config variable "require_click_to_focus". Default is false (off). When true, the canvas never steals the focus when the mouse pointer passes over it. ------------------------------------------------------------------------ e8db16fb657c | Andrew Apted | 2018-06-23 17:22:47 +1000 Open Map dialog : show buttons for ALL maps via scrollable area. ------------------------------------------------------------------------ c4bf26257480 | Andrew Apted | 2018-06-23 17:08:20 +1000 UI_Scroll : support scrollbar on either side (left or right). ------------------------------------------------------------------------ b073d803cddf | Andrew Apted | 2018-06-23 15:29:42 +1000 Insert_Vertex : final refactor, fixing the "zero-length line" error. ------------------------------------------------------------------------ 8fc86f8b864b | Andrew Apted | 2018-06-23 14:47:30 +1000 turn off more debugging noise (dangling vertices). ------------------------------------------------------------------------ 24e2ae32628f | Andrew Apted | 2018-06-23 01:18:56 +1000 Checks / Lines : fixed alignment of buttons. ------------------------------------------------------------------------ 09a1013c20c6 | Andrew Apted | 2018-06-23 01:02:49 +1000 Insert_Vertex : yet more refactoring. The solution to the "Bug detected ..." fatal error is getting closer. Should be able to fix it tomorrow. This commit also turns off some debugging noise on stderr. ------------------------------------------------------------------------ 7c0d2b3a7c3a | Andrew Apted | 2018-06-23 00:31:00 +1000 Insert_Vertex : more refactoring (logic should be unchanged). ------------------------------------------------------------------------ 1f0e16d26088 | Andrew Apted | 2018-06-22 23:37:40 +1000 refactored the Insert_Vertex() code, no changes in the logic. ------------------------------------------------------------------------ 73b3c5b45f44 | Andrew Apted | 2018-06-22 21:57:22 +1000 TODO update. ------------------------------------------------------------------------ 0a54dbdb7015 | Andrew Apted | 2018-06-22 21:56:32 +1000 Checks : fixed merging multiple groups of overlapping vertices. ------------------------------------------------------------------------ ea60f52b6fa5 | Andrew Apted | 2018-06-22 20:44:31 +1000 added VIM syntax file for editing definition (.ugh) files. ------------------------------------------------------------------------ 5c922ee5c16f | Andrew Apted | 2018-06-22 18:54:27 +1000 tidy up misc/ -- removed obsolete crud about the "up" language. ------------------------------------------------------------------------ bc725f701edb | Andrew Apted | 2018-06-22 18:46:15 +1000 Find/Replace : fixed to handle generalized sectors. ------------------------------------------------------------------------ 32d2531a029d | Andrew Apted | 2018-06-22 18:22:13 +1000 TODO update. ------------------------------------------------------------------------ f3be703d26fd | Andrew Apted | 2018-06-22 18:19:33 +1000 PORTS / ZDoom : support the sector bit-flags in Hexen maps. These flags are the same as the BOOM generalized sector flags, but they are shifted up 3 bits to accommodate more real types. This commit also renames the feature keyword --> "gen_sectors". ------------------------------------------------------------------------ 3b1520f67405 | Andrew Apted | 2018-06-22 16:37:03 +1000 Port defs : support new "sector_flags" feature keyword. Previously the "gen_types" feature enabled both generalized line types and sector type bitflags. They are separate now. ------------------------------------------------------------------------ c21fef8b481f | Andrew Apted | 2018-06-22 16:12:17 +1000 PORTS / ZDoom : added missing DOOM sector types (15,18-24). ------------------------------------------------------------------------ 8add11be3216 | Andrew Apted | 2018-06-22 14:56:45 +1000 Version bump to 1.23-WIP ------------------------------------------------------------------------ 7b56119f35bb | Andrew Apted | 2018-06-22 14:52:01 +1000 CHANGELOG update. ------------------------------------------------------------------------ 9cd48cc24cd9 | Andrew Apted | 2018-06-22 14:45:36 +1000 Port defs : indent stuff in an if..endif block. ------------------------------------------------------------------------ 94e685c7f4a9 | Andrew Apted | 2018-06-22 14:42:56 +1000 Game defs : prefer the "linegroup" command over "spec_group". (They are now synonymous). ------------------------------------------------------------------------ 65f6ef4135fd | Andrew Apted | 2018-06-22 14:34:44 +1000 Game def parser : support new "clear" command. This command takes one or more keywords, such as "lines" or "sectors", and clears the corresponding set of types. Use this keyword in the ZDoom port definitions to clear out the DOOM line and sector specials when the map format is HEXEN, to better support "Doom in Hexen Format" maps. ------------------------------------------------------------------------ d856b57a3d26 | Andrew Apted | 2018-06-21 23:58:51 +1000 Checks : for tag 666 checking, support Heretic in a better way. Namely by using a valid of "2" for the tag_666 feature. This is (slightly) better than comparing the game name with the string "heretic". ------------------------------------------------------------------------ d0d46a39f3d4 | Andrew Apted | 2018-06-21 23:54:05 +1000 CHANGELOG updated. ------------------------------------------------------------------------ 052d2b7b2e78 | Andrew Apted | 2018-06-21 23:48:22 +1000 warn user when port is not compatible with the current game. The dialog provides two options, one to reset the port to vanilla, and another to keep the current (invalid) port. This commit also tweaks other code related to handling the port, e.g. produce a fatal error in DeterminePort() for unknown ports specified on the command-line. Plus factored out some of the Main_LoadResources() code to separate functions. Tweaked some error messages too. ------------------------------------------------------------------------ 746a6b35a376 | Andrew Apted | 2018-06-21 22:21:59 +1000 code tidying : commented some of the IWAD handling logic. ------------------------------------------------------------------------ 74c58324ea3f | Andrew Apted | 2018-06-21 21:25:27 +1000 when no explicit port is given, check user's default makes sense. i.e. check that the default port is compatible with the IWAD. If not usable, then revert to "vanilla". ------------------------------------------------------------------------ 9272e7c1ab57 | Andrew Apted | 2018-06-21 21:08:17 +1000 minor rename : DetermineGame --> GameNameFromIWAD. ------------------------------------------------------------------------ 5ced3d495972 | Andrew Apted | 2018-06-21 20:51:18 +1000 Game defs : split off Hexen sectors --> "common/hexen_sectors.ugh" ------------------------------------------------------------------------ bae832b30acd | Andrew Apted | 2018-06-21 20:47:27 +1000 Game defs : renamed "hexen_specials.ugh" --> "hexen_lines.ugh" ------------------------------------------------------------------------ acf329526377 | Andrew Apted | 2018-06-21 20:43:55 +1000 Game defs : split "doom_specials.ugh" into two files. One file for line specials, other file for sector types. ------------------------------------------------------------------------ a2d6004d6b79 | Andrew Apted | 2018-06-21 20:39:48 +1000 Game defs : renamed "doom_specials.ugh" --> "doom_lines.ugh" ------------------------------------------------------------------------ b2c5afb122d5 | Andrew Apted | 2018-06-20 14:46:22 +1000 GAMES / Hexen : removed sector type #9 (it is basically inert). ------------------------------------------------------------------------ 34d2d422a1c6 | Andrew Apted | 2018-06-20 14:36:33 +1000 TODO : even more fun stuff to hack on.... ------------------------------------------------------------------------ 42163a47e50e | Andrew Apted | 2018-06-18 15:05:09 +1000 code tidying : removed some commented-out crud. ------------------------------------------------------------------------ a381064e1fdb | Andrew Apted | 2018-06-18 15:01:38 +1000 Makefiles : added the -fwrapv compiler flag. This ensures that integer addition overflows as expected, i.e. the value wraps around. ------------------------------------------------------------------------ 328628897af5 | Andrew Apted | 2018-06-18 14:45:03 +1000 A preference setting for raw sidedef manipulation buttons. i.e. for the existing "sidedef_add_del_buttons" config var. This closes ticket #24. ------------------------------------------------------------------------ 9dd19874605e | Andrew Apted | 2018-06-18 00:08:56 +1000 TODO update. ------------------------------------------------------------------------ 92f4eeba7cbe | Andrew Apted | 2018-06-18 00:07:11 +1000 Strife : updated Thing panel to support the new thing flags. This closes ticket #20 (for real this time). ------------------------------------------------------------------------ 693cbbafcd25 | Andrew Apted | 2018-06-17 23:29:24 +1000 Strife : define the new thing options (such as MTF_Shadow). ------------------------------------------------------------------------ 800bfdaf576f | Andrew Apted | 2018-06-17 23:09:48 +1000 Strife : support both translucency flags in the LineDef panel. ------------------------------------------------------------------------ 1e9ee6e55da5 | Andrew Apted | 2018-06-17 22:46:05 +1000 Strife : support the new linedef flags in LineDef panel. The flags are: JumpOver, BlockFloaters, Translucent1. The only new flag not supported is Translucent2, because there is not enough space in the LineDef panel. This closes ticket #20. ------------------------------------------------------------------------ fb548b78a015 | Andrew Apted | 2018-06-17 21:53:52 +1000 Strife : define the new linedef flags (like MLF_Strife_JumpOver). ------------------------------------------------------------------------ 17dd820d009b | Andrew Apted | 2018-06-17 20:58:10 +1000 TODO : small update. ------------------------------------------------------------------------ bcd5506a3268 | Andrew Apted | 2018-06-17 20:52:57 +1000 CHANGELOG update (and reformat). ------------------------------------------------------------------------ f20f24da9cfb | Andrew Apted | 2018-06-17 20:51:47 +1000 Hexen : show every arg value when special is not 0. Arg values are also dimmed when the usage is unknown. ------------------------------------------------------------------------ 83765bbb0f89 | Andrew Apted | 2018-06-17 20:17:50 +1000 TODO : minor changes (remove trailing periods). ------------------------------------------------------------------------ 5fff9c7952dc | Andrew Apted | 2018-06-17 14:15:16 +1000 3D View : removed Sort_Bubble() -- it did not speed things up. ------------------------------------------------------------------------ 61f3309c85de | Andrew Apted | 2018-06-17 13:44:45 +1000 3D View : restored the recursion minimization in Sort_Range(). ------------------------------------------------------------------------ c5f48dd65c30 | Andrew Apted | 2018-06-17 13:31:51 +1000 3D View : removed Sort_ChoosePivot() code. Choosing the pivot in a simple way (just the middle element) has shown to be adequate, and in some cases faster than the 3-way median logic which Sort_ChoosePivot() uses. ------------------------------------------------------------------------ 8f24973a8b07 | Andrew Apted | 2018-06-17 13:18:01 +1000 3D View : improved the IsCloser() code and its comments. In particular, we always test if two walls share a vertex (and perform the more complicated closer test). Also added logic to prevent two things at same location from flickering. ------------------------------------------------------------------------ 270cb9a0d12b | Andrew Apted | 2018-06-16 22:44:07 +1000 3D View : worked on rewriting the wall sorting code. The previous code had some problems, especially when the wall list contained many DrawWalls at the same depth, i.e. sprites. This commit is a preliminary fix to the QuickSort algorithm, in particular the case when everything was >= pivot, the old code did not ensure the pivot was moved to the beginning. ------------------------------------------------------------------------ ed95a485bd97 | Andrew Apted | 2018-06-15 19:05:23 +1000 3D View : fixed closed sectors having a see-through gap. ------------------------------------------------------------------------ 580569767cfb | Andrew Apted | 2018-06-15 15:28:12 +1000 Checks : detect when tag 666 or 667 are used on the wrong map. This closes ticket #12. ------------------------------------------------------------------------ 6b692a486984 | Andrew Apted | 2018-06-15 14:41:53 +1000 Checks / Tags : ignore 666 and 667 for unmatched sector tags. They normally never have a linedef, since those sectors are activated by the engine on the death of a boss monster. Also ignore 666/667 for the lowest/highest tag display. ------------------------------------------------------------------------ c5038af61710 | Andrew Apted | 2018-06-15 14:28:05 +1000 Game defs : enable "tag_666" feature for DOOM and Heretic. ------------------------------------------------------------------------ 99355dea395c | Andrew Apted | 2018-06-15 00:21:23 +1000 CHANGELOG update. ------------------------------------------------------------------------ 9ccfad0b7547 | Andrew Apted | 2018-06-15 00:04:57 +1000 Checks : detect unspawnable things where all Hexen classes are unset. This finishes the feature, closing ticket #23. ------------------------------------------------------------------------ 5b5a0ce37866 | Andrew Apted | 2018-06-15 00:00:28 +1000 Checks : for unspawnable things, always ignore the CAMERA_PEST. ------------------------------------------------------------------------ afa3e0c670dd | Andrew Apted | 2018-06-14 23:55:18 +1000 Checks : detect when a thing in unspawnable due to game modes. i.e. when the SP, COOP and DM flags are all clear. This does not apply to Vanilla DOOM, only to Boom compatible source ports and Hexen format maps. ------------------------------------------------------------------------ a47eacbf7813 | Andrew Apted | 2018-06-14 23:13:58 +1000 Checks : skip things which the game engine always spawns. For some things, e.g. player starts, the game engine never checks the skill flags (etc). Hence these can be safely skipped by the "unspawnable thing" detector. ------------------------------------------------------------------------ e52e47513bcf | Andrew Apted | 2018-06-14 23:01:11 +1000 Checks : worked on detecting "unspawnable" things. i.e. things which will never spawn because the skill bits (easy, medium, hard) are all clear. This commit includes ability to "Show" these things, and also "Fix" them (which sets all three skill bits). ------------------------------------------------------------------------ 512c21c3c835 | Andrew Apted | 2018-06-14 15:46:01 +1000 BSP : compute 'angle' and 'dist' of vanilla segs more accurately. ------------------------------------------------------------------------ b4e02e9ad1f7 | Andrew Apted | 2018-06-13 22:57:23 +1000 TODO : reorganized items based on likelihood of getting done. The new section headers are "In Progress", "Most Likely", "Slightly Possible" and "Rejected Ideas". Also moved a couple ideas to the rejection pile, and simply deleted a couple of the wackiest ideas. ------------------------------------------------------------------------ 9098d2b55114 | Andrew Apted | 2018-06-13 22:25:22 +1000 TODO : moved several items to the "NOT-TODO" section. ------------------------------------------------------------------------ b40e69c17028 | Andrew Apted | 2018-06-13 19:05:51 +1000 EditLump : treat "SCRIPTS" as a invalid lump (prevent editing). Normally "SCRIPTS" is a level lump, appearing directly after the "BEHAVIOR" lump, and is completely optional. There are some wad files which contain a global "SCRIPTS" lump (not attached to any particular level). Trying to support such a duality leads to problems, especially when the user creates a global "SCRIPTS" lump, but it ends up directly after a level inside the wad, and hence suddenly looks like a level lump (not global anymore). So the user may find that their edited lump has "disappeared" when next trying to edit it, which is totally unacceptable. Investigations show that source ports (esp. ZDoom) never read a global "SCRIPTS" lump, it is just a way for modders to bundle the source of their ACS scripts (as a courtesy). Hence I think it is better to err on the side of safety, and only allow the creation/editing of level-local "SCRIPTS" lumps. ------------------------------------------------------------------------ 62ee6fc89ace | Andrew Apted | 2018-06-13 18:27:13 +1000 TODO updated (a wish just came true). ------------------------------------------------------------------------ 731fe3f30662 | Andrew Apted | 2018-06-13 18:23:00 +1000 CHANGELOG : noted the new text lump editor. ------------------------------------------------------------------------ 8671caa462ee | Andrew Apted | 2018-06-13 18:19:16 +1000 Merge branch 'text-edit' ------------------------------------------------------------------------ 347a63834105 | Andrew Apted | 2018-06-13 16:35:10 +1000 EditLump : improved code to set the window title. Also fixed a bug or two. ------------------------------------------------------------------------ b40f52ee6775 | Andrew Apted | 2018-06-13 15:43:27 +1000 EditLump : added the two flags to "EditLump" command entry. The two flags are: "/header" and "/scripts". ------------------------------------------------------------------------ 79f2cd470760 | Andrew Apted | 2018-06-13 15:41:26 +1000 EditLump : prevent using "/scripts" option on a non-Hexen map. ------------------------------------------------------------------------ 408c837c2368 | Andrew Apted | 2018-06-13 15:31:18 +1000 EditLump : added EDLUMP_XXX constants for the two special lumps. Those two lumps are the map header of current level, and "SCRIPTS" lump part of the current level. Main reason for this is that some wads contain a global "SCRIPTS" lump, so we cannot use that name to represent the per-level lump. ------------------------------------------------------------------------ 3439417107ac | Andrew Apted | 2018-06-13 15:13:12 +1000 EditLump : implemented loading and saving from/to a memory buffer. ------------------------------------------------------------------------ 6d65b435ee39 | Andrew Apted | 2018-06-12 23:12:37 +1000 EditLump : implemented callbacks for the short-cut buttons. ------------------------------------------------------------------------ f5631b40a558 | Andrew Apted | 2018-06-12 22:44:06 +1000 EditLump : added short-cut buttons to the UI -- currently inert. ------------------------------------------------------------------------ 14beadc17658 | Andrew Apted | 2018-06-12 00:35:34 +1000 EditLump : sorted out main logic for map header and "SCRIPTS" lumps. ------------------------------------------------------------------------ 070f81c8ccee | Andrew Apted | 2018-06-12 00:01:07 +1000 EditLump : collected a group of common text lumps. ------------------------------------------------------------------------ 9cc0d69a2e2d | Andrew Apted | 2018-06-11 16:15:28 +1000 EditLump : verify lump name as it is typed, and fixed a bug. ------------------------------------------------------------------------ fcbdfb20b0f8 | Andrew Apted | 2018-06-11 15:45:58 +1000 EditLump : reject more lumps in ValidLumpToEdit(). ------------------------------------------------------------------------ b6d4875b7fc2 | Andrew Apted | 2018-06-11 01:04:43 +1000 EditLump : fleshed out ValidLumpToEdit() code. Includes a invalid_text_lump[], which lists numerous common lumps which are known to use a binary format (and hence cannot be edited as text). ------------------------------------------------------------------------ 5a5237afa1bc | Andrew Apted | 2018-06-11 00:46:56 +1000 EditLump : "OK" and "Cancel" buttons for UI_ChooseTextLump dialog. ------------------------------------------------------------------------ 516f137adeb1 | Andrew Apted | 2018-06-11 00:30:58 +1000 EditLump : began work on a UI_ChooseTextLump() dialog.... ------------------------------------------------------------------------ 8ef3519c225a | Andrew Apted | 2018-06-10 23:39:35 +1000 Hexen : support loading and saving the "SCRIPTS" level lump. This is an optional (and usually absent) level lump which contains the texts of ACS scripts. The plan is to be able to edit this lump with the Lump Editor being developed. ------------------------------------------------------------------------ dcfe8d1f39a6 | Andrew Apted | 2018-06-10 23:15:27 +1000 TODO : minor update. I tested the render speed with a simpler Sort_ChoosePivot(), and the results were mixed: lo-res mode was faster but hi-res mode was slower. Hence decided to keep the code as-is. ------------------------------------------------------------------------ ed15d59726cd | Andrew Apted | 2018-06-10 22:49:40 +1000 Checks : never consider #0 to be an unknown line or sector type. ------------------------------------------------------------------------ e67850b96de9 | Andrew Apted | 2018-06-09 22:31:34 +1000 EditLump : disabled unimplemented "Replace" menu command. ------------------------------------------------------------------------ 2fe4e962934d | Andrew Apted | 2018-06-09 22:15:33 +1000 EditLump : fixed backwards search getting "stuck" at same spot. ------------------------------------------------------------------------ 198338600a64 | Andrew Apted | 2018-06-09 21:56:58 +1000 EditLump : finished the Find commands. ------------------------------------------------------------------------ ea431cf7ef1f | Andrew Apted | 2018-06-09 21:22:05 +1000 EditLump : partial work on the Find/Find-Next/Find-Prev commands... ------------------------------------------------------------------------ d813cc21ddda | Andrew Apted | 2018-06-09 16:04:09 +1000 EditLump : if user tries to save a read-only lump, ask to export it. Also a successful export clears the MODIFIED status. ------------------------------------------------------------------------ 31c4ccec0363 | Andrew Apted | 2018-06-09 15:35:56 +1000 EditLump : confirmation dialog if closing with modifications. ------------------------------------------------------------------------ a7b30a3e4339 | Andrew Apted | 2018-06-09 15:06:51 +1000 EditLump : fixed MODIFIED being shown directly after loading a lump. ------------------------------------------------------------------------ b46d65ab4b9d | Andrew Apted | 2018-06-09 15:01:59 +1000 EditLump : implemented the "Save" menu command. ------------------------------------------------------------------------ 2ea0dd60c0e8 | Andrew Apted | 2018-06-09 14:22:47 +1000 EditLump : implemented SaveLump() method. ------------------------------------------------------------------------ 5dd1f014cafd | Andrew Apted | 2018-06-09 02:23:07 +1000 EditLump : implemented LoadLump(). ------------------------------------------------------------------------ a4e9f83e3016 | Andrew Apted | 2018-06-09 01:54:08 +1000 EditLump : proper dialog when lump is not found or wad is read-only. ------------------------------------------------------------------------ f6f748774343 | Andrew Apted | 2018-06-08 23:13:02 +1000 EditLump : implemented the "Export to File" menu command. ------------------------------------------------------------------------ 39ddbe96c571 | Andrew Apted | 2018-06-08 22:39:40 +1000 EditLump : implemented the "Insert File" menu command. ------------------------------------------------------------------------ 594deeeaaa37 | Andrew Apted | 2018-06-08 21:44:34 +1000 EditLump : implemented Select-All and Unselect-All menu commands. ------------------------------------------------------------------------ 3990914461fe | Andrew Apted | 2018-06-08 21:32:47 +1000 EditLump : implemented the "Go to Top/Bottom" menu commands. Also tidied up some other menu callbacks. ------------------------------------------------------------------------ 0bf89e06e3eb | Andrew Apted | 2018-06-08 20:48:51 +1000 EditLump : fixed selection color to be visible (FL_BLUE). ------------------------------------------------------------------------ 3a6c299d901b | Andrew Apted | 2018-06-08 20:45:48 +1000 EditLump : implemented menu callbacks for Undo/Cut/Copy/Paste/Delete. ------------------------------------------------------------------------ ce9d6ea111bc | Andrew Apted | 2018-06-08 19:00:22 +1000 EditLump : limit size of editor window to a sensible minimum. ------------------------------------------------------------------------ d4bc461289f4 | Andrew Apted | 2018-06-08 16:45:44 +1000 Makefile : added "full-install" target which uses the XDG tools. This target installs the .desktop file and icon image, whereas the plain "install" target no longer does that. Also added a "full-uninstall" target. ------------------------------------------------------------------------ 9d47f492ac93 | Andrew Apted | 2018-06-08 16:39:33 +1000 Makefile : fixed "clean" target to remove ".o" files (not everything). This allows OBJ_DIR to be safely set to the src/ directory. ------------------------------------------------------------------------ e37d75b2b389 | Andrew Apted | 2018-06-08 16:27:45 +1000 Makefile : support DESTDIR in install and uninstall targets. ------------------------------------------------------------------------ 7e8758b20c4a | Andrew Apted | 2018-06-07 00:45:40 +1000 Makefile : minor commenting. ------------------------------------------------------------------------ 6e08fe7464eb | Andrew Apted | 2018-06-07 00:42:49 +1000 PORTS / ZDoom : fixed missing line-special 0 (NOTHING). This caused spurious "unknown line special" warnings when invoking the level checking system. ------------------------------------------------------------------------ a3291abf0e2b | Andrew Apted | 2018-06-04 16:10:14 +1000 rely on automatic detection of target OS (especially Windows). Removed the "OS" variable from the Makefiles, and updated some code that checked for "UNIX" (mostly in lib_util.cc), and updated the detection for Windows in main.h. ------------------------------------------------------------------------ cbdb95b5a15c | Andrew Apted | 2018-06-02 19:10:12 +1000 BSP : renamed "minor warnings" --> "minor issues". ------------------------------------------------------------------------ 2479cec3fc82 | Andrew Apted | 2018-06-01 01:14:29 +1000 EditLump : added "has_changes" field, use a callback to update it. ------------------------------------------------------------------------ 64b2fc0584e1 | Andrew Apted | 2018-06-01 01:02:14 +1000 EditLump : implemented File/Quit in the menus. ------------------------------------------------------------------------ bcce70741e4d | Andrew Apted | 2018-06-01 00:53:20 +1000 EditLump : got showing the line and column number working. ------------------------------------------------------------------------ b1832b487981 | Andrew Apted | 2018-06-01 00:21:32 +1000 TODO : minor whitespace fixes. ------------------------------------------------------------------------ ee578ebaf7f5 | Andrew Apted | 2018-05-31 23:48:08 +1000 BSP : added BUILD_LumpOverflow result code. ------------------------------------------------------------------------ 8986107f5b14 | Andrew Apted | 2018-05-31 23:30:56 +1000 BSP : removed unused 'message' field and SetErrorMsg() func. ------------------------------------------------------------------------ 506fd12a9e86 | Andrew Apted | 2018-05-31 20:09:31 +1000 BSP : added Failure() func, similar to Warning() but for overflows. ------------------------------------------------------------------------ 74272345ce82 | Andrew Apted | 2018-05-31 19:52:12 +1000 BSP : renamed function PrintVerbose() --> PrintDetail() ------------------------------------------------------------------------ c2acac4a3e8c | Andrew Apted | 2018-05-31 01:36:09 +1000 EditLump : wrap Fl_Text_Editor class in order to get line/col info. ------------------------------------------------------------------------ 14db0511ba3d | Andrew Apted | 2018-05-31 01:03:11 +1000 EditLump : fully implemented the status bar widget. ------------------------------------------------------------------------ 948817be3c34 | Andrew Apted | 2018-05-29 00:34:35 +1000 EditLump : decided contents of each menu (awaiting impl...) ------------------------------------------------------------------------ 0cbd823988b1 | Andrew Apted | 2018-05-29 00:06:37 +1000 EditLump : added a minimal menu bar, though nothing works yet. ------------------------------------------------------------------------ dd70154e4c7a | Andrew Apted | 2018-05-28 19:18:50 +1000 BSP : code tidying, removed unused parameter from PutNodes(). ------------------------------------------------------------------------ 686d2c77728c | Andrew Apted | 2018-05-28 19:10:02 +1000 code correctness : made Editor_State_t not be a typedef. ------------------------------------------------------------------------ ee3b3af939b0 | Andrew Apted | 2018-05-28 19:07:48 +1000 code correctness : removed spurious '&' before arrays in memset(). ------------------------------------------------------------------------ 714f90c2c970 | Andrew Apted | 2018-05-28 19:06:01 +1000 code correctness : added #include to main.h That's because we use std::swap() a lot, and that function requires the header file. ------------------------------------------------------------------------ 9fa124561491 | Andrew Apted | 2018-05-28 15:29:16 +1000 fixed returning NULL from a function which returns bool. ------------------------------------------------------------------------ 283e4b022565 | Andrew Apted | 2018-05-28 15:27:00 +1000 Basis : removed unused typedefs: VPtr, TPtr, SPtr, LDPtr and SDPtr. ------------------------------------------------------------------------ 765f38e3ae02 | Andrew Apted | 2018-05-28 15:21:17 +1000 Makefiles : have a WARNINGS var, enable extra warnings. ------------------------------------------------------------------------ e802ae56bd9b | Andrew Apted | 2018-05-28 15:02:14 +1000 minor rename of ClipboardOp() parameter: what --> op. ------------------------------------------------------------------------ f8f8dab7978d | Andrew Apted | 2018-05-28 14:57:00 +1000 minor rename of a local variable (category --> item_cat). ------------------------------------------------------------------------ daca8454a3e7 | Andrew Apted | 2018-05-28 14:49:13 +1000 wad code : renamed parameter of Backup() method. ------------------------------------------------------------------------ c91eb66acc6a | Andrew Apted | 2018-05-28 14:46:39 +1000 EditLump : tweaked the text color. ------------------------------------------------------------------------ c48c308b9461 | Andrew Apted | 2018-05-28 00:18:07 +1000 EditLump : add status bar, text editing widget to UI_TextEditor. The status bar is currently empty. This commit also creates a menu, which is empty too. ------------------------------------------------------------------------ dc262a1ae03b | Andrew Apted | 2018-05-27 19:06:24 +1000 EditLump : split UI_TextEditor code into its own file. That's because I expect the UI aspects of the code to grow to a considerable size, with the addition to several menus, a status bar, etc... More non-editor stuff is needed too, like a dialog for selecting what lump to edit. ------------------------------------------------------------------------ bb8ef9ebfc11 | Andrew Apted | 2018-05-27 18:31:21 +1000 EditLump : set the window title, and check for read-only wads. ------------------------------------------------------------------------ f3b54cd92b0e | Andrew Apted | 2018-05-27 18:26:31 +1000 EditLump : bit more fleshing out, determine Wad_file to use. ------------------------------------------------------------------------ d9da157135b7 | Andrew Apted | 2018-05-27 16:29:14 +1000 EditLump : more fleshing out of the high-level logic. ------------------------------------------------------------------------ 031c3382470d | Andrew Apted | 2018-05-27 15:49:13 +1000 EditLump : the beginnings of a UI_TextEditor class.... ------------------------------------------------------------------------ 451a7895eb5a | Andrew Apted | 2018-05-27 13:57:10 +1000 began work on a command to edit text lumps. This commit adds two new files: "m_editlump.cc/h", and a "Lump Editor" entry to the File menu, and adds "EditLump" to the command table. The implementation (in CMD_EditLump) has barely begun... ------------------------------------------------------------------------ 30d0ce15853f | Andrew Apted | 2018-05-27 01:18:40 +1000 Makefiles : added rule to create the OBJ_DIR directory. ------------------------------------------------------------------------ 1280695b7336 | Andrew Apted | 2018-05-27 01:02:59 +1000 TODO.txt updated. ------------------------------------------------------------------------ 4cd4bf1ecfc2 | Andrew Apted | 2018-05-26 00:27:56 +1000 BSP : removed BUILD_ReadError and BUILD_WriteError -- never used. ------------------------------------------------------------------------ 274ba59ed21f | Andrew Apted | 2018-05-26 00:22:57 +1000 BSP : better error messages when Seek() fails. ------------------------------------------------------------------------ 61cb22e8fcac | Andrew Apted | 2018-05-25 23:44:56 +1000 BSP : code tidying, use the term "overflow" instead of "hard failure". ------------------------------------------------------------------------ 2614eb09c626 | Andrew Apted | 2018-05-25 15:50:01 +1000 BSP : tweaked the message about forcing XNOD format. ------------------------------------------------------------------------ 351a16fe07db | Andrew Apted | 2018-05-25 14:31:07 +1000 lib_util : improved StringTidy() to not use a static buffer. ------------------------------------------------------------------------ c41fbafc1c47 | Andrew Apted | 2018-05-25 14:29:33 +1000 fixed typo in a node building message ("filed" --> "failed"). ------------------------------------------------------------------------ ae6efd559fd7 | Andrew Apted | 2018-05-25 14:27:41 +1000 wad code : fixed a printf with wrong arguments. ------------------------------------------------------------------------ 6bd3cdd51826 | Andrew Apted | 2018-05-16 23:43:13 +1000 conversion scripts : add "next page" links to each page. ------------------------------------------------------------------------ dfa5b5d28cdd | Andrew Apted | 2018-05-16 23:10:40 +1000 conversion scripts : add a link back to the index (TOC) on each page. ------------------------------------------------------------------------ 785ab5241e36 | Andrew Apted | 2018-05-15 16:21:49 +1000 conversion scripts : better handling of code blocks. ------------------------------------------------------------------------ 98791cab97a6 | Andrew Apted | 2018-05-08 21:38:07 +1000 handle a very rare assertion failure in m_strings.cc more gracefully. Note: I would normally look for the root cause, but internalised strings are used a lot throughout the code, so it is impossible to know where the real problem is unless you can trigger the issue while using a debugger. Hence added a workaround here for the sake of robustness. ------------------------------------------------------------------------ 40b244d85807 | Andrew Apted | 2018-05-08 20:28:59 +1000 fix for a rare assertion failure in UI_LineDef::SolidMask(). ------------------------------------------------------------------------ 1597b376b98e | Andrew Apted | 2018-05-08 00:41:55 +1000 fixed inserting things in Hexen getting no SP/COOP/DM/class flags. ------------------------------------------------------------------------ 0a3b6483b923 | Andrew Apted | 2018-05-08 00:18:56 +1000 Updated some copyright years (e.g. About box) for 2018. ------------------------------------------------------------------------ 2ac07bfae448 | Andrew Apted | 2018-05-08 00:07:19 +1000 conversion scripts : improved "note" and "warning" blocks. ------------------------------------------------------------------------ 5c5ad8d47b97 | Andrew Apted | 2018-05-07 23:45:39 +1000 CHANGELOG : another two fixes. ------------------------------------------------------------------------ b127974e4729 | Andrew Apted | 2018-05-07 23:34:31 +1000 TODO.txt : merged the high/low priority sections (remove that distinction). ------------------------------------------------------------------------ bf22dbd2f3f7 | Andrew Apted | 2018-05-07 16:58:55 +1000 conversion scripts : link :download: to the SF project files/ dir. ------------------------------------------------------------------------ 1f2f1d31df3e | Andrew Apted | 2018-05-07 15:17:45 +1000 AUTHORS.txt : added Wesley Werner as a contributor. ------------------------------------------------------------------------ 0f7f503e725a | Andrew Apted | 2018-05-07 15:06:11 +1000 Merge branch 'master' of ssh://git.code.sf.net/p/eureka-editor/git ------------------------------------------------------------------------ a28cb63abd90 | Andrew Apted | 2018-05-05 23:42:50 +1000 conversion scripts : fixed wrong sub-list syntax (in Index). ------------------------------------------------------------------------ a755cccadd0f | Andrew Apted | 2018-05-05 23:31:01 +1000 conversion scripts : added #notifybox and #warningbox CSS. ------------------------------------------------------------------------ 3ecd689f507e | Andrew Apted | 2018-05-05 22:35:19 +1000 conversion scripts : don't clobber our hand-edited User.Index ------------------------------------------------------------------------ dbf4feac7a6c | Andrew Apted | 2018-05-05 22:30:18 +1000 conversion scripts : workaround for a pandoc issue with `\`` ------------------------------------------------------------------------ 66e85e5670c2 | Andrew Apted | 2018-05-05 19:04:40 +1000 conversion scripts : fixed order of pages (for the Index). ------------------------------------------------------------------------ 2975ecd6ede3 | Andrew Apted | 2018-05-05 18:41:14 +1000 conversion scripts : generate links for the Index page. ------------------------------------------------------------------------ baba03eb19c3 | Andrew Apted | 2018-05-05 17:25:03 +1000 conversion scripts : generate raw pmWiki page files. ------------------------------------------------------------------------ 2fa5cec5e954 | Andrew Apted | 2018-05-05 16:18:01 +1000 conversion scripts : put a copy of image files into pm/user/ ------------------------------------------------------------------------ e379f79d047b | Andrew Apted | 2018-05-05 15:51:27 +1000 conversion scripts : put a copy of :download: files into pm/user/ ------------------------------------------------------------------------ cdfab4d638fd | Andrew Apted | 2018-05-05 15:32:13 +1000 conversion scripts : handle the :download: elements. ------------------------------------------------------------------------ c4e4022c5f8a | Andrew Apted | 2018-05-05 15:23:37 +1000 conversion scripts : store output files in a "pm" directory. ------------------------------------------------------------------------ d83a1b9930d2 | Andrew Apted | 2018-05-05 15:22:54 +1000 conversion scripts : handle the :kbd: elements. ------------------------------------------------------------------------ 25c484bd3290 | Andrew Apted | 2018-05-04 22:28:20 +1000 conversion scripts : support links and images, removed dead code. ------------------------------------------------------------------------ e82cfdb8192d | Andrew Apted | 2018-05-04 21:05:06 +1000 conversion scripts : more work on them.... ------------------------------------------------------------------------ 3986094e3020 | Andrew Apted | 2018-05-04 18:01:32 +1000 conversion scripts : implemented Header and HorizontalRule. ------------------------------------------------------------------------ ac252e9092d7 | Andrew Apted | 2018-05-04 17:53:22 +1000 preliminary work on conversion scripts for the user manual. ------------------------------------------------------------------------ e6d67765e121 | Andrew Apted | 2017-12-06 23:48:39 +1100 fixed "Removed unused vertices" message to show the correct number. ------------------------------------------------------------------------ 219d13379ec3 | Andrew Apted | 2017-12-06 23:48:01 +1100 fixed warning messages when linedefs contain an invalid vertex. ------------------------------------------------------------------------ 4faea9a19798 | Ioan Chera | 2018-04-24 19:53:05 +0300 Updated Xcode project ------------------------------------------------------------------------ 58bc948525c4 | Andrew Apted | 2017-09-02 14:12:09 +1000 Merge branch 'master' of ssh://git.code.sf.net/p/eureka-editor/git ------------------------------------------------------------------------ 4b4aca8110be | Andrew Apted | 2017-09-02 14:11:00 +1000 updated CHANGELOG.txt and TODO.txt ------------------------------------------------------------------------ 8ce114e9e7b5 | Ioan Chera | 2017-08-30 22:06:56 +0300 Eternity config: moved the slope specials from "stairs" to "others" It made no sense to put them in stairs. ------------------------------------------------------------------------ b02133b9ed01 | Ioan Chera | 2017-08-30 21:38:17 +0300 Fixed a memory deletion bug in Img_c ------------------------------------------------------------------------ d7ea96cbd36b | Ioan Chera | 2017-08-16 08:30:55 +0300 Silenced some clang 64-bit warnings. ------------------------------------------------------------------------ a0943ebde940 | Ioan Chera | 2017-08-16 08:23:37 +0300 macOS: updated the Eureka version in the plist. ------------------------------------------------------------------------ a7cd233dc235 | Andrew Apted | 2017-08-02 23:07:06 +1000 HERETIC config : fixed sprite of the wall torch (WTRH). ------------------------------------------------------------------------ f8866bfd60d0 | Andrew Apted | 2017-06-07 19:31:25 +1000 minor commenting. ------------------------------------------------------------------------ 2c43e820d58f | Andrew Apted | 2017-06-07 19:13:34 +1000 3D View : rewrote code to sort the active list of draw-walls, using custom sorting code (implementing QuickSort). It previously used std::sort(), but because our wall-distance comparison function is "wonky" (e.g. can be non-reversable or non-transitive), it was causing the local std::sort() function to access elements outside of the list (leading to a CRASH). ------------------------------------------------------------------------ 6ae140bf273d | Andrew Apted | 2017-05-06 12:57:53 +1000 GAME defs : added comment to explain why exit linetypes use lowercase "s1" and "w1". ------------------------------------------------------------------------ 8129c104c7ab | Andrew Apted | 2017-04-04 12:54:53 +1000 TODO.txt : small update. ------------------------------------------------------------------------ dbc69819bb58 | Andrew Apted | 2017-04-04 12:52:56 +1000 Fixed regression with sector merging, it is supposed to keep the properties of the first selected sector, but this behavior broke when another issue with sector merging was fixed. ------------------------------------------------------------------------ f6f5256fa384 | Andrew Apted | 2017-04-04 12:48:37 +1000 Version bump after the release. ------------------------------------------------------------------------ cc9b3c7441df | Andrew Apted | 2017-04-04 12:39:42 +1000 CHANGELOG : began a fresh one... ------------------------------------------------------------------------ 852053cf43e3 | Andrew Apted | 2017-04-04 12:37:37 +1000 Version 1.21 was released. Hence moved CHANGELOG --> changelogs/ directory. ------------------------------------------------------------------------ 15efcd30ab1f | Ioan Chera | 2017-01-18 22:19:49 +0200 Updated Xcode project for distribution * Made sure that the static library files are ignored * Also ignore the userdata subfolders of Xcode * Updated project to recommended settings * Updated file references * Added the two new resource files * Updated code signing * Increased deployment target to 10.9 to satisfy all requirements * Updated the info plist * Updated the macOS version for the xib * Removed accidental static libraries ------------------------------------------------------------------------ 6ac71b29bb7c | Andrew Apted | 2017-01-12 22:12:17 +1100 docs/History.txt : updated with logs since last release. ------------------------------------------------------------------------ 355d3d20049f | Andrew Apted | 2017-01-12 21:50:06 +1100 Removed the file "docs/MiscNotes.txt" -- some parts are obsolete and the other parts are not very useful anymore. ------------------------------------------------------------------------ 1a6938e99914 | Andrew Apted | 2017-01-12 21:27:05 +1100 README.txt : updated the KEYBOARD/MOUSE section for all changes to the key/button bindings since the previous release. ------------------------------------------------------------------------ 787b150c5abd | Andrew Apted | 2017-01-12 21:21:35 +1100 CHANGELOG : tweaks. ------------------------------------------------------------------------ b49cc8efbda1 | Andrew Apted | 2017-01-12 20:48:21 +1100 Operation menu : added "Select same xxx" ops for sector mode. ------------------------------------------------------------------------ dd63ff346638 | Andrew Apted | 2017-01-12 20:02:59 +1100 Test map : fixed execution of the binary on Windows. ------------------------------------------------------------------------ 97b15a4d23fe | Andrew Apted | 2017-01-12 16:03:30 +1100 Updated the --help text for 2017. ------------------------------------------------------------------------ 33e0c0888b65 | Andrew Apted | 2017-01-12 15:59:41 +1100 About dialog : for Win32, find the logo image in "common/" folder. ------------------------------------------------------------------------ 7e3047e44233 | Andrew Apted | 2017-01-12 15:49:55 +1100 3D View : use a darker red for info-bar when stuff is selected. ------------------------------------------------------------------------ a6cd727ee283 | Andrew Apted | 2017-01-12 15:45:00 +1100 About dialog : updated for 2017. ------------------------------------------------------------------------ b50ab15c1bc2 | Andrew Apted | 2017-01-12 15:05:47 +1100 README.txt : update for the release. ------------------------------------------------------------------------ be64c1a08b1e | Andrew Apted | 2017-01-12 15:02:52 +1100 TODO : reorganized various items. ------------------------------------------------------------------------ a2b76534ce73 | Andrew Apted | 2017-01-12 14:43:35 +1100 Removed two obsolete config vars: "scroll_less" and "scroll_more". ------------------------------------------------------------------------ 45def5ab752b | Andrew Apted | 2017-01-12 14:42:19 +1100 Makefile : enable optimisation (-O2) for the release. ------------------------------------------------------------------------ 15a976db1495 | Andrew Apted | 2017-01-02 00:16:27 +1100 TODO update. ------------------------------------------------------------------------ c9375f28f238 | Andrew Apted | 2017-01-02 00:14:23 +1100 Wiki : slightly bigger font sizes for

and

headings. ------------------------------------------------------------------------ dd54b093090e | Andrew Apted | 2017-01-02 00:13:03 +1100 Operation menu : added "Auto align" and "Clear offsets" commands. ------------------------------------------------------------------------ e8f7cb66e574 | Andrew Apted | 2017-01-02 00:10:50 +1100 Operation Menu : fixed "3D_Align" commands which changed to use flags like /x and /y instead of plain keywords. ------------------------------------------------------------------------ ec986567b8de | Andrew Apted | 2016-12-31 01:17:51 +1100 CHANGES.txt : large rejigging, added "Editing" section, added a few entries for recent changes. ------------------------------------------------------------------------ 882ad22b3841 | Andrew Apted | 2016-12-30 18:21:52 +1100 Version bump to 1.21 -- ready for release. ------------------------------------------------------------------------ 728fd8937b09 | Andrew Apted | 2016-12-24 21:10:06 +1100 TODO update. ------------------------------------------------------------------------ 04f954c95fd6 | Andrew Apted | 2016-12-24 21:08:28 +1100 Texture alignment : support /clear + /right flags. ------------------------------------------------------------------------ e8c405f482b3 | Andrew Apted | 2016-12-24 21:03:49 +1100 dead code removal. ------------------------------------------------------------------------ 4fd010bf09aa | Andrew Apted | 2016-12-24 16:57:17 +1100 Texture alignment : fixed some bugs in recent changes. ------------------------------------------------------------------------ d4e5893c5938 | Andrew Apted | 2016-12-24 16:47:35 +1100 3D View : fixed not saving/restoring the current gravity setting in the DAT file (i.e. where UI state is persisted for a map). ------------------------------------------------------------------------ 4feee7609c2e | Andrew Apted | 2016-12-24 16:32:54 +1100 Texture alignment : implemented ScoreTextureMatch() logic. ------------------------------------------------------------------------ 4734ca99b548 | Andrew Apted | 2016-12-24 15:00:39 +1100 Wiki : added ".kw" style to CSS, for command keywords and flags. ------------------------------------------------------------------------ be39523c7734 | Andrew Apted | 2016-12-24 14:38:47 +1100 Wiki : added ".key" style to the CSS, for drawing keyboard keys. ------------------------------------------------------------------------ fd121f70477b | Andrew Apted | 2016-12-24 12:24:49 +1100 Implemented "LIN_Align" command for auto-aligning offsets of a group of selected linedefs in the 2D view. Bound to 'A' key. ------------------------------------------------------------------------ 756682e6d903 | Andrew Apted | 2016-12-24 12:02:56 +1100 3D_Align command : have "/x" and "/y" flags instead of a keyword. ------------------------------------------------------------------------ d317842a1f88 | Andrew Apted | 2016-12-24 11:22:59 +1100 Man page : updated the date string. ------------------------------------------------------------------------ c6c3c108230e | Andrew Apted | 2016-12-24 11:21:19 +1100 Texture aligning : moved Line_AlignGroup() code --> e_linedef.cc (from r_render.cc), passing in the array of surfaces to process. ------------------------------------------------------------------------ 48565c96bfc2 | Andrew Apted | 2016-12-23 23:24:48 +1100 Texture aligning : more work on improving the logic, especially the ScoreAdjoiner() function.... ------------------------------------------------------------------------ dfc1b50acce8 | Andrew Apted | 2016-12-23 22:34:28 +1100 Texture aligning : partial work to improve the Line_AlignOffsets() code, using the "Obj3d_t" class to refer to surfaces instead of the hacky "soal" stuff (side-on-a-line), and generally improving all the logic used.... ------------------------------------------------------------------------ 22c7464784bf | Andrew Apted | 2016-12-23 20:55:38 +1100 TODO update. ------------------------------------------------------------------------ dd739b25cf74 | Andrew Apted | 2016-12-23 20:52:44 +1100 3D View : when aligning multiple selected walls, fixed the logic for visiting the surfaces in the right order. ------------------------------------------------------------------------ 140b354a17d6 | Andrew Apted | 2016-12-23 20:41:35 +1100 Texture aligning : added LINALIGN_Unpeg flag, which must be set to enable changing the unpegging flags on the linedef. ------------------------------------------------------------------------ dbf6863bf585 | Andrew Apted | 2016-12-23 14:29:24 +1100 Rewrote the "Enlarge" and "Shrink" commands to use the transform_t stuff, reducing amount of code, and to support fractional values like "1.5" or "0.3". ------------------------------------------------------------------------ e8c05f0fc585 | Andrew Apted | 2016-12-22 16:36:18 +1100 ACT_Click command : changed the flags to be disablers instead of enablers, i.e. renamed to "/noselect", "/nodrag", "/nosplit". ------------------------------------------------------------------------ 061cc267b8f9 | Andrew Apted | 2016-12-22 16:16:43 +1100 Bindings : bound "D" --> SEC_SelectGroup /ceil_tex ------------------------------------------------------------------------ 828251fcfe44 | Andrew Apted | 2016-12-22 16:11:57 +1100 Bindings : added "C" for the reverse CopyProperties command. ------------------------------------------------------------------------ 8f0df1b32b01 | Andrew Apted | 2016-12-22 15:56:49 +1100 LIN_SelectPath and SEC_SelectGroup commands : made additive mode be the default, replacing "/add" flag with a "/fresh" flag. ------------------------------------------------------------------------ 31020115e81a | Andrew Apted | 2016-12-22 15:47:05 +1100 3D_Set command : removed "gamma" keyword, since that is handled by the ordinary "Set" command now. ------------------------------------------------------------------------ 43ca46a4f0bb | Andrew Apted | 2016-12-22 15:38:58 +1100 LIN_Flip command : simplified the flags, have a "/force" command which will flip a linedef non-safely, and have new "LIN_SwapSides" command for the functionality of swapping the sidedefs on a line. ------------------------------------------------------------------------ 437538312230 | Andrew Apted | 2016-12-22 15:26:42 +1100 3D View : more work on "3D_Align" to visit surfaces in the correct order, but it is still not right yet. ------------------------------------------------------------------------ 1533facdab03 | Andrew Apted | 2016-12-22 15:25:08 +1100 Wiki : tweaked main background color again. ------------------------------------------------------------------------ 5ffc2a7aacd2 | Andrew Apted | 2016-12-21 22:10:26 +1100 3D View : partial work to fix the "3D_Align" command to support multiple objects (in the 3D selection). ------------------------------------------------------------------------ 0a1296b56d2e | Andrew Apted | 2016-12-21 18:59:21 +1100 Key system : replaced "Gamma" command with "gamma" keyword to the existing SET and TOGGLE commands. ------------------------------------------------------------------------ efed458a107d | Andrew Apted | 2016-12-21 18:56:34 +1100 Preferences : fixed silly recently-introduced crash bug in the edit-key dialog. ------------------------------------------------------------------------ 53f09e55ecf9 | Andrew Apted | 2016-12-20 15:39:34 +1100 3D View : fixed ACT_AdjustOfs command to work on selected lines (i.e. not just the highlighted one). ------------------------------------------------------------------------ a799e9858602 | Andrew Apted | 2016-12-19 21:02:45 +1100 TODO update. ------------------------------------------------------------------------ e1afcbdcce94 | Andrew Apted | 2016-12-19 21:01:49 +1100 Fixed recent bug: dragging a single sector would not move the things inside it. ------------------------------------------------------------------------ 8ae6258b39df | Andrew Apted | 2016-12-19 20:03:58 +1100 BSP : code tidying, have a SortSegs() function. ------------------------------------------------------------------------ c26c3213bc57 | Andrew Apted | 2016-12-19 20:00:51 +1100 BSP : replaced the "normal_dup" rubbish with a RoundOffVertices() function, done as part of RoundOffBspTree(). This should fix the bug where ZDoom format nodes had a too high value for the number of original vertices. ------------------------------------------------------------------------ 3ba15ef6dbfb | Andrew Apted | 2016-12-19 19:48:19 +1100 BSP : replaced "ref_count" fields with simpler "is_used" value, and tidied up assigning of boolean values to "char" fields. ------------------------------------------------------------------------ 6fc884bd03e8 | Andrew Apted | 2016-12-19 19:38:58 +1100 BSP : tweaked logic in SaveLevel(), ensure segs array is always sorted after calling NormaliseBspTree() or RoundOffBspTree(). ------------------------------------------------------------------------ 3be1d2347da0 | Andrew Apted | 2016-12-19 19:27:07 +1100 BSP : have an "is_new" field of vertex_t, instead of IS_GL_VERTEX constant, and renamed "num_gl_vert" --> "num_new_vert". ------------------------------------------------------------------------ d8f36f5fca38 | Andrew Apted | 2016-12-19 18:50:25 +1100 BSP : removed obsolete "is_dummy" field of subsector struct. ------------------------------------------------------------------------ 39d9282b1f56 | Andrew Apted | 2016-12-19 16:52:40 +1100 CHANGELOG update. ------------------------------------------------------------------------ 760806a5b461 | Andrew Apted | 2016-12-19 16:45:55 +1100 Fixed recent bug: wrong highlight after zooming. ------------------------------------------------------------------------ c0a72703c63a | Andrew Apted | 2016-12-19 16:24:00 +1100 Sound propagation : better linedef colors, show the sound-blocking lines as magenta, and all others as either white or gray. ------------------------------------------------------------------------ 2db19f6631e8 | Andrew Apted | 2016-12-19 15:08:26 +1100 Sound propagation : implemented a new sector rendering mode for it. ------------------------------------------------------------------------ 509a6e9a3fdc | Andrew Apted | 2016-12-19 15:02:32 +1100 SoundPropagation : fixed a silly bug. ------------------------------------------------------------------------ 0be237d24af5 | Andrew Apted | 2016-12-19 14:18:28 +1100 Implemented SoundPropagation() function, which determines which sectors can be "heard" from a start sector -- using same logic as the DOOM engine P_NoiseAlert() function. ------------------------------------------------------------------------ c0ba81cff344 | Andrew Apted | 2016-12-18 22:37:47 +1100 Bindings : bind RMB (MOUSE3) in sectors mode to "Merge" command, as such an fundamental function deserves a mouse button (and it was not being used for anything else). ------------------------------------------------------------------------ 9976cc9e1e0b | Andrew Apted | 2016-12-18 21:22:05 +1100 TODO update. ------------------------------------------------------------------------ 03f8bc90fab3 | Andrew Apted | 2016-12-18 21:20:04 +1100 Copy/Paste : allow using delete on floor textures in Sector and Default Properties panels to turn them into sky -- even though this is not very useful, being consistent is important. ------------------------------------------------------------------------ f341483807dd | Andrew Apted | 2016-12-18 21:01:13 +1100 Copy/Paste : using delete on ceiling texture in 3D view turns it into sky. ------------------------------------------------------------------------ c6b624e0dd44 | Andrew Apted | 2016-12-18 20:18:43 +1100 Copy/Paste : using delete on ceiling texture in the Sector panel and Default Props panel turns that texture into sky. ------------------------------------------------------------------------ 673704d19d62 | Andrew Apted | 2016-12-18 19:55:39 +1100 Key system : workaround for Linux / X-Windows where a change in modifier keys (SHIFT or CTRL) would not immediately take effect while a navigation or action was pressed. ------------------------------------------------------------------------ 2cb67c50e3fe | Andrew Apted | 2016-12-18 18:45:47 +1100 Copy/Paste : support Delete in 3D mode, set wall textures to "-" (and shows an error for floor or ceiling textures). ------------------------------------------------------------------------ 04ebce73122e | Andrew Apted | 2016-12-18 17:58:29 +1100 Operation menu : added "Copy Texture", "Paste Texture" for 3d mode. ------------------------------------------------------------------------ 7f79cbd0e750 | Andrew Apted | 2016-12-18 17:57:03 +1100 3D View : don't forget 3d highlight when using the operation menu. ------------------------------------------------------------------------ dddfec3840c7 | Andrew Apted | 2016-12-18 16:28:08 +1100 CHANGELOG and TODO update. ------------------------------------------------------------------------ 12be0004d724 | Andrew Apted | 2016-12-18 16:23:42 +1100 3D View : improved the info bar to show information about the current highlighted object (the thing/line/sector number and the texture name or thing description). Also removed the X/Y coordinates, instead show them in the main info bar (at the bottom of the main window). ------------------------------------------------------------------------ b963f8288bf3 | Andrew Apted | 2016-12-18 15:06:33 +1100 (part of previous commit) ------------------------------------------------------------------------ 3b3cf8572527 | Andrew Apted | 2016-12-18 15:05:21 +1100 Added "panel gamma" config variable. ------------------------------------------------------------------------ 0960d6c54e9b | Andrew Apted | 2016-12-18 14:58:25 +1100 UI : draw the textures/flats/sprites in the browser and panels using a constant gamma, instead of the "usegamma" which is meant for rendering the 3D view and sectors/sprites on the 2D view. ------------------------------------------------------------------------ c3b13cc15403 | Andrew Apted | 2016-12-18 14:05:24 +1100 Copy/Paste : finally got distribution of clipboard events right. Namely try the panels FIRST, and if none want it then ALWAYS send it to the 3D view when it is active. ------------------------------------------------------------------------ 1e3a60497857 | Andrew Apted | 2016-12-18 13:12:14 +1100 Copy/Paste : support them for textures in the Default Props panel. ------------------------------------------------------------------------ ef8a65ae9ba7 | Andrew Apted | 2016-12-18 13:07:13 +1100 Copy/Paste : fully fixed 3D view eating clipboard ops even when nothing is highlighted or selected (see commit 8546694cfb5a). ------------------------------------------------------------------------ 2180ffce65f8 | Andrew Apted | 2016-12-17 23:10:30 +1100 CHANGELOG and TODO update. ------------------------------------------------------------------------ b203ecb2a7b7 | Andrew Apted | 2016-12-17 23:07:10 +1100 3D View : fixed the highlight not being cleared when the mouse has moved outside of the 3D viewport. ------------------------------------------------------------------------ b286c009d808 | Andrew Apted | 2016-12-17 22:52:44 +1100 Copy/Paste : disabled for Defaults Props and Find/Replace panels (for now anyway, it is under review....) ------------------------------------------------------------------------ 8546694cfb5a | Andrew Apted | 2016-12-17 20:49:01 +1100 Copy/Paste : don't eat a clipboard operation in 3D mode when both the 3d highlight and 3d selection are empty. ------------------------------------------------------------------------ 447cff27e763 | Andrew Apted | 2016-12-17 20:48:24 +1100 Copy/Paste : CTRL-C/X/V for textures in the LineDef panel. ------------------------------------------------------------------------ a33e63545da1 | Andrew Apted | 2016-12-17 19:48:07 +1100 Copy/Paste : support CTRL-C/X/V for textures in the Sector panel. ------------------------------------------------------------------------ c8704e1b490a | Andrew Apted | 2016-12-17 16:34:42 +1100 Copy/Paste : moved the 3D clipboard stuff to the global scope, namely the "r_clipboard" structure, with code in e_main.cc/h. ------------------------------------------------------------------------ b65353e06705 | Andrew Apted | 2016-12-17 15:21:54 +1100 Copy/Paste : added stub ClipboardOp() methods to all the panel classes which can use it (UI_Sector, UI_DefaultProps, etc...) ------------------------------------------------------------------------ b825bd74eb44 | Andrew Apted | 2016-12-17 15:05:52 +1100 Copy/Paste : added main_win::ClipboardOp() to see if various UI stuff wants to override the normal cut/copy/paste/delete commands, and updated the 3D renderer code to use this mechanism. ------------------------------------------------------------------------ b69c116b1a2c | Andrew Apted | 2016-12-17 13:54:24 +1100 Operation menu : look for "operations.cfg" in user's home_dir, using that when it exists, otherwise load it from install_dir. ------------------------------------------------------------------------ 6ad148165ffe | Andrew Apted | 2016-12-17 13:47:12 +1100 3D View : fixed most glitches when drawing highlight/select lines, caused by gross limitations of line clipping in X windows. ------------------------------------------------------------------------ 14a9da935f88 | Andrew Apted | 2016-12-17 13:23:47 +1100 3D View : fixed highlight/select lines not being clipped to the rendering area. ------------------------------------------------------------------------ 0059a9a0a34a | Andrew Apted | 2016-12-17 13:00:58 +1100 3D View : support for using the texture browser to set the texture or flat on selected walls / floors / ceilings. ------------------------------------------------------------------------ 3cfe94c40cf5 | Andrew Apted | 2016-12-17 12:41:33 +1100 Browser : previous commit allows a few methods of the panel classes (UI_Sector etc) to become private. ------------------------------------------------------------------------ f221ecd172b7 | Andrew Apted | 2016-12-17 12:35:56 +1100 Browser : gave more panel classes a BrowsedItem() method, which simplifies the code in main_win::BrowsedItem(). ------------------------------------------------------------------------ 0ff0bdc0ff37 | Andrew Apted | 2016-12-16 23:55:20 +1100 tweak to UI_MainWindow constructor. ------------------------------------------------------------------------ 95671f62f474 | Andrew Apted | 2016-12-16 23:20:04 +1100 3D View : code tidying, removed "RenderLine" struct. ------------------------------------------------------------------------ 625114e22258 | Andrew Apted | 2016-12-16 23:18:38 +1100 3D View : draw the highlighted/selected objects in a simpler way, without having to store the line coordinates. ------------------------------------------------------------------------ c68dc0ac13f4 | Andrew Apted | 2016-12-16 23:02:10 +1100 TODO update. ------------------------------------------------------------------------ f054d634dbaa | Andrew Apted | 2016-12-16 22:57:21 +1100 Panels : allow the textures in LineDef panel and flats in Sector panel to be highlighted (yellow border) when mouse is over them. Does nothing yet, but will be needed for Copy/Paste support... ------------------------------------------------------------------------ 8fb24ebf0c71 | Andrew Apted | 2016-12-16 22:37:47 +1100 3D View : ensure a redraw when the 3d selection is cleared. ------------------------------------------------------------------------ d3e43d96d09d | Andrew Apted | 2016-12-16 21:22:26 +1100 CHANGELOG update (mention the operation menu). ------------------------------------------------------------------------ 0f761ea903bb | Andrew Apted | 2016-12-16 21:12:34 +1100 Bindings : require CMD key with RMB to open the operation menu. Previously plain RMB would open the operation menu *except* in vertex mode, where plain RMB does line drawing. But I think such an inconsistency is going to annoy/confuse users. ------------------------------------------------------------------------ 41db86b221e5 | Andrew Apted | 2016-12-16 18:52:24 +1100 Bindings : changed "toggle sector rendering" from '/' --> F8 key. ------------------------------------------------------------------------ 1f15f95e7820 | Andrew Apted | 2016-12-16 18:31:09 +1100 3D View : made CTRL-X "Cut" do something useful: set the texture or flat to the default property. ------------------------------------------------------------------------ 889b9dec6c21 | Andrew Apted | 2016-12-16 18:11:46 +1100 3D View : make the info-bar background RED when some objects are selected. ------------------------------------------------------------------------ 5047908e3f25 | Andrew Apted | 2016-12-16 18:08:59 +1100 3D View : code tidying, made GrabClipboard() and StoreClipboard() be methods of the r_editing_info_t struct. ------------------------------------------------------------------------ 4c7e108a8d3d | Andrew Apted | 2016-12-16 17:12:56 +1100 3D View : code clarifying, renamed "r_sel" --> "r_edit" and moved the highlight and selection stuff into it. ------------------------------------------------------------------------ 40ec5cf5a4f0 | Andrew Apted | 2016-12-16 16:51:15 +1100 3D View : implemented a proper "3d clipboard" instead of abusing the default properties (such as default_wall_tex). ------------------------------------------------------------------------ 3036e643a601 | Andrew Apted | 2016-12-16 15:34:55 +1100 3D View : for copy'n'paste, allow using just the current highlight (i.e. don't REQUIRE a selection). That is very convenient. ------------------------------------------------------------------------ b28f20ab083c | Andrew Apted | 2016-12-16 15:13:28 +1100 3D View : implemented copy'n'paste for wall textures and sector flats. ------------------------------------------------------------------------ 8899786eaf44 | Andrew Apted | 2016-12-16 13:59:23 +1100 Preferences : changed default key binding sort mode to sort on the key itself (left column) instead of context (middle column). ------------------------------------------------------------------------ 6c04b6af7234 | Andrew Apted | 2016-12-16 13:46:25 +1100 minor rename : UI_MainWin --> UI_MainWindow ------------------------------------------------------------------------ 1b0f95c5480f | Andrew Apted | 2016-12-15 23:39:00 +1100 TODO update. ------------------------------------------------------------------------ 03e8570331ab | Andrew Apted | 2016-12-15 23:19:32 +1100 3D View : implemented logic to grab the texture from the currently selected surfaces (failing if more than one texture is present). ------------------------------------------------------------------------ 1195b12e9081 | Andrew Apted | 2016-12-15 22:46:38 +1100 3D View : when a surface is both selected and highlighted, let the selection color (RED) be used, giving better feedback to the user. ------------------------------------------------------------------------ 2f8915e17d25 | Andrew Apted | 2016-12-15 16:15:27 +1100 3D View : fixed 3D selection to allow uppers and lowers (or floors and ceilings) at the same time. ------------------------------------------------------------------------ 7e217d076ef3 | Andrew Apted | 2016-12-15 16:10:22 +1100 3D View : unselect pics in the panel when selecting in the 3D view and vice versa, so the user can be sure what will be changing when picking something in the texture/flat browser. ------------------------------------------------------------------------ b27a83dd5a44 | Andrew Apted | 2016-12-15 16:09:47 +1100 3D View : ability to "select" surfaces is now working :) ------------------------------------------------------------------------ 88799a61b54c | Andrew Apted | 2016-12-15 15:52:40 +1100 3D View : support for rendering the 3D selection (red lines). ------------------------------------------------------------------------ a557ab5d9240 | Andrew Apted | 2016-12-15 15:45:26 +1100 3D View : implemented basic (unoptimised) 3D selection handling. ------------------------------------------------------------------------ e0a9d923c893 | Andrew Apted | 2016-12-15 15:25:52 +1100 3D View : refactored the HighlightGeometry() code. ------------------------------------------------------------------------ f5be0bfafc8a | Andrew Apted | 2016-12-15 14:15:42 +1100 3D View : reworked Obj3d_t class to only store an object number (instead of separate "line", "sector", "thing" fields). ------------------------------------------------------------------------ 31d08a10faf4 | Andrew Apted | 2016-12-15 13:35:14 +1100 3D View : renamed "highlight_3D_info_t" --> "Obj3d_t" and moved its definition to objid.h, and renamed QRP_XXX --> OB3D_XXX. ------------------------------------------------------------------------ 034d3142e692 | Andrew Apted | 2016-12-15 13:14:59 +1100 3D View : logic to ensure insertions and deletions of objects will invalidate the 3D selection. ------------------------------------------------------------------------ 69f95a80ef45 | Andrew Apted | 2016-12-15 13:14:12 +1100 (part of previous commit) ------------------------------------------------------------------------ 5a11554a909b | Andrew Apted | 2016-12-15 13:11:51 +1100 3D View : also began work on versions of Cut/Copy/Paste commands which are usable in the 3D mode.... ------------------------------------------------------------------------ fbf1cb2b3132 | Andrew Apted | 2016-12-15 13:09:36 +1100 3D View : began work on new "3D_Click" command, which will be used to select/unselect surfaces in the 3D view.... ------------------------------------------------------------------------ 77f374ab711e | Andrew Apted | 2016-12-14 22:27:50 +1100 TODO update. ------------------------------------------------------------------------ c7c8180a17a4 | Andrew Apted | 2016-12-14 22:27:27 +1100 minor code commenting. ------------------------------------------------------------------------ da482ca46c52 | Andrew Apted | 2016-12-14 22:17:08 +1100 Sector auto-insert : fixed case of extending off an island inside a sector, which was being treated as a "new island" and leaving the interior as void (with broken geometry). ------------------------------------------------------------------------ f0da45f8eb32 | Andrew Apted | 2016-12-14 22:02:44 +1100 Sector auto-insert : look harder to find a nearby default textures we can use for the new linedefs. This improves the case when building a new sector off an existing one (in the void). ------------------------------------------------------------------------ 5fcff0db0f66 | Andrew Apted | 2016-12-14 18:41:49 +1100 Version bump, for good progress with various stuff. ------------------------------------------------------------------------ fe764547e30e | Andrew Apted | 2016-12-14 18:35:54 +1100 PORTS / ZDoom : added the zdoom-specific things. This info was sourced from the ZDoom wiki "standard editor numbers" page. ------------------------------------------------------------------------ a36b073bceba | Andrew Apted | 2016-12-14 18:12:45 +1100 TODO update. ------------------------------------------------------------------------ 357386ee49da | Andrew Apted | 2016-12-14 17:20:50 +1100 FindCrossingPoints : tweaked the 'close_dist' calculation. ------------------------------------------------------------------------ 64bb7bd8a27f | Andrew Apted | 2016-12-14 16:46:33 +1100 Fixed new linedef auto-split code to not create overlapping lines. ------------------------------------------------------------------------ ccf0cae85fbd | Andrew Apted | 2016-12-14 16:41:45 +1100 FindCrossingPoints : fixed 'along' values when checking linedefs, need to store the distance along the WHOLE original line. ------------------------------------------------------------------------ b70fd014f421 | Andrew Apted | 2016-12-14 16:22:57 +1100 TODO : tidying. ------------------------------------------------------------------------ 64200fe91242 | Andrew Apted | 2016-12-14 16:20:46 +1100 crossing_point_c : implemented the Sort() method. ------------------------------------------------------------------------ c8704d69e393 | Andrew Apted | 2016-12-14 16:15:25 +1100 crossing_state_c : implemented add_vert() and add_line(). ------------------------------------------------------------------------ 30881db715ff | Andrew Apted | 2016-12-14 16:10:26 +1100 FindCrossingPoints : bbox test to quickly eliminate linedefs. ------------------------------------------------------------------------ 9204fcc5c063 | Andrew Apted | 2016-12-14 15:47:23 +1100 FindCrossingPoints : code tidying. ------------------------------------------------------------------------ e2f04487a512 | Andrew Apted | 2016-12-14 15:41:02 +1100 FindCrossingPoints : ignore linedefs where an end-point is already within set of vertices in the crossing_state. Tweaked epsilon values (use some #defines for them). ------------------------------------------------------------------------ c66d67092bdc | Andrew Apted | 2016-12-14 15:34:07 +1100 Basis : added LineDef::TouchesCoord() method. ------------------------------------------------------------------------ ad071d0aef07 | Andrew Apted | 2016-12-14 14:41:12 +1100 Wiki : made the background a little bit brighter. ------------------------------------------------------------------------ 9cf000d00e1d | Andrew Apted | 2016-12-14 14:28:47 +1100 FindCrossingPoints : split algorithm into two phases, finding all vertices in the first phase, and second phase processes each pair of adjacent vertices to find crossing linedefs. ------------------------------------------------------------------------ bf8fd9bb72c3 | Andrew Apted | 2016-12-14 14:15:33 +1100 Began work on improved auto-splitting code when inserting new lines, using new "crossing_state_c" class to encapsulate the cross points. ------------------------------------------------------------------------ cbd45bfd9feb | Andrew Apted | 2016-12-13 23:26:18 +1100 Test map : support for the "-merge" option when building the command-line arguments. Although the logic *when* to employ that option is too simplistic atm. ------------------------------------------------------------------------ 2b2ccccfecec | Andrew Apted | 2016-12-13 22:39:22 +1100 TODO update. ------------------------------------------------------------------------ 60828d873ae1 | Andrew Apted | 2016-12-13 22:38:44 +1100 PORTS / ZDoom : renamed the fragglescript specials. ------------------------------------------------------------------------ bdc78d935af1 | Andrew Apted | 2016-12-13 22:35:05 +1100 PORTS / Eternity : moved slope linetypes to the "Stairs" category, consistent with the other ports. ------------------------------------------------------------------------ 5ec45ad390fb | Andrew Apted | 2016-12-13 22:31:22 +1100 PORTS / ZDoom : fixed using STAIRS category for some special FX. ------------------------------------------------------------------------ 48730038c580 | Andrew Apted | 2016-12-13 22:26:54 +1100 PORTS : added three line categories to doom_groups.ugh: "Scripting", "Renderer" and "3D Floor", and use them consistently in each port. ------------------------------------------------------------------------ a8aab81787a3 | Andrew Apted | 2016-12-13 22:09:45 +1100 GAMES / Heretic : include "doom_groups", fixing the stairs to use "s" and removing the unused "Sounds" category. ------------------------------------------------------------------------ 6dcd93be2ef9 | Andrew Apted | 2016-12-13 22:04:54 +1100 GAMES / Strife : include "doom_groups" (most were the same). ------------------------------------------------------------------------ 2e30d1350ca6 | Andrew Apted | 2016-12-13 21:56:52 +1100 GAMES : separated out groups for DOOM linetypes --> doom_groups.ugh ------------------------------------------------------------------------ b17469ec8147 | Andrew Apted | 2016-12-13 21:49:03 +1100 PORTS : separated out groups for HEXEN specials --> hexen_groups.ugh ------------------------------------------------------------------------ ecc94ac3a5c2 | Andrew Apted | 2016-12-13 21:39:59 +1100 Game def parser : support "spec_group" directive, equivalent to "linegroup" but only applies to HEXEN format maps. ------------------------------------------------------------------------ 7413da0b6303 | Andrew Apted | 2016-12-13 21:17:53 +1100 PORTS / ZDoom : added "ZD:" prefix to the ZDoom-specific doom-format line types, and changed category of 3D Floors to "y" since "v" is already being used for the BOOM elevators. ------------------------------------------------------------------------ 8154298b96be | Andrew Apted | 2016-12-13 20:59:29 +1100 Preferences : improved look of the tabs, the background of all the unselected tabs are now drawn darker than normal, so the current tab stands out. ------------------------------------------------------------------------ 0ab33cb990c7 | Andrew Apted | 2016-12-13 20:36:22 +1100 PORTS / ZDoom : added all the extra Doom-format line types. These were adapted from the SLADE editor (once again). ------------------------------------------------------------------------ 6629aff212f1 | Andrew Apted | 2016-12-13 20:14:24 +1100 TODO update. ------------------------------------------------------------------------ 6c682f75fbe0 | Andrew Apted | 2016-12-13 18:35:39 +1100 Sector auto-insert : fleshed out logic for determining better texture to use on fresh linedefs. But it does not handle the important case of building a sector off an existing 1S wall... ------------------------------------------------------------------------ 2a46c09dcdf0 | Andrew Apted | 2016-12-13 18:31:03 +1100 Operation menu : ensure the popup menus normally stay hidden, which fixes the bug where line-drawing stopped at an invisible rectangle (due to mouse "entering" the menu and sending FL_LEAVE to the canvas). ------------------------------------------------------------------------ ac0805a43a93 | Andrew Apted | 2016-12-13 15:38:12 +1100 Sector auto-insert : began work to choose better default textures for the newly added linedefs.... ------------------------------------------------------------------------ e3b60f641242 | Andrew Apted | 2016-12-13 15:08:10 +1100 Basis : optional 'new_tex' parameter for SideDef::SetDefaults(). ------------------------------------------------------------------------ f0d4f9370395 | Andrew Apted | 2016-12-13 14:11:44 +1100 Wiki : improved look of the editing Cheat Sheet. ------------------------------------------------------------------------ 59f9826e5011 | Andrew Apted | 2016-12-13 13:56:34 +1100 Wiki : tweaked the hyperlink colors ("a" tags). ------------------------------------------------------------------------ c66aacdbf13b | Andrew Apted | 2016-12-13 13:31:34 +1100 Wiki : removed search box from bottom of page. ------------------------------------------------------------------------ e166f9f5a852 | Andrew Apted | 2016-12-13 13:22:10 +1100 Wiki : always disable the automatic page title, and tidied up the HTML in the template file. ------------------------------------------------------------------------ 521260ae8c4c | Andrew Apted | 2016-12-12 19:09:19 +1100 Sector auto-insert : removed the old ClosedLoop_XXX code. ------------------------------------------------------------------------ dcfb04dbb6d8 | Andrew Apted | 2016-12-12 17:04:08 +1100 Sector auto-insert : proper logic to determine model for new sector (when splitting an existing one, or void space). ------------------------------------------------------------------------ 3cb3ddd5c2d0 | Andrew Apted | 2016-12-12 16:55:08 +1100 Sector auto-insert : main logic for the split-sector cases. ------------------------------------------------------------------------ 23fcd415666a | Andrew Apted | 2016-12-12 16:39:31 +1100 Sector auto-insert : got logic for creating islands (inside a sector or out in void space) working again. ------------------------------------------------------------------------ c0c28f3cb640 | Andrew Apted | 2016-12-12 15:43:54 +1100 Sector auto-insert : use new DetermineSector() method and get the lengths of the line loops. ------------------------------------------------------------------------ 08963aa696ff | Andrew Apted | 2016-12-12 15:41:07 +1100 lineloop_c : added DetermineSector() method. ------------------------------------------------------------------------ 85f87fc0bc30 | Andrew Apted | 2016-12-12 15:22:16 +1100 Sector auto-insert : more work on new logic, handle any outward facing lineloop (if there is one). ------------------------------------------------------------------------ fca7db6ef447 | Andrew Apted | 2016-12-12 14:52:06 +1100 Began work on new logic handling the auto-insertion of sectors when closing linedef loops, as it should not matter exactly where the user closed the loop. ------------------------------------------------------------------------ 0f75792b5f1c | Andrew Apted | 2016-12-11 23:55:12 +1100 CHANGELOG and TODO update. ------------------------------------------------------------------------ 8d8d0dab7402 | Andrew Apted | 2016-12-11 23:23:24 +1100 Wiki : increased base font size from 11pt --> 14pt ------------------------------------------------------------------------ 814ffe78cb4e | Andrew Apted | 2016-12-11 23:06:56 +1100 Wiki : removed trailing whitespace from the CSS and TMPL files. ------------------------------------------------------------------------ 446bcb65d302 | Andrew Apted | 2016-12-11 23:04:15 +1100 Wiki : checked in our pmwiki skin files: wiki/eureka.css + wiki/eureka.tmpl ------------------------------------------------------------------------ e8a711d3ec4b | Andrew Apted | 2016-12-11 21:13:25 +1100 Improved method to find the right line loop when inserting a sector, handling the case of hitting an island much better: look at linedefs opposite the ones in the island, and keep looking even when we hit other islands. ------------------------------------------------------------------------ 6b3d2b2b8724 | Andrew Apted | 2016-12-11 18:53:14 +1100 lineloop_c : when finding islands, handle isolated linedefs. ------------------------------------------------------------------------ 6b318acfbb58 | Andrew Apted | 2016-12-11 18:25:28 +1100 Fixed recent bug, when inserting a sector and failing to trace the lineloop then a dud sector was still created. ------------------------------------------------------------------------ e4a81bdf03d2 | Andrew Apted | 2016-12-11 18:09:38 +1100 TraceLineLoop : support tracing along both sides of a linedef, and tracing around a dangling vertex. ------------------------------------------------------------------------ f029801de4f8 | Andrew Apted | 2016-12-11 17:31:59 +1100 minor rename : "LD_" prefix for AngleBetweenLines(). ------------------------------------------------------------------------ cc9a8312828b | Andrew Apted | 2016-12-11 17:11:21 +1100 TraceLineLoop : explicit check for an isolated linedef. ------------------------------------------------------------------------ 300e2b5bbbee | Andrew Apted | 2016-12-11 17:08:36 +1100 minor tidying in TraceLineLoop(). ------------------------------------------------------------------------ 2805645816ba | Andrew Apted | 2016-12-11 17:02:39 +1100 code tidying : moved LD_GetTwoNeighbors() --> e_linedef.cc/h ------------------------------------------------------------------------ cd7a1783f958 | Andrew Apted | 2016-12-11 16:56:41 +1100 tweak to ClosedLoop_Complex, don't check original loop when splitting. ------------------------------------------------------------------------ 7bee3cea887a | Andrew Apted | 2016-12-11 16:49:41 +1100 lineloop_c : AssignSector() is now a method of lineloop_c. ------------------------------------------------------------------------ 7d2b2027d8ac | Andrew Apted | 2016-12-11 15:30:26 +1100 lineloop_c : renamed FacesSector() method --> IslandSector(), made it ignore lines which face the void (keep looking for a possible outer sector), and some tidying up of code using this method. ------------------------------------------------------------------------ ac025a8ac51c | Andrew Apted | 2016-12-11 15:14:01 +1100 minor rename : lineloop_c::AllNew() --> AllBare(). ------------------------------------------------------------------------ ed91965d70ff | Andrew Apted | 2016-12-11 14:54:18 +1100 fixed recent bug: cannot highlight vertex #0, linedef #0, etc... ------------------------------------------------------------------------ fb16ac973537 | Andrew Apted | 2016-12-11 14:52:17 +1100 Canvas : in drawing mode, show all the linedefs/vertices that will be crossed by the current line (as orange blobs). ------------------------------------------------------------------------ 401c0db29781 | Andrew Apted | 2016-12-11 13:05:54 +1100 code : tidied up all the GetNearObject() logic, replacing most usage Close_obj class with simpler code. ------------------------------------------------------------------------ a2becb3a05e7 | Andrew Apted | 2016-12-10 23:46:25 +1100 Fixed overly zealous highlighting of vertices when zoomed in far. ------------------------------------------------------------------------ 6be3c314fcfa | Andrew Apted | 2016-12-10 21:41:38 +1100 Operation menu : save the current highlight before popping up the menu, and restore it before executing the chosen command, since the pop-up menu window causes the highlight to be cleared. ------------------------------------------------------------------------ 3f650e9d3cd5 | Andrew Apted | 2016-12-10 17:39:35 +1100 Menus : the /MENU flag idea was no good, so reverted the previous commit which added it. ------------------------------------------------------------------------ 5400e626d392 | Andrew Apted | 2016-12-09 21:41:31 +1100 TODO update. ------------------------------------------------------------------------ 4f4a68f9924f | Andrew Apted | 2016-12-09 21:40:22 +1100 Grid code : ensure that changes to the origin or Scale will update the current highlight. ------------------------------------------------------------------------ 6aa546db7b24 | Andrew Apted | 2016-12-09 21:17:40 +1100 Grid code : reorganized methods in Grid_State_c, and remove the CenterMapAt() method which was merely a synonym for MoveTo(). ------------------------------------------------------------------------ 040f6d24229a | Andrew Apted | 2016-12-09 21:05:27 +1100 made RedrawMap() always do an UpdateHighlight(). ------------------------------------------------------------------------ aebabeea8f99 | Andrew Apted | 2016-12-09 19:58:44 +1100 CHANGELOG / TODO update. ------------------------------------------------------------------------ 016576b4ba0e | Andrew Apted | 2016-12-09 19:57:53 +1100 part of previous commit (oops). ------------------------------------------------------------------------ e002265d60b5 | Andrew Apted | 2016-12-09 19:56:16 +1100 Improved ability to highlight/select very short linedefs, esp. ones which are only 1 or 2 units long. ------------------------------------------------------------------------ 52de25e87db2 | Andrew Apted | 2016-12-09 19:26:36 +1100 Event code : changed edit.map_x/y globals to be floating point, as well as the UI_Canvas::MAPX/MAPY inline methods. ------------------------------------------------------------------------ e4965043f85b | Andrew Apted | 2016-12-09 18:47:21 +1100 rethink on previous commit and removed Editor_NotifyChanges(). ------------------------------------------------------------------------ 9b1415db5d10 | Andrew Apted | 2016-12-09 18:45:16 +1100 minor rename : MarkChanges() --> Editor_NotifyChanges() ------------------------------------------------------------------------ 132fab0689a0 | Andrew Apted | 2016-12-09 18:40:23 +1100 code : simplified PointerPos() to set edit.map_x/y directly. ------------------------------------------------------------------------ 299aeda1ee21 | Andrew Apted | 2016-12-09 18:25:18 +1100 Event code : implemented a PointerPos() method which can determine the map coordinate at any time (outside of FLTK event passing). ------------------------------------------------------------------------ eb992126870e | Andrew Apted | 2016-12-09 17:21:59 +1100 Canvas : improved drawing of bold lines with the arrow, improving the arrow size for really short lines. ------------------------------------------------------------------------ 20e20a2a58e7 | Andrew Apted | 2016-12-09 16:46:56 +1100 Grid : added an extra zoom factor: 32:1 ------------------------------------------------------------------------ 946c71c903c0 | Andrew Apted | 2016-12-09 16:38:31 +1100 Event code : tidyied up EV_MouseMotion() function. ------------------------------------------------------------------------ 32ad584f046e | Andrew Apted | 2016-12-09 15:59:43 +1100 Event code : renamed some functions to EV_ prefix, and removed them from the global scope. ------------------------------------------------------------------------ 1e4ea77947fc | Andrew Apted | 2016-12-09 15:52:04 +1100 refactored the duplicate handle() code of UI_Canvas and UI_Render3D into a single function, EV_HandleEvent(), and improved the handling of FL_ENTER events via new EV_EnterWindow() function. ------------------------------------------------------------------------ 5e43057da0d1 | Andrew Apted | 2016-12-09 15:15:20 +1100 code : moved fields in Editor_State_t struct around and tweaked the comments, removed two unused fields. Also fixed Editor_Init() using memset to clear that structure, which is not kosher when it contains real C++ classes. ------------------------------------------------------------------------ 44f6d793e228 | Andrew Apted | 2016-12-09 01:40:06 +1100 TODO update. ------------------------------------------------------------------------ 38acbb944f05 | Andrew Apted | 2016-12-09 01:38:07 +1100 GAMES / Hexen : added spawn arguments to the handful of things which use them. ------------------------------------------------------------------------ d49cb6e0aea8 | Andrew Apted | 2016-12-09 01:35:08 +1100 Hexen format : support spawn arguments for things, both parsing from the game definition and tool-tipping in the Thing panel. ------------------------------------------------------------------------ d1325462cf1e | Andrew Apted | 2016-12-08 23:26:54 +1100 Added config variable "transparent_col", specifies color of the transparent pixels of textures (shown in the browser / panels). ------------------------------------------------------------------------ afaef8a8e501 | Andrew Apted | 2016-12-08 23:11:50 +1100 UI_Scroll : fixed the new JumpToChild() method. ------------------------------------------------------------------------ fcd64a044c44 | Andrew Apted | 2016-12-08 15:34:32 +1100 UI_Scroll : implemented the new JumpToChild() method. ------------------------------------------------------------------------ d0a7bc6701e6 | Andrew Apted | 2016-12-08 15:20:47 +1100 Browser : began work on ability to jump to a particular texture, flat, thing, etc.... ------------------------------------------------------------------------ 1918ca01c9da | Andrew Apted | 2016-12-08 14:27:09 +1100 minor rename : ShowBrowser() method --> BrowserMode() ------------------------------------------------------------------------ fa67f63412d0 | Andrew Apted | 2016-12-08 14:08:53 +1100 Drawing mode : fixed behavior when the line loop finishes at a self-reference line (a vertex or one split), which before was simply doing nothing. ------------------------------------------------------------------------ 959585773f33 | Andrew Apted | 2016-12-08 13:15:13 +1100 CHANGELOG and TODO update. ------------------------------------------------------------------------ 3ce1c14ea638 | Andrew Apted | 2016-12-08 13:11:52 +1100 Open Map : fixed crash when editing a pwad but then trying to open a map from the game iwad. ------------------------------------------------------------------------ 4c97a3fee64d | Andrew Apted | 2016-12-08 12:54:19 +1100 lib_file : fixed FilenameGetPath() code, which was quite borked. ------------------------------------------------------------------------ 31478892199d | Andrew Apted | 2016-12-08 12:42:14 +1100 Export Map : prevent the export if the chosen file is one which we already have open (like the IWAD or the current PWAD). ------------------------------------------------------------------------ a9e9aa0094f4 | Andrew Apted | 2016-12-08 12:20:03 +1100 Fixed potential crash when loading a map from the Given-files or Recent-files menus. ------------------------------------------------------------------------ 28d3bb3ba4c4 | Andrew Apted | 2016-12-08 11:41:08 +1100 Map loader : fixed a bug handling bad sidedef references in linedefs when the map has no sectors. ------------------------------------------------------------------------ a960783c8446 | Andrew Apted | 2016-12-08 11:24:13 +1100 BSP : don't crash on maps which consist entirely of dud linedefs (ones which lack any sidedefs). Treat the map as empty instead. ------------------------------------------------------------------------ 8579170b73b6 | Andrew Apted | 2016-12-07 23:56:39 +1100 code tidying : fixed several FatalError() and BugError() strings which lacked a trailing new-line ('\n'). ------------------------------------------------------------------------ 7ce770f75367 | Andrew Apted | 2016-12-07 23:31:39 +1100 CHANGELOG and TODO update. ------------------------------------------------------------------------ 9e4f7eaf289c | Andrew Apted | 2016-12-07 23:30:10 +1100 Checks : fixed the criss-cross linedef detection, which was too sloppy and did not handle some cases properly (like co-linear lines which partially overlap). ------------------------------------------------------------------------ 9a644ea29e57 | Andrew Apted | 2016-12-07 20:41:35 +1100 TODO update. ------------------------------------------------------------------------ 0544f2d85421 | Andrew Apted | 2016-12-07 19:37:39 +1100 Menus : pass /MENU flag to certain editing commands, so they will know that the current highlight cannot be used. ------------------------------------------------------------------------ 46f1721e99e6 | Andrew Apted | 2016-12-07 19:36:38 +1100 Menus : rearranged the HELP menu, removed dividing lines. ------------------------------------------------------------------------ 0109127fbeb9 | Andrew Apted | 2016-12-07 19:29:49 +1100 Menus : added "Operation Menu" to the VIEW menu, with F1 as the shortcut, and hence removed the F1 binding from bindings.cfg ------------------------------------------------------------------------ a606e2f41192 | Andrew Apted | 2016-12-07 19:03:29 +1100 dead code removal. ------------------------------------------------------------------------ efee4ad13d35 | Andrew Apted | 2016-12-07 19:01:28 +1100 Prefs / key bindings : ensure a fresh binding (from the "Add" and "Copy" buttons) will be visible and selected in the key list. ------------------------------------------------------------------------ 4ea96b420870 | Andrew Apted | 2016-12-07 16:47:45 +1100 Prefs / key bindings : fixed the Keyword/Flags menus not updating after selecting a new function, and renamed the "Mode" choices to be pluralized ("Linedefs", "Sectors", etc) like on the infobar. ------------------------------------------------------------------------ 54e96daba6f1 | Andrew Apted | 2016-12-07 16:33:50 +1100 Prefs / key bindings : don't have "General" as a selectable context when the command is context-limited (like SEC_Floor or LIN_Path). ------------------------------------------------------------------------ 0bba205a8598 | Andrew Apted | 2016-12-07 16:26:49 +1100 Prefs / key binding : got the "Mode" choice to be updated properly when a new function is selected. ------------------------------------------------------------------------ f4c702b845db | Andrew Apted | 2016-12-07 15:29:20 +1100 Prefs / key bindings : added code to populate the "Mode" choice, supporting deactivated items and handling the reverse order. ------------------------------------------------------------------------ fe43132d0206 | Andrew Apted | 2016-12-07 15:03:46 +1100 Prefs / key bindings : moved "Function" above "Mode" in key edit dialog, and tidied up the UI_EditKey constructor code. ------------------------------------------------------------------------ 2bf13d7e8e92 | Andrew Apted | 2016-12-07 14:12:52 +1100 tweaked default grid colors. ------------------------------------------------------------------------ 5a99882f7ba5 | Andrew Apted | 2016-12-07 14:12:00 +1100 Preferences : added tooltips to the colors in GRID tab. ------------------------------------------------------------------------ 5536f9583df3 | Andrew Apted | 2016-12-07 14:00:58 +1100 Preferences : fixed layout in the GRID tab. ------------------------------------------------------------------------ df4a286860c6 | Andrew Apted | 2016-12-06 22:28:10 +1100 LineDef panel : updated description as user types, and support hexadecimal in the type field (which is slighly useful for BOOM generalized line types). ------------------------------------------------------------------------ 2f1776e32884 | Andrew Apted | 2016-12-06 22:13:28 +1100 Defaults panel : update thing description as user types. ------------------------------------------------------------------------ d1adfe7ec7da | Andrew Apted | 2016-12-06 22:04:08 +1100 Thing panel : update description field as the user types, and also the special (when the map format is HEXEN). ------------------------------------------------------------------------ 2eb96ec4a959 | Andrew Apted | 2016-12-06 21:51:00 +1100 code : renamed "UI_PicName" --> "UI_DynInput". ------------------------------------------------------------------------ 61fd7b5592a4 | Andrew Apted | 2016-12-06 21:45:47 +1100 Sector panel : update description field as the user types. ------------------------------------------------------------------------ da05dfe352cb | Andrew Apted | 2016-12-06 20:46:59 +1100 TODO.txt : merged in the current WIP.txt stuff, updated some stuff that has been done, and general tidying up. ------------------------------------------------------------------------ 93820c2e45e0 | Andrew Apted | 2016-12-06 20:07:21 +1100 Browser : minor rename: "Line Types" --> "Line Specials". ------------------------------------------------------------------------ 6c992624ca8d | Andrew Apted | 2016-12-06 19:48:10 +1100 Bindings : for vertex mode, added SHIFT-MOUSE3 for inserting a vertex with "/continue" flag (matching SHIFT-INS and SHIFT-SPACE). ------------------------------------------------------------------------ 349075b4eccd | Andrew Apted | 2016-12-06 19:43:34 +1100 Insert command : removed "/new" flag -- it only did something in sectors mode, and now we *always* create a new sector. ------------------------------------------------------------------------ d69818948208 | Andrew Apted | 2016-12-06 19:10:35 +1100 PORTS / ZDoom : sorted out the categories for action specials, adding several new ones (in hexen_specials.ugh) and changing several specials. ------------------------------------------------------------------------ 643546827e8b | Andrew Apted | 2016-12-06 18:52:20 +1100 GAMES/PORTS : removed trailing whitespcae in hexen_specials.ugh ------------------------------------------------------------------------ 2d321a194fd6 | Andrew Apted | 2016-12-06 18:50:59 +1100 GAMES/PORTS : rename "sound" --> "sound_seq" in action specials. ------------------------------------------------------------------------ 50a9f0463262 | Andrew Apted | 2016-12-06 18:46:59 +1100 operations.cfg : changed name of 90-degree arc command. ------------------------------------------------------------------------ be8469affc1d | Andrew Apted | 2016-12-06 18:19:35 +1100 Delete command : simplified to have just a single "/keep" flag, instead of two variants (keep_things and keep_unused). ------------------------------------------------------------------------ a123703a16b7 | Andrew Apted | 2016-12-06 16:53:52 +1100 Browser : when opening the browser via binding or the menus, and that type of browser (e.g. textures) is already open, then close it. This is consistent with what CTRL-D (Defaults panel) and CTRL-F (Find/Replace panel) do. ------------------------------------------------------------------------ 6bde70c1a3cb | Andrew Apted | 2016-12-06 14:56:59 +1100 VT_ShapeArc : fixed error message when selection is empty. ------------------------------------------------------------------------ 3c14166d51a3 | Andrew Apted | 2016-12-06 14:13:26 +1100 Grid : made the dotty grid be a preference setting instead of a three-way toggle (which was confusing and not very useful). Also draw the square grid when sector rendering is enabled (i.e. don't force the grid off in that situation). Lastly, renamed a few config vars to have the "grid_" prefix. ------------------------------------------------------------------------ e7da65cdc70c | Andrew Apted | 2016-12-06 13:34:18 +1100 renamed the "Documentation" command --> "OnlineDocs". ------------------------------------------------------------------------ 3b21966059b3 | Andrew Apted | 2016-12-06 13:20:40 +1100 CHANGELOG update, rejigged the Games/Ports section. ------------------------------------------------------------------------ 4c5661dd2239 | Andrew Apted | 2016-12-06 13:18:28 +1100 Menus : added F1..F10 function keys as shortcuts for various menu items, F2..F4 are the Move/Scale/Rotate dialogs, F5..F8 are browser functions, F9 is the map checking (ALL), etc. Also changed "Toggle grid type" --> "Toggle gamma" in VIEW menu. ------------------------------------------------------------------------ 4484fd469767 | Andrew Apted | 2016-12-06 00:24:35 +1100 Reorganised command_table[], with new groups "Misc" and "2D View" replacing the "UI" group, and moving the "General" group down to be with the linedef/sector/etc operations. ------------------------------------------------------------------------ 19a9cec89297 | Andrew Apted | 2016-12-05 23:54:02 +1100 code tidying : use "()" instead of "(void)" for most CMD_xxx functions. ------------------------------------------------------------------------ a5e8d2a7fc57 | Andrew Apted | 2016-12-05 23:47:24 +1100 Set and Toggle commands : support "sec_render" keyword to change the current sector-rendering mode. ------------------------------------------------------------------------ f1d380e8a61c | Andrew Apted | 2016-12-05 23:36:20 +1100 Fixed sector merging -- unused sectors are now deleted and this was causing the wrong sector to be re-selected afterwards. ------------------------------------------------------------------------ 97b5488e9f56 | Andrew Apted | 2016-12-05 23:26:34 +1100 Fixed vertex merging to clear selection afterwards. ------------------------------------------------------------------------ efa4141be214 | Andrew Apted | 2016-12-05 22:12:16 +1100 PORTS / ZDoom : tidied up all the specials. ------------------------------------------------------------------------ b843d7f87506 | Andrew Apted | 2016-12-05 21:52:49 +1100 PORTS / ZDoom : added all the action specials, adapted (and condensed) from the SLADE editor. Not finished yet! ------------------------------------------------------------------------ dc65498211b5 | Andrew Apted | 2016-12-05 19:07:42 +1100 Key system : implemented better system for "lax" modifiers used by navigation commands, there is now a fake "LAX-" modifier for key bindings, and it must be present for the lax handling to kick in. ------------------------------------------------------------------------ 462b450306b4 | Andrew Apted | 2016-12-05 19:06:54 +1100 TODO : moved stuff around. ------------------------------------------------------------------------ e12c1b96ebcb | Andrew Apted | 2016-12-05 15:34:14 +1100 Key system : replaced Fl::event_shift() and Fl::event_ctrl() with checks using MOD_SHIFT and MOD_COMMAND, for consistent behavior on all platforms. ------------------------------------------------------------------------ ff0b0cd4f4a2 | Andrew Apted | 2016-12-05 01:41:32 +1100 Vertex_MergeList : fixed bug where the remaining vertex could also be deleted (e.g. merging all vertices of an isolated sector). ------------------------------------------------------------------------ a5a0adf499b7 | Andrew Apted | 2016-12-05 00:00:53 +1100 Version bump, as new "Test Map" command is working well. ------------------------------------------------------------------------ dfc32830f386 | Andrew Apted | 2016-12-04 23:59:26 +1100 Win32 : moved the RC file --> src/main.rc ------------------------------------------------------------------------ c87d0a26f096 | Andrew Apted | 2016-12-04 23:53:57 +1100 CHANGELOG and TODO update. ------------------------------------------------------------------------ 7e1a81e6b709 | Andrew Apted | 2016-12-04 23:50:23 +1100 Test Map : fixed silly bug, wrong name for resource wads. ------------------------------------------------------------------------ 98b1cfd066f6 | Andrew Apted | 2016-12-04 23:25:23 +1100 Test Map : fixed the relative EXE name to have "./" prefix to force the shell invoked by system() to find the EXE file, and fixed bug not adding "-file" before the pwad filename. ------------------------------------------------------------------------ b23fb4db54dd | Andrew Apted | 2016-12-04 23:08:44 +1100 Test Map : finished the GrabWadNames() logic. ------------------------------------------------------------------------ 10f03bc32063 | Andrew Apted | 2016-12-04 22:57:50 +1100 Test Map : partial work on GrabWadNames() logic, which handles all the wad filenames (iwad, resources, pwad). The string management is proving to be a headache though.... ------------------------------------------------------------------------ b002f22a02fa | Andrew Apted | 2016-12-04 22:22:27 +1100 Test Map : code to convert the level name to a warp option. ------------------------------------------------------------------------ ae581c7fa1cc | Andrew Apted | 2016-12-04 21:49:01 +1100 Test Map : in port setup, ensure filename is made absolute when adding it to the port-path database. ------------------------------------------------------------------------ 1782346adb4e | Andrew Apted | 2016-12-04 21:46:05 +1100 Test Map : logic for saving/restoring the current working directory, and chdir()-ing to the directory of the executable, and converting the executable name to a relative name. ------------------------------------------------------------------------ 6cea23e58c42 | Andrew Apted | 2016-12-04 21:34:07 +1100 lib_file : added FilenameGetPath() utility function. ------------------------------------------------------------------------ db98b44aad76 | Andrew Apted | 2016-12-04 21:14:11 +1100 Test Map : implemented M_IsPortPathValid(). ------------------------------------------------------------------------ 90f6d1bc8ba9 | Andrew Apted | 2016-12-04 21:08:38 +1100 Test Map : in project setup, only restrict names to "exe" extension on the Windows platform, since executables in Linux tend to have no extension at all. ------------------------------------------------------------------------ edc13e203407 | Andrew Apted | 2016-12-04 20:58:16 +1100 Test Map : pre-set the EXE name in the port setup dialog. ------------------------------------------------------------------------ 8e49d5aef9e5 | Andrew Apted | 2016-12-04 20:49:38 +1100 Test Map : utility to convert "vanilla" + game to a pseudo port name, and implemented the FIND button in the port setup dialog. ------------------------------------------------------------------------ 49fc6d94bcbe | Andrew Apted | 2016-12-04 20:28:54 +1100 Test Map / port setup : mention the correct port name, with special handling for vanilla. ------------------------------------------------------------------------ 070805f5e990 | Andrew Apted | 2016-12-04 19:59:20 +1100 Test Map : nailed down layout and message text of the source port setup dialog. ------------------------------------------------------------------------ 387e725ca64e | Andrew Apted | 2016-12-04 19:23:35 +1100 Test Map : change of tack, instead of having a dialog open when using the command, have a "Setup" button in the Manage Project dialog which opens another dialog for setting up the EXE path. So did a bit of work in this new direction.... ------------------------------------------------------------------------ 0069f1dcb865 | Andrew Apted | 2016-12-04 19:01:52 +1100 Test Map : bit more work on UI_TestMapDialog.... ------------------------------------------------------------------------ 4f4894281dec | Andrew Apted | 2016-12-04 17:53:54 +1100 OperationMenu : don't FatalError() when "operations.cfg" not found, show a notify dialog instead. ------------------------------------------------------------------------ 65bdddb6f23d | Andrew Apted | 2016-12-04 17:38:35 +1100 Test Map : implemented logic for creating/querying the exe path for a given port, and persisting that data in the "misc.cfg" file. ------------------------------------------------------------------------ a162e6b34b96 | Andrew Apted | 2016-12-04 16:06:31 +1100 Test Map : began work on a dialog window.... ------------------------------------------------------------------------ 14908a0b3f12 | Andrew Apted | 2016-12-04 15:29:43 +1100 Fix for "Export Map", always reload resources and do it *after* we have replaced the current edit_wad. ------------------------------------------------------------------------ effdd2d3c572 | Andrew Apted | 2016-12-04 15:21:28 +1100 Improved code in CMD_OpenMap(), ensure we reload resources when the edit_map is removed. ------------------------------------------------------------------------ 41265c4b8e23 | Andrew Apted | 2016-12-04 14:59:16 +1100 code refactoring in m_loadsave.cc : added ReplaceEditWad(). ------------------------------------------------------------------------ cedb68a94f02 | Andrew Apted | 2016-12-04 14:52:03 +1100 code tidying in OpenFileMap() function. ------------------------------------------------------------------------ a9028d2e7ffc | Andrew Apted | 2016-12-04 14:34:38 +1100 minor rename : check_sizes() --> CheckTypeSizes() ------------------------------------------------------------------------ 74d1b4382f64 | Andrew Apted | 2016-12-04 14:30:40 +1100 code tidying : more tweaking of comments before functions. ------------------------------------------------------------------------ 22f1668ba541 | Andrew Apted | 2016-12-04 14:30:09 +1100 lib_util : more code tidying... ------------------------------------------------------------------------ 2b9ecd9fe65d | Andrew Apted | 2016-12-04 14:23:45 +1100 lib_util : simplified y_stricmp() and y_strnicmp() code. ------------------------------------------------------------------------ c273f7f1c8c4 | Andrew Apted | 2016-12-04 14:10:01 +1100 code tidying : tweak comment style before some functions. ------------------------------------------------------------------------ da1ba7ff7357 | Andrew Apted | 2016-12-04 13:59:20 +1100 Menus : enabled the "Test in Game" command in FILE menu. ------------------------------------------------------------------------ 7cd2f4850b88 | Andrew Apted | 2016-12-04 13:38:47 +1100 Test Map : moved existing code from m_nodes.cc --> m_testmap.cc ------------------------------------------------------------------------ 6bebed59fa3d | Andrew Apted | 2016-12-04 13:32:50 +1100 Added code file "m_testmap.cc" -- this will contain the logic for running a source port to test (play) the current map. Empty so far. ------------------------------------------------------------------------ 3cfd013845bb | Andrew Apted | 2016-12-04 13:29:07 +1100 Test Map : minor commenting. ------------------------------------------------------------------------ 62e1c71fe8c5 | Andrew Apted | 2016-12-04 13:23:15 +1100 Preferences : added a "3D View" tab. ------------------------------------------------------------------------ 7913b5d7d3ff | Andrew Apted | 2016-12-04 00:29:44 +1100 TODO update (largish) + CHANGELOG update (smallish). ------------------------------------------------------------------------ d1b443b34bef | Andrew Apted | 2016-12-04 00:00:50 +1100 Added two new commands "Documentation" and "AboutDialog", and execute them for the HELP menu. ------------------------------------------------------------------------ 0b24e3d66620 | Andrew Apted | 2016-12-03 23:45:34 +1100 Menus : added commands for everything in the FILE menu, such as "NewProject", "OpenMap", "SaveMap", "PreferenceDialog" -- and the menu code calls these via ExecuteCommand(). ------------------------------------------------------------------------ 140fc653430f | Andrew Apted | 2016-12-03 23:25:54 +1100 BrowserMode command : support a "/recent" flag. ------------------------------------------------------------------------ 6c80ba6b5f09 | Andrew Apted | 2016-12-03 23:20:05 +1100 Menus : added four new commands "DefaultProps", "FindDialog", "FindNext" and "LogViewer" -- and run these commands in the menu code. ------------------------------------------------------------------------ 160d9bca0b03 | Andrew Apted | 2016-12-03 23:13:30 +1100 Bindings : because Insert is on MOUSE3 in vertex mode, we need to explicitly bind MOUSE3 in render mode to "OperationMenu". ------------------------------------------------------------------------ 96f4bc620725 | Andrew Apted | 2016-12-03 22:58:27 +1100 CHANGELOG and TODO update. ------------------------------------------------------------------------ bdc9abd5a67f | Andrew Apted | 2016-12-03 22:50:50 +1100 Bindings : use '/' instead of ENTER key for the "OperationMenu" command, since using ENTER key can interfere with input widgets (like texture names in the Sector panel). ------------------------------------------------------------------------ 5afe06109157 | Andrew Apted | 2016-12-03 22:33:26 +1100 Menus : changed several callbacks, e.g. in BROWSER menu, to use ExecuteCommand() instead of directly performing the action. ------------------------------------------------------------------------ 4dd3ea465bfc | Andrew Apted | 2016-12-03 22:29:24 +1100 Zoom command : support /center flag which zooms around the center of the 2D canvas (instead of around the mouse pointer). ------------------------------------------------------------------------ eeb994cf66de | Andrew Apted | 2016-12-03 22:06:49 +1100 code : fixed a few places not checking M_ParseLine result properly. ------------------------------------------------------------------------ 9302f822b399 | Andrew Apted | 2016-12-03 21:42:35 +1100 Operation menu : stop the popup menu being positioned so the last command used on that menu is under the mouse pointer. ------------------------------------------------------------------------ 9393d581cd2a | Andrew Apted | 2016-12-03 21:07:44 +1100 Operation menu : parse the command name and any parameters, and implemented the callback function to actually execute the command. ------------------------------------------------------------------------ 651e54f9997f | Andrew Apted | 2016-12-03 20:58:25 +1100 Key system : added ExecuteCommand() variant which directly uses an editor_command_t, added a fourth "paramX" parameter, and properly separate flag names (beginning with '/') from normal parameters. ------------------------------------------------------------------------ 24babd1f8d8f | Andrew Apted | 2016-12-03 20:06:14 +1100 Operation Menus : increased font size + better menu headings. ------------------------------------------------------------------------ 19501a1d92ce | Andrew Apted | 2016-12-03 20:05:55 +1100 code tidying : whitespace in main.cc ------------------------------------------------------------------------ f9aab5a92a02 | Andrew Apted | 2016-12-03 19:47:53 +1100 Operation menu : parse enough to show menu actions, and implemented the CMD_OperationMenu() code to popup the appropriate menu. ------------------------------------------------------------------------ 5b0885c07822 | Andrew Apted | 2016-12-03 19:17:04 +1100 Fixed bug in M_ParseLine() not handling spaces in string tokens. ------------------------------------------------------------------------ 9882ce61324e | Andrew Apted | 2016-12-03 18:09:55 +1100 Operation menu : logic to read and tokenize each line. ------------------------------------------------------------------------ ed6686301e73 | Andrew Apted | 2016-12-03 18:00:45 +1100 Operation menus : worked on the loading code, check for a missing file or a menu that was not parsed properly. ------------------------------------------------------------------------ ad4108e89760 | Andrew Apted | 2016-12-03 17:45:46 +1100 Began work on Operation menus.... ------------------------------------------------------------------------ e9bc9dfda30b | Andrew Apted | 2016-12-03 17:20:14 +1100 Makefile and pack scripts : ensure the new "defaults.cfg" and "operations.cfg" files get installed / packaged. ------------------------------------------------------------------------ 0a8f59e52b32 | Andrew Apted | 2016-12-03 17:14:30 +1100 Preferences / KEYS : prevent a horizontal scrollbar appearing in the key_list browser, and tweaked layout some more. ------------------------------------------------------------------------ 34a6d8337009 | Andrew Apted | 2016-12-03 17:06:06 +1100 Preferences : improved layout of KEYS tab. ------------------------------------------------------------------------ bc68275723b6 | Andrew Apted | 2016-12-03 16:50:32 +1100 Config : added comment to top of the written "config.cfg" file. ------------------------------------------------------------------------ c1acf0441b3b | Andrew Apted | 2016-12-03 16:31:07 +1100 Created "defaults.cfg" file, which contains the default settings. ------------------------------------------------------------------------ 265438b58ce5 | Andrew Apted | 2016-12-03 16:27:45 +1100 Preferences : notify user if "defaults.cfg" could not be loaded. ------------------------------------------------------------------------ a779997b479d | Andrew Apted | 2016-12-03 16:13:25 +1100 Preferences : implemented a new "Reset All Settings" button in the OTHER tab, and moved the "Reset Key Bindings" button here too. Also improved the wording of the confirmation dialog. ------------------------------------------------------------------------ bb0f0fcc6eef | Andrew Apted | 2016-12-03 15:34:04 +1100 Created "operations.cfg" -- contains the commands for the planned Operation menu. ------------------------------------------------------------------------ 08a0b4763727 | Andrew Apted | 2016-12-03 14:29:35 +1100 BSP : fixed bug when building nodes for maps which end up having a single subsector and no nodes (partition lines). ------------------------------------------------------------------------ d3974b8229a8 | Andrew Apted | 2016-12-03 13:45:20 +1100 Changed "Fresh Map" to bail when there is no edit_wad, which makes more sense than falling back to the "New Project" dialog. ------------------------------------------------------------------------ f16711d89ab4 | Andrew Apted | 2016-12-03 13:44:32 +1100 Config : renamed "gui_scheme" so users get the new default (GTK+) ------------------------------------------------------------------------ 610af1432c97 | Andrew Apted | 2016-12-03 13:34:50 +1100 Menus : rejig in FILE menu, renamed "New Map" --> "Fresh Map" and moved it down. ------------------------------------------------------------------------ d9646bfa94fe | Andrew Apted | 2016-12-03 13:13:59 +1100 Config files : added M_ParseDefaultConfigFile() function. ------------------------------------------------------------------------ 0d62617c10c6 | Andrew Apted | 2016-12-03 13:06:44 +1100 Menus : moved "View Logs" to the HELP menu. ------------------------------------------------------------------------ 488cfa4a42e4 | Andrew Apted | 2016-12-03 01:26:35 +1100 debugging : disabled the check for unused stuff, as I have plugged most of the holes now. ------------------------------------------------------------------------ 18334e765d11 | Andrew Apted | 2016-12-03 01:18:49 +1100 CMD_Delete : fixed an issue where deleting a bunch of vertices could leave some unused sidedefs. ------------------------------------------------------------------------ 7b5959712169 | Andrew Apted | 2016-12-03 01:05:52 +1100 Vertex_MergeList : when sandwich merging, fix flags of remaining linedef (TWO-SIDED and IMPASSIBLE flags). ------------------------------------------------------------------------ 182cd3135548 | Andrew Apted | 2016-12-03 00:57:17 +1100 Vertex_MergeLines : prevent unnecessary sandwich mergers. ------------------------------------------------------------------------ a6c332d0271b | Andrew Apted | 2016-12-03 00:25:20 +1100 Vertex_MergeList : improved the logic, collect ALL linedefs to be deleted into a selection and do them last, and ensure that ALL references to a merged-away vertex is changed to the kept one. ------------------------------------------------------------------------ 4f300619825e | Andrew Apted | 2016-12-02 23:44:33 +1100 code reorganising in e_vertex.cc ------------------------------------------------------------------------ 5067514180b8 | Andrew Apted | 2016-12-02 23:43:00 +1100 minor rename of "Vertex_HowManyLineDefs" function. ------------------------------------------------------------------------ 3494b2722f8a | Andrew Apted | 2016-12-02 23:39:44 +1100 Worked on making Vertex_MergeList() be the only conduit for merging two or more vertices -- however it is still buggy.... ------------------------------------------------------------------------ 9d44a951e041 | Andrew Apted | 2016-12-02 23:07:43 +1100 Checks : ignore zero-length lines when finding overlapping ones. ------------------------------------------------------------------------ c145f436101c | Andrew Apted | 2016-12-02 22:53:58 +1100 Checks : improved code to remove zero-length linedefs, ensure that there are no unused sectors or sidedefs afterwards. ------------------------------------------------------------------------ 2813e53f2ed5 | Andrew Apted | 2016-12-02 22:24:40 +1100 Made the Vertex_MergeList() not do BA_Begin/BA_End, instead the calling code does it. One benefit is that merging overlapping vertices is now a single undo/redo operation, rather than an operation for each merge pair. ------------------------------------------------------------------------ 7d0828a0d9d1 | Andrew Apted | 2016-12-02 22:23:32 +1100 Basis : prevent memory leak in BA_End() when no operations were done. ------------------------------------------------------------------------ bba5efe3f6c5 | Andrew Apted | 2016-12-02 22:00:54 +1100 Vertex panel : implemented 4 arrow buttons for position adjustment. ------------------------------------------------------------------------ 0aa4289270a6 | Andrew Apted | 2016-12-02 20:45:05 +1100 TODO and CHANGELOG update. ------------------------------------------------------------------------ ce587c836e6f | Andrew Apted | 2016-12-02 20:42:16 +1100 Drawing mode : when closing a line loop, select ALL vertices of the newly created sector (to allow switching to sector mode and having the new sector stay selected). ------------------------------------------------------------------------ ddf26dad9ed4 | Andrew Apted | 2016-12-02 20:27:31 +1100 Drawing mode : fixed several bugs in new Insert_Vertex logic. ------------------------------------------------------------------------ 017e5641fda2 | Andrew Apted | 2016-12-02 20:17:13 +1100 Rewrote the Insert_Vertex() code to be easier to understand. ------------------------------------------------------------------------ c028df403736 | Andrew Apted | 2016-12-02 16:58:52 +1100 Canvas : fixed not drawing a highlighted vertex when dragging a single vertex (which is needed to show a potential merge). ------------------------------------------------------------------------ c422577ad13f | Andrew Apted | 2016-12-02 16:56:53 +1100 Canvas : draw a single dragged vertex as orange, not yellow. ------------------------------------------------------------------------ d90b7fb72340 | Andrew Apted | 2016-12-02 16:37:27 +1100 When assigning a new sector to an area (CTRL-SPACE), ensure any sectors which are unused afterwards are removed. ------------------------------------------------------------------------ 2bae8a5b840e | Andrew Apted | 2016-12-02 16:03:00 +1100 dead code removal (namely DeleteLineDefs). ------------------------------------------------------------------------ 36fec0f79b5d | Andrew Apted | 2016-12-02 16:02:07 +1100 Fixed sector merging to not leave unused sectors behind. ------------------------------------------------------------------------ 6de9c2715f60 | Andrew Apted | 2016-12-02 15:59:48 +1100 Fixed bug in DeleteObjects_WithUnused(). ------------------------------------------------------------------------ 84e7bf0117ca | Andrew Apted | 2016-12-02 15:33:47 +1100 Refactored CMD_Delete, have a separate DeleteObjects_WithUnused(). ------------------------------------------------------------------------ 2109a90b2215 | Andrew Apted | 2016-12-02 15:18:29 +1100 When deleting a vertex and merging the two connecting lines, ensure we delete any sidedefs that would be unused afterwards. ------------------------------------------------------------------------ 799dac3cf083 | Andrew Apted | 2016-12-02 14:25:28 +1100 Debugging code for operations which leave unused sectors or sidedefs. ------------------------------------------------------------------------ 42f20bf6f3f8 | Andrew Apted | 2016-12-02 13:16:13 +1100 3D View : fixed pixel aspect handling, larger values should make each pixel *wider*, and the default should be 0.83 to match what DOOM originally looked like. This improved the rendering code too, as two "magic" constants (Y_SLOPE being 1.7, and 133 in CalcAspect) have been removed. Also renamed the config variable, so that upgrading users will get the proper pixel aspect value. ------------------------------------------------------------------------ b2f4f8135e55 | Andrew Apted | 2016-12-02 00:08:31 +1100 CHANGELOG and TODO update. ------------------------------------------------------------------------ 05b0339958e2 | Andrew Apted | 2016-12-01 22:37:41 +1100 Preferences : moved "Seg split logic" setting in the Nodes tab. ------------------------------------------------------------------------ 7c5a7dae527a | Andrew Apted | 2016-12-01 22:24:57 +1100 BSP : removed vestiges of the "one-sided window trick" handling. ------------------------------------------------------------------------ e504fd372fdb | Andrew Apted | 2016-12-01 20:03:52 +1100 BSP : fixed two issues with ZDoom format: (1) not sorting the segs unless GL nodes were also built (2) vertex indices of NEW vertices was wrong ------------------------------------------------------------------------ 69568dc59007 | Andrew Apted | 2016-12-01 15:25:14 +1100 BSP : code tidying, renamed "cur" variable --> "seg". ------------------------------------------------------------------------ 6794375bc6ec | Andrew Apted | 2016-12-01 15:12:39 +1100 Sprite loader : recolor the 4001..4004 player starts as blue. ------------------------------------------------------------------------ 8e3d6ec4a3a2 | Andrew Apted | 2016-12-01 15:05:55 +1100 PORTS : added player things 4001..4004 to Boom, Odamex and ZDoom. ------------------------------------------------------------------------ 7747e6821268 | Andrew Apted | 2016-12-01 14:45:54 +1100 Texture loader : validate the texture count and offset values. ------------------------------------------------------------------------ e7100bbde20d | Andrew Apted | 2016-12-01 13:32:20 +1100 TODO updated. ------------------------------------------------------------------------ cbe8d9685722 | Andrew Apted | 2016-12-01 13:29:31 +1100 Bindings : changed key to open texture-browser back to 'T', since it is useful in the 3D View but the 'X' key has a binding there. ------------------------------------------------------------------------ 3d9131c31d2d | Andrew Apted | 2016-12-01 13:21:52 +1100 Texture loader : use a proper method to detect STRIFE format of the TEXTURE1/2 lumps (same logic as in ZDoom), and structured the code better. ------------------------------------------------------------------------ a56ae864e7e0 | Andrew Apted | 2016-12-01 00:39:51 +1100 Bindings : restore 'q' to be Quantize (after testing some stuff). ------------------------------------------------------------------------ d3a772629e54 | Andrew Apted | 2016-12-01 00:39:01 +1100 Code : more tidying.... ------------------------------------------------------------------------ f64026a19dd4 | Andrew Apted | 2016-12-01 00:23:14 +1100 Disabled the half-finished feature to show thing skills via color (on the 2D canvas). May revisit the idea later.... ------------------------------------------------------------------------ 3b564712103f | Andrew Apted | 2016-12-01 00:18:59 +1100 Code : minor tidying. ------------------------------------------------------------------------ e7a9c6660529 | Andrew Apted | 2016-11-30 23:45:58 +1100 Code : simplified M_ParseCommandLine() and M_ParseEnvironmentVars() to be void functions, as they never returned anything meaningful. ------------------------------------------------------------------------ 3dde64363cec | Andrew Apted | 2016-11-30 23:26:19 +1100 BSP : for CMD_BuildAllNodes, check earlier if no levels exist, and removed the duplicated SetErrorMsg() code. ------------------------------------------------------------------------ ca42f3c54896 | Andrew Apted | 2016-11-30 23:11:43 +1100 minor tweak. ------------------------------------------------------------------------ 5f8f5205597b | Andrew Apted | 2016-11-30 22:46:18 +1100 TODO update. ------------------------------------------------------------------------ 426358794acd | Andrew Apted | 2016-11-30 22:45:06 +1100 BSP : implemented the XNOD format (for ZDoom nodes). ------------------------------------------------------------------------ e76e13671f1d | Andrew Apted | 2016-11-30 22:27:18 +1100 BSP : compute a "max_size" when saving ZDoom format NODES. ------------------------------------------------------------------------ cb7f10ea5c7a | Andrew Apted | 2016-11-30 22:25:36 +1100 BSP : free the message string in nodebuildinfo_t destructor. ------------------------------------------------------------------------ 628be7fef492 | Andrew Apted | 2016-11-30 21:52:08 +1100 BSP : actually honor the "Build Nodes on Save" setting. ------------------------------------------------------------------------ 9f1b016c2d19 | Andrew Apted | 2016-11-30 21:49:40 +1100 Preferences : removed (hidden) the "Force zlib compression" setting of the Nodes panel -- this is probably not worth supporting. ------------------------------------------------------------------------ aafd2bd2bc38 | Andrew Apted | 2016-11-30 21:45:26 +1100 BSP : prevent node-building a map twice in the case where the user has not saved the map, uses the "BuildAllNodes" command, and is asked whether to save the map and they choose yes. ------------------------------------------------------------------------ 86a9d4c9426f | Andrew Apted | 2016-11-30 21:35:58 +1100 BSP : handle it when the map is empty (no linedefs etc...) ------------------------------------------------------------------------ 890c5bb01498 | Andrew Apted | 2016-11-30 19:55:03 +1100 PORTS / ZDoom : include "hexen_specials.ugh" ------------------------------------------------------------------------ 0a32ce5fef27 | Andrew Apted | 2016-11-30 19:47:41 +1100 GAMES / Hexen : move special defs --> "common/hexen_specials.ugh" ------------------------------------------------------------------------ a5033d194ab2 | Andrew Apted | 2016-11-30 19:40:44 +1100 Removed "xlat_doom.cfg" and "xlat_hexen.cfg" files, they are unused and almost empty, and I plan translate maps in a different way. ------------------------------------------------------------------------ ce0d618837e5 | Andrew Apted | 2016-11-30 19:39:07 +1100 Game def parser : ignore "special" commands in DOOM map format, and "line" commands in HEXEN map format. ------------------------------------------------------------------------ 3cb5c2e4de1d | Andrew Apted | 2016-11-30 19:22:52 +1100 doc tweaks. ------------------------------------------------------------------------ 3b9cd49d380b | Andrew Apted | 2016-11-30 19:12:14 +1100 CHANGELOG : rearranged stuff and clarified some entries. ------------------------------------------------------------------------ 3eaf698d86ed | Andrew Apted | 2016-11-30 18:55:00 +1100 TODO update. ------------------------------------------------------------------------ 011628b07067 | Andrew Apted | 2016-11-30 18:37:07 +1100 Menus : added "Toggle Sprites" to the VIEW menu. ------------------------------------------------------------------------ 362423bfeb22 | Andrew Apted | 2016-11-30 18:32:58 +1100 Support new "sprites" keyword to Set and Toggle commands. ------------------------------------------------------------------------ 1fdc8d58e298 | Andrew Apted | 2016-11-30 18:30:42 +1100 Fixed the broken "Set" command (it parsed wrong argument). ------------------------------------------------------------------------ dc272fa4bb9a | Andrew Apted | 2016-11-30 18:19:51 +1100 UI : control thing drawing on 2D canvas via "edit.thing_render_mode", and added new config variable "thing_render_default" for it. ------------------------------------------------------------------------ 16c326274b98 | Andrew Apted | 2016-11-30 16:58:21 +1100 CHANGELOG : updated, especially for recent binding changes. ------------------------------------------------------------------------ a9db41fc0e19 | Andrew Apted | 2016-11-30 16:38:42 +1100 CHANGELOG and TODO update. ------------------------------------------------------------------------ c882282ac702 | Andrew Apted | 2016-11-30 16:36:52 +1100 UI : when bringing up a file chooser, set the default directory to a better value (namely: where the current PWAD is located). ------------------------------------------------------------------------ 073d58d1501b | Andrew Apted | 2016-11-30 16:35:24 +1100 PORTS / Odamex : fixed having "end" instead of "endif". ------------------------------------------------------------------------ 33f229170444 | Andrew Apted | 2016-11-30 16:07:32 +1100 CMD_Insert : don't try inserting stuff when 3D View is active (it can lead to strange things happening). ------------------------------------------------------------------------ b53cfdc59c8f | Andrew Apted | 2016-11-30 16:04:10 +1100 UI : when toggling the 3D view, give keyboard focus to the widget that is now active (render or canvas). ------------------------------------------------------------------------ 089d794e3bca | Andrew Apted | 2016-11-30 14:42:23 +1100 Sector panel : layout tweaks. ------------------------------------------------------------------------ 83e478c1b3d6 | Andrew Apted | 2016-11-30 14:27:52 +1100 Sector panel : changed "72" headroom button --> "64". ------------------------------------------------------------------------ b7a3307044b2 | Andrew Apted | 2016-11-30 14:20:10 +1100 UI : made default window size be a bit wider. ------------------------------------------------------------------------ 463ae50ef644 | Andrew Apted | 2016-11-30 14:16:16 +1100 UI : default theme is now "GTK+" ------------------------------------------------------------------------ 789c4f614d29 | Andrew Apted | 2016-11-30 14:07:54 +1100 UI : rejig colors for infobar edit-mode and free/snap widgets. ------------------------------------------------------------------------ 7588b197d534 | Andrew Apted | 2016-11-30 14:07:03 +1100 Preferences : rejig order of themes and colorsets. ------------------------------------------------------------------------ 32caab6d2079 | Andrew Apted | 2016-11-30 13:36:12 +1100 Bindings : bind 'a' to NAV_MouseScroll, 'MENU' to OperationMenu. ------------------------------------------------------------------------ f16ffae769a1 | Andrew Apted | 2016-11-30 00:54:29 +1100 dead code removal. ------------------------------------------------------------------------ d93abc4836fd | Andrew Apted | 2016-11-30 00:49:58 +1100 ACT_Click : when splitting a linedef, if BOTH ends of the linedef are in the selection then select the new vertex too. ------------------------------------------------------------------------ 4406f60b0ce5 | Andrew Apted | 2016-11-30 00:45:10 +1100 ACT_Click : support "/split" flag to allow splitting a linedef, and ensure we can drag the new vertex when keeping the button held down. ------------------------------------------------------------------------ 191888863519 | Andrew Apted | 2016-11-30 00:08:57 +1100 Preferences : small tidy up. ------------------------------------------------------------------------ 0512bed406c6 | Andrew Apted | 2016-11-30 00:08:15 +1100 Bindings : 'g' key now toggles the grid on/off. ------------------------------------------------------------------------ f9f32dc312da | Andrew Apted | 2016-11-30 00:04:54 +1100 Removed the "multi_select_modifier" config variable. ------------------------------------------------------------------------ 87b501b68d33 | Andrew Apted | 2016-11-30 00:01:30 +1100 Removed the "easier_drawing_mode" config variable. ------------------------------------------------------------------------ 5a4faa737ef2 | Andrew Apted | 2016-11-29 23:55:26 +1100 dead code removal. ------------------------------------------------------------------------ b8b8640e0f55 | Andrew Apted | 2016-11-29 23:04:14 +1100 Removed the never-used "mods" folder + support code. Rationale: the idea here was to include definition files for some famous DOOM mods with Eureka. However, none have been made so far and none are currently planned, and if we ever make some then they can simply be distributed as separate packages. ------------------------------------------------------------------------ b14113ad8a24 | Andrew Apted | 2016-11-29 22:57:08 +1100 TODO and CHANGELOG update. ------------------------------------------------------------------------ 0524f44062b5 | Andrew Apted | 2016-11-29 22:46:27 +1100 Bindings : bind ENTER key to "OperationMenu" command. ------------------------------------------------------------------------ 9c98bbdf6748 | Andrew Apted | 2016-11-29 22:34:58 +1100 Delete command : fixed bug where deleting a loop of linedefs (or their vertices) of an island inside another sector could delete the outer sector too. ------------------------------------------------------------------------ 7e7b9e502767 | Andrew Apted | 2016-11-29 21:49:09 +1100 TODO.txt : a few additions. ------------------------------------------------------------------------ 9d3ea15b1dde | Andrew Apted | 2016-11-29 21:44:30 +1100 Texture aligning : disabled the partial comparison of tex names, as it can lead to unexpected/confusing/surprising results. ------------------------------------------------------------------------ d06fdc2522c5 | Andrew Apted | 2016-11-29 21:28:17 +1100 Began work on "OperationMenu" command..... ------------------------------------------------------------------------ 070c17e57843 | Andrew Apted | 2016-11-29 21:27:54 +1100 Bindings : removed the CMD-MOUSE1 binding. ------------------------------------------------------------------------ 58815c0ad581 | Andrew Apted | 2016-11-29 20:59:47 +1100 Bindings : MOUSE3 in vertex mode is now "Insert" (begins line drawing), and MOUSE3 (with and without CTRL) in other modes is "OperationMenu" (which is not implemented yet, but will bring up a menu of operations). ------------------------------------------------------------------------ 01ebe1dbcf9a | Andrew Apted | 2016-11-29 20:55:11 +1100 Bindings : aesthetic changes only, use comments to mark each section of the file, moved all mouse button stuff to the top. ------------------------------------------------------------------------ af96039ad0c6 | Andrew Apted | 2016-11-29 20:47:58 +1100 Bindings : moved map-scroll/3d-navigation stuff from RMB --> MMB. ------------------------------------------------------------------------ 88574413ffb2 | Andrew Apted | 2016-11-29 20:42:25 +1100 Bindings : moved the scale/rotate/adjust-offset commands to 'r' key (plus modifiers), freeing up the middle mouse button. ------------------------------------------------------------------------ 9d9ecc4711b5 | Andrew Apted | 2016-11-29 20:41:12 +1100 EditMode command : handle unknown modes better. ------------------------------------------------------------------------ 8ea6ed01156a | Andrew Apted | 2016-11-29 19:50:08 +1100 LineDef panel : renamed "block walk" flag --> "impassible". ------------------------------------------------------------------------ 256ca5d76064 | Andrew Apted | 2016-11-29 19:46:03 +1100 Default grid snapping and show-grid are now OFF. ------------------------------------------------------------------------ b7bad16888b2 | Andrew Apted | 2016-11-29 19:38:45 +1100 Default editing mode is now "Vertices", since that is where line drawing happens, so it is the most common mode to use (especially when starting a new map). ------------------------------------------------------------------------ 5aa4057c399e | Andrew Apted | 2016-11-29 18:43:29 +1100 ACT_Click : re-implemented ability to select/deselect objects. ------------------------------------------------------------------------ 342af568d2ab | Andrew Apted | 2016-11-29 18:25:28 +1100 ACT_Click : re-implemented ability to drag objects. ------------------------------------------------------------------------ 2fc34192b5cc | Andrew Apted | 2016-11-29 18:13:19 +1100 Bindings : bound "ACT_SelectBox" to SHIFT-MOUSE1. ------------------------------------------------------------------------ 80c474d96ea3 | Andrew Apted | 2016-11-29 18:08:25 +1100 ACT_Click : start a selection-box when clicking in an empty area (requiring the "/select" flag). ------------------------------------------------------------------------ f41758a7f505 | Andrew Apted | 2016-11-29 16:27:14 +1100 Key system : removed "button_down" and "button_mod" fields from the global editor state. ------------------------------------------------------------------------ c4ecbb30bd17 | Andrew Apted | 2016-11-29 15:51:41 +1100 Key system : began work to handle "MOUSE1" (aka LMB) as a normal bindable command: "ACT_Click". So far it is very broken.... ------------------------------------------------------------------------ d593372c6ba3 | Andrew Apted | 2016-11-29 14:13:20 +1100 Key system : honor the speed parameter of "NAV_MouseScroll" and "3D_NAV_MouseMove" commands. ------------------------------------------------------------------------ da0bff6f09b8 | Andrew Apted | 2016-11-29 13:47:30 +1100 Key system : handle SHIFT properly for "3D_ACT_AdjustOfs" command. ------------------------------------------------------------------------ 65163383afc3 | Andrew Apted | 2016-11-29 13:42:13 +1100 Key system : for navigation in 2D or 3D views, support SHIFT and CTRL modifiers to slow down / speed up the movement. ------------------------------------------------------------------------ fc8e232382ef | Andrew Apted | 2016-11-29 13:17:11 +1100 Key system : split NAV_Scroll_X command into two (_Left and _Right), and also NAV_Scroll_Y into _Up and _Down variants. This makes the scrolling work a bit more fluidly. ------------------------------------------------------------------------ b3db855c89f6 | Andrew Apted | 2016-11-29 12:47:49 +1100 Key system : split "NAV_MouseScroll" into two commands, where one is specifically for the 3D View, namely "3D_NAV_MouseMove". ------------------------------------------------------------------------ 20dcea9d7379 | Andrew Apted | 2016-11-28 23:56:44 +1100 TODO.txt : added a few things. ------------------------------------------------------------------------ 7d3c74afa709 | Andrew Apted | 2016-11-28 23:51:21 +1100 Renamed the "Check" command --> "MapCheck", with some code to ensure backwards compatibility when loading key bindings. ------------------------------------------------------------------------ 4e7b75defa36 | Andrew Apted | 2016-11-28 23:33:07 +1100 Bindings : removed SHIFT and CMD versions of the 3D_NAV_xxx binds, since the code now handles this explicitly. ------------------------------------------------------------------------ 396baab927a2 | Andrew Apted | 2016-11-28 23:24:50 +1100 Key system : once a navigation or action is underway, ignore it when only the modifiers have changed (i.e. the bare key or button is still pressed). ------------------------------------------------------------------------ 114bc655a9d6 | Andrew Apted | 2016-11-28 23:15:27 +1100 Key system : updated Nav_SetKey() and Nav_UpdateKeys() to handle commands that use "lax_mods", mainly the NAV_xxx commands. ------------------------------------------------------------------------ 0fe6bdfbcdb4 | Andrew Apted | 2016-11-28 22:39:47 +1100 Key system : allow certain commands, especially "NAV_xxx" ones, to specify one or more modifiers which it uses directly. Matching a binding will allow any of these "lax_mods" to be present or absent. ------------------------------------------------------------------------ a5611c121b12 | Andrew Apted | 2016-11-28 21:10:56 +1100 CHANGELOG : minor update. ------------------------------------------------------------------------ 8660f3ac9e4e | Andrew Apted | 2016-11-28 20:31:01 +1100 Preferences / key bindings : worked on a "Choose" button which shows a nice menu of available functions, grouped into categories. ------------------------------------------------------------------------ 3651ce28553a | Andrew Apted | 2016-11-28 16:18:03 +1100 Key system : added a "group_name" field to editor_command_t, and give most commands an apropriate name. Commands that only apply to a single editing mode (SEC_Floor etc) are computed from that. ------------------------------------------------------------------------ fa54698cbb5d | Andrew Apted | 2016-11-28 14:59:33 +1100 Preferences / key bindings : the "grab" mode now accepts mouse buttons (including the mouse-wheel). ------------------------------------------------------------------------ 4f2737d63c7b | Andrew Apted | 2016-11-28 14:59:04 +1100 Key system : added M_RawKeyForEvent() and M_CookedKeyForEvent() utility functions. ------------------------------------------------------------------------ 18714fef4f2b | Andrew Apted | 2016-11-28 14:15:15 +1100 Preferences : in the Edit Key dialog, added a "Grab" button which waits for the next key press. ------------------------------------------------------------------------ 3abb13a01228 | Andrew Apted | 2016-11-28 13:48:20 +1100 Preferences : made window slightly taller, and worked on the Key binding tab to have an "Add" button, renamed "Bind" --> "Re-bind". ------------------------------------------------------------------------ e14a897f2845 | Andrew Apted | 2016-11-28 10:51:43 +1100 Key system : remove menu shortcuts when that key has a binding, allowing keys previously hard-coded in the menus to be used for other functions (and preventing user confusion too). ------------------------------------------------------------------------ fb2a8c97332b | Andrew Apted | 2016-11-28 10:24:57 +1100 TODO and CHANGELOG update. ------------------------------------------------------------------------ 89afd3fdd697 | Andrew Apted | 2016-11-28 10:18:34 +1100 main() : separated FLTK setup stuff from opening the main window, load the key bindings before opening the main window, and tweaked the "init_progress" handling. ------------------------------------------------------------------------ d045f5df8b74 | Andrew Apted | 2016-11-28 00:57:07 +1100 UI : at startup, use Fl::focus() on the canvas widget to allow keyboard events to be handled, even when the mouse has not entered the main window yet. ------------------------------------------------------------------------ 05a191a8611d | Andrew Apted | 2016-11-27 23:01:46 +1100 PORTS : changed "include boom" --> "include mbf" for most ports. ------------------------------------------------------------------------ 88cc5d91d7cc | Andrew Apted | 2016-11-27 22:59:00 +1100 PORTS : added definition for MBF, removed MBF stuff from boom.ugh ------------------------------------------------------------------------ d9925e12a94f | Andrew Apted | 2016-11-27 20:12:41 +1100 Version bump, for support of the HARMONY TC. ------------------------------------------------------------------------ 64a073a88f55 | Andrew Apted | 2016-11-27 20:12:12 +1100 Canvas : support "scale" for sprites on the 2D view. ------------------------------------------------------------------------ 270d8e78905d | Andrew Apted | 2016-11-27 20:09:33 +1100 Renderer : support thing "scale" values. ------------------------------------------------------------------------ a572c9d5d0f6 | Andrew Apted | 2016-11-27 19:40:41 +1100 UI : support thing "scale" value in the UI_PIC widget. ------------------------------------------------------------------------ c6fb593b0f82 | Andrew Apted | 2016-11-27 19:11:07 +1100 PORTS : enabled "lax_sprites" feature for Boom (and hence every port which is Boom-compatible), and ZDoom. ------------------------------------------------------------------------ b585669f4f89 | Andrew Apted | 2016-11-27 19:07:51 +1100 GAMES / Harmony : enable the "lax_sprites" feature. ------------------------------------------------------------------------ 7d25625f3fab | Andrew Apted | 2016-11-27 19:06:54 +1100 Game defs : support a "lax_sprites" feature which allows finding sprite graphics outside of the S_START..S_END namespace. ------------------------------------------------------------------------ f93578e37e12 | Andrew Apted | 2016-11-27 18:47:30 +1100 CHANGELOG update. ------------------------------------------------------------------------ 618f625957f0 | Andrew Apted | 2016-11-27 18:43:17 +1100 Harmony : added "c" (ceiling) and "l" (lit) flags to things. ------------------------------------------------------------------------ d3257086e681 | Andrew Apted | 2016-11-27 18:33:49 +1100 Harmony : more fixes to thing defs, esp. what sprites are used. ------------------------------------------------------------------------ 3b7f689119d9 | Andrew Apted | 2016-11-27 17:20:55 +1100 Harmony : removed thing 2008 -- not used in this game. ------------------------------------------------------------------------ cf37853e398b | Andrew Apted | 2016-11-27 17:17:22 +1100 Harmony : fixed numerous thing definitions, like the "Beastling". ------------------------------------------------------------------------ 14b7fac7f4e9 | Andrew Apted | 2016-11-27 14:30:27 +1100 Harmony : fleshed out most of the things, based on the DEHACKED lump that exists in the harmony wad. ------------------------------------------------------------------------ 1a0f0b4456c8 | Andrew Apted | 2016-11-25 22:23:45 +1100 Thing panel : prevent the arrow buttons overlapping. ------------------------------------------------------------------------ 160bac6276eb | Andrew Apted | 2016-11-25 21:40:03 +1100 Game def parser : allow "thing" defs to supply a scale value. ------------------------------------------------------------------------ d806faf600fa | Andrew Apted | 2016-11-25 21:27:47 +1100 Harmony : workaround for the COLORMAP being broken. Color #0 of the palette is pure black, and colormap #0 keeps it black, but in colormap #1 it becomes bright white and darkens over subsequent colormaps as though it it were a white color. ------------------------------------------------------------------------ 1918d9a5440e | Andrew Apted | 2016-11-25 20:43:48 +1100 Game defs : beginnings of a HARMONY v1.1 definition file. ------------------------------------------------------------------------ c6d5c2f7314e | Andrew Apted | 2016-11-25 19:33:02 +1100 minor tweaks. ------------------------------------------------------------------------ 581eaea46c8b | Andrew Apted | 2016-11-25 19:24:04 +1100 Code tidying : ensure functions for all commands have "CMD_" prefix (except for rendering commands which have "R3D_" prefix). ------------------------------------------------------------------------ fa26728634ce | Andrew Apted | 2016-11-25 19:10:43 +1100 CHANGELOG and TODO update. ------------------------------------------------------------------------ 776b3a028fc9 | Andrew Apted | 2016-11-25 18:19:45 +1100 Image code : merged im_arrows.cc --> im_img.c and reformatted. ------------------------------------------------------------------------ 1ffa048cc96e | Andrew Apted | 2016-11-25 18:15:00 +1100 Image code : moved IM_CreateDogSprite() --> im_img.cc ------------------------------------------------------------------------ d906c607af43 | Andrew Apted | 2016-11-25 18:14:06 +1100 Tweaked handling of opening the most-recent pwad file. ------------------------------------------------------------------------ f6f15ec579af | Andrew Apted | 2016-11-25 17:13:08 +1100 Fixed the double loading of all resources at startup. ------------------------------------------------------------------------ 722a174ef842 | Andrew Apted | 2016-11-25 16:51:35 +1100 GAMES and PORTS : prevent Boom definitions being used in non-Doom games like Heretic and Strife. ------------------------------------------------------------------------ 27631dbee790 | Andrew Apted | 2016-11-25 16:42:09 +1100 Game def parser : properly support variables in "if" directive. ------------------------------------------------------------------------ 1ec129533070 | Andrew Apted | 2016-11-25 15:11:10 +1100 Game def parser : store tokens in a non-allocated buffer, which reduces how much memory is leaked. ------------------------------------------------------------------------ 4720f3bc718c | Andrew Apted | 2016-11-25 14:59:21 +1100 Game def parser : pre-set the $MAP_FORMAT variable. ------------------------------------------------------------------------ f76d15c14df4 | Andrew Apted | 2016-11-25 14:44:27 +1100 Game def parser : changed how PURPOSE_GameCheck and PURPOSE_PortCheck modes work, they now ignore *everything* except their keywords. That means the "include", "set" and "if"..."endif" directives are NOT handled in these two modes. Rationale here is to keep those modes as simple as possible, as the handling of variables and conditionals was going to be difficult to implement and potentially confusing. ------------------------------------------------------------------------ 4c30824d2658 | Andrew Apted | 2016-11-25 13:23:52 +1100 Game def parser : implemented new "set" command. ------------------------------------------------------------------------ 10b9d5854a7e | Andrew Apted | 2016-11-25 12:53:36 +1100 minor rename : dump_command_line_options --> M_PrintCommandLineOptions. ------------------------------------------------------------------------ 6097e9f3f4d1 | Andrew Apted | 2016-11-24 23:38:57 +1100 PORTS / ZDoom : only include "boom.ugh" file when map_format is DOOM, preventing Boom stuff being enabled in HEXEN format maps. ------------------------------------------------------------------------ d52de6689dca | Andrew Apted | 2016-11-24 23:36:23 +1100 Game def parser : support lines of the form "if $MAP_FORMAT is XXX" where XXX can be DOOM or HEXEN, which allows including or excluding definitions based on the current map's format. ------------------------------------------------------------------------ c974a41d42fb | Andrew Apted | 2016-11-24 23:21:07 +1100 PORTS / Boom : removed the obsolete "exclude_game" lines. ------------------------------------------------------------------------ 25b999d85252 | Andrew Apted | 2016-11-24 22:42:35 +1100 PORTS : treat "vanilla" as a special (fake) port, keeping its definition file empty (except for some comments), and have some special checks in the code e.g. can use it for *ANY* game. ------------------------------------------------------------------------ 870d183baa60 | Andrew Apted | 2016-11-24 22:08:37 +1100 PORTS : changed "medusa_bug" feature --> "medusa_fixed", and use that in all the ports which fix the Medusa bug. ------------------------------------------------------------------------ 83203bfa4668 | Andrew Apted | 2016-11-24 21:38:50 +1100 Code tidying : removed trailing whitespace in all files. ------------------------------------------------------------------------ 1fc634730d2e | Andrew Apted | 2016-11-24 21:35:33 +1100 Code files : yet another rename: e_misc.cc/h --> e_main.cc/h ------------------------------------------------------------------------ 39e7e96e73c2 | Andrew Apted | 2016-11-24 21:31:39 +1100 Code tidying : various minor changes (e.g. constructors). ------------------------------------------------------------------------ afae83fc9da9 | Andrew Apted | 2016-11-24 21:07:53 +1100 Code tidying : removed several functions/methods which are unused, and never likely to be useful. ------------------------------------------------------------------------ 95e874113897 | Andrew Apted | 2016-11-24 20:47:00 +1100 Code : fixed some memory alloc/dealloc issues. ------------------------------------------------------------------------ 9147391d11fe | Andrew Apted | 2016-11-24 20:45:56 +1100 Selection class : added a constructor for selection_iterator_c, plus some asserts checking that the iterator is valid. ------------------------------------------------------------------------ fb26f325f250 | Andrew Apted | 2016-11-24 20:08:09 +1100 (part of previous commit : removed the empty editloop.h file) ------------------------------------------------------------------------ fe9122ff16d3 | Andrew Apted | 2016-11-24 20:05:33 +1100 Code files : renamed editloop.cc/h --> m_events.cc/h ------------------------------------------------------------------------ f4d62c61134f | Andrew Apted | 2016-11-24 19:58:57 +1100 Code tidying : moved RedrawMap(), ZoomWholeMap(), GetCurrentObjs(), UpdateXXX() and Editor_ChangeMode() functions --> e_misc.cc ------------------------------------------------------------------------ 6ffd9607cd56 | Andrew Apted | 2016-11-24 19:48:44 +1100 Code tidying : moved Editor_State_t struct, "edit" global, the Editor_Init() function and few other bits ---> e_misc.cc/h ------------------------------------------------------------------------ 49ae44206739 | Andrew Apted | 2016-11-24 19:35:20 +1100 Code files : moved command funcs in editloop.cc --> e_commands.cc ------------------------------------------------------------------------ 536dbf8dd97c | Andrew Apted | 2016-11-24 18:50:39 +1100 Code files : renamed x_hover.cc/h --> e_hover.cc/h ------------------------------------------------------------------------ 630ce6ea7341 | Andrew Apted | 2016-11-24 18:42:43 +1100 Code files : merged x_loop.cc/h --> e_sector.cc/h ------------------------------------------------------------------------ 1b305b71bb5e | Andrew Apted | 2016-11-24 18:30:42 +1100 Code files : renamed levels.cc/h --> e_misc.cc/h ------------------------------------------------------------------------ cbbde3785688 | Andrew Apted | 2016-11-24 18:06:31 +1100 Code tidying : moved AngleBetweenLines() --> e_linedef.cc ------------------------------------------------------------------------ c17708a1c2dd | Andrew Apted | 2016-11-24 16:33:24 +1100 Code files : renamed e_loadsave and e_nodes --> "m_" prefix. ------------------------------------------------------------------------ cd52ab2cb72f | Andrew Apted | 2016-11-24 16:12:14 +1100 Code files : merged x_mirror.cc/h --> e_objects.cc/h ------------------------------------------------------------------------ 2e1551b895b2 | Andrew Apted | 2016-11-24 16:06:55 +1100 Code tidying : moved Texture_MatchPattern() --> ui_browser.cc ------------------------------------------------------------------------ 844c1981b10b | Andrew Apted | 2016-11-24 16:04:15 +1100 Code files : renamed objects.cc/h --> e_objects.cc/h ------------------------------------------------------------------------ 57f120e8d51e | Andrew Apted | 2016-11-24 15:58:42 +1100 Code files : merged e_checks2.cc --> e_checks.cc ------------------------------------------------------------------------ c33e741d9f47 | Andrew Apted | 2016-11-24 15:51:19 +1100 Code files : merged w_flat.* and w_sprite.* --> w_texture.* ------------------------------------------------------------------------ d31af0918532 | Andrew Apted | 2016-11-24 15:41:24 +1100 TODO : minor update. ------------------------------------------------------------------------ 62eadae19c34 | Andrew Apted | 2016-11-24 14:51:49 +1100 Ensure the "Level_format" is known for each Main_LoadResources() call, since it can affect the parsing of the config files. ------------------------------------------------------------------------ 766d029b1cf6 | Andrew Apted | 2016-11-24 14:32:32 +1100 BSP : for "Build All Nodes" command, don't reload the current level afterwards (as there is no need), and fixed order of the initial checks (i.e. editing a pwad *before* MadeChanges check). ------------------------------------------------------------------------ dfe187d0031f | Andrew Apted | 2016-11-24 13:37:40 +1100 Overhauled handling of textures which are empty strings: - on map load, detect this in SIDEDEFS and convert to "-" - typing an empty string in LineDef panel converts it to "-" - removed the confusing "is_missing_tex()" function ------------------------------------------------------------------------ b41e0fc5ada2 | Andrew Apted | 2016-11-24 13:05:29 +1100 UI : improved layout in "Open Map" dialog, moved PWAD name to the top, since that is the most important thing when the user wants to open a new file. Also simplified the radio buttons into a choice menu. ------------------------------------------------------------------------ 262afbe3c76d | Andrew Apted | 2016-11-24 12:21:27 +1100 Check / textures : fixed the unknown texture "FIX" button from changing the "-" empty texture on uppers and lowers. ------------------------------------------------------------------------ 37395213504d | Andrew Apted | 2016-11-23 22:42:19 +1100 CHANGELOG update. ------------------------------------------------------------------------ 4daf3140d005 | Andrew Apted | 2016-11-23 22:40:47 +1100 Fixed another case of a wad file not being closes when the user cancels the parsing of the "__EUREKA" lump. Also improved the code in the UI_OpenMap class, made it easier to understand. ------------------------------------------------------------------------ d277b20d0748 | Andrew Apted | 2016-11-23 22:04:45 +1100 Fixed not closing an opened wad when parsing an "__EUREKA" lump, detecting missing resources, and the user decided to cancel. ------------------------------------------------------------------------ 540bdaee5c1f | Andrew Apted | 2016-11-23 18:19:00 +1100 TODO update. ------------------------------------------------------------------------ d660e44c6f08 | Andrew Apted | 2016-11-23 18:17:19 +1100 BSP : actually use the new preference settings, transfer the values into the nodebuildinto_t structure. ------------------------------------------------------------------------ f5c73ad4a82a | Andrew Apted | 2016-11-23 17:14:48 +1100 Preferences : added config variables for the new "Nodes" settings, and ensure they are properly reflected in the preferences UI. ------------------------------------------------------------------------ ee95ee205030 | Andrew Apted | 2016-11-23 16:49:21 +1100 Preferences : finalized the layout of the new "Nodes" tab. [ None of the additional settings do anything yet.... ] ------------------------------------------------------------------------ 9f1c729ce086 | Andrew Apted | 2016-11-23 16:27:32 +1100 BSP : moved the "RoundPOW2" function --> lib_util.cc/h ------------------------------------------------------------------------ 362d7b84fc2f | Andrew Apted | 2016-11-23 16:26:42 +1100 Preferences : moved the "Keys" tab to the second spot. ------------------------------------------------------------------------ 837f6c03d4d2 | Andrew Apted | 2016-11-23 15:22:11 +1100 BSP : removed no-longer-used PrintMsg() function, added a warning message when the level structure seems broken. ------------------------------------------------------------------------ 3cd09c4557e8 | Andrew Apted | 2016-11-23 15:14:28 +1100 BSP : added "total_failed_maps" field to nodebuildinfo_t, also renamed the warning fields and the warning functions --> Warning() and MinorWarning(). ------------------------------------------------------------------------ 1070ce65e912 | Andrew Apted | 2016-11-23 14:56:57 +1100 BSP : define ZDoom format node structures in w_rawdef.h ------------------------------------------------------------------------ bf82f10b349b | Andrew Apted | 2016-11-23 14:31:52 +1100 BSP : removed all the ReportFailedLevels() stuff, instead we just print a warning for each hard failure (and also when swithcing to V5 or XNOD format), and a single "FAILED ...." message if the level had any hard failures. ------------------------------------------------------------------------ 941aec503693 | Andrew Apted | 2016-11-23 13:31:12 +1100 BSP : for ZDoom format nodes, we don't need RoundOffBSPTree() or PutVertices() since the lump contains extra vertices which are 32-bit (16.16 fixed point). ------------------------------------------------------------------------ deca06b2997b | Andrew Apted | 2016-11-22 22:40:22 +1100 BSP : re-implemented MarkHardFailure() and removed MarkSoftFailure(), MarkV5Switch() and MarkZDSwitch() functions. ------------------------------------------------------------------------ 623b2dc27405 | Andrew Apted | 2016-11-22 22:23:23 +1100 BSP : tidied up how BLOCKMAP overflow is handled, and simplified the message about building the current map. ------------------------------------------------------------------------ dbcda87476b9 | Andrew Apted | 2016-11-22 21:16:09 +1100 BSP : changed the internal PrintVerbose() and PrintMiniWarn() functions to do nothing. Removed "quiet" field of nodebuildfunc_t and renamed "mini_warnings" field --> "warnings". ------------------------------------------------------------------------ 03956c46e0e5 | Andrew Apted | 2016-11-22 21:05:07 +1100 Preferences : bit more work on the "Nodes" tab. ------------------------------------------------------------------------ 1cd6297f22b4 | Andrew Apted | 2016-11-22 20:38:06 +1100 Preferences : partial work to improve the node-building stuff. This commit adds a new "Nodes" tab. It also removes numerous redundant down_box() calls which Fluid tends to create. ------------------------------------------------------------------------ c11d0b9b3e8e | Andrew Apted | 2016-11-22 20:28:55 +1100 BSP : message about blockmap overflow is now a warning. ------------------------------------------------------------------------ 767a570f2c80 | Andrew Apted | 2016-11-22 15:58:33 +1100 For MacOS X, use the fl_mac_set_about() function in FLTK so the "About" item in the application menu opens our About window. [ This is untested, as I don't have any MacOS X computers... ] ------------------------------------------------------------------------ bbcf327bb49b | Andrew Apted | 2016-11-21 23:45:34 +1100 UI : disable FLTK's normal keyboard navigation system, since it often interferes with our user interface, especially the TAB key used to toggle the 3D view. ------------------------------------------------------------------------ 373414f72458 | Andrew Apted | 2016-11-21 23:20:01 +1100 TODO.txt : added list of BSP tasks. ------------------------------------------------------------------------ c27caa135f23 | Andrew Apted | 2016-11-21 23:11:33 +1100 Menu : increased # of remembered recent files (12 --> 24), and slightly improved their formatting in the menu. ------------------------------------------------------------------------ 0031856b4c9f | Andrew Apted | 2016-11-21 22:20:58 +1100 Wad code : comment with idea about truncating the file. ------------------------------------------------------------------------ 7557d22f453d | Andrew Apted | 2016-11-21 22:12:59 +1100 BSP : compute a "max_size" when writing the BLOCKMAP. ------------------------------------------------------------------------ d6e4b6410322 | Andrew Apted | 2016-11-21 21:17:46 +1100 BSP : ensure most calls to AddLump() or RecreateLump() supply an appropriate "max_size" value, to prevent the wad file from growing excessively big (need to know the size to re-use internal space). ------------------------------------------------------------------------ 99febe7fc789 | Andrew Apted | 2016-11-21 19:08:51 +1100 BSP : moved the polyobject-related constants --> w_rawdef.h ------------------------------------------------------------------------ 9d4db042f94c | Andrew Apted | 2016-11-21 19:02:28 +1100 BSP : moved raw_xxxx_t structures related to Nodes --> w_rawdef.h, removed other structures in bsp.h which have equivalents in w_rawdef.h (like raw_vertex_t), and updated some code for the differences. ------------------------------------------------------------------------ 631a2fa07e10 | Andrew Apted | 2016-11-21 18:39:42 +1100 BSP : tidied up the REJECT handling code, and fixed a bug where Lump_c::Finish() was not being called. ------------------------------------------------------------------------ 74498fabe8c7 | Andrew Apted | 2016-11-21 18:38:57 +1100 Fixed a recently introduced bug in SaveLevel(). ------------------------------------------------------------------------ f91d9672f912 | Andrew Apted | 2016-11-21 18:10:58 +1100 Version bump, for good progress with the BSP rework (etc). ------------------------------------------------------------------------ 24f8b1b3d076 | Andrew Apted | 2016-11-21 17:16:54 +1100 Menu : more use of ExecuteCommand() instead of calling CMD_XXX functions directly. Added Main_Quit(). Various code tidying. ------------------------------------------------------------------------ 8bdb5fddc35c | Andrew Apted | 2016-11-21 16:43:46 +1100 tweak of message when loading user state for a map. ------------------------------------------------------------------------ e5612bed34f4 | Andrew Apted | 2016-11-21 16:39:25 +1100 Wad code : replaced the FindLumpInLevel() methods with just one, LevelLookupLump(), which takes a lev_num instead of a lump index. ------------------------------------------------------------------------ 259b6ed93879 | Andrew Apted | 2016-11-21 16:20:16 +1100 Wad code : removed the old FindLevel() method, fixed LevelFormat() method to take a level number instead of a lump index. ------------------------------------------------------------------------ f76a4e30a40d | Andrew Apted | 2016-11-21 16:05:21 +1100 Wad code : use a level number in RemoveLevel() and RemoveGLNodes() methods, instead of a lump index. ------------------------------------------------------------------------ 424acebf7eb8 | Andrew Apted | 2016-11-21 15:57:38 +1100 Wad code : replaced FindFirstLevel() method with LevelFindFirst() which returns a level number (NOT a lump index). ------------------------------------------------------------------------ 7c0fd6629d18 | Andrew Apted | 2016-11-21 15:42:25 +1100 Wad code : renamed several methods related to levels: NumLevels --> LevelCount GetLevel --> LevelHeader LastLevelLump --> LevelLastLump FindLevelRaw --> LevelFind FindLevelByNumber --> LevelFindByNumber Also LevelFindByNumber() now returns a level number (NOT a lump index). ------------------------------------------------------------------------ 45feb6ef9c3f | Andrew Apted | 2016-11-21 14:29:07 +1100 Main menu : use ExecuteCommand() for the EDIT menu stuff, since calling the CMD_XXX functions directly is not really kosher, especially when the command looks at Exec_Param[]. ------------------------------------------------------------------------ e3831d36a23a | Andrew Apted | 2016-11-21 14:21:32 +1100 Added "Undo" and "Redo" as bindable commands. ------------------------------------------------------------------------ 1374e451957a | Andrew Apted | 2016-11-21 14:09:17 +1100 CHANGELOG : a few clarifications. ------------------------------------------------------------------------ 00e5ed1cc135 | Andrew Apted | 2016-11-21 14:08:20 +1100 Wad code : fixed stupid bug with AddLevel "lev_idx" parameter. ------------------------------------------------------------------------ 560341e39487 | Andrew Apted | 2016-11-21 13:28:25 +1100 minor tweak to some log messages. ------------------------------------------------------------------------ da6684cfa299 | Andrew Apted | 2016-11-21 13:21:43 +1100 Load/save code : removed "save_wad" variable, SaveLevel() always saves into the current "edit_wad" now. ------------------------------------------------------------------------ 9fa8f99cbe2f | Andrew Apted | 2016-11-21 12:57:52 +1100 Improved drag behavior: if the object is NOT in the selection, then only drag that single object (instead of adding it to the selection and dragging the whole selection). Hence removed the hacky "did_a_move" stuff, where doing a move and then selecting an object would clear the rest of the selection, since it only existed to make dragging individual objects easier. ------------------------------------------------------------------------ 868d78d11ab5 | Andrew Apted | 2016-11-21 01:06:22 +1100 BSP : fixed some bugs related to computing the GL checksum. ------------------------------------------------------------------------ 954d8d7636ed | Andrew Apted | 2016-11-21 00:33:41 +1100 BSP : added missing BeginWrite/EndWrite calls to SaveLevel(). ------------------------------------------------------------------------ 83f7d7c9636e | Andrew Apted | 2016-11-21 00:28:50 +1100 BSP : minor change to prevent a compiler warning. ------------------------------------------------------------------------ a2c932cb10cd | Andrew Apted | 2016-11-21 00:10:35 +1100 BSP : implemented BuildNodesAfterSave(), and call it just after saving the map in SaveLevel(). ------------------------------------------------------------------------ 9ad5330d2cd7 | Andrew Apted | 2016-11-21 00:07:44 +1100 Wad code : the AddLevel() method can now return the lev_idx, and prevent it from sorting the "levels" vector since that would invalidate the returned lev_idx. ------------------------------------------------------------------------ 0b8a14259934 | Andrew Apted | 2016-11-20 18:02:54 +1100 BSP : woah, FINALLY I SEE THE LIGHT! All the rubbish which CMD_BuildNodes() used to do, i.e. creating a new file, building nodes, deleting the old file, then renaming the new file to the old file -- that becomes totally unnecessary when you are simply building the nodes *inside* the current edit_wad. Hence updated the code accordingly. ------------------------------------------------------------------------ 831b1980a561 | Andrew Apted | 2016-11-20 17:51:58 +1100 BSP : more code jiggery pokery in e_nodes.cc ------------------------------------------------------------------------ ef5012c5a82b | Andrew Apted | 2016-11-20 17:26:27 +1100 BSP : removed "input_file" and "output_file" from nodebuildinfo_t, and factored out some code --> PrepareInfo() function. ------------------------------------------------------------------------ a4f53f69a6d0 | Andrew Apted | 2016-11-20 17:25:43 +1100 BSP : added back an internal SetErrorMsg() function. ------------------------------------------------------------------------ 7782c3f448ab | Andrew Apted | 2016-11-20 16:58:34 +1100 BSP : moved the UI_NodeDialog class --> e_nodes.cc ------------------------------------------------------------------------ dc5343fdbcae | Andrew Apted | 2016-11-20 16:52:46 +1100 BSP : minor code renaming. ------------------------------------------------------------------------ 495e4667f30e | Andrew Apted | 2016-11-20 16:41:00 +1100 BSP : removed a few unused util functions (UtilStr* UtilFormat). ------------------------------------------------------------------------ 9a5c30ab8e9e | Andrew Apted | 2016-11-20 16:34:54 +1100 BSP : code tidying, removed GCCATTR() attributes which were more cluttery than useful. ------------------------------------------------------------------------ c5e31b62923b | Andrew Apted | 2016-11-20 16:30:58 +1100 BSP : improved API in bsp.h, moved the parts needed by e_nodes.cc out of the namespace, and everything inside the namespace is just the internal structures and functions. ------------------------------------------------------------------------ 245948077836 | Andrew Apted | 2016-11-20 16:09:10 +1100 TODO update. ------------------------------------------------------------------------ 01cbfd2967e9 | Andrew Apted | 2016-11-20 14:08:26 +1100 Makefile.xming : added libfltk_jpeg.a and updated for FLTK 1.3.4 ------------------------------------------------------------------------ a018d85d6f40 | Andrew Apted | 2016-11-20 14:07:37 +1100 BSP : removed the "CreateDummyNode" bogus rubbish. ------------------------------------------------------------------------ 8ecc277c709c | Andrew Apted | 2016-11-20 14:02:51 +1100 Deleted two dummy files in obj_linux/ and obj_win32/ ------------------------------------------------------------------------ 657203452cd4 | Andrew Apted | 2016-11-20 12:48:34 +1100 BSP : removed all GB_DisplayXXX() calls, and logic for calculating fine-grained progress. Progress is now coarse, a step for each map in the wad. ------------------------------------------------------------------------ df4a6e8bcd5f | Andrew Apted | 2016-11-20 12:21:03 +1100 BSP : fixed a misleading comment about what "fast" mode does. ------------------------------------------------------------------------ 37baf69ba944 | Andrew Apted | 2016-11-20 12:17:13 +1100 BSP : removed all calls to GB_DisplayTicker(). ------------------------------------------------------------------------ e01033dc1b22 | Andrew Apted | 2016-11-20 12:10:11 +1100 BSP : tidied up usage of BUILD_XXX result codes. ------------------------------------------------------------------------ 5a4d1f2a1faa | Andrew Apted | 2016-11-20 12:05:02 +1100 BSP : code tidying in e_nodes.cc, merged CheckInfo() into parent. ------------------------------------------------------------------------ 01c7c6a1d6c6 | Andrew Apted | 2016-11-20 11:54:38 +1100 BSP : removed "block_limit" from nodebuildinfo_t. ------------------------------------------------------------------------ 4f689280f998 | Andrew Apted | 2016-11-20 01:16:37 +1100 Pack scripts : updated for removal of glbsp_src/ ------------------------------------------------------------------------ 2a0e39287936 | Andrew Apted | 2016-11-20 01:13:57 +1100 CHANGELOG update. ------------------------------------------------------------------------ 0522edf40a49 | Andrew Apted | 2016-11-20 00:59:35 +1100 BSP : removed the old code, i.e. everything under glbsp_src/ ------------------------------------------------------------------------ 5d226342ffc7 | Andrew Apted | 2016-11-20 00:57:28 +1100 BSP : removed unneeded function "CountWallTips" (it was only used by the code for detecting the one-sided window trick). ------------------------------------------------------------------------ 216934ca9a58 | Andrew Apted | 2016-11-20 00:56:20 +1100 BSP : removed unused variable (cpu_big_endian). ------------------------------------------------------------------------ 78b905b297ec | Andrew Apted | 2016-11-20 00:53:26 +1100 Makefile.xming : updated for the BSP rework. ------------------------------------------------------------------------ 8581557793bc | Andrew Apted | 2016-11-20 00:43:51 +1100 Merge branch 'bsp_rework' ------------------------------------------------------------------------ 0c8d095cd01a | Andrew Apted | 2016-11-20 00:35:36 +1100 BSP : removed unused function "UtilFileExists". ------------------------------------------------------------------------ 63f7c81a23ea | Andrew Apted | 2016-11-20 00:34:12 +1100 BSP : more minor code tidying (comments before functions). ------------------------------------------------------------------------ 24e4d060b66a | Andrew Apted | 2016-11-20 00:27:17 +1100 BSP : minor code tidying (whitespace in for loops). ------------------------------------------------------------------------ 81e0978c1d96 | Andrew Apted | 2016-11-20 00:14:16 +1100 TODO : yet another update. ------------------------------------------------------------------------ 09d1182286f8 | Andrew Apted | 2016-11-20 00:08:25 +1100 3D View : for highlighting, disabled check on the editing mode, since having to switch modes to adjust a wall (etc) is annoying. ------------------------------------------------------------------------ 32ddfcf7172a | Andrew Apted | 2016-11-19 23:54:27 +1100 LineDef panel : re-instated the "Gen" button, used to open the generalized line browser (for BOOM compatible ports). [ this is a partial revert of commit 833a5654cff6 ] ------------------------------------------------------------------------ 7be432cfdd02 | Andrew Apted | 2016-11-19 23:32:15 +1100 Created a proper dialog for the "JumpToObject" command, one which does not allow the user to enter an invalid number. ------------------------------------------------------------------------ bdb6b5d44429 | Andrew Apted | 2016-11-19 20:25:20 +1100 CHANGELOG and TODO update. ------------------------------------------------------------------------ 04c8769810db | Andrew Apted | 2016-11-19 19:30:48 +1100 Bindings : extra ACT_Transform binds for rotate/stretch/skew. ------------------------------------------------------------------------ 30c4cbd11869 | Andrew Apted | 2016-11-19 19:24:14 +1100 ACT_Transform : got the "skew" mode working. ------------------------------------------------------------------------ f6d679612f32 | Andrew Apted | 2016-11-19 19:23:24 +1100 minor debug tweak. ------------------------------------------------------------------------ a8926e157f4c | Andrew Apted | 2016-11-19 17:35:02 +1100 Code tidying : removed "CMD_" prefix from three more functions that are not true commands: MoveObjects(), OpenFileMap(), AdjustLight(). ------------------------------------------------------------------------ 2f2351f1c71f | Andrew Apted | 2016-11-19 17:20:50 +1100 Code tidying : changed prefix on "CMD_Copy" and "CMD_Paste" functions, since they are NOT actual key-system commands. ------------------------------------------------------------------------ 17d682deced9 | Andrew Apted | 2016-11-19 17:05:50 +1100 ACT_Transform : support four keywords: "scale", "stretch", "rotate" and "rotscale". ------------------------------------------------------------------------ 6e0d72655db1 | Andrew Apted | 2016-11-19 16:32:43 +1100 Added "Clipboard_Cut", "Clipboard_Copy", "Clipboard_Paste" commands which are equivalent to the EDIT menu functions. ------------------------------------------------------------------------ 5c560d73a609 | Andrew Apted | 2016-11-19 14:58:58 +1100 Renamed "ACT_Scale" command --> "ACT_Transform", and began work to support keywords (like "scale" and "rotate") as the parameter. ------------------------------------------------------------------------ 53b659536ca9 | Andrew Apted | 2016-11-19 14:36:11 +1100 Code : renamed "scale_param_t" --> "transform_t", and renamed some related methods/functions from "ScaleXyz" --> "TransformXyz". ------------------------------------------------------------------------ eebfaa4cf159 | Andrew Apted | 2016-11-19 13:27:00 +1100 Code tidying : removed "CMD_" prefix from functions in x_mirror.cc which did NOT actually implement a key system command. ------------------------------------------------------------------------ c325535271cb | Andrew Apted | 2016-11-19 13:21:39 +1100 scale_param_t structure now supports skew transforms. ------------------------------------------------------------------------ 8c5a02489068 | Andrew Apted | 2016-11-19 12:52:02 +1100 Bindings : added MOUSE2 bind for adjusting offsets in the 3D view (i.e. restore the previous behavior). ------------------------------------------------------------------------ b0051d6136e9 | Andrew Apted | 2016-11-19 12:36:29 +1100 CHANGELOG : updated, and grouped all bug fixes together. ------------------------------------------------------------------------ 68c1e37a8ab2 | Andrew Apted | 2016-11-19 12:31:09 +1100 3D View : fixed rendering of lowers with "LOWER UNPEG" flag which have a sky ceiling on the front and back sectors. The behaviour now matches the the original DOOM renderer. ------------------------------------------------------------------------ 860a839fe19d | Andrew Apted | 2016-11-19 00:12:11 +1100 Key system : implemented basic "Select" command, it just toggles the highlighted object in the selection (an experiment mainly....) ------------------------------------------------------------------------ b055d3fa4c3a | Andrew Apted | 2016-11-18 23:41:53 +1100 Key system : implemented "ACT_Drag" command, and temporarily disabled its function on the left mouse button. ------------------------------------------------------------------------ bc16f8d169ce | Andrew Apted | 2016-11-18 23:02:48 +1100 Bindings : bind "ACT_Scale" onto MOUSE2 (restore prev behavior). ------------------------------------------------------------------------ 982551b14d3b | Andrew Apted | 2016-11-18 22:51:10 +1100 Bindings : added bindings for WHEEL_UP and WHEEL_DOWN which zoom the 2D map view (i.e. restoring the default behavior). ------------------------------------------------------------------------ da97298afd2a | Andrew Apted | 2016-11-18 22:49:59 +1100 Removed the "mouse_wheel_scrolls_map" config variable, since the user now has full control over the mousewheel via bindings.cfg ------------------------------------------------------------------------ 51011d5fda8c | Andrew Apted | 2016-11-18 22:45:40 +1100 Key system : use key handler for mousewheel events on the 2D canvas, and implemented a "WHEEL_Scroll" command which can scroll the map based on the mousewheel deltas. ------------------------------------------------------------------------ c40e8bcccbf5 | Andrew Apted | 2016-11-18 22:27:25 +1100 Key system : replaced hard-coded mousewheel handling in 3D View with new "3D_WHEEL_Move" command. The parameter specifies what speed to move. ------------------------------------------------------------------------ 8a5a97ddbdc4 | Andrew Apted | 2016-11-18 21:57:01 +1100 Key system : re-implemented CMD_MetaKey to not use the action system, as I feel it is more low-level than that. ------------------------------------------------------------------------ b183ec28ec2b | Andrew Apted | 2016-11-18 20:23:18 +1100 Key system : updated bindings.cfg to use new name "GRID_Bump", and added some backwards-compatibility into the parsing code. ------------------------------------------------------------------------ bef2375c69ae | Andrew Apted | 2016-11-18 20:15:59 +1100 Key system : implemented "GRID_Zoom" which sets the zoom level to a specific value (well, the nearest available one). Hence removed the "digits_set_zoom" config variable, as the user now has full control via the key binding system. ------------------------------------------------------------------------ 55ddc9da693c | Andrew Apted | 2016-11-18 19:55:58 +1100 Key system : fixed info-bar widget for new "GRID_Set" command. ------------------------------------------------------------------------ e8ac69c2f64d | Andrew Apted | 2016-11-18 19:51:07 +1100 Key system : don't hard-code the digit keys, use new "GRID_Set" command to bind the digits. ------------------------------------------------------------------------ fd0115839672 | Andrew Apted | 2016-11-18 18:35:22 +1100 TODO : minor update. ------------------------------------------------------------------------ 30a99d9f5cd3 | Andrew Apted | 2016-11-18 18:31:49 +1100 Key system : implemented "ACT_Scale" command. ------------------------------------------------------------------------ 11967ca7eed0 | Andrew Apted | 2016-11-18 18:21:42 +1100 Key system : experiment with new "3D_ACT_AdjustOfs" command. ------------------------------------------------------------------------ 99487185913e | Andrew Apted | 2016-11-18 17:09:58 +1100 Key system : have a "current action key", and set it / test it for release independently of the navigation keys. ------------------------------------------------------------------------ 41d17ed0255e | Andrew Apted | 2016-11-18 16:42:44 +1100 Key system : experiment with ability to bind the selection-box action to a key, via new "ACT_Selbox_Mouse" command. ------------------------------------------------------------------------ 91221740b30d | Andrew Apted | 2016-11-18 15:37:25 +1100 Keys : pass mouse button #3 through the key handling system (instead of using the hard-coded logic), and implemented a "NAV_Scroll_Mouse" command which performs its original function. ------------------------------------------------------------------------ b079d10ad461 | Andrew Apted | 2016-11-18 14:39:37 +1100 Nav keys : separate 3D movement commands into two opposites, such as "3D_NAV_Forward" and "3D_NAV_Back", which works better when the user presses both at the same time. ------------------------------------------------------------------------ a2992c642937 | Andrew Apted | 2016-11-18 14:06:22 +1100 Keys : fixed parsing of uppercase letters in bindings.cfg ------------------------------------------------------------------------ 7757fd4772bb | Andrew Apted | 2016-11-18 14:02:08 +1100 Nav keys : finished smooth scrolling of 2D view (NAV_Scroll command). ------------------------------------------------------------------------ 53e4e4cb538c | Andrew Apted | 2016-11-18 12:37:28 +1100 Code tidying : moved more code around in editloop.cc ------------------------------------------------------------------------ 28179c6d9182 | Andrew Apted | 2016-11-18 12:24:56 +1100 Nav keys : began work on a "NAV_Scroll" command for the 2D view... ------------------------------------------------------------------------ a388825f8863 | Andrew Apted | 2016-11-18 11:55:14 +1100 Nav Keys : fixed 3D_NAV_Up command to turn off gravity (or produce an error message when the locked-gravity setting is on). ------------------------------------------------------------------------ dfcab69f4e1b | Andrew Apted | 2016-11-18 11:25:39 +1100 Bindings : changed all 3D movement keys (again), use the navigation commands (3D_NAV_Forward, 3D_NAV_Turn, etc....) ------------------------------------------------------------------------ ac88cb3a2b72 | Andrew Apted | 2016-11-18 11:24:36 +1100 Nav keys : fixed wrong turn speed in R3D_NAV_Turn(). ------------------------------------------------------------------------ 7c9a0edb3c32 | Andrew Apted | 2016-11-18 11:20:41 +1100 Nav keys : finished implementing the new R3D_NAV_xxx() functions. ------------------------------------------------------------------------ 40b33467fef9 | Andrew Apted | 2016-11-18 00:47:24 +1100 Nav keys : moved code computing the time difference --> editloop.cc (now called Nav_TimeDiff). ------------------------------------------------------------------------ 8e852c159daa | Andrew Apted | 2016-11-18 00:37:28 +1100 Nav keys : began work on new "3D_NAV_Forward", "3D_Nav_Turn" (etc) commands which will use the new navigation system. ------------------------------------------------------------------------ b384d67825cd | Andrew Apted | 2016-11-18 00:04:24 +1100 Nav keys : finished Nav_UpdateKeys() with logic to check whether the key (or mouse button) is still pressed or not. ------------------------------------------------------------------------ 602bee8d4a6b | Andrew Apted | 2016-11-17 23:50:10 +1100 Keys : FLTK only supports FL_Button+1 .. FL_Button+8, so fixed the is_mouse_button() function accordingly. ------------------------------------------------------------------------ 8eb48aec053d | Andrew Apted | 2016-11-17 23:43:12 +1100 Keys : fixed is_mouse_button() to ignore modifiers. ------------------------------------------------------------------------ cedb61defca4 | Andrew Apted | 2016-11-17 23:41:50 +1100 Keys : added is_mouse_button() function. ------------------------------------------------------------------------ 560d5c79e7ae | Andrew Apted | 2016-11-17 23:32:45 +1100 Code : removed a very out-of-date bit of backwards-compatibility. ------------------------------------------------------------------------ d9854c3a8dfa | Andrew Apted | 2016-11-17 23:18:45 +1100 Bindings : fixed default bindings for shifted symbols, e.g. "<" is now represented as "SHIFT-," etc... ------------------------------------------------------------------------ a3b2baf86010 | Andrew Apted | 2016-11-17 22:54:56 +1100 Keys : use "CTRL" for the shown modifier name in Linux and Windows, and keep the existing "CMD" name in MacOS X. The parsing code for bindings.cfg will accept both forms. ------------------------------------------------------------------------ 627c6da7ab05 | Andrew Apted | 2016-11-17 22:25:11 +1100 Key codes are now always a physical key + a modifier (or none). This means that uppercase letters are represented as the lowercase letter + MOD_SHIFT. Compatibility (like parsing and saving the bindings.cfg) has been kept, and uppercase letters are still shown in the KEYS preferences panel. But this change breaks compatibility with shifted symbols, in particular: '<', '>', '?', '|'. ------------------------------------------------------------------------ 78d8dbfcb0fe | Andrew Apted | 2016-11-17 20:05:46 +1100 Nav keys : bit more work on new system, fleshed out most of the new Nav_XXX() functions.... ------------------------------------------------------------------------ 94ca79549a3f | Andrew Apted | 2016-11-17 16:08:35 +1100 Began work on a "navigation" system, to allow multiple navigation functions to be active at the same time. ------------------------------------------------------------------------ fe5e36e6654f | Andrew Apted | 2016-11-17 15:47:31 +1100 Code tidying : moved the "CMD_xxx" and "BR_xxx" functions to be grouped together in editloop.cc ------------------------------------------------------------------------ 6f5b96e81231 | Andrew Apted | 2016-11-17 13:34:06 +1100 Canvas : optimized the sprite drawing by collecting batches of solid pixels, and by clipping sprites to the drawing area. ------------------------------------------------------------------------ bcad60a42182 | Andrew Apted | 2016-11-17 11:52:53 +1100 3D View : support a "/circle" flag to 3D_Turn command, which causes the camera to circle strafe. ------------------------------------------------------------------------ f34d75516380 | Andrew Apted | 2016-11-17 11:42:32 +1100 3D View : reworked navigation vars to use fwd/right/up instead of axis-aligned deltas. ------------------------------------------------------------------------ 1f6b558dacdf | Andrew Apted | 2016-11-17 00:01:33 +1100 TODO.txt : updated, moved a few entries to "NOT-TODO" section. ------------------------------------------------------------------------ 30422cddae88 | Andrew Apted | 2016-11-16 23:14:07 +1100 3D View : better logic for finding the ground height, check several points on the player's bounding box and use the maximum floor. ------------------------------------------------------------------------ 6dbbfbb7634f | Andrew Apted | 2016-11-16 22:50:55 +1100 Bindings : updated all 3D movement bindings for smooth movement. ------------------------------------------------------------------------ b5bf15804338 | Andrew Apted | 2016-11-16 22:40:58 +1100 Canvas : preliminary code for drawing sprites on the 2D canvas (it is very inefficient so far, but working). ------------------------------------------------------------------------ c1dde5589ca3 | Andrew Apted | 2016-11-16 21:32:52 +1100 3D View : support "/smooth" flag for all the 3D movement and turning commands, enabling the new smooth navigation logic. ------------------------------------------------------------------------ e3f4386042d6 | Andrew Apted | 2016-11-16 21:01:49 +1100 Preferences : for key bindings, show "3D view" instead of "render" for the KCTX_Render context, that is more user-focused language. ------------------------------------------------------------------------ 11060bf981f0 | Andrew Apted | 2016-11-16 19:55:05 +1100 3D Mode : more work on smooth navigation, getting the Forward/Backward commands working. ------------------------------------------------------------------------ a041733ecd42 | Andrew Apted | 2016-11-16 19:28:35 +1100 3D Mode : beginnings of smoother navigation, when a navigation is active (e.g. holding down a key) then call Render3D_Navigate() in a tight loop. ------------------------------------------------------------------------ bf3ed77d2185 | Andrew Apted | 2016-11-16 18:16:35 +1100 3D Mode : use float for 'z' view coordinate (instead of int). ------------------------------------------------------------------------ 6c8455833e91 | Andrew Apted | 2016-11-16 15:27:05 +1100 3D Mode : only highlight things when edit mode is Things. ------------------------------------------------------------------------ a7f1cfa683fb | Andrew Apted | 2016-11-16 15:02:20 +1100 3D Mode : implemented ability to highlight things. ------------------------------------------------------------------------ 15a37ed0d34d | Andrew Apted | 2016-11-16 14:42:40 +1100 3D Mode : fixed the highlight position being vertically out by 15 screen pixels or so. ------------------------------------------------------------------------ e0402c40d5a7 | Andrew Apted | 2016-11-16 14:22:30 +1100 3D Mode : draw things with unknown type as a question mark. ------------------------------------------------------------------------ 185dd8053648 | Andrew Apted | 2016-11-16 13:50:35 +1100 3D Mode : implemented highlighting sectors (floors or ceilings). ------------------------------------------------------------------------ e62d84fe7490 | Andrew Apted | 2016-11-15 22:35:35 +1100 3D Mode : improved the query() code and determine the sector. ------------------------------------------------------------------------ b26f4127f16b | Andrew Apted | 2016-11-15 22:09:59 +1100 3D Mode : support "thick" RenderLines. ------------------------------------------------------------------------ ca1126cff69a | Andrew Apted | 2016-11-15 21:37:16 +1100 Export Map : when target wad already specifies iwad/port/resources (via the __EUREKA lump), then keep them, i.e. don't clobber those settings with the current ones. ------------------------------------------------------------------------ 07afe08e46b6 | Andrew Apted | 2016-11-15 21:16:45 +1100 Undo / redo : always update the panel afterwards, fixing the bug where textures in the LineDef panel would not update. ------------------------------------------------------------------------ 00c4313ed05a | Andrew Apted | 2016-11-15 20:55:44 +1100 Defaults panel : update texture pics dynamically (as we type). ------------------------------------------------------------------------ 2381749c379c | Andrew Apted | 2016-11-15 20:50:38 +1100 Sector and LineDef panels : texture names dynamically update the picture (i.e. as we type). ------------------------------------------------------------------------ 2412ed0bc78f | Andrew Apted | 2016-11-15 20:01:35 +1100 CMD_Delete : possibly catch more unused sidedefs when deleting vertices and linedefs. ------------------------------------------------------------------------ 4d6403cc2196 | Andrew Apted | 2016-11-15 19:44:24 +1100 Removed "PruneUnused" from EDIT menu, and as a binding on 'p' key. Rationale is that unused sidedefs and sectors should be automatially pruned, since there is no way for a user to ever view or edit them. Also, the map checking functions can detect and remove unused stuff. ------------------------------------------------------------------------ f9f368bb785b | Andrew Apted | 2016-11-15 19:40:09 +1100 Began work on a UI_PicName widget, and removed the TexFromWidget() and FlatFromWidget() methods in favor of using NormalizeTex(). ------------------------------------------------------------------------ 157f1fd277db | Andrew Apted | 2016-11-15 19:37:14 +1100 Added global NormalizeTex() utility function. ------------------------------------------------------------------------ 8d9e05aa2c35 | Andrew Apted | 2016-11-14 23:30:10 +1100 Find/Replace : modified the Browser to use a sub-class of Fl_Button which does not grab the keyboard focus when clicked. That fixes an issue with detecting which input box was last active, which relies on checking which widget has the keyboard focus. ------------------------------------------------------------------------ 5f87a2df50f0 | Andrew Apted | 2016-11-14 23:11:52 +1100 minor comment fix. ------------------------------------------------------------------------ c7204abde1d7 | Andrew Apted | 2016-11-14 22:45:34 +1100 TODO : added a wishlist item. ------------------------------------------------------------------------ e85b6c998eff | Andrew Apted | 2016-11-14 22:18:39 +1100 UI_Pic widget : for GetTex() and GetFlat() methods, try an uppercase version of the texture name when the normal lookup fails. Mainly useful for when user is typing a name into an input box. ------------------------------------------------------------------------ 83f1b50ddda6 | Andrew Apted | 2016-11-14 21:41:08 +1100 The "Move/Scale/Rotate Objects" commands in the Edit menu can now be bound to keys. ------------------------------------------------------------------------ 5797ff147c27 | Andrew Apted | 2016-11-14 19:40:26 +1100 Fixed annoying problem where lines could not be split close to an end point, especially when the linedef was long. ------------------------------------------------------------------------ d9bc69202f43 | Andrew Apted | 2016-11-14 19:32:24 +1100 Canvas : for about-to-split lines, show lengths of both pieces. ------------------------------------------------------------------------ 42d189232615 | Andrew Apted | 2016-11-14 19:00:22 +1100 BSP : proper insertion point for CreateLevelLump(), CreateGLMarker(). ------------------------------------------------------------------------ 07e5ef410cb3 | Andrew Apted | 2016-11-14 18:50:42 +1100 BSP : removed some obsolete fields of nodebuildinfo_t, such as: "load_all", "no_progress", "same_filenames", "missing_output". ------------------------------------------------------------------------ a4a6f2b78579 | Andrew Apted | 2016-11-14 18:46:57 +1100 BSP : moved CheckInfo() function --> e_nodes.cc ------------------------------------------------------------------------ 2998e4a816a3 | Andrew Apted | 2016-11-14 18:40:01 +1100 BSP : added an Fl::check() after building each level. ------------------------------------------------------------------------ 24e23615aea9 | Andrew Apted | 2016-11-14 18:26:06 +1100 BSP : ensure that all necessary level lumps (NODES, BLOCKMAP, etc) are present before saving the level data, adding an empty place-holder for any that are missing. ------------------------------------------------------------------------ 803aa34bc0b0 | Andrew Apted | 2016-11-14 18:17:05 +1100 Wad code : added FindLumpInLevel_Raw() method. ------------------------------------------------------------------------ e0893b57485b | Andrew Apted | 2016-11-14 18:11:27 +1100 Wad code : fixed misleading parameter in FindLumpInLevel(). ------------------------------------------------------------------------ a6fc046a8dab | Andrew Apted | 2016-11-14 18:04:04 +1100 Wad code : implemented new RemoveGLNodes() method. ------------------------------------------------------------------------ 4624022667fe | Andrew Apted | 2016-11-14 16:53:29 +1100 TODO tweak. ------------------------------------------------------------------------ 1191834569dc | Andrew Apted | 2016-11-14 16:08:21 +1100 CHANGELOG and TODO update. ------------------------------------------------------------------------ 5528622359f4 | Andrew Apted | 2016-11-14 16:06:29 +1100 Texture loader : support TGA textures in TX_START/END. ------------------------------------------------------------------------ cdbad1d21487 | Andrew Apted | 2016-11-14 15:58:38 +1100 Texture loader : fixed bug in TGA (Targa) format detection. ------------------------------------------------------------------------ cbf7ba5f3ab6 | Andrew Apted | 2016-11-14 15:35:25 +1100 Texture loader : support PNG and JPEG textures in TX_START/END. ------------------------------------------------------------------------ f4dfeb68891b | Andrew Apted | 2016-11-14 15:20:59 +1100 BSP : removed the "bsp_wad.cc/h" code files, no longer needed. ------------------------------------------------------------------------ de7c2ff16dce | Andrew Apted | 2016-11-14 15:15:24 +1100 File / Test Map : bit more work on this feature, e.g. show the result code in the status area. ------------------------------------------------------------------------ 0f8ec8fe078d | Andrew Apted | 2016-11-13 23:58:35 +1100 TODO.txt : updated entry for Test Map command... ------------------------------------------------------------------------ b2c9c1fd98e8 | Andrew Apted | 2016-11-13 20:17:31 +1100 BSP : fixed CalcGLChecksum() to use the Lump_c methods. ------------------------------------------------------------------------ 595677ea5697 | Andrew Apted | 2016-11-13 20:05:45 +1100 BSP : updated level loading code to use lump->Length(), lump->Seek() and lump->Read() functions. ------------------------------------------------------------------------ e367ee321f20 | Andrew Apted | 2016-11-13 19:52:10 +1100 BSP : replaced AppendLevelLump() with lump->Write(), and added a FindLevelLump() utility function. ------------------------------------------------------------------------ dcd179915875 | Andrew Apted | 2016-11-13 19:50:53 +1100 Wad code : added const to Lump_c::Write "data" parameter. ------------------------------------------------------------------------ 08ff3627defe | Andrew Apted | 2016-11-13 19:18:38 +1100 BSP : worked on new CreateLevelLump() implementation, updated some code to use "Lump_c" instead of "lump_t", incorporated LIMIT_XXX values and some prototypes from bsp_wad.h, and removed "bsp_wad.h" from the files #included. Everything is QUITE BORKED now..... ------------------------------------------------------------------------ 529cbea6496b | Andrew Apted | 2016-11-13 18:36:31 +1100 BSP: more work on code to create/update the GL marker lump, using the Eureka wad API to make it and write into it. ------------------------------------------------------------------------ 082bf9b06622 | Andrew Apted | 2016-11-13 17:45:28 +1100 BSP : tidied up handling of V5 keywords for the GL marker lump. ------------------------------------------------------------------------ 02e04ad14943 | Andrew Apted | 2016-11-13 16:56:27 +1100 BSP : here is the commit which breaks everything! - moved the logic for iterating over a whole wad --> e_nodes.cc. - removed bsp_wad.o from OBJS in the Makefile. - moved the ZLibXXX functions from bsp_wad --> bsp_level. - also moved the problem marking/reporting functions. - also moved the CreateGLMarker() and AddGLTextLine() functions. - added BuildNodesForLevel() to the API, pass "lev_idx" to it. - pass "lev_idx" to the LoadLevel() and SaveLevel() functions. - replaced UtilCheckExtension() with the Eureka equivalent. ------------------------------------------------------------------------ d5ed4c6377b4 | Andrew Apted | 2016-11-13 15:15:54 +1100 Wad code : allow FindLumpInLevel() to find GL-Node lumps. ------------------------------------------------------------------------ cb306203a64f | Andrew Apted | 2016-11-13 15:07:44 +1100 Wad code : added LastLevelLump() method. ------------------------------------------------------------------------ 3edd17e13d42 | Andrew Apted | 2016-11-13 14:58:42 +1100 Wad code : added RecreateLump() method which allows an existing lump to be created from scratch, discarding the old contents. ------------------------------------------------------------------------ c63601010557 | Andrew Apted | 2016-11-13 14:47:37 +1100 BSP : minor commenting. ------------------------------------------------------------------------ 41dceb60dd54 | Andrew Apted | 2016-11-13 14:43:23 +1100 BSP : added three fields to nodebuildinfo_t: "gl_nodes", "do_blockmap" and "do_reject", which default to TRUE. When "gl_nodes" is FALSE, then GL-Nodes are not created. When "do_blockmap" or "do_reject" is FALSE, the corresponding lump is still created, but left empty (zero sized). Source ports will generally detect the empty size and handle it properly. ------------------------------------------------------------------------ 8dd8bc5b4c83 | Andrew Apted | 2016-11-13 14:18:29 +1100 BSP : *always* build the normal nodes. ------------------------------------------------------------------------ 5f03be680848 | Andrew Apted | 2016-11-13 14:03:10 +1100 BSP : allow empty lumps (VERTEXES, LINEDEFS, SECTORS etc) when loading the level. ------------------------------------------------------------------------ 1f0f639a66c9 | Andrew Apted | 2016-11-13 13:57:30 +1100 BSP : comment tweaks. ------------------------------------------------------------------------ 4843e1265f39 | Andrew Apted | 2016-11-13 13:53:33 +1100 BSP : rename "duplicate" vertices --> "overlapping" vertices. ------------------------------------------------------------------------ 4b2ad71f2255 | Andrew Apted | 2016-11-13 13:50:00 +1100 BSP : skip zero-length lines when creating wall-tips. ------------------------------------------------------------------------ 7c764524e3fd | Andrew Apted | 2016-11-13 13:49:13 +1100 BSP : skip overlapping lines when creating wall-tips. ------------------------------------------------------------------------ e034d42fbdbf | Andrew Apted | 2016-11-13 13:45:37 +1100 BSP : enable the duplicated vertex detection, mainly to help the miniseg creation logic. ------------------------------------------------------------------------ ff24f2c903e4 | Andrew Apted | 2016-11-13 13:27:18 +1100 BSP : added "force_xnod" to nodebuildinfo_t, and use this in the SaveLevel() logic to decide whether to save in ZDoom format. [ Note: real XNOD support is not there, it still does ZNOD format ] ------------------------------------------------------------------------ 707d4c41c193 | Andrew Apted | 2016-11-13 13:19:28 +1100 BSP : we only need to build V2 or V5 GL-Nodes, hence removed the logic for building V1 and V3 GL-Nodes. ------------------------------------------------------------------------ 4a7145d68140 | Andrew Apted | 2016-11-13 13:02:14 +1100 BSP : removed code for writing the LINEDEFS, SIDEDEFS and SECTORS lumps, since the policy here is to never modify those lumps. ------------------------------------------------------------------------ 9281b2a3184a | Andrew Apted | 2016-11-13 12:36:18 +1100 BSP : removed the "one-sided window trick" detection code, very much past the point of diminishing returns on that rare trick. Also removed the "skip_self_ref" feature, it is quite useless. ------------------------------------------------------------------------ a575107cc2d9 | Andrew Apted | 2016-11-13 12:25:05 +1100 BSP : a fix for commit 17b6bbc1adbc. ------------------------------------------------------------------------ cd967acd7764 | Andrew Apted | 2016-11-13 12:17:05 +1100 BSP : tweaked top-of-file comments. ------------------------------------------------------------------------ 011eec922f41 | Andrew Apted | 2016-11-13 12:07:26 +1100 BSP : removed "force_hexen" field of nodebuildinfo_t. ------------------------------------------------------------------------ 17b6bbc1adbc | Andrew Apted | 2016-11-13 12:04:09 +1100 BSP : removed the sidedef-packing feature, as it would cause the LINEDEFS lump to be modified. If we ever need this, it is something to be handled *outside* of the node builder (by Eureka instead). ------------------------------------------------------------------------ d7f564656d46 | Andrew Apted | 2016-11-13 12:01:15 +1100 BSP : added a copy of the sidedef-packing code to e_linedef.cc (disabled since it is not adapted to Eureka yet), as it may be useful or needed in the future. ------------------------------------------------------------------------ abc5a4bd0fc9 | Andrew Apted | 2016-11-13 11:50:09 +1100 Code : better parameter name for SideDefs_Unpack(). ------------------------------------------------------------------------ c8a2634f060a | Andrew Apted | 2016-11-13 00:20:28 +1100 BSP : removed "merge_vert" functionality, since that would require modifying the LINEDEFS lump. [ plus Eureka has a checker for overlapping vertices ] ------------------------------------------------------------------------ 9cd3f7dec52a | Andrew Apted | 2016-11-13 00:15:10 +1100 BSP : changed PruneVertices() to only remove unused vertices at the end of the VERTEXES lump. That means we don't need to modify the existing LINEDEFS lump. ------------------------------------------------------------------------ 53ede5835161 | Andrew Apted | 2016-11-12 23:58:30 +1100 BSP : renamed config variables "glbsp_xxx" --> "bsp_xxx". ------------------------------------------------------------------------ 51537d2e2bf3 | Andrew Apted | 2016-11-12 23:54:40 +1100 BSP : renamed "Build Nodes" in File menu --> "Build All Nodes". ------------------------------------------------------------------------ eabac55f1ab7 | Andrew Apted | 2016-11-12 23:33:11 +1100 BSP : removed code for pruning linedefs, sidedefs and sectors, as I plan to not modify the level lumps where possible (and hence not introduce any discrepancy between Eureka's in-memory idea of the map and the on-disk version). ------------------------------------------------------------------------ 2f485ff6d7d6 | Andrew Apted | 2016-11-12 23:12:56 +1100 Code tidying : use StringDup() and StringFree() in a few places which were using strdup() and free(). ------------------------------------------------------------------------ 5eaad0dc4d4d | Andrew Apted | 2016-11-12 22:44:53 +1100 BSP : removed all GWA-related code, plus the "extra_files" stuff. ------------------------------------------------------------------------ abe0f8f0544c | Andrew Apted | 2016-11-12 22:40:03 +1100 BSP : removed ParseArgs() stuff -- total not needed here. ------------------------------------------------------------------------ 0fa6fcab6e1b | Andrew Apted | 2016-11-12 22:36:27 +1100 BSP : renamed HandleLevel() --> BuildNodesForLevel(), and tweaks. ------------------------------------------------------------------------ 57e7f9d36901 | Andrew Apted | 2016-11-12 22:24:51 +1100 BSP : removed custom endian handling, use Eureka's system. ------------------------------------------------------------------------ 541a30c96f78 | Andrew Apted | 2016-11-12 20:22:08 +1100 BSP : removed CheckInfo() from the API, just do it internally as the first step in ajbsp::BuildNodes() function. ------------------------------------------------------------------------ cec583c4dc7b | Andrew Apted | 2016-11-12 20:09:15 +1100 BSP : converted nodebuildinfo_t into a class, where the constructor sets all default values, and merged nodebuildcomms_t into it too. ------------------------------------------------------------------------ 50cbd7c33ec4 | Andrew Apted | 2016-11-12 19:36:28 +1100 BSP : minor tweak, a function name in e_nodes.cc ------------------------------------------------------------------------ d2050051e03b | Andrew Apted | 2016-11-12 19:17:49 +1100 BSP : removed GlbspStrDup() and GlbspFree(), use the equivalents that Eureka already has. ------------------------------------------------------------------------ 200408692ad1 | Andrew Apted | 2016-11-12 19:13:57 +1100 BSP : renamed build result enums from GLBSP_E_xxx --> BUILD_xxx ------------------------------------------------------------------------ 71d05b29c6c8 | Andrew Apted | 2016-11-12 18:59:39 +1100 BSP : removed "nodebuildfuncs_t" structure, and call the GB_XXX functions in e_node.cc directly. ------------------------------------------------------------------------ 0aba2d16a6ed | Andrew Apted | 2016-11-11 22:05:06 +1100 BSP : removed the custom FatalError(), use the one in Eureka. ------------------------------------------------------------------------ 96ac37566109 | Andrew Apted | 2016-11-11 22:01:23 +1100 BSP : use BugError() instead of custom InternalError(). ------------------------------------------------------------------------ 5c81fce5b416 | Andrew Apted | 2016-11-11 21:57:55 +1100 BSP : replaced PrintDebug() calls with DebugPrintf(). ------------------------------------------------------------------------ 98a23b1feeec | Andrew Apted | 2016-11-11 17:15:08 +1100 BSP : improved the top-of-file comments, calling this "AJ-BSP" to distinguish from the real glBSP, changed namespace name to "ajbsp". ------------------------------------------------------------------------ 79f77d3f0546 | Andrew Apted | 2016-11-11 15:51:11 +1100 BSP : removed some out-of-date comments. ------------------------------------------------------------------------ 076112ba99c2 | Andrew Apted | 2016-11-11 15:50:20 +1100 BSP : removed whitespace at ends of lines. ------------------------------------------------------------------------ e07f2e8d9be8 | Andrew Apted | 2016-11-11 15:44:43 +1100 Preferences : simplified name of "Node Building" section. ------------------------------------------------------------------------ 1f6a37f14972 | Andrew Apted | 2016-11-11 15:28:16 +1100 BSP : changed the "BUILDER" name stored in the GL-nodes map header to be "Eureka X.XX" instead of "glBSP X.XX" -- since that reflects better how someone built the GL-nodes. ------------------------------------------------------------------------ b1aaa2e84b85 | Andrew Apted | 2016-11-11 15:19:28 +1100 BSP : updated whitespace in rest of code to use tabs. ------------------------------------------------------------------------ ee2b1b6fd6b4 | Andrew Apted | 2016-11-11 15:09:30 +1100 BSP : removed header, use SYS_ASSERT() instead. ------------------------------------------------------------------------ a8a9783b641d | Andrew Apted | 2016-11-11 15:08:17 +1100 BSP : tidied up the include guards in "bsp.h" ------------------------------------------------------------------------ a80c996f8cbe | Andrew Apted | 2016-11-11 14:42:58 +1100 BSP : added editor settings to each code file. ------------------------------------------------------------------------ 38b8f1f8b224 | Andrew Apted | 2016-11-11 14:42:30 +1100 BSP : reformatted "bsp.h" to use tabs instead of spaces. ------------------------------------------------------------------------ e8a27a027dcb | Andrew Apted | 2016-11-11 14:33:50 +1100 BSP : replaced custom "boolean_g" typedef with plain "bool", and replaced "TRUE" and "FALSE" with the normal keywords. ------------------------------------------------------------------------ 35cdde70053f | Andrew Apted | 2016-11-11 14:25:26 +1100 BSP : replaced "sint8_g", "uint32_g" typedefs with the similar ones which Eureka already has (s8_t, u32_t, etc). Also replaced "float_g" typedef with the standard "double" type. ------------------------------------------------------------------------ 19d8ef5f9a18 | Andrew Apted | 2016-11-11 14:15:27 +1100 BSP : removed duplicated macros like MIN() and ABS(). ------------------------------------------------------------------------ 936f012e801c | Andrew Apted | 2016-11-11 13:41:23 +1100 Makefile : added new "bsp_xx" files to the build, and removed the old GLBSP stuff, like references to glbsp_src/ ------------------------------------------------------------------------ 5aceafa24d11 | Andrew Apted | 2016-11-11 13:39:58 +1100 BSP : fixed #includes for the new file layout. ------------------------------------------------------------------------ 06928970f475 | Andrew Apted | 2016-11-11 13:28:57 +1100 BSP : replaced "INLINE_G" with plain "inline" keyword. ------------------------------------------------------------------------ f4b5a4475fbd | Andrew Apted | 2016-11-11 13:17:46 +1100 Began rework of glBSP code, with the goal to integrate it more tightly with Eureka, e.g. use Eureka's WAD handling code, and ultimately to support building nodes for a single map. This commit concatenates files from glbsp_src/ to produce some code files with "bsp_" prefix (bsp_node.cc etc...), and one big header file "bsp.h". ------------------------------------------------------------------------ 7ff0ec89c55f | Andrew Apted | 2016-11-11 13:00:03 +1100 Game def parser : removed "exclude_game" directive (ignored it), since it will be replaced with something better soon. ------------------------------------------------------------------------ 0d9dd50581fa | Andrew Apted | 2016-11-10 23:24:27 +1100 Game def parser : merged ParseSupportedGame() code into the calling one (handing PURPOSE_GameCheck), as it was simple and nothing else will need it. ------------------------------------------------------------------------ 85164d03fb24 | Andrew Apted | 2016-11-10 23:06:07 +1100 Game def parser : code for handling "if", "else", "endif" lines. When the "if" condition is false, we simply skip lines until the next "else" or "endif" line. A missing "endif" is detected. Still to-do is actually parsing conditions on the "if" lines, and checking whether they are true or not...... ------------------------------------------------------------------------ 08b059a7dbd3 | Andrew Apted | 2016-11-10 22:43:21 +1100 Game def parser : refactored the M_ParseDefinitionFile() code into several functions, sharing state via a struct. ------------------------------------------------------------------------ a9f5d5ce9709 | Andrew Apted | 2016-11-10 21:01:22 +1100 Game def parser : refactored tokenizing code into its own function, and tidied up the code. ------------------------------------------------------------------------ 7772a404357a | Andrew Apted | 2016-11-10 14:52:43 +1100 Canvas : show length of the current line (in draw mode). ------------------------------------------------------------------------ e52aae145131 | Andrew Apted | 2016-11-10 00:25:59 +1100 Check / things : support a "no_need_players" feature in definition files, which turns of warnings about missing players. This can be useful when editing prefabs. ------------------------------------------------------------------------ 094d6fa3fdac | Andrew Apted | 2016-11-10 00:06:58 +1100 Image code : added IM_ConvertTGAImage() function. ------------------------------------------------------------------------ 5aa22a5b3d60 | Andrew Apted | 2016-11-09 23:49:01 +1100 Fixed bug, where going into 3D mode caused the panel to stay stuck on the currently highlighted object. ------------------------------------------------------------------------ ef03db5fc55d | Andrew Apted | 2016-11-09 23:22:06 +1100 Find/Replace : clearing a selected picture box should not open the browser (or focus the input box) -- fixed. ------------------------------------------------------------------------ 7efddb423c93 | Andrew Apted | 2016-11-09 21:42:17 +1100 Find/Replace : when using "Restrict to Selection", detect early on when the selection is empty and beep with a status message. ------------------------------------------------------------------------ 129b77d18561 | Andrew Apted | 2016-11-08 20:37:48 +1100 Find/Replace : added a "Restrict to Selection" filter. When active, objects not in the current selection will be ignored (skipped). ------------------------------------------------------------------------ c7a4c5517f76 | Andrew Apted | 2016-11-08 18:45:37 +1100 Find/Replace : fixed how the picture is set, and support Things. ------------------------------------------------------------------------ 26b49748c565 | Andrew Apted | 2016-11-08 18:11:22 +1100 Find/Replace : show the texture/flat in the choose box. Also only allow appending in the Match box when the SHIFT key is pressed. ------------------------------------------------------------------------ d94fdf5f53ed | Andrew Apted | 2016-11-08 16:52:29 +1100 Find/Replace : began work to change the "Choose" buttons into a picture of the texture or thing. Apart from looking nice, this will fix the problem of pressing "Choose" and selecting something and the name is inserted into the wrong input box. ------------------------------------------------------------------------ f7e3f7682985 | Andrew Apted | 2016-11-08 16:42:43 +1100 UI Code : fixed UI_Pic::Selected(_val) to redraw if changed. ------------------------------------------------------------------------ 9126db49f6b2 | Andrew Apted | 2016-11-08 15:37:59 +1100 Ensure we never highlight objects while in the 3D preview. ------------------------------------------------------------------------ 4be3e9501fc8 | Andrew Apted | 2016-11-08 15:20:14 +1100 Source code : added "lib_tga.cc/h" code files, support for decoding TGA (Targa) image files. Ultimately this code came from Quake 2, but it has been modified a lot since then, e.g. I added support for colormapped formats. ------------------------------------------------------------------------ 170c89ec0c79 | Andrew Apted | 2016-11-08 15:08:58 +1100 glBSP library : shut up a compiler warning. ------------------------------------------------------------------------ 8cd6da0124a3 | Andrew Apted | 2016-11-08 10:20:08 +1100 Manage Project : when user adds a new game iwad (via FIND button) then make it the one currently shown. [ this was probably a regression due to recent changes ] ------------------------------------------------------------------------ faaa9692af16 | Andrew Apted | 2016-11-08 00:11:37 +1100 HEXEN config tweak. ------------------------------------------------------------------------ 8600e4e8535d | Andrew Apted | 2016-11-08 00:09:05 +1100 Improved the "New Project" command, ask for the filename *first* and then do the ProjectSetup dialog. Also tidied up how FreshLevel() and SaveLevel() were used, moving some common code into them. ------------------------------------------------------------------------ 2f9204dc8f65 | Andrew Apted | 2016-11-07 23:40:14 +1100 More refactoring... split ProjectSetup() code into two separate functions: CMD_ManageProject() and CMD_NewProject(), and merged the Project_New() code into the latter. ------------------------------------------------------------------------ d854f740f16e | Andrew Apted | 2016-11-07 23:27:37 +1100 Code tidying : refactored new MissingIWAD_Dialog() function out of the ProjectSetup() code, also factored out filename asking code. ------------------------------------------------------------------------ c3b52f873b5c | Andrew Apted | 2016-11-07 22:58:10 +1100 Renderer : code tidying, fixed the confusing "buf" and "wbuf" var names ("wbuf" was the reading one, NOT the writing one). ------------------------------------------------------------------------ f4643fda7fc2 | Andrew Apted | 2016-11-07 22:27:19 +1100 Image code : fixed gamma handling of RGB img pixels, and moved the gamma tables --> im_color.cc ------------------------------------------------------------------------ b1605163e285 | Andrew Apted | 2016-11-07 21:46:59 +1100 Renderer : fixed partial-invis effect with RGB img pixels. ------------------------------------------------------------------------ 89561e0603b6 | Andrew Apted | 2016-11-07 21:39:00 +1100 Image code : added test_make_RGB() to help test other code. ------------------------------------------------------------------------ a6cd501135dc | Andrew Apted | 2016-11-07 21:22:43 +1100 Image code : support RGB img_pixel_t in the UI_Pic widget. ------------------------------------------------------------------------ 67be95de4bf2 | Andrew Apted | 2016-11-07 21:11:33 +1100 Image code : support RGB img_pixel_t in the 3D renderer, including the lighting calculation and the partial-invis effect. ------------------------------------------------------------------------ 8b11888e745a | Andrew Apted | 2016-11-07 20:59:54 +1100 Image code : support RGB img_pixel_t in the sector renderer. ------------------------------------------------------------------------ 691eb4dea827 | Andrew Apted | 2016-11-07 20:55:03 +1100 Image code : start work to extend img_pixel_t, make it 16 bits and support both a palettized index (0-255) but also 5:5:5 RGB colors when the high bit is set. This commit includes the decode and encode macros, as well as two inline functions: IM_PixelToRGB() and IM_DecodePixel(). ------------------------------------------------------------------------ 67f1515ea2fe | Andrew Apted | 2016-11-07 20:02:16 +1100 Renderer : fixed how the screen[] array is cleared. ------------------------------------------------------------------------ 012e9aedbc60 | Andrew Apted | 2016-11-07 19:59:41 +1100 Image code : fixed Img_c::clear() to not use memset. ------------------------------------------------------------------------ 0678c2dd955e | Andrew Apted | 2016-11-07 19:57:32 +1100 Image code : fixed another use of "byte" to be "img_pixel_t". ------------------------------------------------------------------------ a0c410b9b9ce | Andrew Apted | 2016-11-07 19:56:47 +1100 STRIFE config : small fix. ------------------------------------------------------------------------ 1453a2106552 | Andrew Apted | 2016-11-07 19:51:34 +1100 Sector rendering : fixed a misuse of Img_c::wbuf(), which is for writing the image but this code is only reading them. ------------------------------------------------------------------------ f5daa25a2a9f | Andrew Apted | 2016-11-07 19:50:47 +1100 Flat loader : remap any TRANS_PIXEL pixels. ------------------------------------------------------------------------ d952757e0cd4 | Andrew Apted | 2016-11-07 19:26:45 +1100 Refactored flat loading code with separate LoadFlatImage() func. ------------------------------------------------------------------------ 4f93fe660368 | Andrew Apted | 2016-11-07 19:12:12 +1100 hdr_fltk : #include "Fl_JPEG_Image.H", just in case we need some jpeg loading support. ------------------------------------------------------------------------ 988374cff494 | Andrew Apted | 2016-11-07 18:51:55 +1100 Game defs : added new "invis" color range, used when creating the partial-invisibility effect on sprites. ------------------------------------------------------------------------ 45da40222128 | Andrew Apted | 2016-11-07 18:28:00 +1100 Image code : use "img_pixel_t" instead of "byte" in a few places. ------------------------------------------------------------------------ 9dcd0a88d88d | Andrew Apted | 2016-11-07 17:05:17 +1100 Image code : implemented conversion from a Fl_RGB_Image --> Img_c. Since it does a palette lookup for every pixel, it is very slow. ------------------------------------------------------------------------ 8a37078a3e41 | Andrew Apted | 2016-11-07 16:13:08 +1100 STRIFE config : added "l" lit flag to several things. ------------------------------------------------------------------------ 9b0fff312057 | Andrew Apted | 2016-11-07 15:43:54 +1100 Game defs : removed '&' from the names of line types. That convention was used in (and inherited from) the Unofficial DOOM Specs, and means the target sector is locked out of further changes. But for Eureka I feel it is only visual noise. ------------------------------------------------------------------------ 5fdb9aae6e36 | Andrew Apted | 2016-11-07 15:34:51 +1100 Version bump, in honor of a working STRIFE definition. ------------------------------------------------------------------------ 904f694542da | Andrew Apted | 2016-11-07 15:30:41 +1100 CHANGELOG and TODO update. ------------------------------------------------------------------------ 0d8706d22cfc | Andrew Apted | 2016-11-07 15:25:39 +1100 STRIFE config : fixed radius of players, which according to the Chocolate-Strife source code is 18 units (not 16 units like all the other games). ------------------------------------------------------------------------ 3e835410db40 | Andrew Apted | 2016-11-07 15:23:29 +1100 Game defs : added "player_size" info to most games (for DOOM games it is in common/doom_things). ------------------------------------------------------------------------ d01e33e7fd42 | Andrew Apted | 2016-11-07 15:08:10 +1100 Game def parser : new "player_size" command to specify the size of players (radius, height and view_ofs). Use this in the renderer, removing the hard-coded EYE_HEIGHT value. ------------------------------------------------------------------------ 6abc42c70317 | Andrew Apted | 2016-11-07 14:44:20 +1100 DOOM and HERETIC config : tweaked names of some specials. ------------------------------------------------------------------------ 33765e4d519a | Andrew Apted | 2016-11-07 14:42:01 +1100 STRIFE config : finished the line specials, plus a few tweaks. ------------------------------------------------------------------------ 556cc6e1f968 | Andrew Apted | 2016-11-07 14:24:38 +1100 STRIFE config : sorted out all the doors, having "Split Door" and "Keyed Door" categories in addition to normal "Door" category. ------------------------------------------------------------------------ b158b60144ba | Andrew Apted | 2016-11-07 13:29:51 +1100 STRIFE config : worked on adding the line specials (from SLADE), adapting the names to match Eureka conventions. ------------------------------------------------------------------------ 95489c7a4f2a | Andrew Apted | 2016-11-07 01:02:26 +1100 Disabled normalization of sidedefs on 1-S lines after level load. The original reason for this was to prevent showing useless crap in the "rail" and "upper" boxes in the LineDef panel. These days 1-S lines only show their lower texture, so it's no longer needed, and may intefere with special usage of those sidedef parts. ------------------------------------------------------------------------ e0a7e210f083 | Andrew Apted | 2016-11-07 00:31:22 +1100 Project Setup : when doing the missing-iwad dialog, hide the port choice, map format, and all the resource stuff, since they are distractions from the task of finding a usable iwad. ------------------------------------------------------------------------ 941d7945fea4 | Andrew Apted | 2016-11-07 00:11:53 +1100 several fixes for recent code (e.g. some string memory issues). ------------------------------------------------------------------------ 892491a0fcd0 | Andrew Apted | 2016-11-06 23:21:56 +1100 Project Setup : ensure Level_format is set *before* reloading all resources, so the UI panels can update themselves properly. ------------------------------------------------------------------------ 802366bd9ef7 | Andrew Apted | 2016-11-06 22:39:56 +1100 Project Setup dialog : changed code to store the plain "game" name instead of full iwad pathname, so the code easier to understand. ------------------------------------------------------------------------ 3bdfc841d532 | Andrew Apted | 2016-11-06 22:10:40 +1100 Project Setup : implemented logic for the map-format choice, and various tidying in related code. ------------------------------------------------------------------------ 855a6b08f1f5 | Andrew Apted | 2016-11-06 21:24:20 +1100 STRIFE config : added sector types. ------------------------------------------------------------------------ 1e46fffef76a | Andrew Apted | 2016-11-06 21:03:51 +1100 Project Setup : keep same port when changing the game (if possible), and more robust code in the PopulatePort() method. ------------------------------------------------------------------------ eb00612709d6 | Andrew Apted | 2016-11-06 20:31:03 +1100 Project Setup : default for "supported_games" should be "doom doom2" (mainly for backwards compatibility). ------------------------------------------------------------------------ bec9f9db94af | Andrew Apted | 2016-11-06 20:19:10 +1100 fixed several bugs in latest code... ------------------------------------------------------------------------ 8a0a012199ef | Andrew Apted | 2016-11-06 19:51:00 +1100 Game def parser : implemented the "variant_of" and "supported_games" keywords. ------------------------------------------------------------------------ 698a9be80210 | Andrew Apted | 2016-11-06 19:40:28 +1100 Project Setup : implemented the machinery for limiting the list of ports to show to ones supporting the selected game. ------------------------------------------------------------------------ e96a41e8e3aa | Andrew Apted | 2016-11-06 19:04:18 +1100 Project Setup : started work to have a map-format choice, and to limit the port choices to ones which support the selected game. ------------------------------------------------------------------------ c341ac965a94 | Andrew Apted | 2016-11-06 16:48:07 +1100 .gitignore ------------------------------------------------------------------------ 89c0bf9e4537 | Andrew Apted | 2016-11-06 16:46:59 +1100 TODO.txt updated ------------------------------------------------------------------------ 88e392a8f2e9 | Andrew Apted | 2016-11-06 16:34:00 +1100 Game def parser : partial work to support minimal parsing of a definition file to extract some info needed by the Manage Project dialog -- like which source ports work with the chosen game. ------------------------------------------------------------------------ 7fc523ea11f2 | Andrew Apted | 2016-11-06 16:18:52 +1100 CHANGELOG update. ------------------------------------------------------------------------ 37ba3e6e998d | Andrew Apted | 2016-11-06 15:59:44 +1100 Game def parser : only use the "common" folder when looking for an included file, and simplified the M_LoadDefinitions() code. ------------------------------------------------------------------------ d90d8c6c5902 | Andrew Apted | 2016-11-06 15:49:14 +1100 Game def parser : simplified some code, moved home_dir/install_dir checks into the FindDefinitionFile() function. ------------------------------------------------------------------------ 4800dccc0b9a | Andrew Apted | 2016-11-06 14:09:00 +1100 Makefile : re-enable debugging build (until next release....) ------------------------------------------------------------------------ ac5465fdfcd1 | Andrew Apted | 2016-11-06 14:04:35 +1100 Port defs : added "supported_games" to BOOM (and hence anything which includes boom.ugh), and also XDOOM. (This is not strictly necessary, as it matches what the defaults will be, but being explicit is generally more helpful to people). ------------------------------------------------------------------------ d5e05fb966b3 | Andrew Apted | 2016-11-06 13:58:44 +1100 STRIFE config : added remaining thing definitions (decor objects), adapted from the SLADE config files. ------------------------------------------------------------------------ 52958a840c6b | Andrew Apted | 2016-11-06 13:09:44 +1100 STRIFE config : added the monsters, rebels and civilian things, and gave all the pickup items the "n" non-blocking flag. ------------------------------------------------------------------------ d41820cc4a6e | Andrew Apted | 2016-11-06 12:23:43 +1100 Port defs : added "supported_games" line to vanilla and zdoom configs. (vanilla is a special case, as it does not represent a single source port but rather the engine which each game was shipped with). ------------------------------------------------------------------------ 866bc92b8cd3 | Andrew Apted | 2016-11-06 12:11:00 +1100 Game defs : added "variant_of" lines to various game configs. For example, TNT has "variant_of doom2" since any port which supports DOOM 2 will support TNT Evilution. ------------------------------------------------------------------------ 86646c397f68 | Andrew Apted | 2016-11-06 12:09:39 +1100 Game def parser : ignore three keywords: "variant_of", "supported_games" and "map_formats". These will be handled by different code. ------------------------------------------------------------------------ 618f84bdb326 | Andrew Apted | 2016-11-06 11:42:48 +1100 STRIFE config : added numerous thing defs: player starts, teleports, health, ammo, keys, weapons, powerups, and quest items. (This info shamelessly stolen from the SLADE editor) ------------------------------------------------------------------------ f3a6f0de70ae | Andrew Apted | 2016-11-05 23:24:27 +1100 Added "map_formats" line to HEXEN and ZDOOM config files. ------------------------------------------------------------------------ 16d50e3517ec | Andrew Apted | 2016-11-05 23:22:19 +1100 Game def parser : support a "map_formats" line for config files, taking one or more map format names ("DOOM" or "HEXEN"). ------------------------------------------------------------------------ 9f11b222e525 | Andrew Apted | 2016-11-05 22:48:03 +1100 minor code tidying. ------------------------------------------------------------------------ ac549f2f6f5d | Andrew Apted | 2016-11-05 22:40:19 +1100 Texture loader : fixed hack for loading the STRIFE texture lump. ------------------------------------------------------------------------ bd8b81208d23 | Andrew Apted | 2016-11-05 21:51:24 +1100 Games / STRIFE : renamed config file to match iwad filename. ------------------------------------------------------------------------ 7e3f0bdfd09b | Andrew Apted | 2016-11-05 21:43:02 +1100 Texture loader : support the STRIFE format of "TEXTURE1" lump. ------------------------------------------------------------------------ 3a95d924682b | Andrew Apted | 2016-11-05 21:21:01 +1100 Game defs : added config for the game STRIFE, quite empty so far. ------------------------------------------------------------------------ 6dac24e3c180 | Andrew Apted | 2016-11-05 20:21:35 +1100 Code tidying : removed "default_upper_tex" and "default_lower_tex" global vars, as they always mirrored the default wall texture. ------------------------------------------------------------------------ eae977031829 | Andrew Apted | 2016-11-05 20:19:49 +1100 Game defs : tweaked default textures of Heretic and Hexen. ------------------------------------------------------------------------ 1e7714a24431 | Andrew Apted | 2016-11-05 20:12:45 +1100 Game defs : changed default textures for DOOM maps. ------------------------------------------------------------------------ 66af446104fb | Andrew Apted | 2016-11-05 19:44:40 +1100 Ports : added "zdoom.ugh" configuration -- very empty so far. ------------------------------------------------------------------------ 1ba18909f518 | Andrew Apted | 2016-11-05 19:31:45 +1100 Ports / Eternity : enable "tx_start" feature here too. ------------------------------------------------------------------------ b04fe994915e | Andrew Apted | 2016-11-05 19:19:22 +1100 Ports / EDGE : enable the "tx_start" feature. ------------------------------------------------------------------------ f1411037d5da | Andrew Apted | 2016-11-05 19:17:26 +1100 Texture loader : require "feature tx_start" in a port config file in order to load and see the textures in TX_START/END namespace. ------------------------------------------------------------------------ a116aa2517d8 | Andrew Apted | 2016-11-05 18:12:23 +1100 Texture loader : support "patch" format textures in the TX_START/END namespace. ------------------------------------------------------------------------ 093c9b4e5dfc | Andrew Apted | 2016-11-05 17:57:36 +1100 Texture loader : properly free any images that get replaced by a later wad (e.g. a resource wad). ------------------------------------------------------------------------ 5c092ca8e03a | Andrew Apted | 2016-11-05 17:49:06 +1100 Texture loader : bit more work to load the TX_START/TX_END textures. ------------------------------------------------------------------------ 3db6ad8381a6 | Andrew Apted | 2016-11-05 17:46:46 +1100 Flat loader : properly free any flat images that get replaced (e.g. by a resource wad). ------------------------------------------------------------------------ b2602b090407 | Andrew Apted | 2016-11-05 17:31:33 +1100 In W_DetectImageFormat(), return a letter for all the formats we can detect, and let higher up code decide what to support. ------------------------------------------------------------------------ 00f847efbee4 | Andrew Apted | 2016-11-05 17:13:20 +1100 In W_DetectImageFormat(), check for some common but unsupported image formats: JPEG, GIF, BMP, and DDS. ------------------------------------------------------------------------ a8e341860972 | Andrew Apted | 2016-11-05 16:54:38 +1100 Added W_DetectImageFormat() function, detect what kind of image is used in a given wad lump. ------------------------------------------------------------------------ d1ae402290fc | Andrew Apted | 2016-11-05 13:55:21 +1100 Undo messages : simplified an overly long message. ------------------------------------------------------------------------ 69d632b2cf9f | Andrew Apted | 2016-11-05 13:49:34 +1100 Undo messages : finished the remaining operations. ------------------------------------------------------------------------ 276436e47c78 | Andrew Apted | 2016-11-05 13:18:00 +1100 Undo messages : did about half of the remaining operations. ------------------------------------------------------------------------ 150c4e2549ea | Andrew Apted | 2016-11-05 00:32:58 +1100 Wad code : detect lumps in the TX_START..TX_END namespace. ------------------------------------------------------------------------ e9a831139e44 | Andrew Apted | 2016-11-05 00:12:57 +1100 Undo messages : handle r_render.cc -- e.g. adjusting offsets. ------------------------------------------------------------------------ d60af78e67d6 | Andrew Apted | 2016-11-05 00:08:32 +1100 Undo messages : handle inserting new objects and splitting linedefs. ------------------------------------------------------------------------ 1e27900b4517 | Andrew Apted | 2016-11-05 00:04:40 +1100 Undo messages : handle the Find/Replace panel. ------------------------------------------------------------------------ c2954bbe68ea | Andrew Apted | 2016-11-04 23:48:15 +1100 Undo messages : added messages for editing done via the UI panels (Things, LineDef, Sector, Vertex). ------------------------------------------------------------------------ 6e979ce8ae2e | Andrew Apted | 2016-11-04 23:30:34 +1100 Basis : added BA_MessageForSel() utility function, used to create a message from a verb and a selection of objects. ------------------------------------------------------------------------ 7c43e11f0932 | Andrew Apted | 2016-11-04 22:39:31 +1100 Basis : have a new BA_Message() function, instead of supplying the message to the BA_End() function. Makes it easier to have utility methods for setting the message, without hiding the BA_End call. ------------------------------------------------------------------------ 07612c8c0663 | Andrew Apted | 2016-11-04 22:05:41 +1100 Began work on assigning a message to each operation, and show that message in the status area after each Undo or Redo. This commit manages the storage of the message in each undo_group_c, updates status on Undo and Redo, and gives BA_End() function an optional message argument (as per printf). ------------------------------------------------------------------------ b24d15382948 | Andrew Apted | 2016-11-04 21:35:05 +1100 Browser : changing categories clears the search box. ------------------------------------------------------------------------ f53de7cd4ec2 | Andrew Apted | 2016-11-04 21:14:04 +1100 CHANGELOG update. ------------------------------------------------------------------------ 25abee83f394 | Andrew Apted | 2016-11-04 21:11:00 +1100 LineDef panel : allow entering a negative "Length" value which causes the start vertex to be moved instead of the end vertex. ------------------------------------------------------------------------ d3dc1d46f642 | Andrew Apted | 2016-11-04 20:51:09 +1100 LineDef panel : always show an integer in the "Length" widget, making it easier to edit that value. ------------------------------------------------------------------------ 3088a0615d87 | Ioan Chera | 2016-08-09 21:01:49 +0300 Added forgotten (401) ExtraData sector linedef special. ------------------------------------------------------------------------ 59a169a2ba24 | Ioan Chera | 2016-07-19 09:21:41 +0300 Updated Xcode project ------------------------------------------------------------------------ f762a82f53ca | Andrew Apted | 2016-04-30 13:07:54 +1000 Implemented new 'File/Copy Map' command. ------------------------------------------------------------------------ 559f2ca0bfda | Andrew Apted | 2016-02-25 15:28:11 +1100 3D Preview : fixed bug not showing railings (introduced in a recent commit). ------------------------------------------------------------------------ cfa11071dc1a | Andrew Apted | 2016-02-21 12:49:34 +1100 CHANGELOG update. ------------------------------------------------------------------------ 6a3693e05aaa | Andrew Apted | 2016-02-21 12:47:13 +1100 Version bump after the release. ------------------------------------------------------------------------ cd9b86ca6959 | Andrew Apted | 2016-02-21 12:40:25 +1100 Fixed some usage of isalnum(texname[0]) to use !is_null_tex() instead, which fixes bad behavior when texture names begin with '_' or '#'. ------------------------------------------------------------------------ 417a510fcdc5 | Andrew Apted | 2016-02-21 12:35:01 +1100 Added is_null_tex() function to global scope, use it everywhere instead of directly testing the texture name. ------------------------------------------------------------------------ cb3aff590acf | Andrew Apted | 2016-02-21 12:14:09 +1100 Moved some code: LD_AddSecondSideDef() and LD_RemoveSideDef() functions from x_loop.cc --> e_linedef.cc ------------------------------------------------------------------------ f7026f24a7eb | Andrew Apted | 2016-02-21 11:35:11 +1100 LineDef panel : hide the ADD and DEL sidedef buttons. [ a preference setting for this is under consideration... ] ------------------------------------------------------------------------ 66f7d07cd165 | Andrew Apted | 2016-02-06 16:21:06 +1100 INSTALL.txt : mention 'libfontconfig-dev' as a package that may be needed. ------------------------------------------------------------------------ 2aa9ee5669b9 | Andrew Apted | 2016-02-04 21:12:10 +1100 glBSP library : do not create "truncated" blockmaps, which rarely allows the map to be playable. Instead, leave the BLOCKMAP lump as empty, to allow source ports with internal blockmap generators to generate one. ------------------------------------------------------------------------ 727b91784b4d | Andrew Apted | 2016-01-29 13:03:03 +1100 Added new CHANGES.txt file (after the 1.11 release) ------------------------------------------------------------------------ b76005aeeda2 | Andrew Apted | 2016-01-29 13:01:26 +1100 Version 1.11 was released. Hence moved CHANGELOG --> changelogs/ directory. ------------------------------------------------------------------------ 202acafa7736 | Andrew Apted | 2016-01-29 13:00:21 +1100 TODO : added a few post-release issues. ------------------------------------------------------------------------ 8bbf0550c36b | Ioan Chera | 2016-01-26 09:26:18 +0200 Updated Xcode project and info plist version. Removed "mods" from the referenced folders. ------------------------------------------------------------------------ 5760ac988954 | Andrew Apted | 2016-01-26 14:03:07 +1100 pack scripts : fixed for missing "mods" directory. ------------------------------------------------------------------------ cf09ed180c2f | Andrew Apted | 2016-01-26 13:53:37 +1100 pack scripts : updated for transition from SVN to GIT. ------------------------------------------------------------------------ 8f01beae576c | Andrew Apted | 2016-01-26 13:08:16 +1100 man page : bumped the date. ------------------------------------------------------------------------ 3b1eb152e5c1 | Andrew Apted | 2016-01-26 13:07:49 +1100 eureka.desktop : added "hexen" to the keywords. ------------------------------------------------------------------------ 552ca759b634 | Andrew Apted | 2016-01-26 11:54:14 +1100 Checks : fixed dangling vertex check to ignore lines that sit alone inside a sector (i.e. front and back are the same sector), which is a perfectly valid situation. ------------------------------------------------------------------------ 228e54af5e81 | Andrew Apted | 2016-01-26 11:43:38 +1100 Sector rendering : for unknown flats, use the cyan-ish image instead of the green one. ------------------------------------------------------------------------ b9ca1795b2b4 | Andrew Apted | 2016-01-26 10:05:10 +1100 TODO.txt : final update (I swear!) ------------------------------------------------------------------------ 275d7fe67989 | Andrew Apted | 2016-01-26 09:42:39 +1100 CHANGELOG / TODO updated. ------------------------------------------------------------------------ 4a8d41818129 | Andrew Apted | 2016-01-26 09:38:39 +1100 Added user config variable "sector_render_default". ------------------------------------------------------------------------ 579c1c154b13 | Andrew Apted | 2016-01-26 09:34:20 +1100 When creating a fresh map, add all four player starts, make them look north, and center the map around (0, 0). ------------------------------------------------------------------------ 0cca2756095b | Andrew Apted | 2016-01-25 23:56:30 +1100 Menu : added "Online Docs..." to the Help menu, which will open a web browser and load the documentation page of the website. ------------------------------------------------------------------------ e3a840784871 | Andrew Apted | 2016-01-25 22:49:07 +1100 Sector panel : MMB on the ceiling flat sets it to sky. ------------------------------------------------------------------------ 83b4206044bc | Andrew Apted | 2016-01-25 22:42:22 +1100 Fixed recent bug: RMB in the flat browser did not set ceiling tex. ------------------------------------------------------------------------ 9c17ace38d33 | Andrew Apted | 2016-01-25 18:15:24 +1100 AUTHORS.txt : minor tweakage. ------------------------------------------------------------------------ 6e6f2030f6be | Andrew Apted | 2016-01-25 18:07:39 +1100 README.txt : shortened the introduction paragraph. ------------------------------------------------------------------------ 049526ea4943 | Andrew Apted | 2016-01-25 14:05:07 +1100 TODO.txt : added a few things. ------------------------------------------------------------------------ cd4d22c9ade7 | Andrew Apted | 2016-01-25 14:02:40 +1100 docs/History.txt : changed date format of the recent GIT commits. ------------------------------------------------------------------------ 30fdd6f08241 | Andrew Apted | 2016-01-25 13:44:29 +1100 docs/History.txt : tweaked descriptive text. ------------------------------------------------------------------------ 6bee5562fcbb | Andrew Apted | 2016-01-25 12:15:29 +1100 docs/History.txt : created new section for GIT repository, and added the commits from the old SVN repository and the commits from the new GIT repository. ------------------------------------------------------------------------ fa4b5a27193e | Andrew Apted | 2016-01-24 22:31:59 +1100 README and CHANGELOG : small update. ------------------------------------------------------------------------ 283db5159c29 | Andrew Apted | 2016-01-24 22:29:09 +1100 TODO : went through and re-evaluated most items, moved several to the "NOT-TO-DO" section. ------------------------------------------------------------------------ bb89fd036ef2 | Andrew Apted | 2016-01-24 22:13:26 +1100 Editing : SHIFT + LMB in sector/linedef mode forces the opening of a selection box -- handy for places were it is otherwise impossible. ------------------------------------------------------------------------ 6f1fb5073c59 | Andrew Apted | 2016-01-24 21:44:31 +1100 Code tidying, miscellaneous stuff here and there. ------------------------------------------------------------------------ 2ef2708b2f39 | Andrew Apted | 2016-01-24 21:43:46 +1100 Browser : removed CycleCategory method from generalized line editor. ------------------------------------------------------------------------ 23fc3cf6eb24 | Andrew Apted | 2016-01-24 21:39:57 +1100 Code tidying : removed the unused exchange_object_numbers() which is legacy code that would require major surgery to get working again but has very little utility. ------------------------------------------------------------------------ df4b2b95b474 | Andrew Apted | 2016-01-24 21:30:34 +1100 Code tidying : removed some unused code in e_sector.cc ------------------------------------------------------------------------ e6214230a578 | Andrew Apted | 2016-01-24 21:03:17 +1100 Version bumped, ------------------------------------------------------------------------ bafc1cc78a17 | Andrew Apted | 2016-01-24 20:59:15 +1100 CHANGELOG : re-organized into sections like "Editing" etc. ------------------------------------------------------------------------ 595b8a63f540 | Andrew Apted | 2016-01-24 20:41:24 +1100 3D Preview : small optimisation of the texture-warp fix. ------------------------------------------------------------------------ e45cf71fb832 | Andrew Apted | 2016-01-24 19:38:31 +1100 3D Preview : fixed the texture warping issue, caused by interpolating the angles across the wall (not the correct method). ------------------------------------------------------------------------ 917fd68cb3a4 | Andrew Apted | 2016-01-24 18:15:06 +1100 TODO updated. ------------------------------------------------------------------------ 48bc72ceb2e1 | Andrew Apted | 2016-01-24 18:12:41 +1100 When scrolling via keyboard, ensure certain actions (esp. drawing mode) get updated properly. ------------------------------------------------------------------------ 502373e63c25 | Andrew Apted | 2016-01-24 17:37:43 +1100 TODO update. ------------------------------------------------------------------------ eb171c92d11c | Andrew Apted | 2016-01-24 16:28:10 +1100 LIN_Flip : 1. default behavior on 1S lines is to NOT makes lines without a right side 2. support /verts flag which only swaps the vertices 3. support /sides flag which only swaps the sidedefs ------------------------------------------------------------------------ be11e914ff48 | Andrew Apted | 2016-01-24 16:27:29 +1100 Fixed bug saving the key bindings (file handle was not closed). ------------------------------------------------------------------------ d9344de9a581 | Andrew Apted | 2016-01-24 16:22:08 +1100 Canvas sector rendering : treat lines missing a right side as broken (i.e. do not create spans even when the left side is valid). ------------------------------------------------------------------------ 4c62d990849a | Andrew Apted | 2016-01-24 15:44:18 +1100 Improved split-line detection when grid snapping -- prevent the split point from being far away from the line. ------------------------------------------------------------------------ a46432dcaa8b | Andrew Apted | 2016-01-24 14:58:32 +1100 Drawing mode : added special case for splitting a line via mouse button (and not in drawing mode) to allow the new vertex to be dragged. [ this was not possible in the normal Insert_Vertex code-path ] ------------------------------------------------------------------------ d8715a09ddfc | Andrew Apted | 2016-01-24 13:54:13 +1100 code : futher tidying in Editor_MouseRelease(). ------------------------------------------------------------------------ 12134d210757 | Andrew Apted | 2016-01-24 13:53:07 +1100 Implemented "!=" operator for the Objid class. ------------------------------------------------------------------------ ecde28798c7f | Andrew Apted | 2016-01-24 13:44:03 +1100 code : various tidying in Editor_MouseMotion(). ------------------------------------------------------------------------ ff44e9660b02 | Andrew Apted | 2016-01-24 13:35:09 +1100 code : some refactoring in Editor_MouseRelease(). ------------------------------------------------------------------------ 97b340a84f1d | Andrew Apted | 2016-01-24 13:23:16 +1100 minor code rejig in Editor_MouseRelease(). ------------------------------------------------------------------------ 6b6d6101db2e | Andrew Apted | 2016-01-24 13:09:53 +1100 Drawing mode : worked on fixing drawing mode erroneously beginning again after closing a sector via splitting a line. Still not correct, ugh... ------------------------------------------------------------------------ 7a7e8cefea7f | Andrew Apted | 2016-01-24 11:39:08 +1100 Fixed Selection_NotifyInsert() to not clear a vertex selection when a new linedef or sector is created. ------------------------------------------------------------------------ 0340593de210 | Andrew Apted | 2016-01-23 23:25:47 +1100 Added workaround in Editor_RawButton() for FLTK not sending us a button release event after another mouse button was released (i.e. when two buttons were being held down simultaneously). ------------------------------------------------------------------------ a106d2019868 | Andrew Apted | 2016-01-23 22:57:04 +1100 fix for previous commit: do not check for FL_DRAG event when calling Editor_MouseMotion, since it won't be set after scrolling via RMB. ------------------------------------------------------------------------ 701606bbb8f1 | Andrew Apted | 2016-01-23 22:49:07 +1100 Changed the way map scrolling via RMB is done, no longer an action state (ACT_XXX value) because that prevents scrolling and line drawing being used together [ a scroll would disable the current line ]. ------------------------------------------------------------------------ d1b3b2a4744e | Andrew Apted | 2016-01-23 21:12:37 +1100 For dangling vertex fixer, when merging two vertices make the final vertex selected (and nothing else). ------------------------------------------------------------------------ 025c5161c1f1 | Andrew Apted | 2016-01-23 21:01:05 +1100 Fixed the logic for fixing a dangling vertex. ------------------------------------------------------------------------ 9ad68d2fb07e | Andrew Apted | 2016-01-23 20:29:42 +1100 Insert_Vertex : added back the check preventing the creation of a zero length linedef -- it displays a "Bug detected" message as I am quite sure that it should never happen. ------------------------------------------------------------------------ f2015147a513 | Andrew Apted | 2016-01-23 20:08:29 +1100 Insert_Vertex : fixed a few cases involving a split-line. ------------------------------------------------------------------------ d96639336041 | Andrew Apted | 2016-01-22 22:49:25 +1100 CHANGELOG and TODO update. ------------------------------------------------------------------------ 770427e0583e | Andrew Apted | 2016-01-22 22:48:04 +1100 Insert_Vertex : bit more work, e.g. split-line handling. ------------------------------------------------------------------------ 0d24939ea117 | Andrew Apted | 2016-01-22 22:37:25 +1100 Insert_Vertex : tidied up the highlight handling code. ------------------------------------------------------------------------ ef8079ded2eb | Andrew Apted | 2016-01-22 22:27:57 +1100 Began some major surgery to Insert_Vertex() to better manage all the possible cases (e.g. easier_drawing_mode either ON or OFF). ------------------------------------------------------------------------ cb1ada9985dc | Andrew Apted | 2016-01-22 19:40:09 +1100 Drawing mode : when drawing a line AND grid snapping, allow the highlight and split-line to move onto the snapped position (when they would otherwise not show anything). This prevents creating a vertex which inadvertently sits on top of another vertex or sits on a line (due to the coordinate being snapped). ------------------------------------------------------------------------ 9b45589532ba | Andrew Apted | 2016-01-22 19:38:38 +1100 Canvas : draw the split-line orange ball larger when zoomed in (closer to the size of the vertices). ------------------------------------------------------------------------ 94e30ea2dfe2 | Andrew Apted | 2016-01-22 19:10:19 +1100 Code : merely moved some code around in editloop.cc ------------------------------------------------------------------------ 6309684a23b5 | Andrew Apted | 2016-01-22 19:07:15 +1100 Code : renamed GetCurobject --> GetNearObject, removed unused "snap" param. ------------------------------------------------------------------------ 7effd83d2359 | Andrew Apted | 2016-01-22 18:24:08 +1100 Added config file variable "minimum_drag_pixels". ------------------------------------------------------------------------ 1e410deea699 | Andrew Apted | 2016-01-22 18:12:57 +1100 Improved dragging: only begin dragging if cursor has moved a minimum # of pixels away from the click point. This prevents the problem where you only wanted to select a vertex, but instead you "dragged" it. ------------------------------------------------------------------------ 0cab70de706f | Andrew Apted | 2016-01-22 16:43:16 +1100 Drawing mode : allow a vertex created by spliting a line to be dragged. ------------------------------------------------------------------------ 7fd666632eb1 | Andrew Apted | 2016-01-22 15:14:42 +1100 When merging vertices, simply keep the coordinates of the first vertex (the one not delete). The previous way of computing the middle coord was not working well with grid-snapped vertices. ------------------------------------------------------------------------ 51c91df163bc | Andrew Apted | 2016-01-22 13:57:51 +1100 More work on dangling vert fixer, but the logic is still not right... ------------------------------------------------------------------------ 0f2b97fef84a | Andrew Apted | 2016-01-22 13:39:43 +1100 Implemented code to try to fix a dangling vertex -- if it sits on another vertex, merge into that one, or if it sits on a line then split the line with it. Also when using CMD_Insert on a vertex, try to fix it if dangling. ------------------------------------------------------------------------ e017b4dc494e | Andrew Apted | 2016-01-22 12:49:27 +1100 Code tidying : removed unused/obsolete DrawSnapMarker() method. ------------------------------------------------------------------------ fc5e6a76bf2a | Andrew Apted | 2016-01-22 11:49:32 +1100 Checks : fixed sector checker for Boom generalized types. ------------------------------------------------------------------------ f7eadbbeda47 | Andrew Apted | 2016-01-22 11:42:47 +1100 Added preference setting to disable the "easier line drawing" mode. ------------------------------------------------------------------------ ae42eb238506 | Andrew Apted | 2016-01-22 10:54:51 +1100 Generalized browser : changing fields will now update the line's type value. This commit marks the completion of BOOM generalized type support :) ------------------------------------------------------------------------ 768bea808584 | Andrew Apted | 2016-01-22 10:41:04 +1100 Generalized browser : allow "NONE" category to clear the line's type. ------------------------------------------------------------------------ cb81af656fcf | Andrew Apted | 2016-01-22 10:40:07 +1100 LineDef panel : change "Choose" button to "Edit" for generalized types. ------------------------------------------------------------------------ 2b58a571e419 | Andrew Apted | 2016-01-22 10:26:12 +1100 Checks : fixed unknown line-type checker to accept Boom generalized types when the current port is boom-compatible. ------------------------------------------------------------------------ c17e1a147d37 | Andrew Apted | 2016-01-20 22:05:13 +1100 CHANGELOG and TODO updated. ------------------------------------------------------------------------ 8e8f1884ba13 | Andrew Apted | 2016-01-20 21:51:20 +1100 Drawing mode : prevent LMB from adding linedefs when not in drawing mode (this was happening when splitting a linedef with LMB and another vertex was selected). ------------------------------------------------------------------------ 16edc3c8a418 | Andrew Apted | 2016-01-20 19:12:06 +1100 CMD_LastSelection : tweak invalidation logic. ------------------------------------------------------------------------ 5518ba839444 | Andrew Apted | 2016-01-20 18:45:10 +1100 TODO update. ------------------------------------------------------------------------ 2f83b1983fb5 | Andrew Apted | 2016-01-20 18:43:52 +1100 Checks / vertex : added new test for "dangling" vertices (one which are only connected to a single line). ------------------------------------------------------------------------ a38e3a4a24ba | Andrew Apted | 2016-01-20 17:18:04 +1100 .gitignore : added "_work" and various MacOS-X crud. ------------------------------------------------------------------------ 8da24b1c39ad | Andrew Apted | 2016-01-20 17:09:22 +1100 Browser : fixed recent bug causing the browser to jump to top of list when clicking on an entry (such as a texture). ------------------------------------------------------------------------ ac2bc6f8bbf6 | Andrew Apted | 2016-01-20 16:45:18 +1100 Code tidying : removed obsolete GetMaxObjectNum() function. ------------------------------------------------------------------------ ca58ba967f23 | Andrew Apted | 2016-01-20 16:43:35 +1100 CMD_LastSelection : validate the new selection (i.e. don't crash if there turns out to be a bug in the normal invalidation logic). ------------------------------------------------------------------------ cc93a8f9c43a | Andrew Apted | 2016-01-20 16:27:27 +1100 A few fixes for "LastSelection" command, which involved changing the "mode" parameter of the NewEditMode() methods from char --> obj_type_e (which is much more sensible). ------------------------------------------------------------------------ cc9db892869d | Andrew Apted | 2016-01-20 15:59:11 +1100 CMD_LastSelection : properly invalidate the last selection if an editing operation inserts or deletes objects in its range. ------------------------------------------------------------------------ d8a8633063ca | Andrew Apted | 22016-01-20 15:51:35 +1100 Info bar : give the status widget a tooltip with the same message, for cases when the message is too long to fit on-screen. ------------------------------------------------------------------------ 37fd31d0f80b | Andrew Apted | 2016-01-20 15:41:30 +1100 CMD_LastSelection : change editor mode if different than the last selection (and zoom into the selection, which helps make the mode change more obvious). ------------------------------------------------------------------------ 55c50ce52c87 | Andrew Apted | 2016-01-20 15:34:43 +1100 CMD_LastSelection : got the basic functionality working. ------------------------------------------------------------------------ f9f4f2cda77e | Andrew Apted | 2016-01-20 15:06:45 +1100 Drawing mode : fixed handling of SHIFT + LMB (continue drawing) when the line connected to an existing used vertex. ------------------------------------------------------------------------ cd3a8b697bfd | Andrew Apted | 2016-01-20 15:01:59 +1100 Replaced "edit.Selected->clear_all()" code --> Selection_Clear(). Also began work on ability to restore the last selection (when possible). ------------------------------------------------------------------------ 29320c1f53c2 | Andrew Apted | 2016-01-20 14:15:10 +1100 Selection class : implemented new "test_equal()" method, checks if two selections are the same. ------------------------------------------------------------------------ f40a855324eb | Andrew Apted | 2016-01-19 22:00:53 +1100 TODO update. ------------------------------------------------------------------------ 4ab4adfac0dc | Andrew Apted | 2016-01-19 22:00:14 +1100 CHANGELOG updated. ------------------------------------------------------------------------ ff1b2c5d2b6a | Andrew Apted | 2016-01-19 21:55:37 +1100 Generalized browser : made choice widgets a bit wider. ------------------------------------------------------------------------ b6b47b8ca0e5 | Andrew Apted | 2016-01-19 21:54:39 +1100 gen_types.ugh : expanded "HnF", "LnC" (etc) --> "Highest Floor", "Lowest Ceil" (etc). ------------------------------------------------------------------------ cc97e49d0309 | Andrew Apted | 2016-01-19 21:38:44 +1100 gen_types.ugh : improved various keywords, e.g. target names. ------------------------------------------------------------------------ c5bc0c49356a | Andrew Apted | 2016-01-19 21:25:02 +1100 Generalized browser : ability to reset all fields to default values, and fixed bug showing the wrong page. ------------------------------------------------------------------------ dbc53c8454c5 | Andrew Apted | 2016-01-19 21:00:42 +1100 Generalized browser : small improvement to previous commit. ------------------------------------------------------------------------ 833a5654cff6 | Andrew Apted | 2016-01-19 20:53:47 +1100 Generalized browser : removed the "Gen" button, too much clutter. Instead: clicking "Choose" when the type is in range will open the generalized browser, also by right clicking that button. Plus it can be opened via the menus. ------------------------------------------------------------------------ 5085fac14cc2 | Andrew Apted | 2016-01-19 20:45:45 +1100 Generalized browser : implemented decoding the line_type. ------------------------------------------------------------------------ 91680fa56b9c | Andrew Apted | 2016-01-19 20:18:41 +1100 Generalized browser : worked on UpdateGenType() for setting the page and all the field widgets to match the current linedef type. Also removed the "SET" button -- changes will take effect immediately (just like everything else in the LineDef panel). ------------------------------------------------------------------------ 040d3c6ebbdc | Andrew Apted | 2016-01-19 19:15:33 +1100 Generalized browser : tweaked layout for extra line in FLOOR/CEILING categories, and some other stuff for the Model/Monsters duality... ------------------------------------------------------------------------ f793fde39431 | Andrew Apted | 2016-01-19 18:19:20 +1100 gen_types.ugh : moved "Speed" field lower (underneath Target field), and for FLOOR and CEILING added a "Monsters" field (having same bit position as the "Model" field -- will need code to handle that properly). ------------------------------------------------------------------------ 1086a2117b04 | Andrew Apted | 2016-01-19 17:21:10 +1100 gen_types.ugh : added a default value in each "gen_field" line, and tweaked some more field names / keywords. ------------------------------------------------------------------------ ba4e660499b8 | Andrew Apted | 2016-01-19 17:05:12 +1100 gen_types.ugh : changed order so that "DOOR" is first, and capitalized various of the keywords and tweaked a few others. ------------------------------------------------------------------------ 603c1d5fcc36 | Andrew Apted | 2016-01-19 17:03:45 +1100 Generalized browser : layout tweak. ------------------------------------------------------------------------ df23936ec62b | Andrew Apted | 2016-01-19 16:41:48 +1100 Generalized browser : implemented creating the choice buttons in each page, and computing a type value, and fixed a few bugs. ------------------------------------------------------------------------ a30790a7fae3 | Andrew Apted | 2016-01-19 16:02:49 +1100 Generalized browser : changed resize behavior again, match what the other browsers do (everything follows the left edge). ------------------------------------------------------------------------ cc1f97a5491c | Andrew Apted | 2016-01-19 15:57:58 +1100 Generalized browser : minimise it whenever we change to the GEN browser (since it looks quite bad otherwise). ------------------------------------------------------------------------ 0dba3322afe3 | Andrew Apted | 2016-01-19 14:50:05 +1100 Heretic config : categorized all the flats and textures. ------------------------------------------------------------------------ b541f4c70e5c | Andrew Apted | 2016-01-19 14:13:46 +1100 Hexen config tweak. ------------------------------------------------------------------------ 6922aca68c73 | Andrew Apted | 2016-01-19 14:10:09 +1100 Hexen config : categorized all the textures and flats. ------------------------------------------------------------------------ e5c78e090cc6 | Andrew Apted | 2016-01-19 13:01:42 +1100 Browser : only populate the Category widget with non-empty categories. ------------------------------------------------------------------------ 419c132ca180 | Andrew Apted | 2016-01-18 23:08:47 +1100 TODO updated. ------------------------------------------------------------------------ 4372deb33d8e | Andrew Apted | 2016-01-18 23:03:35 +1100 Generalized browser : implemented apply_callback(). ------------------------------------------------------------------------ 95fad8495f84 | Andrew Apted | 2016-01-18 22:49:17 +1100 Generalized browser : implemented category callback which shows the corresponding page (hiding the rest), and support cycling through the categories. ------------------------------------------------------------------------ c89c229084a8 | Andrew Apted | 2016-01-18 22:20:37 +1100 Generalized browser : create the category and apply widgets, create all the pages (albeit just empty rects), and handle changes to game_info. ------------------------------------------------------------------------ 048c6e57bef6 | Andrew Apted | 2016-01-18 21:18:37 +1100 Generalized browser : fleshed out structure of UI_Generalized_Box class, added a message box to show when not in BOOM mode. ------------------------------------------------------------------------ 90bbb8850446 | Andrew Apted | 2016-01-18 20:54:44 +1100 Generalized browser : fixed resize behavior, tweaked title. ------------------------------------------------------------------------ 206d7e8464a1 | Andrew Apted | 2016-01-18 20:34:04 +1100 Generalized type : in LineDef panel, show a basic description for a gen line, currently it is the trigger + "GENERALIZED" + category name. ------------------------------------------------------------------------ e400500674fe | Andrew Apted | 2016-01-18 19:59:46 +1100 Sector panel : when user enters a large value into type box, store it directly in sectors -- the panel will show the Boom interpretation. ------------------------------------------------------------------------ 7d1b2dc12219 | Andrew Apted | 2016-01-18 19:38:09 +1100 Sector panel : use "BoomSF_XXX" constants for generalized masks. ------------------------------------------------------------------------ 60d57d7d9945 | Andrew Apted | 2016-01-18 19:25:57 +1100 Sector panel : the Boom flag widgets now show values for current sector, and reworked type_callback() to allow setting these values too. ------------------------------------------------------------------------ e96dc17a0625 | Andrew Apted | 2016-01-18 18:22:19 +1100 Sector panel : added widgets at bottom for Boom generalized sector types, and enable/disable them based on the game_info. They do not work yet... ------------------------------------------------------------------------ 282819b660af | Andrew Apted | 2016-01-18 16:04:35 +1100 Sector panel : got the headroom shortcut buttons working. ------------------------------------------------------------------------ 2b8bbdbc19cb | Andrew Apted | 2016-01-18 15:58:51 +1100 Sector panel : began work on buttons for setting headroom... ------------------------------------------------------------------------ bbceb92effdb | Andrew Apted | 2016-01-18 15:30:07 +1100 Generalized types : hide or show "Gen" button depending on game_info. ------------------------------------------------------------------------ fa5b620d1365 | Andrew Apted | 2016-01-18 15:08:24 +1100 Added a .gitignore file, ignore objects (*.o) and executables. ------------------------------------------------------------------------ cb6a39ba1ebb | Andrew Apted | 2016-01-18 15:03:41 +1100 Create obj_linux/ and obj_win32/ folders, which were lost after the conversion from SVN, and added .gitignore files in them. ------------------------------------------------------------------------ 0b46a7d4032f | Andrew Apted | 2016-01-17 13:11:33 +0000 TODO update. ------------------------------------------------------------------------ 9af1f2337766 | Andrew Apted | 2016-01-17 13:10:22 +0000 Generalized types : added "Gen" button to LineDef panel. ==================================================== DEVELOPMENT IN SVN REPOSITORY ==================================================== ------------------------------------------------------------------------ r1909 | ajapted | 2016-01-17 23:44:49 +1100 (Sun, 17 Jan 2016) | 3 lines Generalized types : in the Browser, support ACTIVE_GENERALIZED as the special value for "active" member, support 'G' in ChangeMode() method. ------------------------------------------------------------------------ r1908 | ajapted | 2016-01-17 23:20:25 +1100 (Sun, 17 Jan 2016) | 2 lines CMD_BrowserMode : support a "genline" keyword. ------------------------------------------------------------------------ r1907 | ajapted | 2016-01-17 23:18:21 +1100 (Sun, 17 Jan 2016) | 2 lines Menu : added "Generalized Line" command to Browser menu. ------------------------------------------------------------------------ r1906 | ajapted | 2016-01-17 23:13:56 +1100 (Sun, 17 Jan 2016) | 3 lines Generalized types : began work on a special browser box for displaying and editing a generalized type (via new UI_Generalized_Box class). ------------------------------------------------------------------------ r1905 | ajapted | 2016-01-17 23:00:16 +1100 (Sun, 17 Jan 2016) | 3 lines gen_types.ugh : removed the mask values, we simply compute it from the bits and shift values. ------------------------------------------------------------------------ r1904 | ajapted | 2016-01-17 21:51:04 +1100 (Sun, 17 Jan 2016) | 3 lines Replaced "Aspect ratio" preference with "Pixel aspect ratio", now just a simple number input box. The config variable was also renamed. ------------------------------------------------------------------------ r1903 | ajapted | 2016-01-17 21:07:11 +1100 (Sun, 17 Jan 2016) | 3 lines CMD_CopyProperties : implemented /reverse flag which copies from the highlighted object to the selected object(s). ------------------------------------------------------------------------ r1902 | ajapted | 2016-01-17 18:55:36 +1100 (Sun, 17 Jan 2016) | 2 lines TODO.txt updated. ------------------------------------------------------------------------ r1901 | ajapted | 2016-01-17 18:52:10 +1100 (Sun, 17 Jan 2016) | 9 lines CMD_Delete : allow sectors to be considered "unused" (and hence removed) if were are deleting linedefs (or verts) and the only linedefs remaining will not have a valid sector reference opposite them. This change was prompted by the case of removing the 3rd vertex in a triangle poking out from other geometry, which would delete the two linedefs but leave the one opposite the vertex with broken geometry (still two sided, with a sidedef facing the now defunct sector). ------------------------------------------------------------------------ r1900 | ajapted | 2016-01-17 18:36:56 +1100 (Sun, 17 Jan 2016) | 2 lines Check / vertices : ability to SHOW unused vertices. ------------------------------------------------------------------------ r1899 | ajapted | 2016-01-17 18:10:22 +1100 (Sun, 17 Jan 2016) | 2 lines CMD_Delete : remove unused sectors in vertex/linedef mode, fixed some bugs. ------------------------------------------------------------------------ r1898 | ajapted | 2016-01-17 17:54:25 +1100 (Sun, 17 Jan 2016) | 2 lines Improved the code in CMD_Delete(). ------------------------------------------------------------------------ r1897 | ajapted | 2016-01-17 16:00:12 +1100 (Sun, 17 Jan 2016) | 4 lines Improved FindClosestCrossPoint() to treat vertices as quite large, the exact size depending on the current zoom factor. This makes it easier for the user to draw a line through a vertex and have it autosplit. ------------------------------------------------------------------------ r1896 | ajapted | 2016-01-17 15:21:30 +1100 (Sun, 17 Jan 2016) | 2 lines Proper fix for previous commit (that commit was causing unclosed sectors). ------------------------------------------------------------------------ r1895 | ajapted | 2016-01-17 14:53:14 +1100 (Sun, 17 Jan 2016) | 4 lines When merging two connected linedefs (by dragging a vertex),fixed the handling when one of the lines is one-sided -- caused bad orientation of the merged line and/or missing middle texture. ------------------------------------------------------------------------ r1894 | ajapted | 2016-01-17 14:19:48 +1100 (Sun, 17 Jan 2016) | 2 lines Factored out a linedef utility function: LD_FixForLostSide() ------------------------------------------------------------------------ r1893 | ajapted | 2016-01-17 13:45:16 +1100 (Sun, 17 Jan 2016) | 3 lines Fixed creating overlapping lines when deleting 3rd vertex of a triangle (caused by merging the two linedefs connected at that vertex). ------------------------------------------------------------------------ r1892 | ajapted | 2016-01-17 00:45:42 +1100 (Sun, 17 Jan 2016) | 4 lines Added common/xlat_doom.cfg and common/xlat_hexen.cfg files. These are not used yet, but later will contain directives for converting between the two supported map formats (Doom and Hexen). ------------------------------------------------------------------------ r1891 | ajapted | 2016-01-17 00:13:51 +1100 (Sun, 17 Jan 2016) | 2 lines Browser : fixed things inserted by SPACE not appearing in RECENT category. ------------------------------------------------------------------------ r1890 | ajapted | 2016-01-17 00:03:49 +1100 (Sun, 17 Jan 2016) | 3 lines Browser : improved the RECENT category, properly sort items so that the most recent ones are near the top. ------------------------------------------------------------------------ r1889 | ajapted | 2016-01-16 21:42:55 +1100 (Sat, 16 Jan 2016) | 4 lines Browser : don't call RecentUpdate() directly from the insert() method of the recently used lists, since RecentUpdate() might be very expensive (e.g. needing to sort the whole texture list). ------------------------------------------------------------------------ r1888 | ajapted | 2016-01-16 20:53:28 +1100 (Sat, 16 Jan 2016) | 3 lines Disabled the MMB doing an "Insert" command, that functionality has been superceded by the new drawing mode. ------------------------------------------------------------------------ r1887 | ajapted | 2016-01-16 20:46:13 +1100 (Sat, 16 Jan 2016) | 2 lines Menu : added "Recent Textures" (etc) commands to the Browser menu. ------------------------------------------------------------------------ r1886 | ajapted | 2016-01-16 20:44:13 +1100 (Sat, 16 Jan 2016) | 2 lines Browser : increased size of RECENT category to 30 (was 11). ------------------------------------------------------------------------ r1885 | ajapted | 2016-01-16 18:45:53 +1100 (Sat, 16 Jan 2016) | 2 lines CHANGELOG and TODO update. ------------------------------------------------------------------------ r1884 | ajapted | 2016-01-16 18:34:21 +1100 (Sat, 16 Jan 2016) | 3 lines Disable a check for potential linedef overlaps -- not needed with the new autosplit logic. ------------------------------------------------------------------------ r1883 | ajapted | 2016-01-16 18:33:22 +1100 (Sat, 16 Jan 2016) | 2 lines FindClosestCrossPoint : finished the implementation. ------------------------------------------------------------------------ r1882 | ajapted | 2016-01-16 18:21:42 +1100 (Sat, 16 Jan 2016) | 3 lines FindClosestCrossPoint : tweak vertex check, worked on the linedef check (e.g. the intersection calculation, which seems to be working). ------------------------------------------------------------------------ r1881 | ajapted | 2016-01-16 15:52:16 +1100 (Sat, 16 Jan 2016) | 2 lines Detect vertex crossing in FindClosestCrossPoint(). ------------------------------------------------------------------------ r1880 | ajapted | 2016-01-16 14:11:33 +1100 (Sat, 16 Jan 2016) | 2 lines Began work on new FindClosestCrossPoint() function.... ------------------------------------------------------------------------ r1879 | ajapted | 2016-01-16 13:35:43 +1100 (Sat, 16 Jan 2016) | 4 lines Implemented high-level logic for Insert_LineDef_autosplit(), which will check if the new line crosses any existing lines or vertices and if so automatically create splits and multiple new linedefs (as needed). ------------------------------------------------------------------------ r1878 | ajapted | 2016-01-16 13:10:33 +1100 (Sat, 16 Jan 2016) | 5 lines Hexen : use "special" instead of "line" in the game definition file. In the code, temporarily made "special" synonymous with "line", though later they will need to be separate tables. ------------------------------------------------------------------------ r1877 | ajapted | 2016-01-16 12:16:33 +1100 (Sat, 16 Jan 2016) | 2 lines LineDef panel : made the Hexen arg boxes a bit wider. ------------------------------------------------------------------------ r1876 | ajapted | 2016-01-15 23:19:20 +1100 (Fri, 15 Jan 2016) | 2 lines Ports : include "gen_types" from the BOOM definition file. ------------------------------------------------------------------------ r1875 | ajapted | 2016-01-15 23:14:43 +1100 (Fri, 15 Jan 2016) | 3 lines Generalized types : implemented parsing of "gen_line" and "gen_field" commands (in the gen_types.ugh file). ------------------------------------------------------------------------ r1874 | ajapted | 2016-01-15 22:42:58 +1100 (Fri, 15 Jan 2016) | 3 lines Generalized types : define the structures that the parsing code will store the information into. ------------------------------------------------------------------------ r1873 | ajapted | 2016-01-15 22:25:14 +1100 (Fri, 15 Jan 2016) | 3 lines gen_types.ugh : fleshed out remaining types (LIFT, STAIR, CRUSHER) and tweaked a few other things. ------------------------------------------------------------------------ r1872 | ajapted | 2016-01-15 22:08:23 +1100 (Fri, 15 Jan 2016) | 2 lines gen_types.ugh : added fields for CEILING, DOOR and KEY DOOR. ------------------------------------------------------------------------ r1871 | ajapted | 2016-01-15 21:53:24 +1100 (Fri, 15 Jan 2016) | 3 lines Began work on 'common/gen_types.ugh' file which defines all the BOOM generalized line types. [ it will require new code too... ] ------------------------------------------------------------------------ r1870 | ajapted | 2016-01-15 20:54:59 +1100 (Fri, 15 Jan 2016) | 2 lines Find and Replace : added 'X' button to hide the panel. ------------------------------------------------------------------------ r1869 | ajapted | 2016-01-15 20:51:09 +1100 (Fri, 15 Jan 2016) | 2 lines Default Props : added an 'X' button to hide the panel. ------------------------------------------------------------------------ r1868 | ajapted | 2016-01-15 20:17:30 +1100 (Fri, 15 Jan 2016) | 2 lines TODO updated. ------------------------------------------------------------------------ r1867 | ajapted | 2016-01-15 20:16:54 +1100 (Fri, 15 Jan 2016) | 2 lines README : updated some key combos (e.g. SPACE + SHIFT) ------------------------------------------------------------------------ r1866 | ajapted | 2016-01-15 20:11:16 +1100 (Fri, 15 Jan 2016) | 3 lines Bindings : added /nofill flag to CMD-SPACE and CMD-INSERT, so that they behave the same as the hard-coded behavior of the LMB. ------------------------------------------------------------------------ r1865 | ajapted | 2016-01-15 20:08:30 +1100 (Fri, 15 Jan 2016) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1864 | ajapted | 2016-01-15 20:03:36 +1100 (Fri, 15 Jan 2016) | 3 lines Drawing mode : LMB + SHIFT now continues drawing mode (in cases where it normally stops) and LMB + CTRL now inhibits the creation of new sectors. ------------------------------------------------------------------------ r1863 | ajapted | 2016-01-15 19:54:09 +1100 (Fri, 15 Jan 2016) | 3 lines Implemented /nofill flag for CMD_Insert command, in vertex mode it prevents creating any new sectors. ------------------------------------------------------------------------ r1862 | ajapted | 2016-01-15 18:28:21 +1100 (Fri, 15 Jan 2016) | 2 lines Drawing mode : cancel drawing mode if the source vertex is deleted. ------------------------------------------------------------------------ r1861 | ajapted | 2016-01-15 17:47:22 +1100 (Fri, 15 Jan 2016) | 4 lines Drawing mode : if second vertex is on a line connected to first one, merely select them both. This allows to select numerous vertices even when drawing mode begins at first one. ------------------------------------------------------------------------ r1860 | ajapted | 2016-01-15 17:14:37 +1100 (Fri, 15 Jan 2016) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1859 | ajapted | 2016-01-15 17:11:33 +1100 (Fri, 15 Jan 2016) | 2 lines Sector panel : right click on floor/ceiling flat sets it to default. ------------------------------------------------------------------------ r1858 | ajapted | 2016-01-15 17:06:42 +1100 (Fri, 15 Jan 2016) | 3 lines LineDef panel : right-clicking on a texture sets it to the default, or "-" for the rail textures. ------------------------------------------------------------------------ r1857 | ajapted | 2016-01-15 00:57:18 +1100 (Fri, 15 Jan 2016) | 4 lines When inserting a linedef which splits a sector, ensure the line faces a consistent way (in other words, make the line's end vertex be the second one selected or created). ------------------------------------------------------------------------ r1856 | ajapted | 2016-01-13 20:31:44 +1100 (Wed, 13 Jan 2016) | 2 lines Drawing mode : exit drawing mode on the "Unselect All" command. ------------------------------------------------------------------------ r1855 | ajapted | 2016-01-13 20:11:04 +1100 (Wed, 13 Jan 2016) | 2 lines Drawing mode : fixed bug beginning to draw when edit mode != VERTEX. ------------------------------------------------------------------------ r1854 | ajapted | 2016-01-13 20:01:18 +1100 (Wed, 13 Jan 2016) | 2 lines Replaced "edit.RedrawMap = 1" with a function call: RedrawMap() ------------------------------------------------------------------------ r1853 | ajapted | 2016-01-13 19:47:58 +1100 (Wed, 13 Jan 2016) | 5 lines Drawing mode : begin drawing on mouse release after clicking on a vertex and not dragging it, and when no other vertices were selected. This is now working as a user would expect. ------------------------------------------------------------------------ r1852 | ajapted | 2016-01-13 19:01:08 +1100 (Wed, 13 Jan 2016) | 3 lines When showing a split-line, store X/Y coordinate in the editor state (instead of recomputing them in Vertex_Insert). ------------------------------------------------------------------------ r1851 | ajapted | 2016-01-13 18:35:55 +1100 (Wed, 13 Jan 2016) | 4 lines Drawing mode : don't draw a vertex when another vertex is highlighted, or when split-line is active. If another vertex is highlighted, "snap" the line onto it (since inserting will use it as the new endpoint). ------------------------------------------------------------------------ r1850 | ajapted | 2016-01-13 18:15:17 +1100 (Wed, 13 Jan 2016) | 2 lines Drawing mode : worked on making it a proper action: ACT_DRAW_LINE. ------------------------------------------------------------------------ r1849 | ajapted | 2016-01-12 21:42:11 +1100 (Tue, 12 Jan 2016) | 2 lines Sector rendering : use the dummy image for unknown flats. ------------------------------------------------------------------------ r1848 | ajapted | 2016-01-12 21:38:25 +1100 (Tue, 12 Jan 2016) | 4 lines Reworked code for creating dummy textures, they are now cached by functions in im_img.cc (IM_MissingTex etc) instead of r_render.cc, and increased the size from 32x32 --> 64x64. ------------------------------------------------------------------------ r1847 | ajapted | 2016-01-12 19:15:03 +1100 (Tue, 12 Jan 2016) | 4 lines Vertex drawing : draw a vertex too (as well as the red line) and handle grid-snapping properly. Fixed several issues when inserting (generally turning off the drawing mode). ------------------------------------------------------------------------ r1846 | ajapted | 2016-01-12 18:42:20 +1100 (Tue, 12 Jan 2016) | 4 lines Began work on a "drawing mode", after inserting a vertex we continuously draw a red line from it to where the next vertex will go, and allow a simple left click to insert the next vertex. Quite buggy atm... ------------------------------------------------------------------------ r1845 | ajapted | 2016-01-12 16:52:14 +1100 (Tue, 12 Jan 2016) | 2 lines Fixed mouse-wheel zooming around wrong spot after loading a new map. ------------------------------------------------------------------------ r1844 | ajapted | 2016-01-12 16:39:52 +1100 (Tue, 12 Jan 2016) | 2 lines Sector rendering : save/restore the state to the cache .dat file. ------------------------------------------------------------------------ r1843 | ajapted | 2016-01-12 16:30:30 +1100 (Tue, 12 Jan 2016) | 2 lines CHANGELOG updated. ------------------------------------------------------------------------ r1842 | ajapted | 2016-01-12 16:29:00 +1100 (Tue, 12 Jan 2016) | 3 lines Menu : added "Sector Rendering" choice to the View menu, implemented via new 'sector_render_mode' field in the editor_state structure. ------------------------------------------------------------------------ r1841 | ajapted | 2016-01-11 14:06:12 +1100 (Mon, 11 Jan 2016) | 7 lines ALL GAMES : reworked color definitions: * sky is now a fairly light blue * unknown_tex is as close to bright cyan as possible * unknown_flat is a fairly bright green * wall colors are grayscale * floor colors are a light brown ------------------------------------------------------------------------ r1840 | ajapted | 2016-01-11 13:44:02 +1100 (Mon, 11 Jan 2016) | 3 lines Replaced "R3D_Gamma" command with "Gamma" command so it can be used in general scope, and fixed the F11 key in the bindings.cfg file. ------------------------------------------------------------------------ r1839 | ajapted | 2016-01-11 13:33:50 +1100 (Mon, 11 Jan 2016) | 6 lines Changed TRANS_PIXEL from 247 --> 255, which is more friendly to Heretic and Hexen games. Also updated COLORMAP loader to replace any TRANS_PIXEL values, just in case some code uses it when creating an Img_c. ------------------------------------------------------------------------ r1838 | ajapted | 2016-01-11 11:33:58 +1100 (Mon, 11 Jan 2016) | 3 lines Canvas : fleshed out support for different modes in RenderSector(), e.g. solid rendering for an unknown texture using the game specific color. ------------------------------------------------------------------------ r1837 | ajapted | 2016-01-10 20:48:36 +1100 (Sun, 10 Jan 2016) | 2 lines Canvas : compute proper texture coords for rendering sector flats. ------------------------------------------------------------------------ r1836 | ajapted | 2016-01-10 20:33:47 +1100 (Sun, 10 Jan 2016) | 3 lines Canvas : rendering sector flats is working, albeit not scaled or translated properly yet.... ------------------------------------------------------------------------ r1835 | ajapted | 2016-01-10 20:20:31 +1100 (Sun, 10 Jan 2016) | 2 lines Canvas : partial work on rendering sectors with a flat texture... ------------------------------------------------------------------------ r1834 | ajapted | 2016-01-10 20:06:20 +1100 (Sun, 10 Jan 2016) | 2 lines Canvas : ability to render sectors as solid, showing their light levels. ------------------------------------------------------------------------ r1833 | ajapted | 2016-01-10 19:34:40 +1100 (Sun, 10 Jan 2016) | 3 lines Added config file variables: light_bump_small, _medium, _large. The default for non-modifier light button is 16 units (up or down). ------------------------------------------------------------------------ r1832 | ajapted | 2016-01-10 19:26:21 +1100 (Sun, 10 Jan 2016) | 2 lines Added SectorLightColor() utility function. ------------------------------------------------------------------------ r1831 | ajapted | 2016-01-10 18:40:08 +1100 (Sun, 10 Jan 2016) | 2 lines README : some updates. ------------------------------------------------------------------------ r1830 | ajapted | 2016-01-10 18:37:36 +1100 (Sun, 10 Jan 2016) | 2 lines TODO update. ------------------------------------------------------------------------ r1829 | ajapted | 2016-01-10 18:31:57 +1100 (Sun, 10 Jan 2016) | 7 lines Added workaround for loading BOOM definitions with games that are not supported by BOOM (Heretic and Hexen) -- we skip parsing the boom.ugh config file for certain games (done via new "exclude_game" directive). A better system for specifying which game + port combinations are usable is definitely needed -- something to be tackled later on. ------------------------------------------------------------------------ r1828 | ajapted | 2016-01-10 18:10:47 +1100 (Sun, 10 Jan 2016) | 2 lines Version bump and updated printf'd copyright year for 2016. ------------------------------------------------------------------------ r1827 | ajapted | 2016-01-10 18:09:32 +1100 (Sun, 10 Jan 2016) | 2 lines About window : credit Ioan Chera in the copyright lines. ------------------------------------------------------------------------ r1826 | ajapted | 2016-01-10 17:09:59 +1100 (Sun, 10 Jan 2016) | 2 lines Eternity support : added a "3D MidTex" checkbox to the LineDef panel. ------------------------------------------------------------------------ r1825 | ajapted | 2016-01-10 16:54:23 +1100 (Sun, 10 Jan 2016) | 2 lines code : removed unused GetAngleName() and GetWhenName() functions. ------------------------------------------------------------------------ r1824 | ajapted | 2016-01-10 16:51:01 +1100 (Sun, 10 Jan 2016) | 3 lines Only show the "passthru" linedef flag when the game/port supports it. Added "feature pass_through 1" to the BOOM definition file. ------------------------------------------------------------------------ r1823 | ajapted | 2016-01-10 16:39:06 +1100 (Sun, 10 Jan 2016) | 3 lines Hexen (etc) : removed UpdateMapFormatInfo() methods, use UpdateGameInfo() for map format stuff too. ------------------------------------------------------------------------ r1822 | ajapted | 2016-01-10 16:08:23 +1100 (Sun, 10 Jan 2016) | 3 lines UI : in Sector panel, moved the "Headroom" widget below the rest, with a few other tweaks to the layout. ------------------------------------------------------------------------ r1821 | ajapted | 2016-01-10 15:25:23 +1100 (Sun, 10 Jan 2016) | 3 lines UI : code tidying -- remove explicit add() calls in UI_Sector and UI_NodeDialog constructors. ------------------------------------------------------------------------ r1820 | ajapted | 2016-01-10 15:18:30 +1100 (Sun, 10 Jan 2016) | 2 lines UI : improved layout of Sector panel, more roomy. ------------------------------------------------------------------------ r1819 | ajapted | 2016-01-10 15:09:26 +1100 (Sun, 10 Jan 2016) | 2 lines UI : tweaked position of UI_Nombre in each editing panel. ------------------------------------------------------------------------ r1818 | ajapted | 2016-01-10 14:54:23 +1100 (Sun, 10 Jan 2016) | 2 lines UI : offset the first column of flags in the LineDef panel. ------------------------------------------------------------------------ r1817 | ajapted | 2016-01-10 14:49:24 +1100 (Sun, 10 Jan 2016) | 2 lines UI : tweaked layout in the LineDef panel, bit more vertical spacing. ------------------------------------------------------------------------ r1816 | ajapted | 2016-01-10 13:27:01 +1100 (Sun, 10 Jan 2016) | 2 lines Hexen : use tooltips to show what arguments of a line/thing special do. ------------------------------------------------------------------------ r1815 | ajapted | 2016-01-10 13:16:50 +1100 (Sun, 10 Jan 2016) | 3 lines Hexen : when showing args in LineDef / Thing panels, show a zero instead of a blank when the special for the line/thing actually uses that arg. ------------------------------------------------------------------------ r1814 | ajapted | 2016-01-10 12:26:49 +1100 (Sun, 10 Jan 2016) | 3 lines Inserting vertices with SHIFT always selects the new vertex. This is achieved via new "/select" flag for the Insert key command. ------------------------------------------------------------------------ r1813 | ajapted | 2016-01-10 11:02:06 +1100 (Sun, 10 Jan 2016) | 2 lines Canvas : fixed some bugs in 2D sector rendering (e.g. min_y/max_y calcs). ------------------------------------------------------------------------ r1812 | ajapted | 2016-01-10 01:10:37 +1100 (Sun, 10 Jan 2016) | 2 lines Canvas / RenderSector : fixed CMP_X to place NULLs at end of list. ------------------------------------------------------------------------ r1811 | ajapted | 2016-01-10 01:01:36 +1100 (Sun, 10 Jan 2016) | 3 lines Canvas : got solid rendering of a rectangular sector working. The next step will be to render flats.... ------------------------------------------------------------------------ r1810 | ajapted | 2016-01-10 00:52:18 +1100 (Sun, 10 Jan 2016) | 4 lines Canvas : for 2D sector rendering, compute the "side" field, added "x" field for the computed X values, and implemented finding the spans. ------------------------------------------------------------------------ r1809 | ajapted | 2016-01-10 00:30:14 +1100 (Sun, 10 Jan 2016) | 2 lines TODO.txt updated. ------------------------------------------------------------------------ r1808 | ajapted | 2016-01-10 00:25:23 +1100 (Sun, 10 Jan 2016) | 2 lines CHANGELOG : minor rearrange. ------------------------------------------------------------------------ r1807 | ajapted | 2016-01-10 00:14:01 +1100 (Sun, 10 Jan 2016) | 2 lines Canvas : more work on experimental 2D sector rendering.... ------------------------------------------------------------------------ r1806 | ajapted | 2016-01-09 21:19:26 +1100 (Sat, 09 Jan 2016) | 2 lines Hexen : fully support the special type in the Thing panel. ------------------------------------------------------------------------ r1805 | ajapted | 2016-01-09 21:04:17 +1100 (Sat, 09 Jan 2016) | 3 lines Hexen : implemented the Thing special "Choose" button, and allow a click on a browser item to set the special type. ------------------------------------------------------------------------ r1804 | ajapted | 2016-01-09 20:52:13 +1100 (Sat, 09 Jan 2016) | 2 lines Canvas : began work on experimental RenderSector() method.... ------------------------------------------------------------------------ r1803 | ajapted | 2016-01-09 20:05:36 +1100 (Sat, 09 Jan 2016) | 2 lines Hexen : support showing and editing arguments in the Thing panel. ------------------------------------------------------------------------ r1802 | ajapted | 2016-01-08 19:43:59 +1100 (Fri, 08 Jan 2016) | 6 lines Thing panel : reorganized it e.g. moved sprite above the arrow circle (closer to the Type / Desc widgets), and a few other tweaks. This was prompted by a need for all the new Hexen stuff to fit in the minimum window size (which it now does). ------------------------------------------------------------------------ r1801 | ajapted | 2016-01-08 18:45:50 +1100 (Fri, 08 Jan 2016) | 3 lines Hexen : added "Special", "Args" (etc) widgets in the Thing panel. They are not implemented yet.... ------------------------------------------------------------------------ r1800 | ajapted | 2016-01-08 18:22:52 +1100 (Fri, 08 Jan 2016) | 2 lines Hexen : implemented "dormant" flag in the Thing panel. ------------------------------------------------------------------------ r1799 | ajapted | 2016-01-08 18:11:33 +1100 (Fri, 08 Jan 2016) | 2 lines Hexen : fixed wrong "mask" values for SP/COOP/DM buttons (used by callback function). ------------------------------------------------------------------------ r1798 | ajapted | 2016-01-08 17:10:03 +1100 (Fri, 08 Jan 2016) | 2 lines Hexen : support the class flags (Fighter/Cleric/Magic) in Thing panel. ------------------------------------------------------------------------ r1797 | ajapted | 2016-01-08 16:46:35 +1100 (Fri, 08 Jan 2016) | 2 lines Hexen : support game mode flags (SP, COOP, DM) in the Things panel. ------------------------------------------------------------------------ r1796 | ajapted | 2016-01-08 16:31:15 +1100 (Fri, 08 Jan 2016) | 3 lines Check things : updated stuck-things detection to handle HEXEN flags, especially the class bits. ------------------------------------------------------------------------ r1795 | ajapted | 2016-01-08 16:24:10 +1100 (Fri, 08 Jan 2016) | 2 lines Fixed a bug recently introduced in the stuck-thing detection. ------------------------------------------------------------------------ r1794 | ajapted | 2016-01-08 16:18:24 +1100 (Fri, 08 Jan 2016) | 2 lines Added config file variable: default_gamma ------------------------------------------------------------------------ r1793 | ajapted | 2016-01-08 15:08:53 +1100 (Fri, 08 Jan 2016) | 2 lines Added config file variables: floor_bump_small, _medium, _large. ------------------------------------------------------------------------ r1792 | ajapted | 2016-01-06 14:49:05 +1100 (Wed, 06 Jan 2016) | 4 lines Makefile : the install target now deletes the old "freedoom.ugh" config, preventing it from appearing in the Manage Project dialog (along with freedoom1 and freedoom2, which is confusing). ------------------------------------------------------------------------ r1791 | ajapted | 2015-12-31 14:31:48 +1100 (Thu, 31 Dec 2015) | 3 lines CHANGELOG : brought the changelog completely up-to-date, and reorganised with most important elements at the top. ------------------------------------------------------------------------ r1790 | ajapted | 2015-12-30 12:45:23 +1100 (Wed, 30 Dec 2015) | 3 lines Hexen : in Linedef panel, support setting new Activation values via the choice button. ------------------------------------------------------------------------ r1789 | ajapted | 2015-12-30 12:35:29 +1100 (Wed, 30 Dec 2015) | 2 lines Hexen : properly update the Activation choice when selecting/hilighting lines. ------------------------------------------------------------------------ r1788 | ajapted | 2015-12-30 12:14:47 +1100 (Wed, 30 Dec 2015) | 2 lines Thing panel : moved the arrow circle (up and left) and made the buttons bigger. ------------------------------------------------------------------------ r1787 | ajapted | 2015-12-30 12:10:41 +1100 (Wed, 30 Dec 2015) | 2 lines UI : made the right panel slightly wider. ------------------------------------------------------------------------ r1786 | ajapted | 2015-12-30 12:06:21 +1100 (Wed, 30 Dec 2015) | 3 lines Hexen : in LineDef panel added a choice widget for the activation mode of the linedef -- with choices such as W1, SR, G1 (etc....) ------------------------------------------------------------------------ r1785 | ajapted | 2015-12-30 11:30:21 +1100 (Wed, 30 Dec 2015) | 3 lines Map loading : allow loading a map with no vertices, no linedefs (etc...) Also factored out some common code in linedef loaders: ValidateSidedefs() ------------------------------------------------------------------------ r1784 | ajapted | 2015-12-29 23:27:54 +1100 (Tue, 29 Dec 2015) | 2 lines Hexen : made the Linedef panel actually show the 5 arguments. ------------------------------------------------------------------------ r1783 | ajapted | 2015-12-29 23:13:56 +1100 (Tue, 29 Dec 2015) | 3 lines Hexen : in Linedef panel show the five "Args:" boxes when in Hexen mode, and implemented args_callback() which can set new values. ------------------------------------------------------------------------ r1782 | ajapted | 2015-12-29 22:51:03 +1100 (Tue, 29 Dec 2015) | 2 lines Find / Replace : support the "tag" filter for Hexen things (TID). ------------------------------------------------------------------------ r1781 | ajapted | 2015-12-29 19:43:14 +1100 (Tue, 29 Dec 2015) | 3 lines Changed DEFAULT_PORT to be "vanilla" instead of "boom", because Boom is only a DOOM engine and does not support Heretic or Hexen. ------------------------------------------------------------------------ r1780 | ajapted | 2015-12-29 19:36:23 +1100 (Tue, 29 Dec 2015) | 2 lines HEXEN conf : added four linegroups: Animated, Door, Lift, Stairs. ------------------------------------------------------------------------ r1779 | ajapted | 2015-12-29 19:20:09 +1100 (Tue, 29 Dec 2015) | 2 lines DOOM conf : minor comment fix (syntax of "line" command). ------------------------------------------------------------------------ r1778 | ajapted | 2015-12-29 19:15:57 +1100 (Tue, 29 Dec 2015) | 3 lines Browser : fixed alpha sorting of line specials for Hexen (it did not handle the lack of a S1/WR/etc action name at beginning of the description). ------------------------------------------------------------------------ r1777 | ajapted | 2015-12-29 19:05:15 +1100 (Tue, 29 Dec 2015) | 2 lines HEXEN conf : added two missing specials: 138 "Floor_Waggle" and 109 "Force_Lightning". ------------------------------------------------------------------------ r1776 | ajapted | 2015-12-29 18:58:34 +1100 (Tue, 29 Dec 2015) | 2 lines HEXEN conf : added missing line/thing special 0 ("NOTHING"). ------------------------------------------------------------------------ r1775 | ajapted | 2015-12-29 18:48:31 +1100 (Tue, 29 Dec 2015) | 2 lines Game def parser : support arg1..arg5 names in "line" commands (for Hexen). ------------------------------------------------------------------------ r1774 | ajapted | 2015-12-29 18:38:29 +1100 (Tue, 29 Dec 2015) | 2 lines HEXEN conf : finished the line/thing specials. ------------------------------------------------------------------------ r1773 | ajapted | 2015-12-29 18:20:15 +1100 (Tue, 29 Dec 2015) | 3 lines HEXEN conf : more work on line/thing specials, simplifying and/or abbreviating some names and renamed a few argument names. ------------------------------------------------------------------------ r1772 | ajapted | 2015-12-29 17:19:27 +1100 (Tue, 29 Dec 2015) | 3 lines HEXEN conf : more work on the specials, put all types into an appropriate category and renamed a few specials. ------------------------------------------------------------------------ r1771 | ajapted | 2015-12-29 17:06:36 +1100 (Tue, 29 Dec 2015) | 3 lines HEXEN config : began work to define all the line/thing specials, based on the Unofficial Hexen Specifications. ------------------------------------------------------------------------ r1770 | ajapted | 2015-12-29 14:55:02 +1100 (Tue, 29 Dec 2015) | 3 lines Use absolute paths for resource filenames in __EUREKA lump, since that is more robust (allows moving the wad to another folder). ------------------------------------------------------------------------ r1769 | ajapted | 2015-12-29 14:42:04 +1100 (Tue, 29 Dec 2015) | 8 lines Added a built-in "DOGS" sprite for when port is Boom (or compatible), as that sprite is generally not available in the IWADs and showing a missing sprite in the browser was quite ugly / distracting. This dog sprite was sourced from the OpenGameArt.org website. Authors are 'Benalene' and 'qudobup' (users on the OGA site). License is CC-BY 3.0 (Creative Commons Attribution license). ------------------------------------------------------------------------ r1768 | ajapted | 2015-12-29 14:33:02 +1100 (Tue, 29 Dec 2015) | 3 lines Image class : added IM_CreateFromText() function which can generate an Img_c from some builtin strings and palette [ not unlike XPM ]. ------------------------------------------------------------------------ r1767 | ajapted | 2015-12-29 14:04:29 +1100 (Tue, 29 Dec 2015) | 2 lines Removed RGB_INVALID constant -- not used anywhere. ------------------------------------------------------------------------ r1766 | ajapted | 2015-12-27 21:29:19 +1100 (Sun, 27 Dec 2015) | 2 lines Configs : updated comments to remove "should not exceed 24 characters" advice. ------------------------------------------------------------------------ r1765 | ajapted | 2015-12-27 21:24:32 +1100 (Sun, 27 Dec 2015) | 3 lines Hexen : define the new linedef flags (MLF_Repeatable, MLF_Activation) plus some ZDoom flags. Also define the activation values (SPAC_XXX). ------------------------------------------------------------------------ r1764 | ajapted | 2015-12-27 19:23:52 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN config : finished sector types. ------------------------------------------------------------------------ r1763 | ajapted | 2015-12-27 19:13:12 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN conf : worked on adding all the Sector specials... ------------------------------------------------------------------------ r1762 | ajapted | 2015-12-27 18:09:37 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN config : a few fixes (e.g. Cauldron sprites). ------------------------------------------------------------------------ r1761 | ajapted | 2015-12-27 18:07:25 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN config : finished improving the names of things. ------------------------------------------------------------------------ r1760 | ajapted | 2015-12-27 17:54:22 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN conf : worked on improving names of decorative things... ------------------------------------------------------------------------ r1759 | ajapted | 2015-12-27 17:17:35 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN config : split decorations by adding new "Natural" category. ------------------------------------------------------------------------ r1758 | ajapted | 2015-12-27 17:06:56 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN config : added all remaining thing types (though names need fixing...) ------------------------------------------------------------------------ r1757 | ajapted | 2015-12-27 16:49:46 +1100 (Sun, 27 Dec 2015) | 2 lines Hexen config : added thing types 10500-10503 and 8500-8509. ------------------------------------------------------------------------ r1756 | ajapted | 2015-12-27 16:41:03 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN config : added the puzzle-piece items (plus a new category for them). ------------------------------------------------------------------------ r1755 | ajapted | 2015-12-27 16:36:23 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN config : id numbers for 'Flechette' and 'Disc of Repulsion' were reversed, fixed. ------------------------------------------------------------------------ r1754 | ajapted | 2015-12-27 15:03:45 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN config : added player starts 5-8 and the soundtype markers (things 1400-1409). ------------------------------------------------------------------------ r1753 | ajapted | 2015-12-27 14:48:40 +1100 (Sun, 27 Dec 2015) | 2 lines HEXEN : added whitespace to align columns (for Things). ------------------------------------------------------------------------ r1752 | ajapted | 2015-12-27 12:09:48 +1100 (Sun, 27 Dec 2015) | 2 lines TODO : minor update ------------------------------------------------------------------------ r1751 | ajapted | 2015-12-27 12:05:35 +1100 (Sun, 27 Dec 2015) | 7 lines In game definitions support 't' flag for things like teleport destination which can safely overlap moving actors (players and monsters) but not decorative things. Reworked thing stuck checking code to handle it (and also to only check each pair of blocking things ONCE). ------------------------------------------------------------------------ r1750 | ajapted | 2015-12-20 12:42:05 +1100 (Sun, 20 Dec 2015) | 2 lines Removed top-level "ups" folder -- not used for anything. ------------------------------------------------------------------------ r1749 | ajapted | 2015-12-20 12:38:40 +1100 (Sun, 20 Dec 2015) | 2 lines TODO.txt : updated. ------------------------------------------------------------------------ r1748 | ajapted | 2015-12-20 12:35:17 +1100 (Sun, 20 Dec 2015) | 3 lines GAME definitions : removed "level_name XXX" lines, which are not used (they were simply ignored by the UGH file parser). ------------------------------------------------------------------------ r1747 | ajapted | 2015-12-19 23:48:41 +1100 (Sat, 19 Dec 2015) | 4 lines Hexen support : added "z" widget to the Thing panel (only visible when editing a hexen format map). Also apply the Z value when rendering things in the 3D preview. These changes by Ioan Chera. ------------------------------------------------------------------------ r1746 | ajapted | 2015-12-19 23:21:37 +1100 (Sat, 19 Dec 2015) | 3 lines Hexen support : added "TID" widget to the Thing panel when the current map format is Hexen (and hide it otherwise). This code by Ioan Chera. ------------------------------------------------------------------------ r1745 | ajapted | 2015-12-19 23:08:56 +1100 (Sat, 19 Dec 2015) | 4 lines Hexen support : code for reading and writing Hexen format maps, including handling the BEHAVIOR lump. This code originally by Ioan Chera (printz) with a few tweaks by me. ------------------------------------------------------------------------ r1744 | ajapted | 2015-12-19 22:13:01 +1100 (Sat, 19 Dec 2015) | 2 lines GAMES : added partial Hexen config (ugh) file -- thanks to printz. ------------------------------------------------------------------------ r1743 | ajapted | 2015-12-19 21:29:24 +1100 (Sat, 19 Dec 2015) | 6 lines Check lines : detect manual (D1,DR) doors on one-sided linedefs, with options to show or fix them (we "fix" them by clearing the special). Reason for this check is that such doors can crash vanilla DOOM. This closes ticket #16. ------------------------------------------------------------------------ r1742 | ajapted | 2015-12-19 20:58:19 +1100 (Sat, 19 Dec 2015) | 3 lines HERETIC: renamed two monsters: "Gargoyle Leader" --> "Fire Gargoyle", and "Golem Leader" --> "Nitro Golem" (more consistent with the game). ------------------------------------------------------------------------ r1741 | ajapted | 2015-11-27 12:56:56 +1100 (Fri, 27 Nov 2015) | 3 lines glBSP library : disabled the "no nodes" hack which created a dummy node and subsector -- turns out that vanilla DOOM copes with no nodes just fine. ------------------------------------------------------------------------ r1740 | ajapted | 2015-09-21 19:40:23 +1000 (Mon, 21 Sep 2015) | 9 lines Updated eureka.desktop file with: 1. %f on Exec line and a MimeType line, so can handle wad files from file-system exploring/navigation programs 2. replaced "X-DoomEditor" category with "ActionGame" 3. added Keywords line Thanks to Fabian Greffrath for the patch (ticket #17). I tweaked the set of keywords (e.g. added "heretic"). ------------------------------------------------------------------------ r1739 | ajapted | 2015-09-09 13:54:40 +1000 (Wed, 09 Sep 2015) | 4 lines Another fix for the freedoom1/freedoom2 distinction -- when loading known iwads, ignore the plain "freedoom" entry (so it won't appear as a choice in the Manage Project dialog). ------------------------------------------------------------------------ r1738 | ajapted | 2015-09-08 21:37:46 +1000 (Tue, 08 Sep 2015) | 5 lines Fixed problem when looking for 'freedoom' as an emergency IWAD to use, since there are now separate config files for Phase 1 and Phase 2, namely 'freedoom1.ugh' and 'freedoom2.ugh', hence the code should check these instead of plain 'freedoom'. ------------------------------------------------------------------------ r1737 | ajapted | 2015-09-07 22:02:51 +1000 (Mon, 07 Sep 2015) | 4 lines Ports / Eternity : added "EE:" prefix to all linetype descriptions, removed the 'x', 'w' and 'u' categories, various tweaks to the descriptions e.g. added /f and /c to designate types that use/affect a floor or ceiling. ------------------------------------------------------------------------ r1736 | ajapted | 2015-09-07 21:43:05 +1000 (Mon, 07 Sep 2015) | 3 lines Checked in definition file for the 'Eternity' source port, courtesy printz (with some editing by me). ------------------------------------------------------------------------ r1735 | ajapted | 2015-08-29 22:53:08 +1000 (Sat, 29 Aug 2015) | 2 lines Browser: increased default width by 10 pixels (show 4 columns of sprites). ------------------------------------------------------------------------ r1734 | ajapted | 2015-08-29 22:51:38 +1000 (Sat, 29 Aug 2015) | 4 lines Better handle the case when merging linedefs after dragging a vertex (check the sectors on each side and decide if need to change a sidedef on the linedef which remains, or even delete the other linedef). ------------------------------------------------------------------------ r1733 | printz | 2015-08-23 18:58:37 +1000 (Sun, 23 Aug 2015) | 3 lines Eureka for OSX is now code-signed * Also updated recommended project settings. ------------------------------------------------------------------------ r1732 | ajapted | 2015-06-13 16:43:15 +1000 (Sat, 13 Jun 2015) | 2 lines Created new CHANGES.txt after the previous release. ------------------------------------------------------------------------ r1731 | ajapted | 2015-06-13 16:40:15 +1000 (Sat, 13 Jun 2015) | 2 lines Moved CHANGES.txt --> changelogs/107.txt ------------------------------------------------------------------------ r1730 | ajapted | 2015-06-13 16:36:33 +1000 (Sat, 13 Jun 2015) | 3 lines Check / textures : implemented checking for the Medusa Effect, but only when the game or port specifies the "medusa_bug" feature. ------------------------------------------------------------------------ r1729 | ajapted | 2015-06-13 14:21:01 +1000 (Sat, 13 Jun 2015) | 2 lines Ports / vanilla : added "feature medusa_bug 1" ------------------------------------------------------------------------ r1728 | ajapted | 2015-06-13 14:20:18 +1000 (Sat, 13 Jun 2015) | 3 lines Support 'medusa_bug' feature in game definitions (mainly needed by Vanilla to indicate that it is prone to the Medusa Effect). ------------------------------------------------------------------------ r1727 | ajapted | 2015-06-13 14:14:16 +1000 (Sat, 13 Jun 2015) | 3 lines Texture loader : check for textures which potentially cause the Medusa Effect when used as a mid-masked texture on a 2S line. ------------------------------------------------------------------------ r1726 | ajapted | 2015-06-12 14:57:04 +1000 (Fri, 12 Jun 2015) | 4 lines Check / textures : implemented test for transparent textures used on solid parts of walls, including "Log" button to list them and "Fix" button to automatically set them to the default wall texture. ------------------------------------------------------------------------ r1725 | ajapted | 2015-06-12 14:34:19 +1000 (Fri, 12 Jun 2015) | 2 lines Image class : added has_transparent() method. ------------------------------------------------------------------------ r1724 | ajapted | 2015-03-03 19:47:41 +1100 (Tue, 03 Mar 2015) | 2 lines GAME DEFS : minor comment changes in freedoom2.ugh ------------------------------------------------------------------------ r1723 | ajapted | 2015-03-03 19:46:24 +1100 (Tue, 03 Mar 2015) | 4 lines GAME DEFS : better support for latest FreeDoom release: 1. renamed freedoom.ugh --> freedoom2.ugh 2. added freedoom1.ugh which simply includes "doom" ------------------------------------------------------------------------ r1722 | ajapted | 2015-02-18 18:22:05 +1100 (Wed, 18 Feb 2015) | 2 lines README.txt : removed 'F5' key description. ------------------------------------------------------------------------ r1721 | printz | 2015-02-17 18:30:38 +1100 (Tue, 17 Feb 2015) | 1 line osx: Bumped info.plist version ------------------------------------------------------------------------ r1720 | ajapted | 2015-02-16 18:24:43 +1100 (Mon, 16 Feb 2015) | 2 lines Changed default of 'render_aspect_ratio' config var --> 133. ------------------------------------------------------------------------ r1719 | ajapted | 2015-02-16 18:21:57 +1100 (Mon, 16 Feb 2015) | 2 lines Win32 package : fixed missing logo image. ------------------------------------------------------------------------ r1718 | ajapted | 2015-02-16 16:58:48 +1100 (Mon, 16 Feb 2015) | 2 lines CHANGELOG : added current revision. ------------------------------------------------------------------------ r1717 | ajapted | 2015-02-16 16:47:13 +1100 (Mon, 16 Feb 2015) | 2 lines docs/History : re-sync with SVN repository logs (ready fo release). ------------------------------------------------------------------------ r1716 | ajapted | 2015-02-16 15:41:50 +1100 (Mon, 16 Feb 2015) | 2 lines CHANGELOG and TODO updated for the release. ------------------------------------------------------------------------ r1715 | ajapted | 2015-02-16 15:41:00 +1100 (Mon, 16 Feb 2015) | 2 lines Makefile : re-enable optimisation for the upcoming release. ------------------------------------------------------------------------ r1714 | ajapted | 2015-02-16 15:31:38 +1100 (Mon, 16 Feb 2015) | 3 lines Default Props : implemented showing sprite for default thing, and clicking on it opens the Thing browser. ------------------------------------------------------------------------ r1713 | ajapted | 2015-02-16 15:06:41 +1100 (Mon, 16 Feb 2015) | 3 lines Default Properties : only show a single "wall" texture (instead of having three of them, which was rather unwieldy). ------------------------------------------------------------------------ r1712 | ajapted | 2015-02-16 12:38:52 +1100 (Mon, 16 Feb 2015) | 2 lines Makefile.xming : updated to FLTK 1.3.3 ------------------------------------------------------------------------ r1711 | ajapted | 2015-02-16 12:38:03 +1100 (Mon, 16 Feb 2015) | 2 lines FLTK tweak : add FL_DOUBLE flag to Fl::visual() call. ------------------------------------------------------------------------ r1710 | ajapted | 2015-02-16 12:35:31 +1100 (Mon, 16 Feb 2015) | 2 lines README.txt : update (c) year. ------------------------------------------------------------------------ r1709 | ajapted | 2015-02-16 00:21:28 +1100 (Mon, 16 Feb 2015) | 2 lines pack scripts : added missing "bindings.cfg" to them (Esp. the Win32 package) ------------------------------------------------------------------------ r1708 | ajapted | 2015-02-16 00:10:20 +1100 (Mon, 16 Feb 2015) | 3 lines Show error dialog when the standard "bindings.cfg" file cannot be loaded (call M_LoadBindings _after_ bumping init_progress to 3). ------------------------------------------------------------------------ r1707 | ajapted | 2015-02-15 23:14:15 +1100 (Sun, 15 Feb 2015) | 2 lines pack-win32 script : small improvements. ------------------------------------------------------------------------ r1706 | ajapted | 2015-02-15 23:10:27 +1100 (Sun, 15 Feb 2015) | 2 lines Win32 : created 'pack-win32.sh' shell script for creating a package. ------------------------------------------------------------------------ r1705 | ajapted | 2015-02-15 22:56:42 +1100 (Sun, 15 Feb 2015) | 3 lines pack-source script : rewrote it, removed "cd ..", removed "$src" variable, use "svn export" for copying directory contents. ------------------------------------------------------------------------ r1704 | ajapted | 2015-02-15 22:31:25 +1100 (Sun, 15 Feb 2015) | 7 lines Win32 : implement a fallback for $home_dir when the %APPDATA% folder cannot be determined. We also now call Determine_InstallPath() _before_ Determine_HomeDir(), needed by the above change, and I'm 99% sure that this is perfectly fine for all platforms. ------------------------------------------------------------------------ r1703 | ajapted | 2015-02-15 22:15:14 +1100 (Sun, 15 Feb 2015) | 2 lines Makefile.xming : more tidying. ------------------------------------------------------------------------ r1702 | ajapted | 2015-02-15 22:14:10 +1100 (Sun, 15 Feb 2015) | 2 lines Makefile.xming : removed obsolete NSIS stuff. ------------------------------------------------------------------------ r1701 | ajapted | 2015-02-15 22:13:05 +1100 (Sun, 15 Feb 2015) | 3 lines Win32 : as we no longer use an installer, removed code which queries the registry for the installation folder. Use GetExecutablePath() instead. ------------------------------------------------------------------------ r1700 | ajapted | 2015-02-15 22:11:05 +1100 (Sun, 15 Feb 2015) | 2 lines code tweak. ------------------------------------------------------------------------ r1699 | ajapted | 2015-02-15 22:10:04 +1100 (Sun, 15 Feb 2015) | 2 lines hdr_fltk.h : added missing #include for Fl_Menu_Button. ------------------------------------------------------------------------ r1698 | ajapted | 2015-02-15 21:36:23 +1100 (Sun, 15 Feb 2015) | 2 lines code tweak. ------------------------------------------------------------------------ r1697 | ajapted | 2015-02-15 21:28:27 +1100 (Sun, 15 Feb 2015) | 2 lines Config : tweak to description of --file option. ------------------------------------------------------------------------ r1696 | ajapted | 2015-02-15 21:20:06 +1100 (Sun, 15 Feb 2015) | 3 lines misc : removed NSIS script "eureka.nsi" -- I plan on a simpler method of packaging binaries for the Windows platform. ------------------------------------------------------------------------ r1695 | ajapted | 2015-02-15 21:17:52 +1100 (Sun, 15 Feb 2015) | 6 lines misc : removed the 'Makefile.debian' and control files in misc/debian, partly so as not to confuse that stuff with the official Debian package, but also because I plan to explore a more distribution-neutral method for packaging Linux binaries. ------------------------------------------------------------------------ r1694 | ajapted | 2015-02-15 21:10:00 +1100 (Sun, 15 Feb 2015) | 2 lines eureka.rc : updated version for next release. ------------------------------------------------------------------------ r1693 | ajapted | 2015-02-15 21:09:21 +1100 (Sun, 15 Feb 2015) | 2 lines TODO.txt tidying ------------------------------------------------------------------------ r1692 | ajapted | 2015-02-15 19:28:57 +1100 (Sun, 15 Feb 2015) | 2 lines TODO update. ------------------------------------------------------------------------ r1691 | ajapted | 2015-02-15 19:28:36 +1100 (Sun, 15 Feb 2015) | 2 lines UI_EditKey dialog : fixed wrong function name in Encode() method. ------------------------------------------------------------------------ r1690 | ajapted | 2015-02-15 18:44:17 +1100 (Sun, 15 Feb 2015) | 2 lines UI_EditKey dialog : changing the context re-populates the Function choices. ------------------------------------------------------------------------ r1689 | ajapted | 2015-02-15 18:30:38 +1100 (Sun, 15 Feb 2015) | 3 lines UI_EditKey dialog : re-populate the 'Keywords' and 'Flags' menus when the function choice has been changed. ------------------------------------------------------------------------ r1688 | ajapted | 2015-02-15 18:16:30 +1100 (Sun, 15 Feb 2015) | 2 lines UI_EditKey dialog : implemented the 'Flags...' menu. ------------------------------------------------------------------------ r1687 | ajapted | 2015-02-15 18:06:54 +1100 (Sun, 15 Feb 2015) | 2 lines UI_EditKey dialog : implemented the 'Keywords...' menu. ------------------------------------------------------------------------ r1686 | ajapted | 2015-02-15 16:59:35 +1100 (Sun, 15 Feb 2015) | 2 lines Various tidying in changelogs/*.txt ------------------------------------------------------------------------ r1685 | ajapted | 2015-02-15 16:37:02 +1100 (Sun, 15 Feb 2015) | 2 lines TODO.txt updated ------------------------------------------------------------------------ r1684 | ajapted | 2015-02-15 16:36:42 +1100 (Sun, 15 Feb 2015) | 2 lines CHANGELOG update and version bump. ------------------------------------------------------------------------ r1683 | ajapted | 2015-02-15 16:28:45 +1100 (Sun, 15 Feb 2015) | 2 lines About box : yet another tweak. ------------------------------------------------------------------------ r1682 | ajapted | 2015-02-15 16:22:00 +1100 (Sun, 15 Feb 2015) | 2 lines CMD_NewMap : backup the current pwad before saving. ------------------------------------------------------------------------ r1681 | ajapted | 2015-02-15 16:15:31 +1100 (Sun, 15 Feb 2015) | 5 lines The 'New Map' command (in File menu) now saves the fresh map into the current pwad, asking for confirmation if it already exists. Hence removed 'Replacer' global and the overwrite test in CMD_SaveMap. ------------------------------------------------------------------------ r1680 | ajapted | 2015-02-15 15:41:12 +1100 (Sun, 15 Feb 2015) | 2 lines (part of last commit) -- removed 'new_file' stuff from UI_ChooseMap. ------------------------------------------------------------------------ r1679 | ajapted | 2015-02-15 15:22:32 +1100 (Sun, 15 Feb 2015) | 2 lines UI_ChooseMap : removed the 'new_file' stuff -- obsolete now. ------------------------------------------------------------------------ r1678 | ajapted | 2015-02-15 15:03:25 +1100 (Sun, 15 Feb 2015) | 2 lines Finished implementing the 'New Project' command (in File menu). ------------------------------------------------------------------------ r1677 | ajapted | 2015-02-15 14:44:24 +1100 (Sun, 15 Feb 2015) | 3 lines More work on 'File / New Project' command, implemented the file chooser and logic to determine the initial map name. ------------------------------------------------------------------------ r1676 | ajapted | 2015-02-15 14:02:28 +1100 (Sun, 15 Feb 2015) | 4 lines Partial work on a 'File / New Project' command, which feels like a better way of handling create new files from scratch (rather than a radio button in the New Map dialog). ------------------------------------------------------------------------ r1675 | ajapted | 2015-02-15 11:41:53 +1100 (Sun, 15 Feb 2015) | 4 lines For the File / Recent and File / Given-files menus, add a number to the beginning of each entry and make it the shortcut key (e.g. pressing '4' can be used to select the fourth entry while the menu is shown). ------------------------------------------------------------------------ r1674 | ajapted | 2015-02-14 22:57:35 +1100 (Sat, 14 Feb 2015) | 3 lines About box : overlay a small version number on top of the logo (in bottom right corner), and tweaked a few things. ------------------------------------------------------------------------ r1673 | ajapted | 2015-02-14 21:16:13 +1100 (Sat, 14 Feb 2015) | 3 lines Renamed prefix for vertex commands from 'VERT_' --> 'VT_', and renamed vertex reshaping commands to 'VT_ShapeArc' and 'VT_ShapeLine'. ------------------------------------------------------------------------ r1672 | ajapted | 2015-02-14 21:01:42 +1100 (Sat, 14 Feb 2015) | 3 lines Key bind dialog : fixed wrong context strings (seems to have gotten out of sync with the KCTX_xxx values). ------------------------------------------------------------------------ r1671 | ajapted | 2015-02-14 20:31:49 +1100 (Sat, 14 Feb 2015) | 2 lines README.txt : minor updates. ------------------------------------------------------------------------ r1670 | ajapted | 2015-02-14 19:11:37 +1100 (Sat, 14 Feb 2015) | 4 lines Fixed the key binding list so that pressing 'Bind', 'Copy' etc on a non-visible line will scroll to that line (make it visible). ------------------------------------------------------------------------ r1669 | ajapted | 2015-02-14 16:49:06 +1100 (Sat, 14 Feb 2015) | 2 lines Reworked SEC_SelectGroup command to use the new flag system. ------------------------------------------------------------------------ r1668 | ajapted | 2015-02-14 16:07:01 +1100 (Sat, 14 Feb 2015) | 2 lines Updated LIN_SelectPath command to use new flag system. ------------------------------------------------------------------------ r1667 | ajapted | 2015-02-14 15:43:31 +1100 (Sat, 14 Feb 2015) | 3 lines Fixed damn silly bug in ExecuteKey() not storing flag parameters, which begin with a slash '/', into the EXEC_Flags[] array. ------------------------------------------------------------------------ r1666 | ajapted | 2015-02-14 15:17:42 +1100 (Sat, 14 Feb 2015) | 3 lines For "Delete" command support two flags: /keep_unused and /keep_things (the latter only useful in sectors mode). ------------------------------------------------------------------------ r1665 | ajapted | 2015-02-14 14:50:13 +1100 (Sat, 14 Feb 2015) | 3 lines 1. updated CMD_Rotate90 to take a keyword ("cw" for clockwise, "acw" for anti-clockwise) 2. split VERT_Reshape into two commands : VERT_ReshapeLine and VERT_ReshapeArc ------------------------------------------------------------------------ r1664 | ajapted | 2015-02-13 22:11:54 +1100 (Fri, 13 Feb 2015) | 3 lines Added 'flag_list' and 'keyword_list' to every editor_command_t that needs them. [ Note that most commands do not support their flags yet.... ] ------------------------------------------------------------------------ r1663 | ajapted | 2015-02-13 19:59:42 +1100 (Fri, 13 Feb 2015) | 4 lines Reworked LineDef_Align() function to take 'flags' as a integer bitmask instead of a string. Updated the 3D_Align implementation for this, and to use the new Exec_HasFlag() mechanism to check for "/clear" and "/right". ------------------------------------------------------------------------ r1662 | ajapted | 2015-02-13 19:39:23 +1100 (Fri, 13 Feb 2015) | 4 lines Added EXEC_Flags[] global which is similar to EXEC_Param[] but stores "flags" (paremeters beginning with '/'). Implemented adding such flags into that array (from a key binding), and added Exec_HasFlag() utility function. ------------------------------------------------------------------------ r1661 | ajapted | 2015-02-13 16:50:31 +1100 (Fri, 13 Feb 2015) | 2 lines TODO update. ------------------------------------------------------------------------ r1660 | ajapted | 2015-02-13 16:42:23 +1100 (Fri, 13 Feb 2015) | 5 lines Added 'flag_list' and 'keyword_list' fields to editor_command_t. Use these in the UI_EditKey dialog to populate a 'Keywords' and/or 'Flags' menus. These menus don't actually do anything yet.... ------------------------------------------------------------------------ r1659 | ajapted | 2015-02-13 13:51:28 +1100 (Fri, 13 Feb 2015) | 4 lines Began work on some improvements to key binding system. This commit works on the UI_EditKey dialog, the 'Function' widget is now a choice menu that contains all the possible functions for the current context. ------------------------------------------------------------------------ r1658 | ajapted | 2015-02-10 15:35:17 +1100 (Tue, 10 Feb 2015) | 4 lines Fixed crash when trying to build nodes (via File menu) on an IWAD map which has had some changes made to it, but has not been saved yet (and hence 'edit_wad' was NULL). ------------------------------------------------------------------------ r1657 | ajapted | 2015-02-10 15:15:44 +1100 (Tue, 10 Feb 2015) | 2 lines TODO update. ------------------------------------------------------------------------ r1656 | ajapted | 2015-02-10 15:14:59 +1100 (Tue, 10 Feb 2015) | 3 lines Key bindings : changed vertex reshapers 'C' to be 120 degrees and 'Q' to 240 degrees -- I think these will be more useful than 90/270 in practice. ------------------------------------------------------------------------ r1655 | ajapted | 2015-02-10 15:13:17 +1100 (Tue, 10 Feb 2015) | 2 lines Version bump, in honor of Find/Replace feature fully implemented. ------------------------------------------------------------------------ r1654 | ajapted | 2015-02-10 15:07:37 +1100 (Tue, 10 Feb 2015) | 3 lines Find/Replace : added 'skies' checkbox to the Sector filters. This can be used to prevent matches from affecting sky ceilings. ------------------------------------------------------------------------ r1653 | ajapted | 2015-02-10 14:52:20 +1100 (Tue, 10 Feb 2015) | 3 lines Find/Replace : prevent matching the empty rail texture ('-') against a "*" wildcard pattern -- especially pertinent when doing a Replace All operation. ------------------------------------------------------------------------ r1652 | ajapted | 2015-02-10 13:22:11 +1100 (Tue, 10 Feb 2015) | 2 lines Find/Replace : fixed the filter toggle button being out-of-sync. ------------------------------------------------------------------------ r1651 | ajapted | 2015-02-10 13:15:58 +1100 (Tue, 10 Feb 2015) | 3 lines Find/Replace : only clear everything when the type changes (i.e. keep the existing match text, filters, etc... while edit mode stays the same). ------------------------------------------------------------------------ r1650 | ajapted | 2015-02-10 13:00:58 +1100 (Tue, 10 Feb 2015) | 2 lines Find/Replace : code to reset the filters section. ------------------------------------------------------------------------ r1649 | ajapted | 2015-02-09 22:22:33 +1100 (Mon, 09 Feb 2015) | 2 lines Find/Replace : implemented replacement for LineDef textures. ------------------------------------------------------------------------ r1648 | ajapted | 2015-02-09 22:11:55 +1100 (Mon, 09 Feb 2015) | 8 lines Find/Replace : decided to remove handling of negative matches ('!' prefix) for textures and flats -- primarily because the semantics of find is quite different for semantics of replace (with find, user wants to see all sectors where BOTH flats match the negative pattern, but with replace user wants to visit sectors where EITHER flat match the negative pattern). Hence opting for K.I.S.S. ------------------------------------------------------------------------ r1647 | ajapted | 2015-02-09 21:48:58 +1100 (Mon, 09 Feb 2015) | 4 lines Invert selection command : do not clear the selection when 'error_mode' is active -- firstly because it all we get is the same as Select All command, and using CTRL-I (twice) to keep the error selection can be useful. ------------------------------------------------------------------------ r1646 | ajapted | 2015-02-09 21:32:37 +1100 (Mon, 09 Feb 2015) | 2 lines Find/Replace : implemented replacement for sector flats. ------------------------------------------------------------------------ r1645 | ajapted | 2015-02-09 21:30:23 +1100 (Mon, 09 Feb 2015) | 3 lines UI : made TexFromWidget() and FlatFromWidget() be static functions since they do not use or require any fields or methods of their class. ------------------------------------------------------------------------ r1644 | ajapted | 2015-02-09 20:54:06 +1100 (Mon, 09 Feb 2015) | 4 lines Find/Replace : Allow user to dismiss the Find/Replace panel without losing the current selection (it was being cleared because it now uses the error mode). ------------------------------------------------------------------------ r1643 | ajapted | 2015-02-09 20:18:48 +1100 (Mon, 09 Feb 2015) | 3 lines Find/Replace : implemented Match_LineDef(), logic for matching textures on the sidedefs. ------------------------------------------------------------------------ r1642 | ajapted | 2015-02-09 19:35:46 +1100 (Mon, 09 Feb 2015) | 4 lines Find/Replace : allow '/' and '|' as separators for textures (consistent with numeric searches), and when adding a texture from the browser add a comma separator if current match ends with '*'. ------------------------------------------------------------------------ r1641 | ajapted | 2015-02-09 19:19:22 +1100 (Mon, 09 Feb 2015) | 6 lines Find/Replace : implemented Pattern_Match() method for matching texture names, supporting a list of names (simple patterns) separated by commas. Use this to implement Match_Sector() logic, and support initial '!' character in the pattern to negate the results. ------------------------------------------------------------------------ r1640 | ajapted | 2015-02-09 18:25:34 +1100 (Mon, 09 Feb 2015) | 6 lines Factored out code to match texture names (etc) --> Texture_MatchPattern(), now in the objects.cc/h file. Also fixed bug in browser where patterns like '4$' would not match some flats or textures, like 'CEIL3_4', due to spaces (padding) on the end. ------------------------------------------------------------------------ r1639 | ajapted | 2015-02-09 17:09:22 +1100 (Mon, 09 Feb 2015) | 2 lines TODO update. ------------------------------------------------------------------------ r1638 | ajapted | 2015-02-09 17:02:57 +1100 (Mon, 09 Feb 2015) | 4 lines Vertex Reshaping : finished logic for arbitrary arc angles, updating the key bindings for O/C/D/Q to specify the angle directly. Document new 'Q' binding (270 degrees) in the README. ------------------------------------------------------------------------ r1637 | ajapted | 2015-02-09 16:43:05 +1100 (Mon, 09 Feb 2015) | 3 lines Vertex Reshaping : worked to support arbitrary arc sizes (angles), and to keep the start and end vertices of the arc in the same location.... ------------------------------------------------------------------------ r1636 | ajapted | 2015-02-09 15:55:17 +1100 (Mon, 09 Feb 2015) | 2 lines sys_macro.h : #define M_SQRT2 if not already defined. ------------------------------------------------------------------------ r1635 | ajapted | 2015-02-09 15:19:40 +1100 (Mon, 09 Feb 2015) | 2 lines Fixed not reloading textures (etc) when opening a new wad file. ------------------------------------------------------------------------ r1634 | ajapted | 2015-02-09 14:37:11 +1100 (Mon, 09 Feb 2015) | 2 lines TODO.txt : update and tidy up. ------------------------------------------------------------------------ r1633 | ajapted | 2015-02-09 14:33:55 +1100 (Mon, 09 Feb 2015) | 5 lines When loading a wad specified on the command line, and it contains settings for the iwad, port and/or resources in an EUREKA_LUMP, then allow command line arguments to override those values (and _add_ new resources). ------------------------------------------------------------------------ r1632 | ajapted | 2015-02-09 13:01:55 +1100 (Mon, 09 Feb 2015) | 4 lines Makefile.xming : link with -static-libgcc and -static-libstdc++ so that the Windows executable actually works on Windows (and not complain about a missing DLL). ------------------------------------------------------------------------ r1631 | ajapted | 2015-01-24 16:29:41 +1100 (Sat, 24 Jan 2015) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1630 | ajapted | 2015-01-24 16:28:30 +1100 (Sat, 24 Jan 2015) | 3 lines Config : added 'show_full_one_sided' config variable, enables showing the rail / upper textures for one-sided lines in the LineDef panel. ------------------------------------------------------------------------ r1629 | ajapted | 2015-01-24 15:45:39 +1100 (Sat, 24 Jan 2015) | 3 lines Linedef panel : for one-sided lines, don't show upper and rail texture (since editing them generally does nothing). ------------------------------------------------------------------------ r1628 | ajapted | 2015-01-24 15:15:15 +1100 (Sat, 24 Jan 2015) | 3 lines Canvas : tweak to error mode, when active don't highlight the tagged sector(s) of the currently highlighted linedef. ------------------------------------------------------------------------ r1627 | ajapted | 2015-01-24 15:11:43 +1100 (Sat, 24 Jan 2015) | 3 lines Canvas : in the error mode, draw most linedefs as LIGHTGREY so the selected objects stand out more. ------------------------------------------------------------------------ r1626 | ajapted | 2015-01-24 14:57:17 +1100 (Sat, 24 Jan 2015) | 2 lines Linedef checker : implemented detection of unknown line types. ------------------------------------------------------------------------ r1625 | ajapted | 2015-01-24 14:18:05 +1100 (Sat, 24 Jan 2015) | 3 lines Sector checker : detect unknown sector types. They are shown in red since in vanilla DOOM they will cause a fatal error. ------------------------------------------------------------------------ r1624 | printz | 2015-01-19 18:43:48 +1100 (Mon, 19 Jan 2015) | 1 line osx: updated Xcode project ------------------------------------------------------------------------ r1623 | ajapted | 2015-01-18 22:40:46 +1100 (Sun, 18 Jan 2015) | 6 lines Game definitions : 1. fixed category of linetype #68 (should be a raising floor) 2. changed category letter of raising floors to 'g', so they appear near the lowering floors in the Browser. ------------------------------------------------------------------------ r1622 | ajapted | 2015-01-17 22:10:09 +1100 (Sat, 17 Jan 2015) | 3 lines Find/Replace : make 'Select All' button use the error mode, i.e. show all matches in bright red and everything else in a rather dim gray. ------------------------------------------------------------------------ r1621 | ajapted | 2015-01-17 21:30:21 +1100 (Sat, 17 Jan 2015) | 2 lines tweak the --help text ------------------------------------------------------------------------ r1620 | ajapted | 2015-01-17 21:29:41 +1100 (Sat, 17 Jan 2015) | 2 lines Man page : bit more fleshing out + lots of polishing. ------------------------------------------------------------------------ r1619 | ajapted | 2015-01-17 17:30:54 +1100 (Sat, 17 Jan 2015) | 2 lines Man page : fixed long options to have two dashes, plus some tweaks. ------------------------------------------------------------------------ r1618 | ajapted | 2015-01-17 17:26:21 +1100 (Sat, 17 Jan 2015) | 2 lines Man page : finished describing the remaining options. ------------------------------------------------------------------------ r1617 | ajapted | 2015-01-17 16:14:03 +1100 (Sat, 17 Jan 2015) | 3 lines Browser : tidied up some code with 'sort_method_e' typedef (instead of using 0/1/2 with special meanings). ------------------------------------------------------------------------ r1616 | ajapted | 2015-01-17 15:56:21 +1100 (Sat, 17 Jan 2015) | 4 lines Menus : the 'Default Properties' command did not belong in FILE menu, so moved it into the VIEW menu (the EDIT menu might make more sense, but is rather full right now). ------------------------------------------------------------------------ r1615 | ajapted | 2015-01-16 22:19:49 +1100 (Fri, 16 Jan 2015) | 4 lines DOOM defs : moved 'SKY1/2/3' textures from NATURAL --> OTHER category, since they looked out of place there (they have little utility when used on walls, so "Other" category seems the most appropiate). ------------------------------------------------------------------------ r1614 | ajapted | 2015-01-16 22:16:27 +1100 (Fri, 16 Jan 2015) | 4 lines Game defs : moved the MBF dog thing --> Boom definition (ports/boom.ugh), which at least prevents it appearing in "vanilla" mode. Also changed its category from Player --> Other. ------------------------------------------------------------------------ r1613 | ajapted | 2015-01-16 22:13:53 +1100 (Fri, 16 Jan 2015) | 2 lines Renamed 'Manage Wads' command --> 'Manage Project' ------------------------------------------------------------------------ r1612 | ajapted | 2015-01-16 21:35:14 +1100 (Fri, 16 Jan 2015) | 3 lines Recolor the co-op player starts to match DOOM, i.e. type 2 start is gray, type 3 start is brown, type 4 start is red. ------------------------------------------------------------------------ r1611 | ajapted | 2015-01-16 20:50:00 +1100 (Fri, 16 Jan 2015) | 2 lines Code : minor rename, Img class --> Img_c ------------------------------------------------------------------------ r1610 | ajapted | 2015-01-16 20:40:03 +1100 (Fri, 16 Jan 2015) | 4 lines Img class : removed the Img_priv class, just have the fields in the private area of 'Img' class (renamed since they clashed with access methods). Also reformatted code to use tabs, plus various tidying. ------------------------------------------------------------------------ r1609 | ajapted | 2015-01-16 20:14:12 +1100 (Fri, 16 Jan 2015) | 3 lines Img class : implemented color_remap() method, like spectrify() but remaps a source color range into a target color range. ------------------------------------------------------------------------ r1608 | ajapted | 2015-01-16 19:59:08 +1100 (Fri, 16 Jan 2015) | 6 lines Browser : the BR_CycleCategory command now skips the 'RECENT' category. Rationale is that another key toggles between RECENT category and the ALL category, so when the user uses this function they are probably not after the special RECENT category. ------------------------------------------------------------------------ r1607 | ajapted | 2015-01-16 17:17:54 +1100 (Fri, 16 Jan 2015) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1606 | ajapted | 2015-01-16 15:47:39 +1100 (Fri, 16 Jan 2015) | 2 lines Man page : describe '$PREFIX/share/eureka' in FILES section. ------------------------------------------------------------------------ r1605 | ajapted | 2015-01-16 15:27:59 +1100 (Fri, 16 Jan 2015) | 2 lines Man page : added "FILES", "ENVIRONMENT" and "SEE ALSO" sections ------------------------------------------------------------------------ r1604 | ajapted | 2015-01-16 15:15:54 +1100 (Fri, 16 Jan 2015) | 2 lines Removed "ups" from the directories created in the $home_dir. ------------------------------------------------------------------------ r1603 | ajapted | 2015-01-16 14:22:20 +1100 (Fri, 16 Jan 2015) | 2 lines Man page : documented the main options, --file, --warp, --iwad, etc.... ------------------------------------------------------------------------ r1602 | ajapted | 2015-01-16 12:48:03 +1100 (Fri, 16 Jan 2015) | 3 lines Manual page : created a DESCRIPTION section, listing some of Eureka's features, and reworked other parts at top of file (SYNOPSIS, etc). ------------------------------------------------------------------------ r1601 | ajapted | 2015-01-16 12:45:54 +1100 (Fri, 16 Jan 2015) | 2 lines Added 'misc/eureka.6' -- a skeletal manual page, courtesy Fabian Greffrath. ------------------------------------------------------------------------ r1600 | ajapted | 2015-01-16 12:26:12 +1100 (Fri, 16 Jan 2015) | 3 lines For --help text, change order of command-line options to show the most important ones first (like --file and --iwad). ------------------------------------------------------------------------ r1599 | ajapted | 2015-01-16 11:38:10 +1100 (Fri, 16 Jan 2015) | 3 lines For the --help text, show long options with two dashes ('--') since I will use double dashes in the manpage. ------------------------------------------------------------------------ r1598 | ajapted | 2015-01-16 11:26:56 +1100 (Fri, 16 Jan 2015) | 2 lines Updated AUTHORS.txt ------------------------------------------------------------------------ r1597 | ajapted | 2015-01-16 10:59:37 +1100 (Fri, 16 Jan 2015) | 2 lines Code : fixed previous commit (SYS_ASSERT in the wrong place) ------------------------------------------------------------------------ r1596 | ajapted | 2015-01-16 10:50:33 +1100 (Fri, 16 Jan 2015) | 4 lines Code : added some SYS_ASSERT() checks to erase() method of RecentFiles_c. Perhaps this will silence the bogus warnings about out-of-bounds access which older GNU compilers generate. ------------------------------------------------------------------------ r1595 | ajapted | 2015-01-16 10:43:54 +1100 (Fri, 16 Jan 2015) | 2 lines Code : added __attribute((noreturn)) to the FatalError() prototype. ------------------------------------------------------------------------ r1594 | ajapted | 2015-01-16 00:03:40 +1100 (Fri, 16 Jan 2015) | 4 lines Browser : reduced size of sprites in Thing browser --> 64x72 (from 80x80) which works better horizontally (three columns at minimum size) and can generally see more things, albeit a few more things are cut off now. ------------------------------------------------------------------------ r1593 | ajapted | 2015-01-15 23:57:33 +1100 (Thu, 15 Jan 2015) | 2 lines Browser : tweaked name of "Other" category. ------------------------------------------------------------------------ r1592 | ajapted | 2015-01-15 23:56:49 +1100 (Thu, 15 Jan 2015) | 4 lines Browser : replaced the "Sort" choice widget with a "Alpha" checkbox, and moved the "Match" widget up. This makes the Things (etc) browsers more consistent looking with Flats and Textures, and a bit easier to use. ------------------------------------------------------------------------ r1591 | ajapted | 2015-01-15 23:44:44 +1100 (Thu, 15 Jan 2015) | 2 lines Browser : made the minimum width a bit narrower (10 units). ------------------------------------------------------------------------ r1590 | ajapted | 2015-01-15 23:28:43 +1100 (Thu, 15 Jan 2015) | 4 lines In main window's title, disabled the program name "Eureka" tacked on the end -- just seems like visual noise, especially with a [Read-Only] in the title. ------------------------------------------------------------------------ r1589 | ajapted | 2015-01-15 23:06:42 +1100 (Thu, 15 Jan 2015) | 2 lines Bindings : added '|' (SHIFT + '\') as the BR_CycleCategory function. ------------------------------------------------------------------------ r1588 | ajapted | 2015-01-15 22:50:15 +1100 (Thu, 15 Jan 2015) | 2 lines Game defs : tweaked name of "Health & Ammo" category. ------------------------------------------------------------------------ r1587 | ajapted | 2015-01-15 22:23:38 +1100 (Thu, 15 Jan 2015) | 4 lines Bindings : make 'T' (shift + t) open the browser to things, and 'X' (shift + x) open the browser to textures -- for consistency with the shortcuts in the BROWSER menu. ------------------------------------------------------------------------ r1586 | ajapted | 2015-01-15 22:12:10 +1100 (Thu, 15 Jan 2015) | 3 lines Menus : in Browser menu, moved 'Things' to first position, matching the order in the MODE choice on info-bar and the Find/Replace dialog. ------------------------------------------------------------------------ r1585 | ajapted | 2015-01-15 21:54:33 +1100 (Thu, 15 Jan 2015) | 2 lines Browser : tweaked title names and positioning. ------------------------------------------------------------------------ r1584 | ajapted | 2015-01-15 21:30:55 +1100 (Thu, 15 Jan 2015) | 2 lines Version bump. ------------------------------------------------------------------------ r1583 | ajapted | 2015-01-15 21:18:32 +1100 (Thu, 15 Jan 2015) | 3 lines 3D View : changed the low_detail/high_detail flag into a preference setting (instead of being toggleable with the F5 key). ------------------------------------------------------------------------ r1582 | ajapted | 2015-01-15 20:42:32 +1100 (Thu, 15 Jan 2015) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1581 | ajapted | 2015-01-15 20:41:12 +1100 (Thu, 15 Jan 2015) | 4 lines 3D View : tweaked the info bar, move gamma to just after gravity, and made the Tex/Lit/Obj indicators be highlighted when NOT in effect (so under normal circumstances they remain dim). ------------------------------------------------------------------------ r1580 | ajapted | 2015-01-15 20:34:56 +1100 (Thu, 15 Jan 2015) | 2 lines 3D View : finished the info-bar implementation. ------------------------------------------------------------------------ r1579 | ajapted | 2015-01-15 19:54:14 +1100 (Thu, 15 Jan 2015) | 3 lines 3D View : began work on an Information bar at top of render, showing the camera position, angle and various state. ------------------------------------------------------------------------ r1578 | ajapted | 2015-01-15 19:15:15 +1100 (Thu, 15 Jan 2015) | 3 lines Canvas : when drawing the "split line", show how and where the line will be split, with two new lines in orange and a small disc at new vertex. ------------------------------------------------------------------------ r1577 | ajapted | 2015-01-15 18:29:03 +1100 (Thu, 15 Jan 2015) | 4 lines Canvas : experimented with drawing a solid circle where the closest snap position to the mouse is (when SNAP is enabled), with a line going to the current mouse position.... Seems too weird to be useful. ------------------------------------------------------------------------ r1576 | ajapted | 2015-01-15 17:55:03 +1100 (Thu, 15 Jan 2015) | 5 lines Command system : registering commands is now done by passing a list of structures (instead of calling a function for each command). This will allow extra fields in the future, e.g. description of the command and what parameters it takes. ------------------------------------------------------------------------ r1575 | ajapted | 2015-01-15 16:52:49 +1100 (Thu, 15 Jan 2015) | 2 lines The 'CopyAndPaste' command broke recently -- fixed it. ------------------------------------------------------------------------ r1574 | ajapted | 2015-01-15 12:22:50 +1100 (Thu, 15 Jan 2015) | 2 lines Simplified some code using the bit-vector class. ------------------------------------------------------------------------ r1573 | ajapted | 2015-01-15 12:22:03 +1100 (Thu, 15 Jan 2015) | 2 lines Selection class : no need to check/grow the bit-vector, as it grows itself now. ------------------------------------------------------------------------ r1572 | ajapted | 2015-01-15 12:14:52 +1100 (Thu, 15 Jan 2015) | 2 lines Bitvec class : improved way vector is grown in set() method. ------------------------------------------------------------------------ r1571 | ajapted | 2015-01-15 11:58:20 +1100 (Thu, 15 Jan 2015) | 7 lines Bitvec class : added raw_get(), raw_set(), etc... as inline methods which do no range checking, and the normal get(), set(), etc... methods now check the position and will automatically resize the vector when needed. Also made resize() allow shrinking the vector when reduced by a large amount. ------------------------------------------------------------------------ r1570 | ajapted | 2015-01-15 11:33:58 +1100 (Thu, 15 Jan 2015) | 2 lines Bitvec class : removed unused 'merge()' method. ------------------------------------------------------------------------ r1569 | ajapted | 2015-01-14 23:25:36 +1100 (Wed, 14 Jan 2015) | 7 lines Menus : 1. added shortcuts to numerous menu items that lacked them (especially the Browser menu) 2. moved 'Prune unused' to below Delete, and removed its shortcut since the 'P' shortcut is already used by Paste. ------------------------------------------------------------------------ r1568 | ajapted | 2015-01-14 22:39:16 +1100 (Wed, 14 Jan 2015) | 3 lines Find/Replace : implemented linedef filtering based on sidedness, and fixed some issues with the tag filtering logic. ------------------------------------------------------------------------ r1567 | ajapted | 2015-01-14 22:18:41 +1100 (Wed, 14 Jan 2015) | 4 lines Find/Replace : 1. got the skill and mode filters for Things working 2. got the tag-number filter for Line/Sector searches working ------------------------------------------------------------------------ r1566 | ajapted | 2015-01-14 21:30:02 +1100 (Wed, 14 Jan 2015) | 4 lines Find/Replace : got the UI_TripleCheckButton working quite well, for both the skill flags and the mode flags, and implemented logic to compute the mask and compare value from those widgets. ------------------------------------------------------------------------ r1565 | ajapted | 2015-01-14 20:37:40 +1100 (Wed, 14 Jan 2015) | 3 lines Find/Replace : created a UI_TripleCheckButton() which is used to represent the search state for a boolean flag (YES, NO, DontCare). ------------------------------------------------------------------------ r1564 | ajapted | 2015-01-14 19:21:04 +1100 (Wed, 14 Jan 2015) | 2 lines CHANGELOG : yet another reorganisation... ------------------------------------------------------------------------ r1563 | ajapted | 2015-01-14 19:17:05 +1100 (Wed, 14 Jan 2015) | 3 lines Find/Replace : added code to show/hide the filter widgets based on the current mode (Things, LineDefs, etc). Also improved widget positions. ------------------------------------------------------------------------ r1562 | ajapted | 2015-01-14 18:50:42 +1100 (Wed, 14 Jan 2015) | 3 lines Find/Replace : began work on Filters -- this commit merely creates all the widgets we will need. ------------------------------------------------------------------------ r1561 | ajapted | 2015-01-14 16:53:11 +1100 (Wed, 14 Jan 2015) | 2 lines Find/Replace : finished 'Choose' button and browser interaction logic. ------------------------------------------------------------------------ r1560 | ajapted | 2015-01-14 15:29:34 +1100 (Wed, 14 Jan 2015) | 2 lines Find/Replace : worked on 'Choose' button and interaction with the Browser... ------------------------------------------------------------------------ r1559 | ajapted | 2015-01-14 15:01:19 +1100 (Wed, 14 Jan 2015) | 2 lines Find/Replace : when '*' is used, show "(everything)" as the description. ------------------------------------------------------------------------ r1558 | ajapted | 2015-01-14 14:51:58 +1100 (Wed, 14 Jan 2015) | 3 lines Find/Replace : when 'Replace All', select all the objects which were modified and goto this selection at the end -- lets the user see what was affected. ------------------------------------------------------------------------ r1557 | ajapted | 2015-01-14 14:47:43 +1100 (Wed, 14 Jan 2015) | 2 lines Find/Replace : support for finding and replacing Line-Types and Sector-Types. ------------------------------------------------------------------------ r1556 | ajapted | 2015-01-14 14:46:43 +1100 (Wed, 14 Jan 2015) | 2 lines Objid : the clear() method now only changes the 'num', leaves 'type' alone. ------------------------------------------------------------------------ r1555 | ajapted | 2015-01-13 21:59:34 +1100 (Tue, 13 Jan 2015) | 2 lines README.txt : document the '\' key (toggle RECENT category). ------------------------------------------------------------------------ r1554 | ajapted | 2015-01-13 21:51:24 +1100 (Tue, 13 Jan 2015) | 5 lines Find/Replace : 1. renamed 'Apply' button --> 'Replace' 2. only activate 'Replace' button when something has been found 3. implemented Replace_Thing() method ------------------------------------------------------------------------ r1553 | ajapted | 2015-01-13 21:30:53 +1100 (Tue, 13 Jan 2015) | 3 lines Texture checker : assume textures beginning with '#' are special, do not treat them as unknown textures. ------------------------------------------------------------------------ r1552 | ajapted | 2015-01-13 21:15:14 +1100 (Tue, 13 Jan 2015) | 3 lines Vertex Reshaping : added bindings for them, and document them in the README and CHANGELOG. ------------------------------------------------------------------------ r1551 | ajapted | 2015-01-13 21:13:20 +1100 (Tue, 13 Jan 2015) | 3 lines Vertex Reshaping : register its command, and properly check the parameter to call the correct function (e.g. "line" vs "circle" vs "arc180"). ------------------------------------------------------------------------ r1550 | ajapted | 2015-01-13 20:48:05 +1100 (Tue, 13 Jan 2015) | 3 lines Vertices : support for shaping vertices into a half-circle (180 degrees) or a quarter circle (90 degrees). ------------------------------------------------------------------------ r1549 | ajapted | 2015-01-13 18:54:52 +1100 (Tue, 13 Jan 2015) | 3 lines Vertices : implemented the EvalCircle() function -- the circle reshaping code is working now. ------------------------------------------------------------------------ r1548 | ajapted | 2015-01-13 18:27:27 +1100 (Tue, 13 Jan 2015) | 2 lines Vertices : partial work on command to reshape vertices into a pure circle. ------------------------------------------------------------------------ r1547 | ajapted | 2015-01-13 17:44:12 +1100 (Tue, 13 Jan 2015) | 2 lines Vertices : got the Reshape_Line() code working. ------------------------------------------------------------------------ r1546 | ajapted | 2015-01-13 17:07:24 +1100 (Tue, 13 Jan 2015) | 3 lines Vertices : further work on straight line reshaper, collect all vertices and sort them along the line, and then determine the end-points we need. ------------------------------------------------------------------------ r1545 | ajapted | 2015-01-13 16:30:52 +1100 (Tue, 13 Jan 2015) | 3 lines Vertices : worked on code to move all selected vertices onto a straight line (some experimental stuff...) ------------------------------------------------------------------------ r1544 | ajapted | 2015-01-13 16:29:12 +1100 (Tue, 13 Jan 2015) | 2 lines Basis : ensure BA_Begin() has been called for BA_New() and BA_Delete() functions. ------------------------------------------------------------------------ r1543 | ajapted | 2015-01-13 15:19:59 +1100 (Tue, 13 Jan 2015) | 3 lines Key bindings : increased maximum parameters of a binding from 4 --> 16, and increased the maximum length of a parameter from 16 --> 32. ------------------------------------------------------------------------ r1542 | ajapted | 2015-01-13 14:56:52 +1100 (Tue, 13 Jan 2015) | 2 lines Code : moved prototypes for Status_xxx() and Beep() functions --> main.h ------------------------------------------------------------------------ r1541 | ajapted | 2015-01-13 12:22:42 +1100 (Tue, 13 Jan 2015) | 4 lines Find/Replace : implemented rep_value_callback(), ensuring the 'Apply' and 'Replace All' buttons are only active when both the rep_value is valid and the find_match is valid. ------------------------------------------------------------------------ r1540 | ajapted | 2015-01-13 11:58:40 +1100 (Tue, 13 Jan 2015) | 2 lines Find/Replace : support '*' wildcard in number_group_c ------------------------------------------------------------------------ r1539 | ajapted | 2015-01-12 23:17:13 +1100 (Mon, 12 Jan 2015) | 2 lines Code tweak : consistent capitalization for top-of-file descriptions. ------------------------------------------------------------------------ r1538 | ajapted | 2015-01-12 23:04:23 +1100 (Mon, 12 Jan 2015) | 3 lines Code : removed commented-out code for CMD_FindObjectByType() -- the new Find/Replace panel implements equivalent functionality. ------------------------------------------------------------------------ r1537 | ajapted | 2015-01-12 23:01:48 +1100 (Mon, 12 Jan 2015) | 9 lines Objid rework: 1. moved obj_type_e definition --> objid.h 2. removed 'OBJ_NONE' as a member of obj_type_e enumeration 3. renamed 'OBJ_NO_NONE' constant --> 'NIL_OBJ' 4. in Objid class, replaced '()' operator with 'valid()' method 5. removed the barely used is_obj() macro 6. renamed 'edit.highlighted' --> 'edit.highlight' ------------------------------------------------------------------------ r1536 | ajapted | 2015-01-12 21:00:51 +1100 (Mon, 12 Jan 2015) | 2 lines Find/Replace : tweaked size of 'what' choice widget. ------------------------------------------------------------------------ r1535 | ajapted | 2015-01-12 20:58:23 +1100 (Mon, 12 Jan 2015) | 7 lines Find/Replace : 1. remove the toggle button for the Replace section, was rather unnecessary, and now there is more room for the Filters section. 2. made the 'what' choice (Things, Line Textures, etc) be colored, using colors that match the mode colors in infobar widget. ------------------------------------------------------------------------ r1534 | ajapted | 2015-01-12 19:50:23 +1100 (Mon, 12 Jan 2015) | 4 lines Find/Replace : better handling of 'Select All' button, e.g. beep with "nothing found" message if nothing was found, and if some stuff _was_ found then use GoToSelection() to move/zoom in to it. ------------------------------------------------------------------------ r1533 | ajapted | 2015-01-12 19:38:54 +1100 (Mon, 12 Jan 2015) | 4 lines Find/Replace : 1. Got the 'number_group_c' class working, can find things with it now. 2. Make sure selection is cleared after nothing is found ------------------------------------------------------------------------ r1532 | ajapted | 2015-01-12 18:55:59 +1100 (Mon, 12 Jan 2015) | 3 lines Find/Replace : created a 'number_group_c' class for storing a small group of numbers or number ranges. Also implemented its ParseString() method. ------------------------------------------------------------------------ r1531 | ajapted | 2015-01-12 18:19:44 +1100 (Mon, 12 Jan 2015) | 4 lines Removed the 'selectn.cc/h' code files -- merged the code into levels.cc/h Also moved some code from objects.cc/h --> levels.cc/h (notification stuff) ------------------------------------------------------------------------ r1530 | ajapted | 2015-01-12 18:09:13 +1100 (Mon, 12 Jan 2015) | 2 lines Find/Replace : bit more work, got basic Thing matching working. ------------------------------------------------------------------------ r1529 | ajapted | 2015-01-12 16:53:31 +1100 (Mon, 12 Jan 2015) | 2 lines Find/Replace : properly set the description for a thing type (etc). ------------------------------------------------------------------------ r1528 | ajapted | 2015-01-12 16:46:27 +1100 (Mon, 12 Jan 2015) | 3 lines Find/Replace : implemented find_match callback, e.g. validate that the string is numeric (for Things or for line/sector types). ------------------------------------------------------------------------ r1527 | ajapted | 2015-01-12 15:57:04 +1100 (Mon, 12 Jan 2015) | 2 lines Added Editor_ChangeMode_Raw() function. ------------------------------------------------------------------------ r1526 | ajapted | 2015-01-12 15:18:32 +1100 (Mon, 12 Jan 2015) | 4 lines Find/Replace : worked on outer logic for finding the first/next object, and for selecting everything or doing a replace on all matches. The inner logic (MatchObject or ApplyReplace methods) are not started yet.... ------------------------------------------------------------------------ r1525 | ajapted | 2015-01-12 15:10:04 +1100 (Mon, 12 Jan 2015) | 2 lines minor rename ------------------------------------------------------------------------ r1524 | ajapted | 2015-01-12 14:57:11 +1100 (Mon, 12 Jan 2015) | 2 lines Coding : removed unused macros (IsSelected, SelectObject, etc) from selectn.h ------------------------------------------------------------------------ r1523 | ajapted | 2015-01-12 14:24:54 +1100 (Mon, 12 Jan 2015) | 3 lines Find/Replace : bit more work, added Clear() method, added several more callback functions (skeletal atm), call BrowsedItem() from UI_MainWin. ------------------------------------------------------------------------ r1522 | ajapted | 2015-01-12 12:13:05 +1100 (Mon, 12 Jan 2015) | 4 lines Preferences : enabled the 'Maximize on start-up' option, except for MacOS X platform. This is instead of restoring the last window position and maximized state, which is non-trivial (especially on Linux), but better than nothing. ------------------------------------------------------------------------ r1521 | ajapted | 2015-01-12 11:56:19 +1100 (Mon, 12 Jan 2015) | 2 lines Added 'Toggle 3D View' command to the VIEW menu. ------------------------------------------------------------------------ r1520 | ajapted | 2015-01-12 11:45:49 +1100 (Mon, 12 Jan 2015) | 2 lines Default probs : layout tweak. ------------------------------------------------------------------------ r1519 | ajapted | 2015-01-12 11:42:16 +1100 (Mon, 12 Jan 2015) | 3 lines Default props : added labels above the textures, and spaced the three groups out some more. ------------------------------------------------------------------------ r1518 | ajapted | 2015-01-12 11:13:05 +1100 (Mon, 12 Jan 2015) | 3 lines Preferences : when the 'browser_small_tex' value is changed, re-populate the browser (to show the resized textures). ------------------------------------------------------------------------ r1517 | ajapted | 2015-01-11 23:16:17 +1100 (Sun, 11 Jan 2015) | 2 lines TODO.txt updated (lots of WIP stuff...) ------------------------------------------------------------------------ r1516 | ajapted | 2015-01-11 22:56:55 +1100 (Sun, 11 Jan 2015) | 3 lines Implemented new 'browser_small_tex' option to show smaller textures in the texture browser. Includes addition to the Preferences dialog. ------------------------------------------------------------------------ r1515 | ajapted | 2015-01-11 21:35:26 +1100 (Sun, 11 Jan 2015) | 2 lines Find/Replace : implemented the toggle buttons showing/hiding their group. ------------------------------------------------------------------------ r1514 | ajapted | 2015-01-11 21:02:47 +1100 (Sun, 11 Jan 2015) | 3 lines Find/Replace : fixed dismissing the panel by pressing the key for the current mode, e.g. 'v' for vertices. ------------------------------------------------------------------------ r1513 | ajapted | 2015-01-11 20:51:35 +1100 (Sun, 11 Jan 2015) | 4 lines Find/Replace : worked on layout some more, grouping the three sub-panels into their own group (leaving a think BG_COLOR border between each panel). Also tidied up the code (the output from fluid). ------------------------------------------------------------------------ r1512 | ajapted | 2015-01-11 20:21:21 +1100 (Sun, 11 Jan 2015) | 3 lines Find/Replace : created main UI for this (done in Fluid, code reformatted and pasted here). Nothing works yet.... ------------------------------------------------------------------------ r1511 | ajapted | 2015-01-11 17:13:10 +1100 (Sun, 11 Jan 2015) | 2 lines Find/Replace : added 'Go to next' to View menu (not implemented yet....) ------------------------------------------------------------------------ r1510 | ajapted | 2015-01-11 17:03:54 +1100 (Sun, 11 Jan 2015) | 2 lines Find/Replace : add widget to main window, and added menu item for it. ------------------------------------------------------------------------ r1509 | ajapted | 2015-01-11 17:02:31 +1100 (Sun, 11 Jan 2015) | 2 lines Makefiles : added 'ui_replace.o' into the build. ------------------------------------------------------------------------ r1508 | ajapted | 2015-01-11 15:53:41 +1100 (Sun, 11 Jan 2015) | 3 lines Added new files 'ui_replace.cc/h' -- will contain the Find and Replace panel (only contains minimal code at the moment). ------------------------------------------------------------------------ r1507 | ajapted | 2015-01-11 15:45:16 +1100 (Sun, 11 Jan 2015) | 2 lines Default props : fixed using the Browser to set stuff (textures etc). ------------------------------------------------------------------------ r1506 | ajapted | 2015-01-11 15:28:07 +1100 (Sun, 11 Jan 2015) | 2 lines Default props : hide it when press CTRL-D and already shown. ------------------------------------------------------------------------ r1505 | ajapted | 2015-01-11 15:15:27 +1100 (Sun, 11 Jan 2015) | 2 lines Default props : added command in File/ menu to show it, and various fixes. ------------------------------------------------------------------------ r1504 | ajapted | 2015-01-11 14:52:55 +1100 (Sun, 11 Jan 2015) | 2 lines Default props : removed toggle button and related code. ------------------------------------------------------------------------ r1503 | ajapted | 2015-01-11 14:45:51 +1100 (Sun, 11 Jan 2015) | 2 lines Default props : added "Lower" (etc) names to the wall texture pics. ------------------------------------------------------------------------ r1502 | ajapted | 2015-01-11 14:07:15 +1100 (Sun, 11 Jan 2015) | 3 lines Finished separating UI_DefaultProps code, splitting the implementation into header file + code file definitions. ------------------------------------------------------------------------ r1501 | ajapted | 2015-01-11 13:57:04 +1100 (Sun, 11 Jan 2015) | 2 lines (forgot 'Makefile' in previous commit) ------------------------------------------------------------------------ r1500 | ajapted | 2015-01-11 13:45:05 +1100 (Sun, 11 Jan 2015) | 3 lines More work to separate UI_DefaultProps code -- mainly deleting the relevant parts from ui_vertex.* and ui_default.* -- but also updated the Makefiles. ------------------------------------------------------------------------ r1499 | ajapted | 2015-01-11 13:35:17 +1100 (Sun, 11 Jan 2015) | 3 lines Began work to separate code for the 'Default Properties' panel into its own code files --> ui_default.cc/h. This commit merely copies the new files. ------------------------------------------------------------------------ r1498 | ajapted | 2015-01-11 13:31:07 +1100 (Sun, 11 Jan 2015) | 3 lines Always show a two-sided line in LineDef panel when multiple lines are selected (and are a mix of one-sided and two-sided lines). ------------------------------------------------------------------------ r1497 | ajapted | 2015-01-09 14:30:00 +1100 (Fri, 09 Jan 2015) | 2 lines Wad code : re-sort the levels[] array after adding a new level. ------------------------------------------------------------------------ r1496 | ajapted | 2015-01-07 13:32:52 +1100 (Wed, 07 Jan 2015) | 3 lines Keys : convert FL_Button+n values <--> "MOUSE##" string, and FL_WheelUp/Dn values <--> "WHEEL_UP/DN" strings. ------------------------------------------------------------------------ r1495 | ajapted | 2015-01-06 16:01:31 +1100 (Tue, 06 Jan 2015) | 2 lines TODO.txt : moved the 'NO:' stuff to a separate NOT-TO-DO section. ------------------------------------------------------------------------ r1494 | ajapted | 2015-01-06 15:55:59 +1100 (Tue, 06 Jan 2015) | 3 lines Finished support for RECENT browser category, with new binding for '\' key which toggles between the ALL and RECENT categories. ------------------------------------------------------------------------ r1493 | ajapted | 2015-01-06 13:57:11 +1100 (Tue, 06 Jan 2015) | 4 lines More work on new "RECENT" category for Texture (etc) browsers. Implemented ability to save/restore them from the .dat cache file, and fixed a few issues. ------------------------------------------------------------------------ r1492 | ajapted | 2015-01-06 13:55:15 +1100 (Tue, 06 Jan 2015) | 3 lines Menu : removed short-cut from 'File/Delete Map' command, as it likely will be used rarely and it's not something you want to hit accidentally. ------------------------------------------------------------------------ r1491 | ajapted | 2015-01-06 11:05:17 +1100 (Tue, 06 Jan 2015) | 2 lines Partial work on a "RECENT" category for the Texture, Flat and Thing browsers. ------------------------------------------------------------------------ r1490 | ajapted | 2015-01-05 19:31:27 +1100 (Mon, 05 Jan 2015) | 2 lines Updated some copyright messages (e.g. About box) for 2015. ------------------------------------------------------------------------ r1489 | ajapted | 2015-01-05 19:30:50 +1100 (Mon, 05 Jan 2015) | 2 lines Version bump. ------------------------------------------------------------------------ r1488 | ajapted | 2015-01-05 19:14:57 +1100 (Mon, 05 Jan 2015) | 2 lines Render : fixed clipping of mid-masked textures (e.g. the cage in E1M9) ------------------------------------------------------------------------ r1487 | ajapted | 2015-01-05 11:55:34 +1100 (Mon, 05 Jan 2015) | 2 lines Moved the BA_LevelChecksum() code from e_loadsave --> e_basis ------------------------------------------------------------------------ r1486 | ajapted | 2015-01-05 11:54:31 +1100 (Mon, 05 Jan 2015) | 3 lines Wad code : sort the levels alphabetically in the levels[] vector (mainly for the next-map and prev-map commands). ------------------------------------------------------------------------ r1485 | ajapted | 2015-01-05 11:10:08 +1100 (Mon, 05 Jan 2015) | 2 lines Implemented the 'File / Rename Map' command (no shortcut key). ------------------------------------------------------------------------ r1484 | ajapted | 2015-01-05 10:21:10 +1100 (Mon, 05 Jan 2015) | 2 lines Wad code : implemented 'RenameLump()' method. ------------------------------------------------------------------------ r1483 | ajapted | 2015-01-05 10:07:04 +1100 (Mon, 05 Jan 2015) | 2 lines Implemented new 'File / Delete Map' command (bound to CTRL-d key). ------------------------------------------------------------------------ r1482 | ajapted | 2015-01-04 20:50:46 +1100 (Sun, 04 Jan 2015) | 5 lines Reworked the way "New WAD File" button in the 'New Map' command works, it is now a radio button with another choice "Current WAD File", and when chosen then we immediately try to save (export) the new map -- which feels more like what the user would expect. ------------------------------------------------------------------------ r1481 | ajapted | 2015-01-04 20:10:14 +1100 (Sun, 04 Jan 2015) | 2 lines TODO update. ------------------------------------------------------------------------ r1480 | ajapted | 2015-01-04 20:06:35 +1100 (Sun, 04 Jan 2015) | 3 lines Fixed the occasional false positives with the sector mismatch test (caused by poor logic in OppositeLineDef and OppositeSector functions). ------------------------------------------------------------------------ r1479 | ajapted | 2015-01-04 20:04:46 +1100 (Sun, 04 Jan 2015) | 3 lines Fixed zooming after doing a command, like 'j' JumpToObject, which moves the map origin to focus on some selected object(s). ------------------------------------------------------------------------ r1478 | ajapted | 2015-01-04 16:48:05 +1100 (Sun, 04 Jan 2015) | 2 lines Makefile.xming : updated to use 'mingw-w64' cross compiler and zlib 1.2.8 ------------------------------------------------------------------------ r1477 | ajapted | 2015-01-04 16:34:56 +1100 (Sun, 04 Jan 2015) | 2 lines Removed 'slurp' directory from obj_linux/ and obj_win32/ ------------------------------------------------------------------------ r1476 | ajapted | 2015-01-04 16:32:14 +1100 (Sun, 04 Jan 2015) | 2 lines Makefiles : added 'STRIP_FLAGS' variable (for "stripped" target). ------------------------------------------------------------------------ r1475 | ajapted | 2015-01-04 16:01:35 +1100 (Sun, 04 Jan 2015) | 4 lines For 'New Map' dialog, added a "New File" check button which means the wad will be saved into a new file (disables the map selection, since that is done by the export map dialog). ------------------------------------------------------------------------ r1474 | ajapted | 2015-01-04 11:55:08 +1100 (Sun, 04 Jan 2015) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1473 | ajapted | 2015-01-04 11:54:26 +1100 (Sun, 04 Jan 2015) | 2 lines Support two numeric values after -warp, compatible with vanilla DOOM. ------------------------------------------------------------------------ r1472 | ajapted | 2015-01-04 11:30:20 +1100 (Sun, 04 Jan 2015) | 3 lines Linedef panel : swapped 'Tag' and 'Length' widgets(so Tag is now on left (like the Sector panel). ------------------------------------------------------------------------ r1471 | ajapted | 2015-01-04 11:25:27 +1100 (Sun, 04 Jan 2015) | 2 lines Code : silence some compiler warnings about integer conversions. ------------------------------------------------------------------------ r1470 | printz | 2015-01-03 09:01:20 +1100 (Sat, 03 Jan 2015) | 3 lines osx: * Fixed type warnings on the app delegate because I didn't set it to conform to the NSApplicationDelegate protocol * Added other .a files to the dependency list, because I was getting linker errors. ------------------------------------------------------------------------ r1469 | printz | 2014-11-15 10:06:48 +1100 (Sat, 15 Nov 2014) | 2 lines * Updated Xcode project to work * Removed a personal file ------------------------------------------------------------------------ r1468 | ajapted | 2014-10-25 22:34:34 +1100 (Sat, 25 Oct 2014) | 4 lines Support 'coop_dm_flags' feature in game definitions, and when not enabled then show a vanilla DOOM compatible "dm" thing flag (instead of the normal three sp/coop/dm flags). ------------------------------------------------------------------------ r1467 | ajapted | 2014-10-25 22:00:21 +1100 (Sat, 25 Oct 2014) | 2 lines Fixed makefile "install" targets for r1459 (moved "bindings.cfg" to top level) ------------------------------------------------------------------------ r1466 | ajapted | 2014-10-25 21:54:50 +1100 (Sat, 25 Oct 2014) | 3 lines UI_Window : added UpdateGameInfo() method, and use it for THING panel to show or hide the "friend" checkbox depending on game_info.friend_flag ------------------------------------------------------------------------ r1465 | ajapted | 2014-10-25 21:53:26 +1100 (Sat, 25 Oct 2014) | 2 lines Added 'friend_flag' field to game_info_t and parse it from definition files. ------------------------------------------------------------------------ r1464 | ajapted | 2014-10-25 21:52:16 +1100 (Sat, 25 Oct 2014) | 2 lines Ports / BOOM : added "feature friend_flag 1" ------------------------------------------------------------------------ r1463 | ajapted | 2014-10-25 21:27:26 +1100 (Sat, 25 Oct 2014) | 3 lines Use simple char[] for 'sky_flat' member of game_info, so we can memset() the whole structure to zero in M_InitDefinitions(). ------------------------------------------------------------------------ r1462 | ajapted | 2014-10-25 20:11:57 +1100 (Sat, 25 Oct 2014) | 4 lines (part of VM removal) : removed 'misc/core_defs.up' script file, which was never used and barely had anything in it. Updated 'make install' targets in the Makefiles too. ------------------------------------------------------------------------ r1461 | ajapted | 2014-10-25 20:07:13 +1100 (Sat, 25 Oct 2014) | 3 lines Removed all the VM code (vm.h + vm_*.cc) -- this was never used and was a long way from becoming usable. Lua would be a better choice anyway. ------------------------------------------------------------------------ r1460 | ajapted | 2014-10-25 19:52:30 +1100 (Sat, 25 Oct 2014) | 2 lines Preferences : added '192' to list of possible default grid sizes. ------------------------------------------------------------------------ r1459 | ajapted | 2014-09-12 20:29:11 +1000 (Fri, 12 Sep 2014) | 3 lines Moved 'bindings.cfg' to top level in repository, so that running Eureka after a compilation (without installing it) works. ------------------------------------------------------------------------ r1458 | ajapted | 2014-09-12 20:22:51 +1000 (Fri, 12 Sep 2014) | 2 lines silence a compiler warning. ------------------------------------------------------------------------ r1457 | ajapted | 2014-08-15 15:28:58 +1000 (Fri, 15 Aug 2014) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1456 | ajapted | 2014-08-15 13:45:35 +1000 (Fri, 15 Aug 2014) | 5 lines 3D View : fixed texturing issue, textures could be vertically off by a pixel (due to the way casting float --> int will round towards zero). This closes ticket #3. Bug reported by 'umbrakun'. ------------------------------------------------------------------------ r1455 | ajapted | 2014-08-06 16:14:06 +1000 (Wed, 06 Aug 2014) | 2 lines README.txt : added contact details at the end. ------------------------------------------------------------------------ r1454 | ajapted | 2014-08-06 15:49:34 +1000 (Wed, 06 Aug 2014) | 2 lines TODO update. ------------------------------------------------------------------------ r1453 | ajapted | 2014-06-25 22:05:45 +1000 (Wed, 25 Jun 2014) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1452 | ajapted | 2014-06-25 22:04:01 +1000 (Wed, 25 Jun 2014) | 8 lines glBSP library : improved method of creating a dummy node, we now create a real subsector and a real seg for the back side of the partition line (though the seg is a carbon copy of an existing one). This method should be more robust, since the created structures are all real (instead of re-using an index number). Tested in various software rendered ports without any problem. ------------------------------------------------------------------------ r1451 | ajapted | 2014-06-25 21:32:11 +1000 (Wed, 25 Jun 2014) | 3 lines Removed misc/slurp -- (a) it does not belong here, and (b) I do not plan to finish or release it. ------------------------------------------------------------------------ r1450 | ajapted | 2014-06-25 21:15:11 +1000 (Wed, 25 Jun 2014) | 2 lines Comment the NSIS makefile and 'nsi' file as OLD / OBSOLETE. ------------------------------------------------------------------------ r1449 | ajapted | 2014-06-25 19:53:59 +1000 (Wed, 25 Jun 2014) | 3 lines Ports / BOOM : added "feature gen_types 1" -- this will (in the future) enable support for generalized linedefs and sectors. ------------------------------------------------------------------------ r1448 | ajapted | 2014-06-25 19:51:55 +1000 (Wed, 25 Jun 2014) | 6 lines Game definition parser : support "feature" keyword which is used to activate (or de-activate) certain game- or port-related features. So far three feature names are _parsed_, but there is no actual support for those features yet. ------------------------------------------------------------------------ r1447 | printz | 2014-06-25 17:27:19 +1000 (Wed, 25 Jun 2014) | 3 lines Xcode project: * Updated library references * Made it so all source files (at least from the C++ group) will have real tabs instead of groups of spaces ------------------------------------------------------------------------ r1446 | ajapted | 2014-06-19 22:31:53 +1000 (Thu, 19 Jun 2014) | 2 lines glBSP library : more dramatic warning when creating a dummy node. ------------------------------------------------------------------------ r1445 | ajapted | 2014-06-19 22:14:18 +1000 (Thu, 19 Jun 2014) | 6 lines glBSP library : implemented a hack for the case when no nodes are generated (i.e. when the whole level is a single convex sector). This hack involves creating a dummy node with the real subsector on one side, and a dummy one on the other. ------------------------------------------------------------------------ r1444 | ajapted | 2014-06-19 20:38:08 +1000 (Thu, 19 Jun 2014) | 2 lines TODO.txt : moved more stuff --> doc/MiscNotes.txt ------------------------------------------------------------------------ r1443 | ajapted | 2014-06-19 19:20:55 +1000 (Thu, 19 Jun 2014) | 3 lines TODO.txt : updated various entries, and moved some of the notes to a new file --> docs/MiscNotes.txt ------------------------------------------------------------------------ r1442 | ajapted | 2014-06-19 19:05:47 +1000 (Thu, 19 Jun 2014) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1441 | ajapted | 2014-06-19 19:01:17 +1000 (Thu, 19 Jun 2014) | 2 lines About box : show version number _in_ the text (not just window title). ------------------------------------------------------------------------ r1440 | ajapted | 2014-06-19 18:47:45 +1000 (Thu, 19 Jun 2014) | 2 lines When saving the map, save any header data too (for FraggleScript etc). ------------------------------------------------------------------------ r1439 | ajapted | 2014-06-19 18:27:28 +1000 (Thu, 19 Jun 2014) | 3 lines When loading a map, load any data in the header lump, especially the FraggleScript and level-info data used by DOOM Legacy. ------------------------------------------------------------------------ r1438 | ajapted | 2014-06-19 17:45:39 +1000 (Thu, 19 Jun 2014) | 2 lines Makefile.xming (WIN32) : update to FLTK 1.3.2 and zlib 1.2.6 ------------------------------------------------------------------------ r1437 | ajapted | 2014-06-19 13:07:06 +1000 (Thu, 19 Jun 2014) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1436 | ajapted | 2014-06-19 13:05:54 +1000 (Thu, 19 Jun 2014) | 8 lines Support loading a pwad which is READ-ONLY. This will cause the 'Save' action to ask whether to export to a file, and the 'Build Nodes' action will show a fail message. The window title will also show the read-only state of the current file. This closes bug ticket #2. ------------------------------------------------------------------------ r1435 | ajapted | 2014-05-18 16:59:56 +1000 (Sun, 18 May 2014) | 2 lines File menu : tweaked position of Build Nodes entry. ------------------------------------------------------------------------ r1434 | ajapted | 2014-05-18 16:54:44 +1000 (Sun, 18 May 2014) | 4 lines Fixed bug when saving a map and using the "ExMx" buttons -- there was an erroneous newline added to the lump name, preventing the game from accessing the map. Thanks to ettingrinder for the bug report. ------------------------------------------------------------------------ r1433 | ajapted | 2014-01-26 00:16:36 +1100 (Sun, 26 Jan 2014) | 3 lines Fixed bug not loading 'ASHWALL' texture for DOOM 1, which occurred because we erroneously skipped the first entry of TEXTURE2 lump. ------------------------------------------------------------------------ r1432 | ajapted | 2014-01-26 00:14:51 +1100 (Sun, 26 Jan 2014) | 2 lines Began fresh CHANGES.txt document (after 1.00 release) ------------------------------------------------------------------------ r1431 | ajapted | 2014-01-26 00:13:52 +1100 (Sun, 26 Jan 2014) | 2 lines Moved version 1.00 CHANGELOG --> changelogs/100.txt ------------------------------------------------------------------------ r1430 | ajapted | 2014-01-09 10:26:25 +1100 (Thu, 09 Jan 2014) | 2 lines Post-release version bump. ------------------------------------------------------------------------ r1429 | ajapted | 2014-01-05 22:31:54 +1100 (Sun, 05 Jan 2014) | 2 lines Updated some copyright years (e.g. in About box) for 2014. ------------------------------------------------------------------------ r1428 | ajapted | 2014-01-05 21:26:00 +1100 (Sun, 05 Jan 2014) | 2 lines Re-instated the '192' grid size (reverted revision 628). ------------------------------------------------------------------------ r1427 | ajapted | 2013-12-27 10:22:24 +1100 (Fri, 27 Dec 2013) | 2 lines Updated GPL.txt -- the GNU General Public License (version 2). ------------------------------------------------------------------------ r1426 | ajapted | 2013-10-27 14:21:34 +1100 (Sun, 27 Oct 2013) | 2 lines Makefile : renamed INSTALL_PREFIX --> PREFIX ------------------------------------------------------------------------ r1425 | ajapted | 2013-10-27 13:49:10 +1100 (Sun, 27 Oct 2013) | 2 lines Use I_ROUND() macro instead of round() standard library call. ------------------------------------------------------------------------ r1424 | ajapted | 2013-09-09 20:02:55 +1000 (Mon, 09 Sep 2013) | 2 lines Workaround a compiler warning. ------------------------------------------------------------------------ r1423 | ajapted | 2013-08-25 15:26:16 +1000 (Sun, 25 Aug 2013) | 2 lines History.txt : resync for the 1.00 release. ------------------------------------------------------------------------ r1422 | ajapted | 2013-08-25 15:20:46 +1000 (Sun, 25 Aug 2013) | 2 lines Pack-source script: handle the 'ups' folder (as per 'mods' etc). ------------------------------------------------------------------------ r1421 | ajapted | 2013-08-25 14:58:40 +1000 (Sun, 25 Aug 2013) | 2 lines README.txt : more updates to the keys list. ------------------------------------------------------------------------ r1420 | ajapted | 2013-08-25 14:48:04 +1000 (Sun, 25 Aug 2013) | 2 lines README.txt : updated key list for ';' and 3D view offset commands. ------------------------------------------------------------------------ r1419 | ajapted | 2013-08-25 14:36:09 +1000 (Sun, 25 Aug 2013) | 2 lines README.txt : simplified the INTRODUCTION section. ------------------------------------------------------------------------ r1418 | printz | 2013-08-25 09:18:26 +1000 (Sun, 25 Aug 2013) | 7 lines osx: * Added a new generic OSX call module, for interfacing OSX system calls with the main application C++ code * Prepared Xcode project for release * Corrected copyright in my modules to actually refer to the author(s) of Eureka in whole, not to the author of the module. * Removed dead code from AppDelegate.mm * Updated OSX icon * Fixed main.cc to use system-proof application data directories. ------------------------------------------------------------------------ r1417 | ajapted | 2013-08-23 21:52:21 +1000 (Fri, 23 Aug 2013) | 2 lines INSTALL.txt tweak. ------------------------------------------------------------------------ r1416 | ajapted | 2013-08-23 21:44:10 +1000 (Fri, 23 Aug 2013) | 2 lines CHANGELOG tweak for 1.00 release. ------------------------------------------------------------------------ r1415 | ajapted | 2013-08-23 21:34:00 +1000 (Fri, 23 Aug 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1414 | ajapted | 2013-08-23 15:33:43 +1000 (Fri, 23 Aug 2013) | 2 lines NSIS install script : updated to use the Modern UI (MUI2.nsh). ------------------------------------------------------------------------ r1413 | ajapted | 2013-08-23 15:30:07 +1000 (Fri, 23 Aug 2013) | 3 lines Makefile.xming : updated 'nsis_build' target to add "ups" folder and to copy the "about_logo.png" and "core_defs.up" files. ------------------------------------------------------------------------ r1412 | ajapted | 2013-08-23 15:05:08 +1000 (Fri, 23 Aug 2013) | 2 lines Makefile.xming : properly include the Win32 resource stuff in the build. ------------------------------------------------------------------------ r1411 | ajapted | 2013-08-23 14:51:50 +1000 (Fri, 23 Aug 2013) | 2 lines Updated WIN32 "rc" file to include the ICON resource. ------------------------------------------------------------------------ r1410 | ajapted | 2013-08-23 14:51:17 +1000 (Fri, 23 Aug 2013) | 3 lines Fixed WIN32 icon file (eureka.ico) -- I accidentally committed the XCF version before. ------------------------------------------------------------------------ r1409 | ajapted | 2013-08-23 14:42:56 +1000 (Fri, 23 Aug 2013) | 2 lines Makefile.xming : added 'fltk_png.a' library to the build. ------------------------------------------------------------------------ r1408 | ajapted | 2013-08-23 14:39:37 +1000 (Fri, 23 Aug 2013) | 2 lines Fixed bug in WIN32-specific code. ------------------------------------------------------------------------ r1407 | ajapted | 2013-08-23 14:37:11 +1000 (Fri, 23 Aug 2013) | 2 lines Quieten some compiler warnings. ------------------------------------------------------------------------ r1406 | ajapted | 2013-08-23 14:24:38 +1000 (Fri, 23 Aug 2013) | 2 lines Created a 128x128 win32 icon and a 32x32 linux xpm from Jason's logo. ------------------------------------------------------------------------ r1405 | ajapted | 2013-08-22 22:32:34 +1000 (Thu, 22 Aug 2013) | 2 lines TODO updated. ------------------------------------------------------------------------ r1404 | ajapted | 2013-08-22 21:48:25 +1000 (Thu, 22 Aug 2013) | 2 lines Version bump to 1.00, heading towards a release... ------------------------------------------------------------------------ r1403 | ajapted | 2013-08-22 21:42:42 +1000 (Thu, 22 Aug 2013) | 2 lines CHANGELOG: more tweakage. ------------------------------------------------------------------------ r1402 | ajapted | 2013-08-22 21:35:06 +1000 (Thu, 22 Aug 2013) | 6 lines 3D View: 1. implemented logic to determine coordinates for a highlighted wall and then create the lines to draw. 2. removed some old, non-working highlight code. ------------------------------------------------------------------------ r1401 | ajapted | 2013-08-22 16:30:35 +1000 (Thu, 22 Aug 2013) | 2 lines 3D View: more work on logic to highlight walls.... ------------------------------------------------------------------------ r1400 | ajapted | 2013-08-22 15:37:20 +1000 (Thu, 22 Aug 2013) | 3 lines 3D View: use current highlight info for offset adjustment and alignment commands (rather than perform a redundant query). ------------------------------------------------------------------------ r1399 | ajapted | 2013-08-22 14:40:03 +1000 (Thu, 22 Aug 2013) | 3 lines 3D View: added logic to keep track of a "highlighted" wotsit, and to only redraw the view when it changes. ------------------------------------------------------------------------ r1398 | ajapted | 2013-08-22 14:12:53 +1000 (Thu, 22 Aug 2013) | 4 lines 3D View: 1. began work on ability to highlight sidedef under the mouse 2. moved some code around ------------------------------------------------------------------------ r1397 | ajapted | 2013-08-21 22:50:28 +1000 (Wed, 21 Aug 2013) | 2 lines CHANGELOG : update and tweakage. ------------------------------------------------------------------------ r1396 | ajapted | 2013-08-21 22:49:36 +1000 (Wed, 21 Aug 2013) | 2 lines Texture alignment: added 'X', 'Y', 'Z' key bindings. ------------------------------------------------------------------------ r1395 | ajapted | 2013-08-21 22:29:00 +1000 (Wed, 21 Aug 2013) | 5 lines Texture alignment: 1. support for 'r' flag : align with wall "to the right" 2. PartialTexCmp() now compares 6 letters, not 4 3. tweaked scoring function for adjoiners ------------------------------------------------------------------------ r1394 | ajapted | 2013-08-21 19:02:58 +1000 (Wed, 21 Aug 2013) | 3 lines Texture alignment: dead code removal: (1) old DEU alignment stuff, and (2) my linedef-mode alignment logic. ------------------------------------------------------------------------ r1393 | ajapted | 2013-08-21 18:58:45 +1000 (Wed, 21 Aug 2013) | 3 lines Texture alignment: implemented PickAdjoinerPart(), tweaked some code, and removed some dead code. ------------------------------------------------------------------------ r1392 | ajapted | 2013-08-20 22:17:31 +1000 (Tue, 20 Aug 2013) | 4 lines Texture alignment: still banging away on this, e.g. pass the particular part (upper or lower) which the user clicked on to LineDefs_Align(), and wrote some logic for picking which adjoiner part of align with. ------------------------------------------------------------------------ r1391 | ajapted | 2013-08-20 15:20:57 +1000 (Tue, 20 Aug 2013) | 3 lines Texture alignment: fleshed out the logic for Y alignment, though it is not 100% finished yet.... ------------------------------------------------------------------------ r1390 | ajapted | 2013-08-17 16:22:13 +1000 (Sat, 17 Aug 2013) | 5 lines 3D_Align: more work on texture alignment: 1. the chosen adjoiner is always on the LEFT to the chosen sidedef 2. implemented DoAlignX() 3. started work on DoAlignY(), but it needs proper calculation ------------------------------------------------------------------------ r1389 | ajapted | 2013-08-17 15:51:07 +1000 (Sat, 17 Aug 2013) | 3 lines 3D_Align: for 'c' clear flag, properly handle different combinations of the 'x' and 'y' flags. ------------------------------------------------------------------------ r1388 | ajapted | 2013-08-17 14:55:19 +1000 (Sat, 17 Aug 2013) | 2 lines Texture alignment: implemented the 'c' (clear offsets) flag. ------------------------------------------------------------------------ r1387 | ajapted | 2013-08-17 14:37:07 +1000 (Sat, 17 Aug 2013) | 8 lines Texture aligning: began work on new method which is done in 3D Mode. This commit disables the 'LIN_Align' binding command, replacing it with '3D_Align' binding command (which does nothing yet). Updated the default bindings too, with 'x', 'y', 'z' and 'c' keys. The 'c' key will clear the offsets, and 'z' aligns both X and Y (I would preferred 'a' do both, but it is used for WASD movement). ------------------------------------------------------------------------ r1386 | ajapted | 2013-08-17 14:31:30 +1000 (Sat, 17 Aug 2013) | 2 lines Disabled the Adjoiner test code.... ------------------------------------------------------------------------ r1385 | ajapted | 2013-08-02 22:46:35 +1000 (Fri, 02 Aug 2013) | 2 lines minor update. ------------------------------------------------------------------------ r1384 | ajapted | 2013-08-02 21:23:52 +1000 (Fri, 02 Aug 2013) | 3 lines Texture alignment: try to pick the next sidedef a bit more intelligently, however I don't think this approach is really cutting the mustard.... ------------------------------------------------------------------------ r1383 | ajapted | 2013-08-02 19:54:42 +1000 (Fri, 02 Aug 2013) | 4 lines Texture alignment: 1. adjoiner scoring function: preference for same sided-ness of lines 2. added testing code -- highlight the best adjoiner of a line ------------------------------------------------------------------------ r1382 | ajapted | 2013-08-02 19:32:03 +1000 (Fri, 02 Aug 2013) | 4 lines Texture alignment: implemented scoring logic for adjoiners, firstly making sure that the sidedefs are actually next to each other, and secondly giving a score based on texture matching (etc). ------------------------------------------------------------------------ r1381 | ajapted | 2013-08-02 17:22:04 +1000 (Fri, 02 Aug 2013) | 3 lines Texture alignment: updated remaining code for 'side_on_a_line_t' typedef and access functions. ------------------------------------------------------------------------ r1380 | ajapted | 2013-08-02 14:42:51 +1000 (Fri, 02 Aug 2013) | 4 lines Texture alignment: introduced a 'side_on_a_line_t' typedef to simplify passing around the LINE+SIDE references. Partial work on the logic to determine the adjoiner for a side. ------------------------------------------------------------------------ r1379 | ajapted | 2013-08-02 14:18:53 +1000 (Fri, 02 Aug 2013) | 2 lines Basis : added LineDef::WhatSideDef() method. ------------------------------------------------------------------------ r1378 | ajapted | 2013-08-02 13:42:17 +1000 (Fri, 02 Aug 2013) | 3 lines Texture alignment: a bit more work, e.g. logic for handling the unpeg linedef flags, and added PartialTexCmp() function. ------------------------------------------------------------------------ r1377 | ajapted | 2013-08-02 12:33:09 +1000 (Fri, 02 Aug 2013) | 4 lines LineDef panel: reverted layout of sidedef textures to match previous versions (i.e. LOWER / RAIL / UPPER) -- although single-sided lines still use the LOWER spot for its texture. ------------------------------------------------------------------------ r1376 | ajapted | 2013-08-02 12:26:58 +1000 (Fri, 02 Aug 2013) | 5 lines Texture alignment: fleshed out more of the code, e.g. the logic for collecting which sidedefs to align, and logic to pick which sidedef to align next (ensuring we do an adjoiner _before_ that sidedef, if possible). ------------------------------------------------------------------------ r1375 | ajapted | 2013-08-01 22:54:29 +1000 (Thu, 01 Aug 2013) | 2 lines History.txt : added a preface about the different repositories. ------------------------------------------------------------------------ r1374 | ajapted | 2013-08-01 21:25:14 +1000 (Thu, 01 Aug 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1373 | ajapted | 2013-08-01 21:12:07 +1000 (Thu, 01 Aug 2013) | 2 lines TODO updated. ------------------------------------------------------------------------ r1372 | ajapted | 2013-08-01 21:10:45 +1000 (Thu, 01 Aug 2013) | 3 lines Renderer: got the query() method working, and use it to determine which linedef / sidedef to adjust the offsets on. ------------------------------------------------------------------------ r1371 | ajapted | 2013-08-01 17:16:49 +1000 (Thu, 01 Aug 2013) | 2 lines Renderer: use SIDE_LEFT / SIDE_RIGHT rather than 0/1. ------------------------------------------------------------------------ r1370 | ajapted | 2013-08-01 17:11:04 +1000 (Thu, 01 Aug 2013) | 2 lines Renderer: more work on query() method.... ------------------------------------------------------------------------ r1369 | ajapted | 2013-08-01 16:49:41 +1000 (Thu, 01 Aug 2013) | 4 lines Renderer: began work on a query() method which will determine what the mouse pointer is pointing at. It will perform a limited rendering to determine which wall / floor under the pointer. ------------------------------------------------------------------------ r1368 | ajapted | 2013-08-01 16:47:17 +1000 (Thu, 01 Aug 2013) | 2 lines Texture alignment: comment defining flags to LIN_Align(). ------------------------------------------------------------------------ r1367 | ajapted | 2013-08-01 15:33:29 +1000 (Thu, 01 Aug 2013) | 2 lines Preferences: tweaked layout in each panel for better consistency. ------------------------------------------------------------------------ r1366 | ajapted | 2013-08-01 13:55:28 +1000 (Thu, 01 Aug 2013) | 2 lines Improved normal grid drawing, darken colors when lines get close together. ------------------------------------------------------------------------ r1365 | ajapted | 2013-07-31 22:31:53 +1000 (Wed, 31 Jul 2013) | 4 lines Began work on texture alignment commands. This commit merely replaces the two LIN_AlignX/Y functions into a single one 'LIN_Align', with updated key bindings file. ------------------------------------------------------------------------ r1364 | ajapted | 2013-07-31 22:22:00 +1000 (Wed, 31 Jul 2013) | 2 lines Version bump to 0.99 ------------------------------------------------------------------------ r1363 | ajapted | 2013-07-31 21:07:37 +1000 (Wed, 31 Jul 2013) | 2 lines Preferences: fixed the 'render_lock_gravity' option. ------------------------------------------------------------------------ r1362 | ajapted | 2013-07-31 21:01:38 +1000 (Wed, 31 Jul 2013) | 2 lines Render3D_Wheel: added 'dx' parameter, use it to move left/right. ------------------------------------------------------------------------ r1361 | ajapted | 2013-07-31 20:40:43 +1000 (Wed, 31 Jul 2013) | 2 lines Removed obj_no_t typedef -- just use 'int' instead. ------------------------------------------------------------------------ r1360 | ajapted | 2013-07-31 20:12:29 +1000 (Wed, 31 Jul 2013) | 6 lines Improved highlight behavior of vertices when grid-snap is enabled. The previous method merely expanded the search range to find a vertex to highlight (get_cur_vertex) -- this made it too easy to accidently drag the wrong vertex. ------------------------------------------------------------------------ r1359 | ajapted | 2013-07-31 20:07:54 +1000 (Wed, 31 Jul 2013) | 2 lines Objid class: added a copy constructor. ------------------------------------------------------------------------ r1358 | ajapted | 2013-07-31 20:05:16 +1000 (Wed, 31 Jul 2013) | 2 lines Added Vertex_FindExact() utility function. ------------------------------------------------------------------------ r1357 | ajapted | 2013-07-31 16:03:40 +1000 (Wed, 31 Jul 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1356 | ajapted | 2013-07-31 16:01:16 +1000 (Wed, 31 Jul 2013) | 3 lines Implemented 'render_lock_gravity' config option, when enabled and gravity is ON then you cannot move up or down in the 3D view. ------------------------------------------------------------------------ r1355 | ajapted | 2013-07-31 14:34:17 +1000 (Wed, 31 Jul 2013) | 5 lines LineDef panel: the 'Length' widget is now an input box, and implemented ability to enter a new length value and change all selected linedefs. Doing this with all linedefs selected is a great way to wreck a map! ------------------------------------------------------------------------ r1354 | ajapted | 2013-07-31 14:22:11 +1000 (Wed, 31 Jul 2013) | 2 lines Check / linedefs: layout tweak. ------------------------------------------------------------------------ r1353 | ajapted | 2013-07-31 13:38:09 +1000 (Wed, 31 Jul 2013) | 2 lines Dead code removal : frob_things_flags(). ------------------------------------------------------------------------ r1352 | ajapted | 2013-07-31 13:36:16 +1000 (Wed, 31 Jul 2013) | 2 lines Dead code removal : frob_linedefs_flags() etc... ------------------------------------------------------------------------ r1351 | ajapted | 2013-07-31 13:13:01 +1000 (Wed, 31 Jul 2013) | 3 lines In vertex mode, display length of last three linedefs (typically ones which the user just added). ------------------------------------------------------------------------ r1350 | ajapted | 2013-07-30 22:23:42 +1000 (Tue, 30 Jul 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1349 | ajapted | 2013-07-30 22:21:24 +1000 (Tue, 30 Jul 2013) | 3 lines Better drawing of things (in THINGS mode) -- fill in their body with a darker version of their color. ------------------------------------------------------------------------ r1348 | ajapted | 2013-07-30 21:59:08 +1000 (Tue, 30 Jul 2013) | 2 lines Implemented mouse scaling using new 'edit.action' mechanism. ------------------------------------------------------------------------ r1347 | ajapted | 2013-07-30 16:58:21 +1000 (Tue, 30 Jul 2013) | 2 lines Use the edit.action mechanism for dragging and the selection box. ------------------------------------------------------------------------ r1346 | ajapted | 2013-07-30 14:45:22 +1000 (Tue, 30 Jul 2013) | 3 lines Implemented ClosestLine_CastAtAngle() utility function which finds the closest linedef to a point casting at an arbitrary angle. ------------------------------------------------------------------------ r1345 | ajapted | 2013-07-30 14:34:26 +1000 (Tue, 30 Jul 2013) | 2 lines Print a log message after unpacking sidedefs. ------------------------------------------------------------------------ r1344 | ajapted | 2013-07-30 14:33:53 +1000 (Tue, 30 Jul 2013) | 2 lines LoadLevel: reset editor state _before_ loading the user state. ------------------------------------------------------------------------ r1343 | ajapted | 2013-07-29 22:38:52 +1000 (Mon, 29 Jul 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1342 | ajapted | 2013-07-29 22:38:00 +1000 (Mon, 29 Jul 2013) | 4 lines Adjust offsets: properly compute 'dx_factor' and 'dy_factor' values based on the distance of the linedef to the camera. This makes it look like you are really dragging the texture around the wall. ------------------------------------------------------------------------ r1341 | ajapted | 2013-07-29 21:54:34 +1000 (Mon, 29 Jul 2013) | 2 lines Adjust offsets: the SHIFT key makes the adjustment finer (slower). ------------------------------------------------------------------------ r1340 | ajapted | 2013-07-29 21:47:59 +1000 (Mon, 29 Jul 2013) | 4 lines Removed unnecessary MarkChanges() and 'edit.RedrawMap = 1' statements. Also fixed recent bug of texture changes not redrawing the 3D view. ------------------------------------------------------------------------ r1339 | ajapted | 2013-07-29 21:35:40 +1000 (Mon, 29 Jul 2013) | 2 lines Dead code removal. ------------------------------------------------------------------------ r1338 | ajapted | 2013-07-29 21:29:02 +1000 (Mon, 29 Jul 2013) | 2 lines Added GoToErrors() convenience function. ------------------------------------------------------------------------ r1337 | ajapted | 2013-07-29 21:18:08 +1000 (Mon, 29 Jul 2013) | 2 lines Simplified handling of 'MadeChanges' global var. ------------------------------------------------------------------------ r1336 | ajapted | 2013-07-29 15:58:13 +1000 (Mon, 29 Jul 2013) | 2 lines Disabled '!' prefix in the window title -- was not useful after all. ------------------------------------------------------------------------ r1335 | ajapted | 2013-07-29 12:28:46 +1000 (Mon, 29 Jul 2013) | 4 lines Implemented SideDefs_NormalizeMiddles(), which is used after level load and ensures that one-sided linedefs do not have an "Upper" or "Rail" texture (as shown by the LineDef panel). ------------------------------------------------------------------------ r1334 | ajapted | 2013-07-28 20:05:32 +1000 (Sun, 28 Jul 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1333 | ajapted | 2013-07-28 20:01:41 +1000 (Sun, 28 Jul 2013) | 4 lines After loading a map, reset various editor state, especially clearing the selection and highlight (prevent a possible crash), and update the map totals (# of linedefs, etc) for the side panel. ------------------------------------------------------------------------ r1332 | ajapted | 2013-07-28 19:44:00 +1000 (Sun, 28 Jul 2013) | 2 lines CHANGELOG: added the new sidedef layout. ------------------------------------------------------------------------ r1331 | ajapted | 2013-07-28 19:43:25 +1000 (Sun, 28 Jul 2013) | 4 lines Adjust offsets: force mouse deltas to be either vertical or horizontal, which makes it easier to make large horizontal adjustments without it going up or down, and vice versa. ------------------------------------------------------------------------ r1330 | ajapted | 2013-07-28 19:27:02 +1000 (Sun, 28 Jul 2013) | 11 lines LideDef panel: changed layout of textures in each SideDef section. The default order is now LOWER / UPPER / RAIL. Also, single-sided linedefs show the texture in the "LOWER" position, since there is no longer a spot for a "middle" texture. The main benefit of this is when multiple linedefs are selected which is a mix of one-sided and two-sided lines, the user can safely change the "LOWER" (or LOWER + UPPER) on all the linedefs without ending up with unwanted railing textures. ------------------------------------------------------------------------ r1329 | ajapted | 2013-07-28 19:17:59 +1000 (Sun, 28 Jul 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1328 | ajapted | 2013-07-28 19:00:52 +1000 (Sun, 28 Jul 2013) | 3 lines Automatically unpack sidedefs when loading a map, since the previous confirmation dialog was probably more of a nuisance than a help. ------------------------------------------------------------------------ r1327 | ajapted | 2013-07-28 18:45:49 +1000 (Sun, 28 Jul 2013) | 3 lines Basis: added BA_Abort() function which discards the current group of operations and (optionally) undoes the changes since BA_Begin(). ------------------------------------------------------------------------ r1326 | ajapted | 2013-07-28 18:10:50 +1000 (Sun, 28 Jul 2013) | 3 lines 3D View: changing the aspect ratio preference setting did not update the rendered view (unless user changed window size) -- fixed. ------------------------------------------------------------------------ r1325 | ajapted | 2013-07-28 15:43:51 +1000 (Sun, 28 Jul 2013) | 3 lines Checks: updated missing texture detection to count "" (empty string) as a missing texture. ------------------------------------------------------------------------ r1324 | ajapted | 2013-07-28 15:27:49 +1000 (Sun, 28 Jul 2013) | 2 lines Dead code removal : UI_SideDef::SetTexture() method. ------------------------------------------------------------------------ r1323 | ajapted | 2013-07-28 14:12:49 +1000 (Sun, 28 Jul 2013) | 3 lines Preferences: implemented setting for Aspect ratio in 3D view, supporting a "CUSTOM" choice allowing the user to enter arbitrary values. ------------------------------------------------------------------------ r1322 | ajapted | 2013-07-28 13:58:19 +1000 (Sun, 28 Jul 2013) | 3 lines 3D View: added 'render_aspect_ratio' config variable, and use it when rendering a scene. No preference setting yet.... ------------------------------------------------------------------------ r1321 | ajapted | 2013-07-28 13:56:49 +1000 (Sun, 28 Jul 2013) | 2 lines Fixed recent bug of highlighting map stuff when 3D view is active. ------------------------------------------------------------------------ r1320 | ajapted | 2013-07-27 21:06:44 +1000 (Sat, 27 Jul 2013) | 3 lines Render3D: moved code around, namely UpdateScreen() method of 'view' and draw(), BlitLores() and BlitHires() methods in UI_Render3D class. ------------------------------------------------------------------------ r1319 | ajapted | 2013-07-27 17:41:55 +1000 (Sat, 27 Jul 2013) | 2 lines Adjusting offsets: apply the offsets when mouse button is released. ------------------------------------------------------------------------ r1318 | ajapted | 2013-07-27 17:29:21 +1000 (Sat, 27 Jul 2013) | 6 lines More work on adjusting X/Y offsets via the mouse. Implemented the logic to save/change/restore the current offsets in the renderer (the real change only occurs when the user releases the button -- NYI). It does NOT pick the linedef/sidedef properly yet.... ------------------------------------------------------------------------ r1317 | ajapted | 2013-07-26 22:23:11 +1000 (Fri, 26 Jul 2013) | 4 lines 1. added Editor_ClearAction() and Editor_SetAction() functions 2. re-implemented RMB map scrolling using the action system 3. began implementation of sidedef adjustment via MMB ------------------------------------------------------------------------ r1316 | ajapted | 2013-07-26 11:08:17 +1000 (Fri, 26 Jul 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1315 | ajapted | 2013-07-26 11:07:54 +1000 (Fri, 26 Jul 2013) | 2 lines CHANGELOG : yet another rejig. ------------------------------------------------------------------------ r1314 | ajapted | 2013-07-26 11:01:26 +1000 (Fri, 26 Jul 2013) | 4 lines Preferences: disabled the "maximize on startup" option. It is planned to replace it in a future release with code to remember the window position and maximized state. ------------------------------------------------------------------------ r1313 | ajapted | 2013-07-25 20:44:14 +1000 (Thu, 25 Jul 2013) | 3 lines Menu: rewrote code to populate the "Recent Files" sub-menu, using same basic method as for "Given Files" (recreating the Fl_Menu_Item array). ------------------------------------------------------------------------ r1312 | ajapted | 2013-07-25 20:30:26 +1000 (Thu, 25 Jul 2013) | 6 lines Menu: worked on reimplementing the way the "Given Files" and "Recent Files" sub-menus are populated, since previous way did not work under MacOS X. Instead of fiddling with the menu bar _after_ creating it, we fiddle with arrays of raw Fl_Menu_Items _before_ creating it. ------------------------------------------------------------------------ r1311 | ajapted | 2013-07-25 18:52:38 +1000 (Thu, 25 Jul 2013) | 12 lines 1. removed unused 'move_speed', 'extra_zoom' fields from Editor_State_t 2. added 'edit.action' field and a set of ACT_XXXXX enumerated values which will bring some sanity to the handling of temporal actions like dragging objects, drawing a sel box, scrolling the map, etc... 3. handle the META-fier command using the 'edit.action' mechanism 4. fixed bug with META-fying logic where an unrecogized META-fied key would be sent on to other widgets, even coming back to be handled as a normal key instead of being ignored. ------------------------------------------------------------------------ r1310 | ajapted | 2013-07-25 13:53:12 +1000 (Thu, 25 Jul 2013) | 2 lines M_ParseEurekaLump: use DLG_Confirm() instead of fl_choice. ------------------------------------------------------------------------ r1309 | ajapted | 2013-07-25 13:52:17 +1000 (Thu, 25 Jul 2013) | 3 lines Don't quit the program when the user cancels loading a wad during parsing of the EUREKA lump. ------------------------------------------------------------------------ r1308 | ajapted | 2013-07-25 13:37:56 +1000 (Thu, 25 Jul 2013) | 5 lines Preferences / Keys: renamed last button to "Reset Defaults" and _always_ show the confirmation dialog, since it erases ALL the user's changes. Code-wise: use DLG_Confirm() instead of fl_choice() there. ------------------------------------------------------------------------ r1307 | ajapted | 2013-07-25 13:18:51 +1000 (Thu, 25 Jul 2013) | 6 lines Fixed "venetian blind" issue when drawing large dots for the grid. The real problem is with FLTK and how it clips non-filled rectangles. To workaround the FLTK bug, use filled rectangles instead -- it might even be faster. ------------------------------------------------------------------------ r1306 | ajapted | 2013-07-25 13:08:23 +1000 (Thu, 25 Jul 2013) | 2 lines Edit / Move objects: implemented 'Z' delta for sectors. ------------------------------------------------------------------------ r1305 | ajapted | 2013-07-24 23:05:57 +1000 (Wed, 24 Jul 2013) | 2 lines Tweaked the single-line title + copyright message. ------------------------------------------------------------------------ r1304 | ajapted | 2013-07-24 22:35:40 +1000 (Wed, 24 Jul 2013) | 3 lines Dead code removal : MakeDoorFromSector and MakeLiftFromSector. (that functionality may return one day, in the form of a script). ------------------------------------------------------------------------ r1303 | ajapted | 2013-07-24 22:31:04 +1000 (Wed, 24 Jul 2013) | 2 lines Dead code removal : bv_vertices_of_xxx and linedefs_of_sector(s). ------------------------------------------------------------------------ r1302 | ajapted | 2013-07-24 22:27:18 +1000 (Wed, 24 Jul 2013) | 2 lines Dead code removal : Superimposed_ld class. ------------------------------------------------------------------------ r1301 | printz | 2013-07-24 19:22:04 +1000 (Wed, 24 Jul 2013) | 4 lines osx: * Updated Xcode project to Makefile's new specifications * Updated the info plist to the current version * Updated the icns file to the new logo. File is a bit too large now, especially after I used a free tool called "Retina Icon Binder". Thus the total package size is even bigger than the previous OSX Eureka release, even if now I merely linked FLTK statically. Might be the redundant lower-scale icons adding to the size. I need a better ICNS tool that can safely delete the smaller icons. ------------------------------------------------------------------------ r1300 | ajapted | 2013-07-23 19:32:51 +1000 (Tue, 23 Jul 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1299 | ajapted | 2013-07-23 19:22:14 +1000 (Tue, 23 Jul 2013) | 2 lines M_WriteEurekaLump : it handles the BeginWrite/EndWrite itself now. ------------------------------------------------------------------------ r1298 | ajapted | 2013-07-23 19:21:18 +1000 (Tue, 23 Jul 2013) | 3 lines Wad code: fixed potential issue with 'insert_point' handling which was probably responsible for the rare level-lumps-in-wrong-order problem. ------------------------------------------------------------------------ r1297 | ajapted | 2013-07-23 16:20:47 +1000 (Tue, 23 Jul 2013) | 3 lines File / Test map: if changes have been made, ask user if they want to save the map and build the nodes. ------------------------------------------------------------------------ r1296 | ajapted | 2013-07-23 16:09:50 +1000 (Tue, 23 Jul 2013) | 2 lines Tweaks. ------------------------------------------------------------------------ r1295 | ajapted | 2013-07-23 16:06:33 +1000 (Tue, 23 Jul 2013) | 2 lines FatalError: replace single newlines with spaces for DLG_ShowError(). ------------------------------------------------------------------------ r1294 | ajapted | 2013-07-23 14:59:54 +1000 (Tue, 23 Jul 2013) | 5 lines Dialogs: added keyboard shortcuts (via '&') for all buttons except Cancel. We don't do Cancel since "Create" button (from File / New Map) would conflict, plus the ESCAPE key already serves that function. ------------------------------------------------------------------------ r1293 | ajapted | 2013-07-23 14:44:30 +1000 (Tue, 23 Jul 2013) | 3 lines Wad code: no need to LogPrintf() updates to the master directory or when reading/writing a directory from a wad -- they are now debug messages. ------------------------------------------------------------------------ r1292 | ajapted | 2013-07-23 14:43:03 +1000 (Tue, 23 Jul 2013) | 3 lines File / Build nodes: better handle the case when there is no current pwad, but the user has made changes (e.g. an edited IWAD map, or a fresh map). ------------------------------------------------------------------------ r1291 | ajapted | 2013-07-23 14:35:28 +1000 (Tue, 23 Jul 2013) | 3 lines Dialogs: use UI_Escapable_Window so that dialogs can be dismissed with the ESCAPE key. ------------------------------------------------------------------------ r1290 | ajapted | 2013-07-23 14:31:56 +1000 (Tue, 23 Jul 2013) | 4 lines File / Build nodes: when the map has unsaved changes, we now ask the user whether they want to save the map and then build the nodes. (Previously it was just a notification dialog.) ------------------------------------------------------------------------ r1289 | ajapted | 2013-07-23 14:28:15 +1000 (Tue, 23 Jul 2013) | 10 lines Fixed bug causing a FatalError() when editing a pwad, creating a new map which is fresh (does not replace any existing map), and then attempting to build the nodes. Since the new map was not saved, Eureka was unable to re-load the map from the node-enhanced wad. Hence creating a new map (CTRL-N) always sets the "Made Changes" flag. This commit also makes CMD_SaveMap() and CMD_ExportMap() return a bool indicating success or failure. ------------------------------------------------------------------------ r1288 | ajapted | 2013-07-23 14:01:08 +1000 (Tue, 23 Jul 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1287 | ajapted | 2013-07-23 13:55:44 +1000 (Tue, 23 Jul 2013) | 3 lines Show an '!' symbol in the window title when a new map would replace an existing map in the current wad. ------------------------------------------------------------------------ r1286 | ajapted | 2013-07-23 13:41:28 +1000 (Tue, 23 Jul 2013) | 3 lines File / Save: if a new map would replace (overwrite) an existing map, give the user a third option: "Export" the map. ------------------------------------------------------------------------ r1285 | ajapted | 2013-07-22 22:20:54 +1000 (Mon, 22 Jul 2013) | 3 lines Improved look of Preferences and Log-viewer windows when not using the "Bright" color scheme -- the background at the bottom was too dark. ------------------------------------------------------------------------ r1284 | ajapted | 2013-07-22 21:38:47 +1000 (Mon, 22 Jul 2013) | 3 lines Dialogs: copy the fl_ask (etc) behavior and make the window's position dependent on where the mouse pointer is. ------------------------------------------------------------------------ r1283 | ajapted | 2013-07-22 21:15:40 +1000 (Mon, 22 Jul 2013) | 5 lines Dialogs: 1. support the 'icon_type' to make different colored icons 2. ensure the left-most button gets the focus 3. fixed navigation problem (LEFT and RIGHT cursor keys) ------------------------------------------------------------------------ r1282 | ajapted | 2013-07-22 20:54:20 +1000 (Mon, 22 Jul 2013) | 4 lines Dialogs: worked to parse and create the buttons for DLG_Confirm(), and properly handle the var-args for DLG_Notify() and DLG_Confirm(), plus a few other tweaks. ------------------------------------------------------------------------ r1281 | ajapted | 2013-07-22 20:19:31 +1000 (Mon, 22 Jul 2013) | 5 lines 1. Thing checker now detects if too many DM starts are present 2. moved the DOOM_PLAYER_HEIGHT and DOOM_MIN/MAX_DEATHMATCH_STARTS to be fields of the game_info_t structure. ------------------------------------------------------------------------ r1280 | ajapted | 2013-07-22 20:05:23 +1000 (Mon, 22 Jul 2013) | 3 lines Removed unused confirm_t type, and the OPT_CONFIRM stuff in the config loading and saving code. ------------------------------------------------------------------------ r1279 | ajapted | 2013-07-22 20:01:49 +1000 (Mon, 22 Jul 2013) | 2 lines Tidied up main.h ------------------------------------------------------------------------ r1278 | ajapted | 2013-07-22 16:40:24 +1000 (Mon, 22 Jul 2013) | 2 lines Removed code file: m_dialog.cc ------------------------------------------------------------------------ r1277 | ajapted | 2013-07-22 16:36:37 +1000 (Mon, 22 Jul 2013) | 5 lines Dialogs: renamed Confirm() --> DLG_Confirm(), and changed the parameters to take button names and use var-arg message. Note that the new DLG_Confirm() is not implemented yet. ------------------------------------------------------------------------ r1276 | ajapted | 2013-07-22 16:12:32 +1000 (Mon, 22 Jul 2013) | 2 lines Removed header files: m_dialog.h and ui_dialog.h ------------------------------------------------------------------------ r1275 | ajapted | 2013-07-22 16:05:23 +1000 (Mon, 22 Jul 2013) | 3 lines Began work on better dialog boxes. This commit mainly renames 'Notify' function to 'DLG_Notify' and simplifies its parameters. ------------------------------------------------------------------------ r1274 | ajapted | 2013-07-22 15:17:27 +1000 (Mon, 22 Jul 2013) | 2 lines Dead code removal : NotImplemented() and Confirm2() functions. ------------------------------------------------------------------------ r1273 | ajapted | 2013-07-21 16:02:13 +1000 (Sun, 21 Jul 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1272 | ajapted | 2013-07-21 16:01:15 +1000 (Sun, 21 Jul 2013) | 2 lines Improved scroll-bar colors. ------------------------------------------------------------------------ r1271 | ajapted | 2013-07-21 14:42:44 +1000 (Sun, 21 Jul 2013) | 2 lines Check / textures: allow "-" on uppers when between two sky ceilings. ------------------------------------------------------------------------ r1270 | ajapted | 2013-07-21 14:29:51 +1000 (Sun, 21 Jul 2013) | 2 lines CHANGELOG: minor rejig. ------------------------------------------------------------------------ r1269 | ajapted | 2013-07-21 14:23:17 +1000 (Sun, 21 Jul 2013) | 2 lines Check / textures: wrote logic to detect and fix missing textures. ------------------------------------------------------------------------ r1268 | ajapted | 2013-07-21 14:00:38 +1000 (Sun, 21 Jul 2013) | 3 lines Check / things: fixed "Remove" button for things in void to not close the thing check dialog. ------------------------------------------------------------------------ r1267 | ajapted | 2013-07-21 13:59:29 +1000 (Sun, 21 Jul 2013) | 3 lines Check / textures: implemented "Fix" buttons for unknown textures and unknown flats. ------------------------------------------------------------------------ r1266 | ajapted | 2013-07-21 13:43:59 +1000 (Sun, 21 Jul 2013) | 2 lines HERETIC: changed default floor to FLOOR00 (was FLOOR01). ------------------------------------------------------------------------ r1265 | ajapted | 2013-07-21 13:07:42 +1000 (Sun, 21 Jul 2013) | 2 lines Ports / BOOM: added 'v' flag to point push/pull things. ------------------------------------------------------------------------ r1264 | ajapted | 2013-07-21 13:05:32 +1000 (Sun, 21 Jul 2013) | 3 lines Check / things: improved VOID testing to ignore things with the 'v' flag (such as Heretic's sound emitters). ------------------------------------------------------------------------ r1263 | ajapted | 2013-07-21 13:04:31 +1000 (Sun, 21 Jul 2013) | 3 lines Game defs: implemented new 'v' thing flag for things which may exist in the VOID, and use this flag for Heretic's sound emitters. ------------------------------------------------------------------------ r1262 | ajapted | 2013-07-21 12:39:40 +1000 (Sun, 21 Jul 2013) | 5 lines Check / things: 1. implemented 'Remove' button for unknown things 2. more accurate testing for "in the void" things 3. added 'Remove' button for things in the void ------------------------------------------------------------------------ r1261 | ajapted | 2013-07-21 12:20:05 +1000 (Sun, 21 Jul 2013) | 2 lines foo ------------------------------------------------------------------------ r1260 | ajapted | 2013-07-21 12:13:33 +1000 (Sun, 21 Jul 2013) | 6 lines Check / things: 1. implemented "Log" button for unknown things, which dumps all the unknown id numbers to the log file (and opens the log viewer) 2. moved the unknown thing results to the top. ------------------------------------------------------------------------ r1259 | ajapted | 2013-07-20 23:22:20 +1000 (Sat, 20 Jul 2013) | 4 lines Check / textures: implemented a "Log" button for unknown flats and textures, which prints the names (and usage count) into the log file, then opens up the log viewer. ------------------------------------------------------------------------ r1258 | ajapted | 2013-07-20 22:59:48 +1000 (Sat, 20 Jul 2013) | 3 lines Log viewer: have a function to open it, which now jumps to the end (i.e. ensures the last line is visible). ------------------------------------------------------------------------ r1257 | ajapted | 2013-07-20 22:25:26 +1000 (Sat, 20 Jul 2013) | 3 lines Check / textures: implemented detecting unknown flats and textures, and ability to show the sectors / lines (in the ERROR mode). ------------------------------------------------------------------------ r1256 | ajapted | 2013-07-20 22:01:19 +1000 (Sat, 20 Jul 2013) | 2 lines Added W_TextureExists() and W_FlatExists() functions. ------------------------------------------------------------------------ r1255 | ajapted | 2013-07-20 21:49:28 +1000 (Sat, 20 Jul 2013) | 2 lines Checks: began work on Texture checking functions.... ------------------------------------------------------------------------ r1254 | ajapted | 2013-07-20 21:47:14 +1000 (Sat, 20 Jul 2013) | 3 lines Check / things: made unknown things a serious error, since vanilla DOOM will produce a fatal error for them. ------------------------------------------------------------------------ r1253 | ajapted | 2013-07-20 17:51:25 +1000 (Sat, 20 Jul 2013) | 2 lines TODO: updated. ------------------------------------------------------------------------ r1252 | ajapted | 2013-07-20 17:38:10 +1000 (Sat, 20 Jul 2013) | 6 lines Clear the ERROR mode when necessary, such as when changing the edit mode or trying to select a new object, or certain operations that leave a certain object selected. For the Quantize command, we now _set_ the ERROR mode. ------------------------------------------------------------------------ r1251 | ajapted | 2013-07-20 14:33:28 +1000 (Sat, 20 Jul 2013) | 3 lines Preferences: reserve an area in 'Other' tab for "3D Preview Options". Nothing is there yet.... ------------------------------------------------------------------------ r1250 | ajapted | 2013-07-20 14:24:50 +1000 (Sat, 20 Jul 2013) | 4 lines Fixed assertion when the 'FlipMap' command was used and the current level name cannot be found in the current wad (e.g. the IWAD was changed from DOOM 2 --> DOOM 1). ------------------------------------------------------------------------ r1249 | ajapted | 2013-07-20 14:17:15 +1000 (Sat, 20 Jul 2013) | 2 lines DOOM 1: categorized the DOOM1-specific textures. ------------------------------------------------------------------------ r1248 | ajapted | 2013-07-20 14:06:27 +1000 (Sat, 20 Jul 2013) | 2 lines DOOM: moved the DOOM2-only textures out of common/doom_tex.ugh ------------------------------------------------------------------------ r1247 | ajapted | 2013-07-20 13:41:59 +1000 (Sat, 20 Jul 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1246 | ajapted | 2013-07-20 13:31:55 +1000 (Sat, 20 Jul 2013) | 4 lines Map view: better drawing of selected sectors, draw knobbly lines where the knobs point inside the sectors, and skip lines that exist between two selected sectors. ------------------------------------------------------------------------ r1245 | ajapted | 2013-07-20 11:36:26 +1000 (Sat, 20 Jul 2013) | 5 lines Map view: 1. smaller surrounding box for highlighted things 2. improved arrow drawing for large highlighted things 3. improved arrow drawing for highlighted linedefs ------------------------------------------------------------------------ r1244 | ajapted | 2013-07-19 20:36:21 +1000 (Fri, 19 Jul 2013) | 2 lines HERETIC: apply same fix for exit-level linetypes. ------------------------------------------------------------------------ r1243 | ajapted | 2013-07-19 20:28:36 +1000 (Fri, 19 Jul 2013) | 3 lines DOOM: updated exit specials to use "s1" instead of "S1", to prevent those lines showing up in the "linedefs missing a needed tag" check. ------------------------------------------------------------------------ r1242 | ajapted | 2013-07-19 20:24:54 +1000 (Fri, 19 Jul 2013) | 4 lines Check / tags: added new test for linedefs missing a needed tag. Needs some game definition changes to work properly, especially the exit level types to use "s1" instead of "S1". ------------------------------------------------------------------------ r1241 | ajapted | 2013-07-19 20:00:25 +1000 (Fri, 19 Jul 2013) | 3 lines Check / tags: finished GUI parts of detecting unmatched tagged stuff. Also moved the Lowest/Highest values to occupy a single line. ------------------------------------------------------------------------ r1240 | ajapted | 2013-07-19 19:15:11 +1000 (Fri, 19 Jul 2013) | 3 lines Check / tags: worked on detecting sectors with no tagged linedef and vice versa. This commit has the detection logic. ------------------------------------------------------------------------ r1239 | ajapted | 2013-07-19 15:59:19 +1000 (Fri, 19 Jul 2013) | 2 lines Check / tags: fixed the "all_mode" handling. ------------------------------------------------------------------------ r1238 | ajapted | 2013-07-19 15:56:48 +1000 (Fri, 19 Jul 2013) | 2 lines Checks.txt : a few more tag-testing ideas... ------------------------------------------------------------------------ r1237 | ajapted | 2013-07-19 15:52:49 +1000 (Fri, 19 Jul 2013) | 3 lines Check / things: implemented ThingStuckInWall() -- finishing the support for stuck thing detection. ------------------------------------------------------------------------ r1236 | ajapted | 2013-07-19 15:51:55 +1000 (Fri, 19 Jul 2013) | 2 lines Renamed LineCrossesBox() --> LineTouchesBox(), and removed some unused code. ------------------------------------------------------------------------ r1235 | ajapted | 2013-07-19 14:29:09 +1000 (Fri, 19 Jul 2013) | 5 lines Check / things: for monsters, allow a small (8 unit) leeway to overlap a solid thing before considering it as stuck. That's because the monster movement code allows a monster to move a certain distance from its starting position. ------------------------------------------------------------------------ r1234 | ajapted | 2013-07-19 13:53:02 +1000 (Fri, 19 Jul 2013) | 2 lines Check / things: implemented detecting actors stuck in solid things. ------------------------------------------------------------------------ r1233 | ajapted | 2013-07-19 13:09:33 +1000 (Fri, 19 Jul 2013) | 3 lines Check / things: began work on detecting players and monsters stuck in walls or other things. ------------------------------------------------------------------------ r1232 | ajapted | 2013-07-19 11:56:33 +1000 (Fri, 19 Jul 2013) | 3 lines Checks: removed the previous checking code -- it was not used as-is, but some of that code or algorithms were used in the new functions. ------------------------------------------------------------------------ r1231 | ajapted | 2013-07-19 11:53:40 +1000 (Fri, 19 Jul 2013) | 2 lines Checks: just moved code around. ------------------------------------------------------------------------ r1230 | ajapted | 2013-07-19 11:37:36 +1000 (Fri, 19 Jul 2013) | 2 lines Port definitions: updated with 'n' (non-blocking) thing flag. ------------------------------------------------------------------------ r1229 | ajapted | 2013-07-19 11:35:31 +1000 (Fri, 19 Jul 2013) | 2 lines HACX: updated thing defs with new 'n' (non-blocking) flag. ------------------------------------------------------------------------ r1228 | ajapted | 2013-07-19 11:31:05 +1000 (Fri, 19 Jul 2013) | 3 lines HERETIC: updated things, added missing 'l' (lit) and 'c' (ceiling) flags as well as the new 'n' (non-blocking) flag. ------------------------------------------------------------------------ r1227 | ajapted | 2013-07-18 22:47:55 +1000 (Thu, 18 Jul 2013) | 3 lines Game defs: updated DOOM 1 and 2 definitions to add the 'n' non-solid flag to all the things which need it. ------------------------------------------------------------------------ r1226 | ajapted | 2013-07-18 22:45:42 +1000 (Thu, 18 Jul 2013) | 3 lines Game defs: support a new thing flag 'n' : Non-Solid. This will be used later for detecting things stuck in walls or other things. ------------------------------------------------------------------------ r1225 | ajapted | 2013-07-18 22:19:24 +1000 (Thu, 18 Jul 2013) | 2 lines TODO and CHANGELOG update. ------------------------------------------------------------------------ r1224 | ajapted | 2013-07-18 22:15:06 +1000 (Thu, 18 Jul 2013) | 3 lines Log viewer: finished the ability to "Save" the full logs to a file. The grunt-work is done by new LogSaveTo(FILE *) function. ------------------------------------------------------------------------ r1223 | ajapted | 2013-07-18 21:51:41 +1000 (Thu, 18 Jul 2013) | 5 lines Log viewer: 1. implemented copying the selected lines to the clipboard 2. made CTRL-C be a shortcut for the "Copy" button 3. renamed the "OK" button to "Close" ------------------------------------------------------------------------ r1222 | ajapted | 2013-07-18 21:01:04 +1000 (Thu, 18 Jul 2013) | 3 lines Opposite finder: when building the binary trees, skip purely horizontal lines in the Y tree, similarly purely vertical lines in the X tree. ------------------------------------------------------------------------ r1221 | ajapted | 2013-07-18 20:45:30 +1000 (Thu, 18 Jul 2013) | 3 lines Log viewer: added logic to activate the "Copy" button when the user has selected two or more lines -- otherwise it stays deactivated. ------------------------------------------------------------------------ r1220 | ajapted | 2013-07-18 19:57:30 +1000 (Thu, 18 Jul 2013) | 6 lines Log viewer: 1. partial work to implement "Save" button 2. use a Fl_Multi_Browser, so user can select areas to copy/save 3. added a "Copy" button to bottom area (not yet functional) 4. in bottom area, place resizable gap between "OK" and other buttons ------------------------------------------------------------------------ r1219 | ajapted | 2013-07-18 19:08:16 +1000 (Thu, 18 Jul 2013) | 2 lines Log viewer: implemented the "OK" button (to close) and "Clear" button. ------------------------------------------------------------------------ r1218 | ajapted | 2013-07-18 18:55:33 +1000 (Thu, 18 Jul 2013) | 3 lines Log viewer: began work improving it, with a button area at the bottom which will contain three buttons: "Save", "Clear" and "OK". ------------------------------------------------------------------------ r1217 | ajapted | 2013-07-18 17:21:19 +1000 (Thu, 18 Jul 2013) | 3 lines Opposite finder: fixed some bugs, and actually use it to speed up the sector mismatch test. The new logic is roughly 4-5 times faster. ------------------------------------------------------------------------ r1216 | ajapted | 2013-07-18 16:36:24 +1000 (Thu, 18 Jul 2013) | 2 lines Opposite finder: implemented the binary-tree testing logic. ------------------------------------------------------------------------ r1215 | ajapted | 2013-07-18 16:20:35 +1000 (Thu, 18 Jul 2013) | 3 lines Opposite finder: in fastopp nodes, store linedefs as integers rather than pointers. ------------------------------------------------------------------------ r1214 | ajapted | 2013-07-18 16:16:09 +1000 (Thu, 18 Jul 2013) | 3 lines Opposite finder: moved state into a 'opp_test_state_t' structure, and also moved the code to handle a single linedef there. ------------------------------------------------------------------------ r1213 | ajapted | 2013-07-18 15:58:10 +1000 (Thu, 18 Jul 2013) | 7 lines Began work on a faster version of OppositeLineDef() and OppositeSector(), mainly for the sector mismatch test. So far: written the logic for creating a quadtree-like structure and storing linedefs in it. Unlike a quadtree, this is one-dimensional and there are two of them (for X and Y dimensions). ------------------------------------------------------------------------ r1212 | ajapted | 2013-07-18 15:20:36 +1000 (Thu, 18 Jul 2013) | 3 lines Checks / linedefs: added test for linedefs with wrong 2S (TwoSided) flag, as well as actions to show and fix them. ------------------------------------------------------------------------ r1211 | ajapted | 2013-07-18 15:10:49 +1000 (Thu, 18 Jul 2013) | 3 lines Checks / linedefs: implemented test for one-sided lines without blocking flag, and actions to show and fix them. ------------------------------------------------------------------------ r1210 | ajapted | 2013-07-18 13:46:32 +1000 (Thu, 18 Jul 2013) | 3 lines Checks: use UI_Check_base as the base for remaining dialog classes, namely UI_Check_Sectors, UI_Check_Things and UI_Check_Tags. ------------------------------------------------------------------------ r1209 | ajapted | 2013-07-16 22:30:09 +1000 (Tue, 16 Jul 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1208 | ajapted | 2013-07-16 22:29:18 +1000 (Tue, 16 Jul 2013) | 3 lines Checks: converted UI_Check_Vertices and UI_Check_LineDefs classes to use the new base class. ------------------------------------------------------------------------ r1207 | ajapted | 2013-07-16 22:19:21 +1000 (Tue, 16 Jul 2013) | 3 lines Checks: created a base class for all the dialogs : UI_Check_base. Nothing uses it yet.... ------------------------------------------------------------------------ r1206 | ajapted | 2013-07-16 21:16:28 +1000 (Tue, 16 Jul 2013) | 7 lines Use UI_Escapable_Window for most other dialogs with a "Cancel" button. Not used for UI_NodeDialog since it has special behavior (first ESC press cancels the build but keeps the window open). Not used with UI_Check_XXX yet, pending a superclass for them. ------------------------------------------------------------------------ r1205 | ajapted | 2013-07-16 21:02:26 +1000 (Tue, 16 Jul 2013) | 3 lines About dialog: subclass from UI_Escapable_Window, simplifying the code e.g. no longer need our own handle() method. ------------------------------------------------------------------------ r1204 | ajapted | 2013-07-16 21:01:08 +1000 (Tue, 16 Jul 2013) | 2 lines Added UI_Escapable_Window class -- a subclass of Fl_Double_Window. ------------------------------------------------------------------------ r1203 | ajapted | 2013-07-16 20:38:33 +1000 (Tue, 16 Jul 2013) | 2 lines Code: re-whitespaced ui_about.cc/h to be consistent. ------------------------------------------------------------------------ r1202 | ajapted | 2013-07-16 20:11:27 +1000 (Tue, 16 Jul 2013) | 2 lines misc/Checks.txt : more twiddling... ------------------------------------------------------------------------ r1201 | ajapted | 2013-07-16 20:10:56 +1000 (Tue, 16 Jul 2013) | 2 lines Made some Beep() error messages more consistent. ------------------------------------------------------------------------ r1200 | ajapted | 2013-07-16 19:52:43 +1000 (Tue, 16 Jul 2013) | 2 lines Checks: moved code around, namely TAG stuff --> e_checks2.cc ------------------------------------------------------------------------ r1199 | ajapted | 2013-07-16 19:49:37 +1000 (Tue, 16 Jul 2013) | 10 lines Checks: 1. rearranged 'Check' menu, added 'Major stuff' item which does all the checks but ignores minor problems. 2. made the 'Check / ALL' menu item perform the Texture and Tags tests too (not just the Vert/Lin/Sec/Thing tests). 3. Code-wise, pass 'min_severity' to each CHECK_xxx function, instead of 'all_mode' boolean. ------------------------------------------------------------------------ r1198 | ajapted | 2013-07-16 19:06:16 +1000 (Tue, 16 Jul 2013) | 2 lines Check / linedefs: implemented test for criss-crossing linedefs. ------------------------------------------------------------------------ r1197 | ajapted | 2013-07-16 18:08:59 +1000 (Tue, 16 Jul 2013) | 2 lines Check / linedefs: moved code around, added linedef_minx_CMP_pred. ------------------------------------------------------------------------ r1196 | ajapted | 2013-07-16 17:10:27 +1000 (Tue, 16 Jul 2013) | 6 lines Checks: for tests which have a "Show" button and a map-modifying button, place the "Show" button on the left and other button on the right. That's because the first button is navigated to by FLTK, and hence it should ideally be a non-destructive action. ------------------------------------------------------------------------ r1195 | ajapted | 2013-07-16 17:06:58 +1000 (Tue, 16 Jul 2013) | 2 lines Check / linedefs: added 'Remove' feature for overlapping linedefs. ------------------------------------------------------------------------ r1194 | ajapted | 2013-07-16 16:46:27 +1000 (Tue, 16 Jul 2013) | 2 lines Checks: layout tweak. ------------------------------------------------------------------------ r1193 | ajapted | 2013-07-16 16:43:27 +1000 (Tue, 16 Jul 2013) | 2 lines Check / linedefs: detection logic for directly overlapping linedefs. ------------------------------------------------------------------------ r1192 | ajapted | 2013-07-16 14:53:14 +1000 (Tue, 16 Jul 2013) | 2 lines Check / linedefs: added test for linedefs without a right side. ------------------------------------------------------------------------ r1191 | ajapted | 2013-07-16 14:43:41 +1000 (Tue, 16 Jul 2013) | 3 lines Check / linedefs: implemented zero-length linedef test, with a button to show them (in vertex mode) and a button to remove them. ------------------------------------------------------------------------ r1190 | ajapted | 2013-07-16 13:58:52 +1000 (Tue, 16 Jul 2013) | 2 lines New code file 'e_checks2.cc' -- it will contain linedef checking code. ------------------------------------------------------------------------ r1189 | ajapted | 2013-07-16 13:38:22 +1000 (Tue, 16 Jul 2013) | 4 lines Check / sectors: re-implemented the mismatched sectors test, based on the existing DEU code. However it is quite slow, O(n^2) with number of linedefs. ------------------------------------------------------------------------ r1188 | ajapted | 2013-07-16 13:04:51 +1000 (Tue, 16 Jul 2013) | 2 lines Removed the now redundant GetOppositeSector() code. ------------------------------------------------------------------------ r1187 | ajapted | 2013-07-16 13:03:32 +1000 (Tue, 16 Jul 2013) | 2 lines Added OppositeSector() function which uses OppositeLineDef(). ------------------------------------------------------------------------ r1186 | ajapted | 2013-07-16 12:45:28 +1000 (Tue, 16 Jul 2013) | 2 lines Check / things: tweaked player start messages. ------------------------------------------------------------------------ r1185 | ajapted | 2013-07-16 12:38:32 +1000 (Tue, 16 Jul 2013) | 2 lines misc/Checks.txt updated. ------------------------------------------------------------------------ r1184 | ajapted | 2013-07-16 12:38:07 +1000 (Tue, 16 Jul 2013) | 5 lines Check / sectors: implemented detection of unclosed sectors (mismatches at vertices), with buttons to show the sectors and show the vertices. Renamed XXX_Highlight --> XXX_Show, and removed a bit of dead code. ------------------------------------------------------------------------ r1183 | ajapted | 2013-07-16 10:59:25 +1000 (Tue, 16 Jul 2013) | 4 lines Key bindings: 1. renamed binding command: AwaitMeta --> MetaKey 2. allow ';' to toggle the await_meta state on and off ------------------------------------------------------------------------ r1182 | ajapted | 2013-07-15 21:50:17 +1000 (Mon, 15 Jul 2013) | 3 lines When loading a level, check for shared sidedefs and if exist ask user whether to unpack them or not. ------------------------------------------------------------------------ r1181 | ajapted | 2013-07-15 21:40:06 +1000 (Mon, 15 Jul 2013) | 2 lines Check / sectors: finished the sidedef unpacking algorithm. ------------------------------------------------------------------------ r1180 | ajapted | 2013-07-15 21:19:04 +1000 (Mon, 15 Jul 2013) | 2 lines Check / sectors: worked on algorithm to unpack sidedefs... ------------------------------------------------------------------------ r1179 | ajapted | 2013-07-15 20:49:59 +1000 (Mon, 15 Jul 2013) | 3 lines Check / sectors: implemented detection of shared sidedefs, and ability to show them in the error mode. To-Do: ability to unpack them. ------------------------------------------------------------------------ r1178 | ajapted | 2013-07-15 20:08:11 +1000 (Mon, 15 Jul 2013) | 4 lines Check / sectors: added test for ceiling < floor height, with two action buttons: "Fix" will set ceiling same as floor, and "Show" to highlight them in the error_mode. ------------------------------------------------------------------------ r1177 | ajapted | 2013-07-15 19:56:46 +1000 (Mon, 15 Jul 2013) | 2 lines Check / sectors: count unused sidedefs, and ability to remove them. ------------------------------------------------------------------------ r1176 | ajapted | 2013-07-15 19:41:24 +1000 (Mon, 15 Jul 2013) | 3 lines Checks: began work on SECTOR checks... So far only have unused count (with button to remove those unused sectors). ------------------------------------------------------------------------ r1175 | ajapted | 2013-07-15 19:40:15 +1000 (Mon, 15 Jul 2013) | 2 lines tweaked Prune message. ------------------------------------------------------------------------ r1174 | ajapted | 2013-07-15 19:26:55 +1000 (Mon, 15 Jul 2013) | 2 lines Checks.txt : updated for current plans. ------------------------------------------------------------------------ r1173 | ajapted | 2013-07-15 19:11:54 +1000 (Mon, 15 Jul 2013) | 3 lines Checks: when highlighting error objects, ensure we change the editor mode when necessary. ------------------------------------------------------------------------ r1172 | ajapted | 2013-07-15 19:01:23 +1000 (Mon, 15 Jul 2013) | 2 lines Checks: tweakage. ------------------------------------------------------------------------ r1171 | ajapted | 2013-07-15 18:53:32 +1000 (Mon, 15 Jul 2013) | 2 lines Checks / things: added detection of things in void-space. ------------------------------------------------------------------------ r1170 | ajapted | 2013-07-15 18:41:25 +1000 (Mon, 15 Jul 2013) | 2 lines Dead code removal : CheckStartingPos() ------------------------------------------------------------------------ r1169 | ajapted | 2013-07-15 18:40:20 +1000 (Mon, 15 Jul 2013) | 2 lines Checks / things: added checks for missing player starts. ------------------------------------------------------------------------ r1168 | ajapted | 2013-07-15 16:59:05 +1000 (Mon, 15 Jul 2013) | 3 lines Checks: when highlighting error objects, use GoToSelection() to ensure the user will see them. ------------------------------------------------------------------------ r1167 | ajapted | 2013-07-15 16:56:07 +1000 (Mon, 15 Jul 2013) | 3 lines Checks: began work on THING checking. So far: can count the number of unknown things, and highlight them in the error mode. ------------------------------------------------------------------------ r1166 | ajapted | 2013-07-15 16:31:55 +1000 (Mon, 15 Jul 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1165 | ajapted | 2013-07-15 16:22:19 +1000 (Mon, 15 Jul 2013) | 2 lines Prefs: layout tweaks. ------------------------------------------------------------------------ r1164 | ajapted | 2013-07-15 16:19:22 +1000 (Mon, 15 Jul 2013) | 2 lines Preferences: implemented a 'Default editing mode' setting. ------------------------------------------------------------------------ r1163 | ajapted | 2013-07-15 14:22:11 +1000 (Mon, 15 Jul 2013) | 2 lines UI_Sector and UI_LineDef: use Tags_ApplyNewValue() in tag_callback. ------------------------------------------------------------------------ r1162 | ajapted | 2013-07-15 14:19:28 +1000 (Mon, 15 Jul 2013) | 6 lines Implemented new 'ApplyTag' key-binding command. With the "fresh" param it sets the tags on selected objects to a fresh tag (max + 1), and with the "last" parameter it sets the tag to the last one (maximum). Current bindings are META-F and META-L. ------------------------------------------------------------------------ r1161 | ajapted | 2013-07-15 14:08:52 +1000 (Mon, 15 Jul 2013) | 2 lines Main loop: disable error_mode whenever selection becomes empty. ------------------------------------------------------------------------ r1160 | ajapted | 2013-07-15 13:35:16 +1000 (Mon, 15 Jul 2013) | 3 lines Checks / tags: added feature to assign a fresh tag value to the current selected linedefs or sectors. ------------------------------------------------------------------------ r1159 | ajapted | 2013-07-15 13:18:26 +1000 (Mon, 15 Jul 2013) | 3 lines Checks: implemented "TAG" dialog, which for now just shows the lowest and highest used tag numbers. ------------------------------------------------------------------------ r1158 | ajapted | 2013-07-15 13:02:04 +1000 (Mon, 15 Jul 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1157 | ajapted | 2013-07-15 12:27:08 +1000 (Mon, 15 Jul 2013) | 3 lines Save message : added "NO NODES" so the user knows that nodes have not been built. ------------------------------------------------------------------------ r1156 | ajapted | 2013-07-15 11:58:03 +1000 (Mon, 15 Jul 2013) | 2 lines Minor rename: edit.obj_type --> edit.mode ------------------------------------------------------------------------ r1155 | ajapted | 2013-07-14 22:57:21 +1000 (Sun, 14 Jul 2013) | 3 lines Check / vertices: implemented ability to merge overlapping vertices, or highlight them in the error selection [that part is not complete]. ------------------------------------------------------------------------ r1154 | ajapted | 2013-07-14 22:19:41 +1000 (Sun, 14 Jul 2013) | 4 lines Checks / vertices: 1. fixed some bugs in Reset() method [one was quite nasty] 2. implemented Vertex_RemoveUnused() function ------------------------------------------------------------------------ r1153 | ajapted | 2013-07-14 22:05:20 +1000 (Sun, 14 Jul 2013) | 3 lines Checks / vertices: implemented Vertex_FindOverlaps() and FindUnused(), fixed AddLine() to copy the label, and tweaked a few things. ------------------------------------------------------------------------ r1152 | ajapted | 2013-07-14 21:29:21 +1000 (Sun, 14 Jul 2013) | 3 lines Checks / vertices: worked on performing proper tests, and improved the size and layout of the dialog window. ------------------------------------------------------------------------ r1151 | ajapted | 2013-07-14 20:32:35 +1000 (Sun, 14 Jul 2013) | 11 lines Check: 1. use an enumeration for the result of CHECK_xxx functions 2. support CHECK_xxx functions returning a value to indicate skipping the rest of the checks in CHECK_All() 3. ability to Reset() the UI dialog, so checks can be re-performed on an existing dialog window 4. fixed not passing 'this' to the callback functions. ------------------------------------------------------------------------ r1150 | ajapted | 2013-07-14 19:57:20 +1000 (Sun, 14 Jul 2013) | 6 lines Checks: 1. the CHECK_xxx functions now return a "severity" value (an int) 2. keep track of 'worst_severity' in the UI_CheckXXX classes 3. fixed logic in CHECK_All() -- it needs to keep going when one of the CHECK_xxx() functions returns a non-zero severity ------------------------------------------------------------------------ r1149 | ajapted | 2013-07-14 19:40:29 +1000 (Sun, 14 Jul 2013) | 3 lines Checks: implemented an 'AddLine' method for the Vertex dialog, which supports upto three buttons for actions to take. ------------------------------------------------------------------------ r1148 | ajapted | 2013-07-14 19:03:33 +1000 (Sun, 14 Jul 2013) | 2 lines Check Menu: fixed shortcuts. ------------------------------------------------------------------------ r1147 | ajapted | 2013-07-14 18:57:38 +1000 (Sun, 14 Jul 2013) | 4 lines Checks: 1. added a bare-bones UI_CheckVertices dialog class 2. removed some obsolete code ------------------------------------------------------------------------ r1146 | ajapted | 2013-07-14 18:55:03 +1000 (Sun, 14 Jul 2013) | 3 lines Preferences: fixed potential problem with UI_EditKey and the close button of the window manager. ------------------------------------------------------------------------ r1145 | ajapted | 2013-07-14 18:20:19 +1000 (Sun, 14 Jul 2013) | 6 lines Began work on map-checking functions. Firstly have a 'Check' menu with various choices (like "Vertices", "Sectors", etc). These are routed through a new 'CheckMap' binding command whose first parameter is the area to check. Some special keywords are "current" for the current enditing mode, and "all" to check all the major stuff. ------------------------------------------------------------------------ r1144 | ajapted | 2013-07-14 18:10:59 +1000 (Sun, 14 Jul 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1143 | ajapted | 2013-07-14 15:20:28 +1000 (Sun, 14 Jul 2013) | 3 lines VM: disabled the testing stuff in main.cc -- all the scripting stuff is very much on the back-burner now.... ------------------------------------------------------------------------ r1142 | ajapted | 2013-07-14 15:15:08 +1000 (Sun, 14 Jul 2013) | 4 lines The ';' key waits for the next key, and makes it META (as if it had been pressed with the META modifier key). This could be handy on computers with limited keyboards -- especially laptops. ------------------------------------------------------------------------ r1141 | ajapted | 2013-07-14 14:42:43 +1000 (Sun, 14 Jul 2013) | 2 lines Prefs: tweak. ------------------------------------------------------------------------ r1140 | ajapted | 2013-07-14 14:36:15 +1000 (Sun, 14 Jul 2013) | 4 lines Config file: 1. handle empty strings, write and parse as '' (two single quotes) 2. moved the glbsp_xxx entries down ------------------------------------------------------------------------ r1139 | ajapted | 2013-07-14 14:23:06 +1000 (Sun, 14 Jul 2013) | 2 lines Game defs: removed obsolete 'default_port' command. ------------------------------------------------------------------------ r1138 | ajapted | 2013-07-14 14:11:07 +1000 (Sun, 14 Jul 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1137 | ajapted | 2013-07-14 14:07:40 +1000 (Sun, 14 Jul 2013) | 6 lines Preferences: added 'Default Port' setting to the Editing tab. This affects general startup too, as previously the default port was a game definition setting. Hence added DeterminePort() whose main job is to ensure the default_port value is valid [and reset it if not]. ------------------------------------------------------------------------ r1136 | ajapted | 2013-07-14 14:03:11 +1000 (Sun, 14 Jul 2013) | 2 lines Game (UGH) parser: disabled the 'default_port' command. ------------------------------------------------------------------------ r1135 | ajapted | 2013-07-14 13:24:22 +1000 (Sun, 14 Jul 2013) | 3 lines the X11 UI_Window::Maximize() implementation now does a short delay, to allow the X message to get to the X server and back. ------------------------------------------------------------------------ r1134 | ajapted | 2013-07-14 13:11:41 +1000 (Sun, 14 Jul 2013) | 2 lines Utils: added TimeDelay() function. ------------------------------------------------------------------------ r1133 | ajapted | 2013-07-14 13:03:49 +1000 (Sun, 14 Jul 2013) | 3 lines Made patch image loading fail more gracefully: a bad offset now prints a warning to the log file instead of inducing a fatal error. ------------------------------------------------------------------------ r1132 | ajapted | 2013-07-11 19:08:38 +1000 (Thu, 11 Jul 2013) | 2 lines Version bump. ------------------------------------------------------------------------ r1131 | ajapted | 2013-07-11 18:58:15 +1000 (Thu, 11 Jul 2013) | 3 lines Key bindings: shifted 'N' and 'P' keys now have the FlipMap function, and moved the GivenFile functions to META-N and META-P. ------------------------------------------------------------------------ r1130 | ajapted | 2013-07-11 18:55:30 +1000 (Thu, 11 Jul 2013) | 4 lines Implemented new binding command 'FlipMap' which loads another map in the current wad. The first param must be "next", "prev", "first" or "last". Very useful for browsing through a pwad with multiple maps. ------------------------------------------------------------------------ r1129 | ajapted | 2013-07-11 18:43:32 +1000 (Thu, 11 Jul 2013) | 3 lines Wad code: added FindLevel_Raw() method which returns a level index instead of a _lump_ index. ------------------------------------------------------------------------ r1128 | ajapted | 2013-07-05 21:34:57 +1000 (Fri, 05 Jul 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1127 | ajapted | 2013-07-05 20:28:47 +1000 (Fri, 05 Jul 2013) | 2 lines Removed obsolete GRID_XXX color defines. ------------------------------------------------------------------------ r1126 | ajapted | 2013-07-05 20:13:27 +1000 (Fri, 05 Jul 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1125 | ajapted | 2013-07-05 20:11:11 +1000 (Fri, 05 Jul 2013) | 2 lines Grid: implemented preference colors for the Normal grid. ------------------------------------------------------------------------ r1124 | ajapted | 2013-07-05 19:03:30 +1000 (Fri, 05 Jul 2013) | 4 lines Grid: 1. added preference settings for the Dotty grid colors 2. slightly better rendering of the Dotty grid ------------------------------------------------------------------------ r1123 | ajapted | 2013-07-05 16:33:33 +1000 (Fri, 05 Jul 2013) | 5 lines Grid: 1. implemented option to limit grid toggle to a single kind 2. added option to hide grid in FREE mode, show it in SNAP mode 3. nomenclature: old grid is called "dotty", new grid "normal" ------------------------------------------------------------------------ r1122 | ajapted | 2013-07-05 16:28:36 +1000 (Fri, 05 Jul 2013) | 2 lines UI_Canvas: split DrawGrid() into two separate methods. ------------------------------------------------------------------------ r1121 | ajapted | 2013-07-04 20:19:47 +1000 (Thu, 04 Jul 2013) | 2 lines Preferences: a few more tweaks ------------------------------------------------------------------------ r1120 | ajapted | 2013-07-04 18:24:04 +1000 (Thu, 04 Jul 2013) | 4 lines Preferences: 1. added a 'Mouse' tab, nothing in it yet 2. renamed 'glBSP' tab --> 'Other', ready for some other stuff ------------------------------------------------------------------------ r1119 | ajapted | 2013-07-04 16:54:11 +1000 (Thu, 04 Jul 2013) | 4 lines Fixed recent bug with mousewheel zooming -- Editor_RawWheel() was not returning 1 and hence FLTK was sending the mousewheel event to the scrollbars which used it to scroll. ------------------------------------------------------------------------ r1118 | ajapted | 2013-07-04 16:28:06 +1000 (Thu, 04 Jul 2013) | 2 lines CHANGELOG rejigged. ------------------------------------------------------------------------ r1117 | ajapted | 2013-07-04 14:45:46 +1000 (Thu, 04 Jul 2013) | 2 lines Implemented new preference setting : maximize the window on start. ------------------------------------------------------------------------ r1116 | ajapted | 2013-07-04 14:36:43 +1000 (Thu, 04 Jul 2013) | 5 lines UI_Window: added Maximize() method, using OS-native code since FLTK does not provide the required functionality. Only implemented for Win32 and Linux/X11 : the OSX implemented is commented out since it requires some Objective-C logic. ------------------------------------------------------------------------ r1115 | ajapted | 2013-07-01 15:49:13 +1000 (Mon, 01 Jul 2013) | 2 lines event handling tweaks. ------------------------------------------------------------------------ r1114 | ajapted | 2013-07-01 13:11:44 +1000 (Mon, 01 Jul 2013) | 6 lines Moved the mouse button and movement logic out of UI_Canvas class and into Editor_RawButton() and Editor_RawMouse() functions. This fixes the hack in UI_Render3D class [calling the handle method of UI_Canvas, even though the widget was hidden]. ------------------------------------------------------------------------ r1113 | ajapted | 2013-07-01 12:55:11 +1000 (Mon, 01 Jul 2013) | 2 lines Minor refactoring of event handling in UI_Canvas class. ------------------------------------------------------------------------ r1112 | ajapted | 2013-07-01 11:59:37 +1000 (Mon, 01 Jul 2013) | 2 lines Keys: added 'FL_Wheel' : pseudo key value for the mouse wheel. ------------------------------------------------------------------------ r1111 | ajapted | 2013-07-01 11:41:14 +1000 (Mon, 01 Jul 2013) | 2 lines Moved handling of mouse wheel events to Editor_RawWheel() function. ------------------------------------------------------------------------ r1110 | ajapted | 2013-07-01 11:23:40 +1000 (Mon, 01 Jul 2013) | 2 lines Key bindings: support 4 parameters to a binding (limit was 2 before). ------------------------------------------------------------------------ r1109 | ajapted | 2013-07-01 11:12:24 +1000 (Mon, 01 Jul 2013) | 2 lines handle the FL_KEYUP event in Editor_RawKey(). ------------------------------------------------------------------------ r1108 | ajapted | 2013-06-30 17:16:34 +1000 (Sun, 30 Jun 2013) | 3 lines Moved the raw keyboard event handling out of UI_Canvas class, instead have a global function: Editor_RawKey(). ------------------------------------------------------------------------ r1107 | ajapted | 2013-06-30 16:47:14 +1000 (Sun, 30 Jun 2013) | 2 lines VM: tweak ------------------------------------------------------------------------ r1106 | ajapted | 2013-06-30 16:39:56 +1000 (Sun, 30 Jun 2013) | 2 lines Renamed directory: up_scripts --> ups ------------------------------------------------------------------------ r1105 | ajapted | 2013-06-30 16:38:40 +1000 (Sun, 30 Jun 2013) | 3 lines Updated installation makefiles (etc) to create 'ups' folder and to install the 'core_defs.lua' file. ------------------------------------------------------------------------ r1104 | ajapted | 2013-06-30 16:31:54 +1000 (Sun, 30 Jun 2013) | 3 lines VM: added file 'core_defs.up' -- will define all the builtins and any other needed stuff. ------------------------------------------------------------------------ r1103 | ajapted | 2013-06-30 15:44:13 +1000 (Sun, 30 Jun 2013) | 2 lines Added top-level directory: 'up_scripts' ------------------------------------------------------------------------ r1102 | ajapted | 2013-06-30 13:41:42 +1000 (Sun, 30 Jun 2013) | 2 lines TODO update (did some things, added some things). ------------------------------------------------------------------------ r1101 | ajapted | 2013-06-30 13:40:29 +1000 (Sun, 30 Jun 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1100 | ajapted | 2013-06-30 13:39:18 +1000 (Sun, 30 Jun 2013) | 5 lines Config: added 'render_missing_bright' and 'render_unknown_bright' vars, and handle them in the rendering code. Note: not present in the Preferences dialog (yet). ------------------------------------------------------------------------ r1099 | ajapted | 2013-06-30 13:29:42 +1000 (Sun, 30 Jun 2013) | 2 lines 3D preview: implemented missing textures (an '!' on an orange background). ------------------------------------------------------------------------ r1098 | ajapted | 2013-06-30 13:23:41 +1000 (Sun, 30 Jun 2013) | 3 lines 3D preview: show missing textures as fullbright, so they stand out in dark rooms. ------------------------------------------------------------------------ r1097 | ajapted | 2013-06-30 12:58:35 +1000 (Sun, 30 Jun 2013) | 2 lines 3d preview: tweaked untextured color choice. ------------------------------------------------------------------------ r1096 | ajapted | 2013-06-30 12:57:38 +1000 (Sun, 30 Jun 2013) | 2 lines Game defs / DOOM (etc) : updated color definitions. ------------------------------------------------------------------------ r1095 | ajapted | 2013-06-30 12:56:46 +1000 (Sun, 30 Jun 2013) | 3 lines Auto-load recent map: don't do it when -iwad or -warp has been used on the command line. ------------------------------------------------------------------------ r1094 | ajapted | 2013-06-30 12:31:47 +1000 (Sun, 30 Jun 2013) | 2 lines Game defs / HERETIC: updated with color definitions ('wall', 'missing' etc). ------------------------------------------------------------------------ r1093 | ajapted | 2013-06-30 12:25:19 +1000 (Sun, 30 Jun 2013) | 3 lines 3D preview: use the game-specified wall and floor colors, rather than the hard-coded values which were DOOM specific. ------------------------------------------------------------------------ r1092 | ajapted | 2013-06-30 12:23:01 +1000 (Sun, 30 Jun 2013) | 2 lines Game def parser: support 'wall' and 'floor' color definitions. ------------------------------------------------------------------------ r1091 | ajapted | 2013-06-30 12:00:25 +1000 (Sun, 30 Jun 2013) | 4 lines Game def parser: implemented new 'color' command which takes a keyword and one or two numbers (palette indices). The following keywords are currently supported: 'sky', 'missing', 'unknown_tex', 'unknown_flat'. ------------------------------------------------------------------------ r1090 | ajapted | 2013-06-29 22:19:26 +1000 (Sat, 29 Jun 2013) | 3 lines 1. moved g_sky_color and g_sky_flat into a new 'game_info' structure 2. moved is_sky() function from levels.cc --> m_game.cc ------------------------------------------------------------------------ r1089 | ajapted | 2013-06-29 22:10:44 +1000 (Sat, 29 Jun 2013) | 3 lines GAME DEFS: added common/doom_colors.ugh : color defs for games using the DOOM palette. ------------------------------------------------------------------------ r1088 | ajapted | 2013-06-29 22:03:59 +1000 (Sat, 29 Jun 2013) | 3 lines 3D Preview: implemented displaying a dummy texture for unknown flats or textures (a different one for flats vs textures). ------------------------------------------------------------------------ r1087 | ajapted | 2013-06-29 21:28:57 +1000 (Sat, 29 Jun 2013) | 3 lines Img code: added functions to create dummy textures for the 3D renderer, one for missing (HOM) textures and one for unknown textures. ------------------------------------------------------------------------ r1086 | ajapted | 2013-06-29 21:14:25 +1000 (Sat, 29 Jun 2013) | 2 lines Img class: turned 'scale_img()' into a method, plus various tidying. ------------------------------------------------------------------------ r1085 | ajapted | 2013-06-29 20:38:51 +1000 (Sat, 29 Jun 2013) | 2 lines Fixed thing images in the browser to have a black background. ------------------------------------------------------------------------ r1084 | ajapted | 2013-06-29 20:28:42 +1000 (Sat, 29 Jun 2013) | 3 lines LineDef panel: don't show an upper texture as missing if sky ceilings exist on both sides. ------------------------------------------------------------------------ r1083 | ajapted | 2013-06-29 20:18:27 +1000 (Sat, 29 Jun 2013) | 3 lines LineDef panel: implemented showing missing textures, for uppers and lowers this involves checking for a floor / ceiling difference. ------------------------------------------------------------------------ r1082 | ajapted | 2013-06-29 20:02:08 +1000 (Sat, 29 Jun 2013) | 4 lines UI_Pic : implemented ability to show "unknown" and "missing" textures, the former as a large '?' on a cyan background, the latter as '!' on an orange background. ------------------------------------------------------------------------ r1081 | ajapted | 2013-06-28 21:18:31 +1000 (Fri, 28 Jun 2013) | 3 lines UI: in sidedef panels, show low-contrast "Lower", "Mid" and "Upper" for unset textures. Similarly for pics in sector and thing panels. ------------------------------------------------------------------------ r1080 | ajapted | 2013-06-28 19:51:32 +1000 (Fri, 28 Jun 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1079 | ajapted | 2013-06-28 19:35:54 +1000 (Fri, 28 Jun 2013) | 4 lines Scroll-bars: improved logic for adjusting the scroll bars after the canvas position has moved, having grid.MoveTo() and grid.Scroll() methods instead of directly modifying grid.orig_x/_y ------------------------------------------------------------------------ r1078 | ajapted | 2013-06-28 12:11:35 +1000 (Fri, 28 Jun 2013) | 4 lines Scroll-bars: implemented callbacks, i.e. dragging the knobs actually scrolls the map (and in turn, moves the knobs). Hence the scroll-bar feature is mostly complete now. ------------------------------------------------------------------------ r1077 | ajapted | 2013-06-28 11:46:10 +1000 (Fri, 28 Jun 2013) | 3 lines Scroll-bars: implemented logic to compute the position/size of each bar based on the map bounds and the current view position and zoom level. ------------------------------------------------------------------------ r1076 | ajapted | 2013-06-27 22:46:27 +1000 (Thu, 27 Jun 2013) | 1 line CHANGELOG update ------------------------------------------------------------------------ r1075 | ajapted | 2013-06-27 22:45:07 +1000 (Thu, 27 Jun 2013) | 2 lines Minor coding rename: MapBound_[lh][xy] --> Map_bound_[xy][12] ------------------------------------------------------------------------ r1074 | ajapted | 2013-06-27 22:20:00 +1000 (Thu, 27 Jun 2013) | 3 lines Scroll-bars: implemented ability to hide/show the bars based on the user's preference setting. ------------------------------------------------------------------------ r1073 | ajapted | 2013-06-27 21:46:18 +1000 (Thu, 27 Jun 2013) | 3 lines Config: added 'map_scroll_bars' variable which will be used to enable or disable the scroll-bars for the map view. ------------------------------------------------------------------------ r1072 | ajapted | 2013-06-27 17:14:55 +1000 (Thu, 27 Jun 2013) | 2 lines Updated AUTHORS.txt to match website (Jason's contribution). ------------------------------------------------------------------------ r1071 | ajapted | 2013-06-27 17:10:53 +1000 (Thu, 27 Jun 2013) | 3 lines Reworked the About dialog to show the new logo, and have a fallback just in case we cannot open the file, plus tweaked the text. ------------------------------------------------------------------------ r1070 | ajapted | 2013-06-27 17:09:11 +1000 (Thu, 27 Jun 2013) | 2 lines Added 'about_logo.png' -- cropped and scaled from Jason's original. ------------------------------------------------------------------------ r1069 | ajapted | 2013-06-27 16:27:58 +1000 (Thu, 27 Jun 2013) | 2 lines Checked in Jason R Johnston's logo image, and removed the old cruddy one. ------------------------------------------------------------------------ r1068 | ajapted | 2013-06-26 22:17:47 +1000 (Wed, 26 Jun 2013) | 3 lines More work on having a proper widget for the 3D preview. It seems to be working now, albeit with some ugly hacks. ------------------------------------------------------------------------ r1067 | ajapted | 2013-06-26 19:35:35 +1000 (Wed, 26 Jun 2013) | 4 lines Created a UI_Render3D class for the 3D preview. The idea is to show this widget (and hide the canvas/sbars) when 3D mode is active, and do the reverse when not active -- but keyboard handling is now fubar.... ------------------------------------------------------------------------ r1066 | ajapted | 2013-06-26 16:51:36 +1000 (Wed, 26 Jun 2013) | 4 lines Moved the 'render3d' field out of UI_Canvas and into Editor_State_t, since the canvas is no longer responsible for drawing the 3D preview (the new UI_CanvasScroll wrapper is). ------------------------------------------------------------------------ r1065 | ajapted | 2013-06-26 16:27:21 +1000 (Wed, 26 Jun 2013) | 3 lines Initial work on scrollbars for the map view. This commit merely creates a container for the canvas + scrollbars : UI_CanvasScroll. ------------------------------------------------------------------------ r1064 | ajapted | 2013-06-26 14:17:56 +1000 (Wed, 26 Jun 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1063 | ajapted | 2013-06-26 14:02:15 +1000 (Wed, 26 Jun 2013) | 6 lines Improved handling of bad references when loading a level: If a linedef has a bad vertex, it is removed. Bad sector or sidedef references are replaced with something valid. Details are written to the log file, and a dialog is shown to the user when these happen. ------------------------------------------------------------------------ r1062 | ajapted | 2013-06-25 22:45:26 +1000 (Tue, 25 Jun 2013) | 2 lines Created a definition file for the XDoom source port (by Udo Monk). ------------------------------------------------------------------------ r1061 | ajapted | 2013-06-24 23:47:02 +1000 (Mon, 24 Jun 2013) | 3 lines Fixed splitting void islands : it was adding a sector in _both_ sides, but we only want one in a single side (the smallest). ------------------------------------------------------------------------ r1060 | ajapted | 2013-06-24 23:39:39 +1000 (Mon, 24 Jun 2013) | 4 lines Lineloop class: 1. added a Dump() method to aid debugging 2. fixed silly bug in TotalLength() method ------------------------------------------------------------------------ r1059 | ajapted | 2013-06-24 22:26:42 +1000 (Mon, 24 Jun 2013) | 3 lines Basis: fixed assertion checks in BA_ChangeTH() and BA_ChangeLD() to handle the new HEXEN fields. ------------------------------------------------------------------------ r1058 | ajapted | 2013-06-24 15:59:01 +1000 (Mon, 24 Jun 2013) | 4 lines Minor code tidying: 1. removed unused levelname2xxx() functions 2. removed unused yg_level_name variable ------------------------------------------------------------------------ r1057 | ajapted | 2013-06-23 14:24:06 +1000 (Sun, 23 Jun 2013) | 2 lines CHANGELOG and TODO update. ------------------------------------------------------------------------ r1056 | ajapted | 2013-06-23 14:21:03 +1000 (Sun, 23 Jun 2013) | 2 lines Support Eureka config (.ugh) files as resource files. ------------------------------------------------------------------------ r1055 | ajapted | 2013-06-23 13:38:00 +1000 (Sun, 23 Jun 2013) | 4 lines Minor code refactoring: 1. use "M_" prefix on some m_game.cc functions 2. have a LoadResourceFile() function in main.cc ------------------------------------------------------------------------ r1054 | ajapted | 2013-06-23 12:07:40 +1000 (Sun, 23 Jun 2013) | 2 lines Added 'Level_format' global variable. ------------------------------------------------------------------------ r1053 | ajapted | 2013-06-23 12:02:43 +1000 (Sun, 23 Jun 2013) | 4 lines Hexen: 1. have proper F_ARG1..5 keywords for the argument fields 2. updated the CopyProperties command to copy the Hexen fields ------------------------------------------------------------------------ r1052 | ajapted | 2013-06-23 11:49:44 +1000 (Sun, 23 Jun 2013) | 3 lines Basis: expanded Thing and LineDef structures with HEXEN fields. (Note: not actually used anywhere yet). ------------------------------------------------------------------------ r1051 | ajapted | 2013-06-23 11:33:22 +1000 (Sun, 23 Jun 2013) | 2 lines README: added the new 'N' / 'P' keys : next file / prev file. ------------------------------------------------------------------------ r1050 | ajapted | 2013-06-23 11:29:02 +1000 (Sun, 23 Jun 2013) | 3 lines Implemented SEC_Light() binding command for adjusting sector lighting. It takes a delta parameter as per the SEC_Floor() command. ------------------------------------------------------------------------ r1049 | ajapted | 2013-06-22 23:40:29 +1000 (Sat, 22 Jun 2013) | 2 lines CHANGELOG and TODO update. ------------------------------------------------------------------------ r1048 | ajapted | 2013-06-22 23:37:51 +1000 (Sat, 22 Jun 2013) | 4 lines Browser: 1. remember the "off mode" properly in user state 2. persist the browser width in the user state ------------------------------------------------------------------------ r1047 | ajapted | 2013-06-22 23:00:44 +1000 (Sat, 22 Jun 2013) | 4 lines VM: partial work on ability to read/write the members of a set. There are two new instructions, OP_SET_READ and OP_SET_WRITE, which are generated but their execution is not implemented yet. ------------------------------------------------------------------------ r1046 | ajapted | 2013-06-22 16:31:55 +1000 (Sat, 22 Jun 2013) | 4 lines VM: 1. fixed bug when pushing vector literals onto the stack 2. support assigning 'nil' values to any kind of variable ------------------------------------------------------------------------ r1045 | ajapted | 2013-06-22 16:04:02 +1000 (Sat, 22 Jun 2013) | 2 lines VM: updated VIM syntax file for new types. ------------------------------------------------------------------------ r1044 | ajapted | 2013-06-22 15:58:44 +1000 (Sat, 22 Jun 2013) | 7 lines VM: added the following new types: linedef, sidedef, sector, thing and vertex, plus also set[xxx] where xxx is linedef (etc). So far there is nothing which can be done with any of these types. Also support a "nil" keyword with its own ev_nil type. It cannot be used anywhere yet. ------------------------------------------------------------------------ r1043 | ajapted | 2013-06-22 15:22:46 +1000 (Sat, 22 Jun 2013) | 2 lines VM: removed type_size[] array. ------------------------------------------------------------------------ r1042 | ajapted | 2013-06-22 13:40:38 +1000 (Sat, 22 Jun 2013) | 2 lines Fixed remembering 3D mode (actually the lack of it) for a map. ------------------------------------------------------------------------ r1041 | ajapted | 2013-06-22 13:33:33 +1000 (Sat, 22 Jun 2013) | 2 lines Removed some unused code : word_splitting() ------------------------------------------------------------------------ r1040 | ajapted | 2013-06-22 13:19:26 +1000 (Sat, 22 Jun 2013) | 2 lines Moved code around: put Beep() function into m_keys.cc ------------------------------------------------------------------------ r1039 | ajapted | 2013-06-22 13:10:10 +1000 (Sat, 22 Jun 2013) | 3 lines Fixed the key binding dialog: unable to remove a parameter (when the binding already had a parameter). ------------------------------------------------------------------------ r1038 | ajapted | 2013-06-22 11:30:14 +1000 (Sat, 22 Jun 2013) | 8 lines 1. when registering binding commands, determine the context automatically from the name e.g. "LIN_xxxx" will be KCTX_Line. 2. support finding a binding command as a script function (in the VM), and execute that script function when the command is executed. This is bare-bones at the moment, numerous things (error handling, passing parameters) are NOT done yet. ------------------------------------------------------------------------ r1037 | ajapted | 2013-06-21 22:36:31 +1000 (Fri, 21 Jun 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r1036 | ajapted | 2013-06-18 19:36:30 +1000 (Tue, 18 Jun 2013) | 2 lines VM: removed more field-related stuff. ------------------------------------------------------------------------ r1035 | ajapted | 2013-06-18 19:18:08 +1000 (Tue, 18 Jun 2013) | 4 lines VM / compiler: tidied up code to parse global definitions. Also removed code to parse "fields" (won't be needed here). ------------------------------------------------------------------------ r1034 | ajapted | 2013-06-18 18:51:19 +1000 (Tue, 18 Jun 2013) | 2 lines VM: ensure local string variables get a valid default (the empty string). ------------------------------------------------------------------------ r1033 | ajapted | 2013-06-18 18:48:46 +1000 (Tue, 18 Jun 2013) | 2 lines VM: ensure global variables of type 'string' get a valid default. ------------------------------------------------------------------------ r1032 | ajapted | 2013-06-18 18:37:01 +1000 (Tue, 18 Jun 2013) | 3 lines VM: replaced 's_file' field of dfunction_t with a normal string ptr, replaced usages of 's_name' field, and removed mpr.strings[] table. ------------------------------------------------------------------------ r1031 | ajapted | 2013-06-18 18:26:13 +1000 (Tue, 18 Jun 2013) | 4 lines VM: changed OP_LITERAL instruction to store the kval_t value in the following instruction slot. This is a bit cleaner than the previous way of storing the value inside the dstatement_t. ------------------------------------------------------------------------ r1030 | ajapted | 2013-06-18 15:55:03 +1000 (Tue, 18 Jun 2013) | 3 lines VM: changed representation of _string in kval_t, esp. on the stack, to use a pointer to object_ref_c instead of an offset into mpr.strings[]. ------------------------------------------------------------------------ r1029 | ajapted | 2013-06-18 15:25:04 +1000 (Tue, 18 Jun 2013) | 2 lines Makefiles: added vm_object.o to the build. ------------------------------------------------------------------------ r1028 | ajapted | 2013-06-18 15:24:24 +1000 (Tue, 18 Jun 2013) | 2 lines VM / lex: removed lex_eval_t union -- for simpler code. ------------------------------------------------------------------------ r1027 | ajapted | 2013-06-18 15:21:23 +1000 (Tue, 18 Jun 2013) | 2 lines VM / objects: added MakePermanent() method, will be needed for string literals. ------------------------------------------------------------------------ r1026 | ajapted | 2013-06-18 14:07:39 +1000 (Tue, 18 Jun 2013) | 3 lines VM / objects: fleshed out remaining methods, e.g. NewSelection(), and fixed various compiling issues. ------------------------------------------------------------------------ r1025 | ajapted | 2013-06-18 13:47:32 +1000 (Tue, 18 Jun 2013) | 2 lines VM / objects: description of the memory model. ------------------------------------------------------------------------ r1024 | ajapted | 2013-06-18 13:33:42 +1000 (Tue, 18 Jun 2013) | 4 lines VM: began work on some simple object management code for the VM. The objects so far are (1) strings and (2) selections for each map kind of map element. Other objects may be added later. ------------------------------------------------------------------------ r1023 | ajapted | 2013-06-17 13:57:40 +1000 (Mon, 17 Jun 2013) | 2 lines VM: added grammar description, using EBNF notation. ------------------------------------------------------------------------ r1022 | ajapted | 2013-06-17 13:49:17 +1000 (Mon, 17 Jun 2013) | 2 lines VM: made all semicolons optional. ------------------------------------------------------------------------ r1021 | ajapted | 2013-06-16 23:46:45 +1000 (Sun, 16 Jun 2013) | 4 lines VM: 1. removed redundant check on "float" in ParseType(). 2. removed "void" as a usable type. ------------------------------------------------------------------------ r1020 | ajapted | 2013-06-16 20:41:07 +1000 (Sun, 16 Jun 2013) | 4 lines VM: 1. renamed 'extern' keyword --> 'builtin' 2. renamed 'va' function --> 'format' ------------------------------------------------------------------------ r1019 | ajapted | 2013-06-16 20:27:58 +1000 (Sun, 16 Jun 2013) | 3 lines Detect HEXEN format maps, and prevent trying to load them -- instead we show an error message, which is better than crashing out. ------------------------------------------------------------------------ r1018 | ajapted | 2013-06-16 19:15:31 +1000 (Sun, 16 Jun 2013) | 3 lines VM: fixed precedence of the '?:' ternary operator, which needs to be higher than assignment. ------------------------------------------------------------------------ r1017 | ajapted | 2013-06-16 19:01:24 +1000 (Sun, 16 Jun 2013) | 2 lines Minor rename: 'ResourceWads' --> 'Resource_list' ------------------------------------------------------------------------ r1016 | ajapted | 2013-06-16 18:35:32 +1000 (Sun, 16 Jun 2013) | 2 lines Preferences: added button for 'auto_load_recent' config var. ------------------------------------------------------------------------ r1015 | ajapted | 2013-06-16 18:22:33 +1000 (Sun, 16 Jun 2013) | 3 lines Preferences: added a new 'Grid' tab, and moved the griddy stuff there, though I expect to add more griddy stuff too (soon). ------------------------------------------------------------------------ r1014 | ajapted | 2013-06-16 16:26:32 +1000 (Sun, 16 Jun 2013) | 3 lines Implemented opening the most recently saved pwad on startup -- but only when Eureka is started without any pwad filenames. ------------------------------------------------------------------------ r1013 | ajapted | 2013-06-16 16:01:14 +1000 (Sun, 16 Jun 2013) | 2 lines Moved code around in m_files.cc ------------------------------------------------------------------------ r1012 | ajapted | 2013-06-16 15:51:11 +1000 (Sun, 16 Jun 2013) | 2 lines Support DOOMWADPATH for finding IWAD files. ------------------------------------------------------------------------ r1011 | ajapted | 2013-06-16 15:01:57 +1000 (Sun, 16 Jun 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r1010 | ajapted | 2013-06-16 14:59:16 +1000 (Sun, 16 Jun 2013) | 2 lines Use Wad_file::Validate() instead of FileExists() where appropriate. ------------------------------------------------------------------------ r1009 | ajapted | 2013-06-16 14:43:26 +1000 (Sun, 16 Jun 2013) | 2 lines Validate all given pwad files (make sure they exist, etc). ------------------------------------------------------------------------ r1008 | ajapted | 2013-06-16 14:40:42 +1000 (Sun, 16 Jun 2013) | 3 lines Wad code: added Validate() static method to check if a wad exists and is indeed a WAD file. ------------------------------------------------------------------------ r1007 | ajapted | 2013-06-16 13:58:10 +1000 (Sun, 16 Jun 2013) | 3 lines Fixed CMD_OpenFileMap() to confirm with user when the current map has been modified. ------------------------------------------------------------------------ r1006 | ajapted | 2013-06-16 13:54:32 +1000 (Sun, 16 Jun 2013) | 3 lines Allow any number of given pwad files (in Pwad_list), only limit them when creating the 'Given Files' menu. ------------------------------------------------------------------------ r1005 | ajapted | 2013-06-16 13:45:44 +1000 (Sun, 16 Jun 2013) | 9 lines Implemented "GivenFile" command which supports loading the next / previous file in the given files list, with default bindings on 'N' and 'P' keys. This makes it easy to step through a large group of wads. The command also supports "first" and "last" keywords, but these are not bound to any keys by default. Also moved binding of PRUNE command from 'P' --> 'p' key. ------------------------------------------------------------------------ r1004 | ajapted | 2013-06-16 11:49:30 +1000 (Sun, 16 Jun 2013) | 2 lines Tidied up the latest 'Recent Files' handling code. ------------------------------------------------------------------------ r1003 | ajapted | 2013-06-16 11:35:29 +1000 (Sun, 16 Jun 2013) | 2 lines Dead code removal : CMD_OpenRecentMap() and UI_RecentFiles dialog. ------------------------------------------------------------------------ r1002 | ajapted | 2013-06-14 21:53:11 +1000 (Fri, 14 Jun 2013) | 3 lines More work on new 'File/Recent Files' sub-menu, which is working now, though the code needs some tidying up... ------------------------------------------------------------------------ r1001 | ajapted | 2013-06-14 21:02:25 +1000 (Fri, 14 Jun 2013) | 7 lines Partial work changing 'File/Recent Files' into a sub-menu which is populated at startup with the recent file list. This commit has the code to populate the sub-menu. Also: disable (gray out) the 'Given Files' sub-menu when there is not multiple specified filenames. ------------------------------------------------------------------------ r1000 | ajapted | 2013-06-14 19:38:26 +1000 (Fri, 14 Jun 2013) | 3 lines Made -file option accept multiple filenames, adding them to Pwad_list as per loose filenames. ------------------------------------------------------------------------ r999 | ajapted | 2013-06-14 18:45:37 +1000 (Fri, 14 Jun 2013) | 3 lines Makefile.xming : removed -lshfolder from linkage [was only there to test a binary under Windows 95]. ------------------------------------------------------------------------ r998 | ajapted | 2013-06-14 16:52:30 +1000 (Fri, 14 Jun 2013) | 3 lines Implemented a 'Given Files' sub-menu of the File menu, which is populated when Eureka is run with a list of wad files. ------------------------------------------------------------------------ r997 | ajapted | 2013-06-14 15:23:58 +1000 (Fri, 14 Jun 2013) | 2 lines VM: checked in a Vim syntax file for the scripting language. ------------------------------------------------------------------------ r996 | ajapted | 2013-06-14 15:23:01 +1000 (Fri, 14 Jun 2013) | 2 lines Makefiles: added VM code files to the build. ------------------------------------------------------------------------ r995 | ajapted | 2013-06-10 23:52:39 +1000 (Mon, 10 Jun 2013) | 2 lines VM: added missing code to resolve builtin functions. ------------------------------------------------------------------------ r994 | ajapted | 2013-06-10 23:40:45 +1000 (Mon, 10 Jun 2013) | 3 lines VM: worked on implementing the API functions, e.g. VM_CompileFile() and VM_Call(), and wrote some test code for loading / running a script. ------------------------------------------------------------------------ r993 | ajapted | 2013-06-10 22:00:38 +1000 (Mon, 10 Jun 2013) | 3 lines VM: more work integrating this code, it compiles now, but is still far away from being able to actually do anything.... ------------------------------------------------------------------------ r992 | ajapted | 2013-06-10 19:21:52 +1000 (Mon, 10 Jun 2013) | 2 lines VM: various work to integrate the VM code into its new environment... ------------------------------------------------------------------------ r991 | ajapted | 2013-06-10 18:10:20 +1000 (Mon, 10 Jun 2013) | 4 lines Began work on a scripting system. This commit contains code for a VM which I have been developing for a while now. It was originally based on the QCC compiler and execution engine from Quake, by Id Software. ------------------------------------------------------------------------ r990 | ajapted | 2013-06-10 16:56:48 +1000 (Mon, 10 Jun 2013) | 5 lines Removed the unfinished support for Radius Triggers (RTS), which is a feature of the EDGE source port. It would've required a lot more code to finish the RTS mode, not only parsing and re-creating the RSCRIPT lump, but also the ability to edit the scripts. ------------------------------------------------------------------------ r989 | ajapted | 2013-06-10 16:39:36 +1000 (Mon, 10 Jun 2013) | 1 line Version bump ------------------------------------------------------------------------ r988 | ajapted | 2013-06-10 15:27:13 +1000 (Mon, 10 Jun 2013) | 3 lines Changed PASTE behavior : place objects around their true centre, instead of around the thing or vertex which is closest to the centre. ------------------------------------------------------------------------ r987 | ajapted | 2013-06-10 15:18:36 +1000 (Mon, 10 Jun 2013) | 4 lines Added 'reselect_second_vertex' variable to control when adding a linedef onto an existing vertex (or line) if the second vertex will be selected. ------------------------------------------------------------------------ r986 | ajapted | 2013-06-10 15:13:28 +1000 (Mon, 10 Jun 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r985 | printz | 2013-05-29 07:23:50 +1000 (Wed, 29 May 2013) | 1 line osx: FLTK is now statically linked ------------------------------------------------------------------------ r984 | ajapted | 2013-05-07 22:30:00 +1000 (Tue, 07 May 2013) | 3 lines Tweaked BA_ChecksumLevel() to produce checksums the same as before, so that persistent data for previously edited maps gets found. ------------------------------------------------------------------------ r983 | ajapted | 2013-05-06 13:19:33 +1000 (Mon, 06 May 2013) | 3 lines Fixed crash bug in BA_ChecksumLevel(), used when loading and saving a map, occurring when a linedef was missing the right sidedef. ------------------------------------------------------------------------ r981 | ajapted | 2013-05-01 15:11:48 +1000 (Wed, 01 May 2013) | 2 lines Preferences: leave_offsets_alone now defaults to TRUE. ------------------------------------------------------------------------ r968 | ajapted | 2013-04-28 21:07:50 +1000 (Sun, 28 Apr 2013) | 2 lines TODO: minor update. ------------------------------------------------------------------------ r967 | ajapted | 2013-04-28 21:07:23 +1000 (Sun, 28 Apr 2013) | 2 lines More grid-color tweakage. ------------------------------------------------------------------------ r943 | ajapted | 2013-03-16 21:57:03 +1100 (Sat, 16 Mar 2013) | 2 lines Grid: color tweakage. ------------------------------------------------------------------------ r942 | ajapted | 2013-03-16 11:19:44 +1100 (Sat, 16 Mar 2013) | 2 lines Grid: improved the simple grid to show flat boundaries. ------------------------------------------------------------------------ r941 | ajapted | 2013-03-16 09:25:33 +1100 (Sat, 16 Mar 2013) | 3 lines Fixed the selection after a sector merge (the "gone away" sectors were still in the selection, preventing a subsequent merge). ------------------------------------------------------------------------ r940 | ajapted | 2013-03-16 09:17:33 +1100 (Sat, 16 Mar 2013) | 2 lines Version bump after 0.95 release. ------------------------------------------------------------------------ r939 | ajapted | 2013-03-16 09:16:08 +1100 (Sat, 16 Mar 2013) | 2 lines CHANGES.txt : added fresh one (post v0.95 release). ------------------------------------------------------------------------ r938 | ajapted | 2013-03-03 11:20:04 +1100 (Sun, 03 Mar 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r937 | ajapted | 2013-03-01 11:09:50 +1100 (Fri, 01 Mar 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r936 | ajapted | 2013-02-25 10:20:28 +1100 (Mon, 25 Feb 2013) | 2 lines Moved CHANGES.txt --> changelog/095.txt [after the 0.95 release] ------------------------------------------------------------------------ r935 | ajapted | 2013-02-25 10:17:39 +1100 (Mon, 25 Feb 2013) | 2 lines bindings.cfg : added SHIFT + cursor keys for scrolling in bigger steps. ------------------------------------------------------------------------ r934 | ajapted | 2013-02-24 15:44:50 +1100 (Sun, 24 Feb 2013) | 2 lines TODO : small addition. ------------------------------------------------------------------------ r933 | ajapted | 2013-02-24 15:36:11 +1100 (Sun, 24 Feb 2013) | 2 lines Updated doc/History.txt with SVN changes since last release. ------------------------------------------------------------------------ r932 | ajapted | 2013-02-24 15:30:07 +1100 (Sun, 24 Feb 2013) | 2 lines Pack-source script: copy the 'osx' directory too. ------------------------------------------------------------------------ r931 | ajapted | 2013-02-24 15:25:07 +1100 (Sun, 24 Feb 2013) | 2 lines MacOSX: fixed bug in Determine_HomeDir() using 'path' twice. ------------------------------------------------------------------------ r930 | printz | 2013-02-23 21:26:12 +1100 (Sat, 23 Feb 2013) | 1 line Bumped PLIST version ------------------------------------------------------------------------ r929 | printz | 2013-02-23 21:13:44 +1100 (Sat, 23 Feb 2013) | 1 line Removed deleted file references in the xcode project ------------------------------------------------------------------------ r928 | ajapted | 2013-02-23 20:11:21 +1100 (Sat, 23 Feb 2013) | 2 lines Win32 / installer: fixed NSIS script to require "admin" rights. ------------------------------------------------------------------------ r927 | ajapted | 2013-02-23 17:49:36 +1100 (Sat, 23 Feb 2013) | 2 lines Pack-source script: updated for 'changelogs' folder. ------------------------------------------------------------------------ r926 | ajapted | 2013-02-23 17:48:30 +1100 (Sat, 23 Feb 2013) | 2 lines Moved changelog documents from docs/ --> changelogs/ ------------------------------------------------------------------------ r925 | ajapted | 2013-02-23 17:46:31 +1100 (Sat, 23 Feb 2013) | 2 lines New top-level folder 'changelogs' -- no prizes for guessing what will go in there! ------------------------------------------------------------------------ r924 | ajapted | 2013-02-23 17:39:06 +1100 (Sat, 23 Feb 2013) | 2 lines README.txt : updated keys for 'd' and 'm' in Things mode. ------------------------------------------------------------------------ r923 | ajapted | 2013-02-23 16:38:12 +1100 (Sat, 23 Feb 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r922 | ajapted | 2013-02-23 16:35:31 +1100 (Sat, 23 Feb 2013) | 3 lines Config: added 'swap_sidedefs' preference setting which swaps the upper and lower sidedefs in the Linedef panel (i.e. to Upper/Middle/Lower). ------------------------------------------------------------------------ r921 | ajapted | 2013-02-23 15:45:40 +1100 (Sat, 23 Feb 2013) | 2 lines Debian: updated control info (mainly version #) for 0.95 release. ------------------------------------------------------------------------ r920 | ajapted | 2013-02-23 15:41:53 +1100 (Sat, 23 Feb 2013) | 2 lines TODO.txt : another addition. ------------------------------------------------------------------------ r919 | ajapted | 2013-02-23 15:33:01 +1100 (Sat, 23 Feb 2013) | 2 lines README.txt : minor changes to FEATURES section. ------------------------------------------------------------------------ r918 | ajapted | 2013-02-23 15:31:39 +1100 (Sat, 23 Feb 2013) | 2 lines TODO updated. ------------------------------------------------------------------------ r917 | ajapted | 2013-02-22 19:27:32 +1100 (Fri, 22 Feb 2013) | 4 lines 1. made UI_ChooseMap window shorter 2. fixed weird order of "ExMx" level names in UI_ChooseMap 3. fixed unclickable bottom row of buttons in UI_OpenMap dialog ------------------------------------------------------------------------ r916 | ajapted | 2013-02-22 19:14:58 +1100 (Fri, 22 Feb 2013) | 2 lines Fixed the mode widget on info bar not having any color at startup. ------------------------------------------------------------------------ r915 | ajapted | 2013-02-22 19:08:35 +1100 (Fri, 22 Feb 2013) | 2 lines Tweaked background colors of some widgets for non-plastic themes. ------------------------------------------------------------------------ r914 | ajapted | 2013-02-22 17:26:14 +1100 (Fri, 22 Feb 2013) | 5 lines Made map buttons in ChooseMap and OpenMap dialogs be ordered differently, increasing across-ways instead of down in columns. That's because I want the map buttons to be placed in predictable places (e.g. the layout does not change depending on number of maps present) -- for better usability. ------------------------------------------------------------------------ r913 | ajapted | 2013-02-22 16:58:48 +1100 (Fri, 22 Feb 2013) | 3 lines Partial work to make ChooseMap and OpenMap dialogs consistent w.r.t the map selection buttons -- same color, font size and positioning. ------------------------------------------------------------------------ r912 | ajapted | 2013-02-22 16:57:42 +1100 (Fri, 22 Feb 2013) | 2 lines Queiten another warning. ------------------------------------------------------------------------ r911 | ajapted | 2013-02-22 16:29:09 +1100 (Fri, 22 Feb 2013) | 2 lines Code: quieten a compiler warning. ------------------------------------------------------------------------ r910 | ajapted | 2013-02-22 15:49:54 +1100 (Fri, 22 Feb 2013) | 2 lines Dead code removal : SliceLineDef() and MakeRectangularNook(). ------------------------------------------------------------------------ r909 | ajapted | 2013-02-22 15:44:42 +1100 (Fri, 22 Feb 2013) | 2 lines Makefiles: added -fno-strict-aliasing to compiler flags. ------------------------------------------------------------------------ r908 | ajapted | 2013-02-22 15:35:02 +1100 (Fri, 22 Feb 2013) | 2 lines Win32 / installer: create a shortcut in the Start Menu. ------------------------------------------------------------------------ r907 | ajapted | 2013-02-22 13:57:16 +1100 (Fri, 22 Feb 2013) | 3 lines View menu: removed the 'Toggle Fullscreen' command, the FLTK fullscreen() method fails miserably on every platform tested, especially Windows XP. ------------------------------------------------------------------------ r906 | ajapted | 2013-02-21 23:30:12 +1100 (Thu, 21 Feb 2013) | 3 lines Wad code: fixed some bugs when adding level lumps -- especially need to fix all the groups when the 'insert_point' is valid. ------------------------------------------------------------------------ r905 | ajapted | 2013-02-21 19:21:36 +1100 (Thu, 21 Feb 2013) | 4 lines Prefs: reset colors when user chooses the "Bright" setting. Unfortunately I don't know how to reset the "Default" colors.... ------------------------------------------------------------------------ r904 | ajapted | 2013-02-21 19:13:10 +1100 (Thu, 21 Feb 2013) | 2 lines Prefs: when 'Custom Colors' is enabled, update the colors immediately. ------------------------------------------------------------------------ r903 | ajapted | 2013-02-21 19:06:02 +1100 (Thu, 21 Feb 2013) | 2 lines Prefs: fixed (I think) the color buttons not updating to a new color. ------------------------------------------------------------------------ r902 | ajapted | 2013-02-21 17:38:56 +1100 (Thu, 21 Feb 2013) | 4 lines Win32: when reading Install_Dir from the registry, ensure that the string is NUL-terminated (the MSDN docs mention that the string may have been stored without a trailing NUL). ------------------------------------------------------------------------ r901 | ajapted | 2013-02-21 17:28:21 +1100 (Thu, 21 Feb 2013) | 3 lines Win32: attempt to fix the problem reading the $Install_Dir registry value, which was returning (I think) UCS2 format unicode instead of ASCII. ------------------------------------------------------------------------ r900 | ajapted | 2013-02-21 17:16:54 +1100 (Thu, 21 Feb 2013) | 2 lines Renamed global var: 'local_dir' --> 'cache_dir' ------------------------------------------------------------------------ r899 | ajapted | 2013-02-21 17:14:53 +1100 (Thu, 21 Feb 2013) | 2 lines MacOSX: set the 'cache_dir' to $HOME/Library/Caches/eureka-editor ------------------------------------------------------------------------ r898 | ajapted | 2013-02-21 16:49:06 +1100 (Thu, 21 Feb 2013) | 2 lines Removed dummy mods/foo.bar file. ------------------------------------------------------------------------ r897 | ajapted | 2013-02-21 16:48:42 +1100 (Thu, 21 Feb 2013) | 2 lines Win32 / nsis_build: I forgot to copy the executable, duh. ------------------------------------------------------------------------ r896 | ajapted | 2013-02-21 16:46:05 +1100 (Thu, 21 Feb 2013) | 4 lines Win32: reworked NSIS script and Makefile.xming so that we first create a replicate of the final directory structure. Main reason is because we need to convert the text files to MSDOS/Windows format. ------------------------------------------------------------------------ r895 | ajapted | 2013-02-21 15:45:18 +1100 (Thu, 21 Feb 2013) | 2 lines svn:ignore update ------------------------------------------------------------------------ r894 | ajapted | 2013-02-21 15:44:24 +1100 (Thu, 21 Feb 2013) | 2 lines Added empty mods/foo.bar file, to keep NSIS happy. ------------------------------------------------------------------------ r893 | ajapted | 2013-02-21 15:41:23 +1100 (Thu, 21 Feb 2013) | 2 lines Version bump to 0.95 -- for upcoming release. ------------------------------------------------------------------------ r892 | ajapted | 2013-02-21 15:40:43 +1100 (Thu, 21 Feb 2013) | 2 lines Win32: some fixes for building the NSIS installer. ------------------------------------------------------------------------ r891 | ajapted | 2013-02-21 15:22:38 +1100 (Thu, 21 Feb 2013) | 2 lines Win32: created obj_win32/glbsp folder. ------------------------------------------------------------------------ r890 | ajapted | 2013-02-21 15:21:47 +1100 (Thu, 21 Feb 2013) | 2 lines Win32: hmmmm, PathAppend() doesn't seem available -- use strcat() instead. ------------------------------------------------------------------------ r889 | ajapted | 2013-02-21 15:16:00 +1100 (Thu, 21 Feb 2013) | 2 lines Fixed typo in last commit. ------------------------------------------------------------------------ r888 | ajapted | 2013-02-21 15:14:52 +1100 (Thu, 21 Feb 2013) | 4 lines Win32 port: 1. fixed not appending our own folder name to %APPDATA% 2. fixed a few compiling issues (e.g. MOD_SHIFT conflicts with windows headers) ------------------------------------------------------------------------ r887 | ajapted | 2013-02-21 14:56:52 +1100 (Thu, 21 Feb 2013) | 2 lines Win32: more work on Makefile.xming, should be usable now (barring mistakes). ------------------------------------------------------------------------ r886 | ajapted | 2013-02-21 14:55:38 +1100 (Thu, 21 Feb 2013) | 2 lines Win32: added folder for build objects: obj_win32/ ------------------------------------------------------------------------ r885 | ajapted | 2013-02-21 14:54:00 +1100 (Thu, 21 Feb 2013) | 2 lines Win32: created a resource file : eureka.rc ------------------------------------------------------------------------ r884 | ajapted | 2013-02-21 14:38:14 +1100 (Thu, 21 Feb 2013) | 2 lines Win32: tweaked name of install directory and registry key. ------------------------------------------------------------------------ r883 | ajapted | 2013-02-21 14:37:08 +1100 (Thu, 21 Feb 2013) | 3 lines Win32: started work on Makefile.xming -- uses a cross-compiler to make the Windows executable. ------------------------------------------------------------------------ r882 | ajapted | 2013-02-21 13:11:31 +1100 (Thu, 21 Feb 2013) | 5 lines Win32: implemented Determine_HomeDir() logic, which uses SHGetFolderPath to determine the %APPDATA% folder. Also have fallback for 'local_dir' value (needed for Linux). ------------------------------------------------------------------------ r881 | ajapted | 2013-02-21 12:57:05 +1100 (Thu, 21 Feb 2013) | 2 lines Use $local_dir (not $home_dir) as prefix for 'cache' and 'backups' folders. ------------------------------------------------------------------------ r880 | ajapted | 2013-02-21 12:51:57 +1100 (Thu, 21 Feb 2013) | 10 lines 1. implemented WIN32 logic to read the "Install_Dir" registry key which is created by the NSIS installer 2. made FatalError() on WIN32 use the system MessageBox() function when FLTK has not been initialized yet. 3. added 'local_dir' global var, this will be the place for the cache and backup folders -- i.e. non-roamable stuff. On Linux it will just be the same as $home_dir. ------------------------------------------------------------------------ r879 | ajapted | 2013-02-21 11:49:16 +1100 (Thu, 21 Feb 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r878 | ajapted | 2013-02-21 11:48:36 +1100 (Thu, 21 Feb 2013) | 2 lines Updated README.txt and CHANGES.txt -- preparing for a release. ------------------------------------------------------------------------ r877 | ajapted | 2013-02-21 11:35:15 +1100 (Thu, 21 Feb 2013) | 2 lines Checked in basic NSIS script to create a Win32 installer : eureka.nsi ------------------------------------------------------------------------ r876 | ajapted | 2013-02-19 22:23:44 +1100 (Tue, 19 Feb 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r875 | ajapted | 2013-02-19 22:16:21 +1100 (Tue, 19 Feb 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r874 | ajapted | 2013-02-19 22:09:43 +1100 (Tue, 19 Feb 2013) | 2 lines Default Props panel: now hidden by default. ------------------------------------------------------------------------ r873 | ajapted | 2013-02-19 22:05:07 +1100 (Tue, 19 Feb 2013) | 2 lines log viewer tweak ------------------------------------------------------------------------ r872 | ajapted | 2013-02-19 22:03:30 +1100 (Tue, 19 Feb 2013) | 3 lines Log Viewer: reduced MAX_LINES to 600, and made it jump to the bottom when adding a new line. ------------------------------------------------------------------------ r871 | ajapted | 2013-02-19 21:56:26 +1100 (Tue, 19 Feb 2013) | 2 lines Print the current time (in the log file) at startup. ------------------------------------------------------------------------ r870 | ajapted | 2013-02-19 21:49:59 +1100 (Tue, 19 Feb 2013) | 2 lines main.h : ensure we #include for WIN32 builds ------------------------------------------------------------------------ r869 | ajapted | 2013-02-19 21:38:58 +1100 (Tue, 19 Feb 2013) | 8 lines Log file rejigging: 1. we always create a log file, default is $home_dir/logs.txt 2. all messages are sent to stdout (unless --quiet is used) 3. remember messages in memory until LogViewer window is opened 4. after opening the log file, write saved messages to it 5. after created LogViewer window, grab the saved messages 6. tweaks to debug handling ------------------------------------------------------------------------ r868 | ajapted | 2013-02-19 18:12:36 +1100 (Tue, 19 Feb 2013) | 3 lines Config: added "-m" as short option for "--merge", and "-v" as short option for "--version". ------------------------------------------------------------------------ r867 | ajapted | 2013-02-19 17:56:53 +1100 (Tue, 19 Feb 2013) | 3 lines Removed 'r_misc' code files -- since we longer use anything in there (such as the SetWindowSize() function and ScrMaxX/Y variables). ------------------------------------------------------------------------ r866 | ajapted | 2013-02-19 16:53:54 +1100 (Tue, 19 Feb 2013) | 3 lines Log Viewer: added 'View/Logs' menu to show the log viewer, and don't show it automatically on start-up. ------------------------------------------------------------------------ r865 | ajapted | 2013-02-19 16:42:58 +1100 (Tue, 19 Feb 2013) | 4 lines Began working on a Log Viewing window. So far the window is opened at startup, and it contains only an Fl_Browser to show the text. Also the LogPrintf() function has been hacked up to send the lines into it. ------------------------------------------------------------------------ r864 | ajapted | 2013-02-19 16:17:15 +1100 (Tue, 19 Feb 2013) | 2 lines Moved Int_TmpStr() function to lib_util.cc/h ------------------------------------------------------------------------ r863 | ajapted | 2013-02-19 15:26:19 +1100 (Tue, 19 Feb 2013) | 2 lines minor menu tweak. ------------------------------------------------------------------------ r862 | ajapted | 2013-02-19 15:23:03 +1100 (Tue, 19 Feb 2013) | 2 lines bindings.cfg : swapped grid keys, 'g' now goes smaller, 'G' goes bigger. ------------------------------------------------------------------------ r861 | ajapted | 2013-02-19 15:20:29 +1100 (Tue, 19 Feb 2013) | 3 lines 1. made sure every Beep() call has a message 2. removed the no-message Beep() function ------------------------------------------------------------------------ r860 | ajapted | 2013-02-19 14:43:44 +1100 (Tue, 19 Feb 2013) | 2 lines File menu: use CTRL-M for Manage Wads, CTRL-P for Preferences. ------------------------------------------------------------------------ r859 | ajapted | 2013-02-19 14:38:28 +1100 (Tue, 19 Feb 2013) | 5 lines Prefs / key binds: 1. save the bindings when APPLY button is clicked 2. fixed bug in M_SaveBindings() which skipped the general context 3. changed ordering which contexts are displayed in the key browser ------------------------------------------------------------------------ r858 | ajapted | 2013-02-19 14:27:21 +1100 (Tue, 19 Feb 2013) | 2 lines bindings.cfg : moved PruneUnused from 'p' --> 'P' key ------------------------------------------------------------------------ r857 | ajapted | 2013-02-19 13:32:11 +1100 (Tue, 19 Feb 2013) | 7 lines Prefs / key binds: 1. changed "Add" button into a "Copy" button, which copies the line and automatically goes into grab-key mode 2. moved "Bind" button to the top 3. made UI_EditKey dialog give focus to the function name input 4. fixed "Edit" button so arrow keys control the browser afterwards ------------------------------------------------------------------------ r856 | ajapted | 2013-02-19 13:03:53 +1100 (Tue, 19 Feb 2013) | 3 lines Prefs / key binds: implemented good method to detect conflicting key bindings -- will be shown in RED no matter how the list is sorted. ------------------------------------------------------------------------ r855 | ajapted | 2013-02-19 12:46:01 +1100 (Tue, 19 Feb 2013) | 3 lines Prefs / key binds: got the "Edit" and "Add" buttons working, using the values chosen in the UI_EditKey dialog. ------------------------------------------------------------------------ r854 | ajapted | 2013-02-18 23:10:56 +1100 (Mon, 18 Feb 2013) | 2 lines TODO updated. ------------------------------------------------------------------------ r853 | ajapted | 2013-02-18 23:02:38 +1100 (Mon, 18 Feb 2013) | 2 lines UI_EditKey dialog: when validating func_name, check the brackets. ------------------------------------------------------------------------ r852 | ajapted | 2013-02-18 22:58:20 +1100 (Mon, 18 Feb 2013) | 2 lines UI_EditKey dialog: implemented ValidateFunc(). ------------------------------------------------------------------------ r851 | ajapted | 2013-02-18 22:52:48 +1100 (Mon, 18 Feb 2013) | 4 lines 1. fixed M_ParseKeyString() not handling hex values like "0x1234" 2. added some synonyms to the M_ParseKeyString() key table, such as "RETURN" for "ENTER", "INSERT" for "INS", etc... ------------------------------------------------------------------------ r850 | ajapted | 2013-02-18 22:41:53 +1100 (Mon, 18 Feb 2013) | 3 lines UI_EditKey dialog: implemented validation of the key name (drawn red when the name fails to parse). ------------------------------------------------------------------------ r849 | ajapted | 2013-02-18 22:23:51 +1100 (Mon, 18 Feb 2013) | 7 lines Prefs / key binds: show duplicated key bindings (same mode and key) using red text in the key browser. This only works when the two keys are together in the list (i.e. the list has been recently sorted, and the sort criterion was either KEY or MODE). It could be done better -- but this will suffice for now. ------------------------------------------------------------------------ r848 | ajapted | 2013-02-18 22:02:05 +1100 (Mon, 18 Feb 2013) | 2 lines Version bump to 0.92 ------------------------------------------------------------------------ r847 | ajapted | 2013-02-18 16:39:04 +1100 (Mon, 18 Feb 2013) | 4 lines Prefs / key binds: 1. setup the initial values for UI_EditKey dialog 2. renamed 'dialog' --> 'prefs' in all UI_Preferences callbacks ------------------------------------------------------------------------ r846 | ajapted | 2013-02-18 16:27:00 +1100 (Mon, 18 Feb 2013) | 3 lines Prefs / key binds: bit more work on UI_EditKey dialog, fixed a few layout issues, added Run() method, implemented Close and OK buttons. ------------------------------------------------------------------------ r845 | ajapted | 2013-02-18 10:31:29 +1100 (Mon, 18 Feb 2013) | 2 lines CHANGELOG and TODO update. ------------------------------------------------------------------------ r844 | ajapted | 2013-02-18 10:27:00 +1100 (Mon, 18 Feb 2013) | 3 lines When saving a map, prefer existing location in the wad directory (i.e. if map already exists, don't place lumps at end of wad). ------------------------------------------------------------------------ r843 | ajapted | 2013-02-17 22:36:36 +1100 (Sun, 17 Feb 2013) | 2 lines Quantize: status message when cannot move some things / vertices. ------------------------------------------------------------------------ r842 | ajapted | 2013-02-17 22:31:18 +1100 (Sun, 17 Feb 2013) | 2 lines CHANGELOG updated. ------------------------------------------------------------------------ r841 | ajapted | 2013-02-17 22:26:51 +1100 (Sun, 17 Feb 2013) | 2 lines Ensure displayed level name is always uppercase. ------------------------------------------------------------------------ r840 | ajapted | 2013-02-17 21:38:58 +1100 (Sun, 17 Feb 2013) | 6 lines Prefs / key binds: initial work on a UI_EditKey dialog, which allows the user to change the key, context and function of a binding. So far only the layout is done (code is output of Fluid with some tidying up). ------------------------------------------------------------------------ r839 | ajapted | 2013-02-17 21:04:03 +1100 (Sun, 17 Feb 2013) | 3 lines Prefs / key binds: added two utility functions: M_GetBindingInfo() and M_IsBindingFuncValid(). ------------------------------------------------------------------------ r838 | ajapted | 2013-02-17 20:41:07 +1100 (Sun, 17 Feb 2013) | 6 lines Prefs / key binds: 1. the ESCAPE key now cancels a bind-in-progress 2. added some shortcut keys: ENTER for "Bind", INSERT and DELETE 3. ensure key browser gets focus after these operations so user can use up/down arrow keys to move through the list. ------------------------------------------------------------------------ r837 | ajapted | 2013-02-17 19:58:52 +1100 (Sun, 17 Feb 2013) | 2 lines TODO.txt : update ------------------------------------------------------------------------ r836 | ajapted | 2013-02-17 19:55:59 +1100 (Sun, 17 Feb 2013) | 7 lines Prefs / key binds: 1. no longer use the 'data' field of browser lines for bind indices, since browser lines map one-to-one with the local bindings 2. renamed 'awaiting_slot' --> 'awaiting_line' and made zero be the "off" value ------------------------------------------------------------------------ r835 | ajapted | 2013-02-17 19:45:34 +1100 (Sun, 17 Feb 2013) | 2 lines Prefs / key binds: implemented the "Delete" button. ------------------------------------------------------------------------ r834 | ajapted | 2013-02-17 19:34:03 +1100 (Sun, 17 Feb 2013) | 3 lines Prefs / key binds: wrote M_AddLocalBinding() and M_DeleteLocalBinding() functions. ------------------------------------------------------------------------ r833 | ajapted | 2013-02-17 19:06:22 +1100 (Sun, 17 Feb 2013) | 2 lines Prefs / key bindings: message tweaks. ------------------------------------------------------------------------ r832 | ajapted | 2013-02-17 17:08:10 +1100 (Sun, 17 Feb 2013) | 8 lines Prefs / key bindings: 1. made key browser higher (i.e. revert previous change, since I don't think a message area will be needded) 2. when waiting for a key press, give the whole preferences window the keyboard focus (via Fl::focus). This fixes certain keys not being bindable (like SPACE). ------------------------------------------------------------------------ r831 | ajapted | 2013-02-17 16:44:00 +1100 (Sun, 17 Feb 2013) | 2 lines Prefs / key bindings: updated code for m_keys rejiggage. ------------------------------------------------------------------------ r830 | ajapted | 2013-02-17 15:47:23 +1100 (Sun, 17 Feb 2013) | 2 lines Prefs / key bindings: better error messages for M_ChangeBindingFunc(). ------------------------------------------------------------------------ r829 | ajapted | 2013-02-17 15:42:41 +1100 (Sun, 17 Feb 2013) | 5 lines Prefs / key bindings: reworked code in m_keys, it now follows a model where the key bindings are copied and the dialog will query and change that copy. The M_ApplyBindings() function will transfer them back. Also the M_ChangeBindingFunc() now returns an error string. ------------------------------------------------------------------------ r828 | ajapted | 2013-02-17 15:19:21 +1100 (Sun, 17 Feb 2013) | 4 lines Prefs / key bindings: 1. renamed CONTEXT column --> MODE 2. began work on "Add", "Delete" and "Load Defaults" buttons ------------------------------------------------------------------------ r827 | ajapted | 2013-02-17 14:54:56 +1100 (Sun, 17 Feb 2013) | 4 lines Prefs / key bindings: 1. changed order of columns to: KEY | CONTEXT | FUNCTION 2. added some space underneath the list for a message ------------------------------------------------------------------------ r826 | ajapted | 2013-02-17 14:05:03 +1100 (Sun, 17 Feb 2013) | 3 lines Preferences dialog: changed "OK" button to "Apply", and added a "Discard" button which does not keep the changes made. ------------------------------------------------------------------------ r825 | ajapted | 2013-02-16 15:15:28 +1100 (Sat, 16 Feb 2013) | 3 lines Prefs / key bindings: implemented the "Edit" button, with code to parse the entered string, find the command and store it + parameters. ------------------------------------------------------------------------ r824 | ajapted | 2013-02-16 13:37:41 +1100 (Sat, 16 Feb 2013) | 2 lines Prefs / key bindings: can actually change a key binding now. ------------------------------------------------------------------------ r823 | ajapted | 2013-02-16 12:44:02 +1100 (Sat, 16 Feb 2013) | 4 lines Prefs / key bindings: worked on ability to show in the current binding (with background changed to yellow) and the next key-press will become the new binding -- or clear the binding on a mouse press. ------------------------------------------------------------------------ r822 | ajapted | 2013-02-16 11:46:55 +1100 (Sat, 16 Feb 2013) | 3 lines Prefs / key bindings: improved display of keys with modifiers, show the modifier in its own column (so that the bare keys are aligned). ------------------------------------------------------------------------ r821 | ajapted | 2013-02-16 11:36:23 +1100 (Sat, 16 Feb 2013) | 4 lines Prefs / key bindings: implemented the different sorting modes -- clicking on the header buttons will select that as the sort column, or toggle reverse mode if it already was. ------------------------------------------------------------------------ r820 | ajapted | 2013-02-16 11:16:32 +1100 (Sat, 16 Feb 2013) | 2 lines Key handling: implemented a key compare function: M_KeyCmp() ------------------------------------------------------------------------ r819 | ajapted | 2013-02-16 11:05:17 +1100 (Sat, 16 Feb 2013) | 5 lines Prefs / key bindings: added M_SortBindingsToVec() which sorts the key bindings (actually an int vector) for display by the key browser. Different sorting methods are not implemented yet. ------------------------------------------------------------------------ r818 | ajapted | 2013-02-16 10:31:02 +1100 (Sat, 16 Feb 2013) | 2 lines Key handling: renamed 'global' context --> 'general'. ------------------------------------------------------------------------ r817 | ajapted | 2013-02-15 23:08:46 +1100 (Fri, 15 Feb 2013) | 2 lines Prefs / key bindings: renamed 'GROUP' column --> 'CONTEXT' ------------------------------------------------------------------------ r816 | ajapted | 2013-02-15 22:36:57 +1100 (Fri, 15 Feb 2013) | 2 lines Fluid work : prefs2.fl ------------------------------------------------------------------------ r815 | ajapted | 2013-02-15 22:36:05 +1100 (Fri, 15 Feb 2013) | 2 lines Prefs / key bindings: partial work on "Bind" and "Edit" buttons. ------------------------------------------------------------------------ r814 | ajapted | 2013-02-15 22:01:55 +1100 (Fri, 15 Feb 2013) | 3 lines Prefs / Key bindings: added buttons above the browser which show what each column is (and later will allow sorting by that column). ------------------------------------------------------------------------ r813 | ajapted | 2013-02-15 21:20:01 +1100 (Fri, 15 Feb 2013) | 3 lines Preference dialog: worked on a new "Keys" tab, which will allow the user to edit the key bindings. So far it can only display them. ------------------------------------------------------------------------ r812 | ajapted | 2013-02-15 21:18:28 +1100 (Fri, 15 Feb 2013) | 3 lines Key handling: added M_StringForBinding() function to format a binding into a string suitable for an Fl_Browser widget. ------------------------------------------------------------------------ r811 | ajapted | 2013-02-15 19:39:32 +1100 (Fri, 15 Feb 2013) | 3 lines bindings.cfg : minor change: use '/' to separate flags letters for LIN_SelectPath and SEC_SelectGroup. ------------------------------------------------------------------------ r810 | ajapted | 2013-02-15 17:16:16 +1100 (Fri, 15 Feb 2013) | 2 lines UI_Scroll: implemented the Scroll() method. ------------------------------------------------------------------------ r809 | ajapted | 2013-02-14 22:43:42 +1100 (Thu, 14 Feb 2013) | 2 lines Browser: started work to fix keyboard scrolling.... ------------------------------------------------------------------------ r808 | ajapted | 2013-02-14 22:21:47 +1100 (Thu, 14 Feb 2013) | 4 lines Fixed editor mode getting out-of-sync with the GUI (side panel etc) after loading a map with no user state. ------------------------------------------------------------------------ r807 | ajapted | 2013-02-14 22:17:14 +1100 (Thu, 14 Feb 2013) | 3 lines Fixed SNAP button which could become out-of-sync with the editor after loading a map with no user state. ------------------------------------------------------------------------ r806 | ajapted | 2013-02-14 22:11:40 +1100 (Thu, 14 Feb 2013) | 4 lines File / OpenMap: don't parse the EUREKA lump (and reload the IWAD and resource files) when the current pwad has not changed. ------------------------------------------------------------------------ r805 | ajapted | 2013-02-14 21:56:13 +1100 (Thu, 14 Feb 2013) | 4 lines Added bindings for CTRL + SPACE and CTRL + INSERT to re-enable the feature of forcing a new sector to be created (rather than correcting an existing one). Thanks to d1337r for the bug report. ------------------------------------------------------------------------ r804 | ajapted | 2013-02-05 14:32:43 +1100 (Tue, 05 Feb 2013) | 6 lines Added an 'error_mode' field to Editor_State_t -- when enabled, the current selection is drawn in bright red instead of blue. This will be used later by the error detection dialog. UI_Canvas: factored some common code --> DrawThing() method. ------------------------------------------------------------------------ r803 | ajapted | 2013-02-05 13:58:06 +1100 (Tue, 05 Feb 2013) | 2 lines CHANGELOG update and rearrangement. ------------------------------------------------------------------------ r802 | ajapted | 2013-02-05 13:55:23 +1100 (Tue, 05 Feb 2013) | 2 lines Scale Objects dialog: finished ability to scale Z of sectors. ------------------------------------------------------------------------ r801 | ajapted | 2013-02-05 11:53:13 +1100 (Tue, 05 Feb 2013) | 3 lines Scale Objects dialog: partial work to introduce a 'Z' component (hidden for modes where it doesn't make sense -- which is most of them). ------------------------------------------------------------------------ r800 | ajapted | 2013-02-05 11:51:26 +1100 (Tue, 05 Feb 2013) | 2 lines Checks.txt : minor addition ------------------------------------------------------------------------ r799 | ajapted | 2013-02-04 14:10:36 +1100 (Mon, 04 Feb 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r798 | ajapted | 2013-02-04 14:08:00 +1100 (Mon, 04 Feb 2013) | 3 lines Implemented new 'PruneUnused' command -- remove unused sectors, sidedefs and vertices. Default binding is on 'p' key. ------------------------------------------------------------------------ r797 | ajapted | 2013-02-03 22:03:16 +1100 (Sun, 03 Feb 2013) | 2 lines Yet another CHANGELOG update. ------------------------------------------------------------------------ r796 | ajapted | 2013-02-03 22:02:45 +1100 (Sun, 03 Feb 2013) | 4 lines 1. TH_Merge and VERT_Merge: support one selected + highlight 2. VERT_Merge: don't re-select the final vertex -- index can be wrong (due to deletions). ------------------------------------------------------------------------ r795 | ajapted | 2013-02-03 20:34:38 +1100 (Sun, 03 Feb 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r794 | ajapted | 2013-02-03 20:30:13 +1100 (Sun, 03 Feb 2013) | 4 lines Side panels: show blue background of 'Nombre' when a single object is selected. This is another visual cue that something is selected, especially when that object is off-screen. ------------------------------------------------------------------------ r793 | ajapted | 2013-02-03 19:09:00 +1100 (Sun, 03 Feb 2013) | 4 lines Fixed bug not clearing an after-drag selection when selecting a group of objects via the outline box. ------------------------------------------------------------------------ r792 | ajapted | 2013-02-03 17:19:15 +1100 (Sun, 03 Feb 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r791 | ajapted | 2013-02-03 17:18:08 +1100 (Sun, 03 Feb 2013) | 3 lines LIN_MergeTwo: support one selected + one highlighted, and merge the second linedef into the first (consistent with SEC_Merge). ------------------------------------------------------------------------ r790 | ajapted | 2013-02-03 17:14:10 +1100 (Sun, 03 Feb 2013) | 2 lines SEC_Merge: support one selected + one highlighted. ------------------------------------------------------------------------ r789 | ajapted | 2013-02-01 22:37:22 +1100 (Fri, 01 Feb 2013) | 2 lines CHANGELOG and TODO update. ------------------------------------------------------------------------ r788 | ajapted | 2013-02-01 22:35:21 +1100 (Fri, 01 Feb 2013) | 4 lines When merging vertices (especially the one being dragged), check for the situation where two linedefs would end up overlapping, if so then delete one of them (the one connected to the dragged vertex). ------------------------------------------------------------------------ r787 | ajapted | 2013-02-01 15:50:11 +1100 (Fri, 01 Feb 2013) | 3 lines Beep messages: ensure first letter is uppercase, also simplified a few of the messages. ------------------------------------------------------------------------ r786 | ajapted | 2013-02-01 15:41:22 +1100 (Fri, 01 Feb 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r785 | ajapted | 2013-02-01 15:39:43 +1100 (Fri, 01 Feb 2013) | 3 lines CMD_CopyProperties: implemented 2S --> 2S for linedef textures, with logic to "intelligently" decide which sides to copy. ------------------------------------------------------------------------ r784 | ajapted | 2013-02-01 15:20:28 +1100 (Fri, 01 Feb 2013) | 2 lines CMD_CopyProperties: implemented 2S --> 1S case for linedefs. ------------------------------------------------------------------------ r783 | ajapted | 2013-02-01 15:01:14 +1100 (Fri, 01 Feb 2013) | 2 lines CMD_CopyProperties: partial work to copy textures between linedefs. ------------------------------------------------------------------------ r782 | ajapted | 2013-02-01 12:00:36 +1100 (Fri, 01 Feb 2013) | 3 lines Fixed jerky RMB scrolling at large zoom factors, done by changing the grid fields 'orig_x' and 'orig_y' from int --> double. ------------------------------------------------------------------------ r781 | ajapted | 2013-01-30 22:32:28 +1100 (Wed, 30 Jan 2013) | 2 lines Yet another TODO / CHANGELOG update. ------------------------------------------------------------------------ r780 | ajapted | 2013-01-30 22:30:55 +1100 (Wed, 30 Jan 2013) | 3 lines Fixed (I hope) ClosestLine_XXX() and OppositeLineDef() functions so that they can never hit a vertex, by offsetting the (x,y) coord by 0.5 units. ------------------------------------------------------------------------ r779 | ajapted | 2013-01-30 22:07:02 +1100 (Wed, 30 Jan 2013) | 3 lines LineDef panel: fixed CRASH when clicking on a flag button and no linedef was selected. ------------------------------------------------------------------------ r778 | ajapted | 2013-01-30 21:37:46 +1100 (Wed, 30 Jan 2013) | 3 lines LineDef panel: made the flag widgets ("upper unpeg" etc) easier to click on, the effective width covers the text (not just the checkbox). ------------------------------------------------------------------------ r777 | ajapted | 2013-01-30 21:15:37 +1100 (Wed, 30 Jan 2013) | 2 lines CHANGELOG and TODO updated. ------------------------------------------------------------------------ r776 | ajapted | 2013-01-30 21:10:48 +1100 (Wed, 30 Jan 2013) | 2 lines Config: added 'backup_max_files' and 'backup_max_space' vars. ------------------------------------------------------------------------ r775 | ajapted | 2013-01-30 21:04:28 +1100 (Wed, 30 Jan 2013) | 2 lines Removed the 'escape_key_quits' config var (and from Prefs dialog). ------------------------------------------------------------------------ r774 | ajapted | 2013-01-30 20:55:42 +1100 (Wed, 30 Jan 2013) | 1 line tweak ------------------------------------------------------------------------ r773 | ajapted | 2013-01-30 20:55:22 +1100 (Wed, 30 Jan 2013) | 4 lines Backup system: implemented the directory scanning (to get the low and high values which are present). The backup system is enabled now, and it seems to be working OK. ------------------------------------------------------------------------ r772 | ajapted | 2013-01-30 19:58:56 +1100 (Wed, 30 Jan 2013) | 4 lines Backup system: implemented logic to limit backups (of a certain wad) to a certain space limit -- currently hard-coded as 100 MB. ------------------------------------------------------------------------ r771 | ajapted | 2013-01-30 16:57:44 +1100 (Wed, 30 Jan 2013) | 2 lines Wad code: set offset to 0 for zero-length lumps. ------------------------------------------------------------------------ r770 | ajapted | 2013-01-30 15:52:49 +1100 (Wed, 30 Jan 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r769 | ajapted | 2013-01-30 15:44:25 +1100 (Wed, 30 Jan 2013) | 2 lines Wad code: small optimisation for zero-length lumps. ------------------------------------------------------------------------ r768 | ajapted | 2013-01-30 15:37:12 +1100 (Wed, 30 Jan 2013) | 4 lines Wad code: implemented new PositionForWrite() logic which tries to use free space in the wad file. We also check that a lump did not write more than the 'max_size' value given to AddLump(). ------------------------------------------------------------------------ r767 | ajapted | 2013-01-30 14:29:24 +1100 (Wed, 30 Jan 2013) | 3 lines Wad code: implemented private FindFreeSpace() method, which can find an unused area of a given size. ------------------------------------------------------------------------ r766 | ajapted | 2013-01-30 13:01:17 +1100 (Wed, 30 Jan 2013) | 2 lines status message tweak. ------------------------------------------------------------------------ r765 | ajapted | 2013-01-30 12:59:08 +1100 (Wed, 30 Jan 2013) | 2 lines Made the status area more distinct: bold font, vertical divider. ------------------------------------------------------------------------ r764 | ajapted | 2013-01-30 12:50:14 +1100 (Wed, 30 Jan 2013) | 2 lines CMD_BuildNodes: update status area. ------------------------------------------------------------------------ r763 | ajapted | 2013-01-30 12:11:49 +1100 (Wed, 30 Jan 2013) | 2 lines TODO: added plan to handle multiple files. ------------------------------------------------------------------------ r762 | printz | 2013-01-29 21:53:11 +1100 (Tue, 29 Jan 2013) | 3 lines osx port: * Updated project to Xcode 4.6 * Removed user-specific files from inside *.xcodeproj ------------------------------------------------------------------------ r761 | printz | 2013-01-29 21:52:55 +1100 (Tue, 29 Jan 2013) | 4 lines osx port: * Removed dead code and comments * Added descriptive comments * Updated version info and copyright formatting in the native automatic About box ------------------------------------------------------------------------ r760 | ajapted | 2013-01-29 17:16:28 +1100 (Tue, 29 Jan 2013) | 3 lines Backup system: the main M_BackupWad() logic is done, but some helper functions are not implemented yet -- namely Backup_ScanDir(). ------------------------------------------------------------------------ r759 | ajapted | 2013-01-29 16:43:06 +1100 (Tue, 29 Jan 2013) | 7 lines Began work on the Back-up system, which will save a copy of the wad into the "backups" folder in $home_dir whenever the user saves the map (CTRL-S) or exports the map into an existing wad. This commit merely (a) creates the "backups" folder and (b) adds the calls to M_BackupWad() at the appropriate places. ------------------------------------------------------------------------ r758 | ajapted | 2013-01-29 16:29:31 +1100 (Tue, 29 Jan 2013) | 3 lines Wad class: implemented a Backup() method. ------------------------------------------------------------------------ r757 | ajapted | 2013-01-29 14:58:32 +1100 (Tue, 29 Jan 2013) | 2 lines Checked in the MacOS X port source, created by Ioan Chera. ------------------------------------------------------------------------ r756 | ajapted | 2013-01-29 14:56:56 +1100 (Tue, 29 Jan 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r755 | ajapted | 2013-01-28 16:45:37 +1100 (Mon, 28 Jan 2013) | 2 lines After loading or saving a map, show a message in status bar. ------------------------------------------------------------------------ r754 | ajapted | 2013-01-28 14:47:17 +1100 (Mon, 28 Jan 2013) | 3 lines Fixed bug parsing user state for maps (.dat files), which was not handling strings properly. ------------------------------------------------------------------------ r753 | ajapted | 2013-01-28 14:11:29 +1100 (Mon, 28 Jan 2013) | 2 lines bindings.cfg : removed ESC key (bound to Quit). ------------------------------------------------------------------------ r752 | ajapted | 2013-01-28 11:20:25 +1100 (Mon, 28 Jan 2013) | 2 lines bindings.cfg : fixed LIN_Flip key, which clashed with SNAP toggle key. ------------------------------------------------------------------------ r751 | ajapted | 2013-01-26 14:06:30 +1100 (Sat, 26 Jan 2013) | 2 lines Made Editor_State_t be a struct (not a class). ------------------------------------------------------------------------ r750 | ajapted | 2013-01-26 14:01:44 +1100 (Sat, 26 Jan 2013) | 3 lines Silenced 64-bit compiler warnings (loss of precision when assigning a 64-bit value to a 32-bit variable or parameter). ------------------------------------------------------------------------ r749 | ajapted | 2013-01-26 13:55:34 +1100 (Sat, 26 Jan 2013) | 2 lines Fixed a uninitialized variable bug, and some 64-bit tweaks. ------------------------------------------------------------------------ r748 | ajapted | 2013-01-26 13:39:55 +1100 (Sat, 26 Jan 2013) | 2 lines Render3D: when changing gamma, show new value in status area. ------------------------------------------------------------------------ r747 | ajapted | 2013-01-25 09:43:00 +1100 (Fri, 25 Jan 2013) | 2 lines Wrote some notes about possible scripting API : misc/Scripting.txt ------------------------------------------------------------------------ r746 | ajapted | 2013-01-24 21:42:16 +1100 (Thu, 24 Jan 2013) | 2 lines debug tweak. ------------------------------------------------------------------------ r745 | ajapted | 2013-01-24 21:37:41 +1100 (Thu, 24 Jan 2013) | 2 lines TODO updated. ------------------------------------------------------------------------ r744 | ajapted | 2013-01-24 21:36:59 +1100 (Thu, 24 Jan 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r743 | ajapted | 2013-01-24 21:36:27 +1100 (Thu, 24 Jan 2013) | 3 lines When executing key bindings, clear status area if no error occurs. (Implementation detail: we clear it beforehand). ------------------------------------------------------------------------ r742 | ajapted | 2013-01-24 21:32:17 +1100 (Thu, 24 Jan 2013) | 2 lines SEC_Merge: beep at user if only 1 sector was selected. ------------------------------------------------------------------------ r741 | ajapted | 2013-01-24 16:56:20 +1100 (Thu, 24 Jan 2013) | 3 lines Version bump, in honor of new key binding system (all hard-coded keys, except for digits and the menus, are now handled via key bindings). ------------------------------------------------------------------------ r740 | ajapted | 2013-01-24 15:57:37 +1100 (Thu, 24 Jan 2013) | 2 lines Fixed missing "else" in R3D_Set() function. ------------------------------------------------------------------------ r739 | ajapted | 2013-01-24 15:56:43 +1100 (Thu, 24 Jan 2013) | 2 lines Implemented new '3D_Set' binding command. ------------------------------------------------------------------------ r738 | ajapted | 2013-01-24 15:55:02 +1100 (Thu, 24 Jan 2013) | 2 lines Fixed some bugs in CMD_Set(). ------------------------------------------------------------------------ r737 | ajapted | 2013-01-24 15:43:48 +1100 (Thu, 24 Jan 2013) | 3 lines 1. implemented '3D_Toggle' binding command 2. removed the now-dead Render3D_Key() function ------------------------------------------------------------------------ r736 | ajapted | 2013-01-24 15:42:38 +1100 (Thu, 24 Jan 2013) | 2 lines Tidying of the CMD_Toggle() and CMD_Set() code. ------------------------------------------------------------------------ r735 | ajapted | 2013-01-24 15:30:16 +1100 (Thu, 24 Jan 2013) | 2 lines bindings.cfg : fixed wrong comment syntax ------------------------------------------------------------------------ r734 | ajapted | 2013-01-24 15:28:09 +1100 (Thu, 24 Jan 2013) | 3 lines Implemented more render binding commands: '3D_Up', '3D_Down', '3D_Turn', '3D_DropToFloor' and '3D_Gamma'. ------------------------------------------------------------------------ r733 | ajapted | 2013-01-24 14:43:31 +1100 (Thu, 24 Jan 2013) | 3 lines Implemented four binding commands for renderer: '3D_Forward', '3D_Backward', '3D_Left' and '3D_Right'. ------------------------------------------------------------------------ r732 | ajapted | 2013-01-24 14:23:17 +1100 (Thu, 24 Jan 2013) | 3 lines Fixed missing 'SEC_SwapFlats' registration (I must have clobbered it accidentally in an earlier commit). ------------------------------------------------------------------------ r731 | ajapted | 2013-01-24 14:14:17 +1100 (Thu, 24 Jan 2013) | 3 lines 1. implemented 'JumpToObject' binding command 2. removed the now-dead Editor_Key() code ------------------------------------------------------------------------ r730 | ajapted | 2013-01-24 13:31:03 +1100 (Thu, 24 Jan 2013) | 3 lines Added Editor_DigitKey() function to handle digit keys (which do not use the key binding system). ------------------------------------------------------------------------ r729 | ajapted | 2013-01-24 13:24:18 +1100 (Thu, 24 Jan 2013) | 3 lines Implemented "grid" and "snap" variables for 'Toggle' and 'Set' binding commands. ------------------------------------------------------------------------ r728 | ajapted | 2013-01-24 13:11:53 +1100 (Thu, 24 Jan 2013) | 2 lines Implemented 'GRID_Step' binding command. ------------------------------------------------------------------------ r727 | ajapted | 2013-01-24 12:53:24 +1100 (Thu, 24 Jan 2013) | 2 lines Implemented 'Zoom' binding command. ------------------------------------------------------------------------ r726 | ajapted | 2013-01-24 12:46:03 +1100 (Thu, 24 Jan 2013) | 2 lines Implemented 'ZoomWholeMap' and 'ZoomSelection' binding commands. ------------------------------------------------------------------------ r725 | ajapted | 2013-01-24 12:32:17 +1100 (Thu, 24 Jan 2013) | 2 lines Tweaked a few bits of 'long' usage to prevent warnings. ------------------------------------------------------------------------ r724 | ajapted | 2013-01-24 12:24:56 +1100 (Thu, 24 Jan 2013) | 2 lines Changed rgb_color_t typedef to use u32_t (was: unsigned long). ------------------------------------------------------------------------ r723 | ajapted | 2013-01-24 12:23:49 +1100 (Thu, 24 Jan 2013) | 2 lines Removed unused centre_of_sectors() function. ------------------------------------------------------------------------ r722 | ajapted | 2013-01-24 12:18:50 +1100 (Thu, 24 Jan 2013) | 5 lines 1. renamed IsLineDefInside() --> LineCrossesBox(), tidied up the code and replaced 'long' usage 2. removed unused GetObjectCoords() function 3. replaced 'long' usage in GetOppositeSector() ------------------------------------------------------------------------ r721 | ajapted | 2013-01-23 23:57:42 +1100 (Wed, 23 Jan 2013) | 3 lines Implemented three browser-related binding commands, and removed the no-longer-needed Browser_Key() function. ------------------------------------------------------------------------ r720 | ajapted | 2013-01-23 20:46:04 +1100 (Wed, 23 Jan 2013) | 3 lines 1. implemented 'CMD_SetBrowser' binding command 2. removed dead Global_Key() function ------------------------------------------------------------------------ r719 | ajapted | 2013-01-23 19:48:26 +1100 (Wed, 23 Jan 2013) | 3 lines 1. implemented 'LIN_SelectPath' binding command 2. removed the dead Thing_Key / Sector_Key (etc) functions ------------------------------------------------------------------------ r718 | ajapted | 2013-01-23 19:28:16 +1100 (Wed, 23 Jan 2013) | 3 lines 1. implemented 'LIN_Flip' and 'LIN_SplitHalf' binding commands 2. changed binding of LIN_SplitHalf from 'x' --> 'k' ------------------------------------------------------------------------ r717 | ajapted | 2013-01-23 19:12:53 +1100 (Wed, 23 Jan 2013) | 3 lines 1. Use ExecuteCommand() for some menu functions 2. added some Beep() error messages ------------------------------------------------------------------------ r716 | ajapted | 2013-01-23 16:53:24 +1100 (Wed, 23 Jan 2013) | 2 lines Implemented 'CopyProperties' binding command. ------------------------------------------------------------------------ r715 | ajapted | 2013-01-23 16:45:04 +1100 (Wed, 23 Jan 2013) | 3 lines 1. renamed EXEC_Result --> EXEC_Errno 2. set EXEC_Errno to 1 in the Beep() error function ------------------------------------------------------------------------ r714 | ajapted | 2013-01-23 16:40:45 +1100 (Wed, 23 Jan 2013) | 3 lines 1. added EXEC_Result global, for testing if a command failed 2. implemented an ExecuteCommand() function ------------------------------------------------------------------------ r713 | ajapted | 2013-01-23 15:08:41 +1100 (Wed, 23 Jan 2013) | 3 lines SEC_SelectGroup : implemented new 'w' flag, perform a walking test (i.e. don't spread selection across lines which block the player). ------------------------------------------------------------------------ r712 | ajapted | 2013-01-23 14:56:10 +1100 (Wed, 23 Jan 2013) | 4 lines Implemented 'SEC_SelectGroup' binding command, and expanding the matching capabilities to support matching the light, tag and special values, and also have a flag to allow passing through doors. ------------------------------------------------------------------------ r711 | ajapted | 2013-01-23 12:59:05 +1100 (Wed, 23 Jan 2013) | 3 lines Support "3d" and "browser" variables with 'Toggle' and 'Set' binding commands. This replaces the 'Toggle3D' and 'ToggleBrowser' commands. ------------------------------------------------------------------------ r710 | ajapted | 2013-01-23 12:31:05 +1100 (Wed, 23 Jan 2013) | 2 lines Implemented 'SEC_Floor' and 'SEC_Ceil' binding commands. ------------------------------------------------------------------------ r709 | ajapted | 2013-01-23 11:13:31 +1100 (Wed, 23 Jan 2013) | 2 lines Implemented 'GoToCamera' and 'PlaceCamera' binding commands. ------------------------------------------------------------------------ r708 | ajapted | 2013-01-23 10:57:03 +1100 (Wed, 23 Jan 2013) | 3 lines Implemented new 'Set' binding command, this can set a variable to a particular value. Only one variable "obj_nums" is supported so far. ------------------------------------------------------------------------ r707 | ajapted | 2013-01-23 10:48:00 +1100 (Wed, 23 Jan 2013) | 4 lines Implemented 'Toggle' binding command, which takes a variable name to toggle. Current variables are "obj_nums" and "skills". This replaces the previous 'ToggleObjNums' command. ------------------------------------------------------------------------ r706 | ajapted | 2013-01-22 22:59:16 +1100 (Tue, 22 Jan 2013) | 2 lines Implemented the 'Delete' binding command, with optional "keep" parameter. ------------------------------------------------------------------------ r705 | ajapted | 2013-01-22 22:57:14 +1100 (Tue, 22 Jan 2013) | 4 lines Fixed two bugs in M_ParseKeyString() :- 1. the "SHIFT-" modifier had the wrong value 2. keys found in the table did not apply any modifier mask ------------------------------------------------------------------------ r704 | ajapted | 2013-01-22 22:48:47 +1100 (Tue, 22 Jan 2013) | 3 lines Keys: fixed bug in M_TranslateKey() -- don't use ispunct() on keys which are not ASCII (especially values like FL_BackSpace). ------------------------------------------------------------------------ r703 | ajapted | 2013-01-22 18:56:04 +1100 (Tue, 22 Jan 2013) | 3 lines 1. removed last vestiges of 'keymod_e' and KM_XXX 2. renamed some editor functions to have "Editor_" prefix ------------------------------------------------------------------------ r702 | ajapted | 2013-01-22 18:21:50 +1100 (Tue, 22 Jan 2013) | 5 lines 1. define PACKEDATTR in sys_macro.h -- source was Chocolate-Doom 2. added PACKEDATTR macro to all the raw on-disk structures, which may be needed on certain systems (especially 64-bit systems). ------------------------------------------------------------------------ r701 | ajapted | 2013-01-22 14:26:53 +1100 (Tue, 22 Jan 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r700 | ajapted | 2013-01-22 14:26:11 +1100 (Tue, 22 Jan 2013) | 2 lines Implemented 'Insert' binding command. ------------------------------------------------------------------------ r699 | ajapted | 2013-01-22 14:08:29 +1100 (Tue, 22 Jan 2013) | 3 lines Implemented a 'Nothing' command binding, as the name suggests it does nothing at all -- possibly more useful than it sounds. ------------------------------------------------------------------------ r698 | ajapted | 2013-01-22 14:04:56 +1100 (Tue, 22 Jan 2013) | 3 lines Implemented 'Merge' binding command for things, which places all the selected things at a single location. ------------------------------------------------------------------------ r697 | ajapted | 2013-01-22 12:21:29 +1100 (Tue, 22 Jan 2013) | 3 lines Things: new logic for 'Disconnect' -- the semantics are to move apart things at the same location (or very close). ------------------------------------------------------------------------ r696 | ajapted | 2013-01-22 10:44:39 +1100 (Tue, 22 Jan 2013) | 2 lines Added or tweaked some Beep() messages. ------------------------------------------------------------------------ r695 | ajapted | 2013-01-22 10:43:28 +1100 (Tue, 22 Jan 2013) | 4 lines Things: worked on 'Disconnect' for things, which will separate things which are overlapping each other. The logic in this commit is rather flawed though... ------------------------------------------------------------------------ r694 | ajapted | 2013-01-22 09:55:10 +1100 (Tue, 22 Jan 2013) | 4 lines Implemented 'Merge' and 'Disconnect' binding commands, which are used for every mode ("global" context). These replace the mode-specific binding commands like 'LIN_MergeTwo'. ------------------------------------------------------------------------ r693 | ajapted | 2013-01-22 09:49:08 +1100 (Tue, 22 Jan 2013) | 1 line minor tweak ------------------------------------------------------------------------ r692 | ajapted | 2013-01-21 13:09:26 +1100 (Mon, 21 Jan 2013) | 4 lines Key handling / M_SaveBindings: 1. fixed bug writing an 'UNBOUND' key multiple times 2. aesthetic change : no contiguous blank lines ------------------------------------------------------------------------ r691 | ajapted | 2013-01-21 12:59:36 +1100 (Mon, 21 Jan 2013) | 1 line tweak ------------------------------------------------------------------------ r690 | ajapted | 2013-01-21 12:58:36 +1100 (Mon, 21 Jan 2013) | 6 lines Key handling: 1. when writing the local bindings.cfg, skip bindings which are exactly the same as one from the install_dir 2. detect un-bound keys and write them using "UNBOUND" as the command 3. parse this "UNBOUND" keyword when reading a bindings.cfg ------------------------------------------------------------------------ r689 | ajapted | 2013-01-21 12:23:55 +1100 (Mon, 21 Jan 2013) | 3 lines Key handling: keep an in-memory copy of the install_dir bindings. It will be needed for M_SaveBindings() to only write the differences. ------------------------------------------------------------------------ r688 | ajapted | 2013-01-21 10:38:05 +1100 (Mon, 21 Jan 2013) | 2 lines tidied up Main_key_handler(). ------------------------------------------------------------------------ r687 | ajapted | 2013-01-21 08:53:42 +1100 (Mon, 21 Jan 2013) | 3 lines Key handling: moved translation code to M_TranslateKey() function (out of UI_Canvas::handle_key method). ------------------------------------------------------------------------ r686 | ajapted | 2013-01-21 08:29:28 +1100 (Mon, 21 Jan 2013) | 4 lines 1. replaced map name on info bar with a status box 2. added Status_Set() and Status_Clear() functions 3. updated Beep() to set the status and show message in log ------------------------------------------------------------------------ r685 | ajapted | 2013-01-20 19:05:39 +1100 (Sun, 20 Jan 2013) | 2 lines Implemented 'Scroll' binding command (for scrolling the map view). ------------------------------------------------------------------------ r684 | ajapted | 2013-01-20 18:37:07 +1100 (Sun, 20 Jan 2013) | 2 lines Implemented 'EditMode' binding command. ------------------------------------------------------------------------ r683 | ajapted | 2013-01-20 18:35:16 +1100 (Sun, 20 Jan 2013) | 2 lines tweaks. ------------------------------------------------------------------------ r682 | ajapted | 2013-01-20 16:28:38 +1100 (Sun, 20 Jan 2013) | 4 lines bindings.cfg : 1. fixed key for vertical mirror ('V' not 'v') 2. fixed some command names ------------------------------------------------------------------------ r681 | ajapted | 2013-01-20 16:20:48 +1100 (Sun, 20 Jan 2013) | 2 lines Implemented 'CopyAndPaste' binding command. ------------------------------------------------------------------------ r680 | ajapted | 2013-01-20 16:15:43 +1100 (Sun, 20 Jan 2013) | 7 lines Implemented these binding commands: Mirror (parameter is "horiz" or "vert") Rotate90 (parameter is direction, +1 for acw, -1 for cw) Enlarge (replaces CMD_ScaleObjects, parameter is multiplier) Shrink (replaces CMD_ScaleObjects, parameter is divisor) Quantize ------------------------------------------------------------------------ r679 | ajapted | 2013-01-20 13:14:41 +1100 (Sun, 20 Jan 2013) | 5 lines Implemented following as binding commands: 1. VERT_Merge, VERT_Disconnect 2. LIN_MergeTwo, LIN_Disconnect 3. SEC_Merge, SEC_Disconnect ------------------------------------------------------------------------ r678 | ajapted | 2013-01-20 12:46:06 +1100 (Sun, 20 Jan 2013) | 2 lines Key binding: Implemented 'TH_Spin' command (removed hard-coded 'w' and 'x' keys). ------------------------------------------------------------------------ r677 | ajapted | 2013-01-20 12:36:23 +1100 (Sun, 20 Jan 2013) | 3 lines Key handling: ensure the EXEC_Param[] values are never NULL, use the empty string instead. ------------------------------------------------------------------------ r676 | ajapted | 2013-01-20 12:06:46 +1100 (Sun, 20 Jan 2013) | 2 lines bindings.cfg : tweaked prefixes (e.g. LN --> LIN, GR --> GRID) ------------------------------------------------------------------------ r675 | ajapted | 2013-01-20 10:59:59 +1100 (Sun, 20 Jan 2013) | 2 lines Key handling: merged "edit" and "global" contexts into one (global). ------------------------------------------------------------------------ r674 | ajapted | 2013-01-20 10:36:01 +1100 (Sun, 20 Jan 2013) | 3 lines Key handling: implemented M_RemoveBinding(), and use it to ensure that bindings from the home_dir replace bindings from the install_dir. ------------------------------------------------------------------------ r673 | ajapted | 2013-01-20 10:23:59 +1100 (Sun, 20 Jan 2013) | 5 lines Key handling: 1. load bindings from BOTH install_dir and home_dir paths (otherwise new releases of Eureka would be unable to add new bindings) 2. fixed parsing of double quotes (") in bindings.cfg ------------------------------------------------------------------------ r672 | ajapted | 2013-01-19 21:59:24 +1100 (Sat, 19 Jan 2013) | 2 lines Key handling: un-hard-code the ` (back-quote) key -- rely on binding. ------------------------------------------------------------------------ r671 | ajapted | 2013-01-19 21:57:25 +1100 (Sat, 19 Jan 2013) | 3 lines Key handling: when writing the bindings, group them by their context (a purely aesthetic change). ------------------------------------------------------------------------ r670 | ajapted | 2013-01-19 21:31:19 +1100 (Sat, 19 Jan 2013) | 5 lines Key handling: 1. renamed CMD_SwapFlats --> SEC_SwapFlats 2. made it use key bindings (no hard-coded test against 'w' key) 3. moved M_RegisterCommand() calls into a separate function (editloop.cc) ------------------------------------------------------------------------ r669 | ajapted | 2013-01-19 21:23:30 +1100 (Sat, 19 Jan 2013) | 2 lines tweaked M_ModeToKeyContext() ------------------------------------------------------------------------ r668 | ajapted | 2013-01-19 21:21:23 +1100 (Sat, 19 Jan 2013) | 3 lines Key handling: have EXEC_Param[] global var to contain the parameters from the key binding being executed. ------------------------------------------------------------------------ r667 | ajapted | 2013-01-19 21:15:16 +1100 (Sat, 19 Jan 2013) | 5 lines Key handling: 1. renamed KCTX_INVALID --> KCTX_NONE 2. when registering commands, can specify a required context 3. prevent binding keys to a command in the wrong context ------------------------------------------------------------------------ r666 | ajapted | 2013-01-19 18:48:38 +1100 (Sat, 19 Jan 2013) | 3 lines Key handler: a few commands now rely on new system, e.g. TAB to toggle the 3D view, and 'b' to toggle the browser panel. ------------------------------------------------------------------------ r665 | ajapted | 2013-01-19 18:45:22 +1100 (Sat, 19 Jan 2013) | 7 lines Key handling: use new ExecuteKey() function to handle keys, using the same propagation logic. A few commands now rely on this, e.g. TAB to toggle the 3D view. The existing XXX_Key() functions are still in place, but will only remain during the transition to the new system. ------------------------------------------------------------------------ r664 | ajapted | 2013-01-19 18:40:36 +1100 (Sat, 19 Jan 2013) | 2 lines Key handling: fixed parsing of long key names (like "ESC"). ------------------------------------------------------------------------ r663 | ajapted | 2013-01-19 18:32:38 +1100 (Sat, 19 Jan 2013) | 5 lines Key handling: 1. moved key_context_e enumeration to global scope (header file) 2. added M_ModeToKeyContext() function 3. implemented ExecuteKey() function ------------------------------------------------------------------------ r662 | ajapted | 2013-01-19 15:47:37 +1100 (Sat, 19 Jan 2013) | 2 lines Key handling: finished M_LoadBindings() -- parse each binding and add it. ------------------------------------------------------------------------ r661 | ajapted | 2013-01-19 15:31:46 +1100 (Sat, 19 Jan 2013) | 3 lines Key handling: partial work implementing M_LoadBindings(). This commit just has the code to open the file and read tokens. ------------------------------------------------------------------------ r660 | ajapted | 2013-01-19 14:23:30 +1100 (Sat, 19 Jan 2013) | 3 lines Key handling: handle function and keypad keys in M_ParseKeyString() and M_KeyToString(). ------------------------------------------------------------------------ r659 | ajapted | 2013-01-19 14:10:42 +1100 (Sat, 19 Jan 2013) | 2 lines Key handling: more names for key_map[] table (e.g. VOL_DOWN, CD_PLAY, etc). ------------------------------------------------------------------------ r658 | ajapted | 2013-01-19 14:00:15 +1100 (Sat, 19 Jan 2013) | 4 lines Key handling: added a key_map[] table for mapping special keys from their code to their name or vice versa. ------------------------------------------------------------------------ r657 | ajapted | 2013-01-19 13:25:45 +1100 (Sat, 19 Jan 2013) | 4 lines Key handling: 1. implemented M_WriteBindings() 2. partial work on M_ParseKeyString() and M_KeyToString() ------------------------------------------------------------------------ r656 | ajapted | 2013-01-19 12:52:29 +1100 (Sat, 19 Jan 2013) | 2 lines Makefile: install the 'bindings.cfg' file. ------------------------------------------------------------------------ r655 | ajapted | 2013-01-19 12:45:29 +1100 (Sat, 19 Jan 2013) | 2 lines Added some M_RegisterCommand() calls in Editor_Init(). ------------------------------------------------------------------------ r654 | ajapted | 2013-01-19 12:42:18 +1100 (Sat, 19 Jan 2013) | 2 lines Key handling: changed command_func_t to return 'void' (not 'bool'). ------------------------------------------------------------------------ r653 | ajapted | 2013-01-19 10:41:47 +1100 (Sat, 19 Jan 2013) | 7 lines Key handling (m_keys.cc) : 1. added editor_command_t structure 2. added M_AddEditorCommand() and FindEditorCommand() 3. added key_context_e enumeration 4. added ParseKeyContext() and KeyContextString() functions 5. added key_binding_t structure ------------------------------------------------------------------------ r652 | ajapted | 2013-01-18 21:59:36 +1100 (Fri, 18 Jan 2013) | 2 lines New code files to handle key binding logic : m_keys.cc/h ------------------------------------------------------------------------ r651 | ajapted | 2013-01-18 21:52:26 +1100 (Fri, 18 Jan 2013) | 3 lines Key handling: changed some keymod_e (KM_XXX) usages to use keycode_t (MOD_XXX) defines instead. ------------------------------------------------------------------------ r650 | ajapted | 2013-01-18 21:18:44 +1100 (Fri, 18 Jan 2013) | 2 lines Bindings.txt : simpler format, a few tweaks. ------------------------------------------------------------------------ r649 | ajapted | 2013-01-18 17:11:03 +1100 (Fri, 18 Jan 2013) | 2 lines Finished the list of needed key bindings. ------------------------------------------------------------------------ r648 | ajapted | 2013-01-18 16:42:37 +1100 (Fri, 18 Jan 2013) | 2 lines Partial work on a list of needed key bindings. ------------------------------------------------------------------------ r647 | ajapted | 2013-01-18 16:08:29 +1100 (Fri, 18 Jan 2013) | 3 lines Key handling: convert SHIFT + punctuation key to the shifted value, for example SHIFT + ',' --> '<' ------------------------------------------------------------------------ r646 | ajapted | 2013-01-18 15:55:59 +1100 (Fri, 18 Jan 2013) | 3 lines Updated key handling code (UI_Canvas::handle_key, XXX_Key functions) to use the new keycode_t semantics. ------------------------------------------------------------------------ r645 | ajapted | 2013-01-18 15:35:20 +1100 (Fri, 18 Jan 2013) | 2 lines Updated semantics of keycode_t for digits. ------------------------------------------------------------------------ r644 | ajapted | 2013-01-16 22:16:55 +1100 (Wed, 16 Jan 2013) | 3 lines Added key_code_t typedef (and more importantly, comments defining its semantics). Not used yet, but will be needed for configurable keys... ------------------------------------------------------------------------ r643 | ajapted | 2013-01-15 22:11:41 +1100 (Tue, 15 Jan 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r642 | ajapted | 2013-01-15 22:09:55 +1100 (Tue, 15 Jan 2013) | 2 lines Updated some copyright messages for 2013. ------------------------------------------------------------------------ r641 | ajapted | 2013-01-15 22:05:22 +1100 (Tue, 15 Jan 2013) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r640 | ajapted | 2013-01-15 21:28:58 +1100 (Tue, 15 Jan 2013) | 2 lines Prefs and Config: implemented a "default grid mode" setting. ------------------------------------------------------------------------ r639 | ajapted | 2013-01-15 21:05:24 +1100 (Tue, 15 Jan 2013) | 2 lines Prefs dialog: implemented 'default_grid_size' setting. ------------------------------------------------------------------------ r638 | ajapted | 2013-01-15 20:52:38 +1100 (Tue, 15 Jan 2013) | 2 lines Grid: removed '192' as a possible grid size. ------------------------------------------------------------------------ r637 | ajapted | 2013-01-15 19:18:17 +1100 (Tue, 15 Jan 2013) | 3 lines Prefs dialog: implemented some of remaining General stuff, such as: default_grid_snap, digits_set_zoom and escape_key_quits. ------------------------------------------------------------------------ r636 | ajapted | 2013-01-15 16:33:40 +1100 (Tue, 15 Jan 2013) | 2 lines Config: added gui_custom_xx color variables. ------------------------------------------------------------------------ r635 | ajapted | 2013-01-15 16:20:40 +1100 (Tue, 15 Jan 2013) | 2 lines Prefs dialog: got the theme section of 'General' tab working. ------------------------------------------------------------------------ r634 | ajapted | 2013-01-15 16:03:28 +1100 (Tue, 15 Jan 2013) | 2 lines Prefs dialog: got the glBSP settings working. ------------------------------------------------------------------------ r633 | ajapted | 2013-01-15 14:21:08 +1100 (Tue, 15 Jan 2013) | 3 lines Prefs dialog: implemented rest of Editing options (except the modifier key for multi-select has only one choice: CTRL). ------------------------------------------------------------------------ r632 | ajapted | 2013-01-15 14:08:23 +1100 (Tue, 15 Jan 2013) | 4 lines Prefs dialog: 1. call M_WriteConfigFile() to persist the changes 2. implemented one of the settings : new_sector_size ------------------------------------------------------------------------ r631 | ajapted | 2013-01-15 14:04:01 +1100 (Tue, 15 Jan 2013) | 3 lines Config: moved extern declarations into header (m_config.h) so that the preferences code can access them. ------------------------------------------------------------------------ r630 | ajapted | 2013-01-15 13:55:52 +1100 (Tue, 15 Jan 2013) | 2 lines Prefs dialog: implemented color_callback(). ------------------------------------------------------------------------ r629 | ajapted | 2013-01-15 13:50:09 +1100 (Tue, 15 Jan 2013) | 3 lines Prefs dialog: make initial tab be the first one, and remember the last active tab for next time preferences dialog is opened. ------------------------------------------------------------------------ r628 | ajapted | 2013-01-15 13:29:10 +1100 (Tue, 15 Jan 2013) | 2 lines Prefs dialog: implemented callback for OK button and window close. ------------------------------------------------------------------------ r627 | ajapted | 2013-01-15 13:28:28 +1100 (Tue, 15 Jan 2013) | 1 line layout tweak ------------------------------------------------------------------------ r626 | ajapted | 2013-01-15 12:34:10 +1100 (Tue, 15 Jan 2013) | 3 lines EUREKA lump: better iwad check when a resource cannot be found (i.e. use the IWAD path for the game specified in the lump, not Iwad_name). ------------------------------------------------------------------------ r625 | ajapted | 2013-01-15 12:24:53 +1100 (Tue, 15 Jan 2013) | 2 lines docco tweaks. ------------------------------------------------------------------------ r624 | ajapted | 2013-01-15 12:19:24 +1100 (Tue, 15 Jan 2013) | 3 lines Prefs dialog: inserted the code generated by fluid (from prefs2.fl), with some tidying and adding missing fields and methods. ------------------------------------------------------------------------ r623 | ajapted | 2013-01-15 12:03:19 +1100 (Tue, 15 Jan 2013) | 2 lines Prefs dialog: started work on it, e.g. the basic Run() method. ------------------------------------------------------------------------ r622 | ajapted | 2013-01-15 11:50:35 +1100 (Tue, 15 Jan 2013) | 4 lines About dialog: reworked code, use an '_instance' field to keep track of the current window, and allow the rest of the application to function while it is open (i.e. it is _not_ modal). ------------------------------------------------------------------------ r621 | ajapted | 2013-01-15 10:33:13 +1100 (Tue, 15 Jan 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r620 | ajapted | 2013-01-15 10:25:36 +1100 (Tue, 15 Jan 2013) | 2 lines CHANGELOG: created a fresh one (after 0.88c release). ------------------------------------------------------------------------ r619 | ajapted | 2013-01-15 10:20:53 +1100 (Tue, 15 Jan 2013) | 3 lines When parsing the EUREKA lump and a resource wad cannot be found, look for it same directory as the PWAD, then try same dir as the IWAD. ------------------------------------------------------------------------ r618 | ajapted | 2013-01-15 10:18:26 +1100 (Tue, 15 Jan 2013) | 2 lines File utils: fixed some bugs in FileReposition(). ------------------------------------------------------------------------ r617 | ajapted | 2013-01-15 10:06:08 +1100 (Tue, 15 Jan 2013) | 3 lines File utils: implemented FilenameReposition() function, which takes a filename and replaces its path with the path from another filename. ------------------------------------------------------------------------ r616 | ajapted | 2013-01-10 22:47:36 +1100 (Thu, 10 Jan 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r615 | ajapted | 2013-01-06 19:34:04 +1100 (Sun, 06 Jan 2013) | 2 lines more TO-DO goodies... ------------------------------------------------------------------------ r614 | ajapted | 2013-01-04 12:58:27 +1100 (Fri, 04 Jan 2013) | 2 lines Version bump after 0.88c release. ------------------------------------------------------------------------ r613 | ajapted | 2013-01-04 12:57:24 +1100 (Fri, 04 Jan 2013) | 2 lines README.txt : added my SF email address. ------------------------------------------------------------------------ r612 | ajapted | 2013-01-04 12:56:59 +1100 (Fri, 04 Jan 2013) | 2 lines Debian: control tweak ------------------------------------------------------------------------ r611 | ajapted | 2013-01-04 12:56:29 +1100 (Fri, 04 Jan 2013) | 2 lines Moved CHANGES.txt --> docs/ folder, after 0.88c release. ------------------------------------------------------------------------ r610 | ajapted | 2013-01-04 12:55:45 +1100 (Fri, 04 Jan 2013) | 2 lines CHANGELOG tweak. ------------------------------------------------------------------------ r609 | ajapted | 2013-01-04 12:55:19 +1100 (Fri, 04 Jan 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r608 | ajapted | 2013-01-02 15:26:44 +1100 (Wed, 02 Jan 2013) | 2 lines TODO update. ------------------------------------------------------------------------ r607 | ajapted | 2012-12-27 21:03:42 +1100 (Thu, 27 Dec 2012) | 2 lines TODO.txt : document logic for texture alignment keys. ------------------------------------------------------------------------ r606 | ajapted | 2012-12-26 21:08:54 +1100 (Wed, 26 Dec 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r605 | ajapted | 2012-12-26 19:08:02 +1100 (Wed, 26 Dec 2012) | 2 lines TODO update (fixed the slime trails). ------------------------------------------------------------------------ r604 | ajapted | 2012-12-26 19:06:11 +1100 (Wed, 26 Dec 2012) | 2 lines Makefile: made 'uninstall' also remove the desktop and icon files. ------------------------------------------------------------------------ r603 | ajapted | 2012-12-26 18:44:19 +1100 (Wed, 26 Dec 2012) | 3 lines 3D View: implemented even better DistCmp() logic, which has eliminated nearly all trails. ------------------------------------------------------------------------ r602 | ajapted | 2012-12-26 18:12:10 +1100 (Wed, 26 Dec 2012) | 2 lines 3D View: reduced the slime trails. ------------------------------------------------------------------------ r601 | ajapted | 2012-12-26 16:17:53 +1100 (Wed, 26 Dec 2012) | 2 lines Coding: simpler usage of Fl_Sys_Menu_Bar. ------------------------------------------------------------------------ r600 | ajapted | 2012-12-26 16:17:11 +1100 (Wed, 26 Dec 2012) | 2 lines Dead code removal (ui_menu.cc) ------------------------------------------------------------------------ r599 | ajapted | 2012-12-24 22:23:01 +1100 (Mon, 24 Dec 2012) | 2 lines Renamed WISHLIST.txt --> TODO.txt ------------------------------------------------------------------------ r598 | ajapted | 2012-12-24 22:21:49 +1100 (Mon, 24 Dec 2012) | 2 lines Removed TODO.txt file : about to rename WISHLIST --> TODO... ------------------------------------------------------------------------ r597 | ajapted | 2012-12-24 22:18:25 +1100 (Mon, 24 Dec 2012) | 2 lines WISHLIST update. ------------------------------------------------------------------------ r596 | ajapted | 2012-12-24 22:17:25 +1100 (Mon, 24 Dec 2012) | 1 line tweak ------------------------------------------------------------------------ r595 | ajapted | 2012-12-24 22:16:30 +1100 (Mon, 24 Dec 2012) | 5 lines Debian: updated control file: 1. removed libfltk1.3 as a dependency (statically linked now) 2. added various dependencies, esp. X window stuff 3. bumped version ------------------------------------------------------------------------ r594 | ajapted | 2012-12-24 22:14:49 +1100 (Mon, 24 Dec 2012) | 2 lines Debian: updated Makefile to "install" the eureka desktop file and icon. ------------------------------------------------------------------------ r593 | ajapted | 2012-12-24 19:22:34 +1100 (Mon, 24 Dec 2012) | 4 lines Makefile: support for static linking with an FLTK which does not include OpenGL support and which uses 'localjpeg' and 'localpng' configuration. That is conditional on FLTK_STATIC being defined. ------------------------------------------------------------------------ r592 | ajapted | 2012-12-24 19:18:58 +1100 (Mon, 24 Dec 2012) | 3 lines Manage Wads dialog: fixed bug where the selected port reset to 'boom' unless the user selected something in the choice button. ------------------------------------------------------------------------ r591 | ajapted | 2012-12-24 16:54:40 +1100 (Mon, 24 Dec 2012) | 2 lines PORT defs: tweaks. ------------------------------------------------------------------------ r590 | ajapted | 2012-12-24 16:53:49 +1100 (Mon, 24 Dec 2012) | 2 lines AUTHORS.txt updated. ------------------------------------------------------------------------ r589 | ajapted | 2012-12-24 16:50:52 +1100 (Mon, 24 Dec 2012) | 2 lines LineDef panel: minor rename: 'pass use' --> 'pass thru' ------------------------------------------------------------------------ r588 | ajapted | 2012-12-24 15:47:37 +1100 (Mon, 24 Dec 2012) | 3 lines PORTS: added Doom Legacy definition 'legacy.ugh', by wesleyjohnson (with a few tweaks by me). ------------------------------------------------------------------------ r587 | ajapted | 2012-12-24 12:13:04 +1100 (Mon, 24 Dec 2012) | 3 lines Fix (hopefully) for compile error on 64-bit targets: casting a 'void*' to an 'int' losing precision. ------------------------------------------------------------------------ r586 | ajapted | 2012-12-23 18:24:18 +1100 (Sun, 23 Dec 2012) | 2 lines CHANGELOG: added revision numbers and "Changes since ..." line. ------------------------------------------------------------------------ r585 | ajapted | 2012-12-23 16:12:45 +1100 (Sun, 23 Dec 2012) | 3 lines Docs: created a single file with all the repository commit history, namely the 'docs/History.txt' file. Hence removed the other copies. ------------------------------------------------------------------------ r584 | ajapted | 2012-12-23 14:55:34 +1100 (Sun, 23 Dec 2012) | 2 lines WISHLIST update. ------------------------------------------------------------------------ r583 | ajapted | 2012-12-23 14:23:56 +1100 (Sun, 23 Dec 2012) | 2 lines Changed '__EUREKA' lump format, store 'game' instead than an iwad path. ------------------------------------------------------------------------ r582 | ajapted | 2012-12-23 14:09:25 +1100 (Sun, 23 Dec 2012) | 6 lines Handle the '__EUREKA' lump a lot more robustly: 1. if the game is unsupported, warn user with a choice: ignore/cancel 2. if iwad is not found, but it is known, use the known path 3. if iwad cannot be found at all, warn user with a choice: ignore/cancel 4. log some warnings on syntax errors ------------------------------------------------------------------------ r581 | ajapted | 2012-12-23 12:33:07 +1100 (Sun, 23 Dec 2012) | 4 lines Updated handing of '__EUREKA' lump, the M_ParseEurekaLump() can now return false (e.g. when the iwad cannot be found) -- hence need to be able to cancel the OpenMap or OpenRecentMap command. ------------------------------------------------------------------------ r580 | ajapted | 2012-12-22 22:27:32 +1100 (Sat, 22 Dec 2012) | 2 lines tweaked pack-source script ------------------------------------------------------------------------ r579 | ajapted | 2012-12-22 17:54:38 +1100 (Sat, 22 Dec 2012) | 2 lines README.txt : tweaked a few things, updated keyboard controls. ------------------------------------------------------------------------ r578 | ajapted | 2012-12-22 17:43:49 +1100 (Sat, 22 Dec 2012) | 2 lines INSTALL.txt : small update to setting up section. ------------------------------------------------------------------------ r577 | ajapted | 2012-12-22 17:39:54 +1100 (Sat, 22 Dec 2012) | 2 lines svn ignorations ------------------------------------------------------------------------ r576 | ajapted | 2012-12-22 17:17:53 +1100 (Sat, 22 Dec 2012) | 2 lines TODO updated. ------------------------------------------------------------------------ r575 | ajapted | 2012-12-22 17:15:01 +1100 (Sat, 22 Dec 2012) | 2 lines INSTALL.txt : tweak ------------------------------------------------------------------------ r574 | ajapted | 2012-12-22 17:09:12 +1100 (Sat, 22 Dec 2012) | 2 lines MacOSX: home_dir changed to '~/Library/Application Support/eureka-editor' ------------------------------------------------------------------------ r573 | ajapted | 2012-12-22 17:07:43 +1100 (Sat, 22 Dec 2012) | 2 lines Version bumped to 0.88 -- ready for release. ------------------------------------------------------------------------ r572 | ajapted | 2012-12-17 23:14:55 +1100 (Mon, 17 Dec 2012) | 2 lines WISHLIST update. ------------------------------------------------------------------------ r571 | ajapted | 2012-12-17 23:13:08 +1100 (Mon, 17 Dec 2012) | 2 lines CHANGELOG: updated, e.g. group View menu stuff together. ------------------------------------------------------------------------ r570 | ajapted | 2012-12-17 23:05:22 +1100 (Mon, 17 Dec 2012) | 3 lines Copy'n'paste: properly assign a new middle texture for linedefs which lose a sidedef (because the sector no longer exists). ------------------------------------------------------------------------ r569 | ajapted | 2012-12-17 22:51:56 +1100 (Mon, 17 Dec 2012) | 3 lines Copy'n'paste: when pasting, flip linedefs that would otherwise end up with only a left side (no right side). ------------------------------------------------------------------------ r568 | ajapted | 2012-12-17 15:12:24 +1100 (Mon, 17 Dec 2012) | 2 lines Error message tweak. ------------------------------------------------------------------------ r567 | ajapted | 2012-12-17 15:08:59 +1100 (Mon, 17 Dec 2012) | 2 lines comment tweak ------------------------------------------------------------------------ r566 | ajapted | 2012-12-17 15:07:46 +1100 (Mon, 17 Dec 2012) | 3 lines main: moved IWAD handling into a DetermineIWAD() function, and make sure that the --iwad parameter not only exists but is a supported game. ------------------------------------------------------------------------ r565 | ajapted | 2012-12-17 14:46:59 +1100 (Mon, 17 Dec 2012) | 2 lines Info bar: when map is changed, draw a '*' next to the map name. ------------------------------------------------------------------------ r564 | ajapted | 2012-12-17 14:22:00 +1100 (Mon, 17 Dec 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r563 | ajapted | 2012-12-17 14:21:37 +1100 (Mon, 17 Dec 2012) | 2 lines Support for --iwad parameter being a bare game name. ------------------------------------------------------------------------ r562 | ajapted | 2012-12-17 14:11:52 +1100 (Mon, 17 Dec 2012) | 2 lines File utilities: added FilenameIsBare() function. ------------------------------------------------------------------------ r561 | ajapted | 2012-12-17 13:55:17 +1100 (Mon, 17 Dec 2012) | 4 lines If the --iwad parameter is missing an extension, add ".wad". Removed the obsolete DetermineIWAD() code. ------------------------------------------------------------------------ r560 | ajapted | 2012-12-17 12:18:24 +1100 (Mon, 17 Dec 2012) | 2 lines INSTALL.txt : updated the 'Setting Up' section. ------------------------------------------------------------------------ r559 | ajapted | 2012-12-17 12:02:48 +1100 (Mon, 17 Dec 2012) | 2 lines docco tweaks. ------------------------------------------------------------------------ r558 | ajapted | 2012-12-17 11:42:09 +1100 (Mon, 17 Dec 2012) | 2 lines m_files.h needed a forward declaration -- patch courtesy Jeremy Henty. ------------------------------------------------------------------------ r557 | ajapted | 2012-12-17 11:35:36 +1100 (Mon, 17 Dec 2012) | 4 lines HACX things: 1. added missing BRS1 (mummy) and BAR1 (nitro canister) things 2. added two categories: 'Gore' and 'Natural' ------------------------------------------------------------------------ r556 | ajapted | 2012-12-16 20:21:43 +1100 (Sun, 16 Dec 2012) | 2 lines WISHLIST update (e.g. backup system) ------------------------------------------------------------------------ r555 | ajapted | 2012-12-16 20:14:40 +1100 (Sun, 16 Dec 2012) | 2 lines CHANGELOG: update ------------------------------------------------------------------------ r554 | ajapted | 2012-12-16 20:12:21 +1100 (Sun, 16 Dec 2012) | 2 lines HACX: added a lot of missing things. ------------------------------------------------------------------------ r553 | ajapted | 2012-12-16 19:18:06 +1100 (Sun, 16 Dec 2012) | 2 lines HACX: fixed names of powerups (based on the pickup messages). ------------------------------------------------------------------------ r552 | ajapted | 2012-12-16 19:12:32 +1100 (Sun, 16 Dec 2012) | 2 lines Grid: changed default step yet again ---> 64 ------------------------------------------------------------------------ r551 | ajapted | 2012-12-16 16:17:39 +1100 (Sun, 16 Dec 2012) | 2 lines HACX: changed the default textures. ------------------------------------------------------------------------ r550 | ajapted | 2012-12-16 16:06:25 +1100 (Sun, 16 Dec 2012) | 2 lines HACX: added more things (decorations), and fixed a few bugs. ------------------------------------------------------------------------ r549 | ajapted | 2012-12-16 12:13:41 +1100 (Sun, 16 Dec 2012) | 2 lines Game defs: began work on HACX definition file. ------------------------------------------------------------------------ r548 | ajapted | 2012-12-16 11:52:06 +1100 (Sun, 16 Dec 2012) | 2 lines tweaked some warning messages ------------------------------------------------------------------------ r547 | ajapted | 2012-12-16 11:32:27 +1100 (Sun, 16 Dec 2012) | 2 lines dead code removal ------------------------------------------------------------------------ r546 | ajapted | 2012-12-15 22:43:37 +1100 (Sat, 15 Dec 2012) | 2 lines TODO and WISHLIST update. ------------------------------------------------------------------------ r545 | ajapted | 2012-12-15 22:42:14 +1100 (Sat, 15 Dec 2012) | 2 lines Moved file 'New_Workflow.txt' out of docs/ ------------------------------------------------------------------------ r544 | ajapted | 2012-12-15 22:26:03 +1100 (Sat, 15 Dec 2012) | 2 lines Menu: disabled the unimplemented Preferences command. ------------------------------------------------------------------------ r543 | ajapted | 2012-12-15 21:17:28 +1100 (Sat, 15 Dec 2012) | 2 lines Menu: disabled the unimplemented 'Find' and 'Find Next' commands. ------------------------------------------------------------------------ r542 | ajapted | 2012-12-15 20:16:08 +1100 (Sat, 15 Dec 2012) | 2 lines CHANGELOG: added all the recent 'Manage Wads' work... ------------------------------------------------------------------------ r541 | ajapted | 2012-12-15 20:06:58 +1100 (Sat, 15 Dec 2012) | 2 lines minor rename: CMD_PlayMap --> CMD_TestMap ------------------------------------------------------------------------ r540 | ajapted | 2012-12-15 20:03:23 +1100 (Sat, 15 Dec 2012) | 2 lines Added doc about level checking: misc/Checks.txt ------------------------------------------------------------------------ r539 | ajapted | 2012-12-15 16:06:55 +1100 (Sat, 15 Dec 2012) | 2 lines CMD_OpenMap / OpenRecentMap : handle the '__EUREKA' lump. ------------------------------------------------------------------------ r538 | ajapted | 2012-12-15 15:13:31 +1100 (Sat, 15 Dec 2012) | 2 lines tweaks for '__EUREKA' lump handling... ------------------------------------------------------------------------ r537 | ajapted | 2012-12-15 15:11:56 +1100 (Sat, 15 Dec 2012) | 2 lines Wad code: implemented Lump_c::GetLine() method. ------------------------------------------------------------------------ r536 | ajapted | 2012-12-15 14:57:04 +1100 (Sat, 15 Dec 2012) | 4 lines The __EUREKA lump: 1. implemented parsing code 2. fixed missing 'lump->Finish()' in writing code ------------------------------------------------------------------------ r535 | ajapted | 2012-12-15 14:10:57 +1100 (Sat, 15 Dec 2012) | 3 lines Worked on support for '__EUREKA' lump, which contains the project info (the IWAD, port and resource wads). So far, can only create the lump. ------------------------------------------------------------------------ r534 | ajapted | 2012-12-15 14:04:29 +1100 (Sat, 15 Dec 2012) | 2 lines Wad code: added Lump_c::Printf() method. ------------------------------------------------------------------------ r533 | ajapted | 2012-12-15 13:29:53 +1100 (Sat, 15 Dec 2012) | 3 lines Manage Wads dialog: implemented code for 'Find' button which repopulates the iwad choice button with the known iwads. ------------------------------------------------------------------------ r532 | ajapted | 2012-12-14 21:47:11 +1100 (Fri, 14 Dec 2012) | 2 lines Manage Wads dialog: more work on this delightful little f.... ------------------------------------------------------------------------ r531 | ajapted | 2012-12-14 21:13:53 +1100 (Fri, 14 Dec 2012) | 2 lines TODO / WISHLIST update. ------------------------------------------------------------------------ r530 | ajapted | 2012-12-14 21:07:33 +1100 (Fri, 14 Dec 2012) | 3 lines Manage Wads dialog: tweaked startup message, using a red background and yellow text which makes it very striking. ------------------------------------------------------------------------ r529 | ajapted | 2012-12-14 20:55:08 +1100 (Fri, 14 Dec 2012) | 3 lines Worked on showing the Manage Wads dialog at startup when no iwads were found. Also, properly setup Iwad_name (etc) from that dialog. ------------------------------------------------------------------------ r528 | ajapted | 2012-12-14 20:37:49 +1100 (Fri, 14 Dec 2012) | 2 lines Utilities: allow passing NULL to StringDup() -- just return NULL. ------------------------------------------------------------------------ r527 | ajapted | 2012-12-14 20:16:57 +1100 (Fri, 14 Dec 2012) | 2 lines When Iwad_name is unset, try to pick a sensible default. ------------------------------------------------------------------------ r526 | ajapted | 2012-12-14 20:15:27 +1100 (Fri, 14 Dec 2012) | 3 lines Implemented M_PickDefaultIWAD() -- guesses either DOOM or DOOM2 based on level names (if any), and as last resource picks any known iwad. ------------------------------------------------------------------------ r525 | ajapted | 2012-12-14 19:50:38 +1100 (Fri, 14 Dec 2012) | 4 lines Worked on getting the startup sequence in main() sorted out, e.g. we now load the PWAD (but not the map) before other stuff so that the __EUREKA lump can be handled appropriately. ------------------------------------------------------------------------ r524 | ajapted | 2012-12-14 19:24:53 +1100 (Fri, 14 Dec 2012) | 2 lines Added EUREKA_LUMP define, bumped version. ------------------------------------------------------------------------ r523 | ajapted | 2012-12-14 17:18:06 +1100 (Fri, 14 Dec 2012) | 4 lines Removed the unused 'remind_to_build_nodes' stuff, I think for Eureka such a dialog could be really annoying -- for Yadex it was OK since the message was merely printed to the terminal. ------------------------------------------------------------------------ r522 | ajapted | 2012-12-14 15:25:58 +1100 (Fri, 14 Dec 2012) | 2 lines fixed bug in SearchDirForIWAD (need ".wad" extenstion) ------------------------------------------------------------------------ r521 | ajapted | 2012-12-14 13:45:18 +1100 (Fri, 14 Dec 2012) | 4 lines Worked on new M_LookForIWADs() code which looks for each game iwad in various places and updates the known_iwads list when found. This involves moving some code (e.g. SearchDirForIWAD) into m_files.cc. ------------------------------------------------------------------------ r520 | ajapted | 2012-12-14 13:40:10 +1100 (Fri, 14 Dec 2012) | 2 lines Fixed FatalError() messages which lacked a trailing newline. ------------------------------------------------------------------------ r519 | ajapted | 2012-12-14 13:18:15 +1100 (Fri, 14 Dec 2012) | 2 lines Ensure recent filenames and known iwad filenames are absolute. ------------------------------------------------------------------------ r518 | ajapted | 2012-12-14 13:04:23 +1100 (Fri, 14 Dec 2012) | 2 lines debugging fix. ------------------------------------------------------------------------ r517 | ajapted | 2012-12-14 13:00:07 +1100 (Fri, 14 Dec 2012) | 2 lines When loading recent files and known iwads, check the file still exists. ------------------------------------------------------------------------ r516 | ajapted | 2012-12-14 12:57:08 +1100 (Fri, 14 Dec 2012) | 2 lines Implemented parsing logic for "misc.cfg" -- recent wads and known iwads. ------------------------------------------------------------------------ r515 | ajapted | 2012-12-14 12:04:45 +1100 (Fri, 14 Dec 2012) | 3 lines Worked on saving known iwads in the 'misc.cfg' file, and changed the format of the recent files. Loading is not done yet... ------------------------------------------------------------------------ r514 | ajapted | 2012-12-14 10:52:57 +1100 (Fri, 14 Dec 2012) | 4 lines Project Setup dialog: 1. properly setup the 'Game IWAD' choice, using the known iwads list 2. fixed window close button (use close_callback) ------------------------------------------------------------------------ r513 | ajapted | 2012-12-14 10:46:29 +1100 (Fri, 14 Dec 2012) | 3 lines Known iwads: implemented function to return '|'-separated list of game names, namely M_KnownIWADsForMenu(). ------------------------------------------------------------------------ r512 | ajapted | 2012-12-13 22:47:49 +1100 (Thu, 13 Dec 2012) | 2 lines Known iwads: implemented M_AddKnownIWAD() and M_QueryrKnownIWAD() functions. ------------------------------------------------------------------------ r511 | ajapted | 2012-12-13 20:28:57 +1100 (Thu, 13 Dec 2012) | 2 lines Bound '\' key to cycle categories in the browser. ------------------------------------------------------------------------ r510 | ajapted | 2012-12-13 20:09:03 +1100 (Thu, 13 Dec 2012) | 2 lines Renamed recent.cfg --> misc.cfg [it will contain other stuff too] ------------------------------------------------------------------------ r509 | ajapted | 2012-12-13 20:00:01 +1100 (Thu, 13 Dec 2012) | 5 lines Config handling: 1. have a 'v' flag for real variables (only those are written out) 2. hence no need for 'h' flag -- removed 3. tweaked the --help descriptions (esp. for merge) ------------------------------------------------------------------------ r508 | ajapted | 2012-12-13 19:46:51 +1100 (Thu, 13 Dec 2012) | 2 lines Config handling: implemented M_WriteConfigFile(). ------------------------------------------------------------------------ r507 | ajapted | 2012-12-13 19:21:53 +1100 (Thu, 13 Dec 2012) | 3 lines Config handling: minor function rename, e.g. M_ParseConfigFile() and M_ParseCommandLine(), and rejiggage of how they are called. ------------------------------------------------------------------------ r506 | ajapted | 2012-12-13 16:49:51 +1100 (Thu, 13 Dec 2012) | 2 lines part (b) of renamed code files: m_recent --> m_files ------------------------------------------------------------------------ r505 | ajapted | 2012-12-13 15:53:02 +1100 (Thu, 13 Dec 2012) | 2 lines Renamed code file: m_recent.cc/h --> m_files.cc/h ------------------------------------------------------------------------ r504 | ajapted | 2012-12-13 15:42:42 +1100 (Thu, 13 Dec 2012) | 2 lines Game defs: implemented M_CollectKnownDefs() function. ------------------------------------------------------------------------ r503 | ajapted | 2012-12-13 15:22:18 +1100 (Thu, 13 Dec 2012) | 3 lines M_CollectDefsForMenu: pass in an existing name, and pass out its index (if found). ------------------------------------------------------------------------ r502 | ajapted | 2012-12-13 15:20:35 +1100 (Thu, 13 Dec 2012) | 3 lines Renamed the File -> 'Project Setup' command to 'Manage Wads' (as a test, since I haven't decided which one is more intuitive). ------------------------------------------------------------------------ r501 | ajapted | 2012-12-13 00:01:39 +1100 (Thu, 13 Dec 2012) | 3 lines Partial work on logic to get a list of definitions (e.g. list of ports) by scanning the installed UGH files. ------------------------------------------------------------------------ r500 | ajapted | 2012-12-11 22:29:45 +1100 (Tue, 11 Dec 2012) | 2 lines TODO update. ------------------------------------------------------------------------ r499 | ajapted | 2012-12-11 22:09:54 +1100 (Tue, 11 Dec 2012) | 3 lines Project Setup dialog: got the resource buttons ('X' and 'Load') working and got the IWAD 'Find' button mostly working. ------------------------------------------------------------------------ r498 | ajapted | 2012-12-11 21:40:52 +1100 (Tue, 11 Dec 2012) | 3 lines Moved texture loading calls into Main_LoadResources(), making sure that all previous textures are removed and freed. ------------------------------------------------------------------------ r497 | ajapted | 2012-12-11 21:36:55 +1100 (Tue, 11 Dec 2012) | 2 lines Show a '*' in the window title bar when the map has been modified. ------------------------------------------------------------------------ r496 | ajapted | 2012-12-11 21:34:46 +1100 (Tue, 11 Dec 2012) | 2 lines Code tidying: removed some dead code (e.g. DrawScreenText). ------------------------------------------------------------------------ r495 | ajapted | 2012-12-11 14:37:58 +1100 (Tue, 11 Dec 2012) | 5 lines Implemented ability to load "mod" definition files, which correspond to a loaded resource wad. Also fixed Main_LoadResources() to clear all definitions. ------------------------------------------------------------------------ r494 | ajapted | 2012-12-11 14:25:15 +1100 (Tue, 11 Dec 2012) | 3 lines Factored IWAD/resource loading code into Main_LoadResources() function. This is going to allow dynamically changing the iwad/port/resources. ------------------------------------------------------------------------ r493 | ajapted | 2012-12-11 14:11:22 +1100 (Tue, 11 Dec 2012) | 5 lines Code tidying: 1. renamed global var: base_wad --> game_wad 2. renamed Iwad --> Iwad_name, ensure it stays valid 3. renamed Pwad --> Pwad_name, keep it valid (when changing edit_wad) ------------------------------------------------------------------------ r492 | ajapted | 2012-12-11 13:54:56 +1100 (Tue, 11 Dec 2012) | 2 lines Project Setup dialog: bit more work e.g. Populate method... ------------------------------------------------------------------------ r491 | ajapted | 2012-12-11 11:57:22 +1100 (Tue, 11 Dec 2012) | 5 lines File menu update: 1. added 'Project Setup' command 2. CTRL-R is now the shortcut key for 'Recent Files' command 3. tweaked the keyboard navigation ------------------------------------------------------------------------ r490 | ajapted | 2012-12-11 11:55:04 +1100 (Tue, 11 Dec 2012) | 2 lines Project Setup: bit more work, wrote skeletal Main_ProjectSetup() code. ------------------------------------------------------------------------ r489 | ajapted | 2012-12-11 11:50:22 +1100 (Tue, 11 Dec 2012) | 3 lines Renamed UI_ProjectInfo --> UI_ProjectSetup, added skeletal callback functions, fixed window title and resource numbering. ------------------------------------------------------------------------ r488 | ajapted | 2012-12-11 11:33:41 +1100 (Tue, 11 Dec 2012) | 1 line tweak ------------------------------------------------------------------------ r487 | ajapted | 2012-12-11 11:26:04 +1100 (Tue, 11 Dec 2012) | 2 lines manage2.fl : various work ------------------------------------------------------------------------ r486 | ajapted | 2012-12-11 10:57:33 +1100 (Tue, 11 Dec 2012) | 4 lines Began work on a 'Project Info' dialog, where the user can select / change the current IWAD and port (engine) and resource wads. So far this is only the widget layout (imported from fluid output). ------------------------------------------------------------------------ r485 | ajapted | 2012-12-10 22:02:57 +1100 (Mon, 10 Dec 2012) | 2 lines TODO update. ------------------------------------------------------------------------ r484 | ajapted | 2012-12-10 21:23:14 +1100 (Mon, 10 Dec 2012) | 10 lines Open Map dialog: we no longer directly change 'edit_wad' in the dialog itself, instead we keep a local copy of the Wad_file object, and communicate the newly-openness of it via 'is_new_pwad' Run() param. Updated the CMD_OpenMap() logic accordingly, removing the edit_wad from master dir when the returned wad is different, and establishing the 'new_pwad' as the edit_wad if that's what the user selected. So I think the logic is 100% correct now, but will review it soon... ------------------------------------------------------------------------ r483 | ajapted | 2012-12-10 20:55:31 +1100 (Mon, 10 Dec 2012) | 2 lines Disconnect Sectors: fixed texture on the separated linedefs. ------------------------------------------------------------------------ r482 | ajapted | 2012-12-10 15:25:43 +1100 (Mon, 10 Dec 2012) | 2 lines Disconnect Sectors: improved calculation of move vector. ------------------------------------------------------------------------ r481 | ajapted | 2012-12-10 15:16:44 +1100 (Mon, 10 Dec 2012) | 3 lines Disconnect Sectors: got the logic for moving the vertices in a good direction working, via new DETSEC_CalcMoveVector() function. ------------------------------------------------------------------------ r480 | ajapted | 2012-12-10 14:37:17 +1100 (Mon, 10 Dec 2012) | 2 lines Merge linedefs: fixed handling of sidedef textures. ------------------------------------------------------------------------ r479 | ajapted | 2012-12-10 11:29:58 +1100 (Mon, 10 Dec 2012) | 3 lines Open Map dialog: re-check map name after changing the "Look in" wad or after loading a new pwad. Fixed some bugs. ------------------------------------------------------------------------ r478 | ajapted | 2012-12-10 11:19:21 +1100 (Mon, 10 Dec 2012) | 4 lines Open Map dialog: implemented logic to validate the map name, including checking that it exists in the selected wad, and only enable the "OK" button when valid. ------------------------------------------------------------------------ r477 | ajapted | 2012-12-09 22:34:51 +1100 (Sun, 09 Dec 2012) | 2 lines TODO update. ------------------------------------------------------------------------ r476 | ajapted | 2012-12-09 22:29:34 +1100 (Sun, 09 Dec 2012) | 2 lines Open Map dialog: prevent loading a PWAD without any levels. ------------------------------------------------------------------------ r475 | ajapted | 2012-12-09 22:25:51 +1100 (Sun, 09 Dec 2012) | 2 lines CMD_OpenMap: fixed the new 'Replacer' logic. ------------------------------------------------------------------------ r474 | ajapted | 2012-12-09 22:10:30 +1100 (Sun, 09 Dec 2012) | 5 lines Open Map dialog: 1. use it properly in CMD_OpenMap() -- remove a lot of old logic 2. return the selected wad and map from the Run() method 3. support clicking on a map button ------------------------------------------------------------------------ r473 | ajapted | 2012-12-09 21:47:46 +1100 (Sun, 09 Dec 2012) | 6 lines Open Map dialog: implemented the 'Load' button, which pops up a file requester to get a WAD file and can load that as the 'edit_wad' (code portions were copy'n'pasted from CMD_OpenMap). We also setup the currently edited pwad widget. ------------------------------------------------------------------------ r472 | ajapted | 2012-12-09 21:24:05 +1100 (Sun, 09 Dec 2012) | 5 lines Choose Map dialog: implemented checking the map name as the user types it, when invalid it is drawn in RED and the OK button is deactivated. Also removed some gunk. ------------------------------------------------------------------------ r471 | ajapted | 2012-12-09 19:54:33 +1100 (Sun, 09 Dec 2012) | 7 lines Preferences dialog: more work in fluid: 1. fixed the radio and check buttons so the size covers the label 2. added C++ variable names to each widget 3. use BORDER_BOX for color buttons (so the plastic scheme doesn't show the wrong color) 4. miscellaneous tweaking. ------------------------------------------------------------------------ r470 | ajapted | 2012-12-09 18:51:16 +1100 (Sun, 09 Dec 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r469 | ajapted | 2012-12-09 18:41:41 +1100 (Sun, 09 Dec 2012) | 3 lines Open Map dialog: improved layout of map buttons, make buttons bigger when there are less columns, and use less rows sometimes. ------------------------------------------------------------------------ r468 | ajapted | 2012-12-09 17:12:35 +1100 (Sun, 09 Dec 2012) | 3 lines Open Map dialog: wrote the Populate() method which creates a button for each found map in the selected "look for" place. ------------------------------------------------------------------------ r467 | ajapted | 2012-12-09 16:40:21 +1100 (Sun, 09 Dec 2012) | 2 lines Open Map dialog: made more compact (vertically) + a few tweaks. ------------------------------------------------------------------------ r466 | ajapted | 2012-12-09 16:08:59 +1100 (Sun, 09 Dec 2012) | 3 lines Open Map dialog: a few fixes, especially a bad labelfont() value which caused a crash. ------------------------------------------------------------------------ r465 | ajapted | 2012-12-09 15:53:27 +1100 (Sun, 09 Dec 2012) | 2 lines Partial work on new 'Open Map' dialog, main skeleton and widget layout. ------------------------------------------------------------------------ r464 | ajapted | 2012-12-09 15:31:35 +1100 (Sun, 09 Dec 2012) | 2 lines Use the new map choosing dialog with File/New command. ------------------------------------------------------------------------ r463 | ajapted | 2012-12-09 14:37:39 +1100 (Sun, 09 Dec 2012) | 5 lines Choose Map dialog: 1. changed the layout so that MAP01/02/03 (etc) goes down columns instead of across rows 2. got the buttons working (implemented the callback) ------------------------------------------------------------------------ r462 | ajapted | 2012-12-09 14:23:05 +1100 (Sun, 09 Dec 2012) | 3 lines Choose Map dialog: code to populate with map-name buttons. It can also test whether the map already exists, changes the color of the button. ------------------------------------------------------------------------ r461 | ajapted | 2012-12-09 13:27:38 +1100 (Sun, 09 Dec 2012) | 4 lines Export map: use the new 'Choose Map' dialog. We also open/create the destination wad file first, so that the dialog will be able to show which maps are used and which maps are free (planned feature). ------------------------------------------------------------------------ r460 | ajapted | 2012-12-09 13:24:17 +1100 (Sun, 09 Dec 2012) | 2 lines UI_ChooseMap: validate the map name, and fixed several issues. ------------------------------------------------------------------------ r459 | ajapted | 2012-12-09 12:52:16 +1100 (Sun, 09 Dec 2012) | 2 lines Worked on 'Choose Map' dialog, basic widgets are in place... ------------------------------------------------------------------------ r458 | ajapted | 2012-12-09 12:23:54 +1100 (Sun, 09 Dec 2012) | 3 lines Added new code files 'ui_file.cc/h', which will contain some File-related dialogs. Currently only has the beginnings of a UI_ChooseMap dialog. ------------------------------------------------------------------------ r457 | ajapted | 2012-12-08 22:14:27 +1100 (Sat, 08 Dec 2012) | 3 lines Misc: commit the in-progress fluid versions of Preference dialog and Project Info (wad manager) dialog. ------------------------------------------------------------------------ r456 | ajapted | 2012-12-08 21:26:14 +1100 (Sat, 08 Dec 2012) | 2 lines implemented 'View / Whole Selection' menu command. ------------------------------------------------------------------------ r455 | ajapted | 2012-12-08 20:38:21 +1100 (Sat, 08 Dec 2012) | 4 lines Preferences: added bare-bones code files: ui_prefs.cc/h (The actual dialog is being worked on in fluid...) ------------------------------------------------------------------------ r454 | ajapted | 2012-12-08 18:30:04 +1100 (Sat, 08 Dec 2012) | 2 lines Removed obselete config vars: 'sprite_scale' and 'copy_linedef_reuse_sidedef'. ------------------------------------------------------------------------ r453 | ajapted | 2012-12-08 15:58:07 +1100 (Sat, 08 Dec 2012) | 2 lines CHANGELOG: update, rejigged the order of some items. ------------------------------------------------------------------------ r452 | ajapted | 2012-12-08 15:56:09 +1100 (Sat, 08 Dec 2012) | 3 lines Fixed File/Open and OpenRecent to not zoom out when there is persisted state for that map. ------------------------------------------------------------------------ r451 | ajapted | 2012-12-08 15:49:48 +1100 (Sat, 08 Dec 2012) | 2 lines Recent files: actually load the file/map picked in the GUI. ------------------------------------------------------------------------ r450 | ajapted | 2012-12-08 15:39:10 +1100 (Sat, 08 Dec 2012) | 3 lines Recent files: implemented callback for the buttons, we use the user data to hold the index number (needed a ugly hack to allow that). ------------------------------------------------------------------------ r449 | ajapted | 2012-12-08 15:25:16 +1100 (Sat, 08 Dec 2012) | 4 lines Recent files: partial work on CMD_OpenRecentMap() code which is responsible for actually opening the selected map. Also updated M_RecentDialog() to pass back the chosen filename and map. ------------------------------------------------------------------------ r448 | ajapted | 2012-12-08 15:08:36 +1100 (Sat, 08 Dec 2012) | 2 lines Recent files: layout tweaks. ------------------------------------------------------------------------ r447 | ajapted | 2012-12-08 15:04:05 +1100 (Sat, 08 Dec 2012) | 8 lines Recent files: 1. reduced MAX_RECENT from 10 to 8 2. the find() method can also match a map name 3. added Format() method to format a file/map for a gui button 4. made the dialog window height depend on # of recent files 5. create buttons for each file/map 6. show a different message when list is empty ------------------------------------------------------------------------ r446 | ajapted | 2012-12-08 14:32:10 +1100 (Sat, 08 Dec 2012) | 2 lines Recent files: implemented the cancel button (close_callback). ------------------------------------------------------------------------ r445 | ajapted | 2012-12-08 14:00:45 +1100 (Sat, 08 Dec 2012) | 3 lines Recent files: began work on dialog to show the files and let the user select one. So far this is just creates the window, nothing works yet. ------------------------------------------------------------------------ r444 | ajapted | 2012-12-08 13:44:37 +1100 (Sat, 08 Dec 2012) | 3 lines Made linedef-path and contig-sector select commands consistent with normal selection -- clear previous selection after a move. ------------------------------------------------------------------------ r443 | ajapted | 2012-12-08 13:37:30 +1100 (Sat, 08 Dec 2012) | 2 lines Merge linedefs tweak. ------------------------------------------------------------------------ r442 | ajapted | 2012-12-08 12:59:28 +1100 (Sat, 08 Dec 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r441 | ajapted | 2012-12-08 12:59:03 +1100 (Sat, 08 Dec 2012) | 2 lines Linedef mode: Implemented 'm' merge command for two one-sided lines. ------------------------------------------------------------------------ r440 | ajapted | 2012-12-08 12:38:35 +1100 (Sat, 08 Dec 2012) | 4 lines Added a version of the Beep() function which takes a message, as eventually it would be good to show a message somewhere (like a status bar). ------------------------------------------------------------------------ r439 | ajapted | 2012-12-08 12:31:45 +1100 (Sat, 08 Dec 2012) | 2 lines UI: added 'Recent file' command to File menu (does not work yet). ------------------------------------------------------------------------ r438 | ajapted | 2012-12-08 11:47:48 +1100 (Sat, 08 Dec 2012) | 2 lines TODO update. ------------------------------------------------------------------------ r437 | ajapted | 2012-12-08 11:46:37 +1100 (Sat, 08 Dec 2012) | 2 lines Disconnect sectors: fixed another issue. ------------------------------------------------------------------------ r436 | ajapted | 2012-12-08 11:33:07 +1100 (Sat, 08 Dec 2012) | 5 lines Disconnect sectors: 1. got the sidedef handling in DETSEC_AddNewLine() working properly 2. fixed a bug where we visited newly added linedefs 3. few other fixes to the logic ------------------------------------------------------------------------ r435 | ajapted | 2012-12-08 11:04:28 +1100 (Sat, 08 Dec 2012) | 2 lines Disconnect sectors: worked on line separation logic... ------------------------------------------------------------------------ r434 | ajapted | 2012-12-08 10:47:02 +1100 (Sat, 08 Dec 2012) | 2 lines Worked on a 'd' disconnect command for Sectors... ------------------------------------------------------------------------ r433 | ajapted | 2012-12-07 22:49:02 +1100 (Fri, 07 Dec 2012) | 2 lines TODO update. ------------------------------------------------------------------------ r432 | ajapted | 2012-12-07 22:47:40 +1100 (Fri, 07 Dec 2012) | 2 lines UI: about box tweak. ------------------------------------------------------------------------ r431 | ajapted | 2012-12-07 22:13:27 +1100 (Fri, 07 Dec 2012) | 4 lines Recent files: 1. fixed parse code to remove trailing CR/LF 2. call M_LoadRecent() and M_AddRecent() where needed ------------------------------------------------------------------------ r430 | ajapted | 2012-12-07 21:31:17 +1100 (Fri, 07 Dec 2012) | 2 lines Recent files: implemented M_LoadRecent() and M_SaveRecent(). ------------------------------------------------------------------------ r429 | ajapted | 2012-12-07 21:24:31 +1100 (Fri, 07 Dec 2012) | 2 lines Recent files: implemented ParseFile() method and fixed a few bugs. ------------------------------------------------------------------------ r428 | ajapted | 2012-12-07 21:13:00 +1100 (Fri, 07 Dec 2012) | 5 lines Recent files: 1. implemented insert() method, with logic to find() an existing file with the same base-name and erase() it. 2. implemented the WriteFile() method. ------------------------------------------------------------------------ r427 | ajapted | 2012-12-07 21:00:47 +1100 (Fri, 07 Dec 2012) | 3 lines Began work on code to remember recently edited files, with a goal to show a dialog allowing users to pick one to open. ------------------------------------------------------------------------ r426 | ajapted | 2012-12-07 20:29:10 +1100 (Fri, 07 Dec 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r425 | ajapted | 2012-12-07 20:24:10 +1100 (Fri, 07 Dec 2012) | 2 lines View menu: added 'Toggle Grid Type' item. ------------------------------------------------------------------------ r424 | ajapted | 2012-12-07 19:32:37 +1100 (Fri, 07 Dec 2012) | 7 lines Show object nums: use a better algorithm for sectors, keep track of which sectors we have "seen" and draw the number on the first visited linedef. Also changed the linedef position to be directly on the line (which is generally uglier, but less confusing). ------------------------------------------------------------------------ r423 | ajapted | 2012-12-07 18:57:11 +1100 (Fri, 07 Dec 2012) | 6 lines Show object nums: reworked drawing for Linedefs, done in a separate pass (like things etc), and really honed the logic determining how far away from the line's middle to draw the number. Added 'center' parameter to DrawObjNum() method. ------------------------------------------------------------------------ r422 | ajapted | 2012-12-07 17:41:45 +1100 (Fri, 07 Dec 2012) | 2 lines Show object nums: persist the setting. ------------------------------------------------------------------------ r421 | ajapted | 2012-12-07 16:11:43 +1100 (Fri, 07 Dec 2012) | 2 lines Show object numbers: added to VIEW menu, and changed key to 'J'. ------------------------------------------------------------------------ r420 | ajapted | 2012-12-07 15:51:39 +1100 (Fri, 07 Dec 2012) | 8 lines Worked to improve object numbers on canvas: 1. moved thing code into DrawThings() 2. moved sector code into new DrawSectorNums() method 3. OBJ_NUM_COL replaces the THING_NO, SECTOR_NO (etc) defines 4. DrawObjNum() no longer uses obsolete DrawScreenText() function 5. font size depends for the current scale 6. position the number at top/right of things and vertices ------------------------------------------------------------------------ r419 | ajapted | 2012-12-07 15:01:53 +1100 (Fri, 07 Dec 2012) | 2 lines Key propagation: fixed the 3D view eating all keys when active. ------------------------------------------------------------------------ r418 | ajapted | 2012-12-07 13:45:40 +1100 (Fri, 07 Dec 2012) | 6 lines Implemented a decent GoToObject() function, via new GoToSelection() function which can zoom out when the objects are too large to fit on-screen, or zoom in when they are very small. New code is in e_path.cc/h (no longer in objects.cc/h) ------------------------------------------------------------------------ r417 | ajapted | 2012-12-07 12:43:05 +1100 (Fri, 07 Dec 2012) | 2 lines Unbind 'n' and 'p' keys from the next obj / prev obj mis-feature. ------------------------------------------------------------------------ r416 | ajapted | 2012-12-07 11:09:57 +1100 (Fri, 07 Dec 2012) | 5 lines Menu code stuff: 1. replace fl_beep() with Beep() 2. reworked find commands in View menu, removed 'next / prev object' 3. experimental support for Fullscreen mode ------------------------------------------------------------------------ r415 | ajapted | 2012-12-07 11:03:14 +1100 (Fri, 07 Dec 2012) | 3 lines UI_Window: added ToggleFullscreen() method, though it doesn't work too well (here anyway) due to FLTK's implementation. ------------------------------------------------------------------------ r414 | ajapted | 2012-12-06 23:57:21 +1100 (Thu, 06 Dec 2012) | 2 lines TODO and WISHLIST updates. ------------------------------------------------------------------------ r413 | ajapted | 2012-12-06 23:54:16 +1100 (Thu, 06 Dec 2012) | 2 lines Implemented 'm' merge command for vertex mode. ------------------------------------------------------------------------ r412 | ajapted | 2012-12-06 23:20:03 +1100 (Thu, 06 Dec 2012) | 2 lines Removed dead code : set_colour(), push_colour(), pop_colour(). ------------------------------------------------------------------------ r411 | ajapted | 2012-12-06 23:15:50 +1100 (Thu, 06 Dec 2012) | 4 lines Merged stuff from s_misc.cc/h --> e_sector.cc/h (some disabled code which may be needed later). Hence deleted s_misc.cc/h and removed from the Makefile. ------------------------------------------------------------------------ r410 | ajapted | 2012-12-06 23:08:49 +1100 (Thu, 06 Dec 2012) | 2 lines Removed dead code : find_linedef_for_area(). ------------------------------------------------------------------------ r409 | ajapted | 2012-12-06 23:03:54 +1100 (Thu, 06 Dec 2012) | 3 lines Removed dead code : old non-working SplitSector() and SplitLineDefsAndSector() functions. ------------------------------------------------------------------------ r408 | ajapted | 2012-12-06 22:57:39 +1100 (Thu, 06 Dec 2012) | 2 lines Config: support for color variables (via new OPT_COLOR type). ------------------------------------------------------------------------ r407 | ajapted | 2012-12-06 22:56:14 +1100 (Thu, 06 Dec 2012) | 3 lines Added ParseColor() function to im_color code, originally in m_game.cc but updated to support both 3- and 6-digit formats (RGB and RRGGBB). ------------------------------------------------------------------------ r406 | ajapted | 2012-12-06 16:37:21 +1100 (Thu, 06 Dec 2012) | 3 lines Added 'digits_set_zoom' config var which enabled the Yadex behavior where the digit keys set the zoom factor. ------------------------------------------------------------------------ r405 | ajapted | 2012-12-06 16:11:34 +1100 (Thu, 06 Dec 2012) | 2 lines tweaked handling of BackSpace key. ------------------------------------------------------------------------ r404 | ajapted | 2012-12-06 16:10:50 +1100 (Thu, 06 Dec 2012) | 2 lines Removed sector_slice() stuff : was unused and non-working. ------------------------------------------------------------------------ r403 | ajapted | 2012-12-06 15:52:22 +1100 (Thu, 06 Dec 2012) | 2 lines Key propagation: moved more checks into mode-specific functions. ------------------------------------------------------------------------ r402 | ajapted | 2012-12-06 15:39:22 +1100 (Thu, 06 Dec 2012) | 3 lines Key propagation: have a handler function for each editing mode, i.e. Thing_Key(), Sector_Key(), etc... ------------------------------------------------------------------------ r401 | ajapted | 2012-12-06 15:22:50 +1100 (Thu, 06 Dec 2012) | 2 lines Config: removed OPT_STRINGBUF8 as a config type (not needed). ------------------------------------------------------------------------ r400 | ajapted | 2012-12-06 14:34:27 +1100 (Thu, 06 Dec 2012) | 5 lines Key propagation: 1. the Global_Key() handler has highest priority 2. moved handling of TAB and browser open keys to Global_Key() 3. new function: CMD_Toggle3Dview() ------------------------------------------------------------------------ r399 | ajapted | 2012-12-06 11:11:08 +1100 (Thu, 06 Dec 2012) | 2 lines Partial work on new keyboard propagation logic.... ------------------------------------------------------------------------ r398 | ajapted | 2012-12-06 10:34:09 +1100 (Thu, 06 Dec 2012) | 2 lines CHANGELOG updated. ------------------------------------------------------------------------ r397 | ajapted | 2012-12-06 10:32:08 +1100 (Thu, 06 Dec 2012) | 2 lines UI / Default props: persist the hidden/shown state. ------------------------------------------------------------------------ r396 | ajapted | 2012-12-06 10:18:11 +1100 (Thu, 06 Dec 2012) | 3 lines UI / Default props: added a button which hides/shows the properties (since they can be distracting during normal editing). ------------------------------------------------------------------------ r395 | ajapted | 2012-12-05 23:11:45 +1100 (Wed, 05 Dec 2012) | 2 lines minor commenting... ------------------------------------------------------------------------ r394 | ajapted | 2012-12-05 23:10:08 +1100 (Wed, 05 Dec 2012) | 3 lines Fixed Props_LoadValues() being called too early (before main_win was created) and hence not working. ------------------------------------------------------------------------ r393 | ajapted | 2012-12-05 23:09:03 +1100 (Wed, 05 Dec 2012) | 2 lines Game defs / DOOM: changed default_thing --> 2014 (health potion) ------------------------------------------------------------------------ r392 | ajapted | 2012-12-05 23:03:53 +1100 (Wed, 05 Dec 2012) | 2 lines UI / Default props: ability to set wall textures via the browser. ------------------------------------------------------------------------ r391 | ajapted | 2012-12-05 22:50:22 +1100 (Wed, 05 Dec 2012) | 2 lines UI / Default props: ability to set sector flats via the browser. ------------------------------------------------------------------------ r390 | ajapted | 2012-12-05 22:44:37 +1100 (Wed, 05 Dec 2012) | 2 lines minor rename, UI_Sector::SetTexture() --> SetFlat() ------------------------------------------------------------------------ r389 | ajapted | 2012-12-05 22:40:54 +1100 (Wed, 05 Dec 2012) | 2 lines UI / Default props: ability to set default thing via the browser. ------------------------------------------------------------------------ r388 | ajapted | 2012-12-05 22:33:29 +1100 (Wed, 05 Dec 2012) | 2 lines Browser: got existing stuff working again via the new system. ------------------------------------------------------------------------ r387 | ajapted | 2012-12-05 22:23:43 +1100 (Wed, 05 Dec 2012) | 4 lines Browser: partial work on passing all browser selections through a new 'BrowsedItem()' method of UI_MainWin class. This method will decide what to do with the selected item. ------------------------------------------------------------------------ r386 | ajapted | 2012-12-05 21:35:27 +1100 (Wed, 05 Dec 2012) | 4 lines UI / Default props: allow pics to be selected, opening the browser in the right mode. Unselect the pics when browser is closed. Don't allow both textures and flats to be selected. ------------------------------------------------------------------------ r385 | ajapted | 2012-12-05 21:16:01 +1100 (Wed, 05 Dec 2012) | 3 lines UI / Default Props: got the texture and flat input fields working, and make sure the name is normalized (uppercased and length limited). ------------------------------------------------------------------------ r384 | ajapted | 2012-12-05 21:02:31 +1100 (Wed, 05 Dec 2012) | 4 lines UI / Default Props: 1. got the floor_h / ceil_h / light input fields working 2. fixed bug parsing the "thing" value from a user state file ------------------------------------------------------------------------ r383 | ajapted | 2012-12-05 20:50:48 +1100 (Wed, 05 Dec 2012) | 2 lines UI / Default Props: implemented callbacks for height buttons. ------------------------------------------------------------------------ r382 | ajapted | 2012-12-05 20:05:55 +1100 (Wed, 05 Dec 2012) | 2 lines UI / Default Props: added Props_LoadValues() function, call it where needed. ------------------------------------------------------------------------ r381 | ajapted | 2012-12-05 20:04:53 +1100 (Wed, 05 Dec 2012) | 2 lines Browser: for textual modes, pack them a bit tighter vertically (show more). ------------------------------------------------------------------------ r380 | ajapted | 2012-12-05 19:50:54 +1100 (Wed, 05 Dec 2012) | 3 lines UI / Default Props: implemented LoadValues() method to setup each widget with the current values. ------------------------------------------------------------------------ r379 | ajapted | 2012-12-05 19:38:05 +1100 (Wed, 05 Dec 2012) | 3 lines UI / Default Props: implemented Props_ParseUser(), and changed the write code to use a space after "default". ------------------------------------------------------------------------ r378 | ajapted | 2012-12-05 19:29:09 +1100 (Wed, 05 Dec 2012) | 2 lines Utils: added StringTidy() function. ------------------------------------------------------------------------ r377 | ajapted | 2012-12-05 19:21:00 +1100 (Wed, 05 Dec 2012) | 2 lines UI / Default Props: implemented Props_WriteUser(). ------------------------------------------------------------------------ r376 | ajapted | 2012-12-05 19:19:52 +1100 (Wed, 05 Dec 2012) | 2 lines New util function: StringRemoveCRLF(). ------------------------------------------------------------------------ r375 | ajapted | 2012-12-05 17:19:24 +1100 (Wed, 05 Dec 2012) | 2 lines Config: remove trailing LF (and/or CR) from .dat lines, for better warning messages. ------------------------------------------------------------------------ r374 | ajapted | 2012-12-05 17:12:33 +1100 (Wed, 05 Dec 2012) | 2 lines minor renaming. ------------------------------------------------------------------------ r373 | ajapted | 2012-12-05 15:29:09 +1100 (Wed, 05 Dec 2012) | 5 lines UI / Default Props: make consistent use of 'default_xxx' global vars, which replace the 'g_default_xxx' ones in m_game.cc/h. Moved their definition into e_basis.cc (that's the primary place they are used). Simplified some of the names. ------------------------------------------------------------------------ r372 | ajapted | 2012-12-05 15:11:00 +1100 (Wed, 05 Dec 2012) | 3 lines Config: removed default_floor_height, default_middle_texture (etc...) as config variables -- they are now considered as user state of a map. ------------------------------------------------------------------------ r371 | ajapted | 2012-12-05 15:09:06 +1100 (Wed, 05 Dec 2012) | 3 lines UI / Default Props: skeletal functions to read/write the properties into the user state of a map. ------------------------------------------------------------------------ r370 | ajapted | 2012-12-05 15:01:33 +1100 (Wed, 05 Dec 2012) | 2 lines UI: tweaked layout of sidedef pics. ------------------------------------------------------------------------ r369 | ajapted | 2012-12-05 14:29:30 +1100 (Wed, 05 Dec 2012) | 2 lines UI: tweaked layout of sector floor / ceiling properties. ------------------------------------------------------------------------ r368 | ajapted | 2012-12-04 22:36:45 +1100 (Tue, 04 Dec 2012) | 2 lines minor update. ------------------------------------------------------------------------ r367 | ajapted | 2012-12-04 22:34:18 +1100 (Tue, 04 Dec 2012) | 3 lines Sector mode: handle CTRL key with floor/ceiling height adjusters, stepping by 64 units. ------------------------------------------------------------------------ r366 | ajapted | 2012-12-04 22:30:50 +1100 (Tue, 04 Dec 2012) | 9 lines Sector mode: swapped keys to height adjusting: '.' and ',' now adjust the floor height, and '[' and ']' now adjust the ceiling. This was suggested by d1337r. The rationale is that '.' and ',' are lower on the keyboard than the '[' and ']' keys. Also made step amounts consistent between the keys and the GUI buttons: 8 units with no modifier, 1 unit shifted. ------------------------------------------------------------------------ r365 | ajapted | 2012-12-04 22:17:28 +1100 (Tue, 04 Dec 2012) | 5 lines 3D View: 1. disabled '.' and ',' as strafe keys (a sector function using these keys is more important) 2. allow UP and DOWN arrows to work with ALT pressed. ------------------------------------------------------------------------ r364 | ajapted | 2012-12-04 20:12:51 +1100 (Tue, 04 Dec 2012) | 4 lines UI / Default Props: 1. added Thing number and description 2. disabled the sector title (it is fairly obvious) ------------------------------------------------------------------------ r363 | ajapted | 2012-12-04 19:58:30 +1100 (Tue, 04 Dec 2012) | 2 lines UI / Default Props: added and layouted the Sector props. ------------------------------------------------------------------------ r362 | ajapted | 2012-12-04 19:32:17 +1100 (Tue, 04 Dec 2012) | 2 lines UI / Default Props: added widgets for the Linedef textures. ------------------------------------------------------------------------ r361 | ajapted | 2012-12-04 19:19:13 +1100 (Tue, 04 Dec 2012) | 4 lines UI: began work on a 'Default Props' panel, which sits underneath the Vertex panel (with all that unused space) and will be used for setting the default insert properties of objects (e.g. sector floor, wall tex). ------------------------------------------------------------------------ r360 | ajapted | 2012-12-04 19:08:15 +1100 (Tue, 04 Dec 2012) | 2 lines minor commenting. ------------------------------------------------------------------------ r359 | ajapted | 2012-12-04 18:47:00 +1100 (Tue, 04 Dec 2012) | 2 lines Coding: use 'WINDOW_BG' define for window backgrounds. ------------------------------------------------------------------------ r358 | ajapted | 2012-12-04 18:24:44 +1100 (Tue, 04 Dec 2012) | 3 lines Changed default grid size to be 16 (was: 128), and added two new config vars: 'default_grid_size' and 'default_grid_snap'. ------------------------------------------------------------------------ r357 | ajapted | 2012-12-04 18:20:49 +1100 (Tue, 04 Dec 2012) | 2 lines Properly initialise the Grid_State_c object. ------------------------------------------------------------------------ r356 | ajapted | 2012-12-04 18:16:51 +1100 (Tue, 04 Dec 2012) | 2 lines UI: tweaked grid color when zoomed far out (GRID_DARK). ------------------------------------------------------------------------ r355 | ajapted | 2012-12-04 16:55:06 +1100 (Tue, 04 Dec 2012) | 2 lines Made multi-select optional, with new 'multi_select_modifier' config var. ------------------------------------------------------------------------ r354 | ajapted | 2012-12-04 16:15:10 +1100 (Tue, 04 Dec 2012) | 4 lines Code tidying: replaced 'is_butl' and 'is_middle' hacks with 'button_down' field in the Editor_State_c class. Replaced 'click_ctrl' with 'button_mod' field. Removed some dead code. ------------------------------------------------------------------------ r353 | ajapted | 2012-12-04 14:49:13 +1100 (Tue, 04 Dec 2012) | 2 lines UI: changed the grid_snap from a Choice --> Toggle_Button. ------------------------------------------------------------------------ r352 | ajapted | 2012-12-04 14:15:42 +1100 (Tue, 04 Dec 2012) | 3 lines WISHLIST: added a few items, moved a few others, fleshed out the item about configurable keys. ------------------------------------------------------------------------ r351 | ajapted | 2012-12-03 22:16:39 +1100 (Mon, 03 Dec 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r350 | ajapted | 2012-12-03 22:15:21 +1100 (Mon, 03 Dec 2012) | 5 lines Building Nodes: added the following config vars: 1. glbsp_fast 2. glbsp_verbose 3. glbsp_warn ------------------------------------------------------------------------ r349 | ajapted | 2012-12-03 20:33:45 +1100 (Mon, 03 Dec 2012) | 3 lines Worked on supporting a configurable GUI scheme and color set, via two new config vars: 'gui_scheme' and 'gui_color_set'. ------------------------------------------------------------------------ r348 | ajapted | 2012-12-03 16:06:37 +1100 (Mon, 03 Dec 2012) | 2 lines TODO and WISHLIST: added some suggestions by d1337r. ------------------------------------------------------------------------ r347 | ajapted | 2012-12-03 15:17:22 +1100 (Mon, 03 Dec 2012) | 3 lines Fixed color of a line or sector when tagged -- only the tagged object should be drawn in pink, not the current line or sector. ------------------------------------------------------------------------ r346 | ajapted | 2012-12-03 14:55:24 +1100 (Mon, 03 Dec 2012) | 1 line compiler warning ------------------------------------------------------------------------ r345 | ajapted | 2012-12-03 14:24:25 +1100 (Mon, 03 Dec 2012) | 3 lines DOOM defs: moved 'Commander Keen' thing out of common/, since it is specific to DOOM 2, and changed its category to OTHER. ------------------------------------------------------------------------ r344 | ajapted | 2012-12-03 10:26:25 +1100 (Mon, 03 Dec 2012) | 2 lines Version bump after release (a little late...) ------------------------------------------------------------------------ r343 | ajapted | 2012-12-03 10:25:17 +1100 (Mon, 03 Dec 2012) | 2 lines TODO and WISHLIST update. ------------------------------------------------------------------------ r342 | ajapted | 2012-12-03 10:21:00 +1100 (Mon, 03 Dec 2012) | 2 lines Renamed doom_common.ugh --> doom_things.ugh ------------------------------------------------------------------------ r341 | ajapted | 2012-12-03 10:20:19 +1100 (Mon, 03 Dec 2012) | 5 lines DOOM definitions: 1. split off common textures into its own file: common/doom_tex 2. moved 'sky_flat', 'default_port' (etc) back to main def (in games/) 3. will rename doom_common.ugh --> doom_things.ugh ------------------------------------------------------------------------ r340 | ajapted | 2012-12-03 09:57:35 +1100 (Mon, 03 Dec 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r339 | ajapted | 2012-12-03 09:57:11 +1100 (Mon, 03 Dec 2012) | 3 lines Browser: added 'pic_mode' field to Browser_Box, replaces hard-coded tests against the browser kind (e.g. for resizing behavior). ------------------------------------------------------------------------ r338 | ajapted | 2012-12-03 09:40:26 +1100 (Mon, 03 Dec 2012) | 3 lines Browser / Things: implemented the 'pics' button, show sprites when on and show descriptions when off. ------------------------------------------------------------------------ r337 | ajapted | 2012-12-03 09:18:46 +1100 (Mon, 03 Dec 2012) | 3 lines Browser: added a 'number' field to each Browser_Item, and use it when sorting numerically (and in the callbacks too). ------------------------------------------------------------------------ r336 | ajapted | 2012-12-02 23:24:43 +1100 (Sun, 02 Dec 2012) | 2 lines minor corrections. ------------------------------------------------------------------------ r335 | ajapted | 2012-12-02 23:23:52 +1100 (Sun, 02 Dec 2012) | 2 lines Game defs: moved boss-brain things out of 'Monster' category. ------------------------------------------------------------------------ r334 | ajapted | 2012-12-02 23:16:43 +1100 (Sun, 02 Dec 2012) | 2 lines Tweak : changed thingtype_t::flags field from byte to short. ------------------------------------------------------------------------ r333 | ajapted | 2012-12-02 23:14:22 +1100 (Sun, 02 Dec 2012) | 4 lines Browser | Thing pics: 1. ignore things which have no sprites ("NULL" in the def file). 2. alphabetical sort shows sprite names, numerical sort shows id numbers. ------------------------------------------------------------------------ r332 | ajapted | 2012-12-02 16:55:39 +1100 (Sun, 02 Dec 2012) | 2 lines Browser: initial work on picture mode for Things... ------------------------------------------------------------------------ r331 | ajapted | 2012-12-02 14:21:42 +1100 (Sun, 02 Dec 2012) | 3 lines Removed doc/Features.txt : the info has been absorbed into README.txt and the website. ------------------------------------------------------------------------ r330 | ajapted | 2012-12-02 14:19:24 +1100 (Sun, 02 Dec 2012) | 2 lines README.txt : added 'Features' and 'Supported Games' sections (from wiki). ------------------------------------------------------------------------ r329 | ajapted | 2012-12-01 20:49:36 +1100 (Sat, 01 Dec 2012) | 2 lines Added AUTHORS.txt document. ------------------------------------------------------------------------ r328 | ajapted | 2012-11-30 22:19:08 +1100 (Fri, 30 Nov 2012) | 3 lines Worked on the Jump/Next/Previous commands. However I don't think they are very useful... ------------------------------------------------------------------------ r327 | ajapted | 2012-11-30 21:02:29 +1100 (Fri, 30 Nov 2012) | 3 lines Simplified how new sector squares are created outside of the map, size is fixed but configurable via 'new_sector_size' config var. ------------------------------------------------------------------------ r326 | ajapted | 2012-11-30 20:24:18 +1100 (Fri, 30 Nov 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r325 | ajapted | 2012-11-30 20:23:47 +1100 (Fri, 30 Nov 2012) | 2 lines Rotate dialog: implemented its functionality. ------------------------------------------------------------------------ r324 | ajapted | 2012-11-30 19:47:18 +1100 (Fri, 30 Nov 2012) | 2 lines Rotate dialog: began work on it, got the layout done so far... ------------------------------------------------------------------------ r323 | ajapted | 2012-11-30 19:24:20 +1100 (Fri, 30 Nov 2012) | 3 lines When rotating a group of things (or sectors which contain things), update the angles of the things too. ------------------------------------------------------------------------ r322 | ajapted | 2012-11-30 19:09:36 +1100 (Fri, 30 Nov 2012) | 2 lines Scale dialog: fixed percentage parsing ------------------------------------------------------------------------ r321 | ajapted | 2012-11-30 19:02:25 +1100 (Fri, 30 Nov 2012) | 2 lines Scale dialog: completed the functionality. ------------------------------------------------------------------------ r320 | ajapted | 2012-11-30 18:53:41 +1100 (Fri, 30 Nov 2012) | 2 lines Scale dialog: implemented parsing code: ParseScaleStr(). ------------------------------------------------------------------------ r319 | ajapted | 2012-11-30 18:41:33 +1100 (Fri, 30 Nov 2012) | 3 lines Scale dialog: Partial work implementing the scaling, e.g. added code to determine the focus point of scaling from the 'origin' choice. ------------------------------------------------------------------------ r318 | ajapted | 2012-11-30 16:46:33 +1100 (Fri, 30 Nov 2012) | 4 lines Scale dialog layouting: 1. added 'origin' button 2. rearranged bottom section, added some help text ------------------------------------------------------------------------ r317 | ajapted | 2012-11-30 16:04:08 +1100 (Fri, 30 Nov 2012) | 2 lines Move dialog: ensure initial values are zero. ------------------------------------------------------------------------ r316 | ajapted | 2012-11-30 15:57:37 +1100 (Fri, 30 Nov 2012) | 2 lines Began work on 'Scale Objects' dialog... ------------------------------------------------------------------------ r315 | ajapted | 2012-11-30 15:25:59 +1100 (Fri, 30 Nov 2012) | 2 lines Implemented the functionality of the Move dialog. ------------------------------------------------------------------------ r314 | ajapted | 2012-11-30 15:11:29 +1100 (Fri, 30 Nov 2012) | 3 lines Finished layout on UI_MoveDialog window (e.g. added a darker group around the buttons). Renamed "OK" button --> "Move" and made it bold. ------------------------------------------------------------------------ r313 | ajapted | 2012-11-30 14:49:21 +1100 (Fri, 30 Nov 2012) | 3 lines Partial work on a dialog window for moving objects (via the Edit menu). Still in the layout phase.... ------------------------------------------------------------------------ r312 | ajapted | 2012-11-30 14:33:18 +1100 (Fri, 30 Nov 2012) | 3 lines Added new (empty) code files: ui_misc.cc/h -- for miscellaneous dialog windows, such as a move object dialog.... ------------------------------------------------------------------------ r311 | ajapted | 2012-11-30 14:05:10 +1100 (Fri, 30 Nov 2012) | 2 lines Disabled the 'Play Map' feature for now. ------------------------------------------------------------------------ r310 | ajapted | 2012-11-30 10:43:23 +1100 (Fri, 30 Nov 2012) | 2 lines Changed shortcut key for 'File/Export Map' to CTRL-E ------------------------------------------------------------------------ r309 | ajapted | 2012-11-30 10:34:47 +1100 (Fri, 30 Nov 2012) | 4 lines Experiment with a 'File/Play Map' command (CTRL-P). Currently the directory to enter and program to run are hard-coded, these would need to be configurable. ------------------------------------------------------------------------ r308 | ajapted | 2012-11-28 22:37:36 +1100 (Wed, 28 Nov 2012) | 2 lines Began a fresh CHANGES.txt file, tweaked previous one. ------------------------------------------------------------------------ r307 | ajapted | 2012-11-28 22:35:52 +1100 (Wed, 28 Nov 2012) | 2 lines Moved CHANGES.txt --> docs/ folder, after the 0.84 release. ------------------------------------------------------------------------ r306 | ajapted | 2012-11-28 17:44:41 +1100 (Wed, 28 Nov 2012) | 3 lines MacOS X: set home_dir to '~/documents/eureka', making sure we create the ~/documents folder (in case it doesn't exist). ------------------------------------------------------------------------ r305 | ajapted | 2012-11-28 16:30:40 +1100 (Wed, 28 Nov 2012) | 2 lines Renamed 'Nil' method --> 'Clear' (for MacOS X compatibility). ------------------------------------------------------------------------ r304 | ajapted | 2012-11-27 18:09:20 +1100 (Tue, 27 Nov 2012) | 2 lines pack-source script: added debian stuff. ------------------------------------------------------------------------ r303 | ajapted | 2012-11-27 17:55:17 +1100 (Tue, 27 Nov 2012) | 2 lines INSTALL.txt : mention /usr/share/games/doom ------------------------------------------------------------------------ r302 | ajapted | 2012-11-27 17:49:20 +1100 (Tue, 27 Nov 2012) | 2 lines TODO and WISHLIST updated before release. ------------------------------------------------------------------------ r301 | ajapted | 2012-11-27 17:18:59 +1100 (Tue, 27 Nov 2012) | 2 lines README.txt : added a REQUIREMENTS section. ------------------------------------------------------------------------ r300 | ajapted | 2012-11-27 17:06:41 +1100 (Tue, 27 Nov 2012) | 2 lines CHANGELOG: yet another update. ------------------------------------------------------------------------ r299 | ajapted | 2012-11-27 17:04:48 +1100 (Tue, 27 Nov 2012) | 2 lines Made vertices slightly bigger, but not too big when zooming right in. ------------------------------------------------------------------------ r298 | ajapted | 2012-11-27 16:00:39 +1100 (Tue, 27 Nov 2012) | 2 lines TODO / WISHLIST update. ------------------------------------------------------------------------ r297 | ajapted | 2012-11-27 15:57:34 +1100 (Tue, 27 Nov 2012) | 4 lines Implemented a 'mouse_wheel_scrolls_map' config var, when enabled the mouse wheel will scroll the map (can do horizontally too). Pressing the CTRL key (ALT in MacOS X) will perform the zoom function. ------------------------------------------------------------------------ r296 | ajapted | 2012-11-27 15:31:52 +1100 (Tue, 27 Nov 2012) | 2 lines Handle '+' and '-' zooming keys by calling CMD_Zoom() directly (NOT via Editor_Wheel). ------------------------------------------------------------------------ r295 | ajapted | 2012-11-27 15:27:56 +1100 (Tue, 27 Nov 2012) | 3 lines UI_Canvas: tidier event handling code, added handle_key(), handle_push() (and so forth) methods to manage the major event kinds. ------------------------------------------------------------------------ r294 | ajapted | 2012-11-26 22:44:55 +1100 (Mon, 26 Nov 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r293 | ajapted | 2012-11-26 15:00:00 +1100 (Mon, 26 Nov 2012) | 2 lines Version bump to 0.84, ready for release. ------------------------------------------------------------------------ r292 | ajapted | 2012-11-26 14:44:49 +1100 (Mon, 26 Nov 2012) | 2 lines commenting... ------------------------------------------------------------------------ r291 | ajapted | 2012-11-26 12:18:55 +1100 (Mon, 26 Nov 2012) | 2 lines Moved Makefile.debian --> misc/ directory. ------------------------------------------------------------------------ r290 | ajapted | 2012-11-25 21:29:25 +1100 (Sun, 25 Nov 2012) | 2 lines Makefile.debian : fixed for moving 'debian' dir --> misc/ ------------------------------------------------------------------------ r289 | ajapted | 2012-11-25 21:23:33 +1100 (Sun, 25 Nov 2012) | 2 lines Moved 'debian' folder from top level --> misc/ folder ------------------------------------------------------------------------ r288 | ajapted | 2012-11-25 21:13:45 +1100 (Sun, 25 Nov 2012) | 7 lines Makefile.debian fixes: 1. added missing PROGRAM value 2. gzip the changelog file 3. do a 'debclean' before doing a 'debbuild' 4. store result in parent dir -- this also gives it the proper package name, with version and architecture in it. ------------------------------------------------------------------------ r287 | ajapted | 2012-11-25 21:07:37 +1100 (Sun, 25 Nov 2012) | 3 lines Removed debian stuff from plain Makefile. (This change should have been in r284....) ------------------------------------------------------------------------ r286 | ajapted | 2012-11-25 21:04:09 +1100 (Sun, 25 Nov 2012) | 3 lines Debian/copyright: indented Copyright lines, which fixes a lintian warning about lacking a copyright statement ^_^ ------------------------------------------------------------------------ r285 | ajapted | 2012-11-25 21:02:20 +1100 (Sun, 25 Nov 2012) | 3 lines Debian/control: changed section to 'misc' and added 'libc6' as a dependency -- both due to lintian errors. ------------------------------------------------------------------------ r284 | ajapted | 2012-11-25 20:43:00 +1100 (Sun, 25 Nov 2012) | 2 lines Makefiles: removed debian package stuff from plain Makefile. ------------------------------------------------------------------------ r283 | ajapted | 2012-11-25 20:41:02 +1100 (Sun, 25 Nov 2012) | 2 lines Added Makefile.debian, logic for making a debian package. ------------------------------------------------------------------------ r282 | ajapted | 2012-11-25 20:37:49 +1100 (Sun, 25 Nov 2012) | 2 lines Debian: tweaked version in debian/control, removed # comment ------------------------------------------------------------------------ r281 | ajapted | 2012-11-25 20:21:20 +1100 (Sun, 25 Nov 2012) | 3 lines Makefile: partial work on 'debinstall' target to create the file heirarchy for the debian package. ------------------------------------------------------------------------ r280 | ajapted | 2012-11-25 18:51:50 +1100 (Sun, 25 Nov 2012) | 2 lines Wrote the debian/copyright file. ------------------------------------------------------------------------ r279 | ajapted | 2012-11-25 18:37:17 +1100 (Sun, 25 Nov 2012) | 2 lines Added basic debian/changelog file. ------------------------------------------------------------------------ r278 | ajapted | 2012-11-25 14:14:24 +1100 (Sun, 25 Nov 2012) | 2 lines Initial work on a debian/control file. ------------------------------------------------------------------------ r277 | ajapted | 2012-11-25 13:28:20 +1100 (Sun, 25 Nov 2012) | 2 lines Don't create a linedef between two vertices at the same spot. ------------------------------------------------------------------------ r276 | ajapted | 2012-11-25 13:20:20 +1100 (Sun, 25 Nov 2012) | 2 lines Tweaked get_split_linedef() to skip lines with bbox < 4x4 ------------------------------------------------------------------------ r275 | ajapted | 2012-11-25 13:07:48 +1100 (Sun, 25 Nov 2012) | 2 lines Reworked last commit, don't split lines with bbox < 4x4. ------------------------------------------------------------------------ r274 | ajapted | 2012-11-25 13:04:00 +1100 (Sun, 25 Nov 2012) | 2 lines Fixed split_linedef command ('x' key) to not create zero-length lines. ------------------------------------------------------------------------ r273 | ajapted | 2012-11-25 12:24:55 +1100 (Sun, 25 Nov 2012) | 3 lines Fixed LineDefWouldOverlap() to skip zero-length lines, otherwise it raises a fatal error in PerpDist(). ------------------------------------------------------------------------ r272 | ajapted | 2012-11-24 17:46:35 +1100 (Sat, 24 Nov 2012) | 2 lines ChangeLog tweak. ------------------------------------------------------------------------ r271 | ajapted | 2012-11-24 17:01:01 +1100 (Sat, 24 Nov 2012) | 2 lines README: updated for 0.84 release, fixed the different keys. ------------------------------------------------------------------------ r270 | ajapted | 2012-11-24 15:40:58 +1100 (Sat, 24 Nov 2012) | 2 lines Tweaked code of previous commit (bound 'R' to RTS mode). ------------------------------------------------------------------------ r269 | ajapted | 2012-11-24 15:39:13 +1100 (Sat, 24 Nov 2012) | 2 lines Bound 'R' key for RTS editing mode, frees up 'r' for a more common function. ------------------------------------------------------------------------ r268 | ajapted | 2012-11-24 15:10:49 +1100 (Sat, 24 Nov 2012) | 2 lines TODO update. ------------------------------------------------------------------------ r267 | ajapted | 2012-11-24 15:10:33 +1100 (Sat, 24 Nov 2012) | 2 lines INSTALL.txt : tweakage. ------------------------------------------------------------------------ r266 | ajapted | 2012-11-24 15:09:13 +1100 (Sat, 24 Nov 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r265 | ajapted | 2012-11-24 15:06:20 +1100 (Sat, 24 Nov 2012) | 3 lines Determine split line: removed bbox test (was bad for axis-aligned lines) and fixed the bbox test in get_split_line() which ignored mapslack. ------------------------------------------------------------------------ r264 | ajapted | 2012-11-24 14:46:50 +1100 (Sat, 24 Nov 2012) | 3 lines When finding the split_line, check the non-snapped position, but prevent the snapped position being the same as the linedef's start or end. ------------------------------------------------------------------------ r263 | ajapted | 2012-11-24 14:44:19 +1100 (Sat, 24 Nov 2012) | 2 lines MacOS X: fix pathlen type for _NSGetExecutablePath() call. ------------------------------------------------------------------------ r262 | ajapted | 2012-11-23 22:44:18 +1100 (Fri, 23 Nov 2012) | 2 lines minor docco updates. ------------------------------------------------------------------------ r261 | ajapted | 2012-11-23 21:44:43 +1100 (Fri, 23 Nov 2012) | 2 lines ChangeLog update. ------------------------------------------------------------------------ r260 | ajapted | 2012-11-23 21:42:44 +1100 (Fri, 23 Nov 2012) | 3 lines Made SHIFT + MMB do plain scaling (keep aspect ratio), ALT + MMB to scale X and Y independently. ------------------------------------------------------------------------ r259 | ajapted | 2012-11-23 20:59:45 +1100 (Fri, 23 Nov 2012) | 3 lines Key handling: change the ALT ignore code to return _false_, which means FLTK will send them to other places (especially the menu). ------------------------------------------------------------------------ r258 | ajapted | 2012-11-23 20:51:39 +1100 (Fri, 23 Nov 2012) | 4 lines Key handling: in general, ignore key if ALT is also pressed. Since the META modifier is mapped to KM_ALT, this also ignores keys with META (which I think is the CMD key under MacOS X). ------------------------------------------------------------------------ r257 | ajapted | 2012-11-22 22:23:28 +1100 (Thu, 22 Nov 2012) | 2 lines Implemented the -merge option for adding Resource wads. ------------------------------------------------------------------------ r256 | ajapted | 2012-11-22 22:03:17 +1100 (Thu, 22 Nov 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r255 | ajapted | 2012-11-22 22:02:45 +1100 (Thu, 22 Nov 2012) | 2 lines TODO / WISHLIST update. ------------------------------------------------------------------------ r254 | ajapted | 2012-11-22 21:35:53 +1100 (Thu, 22 Nov 2012) | 3 lines MacOSX: renamed the 'nil' method of Objid / Close_obj classes --> 'clear', since it is a reserved keyword in Objective-C. ------------------------------------------------------------------------ r253 | ajapted | 2012-11-22 21:08:32 +1100 (Thu, 22 Nov 2012) | 3 lines The ESC key no longer exits Eureka, unless the new 'escape_key_quits' config variable is enabled. ------------------------------------------------------------------------ r252 | ajapted | 2012-11-22 19:34:19 +1100 (Thu, 22 Nov 2012) | 2 lines MacOSX: Changed #ifdef tests to use __APPLE__ instead of MACOSX. ------------------------------------------------------------------------ r251 | ajapted | 2012-11-22 19:18:04 +1100 (Thu, 22 Nov 2012) | 4 lines Config: new syntax for config files, option name is followed by the value without any '=' sign between -- which is consistent with the game / port definition files. ------------------------------------------------------------------------ r250 | ajapted | 2012-11-22 17:28:25 +1100 (Thu, 22 Nov 2012) | 2 lines Config: split code to parse each line out of parse_config_file() function. ------------------------------------------------------------------------ r249 | ajapted | 2012-11-22 11:25:06 +1100 (Thu, 22 Nov 2012) | 2 lines WISHLIST: finished reorganising / prioritising the desirables. ------------------------------------------------------------------------ r248 | ajapted | 2012-11-22 11:06:47 +1100 (Thu, 22 Nov 2012) | 3 lines IWAD search: check some standard places, like /usr/share/games/doom (and for Win32, places like C:\DOOM). ------------------------------------------------------------------------ r247 | ajapted | 2012-11-22 10:35:07 +1100 (Thu, 22 Nov 2012) | 3 lines Moved some code in main.cc, like InitFLTK, which was sandwiched in between various config and directory handling stuff. ------------------------------------------------------------------------ r246 | ajapted | 2012-11-21 23:14:05 +1100 (Wed, 21 Nov 2012) | 2 lines WISHLIST: more work reorganising... ------------------------------------------------------------------------ r245 | ajapted | 2012-11-21 22:49:13 +1100 (Wed, 21 Nov 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r244 | ajapted | 2012-11-21 22:28:39 +1100 (Wed, 21 Nov 2012) | 2 lines minor commenting ------------------------------------------------------------------------ r243 | ajapted | 2012-11-21 22:26:08 +1100 (Wed, 21 Nov 2012) | 3 lines Allow Eureka to run locally (without a make install) by checking "." as a possible install_dir. ------------------------------------------------------------------------ r242 | ajapted | 2012-11-21 22:18:24 +1100 (Wed, 21 Nov 2012) | 2 lines INSTALL.txt : mention Gentoo info (courtesy GuntherDW). ------------------------------------------------------------------------ r241 | ajapted | 2012-11-21 22:12:59 +1100 (Wed, 21 Nov 2012) | 2 lines Config: fixed bug in recent change of OPT_BOOLEAN handling. ------------------------------------------------------------------------ r240 | ajapted | 2012-11-21 19:40:11 +1100 (Wed, 21 Nov 2012) | 2 lines WISHLIST: began reorganizing into HIGH and LOWER priority sections... ------------------------------------------------------------------------ r239 | ajapted | 2012-11-21 19:06:28 +1100 (Wed, 21 Nov 2012) | 4 lines Config: added 'new_islands_are_void' variable -- it forces islands created inside a sector to have a void interior (rather than a new sector which has same properties as the outer sector). ------------------------------------------------------------------------ r238 | ajapted | 2012-11-21 18:58:25 +1100 (Wed, 21 Nov 2012) | 5 lines Config handling: 1. can provide a value on command line for OPT_BOOLEAN vars 2. removed redundant checks on o->data_ptr (only NULL for OPT_END) 3. made boolean and confirm keywords case-insensitive ------------------------------------------------------------------------ r237 | ajapted | 2012-11-21 18:31:18 +1100 (Wed, 21 Nov 2012) | 2 lines TODO update. ------------------------------------------------------------------------ r236 | ajapted | 2012-11-21 18:30:22 +1100 (Wed, 21 Nov 2012) | 2 lines CHANGELOG: mention the new pic-selection feature. ------------------------------------------------------------------------ r235 | ajapted | 2012-11-21 18:28:39 +1100 (Wed, 21 Nov 2012) | 2 lines Closing the browser unselects any pics in the LineDef and Sector panels. ------------------------------------------------------------------------ r234 | ajapted | 2012-11-21 18:18:34 +1100 (Wed, 21 Nov 2012) | 4 lines LineDef Panel: implemented the selected sidedef parts (with red border) getting a texture when clicking in the texture browser -- the mouse button and modifier keys are not used when any parts are selected. ------------------------------------------------------------------------ r233 | ajapted | 2012-11-21 17:27:01 +1100 (Wed, 21 Nov 2012) | 5 lines Sector panel: implemented the pic selection, i.e. when the floor pic is selected then the floor is changed and when the ceiling pic is selected then the ceiling is changed. The mouse button is ignored when one of them is selected. ------------------------------------------------------------------------ r232 | ajapted | 2012-11-21 16:20:48 +1100 (Wed, 21 Nov 2012) | 2 lines LineDef and Sector panels: don't select pic when there's no object(s). ------------------------------------------------------------------------ r231 | ajapted | 2012-11-21 16:16:35 +1100 (Wed, 21 Nov 2012) | 4 lines LineDef and Sector panels: code to clear the selected pics, automatic when the panel is disabled (NO_OBJ), and can be done externally (e.g. when changing editing modes). ------------------------------------------------------------------------ r230 | ajapted | 2012-11-21 16:02:51 +1100 (Wed, 21 Nov 2012) | 2 lines Use CMD_UnselectAll() for the click-in-empty-spot action. ------------------------------------------------------------------------ r229 | ajapted | 2012-11-21 15:51:04 +1100 (Wed, 21 Nov 2012) | 5 lines 1. added ability to UI_Pic to select/unselect it (done externally) 2. in Sector and SideDef panels, can select/unselect the textures and also open/change the browser to Flats or Textures. (Note: still lacking mechanism to actually change the selected stuff) ------------------------------------------------------------------------ r228 | ajapted | 2012-11-21 14:15:49 +1100 (Wed, 21 Nov 2012) | 2 lines UI_Pic: implemented a draw_selected() method. ------------------------------------------------------------------------ r227 | ajapted | 2012-11-21 12:46:06 +1100 (Wed, 21 Nov 2012) | 3 lines Makefile: remove wayward initial space (stops emacs complaining when saving). Patch courtesy Jeremy Henty. ------------------------------------------------------------------------ r226 | ajapted | 2012-11-21 12:39:32 +1100 (Wed, 21 Nov 2012) | 3 lines Implemented 'leave_offsets_alone' config var -- when set, no automatic adjustment of sidedef offsets when splitting lines (etc). ------------------------------------------------------------------------ r225 | ajapted | 2012-11-21 12:31:39 +1100 (Wed, 21 Nov 2012) | 3 lines Thing panel: experimented with option buttons for Hexen player classes, and hence moved the 'ambush' and 'friend' buttons onto their own line. ------------------------------------------------------------------------ r224 | ajapted | 2012-11-20 22:47:29 +1100 (Tue, 20 Nov 2012) | 2 lines TODO, WISHLIST, CHANGELOG update ------------------------------------------------------------------------ r223 | ajapted | 2012-11-20 22:43:32 +1100 (Tue, 20 Nov 2012) | 3 lines UI_Canvas: fixed bug where a pink-highlighted sectors with tag matching the linedef would not be drawn if the linedef was off the screen. ------------------------------------------------------------------------ r222 | ajapted | 2012-11-20 22:34:58 +1100 (Tue, 20 Nov 2012) | 2 lines LineDef panel: experiment with 'Args' line (for Hexen support) ------------------------------------------------------------------------ r221 | ajapted | 2012-11-20 21:23:19 +1100 (Tue, 20 Nov 2012) | 3 lines Multi-select: handle a small selbox as if it were a click/release pair (clearing the current selection) -- shrink the small selbox to zero. ------------------------------------------------------------------------ r220 | ajapted | 2012-11-20 21:07:22 +1100 (Tue, 20 Nov 2012) | 2 lines Insert_Thing: if a thing is already selected, copy properties to new one. ------------------------------------------------------------------------ r219 | ajapted | 2012-11-20 20:58:04 +1100 (Tue, 20 Nov 2012) | 14 lines Implemented multi-select, i.e. clicking on an object to select it will not clear the current selection first -- merely toggle it. This required some big changes and a hack or two, for one thing when clicking on an object, it's selection status is changed when the the mouse button is _released_ (or user tries to drag it). Also to allow dragging individual objects, after any objects are moved we will clear the selection when an unselected object is clicked on (to select it). Removed the dummy 'CANVAS' object kind, we now properly test whether we are drawing a selbox by the isSelboxActive() call. ------------------------------------------------------------------------ r218 | ajapted | 2012-11-20 17:57:55 +1100 (Tue, 20 Nov 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r217 | ajapted | 2012-11-20 17:48:00 +1100 (Tue, 20 Nov 2012) | 3 lines Fixed inner sector getting defaults when closing a vertex loop which lies within another sector -- the inner should be a copy of the outer. ------------------------------------------------------------------------ r216 | ajapted | 2012-11-19 22:47:45 +1100 (Mon, 19 Nov 2012) | 4 lines Changed the way level checksum is done (for state persistence), it is no longer done directly in the loading and saving code (and performed on the raw formats), now it is computed on the in-memory version of the map. ------------------------------------------------------------------------ r215 | ajapted | 2012-11-19 22:36:36 +1100 (Mon, 19 Nov 2012) | 2 lines Adler-32: fixed the copy constructor to copy the 'extra' field too. ------------------------------------------------------------------------ r214 | ajapted | 2012-11-19 22:31:29 +1100 (Mon, 19 Nov 2012) | 3 lines Implemented BA_LevelChecksum() which computes the CRC of the level, ignoring any unused vertices, sidedefs or sectors. ------------------------------------------------------------------------ r213 | ajapted | 2012-11-19 21:38:13 +1100 (Mon, 19 Nov 2012) | 3 lines Browser: set the 'linesize' to higher values, so that scrolling with the mouse wheel is better (not so tedious). ------------------------------------------------------------------------ r212 | ajapted | 2012-11-19 21:35:21 +1100 (Mon, 19 Nov 2012) | 2 lines Browser: made default width be a bit wider (to fit 4 flats across). ------------------------------------------------------------------------ r211 | ajapted | 2012-11-19 16:51:43 +1100 (Mon, 19 Nov 2012) | 2 lines TODO update. ------------------------------------------------------------------------ r210 | ajapted | 2012-11-19 16:51:07 +1100 (Mon, 19 Nov 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r209 | ajapted | 2012-11-19 16:50:10 +1100 (Mon, 19 Nov 2012) | 3 lines 1. Support a "default_port" command in game definition files 2. Made the fallback port be "vanilla" -- for Heretic ------------------------------------------------------------------------ r208 | ajapted | 2012-11-19 16:42:27 +1100 (Mon, 19 Nov 2012) | 2 lines DOOM defs: added "default_port boom" ------------------------------------------------------------------------ r207 | ajapted | 2012-11-19 16:35:03 +1100 (Mon, 19 Nov 2012) | 2 lines Game def loader: tidied up 'buf' usage, renamed other 'buf' variables. ------------------------------------------------------------------------ r206 | ajapted | 2012-11-19 14:32:53 +1100 (Mon, 19 Nov 2012) | 5 lines lib_file: added GetExecutablePath() function, needed for Win32 builds. Code is from Oblige's lib_file.cc, which I removed earlier as I didn't think it would be needed. ------------------------------------------------------------------------ r205 | ajapted | 2012-11-18 22:26:32 +1100 (Sun, 18 Nov 2012) | 2 lines Updated CHANGELOG, TODO and WISHLIST. ------------------------------------------------------------------------ r204 | ajapted | 2012-11-18 21:38:32 +1100 (Sun, 18 Nov 2012) | 2 lines Thing panel: got new arrow buttons working, and improved the layout. ------------------------------------------------------------------------ r203 | ajapted | 2012-11-18 21:28:24 +1100 (Sun, 18 Nov 2012) | 2 lines Arrow images: trimmed the diagonal arrows, look better now. ------------------------------------------------------------------------ r202 | ajapted | 2012-11-18 21:21:54 +1100 (Sun, 18 Nov 2012) | 3 lines Thing panel: partial work on eight arrow buttons for setting the angle. These replace the <- and -> buttons which rotated things. ------------------------------------------------------------------------ r201 | ajapted | 2012-11-18 20:42:03 +1100 (Sun, 18 Nov 2012) | 2 lines Added 'im_arrows.cc' containing eight small arrow images (XPM format). ------------------------------------------------------------------------ r200 | ajapted | 2012-11-18 18:58:50 +1100 (Sun, 18 Nov 2012) | 2 lines Experiment to make plain MMB insert new objects.... ------------------------------------------------------------------------ r199 | ajapted | 2012-11-18 18:28:14 +1100 (Sun, 18 Nov 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r198 | ajapted | 2012-11-18 18:26:57 +1100 (Sun, 18 Nov 2012) | 8 lines 3D View: 1. support WASD keys for movement 2. rebound 's' key to 'o' (toggle sprites) and 'w' --> 'v' 3. added 'g' key to toggle gravity 4. removed CTRL-L : resync thing Zs when toggling sprites Note (1) and (3) were suggested by Dragonsbrethen. ------------------------------------------------------------------------ r197 | ajapted | 2012-11-18 13:38:51 +1100 (Sun, 18 Nov 2012) | 2 lines INSTALL.txt : mention some libraries people may need (thanks to DoomGater). ------------------------------------------------------------------------ r196 | ajapted | 2012-11-18 13:37:44 +1100 (Sun, 18 Nov 2012) | 2 lines Began a fresh CHANGES.txt document ------------------------------------------------------------------------ r195 | ajapted | 2012-11-18 13:36:10 +1100 (Sun, 18 Nov 2012) | 2 lines Moved CHANGES.txt --> docs folder (after 0.81 release) ------------------------------------------------------------------------ r194 | ajapted | 2012-11-18 13:35:17 +1100 (Sun, 18 Nov 2012) | 2 lines CMD_BuildNodes: on success, re-open the wad and reload the map. ------------------------------------------------------------------------ r193 | ajapted | 2012-11-18 12:50:12 +1100 (Sun, 18 Nov 2012) | 2 lines Post-release version bump: 0.81 --> 0.82 ------------------------------------------------------------------------ r192 | ajapted | 2012-11-16 20:23:01 +1100 (Fri, 16 Nov 2012) | 2 lines Fixed pack-source.sh script (had some Oblige stuff left in it). ------------------------------------------------------------------------ r191 | ajapted | 2012-11-16 13:58:54 +1100 (Fri, 16 Nov 2012) | 2 lines Checked in 'pack-source.sh' shell script. ------------------------------------------------------------------------ r190 | ajapted | 2012-11-16 13:21:15 +1100 (Fri, 16 Nov 2012) | 2 lines TODO and WISHLIST update. ------------------------------------------------------------------------ r189 | ajapted | 2012-11-16 13:19:55 +1100 (Fri, 16 Nov 2012) | 2 lines CHANGELOG update. ------------------------------------------------------------------------ r188 | ajapted | 2012-11-16 13:17:14 +1100 (Fri, 16 Nov 2012) | 5 lines README.txt: 1. completely rewrote the 'RUNNING' section 2. replaced 'INTRODUCTION' section with text from 'About' wiki page 3. replaced 'KEYBOARD / MOUSE' section with text from wiki ------------------------------------------------------------------------ r187 | ajapted | 2012-11-16 11:37:03 +1100 (Fri, 16 Nov 2012) | 2 lines Renamed changelog files (in docs/) ------------------------------------------------------------------------ r186 | ajapted | 2012-11-15 17:29:09 +1100 (Thu, 15 Nov 2012) | 2 lines minor commenting... ------------------------------------------------------------------------ r185 | ajapted | 2012-11-15 17:24:53 +1100 (Thu, 15 Nov 2012) | 3 lines Improved the way AssignSectorToSpace() sets the default sector props from a neighbor. ------------------------------------------------------------------------ r184 | ajapted | 2012-11-15 16:23:04 +1100 (Thu, 15 Nov 2012) | 2 lines With 'c' copy-prop command on things, do not copy the angle. ------------------------------------------------------------------------ r183 | ajapted | 2012-11-15 16:14:59 +1100 (Thu, 15 Nov 2012) | 2 lines Removed no-longer-used code files: editobj.cc/h ------------------------------------------------------------------------ r182 | ajapted | 2012-11-15 16:11:39 +1100 (Thu, 15 Nov 2012) | 4 lines Implemented new 'c' copy-properties command, which will copy the props of a sector (for example) from the selected one to the highlighted one. Works for things and linedefs too (though linedefs is very limited). ------------------------------------------------------------------------ r181 | ajapted | 2012-11-15 15:52:14 +1100 (Thu, 15 Nov 2012) | 2 lines Moved LineDefAlreadyExists() and LineDefWouldOverlap() code --> e_linedef.cc ------------------------------------------------------------------------ r180 | ajapted | 2012-11-15 12:00:04 +1100 (Thu, 15 Nov 2012) | 2 lines CHANGELOG updated. ------------------------------------------------------------------------ r179 | ajapted | 2012-11-15 11:57:10 +1100 (Thu, 15 Nov 2012) | 3 lines Insert_Sector: when creating a square outside of map, if a sector is already selected then copy the properties to the new sector. ------------------------------------------------------------------------ r178 | ajapted | 2012-11-15 11:45:43 +1100 (Thu, 15 Nov 2012) | 2 lines CMD_MergeSectors: if deleting linedefs, delete unused vertices too. ------------------------------------------------------------------------ r177 | ajapted | 2012-11-15 11:43:32 +1100 (Thu, 15 Nov 2012) | 3 lines Wrote DeleteLineDefs() function which not only deletes a list of lines, but also deletes the unused vertices/sidedefs left over. ------------------------------------------------------------------------ r176 | ajapted | 2012-11-15 11:41:54 +1100 (Thu, 15 Nov 2012) | 3 lines Moved UnusedVertices() and UnusedSideDefs() functions to global scope, and renamed the 'list' parameter to 'lines' (for clearer code). ------------------------------------------------------------------------ r175 | ajapted | 2012-11-15 10:49:38 +1100 (Thu, 15 Nov 2012) | 4 lines Emulate the Yadex (DEU?) behavior where trying to set the same mode as currently active will clear the selection. This is enabled by the 'same_mode_clears_selection' config variable (default is OFF). ------------------------------------------------------------------------ r174 | ajapted | 2012-11-15 10:35:56 +1100 (Thu, 15 Nov 2012) | 5 lines CMD_MergeSectors: reworked way common linedefs are found, only detect them between the source sector and a replaced sector (which prevents removing pre-existing "self-ref" linedefs). Also store them in a selection_c. ------------------------------------------------------------------------ r173 | ajapted | 2012-11-15 10:30:24 +1100 (Thu, 15 Nov 2012) | 2 lines Editor_Key: ensure the new 'm' merge command can only be used in Sectors mode. ------------------------------------------------------------------------ r172 | ajapted | 2012-11-14 22:29:26 +1100 (Wed, 14 Nov 2012) | 2 lines Render 3D: made ALT + LEFT / RIGHT keys strafe instead of turn. ------------------------------------------------------------------------ r171 | ajapted | 2012-11-14 22:22:53 +1100 (Wed, 14 Nov 2012) | 2 lines TODO / WISHLIST update. ------------------------------------------------------------------------ r170 | ajapted | 2012-11-14 19:46:24 +1100 (Wed, 14 Nov 2012) | 3 lines Sector mode: implemented 'm' merge command which merges all selected sectors into a single one. The 'M' variant will keep common linedefs, ------------------------------------------------------------------------ r169 | ajapted | 2012-11-14 19:04:33 +1100 (Wed, 14 Nov 2012) | 4 lines Sector mode: reworked handling of SPACE / INSERT key: 1. when a sector is highlighted, assume want to "correct" that sector 2. force insertion of a NEW sector via CTRL key ------------------------------------------------------------------------ r168 | ajapted | 2012-11-14 16:43:28 +1100 (Wed, 14 Nov 2012) | 2 lines CHANGELOG: mention the recent vertex-insertion changes. ------------------------------------------------------------------------ r167 | ajapted | 2012-11-14 16:38:50 +1100 (Wed, 14 Nov 2012) | 4 lines Vertex insertion: handle the case where a new vertex would split a line and the selected vertex is an endpoint of that line -- simply split the line (as if no vertex had been selected). ------------------------------------------------------------------------ r166 | ajapted | 2012-11-14 15:13:36 +1100 (Wed, 14 Nov 2012) | 3 lines Vertex insertion: improved overlap test, refuse the operation for the case of adding a line between old --> new vertex. ------------------------------------------------------------------------ r165 | ajapted | 2012-11-14 15:05:55 +1100 (Wed, 14 Nov 2012) | 3 lines Vertex insertion: prevent adding a new linedef if it would overlap an existing line. ------------------------------------------------------------------------ r164 | ajapted | 2012-11-14 14:57:12 +1100 (Wed, 14 Nov 2012) | 2 lines Basis: added LineDef::CalcLength() method. ------------------------------------------------------------------------ r163 | ajapted | 2012-11-14 14:37:34 +1100 (Wed, 14 Nov 2012) | 7 lines Vertex insertion: 1. if one vertex is selected and it is highlighted (or new position is snapped to same coord), then merely de-select it. 2. if two is selected (or one + highlight) and the linedef already exists, then merely select the second and deselect the first. ------------------------------------------------------------------------ r162 | ajapted | 2012-11-13 21:49:26 +1100 (Tue, 13 Nov 2012) | 4 lines When closing a simple vertex loop which is inside an existing sector, now create a sector on the inside of the loop (instead of creating a pillar). Eventually this will be a config option. ------------------------------------------------------------------------ r161 | ajapted | 2012-11-13 21:38:21 +1100 (Tue, 13 Nov 2012) | 2 lines Removed obsolete CopyObjects() code. ------------------------------------------------------------------------ r160 | ajapted | 2012-11-13 21:35:03 +1100 (Tue, 13 Nov 2012) | 2 lines Fully disabled some usage of 'SelPtr' which I missed before. ------------------------------------------------------------------------ r159 | ajapted | 2012-11-13 21:34:09 +1100 (Tue, 13 Nov 2012) | 2 lines Disabled 'c' and 'm' keys, they are about to be re-purposed... ------------------------------------------------------------------------ r158 | ajapted | 2012-11-13 21:32:18 +1100 (Tue, 13 Nov 2012) | 2 lines Removed obsolete DoInsertObject() code. ------------------------------------------------------------------------ r157 | ajapted | 2012-11-13 21:13:09 +1100 (Tue, 13 Nov 2012) | 2 lines TODO: hammered out new logic for Sector creation / correction / copying. ------------------------------------------------------------------------ r156 | ajapted | 2012-11-13 20:07:29 +1100 (Tue, 13 Nov 2012) | 2 lines TODO / WISHLIST update. ------------------------------------------------------------------------ r155 | ajapted | 2012-11-13 20:01:09 +1100 (Tue, 13 Nov 2012) | 2 lines Removed obsolete ymemory.cc/h code files. ------------------------------------------------------------------------ r154 | ajapted | 2012-11-13 19:59:06 +1100 (Tue, 13 Nov 2012) | 6 lines Config code: 1. define a string_list_t type using std::vector 2. rewrote OPT_STRING_LIST handling to use string_list_t 3. removed append_item_to_list() function 4. replaced a usage of GetMemory() with StringDup() ------------------------------------------------------------------------ r153 | ajapted | 2012-11-13 17:25:09 +1100 (Tue, 13 Nov 2012) | 3 lines Removed the 'SelPtr' type once and for all. Disabled various pieces of code which was using it (most of that was disabled already). ------------------------------------------------------------------------ r152 | ajapted | 2012-11-13 17:22:23 +1100 (Tue, 13 Nov 2012) | 2 lines Removed unused bv_vertices_of_sectors() code. ------------------------------------------------------------------------ r151 | ajapted | 2012-11-13 17:21:33 +1100 (Tue, 13 Nov 2012) | 2 lines Removed obsolete list_to_bitvec() and bitvec_to_list() functions. ------------------------------------------------------------------------ r150 | ajapted | 2012-11-13 17:16:34 +1100 (Tue, 13 Nov 2012) | 2 lines Removed unused linedefs_of_sectors() code. ------------------------------------------------------------------------ r149 | ajapted | 2012-11-13 17:14:13 +1100 (Tue, 13 Nov 2012) | 2 lines Removed unused unlink_sidedef() code. ------------------------------------------------------------------------ r148 | ajapted | 2012-11-13 17:06:16 +1100 (Tue, 13 Nov 2012) | 2 lines Removed obsolete MoveObjectsToCoord() code. ------------------------------------------------------------------------ r147 | ajapted | 2012-11-13 17:05:37 +1100 (Tue, 13 Nov 2012) | 3 lines Removed obsolete list_vertices_of_xxxs() functions. Removed obsolete bv_vertices_of_linedefs(SelPtr) function. ------------------------------------------------------------------------ r146 | ajapted | 2012-11-13 16:57:27 +1100 (Tue, 13 Nov 2012) | 3 lines Removed unused (and mostly broken) centre_of_xxxs functions. Only one left is centre_of_sector(), which is actually used and works. ------------------------------------------------------------------------ r145 | ajapted | 2012-11-13 16:51:55 +1100 (Tue, 13 Nov 2012) | 2 lines Removed old/unused/disabled MergeVertices() and AutoMergeVertices() code. ------------------------------------------------------------------------ r144 | ajapted | 2012-11-13 16:50:06 +1100 (Tue, 13 Nov 2012) | 2 lines Removed obsolete RotateAndScaleObjects() code. ------------------------------------------------------------------------ r143 | ajapted | 2012-11-13 16:09:46 +1100 (Tue, 13 Nov 2012) | 2 lines Removed a bunch of unused stuff from editobj.cc/h ------------------------------------------------------------------------ r142 | ajapted | 2012-11-12 22:32:18 +1100 (Mon, 12 Nov 2012) | 2 lines Fleshed out the INSTALL.txt document. ------------------------------------------------------------------------ r141 | ajapted | 2012-11-12 21:12:28 +1100 (Mon, 12 Nov 2012) | 3 lines CMD_BuildNodes: show an error message if edit_wad has ".new" extension (otherwise the delete + rename logic is going to fail). ------------------------------------------------------------------------ r140 | ajapted | 2012-11-12 21:10:03 +1100 (Mon, 12 Nov 2012) | 2 lines File utils: renamed CheckExtension() --> MatchExtension() ------------------------------------------------------------------------ r139 | ajapted | 2012-11-12 20:24:27 +1100 (Mon, 12 Nov 2012) | 3 lines CMD_BuildNodes: fixed bug where 'old_name' became invalid rubbish because the edit_wad object was deleted. ------------------------------------------------------------------------ r138 | ajapted | 2012-11-12 16:10:50 +1100 (Mon, 12 Nov 2012) | 5 lines CMD_BuildNodes: 1. use proper output name, replacing extension with ".new" 2. delete the ".new" file if the build was unsuccessful (cancel or error) 3. if successful, delete old file and rename new file to old filename ------------------------------------------------------------------------ r137 | ajapted | 2012-11-12 16:08:05 +1100 (Mon, 12 Nov 2012) | 1 line tweak ------------------------------------------------------------------------ r136 | ajapted | 2012-11-12 14:50:31 +1100 (Mon, 12 Nov 2012) | 3 lines CMD_BuildNodes: added proper (albeit simplistic) dialogs when the user tries to build nodes without any PWAD, or when there are unsaved changes. ------------------------------------------------------------------------ r135 | ajapted | 2012-11-12 14:41:23 +1100 (Mon, 12 Nov 2012) | 4 lines CMD_BuildNodes: properly split lines in UI_Nodes::Add() method. Also: added a blank line before each error message. ------------------------------------------------------------------------ r134 | ajapted | 2012-11-12 14:33:49 +1100 (Mon, 12 Nov 2012) | 2 lines CHANGELOG: added entry for the new node building feature. ------------------------------------------------------------------------ r133 | ajapted | 2012-11-12 14:27:34 +1100 (Mon, 12 Nov 2012) | 3 lines CMD_BuildNodes: handle the ESCAPE key better -- if not finished then cancel the build, otherwise close the window. ------------------------------------------------------------------------ r132 | ajapted | 2012-11-12 14:26:38 +1100 (Mon, 12 Nov 2012) | 1 line whitespacing ------------------------------------------------------------------------ r131 | ajapted | 2012-11-12 13:17:48 +1100 (Mon, 12 Nov 2012) | 6 lines CMD_BuildNodes: 1. support the CLOSE button and Cancel button in UI_Nodes 2. cancel the build when user wants to cancel (or close the window) 3. show final status (Success/Cancel/ERROR) in the progress bar 4. on success, use CMD_Quit to exit Eureka ------------------------------------------------------------------------ r130 | ajapted | 2012-11-12 11:32:55 +1100 (Mon, 12 Nov 2012) | 6 lines CMD_BuildNodes: 1. added and implemented the progress bar 2. added 'Cancel' button (not working yet) 3. move text browser to bottom for each Add() 4. tidy up of glbsp callbacks ------------------------------------------------------------------------ r129 | ajapted | 2012-11-11 22:37:48 +1100 (Sun, 11 Nov 2012) | 3 lines CMD_BuildNodes: use Fl::check() to ensure window gets shown before the node building begins. ------------------------------------------------------------------------ r128 | ajapted | 2012-11-11 22:28:37 +1100 (Sun, 11 Nov 2012) | 2 lines Version bump to 0.81 ------------------------------------------------------------------------ r127 | ajapted | 2012-11-11 22:27:04 +1100 (Sun, 11 Nov 2012) | 2 lines svn:ignore ------------------------------------------------------------------------ r126 | ajapted | 2012-11-11 22:14:56 +1100 (Sun, 11 Nov 2012) | 2 lines TODO tidy up. ------------------------------------------------------------------------ r125 | ajapted | 2012-11-11 21:50:49 +1100 (Sun, 11 Nov 2012) | 2 lines Makefile: added ui_nodes.o to the build. ------------------------------------------------------------------------ r124 | ajapted | 2012-11-11 21:50:23 +1100 (Sun, 11 Nov 2012) | 2 lines CMD_BuildNodes: bit more work on dialog window.... ------------------------------------------------------------------------ r123 | ajapted | 2012-11-11 21:24:40 +1100 (Sun, 11 Nov 2012) | 2 lines CMD_BuildNodes: handle the "(Hexen)" suffix when determining map name. ------------------------------------------------------------------------ r122 | ajapted | 2012-11-11 21:22:48 +1100 (Sun, 11 Nov 2012) | 4 lines Initial work on a UI_NodeDialog window, which will show the progress of building nodes and the output from the node builder, as well as have CANCEL and OK buttons. Very skeletal so far.... ------------------------------------------------------------------------ r121 | ajapted | 2012-11-11 20:56:55 +1100 (Sun, 11 Nov 2012) | 2 lines CMD_BuildNodes: extract map name from progress-bar text. ------------------------------------------------------------------------ r120 | ajapted | 2012-11-11 20:50:14 +1100 (Sun, 11 Nov 2012) | 3 lines CMD_BuildNodes: added interface code to glBSP and the function which does all the heavy lifting (DM_BuildNodes). Mainly copy'n'paste from OBLIGE. ------------------------------------------------------------------------ r119 | ajapted | 2012-11-11 20:26:20 +1100 (Sun, 11 Nov 2012) | 4 lines Makefile: logic for building and linking the glBSP code. Also added conditional lines for FLTK in a non-standard place. ------------------------------------------------------------------------ r118 | ajapted | 2012-11-11 20:21:46 +1100 (Sun, 11 Nov 2012) | 2 lines Deleted Makefile.opt -- added the extra bits into 'Makefile' (in a conditional section). ------------------------------------------------------------------------ r117 | ajapted | 2012-11-11 19:15:58 +1100 (Sun, 11 Nov 2012) | 4 lines glbsp code: encapsulated all code into a 'glbsp' namespace. Also removed the 'Glbsp' prefix from a few API functions. ------------------------------------------------------------------------ r116 | ajapted | 2012-11-11 19:00:47 +1100 (Sun, 11 Nov 2012) | 2 lines Checked in a copy of glBSP 2.27 source code. ------------------------------------------------------------------------ r115 | ajapted | 2012-11-11 18:25:04 +1100 (Sun, 11 Nov 2012) | 2 lines CMD_BuildNodes: make sure we have a PWAD. ------------------------------------------------------------------------ r114 | ajapted | 2012-11-11 16:53:06 +1100 (Sun, 11 Nov 2012) | 4 lines Preliminary work on "Build Nodes" command (in File menu, CTRL-B key). This will invoke an external nodes builder (glbsp for now), show the output, then quit. ------------------------------------------------------------------------ r113 | ajapted | 2012-11-10 23:10:38 +1100 (Sat, 10 Nov 2012) | 3 lines 1. Keyboard shortcuts T/F/O/S/L open browser at specific kind 2. Made MIN_BROWSER_W a bit narrower (280 --> 260) ------------------------------------------------------------------------ r112 | ajapted | 2012-11-10 23:08:54 +1100 (Sat, 10 Nov 2012) | 2 lines Browser: tweaked position of 'Pics' button. ------------------------------------------------------------------------ r111 | ajapted | 2012-11-10 22:35:25 +1100 (Sat, 10 Nov 2012) | 2 lines Added 'INSTALL.txt' document (mostly empty). ------------------------------------------------------------------------ r110 | ajapted | 2012-11-10 22:16:58 +1100 (Sat, 10 Nov 2012) | 2 lines Tweaked calculations in zoom_fit(). ------------------------------------------------------------------------ r109 | ajapted | 2012-11-10 22:16:17 +1100 (Sat, 10 Nov 2012) | 2 lines Fixed initial zoom (it was computed while browser was still present). ------------------------------------------------------------------------ r108 | ajapted | 2012-11-10 21:57:45 +1100 (Sat, 10 Nov 2012) | 3 lines Makefiles: updated 'install' target with commands to install the desktop and icon files, using the XDG tools (in the xdg-utils package). ------------------------------------------------------------------------ r107 | ajapted | 2012-11-10 21:11:24 +1100 (Sat, 10 Nov 2012) | 3 lines DESKTOP file: Removed 'Application' from Categories, as the desktop-file-validate program warned it was deprecated. ------------------------------------------------------------------------ r106 | ajapted | 2012-11-10 19:47:55 +1100 (Sat, 10 Nov 2012) | 2 lines Desktop file: added StartupNotify=false ------------------------------------------------------------------------ r105 | ajapted | 2012-11-10 19:07:08 +1100 (Sat, 10 Nov 2012) | 2 lines TODO and CHANGELOG update. ------------------------------------------------------------------------ r104 | ajapted | 2012-11-10 18:45:49 +1100 (Sat, 10 Nov 2012) | 4 lines In game defs, allow texture and flat group to be uppercase, and match these against the 'X' category. This is a very simple way to allow textures and flats to belong (or not) to one additional group. ------------------------------------------------------------------------ r103 | ajapted | 2012-11-10 18:41:05 +1100 (Sat, 10 Nov 2012) | 2 lines Browser: made initial width a bit wider (show 4 flats instead of 3). ------------------------------------------------------------------------ r102 | ajapted | 2012-11-10 17:15:25 +1100 (Sat, 10 Nov 2012) | 2 lines DOOM game def: assigned SKY1/2/3 and F_SKY1 into 'Natural' category. ------------------------------------------------------------------------ r101 | ajapted | 2012-11-10 16:42:14 +1100 (Sat, 10 Nov 2012) | 2 lines PLUTONIA game defs: assigned categories for all the new textures. ------------------------------------------------------------------------ r100 | ajapted | 2012-11-10 16:24:53 +1100 (Sat, 10 Nov 2012) | 3 lines TNT game def: placed all the new TNT textures into categories, including two new categories "Crates" and "Egypt". ------------------------------------------------------------------------ r99 | ajapted | 2012-11-10 15:37:20 +1100 (Sat, 10 Nov 2012) | 3 lines DOOM defs: fixed the 'SW2XXX' textures which were lacking a category line for them -- should be same as their 'SW1' counterparts. ------------------------------------------------------------------------ r98 | ajapted | 2012-11-10 15:32:18 +1100 (Sat, 10 Nov 2012) | 2 lines CHANGELOG: tweaked layout (use two spaces) ------------------------------------------------------------------------ r97 | ajapted | 2012-11-10 15:21:22 +1100 (Sat, 10 Nov 2012) | 2 lines Update for TODO.txt and CHANGES.txt ------------------------------------------------------------------------ r96 | ajapted | 2012-11-10 15:18:45 +1100 (Sat, 10 Nov 2012) | 4 lines Render: strafe left/right when the ALT (or META) key is pressed (in addition to the RMB). It is not ideal, since window manager will typically steal the ALT + RMB combination for themselves. ------------------------------------------------------------------------ r95 | ajapted | 2012-11-10 15:00:50 +1100 (Sat, 10 Nov 2012) | 3 lines When searching for IWADs, check for uppercase'd name (like "DOOM.WAD"). This also required lowercasing it when determining the Game name. ------------------------------------------------------------------------ r94 | ajapted | 2012-11-10 14:56:50 +1100 (Sat, 10 Nov 2012) | 2 lines Utils: added y_strlowr() and rewrote y_strupr(). ------------------------------------------------------------------------ r93 | ajapted | 2012-11-10 14:34:50 +1100 (Sat, 10 Nov 2012) | 6 lines Improved IWAD finding logic: 1. if the -iwad parameter has no extension, add ".wad" 2. if the -iwad parameter is a bare name, look in iwad search path 3. added ~/.eureka/iwads directory to search path 4. when searching, look for other iwad names (e.g. "doom.wad" and "tnt.wad") ------------------------------------------------------------------------ r92 | ajapted | 2012-11-10 13:54:12 +1100 (Sat, 10 Nov 2012) | 3 lines 1. Require a valid home_dir 2. Create extra subdirs in the home dir ("iwads/", "games/" etc) ------------------------------------------------------------------------ r91 | ajapted | 2012-11-10 13:26:44 +1100 (Sat, 10 Nov 2012) | 3 lines Refactored code into DetermineLevel() for finding what level to use, and added support for plain numbers (e.g. -warp 15). ------------------------------------------------------------------------ r90 | ajapted | 2012-11-10 13:23:20 +1100 (Sat, 10 Nov 2012) | 3 lines WAD code: implemented FindLevelByNumber() method for Wad_file, which will look for a match against "MAP##" or "E#M#" level names. ------------------------------------------------------------------------ r89 | ajapted | 2012-11-10 12:57:00 +1100 (Sat, 10 Nov 2012) | 2 lines When level name is not specified, find the first one in the PWAD or IWAD. ------------------------------------------------------------------------ r88 | ajapted | 2012-11-10 12:12:27 +1100 (Sat, 10 Nov 2012) | 2 lines WAD code: added API for reading level list. ------------------------------------------------------------------------ r87 | ajapted | 2012-11-10 12:07:55 +1100 (Sat, 10 Nov 2012) | 2 lines WAD code: added 'FindFirstLevel' method to Wad_file class. ------------------------------------------------------------------------ r86 | ajapted | 2012-11-10 11:57:50 +1100 (Sat, 10 Nov 2012) | 3 lines 1. renamed Editor_Loop --> Main_Loop, moved into main.cc 2. start with browser disabled (turn off after creating main_win) ------------------------------------------------------------------------ r85 | ajapted | 2012-11-09 23:08:49 +1100 (Fri, 09 Nov 2012) | 3 lines UI_Scroll: use clip_children(1) to prevent contents from drawing over other parts of the GUI. ------------------------------------------------------------------------ r84 | ajapted | 2012-11-09 22:54:44 +1100 (Fri, 09 Nov 2012) | 2 lines Browser: tweaked layout of images ------------------------------------------------------------------------ r83 | ajapted | 2012-11-09 22:41:21 +1100 (Fri, 09 Nov 2012) | 2 lines UI_Scroll: added ability to horizontally resize child widgets. ------------------------------------------------------------------------ r82 | ajapted | 2012-11-09 22:21:17 +1100 (Fri, 09 Nov 2012) | 2 lines UI_Scroll: make sure scrollbar gets vertically resized. ------------------------------------------------------------------------ r81 | ajapted | 2012-11-09 22:18:41 +1100 (Fri, 09 Nov 2012) | 2 lines UI_Scroll: fixed Remove_first() which erroneously removed the scrollbar. ------------------------------------------------------------------------ r80 | ajapted | 2012-11-09 21:42:46 +1100 (Fri, 09 Nov 2012) | 4 lines UI_Scroll: made it a subclass of Fl_Group (it is not really possible with FLTK to make container widgets any other way). Renamed the group like methods to use an uppercase letter (Add, Remove, Init_Sizes, etc). ------------------------------------------------------------------------ r79 | ajapted | 2012-11-08 21:52:31 +1100 (Thu, 08 Nov 2012) | 2 lines UI_Scroll: more work on scrolling -- it is working pretty well now. ------------------------------------------------------------------------ r78 | ajapted | 2012-11-08 19:29:29 +1100 (Thu, 08 Nov 2012) | 2 lines UI_Scroll: got ability to scroll working, via new reposition_all() method. ------------------------------------------------------------------------ r77 | ajapted | 2012-11-08 19:20:12 +1100 (Thu, 08 Nov 2012) | 4 lines UI_Scroll: the init_sizes() method now calculates the bottom of all child widgets. Added a callback for the scrollbar (all it does currently is redraw). ------------------------------------------------------------------------ r76 | ajapted | 2012-11-08 15:57:56 +1100 (Thu, 08 Nov 2012) | 2 lines Browser: added an undrawn resize box to control resizing. ------------------------------------------------------------------------ r75 | ajapted | 2012-11-07 20:38:29 +1100 (Wed, 07 Nov 2012) | 2 lines UI_Scroll: draw the box. ------------------------------------------------------------------------ r74 | ajapted | 2012-11-07 20:00:02 +1100 (Wed, 07 Nov 2012) | 4 lines Browser: partial work to transition to new UI_Scroll widget, renamed the 'pack' field --> 'scroll', removed the resize_buttons() and fix_scrollbar_order() hacks, and disabled a few things. ------------------------------------------------------------------------ r73 | ajapted | 2012-11-07 19:57:38 +1100 (Wed, 07 Nov 2012) | 3 lines UI_Scroll widget: fleshed out some methods, and added a few delegates e.g. children() which merely passes through to pack->children(). ------------------------------------------------------------------------ r72 | ajapted | 2012-11-07 19:37:48 +1100 (Wed, 07 Nov 2012) | 5 lines Browser: update the image list when resized (reposition them). This commit includes an attempt to get text buttons horizontally resized, but it doesn't work since Fl_Scroll is an utter piece of crap. ------------------------------------------------------------------------ r71 | ajapted | 2012-11-07 19:12:17 +1100 (Wed, 07 Nov 2012) | 2 lines Began work on a decent scroll widget (Fl_Scroll is fucked). ------------------------------------------------------------------------ r70 | ajapted | 2012-11-07 15:35:01 +1100 (Wed, 07 Nov 2012) | 3 lines Browser: tweak to size and layout, e.g. moved 'X' button to left side and added invisible resize box to the right. ------------------------------------------------------------------------ r69 | ajapted | 2012-11-07 14:50:30 +1100 (Wed, 07 Nov 2012) | 3 lines Fixed UI_Tile event propagation, the FL_NO_BOX 'limiter' was stealing events from the canvas widget. ------------------------------------------------------------------------ r68 | ajapted | 2012-11-07 14:03:40 +1100 (Wed, 07 Nov 2012) | 2 lines CHANGELOG: added browser resize feature. ------------------------------------------------------------------------ r67 | ajapted | 2012-11-07 14:03:23 +1100 (Wed, 07 Nov 2012) | 2 lines TODO update. ------------------------------------------------------------------------ r66 | ajapted | 2012-11-07 14:00:09 +1100 (Wed, 07 Nov 2012) | 4 lines Implemented the resize behavior of UI_Tile, which tries to maintain the width of the right widget (the browser), and remembers that width when it is hidden so it can be restored. ------------------------------------------------------------------------ r65 | ajapted | 2012-11-07 13:36:41 +1100 (Wed, 07 Nov 2012) | 3 lines Implemented new method to show/hide the browser (methods of UI_Tile). Did a bit of work on resize() behavior and handling the limiter box. ------------------------------------------------------------------------ r64 | ajapted | 2012-11-07 13:15:51 +1100 (Wed, 07 Nov 2012) | 2 lines Use the new UI_Tile widget (constructing the main window). ------------------------------------------------------------------------ r63 | ajapted | 2012-11-07 13:08:37 +1100 (Wed, 07 Nov 2012) | 3 lines Began work on UI_Tile widget, a variant on Fl_Tile which will provide better resize behavior and handle the ability to show/hide the browser. ------------------------------------------------------------------------ r62 | ajapted | 2012-11-07 11:10:45 +1100 (Wed, 07 Nov 2012) | 2 lines Added a basic logo image. ------------------------------------------------------------------------ r61 | ajapted | 2012-11-07 11:09:50 +1100 (Wed, 07 Nov 2012) | 2 lines Added a basic icon: eureka.xpm ------------------------------------------------------------------------ r60 | ajapted | 2012-11-01 18:46:49 +1100 (Thu, 01 Nov 2012) | 2 lines Created a basic .desktop file. ------------------------------------------------------------------------ r59 | ajapted | 2012-11-01 18:41:01 +1100 (Thu, 01 Nov 2012) | 2 lines Added top-level 'misc' folder. ------------------------------------------------------------------------ r58 | ajapted | 2012-11-01 12:45:39 +1100 (Thu, 01 Nov 2012) | 2 lines Ignore blank/comment lines in persistent data files. ------------------------------------------------------------------------ r57 | ajapted | 2012-11-01 12:43:41 +1100 (Thu, 01 Nov 2012) | 2 lines Create the cache folder (in home_dir). ------------------------------------------------------------------------ r56 | ajapted | 2012-11-01 12:42:39 +1100 (Thu, 01 Nov 2012) | 2 lines Use proper path for cache data (i.e. home_dir). ------------------------------------------------------------------------ r55 | ajapted | 2012-10-25 15:04:11 +1100 (Thu, 25 Oct 2012) | 2 lines TODO update / tidy up. ------------------------------------------------------------------------ r54 | ajapted | 2012-10-25 15:03:21 +1100 (Thu, 25 Oct 2012) | 4 lines Config: improved output of dump_command_line_options(), use new 'arg_desc' field of option structure to provide a short description of the argument which the option takes. Reordered the list, and removed 'is_file' thang. ------------------------------------------------------------------------ r53 | ajapted | 2012-10-25 12:11:49 +1100 (Thu, 25 Oct 2012) | 4 lines Game defs: look in the "common" folder when an UGH file is not found in the specified folder (like "games"). This is mainly for include directives, and needed for the recent move of shared files to the common folder. ------------------------------------------------------------------------ r52 | ajapted | 2012-10-25 10:47:57 +1100 (Thu, 25 Oct 2012) | 2 lines Makefiles: install the new 'common' folder. ------------------------------------------------------------------------ r51 | ajapted | 2012-10-25 10:47:22 +1100 (Thu, 25 Oct 2012) | 2 lines Moved 'doom_specials.ugh' and 'doom_common.ugh' --> common/ folder. ------------------------------------------------------------------------ r50 | ajapted | 2012-10-25 10:44:04 +1100 (Thu, 25 Oct 2012) | 2 lines Added 'common' folder -- for definitions shared between game defs. ------------------------------------------------------------------------ r49 | ajapted | 2012-10-24 23:37:44 +1100 (Wed, 24 Oct 2012) | 2 lines TODO update. ------------------------------------------------------------------------ r48 | ajapted | 2012-10-24 20:08:49 +1100 (Wed, 24 Oct 2012) | 3 lines Improved dump_command_line_options(), entries need 'h' flag to be displayed, and the '<' flag prints a line break. ------------------------------------------------------------------------ r47 | ajapted | 2012-10-24 19:46:43 +1100 (Wed, 24 Oct 2012) | 2 lines Implemented the --help and --version options. ------------------------------------------------------------------------ r46 | ajapted | 2012-10-24 18:08:40 +1100 (Wed, 24 Oct 2012) | 2 lines tweak to error dialog. ------------------------------------------------------------------------ r45 | ajapted | 2012-10-24 18:06:28 +1100 (Wed, 24 Oct 2012) | 2 lines Config: better handling of lines with extraneous arguments. ------------------------------------------------------------------------ r44 | ajapted | 2012-10-24 17:22:27 +1100 (Wed, 24 Oct 2012) | 6 lines Config handling: 1. simplified OPT_BOOLEAN handling in config files 2. added "WARNING" prefix to some log messages 3. replaced '\0' with 0 4. renamed OPT_STRINGPTRLIST --> OPT_STRING_LIST (etc). ------------------------------------------------------------------------ r43 | ajapted | 2012-10-24 17:05:37 +1100 (Wed, 24 Oct 2012) | 4 lines Config handling: 1. use FatalError() instead of LogPrintf() for some stuff 2. removed OPT_STRINGPTRACC and OPT_UNSIGNED -- simplify the code. ------------------------------------------------------------------------ r42 | ajapted | 2012-10-24 16:42:03 +1100 (Wed, 24 Oct 2012) | 2 lines Error handling polishing. ------------------------------------------------------------------------ r41 | ajapted | 2012-10-24 15:03:14 +1100 (Wed, 24 Oct 2012) | 3 lines Added code files 'ui_dialog' which implements DLG_ShowError(). Source was OBLIGE code. ------------------------------------------------------------------------ r40 | ajapted | 2012-10-24 14:56:22 +1100 (Wed, 24 Oct 2012) | 2 lines FatalError: print message to log file and call DLG_ShowError(). ------------------------------------------------------------------------ r39 | ajapted | 2012-10-24 14:49:11 +1100 (Wed, 24 Oct 2012) | 2 lines Wad: imlemented MasterDir_CloseAll() function. ------------------------------------------------------------------------ r38 | ajapted | 2012-10-23 22:09:18 +1100 (Tue, 23 Oct 2012) | 2 lines Worked on improving the FatalError() logic.... ------------------------------------------------------------------------ r37 | ajapted | 2012-10-23 21:33:42 +1100 (Tue, 23 Oct 2012) | 2 lines Added 'CHANGES.txt' document -- keep track of recent changes. ------------------------------------------------------------------------ r36 | ajapted | 2012-10-23 20:50:09 +1100 (Tue, 23 Oct 2012) | 2 lines Removed last vestiges of err() function. ------------------------------------------------------------------------ r35 | ajapted | 2012-10-23 19:31:30 +1100 (Tue, 23 Oct 2012) | 5 lines Config: 1. replace err() with LogPrintf() 2. show strerror(errno) in some messages 3. fixed warnings about && inside || ------------------------------------------------------------------------ r34 | ajapted | 2012-10-22 22:31:16 +1100 (Mon, 22 Oct 2012) | 2 lines Made 'BugError' just be an alias for FatalError(). ------------------------------------------------------------------------ r33 | ajapted | 2012-10-22 22:24:52 +1100 (Mon, 22 Oct 2012) | 2 lines Replaced 'warn' function with LogPrintf. ------------------------------------------------------------------------ r32 | ajapted | 2012-10-22 22:11:12 +1100 (Mon, 22 Oct 2012) | 3 lines Config: fixed crashing bug with handling loose files (argv and argc were not iterated properly). The same bug also exists in Yadex 1.7.0. ------------------------------------------------------------------------ r31 | ajapted | 2012-10-22 20:47:18 +1100 (Mon, 22 Oct 2012) | 2 lines Config: tweaked handling of loose files, and code reformatting. ------------------------------------------------------------------------ r30 | ajapted | 2012-10-22 20:44:08 +1100 (Mon, 22 Oct 2012) | 3 lines Config: removed hack of first entry in options[] being used for loose filenames. Instead handle them explicitly. ------------------------------------------------------------------------ r29 | ajapted | 2012-10-22 20:26:52 +1100 (Mon, 22 Oct 2012) | 2 lines Makefiles: prevent an install error (since there are currently no mods). ------------------------------------------------------------------------ r28 | ajapted | 2012-10-22 20:25:40 +1100 (Mon, 22 Oct 2012) | 3 lines About box: tweaked Yadex reference -- I don't want to give the impression that Eureka is a continuation of Yadex or is compatible with Yadex. ------------------------------------------------------------------------ r27 | ajapted | 2012-10-22 19:46:27 +1100 (Mon, 22 Oct 2012) | 3 lines Docs: added History_1.txt and History_2.txt -- contains the commit history from the EDGE repository and AwwPorts repository (respectively). ------------------------------------------------------------------------ r26 | ajapted | 2012-10-22 17:19:19 +1100 (Mon, 22 Oct 2012) | 2 lines Makefiles: install the 'mods' folder too (like 'games' and 'ports'). ------------------------------------------------------------------------ r25 | ajapted | 2012-10-22 17:15:34 +1100 (Mon, 22 Oct 2012) | 2 lines Use DebugPrintf() in most places instead of fprintf(stderr). ------------------------------------------------------------------------ r24 | ajapted | 2012-10-22 17:04:23 +1100 (Mon, 22 Oct 2012) | 2 lines Config: fixed --log option (had wrong type, BOOLEAN). ------------------------------------------------------------------------ r23 | ajapted | 2012-10-22 15:47:00 +1100 (Mon, 22 Oct 2012) | 3 lines Version bumped to 0.80, in honor of creating a real sourceforge project and installation of the pmwiki web-site (etc). ------------------------------------------------------------------------ r22 | ajapted | 2012-10-22 15:44:45 +1100 (Mon, 22 Oct 2012) | 3 lines Log file: when output is the terminal, don't print the '=== START OF LOGS ===' message and similar end message. ------------------------------------------------------------------------ r21 | ajapted | 2012-10-22 15:39:15 +1100 (Mon, 22 Oct 2012) | 3 lines Config files: re-implemented the parse_config_file_user() and parse_config_file_default() functions. ------------------------------------------------------------------------ r20 | ajapted | 2012-10-22 15:22:57 +1100 (Mon, 22 Oct 2012) | 2 lines tweakage and movage. ------------------------------------------------------------------------ r19 | ajapted | 2012-10-22 14:22:15 +1100 (Mon, 22 Oct 2012) | 8 lines Rework of log file handling: 1. the --log option specifies a log file, use stdout as fallback 2. the --quiet option suppresses the stdout fallback 3. be sure to LogClose() in error handlers 4. added --debug option to enable debug messages 5. debug messages either go to log file (if used), else stderr 6. added 'init_progress' global var ------------------------------------------------------------------------ r18 | ajapted | 2012-10-22 13:28:25 +1100 (Mon, 22 Oct 2012) | 2 lines Options: better handling of --version (same way as --help). ------------------------------------------------------------------------ r17 | ajapted | 2012-10-22 13:21:45 +1100 (Mon, 22 Oct 2012) | 2 lines Removed unused 'Quieter' option / var. ------------------------------------------------------------------------ r16 | ajapted | 2012-10-21 22:35:58 +1100 (Sun, 21 Oct 2012) | 8 lines Option parsing: 1. revert previous commit, the 'long_name' can now be used with either single or double dashes (e.g. --iwad or just -iwad). I remembered that the options were meant to mimic what DOOM.EXE accepts. 2. handle --version a bit better 3. provide short options for common options: -f (-file), -w (-warp), etc.. 4. reordered entries in options[] table, more common ones near the top. ------------------------------------------------------------------------ r15 | ajapted | 2012-10-21 22:14:51 +1100 (Sun, 21 Oct 2012) | 3 lines Option parsing: require short options be a single letter, and long options begin with double dashes, e.g. --iwad. ------------------------------------------------------------------------ r14 | ajapted | 2012-10-21 21:58:22 +1100 (Sun, 21 Oct 2012) | 4 lines 1. Determine home_dir/install_dir BEFORE parsing config files or normal options 2. Support --home and --install options (override the automatic logic) 3. Renamed --config_file to just --config ------------------------------------------------------------------------ r13 | ajapted | 2012-10-21 21:21:47 +1100 (Sun, 21 Oct 2012) | 4 lines Look for ".ugh" definition files in two places: (1) home_dir and (2) install_dir. (In that order too). This is part of the transition to using proper unixy file location conventions. ------------------------------------------------------------------------ r12 | ajapted | 2012-10-21 21:16:40 +1100 (Sun, 21 Oct 2012) | 2 lines Added 'mods' folder (empty). ------------------------------------------------------------------------ r11 | ajapted | 2012-10-20 22:26:52 +1100 (Sat, 20 Oct 2012) | 2 lines Show the home_dir and install_dir (on stderr), and reformatted that code. ------------------------------------------------------------------------ r10 | ajapted | 2012-10-20 22:17:41 +1100 (Sat, 20 Oct 2012) | 3 lines Added new code files 'lib_file.*' -- contain various file utilities. Source was OBLIGE code, reformatted and tweaked. ------------------------------------------------------------------------ r9 | ajapted | 2012-10-20 22:07:20 +1100 (Sat, 20 Oct 2012) | 3 lines Added the following string utilities (from OBLIGE code) : StringNew(), StringDup(), StringPrintf(), StringFree(). ------------------------------------------------------------------------ r8 | ajapted | 2012-10-20 22:00:56 +1100 (Sat, 20 Oct 2012) | 2 lines Renamed code files: yutil.* --> lib_util.* ------------------------------------------------------------------------ r7 | ajapted | 2012-10-20 21:48:47 +1100 (Sat, 20 Oct 2012) | 3 lines Added 'home_dir' and 'install_dir' global vars, and code to determine what their values should be. ------------------------------------------------------------------------ r6 | ajapted | 2012-10-20 18:50:12 +1100 (Sat, 20 Oct 2012) | 2 lines Makefile: removed FLTK_PREFIX stuff. ------------------------------------------------------------------------ r5 | ajapted | 2012-10-20 17:46:15 +1100 (Sat, 20 Oct 2012) | 2 lines Disabled reading the eureka.cfg file (that mechanism is under review). ------------------------------------------------------------------------ r4 | ajapted | 2012-10-20 17:12:29 +1100 (Sat, 20 Oct 2012) | 2 lines Created 'Makefile.opt' for FLTK installed the /opt folder. ------------------------------------------------------------------------ r3 | ajapted | 2012-10-20 15:40:19 +1100 (Sat, 20 Oct 2012) | 2 lines Initial check-in of existing Eureka code (from the AwwPorts repository). ------------------------------------------------------------------------ r2 | ajapted | 2012-10-20 15:36:36 +1100 (Sat, 20 Oct 2012) | 2 lines Test check-in: README.txt ------------------------------------------------------------------------ r1 | allura | 2012-10-18 22:39:16 +1100 (Thu, 18 Oct 2012) | 1 line Initial commit. ==================================================== DEVELOPMENT IN AWWPORTS REPOSITORY ==================================================== ------------------------------------------------------------------------ r3135 | ajapted | 2012-10-17 Makefile.unix: implemented 'install' and 'uninstall' targets. ------------------------------------------------------------------------ r3134 | ajapted | 2012-10-17 TODO update. ------------------------------------------------------------------------ r3133 | ajapted | 2012-10-17 Eureka: created a Makefile.unix -- will be used to build and install a normal unixy binary. Main difference so far is that it links against a system-wide version of FLTK. ------------------------------------------------------------------------ r3132 | ajapted | 2012-10-16 Eureka: handle a pwad filename given without -file. For example: ./eureka foo.wad ------------------------------------------------------------------------ r3131 | ajapted | 2012-10-16 tweak ------------------------------------------------------------------------ r2744 | ajapted | 2012-07-16 Eureka: TODO item. ------------------------------------------------------------------------ r1468 | ajapted | 2012-05-15 try to unfuck this BZR repository..... ------------------------------------------------------------------------ r1467 | ajapted | 2012-05-15 Eureka / EDGE: various fixes and improvement to new linetypes. ------------------------------------------------------------------------ r1466 | ajapted | 2012-05-15 Eureka / EDGE: fixed remaining linetypes, e.g. rts scripting, sliding doors, aligners, etc.. ------------------------------------------------------------------------ r1465 | ajapted | 2012-05-15 Eureka / EDGE: worked on linetypes, e.g. new keyed doors, hub exits, etc.. ------------------------------------------------------------------------ r1462 | ajapted | 2012-05-14 Eureka / EDGE: added all the sector types. ------------------------------------------------------------------------ r1461 | ajapted | 2012-05-14 Eureka / EDGE: added remaining missing things: dog, glows, stealth monsters. ------------------------------------------------------------------------ r1460 | ajapted | 2012-05-14 Eureka / EDGE: fixed category for slopes, and added some missing things (Jetpack, green keys, new armors). ------------------------------------------------------------------------ r1459 | ajapted | 2012-05-14 Eureka / Odamex: added Blue/Red player starts and Static_Init things (333 to 335). ------------------------------------------------------------------------ r1458 | ajapted | 2012-05-14 Eureka: more work to ODAMEX definitions (sector types, etc etc...) ------------------------------------------------------------------------ r1457 | ajapted | 2012-05-14 Eureka: added slope linetypes to EDGE definition. ------------------------------------------------------------------------ r1456 | ajapted | 2012-05-14 Eureka: partial work on ODAMEX support : ports/odamex.ugh ------------------------------------------------------------------------ r1455 | ajapted | 2012-05-14 Eureka: added bare-bone game definitions for Absolution (Doom64 TC), Blasphemer and HacX. ------------------------------------------------------------------------ r1453 | ajapted | 2012-04-24 Eureka / DOOM defs: fixed linetypes 33 and 34 (red and yellow locked doors) which had swapped descriptions. ------------------------------------------------------------------------ r1452 | ajapted | 2012-04-18 Eureka: fixed W_FindPatchLump() fallback method to try _any_ lump with the matching name (instead of just sprites). This fixes the missing textures with the Doom64 TC. ------------------------------------------------------------------------ r1451 | ajapted | 2012-04-18 Eureka: added a LoadTexture_SinglePatch() function to texture loading code which turned out not to be necessary -- but kept for possible future use. ------------------------------------------------------------------------ r1450 | ajapted | 2012-03-23 Eureka / DOOM: somehow the 'Computer map' pickup disappeared from the definition files -- added it back in. ------------------------------------------------------------------------ r1425 | ajapted | 2012-02-17 Eureka: moved 0.74 changelog --> docs/ directory. ------------------------------------------------------------------------ r1424 | ajapted | 2012-02-17 makefile tweak. ------------------------------------------------------------------------ r1423 | ajapted | 2012-02-17 Eureka: Changelog tweakage. ------------------------------------------------------------------------ r1422 | ajapted | 2012-02-17 Eureka: add revision numbers to changelogs. ------------------------------------------------------------------------ r1421 | ajapted | 2012-02-17 Eureka: CHANGELOG update. ------------------------------------------------------------------------ r1420 | ajapted | 2012-02-17 Eureka: improved the ABOUT box. ------------------------------------------------------------------------ r1419 | ajapted | 2012-02-17 tweakage. ------------------------------------------------------------------------ r1418 | ajapted | 2012-02-17 Eureka: experimented with an 'alternate_look' setting. ------------------------------------------------------------------------ r1417 | ajapted | 2012-02-17 Eureka: tweaked widget positions on the Info bar. ------------------------------------------------------------------------ r1416 | ajapted | 2012-02-17 Eureka: TODO update. ------------------------------------------------------------------------ r1415 | ajapted | 2012-02-17 Eureka: TODO update. ------------------------------------------------------------------------ r1414 | ajapted | 2012-02-17 Eureka: persistence tweak. ------------------------------------------------------------------------ r1413 | ajapted | 2012-02-17 Eureka: persist the rendering On/Off state. ------------------------------------------------------------------------ r1412 | ajapted | 2012-02-17 Eureka: improved layout of sidedefs in LineDef panel (they were a bit cramped). ------------------------------------------------------------------------ r1411 | ajapted | 2012-02-17 Eureka: fixed LineDef panel not updating after "ADD"/"DEL" buttons. ------------------------------------------------------------------------ r1410 | ajapted | 2012-02-17 Eureka: CHANGELOG update (sidedef "ADD" and "DEL" buttons). ------------------------------------------------------------------------ r1409 | ajapted | 2012-02-17 Eureka: e_cutpaste::UnlinkSideFromLine() --> x_loop::LD_RemoveSideDef(). The sidedef "DEL" button uses this to handle sidedef deletion better. ------------------------------------------------------------------------ r1408 | ajapted | 2012-02-17 Eureka: improved "ADD" sidedef button, try GetOppositeSector() to get the new sector for the sidedef, and if that fails then use NumSec - 1. ------------------------------------------------------------------------ r1407 | ajapted | 2012-02-17 Eureka: changelog (etc) update. ------------------------------------------------------------------------ r1406 | ajapted | 2012-02-17 Eureka: implemented the -port option. ------------------------------------------------------------------------ r1405 | ajapted | 2012-02-17 Eureka: version bump to 0.74 ------------------------------------------------------------------------ r1404 | ajapted | 2012-02-17 Eureka: TODO update. ------------------------------------------------------------------------ r1403 | ajapted | 2012-02-17 Eureka: basic implementation of "ADD" button for sidedefs. ------------------------------------------------------------------------ r1402 | ajapted | 2012-02-17 Eureka: implemented the "DEL" button for sidedefs. ------------------------------------------------------------------------ r1401 | ajapted | 2012-02-16 Eureka: in LINEDEF panel, added "ADD" and "DEL" buttons to sidedefs (with only one visible at a time). Currently they do nothing. ------------------------------------------------------------------------ r1400 | ajapted | 2012-02-16 Eureka / Browser: parsing code for persistence (cat, search, etc). ------------------------------------------------------------------------ r1399 | ajapted | 2012-02-16 Eureka: persist which Browser panel is open (if any). ------------------------------------------------------------------------ r1398 | ajapted | 2012-02-16 tweak. ------------------------------------------------------------------------ r1397 | ajapted | 2012-02-16 Eureka: docco update (sector insertion improvements). ------------------------------------------------------------------------ r1396 | ajapted | 2012-02-16 Eureka: improved SECTOR insertion : (a) copy properties from a selected sector, or if none then a neighbor sector. (b) if CTRL is pressed, then the new area BECOMES the same sector as the one selected. ------------------------------------------------------------------------ r1395 | ajapted | 2012-02-16 minor comment. ------------------------------------------------------------------------ r1394 | ajapted | 2012-02-16 Eureka: fixed UI_Pic handling of a certain flat (CEIL4_1 IIRC) which was showing bright cyan in parts that were black (palette color #247). ------------------------------------------------------------------------ r1393 | ajapted | 2012-02-16 docco update. ------------------------------------------------------------------------ r1392 | ajapted | 2012-02-16 Eureka: big rework on CloseLoop_Complex() to fix some failure cases, especially when extending an island within a sector. Also fixed a failure case in CloseLoop_Simple() when surrounding an existing shape WHILE new shape is inside a sector -- we need to assign a sector to both loops for that. ------------------------------------------------------------------------ r1391 | ajapted | 2012-02-15 Eureka: fixed bug where closing a line-loop around an existing shape did not apply the new sector to the outside of that shape. ------------------------------------------------------------------------ r1390 | ajapted | 2012-02-15 Eureka: code tidying, and removed 'e' pointer from UI_Canvas class. ------------------------------------------------------------------------ r1389 | ajapted | 2012-02-15 Eureka / TODO: update. ------------------------------------------------------------------------ r1388 | ajapted | 2012-02-15 Eureka / CHANGELOG: update. ------------------------------------------------------------------------ r1387 | ajapted | 2012-02-15 Eureka: tweakage (e.g. persistent messages). ------------------------------------------------------------------------ r1386 | ajapted | 2012-02-15 Eureka / DOOM config: rearranged linegroups. ------------------------------------------------------------------------ r1385 | ajapted | 2012-02-15 Eureka / Browser: skip the trigger (W1, SR, etc).when sorting line specials alphabetically. ------------------------------------------------------------------------ r1384 | ajapted | 2012-02-15 Eureka / Browser: implemented different SORT methods, and a callback so that changing the Sort setting will update the list. ------------------------------------------------------------------------ r1383 | ajapted | 2012-02-15 Eureka / Browser: fixed display of '&' in linetype descriptions. Added padding to numbers for Thing/Line/Sector types. ------------------------------------------------------------------------ r1382 | ajapted | 2012-02-15 Eureka / Browser: added code to SORT the items (currently the only method is alphabetically). ------------------------------------------------------------------------ r1381 | ajapted | 2012-02-15 Eureka / Browser: updated WriteUser() to write the search string and values for the Sort and Pics widgets. ------------------------------------------------------------------------ r1380 | ajapted | 2012-02-15 Eureka / Browser: added a 'Sort' choice and 'Pics' toggle button to certain browser panels. They currently do NOTHING. ------------------------------------------------------------------------ r1379 | ajapted | 2012-02-15 Eureka: worked on persisting the state of the Browser panels. ------------------------------------------------------------------------ r1378 | ajapted | 2012-02-14 Eureka: fixed bug persisting the 3D preview (view.Sin and view.Cos were not being updated properly). ------------------------------------------------------------------------ r1377 | ajapted | 2012-02-14 Eureka: updated CHANGELOG. ------------------------------------------------------------------------ r1376 | ajapted | 2012-02-14 Eureka: persist the current edit mode. ------------------------------------------------------------------------ r1375 | ajapted | 2012-02-14 Eureka: persist more Render3D state: gamma, texturing, lighting, etc... ------------------------------------------------------------------------ r1374 | ajapted | 2012-02-13 Eureka: properly handle no persistent user state for a map, via new M_DefaultUserState() function which zooms out to show whole map, sets the camera to the player thing, etc.... ------------------------------------------------------------------------ r1373 | ajapted | 2012-02-13 tweak. ------------------------------------------------------------------------ r1372 | ajapted | 2012-02-13 Eureka: make sure the -file pwad exists. ------------------------------------------------------------------------ r1371 | ajapted | 2012-02-13 Eureka: fixed Grid_ParseUser() to update the UI widgets (info bar, etc). ------------------------------------------------------------------------ r1370 | ajapted | 2012-02-12 Eureka: tweaked filename for user state persistence. ------------------------------------------------------------------------ r1369 | ajapted | 2012-02-12 Eureka: separated out some code to Editor_Init() function, and call it earlier than Editor_Loop() so that the user state from LoadLevel() can work properly. ------------------------------------------------------------------------ r1368 | ajapted | 2012-02-12 Eureka: implemented M_LoadUserState(). ------------------------------------------------------------------------ r1367 | ajapted | 2012-02-12 Eureka: implemented a M_ParseLine() function as the general way to break a line into tokens. The strings must be freed with M_FreeLine(). ------------------------------------------------------------------------ r1366 | ajapted | 2012-02-12 Eureka: more work on persisting "user state" when saving and loading maps The parsing and writing logic for the GRID and RENDER systems is now in place, but not yet complete. ------------------------------------------------------------------------ r1365 | ajapted | 2012-02-12 Eureka: more work on persisting "user state" when saving and loading maps The parsing and writing logic for the GRID and RENDER systems is now in place, but not yet complete. ------------------------------------------------------------------------ r1364 | ajapted | 2012-02-12 Eureka: for File/Export function, ask for the map slot _AFTER_ asking for the destination filename. ------------------------------------------------------------------------ r1363 | ajapted | 2012-02-12 Eureka: began work on mechanism to persist user state for a map, stuff like the camera position and angle, grid position and scale and step, browser categories, etc etc..... ------------------------------------------------------------------------ r1362 | ajapted | 2012-02-12 Eureka: added 'cache' directory. ------------------------------------------------------------------------ r1361 | ajapted | 2012-02-12 Eureka: code to compute the adler CRC when loading and saving a map. This required changing the lump processing order in LoadLevel() so that it matches SaveLevel() -- however it cannot do certain checks as it did before (e.g. check for invalid sector numbers in sidedefs), these must be done in a separate pass which hasn't been implemented yet. ------------------------------------------------------------------------ r1360 | ajapted | 2012-02-12 Eureka / Adler-32: tweaks. ------------------------------------------------------------------------ r1359 | ajapted | 2012-02-12 Eureka / Adler-32: added an 'extra' field which is the 32-bit sum of the 16-bit S2 field, modulo a large prime number (0xFFFEFFF9). This should make collisions a lot less likely, but definitely not as good as a proper CRC-64 implementation. ------------------------------------------------------------------------ r1358 | ajapted | 2012-02-12 Eureka: fixed #includes from renamed file: lib_crc --> lib_adler ------------------------------------------------------------------------ r1357 | ajapted | 2012-02-12 Eureka: renamed code file: lib_crc --> lib_adler ------------------------------------------------------------------------ r1356 | ajapted | 2012-02-09 Eureka: TODO (etc) update. ------------------------------------------------------------------------ r1355 | ajapted | 2012-02-09 Eureka: when dragging/scaling/rotating vertices, draw the linedefs too. Changed dynamic rotate (CTRL + Mouse2) to not scale, just rotate. ------------------------------------------------------------------------ r1354 | ajapted | 2012-02-08 Eureka: renamed typedef: obj_type_t --> obj_type_e ------------------------------------------------------------------------ r1353 | ajapted | 2012-02-08 Eureka / DOOM: renamed some Ammunition things. ------------------------------------------------------------------------ r1352 | ajapted | 2012-02-08 Eureka / DOOM: removed "PU:" prefix from pickup items, moved backpack into the Bonus category, and some minor renaming. ------------------------------------------------------------------------ r1351 | ajapted | 2012-02-08 Eureka: TODO update. ------------------------------------------------------------------------ r1350 | ajapted | 2012-02-08 Eureka: implemented MasterDir_Remove(). This should fix the crash issue (and a quick test did not reproduce the crash). ------------------------------------------------------------------------ r1349 | ajapted | 2012-02-08 Eureka: removed obsolete file: w_structs.h ------------------------------------------------------------------------ r1348 | ajapted | 2012-02-08 Eureka: removed most stuff from w_structs.h (obsolete), and moved the two actually used definitions --> w_rawdef.h ------------------------------------------------------------------------ r1347 | ajapted | 2012-02-08 Eureka: updated all header files to have consistent guards (i.e. the #ifndef XXX #define XXX ... #endif paradigm). ------------------------------------------------------------------------ r1346 | ajapted | 2012-02-08 Eureka: replaced 'img_dim_t' typedef with good old 'int'. ------------------------------------------------------------------------ r1345 | ajapted | 2012-02-07 tweak ------------------------------------------------------------------------ r1344 | ajapted | 2012-02-07 Eureka: ChangeLog / TODO update. ------------------------------------------------------------------------ r1343 | ajapted | 2012-02-07 Eureka: for File/New, no need to ask for a map slot when there's no current PWAD, as the File/Save function will do File/Export which always asks for the map slot. ------------------------------------------------------------------------ r1342 | ajapted | 2012-02-07 Eureka: show the current WAD and map name in the window title bar. ------------------------------------------------------------------------ r1341 | ajapted | 2012-02-07 Eureka: TODO twiddling. ------------------------------------------------------------------------ r1340 | ajapted | 2012-02-07 Eureka: committed current change-log. ------------------------------------------------------------------------ r1339 | ajapted | 2012-02-07 Eureka: the clipboard persists when changing maps, allowing copy-n-paste from one map/wad to another map/wad. ------------------------------------------------------------------------ r1338 | ajapted | 2012-02-07 Eureka: renamed variables: Warp --> Level_name, also Game --> Game_name and Port --> Port_name. ------------------------------------------------------------------------ r1337 | ajapted | 2012-02-07 Eureka: snap_to_grid is now the default. ------------------------------------------------------------------------ r1336 | ajapted | 2012-02-07 tweak. ------------------------------------------------------------------------ r1335 | ajapted | 2012-02-05 Eureka: when highlighting the nearest vertex, handle grid-snap mode so that the bbox we check has the same size as the grid step. This ensures we can close a line loop properly, instead of placing a vertex on top of an existing vertex. Bug reported by Lance MDR Rocket. ------------------------------------------------------------------------ r1334 | ajapted | 2012-02-05 Eureka: when creating a square sector (outside of map), make it occupy a single grid square. ------------------------------------------------------------------------ r1333 | ajapted | 2012-02-02 Eureka: moved some documents into new docs/ folder. ------------------------------------------------------------------------ r1332 | ajapted | 2012-02-02 Eureka: WISHLIST update. ------------------------------------------------------------------------ r1331 | ajapted | 2012-02-02 Eureka: added docs/ folder. ------------------------------------------------------------------------ r1330 | ajapted | 2012-02-01 Eureka: TODO update. ------------------------------------------------------------------------ r1329 | ajapted | 2012-02-01 Eureka: disable debugging messages in LOG file. ------------------------------------------------------------------------ r1328 | ajapted | 2012-02-01 Eureka: fixed year in About box text. ------------------------------------------------------------------------ r1327 | ajapted | 2012-02-01 Eureka: disabled some debugging stderr messages. ------------------------------------------------------------------------ r1326 | ajapted | 2012-02-01 tweak. ------------------------------------------------------------------------ r1325 | ajapted | 2012-02-01 Eureka: added changelog for v0.72 ------------------------------------------------------------------------ r1324 | ajapted | 2012-02-01 tweak ------------------------------------------------------------------------ r1323 | ajapted | 2012-02-01 Eureka: updated NEW_WORKFLOW document, various other doc tweaks. ------------------------------------------------------------------------ r1322 | ajapted | 2012-02-01 tweak ------------------------------------------------------------------------ r1321 | ajapted | 2012-02-01 tweak. ------------------------------------------------------------------------ r1320 | ajapted | 2012-02-01 Eureka: fixed FreshLevel() to apply the default textures (etc). ------------------------------------------------------------------------ r1319 | ajapted | 2012-02-01 Eureka: fixed bug in recent commit (Export code). ------------------------------------------------------------------------ r1318 | ajapted | 2012-02-01 Eureka: silenced a few compiler warnings. ------------------------------------------------------------------------ r1317 | ajapted | 2012-02-01 Eureka: tweaked messages when loading/saving/exporting a map. ------------------------------------------------------------------------ r1316 | ajapted | 2012-02-01 Eureka: disabled some unimplemented Menu commands. ------------------------------------------------------------------------ r1315 | ajapted | 2012-02-01 Eureka / DOOM: changed default ceiling texture to CEIL3_5. ------------------------------------------------------------------------ r1314 | ajapted | 2012-02-01 Eureka: more stuff for WISHLIST.... ------------------------------------------------------------------------ r1313 | ajapted | 2012-01-31 Eureka: added MasterDir_Add() and MasterDir_Remove() functions (note the latter is not implemented yet). ------------------------------------------------------------------------ r1312 | ajapted | 2012-01-31 Eureka: improved logic in File/Open function when the user selects a new WAD file -- in particular we only change 'edit_wad' and update the master directory if the operation is successful. Improved File/Export code with the MasterDir_Add/Remove calls. ------------------------------------------------------------------------ r1311 | ajapted | 2012-01-31 Eureka: tidying up... ------------------------------------------------------------------------ r1310 | ajapted | 2012-01-31 Eureka: small fix. ------------------------------------------------------------------------ r1309 | ajapted | 2012-01-31 Eureka: yet another TODO / WISHLIST update. ------------------------------------------------------------------------ r1308 | ajapted | 2012-01-31 Eureka: improved logic for DetermineIWAD(), handle $DOOMWADDIR and when -iwad merely specifies a directory. ------------------------------------------------------------------------ r1307 | ajapted | 2012-01-31 Eureka / Wad_file: fixed ::Open() with mode 'a' to only create the file when it doesn't exist (errno == ENOENT). Before it would try to create the file on other errors (such as no permission to R/W). ------------------------------------------------------------------------ r1306 | ajapted | 2012-01-31 Eureka: changed -file option to only accept a single PWAD. Later on there will be a -merge option for adding resource wads. ------------------------------------------------------------------------ r1305 | ajapted | 2012-01-31 Eureka: ensure new lumps have uppercase names. ------------------------------------------------------------------------ r1304 | ajapted | 2012-01-31 Eureka: TODO and WISHLIST update. ------------------------------------------------------------------------ r1303 | ajapted | 2012-01-31 Eureka: updated README for upcoming test package. ------------------------------------------------------------------------ r1302 | ajapted | 2012-01-31 Eureka: tweaked FEATURES.txt ------------------------------------------------------------------------ r1301 | ajapted | 2012-01-31 Eureka: when creating new sectors, give them proper default values, especially the default floor and ceiling textures. Similarly for new sidedefs. ------------------------------------------------------------------------ r1300 | ajapted | 2012-01-31 Eureka: TODO / WISHLIST update. ------------------------------------------------------------------------ r1299 | ajapted | 2012-01-31 Eureka: use the new 'g_default_thing' global when inserting things, and removed the other one. ------------------------------------------------------------------------ r1298 | ajapted | 2012-01-30 Eureka: added 'default_thing' value to DOOM and HERETIC game defs. ------------------------------------------------------------------------ r1297 | ajapted | 2012-01-30 Eureka: code to parse a 'default_thing' line in game definitions. ------------------------------------------------------------------------ r1296 | ajapted | 2012-01-30 Eureka: added 'default_textures' line to DOOM and HERETIC game defs. ------------------------------------------------------------------------ r1295 | ajapted | 2012-01-30 Eureka: code to parse 'default_textures' line in game definitions. ------------------------------------------------------------------------ r1294 | ajapted | 2012-01-30 Eureka: support for a 'sky_color' field in game definition files. ------------------------------------------------------------------------ r1293 | ajapted | 2012-01-30 Eureka: removed a couple of unused globals. ------------------------------------------------------------------------ r1292 | ajapted | 2012-01-30 tweak ------------------------------------------------------------------------ r1291 | ajapted | 2012-01-30 Eureka: more tidying of obsolete config options... ------------------------------------------------------------------------ r1290 | ajapted | 2012-01-30 Eureka: removed most of the obsolete config settings. ------------------------------------------------------------------------ r1289 | ajapted | 2012-01-30 Eureka: dead code removal. ------------------------------------------------------------------------ r1288 | ajapted | 2012-01-30 Eureka: dead code removal. ------------------------------------------------------------------------ r1287 | ajapted | 2012-01-30 Eureka: removed 'Expert' global variable. ------------------------------------------------------------------------ r1286 | ajapted | 2012-01-30 Eureka / Port defs: consistently have 'BOOM:' or 'EDGE:' in the names of the Boom and Edge specific linetypes, things, etc... ------------------------------------------------------------------------ r1285 | ajapted | 2012-01-30 Eureka: added a DeterminePort() function. ------------------------------------------------------------------------ r1284 | ajapted | 2012-01-30 Eureka: added 'ports/vanilla.ugh' definition, which is empty except for comments (and doesn't need anything). ------------------------------------------------------------------------ r1283 | ajapted | 2012-01-29 Eureka: TODO update. ------------------------------------------------------------------------ r1282 | ajapted | 2012-01-29 Eureka: properly flip linedefs when inserting a sector and the line(s) would have ended up with no right side (only a left side). ------------------------------------------------------------------------ r1281 | ajapted | 2012-01-29 Eureka: when auto-splitting a sector, ensure neither line loop faces outward. ------------------------------------------------------------------------ r1280 | ajapted | 2012-01-29 Eureka: noted a bug with rendering mid-masked textures. ------------------------------------------------------------------------ r1279 | ajapted | 2012-01-29 tweak ------------------------------------------------------------------------ r1278 | ajapted | 2012-01-29 Eureka.cfg : removed the obsolete iwad stuff. ------------------------------------------------------------------------ r1277 | ajapted | 2012-01-29 Eureka: have a single -iwad parameter (instead of -iwad1, -iwad2 etc....) ------------------------------------------------------------------------ r1276 | ajapted | 2012-01-29 tweakage. ------------------------------------------------------------------------ r1275 | ajapted | 2012-01-29 Eureka: WISHLIST update. ------------------------------------------------------------------------ r1274 | ajapted | 2012-01-29 Eureka: determine the 'Game' value from the IWAD filename. ------------------------------------------------------------------------ r1273 | ajapted | 2012-01-29 Eureka: for File/Export function, add ".wad" if filename has no extension. ------------------------------------------------------------------------ r1272 | ajapted | 2012-01-29 Eureka: code tweak (use FileExists utility function). ------------------------------------------------------------------------ r1271 | ajapted | 2012-01-29 Eureka / yutils: removed a few unused functions (fncmp, spec_path) and renamed a few functions (e.g. TimeGetMillies). ------------------------------------------------------------------------ r1270 | ajapted | 2012-01-28 Eureka: TODO update. ------------------------------------------------------------------------ r1269 | ajapted | 2012-01-28 Eureka / Wad_file: added PathName() and IsReadOnly() methods. ------------------------------------------------------------------------ r1268 | ajapted | 2012-01-28 Eureka: made the Wad_file::Open() method mimic the fopen() semantics, it now has a 'mode' parameter which can be 'r', 'w' or 'a'. Hence removed the ::Create() method from the public API. ------------------------------------------------------------------------ r1267 | ajapted | 2012-01-28 Eureka: some work to set 'Game' value differently, it will be based on the IWAD filename instead of being in the CFG file. ------------------------------------------------------------------------ r1266 | ajapted | 2012-01-28 Eureka: for File/Open function, implemented choosing a WAD file to load and improved the wording on the question. ------------------------------------------------------------------------ r1265 | ajapted | 2012-01-28 Eureka: for File/Open command, clear the MadeChanges flag and pan/zoom the canvas to show the whole level. ------------------------------------------------------------------------ r1264 | ajapted | 2012-01-28 Eureka: partial work on File/Open (CTRL-O) functionality. It really needs is a new widget, HOWEVER for now I will make do with fl_input and Confirm/Notify dialogs. ------------------------------------------------------------------------ r1263 | ajapted | 2012-01-28 dead code removal. ------------------------------------------------------------------------ r1262 | ajapted | 2012-01-27 tweakage. ------------------------------------------------------------------------ r1261 | ajapted | 2012-01-27 Eureka: for EXPORT function, if selected wad already exists then we just save the map into that wad, but if the MAP already exists in that wad then get confirmation from the user to overwrite it. ------------------------------------------------------------------------ r1260 | ajapted | 2012-01-27 Eureka: more Wishes.... sigh... ------------------------------------------------------------------------ r1259 | ajapted | 2012-01-27 Eureka: for EXPORT function, ask user for map-slot name and use it, and also make the exported WAD the current PWAD (set 'edit_wad' global). ------------------------------------------------------------------------ r1258 | ajapted | 2012-01-27 Eureka: new global 'Replacer' remembers when the user created a new map (via File/New or CTRL-N) __AND__ it would replace an existing level in the current PWAD. When doing File/Save (CTRL-S), check for Replacer and confirm whether the user really wants to replace the existing map. Improved File/New operation to ask for a map name. ------------------------------------------------------------------------ r1257 | ajapted | 2012-01-27 Eureka: bit of work on wad handling, the 'base_wad' and 'edit_wad' global variables have the current IWAD (required) and current PWAD (optional). ------------------------------------------------------------------------ r1256 | ajapted | 2012-01-27 Eureka / Games: renamed 'doom1.ugh' --> 'doom.ugh', to match the IWAD filename (DOOM.WAD) ------------------------------------------------------------------------ r1255 | ajapted | 2012-01-27 Eureka / Games: added game definitions for FINAL DOOM (tnt.ugh and plutonia.ugh). They merely include the DOOM 2 definitions, although eventually they will need stuff for their new textures. ------------------------------------------------------------------------ r1254 | ajapted | 2012-01-27 Eureka: tweaked color of camera arrow. ------------------------------------------------------------------------ r1253 | ajapted | 2012-01-27 Eureka: implemented 'Go To Camera' function (bound to END key). ------------------------------------------------------------------------ r1252 | ajapted | 2012-01-27 Eureka: version bump to 0.72 ------------------------------------------------------------------------ r1251 | ajapted | 2012-01-27 Eureka / README: document middle click functions (scale etc). ------------------------------------------------------------------------ r1250 | ajapted | 2012-01-27 Eureka: TODO update. ------------------------------------------------------------------------ r1249 | ajapted | 2012-01-27 Eureka: show proper location and angle of camera. ------------------------------------------------------------------------ r1248 | ajapted | 2012-01-27 Eureka: size of the camera arrow now depends on current map scale. ------------------------------------------------------------------------ r1247 | ajapted | 2012-01-27 Eureka: partial work on drawing the camera (a pink arrow)... ------------------------------------------------------------------------ r1246 | ajapted | 2012-01-27 Eureka: worked on semantics for wad handling (the File/ menu) and how the current "game" is defined. ------------------------------------------------------------------------ r1245 | ajapted | 2012-01-26 Eureka / Scaling: fixed bug where a rotation remains in-effect after releasing the CTRL key. ------------------------------------------------------------------------ r1244 | ajapted | 2012-01-26 Eureka / Scaling: properly handle modifiers: none = keep_aspect, SHIFT = any aspect, CTRL = rotate. ------------------------------------------------------------------------ r1243 | ajapted | 2012-01-26 Eureka / Scaling: various fixes... ------------------------------------------------------------------------ r1242 | ajapted | 2012-01-26 Eureka: use new scale_param_t stuff in UI_Canvas class. ------------------------------------------------------------------------ r1241 | ajapted | 2012-01-26 Eureka: added a scale_param_t structure with an Apply() method to transform a coordinate value. Updated all CMD_ScaleObjects2() code to use this structure and method (rather than mid_x etc... parameters). ------------------------------------------------------------------------ r1240 | ajapted | 2012-01-26 TODO bits... ------------------------------------------------------------------------ r1239 | ajapted | 2012-01-26 Eureka: TODO update. ------------------------------------------------------------------------ r1238 | ajapted | 2012-01-26 Eureka: moved next/prev/jump code into CMD_NextObject(), CMD_PrevObject() and CMD_JumpToObject() functions in e_path.cc/h file, and updated menu to call them. ------------------------------------------------------------------------ r1237 | ajapted | 2012-01-26 Eureka: dead code removal. ------------------------------------------------------------------------ r1236 | ajapted | 2012-01-26 Eureka: use 'V' key for the mirror vertically function (not 'I'). ------------------------------------------------------------------------ r1235 | ajapted | 2012-01-26 Eureka: Implemented 'Invert Selection' function (CTRL + I). ------------------------------------------------------------------------ r1234 | ajapted | 2012-01-26 Eureka: moved sel_op_e enum from main.h --> m_bitvec.h ------------------------------------------------------------------------ r1233 | ajapted | 2012-01-26 minor fix. ------------------------------------------------------------------------ r1232 | ajapted | 2012-01-26 WISH-LIST: console idea. ------------------------------------------------------------------------ r1231 | ajapted | 2012-01-25 tweaks. ------------------------------------------------------------------------ r1230 | ajapted | 2012-01-25 Eureka: for 'Export Map' function, properly handle CANCEL and ERROR returns from the file chooser (notify user), and actually use the filename selected, and notify user if creating the file failed. ------------------------------------------------------------------------ r1229 | ajapted | 2012-01-25 Eureka: factored out a Main_ConfirmQuit() function, and use it for the 'New Level' function too (so the user does not lose their changes). ------------------------------------------------------------------------ r1228 | ajapted | 2012-01-25 Eureka: TODO update (scaling stuff). ------------------------------------------------------------------------ r1227 | ajapted | 2012-01-25 Eureka / Scaling: experimental code for dynamic Rotation.... ------------------------------------------------------------------------ r1226 | ajapted | 2012-01-25 Eureka / Scaling: fixed the scaling calculations in Scaled_Coord() and UI_Canvas::ScaleUpdate(). ------------------------------------------------------------------------ r1225 | ajapted | 2012-01-25 Eureka / Scaler: factored out some common mirror logic so it can be used for the dynamic scaling code too (when scale_x or y is negative). Implemented the actual scaling in new CMD_ScaleObjects2() function. For some functions in x_mirror, pass 'selection_c' by reference instead of as a pointer. ------------------------------------------------------------------------ r1224 | ajapted | 2012-01-25 Eureka / Scaling: properly compute middle point of objects. ------------------------------------------------------------------------ r1223 | ajapted | 2012-01-25 Eureka: renamed some stuff, e.g. centre_of_objs() --> Objs_CalcMiddle() bbox_of_objects() --> Objs_CalcBBox(), and a few other things. ------------------------------------------------------------------------ r1222 | ajapted | 2012-01-25 Eureka / Scaling: added code to draw scaled LineDefs and Sectors. ------------------------------------------------------------------------ r1221 | ajapted | 2012-01-25 Eureka / Scaling: proper logic to draw the scaled selection, and added support for a 'keep_aspect' mode (hold down SHIFT key). ------------------------------------------------------------------------ r1220 | ajapted | 2012-01-25 Eureka: initial work on ability to Scale objects via middle mouse button, working very similarly to dragging objects... ------------------------------------------------------------------------ r1219 | ajapted | 2012-01-25 Eureka: WISHLIST bits... ------------------------------------------------------------------------ r1218 | ajapted | 2012-01-25 Eureka: improved Quantization algorithm, for vertices we analyse the linedefs and remember the orientations (V_HORIZ, V_VERT etc), and have better QuantSnapX/Y() grid methods. ------------------------------------------------------------------------ r1217 | ajapted | 2012-01-25 Eureka: for Quantization of vertices, added logic to keep horizontal lines horizontal and vertical lines vertical. ------------------------------------------------------------------------ r1216 | ajapted | 2012-01-25 dead code removal. ------------------------------------------------------------------------ r1215 | ajapted | 2012-01-25 Eureka: preliminary code for Quantize_Vertices(). ------------------------------------------------------------------------ r1214 | ajapted | 2012-01-24 Eureka: worked on Quantization function, for now only for Things. The significant aspects are: (1) leave the unsuccessfully moved things selected (and beep) (2) never move a thing directly on top of another one (3) if the nearest corner is unavailable, try the other corners [these rules will apply to vertex quantization too, and then some] ------------------------------------------------------------------------ r1213 | ajapted | 2012-01-22 Eureka: TODO item. ------------------------------------------------------------------------ r1212 | ajapted | 2012-01-22 Eureka: notes for a better (feasible) quantization algorithm. ------------------------------------------------------------------------ r1211 | ajapted | 2012-01-22 Eureka: experimental code for the 'File/New' menu command, and tweaked some other menu bits. ------------------------------------------------------------------------ r1210 | ajapted | 2012-01-22 Eureka / TODO: moved numerous items to the WISH-LIST, keeping the TODO for stuff which I intend to implemented before the next test package. ------------------------------------------------------------------------ r1209 | ajapted | 2012-01-18 tweak. ------------------------------------------------------------------------ r1208 | ajapted | 2012-01-18 Eureka: call the FLTK load_system_icons() function in InitFLTK(). Doesn't seem to have done anything though (no icons in the file chooser). ------------------------------------------------------------------------ r1207 | ajapted | 2012-01-18 Eureka: better logic for menu 'Zoom In/Out' functions via CMD_Zoom() and CMD_ZoomWholeLevel() functions. Tweaked some other menu bits. ------------------------------------------------------------------------ r1206 | ajapted | 2012-01-18 Eureka: test code for using FL_Native_File_Chooser.... ------------------------------------------------------------------------ r1205 | ajapted | 2012-01-18 Eureka: partial work on the "Export Map" function, i.e. saving the level into a brand spanking new wad file. No file selection dialog yet! ------------------------------------------------------------------------ r1204 | ajapted | 2012-01-18 Eureka: removed 'action' field from UI_MainWin class, have a 'want_quit' global variable instead. ------------------------------------------------------------------------ r1203 | ajapted | 2012-01-17 Eureka: fixed (restored?) deleting things in a sector when deleting that very sector. The things are kept (with the linedefs) in the "keep unused" mode, i.e. when the SHIFT key is held down. ------------------------------------------------------------------------ r1202 | ajapted | 2012-01-17 Eureka: various updates to README, TODO, WISHLIST. ------------------------------------------------------------------------ r1201 | ajapted | 2012-01-17 Eureka: fixed bug when saving a map more than once, the wrong lumps could get removed and hence end up with multiple versions of the map in the output wad file. ------------------------------------------------------------------------ r1200 | ajapted | 2012-01-17 minor code reformatting. ------------------------------------------------------------------------ r1199 | ajapted | 2012-01-17 Eureka: began work on texture alignment functions.... ------------------------------------------------------------------------ r1198 | ajapted | 2012-01-17 Eureka / selection_c class: added a 'first_obj' field which remembers the very first object added to the selection. It is -1 for an empty selection or when that object gets cleared. The find_first() method will return that object if valid, and the find_second() method had been updated to handle it properly too. Reduced MAX_STORE_SEL from 32 --> 24, as I think this will speed up certain operations that make heavy use of selection queries. Did some code formatting (like semicolons in for loops). ------------------------------------------------------------------------ r1197 | ajapted | 2012-01-17 Eureka: changed "rotate 90^ clockwise" key to 'R', leaving 'X' free for texture alignment function. ------------------------------------------------------------------------ r1196 | ajapted | 2012-01-17 Eureka: made grid size button a bit wider. ------------------------------------------------------------------------ r1195 | ajapted | 2012-01-16 Eureka: kicked the "Auto" grid choice code to the curb. ------------------------------------------------------------------------ r1194 | ajapted | 2012-01-16 Eureka: mostly finished grid "AUTO" mode, but it sucks since you cannot see what the current grid step is, so it's gonna get the boot. ------------------------------------------------------------------------ r1193 | ajapted | 2012-01-16 Eureka: fixed wrong initial color of Free/Snap button. ------------------------------------------------------------------------ r1192 | ajapted | 2012-01-16 Eureka: partial work on an "AUTO" mode for the grid, where the grid step automatically follows the current scale. It replaces the "locked" flag, and is now a choice in the Grid setting, so removed the "Locked" choice in the Snap widget. ------------------------------------------------------------------------ r1191 | ajapted | 2012-01-16 Eureka: added ToggleSnap() and ToggleAuto() methods to Grid_State_c. ------------------------------------------------------------------------ r1190 | ajapted | 2012-01-16 TODO update. ------------------------------------------------------------------------ r1189 | ajapted | 2012-01-16 Eureka: made the 'h' key toggle through the alternate grid mode too (i.e. normal --> simple --> none). This replaces the 'P' key function. ------------------------------------------------------------------------ r1188 | ajapted | 2012-01-16 Eureka: don't highlight a split_line if one of its vertices is selected. ------------------------------------------------------------------------ r1187 | ajapted | 2012-01-13 Eureka: in "simple" grid mode, make the X and Y axis lines (at X=0 and at Y=0) a brighter blue than the rest. Can help to orientate yourself. ------------------------------------------------------------------------ r1186 | ajapted | 2012-01-12 Eureka: default for grid snapping is now "FREE". ------------------------------------------------------------------------ r1185 | ajapted | 2012-01-11 Eureka: the digits '1' to '9' now set the GRID step, usually 2^n (i.e. 2, 4, 8, etc) but '8' is 192 units and '9' is 256 units. ------------------------------------------------------------------------ r1184 | ajapted | 2012-01-09 Eureka: notes in TODO.txt and tidying up. ------------------------------------------------------------------------ r1183 | ajapted | 2012-01-09 Eureka: TODO update (iwad stuff, grid keys). ------------------------------------------------------------------------ r1182 | ajapted | 2012-01-08 Eureka: implemented auto-sectoring when EXTENDING off an existing structure. ------------------------------------------------------------------------ r1181 | ajapted | 2012-01-08 Eureka: got automatic splitting of sectors working! :-) ------------------------------------------------------------------------ r1180 | ajapted | 2012-01-08 Eureka: TODO update. ------------------------------------------------------------------------ r1179 | ajapted | 2012-01-08 Eureka / basis: replaced LD_WhatSec() function with LineDef::WhatSector(). ------------------------------------------------------------------------ r1178 | ajapted | 2012-01-08 Eureka / basis: changed TouchesSector() method to take a sector number instead of a Sector pointer. ------------------------------------------------------------------------ r1177 | ajapted | 2012-01-08 Eureka: bit more work on ClosedLoop_Complex() logic.... ------------------------------------------------------------------------ r1176 | ajapted | 2012-01-08 Eureka: began work on logic when adding a new linedef to a vertex with two or more existing linedefs (auto-split OR auto-sectoring). Wrote the TwoNeighboringLinedefs() code and tested it. ------------------------------------------------------------------------ r1175 | ajapted | 2012-01-08 Eureka / basis: added LineDef::TouchesVertex() method. ------------------------------------------------------------------------ r1174 | ajapted | 2012-01-08 Eureka / lineloop: fixed a logic error in LookForIsland() code. ------------------------------------------------------------------------ r1173 | ajapted | 2012-01-08 Eureka / lineloop: removed obsolete super_find_sector_model() code. ------------------------------------------------------------------------ r1172 | ajapted | 2012-01-08 Eureka / lineloop: implemented FacesSector() method for islands. ------------------------------------------------------------------------ r1171 | ajapted | 2012-01-08 Eureka: new Insert_LineDef() function factors out the linedef creation bits from the Insert_Vertex() code. Began work on logic to auto-insert and auto-split sectors when adding new linedefs. New ClosedSimpleLoop() function handles the case of closing a simple loop (last vertex ends up with only two linedefs). ------------------------------------------------------------------------ r1170 | ajapted | 2012-01-08 Eureka / lineloop: made AssignSectorToLoop() part of public API. ------------------------------------------------------------------------ r1169 | ajapted | 2012-01-08 Eureka / lineloop: added clear() method, use it at start of TraceLineLoop(). ------------------------------------------------------------------------ r1168 | ajapted | 2012-01-08 Eureka / lineloop: added AllNew() and NeighboringSector() methods. ------------------------------------------------------------------------ r1167 | ajapted | 2012-01-08 Eureka: added 'ignore_new' flag to TraceLineLoop() function, this will cause "new" linedefs (ones without any sidedefs) to be ignored. ------------------------------------------------------------------------ r1166 | ajapted | 2012-01-06 Eureka / lineloop: added SameSector() method. ------------------------------------------------------------------------ r1165 | ajapted | 2012-01-06 Eureka / lineloop: added TotalLength() method. ------------------------------------------------------------------------ r1164 | ajapted | 2012-01-06 Eureka: updated README.txt ------------------------------------------------------------------------ r1163 | ajapted | 2012-01-06 Eureka / lineloop: determine the 'faces_outward' flag by computing the average angle between lines in the loop (done in TraceLineLoop). Fixed get() and get_just_line() methods to check the islands too, which is vital to make FindIslands() work properly. Fixed AssignSectorToSpace() to handle islands too. ------------------------------------------------------------------------ r1162 | ajapted | 2012-01-06 Eureka / lineloop: reworked TraceLineLoop() code for new class. ------------------------------------------------------------------------ r1161 | ajapted | 2012-01-06 Eureka / lineloop: reworked the FindIslands() logic for new class. ------------------------------------------------------------------------ r1160 | ajapted | 2012-01-06 Eureka / lineloop: destructor now frees the islands. Moved code around. ------------------------------------------------------------------------ r1159 | ajapted | 2012-01-06 Eureka / lineloop: rewrote the CalcBounds() method, which was previously a function called BoundsOfLinePath(). ------------------------------------------------------------------------ r1158 | ajapted | 2012-01-06 Eureka: more work on lineloop_c code, e.g. get() and push_back() methods. ------------------------------------------------------------------------ r1157 | ajapted | 2012-01-06 Eureka: added #include "x_loop.h" where needed. ------------------------------------------------------------------------ r1156 | ajapted | 2012-01-06 Eureka: began work on a lineloop_c class for representing a line-loop (an ordered list of linedef/side pairs). ------------------------------------------------------------------------ r1155 | ajapted | 2012-01-06 Eureka / Makefiles: added 'x_loop' code file to the build. ------------------------------------------------------------------------ r1154 | ajapted | 2012-01-06 Eureka: fixed #includes in x_loop.cc (restored needed, removed uneeded). ------------------------------------------------------------------------ r1153 | ajapted | 2012-01-06 Eureka: moved AssignSectorToSpace() function and related code from s_misc.cc/h --> x_loop.cc/h (new files). ------------------------------------------------------------------------ r1152 | ajapted | 2012-01-05 Eureka / TODO: some notes about line-loop modalities.... ------------------------------------------------------------------------ r1151 | ajapted | 2012-01-05 Eureka: fixed bug with dragging a vertex and splitting a line, the dragged vertex was not moving to the new position. ------------------------------------------------------------------------ r1150 | ajapted | 2012-01-05 tweak. ------------------------------------------------------------------------ r1149 | ajapted | 2012-01-05 Eureka: (tentative commit) : for LoadDefinitions() allow a line or thing or texture/flat to have an unknown group -- print a warning to the log file instead of FatalError. This was prompted by the issue where port-specific stuff (e.g. Boom) was referencing groups that don't exist in a game (e.g. Heretic). I will look for a cleaner way to handle that kind of incompatibility. ------------------------------------------------------------------------ r1148 | ajapted | 2012-01-05 Eureka / HERETIC: added missing 'sky_flat' value. ------------------------------------------------------------------------ r1147 | ajapted | 2012-01-05 Eureka: WISHLIST update. ------------------------------------------------------------------------ r1146 | ajapted | 2012-01-05 Eureka / Browser: implemented '!' in search box for negation. ------------------------------------------------------------------------ r1145 | ajapted | 2012-01-05 Eureka: minor TODO stuff. ------------------------------------------------------------------------ r1144 | ajapted | 2012-01-05 Eureka / DOOM: renamed category letters: l --> p (lifts) L --> l (light related) F --> r (raising floors) C --> h (crusher) E --> x (extrafloor) ------------------------------------------------------------------------ r1143 | ajapted | 2012-01-05 Eureka / HERETIC: changed stairs group letter to 'u' ("up"), and added a new group 's' for 'Sounds' (which the ambient sounds were already using). ------------------------------------------------------------------------ r1142 | ajapted | 2012-01-05 Eureka / DOOM: sorted linetypes into groups, removed the 'D' group (use 'd' for normal and fast doors), and have a single group 'k' for keyed doors. Moved linetype 85 (scroll wall right) into Boom defs. ------------------------------------------------------------------------ r1141 | ajapted | 2012-01-05 Eureka / HERETIC: finished adjusting the line types, using different letters than Yadex did (e.g. 'h' for crushers, 'p' for lifts, 'r' for raising floors -- avoiding upper case letters). ------------------------------------------------------------------------ r1140 | ajapted | 2012-01-05 Eureka / HERETIC: worked on linetypes, pasted line info from YADEX's game definition and sorted them into groups. ------------------------------------------------------------------------ r1139 | ajapted | 2012-01-05 Eureka / HERETIC: finished thing sprites and added the correct sizes. (It would've been a lot easier to copy/paste from YADEX, duh!). ------------------------------------------------------------------------ r1138 | ajapted | 2012-01-05 Eureka / HERETIC: a few more sprites.... ------------------------------------------------------------------------ r1137 | ajapted | 2012-01-05 Eureka / HERETIC: worked on sprite names for things, and fixed the id number for the 'Wings of Wrath' (was 23, should be 83). ------------------------------------------------------------------------ r1136 | ajapted | 2012-01-05 Eureka: worked on thing info for HERETIC game definition.... ------------------------------------------------------------------------ r1135 | ajapted | 2012-01-05 Eureka: began work on a HERETIC game definition file.... ------------------------------------------------------------------------ r1134 | ajapted | 2012-01-04 Eureka: fixed grid-toggle key ('h') not updating the infobar widget. ------------------------------------------------------------------------ r1133 | ajapted | 2012-01-04 Eureka: fixed the Grid menu's "OFF" choice. ------------------------------------------------------------------------ r1132 | ajapted | 2012-01-04 Eureka: WISHLIST update. ------------------------------------------------------------------------ r1131 | ajapted | 2012-01-04 Eureka: added new document 'NEW_WORKFLOW.txt', describing some of the significant differences between Eureka and its precedessor Yadex. ------------------------------------------------------------------------ r1130 | ajapted | 2012-01-04 Eureka: TODO update. ------------------------------------------------------------------------ r1129 | ajapted | 2012-01-04 Eureka: updated MergeVertex() to handle a linedef which exists between the two vertices -- the new logic ensures it gets deleted. ------------------------------------------------------------------------ r1128 | ajapted | 2012-01-04 Eureka: TODO update. ------------------------------------------------------------------------ r1127 | ajapted | 2012-01-04 Eureka: never highlight the same vertex as the one we are dragging, preventing an fatal error when trying to merge a vertex onto itself. ------------------------------------------------------------------------ r1126 | ajapted | 2012-01-04 Eureka: implemented merging vertices when dragging a single vertex onto an existing vertex. ------------------------------------------------------------------------ r1125 | ajapted | 2012-01-04 Eureka: fixed the UI_Canvas widget to draw both a a highlight and a dragged selection at the same time. The logic in UpdateHighlight() is what's responsible for keeping it sane. ------------------------------------------------------------------------ r1124 | ajapted | 2012-01-04 tweaks. ------------------------------------------------------------------------ r1123 | ajapted | 2012-01-04 Eureka: improved the UpdateHighlight() code, with a check for dragging and splitting off the panel stuff into a new UpdatePanel() function. ------------------------------------------------------------------------ r1122 | ajapted | 2012-01-04 Eureka: added Editor_State_c field 'drag_single_vertex', normally -1 but contains a vertex number when dragging just a single vertex. ------------------------------------------------------------------------ r1121 | ajapted | 2012-01-04 Eureka: more DOOM definition tweaks.... ------------------------------------------------------------------------ r1120 | ajapted | 2012-01-04 Eureka: moved most DOOM 2 specific textures and flats into doom2.ugh ------------------------------------------------------------------------ r1119 | ajapted | 2012-01-04 tidying up. ------------------------------------------------------------------------ r1118 | ajapted | 2012-01-04 Eureka: moved rest of BOOM stuff from doom_specials.ugh --> boom.ugh ------------------------------------------------------------------------ r1117 | ajapted | 2012-01-04 Eureka: moved all the EDGE-specific stuff and some BOOM-specific stuff out of the DOOM game definitions and into their own port definitions. ------------------------------------------------------------------------ r1116 | ajapted | 2012-01-04 Eureka: moved DOOM 2 specific things from doom_common.ugh --> doom2.ugh, which includes the Super Shotgun, Megasphere, Boss-brain stuff, extra gore decorations, and the DOOM 2 specific monsters like the Archvile, Mancubus etc.... ------------------------------------------------------------------------ r1115 | ajapted | 2012-01-03 Eureka: merged 'doom_tex.ugh' back into 'doom_common.ugh'. All these shenanigans is to allow some DOOM engine games (such as Chex Quest, HacX, and Harmony) to use the common engine stuff but specify their own thing types and flats/textures. ------------------------------------------------------------------------ r1114 | ajapted | 2012-01-03 Eureka: moved some stuff from doom_tex.ugh --> doom1/2.ugh ------------------------------------------------------------------------ r1113 | ajapted | 2012-01-03 Eureka: separated out the line/sector specials from doom_common.ugh into a new file: 'doom_specials.ugh'. ------------------------------------------------------------------------ r1112 | ajapted | 2012-01-03 Eureka: moved the flat/texture definitions out of doom_common.ugh and into a new file 'doom_tex.ugh'. ------------------------------------------------------------------------ r1111 | ajapted | 2012-01-03 Eureka: added 'doom1.ugh' and 'doom2.ugh' game definitions, which so far do little more than simply include the common file. Work still needs to be done to properly separate everything.... ------------------------------------------------------------------------ r1110 | ajapted | 2012-01-03 Eureka: renamed game config file: doom2.ugh --> doom_common.ugh (as the bulk of that file will be stuff in common to both games). ------------------------------------------------------------------------ r1109 | ajapted | 2012-01-03 Eureka: implemented 'include' directive for ".ugh" definition files. This will be handy for: (a) common stuff between DOOM 1 and DOOM 2 (b) ports which are boom compatible ------------------------------------------------------------------------ r1108 | ajapted | 2012-01-03 Eureka: worked on "ugh" definition file loading, supply a folder name as well as the filename to the LoadDefinitions() function, with some test code which loads the "ports/boom" definition file. ------------------------------------------------------------------------ r1107 | ajapted | 2012-01-03 Eureka: added a mods/ directory. ------------------------------------------------------------------------ r1106 | ajapted | 2012-01-03 WISHLIST tweak. ------------------------------------------------------------------------ r1105 | ajapted | 2012-01-03 Eureka: renamed configs/ folder --> games/ ------------------------------------------------------------------------ r1104 | ajapted | 2012-01-03 Eureka: moved BOOM and EDGE definition files --> ports/ ------------------------------------------------------------------------ r1103 | ajapted | 2012-01-03 Eureka: added 'ports' directory, a place for source-port definitions. ------------------------------------------------------------------------ r1102 | ajapted | 2012-01-03 Eureka: added '192' as a grid size. ------------------------------------------------------------------------ r1101 | ajapted | 2012-01-03 Eureka: draw vertices in proper colors when selected and/or highlighted (previously they remained green, only the box around them has the proper color). Also made vertices more visible (solid area at centre). ------------------------------------------------------------------------ r1100 | ajapted | 2012-01-03 TODO update. ------------------------------------------------------------------------ r1099 | ajapted | 2012-01-03 Eureka: reworked colors of linedefs (UI_Canvas), white is used for single-sided lines (instead of lines with the blocking flag), and white is used in VERTEX mode too now. In LINEDEF mode, cyan is used for double-sided lines which have the blocking flag. ------------------------------------------------------------------------ r1098 | ajapted | 2012-01-03 Eureka: implemented CMD_CorrectSector(). ------------------------------------------------------------------------ r1097 | ajapted | 2012-01-03 Eureka: when splitting a linedef with a new vertex, ensure the vertex lies directly on the linedef (i.e. not slightly off the side). This only applies when grid snapping is OFF. ------------------------------------------------------------------------ r1096 | ajapted | 2012-01-03 Eureka: began work to make 'c' key be a "correct sector" function. ------------------------------------------------------------------------ r1095 | ajapted | 2012-01-03 Eureka / Utilities: added PerpDist() and AlongDist(), and removed some unused stuff. ------------------------------------------------------------------------ r1094 | ajapted | 2012-01-03 Eureka: implemented MoveCoordOntoLineDef() function. ------------------------------------------------------------------------ r1093 | ajapted | 2012-01-03 Eureka: experimented with an alternate grid (simple squares), which can be toggled via 'P' key (need a better key or mechanism though). ------------------------------------------------------------------------ r1092 | ajapted | 2012-01-03 Eureka: made the single-quote key (') move the 3D camera to the cursor position. ------------------------------------------------------------------------ r1091 | ajapted | 2012-01-03 Eureka: changed LighterColor() to be less bright. ------------------------------------------------------------------------ r1090 | ajapted | 2012-01-03 Eureka: added code to create a 'bright_map' table, which maps palette colors to a brighter (closer to white) color in the palette. This could potentially be used in the 3D preview to highlight stuff. ------------------------------------------------------------------------ r1089 | ajapted | 2012-01-03 Eureka: deleting a single vertex attached to TWO linedefs (no more, no less) is now a special case which merges the linedefs together. ------------------------------------------------------------------------ r1088 | ajapted | 2012-01-03 Eureka: TODO update. ------------------------------------------------------------------------ r1087 | ajapted | 2012-01-03 Eureka: changed DisconnectLineDefs logic so that the selected linedefs get any new vertices (existing geometry keeps the existing vertices). ------------------------------------------------------------------------ r1086 | ajapted | 2012-01-03 Eureka: implemented the logic for 'DisconnectLineDefs', which works somewhat different than disconnecting vertices since we want to keep all linedefs in the selection connected and only disconnect from linedefs NOT in the selection. ------------------------------------------------------------------------ r1085 | ajapted | 2012-01-03 tidy up. ------------------------------------------------------------------------ r1084 | ajapted | 2012-01-03 Eureka: added 'd' command to README.txt ------------------------------------------------------------------------ r1083 | ajapted | 2012-01-03 Eureka: fixed problems in the DisconnectVertex code, and improved the logic in CalcDisconnectCoord(). Also assigned to 'd' key (was 'D'). ------------------------------------------------------------------------ r1082 | ajapted | 2012-01-02 Eureka: implemented a 'D' command to Disconnect linedefs. Untested. ------------------------------------------------------------------------ r1081 | ajapted | 2012-01-02 Eureka: version bump to 0.70 -- good progress with vertex stuff. ------------------------------------------------------------------------ r1080 | ajapted | 2012-01-02 Eureka: just some algorithm notes... ------------------------------------------------------------------------ r1079 | ajapted | 2012-01-02 Eureka: yet another TODO update. ------------------------------------------------------------------------ r1078 | ajapted | 2012-01-02 Eureka: when adding a linedef between two existing vertices, reselect the second one IFF it was isolated (not connected to any linedefs). ------------------------------------------------------------------------ r1077 | ajapted | 2012-01-02 Eureka: minor renaming, CastVerty --> CastVert. ------------------------------------------------------------------------ r1076 | ajapted | 2012-01-02 Eureka: use RGB_RED() etc macros instead of directly manipulating color values. ------------------------------------------------------------------------ r1075 | ajapted | 2012-01-02 Eureka: added DarkerColor() function. ------------------------------------------------------------------------ r1074 | ajapted | 2012-01-02 Eureka: renamed pcolour_t --> rgb_color_t ------------------------------------------------------------------------ r1073 | ajapted | 2012-01-02 Eureka: made DARKGREY and LIGHTGREY a bit brighter, and DARKGREY is used for things now (removed THING_REM constant). ------------------------------------------------------------------------ r1072 | ajapted | 2012-01-02 Eureka: implemented dragging a vertex onto a linedef to split it. ------------------------------------------------------------------------ r1071 | ajapted | 2012-01-02 Eureka: use "highlighted()" instead of "! highlighted.is_nil()" ------------------------------------------------------------------------ r1070 | ajapted | 2012-01-02 Eureka / Browser: added a 'X' close button at top right. ------------------------------------------------------------------------ r1069 | ajapted | 2012-01-02 Eureka: for user interface use 'Linedef' instead of 'LineDef'. ------------------------------------------------------------------------ r1068 | ajapted | 2012-01-02 Eureka: TODO update. ------------------------------------------------------------------------ r1067 | ajapted | 2012-01-02 Eureka: made ^U be the main key to unselect everything, instead of END. The back-quota key (`) remains an alternative to ^U, as well as just clicking in an empty spot. Made the '0' key be an alternative for HOME key (centre map, zoom out). ------------------------------------------------------------------------ r1066 | ajapted | 2012-01-02 Eureka: when dragging, require the pointer to move at least 6 pixels before the drag is considered valid. This prevents accidentally moving an object when all you wanted to do was select it. ------------------------------------------------------------------------ r1065 | ajapted | 2012-01-02 Eureka: TODO update. ------------------------------------------------------------------------ r1064 | ajapted | 2012-01-02 Eureka: never highlight a 'split_line' when a vertex is highlighted. Fixed updating the split_line while dragging a single vertex (however the ability to split the line after the drag is not implemented yet). ------------------------------------------------------------------------ r1063 | ajapted | 2012-01-02 Eureka: code reformatting of 'for' loops, have a space before the ';' separators. ------------------------------------------------------------------------ r1062 | ajapted | 2012-01-02 Eureka: added SIDE_RIGHT and SIDE_LEFT constants. ------------------------------------------------------------------------ r1061 | ajapted | 2012-01-02 Eureka: removed unused constant 'Y_NULL'. ------------------------------------------------------------------------ r1060 | ajapted | 2012-01-02 Eureka: TODO update. ------------------------------------------------------------------------ r1059 | ajapted | 2012-01-02 Eureka: when adding vertices, prevent creating zero-length linedefs, and when a vertex is highlighted and nothing is selected then merely select that vertex -- this allows using the SPACE key to begin the process of adding linedefs, which is quite convenient. ------------------------------------------------------------------------ r1058 | ajapted | 2012-01-02 Eureka: when using 'x' key to split linedefs, don't selected the new linedefs if they were not selected before. ------------------------------------------------------------------------ r1057 | ajapted | 2012-01-01 tweak. ------------------------------------------------------------------------ r1056 | ajapted | 2012-01-01 Eureka: pass size to CreateSquare(). ------------------------------------------------------------------------ r1055 | ajapted | 2012-01-01 tweak. ------------------------------------------------------------------------ r1054 | ajapted | 2012-01-01 Eureka: got the 'Choose' buttons in the Line/Sector/Thing panels working [they open up the browser on the appropriate list of types]. ------------------------------------------------------------------------ r1053 | ajapted | 2012-01-01 tweak. ------------------------------------------------------------------------ r1052 | ajapted | 2012-01-01 Eureka / 3D View: removed "walking" mode, the 'w' key now just moves the camera Z to the ground + viewheight. ------------------------------------------------------------------------ r1051 | ajapted | 2012-01-01 Eureka: changed the sector height +/- buttons step from 16 to 8. (It needs to be configurable though). ------------------------------------------------------------------------ r1050 | ajapted | 2011-12-31 Eureka: fixed silly bug in Drag_UpdateObjectDist(). ------------------------------------------------------------------------ r1049 | ajapted | 2011-12-31 Eureka: fixed dragging of objects to honor snapping, and use a focus object as returned by GetDrawFocus(). ------------------------------------------------------------------------ r1048 | ajapted | 2011-12-31 Eureka: fixed bug in GetDragFocus() -- uninitialized variables. ------------------------------------------------------------------------ r1047 | ajapted | 2011-12-31 Eureka: minor renaming: mapx --> map_x, mapy --> map_y ------------------------------------------------------------------------ r1046 | ajapted | 2011-12-31 Eureka: improved GetDragFocus() code in two major ways: (1) check ALL the objects in the selection (2) when snapping is active, check if the majority of the objects are on the grid -- if so then only pick a coordinate which is also on the grid. ------------------------------------------------------------------------ r1045 | ajapted | 2011-12-31 Eureka: added OnGrid() method to test if a point is on the grid. ------------------------------------------------------------------------ r1044 | ajapted | 2011-12-31 Eureka: implemented GetDragFocus() which returns the coordinate of the selected object which will be used as the focus for dragging (especially when grid-snapping, that coordinate will snap to the grid). ------------------------------------------------------------------------ r1043 | ajapted | 2011-12-30 Eureka: TODO update. ------------------------------------------------------------------------ r1042 | ajapted | 2011-12-30 Makefile: lowercased program name: Eureka --> eureka ------------------------------------------------------------------------ r972 | ajapted | 2011-12-11 Eureka: TODO update. ------------------------------------------------------------------------ r960 | ajapted | 2011-12-09 Eureka / Browser: ability to scroll browser with PGUP and PGDN keys. ------------------------------------------------------------------------ r959 | ajapted | 2011-12-09 Eureka: minor reformatting. ------------------------------------------------------------------------ r958 | ajapted | 2011-12-09 Eureka / Browser: fixed scrolling anomalies. ------------------------------------------------------------------------ r957 | ajapted | 2011-12-08 Eureka: mucho tweakage of 'About' window appearance. ------------------------------------------------------------------------ r956 | ajapted | 2011-12-08 Eureka: implemented a basic 'About' window. New code files: ui_about.cc/h and ui_hyper.cc/h ------------------------------------------------------------------------ r955 | ajapted | 2011-12-07 Eureka: TODO update. ------------------------------------------------------------------------ r954 | ajapted | 2011-12-07 Eureka: when adding a vertex which BOTH splits a line and adds a line, don't reselect the new vertex. ------------------------------------------------------------------------ r953 | ajapted | 2011-12-07 color tweak. ------------------------------------------------------------------------ r952 | ajapted | 2011-12-07 Eureka: implemented being able to split a linedef in Vertex mode by simply hovering over a linedef and pressing INSERT. ------------------------------------------------------------------------ r951 | ajapted | 2011-12-07 Eureka: fixed the logic to highlight a to-be-split linedef. ------------------------------------------------------------------------ r950 | ajapted | 2011-12-07 Eureka: worked on logic to find the linedef which would be split by a new vertex. ------------------------------------------------------------------------ r949 | ajapted | 2011-12-07 Eureka: worked on logic to highlight a linedef which would be split by a newly inserted vertex. ------------------------------------------------------------------------ r948 | ajapted | 2011-12-07 Eureka: when adding linedefs in Vertex mode, don't select the second vertex when it wasn't a new vertex (i.e. after closing off an area). ------------------------------------------------------------------------ r947 | ajapted | 2011-12-07 Eureka: TODO update. ------------------------------------------------------------------------ r946 | ajapted | 2011-12-07 Eureka / README: describe 'e' / 'E' keys for SECTOR mode. ------------------------------------------------------------------------ r945 | ajapted | 2011-12-07 Eureka: when selecting contiguous sectors, never go through closed doors. ------------------------------------------------------------------------ r944 | ajapted | 2011-12-07 Eureka: implemented new command 'e' / 'E' in SECTORS mode which selects contiguous sectors with the same floor height / texture. ------------------------------------------------------------------------ r943 | ajapted | 2011-12-07 Eureka: implemented 'E' key which selects lines in a path which all share the same texture. ------------------------------------------------------------------------ r942 | ajapted | 2011-12-07 Eureka: made 'e' key (Select-lines-in-path) use additive mode. The CTRL-E key is also the same function (compatibility with Yadex), though it still could be nabbed for a better use in the future. ------------------------------------------------------------------------ r941 | ajapted | 2011-12-07 Eureka: TODO + WISHLIST update. ------------------------------------------------------------------------ r940 | ajapted | 2011-12-07 Eureka: have a Browser_Key() and Grid_Key() function. ------------------------------------------------------------------------ r939 | ajapted | 2011-12-06 Eureka: worked on having a Global_Key() function which handles all global stuff (such as 'b' to toggle the Browser panel). Editor_Key() will be reserved for commands that modify the map or grid. ------------------------------------------------------------------------ r938 | ajapted | 2011-12-06 Eureka: fixed sidedef info (in LineDef panel) not being updated when picking new textures on selected linedefs. ------------------------------------------------------------------------ r937 | ajapted | 2011-12-06 Eureka: honor grid snapping when pasting + pointer is outside window. ------------------------------------------------------------------------ r936 | ajapted | 2011-12-06 Eureka: fixed Paste (^V) and Copy (o) commands to honor grid snapping, and improved method to find the "centre" vertex or thing (return the coordinate of an actual vertex or thing in the group) -- hence if the copied group was all aligned to the grid, the pasted one will be too. ------------------------------------------------------------------------ r935 | ajapted | 2011-12-06 Eureka: provide a function to check if clipboard contains stuff. ------------------------------------------------------------------------ r934 | ajapted | 2011-12-06 Eureka: when inserting sectors, don't clone the currently selected one unless the SHIFT key is pressed. When inserting linedef, check whether a linedef between the two vertices exists already. Removed the crufty old InsertNewObject() code. ------------------------------------------------------------------------ r933 | ajapted | 2011-12-06 Eureka: implemented key (CTRL-U or CTRL-K) to clear the search box. ------------------------------------------------------------------------ r932 | ajapted | 2011-12-06 Eureka / Browser: implemented 'c' key to cycle through categories, and the 'C' key to reset category to "ALL". ------------------------------------------------------------------------ r931 | ajapted | 2011-12-06 Eureka: yet another TODO / WISHLIST update. ------------------------------------------------------------------------ r930 | ajapted | 2011-12-06 Eureka / Browser: support categories for Thing Types and Line Types. ------------------------------------------------------------------------ r929 | ajapted | 2011-12-06 Eureka / Browser: support categories for Textures and Flats. ------------------------------------------------------------------------ r928 | ajapted | 2011-12-06 Eureka / Browser: worked on getting the Category / Search working, and removed various old crud. ------------------------------------------------------------------------ r927 | ajapted | 2011-12-06 Eureka: version bump, really good progress with the Browser. ------------------------------------------------------------------------ r926 | ajapted | 2011-12-06 Eureka: show mid-masked textures with a bright CYAN background. ------------------------------------------------------------------------ r925 | ajapted | 2011-12-06 Eureka: added panel_W, browser_W fields to UI_Window class. ------------------------------------------------------------------------ r924 | ajapted | 2011-12-06 tweaks. ------------------------------------------------------------------------ r923 | ajapted | 2011-12-06 Eureka: force the Kromulent Factor (KF) = 1 for time being. ------------------------------------------------------------------------ r922 | ajapted | 2011-12-06 Eureka: TODO / WISHLIST update. ------------------------------------------------------------------------ r921 | ajapted | 2011-12-06 Eureka / Browser: make it wider, enough for 4 flats or two 128-wide textures. ------------------------------------------------------------------------ r920 | ajapted | 2011-12-06 Eureka: when loading textures, skip the very first entry (#0) since it's not really usable -- in the DOOM engine the #0 texture is never drawn. ------------------------------------------------------------------------ r919 | ajapted | 2011-12-06 Eureka / Browser: have two constructors for Browser_Item: simple one for text buttons (e.g. Thing Types) and second one for picture buttons (Textures and Flats). The textual buttons are now working again. ------------------------------------------------------------------------ r918 | ajapted | 2011-12-06 Eureka / Browser: show flat and texture names underneath the pic. ------------------------------------------------------------------------ r917 | ajapted | 2011-12-05 Eureka: TODO update. ------------------------------------------------------------------------ r916 | ajapted | 2011-12-05 Eureka / Browser: fixed bug with funny gaps at the top (the Filter method was visited the scrollbar widgets since they were not the last ones). Made the background of scrolling part be BLACK for textures and flats. Various tweaks and tidying of the code. ------------------------------------------------------------------------ r915 | ajapted | 2011-12-05 Eureka / Browser: fixed the side-by-side packing logic in Filter(). ------------------------------------------------------------------------ r914 | ajapted | 2011-12-05 Eureka / Menu: added FL_MENU_INACTIVE to the divider lines, and tidied up some junk in there. ------------------------------------------------------------------------ r913 | ajapted | 2011-12-05 Eureka: TODO / WISHLIST stuff. ------------------------------------------------------------------------ r912 | ajapted | 2011-12-05 Eureka / Browser: worked on Filter() logic and side-by-side packing... ------------------------------------------------------------------------ r911 | ajapted | 2011-12-05 Eureka / Browser: partial work on handling the Category setting.... ------------------------------------------------------------------------ r910 | ajapted | 2011-12-04 Eureka / Browser: code to setup the Category choices for each browser box. (the choice is not used yet however). ------------------------------------------------------------------------ r909 | ajapted | 2011-12-04 Eureka / README: a couple more fixes. ------------------------------------------------------------------------ r908 | ajapted | 2011-12-04 Eureka / README: small fix. ------------------------------------------------------------------------ r907 | ajapted | 2011-12-04 Eureka / Browser: fixed the Texture/Flat browser not showing anything, we need to Populate() the browser boxes _after_ loading all the flats and textures from the wad(s). ------------------------------------------------------------------------ r906 | ajapted | 2011-12-04 Eureka / Browser: various fixes, the new structure is now working OK. ------------------------------------------------------------------------ r905 | ajapted | 2011-12-04 Eureka / Browser: worked on new structure, where UI_Browser is a container widget which contains (and controls) a bunch of UI_Browser_Box widgets. ------------------------------------------------------------------------ r904 | ajapted | 2011-12-04 Eureka: created empty "boom.ugh" and "edge.ugh" engine config files (in preparation to move the specific pieces out of doom2.ugh). ------------------------------------------------------------------------ r903 | ajapted | 2011-12-04 Eureka: moved DOOM2 game configuration file --> configs/ folder. ------------------------------------------------------------------------ r902 | ajapted | 2011-12-04 Eureka: addid configs/ folder. ------------------------------------------------------------------------ r901 | ajapted | 2011-12-04 Eureka: fixes for the new Browser menu... ------------------------------------------------------------------------ r900 | ajapted | 2011-12-04 Eureka: added a "Browser" menu on the main menu bar, worked on code to support it. ------------------------------------------------------------------------ r899 | ajapted | 2011-12-04 Eureka / Canvas: tweaked size of Knobby lines. ------------------------------------------------------------------------ r898 | ajapted | 2011-12-04 Eureka / Browser: worked on a UI_Browser_Menu class. ------------------------------------------------------------------------ r897 | ajapted | 2011-12-04 Eureka: TODO update. ------------------------------------------------------------------------ r896 | ajapted | 2011-12-04 tweak. ------------------------------------------------------------------------ r895 | ajapted | 2011-12-03 Eureka: when making category menu strings, also return the group letters so they can be used to filter the browser items. ------------------------------------------------------------------------ r894 | ajapted | 2011-12-03 tweak. ------------------------------------------------------------------------ r893 | ajapted | 2011-12-03 Eureka: capitalize 'OTHER' in browser categories. ------------------------------------------------------------------------ r892 | ajapted | 2011-12-03 Eureka: fixed missing '|' in category string conversion. ------------------------------------------------------------------------ r891 | ajapted | 2011-12-03 Eureka: added code to convert the descriptions in linegroups (etc) into a menu string which can be used in an Fl_Choice widget. ------------------------------------------------------------------------ r890 | ajapted | 2011-12-03 Eureka: updated game config loader to handle 'texturegroup', 'texture' and 'flat' definitions. ------------------------------------------------------------------------ r889 | ajapted | 2011-12-03 Eureka / DOOM2 config: use '-' (not 'x') as letter for "Other" category, and added the '-' as a thinggroup and a texturegroup too. ------------------------------------------------------------------------ r888 | ajapted | 2011-12-03 Eureka / DOOM2 config: finished texture/flat section, tweaked things section. ------------------------------------------------------------------------ r887 | ajapted | 2011-12-02 Eureka / DOOM2 config: worked on texture categories. ------------------------------------------------------------------------ r886 | ajapted | 2011-11-30 Eureka / 3D view: experimental code to draw a highlight border around a solid surface (lower, upper, floor, ceiling). ------------------------------------------------------------------------ r885 | ajapted | 2011-11-30 Eureka: moved some color #defines --> im_color.h ------------------------------------------------------------------------ r884 | ajapted | 2011-11-30 Eureka / DOOM2 config: tweaked descriptions of some linetypes. ------------------------------------------------------------------------ r883 | ajapted | 2011-11-30 Eureka / DOOM2 config: gave some things prefixes, e.g. "MON:" for monsters, "PU:" for pickups and "WP:" for weapons. ------------------------------------------------------------------------ r882 | ajapted | 2011-11-30 Eureka / Browser: tweaked layout. ------------------------------------------------------------------------ r881 | ajapted | 2011-11-30 Eureka: made the Browser a bit wider (to make things fit more comfortably). ------------------------------------------------------------------------ r880 | ajapted | 2011-11-30 Version bump to 0.666 in honor of Texture/Flat browser working. ------------------------------------------------------------------------ r879 | ajapted | 2011-11-30 Eureka / Browser: only allow Right click to change sector ceilings (not SHIFT or middle click) -- for consistency with linedef handling. ------------------------------------------------------------------------ r878 | ajapted | 2011-11-30 Eureka / Browser: imlemented logic for setting textures on two-sided lines. Left click adjusts lowers and Right click adjusts uppers, and Middle click sets mid-masked textures (on both sides). For lowers and uppers we pick the side that faces out, but SHIFT key picks the opposite side. Also some logic for handling windows nicely (change BOTH lower and upper, but only with Left click). ------------------------------------------------------------------------ r877 | ajapted | 2011-11-30 Eureka: the normal select-lines-in-path (on 'e' key) now doesn't unmerge if the original line was selected, since the whole selection gets cleared anyway. New way is more useful when lots of lines are selected and you only want the new path to be selected. ------------------------------------------------------------------------ r876 | ajapted | 2011-11-30 Eureka / Browser: got texture setting on one-sided linedefs working. ------------------------------------------------------------------------ r875 | ajapted | 2011-11-30 Eureka: tweaked UI_Sector:SetTexture() code (check if count > 0). ------------------------------------------------------------------------ r874 | ajapted | 2011-11-30 Eureka / Browser: got texture setting for floors and ceilings working, where a left click sets the floor and a right click sets the ceilings. ------------------------------------------------------------------------ r873 | ajapted | 2011-11-30 Eureka / Browser: partial worked on ability to set flat and textures on sectors and linedefs via the browser. Changed button to Fl_Repeat_Button since that widget lets us check what buttons / modifiers were used. (The standard Fl_Button callback gets done on RELEASE --> no buttons). ------------------------------------------------------------------------ r872 | ajapted | 2011-11-30 Eureka: renamed code file: selpath --> e_path ------------------------------------------------------------------------ r871 | ajapted | 2011-11-30 Eureka: renamed code file: selpath --> e_path ------------------------------------------------------------------------ r870 | ajapted | 2011-11-30 Eureka: added keys for CMD_SelectLinesInPath : 'e' for normal mode, CTRL-E for the additive mode. ------------------------------------------------------------------------ r869 | ajapted | 2011-11-30 Eureka: for selecting lines in a path, have 'additive' parameter which does not forget the current selection. The 'one_sided' mode proved to be fairly useless, hence removed that logic. ------------------------------------------------------------------------ r868 | ajapted | 2011-11-30 Eureka: finished CMD_SelectLinesInPath() : logic to get starting line. ------------------------------------------------------------------------ r867 | ajapted | 2011-11-30 Eureka: added TwoSided() method to LineDef class. ------------------------------------------------------------------------ r866 | ajapted | 2011-11-30 Eureka: implemented 'one_sided' mode for CMD_SelectLinesInPath(). ------------------------------------------------------------------------ r865 | ajapted | 2011-11-30 Eureka: wrote new logic for selecting linedefs in a path. ------------------------------------------------------------------------ r864 | ajapted | 2011-11-29 Eureka: changed INSERT alternate key from 'a' --> SPACE, and changed the Clear Selection key from SPACE --> END or backquote. ------------------------------------------------------------------------ r863 | ajapted | 2011-11-29 Eureka / Browser: worked on positioning the Flat and Texture pics. ------------------------------------------------------------------------ r862 | ajapted | 2011-11-29 Eureka: made the browser panel a bit wider. ------------------------------------------------------------------------ r861 | ajapted | 2011-11-29 Eureka: upgrade to FLTK 1.3.0 (this is required since the texture browser was overflowing the 16-bit widget coordinates of FLTK 1.1.x). ------------------------------------------------------------------------ r860 | ajapted | 2011-11-29 Eureka / Browser: fixed searching to handle '^' and '$' properly (they are not handled by fl_filename_match). ------------------------------------------------------------------------ r859 | ajapted | 2011-11-29 Eureka: version bump, in honor of progress with the Browser. ------------------------------------------------------------------------ r858 | ajapted | 2011-11-29 Eureka: implemented setting Thing and Sector types via the browser. ------------------------------------------------------------------------ r857 | ajapted | 2011-11-29 Eureka: TODO update. ------------------------------------------------------------------------ r856 | ajapted | 2011-11-29 Eureka / 3D Preview: allow 'b' key to toggle the browser. ------------------------------------------------------------------------ r855 | ajapted | 2011-11-29 Eureka: saving the map now clears MadeChanges, preventing the wrong message about the map having unsaved changes when going to quit. ------------------------------------------------------------------------ r854 | ajapted | 2011-11-29 Eureka: re-implemented a swap-flats command for sectors, bound to 'w' key. ------------------------------------------------------------------------ r853 | ajapted | 2011-11-28 Eureka: TODO updated. ------------------------------------------------------------------------ r852 | ajapted | 2011-11-28 Eureka / Browser: can now change Linedef types via the browser! ------------------------------------------------------------------------ r851 | ajapted | 2011-11-28 Eureka: ensure a new object (added with 'a' / INS) gets selected. ------------------------------------------------------------------------ r850 | ajapted | 2011-11-28 Eureka / Browser: clear search string when mode changes due to a new edit mode. ------------------------------------------------------------------------ r849 | ajapted | 2011-11-28 Eureka / Browser: make each browser item into a button. ------------------------------------------------------------------------ r848 | ajapted | 2011-11-28 Eureka: renamed methods: SetMode() --> NewEditMode() ------------------------------------------------------------------------ r847 | ajapted | 2011-11-28 Eureka / Browser: change the browser mode (Textures / Flats / Things) when the edit mode changes to LineDefs / Sectors / Things bzw. ------------------------------------------------------------------------ r846 | ajapted | 2011-11-28 Eureka / Browser: worked on support for Textures and Flats. Only the names are being shown so far.... ------------------------------------------------------------------------ r845 | ajapted | 2011-11-28 Eureka / Browser: clear search box when changing Mode. ------------------------------------------------------------------------ r844 | ajapted | 2011-11-28 Eureka / Browser: implemented the search function. ------------------------------------------------------------------------ r843 | ajapted | 2011-11-28 Eureka / Doom2 config: tweaked some descriptions, especially the zero linedef type and sector type. ------------------------------------------------------------------------ r842 | ajapted | 2011-11-28 Eureka / Browser: fixed missing end() from Browser_Item constructor, and for search box update the list whenever it changes. ------------------------------------------------------------------------ r841 | ajapted | 2011-11-28 Eureka / Browser: use to callback to update the list when the mode, category or search box changes. ------------------------------------------------------------------------ r840 | ajapted | 2011-11-28 Eureka / Browser: code to populate the list with ThingTypes, LineTypes and SectorTypes. ------------------------------------------------------------------------ r839 | ajapted | 2011-11-28 Eureka / Browser: began work to populate the browser with useful stuff like line_types and thing_types. ------------------------------------------------------------------------ r838 | ajapted | 2011-11-28 Eureka: comment tweak. ------------------------------------------------------------------------ r837 | ajapted | 2011-11-28 Eureka: tweaked gap at bottom of side panel + right end of menu bar. ------------------------------------------------------------------------ r836 | ajapted | 2011-11-28 Eureka / Browser: dead code removal. ------------------------------------------------------------------------ r835 | ajapted | 2011-11-28 Eureka: worked on Browser widget, use Fl_Scroll for the scrolling list. ------------------------------------------------------------------------ r834 | ajapted | 2011-11-28 Eureka: more work to fix Browser size when resizing. ------------------------------------------------------------------------ r833 | ajapted | 2011-11-27 Eureka: needed to call init_sizes() in window's ShowBrowser() method since the widgets got rearranged. ------------------------------------------------------------------------ r832 | ajapted | 2011-11-27 Eureka / README: minor fix. ------------------------------------------------------------------------ r831 | ajapted | 2011-11-27 Eureka / Makefile: fixed 'make clean' target. ------------------------------------------------------------------------ r830 | ajapted | 2011-11-27 Eureka: document tweaks. ------------------------------------------------------------------------ r829 | ajapted | 2011-11-27 Eureka: TODO update. ------------------------------------------------------------------------ r828 | ajapted | 2011-11-27 Eureka: make sure all quit methods (ESCAPE key, File menu, window close button) work the same way, and ask for confirmation if the map has been modified. ------------------------------------------------------------------------ r827 | ajapted | 2011-11-27 Eureka: fixed the current map name (right side of infobar). ------------------------------------------------------------------------ r826 | ajapted | 2011-11-27 Eureka: fixed the infobar "lock" widget to update the editor state (i.e. grid.snap and grid.locked) when changed. ------------------------------------------------------------------------ r825 | ajapted | 2011-11-27 Eureka / README: note requirement of doom2.wad, various tweaks. ------------------------------------------------------------------------ r824 | ajapted | 2011-11-27 Eureka / README: added copyright / license section. ------------------------------------------------------------------------ r823 | ajapted | 2011-11-27 Eureka / README: more work, new "RUNNING" section etc... ------------------------------------------------------------------------ r822 | ajapted | 2011-11-27 Eureka: moved keyboard command list from FEATURES.txt --> README.txt and added some extra ones (especially for 3D preview). ------------------------------------------------------------------------ r821 | ajapted | 2011-11-27 Eureka: began work on a basic README.txt document. ------------------------------------------------------------------------ r820 | ajapted | 2011-11-27 Eureka: added basic INSTALL.txt document. ------------------------------------------------------------------------ r819 | ajapted | 2011-11-27 Eureka: code formatting tweak. ------------------------------------------------------------------------ r818 | ajapted | 2011-11-27 Eureka: minor tweak ------------------------------------------------------------------------ r817 | ajapted | 2011-11-27 Eureka: version bump. ------------------------------------------------------------------------ r816 | ajapted | 2011-11-27 TODO / WISHLIST twiddling.... ------------------------------------------------------------------------ r815 | ajapted | 2011-11-27 Eureka: fixed wrong values with light "-" button (in Sector panel). ------------------------------------------------------------------------ r814 | ajapted | 2011-11-27 Eureka / Render3D: implemented low-detail mode (toggle via F5 key). ------------------------------------------------------------------------ r813 | ajapted | 2011-11-27 Eureka / Render3D: implemented a "lo-res" mode. ------------------------------------------------------------------------ r812 | ajapted | 2011-11-27 Eureka: added 'lib_linux' folder. ------------------------------------------------------------------------ r811 | ajapted | 2011-11-27 Eureka: moved MEMORY.txt document --> attic/ ------------------------------------------------------------------------ r810 | ajapted | 2011-11-27 Eureka: added 'attic' folder. ------------------------------------------------------------------------ r809 | ajapted | 2011-11-27 Eureka / Makefile: fixed location of exe. ------------------------------------------------------------------------ r808 | ajapted | 2011-11-27 Eureka / Makefile: updated for top-level and obj_linux folder. ------------------------------------------------------------------------ r807 | ajapted | 2011-11-27 Eureka: added 'obj_linux' folder for the build process. ------------------------------------------------------------------------ r806 | ajapted | 2011-11-27 Eureka: TODO update. ------------------------------------------------------------------------ r805 | ajapted | 2011-11-27 Eureka: moved Makefile to top level. ------------------------------------------------------------------------ r804 | ajapted | 2011-11-27 Eureka / Render3D: enable 'lighting' by default. ------------------------------------------------------------------------ r803 | ajapted | 2011-11-27 Eureka / Render3D: support for aspect-ratio correction. ------------------------------------------------------------------------ r802 | ajapted | 2011-11-27 Eureka / Render3D: tweaked mouse scrolling (future option to allow both angular and Z movement at same time). ------------------------------------------------------------------------ r801 | ajapted | 2011-11-27 Eureka: fixed 3D preview to handle resizing the main window. ------------------------------------------------------------------------ r800 | ajapted | 2011-11-27 Eureka: draw "knobby" linedefs (only in LineDef and Vertex mode). ------------------------------------------------------------------------ r799 | ajapted | 2011-11-26 Eureka: fixed vertical stretching of info panels (Things etc) when resizing the main window. ------------------------------------------------------------------------ r543 | ajapted | 2010-09-24 MEMORY doc: changed COPY_GROUP to a more general 'GROUP' object, and renamed EDIT_GROUP --> EDIT_SET. ------------------------------------------------------------------------ r542 | ajapted | 2010-09-24 MEMORY doc: described the edit operations, added STRING objects. ------------------------------------------------------------------------ r541 | ajapted | 2010-09-24 MEMORY document: added lots more detail. ------------------------------------------------------------------------ r540 | ajapted | 2010-09-24 Added MEMORY.txt : document the memory model for map objects. ------------------------------------------------------------------------ r539 | ajapted | 2010-09-24 Makefile: library folder is now 'lib_linux' ------------------------------------------------------------------------ r538 | ajapted | 2010-09-24 FIXED (thank dog!) the ESCAPE key quitting unconditionally. ------------------------------------------------------------------------ r528 | ajapted | 2010-05-16 tweak ------------------------------------------------------------------------ r449 | ajapted | 2009-12-02 Eureka: temporary hack (level loading stuff). ------------------------------------------------------------------------ r448 | ajapted | 2009-12-02 Use FLTK 1.1.10 ------------------------------------------------------------------------ r445 | ajapted | 2009-11-09 Eureka: implemented showing and hiding the Browser panel (via 'b' key). ------------------------------------------------------------------------ r444 | ajapted | 2009-11-09 Eureka: bit more work on Browser stuff. ------------------------------------------------------------------------ r443 | ajapted | 2009-11-09 Eureka: worked on the UI_Browser widget, the top section now has a choice button for the current type (Textures, Flats, etc), plus a choice button for the current group (useful for things), plus a search field, and lastly a check button on whether to show images or not. [PROTOTYPE ONLY] ------------------------------------------------------------------------ r442 | ajapted | 2009-11-08 Eureka: renamed UI_FlatTexList --> UI_Browser (et cetera). ------------------------------------------------------------------------ r441 | ajapted | 2009-11-08 Eureka: renamed code files: ui_flattex --> ui_browser ------------------------------------------------------------------------ r440 | ajapted | 2009-11-08 TODO update. ------------------------------------------------------------------------ r439 | ajapted | 2009-11-08 Eureka: draw an selected AND highlighted object in a different color, and changed the selection color to a sky-blue. ------------------------------------------------------------------------ r438 | ajapted | 2009-11-08 Eureka: implemented mirror commands for the Edit menu. ------------------------------------------------------------------------ r437 | ajapted | 2009-11-08 Eureka: fixed Paste from the menu to place new items at centre of canvas. ------------------------------------------------------------------------ r436 | ajapted | 2009-11-08 noted a bug. ------------------------------------------------------------------------ r435 | ajapted | 2009-11-08 Eureka: implemented key to Flip linedefs. ------------------------------------------------------------------------ r434 | ajapted | 2009-11-08 todo tweakage. ------------------------------------------------------------------------ r433 | ajapted | 2009-11-08 Eureka: improved FindIslands() code to handle when the initial path is itself an island, whereby it reaches out to the outer area. ------------------------------------------------------------------------ r432 | ajapted | 2009-11-08 Eureka: finding islands: fixed a bug (erroneous check on sidedefs). ------------------------------------------------------------------------ r431 | ajapted | 2009-11-08 Eureka: FindIslands() : recompute bbox on each call (it can change when islands reach out to other geometry). ------------------------------------------------------------------------ r430 | ajapted | 2009-11-08 Eureka: further work on finding islands... ------------------------------------------------------------------------ r429 | ajapted | 2009-11-08 Eureka: fixed logic in OppositeLineDef() : result_side was wrong. ------------------------------------------------------------------------ r428 | ajapted | 2009-11-07 Eureka: preliminary work on Island-finding algorithm (for sector insertion). ------------------------------------------------------------------------ r427 | ajapted | 2009-11-07 Eureka: decreases the mapslack for highlighting a vertex, making it less likely to accidentally join the wrong vertex while inserting lines (etc). ------------------------------------------------------------------------ r426 | ajapted | 2009-11-07 Eureka: fixed problem with "ugly" 45-degree lines, caused by width = 1 parameter in fl_line_style(). Using width = 0 produces nicer results. ------------------------------------------------------------------------ r425 | ajapted | 2009-11-07 Eureka: fixed bug with wrong initial grid step in the InfoBar. ------------------------------------------------------------------------ r424 | ajapted | 2009-11-07 Eureka: properly update the side panel after map changes. ------------------------------------------------------------------------ r423 | ajapted | 2009-11-07 Eureka: made sure linedefs inserted in vertex mode have Impassible flag. ------------------------------------------------------------------------ r422 | ajapted | 2009-11-07 Eureka: fixed re-selection after inserting a sector (into a space). ------------------------------------------------------------------------ r421 | ajapted | 2009-11-07 reformatted code. ------------------------------------------------------------------------ r420 | ajapted | 2009-11-07 Eureka: when inserting a sector, fixup linedefs which become 2-sided (add 2S flag, clear impassible flag, make middle texture "-"). ------------------------------------------------------------------------ r419 | ajapted | 2009-11-07 Eureka: version bumped to 0.61 ------------------------------------------------------------------------ r418 | ajapted | 2009-11-07 Eureka: try harder to find a usable texture when linedef becomes one-sided (check the to-be-removed sidedef too). ------------------------------------------------------------------------ r417 | ajapted | 2009-11-07 Eureka: for sector deletions, make sure to fix-up any linedefs which become one-sided (update 2S and impassible flag, middle texture, and flip if needed). ------------------------------------------------------------------------ r416 | ajapted | 2009-11-07 Eureka: e_cutpaste.cc : added new DoRemoveSideFromLine() function, and moved all the CMD_Delete() code to the bottom of the file. ------------------------------------------------------------------------ r415 | ajapted | 2009-11-07 Eureka: made SHIFT + DELETE keep any unused bits (vertices etc). ------------------------------------------------------------------------ r414 | ajapted | 2009-11-07 Eureka: pass keymod_e to EditorKey() and similar functions. ------------------------------------------------------------------------ r413 | ajapted | 2009-11-07 Eureka: when deleting sectors, find and delete Linedefs which would be unused afterwards -- and in turn unused vertices and sidedefs. ------------------------------------------------------------------------ r412 | ajapted | 2009-11-07 Eureka: remove unused sidedefs when deleting linedefs (same logic as for vertices). ------------------------------------------------------------------------ r411 | ajapted | 2009-11-07 Eureka: reworked code to delete unused vertices when deleting linedefs. ------------------------------------------------------------------------ r410 | ajapted | 2009-11-07 Eureka: BASIS: no longer delete a linedef when it ends up with no sides, that was too heavy handed (such linedefs are not valid for DOOM engines but is allowed inside the editor). ------------------------------------------------------------------------ r409 | ajapted | 2009-11-07 Eureka: worked on making deletion of linedefs and sectors also remove any vertices and/or sidedefs which would end up unused after deletion. Also merged CMD_Delete() and CMD_FullDelete() into one function. ------------------------------------------------------------------------ r408 | ajapted | 2009-11-07 Eureka: ConvertSelection() now handles LINES->SIDES and SECTORS->SIDES. ------------------------------------------------------------------------ r407 | ajapted | 2009-11-07 Eureka: added new selection_c::unmerge() and intersect() methods. ------------------------------------------------------------------------ r406 | ajapted | 2009-11-06 TODO twiddling. ------------------------------------------------------------------------ r405 | ajapted | 2009-11-06 tweaks ------------------------------------------------------------------------ r404 | ajapted | 2009-11-06 Eureka: improved vertex insertion to merely add a linedef when two vertices are selected (or one selected and one highlighted). ------------------------------------------------------------------------ r403 | ajapted | 2009-11-06 Eureka: added 'find_first' and 'find_second' methods to selection_c class. ------------------------------------------------------------------------ r402 | ajapted | 2009-11-06 Eureka: made the HOME key centre-and-zoom-out the map (instead of '0'). ------------------------------------------------------------------------ r401 | ajapted | 2009-11-06 Eureka: the 'a' key is now equivalent to INSERT key (was 'i' before). ------------------------------------------------------------------------ r400 | ajapted | 2009-11-06 Eureka: bit more work on Sector insertions. ------------------------------------------------------------------------ r399 | ajapted | 2009-11-05 todo update. ------------------------------------------------------------------------ r398 | ajapted | 2009-11-05 Eureka: tweaked the key-binding list (FEATURES.txt) ------------------------------------------------------------------------ r397 | ajapted | 2009-11-05 Eureka: fixed some bugs in the AssignSectorToSpace() code. ------------------------------------------------------------------------ r396 | ajapted | 2009-11-05 Eureka: implemented DoAssignSector() function, for sector insertion code. ------------------------------------------------------------------------ r395 | ajapted | 2009-11-05 Eureka: worked on fixing the code which traces a closed path of linedefs to determine where to place a new (or existing) sector reference. ------------------------------------------------------------------------ r394 | ajapted | 2009-11-05 tweaks. ------------------------------------------------------------------------ r393 | ajapted | 2009-11-05 Eureka: initial code for new OppositeLineDef() function. ------------------------------------------------------------------------ r392 | ajapted | 2009-11-05 Eureka: use new PointOutsideOfMap() check for creating a square when inserting in Sector mode. ------------------------------------------------------------------------ r391 | ajapted | 2009-11-05 dead code removal. ------------------------------------------------------------------------ r390 | ajapted | 2009-11-05 Eureka: x_hover: added PointOutsideOfMap() utility function, and updated the header file with the other new functions. ------------------------------------------------------------------------ r389 | ajapted | 2009-11-05 Eureka: improved get_cur_sector() logic by casting both vertical and horizontal rays to find the closest linedef. ------------------------------------------------------------------------ r388 | ajapted | 2009-11-05 Eureka: fixed bugs in ClosestLine_CastingVerty() function. ------------------------------------------------------------------------ r387 | ajapted | 2009-11-05 Eureka: improved the ClosestLine_CastingXXX functions to (a) check both casting directions, e.g. right AND left, and (b) return which side the test point is on (1, 0, -1). ------------------------------------------------------------------------ r386 | ajapted | 2009-11-05 Eureka: x_hover.cc: separated code into new ClosestLineDef_CastingRight() function, and added new ClosestLineDef_CastingUp() function. ------------------------------------------------------------------------ r385 | ajapted | 2009-11-05 Eureka: renamed map bounds global vars again: MapBound_[lh][xy] ------------------------------------------------------------------------ r384 | ajapted | 2009-11-05 code tidying. ------------------------------------------------------------------------ r383 | ajapted | 2009-11-05 Eureka: no need to invalidate the Selection when the inserted or deleted object is above the max_obj(). ------------------------------------------------------------------------ r382 | ajapted | 2009-11-05 Eureka: added fast max_obj() method to selection_c class, and renamed the slow_count() method --> count_obj(). ------------------------------------------------------------------------ r381 | ajapted | 2009-11-05 Eureka: further work on adjusting move/scroll speeds based on whether SHIFT or CTRL keys are pressed. ------------------------------------------------------------------------ r380 | ajapted | 2009-11-04 Eureka render mode: more control over speed of forward/back/strafe keys (CTRL faster, SHIFT slower). Changed fly up/down keys to PGUP and PGDN. Renamed key_mod_e --> keymod_e ------------------------------------------------------------------------ r379 | ajapted | 2009-11-04 Eureka: for 3D preview, made SHIFT and CTRL control the speed of moving forward/backwards when using the mousewheel. ------------------------------------------------------------------------ r378 | ajapted | 2009-11-04 Eureka: added key_mod_e enumeration (KM_SHIFT, KM_CTRL etc). ------------------------------------------------------------------------ r377 | ajapted | 2009-11-04 Eureka: created new WISHLIST.txt document. ------------------------------------------------------------------------ r376 | ajapted | 2009-11-04 TODO update. ------------------------------------------------------------------------ r375 | ajapted | 2009-11-04 Eureka: made sane the usage of h1 and h2 fields of DrawSurf. ------------------------------------------------------------------------ r374 | ajapted | 2009-11-04 Eureka renderer: fixed y_offset for Mid-Masked textures, YAY! ------------------------------------------------------------------------ r373 | ajapted | 2009-11-04 Eureka: ignore self-referenced lines in 3D renderer. ------------------------------------------------------------------------ r372 | ajapted | 2009-11-04 Eureka: much better mid-masked textures in 3D preview. ------------------------------------------------------------------------ r371 | ajapted | 2009-11-04 reformatted some code. ------------------------------------------------------------------------ r370 | ajapted | 2009-11-04 Eureka: preliminary work on rendering mid-masked textures... ------------------------------------------------------------------------ r369 | ajapted | 2009-11-04 Eureka: worked on improving the x_hover.cc code. ------------------------------------------------------------------------ r368 | ajapted | 2009-11-04 Eureka: disabled experimental new 'get_cur_sector', which did not work properly in several situations (cf MAP02 of TNT). ------------------------------------------------------------------------ r367 | ajapted | 2009-11-04 Eureka: renamed DistanceToLineDef() --> ApproxDistToLineDef(). ------------------------------------------------------------------------ r366 | ajapted | 2009-11-04 Eureka: experimental new way to determine current sector at a point. ------------------------------------------------------------------------ r365 | ajapted | 2009-11-04 Eureka: removed unused utility function. ------------------------------------------------------------------------ r364 | ajapted | 2009-11-04 dead code removal. ------------------------------------------------------------------------ r363 | ajapted | 2009-11-04 Eureka: implemented a DistanceToLineDef() function. Did some tidying in x_hover.cc ------------------------------------------------------------------------ r362 | ajapted | 2009-11-04 Eureka: moved some code in x_hover.cc ------------------------------------------------------------------------ r361 | ajapted | 2009-11-04 Eureka: make sure the Total value in each side panel is kept up-to-date. ------------------------------------------------------------------------ r360 | ajapted | 2009-11-04 Eureka: fixed input widgets on the side panels so that the ENTER key does not jump to another widget, instead staying in that input widget. ------------------------------------------------------------------------ r359 | ajapted | 2009-11-04 Eureka: added list of needed Config items to the TODO. ------------------------------------------------------------------------ r358 | ajapted | 2009-11-04 Eureka: prevent ENTER key doing the 'Unselect All' command. ------------------------------------------------------------------------ r357 | ajapted | 2009-11-04 Eureka: tweaked speed of mouse-wheel forward/back in 3D preview. ------------------------------------------------------------------------ r356 | ajapted | 2009-11-04 Eureka: fixed (Un)select-All commands to update the side panel. ------------------------------------------------------------------------ r355 | ajapted | 2009-11-03 Eureka: show more info (strerror) in LOG.txt when a pwad cannot be opened. ------------------------------------------------------------------------ r354 | ajapted | 2009-11-03 tweak. ------------------------------------------------------------------------ r353 | ajapted | 2009-11-03 Eureka: fixed loading maps with lowercase texture or flat names in the sidedefs or sectors -- they are silently converted to uppercase. ------------------------------------------------------------------------ r352 | ajapted | 2009-11-03 Eureka: support ON_CEILING things in the 3D preview. ------------------------------------------------------------------------ r351 | ajapted | 2009-11-03 Eureka: doom2 game config: lit up the keys and armor vests (added 'l' flag). ------------------------------------------------------------------------ r350 | ajapted | 2009-11-03 Eureka: draw Invis and Lit things properly in the 3D preview. ------------------------------------------------------------------------ r349 | ajapted | 2009-11-03 Eureka: game config: parse new 'l' and 'c' flags for things ('l' for Lit things, 'c' for Ceiling things), and changed 's' --> 'i' (Invis). ------------------------------------------------------------------------ r348 | ajapted | 2009-11-03 Eureka: updated game file (doom2.ugh), giving lit objects the 'l' flags and on-ceiling objects the 'c' flag, and changed 's' flag --> 'i'. Also separated out the EDGE specific things. ------------------------------------------------------------------------ r347 | ajapted | 2009-11-03 Eureka: handle mouse motion/clicks better when the 3D preview is shown. ------------------------------------------------------------------------ r346 | ajapted | 2009-11-03 todo stuff ------------------------------------------------------------------------ r345 | ajapted | 2009-11-03 Eureka: renderer: better code to keep track of what sectors each thing is in, recalculating when the number of things or sectors change, or by the user pressing CTRL-L. ------------------------------------------------------------------------ r344 | ajapted | 2009-11-03 Eureka: can now bump gamma with F11 key (in 3D render view). ------------------------------------------------------------------------ r343 | ajapted | 2009-11-03 minor code reformatting. ------------------------------------------------------------------------ r342 | ajapted | 2009-11-03 Eureka: implemented renderer effect where N/S walls are brighter and E/W walls are darker than normal. ------------------------------------------------------------------------ r341 | ajapted | 2009-11-03 Eureka: r_render.cc: misc tidying, replaced fucking 0 with NULL, etc.. ------------------------------------------------------------------------ r340 | ajapted | 2009-11-02 todo tweak ------------------------------------------------------------------------ r339 | ajapted | 2009-11-02 Eureka: support for Lighting in the 3D preview. ------------------------------------------------------------------------ r338 | ajapted | 2009-11-02 Eureka: added code to load the COLORMAP lump. ------------------------------------------------------------------------ r337 | ajapted | 2009-11-02 Eureka: more reformatting in r_render.cc ------------------------------------------------------------------------ r336 | ajapted | 2009-11-02 Eureka: reformatted the code in r_render.cc ------------------------------------------------------------------------ r335 | ajapted | 2009-11-02 Eureka: added useful mode for Vertex/LineDef inserting: if _one_ vertex is selected, then insert a new one, add a joining linedef, and re-select the new vertex. Also split thing, sector creation into separate funcs. ------------------------------------------------------------------------ r334 | ajapted | 2009-11-02 Eureka: added bare-bones code to create a new square-shape sector. ------------------------------------------------------------------------ r333 | ajapted | 2009-11-02 Eureka: renamed variables: MapMinX/Y, MapMaxX/Y --> Map_lx/y, Map_hx/y. ------------------------------------------------------------------------ r332 | ajapted | 2009-11-02 Eureka: debugging code to draw the level's Bounding box. ------------------------------------------------------------------------ r331 | ajapted | 2009-11-02 Eureka: implemented code (via MapStuff_NotifyXXX functions) to keep the level bounds (MapMinX/Y and MapMaxX/Y globals) up-to-date. ------------------------------------------------------------------------ r330 | ajapted | 2009-11-02 Eureka: fixed Pasted objects to be selected (this broke due to recent work on basis notifications). ------------------------------------------------------------------------ r329 | ajapted | 2009-11-02 Eureka: free textures at exit. ------------------------------------------------------------------------ r328 | ajapted | 2009-11-02 Eureka: fixed finding player for renderer when level has Voodoo dolls. ------------------------------------------------------------------------ r327 | ajapted | 2009-11-02 Eureka: fixed bugs in bitvec_c and selection_c classes. ------------------------------------------------------------------------ r326 | ajapted | 2009-11-02 Eureka: fixed memory leak in bitvec_c::resize() code. ------------------------------------------------------------------------ r325 | ajapted | 2009-11-02 Eureka: updated CMD_SelectAll() for recent selection_c changes. ------------------------------------------------------------------------ r324 | ajapted | 2009-11-02 Eureka: implemented new bitvec_c::resize() method. ------------------------------------------------------------------------ r323 | ajapted | 2009-11-02 Eureka: selection_c class: make the bitvector grow as needed, instead of relying on NumObjects() which changes all the time. ------------------------------------------------------------------------ r322 | ajapted | 2009-11-01 TODO update. ------------------------------------------------------------------------ r321 | ajapted | 2009-11-01 Eureka: beginnings of the code for ObjectBox_NotifyXXX() functions. ------------------------------------------------------------------------ r320 | ajapted | 2009-11-01 Eureka: fixed assertion error due to recent changes. ------------------------------------------------------------------------ r319 | ajapted | 2009-11-01 Eureka: dead code removal (all the 'changed_a_xxxx' variables etc). ------------------------------------------------------------------------ r318 | ajapted | 2009-11-01 Eureka: implemented XXX_Notify() functions for the current Selection. ------------------------------------------------------------------------ r317 | ajapted | 2009-11-01 Eureka: call XXX_NotifyBegin() and XXX_NotifyEnd() functions from the Basis. ------------------------------------------------------------------------ r316 | ajapted | 2009-11-01 Eureka: more work on new BASIS notification framework (Clipboard bits). ------------------------------------------------------------------------ r315 | ajapted | 2009-11-01 Eureka: BASIS: partial work on new way of notifying other code about changes/insertions/deletions of map structures. ------------------------------------------------------------------------ r314 | ajapted | 2009-11-01 Eureka: tweaked turning rate when using RMB. ------------------------------------------------------------------------ r313 | ajapted | 2009-11-01 Eureka: added NumObjects() utility function to the Basis. ------------------------------------------------------------------------ r312 | ajapted | 2009-11-01 Eureka: implemented the 'Select All' command (in edit menu). ------------------------------------------------------------------------ r311 | ajapted | 2009-11-01 Eureka: fixed a bug in selection_c::ConvertToBitvec(). ------------------------------------------------------------------------ r310 | ajapted | 2009-11-01 Eureka: fixed bug using wrong NumXXX values in UI_ThingBox and UI_VertexBox. ------------------------------------------------------------------------ r309 | ajapted | 2009-11-01 todo tweak ------------------------------------------------------------------------ r308 | ajapted | 2009-11-01 Eureka: bit more work on having map changes updated all the widgets (etc). ------------------------------------------------------------------------ r307 | ajapted | 2009-11-01 Eureka: BASIS: new 'appended_an_object' variable. ------------------------------------------------------------------------ r306 | ajapted | 2009-10-31 Eureka: worked on a system (in the Basis) of remembering various types of changes, so that various widgets (e.g. the canvas) can be updated with new information automatically. ------------------------------------------------------------------------ r305 | ajapted | 2009-10-31 Eureka: can now turn and move up/down in the 3D preview with the mouse (RMB). ------------------------------------------------------------------------ r304 | ajapted | 2009-10-31 Eureka: UI_Nombre: improved the format (e.g. use '#' before the number). ------------------------------------------------------------------------ r303 | ajapted | 2009-10-31 Eureka: disabled the thing 'ExFloor' widget for now (punted feature). ------------------------------------------------------------------------ r302 | ajapted | 2009-10-31 Eureka: made '0' key be centre-and-zoom-out function, and disabled the plain centre-map feature (on '`' key) as it seems not very useful. ------------------------------------------------------------------------ r301 | ajapted | 2009-10-31 Eureka: implemented ability to scroll the map with the mouse (RMB). ------------------------------------------------------------------------ r300 | ajapted | 2009-10-30 Eureka: fixed X-Offsets when splitting linedefs. ------------------------------------------------------------------------ r299 | ajapted | 2009-10-30 Eureka: re-implemented 'x' command to Split linedefs. ------------------------------------------------------------------------ r298 | ajapted | 2009-10-30 todo / docco update. ------------------------------------------------------------------------ r297 | ajapted | 2009-10-30 Eureka: the code trying to "fix" bad quantization didn't work and was very inadequate. Disabled for now, until better algorithms can be employed. ------------------------------------------------------------------------ r296 | ajapted | 2009-10-30 Eureka: worked on command to Quantize objects to the grid. ------------------------------------------------------------------------ r295 | ajapted | 2009-10-30 Eureka: added grid::ForceSnapX/Y methods. ------------------------------------------------------------------------ r294 | ajapted | 2009-10-30 Eureka: for 2x scaling, use the bottom left corner of the bbox as the scaling origin, which is better at preserving grid snappage. ------------------------------------------------------------------------ r293 | ajapted | 2009-10-30 Eureka: implemented CMD_ScaleObjects() for 2x and 1/2 scaling. ------------------------------------------------------------------------ r292 | ajapted | 2009-10-30 Eureka: dead code removal (old flip_mirror stuff). ------------------------------------------------------------------------ r291 | ajapted | 2009-10-30 Eureka: implemented the Rotate-by-90-degrees commands. ------------------------------------------------------------------------ r290 | ajapted | 2009-10-30 Eureka: changed mirror keys to 'H' and 'I'. ------------------------------------------------------------------------ r289 | ajapted | 2009-10-30 Eureka: implemented Mirror command (horizontal and vertical). ------------------------------------------------------------------------ r288 | ajapted | 2009-10-30 Eureka: began work on commands to Mirror and Rotate90 objects. ------------------------------------------------------------------------ r287 | ajapted | 2009-10-30 Eureka: improved bbox_of_objects() to use the known radius of things. ------------------------------------------------------------------------ r286 | ajapted | 2009-10-30 Eureka: implemented new bbox_of_objects() function. ------------------------------------------------------------------------ r285 | ajapted | 2009-10-30 Eureka: re-implemented the centre_of_objects() function. ------------------------------------------------------------------------ r284 | ajapted | 2009-10-30 todo stuff. ------------------------------------------------------------------------ r283 | ajapted | 2009-10-30 commenting. ------------------------------------------------------------------------ r282 | ajapted | 2009-10-30 Eureka: implemented re-selected new objects after a Paste. ------------------------------------------------------------------------ r281 | ajapted | 2009-10-30 Eureka: added frob_range() method to selection_c class. ------------------------------------------------------------------------ r280 | ajapted | 2009-10-29 todo twiddle. ------------------------------------------------------------------------ r279 | ajapted | 2009-10-29 Eureka: began creating a list of keyboard commands. ------------------------------------------------------------------------ r278 | ajapted | 2009-10-29 todo twiddle. ------------------------------------------------------------------------ r277 | ajapted | 2009-10-29 debugging tidying. ------------------------------------------------------------------------ r276 | ajapted | 2009-10-29 Eureka: when dragging Sectors, drag their containing Things too. ------------------------------------------------------------------------ r275 | ajapted | 2009-10-29 Eureka: Dragging: actually move the objects after the drag. ------------------------------------------------------------------------ r274 | ajapted | 2009-10-29 Eureka: disable texture listbox for time being. ------------------------------------------------------------------------ r273 | ajapted | 2009-10-29 Eureka: worked on Dragging objects to new places. ------------------------------------------------------------------------ r272 | ajapted | 2009-10-29 Eureka: use 'obj_type_t' instead of 'int' for GetCurObject() parameter. ------------------------------------------------------------------------ r271 | ajapted | 2009-10-29 Eureka: use '0' key instead of '`' for zoom-and-centre-map function. ------------------------------------------------------------------------ r270 | ajapted | 2009-10-29 Eureka: removed unused variable: rulers. ------------------------------------------------------------------------ r269 | ajapted | 2009-10-29 Eureka: restored spin-thing keys to 'w' and 'x'. ------------------------------------------------------------------------ r268 | ajapted | 2009-10-29 Eureka: made clipboard handle sector Insertions like it handles deletions, allowing the copied objects to survive longer (e.g. after undo). ------------------------------------------------------------------------ r267 | ajapted | 2009-10-29 Eureka: improved the way the clipboard reacts to Sector insertions and deletions. In particular, the clipboard can be preserved after a sector is deleted (by adjusting the references). ------------------------------------------------------------------------ r266 | ajapted | 2009-10-29 Eureka: fixed thing positions when Pasting a copied sector. ------------------------------------------------------------------------ r265 | ajapted | 2009-10-29 debugging tweak. ------------------------------------------------------------------------ r264 | ajapted | 2009-10-29 Eureka: implemented Paste for linedefs and sectors (which involves creating associated objects like vertices and sidedefs, and updating the references). ------------------------------------------------------------------------ r263 | ajapted | 2009-10-29 Eureka: further work on Cut'n'Paste code... ------------------------------------------------------------------------ r262 | ajapted | 2009-10-29 Eureka: implemented logic for Copying a group of linedefs or sectors (and all associated objects) into the clipboard. ------------------------------------------------------------------------ r261 | ajapted | 2009-10-29 Eureka: Basis: no need to invalidate the clipboard when inserting new Sectors at the very end of the array. ------------------------------------------------------------------------ r260 | ajapted | 2009-10-29 Eureka: support for Cut/Paste of vertices and RTS triggers. ------------------------------------------------------------------------ r259 | ajapted | 2009-10-29 Eureka: fixed pasting Things to move them to their new position (and when multiple things are in the clipboard, find their centre). ------------------------------------------------------------------------ r258 | ajapted | 2009-10-29 Eureka: better handling of CTRL + letter keys. ------------------------------------------------------------------------ r257 | ajapted | 2009-10-29 Eureka: rewrote 'o' key command to use CMD_Copy + CMD_Paste. ------------------------------------------------------------------------ r256 | ajapted | 2009-10-29 Eureka: Basis: added RawCopy() methods to each class (Thing, Vertex etc). ------------------------------------------------------------------------ r255 | ajapted | 2009-10-29 Eureka: implemented CMD_Copy and CMD_Paste for THINGS. ------------------------------------------------------------------------ r254 | ajapted | 2009-10-29 Eureka: Basis: notify clipboard when sectors are deleted or inserted. ------------------------------------------------------------------------ r253 | ajapted | 2009-10-29 Eureka: fixed bugs in CMD_FullDelete(). ------------------------------------------------------------------------ r252 | ajapted | 2009-10-29 Eureka: mainly commenting (new Cut'n'Paste code). ------------------------------------------------------------------------ r251 | ajapted | 2009-10-29 Eureka: moved CMD_Delete() code into e_cutpaste.cc file, and implemented the CMD_FullDelete() which deletes things in sector mode. ------------------------------------------------------------------------ r250 | ajapted | 2009-10-28 Eureka: made ConvertSelection() into a general purpose function which converts from one selection_c to another. ------------------------------------------------------------------------ r249 | ajapted | 2009-10-28 Eureka: BA_ClearAll() now clears the Clipboard too. ------------------------------------------------------------------------ r248 | ajapted | 2009-10-28 Eureka: preliminary clipboard_data_c class. ------------------------------------------------------------------------ r247 | ajapted | 2009-10-28 Eureka: updated menu code to use new Cut'n'Paste API. ------------------------------------------------------------------------ r246 | ajapted | 2009-10-28 update ------------------------------------------------------------------------ r245 | ajapted | 2009-10-28 Eureka: began work on Cut 'n' Paste functionality. ------------------------------------------------------------------------ r244 | ajapted | 2009-10-28 Eureka: properly handle mouse leaving the canvas area (e.g. unset the currently highlighted object). ------------------------------------------------------------------------ r243 | ajapted | 2009-10-28 Eureka: force custom FLTK color scheme (default with Xfce looked pretty bad). ------------------------------------------------------------------------ r242 | ajapted | 2009-10-28 Eureka: fixed some warnings from GCC 4.3 ------------------------------------------------------------------------ r241 | ajapted | 2009-10-26 Eureka: bit of work on SuperSectorSelector() code. ------------------------------------------------------------------------ r240 | ajapted | 2009-10-25 Eureka: changed default thing type to 2014 (from 3004). ------------------------------------------------------------------------ r239 | ajapted | 2009-10-25 Eureka: ability to Insert new things. ------------------------------------------------------------------------ r238 | ajapted | 2009-10-25 Eureka: for selection_c::clear() method, added unused but potentially useful "slow" version which maintains the order of selections. ------------------------------------------------------------------------ r237 | ajapted | 2009-10-25 Eureka: ability to insert new vertices. ------------------------------------------------------------------------ r236 | ajapted | 2009-10-25 Eureka: don't push empty undo_group_cs onto the undo stack. ------------------------------------------------------------------------ r235 | ajapted | 2009-10-25 Eureka: began work on ability to insert new objects. ------------------------------------------------------------------------ r234 | ajapted | 2009-10-25 Eureka: small fix. ------------------------------------------------------------------------ r233 | ajapted | 2009-10-25 Eureka: implemented trickiest selection conversions: L->S and V->S. ------------------------------------------------------------------------ r232 | ajapted | 2009-10-25 Eureka: implemented V->L selection conversion. ------------------------------------------------------------------------ r231 | ajapted | 2009-10-25 Eureka: implemented S->L, S->V and L->V selection conversions. ------------------------------------------------------------------------ r230 | ajapted | 2009-10-25 Eureka: moved ConvertSelection() from editloop.cc --> selectn.cc ------------------------------------------------------------------------ r229 | ajapted | 2009-10-25 TODO update ------------------------------------------------------------------------ r228 | ajapted | 2009-10-25 Eureka: implemented selection conversion when going from sector mode to things mode. Made the SPACE key unselect everything. ------------------------------------------------------------------------ r227 | ajapted | 2009-10-25 Eureka: fixed BA_Delete() handling of bound objects, it was sufficient to simply delete them before the main object. Also changed sidedef deletion behavior to delete the _linedef_ if it would end up with no sides at all. ------------------------------------------------------------------------ r226 | ajapted | 2009-10-25 Eureka: changed color of "error" linedefs to bright red (from pink). ------------------------------------------------------------------------ r225 | ajapted | 2009-10-25 Eureka: fixed bug in RawInsertLineDef() -- assertion checked wrong value. ------------------------------------------------------------------------ r224 | ajapted | 2009-10-25 Eureka: fixed BA_Delete() which was trying to delete the wrong bound objects (they needed to be collected before applying the deletion). ------------------------------------------------------------------------ r223 | ajapted | 2009-10-25 Eureka: fix highlighted (Panel'd) object after deletion. ------------------------------------------------------------------------ r222 | ajapted | 2009-10-25 Eureka: move the DeleteFinally() stuff out of the edit_op_c destructor and into a 'Destroy' method which gets called explicitly by the undo_group destructor. This fixes serious problems caused by the destructor being called on temporaries of edit_op_c objects. ------------------------------------------------------------------------ r221 | ajapted | 2009-10-25 Eureka: reimplemented deletion of objects. ------------------------------------------------------------------------ r220 | ajapted | 2009-10-25 TODO tweak ------------------------------------------------------------------------ r219 | ajapted | 2009-10-25 Eureka: disable optimisations for time being (as a debugging aide). ------------------------------------------------------------------------ r218 | ajapted | 2009-10-25 Eureka: fixed problem in Undo/Redo code (clearing the history/future arrays) that lead to assertion failures in subsequent operations. ------------------------------------------------------------------------ r217 | ajapted | 2009-10-25 Eureka: disabled some uncompilable code. ------------------------------------------------------------------------ r216 | ajapted | 2009-10-25 Eureka: TODO twiddles. ------------------------------------------------------------------------ r213 | ajapted | 2009-10-25 Moved 'eureka' folder to top level (out of tools/) ------------------------------------------------------------------------ r212 | ajapted | 2009-10-13 Eureka: version bump. ------------------------------------------------------------------------ r211 | ajapted | 2009-10-13 TODO update. ------------------------------------------------------------------------ r210 | ajapted | 2009-10-13 Eureka: fixed changing mode via the button on the Info Bar. ------------------------------------------------------------------------ r209 | ajapted | 2009-10-13 Eureka: fixed issues with initial editing mode. ------------------------------------------------------------------------ r208 | ajapted | 2009-10-13 Eureka: tweaked deltas for raising/lowering floors and ceilings. ------------------------------------------------------------------------ r207 | ajapted | 2009-10-13 Eureka: implemented typing in texture names in the SideDef panels. ------------------------------------------------------------------------ r206 | ajapted | 2009-10-13 Eureka: implemented x_offset/y_offset input boxes in SideDef panel. ------------------------------------------------------------------------ r205 | ajapted | 2009-10-13 updated TODO ------------------------------------------------------------------------ r204 | ajapted | 2009-10-13 Eureka: implemented sector input box for the SideDef Panel. ------------------------------------------------------------------------ r203 | ajapted | 2009-10-13 Eureka: updated UI_SideBox::TexFromWidget() to internalise the string. ------------------------------------------------------------------------ r202 | ajapted | 2009-10-13 Eureka: got the automap flags in the LineDef panel working. ------------------------------------------------------------------------ r201 | ajapted | 2009-10-13 Eureka: implemented ability in LineDef Panel to change type, tag and most of the flags -- supporting multiple linedefs too. ------------------------------------------------------------------------ r200 | ajapted | 2009-10-13 Eureka: ui_thing.cc: renamed opt_callback_data_c --> thing_opt_CB_data_c ------------------------------------------------------------------------ r199 | ajapted | 2009-10-13 Dead code removal. ------------------------------------------------------------------------ r198 | ajapted | 2009-10-13 tweaks ------------------------------------------------------------------------ r197 | ajapted | 2009-10-13 Eureka: small fixes: made FlatFromWidget() uppercase the name, and fixed GetCurrentObjects() to set the correct object type on the selection_c. ------------------------------------------------------------------------ r196 | ajapted | 2009-10-13 Eureka: implemented typing in texture names in the Sector panel. ------------------------------------------------------------------------ r195 | ajapted | 2009-10-13 Eureka: implemented the 'Type' and 'Tag' input boxes in the Sector panel. ------------------------------------------------------------------------ r194 | ajapted | 2009-10-13 minor fix ------------------------------------------------------------------------ r193 | ajapted | 2009-10-13 Eureka: implemented typing a value into light input box in Sector panel. ------------------------------------------------------------------------ r192 | ajapted | 2009-10-13 Eureka: implemented the light up/down buttons in the Sector panel, via new CMD_AdjustLight() function in e_sector.cc ------------------------------------------------------------------------ r191 | ajapted | 2009-10-13 Eureka: moved CMD_MoveFloors() and CMD_MoveCeilings() into e_sector.cc ------------------------------------------------------------------------ r190 | ajapted | 2009-10-13 Eureka: renamed 'spin_things' function --> 'CMD_SpinThings', and moved some of the logic there (GetCurrentObjects etc), simplifying other code. ------------------------------------------------------------------------ r189 | ajapted | 2009-10-13 Eureka: worked on keys and buttons to move sector floors/ceilings, via new CMD_MoveFloors() and CMD_MoveCeilings() functions. ------------------------------------------------------------------------ r188 | ajapted | 2009-10-13 Eureka: reimplemented the floor_h, ceil_h and headroom input boxes in the Sector Panel (support multiple selected sectors). ------------------------------------------------------------------------ r187 | ajapted | 2009-10-13 fixed small bug ------------------------------------------------------------------------ r186 | ajapted | 2009-10-13 Eureka: fixed CLAMP() macro. ------------------------------------------------------------------------ r185 | ajapted | 2009-10-13 Eureka: reimplemented editing X and Y values in Vertex Panel. ------------------------------------------------------------------------ r184 | ajapted | 2009-10-13 Eureka: Thing Panel: fixed the 'type' input callback (handle multiple things). ------------------------------------------------------------------------ r183 | ajapted | 2009-10-13 Eureka: Thing Panel: separated 'pos_callback' into X and Y versions, so that multiple selected things can work properly. ------------------------------------------------------------------------ r182 | ajapted | 2009-10-13 Eureka: Think Panel: reimplemented option_callback, pass a new structure as the 'data' parameter which contains the needed UI_ThingBox pointer. Also fixed a bug (used F_ANGLE instead of F_OPTIONS). ------------------------------------------------------------------------ r181 | ajapted | 2009-10-13 Eureka: Thing Panel: implemented value propagation for X and Y edits. Changed option_callback() method making the 'data' field a mask value, allowing multiple things to be handled but only the apropos bits are actually changed. ------------------------------------------------------------------------ r180 | ajapted | 2009-10-13 tweak. ------------------------------------------------------------------------ r179 | ajapted | 2009-10-13 Eureka: for angle input in Thing panel, implemented propagating the new value to every thing in the current selection. Simplified handling of the < and > rotation buttons. ------------------------------------------------------------------------ r178 | ajapted | 2009-10-13 Eureka: implemented UI_LineBox::UpdateField() method. ------------------------------------------------------------------------ r177 | ajapted | 2009-10-13 Eureka: implemented UpdateField() method for UI_VertexBox and UI_SectorBox. ------------------------------------------------------------------------ r176 | ajapted | 2009-10-13 Eureka: disabled the KF auto-upsizing stuff for now. ------------------------------------------------------------------------ r175 | ajapted | 2009-10-13 Eureka: update Thing UI panel after spin_things. ------------------------------------------------------------------------ r174 | ajapted | 2009-10-13 Eureka: Thing info widget: added UpdateField() method for when a field is changed externally. Removed some dead code. ------------------------------------------------------------------------ r173 | ajapted | 2009-10-13 Eureka: restored keys for spin_things. ------------------------------------------------------------------------ r172 | ajapted | 2009-10-13 Fixed a few warnings. ------------------------------------------------------------------------ r171 | ajapted | 2009-10-13 Eureka: changed keys to spin things to '[' and ']'. Added a function GetCurrentObjects(), and simplified some code using it. ------------------------------------------------------------------------ r170 | ajapted | 2009-10-13 Eureka: improved handling of the current highlighted object and the current selection (for the UI panel). ------------------------------------------------------------------------ r169 | ajapted | 2009-10-13 Eureka: UI_Canvas: renamed some confusing method names: HighlightObject() --> DrawHighlight() HighlightSelection() --> DrawSelection() ------------------------------------------------------------------------ r168 | ajapted | 2009-10-13 Eureka: fixed UI_Nombre::Update() logic. ------------------------------------------------------------------------ r167 | ajapted | 2009-10-13 Eureka: the UI panel should now show how many objects are selected, with a red background to warn that multiple objects may get changed when editing the values in the panel. ------------------------------------------------------------------------ r166 | ajapted | 2009-10-13 Eureka: added 'slow_count' method to selection_c class. ------------------------------------------------------------------------ r165 | ajapted | 2009-10-13 Eureka: updated UI_Nombre widget to support selections. ------------------------------------------------------------------------ r164 | ajapted | 2009-10-12 Eureka: allow 3D renderer to receive mousewheel events. ------------------------------------------------------------------------ r163 | ajapted | 2009-10-12 Eureka: version bump. ------------------------------------------------------------------------ r162 | ajapted | 2009-10-12 Eureka: TODO update. ------------------------------------------------------------------------ r161 | ajapted | 2009-10-12 Eureka: implemented SelectObjectsInBox() for SECTORS. ------------------------------------------------------------------------ r160 | ajapted | 2009-10-12 Eureka: fixed SelectObjectsInBox() for THINGS, LINEDEFS and VERTICES. ------------------------------------------------------------------------ r159 | ajapted | 2009-10-12 Eureka: fixed key handling so that Ctrl-Z (and other menu shortcuts) work. ------------------------------------------------------------------------ r158 | ajapted | 2009-10-12 Eureka: updated TODO, removed old crud. ------------------------------------------------------------------------ r157 | ajapted | 2009-10-12 Eureka: fixed editing of Thing angles in the UI panel. ------------------------------------------------------------------------ r156 | ajapted | 2009-10-12 Eureka: fixed Undo/Redo to redraw map. ------------------------------------------------------------------------ r155 | ajapted | 2009-10-12 tweak ------------------------------------------------------------------------ r154 | ajapted | 2009-10-12 Eureka: replaced 'MadeChanges = 1' with call to MarkChanges(), and replaced 'MadeMapChanges = 1' with MarkChanges(2) function call. This new function remembers to redraw the map too. ------------------------------------------------------------------------ r153 | ajapted | 2009-10-12 Renamed file: AJA_TODO.txt --> TODO.txt ------------------------------------------------------------------------ r152 | ajapted | 2009-10-12 Eureka: implemented 'spin_things' functionality using the BASIS system. ------------------------------------------------------------------------ r151 | ajapted | 2009-10-12 Eureka: implemented menu commands: 'Save', 'Undo' and 'Redo'. ------------------------------------------------------------------------ r150 | ajapted | 2009-10-12 Eureka: dead code removal. ------------------------------------------------------------------------ r149 | ajapted | 2009-10-12 Eureka: fixed bug in saving code (wrong number of linedefs). ------------------------------------------------------------------------ r148 | ajapted | 2009-10-12 Eureka: fixed Wad_file::RemoveLevel() for GL-Nodes, it should remove the "GL_XXX" lumps after the normal level lumps too. ------------------------------------------------------------------------ r147 | ajapted | 2009-10-12 Eureka: load the specified PWADs. ------------------------------------------------------------------------ r4 | ajapted | 2009-09-07 Checked in sources to my 'Eureka DOOM Editor' program. For a while this was developed in EDGE's SVN repository on SourceForge. Before that is was just developed on my hard drive. Eureka is a fork of the Yadex editor (version 1.7.0). ==================================================== DEVELOPMENT IN EDGE REPOSITORY ==================================================== ------------------------------------------------------------------------ r5940 | ajapted | 2009-09-27 14:53:16 Removed eureka code from EDGE's SVN repository. The code has moved to AwwPort's BZR repository. ------------------------------------------------------------------------ r5919 | ajapted | 2009-08-10 16:23:40 Eureka: temporary disable spin_things(). ------------------------------------------------------------------------ r5811 | ajapted | 2009-08-04 14:33:57 Eureka: tweaked Scale choices on the infobar. ------------------------------------------------------------------------ r5810 | ajapted | 2009-08-04 14:28:40 Eureka: fixed privacy of fields in Lump_c and Wad_file classes. ------------------------------------------------------------------------ r5809 | ajapted | 2009-08-03 23:07:55 Tweak. ------------------------------------------------------------------------ r5808 | ajapted | 2009-08-03 22:58:48 Eureka: removed Wad_name class (w_name.h) ------------------------------------------------------------------------ r5807 | ajapted | 2009-08-03 22:39:28 Eureka: dead code removal. ------------------------------------------------------------------------ r5806 | ajapted | 2009-08-03 22:19:51 Eureka: removed the old wad handling code files: w_wads.cc/h w_io.cc/h w_file.cc/h ------------------------------------------------------------------------ r5805 | ajapted | 2009-08-03 22:01:41 Eureka: yet more dead code removed. ------------------------------------------------------------------------ r5804 | ajapted | 2009-08-03 21:20:37 Eureka: removed old patch_dir code. ------------------------------------------------------------------------ r5803 | ajapted | 2009-08-03 20:38:32 Eureka: dead code removal. ------------------------------------------------------------------------ r5802 | ajapted | 2009-08-03 20:25:44 Tweaks. ------------------------------------------------------------------------ r5801 | ajapted | 2009-08-03 20:24:44 Eureka: enabled new texture loading code. ------------------------------------------------------------------------ r5800 | ajapted | 2009-08-03 19:19:13 Eureka: further work on texture loader... ------------------------------------------------------------------------ r5799 | ajapted | 2009-08-03 19:04:15 Eureka: initial work on new texture loading code... ------------------------------------------------------------------------ r5798 | ajapted | 2009-08-03 17:34:03 Eureka: sprite loader updated to use new LoadPicture() code. ------------------------------------------------------------------------ r5797 | ajapted | 2009-08-03 17:17:40 Eureka: new Wad_file function W_FindSpriteLump() which only checks the valid sprites (S_START..S_END), and similarly W_FindPatchLump() for patches. ------------------------------------------------------------------------ r5796 | ajapted | 2009-08-03 16:44:28 Eureka: worked on new LoadPicture() implementation. ------------------------------------------------------------------------ r5795 | ajapted | 2009-08-03 16:26:06 Eureka: added WAD utility function to load a lump into memory. ------------------------------------------------------------------------ r5794 | ajapted | 2009-08-03 14:44:47 Eureka: began work on a new LoadPicture() implementation. ------------------------------------------------------------------------ r5793 | ajapted | 2009-08-03 14:31:38 Eureka: renamed IMG_TRANSP --> TRANS_PIXEL. ------------------------------------------------------------------------ r5792 | ajapted | 2009-08-03 11:22:03 Eureka: updated W_LoadPalette() to use new Wad_file code. ------------------------------------------------------------------------ r5791 | ajapted | 2009-08-03 11:13:20 Eureka: new flat loading code (W_LoadFlats), replaces old stuff. ------------------------------------------------------------------------ r5790 | ajapted | 2009-08-03 10:18:21 Eureka: dead code removal. ------------------------------------------------------------------------ r5789 | ajapted | 2009-08-03 10:09:34 Eureka: replaced calls to 'get_thing_xxx' with new M_GetThingType(). ------------------------------------------------------------------------ r5788 | ajapted | 2009-08-03 09:55:21 Eureka: added 'color' field to thingtype_t (copied from thinggroup). ------------------------------------------------------------------------ r5787 | ajapted | 2009-08-03 09:46:35 Eureka: worked on using std::map for the game def containters (sector_types, line_types, thing_types etc). ------------------------------------------------------------------------ r5786 | ajapted | 2009-08-02 23:47:30 Tweaks. ------------------------------------------------------------------------ r5785 | ajapted | 2009-08-02 23:35:40 Eureka: reworked code which loads the game palette. ------------------------------------------------------------------------ r5784 | ajapted | 2009-08-02 22:52:11 Tweak. ------------------------------------------------------------------------ r5783 | ajapted | 2009-08-02 22:30:52 Eureka: finished new line descriptions for doom2 game def. ------------------------------------------------------------------------ r5782 | ajapted | 2009-08-02 22:11:55 Eureka: yet more line description improvements (doom2 game def). ------------------------------------------------------------------------ r5781 | ajapted | 2009-08-02 21:24:08 Eureka: further work on line descriptions in doom2 game def. ------------------------------------------------------------------------ r5780 | ajapted | 2009-08-02 20:44:25 Eureka: more work on line descriptions in doom2 game definition. ------------------------------------------------------------------------ r5779 | ajapted | 2009-08-02 20:12:16 Eureka: game definition file: for 'thing' commands, moved the sprite name to occur before the description (instead of after it). More work on updating 'line' commands for a single description. ------------------------------------------------------------------------ r5778 | ajapted | 2009-08-02 19:38:05 Eureka: game definitions: began work to make linetype commands only have a single description (instead of short and long). ------------------------------------------------------------------------ r5777 | ajapted | 2009-08-02 19:20:11 Eureka: game definitions: made 'sector' command only have a single description (instead of short and long). ------------------------------------------------------------------------ r5776 | ajapted | 2009-08-02 19:16:40 Eureka: removed acolour_t. ------------------------------------------------------------------------ r5775 | ajapted | 2009-08-02 18:56:31 Eureka: worked on game definition (.ugh) code, renamed some of the commands e.g. ldt --> line and st --> sector, and moved a couple functions into m_game.cc. ------------------------------------------------------------------------ r5774 | ajapted | 2009-08-02 18:12:54 Eureka: dead code removal. ------------------------------------------------------------------------ r5773 | ajapted | 2009-08-02 17:17:33 Eureka: small fixes. ------------------------------------------------------------------------ r5772 | ajapted | 2009-08-02 17:13:35 Eureka: prelim rework of w_texture code (split now complete). ------------------------------------------------------------------------ r5771 | ajapted | 2009-08-02 17:06:13 Eureka: prelim rework of w_sprite.cc code. ------------------------------------------------------------------------ r5770 | ajapted | 2009-08-02 16:59:19 Eureka: preliminary rework of w_flats code. ------------------------------------------------------------------------ r5769 | ajapted | 2009-08-02 16:49:38 Eureka: continued splitting r_images.cc into three files. ------------------------------------------------------------------------ r5768 | ajapted | 2009-08-02 16:48:15 Eureka: began splitting r_image.cc into three (Textures, Flats and Sprites). ------------------------------------------------------------------------ r5767 | ajapted | 2009-08-02 16:45:33 Eureka: dead code removal. ------------------------------------------------------------------------ r5766 | ajapted | 2009-08-02 15:09:30 Eureka: merged w_sprites.cc code into r_images.cc ------------------------------------------------------------------------ r5765 | ajapted | 2009-08-02 14:42:40 Eureka: misc tidying. ------------------------------------------------------------------------ r5764 | ajapted | 2009-08-02 14:27:02 Small fix. ------------------------------------------------------------------------ r5763 | ajapted | 2009-08-02 14:14:06 Eureka: improved canvas drawing, keep the map bbox in member fields (instead of computing it at multiple places), and use a Vis() method for checking if an item would be visible. ------------------------------------------------------------------------ r5762 | ajapted | 2009-08-02 13:28:49 Eureka: reformatted r_grid.h and removed two unused fields. ------------------------------------------------------------------------ r5761 | ajapted | 2009-08-02 13:21:31 Eureka: small fixes. ------------------------------------------------------------------------ r5760 | ajapted | 2009-08-02 12:50:07 Eureka: added constructors to the basis structures (Thing, LineDef etc). ------------------------------------------------------------------------ r5759 | ajapted | 2009-08-02 12:42:56 Eureka: new FreshLevel() function to create a very basic level. ------------------------------------------------------------------------ r5758 | ajapted | 2009-08-02 12:27:37 Eureka: new level load/save code is mostly done. ------------------------------------------------------------------------ r5757 | ajapted | 2009-08-01 15:50:29 Eureka: Wad_file: changed FindLevel() to return a lump index (instead of a level number), which affects the parameter to FindLumpInLevel() and RemoveLevel() as well. Various code tidying. ------------------------------------------------------------------------ r5756 | ajapted | 2009-08-01 11:56:59 Eureka: implemented remaining functionality of Wad_file class. ------------------------------------------------------------------------ r5755 | ajapted | 2009-07-31 22:46:50 Eureka: more Wad_file goodness... ------------------------------------------------------------------------ r5754 | ajapted | 2009-07-31 22:18:34 Eureka: further work on WAD Writing implementation. Fixed the fopen mode string in Open() to "r+b", and in Create() to "w+b". ------------------------------------------------------------------------ r5753 | ajapted | 2009-07-31 19:25:14 Eureka: tweaked the menu. ------------------------------------------------------------------------ r5752 | ajapted | 2009-07-31 19:17:59 Eureka: partial work on fleshing out the Wad_file "Write interface". ------------------------------------------------------------------------ r5751 | ajapted | 2009-07-31 15:48:29 Eureka: created the "Write interface" for new Wad_file class. ------------------------------------------------------------------------ r5750 | ajapted | 2009-07-31 15:37:00 Eureka: fleshed out most of the new SaveLevel() code. ------------------------------------------------------------------------ r5749 | ajapted | 2009-07-30 23:06:51 Eureka: added skeletal SaveLevel() code. ------------------------------------------------------------------------ r5748 | ajapted | 2009-07-30 22:10:50 Eureka: wrote Wad_file::WasExternallyModified() method. ------------------------------------------------------------------------ r5747 | ajapted | 2009-07-30 21:45:53 Eureka: fixed Wad_file::Create() to set 'total_size' field. ------------------------------------------------------------------------ r5746 | ajapted | 2009-07-30 21:44:28 Eureka: determine total size of WAD when opening it. ------------------------------------------------------------------------ r5745 | ajapted | 2009-07-30 20:48:13 Eureka: dead code removal. ------------------------------------------------------------------------ r5744 | ajapted | 2009-07-30 20:47:25 Eureka: implemented Wad_file::ProcessNamespaces(), which handles the S_START/S_END, P_START/P_END, F_START/F_END groups. ------------------------------------------------------------------------ r5743 | ajapted | 2009-07-30 19:53:38 Eureka: version bump, in honor of new WAD reading code. ------------------------------------------------------------------------ r5742 | ajapted | 2009-07-30 19:51:23 Eureka: implemented Wad_file::DetectLevels(). ------------------------------------------------------------------------ r5741 | ajapted | 2009-07-30 19:25:37 Tweak. ------------------------------------------------------------------------ r5740 | ajapted | 2009-07-30 17:41:35 Eureka: preliminary implementation of Wad_file::ReadDirectory(). ------------------------------------------------------------------------ r5739 | ajapted | 2009-07-30 16:51:59 Eureka: reworked LoadLevel() to use new Wad_file class. ------------------------------------------------------------------------ r5738 | ajapted | 2009-07-30 16:51:02 Eureka: mere reformatting. ------------------------------------------------------------------------ r5737 | ajapted | 2009-07-30 16:43:47 Eureka: added w_wad.o to the build, with minor fixes. ------------------------------------------------------------------------ r5736 | ajapted | 2009-07-30 16:42:37 Eureka: temp workaround for old Wad_file class clashing with new one. ------------------------------------------------------------------------ r5735 | ajapted | 2009-07-30 16:25:09 Eureka: new Wad_file class is coming along. ------------------------------------------------------------------------ r5734 | ajapted | 2009-07-30 15:57:08 Eureka: further work on new Wad_file class. ------------------------------------------------------------------------ r5732 | ajapted | 2009-07-30 14:52:33 Eureka: implemented RemoveUnusedVertices() for level loading. ------------------------------------------------------------------------ r5731 | ajapted | 2009-07-30 14:09:29 Eureka: #include math.h by default (via main.h). ------------------------------------------------------------------------ r5730 | ajapted | 2009-07-30 13:57:38 Eureka: bit more work on new Wad_file class. ------------------------------------------------------------------------ r5729 | ajapted | 2009-07-30 13:41:47 Eureka: added Adler-32 CRC code. ------------------------------------------------------------------------ r5728 | ajapted | 2009-07-30 13:36:27 Eureka: check-in of skeletal new Wad_file class. ------------------------------------------------------------------------ r5727 | ajapted | 2009-07-30 12:26:35 Eureka: more miscellaneous tidying. ------------------------------------------------------------------------ r5726 | ajapted | 2009-07-30 12:02:11 Eureka: replaced nf_bug() with BugError(). ------------------------------------------------------------------------ r5725 | ajapted | 2009-07-30 11:55:25 Eureka: removed sys_assert.cc/h. Began tidying the error/log stuff. ------------------------------------------------------------------------ r5724 | ajapted | 2009-07-29 23:35:22 Eureka: removed xref stuff (pretty useless). ------------------------------------------------------------------------ r5723 | ajapted | 2009-07-29 23:33:26 Eureka: moved some prototypes out of main.h ------------------------------------------------------------------------ r5722 | ajapted | 2009-07-29 23:17:29 Eureka: dead code removal. ------------------------------------------------------------------------ r5721 | ajapted | 2009-07-29 22:55:54 Eureka: more tidying / dead code removal. ------------------------------------------------------------------------ r5720 | ajapted | 2009-07-29 22:19:58 Eureka: fixed clashing definitions between w_rawdef.h and w_structs.h and removed some typedefs. ------------------------------------------------------------------------ r5719 | ajapted | 2009-07-29 22:17:17 Eureka: Dead code removal. ------------------------------------------------------------------------ r5718 | ajapted | 2009-07-29 21:56:54 Eureka: fixed side-panel display of sector flats, sidedef textures. ------------------------------------------------------------------------ r5716 | ajapted | 2009-07-29 18:04:00 Eureka: dead code removal. ------------------------------------------------------------------------ r5715 | ajapted | 2009-07-29 16:33:54 Eureka: renamed file: e_load.cc --> e_loadsave.cc ------------------------------------------------------------------------ r5714 | ajapted | 2009-07-29 16:24:15 Eureka: renamed QF --> KF and QF_F --> KF_fonth. ------------------------------------------------------------------------ r5713 | ajapted | 2009-07-29 16:22:59 Eureka: fiddled with menu. ------------------------------------------------------------------------ r5712 | ajapted | 2009-07-29 15:13:17 Eureka: few more fixes to get compiling and running again. ------------------------------------------------------------------------ r5711 | ajapted | 2009-07-29 15:04:25 Eureka: fleshed out new LoadLevel() function, and removed the old crud. ------------------------------------------------------------------------ r5710 | ajapted | 2009-07-29 14:55:38 Eureka: fleshed out LoadThings(), LoadSideDefs() and LoadLineDefs(). ------------------------------------------------------------------------ r5709 | ajapted | 2009-07-29 14:38:05 Eureka: yet more sticky-tape and bubble-gum workarounds... ------------------------------------------------------------------------ r5708 | ajapted | 2009-07-29 13:17:25 Eureka: added LineDef::TouchesSector() method. ------------------------------------------------------------------------ r5707 | ajapted | 2009-07-29 01:10:51 Eureka: more bubble gum patching just to get something to compile. ------------------------------------------------------------------------ r5706 | ajapted | 2009-07-29 00:51:38 Eureka: fleshed out sector loading: LoadSectors(). ------------------------------------------------------------------------ r5705 | ajapted | 2009-07-29 00:48:09 Eureka: added convenience func: BA_InternaliseShortStr(). ------------------------------------------------------------------------ r5704 | ajapted | 2009-07-29 00:09:27 Eureka: began work on new level loading code : e_load.cc ------------------------------------------------------------------------ r5703 | ajapted | 2009-07-29 00:08:32 Eureka: sticky-tape for editloop.cc ------------------------------------------------------------------------ r5702 | ajapted | 2009-07-28 23:04:51 Eureka: wrote a little Features / Requirements doc. ------------------------------------------------------------------------ r5701 | ajapted | 2009-07-28 22:58:06 Eureka: more sticky-tape and bubble-gum to get it compiling again. ------------------------------------------------------------------------ r5700 | ajapted | 2009-07-28 22:51:33 Eureka: fixes for r_images.cc ------------------------------------------------------------------------ r5699 | ajapted | 2009-07-28 22:47:36 Eureka: updated 3D render code for the Basis. ------------------------------------------------------------------------ r5698 | ajapted | 2009-07-28 22:45:19 Eureka: added e_basis.o to the build. ------------------------------------------------------------------------ r5697 | ajapted | 2009-07-28 22:29:31 Eureka: prelim work updating UI widgets for the Basis. ------------------------------------------------------------------------ r5696 | ajapted | 2009-07-28 22:16:50 Eureka: fixed ui_canvas.cc for new basic structs. ------------------------------------------------------------------------ r5695 | ajapted | 2009-07-28 21:53:58 Eureka: remove old defintions of LineDef, Sector (etc) structs. ------------------------------------------------------------------------ r5694 | ajapted | 2009-07-28 21:46:06 Eureka: fixed some things in e_basis.cc ------------------------------------------------------------------------ r5693 | ajapted | 2009-07-28 21:19:02 Eureka: reformatted top-of-file comments, added the word 'Copyright' because the presence of mere '(C)' has no legal significance. ------------------------------------------------------------------------ r5692 | ajapted | 2009-07-28 21:12:18 Eureka: twiddled TODO ------------------------------------------------------------------------ r5525 | ajapted | 2009-07-17 15:27:57 Eureka: completed the BASIS implementation (Undo, Redo, etc). ------------------------------------------------------------------------ r5524 | ajapted | 2009-07-17 14:56:04 Eureka: fleshed out more of the BASIS implementation. ------------------------------------------------------------------------ r5523 | ajapted | 2009-07-17 14:29:00 Eureka: more work on BASIS implementation, moved or removed the irrelevant code out of e_basis.cc. ------------------------------------------------------------------------ r5522 | ajapted | 2009-07-17 14:21:44 Eureka: fleshed out the BASIS API (BA_Begin, BA_Change, etc). ------------------------------------------------------------------------ r5521 | ajapted | 2009-07-17 00:48:52 Eureka: basis stuff yay. ------------------------------------------------------------------------ r5520 | ajapted | 2009-07-16 23:59:32 Eureka: further work on the basis (RawInsert and RawDelete). ------------------------------------------------------------------------ r5519 | ajapted | 2009-07-16 21:27:16 Eureka: removed unused OBJ_XXX constants, added rad-trig bits. ------------------------------------------------------------------------ r5518 | ajapted | 2009-07-16 21:24:38 Eureka: basis code: implemented the helper methods (FloorTex etc), and removed more code that doesn't belong here. ------------------------------------------------------------------------ r5517 | ajapted | 2009-07-16 21:05:32 Eureka: fleshed out all basis InsertXXX() and DeleteXXX() functions. ------------------------------------------------------------------------ r5516 | ajapted | 2009-07-16 20:05:31 Eureka: updated the DeleteObject() code for new basis design. ------------------------------------------------------------------------ r5515 | ajapted | 2009-07-16 19:25:42 Eureka: bit more work on object basis. ------------------------------------------------------------------------ r5514 | ajapted | 2009-07-16 19:22:59 Eureka: updated basis header with design notes and some helper methods in each structure (e.g. Sector::FloorTex). ------------------------------------------------------------------------ r5513 | ajapted | 2009-07-16 18:47:12 Eureka: updated makefile. ------------------------------------------------------------------------ r5512 | ajapted | 2009-07-16 17:28:42 Eureka: improved string table class to support "huge" strings. ------------------------------------------------------------------------ r5511 | ajapted | 2009-07-16 15:49:28 Eureka: fixed string table to find existing strings in add(). ------------------------------------------------------------------------ r5510 | ajapted | 2009-07-16 15:30:11 Eureka: finished implementation of string table. ------------------------------------------------------------------------ r5509 | ajapted | 2009-07-16 15:11:15 Eureka: preliminary work on a string table. ------------------------------------------------------------------------ r5508 | ajapted | 2009-07-16 14:58:40 Eureka: added field enums (F_X, F_FLOOR_TEX, etc) to basis classes. ------------------------------------------------------------------------ r5507 | ajapted | 2009-07-16 14:45:10 Eureka: fleshed out new basis classes (class Thing etc). ------------------------------------------------------------------------ r5506 | ajapted | 2009-07-16 14:20:23 Eureka: began work on new 'e_basis' file for basic object handling. ------------------------------------------------------------------------ r5505 | ajapted | 2009-07-16 14:17:14 Eureka: removed 'ld - LineDefs' and 'sec - Sectors' pointer math. ------------------------------------------------------------------------ r5504 | ajapted | 2009-07-16 00:56:49 Eureka: removed unused 'things_angles' and 'things_types' vars. ------------------------------------------------------------------------ r5503 | ajapted | 2009-07-16 00:55:48 Eureka: fixed 'spin_things' code. ------------------------------------------------------------------------ r5494 | ajapted | 2009-07-14 23:52:22 Eureka: got the code compiling again (after SelPtr change). ------------------------------------------------------------------------ r5493 | ajapted | 2009-07-14 23:14:22 Eureka: partial work, updating all code to use new selection_c class instead of old SelPtr stuff. ------------------------------------------------------------------------ r5492 | ajapted | 2009-07-14 22:56:36 Eureka: optional 'initial' value for selection_c constructor. ------------------------------------------------------------------------ r5491 | ajapted | 2009-07-14 22:48:07 Eureka: reworked InsertObject() code. ------------------------------------------------------------------------ r5490 | ajapted | 2009-07-14 22:23:14 Eureka: new and improved DeleteObjects() code is done. ------------------------------------------------------------------------ r5489 | ajapted | 2009-07-14 21:14:17 Eureka: preliminary rework of DeleteObjects() code. ------------------------------------------------------------------------ r5488 | ajapted | 2009-07-14 21:13:41 Eureka: reinstated objid.h (finished split from objects.h). ------------------------------------------------------------------------ r5487 | ajapted | 2009-07-14 20:33:38 Eureka: reinstated header file: objid.h ------------------------------------------------------------------------ r5486 | ajapted | 2009-07-14 19:43:32 Eureka: improved selection_c class, new change_type() and empty() methods. ------------------------------------------------------------------------ r5485 | ajapted | 2009-07-14 18:42:54 Eureka: new MAX_RADIUS constant. ------------------------------------------------------------------------ r5484 | ajapted | 2009-07-14 18:41:40 Eureka: code reformatting. ------------------------------------------------------------------------ r5483 | ajapted | 2009-07-14 16:54:15 Eureka: yet more reformatting, yay. ------------------------------------------------------------------------ r5482 | ajapted | 2009-07-14 16:28:55 Eureka: more reformatting. ------------------------------------------------------------------------ r5481 | ajapted | 2009-07-14 15:30:07 Eureka: code reformatting. ------------------------------------------------------------------------ r5480 | ajapted | 2009-07-14 15:16:39 Eureka: reformatted code. ------------------------------------------------------------------------ r5479 | ajapted | 2009-07-13 23:30:46 Eureka: implemented iterators for the new selection_c class, with an API similar to (but not the same as) the STL. ------------------------------------------------------------------------ r5478 | ajapted | 2009-07-13 23:01:07 Eureka: fleshed out remaining selection_c methods. ------------------------------------------------------------------------ r5477 | ajapted | 2009-07-13 22:49:17 Eureka: preliminary new class for handling selections. ------------------------------------------------------------------------ r5476 | ajapted | 2009-07-13 22:34:39 Eureka: extended bitvec_c class with set_all(), clear_all(), toggle_all() and merge() methods. ------------------------------------------------------------------------ r5475 | ajapted | 2009-07-13 22:12:38 Eureka: reworked bitvec_c implementation. ------------------------------------------------------------------------ r5474 | ajapted | 2009-07-13 21:47:01 Eureka: incorporated highlight code into UI_Canvas widget. ------------------------------------------------------------------------ r5473 | ajapted | 2009-07-13 20:03:23 Eureka: updated TODO ------------------------------------------------------------------------ r5472 | ajapted | 2009-07-13 19:57:18 Eureka: incorporated selection box functionality into UI_Canvas widget. ------------------------------------------------------------------------ r5471 | ajapted | 2009-07-13 19:20:22 Eureka: updated #includes for recent renamings. ------------------------------------------------------------------------ r5470 | ajapted | 2009-07-13 18:58:35 Eureka: moved levelname2levelno(), levelname2rank() from yutil --> levels.cc ------------------------------------------------------------------------ r5469 | ajapted | 2009-07-13 18:51:00 Eureka: renamed various files, now: e_checks, e_linedef, e_things, e_sector, e_vertex, m_config, m_dialog and m_game. ------------------------------------------------------------------------ r5468 | ajapted | 2009-07-13 18:47:34 Eureka: make side panels wider on higher resolutions. ------------------------------------------------------------------------ r5467 | ajapted | 2009-07-13 18:38:32 Eureka: renamed Makefile.linux --> Makefile.unx ------------------------------------------------------------------------ r5466 | ajapted | 2009-07-13 18:36:07 Eureka: updated #includes for recent file renamings. ------------------------------------------------------------------------ r5465 | ajapted | 2009-07-13 17:46:42 Eureka: renamed files: gfx --> r_misc ------------------------------------------------------------------------ r5464 | ajapted | 2009-07-13 17:45:00 Eureka: dead code removal. ------------------------------------------------------------------------ r5463 | ajapted | 2009-07-13 17:36:33 Eureka: renamed files: grid2 --> r_grid ------------------------------------------------------------------------ r5462 | ajapted | 2009-07-13 17:30:26 Eureka: moved InitFLTK and TermFLTK from gfx.cc --> main.cc, and removed some unused stuff. ------------------------------------------------------------------------ r5461 | ajapted | 2009-07-13 17:00:43 Eureka: merged l_super.h file --> linedefs.cc ------------------------------------------------------------------------ r5460 | ajapted | 2009-07-13 14:51:08 Eureka: merged e_names.cc file --> editobj.cc ------------------------------------------------------------------------ r5459 | ajapted | 2009-07-13 14:47:29 Eureka: merged edit2.h file --> editloop.h ------------------------------------------------------------------------ r5458 | ajapted | 2009-07-13 14:41:43 Eureka: merged gotoobj files --> objects.cc/h ------------------------------------------------------------------------ r5450 | ajapted | 2009-07-12 16:02:58 Eureka: code tidying, removed DRAWING_MAP hack. ------------------------------------------------------------------------ r5449 | ajapted | 2009-07-12 00:40:42 Eureka: renamed various fields of map structures: xoff, yoff --> x_offset, y_offset ceilt, floort --> ceil_tex, floor_tex upper, lower --> upper_tex, lower_tex middle --> mid_tex sidedef1 / 2 --> side_R, side_L when, special --> options, type ------------------------------------------------------------------------ r5448 | ajapted | 2009-07-11 23:46:56 Eureka: Removed unused headers: spot.h and edwidget.h ------------------------------------------------------------------------ r5447 | ajapted | 2009-07-11 23:34:04 Eureka: more file merging, various reformatting and renaming. ------------------------------------------------------------------------ r5446 | ajapted | 2009-07-11 22:46:35 Eureka: reformatting... ------------------------------------------------------------------------ r5445 | ajapted | 2009-07-11 22:32:11 Eureka: more file shenanigans. ------------------------------------------------------------------------ r5444 | ajapted | 2009-07-11 22:22:36 Eureka: merged input.h and y_time.cc/h into other files. ------------------------------------------------------------------------ r5443 | ajapted | 2009-07-11 22:10:29 Eureka: scrollbar tweak. ------------------------------------------------------------------------ r5442 | ajapted | 2009-07-11 21:59:25 Eureka: new top-of-file comments (header files). ------------------------------------------------------------------------ r5441 | ajapted | 2009-07-11 21:44:52 Eureka: new top-of-file comment block. ------------------------------------------------------------------------ r5440 | ajapted | 2009-07-11 18:07:17 Eureka: more work on the Texture list widget. ------------------------------------------------------------------------ r5439 | ajapted | 2009-07-11 15:04:50 Eureka: bit more work on texture selector. ------------------------------------------------------------------------ r5438 | ajapted | 2009-07-11 14:42:58 Eureka: preliminary work on a flat/texture selection panel. ------------------------------------------------------------------------ r5437 | ajapted | 2009-07-11 14:10:45 Eureka: renamed more stuff. ------------------------------------------------------------------------ r5436 | ajapted | 2009-07-11 14:09:23 Eureka: renamed more stuff. ------------------------------------------------------------------------ r5435 | ajapted | 2009-07-11 00:32:21 Eureka: various tidying... ------------------------------------------------------------------------ r5434 | ajapted | 2009-07-11 00:06:45 Eureka: began work on using larger fonts (etc) on higher screen resolutions. ------------------------------------------------------------------------ r5433 | ajapted | 2009-07-10 23:35:44 Eureka: reformatting. ------------------------------------------------------------------------ r5432 | ajapted | 2009-07-10 22:44:04 Eureka: added vim editor settings to each file. ------------------------------------------------------------------------ r5431 | ajapted | 2009-07-10 22:15:48 Eureka: renamed files yadex --> main, merged objid.h into objects.h ------------------------------------------------------------------------ r5430 | ajapted | 2009-07-10 21:59:48 Eureka: tweaks. ------------------------------------------------------------------------ r5429 | ajapted | 2009-07-10 21:54:07 Eureka: yep more twiddling... ------------------------------------------------------------------------ r5428 | ajapted | 2009-07-10 21:38:01 Eureka: more tidying... ------------------------------------------------------------------------ r5427 | ajapted | 2009-07-10 19:31:40 Eureka: more file stuff.... ------------------------------------------------------------------------ r5426 | ajapted | 2009-07-10 19:21:00 Eureka: merged files: im_appcol, im_gamecol, im_rgb --> im_color. ------------------------------------------------------------------------ r5425 | ajapted | 2009-07-10 19:08:03 Eureka: merged files: x_rotate, x_centre, x_exchg --> x_mirror. ------------------------------------------------------------------------ r5424 | ajapted | 2009-07-10 14:56:36 Eureka: finished merging v_* files. ------------------------------------------------------------------------ r5423 | ajapted | 2009-07-10 14:52:39 Eureka: began merging v_* files --> vertices.cc/h ------------------------------------------------------------------------ r5422 | ajapted | 2009-07-10 14:49:52 Eureka: merged s_* files into sectors.cc/h and s_misc.cc/h ------------------------------------------------------------------------ r5421 | ajapted | 2009-07-10 14:38:39 Eureka: merged s_split.cc, s_slice.cc into --> s_misc.cc ------------------------------------------------------------------------ r5420 | ajapted | 2009-07-10 14:33:32 Eureka: renamed files: s_centre --> sectors ------------------------------------------------------------------------ r5419 | ajapted | 2009-07-10 14:32:20 Eureka: renamed file --> s_misc.h ------------------------------------------------------------------------ r5418 | ajapted | 2009-07-10 14:29:40 Eureka: finished merging linedef stuff. ------------------------------------------------------------------------ r5417 | ajapted | 2009-07-10 14:23:12 Eureka: began merging linedef stuff into less files. ------------------------------------------------------------------------ r5416 | ajapted | 2009-07-10 00:38:58 Eureka: renamed file: memory --> ymemory ------------------------------------------------------------------------ r5415 | ajapted | 2009-07-10 00:34:54 Eureka: merged t_spin, t_flags, t_centre files --> things.cc/h ------------------------------------------------------------------------ r5414 | ajapted | 2009-07-10 00:25:51 Eureka: renamed GetFarMemory --> GetMemory (et al). ------------------------------------------------------------------------ r5413 | ajapted | 2009-07-10 00:17:55 Eureka: removed files: locate.cc/h and macro.cc/h ------------------------------------------------------------------------ r5390 | ajapted | 2009-07-09 01:36:07 Eureka: fixed the cpu hogging (use Fl::wait in main loop). ------------------------------------------------------------------------ r5389 | ajapted | 2009-07-09 01:16:45 Eureka: removed dummy atclib.h ------------------------------------------------------------------------ r5388 | ajapted | 2009-07-09 00:52:30 Checked in a map editor based on Yadex 1.7.0 but completely hacked to pieces to work with the FLTK toolkit and removal of the atclib. eureka-editor-eureka-2.0.2/games/000077500000000000000000000000001464327712600166355ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/games/doom.ugh000066400000000000000000000045151464327712600203050ustar00rootroot00000000000000#------------------------------------------------------------------------ # DOOM 1 definitions #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2013 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ base_game doom sky_flat F_SKY1 default_textures GRAY1 FLAT1 FLAT1 default_thing 2014 feature tag_666 1 set $ALLOW_BOOM 1 include "doom_colors" include "doom_things" include "doom_groups" include "doom_lines" include "doom_sectors" include "doom_tex" #---- DOOM 1 TEXTURES ---------------- texture h REDWALL1 texture h SKINBORD texture h SKINTEK1 texture h SKINTEK2 texture h SKULWAL3 texture h SKULWALL texture h SP_DUDE3 texture h SP_DUDE6 texture n ASHWALL texture n MIDVINE1 texture n MIDVINE2 texture n SP_ROCK2 texture n SKY4 texture t BLODGR1 texture t BLODGR2 texture t BLODGR3 texture t BLODGR4 texture t BRNBIGC texture t BRNBIGL texture t BRNBIGR texture t BRNPOIS2 texture t BROVINE texture t BROWNWEL texture t COMP2 texture t COMPOHSO texture t COMPTILE texture t COMPUTE1 texture t COMPUTE2 texture t COMPUTE3 texture t DOORHI texture t GRAYDANG texture t ICKDOOR1 texture t ICKWALL6 texture t LITE2 texture t LITE4 texture t LITE96 texture t LITEBLU2 texture t LITEBLU3 texture t LITEMET texture t LITERED texture t NUKESLAD texture t PLANET1 texture t SLADRIP1 texture t SLADRIP2 texture t SLADRIP3 texture t STARTAN1 texture t TEKWALL2 texture t TEKWALL3 texture t TEKWALL5 texture u CEMPOIS texture u LITESTON texture u STONGARG texture u STONPOIS texture u WOODSKUL eureka-editor-eureka-2.0.2/games/doom2.ugh000066400000000000000000000143611464327712600203670ustar00rootroot00000000000000#------------------------------------------------------------------------ # DOOM 2 definitions #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2013 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ base_game doom2 sky_flat F_SKY1 default_textures GRAY1 FLAT1 FLAT1 default_thing 2014 feature tag_666 1 set $ALLOW_BOOM 1 include "doom_colors" include "doom_things" include "doom_groups" include "doom_lines" include "doom_sectors" include "doom_tex" #---- DOOM 2 THINGS ---------------- thing 82 w n- 20 SGN2 "Super shotgun" thing 83 h nl 20 MEGA "Megasphere" thing 84 m - 20 SSWV "Wolf-SS" thing 65 m - 20 CPOS "Chaingunner" thing 69 m - 24 BOS2 "Hell knight" thing 68 m - 64 BSPI "Arachnotron" thing 71 m - 31 PAIN "Pain elemental" thing 66 m - 20 SKEL "Revenant" thing 67 m - 48 FATT "Mancubus" thing 64 m - 20 VILE "Archvile" thing 73 g c 16 HDB1 "Hanging no guts" thing 74 g c 16 HDB2 "Hanging no brain" thing 75 g c 16 HDB3 "Hang torso looking down" thing 76 g c 16 HDB4 "Hang torso open skull" thing 77 g c 16 HDB5 "Hang torso looking up" thing 78 g c 16 HDB6 "Hang torso w/o brain" thing 79 g n 16 POB1 "Pool of blood 2" thing 80 g n 16 POB2 "Pool of blood 3" thing 81 g n 16 BRS1 "Pool of brains" thing 85 l l 16 TLMP "Tall mercury lamp" thing 86 l l 16 TLP2 "Short mercury lamp" thing 87 - nl 16 FIREF "Spawn spot" thing 88 - - 16 BBRN "Boss brain" thing 89 - - 16 BOSFB "Boss shooter" thing 72 - c 16 KEEN "Commander Keen" #---- DOOM 2 TEXTURES ---------------- texturegroup w "Wolfenstein" texture w ZDOORB1 texture w ZDOORF1 texture w ZELDOOR texture w ZZWOLF1 texture w ZZWOLF10 texture w ZZWOLF11 texture w ZZWOLF12 texture w ZZWOLF13 texture w ZZWOLF2 texture w ZZWOLF3 texture w ZZWOLF4 texture w ZZWOLF5 texture w ZZWOLF6 texture w ZZWOLF7 texture w ZZWOLF9 texture u BIGBRIK1 texture u BIGBRIK2 texture u BIGBRIK3 texture u BRICK1 texture u BRICK10 texture u BRICK11 texture u BRICK12 texture u BRICK2 texture u BRICK3 texture u BRICK4 texture u BRICK5 texture u BRICK6 texture u BRICK7 texture u BRICK8 texture u BRICK9 texture u BRICKLIT texture u BRWINDOW texture u BSTONE1 texture u BSTONE2 texture u BSTONE3 texture u CEMENT7 texture u CEMENT8 texture u CEMENT9 texture h BFALL1 texture h BFALL2 texture h BFALL3 texture h BFALL4 texture h CRACKLE2 texture h CRACKLE4 texture h DBRAIN1 texture h DBRAIN2 texture h DBRAIN3 texture h DBRAIN4 texture h MARBFAC4 texture h MARBGRAY texture h SW1SKULL texture h SW2SKULL texture h ZZZFACE1 texture h ZZZFACE2 texture h ZZZFACE3 texture h ZZZFACE4 texture h ZZZFACE5 texture h ZZZFACE6 texture h ZZZFACE7 texture h ZZZFACE8 texture h ZZZFACE9 texture t BRONZE1 texture t BRONZE2 texture t BRONZE3 texture t BRONZE4 texture t CRATE3 texture t MIDBARS1 texture t MIDBARS3 texture t MIDBRONZ texture t MIDSPACE texture t METAL2 texture t METAL3 texture t METAL4 texture t METAL5 texture t METAL6 texture t METAL7 texture t SFALL1 texture t SFALL2 texture t SFALL3 texture t SFALL4 texture t SW1TEK texture t SW2TEK texture t TEKBRON1 texture t TEKBRON2 texture t TEKGREN1 texture t TEKGREN2 texture t TEKGREN3 texture t TEKGREN4 texture t TEKGREN5 texture t TEKLITE texture t TEKLITE2 texture t TEKWALL6 texture n ASHWALL2 texture n ASHWALL3 texture n ASHWALL4 texture n ASHWALL6 texture n ASHWALL7 texture n ROCK1 texture n ROCK2 texture n ROCK3 texture n ROCK4 texture n ROCK5 texture n STONE4 texture n STONE5 texture n STONE6 texture n STONE7 texture n SW1ROCK texture n SW2ROCK texture n SW1ZIM texture n SW2ZIM texture n TANROCK2 texture n TANROCK3 texture n TANROCK4 texture n TANROCK5 texture n TANROCK7 texture n TANROCK8 texture n ZIMMER1 texture n ZIMMER2 texture n ZIMMER3 texture n ZIMMER4 texture n ZIMMER5 texture n ZIMMER7 texture n ZIMMER8 texture t MODWALL1 texture t MODWALL2 texture t MODWALL3 texture t MODWALL4 texture t PIPES texture t PIPEWAL1 texture t PIPEWAL2 texture t SILVER1 texture t SILVER2 texture t SILVER3 texture t SPACEW2 texture t SPACEW3 texture t SPACEW4 texture t SPCDOOR1 texture t SPCDOOR2 texture t SPCDOOR3 texture t SPCDOOR4 texture u PANBLACK texture u PANBLUE texture u PANBOOK texture u PANBORD1 texture u PANBORD2 texture u PANCASE1 texture u PANCASE2 texture u PANEL1 texture u PANEL2 texture u PANEL3 texture u PANEL4 texture u PANEL5 texture u PANEL6 texture u PANEL7 texture u PANEL8 texture u PANEL9 texture u PANRED texture u SP_DUDE7 texture u SP_DUDE8 texture u STUCCO texture u STUCCO1 texture u STUCCO2 texture u STUCCO3 texture u SW1PANEL texture u SW2PANEL texture u SW1WDMET texture u SW2WDMET texture u WOOD10 texture u WOOD12 texture u WOOD6 texture u WOOD7 texture u WOOD8 texture u WOOD9 texture u WOODMET1 texture u WOODMET2 texture u WOODMET3 texture u WOODMET4 texture u WOODVERT #---- DOOM 2 FLATS ---------------- flat n GRASS1 flat n GRASS2 flat t GRNLITE1 flat n GRNROCK flat n RROCK01 flat n RROCK02 flat n RROCK03 flat n RROCK04 flat n RROCK05 flat n RROCK06 flat n RROCK07 flat n RROCK08 flat n RROCK09 flat n RROCK10 flat n RROCK11 flat n RROCK12 flat n RROCK13 flat n RROCK14 flat n RROCK15 flat n RROCK16 flat n RROCK17 flat n RROCK18 flat n RROCK19 flat n RROCK20 flat u SLIME01 flat u SLIME02 flat u SLIME03 flat u SLIME04 flat u SLIME05 flat u SLIME06 flat u SLIME07 flat u SLIME08 flat h SLIME09 flat h SLIME10 flat h SLIME11 flat h SLIME12 flat u SLIME13 flat t SLIME14 flat t SLIME15 flat t SLIME16 eureka-editor-eureka-2.0.2/games/freedm.ugh000066400000000000000000000015751464327712600206140ustar00rootroot00000000000000#------------------------------------------------------------------------ # FREEDM #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2019 Pascal de Bruijn # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ include "doom2" include "tnt_tex" include "plutonia_tex" # TODO : new FreeDoom textures eureka-editor-eureka-2.0.2/games/freedoom1.ugh000066400000000000000000000015351464327712600212270ustar00rootroot00000000000000#------------------------------------------------------------------------ # FREEDOOM PHASE 1 #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2016 Andrew Apted # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ include "doom" # TODO : new FreeDoom textures eureka-editor-eureka-2.0.2/games/freedoom2.ugh000066400000000000000000000016101464327712600212220ustar00rootroot00000000000000#------------------------------------------------------------------------ # FREEDOOM PHASE 2 #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2019 Andrew Apted # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ include "doom2" include "tnt_tex" include "plutonia_tex" # TODO : new FreeDoom textures eureka-editor-eureka-2.0.2/games/hacx.ugh000066400000000000000000000410031464327712600202630ustar00rootroot00000000000000#------------------------------------------------------------------------ # HACX 1.2 definitions #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2012-2016 Andrew Apted # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ base_game doom2 player_size 16 56 41 sky_flat F_SKY1 default_textures MODWALL3 FLAT14 FLAT5_1 default_thing 2014 feature tag_666 1 include "doom_colors" include "doom_groups" include "doom_lines" include "doom_sectors" #---- THINGS ---------------- thinggroup p 4F4 "Player" thinggroup m F00 "Monster" thinggroup w FA0 "Weapon" thinggroup a 850 "Ammunition" thinggroup h 280 "Health && Armor" thinggroup b 280 "Bonus" thinggroup k F0F "Key" thinggroup d 66C "Decoration" thinggroup g 850 "Gore" thinggroup l 66C "Light Source" thinggroup n 66C "Natural" thinggroup - 0BD "OTHER" thing 1 p - 16 PLAY "Player 1 start" thing 2 p - 16 PLAY "Player 2 start" thing 3 p - 16 PLAY "Player 3 start" thing 4 p - 16 PLAY "Player 4 start" thing 11 p t 16 PLAYF1 "Deathmatch start" thing 14 p t 16 TFOG "Teleport exit" thing 2001 w n 20 SHOT "Tazer" thing 82 w n 20 SGN2 "Cyrogun" thing 2002 w n 20 MGUN "Uzi" thing 2003 w n 20 LAUN "Photon Zooka" thing 2004 w n 20 PLAS "Anti-gun" thing 2005 w n 20 CSAW "Reznator" thing 2006 w n 20 BFUG "Nuker" thing 2007 a n 20 CLIP "Clip" thing 2048 a n 20 AMMO "Box of bullets" thing 2008 a n 20 SHEL "Shells" thing 2049 a n 20 SBOX "Box of shells" thing 2010 a n 20 ROCK "Torpedo" thing 2046 a n 20 BROK "Box of torpedoes" thing 2047 a n 20 CELL "Molecules" thing 17 a n 20 CELP "Box of molecules" thing 8 b n 20 BPAK "Valise w/ ammo" thing 2022 b nl 20 PINV "Force field" thing 2023 b nl 20 PSTR "007-Microtel" thing 2024 b nl 20 PINS "Enk blinder" thing 2025 b nl 20 SUIT "Vulcan rubber boots" thing 2026 b n 20 PMAP "SI Array mapping" thing 2045 b nl 20 PVIS "Infrared visor" thing 83 b nl 20 MEGA "Super kevlar vest" thing 2011 h n 20 STIM "Microkit" thing 2012 h n 20 MEDI "Hypo" thing 2013 h n 20 SOUL "Smart drug" thing 2014 h n 20 BON1 "Dampener" thing 2015 h n 20 BON2 "Inhaler" thing 2018 h n 20 ARM1 "Kevlar Armor" thing 2019 h n 20 ARM2 "Super Armor" thing 5 k nl 20 BKEY "Password" thing 6 k nl 20 YKEY "C-key" thing 13 k nl 20 RKEY "Keycard" thing 40 k nl 20 BSKU "Blue Z-key" thing 39 k nl 20 YSKU "Yellow Z-key" thing 38 k nl 20 RSKU "Red Z-key" # TODO: there may a few missing decorations thing 15 g n 16 PLAYN "Dead player" thing 21 g n 16 SARGN "Destroyed bot" thing 18 g n 20 POSSL "Dead trooper" thing 19 g n 20 SPOSL "Dead sergeant" thing 20 g n 20 TROOM "Dead imp" thing 23 g n 16 SKULK "Dead lost soul" thing 50 g n 16 GOR2 "Corpse 1" thing 51 g n 16 GOR3 "Corpse 2" thing 52 g n 16 GOR4 "Corpse 3" thing 24 g n 16 POL5 "Corpse 4" thing 3004 m - 20 POSS "Thug" thing 9 m - 20 SPOS "Android" thing 3001 m - 20 TROO "I_C_E" thing 3002 m - 30 SARG "Buzzer" thing 3003 m - 24 BOSS "Terminatrix" thing 58 m i 30 SARG "Stealth" thing 3006 m - 16 SKUL "D-Man" thing 84 m - 20 SSWV "Roaming mine" thing 65 m - 20 CPOS "Monstruct" thing 69 m - 24 BOS2A1C1 "Mechamaniac" thing 68 m - 64 BSPI "Thorn Thing" thing 71 m - 31 PAIN "Majong 7" thing 67 m - 48 FATT "Phage" thing 45 l lcn 16 TBLU "Ceiling light" thing 46 l lc 16 TRED "Chandelier" thing 56 l l 16 SMGT "Torch" thing 55 l l 16 SMBT "Desk lamp" thing 57 l l 16 SMRT "Office lamp" thing 2028 d - 16 COLU "Monitor" thing 2035 d - 10 BAR1 "Nitro canister" thing 30 d - 16 COL1 "Robot torso" thing 31 d - 16 COL2 "Robot legs" thing 35 d - 16 CBRA "Chair" thing 80 d - 16 POB2 "Skeleton" thing 81 d - 16 BRS1 "Mummy" thing 44 d - 16 TGRN "Shiny ball" thing 3005 d n 32 HEADC1 "Breakable glass" thing 25 d - 16 POL1 "Laser pole" thing 48 d - 16 ELEC "Metal blades" thing 49 d - 16 GOR1 "Tall robot" thing 26 d - 16 POL6 "Clay jug" thing 28 d - 16 POL2 "Dinghy" thing 34 d - 16 CAND "Warrior statue" thing 41 d l 16 CEYE "Evil eye" thing 42 d l 16 FSKU "Floating galaxy" thing 43 n - 16 TRE1 "Tall tree" thing 54 n - 32 TRE2 "Big tree" thing 47 n - 16 SMIT "Shrub" thing 27 n - 16 POL4 "Bonzai" thing 32 n - 16 COL3 "Pink flowers" thing 33 n - 16 COL4 "Blob" thing 85 n n 16 TLMP "Dots" thing 86 n n 16 TLP2 "Dot" thing 73 n nc 16 HDB1 "Hanging moss 1" thing 74 n nc 16 HDB2 "Hanging moss 2" thing 75 n - 16 HDB3 "Stalagmite 2" thing 76 n - 16 HDB4 "Stalagmite 3" thing 77 n nc 16 HDB5 "Stalactite 1" thing 78 n nc 16 HDB6 "Stalactite 2" thing 79 n - 16 POB1 "Stalagmite 1" #---- TEXTURES ---------------- ## FIXME: more categories texturegroup n "Natural" texturegroup u "Urban" texturegroup c "Cyberspace" texturegroup - "OTHER" ## FIXME: assign to categories texture - AASHITTY texture - ASHWALL2 texture - ASHWALL3 texture - ASHWALL4 texture - ASHWALL6 texture - ASHWALL7 texture - BFALL1 texture - BFALL2 texture - BFALL3 texture - BFALL4 texture - BIGBRIK1 texture - BIGBRIK2 texture - BIGBRIK3 texture - BIGDOOR1 texture - BIGDOOR2 texture - BIGDOOR4 texture - BLAKWAL1 texture - BLAKWAL2 texture - BLODGR1 texture - BLODGR2 texture - BLODGR3 texture - BLODGR4 texture - BLODRIP1 texture - BLODRIP2 texture - BLODRIP3 texture - BLODRIP4 texture - BRICK1 texture - BRICK10 texture - BRICK11 texture - BRICK12 texture - BRICK2 texture - BRICK3 texture - BRICK4 texture - BRICK5 texture - BRICK6 texture - BRICK7 texture - BRICK8 texture - BRICK9 texture - BRICKLIT texture - BRNBIGC texture - BRNBIGL texture - BRNBIGR texture - BRNPOIS texture - BRNPOIS2 texture - BRNSMAL1 texture - BRNSMAL2 texture - BRNSMALC texture - BRNSMALL texture - BRNSMALR texture - BRONZE1 texture - BRONZE2 texture - BRONZE3 texture - BRONZE4 texture - BROWN1 texture - BROWN144 texture - BROWN96 texture - BROWNGRN texture - BROWNHUG texture - BROWNPIP texture - BRWINDOW texture - BSTONE1 texture - BSTONE2 texture - BSTONE3 texture - CEMENT7 texture - CEMENT8 texture - CEMENT9 texture - COMP2 texture - COMPSPAN texture - COMPSTA1 texture - COMPSTA2 texture - COMPTALL texture - COMPTILE texture - COMPUTE1 texture - COMPUTE2 texture - COMPUTE3 texture - CRACKLE2 texture - CRACKLE4 texture - CRATE3 texture - DBRAIN1 texture - DBRAIN2 texture - DBRAIN3 texture - DBRAIN4 texture - DOOR1 texture - DOOR3 texture - DOORBLU texture - DOORRED texture - DOORSTOP texture - DOORTRAK texture - DOORYEL texture - EXITDOOR texture - EXITSIGN texture - FIREWALA texture - FIREWALB texture - FIREWALC texture - FIREWALD texture - FIREWALL texture - GRAY4 texture - GRAY5 texture - GRAY7 texture - GRAYTALL texture - GSTFONT1 texture - GSTFONT2 texture - GSTFONT3 texture - HD1 texture - HD2 texture - HD3 texture - HD4 texture - HD5 texture - HD6 texture - HD7 texture - HD8 texture - HD9 texture - HW162 texture - HW163 texture - HW164 texture - HW165 texture - HW166 texture - HW167 texture - HW168 texture - HW169 texture - HW170 texture - HW171 texture - HW172 texture - HW173 texture - HW174 texture - HW175 texture - HW176 texture - HW177 texture - HW178 texture - HW179 texture - HW180 texture - HW181 texture - HW182 texture - HW183 texture - HW184 texture - HW185 texture - HW186 texture - HW187 texture - HW188 texture - HW189 texture - HW190 texture - HW191 texture - HW192 texture - HW193 texture - HW194 texture - HW195 texture - HW196 texture - HW197 texture - HW198 texture - HW199 texture - HW200 texture - HW201 texture - HW202 texture - HW203 texture - HW204 texture - HW205 texture - HW206 texture - HW207 texture - HW208 texture - HW209 texture - HW210 texture - HW211 texture - HW212 texture - HW213 texture - HW214 texture - HW215 texture - HW216 texture - HW217 texture - HW218 texture - HW219 texture - HW221 texture - HW222 texture - HW223 texture - HW224 texture - HW225 texture - HW226 texture - HW227 texture - HW228 texture - HW229 texture - HW24 texture - HW300 texture - HW301 texture - HW302 texture - HW303 texture - HW304 texture - HW305 texture - HW306 texture - HW307 texture - HW308 texture - HW309 texture - HW310 texture - HW311 texture - HW312 texture - HW313 texture - HW314 texture - HW315 texture - HW316 texture - HW317 texture - HW318 texture - HW319 texture - HW320 texture - HW321 texture - HW322 texture - HW323 texture - HW324 texture - HW325 texture - HW326 texture - HW327 texture - HW328 texture - HW329 texture - HW330 texture - HW331 texture - HW332 texture - HW333 texture - HW334 texture - HW335 texture - HW336 texture - HW337 texture - HW338 texture - HW339 texture - HW340 texture - HW341 texture - HW343 texture - HW344 texture - HW345 texture - HW347 texture - HW348 texture - HW349 texture - HW350 texture - HW351 texture - HW352 texture - HW353 texture - HW354 texture - HW355 texture - HW356 texture - HW357 texture - HW358 texture - HW361 texture - HW363 texture - HW364 texture - HW365 texture - HW366 texture - HW367 texture - HW500 texture - HW501 texture - HW502 texture - HW503 texture - HW504 texture - HW505 texture - HW506 texture - HW507 texture - HW508 texture - HW509 texture - HW510 texture - HW511 texture - HW512 texture - HW513 texture - HW600 texture - HW601 texture - LITE2 texture - LITE3 texture - LITE4 texture - LITE5 texture - LITEBLU1 texture - LITEBLU2 texture - LITEBLU3 texture - LITEBLU4 texture - MARBFAC4 texture - MARBGRAY texture - METAL1 texture - METAL2 texture - METAL3 texture - METAL4 texture - METAL5 texture - METAL6 texture - METAL7 texture - MIDBARS1 texture - MIDBARS3 texture - MIDBRONZ texture - MIDSPACE texture - MODWALL1 texture - MODWALL2 texture - MODWALL3 texture - MODWALL4 texture - NUKE24 texture - NUKEDGE1 texture - NUKESLAD texture - PANBLACK texture - PANBLUE texture - PANBOOK texture - PANBORD1 texture - PANBORD2 texture - PANCASE1 texture - PANCASE2 texture - PANEL1 texture - PANEL2 texture - PANEL3 texture - PANEL4 texture - PANEL5 texture - PANEL6 texture - PANEL7 texture - PANEL8 texture - PANEL9 texture - PANRED texture - PIPE2 texture - PIPES texture - PIPEWAL1 texture - PIPEWAL2 texture - PLANET1 texture - PLAT1 texture - REDWALL1 texture - ROCK1 texture - ROCK2 texture - ROCK3 texture - ROCK4 texture - ROCK5 texture - SAILBOTA texture - SAILBOTB texture - SAILTOPA texture - SAILTOPB texture - SFALL1 texture - SFALL2 texture - SFALL3 texture - SFALL4 texture - SHAWN2 texture - SILVER1 texture - SILVER2 texture - SILVER3 texture - SK_LEFT texture - SK_RIGHT texture - SKY1 texture - SKY2 texture - SKY3 texture - SLADPOIS texture - SLADRIP1 texture - SLADRIP2 texture - SLADRIP3 texture - SLADWALL texture - SLOPPY1 texture - SLOPPY2 texture - SPACEW2 texture - SPACEW3 texture - SPACEW4 texture - SPCDOOR1 texture - SPCDOOR2 texture - SPCDOOR3 texture - SPCDOOR4 texture - SP_DUDE7 texture - SP_DUDE8 texture - SP_FACE2 texture - STARG1 texture - STARG3 texture - STARGR1 texture - STARTAN1 texture - STARTAN2 texture - STARTAN3 texture - STEP1 texture - STEP2 texture - STEP3 texture - STEP4 texture - STEP5 texture - STEP6 texture - STONE texture - STONE2 texture - STONE3 texture - STONE4 texture - STONE5 texture - STONE6 texture - STONE7 texture - STONPOIS texture - STUCCO texture - STUCCO1 texture - STUCCO2 texture - STUCCO3 texture - SUPPORT2 texture - SW1BLUE texture - SW1BRCOM texture - SW1BRIK texture - SW1BRN1 texture - SW1BRN2 texture - SW1BRNGN texture - SW1BROWN texture - SW1CMT texture - SW1COMM texture - SW1COMP texture - SW1DIRT texture - SW1EXIT texture - SW1GARG texture - SW1GRAY texture - SW1GRAY1 texture - SW1GSTON texture - SW1HOT texture - SW1LION texture - SW1MARB texture - SW1MET2 texture - SW1METAL texture - SW1MOD1 texture - SW1PANEL texture - SW1PIPE texture - SW1ROCK texture - SW1SATYR texture - SW1SKIN texture - SW1SKULL texture - SW1SLAD texture - SW1STARG texture - SW1STON1 texture - SW1STON2 texture - SW1STON6 texture - SW1STONE texture - SW1STRTN texture - SW1TEK texture - SW1VINE texture - SW1WDMET texture - SW1WOOD texture - SW1ZIM texture - SW2BLUE texture - SW2BRCOM texture - SW2BRIK texture - SW2BRN1 texture - SW2BRN2 texture - SW2BRNGN texture - SW2BROWN texture - SW2CMT texture - SW2COMM texture - SW2COMP texture - SW2DIRT texture - SW2EXIT texture - SW2GARG texture - SW2GRAY texture - SW2GRAY1 texture - SW2GSTON texture - SW2HOT texture - SW2LION texture - SW2MARB texture - SW2MET2 texture - SW2METAL texture - SW2MOD1 texture - SW2PANEL texture - SW2PIPE texture - SW2ROCK texture - SW2SATYR texture - SW2SKIN texture - SW2SKULL texture - SW2SLAD texture - SW2STARG texture - SW2STON1 texture - SW2STON2 texture - SW2STON6 texture - SW2STONE texture - SW2STRTN texture - SW2TEK texture - SW2VINE texture - SW2WDMET texture - SW2WOOD texture - SW2ZIM texture - TANROCK2 texture - TANROCK3 texture - TANROCK4 texture - TANROCK5 texture - TANROCK7 texture - TANROCK8 texture - TEKBRON1 texture - TEKBRON2 texture - TEKGREN1 texture - TEKGREN2 texture - TEKGREN3 texture - TEKGREN4 texture - TEKGREN5 texture - TEKLITE texture - TEKLITE2 texture - TEKWALL1 texture - TEKWALL2 texture - TEKWALL3 texture - TEKWALL4 texture - TEKWALL5 texture - TEKWALL6 texture - WFALL1 texture - WFALL2 texture - WFALL3 texture - WFALL4 texture - WOOD10 texture - WOOD12 texture - WOOD6 texture - WOOD7 texture - WOOD8 texture - WOOD9 texture - WOODMET1 texture - WOODMET2 texture - WOODMET3 texture - WOODMET4 texture - WOODVERT texture - ZDOORB1 texture - ZDOORF1 texture - ZELDOOR texture - ZIMMER1 texture - ZIMMER2 texture - ZIMMER3 texture - ZIMMER4 texture - ZIMMER5 texture - ZIMMER7 texture - ZIMMER8 texture - ZZWOLF1 texture - ZZWOLF10 texture - ZZWOLF11 texture - ZZWOLF12 texture - ZZWOLF13 texture - ZZWOLF2 texture - ZZWOLF3 texture - ZZWOLF4 texture - ZZWOLF5 texture - ZZWOLF6 texture - ZZWOLF7 texture - ZZWOLF9 texture - ZZZFACE1 texture - ZZZFACE2 texture - ZZZFACE3 texture - ZZZFACE4 texture - ZZZFACE5 texture - ZZZFACE6 texture - ZZZFACE7 texture - ZZZFACE8 texture - ZZZFACE9 #---- FLATS ---------------- ## FIXME: assign to categories flat - BLOOD1 flat - BLOOD2 flat - BLOOD3 flat - CEIL1_1 flat - CEIL1_2 flat - CEIL1_3 flat - CEIL3_1 flat - CEIL3_2 flat - CEIL3_3 flat - CEIL3_4 flat - CEIL3_5 flat - CEIL3_6 flat - CEIL4_1 flat - CEIL4_2 flat - CEIL4_3 flat - CEIL5_1 flat - CEIL5_2 flat - COMP01 flat - CONS1_1 flat - CONS1_5 flat - CONS1_7 flat - CRATOP1 flat - CRATOP2 flat - DEM1_1 flat - DEM1_2 flat - DEM1_3 flat - DEM1_4 flat - DEM1_5 flat - DEM1_6 flat - FLAT1 flat - FLAT10 flat - FLAT1_1 flat - FLAT1_2 flat - FLAT1_3 flat - FLAT14 flat - FLAT17 flat - FLAT18 flat - FLAT19 flat - FLAT2 flat - FLAT20 flat - FLAT22 flat - FLAT23 flat - FLAT3 flat - FLAT4 flat - FLAT5 flat - FLAT5_1 flat - FLAT5_2 flat - FLAT5_3 flat - FLAT5_4 flat - FLAT5_5 flat - FLAT5_6 flat - FLAT5_7 flat - FLAT5_8 flat - FLAT8 flat - FLAT9 flat - FLOOR0_1 flat - FLOOR0_2 flat - FLOOR0_3 flat - FLOOR0_5 flat - FLOOR0_6 flat - FLOOR0_7 flat - FLOOR1_1 flat - FLOOR1_6 flat - FLOOR1_7 flat - FLOOR3_3 flat - FLOOR4_1 flat - FLOOR4_5 flat - FLOOR4_6 flat - FLOOR4_8 flat - FLOOR5_1 flat - FLOOR5_2 flat - FLOOR5_3 flat - FLOOR5_4 flat - FLOOR6_1 flat - FLOOR6_2 flat - FLOOR7_1 flat - FLOOR7_2 flat - F_SKY1 flat - FWATER1 flat - FWATER2 flat - FWATER3 flat - FWATER4 flat - GATE1 flat - GATE2 flat - GATE3 flat - GATE4 flat - GRASS1 flat - GRASS2 flat - GRNLITE1 flat - GRNROCK flat - LAVA1 flat - LAVA2 flat - LAVA3 flat - LAVA4 flat - MFLR8_1 flat - MFLR8_2 flat - MFLR8_3 flat - MFLR8_4 flat - NUKAGE1 flat - NUKAGE2 flat - NUKAGE3 flat - RROCK01 flat - RROCK02 flat - RROCK03 flat - RROCK04 flat - RROCK05 flat - RROCK06 flat - RROCK07 flat - RROCK08 flat - RROCK09 flat - RROCK10 flat - RROCK11 flat - RROCK12 flat - RROCK13 flat - RROCK14 flat - RROCK15 flat - SFLR6_1 flat - SFLR6_4 flat - SFLR7_1 flat - SFLR7_4 flat - SLIME01 flat - SLIME02 flat - SLIME03 flat - SLIME04 flat - SLIME05 flat - SLIME06 flat - SLIME07 flat - SLIME08 flat - SLIME09 flat - SLIME10 flat - SLIME11 flat - SLIME12 flat - SLIME13 flat - SLIME14 flat - SLIME15 flat - SLIME16 flat - STEP1 flat - STEP2 flat - TLITE6_1 flat - TLITE6_4 flat - TLITE6_5 flat - TLITE6_6 eureka-editor-eureka-2.0.2/games/harm1.ugh000066400000000000000000000132621464327712600203560ustar00rootroot00000000000000#------------------------------------------------------------------------ # HARMONY 1.1 definitions #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2016 Andrew Apted # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ base_game harmony player_size 16 56 41 sky_flat F_SKY1 default_textures PANEL2 FLAT10 FLAT20 default_thing 2011 feature tag_666 1 feature lax_sprites 1 include "doom_groups" include "doom_lines" include "doom_sectors" #---- COLORS -------------------- color sky 244 color wall 28 3 color floor 140 130 color invis 14 24 color missing 39 color unknown_tex 241 color unknown_flat 250 color unknown_thing 117 #---- THINGS ---------------- thinggroup p 4F4 "Player" thinggroup m F00 "Monster" thinggroup w FA0 "Weapon" thinggroup a 850 "Ammunition" thinggroup h 280 "Health && Armor" thinggroup b 280 "Bonus" thinggroup k F0F "Key" thinggroup d 66C "Decoration" thinggroup g 850 "Gore" thinggroup - 0BD "OTHER" thing 1 p - 16 PLAY "Player 1 start" 0.30 thing 2 p - 16 PLAY "Player 2 start" 0.30 thing 3 p - 16 PLAY "Player 3 start" 0.30 thing 4 p - 16 PLAY "Player 4 start" 0.30 thing 11 p t 16 PLAYF1 "Deathmatch start" 0.30 thing 14 p t 16 FATBA3A7 "Teleport exit" thing 5 k nl 20 BKEY "Green keycard" 0.30 thing 6 k nl 20 YKEY "Yellow keycard" 0.30 thing 13 k nl 20 RKEY "Purple keycard" 0.30 thing 38 k nl 20 BSKU "Green PP key" 0.30 thing 39 k nl 20 YSKU "Yellow PP key" 0.30 thing 40 k nl 20 RSKU "Purple PP key" 0.30 thing 8 b n 20 BPAKA "Backpack" 0.30 thing 2026 b n 20 PMAPA "Computer map" 0.30 thing 2010 b n 20 ROCKA "Time Bomb" 0.30 thing 30 d - 16 COL1A "Big Mushroom" 0.30 thing 34 d l 20 CBRAA "White candle" 0.30 thing 36 d l 16 MISLB "Looping explosion" 0.30 thing 45 d - 16 TGRNA "Dopefish" 0.50 thing 46 d - 16 TREDA "Green splash" 0.30 thing 48 d l 16 ELECA "Tall lamp" 0.30 thing 28 d - 16 POL2A "Tentacle" 0.30 thing 27 d - 16 SMT2A "Rocket standing" 0.30 thing 29 d l 16 POL3A "Rocket launched" 0.30 thing 31 d - 16 COL2A "Truck pipe" 0.30 thing 32 d - 16 COL3A "Abducted Amira" 0.30 thing 33 d - 16 COL4A "Arty sphere" 0.30 thing 37 d - 16 COL6A "Shell head" 0.30 thing 42 d - 16 FSKUA "Dripping water" 0.30 thing 47 d - 16 SMITA "Gray Blob" 0.30 thing 51 d - 16 GOR3A "Neutronbeam blocker" 0.30 thing 54 d - 32 TRE2A "Large tree" 0.30 thing 55 d l 16 SMBTA "Fire" 0.30 thing 56 d cl 16 SMGTA "Spark from ceiling" 0.30 thing 57 d - 16 SMRTA "Firebox" 0.30 thing 63 d cl 20 GOR1A "Hanging fire" 0.30 thing 73 d c 16 HDB1A "Hanging chain" 0.30 thing 74 d - 16 HDB2A "Stored miniguns" 0.30 thing 75 d - 16 HDB3A "Stored shotguns" 0.30 thing 81 d cl 20 BRS1A "Hanging light" 0.30 thing 3006 d - 16 PAINA "Mine" 0.30 thing 15 g n 20 ARM2B "Dead Amazone" 0.30 thing 19 g n 20 ARM1B "Dead Follower" 0.30 thing 21 g n 20 SARGN "Dead Beastling" 0.30 thing 44 g n 16 TBLUA "Dead Beastling 2" 0.30 thing 18 g n 20 NULL "Dead Giblet" 0.30 thing 2007 g n 20 CEYEB "Flies" 0.30 thing 2028 d l 16 COLUA "Laser lamp" 0.30 thing 2035 d - 10 BAR1A "Red barrel" 0.30 thing 2001 w n 20 SHOTA "Compensator" 0.30 thing 2002 w n 20 MGUNA "Minigun" 0.30 thing 2003 w n 20 LAUNA "Grenade launcher" 0.30 thing 2004 w n 20 PLASA "Entrophy thrower" 0.30 thing 17 a n 20 CELPA "Chaos bars" 0.30 thing 2006 a n 20 BFUGA "Grenade" 0.30 thing 2046 a n 20 BROKA "Belt with grenades" 0.30 thing 2048 a n 20 AMMOA "Minigun ammo" 0.30 thing 2049 a n 20 SBOXA "Box of shells" 0.30 thing 2011 h n 20 STIMA "Mushroom" 0.30 thing 2012 h n 20 MEDIA "Medkit" 0.30 thing 2013 h n 20 SOULA "Big Mushroom" 0.30 thing 2018 h n 20 ARM1A "Red Armor" 0.30 thing 2019 h n 20 ARM2A "NDF armor" 0.30 thing 9 m - 20 SPOSA "Follower" 0.30 thing 64 m - 20 FCANB "Falling Follower" 0.30 thing 65 m - 20 CPOSA "Soldier" 0.30 thing 16 m - 40 CYBRA "Predator" 0.30 thing 66 m - 20 CYBRA "Centaur" 0.30 thing 68 m - 64 SSWVA "Phage" 0.30 thing 3003 m - 24 BOSSA "Critter" 0.30 thing 3004 m - 30 SARGA "Beastling" 0.30 thing 7 m - 128 POSSA "Echidna Boss" 0.30 thing 26 - - 16 HEADH "Shootable crate" 0.30 thing 3002 - - 30 NULL "Window smash fx" thing 67 - - 48 NULL "THING #67 fx" thing 79 - - 20 NULL "Crate explode fx" thing 87 - nl 16 NULL "Spawn spot" thing 88 - - 16 NULL "Boss brain" thing 89 - - 16 NULL "Boss shooter" #---- TEXTURES ---------------- # TODO #---- FLATS ---------------- # TODO eureka-editor-eureka-2.0.2/games/heretic.ugh000066400000000000000000000341471464327712600207760ustar00rootroot00000000000000#------------------------------------------------------------------------ # HERETIC definitions #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2012-2018 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ # # This game definition is derived partially from the Unofficial # Heretic Specs by John "DrSleep" Anderson, partially from the # Heretic source code, and partially from YADEX (which probably # used the other two sources anyway). # #------------------------------------------------------------------------ base_game heretic player_size 16 56 41 sky_flat F_SKY1 default_textures SANDSQ2 FLOOR00 FLOOR30 # 10 = wand crystal default_thing 10 # value 2 enables Heretic-specific checks feature tag_666 2 #---- COLORS -------------------- color sky 199 color wall 6 35 color floor 68 94 color invis 2 12 color missing 244 color unknown_tex 205 color unknown_flat 222 color unknown_thing 173 #---- THING TYPES --------------- thinggroup p 4F4 "Player" thinggroup m F00 "Monster" thinggroup w FA0 "Weapon" thinggroup a 850 "Ammunition" thinggroup h 280 "Health && Armor" thinggroup b 280 "Bonus" thinggroup k F0F "Key" thinggroup d 66C "Decoration" thinggroup l 66C "Light Source" thinggroup s DAD "Sounds" thinggroup - 0BD "OTHER" thing 1 p - 16 PLAY "Player 1" thing 2 p - 16 PLAY "Player 2" thing 3 p - 16 PLAY "Player 3" thing 4 p - 16 PLAY "Player 4" thing 11 p t 16 PLAYF1 "Deathmatch start" thing 14 p t 20 TELE "Teleport Spot" thing 2005 w n 20 WGNT "Gauntlets" thing 2001 w n 20 WBOW "Ethereal Crossbow" thing 53 w n 20 WBLS "Dragon Claw" thing 2004 w n 20 WSKL "Hellstaff" thing 2003 w n 20 WPHX "Phoenix Rod" thing 2002 w n 20 WMCE "Mace" thing 10 a n 20 AMG1 "Wand Crystal" thing 12 a n 20 AMG2 "Wand Geode" thing 18 a n 20 AMC1 "Ethereal Arrows" thing 19 a n 20 AMC2 "Ethereal Quiver" thing 54 a n 20 AMB1 "Claw Orb" thing 55 a n 20 AMB2 "Energy Orb" thing 20 a n 20 AMS1 "Lesser Runes" thing 21 a n 20 AMS2 "Greater Runes" thing 22 a n 20 AMP1 "Flame Orb" thing 23 a n 20 AMP2 "Inferno Orb" thing 13 a n 20 AMM1 "Mace Spheres" thing 16 a n 20 AMM2 "Pile of Mace Spheres" thing 81 h n 20 PTN1 "Crystal Vial" thing 82 h n 20 PTN2 "Quartz Flask" thing 32 h n 20 SPHL "Mystic Urn" thing 85 h n 20 SHLD "Shield (Silver)" thing 31 h n 20 SHD2 "Shield (Enchanted)" thing 8 b n 20 BAGH "Bag of Holding" thing 30 b n 20 EGGC "Morph Ovum" thing 34 b n 20 FBMB "Time Bomb" thing 83 b n 20 SOAR "Wings of Wrath" thing 75 b n 20 INVS "Shadowsphere" thing 84 b nl 20 INVU "Ring of Invulnerability" thing 35 b n 20 SPMP "Map Scroll" thing 36 b n 20 ATLP "Chaos Device" thing 86 b n 20 PWBK "Tome of Power" thing 33 b nl 20 TRCH "Torch" thing 73 k nl 20 AKYY "Green Key" thing 79 k nl 20 BKYY "Blue Key" thing 80 k nl 20 CKYY "Yellow Key" thing 94 k -l 16 KGZB "Blue Key Statue" thing 95 k -l 16 KGZG "Green Key Statue" thing 96 k -l 16 KGZY "Yellow Key Statue" thing 44 d - 12 BARL "Barrel" thing 47 d - 14 BRPL "Brown Pillar" thing 48 d nc 20 MOS1 "Moss 1" thing 49 d nc 20 MOS2 "Moss 2" thing 51 d -c 8 HCOR "Hanging Corpse" thing 26 d nc 20 SKH4 "Hanging Skull 35" thing 25 d nc 20 SKH3 "Hanging Skull 45" thing 24 d nc 20 SKH2 "Hanging Skull 60" thing 17 d nc 20 SKH1 "Hanging Skull 70" thing 29 d - 16 SMPL "Small Pillar" thing 37 d - 8 STGS "Stalagmite (small)" thing 38 d - 12 STGL "Stalagmite (large)" thing 39 d c 8 STCS "Stalactite (small)" thing 40 d c 12 STCL "Stalactite (large)" thing 87 d n- 12 VLCO "Volcano" thing 74 d nl 20 TGLT "Teleport Glitter" thing 52 d nl 20 TGLTF0 "Teleport Glitter (exit)" thing 28 l nlc 20 CHDL "Chandelier" thing 76 l -l 20 KFR1 "Fire Brazier" thing 27 l -l 20 SRTC "Serpent Torch" thing 50 l nl 20 WTRH "Wall Torch" thing 2035 - - 16 PPOD "Pod" thing 43 - n 20 NULL "Pod Generator" thing 66 m - 20 IMPX "Gargoyle" thing 5 m - 20 IMPX "Fire Gargoyle" thing 68 m - 20 MUMM "Golem" thing 69 m i 20 MUMM "Golem Ghost" thing 45 m - 20 MUMMY1 "Nitro Golem" thing 46 m i 20 MUMMY1 "Nitro Golem Ghost" thing 64 m - 20 KNIG "Undead Warrior" thing 65 m i 20 KNIG "Undead Warrior Ghost" thing 15 m - 20 WZRD "Disciple" thing 70 m - 20 BEAS "Weredragon" thing 90 m - 20 CLNK "Sabreclaw" thing 6 m - 20 HEAD "Ironlich" thing 9 m - 20 MNTR "Maulotaur" thing 92 m - 20 SNKE "Ophidian" thing 7 m - 20 SRCR "D'Sparil" thing 56 m t 20 SOR2H0 "D'Sparil Spot" thing 1202 s nv 16 NULL "Sound: Waterdrip" thing 1203 s nv 16 NULL "Sound: Slow Footsteps" thing 1204 s nv 16 NULL "Sound: Heartbeat" thing 1205 s nv 16 NULL "Sound: Bells" thing 1208 s nv 16 NULL "Sound: Laughter" thing 1209 s nv 16 NULL "Sound: Fast Footsteps" thing 1200 s nv 16 NULL "Sound: Scream" thing 1201 s nv 16 NULL "Sound: Squish" thing 1206 s nv 16 NULL "Sound: Growl" thing 1207 s nv 16 NULL "Sound: Magic" thing 42 s nv 20 NULL "Env: Wind" thing 41 s nv 20 NULL "Env: Waterfall" #---- LINE TYPES ---------------- include "doom_groups" line 0 - "-- NOTHING" line 48 a "-- Scroll Left" line 99 a "-- Scroll Right" line 31 d "D1 Open door (stays open)" line 1 d "DR Open door" line 46 d "GR Open door (stays open)" :tag line 50 d "S1 Close door" :tag line 103 d "S1 Open door (stays open)" :tag line 29 d "S1 Open door" :tag line 42 d "SR Close door" :tag line 61 d "SR Open door (stays open)" :tag line 63 d "SR Open door" :tag line 3 d "W1 Close door" :tag line 16 d "W1 Close door for 30 seconds" :tag line 2 d "W1 Open door (stays open)" :tag line 4 d "W1 Open door" :tag line 75 d "WR Close door" :tag line 76 d "WR Close door for 30 seconds" :tag line 86 d "WR Open door (stays open)" :tag line 90 d "WR Open door" :tag line 100 d "WR Open door (turbo)" :tag line 32 k "D1 Open blue door (stays open)" line 26 k "DR Open blue door" line 34 k "D1 Open yellow door (stays open)" line 27 k "DR Open yellow door" line 33 k "D1 Open green door (stays open)" line 28 k "DR Open green door" # the "S1" and "W1" are lowercase here to inhibit the map checking # functions complaining about missing tag numbers. line 11 e "s1 Exit level" line 51 e "s1 Secret exit" line 52 e "w1 Exit level" line 105 e "w1 Secret exit" line 71 f "S1 Lower turbo floor to HEF + 8" :tag line 102 f "S1 Lower floor to HEF" :tag line 23 f "S1 Lower floor to LEF" :tag line 70 f "SR Lower turbo floor to HEF + 8" :tag line 45 f "SR Lower floor to HEF" :tag line 60 f "SR Lower floor to LEF" :tag line 36 f "W1 Lower turbo floor to HEF + 8" :tag line 37 f "W1 Lower floor to LEF (NXP)" :tag line 19 f "W1 Lower floor to HEF" :tag line 38 f "W1 Lower floor to LEF" :tag line 98 f "WR Lower turbo floor to HEF + 8" :tag line 84 f "WR Lower floor to LEF (NXP)" :tag line 83 f "WR Lower floor to HEF" :tag line 82 f "WR Lower floor to LEF" :tag line 21 p "S1 Lower lift" :tag line 62 p "SR Lower lift" :tag line 10 p "W1 Lower lift" :tag line 88 p "WR Lower lift" :tag line 53 m "W1 Start Moving Floor" :tag line 54 m "W1 Stop Moving Floor" :tag line 87 m "WR Start Moving Floor" :tag line 89 m "WR Stop Moving Floor" :tag line 7 s "S1 Raise stairs by 8" :tag line 107 s "S1 Raise stairs by 16" :tag line 8 s "W1 Raise stairs by 8" :tag line 106 s "W1 Raise stairs by 16" :tag line 39 - "W1 Teleport" :tag line 97 - "WR Teleport" :tag line 6 h "W1 Crusher" :tag line 77 h "WR Crusher" :tag line 25 h "W1 Crusher /slow" :tag line 73 h "WR Crusher /slow" :tag line 57 h "W1 Stop Crusher" :tag line 74 h "WR Stop Crusher" :tag line 47 g "G1 Raise floor to nhEF (TX)" :tag line 24 g "G1 Raise floor to LIC" :tag line 55 g "S1 Raise floor to LIC - 8, crush" :tag line 101 g "S1 Raise floor to LIC" :tag line 18 g "S1 Raise floor to nhEF" :tag line 20 g "S1 Raise floor to nhEF (TX)" :tag line 15 g "S1 Raise floor by 24 (TX)" :tag line 14 g "S1 Raise floor by 32 (TX)" :tag line 65 g "SR Raise floor to LIC - 8, crush" :tag line 69 g "SR Raise floor to nhEF" :tag line 64 g "SR Raise floor to LIC" :tag line 66 g "SR Raise floor by 24 (TX)" :tag line 67 g "SR Raise floor by 32 (TX)" :tag line 68 g "SR Raise floor to nhEF (TX)" :tag line 59 g "W1 Raise floor by 24 (TXP)" :tag line 58 g "W1 Raise floor by 24" :tag line 5 g "W1 Raise floor to LIC" :tag line 30 g "W1 Raise floor by ShortestLowerTexture" :tag line 22 g "W1 Raise floor to nhEF (TX)" :tag line 56 g "W1 Raise floor to LIC - 8, crush" :tag line 93 g "WR Raise floor by 24 (TXP)" :tag line 94 g "WR Raise floor to LIC - 8, crush" :tag line 95 g "WR Raise floor to nhEF (TX)" :tag line 92 g "WR Raise floor by 24" :tag line 91 g "WR Raise floor to LIC" :tag line 96 g "WR Raise floor by ShortestLowerTexture" :tag line 13 l "W1 Light level goes to 255" :tag line 35 l "W1 Light level goes to 35" :tag line 12 l "W1 Light level goes to HE" :tag line 104 l "W1 Light level goes to LE" :tag line 81 l "WR Light level goes to 255" :tag line 79 l "WR Light level goes to 35" :tag line 80 l "WR Light level goes to HE" :tag line 17 l "W1 Lignt blinking 1 Hz" :tag line 49 c "S1 Lower ceiling to floor + 8" :tag line 41 c "S1 Lower ceiling to floor" :tag line 43 c "SR Lower ceiling to floor" :tag line 44 c "W1 Lower ceiling to floor + 8" :tag line 40 c "W1 Raise ceiling to HEC, floor to LEF" :tag line 72 c "WR Lower ceiling to floor + 8" :tag line 9 - "S1 Donut (lower outer, raise inner)" :tag #---- SECTOR TYPES ----------- sector 0 "NOTHING" sector 1 "Light: Flickering" sector 2 "Light: Fast Strobe" sector 3 "Light: Slow Strobe" sector 8 "Light: Glowing" sector 12 "Light: Synch (Slow)" sector 13 "Light: Synch (Fast)" sector 6 "Ceiling Crush & Raise" sector 14 "Door: Raise in 5 min" sector 10 "Door: Close in 30 sec" sector 15 "Low Friction" sector 9 "Secret Area" sector 7 "Damage: Sludge" sector 4 "Damage: Lava Flow" sector 5 "Damage: Lava (Light)" sector 16 "Damage: Lava (Heavy)" sector 21 "Scroll: East (slow)" sector 22 "Scroll: East (normal)" sector 23 "Scroll: East (fast)" sector 26 "Scroll: North (slow)" sector 27 "Scroll: North (normal)" sector 28 "Scroll: North (fast)" sector 31 "Scroll: South (slow)" sector 32 "Scroll: South (normal)" sector 33 "Scroll: South (fast)" sector 36 "Scroll: West (slow)" sector 37 "Scroll: West (normal)" sector 38 "Scroll: West (fast)" sector 40 "Wind: East (weak)" sector 41 "Wind: East (normal)" sector 42 "Wind: East (strong)" sector 43 "Wind: North (weak)" sector 44 "Wind: North (normal)" sector 45 "Wind: North (strong)" sector 46 "Wind: South (weak)" sector 47 "Wind: South (normal)" sector 48 "Wind: South (strong)" sector 49 "Wind: West (weak)" sector 50 "Wind: West (normal)" sector 51 "Wind: West (strong)" #---- TEXTURE CATEGORIES ----------- texturegroup c "Castle" texturegroup d "Door && Metal" texturegroup g "Grating" texturegroup l "Liquid" texturegroup m "Magic" texturegroup v "Village" texturegroup - "OTHER" texture c BANNER1 texture c BANNER2 texture c BANNER3 texture c BANNER4 texture c BANNER5 texture c BANNER6 texture c BANNER7 texture c BANNER8 texture c CHAINSD texture c CSTLMOSS texture c CSTLRCK texture c GRNBLOK1 texture c GRNBLOK2 texture c GRNBLOK3 texture c GRNBLOK4 texture c GRSTNPB texture c GRSTNPBV texture c GRSTNPBW texture c LOOSERCK texture c MOSSRCK1 texture c ORNGRAY texture c REDWALL texture c SANDSQ2 texture c SNDBLCKS texture c SNDCHNKS texture c SNDPLAIN texture c SPINE1 texture c SPINE2 texture c SQPEB1 texture c SQPEB2 texture c TRISTON1 texture c TRISTON2 texture c WOODWL texture d CHAINMAN texture d DMNMSK texture d DOORWOOD texture d DOOREXIT texture d DOORSTON texture d GRSKULL1 texture d GRSKULL2 texture d GRSKULL3 texture d HORSES1 texture d SKULLSB1 texture d SKULLSB2 texture d SAINT1 texture d METL1 texture d METL2 texture d SW1OFF texture d SW1ON texture d SW2OFF texture d SW2ON texture g GATMETL texture g GATMETL2 texture g GATMETL3 texture g GATMETL4 texture g GATMETL5 texture g WDGAT64 texture g WEB1_B texture g WEB1_F texture g WEB2_B texture g WEB2_F texture g WEB3_M texture g STNGLS1 texture g STNGLS2 texture g STNGLS3 texture l LAVA1 texture l LAVAFL1 texture l LAVAFL2 texture l LAVAFL3 texture l WATRWAL1 texture l WATRWAL2 texture l WATRWAL3 texture v BRWNRCKS texture v CELTIC texture v CTYSTCI1 texture v CTYSTCI2 texture v CTYSTCI4 texture v CTYSTUC1 texture v CTYSTUC2 texture v CTYSTUC3 texture v CTYSTUC4 texture v CTYSTUC5 texture v DRIPWALL texture v RCKSNMUD texture v ROOTWALL texture v TMBSTON1 texture v TMBSTON2 texture v BLUEFRAG texture v MOSAIC1 texture v MOSAIC2 texture v MOSAIC3 texture v MOSAIC4 texture v MOSAIC5 texture - OLDSKY2 texture - OLDSKY3 texture - SKY1 texture - SKY2 texture - SKY3 texture - SKY5 flat c FLAT500 flat c FLAT503 flat c FLAT504 flat c FLAT520 flat c FLAT521 flat c FLAT522 flat c FLAT523 flat c FLOOR00 flat c FLOOR01 flat c FLOOR03 flat c FLOOR06 flat c FLOOR07 flat c FLOOR09 flat c FLOOR18 flat c FLOOR19 flat c FLOOR20 flat l FLATHUH1 flat l FLATHUH2 flat l FLATHUH3 flat l FLATHUH4 flat l FLTFLWW1 flat l FLTFLWW2 flat l FLTFLWW3 flat l FLTLAVA1 flat l FLTLAVA2 flat l FLTLAVA3 flat l FLTLAVA4 flat l FLTSLUD1 flat l FLTSLUD2 flat l FLTSLUD3 flat l FLTWAWA1 flat l FLTWAWA2 flat l FLTWAWA3 flat l FLAT517 flat v FLAT502 flat v FLAT506 flat v FLAT507 flat v FLAT508 flat v FLAT509 flat v FLAT510 flat v FLAT512 flat v FLAT513 flat v FLAT516 flat v FLOOR04 flat v FLOOR05 flat v FLOOR10 flat v FLOOR11 flat v FLOOR12 flat v FLOOR16 flat v FLOOR17 flat v FLOOR25 flat v FLOOR27 flat m FLTTELE1 flat m FLTTELE2 flat m FLTTELE3 flat m FLTTELE4 flat - F_SKY1 flat - FLOOR08 flat - FLOOR21 flat - FLOOR22 flat - FLOOR23 flat - FLOOR24 flat - FLOOR26 flat - FLOOR28 flat - FLOOR29 flat - FLOOR30 eureka-editor-eureka-2.0.2/games/hexen.ugh000066400000000000000000000473251464327712600204640ustar00rootroot00000000000000#------------------------------------------------------------------------ # HEXEN DEFINITIONS #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2015 Ioan Chera # Copyright (C) 2015-2018 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ # # Thanks to the the Official Hexen Specs by Ben Morris (et al). # See http://doomlegacy.sourceforge.net/hosted/hexenspec09.txt # #------------------------------------------------------------------------ base_game hexen player_size 16 64 48 sky_flat F_SKY default_textures CASTLE07 F_009 F_082 default_thing 81 # healing vial include "hexen_groups" include "hexen_lines" include "hexen_sectors" #---- COLORS -------------------- color sky 219 color wall 6 32 color floor 81 96 color invis 2 12 color missing 227 color unknown_tex 223 color unknown_flat 213 color unknown_thing 236 #---- THING TYPES --------------- thinggroup p 4F4 "Player" thinggroup m F00 "Monster" thinggroup w FA0 "Weapon" thinggroup a 850 "Ammunition" thinggroup h 280 "Health && Armor" thinggroup b 280 "Bonus" thinggroup k F0F "Key" thinggroup j F0F "Puzzle Piece" thinggroup d 66C "Decoration" thinggroup n 66C "Natural" thinggroup s DAD "Sounds" thinggroup - 0BD "OTHER" thing 1 p - 16 PLAY "Player 1 start" thing 2 p - 16 CLER "Player 2 start" thing 3 p - 16 CLER "Player 3 start" thing 4 p - 16 MAGE "Player 4 start" thing 11 p t 16 MAGEF1 "Deathmatch start" thing 14 p t 16 TELE "Teleport exit" thing 9100 p - 16 PLAY "Player 5 start" thing 9101 p - 16 CLER "Player 6 start" thing 9102 p - 16 CLER "Player 7 start" thing 9103 p - 16 MAGE "Player 8 start" thing 10 w n 20 WCSS "Serpent staff" thing 8010 w n 20 WFAX "Axe" thing 53 w nl 20 WMCS "Frost shards" thing 8009 w nl 20 WCFM "Fire storm" thing 123 w n 20 WFHM "Hammer" thing 8040 w nl 20 WMLGH0 "Lightning" thing 20 w nl 20 WCH3 "Wraithverge shaft" thing 19 w nl 20 WCH2 "Wraithverge cross" thing 18 w nl 20 WCH1 "Wraithverge arc" thing 16 w nl 20 WFR3 "Quietus hilt" thing 13 w nl 20 WFR2 "Quietus crosspiece" thing 12 w nl 20 WFR1 "Quietus blade" thing 23 w nl 20 WMS3 "Bloodscourge stick" thing 22 w nl 20 WMS2 "Bloodscourge stub" thing 21 w nl 20 WMS1 "Bloodscourge skull" thing 8000 b n 20 PSBG "Flechette" thing 8003 b n 20 BMAN "Krater of might" thing 8002 b nl 20 SPEDB0 "Boots of speed" thing 8041 b nl 20 BRACC0 "Dragonskin bracers" thing 84 b n 20 INVU "Icon of the defender" thing 30 b n 20 PORK "Porkalator" thing 83 b n 20 SOARB0 "Wings of wrath" thing 32 b n 20 SPHL "Mystic urn" thing 82 b n 20 PTN2 "Quartz flask" thing 10120 b nl 20 HRAD "Mystic ambit incant" thing 10110 b nl 20 BLST "Disc of repulsion" thing 86 b n 20 SUMN "Dark servant" thing 36 b n 20 ATLP "Chaos device" thing 33 b nl 20 TRCH "Torch" thing 10040 b n 20 TELO "Banishment device" thing 8008 h n 20 ARM4 "Amulet of warding" thing 8005 h n 20 ARM1 "Mesh armor" thing 8007 h n 20 ARM3 "Platinum helm" thing 8006 h n 20 ARM2 "Falcon shield" thing 81 h n 20 PTN1 "Healing vial" thing 122 a nl 8 MAN1 "Blue mana" thing 124 a nl 8 MAN2 "Green mana" thing 8004 a nl 8 MAN3 "Combined mana" thing 114 m - 22 BISH "Dark bishop" thing 107 m - 20 CENT "Centaur" thing 115 m l 20 CENTF1 "Slaughtaur" thing 31 m - 32 DEMN "Chaos serpent" thing 8080 m - 32 DEM2 "Chaos serpent 2" thing 254 m - 20 DRAG "Death wyvern" thing 10030 m - 25 ETTN "Ettin" thing 10060 m l 20 FDMN "Afrit" thing 10080 m - 40 SORC "Heresiarch" thing 8020 m - 22 ICEY "Wendigo" thing 10200 m - 65 KORX "Korax" thing 121 m - 32 SSPTI1 "Stalker" thing 120 m - 32 SSPTK1 "Stalker leader" thing 34 m - 20 WRTH "Wraith" thing 10011 m - 20 WRTH "Buried wraith" thing 10100 m - 16 PLAYE "Zedek" thing 10101 m - 16 CLERE "Traductus" thing 10102 m - 16 MAGEE "Mage boss" thing 8032 k n 8 KEY3 "Axe key" thing 8200 k n 8 KEYB "Castle key" thing 8031 k n 8 KEY2 "Cave key" thing 8035 k n 8 KEY6 "Dungeon key" thing 8033 k n 8 KEY4 "Fire key" thing 8034 k n 8 KEY5 "Emerald key" thing 8037 k n 8 KEY8 "Rusty key" thing 8036 k n 8 KEY7 "Silver key" thing 8030 k n 8 KEY1 "Steel key" thing 8039 k n 8 KEYA "Swamp key" thing 8038 k n 8 KEY9 "Horn key" thing 9002 j n 20 ASKU "Puzzle Skull" thing 9003 j n 20 ABGM "Puzzle GemBig" thing 9004 j n 20 AGMR "Puzzle GemRed" thing 9005 j n 20 AGMG "Puzzle GemGreen1" thing 9006 j n 20 AGMB "Puzzle GemBlue1" thing 9007 j n 20 ABK1 "Puzzle Book1" thing 9008 j n 20 ABK2 "Puzzle Book2" thing 9009 j n 20 AGG2 "Puzzle GemGreen2" thing 9010 j n 20 AGB2 "Puzzle GemBlue2" thing 9014 j n 20 ASK2 "Puzzle FlameMask" thing 9015 j n 20 AFWP "Puzzle FWeapon" thing 9016 j n 20 ACWP "Puzzle CWeapon" thing 9017 j n 20 AMWP "Puzzle MWeapon" thing 9018 j nl 20 AGER "Puzzle Gear1" thing 9019 j nl 20 AGR2 "Puzzle Gear2" thing 9020 j nl 20 AGR3 "Puzzle Gear3" thing 9021 j nl 20 AGR4 "Puzzle Gear4" thing 5 d - 10 STTW "Winged Statue" thing 54 d ln 20 WLTR "Wall Torch" thing 55 d n 20 WLTRI0 "WallTorch /unlit" thing 116 d l 10 TWTR "Twined Torch" thing 117 d - 10 TWTRI0 "Twined Torch /unlit" thing 119 d ln 20 CNDL "Candle" thing 61 d - 10 CPS1 "Corpse Kabob" thing 62 d n 20 CPS2 "Corpse Sleeping" thing 72 d - 14 STT2 "Gargoyle Green" thing 73 d - 14 STT3 "Gargoyle Blue" thing 74 d - 14 STT4 "Gargoyle Green /short" thing 76 d - 14 STT5 "Gargoyle Blue /short" thing 77 d - 8 BNR1 "Tattered Banner" thing 103 d - 12 VASE "Vase Pillar" thing 104 d - 10 POT1 "Pottery 1" 1 drop_item thing 105 d - 10 POT2 "Pottery 2" 1 drop_item thing 106 d - 15 POT3 "Pottery 3" 1 drop_item thing 110 d - 15 CPS6 "Corpse Sitting" thing 111 d n 20 BDPL "Blood Pool" thing 140 d n 20 TSMK "Teleport Smoke" thing 8042 d l 20 FBUL "FireBull" thing 8043 d - 20 FBULH0 "FireBull /unlit" thing 8044 d - 14 GAR1 "Gargoyle" thing 8045 d - 14 GAR2 "Gargoyle Dark" thing 8046 d - 14 GAR3 "Gargoyle Red" thing 8047 d - 14 GAR4 "Gargoyle Tan" thing 8048 d - 14 GAR5 "Gargoyle Rust" thing 8049 d - 14 GAR6 "Gargoyle Dark /short" thing 8050 d - 14 GAR7 "Gargoyle Red /short" thing 8051 d - 14 GAR8 "Gargoyle Tan /short" thing 8052 d - 14 GAR9 "Gargoyle Rust /short" thing 8060 d l 5 FSKL "Fire Thing" thing 8061 d l 6 BRTR "Brass Torch" thing 8064 d - 16 SUIT "Suit Of Armor" 1 drop_item thing 8066 d nl 20 CAND "Candle /blue" thing 8067 d - 12 IRON "Iron Maiden" thing 8069 d l 12 CDRNB0 "Cauldron" thing 8070 d - 12 CDRNA0 "Cauldron /unlit" thing 8100 d - 15 BARL "Barrel" thing 9011 d - 10 STWN "Winged Statue 2" thing 9012 d - 10 GMPD "Gem Pedestal" thing 17 d cn 20 CDLR "Chandelier" thing 8063 d cn 20 CDLRD0 "Chandelier /unlit" thing 71 d c 6 CPS3 "Corpse Hanging" thing 108 d c 11 CPS4 "Corpse Lynched" thing 109 d c 10 CPS5 "Corpse Lynched 2" thing 8065 d c 56 BBLL "Bell" thing 8071 d cn 4 CHNSA0 "Chain" thing 8072 d cn 4 CHNSB0 "Chain Long" thing 8073 d cn 4 CHNSC0 "Chain w/ heart" thing 8074 d cn 4 CHNSD0 "Chain Hook" thing 8075 d cn 4 CHNSE0 "Chain Hook 2" thing 8076 d cn 4 CHNSF0 "Chain Mace" thing 8077 d cn 4 CHNSG0 "Chain w/ skull" thing 8103 d c 8 BCKT "Bucket" thing 8500 d n 20 TST1 "Table Item 1" thing 8501 d n 20 TST2 "Table Item 2" thing 8502 d n 20 TST3 "Table Item 3" thing 8503 d n 20 TST4 "Table Item 4" thing 8504 d n 20 TST5 "Table Item 5" thing 8505 d n 20 TST6 "Table Item 6" thing 8506 d n 20 TST7 "Table Item 7" thing 8507 d n 20 TST8 "Table Item 8" thing 8508 d n 20 TST9 "Table Item 9" thing 8509 d n 20 TST0 "Table Item 10" thing 6 n n 20 RCK1 "Rock 1" thing 7 n n 20 RCK2 "Rock 2" thing 9 n n 20 RCK3 "Rock 3" thing 15 n - 20 RCK4 "Rock 4" thing 24 n - 10 TRE1 "Tree 1 /dead" thing 25 n - 15 TRE1 "Tree 1" thing 26 n - 10 TRE2 "Tree 2" thing 27 n - 10 TRE3 "Tree 3" thing 78 n - 15 TRE4 "Tree Large 1" thing 79 n - 15 TRE5 "Tree Large 2" thing 80 n - 22 TRE6 "Tree Gnarled" thing 87 n - 22 TRE7 "Tree Gnarled 2" thing 28 n - 12 STM1 "Stump 1" thing 29 n - 12 STM2 "Stump 2" thing 37 n n 20 STM3 "Stump 3" thing 38 n n 20 STM4 "Stump 4" thing 39 n n 20 MSH1 "Mushroom Large 1" thing 40 n n 20 MSH2 "Mushroom Large 2" thing 41 n n 20 MSH3 "Mushroom Large 3" thing 42 n n 20 MSH4 "Mushroom 1" thing 44 n n 20 MSH5 "Mushroom 2" thing 45 n n 20 MSH6 "Mushroom 3" thing 46 n n 20 MSH7 "Mushroom 4" thing 47 n n 20 MSH8 "Mushroom 5" thing 48 n - 8 SGMP "Stalagmite Pillar" thing 49 n - 8 SGM1 "Stalagmite Large" thing 50 n - 6 SGM2 "Stalagmite Medium" thing 51 n - 8 SGM3 "Stalagmite Small" thing 60 n - 8 SWMV "Swamp Vine" thing 63 n - 10 TMS1 "Tombstone 1" thing 64 n - 10 TMS2 "Tombstone 2" thing 65 n - 10 TMS3 "Tombstone 3" thing 66 n - 10 TMS4 "Tombstone 4" thing 67 n - 10 TMS5 "Tombstone 5" thing 68 n - 8 TMS6 "Tombstone 6" thing 69 n - 8 TMS7 "Tombstone 7" thing 88 n - 20 LOGG "Log" thing 93 n - 8 ICM1 "Ice Stalagmite Large" thing 94 n - 5 ICM2 "Ice Stalagmite Medium" thing 95 n - 4 ICM3 "Ice Stalagmite Small" thing 96 n - 4 ICM4 "Ice Stalagmite Tiny" thing 97 n - 17 RKBL "Boulder 1" thing 98 n - 15 RKBS "Boulder 2" thing 99 n - 20 RKBK "Boulder 3" thing 100 n n 20 RBL1 "Rubble 1" thing 101 n n 20 RBL2 "Rubble 2" thing 102 n n 20 RBL3 "Rubble 3" thing 8062 n - 15 TRDT "Destructible Tree" thing 8068 n - 11 XMAS "Xmas Tree" thing 8101 n - 8 SHB1 "Shrub 1" thing 8102 n - 16 SHB2 "Shrub 2" thing 8104 n - 6 SHRM "Poison Mushroom" thing 58 n cn 20 MSS1 "Moss Ceiling 1" thing 59 n cn 20 MSS2 "Moss Ceiling 2" thing 52 n c 8 SLC1 "Stalactite Large" thing 56 n c 6 SLC2 "Stalactite Medium" thing 57 n c 8 SLC3 "Stalactite Small" thing 89 n c 8 ICT1 "Ice Stalactite Large" thing 90 n c 5 ICT2 "Ice Stalactite Medium" thing 91 n c 4 ICT3 "Ice Stalactite Small" thing 92 n c 4 ICT4 "Ice Stalactite Tiny" thing 118 - - 32 NULL "Bridge" thing 9001 - n 20 _MSP "Map spot" thing 9013 - n 20 _MSP "Map spot /gravity" thing 3000 - nv 8 NULL "Polyobject anchor" thing 3001 - npv 8 NULL "Polyobject spot" thing 3002 - npv 8 NULL "Polyobject spot /crush" thing 1400 s n 8 NULL "Sndtype Stone" thing 1401 s n 8 NULL "Sndtype Heavy" thing 1402 s n 8 NULL "Sndtype Metal Sfx" thing 1403 s n 8 NULL "Sndtype Creak Sfx" thing 1404 s n 8 NULL "Sndtype Silent" thing 1405 s n 8 NULL "Sndtype Lava" thing 1406 s n 8 NULL "Sndtype Water" thing 1407 s n 8 NULL "Sndtype Ice" thing 1408 s n 8 NULL "Sndtype Earth" thing 1409 s n 8 NULL "Sndtype Metal2" thing 1410 s nv 8 NULL "Wind Sound" thing 113 - n 20 LEF1 "Leaf spawner" thing 10000 - nl 20 FOGM "Fog spawner" 1 speed spread frequency lifetime thing 10001 - n 20 FOGS "Fog /small" 1 speed - - lifetime moving thing 10002 - n 20 FOGM "Fog /medium" 1 speed - - lifetime moving thing 10003 - n 20 FOGL "Fog /large" 1 speed - - lifetime moving thing 10225 - n 20 ABAT "Bat spawner" 1 frequency spread duration angles thing 10500 - nl 20 FFSM "Flame Small /temp" thing 10501 - nl 20 FFSM "Flame Small" thing 10502 - nl 20 FFLG "Flame Large /temp" thing 10503 - nl 20 FFLG "Flame Large" #---- TEXTURES CATEGORIES ---------------- texturegroup c "Castle" texturegroup d "Door" texturegroup g "Grating" texturegroup m "Metal" texturegroup n "Natural" texturegroup p "Puzzle" texturegroup s "Switch" texturegroup - "OTHER" texture c BOOKS01 texture c BOOKS02 texture c BOOKS03 texture c BOOKS04 texture c BOSSK1 texture c BOSSK2 texture c CASTLE01 texture c CASTLE02 texture c CASTLE03 texture c CASTLE04 texture c CASTLE05 texture c CASTLE06 texture c CASTLE07 texture c CASTLE08 texture c CASTLE09 texture c CAVE07 texture c CRATE01 texture c CRATE02 texture c CRATE03 texture c CRATE04 texture c CRATE05 texture c FIRE01 texture c FIRE02 texture c FIRE03 texture c FIRE04 texture c FIRE05 texture c FIRE06 texture c FIRE07 texture c FIRE08 texture c FIRE09 texture c FIRE10 texture c FIRE11 texture c FIRE12 texture c FIRE14 texture c FIRE15 texture c FIRE16 texture c FIRE17 texture c FOREST05 texture c ICE02 texture c ICE03 texture c ICE06 texture c MONK01 texture c MONK02 texture c MONK03 texture c MONK04 texture c MONK05 texture c MONK06 texture c MONK07 texture c MONK08 texture c MONK09 texture c MONK11 texture c MONK12 texture c MONK14 texture c MONK15 texture c MONK16 texture c MONK17 texture c MONK18 texture c MONK19 texture c MONK21 texture c MONK22 texture c MONK23 texture c MONK24 texture c PILLAR01 texture c PILLAR02 texture c POOT texture c PRTL02 texture c PRTL03 texture c PRTL04 texture c PRTL05 texture c PRTL06 texture c PRTL07 texture c SEWER01 texture c SEWER02 texture c SEWER05 texture c SEWER06 texture c SEWER07 texture c SEWER08 texture c SEWER09 texture c SEWER10 texture c SEWER11 texture c SEWER12 texture c SEWER13 texture c SEWER14 texture c S_02 texture c S_04 texture c S_05 texture c S_06 texture c S_07 texture c S_09 texture c S_12 texture c S_13 texture c T2_STEP texture c TOMB01 texture c TOMB02 texture c TOMB04 texture c TOMB05 texture c TOMB06 texture c TOMB07 texture c TOMB08 texture c TOMB09 texture c TOMB10 texture c TOMB11 texture c TOMB12 texture c TOMB13 texture c VILL01 texture c VILL04 texture c VILL05 texture c WINNOW02 texture c WOOD01 texture c WOOD02 texture c WOOD03 texture c WOOD04 flat c F_008 flat c F_009 flat c F_010 flat c F_011 flat c F_012 flat c F_013 flat c F_014 flat c F_015 flat c F_018 flat c F_021 flat c F_022 flat c F_023 flat c F_025 flat c F_027 flat c F_030 flat c F_031 flat c F_032 flat c F_037 flat c F_041 flat c F_042 flat c F_043 flat c F_044 flat c F_045 flat c F_046 flat c F_047 flat c F_048 flat c F_049 flat c F_050 flat c F_051 flat c F_052 flat c F_053 flat c F_054 flat c F_055 flat c F_057 flat c F_058 flat c F_077 flat c F_081 flat c F_082 flat c F_089 flat c F_092 flat c F_A501 texture d BRASS1 texture d BRASS3 texture d BRASS4 texture d DOOR51 texture d D_AXE texture d D_BRASS1 texture d D_BRASS2 texture d D_CAST texture d D_CAVE texture d D_CAVE2 texture d D_DUNGEO texture d D_END1 texture d D_END2 texture d D_END3 texture d D_END4 texture d D_ENDBR texture d D_ENDSLV texture d D_FIRE texture d D_RUST texture d D_SILKEY texture d D_SILVER texture d D_SLV1 texture d D_SLV2 texture d D_STEEL texture d D_SWAMP texture d D_SWAMP2 texture d D_WASTE texture d D_WD01 texture d D_WD02 texture d D_WD03 texture d D_WD04 texture d D_WD05 texture d D_WD06 texture d D_WD07 texture d D_WD08 texture d D_WD09 texture d D_WD10 texture d D_WINNOW texture g GATE01 texture g GATE02 texture g GATE03 texture g GATE04 texture g GATE51 texture g GATE52 texture g GATE53 texture g SEWER03 texture g SEWER04 texture g VILL06 texture g VILL07 texture g VILL08 texture g WEB1_L texture g WEB1_R texture g WEB2_L texture g WEB2_R texture g WEB3 texture g GLASS01 texture g GLASS02 texture g GLASS03 texture g GLASS04 texture g GLASS05 texture g GLASS06 texture g GLASS07 texture g TOMB03 texture g TOMB18 texture m FOREST10 texture m GILO1 texture m GILO2 texture m PLAT01 texture m PLAT02 texture m SPAWN01 texture m SPAWN02 texture m SPAWN03 texture m SPAWN04 texture m SPAWN05 texture m SPAWN06 texture m SPAWN07 texture m SPAWN08 texture m SPAWN09 texture m SPAWN10 texture m SPAWN11 texture m SPAWN12 texture m SPAWN13 texture m STEEL01 texture m STEEL02 texture m STEEL05 texture m STEEL06 texture m STEEL07 texture m STEEL08 texture m S_01 texture m VALVE01 texture m VALVE02 texture m VALVE1 texture m VALVE2 texture m WINN01 flat m F_061 flat m F_062 flat m F_063 flat m F_064 flat m F_065 flat m F_066 flat m F_067 flat m F_068 flat m F_069 flat m F_070 flat m F_071 flat m F_072 flat m F_073 flat m F_074 flat m F_075 flat m F_078 flat m F_083 flat m F_091 flat m F_081 flat m F_084 flat m F_085 flat m F_086 flat m F_087 flat m F_088 flat m X_012 flat m X_013 flat m X_014 flat m X_015 flat m X_016 texture n CAVE03 texture n CAVE04 texture n CAVE05 texture n CAVE06 texture n CHAP1 texture n CHAP2 texture n CHAP3 texture n FOREST06 texture n FOREST07 texture n ICE01 texture n WASTE01 texture n WASTE02 texture n WASTE03 texture n WASTE04 texture n GRAVE01 texture n GRAVE03 texture n GRAVE04 texture n GRAVE05 texture n GRAVE06 texture n GRAVE07 texture n GRAVE08 texture n CASTLE11 texture n CAVE01 texture n CAVE02 texture n CAVE11 texture n CAVE12 texture n FOREST01 texture n FOREST02 texture n FOREST03 texture n FOREST04 texture n FOREST11 texture n FOREST12 texture n SWAMP01 texture n SWAMP03 texture n SWAMP04 texture n SWAMP06 texture n SWAMP07 texture n S_11 texture n X_FIRE01 texture n X_FIRE02 texture n X_FIRE03 texture n X_FIRE04 texture n X_SWMP1 texture n X_SWMP2 texture n X_SWMP3 texture n X_SWR1 texture n X_SWR2 texture n X_SWR3 texture n X_WATER1 texture n X_WATER2 texture n X_WATER3 texture n X_WATER4 flat n F_001 flat n F_002 flat n F_003 flat n F_004 flat n F_005 flat n F_006 flat n F_007 flat n F_024 flat n F_033 flat n F_034 flat n F_038 flat n F_039 flat n F_040 flat n F_SKY flat n F_017 flat n F_019 flat n F_020 flat n F_076 flat n F_029 flat n F_028 flat n F_059 flat n X_001 flat n X_002 flat n X_003 flat n X_004 flat n X_005 flat n X_006 flat n X_007 flat n X_008 flat n X_009 flat n X_010 flat n X_011 texture p CLOCKA texture p CLOCKB texture p CLOCKC texture p CLOCK01 texture p CLOCK02 texture p CLOCK03 texture p CLOCK04 texture p CLOCK05 texture p CLOCK06 texture p CLOCK07 texture p CLOCK08 texture p CLOCK11 texture p CLOCK12 texture p CLOCK13 texture p CLOCK14 texture p CLOCK15 texture p CLOCK16 texture p CLOCK17 texture p CLOCK18 texture p FORPUZ1 texture p FORPUZ2 texture p FORPUZ3 texture p GEAR01 texture p GEAR02 texture p GEAR03 texture p GEAR04 texture p GEAR05 texture p GEAR0A texture p GEAR0B texture p GEARW texture p GEARX texture p GEARY texture p GEARZ texture p PLANET1 texture p PLANET2 texture p PUZZLE1 texture p PUZZLE2 texture p PUZZLE3 texture p PUZZLE4 texture p PUZZLE5 texture p PUZZLE6 texture p PUZZLE7 texture p PUZZLE8 texture p PUZZLE9 texture p PUZZLE10 texture p PUZZLE11 texture p PUZZLE12 texture s SW_1_DN texture s SW_1_MD texture s SW_1_UP texture s SW_2_DN texture s SW_2_MD texture s SW_2_UP texture s SW_EL1 texture s SW_EL2 texture s SW_EL3 texture s SW_EL4 texture s SW_EL5 texture s SW_OL1 texture s SW_OL2 texture s SW_OL3 texture s SW_OL4 texture s SW_OL5 texture s SW51_OFF texture s SW51_ON texture s SW52_OFF texture s SW52_ON texture s SW53_DN texture s SW53_MD texture s SW53_UP texture - BLANK texture - SKY1 texture - SKY2 texture - SKY3 texture - SKY4 texture - SKYFOG texture - SKYFOG2 texture - SKYWALL texture - SKYWALL2 texture - TPORTX texture - TPORT1 texture - TPORT2 texture - TPORT3 texture - TPORT4 texture - TPORT5 texture - TPORT6 texture - TPORT7 texture - TPORT8 texture - TPORT9 texture - X_FAC01 texture - X_FAC02 texture - X_FAC03 texture - X_FAC04 texture - X_FAC05 texture - X_FAC06 texture - X_FAC07 texture - X_FAC08 texture - X_FAC09 texture - X_FAC10 texture - X_FAC11 texture - X_FAC12 eureka-editor-eureka-2.0.2/games/plutonia.ugh000066400000000000000000000015461464327712600212030ustar00rootroot00000000000000#------------------------------------------------------------------------ # PLUTONIA EXPERIMENT (Final Doom) #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2019 Andrew Apted # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ include "doom2" include "plutonia_tex" eureka-editor-eureka-2.0.2/games/strife1.ugh000066400000000000000000000526031464327712600207250ustar00rootroot00000000000000#------------------------------------------------------------------------ # STRIFE DEFINITIONS #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2016 Andrew Apted # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ # # Most of this file is based on the Strife configuration files # of SLADE, a map and resource editor by Simon Judd. # #------------------------------------------------------------------------ base_game strife player_size 18 56 41 sky_flat F_SKY001 default_textures BRKBRN02 F_TECH01 F_TECH01 default_thing 84 feature strife_flags 1 #---- COLORS -------------------- color sky 250 color wall 6 28 color floor 164 184 color invis 21 31 color missing 231 color unknown_tex 150 color unknown_flat 105 color unknown_thing 172 #---- THING TYPES --------------- thinggroup p 4F4 "Player" thinggroup m F00 "Monster" thinggroup w FA0 "Weapon" thinggroup a 850 "Ammunition" thinggroup h 280 "Health && Armor" thinggroup b 280 "Bonus" thinggroup k F0F "Key" thinggroup q CC6 "Quest Item" thinggroup r 9F9 "Rebel" thinggroup c 8CC "Civilian" thinggroup g 66C "Gore" thinggroup d 66C "Decoration" thinggroup l 66C "Light Source" thinggroup n 66C "Natural" thinggroup - 0BD "OTHER" thing 1 p - 18 PLAY "Player 1 start" thing 2 p - 18 PLAY "Player 2 start" thing 3 p - 18 PLAY "Player 3 start" thing 4 p - 18 PLAY "Player 4 start" thing 5 p - 18 PLAY "Player 5 start" thing 6 p - 18 PLAY "Player 6 start" thing 7 p - 18 PLAY "Player 7 start" thing 8 p - 18 PLAY "Player 8 start" thing 11 p t 18 PLAYF3 "Deathmatch start" thing 14 p tl 20 TFOGC0 "Teleport exit" thing 23 p tl 20 TELPA "Teleport swirl" # andrewj: I presume these are for hubs thing 118 p t 18 TFOGA "Hub Spot 1" thing 119 p t 18 TFOGA "Hub Spot 2" thing 120 p t 18 TFOGA "Hub Spot 3" thing 121 p t 18 TFOGA "Hub Spot 4" thing 122 p t 18 TFOGA "Hub Spot 5" thing 123 p t 18 TFOGA "Hub Spot 6" thing 124 p t 18 TFOGA "Hub Spot 7" thing 125 p t 18 TFOGA "Hub Spot 8" thing 126 p t 18 TFOGA "Hub Spot 9" thing 127 p t 18 TFOGA "Hub Spot 10" thing 83 h n 20 FULLA "Surgery Kit" thing 2011 h n 20 STMPA "Med Patch" thing 2012 h n 20 MDKTA "Medical Kit" thing 2018 h n 20 ARM2A "Leather Armor" thing 2019 h n 20 ARM1A "Metal Armour" thing 17 a n 20 CPACA "Energy Pack" thing 84 a n 20 GASGA "Gas Grenade (teaser)" thing 114 a n 20 XQRLA "Electric Bolts" thing 115 a n 20 PQRLA "Poison Arrows" thing 152 a n 20 GRN1A "HE Grenades" thing 153 a n 20 GRN2A "Phosphorous Grenades" thing 183 a n 20 BKPKA "Ammo Satchel" thing 2007 a n 20 BLITA "Clip of Bullets" thing 2010 a n 20 MSSLA "Missiles" thing 2046 a n 20 ROKTA "Crate of Missiles" thing 2047 a n 20 BRY1A "Energy Pod" thing 2048 a n 20 BBOXA "Box of Bullets" thing 13 k n 20 CRD2A "ID Card" thing 38 k n 20 KY2SA "Silver Key" thing 39 k n 20 KY3BA "Brass Key" thing 40 k n 20 KY1GA "Gold Key" thing 61 k n 20 ORACA "Oracle Key" thing 86 k n 20 FUBRA "Order Key" thing 91 k n 20 HANDA "Severed Hand" thing 166 k n 20 WAREA "Warehouse Key" thing 184 k n 20 CRD1A "ID Badge" thing 185 k n 20 TPASA "Passcard" thing 192 k nl 20 RCRYA "Red Crystal Key" thing 193 k nl 20 BCRYA "Blue Crystal Key" thing 195 k n 20 CHAPA "Chapel Key" thing 230 k n 20 FUSLA "Base Key (front)" thing 233 k n 20 BLTKA "Mauler Key" thing 234 k n 20 PROCA "Factory Key" thing 235 k n 20 MINEA "Mine Key" thing 236 k n 20 GOIDA "Core Key" # TODO : check these I_SGLx sprite names thing 77 w n 20 I_SGL1 "Sigil 1 (Lightning)" thing 78 w n 20 I_SGL2 "Sigil 2 (Rail)" thing 79 w n 20 I_SGL3 "Sigil 3 (Spread)" thing 80 w n 20 I_SGL4 "Sigil 4 (Column)" thing 81 w n 20 I_SGL5 "Sigil 5 (Blast)" thing 154 w n 20 GRNDA "Grenade Launcher" thing 2001 w n 20 CBOWA "Crossbow" thing 2002 w n 20 RIFLA "Assault Gun" thing 2003 w n 20 MMSLA "Mini-Missile Launcher" thing 2004 w n 20 TRPDA "Mauler" thing 2005 w n 20 FLAMA "Flame Thrower" thing 2006 w n 20 RIFLB "Assault Gun Standing" thing 10 b n 16 BEACA "Teleport Beacon" thing 59 b n 16 XPRKA "Degnin Ore" thing 207 b n 20 TARGA "Targeter" thing 2024 b n 20 SHD1A "Shadow Armor" thing 2025 b n 20 MASKA "Enviro Suit" thing 2026 b nl 20 PMAPA "Map" thing 2027 b nl 20 PMUPA "Scanner" thing 25 q n 10 BNG2I "Force Field Guard" thing 45 q n 20 PSTNA "Gate Piston" thing 52 q n 20 OFICA "Officer Uniform" thing 90 q n 20 UNIFA "Guard Uniform" thing 92 q n 20 CRYSA "Power Crystal" thing 93 q n 20 COINA "Gold Coin" thing 138 q n 20 CREDA "10 Gold" thing 139 q n 20 SACKA "25 Gold" thing 140 q n 20 CHSTA "50 Gold" thing 182 q n 26 SECRA "Computer" thing 205 q nl 10 RELCA "Offering Chalice" thing 206 q n 20 COMMA "Communicator" thing 220 q n 17 COUPA "Power Coupling" thing 226 q n 16 COUPC "Broken Coupling" # TODO : check things 9001-9010, called "Unimplemented spot X" in slade thing 3002 m - 24 AGRDA1 "Acolyte 1 (tan)" thing 142 m - 24 AGRDA1 "Acolyte 2 (red)" thing 143 m - 24 AGRDA1 "Acolyte 3 (rust)" thing 146 m - 24 AGRDA1 "Acolyte 4 (gray)" thing 147 m - 24 AGRDA1 "Acolyte 5 (dkgrn)" thing 148 m - 24 AGRDA1 "Acolyte 6 (gold)" thing 231 m - 24 AGRDA1 "Acolyte 8 (blue)" thing 232 m - 24 AGRDA1 "Acolyte 7 (green)" thing 58 m - 24 AGRDE "Shadow Acolyte" thing 12 m - 15 PRSTA "Loremaster" thing 16 m - 40 ROB3A "Inquisitor" thing 27 m - 20 TURTA "Ceiling Turret" thing 71 m - 45 PRGRE "Programmer" thing 128 m - 130 MNALA "Entity" thing 26 m - 84 NESTA "Entity Nest" thing 198 m - 25 PODDA "Entity Pod" thing 186 m - 31 SPIDB "Stalker" thing 187 m - 40 MLDRA "Bishop" thing 3001 m - 20 ROB1A "Reaver" thing 3003 m - 20 PROCA "Templar" thing 3005 m - 40 ROB2A "Crusader" thing 3006 m - 31 SEWRC "Sentinel" thing 129 m i 64 ALN1A "Spectre Programmer" thing 75 m i 24 ALN1B "Spectre Bishop" thing 76 m i 24 ALN1C "Spectre Oracle" thing 167 m i 24 ALN1D "Spectre Macil" thing 168 m i 24 ALN1E "Spectre Loremaster" thing 9 r - 20 HMN1P "Rebel 1" thing 144 r - 20 HMN1A "Rebel 2" thing 145 r - 20 HMN1B "Rebel 3" thing 149 r - 20 HMN1C "Rebel 4" thing 150 r - 20 HMN1D "Rebel 5" thing 151 r - 20 HMN1Q "Rebel 6" thing 64 r - 20 LEDRA "Macil 1 Invincible" thing 200 r i 20 LEADF "Macil 2 Spectre" thing 65 c - 20 PEASA "Peasant Red 1" thing 132 c - 20 PEASB "Peasant Red 2" thing 133 c - 20 PEASC "Peasant Red 3" thing 66 c - 20 PEASA "Peasant Gray 1" thing 134 c - 20 PEASB "Peasant Gray 2" thing 135 c - 20 PEASC "Peasant Gray 3" thing 67 c - 20 PEASA "Peasant Rust 1" thing 136 c - 20 PEASB "Peasant Rust 2" thing 137 c - 20 PEASC "Peasant Rust 3" thing 172 c - 20 PEASA "Peasant DkGreen 1" thing 173 c - 20 PEASB "Peasant DkGreen 2" thing 174 c - 20 PEASC "Peasant DkGreen 3" thing 175 c - 20 PEASA "Peasant Green 1" thing 176 c - 20 PEASB "Peasant Green 2" thing 177 c - 20 PEASC "Peasant Green 3" thing 178 c - 20 PEASA "Peasant Gold 1" thing 179 c - 20 PEASB "Peasant Gold 2" thing 180 c - 20 PEASC "Peasant Gold 3" thing 181 c - 20 PEASA "Peasant Blue" thing 3004 c - 20 PEASA "Peasant Tan 1" thing 130 c - 20 PEASB "Peasant Tan 2" thing 131 c - 20 PEASC "Peasant Tan 3" thing 141 c - 20 BEGRA "Beggar 1" thing 155 c - 20 BEGRB "Beggar 2" thing 156 c - 20 BEGRC "Beggar 3" thing 157 c - 20 BEGRD "Beggar 4" thing 158 c - 20 BEGRE "Beggar 5" thing 72 c - 20 MRBDB "Bar Keep" thing 73 c - 20 MRYSA "Armorer" thing 74 c - 20 MRNOC "Medic" thing 85 c - 10 RATTA "Rat" thing 116 c - 20 MRGTA "Weapon Smith" thing 169 c - 20 PEASA "Zombie" thing 170 c - 20 AGRDA "Zombie Spawner" thing 199 c - 16 ORCLA "Oracle (map12)" thing 201 c - 20 ARMRA "Becoming Acolyte" thing 204 c - 10 NEALA "Kneeling Guy" thing 15 g n 20 PLAYP "Dead Player (disappears)" thing 18 g n 20 PEASN "Dead Peasant (disappears)" thing 19 g n 20 HMN1N "Dead Rebel" thing 20 g n 20 ROB1R "Dead Reaver" thing 21 g n 20 AGRDN "Dead Acolyte (disappears)" thing 22 g n 20 ROB2P "Dead Crusader" thing 212 g n 20 SACRA "Sacrificed Guy" thing 113 g cl 20 HERTA "Hearts in Tank" thing 209 g c 20 TNK1C "Tank 1" thing 210 g c 20 TNK2C "Tank 2" thing 211 g c 20 TNK3C "Tank 3" thing 213 g c 20 TNK4C "Tank 4 (skeleton)" thing 214 g c 20 TNK5C "Tank 5 (acolyte)" thing 229 g c 20 TNK6C "Tank 6 (spectre)" # actual radius may be smaller, but limited to 10 for usability thing 24 l lnc 10 KLAXB "Klaxon Warning" thing 28 l lnc 20 CAGEA "Cage Light" thing 34 l ln 20 CNDLA "Candle" thing 35 l l 16 CLBRA "Candelabra" thing 43 l l 10 LAMPA "Outside Lamp" thing 46 l l 10 LANTA "Pole Lantern" thing 47 l l 10 LMPCA "Large Torch" thing 50 l l 10 LOGSA "Huge Torch" thing 70 l l 16 BARLA "Burning Barrel" thing 95 l ln 10 LITSA "Silver Fluorescent" thing 96 l ln 10 LITBA "Brass Fluorescent" thing 97 l ln 10 LITGA "Gold Fluorescent" thing 105 l ln 16 BOWLA "Burning Bowl" thing 106 l l 10 BRAZA "Burning Brazier" thing 107 l ln 10 TRCHA "Small Burning Torch" thing 108 l ln 10 TRHOA "Small Unlit Torch" thing 111 l l 10 LTRHA "Medium Torch" thing 196 l l 11 TLMPA "Silver Tech Lamp" thing 197 l l 10 TLMPB "Brass Tech Lamp" thing 225 l l 32 SPDLA "Alien Spider Light" thing 2028 l l 16 LITEA "Globe Light" thing 54 d - 16 STELA "Aztec Pillar" thing 55 d - 16 STLAA "Aztec Pillar 2" thing 56 d - 16 STLEA "Aztec Pillar 3" thing 221 d - 16 BUBBA "Alien Bubble Column" thing 222 d - 16 BUBFA "Alien Floor Bubble" thing 223 d c 16 BUBCA "Alien Ceiling Bubble" thing 224 d - 16 ASPRA "Alien Asp Climber" thing 227 d - 24 APOWA "Alien Pillar" thing 44 d - 20 DSTAA "Ruined Statue" thing 48 d - 20 MONIA "Tech pillar" thing 57 d - 24 HUGEA "Huge Tech Pillar" thing 69 d - 16 BAR1A "Barricade Column" thing 63 d - 20 STAKA "Chimneystack" thing 68 d - 24 TRAYA "Tray" thing 82 d - 10 BARWA "Wooden Barrel" thing 94 d - 10 BARTA "Explosive Barrel" thing 109 d nc 20 CHANA "Ceiling Chain" thing 110 d - 20 STATA "Statue" thing 117 d nc 20 CRABA "Surgery Crab" thing 164 d n 20 MUGGA "Mug" thing 165 d - 12 VASEA "Pot" thing 188 d - 12 VASEB "Pitcher" thing 189 d - 12 STOLA "Stool" thing 190 d - 20 POT1A "Metal Pot" thing 191 d - 20 TUB1A "Tub" thing 194 d n 16 ANVLA "Anvil" thing 208 d - 10 HOGNA "Practice Target" thing 216 d - 24 SBANA "Sigil Banner" thing 217 d n 20 BOTRA "Rebel Boots" thing 218 d n 20 HATRA "Rebel Helmet" thing 219 d n 20 TOPRA "Rebel Shirt" thing 228 d - 12 AFEDA "Ammo Filler" thing 2014 d n 20 WATRA "Water Bottle" thing 53 n nc 20 CDRPA "Water Drip" thing 103 n n 20 DRIPA "Water Drip 2" thing 104 n n 20 SPLHA "Waterfall Splash" thing 215 n n 20 LOGGA "Stick in Water" thing 112 n n 20 WTFTA "Fountain" thing 60 n - 15 BUSHA "Bush 1" thing 62 n - 64 SHRBA "Bush 2" thing 33 n - 15 TRE1A "Tree 1" thing 51 n - 15 TREEA "Tree 2 (palm)" thing 202 n - 15 TREEB "Tree 3" thing 203 n - 15 TREEC "Tree 4 (potted)" thing 29 n n 20 RUB1A "Rubble 1" thing 30 n n 20 RUB2A "Rubble 2" thing 31 n n 20 RUB3A "Rubble 3" thing 32 n n 20 RUB4A "Rubble 4" thing 36 n n 20 RUB5A "Rubble 5" thing 37 n n 20 RUB6A "Rubble 6" thing 41 n n 20 RUB7A "Rubble 7" thing 42 n n 20 RUB8A "Rubble 8" thing 99 n n 20 ROK1A "Rock 1" thing 100 n n 20 ROK2A "Rock 2" thing 101 n n 20 ROK3A "Rock 3" thing 102 n n 20 ROK4A "Rock 4" thing 98 n c 16 STLGC "Stalactite" thing 161 n c 16 STLGA "Stalactite (small)" thing 160 n - 16 STLGB "Stalagmite" thing 163 n - 16 STLGF "Stalagmite (small)" thing 159 n c 16 STLGD "Cave Pillar Top" thing 162 n - 16 STLGE "Cave Pillar Bottom" #---- SECTOR TYPES --------------- sector 0 "NOTHING" sector 1 "Light Blinks Randomly" sector 2 "Light Flashes 2 Hz" sector 3 "Light Flashes 1 Hz" sector 4 "Damage 20% / Flashes" sector 5 "Damage 10%" sector 7 "Damage 5%" sector 8 "Light Oscillates" sector 9 "Secret Area" sector 10 "Close after 30 sec" sector 11 "End level / damage" sector 12 "Flashes 1 Hz sync" sector 13 "Flashes 2 Hz sync" sector 14 "Open after 5 minute" sector 15 "Instant Death!" sector 16 "Damage 20%" sector 17 "Light Flickering" sector 18 "Carry Player by tag" #---- LINE TYPES --------------- include "doom_groups" linegroup j "Split Door" line 0 - "-- NOTHING" line 9 - "S1 Donut (raise outer, lower inner)" :tag line 48 a "-- Scroll Wall Left" line 142 a "-- Scroll Wall Up" line 143 a "-- Scroll Wall Down /fast" line 149 a "-- Scroll Wall Right" line 124 e "W1 Exit (end game)" line 51 e "S1 Exit (end game)" line 11 e "SR Exit to Map #tag" line 52 e "W1 Exit to Map #tag/100" line 186 e "WR Exit to Hub Spot /right" line 145 e "WR Exit to Hub Spot" line 182 - "G1 Break Glass" line 228 - "W1 Entity Taunt" line 165 - "SR Fake Door 1" :tag line 205 - "SR Fake Door 2" :tag line 147 - "S1 Forcefield Clear" :tag line 187 - "W1 Forcefield Clear If Quest" :tag line 148 - "SR Forcefield Damage" :tag line 202 - "W1 Message #Tag" line 201 - "W1 Message #Tag /front" line 210 - "W1 Message #Tag /nolog /flamethrower" line 211 - "SR Message #Tag /nolog" line 215 - "W1 Message If Quest Item" line 204 - "W1 Music Change" line 203 - "WR Music Change" line 150 - "WR Noise Alert" :tag line 175 - "WR Noise Alert /onfloor" :tag line 198 - "WR Noise Alert /uniform" :tag line 208 - "WR Noise Alert /flamethrower" :tag line 206 - "WR Noise Alert /chalice" :tag line 39 t "W1 Teleport" :tag line 125 t "W1 Teleport /mon" :tag line 97 t "WR Teleport" :tag line 126 t "WR Teleport /mon" :tag line 185 t "WR Teleport /silent" :tag line 231 t "WR Teleport /silent-src" :tag line 195 t "WR Teleport /zombie" :tag line 8 s "W1 Stair Raise 8" :tag line 7 s "S1 Stair Raise 8" :tag line 100 s "W1 Stair Raise 16 /crush" :tag line 127 s "S1 Stair Raise 16 /crush" :tag line 178 s "W1 Stair Lower 16" :tag line 146 s "S1 Stair Lower 16" :tag line 209 s "S1 Stair Lower 16 /chalice" :tag line 13 l "W1 Light to 255" :tag line 81 l "WR Light to 255" :tag line 138 l "SR Light to 255" :tag line 35 l "W1 Light to 35" :tag line 79 l "WR Light to 35" :tag line 139 l "SR Light to 35" :tag line 12 l "W1 Light to highest nb" :tag line 80 l "WR Light to highest nb" :tag line 104 l "W1 Light to lowest nb" :tag line 17 l "W1 Light blink 1 Hz" :tag line 179 c "W1 Ceiling close" :tag line 41 c "S1 Ceiling close" :tag line 43 c "SR Ceiling close " :tag line 49 c "S1 Ceiling close flr+8 /cont" :tag line 199 c "S1 Ceiling close /crush" :tag line 6 h "W1 Crusher /fast" :tag line 77 h "WR Crusher /fast" :tag line 25 h "W1 Crusher /slow" :tag line 73 h "WR Crusher /slow" :tag line 44 h "W1 Crusher /oneshot" :tag line 72 h "WR Crusher /oneshot" :tag line 141 h "W1 Crusher /silent" :tag line 57 h "W1 Stop crusher" :tag line 74 h "WR Stop crusher" :tag line 53 m "W1 Start Moving Floor" :tag line 87 m "WR Start Moving Floor" :tag line 54 m "W1 Stop Moving Floor" :tag line 89 m "WR Stop Moving Floor" :tag line 21 p "S1 Lift Lower" :tag line 62 p "SR Lift Lower" :tag line 184 p "WR Lift Lower" :tag line 10 p "W1 Lift Lower /mon" :tag line 88 p "WR Lift Lower /mon" :tag line 121 p "W1 Lift Lower /fast" :tag line 120 p "WR Lift Lower /fast" :tag line 122 p "S1 Lift Lower /fast" :tag line 123 p "SR Lift Lower /fast" :tag line 214 p "SR Lift Lower /slow" :tag line 154 p "SR Lift Lower /goldkey" :tag line 177 p "SR Lift Lower /power3key" :tag line 155 p "SR Lift Raise" :tag line 1 d "DR Door" line 29 d "S1 Door" :tag line 46 d "GR Door" :tag line 63 d "SR Door" :tag line 90 d "WR Door" :tag line 103 d "S1 Door /stay" :tag line 2 d "W1 Door /stay" :tag line 31 d "D1 Door /stay" line 61 d "SR Door /stay" :tag line 86 d "WR Door /stay" :tag line 105 d "WR Door /fast" :tag line 108 d "W1 Door /fast" :tag line 111 d "S1 Door /fast" :tag line 114 d "SR Door /fast" :tag line 117 d "DR Door /fast" line 106 d "WR Door /fast /stay" :tag line 109 d "W1 Door /fast /stay" :tag line 112 d "S1 Door /fast /stay" :tag line 115 d "SR Door /fast /stay" :tag line 118 d "D1 Door /fast /stay" line 4 d "W1 Door /mon" :tag line 200 d "W1 Door /sigil" :tag line 144 d "DR Door /animated" line 207 d "SR Door /animated" :tag line 229 d "SR Door /animated /sigil" :tag line 234 d "SR Door If Irale Unlocked" :tag line 230 d "W1 Door If Quest Item" :tag line 216 d "WR Door If Quest Item" :tag line 188 d "W1 Door If Quest Item 16" :tag line 194 d "S1 Door Free Prisoners /stay" :tag line 3 d "W1 Close Door" :tag line 42 d "SR Close Door" :tag line 50 d "S1 Close Door" :tag line 75 d "WR Close Door" :tag line 107 d "WR Close Door /fast" :tag line 110 d "W1 Close Door /fast" :tag line 113 d "S1 Close Door /fast" :tag line 116 d "SR Close Door /fast" :tag line 197 d "W1 Close Door /fast /pieces" :tag line 227 d "W1 Close Door If Quest Item" :tag line 16 d "W1 Close Door Then Open" :tag line 76 d "WR Close Door Then Open" :tag line 174 j "W1 Split Door" :tag line 40 j "S1 Split Door" :tag line 183 j "W1 Split Door /nearest" :tag line 235 j "S1 Split Door /sigil" :tag line 233 j "SR Split Door Log Msg 70" :tag line 189 j "S1 Split Door Oracle Key" :tag line 169 k "DR Door Base Key" line 225 k "DR Door Catacomb Key" line 213 k "DR Door Chalice" line 224 k "DR Door Chapel Key" line 217 k "DR Door Core Key" line 170 k "DR Door Govs Key" line 221 k "DR Door Mauler Key" line 191 k "SR Door Military ID" :tag line 223 k "SR Door Mine Key" :tag line 232 k "DR Door Oracle Pass" line 190 k "DR Door Order Key" line 172 k "SR Door Power 1 Key" :tag line 173 k "SR Door Power 2 Key" :tag line 176 k "SR Door Power 3 Key" :tag line 171 k "S1 Door Prison Key" :tag line 192 k "SR Door Warehouse Key" :tag line 161 k "DR Door Brass Key" line 152 k "SR Door Brass Key /fast" :tag line 162 k "S1 Door Brass Key /fast" :tag line 156 k "D1 Door Brass Key /stay" line 159 k "DR Door Gold Key" line 151 k "SR Door Gold Key /fast" :tag line 164 k "S1 Door Gold Key /fast" :tag line 158 k "D1 Door Gold Key /stay" line 26 k "DR Door ID Badge" line 133 k "S1 Door ID Badge /fast" :tag line 99 k "SR Door ID Badge /fast" :tag line 32 k "D1 Door ID Badge /stay" line 28 k "DR Door ID Card" line 134 k "SR Door ID Card /fast" :tag line 135 k "S1 Door ID Card /fast" :tag line 33 k "D1 Door ID Card /stay" line 27 k "DR Door Passcard" line 136 k "SR Door Passcard /fast" :tag line 137 k "S1 Door Passcard /fast" :tag line 34 k "D1 Door Passcard /stay" line 166 k "DR Door Severed Hand" line 167 k "S1 Door Severed Hand /fast" :tag line 168 k "SR Door Severed Hand /fast" :tag line 160 k "DR Door Silver Key" line 153 k "SR Door Silver Key /fast" :tag line 163 k "S1 Door Silver Key /fast" :tag line 157 k "D1 Door Silver Key /stay" line 102 f "S1 Floor down HEF" :tag line 19 f "W1 Floor down HEF" :tag line 45 f "SR Floor down HEF" :tag line 83 f "WR Floor down HEF" :tag line 36 f "W1 Floor down HEF /fast" :tag line 70 f "SR Floor down HEF /fast" :tag line 71 f "S1 Floor down HEF /fast" :tag line 98 f "WR Floor down HEF /fast" :tag line 219 f "S1 Floor down HEF If Blue Crystal" :tag line 220 f "S1 Floor down HEF If Red Crystal" :tag line 226 f "S1 Floor down HEF Training Area" :tag line 23 f "S1 Floor down LEF" :tag line 38 f "W1 Floor down LEF" :tag line 60 f "SR Floor down LEF" :tag line 82 f "WR Floor down LEF" :tag line 37 f "W1 Floor down LEF /NXP" :tag line 84 f "WR Floor down LEF /NXP" :tag line 196 f "W1 Floor down LEF If Sigil Pieces" :tag line 212 f "W1 Floor down LEF If Flamethrower" :tag line 193 f "W1 Floor down LEF If Quest Item" :tag line 5 g "W1 Floor up LIC" :tag line 24 g "G1 Floor up LIC" :tag line 101 g "S1 Floor up LIC" :tag line 64 g "SR Floor up LIC" :tag line 91 g "WR Floor up LIC" :tag line 55 g "S1 Floor up LIC-8 /crush" :tag line 56 g "W1 Floor up LIC-8 /crush" :tag line 65 g "SR Floor up LIC-8 /crush" :tag line 94 g "WR Floor up LIC-8 /crush" :tag line 119 g "W1 Floor up nhEF" :tag line 128 g "WR Floor up nhEF" :tag line 18 g "S1 Floor up nhEF" :tag line 69 g "SR Floor up nhEF" :tag line 22 g "W1 Floor up nhEF /TX" :tag line 47 g "G1 Floor up nhEF /TX" :tag line 95 g "WR Floor up nhEF /TX" :tag line 20 g "S1 Floor up nhEF /TX" :tag line 68 g "SR Floor up nhEF /TX" :tag line 129 g "WR Floor up nhEF /fast" :tag line 130 g "W1 Floor up nhEF /fast" :tag line 131 g "S1 Floor up nhEF /fast" :tag line 132 g "SR Floor up nhEF /fast" :tag line 15 g "S1 Floor up 24 /TX" :tag line 66 g "SR Floor up 24 /TX" :tag line 59 g "W1 Floor up 24 /TXP" :tag line 93 g "WR Floor up 24 /TXP" :tag line 14 g "S1 Floor up 32 /TX" :tag line 67 g "SR Floor up 32 /TX" :tag line 58 g "W1 Floor up 64" :tag line 92 g "WR Floor up 64" :tag line 140 g "S1 Floor up 512" :tag line 180 g "G1 Floor up 512 /TXP" :tag line 181 g "S1 Floor up 512 /TXP" :tag line 30 g "W1 Floor up lowest tex" :tag line 96 g "WR Floor up lowest tex" :tag #---- TEXTURE CATEGORIES ---------------- # TODO eureka-editor-eureka-2.0.2/games/tnt.ugh000066400000000000000000000015331464327712600201510ustar00rootroot00000000000000#------------------------------------------------------------------------ # TNT EVILUTION (Final Doom) #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2019 Andrew Apted # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ include "doom2" include "tnt_tex" eureka-editor-eureka-2.0.2/htgen/000077500000000000000000000000001464327712600166465ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/htgen/Docs_CommandList.html000066400000000000000000001213211464327712600227160ustar00rootroot00000000000000

Command Reference

Here is a description of all the available commands which can be bound to keyboard keys or mouse buttons.

See KeySystem for general information about how commands work.


Index

File CommandsGeneral Editing
Edit CommandsVertex Editing
View CommandsLinedef Editing
Browser CommandsSector Editing
Help CommandsThing Editing
2D View3D View
Miscellaneous 

File Commands

NewProject

Creates a fresh map in a new wad file. If you choose an existing file, it will be overwritten (i.e. all existing contents removed).

ManageProject

Manages several important settings about the currently edited wad. That includes which game it is for, which source port is being used, and any resource files.

OpenMap

Opens a map for editing. This map can be found the currently edited wad, or the game iwad, or one of the resource wads, or you can even load another wad file (which becomes the currently edited file).

GivenFile  <keyword>

Loads a new wad file for editing from the list of "given files", i.e. files that were specified on the command line when Eureka was started.
Keywords:
next : the next wad file in the list
prev : the previous wad file in the list
first : the very first wad file in the list
last : the very last wad file in the list
current : the same file currently being edited

FlipMap  <keyword>

Opens another map in the current wad.
Keywords:
next : the next map in the wad
prev : the previous map in the wad
first : the very first map in the wad
last : the very last map in the wad

SaveMap

Saves your map into the currently edited wad. It will also build the nodes (BSP information) unless this is disabled in the preferences. The game iwad is considered read-only, and hence this cannot be used on it, instead you will be prompted for a file to export into.

ExportMap

Saves the map into another wad file, possibly a completely new file.

FreshMap

Creates a fresh map in the currently edited wad. Cannot be used on the game iwad.

CopyMap

Copies the current map in the currently edited wad to another slot. For example, duplicating MAP01 into the MAP02 slot. Cannot be used on the game iwad.

RenameMap

Renames the current map in the currently edited wad, or in other words: move the map to a different slot. For example, moving MAP01 to the MAP23 slot. Cannot be used on the game iwad.

DeleteMap

Deletes the current map from the currently edited wad. Cannot be used on the game iwad.

TestMap

Tests your map by launching the game (using your chosen source port).

BuildAllNodes

Builds the nodes (BSP information) for all maps in the currently edited wad.

PreferenceDialog

Opens the Preferences dialog.

Quit

Quits Eureka. If you have unsaved changes, a dialog box will appear asking for confirmation.

Edit Commands

Undo

Undoes (reverses) the last editing operation. This can be repeated multiple times.

Redo

Redo is the opposite of Undo, it re-instates the editing operation which Undo undid. It can be repeated multiple times.

Insert  [flags...]

Inserts a new vertex, sector or thing into the map. In vertex mode, this will begins line drawing (if not already underway). In sector mode, this can fill empty spaces (or spaces with broken sectors) will a new, valid sector.
Flags:
/continue : when line drawing, do not stop when joining existing geometry
/nofill : when line drawing, do not fill new spaces with sectors

Delete  [flags...]

Deletes one or more objects from the map, using the highlighted object when the selection is empty. Deleting a sector will usually delete all things in the sector too. Deleting a single vertex that connects two linedefs causes the two linedefs to be merged into one.
Note that deleting linedefs or groups of vertices can leave the map in a broken state. It is generally better to go into sectors mode and delete or merge sectors there.
This command can also be used to change textures in the 3D view, or in texture/flat images in the sector or linedef panels. Textures will become "-" (the null texture) and flats will become sky.
Flags:
/keep : when deleting sectors, keep the things in it, and don't remove any unused linedefs

Clipboard_Cut
Clipboard_Copy
Clipboard_Paste

Performs the clipboard Cut, Copy and Paste functions. On the 2D map view, this will apply to the geometry, allowing an object or groups of objects to be copied and pasted. In the 3D view, these allow textures to be copied and pasted (the "cut" operation sets textures to their default).

Select

Toggles an object in the selection, i.e. if the highlighted object is unselected, then select it, otherwise remove it from the selection.

SelectAll

Adds all objects in the current editing mode to the selection.

UnselectAll

Clears the selection, i.e. removes all objects from it.

InvertSelection

Selects all objects not in the current selection, and unselects the rest.

LastSelection

This is like "undo" for the selection, can be used to bring back a selection which was accidently cleared. Note that it is limited to a single undo step, and it cannot bring back a selection once modifications are made to the map.

CopyAndPaste

Same as doing a copy followed by a paste. Can be a useful way of adding things to the map by copying an existing thing.

CopyProperties  [flags...]

Copies properties from a selected object to the highlight object. Not all properties are copied though. For things, the position and angle are not copied. For linedefs, textures are copied but not X or Y offsets, nor the "impassible" flag.
Flags:
/reverse : copy from the highlighted object to the selected object(s).

PruneUnused

Finds any unused vertices, sidedefs or sectors and removes them from the map.

MoveObjectsDialog
ScaleObjectsDialog
RotateObjectsDialog

These comands open a dialog window for moving, scaling or rotating a group of selected objects. They allow specifying an exact distance to move the objects, or an exact scaling factor, or an exact number of degrees to rotate the objects.

View Commands

Zoom  <delta>

Zooms the 2D map view in or out. The <delta> parameter is +1 to zoom in (make everything bigger) or -1 to zoom out (make everything smaller).
Flags:
/center : focal point of zoom is the center of 2D view (instead of where mouse is)

ZoomSelection

Scrolls and zooms the map view so that all objects in the current selection are visible.

DefaultProps

Shows the Default Properties panel, or hides it if already shown.

FindDialog

Shows the Find/Replace panel, or hides it if already shown.

FindNext

Finds the next object in the current search.

GoToCamera

Scrolls the 2D map view so that the camera (for the 3D view) is shown at the center. Does not zoom the map view.

PlaceCamera

Places the camera (for the 3D view) at the spot on the 2D map view where the mouse is.
Flags:
/open3d : activate the 3D view afterwards.

JumpToObject

Brings up the "Jump To Object" dialog window, allowing you to jump to the object with a specified index number.

Browser Commands

BrowserMode  <keyword>

Opens the browser to a particular type of object.
Keywords:
tex : browse textures
flat : browse flats
obj : browse things
line : browse linedef specials
sec : browse sector types
gen : generalize linedef editor (for BOOM ports only)
Flags:
/force : do not close the browser
/recent : set the category to "Recent"
NOTE: the browser can be closed using the "Set browser 0" command.

BR_CycleCategory  <dir>

Cycles through the categories in the currently open browser. The <dir> parameter is optional, when present it can be +1 to move forward or -1 to move backward through the categories.

BR_ClearSearch

Clears the search box in the currently open browser.

BR_Scroll  <delta>

Scrolls the browser by a single step. The <delta> parameter is a small negative or positive number, as follows:
-1 +1 : scroll a small amount
-2 +2 : scroll by a single "line"
-3 +3 : scroll by a single page
-4 +4 : scroll to the end

Help Commands

LogViewer

Opens the log viewer window.

OnlineDocs

Launches a web browser to display Eureka's absolutely fabulous documentation.

AboutDialog

Displays a dialog with some brief information about Eureka.

Miscellaneous

Nothing

Does absolutely nothing. This can sometimes be useful to disable a certain key combination in a certain editing mode, or to disable a shortcut used in the menus.

Set  <keyword> <value>

Sets the value of a certain editor state. It requires two parameters, the first is a keyword for what is being set, and the second is the new value. The value is usually a small number, where 0 means "off" and 1 means "on", though some keywords accept a range of values.
Keywords:
3d : whether the 3D view is active
browser : whether the browser panel is active
gamma : the current gamma level (brightness), 0-4
grid : whether the grid is being drawn
obj_nums : whether object numbers are being shown in 2D view
sec_render : the sector rendering mode in 2D view, 0 for nothing
snap : whether grid-snapping is active
sprites : whether sprites are drawn in 2D view (in Things mode)

Toggle  <keyword>

Toggles or cycles the value of a certain editor state. It accepts the same keywords as the Set command above.

MetaKey

Waits for the next keypress and adds the META modifier to it.

EditMode  <mode>

Changes the current editing mode to the one specified. Note that the 3D mode is not handled by this command (it is changed with the Set or Toggle commands above).
Keywords: vertex, line, sector, thing

OpMenu

Brings up the operation menu.

MapCheck  <keyword>

Runs the map checking dialog.
Keywords: all, major, vertices, sectors, linedefs, things, textures, tags, current

General Editing

Merge  [flags...]

Merges two or more objects into a single one. In things mode, this merely moves the objects to a common location (does not remove any things). In Linedefs mode, this only handles two one-sided linedefs (which are assumed to be back-to-back or close to it).
Flags:
/keep : when merging sectors, keep linedefs that would otherwise be removed.

Disconnect

Disconnects one or more objects from nearby geometry. In things mode, this separates things which exist at the same place (the coordinates must be exactly the same). In vertex mode, this disconnects the linedefs which join at that vertex.

Mirror  <keyword>

Mirrors one or more objects about a central axis.
Keywords:
horiz : mirror horizontally (stuff moves left and right)
vert : mirror vertically (stuff moves up and down)

Rotate90  <keyword>

Rotates one or more objects by 90 degrees around a central point.
Keywords:
cw : rotate clockwise
acw : rotate anti-clockwise

Enlarge  <factor>
Shrink  <factor>

Scales one or more objects, making them bigger or smaller. The <factor> parameter is the value to scale by, defaulting to 2.0 when absent. Fractional values like "1.3" are supported. Objects are scaled from their center point. When a sector is enlarged or shrunk, any things it contains are moved too.

Quantize

Snaps the selected objects to the nearest grid point. For example, if the current grid size is 16 units, and several sectors are selected, all the vertices which are a part of those sectors are moved to be aligned with the 16x16 grid (if possible).
When a vertex cannot be moved (because the nearest grid points are in use), then this command beeps with an error message, and all the vertices which could not be moved are highlighted in red.

ApplyTag  <keyword>

Applies a tag number to the selected objects, which must be either sectors or linedefs.
Keywords:
fresh : use a new tag number (one not used anywhere else)
last : use the last (highest) tag number used on the map

ACT_Click  [flags...]

Performs the functions typically done by a left mouse button click, namely to select or unselect objects in the 2D map view, to drag objects around, and splitting linedefs.
Flags:
/noselect : disable the select function
/nodrag : disable dragging
/nosplit : do not split linedefs

ACT_Drag

Drags the currently selected objects. An outline of the objects follow the mouse while the key or button is held down, and when the key/button is released the objects are actually moved.

ACT_Transform  <keyword>

Transforms the currently selected objects. The <keyword> parameter determines what kind of transformation to apply. An outline of the transformed objects is shown while the key is held down, and moving the mouse around will affect how large, how much rotation (etc) is applied. When the key is released, the objects are actually moved to their final positions.
Keywords:
scale : scale uniformly, maintaining the same aspect ratio
stretch : scale with stretching (can make everything wider or taller)
rotate : rotate the objects
rotscale : rotate and scale uniformly
skew : skew (shear) the objects

Vertex Editing

VT_ShapeLine

Reshapes the selected vertices so they form a straight line, and each vertex is the same distance apart. The vertices need to be roughly in a line already, and the two vertices at the ends of that imaginary line are the anchor points and do not move, but the remaining vertices are moved.

VT_ShapeArc  <angle>

Reshapes the selected vertices so they form an arc of a circle. The <angle> parameter is the number of degrees in this arc, and can be 360 for a full circle. The vertices need to be roughly in the desired shape already, and will be moved to lie on the arc, with an equal distance between each one.

Linedef Editing

LIN_Align  [flags...]

Aligns the X/Y offsets on the selected linedefs. The flags control exactly what is affected by this command.
Flags:
/x : align X offsets
/y : align Y offsets
/right : pick walls to the right to align with (instead of the left).
/clear : clear the X / Y offsets (instead of aligning).

LIN_Flip  [flags...]

Flips the orientation of one or more linedefs.
NOTE: Flipping one-sided lines generally breaks the map geometry, and the /force flag will break the map in a different way: the sidedef stays facing the sector, but leaving the linedef without a right side.

LIN_SwapSides

Swaps the sidedefs on some linedefs. This is only really useful for fixing map problems.

LIN_SplitHalf

Splits one or more linedefs in half, adding a vertex at the exact middle point.

LIN_SelectPath  [flags...]

Selects or unselects a group of linedefs in a path. The path stops at forks, i.e. where there are two or more choices of which way to go.
Flags:
/fresh : make the result a fresh selection (instead of modifying the current selection)
/onesided : only handle one-sided lines (ignore two-sided lines)
/sametex : require lines have the same texture

Sector Editing

SEC_Floor  <delta>

Raises or lowers the floor height of some sectors. The <delta> parameter is the height value to add, which can be positive or negative.
NOTE: a floor cannot be raised above the ceiling in the sector.

SEC_Ceil  <delta>

Raises or lowers the ceiling height of some sectors. The <delta> parameter is the height value to add, which can be positive or negative.
NOTE: a ceiling cannot be lowered below the floor in the sector.

SEC_Light  <delta>

Changes the light level in the selected sectors. The <delta> parameter is the value to add, either negative or positive, and it should be a power of two such as: 1, 2, 4, 8, 16, 32, or 64.
NOTE: vanilla DOOM, and some source ports, only use multiples of 16 for the lighting values. For example, there will be no visible difference between 160 and 170 (the next usable value is 176).

SEC_SelectGroup  [flags...]

Selects a group of contiguous sectors. The flags will control whether neighboring sectors are considered part of the group.
Flags:
/floor_h : require the same floor height
/floor_tex : require the same floor texture
/ceil_h : require the same ceiling height
/ceil_tex : require the same ceiling texture
/light : require the same lighting
/tag : require the same tag value
/special : require the same sector type
/fresh : make the result a fresh selection (instead of modifying the current selection)
/doors : don't stop at doors (closed sectors)
/can_walk : only spread into a neighbor sector if the heights allow the player to walk there and back (i.e. stop at impassible lines)

SEC_SwapFlats

Swaps the floor texture with the ceiling texture in all the selected sectors.

Thing Editing

TH_Spin  <delta>

Spins the angles (the direction things face) of all the selected things. The <delta> parameter is an angle to add, where negative values spin the things clockwise, and positive values spin the things anti-clockwise. Angles are generally multiples of 45.

2D View Commands

Scroll  <x> <y>

Scrolls the map view by a single step. The first parameter is the horizontal distance, and the second parameter is the vertical distance. These values are roughly percentages of the viewing window size.

GRID_Bump  <delta>

Changes the current grid size. The <delta> parameter should be +1 to increase the size to the next usable one, or -1 to decrease it.

GRID_Set  <size>

Sets the current grid size to the given value, which can be anything (i.e. it is not limited to the normal values).

GRID_Zoom  <scale>

Zooms the map view. The parameter is the scale value, which is positive for N:1 scales and negative for 1:N scales. For example, "-3" means 1/3 scaling. The scale factor is limited to be one of the existing ones selectable on the info bar.

ACT_SelectBox

Begins drawing a selection box.

WHEEL_Scroll  <dist>

Scrolls the 2D map view using the mouse-wheel. The <dist> parameter is roughly a percentage of the viewing window size, and each step of the mouse wheel scrolls by this amount.
Note: this command will not work unless bound to WHEEL_XXX.

NAV_Scroll_Left  <speed>
NAV_Scroll_Right  <speed>
NAV_Scroll_Up  <speed>
NAV_Scroll_Down  <speed>

These four commands are used to produce smooth scrolling of the map view. Scrolling continues while the key is held down. The <speed> parameter is roughly a percentage of the viewing window to move each second.

NAV_MouseScroll  <speed>

Activates scrolling the map view using the mouse. While the key or button is held down, moving the mouse will scroll the view. The <speed> parameter controls how fast to scroll, 1.0 means the map follows the mouse 1:1, higher values scroll faster, and lower values will scroll slower.

3D View Commands

3D_Click

Performs the usual mouse-click function of the 3D view, namely to select/unselect wall and floor surfaces.

3D_Set  <keyword> <value>

Sets a particular state of the 3D renderer to a certain value. The <value> parameter is usually a small number, where 0 means OFF and 1 means ON, though some keywords use a range of values.
Keywords:
grav : gravity mode, camera stays on the floor when moving
tex : texturing of walls and floors
obj : draw things (sprites)
light : lighting enable

3D_Toggle  <keyword>

Toggles or cycles a particular state of the 3D renderer. For the <keyword> parameter, see the 3D_Set command above.

3D_Align  [flags...]

Aligns the selected wall surfaces with nearby walls, by changing their X or Y offsets. The flags control exactly what is affected by this command.
Flags:
/x : align X offsets
/y : align Y offsets
/right : pick a wall to the right to align with (instead of the left).
/clear : clear the X / Y offsets (instead of aligning).

3D_Forward  <dist>
3D_Backward  <dist>
3D_Left  <dist>
3D_Right  <dist>
3D_Up  <dist>
3D_Down  <dist>

Moves the 3D camera by a single step. The <dist> parameter gives the distance to move (in map units).
NOTE: these have been superceded by the NAV versions below, which allow moving smoothing through the map. However these are kept for backwards compatibility, and may still be useful for some people.

3D_Turn  <angle>

Turns the 3D camera left or right by a single step. The <angle> parameter is how far to turn, in degrees, where negative values turn right (clockwise) and positive values turn left (anti-clockwise).
NOTE: this has been superceded by the NAV version below, which allows turning the camera smoothly.

3D_DropToFloor

Drops the 3D camera down to the floor, as though the player was standing on the ground. This will raise the camera too if it is below that height.

3D_ACT_AdjustOfs

Adjusts the X and Y offsets on the selected surfaces. While the key or button is held down, moving the mouse will update the offset values.

3D_WHEEL_Move  <speed>

Moves the 3D camera using the mouse-wheel. Each click of the wheel will move a single step. The <dist> parameter is how far to move, in map units. When using this with the LAX modifier, holding SHIFT will move much slower and holding CTRL will move much faster.
NOTE: this command does not work unless bound to a mouse-wheel button.

3D_NAV_Forward  <speed>
3D_NAV_Back  <speed>
3D_NAV_Left  <speed>
3D_NAV_Right  <speed>
3D_NAV_Up  <speed>
3D_NAV_Down  <speed>

Navigates the 3D camera smoothly through the map, while the key is held down. The <speed> parameter is how fast to move, in map units per second. When used with the LAX modifer, the SHIFT key will slow down movement and the CTRL key will move faster.

3D_NAV_TurnLeft  <speed>
3D_NAV_TurnRight  <speed>

Turns the 3D camera smoothly left or right. The <speed> parameter is how fast to turn, in degrees per second. When used with the LAX modifer, the SHIFT key will slow down turning and the CTRL key will turn faster.

3D_NAV_MouseMove  <speed>

Moves or turns the 3D camera while the key or button is held down. Moving the mouse forward/back will make the camera go up/down (purely vertically), and moving the mouse left/right will turn the camera left/right. The <speed> parameter controls how fast to move or turn. When used with the LAX modifier, the SHIFT key will slow down movement and the CTRL key will move faster.
eureka-editor-eureka-2.0.2/htgen/Docs_Index.html000066400000000000000000000024341464327712600215560ustar00rootroot00000000000000

Documentation

Welcome to the documentation portal for Eureka.

Main Docs

Other Docs

  • How to Run Eureka
  • The Keys page summarizes the default keyboard and mouse bindings
  • The Cheat-Sheet is a printable PDF file of common commands

Project Info

  • Visit the About page for an overview of Eureka
  • See the Credits page for who to blame
  • The History page contains a summary of all releases
  • Future plans are in the TODO
eureka-editor-eureka-2.0.2/htgen/Docs_Invoking.html000066400000000000000000000143501464327712600222730ustar00rootroot00000000000000

Running Eureka

You can run Eureka a number of ways: from double clicking its binary after downloading and unpacking (the Windows and macOS packages), from the desktop menu (when installed e.g. from the Debian repository), or from the command line in a terminal emulator.

Note that Eureka needs a game IWAD in order to run. When it cannot find one, then the "Manage Wads" dialog will open up and you can use the "Find" button to locate one. If you do not own any of the games which Eureka supports, there is always the project "FreeDoom" which is completely free.

The rest of this page describes running Eureka from the command line.


Option Syntax

Option names begin with either one or two dashes. Short options consist of a single letter after a single dash, like -f and -w, whereas long options are a whole word following one or two dashes, such as --file and --warp.  Long options are shown on this page with two dashes, but a single dash is supported too, because that syntax was accepted by the original DOOM engine and various source ports.

Some options accept a parameter after them. There must be a space between the option name and the parameter, even for short options, and equal signs cannot be used. A few of the options accept multiple parameters, and each parameter must be separated by spaces too.

When the first thing on the command line is not an option, Eureka treats it as the filename of a pwad to edit. Multiple files can be specified this way.

Examples of valid options:

-w 1
-warp 2
--warp 3

Examples of invalid options:

-w   missing the parameter
-w2   no space between option and parameter
-w=3   equal signs cannot be used

General Options

-f  --file <filename>....

The wad file(s) to edit. When more than one filename is given, the first one is opened for editing, and the others can be accessed from the "Given Files" sub-menu(in the File menu.

-w  --warp <map>

Which level to edit. This can be the full map name, such as "MAP12" or "E3M4", but can also be a single number like "12" or "34", and for Ultimate DOOM and Heretic a pair of numbers (episode + map) is supported too.

-i  --iwad <filename>

The name of the game IWAD file. This specifies what game you are editing for, e.g. "doom.wad" will mean the map is for Ultimate DOOM, whereas "heretic.wad" means we are editing for the game Heretic.

-m  --merge <filename>....

Resource file(s) to load. These can be wad files containing textures, flats, sprites (etc), but can also be Eureka definitions files (with the .ugh extension).

-p  --port <name>

Name of the port (engine) being used. The default port is "vanilla", which refers to the original DOOM EXE (or to Chocolate-Doom), but some other supported ports are "boom", "mbf", "edge", "odamex", "legacy" and "zdoom".

-h  --help

Show a usage summary.

-v  --version

Show the version string.

-q  --quiet

Inhibits messages to the terminal. NOTE: has no effect on beeping!

-d  --debug

Enable extra debugging messages.

Configuration Options

The following options control how Eureka finds some important files and directories. They are not particular useful per se, but may be needed for special circumstances.

--install <dir>

The installation directory where game definition files, default key bindings, and a few other important files are located. Specifying "." for the install directory is useful when compiling and testing Eureka.

--home <dir>

The home directory where user settings, wad backups, and a few other files are stored. Under Linux and other Unixes, this will be the .eureka folder in the user's $HOME directory.

--log <file>

The file where all log messages are written. Defaults to logs.txt in the home directory.

--config <file>

The config file which stores all the user's preferences (except for key bindings). This file is loaded when Eureka starts up, and is saved whenever the user uses the Preferences dialog. Defaults to config.cfg in the home directory.

Environment Variables

The following environment vars are recognized by Eureka:

DOOMWADDIR

If set, contains a single directory name where Eureka will look for IWADs.

DOOMWADPATH

If set, contains a colon-separated list of directories where Eureka will look for IWADs.
eureka-editor-eureka-2.0.2/htgen/Docs_KeySystem.html000066400000000000000000000225671464327712600224550ustar00rootroot00000000000000

Key System

Eureka has a flexible system for binding commands (editing functions) to specific keys on the keyboard and buttons on the mouse. These bindings can be created and modified in the Preferences window, in the "Keys" tab (described below).

For a description of all the commands, see the CommandList page.


Key Names

Key names in the bindings list are based on what usually appears on the keyboard. Letter keys are lowercase without any modifiers, for example: 'a', and are uppercase when used with the SHIFT key, for example: 'A'. All other usage of the SHIFT modifier will show it explicitly.

Some common key names:

SPACE : the Spacebar key
BS : the Backspace key
INS : the Insert key
DEL : the Delete key
PGUP : the Page-Up key
PGDN : the Page-Down key
MENU : the Menu key (only on some keyboards)
F1, F2, F3 (etc) : the function keys

The mouse buttons also have names, as follows:

MOUSE1 : the left mouse button
MOUSE2 : the middle mouse button (or clickable wheel)
MOUSE3 : the right mouse button
WHEEL_UP : mouse wheel pushed up (forward)
WHEEL_DOWN : mouse wheel pushed down (backward)
WHEEL_LEFT : mouse wheel pushed left
WHEEL_RIGHT : mouse wheel pushed right

Lastly, the names of some keys may be unknown. These can still be used, but they will be shown as a cryptic code number. For example, on my system the left "Windows" key is shown as 0xfe03.


Modifiers

Modifiers are the keys like SHIFT and CTRL which you can hold down in addition to a normal key. Modifiers can be used with mouse buttons too, including the mouse wheel.

Modifiers cannot be bound to commands by themselves, they require another normal key or button. There is no distinction between left or right versions of a modifier key. Another restriction is that only one modifier can be used in a binding, so you cannot bind SHIFT+CTRL+SPACE to a command.

The following modifiers are supported:

SHIFT : all keyboards have this, 'nuff said.
CTRL : the control key. Under MacOS X this will be shown as "CMD" instead, and refers to the command key.
ALT : most keyboards have ALT keys, however on Linux this modifier is often used by the window manager to perform window management tasks, making it less useful for bindings. (I am not sure about Windows or MacOS X).
META : an additional modifier key which some keyboards have, e.g. in Linux the "Windows" key is sometimes usable for this. Eureka can generate fake META events by pressing the ; key followed by a normal key, which can be useful for binding extra commands.
LAX : this is not a real modifier key! Instead this means that the binding will match in a lax way, where the current state of the SHIFT and CTRL modifiers is ignored. This is useful for the navigation commands, which change speed depending on whether the SHIFT or CTRL modifiers are pressed.

Command Syntax

Commands are actions or functions which the editor can do. They may be something which modifies the map in same way, like deleting a sector, or they may simply change something in the interface, such as toggling the 3D view on/off.

The syntax of commands is based loosely on DOS syntax. Some commands require a parameter or two, and some commands have optional "flags" which are keywords that being with a '/' (forward slash). Multiple flags can be present, and each one will affect the behavior of the command in some way.

Examples:

UnselectAll
A command with no parameters and no flags. It simply unselects all objects in the selection.
Zoom +1
A command with a single parameter, "+1", which tells the Zoom command to zoom in (whereas "-1" would tell it to zoom out).
SEC_SelectGroup /floor_h /floor_tex
This command is used to select contiguous sectors, and here it has two flags: the /floor_h flag means the sectors must have the same floor height, and the /floor_tex flag means the sectors must have the same floor texture.

Special Prefixes

Some commands can only be used in a certain editing mode, and these commands have a prefix designating the mode, as follows:

LIN_xxx : only usable in Linedefs mode
SEC_xxx : only usable in Sectors mode
TH_xxx : only usable in Things mode
VT_xxx : only usable in Vertex mode
3D_xxx : only usable in the 3D view
BR_xxx : only usable when the Browser is open

There are a few commands which have a purely descriptive prefix, but are not limited to any particular mode, for example: GRID_Set.

Commands which contain "WHEEL_" can only be used with the mouse-wheel. Binding these commands to any other key or button will not work.

Commands containing "ACT_" and "NAV_" are ones which require you to hold the key or button down, such as scrolling the map with the cursor keys. Such commands will not work when bound to the mouse-wheel or certain keys on the keyboard, such as CAPSLOCK, NUMLOCK and PAUSE, because these keys behave differently from normal keys.


Binding Keys

You can create a brand new binding by clicking the "Add" button, or modify an existing binding by selecting the binding in the list and clicking the "Edit" button. The "Copy" button creates a copy of an existing binding and brings up the edit dialog for it. To remove a key binding altogether, click the "Delete" button.

The "Re-bind" button lets you assign a new key to the currently selected binding. That binding will turn yellow and wait for the next key or mouse button to be pressed. Pressing the ESC key cancels that process.

NOTE: like other preference settings, changes made to the key bindings are only kept when clicking the "Apply" button at the bottom of the preferences window. Use the "Discard" button if you decide you don't want to keep your changes, e.g. if you accidentally deleted some bindings.

The key-editing dialog allows you to change any aspect of a key binding. A new key name can be typed into the "Key" box, but an easier way is to press the "Re-bind" button, which will wait for the next key or button press. Use the ESC key to cancel that process. The "Choose" button lets you pick a different function to use, and the "Mode" button can limit the binding to a particular editing mode.

Most functions require at least one parameter, a few require two or more parameters, and many functions support several optional flags. The full set of parameters can be typed into the "Params" box, though for commands which use a keyword it is easier to pick the keyword directly from the "Keywords" menu. Also flags may be added or removed by choosing them in the "Flags" menu.

eureka-editor-eureka-2.0.2/htgen/Docs_Keys.html000066400000000000000000000211231464327712600214160ustar00rootroot00000000000000

Keyboard and Mouse Summary

All Modes

Cursor keys : scroll the map

MOUSE1 (LMB)

  • select an object, drag to move the object(s)
  • click in an empty area to clear the selection
  • click + drag in empty area to select a group of objects

MOUSE2 (MMB)

  • scroll the map around (by dragging)

MOUSE3 (RMB)

  • begin/continue line drawing (in vertex mode)
  • merge sectors (in sectors mode)
  • with CTRL pressed: bring up operation menu

WHEEL : zoom in or out

MENU : operation menu

TAB : toggle the 3D view on or off

t : enter Thing mode
l : enter Linedef mode
s : enter Sector mode
v : enter Vertex mode

b : toggle the Browser on or off

1 .. 9 : select the grid size (smallest to largest)

CTRL-z : undo (can be used multiple times)
CTRL-y : redo (i.e. undo the previous undo)

CTRL-a : select all
CTRL-i : invert the selection
CTRL-u : clear the selection

` (backquote) : clear the selection

HOME : move/zoom 2D viewport to show the whole map
END : move 2D viewport to camera location
' (quote) : move 3D camera to position of mouse pointer

f : toggle free mode vs grid snapping
g : toggle grid on / off

N : open next map in the current wad
P : open previous map in the current wad

j : jump to object (by its numeric id)
J : toggle object number display

o : copy and paste the selected objects
c : copy properties from selected --> highlighted object
C : copy properties from highlighted --> selected objects

H : mirror objects horizontally
V : mirror objects vertically

a : scroll map with the mouse
r : scale selected objects with the mouse
R : scale selected objects, allow stretching
CTRL-r : rotate the selected objects (with the mouse)
K : skew (shear) the selected objects

\ : toggle the RECENT category in the Browser

; : make the next key pressed META

META-n : load next file in given list
META-p : load previous file in given list

META-f : apply a fresh tag to the current objects
META-l : apply the last (highest) tag to the current objects

Things Mode

SPACE : add a new thing

w : rotate things 45 degrees anti-clockwise
x : rotate things 45 degrees clockwise

d : disconnect things at the same location
m : move selected things to occupy the same location

Vertex Mode

SPACE

  • begin/continue line drawing
  • with SHIFT pressed: continue in drawing mode
  • with CTRL pressed: inhibit creation of sectors

d : disconnect all linedefs at the selected vertices
m : merge selected vertices into a single one

I : reshape selected vertices into a line
O : reshape selected vertices into a circle
D : reshape selected vertices into a half-circle
C : reshape selected vertices into a 120-degree arc
Q : reshape selected vertices into a 240-degree arc

Linedef Mode

e : select a chain of linedefs
E : select a chain of linedefs with same textures

w : flip linedefs
k : split linedefs in two
A : auto-align offsets on all selected linedefs

d : disconnect selected linedefs from the rest
m : merge two one-sided linedefs into a two-sided linedef

Sector Mode

SPACE

  • add a new sector to area around the mouse pointer
  • if a sector is selected, copy that sector instead of using defaults

d : disconnect sector(s) from their neighbors
m : merge all selected sectors into a single one

e : select sectors with same floor height
E : select sectors with same floor texture
D : select sectors with same ceiling texture

w : swap floor and ceiling textures

, and < : lower floor heights
. and > : raise floor heights

[ and { : lower ceiling heights
] and } : raise ceiling heights

3D Preview

Cursor keys : move forward and back, turn left and right
(the WASD keys can also be used for moving around the map)

MOUSE1 (LMB) : select walls, floors or ceilings
MOUSE2 (MMB) : turn or move the camera (by dragging the mouse)

WHEEL : move camera forwards or backwards

PGUP and PGDN : move camera up and down

g : toggle gravity (i.e. as if the player was walking on the ground)
v : drop to the ground

r : adjust offsets on highlighted wall (by dragging the mouse)
c : clear offsets on highlighted sidedef

x : align X offset with wall to the left
y : align Y offset with wall to the left
z : align both X and Y offsets

X : align X offset with wall to the right
Y : align Y offset with wall to the right
Z : align both X and Y offsets

F11 : increase brightness (gamma)

l : toggle lighting on or off
t : toggle texturing on or off
o : toggle objects on or off

eureka-editor-eureka-2.0.2/htgen/Main_About.html000066400000000000000000000047771464327712600215710ustar00rootroot00000000000000

About Eureka

Eureka is a map editor for the classic DOOM games, and a few related games such as Heretic, Hexen and Strife. The supported operating systems are: Linux (and other Unices), Windows and macOS.

Eureka is free software under the GNU General Public License (GPL). Please note that it comes with absolutely NO WARRANTY of any kind.

History

It started when the Yadex editor was ported to a proper GUI toolkit, namely FLTK, and implemented a system for multi-level Undo / Redo. These and other features have required rewriting large potions of the existing code, and adding lots of new code too. Eureka is now an indepedent program with its own workflow and its own quirks :-)

See the Credits page for more information / copyrights.

Features

  • Undo/Redo (multiple levels)
  • 3D preview
  • Low system requirements
  • Editable panels for things, linedefs, sectors (etc)
  • Browser for textures, flats, things (etc)
  • Key binding system
  • Built-in nodes builder

Supported Games

  • DOOM
  • DOOM 2
  • Final Doom
  • FreeDoom
  • HacX
  • Heretic
  • Hexen
  • Strife

Requirements

  • 128 MB of computer memory
  • 800x600 or higher screen resolution
  • a keyboard and a two-button mouse
  • the data (IWAD) file from a supported game (DOOM etc)

Getting in Contact

There is a discussion forum on Eureka's SF project page, as well as the issue tracker on GitHub there for making bug reports or feature suggestions.

Screenshots

Normal editing:
Screenshot 1

The 3D preview:
Screenshot 2

Texture browser:
Screenshot 3

eureka-editor-eureka-2.0.2/htgen/Main_Changes072.html000066400000000000000000000031761464327712600223100ustar00rootroot00000000000000

CHANGES IN Eureka 0.72

(Changes are since the 0.64 version)

++ the File menu is fully operational (albeit a bit clunky)

++ browser for textures, flats, thing types (etc)

++ can scale/rotate stuff with middle mouse button

+ grid snapping works again ('f' key to toggle)

+ quantization function ('q' key) which grid-snaps objects

+ disconnect function ('d' key) in vertex and linedef modes

+ automatic sector insertion when closing a line loop
+ automatic sector splitting when a line crosses a sector

+ the -iwad option works again

- split linedefs by just inserting a vertex on a highlighted line
- merge two linedefs by just deleting the vertex in-between

- select linedef path function ('e' key)
- correct sector function ('c' key)
- new sectors get default flats/textures/etc

- invert selection function (CTRL-I or Edit menu)
- draw the camera on the map (a pink arrow)
- move camera function (quote key) and goto camera (END key)

- can find an IWAD (doom2.wad only) in $DOOMWADDIR
- the IWAD is opened in read-only mode

- partial support for DOOM 1 and HERETIC (need -warp E1M1)

- games/ directory for game definitions
- ports/ directory for source port definitions

eureka-editor-eureka-2.0.2/htgen/Main_Changes074.html000066400000000000000000000041271464327712600223070ustar00rootroot00000000000000

CHANGES IN Eureka 0.74

(Changes are since the 0.72 version)

+ show the current WAD and map in the window title bar.

+ clipboard persists when changing maps, so you can copy-n-paste from one map/wad to another map/wad.

+ various user state (grid settings, camera, editing mode, etc..) persists when a map is saved, and is restored when the same map is loaded again.

+ improved SECTOR insertion:
(a) copy properties from a selected sector, or try a neighboring sector if no selection. Use default value as last resort.
(b) if CTRL is pressed, new area BECOMES the same sector as one selected.

+ new 'Sort' setting in Thing/Line/Sector type browsers.

+ new 'ADD' and 'DEL' sidedef buttons in the LineDef panel.

+ new -port option to select the source port. Defaults to boom. Other values currently supported are: vanilla, edge.

- fixed problem where you could seemingly close a line loop, but due to grid snapping the vertex was merely placed on top of the existing one and it did not actually close the loop.

- fixed bug where closing a line-loop around an existing shape did not apply the new sector to the outside of that shape.

- new outside-of-map sectors now occupy a single grid square.

- File/New does not ask for map slot unless there's a current PWAD, since that will be asked on the File/Save (== File/Export).

- File/Export asks for the map slot after the filename.

- dynamic rotating (CTRL + middle button) no longer scales.

- dragging/scaling/rotating vertices will draw the lines too.

- fixed display of a certain flat (CEIL4_1 IIRC) showing bright cyan in parts that should be black (palette color #247).

- better looking About box.

eureka-editor-eureka-2.0.2/htgen/Main_Changes081.html000066400000000000000000000045741464327712600223130ustar00rootroot00000000000000

CHANGES IN Eureka 0.81 (r186)

(Changes are since the 0.74 version)

+ support a proper Unix-style installation

+ made a proper web-site (using PmWiki)

+ command to build nodes (via glBSP) and quit

+ texture browser can be resized by dragging the edge

- log file is only created when --log is used
- the --quiet option (-q) suppresses output to stdout
- new --debug option (-d) enables debug messages
- allow long options to begin with '-' or '--'

- handle a pwad filename given without -file
- more lax finding of patch lumps for textures
- when no level is given, find first one in PWAD or IWAD
- support plain numbers with -warp

- look for iwads in the ~/.eureka/iwads directory
- when searching for iwads, look for more names (e.g. "doom.wad")
- if -iwad parameter is a bare name, look in iwad search path
- if -iwad parameter has no extension, add ".wad"

- using SPACE on a single selected vertex will unselect it
- closing a simple vertex loop always makes a new sector inside it
- can now split a line when one of its vertices is selected

+ new 'm' command for merging sectors
+ new 'c' command to copy sector/thing/line properties

- added 'same_mode_clears_selection' config var (emulates Yadex behavior)

- 3D view: support strafing with ALT or META key

- initial support for Odamex

- DOOM: fixed line types 33 and 34 (red and yellow locked doors)
- DOOM: restored the 'Computer Map' pickup
- DOOM: fixed "SW2xxx" textures not having the right category

- EDGE: added slope line types
- EDGE: added some missing things (jetpack, green keys, dog, stealth mons)
- EDGE: fleshed out sector types
- EDGE: fleshed out line types (hub exits, sliding doors, RTS)

- TNT: assigned the new textures into categories (e.g. "Crates")
- PLUTONIA: assigned the new textures into categories

eureka-editor-eureka-2.0.2/htgen/Main_Changes084.html000066400000000000000000000044331464327712600223100ustar00rootroot00000000000000

CHANGES IN Eureka 0.84 (r304)

(Changes are since the 0.81 version, r186)

+ multi-select : LMB toggles each object (no need for CTRL key)

+ can click on a texture in the LineDef or Sector panels, it becomes highlighted, the browser is opened (if not already), and only the selected parts are changed when clicking in the browser.

+ implemented a -merge option for resource wads

+ reload the wad/map after building the nodes (no longer exit)

- ESC key no longer quits
- plain MMB now inserts an object (like SPACE or INSERT key)
- thing panel has radial arrow buttons for setting the angle

- insert thing: if one already selected, copy its properties
- improved line split highlighting when SNAP mode is active
- limit size of drawn vertices when zooming right in

- allow running locally (without a 'make install')
- iwad search: check more places (like /usr/share/games/doom)

- fixed possible fatal error with zero-length lines
- fixed state persistence to ignore unused vertices (etc)
- fixed inner sector getting defaults when closing simple loop
- fixed pink-highlighted tagged sectors when line was off-screen
- fixed CMD key on MacOS X to only trigger menu commands

- config: can specify a boolean value on the command-line
- config: new simpler syntax for config files
- config: added var: escape_key_quits
- config: added var: leave_offsets_alone
- config: added var: mouse_wheel_scrolls_map
- config: added var: new_islands_are_void

- Browser: faster scrolling with the mouse wheel

- Heretic: fixed the default port (i.e. not BOOM)

- 3D view: can use WASD keys in 3D mode to move around
- 3D view: the 'g' key toggles gravity (walking on the ground)
- 3D view: toggle sprites changed key to 'o' (objects)
- 3D view: removed CTRL-L function, resync objects with 'o' key

eureka-editor-eureka-2.0.2/htgen/Main_Changes088.html000066400000000000000000000050221464327712600223070ustar00rootroot00000000000000

CHANGES IN Eureka 0.88c (r605)

(Changes are since the 0.84 version, r304)

+ large overhaul of file handling:

+ 'Manage Wads' dialog allows setting the IWAD, port and resource wads
+ 'Open Map' dialog, with buttons for easy map selection
+ 'Recent Files' dialog (CTRL-R or File menu)
+ the iwad/port/resource settings are saved in the PWAD
+ better 'Export Map' dialog
+ IWADs found by the user are remembered

+ new Default Properties panel (shown in vertex mode)
+ implemented picture mode for Thing browser
+ new Move/Scale/Rotate dialogs (via Edit menu)

+ support for Doom Legacy, courtesy Wesley Johnson
+ support for HACX (not quite finished, but usable)
+ 3D view: fixed the slime trails

- added 'd' disconnect command for sectors
- added 'm' merge command for vertices
- added 'm' merge command for two linedefs

! the -iwad parameter can no longer be a directory name

- shortcut key for 'File/Export Map' is now CTRL-E
- swapped sector height keys: '.' ',' <---> '[' ']'
- grid-snap button is easier to use (a toggle button now)
- can disable multi-select ('multi_select_modifier' config var)
- sectors created outside of map now have fixed size
- show a '*' in window title when map has unsaved changes

- got 'View/Jump to Object' command working ('j' key)
- got 'View/Show Object Numbers' working (also on 'J' key)
- new 'View/Whole Selection' command
- new 'View/Toggle Grid Type' command

- fixed rotating a group of things to update their angles too
- fixed wrong color of a tagged linedef or sector
- fixed zooming out on File/Open when map has persistent state
- fixed middle texture when pasting and linedef lost a side

- config: default grid size is now 64 (was: 128)
- config: added var: default_grid_size
- config: added var: default_grid_snap
- config: added var: digits_set_zoom

- config: added var: new_sector_size
- config: added vars: gui_scheme and gui_color_set
- config: added some glBSP-related vars

eureka-editor-eureka-2.0.2/htgen/Main_Changes095.html000066400000000000000000000034511464327712600223110ustar00rootroot00000000000000

CHANGES IN Eureka 0.95 (r932)

(Changes are since the 0.88c version, r605)

+ Preferences dialog

+ Key binding system, with GUI in preferences

+ Windows port (32-bit) with an installer

+ Automatically back-up edited wads (multiple times)

+ Status area on info bar -- replaces map name

+ Log viewer

- new 'Prune Unused' command removes unused stuff (sectors etc)

- fixed explosion of wad size when saving repeatedly
- fixed crash clicking a linedef flag when nothing was selected
- fixed PGUP / PGDN keys to scroll the browser
- fixed jerky RMB scrolling at large zoom factors

- Scale Objects: implemented Z scaling for sectors
- Default Props panel is now hidden by default
- copy properties command ('c') now copies linedef textures
- swapped grid keys: 'g' now makes the grid smaller, 'G' bigger
- key for splitting lines in half is now 'k' -- it was 'x'

! removed the 192 grid size

- prevent making two lines overlap when merging vertices
- merge: support one selected + one highlighted
- merge command for things -- place them at same location
- disconnect command for things at same location

- when a resource cannot be found, look in same dir as PWAD and IWAD
- when saving over a map, use existing location in the wad
- command line options: '-m' is shorthand for '--merge'
- preference setting to swap upper and lower in Linedef panel

eureka-editor-eureka-2.0.2/htgen/Main_Changes100.html000066400000000000000000000057551464327712600223050ustar00rootroot00000000000000

CHANGES IN Eureka 1.00 (r1422)

(Changes are since the 0.95 version, r922)

+ extensive map-checking functions

+ validate map data when loading a level

+ texture alignment commands for 3D view

+ splitting void islands now works as expected

+ improved grid, with configurable colors

+ scroll-bars for the map view (optional)

- one sided linedefs show texture in the "Lower" spot

- automatically unpack sidedefs when loading a map

- support multiple filenames: new 'File/Given Files' menu
- commands to visit the next or previous file
- commands to open the next/previous map ('N' and 'P' keys)
- changed 'File/Recent Files' to be a sub-menu
- option to automatically open the most recent file

- improved About dialog with Jason R. Johnston's logo
- improved Log viewer, ability to save the logs to a file
- improved dialog boxes

- support Eureka config (.ugh) files as resource files
- support $DOOMWADPATH for finding IWADs

- implemented SEC_Light() binding command
- commands for setting tags on linedefs/sectors
- Edit / Move objects: implemented Z value for sectors

- the ';' key waits for next key and makes it META

- better drawing of selected sectors
- better drawing of highlighted things and linedefs
- better drawing of things (in THINGS mode)

- show unknown/missing textures in the LineDef panel
- show unknown/missing textures in the 3D preview

- display the lengths of the last few linedefs
- can modify the length of a line in the LineDef panel
- improved behavior of vertices when grid-snap is on

- option to limit grid toggle to a single kind
- option to show grid in SNAP mode, hide it in FREE mode
- option to set the default editing mode
- option to set the default port

- 3D View: option to set the aspect ratio
- 3D View: option to prevent up/down moves when gravity is on

- remember the browser width for a saved map
- remember the 3D mode (the lack of it) for a map

- fixed crash bug when loading or saving a map containing linedefs which have no right sidedef

- fixed rare map saving problem (header lump in wrong position)
- fixed possible crash not clearing selection after loading a map
- fixed wrong linedef (etc) totals after loading another map
- fixed key binding dialog: unable to remove a parameter
- fixed the selection after a sector merge

eureka-editor-eureka-2.0.2/htgen/Main_Changes107.html000066400000000000000000000127541464327712600223110ustar00rootroot00000000000000

CHANGES IN Eureka 1.07 (r1716)

(Changes are since 1.00 version, r1416)

+ implemented Find and Replace (as a panel), with support for stepping though each item or selecting them all, and filters to control which items to visit or ignore

+ added 'File / New Project' command as the proper way to create a brand new WAD file. The 'New Map' command requires a current pwad, and will save the fresh map immediately into it

+ new 'RECENT' category for Texture/Flat/Thing browsers, and rebound the '\' key to toggle this category on/off

+ new 'Rename Map' and 'Delete Map' commands in FILE menu

+ improvement to key binding system, support for "flags" which are parameters beginning with a forward slash, such as "/new" and "/clear". The 'EditKey' dialog is now much easier to use too

+ Windows package no longer uses an installer

+ vertex reshaping commands:

   -  'I' moves selected vertices onto a line
   -  'O' moves them into a circle shape
   -  'D' moves them into a half-circle
   -  'C' moves them into a 120-degree arc
   -  'Q' moves them into a 240-degree arc

- a preference to show smaller textures in the browser

- map checker can find unknown linedef and sector types

- Linedef panel: swapped the 'Tag' and 'Length' positions

- Linedef panel: always show a two-sided line panel when multiple lines are selected (allowing all texture parts to be edited)

- Linedef panel: don't show rail/upper tex for one-sided lines (can be disabled with the 'show_full_one_sided' config var)

- when loading a wad specified on the command line, and it contains settings for the iwad, port and/or resources, then allow command line arguments to override those values (and _add_ new resources)

- new preference to maximize window on start (Linux, WIN32 only)

- the Default Properties now has its own panel

- Default Props: only a single wall texture now, and shows a sprite for the default thing which opens the browser when clicked on

- added back the '192' grid size


- browser: changed two key-bindings: 'T' now opens to Things and 'X' is used to open it to Textures (matching the menu shortcuts)

- browser: changed key-binding for BR_CycleCategory to '|'

- browser: the 'Sort' menu has been replaced with an 'Alpha' checkbox

- browser: made sprites a bit smaller, can now show three columns when browser is at minimum width

- better way to show how a linedef will be split (esp. when snapping)

- co-op player sprites are now colored as in DOOM

- 3D view: the low/high detail flag is now a preference setting (no longer toggleable with the F5 key)

- added info bar for 3D view, shows current position, angle, etc...

- added 'Toggle 3D View' command to View menu


- support loading a read-only wad file

- support data in a map header lump (such as MAP01), make sure to save it when saving the map (instead of removing it)

- node builder: added work-around for "TOO SIMPLE" levels (i.e. a single convex sector), creating a dummy node and an extra subsector and seg for the back side

- wrote a Unix man page

- vanilla DOOM: do not show "friend", "coop" or "sp" thing flags

- support -warp option being followed by two numeric arguments (episode and map number), compatible with vanilla DOOM

- when checking textures, ignore ones beginning with '#'

- show version _in_ the About box (not just the window title)


Bug Fixes:

- fixed not loading 'ASHWALL' texture for DOOM 1

- fixed bug when saving and using the 'ExMx' buttons (an erroneous newline was added into the map lump name)

- 3D view: fixed a vertical mis-alignment of textures (one pixel) in certain circumstances

- fixed occasional false positives with sector mismatch test

- fixed wrong focal point when zooming immediately after the 'j' (JumpToObject) command

- fixed category of linetype #68 (should be a raising floor)

- fixed clipping of mid-masked textures (e.g. the cage in E1M9)

- fixed not reloading textures (etc) when opening a new wad file

- fixed crash when trying to build nodes on an IWAD map which has some changes made to it, but has not been saved (exported) yet

- fixed key binding list so that pressing 'Bind', 'Copy' etc on a non-visible line will scroll to that line (make it visible)

- browser: fixed patterns like '4$' not working properly

eureka-editor-eureka-2.0.2/htgen/Main_Changes111.html000066400000000000000000000061301464327712600222730ustar00rootroot00000000000000

CHANGES IN Eureka 1.11

(Since the 1.07 version)

Games and Ports:

+ Hexen support!

  (thanks to printz for doing some of the heavy lifting)

+ Boom generalized lines and sectors

+ treat Freedoom Phase 1 and Phase 2 as separate games

+ added Eternity port definition, thanks to printz

- Heretic: categorized the textures and flats
- changed default port from Boom --> Vanilla

Editing:

+ rendering of sector flats/lighting in the 2D window

+ easier vertex "drawing mode" using the LMB

+ when adding lines, automatically split crossed lines

- inserting a vertex with SHIFT continues the drawing mode
- inserting a vertex with CTRL inhibits creation of sectors

- SHIFT + LMB in sectors mode always opens a selection box
- better merging of linedefs when dragging a vertex
- prevent overlapping lines when deleting 3rd vertex of a triangle

- much less chance to accidentally drag an object
- when a line splits a sector, use a consistent orientation
- when creating a fresh map, add all four player starts
- allow loading a map with no vertices, no linedefs (etc)

UI:

+ fixed texture warping in 3D preview

- sector panel: buttons for quickly setting the headroom
- sector panel: MMB on the ceiling flat sets it to sky
- right-click on a sidedef or sector texture sets it to default
- various layout tweaks to the editing panels

- added "Recent Textures" command (etc) to Browser menu
- fixed RECENT category to show most recent items at the top
- status bar lets you see full message via a tooltip

Commands:

- new "Last Selection" command, undo an accidental clearing
- added /reverse flag for CopyProperties command
- extended LIN_Flip command, avoid making lines with no right side

Map checking:

- find "dangling" vertices
- detect the Medusa Effect on 2S lines
- detect transparent tex on solid walls

- find manual doors on 1S lines
- don't consider teleport things to be stuck in monsters
- ability to SHOW unused vertices

Miscellaneous:

- improved eureka.desktop file, courtesy Fabian Greffrath
- have a fallback sprite for the MBF dog thing (id 888)
- replaced "Aspect ratio" with "Pixel aspect ratio" in preferences
- use absolute paths for resource filenames in __EUREKA lump

eureka-editor-eureka-2.0.2/htgen/Main_Changes121.html000066400000000000000000000120051464327712600222720ustar00rootroot00000000000000

CHANGES IN Eureka 1.21

(Since the 1.11 version)

Editing:

+ line drawing now done using RMB (MOUSE3) button

+ improved drag behavior, never modify the current selection

+ select/copy/paste textures in the 3D view

+ an operation menu, bound to F1 key or CTRL-RMB

+ undo/redo: show what was undone in the status area

- improved ability to highlight/select very short linedefs
- improved insertion of sectors, less "area not closed" errors
- skew (shear) objects with the mouse, bound to K key
- "dotty" grid is a preference, rather than three-way toggle
- default edit mode is now Vertices, and grid-snapping OFF

- linedef/sector/thing descriptions update as the user types
- arrow buttons in Vertex panel for fine adjustments
- auto-align linedefs on the 2D map, bound to a key
- entering a negative "Length" in Linedef panel moves the start vertex of the line instead of the end vertex

General:

+ improved BSP code, can build nodes for a map on each save, building nodes no longer resets the undo/redo history, more preference settings, ability to disable GL nodes, and support for ZDoom uncompressed node format (XNOD)

+ "Test Map" command for testing your map in the game

+ sprite rendering on the 2D canvas (in Things mode)

+ a mode to show sound propagation

- a new "File/Copy Map" command
- a better dialog for "File / Open Map" command
- a better dialog for "JumpToObject" command
- a "Reset All Settings" button in the preferences dialog

- find/replace: added a "Restrict to Selection" filter
- find/replace: better way to choose textures/things
- changing categories in the browser clears the search box
- increased number of remembered recent files
- better default directory for file chooser dialogs
- more useful info bar in the 3D view

Games and Ports:

+ properly limit which ports can be used with each game

+ ZDoom definition file (thanks to Slade3)

+ Strife support (based on the Slade3 config)

+ support TX_START/TX_END textures, including PNG and TGA format

- find sprites outside of S_START/S_END (except in vanilla)

- support for the Harmony TC
- support for Doom-in-Hexen mapping
- added "MBF" as a separate port

Key System:

+ mouse buttons (and wheel) use the key binding system

+ smooth navigation for the 2D and 3D views

- allow key bindings to override hard-coded menu shortcuts
- bindable commands for all the functions in the menus
- use F1..F12 function keys for various menu shortcuts
- improved key binding dialog in the preferences

- changed scaling and rotation to the r key (was MOUSE2)
- changed map panning to use MMB (MOUSE2) or the a key
- changed browse-textures back to T key
- changed grid toggle to the g key

- Zoom command supports a "/center" flag
- LIN_Flip command was simplified with a "/force" flag
- Enlarge and Shrink commands support fractional values
- Gamma command removed, using "Toggle gamma" instead

Bugs Fixed:

+ fixed problem of unable to split lines close to an end-point

- fixed problem of deleting a loop of linedefs inside another sector could sometimes delete that outer sector too

- fixed unwanted rail texture when splitting a sector and the texture name began with '_' or '#' (such as "_WALL").

- fixed inaccurate criss-cross linedef detection
- fixed rendering of unpegged lowers under sky ceilings
- fixed textures in Linedef panel not updating after undo or redo
- fixed exporting to keep the iwad/port/resources of target wad

- fixed panel stuck on a highlighted object when going to 3D view
- fixed unknown texture "FIX" button to not change "-" textures
- fixed bad sidedef fallback when loading a map with no sectors
- fixed default pixel-aspect to be 0.83 (matching original DOOM)

eureka-editor-eureka-2.0.2/htgen/Main_Changes124.html000066400000000000000000000051451464327712600223040ustar00rootroot00000000000000

CHANGES IN Eureka 1.24

(Since version 1.21)

+ new "Edit Text Lump" command for editing text lumps

+ moved some menu commands to new "Tools" menu

+ fixed wall sorting issue in 3D View which could cause a crash
+ fixed fatal "zero-length line" error when drawing lines
+ fixed sector merge to keep properties of first selected sector
+ fixed inserting things in Hexen having no SP/COOP/DM/class flags

+ faster drawing of plain map view under X windows
+ faster sector rendering on huge maps

- new "fresh" tag button in the Sector panel
- more ZDoom sector types and GZDoom point-light things
- when changing grid size via keyboard, show grid if hidden
- new "Add BEHAVIOR" command to support ACS scripting

- show warning when port is not compatible with current game
- handle text files containing a Unicode BOM (byte-order mark)
- support Strife's new thing flags and linedef flags
- open-map dialog has buttons for ALL maps (in a scrollable area)

- hexen format: fixed wrong sector specials when game is DOOM
- hexen format: show every arg value when special is not 0
- hexen format: support ZDoom generalized sectors

- preferences: a setting to show sidedef ADD / DEL buttons
- preferences: a setting for default sector rendering
- preferences: a setting for default sprite rendering

- map checker: look for unspawnable things
- map checker: check usage of special 666 / 667 tags
- map checker: find non-animating switch textures (on usable lines)
- map checker: fixed merging multiple sets of overlapping verts

- fixed Find/Replace to handle generalized sectors
- fixed wall torch sprite in the Heretic game config
- fixed closed sectors in 3D view having a see-through gap

- fixed raising Eureka window when other windows have KB focus
- fixed "View Logs" command to raise the logs window
- fixed malformed warnings when linedefs contain an invalid vertex
- fixed "Removed unused vertices" message to show correct number

- handle some rare assertion failures more gracefully
- various improvements to the Makefile, e.g. create the OBJ_DIR
- added VIM syntax file for editing definition (.ugh) files

eureka-editor-eureka-2.0.2/htgen/Main_Changes127.html000066400000000000000000000052411464327712600223040ustar00rootroot00000000000000

CHANGES IN Eureka 1.27b

+ fixed a crash bug

CHANGES IN Eureka 1.27

(Since version 1.24)

+ use OpenGL for faster rendering of 2D and 3D views
+ improved non-GL drawing of 2D view, much faster in Linux
+ support mixing textures and flats for ports that allow it
+ improved 3D mode, can move things and sector surfaces
+ ratio lock, makes producing lines at certain angles easier

- a single status bar for both 2D and 3D views
- new popup menus to set edit mode, browser mode, scaling
- render sectors in the 2D view with both lighting and texturing
- create void islands by drawing lines anti-clockwise in a sector
- snap position indicator for 2D view (a light-blue cross)
- added scale "-" and "+" buttons, show scale as percentage
- ability to highlight/select railings in 3D view
- beginning of support for UDMF maps (not usable yet...)

- render BOOM's deep water effect (linetype 242)
- render 3D Floors for EDGE, LEGACY and ZDOOM ports
- render basic slopes for EDGE, ETERNITY, ODAMEX and ZDOOM
- render things with a NULL sprite as a blue triangle
- render Hexen map-spots as a green triangle
- render unknown things with a smaller '?' sprite

- preference to combine flats and textures in a single browser
- preference to show all textures on a one-sided linedef
- preference for linedef information (Length, Angle, Ratio)

- support ESC key to cancel a current action (e.g. dragging)
- support SHIFT and CTRL when using mouse-wheel to move in 3D view
- support the FreeDM iwad
- support TNT and Plutonia textures in FreeDoom2 iwad
- support Hexen map format in the ETERNITY port
- support PNG, JPEG and TGA images in sprite/flat/patch lumps
- added portal specials 156 and 107 to the ZDOOM port
- added missing specials 105, 106 and 130 to the ZDOOM port
- improvements to the Makefile
- improvements to the MacOS build files

- fixed mode menu disappearing into Window's task bar when maximized
- fixed not remembering test-in-game EXE when port is "vanilla"
- fixed the "Online Docs" command in the Help menu
- fixed window title not showing correct map name
- fixed Re-bind in key binding dialog to show new key as valid
- fixed grid getting out-of-sync with the "hide in FREE mode"
- fixed needless line flips when drawing clockwise within a sector

eureka-editor-eureka-2.0.2/htgen/Main_Changes2.0.0.html000066400000000000000000000000331464327712600224220ustar00rootroot00000000000000
eureka-editor-eureka-2.0.2/htgen/Main_Changes2.0.1.html000066400000000000000000000000331464327712600224230ustar00rootroot00000000000000
eureka-editor-eureka-2.0.2/htgen/Main_Credits.html000066400000000000000000000003161464327712600220750ustar00rootroot00000000000000
eureka-editor-eureka-2.0.2/htgen/Main_Download.html000066400000000000000000000005641464327712600222540ustar00rootroot00000000000000

Download Page

See GitHub for the most recent releases.

See SourceForge for releases up to 1.27b.

eureka-editor-eureka-2.0.2/htgen/Main_History.html000066400000000000000000000034331464327712600221440ustar00rootroot00000000000000

Version History

Public Releases

Pre-release Versions

  • Version 0.74 : 17-Feb-2012 : Changes074
  • Version 0.72 : 01-Feb-2012 : Changes072
  • Version 0.64 : 27-Nov-2011 : no changelog

Commit History

For all the gory details, head over to the SVN_Logs page.

eureka-editor-eureka-2.0.2/htgen/Main_SVN_Logs.html000066400000000000000000035341021464327712600221420ustar00rootroot00000000000000

Git and SVN Logs

__________________

REPOSITORY HISTORY
__________________


This file contains commit logs from several different repositories,
in reverse chronological order (from newest to oldest).

When I first created Eureka (forking from Yadex), I just made all
the changes on my hard-drive -- without using any source control
at all.  Hence there are no change logs from that period.

After a while, I developed the code on the EDGE SVN repository,
and later moved the code to the AwwPorts repository and continued
developing it there.  Eventually I made a preview version available
on the DoomWorld forums to see if there was any interest, and then
registered a SourceForge project for it, and the code repository
got moved yet again.

In January 2016 the SVN repository was converted into a GIT
repository (still on SourceForge though).


====================================================
    CURRENT DEVELOPMENT (GIT)
====================================================

------------------------------------------------------------------------
805f280c4502 | Andrew Apted | 2018-08-05 20:10:14 +1000

CHANGELOG : added a missing item.

------------------------------------------------------------------------
ff3c215b9698 | Andrew Apted | 2018-08-05 19:44:21 +1000

README : updated the date.

------------------------------------------------------------------------
a8dc678a77da | Andrew Apted | 2018-08-05 19:39:59 +1000

CHANGELOG : tidied up for the release.

------------------------------------------------------------------------
20809fa092e6 | Andrew Apted | 2018-08-05 19:30:27 +1000

honor defaults for sector/sprite rendering when opening new maps.

------------------------------------------------------------------------
e35bd815e310 | Andrew Apted | 2018-08-05 19:15:55 +1000

preferences : a setting for default sprite rendering (on/off).

------------------------------------------------------------------------
181480403d86 | Andrew Apted | 2018-08-05 18:29:53 +1000

canvas : disable sector rendering when in error mode.

------------------------------------------------------------------------
b3179498cbda | Andrew Apted | 2018-08-05 18:22:01 +1000

CHANGELOG and TODO update.

------------------------------------------------------------------------
686cc40428f9 | Andrew Apted | 2018-08-05 18:19:43 +1000

canvas : ensure the sector cache is invalidated when necessary.

------------------------------------------------------------------------
d23b8b0b8a63 | Andrew Apted | 2018-08-05 17:55:07 +1000

canvas : quickly reject off-screen sectors in RenderSector().

This uses the new sector_info cache.  This test and the
reduced linedef range to iterate over has already massively
improved the sector rendering performace on huge maps (when
the whole map is not in view, at least).

------------------------------------------------------------------------
93c1f08fc392 | Andrew Apted | 2018-08-05 17:39:00 +1000

canvas : added a sector_info cache which remembers some sector info.

So far the cache stores the linedef range used by sectors, and
also the bounding box of each sector.  RenderSector() will use
the cache to help speed up sector rendering.

------------------------------------------------------------------------
6747daff609a | Andrew Apted | 2018-08-05 15:59:41 +1000

CHANGELOG and TODO update.

------------------------------------------------------------------------
8cbd07da0449 | Andrew Apted | 2018-08-05 15:51:17 +1000

canvas : speed up drawing selection when it has many sectors.

This affected all OSes (not just X windows), especially in
maps with a huge number of linedefs.  The slowdown was caused
by iterating over the selected sectors one-by-one, and for
each sector we iterated over ALL the linedefs.

This commit uses a better method when the selection mode is
OBJ_SECTORS and the number of sectors is large.  It performs
just a single iteration over the linedefs.

------------------------------------------------------------------------
dd45516e3d87 | Andrew Apted | 2018-08-05 15:33:00 +1000

canvas : speed up drawing the selection under X windows.

------------------------------------------------------------------------
7f2651e73f68 | Andrew Apted | 2018-08-05 15:19:43 +1000

canvas : moved fl_line_style() calls out of DrawMapVector().

This is preliminary work to speed up drawing of the selection,
which is greatly slowed down under X windows by all the calls
to fl_line_style().

------------------------------------------------------------------------
638b74924669 | Andrew Apted | 2018-08-05 14:44:47 +1000

canvas : reworked DrawHighlight() to minimize color changes.

Includes splitting off some code --> DrawTagged() method.

------------------------------------------------------------------------
0e9a99b631e0 | Andrew Apted | 2018-08-05 14:14:44 +1000

canvas : small speed up of DrawThings() and DrawThingBodies().

------------------------------------------------------------------------
08ed828a2231 | Andrew Apted | 2018-08-05 13:15:40 +1000

canvas : big speed up of DrawLinedefs() under X windows.

It turned out that FLTK's fl_color() under X windows is very
very slow.  This commit works around that issue by iterating
over the lines multiple times, drawing e.g. all LIGHTGREY lines
in a single pass.

------------------------------------------------------------------------
28117740dea9 | Andrew Apted | 2018-08-04 22:35:46 +1000

preferences : moved sector rendering setting --> Grid tab.

------------------------------------------------------------------------
227054a4c2ff | Andrew Apted | 2018-08-04 22:22:00 +1000

wad code : in ReadDirectory, detect invalid lumps.

In other words, detect lumps with where the start or length
are negative or beyond the end of the wad file.

When found, we log a warning message and clear the lump
(make it empty), since an invalid position would lead to an
error or assertion failure later on (e.g. when saving).

------------------------------------------------------------------------
4f0f9d2746ae | Andrew Apted | 2018-08-04 16:06:39 +1000

TODO update.

------------------------------------------------------------------------
7c8de6a554f9 | Andrew Apted | 2018-08-04 16:05:19 +1000

basic validation of the ACS bytecode for "Add BEHAVIOR" command.

------------------------------------------------------------------------
74e3cb5ab9af | Andrew Apted | 2018-08-04 16:02:12 +1000

lib_file : fixed FileLoad() to handle zero-length files.

------------------------------------------------------------------------
ad2e7f803848 | Andrew Apted | 2018-08-04 15:32:13 +1000

implemented new "Add BEHAVIOR" command.

This inserts a compiled ACS file as the BEHAVIOR lump of the
current map.

------------------------------------------------------------------------
ab6fd9306e08 | Andrew Apted | 2018-08-03 14:51:29 +1000

wad code : better error message for "want_pos < total_size" assertion.

------------------------------------------------------------------------
0cf8157eaad4 | Andrew Apted | 2018-08-03 13:36:08 +1000

ZDoom : render point-light things as a yellow ball sprite.

These things use a fake sprite name "_LYT", and the sprite is
generated by some code.

------------------------------------------------------------------------
888ee2aba6ff | Andrew Apted | 2018-08-03 12:55:46 +1000

INSTALL.txt : describe compilation of the Windows binary.

There is also a small section for MacOS X, which merely
refers the reader to the documents in the osx/ folder.

------------------------------------------------------------------------
bdc27218d3b9 | Andrew Apted | 2018-08-02 23:48:15 +1000

TODO and CHANGELOG update.

------------------------------------------------------------------------
a9875d7be4e7 | Andrew Apted | 2018-08-02 23:43:54 +1000

Checks : improved fixer for non-animating switch textures.

The fixer now takes into account whether the lower and/or
upper texture is visible or not (due to sector heights),
and prefers to clear the one(s) which are not visible.

------------------------------------------------------------------------
5f1c21199f62 | Andrew Apted | 2018-07-22 20:35:17 +1000

Version bumped after recent WIP test package.

------------------------------------------------------------------------
7b360b027f8b | Andrew Apted | 2018-07-22 20:30:38 +1000

View Logs : always show/raise the log viewer window.

------------------------------------------------------------------------
26e85f719fd6 | Andrew Apted | 2018-07-22 19:06:07 +1000

fixed clumsiness in missing IWAD dialog (hide the Setup button).

------------------------------------------------------------------------
6d743345bae2 | Andrew Apted | 2018-07-22 18:54:05 +1000

fixed spurious warning dialog about incompatible ports.

For example, specifying --wad as "tnt" and --port "boom" would
trigger the incompatible port warning dialog.  The compatibility
checking code was not handling game variants (e.g. "tnt" is marked
as a variant of "doom2").

------------------------------------------------------------------------
d109b4628cd7 | Andrew Apted | 2018-07-22 18:07:56 +1000

CHANGELOG : added recent changes (not yet prettified).

------------------------------------------------------------------------
d7484099f502 | Andrew Apted | 2018-07-22 18:07:00 +1000

grid : when changing size via keyboard, ensure grid is shown.

------------------------------------------------------------------------
9178e56aa4ce | Andrew Apted | 2018-07-22 18:01:14 +1000

preferences : a setting for default sector rendering (on/off).

------------------------------------------------------------------------
bd1cbc6eed76 | Andrew Apted | 2018-07-22 17:09:26 +1000

removed config var "require_click_to_focus" + preference setting.

This has been solved in a way not requiring an extra setting
(see previous commit).

------------------------------------------------------------------------
7fe0f9e5edd6 | Andrew Apted | 2018-07-22 17:01:36 +1000

Linux/X11 : detect when our main window has "true" focus.

We do this by looking directly at the raw XEvents, because
FLTK does not provide the functionality needed.

When we don't have the true focus, then we never grab the
focus when the mouse hovers over the canvas/render widget.

This should fix ticket #22 once and for all.

------------------------------------------------------------------------
00a18a8c9127 | Andrew Apted | 2018-07-22 16:01:11 +1000

Preferences : better name for add/del button setting.

------------------------------------------------------------------------
5459891116ea | Andrew Apted | 2018-07-22 15:55:59 +1000

PORTS / ZDoom : added gzdoom PointLight things (9800-9824).

------------------------------------------------------------------------
798927a3d21c | Andrew Apted | 2018-07-22 15:44:48 +1000

PORTS / ZDoom : added zdoom hexen-format sector specials.

Specifically: the sector types 65-87, and 195-200.
These are ZDoom-ism which don't exist in vanilla Hexen.

------------------------------------------------------------------------
82c7390f8367 | Andrew Apted | 2018-07-04 16:30:17 +1000

moved several menu commands to a new "Tools" menu.

The commands are: Preferences, Test Map, Build All Nodes,
Edit Text Lump, and View Logs.

------------------------------------------------------------------------
34b25c12059f | Andrew Apted | 2018-07-02 00:25:56 +1000

TODO update.

------------------------------------------------------------------------
66d3a8f88755 | Andrew Apted | 2018-07-02 00:21:00 +1000

Merge branch 'master' of ssh://git.code.sf.net/p/eureka-editor/git

------------------------------------------------------------------------
28bead6e36f5 | Andrew Apted | 2018-07-02 00:20:10 +1000

Sector panel : added a "fresh" button for getting the next free tag.

------------------------------------------------------------------------
4186af94e186 | Ioan Chera | 2018-06-30 22:03:29 +0300

osx: fixed bad dependency on resolved symbolic link paths

------------------------------------------------------------------------
51ff0cd2abb7 | Ioan Chera | 2018-06-30 21:44:26 +0300

Updated the osx app version and removed a year-dependend plist entry

------------------------------------------------------------------------
25c17aee1c5b | Ioan Chera | 2018-06-30 21:44:06 +0300

Fixed Xcode developer ID settings

------------------------------------------------------------------------
4a1f991ab1b4 | Ioan Chera | 2018-06-30 21:40:24 +0300

Cleared all warnings from Xcode project

------------------------------------------------------------------------
735669adf8b6 | Ioan Chera | 2018-06-30 21:32:34 +0300

Ignore downloaded files in osx/

------------------------------------------------------------------------
511ff12a5526 | Ioan Chera | 2018-06-30 21:28:34 +0300

osx Xcode project now automatically downloads FLTK so you don't need to prepare dependencies yourself.

------------------------------------------------------------------------
e59b6a49891c | Ioan Chera | 2018-04-24 19:58:56 +0300

Updated debug settings for Xcode project

------------------------------------------------------------------------
a83bb431b7c8 | Andrew Apted | 2018-06-28 00:25:25 +1000

Checks : find and fix non-animating switch textures.

These are linedefs where a switch texture won't animate
because there is another switch texture in an unseed part
(e.g. in the upper of a 1S wall) and the DOOM engine finds
and changes that texture (and not the visible one).

------------------------------------------------------------------------
f9d36bb29140 | Andrew Apted | 2018-06-27 23:23:49 +1000

Checks : small fix for transparent-texture-on-solid-wall fixer.

Previous we blindly used the default wall texture, assuming
it was never transparent.  This commit checks it, and if so
falls back to something reasonable.

------------------------------------------------------------------------
14f700f02326 | Andrew Apted | 2018-06-27 22:48:42 +1000

Makefiles : added --std=c++03 compiler flag.

This specifies that the C++ standard of the code is the
original C++ plus the amendments from 2003.  I'm not sure
this flag is truly needed, but it does serve as a reminder
that the code may not live up to modern standards.

------------------------------------------------------------------------
a02df53871ae | Andrew Apted | 2018-06-27 19:12:00 +1000

misc : checked in my FLTK 1.3 patch for nicer menu dividers.

------------------------------------------------------------------------
cd030fa98211 | Andrew Apted | 2018-06-24 14:10:29 +1000

fixed version in Win32 RC file.

------------------------------------------------------------------------
15e463f06566 | Andrew Apted | 2018-06-23 23:21:34 +1000

CHANGELOG : re-organized and made pretty.

------------------------------------------------------------------------
bac2d27a9f6d | Andrew Apted | 2018-06-23 22:54:29 +1000

handle text files containing a Unicode BOM (byte-order mark).

The Unicode BOM is common under Windows, but rare under Linux
or MacOSX.  Previously the definition file parser (etc) would
fatal error if a BOM was present.  Now it is simply ignored.

------------------------------------------------------------------------
5c4cacc4860d | Andrew Apted | 2018-06-23 22:40:31 +1000

EditLump : wrote new file reading code (for "Insert" command).

------------------------------------------------------------------------
543c31b0032b | Andrew Apted | 2018-06-23 21:32:00 +1000

added M_ReadTextLine() function, automatically strips CR/LF.

------------------------------------------------------------------------
5f69cc73b3ee | Andrew Apted | 2018-06-23 21:02:20 +1000

EditLump : wrote new file saving code, add a BOM under Windows.

The BOM is only added if the document contains Unicode (UTF-8).
Linux and MacOSX never need a BOM, since UTF-8 is the norm.

------------------------------------------------------------------------
917a6984cf4d | Andrew Apted | 2018-06-23 18:46:00 +1000

Preferences : added checkbox for "require_click_to_focus".

------------------------------------------------------------------------
bdd65ffda1c6 | Andrew Apted | 2018-06-23 18:38:03 +1000

new config variable "require_click_to_focus".

Default is false (off).  When true, the canvas never steals
the focus when the mouse pointer passes over it.

------------------------------------------------------------------------
e8db16fb657c | Andrew Apted | 2018-06-23 17:22:47 +1000

Open Map dialog : show buttons for ALL maps via scrollable area.

------------------------------------------------------------------------
c4bf26257480 | Andrew Apted | 2018-06-23 17:08:20 +1000

UI_Scroll : support scrollbar on either side (left or right).

------------------------------------------------------------------------
b073d803cddf | Andrew Apted | 2018-06-23 15:29:42 +1000

Insert_Vertex : final refactor, fixing the "zero-length line" error.

------------------------------------------------------------------------
8fc86f8b864b | Andrew Apted | 2018-06-23 14:47:30 +1000

turn off more debugging noise (dangling vertices).

------------------------------------------------------------------------
24e2ae32628f | Andrew Apted | 2018-06-23 01:18:56 +1000

Checks / Lines : fixed alignment of buttons.

------------------------------------------------------------------------
09a1013c20c6 | Andrew Apted | 2018-06-23 01:02:49 +1000

Insert_Vertex : yet more refactoring.

The solution to the "Bug detected ..." fatal error is getting
closer.  Should be able to fix it tomorrow.

This commit also turns off some debugging noise on stderr.

------------------------------------------------------------------------
7c0d2b3a7c3a | Andrew Apted | 2018-06-23 00:31:00 +1000

Insert_Vertex : more refactoring (logic should be unchanged).

------------------------------------------------------------------------
1f0e16d26088 | Andrew Apted | 2018-06-22 23:37:40 +1000

refactored the Insert_Vertex() code, no changes in the logic.

------------------------------------------------------------------------
73b3c5b45f44 | Andrew Apted | 2018-06-22 21:57:22 +1000

TODO update.

------------------------------------------------------------------------
0a54dbdb7015 | Andrew Apted | 2018-06-22 21:56:32 +1000

Checks : fixed merging multiple groups of overlapping vertices.

------------------------------------------------------------------------
ea60f52b6fa5 | Andrew Apted | 2018-06-22 20:44:31 +1000

added VIM syntax file for editing definition (.ugh) files.

------------------------------------------------------------------------
5c922ee5c16f | Andrew Apted | 2018-06-22 18:54:27 +1000

tidy up misc/ -- removed obsolete crud about the "up" language.

------------------------------------------------------------------------
bc725f701edb | Andrew Apted | 2018-06-22 18:46:15 +1000

Find/Replace : fixed to handle generalized sectors.

------------------------------------------------------------------------
32d2531a029d | Andrew Apted | 2018-06-22 18:22:13 +1000

TODO update.

------------------------------------------------------------------------
f3be703d26fd | Andrew Apted | 2018-06-22 18:19:33 +1000

PORTS / ZDoom : support the sector bit-flags in Hexen maps.

These flags are the same as the BOOM generalized sector flags,
but they are shifted up 3 bits to accommodate more real types.

This commit also renames the feature keyword --> "gen_sectors".

------------------------------------------------------------------------
3b1520f67405 | Andrew Apted | 2018-06-22 16:37:03 +1000

Port defs : support new "sector_flags" feature keyword.

Previously the "gen_types" feature enabled both generalized
line types and sector type bitflags.  They are separate now.

------------------------------------------------------------------------
c21fef8b481f | Andrew Apted | 2018-06-22 16:12:17 +1000

PORTS / ZDoom : added missing DOOM sector types (15,18-24).

------------------------------------------------------------------------
8add11be3216 | Andrew Apted | 2018-06-22 14:56:45 +1000

Version bump to 1.23-WIP

------------------------------------------------------------------------
7b56119f35bb | Andrew Apted | 2018-06-22 14:52:01 +1000

CHANGELOG update.

------------------------------------------------------------------------
9cd48cc24cd9 | Andrew Apted | 2018-06-22 14:45:36 +1000

Port defs : indent stuff in an if..endif block.

------------------------------------------------------------------------
94e685c7f4a9 | Andrew Apted | 2018-06-22 14:42:56 +1000

Game defs : prefer the "linegroup" command over "spec_group".

(They are now synonymous).

------------------------------------------------------------------------
65f6ef4135fd | Andrew Apted | 2018-06-22 14:34:44 +1000

Game def parser : support new "clear" command.

This command takes one or more keywords, such as "lines" or
"sectors", and clears the corresponding set of types.

Use this keyword in the ZDoom port definitions to clear
out the DOOM line and sector specials when the map format
is HEXEN, to better support "Doom in Hexen Format" maps.

------------------------------------------------------------------------
d856b57a3d26 | Andrew Apted | 2018-06-21 23:58:51 +1000

Checks : for tag 666 checking, support Heretic in a better way.

Namely by using a valid of "2" for the tag_666 feature.
This is (slightly) better than comparing the game name with
the string "heretic".

------------------------------------------------------------------------
d0d46a39f3d4 | Andrew Apted | 2018-06-21 23:54:05 +1000

CHANGELOG updated.

------------------------------------------------------------------------
052d2b7b2e78 | Andrew Apted | 2018-06-21 23:48:22 +1000

warn user when port is not compatible with the current game.

The dialog provides two options, one to reset the port to vanilla,
and another to keep the current (invalid) port.

This commit also tweaks other code related to handling the port,
e.g. produce a fatal error in DeterminePort() for unknown ports
specified on the command-line.  Plus factored out some of the
Main_LoadResources() code to separate functions.  Tweaked some
error messages too.

------------------------------------------------------------------------
746a6b35a376 | Andrew Apted | 2018-06-21 22:21:59 +1000

code tidying : commented some of the IWAD handling logic.

------------------------------------------------------------------------
74c58324ea3f | Andrew Apted | 2018-06-21 21:25:27 +1000

when no explicit port is given, check user's default makes sense.

i.e. check that the default port is compatible with the IWAD.
If not usable, then revert to "vanilla".

------------------------------------------------------------------------
9272e7c1ab57 | Andrew Apted | 2018-06-21 21:08:17 +1000

minor rename : DetermineGame --> GameNameFromIWAD.

------------------------------------------------------------------------
5ced3d495972 | Andrew Apted | 2018-06-21 20:51:18 +1000

Game defs : split off Hexen sectors --> "common/hexen_sectors.ugh"

------------------------------------------------------------------------
bae832b30acd | Andrew Apted | 2018-06-21 20:47:27 +1000

Game defs : renamed "hexen_specials.ugh" --> "hexen_lines.ugh"

------------------------------------------------------------------------
acf329526377 | Andrew Apted | 2018-06-21 20:43:55 +1000

Game defs : split "doom_specials.ugh" into two files.

One file for line specials, other file for sector types.

------------------------------------------------------------------------
a2d6004d6b79 | Andrew Apted | 2018-06-21 20:39:48 +1000

Game defs : renamed "doom_specials.ugh" --> "doom_lines.ugh"

------------------------------------------------------------------------
b2c5afb122d5 | Andrew Apted | 2018-06-20 14:46:22 +1000

GAMES / Hexen : removed sector type #9 (it is basically inert).

------------------------------------------------------------------------
34d2d422a1c6 | Andrew Apted | 2018-06-20 14:36:33 +1000

TODO : even more fun stuff to hack on....

------------------------------------------------------------------------
42163a47e50e | Andrew Apted | 2018-06-18 15:05:09 +1000

code tidying : removed some commented-out crud.

------------------------------------------------------------------------
a381064e1fdb | Andrew Apted | 2018-06-18 15:01:38 +1000

Makefiles : added the -fwrapv compiler flag.

This ensures that integer addition overflows as expected, i.e.
the value wraps around.

------------------------------------------------------------------------
328628897af5 | Andrew Apted | 2018-06-18 14:45:03 +1000

A preference setting for raw sidedef manipulation buttons.

i.e. for the existing "sidedef_add_del_buttons" config var.

This closes ticket #24.

------------------------------------------------------------------------
9dd19874605e | Andrew Apted | 2018-06-18 00:08:56 +1000

TODO update.

------------------------------------------------------------------------
92f4eeba7cbe | Andrew Apted | 2018-06-18 00:07:11 +1000

Strife : updated Thing panel to support the new thing flags.

This closes ticket #20 (for real this time).

------------------------------------------------------------------------
693cbbafcd25 | Andrew Apted | 2018-06-17 23:29:24 +1000

Strife : define the new thing options (such as MTF_Shadow).

------------------------------------------------------------------------
800bfdaf576f | Andrew Apted | 2018-06-17 23:09:48 +1000

Strife : support both translucency flags in the LineDef panel.

------------------------------------------------------------------------
1e9ee6e55da5 | Andrew Apted | 2018-06-17 22:46:05 +1000

Strife : support the new linedef flags in LineDef panel.

The flags are: JumpOver, BlockFloaters, Translucent1.

The only new flag not supported is Translucent2, because
there is not enough space in the LineDef panel.

This closes ticket #20.

------------------------------------------------------------------------
fb548b78a015 | Andrew Apted | 2018-06-17 21:53:52 +1000

Strife : define the new linedef flags (like MLF_Strife_JumpOver).

------------------------------------------------------------------------
17dd820d009b | Andrew Apted | 2018-06-17 20:58:10 +1000

TODO : small update.

------------------------------------------------------------------------
bcd5506a3268 | Andrew Apted | 2018-06-17 20:52:57 +1000

CHANGELOG update (and reformat).

------------------------------------------------------------------------
f20f24da9cfb | Andrew Apted | 2018-06-17 20:51:47 +1000

Hexen : show every arg value when special is not 0.

Arg values are also dimmed when the usage is unknown.

------------------------------------------------------------------------
83765bbb0f89 | Andrew Apted | 2018-06-17 20:17:50 +1000

TODO : minor changes (remove trailing periods).

------------------------------------------------------------------------
5fff9c7952dc | Andrew Apted | 2018-06-17 14:15:16 +1000

3D View : removed Sort_Bubble() -- it did not speed things up.

------------------------------------------------------------------------
61f3309c85de | Andrew Apted | 2018-06-17 13:44:45 +1000

3D View : restored the recursion minimization in Sort_Range().

------------------------------------------------------------------------
c5f48dd65c30 | Andrew Apted | 2018-06-17 13:31:51 +1000

3D View : removed Sort_ChoosePivot() code.

Choosing the pivot in a simple way (just the middle element)
has shown to be adequate, and in some cases faster than the
3-way median logic which Sort_ChoosePivot() uses.

------------------------------------------------------------------------
8f24973a8b07 | Andrew Apted | 2018-06-17 13:18:01 +1000

3D View : improved the IsCloser() code and its comments.

In particular, we always test if two walls share a vertex
(and perform the more complicated closer test).  Also added
logic to prevent two things at same location from flickering.

------------------------------------------------------------------------
270cb9a0d12b | Andrew Apted | 2018-06-16 22:44:07 +1000

3D View : worked on rewriting the wall sorting code.

The previous code had some problems, especially when the wall
list contained many DrawWalls at the same depth, i.e. sprites.

This commit is a preliminary fix to the QuickSort algorithm,
in particular the case when everything was >= pivot, the old
code did not ensure the pivot was moved to the beginning.

------------------------------------------------------------------------
ed95a485bd97 | Andrew Apted | 2018-06-15 19:05:23 +1000

3D View : fixed closed sectors having a see-through gap.

------------------------------------------------------------------------
580569767cfb | Andrew Apted | 2018-06-15 15:28:12 +1000

Checks : detect when tag 666 or 667 are used on the wrong map.

This closes ticket #12.

------------------------------------------------------------------------
6b692a486984 | Andrew Apted | 2018-06-15 14:41:53 +1000

Checks / Tags : ignore 666 and 667 for unmatched sector tags.

They normally never have a linedef, since those sectors are
activated by the engine on the death of a boss monster.

Also ignore 666/667 for the lowest/highest tag display.

------------------------------------------------------------------------
c5038af61710 | Andrew Apted | 2018-06-15 14:28:05 +1000

Game defs : enable "tag_666" feature for DOOM and Heretic.

------------------------------------------------------------------------
99355dea395c | Andrew Apted | 2018-06-15 00:21:23 +1000

CHANGELOG update.

------------------------------------------------------------------------
9ccfad0b7547 | Andrew Apted | 2018-06-15 00:04:57 +1000

Checks : detect unspawnable things where all Hexen classes are unset.

This finishes the feature, closing ticket #23.

------------------------------------------------------------------------
5b5a0ce37866 | Andrew Apted | 2018-06-15 00:00:28 +1000

Checks : for unspawnable things, always ignore the CAMERA_PEST.

------------------------------------------------------------------------
afa3e0c670dd | Andrew Apted | 2018-06-14 23:55:18 +1000

Checks : detect when a thing in unspawnable due to game modes.

i.e. when the SP, COOP and DM flags are all clear.

This does not apply to Vanilla DOOM, only to Boom compatible
source ports and Hexen format maps.

------------------------------------------------------------------------
a47eacbf7813 | Andrew Apted | 2018-06-14 23:13:58 +1000

Checks : skip things which the game engine always spawns.

For some things, e.g. player starts, the game engine never
checks the skill flags (etc).  Hence these can be safely
skipped by the "unspawnable thing" detector.

------------------------------------------------------------------------
e52e47513bcf | Andrew Apted | 2018-06-14 23:01:11 +1000

Checks : worked on detecting "unspawnable" things.

i.e. things which will never spawn because the skill bits
(easy, medium, hard) are all clear.

This commit includes ability to "Show" these things, and
also "Fix" them (which sets all three skill bits).

------------------------------------------------------------------------
512c21c3c835 | Andrew Apted | 2018-06-14 15:46:01 +1000

BSP : compute 'angle' and 'dist' of vanilla segs more accurately.

------------------------------------------------------------------------
b4e02e9ad1f7 | Andrew Apted | 2018-06-13 22:57:23 +1000

TODO : reorganized items based on likelihood of getting done.

The new section headers are "In Progress", "Most Likely",
"Slightly Possible" and "Rejected Ideas".

Also moved a couple ideas to the rejection pile, and simply
deleted a couple of the wackiest ideas.

------------------------------------------------------------------------
9098d2b55114 | Andrew Apted | 2018-06-13 22:25:22 +1000

TODO : moved several items to the "NOT-TODO" section.

------------------------------------------------------------------------
b40e69c17028 | Andrew Apted | 2018-06-13 19:05:51 +1000

EditLump : treat "SCRIPTS" as a invalid lump (prevent editing).

Normally "SCRIPTS" is a level lump, appearing directly after
the "BEHAVIOR" lump, and is completely optional.  There are some
wad files which contain a global "SCRIPTS" lump (not attached to
any particular level).

Trying to support such a duality leads to problems, especially
when the user creates a global "SCRIPTS" lump, but it ends up
directly after a level inside the wad, and hence suddenly looks
like a level lump (not global anymore).  So the user may find that
their edited lump has "disappeared" when next trying to edit it,
which is totally unacceptable.

Investigations show that source ports (esp. ZDoom) never read a
global "SCRIPTS" lump, it is just a way for modders to bundle
the source of their ACS scripts (as a courtesy).  Hence I think
it is better to err on the side of safety, and only allow the
creation/editing of level-local "SCRIPTS" lumps.

------------------------------------------------------------------------
62ee6fc89ace | Andrew Apted | 2018-06-13 18:27:13 +1000

TODO updated (a wish just came true).

------------------------------------------------------------------------
731fe3f30662 | Andrew Apted | 2018-06-13 18:23:00 +1000

CHANGELOG : noted the new text lump editor.

------------------------------------------------------------------------
8671caa462ee | Andrew Apted | 2018-06-13 18:19:16 +1000

Merge branch 'text-edit'

------------------------------------------------------------------------
347a63834105 | Andrew Apted | 2018-06-13 16:35:10 +1000

EditLump : improved code to set the window title.

Also fixed a bug or two.

------------------------------------------------------------------------
b40f52ee6775 | Andrew Apted | 2018-06-13 15:43:27 +1000

EditLump : added the two flags to "EditLump" command entry.

The two flags are: "/header" and "/scripts".

------------------------------------------------------------------------
79f2cd470760 | Andrew Apted | 2018-06-13 15:41:26 +1000

EditLump : prevent using "/scripts" option on a non-Hexen map.

------------------------------------------------------------------------
408c837c2368 | Andrew Apted | 2018-06-13 15:31:18 +1000

EditLump : added EDLUMP_XXX constants for the two special lumps.

Those two lumps are the map header of current level, and "SCRIPTS"
lump part of the current level.  Main reason for this is that some
wads contain a global "SCRIPTS" lump, so we cannot use that name
to represent the per-level lump.

------------------------------------------------------------------------
3439417107ac | Andrew Apted | 2018-06-13 15:13:12 +1000

EditLump : implemented loading and saving from/to a memory buffer.

------------------------------------------------------------------------
6d65b435ee39 | Andrew Apted | 2018-06-12 23:12:37 +1000

EditLump : implemented callbacks for the short-cut buttons.

------------------------------------------------------------------------
f5631b40a558 | Andrew Apted | 2018-06-12 22:44:06 +1000

EditLump : added short-cut buttons to the UI -- currently inert.

------------------------------------------------------------------------
14beadc17658 | Andrew Apted | 2018-06-12 00:35:34 +1000

EditLump : sorted out main logic for map header and "SCRIPTS" lumps.

------------------------------------------------------------------------
070f81c8ccee | Andrew Apted | 2018-06-12 00:01:07 +1000

EditLump : collected a group of common text lumps.

------------------------------------------------------------------------
9cc0d69a2e2d | Andrew Apted | 2018-06-11 16:15:28 +1000

EditLump : verify lump name as it is typed, and fixed a bug.

------------------------------------------------------------------------
fcbdfb20b0f8 | Andrew Apted | 2018-06-11 15:45:58 +1000

EditLump : reject more lumps in ValidLumpToEdit().

------------------------------------------------------------------------
b6d4875b7fc2 | Andrew Apted | 2018-06-11 01:04:43 +1000

EditLump : fleshed out ValidLumpToEdit() code.

Includes a invalid_text_lump[], which lists numerous common lumps
which are known to use a binary format (and hence cannot be edited
as text).

------------------------------------------------------------------------
5a5237afa1bc | Andrew Apted | 2018-06-11 00:46:56 +1000

EditLump : "OK" and "Cancel" buttons for UI_ChooseTextLump dialog.

------------------------------------------------------------------------
516f137adeb1 | Andrew Apted | 2018-06-11 00:30:58 +1000

EditLump : began work on a UI_ChooseTextLump() dialog....

------------------------------------------------------------------------
8ef3519c225a | Andrew Apted | 2018-06-10 23:39:35 +1000

Hexen : support loading and saving the "SCRIPTS" level lump.

This is an optional (and usually absent) level lump which
contains the texts of ACS scripts.  The plan is to be able to
edit this lump with the Lump Editor being developed.

------------------------------------------------------------------------
dcfe8d1f39a6 | Andrew Apted | 2018-06-10 23:15:27 +1000

TODO : minor update.

I tested the render speed with a simpler Sort_ChoosePivot(),
and the results were mixed: lo-res mode was faster but hi-res
mode was slower.  Hence decided to keep the code as-is.

------------------------------------------------------------------------
ed15d59726cd | Andrew Apted | 2018-06-10 22:49:40 +1000

Checks : never consider #0 to be an unknown line or sector type.

------------------------------------------------------------------------
e67850b96de9 | Andrew Apted | 2018-06-09 22:31:34 +1000

EditLump : disabled unimplemented "Replace" menu command.

------------------------------------------------------------------------
2fe4e962934d | Andrew Apted | 2018-06-09 22:15:33 +1000

EditLump : fixed backwards search getting "stuck" at same spot.

------------------------------------------------------------------------
198338600a64 | Andrew Apted | 2018-06-09 21:56:58 +1000

EditLump : finished the Find commands.

------------------------------------------------------------------------
ea431cf7ef1f | Andrew Apted | 2018-06-09 21:22:05 +1000

EditLump : partial work on the Find/Find-Next/Find-Prev commands...

------------------------------------------------------------------------
d813cc21ddda | Andrew Apted | 2018-06-09 16:04:09 +1000

EditLump : if user tries to save a read-only lump, ask to export it.

Also a successful export clears the MODIFIED status.

------------------------------------------------------------------------
31c4ccec0363 | Andrew Apted | 2018-06-09 15:35:56 +1000

EditLump : confirmation dialog if closing with modifications.

------------------------------------------------------------------------
a7b30a3e4339 | Andrew Apted | 2018-06-09 15:06:51 +1000

EditLump : fixed MODIFIED being shown directly after loading a lump.

------------------------------------------------------------------------
b46d65ab4b9d | Andrew Apted | 2018-06-09 15:01:59 +1000

EditLump : implemented the "Save" menu command.

------------------------------------------------------------------------
2ea0dd60c0e8 | Andrew Apted | 2018-06-09 14:22:47 +1000

EditLump : implemented SaveLump() method.

------------------------------------------------------------------------
5dd1f014cafd | Andrew Apted | 2018-06-09 02:23:07 +1000

EditLump : implemented LoadLump().

------------------------------------------------------------------------
a4e9f83e3016 | Andrew Apted | 2018-06-09 01:54:08 +1000

EditLump : proper dialog when lump is not found or wad is read-only.

------------------------------------------------------------------------
f6f748774343 | Andrew Apted | 2018-06-08 23:13:02 +1000

EditLump : implemented the "Export to File" menu command.

------------------------------------------------------------------------
39ddbe96c571 | Andrew Apted | 2018-06-08 22:39:40 +1000

EditLump : implemented the "Insert File" menu command.

------------------------------------------------------------------------
594deeeaaa37 | Andrew Apted | 2018-06-08 21:44:34 +1000

EditLump : implemented Select-All and Unselect-All menu commands.

------------------------------------------------------------------------
3990914461fe | Andrew Apted | 2018-06-08 21:32:47 +1000

EditLump : implemented the "Go to Top/Bottom" menu commands.

Also tidied up some other menu callbacks.

------------------------------------------------------------------------
0bf89e06e3eb | Andrew Apted | 2018-06-08 20:48:51 +1000

EditLump : fixed selection color to be visible (FL_BLUE).

------------------------------------------------------------------------
3a6c299d901b | Andrew Apted | 2018-06-08 20:45:48 +1000

EditLump : implemented menu callbacks for Undo/Cut/Copy/Paste/Delete.

------------------------------------------------------------------------
ce9d6ea111bc | Andrew Apted | 2018-06-08 19:00:22 +1000

EditLump : limit size of editor window to a sensible minimum.

------------------------------------------------------------------------
d4bc461289f4 | Andrew Apted | 2018-06-08 16:45:44 +1000

Makefile : added "full-install" target which uses the XDG tools.

This target installs the .desktop file and icon image, whereas
the plain "install" target no longer does that.

Also added a "full-uninstall" target.

------------------------------------------------------------------------
9d47f492ac93 | Andrew Apted | 2018-06-08 16:39:33 +1000

Makefile : fixed "clean" target to remove ".o" files (not everything).

This allows OBJ_DIR to be safely set to the src/ directory.

------------------------------------------------------------------------
e37d75b2b389 | Andrew Apted | 2018-06-08 16:27:45 +1000

Makefile : support DESTDIR in install and uninstall targets.

------------------------------------------------------------------------
7e8758b20c4a | Andrew Apted | 2018-06-07 00:45:40 +1000

Makefile : minor commenting.

------------------------------------------------------------------------
6e08fe7464eb | Andrew Apted | 2018-06-07 00:42:49 +1000

PORTS / ZDoom : fixed missing line-special 0 (NOTHING).

This caused spurious "unknown line special" warnings when
invoking the level checking system.

------------------------------------------------------------------------
a3291abf0e2b | Andrew Apted | 2018-06-04 16:10:14 +1000

rely on automatic detection of target OS (especially Windows).

Removed the "OS" variable from the Makefiles, and updated
some code that checked for "UNIX" (mostly in lib_util.cc),
and updated the detection for Windows in main.h.

------------------------------------------------------------------------
cbdb95b5a15c | Andrew Apted | 2018-06-02 19:10:12 +1000

BSP : renamed "minor warnings" --> "minor issues".

------------------------------------------------------------------------
2479cec3fc82 | Andrew Apted | 2018-06-01 01:14:29 +1000

EditLump : added "has_changes" field, use a callback to update it.

------------------------------------------------------------------------
64b2fc0584e1 | Andrew Apted | 2018-06-01 01:02:14 +1000

EditLump : implemented File/Quit in the menus.

------------------------------------------------------------------------
bcce70741e4d | Andrew Apted | 2018-06-01 00:53:20 +1000

EditLump : got showing the line and column number working.

------------------------------------------------------------------------
b1832b487981 | Andrew Apted | 2018-06-01 00:21:32 +1000

TODO : minor whitespace fixes.

------------------------------------------------------------------------
ee578ebaf7f5 | Andrew Apted | 2018-05-31 23:48:08 +1000

BSP : added BUILD_LumpOverflow result code.

------------------------------------------------------------------------
8986107f5b14 | Andrew Apted | 2018-05-31 23:30:56 +1000

BSP : removed unused 'message' field and SetErrorMsg() func.

------------------------------------------------------------------------
506fd12a9e86 | Andrew Apted | 2018-05-31 20:09:31 +1000

BSP : added Failure() func, similar to Warning() but for overflows.

------------------------------------------------------------------------
74272345ce82 | Andrew Apted | 2018-05-31 19:52:12 +1000

BSP : renamed function PrintVerbose() --> PrintDetail()

------------------------------------------------------------------------
c2acac4a3e8c | Andrew Apted | 2018-05-31 01:36:09 +1000

EditLump : wrap Fl_Text_Editor class in order to get line/col info.

------------------------------------------------------------------------
14db0511ba3d | Andrew Apted | 2018-05-31 01:03:11 +1000

EditLump : fully implemented the status bar widget.

------------------------------------------------------------------------
948817be3c34 | Andrew Apted | 2018-05-29 00:34:35 +1000

EditLump : decided contents of each menu (awaiting impl...)

------------------------------------------------------------------------
0cbd823988b1 | Andrew Apted | 2018-05-29 00:06:37 +1000

EditLump : added a minimal menu bar, though nothing works yet.

------------------------------------------------------------------------
dd70154e4c7a | Andrew Apted | 2018-05-28 19:18:50 +1000

BSP : code tidying, removed unused parameter from PutNodes().

------------------------------------------------------------------------
686d2c77728c | Andrew Apted | 2018-05-28 19:10:02 +1000

code correctness : made Editor_State_t not be a typedef.

------------------------------------------------------------------------
ee3b3af939b0 | Andrew Apted | 2018-05-28 19:07:48 +1000

code correctness : removed spurious '&' before arrays in memset().

------------------------------------------------------------------------
714f90c2c970 | Andrew Apted | 2018-05-28 19:06:01 +1000

code correctness : added #include <algorithm> to main.h

That's because we use std::swap() a lot, and that function
requires the <algorithm> header file.

------------------------------------------------------------------------
9fa124561491 | Andrew Apted | 2018-05-28 15:29:16 +1000

fixed returning NULL from a function which returns bool.

------------------------------------------------------------------------
283e4b022565 | Andrew Apted | 2018-05-28 15:27:00 +1000

Basis : removed unused typedefs: VPtr, TPtr, SPtr, LDPtr and SDPtr.

------------------------------------------------------------------------
765f38e3ae02 | Andrew Apted | 2018-05-28 15:21:17 +1000

Makefiles : have a WARNINGS var, enable extra warnings.

------------------------------------------------------------------------
e802ae56bd9b | Andrew Apted | 2018-05-28 15:02:14 +1000

minor rename of ClipboardOp() parameter: what --> op.

------------------------------------------------------------------------
f8f8dab7978d | Andrew Apted | 2018-05-28 14:57:00 +1000

minor rename of a local variable (category --> item_cat).

------------------------------------------------------------------------
daca8454a3e7 | Andrew Apted | 2018-05-28 14:49:13 +1000

wad code : renamed parameter of Backup() method.

------------------------------------------------------------------------
c91eb66acc6a | Andrew Apted | 2018-05-28 14:46:39 +1000

EditLump : tweaked the text color.

------------------------------------------------------------------------
c48c308b9461 | Andrew Apted | 2018-05-28 00:18:07 +1000

EditLump : add status bar, text editing widget to UI_TextEditor.

The status bar is currently empty.  This commit also creates a
menu, which is empty too.

------------------------------------------------------------------------
dc262a1ae03b | Andrew Apted | 2018-05-27 19:06:24 +1000

EditLump : split UI_TextEditor code into its own file.

That's because I expect the UI aspects of the code to grow
to a considerable size, with the addition to several menus,
a status bar, etc...

More non-editor stuff is needed too, like a dialog for
selecting what lump to edit.

------------------------------------------------------------------------
bb8ef9ebfc11 | Andrew Apted | 2018-05-27 18:31:21 +1000

EditLump : set the window title, and check for read-only wads.

------------------------------------------------------------------------
f3b54cd92b0e | Andrew Apted | 2018-05-27 18:26:31 +1000

EditLump : bit more fleshing out, determine Wad_file to use.

------------------------------------------------------------------------
d9da157135b7 | Andrew Apted | 2018-05-27 16:29:14 +1000

EditLump : more fleshing out of the high-level logic.

------------------------------------------------------------------------
031c3382470d | Andrew Apted | 2018-05-27 15:49:13 +1000

EditLump : the beginnings of a UI_TextEditor class....

------------------------------------------------------------------------
451a7895eb5a | Andrew Apted | 2018-05-27 13:57:10 +1000

began work on a command to edit text lumps.

This commit adds two new files: "m_editlump.cc/h", and a "Lump Editor"
entry to the File menu, and adds "EditLump" to the command table.

The implementation (in CMD_EditLump) has barely begun...

------------------------------------------------------------------------
30d0ce15853f | Andrew Apted | 2018-05-27 01:18:40 +1000

Makefiles : added rule to create the OBJ_DIR directory.

------------------------------------------------------------------------
1280695b7336 | Andrew Apted | 2018-05-27 01:02:59 +1000

TODO.txt updated.

------------------------------------------------------------------------
4cd4bf1ecfc2 | Andrew Apted | 2018-05-26 00:27:56 +1000

BSP : removed BUILD_ReadError and BUILD_WriteError -- never used.

------------------------------------------------------------------------
274ba59ed21f | Andrew Apted | 2018-05-26 00:22:57 +1000

BSP : better error messages when Seek() fails.

------------------------------------------------------------------------
61cb22e8fcac | Andrew Apted | 2018-05-25 23:44:56 +1000

BSP : code tidying, use the term "overflow" instead of "hard failure".

------------------------------------------------------------------------
2614eb09c626 | Andrew Apted | 2018-05-25 15:50:01 +1000

BSP : tweaked the message about forcing XNOD format.

------------------------------------------------------------------------
351a16fe07db | Andrew Apted | 2018-05-25 14:31:07 +1000

lib_util : improved StringTidy() to not use a static buffer.

------------------------------------------------------------------------
c41fbafc1c47 | Andrew Apted | 2018-05-25 14:29:33 +1000

fixed typo in a node building message ("filed" --> "failed").

------------------------------------------------------------------------
ae6efd559fd7 | Andrew Apted | 2018-05-25 14:27:41 +1000

wad code : fixed a printf with wrong arguments.

------------------------------------------------------------------------
6bd3cdd51826 | Andrew Apted | 2018-05-16 23:43:13 +1000

conversion scripts : add "next page" links to each page.

------------------------------------------------------------------------
dfa5b5d28cdd | Andrew Apted | 2018-05-16 23:10:40 +1000

conversion scripts : add a link back to the index (TOC) on each page.

------------------------------------------------------------------------
785ab5241e36 | Andrew Apted | 2018-05-15 16:21:49 +1000

conversion scripts : better handling of code blocks.

------------------------------------------------------------------------
98791cab97a6 | Andrew Apted | 2018-05-08 21:38:07 +1000

handle a very rare assertion failure in m_strings.cc more gracefully.

Note: I would normally look for the root cause, but internalised
strings are used a lot throughout the code, so it is impossible to
know where the real problem is unless you can trigger the issue
while using a debugger.  Hence added a workaround here for the
sake of robustness.

------------------------------------------------------------------------
40b244d85807 | Andrew Apted | 2018-05-08 20:28:59 +1000

fix for a rare assertion failure in UI_LineDef::SolidMask().

------------------------------------------------------------------------
1597b376b98e | Andrew Apted | 2018-05-08 00:41:55 +1000

fixed inserting things in Hexen getting no SP/COOP/DM/class flags.

------------------------------------------------------------------------
0a3b6483b923 | Andrew Apted | 2018-05-08 00:18:56 +1000

Updated some copyright years (e.g. About box) for 2018.

------------------------------------------------------------------------
2ac07bfae448 | Andrew Apted | 2018-05-08 00:07:19 +1000

conversion scripts : improved "note" and "warning" blocks.

------------------------------------------------------------------------
5c5ad8d47b97 | Andrew Apted | 2018-05-07 23:45:39 +1000

CHANGELOG : another two fixes.

------------------------------------------------------------------------
b127974e4729 | Andrew Apted | 2018-05-07 23:34:31 +1000

TODO.txt : merged the high/low priority sections (remove that distinction).

------------------------------------------------------------------------
bf22dbd2f3f7 | Andrew Apted | 2018-05-07 16:58:55 +1000

conversion scripts : link :download: to the SF project files/ dir.

------------------------------------------------------------------------
1f2f1d31df3e | Andrew Apted | 2018-05-07 15:17:45 +1000

AUTHORS.txt : added Wesley Werner as a contributor.

------------------------------------------------------------------------
0f7f503e725a | Andrew Apted | 2018-05-07 15:06:11 +1000

Merge branch 'master' of ssh://git.code.sf.net/p/eureka-editor/git

------------------------------------------------------------------------
a28cb63abd90 | Andrew Apted | 2018-05-05 23:42:50 +1000

conversion scripts : fixed wrong sub-list syntax (in Index).

------------------------------------------------------------------------
a755cccadd0f | Andrew Apted | 2018-05-05 23:31:01 +1000

conversion scripts : added #notifybox and #warningbox CSS.

------------------------------------------------------------------------
3ecd689f507e | Andrew Apted | 2018-05-05 22:35:19 +1000

conversion scripts : don't clobber our hand-edited User.Index

------------------------------------------------------------------------
dbf4feac7a6c | Andrew Apted | 2018-05-05 22:30:18 +1000

conversion scripts : workaround for a pandoc issue with `\``

------------------------------------------------------------------------
66e85e5670c2 | Andrew Apted | 2018-05-05 19:04:40 +1000

conversion scripts : fixed order of pages (for the Index).

------------------------------------------------------------------------
2975ecd6ede3 | Andrew Apted | 2018-05-05 18:41:14 +1000

conversion scripts : generate links for the Index page.

------------------------------------------------------------------------
baba03eb19c3 | Andrew Apted | 2018-05-05 17:25:03 +1000

conversion scripts : generate raw pmWiki page files.

------------------------------------------------------------------------
2fa5cec5e954 | Andrew Apted | 2018-05-05 16:18:01 +1000

conversion scripts : put a copy of image files into pm/user/

------------------------------------------------------------------------
e379f79d047b | Andrew Apted | 2018-05-05 15:51:27 +1000

conversion scripts : put a copy of :download: files into pm/user/

------------------------------------------------------------------------
cdfab4d638fd | Andrew Apted | 2018-05-05 15:32:13 +1000

conversion scripts : handle the :download: elements.

------------------------------------------------------------------------
c4e4022c5f8a | Andrew Apted | 2018-05-05 15:23:37 +1000

conversion scripts : store output files in a "pm" directory.

------------------------------------------------------------------------
d83a1b9930d2 | Andrew Apted | 2018-05-05 15:22:54 +1000

conversion scripts : handle the :kbd: elements.

------------------------------------------------------------------------
25c484bd3290 | Andrew Apted | 2018-05-04 22:28:20 +1000

conversion scripts : support links and images, removed dead code.

------------------------------------------------------------------------
e82cfdb8192d | Andrew Apted | 2018-05-04 21:05:06 +1000

conversion scripts : more work on them....

------------------------------------------------------------------------
3986094e3020 | Andrew Apted | 2018-05-04 18:01:32 +1000

conversion scripts : implemented Header and HorizontalRule.

------------------------------------------------------------------------
ac252e9092d7 | Andrew Apted | 2018-05-04 17:53:22 +1000

preliminary work on conversion scripts for the user manual.

------------------------------------------------------------------------
e6d67765e121 | Andrew Apted | 2017-12-06 23:48:39 +1100

fixed "Removed unused vertices" message to show the correct number.

------------------------------------------------------------------------
219d13379ec3 | Andrew Apted | 2017-12-06 23:48:01 +1100

fixed warning messages when linedefs contain an invalid vertex.

------------------------------------------------------------------------
4faea9a19798 | Ioan Chera | 2018-04-24 19:53:05 +0300

Updated Xcode project

------------------------------------------------------------------------
58bc948525c4 | Andrew Apted | 2017-09-02 14:12:09 +1000

Merge branch 'master' of ssh://git.code.sf.net/p/eureka-editor/git

------------------------------------------------------------------------
4b4aca8110be | Andrew Apted | 2017-09-02 14:11:00 +1000

updated CHANGELOG.txt and TODO.txt

------------------------------------------------------------------------
8ce114e9e7b5 | Ioan Chera | 2017-08-30 22:06:56 +0300

Eternity config: moved the slope specials from "stairs" to "others"

It made no sense to put them in stairs.

------------------------------------------------------------------------
b02133b9ed01 | Ioan Chera | 2017-08-30 21:38:17 +0300

Fixed a memory deletion bug in Img_c

------------------------------------------------------------------------
d7ea96cbd36b | Ioan Chera | 2017-08-16 08:30:55 +0300

Silenced some clang 64-bit warnings.

------------------------------------------------------------------------
a0943ebde940 | Ioan Chera | 2017-08-16 08:23:37 +0300

macOS: updated the Eureka version in the plist.

------------------------------------------------------------------------
a7cd233dc235 | Andrew Apted | 2017-08-02 23:07:06 +1000

HERETIC config : fixed sprite of the wall torch (WTRH).

------------------------------------------------------------------------
f8866bfd60d0 | Andrew Apted | 2017-06-07 19:31:25 +1000

minor commenting.

------------------------------------------------------------------------
2c43e820d58f | Andrew Apted | 2017-06-07 19:13:34 +1000

3D View : rewrote code to sort the active list of draw-walls,
using custom sorting code (implementing QuickSort).

It previously used std::sort(), but because our wall-distance
comparison function is "wonky" (e.g. can be non-reversable or
non-transitive), it was causing the local std::sort() function
to access elements outside of the list (leading to a CRASH).

------------------------------------------------------------------------
6ae140bf273d | Andrew Apted | 2017-05-06 12:57:53 +1000

GAME defs : added comment to explain why exit linetypes use
lowercase "s1" and "w1".

------------------------------------------------------------------------
8129c104c7ab | Andrew Apted | 2017-04-04 12:54:53 +1000

TODO.txt : small update.

------------------------------------------------------------------------
dbc69819bb58 | Andrew Apted | 2017-04-04 12:52:56 +1000

Fixed regression with sector merging, it is supposed to keep the
properties of the first selected sector, but this behavior broke
when another issue with sector merging was fixed.

------------------------------------------------------------------------
f6f5256fa384 | Andrew Apted | 2017-04-04 12:48:37 +1000

Version bump after the release.

------------------------------------------------------------------------
cc9b3c7441df | Andrew Apted | 2017-04-04 12:39:42 +1000

CHANGELOG : began a fresh one...

------------------------------------------------------------------------
852053cf43e3 | Andrew Apted | 2017-04-04 12:37:37 +1000

Version 1.21 was released.

Hence moved CHANGELOG --> changelogs/ directory.

------------------------------------------------------------------------
15efcd30ab1f | Ioan Chera | 2017-01-18 22:19:49 +0200

Updated Xcode project for distribution

* Made sure that the static library files are ignored
* Also ignore the userdata subfolders of Xcode
* Updated project to recommended settings
* Updated file references
* Added the two new resource files
* Updated code signing
* Increased deployment target to 10.9 to satisfy all requirements
* Updated the info plist
* Updated the macOS version for the xib
* Removed accidental static libraries

------------------------------------------------------------------------
6ac71b29bb7c | Andrew Apted | 2017-01-12 22:12:17 +1100

docs/History.txt : updated with logs since last release.

------------------------------------------------------------------------
355d3d20049f | Andrew Apted | 2017-01-12 21:50:06 +1100

Removed the file "docs/MiscNotes.txt" -- some parts are obsolete
and the other parts are not very useful anymore.

------------------------------------------------------------------------
1a6938e99914 | Andrew Apted | 2017-01-12 21:27:05 +1100

README.txt : updated the KEYBOARD/MOUSE section for all changes
to the key/button bindings since the previous release.

------------------------------------------------------------------------
787b150c5abd | Andrew Apted | 2017-01-12 21:21:35 +1100

CHANGELOG : tweaks.

------------------------------------------------------------------------
b49cc8efbda1 | Andrew Apted | 2017-01-12 20:48:21 +1100

Operation menu : added "Select same xxx" ops for sector mode.

------------------------------------------------------------------------
dd63ff346638 | Andrew Apted | 2017-01-12 20:02:59 +1100

Test map : fixed execution of the binary on Windows.

------------------------------------------------------------------------
97b15a4d23fe | Andrew Apted | 2017-01-12 16:03:30 +1100

Updated the --help text for 2017.

------------------------------------------------------------------------
33e0c0888b65 | Andrew Apted | 2017-01-12 15:59:41 +1100

About dialog : for Win32, find the logo image in "common/" folder.

------------------------------------------------------------------------
7e3047e44233 | Andrew Apted | 2017-01-12 15:49:55 +1100

3D View : use a darker red for info-bar when stuff is selected.

------------------------------------------------------------------------
a6cd727ee283 | Andrew Apted | 2017-01-12 15:45:00 +1100

About dialog : updated for 2017.

------------------------------------------------------------------------
b50ab15c1bc2 | Andrew Apted | 2017-01-12 15:05:47 +1100

README.txt : update for the release.

------------------------------------------------------------------------
be64c1a08b1e | Andrew Apted | 2017-01-12 15:02:52 +1100

TODO : reorganized various items.

------------------------------------------------------------------------
a2b76534ce73 | Andrew Apted | 2017-01-12 14:43:35 +1100

Removed two obsolete config vars: "scroll_less" and "scroll_more".

------------------------------------------------------------------------
45def5ab752b | Andrew Apted | 2017-01-12 14:42:19 +1100

Makefile : enable optimisation (-O2) for the release.

------------------------------------------------------------------------
15a976db1495 | Andrew Apted | 2017-01-02 00:16:27 +1100

TODO update.

------------------------------------------------------------------------
c9375f28f238 | Andrew Apted | 2017-01-02 00:14:23 +1100

Wiki : slightly bigger font sizes for <h1> and <h2> headings.

------------------------------------------------------------------------
dd54b093090e | Andrew Apted | 2017-01-02 00:13:03 +1100

Operation menu : added "Auto align" and "Clear offsets" commands.

------------------------------------------------------------------------
e8f7cb66e574 | Andrew Apted | 2017-01-02 00:10:50 +1100

Operation Menu : fixed "3D_Align" commands which changed to use
flags like /x and /y instead of plain keywords.

------------------------------------------------------------------------
ec986567b8de | Andrew Apted | 2016-12-31 01:17:51 +1100

CHANGES.txt : large rejigging, added "Editing" section, added a
few entries for recent changes.

------------------------------------------------------------------------
882ad22b3841 | Andrew Apted | 2016-12-30 18:21:52 +1100

Version bump to 1.21 -- ready for release.

------------------------------------------------------------------------
728fd8937b09 | Andrew Apted | 2016-12-24 21:10:06 +1100

TODO update.

------------------------------------------------------------------------
04f954c95fd6 | Andrew Apted | 2016-12-24 21:08:28 +1100

Texture alignment : support /clear + /right flags.

------------------------------------------------------------------------
e8c405f482b3 | Andrew Apted | 2016-12-24 21:03:49 +1100

dead code removal.

------------------------------------------------------------------------
4fd010bf09aa | Andrew Apted | 2016-12-24 16:57:17 +1100

Texture alignment : fixed some bugs in recent changes.

------------------------------------------------------------------------
d4e5893c5938 | Andrew Apted | 2016-12-24 16:47:35 +1100

3D View : fixed not saving/restoring the current gravity setting
in the DAT file (i.e. where UI state is persisted for a map).

------------------------------------------------------------------------
4feee7609c2e | Andrew Apted | 2016-12-24 16:32:54 +1100

Texture alignment : implemented ScoreTextureMatch() logic.

------------------------------------------------------------------------
4734ca99b548 | Andrew Apted | 2016-12-24 15:00:39 +1100

Wiki : added ".kw" style to CSS, for command keywords and flags.

------------------------------------------------------------------------
be39523c7734 | Andrew Apted | 2016-12-24 14:38:47 +1100

Wiki : added ".key" style to the CSS, for drawing keyboard keys.

------------------------------------------------------------------------
fd121f70477b | Andrew Apted | 2016-12-24 12:24:49 +1100

Implemented "LIN_Align" command for auto-aligning offsets of a
group of selected linedefs in the 2D view.  Bound to 'A' key.

------------------------------------------------------------------------
756682e6d903 | Andrew Apted | 2016-12-24 12:02:56 +1100

3D_Align command : have "/x" and "/y" flags instead of a keyword.

------------------------------------------------------------------------
d317842a1f88 | Andrew Apted | 2016-12-24 11:22:59 +1100

Man page : updated the date string.

------------------------------------------------------------------------
c6c3c108230e | Andrew Apted | 2016-12-24 11:21:19 +1100

Texture aligning : moved Line_AlignGroup() code --> e_linedef.cc
(from r_render.cc), passing in the array of surfaces to process.

------------------------------------------------------------------------
48565c96bfc2 | Andrew Apted | 2016-12-23 23:24:48 +1100

Texture aligning : more work on improving the logic, especially
the ScoreAdjoiner() function....

------------------------------------------------------------------------
dfc1b50acce8 | Andrew Apted | 2016-12-23 22:34:28 +1100

Texture aligning : partial work to improve the Line_AlignOffsets()
code, using the "Obj3d_t" class to refer to surfaces instead of
the hacky "soal" stuff (side-on-a-line), and generally improving
all the logic used....

------------------------------------------------------------------------
22c7464784bf | Andrew Apted | 2016-12-23 20:55:38 +1100

TODO update.

------------------------------------------------------------------------
dd739b25cf74 | Andrew Apted | 2016-12-23 20:52:44 +1100

3D View : when aligning multiple selected walls, fixed the logic
for visiting the surfaces in the right order.

------------------------------------------------------------------------
140b354a17d6 | Andrew Apted | 2016-12-23 20:41:35 +1100

Texture aligning : added LINALIGN_Unpeg flag, which must be set to
enable changing the unpegging flags on the linedef.

------------------------------------------------------------------------
dbf6863bf585 | Andrew Apted | 2016-12-23 14:29:24 +1100

Rewrote the "Enlarge" and "Shrink" commands to use the transform_t
stuff, reducing amount of code, and to support fractional values
like "1.5" or "0.3".

------------------------------------------------------------------------
e8c05f0fc585 | Andrew Apted | 2016-12-22 16:36:18 +1100

ACT_Click command : changed the flags to be disablers instead of
enablers, i.e. renamed to "/noselect", "/nodrag", "/nosplit".

------------------------------------------------------------------------
061cc267b8f9 | Andrew Apted | 2016-12-22 16:16:43 +1100

Bindings : bound "D" --> SEC_SelectGroup /ceil_tex

------------------------------------------------------------------------
828251fcfe44 | Andrew Apted | 2016-12-22 16:11:57 +1100

Bindings : added "C" for the reverse CopyProperties command.

------------------------------------------------------------------------
8f0df1b32b01 | Andrew Apted | 2016-12-22 15:56:49 +1100

LIN_SelectPath and SEC_SelectGroup commands : made additive mode
be the default, replacing "/add" flag with a "/fresh" flag.

------------------------------------------------------------------------
31020115e81a | Andrew Apted | 2016-12-22 15:47:05 +1100

3D_Set command : removed "gamma" keyword, since that is handled
by the ordinary "Set" command now.

------------------------------------------------------------------------
43ca46a4f0bb | Andrew Apted | 2016-12-22 15:38:58 +1100

LIN_Flip command : simplified the flags, have a "/force" command
which will flip a linedef non-safely, and have new "LIN_SwapSides"
command for the functionality of swapping the sidedefs on a line.

------------------------------------------------------------------------
437538312230 | Andrew Apted | 2016-12-22 15:26:42 +1100

3D View : more work on "3D_Align" to visit surfaces in the correct
order, but it is still not right yet.

------------------------------------------------------------------------
1533facdab03 | Andrew Apted | 2016-12-22 15:25:08 +1100

Wiki : tweaked main background color again.

------------------------------------------------------------------------
5ffc2a7aacd2 | Andrew Apted | 2016-12-21 22:10:26 +1100

3D View : partial work to fix the "3D_Align" command to support
multiple objects (in the 3D selection).

------------------------------------------------------------------------
0a1296b56d2e | Andrew Apted | 2016-12-21 18:59:21 +1100

Key system : replaced "Gamma" command with "gamma" keyword to the
existing SET and TOGGLE commands.

------------------------------------------------------------------------
efed458a107d | Andrew Apted | 2016-12-21 18:56:34 +1100

Preferences : fixed silly recently-introduced crash bug in the
edit-key dialog.

------------------------------------------------------------------------
53f09e55ecf9 | Andrew Apted | 2016-12-20 15:39:34 +1100

3D View : fixed ACT_AdjustOfs command to work on selected lines
(i.e. not just the highlighted one).

------------------------------------------------------------------------
a799e9858602 | Andrew Apted | 2016-12-19 21:02:45 +1100

TODO update.

------------------------------------------------------------------------
e1afcbdcce94 | Andrew Apted | 2016-12-19 21:01:49 +1100

Fixed recent bug: dragging a single sector would not move the things
inside it.

------------------------------------------------------------------------
8ae6258b39df | Andrew Apted | 2016-12-19 20:03:58 +1100

BSP : code tidying, have a SortSegs() function.

------------------------------------------------------------------------
c26c3213bc57 | Andrew Apted | 2016-12-19 20:00:51 +1100

BSP : replaced the "normal_dup" rubbish with a RoundOffVertices()
function, done as part of RoundOffBspTree().

This should fix the bug where ZDoom format nodes had a too high
value for the number of original vertices.

------------------------------------------------------------------------
3ba15ef6dbfb | Andrew Apted | 2016-12-19 19:48:19 +1100

BSP : replaced "ref_count" fields with simpler "is_used" value,
and tidied up assigning of boolean values to "char" fields.

------------------------------------------------------------------------
6fc884bd03e8 | Andrew Apted | 2016-12-19 19:38:58 +1100

BSP : tweaked logic in SaveLevel(), ensure segs array is always
sorted after calling NormaliseBspTree() or RoundOffBspTree().

------------------------------------------------------------------------
3be1d2347da0 | Andrew Apted | 2016-12-19 19:27:07 +1100

BSP : have an "is_new" field of vertex_t, instead of IS_GL_VERTEX
constant, and renamed "num_gl_vert" --> "num_new_vert".

------------------------------------------------------------------------
d8f36f5fca38 | Andrew Apted | 2016-12-19 18:50:25 +1100

BSP : removed obsolete "is_dummy" field of subsector struct.

------------------------------------------------------------------------
39d9282b1f56 | Andrew Apted | 2016-12-19 16:52:40 +1100

CHANGELOG update.

------------------------------------------------------------------------
760806a5b461 | Andrew Apted | 2016-12-19 16:45:55 +1100

Fixed recent bug: wrong highlight after zooming.

------------------------------------------------------------------------
c0a72703c63a | Andrew Apted | 2016-12-19 16:24:00 +1100

Sound propagation : better linedef colors, show the sound-blocking
lines as magenta, and all others as either white or gray.

------------------------------------------------------------------------
2db19f6631e8 | Andrew Apted | 2016-12-19 15:08:26 +1100

Sound propagation : implemented a new sector rendering mode for it.

------------------------------------------------------------------------
509a6e9a3fdc | Andrew Apted | 2016-12-19 15:02:32 +1100

SoundPropagation : fixed a silly bug.

------------------------------------------------------------------------
0be237d24af5 | Andrew Apted | 2016-12-19 14:18:28 +1100

Implemented SoundPropagation() function, which determines which
sectors can be "heard" from a start sector -- using same logic
as the DOOM engine P_NoiseAlert() function.

------------------------------------------------------------------------
c0ba81cff344 | Andrew Apted | 2016-12-18 22:37:47 +1100

Bindings : bind RMB (MOUSE3) in sectors mode to "Merge" command,
as such an fundamental function deserves a mouse button (and it
was not being used for anything else).

------------------------------------------------------------------------
9976cc9e1e0b | Andrew Apted | 2016-12-18 21:22:05 +1100

TODO update.

------------------------------------------------------------------------
03f8bc90fab3 | Andrew Apted | 2016-12-18 21:20:04 +1100

Copy/Paste : allow using delete on floor textures in Sector and
Default Properties panels to turn them into sky -- even though
this is not very useful, being consistent is important.

------------------------------------------------------------------------
f341483807dd | Andrew Apted | 2016-12-18 21:01:13 +1100

Copy/Paste : using delete on ceiling texture in 3D view turns it
into sky.

------------------------------------------------------------------------
c6b624e0dd44 | Andrew Apted | 2016-12-18 20:18:43 +1100

Copy/Paste : using delete on ceiling texture in the Sector panel
and Default Props panel turns that texture into sky.

------------------------------------------------------------------------
673704d19d62 | Andrew Apted | 2016-12-18 19:55:39 +1100

Key system : workaround for Linux / X-Windows where a change in
modifier keys (SHIFT or CTRL) would not immediately take effect
while a navigation or action was pressed.

------------------------------------------------------------------------
2cb67c50e3fe | Andrew Apted | 2016-12-18 18:45:47 +1100

Copy/Paste : support Delete in 3D mode, set wall textures to "-"
(and shows an error for floor or ceiling textures).

------------------------------------------------------------------------
04ebce73122e | Andrew Apted | 2016-12-18 17:58:29 +1100

Operation menu : added "Copy Texture", "Paste Texture" for 3d mode.

------------------------------------------------------------------------
7f79cbd0e750 | Andrew Apted | 2016-12-18 17:57:03 +1100

3D View : don't forget 3d highlight when using the operation menu.

------------------------------------------------------------------------
dddfec3840c7 | Andrew Apted | 2016-12-18 16:28:08 +1100

CHANGELOG and TODO update.

------------------------------------------------------------------------
12be0004d724 | Andrew Apted | 2016-12-18 16:23:42 +1100

3D View : improved the info bar to show information about the
current highlighted object (the thing/line/sector number and the
texture name or thing description).

Also removed the X/Y coordinates, instead show them in the main
info bar (at the bottom of the main window).

------------------------------------------------------------------------
b963f8288bf3 | Andrew Apted | 2016-12-18 15:06:33 +1100

(part of previous commit)

------------------------------------------------------------------------
3b3cf8572527 | Andrew Apted | 2016-12-18 15:05:21 +1100

Added "panel gamma" config variable.

------------------------------------------------------------------------
0960d6c54e9b | Andrew Apted | 2016-12-18 14:58:25 +1100

UI : draw the textures/flats/sprites in the browser and panels
using a constant gamma, instead of the "usegamma" which is meant
for rendering the 3D view and sectors/sprites on the 2D view.

------------------------------------------------------------------------
c3b13cc15403 | Andrew Apted | 2016-12-18 14:05:24 +1100

Copy/Paste : finally got distribution of clipboard events right.
Namely try the panels FIRST, and if none want it then ALWAYS send
it to the 3D view when it is active.

------------------------------------------------------------------------
1e3a60497857 | Andrew Apted | 2016-12-18 13:12:14 +1100

Copy/Paste : support them for textures in the Default Props panel.

------------------------------------------------------------------------
ef8a65ae9ba7 | Andrew Apted | 2016-12-18 13:07:13 +1100

Copy/Paste : fully fixed 3D view eating clipboard ops even when
nothing is highlighted or selected (see commit 8546694cfb5a).

------------------------------------------------------------------------
2180ffce65f8 | Andrew Apted | 2016-12-17 23:10:30 +1100

CHANGELOG and TODO update.

------------------------------------------------------------------------
b203ecb2a7b7 | Andrew Apted | 2016-12-17 23:07:10 +1100

3D View : fixed the highlight not being cleared when the mouse has
moved outside of the 3D viewport.

------------------------------------------------------------------------
b286c009d808 | Andrew Apted | 2016-12-17 22:52:44 +1100

Copy/Paste : disabled for Defaults Props and Find/Replace panels
(for now anyway, it is under review....)

------------------------------------------------------------------------
8546694cfb5a | Andrew Apted | 2016-12-17 20:49:01 +1100

Copy/Paste : don't eat a clipboard operation in 3D mode when both
the 3d highlight and 3d selection are empty.

------------------------------------------------------------------------
447cff27e763 | Andrew Apted | 2016-12-17 20:48:24 +1100

Copy/Paste : CTRL-C/X/V for textures in the LineDef panel.

------------------------------------------------------------------------
a33e63545da1 | Andrew Apted | 2016-12-17 19:48:07 +1100

Copy/Paste : support CTRL-C/X/V for textures in the Sector panel.

------------------------------------------------------------------------
c8704e1b490a | Andrew Apted | 2016-12-17 16:34:42 +1100

Copy/Paste : moved the 3D clipboard stuff to the global scope,
namely the "r_clipboard" structure, with code in e_main.cc/h.

------------------------------------------------------------------------
b65353e06705 | Andrew Apted | 2016-12-17 15:21:54 +1100

Copy/Paste : added stub ClipboardOp() methods to all the panel
classes which can use it (UI_Sector, UI_DefaultProps, etc...)

------------------------------------------------------------------------
b825bd74eb44 | Andrew Apted | 2016-12-17 15:05:52 +1100

Copy/Paste : added main_win::ClipboardOp() to see if various UI
stuff wants to override the normal cut/copy/paste/delete commands,
and updated the 3D renderer code to use this mechanism.

------------------------------------------------------------------------
b69c116b1a2c | Andrew Apted | 2016-12-17 13:54:24 +1100

Operation menu : look for "operations.cfg" in user's home_dir,
using that when it exists, otherwise load it from install_dir.

------------------------------------------------------------------------
6ad148165ffe | Andrew Apted | 2016-12-17 13:47:12 +1100

3D View : fixed most glitches when drawing highlight/select lines,
caused by gross limitations of line clipping in X windows.

------------------------------------------------------------------------
14a9da935f88 | Andrew Apted | 2016-12-17 13:23:47 +1100

3D View : fixed highlight/select lines not being clipped to the
rendering area.

------------------------------------------------------------------------
0059a9a0a34a | Andrew Apted | 2016-12-17 13:00:58 +1100

3D View : support for using the texture browser to set the texture
or flat on selected walls / floors / ceilings.

------------------------------------------------------------------------
3cfe94c40cf5 | Andrew Apted | 2016-12-17 12:41:33 +1100

Browser : previous commit allows a few methods of the panel classes
(UI_Sector etc) to become private.

------------------------------------------------------------------------
f221ecd172b7 | Andrew Apted | 2016-12-17 12:35:56 +1100

Browser : gave more panel classes a BrowsedItem() method, which
simplifies the code in main_win::BrowsedItem().

------------------------------------------------------------------------
0ff0bdc0ff37 | Andrew Apted | 2016-12-16 23:55:20 +1100

tweak to UI_MainWindow constructor.

------------------------------------------------------------------------
95671f62f474 | Andrew Apted | 2016-12-16 23:20:04 +1100

3D View : code tidying, removed "RenderLine" struct.

------------------------------------------------------------------------
625114e22258 | Andrew Apted | 2016-12-16 23:18:38 +1100

3D View : draw the highlighted/selected objects in a simpler way,
without having to store the line coordinates.

------------------------------------------------------------------------
c68dc0ac13f4 | Andrew Apted | 2016-12-16 23:02:10 +1100

TODO update.

------------------------------------------------------------------------
f054d634dbaa | Andrew Apted | 2016-12-16 22:57:21 +1100

Panels : allow the textures in LineDef panel and flats in Sector
panel to be highlighted (yellow border) when mouse is over them.

Does nothing yet, but will be needed for Copy/Paste support...

------------------------------------------------------------------------
8fb24ebf0c71 | Andrew Apted | 2016-12-16 22:37:47 +1100

3D View : ensure a redraw when the 3d selection is cleared.

------------------------------------------------------------------------
d3e43d96d09d | Andrew Apted | 2016-12-16 21:22:26 +1100

CHANGELOG update (mention the operation menu).

------------------------------------------------------------------------
0f761ea903bb | Andrew Apted | 2016-12-16 21:12:34 +1100

Bindings : require CMD key with RMB to open the operation menu.

Previously plain RMB would open the operation menu *except* in
vertex mode, where plain RMB does line drawing.  But I think
such an inconsistency is going to annoy/confuse users.

------------------------------------------------------------------------
41db86b221e5 | Andrew Apted | 2016-12-16 18:52:24 +1100

Bindings : changed "toggle sector rendering" from '/' --> F8 key.

------------------------------------------------------------------------
1f15f95e7820 | Andrew Apted | 2016-12-16 18:31:09 +1100

3D View : made CTRL-X "Cut" do something useful: set the texture
or flat to the default property.

------------------------------------------------------------------------
889b9dec6c21 | Andrew Apted | 2016-12-16 18:11:46 +1100

3D View : make the info-bar background RED when some objects are
selected.

------------------------------------------------------------------------
5047908e3f25 | Andrew Apted | 2016-12-16 18:08:59 +1100

3D View : code tidying, made GrabClipboard() and StoreClipboard()
be methods of the r_editing_info_t struct.

------------------------------------------------------------------------
4c7e108a8d3d | Andrew Apted | 2016-12-16 17:12:56 +1100

3D View : code clarifying, renamed "r_sel" --> "r_edit" and moved
the highlight and selection stuff into it.

------------------------------------------------------------------------
40ec5cf5a4f0 | Andrew Apted | 2016-12-16 16:51:15 +1100

3D View : implemented a proper "3d clipboard" instead of abusing
the default properties (such as default_wall_tex).

------------------------------------------------------------------------
3036e643a601 | Andrew Apted | 2016-12-16 15:34:55 +1100

3D View : for copy'n'paste, allow using just the current highlight
(i.e. don't REQUIRE a selection).  That is very convenient.

------------------------------------------------------------------------
b28f20ab083c | Andrew Apted | 2016-12-16 15:13:28 +1100

3D View : implemented copy'n'paste for wall textures and sector flats.

------------------------------------------------------------------------
8899786eaf44 | Andrew Apted | 2016-12-16 13:59:23 +1100

Preferences : changed default key binding sort mode to sort on
the key itself (left column) instead of context (middle column).

------------------------------------------------------------------------
6c04b6af7234 | Andrew Apted | 2016-12-16 13:46:25 +1100

minor rename : UI_MainWin --> UI_MainWindow

------------------------------------------------------------------------
1b0f95c5480f | Andrew Apted | 2016-12-15 23:39:00 +1100

TODO update.

------------------------------------------------------------------------
03e8570331ab | Andrew Apted | 2016-12-15 23:19:32 +1100

3D View : implemented logic to grab the texture from the currently
selected surfaces (failing if more than one texture is present).

------------------------------------------------------------------------
1195b12e9081 | Andrew Apted | 2016-12-15 22:46:38 +1100

3D View : when a surface is both selected and highlighted, let the
selection color (RED) be used, giving better feedback to the user.

------------------------------------------------------------------------
2f8915e17d25 | Andrew Apted | 2016-12-15 16:15:27 +1100

3D View : fixed 3D selection to allow uppers and lowers (or floors
and ceilings) at the same time.

------------------------------------------------------------------------
7e217d076ef3 | Andrew Apted | 2016-12-15 16:10:22 +1100

3D View : unselect pics in the panel when selecting in the 3D view
and vice versa, so the user can be sure what will be changing when
picking something in the texture/flat browser.

------------------------------------------------------------------------
b27a83dd5a44 | Andrew Apted | 2016-12-15 16:09:47 +1100

3D View : ability to "select" surfaces is now working :)

------------------------------------------------------------------------
88799a61b54c | Andrew Apted | 2016-12-15 15:52:40 +1100

3D View : support for rendering the 3D selection (red lines).

------------------------------------------------------------------------
a557ab5d9240 | Andrew Apted | 2016-12-15 15:45:26 +1100

3D View : implemented basic (unoptimised) 3D selection handling.

------------------------------------------------------------------------
e0a9d923c893 | Andrew Apted | 2016-12-15 15:25:52 +1100

3D View : refactored the HighlightGeometry() code.

------------------------------------------------------------------------
f5be0bfafc8a | Andrew Apted | 2016-12-15 14:15:42 +1100

3D View : reworked Obj3d_t class to only store an object number
(instead of separate "line", "sector", "thing" fields).

------------------------------------------------------------------------
31d08a10faf4 | Andrew Apted | 2016-12-15 13:35:14 +1100

3D View : renamed "highlight_3D_info_t" --> "Obj3d_t" and moved
its definition to objid.h, and renamed QRP_XXX --> OB3D_XXX.

------------------------------------------------------------------------
034d3142e692 | Andrew Apted | 2016-12-15 13:14:59 +1100

3D View : logic to ensure insertions and deletions of objects will
invalidate the 3D selection.

------------------------------------------------------------------------
69f95a80ef45 | Andrew Apted | 2016-12-15 13:14:12 +1100

(part of previous commit)

------------------------------------------------------------------------
5a11554a909b | Andrew Apted | 2016-12-15 13:11:51 +1100

3D View : also began work on versions of Cut/Copy/Paste commands
which are usable in the 3D mode....

------------------------------------------------------------------------
fbf1cb2b3132 | Andrew Apted | 2016-12-15 13:09:36 +1100

3D View : began work on new "3D_Click" command, which will be used
to select/unselect surfaces in the 3D view....

------------------------------------------------------------------------
77f374ab711e | Andrew Apted | 2016-12-14 22:27:50 +1100

TODO update.

------------------------------------------------------------------------
c7c8180a17a4 | Andrew Apted | 2016-12-14 22:27:27 +1100

minor code commenting.

------------------------------------------------------------------------
da482ca46c52 | Andrew Apted | 2016-12-14 22:17:08 +1100

Sector auto-insert : fixed case of extending off an island inside
a sector, which was being treated as a "new island" and leaving
the interior as void (with broken geometry).

------------------------------------------------------------------------
f0da45f8eb32 | Andrew Apted | 2016-12-14 22:02:44 +1100

Sector auto-insert : look harder to find a nearby default textures
we can use for the new linedefs.  This improves the case when
building a new sector off an existing one (in the void).

------------------------------------------------------------------------
5fcff0db0f66 | Andrew Apted | 2016-12-14 18:41:49 +1100

Version bump, for good progress with various stuff.

------------------------------------------------------------------------
fe764547e30e | Andrew Apted | 2016-12-14 18:35:54 +1100

PORTS / ZDoom : added the zdoom-specific things.  This info was
sourced from the ZDoom wiki "standard editor numbers" page.

------------------------------------------------------------------------
a36b073bceba | Andrew Apted | 2016-12-14 18:12:45 +1100

TODO update.

------------------------------------------------------------------------
357386ee49da | Andrew Apted | 2016-12-14 17:20:50 +1100

FindCrossingPoints : tweaked the 'close_dist' calculation.

------------------------------------------------------------------------
64bb7bd8a27f | Andrew Apted | 2016-12-14 16:46:33 +1100

Fixed new linedef auto-split code to not create overlapping lines.

------------------------------------------------------------------------
ccf0cae85fbd | Andrew Apted | 2016-12-14 16:41:45 +1100

FindCrossingPoints : fixed 'along' values when checking linedefs,
need to store the distance along the WHOLE original line.

------------------------------------------------------------------------
b70fd014f421 | Andrew Apted | 2016-12-14 16:22:57 +1100

TODO : tidying.

------------------------------------------------------------------------
64200fe91242 | Andrew Apted | 2016-12-14 16:20:46 +1100

crossing_point_c : implemented the Sort() method.

------------------------------------------------------------------------
c8704d69e393 | Andrew Apted | 2016-12-14 16:15:25 +1100

crossing_state_c : implemented add_vert() and add_line().

------------------------------------------------------------------------
30881db715ff | Andrew Apted | 2016-12-14 16:10:26 +1100

FindCrossingPoints : bbox test to quickly eliminate linedefs.

------------------------------------------------------------------------
9204fcc5c063 | Andrew Apted | 2016-12-14 15:47:23 +1100

FindCrossingPoints : code tidying.

------------------------------------------------------------------------
e2f04487a512 | Andrew Apted | 2016-12-14 15:41:02 +1100

FindCrossingPoints : ignore linedefs where an end-point is already
within set of vertices in the crossing_state.  Tweaked epsilon
values (use some #defines for them).

------------------------------------------------------------------------
c66d67092bdc | Andrew Apted | 2016-12-14 15:34:07 +1100

Basis : added LineDef::TouchesCoord() method.

------------------------------------------------------------------------
ad071d0aef07 | Andrew Apted | 2016-12-14 14:41:12 +1100

Wiki : made the background a little bit brighter.

------------------------------------------------------------------------
9cf000d00e1d | Andrew Apted | 2016-12-14 14:28:47 +1100

FindCrossingPoints : split algorithm into two phases, finding all
vertices in the first phase, and second phase processes each pair
of adjacent vertices to find crossing linedefs.

------------------------------------------------------------------------
bf8fd9bb72c3 | Andrew Apted | 2016-12-14 14:15:33 +1100

Began work on improved auto-splitting code when inserting new lines,
using new "crossing_state_c" class to encapsulate the cross points.

------------------------------------------------------------------------
cbd45bfd9feb | Andrew Apted | 2016-12-13 23:26:18 +1100

Test map : support for the "-merge" option when building the
command-line arguments.  Although the logic *when* to employ
that option is too simplistic atm.

------------------------------------------------------------------------
2b2ccccfecec | Andrew Apted | 2016-12-13 22:39:22 +1100

TODO update.

------------------------------------------------------------------------
60828d873ae1 | Andrew Apted | 2016-12-13 22:38:44 +1100

PORTS / ZDoom : renamed the fragglescript specials.

------------------------------------------------------------------------
bdc78d935af1 | Andrew Apted | 2016-12-13 22:35:05 +1100

PORTS / Eternity : moved slope linetypes to the "Stairs" category,
consistent with the other ports.

------------------------------------------------------------------------
5ec45ad390fb | Andrew Apted | 2016-12-13 22:31:22 +1100

PORTS / ZDoom : fixed using STAIRS category for some special FX.

------------------------------------------------------------------------
48730038c580 | Andrew Apted | 2016-12-13 22:26:54 +1100

PORTS : added three line categories to doom_groups.ugh: "Scripting",
"Renderer" and "3D Floor", and use them consistently in each port.

------------------------------------------------------------------------
a8aab81787a3 | Andrew Apted | 2016-12-13 22:09:45 +1100

GAMES / Heretic : include "doom_groups", fixing the stairs to use "s"
and removing the unused "Sounds" category.

------------------------------------------------------------------------
6dcd93be2ef9 | Andrew Apted | 2016-12-13 22:04:54 +1100

GAMES / Strife : include "doom_groups" (most were the same).

------------------------------------------------------------------------
2e30d1350ca6 | Andrew Apted | 2016-12-13 21:56:52 +1100

GAMES : separated out groups for DOOM linetypes --> doom_groups.ugh

------------------------------------------------------------------------
b17469ec8147 | Andrew Apted | 2016-12-13 21:49:03 +1100

PORTS : separated out groups for HEXEN specials --> hexen_groups.ugh

------------------------------------------------------------------------
ecc94ac3a5c2 | Andrew Apted | 2016-12-13 21:39:59 +1100

Game def parser : support "spec_group" directive, equivalent to
"linegroup" but only applies to HEXEN format maps.

------------------------------------------------------------------------
7413da0b6303 | Andrew Apted | 2016-12-13 21:17:53 +1100

PORTS / ZDoom : added "ZD:" prefix to the ZDoom-specific doom-format
line types, and changed category of 3D Floors to "y" since "v" is
already being used for the BOOM elevators.

------------------------------------------------------------------------
8154298b96be | Andrew Apted | 2016-12-13 20:59:29 +1100

Preferences : improved look of the tabs, the background of all the
unselected tabs are now drawn darker than normal, so the current
tab stands out.

------------------------------------------------------------------------
0ab33cb990c7 | Andrew Apted | 2016-12-13 20:36:22 +1100

PORTS / ZDoom : added all the extra Doom-format line types.
These were adapted from the SLADE editor (once again).

------------------------------------------------------------------------
6629aff212f1 | Andrew Apted | 2016-12-13 20:14:24 +1100

TODO update.

------------------------------------------------------------------------
6c682f75fbe0 | Andrew Apted | 2016-12-13 18:35:39 +1100

Sector auto-insert : fleshed out logic for determining better
texture to use on fresh linedefs.  But it does not handle the
important case of building a sector off an existing 1S wall...

------------------------------------------------------------------------
2a46c09dcdf0 | Andrew Apted | 2016-12-13 18:31:03 +1100

Operation menu : ensure the popup menus normally stay hidden, which
fixes the bug where line-drawing stopped at an invisible rectangle
(due to mouse "entering" the menu and sending FL_LEAVE to the canvas).

------------------------------------------------------------------------
ac0805a43a93 | Andrew Apted | 2016-12-13 15:38:12 +1100

Sector auto-insert : began work to choose better default textures
for the newly added linedefs....

------------------------------------------------------------------------
e3b60f641242 | Andrew Apted | 2016-12-13 15:08:10 +1100

Basis : optional 'new_tex' parameter for SideDef::SetDefaults().

------------------------------------------------------------------------
f0d4f9370395 | Andrew Apted | 2016-12-13 14:11:44 +1100

Wiki : improved look of the editing Cheat Sheet.

------------------------------------------------------------------------
59f9826e5011 | Andrew Apted | 2016-12-13 13:56:34 +1100

Wiki : tweaked the hyperlink colors ("a" tags).

------------------------------------------------------------------------
c66aacdbf13b | Andrew Apted | 2016-12-13 13:31:34 +1100

Wiki : removed search box from bottom of page.

------------------------------------------------------------------------
e166f9f5a852 | Andrew Apted | 2016-12-13 13:22:10 +1100

Wiki : always disable the automatic page title, and tidied up the
HTML in the template file.

------------------------------------------------------------------------
521260ae8c4c | Andrew Apted | 2016-12-12 19:09:19 +1100

Sector auto-insert : removed the old ClosedLoop_XXX code.

------------------------------------------------------------------------
dcfb04dbb6d8 | Andrew Apted | 2016-12-12 17:04:08 +1100

Sector auto-insert : proper logic to determine model for new sector
(when splitting an existing one, or void space).

------------------------------------------------------------------------
3cb3ddd5c2d0 | Andrew Apted | 2016-12-12 16:55:08 +1100

Sector auto-insert : main logic for the split-sector cases.

------------------------------------------------------------------------
23fcd415666a | Andrew Apted | 2016-12-12 16:39:31 +1100

Sector auto-insert : got logic for creating islands (inside a sector
or out in void space) working again.

------------------------------------------------------------------------
c0c28f3cb640 | Andrew Apted | 2016-12-12 15:43:54 +1100

Sector auto-insert : use new DetermineSector() method and get the
lengths of the line loops.

------------------------------------------------------------------------
08963aa696ff | Andrew Apted | 2016-12-12 15:41:07 +1100

lineloop_c : added DetermineSector() method.

------------------------------------------------------------------------
85f87fc0bc30 | Andrew Apted | 2016-12-12 15:22:16 +1100

Sector auto-insert : more work on new logic, handle any outward
facing lineloop (if there is one).

------------------------------------------------------------------------
fca7db6ef447 | Andrew Apted | 2016-12-12 14:52:06 +1100

Began work on new logic handling the auto-insertion of sectors when
closing linedef loops, as it should not matter exactly where the
user closed the loop.

------------------------------------------------------------------------
0f75792b5f1c | Andrew Apted | 2016-12-11 23:55:12 +1100

CHANGELOG and TODO update.

------------------------------------------------------------------------
8d8d0dab7402 | Andrew Apted | 2016-12-11 23:23:24 +1100

Wiki : increased base font size from 11pt --> 14pt

------------------------------------------------------------------------
814ffe78cb4e | Andrew Apted | 2016-12-11 23:06:56 +1100

Wiki : removed trailing whitespace from the CSS and TMPL files.

------------------------------------------------------------------------
446bcb65d302 | Andrew Apted | 2016-12-11 23:04:15 +1100

Wiki : checked in our pmwiki skin files: wiki/eureka.css + wiki/eureka.tmpl

------------------------------------------------------------------------
e8a711d3ec4b | Andrew Apted | 2016-12-11 21:13:25 +1100

Improved method to find the right line loop when inserting a sector,
handling the case of hitting an island much better: look at linedefs
opposite the ones in the island, and keep looking even when we hit
other islands.

------------------------------------------------------------------------
6b3d2b2b8724 | Andrew Apted | 2016-12-11 18:53:14 +1100

lineloop_c : when finding islands, handle isolated linedefs.

------------------------------------------------------------------------
6b318acfbb58 | Andrew Apted | 2016-12-11 18:25:28 +1100

Fixed recent bug, when inserting a sector and failing to trace the
lineloop then a dud sector was still created.

------------------------------------------------------------------------
e4a81bdf03d2 | Andrew Apted | 2016-12-11 18:09:38 +1100

TraceLineLoop : support tracing along both sides of a linedef, and
tracing around a dangling vertex.

------------------------------------------------------------------------
f029801de4f8 | Andrew Apted | 2016-12-11 17:31:59 +1100

minor rename : "LD_" prefix for AngleBetweenLines().

------------------------------------------------------------------------
cc9a8312828b | Andrew Apted | 2016-12-11 17:11:21 +1100

TraceLineLoop : explicit check for an isolated linedef.

------------------------------------------------------------------------
300e2b5bbbee | Andrew Apted | 2016-12-11 17:08:36 +1100

minor tidying in TraceLineLoop().

------------------------------------------------------------------------
2805645816ba | Andrew Apted | 2016-12-11 17:02:39 +1100

code tidying : moved LD_GetTwoNeighbors() --> e_linedef.cc/h

------------------------------------------------------------------------
cd7a1783f958 | Andrew Apted | 2016-12-11 16:56:41 +1100

tweak to ClosedLoop_Complex, don't check original loop when splitting.

------------------------------------------------------------------------
7bee3cea887a | Andrew Apted | 2016-12-11 16:49:41 +1100

lineloop_c : AssignSector() is now a method of lineloop_c.

------------------------------------------------------------------------
7d2b2027d8ac | Andrew Apted | 2016-12-11 15:30:26 +1100

lineloop_c : renamed FacesSector() method --> IslandSector(), made
it ignore lines which face the void (keep looking for a possible
outer sector), and some tidying up of code using this method.

------------------------------------------------------------------------
ac025a8ac51c | Andrew Apted | 2016-12-11 15:14:01 +1100

minor rename : lineloop_c::AllNew() --> AllBare().

------------------------------------------------------------------------
ed91965d70ff | Andrew Apted | 2016-12-11 14:54:18 +1100

fixed recent bug: cannot highlight vertex #0, linedef #0, etc...

------------------------------------------------------------------------
fb16ac973537 | Andrew Apted | 2016-12-11 14:52:17 +1100

Canvas : in drawing mode, show all the linedefs/vertices that will
be crossed by the current line (as orange blobs).

------------------------------------------------------------------------
401c0db29781 | Andrew Apted | 2016-12-11 13:05:54 +1100

code : tidied up all the GetNearObject() logic, replacing most usage
Close_obj class with simpler code.

------------------------------------------------------------------------
a2becb3a05e7 | Andrew Apted | 2016-12-10 23:46:25 +1100

Fixed overly zealous highlighting of vertices when zoomed in far.

------------------------------------------------------------------------
6be3c314fcfa | Andrew Apted | 2016-12-10 21:41:38 +1100

Operation menu : save the current highlight before popping up the
menu, and restore it before executing the chosen command, since
the pop-up menu window causes the highlight to be cleared.

------------------------------------------------------------------------
3f650e9d3cd5 | Andrew Apted | 2016-12-10 17:39:35 +1100

Menus : the /MENU flag idea was no good, so reverted the previous
commit which added it.

------------------------------------------------------------------------
5400e626d392 | Andrew Apted | 2016-12-09 21:41:31 +1100

TODO update.

------------------------------------------------------------------------
4f4a68f9924f | Andrew Apted | 2016-12-09 21:40:22 +1100

Grid code : ensure that changes to the origin or Scale will update
the current highlight.

------------------------------------------------------------------------
6aa546db7b24 | Andrew Apted | 2016-12-09 21:17:40 +1100

Grid code : reorganized methods in Grid_State_c, and remove the
CenterMapAt() method which was merely a synonym for MoveTo().

------------------------------------------------------------------------
040f6d24229a | Andrew Apted | 2016-12-09 21:05:27 +1100

made RedrawMap() always do an UpdateHighlight().

------------------------------------------------------------------------
aebabeea8f99 | Andrew Apted | 2016-12-09 19:58:44 +1100

CHANGELOG / TODO update.

------------------------------------------------------------------------
016576b4ba0e | Andrew Apted | 2016-12-09 19:57:53 +1100

part of previous commit (oops).

------------------------------------------------------------------------
e002265d60b5 | Andrew Apted | 2016-12-09 19:56:16 +1100

Improved ability to highlight/select very short linedefs, esp. ones
which are only 1 or 2 units long.

------------------------------------------------------------------------
52de25e87db2 | Andrew Apted | 2016-12-09 19:26:36 +1100

Event code : changed edit.map_x/y globals to be floating point,
as well as the UI_Canvas::MAPX/MAPY inline methods.

------------------------------------------------------------------------
e4965043f85b | Andrew Apted | 2016-12-09 18:47:21 +1100

rethink on previous commit and removed Editor_NotifyChanges().

------------------------------------------------------------------------
9b1415db5d10 | Andrew Apted | 2016-12-09 18:45:16 +1100

minor rename : MarkChanges() --> Editor_NotifyChanges()

------------------------------------------------------------------------
132fab0689a0 | Andrew Apted | 2016-12-09 18:40:23 +1100

code : simplified PointerPos() to set edit.map_x/y directly.

------------------------------------------------------------------------
299aeda1ee21 | Andrew Apted | 2016-12-09 18:25:18 +1100

Event code : implemented a PointerPos() method which can determine
the map coordinate at any time (outside of FLTK event passing).

------------------------------------------------------------------------
eb992126870e | Andrew Apted | 2016-12-09 17:21:59 +1100

Canvas : improved drawing of bold lines with the arrow, improving
the arrow size for really short lines.

------------------------------------------------------------------------
20e20a2a58e7 | Andrew Apted | 2016-12-09 16:46:56 +1100

Grid : added an extra zoom factor: 32:1

------------------------------------------------------------------------
946c71c903c0 | Andrew Apted | 2016-12-09 16:38:31 +1100

Event code : tidyied up EV_MouseMotion() function.

------------------------------------------------------------------------
32ad584f046e | Andrew Apted | 2016-12-09 15:59:43 +1100

Event code : renamed some functions to EV_ prefix, and removed
them from the global scope.

------------------------------------------------------------------------
1e4ea77947fc | Andrew Apted | 2016-12-09 15:52:04 +1100

refactored the duplicate handle() code of UI_Canvas and UI_Render3D
into a single function, EV_HandleEvent(), and improved the handling
of FL_ENTER events via new EV_EnterWindow() function.

------------------------------------------------------------------------
5e43057da0d1 | Andrew Apted | 2016-12-09 15:15:20 +1100

code : moved fields in Editor_State_t struct around and tweaked
the comments, removed two unused fields.

Also fixed Editor_Init() using memset to clear that structure,
which is not kosher when it contains real C++ classes.

------------------------------------------------------------------------
44f6d793e228 | Andrew Apted | 2016-12-09 01:40:06 +1100

TODO update.

------------------------------------------------------------------------
38acbb944f05 | Andrew Apted | 2016-12-09 01:38:07 +1100

GAMES / Hexen : added spawn arguments to the handful of things
which use them.

------------------------------------------------------------------------
d49cb6e0aea8 | Andrew Apted | 2016-12-09 01:35:08 +1100

Hexen format : support spawn arguments for things, both parsing
from the game definition and tool-tipping in the Thing panel.

------------------------------------------------------------------------
d1325462cf1e | Andrew Apted | 2016-12-08 23:26:54 +1100

Added config variable "transparent_col", specifies color of the
transparent pixels of textures (shown in the browser / panels).

------------------------------------------------------------------------
afaef8a8e501 | Andrew Apted | 2016-12-08 23:11:50 +1100

UI_Scroll : fixed the new JumpToChild() method.

------------------------------------------------------------------------
fcd64a044c44 | Andrew Apted | 2016-12-08 15:34:32 +1100

UI_Scroll : implemented the new JumpToChild() method.

------------------------------------------------------------------------
d0a7bc6701e6 | Andrew Apted | 2016-12-08 15:20:47 +1100

Browser : began work on ability to jump to a particular texture,
flat, thing, etc....

------------------------------------------------------------------------
1918ca01c9da | Andrew Apted | 2016-12-08 14:27:09 +1100

minor rename : ShowBrowser() method --> BrowserMode()

------------------------------------------------------------------------
fa67f63412d0 | Andrew Apted | 2016-12-08 14:08:53 +1100

Drawing mode : fixed behavior when the line loop finishes at a
self-reference line (a vertex or one split), which before was
simply doing nothing.

------------------------------------------------------------------------
959585773f33 | Andrew Apted | 2016-12-08 13:15:13 +1100

CHANGELOG and TODO update.

------------------------------------------------------------------------
3ce1c14ea638 | Andrew Apted | 2016-12-08 13:11:52 +1100

Open Map : fixed crash when editing a pwad but then trying to open
a map from the game iwad.

------------------------------------------------------------------------
4c97a3fee64d | Andrew Apted | 2016-12-08 12:54:19 +1100

lib_file : fixed FilenameGetPath() code, which was quite borked.

------------------------------------------------------------------------
31478892199d | Andrew Apted | 2016-12-08 12:42:14 +1100

Export Map : prevent the export if the chosen file is one which
we already have open (like the IWAD or the current PWAD).

------------------------------------------------------------------------
a9e9aa0094f4 | Andrew Apted | 2016-12-08 12:20:03 +1100

Fixed potential crash when loading a map from the Given-files or
Recent-files menus.

------------------------------------------------------------------------
28d3bb3ba4c4 | Andrew Apted | 2016-12-08 11:41:08 +1100

Map loader : fixed a bug handling bad sidedef references in linedefs
when the map has no sectors.

------------------------------------------------------------------------
a960783c8446 | Andrew Apted | 2016-12-08 11:24:13 +1100

BSP : don't crash on maps which consist entirely of dud linedefs
(ones which lack any sidedefs).   Treat the map as empty instead.

------------------------------------------------------------------------
8579170b73b6 | Andrew Apted | 2016-12-07 23:56:39 +1100

code tidying : fixed several FatalError() and BugError() strings
which lacked a trailing new-line ('\n').

------------------------------------------------------------------------
7ce770f75367 | Andrew Apted | 2016-12-07 23:31:39 +1100

CHANGELOG and TODO update.

------------------------------------------------------------------------
9e4f7eaf289c | Andrew Apted | 2016-12-07 23:30:10 +1100

Checks : fixed the criss-cross linedef detection, which was too
sloppy and did not handle some cases properly (like co-linear
lines which partially overlap).

------------------------------------------------------------------------
9a644ea29e57 | Andrew Apted | 2016-12-07 20:41:35 +1100

TODO update.

------------------------------------------------------------------------
0544f2d85421 | Andrew Apted | 2016-12-07 19:37:39 +1100

Menus : pass /MENU flag to certain editing commands, so they will
know that the current highlight cannot be used.

------------------------------------------------------------------------
46f1721e99e6 | Andrew Apted | 2016-12-07 19:36:38 +1100

Menus : rearranged the HELP menu, removed dividing lines.

------------------------------------------------------------------------
0109127fbeb9 | Andrew Apted | 2016-12-07 19:29:49 +1100

Menus : added "Operation Menu" to the VIEW menu, with F1 as the
shortcut, and hence removed the F1 binding from bindings.cfg

------------------------------------------------------------------------
a606e2f41192 | Andrew Apted | 2016-12-07 19:03:29 +1100

dead code removal.

------------------------------------------------------------------------
efee4ad13d35 | Andrew Apted | 2016-12-07 19:01:28 +1100

Prefs / key bindings : ensure a fresh binding (from the "Add" and
"Copy" buttons) will be visible and selected in the key list.

------------------------------------------------------------------------
4ea96b420870 | Andrew Apted | 2016-12-07 16:47:45 +1100

Prefs / key bindings : fixed the Keyword/Flags menus not updating
after selecting a new function, and renamed the "Mode" choices to
be pluralized ("Linedefs", "Sectors", etc) like on the infobar.

------------------------------------------------------------------------
54e96daba6f1 | Andrew Apted | 2016-12-07 16:33:50 +1100

Prefs / key bindings : don't have "General" as a selectable context
when the command is context-limited (like SEC_Floor or LIN_Path).

------------------------------------------------------------------------
0bba205a8598 | Andrew Apted | 2016-12-07 16:26:49 +1100

Prefs / key binding : got the "Mode" choice to be updated properly
when a new function is selected.

------------------------------------------------------------------------
f4c702b845db | Andrew Apted | 2016-12-07 15:29:20 +1100

Prefs / key bindings : added code to populate the "Mode" choice,
supporting deactivated items and handling the reverse order.

------------------------------------------------------------------------
fe43132d0206 | Andrew Apted | 2016-12-07 15:03:46 +1100

Prefs / key bindings : moved "Function" above "Mode" in key edit
dialog, and tidied up the UI_EditKey constructor code.

------------------------------------------------------------------------
2bf13d7e8e92 | Andrew Apted | 2016-12-07 14:12:52 +1100

tweaked default grid colors.

------------------------------------------------------------------------
5a99882f7ba5 | Andrew Apted | 2016-12-07 14:12:00 +1100

Preferences : added tooltips to the colors in GRID tab.

------------------------------------------------------------------------
5536f9583df3 | Andrew Apted | 2016-12-07 14:00:58 +1100

Preferences : fixed layout in the GRID tab.

------------------------------------------------------------------------
df4a286860c6 | Andrew Apted | 2016-12-06 22:28:10 +1100

LineDef panel : updated description as user types, and support
hexadecimal in the type field (which is slighly useful for BOOM
generalized line types).

------------------------------------------------------------------------
2f1776e32884 | Andrew Apted | 2016-12-06 22:13:28 +1100

Defaults panel : update thing description as user types.

------------------------------------------------------------------------
d1adfe7ec7da | Andrew Apted | 2016-12-06 22:04:08 +1100

Thing panel : update description field as the user types, and also
the special (when the map format is HEXEN).

------------------------------------------------------------------------
2eb96ec4a959 | Andrew Apted | 2016-12-06 21:51:00 +1100

code : renamed "UI_PicName" --> "UI_DynInput".

------------------------------------------------------------------------
61fd7b5592a4 | Andrew Apted | 2016-12-06 21:45:47 +1100

Sector panel : update description field as the user types.

------------------------------------------------------------------------
da05dfe352cb | Andrew Apted | 2016-12-06 20:46:59 +1100

TODO.txt : merged in the current WIP.txt stuff, updated some stuff
that has been done, and general tidying up.

------------------------------------------------------------------------
93820c2e45e0 | Andrew Apted | 2016-12-06 20:07:21 +1100

Browser : minor rename: "Line Types" --> "Line Specials".

------------------------------------------------------------------------
6c992624ca8d | Andrew Apted | 2016-12-06 19:48:10 +1100

Bindings : for vertex mode, added SHIFT-MOUSE3 for inserting a
vertex with "/continue" flag (matching SHIFT-INS and SHIFT-SPACE).

------------------------------------------------------------------------
349075b4eccd | Andrew Apted | 2016-12-06 19:43:34 +1100

Insert command : removed "/new" flag -- it only did something in
sectors mode, and now we *always* create a new sector.

------------------------------------------------------------------------
d69818948208 | Andrew Apted | 2016-12-06 19:10:35 +1100

PORTS / ZDoom : sorted out the categories for action specials,
adding several new ones (in hexen_specials.ugh) and changing
several specials.

------------------------------------------------------------------------
643546827e8b | Andrew Apted | 2016-12-06 18:52:20 +1100

GAMES/PORTS : removed trailing whitespcae in hexen_specials.ugh

------------------------------------------------------------------------
2d321a194fd6 | Andrew Apted | 2016-12-06 18:50:59 +1100

GAMES/PORTS : rename "sound" --> "sound_seq" in action specials.

------------------------------------------------------------------------
50a9f0463262 | Andrew Apted | 2016-12-06 18:46:59 +1100

operations.cfg : changed name of 90-degree arc command.

------------------------------------------------------------------------
be8469affc1d | Andrew Apted | 2016-12-06 18:19:35 +1100

Delete command : simplified to have just a single "/keep" flag,
instead of two variants (keep_things and keep_unused).

------------------------------------------------------------------------
a123703a16b7 | Andrew Apted | 2016-12-06 16:53:52 +1100

Browser : when opening the browser via binding or the menus, and
that type of browser (e.g. textures) is already open, then close it.

This is consistent with what CTRL-D (Defaults panel) and CTRL-F
(Find/Replace panel) do.

------------------------------------------------------------------------
6bde70c1a3cb | Andrew Apted | 2016-12-06 14:56:59 +1100

VT_ShapeArc : fixed error message when selection is empty.

------------------------------------------------------------------------
3c14166d51a3 | Andrew Apted | 2016-12-06 14:13:26 +1100

Grid : made the dotty grid be a preference setting instead of a
three-way toggle (which was confusing and not very useful).

Also draw the square grid when sector rendering is enabled (i.e.
don't force the grid off in that situation).

Lastly, renamed a few config vars to have the "grid_" prefix.

------------------------------------------------------------------------
e7da65cdc70c | Andrew Apted | 2016-12-06 13:34:18 +1100

renamed the "Documentation" command --> "OnlineDocs".

------------------------------------------------------------------------
3b21966059b3 | Andrew Apted | 2016-12-06 13:20:40 +1100

CHANGELOG update, rejigged the Games/Ports section.

------------------------------------------------------------------------
4c5661dd2239 | Andrew Apted | 2016-12-06 13:18:28 +1100

Menus : added F1..F10 function keys as shortcuts for various menu
items, F2..F4 are the Move/Scale/Rotate dialogs, F5..F8 are browser
functions, F9 is the map checking (ALL), etc.

Also changed "Toggle grid type" --> "Toggle gamma" in VIEW menu.

------------------------------------------------------------------------
4484fd469767 | Andrew Apted | 2016-12-06 00:24:35 +1100

Reorganised command_table[], with new groups "Misc" and "2D View"
replacing the "UI" group, and moving the "General" group down to
be with the linedef/sector/etc operations.

------------------------------------------------------------------------
19a9cec89297 | Andrew Apted | 2016-12-05 23:54:02 +1100

code tidying : use "()" instead of "(void)" for most CMD_xxx functions.

------------------------------------------------------------------------
a5e8d2a7fc57 | Andrew Apted | 2016-12-05 23:47:24 +1100

Set and Toggle commands : support "sec_render" keyword to change
the current sector-rendering mode.

------------------------------------------------------------------------
f1d380e8a61c | Andrew Apted | 2016-12-05 23:36:20 +1100

Fixed sector merging -- unused sectors are now deleted and this
was causing the wrong sector to be re-selected afterwards.

------------------------------------------------------------------------
97b5488e9f56 | Andrew Apted | 2016-12-05 23:26:34 +1100

Fixed vertex merging to clear selection afterwards.

------------------------------------------------------------------------
efa4141be214 | Andrew Apted | 2016-12-05 22:12:16 +1100

PORTS / ZDoom : tidied up all the specials.

------------------------------------------------------------------------
b843d7f87506 | Andrew Apted | 2016-12-05 21:52:49 +1100

PORTS / ZDoom : added all the action specials, adapted (and condensed)
from the SLADE editor.  Not finished yet!

------------------------------------------------------------------------
dc65498211b5 | Andrew Apted | 2016-12-05 19:07:42 +1100

Key system : implemented better system for "lax" modifiers used by
navigation commands, there is now a fake "LAX-" modifier for key
bindings, and it must be present for the lax handling to kick in.

------------------------------------------------------------------------
462b450306b4 | Andrew Apted | 2016-12-05 19:06:54 +1100

TODO : moved stuff around.

------------------------------------------------------------------------
e12c1b96ebcb | Andrew Apted | 2016-12-05 15:34:14 +1100

Key system : replaced Fl::event_shift() and Fl::event_ctrl() with
checks using MOD_SHIFT and MOD_COMMAND, for consistent behavior on
all platforms.

------------------------------------------------------------------------
ff0b0cd4f4a2 | Andrew Apted | 2016-12-05 01:41:32 +1100

Vertex_MergeList : fixed bug where the remaining vertex could also
be deleted (e.g. merging all vertices of an isolated sector).

------------------------------------------------------------------------
a5a0adf499b7 | Andrew Apted | 2016-12-05 00:00:53 +1100

Version bump, as new "Test Map" command is working well.

------------------------------------------------------------------------
dfc32830f386 | Andrew Apted | 2016-12-04 23:59:26 +1100

Win32 : moved the RC file --> src/main.rc

------------------------------------------------------------------------
c87d0a26f096 | Andrew Apted | 2016-12-04 23:53:57 +1100

CHANGELOG and TODO update.

------------------------------------------------------------------------
7e1a81e6b709 | Andrew Apted | 2016-12-04 23:50:23 +1100

Test Map : fixed silly bug, wrong name for resource wads.

------------------------------------------------------------------------
98b1cfd066f6 | Andrew Apted | 2016-12-04 23:25:23 +1100

Test Map : fixed the relative EXE name to have "./" prefix to force
the shell invoked by system() to find the EXE file, and fixed bug
not adding "-file" before the pwad filename.

------------------------------------------------------------------------
b23fb4db54dd | Andrew Apted | 2016-12-04 23:08:44 +1100

Test Map : finished the GrabWadNames() logic.

------------------------------------------------------------------------
10f03bc32063 | Andrew Apted | 2016-12-04 22:57:50 +1100

Test Map : partial work on GrabWadNames() logic, which handles all
the wad filenames (iwad, resources, pwad).  The string management
is proving to be a headache though....

------------------------------------------------------------------------
b002f22a02fa | Andrew Apted | 2016-12-04 22:22:27 +1100

Test Map : code to convert the level name to a warp option.

------------------------------------------------------------------------
ae581c7fa1cc | Andrew Apted | 2016-12-04 21:49:01 +1100

Test Map : in port setup, ensure filename is made absolute when
adding it to the port-path database.

------------------------------------------------------------------------
1782346adb4e | Andrew Apted | 2016-12-04 21:46:05 +1100

Test Map : logic for saving/restoring the current working directory,
and chdir()-ing to the directory of the executable, and converting
the executable name to a relative name.

------------------------------------------------------------------------
6cea23e58c42 | Andrew Apted | 2016-12-04 21:34:07 +1100

lib_file : added FilenameGetPath() utility function.

------------------------------------------------------------------------
db98b44aad76 | Andrew Apted | 2016-12-04 21:14:11 +1100

Test Map : implemented M_IsPortPathValid().

------------------------------------------------------------------------
90f6d1bc8ba9 | Andrew Apted | 2016-12-04 21:08:38 +1100

Test Map : in project setup, only restrict names to "exe" extension
on the Windows platform, since executables in Linux tend to have no
extension at all.

------------------------------------------------------------------------
edc13e203407 | Andrew Apted | 2016-12-04 20:58:16 +1100

Test Map : pre-set the EXE name in the port setup dialog.

------------------------------------------------------------------------
8e49d5aef9e5 | Andrew Apted | 2016-12-04 20:49:38 +1100

Test Map : utility to convert "vanilla" + game to a pseudo port
name, and implemented the FIND button in the port setup dialog.

------------------------------------------------------------------------
49fc6d94bcbe | Andrew Apted | 2016-12-04 20:28:54 +1100

Test Map / port setup : mention the correct port name, with special
handling for vanilla.

------------------------------------------------------------------------
070805f5e990 | Andrew Apted | 2016-12-04 19:59:20 +1100

Test Map : nailed down layout and message text of the source port
setup dialog.

------------------------------------------------------------------------
387e725ca64e | Andrew Apted | 2016-12-04 19:23:35 +1100

Test Map : change of tack, instead of having a dialog open when
using the command, have a "Setup" button in the Manage Project
dialog which opens another dialog for setting up the EXE path.

So did a bit of work in this new direction....

------------------------------------------------------------------------
0069f1dcb865 | Andrew Apted | 2016-12-04 19:01:52 +1100

Test Map : bit more work on UI_TestMapDialog....

------------------------------------------------------------------------
4f4894281dec | Andrew Apted | 2016-12-04 17:53:54 +1100

OperationMenu : don't FatalError() when "operations.cfg" not found,
show a notify dialog instead.

------------------------------------------------------------------------
65bdddb6f23d | Andrew Apted | 2016-12-04 17:38:35 +1100

Test Map : implemented logic for creating/querying the exe path
for a given port, and persisting that data in the "misc.cfg" file.

------------------------------------------------------------------------
a162e6b34b96 | Andrew Apted | 2016-12-04 16:06:31 +1100

Test Map : began work on a dialog window....

------------------------------------------------------------------------
14908a0b3f12 | Andrew Apted | 2016-12-04 15:29:43 +1100

Fix for "Export Map", always reload resources and do it *after* we
have replaced the current edit_wad.

------------------------------------------------------------------------
effdd2d3c572 | Andrew Apted | 2016-12-04 15:21:28 +1100

Improved code in CMD_OpenMap(), ensure we reload resources when
the edit_map is removed.

------------------------------------------------------------------------
41265c4b8e23 | Andrew Apted | 2016-12-04 14:59:16 +1100

code refactoring in m_loadsave.cc : added ReplaceEditWad().

------------------------------------------------------------------------
cedb68a94f02 | Andrew Apted | 2016-12-04 14:52:03 +1100

code tidying in OpenFileMap() function.

------------------------------------------------------------------------
a9028d2e7ffc | Andrew Apted | 2016-12-04 14:34:38 +1100

minor rename : check_sizes() --> CheckTypeSizes()

------------------------------------------------------------------------
74d1b4382f64 | Andrew Apted | 2016-12-04 14:30:40 +1100

code tidying : more tweaking of comments before functions.

------------------------------------------------------------------------
22f1668ba541 | Andrew Apted | 2016-12-04 14:30:09 +1100

lib_util : more code tidying...

------------------------------------------------------------------------
2b9ecd9fe65d | Andrew Apted | 2016-12-04 14:23:45 +1100

lib_util : simplified y_stricmp() and y_strnicmp() code.

------------------------------------------------------------------------
c273f7f1c8c4 | Andrew Apted | 2016-12-04 14:10:01 +1100

code tidying : tweak comment style before some functions.

------------------------------------------------------------------------
da1ba7ff7357 | Andrew Apted | 2016-12-04 13:59:20 +1100

Menus : enabled the "Test in Game" command in FILE menu.

------------------------------------------------------------------------
7cd2f4850b88 | Andrew Apted | 2016-12-04 13:38:47 +1100

Test Map : moved existing code from m_nodes.cc --> m_testmap.cc

------------------------------------------------------------------------
6bebed59fa3d | Andrew Apted | 2016-12-04 13:32:50 +1100

Added code file "m_testmap.cc" -- this will contain the logic for
running a source port to test (play) the current map.  Empty so far.

------------------------------------------------------------------------
3cfd013845bb | Andrew Apted | 2016-12-04 13:29:07 +1100

Test Map : minor commenting.

------------------------------------------------------------------------
62e1c71fe8c5 | Andrew Apted | 2016-12-04 13:23:15 +1100

Preferences : added a "3D View" tab.

------------------------------------------------------------------------
7913b5d7d3ff | Andrew Apted | 2016-12-04 00:29:44 +1100

TODO update (largish) + CHANGELOG update (smallish).

------------------------------------------------------------------------
d1b443b34bef | Andrew Apted | 2016-12-04 00:00:50 +1100

Added two new commands "Documentation" and "AboutDialog", and
execute them for the HELP menu.

------------------------------------------------------------------------
0b24e3d66620 | Andrew Apted | 2016-12-03 23:45:34 +1100

Menus : added commands for everything in the FILE menu, such as
"NewProject", "OpenMap", "SaveMap", "PreferenceDialog" -- and the
menu code calls these via ExecuteCommand().

------------------------------------------------------------------------
140fc653430f | Andrew Apted | 2016-12-03 23:25:54 +1100

BrowserMode command : support a "/recent" flag.

------------------------------------------------------------------------
6c80ba6b5f09 | Andrew Apted | 2016-12-03 23:20:05 +1100

Menus : added four new commands "DefaultProps", "FindDialog", "FindNext"
and "LogViewer" -- and run these commands in the menu code.

------------------------------------------------------------------------
160d9bca0b03 | Andrew Apted | 2016-12-03 23:13:30 +1100

Bindings : because Insert is on MOUSE3 in vertex mode, we need to
explicitly bind MOUSE3 in render mode to "OperationMenu".

------------------------------------------------------------------------
96f4bc620725 | Andrew Apted | 2016-12-03 22:58:27 +1100

CHANGELOG and TODO update.

------------------------------------------------------------------------
bdc9abd5a67f | Andrew Apted | 2016-12-03 22:50:50 +1100

Bindings : use '/' instead of ENTER key for the "OperationMenu"
command, since using ENTER key can interfere with input widgets
(like texture names in the Sector panel).

------------------------------------------------------------------------
5afe06109157 | Andrew Apted | 2016-12-03 22:33:26 +1100

Menus : changed several callbacks, e.g. in BROWSER menu, to use
ExecuteCommand() instead of directly performing the action.

------------------------------------------------------------------------
4dd3ea465bfc | Andrew Apted | 2016-12-03 22:29:24 +1100

Zoom command : support /center flag which zooms around the center
of the 2D canvas (instead of around the mouse pointer).

------------------------------------------------------------------------
eeb994cf66de | Andrew Apted | 2016-12-03 22:06:49 +1100

code : fixed a few places not checking M_ParseLine result properly.

------------------------------------------------------------------------
9302f822b399 | Andrew Apted | 2016-12-03 21:42:35 +1100

Operation menu : stop the popup menu being positioned so the last
command used on that menu is under the mouse pointer.

------------------------------------------------------------------------
9393d581cd2a | Andrew Apted | 2016-12-03 21:07:44 +1100

Operation menu : parse the command name and any parameters, and
implemented the callback function to actually execute the command.

------------------------------------------------------------------------
651e54f9997f | Andrew Apted | 2016-12-03 20:58:25 +1100

Key system : added ExecuteCommand() variant which directly uses an
editor_command_t, added a fourth "paramX" parameter, and properly
separate flag names (beginning with '/') from normal parameters.

------------------------------------------------------------------------
24babd1f8d8f | Andrew Apted | 2016-12-03 20:06:14 +1100

Operation Menus : increased font size + better menu headings.

------------------------------------------------------------------------
19501a1d92ce | Andrew Apted | 2016-12-03 20:05:55 +1100

code tidying : whitespace in main.cc

------------------------------------------------------------------------
f9aab5a92a02 | Andrew Apted | 2016-12-03 19:47:53 +1100

Operation menu : parse enough to show menu actions, and implemented
the CMD_OperationMenu() code to popup the appropriate menu.

------------------------------------------------------------------------
5b0885c07822 | Andrew Apted | 2016-12-03 19:17:04 +1100

Fixed bug in M_ParseLine() not handling spaces in string tokens.

------------------------------------------------------------------------
9882ce61324e | Andrew Apted | 2016-12-03 18:09:55 +1100

Operation menu : logic to read and tokenize each line.

------------------------------------------------------------------------
ed6686301e73 | Andrew Apted | 2016-12-03 18:00:45 +1100

Operation menus : worked on the loading code, check for a missing
file or a menu that was not parsed properly.

------------------------------------------------------------------------
ad4108e89760 | Andrew Apted | 2016-12-03 17:45:46 +1100

Began work on Operation menus....

------------------------------------------------------------------------
e9bc9dfda30b | Andrew Apted | 2016-12-03 17:20:14 +1100

Makefile and pack scripts : ensure the new "defaults.cfg" and
"operations.cfg" files get installed / packaged.

------------------------------------------------------------------------
0a8f59e52b32 | Andrew Apted | 2016-12-03 17:14:30 +1100

Preferences / KEYS : prevent a horizontal scrollbar appearing in
the key_list browser, and tweaked layout some more.

------------------------------------------------------------------------
34a6d8337009 | Andrew Apted | 2016-12-03 17:06:06 +1100

Preferences : improved layout of KEYS tab.

------------------------------------------------------------------------
bc68275723b6 | Andrew Apted | 2016-12-03 16:50:32 +1100

Config : added comment to top of the written "config.cfg" file.

------------------------------------------------------------------------
c1acf0441b3b | Andrew Apted | 2016-12-03 16:31:07 +1100

Created "defaults.cfg" file, which contains the default settings.

------------------------------------------------------------------------
265438b58ce5 | Andrew Apted | 2016-12-03 16:27:45 +1100

Preferences : notify user if "defaults.cfg" could not be loaded.

------------------------------------------------------------------------
a779997b479d | Andrew Apted | 2016-12-03 16:13:25 +1100

Preferences : implemented a new "Reset All Settings" button in the
OTHER tab, and moved the "Reset Key Bindings" button here too.
Also improved the wording of the confirmation dialog.

------------------------------------------------------------------------
bb0f0fcc6eef | Andrew Apted | 2016-12-03 15:34:04 +1100

Created "operations.cfg" -- contains the commands for the planned
Operation menu.

------------------------------------------------------------------------
08a0b4763727 | Andrew Apted | 2016-12-03 14:29:35 +1100

BSP : fixed bug when building nodes for maps which end up having a
single subsector and no nodes (partition lines).

------------------------------------------------------------------------
d3974b8229a8 | Andrew Apted | 2016-12-03 13:45:20 +1100

Changed "Fresh Map" to bail when there is no edit_wad, which makes
more sense than falling back to the "New Project" dialog.

------------------------------------------------------------------------
f16711d89ab4 | Andrew Apted | 2016-12-03 13:44:32 +1100

Config : renamed "gui_scheme" so users get the new default (GTK+)

------------------------------------------------------------------------
610af1432c97 | Andrew Apted | 2016-12-03 13:34:50 +1100

Menus : rejig in FILE menu, renamed "New Map" --> "Fresh Map" and
moved it down.

------------------------------------------------------------------------
d9646bfa94fe | Andrew Apted | 2016-12-03 13:13:59 +1100

Config files : added M_ParseDefaultConfigFile() function.

------------------------------------------------------------------------
0d62617c10c6 | Andrew Apted | 2016-12-03 13:06:44 +1100

Menus : moved "View Logs" to the HELP menu.

------------------------------------------------------------------------
488cfa4a42e4 | Andrew Apted | 2016-12-03 01:26:35 +1100

debugging : disabled the check for unused stuff, as I have plugged
most of the holes now.

------------------------------------------------------------------------
18334e765d11 | Andrew Apted | 2016-12-03 01:18:49 +1100

CMD_Delete : fixed an issue where deleting a bunch of vertices
could leave some unused sidedefs.

------------------------------------------------------------------------
7b5959712169 | Andrew Apted | 2016-12-03 01:05:52 +1100

Vertex_MergeList : when sandwich merging, fix flags of remaining
linedef (TWO-SIDED and IMPASSIBLE flags).

------------------------------------------------------------------------
182cd3135548 | Andrew Apted | 2016-12-03 00:57:17 +1100

Vertex_MergeLines : prevent unnecessary sandwich mergers.

------------------------------------------------------------------------
a6c332d0271b | Andrew Apted | 2016-12-03 00:25:20 +1100

Vertex_MergeList : improved the logic, collect ALL linedefs to be
deleted into a selection and do them last, and ensure that ALL
references to a merged-away vertex is changed to the kept one.

------------------------------------------------------------------------
4f300619825e | Andrew Apted | 2016-12-02 23:44:33 +1100

code reorganising in e_vertex.cc

------------------------------------------------------------------------
5067514180b8 | Andrew Apted | 2016-12-02 23:43:00 +1100

minor rename of "Vertex_HowManyLineDefs" function.

------------------------------------------------------------------------
3494b2722f8a | Andrew Apted | 2016-12-02 23:39:44 +1100

Worked on making Vertex_MergeList() be the only conduit for merging
two or more vertices -- however it is still buggy....

------------------------------------------------------------------------
9d44a951e041 | Andrew Apted | 2016-12-02 23:07:43 +1100

Checks : ignore zero-length lines when finding overlapping ones.

------------------------------------------------------------------------
c145f436101c | Andrew Apted | 2016-12-02 22:53:58 +1100

Checks : improved code to remove zero-length linedefs, ensure that
there are no unused sectors or sidedefs afterwards.

------------------------------------------------------------------------
2813e53f2ed5 | Andrew Apted | 2016-12-02 22:24:40 +1100

Made the Vertex_MergeList() not do BA_Begin/BA_End, instead the
calling code does it.

One benefit is that merging overlapping vertices is now a single
undo/redo operation, rather than an operation for each merge pair.

------------------------------------------------------------------------
7d0828a0d9d1 | Andrew Apted | 2016-12-02 22:23:32 +1100

Basis : prevent memory leak in BA_End() when no operations were done.

------------------------------------------------------------------------
bba5efe3f6c5 | Andrew Apted | 2016-12-02 22:00:54 +1100

Vertex panel : implemented 4 arrow buttons for position adjustment.

------------------------------------------------------------------------
0aa4289270a6 | Andrew Apted | 2016-12-02 20:45:05 +1100

TODO and CHANGELOG update.

------------------------------------------------------------------------
ce587c836e6f | Andrew Apted | 2016-12-02 20:42:16 +1100

Drawing mode : when closing a line loop, select ALL vertices of the
newly created sector (to allow switching to sector mode and having
the new sector stay selected).

------------------------------------------------------------------------
ddf26dad9ed4 | Andrew Apted | 2016-12-02 20:27:31 +1100

Drawing mode : fixed several bugs in new Insert_Vertex logic.

------------------------------------------------------------------------
017e5641fda2 | Andrew Apted | 2016-12-02 20:17:13 +1100

Rewrote the Insert_Vertex() code to be easier to understand.

------------------------------------------------------------------------
c028df403736 | Andrew Apted | 2016-12-02 16:58:52 +1100

Canvas : fixed not drawing a highlighted vertex when dragging a
single vertex (which is needed to show a potential merge).

------------------------------------------------------------------------
c422577ad13f | Andrew Apted | 2016-12-02 16:56:53 +1100

Canvas : draw a single dragged vertex as orange, not yellow.

------------------------------------------------------------------------
d90b7fb72340 | Andrew Apted | 2016-12-02 16:37:27 +1100

When assigning a new sector to an area (CTRL-SPACE), ensure any
sectors which are unused afterwards are removed.

------------------------------------------------------------------------
2bae8a5b840e | Andrew Apted | 2016-12-02 16:03:00 +1100

dead code removal (namely DeleteLineDefs).

------------------------------------------------------------------------
36fec0f79b5d | Andrew Apted | 2016-12-02 16:02:07 +1100

Fixed sector merging to not leave unused sectors behind.

------------------------------------------------------------------------
6de9c2715f60 | Andrew Apted | 2016-12-02 15:59:48 +1100

Fixed bug in DeleteObjects_WithUnused().

------------------------------------------------------------------------
84e7bf0117ca | Andrew Apted | 2016-12-02 15:33:47 +1100

Refactored CMD_Delete, have a separate DeleteObjects_WithUnused().

------------------------------------------------------------------------
2109a90b2215 | Andrew Apted | 2016-12-02 15:18:29 +1100

When deleting a vertex and merging the two connecting lines, ensure
we delete any sidedefs that would be unused afterwards.

------------------------------------------------------------------------
799dac3cf083 | Andrew Apted | 2016-12-02 14:25:28 +1100

Debugging code for operations which leave unused sectors or sidedefs.

------------------------------------------------------------------------
42f20bf6f3f8 | Andrew Apted | 2016-12-02 13:16:13 +1100

3D View : fixed pixel aspect handling, larger values should make
each pixel *wider*, and the default should be 0.83 to match what
DOOM originally looked like.

This improved the rendering code too, as two "magic" constants
(Y_SLOPE being 1.7, and 133 in CalcAspect) have been removed.

Also renamed the config variable, so that upgrading users will
get the proper pixel aspect value.

------------------------------------------------------------------------
b2f4f8135e55 | Andrew Apted | 2016-12-02 00:08:31 +1100

CHANGELOG and TODO update.

------------------------------------------------------------------------
05b0339958e2 | Andrew Apted | 2016-12-01 22:37:41 +1100

Preferences : moved "Seg split logic" setting in the Nodes tab.

------------------------------------------------------------------------
7c5a7dae527a | Andrew Apted | 2016-12-01 22:24:57 +1100

BSP : removed vestiges of the "one-sided window trick" handling.

------------------------------------------------------------------------
e504fd372fdb | Andrew Apted | 2016-12-01 20:03:52 +1100

BSP : fixed two issues with ZDoom format:
(1) not sorting the segs unless GL nodes were also built
(2) vertex indices of NEW vertices was wrong

------------------------------------------------------------------------
69568dc59007 | Andrew Apted | 2016-12-01 15:25:14 +1100

BSP : code tidying, renamed "cur" variable --> "seg".

------------------------------------------------------------------------
6794375bc6ec | Andrew Apted | 2016-12-01 15:12:39 +1100

Sprite loader : recolor the 4001..4004 player starts as blue.

------------------------------------------------------------------------
8e3d6ec4a3a2 | Andrew Apted | 2016-12-01 15:05:55 +1100

PORTS : added player things 4001..4004 to Boom, Odamex and ZDoom.

------------------------------------------------------------------------
7747e6821268 | Andrew Apted | 2016-12-01 14:45:54 +1100

Texture loader : validate the texture count and offset values.

------------------------------------------------------------------------
e7100bbde20d | Andrew Apted | 2016-12-01 13:32:20 +1100

TODO updated.

------------------------------------------------------------------------
cbe8d9685722 | Andrew Apted | 2016-12-01 13:29:31 +1100

Bindings : changed key to open texture-browser back to 'T', since
it is useful in the 3D View but the 'X' key has a binding there.

------------------------------------------------------------------------
3d9131c31d2d | Andrew Apted | 2016-12-01 13:21:52 +1100

Texture loader : use a proper method to detect STRIFE format of
the TEXTURE1/2 lumps (same logic as in ZDoom), and structured the
code better.

------------------------------------------------------------------------
a56ae864e7e0 | Andrew Apted | 2016-12-01 00:39:51 +1100

Bindings : restore 'q' to be Quantize (after testing some stuff).

------------------------------------------------------------------------
d3a772629e54 | Andrew Apted | 2016-12-01 00:39:01 +1100

Code : more tidying....

------------------------------------------------------------------------
f64026a19dd4 | Andrew Apted | 2016-12-01 00:23:14 +1100

Disabled the half-finished feature to show thing skills via color
(on the 2D canvas).  May revisit the idea later....

------------------------------------------------------------------------
3b564712103f | Andrew Apted | 2016-12-01 00:18:59 +1100

Code : minor tidying.

------------------------------------------------------------------------
e7a9c6660529 | Andrew Apted | 2016-11-30 23:45:58 +1100

Code : simplified M_ParseCommandLine() and M_ParseEnvironmentVars()
to be void functions, as they never returned anything meaningful.

------------------------------------------------------------------------
3dde64363cec | Andrew Apted | 2016-11-30 23:26:19 +1100

BSP : for CMD_BuildAllNodes, check earlier if no levels exist, and
removed the duplicated SetErrorMsg() code.

------------------------------------------------------------------------
ca42f3c54896 | Andrew Apted | 2016-11-30 23:11:43 +1100

minor tweak.

------------------------------------------------------------------------
5f8f5205597b | Andrew Apted | 2016-11-30 22:46:18 +1100

TODO update.

------------------------------------------------------------------------
426358794acd | Andrew Apted | 2016-11-30 22:45:06 +1100

BSP : implemented the XNOD format (for ZDoom nodes).

------------------------------------------------------------------------
e76e13671f1d | Andrew Apted | 2016-11-30 22:27:18 +1100

BSP : compute a "max_size" when saving ZDoom format NODES.

------------------------------------------------------------------------
cb7f10ea5c7a | Andrew Apted | 2016-11-30 22:25:36 +1100

BSP : free the message string in nodebuildinfo_t destructor.

------------------------------------------------------------------------
628be7fef492 | Andrew Apted | 2016-11-30 21:52:08 +1100

BSP : actually honor the "Build Nodes on Save" setting.

------------------------------------------------------------------------
9f1b016c2d19 | Andrew Apted | 2016-11-30 21:49:40 +1100

Preferences : removed (hidden) the "Force zlib compression" setting
of the Nodes panel -- this is probably not worth supporting.

------------------------------------------------------------------------
aafd2bd2bc38 | Andrew Apted | 2016-11-30 21:45:26 +1100

BSP : prevent node-building a map twice in the case where the user
has not saved the map, uses the "BuildAllNodes" command, and is
asked whether to save the map and they choose yes.

------------------------------------------------------------------------
86a9d4c9426f | Andrew Apted | 2016-11-30 21:35:58 +1100

BSP : handle it when the map is empty (no linedefs etc...)

------------------------------------------------------------------------
890c5bb01498 | Andrew Apted | 2016-11-30 19:55:03 +1100

PORTS / ZDoom : include "hexen_specials.ugh"

------------------------------------------------------------------------
0a32ce5fef27 | Andrew Apted | 2016-11-30 19:47:41 +1100

GAMES / Hexen : move special defs --> "common/hexen_specials.ugh"

------------------------------------------------------------------------
a5033d194ab2 | Andrew Apted | 2016-11-30 19:40:44 +1100

Removed "xlat_doom.cfg" and "xlat_hexen.cfg" files, they are unused
and almost empty, and I plan translate maps in a different way.

------------------------------------------------------------------------
ce0d618837e5 | Andrew Apted | 2016-11-30 19:39:07 +1100

Game def parser : ignore "special" commands in DOOM map format,
and "line" commands in HEXEN map format.

------------------------------------------------------------------------
3cb5c2e4de1d | Andrew Apted | 2016-11-30 19:22:52 +1100

doc tweaks.

------------------------------------------------------------------------
3b9cd49d380b | Andrew Apted | 2016-11-30 19:12:14 +1100

CHANGELOG : rearranged stuff and clarified some entries.

------------------------------------------------------------------------
3eaf698d86ed | Andrew Apted | 2016-11-30 18:55:00 +1100

TODO update.

------------------------------------------------------------------------
011628b07067 | Andrew Apted | 2016-11-30 18:37:07 +1100

Menus : added "Toggle Sprites" to the VIEW menu.

------------------------------------------------------------------------
362423bfeb22 | Andrew Apted | 2016-11-30 18:32:58 +1100

Support new "sprites" keyword to Set and Toggle commands.

------------------------------------------------------------------------
1fdc8d58e298 | Andrew Apted | 2016-11-30 18:30:42 +1100

Fixed the broken "Set" command (it parsed wrong argument).

------------------------------------------------------------------------
dc272fa4bb9a | Andrew Apted | 2016-11-30 18:19:51 +1100

UI : control thing drawing on 2D canvas via "edit.thing_render_mode",
and added new config variable "thing_render_default" for it.

------------------------------------------------------------------------
16c326274b98 | Andrew Apted | 2016-11-30 16:58:21 +1100

CHANGELOG : updated, especially for recent binding changes.

------------------------------------------------------------------------
a9db41fc0e19 | Andrew Apted | 2016-11-30 16:38:42 +1100

CHANGELOG and TODO update.

------------------------------------------------------------------------
c882282ac702 | Andrew Apted | 2016-11-30 16:36:52 +1100

UI : when bringing up a file chooser, set the default directory to
a better value (namely: where the current PWAD is located).

------------------------------------------------------------------------
073d58d1501b | Andrew Apted | 2016-11-30 16:35:24 +1100

PORTS / Odamex : fixed having "end" instead of "endif".

------------------------------------------------------------------------
33f229170444 | Andrew Apted | 2016-11-30 16:07:32 +1100

CMD_Insert : don't try inserting stuff when 3D View is active
(it can lead to strange things happening).

------------------------------------------------------------------------
b53cfdc59c8f | Andrew Apted | 2016-11-30 16:04:10 +1100

UI : when toggling the 3D view, give keyboard focus to the widget
that is now active (render or canvas).

------------------------------------------------------------------------
089d794e3bca | Andrew Apted | 2016-11-30 14:42:23 +1100

Sector panel : layout tweaks.

------------------------------------------------------------------------
83e478c1b3d6 | Andrew Apted | 2016-11-30 14:27:52 +1100

Sector panel : changed "72" headroom button --> "64".

------------------------------------------------------------------------
b7a3307044b2 | Andrew Apted | 2016-11-30 14:20:10 +1100

UI : made default window size be a bit wider.

------------------------------------------------------------------------
463ae50ef644 | Andrew Apted | 2016-11-30 14:16:16 +1100

UI : default theme is now "GTK+"

------------------------------------------------------------------------
789c4f614d29 | Andrew Apted | 2016-11-30 14:07:54 +1100

UI : rejig colors for infobar edit-mode and free/snap widgets.

------------------------------------------------------------------------
7588b197d534 | Andrew Apted | 2016-11-30 14:07:03 +1100

Preferences : rejig order of themes and colorsets.

------------------------------------------------------------------------
32caab6d2079 | Andrew Apted | 2016-11-30 13:36:12 +1100

Bindings : bind 'a' to NAV_MouseScroll, 'MENU' to OperationMenu.

------------------------------------------------------------------------
f16ffae769a1 | Andrew Apted | 2016-11-30 00:54:29 +1100

dead code removal.

------------------------------------------------------------------------
d93abc4836fd | Andrew Apted | 2016-11-30 00:49:58 +1100

ACT_Click : when splitting a linedef, if BOTH ends of the linedef
are in the selection then select the new vertex too.

------------------------------------------------------------------------
4406f60b0ce5 | Andrew Apted | 2016-11-30 00:45:10 +1100

ACT_Click : support "/split" flag to allow splitting a linedef,
and ensure we can drag the new vertex when keeping the button
held down.

------------------------------------------------------------------------
191888863519 | Andrew Apted | 2016-11-30 00:08:57 +1100

Preferences : small tidy up.

------------------------------------------------------------------------
0512bed406c6 | Andrew Apted | 2016-11-30 00:08:15 +1100

Bindings : 'g' key now toggles the grid on/off.

------------------------------------------------------------------------
f9f32dc312da | Andrew Apted | 2016-11-30 00:04:54 +1100

Removed the "multi_select_modifier" config variable.

------------------------------------------------------------------------
87b501b68d33 | Andrew Apted | 2016-11-30 00:01:30 +1100

Removed the "easier_drawing_mode" config variable.

------------------------------------------------------------------------
5a4faa737ef2 | Andrew Apted | 2016-11-29 23:55:26 +1100

dead code removal.

------------------------------------------------------------------------
b8b8640e0f55 | Andrew Apted | 2016-11-29 23:04:14 +1100

Removed the never-used "mods" folder + support code.

Rationale: the idea here was to include definition files for some
famous DOOM mods with Eureka.  However, none have been made so far
and none are currently planned, and if we ever make some then they
can simply be distributed as separate packages.

------------------------------------------------------------------------
b14113ad8a24 | Andrew Apted | 2016-11-29 22:57:08 +1100

TODO and CHANGELOG update.

------------------------------------------------------------------------
0524f44062b5 | Andrew Apted | 2016-11-29 22:46:27 +1100

Bindings : bind ENTER key to "OperationMenu" command.

------------------------------------------------------------------------
9c98bbdf6748 | Andrew Apted | 2016-11-29 22:34:58 +1100

Delete command : fixed bug where deleting a loop of linedefs (or
their vertices) of an island inside another sector could delete
the outer sector too.

------------------------------------------------------------------------
7e7b9e502767 | Andrew Apted | 2016-11-29 21:49:09 +1100

TODO.txt : a few additions.

------------------------------------------------------------------------
9d3ea15b1dde | Andrew Apted | 2016-11-29 21:44:30 +1100

Texture aligning : disabled the partial comparison of tex names,
as it can lead to unexpected/confusing/surprising results.

------------------------------------------------------------------------
d06fdc2522c5 | Andrew Apted | 2016-11-29 21:28:17 +1100

Began work on "OperationMenu" command.....

------------------------------------------------------------------------
070c17e57843 | Andrew Apted | 2016-11-29 21:27:54 +1100

Bindings : removed the CMD-MOUSE1 binding.

------------------------------------------------------------------------
58815c0ad581 | Andrew Apted | 2016-11-29 20:59:47 +1100

Bindings : MOUSE3 in vertex mode is now "Insert" (begins line drawing),
and MOUSE3 (with and without CTRL) in other modes is "OperationMenu"
(which is not implemented yet, but will bring up a menu of operations).

------------------------------------------------------------------------
01ebe1dbcf9a | Andrew Apted | 2016-11-29 20:55:11 +1100

Bindings : aesthetic changes only, use comments to mark each
section of the file, moved all mouse button stuff to the top.

------------------------------------------------------------------------
af96039ad0c6 | Andrew Apted | 2016-11-29 20:47:58 +1100

Bindings : moved map-scroll/3d-navigation stuff from RMB --> MMB.

------------------------------------------------------------------------
88574413ffb2 | Andrew Apted | 2016-11-29 20:42:25 +1100

Bindings : moved the scale/rotate/adjust-offset commands to 'r' key
(plus modifiers), freeing up the middle mouse button.

------------------------------------------------------------------------
9d9ecc4711b5 | Andrew Apted | 2016-11-29 20:41:12 +1100

EditMode command : handle unknown modes better.

------------------------------------------------------------------------
8ea6ed01156a | Andrew Apted | 2016-11-29 19:50:08 +1100

LineDef panel : renamed "block walk" flag --> "impassible".

------------------------------------------------------------------------
256ca5d76064 | Andrew Apted | 2016-11-29 19:46:03 +1100

Default grid snapping and show-grid are now OFF.

------------------------------------------------------------------------
b7bad16888b2 | Andrew Apted | 2016-11-29 19:38:45 +1100

Default editing mode is now "Vertices", since that is where line
drawing happens, so it is the most common mode to use (especially
when starting a new map).

------------------------------------------------------------------------
5aa4057c399e | Andrew Apted | 2016-11-29 18:43:29 +1100

ACT_Click : re-implemented ability to select/deselect objects.

------------------------------------------------------------------------
342af568d2ab | Andrew Apted | 2016-11-29 18:25:28 +1100

ACT_Click : re-implemented ability to drag objects.

------------------------------------------------------------------------
2fc34192b5cc | Andrew Apted | 2016-11-29 18:13:19 +1100

Bindings : bound "ACT_SelectBox" to SHIFT-MOUSE1.

------------------------------------------------------------------------
80c474d96ea3 | Andrew Apted | 2016-11-29 18:08:25 +1100

ACT_Click : start a selection-box when clicking in an empty area
(requiring the "/select" flag).

------------------------------------------------------------------------
f41758a7f505 | Andrew Apted | 2016-11-29 16:27:14 +1100

Key system : removed "button_down" and "button_mod" fields from
the global editor state.

------------------------------------------------------------------------
c4ecbb30bd17 | Andrew Apted | 2016-11-29 15:51:41 +1100

Key system : began work to handle "MOUSE1" (aka LMB) as a normal
bindable command: "ACT_Click".  So far it is very broken....

------------------------------------------------------------------------
d593372c6ba3 | Andrew Apted | 2016-11-29 14:13:20 +1100

Key system : honor the speed parameter of "NAV_MouseScroll" and
"3D_NAV_MouseMove" commands.

------------------------------------------------------------------------
da0bff6f09b8 | Andrew Apted | 2016-11-29 13:47:30 +1100

Key system : handle SHIFT properly for "3D_ACT_AdjustOfs" command.

------------------------------------------------------------------------
65163383afc3 | Andrew Apted | 2016-11-29 13:42:13 +1100

Key system : for navigation in 2D or 3D views, support SHIFT and CTRL
modifiers to slow down / speed up the movement.

------------------------------------------------------------------------
fc8e232382ef | Andrew Apted | 2016-11-29 13:17:11 +1100

Key system : split NAV_Scroll_X command into two (_Left and _Right),
and also NAV_Scroll_Y into _Up and _Down variants.  This makes the
scrolling work a bit more fluidly.

------------------------------------------------------------------------
b3db855c89f6 | Andrew Apted | 2016-11-29 12:47:49 +1100

Key system : split "NAV_MouseScroll" into two commands, where one
is specifically for the 3D View, namely "3D_NAV_MouseMove".

------------------------------------------------------------------------
20dcea9d7379 | Andrew Apted | 2016-11-28 23:56:44 +1100

TODO.txt : added a few things.

------------------------------------------------------------------------
7d3c74afa709 | Andrew Apted | 2016-11-28 23:51:21 +1100

Renamed the "Check" command --> "MapCheck", with some code to
ensure backwards compatibility when loading key bindings.

------------------------------------------------------------------------
4e7b75defa36 | Andrew Apted | 2016-11-28 23:33:07 +1100

Bindings : removed SHIFT and CMD versions of the 3D_NAV_xxx binds,
since the code now handles this explicitly.

------------------------------------------------------------------------
396baab927a2 | Andrew Apted | 2016-11-28 23:24:50 +1100

Key system : once a navigation or action is underway, ignore it
when only the modifiers have changed (i.e. the bare key or button
is still pressed).

------------------------------------------------------------------------
114bc655a9d6 | Andrew Apted | 2016-11-28 23:15:27 +1100

Key system : updated Nav_SetKey() and Nav_UpdateKeys() to handle
commands that use "lax_mods", mainly the NAV_xxx commands.

------------------------------------------------------------------------
0fe6bdfbcdb4 | Andrew Apted | 2016-11-28 22:39:47 +1100

Key system : allow certain commands, especially "NAV_xxx" ones, to
specify one or more modifiers which it uses directly.  Matching a
binding will allow any of these "lax_mods" to be present or absent.

------------------------------------------------------------------------
a5611c121b12 | Andrew Apted | 2016-11-28 21:10:56 +1100

CHANGELOG : minor update.

------------------------------------------------------------------------
8660f3ac9e4e | Andrew Apted | 2016-11-28 20:31:01 +1100

Preferences / key bindings : worked on a "Choose" button which
shows a nice menu of available functions, grouped into categories.

------------------------------------------------------------------------
3651ce28553a | Andrew Apted | 2016-11-28 16:18:03 +1100

Key system : added a "group_name" field to editor_command_t, and
give most commands an apropriate name.  Commands that only apply
to a single editing mode (SEC_Floor etc) are computed from that.

------------------------------------------------------------------------
fa54698cbb5d | Andrew Apted | 2016-11-28 14:59:33 +1100

Preferences / key bindings : the "grab" mode now accepts mouse
buttons (including the mouse-wheel).

------------------------------------------------------------------------
4f2737d63c7b | Andrew Apted | 2016-11-28 14:59:04 +1100

Key system : added M_RawKeyForEvent() and M_CookedKeyForEvent()
utility functions.

------------------------------------------------------------------------
18714fef4f2b | Andrew Apted | 2016-11-28 14:15:15 +1100

Preferences : in the Edit Key dialog, added a "Grab" button which
waits for the next key press.

------------------------------------------------------------------------
3abb13a01228 | Andrew Apted | 2016-11-28 13:48:20 +1100

Preferences : made window slightly taller, and worked on the Key
binding tab to have an "Add" button, renamed "Bind" --> "Re-bind".

------------------------------------------------------------------------
e14a897f2845 | Andrew Apted | 2016-11-28 10:51:43 +1100

Key system : remove menu shortcuts when that key has a binding,
allowing keys previously hard-coded in the menus to be used for
other functions (and preventing user confusion too).

------------------------------------------------------------------------
fb2a8c97332b | Andrew Apted | 2016-11-28 10:24:57 +1100

TODO and CHANGELOG update.

------------------------------------------------------------------------
89afd3fdd697 | Andrew Apted | 2016-11-28 10:18:34 +1100

main() : separated FLTK setup stuff from opening the main window,
load the key bindings before opening the main window, and tweaked
the "init_progress" handling.

------------------------------------------------------------------------
d045f5df8b74 | Andrew Apted | 2016-11-28 00:57:07 +1100

UI : at startup, use Fl::focus() on the canvas widget to allow
keyboard events to be handled, even when the mouse has not
entered the main window yet.

------------------------------------------------------------------------
05a191a8611d | Andrew Apted | 2016-11-27 23:01:46 +1100

PORTS : changed "include boom" --> "include mbf" for most ports.

------------------------------------------------------------------------
88cc5d91d7cc | Andrew Apted | 2016-11-27 22:59:00 +1100

PORTS : added definition for MBF, removed MBF stuff from boom.ugh

------------------------------------------------------------------------
d9925e12a94f | Andrew Apted | 2016-11-27 20:12:41 +1100

Version bump, for support of the HARMONY TC.

------------------------------------------------------------------------
64a073a88f55 | Andrew Apted | 2016-11-27 20:12:12 +1100

Canvas : support "scale" for sprites on the 2D view.

------------------------------------------------------------------------
270d8e78905d | Andrew Apted | 2016-11-27 20:09:33 +1100

Renderer : support thing "scale" values.

------------------------------------------------------------------------
a572c9d5d0f6 | Andrew Apted | 2016-11-27 19:40:41 +1100

UI : support thing "scale" value in the UI_PIC widget.

------------------------------------------------------------------------
c6fb593b0f82 | Andrew Apted | 2016-11-27 19:11:07 +1100

PORTS : enabled "lax_sprites" feature for Boom (and hence every
port which is Boom-compatible), and ZDoom.

------------------------------------------------------------------------
b585669f4f89 | Andrew Apted | 2016-11-27 19:07:51 +1100

GAMES / Harmony : enable the "lax_sprites" feature.

------------------------------------------------------------------------
7d25625f3fab | Andrew Apted | 2016-11-27 19:06:54 +1100

Game defs : support a "lax_sprites" feature which allows finding
sprite graphics outside of the S_START..S_END namespace.

------------------------------------------------------------------------
f93578e37e12 | Andrew Apted | 2016-11-27 18:47:30 +1100

CHANGELOG update.

------------------------------------------------------------------------
618f625957f0 | Andrew Apted | 2016-11-27 18:43:17 +1100

Harmony : added "c" (ceiling) and "l" (lit) flags to things.

------------------------------------------------------------------------
d3257086e681 | Andrew Apted | 2016-11-27 18:33:49 +1100

Harmony : more fixes to thing defs, esp. what sprites are used.

------------------------------------------------------------------------
3b7f689119d9 | Andrew Apted | 2016-11-27 17:20:55 +1100

Harmony : removed thing 2008 -- not used in this game.

------------------------------------------------------------------------
cf37853e398b | Andrew Apted | 2016-11-27 17:17:22 +1100

Harmony : fixed numerous thing definitions, like the "Beastling".

------------------------------------------------------------------------
14b7fac7f4e9 | Andrew Apted | 2016-11-27 14:30:27 +1100

Harmony : fleshed out most of the things, based on the DEHACKED
lump that exists in the harmony wad.

------------------------------------------------------------------------
1a0f0b4456c8 | Andrew Apted | 2016-11-25 22:23:45 +1100

Thing panel : prevent the arrow buttons overlapping.

------------------------------------------------------------------------
160bac6276eb | Andrew Apted | 2016-11-25 21:40:03 +1100

Game def parser : allow "thing" defs to supply a scale value.

------------------------------------------------------------------------
d806faf600fa | Andrew Apted | 2016-11-25 21:27:47 +1100

Harmony : workaround for the COLORMAP being broken.

Color #0 of the palette is pure black, and colormap #0 keeps it
black, but in colormap #1 it becomes bright white and darkens
over subsequent colormaps as though it it were a white color.

------------------------------------------------------------------------
1918d9a5440e | Andrew Apted | 2016-11-25 20:43:48 +1100

Game defs : beginnings of a HARMONY v1.1 definition file.

------------------------------------------------------------------------
c6d5c2f7314e | Andrew Apted | 2016-11-25 19:33:02 +1100

minor tweaks.

------------------------------------------------------------------------
581eaea46c8b | Andrew Apted | 2016-11-25 19:24:04 +1100

Code tidying : ensure functions for all commands have "CMD_" prefix
(except for rendering commands which have "R3D_" prefix).

------------------------------------------------------------------------
fa26728634ce | Andrew Apted | 2016-11-25 19:10:43 +1100

CHANGELOG and TODO update.

------------------------------------------------------------------------
776b3a028fc9 | Andrew Apted | 2016-11-25 18:19:45 +1100

Image code : merged im_arrows.cc --> im_img.c and reformatted.

------------------------------------------------------------------------
1ffa048cc96e | Andrew Apted | 2016-11-25 18:15:00 +1100

Image code : moved IM_CreateDogSprite() --> im_img.cc

------------------------------------------------------------------------
d906c607af43 | Andrew Apted | 2016-11-25 18:14:06 +1100

Tweaked handling of opening the most-recent pwad file.

------------------------------------------------------------------------
f6f15ec579af | Andrew Apted | 2016-11-25 17:13:08 +1100

Fixed the double loading of all resources at startup.

------------------------------------------------------------------------
722a174ef842 | Andrew Apted | 2016-11-25 16:51:35 +1100

GAMES and PORTS : prevent Boom definitions being used in non-Doom
games like Heretic and Strife.

------------------------------------------------------------------------
27631dbee790 | Andrew Apted | 2016-11-25 16:42:09 +1100

Game def parser : properly support variables in "if" directive.

------------------------------------------------------------------------
1ec129533070 | Andrew Apted | 2016-11-25 15:11:10 +1100

Game def parser : store tokens in a non-allocated buffer, which
reduces how much memory is leaked.

------------------------------------------------------------------------
4720f3bc718c | Andrew Apted | 2016-11-25 14:59:21 +1100

Game def parser : pre-set the $MAP_FORMAT variable.

------------------------------------------------------------------------
f76d15c14df4 | Andrew Apted | 2016-11-25 14:44:27 +1100

Game def parser : changed how PURPOSE_GameCheck and PURPOSE_PortCheck
modes work, they now ignore *everything* except their keywords. That
means the "include", "set" and "if"..."endif" directives are NOT
handled in these two modes.

Rationale here is to keep those modes as simple as possible, as the
handling of variables and conditionals was going to be difficult
to implement and potentially confusing.

------------------------------------------------------------------------
4c30824d2658 | Andrew Apted | 2016-11-25 13:23:52 +1100

Game def parser : implemented new "set" command.

------------------------------------------------------------------------
10b9d5854a7e | Andrew Apted | 2016-11-25 12:53:36 +1100

minor rename : dump_command_line_options --> M_PrintCommandLineOptions.

------------------------------------------------------------------------
6097e9f3f4d1 | Andrew Apted | 2016-11-24 23:38:57 +1100

PORTS / ZDoom : only include "boom.ugh" file when map_format is DOOM,
preventing Boom stuff being enabled in HEXEN format maps.

------------------------------------------------------------------------
d52de6689dca | Andrew Apted | 2016-11-24 23:36:23 +1100

Game def parser : support lines of the form "if $MAP_FORMAT is XXX"
where XXX can be DOOM or HEXEN, which allows including or excluding
definitions based on the current map's format.

------------------------------------------------------------------------
c974a41d42fb | Andrew Apted | 2016-11-24 23:21:07 +1100

PORTS / Boom : removed the obsolete "exclude_game" lines.

------------------------------------------------------------------------
25b999d85252 | Andrew Apted | 2016-11-24 22:42:35 +1100

PORTS : treat "vanilla" as a special (fake) port, keeping its
definition file empty (except for some comments), and have some
special checks in the code e.g. can use it for *ANY* game.

------------------------------------------------------------------------
870d183baa60 | Andrew Apted | 2016-11-24 22:08:37 +1100

PORTS : changed "medusa_bug" feature --> "medusa_fixed", and use
that in all the ports which fix the Medusa bug.

------------------------------------------------------------------------
83203bfa4668 | Andrew Apted | 2016-11-24 21:38:50 +1100

Code tidying : removed trailing whitespace in all files.

------------------------------------------------------------------------
1fc634730d2e | Andrew Apted | 2016-11-24 21:35:33 +1100

Code files : yet another rename: e_misc.cc/h --> e_main.cc/h

------------------------------------------------------------------------
39e7e96e73c2 | Andrew Apted | 2016-11-24 21:31:39 +1100

Code tidying : various minor changes (e.g. constructors).

------------------------------------------------------------------------
afae83fc9da9 | Andrew Apted | 2016-11-24 21:07:53 +1100

Code tidying : removed several functions/methods which are unused,
and never likely to be useful.

------------------------------------------------------------------------
95e874113897 | Andrew Apted | 2016-11-24 20:47:00 +1100

Code : fixed some memory alloc/dealloc issues.

------------------------------------------------------------------------
9147391d11fe | Andrew Apted | 2016-11-24 20:45:56 +1100

Selection class : added a constructor for selection_iterator_c,
plus some asserts checking that the iterator is valid.

------------------------------------------------------------------------
fb26f325f250 | Andrew Apted | 2016-11-24 20:08:09 +1100

(part of previous commit : removed the empty editloop.h file)

------------------------------------------------------------------------
fe9122ff16d3 | Andrew Apted | 2016-11-24 20:05:33 +1100

Code files : renamed editloop.cc/h --> m_events.cc/h

------------------------------------------------------------------------
f4d62c61134f | Andrew Apted | 2016-11-24 19:58:57 +1100

Code tidying : moved RedrawMap(), ZoomWholeMap(), GetCurrentObjs(),
UpdateXXX() and Editor_ChangeMode() functions --> e_misc.cc

------------------------------------------------------------------------
6ffd9607cd56 | Andrew Apted | 2016-11-24 19:48:44 +1100

Code tidying : moved Editor_State_t struct, "edit" global, the
Editor_Init() function and few other bits ---> e_misc.cc/h

------------------------------------------------------------------------
49ae44206739 | Andrew Apted | 2016-11-24 19:35:20 +1100

Code files : moved command funcs in editloop.cc --> e_commands.cc

------------------------------------------------------------------------
536dbf8dd97c | Andrew Apted | 2016-11-24 18:50:39 +1100

Code files : renamed x_hover.cc/h --> e_hover.cc/h

------------------------------------------------------------------------
630ce6ea7341 | Andrew Apted | 2016-11-24 18:42:43 +1100

Code files : merged x_loop.cc/h --> e_sector.cc/h

------------------------------------------------------------------------
1b305b71bb5e | Andrew Apted | 2016-11-24 18:30:42 +1100

Code files : renamed levels.cc/h --> e_misc.cc/h

------------------------------------------------------------------------
cbbde3785688 | Andrew Apted | 2016-11-24 18:06:31 +1100

Code tidying : moved AngleBetweenLines() --> e_linedef.cc

------------------------------------------------------------------------
c17708a1c2dd | Andrew Apted | 2016-11-24 16:33:24 +1100

Code files : renamed e_loadsave and e_nodes --> "m_" prefix.

------------------------------------------------------------------------
cd52ab2cb72f | Andrew Apted | 2016-11-24 16:12:14 +1100

Code files : merged x_mirror.cc/h --> e_objects.cc/h

------------------------------------------------------------------------
2e1551b895b2 | Andrew Apted | 2016-11-24 16:06:55 +1100

Code tidying : moved Texture_MatchPattern() --> ui_browser.cc

------------------------------------------------------------------------
844c1981b10b | Andrew Apted | 2016-11-24 16:04:15 +1100

Code files : renamed objects.cc/h --> e_objects.cc/h

------------------------------------------------------------------------
57f120e8d51e | Andrew Apted | 2016-11-24 15:58:42 +1100

Code files : merged e_checks2.cc --> e_checks.cc

------------------------------------------------------------------------
c33e741d9f47 | Andrew Apted | 2016-11-24 15:51:19 +1100

Code files : merged w_flat.* and w_sprite.* --> w_texture.*

------------------------------------------------------------------------
d31af0918532 | Andrew Apted | 2016-11-24 15:41:24 +1100

TODO : minor update.

------------------------------------------------------------------------
62eadae19c34 | Andrew Apted | 2016-11-24 14:51:49 +1100

Ensure the "Level_format" is known for each Main_LoadResources()
call, since it can affect the parsing of the config files.

------------------------------------------------------------------------
766d029b1cf6 | Andrew Apted | 2016-11-24 14:32:32 +1100

BSP : for "Build All Nodes" command, don't reload the current level
afterwards (as there is no need), and fixed order of the initial
checks (i.e. editing a pwad *before* MadeChanges check).

------------------------------------------------------------------------
dfe187d0031f | Andrew Apted | 2016-11-24 13:37:40 +1100

Overhauled handling of textures which are empty strings:
-  on map load, detect this in SIDEDEFS and convert to "-"
-  typing an empty string in LineDef panel converts it to "-"
-  removed the confusing "is_missing_tex()" function

------------------------------------------------------------------------
b41e0fc5ada2 | Andrew Apted | 2016-11-24 13:05:29 +1100

UI : improved layout in "Open Map" dialog, moved PWAD name to the top,
since that is the most important thing when the user wants to open a
new file.  Also simplified the radio buttons into a choice menu.

------------------------------------------------------------------------
262afbe3c76d | Andrew Apted | 2016-11-24 12:21:27 +1100

Check / textures : fixed the unknown texture "FIX" button from
changing the "-" empty texture on uppers and lowers.

------------------------------------------------------------------------
37395213504d | Andrew Apted | 2016-11-23 22:42:19 +1100

CHANGELOG update.

------------------------------------------------------------------------
4daf3140d005 | Andrew Apted | 2016-11-23 22:40:47 +1100

Fixed another case of a wad file not being closes when the user
cancels the parsing of the "__EUREKA" lump.  Also improved the
code in the UI_OpenMap class, made it easier to understand.

------------------------------------------------------------------------
d277b20d0748 | Andrew Apted | 2016-11-23 22:04:45 +1100

Fixed not closing an opened wad when parsing an "__EUREKA" lump,
detecting missing resources, and the user decided to cancel.

------------------------------------------------------------------------
540bdaee5c1f | Andrew Apted | 2016-11-23 18:19:00 +1100

TODO update.

------------------------------------------------------------------------
d660e44c6f08 | Andrew Apted | 2016-11-23 18:17:19 +1100

BSP : actually use the new preference settings, transfer the values
into the nodebuildinto_t structure.

------------------------------------------------------------------------
f5c73ad4a82a | Andrew Apted | 2016-11-23 17:14:48 +1100

Preferences : added config variables for the new "Nodes" settings,
and ensure they are properly reflected in the preferences UI.

------------------------------------------------------------------------
ee95ee205030 | Andrew Apted | 2016-11-23 16:49:21 +1100

Preferences : finalized the layout of the new "Nodes" tab.

[ None of the additional settings do anything yet.... ]

------------------------------------------------------------------------
9f1c729ce086 | Andrew Apted | 2016-11-23 16:27:32 +1100

BSP : moved the "RoundPOW2" function --> lib_util.cc/h

------------------------------------------------------------------------
362d7b84fc2f | Andrew Apted | 2016-11-23 16:26:42 +1100

Preferences : moved the "Keys" tab to the second spot.

------------------------------------------------------------------------
837f6c03d4d2 | Andrew Apted | 2016-11-23 15:22:11 +1100

BSP : removed no-longer-used PrintMsg() function, added a warning
message when the level structure seems broken.

------------------------------------------------------------------------
3cd09c4557e8 | Andrew Apted | 2016-11-23 15:14:28 +1100

BSP : added "total_failed_maps" field to nodebuildinfo_t, also
renamed the warning fields and the warning functions --> Warning()
and MinorWarning().

------------------------------------------------------------------------
1070ce65e912 | Andrew Apted | 2016-11-23 14:56:57 +1100

BSP : define ZDoom format node structures in w_rawdef.h

------------------------------------------------------------------------
bf82f10b349b | Andrew Apted | 2016-11-23 14:31:52 +1100

BSP : removed all the ReportFailedLevels() stuff, instead we just
print a warning for each hard failure (and also when swithcing to
V5 or XNOD format), and a single "FAILED ...." message if the level
had any hard failures.

------------------------------------------------------------------------
941aec503693 | Andrew Apted | 2016-11-23 13:31:12 +1100

BSP : for ZDoom format nodes, we don't need RoundOffBSPTree() or
PutVertices() since the lump contains extra vertices which are
32-bit (16.16 fixed point).

------------------------------------------------------------------------
deca06b2997b | Andrew Apted | 2016-11-22 22:40:22 +1100

BSP : re-implemented MarkHardFailure() and removed MarkSoftFailure(),
MarkV5Switch() and MarkZDSwitch() functions.

------------------------------------------------------------------------
623b2dc27405 | Andrew Apted | 2016-11-22 22:23:23 +1100

BSP : tidied up how BLOCKMAP overflow is handled, and simplified
the message about building the current map.

------------------------------------------------------------------------
dbcda87476b9 | Andrew Apted | 2016-11-22 21:16:09 +1100

BSP : changed the internal PrintVerbose() and PrintMiniWarn()
functions to do nothing.  Removed "quiet" field of nodebuildfunc_t
and renamed "mini_warnings" field --> "warnings".

------------------------------------------------------------------------
03956c46e0e5 | Andrew Apted | 2016-11-22 21:05:07 +1100

Preferences : bit more work on the "Nodes" tab.

------------------------------------------------------------------------
1cd6297f22b4 | Andrew Apted | 2016-11-22 20:38:06 +1100

Preferences : partial work to improve the node-building stuff.
This commit adds a new "Nodes" tab.  It also removes numerous
redundant down_box() calls which Fluid tends to create.

------------------------------------------------------------------------
c11d0b9b3e8e | Andrew Apted | 2016-11-22 20:28:55 +1100

BSP : message about blockmap overflow is now a warning.

------------------------------------------------------------------------
767a570f2c80 | Andrew Apted | 2016-11-22 15:58:33 +1100

For MacOS X, use the fl_mac_set_about() function in FLTK so the
"About" item in the application menu opens our About window.

[ This is untested, as I don't have any MacOS X computers... ]

------------------------------------------------------------------------
bbcf327bb49b | Andrew Apted | 2016-11-21 23:45:34 +1100

UI : disable FLTK's normal keyboard navigation system, since it
often interferes with our user interface, especially the TAB key
used to toggle the 3D view.

------------------------------------------------------------------------
373414f72458 | Andrew Apted | 2016-11-21 23:20:01 +1100

TODO.txt : added list of BSP tasks.

------------------------------------------------------------------------
c27caa135f23 | Andrew Apted | 2016-11-21 23:11:33 +1100

Menu : increased # of remembered recent files (12 --> 24), and
slightly improved their formatting in the menu.

------------------------------------------------------------------------
0031856b4c9f | Andrew Apted | 2016-11-21 22:20:58 +1100

Wad code : comment with idea about truncating the file.

------------------------------------------------------------------------
7557d22f453d | Andrew Apted | 2016-11-21 22:12:59 +1100

BSP : compute a "max_size" when writing the BLOCKMAP.

------------------------------------------------------------------------
d6e4b6410322 | Andrew Apted | 2016-11-21 21:17:46 +1100

BSP : ensure most calls to AddLump() or RecreateLump() supply an
appropriate "max_size" value, to prevent the wad file from growing
excessively big (need to know the size to re-use internal space).

------------------------------------------------------------------------
99febe7fc789 | Andrew Apted | 2016-11-21 19:08:51 +1100

BSP : moved the polyobject-related constants --> w_rawdef.h

------------------------------------------------------------------------
9d4db042f94c | Andrew Apted | 2016-11-21 19:02:28 +1100

BSP : moved raw_xxxx_t structures related to Nodes --> w_rawdef.h,
removed other structures in bsp.h which have equivalents in w_rawdef.h
(like raw_vertex_t), and updated some code for the differences.

------------------------------------------------------------------------
631a2fa07e10 | Andrew Apted | 2016-11-21 18:39:42 +1100

BSP : tidied up the REJECT handling code, and fixed a bug where
Lump_c::Finish() was not being called.

------------------------------------------------------------------------
74498fabe8c7 | Andrew Apted | 2016-11-21 18:38:57 +1100

Fixed a recently introduced bug in SaveLevel().

------------------------------------------------------------------------
f91d9672f912 | Andrew Apted | 2016-11-21 18:10:58 +1100

Version bump, for good progress with the BSP rework (etc).

------------------------------------------------------------------------
24f8b1b3d076 | Andrew Apted | 2016-11-21 17:16:54 +1100

Menu : more use of ExecuteCommand() instead of calling CMD_XXX
functions directly.  Added Main_Quit().  Various code tidying.

------------------------------------------------------------------------
8bdb5fddc35c | Andrew Apted | 2016-11-21 16:43:46 +1100

tweak of message when loading user state for a map.

------------------------------------------------------------------------
e5612bed34f4 | Andrew Apted | 2016-11-21 16:39:25 +1100

Wad code : replaced the FindLumpInLevel() methods with just one,
LevelLookupLump(), which takes a lev_num instead of a lump index.

------------------------------------------------------------------------
259b6ed93879 | Andrew Apted | 2016-11-21 16:20:16 +1100

Wad code : removed the old FindLevel() method, fixed LevelFormat()
method to take a level number instead of a lump index.

------------------------------------------------------------------------
f76a4e30a40d | Andrew Apted | 2016-11-21 16:05:21 +1100

Wad code : use a level number in RemoveLevel() and RemoveGLNodes()
methods, instead of a lump index.

------------------------------------------------------------------------
424acebf7eb8 | Andrew Apted | 2016-11-21 15:57:38 +1100

Wad code : replaced FindFirstLevel() method with LevelFindFirst()
which returns a level number (NOT a lump index).

------------------------------------------------------------------------
7c0fd6629d18 | Andrew Apted | 2016-11-21 15:42:25 +1100

Wad code : renamed several methods related to levels:
   NumLevels --> LevelCount
   GetLevel --> LevelHeader
   LastLevelLump --> LevelLastLump
   FindLevelRaw --> LevelFind
   FindLevelByNumber --> LevelFindByNumber

Also LevelFindByNumber() now returns a level number (NOT a lump index).

------------------------------------------------------------------------
45feb6ef9c3f | Andrew Apted | 2016-11-21 14:29:07 +1100

Main menu : use ExecuteCommand() for the EDIT menu stuff, since
calling the CMD_XXX functions directly is not really kosher,
especially when the command looks at Exec_Param[].

------------------------------------------------------------------------
e3831d36a23a | Andrew Apted | 2016-11-21 14:21:32 +1100

Added "Undo" and "Redo" as bindable commands.

------------------------------------------------------------------------
1374e451957a | Andrew Apted | 2016-11-21 14:09:17 +1100

CHANGELOG : a few clarifications.

------------------------------------------------------------------------
00e5ed1cc135 | Andrew Apted | 2016-11-21 14:08:20 +1100

Wad code : fixed stupid bug with AddLevel "lev_idx" parameter.

------------------------------------------------------------------------
560341e39487 | Andrew Apted | 2016-11-21 13:28:25 +1100

minor tweak to some log messages.

------------------------------------------------------------------------
da6684cfa299 | Andrew Apted | 2016-11-21 13:21:43 +1100

Load/save code : removed "save_wad" variable, SaveLevel() always
saves into the current "edit_wad" now.

------------------------------------------------------------------------
9fa8f99cbe2f | Andrew Apted | 2016-11-21 12:57:52 +1100

Improved drag behavior: if the object is NOT in the selection, then
only drag that single object (instead of adding it to the selection
and dragging the whole selection).

Hence removed the hacky "did_a_move" stuff, where doing a move and
then selecting an object would clear the rest of the selection,
since it only existed to make dragging individual objects easier.

------------------------------------------------------------------------
868d78d11ab5 | Andrew Apted | 2016-11-21 01:06:22 +1100

BSP : fixed some bugs related to computing the GL checksum.

------------------------------------------------------------------------
954d8d7636ed | Andrew Apted | 2016-11-21 00:33:41 +1100

BSP : added missing BeginWrite/EndWrite calls to SaveLevel().

------------------------------------------------------------------------
83f7d7c9636e | Andrew Apted | 2016-11-21 00:28:50 +1100

BSP : minor change to prevent a compiler warning.

------------------------------------------------------------------------
a2c932cb10cd | Andrew Apted | 2016-11-21 00:10:35 +1100

BSP : implemented BuildNodesAfterSave(), and call it just after
saving the map in SaveLevel().

------------------------------------------------------------------------
9ad5330d2cd7 | Andrew Apted | 2016-11-21 00:07:44 +1100

Wad code : the AddLevel() method can now return the lev_idx, and
prevent it from sorting the "levels" vector since that would
invalidate the returned lev_idx.

------------------------------------------------------------------------
0b8a14259934 | Andrew Apted | 2016-11-20 18:02:54 +1100

BSP : woah, FINALLY I SEE THE LIGHT!

All the rubbish which CMD_BuildNodes() used to do, i.e. creating a
new file, building nodes, deleting the old file, then renaming the
new file to the old file -- that becomes totally unnecessary when
you are simply building the nodes *inside* the current edit_wad.

Hence updated the code accordingly.

------------------------------------------------------------------------
831b1980a561 | Andrew Apted | 2016-11-20 17:51:58 +1100

BSP : more code jiggery pokery in e_nodes.cc

------------------------------------------------------------------------
ef5012c5a82b | Andrew Apted | 2016-11-20 17:26:27 +1100

BSP : removed "input_file" and "output_file" from nodebuildinfo_t,
and factored out some code --> PrepareInfo() function.

------------------------------------------------------------------------
a4f53f69a6d0 | Andrew Apted | 2016-11-20 17:25:43 +1100

BSP : added back an internal SetErrorMsg() function.

------------------------------------------------------------------------
7782c3f448ab | Andrew Apted | 2016-11-20 16:58:34 +1100

BSP : moved the UI_NodeDialog class --> e_nodes.cc

------------------------------------------------------------------------
dc5343fdbcae | Andrew Apted | 2016-11-20 16:52:46 +1100

BSP : minor code renaming.

------------------------------------------------------------------------
495e4667f30e | Andrew Apted | 2016-11-20 16:41:00 +1100

BSP : removed a few unused util functions (UtilStr* UtilFormat).

------------------------------------------------------------------------
9a5c30ab8e9e | Andrew Apted | 2016-11-20 16:34:54 +1100

BSP : code tidying, removed GCCATTR() attributes which were more
cluttery than useful.

------------------------------------------------------------------------
c5e31b62923b | Andrew Apted | 2016-11-20 16:30:58 +1100

BSP : improved API in bsp.h, moved the parts needed by e_nodes.cc
out of the namespace, and everything inside the namespace is just
the internal structures and functions.

------------------------------------------------------------------------
245948077836 | Andrew Apted | 2016-11-20 16:09:10 +1100

TODO update.

------------------------------------------------------------------------
01cbfd2967e9 | Andrew Apted | 2016-11-20 14:08:26 +1100

Makefile.xming : added libfltk_jpeg.a and updated for FLTK 1.3.4

------------------------------------------------------------------------
a018d85d6f40 | Andrew Apted | 2016-11-20 14:07:37 +1100

BSP : removed the "CreateDummyNode" bogus rubbish.

------------------------------------------------------------------------
8ecc277c709c | Andrew Apted | 2016-11-20 14:02:51 +1100

Deleted two dummy files in obj_linux/ and obj_win32/

------------------------------------------------------------------------
657203452cd4 | Andrew Apted | 2016-11-20 12:48:34 +1100

BSP : removed all GB_DisplayXXX() calls, and logic for calculating
fine-grained progress.  Progress is now coarse, a step for each map
in the wad.

------------------------------------------------------------------------
df4a6e8bcd5f | Andrew Apted | 2016-11-20 12:21:03 +1100

BSP : fixed a misleading comment about what "fast" mode does.

------------------------------------------------------------------------
37baf69ba944 | Andrew Apted | 2016-11-20 12:17:13 +1100

BSP : removed all calls to GB_DisplayTicker().

------------------------------------------------------------------------
e01033dc1b22 | Andrew Apted | 2016-11-20 12:10:11 +1100

BSP : tidied up usage of BUILD_XXX result codes.

------------------------------------------------------------------------
5a4d1f2a1faa | Andrew Apted | 2016-11-20 12:05:02 +1100

BSP : code tidying in e_nodes.cc, merged CheckInfo() into parent.

------------------------------------------------------------------------
01c7c6a1d6c6 | Andrew Apted | 2016-11-20 11:54:38 +1100

BSP : removed "block_limit" from nodebuildinfo_t.

------------------------------------------------------------------------
4f689280f998 | Andrew Apted | 2016-11-20 01:16:37 +1100

Pack scripts : updated for removal of glbsp_src/

------------------------------------------------------------------------
2a0e39287936 | Andrew Apted | 2016-11-20 01:13:57 +1100

CHANGELOG update.

------------------------------------------------------------------------
0522edf40a49 | Andrew Apted | 2016-11-20 00:59:35 +1100

BSP : removed the old code, i.e. everything under glbsp_src/

------------------------------------------------------------------------
5d226342ffc7 | Andrew Apted | 2016-11-20 00:57:28 +1100

BSP : removed unneeded function "CountWallTips" (it was only used
by the code for detecting the one-sided window trick).

------------------------------------------------------------------------
216934ca9a58 | Andrew Apted | 2016-11-20 00:56:20 +1100

BSP : removed unused variable (cpu_big_endian).

------------------------------------------------------------------------
78b905b297ec | Andrew Apted | 2016-11-20 00:53:26 +1100

Makefile.xming : updated for the BSP rework.

------------------------------------------------------------------------
8581557793bc | Andrew Apted | 2016-11-20 00:43:51 +1100

Merge branch 'bsp_rework'

------------------------------------------------------------------------
0c8d095cd01a | Andrew Apted | 2016-11-20 00:35:36 +1100

BSP : removed unused function "UtilFileExists".

------------------------------------------------------------------------
63f7c81a23ea | Andrew Apted | 2016-11-20 00:34:12 +1100

BSP : more minor code tidying (comments before functions).

------------------------------------------------------------------------
24e4d060b66a | Andrew Apted | 2016-11-20 00:27:17 +1100

BSP : minor code tidying (whitespace in for loops).

------------------------------------------------------------------------
81e0978c1d96 | Andrew Apted | 2016-11-20 00:14:16 +1100

TODO : yet another update.

------------------------------------------------------------------------
09d1182286f8 | Andrew Apted | 2016-11-20 00:08:25 +1100

3D View : for highlighting, disabled check on the editing mode,
since having to switch modes to adjust a wall (etc) is annoying.

------------------------------------------------------------------------
32ddfcf7172a | Andrew Apted | 2016-11-19 23:54:27 +1100

LineDef panel : re-instated the "Gen" button, used to open the
generalized line browser (for BOOM compatible ports).

[ this is a partial revert of commit 833a5654cff6 ]

------------------------------------------------------------------------
7be432cfdd02 | Andrew Apted | 2016-11-19 23:32:15 +1100

Created a proper dialog for the "JumpToObject" command, one which
does not allow the user to enter an invalid number.

------------------------------------------------------------------------
bdb6b5d44429 | Andrew Apted | 2016-11-19 20:25:20 +1100

CHANGELOG and TODO update.

------------------------------------------------------------------------
04c8769810db | Andrew Apted | 2016-11-19 19:30:48 +1100

Bindings : extra ACT_Transform binds for rotate/stretch/skew.

------------------------------------------------------------------------
30c4cbd11869 | Andrew Apted | 2016-11-19 19:24:14 +1100

ACT_Transform : got the "skew" mode working.

------------------------------------------------------------------------
f6d679612f32 | Andrew Apted | 2016-11-19 19:23:24 +1100

minor debug tweak.

------------------------------------------------------------------------
a8926e157f4c | Andrew Apted | 2016-11-19 17:35:02 +1100

Code tidying : removed "CMD_" prefix from three more functions that
are not true commands: MoveObjects(), OpenFileMap(), AdjustLight().

------------------------------------------------------------------------
2f2351f1c71f | Andrew Apted | 2016-11-19 17:20:50 +1100

Code tidying : changed prefix on "CMD_Copy" and "CMD_Paste" functions,
since they are NOT actual key-system commands.

------------------------------------------------------------------------
17d682deced9 | Andrew Apted | 2016-11-19 17:05:50 +1100

ACT_Transform : support four keywords: "scale", "stretch", "rotate"
and "rotscale".

------------------------------------------------------------------------
6e0d72655db1 | Andrew Apted | 2016-11-19 16:32:43 +1100

Added "Clipboard_Cut", "Clipboard_Copy", "Clipboard_Paste" commands
which are equivalent to the EDIT menu functions.

------------------------------------------------------------------------
5c560d73a609 | Andrew Apted | 2016-11-19 14:58:58 +1100

Renamed "ACT_Scale" command --> "ACT_Transform", and began work to
support keywords (like "scale" and "rotate") as the parameter.

------------------------------------------------------------------------
53b659536ca9 | Andrew Apted | 2016-11-19 14:36:11 +1100

Code : renamed "scale_param_t" --> "transform_t", and renamed some
related methods/functions from "ScaleXyz" --> "TransformXyz".

------------------------------------------------------------------------
eebfaa4cf159 | Andrew Apted | 2016-11-19 13:27:00 +1100

Code tidying : removed "CMD_" prefix from functions in x_mirror.cc
which did NOT actually implement a key system command.

------------------------------------------------------------------------
c325535271cb | Andrew Apted | 2016-11-19 13:21:39 +1100

scale_param_t structure now supports skew transforms.

------------------------------------------------------------------------
8c5a02489068 | Andrew Apted | 2016-11-19 12:52:02 +1100

Bindings : added MOUSE2 bind for adjusting offsets in the 3D view
(i.e. restore the previous behavior).

------------------------------------------------------------------------
b0051d6136e9 | Andrew Apted | 2016-11-19 12:36:29 +1100

CHANGELOG : updated, and grouped all bug fixes together.

------------------------------------------------------------------------
68c1e37a8ab2 | Andrew Apted | 2016-11-19 12:31:09 +1100

3D View : fixed rendering of lowers with "LOWER UNPEG" flag which
have a sky ceiling on the front and back sectors.  The behaviour
now matches the the original DOOM renderer.

------------------------------------------------------------------------
860a839fe19d | Andrew Apted | 2016-11-19 00:12:11 +1100

Key system : implemented basic "Select" command, it just toggles the
highlighted object in the selection (an experiment mainly....)

------------------------------------------------------------------------
b055d3fa4c3a | Andrew Apted | 2016-11-18 23:41:53 +1100

Key system : implemented "ACT_Drag" command, and temporarily
disabled its function on the left mouse button.

------------------------------------------------------------------------
bc16f8d169ce | Andrew Apted | 2016-11-18 23:02:48 +1100

Bindings : bind "ACT_Scale" onto MOUSE2 (restore prev behavior).

------------------------------------------------------------------------
982551b14d3b | Andrew Apted | 2016-11-18 22:51:10 +1100

Bindings : added bindings for WHEEL_UP and WHEEL_DOWN which zoom
the 2D map view (i.e. restoring the default behavior).

------------------------------------------------------------------------
da97298afd2a | Andrew Apted | 2016-11-18 22:49:59 +1100

Removed the "mouse_wheel_scrolls_map" config variable, since the
user now has full control over the mousewheel via bindings.cfg

------------------------------------------------------------------------
51011d5fda8c | Andrew Apted | 2016-11-18 22:45:40 +1100

Key system : use key handler for mousewheel events on the 2D canvas,
and implemented a "WHEEL_Scroll" command which can scroll the map
based on the mousewheel deltas.

------------------------------------------------------------------------
c40e8bcccbf5 | Andrew Apted | 2016-11-18 22:27:25 +1100

Key system : replaced hard-coded mousewheel handling in 3D View
with new "3D_WHEEL_Move" command.  The parameter specifies what
speed to move.

------------------------------------------------------------------------
8a5a97ddbdc4 | Andrew Apted | 2016-11-18 21:57:01 +1100

Key system : re-implemented CMD_MetaKey to not use the action system,
as I feel it is more low-level than that.

------------------------------------------------------------------------
b183ec28ec2b | Andrew Apted | 2016-11-18 20:23:18 +1100

Key system : updated bindings.cfg to use new name "GRID_Bump", and
added some backwards-compatibility into the parsing code.

------------------------------------------------------------------------
bef2375c69ae | Andrew Apted | 2016-11-18 20:15:59 +1100

Key system : implemented "GRID_Zoom" which sets the zoom level to a
specific value (well, the nearest available one).

Hence removed the "digits_set_zoom" config variable, as the user now
has full control via the key binding system.

------------------------------------------------------------------------
55ddc9da693c | Andrew Apted | 2016-11-18 19:55:58 +1100

Key system : fixed info-bar widget for new "GRID_Set" command.

------------------------------------------------------------------------
e8ac69c2f64d | Andrew Apted | 2016-11-18 19:51:07 +1100

Key system : don't hard-code the digit keys, use new "GRID_Set"
command to bind the digits.

------------------------------------------------------------------------
fd0115839672 | Andrew Apted | 2016-11-18 18:35:22 +1100

TODO : minor update.

------------------------------------------------------------------------
30a99d9f5cd3 | Andrew Apted | 2016-11-18 18:31:49 +1100

Key system : implemented "ACT_Scale" command.

------------------------------------------------------------------------
11967ca7eed0 | Andrew Apted | 2016-11-18 18:21:42 +1100

Key system : experiment with new "3D_ACT_AdjustOfs" command.

------------------------------------------------------------------------
99487185913e | Andrew Apted | 2016-11-18 17:09:58 +1100

Key system : have a "current action key", and set it / test it for
release independently of the navigation keys.

------------------------------------------------------------------------
41d17ed0255e | Andrew Apted | 2016-11-18 16:42:44 +1100

Key system : experiment with ability to bind the selection-box
action to a key, via new "ACT_Selbox_Mouse" command.

------------------------------------------------------------------------
91221740b30d | Andrew Apted | 2016-11-18 15:37:25 +1100

Keys : pass mouse button #3 through the key handling system (instead
of using the hard-coded logic), and implemented a "NAV_Scroll_Mouse"
command which performs its original function.

------------------------------------------------------------------------
b079d10ad461 | Andrew Apted | 2016-11-18 14:39:37 +1100

Nav keys : separate 3D movement commands into two opposites, such
as "3D_NAV_Forward" and "3D_NAV_Back", which works better when the
user presses both at the same time.

------------------------------------------------------------------------
a2992c642937 | Andrew Apted | 2016-11-18 14:06:22 +1100

Keys : fixed parsing of uppercase letters in bindings.cfg

------------------------------------------------------------------------
7757fd4772bb | Andrew Apted | 2016-11-18 14:02:08 +1100

Nav keys : finished smooth scrolling of 2D view (NAV_Scroll command).

------------------------------------------------------------------------
53e4e4cb538c | Andrew Apted | 2016-11-18 12:37:28 +1100

Code tidying : moved more code around in editloop.cc

------------------------------------------------------------------------
28179c6d9182 | Andrew Apted | 2016-11-18 12:24:56 +1100

Nav keys : began work on a "NAV_Scroll" command for the 2D view...

------------------------------------------------------------------------
a388825f8863 | Andrew Apted | 2016-11-18 11:55:14 +1100

Nav Keys : fixed 3D_NAV_Up command to turn off gravity (or produce
an error message when the locked-gravity setting is on).

------------------------------------------------------------------------
dfcab69f4e1b | Andrew Apted | 2016-11-18 11:25:39 +1100

Bindings : changed all 3D movement keys (again), use the navigation
commands (3D_NAV_Forward, 3D_NAV_Turn, etc....)

------------------------------------------------------------------------
ac88cb3a2b72 | Andrew Apted | 2016-11-18 11:24:36 +1100

Nav keys : fixed wrong turn speed in R3D_NAV_Turn().

------------------------------------------------------------------------
7c9a0edb3c32 | Andrew Apted | 2016-11-18 11:20:41 +1100

Nav keys : finished implementing the new R3D_NAV_xxx() functions.

------------------------------------------------------------------------
40b33467fef9 | Andrew Apted | 2016-11-18 00:47:24 +1100

Nav keys : moved code computing the time difference --> editloop.cc
(now called Nav_TimeDiff).

------------------------------------------------------------------------
8e852c159daa | Andrew Apted | 2016-11-18 00:37:28 +1100

Nav keys : began work on new "3D_NAV_Forward", "3D_Nav_Turn" (etc)
commands which will use the new navigation system.

------------------------------------------------------------------------
b384d67825cd | Andrew Apted | 2016-11-18 00:04:24 +1100

Nav keys : finished Nav_UpdateKeys() with logic to check whether
the key (or mouse button) is still pressed or not.

------------------------------------------------------------------------
602bee8d4a6b | Andrew Apted | 2016-11-17 23:50:10 +1100

Keys : FLTK only supports FL_Button+1 .. FL_Button+8, so fixed the
is_mouse_button() function accordingly.

------------------------------------------------------------------------
8eb48aec053d | Andrew Apted | 2016-11-17 23:43:12 +1100

Keys : fixed is_mouse_button() to ignore modifiers.

------------------------------------------------------------------------
cedb61defca4 | Andrew Apted | 2016-11-17 23:41:50 +1100

Keys : added is_mouse_button() function.

------------------------------------------------------------------------
560d5c79e7ae | Andrew Apted | 2016-11-17 23:32:45 +1100

Code : removed a very out-of-date bit of backwards-compatibility.

------------------------------------------------------------------------
d9854c3a8dfa | Andrew Apted | 2016-11-17 23:18:45 +1100

Bindings : fixed default bindings for shifted symbols, e.g. "<" is
now represented as "SHIFT-," etc...

------------------------------------------------------------------------
a3b2baf86010 | Andrew Apted | 2016-11-17 22:54:56 +1100

Keys : use "CTRL" for the shown modifier name in Linux and Windows,
and keep the existing "CMD" name in MacOS X.  The parsing code for
bindings.cfg will accept both forms.

------------------------------------------------------------------------
627c6da7ab05 | Andrew Apted | 2016-11-17 22:25:11 +1100

Key codes are now always a physical key + a modifier (or none).
This means that uppercase letters are represented as the lowercase
letter + MOD_SHIFT.

Compatibility (like parsing and saving the bindings.cfg) has been
kept, and uppercase letters are still shown in the KEYS preferences
panel.  But this change breaks compatibility with shifted symbols,
in particular: '<', '>', '?', '|'.

------------------------------------------------------------------------
78d8dbfcb0fe | Andrew Apted | 2016-11-17 20:05:46 +1100

Nav keys : bit more work on new system, fleshed out most of the
new Nav_XXX() functions....

------------------------------------------------------------------------
94ca79549a3f | Andrew Apted | 2016-11-17 16:08:35 +1100

Began work on a "navigation" system, to allow multiple navigation
functions to be active at the same time.

------------------------------------------------------------------------
fe5e36e6654f | Andrew Apted | 2016-11-17 15:47:31 +1100

Code tidying : moved the "CMD_xxx" and "BR_xxx" functions to be
grouped together in editloop.cc

------------------------------------------------------------------------
6f5b96e81231 | Andrew Apted | 2016-11-17 13:34:06 +1100

Canvas : optimized the sprite drawing by collecting batches of solid
pixels, and by clipping sprites to the drawing area.

------------------------------------------------------------------------
bcad60a42182 | Andrew Apted | 2016-11-17 11:52:53 +1100

3D View : support a "/circle" flag to 3D_Turn command, which causes
the camera to circle strafe.

------------------------------------------------------------------------
f34d75516380 | Andrew Apted | 2016-11-17 11:42:32 +1100

3D View : reworked navigation vars to use fwd/right/up instead of
axis-aligned deltas.

------------------------------------------------------------------------
1f6b558dacdf | Andrew Apted | 2016-11-17 00:01:33 +1100

TODO.txt : updated, moved a few entries to "NOT-TODO" section.

------------------------------------------------------------------------
30422cddae88 | Andrew Apted | 2016-11-16 23:14:07 +1100

3D View : better logic for finding the ground height, check several
points on the player's bounding box and use the maximum floor.

------------------------------------------------------------------------
6dbbfbb7634f | Andrew Apted | 2016-11-16 22:50:55 +1100

Bindings : updated all 3D movement bindings for smooth movement.

------------------------------------------------------------------------
b5bf15804338 | Andrew Apted | 2016-11-16 22:40:58 +1100

Canvas : preliminary code for drawing sprites on the 2D canvas
(it is very inefficient so far, but working).

------------------------------------------------------------------------
c1dde5589ca3 | Andrew Apted | 2016-11-16 21:32:52 +1100

3D View : support "/smooth" flag for all the 3D movement and turning
commands, enabling the new smooth navigation logic.

------------------------------------------------------------------------
e3f4386042d6 | Andrew Apted | 2016-11-16 21:01:49 +1100

Preferences : for key bindings, show "3D view" instead of "render"
for the KCTX_Render context, that is more user-focused language.

------------------------------------------------------------------------
11060bf981f0 | Andrew Apted | 2016-11-16 19:55:05 +1100

3D Mode : more work on smooth navigation, getting the Forward/Backward
commands working.

------------------------------------------------------------------------
a041733ecd42 | Andrew Apted | 2016-11-16 19:28:35 +1100

3D Mode : beginnings of smoother navigation, when a navigation is
active (e.g. holding down a key) then call Render3D_Navigate() in
a tight loop.

------------------------------------------------------------------------
bf3ed77d2185 | Andrew Apted | 2016-11-16 18:16:35 +1100

3D Mode : use float for 'z' view coordinate (instead of int).

------------------------------------------------------------------------
6c8455833e91 | Andrew Apted | 2016-11-16 15:27:05 +1100

3D Mode : only highlight things when edit mode is Things.

------------------------------------------------------------------------
a7f1cfa683fb | Andrew Apted | 2016-11-16 15:02:20 +1100

3D Mode : implemented ability to highlight things.

------------------------------------------------------------------------
15a37ed0d34d | Andrew Apted | 2016-11-16 14:42:40 +1100

3D Mode : fixed the highlight position being vertically out by 15
screen pixels or so.

------------------------------------------------------------------------
e0402c40d5a7 | Andrew Apted | 2016-11-16 14:22:30 +1100

3D Mode : draw things with unknown type as a question mark.

------------------------------------------------------------------------
185dd8053648 | Andrew Apted | 2016-11-16 13:50:35 +1100

3D Mode : implemented highlighting sectors (floors or ceilings).

------------------------------------------------------------------------
e62d84fe7490 | Andrew Apted | 2016-11-15 22:35:35 +1100

3D Mode : improved the query() code and determine the sector.

------------------------------------------------------------------------
b26f4127f16b | Andrew Apted | 2016-11-15 22:09:59 +1100

3D Mode : support "thick" RenderLines.

------------------------------------------------------------------------
ca1126cff69a | Andrew Apted | 2016-11-15 21:37:16 +1100

Export Map : when target wad already specifies iwad/port/resources
(via the __EUREKA lump), then keep them, i.e. don't clobber those
settings with the current ones.

------------------------------------------------------------------------
07afe08e46b6 | Andrew Apted | 2016-11-15 21:16:45 +1100

Undo / redo : always update the panel afterwards, fixing the bug
where textures in the LineDef panel would not update.

------------------------------------------------------------------------
00c4313ed05a | Andrew Apted | 2016-11-15 20:55:44 +1100

Defaults panel : update texture pics dynamically (as we type).

------------------------------------------------------------------------
2381749c379c | Andrew Apted | 2016-11-15 20:50:38 +1100

Sector and LineDef panels : texture names dynamically update the
picture (i.e. as we type).

------------------------------------------------------------------------
2412ed0bc78f | Andrew Apted | 2016-11-15 20:01:35 +1100

CMD_Delete : possibly catch more unused sidedefs when deleting
vertices and linedefs.

------------------------------------------------------------------------
4d6403cc2196 | Andrew Apted | 2016-11-15 19:44:24 +1100

Removed "PruneUnused" from EDIT menu, and as a binding on 'p' key.

Rationale is that unused sidedefs and sectors should be automatially
pruned, since there is no way for a user to ever view or edit them.
Also, the map checking functions can detect and remove unused stuff.

------------------------------------------------------------------------
f9f368bb785b | Andrew Apted | 2016-11-15 19:40:09 +1100

Began work on a UI_PicName widget, and removed the TexFromWidget()
and FlatFromWidget() methods in favor of using NormalizeTex().

------------------------------------------------------------------------
157f1fd277db | Andrew Apted | 2016-11-15 19:37:14 +1100

Added global NormalizeTex() utility function.

------------------------------------------------------------------------
8d9e05aa2c35 | Andrew Apted | 2016-11-14 23:30:10 +1100

Find/Replace : modified the Browser to use a sub-class of Fl_Button
which does not grab the keyboard focus when clicked.

That fixes an issue with detecting which input box was last active,
which relies on checking which widget has the keyboard focus.

------------------------------------------------------------------------
5f87a2df50f0 | Andrew Apted | 2016-11-14 23:11:52 +1100

minor comment fix.

------------------------------------------------------------------------
c7204abde1d7 | Andrew Apted | 2016-11-14 22:45:34 +1100

TODO : added a wishlist item.

------------------------------------------------------------------------
e85b6c998eff | Andrew Apted | 2016-11-14 22:18:39 +1100

UI_Pic widget : for GetTex() and GetFlat() methods, try an uppercase
version of the texture name when the normal lookup fails.  Mainly
useful for when user is typing a name into an input box.

------------------------------------------------------------------------
83f1b50ddda6 | Andrew Apted | 2016-11-14 21:41:08 +1100

The "Move/Scale/Rotate Objects" commands in the Edit menu can now
be bound to keys.

------------------------------------------------------------------------
5797ff147c27 | Andrew Apted | 2016-11-14 19:40:26 +1100

Fixed annoying problem where lines could not be split close to an
end point, especially when the linedef was long.

------------------------------------------------------------------------
d9bc69202f43 | Andrew Apted | 2016-11-14 19:32:24 +1100

Canvas : for about-to-split lines, show lengths of both pieces.

------------------------------------------------------------------------
42d189232615 | Andrew Apted | 2016-11-14 19:00:22 +1100

BSP : proper insertion point for CreateLevelLump(), CreateGLMarker().

------------------------------------------------------------------------
07e5ef410cb3 | Andrew Apted | 2016-11-14 18:50:42 +1100

BSP : removed some obsolete fields of nodebuildinfo_t, such as:
"load_all", "no_progress", "same_filenames", "missing_output".

------------------------------------------------------------------------
a4a6f2b78579 | Andrew Apted | 2016-11-14 18:46:57 +1100

BSP : moved CheckInfo() function --> e_nodes.cc

------------------------------------------------------------------------
2998e4a816a3 | Andrew Apted | 2016-11-14 18:40:01 +1100

BSP : added an Fl::check() after building each level.

------------------------------------------------------------------------
24e23615aea9 | Andrew Apted | 2016-11-14 18:26:06 +1100

BSP : ensure that all necessary level lumps (NODES, BLOCKMAP, etc)
are present before saving the level data, adding an empty place-holder
for any that are missing.

------------------------------------------------------------------------
803aa34bc0b0 | Andrew Apted | 2016-11-14 18:17:05 +1100

Wad code : added FindLumpInLevel_Raw() method.

------------------------------------------------------------------------
e0893b57485b | Andrew Apted | 2016-11-14 18:11:27 +1100

Wad code : fixed misleading parameter in FindLumpInLevel().

------------------------------------------------------------------------
a6fc046a8dab | Andrew Apted | 2016-11-14 18:04:04 +1100

Wad code : implemented new RemoveGLNodes() method.

------------------------------------------------------------------------
4624022667fe | Andrew Apted | 2016-11-14 16:53:29 +1100

TODO tweak.

------------------------------------------------------------------------
1191834569dc | Andrew Apted | 2016-11-14 16:08:21 +1100

CHANGELOG and TODO update.

------------------------------------------------------------------------
5528622359f4 | Andrew Apted | 2016-11-14 16:06:29 +1100

Texture loader : support TGA textures in TX_START/END.

------------------------------------------------------------------------
cdbad1d21487 | Andrew Apted | 2016-11-14 15:58:38 +1100

Texture loader : fixed bug in TGA (Targa) format detection.

------------------------------------------------------------------------
cbf7ba5f3ab6 | Andrew Apted | 2016-11-14 15:35:25 +1100

Texture loader : support PNG and JPEG textures in TX_START/END.

------------------------------------------------------------------------
f4dfeb68891b | Andrew Apted | 2016-11-14 15:20:59 +1100

BSP : removed the "bsp_wad.cc/h" code files, no longer needed.

------------------------------------------------------------------------
de7c2ff16dce | Andrew Apted | 2016-11-14 15:15:24 +1100

File / Test Map : bit more work on this feature, e.g. show the
result code in the status area.

------------------------------------------------------------------------
0f8ec8fe078d | Andrew Apted | 2016-11-13 23:58:35 +1100

TODO.txt : updated entry for Test Map command...

------------------------------------------------------------------------
b2c9c1fd98e8 | Andrew Apted | 2016-11-13 20:17:31 +1100

BSP : fixed CalcGLChecksum() to use the Lump_c methods.

------------------------------------------------------------------------
595677ea5697 | Andrew Apted | 2016-11-13 20:05:45 +1100

BSP : updated level loading code to use lump->Length(), lump->Seek()
and lump->Read() functions.

------------------------------------------------------------------------
e367ee321f20 | Andrew Apted | 2016-11-13 19:52:10 +1100

BSP : replaced AppendLevelLump() with lump->Write(), and added a
FindLevelLump() utility function.

------------------------------------------------------------------------
dcd179915875 | Andrew Apted | 2016-11-13 19:50:53 +1100

Wad code : added const to Lump_c::Write "data" parameter.

------------------------------------------------------------------------
08ff3627defe | Andrew Apted | 2016-11-13 19:18:38 +1100

BSP : worked on new CreateLevelLump() implementation, updated some
code to use "Lump_c" instead of "lump_t", incorporated LIMIT_XXX
values and some prototypes from bsp_wad.h, and removed "bsp_wad.h"
from the files #included.  Everything is QUITE BORKED now.....

------------------------------------------------------------------------
529cbea6496b | Andrew Apted | 2016-11-13 18:36:31 +1100

BSP: more work on code to create/update the GL marker lump, using
the Eureka wad API to make it and write into it.

------------------------------------------------------------------------
082bf9b06622 | Andrew Apted | 2016-11-13 17:45:28 +1100

BSP : tidied up handling of V5 keywords for the GL marker lump.

------------------------------------------------------------------------
02e04ad14943 | Andrew Apted | 2016-11-13 16:56:27 +1100

BSP : here is the commit which breaks everything!

- moved the logic for iterating over a whole wad --> e_nodes.cc.
- removed bsp_wad.o from OBJS in the Makefile.
- moved the ZLibXXX functions from bsp_wad --> bsp_level.
- also moved the problem marking/reporting functions.
- also moved the CreateGLMarker() and AddGLTextLine() functions.
- added BuildNodesForLevel() to the API, pass "lev_idx" to it.
- pass "lev_idx" to the LoadLevel() and SaveLevel() functions.
- replaced UtilCheckExtension() with the Eureka equivalent.

------------------------------------------------------------------------
d5ed4c6377b4 | Andrew Apted | 2016-11-13 15:15:54 +1100

Wad code : allow FindLumpInLevel() to find GL-Node lumps.

------------------------------------------------------------------------
cb306203a64f | Andrew Apted | 2016-11-13 15:07:44 +1100

Wad code : added LastLevelLump() method.

------------------------------------------------------------------------
3edd17e13d42 | Andrew Apted | 2016-11-13 14:58:42 +1100

Wad code : added RecreateLump() method which allows an existing
lump to be created from scratch, discarding the old contents.

------------------------------------------------------------------------
c63601010557 | Andrew Apted | 2016-11-13 14:47:37 +1100

BSP : minor commenting.

------------------------------------------------------------------------
41dceb60dd54 | Andrew Apted | 2016-11-13 14:43:23 +1100

BSP : added three fields to nodebuildinfo_t: "gl_nodes", "do_blockmap"
and "do_reject", which default to TRUE.

When "gl_nodes" is FALSE, then GL-Nodes are not created.

When "do_blockmap" or "do_reject" is FALSE, the corresponding lump
is still created, but left empty (zero sized).  Source ports will
generally detect the empty size and handle it properly.

------------------------------------------------------------------------
8dd8bc5b4c83 | Andrew Apted | 2016-11-13 14:18:29 +1100

BSP : *always* build the normal nodes.

------------------------------------------------------------------------
5f03be680848 | Andrew Apted | 2016-11-13 14:03:10 +1100

BSP : allow empty lumps (VERTEXES, LINEDEFS, SECTORS etc) when
loading the level.

------------------------------------------------------------------------
1f0f639a66c9 | Andrew Apted | 2016-11-13 13:57:30 +1100

BSP : comment tweaks.

------------------------------------------------------------------------
4843e1265f39 | Andrew Apted | 2016-11-13 13:53:33 +1100

BSP : rename "duplicate" vertices --> "overlapping" vertices.

------------------------------------------------------------------------
4b2ad71f2255 | Andrew Apted | 2016-11-13 13:50:00 +1100

BSP : skip zero-length lines when creating wall-tips.

------------------------------------------------------------------------
7c764524e3fd | Andrew Apted | 2016-11-13 13:49:13 +1100

BSP : skip overlapping lines when creating wall-tips.

------------------------------------------------------------------------
e034d42fbdbf | Andrew Apted | 2016-11-13 13:45:37 +1100

BSP : enable the duplicated vertex detection, mainly to help the
miniseg creation logic.

------------------------------------------------------------------------
ff24f2c903e4 | Andrew Apted | 2016-11-13 13:27:18 +1100

BSP : added "force_xnod" to nodebuildinfo_t, and use this in the
SaveLevel() logic to decide whether to save in ZDoom format.

[ Note: real XNOD support is not there, it still does ZNOD format ]

------------------------------------------------------------------------
707d4c41c193 | Andrew Apted | 2016-11-13 13:19:28 +1100

BSP : we only need to build V2 or V5 GL-Nodes, hence removed the
logic for building V1 and V3 GL-Nodes.

------------------------------------------------------------------------
4a7145d68140 | Andrew Apted | 2016-11-13 13:02:14 +1100

BSP : removed code for writing the LINEDEFS, SIDEDEFS and SECTORS
lumps, since the policy here is to never modify those lumps.

------------------------------------------------------------------------
9281b2a3184a | Andrew Apted | 2016-11-13 12:36:18 +1100

BSP : removed the "one-sided window trick" detection code, very
much past the point of diminishing returns on that rare trick.

Also removed the "skip_self_ref" feature, it is quite useless.

------------------------------------------------------------------------
a575107cc2d9 | Andrew Apted | 2016-11-13 12:25:05 +1100

BSP : a fix for commit 17b6bbc1adbc.

------------------------------------------------------------------------
cd967acd7764 | Andrew Apted | 2016-11-13 12:17:05 +1100

BSP : tweaked top-of-file comments.

------------------------------------------------------------------------
011eec922f41 | Andrew Apted | 2016-11-13 12:07:26 +1100

BSP : removed "force_hexen" field of nodebuildinfo_t.

------------------------------------------------------------------------
17b6bbc1adbc | Andrew Apted | 2016-11-13 12:04:09 +1100

BSP : removed the sidedef-packing feature, as it would cause the
LINEDEFS lump to be modified.  If we ever need this, it is something
to be handled *outside* of the node builder (by Eureka instead).

------------------------------------------------------------------------
d7f564656d46 | Andrew Apted | 2016-11-13 12:01:15 +1100

BSP : added a copy of the sidedef-packing code to e_linedef.cc
(disabled since it is not adapted to Eureka yet), as it may be
useful or needed in the future.

------------------------------------------------------------------------
abc5a4bd0fc9 | Andrew Apted | 2016-11-13 11:50:09 +1100

Code : better parameter name for SideDefs_Unpack().

------------------------------------------------------------------------
c8a2634f060a | Andrew Apted | 2016-11-13 00:20:28 +1100

BSP : removed "merge_vert" functionality, since that would require
modifying the LINEDEFS lump.

[ plus Eureka has a checker for overlapping vertices ]

------------------------------------------------------------------------
9cd3f7dec52a | Andrew Apted | 2016-11-13 00:15:10 +1100

BSP : changed PruneVertices() to only remove unused vertices at the
end of the VERTEXES lump.  That means we don't need to modify the
existing LINEDEFS lump.

------------------------------------------------------------------------
53ede5835161 | Andrew Apted | 2016-11-12 23:58:30 +1100

BSP : renamed config variables "glbsp_xxx" --> "bsp_xxx".

------------------------------------------------------------------------
51537d2e2bf3 | Andrew Apted | 2016-11-12 23:54:40 +1100

BSP : renamed "Build Nodes" in File menu --> "Build All Nodes".

------------------------------------------------------------------------
eabac55f1ab7 | Andrew Apted | 2016-11-12 23:33:11 +1100

BSP : removed code for pruning linedefs, sidedefs and sectors, as
I plan to not modify the level lumps where possible (and hence not
introduce any discrepancy between Eureka's in-memory idea of the
map and the on-disk version).

------------------------------------------------------------------------
2f485ff6d7d6 | Andrew Apted | 2016-11-12 23:12:56 +1100

Code tidying : use StringDup() and StringFree() in a few places
which were using strdup() and free().

------------------------------------------------------------------------
5eaad0dc4d4d | Andrew Apted | 2016-11-12 22:44:53 +1100

BSP : removed all GWA-related code, plus the "extra_files" stuff.

------------------------------------------------------------------------
abe0f8f0544c | Andrew Apted | 2016-11-12 22:40:03 +1100

BSP : removed ParseArgs() stuff -- total not needed here.

------------------------------------------------------------------------
0fa6fcab6e1b | Andrew Apted | 2016-11-12 22:36:27 +1100

BSP : renamed HandleLevel() --> BuildNodesForLevel(), and tweaks.

------------------------------------------------------------------------
57e7f9d36901 | Andrew Apted | 2016-11-12 22:24:51 +1100

BSP : removed custom endian handling, use Eureka's system.

------------------------------------------------------------------------
541a30c96f78 | Andrew Apted | 2016-11-12 20:22:08 +1100

BSP : removed CheckInfo() from the API, just do it internally
as the first step in ajbsp::BuildNodes() function.

------------------------------------------------------------------------
cec583c4dc7b | Andrew Apted | 2016-11-12 20:09:15 +1100

BSP : converted nodebuildinfo_t into a class, where the constructor
sets all default values, and merged nodebuildcomms_t into it too.

------------------------------------------------------------------------
50cbd7c33ec4 | Andrew Apted | 2016-11-12 19:36:28 +1100

BSP : minor tweak, a function name in e_nodes.cc

------------------------------------------------------------------------
d2050051e03b | Andrew Apted | 2016-11-12 19:17:49 +1100

BSP : removed GlbspStrDup() and GlbspFree(), use the equivalents
that Eureka already has.

------------------------------------------------------------------------
200408692ad1 | Andrew Apted | 2016-11-12 19:13:57 +1100

BSP : renamed build result enums from GLBSP_E_xxx --> BUILD_xxx

------------------------------------------------------------------------
71d05b29c6c8 | Andrew Apted | 2016-11-12 18:59:39 +1100

BSP : removed "nodebuildfuncs_t" structure, and call the GB_XXX
functions in e_node.cc directly.

------------------------------------------------------------------------
0aba2d16a6ed | Andrew Apted | 2016-11-11 22:05:06 +1100

BSP : removed the custom FatalError(), use the one in Eureka.

------------------------------------------------------------------------
96ac37566109 | Andrew Apted | 2016-11-11 22:01:23 +1100

BSP : use BugError() instead of custom InternalError().

------------------------------------------------------------------------
5c81fce5b416 | Andrew Apted | 2016-11-11 21:57:55 +1100

BSP : replaced PrintDebug() calls with DebugPrintf().

------------------------------------------------------------------------
98a23b1feeec | Andrew Apted | 2016-11-11 17:15:08 +1100

BSP : improved the top-of-file comments, calling this "AJ-BSP" to
distinguish from the real glBSP, changed namespace name to "ajbsp".

------------------------------------------------------------------------
79f77d3f0546 | Andrew Apted | 2016-11-11 15:51:11 +1100

BSP : removed some out-of-date comments.

------------------------------------------------------------------------
076112ba99c2 | Andrew Apted | 2016-11-11 15:50:20 +1100

BSP : removed whitespace at ends of lines.

------------------------------------------------------------------------
e07f2e8d9be8 | Andrew Apted | 2016-11-11 15:44:43 +1100

Preferences : simplified name of "Node Building" section.

------------------------------------------------------------------------
1f6a37f14972 | Andrew Apted | 2016-11-11 15:28:16 +1100

BSP : changed the "BUILDER" name stored in the GL-nodes map header
to be "Eureka X.XX" instead of "glBSP X.XX" -- since that reflects
better how someone built the GL-nodes.

------------------------------------------------------------------------
b1aaa2e84b85 | Andrew Apted | 2016-11-11 15:19:28 +1100

BSP : updated whitespace in rest of code to use tabs.

------------------------------------------------------------------------
ee2b1b6fd6b4 | Andrew Apted | 2016-11-11 15:09:30 +1100

BSP : removed <assert.h> header, use SYS_ASSERT() instead.

------------------------------------------------------------------------
a8a9783b641d | Andrew Apted | 2016-11-11 15:08:17 +1100

BSP : tidied up the include guards in "bsp.h"

------------------------------------------------------------------------
a80c996f8cbe | Andrew Apted | 2016-11-11 14:42:58 +1100

BSP : added editor settings to each code file.

------------------------------------------------------------------------
38b8f1f8b224 | Andrew Apted | 2016-11-11 14:42:30 +1100

BSP : reformatted "bsp.h" to use tabs instead of spaces.

------------------------------------------------------------------------
e8a27a027dcb | Andrew Apted | 2016-11-11 14:33:50 +1100

BSP : replaced custom "boolean_g" typedef with plain "bool", and
replaced "TRUE" and "FALSE" with the normal keywords.

------------------------------------------------------------------------
35cdde70053f | Andrew Apted | 2016-11-11 14:25:26 +1100

BSP : replaced "sint8_g", "uint32_g" typedefs with the similar ones
which Eureka already has (s8_t, u32_t, etc).  Also replaced "float_g"
typedef with the standard "double" type.

------------------------------------------------------------------------
19d8ef5f9a18 | Andrew Apted | 2016-11-11 14:15:27 +1100

BSP : removed duplicated macros like MIN() and ABS().

------------------------------------------------------------------------
936f012e801c | Andrew Apted | 2016-11-11 13:41:23 +1100

Makefile : added new "bsp_xx" files to the build, and removed the
old GLBSP stuff, like references to glbsp_src/

------------------------------------------------------------------------
5aceafa24d11 | Andrew Apted | 2016-11-11 13:39:58 +1100

BSP : fixed #includes for the new file layout.

------------------------------------------------------------------------
06928970f475 | Andrew Apted | 2016-11-11 13:28:57 +1100

BSP : replaced "INLINE_G" with plain "inline" keyword.

------------------------------------------------------------------------
f4b5a4475fbd | Andrew Apted | 2016-11-11 13:17:46 +1100

Began rework of glBSP code, with the goal to integrate it more
tightly with Eureka, e.g. use Eureka's WAD handling code, and
ultimately to support building nodes for a single map.

This commit concatenates files from glbsp_src/ to produce some
code files with "bsp_" prefix (bsp_node.cc etc...), and one big
header file "bsp.h".

------------------------------------------------------------------------
7ff0ec89c55f | Andrew Apted | 2016-11-11 13:00:03 +1100

Game def parser : removed "exclude_game" directive (ignored it),
since it will be replaced with something better soon.

------------------------------------------------------------------------
0d9dd50581fa | Andrew Apted | 2016-11-10 23:24:27 +1100

Game def parser : merged ParseSupportedGame() code into the calling
one (handing PURPOSE_GameCheck), as it was simple and nothing else
will need it.

------------------------------------------------------------------------
85164d03fb24 | Andrew Apted | 2016-11-10 23:06:07 +1100

Game def parser : code for handling "if", "else", "endif" lines.
When the "if" condition is false, we simply skip lines until the
next "else" or "endif" line.  A missing "endif" is detected.

Still to-do is actually parsing conditions on the "if" lines,
and checking whether they are true or not......

------------------------------------------------------------------------
08b059a7dbd3 | Andrew Apted | 2016-11-10 22:43:21 +1100

Game def parser : refactored the M_ParseDefinitionFile() code into
several functions, sharing state via a struct.

------------------------------------------------------------------------
a9f5d5ce9709 | Andrew Apted | 2016-11-10 21:01:22 +1100

Game def parser : refactored tokenizing code into its own function,
and tidied up the code.

------------------------------------------------------------------------
7772a404357a | Andrew Apted | 2016-11-10 14:52:43 +1100

Canvas : show length of the current line (in draw mode).

------------------------------------------------------------------------
e52aae145131 | Andrew Apted | 2016-11-10 00:25:59 +1100

Check / things : support a "no_need_players" feature in definition
files, which turns of warnings about missing players.  This can be
useful when editing prefabs.

------------------------------------------------------------------------
094d6fa3fdac | Andrew Apted | 2016-11-10 00:06:58 +1100

Image code : added IM_ConvertTGAImage() function.

------------------------------------------------------------------------
5aa22a5b3d60 | Andrew Apted | 2016-11-09 23:49:01 +1100

Fixed bug, where going into 3D mode caused the panel to stay stuck
on the currently highlighted object.

------------------------------------------------------------------------
ef03db5fc55d | Andrew Apted | 2016-11-09 23:22:06 +1100

Find/Replace : clearing a selected picture box should not open the
browser (or focus the input box) -- fixed.

------------------------------------------------------------------------
7efddb423c93 | Andrew Apted | 2016-11-09 21:42:17 +1100

Find/Replace : when using "Restrict to Selection", detect early on
when the selection is empty and beep with a status message.

------------------------------------------------------------------------
129b77d18561 | Andrew Apted | 2016-11-08 20:37:48 +1100

Find/Replace : added a "Restrict to Selection" filter.  When active,
objects not in the current selection will be ignored (skipped).

------------------------------------------------------------------------
c7a4c5517f76 | Andrew Apted | 2016-11-08 18:45:37 +1100

Find/Replace : fixed how the picture is set, and support Things.

------------------------------------------------------------------------
26b49748c565 | Andrew Apted | 2016-11-08 18:11:22 +1100

Find/Replace : show the texture/flat in the choose box.  Also only
allow appending in the Match box when the SHIFT key is pressed.

------------------------------------------------------------------------
d94fdf5f53ed | Andrew Apted | 2016-11-08 16:52:29 +1100

Find/Replace : began work to change the "Choose" buttons into a
picture of the texture or thing.  Apart from looking nice, this
will fix the problem of pressing "Choose" and selecting something
and the name is inserted into the wrong input box.

------------------------------------------------------------------------
f7e3f7682985 | Andrew Apted | 2016-11-08 16:42:43 +1100

UI Code : fixed UI_Pic::Selected(_val) to redraw if changed.

------------------------------------------------------------------------
9126db49f6b2 | Andrew Apted | 2016-11-08 15:37:59 +1100

Ensure we never highlight objects while in the 3D preview.

------------------------------------------------------------------------
4be3e9501fc8 | Andrew Apted | 2016-11-08 15:20:14 +1100

Source code : added "lib_tga.cc/h" code files, support for decoding
TGA (Targa) image files.

Ultimately this code came from Quake 2, but it has been modified a
lot since then, e.g. I added support for colormapped formats.

------------------------------------------------------------------------
170c89ec0c79 | Andrew Apted | 2016-11-08 15:08:58 +1100

glBSP library : shut up a compiler warning.

------------------------------------------------------------------------
8cd6da0124a3 | Andrew Apted | 2016-11-08 10:20:08 +1100

Manage Project : when user adds a new game iwad (via FIND button)
then make it the one currently shown.

[ this was probably a regression due to recent changes ]

------------------------------------------------------------------------
faaa9692af16 | Andrew Apted | 2016-11-08 00:11:37 +1100

HEXEN config tweak.

------------------------------------------------------------------------
8600e4e8535d | Andrew Apted | 2016-11-08 00:09:05 +1100

Improved the "New Project" command, ask for the filename *first*
and then do the ProjectSetup dialog.  Also tidied up how FreshLevel()
and SaveLevel() were used, moving some common code into them.

------------------------------------------------------------------------
2f9204dc8f65 | Andrew Apted | 2016-11-07 23:40:14 +1100

More refactoring... split ProjectSetup() code into two separate
functions: CMD_ManageProject() and CMD_NewProject(), and merged
the Project_New() code into the latter.

------------------------------------------------------------------------
d854f740f16e | Andrew Apted | 2016-11-07 23:27:37 +1100

Code tidying : refactored new MissingIWAD_Dialog() function out of
the ProjectSetup() code, also factored out filename asking code.

------------------------------------------------------------------------
c3b52f873b5c | Andrew Apted | 2016-11-07 22:58:10 +1100

Renderer : code tidying, fixed the confusing "buf" and "wbuf" var
names ("wbuf" was the reading one, NOT the writing one).

------------------------------------------------------------------------
f4643fda7fc2 | Andrew Apted | 2016-11-07 22:27:19 +1100

Image code : fixed gamma handling of RGB img pixels, and moved the
gamma tables --> im_color.cc

------------------------------------------------------------------------
b1605163e285 | Andrew Apted | 2016-11-07 21:46:59 +1100

Renderer : fixed partial-invis effect with RGB img pixels.

------------------------------------------------------------------------
89561e0603b6 | Andrew Apted | 2016-11-07 21:39:00 +1100

Image code : added test_make_RGB() to help test other code.

------------------------------------------------------------------------
a6cd501135dc | Andrew Apted | 2016-11-07 21:22:43 +1100

Image code : support RGB img_pixel_t in the UI_Pic widget.

------------------------------------------------------------------------
67be95de4bf2 | Andrew Apted | 2016-11-07 21:11:33 +1100

Image code : support RGB img_pixel_t in the 3D renderer, including
the lighting calculation and the partial-invis effect.

------------------------------------------------------------------------
8b11888e745a | Andrew Apted | 2016-11-07 20:59:54 +1100

Image code : support RGB img_pixel_t in the sector renderer.

------------------------------------------------------------------------
691eb4dea827 | Andrew Apted | 2016-11-07 20:55:03 +1100

Image code : start work to extend img_pixel_t, make it 16 bits and
support both a palettized index (0-255) but also 5:5:5 RGB colors
when the high bit is set.

This commit includes the decode and encode macros, as well as two
inline functions: IM_PixelToRGB() and IM_DecodePixel().

------------------------------------------------------------------------
67f1515ea2fe | Andrew Apted | 2016-11-07 20:02:16 +1100

Renderer : fixed how the screen[] array is cleared.

------------------------------------------------------------------------
012e9aedbc60 | Andrew Apted | 2016-11-07 19:59:41 +1100

Image code : fixed Img_c::clear() to not use memset.

------------------------------------------------------------------------
0678c2dd955e | Andrew Apted | 2016-11-07 19:57:32 +1100

Image code : fixed another use of "byte" to be "img_pixel_t".

------------------------------------------------------------------------
a0c410b9b9ce | Andrew Apted | 2016-11-07 19:56:47 +1100

STRIFE config : small fix.

------------------------------------------------------------------------
1453a2106552 | Andrew Apted | 2016-11-07 19:51:34 +1100

Sector rendering : fixed a misuse of Img_c::wbuf(), which is for
writing the image but this code is only reading them.

------------------------------------------------------------------------
f5daa25a2a9f | Andrew Apted | 2016-11-07 19:50:47 +1100

Flat loader : remap any TRANS_PIXEL pixels.

------------------------------------------------------------------------
d952757e0cd4 | Andrew Apted | 2016-11-07 19:26:45 +1100

Refactored flat loading code with separate LoadFlatImage() func.

------------------------------------------------------------------------
4f93fe660368 | Andrew Apted | 2016-11-07 19:12:12 +1100

hdr_fltk : #include "Fl_JPEG_Image.H", just in case we need some
jpeg loading support.

------------------------------------------------------------------------
988374cff494 | Andrew Apted | 2016-11-07 18:51:55 +1100

Game defs : added new "invis" color range, used when creating the
partial-invisibility effect on sprites.

------------------------------------------------------------------------
45da40222128 | Andrew Apted | 2016-11-07 18:28:00 +1100

Image code : use "img_pixel_t" instead of "byte" in a few places.

------------------------------------------------------------------------
9dcd0a88d88d | Andrew Apted | 2016-11-07 17:05:17 +1100

Image code : implemented conversion from a Fl_RGB_Image --> Img_c.
Since it does a palette lookup for every pixel, it is very slow.

------------------------------------------------------------------------
8a37078a3e41 | Andrew Apted | 2016-11-07 16:13:08 +1100

STRIFE config : added "l" lit flag to several things.

------------------------------------------------------------------------
9b0fff312057 | Andrew Apted | 2016-11-07 15:43:54 +1100

Game defs : removed '&' from the names of line types.

That convention was used in (and inherited from) the Unofficial
DOOM Specs, and means the target sector is locked out of further
changes.  But for Eureka I feel it is only visual noise.

------------------------------------------------------------------------
5fdb9aae6e36 | Andrew Apted | 2016-11-07 15:34:51 +1100

Version bump, in honor of a working STRIFE definition.

------------------------------------------------------------------------
904f694542da | Andrew Apted | 2016-11-07 15:30:41 +1100

CHANGELOG and TODO update.

------------------------------------------------------------------------
0d8706d22cfc | Andrew Apted | 2016-11-07 15:25:39 +1100

STRIFE config : fixed radius of players, which according to the
Chocolate-Strife source code is 18 units (not 16 units like all
the other games).

------------------------------------------------------------------------
3e835410db40 | Andrew Apted | 2016-11-07 15:23:29 +1100

Game defs : added "player_size" info to most games (for DOOM games
it is in common/doom_things).

------------------------------------------------------------------------
d01e33e7fd42 | Andrew Apted | 2016-11-07 15:08:10 +1100

Game def parser : new "player_size" command to specify the size of
players (radius, height and view_ofs).  Use this in the renderer,
removing the hard-coded EYE_HEIGHT value.

------------------------------------------------------------------------
6abc42c70317 | Andrew Apted | 2016-11-07 14:44:20 +1100

DOOM and HERETIC config : tweaked names of some specials.

------------------------------------------------------------------------
33765e4d519a | Andrew Apted | 2016-11-07 14:42:01 +1100

STRIFE config : finished the line specials, plus a few tweaks.

------------------------------------------------------------------------
556cc6e1f968 | Andrew Apted | 2016-11-07 14:24:38 +1100

STRIFE config : sorted out all the doors, having "Split Door" and
"Keyed Door" categories in addition to normal "Door" category.

------------------------------------------------------------------------
b158b60144ba | Andrew Apted | 2016-11-07 13:29:51 +1100

STRIFE config : worked on adding the line specials (from SLADE),
adapting the names to match Eureka conventions.

------------------------------------------------------------------------
95489c7a4f2a | Andrew Apted | 2016-11-07 01:02:26 +1100

Disabled normalization of sidedefs on 1-S lines after level load.

The original reason for this was to prevent showing useless crap
in the "rail" and "upper" boxes in the LineDef panel.  These days
1-S lines only show their lower texture, so it's no longer needed,
and may intefere with special usage of those sidedef parts.

------------------------------------------------------------------------
e0a7e210f083 | Andrew Apted | 2016-11-07 00:31:22 +1100

Project Setup : when doing the missing-iwad dialog, hide the port
choice, map format, and all the resource stuff, since they are
distractions from the task of finding a usable iwad.

------------------------------------------------------------------------
941d7945fea4 | Andrew Apted | 2016-11-07 00:11:53 +1100

several fixes for recent code (e.g. some string memory issues).

------------------------------------------------------------------------
892491a0fcd0 | Andrew Apted | 2016-11-06 23:21:56 +1100

Project Setup : ensure Level_format is set *before* reloading all
resources, so the UI panels can update themselves properly.

------------------------------------------------------------------------
802366bd9ef7 | Andrew Apted | 2016-11-06 22:39:56 +1100

Project Setup dialog : changed code to store the plain "game" name
instead of full iwad pathname, so the code easier to understand.

------------------------------------------------------------------------
3bdfc841d532 | Andrew Apted | 2016-11-06 22:10:40 +1100

Project Setup : implemented logic for the map-format choice, and
various tidying in related code.

------------------------------------------------------------------------
855a6b08f1f5 | Andrew Apted | 2016-11-06 21:24:20 +1100

STRIFE config : added sector types.

------------------------------------------------------------------------
1e46fffef76a | Andrew Apted | 2016-11-06 21:03:51 +1100

Project Setup : keep same port when changing the game (if possible),
and more robust code in the PopulatePort() method.

------------------------------------------------------------------------
eb00612709d6 | Andrew Apted | 2016-11-06 20:31:03 +1100

Project Setup : default for "supported_games" should be "doom doom2"
(mainly for backwards compatibility).

------------------------------------------------------------------------
bec9f9db94af | Andrew Apted | 2016-11-06 20:19:10 +1100

fixed several bugs in latest code...

------------------------------------------------------------------------
8a0a012199ef | Andrew Apted | 2016-11-06 19:51:00 +1100

Game def parser : implemented the "variant_of" and "supported_games"
keywords.

------------------------------------------------------------------------
698a9be80210 | Andrew Apted | 2016-11-06 19:40:28 +1100

Project Setup : implemented the machinery for limiting the list of
ports to show to ones supporting the selected game.

------------------------------------------------------------------------
e96a41e8e3aa | Andrew Apted | 2016-11-06 19:04:18 +1100

Project Setup : started work to have a map-format choice, and to
limit the port choices to ones which support the selected game.

------------------------------------------------------------------------
c341ac965a94 | Andrew Apted | 2016-11-06 16:48:07 +1100

.gitignore

------------------------------------------------------------------------
89c0bf9e4537 | Andrew Apted | 2016-11-06 16:46:59 +1100

TODO.txt updated

------------------------------------------------------------------------
88e392a8f2e9 | Andrew Apted | 2016-11-06 16:34:00 +1100

Game def parser : partial work to support minimal parsing of a
definition file to extract some info needed by the Manage Project
dialog -- like which source ports work with the chosen game.

------------------------------------------------------------------------
7fc523ea11f2 | Andrew Apted | 2016-11-06 16:18:52 +1100

CHANGELOG update.

------------------------------------------------------------------------
37ba3e6e998d | Andrew Apted | 2016-11-06 15:59:44 +1100

Game def parser : only use the "common" folder when looking for an
included file, and simplified the M_LoadDefinitions() code.

------------------------------------------------------------------------
d90d8c6c5902 | Andrew Apted | 2016-11-06 15:49:14 +1100

Game def parser : simplified some code, moved home_dir/install_dir
checks into the FindDefinitionFile() function.

------------------------------------------------------------------------
4800dccc0b9a | Andrew Apted | 2016-11-06 14:09:00 +1100

Makefile : re-enable debugging build (until next release....)

------------------------------------------------------------------------
ac5465fdfcd1 | Andrew Apted | 2016-11-06 14:04:35 +1100

Port defs : added "supported_games" to BOOM (and hence anything
which includes boom.ugh), and also XDOOM.

(This is not strictly necessary, as it matches what the defaults
will be, but being explicit is generally more helpful to people).

------------------------------------------------------------------------
d5e05fb966b3 | Andrew Apted | 2016-11-06 13:58:44 +1100

STRIFE config : added remaining thing definitions (decor objects),
adapted from the SLADE config files.

------------------------------------------------------------------------
52958a840c6b | Andrew Apted | 2016-11-06 13:09:44 +1100

STRIFE config : added the monsters, rebels and civilian things,
and gave all the pickup items the "n" non-blocking flag.

------------------------------------------------------------------------
d41820cc4a6e | Andrew Apted | 2016-11-06 12:23:43 +1100

Port defs : added "supported_games" line to vanilla and zdoom configs.

(vanilla is a special case, as it does not represent a single source
port but rather the engine which each game was shipped with).

------------------------------------------------------------------------
866bc92b8cd3 | Andrew Apted | 2016-11-06 12:11:00 +1100

Game defs : added "variant_of" lines to various game configs.

For example, TNT has "variant_of doom2" since any port which
supports DOOM 2 will support TNT Evilution.

------------------------------------------------------------------------
86646c397f68 | Andrew Apted | 2016-11-06 12:09:39 +1100

Game def parser : ignore three keywords: "variant_of", "supported_games"
and "map_formats".  These will be handled by different code.

------------------------------------------------------------------------
618f84bdb326 | Andrew Apted | 2016-11-06 11:42:48 +1100

STRIFE config : added numerous thing defs: player starts, teleports,
health, ammo, keys, weapons, powerups, and quest items.

(This info shamelessly stolen from the SLADE editor)

------------------------------------------------------------------------
f3a6f0de70ae | Andrew Apted | 2016-11-05 23:24:27 +1100

Added "map_formats" line to HEXEN and ZDOOM config files.

------------------------------------------------------------------------
16d50e3517ec | Andrew Apted | 2016-11-05 23:22:19 +1100

Game def parser : support a "map_formats" line for config files,
taking one or more map format names ("DOOM" or "HEXEN").

------------------------------------------------------------------------
9f11b222e525 | Andrew Apted | 2016-11-05 22:48:03 +1100

minor code tidying.

------------------------------------------------------------------------
ac549f2f6f5d | Andrew Apted | 2016-11-05 22:40:19 +1100

Texture loader : fixed hack for loading the STRIFE texture lump.

------------------------------------------------------------------------
bd8b81208d23 | Andrew Apted | 2016-11-05 21:51:24 +1100

Games / STRIFE : renamed config file to match iwad filename.

------------------------------------------------------------------------
7e3f0bdfd09b | Andrew Apted | 2016-11-05 21:43:02 +1100

Texture loader : support the STRIFE format of "TEXTURE1" lump.

------------------------------------------------------------------------
3a95d924682b | Andrew Apted | 2016-11-05 21:21:01 +1100

Game defs : added config for the game STRIFE, quite empty so far.

------------------------------------------------------------------------
6dac24e3c180 | Andrew Apted | 2016-11-05 20:21:35 +1100

Code tidying : removed "default_upper_tex" and "default_lower_tex"
global vars, as they always mirrored the default wall texture.

------------------------------------------------------------------------
eae977031829 | Andrew Apted | 2016-11-05 20:19:49 +1100

Game defs : tweaked default textures of Heretic and Hexen.

------------------------------------------------------------------------
1e7714a24431 | Andrew Apted | 2016-11-05 20:12:45 +1100

Game defs : changed default textures for DOOM maps.

------------------------------------------------------------------------
66af446104fb | Andrew Apted | 2016-11-05 19:44:40 +1100

Ports : added "zdoom.ugh" configuration -- very empty so far.

------------------------------------------------------------------------
1ba18909f518 | Andrew Apted | 2016-11-05 19:31:45 +1100

Ports / Eternity : enable "tx_start" feature here too.

------------------------------------------------------------------------
b04fe994915e | Andrew Apted | 2016-11-05 19:19:22 +1100

Ports / EDGE : enable the "tx_start" feature.

------------------------------------------------------------------------
f1411037d5da | Andrew Apted | 2016-11-05 19:17:26 +1100

Texture loader : require "feature tx_start" in a port config file
in order to load and see the textures in TX_START/END namespace.

------------------------------------------------------------------------
a116aa2517d8 | Andrew Apted | 2016-11-05 18:12:23 +1100

Texture loader : support "patch" format textures in the TX_START/END
namespace.

------------------------------------------------------------------------
093c9b4e5dfc | Andrew Apted | 2016-11-05 17:57:36 +1100

Texture loader : properly free any images that get replaced by a
later wad (e.g. a resource wad).

------------------------------------------------------------------------
5c092ca8e03a | Andrew Apted | 2016-11-05 17:49:06 +1100

Texture loader : bit more work to load the TX_START/TX_END textures.

------------------------------------------------------------------------
3db6ad8381a6 | Andrew Apted | 2016-11-05 17:46:46 +1100

Flat loader : properly free any flat images that get replaced
(e.g. by a resource wad).

------------------------------------------------------------------------
b2602b090407 | Andrew Apted | 2016-11-05 17:31:33 +1100

In W_DetectImageFormat(), return a letter for all the formats we
can detect, and let higher up code decide what to support.

------------------------------------------------------------------------
00f847efbee4 | Andrew Apted | 2016-11-05 17:13:20 +1100

In W_DetectImageFormat(), check for some common but unsupported
image formats: JPEG, GIF, BMP, and DDS.

------------------------------------------------------------------------
a8e341860972 | Andrew Apted | 2016-11-05 16:54:38 +1100

Added W_DetectImageFormat() function, detect what kind of image is
used in a given wad lump.

------------------------------------------------------------------------
d1ae402290fc | Andrew Apted | 2016-11-05 13:55:21 +1100

Undo messages : simplified an overly long message.

------------------------------------------------------------------------
69d632b2cf9f | Andrew Apted | 2016-11-05 13:49:34 +1100

Undo messages : finished the remaining operations.

------------------------------------------------------------------------
276436e47c78 | Andrew Apted | 2016-11-05 13:18:00 +1100

Undo messages : did about half of the remaining operations.

------------------------------------------------------------------------
150c4e2549ea | Andrew Apted | 2016-11-05 00:32:58 +1100

Wad code : detect lumps in the TX_START..TX_END namespace.

------------------------------------------------------------------------
e9a831139e44 | Andrew Apted | 2016-11-05 00:12:57 +1100

Undo messages : handle r_render.cc -- e.g. adjusting offsets.

------------------------------------------------------------------------
d60af78e67d6 | Andrew Apted | 2016-11-05 00:08:32 +1100

Undo messages : handle inserting new objects and splitting linedefs.

------------------------------------------------------------------------
1e27900b4517 | Andrew Apted | 2016-11-05 00:04:40 +1100

Undo messages : handle the Find/Replace panel.

------------------------------------------------------------------------
c2954bbe68ea | Andrew Apted | 2016-11-04 23:48:15 +1100

Undo messages : added messages for editing done via the UI panels
(Things, LineDef, Sector, Vertex).

------------------------------------------------------------------------
6e979ce8ae2e | Andrew Apted | 2016-11-04 23:30:34 +1100

Basis : added BA_MessageForSel() utility function, used to create a
message from a verb and a selection of objects.

------------------------------------------------------------------------
7c43e11f0932 | Andrew Apted | 2016-11-04 22:39:31 +1100

Basis : have a new BA_Message() function, instead of supplying the
message to the BA_End() function.  Makes it easier to have utility
methods for setting the message, without hiding the BA_End call.

------------------------------------------------------------------------
07612c8c0663 | Andrew Apted | 2016-11-04 22:05:41 +1100

Began work on assigning a message to each operation, and show that
message in the status area after each Undo or Redo.

This commit manages the storage of the message in each undo_group_c,
updates status on Undo and Redo, and gives BA_End() function an
optional message argument (as per printf).

------------------------------------------------------------------------
b24d15382948 | Andrew Apted | 2016-11-04 21:35:05 +1100

Browser : changing categories clears the search box.

------------------------------------------------------------------------
f53de7cd4ec2 | Andrew Apted | 2016-11-04 21:14:04 +1100

CHANGELOG update.

------------------------------------------------------------------------
25abee83f394 | Andrew Apted | 2016-11-04 21:11:00 +1100

LineDef panel : allow entering a negative "Length" value which
causes the start vertex to be moved instead of the end vertex.

------------------------------------------------------------------------
d3dc1d46f642 | Andrew Apted | 2016-11-04 20:51:09 +1100

LineDef panel : always show an integer in the "Length" widget,
making it easier to edit that value.

------------------------------------------------------------------------
3088a0615d87 | Ioan Chera | 2016-08-09 21:01:49 +0300

Added forgotten (401) ExtraData sector linedef special.

------------------------------------------------------------------------
59a169a2ba24 | Ioan Chera | 2016-07-19 09:21:41 +0300

Updated Xcode project

------------------------------------------------------------------------
f762a82f53ca | Andrew Apted | 2016-04-30 13:07:54 +1000

Implemented new 'File/Copy Map' command.

------------------------------------------------------------------------
559f2ca0bfda | Andrew Apted | 2016-02-25 15:28:11 +1100

3D Preview : fixed bug not showing railings (introduced in a recent commit).

------------------------------------------------------------------------
cfa11071dc1a | Andrew Apted | 2016-02-21 12:49:34 +1100

CHANGELOG update.

------------------------------------------------------------------------
6a3693e05aaa | Andrew Apted | 2016-02-21 12:47:13 +1100

Version bump after the release.

------------------------------------------------------------------------
cd9b86ca6959 | Andrew Apted | 2016-02-21 12:40:25 +1100

Fixed some usage of isalnum(texname[0]) to use !is_null_tex() instead,
which fixes bad behavior when texture names begin with '_' or '#'.

------------------------------------------------------------------------
417a510fcdc5 | Andrew Apted | 2016-02-21 12:35:01 +1100

Added is_null_tex() function to global scope, use it everywhere instead
of directly testing the texture name.

------------------------------------------------------------------------
cb3aff590acf | Andrew Apted | 2016-02-21 12:14:09 +1100

Moved some code: LD_AddSecondSideDef() and LD_RemoveSideDef() functions
from x_loop.cc --> e_linedef.cc

------------------------------------------------------------------------
f7026f24a7eb | Andrew Apted | 2016-02-21 11:35:11 +1100

LineDef panel : hide the ADD and DEL sidedef buttons.
[ a preference setting for this is under consideration... ]

------------------------------------------------------------------------
66f7d07cd165 | Andrew Apted | 2016-02-06 16:21:06 +1100

INSTALL.txt : mention 'libfontconfig-dev' as a package that may be needed.

------------------------------------------------------------------------
2aa9ee5669b9 | Andrew Apted | 2016-02-04 21:12:10 +1100

glBSP library : do not create "truncated" blockmaps, which rarely allows
the map to be playable.  Instead, leave the BLOCKMAP lump as empty, to
allow source ports with internal blockmap generators to generate one.

------------------------------------------------------------------------
727b91784b4d | Andrew Apted | 2016-01-29 13:03:03 +1100

Added new CHANGES.txt file (after the 1.11 release)

------------------------------------------------------------------------
b76005aeeda2 | Andrew Apted | 2016-01-29 13:01:26 +1100

Version 1.11 was released.

Hence moved CHANGELOG --> changelogs/ directory.

------------------------------------------------------------------------
202acafa7736 | Andrew Apted | 2016-01-29 13:00:21 +1100

TODO : added a few post-release issues.

------------------------------------------------------------------------
8bbf0550c36b | Ioan Chera | 2016-01-26 09:26:18 +0200

Updated Xcode project and info plist version.

Removed "mods" from the referenced folders.

------------------------------------------------------------------------
5760ac988954 | Andrew Apted | 2016-01-26 14:03:07 +1100

pack scripts : fixed for missing "mods" directory.

------------------------------------------------------------------------
cf09ed180c2f | Andrew Apted | 2016-01-26 13:53:37 +1100

pack scripts : updated for transition from SVN to GIT.

------------------------------------------------------------------------
8f01beae576c | Andrew Apted | 2016-01-26 13:08:16 +1100

man page : bumped the date.

------------------------------------------------------------------------
3b1eb152e5c1 | Andrew Apted | 2016-01-26 13:07:49 +1100

eureka.desktop : added "hexen" to the keywords.

------------------------------------------------------------------------
552ca759b634 | Andrew Apted | 2016-01-26 11:54:14 +1100

Checks : fixed dangling vertex check to ignore lines that sit alone
inside a sector (i.e. front and back are the same sector), which is a
perfectly valid situation.

------------------------------------------------------------------------
228e54af5e81 | Andrew Apted | 2016-01-26 11:43:38 +1100

Sector rendering : for unknown flats, use the cyan-ish image instead of
the green one.

------------------------------------------------------------------------
b9ca1795b2b4 | Andrew Apted | 2016-01-26 10:05:10 +1100

TODO.txt : final update (I swear!)

------------------------------------------------------------------------
275d7fe67989 | Andrew Apted | 2016-01-26 09:42:39 +1100

CHANGELOG / TODO updated.

------------------------------------------------------------------------
4a8d41818129 | Andrew Apted | 2016-01-26 09:38:39 +1100

Added user config variable "sector_render_default".

------------------------------------------------------------------------
579c1c154b13 | Andrew Apted | 2016-01-26 09:34:20 +1100

When creating a fresh map, add all four player starts, make them look north,
and center the map around (0, 0).

------------------------------------------------------------------------
0cca2756095b | Andrew Apted | 2016-01-25 23:56:30 +1100

Menu : added "Online Docs..." to the Help menu, which will open a web
browser and load the documentation page of the website.

------------------------------------------------------------------------
e3a840784871 | Andrew Apted | 2016-01-25 22:49:07 +1100

Sector panel : MMB on the ceiling flat sets it to sky.

------------------------------------------------------------------------
83b4206044bc | Andrew Apted | 2016-01-25 22:42:22 +1100

Fixed recent bug: RMB in the flat browser did not set ceiling tex.

------------------------------------------------------------------------
9c17ace38d33 | Andrew Apted | 2016-01-25 18:15:24 +1100

AUTHORS.txt : minor tweakage.

------------------------------------------------------------------------
6e6f2030f6be | Andrew Apted | 2016-01-25 18:07:39 +1100

README.txt : shortened the introduction paragraph.

------------------------------------------------------------------------
049526ea4943 | Andrew Apted | 2016-01-25 14:05:07 +1100

TODO.txt : added a few things.

------------------------------------------------------------------------
cd4d22c9ade7 | Andrew Apted | 2016-01-25 14:02:40 +1100

docs/History.txt : changed date format of the recent GIT commits.

------------------------------------------------------------------------
30fdd6f08241 | Andrew Apted | 2016-01-25 13:44:29 +1100

docs/History.txt : tweaked descriptive text.

------------------------------------------------------------------------
6bee5562fcbb | Andrew Apted | 2016-01-25 12:15:29 +1100

docs/History.txt : created new section for GIT repository, and added
the commits from the old SVN repository and the commits from the new
GIT repository.

------------------------------------------------------------------------
fa4b5a27193e | Andrew Apted | 2016-01-24 22:31:59 +1100

README and CHANGELOG : small update.

------------------------------------------------------------------------
283db5159c29 | Andrew Apted | 2016-01-24 22:29:09 +1100

TODO : went through and re-evaluated most items, moved several to the
"NOT-TO-DO" section.

------------------------------------------------------------------------
bb89fd036ef2 | Andrew Apted | 2016-01-24 22:13:26 +1100

Editing : SHIFT + LMB in sector/linedef mode forces the opening of a
selection box -- handy for places were it is otherwise impossible.

------------------------------------------------------------------------
6f1fb5073c59 | Andrew Apted | 2016-01-24 21:44:31 +1100

Code tidying, miscellaneous stuff here and there.

------------------------------------------------------------------------
2ef2708b2f39 | Andrew Apted | 2016-01-24 21:43:46 +1100

Browser : removed CycleCategory method from generalized line editor.

------------------------------------------------------------------------
23fc3cf6eb24 | Andrew Apted | 2016-01-24 21:39:57 +1100

Code tidying : removed the unused exchange_object_numbers() which is
legacy code that would require major surgery to get working again but
has very little utility.

------------------------------------------------------------------------
df4b2b95b474 | Andrew Apted | 2016-01-24 21:30:34 +1100

Code tidying : removed some unused code in e_sector.cc

------------------------------------------------------------------------
e6214230a578 | Andrew Apted | 2016-01-24 21:03:17 +1100

Version bumped,

------------------------------------------------------------------------
bafc1cc78a17 | Andrew Apted | 2016-01-24 20:59:15 +1100

CHANGELOG : re-organized into sections like "Editing" etc.

------------------------------------------------------------------------
595b8a63f540 | Andrew Apted | 2016-01-24 20:41:24 +1100

3D Preview : small optimisation of the texture-warp fix.

------------------------------------------------------------------------
e45cf71fb832 | Andrew Apted | 2016-01-24 19:38:31 +1100

3D Preview : fixed the texture warping issue, caused by interpolating the
angles across the wall (not the correct method).

------------------------------------------------------------------------
917fd68cb3a4 | Andrew Apted | 2016-01-24 18:15:06 +1100

TODO updated.

------------------------------------------------------------------------
48bc72ceb2e1 | Andrew Apted | 2016-01-24 18:12:41 +1100

When scrolling via keyboard, ensure certain actions (esp. drawing mode)
get updated properly.

------------------------------------------------------------------------
502373e63c25 | Andrew Apted | 2016-01-24 17:37:43 +1100

TODO update.

------------------------------------------------------------------------
eb171c92d11c | Andrew Apted | 2016-01-24 16:28:10 +1100

LIN_Flip :
1. default behavior on 1S lines is to NOT makes lines without a right side
2. support /verts flag which only swaps the vertices
3. support /sides flag which only swaps the sidedefs

------------------------------------------------------------------------
be11e914ff48 | Andrew Apted | 2016-01-24 16:27:29 +1100

Fixed bug saving the key bindings (file handle was not closed).

------------------------------------------------------------------------
d9344de9a581 | Andrew Apted | 2016-01-24 16:22:08 +1100

Canvas sector rendering : treat lines missing a right side as broken
(i.e. do not create spans even when the left side is valid).

------------------------------------------------------------------------
4c62d990849a | Andrew Apted | 2016-01-24 15:44:18 +1100

Improved split-line detection when grid snapping -- prevent the split
point from being far away from the line.

------------------------------------------------------------------------
a46432dcaa8b | Andrew Apted | 2016-01-24 14:58:32 +1100

Drawing mode : added special case for splitting a line via mouse button
(and not in drawing mode) to allow the new vertex to be dragged.
[ this was not possible in the normal Insert_Vertex code-path ]

------------------------------------------------------------------------
d8715a09ddfc | Andrew Apted | 2016-01-24 13:54:13 +1100

code : futher tidying in Editor_MouseRelease().

------------------------------------------------------------------------
12134d210757 | Andrew Apted | 2016-01-24 13:53:07 +1100

Implemented "!=" operator for the Objid class.

------------------------------------------------------------------------
ecde28798c7f | Andrew Apted | 2016-01-24 13:44:03 +1100

code : various tidying in Editor_MouseMotion().

------------------------------------------------------------------------
ff44e9660b02 | Andrew Apted | 2016-01-24 13:35:09 +1100

code : some refactoring in Editor_MouseRelease().

------------------------------------------------------------------------
97b340a84f1d | Andrew Apted | 2016-01-24 13:23:16 +1100

minor code rejig in Editor_MouseRelease().

------------------------------------------------------------------------
6b6d6101db2e | Andrew Apted | 2016-01-24 13:09:53 +1100

Drawing mode : worked on fixing drawing mode erroneously beginning again
after closing a sector via splitting a line.  Still not correct, ugh...

------------------------------------------------------------------------
7a7e8cefea7f | Andrew Apted | 2016-01-24 11:39:08 +1100

Fixed Selection_NotifyInsert() to not clear a vertex selection when a
new linedef or sector is created.

------------------------------------------------------------------------
0340593de210 | Andrew Apted | 2016-01-23 23:25:47 +1100

Added workaround in Editor_RawButton() for FLTK not sending us a button
release event after another mouse button was released (i.e. when two
buttons were being held down simultaneously).

------------------------------------------------------------------------
a106d2019868 | Andrew Apted | 2016-01-23 22:57:04 +1100

fix for previous commit: do not check for FL_DRAG event when calling
Editor_MouseMotion, since it won't be set after scrolling via RMB.

------------------------------------------------------------------------
701606bbb8f1 | Andrew Apted | 2016-01-23 22:49:07 +1100

Changed the way map scrolling via RMB is done, no longer an action state
(ACT_XXX value) because that prevents scrolling and line drawing being
used together [ a scroll would disable the current line ].

------------------------------------------------------------------------
d1b3b2a4744e | Andrew Apted | 2016-01-23 21:12:37 +1100

For dangling vertex fixer, when merging two vertices make the final
vertex selected (and nothing else).

------------------------------------------------------------------------
025c5161c1f1 | Andrew Apted | 2016-01-23 21:01:05 +1100

Fixed the logic for fixing a dangling vertex.

------------------------------------------------------------------------
9ad68d2fb07e | Andrew Apted | 2016-01-23 20:29:42 +1100

Insert_Vertex : added back the check preventing the creation of a zero
length linedef -- it displays a "Bug detected" message as I am quite
sure that it should never happen.

------------------------------------------------------------------------
f2015147a513 | Andrew Apted | 2016-01-23 20:08:29 +1100

Insert_Vertex : fixed a few cases involving a split-line.

------------------------------------------------------------------------
d96639336041 | Andrew Apted | 2016-01-22 22:49:25 +1100

CHANGELOG and TODO update.

------------------------------------------------------------------------
770427e0583e | Andrew Apted | 2016-01-22 22:48:04 +1100

Insert_Vertex : bit more work, e.g. split-line handling.

------------------------------------------------------------------------
0d24939ea117 | Andrew Apted | 2016-01-22 22:37:25 +1100

Insert_Vertex : tidied up the highlight handling code.

------------------------------------------------------------------------
ef8079ded2eb | Andrew Apted | 2016-01-22 22:27:57 +1100

Began some major surgery to Insert_Vertex() to better manage all the
possible cases (e.g. easier_drawing_mode either ON or OFF).

------------------------------------------------------------------------
cb1ada9985dc | Andrew Apted | 2016-01-22 19:40:09 +1100

Drawing mode : when drawing a line AND grid snapping, allow the highlight
and split-line to move onto the snapped position (when they would otherwise
not show anything).

This prevents creating a vertex which inadvertently sits on top of another
vertex or sits on a line (due to the coordinate being snapped).

------------------------------------------------------------------------
9b45589532ba | Andrew Apted | 2016-01-22 19:38:38 +1100

Canvas : draw the split-line orange ball larger when zoomed in (closer
to the size of the vertices).

------------------------------------------------------------------------
94e30ea2dfe2 | Andrew Apted | 2016-01-22 19:10:19 +1100

Code : merely moved some code around in editloop.cc

------------------------------------------------------------------------
6309684a23b5 | Andrew Apted | 2016-01-22 19:07:15 +1100

Code : renamed GetCurobject --> GetNearObject, removed unused "snap" param.

------------------------------------------------------------------------
7effd83d2359 | Andrew Apted | 2016-01-22 18:24:08 +1100

Added config file variable "minimum_drag_pixels".

------------------------------------------------------------------------
1e410deea699 | Andrew Apted | 2016-01-22 18:12:57 +1100

Improved dragging: only begin dragging if cursor has moved a minimum # of
pixels away from the click point.  This prevents the problem where you
only wanted to select a vertex, but instead you "dragged" it.

------------------------------------------------------------------------
0cab70de706f | Andrew Apted | 2016-01-22 16:43:16 +1100

Drawing mode : allow a vertex created by spliting a line to be dragged.

------------------------------------------------------------------------
7fd666632eb1 | Andrew Apted | 2016-01-22 15:14:42 +1100

When merging vertices, simply keep the coordinates of the first vertex
(the one not delete).  The previous way of computing the middle coord
was not working well with grid-snapped vertices.

------------------------------------------------------------------------
51c91df163bc | Andrew Apted | 2016-01-22 13:57:51 +1100

More work on dangling vert fixer, but the logic is still not right...

------------------------------------------------------------------------
0f2b97fef84a | Andrew Apted | 2016-01-22 13:39:43 +1100

Implemented code to try to fix a dangling vertex -- if it sits on another
vertex, merge into that one, or if it sits on a line then split the line
with it.

Also when using CMD_Insert on a vertex, try to fix it if dangling.

------------------------------------------------------------------------
e017b4dc494e | Andrew Apted | 2016-01-22 12:49:27 +1100

Code tidying : removed unused/obsolete DrawSnapMarker() method.

------------------------------------------------------------------------
fc5e6a76bf2a | Andrew Apted | 2016-01-22 11:49:32 +1100

Checks : fixed sector checker for Boom generalized types.

------------------------------------------------------------------------
f7eadbbeda47 | Andrew Apted | 2016-01-22 11:42:47 +1100

Added preference setting to disable the "easier line drawing" mode.

------------------------------------------------------------------------
ae42eb238506 | Andrew Apted | 2016-01-22 10:54:51 +1100

Generalized browser : changing fields will now update the line's type value.

This commit marks the completion of BOOM generalized type support :)

------------------------------------------------------------------------
768bea808584 | Andrew Apted | 2016-01-22 10:41:04 +1100

Generalized browser : allow "NONE" category to clear the line's type.

------------------------------------------------------------------------
cb81af656fcf | Andrew Apted | 2016-01-22 10:40:07 +1100

LineDef panel : change "Choose" button to "Edit" for generalized types.

------------------------------------------------------------------------
2b58a571e419 | Andrew Apted | 2016-01-22 10:26:12 +1100

Checks : fixed unknown line-type checker to accept Boom generalized types
when the current port is boom-compatible.

------------------------------------------------------------------------
c17e1a147d37 | Andrew Apted | 2016-01-20 22:05:13 +1100

CHANGELOG and TODO updated.

------------------------------------------------------------------------
8e8f1884ba13 | Andrew Apted | 2016-01-20 21:51:20 +1100

Drawing mode : prevent LMB from adding linedefs when not in drawing mode
(this was happening when splitting a linedef with LMB and another vertex
was selected).

------------------------------------------------------------------------
16edc3c8a418 | Andrew Apted | 2016-01-20 19:12:06 +1100

CMD_LastSelection : tweak invalidation logic.

------------------------------------------------------------------------
5518ba839444 | Andrew Apted | 2016-01-20 18:45:10 +1100

TODO update.

------------------------------------------------------------------------
2f83b1983fb5 | Andrew Apted | 2016-01-20 18:43:52 +1100

Checks / vertex : added new test for "dangling" vertices (one which are
only connected to a single line).

------------------------------------------------------------------------
a38e3a4a24ba | Andrew Apted | 2016-01-20 17:18:04 +1100

.gitignore : added "_work" and various MacOS-X crud.

------------------------------------------------------------------------
8da24b1c39ad | Andrew Apted | 2016-01-20 17:09:22 +1100

Browser : fixed recent bug causing the browser to jump to top of list
when clicking on an entry (such as a texture).

------------------------------------------------------------------------
ac2bc6f8bbf6 | Andrew Apted | 2016-01-20 16:45:18 +1100

Code tidying : removed obsolete GetMaxObjectNum() function.

------------------------------------------------------------------------
ca58ba967f23 | Andrew Apted | 2016-01-20 16:43:35 +1100

CMD_LastSelection : validate the new selection (i.e. don't crash if there
turns out to be a bug in the normal invalidation logic).

------------------------------------------------------------------------
cc93a8f9c43a | Andrew Apted | 2016-01-20 16:27:27 +1100

A few fixes for "LastSelection" command, which involved changing the
"mode" parameter of the NewEditMode() methods from char --> obj_type_e
(which is much more sensible).

------------------------------------------------------------------------
cc9db892869d | Andrew Apted | 2016-01-20 15:59:11 +1100

CMD_LastSelection : properly invalidate the last selection if an editing
operation inserts or deletes objects in its range.

------------------------------------------------------------------------
d8a8633063ca | Andrew Apted | 22016-01-20 15:51:35 +1100

Info bar : give the status widget a tooltip with the same message, for
cases when the message is too long to fit on-screen.

------------------------------------------------------------------------
37fd31d0f80b | Andrew Apted | 2016-01-20 15:41:30 +1100

CMD_LastSelection : change editor mode if different than the last
selection (and zoom into the selection, which helps make the mode
change more obvious).

------------------------------------------------------------------------
55c50ce52c87 | Andrew Apted | 2016-01-20 15:34:43 +1100

CMD_LastSelection : got the basic functionality working.

------------------------------------------------------------------------
f9f4f2cda77e | Andrew Apted | 2016-01-20 15:06:45 +1100

Drawing mode : fixed handling of SHIFT + LMB (continue drawing) when
the line connected to an existing used vertex.

------------------------------------------------------------------------
cd3a8b697bfd | Andrew Apted | 2016-01-20 15:01:59 +1100

Replaced "edit.Selected->clear_all()" code --> Selection_Clear().

Also began work on ability to restore the last selection (when possible).

------------------------------------------------------------------------
29320c1f53c2 | Andrew Apted | 2016-01-20 14:15:10 +1100

Selection class : implemented new "test_equal()" method, checks if two
selections are the same.

------------------------------------------------------------------------
f40a855324eb | Andrew Apted | 2016-01-19 22:00:53 +1100

TODO update.

------------------------------------------------------------------------
4ab4adfac0dc | Andrew Apted | 2016-01-19 22:00:14 +1100

CHANGELOG updated.

------------------------------------------------------------------------
ff1b2c5d2b6a | Andrew Apted | 2016-01-19 21:55:37 +1100

Generalized browser : made choice widgets a bit wider.

------------------------------------------------------------------------
b6b47b8ca0e5 | Andrew Apted | 2016-01-19 21:54:39 +1100

gen_types.ugh : expanded "HnF", "LnC" (etc) --> "Highest Floor", "Lowest Ceil" (etc).

------------------------------------------------------------------------
cc97e49d0309 | Andrew Apted | 2016-01-19 21:38:44 +1100

gen_types.ugh : improved various keywords, e.g. target names.

------------------------------------------------------------------------
c5bc0c49356a | Andrew Apted | 2016-01-19 21:25:02 +1100

Generalized browser : ability to reset all fields to default values, and
fixed bug showing the wrong page.

------------------------------------------------------------------------
dbc53c8454c5 | Andrew Apted | 2016-01-19 21:00:42 +1100

Generalized browser : small improvement to previous commit.

------------------------------------------------------------------------
833a5654cff6 | Andrew Apted | 2016-01-19 20:53:47 +1100

Generalized browser : removed the "Gen" button, too much clutter.

Instead: clicking "Choose" when the type is in range will open the
generalized browser, also by right clicking that button.  Plus it can
be opened via the menus.

------------------------------------------------------------------------
5085fac14cc2 | Andrew Apted | 2016-01-19 20:45:45 +1100

Generalized browser : implemented decoding the line_type.

------------------------------------------------------------------------
91680fa56b9c | Andrew Apted | 2016-01-19 20:18:41 +1100

Generalized browser : worked on UpdateGenType() for setting the page and
all the field widgets to match the current linedef type.

Also removed the "SET" button -- changes will take effect immediately
(just like everything else in the LineDef panel).

------------------------------------------------------------------------
040d3c6ebbdc | Andrew Apted | 2016-01-19 19:15:33 +1100

Generalized browser : tweaked layout for extra line in FLOOR/CEILING
categories, and some other stuff for the Model/Monsters duality...

------------------------------------------------------------------------
f793fde39431 | Andrew Apted | 2016-01-19 18:19:20 +1100

gen_types.ugh : moved "Speed" field lower (underneath Target field), and
for FLOOR and CEILING added a "Monsters" field (having same bit position
as the "Model" field -- will need code to handle that properly).

------------------------------------------------------------------------
1086a2117b04 | Andrew Apted | 2016-01-19 17:21:10 +1100

gen_types.ugh : added a default value in each "gen_field" line, and
tweaked some more field names / keywords.

------------------------------------------------------------------------
ba4e660499b8 | Andrew Apted | 2016-01-19 17:05:12 +1100

gen_types.ugh : changed order so that "DOOR" is first, and capitalized
various of the keywords and tweaked a few others.

------------------------------------------------------------------------
603c1d5fcc36 | Andrew Apted | 2016-01-19 17:03:45 +1100

Generalized browser : layout tweak.

------------------------------------------------------------------------
df23936ec62b | Andrew Apted | 2016-01-19 16:41:48 +1100

Generalized browser : implemented creating the choice buttons in each
page, and computing a type value, and fixed a few bugs.

------------------------------------------------------------------------
a30790a7fae3 | Andrew Apted | 2016-01-19 16:02:49 +1100

Generalized browser : changed resize behavior again, match what the other
browsers do (everything follows the left edge).

------------------------------------------------------------------------
cc1f97a5491c | Andrew Apted | 2016-01-19 15:57:58 +1100

Generalized browser : minimise it whenever we change to the GEN browser
(since it looks quite bad otherwise).

------------------------------------------------------------------------
0dba3322afe3 | Andrew Apted | 2016-01-19 14:50:05 +1100

Heretic config : categorized all the flats and textures.

------------------------------------------------------------------------
b541f4c70e5c | Andrew Apted | 2016-01-19 14:13:46 +1100

Hexen config tweak.

------------------------------------------------------------------------
6922aca68c73 | Andrew Apted | 2016-01-19 14:10:09 +1100

Hexen config : categorized all the textures and flats.

------------------------------------------------------------------------
e5c78e090cc6 | Andrew Apted | 2016-01-19 13:01:42 +1100

Browser : only populate the Category widget with non-empty categories.

------------------------------------------------------------------------
419c132ca180 | Andrew Apted | 2016-01-18 23:08:47 +1100

TODO updated.

------------------------------------------------------------------------
4372deb33d8e | Andrew Apted | 2016-01-18 23:03:35 +1100

Generalized browser : implemented apply_callback().

------------------------------------------------------------------------
95fad8495f84 | Andrew Apted | 2016-01-18 22:49:17 +1100

Generalized browser : implemented category callback which shows the
corresponding page (hiding the rest), and support cycling through the
categories.

------------------------------------------------------------------------
c89c229084a8 | Andrew Apted | 2016-01-18 22:20:37 +1100

Generalized browser : create the category and apply widgets, create all
the pages (albeit just empty rects), and handle changes to game_info.

------------------------------------------------------------------------
048c6e57bef6 | Andrew Apted | 2016-01-18 21:18:37 +1100

Generalized browser : fleshed out structure of UI_Generalized_Box class,
added a message box to show when not in BOOM mode.

------------------------------------------------------------------------
90bbb8850446 | Andrew Apted | 2016-01-18 20:54:44 +1100

Generalized browser : fixed resize behavior, tweaked title.

------------------------------------------------------------------------
206d7e8464a1 | Andrew Apted | 2016-01-18 20:34:04 +1100

Generalized type : in LineDef panel, show a basic description for a gen
line, currently it is the trigger + "GENERALIZED" + category name.

------------------------------------------------------------------------
e400500674fe | Andrew Apted | 2016-01-18 19:59:46 +1100

Sector panel : when user enters a large value into type box, store it
directly in sectors -- the panel will show the Boom interpretation.

------------------------------------------------------------------------
7d1b2dc12219 | Andrew Apted | 2016-01-18 19:38:09 +1100

Sector panel : use "BoomSF_XXX" constants for generalized masks.

------------------------------------------------------------------------
60d57d7d9945 | Andrew Apted | 2016-01-18 19:25:57 +1100

Sector panel : the Boom flag widgets now show values for current sector,
and reworked type_callback() to allow setting these values too.

------------------------------------------------------------------------
e96dc17a0625 | Andrew Apted | 2016-01-18 18:22:19 +1100

Sector panel : added widgets at bottom for Boom generalized sector types,
and enable/disable them based on the game_info.  They do not work yet...

------------------------------------------------------------------------
282819b660af | Andrew Apted | 2016-01-18 16:04:35 +1100

Sector panel : got the headroom shortcut buttons working.

------------------------------------------------------------------------
2b8bbdbc19cb | Andrew Apted | 2016-01-18 15:58:51 +1100

Sector panel : began work on buttons for setting headroom...

------------------------------------------------------------------------
bbceb92effdb | Andrew Apted | 2016-01-18 15:30:07 +1100

Generalized types : hide or show "Gen" button depending on game_info.

------------------------------------------------------------------------
fa5b620d1365 | Andrew Apted | 2016-01-18 15:08:24 +1100

Added a .gitignore file, ignore objects (*.o) and executables.

------------------------------------------------------------------------
cb6a39ba1ebb | Andrew Apted | 2016-01-18 15:03:41 +1100

Create obj_linux/ and obj_win32/ folders, which were lost after the
conversion from SVN, and added .gitignore files in them.

------------------------------------------------------------------------
0b46a7d4032f | Andrew Apted | 2016-01-17 13:11:33 +0000

TODO update.

------------------------------------------------------------------------
9af1f2337766 | Andrew Apted | 2016-01-17 13:10:22 +0000

Generalized types : added "Gen" button to LineDef panel.



====================================================
    DEVELOPMENT IN SVN REPOSITORY
====================================================

------------------------------------------------------------------------
r1909 | ajapted | 2016-01-17 23:44:49 +1100 (Sun, 17 Jan 2016) | 3 lines

Generalized types : in the Browser, support ACTIVE_GENERALIZED as the
special value for "active" member, support 'G' in ChangeMode() method.

------------------------------------------------------------------------
r1908 | ajapted | 2016-01-17 23:20:25 +1100 (Sun, 17 Jan 2016) | 2 lines

CMD_BrowserMode : support a "genline" keyword.

------------------------------------------------------------------------
r1907 | ajapted | 2016-01-17 23:18:21 +1100 (Sun, 17 Jan 2016) | 2 lines

Menu : added "Generalized Line" command to Browser menu.

------------------------------------------------------------------------
r1906 | ajapted | 2016-01-17 23:13:56 +1100 (Sun, 17 Jan 2016) | 3 lines

Generalized types : began work on a special browser box for displaying
and editing a generalized type (via new UI_Generalized_Box class).

------------------------------------------------------------------------
r1905 | ajapted | 2016-01-17 23:00:16 +1100 (Sun, 17 Jan 2016) | 3 lines

gen_types.ugh : removed the mask values, we simply compute it from the
bits and shift values.

------------------------------------------------------------------------
r1904 | ajapted | 2016-01-17 21:51:04 +1100 (Sun, 17 Jan 2016) | 3 lines

Replaced "Aspect ratio" preference with "Pixel aspect ratio", now just
a simple number input box.  The config variable was also renamed.

------------------------------------------------------------------------
r1903 | ajapted | 2016-01-17 21:07:11 +1100 (Sun, 17 Jan 2016) | 3 lines

CMD_CopyProperties : implemented /reverse flag which copies from the
highlighted object to the selected object(s).

------------------------------------------------------------------------
r1902 | ajapted | 2016-01-17 18:55:36 +1100 (Sun, 17 Jan 2016) | 2 lines

TODO.txt updated.

------------------------------------------------------------------------
r1901 | ajapted | 2016-01-17 18:52:10 +1100 (Sun, 17 Jan 2016) | 9 lines

CMD_Delete : allow sectors to be considered "unused" (and hence removed)
if were are deleting linedefs (or verts) and the only linedefs remaining
will not have a valid sector reference opposite them.

This change was prompted by the case of removing the 3rd vertex in a
triangle poking out from other geometry, which would delete the two
linedefs but leave the one opposite the vertex with broken geometry
(still two sided, with a sidedef facing the now defunct sector).

------------------------------------------------------------------------
r1900 | ajapted | 2016-01-17 18:36:56 +1100 (Sun, 17 Jan 2016) | 2 lines

Check / vertices : ability to SHOW unused vertices.

------------------------------------------------------------------------
r1899 | ajapted | 2016-01-17 18:10:22 +1100 (Sun, 17 Jan 2016) | 2 lines

CMD_Delete : remove unused sectors in vertex/linedef mode, fixed some bugs.

------------------------------------------------------------------------
r1898 | ajapted | 2016-01-17 17:54:25 +1100 (Sun, 17 Jan 2016) | 2 lines

Improved the code in CMD_Delete().

------------------------------------------------------------------------
r1897 | ajapted | 2016-01-17 16:00:12 +1100 (Sun, 17 Jan 2016) | 4 lines

Improved FindClosestCrossPoint() to treat vertices as quite large, the
exact size depending on the current zoom factor.  This makes it easier
for the user to draw a line through a vertex and have it autosplit.

------------------------------------------------------------------------
r1896 | ajapted | 2016-01-17 15:21:30 +1100 (Sun, 17 Jan 2016) | 2 lines

Proper fix for previous commit (that commit was causing unclosed sectors).

------------------------------------------------------------------------
r1895 | ajapted | 2016-01-17 14:53:14 +1100 (Sun, 17 Jan 2016) | 4 lines

When merging two connected linedefs (by dragging a vertex),fixed the
handling when one of the lines is one-sided -- caused bad orientation
of the merged line and/or missing middle texture.

------------------------------------------------------------------------
r1894 | ajapted | 2016-01-17 14:19:48 +1100 (Sun, 17 Jan 2016) | 2 lines

Factored out a linedef utility function: LD_FixForLostSide()

------------------------------------------------------------------------
r1893 | ajapted | 2016-01-17 13:45:16 +1100 (Sun, 17 Jan 2016) | 3 lines

Fixed creating overlapping lines when deleting 3rd vertex of a triangle
(caused by merging the two linedefs connected at that vertex).

------------------------------------------------------------------------
r1892 | ajapted | 2016-01-17 00:45:42 +1100 (Sun, 17 Jan 2016) | 4 lines

Added common/xlat_doom.cfg and common/xlat_hexen.cfg files.  These are not
used yet, but later will contain directives for converting between the two
supported map formats (Doom and Hexen).

------------------------------------------------------------------------
r1891 | ajapted | 2016-01-17 00:13:51 +1100 (Sun, 17 Jan 2016) | 2 lines

Browser : fixed things inserted by SPACE not appearing in RECENT category.

------------------------------------------------------------------------
r1890 | ajapted | 2016-01-17 00:03:49 +1100 (Sun, 17 Jan 2016) | 3 lines

Browser : improved the RECENT category, properly sort items so that the
most recent ones are near the top.

------------------------------------------------------------------------
r1889 | ajapted | 2016-01-16 21:42:55 +1100 (Sat, 16 Jan 2016) | 4 lines

Browser : don't call RecentUpdate() directly from the insert() method of
the recently used lists, since RecentUpdate() might be very expensive
(e.g. needing to sort the whole texture list).

------------------------------------------------------------------------
r1888 | ajapted | 2016-01-16 20:53:28 +1100 (Sat, 16 Jan 2016) | 3 lines

Disabled the MMB doing an "Insert" command, that functionality has been
superceded by the new drawing mode.

------------------------------------------------------------------------
r1887 | ajapted | 2016-01-16 20:46:13 +1100 (Sat, 16 Jan 2016) | 2 lines

Menu : added "Recent Textures" (etc) commands to the Browser menu.

------------------------------------------------------------------------
r1886 | ajapted | 2016-01-16 20:44:13 +1100 (Sat, 16 Jan 2016) | 2 lines

Browser : increased size of RECENT category to 30 (was 11).

------------------------------------------------------------------------
r1885 | ajapted | 2016-01-16 18:45:53 +1100 (Sat, 16 Jan 2016) | 2 lines

CHANGELOG and TODO update.

------------------------------------------------------------------------
r1884 | ajapted | 2016-01-16 18:34:21 +1100 (Sat, 16 Jan 2016) | 3 lines

Disable a check for potential linedef overlaps -- not needed with the new
autosplit logic.

------------------------------------------------------------------------
r1883 | ajapted | 2016-01-16 18:33:22 +1100 (Sat, 16 Jan 2016) | 2 lines

FindClosestCrossPoint : finished the implementation.

------------------------------------------------------------------------
r1882 | ajapted | 2016-01-16 18:21:42 +1100 (Sat, 16 Jan 2016) | 3 lines

FindClosestCrossPoint : tweak vertex check, worked on the linedef check
(e.g. the intersection calculation, which seems to be working).

------------------------------------------------------------------------
r1881 | ajapted | 2016-01-16 15:52:16 +1100 (Sat, 16 Jan 2016) | 2 lines

Detect vertex crossing in FindClosestCrossPoint().

------------------------------------------------------------------------
r1880 | ajapted | 2016-01-16 14:11:33 +1100 (Sat, 16 Jan 2016) | 2 lines

Began work on new FindClosestCrossPoint() function....

------------------------------------------------------------------------
r1879 | ajapted | 2016-01-16 13:35:43 +1100 (Sat, 16 Jan 2016) | 4 lines

Implemented high-level logic for Insert_LineDef_autosplit(), which will
check if the new line crosses any existing lines or vertices and if so
automatically create splits and multiple new linedefs (as needed).

------------------------------------------------------------------------
r1878 | ajapted | 2016-01-16 13:10:33 +1100 (Sat, 16 Jan 2016) | 5 lines

Hexen : use "special" instead of "line" in the game definition file.

In the code, temporarily made "special" synonymous with "line", though
later they will need to be separate tables.

------------------------------------------------------------------------
r1877 | ajapted | 2016-01-16 12:16:33 +1100 (Sat, 16 Jan 2016) | 2 lines

LineDef panel : made the Hexen arg boxes a bit wider.

------------------------------------------------------------------------
r1876 | ajapted | 2016-01-15 23:19:20 +1100 (Fri, 15 Jan 2016) | 2 lines

Ports : include "gen_types" from the BOOM definition file.

------------------------------------------------------------------------
r1875 | ajapted | 2016-01-15 23:14:43 +1100 (Fri, 15 Jan 2016) | 3 lines

Generalized types : implemented parsing of "gen_line" and "gen_field"
commands (in the gen_types.ugh file).

------------------------------------------------------------------------
r1874 | ajapted | 2016-01-15 22:42:58 +1100 (Fri, 15 Jan 2016) | 3 lines

Generalized types : define the structures that the parsing code will
store the information into.

------------------------------------------------------------------------
r1873 | ajapted | 2016-01-15 22:25:14 +1100 (Fri, 15 Jan 2016) | 3 lines

gen_types.ugh : fleshed out remaining types (LIFT, STAIR, CRUSHER) and
tweaked a few other things.

------------------------------------------------------------------------
r1872 | ajapted | 2016-01-15 22:08:23 +1100 (Fri, 15 Jan 2016) | 2 lines

gen_types.ugh : added fields for CEILING, DOOR and KEY DOOR.

------------------------------------------------------------------------
r1871 | ajapted | 2016-01-15 21:53:24 +1100 (Fri, 15 Jan 2016) | 3 lines

Began work on 'common/gen_types.ugh' file which defines all the BOOM
generalized line types.  [ it will require new code too... ]

------------------------------------------------------------------------
r1870 | ajapted | 2016-01-15 20:54:59 +1100 (Fri, 15 Jan 2016) | 2 lines

Find and Replace : added 'X' button to hide the panel.

------------------------------------------------------------------------
r1869 | ajapted | 2016-01-15 20:51:09 +1100 (Fri, 15 Jan 2016) | 2 lines

Default Props : added an 'X' button to hide the panel.

------------------------------------------------------------------------
r1868 | ajapted | 2016-01-15 20:17:30 +1100 (Fri, 15 Jan 2016) | 2 lines

TODO updated.

------------------------------------------------------------------------
r1867 | ajapted | 2016-01-15 20:16:54 +1100 (Fri, 15 Jan 2016) | 2 lines

README : updated some key combos (e.g. SPACE + SHIFT)

------------------------------------------------------------------------
r1866 | ajapted | 2016-01-15 20:11:16 +1100 (Fri, 15 Jan 2016) | 3 lines

Bindings : added /nofill flag to CMD-SPACE and CMD-INSERT, so that they
behave the same as the hard-coded behavior of the LMB.

------------------------------------------------------------------------
r1865 | ajapted | 2016-01-15 20:08:30 +1100 (Fri, 15 Jan 2016) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1864 | ajapted | 2016-01-15 20:03:36 +1100 (Fri, 15 Jan 2016) | 3 lines

Drawing mode : LMB + SHIFT now continues drawing mode (in cases where it
normally stops) and LMB + CTRL now inhibits the creation of new sectors.

------------------------------------------------------------------------
r1863 | ajapted | 2016-01-15 19:54:09 +1100 (Fri, 15 Jan 2016) | 3 lines

Implemented /nofill flag for CMD_Insert command, in vertex mode it prevents
creating any new sectors.

------------------------------------------------------------------------
r1862 | ajapted | 2016-01-15 18:28:21 +1100 (Fri, 15 Jan 2016) | 2 lines

Drawing mode : cancel drawing mode if the source vertex is deleted.

------------------------------------------------------------------------
r1861 | ajapted | 2016-01-15 17:47:22 +1100 (Fri, 15 Jan 2016) | 4 lines

Drawing mode : if second vertex is on a line connected to first one,
merely select them both.  This allows to select numerous vertices even
when drawing mode begins at first one.

------------------------------------------------------------------------
r1860 | ajapted | 2016-01-15 17:14:37 +1100 (Fri, 15 Jan 2016) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1859 | ajapted | 2016-01-15 17:11:33 +1100 (Fri, 15 Jan 2016) | 2 lines

Sector panel : right click on floor/ceiling flat sets it to default.

------------------------------------------------------------------------
r1858 | ajapted | 2016-01-15 17:06:42 +1100 (Fri, 15 Jan 2016) | 3 lines

LineDef panel : right-clicking on a texture sets it to the default, or "-"
for the rail textures.

------------------------------------------------------------------------
r1857 | ajapted | 2016-01-15 00:57:18 +1100 (Fri, 15 Jan 2016) | 4 lines

When inserting a linedef which splits a sector, ensure the line faces a
consistent way (in other words, make the line's end vertex be the second
one selected or created).

------------------------------------------------------------------------
r1856 | ajapted | 2016-01-13 20:31:44 +1100 (Wed, 13 Jan 2016) | 2 lines

Drawing mode : exit drawing mode on the "Unselect All" command.

------------------------------------------------------------------------
r1855 | ajapted | 2016-01-13 20:11:04 +1100 (Wed, 13 Jan 2016) | 2 lines

Drawing mode : fixed bug beginning to draw when edit mode != VERTEX.

------------------------------------------------------------------------
r1854 | ajapted | 2016-01-13 20:01:18 +1100 (Wed, 13 Jan 2016) | 2 lines

Replaced "edit.RedrawMap = 1" with a function call: RedrawMap()

------------------------------------------------------------------------
r1853 | ajapted | 2016-01-13 19:47:58 +1100 (Wed, 13 Jan 2016) | 5 lines

Drawing mode : begin drawing on mouse release after clicking on a vertex
and not dragging it, and when no other vertices were selected.

This is now working as a user would expect.

------------------------------------------------------------------------
r1852 | ajapted | 2016-01-13 19:01:08 +1100 (Wed, 13 Jan 2016) | 3 lines

When showing a split-line, store X/Y coordinate in the editor state
(instead of recomputing them in Vertex_Insert).

------------------------------------------------------------------------
r1851 | ajapted | 2016-01-13 18:35:55 +1100 (Wed, 13 Jan 2016) | 4 lines

Drawing mode : don't draw a vertex when another vertex is highlighted,
or when split-line is active.  If another vertex is highlighted, "snap"
the line onto it (since inserting will use it as the new endpoint).

------------------------------------------------------------------------
r1850 | ajapted | 2016-01-13 18:15:17 +1100 (Wed, 13 Jan 2016) | 2 lines

Drawing mode : worked on making it a proper action: ACT_DRAW_LINE.

------------------------------------------------------------------------
r1849 | ajapted | 2016-01-12 21:42:11 +1100 (Tue, 12 Jan 2016) | 2 lines

Sector rendering : use the dummy image for unknown flats.

------------------------------------------------------------------------
r1848 | ajapted | 2016-01-12 21:38:25 +1100 (Tue, 12 Jan 2016) | 4 lines

Reworked code for creating dummy textures, they are now cached by functions
in im_img.cc (IM_MissingTex etc) instead of r_render.cc, and increased the
size from 32x32 --> 64x64.

------------------------------------------------------------------------
r1847 | ajapted | 2016-01-12 19:15:03 +1100 (Tue, 12 Jan 2016) | 4 lines

Vertex drawing : draw a vertex too (as well as the red line) and handle
grid-snapping properly.  Fixed several issues when inserting (generally
turning off the drawing mode).

------------------------------------------------------------------------
r1846 | ajapted | 2016-01-12 18:42:20 +1100 (Tue, 12 Jan 2016) | 4 lines

Began work on a "drawing mode", after inserting a vertex we continuously
draw a red line from it to where the next vertex will go, and allow a
simple left click to insert the next vertex.  Quite buggy atm...

------------------------------------------------------------------------
r1845 | ajapted | 2016-01-12 16:52:14 +1100 (Tue, 12 Jan 2016) | 2 lines

Fixed mouse-wheel zooming around wrong spot after loading a new map.

------------------------------------------------------------------------
r1844 | ajapted | 2016-01-12 16:39:52 +1100 (Tue, 12 Jan 2016) | 2 lines

Sector rendering : save/restore the state to the cache .dat file.

------------------------------------------------------------------------
r1843 | ajapted | 2016-01-12 16:30:30 +1100 (Tue, 12 Jan 2016) | 2 lines

CHANGELOG updated.

------------------------------------------------------------------------
r1842 | ajapted | 2016-01-12 16:29:00 +1100 (Tue, 12 Jan 2016) | 3 lines

Menu : added "Sector Rendering" choice to the View menu, implemented via
new 'sector_render_mode' field in the editor_state structure.

------------------------------------------------------------------------
r1841 | ajapted | 2016-01-11 14:06:12 +1100 (Mon, 11 Jan 2016) | 7 lines

ALL GAMES : reworked color definitions:
* sky is now a fairly light blue
* unknown_tex is as close to bright cyan as possible
* unknown_flat is a fairly bright green
* wall colors are grayscale
* floor colors are a light brown

------------------------------------------------------------------------
r1840 | ajapted | 2016-01-11 13:44:02 +1100 (Mon, 11 Jan 2016) | 3 lines

Replaced "R3D_Gamma" command with "Gamma" command so it can be used in
general scope, and fixed the F11 key in the bindings.cfg file.

------------------------------------------------------------------------
r1839 | ajapted | 2016-01-11 13:33:50 +1100 (Mon, 11 Jan 2016) | 6 lines

Changed TRANS_PIXEL from 247 --> 255, which is more friendly to Heretic
and Hexen games.

Also updated COLORMAP loader to replace any TRANS_PIXEL values, just in
case some code uses it when creating an Img_c.

------------------------------------------------------------------------
r1838 | ajapted | 2016-01-11 11:33:58 +1100 (Mon, 11 Jan 2016) | 3 lines

Canvas : fleshed out support for different modes in RenderSector(), e.g.
solid rendering for an unknown texture using the game specific color.

------------------------------------------------------------------------
r1837 | ajapted | 2016-01-10 20:48:36 +1100 (Sun, 10 Jan 2016) | 2 lines

Canvas : compute proper texture coords for rendering sector flats.

------------------------------------------------------------------------
r1836 | ajapted | 2016-01-10 20:33:47 +1100 (Sun, 10 Jan 2016) | 3 lines

Canvas : rendering sector flats is working, albeit not scaled or translated
properly yet....

------------------------------------------------------------------------
r1835 | ajapted | 2016-01-10 20:20:31 +1100 (Sun, 10 Jan 2016) | 2 lines

Canvas : partial work on rendering sectors with a flat texture...

------------------------------------------------------------------------
r1834 | ajapted | 2016-01-10 20:06:20 +1100 (Sun, 10 Jan 2016) | 2 lines

Canvas : ability to render sectors as solid, showing their light levels.

------------------------------------------------------------------------
r1833 | ajapted | 2016-01-10 19:34:40 +1100 (Sun, 10 Jan 2016) | 3 lines

Added config file variables: light_bump_small, _medium, _large.
The default for non-modifier light button is 16 units (up or down).

------------------------------------------------------------------------
r1832 | ajapted | 2016-01-10 19:26:21 +1100 (Sun, 10 Jan 2016) | 2 lines

Added SectorLightColor() utility function.

------------------------------------------------------------------------
r1831 | ajapted | 2016-01-10 18:40:08 +1100 (Sun, 10 Jan 2016) | 2 lines

README : some updates.

------------------------------------------------------------------------
r1830 | ajapted | 2016-01-10 18:37:36 +1100 (Sun, 10 Jan 2016) | 2 lines

TODO update.

------------------------------------------------------------------------
r1829 | ajapted | 2016-01-10 18:31:57 +1100 (Sun, 10 Jan 2016) | 7 lines

Added workaround for loading BOOM definitions with games that are not
supported by BOOM (Heretic and Hexen) -- we skip parsing the boom.ugh
config file for certain games (done via new "exclude_game" directive).

A better system for specifying which game + port combinations are
usable is definitely needed -- something to be tackled later on.

------------------------------------------------------------------------
r1828 | ajapted | 2016-01-10 18:10:47 +1100 (Sun, 10 Jan 2016) | 2 lines

Version bump and updated printf'd copyright year for 2016.

------------------------------------------------------------------------
r1827 | ajapted | 2016-01-10 18:09:32 +1100 (Sun, 10 Jan 2016) | 2 lines

About window : credit Ioan Chera in the copyright lines.

------------------------------------------------------------------------
r1826 | ajapted | 2016-01-10 17:09:59 +1100 (Sun, 10 Jan 2016) | 2 lines

Eternity support : added a "3D MidTex" checkbox to the LineDef panel.

------------------------------------------------------------------------
r1825 | ajapted | 2016-01-10 16:54:23 +1100 (Sun, 10 Jan 2016) | 2 lines

code : removed unused GetAngleName() and GetWhenName() functions.

------------------------------------------------------------------------
r1824 | ajapted | 2016-01-10 16:51:01 +1100 (Sun, 10 Jan 2016) | 3 lines

Only show the "passthru" linedef flag when the game/port supports it.
Added "feature pass_through 1" to the BOOM definition file.

------------------------------------------------------------------------
r1823 | ajapted | 2016-01-10 16:39:06 +1100 (Sun, 10 Jan 2016) | 3 lines

Hexen (etc) : removed UpdateMapFormatInfo() methods, use UpdateGameInfo()
for map format stuff too.

------------------------------------------------------------------------
r1822 | ajapted | 2016-01-10 16:08:23 +1100 (Sun, 10 Jan 2016) | 3 lines

UI : in Sector panel, moved the "Headroom" widget below the rest, with a
few other tweaks to the layout.

------------------------------------------------------------------------
r1821 | ajapted | 2016-01-10 15:25:23 +1100 (Sun, 10 Jan 2016) | 3 lines

UI : code tidying -- remove explicit add() calls in UI_Sector and
UI_NodeDialog constructors.

------------------------------------------------------------------------
r1820 | ajapted | 2016-01-10 15:18:30 +1100 (Sun, 10 Jan 2016) | 2 lines

UI : improved layout of Sector panel, more roomy.

------------------------------------------------------------------------
r1819 | ajapted | 2016-01-10 15:09:26 +1100 (Sun, 10 Jan 2016) | 2 lines

UI : tweaked position of UI_Nombre in each editing panel.

------------------------------------------------------------------------
r1818 | ajapted | 2016-01-10 14:54:23 +1100 (Sun, 10 Jan 2016) | 2 lines

UI : offset the first column of flags in the LineDef panel.

------------------------------------------------------------------------
r1817 | ajapted | 2016-01-10 14:49:24 +1100 (Sun, 10 Jan 2016) | 2 lines

UI : tweaked layout in the LineDef panel, bit more vertical spacing.

------------------------------------------------------------------------
r1816 | ajapted | 2016-01-10 13:27:01 +1100 (Sun, 10 Jan 2016) | 2 lines

Hexen : use tooltips to show what arguments of a line/thing special do.

------------------------------------------------------------------------
r1815 | ajapted | 2016-01-10 13:16:50 +1100 (Sun, 10 Jan 2016) | 3 lines

Hexen : when showing args in LineDef / Thing panels, show a zero instead
of a blank when the special for the line/thing actually uses that arg.

------------------------------------------------------------------------
r1814 | ajapted | 2016-01-10 12:26:49 +1100 (Sun, 10 Jan 2016) | 3 lines

Inserting vertices with SHIFT always selects the new vertex.
This is achieved via new "/select" flag for the Insert key command.

------------------------------------------------------------------------
r1813 | ajapted | 2016-01-10 11:02:06 +1100 (Sun, 10 Jan 2016) | 2 lines

Canvas : fixed some bugs in 2D sector rendering (e.g. min_y/max_y calcs).

------------------------------------------------------------------------
r1812 | ajapted | 2016-01-10 01:10:37 +1100 (Sun, 10 Jan 2016) | 2 lines

Canvas / RenderSector : fixed CMP_X to place NULLs at end of list.

------------------------------------------------------------------------
r1811 | ajapted | 2016-01-10 01:01:36 +1100 (Sun, 10 Jan 2016) | 3 lines

Canvas : got solid rendering of a rectangular sector working.  The next
step will be to render flats....

------------------------------------------------------------------------
r1810 | ajapted | 2016-01-10 00:52:18 +1100 (Sun, 10 Jan 2016) | 4 lines

Canvas : for 2D sector rendering, compute the "side" field, added "x"
field for the computed X values, and implemented finding the spans.

------------------------------------------------------------------------
r1809 | ajapted | 2016-01-10 00:30:14 +1100 (Sun, 10 Jan 2016) | 2 lines

TODO.txt updated.

------------------------------------------------------------------------
r1808 | ajapted | 2016-01-10 00:25:23 +1100 (Sun, 10 Jan 2016) | 2 lines

CHANGELOG : minor rearrange.

------------------------------------------------------------------------
r1807 | ajapted | 2016-01-10 00:14:01 +1100 (Sun, 10 Jan 2016) | 2 lines

Canvas : more work on experimental 2D sector rendering....

------------------------------------------------------------------------
r1806 | ajapted | 2016-01-09 21:19:26 +1100 (Sat, 09 Jan 2016) | 2 lines

Hexen : fully support the special type in the Thing panel.

------------------------------------------------------------------------
r1805 | ajapted | 2016-01-09 21:04:17 +1100 (Sat, 09 Jan 2016) | 3 lines

Hexen : implemented the Thing special "Choose" button, and allow a click
on a browser item to set the special type.

------------------------------------------------------------------------
r1804 | ajapted | 2016-01-09 20:52:13 +1100 (Sat, 09 Jan 2016) | 2 lines

Canvas : began work on experimental RenderSector() method....

------------------------------------------------------------------------
r1803 | ajapted | 2016-01-09 20:05:36 +1100 (Sat, 09 Jan 2016) | 2 lines

Hexen : support showing and editing arguments in the Thing panel.

------------------------------------------------------------------------
r1802 | ajapted | 2016-01-08 19:43:59 +1100 (Fri, 08 Jan 2016) | 6 lines

Thing panel : reorganized it e.g. moved sprite above the arrow circle
(closer to the Type / Desc widgets), and a few other tweaks.

This was prompted by a need for all the new Hexen stuff to fit in the
minimum window size (which it now does).

------------------------------------------------------------------------
r1801 | ajapted | 2016-01-08 18:45:50 +1100 (Fri, 08 Jan 2016) | 3 lines

Hexen : added "Special", "Args" (etc) widgets in the Thing panel.
They are not implemented yet....

------------------------------------------------------------------------
r1800 | ajapted | 2016-01-08 18:22:52 +1100 (Fri, 08 Jan 2016) | 2 lines

Hexen : implemented "dormant" flag in the Thing panel.

------------------------------------------------------------------------
r1799 | ajapted | 2016-01-08 18:11:33 +1100 (Fri, 08 Jan 2016) | 2 lines

Hexen : fixed wrong "mask" values for SP/COOP/DM buttons (used by callback function).

------------------------------------------------------------------------
r1798 | ajapted | 2016-01-08 17:10:03 +1100 (Fri, 08 Jan 2016) | 2 lines

Hexen : support the class flags (Fighter/Cleric/Magic) in Thing panel.

------------------------------------------------------------------------
r1797 | ajapted | 2016-01-08 16:46:35 +1100 (Fri, 08 Jan 2016) | 2 lines

Hexen : support game mode flags (SP, COOP, DM) in the Things panel.

------------------------------------------------------------------------
r1796 | ajapted | 2016-01-08 16:31:15 +1100 (Fri, 08 Jan 2016) | 3 lines

Check things : updated stuck-things detection to handle HEXEN flags,
especially the class bits.

------------------------------------------------------------------------
r1795 | ajapted | 2016-01-08 16:24:10 +1100 (Fri, 08 Jan 2016) | 2 lines

Fixed a bug recently introduced in the stuck-thing detection.

------------------------------------------------------------------------
r1794 | ajapted | 2016-01-08 16:18:24 +1100 (Fri, 08 Jan 2016) | 2 lines

Added config file variable: default_gamma

------------------------------------------------------------------------
r1793 | ajapted | 2016-01-08 15:08:53 +1100 (Fri, 08 Jan 2016) | 2 lines

Added config file variables: floor_bump_small, _medium, _large.

------------------------------------------------------------------------
r1792 | ajapted | 2016-01-06 14:49:05 +1100 (Wed, 06 Jan 2016) | 4 lines

Makefile : the install target now deletes the old "freedoom.ugh" config,
preventing it from appearing in the Manage Project dialog (along with
freedoom1 and freedoom2, which is confusing).

------------------------------------------------------------------------
r1791 | ajapted | 2015-12-31 14:31:48 +1100 (Thu, 31 Dec 2015) | 3 lines

CHANGELOG : brought the changelog completely up-to-date, and reorganised
with most important elements at the top.

------------------------------------------------------------------------
r1790 | ajapted | 2015-12-30 12:45:23 +1100 (Wed, 30 Dec 2015) | 3 lines

Hexen : in Linedef panel, support setting new Activation values via the
choice button.

------------------------------------------------------------------------
r1789 | ajapted | 2015-12-30 12:35:29 +1100 (Wed, 30 Dec 2015) | 2 lines

Hexen : properly update the Activation choice when selecting/hilighting lines.

------------------------------------------------------------------------
r1788 | ajapted | 2015-12-30 12:14:47 +1100 (Wed, 30 Dec 2015) | 2 lines

Thing panel : moved the arrow circle (up and left) and made the buttons bigger.

------------------------------------------------------------------------
r1787 | ajapted | 2015-12-30 12:10:41 +1100 (Wed, 30 Dec 2015) | 2 lines

UI : made the right panel slightly wider.

------------------------------------------------------------------------
r1786 | ajapted | 2015-12-30 12:06:21 +1100 (Wed, 30 Dec 2015) | 3 lines

Hexen : in LineDef panel added a choice widget for the activation mode of
the linedef -- with choices such as W1, SR, G1 (etc....)

------------------------------------------------------------------------
r1785 | ajapted | 2015-12-30 11:30:21 +1100 (Wed, 30 Dec 2015) | 3 lines

Map loading : allow loading a map with no vertices, no linedefs (etc...)
Also factored out some common code in linedef loaders: ValidateSidedefs()

------------------------------------------------------------------------
r1784 | ajapted | 2015-12-29 23:27:54 +1100 (Tue, 29 Dec 2015) | 2 lines

Hexen : made the Linedef panel actually show the 5 arguments.

------------------------------------------------------------------------
r1783 | ajapted | 2015-12-29 23:13:56 +1100 (Tue, 29 Dec 2015) | 3 lines

Hexen : in Linedef panel show the five "Args:" boxes when in Hexen mode,
and implemented args_callback() which can set new values.

------------------------------------------------------------------------
r1782 | ajapted | 2015-12-29 22:51:03 +1100 (Tue, 29 Dec 2015) | 2 lines

Find / Replace : support the "tag" filter for Hexen things (TID).

------------------------------------------------------------------------
r1781 | ajapted | 2015-12-29 19:43:14 +1100 (Tue, 29 Dec 2015) | 3 lines

Changed DEFAULT_PORT to be "vanilla" instead of "boom", because Boom is
only a DOOM engine and does not support Heretic or Hexen.

------------------------------------------------------------------------
r1780 | ajapted | 2015-12-29 19:36:23 +1100 (Tue, 29 Dec 2015) | 2 lines

HEXEN conf : added four linegroups: Animated, Door, Lift, Stairs.

------------------------------------------------------------------------
r1779 | ajapted | 2015-12-29 19:20:09 +1100 (Tue, 29 Dec 2015) | 2 lines

DOOM conf : minor comment fix (syntax of "line" command).

------------------------------------------------------------------------
r1778 | ajapted | 2015-12-29 19:15:57 +1100 (Tue, 29 Dec 2015) | 3 lines

Browser : fixed alpha sorting of line specials for Hexen (it did not handle
the lack of a S1/WR/etc action name at beginning of the description).

------------------------------------------------------------------------
r1777 | ajapted | 2015-12-29 19:05:15 +1100 (Tue, 29 Dec 2015) | 2 lines

HEXEN conf : added two missing specials: 138 "Floor_Waggle" and 109 "Force_Lightning".

------------------------------------------------------------------------
r1776 | ajapted | 2015-12-29 18:58:34 +1100 (Tue, 29 Dec 2015) | 2 lines

HEXEN conf : added missing line/thing special 0 ("NOTHING").

------------------------------------------------------------------------
r1775 | ajapted | 2015-12-29 18:48:31 +1100 (Tue, 29 Dec 2015) | 2 lines

Game def parser : support arg1..arg5 names in "line" commands (for Hexen).

------------------------------------------------------------------------
r1774 | ajapted | 2015-12-29 18:38:29 +1100 (Tue, 29 Dec 2015) | 2 lines

HEXEN conf : finished the line/thing specials.

------------------------------------------------------------------------
r1773 | ajapted | 2015-12-29 18:20:15 +1100 (Tue, 29 Dec 2015) | 3 lines

HEXEN conf : more work on line/thing specials, simplifying and/or abbreviating
some names and renamed a few argument names.

------------------------------------------------------------------------
r1772 | ajapted | 2015-12-29 17:19:27 +1100 (Tue, 29 Dec 2015) | 3 lines

HEXEN conf : more work on the specials, put all types into an appropriate
category and renamed a few specials.

------------------------------------------------------------------------
r1771 | ajapted | 2015-12-29 17:06:36 +1100 (Tue, 29 Dec 2015) | 3 lines

HEXEN config : began work to define all the line/thing specials, based
on the Unofficial Hexen Specifications.

------------------------------------------------------------------------
r1770 | ajapted | 2015-12-29 14:55:02 +1100 (Tue, 29 Dec 2015) | 3 lines

Use absolute paths for resource filenames in __EUREKA lump, since that is
more robust (allows moving the wad to another folder).

------------------------------------------------------------------------
r1769 | ajapted | 2015-12-29 14:42:04 +1100 (Tue, 29 Dec 2015) | 8 lines

Added a built-in "DOGS" sprite for when port is Boom (or compatible), as
that sprite is generally not available in the IWADs and showing a missing
sprite in the browser was quite ugly / distracting.

This dog sprite was sourced from the OpenGameArt.org website.
Authors are 'Benalene' and 'qudobup' (users on the OGA site).
License is CC-BY 3.0 (Creative Commons Attribution license).

------------------------------------------------------------------------
r1768 | ajapted | 2015-12-29 14:33:02 +1100 (Tue, 29 Dec 2015) | 3 lines

Image class : added IM_CreateFromText() function which can generate an Img_c
from some builtin strings and palette [ not unlike XPM ].

------------------------------------------------------------------------
r1767 | ajapted | 2015-12-29 14:04:29 +1100 (Tue, 29 Dec 2015) | 2 lines

Removed RGB_INVALID constant -- not used anywhere.

------------------------------------------------------------------------
r1766 | ajapted | 2015-12-27 21:29:19 +1100 (Sun, 27 Dec 2015) | 2 lines

Configs : updated comments to remove "should not exceed 24 characters" advice.

------------------------------------------------------------------------
r1765 | ajapted | 2015-12-27 21:24:32 +1100 (Sun, 27 Dec 2015) | 3 lines

Hexen : define the new linedef flags (MLF_Repeatable, MLF_Activation)
plus some ZDoom flags.  Also define the activation values (SPAC_XXX).

------------------------------------------------------------------------
r1764 | ajapted | 2015-12-27 19:23:52 +1100 (Sun, 27 Dec 2015) | 2 lines

HEXEN config : finished sector types.

------------------------------------------------------------------------
r1763 | ajapted | 2015-12-27 19:13:12 +1100 (Sun, 27 Dec 2015) | 2 lines

HEXEN conf : worked on adding all the Sector specials...

------------------------------------------------------------------------
r1762 | ajapted | 2015-12-27 18:09:37 +1100 (Sun, 27 Dec 2015) | 2 lines

HEXEN config : a few fixes (e.g. Cauldron sprites).

------------------------------------------------------------------------
r1761 | ajapted | 2015-12-27 18:07:25 +1100 (Sun, 27 Dec 2015) | 2 lines

HEXEN config : finished improving the names of things.

------------------------------------------------------------------------
r1760 | ajapted | 2015-12-27 17:54:22 +1100 (Sun, 27 Dec 2015) | 2 lines

HEXEN conf : worked on improving names of decorative things...

------------------------------------------------------------------------
r1759 | ajapted | 2015-12-27 17:17:35 +1100 (Sun, 27 Dec 2015) | 2 lines

HEXEN config : split decorations by adding new "Natural" category.

------------------------------------------------------------------------
r1758 | ajapted | 2015-12-27 17:06:56 +1100 (Sun, 27 Dec 2015) | 2 lines

HEXEN config : added all remaining thing types (though names need fixing...)

------------------------------------------------------------------------
r1757 | ajapted | 2015-12-27 16:49:46 +1100 (Sun, 27 Dec 2015) | 2 lines

Hexen config : added thing types 10500-10503 and 8500-8509.

------------------------------------------------------------------------
r1756 | ajapted | 2015-12-27 16:41:03 +1100 (Sun, 27 Dec 2015) | 2 lines

HEXEN config : added the puzzle-piece items (plus a new category for them).

------------------------------------------------------------------------
r1755 | ajapted | 2015-12-27 16:36:23 +1100 (Sun, 27 Dec 2015) | 2 lines

HEXEN config : id numbers for 'Flechette' and 'Disc of Repulsion' were reversed, fixed.

------------------------------------------------------------------------
r1754 | ajapted | 2015-12-27 15:03:45 +1100 (Sun, 27 Dec 2015) | 2 lines

HEXEN config : added player starts 5-8 and the soundtype markers (things 1400-1409).

------------------------------------------------------------------------
r1753 | ajapted | 2015-12-27 14:48:40 +1100 (Sun, 27 Dec 2015) | 2 lines

HEXEN : added whitespace to align columns (for Things).

------------------------------------------------------------------------
r1752 | ajapted | 2015-12-27 12:09:48 +1100 (Sun, 27 Dec 2015) | 2 lines

TODO : minor update

------------------------------------------------------------------------
r1751 | ajapted | 2015-12-27 12:05:35 +1100 (Sun, 27 Dec 2015) | 7 lines

In game definitions support 't' flag for things like teleport destination
which can safely overlap moving actors (players and monsters) but not
decorative things.

Reworked thing stuck checking code to handle it (and also to only check
each pair of blocking things ONCE).

------------------------------------------------------------------------
r1750 | ajapted | 2015-12-20 12:42:05 +1100 (Sun, 20 Dec 2015) | 2 lines

Removed top-level "ups" folder -- not used for anything.

------------------------------------------------------------------------
r1749 | ajapted | 2015-12-20 12:38:40 +1100 (Sun, 20 Dec 2015) | 2 lines

TODO.txt : updated.

------------------------------------------------------------------------
r1748 | ajapted | 2015-12-20 12:35:17 +1100 (Sun, 20 Dec 2015) | 3 lines

GAME definitions : removed "level_name XXX" lines, which are not used
(they were simply ignored by the UGH file parser).

------------------------------------------------------------------------
r1747 | ajapted | 2015-12-19 23:48:41 +1100 (Sat, 19 Dec 2015) | 4 lines

Hexen support : added "z" widget to the Thing panel (only visible when
editing a hexen format map).  Also apply the Z value when rendering
things in the 3D preview.  These changes by Ioan Chera.

------------------------------------------------------------------------
r1746 | ajapted | 2015-12-19 23:21:37 +1100 (Sat, 19 Dec 2015) | 3 lines

Hexen support : added "TID" widget to the Thing panel when the current
map format is Hexen (and hide it otherwise).  This code by Ioan Chera.

------------------------------------------------------------------------
r1745 | ajapted | 2015-12-19 23:08:56 +1100 (Sat, 19 Dec 2015) | 4 lines

Hexen support : code for reading and writing Hexen format maps, including
handling the BEHAVIOR lump.  This code originally by Ioan Chera (printz)
with a few tweaks by me.

------------------------------------------------------------------------
r1744 | ajapted | 2015-12-19 22:13:01 +1100 (Sat, 19 Dec 2015) | 2 lines

GAMES : added partial Hexen config (ugh) file -- thanks to printz.

------------------------------------------------------------------------
r1743 | ajapted | 2015-12-19 21:29:24 +1100 (Sat, 19 Dec 2015) | 6 lines

Check lines : detect manual (D1,DR) doors on one-sided linedefs, with
options to show or fix them (we "fix" them by clearing the special).
Reason for this check is that such doors can crash vanilla DOOM.

This closes ticket #16.

------------------------------------------------------------------------
r1742 | ajapted | 2015-12-19 20:58:19 +1100 (Sat, 19 Dec 2015) | 3 lines

HERETIC: renamed two monsters: "Gargoyle Leader" --> "Fire Gargoyle",
and "Golem Leader" --> "Nitro Golem" (more consistent with the game).

------------------------------------------------------------------------
r1741 | ajapted | 2015-11-27 12:56:56 +1100 (Fri, 27 Nov 2015) | 3 lines

glBSP library : disabled the "no nodes" hack which created a dummy node and
subsector -- turns out that vanilla DOOM copes with no nodes just fine.

------------------------------------------------------------------------
r1740 | ajapted | 2015-09-21 19:40:23 +1000 (Mon, 21 Sep 2015) | 9 lines

Updated eureka.desktop file with:
1. %f on Exec line and a MimeType line, so can handle wad files from
   file-system exploring/navigation programs
2. replaced "X-DoomEditor" category with "ActionGame"
3. added Keywords line

Thanks to Fabian Greffrath for the patch (ticket #17).
I tweaked the set of keywords (e.g. added "heretic").

------------------------------------------------------------------------
r1739 | ajapted | 2015-09-09 13:54:40 +1000 (Wed, 09 Sep 2015) | 4 lines

Another fix for the freedoom1/freedoom2 distinction -- when loading known iwads,
ignore the plain "freedoom" entry (so it won't appear as a choice in the Manage
Project dialog).

------------------------------------------------------------------------
r1738 | ajapted | 2015-09-08 21:37:46 +1000 (Tue, 08 Sep 2015) | 5 lines

Fixed problem when looking for 'freedoom' as an emergency IWAD to use,
since there are now separate config files for Phase 1 and Phase 2, namely
'freedoom1.ugh' and 'freedoom2.ugh', hence the code should check these
instead of plain 'freedoom'.

------------------------------------------------------------------------
r1737 | ajapted | 2015-09-07 22:02:51 +1000 (Mon, 07 Sep 2015) | 4 lines

Ports / Eternity : added "EE:" prefix to all linetype descriptions, removed
the 'x', 'w' and 'u' categories, various tweaks to the descriptions e.g.
added /f and /c to designate types that use/affect a floor or ceiling.

------------------------------------------------------------------------
r1736 | ajapted | 2015-09-07 21:43:05 +1000 (Mon, 07 Sep 2015) | 3 lines

Checked in definition file for the 'Eternity' source port, courtesy printz
(with some editing by me).

------------------------------------------------------------------------
r1735 | ajapted | 2015-08-29 22:53:08 +1000 (Sat, 29 Aug 2015) | 2 lines

Browser: increased default width by 10 pixels (show 4 columns of sprites).

------------------------------------------------------------------------
r1734 | ajapted | 2015-08-29 22:51:38 +1000 (Sat, 29 Aug 2015) | 4 lines

Better handle the case when merging linedefs after dragging a vertex
(check the sectors on each side and decide if need to change a sidedef
on the linedef which remains, or even delete the other linedef).

------------------------------------------------------------------------
r1733 | printz | 2015-08-23 18:58:37 +1000 (Sun, 23 Aug 2015) | 3 lines

Eureka for OSX is now code-signed

* Also updated recommended project settings.
------------------------------------------------------------------------
r1732 | ajapted | 2015-06-13 16:43:15 +1000 (Sat, 13 Jun 2015) | 2 lines

Created new CHANGES.txt after the previous release.

------------------------------------------------------------------------
r1731 | ajapted | 2015-06-13 16:40:15 +1000 (Sat, 13 Jun 2015) | 2 lines

Moved CHANGES.txt --> changelogs/107.txt

------------------------------------------------------------------------
r1730 | ajapted | 2015-06-13 16:36:33 +1000 (Sat, 13 Jun 2015) | 3 lines

Check / textures : implemented checking for the Medusa Effect, but only when
the game or port specifies the "medusa_bug" feature.

------------------------------------------------------------------------
r1729 | ajapted | 2015-06-13 14:21:01 +1000 (Sat, 13 Jun 2015) | 2 lines

Ports / vanilla : added "feature medusa_bug 1"

------------------------------------------------------------------------
r1728 | ajapted | 2015-06-13 14:20:18 +1000 (Sat, 13 Jun 2015) | 3 lines

Support 'medusa_bug' feature in game definitions (mainly needed by Vanilla
to indicate that it is prone to the Medusa Effect).

------------------------------------------------------------------------
r1727 | ajapted | 2015-06-13 14:14:16 +1000 (Sat, 13 Jun 2015) | 3 lines

Texture loader : check for textures which potentially cause the Medusa Effect
when used as a mid-masked texture on a 2S line.

------------------------------------------------------------------------
r1726 | ajapted | 2015-06-12 14:57:04 +1000 (Fri, 12 Jun 2015) | 4 lines

Check / textures : implemented test for transparent textures used on solid
parts of walls, including "Log" button to list them and "Fix" button to
automatically set them to the default wall texture.

------------------------------------------------------------------------
r1725 | ajapted | 2015-06-12 14:34:19 +1000 (Fri, 12 Jun 2015) | 2 lines

Image class : added has_transparent() method.

------------------------------------------------------------------------
r1724 | ajapted | 2015-03-03 19:47:41 +1100 (Tue, 03 Mar 2015) | 2 lines

GAME DEFS : minor comment changes in freedoom2.ugh

------------------------------------------------------------------------
r1723 | ajapted | 2015-03-03 19:46:24 +1100 (Tue, 03 Mar 2015) | 4 lines

GAME DEFS : better support for latest FreeDoom release:
1. renamed freedoom.ugh --> freedoom2.ugh
2. added freedoom1.ugh which simply includes "doom"

------------------------------------------------------------------------
r1722 | ajapted | 2015-02-18 18:22:05 +1100 (Wed, 18 Feb 2015) | 2 lines

README.txt : removed 'F5' key description.

------------------------------------------------------------------------
r1721 | printz | 2015-02-17 18:30:38 +1100 (Tue, 17 Feb 2015) | 1 line

osx: Bumped info.plist version

------------------------------------------------------------------------
r1720 | ajapted | 2015-02-16 18:24:43 +1100 (Mon, 16 Feb 2015) | 2 lines

Changed default of 'render_aspect_ratio' config var --> 133.

------------------------------------------------------------------------
r1719 | ajapted | 2015-02-16 18:21:57 +1100 (Mon, 16 Feb 2015) | 2 lines

Win32 package : fixed missing logo image.

------------------------------------------------------------------------
r1718 | ajapted | 2015-02-16 16:58:48 +1100 (Mon, 16 Feb 2015) | 2 lines

CHANGELOG : added current revision.

------------------------------------------------------------------------
r1717 | ajapted | 2015-02-16 16:47:13 +1100 (Mon, 16 Feb 2015) | 2 lines

docs/History : re-sync with SVN repository logs (ready fo release).

------------------------------------------------------------------------
r1716 | ajapted | 2015-02-16 15:41:50 +1100 (Mon, 16 Feb 2015) | 2 lines

CHANGELOG and TODO updated for the release.

------------------------------------------------------------------------
r1715 | ajapted | 2015-02-16 15:41:00 +1100 (Mon, 16 Feb 2015) | 2 lines

Makefile : re-enable optimisation for the upcoming release.

------------------------------------------------------------------------
r1714 | ajapted | 2015-02-16 15:31:38 +1100 (Mon, 16 Feb 2015) | 3 lines

Default Props : implemented showing sprite for default thing, and clicking
on it opens the Thing browser.

------------------------------------------------------------------------
r1713 | ajapted | 2015-02-16 15:06:41 +1100 (Mon, 16 Feb 2015) | 3 lines

Default Properties : only show a single "wall" texture (instead of having
three of them, which was rather unwieldy).

------------------------------------------------------------------------
r1712 | ajapted | 2015-02-16 12:38:52 +1100 (Mon, 16 Feb 2015) | 2 lines

Makefile.xming : updated to FLTK 1.3.3

------------------------------------------------------------------------
r1711 | ajapted | 2015-02-16 12:38:03 +1100 (Mon, 16 Feb 2015) | 2 lines

FLTK tweak : add FL_DOUBLE flag to Fl::visual() call.

------------------------------------------------------------------------
r1710 | ajapted | 2015-02-16 12:35:31 +1100 (Mon, 16 Feb 2015) | 2 lines

README.txt : update (c) year.

------------------------------------------------------------------------
r1709 | ajapted | 2015-02-16 00:21:28 +1100 (Mon, 16 Feb 2015) | 2 lines

pack scripts : added missing "bindings.cfg" to them (Esp. the Win32 package)

------------------------------------------------------------------------
r1708 | ajapted | 2015-02-16 00:10:20 +1100 (Mon, 16 Feb 2015) | 3 lines

Show error dialog when the standard "bindings.cfg" file cannot be loaded
(call M_LoadBindings _after_ bumping init_progress to 3).

------------------------------------------------------------------------
r1707 | ajapted | 2015-02-15 23:14:15 +1100 (Sun, 15 Feb 2015) | 2 lines

pack-win32 script : small improvements.

------------------------------------------------------------------------
r1706 | ajapted | 2015-02-15 23:10:27 +1100 (Sun, 15 Feb 2015) | 2 lines

Win32 : created 'pack-win32.sh' shell script for creating a package.

------------------------------------------------------------------------
r1705 | ajapted | 2015-02-15 22:56:42 +1100 (Sun, 15 Feb 2015) | 3 lines

pack-source script : rewrote it, removed "cd ..", removed "$src" variable,
use "svn export" for copying directory contents.

------------------------------------------------------------------------
r1704 | ajapted | 2015-02-15 22:31:25 +1100 (Sun, 15 Feb 2015) | 7 lines

Win32 : implement a fallback for $home_dir when the %APPDATA% folder
cannot be determined.

We also now call Determine_InstallPath() _before_ Determine_HomeDir(),
needed by the above change, and I'm 99% sure that this is perfectly fine
for all platforms.

------------------------------------------------------------------------
r1703 | ajapted | 2015-02-15 22:15:14 +1100 (Sun, 15 Feb 2015) | 2 lines

Makefile.xming : more tidying.

------------------------------------------------------------------------
r1702 | ajapted | 2015-02-15 22:14:10 +1100 (Sun, 15 Feb 2015) | 2 lines

Makefile.xming : removed obsolete NSIS stuff.

------------------------------------------------------------------------
r1701 | ajapted | 2015-02-15 22:13:05 +1100 (Sun, 15 Feb 2015) | 3 lines

Win32 : as we no longer use an installer, removed code which queries the
registry for the installation folder.  Use GetExecutablePath() instead.

------------------------------------------------------------------------
r1700 | ajapted | 2015-02-15 22:11:05 +1100 (Sun, 15 Feb 2015) | 2 lines

code tweak.

------------------------------------------------------------------------
r1699 | ajapted | 2015-02-15 22:10:04 +1100 (Sun, 15 Feb 2015) | 2 lines

hdr_fltk.h : added missing #include for Fl_Menu_Button.

------------------------------------------------------------------------
r1698 | ajapted | 2015-02-15 21:36:23 +1100 (Sun, 15 Feb 2015) | 2 lines

code tweak.

------------------------------------------------------------------------
r1697 | ajapted | 2015-02-15 21:28:27 +1100 (Sun, 15 Feb 2015) | 2 lines

Config : tweak to description of --file option.

------------------------------------------------------------------------
r1696 | ajapted | 2015-02-15 21:20:06 +1100 (Sun, 15 Feb 2015) | 3 lines

misc : removed NSIS script "eureka.nsi" -- I plan on a simpler method of
packaging binaries for the Windows platform.

------------------------------------------------------------------------
r1695 | ajapted | 2015-02-15 21:17:52 +1100 (Sun, 15 Feb 2015) | 6 lines

misc : removed the 'Makefile.debian' and control files in misc/debian,
partly so as not to confuse that stuff with the official Debian package,
but also because I plan to explore a more distribution-neutral method
for packaging Linux binaries.

------------------------------------------------------------------------
r1694 | ajapted | 2015-02-15 21:10:00 +1100 (Sun, 15 Feb 2015) | 2 lines

eureka.rc : updated version for next release.

------------------------------------------------------------------------
r1693 | ajapted | 2015-02-15 21:09:21 +1100 (Sun, 15 Feb 2015) | 2 lines

TODO.txt tidying

------------------------------------------------------------------------
r1692 | ajapted | 2015-02-15 19:28:57 +1100 (Sun, 15 Feb 2015) | 2 lines

TODO update.

------------------------------------------------------------------------
r1691 | ajapted | 2015-02-15 19:28:36 +1100 (Sun, 15 Feb 2015) | 2 lines

UI_EditKey dialog : fixed wrong function name in Encode() method.

------------------------------------------------------------------------
r1690 | ajapted | 2015-02-15 18:44:17 +1100 (Sun, 15 Feb 2015) | 2 lines

UI_EditKey dialog : changing the context re-populates the Function choices.

------------------------------------------------------------------------
r1689 | ajapted | 2015-02-15 18:30:38 +1100 (Sun, 15 Feb 2015) | 3 lines

UI_EditKey dialog : re-populate the 'Keywords' and 'Flags' menus when the
function choice has been changed.

------------------------------------------------------------------------
r1688 | ajapted | 2015-02-15 18:16:30 +1100 (Sun, 15 Feb 2015) | 2 lines

UI_EditKey dialog : implemented the 'Flags...' menu.

------------------------------------------------------------------------
r1687 | ajapted | 2015-02-15 18:06:54 +1100 (Sun, 15 Feb 2015) | 2 lines

UI_EditKey dialog : implemented the 'Keywords...' menu.

------------------------------------------------------------------------
r1686 | ajapted | 2015-02-15 16:59:35 +1100 (Sun, 15 Feb 2015) | 2 lines

Various tidying in changelogs/*.txt

------------------------------------------------------------------------
r1685 | ajapted | 2015-02-15 16:37:02 +1100 (Sun, 15 Feb 2015) | 2 lines

TODO.txt updated

------------------------------------------------------------------------
r1684 | ajapted | 2015-02-15 16:36:42 +1100 (Sun, 15 Feb 2015) | 2 lines

CHANGELOG update and version bump.

------------------------------------------------------------------------
r1683 | ajapted | 2015-02-15 16:28:45 +1100 (Sun, 15 Feb 2015) | 2 lines

About box : yet another tweak.

------------------------------------------------------------------------
r1682 | ajapted | 2015-02-15 16:22:00 +1100 (Sun, 15 Feb 2015) | 2 lines

CMD_NewMap : backup the current pwad before saving.

------------------------------------------------------------------------
r1681 | ajapted | 2015-02-15 16:15:31 +1100 (Sun, 15 Feb 2015) | 5 lines

The 'New Map' command (in File menu) now saves the fresh map into the
current pwad, asking for confirmation if it already exists.

Hence removed 'Replacer' global and the overwrite test in CMD_SaveMap.

------------------------------------------------------------------------
r1680 | ajapted | 2015-02-15 15:41:12 +1100 (Sun, 15 Feb 2015) | 2 lines

(part of last commit) -- removed 'new_file' stuff from UI_ChooseMap.

------------------------------------------------------------------------
r1679 | ajapted | 2015-02-15 15:22:32 +1100 (Sun, 15 Feb 2015) | 2 lines

UI_ChooseMap : removed the 'new_file' stuff -- obsolete now.

------------------------------------------------------------------------
r1678 | ajapted | 2015-02-15 15:03:25 +1100 (Sun, 15 Feb 2015) | 2 lines

Finished implementing the 'New Project' command (in File menu).

------------------------------------------------------------------------
r1677 | ajapted | 2015-02-15 14:44:24 +1100 (Sun, 15 Feb 2015) | 3 lines

More work on 'File / New Project' command, implemented the file chooser and
logic to determine the initial map name.

------------------------------------------------------------------------
r1676 | ajapted | 2015-02-15 14:02:28 +1100 (Sun, 15 Feb 2015) | 4 lines

Partial work on a 'File / New Project' command, which feels like a better way
of handling create new files from scratch (rather than a radio button in the
New Map dialog).

------------------------------------------------------------------------
r1675 | ajapted | 2015-02-15 11:41:53 +1100 (Sun, 15 Feb 2015) | 4 lines

For the File / Recent and File / Given-files menus, add a number to the
beginning of each entry and make it the shortcut key (e.g. pressing '4' can
be used to select the fourth entry while the menu is shown).

------------------------------------------------------------------------
r1674 | ajapted | 2015-02-14 22:57:35 +1100 (Sat, 14 Feb 2015) | 3 lines

About box : overlay a small version number on top of the logo (in bottom
right corner), and tweaked a few things.

------------------------------------------------------------------------
r1673 | ajapted | 2015-02-14 21:16:13 +1100 (Sat, 14 Feb 2015) | 3 lines

Renamed prefix for vertex commands from 'VERT_' --> 'VT_', and renamed
vertex reshaping commands to 'VT_ShapeArc' and 'VT_ShapeLine'.

------------------------------------------------------------------------
r1672 | ajapted | 2015-02-14 21:01:42 +1100 (Sat, 14 Feb 2015) | 3 lines

Key bind dialog : fixed wrong context strings (seems to have gotten out of
sync with the KCTX_xxx values).

------------------------------------------------------------------------
r1671 | ajapted | 2015-02-14 20:31:49 +1100 (Sat, 14 Feb 2015) | 2 lines

README.txt : minor updates.

------------------------------------------------------------------------
r1670 | ajapted | 2015-02-14 19:11:37 +1100 (Sat, 14 Feb 2015) | 4 lines

Fixed the key binding list so that pressing 'Bind', 'Copy' etc on a
non-visible line will scroll to that line (make it visible).

------------------------------------------------------------------------
r1669 | ajapted | 2015-02-14 16:49:06 +1100 (Sat, 14 Feb 2015) | 2 lines

Reworked SEC_SelectGroup command to use the new flag system.

------------------------------------------------------------------------
r1668 | ajapted | 2015-02-14 16:07:01 +1100 (Sat, 14 Feb 2015) | 2 lines

Updated LIN_SelectPath command to use new flag system.

------------------------------------------------------------------------
r1667 | ajapted | 2015-02-14 15:43:31 +1100 (Sat, 14 Feb 2015) | 3 lines

Fixed damn silly bug in ExecuteKey() not storing flag parameters, which begin
with a slash '/', into the EXEC_Flags[] array.

------------------------------------------------------------------------
r1666 | ajapted | 2015-02-14 15:17:42 +1100 (Sat, 14 Feb 2015) | 3 lines

For "Delete" command support two flags: /keep_unused and /keep_things
(the latter only useful in sectors mode).

------------------------------------------------------------------------
r1665 | ajapted | 2015-02-14 14:50:13 +1100 (Sat, 14 Feb 2015) | 3 lines

1. updated CMD_Rotate90 to take a keyword ("cw" for clockwise, "acw" for anti-clockwise)
2. split VERT_Reshape into two commands : VERT_ReshapeLine and VERT_ReshapeArc

------------------------------------------------------------------------
r1664 | ajapted | 2015-02-13 22:11:54 +1100 (Fri, 13 Feb 2015) | 3 lines

Added 'flag_list' and 'keyword_list' to every editor_command_t that needs
them.  [ Note that most commands do not support their flags yet.... ]

------------------------------------------------------------------------
r1663 | ajapted | 2015-02-13 19:59:42 +1100 (Fri, 13 Feb 2015) | 4 lines

Reworked LineDef_Align() function to take 'flags' as a integer bitmask
instead of a string.  Updated the 3D_Align implementation for this, and to
use the new Exec_HasFlag() mechanism to check for "/clear" and "/right".

------------------------------------------------------------------------
r1662 | ajapted | 2015-02-13 19:39:23 +1100 (Fri, 13 Feb 2015) | 4 lines

Added EXEC_Flags[] global which is similar to EXEC_Param[] but stores "flags"
(paremeters beginning with '/').  Implemented adding such flags into that
array (from a key binding), and added Exec_HasFlag() utility function.

------------------------------------------------------------------------
r1661 | ajapted | 2015-02-13 16:50:31 +1100 (Fri, 13 Feb 2015) | 2 lines

TODO update.

------------------------------------------------------------------------
r1660 | ajapted | 2015-02-13 16:42:23 +1100 (Fri, 13 Feb 2015) | 5 lines

Added 'flag_list' and 'keyword_list' fields to editor_command_t.

Use these in the UI_EditKey dialog to populate a 'Keywords' and/or 'Flags'
menus.  These menus don't actually do anything yet....

------------------------------------------------------------------------
r1659 | ajapted | 2015-02-13 13:51:28 +1100 (Fri, 13 Feb 2015) | 4 lines

Began work on some improvements to key binding system.  This commit works
on the UI_EditKey dialog, the 'Function' widget is now a choice menu that
contains all the possible functions for the current context.

------------------------------------------------------------------------
r1658 | ajapted | 2015-02-10 15:35:17 +1100 (Tue, 10 Feb 2015) | 4 lines

Fixed crash when trying to build nodes (via File menu) on an IWAD map
which has had some changes made to it, but has not been saved yet (and
hence 'edit_wad' was NULL).

------------------------------------------------------------------------
r1657 | ajapted | 2015-02-10 15:15:44 +1100 (Tue, 10 Feb 2015) | 2 lines

TODO update.

------------------------------------------------------------------------
r1656 | ajapted | 2015-02-10 15:14:59 +1100 (Tue, 10 Feb 2015) | 3 lines

Key bindings : changed vertex reshapers 'C' to be 120 degrees and 'Q' to 240
degrees -- I think these will be more useful than 90/270 in practice.

------------------------------------------------------------------------
r1655 | ajapted | 2015-02-10 15:13:17 +1100 (Tue, 10 Feb 2015) | 2 lines

Version bump, in honor of Find/Replace feature fully implemented.

------------------------------------------------------------------------
r1654 | ajapted | 2015-02-10 15:07:37 +1100 (Tue, 10 Feb 2015) | 3 lines

Find/Replace : added 'skies' checkbox to the Sector filters.  This can be
used to prevent matches from affecting sky ceilings.

------------------------------------------------------------------------
r1653 | ajapted | 2015-02-10 14:52:20 +1100 (Tue, 10 Feb 2015) | 3 lines

Find/Replace : prevent matching the empty rail texture ('-') against a "*"
wildcard pattern -- especially pertinent when doing a Replace All operation.

------------------------------------------------------------------------
r1652 | ajapted | 2015-02-10 13:22:11 +1100 (Tue, 10 Feb 2015) | 2 lines

Find/Replace : fixed the filter toggle button being out-of-sync.

------------------------------------------------------------------------
r1651 | ajapted | 2015-02-10 13:15:58 +1100 (Tue, 10 Feb 2015) | 3 lines

Find/Replace : only clear everything when the type changes (i.e. keep the
existing match text, filters, etc... while edit mode stays the same).

------------------------------------------------------------------------
r1650 | ajapted | 2015-02-10 13:00:58 +1100 (Tue, 10 Feb 2015) | 2 lines

Find/Replace : code to reset the filters section.

------------------------------------------------------------------------
r1649 | ajapted | 2015-02-09 22:22:33 +1100 (Mon, 09 Feb 2015) | 2 lines

Find/Replace : implemented replacement for LineDef textures.

------------------------------------------------------------------------
r1648 | ajapted | 2015-02-09 22:11:55 +1100 (Mon, 09 Feb 2015) | 8 lines

Find/Replace : decided to remove handling of negative matches ('!' prefix)
for textures and flats -- primarily because the semantics of find is quite
different for semantics of replace (with find, user wants to see all sectors
where BOTH flats match the negative pattern, but with replace user wants to
visit sectors where EITHER flat match the negative pattern).

Hence opting for K.I.S.S.

------------------------------------------------------------------------
r1647 | ajapted | 2015-02-09 21:48:58 +1100 (Mon, 09 Feb 2015) | 4 lines

Invert selection command : do not clear the selection when 'error_mode' is
active -- firstly because it all we get is the same as Select All command,
and using CTRL-I (twice) to keep the error selection can be useful.

------------------------------------------------------------------------
r1646 | ajapted | 2015-02-09 21:32:37 +1100 (Mon, 09 Feb 2015) | 2 lines

Find/Replace : implemented replacement for sector flats.

------------------------------------------------------------------------
r1645 | ajapted | 2015-02-09 21:30:23 +1100 (Mon, 09 Feb 2015) | 3 lines

UI : made TexFromWidget() and FlatFromWidget() be static functions since
they do not use or require any fields or methods of their class.

------------------------------------------------------------------------
r1644 | ajapted | 2015-02-09 20:54:06 +1100 (Mon, 09 Feb 2015) | 4 lines

Find/Replace : Allow user to dismiss the Find/Replace panel without losing
the current selection (it was being cleared because it now uses the error
mode).

------------------------------------------------------------------------
r1643 | ajapted | 2015-02-09 20:18:48 +1100 (Mon, 09 Feb 2015) | 3 lines

Find/Replace : implemented Match_LineDef(), logic for matching textures
on the sidedefs.

------------------------------------------------------------------------
r1642 | ajapted | 2015-02-09 19:35:46 +1100 (Mon, 09 Feb 2015) | 4 lines

Find/Replace : allow '/' and '|' as separators for textures (consistent
with numeric searches), and when adding a texture from the browser add a
comma separator if current match ends with '*'.

------------------------------------------------------------------------
r1641 | ajapted | 2015-02-09 19:19:22 +1100 (Mon, 09 Feb 2015) | 6 lines

Find/Replace : implemented Pattern_Match() method for matching texture names,
supporting a list of names (simple patterns) separated by commas.

Use this to implement Match_Sector() logic, and support initial '!' character
in the pattern to negate the results.

------------------------------------------------------------------------
r1640 | ajapted | 2015-02-09 18:25:34 +1100 (Mon, 09 Feb 2015) | 6 lines

Factored out code to match texture names (etc) --> Texture_MatchPattern(),
now in the objects.cc/h file.

Also fixed bug in browser where patterns like '4$' would not match some
flats or textures, like 'CEIL3_4', due to spaces (padding) on the end.

------------------------------------------------------------------------
r1639 | ajapted | 2015-02-09 17:09:22 +1100 (Mon, 09 Feb 2015) | 2 lines

TODO update.

------------------------------------------------------------------------
r1638 | ajapted | 2015-02-09 17:02:57 +1100 (Mon, 09 Feb 2015) | 4 lines

Vertex Reshaping : finished logic for arbitrary arc angles, updating the
key bindings for O/C/D/Q to specify the angle directly.  Document new 'Q'
binding (270 degrees) in the README.

------------------------------------------------------------------------
r1637 | ajapted | 2015-02-09 16:43:05 +1100 (Mon, 09 Feb 2015) | 3 lines

Vertex Reshaping : worked to support arbitrary arc sizes (angles), and to
keep the start and end vertices of the arc in the same location....

------------------------------------------------------------------------
r1636 | ajapted | 2015-02-09 15:55:17 +1100 (Mon, 09 Feb 2015) | 2 lines

sys_macro.h : #define M_SQRT2 if not already defined.

------------------------------------------------------------------------
r1635 | ajapted | 2015-02-09 15:19:40 +1100 (Mon, 09 Feb 2015) | 2 lines

Fixed not reloading textures (etc) when opening a new wad file.

------------------------------------------------------------------------
r1634 | ajapted | 2015-02-09 14:37:11 +1100 (Mon, 09 Feb 2015) | 2 lines

TODO.txt : update and tidy up.

------------------------------------------------------------------------
r1633 | ajapted | 2015-02-09 14:33:55 +1100 (Mon, 09 Feb 2015) | 5 lines

When loading a wad specified on the command line, and it contains settings
for the iwad, port and/or resources in an EUREKA_LUMP, then allow command
line arguments to override those values (and _add_ new resources).

------------------------------------------------------------------------
r1632 | ajapted | 2015-02-09 13:01:55 +1100 (Mon, 09 Feb 2015) | 4 lines

Makefile.xming : link with -static-libgcc and -static-libstdc++ so that
the Windows executable actually works on Windows (and not complain about
a missing DLL).

------------------------------------------------------------------------
r1631 | ajapted | 2015-01-24 16:29:41 +1100 (Sat, 24 Jan 2015) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1630 | ajapted | 2015-01-24 16:28:30 +1100 (Sat, 24 Jan 2015) | 3 lines

Config : added 'show_full_one_sided' config variable, enables showing
the rail / upper textures for one-sided lines in the LineDef panel.

------------------------------------------------------------------------
r1629 | ajapted | 2015-01-24 15:45:39 +1100 (Sat, 24 Jan 2015) | 3 lines

Linedef panel : for one-sided lines, don't show upper and rail texture
(since editing them generally does nothing).

------------------------------------------------------------------------
r1628 | ajapted | 2015-01-24 15:15:15 +1100 (Sat, 24 Jan 2015) | 3 lines

Canvas : tweak to error mode, when active don't highlight the tagged sector(s)
of the currently highlighted linedef.

------------------------------------------------------------------------
r1627 | ajapted | 2015-01-24 15:11:43 +1100 (Sat, 24 Jan 2015) | 3 lines

Canvas : in the error mode, draw most linedefs as LIGHTGREY so the selected
objects stand out more.

------------------------------------------------------------------------
r1626 | ajapted | 2015-01-24 14:57:17 +1100 (Sat, 24 Jan 2015) | 2 lines

Linedef checker : implemented detection of unknown line types.

------------------------------------------------------------------------
r1625 | ajapted | 2015-01-24 14:18:05 +1100 (Sat, 24 Jan 2015) | 3 lines

Sector checker : detect unknown sector types.  They are shown in red since
in vanilla DOOM they will cause a fatal error.

------------------------------------------------------------------------
r1624 | printz | 2015-01-19 18:43:48 +1100 (Mon, 19 Jan 2015) | 1 line

osx: updated Xcode project
------------------------------------------------------------------------
r1623 | ajapted | 2015-01-18 22:40:46 +1100 (Sun, 18 Jan 2015) | 6 lines

Game definitions :
1. fixed category of linetype #68 (should be a raising floor)

2. changed category letter of raising floors to 'g', so they appear near
   the lowering floors in the Browser.

------------------------------------------------------------------------
r1622 | ajapted | 2015-01-17 22:10:09 +1100 (Sat, 17 Jan 2015) | 3 lines

Find/Replace : make 'Select All' button use the error mode, i.e. show all
matches in bright red and everything else in a rather dim gray.

------------------------------------------------------------------------
r1621 | ajapted | 2015-01-17 21:30:21 +1100 (Sat, 17 Jan 2015) | 2 lines

tweak the --help text

------------------------------------------------------------------------
r1620 | ajapted | 2015-01-17 21:29:41 +1100 (Sat, 17 Jan 2015) | 2 lines

Man page : bit more fleshing out + lots of polishing.

------------------------------------------------------------------------
r1619 | ajapted | 2015-01-17 17:30:54 +1100 (Sat, 17 Jan 2015) | 2 lines

Man page : fixed long options to have two dashes, plus some tweaks.

------------------------------------------------------------------------
r1618 | ajapted | 2015-01-17 17:26:21 +1100 (Sat, 17 Jan 2015) | 2 lines

Man page : finished describing the remaining options.

------------------------------------------------------------------------
r1617 | ajapted | 2015-01-17 16:14:03 +1100 (Sat, 17 Jan 2015) | 3 lines

Browser : tidied up some code with 'sort_method_e' typedef (instead of
using 0/1/2 with special meanings).

------------------------------------------------------------------------
r1616 | ajapted | 2015-01-17 15:56:21 +1100 (Sat, 17 Jan 2015) | 4 lines

Menus : the 'Default Properties' command did not belong in FILE menu, so
moved it into the VIEW menu (the EDIT menu might make more sense, but is
rather full right now).

------------------------------------------------------------------------
r1615 | ajapted | 2015-01-16 22:19:49 +1100 (Fri, 16 Jan 2015) | 4 lines

DOOM defs : moved 'SKY1/2/3' textures from NATURAL --> OTHER category,
since they looked out of place there (they have little utility when used
on walls, so "Other" category seems the most appropiate).

------------------------------------------------------------------------
r1614 | ajapted | 2015-01-16 22:16:27 +1100 (Fri, 16 Jan 2015) | 4 lines

Game defs : moved the MBF dog thing --> Boom definition (ports/boom.ugh),
which at least prevents it appearing in "vanilla" mode.  Also changed its
category from Player --> Other.

------------------------------------------------------------------------
r1613 | ajapted | 2015-01-16 22:13:53 +1100 (Fri, 16 Jan 2015) | 2 lines

Renamed 'Manage Wads' command --> 'Manage Project'

------------------------------------------------------------------------
r1612 | ajapted | 2015-01-16 21:35:14 +1100 (Fri, 16 Jan 2015) | 3 lines

Recolor the co-op player starts to match DOOM, i.e. type 2 start is gray,
type 3 start is brown, type 4 start is red.

------------------------------------------------------------------------
r1611 | ajapted | 2015-01-16 20:50:00 +1100 (Fri, 16 Jan 2015) | 2 lines

Code : minor rename, Img class --> Img_c

------------------------------------------------------------------------
r1610 | ajapted | 2015-01-16 20:40:03 +1100 (Fri, 16 Jan 2015) | 4 lines

Img class : removed the Img_priv class, just have the fields in the
private area of 'Img' class (renamed since they clashed with access
methods).  Also reformatted code to use tabs, plus various tidying.

------------------------------------------------------------------------
r1609 | ajapted | 2015-01-16 20:14:12 +1100 (Fri, 16 Jan 2015) | 3 lines

Img class : implemented color_remap() method, like spectrify() but remaps a
source color range into a target color range.

------------------------------------------------------------------------
r1608 | ajapted | 2015-01-16 19:59:08 +1100 (Fri, 16 Jan 2015) | 6 lines

Browser : the BR_CycleCategory command now skips the 'RECENT' category.

Rationale is that another key toggles between RECENT category and the ALL
category, so when the user uses this function they are probably not after
the special RECENT category.

------------------------------------------------------------------------
r1607 | ajapted | 2015-01-16 17:17:54 +1100 (Fri, 16 Jan 2015) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1606 | ajapted | 2015-01-16 15:47:39 +1100 (Fri, 16 Jan 2015) | 2 lines

Man page : describe '$PREFIX/share/eureka' in FILES section.

------------------------------------------------------------------------
r1605 | ajapted | 2015-01-16 15:27:59 +1100 (Fri, 16 Jan 2015) | 2 lines

Man page : added "FILES", "ENVIRONMENT" and "SEE ALSO" sections

------------------------------------------------------------------------
r1604 | ajapted | 2015-01-16 15:15:54 +1100 (Fri, 16 Jan 2015) | 2 lines

Removed "ups" from the directories created in the $home_dir.

------------------------------------------------------------------------
r1603 | ajapted | 2015-01-16 14:22:20 +1100 (Fri, 16 Jan 2015) | 2 lines

Man page : documented the main options, --file, --warp, --iwad, etc....

------------------------------------------------------------------------
r1602 | ajapted | 2015-01-16 12:48:03 +1100 (Fri, 16 Jan 2015) | 3 lines

Manual page : created a DESCRIPTION section, listing some of Eureka's
features, and reworked other parts at top of file (SYNOPSIS, etc).

------------------------------------------------------------------------
r1601 | ajapted | 2015-01-16 12:45:54 +1100 (Fri, 16 Jan 2015) | 2 lines

Added 'misc/eureka.6' -- a skeletal manual page, courtesy Fabian Greffrath.

------------------------------------------------------------------------
r1600 | ajapted | 2015-01-16 12:26:12 +1100 (Fri, 16 Jan 2015) | 3 lines

For --help text, change order of command-line options to show the most
important ones first (like --file and --iwad).

------------------------------------------------------------------------
r1599 | ajapted | 2015-01-16 11:38:10 +1100 (Fri, 16 Jan 2015) | 3 lines

For the --help text, show long options with two dashes ('--') since I will
use double dashes in the manpage.

------------------------------------------------------------------------
r1598 | ajapted | 2015-01-16 11:26:56 +1100 (Fri, 16 Jan 2015) | 2 lines

Updated AUTHORS.txt

------------------------------------------------------------------------
r1597 | ajapted | 2015-01-16 10:59:37 +1100 (Fri, 16 Jan 2015) | 2 lines

Code : fixed previous commit (SYS_ASSERT in the wrong place)

------------------------------------------------------------------------
r1596 | ajapted | 2015-01-16 10:50:33 +1100 (Fri, 16 Jan 2015) | 4 lines

Code : added some SYS_ASSERT() checks to erase() method of RecentFiles_c.
Perhaps this will silence the bogus warnings about out-of-bounds access
which older GNU compilers generate.

------------------------------------------------------------------------
r1595 | ajapted | 2015-01-16 10:43:54 +1100 (Fri, 16 Jan 2015) | 2 lines

Code : added __attribute((noreturn)) to the FatalError() prototype.

------------------------------------------------------------------------
r1594 | ajapted | 2015-01-16 00:03:40 +1100 (Fri, 16 Jan 2015) | 4 lines

Browser : reduced size of sprites in Thing browser --> 64x72 (from 80x80)
which works better horizontally (three columns at minimum size) and can
generally see more things, albeit a few more things are cut off now.

------------------------------------------------------------------------
r1593 | ajapted | 2015-01-15 23:57:33 +1100 (Thu, 15 Jan 2015) | 2 lines

Browser : tweaked name of "Other" category.

------------------------------------------------------------------------
r1592 | ajapted | 2015-01-15 23:56:49 +1100 (Thu, 15 Jan 2015) | 4 lines

Browser : replaced the "Sort" choice widget with a "Alpha" checkbox, and
moved the "Match" widget up.  This makes the Things (etc) browsers more
consistent looking with Flats and Textures, and a bit easier to use.

------------------------------------------------------------------------
r1591 | ajapted | 2015-01-15 23:44:44 +1100 (Thu, 15 Jan 2015) | 2 lines

Browser : made the minimum width a bit narrower (10 units).

------------------------------------------------------------------------
r1590 | ajapted | 2015-01-15 23:28:43 +1100 (Thu, 15 Jan 2015) | 4 lines

In main window's title, disabled the program name "Eureka" tacked on
the end -- just seems like visual noise, especially with a [Read-Only]
in the title.

------------------------------------------------------------------------
r1589 | ajapted | 2015-01-15 23:06:42 +1100 (Thu, 15 Jan 2015) | 2 lines

Bindings : added '|' (SHIFT + '\') as the BR_CycleCategory function.

------------------------------------------------------------------------
r1588 | ajapted | 2015-01-15 22:50:15 +1100 (Thu, 15 Jan 2015) | 2 lines

Game defs : tweaked name of "Health & Ammo" category.

------------------------------------------------------------------------
r1587 | ajapted | 2015-01-15 22:23:38 +1100 (Thu, 15 Jan 2015) | 4 lines

Bindings : make 'T' (shift + t) open the browser to things, and 'X'
(shift + x) open the browser to textures -- for consistency with the
shortcuts in the BROWSER menu.

------------------------------------------------------------------------
r1586 | ajapted | 2015-01-15 22:12:10 +1100 (Thu, 15 Jan 2015) | 3 lines

Menus : in Browser menu, moved 'Things' to first position, matching the
order in the MODE choice on info-bar and the Find/Replace dialog.

------------------------------------------------------------------------
r1585 | ajapted | 2015-01-15 21:54:33 +1100 (Thu, 15 Jan 2015) | 2 lines

Browser : tweaked title names and positioning.

------------------------------------------------------------------------
r1584 | ajapted | 2015-01-15 21:30:55 +1100 (Thu, 15 Jan 2015) | 2 lines

Version bump.

------------------------------------------------------------------------
r1583 | ajapted | 2015-01-15 21:18:32 +1100 (Thu, 15 Jan 2015) | 3 lines

3D View : changed the low_detail/high_detail flag into a preference setting
(instead of being toggleable with the F5 key).

------------------------------------------------------------------------
r1582 | ajapted | 2015-01-15 20:42:32 +1100 (Thu, 15 Jan 2015) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1581 | ajapted | 2015-01-15 20:41:12 +1100 (Thu, 15 Jan 2015) | 4 lines

3D View : tweaked the info bar, move gamma to just after gravity, and made
the Tex/Lit/Obj indicators be highlighted when NOT in effect (so under
normal circumstances they remain dim).

------------------------------------------------------------------------
r1580 | ajapted | 2015-01-15 20:34:56 +1100 (Thu, 15 Jan 2015) | 2 lines

3D View : finished the info-bar implementation.

------------------------------------------------------------------------
r1579 | ajapted | 2015-01-15 19:54:14 +1100 (Thu, 15 Jan 2015) | 3 lines

3D View : began work on an Information bar at top of render, showing the
camera position, angle and various state.

------------------------------------------------------------------------
r1578 | ajapted | 2015-01-15 19:15:15 +1100 (Thu, 15 Jan 2015) | 3 lines

Canvas : when drawing the "split line", show how and where the line will
be split, with two new lines in orange and a small disc at new vertex.

------------------------------------------------------------------------
r1577 | ajapted | 2015-01-15 18:29:03 +1100 (Thu, 15 Jan 2015) | 4 lines

Canvas : experimented with drawing a solid circle where the closest snap
position to the mouse is (when SNAP is enabled), with a line going to
the current mouse position....  Seems too weird to be useful.

------------------------------------------------------------------------
r1576 | ajapted | 2015-01-15 17:55:03 +1100 (Thu, 15 Jan 2015) | 5 lines

Command system : registering commands is now done by passing a list of
structures (instead of calling a function for each command).  This will
allow extra fields in the future, e.g. description of the command and
what parameters it takes.

------------------------------------------------------------------------
r1575 | ajapted | 2015-01-15 16:52:49 +1100 (Thu, 15 Jan 2015) | 2 lines

The 'CopyAndPaste' command broke recently -- fixed it.

------------------------------------------------------------------------
r1574 | ajapted | 2015-01-15 12:22:50 +1100 (Thu, 15 Jan 2015) | 2 lines

Simplified some code using the bit-vector class.

------------------------------------------------------------------------
r1573 | ajapted | 2015-01-15 12:22:03 +1100 (Thu, 15 Jan 2015) | 2 lines

Selection class : no need to check/grow the bit-vector, as it grows itself now.

------------------------------------------------------------------------
r1572 | ajapted | 2015-01-15 12:14:52 +1100 (Thu, 15 Jan 2015) | 2 lines

Bitvec class : improved way vector is grown in set() method.

------------------------------------------------------------------------
r1571 | ajapted | 2015-01-15 11:58:20 +1100 (Thu, 15 Jan 2015) | 7 lines

Bitvec class : added raw_get(), raw_set(), etc... as inline methods which
do no range checking, and the normal get(), set(), etc... methods now
check the position and will automatically resize the vector when needed.

Also made resize() allow shrinking the vector when reduced by a large
amount.

------------------------------------------------------------------------
r1570 | ajapted | 2015-01-15 11:33:58 +1100 (Thu, 15 Jan 2015) | 2 lines

Bitvec class : removed unused 'merge()' method.

------------------------------------------------------------------------
r1569 | ajapted | 2015-01-14 23:25:36 +1100 (Wed, 14 Jan 2015) | 7 lines

Menus :
1. added shortcuts to numerous menu items that lacked them
   (especially the Browser menu)

2. moved 'Prune unused' to below Delete, and removed its shortcut
   since the 'P' shortcut is already used by Paste.

------------------------------------------------------------------------
r1568 | ajapted | 2015-01-14 22:39:16 +1100 (Wed, 14 Jan 2015) | 3 lines

Find/Replace : implemented linedef filtering based on sidedness, and fixed
some issues with the tag filtering logic.

------------------------------------------------------------------------
r1567 | ajapted | 2015-01-14 22:18:41 +1100 (Wed, 14 Jan 2015) | 4 lines

Find/Replace :
1. got the skill and mode filters for Things working
2. got the tag-number filter for Line/Sector searches working

------------------------------------------------------------------------
r1566 | ajapted | 2015-01-14 21:30:02 +1100 (Wed, 14 Jan 2015) | 4 lines

Find/Replace : got the UI_TripleCheckButton working quite well, for both the
skill flags and the mode flags, and implemented logic to compute the mask
and compare value from those widgets.

------------------------------------------------------------------------
r1565 | ajapted | 2015-01-14 20:37:40 +1100 (Wed, 14 Jan 2015) | 3 lines

Find/Replace : created a UI_TripleCheckButton() which is used to represent
the search state for a boolean flag (YES, NO, DontCare).

------------------------------------------------------------------------
r1564 | ajapted | 2015-01-14 19:21:04 +1100 (Wed, 14 Jan 2015) | 2 lines

CHANGELOG : yet another reorganisation...

------------------------------------------------------------------------
r1563 | ajapted | 2015-01-14 19:17:05 +1100 (Wed, 14 Jan 2015) | 3 lines

Find/Replace : added code to show/hide the filter widgets based on the
current mode (Things, LineDefs, etc).  Also improved widget positions.

------------------------------------------------------------------------
r1562 | ajapted | 2015-01-14 18:50:42 +1100 (Wed, 14 Jan 2015) | 3 lines

Find/Replace : began work on Filters -- this commit merely creates all the
widgets we will need.

------------------------------------------------------------------------
r1561 | ajapted | 2015-01-14 16:53:11 +1100 (Wed, 14 Jan 2015) | 2 lines

Find/Replace : finished 'Choose' button and browser interaction logic.

------------------------------------------------------------------------
r1560 | ajapted | 2015-01-14 15:29:34 +1100 (Wed, 14 Jan 2015) | 2 lines

Find/Replace : worked on 'Choose' button and interaction with the Browser...

------------------------------------------------------------------------
r1559 | ajapted | 2015-01-14 15:01:19 +1100 (Wed, 14 Jan 2015) | 2 lines

Find/Replace : when '*' is used, show "(everything)" as the description.

------------------------------------------------------------------------
r1558 | ajapted | 2015-01-14 14:51:58 +1100 (Wed, 14 Jan 2015) | 3 lines

Find/Replace : when 'Replace All', select all the objects which were modified
and goto this selection at the end -- lets the user see what was affected.

------------------------------------------------------------------------
r1557 | ajapted | 2015-01-14 14:47:43 +1100 (Wed, 14 Jan 2015) | 2 lines

Find/Replace : support for finding and replacing Line-Types and Sector-Types.

------------------------------------------------------------------------
r1556 | ajapted | 2015-01-14 14:46:43 +1100 (Wed, 14 Jan 2015) | 2 lines

Objid : the clear() method now only changes the 'num', leaves 'type' alone.

------------------------------------------------------------------------
r1555 | ajapted | 2015-01-13 21:59:34 +1100 (Tue, 13 Jan 2015) | 2 lines

README.txt : document the '\' key (toggle RECENT category).

------------------------------------------------------------------------
r1554 | ajapted | 2015-01-13 21:51:24 +1100 (Tue, 13 Jan 2015) | 5 lines

Find/Replace :
1. renamed 'Apply' button --> 'Replace'
2. only activate 'Replace' button when something has been found
3. implemented Replace_Thing() method

------------------------------------------------------------------------
r1553 | ajapted | 2015-01-13 21:30:53 +1100 (Tue, 13 Jan 2015) | 3 lines

Texture checker : assume textures beginning with '#' are special, do not
treat them as unknown textures.

------------------------------------------------------------------------
r1552 | ajapted | 2015-01-13 21:15:14 +1100 (Tue, 13 Jan 2015) | 3 lines

Vertex Reshaping : added bindings for them, and document them in the README
and CHANGELOG.

------------------------------------------------------------------------
r1551 | ajapted | 2015-01-13 21:13:20 +1100 (Tue, 13 Jan 2015) | 3 lines

Vertex Reshaping : register its command, and properly check the parameter
to call the correct function (e.g. "line" vs "circle" vs "arc180").

------------------------------------------------------------------------
r1550 | ajapted | 2015-01-13 20:48:05 +1100 (Tue, 13 Jan 2015) | 3 lines

Vertices : support for shaping vertices into a half-circle (180 degrees)
or a quarter circle (90 degrees).

------------------------------------------------------------------------
r1549 | ajapted | 2015-01-13 18:54:52 +1100 (Tue, 13 Jan 2015) | 3 lines

Vertices : implemented the EvalCircle() function -- the circle reshaping code
is working now.

------------------------------------------------------------------------
r1548 | ajapted | 2015-01-13 18:27:27 +1100 (Tue, 13 Jan 2015) | 2 lines

Vertices : partial work on command to reshape vertices into a pure circle.

------------------------------------------------------------------------
r1547 | ajapted | 2015-01-13 17:44:12 +1100 (Tue, 13 Jan 2015) | 2 lines

Vertices : got the Reshape_Line() code working.

------------------------------------------------------------------------
r1546 | ajapted | 2015-01-13 17:07:24 +1100 (Tue, 13 Jan 2015) | 3 lines

Vertices : further work on straight line reshaper, collect all vertices and
sort them along the line, and then determine the end-points we need.

------------------------------------------------------------------------
r1545 | ajapted | 2015-01-13 16:30:52 +1100 (Tue, 13 Jan 2015) | 3 lines

Vertices : worked on code to move all selected vertices onto a straight line
(some experimental stuff...)

------------------------------------------------------------------------
r1544 | ajapted | 2015-01-13 16:29:12 +1100 (Tue, 13 Jan 2015) | 2 lines

Basis : ensure BA_Begin() has been called for BA_New() and BA_Delete() functions.

------------------------------------------------------------------------
r1543 | ajapted | 2015-01-13 15:19:59 +1100 (Tue, 13 Jan 2015) | 3 lines

Key bindings : increased maximum parameters of a binding from 4 --> 16, and
increased the maximum length of a parameter from 16 --> 32.

------------------------------------------------------------------------
r1542 | ajapted | 2015-01-13 14:56:52 +1100 (Tue, 13 Jan 2015) | 2 lines

Code : moved prototypes for Status_xxx() and Beep() functions --> main.h

------------------------------------------------------------------------
r1541 | ajapted | 2015-01-13 12:22:42 +1100 (Tue, 13 Jan 2015) | 4 lines

Find/Replace : implemented rep_value_callback(), ensuring the 'Apply' and
'Replace All' buttons are only active when both the rep_value is valid and
the find_match is valid.

------------------------------------------------------------------------
r1540 | ajapted | 2015-01-13 11:58:40 +1100 (Tue, 13 Jan 2015) | 2 lines

Find/Replace : support '*' wildcard in number_group_c

------------------------------------------------------------------------
r1539 | ajapted | 2015-01-12 23:17:13 +1100 (Mon, 12 Jan 2015) | 2 lines

Code tweak : consistent capitalization for top-of-file descriptions.

------------------------------------------------------------------------
r1538 | ajapted | 2015-01-12 23:04:23 +1100 (Mon, 12 Jan 2015) | 3 lines

Code : removed commented-out code for CMD_FindObjectByType() -- the new
Find/Replace panel implements equivalent functionality.

------------------------------------------------------------------------
r1537 | ajapted | 2015-01-12 23:01:48 +1100 (Mon, 12 Jan 2015) | 9 lines

Objid rework:
1. moved obj_type_e definition --> objid.h
2. removed 'OBJ_NONE' as a member of obj_type_e enumeration
3. renamed 'OBJ_NO_NONE' constant --> 'NIL_OBJ'
4. in Objid class, replaced '()' operator with 'valid()' method
5. removed the barely used is_obj() macro
6. renamed 'edit.highlighted' --> 'edit.highlight'

------------------------------------------------------------------------
r1536 | ajapted | 2015-01-12 21:00:51 +1100 (Mon, 12 Jan 2015) | 2 lines

Find/Replace : tweaked size of 'what' choice widget.

------------------------------------------------------------------------
r1535 | ajapted | 2015-01-12 20:58:23 +1100 (Mon, 12 Jan 2015) | 7 lines

Find/Replace :
1. remove the toggle button for the Replace section, was rather unnecessary,
   and now there is more room for the Filters section.

2. made the 'what' choice (Things, Line Textures, etc) be colored, using
   colors that match the mode colors in infobar widget.

------------------------------------------------------------------------
r1534 | ajapted | 2015-01-12 19:50:23 +1100 (Mon, 12 Jan 2015) | 4 lines

Find/Replace : better handling of 'Select All' button, e.g. beep with
"nothing found" message if nothing was found, and if some stuff _was_
found then use GoToSelection() to move/zoom in to it.

------------------------------------------------------------------------
r1533 | ajapted | 2015-01-12 19:38:54 +1100 (Mon, 12 Jan 2015) | 4 lines

Find/Replace :
1. Got the 'number_group_c' class working, can find things with it now.
2. Make sure selection is cleared after nothing is found

------------------------------------------------------------------------
r1532 | ajapted | 2015-01-12 18:55:59 +1100 (Mon, 12 Jan 2015) | 3 lines

Find/Replace : created a 'number_group_c' class for storing a small group
of numbers or number ranges.  Also implemented its ParseString() method.

------------------------------------------------------------------------
r1531 | ajapted | 2015-01-12 18:19:44 +1100 (Mon, 12 Jan 2015) | 4 lines

Removed the 'selectn.cc/h' code files -- merged the code into levels.cc/h

Also moved some code from objects.cc/h --> levels.cc/h (notification stuff)

------------------------------------------------------------------------
r1530 | ajapted | 2015-01-12 18:09:13 +1100 (Mon, 12 Jan 2015) | 2 lines

Find/Replace : bit more work, got basic Thing matching working.

------------------------------------------------------------------------
r1529 | ajapted | 2015-01-12 16:53:31 +1100 (Mon, 12 Jan 2015) | 2 lines

Find/Replace : properly set the description for a thing type (etc).

------------------------------------------------------------------------
r1528 | ajapted | 2015-01-12 16:46:27 +1100 (Mon, 12 Jan 2015) | 3 lines

Find/Replace : implemented find_match callback, e.g. validate that the
string is numeric (for Things or for line/sector types).

------------------------------------------------------------------------
r1527 | ajapted | 2015-01-12 15:57:04 +1100 (Mon, 12 Jan 2015) | 2 lines

Added Editor_ChangeMode_Raw() function.

------------------------------------------------------------------------
r1526 | ajapted | 2015-01-12 15:18:32 +1100 (Mon, 12 Jan 2015) | 4 lines

Find/Replace : worked on outer logic for finding the first/next object, and
for selecting everything or doing a replace on all matches.  The inner logic
(MatchObject or ApplyReplace methods) are not started yet....

------------------------------------------------------------------------
r1525 | ajapted | 2015-01-12 15:10:04 +1100 (Mon, 12 Jan 2015) | 2 lines

minor rename

------------------------------------------------------------------------
r1524 | ajapted | 2015-01-12 14:57:11 +1100 (Mon, 12 Jan 2015) | 2 lines

Coding : removed unused macros (IsSelected, SelectObject, etc) from selectn.h

------------------------------------------------------------------------
r1523 | ajapted | 2015-01-12 14:24:54 +1100 (Mon, 12 Jan 2015) | 3 lines

Find/Replace : bit more work, added Clear() method, added several more
callback functions (skeletal atm), call BrowsedItem() from UI_MainWin.

------------------------------------------------------------------------
r1522 | ajapted | 2015-01-12 12:13:05 +1100 (Mon, 12 Jan 2015) | 4 lines

Preferences : enabled the 'Maximize on start-up' option, except for MacOS X
platform.  This is instead of restoring the last window position and maximized
state, which is non-trivial (especially on Linux), but better than nothing.

------------------------------------------------------------------------
r1521 | ajapted | 2015-01-12 11:56:19 +1100 (Mon, 12 Jan 2015) | 2 lines

Added 'Toggle 3D View' command to the VIEW menu.

------------------------------------------------------------------------
r1520 | ajapted | 2015-01-12 11:45:49 +1100 (Mon, 12 Jan 2015) | 2 lines

Default probs : layout tweak.

------------------------------------------------------------------------
r1519 | ajapted | 2015-01-12 11:42:16 +1100 (Mon, 12 Jan 2015) | 3 lines

Default props : added labels above the textures, and spaced the three groups
out some more.

------------------------------------------------------------------------
r1518 | ajapted | 2015-01-12 11:13:05 +1100 (Mon, 12 Jan 2015) | 3 lines

Preferences : when the 'browser_small_tex' value is changed, re-populate
the browser (to show the resized textures).

------------------------------------------------------------------------
r1517 | ajapted | 2015-01-11 23:16:17 +1100 (Sun, 11 Jan 2015) | 2 lines

TODO.txt updated (lots of WIP stuff...)

------------------------------------------------------------------------
r1516 | ajapted | 2015-01-11 22:56:55 +1100 (Sun, 11 Jan 2015) | 3 lines

Implemented new 'browser_small_tex' option to show smaller textures in
the texture browser.  Includes addition to the Preferences dialog.

------------------------------------------------------------------------
r1515 | ajapted | 2015-01-11 21:35:26 +1100 (Sun, 11 Jan 2015) | 2 lines

Find/Replace : implemented the toggle buttons showing/hiding their group.

------------------------------------------------------------------------
r1514 | ajapted | 2015-01-11 21:02:47 +1100 (Sun, 11 Jan 2015) | 3 lines

Find/Replace : fixed dismissing the panel by pressing the key for the
current mode, e.g. 'v' for vertices.

------------------------------------------------------------------------
r1513 | ajapted | 2015-01-11 20:51:35 +1100 (Sun, 11 Jan 2015) | 4 lines

Find/Replace : worked on layout some more, grouping the three sub-panels into
their own group (leaving a think BG_COLOR border between each panel).  Also
tidied up the code (the output from fluid).

------------------------------------------------------------------------
r1512 | ajapted | 2015-01-11 20:21:21 +1100 (Sun, 11 Jan 2015) | 3 lines

Find/Replace : created main UI for this (done in Fluid, code reformatted
and pasted here).  Nothing works yet....

------------------------------------------------------------------------
r1511 | ajapted | 2015-01-11 17:13:10 +1100 (Sun, 11 Jan 2015) | 2 lines

Find/Replace : added 'Go to next' to View menu (not implemented yet....)

------------------------------------------------------------------------
r1510 | ajapted | 2015-01-11 17:03:54 +1100 (Sun, 11 Jan 2015) | 2 lines

Find/Replace : add widget to main window, and added menu item for it.

------------------------------------------------------------------------
r1509 | ajapted | 2015-01-11 17:02:31 +1100 (Sun, 11 Jan 2015) | 2 lines

Makefiles : added 'ui_replace.o' into the build.

------------------------------------------------------------------------
r1508 | ajapted | 2015-01-11 15:53:41 +1100 (Sun, 11 Jan 2015) | 3 lines

Added new files 'ui_replace.cc/h' -- will contain the Find and Replace panel
(only contains minimal code at the moment).

------------------------------------------------------------------------
r1507 | ajapted | 2015-01-11 15:45:16 +1100 (Sun, 11 Jan 2015) | 2 lines

Default props : fixed using the Browser to set stuff (textures etc).

------------------------------------------------------------------------
r1506 | ajapted | 2015-01-11 15:28:07 +1100 (Sun, 11 Jan 2015) | 2 lines

Default props : hide it when press CTRL-D and already shown.

------------------------------------------------------------------------
r1505 | ajapted | 2015-01-11 15:15:27 +1100 (Sun, 11 Jan 2015) | 2 lines

Default props : added command in File/ menu to show it, and various fixes.

------------------------------------------------------------------------
r1504 | ajapted | 2015-01-11 14:52:55 +1100 (Sun, 11 Jan 2015) | 2 lines

Default props : removed toggle button and related code.

------------------------------------------------------------------------
r1503 | ajapted | 2015-01-11 14:45:51 +1100 (Sun, 11 Jan 2015) | 2 lines

Default props : added "Lower" (etc) names to the wall texture pics.

------------------------------------------------------------------------
r1502 | ajapted | 2015-01-11 14:07:15 +1100 (Sun, 11 Jan 2015) | 3 lines

Finished separating UI_DefaultProps code, splitting the implementation into
header file + code file definitions.

------------------------------------------------------------------------
r1501 | ajapted | 2015-01-11 13:57:04 +1100 (Sun, 11 Jan 2015) | 2 lines

(forgot 'Makefile' in previous commit)

------------------------------------------------------------------------
r1500 | ajapted | 2015-01-11 13:45:05 +1100 (Sun, 11 Jan 2015) | 3 lines

More work to separate UI_DefaultProps code -- mainly deleting the relevant
parts from ui_vertex.* and ui_default.* -- but also updated the Makefiles.

------------------------------------------------------------------------
r1499 | ajapted | 2015-01-11 13:35:17 +1100 (Sun, 11 Jan 2015) | 3 lines

Began work to separate code for the 'Default Properties' panel into its own
code files --> ui_default.cc/h.   This commit merely copies the new files.

------------------------------------------------------------------------
r1498 | ajapted | 2015-01-11 13:31:07 +1100 (Sun, 11 Jan 2015) | 3 lines

Always show a two-sided line in LineDef panel when multiple lines are selected
(and are a mix of one-sided and two-sided lines).

------------------------------------------------------------------------
r1497 | ajapted | 2015-01-09 14:30:00 +1100 (Fri, 09 Jan 2015) | 2 lines

Wad code : re-sort the levels[] array after adding a new level.

------------------------------------------------------------------------
r1496 | ajapted | 2015-01-07 13:32:52 +1100 (Wed, 07 Jan 2015) | 3 lines

Keys : convert FL_Button+n values <--> "MOUSE##" string, and FL_WheelUp/Dn
values <--> "WHEEL_UP/DN" strings.

------------------------------------------------------------------------
r1495 | ajapted | 2015-01-06 16:01:31 +1100 (Tue, 06 Jan 2015) | 2 lines

TODO.txt : moved the 'NO:' stuff to a separate NOT-TO-DO section.

------------------------------------------------------------------------
r1494 | ajapted | 2015-01-06 15:55:59 +1100 (Tue, 06 Jan 2015) | 3 lines

Finished support for RECENT browser category, with new binding for '\' key
which toggles between the ALL and RECENT categories.

------------------------------------------------------------------------
r1493 | ajapted | 2015-01-06 13:57:11 +1100 (Tue, 06 Jan 2015) | 4 lines

More work on new "RECENT" category for Texture (etc) browsers.
Implemented ability to save/restore them from the .dat cache file,
and fixed a few issues.

------------------------------------------------------------------------
r1492 | ajapted | 2015-01-06 13:55:15 +1100 (Tue, 06 Jan 2015) | 3 lines

Menu : removed short-cut from 'File/Delete Map' command, as it likely will
be used rarely and it's not something you want to hit accidentally.

------------------------------------------------------------------------
r1491 | ajapted | 2015-01-06 11:05:17 +1100 (Tue, 06 Jan 2015) | 2 lines

Partial work on a "RECENT" category for the Texture, Flat and Thing browsers.

------------------------------------------------------------------------
r1490 | ajapted | 2015-01-05 19:31:27 +1100 (Mon, 05 Jan 2015) | 2 lines

Updated some copyright messages (e.g. About box) for 2015.

------------------------------------------------------------------------
r1489 | ajapted | 2015-01-05 19:30:50 +1100 (Mon, 05 Jan 2015) | 2 lines

Version bump.

------------------------------------------------------------------------
r1488 | ajapted | 2015-01-05 19:14:57 +1100 (Mon, 05 Jan 2015) | 2 lines

Render : fixed clipping of mid-masked textures (e.g. the cage in E1M9)

------------------------------------------------------------------------
r1487 | ajapted | 2015-01-05 11:55:34 +1100 (Mon, 05 Jan 2015) | 2 lines

Moved the BA_LevelChecksum() code from e_loadsave --> e_basis

------------------------------------------------------------------------
r1486 | ajapted | 2015-01-05 11:54:31 +1100 (Mon, 05 Jan 2015) | 3 lines

Wad code : sort the levels alphabetically in the levels[] vector (mainly for
the next-map and prev-map commands).

------------------------------------------------------------------------
r1485 | ajapted | 2015-01-05 11:10:08 +1100 (Mon, 05 Jan 2015) | 2 lines

Implemented the 'File / Rename Map' command (no shortcut key).

------------------------------------------------------------------------
r1484 | ajapted | 2015-01-05 10:21:10 +1100 (Mon, 05 Jan 2015) | 2 lines

Wad code : implemented 'RenameLump()' method.

------------------------------------------------------------------------
r1483 | ajapted | 2015-01-05 10:07:04 +1100 (Mon, 05 Jan 2015) | 2 lines

Implemented new 'File / Delete Map' command (bound to CTRL-d key).

------------------------------------------------------------------------
r1482 | ajapted | 2015-01-04 20:50:46 +1100 (Sun, 04 Jan 2015) | 5 lines

Reworked the way "New WAD File" button in the 'New Map' command works, it is
now a radio button with another choice "Current WAD File", and when chosen
then we immediately try to save (export) the new map -- which feels more
like what the user would expect.

------------------------------------------------------------------------
r1481 | ajapted | 2015-01-04 20:10:14 +1100 (Sun, 04 Jan 2015) | 2 lines

TODO update.

------------------------------------------------------------------------
r1480 | ajapted | 2015-01-04 20:06:35 +1100 (Sun, 04 Jan 2015) | 3 lines

Fixed the occasional false positives with the sector mismatch test
(caused by poor logic in OppositeLineDef and OppositeSector functions).

------------------------------------------------------------------------
r1479 | ajapted | 2015-01-04 20:04:46 +1100 (Sun, 04 Jan 2015) | 3 lines

Fixed zooming after doing a command, like 'j' JumpToObject, which moves the
map origin to focus on some selected object(s).

------------------------------------------------------------------------
r1478 | ajapted | 2015-01-04 16:48:05 +1100 (Sun, 04 Jan 2015) | 2 lines

Makefile.xming : updated to use 'mingw-w64' cross compiler and zlib 1.2.8

------------------------------------------------------------------------
r1477 | ajapted | 2015-01-04 16:34:56 +1100 (Sun, 04 Jan 2015) | 2 lines

Removed 'slurp' directory from obj_linux/ and obj_win32/

------------------------------------------------------------------------
r1476 | ajapted | 2015-01-04 16:32:14 +1100 (Sun, 04 Jan 2015) | 2 lines

Makefiles : added 'STRIP_FLAGS' variable (for "stripped" target).

------------------------------------------------------------------------
r1475 | ajapted | 2015-01-04 16:01:35 +1100 (Sun, 04 Jan 2015) | 4 lines

For 'New Map' dialog, added a "New File" check button which means the wad
will be saved into a new file (disables the map selection, since that is
done by the export map dialog).

------------------------------------------------------------------------
r1474 | ajapted | 2015-01-04 11:55:08 +1100 (Sun, 04 Jan 2015) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1473 | ajapted | 2015-01-04 11:54:26 +1100 (Sun, 04 Jan 2015) | 2 lines

Support two numeric values after -warp, compatible with vanilla DOOM.

------------------------------------------------------------------------
r1472 | ajapted | 2015-01-04 11:30:20 +1100 (Sun, 04 Jan 2015) | 3 lines

Linedef panel : swapped 'Tag' and 'Length' widgets(so Tag is now on left
(like the Sector panel).

------------------------------------------------------------------------
r1471 | ajapted | 2015-01-04 11:25:27 +1100 (Sun, 04 Jan 2015) | 2 lines

Code : silence some compiler warnings about integer conversions.

------------------------------------------------------------------------
r1470 | printz | 2015-01-03 09:01:20 +1100 (Sat, 03 Jan 2015) | 3 lines

osx:
* Fixed type warnings on the app delegate because I didn't set it to conform to the NSApplicationDelegate protocol
* Added other .a files to the dependency list, because I was getting linker errors.
------------------------------------------------------------------------
r1469 | printz | 2014-11-15 10:06:48 +1100 (Sat, 15 Nov 2014) | 2 lines

* Updated Xcode project to work
* Removed a personal file
------------------------------------------------------------------------
r1468 | ajapted | 2014-10-25 22:34:34 +1100 (Sat, 25 Oct 2014) | 4 lines

Support 'coop_dm_flags' feature in game definitions, and when not enabled
then show a vanilla DOOM compatible "dm" thing flag (instead of the normal
three sp/coop/dm flags).

------------------------------------------------------------------------
r1467 | ajapted | 2014-10-25 22:00:21 +1100 (Sat, 25 Oct 2014) | 2 lines

Fixed makefile "install" targets for r1459 (moved "bindings.cfg" to top level)

------------------------------------------------------------------------
r1466 | ajapted | 2014-10-25 21:54:50 +1100 (Sat, 25 Oct 2014) | 3 lines

UI_Window : added UpdateGameInfo() method, and use it for THING panel to
show or hide the "friend" checkbox depending on game_info.friend_flag

------------------------------------------------------------------------
r1465 | ajapted | 2014-10-25 21:53:26 +1100 (Sat, 25 Oct 2014) | 2 lines

Added 'friend_flag' field to game_info_t and parse it from definition files.

------------------------------------------------------------------------
r1464 | ajapted | 2014-10-25 21:52:16 +1100 (Sat, 25 Oct 2014) | 2 lines

Ports / BOOM : added "feature friend_flag 1"

------------------------------------------------------------------------
r1463 | ajapted | 2014-10-25 21:27:26 +1100 (Sat, 25 Oct 2014) | 3 lines

Use simple char[] for 'sky_flat' member of game_info, so we can memset() the
whole structure to zero in M_InitDefinitions().

------------------------------------------------------------------------
r1462 | ajapted | 2014-10-25 20:11:57 +1100 (Sat, 25 Oct 2014) | 4 lines

(part of VM removal) : removed 'misc/core_defs.up' script file, which was
never used and barely had anything in it.  Updated 'make install' targets
in the Makefiles too.

------------------------------------------------------------------------
r1461 | ajapted | 2014-10-25 20:07:13 +1100 (Sat, 25 Oct 2014) | 3 lines

Removed all the VM code (vm.h + vm_*.cc) -- this was never used and was a
long way from becoming usable.  Lua would be a better choice anyway.

------------------------------------------------------------------------
r1460 | ajapted | 2014-10-25 19:52:30 +1100 (Sat, 25 Oct 2014) | 2 lines

Preferences : added '192' to list of possible default grid sizes.

------------------------------------------------------------------------
r1459 | ajapted | 2014-09-12 20:29:11 +1000 (Fri, 12 Sep 2014) | 3 lines

Moved 'bindings.cfg' to top level in repository, so that running Eureka after a
compilation (without installing it) works.

------------------------------------------------------------------------
r1458 | ajapted | 2014-09-12 20:22:51 +1000 (Fri, 12 Sep 2014) | 2 lines

silence a compiler warning.

------------------------------------------------------------------------
r1457 | ajapted | 2014-08-15 15:28:58 +1000 (Fri, 15 Aug 2014) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1456 | ajapted | 2014-08-15 13:45:35 +1000 (Fri, 15 Aug 2014) | 5 lines

3D View : fixed texturing issue, textures could be vertically off by a
pixel (due to the way casting float --> int will round towards zero).

This closes ticket #3.  Bug reported by 'umbrakun'.

------------------------------------------------------------------------
r1455 | ajapted | 2014-08-06 16:14:06 +1000 (Wed, 06 Aug 2014) | 2 lines

README.txt : added contact details at the end.

------------------------------------------------------------------------
r1454 | ajapted | 2014-08-06 15:49:34 +1000 (Wed, 06 Aug 2014) | 2 lines

TODO update.

------------------------------------------------------------------------
r1453 | ajapted | 2014-06-25 22:05:45 +1000 (Wed, 25 Jun 2014) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1452 | ajapted | 2014-06-25 22:04:01 +1000 (Wed, 25 Jun 2014) | 8 lines

glBSP library : improved method of creating a dummy node, we now
create a real subsector and a real seg for the back side of the
partition line (though the seg is a carbon copy of an existing one).

This method should be more robust, since the created structures are
all real (instead of re-using an index number).  Tested in various
software rendered ports without any problem.

------------------------------------------------------------------------
r1451 | ajapted | 2014-06-25 21:32:11 +1000 (Wed, 25 Jun 2014) | 3 lines

Removed misc/slurp -- (a) it does not belong here, and (b) I do not
plan to finish or release it.

------------------------------------------------------------------------
r1450 | ajapted | 2014-06-25 21:15:11 +1000 (Wed, 25 Jun 2014) | 2 lines

Comment the NSIS makefile and 'nsi' file as OLD / OBSOLETE.

------------------------------------------------------------------------
r1449 | ajapted | 2014-06-25 19:53:59 +1000 (Wed, 25 Jun 2014) | 3 lines

Ports / BOOM : added "feature gen_types 1" -- this will (in the future)
enable support for generalized linedefs and sectors.

------------------------------------------------------------------------
r1448 | ajapted | 2014-06-25 19:51:55 +1000 (Wed, 25 Jun 2014) | 6 lines

Game definition parser : support "feature" keyword which is used to
activate (or de-activate) certain game- or port-related features.

So far three feature names are _parsed_, but there is no actual
support for those features yet.

------------------------------------------------------------------------
r1447 | printz | 2014-06-25 17:27:19 +1000 (Wed, 25 Jun 2014) | 3 lines

Xcode project:
* Updated library references
* Made it so all source files (at least from the C++ group) will have real tabs instead of groups of spaces
------------------------------------------------------------------------
r1446 | ajapted | 2014-06-19 22:31:53 +1000 (Thu, 19 Jun 2014) | 2 lines

glBSP library : more dramatic warning when creating a dummy node.

------------------------------------------------------------------------
r1445 | ajapted | 2014-06-19 22:14:18 +1000 (Thu, 19 Jun 2014) | 6 lines

glBSP library : implemented a hack for the case when no nodes are
generated (i.e. when the whole level is a single convex sector).

This hack involves creating a dummy node with the real subsector
on one side, and a dummy one on the other.

------------------------------------------------------------------------
r1444 | ajapted | 2014-06-19 20:38:08 +1000 (Thu, 19 Jun 2014) | 2 lines

TODO.txt : moved more stuff --> doc/MiscNotes.txt

------------------------------------------------------------------------
r1443 | ajapted | 2014-06-19 19:20:55 +1000 (Thu, 19 Jun 2014) | 3 lines

TODO.txt : updated various entries, and moved some of the notes to a
new file --> docs/MiscNotes.txt

------------------------------------------------------------------------
r1442 | ajapted | 2014-06-19 19:05:47 +1000 (Thu, 19 Jun 2014) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1441 | ajapted | 2014-06-19 19:01:17 +1000 (Thu, 19 Jun 2014) | 2 lines

About box : show version number _in_ the text (not just window title).

------------------------------------------------------------------------
r1440 | ajapted | 2014-06-19 18:47:45 +1000 (Thu, 19 Jun 2014) | 2 lines

When saving the map, save any header data too (for FraggleScript etc).

------------------------------------------------------------------------
r1439 | ajapted | 2014-06-19 18:27:28 +1000 (Thu, 19 Jun 2014) | 3 lines

When loading a map, load any data in the header lump, especially the
FraggleScript and level-info data used by DOOM Legacy.

------------------------------------------------------------------------
r1438 | ajapted | 2014-06-19 17:45:39 +1000 (Thu, 19 Jun 2014) | 2 lines

Makefile.xming (WIN32) : update to FLTK 1.3.2 and zlib 1.2.6

------------------------------------------------------------------------
r1437 | ajapted | 2014-06-19 13:07:06 +1000 (Thu, 19 Jun 2014) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1436 | ajapted | 2014-06-19 13:05:54 +1000 (Thu, 19 Jun 2014) | 8 lines

Support loading a pwad which is READ-ONLY.

This will cause the 'Save' action to ask whether to export to a file,
and the 'Build Nodes' action will show a fail message.  The window
title will also show the read-only state of the current file.

This closes bug ticket #2.

------------------------------------------------------------------------
r1435 | ajapted | 2014-05-18 16:59:56 +1000 (Sun, 18 May 2014) | 2 lines

File menu : tweaked position of Build Nodes entry.

------------------------------------------------------------------------
r1434 | ajapted | 2014-05-18 16:54:44 +1000 (Sun, 18 May 2014) | 4 lines

Fixed bug when saving a map and using the "ExMx" buttons -- there was
an erroneous newline added to the lump name, preventing the game from
accessing the map.  Thanks to ettingrinder for the bug report.

------------------------------------------------------------------------
r1433 | ajapted | 2014-01-26 00:16:36 +1100 (Sun, 26 Jan 2014) | 3 lines

Fixed bug not loading 'ASHWALL' texture for DOOM 1, which occurred
because we erroneously skipped the first entry of TEXTURE2 lump.

------------------------------------------------------------------------
r1432 | ajapted | 2014-01-26 00:14:51 +1100 (Sun, 26 Jan 2014) | 2 lines

Began fresh CHANGES.txt document (after 1.00 release)

------------------------------------------------------------------------
r1431 | ajapted | 2014-01-26 00:13:52 +1100 (Sun, 26 Jan 2014) | 2 lines

Moved version 1.00 CHANGELOG --> changelogs/100.txt

------------------------------------------------------------------------
r1430 | ajapted | 2014-01-09 10:26:25 +1100 (Thu, 09 Jan 2014) | 2 lines

Post-release version bump.

------------------------------------------------------------------------
r1429 | ajapted | 2014-01-05 22:31:54 +1100 (Sun, 05 Jan 2014) | 2 lines

Updated some copyright years (e.g. in About box) for 2014.

------------------------------------------------------------------------
r1428 | ajapted | 2014-01-05 21:26:00 +1100 (Sun, 05 Jan 2014) | 2 lines

Re-instated the '192' grid size (reverted revision 628).

------------------------------------------------------------------------
r1427 | ajapted | 2013-12-27 10:22:24 +1100 (Fri, 27 Dec 2013) | 2 lines

Updated GPL.txt -- the GNU General Public License (version 2).

------------------------------------------------------------------------
r1426 | ajapted | 2013-10-27 14:21:34 +1100 (Sun, 27 Oct 2013) | 2 lines

Makefile : renamed INSTALL_PREFIX --> PREFIX

------------------------------------------------------------------------
r1425 | ajapted | 2013-10-27 13:49:10 +1100 (Sun, 27 Oct 2013) | 2 lines

Use I_ROUND() macro instead of round() standard library call.

------------------------------------------------------------------------
r1424 | ajapted | 2013-09-09 20:02:55 +1000 (Mon, 09 Sep 2013) | 2 lines

Workaround a compiler warning.

------------------------------------------------------------------------
r1423 | ajapted | 2013-08-25 15:26:16 +1000 (Sun, 25 Aug 2013) | 2 lines

History.txt : resync for the 1.00 release.

------------------------------------------------------------------------
r1422 | ajapted | 2013-08-25 15:20:46 +1000 (Sun, 25 Aug 2013) | 2 lines

Pack-source script: handle the 'ups' folder (as per 'mods' etc).

------------------------------------------------------------------------
r1421 | ajapted | 2013-08-25 14:58:40 +1000 (Sun, 25 Aug 2013) | 2 lines

README.txt : more updates to the keys list.

------------------------------------------------------------------------
r1420 | ajapted | 2013-08-25 14:48:04 +1000 (Sun, 25 Aug 2013) | 2 lines

README.txt : updated key list for ';' and 3D view offset commands.

------------------------------------------------------------------------
r1419 | ajapted | 2013-08-25 14:36:09 +1000 (Sun, 25 Aug 2013) | 2 lines

README.txt : simplified the INTRODUCTION section.

------------------------------------------------------------------------
r1418 | printz | 2013-08-25 09:18:26 +1000 (Sun, 25 Aug 2013) | 7 lines

osx:
* Added a new generic OSX call module, for interfacing OSX system calls with the main application C++ code
* Prepared Xcode project for release
* Corrected copyright in my modules to actually refer to the author(s) of Eureka in whole, not to the author of the module.
* Removed dead code from AppDelegate.mm
* Updated OSX icon
* Fixed main.cc to use system-proof application data directories.

------------------------------------------------------------------------
r1417 | ajapted | 2013-08-23 21:52:21 +1000 (Fri, 23 Aug 2013) | 2 lines

INSTALL.txt tweak.

------------------------------------------------------------------------
r1416 | ajapted | 2013-08-23 21:44:10 +1000 (Fri, 23 Aug 2013) | 2 lines

CHANGELOG tweak for 1.00 release.

------------------------------------------------------------------------
r1415 | ajapted | 2013-08-23 21:34:00 +1000 (Fri, 23 Aug 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r1414 | ajapted | 2013-08-23 15:33:43 +1000 (Fri, 23 Aug 2013) | 2 lines

NSIS install script : updated to use the Modern UI (MUI2.nsh).

------------------------------------------------------------------------
r1413 | ajapted | 2013-08-23 15:30:07 +1000 (Fri, 23 Aug 2013) | 3 lines

Makefile.xming : updated 'nsis_build' target to add "ups" folder and to
copy the "about_logo.png" and "core_defs.up" files.

------------------------------------------------------------------------
r1412 | ajapted | 2013-08-23 15:05:08 +1000 (Fri, 23 Aug 2013) | 2 lines

Makefile.xming : properly include the Win32 resource stuff in the build.

------------------------------------------------------------------------
r1411 | ajapted | 2013-08-23 14:51:50 +1000 (Fri, 23 Aug 2013) | 2 lines

Updated WIN32 "rc" file to include the ICON resource.

------------------------------------------------------------------------
r1410 | ajapted | 2013-08-23 14:51:17 +1000 (Fri, 23 Aug 2013) | 3 lines

Fixed WIN32 icon file (eureka.ico) -- I accidentally committed the XCF
version before.

------------------------------------------------------------------------
r1409 | ajapted | 2013-08-23 14:42:56 +1000 (Fri, 23 Aug 2013) | 2 lines

Makefile.xming : added 'fltk_png.a' library to the build.

------------------------------------------------------------------------
r1408 | ajapted | 2013-08-23 14:39:37 +1000 (Fri, 23 Aug 2013) | 2 lines

Fixed bug in WIN32-specific code.

------------------------------------------------------------------------
r1407 | ajapted | 2013-08-23 14:37:11 +1000 (Fri, 23 Aug 2013) | 2 lines

Quieten some compiler warnings.

------------------------------------------------------------------------
r1406 | ajapted | 2013-08-23 14:24:38 +1000 (Fri, 23 Aug 2013) | 2 lines

Created a 128x128 win32 icon and a 32x32 linux xpm from Jason's logo.

------------------------------------------------------------------------
r1405 | ajapted | 2013-08-22 22:32:34 +1000 (Thu, 22 Aug 2013) | 2 lines

TODO updated.

------------------------------------------------------------------------
r1404 | ajapted | 2013-08-22 21:48:25 +1000 (Thu, 22 Aug 2013) | 2 lines

Version bump to 1.00, heading towards a release...

------------------------------------------------------------------------
r1403 | ajapted | 2013-08-22 21:42:42 +1000 (Thu, 22 Aug 2013) | 2 lines

CHANGELOG: more tweakage.

------------------------------------------------------------------------
r1402 | ajapted | 2013-08-22 21:35:06 +1000 (Thu, 22 Aug 2013) | 6 lines

3D View:
1. implemented logic to determine coordinates for a highlighted wall
   and then create the lines to draw.

2. removed some old, non-working highlight code.

------------------------------------------------------------------------
r1401 | ajapted | 2013-08-22 16:30:35 +1000 (Thu, 22 Aug 2013) | 2 lines

3D View: more work on logic to highlight walls....

------------------------------------------------------------------------
r1400 | ajapted | 2013-08-22 15:37:20 +1000 (Thu, 22 Aug 2013) | 3 lines

3D View: use current highlight info for offset adjustment and alignment
commands (rather than perform a redundant query).

------------------------------------------------------------------------
r1399 | ajapted | 2013-08-22 14:40:03 +1000 (Thu, 22 Aug 2013) | 3 lines

3D View: added logic to keep track of a "highlighted" wotsit, and to only
redraw the view when it changes.

------------------------------------------------------------------------
r1398 | ajapted | 2013-08-22 14:12:53 +1000 (Thu, 22 Aug 2013) | 4 lines

3D View:
1. began work on ability to highlight sidedef under the mouse
2. moved some code around

------------------------------------------------------------------------
r1397 | ajapted | 2013-08-21 22:50:28 +1000 (Wed, 21 Aug 2013) | 2 lines

CHANGELOG : update and tweakage.

------------------------------------------------------------------------
r1396 | ajapted | 2013-08-21 22:49:36 +1000 (Wed, 21 Aug 2013) | 2 lines

Texture alignment: added 'X', 'Y', 'Z' key bindings.

------------------------------------------------------------------------
r1395 | ajapted | 2013-08-21 22:29:00 +1000 (Wed, 21 Aug 2013) | 5 lines

Texture alignment:
1. support for 'r' flag : align with wall "to the right"
2. PartialTexCmp() now compares 6 letters, not 4
3. tweaked scoring function for adjoiners

------------------------------------------------------------------------
r1394 | ajapted | 2013-08-21 19:02:58 +1000 (Wed, 21 Aug 2013) | 3 lines

Texture alignment: dead code removal: (1) old DEU alignment stuff, and
(2) my linedef-mode alignment logic.

------------------------------------------------------------------------
r1393 | ajapted | 2013-08-21 18:58:45 +1000 (Wed, 21 Aug 2013) | 3 lines

Texture alignment: implemented PickAdjoinerPart(), tweaked some code,
and removed some dead code.

------------------------------------------------------------------------
r1392 | ajapted | 2013-08-20 22:17:31 +1000 (Tue, 20 Aug 2013) | 4 lines

Texture alignment: still banging away on this, e.g. pass the particular
part (upper or lower) which the user clicked on to LineDefs_Align(),
and wrote some logic for picking which adjoiner part of align with.

------------------------------------------------------------------------
r1391 | ajapted | 2013-08-20 15:20:57 +1000 (Tue, 20 Aug 2013) | 3 lines

Texture alignment: fleshed out the logic for Y alignment, though it is
not 100% finished yet....

------------------------------------------------------------------------
r1390 | ajapted | 2013-08-17 16:22:13 +1000 (Sat, 17 Aug 2013) | 5 lines

3D_Align: more work on texture alignment:
1. the chosen adjoiner is always on the LEFT to the chosen sidedef
2. implemented DoAlignX()
3. started work on DoAlignY(), but it needs proper calculation

------------------------------------------------------------------------
r1389 | ajapted | 2013-08-17 15:51:07 +1000 (Sat, 17 Aug 2013) | 3 lines

3D_Align: for 'c' clear flag, properly handle different combinations of
the 'x' and 'y' flags.

------------------------------------------------------------------------
r1388 | ajapted | 2013-08-17 14:55:19 +1000 (Sat, 17 Aug 2013) | 2 lines

Texture alignment: implemented the 'c' (clear offsets) flag.

------------------------------------------------------------------------
r1387 | ajapted | 2013-08-17 14:37:07 +1000 (Sat, 17 Aug 2013) | 8 lines

Texture aligning: began work on new method which is done in 3D Mode.

This commit disables the 'LIN_Align' binding command, replacing it
with '3D_Align' binding command (which does nothing yet).  Updated
the default bindings too, with 'x', 'y', 'z' and 'c' keys.
The 'c' key will clear the offsets, and 'z' aligns both X and Y
(I would preferred 'a' do both, but it is used for WASD movement).

------------------------------------------------------------------------
r1386 | ajapted | 2013-08-17 14:31:30 +1000 (Sat, 17 Aug 2013) | 2 lines

Disabled the Adjoiner test code....

------------------------------------------------------------------------
r1385 | ajapted | 2013-08-02 22:46:35 +1000 (Fri, 02 Aug 2013) | 2 lines

minor update.

------------------------------------------------------------------------
r1384 | ajapted | 2013-08-02 21:23:52 +1000 (Fri, 02 Aug 2013) | 3 lines

Texture alignment: try to pick the next sidedef a bit more intelligently,
however I don't think this approach is really cutting the mustard....

------------------------------------------------------------------------
r1383 | ajapted | 2013-08-02 19:54:42 +1000 (Fri, 02 Aug 2013) | 4 lines

Texture alignment:
1. adjoiner scoring function: preference for same sided-ness of lines
2. added testing code -- highlight the best adjoiner of a line

------------------------------------------------------------------------
r1382 | ajapted | 2013-08-02 19:32:03 +1000 (Fri, 02 Aug 2013) | 4 lines

Texture alignment: implemented scoring logic for adjoiners, firstly
making sure that the sidedefs are actually next to each other, and
secondly giving a score based on texture matching (etc).

------------------------------------------------------------------------
r1381 | ajapted | 2013-08-02 17:22:04 +1000 (Fri, 02 Aug 2013) | 3 lines

Texture alignment: updated remaining code for 'side_on_a_line_t' typedef
and access functions.

------------------------------------------------------------------------
r1380 | ajapted | 2013-08-02 14:42:51 +1000 (Fri, 02 Aug 2013) | 4 lines

Texture alignment: introduced a 'side_on_a_line_t' typedef to simplify
passing around the LINE+SIDE references.  Partial work on the logic to
determine the adjoiner for a side.

------------------------------------------------------------------------
r1379 | ajapted | 2013-08-02 14:18:53 +1000 (Fri, 02 Aug 2013) | 2 lines

Basis : added LineDef::WhatSideDef() method.

------------------------------------------------------------------------
r1378 | ajapted | 2013-08-02 13:42:17 +1000 (Fri, 02 Aug 2013) | 3 lines

Texture alignment: a bit more work, e.g. logic for handling the unpeg
linedef flags, and added PartialTexCmp() function.

------------------------------------------------------------------------
r1377 | ajapted | 2013-08-02 12:33:09 +1000 (Fri, 02 Aug 2013) | 4 lines

LineDef panel: reverted layout of sidedef textures to match previous
versions (i.e. LOWER / RAIL / UPPER) -- although single-sided lines
still use the LOWER spot for its texture.

------------------------------------------------------------------------
r1376 | ajapted | 2013-08-02 12:26:58 +1000 (Fri, 02 Aug 2013) | 5 lines

Texture alignment: fleshed out more of the code, e.g. the logic for
collecting which sidedefs to align, and logic to pick which sidedef
to align next (ensuring we do an adjoiner _before_ that sidedef, if
possible).

------------------------------------------------------------------------
r1375 | ajapted | 2013-08-01 22:54:29 +1000 (Thu, 01 Aug 2013) | 2 lines

History.txt : added a preface about the different repositories.

------------------------------------------------------------------------
r1374 | ajapted | 2013-08-01 21:25:14 +1000 (Thu, 01 Aug 2013) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1373 | ajapted | 2013-08-01 21:12:07 +1000 (Thu, 01 Aug 2013) | 2 lines

TODO updated.

------------------------------------------------------------------------
r1372 | ajapted | 2013-08-01 21:10:45 +1000 (Thu, 01 Aug 2013) | 3 lines

Renderer: got the query() method working, and use it to determine which
linedef / sidedef to adjust the offsets on.

------------------------------------------------------------------------
r1371 | ajapted | 2013-08-01 17:16:49 +1000 (Thu, 01 Aug 2013) | 2 lines

Renderer: use SIDE_LEFT / SIDE_RIGHT rather than 0/1.

------------------------------------------------------------------------
r1370 | ajapted | 2013-08-01 17:11:04 +1000 (Thu, 01 Aug 2013) | 2 lines

Renderer: more work on query() method....

------------------------------------------------------------------------
r1369 | ajapted | 2013-08-01 16:49:41 +1000 (Thu, 01 Aug 2013) | 4 lines

Renderer: began work on a query() method which will determine what the
mouse pointer is pointing at.  It will perform a limited rendering to
determine which wall / floor under the pointer.

------------------------------------------------------------------------
r1368 | ajapted | 2013-08-01 16:47:17 +1000 (Thu, 01 Aug 2013) | 2 lines

Texture alignment: comment defining flags to LIN_Align().

------------------------------------------------------------------------
r1367 | ajapted | 2013-08-01 15:33:29 +1000 (Thu, 01 Aug 2013) | 2 lines

Preferences: tweaked layout in each panel for better consistency.

------------------------------------------------------------------------
r1366 | ajapted | 2013-08-01 13:55:28 +1000 (Thu, 01 Aug 2013) | 2 lines

Improved normal grid drawing, darken colors when lines get close together.

------------------------------------------------------------------------
r1365 | ajapted | 2013-07-31 22:31:53 +1000 (Wed, 31 Jul 2013) | 4 lines

Began work on texture alignment commands.  This commit merely replaces
the two LIN_AlignX/Y functions into a single one 'LIN_Align', with
updated key bindings file.

------------------------------------------------------------------------
r1364 | ajapted | 2013-07-31 22:22:00 +1000 (Wed, 31 Jul 2013) | 2 lines

Version bump to 0.99

------------------------------------------------------------------------
r1363 | ajapted | 2013-07-31 21:07:37 +1000 (Wed, 31 Jul 2013) | 2 lines

Preferences: fixed the 'render_lock_gravity' option.

------------------------------------------------------------------------
r1362 | ajapted | 2013-07-31 21:01:38 +1000 (Wed, 31 Jul 2013) | 2 lines

Render3D_Wheel: added 'dx' parameter, use it to move left/right.

------------------------------------------------------------------------
r1361 | ajapted | 2013-07-31 20:40:43 +1000 (Wed, 31 Jul 2013) | 2 lines

Removed obj_no_t typedef -- just use 'int' instead.

------------------------------------------------------------------------
r1360 | ajapted | 2013-07-31 20:12:29 +1000 (Wed, 31 Jul 2013) | 6 lines

Improved highlight behavior of vertices when grid-snap is enabled.

The previous method merely expanded the search range to find a vertex
to highlight (get_cur_vertex) -- this made it too easy to accidently
drag the wrong vertex.

------------------------------------------------------------------------
r1359 | ajapted | 2013-07-31 20:07:54 +1000 (Wed, 31 Jul 2013) | 2 lines

Objid class: added a copy constructor.

------------------------------------------------------------------------
r1358 | ajapted | 2013-07-31 20:05:16 +1000 (Wed, 31 Jul 2013) | 2 lines

Added Vertex_FindExact() utility function.

------------------------------------------------------------------------
r1357 | ajapted | 2013-07-31 16:03:40 +1000 (Wed, 31 Jul 2013) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1356 | ajapted | 2013-07-31 16:01:16 +1000 (Wed, 31 Jul 2013) | 3 lines

Implemented 'render_lock_gravity' config option, when enabled and gravity
is ON then you cannot move up or down in the 3D view.

------------------------------------------------------------------------
r1355 | ajapted | 2013-07-31 14:34:17 +1000 (Wed, 31 Jul 2013) | 5 lines

LineDef panel: the 'Length' widget is now an input box, and implemented
ability to enter a new length value and change all selected linedefs.

Doing this with all linedefs selected is a great way to wreck a map!

------------------------------------------------------------------------
r1354 | ajapted | 2013-07-31 14:22:11 +1000 (Wed, 31 Jul 2013) | 2 lines

Check / linedefs: layout tweak.

------------------------------------------------------------------------
r1353 | ajapted | 2013-07-31 13:38:09 +1000 (Wed, 31 Jul 2013) | 2 lines

Dead code removal : frob_things_flags().

------------------------------------------------------------------------
r1352 | ajapted | 2013-07-31 13:36:16 +1000 (Wed, 31 Jul 2013) | 2 lines

Dead code removal : frob_linedefs_flags() etc...

------------------------------------------------------------------------
r1351 | ajapted | 2013-07-31 13:13:01 +1000 (Wed, 31 Jul 2013) | 3 lines

In vertex mode, display length of last three linedefs (typically ones
which the user just added).

------------------------------------------------------------------------
r1350 | ajapted | 2013-07-30 22:23:42 +1000 (Tue, 30 Jul 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r1349 | ajapted | 2013-07-30 22:21:24 +1000 (Tue, 30 Jul 2013) | 3 lines

Better drawing of things (in THINGS mode) -- fill in their body with a
darker version of their color.

------------------------------------------------------------------------
r1348 | ajapted | 2013-07-30 21:59:08 +1000 (Tue, 30 Jul 2013) | 2 lines

Implemented mouse scaling using new 'edit.action' mechanism.

------------------------------------------------------------------------
r1347 | ajapted | 2013-07-30 16:58:21 +1000 (Tue, 30 Jul 2013) | 2 lines

Use the edit.action mechanism for dragging and the selection box.

------------------------------------------------------------------------
r1346 | ajapted | 2013-07-30 14:45:22 +1000 (Tue, 30 Jul 2013) | 3 lines

Implemented ClosestLine_CastAtAngle() utility function which finds the
closest linedef to a point casting at an arbitrary angle.

------------------------------------------------------------------------
r1345 | ajapted | 2013-07-30 14:34:26 +1000 (Tue, 30 Jul 2013) | 2 lines

Print a log message after unpacking sidedefs.

------------------------------------------------------------------------
r1344 | ajapted | 2013-07-30 14:33:53 +1000 (Tue, 30 Jul 2013) | 2 lines

LoadLevel: reset editor state _before_ loading the user state.

------------------------------------------------------------------------
r1343 | ajapted | 2013-07-29 22:38:52 +1000 (Mon, 29 Jul 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r1342 | ajapted | 2013-07-29 22:38:00 +1000 (Mon, 29 Jul 2013) | 4 lines

Adjust offsets: properly compute 'dx_factor' and 'dy_factor' values
based on the distance of the linedef to the camera.  This makes it
look like you are really dragging the texture around the wall.

------------------------------------------------------------------------
r1341 | ajapted | 2013-07-29 21:54:34 +1000 (Mon, 29 Jul 2013) | 2 lines

Adjust offsets: the SHIFT key makes the adjustment finer (slower).

------------------------------------------------------------------------
r1340 | ajapted | 2013-07-29 21:47:59 +1000 (Mon, 29 Jul 2013) | 4 lines

Removed unnecessary MarkChanges() and 'edit.RedrawMap = 1' statements.

Also fixed recent bug of texture changes not redrawing the 3D view.

------------------------------------------------------------------------
r1339 | ajapted | 2013-07-29 21:35:40 +1000 (Mon, 29 Jul 2013) | 2 lines

Dead code removal.

------------------------------------------------------------------------
r1338 | ajapted | 2013-07-29 21:29:02 +1000 (Mon, 29 Jul 2013) | 2 lines

Added GoToErrors() convenience function.

------------------------------------------------------------------------
r1337 | ajapted | 2013-07-29 21:18:08 +1000 (Mon, 29 Jul 2013) | 2 lines

Simplified handling of 'MadeChanges' global var.

------------------------------------------------------------------------
r1336 | ajapted | 2013-07-29 15:58:13 +1000 (Mon, 29 Jul 2013) | 2 lines

Disabled '!' prefix in the window title -- was not useful after all.

------------------------------------------------------------------------
r1335 | ajapted | 2013-07-29 12:28:46 +1000 (Mon, 29 Jul 2013) | 4 lines

Implemented SideDefs_NormalizeMiddles(), which is used after level load
and ensures that one-sided linedefs do not have an "Upper" or "Rail"
texture (as shown by the LineDef panel).

------------------------------------------------------------------------
r1334 | ajapted | 2013-07-28 20:05:32 +1000 (Sun, 28 Jul 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r1333 | ajapted | 2013-07-28 20:01:41 +1000 (Sun, 28 Jul 2013) | 4 lines

After loading a map, reset various editor state, especially clearing the
selection and highlight (prevent a possible crash), and update the map
totals (# of linedefs, etc) for the side panel.

------------------------------------------------------------------------
r1332 | ajapted | 2013-07-28 19:44:00 +1000 (Sun, 28 Jul 2013) | 2 lines

CHANGELOG: added the new sidedef layout.

------------------------------------------------------------------------
r1331 | ajapted | 2013-07-28 19:43:25 +1000 (Sun, 28 Jul 2013) | 4 lines

Adjust offsets: force mouse deltas to be either vertical or horizontal,
which makes it easier to make large horizontal adjustments without it
going up or down, and vice versa.

------------------------------------------------------------------------
r1330 | ajapted | 2013-07-28 19:27:02 +1000 (Sun, 28 Jul 2013) | 11 lines

LideDef panel: changed layout of textures in each SideDef section.
The default order is now LOWER / UPPER / RAIL.

Also, single-sided linedefs show the texture in the "LOWER" position,
since there is no longer a spot for a "middle" texture.

The main benefit of this is when multiple linedefs are selected which
is a mix of one-sided and two-sided lines, the user can safely change
the "LOWER" (or LOWER + UPPER) on all the linedefs without ending up
with unwanted railing textures.

------------------------------------------------------------------------
r1329 | ajapted | 2013-07-28 19:17:59 +1000 (Sun, 28 Jul 2013) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1328 | ajapted | 2013-07-28 19:00:52 +1000 (Sun, 28 Jul 2013) | 3 lines

Automatically unpack sidedefs when loading a map, since the previous
confirmation dialog was probably more of a nuisance than a help.

------------------------------------------------------------------------
r1327 | ajapted | 2013-07-28 18:45:49 +1000 (Sun, 28 Jul 2013) | 3 lines

Basis: added BA_Abort() function which discards the current group of
operations and (optionally) undoes the changes since BA_Begin().

------------------------------------------------------------------------
r1326 | ajapted | 2013-07-28 18:10:50 +1000 (Sun, 28 Jul 2013) | 3 lines

3D View: changing the aspect ratio preference setting did not update the
rendered view (unless user changed window size) -- fixed.

------------------------------------------------------------------------
r1325 | ajapted | 2013-07-28 15:43:51 +1000 (Sun, 28 Jul 2013) | 3 lines

Checks: updated missing texture detection to count "" (empty string) as a
missing texture.

------------------------------------------------------------------------
r1324 | ajapted | 2013-07-28 15:27:49 +1000 (Sun, 28 Jul 2013) | 2 lines

Dead code removal : UI_SideDef::SetTexture() method.

------------------------------------------------------------------------
r1323 | ajapted | 2013-07-28 14:12:49 +1000 (Sun, 28 Jul 2013) | 3 lines

Preferences: implemented setting for Aspect ratio in 3D view, supporting
a "CUSTOM" choice allowing the user to enter arbitrary values.

------------------------------------------------------------------------
r1322 | ajapted | 2013-07-28 13:58:19 +1000 (Sun, 28 Jul 2013) | 3 lines

3D View: added 'render_aspect_ratio' config variable, and use it when
rendering a scene.  No preference setting yet....

------------------------------------------------------------------------
r1321 | ajapted | 2013-07-28 13:56:49 +1000 (Sun, 28 Jul 2013) | 2 lines

Fixed recent bug of highlighting map stuff when 3D view is active.

------------------------------------------------------------------------
r1320 | ajapted | 2013-07-27 21:06:44 +1000 (Sat, 27 Jul 2013) | 3 lines

Render3D: moved code around, namely UpdateScreen() method of 'view' and
draw(), BlitLores() and BlitHires() methods in UI_Render3D class.

------------------------------------------------------------------------
r1319 | ajapted | 2013-07-27 17:41:55 +1000 (Sat, 27 Jul 2013) | 2 lines

Adjusting offsets: apply the offsets when mouse button is released.

------------------------------------------------------------------------
r1318 | ajapted | 2013-07-27 17:29:21 +1000 (Sat, 27 Jul 2013) | 6 lines

More work on adjusting X/Y offsets via the mouse.  Implemented the logic
to save/change/restore the current offsets in the renderer (the real
change only occurs when the user releases the button -- NYI).

It does NOT pick the linedef/sidedef properly yet....

------------------------------------------------------------------------
r1317 | ajapted | 2013-07-26 22:23:11 +1000 (Fri, 26 Jul 2013) | 4 lines

1. added Editor_ClearAction() and Editor_SetAction() functions
2. re-implemented RMB map scrolling using the action system
3. began implementation of sidedef adjustment via MMB

------------------------------------------------------------------------
r1316 | ajapted | 2013-07-26 11:08:17 +1000 (Fri, 26 Jul 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r1315 | ajapted | 2013-07-26 11:07:54 +1000 (Fri, 26 Jul 2013) | 2 lines

CHANGELOG : yet another rejig.

------------------------------------------------------------------------
r1314 | ajapted | 2013-07-26 11:01:26 +1000 (Fri, 26 Jul 2013) | 4 lines

Preferences: disabled the "maximize on startup" option.  It is planned to
replace it in a future release with code to remember the window position
and maximized state.

------------------------------------------------------------------------
r1313 | ajapted | 2013-07-25 20:44:14 +1000 (Thu, 25 Jul 2013) | 3 lines

Menu: rewrote code to populate the "Recent Files" sub-menu, using same
basic method as for "Given Files" (recreating the Fl_Menu_Item array).

------------------------------------------------------------------------
r1312 | ajapted | 2013-07-25 20:30:26 +1000 (Thu, 25 Jul 2013) | 6 lines

Menu: worked on reimplementing the way the "Given Files" and "Recent Files"
sub-menus are populated, since previous way did not work under MacOS X.

Instead of fiddling with the menu bar _after_ creating it, we fiddle with
arrays of raw Fl_Menu_Items _before_ creating it.

------------------------------------------------------------------------
r1311 | ajapted | 2013-07-25 18:52:38 +1000 (Thu, 25 Jul 2013) | 12 lines

1. removed unused 'move_speed', 'extra_zoom' fields from Editor_State_t

2. added 'edit.action' field and a set of ACT_XXXXX enumerated values
   which will bring some sanity to the handling of temporal actions
   like dragging objects, drawing a sel box, scrolling the map, etc...

3. handle the META-fier command using the 'edit.action' mechanism

4. fixed bug with META-fying logic where an unrecogized META-fied key
   would be sent on to other widgets, even coming back to be handled
   as a normal key instead of being ignored.

------------------------------------------------------------------------
r1310 | ajapted | 2013-07-25 13:53:12 +1000 (Thu, 25 Jul 2013) | 2 lines

M_ParseEurekaLump: use DLG_Confirm() instead of fl_choice.

------------------------------------------------------------------------
r1309 | ajapted | 2013-07-25 13:52:17 +1000 (Thu, 25 Jul 2013) | 3 lines

Don't quit the program when the user cancels loading a wad during parsing
of the EUREKA lump.

------------------------------------------------------------------------
r1308 | ajapted | 2013-07-25 13:37:56 +1000 (Thu, 25 Jul 2013) | 5 lines

Preferences / Keys: renamed last button to "Reset Defaults" and _always_
show the confirmation dialog, since it erases ALL the user's changes.

Code-wise: use DLG_Confirm() instead of fl_choice() there.

------------------------------------------------------------------------
r1307 | ajapted | 2013-07-25 13:18:51 +1000 (Thu, 25 Jul 2013) | 6 lines

Fixed "venetian blind" issue when drawing large dots for the grid.

The real problem is with FLTK and how it clips non-filled rectangles.
To workaround the FLTK bug, use filled rectangles instead -- it might
even be faster.

------------------------------------------------------------------------
r1306 | ajapted | 2013-07-25 13:08:23 +1000 (Thu, 25 Jul 2013) | 2 lines

Edit / Move objects: implemented 'Z' delta for sectors.

------------------------------------------------------------------------
r1305 | ajapted | 2013-07-24 23:05:57 +1000 (Wed, 24 Jul 2013) | 2 lines

Tweaked the single-line title + copyright message.

------------------------------------------------------------------------
r1304 | ajapted | 2013-07-24 22:35:40 +1000 (Wed, 24 Jul 2013) | 3 lines

Dead code removal : MakeDoorFromSector and MakeLiftFromSector.
(that functionality may return one day, in the form of a script).

------------------------------------------------------------------------
r1303 | ajapted | 2013-07-24 22:31:04 +1000 (Wed, 24 Jul 2013) | 2 lines

Dead code removal : bv_vertices_of_xxx and linedefs_of_sector(s).

------------------------------------------------------------------------
r1302 | ajapted | 2013-07-24 22:27:18 +1000 (Wed, 24 Jul 2013) | 2 lines

Dead code removal : Superimposed_ld class.

------------------------------------------------------------------------
r1301 | printz | 2013-07-24 19:22:04 +1000 (Wed, 24 Jul 2013) | 4 lines

osx:
* Updated Xcode project to Makefile's new specifications
* Updated the info plist to the current version
* Updated the icns file to the new logo. File is a bit too large now,
  especially after I used a free tool called "Retina Icon Binder".
  Thus the total package size is even bigger than the previous OSX Eureka
  release, even if now I merely linked FLTK statically.
  Might be the redundant lower-scale icons adding to the size.
  I need a better ICNS tool that can safely delete the smaller icons.

------------------------------------------------------------------------
r1300 | ajapted | 2013-07-23 19:32:51 +1000 (Tue, 23 Jul 2013) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1299 | ajapted | 2013-07-23 19:22:14 +1000 (Tue, 23 Jul 2013) | 2 lines

M_WriteEurekaLump : it handles the BeginWrite/EndWrite itself now.

------------------------------------------------------------------------
r1298 | ajapted | 2013-07-23 19:21:18 +1000 (Tue, 23 Jul 2013) | 3 lines

Wad code: fixed potential issue with 'insert_point' handling which was
probably responsible for the rare level-lumps-in-wrong-order problem.

------------------------------------------------------------------------
r1297 | ajapted | 2013-07-23 16:20:47 +1000 (Tue, 23 Jul 2013) | 3 lines

File / Test map: if changes have been made, ask user if they want to
save the map and build the nodes.

------------------------------------------------------------------------
r1296 | ajapted | 2013-07-23 16:09:50 +1000 (Tue, 23 Jul 2013) | 2 lines

Tweaks.

------------------------------------------------------------------------
r1295 | ajapted | 2013-07-23 16:06:33 +1000 (Tue, 23 Jul 2013) | 2 lines

FatalError: replace single newlines with spaces for DLG_ShowError().

------------------------------------------------------------------------
r1294 | ajapted | 2013-07-23 14:59:54 +1000 (Tue, 23 Jul 2013) | 5 lines

Dialogs: added keyboard shortcuts (via '&') for all buttons except Cancel.

We don't do Cancel since "Create" button (from File / New Map) would
conflict, plus the ESCAPE key already serves that function.

------------------------------------------------------------------------
r1293 | ajapted | 2013-07-23 14:44:30 +1000 (Tue, 23 Jul 2013) | 3 lines

Wad code: no need to LogPrintf() updates to the master directory or when
reading/writing a directory from a wad -- they are now debug messages.

------------------------------------------------------------------------
r1292 | ajapted | 2013-07-23 14:43:03 +1000 (Tue, 23 Jul 2013) | 3 lines

File / Build nodes: better handle the case when there is no current pwad,
but the user has made changes (e.g. an edited IWAD map, or a fresh map).

------------------------------------------------------------------------
r1291 | ajapted | 2013-07-23 14:35:28 +1000 (Tue, 23 Jul 2013) | 3 lines

Dialogs: use UI_Escapable_Window so that dialogs can be dismissed with
the ESCAPE key.

------------------------------------------------------------------------
r1290 | ajapted | 2013-07-23 14:31:56 +1000 (Tue, 23 Jul 2013) | 4 lines

File / Build nodes: when the map has unsaved changes, we now ask the user
whether they want to save the map and then build the nodes.  (Previously
it was just a notification dialog.)

------------------------------------------------------------------------
r1289 | ajapted | 2013-07-23 14:28:15 +1000 (Tue, 23 Jul 2013) | 10 lines

Fixed bug causing a FatalError() when editing a pwad, creating a new map
which is fresh (does not replace any existing map), and then attempting
to build the nodes.  Since the new map was not saved, Eureka was unable
to re-load the map from the node-enhanced wad.

Hence creating a new map (CTRL-N) always sets the "Made Changes" flag.

This commit also makes CMD_SaveMap() and CMD_ExportMap() return a bool
indicating success or failure.

------------------------------------------------------------------------
r1288 | ajapted | 2013-07-23 14:01:08 +1000 (Tue, 23 Jul 2013) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1287 | ajapted | 2013-07-23 13:55:44 +1000 (Tue, 23 Jul 2013) | 3 lines

Show an '!' symbol in the window title when a new map would replace an
existing map in the current wad.

------------------------------------------------------------------------
r1286 | ajapted | 2013-07-23 13:41:28 +1000 (Tue, 23 Jul 2013) | 3 lines

File / Save: if a new map would replace (overwrite) an existing map,
give the user a third option: "Export" the map.

------------------------------------------------------------------------
r1285 | ajapted | 2013-07-22 22:20:54 +1000 (Mon, 22 Jul 2013) | 3 lines

Improved look of Preferences and Log-viewer windows when not using the
"Bright" color scheme -- the background at the bottom was too dark.

------------------------------------------------------------------------
r1284 | ajapted | 2013-07-22 21:38:47 +1000 (Mon, 22 Jul 2013) | 3 lines

Dialogs: copy the fl_ask (etc) behavior and make the window's position
dependent on where the mouse pointer is.

------------------------------------------------------------------------
r1283 | ajapted | 2013-07-22 21:15:40 +1000 (Mon, 22 Jul 2013) | 5 lines

Dialogs:
1. support the 'icon_type' to make different colored icons
2. ensure the left-most button gets the focus
3. fixed navigation problem (LEFT and RIGHT cursor keys)

------------------------------------------------------------------------
r1282 | ajapted | 2013-07-22 20:54:20 +1000 (Mon, 22 Jul 2013) | 4 lines

Dialogs: worked to parse and create the buttons for DLG_Confirm(), and
properly handle the var-args for DLG_Notify() and DLG_Confirm(), plus
a few other tweaks.

------------------------------------------------------------------------
r1281 | ajapted | 2013-07-22 20:19:31 +1000 (Mon, 22 Jul 2013) | 5 lines

1. Thing checker now detects if too many DM starts are present

2. moved the DOOM_PLAYER_HEIGHT and DOOM_MIN/MAX_DEATHMATCH_STARTS to
   be fields of the game_info_t structure.

------------------------------------------------------------------------
r1280 | ajapted | 2013-07-22 20:05:23 +1000 (Mon, 22 Jul 2013) | 3 lines

Removed unused confirm_t type, and the OPT_CONFIRM stuff in the config
loading and saving code.

------------------------------------------------------------------------
r1279 | ajapted | 2013-07-22 20:01:49 +1000 (Mon, 22 Jul 2013) | 2 lines

Tidied up main.h

------------------------------------------------------------------------
r1278 | ajapted | 2013-07-22 16:40:24 +1000 (Mon, 22 Jul 2013) | 2 lines

Removed code file: m_dialog.cc

------------------------------------------------------------------------
r1277 | ajapted | 2013-07-22 16:36:37 +1000 (Mon, 22 Jul 2013) | 5 lines

Dialogs: renamed Confirm() --> DLG_Confirm(), and changed the parameters
to take button names and use var-arg message.

Note that the new DLG_Confirm() is not implemented yet.

------------------------------------------------------------------------
r1276 | ajapted | 2013-07-22 16:12:32 +1000 (Mon, 22 Jul 2013) | 2 lines

Removed header files: m_dialog.h and ui_dialog.h

------------------------------------------------------------------------
r1275 | ajapted | 2013-07-22 16:05:23 +1000 (Mon, 22 Jul 2013) | 3 lines

Began work on better dialog boxes.  This commit mainly renames 'Notify'
function to 'DLG_Notify' and simplifies its parameters.

------------------------------------------------------------------------
r1274 | ajapted | 2013-07-22 15:17:27 +1000 (Mon, 22 Jul 2013) | 2 lines

Dead code removal : NotImplemented() and Confirm2() functions.

------------------------------------------------------------------------
r1273 | ajapted | 2013-07-21 16:02:13 +1000 (Sun, 21 Jul 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r1272 | ajapted | 2013-07-21 16:01:15 +1000 (Sun, 21 Jul 2013) | 2 lines

Improved scroll-bar colors.

------------------------------------------------------------------------
r1271 | ajapted | 2013-07-21 14:42:44 +1000 (Sun, 21 Jul 2013) | 2 lines

Check / textures: allow "-" on uppers when between two sky ceilings.

------------------------------------------------------------------------
r1270 | ajapted | 2013-07-21 14:29:51 +1000 (Sun, 21 Jul 2013) | 2 lines

CHANGELOG: minor rejig.

------------------------------------------------------------------------
r1269 | ajapted | 2013-07-21 14:23:17 +1000 (Sun, 21 Jul 2013) | 2 lines

Check / textures: wrote logic to detect and fix missing textures.

------------------------------------------------------------------------
r1268 | ajapted | 2013-07-21 14:00:38 +1000 (Sun, 21 Jul 2013) | 3 lines

Check / things: fixed "Remove" button for things in void to not close
the thing check dialog.

------------------------------------------------------------------------
r1267 | ajapted | 2013-07-21 13:59:29 +1000 (Sun, 21 Jul 2013) | 3 lines

Check / textures: implemented "Fix" buttons for unknown textures and
unknown flats.

------------------------------------------------------------------------
r1266 | ajapted | 2013-07-21 13:43:59 +1000 (Sun, 21 Jul 2013) | 2 lines

HERETIC: changed default floor to FLOOR00 (was FLOOR01).

------------------------------------------------------------------------
r1265 | ajapted | 2013-07-21 13:07:42 +1000 (Sun, 21 Jul 2013) | 2 lines

Ports / BOOM: added 'v' flag to point push/pull things.

------------------------------------------------------------------------
r1264 | ajapted | 2013-07-21 13:05:32 +1000 (Sun, 21 Jul 2013) | 3 lines

Check / things: improved VOID testing to ignore things with the 'v' flag
(such as Heretic's sound emitters).

------------------------------------------------------------------------
r1263 | ajapted | 2013-07-21 13:04:31 +1000 (Sun, 21 Jul 2013) | 3 lines

Game defs: implemented new 'v' thing flag for things which may exist
in the VOID, and use this flag for Heretic's sound emitters.

------------------------------------------------------------------------
r1262 | ajapted | 2013-07-21 12:39:40 +1000 (Sun, 21 Jul 2013) | 5 lines

Check / things:
1. implemented 'Remove' button for unknown things
2. more accurate testing for "in the void" things
3. added 'Remove' button for things in the void

------------------------------------------------------------------------
r1261 | ajapted | 2013-07-21 12:20:05 +1000 (Sun, 21 Jul 2013) | 2 lines

foo

------------------------------------------------------------------------
r1260 | ajapted | 2013-07-21 12:13:33 +1000 (Sun, 21 Jul 2013) | 6 lines

Check / things:
1. implemented "Log" button for unknown things, which dumps all the
   unknown id numbers to the log file (and opens the log viewer)

2. moved the unknown thing results to the top.

------------------------------------------------------------------------
r1259 | ajapted | 2013-07-20 23:22:20 +1000 (Sat, 20 Jul 2013) | 4 lines

Check / textures: implemented a "Log" button for unknown flats and textures,
which prints the names (and usage count) into the log file, then opens up
the log viewer.

------------------------------------------------------------------------
r1258 | ajapted | 2013-07-20 22:59:48 +1000 (Sat, 20 Jul 2013) | 3 lines

Log viewer: have a function to open it, which now jumps to the end
(i.e. ensures the last line is visible).

------------------------------------------------------------------------
r1257 | ajapted | 2013-07-20 22:25:26 +1000 (Sat, 20 Jul 2013) | 3 lines

Check / textures: implemented detecting unknown flats and textures,
and ability to show the sectors / lines (in the ERROR mode).

------------------------------------------------------------------------
r1256 | ajapted | 2013-07-20 22:01:19 +1000 (Sat, 20 Jul 2013) | 2 lines

Added W_TextureExists() and W_FlatExists() functions.

------------------------------------------------------------------------
r1255 | ajapted | 2013-07-20 21:49:28 +1000 (Sat, 20 Jul 2013) | 2 lines

Checks: began work on Texture checking functions....

------------------------------------------------------------------------
r1254 | ajapted | 2013-07-20 21:47:14 +1000 (Sat, 20 Jul 2013) | 3 lines

Check / things: made unknown things a serious error, since vanilla DOOM
will produce a fatal error for them.

------------------------------------------------------------------------
r1253 | ajapted | 2013-07-20 17:51:25 +1000 (Sat, 20 Jul 2013) | 2 lines

TODO: updated.

------------------------------------------------------------------------
r1252 | ajapted | 2013-07-20 17:38:10 +1000 (Sat, 20 Jul 2013) | 6 lines

Clear the ERROR mode when necessary, such as when changing the edit mode
or trying to select a new object, or certain operations that leave a
certain object selected.

For the Quantize command, we now _set_ the ERROR mode.

------------------------------------------------------------------------
r1251 | ajapted | 2013-07-20 14:33:28 +1000 (Sat, 20 Jul 2013) | 3 lines

Preferences: reserve an area in 'Other' tab for "3D Preview Options".
Nothing is there yet....

------------------------------------------------------------------------
r1250 | ajapted | 2013-07-20 14:24:50 +1000 (Sat, 20 Jul 2013) | 4 lines

Fixed assertion when the 'FlipMap' command was used and the current level
name cannot be found in the current wad (e.g. the IWAD was changed from
DOOM 2 --> DOOM 1).

------------------------------------------------------------------------
r1249 | ajapted | 2013-07-20 14:17:15 +1000 (Sat, 20 Jul 2013) | 2 lines

DOOM 1: categorized the DOOM1-specific textures.

------------------------------------------------------------------------
r1248 | ajapted | 2013-07-20 14:06:27 +1000 (Sat, 20 Jul 2013) | 2 lines

DOOM: moved the DOOM2-only textures out of common/doom_tex.ugh

------------------------------------------------------------------------
r1247 | ajapted | 2013-07-20 13:41:59 +1000 (Sat, 20 Jul 2013) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1246 | ajapted | 2013-07-20 13:31:55 +1000 (Sat, 20 Jul 2013) | 4 lines

Map view: better drawing of selected sectors, draw knobbly lines where
the knobs point inside the sectors, and skip lines that exist between
two selected sectors.

------------------------------------------------------------------------
r1245 | ajapted | 2013-07-20 11:36:26 +1000 (Sat, 20 Jul 2013) | 5 lines

Map view:
1. smaller surrounding box for highlighted things
2. improved arrow drawing for large highlighted things
3. improved arrow drawing for highlighted linedefs

------------------------------------------------------------------------
r1244 | ajapted | 2013-07-19 20:36:21 +1000 (Fri, 19 Jul 2013) | 2 lines

HERETIC: apply same fix for exit-level linetypes.

------------------------------------------------------------------------
r1243 | ajapted | 2013-07-19 20:28:36 +1000 (Fri, 19 Jul 2013) | 3 lines

DOOM: updated exit specials to use "s1" instead of "S1", to prevent
those lines showing up in the "linedefs missing a needed tag" check.

------------------------------------------------------------------------
r1242 | ajapted | 2013-07-19 20:24:54 +1000 (Fri, 19 Jul 2013) | 4 lines

Check / tags: added new test for linedefs missing a needed tag.
Needs some game definition changes to work properly, especially the
exit level types to use "s1" instead of "S1".

------------------------------------------------------------------------
r1241 | ajapted | 2013-07-19 20:00:25 +1000 (Fri, 19 Jul 2013) | 3 lines

Check / tags: finished GUI parts of detecting unmatched tagged stuff.
Also moved the Lowest/Highest values to occupy a single line.

------------------------------------------------------------------------
r1240 | ajapted | 2013-07-19 19:15:11 +1000 (Fri, 19 Jul 2013) | 3 lines

Check / tags: worked on detecting sectors with no tagged linedef and
vice versa.  This commit has the detection logic.

------------------------------------------------------------------------
r1239 | ajapted | 2013-07-19 15:59:19 +1000 (Fri, 19 Jul 2013) | 2 lines

Check / tags: fixed the "all_mode" handling.

------------------------------------------------------------------------
r1238 | ajapted | 2013-07-19 15:56:48 +1000 (Fri, 19 Jul 2013) | 2 lines

Checks.txt : a few more tag-testing ideas...

------------------------------------------------------------------------
r1237 | ajapted | 2013-07-19 15:52:49 +1000 (Fri, 19 Jul 2013) | 3 lines

Check / things: implemented ThingStuckInWall() -- finishing the support
for stuck thing detection.

------------------------------------------------------------------------
r1236 | ajapted | 2013-07-19 15:51:55 +1000 (Fri, 19 Jul 2013) | 2 lines

Renamed LineCrossesBox() --> LineTouchesBox(), and removed some unused code.

------------------------------------------------------------------------
r1235 | ajapted | 2013-07-19 14:29:09 +1000 (Fri, 19 Jul 2013) | 5 lines

Check / things: for monsters, allow a small (8 unit) leeway to overlap a
solid thing before considering it as stuck.  That's because the monster
movement code allows a monster to move a certain distance from its
starting position.

------------------------------------------------------------------------
r1234 | ajapted | 2013-07-19 13:53:02 +1000 (Fri, 19 Jul 2013) | 2 lines

Check / things: implemented detecting actors stuck in solid things.

------------------------------------------------------------------------
r1233 | ajapted | 2013-07-19 13:09:33 +1000 (Fri, 19 Jul 2013) | 3 lines

Check / things: began work on detecting players and monsters stuck in
walls or other things.

------------------------------------------------------------------------
r1232 | ajapted | 2013-07-19 11:56:33 +1000 (Fri, 19 Jul 2013) | 3 lines

Checks: removed the previous checking code -- it was not used as-is,
but some of that code or algorithms were used in the new functions.

------------------------------------------------------------------------
r1231 | ajapted | 2013-07-19 11:53:40 +1000 (Fri, 19 Jul 2013) | 2 lines

Checks: just moved code around.

------------------------------------------------------------------------
r1230 | ajapted | 2013-07-19 11:37:36 +1000 (Fri, 19 Jul 2013) | 2 lines

Port definitions: updated with 'n' (non-blocking) thing flag.

------------------------------------------------------------------------
r1229 | ajapted | 2013-07-19 11:35:31 +1000 (Fri, 19 Jul 2013) | 2 lines

HACX: updated thing defs with new 'n' (non-blocking) flag.

------------------------------------------------------------------------
r1228 | ajapted | 2013-07-19 11:31:05 +1000 (Fri, 19 Jul 2013) | 3 lines

HERETIC: updated things, added missing 'l' (lit) and 'c' (ceiling) flags
as well as the new 'n' (non-blocking) flag.

------------------------------------------------------------------------
r1227 | ajapted | 2013-07-18 22:47:55 +1000 (Thu, 18 Jul 2013) | 3 lines

Game defs: updated DOOM 1 and 2 definitions to add the 'n' non-solid flag
to all the things which need it.

------------------------------------------------------------------------
r1226 | ajapted | 2013-07-18 22:45:42 +1000 (Thu, 18 Jul 2013) | 3 lines

Game defs: support a new thing flag 'n' : Non-Solid.  This will be used
later for detecting things stuck in walls or other things.

------------------------------------------------------------------------
r1225 | ajapted | 2013-07-18 22:19:24 +1000 (Thu, 18 Jul 2013) | 2 lines

TODO and CHANGELOG update.

------------------------------------------------------------------------
r1224 | ajapted | 2013-07-18 22:15:06 +1000 (Thu, 18 Jul 2013) | 3 lines

Log viewer: finished the ability to "Save" the full logs to a file.
The grunt-work is done by new LogSaveTo(FILE *) function.

------------------------------------------------------------------------
r1223 | ajapted | 2013-07-18 21:51:41 +1000 (Thu, 18 Jul 2013) | 5 lines

Log viewer:
1. implemented copying the selected lines to the clipboard
2. made CTRL-C be a shortcut for the "Copy" button
3. renamed the "OK" button to "Close"

------------------------------------------------------------------------
r1222 | ajapted | 2013-07-18 21:01:04 +1000 (Thu, 18 Jul 2013) | 3 lines

Opposite finder: when building the binary trees, skip purely horizontal
lines in the Y tree, similarly purely vertical lines in the X tree.

------------------------------------------------------------------------
r1221 | ajapted | 2013-07-18 20:45:30 +1000 (Thu, 18 Jul 2013) | 3 lines

Log viewer: added logic to activate the "Copy" button when the user has
selected two or more lines -- otherwise it stays deactivated.

------------------------------------------------------------------------
r1220 | ajapted | 2013-07-18 19:57:30 +1000 (Thu, 18 Jul 2013) | 6 lines

Log viewer:
1. partial work to implement "Save" button
2. use a Fl_Multi_Browser, so user can select areas to copy/save
3. added a "Copy" button to bottom area (not yet functional)
4. in bottom area, place resizable gap between "OK" and other buttons

------------------------------------------------------------------------
r1219 | ajapted | 2013-07-18 19:08:16 +1000 (Thu, 18 Jul 2013) | 2 lines

Log viewer: implemented the "OK" button (to close) and "Clear" button.

------------------------------------------------------------------------
r1218 | ajapted | 2013-07-18 18:55:33 +1000 (Thu, 18 Jul 2013) | 3 lines

Log viewer: began work improving it, with a button area at the bottom
which will contain three buttons: "Save", "Clear" and "OK".

------------------------------------------------------------------------
r1217 | ajapted | 2013-07-18 17:21:19 +1000 (Thu, 18 Jul 2013) | 3 lines

Opposite finder: fixed some bugs, and actually use it to speed up the
sector mismatch test.  The new logic is roughly 4-5 times faster.

------------------------------------------------------------------------
r1216 | ajapted | 2013-07-18 16:36:24 +1000 (Thu, 18 Jul 2013) | 2 lines

Opposite finder: implemented the binary-tree testing logic.

------------------------------------------------------------------------
r1215 | ajapted | 2013-07-18 16:20:35 +1000 (Thu, 18 Jul 2013) | 3 lines

Opposite finder: in fastopp nodes, store linedefs as integers rather than
pointers.

------------------------------------------------------------------------
r1214 | ajapted | 2013-07-18 16:16:09 +1000 (Thu, 18 Jul 2013) | 3 lines

Opposite finder: moved state into a 'opp_test_state_t' structure, and
also moved the code to handle a single linedef there.

------------------------------------------------------------------------
r1213 | ajapted | 2013-07-18 15:58:10 +1000 (Thu, 18 Jul 2013) | 7 lines

Began work on a faster version of OppositeLineDef() and OppositeSector(),
mainly for the sector mismatch test.

So far: written the logic for creating a quadtree-like structure and
storing linedefs in it.  Unlike a quadtree, this is one-dimensional and
there are two of them (for X and Y dimensions).

------------------------------------------------------------------------
r1212 | ajapted | 2013-07-18 15:20:36 +1000 (Thu, 18 Jul 2013) | 3 lines

Checks / linedefs: added test for linedefs with wrong 2S (TwoSided) flag,
as well as actions to show and fix them.

------------------------------------------------------------------------
r1211 | ajapted | 2013-07-18 15:10:49 +1000 (Thu, 18 Jul 2013) | 3 lines

Checks / linedefs: implemented test for one-sided lines without blocking
flag, and actions to show and fix them.

------------------------------------------------------------------------
r1210 | ajapted | 2013-07-18 13:46:32 +1000 (Thu, 18 Jul 2013) | 3 lines

Checks: use UI_Check_base as the base for remaining dialog classes,
namely UI_Check_Sectors, UI_Check_Things and UI_Check_Tags.

------------------------------------------------------------------------
r1209 | ajapted | 2013-07-16 22:30:09 +1000 (Tue, 16 Jul 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r1208 | ajapted | 2013-07-16 22:29:18 +1000 (Tue, 16 Jul 2013) | 3 lines

Checks: converted UI_Check_Vertices and UI_Check_LineDefs classes to
use the new base class.

------------------------------------------------------------------------
r1207 | ajapted | 2013-07-16 22:19:21 +1000 (Tue, 16 Jul 2013) | 3 lines

Checks: created a base class for all the dialogs : UI_Check_base.
Nothing uses it yet....

------------------------------------------------------------------------
r1206 | ajapted | 2013-07-16 21:16:28 +1000 (Tue, 16 Jul 2013) | 7 lines

Use UI_Escapable_Window for most other dialogs with a "Cancel" button.

Not used for UI_NodeDialog since it has special behavior (first ESC
press cancels the build but keeps the window open).

Not used with UI_Check_XXX yet, pending a superclass for them.

------------------------------------------------------------------------
r1205 | ajapted | 2013-07-16 21:02:26 +1000 (Tue, 16 Jul 2013) | 3 lines

About dialog: subclass from UI_Escapable_Window, simplifying the code
e.g. no longer need our own handle() method.

------------------------------------------------------------------------
r1204 | ajapted | 2013-07-16 21:01:08 +1000 (Tue, 16 Jul 2013) | 2 lines

Added UI_Escapable_Window class -- a subclass of Fl_Double_Window.

------------------------------------------------------------------------
r1203 | ajapted | 2013-07-16 20:38:33 +1000 (Tue, 16 Jul 2013) | 2 lines

Code: re-whitespaced ui_about.cc/h to be consistent.

------------------------------------------------------------------------
r1202 | ajapted | 2013-07-16 20:11:27 +1000 (Tue, 16 Jul 2013) | 2 lines

misc/Checks.txt : more twiddling...

------------------------------------------------------------------------
r1201 | ajapted | 2013-07-16 20:10:56 +1000 (Tue, 16 Jul 2013) | 2 lines

Made some Beep() error messages more consistent.

------------------------------------------------------------------------
r1200 | ajapted | 2013-07-16 19:52:43 +1000 (Tue, 16 Jul 2013) | 2 lines

Checks: moved code around, namely TAG stuff --> e_checks2.cc

------------------------------------------------------------------------
r1199 | ajapted | 2013-07-16 19:49:37 +1000 (Tue, 16 Jul 2013) | 10 lines

Checks:
1. rearranged 'Check' menu, added 'Major stuff' item which does all
   the checks but ignores minor problems.

2. made the 'Check / ALL' menu item perform the Texture and Tags
   tests too (not just the Vert/Lin/Sec/Thing tests).

3. Code-wise, pass 'min_severity' to each CHECK_xxx function,
   instead of 'all_mode' boolean.

------------------------------------------------------------------------
r1198 | ajapted | 2013-07-16 19:06:16 +1000 (Tue, 16 Jul 2013) | 2 lines

Check / linedefs: implemented test for criss-crossing linedefs.

------------------------------------------------------------------------
r1197 | ajapted | 2013-07-16 18:08:59 +1000 (Tue, 16 Jul 2013) | 2 lines

Check / linedefs: moved code around, added linedef_minx_CMP_pred.

------------------------------------------------------------------------
r1196 | ajapted | 2013-07-16 17:10:27 +1000 (Tue, 16 Jul 2013) | 6 lines

Checks: for tests which have a "Show" button and a map-modifying button,
place the "Show" button on the left and other button on the right.

That's because the first button is navigated to by FLTK, and hence it
should ideally be a non-destructive action.

------------------------------------------------------------------------
r1195 | ajapted | 2013-07-16 17:06:58 +1000 (Tue, 16 Jul 2013) | 2 lines

Check / linedefs: added 'Remove' feature for overlapping linedefs.

------------------------------------------------------------------------
r1194 | ajapted | 2013-07-16 16:46:27 +1000 (Tue, 16 Jul 2013) | 2 lines

Checks: layout tweak.

------------------------------------------------------------------------
r1193 | ajapted | 2013-07-16 16:43:27 +1000 (Tue, 16 Jul 2013) | 2 lines

Check / linedefs: detection logic for directly overlapping linedefs.

------------------------------------------------------------------------
r1192 | ajapted | 2013-07-16 14:53:14 +1000 (Tue, 16 Jul 2013) | 2 lines

Check / linedefs: added test for linedefs without a right side.

------------------------------------------------------------------------
r1191 | ajapted | 2013-07-16 14:43:41 +1000 (Tue, 16 Jul 2013) | 3 lines

Check / linedefs: implemented zero-length linedef test, with a button to
show them (in vertex mode) and a button to remove them.

------------------------------------------------------------------------
r1190 | ajapted | 2013-07-16 13:58:52 +1000 (Tue, 16 Jul 2013) | 2 lines

New code file 'e_checks2.cc' -- it will contain linedef checking code.

------------------------------------------------------------------------
r1189 | ajapted | 2013-07-16 13:38:22 +1000 (Tue, 16 Jul 2013) | 4 lines

Check / sectors: re-implemented the mismatched sectors test, based on
the existing DEU code.  However it is quite slow, O(n^2) with number
of linedefs.

------------------------------------------------------------------------
r1188 | ajapted | 2013-07-16 13:04:51 +1000 (Tue, 16 Jul 2013) | 2 lines

Removed the now redundant GetOppositeSector() code.

------------------------------------------------------------------------
r1187 | ajapted | 2013-07-16 13:03:32 +1000 (Tue, 16 Jul 2013) | 2 lines

Added OppositeSector() function which uses OppositeLineDef().

------------------------------------------------------------------------
r1186 | ajapted | 2013-07-16 12:45:28 +1000 (Tue, 16 Jul 2013) | 2 lines

Check / things: tweaked player start messages.

------------------------------------------------------------------------
r1185 | ajapted | 2013-07-16 12:38:32 +1000 (Tue, 16 Jul 2013) | 2 lines

misc/Checks.txt updated.

------------------------------------------------------------------------
r1184 | ajapted | 2013-07-16 12:38:07 +1000 (Tue, 16 Jul 2013) | 5 lines

Check / sectors: implemented detection of unclosed sectors (mismatches
at vertices), with buttons to show the sectors and show the vertices.

Renamed XXX_Highlight --> XXX_Show, and removed a bit of dead code.

------------------------------------------------------------------------
r1183 | ajapted | 2013-07-16 10:59:25 +1000 (Tue, 16 Jul 2013) | 4 lines

Key bindings:
1. renamed binding command: AwaitMeta --> MetaKey
2. allow ';' to toggle the await_meta state on and off

------------------------------------------------------------------------
r1182 | ajapted | 2013-07-15 21:50:17 +1000 (Mon, 15 Jul 2013) | 3 lines

When loading a level, check for shared sidedefs and if exist ask user
whether to unpack them or not.

------------------------------------------------------------------------
r1181 | ajapted | 2013-07-15 21:40:06 +1000 (Mon, 15 Jul 2013) | 2 lines

Check / sectors: finished the sidedef unpacking algorithm.

------------------------------------------------------------------------
r1180 | ajapted | 2013-07-15 21:19:04 +1000 (Mon, 15 Jul 2013) | 2 lines

Check / sectors: worked on algorithm to unpack sidedefs...

------------------------------------------------------------------------
r1179 | ajapted | 2013-07-15 20:49:59 +1000 (Mon, 15 Jul 2013) | 3 lines

Check / sectors: implemented detection of shared sidedefs, and ability
to show them in the error mode.  To-Do: ability to unpack them.

------------------------------------------------------------------------
r1178 | ajapted | 2013-07-15 20:08:11 +1000 (Mon, 15 Jul 2013) | 4 lines

Check / sectors: added test for ceiling < floor height, with two action
buttons: "Fix" will set ceiling same as floor, and "Show" to highlight
them in the error_mode.

------------------------------------------------------------------------
r1177 | ajapted | 2013-07-15 19:56:46 +1000 (Mon, 15 Jul 2013) | 2 lines

Check / sectors: count unused sidedefs, and ability to remove them.

------------------------------------------------------------------------
r1176 | ajapted | 2013-07-15 19:41:24 +1000 (Mon, 15 Jul 2013) | 3 lines

Checks: began work on SECTOR checks...  So far only have unused count
(with button to remove those unused sectors).

------------------------------------------------------------------------
r1175 | ajapted | 2013-07-15 19:40:15 +1000 (Mon, 15 Jul 2013) | 2 lines

tweaked Prune message.

------------------------------------------------------------------------
r1174 | ajapted | 2013-07-15 19:26:55 +1000 (Mon, 15 Jul 2013) | 2 lines

Checks.txt : updated for current plans.

------------------------------------------------------------------------
r1173 | ajapted | 2013-07-15 19:11:54 +1000 (Mon, 15 Jul 2013) | 3 lines

Checks: when highlighting error objects, ensure we change the editor mode
when necessary.

------------------------------------------------------------------------
r1172 | ajapted | 2013-07-15 19:01:23 +1000 (Mon, 15 Jul 2013) | 2 lines

Checks: tweakage.

------------------------------------------------------------------------
r1171 | ajapted | 2013-07-15 18:53:32 +1000 (Mon, 15 Jul 2013) | 2 lines

Checks / things: added detection of things in void-space.

------------------------------------------------------------------------
r1170 | ajapted | 2013-07-15 18:41:25 +1000 (Mon, 15 Jul 2013) | 2 lines

Dead code removal : CheckStartingPos()

------------------------------------------------------------------------
r1169 | ajapted | 2013-07-15 18:40:20 +1000 (Mon, 15 Jul 2013) | 2 lines

Checks / things: added checks for missing player starts.

------------------------------------------------------------------------
r1168 | ajapted | 2013-07-15 16:59:05 +1000 (Mon, 15 Jul 2013) | 3 lines

Checks: when highlighting error objects, use GoToSelection() to ensure
the user will see them.

------------------------------------------------------------------------
r1167 | ajapted | 2013-07-15 16:56:07 +1000 (Mon, 15 Jul 2013) | 3 lines

Checks: began work on THING checking.  So far: can count the number of
unknown things, and highlight them in the error mode.

------------------------------------------------------------------------
r1166 | ajapted | 2013-07-15 16:31:55 +1000 (Mon, 15 Jul 2013) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1165 | ajapted | 2013-07-15 16:22:19 +1000 (Mon, 15 Jul 2013) | 2 lines

Prefs: layout tweaks.

------------------------------------------------------------------------
r1164 | ajapted | 2013-07-15 16:19:22 +1000 (Mon, 15 Jul 2013) | 2 lines

Preferences: implemented a 'Default editing mode' setting.

------------------------------------------------------------------------
r1163 | ajapted | 2013-07-15 14:22:11 +1000 (Mon, 15 Jul 2013) | 2 lines

UI_Sector and UI_LineDef: use Tags_ApplyNewValue() in tag_callback.

------------------------------------------------------------------------
r1162 | ajapted | 2013-07-15 14:19:28 +1000 (Mon, 15 Jul 2013) | 6 lines

Implemented new 'ApplyTag' key-binding command.  With the "fresh" param
it sets the tags on selected objects to a fresh tag (max + 1), and with
the "last" parameter it sets the tag to the last one (maximum).

Current bindings are META-F and META-L.

------------------------------------------------------------------------
r1161 | ajapted | 2013-07-15 14:08:52 +1000 (Mon, 15 Jul 2013) | 2 lines

Main loop: disable error_mode whenever selection becomes empty.

------------------------------------------------------------------------
r1160 | ajapted | 2013-07-15 13:35:16 +1000 (Mon, 15 Jul 2013) | 3 lines

Checks / tags: added feature to assign a fresh tag value to the current
selected linedefs or sectors.

------------------------------------------------------------------------
r1159 | ajapted | 2013-07-15 13:18:26 +1000 (Mon, 15 Jul 2013) | 3 lines

Checks: implemented "TAG" dialog, which for now just shows the lowest and
highest used tag numbers.

------------------------------------------------------------------------
r1158 | ajapted | 2013-07-15 13:02:04 +1000 (Mon, 15 Jul 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r1157 | ajapted | 2013-07-15 12:27:08 +1000 (Mon, 15 Jul 2013) | 3 lines

Save message : added "NO NODES" so the user knows that nodes have not
been built.

------------------------------------------------------------------------
r1156 | ajapted | 2013-07-15 11:58:03 +1000 (Mon, 15 Jul 2013) | 2 lines

Minor rename: edit.obj_type --> edit.mode

------------------------------------------------------------------------
r1155 | ajapted | 2013-07-14 22:57:21 +1000 (Sun, 14 Jul 2013) | 3 lines

Check / vertices: implemented ability to merge overlapping vertices, or
highlight them in the error selection [that part is not complete].

------------------------------------------------------------------------
r1154 | ajapted | 2013-07-14 22:19:41 +1000 (Sun, 14 Jul 2013) | 4 lines

Checks / vertices:
1. fixed some bugs in Reset() method [one was quite nasty]
2. implemented Vertex_RemoveUnused() function

------------------------------------------------------------------------
r1153 | ajapted | 2013-07-14 22:05:20 +1000 (Sun, 14 Jul 2013) | 3 lines

Checks / vertices: implemented Vertex_FindOverlaps() and FindUnused(),
fixed AddLine() to copy the label, and tweaked a few things.

------------------------------------------------------------------------
r1152 | ajapted | 2013-07-14 21:29:21 +1000 (Sun, 14 Jul 2013) | 3 lines

Checks / vertices: worked on performing proper tests, and improved the
size and layout of the dialog window.

------------------------------------------------------------------------
r1151 | ajapted | 2013-07-14 20:32:35 +1000 (Sun, 14 Jul 2013) | 11 lines

Check:
1. use an enumeration for the result of CHECK_xxx functions

2. support CHECK_xxx functions returning a value to indicate skipping
   the rest of the checks in CHECK_All()

3. ability to Reset() the UI dialog, so checks can be re-performed on
   an existing dialog window

4. fixed not passing 'this' to the callback functions.

------------------------------------------------------------------------
r1150 | ajapted | 2013-07-14 19:57:20 +1000 (Sun, 14 Jul 2013) | 6 lines

Checks:
1. the CHECK_xxx functions now return a "severity" value (an int)
2. keep track of 'worst_severity' in the UI_CheckXXX classes
3. fixed logic in CHECK_All() -- it needs to keep going when one of the
   CHECK_xxx() functions returns a non-zero severity

------------------------------------------------------------------------
r1149 | ajapted | 2013-07-14 19:40:29 +1000 (Sun, 14 Jul 2013) | 3 lines

Checks: implemented an 'AddLine' method for the Vertex dialog, which
supports upto three buttons for actions to take.

------------------------------------------------------------------------
r1148 | ajapted | 2013-07-14 19:03:33 +1000 (Sun, 14 Jul 2013) | 2 lines

Check Menu: fixed shortcuts.

------------------------------------------------------------------------
r1147 | ajapted | 2013-07-14 18:57:38 +1000 (Sun, 14 Jul 2013) | 4 lines

Checks:
1. added a bare-bones UI_CheckVertices dialog class
2. removed some obsolete code

------------------------------------------------------------------------
r1146 | ajapted | 2013-07-14 18:55:03 +1000 (Sun, 14 Jul 2013) | 3 lines

Preferences: fixed potential problem with UI_EditKey and the close button
of the window manager.

------------------------------------------------------------------------
r1145 | ajapted | 2013-07-14 18:20:19 +1000 (Sun, 14 Jul 2013) | 6 lines

Began work on map-checking functions.  Firstly have a 'Check' menu with
various choices (like "Vertices", "Sectors", etc).  These are routed
through a new 'CheckMap' binding command whose first parameter is the
area to check.  Some special keywords are "current" for the current
enditing mode, and "all" to check all the major stuff.

------------------------------------------------------------------------
r1144 | ajapted | 2013-07-14 18:10:59 +1000 (Sun, 14 Jul 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r1143 | ajapted | 2013-07-14 15:20:28 +1000 (Sun, 14 Jul 2013) | 3 lines

VM: disabled the testing stuff in main.cc -- all the scripting stuff is
very much on the back-burner now....

------------------------------------------------------------------------
r1142 | ajapted | 2013-07-14 15:15:08 +1000 (Sun, 14 Jul 2013) | 4 lines

The ';' key waits for the next key, and makes it META (as if it had
been pressed with the META modifier key).  This could be handy on
computers with limited keyboards -- especially laptops.

------------------------------------------------------------------------
r1141 | ajapted | 2013-07-14 14:42:43 +1000 (Sun, 14 Jul 2013) | 2 lines

Prefs: tweak.

------------------------------------------------------------------------
r1140 | ajapted | 2013-07-14 14:36:15 +1000 (Sun, 14 Jul 2013) | 4 lines

Config file:
1. handle empty strings, write and parse as '' (two single quotes)
2. moved the glbsp_xxx entries down

------------------------------------------------------------------------
r1139 | ajapted | 2013-07-14 14:23:06 +1000 (Sun, 14 Jul 2013) | 2 lines

Game defs: removed obsolete 'default_port' command.

------------------------------------------------------------------------
r1138 | ajapted | 2013-07-14 14:11:07 +1000 (Sun, 14 Jul 2013) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1137 | ajapted | 2013-07-14 14:07:40 +1000 (Sun, 14 Jul 2013) | 6 lines

Preferences: added 'Default Port' setting to the Editing tab.

This affects general startup too, as previously the default port was a
game definition setting.  Hence added DeterminePort() whose main job
is to ensure the default_port value is valid [and reset it if not].

------------------------------------------------------------------------
r1136 | ajapted | 2013-07-14 14:03:11 +1000 (Sun, 14 Jul 2013) | 2 lines

Game (UGH) parser: disabled the 'default_port' command.

------------------------------------------------------------------------
r1135 | ajapted | 2013-07-14 13:24:22 +1000 (Sun, 14 Jul 2013) | 3 lines

the X11 UI_Window::Maximize() implementation now does a short delay, to
allow the X message to get to the X server and back.

------------------------------------------------------------------------
r1134 | ajapted | 2013-07-14 13:11:41 +1000 (Sun, 14 Jul 2013) | 2 lines

Utils: added TimeDelay() function.

------------------------------------------------------------------------
r1133 | ajapted | 2013-07-14 13:03:49 +1000 (Sun, 14 Jul 2013) | 3 lines

Made patch image loading fail more gracefully: a bad offset now prints a
warning to the log file instead of inducing a fatal error.

------------------------------------------------------------------------
r1132 | ajapted | 2013-07-11 19:08:38 +1000 (Thu, 11 Jul 2013) | 2 lines

Version bump.

------------------------------------------------------------------------
r1131 | ajapted | 2013-07-11 18:58:15 +1000 (Thu, 11 Jul 2013) | 3 lines

Key bindings: shifted 'N' and 'P' keys now have the FlipMap function,
and moved the GivenFile functions to META-N and META-P.

------------------------------------------------------------------------
r1130 | ajapted | 2013-07-11 18:55:30 +1000 (Thu, 11 Jul 2013) | 4 lines

Implemented new binding command 'FlipMap' which loads another map in the
current wad.  The first param must be "next", "prev", "first" or "last".
Very useful for browsing through a pwad with multiple maps.

------------------------------------------------------------------------
r1129 | ajapted | 2013-07-11 18:43:32 +1000 (Thu, 11 Jul 2013) | 3 lines

Wad code: added FindLevel_Raw() method which returns a level index
instead of a _lump_ index.

------------------------------------------------------------------------
r1128 | ajapted | 2013-07-05 21:34:57 +1000 (Fri, 05 Jul 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r1127 | ajapted | 2013-07-05 20:28:47 +1000 (Fri, 05 Jul 2013) | 2 lines

Removed obsolete GRID_XXX color defines.

------------------------------------------------------------------------
r1126 | ajapted | 2013-07-05 20:13:27 +1000 (Fri, 05 Jul 2013) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1125 | ajapted | 2013-07-05 20:11:11 +1000 (Fri, 05 Jul 2013) | 2 lines

Grid: implemented preference colors for the Normal grid.

------------------------------------------------------------------------
r1124 | ajapted | 2013-07-05 19:03:30 +1000 (Fri, 05 Jul 2013) | 4 lines

Grid:
1. added preference settings for the Dotty grid colors
2. slightly better rendering of the Dotty grid

------------------------------------------------------------------------
r1123 | ajapted | 2013-07-05 16:33:33 +1000 (Fri, 05 Jul 2013) | 5 lines

Grid:
1. implemented option to limit grid toggle to a single kind
2. added option to hide grid in FREE mode, show it in SNAP mode
3. nomenclature: old grid is called "dotty", new grid "normal"

------------------------------------------------------------------------
r1122 | ajapted | 2013-07-05 16:28:36 +1000 (Fri, 05 Jul 2013) | 2 lines

UI_Canvas: split DrawGrid() into two separate methods.

------------------------------------------------------------------------
r1121 | ajapted | 2013-07-04 20:19:47 +1000 (Thu, 04 Jul 2013) | 2 lines

Preferences: a few more tweaks

------------------------------------------------------------------------
r1120 | ajapted | 2013-07-04 18:24:04 +1000 (Thu, 04 Jul 2013) | 4 lines

Preferences:
1. added a 'Mouse' tab, nothing in it yet
2. renamed 'glBSP' tab --> 'Other', ready for some other stuff

------------------------------------------------------------------------
r1119 | ajapted | 2013-07-04 16:54:11 +1000 (Thu, 04 Jul 2013) | 4 lines

Fixed recent bug with mousewheel zooming -- Editor_RawWheel() was not
returning 1 and hence FLTK was sending the mousewheel event to the
scrollbars which used it to scroll.

------------------------------------------------------------------------
r1118 | ajapted | 2013-07-04 16:28:06 +1000 (Thu, 04 Jul 2013) | 2 lines

CHANGELOG rejigged.

------------------------------------------------------------------------
r1117 | ajapted | 2013-07-04 14:45:46 +1000 (Thu, 04 Jul 2013) | 2 lines

Implemented new preference setting : maximize the window on start.

------------------------------------------------------------------------
r1116 | ajapted | 2013-07-04 14:36:43 +1000 (Thu, 04 Jul 2013) | 5 lines

UI_Window: added Maximize() method, using OS-native code since FLTK does
not provide the required functionality.  Only implemented for Win32 and
Linux/X11 : the OSX implemented is commented out since it requires some
Objective-C logic.

------------------------------------------------------------------------
r1115 | ajapted | 2013-07-01 15:49:13 +1000 (Mon, 01 Jul 2013) | 2 lines

event handling tweaks.

------------------------------------------------------------------------
r1114 | ajapted | 2013-07-01 13:11:44 +1000 (Mon, 01 Jul 2013) | 6 lines

Moved the mouse button and movement logic out of UI_Canvas class and
into Editor_RawButton() and Editor_RawMouse() functions.

This fixes the hack in UI_Render3D class [calling the handle method of
UI_Canvas, even though the widget was hidden].

------------------------------------------------------------------------
r1113 | ajapted | 2013-07-01 12:55:11 +1000 (Mon, 01 Jul 2013) | 2 lines

Minor refactoring of event handling in UI_Canvas class.

------------------------------------------------------------------------
r1112 | ajapted | 2013-07-01 11:59:37 +1000 (Mon, 01 Jul 2013) | 2 lines

Keys: added 'FL_Wheel' : pseudo key value for the mouse wheel.

------------------------------------------------------------------------
r1111 | ajapted | 2013-07-01 11:41:14 +1000 (Mon, 01 Jul 2013) | 2 lines

Moved handling of mouse wheel events to Editor_RawWheel() function.

------------------------------------------------------------------------
r1110 | ajapted | 2013-07-01 11:23:40 +1000 (Mon, 01 Jul 2013) | 2 lines

Key bindings: support 4 parameters to a binding (limit was 2 before).

------------------------------------------------------------------------
r1109 | ajapted | 2013-07-01 11:12:24 +1000 (Mon, 01 Jul 2013) | 2 lines

handle the FL_KEYUP event in Editor_RawKey().

------------------------------------------------------------------------
r1108 | ajapted | 2013-06-30 17:16:34 +1000 (Sun, 30 Jun 2013) | 3 lines

Moved the raw keyboard event handling out of UI_Canvas class, instead
have a global function: Editor_RawKey().

------------------------------------------------------------------------
r1107 | ajapted | 2013-06-30 16:47:14 +1000 (Sun, 30 Jun 2013) | 2 lines

VM: tweak

------------------------------------------------------------------------
r1106 | ajapted | 2013-06-30 16:39:56 +1000 (Sun, 30 Jun 2013) | 2 lines

Renamed directory: up_scripts --> ups

------------------------------------------------------------------------
r1105 | ajapted | 2013-06-30 16:38:40 +1000 (Sun, 30 Jun 2013) | 3 lines

Updated installation makefiles (etc) to create 'ups' folder and to
install the 'core_defs.lua' file.

------------------------------------------------------------------------
r1104 | ajapted | 2013-06-30 16:31:54 +1000 (Sun, 30 Jun 2013) | 3 lines

VM: added file 'core_defs.up' -- will define all the builtins and any
other needed stuff.

------------------------------------------------------------------------
r1103 | ajapted | 2013-06-30 15:44:13 +1000 (Sun, 30 Jun 2013) | 2 lines

Added top-level directory: 'up_scripts'

------------------------------------------------------------------------
r1102 | ajapted | 2013-06-30 13:41:42 +1000 (Sun, 30 Jun 2013) | 2 lines

TODO update (did some things, added some things).

------------------------------------------------------------------------
r1101 | ajapted | 2013-06-30 13:40:29 +1000 (Sun, 30 Jun 2013) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1100 | ajapted | 2013-06-30 13:39:18 +1000 (Sun, 30 Jun 2013) | 5 lines

Config: added 'render_missing_bright' and 'render_unknown_bright' vars,
and handle them in the rendering code.

Note: not present in the Preferences dialog (yet).

------------------------------------------------------------------------
r1099 | ajapted | 2013-06-30 13:29:42 +1000 (Sun, 30 Jun 2013) | 2 lines

3D preview: implemented missing textures (an '!' on an orange background).

------------------------------------------------------------------------
r1098 | ajapted | 2013-06-30 13:23:41 +1000 (Sun, 30 Jun 2013) | 3 lines

3D preview: show missing textures as fullbright, so they stand out in
dark rooms.

------------------------------------------------------------------------
r1097 | ajapted | 2013-06-30 12:58:35 +1000 (Sun, 30 Jun 2013) | 2 lines

3d preview: tweaked untextured color choice.

------------------------------------------------------------------------
r1096 | ajapted | 2013-06-30 12:57:38 +1000 (Sun, 30 Jun 2013) | 2 lines

Game defs / DOOM (etc) : updated color definitions.

------------------------------------------------------------------------
r1095 | ajapted | 2013-06-30 12:56:46 +1000 (Sun, 30 Jun 2013) | 3 lines

Auto-load recent map: don't do it when -iwad or -warp has been used on
the command line.

------------------------------------------------------------------------
r1094 | ajapted | 2013-06-30 12:31:47 +1000 (Sun, 30 Jun 2013) | 2 lines

Game defs / HERETIC: updated with color definitions ('wall', 'missing' etc).

------------------------------------------------------------------------
r1093 | ajapted | 2013-06-30 12:25:19 +1000 (Sun, 30 Jun 2013) | 3 lines

3D preview: use the game-specified wall and floor colors, rather than
the hard-coded values which were DOOM specific.

------------------------------------------------------------------------
r1092 | ajapted | 2013-06-30 12:23:01 +1000 (Sun, 30 Jun 2013) | 2 lines

Game def parser: support 'wall' and 'floor' color definitions.

------------------------------------------------------------------------
r1091 | ajapted | 2013-06-30 12:00:25 +1000 (Sun, 30 Jun 2013) | 4 lines

Game def parser: implemented new 'color' command which takes a keyword
and one or two numbers (palette indices).  The following keywords are
currently supported: 'sky', 'missing', 'unknown_tex', 'unknown_flat'.

------------------------------------------------------------------------
r1090 | ajapted | 2013-06-29 22:19:26 +1000 (Sat, 29 Jun 2013) | 3 lines

1. moved g_sky_color and g_sky_flat into a new 'game_info' structure
2. moved is_sky() function from levels.cc --> m_game.cc

------------------------------------------------------------------------
r1089 | ajapted | 2013-06-29 22:10:44 +1000 (Sat, 29 Jun 2013) | 3 lines

GAME DEFS: added common/doom_colors.ugh : color defs for games using
the DOOM palette.

------------------------------------------------------------------------
r1088 | ajapted | 2013-06-29 22:03:59 +1000 (Sat, 29 Jun 2013) | 3 lines

3D Preview: implemented displaying a dummy texture for unknown flats or
textures (a different one for flats vs textures).

------------------------------------------------------------------------
r1087 | ajapted | 2013-06-29 21:28:57 +1000 (Sat, 29 Jun 2013) | 3 lines

Img code: added functions to create dummy textures for the 3D renderer,
one for missing (HOM) textures and one for unknown textures.

------------------------------------------------------------------------
r1086 | ajapted | 2013-06-29 21:14:25 +1000 (Sat, 29 Jun 2013) | 2 lines

Img class: turned 'scale_img()' into a method, plus various tidying.

------------------------------------------------------------------------
r1085 | ajapted | 2013-06-29 20:38:51 +1000 (Sat, 29 Jun 2013) | 2 lines

Fixed thing images in the browser to have a black background.

------------------------------------------------------------------------
r1084 | ajapted | 2013-06-29 20:28:42 +1000 (Sat, 29 Jun 2013) | 3 lines

LineDef panel: don't show an upper texture as missing if sky ceilings
exist on both sides.

------------------------------------------------------------------------
r1083 | ajapted | 2013-06-29 20:18:27 +1000 (Sat, 29 Jun 2013) | 3 lines

LineDef panel: implemented showing missing textures, for uppers and lowers
this involves checking for a floor / ceiling difference.

------------------------------------------------------------------------
r1082 | ajapted | 2013-06-29 20:02:08 +1000 (Sat, 29 Jun 2013) | 4 lines

UI_Pic : implemented ability to show "unknown" and "missing" textures,
the former as a large '?' on a cyan background, the latter as '!' on an
orange background.

------------------------------------------------------------------------
r1081 | ajapted | 2013-06-28 21:18:31 +1000 (Fri, 28 Jun 2013) | 3 lines

UI: in sidedef panels, show low-contrast "Lower", "Mid" and "Upper" for
unset textures.  Similarly for pics in sector and thing panels.

------------------------------------------------------------------------
r1080 | ajapted | 2013-06-28 19:51:32 +1000 (Fri, 28 Jun 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r1079 | ajapted | 2013-06-28 19:35:54 +1000 (Fri, 28 Jun 2013) | 4 lines

Scroll-bars: improved logic for adjusting the scroll bars after the
canvas position has moved, having grid.MoveTo() and grid.Scroll()
methods instead of directly modifying grid.orig_x/_y

------------------------------------------------------------------------
r1078 | ajapted | 2013-06-28 12:11:35 +1000 (Fri, 28 Jun 2013) | 4 lines

Scroll-bars: implemented callbacks, i.e. dragging the knobs actually
scrolls the map (and in turn, moves the knobs).  Hence the scroll-bar
feature is mostly complete now.

------------------------------------------------------------------------
r1077 | ajapted | 2013-06-28 11:46:10 +1000 (Fri, 28 Jun 2013) | 3 lines

Scroll-bars: implemented logic to compute the position/size of each bar
based on the map bounds and the current view position and zoom level.

------------------------------------------------------------------------
r1076 | ajapted | 2013-06-27 22:46:27 +1000 (Thu, 27 Jun 2013) | 1 line

CHANGELOG update
------------------------------------------------------------------------
r1075 | ajapted | 2013-06-27 22:45:07 +1000 (Thu, 27 Jun 2013) | 2 lines

Minor coding rename: MapBound_[lh][xy] --> Map_bound_[xy][12]

------------------------------------------------------------------------
r1074 | ajapted | 2013-06-27 22:20:00 +1000 (Thu, 27 Jun 2013) | 3 lines

Scroll-bars: implemented ability to hide/show the bars based on the
user's preference setting.

------------------------------------------------------------------------
r1073 | ajapted | 2013-06-27 21:46:18 +1000 (Thu, 27 Jun 2013) | 3 lines

Config: added 'map_scroll_bars' variable which will be used to enable or
disable the scroll-bars for the map view.

------------------------------------------------------------------------
r1072 | ajapted | 2013-06-27 17:14:55 +1000 (Thu, 27 Jun 2013) | 2 lines

Updated AUTHORS.txt to match website (Jason's contribution).

------------------------------------------------------------------------
r1071 | ajapted | 2013-06-27 17:10:53 +1000 (Thu, 27 Jun 2013) | 3 lines

Reworked the About dialog to show the new logo, and have a fallback just
in case we cannot open the file, plus tweaked the text.

------------------------------------------------------------------------
r1070 | ajapted | 2013-06-27 17:09:11 +1000 (Thu, 27 Jun 2013) | 2 lines

Added 'about_logo.png' -- cropped and scaled from Jason's original.

------------------------------------------------------------------------
r1069 | ajapted | 2013-06-27 16:27:58 +1000 (Thu, 27 Jun 2013) | 2 lines

Checked in Jason R Johnston's logo image, and removed the old cruddy one.

------------------------------------------------------------------------
r1068 | ajapted | 2013-06-26 22:17:47 +1000 (Wed, 26 Jun 2013) | 3 lines

More work on having a proper widget for the 3D preview.  It seems to
be working now, albeit with some ugly hacks.

------------------------------------------------------------------------
r1067 | ajapted | 2013-06-26 19:35:35 +1000 (Wed, 26 Jun 2013) | 4 lines

Created a UI_Render3D class for the 3D preview.  The idea is to show
this widget (and hide the canvas/sbars) when 3D mode is active, and do
the reverse when not active -- but keyboard handling is now fubar....

------------------------------------------------------------------------
r1066 | ajapted | 2013-06-26 16:51:36 +1000 (Wed, 26 Jun 2013) | 4 lines

Moved the 'render3d' field out of UI_Canvas and into Editor_State_t,
since the canvas is no longer responsible for drawing the 3D preview
(the new UI_CanvasScroll wrapper is).

------------------------------------------------------------------------
r1065 | ajapted | 2013-06-26 16:27:21 +1000 (Wed, 26 Jun 2013) | 3 lines

Initial work on scrollbars for the map view.  This commit merely creates
a container for the canvas + scrollbars : UI_CanvasScroll.

------------------------------------------------------------------------
r1064 | ajapted | 2013-06-26 14:17:56 +1000 (Wed, 26 Jun 2013) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1063 | ajapted | 2013-06-26 14:02:15 +1000 (Wed, 26 Jun 2013) | 6 lines

Improved handling of bad references when loading a level:

If a linedef has a bad vertex, it is removed.  Bad sector or sidedef
references are replaced with something valid.  Details are written to
the log file, and a dialog is shown to the user when these happen.

------------------------------------------------------------------------
r1062 | ajapted | 2013-06-25 22:45:26 +1000 (Tue, 25 Jun 2013) | 2 lines

Created a definition file for the XDoom source port (by Udo Monk).

------------------------------------------------------------------------
r1061 | ajapted | 2013-06-24 23:47:02 +1000 (Mon, 24 Jun 2013) | 3 lines

Fixed splitting void islands : it was adding a sector in _both_ sides,
but we only want one in a single side (the smallest).

------------------------------------------------------------------------
r1060 | ajapted | 2013-06-24 23:39:39 +1000 (Mon, 24 Jun 2013) | 4 lines

Lineloop class:
1. added a Dump() method to aid debugging
2. fixed silly bug in TotalLength() method

------------------------------------------------------------------------
r1059 | ajapted | 2013-06-24 22:26:42 +1000 (Mon, 24 Jun 2013) | 3 lines

Basis: fixed assertion checks in BA_ChangeTH() and BA_ChangeLD() to
handle the new HEXEN fields.

------------------------------------------------------------------------
r1058 | ajapted | 2013-06-24 15:59:01 +1000 (Mon, 24 Jun 2013) | 4 lines

Minor code tidying:
1. removed unused levelname2xxx() functions
2. removed unused yg_level_name variable

------------------------------------------------------------------------
r1057 | ajapted | 2013-06-23 14:24:06 +1000 (Sun, 23 Jun 2013) | 2 lines

CHANGELOG and TODO update.

------------------------------------------------------------------------
r1056 | ajapted | 2013-06-23 14:21:03 +1000 (Sun, 23 Jun 2013) | 2 lines

Support Eureka config (.ugh) files as resource files.

------------------------------------------------------------------------
r1055 | ajapted | 2013-06-23 13:38:00 +1000 (Sun, 23 Jun 2013) | 4 lines

Minor code refactoring:
1. use "M_" prefix on some m_game.cc functions
2. have a LoadResourceFile() function in main.cc

------------------------------------------------------------------------
r1054 | ajapted | 2013-06-23 12:07:40 +1000 (Sun, 23 Jun 2013) | 2 lines

Added 'Level_format' global variable.

------------------------------------------------------------------------
r1053 | ajapted | 2013-06-23 12:02:43 +1000 (Sun, 23 Jun 2013) | 4 lines

Hexen:
1. have proper F_ARG1..5 keywords for the argument fields
2. updated the CopyProperties command to copy the Hexen fields

------------------------------------------------------------------------
r1052 | ajapted | 2013-06-23 11:49:44 +1000 (Sun, 23 Jun 2013) | 3 lines

Basis: expanded Thing and LineDef structures with HEXEN fields.
(Note: not actually used anywhere yet).

------------------------------------------------------------------------
r1051 | ajapted | 2013-06-23 11:33:22 +1000 (Sun, 23 Jun 2013) | 2 lines

README: added the new 'N' / 'P' keys : next file / prev file.

------------------------------------------------------------------------
r1050 | ajapted | 2013-06-23 11:29:02 +1000 (Sun, 23 Jun 2013) | 3 lines

Implemented SEC_Light() binding command for adjusting sector lighting.
It takes a delta parameter as per the SEC_Floor() command.

------------------------------------------------------------------------
r1049 | ajapted | 2013-06-22 23:40:29 +1000 (Sat, 22 Jun 2013) | 2 lines

CHANGELOG and TODO update.

------------------------------------------------------------------------
r1048 | ajapted | 2013-06-22 23:37:51 +1000 (Sat, 22 Jun 2013) | 4 lines

Browser:
1. remember the "off mode" properly in user state
2. persist the browser width in the user state

------------------------------------------------------------------------
r1047 | ajapted | 2013-06-22 23:00:44 +1000 (Sat, 22 Jun 2013) | 4 lines

VM: partial work on ability to read/write the members of a set.
There are two new instructions, OP_SET_READ and OP_SET_WRITE, which
are generated but their execution is not implemented yet.

------------------------------------------------------------------------
r1046 | ajapted | 2013-06-22 16:31:55 +1000 (Sat, 22 Jun 2013) | 4 lines

VM:
1. fixed bug when pushing vector literals onto the stack
2. support assigning 'nil' values to any kind of variable

------------------------------------------------------------------------
r1045 | ajapted | 2013-06-22 16:04:02 +1000 (Sat, 22 Jun 2013) | 2 lines

VM: updated VIM syntax file for new types.

------------------------------------------------------------------------
r1044 | ajapted | 2013-06-22 15:58:44 +1000 (Sat, 22 Jun 2013) | 7 lines

VM: added the following new types: linedef, sidedef, sector, thing and
vertex, plus also set[xxx] where xxx is linedef (etc).  So far there
is nothing which can be done with any of these types.

Also support a "nil" keyword with its own ev_nil type.  It cannot be
used anywhere yet.

------------------------------------------------------------------------
r1043 | ajapted | 2013-06-22 15:22:46 +1000 (Sat, 22 Jun 2013) | 2 lines

VM: removed type_size[] array.

------------------------------------------------------------------------
r1042 | ajapted | 2013-06-22 13:40:38 +1000 (Sat, 22 Jun 2013) | 2 lines

Fixed remembering 3D mode (actually the lack of it) for a map.

------------------------------------------------------------------------
r1041 | ajapted | 2013-06-22 13:33:33 +1000 (Sat, 22 Jun 2013) | 2 lines

Removed some unused code : word_splitting()

------------------------------------------------------------------------
r1040 | ajapted | 2013-06-22 13:19:26 +1000 (Sat, 22 Jun 2013) | 2 lines

Moved code around: put Beep() function into m_keys.cc

------------------------------------------------------------------------
r1039 | ajapted | 2013-06-22 13:10:10 +1000 (Sat, 22 Jun 2013) | 3 lines

Fixed the key binding dialog: unable to remove a parameter (when the
binding already had a parameter).

------------------------------------------------------------------------
r1038 | ajapted | 2013-06-22 11:30:14 +1000 (Sat, 22 Jun 2013) | 8 lines

1. when registering binding commands, determine the context automatically
   from the name e.g. "LIN_xxxx" will be KCTX_Line.

2. support finding a binding command as a script function (in the VM),
   and execute that script function when the command is executed.  This
   is bare-bones at the moment, numerous things (error handling, passing
   parameters) are NOT done yet.

------------------------------------------------------------------------
r1037 | ajapted | 2013-06-21 22:36:31 +1000 (Fri, 21 Jun 2013) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r1036 | ajapted | 2013-06-18 19:36:30 +1000 (Tue, 18 Jun 2013) | 2 lines

VM: removed more field-related stuff.

------------------------------------------------------------------------
r1035 | ajapted | 2013-06-18 19:18:08 +1000 (Tue, 18 Jun 2013) | 4 lines

VM / compiler: tidied up code to parse global definitions.

Also removed code to parse "fields" (won't be needed here).

------------------------------------------------------------------------
r1034 | ajapted | 2013-06-18 18:51:19 +1000 (Tue, 18 Jun 2013) | 2 lines

VM: ensure local string variables get a valid default (the empty string).

------------------------------------------------------------------------
r1033 | ajapted | 2013-06-18 18:48:46 +1000 (Tue, 18 Jun 2013) | 2 lines

VM: ensure global variables of type 'string' get a valid default.

------------------------------------------------------------------------
r1032 | ajapted | 2013-06-18 18:37:01 +1000 (Tue, 18 Jun 2013) | 3 lines

VM: replaced 's_file' field of dfunction_t with a normal string ptr,
replaced usages of 's_name' field, and removed mpr.strings[] table.

------------------------------------------------------------------------
r1031 | ajapted | 2013-06-18 18:26:13 +1000 (Tue, 18 Jun 2013) | 4 lines

VM: changed OP_LITERAL instruction to store the kval_t value in the
following instruction slot.  This is a bit cleaner than the previous
way of storing the value inside the dstatement_t.

------------------------------------------------------------------------
r1030 | ajapted | 2013-06-18 15:55:03 +1000 (Tue, 18 Jun 2013) | 3 lines

VM: changed representation of _string in kval_t, esp. on the stack, to
use a pointer to object_ref_c instead of an offset into mpr.strings[].

------------------------------------------------------------------------
r1029 | ajapted | 2013-06-18 15:25:04 +1000 (Tue, 18 Jun 2013) | 2 lines

Makefiles: added vm_object.o to the build.

------------------------------------------------------------------------
r1028 | ajapted | 2013-06-18 15:24:24 +1000 (Tue, 18 Jun 2013) | 2 lines

VM / lex: removed lex_eval_t union -- for simpler code.

------------------------------------------------------------------------
r1027 | ajapted | 2013-06-18 15:21:23 +1000 (Tue, 18 Jun 2013) | 2 lines

VM / objects: added MakePermanent() method, will be needed for string literals.

------------------------------------------------------------------------
r1026 | ajapted | 2013-06-18 14:07:39 +1000 (Tue, 18 Jun 2013) | 3 lines

VM / objects: fleshed out remaining methods, e.g. NewSelection(), and
fixed various compiling issues.

------------------------------------------------------------------------
r1025 | ajapted | 2013-06-18 13:47:32 +1000 (Tue, 18 Jun 2013) | 2 lines

VM / objects: description of the memory model.

------------------------------------------------------------------------
r1024 | ajapted | 2013-06-18 13:33:42 +1000 (Tue, 18 Jun 2013) | 4 lines

VM: began work on some simple object management code for the VM.
The objects so far are (1) strings and (2) selections for each map
kind of map element.  Other objects may be added later.

------------------------------------------------------------------------
r1023 | ajapted | 2013-06-17 13:57:40 +1000 (Mon, 17 Jun 2013) | 2 lines

VM: added grammar description, using EBNF notation.

------------------------------------------------------------------------
r1022 | ajapted | 2013-06-17 13:49:17 +1000 (Mon, 17 Jun 2013) | 2 lines

VM: made all semicolons optional.

------------------------------------------------------------------------
r1021 | ajapted | 2013-06-16 23:46:45 +1000 (Sun, 16 Jun 2013) | 4 lines

VM:
1. removed redundant check on "float" in ParseType().
2. removed "void" as a usable type.

------------------------------------------------------------------------
r1020 | ajapted | 2013-06-16 20:41:07 +1000 (Sun, 16 Jun 2013) | 4 lines

VM:
1. renamed 'extern' keyword --> 'builtin'
2. renamed 'va' function --> 'format'

------------------------------------------------------------------------
r1019 | ajapted | 2013-06-16 20:27:58 +1000 (Sun, 16 Jun 2013) | 3 lines

Detect HEXEN format maps, and prevent trying to load them -- instead we
show an error message, which is better than crashing out.

------------------------------------------------------------------------
r1018 | ajapted | 2013-06-16 19:15:31 +1000 (Sun, 16 Jun 2013) | 3 lines

VM: fixed precedence of the '?:' ternary operator, which needs to be
higher than assignment.

------------------------------------------------------------------------
r1017 | ajapted | 2013-06-16 19:01:24 +1000 (Sun, 16 Jun 2013) | 2 lines

Minor rename: 'ResourceWads' --> 'Resource_list'

------------------------------------------------------------------------
r1016 | ajapted | 2013-06-16 18:35:32 +1000 (Sun, 16 Jun 2013) | 2 lines

Preferences: added button for 'auto_load_recent' config var.

------------------------------------------------------------------------
r1015 | ajapted | 2013-06-16 18:22:33 +1000 (Sun, 16 Jun 2013) | 3 lines

Preferences: added a new 'Grid' tab, and moved the griddy stuff there,
though I expect to add more griddy stuff too (soon).

------------------------------------------------------------------------
r1014 | ajapted | 2013-06-16 16:26:32 +1000 (Sun, 16 Jun 2013) | 3 lines

Implemented opening the most recently saved pwad on startup -- but only
when Eureka is started without any pwad filenames.

------------------------------------------------------------------------
r1013 | ajapted | 2013-06-16 16:01:14 +1000 (Sun, 16 Jun 2013) | 2 lines

Moved code around in m_files.cc

------------------------------------------------------------------------
r1012 | ajapted | 2013-06-16 15:51:11 +1000 (Sun, 16 Jun 2013) | 2 lines

Support DOOMWADPATH for finding IWAD files.

------------------------------------------------------------------------
r1011 | ajapted | 2013-06-16 15:01:57 +1000 (Sun, 16 Jun 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r1010 | ajapted | 2013-06-16 14:59:16 +1000 (Sun, 16 Jun 2013) | 2 lines

Use Wad_file::Validate() instead of FileExists() where appropriate.

------------------------------------------------------------------------
r1009 | ajapted | 2013-06-16 14:43:26 +1000 (Sun, 16 Jun 2013) | 2 lines

Validate all given pwad files (make sure they exist, etc).

------------------------------------------------------------------------
r1008 | ajapted | 2013-06-16 14:40:42 +1000 (Sun, 16 Jun 2013) | 3 lines

Wad code: added Validate() static method to check if a wad exists and is
indeed a WAD file.

------------------------------------------------------------------------
r1007 | ajapted | 2013-06-16 13:58:10 +1000 (Sun, 16 Jun 2013) | 3 lines

Fixed CMD_OpenFileMap() to confirm with user when the current map has
been modified.

------------------------------------------------------------------------
r1006 | ajapted | 2013-06-16 13:54:32 +1000 (Sun, 16 Jun 2013) | 3 lines

Allow any number of given pwad files (in Pwad_list), only limit them when
creating the 'Given Files' menu.

------------------------------------------------------------------------
r1005 | ajapted | 2013-06-16 13:45:44 +1000 (Sun, 16 Jun 2013) | 9 lines

Implemented "GivenFile" command which supports loading the next / previous
file in the given files list, with default bindings on 'N' and 'P' keys.
This makes it easy to step through a large group of wads.

The command also supports "first" and "last" keywords, but these are not
bound to any keys by default.

Also moved binding of PRUNE command from 'P' --> 'p' key.

------------------------------------------------------------------------
r1004 | ajapted | 2013-06-16 11:49:30 +1000 (Sun, 16 Jun 2013) | 2 lines

Tidied up the latest 'Recent Files' handling code.

------------------------------------------------------------------------
r1003 | ajapted | 2013-06-16 11:35:29 +1000 (Sun, 16 Jun 2013) | 2 lines

Dead code removal : CMD_OpenRecentMap() and UI_RecentFiles dialog.

------------------------------------------------------------------------
r1002 | ajapted | 2013-06-14 21:53:11 +1000 (Fri, 14 Jun 2013) | 3 lines

More work on new 'File/Recent Files' sub-menu, which is working now,
though the code needs some tidying up...

------------------------------------------------------------------------
r1001 | ajapted | 2013-06-14 21:02:25 +1000 (Fri, 14 Jun 2013) | 7 lines

Partial work changing 'File/Recent Files' into a sub-menu which is
populated at startup with the recent file list.  This commit has the
code to populate the sub-menu.

Also: disable (gray out) the 'Given Files' sub-menu when there is
not multiple specified filenames.

------------------------------------------------------------------------
r1000 | ajapted | 2013-06-14 19:38:26 +1000 (Fri, 14 Jun 2013) | 3 lines

Made -file option accept multiple filenames, adding them to Pwad_list
as per loose filenames.

------------------------------------------------------------------------
r999 | ajapted | 2013-06-14 18:45:37 +1000 (Fri, 14 Jun 2013) | 3 lines

Makefile.xming : removed -lshfolder from linkage [was only there to
test a binary under Windows 95].

------------------------------------------------------------------------
r998 | ajapted | 2013-06-14 16:52:30 +1000 (Fri, 14 Jun 2013) | 3 lines

Implemented a 'Given Files' sub-menu of the File menu, which is populated
when Eureka is run with a list of wad files.

------------------------------------------------------------------------
r997 | ajapted | 2013-06-14 15:23:58 +1000 (Fri, 14 Jun 2013) | 2 lines

VM: checked in a Vim syntax file for the scripting language.

------------------------------------------------------------------------
r996 | ajapted | 2013-06-14 15:23:01 +1000 (Fri, 14 Jun 2013) | 2 lines

Makefiles: added VM code files to the build.

------------------------------------------------------------------------
r995 | ajapted | 2013-06-10 23:52:39 +1000 (Mon, 10 Jun 2013) | 2 lines

VM: added missing code to resolve builtin functions.

------------------------------------------------------------------------
r994 | ajapted | 2013-06-10 23:40:45 +1000 (Mon, 10 Jun 2013) | 3 lines

VM: worked on implementing the API functions, e.g. VM_CompileFile() and
VM_Call(), and wrote some test code for loading / running a script.

------------------------------------------------------------------------
r993 | ajapted | 2013-06-10 22:00:38 +1000 (Mon, 10 Jun 2013) | 3 lines

VM: more work integrating this code, it compiles now, but is still far
away from being able to actually do anything....

------------------------------------------------------------------------
r992 | ajapted | 2013-06-10 19:21:52 +1000 (Mon, 10 Jun 2013) | 2 lines

VM: various work to integrate the VM code into its new environment...

------------------------------------------------------------------------
r991 | ajapted | 2013-06-10 18:10:20 +1000 (Mon, 10 Jun 2013) | 4 lines

Began work on a scripting system.  This commit contains code for a VM
which I have been developing for a while now.  It was originally based
on the QCC compiler and execution engine from Quake, by Id Software.

------------------------------------------------------------------------
r990 | ajapted | 2013-06-10 16:56:48 +1000 (Mon, 10 Jun 2013) | 5 lines

Removed the unfinished support for Radius Triggers (RTS), which is a
feature of the EDGE source port.  It would've required a lot more code
to finish the RTS mode, not only parsing and re-creating the RSCRIPT
lump, but also the ability to edit the scripts.

------------------------------------------------------------------------
r989 | ajapted | 2013-06-10 16:39:36 +1000 (Mon, 10 Jun 2013) | 1 line

Version bump

------------------------------------------------------------------------
r988 | ajapted | 2013-06-10 15:27:13 +1000 (Mon, 10 Jun 2013) | 3 lines

Changed PASTE behavior : place objects around their true centre, instead
of around the thing or vertex which is closest to the centre.

------------------------------------------------------------------------
r987 | ajapted | 2013-06-10 15:18:36 +1000 (Mon, 10 Jun 2013) | 4 lines

Added 'reselect_second_vertex' variable to control when adding a linedef
onto an existing vertex (or line) if the second vertex will be selected.

------------------------------------------------------------------------
r986 | ajapted | 2013-06-10 15:13:28 +1000 (Mon, 10 Jun 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r985 | printz | 2013-05-29 07:23:50 +1000 (Wed, 29 May 2013) | 1 line

osx: FLTK is now statically linked

------------------------------------------------------------------------
r984 | ajapted | 2013-05-07 22:30:00 +1000 (Tue, 07 May 2013) | 3 lines

Tweaked BA_ChecksumLevel() to produce checksums the same as before,
so that persistent data for previously edited maps gets found.

------------------------------------------------------------------------
r983 | ajapted | 2013-05-06 13:19:33 +1000 (Mon, 06 May 2013) | 3 lines

Fixed crash bug in BA_ChecksumLevel(), used when loading and saving a
map, occurring when a linedef was missing the right sidedef.

------------------------------------------------------------------------
r981 | ajapted | 2013-05-01 15:11:48 +1000 (Wed, 01 May 2013) | 2 lines

Preferences: leave_offsets_alone now defaults to TRUE.

------------------------------------------------------------------------
r968 | ajapted | 2013-04-28 21:07:50 +1000 (Sun, 28 Apr 2013) | 2 lines

TODO: minor update.

------------------------------------------------------------------------
r967 | ajapted | 2013-04-28 21:07:23 +1000 (Sun, 28 Apr 2013) | 2 lines

More grid-color tweakage.

------------------------------------------------------------------------
r943 | ajapted | 2013-03-16 21:57:03 +1100 (Sat, 16 Mar 2013) | 2 lines

Grid: color tweakage.

------------------------------------------------------------------------
r942 | ajapted | 2013-03-16 11:19:44 +1100 (Sat, 16 Mar 2013) | 2 lines

Grid: improved the simple grid to show flat boundaries.

------------------------------------------------------------------------
r941 | ajapted | 2013-03-16 09:25:33 +1100 (Sat, 16 Mar 2013) | 3 lines

Fixed the selection after a sector merge (the "gone away" sectors were
still in the selection, preventing a subsequent merge).

------------------------------------------------------------------------
r940 | ajapted | 2013-03-16 09:17:33 +1100 (Sat, 16 Mar 2013) | 2 lines

Version bump after 0.95 release.

------------------------------------------------------------------------
r939 | ajapted | 2013-03-16 09:16:08 +1100 (Sat, 16 Mar 2013) | 2 lines

CHANGES.txt : added fresh one (post v0.95 release).

------------------------------------------------------------------------
r938 | ajapted | 2013-03-03 11:20:04 +1100 (Sun, 03 Mar 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r937 | ajapted | 2013-03-01 11:09:50 +1100 (Fri, 01 Mar 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r936 | ajapted | 2013-02-25 10:20:28 +1100 (Mon, 25 Feb 2013) | 2 lines

Moved CHANGES.txt --> changelog/095.txt  [after the 0.95 release]

------------------------------------------------------------------------
r935 | ajapted | 2013-02-25 10:17:39 +1100 (Mon, 25 Feb 2013) | 2 lines

bindings.cfg : added SHIFT + cursor keys for scrolling in bigger steps.

------------------------------------------------------------------------
r934 | ajapted | 2013-02-24 15:44:50 +1100 (Sun, 24 Feb 2013) | 2 lines

TODO : small addition.

------------------------------------------------------------------------
r933 | ajapted | 2013-02-24 15:36:11 +1100 (Sun, 24 Feb 2013) | 2 lines

Updated doc/History.txt with SVN changes since last release.

------------------------------------------------------------------------
r932 | ajapted | 2013-02-24 15:30:07 +1100 (Sun, 24 Feb 2013) | 2 lines

Pack-source script: copy the 'osx' directory too.

------------------------------------------------------------------------
r931 | ajapted | 2013-02-24 15:25:07 +1100 (Sun, 24 Feb 2013) | 2 lines

MacOSX: fixed bug in Determine_HomeDir() using 'path' twice.

------------------------------------------------------------------------
r930 | printz | 2013-02-23 21:26:12 +1100 (Sat, 23 Feb 2013) | 1 line

Bumped PLIST version

------------------------------------------------------------------------
r929 | printz | 2013-02-23 21:13:44 +1100 (Sat, 23 Feb 2013) | 1 line

Removed deleted file references in the xcode project

------------------------------------------------------------------------
r928 | ajapted | 2013-02-23 20:11:21 +1100 (Sat, 23 Feb 2013) | 2 lines

Win32 / installer: fixed NSIS script to require "admin" rights.

------------------------------------------------------------------------
r927 | ajapted | 2013-02-23 17:49:36 +1100 (Sat, 23 Feb 2013) | 2 lines

Pack-source script: updated for 'changelogs' folder.

------------------------------------------------------------------------
r926 | ajapted | 2013-02-23 17:48:30 +1100 (Sat, 23 Feb 2013) | 2 lines

Moved changelog documents from docs/ --> changelogs/

------------------------------------------------------------------------
r925 | ajapted | 2013-02-23 17:46:31 +1100 (Sat, 23 Feb 2013) | 2 lines

New top-level folder 'changelogs' -- no prizes for guessing what will go in there!

------------------------------------------------------------------------
r924 | ajapted | 2013-02-23 17:39:06 +1100 (Sat, 23 Feb 2013) | 2 lines

README.txt : updated keys for 'd' and 'm' in Things mode.

------------------------------------------------------------------------
r923 | ajapted | 2013-02-23 16:38:12 +1100 (Sat, 23 Feb 2013) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r922 | ajapted | 2013-02-23 16:35:31 +1100 (Sat, 23 Feb 2013) | 3 lines

Config: added 'swap_sidedefs' preference setting which swaps the upper
and lower sidedefs in the Linedef panel (i.e. to Upper/Middle/Lower).

------------------------------------------------------------------------
r921 | ajapted | 2013-02-23 15:45:40 +1100 (Sat, 23 Feb 2013) | 2 lines

Debian: updated control info (mainly version #) for 0.95 release.

------------------------------------------------------------------------
r920 | ajapted | 2013-02-23 15:41:53 +1100 (Sat, 23 Feb 2013) | 2 lines

TODO.txt : another addition.

------------------------------------------------------------------------
r919 | ajapted | 2013-02-23 15:33:01 +1100 (Sat, 23 Feb 2013) | 2 lines

README.txt : minor changes to FEATURES section.

------------------------------------------------------------------------
r918 | ajapted | 2013-02-23 15:31:39 +1100 (Sat, 23 Feb 2013) | 2 lines

TODO updated.

------------------------------------------------------------------------
r917 | ajapted | 2013-02-22 19:27:32 +1100 (Fri, 22 Feb 2013) | 4 lines

1. made UI_ChooseMap window shorter
2. fixed weird order of "ExMx" level names in UI_ChooseMap
3. fixed unclickable bottom row of buttons in UI_OpenMap dialog

------------------------------------------------------------------------
r916 | ajapted | 2013-02-22 19:14:58 +1100 (Fri, 22 Feb 2013) | 2 lines

Fixed the mode widget on info bar not having any color at startup.

------------------------------------------------------------------------
r915 | ajapted | 2013-02-22 19:08:35 +1100 (Fri, 22 Feb 2013) | 2 lines

Tweaked background colors of some widgets for non-plastic themes.

------------------------------------------------------------------------
r914 | ajapted | 2013-02-22 17:26:14 +1100 (Fri, 22 Feb 2013) | 5 lines

Made map buttons in ChooseMap and OpenMap dialogs be ordered differently,
increasing across-ways instead of down in columns.  That's because I want
the map buttons to be placed in predictable places (e.g. the layout does
not change depending on number of maps present) -- for better usability.

------------------------------------------------------------------------
r913 | ajapted | 2013-02-22 16:58:48 +1100 (Fri, 22 Feb 2013) | 3 lines

Partial work to make ChooseMap and OpenMap dialogs consistent w.r.t the
map selection buttons -- same color, font size and positioning.

------------------------------------------------------------------------
r912 | ajapted | 2013-02-22 16:57:42 +1100 (Fri, 22 Feb 2013) | 2 lines

Queiten another warning.

------------------------------------------------------------------------
r911 | ajapted | 2013-02-22 16:29:09 +1100 (Fri, 22 Feb 2013) | 2 lines

Code: quieten a compiler warning.

------------------------------------------------------------------------
r910 | ajapted | 2013-02-22 15:49:54 +1100 (Fri, 22 Feb 2013) | 2 lines

Dead code removal : SliceLineDef() and MakeRectangularNook().

------------------------------------------------------------------------
r909 | ajapted | 2013-02-22 15:44:42 +1100 (Fri, 22 Feb 2013) | 2 lines

Makefiles: added -fno-strict-aliasing to compiler flags.

------------------------------------------------------------------------
r908 | ajapted | 2013-02-22 15:35:02 +1100 (Fri, 22 Feb 2013) | 2 lines

Win32 / installer: create a shortcut in the Start Menu.

------------------------------------------------------------------------
r907 | ajapted | 2013-02-22 13:57:16 +1100 (Fri, 22 Feb 2013) | 3 lines

View menu: removed the 'Toggle Fullscreen' command, the FLTK fullscreen()
method fails miserably on every platform tested, especially Windows XP.

------------------------------------------------------------------------
r906 | ajapted | 2013-02-21 23:30:12 +1100 (Thu, 21 Feb 2013) | 3 lines

Wad code: fixed some bugs when adding level lumps -- especially need to
fix all the groups when the 'insert_point' is valid.

------------------------------------------------------------------------
r905 | ajapted | 2013-02-21 19:21:36 +1100 (Thu, 21 Feb 2013) | 4 lines

Prefs: reset colors when user chooses the "Bright" setting.

Unfortunately I don't know how to reset the "Default" colors....

------------------------------------------------------------------------
r904 | ajapted | 2013-02-21 19:13:10 +1100 (Thu, 21 Feb 2013) | 2 lines

Prefs: when 'Custom Colors' is enabled, update the colors immediately.

------------------------------------------------------------------------
r903 | ajapted | 2013-02-21 19:06:02 +1100 (Thu, 21 Feb 2013) | 2 lines

Prefs: fixed (I think) the color buttons not updating to a new color.

------------------------------------------------------------------------
r902 | ajapted | 2013-02-21 17:38:56 +1100 (Thu, 21 Feb 2013) | 4 lines

Win32: when reading Install_Dir from the registry, ensure that the
string is NUL-terminated (the MSDN docs mention that the string may
have been stored without a trailing NUL).

------------------------------------------------------------------------
r901 | ajapted | 2013-02-21 17:28:21 +1100 (Thu, 21 Feb 2013) | 3 lines

Win32: attempt to fix the problem reading the $Install_Dir registry value,
which was returning (I think) UCS2 format unicode instead of ASCII.

------------------------------------------------------------------------
r900 | ajapted | 2013-02-21 17:16:54 +1100 (Thu, 21 Feb 2013) | 2 lines

Renamed global var: 'local_dir' --> 'cache_dir'

------------------------------------------------------------------------
r899 | ajapted | 2013-02-21 17:14:53 +1100 (Thu, 21 Feb 2013) | 2 lines

MacOSX: set the 'cache_dir' to $HOME/Library/Caches/eureka-editor

------------------------------------------------------------------------
r898 | ajapted | 2013-02-21 16:49:06 +1100 (Thu, 21 Feb 2013) | 2 lines

Removed dummy mods/foo.bar file.

------------------------------------------------------------------------
r897 | ajapted | 2013-02-21 16:48:42 +1100 (Thu, 21 Feb 2013) | 2 lines

Win32 / nsis_build: I forgot to copy the executable, duh.

------------------------------------------------------------------------
r896 | ajapted | 2013-02-21 16:46:05 +1100 (Thu, 21 Feb 2013) | 4 lines

Win32: reworked NSIS script and Makefile.xming so that we first create a
replicate of the final directory structure.  Main reason is because we
need to convert the text files to MSDOS/Windows format.

------------------------------------------------------------------------
r895 | ajapted | 2013-02-21 15:45:18 +1100 (Thu, 21 Feb 2013) | 2 lines

svn:ignore update

------------------------------------------------------------------------
r894 | ajapted | 2013-02-21 15:44:24 +1100 (Thu, 21 Feb 2013) | 2 lines

Added empty mods/foo.bar file, to keep NSIS happy.

------------------------------------------------------------------------
r893 | ajapted | 2013-02-21 15:41:23 +1100 (Thu, 21 Feb 2013) | 2 lines

Version bump to 0.95 -- for upcoming release.

------------------------------------------------------------------------
r892 | ajapted | 2013-02-21 15:40:43 +1100 (Thu, 21 Feb 2013) | 2 lines

Win32: some fixes for building the NSIS installer.

------------------------------------------------------------------------
r891 | ajapted | 2013-02-21 15:22:38 +1100 (Thu, 21 Feb 2013) | 2 lines

Win32: created obj_win32/glbsp folder.

------------------------------------------------------------------------
r890 | ajapted | 2013-02-21 15:21:47 +1100 (Thu, 21 Feb 2013) | 2 lines

Win32: hmmmm, PathAppend() doesn't seem available -- use strcat() instead.

------------------------------------------------------------------------
r889 | ajapted | 2013-02-21 15:16:00 +1100 (Thu, 21 Feb 2013) | 2 lines

Fixed typo in last commit.

------------------------------------------------------------------------
r888 | ajapted | 2013-02-21 15:14:52 +1100 (Thu, 21 Feb 2013) | 4 lines

Win32 port:
1. fixed not appending our own folder name to %APPDATA%
2. fixed a few compiling issues (e.g. MOD_SHIFT conflicts with windows headers)

------------------------------------------------------------------------
r887 | ajapted | 2013-02-21 14:56:52 +1100 (Thu, 21 Feb 2013) | 2 lines

Win32: more work on Makefile.xming, should be usable now (barring mistakes).

------------------------------------------------------------------------
r886 | ajapted | 2013-02-21 14:55:38 +1100 (Thu, 21 Feb 2013) | 2 lines

Win32: added folder for build objects: obj_win32/

------------------------------------------------------------------------
r885 | ajapted | 2013-02-21 14:54:00 +1100 (Thu, 21 Feb 2013) | 2 lines

Win32: created a resource file : eureka.rc

------------------------------------------------------------------------
r884 | ajapted | 2013-02-21 14:38:14 +1100 (Thu, 21 Feb 2013) | 2 lines

Win32: tweaked name of install directory and registry key.

------------------------------------------------------------------------
r883 | ajapted | 2013-02-21 14:37:08 +1100 (Thu, 21 Feb 2013) | 3 lines

Win32: started work on Makefile.xming -- uses a cross-compiler to make
the Windows executable.

------------------------------------------------------------------------
r882 | ajapted | 2013-02-21 13:11:31 +1100 (Thu, 21 Feb 2013) | 5 lines

Win32: implemented Determine_HomeDir() logic, which uses SHGetFolderPath
to determine the %APPDATA% folder.

Also have fallback for 'local_dir' value (needed for Linux).

------------------------------------------------------------------------
r881 | ajapted | 2013-02-21 12:57:05 +1100 (Thu, 21 Feb 2013) | 2 lines

Use $local_dir (not $home_dir) as prefix for 'cache' and 'backups' folders.

------------------------------------------------------------------------
r880 | ajapted | 2013-02-21 12:51:57 +1100 (Thu, 21 Feb 2013) | 10 lines

1. implemented WIN32 logic to read the "Install_Dir" registry key which
   is created by the NSIS installer

2. made FatalError() on WIN32 use the system MessageBox() function
   when FLTK has not been initialized yet.

3. added 'local_dir' global var, this will be the place for the cache
   and backup folders -- i.e. non-roamable stuff.  On Linux it will
   just be the same as $home_dir.

------------------------------------------------------------------------
r879 | ajapted | 2013-02-21 11:49:16 +1100 (Thu, 21 Feb 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r878 | ajapted | 2013-02-21 11:48:36 +1100 (Thu, 21 Feb 2013) | 2 lines

Updated README.txt and CHANGES.txt -- preparing for a release.

------------------------------------------------------------------------
r877 | ajapted | 2013-02-21 11:35:15 +1100 (Thu, 21 Feb 2013) | 2 lines

Checked in basic NSIS script to create a Win32 installer : eureka.nsi

------------------------------------------------------------------------
r876 | ajapted | 2013-02-19 22:23:44 +1100 (Tue, 19 Feb 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r875 | ajapted | 2013-02-19 22:16:21 +1100 (Tue, 19 Feb 2013) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r874 | ajapted | 2013-02-19 22:09:43 +1100 (Tue, 19 Feb 2013) | 2 lines

Default Props panel: now hidden by default.

------------------------------------------------------------------------
r873 | ajapted | 2013-02-19 22:05:07 +1100 (Tue, 19 Feb 2013) | 2 lines

log viewer tweak

------------------------------------------------------------------------
r872 | ajapted | 2013-02-19 22:03:30 +1100 (Tue, 19 Feb 2013) | 3 lines

Log Viewer: reduced MAX_LINES to 600, and made it jump to the bottom
when adding a new line.

------------------------------------------------------------------------
r871 | ajapted | 2013-02-19 21:56:26 +1100 (Tue, 19 Feb 2013) | 2 lines

Print the current time (in the log file) at startup.

------------------------------------------------------------------------
r870 | ajapted | 2013-02-19 21:49:59 +1100 (Tue, 19 Feb 2013) | 2 lines

main.h : ensure we #include <windows.h> for WIN32 builds

------------------------------------------------------------------------
r869 | ajapted | 2013-02-19 21:38:58 +1100 (Tue, 19 Feb 2013) | 8 lines

Log file rejigging:
1. we always create a log file, default is $home_dir/logs.txt
2. all messages are sent to stdout (unless --quiet is used)
3. remember messages in memory until LogViewer window is opened
4. after opening the log file, write saved messages to it
5. after created LogViewer window, grab the saved messages
6. tweaks to debug handling

------------------------------------------------------------------------
r868 | ajapted | 2013-02-19 18:12:36 +1100 (Tue, 19 Feb 2013) | 3 lines

Config: added "-m" as short option for "--merge", and "-v" as short
option for "--version".

------------------------------------------------------------------------
r867 | ajapted | 2013-02-19 17:56:53 +1100 (Tue, 19 Feb 2013) | 3 lines

Removed 'r_misc' code files -- since we longer use anything in there
(such as the SetWindowSize() function and ScrMaxX/Y variables).

------------------------------------------------------------------------
r866 | ajapted | 2013-02-19 16:53:54 +1100 (Tue, 19 Feb 2013) | 3 lines

Log Viewer: added 'View/Logs' menu to show the log viewer, and don't show
it automatically on start-up.

------------------------------------------------------------------------
r865 | ajapted | 2013-02-19 16:42:58 +1100 (Tue, 19 Feb 2013) | 4 lines

Began working on a Log Viewing window.  So far the window is opened at
startup, and it contains only an Fl_Browser to show the text.  Also the
LogPrintf() function has been hacked up to send the lines into it.

------------------------------------------------------------------------
r864 | ajapted | 2013-02-19 16:17:15 +1100 (Tue, 19 Feb 2013) | 2 lines

Moved Int_TmpStr() function to lib_util.cc/h

------------------------------------------------------------------------
r863 | ajapted | 2013-02-19 15:26:19 +1100 (Tue, 19 Feb 2013) | 2 lines

minor menu tweak.

------------------------------------------------------------------------
r862 | ajapted | 2013-02-19 15:23:03 +1100 (Tue, 19 Feb 2013) | 2 lines

bindings.cfg : swapped grid keys, 'g' now goes smaller, 'G' goes bigger.

------------------------------------------------------------------------
r861 | ajapted | 2013-02-19 15:20:29 +1100 (Tue, 19 Feb 2013) | 3 lines

1. made sure every Beep() call has a message
2. removed the no-message Beep() function

------------------------------------------------------------------------
r860 | ajapted | 2013-02-19 14:43:44 +1100 (Tue, 19 Feb 2013) | 2 lines

File menu: use CTRL-M for Manage Wads, CTRL-P for Preferences.

------------------------------------------------------------------------
r859 | ajapted | 2013-02-19 14:38:28 +1100 (Tue, 19 Feb 2013) | 5 lines

Prefs / key binds:
1. save the bindings when APPLY button is clicked
2. fixed bug in M_SaveBindings() which skipped the general context
3. changed ordering which contexts are displayed in the key browser

------------------------------------------------------------------------
r858 | ajapted | 2013-02-19 14:27:21 +1100 (Tue, 19 Feb 2013) | 2 lines

bindings.cfg : moved PruneUnused from 'p' --> 'P' key

------------------------------------------------------------------------
r857 | ajapted | 2013-02-19 13:32:11 +1100 (Tue, 19 Feb 2013) | 7 lines

Prefs / key binds:
1. changed "Add" button into a "Copy" button, which copies the line
   and automatically goes into grab-key mode
2. moved "Bind" button to the top
3. made UI_EditKey dialog give focus to the function name input
4. fixed "Edit" button so arrow keys control the browser afterwards

------------------------------------------------------------------------
r856 | ajapted | 2013-02-19 13:03:53 +1100 (Tue, 19 Feb 2013) | 3 lines

Prefs / key binds: implemented good method to detect conflicting key
bindings -- will be shown in RED no matter how the list is sorted.

------------------------------------------------------------------------
r855 | ajapted | 2013-02-19 12:46:01 +1100 (Tue, 19 Feb 2013) | 3 lines

Prefs / key binds: got the "Edit" and "Add" buttons working, using the
values chosen in the UI_EditKey dialog.

------------------------------------------------------------------------
r854 | ajapted | 2013-02-18 23:10:56 +1100 (Mon, 18 Feb 2013) | 2 lines

TODO updated.

------------------------------------------------------------------------
r853 | ajapted | 2013-02-18 23:02:38 +1100 (Mon, 18 Feb 2013) | 2 lines

UI_EditKey dialog: when validating func_name, check the brackets.

------------------------------------------------------------------------
r852 | ajapted | 2013-02-18 22:58:20 +1100 (Mon, 18 Feb 2013) | 2 lines

UI_EditKey dialog: implemented ValidateFunc().

------------------------------------------------------------------------
r851 | ajapted | 2013-02-18 22:52:48 +1100 (Mon, 18 Feb 2013) | 4 lines

1. fixed M_ParseKeyString() not handling hex values like "0x1234"
2. added some synonyms to the M_ParseKeyString() key table, such as
   "RETURN" for "ENTER", "INSERT" for "INS", etc...

------------------------------------------------------------------------
r850 | ajapted | 2013-02-18 22:41:53 +1100 (Mon, 18 Feb 2013) | 3 lines

UI_EditKey dialog: implemented validation of the key name (drawn red
when the name fails to parse).

------------------------------------------------------------------------
r849 | ajapted | 2013-02-18 22:23:51 +1100 (Mon, 18 Feb 2013) | 7 lines

Prefs / key binds: show duplicated key bindings (same mode and key) using
red text in the key browser.

This only works when the two keys are together in the list (i.e. the list
has been recently sorted, and the sort criterion was either KEY or MODE).
It could be done better -- but this will suffice for now.

------------------------------------------------------------------------
r848 | ajapted | 2013-02-18 22:02:05 +1100 (Mon, 18 Feb 2013) | 2 lines

Version bump to 0.92

------------------------------------------------------------------------
r847 | ajapted | 2013-02-18 16:39:04 +1100 (Mon, 18 Feb 2013) | 4 lines

Prefs / key binds:
1. setup the initial values for UI_EditKey dialog
2. renamed 'dialog' --> 'prefs' in all UI_Preferences callbacks

------------------------------------------------------------------------
r846 | ajapted | 2013-02-18 16:27:00 +1100 (Mon, 18 Feb 2013) | 3 lines

Prefs / key binds: bit more work on UI_EditKey dialog, fixed a few
layout issues, added Run() method, implemented Close and OK buttons.

------------------------------------------------------------------------
r845 | ajapted | 2013-02-18 10:31:29 +1100 (Mon, 18 Feb 2013) | 2 lines

CHANGELOG and TODO update.

------------------------------------------------------------------------
r844 | ajapted | 2013-02-18 10:27:00 +1100 (Mon, 18 Feb 2013) | 3 lines

When saving a map, prefer existing location in the wad directory
(i.e. if map already exists, don't place lumps at end of wad).

------------------------------------------------------------------------
r843 | ajapted | 2013-02-17 22:36:36 +1100 (Sun, 17 Feb 2013) | 2 lines

Quantize: status message when cannot move some things / vertices.

------------------------------------------------------------------------
r842 | ajapted | 2013-02-17 22:31:18 +1100 (Sun, 17 Feb 2013) | 2 lines

CHANGELOG updated.

------------------------------------------------------------------------
r841 | ajapted | 2013-02-17 22:26:51 +1100 (Sun, 17 Feb 2013) | 2 lines

Ensure displayed level name is always uppercase.

------------------------------------------------------------------------
r840 | ajapted | 2013-02-17 21:38:58 +1100 (Sun, 17 Feb 2013) | 6 lines

Prefs / key binds: initial work on a UI_EditKey dialog, which allows
the user to change the key, context and function of a binding.

So far only the layout is done (code is output of Fluid with some
tidying up).

------------------------------------------------------------------------
r839 | ajapted | 2013-02-17 21:04:03 +1100 (Sun, 17 Feb 2013) | 3 lines

Prefs / key binds: added two utility functions: M_GetBindingInfo() and
M_IsBindingFuncValid().

------------------------------------------------------------------------
r838 | ajapted | 2013-02-17 20:41:07 +1100 (Sun, 17 Feb 2013) | 6 lines

Prefs / key binds:
1. the ESCAPE key now cancels a bind-in-progress
2. added some shortcut keys: ENTER for "Bind", INSERT and DELETE
3. ensure key browser gets focus after these operations so user can
   use up/down arrow keys to move through the list.

------------------------------------------------------------------------
r837 | ajapted | 2013-02-17 19:58:52 +1100 (Sun, 17 Feb 2013) | 2 lines

TODO.txt : update

------------------------------------------------------------------------
r836 | ajapted | 2013-02-17 19:55:59 +1100 (Sun, 17 Feb 2013) | 7 lines

Prefs / key binds:
1. no longer use the 'data' field of browser lines for bind indices,
   since browser lines map one-to-one with the local bindings

2. renamed 'awaiting_slot' --> 'awaiting_line' and made zero be the
   "off" value

------------------------------------------------------------------------
r835 | ajapted | 2013-02-17 19:45:34 +1100 (Sun, 17 Feb 2013) | 2 lines

Prefs / key binds: implemented the "Delete" button.

------------------------------------------------------------------------
r834 | ajapted | 2013-02-17 19:34:03 +1100 (Sun, 17 Feb 2013) | 3 lines

Prefs / key binds: wrote M_AddLocalBinding() and M_DeleteLocalBinding()
functions.

------------------------------------------------------------------------
r833 | ajapted | 2013-02-17 19:06:22 +1100 (Sun, 17 Feb 2013) | 2 lines

Prefs / key bindings: message tweaks.

------------------------------------------------------------------------
r832 | ajapted | 2013-02-17 17:08:10 +1100 (Sun, 17 Feb 2013) | 8 lines

Prefs / key bindings:
1. made key browser higher (i.e. revert previous change, since I don't
   think a message area will be needded)

2. when waiting for a key press, give the whole preferences window
   the keyboard focus (via Fl::focus).  This fixes certain keys not
   being bindable (like SPACE).

------------------------------------------------------------------------
r831 | ajapted | 2013-02-17 16:44:00 +1100 (Sun, 17 Feb 2013) | 2 lines

Prefs / key bindings: updated code for m_keys rejiggage.

------------------------------------------------------------------------
r830 | ajapted | 2013-02-17 15:47:23 +1100 (Sun, 17 Feb 2013) | 2 lines

Prefs / key bindings: better error messages for M_ChangeBindingFunc().

------------------------------------------------------------------------
r829 | ajapted | 2013-02-17 15:42:41 +1100 (Sun, 17 Feb 2013) | 5 lines

Prefs / key bindings: reworked code in m_keys, it now follows a model
where the key bindings are copied and the dialog will query and change
that copy.  The M_ApplyBindings() function will transfer them back.
Also the M_ChangeBindingFunc() now returns an error string.

------------------------------------------------------------------------
r828 | ajapted | 2013-02-17 15:19:21 +1100 (Sun, 17 Feb 2013) | 4 lines

Prefs / key bindings:
1. renamed CONTEXT column --> MODE
2. began work on "Add", "Delete" and "Load Defaults" buttons

------------------------------------------------------------------------
r827 | ajapted | 2013-02-17 14:54:56 +1100 (Sun, 17 Feb 2013) | 4 lines

Prefs / key bindings:
1. changed order of columns to: KEY | CONTEXT | FUNCTION
2. added some space underneath the list for a message

------------------------------------------------------------------------
r826 | ajapted | 2013-02-17 14:05:03 +1100 (Sun, 17 Feb 2013) | 3 lines

Preferences dialog: changed "OK" button to "Apply", and added a "Discard"
button which does not keep the changes made.

------------------------------------------------------------------------
r825 | ajapted | 2013-02-16 15:15:28 +1100 (Sat, 16 Feb 2013) | 3 lines

Prefs / key bindings: implemented the "Edit" button, with code to parse
the entered string, find the command and store it + parameters.

------------------------------------------------------------------------
r824 | ajapted | 2013-02-16 13:37:41 +1100 (Sat, 16 Feb 2013) | 2 lines

Prefs / key bindings: can actually change a key binding now.

------------------------------------------------------------------------
r823 | ajapted | 2013-02-16 12:44:02 +1100 (Sat, 16 Feb 2013) | 4 lines

Prefs / key bindings: worked on ability to show <???> in the current
binding (with background changed to yellow) and the next key-press will
become the new binding -- or clear the binding on a mouse press.

------------------------------------------------------------------------
r822 | ajapted | 2013-02-16 11:46:55 +1100 (Sat, 16 Feb 2013) | 3 lines

Prefs / key bindings: improved display of keys with modifiers, show the
modifier in its own column (so that the bare keys are aligned).

------------------------------------------------------------------------
r821 | ajapted | 2013-02-16 11:36:23 +1100 (Sat, 16 Feb 2013) | 4 lines

Prefs / key bindings: implemented the different sorting modes -- clicking
on the header buttons will select that as the sort column, or toggle
reverse mode if it already was.

------------------------------------------------------------------------
r820 | ajapted | 2013-02-16 11:16:32 +1100 (Sat, 16 Feb 2013) | 2 lines

Key handling: implemented a key compare function: M_KeyCmp()

------------------------------------------------------------------------
r819 | ajapted | 2013-02-16 11:05:17 +1100 (Sat, 16 Feb 2013) | 5 lines

Prefs / key bindings: added M_SortBindingsToVec() which sorts the key
bindings (actually an int vector) for display by the key browser.
Different sorting methods are not implemented yet.


------------------------------------------------------------------------
r818 | ajapted | 2013-02-16 10:31:02 +1100 (Sat, 16 Feb 2013) | 2 lines

Key handling: renamed 'global' context --> 'general'.

------------------------------------------------------------------------
r817 | ajapted | 2013-02-15 23:08:46 +1100 (Fri, 15 Feb 2013) | 2 lines

Prefs / key bindings: renamed 'GROUP' column --> 'CONTEXT'

------------------------------------------------------------------------
r816 | ajapted | 2013-02-15 22:36:57 +1100 (Fri, 15 Feb 2013) | 2 lines

Fluid work : prefs2.fl

------------------------------------------------------------------------
r815 | ajapted | 2013-02-15 22:36:05 +1100 (Fri, 15 Feb 2013) | 2 lines

Prefs / key bindings: partial work on "Bind" and "Edit" buttons.

------------------------------------------------------------------------
r814 | ajapted | 2013-02-15 22:01:55 +1100 (Fri, 15 Feb 2013) | 3 lines

Prefs / Key bindings: added buttons above the browser which show what
each column is (and later will allow sorting by that column).

------------------------------------------------------------------------
r813 | ajapted | 2013-02-15 21:20:01 +1100 (Fri, 15 Feb 2013) | 3 lines

Preference dialog: worked on a new "Keys" tab, which will allow the user
to edit the key bindings.  So far it can only display them.

------------------------------------------------------------------------
r812 | ajapted | 2013-02-15 21:18:28 +1100 (Fri, 15 Feb 2013) | 3 lines

Key handling: added M_StringForBinding() function to format a binding
into a string suitable for an Fl_Browser widget.

------------------------------------------------------------------------
r811 | ajapted | 2013-02-15 19:39:32 +1100 (Fri, 15 Feb 2013) | 3 lines

bindings.cfg : minor change: use '/' to separate flags letters for
LIN_SelectPath and SEC_SelectGroup.

------------------------------------------------------------------------
r810 | ajapted | 2013-02-15 17:16:16 +1100 (Fri, 15 Feb 2013) | 2 lines

UI_Scroll: implemented the Scroll() method.

------------------------------------------------------------------------
r809 | ajapted | 2013-02-14 22:43:42 +1100 (Thu, 14 Feb 2013) | 2 lines

Browser: started work to fix keyboard scrolling....

------------------------------------------------------------------------
r808 | ajapted | 2013-02-14 22:21:47 +1100 (Thu, 14 Feb 2013) | 4 lines

Fixed editor mode getting out-of-sync with the GUI (side panel etc) after
loading a map with no user state.


------------------------------------------------------------------------
r807 | ajapted | 2013-02-14 22:17:14 +1100 (Thu, 14 Feb 2013) | 3 lines

Fixed SNAP button which could become out-of-sync with the editor
after loading a map with no user state.

------------------------------------------------------------------------
r806 | ajapted | 2013-02-14 22:11:40 +1100 (Thu, 14 Feb 2013) | 4 lines

File / OpenMap: don't parse the EUREKA lump (and reload the IWAD and
resource files) when the current pwad has not changed.


------------------------------------------------------------------------
r805 | ajapted | 2013-02-14 21:56:13 +1100 (Thu, 14 Feb 2013) | 4 lines

Added bindings for CTRL + SPACE and CTRL + INSERT to re-enable the
feature of forcing a new sector to be created (rather than correcting
an existing one).  Thanks to d1337r for the bug report.

------------------------------------------------------------------------
r804 | ajapted | 2013-02-05 14:32:43 +1100 (Tue, 05 Feb 2013) | 6 lines

Added an 'error_mode' field to Editor_State_t -- when enabled, the
current selection is drawn in bright red instead of blue.  This will
be used later by the error detection dialog.

UI_Canvas: factored some common code --> DrawThing() method.

------------------------------------------------------------------------
r803 | ajapted | 2013-02-05 13:58:06 +1100 (Tue, 05 Feb 2013) | 2 lines

CHANGELOG update and rearrangement.

------------------------------------------------------------------------
r802 | ajapted | 2013-02-05 13:55:23 +1100 (Tue, 05 Feb 2013) | 2 lines

Scale Objects dialog: finished ability to scale Z of sectors.

------------------------------------------------------------------------
r801 | ajapted | 2013-02-05 11:53:13 +1100 (Tue, 05 Feb 2013) | 3 lines

Scale Objects dialog: partial work to introduce a 'Z' component (hidden
for modes where it doesn't make sense -- which is most of them).

------------------------------------------------------------------------
r800 | ajapted | 2013-02-05 11:51:26 +1100 (Tue, 05 Feb 2013) | 2 lines

Checks.txt : minor addition

------------------------------------------------------------------------
r799 | ajapted | 2013-02-04 14:10:36 +1100 (Mon, 04 Feb 2013) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r798 | ajapted | 2013-02-04 14:08:00 +1100 (Mon, 04 Feb 2013) | 3 lines

Implemented new 'PruneUnused' command -- remove unused sectors, sidedefs
and vertices.  Default binding is on 'p' key.

------------------------------------------------------------------------
r797 | ajapted | 2013-02-03 22:03:16 +1100 (Sun, 03 Feb 2013) | 2 lines

Yet another CHANGELOG update.

------------------------------------------------------------------------
r796 | ajapted | 2013-02-03 22:02:45 +1100 (Sun, 03 Feb 2013) | 4 lines

1. TH_Merge and VERT_Merge: support one selected + highlight
2. VERT_Merge: don't re-select the final vertex -- index can be wrong
   (due to deletions).

------------------------------------------------------------------------
r795 | ajapted | 2013-02-03 20:34:38 +1100 (Sun, 03 Feb 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r794 | ajapted | 2013-02-03 20:30:13 +1100 (Sun, 03 Feb 2013) | 4 lines

Side panels: show blue background of 'Nombre' when a single object
is selected.  This is another visual cue that something is selected,
especially when that object is off-screen.

------------------------------------------------------------------------
r793 | ajapted | 2013-02-03 19:09:00 +1100 (Sun, 03 Feb 2013) | 4 lines

Fixed bug not clearing an after-drag selection when selecting a group
of objects via the outline box.


------------------------------------------------------------------------
r792 | ajapted | 2013-02-03 17:19:15 +1100 (Sun, 03 Feb 2013) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r791 | ajapted | 2013-02-03 17:18:08 +1100 (Sun, 03 Feb 2013) | 3 lines

LIN_MergeTwo: support one selected + one highlighted, and merge the
second linedef into the first (consistent with SEC_Merge).

------------------------------------------------------------------------
r790 | ajapted | 2013-02-03 17:14:10 +1100 (Sun, 03 Feb 2013) | 2 lines

SEC_Merge: support one selected + one highlighted.

------------------------------------------------------------------------
r789 | ajapted | 2013-02-01 22:37:22 +1100 (Fri, 01 Feb 2013) | 2 lines

CHANGELOG and TODO update.

------------------------------------------------------------------------
r788 | ajapted | 2013-02-01 22:35:21 +1100 (Fri, 01 Feb 2013) | 4 lines

When merging vertices (especially the one being dragged), check for
the situation where two linedefs would end up overlapping, if so then
delete one of them (the one connected to the dragged vertex).

------------------------------------------------------------------------
r787 | ajapted | 2013-02-01 15:50:11 +1100 (Fri, 01 Feb 2013) | 3 lines

Beep messages: ensure first letter is uppercase, also simplified a few
of the messages.

------------------------------------------------------------------------
r786 | ajapted | 2013-02-01 15:41:22 +1100 (Fri, 01 Feb 2013) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r785 | ajapted | 2013-02-01 15:39:43 +1100 (Fri, 01 Feb 2013) | 3 lines

CMD_CopyProperties: implemented 2S --> 2S for linedef textures, with
logic to "intelligently" decide which sides to copy.

------------------------------------------------------------------------
r784 | ajapted | 2013-02-01 15:20:28 +1100 (Fri, 01 Feb 2013) | 2 lines

CMD_CopyProperties: implemented 2S --> 1S case for linedefs.

------------------------------------------------------------------------
r783 | ajapted | 2013-02-01 15:01:14 +1100 (Fri, 01 Feb 2013) | 2 lines

CMD_CopyProperties: partial work to copy textures between linedefs.

------------------------------------------------------------------------
r782 | ajapted | 2013-02-01 12:00:36 +1100 (Fri, 01 Feb 2013) | 3 lines

Fixed jerky RMB scrolling at large zoom factors, done by changing the
grid fields 'orig_x' and 'orig_y' from int --> double.

------------------------------------------------------------------------
r781 | ajapted | 2013-01-30 22:32:28 +1100 (Wed, 30 Jan 2013) | 2 lines

Yet another TODO / CHANGELOG update.

------------------------------------------------------------------------
r780 | ajapted | 2013-01-30 22:30:55 +1100 (Wed, 30 Jan 2013) | 3 lines

Fixed (I hope) ClosestLine_XXX() and OppositeLineDef() functions so that
they can never hit a vertex, by offsetting the (x,y) coord by 0.5 units.

------------------------------------------------------------------------
r779 | ajapted | 2013-01-30 22:07:02 +1100 (Wed, 30 Jan 2013) | 3 lines

LineDef panel: fixed CRASH when clicking on a flag button and no linedef
was selected.

------------------------------------------------------------------------
r778 | ajapted | 2013-01-30 21:37:46 +1100 (Wed, 30 Jan 2013) | 3 lines

LineDef panel: made the flag widgets ("upper unpeg" etc) easier to
click on, the effective width covers the text (not just the checkbox).

------------------------------------------------------------------------
r777 | ajapted | 2013-01-30 21:15:37 +1100 (Wed, 30 Jan 2013) | 2 lines

CHANGELOG and TODO updated.

------------------------------------------------------------------------
r776 | ajapted | 2013-01-30 21:10:48 +1100 (Wed, 30 Jan 2013) | 2 lines

Config: added 'backup_max_files' and 'backup_max_space' vars.

------------------------------------------------------------------------
r775 | ajapted | 2013-01-30 21:04:28 +1100 (Wed, 30 Jan 2013) | 2 lines

Removed the 'escape_key_quits' config var (and from Prefs dialog).

------------------------------------------------------------------------
r774 | ajapted | 2013-01-30 20:55:42 +1100 (Wed, 30 Jan 2013) | 1 line

tweak
------------------------------------------------------------------------
r773 | ajapted | 2013-01-30 20:55:22 +1100 (Wed, 30 Jan 2013) | 4 lines

Backup system: implemented the directory scanning (to get the low and
high values which are present).  The backup system is enabled now, and
it seems to be working OK.

------------------------------------------------------------------------
r772 | ajapted | 2013-01-30 19:58:56 +1100 (Wed, 30 Jan 2013) | 4 lines

Backup system: implemented logic to limit backups (of a certain wad)
to a certain space limit -- currently hard-coded as 100 MB.


------------------------------------------------------------------------
r771 | ajapted | 2013-01-30 16:57:44 +1100 (Wed, 30 Jan 2013) | 2 lines

Wad code: set offset to 0 for zero-length lumps.

------------------------------------------------------------------------
r770 | ajapted | 2013-01-30 15:52:49 +1100 (Wed, 30 Jan 2013) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r769 | ajapted | 2013-01-30 15:44:25 +1100 (Wed, 30 Jan 2013) | 2 lines

Wad code: small optimisation for zero-length lumps.

------------------------------------------------------------------------
r768 | ajapted | 2013-01-30 15:37:12 +1100 (Wed, 30 Jan 2013) | 4 lines

Wad code: implemented new PositionForWrite() logic which tries to use
free space in the wad file.  We also check that a lump did not write
more than the 'max_size' value given to AddLump().

------------------------------------------------------------------------
r767 | ajapted | 2013-01-30 14:29:24 +1100 (Wed, 30 Jan 2013) | 3 lines

Wad code: implemented private FindFreeSpace() method, which can find
an unused area of a given size.

------------------------------------------------------------------------
r766 | ajapted | 2013-01-30 13:01:17 +1100 (Wed, 30 Jan 2013) | 2 lines

status message tweak.

------------------------------------------------------------------------
r765 | ajapted | 2013-01-30 12:59:08 +1100 (Wed, 30 Jan 2013) | 2 lines

Made the status area more distinct: bold font, vertical divider.

------------------------------------------------------------------------
r764 | ajapted | 2013-01-30 12:50:14 +1100 (Wed, 30 Jan 2013) | 2 lines

CMD_BuildNodes: update status area.

------------------------------------------------------------------------
r763 | ajapted | 2013-01-30 12:11:49 +1100 (Wed, 30 Jan 2013) | 2 lines

TODO: added plan to handle multiple files.

------------------------------------------------------------------------
r762 | printz | 2013-01-29 21:53:11 +1100 (Tue, 29 Jan 2013) | 3 lines

osx port:
* Updated project to Xcode 4.6
* Removed user-specific files from inside *.xcodeproj
------------------------------------------------------------------------
r761 | printz | 2013-01-29 21:52:55 +1100 (Tue, 29 Jan 2013) | 4 lines

osx port:
* Removed dead code and comments
* Added descriptive comments
* Updated version info and copyright formatting in the native automatic About box
------------------------------------------------------------------------
r760 | ajapted | 2013-01-29 17:16:28 +1100 (Tue, 29 Jan 2013) | 3 lines

Backup system: the main M_BackupWad() logic is done, but some helper
functions are not implemented yet -- namely Backup_ScanDir().

------------------------------------------------------------------------
r759 | ajapted | 2013-01-29 16:43:06 +1100 (Tue, 29 Jan 2013) | 7 lines

Began work on the Back-up system, which will save a copy of the wad
into the "backups" folder in $home_dir whenever the user saves the
map (CTRL-S) or exports the map into an existing wad.

This commit merely (a) creates the "backups" folder and (b) adds the
calls to M_BackupWad() at the appropriate places.

------------------------------------------------------------------------
r758 | ajapted | 2013-01-29 16:29:31 +1100 (Tue, 29 Jan 2013) | 3 lines

Wad class: implemented a Backup() method.


------------------------------------------------------------------------
r757 | ajapted | 2013-01-29 14:58:32 +1100 (Tue, 29 Jan 2013) | 2 lines

Checked in the MacOS X port source, created by Ioan Chera.

------------------------------------------------------------------------
r756 | ajapted | 2013-01-29 14:56:56 +1100 (Tue, 29 Jan 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r755 | ajapted | 2013-01-28 16:45:37 +1100 (Mon, 28 Jan 2013) | 2 lines

After loading or saving a map, show a message in status bar.

------------------------------------------------------------------------
r754 | ajapted | 2013-01-28 14:47:17 +1100 (Mon, 28 Jan 2013) | 3 lines

Fixed bug parsing user state for maps (.dat files), which was not
handling strings properly.

------------------------------------------------------------------------
r753 | ajapted | 2013-01-28 14:11:29 +1100 (Mon, 28 Jan 2013) | 2 lines

bindings.cfg : removed ESC key (bound to Quit).

------------------------------------------------------------------------
r752 | ajapted | 2013-01-28 11:20:25 +1100 (Mon, 28 Jan 2013) | 2 lines

bindings.cfg : fixed LIN_Flip key, which clashed with SNAP toggle key.

------------------------------------------------------------------------
r751 | ajapted | 2013-01-26 14:06:30 +1100 (Sat, 26 Jan 2013) | 2 lines

Made Editor_State_t be a struct (not a class).

------------------------------------------------------------------------
r750 | ajapted | 2013-01-26 14:01:44 +1100 (Sat, 26 Jan 2013) | 3 lines

Silenced 64-bit compiler warnings (loss of precision when assigning a 64-bit
value to a 32-bit variable or parameter).

------------------------------------------------------------------------
r749 | ajapted | 2013-01-26 13:55:34 +1100 (Sat, 26 Jan 2013) | 2 lines

Fixed a uninitialized variable bug, and some 64-bit tweaks.

------------------------------------------------------------------------
r748 | ajapted | 2013-01-26 13:39:55 +1100 (Sat, 26 Jan 2013) | 2 lines

Render3D: when changing gamma, show new value in status area.

------------------------------------------------------------------------
r747 | ajapted | 2013-01-25 09:43:00 +1100 (Fri, 25 Jan 2013) | 2 lines

Wrote some notes about possible scripting API : misc/Scripting.txt

------------------------------------------------------------------------
r746 | ajapted | 2013-01-24 21:42:16 +1100 (Thu, 24 Jan 2013) | 2 lines

debug tweak.

------------------------------------------------------------------------
r745 | ajapted | 2013-01-24 21:37:41 +1100 (Thu, 24 Jan 2013) | 2 lines

TODO updated.

------------------------------------------------------------------------
r744 | ajapted | 2013-01-24 21:36:59 +1100 (Thu, 24 Jan 2013) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r743 | ajapted | 2013-01-24 21:36:27 +1100 (Thu, 24 Jan 2013) | 3 lines

When executing key bindings, clear status area if no error occurs.
(Implementation detail: we clear it beforehand).

------------------------------------------------------------------------
r742 | ajapted | 2013-01-24 21:32:17 +1100 (Thu, 24 Jan 2013) | 2 lines

SEC_Merge: beep at user if only 1 sector was selected.

------------------------------------------------------------------------
r741 | ajapted | 2013-01-24 16:56:20 +1100 (Thu, 24 Jan 2013) | 3 lines

Version bump, in honor of new key binding system (all hard-coded keys,
except for digits and the menus, are now handled via key bindings).

------------------------------------------------------------------------
r740 | ajapted | 2013-01-24 15:57:37 +1100 (Thu, 24 Jan 2013) | 2 lines

Fixed missing "else" in R3D_Set() function.

------------------------------------------------------------------------
r739 | ajapted | 2013-01-24 15:56:43 +1100 (Thu, 24 Jan 2013) | 2 lines

Implemented new '3D_Set' binding command.

------------------------------------------------------------------------
r738 | ajapted | 2013-01-24 15:55:02 +1100 (Thu, 24 Jan 2013) | 2 lines

Fixed some bugs in CMD_Set().

------------------------------------------------------------------------
r737 | ajapted | 2013-01-24 15:43:48 +1100 (Thu, 24 Jan 2013) | 3 lines

1. implemented '3D_Toggle' binding command
2. removed the now-dead Render3D_Key() function

------------------------------------------------------------------------
r736 | ajapted | 2013-01-24 15:42:38 +1100 (Thu, 24 Jan 2013) | 2 lines

Tidying of the CMD_Toggle() and CMD_Set() code.

------------------------------------------------------------------------
r735 | ajapted | 2013-01-24 15:30:16 +1100 (Thu, 24 Jan 2013) | 2 lines

bindings.cfg : fixed wrong comment syntax

------------------------------------------------------------------------
r734 | ajapted | 2013-01-24 15:28:09 +1100 (Thu, 24 Jan 2013) | 3 lines

Implemented more render binding commands: '3D_Up', '3D_Down', '3D_Turn',
'3D_DropToFloor' and '3D_Gamma'.

------------------------------------------------------------------------
r733 | ajapted | 2013-01-24 14:43:31 +1100 (Thu, 24 Jan 2013) | 3 lines

Implemented four binding commands for renderer: '3D_Forward', '3D_Backward',
'3D_Left' and '3D_Right'.

------------------------------------------------------------------------
r732 | ajapted | 2013-01-24 14:23:17 +1100 (Thu, 24 Jan 2013) | 3 lines

Fixed missing 'SEC_SwapFlats' registration (I must have clobbered it
accidentally in an earlier commit).

------------------------------------------------------------------------
r731 | ajapted | 2013-01-24 14:14:17 +1100 (Thu, 24 Jan 2013) | 3 lines

1. implemented 'JumpToObject' binding command
2. removed the now-dead Editor_Key() code

------------------------------------------------------------------------
r730 | ajapted | 2013-01-24 13:31:03 +1100 (Thu, 24 Jan 2013) | 3 lines

Added Editor_DigitKey() function to handle digit keys (which do not
use the key binding system).

------------------------------------------------------------------------
r729 | ajapted | 2013-01-24 13:24:18 +1100 (Thu, 24 Jan 2013) | 3 lines

Implemented "grid" and "snap" variables for 'Toggle' and 'Set' binding
commands.

------------------------------------------------------------------------
r728 | ajapted | 2013-01-24 13:11:53 +1100 (Thu, 24 Jan 2013) | 2 lines

Implemented 'GRID_Step' binding command.

------------------------------------------------------------------------
r727 | ajapted | 2013-01-24 12:53:24 +1100 (Thu, 24 Jan 2013) | 2 lines

Implemented 'Zoom' binding command.

------------------------------------------------------------------------
r726 | ajapted | 2013-01-24 12:46:03 +1100 (Thu, 24 Jan 2013) | 2 lines

Implemented 'ZoomWholeMap' and 'ZoomSelection' binding commands.

------------------------------------------------------------------------
r725 | ajapted | 2013-01-24 12:32:17 +1100 (Thu, 24 Jan 2013) | 2 lines

Tweaked a few bits of 'long' usage to prevent warnings.

------------------------------------------------------------------------
r724 | ajapted | 2013-01-24 12:24:56 +1100 (Thu, 24 Jan 2013) | 2 lines

Changed rgb_color_t typedef to use u32_t (was: unsigned long).

------------------------------------------------------------------------
r723 | ajapted | 2013-01-24 12:23:49 +1100 (Thu, 24 Jan 2013) | 2 lines

Removed unused centre_of_sectors() function.

------------------------------------------------------------------------
r722 | ajapted | 2013-01-24 12:18:50 +1100 (Thu, 24 Jan 2013) | 5 lines

1. renamed IsLineDefInside() --> LineCrossesBox(), tidied up the code
   and replaced 'long' usage
2. removed unused GetObjectCoords() function
3. replaced 'long' usage in GetOppositeSector()

------------------------------------------------------------------------
r721 | ajapted | 2013-01-23 23:57:42 +1100 (Wed, 23 Jan 2013) | 3 lines

Implemented three browser-related binding commands, and removed the
no-longer-needed Browser_Key() function.

------------------------------------------------------------------------
r720 | ajapted | 2013-01-23 20:46:04 +1100 (Wed, 23 Jan 2013) | 3 lines

1. implemented 'CMD_SetBrowser' binding command
2. removed dead Global_Key() function

------------------------------------------------------------------------
r719 | ajapted | 2013-01-23 19:48:26 +1100 (Wed, 23 Jan 2013) | 3 lines

1. implemented 'LIN_SelectPath' binding command
2. removed the dead Thing_Key / Sector_Key (etc) functions

------------------------------------------------------------------------
r718 | ajapted | 2013-01-23 19:28:16 +1100 (Wed, 23 Jan 2013) | 3 lines

1. implemented 'LIN_Flip' and 'LIN_SplitHalf' binding commands
2. changed binding of LIN_SplitHalf from 'x' --> 'k'

------------------------------------------------------------------------
r717 | ajapted | 2013-01-23 19:12:53 +1100 (Wed, 23 Jan 2013) | 3 lines

1. Use ExecuteCommand() for some menu functions
2. added some Beep() error messages

------------------------------------------------------------------------
r716 | ajapted | 2013-01-23 16:53:24 +1100 (Wed, 23 Jan 2013) | 2 lines

Implemented 'CopyProperties' binding command.

------------------------------------------------------------------------
r715 | ajapted | 2013-01-23 16:45:04 +1100 (Wed, 23 Jan 2013) | 3 lines

1. renamed EXEC_Result --> EXEC_Errno
2. set EXEC_Errno to 1 in the Beep() error function

------------------------------------------------------------------------
r714 | ajapted | 2013-01-23 16:40:45 +1100 (Wed, 23 Jan 2013) | 3 lines

1. added EXEC_Result global, for testing if a command failed
2. implemented an ExecuteCommand() function

------------------------------------------------------------------------
r713 | ajapted | 2013-01-23 15:08:41 +1100 (Wed, 23 Jan 2013) | 3 lines

SEC_SelectGroup : implemented new 'w' flag, perform a walking test
(i.e. don't spread selection across lines which block the player).

------------------------------------------------------------------------
r712 | ajapted | 2013-01-23 14:56:10 +1100 (Wed, 23 Jan 2013) | 4 lines

Implemented 'SEC_SelectGroup' binding command, and expanding the matching
capabilities to support matching the light, tag and special values, and
also have a flag to allow passing through doors.

------------------------------------------------------------------------
r711 | ajapted | 2013-01-23 12:59:05 +1100 (Wed, 23 Jan 2013) | 3 lines

Support "3d" and "browser" variables with 'Toggle' and 'Set' binding
commands.  This replaces the 'Toggle3D' and 'ToggleBrowser' commands.

------------------------------------------------------------------------
r710 | ajapted | 2013-01-23 12:31:05 +1100 (Wed, 23 Jan 2013) | 2 lines

Implemented 'SEC_Floor' and 'SEC_Ceil' binding commands.

------------------------------------------------------------------------
r709 | ajapted | 2013-01-23 11:13:31 +1100 (Wed, 23 Jan 2013) | 2 lines

Implemented 'GoToCamera' and 'PlaceCamera' binding commands.

------------------------------------------------------------------------
r708 | ajapted | 2013-01-23 10:57:03 +1100 (Wed, 23 Jan 2013) | 3 lines

Implemented new 'Set' binding command, this can set a variable to a
particular value.  Only one variable "obj_nums" is supported so far.

------------------------------------------------------------------------
r707 | ajapted | 2013-01-23 10:48:00 +1100 (Wed, 23 Jan 2013) | 4 lines

Implemented 'Toggle' binding command, which takes a variable name to
toggle.  Current variables are "obj_nums" and "skills".  This replaces
the previous 'ToggleObjNums' command.

------------------------------------------------------------------------
r706 | ajapted | 2013-01-22 22:59:16 +1100 (Tue, 22 Jan 2013) | 2 lines

Implemented the 'Delete' binding command, with optional "keep" parameter.

------------------------------------------------------------------------
r705 | ajapted | 2013-01-22 22:57:14 +1100 (Tue, 22 Jan 2013) | 4 lines

Fixed two bugs in M_ParseKeyString() :-
1. the "SHIFT-" modifier had the wrong value
2. keys found in the table did not apply any modifier mask

------------------------------------------------------------------------
r704 | ajapted | 2013-01-22 22:48:47 +1100 (Tue, 22 Jan 2013) | 3 lines

Keys: fixed bug in M_TranslateKey() -- don't use ispunct() on keys which
are not ASCII (especially values like FL_BackSpace).

------------------------------------------------------------------------
r703 | ajapted | 2013-01-22 18:56:04 +1100 (Tue, 22 Jan 2013) | 3 lines

1. removed last vestiges of 'keymod_e' and KM_XXX
2. renamed some editor functions to have "Editor_" prefix

------------------------------------------------------------------------
r702 | ajapted | 2013-01-22 18:21:50 +1100 (Tue, 22 Jan 2013) | 5 lines

1. define PACKEDATTR in sys_macro.h -- source was Chocolate-Doom

2. added PACKEDATTR macro to all the raw on-disk structures, which
   may be needed on certain systems (especially 64-bit systems).

------------------------------------------------------------------------
r701 | ajapted | 2013-01-22 14:26:53 +1100 (Tue, 22 Jan 2013) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r700 | ajapted | 2013-01-22 14:26:11 +1100 (Tue, 22 Jan 2013) | 2 lines

Implemented 'Insert' binding command.

------------------------------------------------------------------------
r699 | ajapted | 2013-01-22 14:08:29 +1100 (Tue, 22 Jan 2013) | 3 lines

Implemented a 'Nothing' command binding, as the name suggests it does
nothing at all -- possibly more useful than it sounds.

------------------------------------------------------------------------
r698 | ajapted | 2013-01-22 14:04:56 +1100 (Tue, 22 Jan 2013) | 3 lines

Implemented 'Merge' binding command for things, which places all the
selected things at a single location.

------------------------------------------------------------------------
r697 | ajapted | 2013-01-22 12:21:29 +1100 (Tue, 22 Jan 2013) | 3 lines

Things: new logic for 'Disconnect' -- the semantics are to move apart
things at the same location (or very close).

------------------------------------------------------------------------
r696 | ajapted | 2013-01-22 10:44:39 +1100 (Tue, 22 Jan 2013) | 2 lines

Added or tweaked some Beep() messages.

------------------------------------------------------------------------
r695 | ajapted | 2013-01-22 10:43:28 +1100 (Tue, 22 Jan 2013) | 4 lines

Things: worked on 'Disconnect' for things, which will separate things
which are overlapping each other.  The logic in this commit is rather
flawed though...

------------------------------------------------------------------------
r694 | ajapted | 2013-01-22 09:55:10 +1100 (Tue, 22 Jan 2013) | 4 lines

Implemented 'Merge' and 'Disconnect' binding commands, which are used
for every mode ("global" context).  These replace the mode-specific
binding commands like 'LIN_MergeTwo'.

------------------------------------------------------------------------
r693 | ajapted | 2013-01-22 09:49:08 +1100 (Tue, 22 Jan 2013) | 1 line

minor tweak
------------------------------------------------------------------------
r692 | ajapted | 2013-01-21 13:09:26 +1100 (Mon, 21 Jan 2013) | 4 lines

Key handling / M_SaveBindings:
1. fixed bug writing an 'UNBOUND' key multiple times
2. aesthetic change : no contiguous blank lines

------------------------------------------------------------------------
r691 | ajapted | 2013-01-21 12:59:36 +1100 (Mon, 21 Jan 2013) | 1 line

tweak
------------------------------------------------------------------------
r690 | ajapted | 2013-01-21 12:58:36 +1100 (Mon, 21 Jan 2013) | 6 lines

Key handling:
1. when writing the local bindings.cfg, skip bindings which are exactly
   the same as one from the install_dir
2. detect un-bound keys and write them using "UNBOUND" as the command
3. parse this "UNBOUND" keyword when reading a bindings.cfg

------------------------------------------------------------------------
r689 | ajapted | 2013-01-21 12:23:55 +1100 (Mon, 21 Jan 2013) | 3 lines

Key handling: keep an in-memory copy of the install_dir bindings.
It will be needed for M_SaveBindings() to only write the differences.

------------------------------------------------------------------------
r688 | ajapted | 2013-01-21 10:38:05 +1100 (Mon, 21 Jan 2013) | 2 lines

tidied up Main_key_handler().

------------------------------------------------------------------------
r687 | ajapted | 2013-01-21 08:53:42 +1100 (Mon, 21 Jan 2013) | 3 lines

Key handling: moved translation code to M_TranslateKey() function
(out of UI_Canvas::handle_key method).

------------------------------------------------------------------------
r686 | ajapted | 2013-01-21 08:29:28 +1100 (Mon, 21 Jan 2013) | 4 lines

1. replaced map name on info bar with a status box
2. added Status_Set() and Status_Clear() functions
3. updated Beep() to set the status and show message in log

------------------------------------------------------------------------
r685 | ajapted | 2013-01-20 19:05:39 +1100 (Sun, 20 Jan 2013) | 2 lines

Implemented 'Scroll' binding command (for scrolling the map view).

------------------------------------------------------------------------
r684 | ajapted | 2013-01-20 18:37:07 +1100 (Sun, 20 Jan 2013) | 2 lines

Implemented 'EditMode' binding command.

------------------------------------------------------------------------
r683 | ajapted | 2013-01-20 18:35:16 +1100 (Sun, 20 Jan 2013) | 2 lines

tweaks.

------------------------------------------------------------------------
r682 | ajapted | 2013-01-20 16:28:38 +1100 (Sun, 20 Jan 2013) | 4 lines

bindings.cfg :
1. fixed key for vertical mirror ('V' not 'v')
2. fixed some command names

------------------------------------------------------------------------
r681 | ajapted | 2013-01-20 16:20:48 +1100 (Sun, 20 Jan 2013) | 2 lines

Implemented 'CopyAndPaste' binding command.

------------------------------------------------------------------------
r680 | ajapted | 2013-01-20 16:15:43 +1100 (Sun, 20 Jan 2013) | 7 lines

Implemented these binding commands:
   Mirror    (parameter is "horiz" or "vert")
   Rotate90  (parameter is direction, +1 for acw, -1 for cw)
   Enlarge   (replaces CMD_ScaleObjects, parameter is multiplier)
   Shrink    (replaces CMD_ScaleObjects, parameter is divisor)
   Quantize

------------------------------------------------------------------------
r679 | ajapted | 2013-01-20 13:14:41 +1100 (Sun, 20 Jan 2013) | 5 lines

Implemented following as binding commands:
1. VERT_Merge, VERT_Disconnect
2. LIN_MergeTwo, LIN_Disconnect
3. SEC_Merge, SEC_Disconnect

------------------------------------------------------------------------
r678 | ajapted | 2013-01-20 12:46:06 +1100 (Sun, 20 Jan 2013) | 2 lines

Key binding: Implemented 'TH_Spin' command (removed hard-coded 'w' and 'x' keys).

------------------------------------------------------------------------
r677 | ajapted | 2013-01-20 12:36:23 +1100 (Sun, 20 Jan 2013) | 3 lines

Key handling: ensure the EXEC_Param[] values are never NULL, use the
empty string instead.

------------------------------------------------------------------------
r676 | ajapted | 2013-01-20 12:06:46 +1100 (Sun, 20 Jan 2013) | 2 lines

bindings.cfg : tweaked prefixes (e.g. LN --> LIN, GR --> GRID)

------------------------------------------------------------------------
r675 | ajapted | 2013-01-20 10:59:59 +1100 (Sun, 20 Jan 2013) | 2 lines

Key handling: merged "edit" and "global" contexts into one (global).

------------------------------------------------------------------------
r674 | ajapted | 2013-01-20 10:36:01 +1100 (Sun, 20 Jan 2013) | 3 lines

Key handling: implemented M_RemoveBinding(), and use it to ensure that
bindings from the home_dir replace bindings from the install_dir.

------------------------------------------------------------------------
r673 | ajapted | 2013-01-20 10:23:59 +1100 (Sun, 20 Jan 2013) | 5 lines

Key handling:
1. load bindings from BOTH install_dir and home_dir paths (otherwise
   new releases of Eureka would be unable to add new bindings)
2. fixed parsing of double quotes (") in bindings.cfg

------------------------------------------------------------------------
r672 | ajapted | 2013-01-19 21:59:24 +1100 (Sat, 19 Jan 2013) | 2 lines

Key handling: un-hard-code the ` (back-quote) key -- rely on binding.

------------------------------------------------------------------------
r671 | ajapted | 2013-01-19 21:57:25 +1100 (Sat, 19 Jan 2013) | 3 lines

Key handling: when writing the bindings, group them by their context
(a purely aesthetic change).

------------------------------------------------------------------------
r670 | ajapted | 2013-01-19 21:31:19 +1100 (Sat, 19 Jan 2013) | 5 lines

Key handling:
1. renamed CMD_SwapFlats --> SEC_SwapFlats
2. made it use key bindings (no hard-coded test against 'w' key)
3. moved M_RegisterCommand() calls into a separate function (editloop.cc)

------------------------------------------------------------------------
r669 | ajapted | 2013-01-19 21:23:30 +1100 (Sat, 19 Jan 2013) | 2 lines

tweaked M_ModeToKeyContext()

------------------------------------------------------------------------
r668 | ajapted | 2013-01-19 21:21:23 +1100 (Sat, 19 Jan 2013) | 3 lines

Key handling: have EXEC_Param[] global var to contain the parameters
from the key binding being executed.

------------------------------------------------------------------------
r667 | ajapted | 2013-01-19 21:15:16 +1100 (Sat, 19 Jan 2013) | 5 lines

Key handling:
1. renamed KCTX_INVALID --> KCTX_NONE
2. when registering commands, can specify a required context
3. prevent binding keys to a command in the wrong context

------------------------------------------------------------------------
r666 | ajapted | 2013-01-19 18:48:38 +1100 (Sat, 19 Jan 2013) | 3 lines

Key handler: a few commands now rely on new system, e.g. TAB to toggle
the 3D view, and 'b' to toggle the browser panel.

------------------------------------------------------------------------
r665 | ajapted | 2013-01-19 18:45:22 +1100 (Sat, 19 Jan 2013) | 7 lines

Key handling: use new ExecuteKey() function to handle keys, using the
same propagation logic.  A few commands now rely on this, e.g. TAB to
toggle the 3D view.

The existing XXX_Key() functions are still in place, but will only
remain during the transition to the new system.

------------------------------------------------------------------------
r664 | ajapted | 2013-01-19 18:40:36 +1100 (Sat, 19 Jan 2013) | 2 lines

Key handling: fixed parsing of long key names (like "ESC").

------------------------------------------------------------------------
r663 | ajapted | 2013-01-19 18:32:38 +1100 (Sat, 19 Jan 2013) | 5 lines

Key handling:
1. moved key_context_e enumeration to global scope (header file)
2. added M_ModeToKeyContext() function
3. implemented ExecuteKey() function

------------------------------------------------------------------------
r662 | ajapted | 2013-01-19 15:47:37 +1100 (Sat, 19 Jan 2013) | 2 lines

Key handling: finished M_LoadBindings() -- parse each binding and add it.

------------------------------------------------------------------------
r661 | ajapted | 2013-01-19 15:31:46 +1100 (Sat, 19 Jan 2013) | 3 lines

Key handling: partial work implementing M_LoadBindings().
This commit just has the code to open the file and read tokens.

------------------------------------------------------------------------
r660 | ajapted | 2013-01-19 14:23:30 +1100 (Sat, 19 Jan 2013) | 3 lines

Key handling: handle function and keypad keys in M_ParseKeyString() and
M_KeyToString().

------------------------------------------------------------------------
r659 | ajapted | 2013-01-19 14:10:42 +1100 (Sat, 19 Jan 2013) | 2 lines

Key handling: more names for key_map[] table (e.g. VOL_DOWN, CD_PLAY, etc).

------------------------------------------------------------------------
r658 | ajapted | 2013-01-19 14:00:15 +1100 (Sat, 19 Jan 2013) | 4 lines

Key handling: added a key_map[] table for mapping special keys from
their code to their name or vice versa.

------------------------------------------------------------------------
r657 | ajapted | 2013-01-19 13:25:45 +1100 (Sat, 19 Jan 2013) | 4 lines

Key handling:
1. implemented M_WriteBindings()
2. partial work on M_ParseKeyString() and M_KeyToString()

------------------------------------------------------------------------
r656 | ajapted | 2013-01-19 12:52:29 +1100 (Sat, 19 Jan 2013) | 2 lines

Makefile: install the 'bindings.cfg' file.

------------------------------------------------------------------------
r655 | ajapted | 2013-01-19 12:45:29 +1100 (Sat, 19 Jan 2013) | 2 lines

Added some M_RegisterCommand() calls in Editor_Init().

------------------------------------------------------------------------
r654 | ajapted | 2013-01-19 12:42:18 +1100 (Sat, 19 Jan 2013) | 2 lines

Key handling: changed command_func_t to return 'void' (not 'bool').

------------------------------------------------------------------------
r653 | ajapted | 2013-01-19 10:41:47 +1100 (Sat, 19 Jan 2013) | 7 lines

Key handling (m_keys.cc) :
1. added editor_command_t structure
2. added M_AddEditorCommand() and FindEditorCommand()
3. added key_context_e enumeration
4. added ParseKeyContext() and KeyContextString() functions
5. added key_binding_t structure

------------------------------------------------------------------------
r652 | ajapted | 2013-01-18 21:59:36 +1100 (Fri, 18 Jan 2013) | 2 lines

New code files to handle key binding logic : m_keys.cc/h

------------------------------------------------------------------------
r651 | ajapted | 2013-01-18 21:52:26 +1100 (Fri, 18 Jan 2013) | 3 lines

Key handling: changed some keymod_e (KM_XXX) usages to use keycode_t
(MOD_XXX) defines instead.

------------------------------------------------------------------------
r650 | ajapted | 2013-01-18 21:18:44 +1100 (Fri, 18 Jan 2013) | 2 lines

Bindings.txt : simpler format, a few tweaks.

------------------------------------------------------------------------
r649 | ajapted | 2013-01-18 17:11:03 +1100 (Fri, 18 Jan 2013) | 2 lines

Finished the list of needed key bindings.

------------------------------------------------------------------------
r648 | ajapted | 2013-01-18 16:42:37 +1100 (Fri, 18 Jan 2013) | 2 lines

Partial work on a list of needed key bindings.

------------------------------------------------------------------------
r647 | ajapted | 2013-01-18 16:08:29 +1100 (Fri, 18 Jan 2013) | 3 lines

Key handling: convert SHIFT + punctuation key to the shifted value,
for example SHIFT + ',' --> '<'

------------------------------------------------------------------------
r646 | ajapted | 2013-01-18 15:55:59 +1100 (Fri, 18 Jan 2013) | 3 lines

Updated key handling code (UI_Canvas::handle_key, XXX_Key functions) to
use the new keycode_t semantics.

------------------------------------------------------------------------
r645 | ajapted | 2013-01-18 15:35:20 +1100 (Fri, 18 Jan 2013) | 2 lines

Updated semantics of keycode_t for digits.

------------------------------------------------------------------------
r644 | ajapted | 2013-01-16 22:16:55 +1100 (Wed, 16 Jan 2013) | 3 lines

Added key_code_t typedef (and more importantly, comments defining its
semantics).  Not used yet, but will be needed for configurable keys...

------------------------------------------------------------------------
r643 | ajapted | 2013-01-15 22:11:41 +1100 (Tue, 15 Jan 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r642 | ajapted | 2013-01-15 22:09:55 +1100 (Tue, 15 Jan 2013) | 2 lines

Updated some copyright messages for 2013.

------------------------------------------------------------------------
r641 | ajapted | 2013-01-15 22:05:22 +1100 (Tue, 15 Jan 2013) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r640 | ajapted | 2013-01-15 21:28:58 +1100 (Tue, 15 Jan 2013) | 2 lines

Prefs and Config: implemented a "default grid mode" setting.

------------------------------------------------------------------------
r639 | ajapted | 2013-01-15 21:05:24 +1100 (Tue, 15 Jan 2013) | 2 lines

Prefs dialog: implemented 'default_grid_size' setting.

------------------------------------------------------------------------
r638 | ajapted | 2013-01-15 20:52:38 +1100 (Tue, 15 Jan 2013) | 2 lines

Grid: removed '192' as a possible grid size.

------------------------------------------------------------------------
r637 | ajapted | 2013-01-15 19:18:17 +1100 (Tue, 15 Jan 2013) | 3 lines

Prefs dialog: implemented some of remaining General stuff, such as:
default_grid_snap, digits_set_zoom and escape_key_quits.

------------------------------------------------------------------------
r636 | ajapted | 2013-01-15 16:33:40 +1100 (Tue, 15 Jan 2013) | 2 lines

Config: added gui_custom_xx color variables.

------------------------------------------------------------------------
r635 | ajapted | 2013-01-15 16:20:40 +1100 (Tue, 15 Jan 2013) | 2 lines

Prefs dialog: got the theme section of 'General' tab working.

------------------------------------------------------------------------
r634 | ajapted | 2013-01-15 16:03:28 +1100 (Tue, 15 Jan 2013) | 2 lines

Prefs dialog: got the glBSP settings working.

------------------------------------------------------------------------
r633 | ajapted | 2013-01-15 14:21:08 +1100 (Tue, 15 Jan 2013) | 3 lines

Prefs dialog: implemented rest of Editing options (except the modifier
key for multi-select has only one choice: CTRL).

------------------------------------------------------------------------
r632 | ajapted | 2013-01-15 14:08:23 +1100 (Tue, 15 Jan 2013) | 4 lines

Prefs dialog:
1. call M_WriteConfigFile() to persist the changes
2. implemented one of the settings : new_sector_size

------------------------------------------------------------------------
r631 | ajapted | 2013-01-15 14:04:01 +1100 (Tue, 15 Jan 2013) | 3 lines

Config: moved extern declarations into header (m_config.h) so that the
preferences code can access them.

------------------------------------------------------------------------
r630 | ajapted | 2013-01-15 13:55:52 +1100 (Tue, 15 Jan 2013) | 2 lines

Prefs dialog: implemented color_callback().

------------------------------------------------------------------------
r629 | ajapted | 2013-01-15 13:50:09 +1100 (Tue, 15 Jan 2013) | 3 lines

Prefs dialog: make initial tab be the first one, and remember the last
active tab for next time preferences dialog is opened.

------------------------------------------------------------------------
r628 | ajapted | 2013-01-15 13:29:10 +1100 (Tue, 15 Jan 2013) | 2 lines

Prefs dialog: implemented callback for OK button and window close.

------------------------------------------------------------------------
r627 | ajapted | 2013-01-15 13:28:28 +1100 (Tue, 15 Jan 2013) | 1 line

layout tweak
------------------------------------------------------------------------
r626 | ajapted | 2013-01-15 12:34:10 +1100 (Tue, 15 Jan 2013) | 3 lines

EUREKA lump: better iwad check when a resource cannot be found (i.e.
use the IWAD path for the game specified in the lump, not Iwad_name).

------------------------------------------------------------------------
r625 | ajapted | 2013-01-15 12:24:53 +1100 (Tue, 15 Jan 2013) | 2 lines

docco tweaks.

------------------------------------------------------------------------
r624 | ajapted | 2013-01-15 12:19:24 +1100 (Tue, 15 Jan 2013) | 3 lines

Prefs dialog: inserted the code generated by fluid (from prefs2.fl),
with some tidying and adding missing fields and methods.

------------------------------------------------------------------------
r623 | ajapted | 2013-01-15 12:03:19 +1100 (Tue, 15 Jan 2013) | 2 lines

Prefs dialog: started work on it, e.g. the basic Run() method.

------------------------------------------------------------------------
r622 | ajapted | 2013-01-15 11:50:35 +1100 (Tue, 15 Jan 2013) | 4 lines

About dialog: reworked code, use an '_instance' field to keep track of
the current window, and allow the rest of the application to function
while it is open (i.e. it is _not_ modal).

------------------------------------------------------------------------
r621 | ajapted | 2013-01-15 10:33:13 +1100 (Tue, 15 Jan 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r620 | ajapted | 2013-01-15 10:25:36 +1100 (Tue, 15 Jan 2013) | 2 lines

CHANGELOG: created a fresh one (after 0.88c release).

------------------------------------------------------------------------
r619 | ajapted | 2013-01-15 10:20:53 +1100 (Tue, 15 Jan 2013) | 3 lines

When parsing the EUREKA lump and a resource wad cannot be found, look
for it same directory as the PWAD, then try same dir as the IWAD.

------------------------------------------------------------------------
r618 | ajapted | 2013-01-15 10:18:26 +1100 (Tue, 15 Jan 2013) | 2 lines

File utils: fixed some bugs in FileReposition().

------------------------------------------------------------------------
r617 | ajapted | 2013-01-15 10:06:08 +1100 (Tue, 15 Jan 2013) | 3 lines

File utils: implemented FilenameReposition() function, which takes a
filename and replaces its path with the path from another filename.

------------------------------------------------------------------------
r616 | ajapted | 2013-01-10 22:47:36 +1100 (Thu, 10 Jan 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r615 | ajapted | 2013-01-06 19:34:04 +1100 (Sun, 06 Jan 2013) | 2 lines

more TO-DO goodies...

------------------------------------------------------------------------
r614 | ajapted | 2013-01-04 12:58:27 +1100 (Fri, 04 Jan 2013) | 2 lines

Version bump after 0.88c release.

------------------------------------------------------------------------
r613 | ajapted | 2013-01-04 12:57:24 +1100 (Fri, 04 Jan 2013) | 2 lines

README.txt : added my SF email address.

------------------------------------------------------------------------
r612 | ajapted | 2013-01-04 12:56:59 +1100 (Fri, 04 Jan 2013) | 2 lines

Debian: control tweak

------------------------------------------------------------------------
r611 | ajapted | 2013-01-04 12:56:29 +1100 (Fri, 04 Jan 2013) | 2 lines

Moved CHANGES.txt --> docs/ folder, after 0.88c release.

------------------------------------------------------------------------
r610 | ajapted | 2013-01-04 12:55:45 +1100 (Fri, 04 Jan 2013) | 2 lines

CHANGELOG tweak.

------------------------------------------------------------------------
r609 | ajapted | 2013-01-04 12:55:19 +1100 (Fri, 04 Jan 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r608 | ajapted | 2013-01-02 15:26:44 +1100 (Wed, 02 Jan 2013) | 2 lines

TODO update.

------------------------------------------------------------------------
r607 | ajapted | 2012-12-27 21:03:42 +1100 (Thu, 27 Dec 2012) | 2 lines

TODO.txt : document logic for texture alignment keys.

------------------------------------------------------------------------
r606 | ajapted | 2012-12-26 21:08:54 +1100 (Wed, 26 Dec 2012) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r605 | ajapted | 2012-12-26 19:08:02 +1100 (Wed, 26 Dec 2012) | 2 lines

TODO update (fixed the slime trails).

------------------------------------------------------------------------
r604 | ajapted | 2012-12-26 19:06:11 +1100 (Wed, 26 Dec 2012) | 2 lines

Makefile: made 'uninstall' also remove the desktop and icon files.

------------------------------------------------------------------------
r603 | ajapted | 2012-12-26 18:44:19 +1100 (Wed, 26 Dec 2012) | 3 lines

3D View: implemented even better DistCmp() logic, which has eliminated
nearly all trails.

------------------------------------------------------------------------
r602 | ajapted | 2012-12-26 18:12:10 +1100 (Wed, 26 Dec 2012) | 2 lines

3D View: reduced the slime trails.

------------------------------------------------------------------------
r601 | ajapted | 2012-12-26 16:17:53 +1100 (Wed, 26 Dec 2012) | 2 lines

Coding: simpler usage of Fl_Sys_Menu_Bar.

------------------------------------------------------------------------
r600 | ajapted | 2012-12-26 16:17:11 +1100 (Wed, 26 Dec 2012) | 2 lines

Dead code removal (ui_menu.cc)

------------------------------------------------------------------------
r599 | ajapted | 2012-12-24 22:23:01 +1100 (Mon, 24 Dec 2012) | 2 lines

Renamed WISHLIST.txt --> TODO.txt

------------------------------------------------------------------------
r598 | ajapted | 2012-12-24 22:21:49 +1100 (Mon, 24 Dec 2012) | 2 lines

Removed TODO.txt file : about to rename WISHLIST --> TODO...

------------------------------------------------------------------------
r597 | ajapted | 2012-12-24 22:18:25 +1100 (Mon, 24 Dec 2012) | 2 lines

WISHLIST update.

------------------------------------------------------------------------
r596 | ajapted | 2012-12-24 22:17:25 +1100 (Mon, 24 Dec 2012) | 1 line

tweak
------------------------------------------------------------------------
r595 | ajapted | 2012-12-24 22:16:30 +1100 (Mon, 24 Dec 2012) | 5 lines

Debian: updated control file:
1. removed libfltk1.3 as a dependency (statically linked now)
2. added various dependencies, esp. X window stuff
3. bumped version

------------------------------------------------------------------------
r594 | ajapted | 2012-12-24 22:14:49 +1100 (Mon, 24 Dec 2012) | 2 lines

Debian: updated Makefile to "install" the eureka desktop file and icon.

------------------------------------------------------------------------
r593 | ajapted | 2012-12-24 19:22:34 +1100 (Mon, 24 Dec 2012) | 4 lines

Makefile: support for static linking with an FLTK which does not include
OpenGL support and which uses 'localjpeg' and 'localpng' configuration.
That is conditional on FLTK_STATIC being defined.

------------------------------------------------------------------------
r592 | ajapted | 2012-12-24 19:18:58 +1100 (Mon, 24 Dec 2012) | 3 lines

Manage Wads dialog: fixed bug where the selected port reset to 'boom'
unless the user selected something in the choice button.

------------------------------------------------------------------------
r591 | ajapted | 2012-12-24 16:54:40 +1100 (Mon, 24 Dec 2012) | 2 lines

PORT defs: tweaks.

------------------------------------------------------------------------
r590 | ajapted | 2012-12-24 16:53:49 +1100 (Mon, 24 Dec 2012) | 2 lines

AUTHORS.txt updated.

------------------------------------------------------------------------
r589 | ajapted | 2012-12-24 16:50:52 +1100 (Mon, 24 Dec 2012) | 2 lines

LineDef panel: minor rename: 'pass use' --> 'pass thru'

------------------------------------------------------------------------
r588 | ajapted | 2012-12-24 15:47:37 +1100 (Mon, 24 Dec 2012) | 3 lines

PORTS: added Doom Legacy definition 'legacy.ugh', by wesleyjohnson
(with a few tweaks by me).

------------------------------------------------------------------------
r587 | ajapted | 2012-12-24 12:13:04 +1100 (Mon, 24 Dec 2012) | 3 lines

Fix (hopefully) for compile error on 64-bit targets: casting a 'void*'
to an 'int' losing precision.

------------------------------------------------------------------------
r586 | ajapted | 2012-12-23 18:24:18 +1100 (Sun, 23 Dec 2012) | 2 lines

CHANGELOG: added revision numbers and "Changes since ..." line.

------------------------------------------------------------------------
r585 | ajapted | 2012-12-23 16:12:45 +1100 (Sun, 23 Dec 2012) | 3 lines

Docs: created a single file with all the repository commit history,
namely the 'docs/History.txt' file.  Hence removed the other copies.

------------------------------------------------------------------------
r584 | ajapted | 2012-12-23 14:55:34 +1100 (Sun, 23 Dec 2012) | 2 lines

WISHLIST update.

------------------------------------------------------------------------
r583 | ajapted | 2012-12-23 14:23:56 +1100 (Sun, 23 Dec 2012) | 2 lines

Changed '__EUREKA' lump format, store 'game' instead than an iwad path.

------------------------------------------------------------------------
r582 | ajapted | 2012-12-23 14:09:25 +1100 (Sun, 23 Dec 2012) | 6 lines

Handle the '__EUREKA' lump a lot more robustly:
1. if the game is unsupported, warn user with a choice: ignore/cancel
2. if iwad is not found, but it is known, use the known path
3. if iwad cannot be found at all, warn user with a choice: ignore/cancel
4. log some warnings on syntax errors

------------------------------------------------------------------------
r581 | ajapted | 2012-12-23 12:33:07 +1100 (Sun, 23 Dec 2012) | 4 lines

Updated handing of '__EUREKA' lump, the M_ParseEurekaLump() can now
return false (e.g. when the iwad cannot be found) -- hence need to be
able to cancel the OpenMap or OpenRecentMap command.

------------------------------------------------------------------------
r580 | ajapted | 2012-12-22 22:27:32 +1100 (Sat, 22 Dec 2012) | 2 lines

tweaked pack-source script

------------------------------------------------------------------------
r579 | ajapted | 2012-12-22 17:54:38 +1100 (Sat, 22 Dec 2012) | 2 lines

README.txt : tweaked a few things, updated keyboard controls.

------------------------------------------------------------------------
r578 | ajapted | 2012-12-22 17:43:49 +1100 (Sat, 22 Dec 2012) | 2 lines

INSTALL.txt : small update to setting up section.

------------------------------------------------------------------------
r577 | ajapted | 2012-12-22 17:39:54 +1100 (Sat, 22 Dec 2012) | 2 lines

svn ignorations

------------------------------------------------------------------------
r576 | ajapted | 2012-12-22 17:17:53 +1100 (Sat, 22 Dec 2012) | 2 lines

TODO updated.

------------------------------------------------------------------------
r575 | ajapted | 2012-12-22 17:15:01 +1100 (Sat, 22 Dec 2012) | 2 lines

INSTALL.txt : tweak

------------------------------------------------------------------------
r574 | ajapted | 2012-12-22 17:09:12 +1100 (Sat, 22 Dec 2012) | 2 lines

MacOSX: home_dir changed to '~/Library/Application Support/eureka-editor'

------------------------------------------------------------------------
r573 | ajapted | 2012-12-22 17:07:43 +1100 (Sat, 22 Dec 2012) | 2 lines

Version bumped to 0.88 -- ready for release.

------------------------------------------------------------------------
r572 | ajapted | 2012-12-17 23:14:55 +1100 (Mon, 17 Dec 2012) | 2 lines

WISHLIST update.

------------------------------------------------------------------------
r571 | ajapted | 2012-12-17 23:13:08 +1100 (Mon, 17 Dec 2012) | 2 lines

CHANGELOG: updated, e.g. group View menu stuff together.

------------------------------------------------------------------------
r570 | ajapted | 2012-12-17 23:05:22 +1100 (Mon, 17 Dec 2012) | 3 lines

Copy'n'paste: properly assign a new middle texture for linedefs which
lose a sidedef (because the sector no longer exists).

------------------------------------------------------------------------
r569 | ajapted | 2012-12-17 22:51:56 +1100 (Mon, 17 Dec 2012) | 3 lines

Copy'n'paste: when pasting, flip linedefs that would otherwise end up
with only a left side (no right side).

------------------------------------------------------------------------
r568 | ajapted | 2012-12-17 15:12:24 +1100 (Mon, 17 Dec 2012) | 2 lines

Error message tweak.

------------------------------------------------------------------------
r567 | ajapted | 2012-12-17 15:08:59 +1100 (Mon, 17 Dec 2012) | 2 lines

comment tweak

------------------------------------------------------------------------
r566 | ajapted | 2012-12-17 15:07:46 +1100 (Mon, 17 Dec 2012) | 3 lines

main: moved IWAD handling into a DetermineIWAD() function, and make sure
that the --iwad parameter not only exists but is a supported game.

------------------------------------------------------------------------
r565 | ajapted | 2012-12-17 14:46:59 +1100 (Mon, 17 Dec 2012) | 2 lines

Info bar: when map is changed, draw a '*' next to the map name.

------------------------------------------------------------------------
r564 | ajapted | 2012-12-17 14:22:00 +1100 (Mon, 17 Dec 2012) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r563 | ajapted | 2012-12-17 14:21:37 +1100 (Mon, 17 Dec 2012) | 2 lines

Support for --iwad parameter being a bare game name.

------------------------------------------------------------------------
r562 | ajapted | 2012-12-17 14:11:52 +1100 (Mon, 17 Dec 2012) | 2 lines

File utilities: added FilenameIsBare() function.

------------------------------------------------------------------------
r561 | ajapted | 2012-12-17 13:55:17 +1100 (Mon, 17 Dec 2012) | 4 lines

If the --iwad parameter is missing an extension, add ".wad".

Removed the obsolete DetermineIWAD() code.

------------------------------------------------------------------------
r560 | ajapted | 2012-12-17 12:18:24 +1100 (Mon, 17 Dec 2012) | 2 lines

INSTALL.txt : updated the 'Setting Up' section.

------------------------------------------------------------------------
r559 | ajapted | 2012-12-17 12:02:48 +1100 (Mon, 17 Dec 2012) | 2 lines

docco tweaks.

------------------------------------------------------------------------
r558 | ajapted | 2012-12-17 11:42:09 +1100 (Mon, 17 Dec 2012) | 2 lines

m_files.h needed a forward declaration -- patch courtesy Jeremy Henty.

------------------------------------------------------------------------
r557 | ajapted | 2012-12-17 11:35:36 +1100 (Mon, 17 Dec 2012) | 4 lines

HACX things:
1. added missing BRS1 (mummy) and BAR1 (nitro canister) things
2. added two categories: 'Gore' and 'Natural'

------------------------------------------------------------------------
r556 | ajapted | 2012-12-16 20:21:43 +1100 (Sun, 16 Dec 2012) | 2 lines

WISHLIST update (e.g. backup system)

------------------------------------------------------------------------
r555 | ajapted | 2012-12-16 20:14:40 +1100 (Sun, 16 Dec 2012) | 2 lines

CHANGELOG: update

------------------------------------------------------------------------
r554 | ajapted | 2012-12-16 20:12:21 +1100 (Sun, 16 Dec 2012) | 2 lines

HACX: added a lot of missing things.

------------------------------------------------------------------------
r553 | ajapted | 2012-12-16 19:18:06 +1100 (Sun, 16 Dec 2012) | 2 lines

HACX: fixed names of powerups (based on the pickup messages).

------------------------------------------------------------------------
r552 | ajapted | 2012-12-16 19:12:32 +1100 (Sun, 16 Dec 2012) | 2 lines

Grid: changed default step yet again ---> 64

------------------------------------------------------------------------
r551 | ajapted | 2012-12-16 16:17:39 +1100 (Sun, 16 Dec 2012) | 2 lines

HACX: changed the default textures.

------------------------------------------------------------------------
r550 | ajapted | 2012-12-16 16:06:25 +1100 (Sun, 16 Dec 2012) | 2 lines

HACX: added more things (decorations), and fixed a few bugs.

------------------------------------------------------------------------
r549 | ajapted | 2012-12-16 12:13:41 +1100 (Sun, 16 Dec 2012) | 2 lines

Game defs: began work on HACX definition file.

------------------------------------------------------------------------
r548 | ajapted | 2012-12-16 11:52:06 +1100 (Sun, 16 Dec 2012) | 2 lines

tweaked some warning messages

------------------------------------------------------------------------
r547 | ajapted | 2012-12-16 11:32:27 +1100 (Sun, 16 Dec 2012) | 2 lines

dead code removal

------------------------------------------------------------------------
r546 | ajapted | 2012-12-15 22:43:37 +1100 (Sat, 15 Dec 2012) | 2 lines

TODO and WISHLIST update.

------------------------------------------------------------------------
r545 | ajapted | 2012-12-15 22:42:14 +1100 (Sat, 15 Dec 2012) | 2 lines

Moved file 'New_Workflow.txt' out of docs/

------------------------------------------------------------------------
r544 | ajapted | 2012-12-15 22:26:03 +1100 (Sat, 15 Dec 2012) | 2 lines

Menu: disabled the unimplemented Preferences command.

------------------------------------------------------------------------
r543 | ajapted | 2012-12-15 21:17:28 +1100 (Sat, 15 Dec 2012) | 2 lines

Menu: disabled the unimplemented 'Find' and 'Find Next' commands.

------------------------------------------------------------------------
r542 | ajapted | 2012-12-15 20:16:08 +1100 (Sat, 15 Dec 2012) | 2 lines

CHANGELOG: added all the recent 'Manage Wads' work...

------------------------------------------------------------------------
r541 | ajapted | 2012-12-15 20:06:58 +1100 (Sat, 15 Dec 2012) | 2 lines

minor rename: CMD_PlayMap --> CMD_TestMap

------------------------------------------------------------------------
r540 | ajapted | 2012-12-15 20:03:23 +1100 (Sat, 15 Dec 2012) | 2 lines

Added doc about level checking: misc/Checks.txt

------------------------------------------------------------------------
r539 | ajapted | 2012-12-15 16:06:55 +1100 (Sat, 15 Dec 2012) | 2 lines

CMD_OpenMap / OpenRecentMap : handle the '__EUREKA' lump.

------------------------------------------------------------------------
r538 | ajapted | 2012-12-15 15:13:31 +1100 (Sat, 15 Dec 2012) | 2 lines

tweaks for '__EUREKA' lump handling...

------------------------------------------------------------------------
r537 | ajapted | 2012-12-15 15:11:56 +1100 (Sat, 15 Dec 2012) | 2 lines

Wad code: implemented Lump_c::GetLine() method.

------------------------------------------------------------------------
r536 | ajapted | 2012-12-15 14:57:04 +1100 (Sat, 15 Dec 2012) | 4 lines

The __EUREKA lump:
1. implemented parsing code
2. fixed missing 'lump->Finish()' in writing code

------------------------------------------------------------------------
r535 | ajapted | 2012-12-15 14:10:57 +1100 (Sat, 15 Dec 2012) | 3 lines

Worked on support for '__EUREKA' lump, which contains the project info
(the IWAD, port and resource wads).  So far, can only create the lump.

------------------------------------------------------------------------
r534 | ajapted | 2012-12-15 14:04:29 +1100 (Sat, 15 Dec 2012) | 2 lines

Wad code: added Lump_c::Printf() method.

------------------------------------------------------------------------
r533 | ajapted | 2012-12-15 13:29:53 +1100 (Sat, 15 Dec 2012) | 3 lines

Manage Wads dialog: implemented code for 'Find' button which repopulates
the iwad choice button with the known iwads.

------------------------------------------------------------------------
r532 | ajapted | 2012-12-14 21:47:11 +1100 (Fri, 14 Dec 2012) | 2 lines

Manage Wads dialog: more work on this delightful little f....

------------------------------------------------------------------------
r531 | ajapted | 2012-12-14 21:13:53 +1100 (Fri, 14 Dec 2012) | 2 lines

TODO / WISHLIST update.

------------------------------------------------------------------------
r530 | ajapted | 2012-12-14 21:07:33 +1100 (Fri, 14 Dec 2012) | 3 lines

Manage Wads dialog: tweaked startup message, using a red background and
yellow text which makes it very striking.

------------------------------------------------------------------------
r529 | ajapted | 2012-12-14 20:55:08 +1100 (Fri, 14 Dec 2012) | 3 lines

Worked on showing the Manage Wads dialog at startup when no iwads were
found.  Also, properly setup Iwad_name (etc) from that dialog.

------------------------------------------------------------------------
r528 | ajapted | 2012-12-14 20:37:49 +1100 (Fri, 14 Dec 2012) | 2 lines

Utilities: allow passing NULL to StringDup() -- just return NULL.

------------------------------------------------------------------------
r527 | ajapted | 2012-12-14 20:16:57 +1100 (Fri, 14 Dec 2012) | 2 lines

When Iwad_name is unset, try to pick a sensible default.

------------------------------------------------------------------------
r526 | ajapted | 2012-12-14 20:15:27 +1100 (Fri, 14 Dec 2012) | 3 lines

Implemented M_PickDefaultIWAD() -- guesses either DOOM or DOOM2 based on
level names (if any), and as last resource picks any known iwad.

------------------------------------------------------------------------
r525 | ajapted | 2012-12-14 19:50:38 +1100 (Fri, 14 Dec 2012) | 4 lines

Worked on getting the startup sequence in main() sorted out, e.g. we now
load the PWAD (but not the map) before other stuff so that the __EUREKA
lump can be handled appropriately.

------------------------------------------------------------------------
r524 | ajapted | 2012-12-14 19:24:53 +1100 (Fri, 14 Dec 2012) | 2 lines

Added EUREKA_LUMP define, bumped version.

------------------------------------------------------------------------
r523 | ajapted | 2012-12-14 17:18:06 +1100 (Fri, 14 Dec 2012) | 4 lines

Removed the unused 'remind_to_build_nodes' stuff, I think for Eureka
such a dialog could be really annoying -- for Yadex it was OK since
the message was merely printed to the terminal.

------------------------------------------------------------------------
r522 | ajapted | 2012-12-14 15:25:58 +1100 (Fri, 14 Dec 2012) | 2 lines

fixed bug in SearchDirForIWAD (need ".wad" extenstion)

------------------------------------------------------------------------
r521 | ajapted | 2012-12-14 13:45:18 +1100 (Fri, 14 Dec 2012) | 4 lines

Worked on new M_LookForIWADs() code which looks for each game iwad in
various places and updates the known_iwads list when found.  This
involves moving some code (e.g. SearchDirForIWAD) into m_files.cc.

------------------------------------------------------------------------
r520 | ajapted | 2012-12-14 13:40:10 +1100 (Fri, 14 Dec 2012) | 2 lines

Fixed FatalError() messages which lacked a trailing newline.

------------------------------------------------------------------------
r519 | ajapted | 2012-12-14 13:18:15 +1100 (Fri, 14 Dec 2012) | 2 lines

Ensure recent filenames and known iwad filenames are absolute.

------------------------------------------------------------------------
r518 | ajapted | 2012-12-14 13:04:23 +1100 (Fri, 14 Dec 2012) | 2 lines

debugging fix.

------------------------------------------------------------------------
r517 | ajapted | 2012-12-14 13:00:07 +1100 (Fri, 14 Dec 2012) | 2 lines

When loading recent files and known iwads, check the file still exists.

------------------------------------------------------------------------
r516 | ajapted | 2012-12-14 12:57:08 +1100 (Fri, 14 Dec 2012) | 2 lines

Implemented parsing logic for "misc.cfg" -- recent wads and known iwads.

------------------------------------------------------------------------
r515 | ajapted | 2012-12-14 12:04:45 +1100 (Fri, 14 Dec 2012) | 3 lines

Worked on saving known iwads in the 'misc.cfg' file, and changed the
format of the recent files.  Loading is not done yet...

------------------------------------------------------------------------
r514 | ajapted | 2012-12-14 10:52:57 +1100 (Fri, 14 Dec 2012) | 4 lines

Project Setup dialog:
1. properly setup the 'Game IWAD' choice, using the known iwads list
2. fixed window close button (use close_callback)

------------------------------------------------------------------------
r513 | ajapted | 2012-12-14 10:46:29 +1100 (Fri, 14 Dec 2012) | 3 lines

Known iwads: implemented function to return '|'-separated list of game
names, namely M_KnownIWADsForMenu().

------------------------------------------------------------------------
r512 | ajapted | 2012-12-13 22:47:49 +1100 (Thu, 13 Dec 2012) | 2 lines

Known iwads: implemented M_AddKnownIWAD() and M_QueryrKnownIWAD() functions.

------------------------------------------------------------------------
r511 | ajapted | 2012-12-13 20:28:57 +1100 (Thu, 13 Dec 2012) | 2 lines

Bound '\' key to cycle categories in the browser.

------------------------------------------------------------------------
r510 | ajapted | 2012-12-13 20:09:03 +1100 (Thu, 13 Dec 2012) | 2 lines

Renamed recent.cfg --> misc.cfg  [it will contain other stuff too]

------------------------------------------------------------------------
r509 | ajapted | 2012-12-13 20:00:01 +1100 (Thu, 13 Dec 2012) | 5 lines

Config handling:
1. have a 'v' flag for real variables (only those are written out)
2. hence no need for 'h' flag -- removed
3. tweaked the --help descriptions (esp. for merge)

------------------------------------------------------------------------
r508 | ajapted | 2012-12-13 19:46:51 +1100 (Thu, 13 Dec 2012) | 2 lines

Config handling: implemented M_WriteConfigFile().

------------------------------------------------------------------------
r507 | ajapted | 2012-12-13 19:21:53 +1100 (Thu, 13 Dec 2012) | 3 lines

Config handling: minor function rename, e.g. M_ParseConfigFile() and
M_ParseCommandLine(), and rejiggage of how they are called.

------------------------------------------------------------------------
r506 | ajapted | 2012-12-13 16:49:51 +1100 (Thu, 13 Dec 2012) | 2 lines

part (b) of renamed code files: m_recent --> m_files

------------------------------------------------------------------------
r505 | ajapted | 2012-12-13 15:53:02 +1100 (Thu, 13 Dec 2012) | 2 lines

Renamed code file: m_recent.cc/h --> m_files.cc/h

------------------------------------------------------------------------
r504 | ajapted | 2012-12-13 15:42:42 +1100 (Thu, 13 Dec 2012) | 2 lines

Game defs: implemented M_CollectKnownDefs() function.

------------------------------------------------------------------------
r503 | ajapted | 2012-12-13 15:22:18 +1100 (Thu, 13 Dec 2012) | 3 lines

M_CollectDefsForMenu: pass in an existing name, and pass out its index
(if found).

------------------------------------------------------------------------
r502 | ajapted | 2012-12-13 15:20:35 +1100 (Thu, 13 Dec 2012) | 3 lines

Renamed the File -> 'Project Setup' command to 'Manage Wads'
(as a test, since I haven't decided which one is more intuitive).

------------------------------------------------------------------------
r501 | ajapted | 2012-12-13 00:01:39 +1100 (Thu, 13 Dec 2012) | 3 lines

Partial work on logic to get a list of definitions (e.g. list of ports)
by scanning the installed UGH files.

------------------------------------------------------------------------
r500 | ajapted | 2012-12-11 22:29:45 +1100 (Tue, 11 Dec 2012) | 2 lines

TODO update.

------------------------------------------------------------------------
r499 | ajapted | 2012-12-11 22:09:54 +1100 (Tue, 11 Dec 2012) | 3 lines

Project Setup dialog: got the resource buttons ('X' and 'Load') working
and got the IWAD 'Find' button mostly working.

------------------------------------------------------------------------
r498 | ajapted | 2012-12-11 21:40:52 +1100 (Tue, 11 Dec 2012) | 3 lines

Moved texture loading calls into Main_LoadResources(), making sure that
all previous textures are removed and freed.

------------------------------------------------------------------------
r497 | ajapted | 2012-12-11 21:36:55 +1100 (Tue, 11 Dec 2012) | 2 lines

Show a '*' in the window title bar when the map has been modified.

------------------------------------------------------------------------
r496 | ajapted | 2012-12-11 21:34:46 +1100 (Tue, 11 Dec 2012) | 2 lines

Code tidying: removed some dead code (e.g. DrawScreenText).

------------------------------------------------------------------------
r495 | ajapted | 2012-12-11 14:37:58 +1100 (Tue, 11 Dec 2012) | 5 lines

Implemented ability to load "mod" definition files, which correspond to a
loaded resource wad.

Also fixed Main_LoadResources() to clear all definitions.

------------------------------------------------------------------------
r494 | ajapted | 2012-12-11 14:25:15 +1100 (Tue, 11 Dec 2012) | 3 lines

Factored IWAD/resource loading code into Main_LoadResources() function.
This is going to allow dynamically changing the iwad/port/resources.

------------------------------------------------------------------------
r493 | ajapted | 2012-12-11 14:11:22 +1100 (Tue, 11 Dec 2012) | 5 lines

Code tidying:
1. renamed global var: base_wad --> game_wad
2. renamed Iwad --> Iwad_name, ensure it stays valid
3. renamed Pwad --> Pwad_name, keep it valid (when changing edit_wad)

------------------------------------------------------------------------
r492 | ajapted | 2012-12-11 13:54:56 +1100 (Tue, 11 Dec 2012) | 2 lines

Project Setup dialog: bit more work e.g. Populate method...

------------------------------------------------------------------------
r491 | ajapted | 2012-12-11 11:57:22 +1100 (Tue, 11 Dec 2012) | 5 lines

File menu update:
1. added 'Project Setup' command
2. CTRL-R is now the shortcut key for 'Recent Files' command
3. tweaked the keyboard navigation

------------------------------------------------------------------------
r490 | ajapted | 2012-12-11 11:55:04 +1100 (Tue, 11 Dec 2012) | 2 lines

Project Setup: bit more work, wrote skeletal Main_ProjectSetup() code.

------------------------------------------------------------------------
r489 | ajapted | 2012-12-11 11:50:22 +1100 (Tue, 11 Dec 2012) | 3 lines

Renamed UI_ProjectInfo --> UI_ProjectSetup, added skeletal callback
functions, fixed window title and resource numbering.

------------------------------------------------------------------------
r488 | ajapted | 2012-12-11 11:33:41 +1100 (Tue, 11 Dec 2012) | 1 line

tweak
------------------------------------------------------------------------
r487 | ajapted | 2012-12-11 11:26:04 +1100 (Tue, 11 Dec 2012) | 2 lines

manage2.fl : various work

------------------------------------------------------------------------
r486 | ajapted | 2012-12-11 10:57:33 +1100 (Tue, 11 Dec 2012) | 4 lines

Began work on a 'Project Info' dialog, where the user can select / change
the current IWAD and port (engine) and resource wads.  So far this is
only the widget layout (imported from fluid output).

------------------------------------------------------------------------
r485 | ajapted | 2012-12-10 22:02:57 +1100 (Mon, 10 Dec 2012) | 2 lines

TODO update.

------------------------------------------------------------------------
r484 | ajapted | 2012-12-10 21:23:14 +1100 (Mon, 10 Dec 2012) | 10 lines

Open Map dialog: we no longer directly change 'edit_wad' in the dialog
itself, instead we keep a local copy of the Wad_file object, and
communicate the newly-openness of it via 'is_new_pwad' Run() param.

Updated the CMD_OpenMap() logic accordingly, removing the edit_wad
from master dir when the returned wad is different, and establishing
the 'new_pwad' as the edit_wad if that's what the user selected.

So I think the logic is 100% correct now, but will review it soon...

------------------------------------------------------------------------
r483 | ajapted | 2012-12-10 20:55:31 +1100 (Mon, 10 Dec 2012) | 2 lines

Disconnect Sectors: fixed texture on the separated linedefs.

------------------------------------------------------------------------
r482 | ajapted | 2012-12-10 15:25:43 +1100 (Mon, 10 Dec 2012) | 2 lines

Disconnect Sectors: improved calculation of move vector.

------------------------------------------------------------------------
r481 | ajapted | 2012-12-10 15:16:44 +1100 (Mon, 10 Dec 2012) | 3 lines

Disconnect Sectors: got the logic for moving the vertices in a good
direction working, via new DETSEC_CalcMoveVector() function.

------------------------------------------------------------------------
r480 | ajapted | 2012-12-10 14:37:17 +1100 (Mon, 10 Dec 2012) | 2 lines

Merge linedefs: fixed handling of sidedef textures.

------------------------------------------------------------------------
r479 | ajapted | 2012-12-10 11:29:58 +1100 (Mon, 10 Dec 2012) | 3 lines

Open Map dialog: re-check map name after changing the "Look in" wad or
after loading a new pwad.  Fixed some bugs.

------------------------------------------------------------------------
r478 | ajapted | 2012-12-10 11:19:21 +1100 (Mon, 10 Dec 2012) | 4 lines

Open Map dialog: implemented logic to validate the map name, including
checking that it exists in the selected wad, and only enable the "OK"
button when valid.

------------------------------------------------------------------------
r477 | ajapted | 2012-12-09 22:34:51 +1100 (Sun, 09 Dec 2012) | 2 lines

TODO update.

------------------------------------------------------------------------
r476 | ajapted | 2012-12-09 22:29:34 +1100 (Sun, 09 Dec 2012) | 2 lines

Open Map dialog: prevent loading a PWAD without any levels.

------------------------------------------------------------------------
r475 | ajapted | 2012-12-09 22:25:51 +1100 (Sun, 09 Dec 2012) | 2 lines

CMD_OpenMap: fixed the new 'Replacer' logic.

------------------------------------------------------------------------
r474 | ajapted | 2012-12-09 22:10:30 +1100 (Sun, 09 Dec 2012) | 5 lines

Open Map dialog:
1. use it properly in CMD_OpenMap() -- remove a lot of old logic
2. return the selected wad and map from the Run() method
3. support clicking on a map button

------------------------------------------------------------------------
r473 | ajapted | 2012-12-09 21:47:46 +1100 (Sun, 09 Dec 2012) | 6 lines

Open Map dialog: implemented the 'Load' button, which pops up a file
requester to get a WAD file and can load that as the 'edit_wad' (code
portions were copy'n'pasted from CMD_OpenMap).

We also setup the currently edited pwad widget.

------------------------------------------------------------------------
r472 | ajapted | 2012-12-09 21:24:05 +1100 (Sun, 09 Dec 2012) | 5 lines

Choose Map dialog: implemented checking the map name as the user types it,
when invalid it is drawn in RED and the OK button is deactivated.

Also removed some gunk.

------------------------------------------------------------------------
r471 | ajapted | 2012-12-09 19:54:33 +1100 (Sun, 09 Dec 2012) | 7 lines

Preferences dialog: more work in fluid:
1. fixed the radio and check buttons so the size covers the label
2. added C++ variable names to each widget
3. use BORDER_BOX for color buttons (so the plastic scheme doesn't show
   the wrong color)
4. miscellaneous tweaking.

------------------------------------------------------------------------
r470 | ajapted | 2012-12-09 18:51:16 +1100 (Sun, 09 Dec 2012) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r469 | ajapted | 2012-12-09 18:41:41 +1100 (Sun, 09 Dec 2012) | 3 lines

Open Map dialog: improved layout of map buttons, make buttons bigger
when there are less columns, and use less rows sometimes.

------------------------------------------------------------------------
r468 | ajapted | 2012-12-09 17:12:35 +1100 (Sun, 09 Dec 2012) | 3 lines

Open Map dialog: wrote the Populate() method which creates a button for
each found map in the selected "look for" place.

------------------------------------------------------------------------
r467 | ajapted | 2012-12-09 16:40:21 +1100 (Sun, 09 Dec 2012) | 2 lines

Open Map dialog: made more compact (vertically) + a few tweaks.

------------------------------------------------------------------------
r466 | ajapted | 2012-12-09 16:08:59 +1100 (Sun, 09 Dec 2012) | 3 lines

Open Map dialog: a few fixes, especially a bad labelfont() value which
caused a crash.

------------------------------------------------------------------------
r465 | ajapted | 2012-12-09 15:53:27 +1100 (Sun, 09 Dec 2012) | 2 lines

Partial work on new 'Open Map' dialog, main skeleton and widget layout.

------------------------------------------------------------------------
r464 | ajapted | 2012-12-09 15:31:35 +1100 (Sun, 09 Dec 2012) | 2 lines

Use the new map choosing dialog with File/New command.

------------------------------------------------------------------------
r463 | ajapted | 2012-12-09 14:37:39 +1100 (Sun, 09 Dec 2012) | 5 lines

Choose Map dialog:
1. changed the layout so that MAP01/02/03 (etc) goes down columns
   instead of across rows
2. got the buttons working (implemented the callback)

------------------------------------------------------------------------
r462 | ajapted | 2012-12-09 14:23:05 +1100 (Sun, 09 Dec 2012) | 3 lines

Choose Map dialog: code to populate with map-name buttons.  It can also
test whether the map already exists, changes the color of the button.

------------------------------------------------------------------------
r461 | ajapted | 2012-12-09 13:27:38 +1100 (Sun, 09 Dec 2012) | 4 lines

Export map: use the new 'Choose Map' dialog.  We also open/create the
destination wad file first, so that the dialog will be able to show
which maps are used and which maps are free (planned feature).

------------------------------------------------------------------------
r460 | ajapted | 2012-12-09 13:24:17 +1100 (Sun, 09 Dec 2012) | 2 lines

UI_ChooseMap: validate the map name, and fixed several issues.

------------------------------------------------------------------------
r459 | ajapted | 2012-12-09 12:52:16 +1100 (Sun, 09 Dec 2012) | 2 lines

Worked on 'Choose Map' dialog, basic widgets are in place...

------------------------------------------------------------------------
r458 | ajapted | 2012-12-09 12:23:54 +1100 (Sun, 09 Dec 2012) | 3 lines

Added new code files 'ui_file.cc/h', which will contain some File-related
dialogs.  Currently only has the beginnings of a UI_ChooseMap dialog.

------------------------------------------------------------------------
r457 | ajapted | 2012-12-08 22:14:27 +1100 (Sat, 08 Dec 2012) | 3 lines

Misc: commit the in-progress fluid versions of Preference dialog and
Project Info (wad manager) dialog.

------------------------------------------------------------------------
r456 | ajapted | 2012-12-08 21:26:14 +1100 (Sat, 08 Dec 2012) | 2 lines

implemented 'View / Whole Selection' menu command.

------------------------------------------------------------------------
r455 | ajapted | 2012-12-08 20:38:21 +1100 (Sat, 08 Dec 2012) | 4 lines

Preferences: added bare-bones code files: ui_prefs.cc/h

(The actual dialog is being worked on in fluid...)

------------------------------------------------------------------------
r454 | ajapted | 2012-12-08 18:30:04 +1100 (Sat, 08 Dec 2012) | 2 lines

Removed obselete config vars: 'sprite_scale' and 'copy_linedef_reuse_sidedef'.

------------------------------------------------------------------------
r453 | ajapted | 2012-12-08 15:58:07 +1100 (Sat, 08 Dec 2012) | 2 lines

CHANGELOG: update, rejigged the order of some items.

------------------------------------------------------------------------
r452 | ajapted | 2012-12-08 15:56:09 +1100 (Sat, 08 Dec 2012) | 3 lines

Fixed File/Open and OpenRecent to not zoom out when there is persisted
state for that map.

------------------------------------------------------------------------
r451 | ajapted | 2012-12-08 15:49:48 +1100 (Sat, 08 Dec 2012) | 2 lines

Recent files: actually load the file/map picked in the GUI.

------------------------------------------------------------------------
r450 | ajapted | 2012-12-08 15:39:10 +1100 (Sat, 08 Dec 2012) | 3 lines

Recent files: implemented callback for the buttons, we use the user data
to hold the index number (needed a ugly hack to allow that).

------------------------------------------------------------------------
r449 | ajapted | 2012-12-08 15:25:16 +1100 (Sat, 08 Dec 2012) | 4 lines

Recent files: partial work on CMD_OpenRecentMap() code which is
responsible for actually opening the selected map.  Also updated
M_RecentDialog() to pass back the chosen filename and map.

------------------------------------------------------------------------
r448 | ajapted | 2012-12-08 15:08:36 +1100 (Sat, 08 Dec 2012) | 2 lines

Recent files: layout tweaks.

------------------------------------------------------------------------
r447 | ajapted | 2012-12-08 15:04:05 +1100 (Sat, 08 Dec 2012) | 8 lines

Recent files:
1. reduced MAX_RECENT from 10 to 8
2. the find() method can also match a map name
3. added Format() method to format a file/map for a gui button
4. made the dialog window height depend on # of recent files
5. create buttons for each file/map
6. show a different message when list is empty

------------------------------------------------------------------------
r446 | ajapted | 2012-12-08 14:32:10 +1100 (Sat, 08 Dec 2012) | 2 lines

Recent files: implemented the cancel button (close_callback).

------------------------------------------------------------------------
r445 | ajapted | 2012-12-08 14:00:45 +1100 (Sat, 08 Dec 2012) | 3 lines

Recent files: began work on dialog to show the files and let the user
select one.  So far this is just creates the window, nothing works yet.

------------------------------------------------------------------------
r444 | ajapted | 2012-12-08 13:44:37 +1100 (Sat, 08 Dec 2012) | 3 lines

Made linedef-path and contig-sector select commands consistent with
normal selection -- clear previous selection after a move.

------------------------------------------------------------------------
r443 | ajapted | 2012-12-08 13:37:30 +1100 (Sat, 08 Dec 2012) | 2 lines

Merge linedefs tweak.

------------------------------------------------------------------------
r442 | ajapted | 2012-12-08 12:59:28 +1100 (Sat, 08 Dec 2012) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r441 | ajapted | 2012-12-08 12:59:03 +1100 (Sat, 08 Dec 2012) | 2 lines

Linedef mode: Implemented 'm' merge command for two one-sided lines.

------------------------------------------------------------------------
r440 | ajapted | 2012-12-08 12:38:35 +1100 (Sat, 08 Dec 2012) | 4 lines

Added a version of the Beep() function which takes a message, as
eventually it would be good to show a message somewhere (like a status
bar).

------------------------------------------------------------------------
r439 | ajapted | 2012-12-08 12:31:45 +1100 (Sat, 08 Dec 2012) | 2 lines

UI: added 'Recent file' command to File menu (does not work yet).

------------------------------------------------------------------------
r438 | ajapted | 2012-12-08 11:47:48 +1100 (Sat, 08 Dec 2012) | 2 lines

TODO update.

------------------------------------------------------------------------
r437 | ajapted | 2012-12-08 11:46:37 +1100 (Sat, 08 Dec 2012) | 2 lines

Disconnect sectors: fixed another issue.

------------------------------------------------------------------------
r436 | ajapted | 2012-12-08 11:33:07 +1100 (Sat, 08 Dec 2012) | 5 lines

Disconnect sectors:
1. got the sidedef handling in DETSEC_AddNewLine() working properly
2. fixed a bug where we visited newly added linedefs
3. few other fixes to the logic

------------------------------------------------------------------------
r435 | ajapted | 2012-12-08 11:04:28 +1100 (Sat, 08 Dec 2012) | 2 lines

Disconnect sectors: worked on line separation logic...

------------------------------------------------------------------------
r434 | ajapted | 2012-12-08 10:47:02 +1100 (Sat, 08 Dec 2012) | 2 lines

Worked on a 'd' disconnect command for Sectors...

------------------------------------------------------------------------
r433 | ajapted | 2012-12-07 22:49:02 +1100 (Fri, 07 Dec 2012) | 2 lines

TODO update.

------------------------------------------------------------------------
r432 | ajapted | 2012-12-07 22:47:40 +1100 (Fri, 07 Dec 2012) | 2 lines

UI: about box tweak.

------------------------------------------------------------------------
r431 | ajapted | 2012-12-07 22:13:27 +1100 (Fri, 07 Dec 2012) | 4 lines

Recent files:
1. fixed parse code to remove trailing CR/LF
2. call M_LoadRecent() and M_AddRecent() where needed

------------------------------------------------------------------------
r430 | ajapted | 2012-12-07 21:31:17 +1100 (Fri, 07 Dec 2012) | 2 lines

Recent files: implemented M_LoadRecent() and M_SaveRecent().

------------------------------------------------------------------------
r429 | ajapted | 2012-12-07 21:24:31 +1100 (Fri, 07 Dec 2012) | 2 lines

Recent files: implemented ParseFile() method and fixed a few bugs.

------------------------------------------------------------------------
r428 | ajapted | 2012-12-07 21:13:00 +1100 (Fri, 07 Dec 2012) | 5 lines

Recent files:
1. implemented insert() method, with logic to find() an existing file
   with the same base-name and erase() it.
2. implemented the WriteFile() method.

------------------------------------------------------------------------
r427 | ajapted | 2012-12-07 21:00:47 +1100 (Fri, 07 Dec 2012) | 3 lines

Began work on code to remember recently edited files, with a goal to
show a dialog allowing users to pick one to open.

------------------------------------------------------------------------
r426 | ajapted | 2012-12-07 20:29:10 +1100 (Fri, 07 Dec 2012) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r425 | ajapted | 2012-12-07 20:24:10 +1100 (Fri, 07 Dec 2012) | 2 lines

View menu: added 'Toggle Grid Type' item.

------------------------------------------------------------------------
r424 | ajapted | 2012-12-07 19:32:37 +1100 (Fri, 07 Dec 2012) | 7 lines

Show object nums: use a better algorithm for sectors, keep track of
which sectors we have "seen" and draw the number on the first visited
linedef.

Also changed the linedef position to be directly on the line (which
is generally uglier, but less confusing).

------------------------------------------------------------------------
r423 | ajapted | 2012-12-07 18:57:11 +1100 (Fri, 07 Dec 2012) | 6 lines

Show object nums: reworked drawing for Linedefs, done in a separate pass
(like things etc), and really honed the logic determining how far away
from the line's middle to draw the number.

Added 'center' parameter to DrawObjNum() method.

------------------------------------------------------------------------
r422 | ajapted | 2012-12-07 17:41:45 +1100 (Fri, 07 Dec 2012) | 2 lines

Show object nums: persist the setting.

------------------------------------------------------------------------
r421 | ajapted | 2012-12-07 16:11:43 +1100 (Fri, 07 Dec 2012) | 2 lines

Show object numbers: added to VIEW menu, and changed key to 'J'.

------------------------------------------------------------------------
r420 | ajapted | 2012-12-07 15:51:39 +1100 (Fri, 07 Dec 2012) | 8 lines

Worked to improve object numbers on canvas:
1. moved thing code into DrawThings()
2. moved sector code into new DrawSectorNums() method
3. OBJ_NUM_COL replaces the THING_NO, SECTOR_NO (etc) defines
4. DrawObjNum() no longer uses obsolete DrawScreenText() function
5. font size depends for the current scale
6. position the number at top/right of things and vertices

------------------------------------------------------------------------
r419 | ajapted | 2012-12-07 15:01:53 +1100 (Fri, 07 Dec 2012) | 2 lines

Key propagation: fixed the 3D view eating all keys when active.

------------------------------------------------------------------------
r418 | ajapted | 2012-12-07 13:45:40 +1100 (Fri, 07 Dec 2012) | 6 lines

Implemented a decent GoToObject() function, via new GoToSelection()
function which can zoom out when the objects are too large to fit
on-screen, or zoom in when they are very small.

New code is in e_path.cc/h (no longer in objects.cc/h)

------------------------------------------------------------------------
r417 | ajapted | 2012-12-07 12:43:05 +1100 (Fri, 07 Dec 2012) | 2 lines

Unbind 'n' and 'p' keys from the next obj / prev obj mis-feature.

------------------------------------------------------------------------
r416 | ajapted | 2012-12-07 11:09:57 +1100 (Fri, 07 Dec 2012) | 5 lines

Menu code stuff:
1. replace fl_beep() with Beep()
2. reworked find commands in View menu, removed 'next / prev object'
3. experimental support for Fullscreen mode

------------------------------------------------------------------------
r415 | ajapted | 2012-12-07 11:03:14 +1100 (Fri, 07 Dec 2012) | 3 lines

UI_Window: added ToggleFullscreen() method, though it doesn't work too
well (here anyway) due to FLTK's implementation.

------------------------------------------------------------------------
r414 | ajapted | 2012-12-06 23:57:21 +1100 (Thu, 06 Dec 2012) | 2 lines

TODO and WISHLIST updates.

------------------------------------------------------------------------
r413 | ajapted | 2012-12-06 23:54:16 +1100 (Thu, 06 Dec 2012) | 2 lines

Implemented 'm' merge command for vertex mode.

------------------------------------------------------------------------
r412 | ajapted | 2012-12-06 23:20:03 +1100 (Thu, 06 Dec 2012) | 2 lines

Removed dead code : set_colour(), push_colour(), pop_colour().

------------------------------------------------------------------------
r411 | ajapted | 2012-12-06 23:15:50 +1100 (Thu, 06 Dec 2012) | 4 lines

Merged stuff from s_misc.cc/h --> e_sector.cc/h (some disabled code
which may be needed later).  Hence deleted s_misc.cc/h and removed
from the Makefile.

------------------------------------------------------------------------
r410 | ajapted | 2012-12-06 23:08:49 +1100 (Thu, 06 Dec 2012) | 2 lines

Removed dead code : find_linedef_for_area().

------------------------------------------------------------------------
r409 | ajapted | 2012-12-06 23:03:54 +1100 (Thu, 06 Dec 2012) | 3 lines

Removed dead code : old non-working SplitSector() and
SplitLineDefsAndSector() functions.

------------------------------------------------------------------------
r408 | ajapted | 2012-12-06 22:57:39 +1100 (Thu, 06 Dec 2012) | 2 lines

Config: support for color variables (via new OPT_COLOR type).

------------------------------------------------------------------------
r407 | ajapted | 2012-12-06 22:56:14 +1100 (Thu, 06 Dec 2012) | 3 lines

Added ParseColor() function to im_color code, originally in m_game.cc
but updated to support both 3- and 6-digit formats (RGB and RRGGBB).

------------------------------------------------------------------------
r406 | ajapted | 2012-12-06 16:37:21 +1100 (Thu, 06 Dec 2012) | 3 lines

Added 'digits_set_zoom' config var which enabled the Yadex behavior
where the digit keys set the zoom factor.

------------------------------------------------------------------------
r405 | ajapted | 2012-12-06 16:11:34 +1100 (Thu, 06 Dec 2012) | 2 lines

tweaked handling of BackSpace key.

------------------------------------------------------------------------
r404 | ajapted | 2012-12-06 16:10:50 +1100 (Thu, 06 Dec 2012) | 2 lines

Removed sector_slice() stuff : was unused and non-working.

------------------------------------------------------------------------
r403 | ajapted | 2012-12-06 15:52:22 +1100 (Thu, 06 Dec 2012) | 2 lines

Key propagation: moved more checks into mode-specific functions.

------------------------------------------------------------------------
r402 | ajapted | 2012-12-06 15:39:22 +1100 (Thu, 06 Dec 2012) | 3 lines

Key propagation: have a handler function for each editing mode, i.e.
Thing_Key(), Sector_Key(), etc...

------------------------------------------------------------------------
r401 | ajapted | 2012-12-06 15:22:50 +1100 (Thu, 06 Dec 2012) | 2 lines

Config: removed OPT_STRINGBUF8 as a config type (not needed).

------------------------------------------------------------------------
r400 | ajapted | 2012-12-06 14:34:27 +1100 (Thu, 06 Dec 2012) | 5 lines

Key propagation:
1. the Global_Key() handler has highest priority
2. moved handling of TAB and browser open keys to Global_Key()
3. new function: CMD_Toggle3Dview()

------------------------------------------------------------------------
r399 | ajapted | 2012-12-06 11:11:08 +1100 (Thu, 06 Dec 2012) | 2 lines

Partial work on new keyboard propagation logic....

------------------------------------------------------------------------
r398 | ajapted | 2012-12-06 10:34:09 +1100 (Thu, 06 Dec 2012) | 2 lines

CHANGELOG updated.

------------------------------------------------------------------------
r397 | ajapted | 2012-12-06 10:32:08 +1100 (Thu, 06 Dec 2012) | 2 lines

UI / Default props: persist the hidden/shown state.

------------------------------------------------------------------------
r396 | ajapted | 2012-12-06 10:18:11 +1100 (Thu, 06 Dec 2012) | 3 lines

UI / Default props: added a button which hides/shows the properties
(since they can be distracting during normal editing).

------------------------------------------------------------------------
r395 | ajapted | 2012-12-05 23:11:45 +1100 (Wed, 05 Dec 2012) | 2 lines

minor commenting...

------------------------------------------------------------------------
r394 | ajapted | 2012-12-05 23:10:08 +1100 (Wed, 05 Dec 2012) | 3 lines

Fixed Props_LoadValues() being called too early (before main_win was
created) and hence not working.

------------------------------------------------------------------------
r393 | ajapted | 2012-12-05 23:09:03 +1100 (Wed, 05 Dec 2012) | 2 lines

Game defs / DOOM: changed default_thing --> 2014 (health potion)

------------------------------------------------------------------------
r392 | ajapted | 2012-12-05 23:03:53 +1100 (Wed, 05 Dec 2012) | 2 lines

UI / Default props: ability to set wall textures via the browser.

------------------------------------------------------------------------
r391 | ajapted | 2012-12-05 22:50:22 +1100 (Wed, 05 Dec 2012) | 2 lines

UI / Default props: ability to set sector flats via the browser.

------------------------------------------------------------------------
r390 | ajapted | 2012-12-05 22:44:37 +1100 (Wed, 05 Dec 2012) | 2 lines

minor rename, UI_Sector::SetTexture() --> SetFlat()

------------------------------------------------------------------------
r389 | ajapted | 2012-12-05 22:40:54 +1100 (Wed, 05 Dec 2012) | 2 lines

UI / Default props: ability to set default thing via the browser.

------------------------------------------------------------------------
r388 | ajapted | 2012-12-05 22:33:29 +1100 (Wed, 05 Dec 2012) | 2 lines

Browser: got existing stuff working again via the new system.

------------------------------------------------------------------------
r387 | ajapted | 2012-12-05 22:23:43 +1100 (Wed, 05 Dec 2012) | 4 lines

Browser: partial work on passing all browser selections through a
new 'BrowsedItem()' method of UI_MainWin class.  This method will
decide what to do with the selected item.

------------------------------------------------------------------------
r386 | ajapted | 2012-12-05 21:35:27 +1100 (Wed, 05 Dec 2012) | 4 lines

UI / Default props: allow pics to be selected, opening the browser in
the right mode.  Unselect the pics when browser is closed.  Don't allow
both textures and flats to be selected.

------------------------------------------------------------------------
r385 | ajapted | 2012-12-05 21:16:01 +1100 (Wed, 05 Dec 2012) | 3 lines

UI / Default Props: got the texture and flat input fields working, and
make sure the name is normalized (uppercased and length limited).

------------------------------------------------------------------------
r384 | ajapted | 2012-12-05 21:02:31 +1100 (Wed, 05 Dec 2012) | 4 lines

UI / Default Props:
1. got the floor_h / ceil_h / light input fields working
2. fixed bug parsing the "thing" value from a user state file

------------------------------------------------------------------------
r383 | ajapted | 2012-12-05 20:50:48 +1100 (Wed, 05 Dec 2012) | 2 lines

UI / Default Props: implemented callbacks for height buttons.

------------------------------------------------------------------------
r382 | ajapted | 2012-12-05 20:05:55 +1100 (Wed, 05 Dec 2012) | 2 lines

UI / Default Props: added Props_LoadValues() function, call it where needed.

------------------------------------------------------------------------
r381 | ajapted | 2012-12-05 20:04:53 +1100 (Wed, 05 Dec 2012) | 2 lines

Browser: for textual modes, pack them a bit tighter vertically (show more).

------------------------------------------------------------------------
r380 | ajapted | 2012-12-05 19:50:54 +1100 (Wed, 05 Dec 2012) | 3 lines

UI / Default Props: implemented LoadValues() method to setup each widget
with the current values.

------------------------------------------------------------------------
r379 | ajapted | 2012-12-05 19:38:05 +1100 (Wed, 05 Dec 2012) | 3 lines

UI / Default Props: implemented Props_ParseUser(), and changed the write
code to use a space after "default".

------------------------------------------------------------------------
r378 | ajapted | 2012-12-05 19:29:09 +1100 (Wed, 05 Dec 2012) | 2 lines

Utils: added StringTidy() function.

------------------------------------------------------------------------
r377 | ajapted | 2012-12-05 19:21:00 +1100 (Wed, 05 Dec 2012) | 2 lines

UI / Default Props: implemented Props_WriteUser().

------------------------------------------------------------------------
r376 | ajapted | 2012-12-05 19:19:52 +1100 (Wed, 05 Dec 2012) | 2 lines

New util function: StringRemoveCRLF().

------------------------------------------------------------------------
r375 | ajapted | 2012-12-05 17:19:24 +1100 (Wed, 05 Dec 2012) | 2 lines

Config: remove trailing LF (and/or CR) from .dat lines, for better warning messages.

------------------------------------------------------------------------
r374 | ajapted | 2012-12-05 17:12:33 +1100 (Wed, 05 Dec 2012) | 2 lines

minor renaming.

------------------------------------------------------------------------
r373 | ajapted | 2012-12-05 15:29:09 +1100 (Wed, 05 Dec 2012) | 5 lines

UI / Default Props: make consistent use of 'default_xxx' global vars,
which replace the 'g_default_xxx' ones in m_game.cc/h.  Moved their
definition into e_basis.cc (that's the primary place they are used).
Simplified some of the names.

------------------------------------------------------------------------
r372 | ajapted | 2012-12-05 15:11:00 +1100 (Wed, 05 Dec 2012) | 3 lines

Config: removed default_floor_height, default_middle_texture (etc...)
as config variables -- they are now considered as user state of a map.

------------------------------------------------------------------------
r371 | ajapted | 2012-12-05 15:09:06 +1100 (Wed, 05 Dec 2012) | 3 lines

UI / Default Props: skeletal functions to read/write the properties
into the user state of a map.

------------------------------------------------------------------------
r370 | ajapted | 2012-12-05 15:01:33 +1100 (Wed, 05 Dec 2012) | 2 lines

UI: tweaked layout of sidedef pics.

------------------------------------------------------------------------
r369 | ajapted | 2012-12-05 14:29:30 +1100 (Wed, 05 Dec 2012) | 2 lines

UI: tweaked layout of sector floor / ceiling properties.

------------------------------------------------------------------------
r368 | ajapted | 2012-12-04 22:36:45 +1100 (Tue, 04 Dec 2012) | 2 lines

minor update.

------------------------------------------------------------------------
r367 | ajapted | 2012-12-04 22:34:18 +1100 (Tue, 04 Dec 2012) | 3 lines

Sector mode: handle CTRL key with floor/ceiling height adjusters,
stepping by 64 units.

------------------------------------------------------------------------
r366 | ajapted | 2012-12-04 22:30:50 +1100 (Tue, 04 Dec 2012) | 9 lines

Sector mode: swapped keys to height adjusting: '.' and ',' now adjust
the floor height, and '[' and ']' now adjust the ceiling.

This was suggested by d1337r.  The rationale is that '.' and ',' are
lower on the keyboard than the '[' and ']' keys.

Also made step amounts consistent between the keys and the GUI
buttons: 8 units with no modifier, 1 unit shifted.

------------------------------------------------------------------------
r365 | ajapted | 2012-12-04 22:17:28 +1100 (Tue, 04 Dec 2012) | 5 lines

3D View:
1. disabled '.' and ',' as strafe keys (a sector function using these
   keys is more important)
2. allow UP and DOWN arrows to work with ALT pressed.

------------------------------------------------------------------------
r364 | ajapted | 2012-12-04 20:12:51 +1100 (Tue, 04 Dec 2012) | 4 lines

UI / Default Props:
1. added Thing number and description
2. disabled the sector title (it is fairly obvious)

------------------------------------------------------------------------
r363 | ajapted | 2012-12-04 19:58:30 +1100 (Tue, 04 Dec 2012) | 2 lines

UI / Default Props: added and layouted the Sector props.

------------------------------------------------------------------------
r362 | ajapted | 2012-12-04 19:32:17 +1100 (Tue, 04 Dec 2012) | 2 lines

UI / Default Props: added widgets for the Linedef textures.

------------------------------------------------------------------------
r361 | ajapted | 2012-12-04 19:19:13 +1100 (Tue, 04 Dec 2012) | 4 lines

UI: began work on a 'Default Props' panel, which sits underneath the
Vertex panel (with all that unused space) and will be used for setting
the default insert properties of objects (e.g. sector floor, wall tex).

------------------------------------------------------------------------
r360 | ajapted | 2012-12-04 19:08:15 +1100 (Tue, 04 Dec 2012) | 2 lines

minor commenting.

------------------------------------------------------------------------
r359 | ajapted | 2012-12-04 18:47:00 +1100 (Tue, 04 Dec 2012) | 2 lines

Coding: use 'WINDOW_BG' define for window backgrounds.

------------------------------------------------------------------------
r358 | ajapted | 2012-12-04 18:24:44 +1100 (Tue, 04 Dec 2012) | 3 lines

Changed default grid size to be 16 (was: 128), and added two new
config vars: 'default_grid_size' and 'default_grid_snap'.

------------------------------------------------------------------------
r357 | ajapted | 2012-12-04 18:20:49 +1100 (Tue, 04 Dec 2012) | 2 lines

Properly initialise the Grid_State_c object.

------------------------------------------------------------------------
r356 | ajapted | 2012-12-04 18:16:51 +1100 (Tue, 04 Dec 2012) | 2 lines

UI: tweaked grid color when zoomed far out (GRID_DARK).

------------------------------------------------------------------------
r355 | ajapted | 2012-12-04 16:55:06 +1100 (Tue, 04 Dec 2012) | 2 lines

Made multi-select optional, with new 'multi_select_modifier' config var.

------------------------------------------------------------------------
r354 | ajapted | 2012-12-04 16:15:10 +1100 (Tue, 04 Dec 2012) | 4 lines

Code tidying: replaced 'is_butl' and 'is_middle' hacks with 'button_down'
field in the Editor_State_c class.  Replaced 'click_ctrl' with 'button_mod'
field.  Removed some dead code.

------------------------------------------------------------------------
r353 | ajapted | 2012-12-04 14:49:13 +1100 (Tue, 04 Dec 2012) | 2 lines

UI: changed the grid_snap from a Choice --> Toggle_Button.

------------------------------------------------------------------------
r352 | ajapted | 2012-12-04 14:15:42 +1100 (Tue, 04 Dec 2012) | 3 lines

WISHLIST: added a few items, moved a few others, fleshed out the item
about configurable keys.

------------------------------------------------------------------------
r351 | ajapted | 2012-12-03 22:16:39 +1100 (Mon, 03 Dec 2012) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r350 | ajapted | 2012-12-03 22:15:21 +1100 (Mon, 03 Dec 2012) | 5 lines

Building Nodes: added the following config vars:
1. glbsp_fast
2. glbsp_verbose
3. glbsp_warn

------------------------------------------------------------------------
r349 | ajapted | 2012-12-03 20:33:45 +1100 (Mon, 03 Dec 2012) | 3 lines

Worked on supporting a configurable GUI scheme and color set, via two
new config vars: 'gui_scheme' and 'gui_color_set'.

------------------------------------------------------------------------
r348 | ajapted | 2012-12-03 16:06:37 +1100 (Mon, 03 Dec 2012) | 2 lines

TODO and WISHLIST: added some suggestions by d1337r.

------------------------------------------------------------------------
r347 | ajapted | 2012-12-03 15:17:22 +1100 (Mon, 03 Dec 2012) | 3 lines

Fixed color of a line or sector when tagged -- only the tagged object
should be drawn in pink, not the current line or sector.

------------------------------------------------------------------------
r346 | ajapted | 2012-12-03 14:55:24 +1100 (Mon, 03 Dec 2012) | 1 line

compiler warning
------------------------------------------------------------------------
r345 | ajapted | 2012-12-03 14:24:25 +1100 (Mon, 03 Dec 2012) | 3 lines

DOOM defs: moved 'Commander Keen' thing out of common/, since it is
specific to DOOM 2, and changed its category to OTHER.

------------------------------------------------------------------------
r344 | ajapted | 2012-12-03 10:26:25 +1100 (Mon, 03 Dec 2012) | 2 lines

Version bump after release (a little late...)

------------------------------------------------------------------------
r343 | ajapted | 2012-12-03 10:25:17 +1100 (Mon, 03 Dec 2012) | 2 lines

TODO and WISHLIST update.

------------------------------------------------------------------------
r342 | ajapted | 2012-12-03 10:21:00 +1100 (Mon, 03 Dec 2012) | 2 lines

Renamed doom_common.ugh --> doom_things.ugh

------------------------------------------------------------------------
r341 | ajapted | 2012-12-03 10:20:19 +1100 (Mon, 03 Dec 2012) | 5 lines

DOOM definitions:
1. split off common textures into its own file: common/doom_tex
2. moved 'sky_flat', 'default_port' (etc) back to main def (in games/)
3. will rename doom_common.ugh --> doom_things.ugh

------------------------------------------------------------------------
r340 | ajapted | 2012-12-03 09:57:35 +1100 (Mon, 03 Dec 2012) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r339 | ajapted | 2012-12-03 09:57:11 +1100 (Mon, 03 Dec 2012) | 3 lines

Browser: added 'pic_mode' field to Browser_Box, replaces hard-coded tests
against the browser kind (e.g. for resizing behavior).

------------------------------------------------------------------------
r338 | ajapted | 2012-12-03 09:40:26 +1100 (Mon, 03 Dec 2012) | 3 lines

Browser / Things: implemented the 'pics' button, show sprites when on
and show descriptions when off.

------------------------------------------------------------------------
r337 | ajapted | 2012-12-03 09:18:46 +1100 (Mon, 03 Dec 2012) | 3 lines

Browser: added a 'number' field to each Browser_Item, and use it when
sorting numerically (and in the callbacks too).

------------------------------------------------------------------------
r336 | ajapted | 2012-12-02 23:24:43 +1100 (Sun, 02 Dec 2012) | 2 lines

minor corrections.

------------------------------------------------------------------------
r335 | ajapted | 2012-12-02 23:23:52 +1100 (Sun, 02 Dec 2012) | 2 lines

Game defs: moved boss-brain things out of 'Monster' category.

------------------------------------------------------------------------
r334 | ajapted | 2012-12-02 23:16:43 +1100 (Sun, 02 Dec 2012) | 2 lines

Tweak : changed thingtype_t::flags field from byte to short.

------------------------------------------------------------------------
r333 | ajapted | 2012-12-02 23:14:22 +1100 (Sun, 02 Dec 2012) | 4 lines

Browser | Thing pics:
1. ignore things which have no sprites ("NULL" in the def file).
2. alphabetical sort shows sprite names, numerical sort shows id numbers.

------------------------------------------------------------------------
r332 | ajapted | 2012-12-02 16:55:39 +1100 (Sun, 02 Dec 2012) | 2 lines

Browser: initial work on picture mode for Things...

------------------------------------------------------------------------
r331 | ajapted | 2012-12-02 14:21:42 +1100 (Sun, 02 Dec 2012) | 3 lines

Removed doc/Features.txt : the info has been absorbed into README.txt
and the website.

------------------------------------------------------------------------
r330 | ajapted | 2012-12-02 14:19:24 +1100 (Sun, 02 Dec 2012) | 2 lines

README.txt : added 'Features' and 'Supported Games' sections (from wiki).

------------------------------------------------------------------------
r329 | ajapted | 2012-12-01 20:49:36 +1100 (Sat, 01 Dec 2012) | 2 lines

Added AUTHORS.txt document.

------------------------------------------------------------------------
r328 | ajapted | 2012-11-30 22:19:08 +1100 (Fri, 30 Nov 2012) | 3 lines

Worked on the Jump/Next/Previous commands.  However I don't think they
are very useful...

------------------------------------------------------------------------
r327 | ajapted | 2012-11-30 21:02:29 +1100 (Fri, 30 Nov 2012) | 3 lines

Simplified how new sector squares are created outside of the map,
size is fixed but configurable via 'new_sector_size' config var.

------------------------------------------------------------------------
r326 | ajapted | 2012-11-30 20:24:18 +1100 (Fri, 30 Nov 2012) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r325 | ajapted | 2012-11-30 20:23:47 +1100 (Fri, 30 Nov 2012) | 2 lines

Rotate dialog: implemented its functionality.

------------------------------------------------------------------------
r324 | ajapted | 2012-11-30 19:47:18 +1100 (Fri, 30 Nov 2012) | 2 lines

Rotate dialog: began work on it, got the layout done so far...

------------------------------------------------------------------------
r323 | ajapted | 2012-11-30 19:24:20 +1100 (Fri, 30 Nov 2012) | 3 lines

When rotating a group of things (or sectors which contain things),
update the angles of the things too.

------------------------------------------------------------------------
r322 | ajapted | 2012-11-30 19:09:36 +1100 (Fri, 30 Nov 2012) | 2 lines

Scale dialog: fixed percentage parsing

------------------------------------------------------------------------
r321 | ajapted | 2012-11-30 19:02:25 +1100 (Fri, 30 Nov 2012) | 2 lines

Scale dialog: completed the functionality.

------------------------------------------------------------------------
r320 | ajapted | 2012-11-30 18:53:41 +1100 (Fri, 30 Nov 2012) | 2 lines

Scale dialog: implemented parsing code: ParseScaleStr().

------------------------------------------------------------------------
r319 | ajapted | 2012-11-30 18:41:33 +1100 (Fri, 30 Nov 2012) | 3 lines

Scale dialog: Partial work implementing the scaling, e.g. added code
to determine the focus point of scaling from the 'origin' choice.

------------------------------------------------------------------------
r318 | ajapted | 2012-11-30 16:46:33 +1100 (Fri, 30 Nov 2012) | 4 lines

Scale dialog layouting:
1. added 'origin' button
2. rearranged bottom section, added some help text

------------------------------------------------------------------------
r317 | ajapted | 2012-11-30 16:04:08 +1100 (Fri, 30 Nov 2012) | 2 lines

Move dialog: ensure initial values are zero.

------------------------------------------------------------------------
r316 | ajapted | 2012-11-30 15:57:37 +1100 (Fri, 30 Nov 2012) | 2 lines

Began work on 'Scale Objects' dialog...

------------------------------------------------------------------------
r315 | ajapted | 2012-11-30 15:25:59 +1100 (Fri, 30 Nov 2012) | 2 lines

Implemented the functionality of the Move dialog.

------------------------------------------------------------------------
r314 | ajapted | 2012-11-30 15:11:29 +1100 (Fri, 30 Nov 2012) | 3 lines

Finished layout on UI_MoveDialog window (e.g. added a darker group around
the buttons).  Renamed "OK" button --> "Move" and made it bold.

------------------------------------------------------------------------
r313 | ajapted | 2012-11-30 14:49:21 +1100 (Fri, 30 Nov 2012) | 3 lines

Partial work on a dialog window for moving objects (via the Edit menu).
Still in the layout phase....

------------------------------------------------------------------------
r312 | ajapted | 2012-11-30 14:33:18 +1100 (Fri, 30 Nov 2012) | 3 lines

Added new (empty) code files: ui_misc.cc/h -- for miscellaneous dialog
windows, such as a move object dialog....

------------------------------------------------------------------------
r311 | ajapted | 2012-11-30 14:05:10 +1100 (Fri, 30 Nov 2012) | 2 lines

Disabled the 'Play Map' feature for now.

------------------------------------------------------------------------
r310 | ajapted | 2012-11-30 10:43:23 +1100 (Fri, 30 Nov 2012) | 2 lines

Changed shortcut key for 'File/Export Map' to CTRL-E

------------------------------------------------------------------------
r309 | ajapted | 2012-11-30 10:34:47 +1100 (Fri, 30 Nov 2012) | 4 lines

Experiment with a 'File/Play Map' command (CTRL-P).  Currently the
directory to enter and program to run are hard-coded, these would
need to be configurable.

------------------------------------------------------------------------
r308 | ajapted | 2012-11-28 22:37:36 +1100 (Wed, 28 Nov 2012) | 2 lines

Began a fresh CHANGES.txt file, tweaked previous one.

------------------------------------------------------------------------
r307 | ajapted | 2012-11-28 22:35:52 +1100 (Wed, 28 Nov 2012) | 2 lines

Moved CHANGES.txt --> docs/ folder, after the 0.84 release.

------------------------------------------------------------------------
r306 | ajapted | 2012-11-28 17:44:41 +1100 (Wed, 28 Nov 2012) | 3 lines

MacOS X: set home_dir to '~/documents/eureka', making sure we create
the ~/documents folder (in case it doesn't exist).

------------------------------------------------------------------------
r305 | ajapted | 2012-11-28 16:30:40 +1100 (Wed, 28 Nov 2012) | 2 lines

Renamed 'Nil' method --> 'Clear' (for MacOS X compatibility).

------------------------------------------------------------------------
r304 | ajapted | 2012-11-27 18:09:20 +1100 (Tue, 27 Nov 2012) | 2 lines

pack-source script: added debian stuff.

------------------------------------------------------------------------
r303 | ajapted | 2012-11-27 17:55:17 +1100 (Tue, 27 Nov 2012) | 2 lines

INSTALL.txt : mention /usr/share/games/doom

------------------------------------------------------------------------
r302 | ajapted | 2012-11-27 17:49:20 +1100 (Tue, 27 Nov 2012) | 2 lines

TODO and WISHLIST updated before release.

------------------------------------------------------------------------
r301 | ajapted | 2012-11-27 17:18:59 +1100 (Tue, 27 Nov 2012) | 2 lines

README.txt : added a REQUIREMENTS section.

------------------------------------------------------------------------
r300 | ajapted | 2012-11-27 17:06:41 +1100 (Tue, 27 Nov 2012) | 2 lines

CHANGELOG: yet another update.

------------------------------------------------------------------------
r299 | ajapted | 2012-11-27 17:04:48 +1100 (Tue, 27 Nov 2012) | 2 lines

Made vertices slightly bigger, but not too big when zooming right in.

------------------------------------------------------------------------
r298 | ajapted | 2012-11-27 16:00:39 +1100 (Tue, 27 Nov 2012) | 2 lines

TODO / WISHLIST update.

------------------------------------------------------------------------
r297 | ajapted | 2012-11-27 15:57:34 +1100 (Tue, 27 Nov 2012) | 4 lines

Implemented a 'mouse_wheel_scrolls_map' config var, when enabled the
mouse wheel will scroll the map (can do horizontally too).  Pressing
the CTRL key (ALT in MacOS X) will perform the zoom function.

------------------------------------------------------------------------
r296 | ajapted | 2012-11-27 15:31:52 +1100 (Tue, 27 Nov 2012) | 2 lines

Handle '+' and '-' zooming keys by calling CMD_Zoom() directly (NOT via Editor_Wheel).

------------------------------------------------------------------------
r295 | ajapted | 2012-11-27 15:27:56 +1100 (Tue, 27 Nov 2012) | 3 lines

UI_Canvas: tidier event handling code, added handle_key(), handle_push()
(and so forth) methods to manage the major event kinds.

------------------------------------------------------------------------
r294 | ajapted | 2012-11-26 22:44:55 +1100 (Mon, 26 Nov 2012) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r293 | ajapted | 2012-11-26 15:00:00 +1100 (Mon, 26 Nov 2012) | 2 lines

Version bump to 0.84, ready for release.

------------------------------------------------------------------------
r292 | ajapted | 2012-11-26 14:44:49 +1100 (Mon, 26 Nov 2012) | 2 lines

commenting...

------------------------------------------------------------------------
r291 | ajapted | 2012-11-26 12:18:55 +1100 (Mon, 26 Nov 2012) | 2 lines

Moved Makefile.debian --> misc/ directory.

------------------------------------------------------------------------
r290 | ajapted | 2012-11-25 21:29:25 +1100 (Sun, 25 Nov 2012) | 2 lines

Makefile.debian : fixed for moving 'debian' dir --> misc/

------------------------------------------------------------------------
r289 | ajapted | 2012-11-25 21:23:33 +1100 (Sun, 25 Nov 2012) | 2 lines

Moved 'debian' folder from top level --> misc/ folder

------------------------------------------------------------------------
r288 | ajapted | 2012-11-25 21:13:45 +1100 (Sun, 25 Nov 2012) | 7 lines

Makefile.debian fixes:
1. added missing PROGRAM value
2. gzip the changelog file
3. do a 'debclean' before doing a 'debbuild'
4. store result in parent dir -- this also gives it the proper package
   name, with version and architecture in it.

------------------------------------------------------------------------
r287 | ajapted | 2012-11-25 21:07:37 +1100 (Sun, 25 Nov 2012) | 3 lines

Removed debian stuff from plain Makefile.
(This change should have been in r284....)

------------------------------------------------------------------------
r286 | ajapted | 2012-11-25 21:04:09 +1100 (Sun, 25 Nov 2012) | 3 lines

Debian/copyright: indented Copyright lines, which fixes a lintian
warning about lacking a copyright statement ^_^

------------------------------------------------------------------------
r285 | ajapted | 2012-11-25 21:02:20 +1100 (Sun, 25 Nov 2012) | 3 lines

Debian/control: changed section to 'misc' and added 'libc6' as a
dependency -- both due to lintian errors.

------------------------------------------------------------------------
r284 | ajapted | 2012-11-25 20:43:00 +1100 (Sun, 25 Nov 2012) | 2 lines

Makefiles: removed debian package stuff from plain Makefile.

------------------------------------------------------------------------
r283 | ajapted | 2012-11-25 20:41:02 +1100 (Sun, 25 Nov 2012) | 2 lines

Added Makefile.debian, logic for making a debian package.

------------------------------------------------------------------------
r282 | ajapted | 2012-11-25 20:37:49 +1100 (Sun, 25 Nov 2012) | 2 lines

Debian: tweaked version in debian/control, removed # comment

------------------------------------------------------------------------
r281 | ajapted | 2012-11-25 20:21:20 +1100 (Sun, 25 Nov 2012) | 3 lines

Makefile: partial work on 'debinstall' target to create the file
heirarchy for the debian package.

------------------------------------------------------------------------
r280 | ajapted | 2012-11-25 18:51:50 +1100 (Sun, 25 Nov 2012) | 2 lines

Wrote the debian/copyright file.

------------------------------------------------------------------------
r279 | ajapted | 2012-11-25 18:37:17 +1100 (Sun, 25 Nov 2012) | 2 lines

Added basic debian/changelog file.

------------------------------------------------------------------------
r278 | ajapted | 2012-11-25 14:14:24 +1100 (Sun, 25 Nov 2012) | 2 lines

Initial work on a debian/control file.

------------------------------------------------------------------------
r277 | ajapted | 2012-11-25 13:28:20 +1100 (Sun, 25 Nov 2012) | 2 lines

Don't create a linedef between two vertices at the same spot.

------------------------------------------------------------------------
r276 | ajapted | 2012-11-25 13:20:20 +1100 (Sun, 25 Nov 2012) | 2 lines

Tweaked get_split_linedef() to skip lines with bbox < 4x4

------------------------------------------------------------------------
r275 | ajapted | 2012-11-25 13:07:48 +1100 (Sun, 25 Nov 2012) | 2 lines

Reworked last commit, don't split lines with bbox < 4x4.

------------------------------------------------------------------------
r274 | ajapted | 2012-11-25 13:04:00 +1100 (Sun, 25 Nov 2012) | 2 lines

Fixed split_linedef command ('x' key) to not create zero-length lines.

------------------------------------------------------------------------
r273 | ajapted | 2012-11-25 12:24:55 +1100 (Sun, 25 Nov 2012) | 3 lines

Fixed LineDefWouldOverlap() to skip zero-length lines, otherwise it
raises a fatal error in PerpDist().

------------------------------------------------------------------------
r272 | ajapted | 2012-11-24 17:46:35 +1100 (Sat, 24 Nov 2012) | 2 lines

ChangeLog tweak.

------------------------------------------------------------------------
r271 | ajapted | 2012-11-24 17:01:01 +1100 (Sat, 24 Nov 2012) | 2 lines

README: updated for 0.84 release, fixed the different keys.

------------------------------------------------------------------------
r270 | ajapted | 2012-11-24 15:40:58 +1100 (Sat, 24 Nov 2012) | 2 lines

Tweaked code of previous commit (bound 'R' to RTS mode).

------------------------------------------------------------------------
r269 | ajapted | 2012-11-24 15:39:13 +1100 (Sat, 24 Nov 2012) | 2 lines

Bound 'R' key for RTS editing mode, frees up 'r' for a more common function.

------------------------------------------------------------------------
r268 | ajapted | 2012-11-24 15:10:49 +1100 (Sat, 24 Nov 2012) | 2 lines

TODO update.

------------------------------------------------------------------------
r267 | ajapted | 2012-11-24 15:10:33 +1100 (Sat, 24 Nov 2012) | 2 lines

INSTALL.txt : tweakage.

------------------------------------------------------------------------
r266 | ajapted | 2012-11-24 15:09:13 +1100 (Sat, 24 Nov 2012) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r265 | ajapted | 2012-11-24 15:06:20 +1100 (Sat, 24 Nov 2012) | 3 lines

Determine split line: removed bbox test (was bad for axis-aligned lines)
and fixed the bbox test in get_split_line() which ignored mapslack.

------------------------------------------------------------------------
r264 | ajapted | 2012-11-24 14:46:50 +1100 (Sat, 24 Nov 2012) | 3 lines

When finding the split_line, check the non-snapped position, but prevent
the snapped position being the same as the linedef's start or end.

------------------------------------------------------------------------
r263 | ajapted | 2012-11-24 14:44:19 +1100 (Sat, 24 Nov 2012) | 2 lines

MacOS X: fix pathlen type for _NSGetExecutablePath() call.

------------------------------------------------------------------------
r262 | ajapted | 2012-11-23 22:44:18 +1100 (Fri, 23 Nov 2012) | 2 lines

minor docco updates.

------------------------------------------------------------------------
r261 | ajapted | 2012-11-23 21:44:43 +1100 (Fri, 23 Nov 2012) | 2 lines

ChangeLog update.

------------------------------------------------------------------------
r260 | ajapted | 2012-11-23 21:42:44 +1100 (Fri, 23 Nov 2012) | 3 lines

Made SHIFT + MMB do plain scaling (keep aspect ratio), ALT + MMB to
scale X and Y independently.

------------------------------------------------------------------------
r259 | ajapted | 2012-11-23 20:59:45 +1100 (Fri, 23 Nov 2012) | 3 lines

Key handling: change the ALT ignore code to return _false_, which means
FLTK will send them to other places (especially the menu).

------------------------------------------------------------------------
r258 | ajapted | 2012-11-23 20:51:39 +1100 (Fri, 23 Nov 2012) | 4 lines

Key handling: in general, ignore key if ALT is also pressed.  Since the
META modifier is mapped to KM_ALT, this also ignores keys with META
(which I think is the CMD key under MacOS X).

------------------------------------------------------------------------
r257 | ajapted | 2012-11-22 22:23:28 +1100 (Thu, 22 Nov 2012) | 2 lines

Implemented the -merge option for adding Resource wads.

------------------------------------------------------------------------
r256 | ajapted | 2012-11-22 22:03:17 +1100 (Thu, 22 Nov 2012) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r255 | ajapted | 2012-11-22 22:02:45 +1100 (Thu, 22 Nov 2012) | 2 lines

TODO / WISHLIST update.

------------------------------------------------------------------------
r254 | ajapted | 2012-11-22 21:35:53 +1100 (Thu, 22 Nov 2012) | 3 lines

MacOSX: renamed the 'nil' method of Objid / Close_obj classes --> 'clear',
since it is a reserved keyword in Objective-C.

------------------------------------------------------------------------
r253 | ajapted | 2012-11-22 21:08:32 +1100 (Thu, 22 Nov 2012) | 3 lines

The ESC key no longer exits Eureka, unless the new 'escape_key_quits'
config variable is enabled.

------------------------------------------------------------------------
r252 | ajapted | 2012-11-22 19:34:19 +1100 (Thu, 22 Nov 2012) | 2 lines

MacOSX: Changed #ifdef tests to use __APPLE__ instead of MACOSX.

------------------------------------------------------------------------
r251 | ajapted | 2012-11-22 19:18:04 +1100 (Thu, 22 Nov 2012) | 4 lines

Config: new syntax for config files, option name is followed by the value
without any '=' sign between -- which is consistent with the game / port
definition files.

------------------------------------------------------------------------
r250 | ajapted | 2012-11-22 17:28:25 +1100 (Thu, 22 Nov 2012) | 2 lines

Config: split code to parse each line out of parse_config_file() function.

------------------------------------------------------------------------
r249 | ajapted | 2012-11-22 11:25:06 +1100 (Thu, 22 Nov 2012) | 2 lines

WISHLIST: finished reorganising / prioritising the desirables.

------------------------------------------------------------------------
r248 | ajapted | 2012-11-22 11:06:47 +1100 (Thu, 22 Nov 2012) | 3 lines

IWAD search: check some standard places, like /usr/share/games/doom
(and for Win32, places like C:\DOOM).

------------------------------------------------------------------------
r247 | ajapted | 2012-11-22 10:35:07 +1100 (Thu, 22 Nov 2012) | 3 lines

Moved some code in main.cc, like InitFLTK, which was sandwiched in
between various config and directory handling stuff.

------------------------------------------------------------------------
r246 | ajapted | 2012-11-21 23:14:05 +1100 (Wed, 21 Nov 2012) | 2 lines

WISHLIST: more work reorganising...

------------------------------------------------------------------------
r245 | ajapted | 2012-11-21 22:49:13 +1100 (Wed, 21 Nov 2012) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r244 | ajapted | 2012-11-21 22:28:39 +1100 (Wed, 21 Nov 2012) | 2 lines

minor commenting

------------------------------------------------------------------------
r243 | ajapted | 2012-11-21 22:26:08 +1100 (Wed, 21 Nov 2012) | 3 lines

Allow Eureka to run locally (without a make install) by checking "."
as a possible install_dir.

------------------------------------------------------------------------
r242 | ajapted | 2012-11-21 22:18:24 +1100 (Wed, 21 Nov 2012) | 2 lines

INSTALL.txt : mention Gentoo info (courtesy GuntherDW).

------------------------------------------------------------------------
r241 | ajapted | 2012-11-21 22:12:59 +1100 (Wed, 21 Nov 2012) | 2 lines

Config: fixed bug in recent change of OPT_BOOLEAN handling.

------------------------------------------------------------------------
r240 | ajapted | 2012-11-21 19:40:11 +1100 (Wed, 21 Nov 2012) | 2 lines

WISHLIST: began reorganizing into HIGH and LOWER priority sections...

------------------------------------------------------------------------
r239 | ajapted | 2012-11-21 19:06:28 +1100 (Wed, 21 Nov 2012) | 4 lines

Config: added 'new_islands_are_void' variable -- it forces islands created
inside a sector to have a void interior (rather than a new sector which
has same properties as the outer sector).

------------------------------------------------------------------------
r238 | ajapted | 2012-11-21 18:58:25 +1100 (Wed, 21 Nov 2012) | 5 lines

Config handling:
1. can provide a value on command line for OPT_BOOLEAN vars
2. removed redundant checks on o->data_ptr (only NULL for OPT_END)
3. made boolean and confirm keywords case-insensitive

------------------------------------------------------------------------
r237 | ajapted | 2012-11-21 18:31:18 +1100 (Wed, 21 Nov 2012) | 2 lines

TODO update.

------------------------------------------------------------------------
r236 | ajapted | 2012-11-21 18:30:22 +1100 (Wed, 21 Nov 2012) | 2 lines

CHANGELOG: mention the new pic-selection feature.

------------------------------------------------------------------------
r235 | ajapted | 2012-11-21 18:28:39 +1100 (Wed, 21 Nov 2012) | 2 lines

Closing the browser unselects any pics in the LineDef and Sector panels.

------------------------------------------------------------------------
r234 | ajapted | 2012-11-21 18:18:34 +1100 (Wed, 21 Nov 2012) | 4 lines

LineDef Panel: implemented the selected sidedef parts (with red border)
getting a texture when clicking in the texture browser -- the mouse
button and modifier keys are not used when any parts are selected.

------------------------------------------------------------------------
r233 | ajapted | 2012-11-21 17:27:01 +1100 (Wed, 21 Nov 2012) | 5 lines

Sector panel: implemented the pic selection, i.e. when the floor pic is
selected then the floor is changed and when the ceiling pic is selected
then the ceiling is changed.  The mouse button is ignored when one of
them is selected.

------------------------------------------------------------------------
r232 | ajapted | 2012-11-21 16:20:48 +1100 (Wed, 21 Nov 2012) | 2 lines

LineDef and Sector panels: don't select pic when there's no object(s).

------------------------------------------------------------------------
r231 | ajapted | 2012-11-21 16:16:35 +1100 (Wed, 21 Nov 2012) | 4 lines

LineDef and Sector panels: code to clear the selected pics, automatic
when the panel is disabled (NO_OBJ), and can be done externally (e.g.
when changing editing modes).

------------------------------------------------------------------------
r230 | ajapted | 2012-11-21 16:02:51 +1100 (Wed, 21 Nov 2012) | 2 lines

Use CMD_UnselectAll() for the click-in-empty-spot action.

------------------------------------------------------------------------
r229 | ajapted | 2012-11-21 15:51:04 +1100 (Wed, 21 Nov 2012) | 5 lines

1. added ability to UI_Pic to select/unselect it (done externally)
2. in Sector and SideDef panels, can select/unselect the textures and
   also open/change the browser to Flats or Textures.
(Note: still lacking mechanism to actually change the selected stuff)

------------------------------------------------------------------------
r228 | ajapted | 2012-11-21 14:15:49 +1100 (Wed, 21 Nov 2012) | 2 lines

UI_Pic: implemented a draw_selected() method.

------------------------------------------------------------------------
r227 | ajapted | 2012-11-21 12:46:06 +1100 (Wed, 21 Nov 2012) | 3 lines

Makefile: remove wayward initial space (stops emacs complaining when saving).
Patch courtesy Jeremy Henty.

------------------------------------------------------------------------
r226 | ajapted | 2012-11-21 12:39:32 +1100 (Wed, 21 Nov 2012) | 3 lines

Implemented 'leave_offsets_alone' config var -- when set, no automatic
adjustment of sidedef offsets when splitting lines (etc).

------------------------------------------------------------------------
r225 | ajapted | 2012-11-21 12:31:39 +1100 (Wed, 21 Nov 2012) | 3 lines

Thing panel: experimented with option buttons for Hexen player classes,
and hence moved the 'ambush' and 'friend' buttons onto their own line.

------------------------------------------------------------------------
r224 | ajapted | 2012-11-20 22:47:29 +1100 (Tue, 20 Nov 2012) | 2 lines

TODO, WISHLIST, CHANGELOG update

------------------------------------------------------------------------
r223 | ajapted | 2012-11-20 22:43:32 +1100 (Tue, 20 Nov 2012) | 3 lines

UI_Canvas: fixed bug where a pink-highlighted sectors with tag matching
the linedef would not be drawn if the linedef was off the screen.

------------------------------------------------------------------------
r222 | ajapted | 2012-11-20 22:34:58 +1100 (Tue, 20 Nov 2012) | 2 lines

LineDef panel: experiment with 'Args' line (for Hexen support)

------------------------------------------------------------------------
r221 | ajapted | 2012-11-20 21:23:19 +1100 (Tue, 20 Nov 2012) | 3 lines

Multi-select: handle a small selbox as if it were a click/release pair
(clearing the current selection) -- shrink the small selbox to zero.

------------------------------------------------------------------------
r220 | ajapted | 2012-11-20 21:07:22 +1100 (Tue, 20 Nov 2012) | 2 lines

Insert_Thing: if a thing is already selected, copy properties to new one.

------------------------------------------------------------------------
r219 | ajapted | 2012-11-20 20:58:04 +1100 (Tue, 20 Nov 2012) | 14 lines

Implemented multi-select, i.e. clicking on an object to select it
will not clear the current selection first -- merely toggle it.

This required some big changes and a hack or two, for one thing
when clicking on an object, it's selection status is changed when
the the mouse button is _released_ (or user tries to drag it).

Also to allow dragging individual objects, after any objects are
moved we will clear the selection when an unselected object is
clicked on (to select it).

Removed the dummy 'CANVAS' object kind, we now properly test
whether we are drawing a selbox by the isSelboxActive() call.

------------------------------------------------------------------------
r218 | ajapted | 2012-11-20 17:57:55 +1100 (Tue, 20 Nov 2012) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r217 | ajapted | 2012-11-20 17:48:00 +1100 (Tue, 20 Nov 2012) | 3 lines

Fixed inner sector getting defaults when closing a vertex loop which
lies within another sector -- the inner should be a copy of the outer.

------------------------------------------------------------------------
r216 | ajapted | 2012-11-19 22:47:45 +1100 (Mon, 19 Nov 2012) | 4 lines

Changed the way level checksum is done (for state persistence), it is no
longer done directly in the loading and saving code (and performed on the
raw formats), now it is computed on the in-memory version of the map.

------------------------------------------------------------------------
r215 | ajapted | 2012-11-19 22:36:36 +1100 (Mon, 19 Nov 2012) | 2 lines

Adler-32: fixed the copy constructor to copy the 'extra' field too.

------------------------------------------------------------------------
r214 | ajapted | 2012-11-19 22:31:29 +1100 (Mon, 19 Nov 2012) | 3 lines

Implemented BA_LevelChecksum() which computes the CRC of the level,
ignoring any unused vertices, sidedefs or sectors.

------------------------------------------------------------------------
r213 | ajapted | 2012-11-19 21:38:13 +1100 (Mon, 19 Nov 2012) | 3 lines

Browser: set the 'linesize' to higher values, so that scrolling with
the mouse wheel is better (not so tedious).

------------------------------------------------------------------------
r212 | ajapted | 2012-11-19 21:35:21 +1100 (Mon, 19 Nov 2012) | 2 lines

Browser: made default width be a bit wider (to fit 4 flats across).

------------------------------------------------------------------------
r211 | ajapted | 2012-11-19 16:51:43 +1100 (Mon, 19 Nov 2012) | 2 lines

TODO update.

------------------------------------------------------------------------
r210 | ajapted | 2012-11-19 16:51:07 +1100 (Mon, 19 Nov 2012) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r209 | ajapted | 2012-11-19 16:50:10 +1100 (Mon, 19 Nov 2012) | 3 lines

1. Support a "default_port" command in game definition files
2. Made the fallback port be "vanilla" -- for Heretic

------------------------------------------------------------------------
r208 | ajapted | 2012-11-19 16:42:27 +1100 (Mon, 19 Nov 2012) | 2 lines

DOOM defs: added "default_port boom"

------------------------------------------------------------------------
r207 | ajapted | 2012-11-19 16:35:03 +1100 (Mon, 19 Nov 2012) | 2 lines

Game def loader: tidied up 'buf' usage, renamed other 'buf' variables.

------------------------------------------------------------------------
r206 | ajapted | 2012-11-19 14:32:53 +1100 (Mon, 19 Nov 2012) | 5 lines

lib_file: added GetExecutablePath() function, needed for Win32 builds.

Code is from Oblige's lib_file.cc, which I removed earlier as I didn't
think it would be needed.

------------------------------------------------------------------------
r205 | ajapted | 2012-11-18 22:26:32 +1100 (Sun, 18 Nov 2012) | 2 lines

Updated CHANGELOG, TODO and WISHLIST.

------------------------------------------------------------------------
r204 | ajapted | 2012-11-18 21:38:32 +1100 (Sun, 18 Nov 2012) | 2 lines

Thing panel: got new arrow buttons working, and improved the layout.

------------------------------------------------------------------------
r203 | ajapted | 2012-11-18 21:28:24 +1100 (Sun, 18 Nov 2012) | 2 lines

Arrow images: trimmed the diagonal arrows, look better now.

------------------------------------------------------------------------
r202 | ajapted | 2012-11-18 21:21:54 +1100 (Sun, 18 Nov 2012) | 3 lines

Thing panel: partial work on eight arrow buttons for setting the angle.
These replace the <- and -> buttons which rotated things.

------------------------------------------------------------------------
r201 | ajapted | 2012-11-18 20:42:03 +1100 (Sun, 18 Nov 2012) | 2 lines

Added 'im_arrows.cc' containing eight small arrow images (XPM format).

------------------------------------------------------------------------
r200 | ajapted | 2012-11-18 18:58:50 +1100 (Sun, 18 Nov 2012) | 2 lines

Experiment to make plain MMB insert new objects....

------------------------------------------------------------------------
r199 | ajapted | 2012-11-18 18:28:14 +1100 (Sun, 18 Nov 2012) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r198 | ajapted | 2012-11-18 18:26:57 +1100 (Sun, 18 Nov 2012) | 8 lines

3D View:
1. support WASD keys for movement
2. rebound 's' key to 'o' (toggle sprites) and 'w' --> 'v'
3. added 'g' key to toggle gravity
4. removed CTRL-L : resync thing Zs when toggling sprites

Note (1) and (3) were suggested by Dragonsbrethen.

------------------------------------------------------------------------
r197 | ajapted | 2012-11-18 13:38:51 +1100 (Sun, 18 Nov 2012) | 2 lines

INSTALL.txt : mention some libraries people may need (thanks to DoomGater).

------------------------------------------------------------------------
r196 | ajapted | 2012-11-18 13:37:44 +1100 (Sun, 18 Nov 2012) | 2 lines

Began a fresh CHANGES.txt document

------------------------------------------------------------------------
r195 | ajapted | 2012-11-18 13:36:10 +1100 (Sun, 18 Nov 2012) | 2 lines

Moved CHANGES.txt --> docs folder (after 0.81 release)

------------------------------------------------------------------------
r194 | ajapted | 2012-11-18 13:35:17 +1100 (Sun, 18 Nov 2012) | 2 lines

CMD_BuildNodes: on success, re-open the wad and reload the map.

------------------------------------------------------------------------
r193 | ajapted | 2012-11-18 12:50:12 +1100 (Sun, 18 Nov 2012) | 2 lines

Post-release version bump: 0.81 --> 0.82

------------------------------------------------------------------------
r192 | ajapted | 2012-11-16 20:23:01 +1100 (Fri, 16 Nov 2012) | 2 lines

Fixed pack-source.sh script (had some Oblige stuff left in it).

------------------------------------------------------------------------
r191 | ajapted | 2012-11-16 13:58:54 +1100 (Fri, 16 Nov 2012) | 2 lines

Checked in 'pack-source.sh' shell script.

------------------------------------------------------------------------
r190 | ajapted | 2012-11-16 13:21:15 +1100 (Fri, 16 Nov 2012) | 2 lines

TODO and WISHLIST update.

------------------------------------------------------------------------
r189 | ajapted | 2012-11-16 13:19:55 +1100 (Fri, 16 Nov 2012) | 2 lines

CHANGELOG update.

------------------------------------------------------------------------
r188 | ajapted | 2012-11-16 13:17:14 +1100 (Fri, 16 Nov 2012) | 5 lines

README.txt:
1. completely rewrote the 'RUNNING' section
2. replaced 'INTRODUCTION' section with text from 'About' wiki page
3. replaced 'KEYBOARD / MOUSE' section with text from wiki

------------------------------------------------------------------------
r187 | ajapted | 2012-11-16 11:37:03 +1100 (Fri, 16 Nov 2012) | 2 lines

Renamed changelog files (in docs/)

------------------------------------------------------------------------
r186 | ajapted | 2012-11-15 17:29:09 +1100 (Thu, 15 Nov 2012) | 2 lines

minor commenting...

------------------------------------------------------------------------
r185 | ajapted | 2012-11-15 17:24:53 +1100 (Thu, 15 Nov 2012) | 3 lines

Improved the way AssignSectorToSpace() sets the default sector props
from a neighbor.

------------------------------------------------------------------------
r184 | ajapted | 2012-11-15 16:23:04 +1100 (Thu, 15 Nov 2012) | 2 lines

With 'c' copy-prop command on things, do not copy the angle.

------------------------------------------------------------------------
r183 | ajapted | 2012-11-15 16:14:59 +1100 (Thu, 15 Nov 2012) | 2 lines

Removed no-longer-used code files: editobj.cc/h

------------------------------------------------------------------------
r182 | ajapted | 2012-11-15 16:11:39 +1100 (Thu, 15 Nov 2012) | 4 lines

Implemented new 'c' copy-properties command, which will copy the props
of a sector (for example) from the selected one to the highlighted one.
Works for things and linedefs too (though linedefs is very limited).

------------------------------------------------------------------------
r181 | ajapted | 2012-11-15 15:52:14 +1100 (Thu, 15 Nov 2012) | 2 lines

Moved LineDefAlreadyExists() and LineDefWouldOverlap() code --> e_linedef.cc

------------------------------------------------------------------------
r180 | ajapted | 2012-11-15 12:00:04 +1100 (Thu, 15 Nov 2012) | 2 lines

CHANGELOG updated.

------------------------------------------------------------------------
r179 | ajapted | 2012-11-15 11:57:10 +1100 (Thu, 15 Nov 2012) | 3 lines

Insert_Sector: when creating a square outside of map, if a sector is
already selected then copy the properties to the new sector.

------------------------------------------------------------------------
r178 | ajapted | 2012-11-15 11:45:43 +1100 (Thu, 15 Nov 2012) | 2 lines

CMD_MergeSectors: if deleting linedefs, delete unused vertices too.

------------------------------------------------------------------------
r177 | ajapted | 2012-11-15 11:43:32 +1100 (Thu, 15 Nov 2012) | 3 lines

Wrote DeleteLineDefs() function which not only deletes a list of lines,
but also deletes the unused vertices/sidedefs left over.

------------------------------------------------------------------------
r176 | ajapted | 2012-11-15 11:41:54 +1100 (Thu, 15 Nov 2012) | 3 lines

Moved UnusedVertices() and UnusedSideDefs() functions to global scope,
and renamed the 'list' parameter to 'lines' (for clearer code).

------------------------------------------------------------------------
r175 | ajapted | 2012-11-15 10:49:38 +1100 (Thu, 15 Nov 2012) | 4 lines

Emulate the Yadex (DEU?) behavior where trying to set the same mode as
currently active will clear the selection.  This is enabled by the
'same_mode_clears_selection' config variable (default is OFF).

------------------------------------------------------------------------
r174 | ajapted | 2012-11-15 10:35:56 +1100 (Thu, 15 Nov 2012) | 5 lines

CMD_MergeSectors: reworked way common linedefs are found, only detect
them between the source sector and a replaced sector (which prevents
removing pre-existing "self-ref" linedefs).  Also store them in a
selection_c.

------------------------------------------------------------------------
r173 | ajapted | 2012-11-15 10:30:24 +1100 (Thu, 15 Nov 2012) | 2 lines

Editor_Key: ensure the new 'm' merge command can only be used in Sectors mode.

------------------------------------------------------------------------
r172 | ajapted | 2012-11-14 22:29:26 +1100 (Wed, 14 Nov 2012) | 2 lines

Render 3D: made ALT + LEFT / RIGHT keys strafe instead of turn.

------------------------------------------------------------------------
r171 | ajapted | 2012-11-14 22:22:53 +1100 (Wed, 14 Nov 2012) | 2 lines

TODO / WISHLIST update.

------------------------------------------------------------------------
r170 | ajapted | 2012-11-14 19:46:24 +1100 (Wed, 14 Nov 2012) | 3 lines

Sector mode: implemented 'm' merge command which merges all selected
sectors into a single one.  The 'M' variant will keep common linedefs,

------------------------------------------------------------------------
r169 | ajapted | 2012-11-14 19:04:33 +1100 (Wed, 14 Nov 2012) | 4 lines

Sector mode: reworked handling of SPACE / INSERT key:
1. when a sector is highlighted, assume want to "correct" that sector
2. force insertion of a NEW sector via CTRL key

------------------------------------------------------------------------
r168 | ajapted | 2012-11-14 16:43:28 +1100 (Wed, 14 Nov 2012) | 2 lines

CHANGELOG: mention the recent vertex-insertion changes.

------------------------------------------------------------------------
r167 | ajapted | 2012-11-14 16:38:50 +1100 (Wed, 14 Nov 2012) | 4 lines

Vertex insertion: handle the case where a new vertex would split a line
and the selected vertex is an endpoint of that line -- simply split the
line (as if no vertex had been selected).

------------------------------------------------------------------------
r166 | ajapted | 2012-11-14 15:13:36 +1100 (Wed, 14 Nov 2012) | 3 lines

Vertex insertion: improved overlap test, refuse the operation for the
case of adding a line between old --> new vertex.

------------------------------------------------------------------------
r165 | ajapted | 2012-11-14 15:05:55 +1100 (Wed, 14 Nov 2012) | 3 lines

Vertex insertion: prevent adding a new linedef if it would overlap an
existing line.

------------------------------------------------------------------------
r164 | ajapted | 2012-11-14 14:57:12 +1100 (Wed, 14 Nov 2012) | 2 lines

Basis: added LineDef::CalcLength() method.

------------------------------------------------------------------------
r163 | ajapted | 2012-11-14 14:37:34 +1100 (Wed, 14 Nov 2012) | 7 lines

Vertex insertion:
1. if one vertex is selected and it is highlighted (or new position
   is snapped to same coord), then merely de-select it.

2. if two is selected (or one + highlight) and the linedef already
   exists, then merely select the second and deselect the first.

------------------------------------------------------------------------
r162 | ajapted | 2012-11-13 21:49:26 +1100 (Tue, 13 Nov 2012) | 4 lines

When closing a simple vertex loop which is inside an existing sector,
now create a sector on the inside of the loop (instead of creating a
pillar).  Eventually this will be a config option.

------------------------------------------------------------------------
r161 | ajapted | 2012-11-13 21:38:21 +1100 (Tue, 13 Nov 2012) | 2 lines

Removed obsolete CopyObjects() code.

------------------------------------------------------------------------
r160 | ajapted | 2012-11-13 21:35:03 +1100 (Tue, 13 Nov 2012) | 2 lines

Fully disabled some usage of 'SelPtr' which I missed before.

------------------------------------------------------------------------
r159 | ajapted | 2012-11-13 21:34:09 +1100 (Tue, 13 Nov 2012) | 2 lines

Disabled 'c' and 'm' keys, they are about to be re-purposed...

------------------------------------------------------------------------
r158 | ajapted | 2012-11-13 21:32:18 +1100 (Tue, 13 Nov 2012) | 2 lines

Removed obsolete DoInsertObject() code.

------------------------------------------------------------------------
r157 | ajapted | 2012-11-13 21:13:09 +1100 (Tue, 13 Nov 2012) | 2 lines

TODO: hammered out new logic for Sector creation / correction / copying.

------------------------------------------------------------------------
r156 | ajapted | 2012-11-13 20:07:29 +1100 (Tue, 13 Nov 2012) | 2 lines

TODO / WISHLIST update.

------------------------------------------------------------------------
r155 | ajapted | 2012-11-13 20:01:09 +1100 (Tue, 13 Nov 2012) | 2 lines

Removed obsolete ymemory.cc/h code files.

------------------------------------------------------------------------
r154 | ajapted | 2012-11-13 19:59:06 +1100 (Tue, 13 Nov 2012) | 6 lines

Config code:
1. define a string_list_t type using std::vector
2. rewrote OPT_STRING_LIST handling to use string_list_t
3. removed append_item_to_list() function
4. replaced a usage of GetMemory() with StringDup()

------------------------------------------------------------------------
r153 | ajapted | 2012-11-13 17:25:09 +1100 (Tue, 13 Nov 2012) | 3 lines

Removed the 'SelPtr' type once and for all.  Disabled various pieces of
code which was using it (most of that was disabled already).

------------------------------------------------------------------------
r152 | ajapted | 2012-11-13 17:22:23 +1100 (Tue, 13 Nov 2012) | 2 lines

Removed unused bv_vertices_of_sectors() code.

------------------------------------------------------------------------
r151 | ajapted | 2012-11-13 17:21:33 +1100 (Tue, 13 Nov 2012) | 2 lines

Removed obsolete list_to_bitvec() and bitvec_to_list() functions.

------------------------------------------------------------------------
r150 | ajapted | 2012-11-13 17:16:34 +1100 (Tue, 13 Nov 2012) | 2 lines

Removed unused linedefs_of_sectors() code.

------------------------------------------------------------------------
r149 | ajapted | 2012-11-13 17:14:13 +1100 (Tue, 13 Nov 2012) | 2 lines

Removed unused unlink_sidedef() code.

------------------------------------------------------------------------
r148 | ajapted | 2012-11-13 17:06:16 +1100 (Tue, 13 Nov 2012) | 2 lines

Removed obsolete MoveObjectsToCoord() code.

------------------------------------------------------------------------
r147 | ajapted | 2012-11-13 17:05:37 +1100 (Tue, 13 Nov 2012) | 3 lines

Removed obsolete list_vertices_of_xxxs() functions.
Removed obsolete bv_vertices_of_linedefs(SelPtr) function.

------------------------------------------------------------------------
r146 | ajapted | 2012-11-13 16:57:27 +1100 (Tue, 13 Nov 2012) | 3 lines

Removed unused (and mostly broken) centre_of_xxxs functions.
Only one left is centre_of_sector(), which is actually used and works.

------------------------------------------------------------------------
r145 | ajapted | 2012-11-13 16:51:55 +1100 (Tue, 13 Nov 2012) | 2 lines

Removed old/unused/disabled MergeVertices() and AutoMergeVertices() code.

------------------------------------------------------------------------
r144 | ajapted | 2012-11-13 16:50:06 +1100 (Tue, 13 Nov 2012) | 2 lines

Removed obsolete RotateAndScaleObjects() code.

------------------------------------------------------------------------
r143 | ajapted | 2012-11-13 16:09:46 +1100 (Tue, 13 Nov 2012) | 2 lines

Removed a bunch of unused stuff from editobj.cc/h

------------------------------------------------------------------------
r142 | ajapted | 2012-11-12 22:32:18 +1100 (Mon, 12 Nov 2012) | 2 lines

Fleshed out the INSTALL.txt document.

------------------------------------------------------------------------
r141 | ajapted | 2012-11-12 21:12:28 +1100 (Mon, 12 Nov 2012) | 3 lines

CMD_BuildNodes: show an error message if edit_wad has ".new" extension
(otherwise the delete + rename logic is going to fail).

------------------------------------------------------------------------
r140 | ajapted | 2012-11-12 21:10:03 +1100 (Mon, 12 Nov 2012) | 2 lines

File utils: renamed CheckExtension() --> MatchExtension()

------------------------------------------------------------------------
r139 | ajapted | 2012-11-12 20:24:27 +1100 (Mon, 12 Nov 2012) | 3 lines

CMD_BuildNodes: fixed bug where 'old_name' became invalid rubbish because
the edit_wad object was deleted.

------------------------------------------------------------------------
r138 | ajapted | 2012-11-12 16:10:50 +1100 (Mon, 12 Nov 2012) | 5 lines

CMD_BuildNodes:
1. use proper output name, replacing extension with ".new"
2. delete the ".new" file if the build was unsuccessful (cancel or error)
3. if successful, delete old file and rename new file to old filename

------------------------------------------------------------------------
r137 | ajapted | 2012-11-12 16:08:05 +1100 (Mon, 12 Nov 2012) | 1 line

tweak
------------------------------------------------------------------------
r136 | ajapted | 2012-11-12 14:50:31 +1100 (Mon, 12 Nov 2012) | 3 lines

CMD_BuildNodes: added proper (albeit simplistic) dialogs when the user
tries to build nodes without any PWAD, or when there are unsaved changes.

------------------------------------------------------------------------
r135 | ajapted | 2012-11-12 14:41:23 +1100 (Mon, 12 Nov 2012) | 4 lines

CMD_BuildNodes: properly split lines in UI_Nodes::Add() method.

Also: added a blank line before each error message.

------------------------------------------------------------------------
r134 | ajapted | 2012-11-12 14:33:49 +1100 (Mon, 12 Nov 2012) | 2 lines

CHANGELOG: added entry for the new node building feature.

------------------------------------------------------------------------
r133 | ajapted | 2012-11-12 14:27:34 +1100 (Mon, 12 Nov 2012) | 3 lines

CMD_BuildNodes: handle the ESCAPE key better -- if not finished then
cancel the build, otherwise close the window.

------------------------------------------------------------------------
r132 | ajapted | 2012-11-12 14:26:38 +1100 (Mon, 12 Nov 2012) | 1 line

whitespacing
------------------------------------------------------------------------
r131 | ajapted | 2012-11-12 13:17:48 +1100 (Mon, 12 Nov 2012) | 6 lines

CMD_BuildNodes:
1. support the CLOSE button and Cancel button in UI_Nodes
2. cancel the build when user wants to cancel (or close the window)
3. show final status (Success/Cancel/ERROR) in the progress bar
4. on success, use CMD_Quit to exit Eureka

------------------------------------------------------------------------
r130 | ajapted | 2012-11-12 11:32:55 +1100 (Mon, 12 Nov 2012) | 6 lines

CMD_BuildNodes:
1. added and implemented the progress bar
2. added 'Cancel' button (not working yet)
3. move text browser to bottom for each Add()
4. tidy up of glbsp callbacks

------------------------------------------------------------------------
r129 | ajapted | 2012-11-11 22:37:48 +1100 (Sun, 11 Nov 2012) | 3 lines

CMD_BuildNodes: use Fl::check() to ensure window gets shown before the
node building begins.

------------------------------------------------------------------------
r128 | ajapted | 2012-11-11 22:28:37 +1100 (Sun, 11 Nov 2012) | 2 lines

Version bump to 0.81

------------------------------------------------------------------------
r127 | ajapted | 2012-11-11 22:27:04 +1100 (Sun, 11 Nov 2012) | 2 lines

svn:ignore

------------------------------------------------------------------------
r126 | ajapted | 2012-11-11 22:14:56 +1100 (Sun, 11 Nov 2012) | 2 lines

TODO tidy up.

------------------------------------------------------------------------
r125 | ajapted | 2012-11-11 21:50:49 +1100 (Sun, 11 Nov 2012) | 2 lines

Makefile: added ui_nodes.o to the build.

------------------------------------------------------------------------
r124 | ajapted | 2012-11-11 21:50:23 +1100 (Sun, 11 Nov 2012) | 2 lines

CMD_BuildNodes: bit more work on dialog window....

------------------------------------------------------------------------
r123 | ajapted | 2012-11-11 21:24:40 +1100 (Sun, 11 Nov 2012) | 2 lines

CMD_BuildNodes: handle the "(Hexen)" suffix when determining map name.

------------------------------------------------------------------------
r122 | ajapted | 2012-11-11 21:22:48 +1100 (Sun, 11 Nov 2012) | 4 lines

Initial work on a UI_NodeDialog window, which will show the progress of
building nodes and the output from the node builder, as well as have
CANCEL and OK buttons.  Very skeletal so far....

------------------------------------------------------------------------
r121 | ajapted | 2012-11-11 20:56:55 +1100 (Sun, 11 Nov 2012) | 2 lines

CMD_BuildNodes: extract map name from progress-bar text.

------------------------------------------------------------------------
r120 | ajapted | 2012-11-11 20:50:14 +1100 (Sun, 11 Nov 2012) | 3 lines

CMD_BuildNodes: added interface code to glBSP and the function which does
all the heavy lifting (DM_BuildNodes).  Mainly copy'n'paste from OBLIGE.

------------------------------------------------------------------------
r119 | ajapted | 2012-11-11 20:26:20 +1100 (Sun, 11 Nov 2012) | 4 lines

Makefile: logic for building and linking the glBSP code.

Also added conditional lines for FLTK in a non-standard place.

------------------------------------------------------------------------
r118 | ajapted | 2012-11-11 20:21:46 +1100 (Sun, 11 Nov 2012) | 2 lines

Deleted Makefile.opt -- added the extra bits into 'Makefile' (in a conditional section).

------------------------------------------------------------------------
r117 | ajapted | 2012-11-11 19:15:58 +1100 (Sun, 11 Nov 2012) | 4 lines

glbsp code: encapsulated all code into a 'glbsp' namespace.

Also removed the 'Glbsp' prefix from a few API functions.

------------------------------------------------------------------------
r116 | ajapted | 2012-11-11 19:00:47 +1100 (Sun, 11 Nov 2012) | 2 lines

Checked in a copy of glBSP 2.27 source code.

------------------------------------------------------------------------
r115 | ajapted | 2012-11-11 18:25:04 +1100 (Sun, 11 Nov 2012) | 2 lines

CMD_BuildNodes: make sure we have a PWAD.

------------------------------------------------------------------------
r114 | ajapted | 2012-11-11 16:53:06 +1100 (Sun, 11 Nov 2012) | 4 lines

Preliminary work on "Build Nodes" command (in File menu, CTRL-B key).
This will invoke an external nodes builder (glbsp for now), show the
output, then quit.

------------------------------------------------------------------------
r113 | ajapted | 2012-11-10 23:10:38 +1100 (Sat, 10 Nov 2012) | 3 lines

1. Keyboard shortcuts T/F/O/S/L open browser at specific kind
2. Made MIN_BROWSER_W a bit narrower (280 --> 260)

------------------------------------------------------------------------
r112 | ajapted | 2012-11-10 23:08:54 +1100 (Sat, 10 Nov 2012) | 2 lines

Browser: tweaked position of 'Pics' button.

------------------------------------------------------------------------
r111 | ajapted | 2012-11-10 22:35:25 +1100 (Sat, 10 Nov 2012) | 2 lines

Added 'INSTALL.txt' document (mostly empty).

------------------------------------------------------------------------
r110 | ajapted | 2012-11-10 22:16:58 +1100 (Sat, 10 Nov 2012) | 2 lines

Tweaked calculations in zoom_fit().

------------------------------------------------------------------------
r109 | ajapted | 2012-11-10 22:16:17 +1100 (Sat, 10 Nov 2012) | 2 lines

Fixed initial zoom (it was computed while browser was still present).

------------------------------------------------------------------------
r108 | ajapted | 2012-11-10 21:57:45 +1100 (Sat, 10 Nov 2012) | 3 lines

Makefiles: updated 'install' target with commands to install the desktop
and icon files, using the XDG tools (in the xdg-utils package).

------------------------------------------------------------------------
r107 | ajapted | 2012-11-10 21:11:24 +1100 (Sat, 10 Nov 2012) | 3 lines

DESKTOP file: Removed 'Application' from Categories, as the
desktop-file-validate program warned it was deprecated.

------------------------------------------------------------------------
r106 | ajapted | 2012-11-10 19:47:55 +1100 (Sat, 10 Nov 2012) | 2 lines

Desktop file: added StartupNotify=false

------------------------------------------------------------------------
r105 | ajapted | 2012-11-10 19:07:08 +1100 (Sat, 10 Nov 2012) | 2 lines

TODO and CHANGELOG update.

------------------------------------------------------------------------
r104 | ajapted | 2012-11-10 18:45:49 +1100 (Sat, 10 Nov 2012) | 4 lines

In game defs, allow texture and flat group to be uppercase, and match
these against the 'X' category.  This is a very simple way to allow
textures and flats to belong (or not) to one additional group.

------------------------------------------------------------------------
r103 | ajapted | 2012-11-10 18:41:05 +1100 (Sat, 10 Nov 2012) | 2 lines

Browser: made initial width a bit wider (show 4 flats instead of 3).

------------------------------------------------------------------------
r102 | ajapted | 2012-11-10 17:15:25 +1100 (Sat, 10 Nov 2012) | 2 lines

DOOM game def: assigned SKY1/2/3 and F_SKY1 into 'Natural' category.

------------------------------------------------------------------------
r101 | ajapted | 2012-11-10 16:42:14 +1100 (Sat, 10 Nov 2012) | 2 lines

PLUTONIA game defs: assigned categories for all the new textures.

------------------------------------------------------------------------
r100 | ajapted | 2012-11-10 16:24:53 +1100 (Sat, 10 Nov 2012) | 3 lines

TNT game def: placed all the new TNT textures into categories, including
two new categories "Crates" and "Egypt".

------------------------------------------------------------------------
r99 | ajapted | 2012-11-10 15:37:20 +1100 (Sat, 10 Nov 2012) | 3 lines

DOOM defs: fixed the 'SW2XXX' textures which were lacking a category
line for them -- should be same as their 'SW1' counterparts.

------------------------------------------------------------------------
r98 | ajapted | 2012-11-10 15:32:18 +1100 (Sat, 10 Nov 2012) | 2 lines

CHANGELOG: tweaked layout (use two spaces)

------------------------------------------------------------------------
r97 | ajapted | 2012-11-10 15:21:22 +1100 (Sat, 10 Nov 2012) | 2 lines

Update for TODO.txt and CHANGES.txt

------------------------------------------------------------------------
r96 | ajapted | 2012-11-10 15:18:45 +1100 (Sat, 10 Nov 2012) | 4 lines

Render: strafe left/right when the ALT (or META) key is pressed
(in addition to the RMB).  It is not ideal, since window manager
will typically steal the ALT + RMB combination for themselves.

------------------------------------------------------------------------
r95 | ajapted | 2012-11-10 15:00:50 +1100 (Sat, 10 Nov 2012) | 3 lines

When searching for IWADs, check for uppercase'd name (like "DOOM.WAD").
This also required lowercasing it when determining the Game name.

------------------------------------------------------------------------
r94 | ajapted | 2012-11-10 14:56:50 +1100 (Sat, 10 Nov 2012) | 2 lines

Utils: added y_strlowr() and rewrote y_strupr().

------------------------------------------------------------------------
r93 | ajapted | 2012-11-10 14:34:50 +1100 (Sat, 10 Nov 2012) | 6 lines

Improved IWAD finding logic:
1. if the -iwad parameter has no extension, add ".wad"
2. if the -iwad parameter is a bare name, look in iwad search path
3. added ~/.eureka/iwads directory to search path
4. when searching, look for other iwad names (e.g. "doom.wad" and "tnt.wad")

------------------------------------------------------------------------
r92 | ajapted | 2012-11-10 13:54:12 +1100 (Sat, 10 Nov 2012) | 3 lines

1. Require a valid home_dir
2. Create extra subdirs in the home dir ("iwads/", "games/" etc)

------------------------------------------------------------------------
r91 | ajapted | 2012-11-10 13:26:44 +1100 (Sat, 10 Nov 2012) | 3 lines

Refactored code into DetermineLevel() for finding what level to use,
and added support for plain numbers (e.g. -warp 15).

------------------------------------------------------------------------
r90 | ajapted | 2012-11-10 13:23:20 +1100 (Sat, 10 Nov 2012) | 3 lines

WAD code: implemented FindLevelByNumber() method for Wad_file, which
will look for a match against "MAP##" or "E#M#" level names.

------------------------------------------------------------------------
r89 | ajapted | 2012-11-10 12:57:00 +1100 (Sat, 10 Nov 2012) | 2 lines

When level name is not specified, find the first one in the PWAD or IWAD.

------------------------------------------------------------------------
r88 | ajapted | 2012-11-10 12:12:27 +1100 (Sat, 10 Nov 2012) | 2 lines

WAD code: added API for reading level list.

------------------------------------------------------------------------
r87 | ajapted | 2012-11-10 12:07:55 +1100 (Sat, 10 Nov 2012) | 2 lines

WAD code: added 'FindFirstLevel' method to Wad_file class.

------------------------------------------------------------------------
r86 | ajapted | 2012-11-10 11:57:50 +1100 (Sat, 10 Nov 2012) | 3 lines

1. renamed Editor_Loop --> Main_Loop, moved into main.cc
2. start with browser disabled (turn off after creating main_win)

------------------------------------------------------------------------
r85 | ajapted | 2012-11-09 23:08:49 +1100 (Fri, 09 Nov 2012) | 3 lines

UI_Scroll: use clip_children(1) to prevent contents from drawing over
other parts of the GUI.

------------------------------------------------------------------------
r84 | ajapted | 2012-11-09 22:54:44 +1100 (Fri, 09 Nov 2012) | 2 lines

Browser: tweaked layout of images

------------------------------------------------------------------------
r83 | ajapted | 2012-11-09 22:41:21 +1100 (Fri, 09 Nov 2012) | 2 lines

UI_Scroll: added ability to horizontally resize child widgets.

------------------------------------------------------------------------
r82 | ajapted | 2012-11-09 22:21:17 +1100 (Fri, 09 Nov 2012) | 2 lines

UI_Scroll: make sure scrollbar gets vertically resized.

------------------------------------------------------------------------
r81 | ajapted | 2012-11-09 22:18:41 +1100 (Fri, 09 Nov 2012) | 2 lines

UI_Scroll: fixed Remove_first() which erroneously removed the scrollbar.

------------------------------------------------------------------------
r80 | ajapted | 2012-11-09 21:42:46 +1100 (Fri, 09 Nov 2012) | 4 lines

UI_Scroll: made it a subclass of Fl_Group (it is not really possible
with FLTK to make container widgets any other way).  Renamed the group
like methods to use an uppercase letter (Add, Remove, Init_Sizes, etc).

------------------------------------------------------------------------
r79 | ajapted | 2012-11-08 21:52:31 +1100 (Thu, 08 Nov 2012) | 2 lines

UI_Scroll: more work on scrolling -- it is working pretty well now.

------------------------------------------------------------------------
r78 | ajapted | 2012-11-08 19:29:29 +1100 (Thu, 08 Nov 2012) | 2 lines

UI_Scroll: got ability to scroll working, via new reposition_all() method.

------------------------------------------------------------------------
r77 | ajapted | 2012-11-08 19:20:12 +1100 (Thu, 08 Nov 2012) | 4 lines

UI_Scroll: the init_sizes() method now calculates the bottom of all child
widgets.  Added a callback for the scrollbar (all it does currently is
redraw).

------------------------------------------------------------------------
r76 | ajapted | 2012-11-08 15:57:56 +1100 (Thu, 08 Nov 2012) | 2 lines

Browser: added an undrawn resize box to control resizing.

------------------------------------------------------------------------
r75 | ajapted | 2012-11-07 20:38:29 +1100 (Wed, 07 Nov 2012) | 2 lines

UI_Scroll: draw the box.

------------------------------------------------------------------------
r74 | ajapted | 2012-11-07 20:00:02 +1100 (Wed, 07 Nov 2012) | 4 lines

Browser: partial work to transition to new UI_Scroll widget, renamed
the 'pack' field --> 'scroll', removed the resize_buttons() and
fix_scrollbar_order() hacks, and disabled a few things.

------------------------------------------------------------------------
r73 | ajapted | 2012-11-07 19:57:38 +1100 (Wed, 07 Nov 2012) | 3 lines

UI_Scroll widget: fleshed out some methods, and added a few delegates
e.g. children() which merely passes through to pack->children().

------------------------------------------------------------------------
r72 | ajapted | 2012-11-07 19:37:48 +1100 (Wed, 07 Nov 2012) | 5 lines

Browser: update the image list when resized (reposition them).

This commit includes an attempt to get text buttons horizontally resized,
but it doesn't work since Fl_Scroll is an utter piece of crap.

------------------------------------------------------------------------
r71 | ajapted | 2012-11-07 19:12:17 +1100 (Wed, 07 Nov 2012) | 2 lines

Began work on a decent scroll widget (Fl_Scroll is fucked).

------------------------------------------------------------------------
r70 | ajapted | 2012-11-07 15:35:01 +1100 (Wed, 07 Nov 2012) | 3 lines

Browser: tweak to size and layout, e.g. moved 'X' button to left side and
added invisible resize box to the right.

------------------------------------------------------------------------
r69 | ajapted | 2012-11-07 14:50:30 +1100 (Wed, 07 Nov 2012) | 3 lines

Fixed UI_Tile event propagation, the FL_NO_BOX 'limiter' was stealing
events from the canvas widget.

------------------------------------------------------------------------
r68 | ajapted | 2012-11-07 14:03:40 +1100 (Wed, 07 Nov 2012) | 2 lines

CHANGELOG: added browser resize feature.

------------------------------------------------------------------------
r67 | ajapted | 2012-11-07 14:03:23 +1100 (Wed, 07 Nov 2012) | 2 lines

TODO update.

------------------------------------------------------------------------
r66 | ajapted | 2012-11-07 14:00:09 +1100 (Wed, 07 Nov 2012) | 4 lines

Implemented the resize behavior of UI_Tile, which tries to maintain the
width of the right widget (the browser), and remembers that width when
it is hidden so it can be restored.

------------------------------------------------------------------------
r65 | ajapted | 2012-11-07 13:36:41 +1100 (Wed, 07 Nov 2012) | 3 lines

Implemented new method to show/hide the browser (methods of UI_Tile).
Did a bit of work on resize() behavior and handling the limiter box.

------------------------------------------------------------------------
r64 | ajapted | 2012-11-07 13:15:51 +1100 (Wed, 07 Nov 2012) | 2 lines

Use the new UI_Tile widget (constructing the main window).

------------------------------------------------------------------------
r63 | ajapted | 2012-11-07 13:08:37 +1100 (Wed, 07 Nov 2012) | 3 lines

Began work on UI_Tile widget, a variant on Fl_Tile which will provide
better resize behavior and handle the ability to show/hide the browser.

------------------------------------------------------------------------
r62 | ajapted | 2012-11-07 11:10:45 +1100 (Wed, 07 Nov 2012) | 2 lines

Added a basic logo image.

------------------------------------------------------------------------
r61 | ajapted | 2012-11-07 11:09:50 +1100 (Wed, 07 Nov 2012) | 2 lines

Added a basic icon: eureka.xpm

------------------------------------------------------------------------
r60 | ajapted | 2012-11-01 18:46:49 +1100 (Thu, 01 Nov 2012) | 2 lines

Created a basic .desktop file.

------------------------------------------------------------------------
r59 | ajapted | 2012-11-01 18:41:01 +1100 (Thu, 01 Nov 2012) | 2 lines

Added top-level 'misc' folder.

------------------------------------------------------------------------
r58 | ajapted | 2012-11-01 12:45:39 +1100 (Thu, 01 Nov 2012) | 2 lines

Ignore blank/comment lines in persistent data files.

------------------------------------------------------------------------
r57 | ajapted | 2012-11-01 12:43:41 +1100 (Thu, 01 Nov 2012) | 2 lines

Create the cache folder (in home_dir).

------------------------------------------------------------------------
r56 | ajapted | 2012-11-01 12:42:39 +1100 (Thu, 01 Nov 2012) | 2 lines

Use proper path for cache data (i.e. home_dir).

------------------------------------------------------------------------
r55 | ajapted | 2012-10-25 15:04:11 +1100 (Thu, 25 Oct 2012) | 2 lines

TODO update / tidy up.

------------------------------------------------------------------------
r54 | ajapted | 2012-10-25 15:03:21 +1100 (Thu, 25 Oct 2012) | 4 lines

Config: improved output of dump_command_line_options(), use new 'arg_desc'
field of option structure to provide a short description of the argument
which the option takes.  Reordered the list, and removed 'is_file' thang.

------------------------------------------------------------------------
r53 | ajapted | 2012-10-25 12:11:49 +1100 (Thu, 25 Oct 2012) | 4 lines

Game defs: look in the "common" folder when an UGH file is not found in the
specified folder (like "games").  This is mainly for include directives,
and needed for the recent move of shared files to the common folder.

------------------------------------------------------------------------
r52 | ajapted | 2012-10-25 10:47:57 +1100 (Thu, 25 Oct 2012) | 2 lines

Makefiles: install the new 'common' folder.

------------------------------------------------------------------------
r51 | ajapted | 2012-10-25 10:47:22 +1100 (Thu, 25 Oct 2012) | 2 lines

Moved 'doom_specials.ugh' and 'doom_common.ugh' --> common/ folder.

------------------------------------------------------------------------
r50 | ajapted | 2012-10-25 10:44:04 +1100 (Thu, 25 Oct 2012) | 2 lines

Added 'common' folder -- for definitions shared between game defs.

------------------------------------------------------------------------
r49 | ajapted | 2012-10-24 23:37:44 +1100 (Wed, 24 Oct 2012) | 2 lines

TODO update.

------------------------------------------------------------------------
r48 | ajapted | 2012-10-24 20:08:49 +1100 (Wed, 24 Oct 2012) | 3 lines

Improved dump_command_line_options(), entries need 'h' flag to be displayed,
and the '<' flag prints a line break.

------------------------------------------------------------------------
r47 | ajapted | 2012-10-24 19:46:43 +1100 (Wed, 24 Oct 2012) | 2 lines

Implemented the --help and --version options.

------------------------------------------------------------------------
r46 | ajapted | 2012-10-24 18:08:40 +1100 (Wed, 24 Oct 2012) | 2 lines

tweak to error dialog.

------------------------------------------------------------------------
r45 | ajapted | 2012-10-24 18:06:28 +1100 (Wed, 24 Oct 2012) | 2 lines

Config: better handling of lines with extraneous arguments.

------------------------------------------------------------------------
r44 | ajapted | 2012-10-24 17:22:27 +1100 (Wed, 24 Oct 2012) | 6 lines

Config handling:
1. simplified OPT_BOOLEAN handling in config files
2. added "WARNING" prefix to some log messages
3. replaced '\0' with 0
4. renamed OPT_STRINGPTRLIST --> OPT_STRING_LIST (etc).

------------------------------------------------------------------------
r43 | ajapted | 2012-10-24 17:05:37 +1100 (Wed, 24 Oct 2012) | 4 lines

Config handling:
1. use FatalError() instead of LogPrintf() for some stuff
2. removed OPT_STRINGPTRACC and OPT_UNSIGNED -- simplify the code.

------------------------------------------------------------------------
r42 | ajapted | 2012-10-24 16:42:03 +1100 (Wed, 24 Oct 2012) | 2 lines

Error handling polishing.

------------------------------------------------------------------------
r41 | ajapted | 2012-10-24 15:03:14 +1100 (Wed, 24 Oct 2012) | 3 lines

Added code files 'ui_dialog' which implements DLG_ShowError().
Source was OBLIGE code.

------------------------------------------------------------------------
r40 | ajapted | 2012-10-24 14:56:22 +1100 (Wed, 24 Oct 2012) | 2 lines

FatalError: print message to log file and call DLG_ShowError().

------------------------------------------------------------------------
r39 | ajapted | 2012-10-24 14:49:11 +1100 (Wed, 24 Oct 2012) | 2 lines

Wad: imlemented MasterDir_CloseAll() function.

------------------------------------------------------------------------
r38 | ajapted | 2012-10-23 22:09:18 +1100 (Tue, 23 Oct 2012) | 2 lines

Worked on improving the FatalError() logic....

------------------------------------------------------------------------
r37 | ajapted | 2012-10-23 21:33:42 +1100 (Tue, 23 Oct 2012) | 2 lines

Added 'CHANGES.txt' document -- keep track of recent changes.

------------------------------------------------------------------------
r36 | ajapted | 2012-10-23 20:50:09 +1100 (Tue, 23 Oct 2012) | 2 lines

Removed last vestiges of err() function.

------------------------------------------------------------------------
r35 | ajapted | 2012-10-23 19:31:30 +1100 (Tue, 23 Oct 2012) | 5 lines

Config:
1. replace err() with LogPrintf()
2. show strerror(errno) in some messages
3. fixed warnings about && inside ||

------------------------------------------------------------------------
r34 | ajapted | 2012-10-22 22:31:16 +1100 (Mon, 22 Oct 2012) | 2 lines

Made 'BugError' just be an alias for FatalError().

------------------------------------------------------------------------
r33 | ajapted | 2012-10-22 22:24:52 +1100 (Mon, 22 Oct 2012) | 2 lines

Replaced 'warn' function with LogPrintf.

------------------------------------------------------------------------
r32 | ajapted | 2012-10-22 22:11:12 +1100 (Mon, 22 Oct 2012) | 3 lines

Config: fixed crashing bug with handling loose files (argv and argc were
not iterated properly).  The same bug also exists in Yadex 1.7.0.

------------------------------------------------------------------------
r31 | ajapted | 2012-10-22 20:47:18 +1100 (Mon, 22 Oct 2012) | 2 lines

Config: tweaked handling of loose files, and code reformatting.

------------------------------------------------------------------------
r30 | ajapted | 2012-10-22 20:44:08 +1100 (Mon, 22 Oct 2012) | 3 lines

Config: removed hack of first entry in options[] being used for loose
filenames.  Instead handle them explicitly.

------------------------------------------------------------------------
r29 | ajapted | 2012-10-22 20:26:52 +1100 (Mon, 22 Oct 2012) | 2 lines

Makefiles: prevent an install error (since there are currently no mods).

------------------------------------------------------------------------
r28 | ajapted | 2012-10-22 20:25:40 +1100 (Mon, 22 Oct 2012) | 3 lines

About box: tweaked Yadex reference -- I don't want to give the impression
that Eureka is a continuation of Yadex or is compatible with Yadex.

------------------------------------------------------------------------
r27 | ajapted | 2012-10-22 19:46:27 +1100 (Mon, 22 Oct 2012) | 3 lines

Docs: added History_1.txt and History_2.txt -- contains the commit history
from the EDGE repository and AwwPorts repository (respectively).

------------------------------------------------------------------------
r26 | ajapted | 2012-10-22 17:19:19 +1100 (Mon, 22 Oct 2012) | 2 lines

Makefiles: install the 'mods' folder too (like 'games' and 'ports').

------------------------------------------------------------------------
r25 | ajapted | 2012-10-22 17:15:34 +1100 (Mon, 22 Oct 2012) | 2 lines

Use DebugPrintf() in most places instead of fprintf(stderr).

------------------------------------------------------------------------
r24 | ajapted | 2012-10-22 17:04:23 +1100 (Mon, 22 Oct 2012) | 2 lines

Config: fixed --log option (had wrong type, BOOLEAN).

------------------------------------------------------------------------
r23 | ajapted | 2012-10-22 15:47:00 +1100 (Mon, 22 Oct 2012) | 3 lines

Version bumped to 0.80, in honor of creating a real sourceforge project
and installation of the pmwiki web-site (etc).

------------------------------------------------------------------------
r22 | ajapted | 2012-10-22 15:44:45 +1100 (Mon, 22 Oct 2012) | 3 lines

Log file: when output is the terminal, don't print the '=== START OF LOGS ==='
message and similar end message.

------------------------------------------------------------------------
r21 | ajapted | 2012-10-22 15:39:15 +1100 (Mon, 22 Oct 2012) | 3 lines

Config files: re-implemented the parse_config_file_user() and
parse_config_file_default() functions.

------------------------------------------------------------------------
r20 | ajapted | 2012-10-22 15:22:57 +1100 (Mon, 22 Oct 2012) | 2 lines

tweakage and movage.

------------------------------------------------------------------------
r19 | ajapted | 2012-10-22 14:22:15 +1100 (Mon, 22 Oct 2012) | 8 lines

Rework of log file handling:
1. the --log option specifies a log file, use stdout as fallback
2. the --quiet option suppresses the stdout fallback
3. be sure to LogClose() in error handlers
4. added --debug option to enable debug messages
5. debug messages either go to log file (if used), else stderr
6. added 'init_progress' global var

------------------------------------------------------------------------
r18 | ajapted | 2012-10-22 13:28:25 +1100 (Mon, 22 Oct 2012) | 2 lines

Options: better handling of --version (same way as --help).

------------------------------------------------------------------------
r17 | ajapted | 2012-10-22 13:21:45 +1100 (Mon, 22 Oct 2012) | 2 lines

Removed unused 'Quieter' option / var.

------------------------------------------------------------------------
r16 | ajapted | 2012-10-21 22:35:58 +1100 (Sun, 21 Oct 2012) | 8 lines

Option parsing:
1. revert previous commit, the 'long_name' can now be used with either
   single or double dashes (e.g. --iwad or just -iwad).  I remembered
   that the options were meant to mimic what DOOM.EXE accepts.
2. handle --version a bit better
3. provide short options for common options: -f (-file), -w (-warp), etc..
4. reordered entries in options[] table, more common ones near the top.

------------------------------------------------------------------------
r15 | ajapted | 2012-10-21 22:14:51 +1100 (Sun, 21 Oct 2012) | 3 lines

Option parsing: require short options be a single letter, and long options
begin with double dashes, e.g. --iwad.

------------------------------------------------------------------------
r14 | ajapted | 2012-10-21 21:58:22 +1100 (Sun, 21 Oct 2012) | 4 lines

1. Determine home_dir/install_dir BEFORE parsing config files or normal options
2. Support --home and --install options (override the automatic logic)
3. Renamed --config_file to just --config

------------------------------------------------------------------------
r13 | ajapted | 2012-10-21 21:21:47 +1100 (Sun, 21 Oct 2012) | 4 lines

Look for ".ugh" definition files in two places: (1) home_dir and (2) install_dir.
(In that order too).  This is part of the transition to using proper unixy
file location conventions.

------------------------------------------------------------------------
r12 | ajapted | 2012-10-21 21:16:40 +1100 (Sun, 21 Oct 2012) | 2 lines

Added 'mods' folder (empty).

------------------------------------------------------------------------
r11 | ajapted | 2012-10-20 22:26:52 +1100 (Sat, 20 Oct 2012) | 2 lines

Show the home_dir and install_dir (on stderr), and reformatted that code.

------------------------------------------------------------------------
r10 | ajapted | 2012-10-20 22:17:41 +1100 (Sat, 20 Oct 2012) | 3 lines

Added new code files 'lib_file.*' -- contain various file utilities.
Source was OBLIGE code, reformatted and tweaked.

------------------------------------------------------------------------
r9 | ajapted | 2012-10-20 22:07:20 +1100 (Sat, 20 Oct 2012) | 3 lines

Added the following string utilities (from OBLIGE code) :
   StringNew(), StringDup(), StringPrintf(), StringFree().

------------------------------------------------------------------------
r8 | ajapted | 2012-10-20 22:00:56 +1100 (Sat, 20 Oct 2012) | 2 lines

Renamed code files: yutil.* --> lib_util.*

------------------------------------------------------------------------
r7 | ajapted | 2012-10-20 21:48:47 +1100 (Sat, 20 Oct 2012) | 3 lines

Added 'home_dir' and 'install_dir' global vars, and code to determine
what their values should be.

------------------------------------------------------------------------
r6 | ajapted | 2012-10-20 18:50:12 +1100 (Sat, 20 Oct 2012) | 2 lines

Makefile: removed FLTK_PREFIX stuff.

------------------------------------------------------------------------
r5 | ajapted | 2012-10-20 17:46:15 +1100 (Sat, 20 Oct 2012) | 2 lines

Disabled reading the eureka.cfg file (that mechanism is under review).

------------------------------------------------------------------------
r4 | ajapted | 2012-10-20 17:12:29 +1100 (Sat, 20 Oct 2012) | 2 lines

Created 'Makefile.opt' for FLTK installed the /opt folder.

------------------------------------------------------------------------
r3 | ajapted | 2012-10-20 15:40:19 +1100 (Sat, 20 Oct 2012) | 2 lines

Initial check-in of existing Eureka code (from the AwwPorts repository).

------------------------------------------------------------------------
r2 | ajapted | 2012-10-20 15:36:36 +1100 (Sat, 20 Oct 2012) | 2 lines

Test check-in: README.txt

------------------------------------------------------------------------
r1 | allura | 2012-10-18 22:39:16 +1100 (Thu, 18 Oct 2012) | 1 line

Initial commit.



====================================================
    DEVELOPMENT IN AWWPORTS REPOSITORY
====================================================

------------------------------------------------------------------------
r3135 | ajapted | 2012-10-17

Makefile.unix: implemented 'install' and 'uninstall' targets.

------------------------------------------------------------------------
r3134 | ajapted | 2012-10-17

TODO update.

------------------------------------------------------------------------
r3133 | ajapted | 2012-10-17

Eureka: created a Makefile.unix -- will be used to build and install
a normal unixy binary.  Main difference so far is that it links
against a system-wide version of FLTK.

------------------------------------------------------------------------
r3132 | ajapted | 2012-10-16

Eureka: handle a pwad filename given without -file.
For example: ./eureka foo.wad

------------------------------------------------------------------------
r3131 | ajapted | 2012-10-16

tweak

------------------------------------------------------------------------
r2744 | ajapted | 2012-07-16

Eureka: TODO item.

------------------------------------------------------------------------
r1468 | ajapted | 2012-05-15

try to unfuck this BZR repository.....

------------------------------------------------------------------------
r1467 | ajapted | 2012-05-15

Eureka / EDGE: various fixes and improvement to new linetypes.

------------------------------------------------------------------------
r1466 | ajapted | 2012-05-15

Eureka / EDGE: fixed remaining linetypes, e.g. rts scripting, sliding doors,
aligners, etc..

------------------------------------------------------------------------
r1465 | ajapted | 2012-05-15

Eureka / EDGE: worked on linetypes, e.g. new keyed doors, hub exits, etc..

------------------------------------------------------------------------
r1462 | ajapted | 2012-05-14

Eureka / EDGE: added all the sector types.

------------------------------------------------------------------------
r1461 | ajapted | 2012-05-14

Eureka / EDGE: added remaining missing things: dog, glows, stealth monsters.

------------------------------------------------------------------------
r1460 | ajapted | 2012-05-14

Eureka / EDGE: fixed category for slopes, and added some missing things
(Jetpack, green keys, new armors).

------------------------------------------------------------------------
r1459 | ajapted | 2012-05-14

Eureka / Odamex: added Blue/Red player starts and Static_Init things (333 to 335).

------------------------------------------------------------------------
r1458 | ajapted | 2012-05-14

Eureka: more work to ODAMEX definitions (sector types, etc etc...)

------------------------------------------------------------------------
r1457 | ajapted | 2012-05-14

Eureka: added slope linetypes to EDGE definition.

------------------------------------------------------------------------
r1456 | ajapted | 2012-05-14

Eureka: partial work on ODAMEX support : ports/odamex.ugh

------------------------------------------------------------------------
r1455 | ajapted | 2012-05-14

Eureka: added bare-bone game definitions for Absolution (Doom64 TC),
Blasphemer and HacX.

------------------------------------------------------------------------
r1453 | ajapted | 2012-04-24

Eureka / DOOM defs: fixed linetypes 33 and 34 (red and yellow locked doors)
which had swapped descriptions.

------------------------------------------------------------------------
r1452 | ajapted | 2012-04-18

Eureka: fixed W_FindPatchLump() fallback method to try _any_ lump with
the matching name (instead of just sprites).  This fixes the missing
textures with the Doom64 TC.

------------------------------------------------------------------------
r1451 | ajapted | 2012-04-18

Eureka: added a LoadTexture_SinglePatch() function to texture loading code
which turned out not to be necessary -- but kept for possible future use.

------------------------------------------------------------------------
r1450 | ajapted | 2012-03-23

Eureka / DOOM: somehow the 'Computer map' pickup disappeared from the
definition files -- added it back in.

------------------------------------------------------------------------
r1425 | ajapted | 2012-02-17

Eureka: moved 0.74 changelog --> docs/ directory.

------------------------------------------------------------------------
r1424 | ajapted | 2012-02-17

makefile tweak.

------------------------------------------------------------------------
r1423 | ajapted | 2012-02-17

Eureka: Changelog tweakage.

------------------------------------------------------------------------
r1422 | ajapted | 2012-02-17

Eureka: add revision numbers to changelogs.

------------------------------------------------------------------------
r1421 | ajapted | 2012-02-17

Eureka: CHANGELOG update.

------------------------------------------------------------------------
r1420 | ajapted | 2012-02-17

Eureka: improved the ABOUT box.

------------------------------------------------------------------------
r1419 | ajapted | 2012-02-17

tweakage.

------------------------------------------------------------------------
r1418 | ajapted | 2012-02-17

Eureka: experimented with an 'alternate_look' setting.

------------------------------------------------------------------------
r1417 | ajapted | 2012-02-17

Eureka: tweaked widget positions on the Info bar.

------------------------------------------------------------------------
r1416 | ajapted | 2012-02-17

Eureka: TODO update.

------------------------------------------------------------------------
r1415 | ajapted | 2012-02-17

Eureka: TODO update.

------------------------------------------------------------------------
r1414 | ajapted | 2012-02-17

Eureka: persistence tweak.

------------------------------------------------------------------------
r1413 | ajapted | 2012-02-17

Eureka: persist the rendering On/Off state.

------------------------------------------------------------------------
r1412 | ajapted | 2012-02-17

Eureka: improved layout of sidedefs in LineDef panel (they were a bit cramped).

------------------------------------------------------------------------
r1411 | ajapted | 2012-02-17

Eureka: fixed LineDef panel not updating after "ADD"/"DEL" buttons.

------------------------------------------------------------------------
r1410 | ajapted | 2012-02-17

Eureka: CHANGELOG update (sidedef "ADD" and "DEL" buttons).

------------------------------------------------------------------------
r1409 | ajapted | 2012-02-17

Eureka: e_cutpaste::UnlinkSideFromLine() --> x_loop::LD_RemoveSideDef().
The sidedef "DEL" button uses this to handle sidedef deletion better.

------------------------------------------------------------------------
r1408 | ajapted | 2012-02-17

Eureka: improved "ADD" sidedef button, try GetOppositeSector() to get
the new sector for the sidedef, and if that fails then use NumSec - 1.

------------------------------------------------------------------------
r1407 | ajapted | 2012-02-17

Eureka: changelog (etc) update.

------------------------------------------------------------------------
r1406 | ajapted | 2012-02-17

Eureka: implemented the -port option.

------------------------------------------------------------------------
r1405 | ajapted | 2012-02-17

Eureka: version bump to 0.74

------------------------------------------------------------------------
r1404 | ajapted | 2012-02-17

Eureka: TODO update.

------------------------------------------------------------------------
r1403 | ajapted | 2012-02-17

Eureka: basic implementation of "ADD" button for sidedefs.

------------------------------------------------------------------------
r1402 | ajapted | 2012-02-17

Eureka: implemented the "DEL" button for sidedefs.

------------------------------------------------------------------------
r1401 | ajapted | 2012-02-16

Eureka: in LINEDEF panel, added "ADD" and "DEL" buttons to sidedefs
(with only one visible at a time).  Currently they do nothing.

------------------------------------------------------------------------
r1400 | ajapted | 2012-02-16

Eureka / Browser: parsing code for persistence (cat, search, etc).

------------------------------------------------------------------------
r1399 | ajapted | 2012-02-16

Eureka: persist which Browser panel is open (if any).

------------------------------------------------------------------------
r1398 | ajapted | 2012-02-16

tweak.

------------------------------------------------------------------------
r1397 | ajapted | 2012-02-16

Eureka: docco update (sector insertion improvements).

------------------------------------------------------------------------
r1396 | ajapted | 2012-02-16

Eureka: improved SECTOR insertion : (a) copy properties from a selected
sector, or if none then a neighbor sector.  (b) if CTRL is pressed, then
the new area BECOMES the same sector as the one selected.

------------------------------------------------------------------------
r1395 | ajapted | 2012-02-16

minor comment.

------------------------------------------------------------------------
r1394 | ajapted | 2012-02-16

Eureka: fixed UI_Pic handling of a certain flat (CEIL4_1 IIRC) which
was showing bright cyan in parts that were black (palette color #247).

------------------------------------------------------------------------
r1393 | ajapted | 2012-02-16

docco update.

------------------------------------------------------------------------
r1392 | ajapted | 2012-02-16

Eureka: big rework on CloseLoop_Complex() to fix some failure cases,
especially when extending an island within a sector.

Also fixed a failure case in CloseLoop_Simple() when surrounding an
existing shape WHILE new shape is inside a sector -- we need to
assign a sector to both loops for that.

------------------------------------------------------------------------
r1391 | ajapted | 2012-02-15

Eureka: fixed bug where closing a line-loop around an existing shape
did not apply the new sector to the outside of that shape.

------------------------------------------------------------------------
r1390 | ajapted | 2012-02-15

Eureka: code tidying, and removed 'e' pointer from UI_Canvas class.

------------------------------------------------------------------------
r1389 | ajapted | 2012-02-15

Eureka / TODO: update.

------------------------------------------------------------------------
r1388 | ajapted | 2012-02-15

Eureka / CHANGELOG: update.

------------------------------------------------------------------------
r1387 | ajapted | 2012-02-15

Eureka: tweakage (e.g. persistent messages).

------------------------------------------------------------------------
r1386 | ajapted | 2012-02-15

Eureka / DOOM config: rearranged linegroups.

------------------------------------------------------------------------
r1385 | ajapted | 2012-02-15

Eureka / Browser: skip the trigger (W1, SR, etc).when sorting line
specials alphabetically.

------------------------------------------------------------------------
r1384 | ajapted | 2012-02-15

Eureka / Browser: implemented different SORT methods, and a callback
so that changing the Sort setting will update the list.

------------------------------------------------------------------------
r1383 | ajapted | 2012-02-15

Eureka / Browser: fixed display of '&' in linetype descriptions.
Added padding to numbers for Thing/Line/Sector types.

------------------------------------------------------------------------
r1382 | ajapted | 2012-02-15

Eureka / Browser: added code to SORT the items (currently the only method
is alphabetically).

------------------------------------------------------------------------
r1381 | ajapted | 2012-02-15

Eureka / Browser: updated WriteUser() to write the search string and
values for the Sort and Pics widgets.

------------------------------------------------------------------------
r1380 | ajapted | 2012-02-15

Eureka / Browser: added a 'Sort' choice and 'Pics' toggle button to
certain browser panels.  They currently do NOTHING.

------------------------------------------------------------------------
r1379 | ajapted | 2012-02-15

Eureka: worked on persisting the state of the Browser panels.

------------------------------------------------------------------------
r1378 | ajapted | 2012-02-14

Eureka: fixed bug persisting the 3D preview (view.Sin and view.Cos were
not being updated properly).

------------------------------------------------------------------------
r1377 | ajapted | 2012-02-14

Eureka: updated CHANGELOG.

------------------------------------------------------------------------
r1376 | ajapted | 2012-02-14

Eureka: persist the current edit mode.

------------------------------------------------------------------------
r1375 | ajapted | 2012-02-14

Eureka: persist more Render3D state: gamma, texturing, lighting, etc...

------------------------------------------------------------------------
r1374 | ajapted | 2012-02-13

Eureka: properly handle no persistent user state for a map, via new
M_DefaultUserState() function which zooms out to show whole map,
sets the camera to the player thing, etc....

------------------------------------------------------------------------
r1373 | ajapted | 2012-02-13

tweak.

------------------------------------------------------------------------
r1372 | ajapted | 2012-02-13

Eureka: make sure the -file pwad exists.

------------------------------------------------------------------------
r1371 | ajapted | 2012-02-13

Eureka: fixed Grid_ParseUser() to update the UI widgets (info bar, etc).

------------------------------------------------------------------------
r1370 | ajapted | 2012-02-12

Eureka: tweaked filename for user state persistence.

------------------------------------------------------------------------
r1369 | ajapted | 2012-02-12

Eureka: separated out some code to Editor_Init() function, and call it
earlier than Editor_Loop() so that the user state from LoadLevel() can
work properly.

------------------------------------------------------------------------
r1368 | ajapted | 2012-02-12

Eureka: implemented M_LoadUserState().

------------------------------------------------------------------------
r1367 | ajapted | 2012-02-12

Eureka: implemented a M_ParseLine() function as the general way to
break a line into tokens.  The strings must be freed with M_FreeLine().

------------------------------------------------------------------------
r1366 | ajapted | 2012-02-12

Eureka: more work on persisting "user state" when saving and loading maps
The parsing and writing logic for the GRID and RENDER systems is now in
place, but not yet complete.

------------------------------------------------------------------------
r1365 | ajapted | 2012-02-12

Eureka: more work on persisting "user state" when saving and loading maps
The parsing and writing logic for the GRID and RENDER systems is now in
place, but not yet complete.

------------------------------------------------------------------------
r1364 | ajapted | 2012-02-12

Eureka: for File/Export function, ask for the map slot _AFTER_ asking
for the destination filename.

------------------------------------------------------------------------
r1363 | ajapted | 2012-02-12

Eureka: began work on mechanism to persist user state for a map, stuff
like the camera position and angle, grid position and scale and step,
browser categories, etc etc.....

------------------------------------------------------------------------
r1362 | ajapted | 2012-02-12

Eureka: added 'cache' directory.

------------------------------------------------------------------------
r1361 | ajapted | 2012-02-12

Eureka: code to compute the adler CRC when loading and saving a map.

This required changing the lump processing order in LoadLevel() so that
it matches SaveLevel() -- however it cannot do certain checks as it did
before (e.g. check for invalid sector numbers in sidedefs), these must
be done in a separate pass which hasn't been implemented yet.

------------------------------------------------------------------------
r1360 | ajapted | 2012-02-12

Eureka / Adler-32: tweaks.

------------------------------------------------------------------------
r1359 | ajapted | 2012-02-12

Eureka / Adler-32: added an 'extra' field which is the 32-bit sum of
the 16-bit S2 field, modulo a large prime number (0xFFFEFFF9).  This
should make collisions a lot less likely, but definitely not as good
as a proper CRC-64 implementation.

------------------------------------------------------------------------
r1358 | ajapted | 2012-02-12

Eureka: fixed #includes from renamed file: lib_crc --> lib_adler

------------------------------------------------------------------------
r1357 | ajapted | 2012-02-12

Eureka: renamed code file: lib_crc --> lib_adler

------------------------------------------------------------------------
r1356 | ajapted | 2012-02-09

Eureka: TODO (etc) update.

------------------------------------------------------------------------
r1355 | ajapted | 2012-02-09

Eureka: when dragging/scaling/rotating vertices, draw the linedefs too.

Changed dynamic rotate (CTRL + Mouse2) to not scale, just rotate.

------------------------------------------------------------------------
r1354 | ajapted | 2012-02-08

Eureka: renamed typedef: obj_type_t --> obj_type_e

------------------------------------------------------------------------
r1353 | ajapted | 2012-02-08

Eureka / DOOM: renamed some Ammunition things.

------------------------------------------------------------------------
r1352 | ajapted | 2012-02-08

Eureka / DOOM: removed "PU:" prefix from pickup items, moved backpack
into the Bonus category, and some minor renaming.

------------------------------------------------------------------------
r1351 | ajapted | 2012-02-08

Eureka: TODO update.

------------------------------------------------------------------------
r1350 | ajapted | 2012-02-08

Eureka: implemented MasterDir_Remove().  This should fix the crash issue
(and a quick test did not reproduce the crash).

------------------------------------------------------------------------
r1349 | ajapted | 2012-02-08

Eureka: removed obsolete file: w_structs.h

------------------------------------------------------------------------
r1348 | ajapted | 2012-02-08

Eureka: removed most stuff from w_structs.h (obsolete), and moved the
two actually used definitions --> w_rawdef.h

------------------------------------------------------------------------
r1347 | ajapted | 2012-02-08

Eureka: updated all header files to have consistent guards (i.e. the
#ifndef XXX #define XXX ... #endif paradigm).

------------------------------------------------------------------------
r1346 | ajapted | 2012-02-08

Eureka: replaced 'img_dim_t' typedef with good old 'int'.

------------------------------------------------------------------------
r1345 | ajapted | 2012-02-07

tweak

------------------------------------------------------------------------
r1344 | ajapted | 2012-02-07

Eureka: ChangeLog / TODO update.

------------------------------------------------------------------------
r1343 | ajapted | 2012-02-07

Eureka: for File/New, no need to ask for a map slot when there's no
current PWAD, as the File/Save function will do File/Export which
always asks for the map slot.

------------------------------------------------------------------------
r1342 | ajapted | 2012-02-07

Eureka: show the current WAD and map name in the window title bar.

------------------------------------------------------------------------
r1341 | ajapted | 2012-02-07

Eureka: TODO twiddling.

------------------------------------------------------------------------
r1340 | ajapted | 2012-02-07

Eureka: committed current change-log.

------------------------------------------------------------------------
r1339 | ajapted | 2012-02-07

Eureka: the clipboard persists when changing maps, allowing copy-n-paste
from one map/wad to another map/wad.

------------------------------------------------------------------------
r1338 | ajapted | 2012-02-07

Eureka: renamed variables: Warp --> Level_name, also Game --> Game_name
and Port --> Port_name.

------------------------------------------------------------------------
r1337 | ajapted | 2012-02-07

Eureka: snap_to_grid is now the default.

------------------------------------------------------------------------
r1336 | ajapted | 2012-02-07

tweak.

------------------------------------------------------------------------
r1335 | ajapted | 2012-02-05

Eureka: when highlighting the nearest vertex, handle grid-snap mode so
that the bbox we check has the same size as the grid step.  This ensures
we can close a line loop properly, instead of placing a vertex on top of
an existing vertex.

Bug reported by Lance MDR Rocket.

------------------------------------------------------------------------
r1334 | ajapted | 2012-02-05

Eureka: when creating a square sector (outside of map), make it occupy a
single grid square.

------------------------------------------------------------------------
r1333 | ajapted | 2012-02-02

Eureka: moved some documents into new docs/ folder.

------------------------------------------------------------------------
r1332 | ajapted | 2012-02-02

Eureka: WISHLIST update.

------------------------------------------------------------------------
r1331 | ajapted | 2012-02-02

Eureka: added docs/ folder.

------------------------------------------------------------------------
r1330 | ajapted | 2012-02-01

Eureka: TODO update.

------------------------------------------------------------------------
r1329 | ajapted | 2012-02-01

Eureka: disable debugging messages in LOG file.

------------------------------------------------------------------------
r1328 | ajapted | 2012-02-01

Eureka: fixed year in About box text.

------------------------------------------------------------------------
r1327 | ajapted | 2012-02-01

Eureka: disabled some debugging stderr messages.

------------------------------------------------------------------------
r1326 | ajapted | 2012-02-01

tweak.

------------------------------------------------------------------------
r1325 | ajapted | 2012-02-01

Eureka: added changelog for v0.72

------------------------------------------------------------------------
r1324 | ajapted | 2012-02-01

tweak

------------------------------------------------------------------------
r1323 | ajapted | 2012-02-01

Eureka: updated NEW_WORKFLOW document, various other doc tweaks.

------------------------------------------------------------------------
r1322 | ajapted | 2012-02-01

tweak

------------------------------------------------------------------------
r1321 | ajapted | 2012-02-01

tweak.

------------------------------------------------------------------------
r1320 | ajapted | 2012-02-01

Eureka: fixed FreshLevel() to apply the default textures (etc).

------------------------------------------------------------------------
r1319 | ajapted | 2012-02-01

Eureka: fixed bug in recent commit (Export code).

------------------------------------------------------------------------
r1318 | ajapted | 2012-02-01

Eureka: silenced a few compiler warnings.

------------------------------------------------------------------------
r1317 | ajapted | 2012-02-01

Eureka: tweaked messages when loading/saving/exporting a map.

------------------------------------------------------------------------
r1316 | ajapted | 2012-02-01

Eureka: disabled some unimplemented Menu commands.

------------------------------------------------------------------------
r1315 | ajapted | 2012-02-01

Eureka / DOOM: changed default ceiling texture to CEIL3_5.

------------------------------------------------------------------------
r1314 | ajapted | 2012-02-01

Eureka: more stuff for WISHLIST....

------------------------------------------------------------------------
r1313 | ajapted | 2012-01-31

Eureka: added MasterDir_Add() and MasterDir_Remove() functions
(note the latter is not implemented yet).

------------------------------------------------------------------------
r1312 | ajapted | 2012-01-31

Eureka: improved logic in File/Open function when the user selects a
new WAD file -- in particular we only change 'edit_wad' and update the
master directory if the operation is successful.

Improved File/Export code with the MasterDir_Add/Remove calls.

------------------------------------------------------------------------
r1311 | ajapted | 2012-01-31

Eureka: tidying up...

------------------------------------------------------------------------
r1310 | ajapted | 2012-01-31

Eureka: small fix.

------------------------------------------------------------------------
r1309 | ajapted | 2012-01-31

Eureka: yet another TODO / WISHLIST update.

------------------------------------------------------------------------
r1308 | ajapted | 2012-01-31

Eureka: improved logic for DetermineIWAD(), handle $DOOMWADDIR and
when -iwad merely specifies a directory.

------------------------------------------------------------------------
r1307 | ajapted | 2012-01-31

Eureka / Wad_file: fixed ::Open() with mode 'a' to only create the
file when it doesn't exist (errno == ENOENT).  Before it would try
to create the file on other errors (such as no permission to R/W).

------------------------------------------------------------------------
r1306 | ajapted | 2012-01-31

Eureka: changed -file option to only accept a single PWAD.  Later on
there will be a -merge option for adding resource wads.

------------------------------------------------------------------------
r1305 | ajapted | 2012-01-31

Eureka: ensure new lumps have uppercase names.

------------------------------------------------------------------------
r1304 | ajapted | 2012-01-31

Eureka: TODO and WISHLIST update.

------------------------------------------------------------------------
r1303 | ajapted | 2012-01-31

Eureka: updated README for upcoming test package.

------------------------------------------------------------------------
r1302 | ajapted | 2012-01-31

Eureka: tweaked FEATURES.txt

------------------------------------------------------------------------
r1301 | ajapted | 2012-01-31

Eureka: when creating new sectors, give them proper default values,
especially the default floor and ceiling textures.  Similarly for
new sidedefs.

------------------------------------------------------------------------
r1300 | ajapted | 2012-01-31

Eureka: TODO / WISHLIST update.

------------------------------------------------------------------------
r1299 | ajapted | 2012-01-31

Eureka: use the new 'g_default_thing' global when inserting things,
and removed the other one.

------------------------------------------------------------------------
r1298 | ajapted | 2012-01-30

Eureka: added 'default_thing' value to DOOM and HERETIC game defs.

------------------------------------------------------------------------
r1297 | ajapted | 2012-01-30

Eureka: code to parse a 'default_thing' line in game definitions.

------------------------------------------------------------------------
r1296 | ajapted | 2012-01-30

Eureka: added 'default_textures' line to DOOM and HERETIC game defs.

------------------------------------------------------------------------
r1295 | ajapted | 2012-01-30

Eureka: code to parse 'default_textures' line in game definitions.

------------------------------------------------------------------------
r1294 | ajapted | 2012-01-30

Eureka: support for a 'sky_color' field in game definition files.

------------------------------------------------------------------------
r1293 | ajapted | 2012-01-30

Eureka: removed a couple of unused globals.

------------------------------------------------------------------------
r1292 | ajapted | 2012-01-30

tweak

------------------------------------------------------------------------
r1291 | ajapted | 2012-01-30

Eureka: more tidying of obsolete config options...

------------------------------------------------------------------------
r1290 | ajapted | 2012-01-30

Eureka: removed most of the obsolete config settings.

------------------------------------------------------------------------
r1289 | ajapted | 2012-01-30

Eureka: dead code removal.

------------------------------------------------------------------------
r1288 | ajapted | 2012-01-30

Eureka: dead code removal.

------------------------------------------------------------------------
r1287 | ajapted | 2012-01-30

Eureka: removed 'Expert' global variable.

------------------------------------------------------------------------
r1286 | ajapted | 2012-01-30

Eureka / Port defs: consistently have 'BOOM:' or 'EDGE:' in the names
of the Boom and Edge specific linetypes, things, etc...

------------------------------------------------------------------------
r1285 | ajapted | 2012-01-30

Eureka: added a DeterminePort() function.

------------------------------------------------------------------------
r1284 | ajapted | 2012-01-30

Eureka: added 'ports/vanilla.ugh' definition, which is empty except for
comments (and doesn't need anything).

------------------------------------------------------------------------
r1283 | ajapted | 2012-01-29

Eureka: TODO update.

------------------------------------------------------------------------
r1282 | ajapted | 2012-01-29

Eureka: properly flip linedefs when inserting a sector and the line(s)
would have ended up with no right side (only a left side).

------------------------------------------------------------------------
r1281 | ajapted | 2012-01-29

Eureka: when auto-splitting a sector, ensure neither line loop faces outward.

------------------------------------------------------------------------
r1280 | ajapted | 2012-01-29

Eureka: noted a bug with rendering mid-masked textures.

------------------------------------------------------------------------
r1279 | ajapted | 2012-01-29

tweak

------------------------------------------------------------------------
r1278 | ajapted | 2012-01-29

Eureka.cfg : removed the obsolete iwad stuff.

------------------------------------------------------------------------
r1277 | ajapted | 2012-01-29

Eureka: have a single -iwad parameter (instead of -iwad1, -iwad2 etc....)

------------------------------------------------------------------------
r1276 | ajapted | 2012-01-29

tweakage.

------------------------------------------------------------------------
r1275 | ajapted | 2012-01-29

Eureka: WISHLIST update.

------------------------------------------------------------------------
r1274 | ajapted | 2012-01-29

Eureka: determine the 'Game' value from the IWAD filename.

------------------------------------------------------------------------
r1273 | ajapted | 2012-01-29

Eureka: for File/Export function, add ".wad" if filename has no extension.

------------------------------------------------------------------------
r1272 | ajapted | 2012-01-29

Eureka: code tweak (use FileExists utility function).

------------------------------------------------------------------------
r1271 | ajapted | 2012-01-29

Eureka / yutils: removed a few unused functions (fncmp, spec_path) and
renamed a few functions (e.g. TimeGetMillies).

------------------------------------------------------------------------
r1270 | ajapted | 2012-01-28

Eureka: TODO update.

------------------------------------------------------------------------
r1269 | ajapted | 2012-01-28

Eureka / Wad_file: added PathName() and IsReadOnly() methods.

------------------------------------------------------------------------
r1268 | ajapted | 2012-01-28

Eureka: made the Wad_file::Open() method mimic the fopen() semantics,
it now has a 'mode' parameter which can be 'r', 'w' or 'a'.

Hence removed the ::Create() method from the public API.

------------------------------------------------------------------------
r1267 | ajapted | 2012-01-28

Eureka: some work to set 'Game' value differently, it will be based on
the IWAD filename instead of being in the CFG file.

------------------------------------------------------------------------
r1266 | ajapted | 2012-01-28

Eureka: for File/Open function, implemented choosing a WAD file to load
and improved the wording on the question.

------------------------------------------------------------------------
r1265 | ajapted | 2012-01-28

Eureka: for File/Open command, clear the MadeChanges flag and pan/zoom
the canvas to show the whole level.

------------------------------------------------------------------------
r1264 | ajapted | 2012-01-28

Eureka: partial work on File/Open (CTRL-O) functionality.  It really
needs is a new widget, HOWEVER for now I will make do with fl_input and
Confirm/Notify dialogs.

------------------------------------------------------------------------
r1263 | ajapted | 2012-01-28

dead code removal.

------------------------------------------------------------------------
r1262 | ajapted | 2012-01-27

tweakage.

------------------------------------------------------------------------
r1261 | ajapted | 2012-01-27

Eureka: for EXPORT function, if selected wad already exists then we just
save the map into that wad, but if the MAP already exists in that wad
then get confirmation from the user to overwrite it.

------------------------------------------------------------------------
r1260 | ajapted | 2012-01-27

Eureka: more Wishes.... sigh...

------------------------------------------------------------------------
r1259 | ajapted | 2012-01-27

Eureka: for EXPORT function, ask user for map-slot name and use it,
and also make the exported WAD the current PWAD (set 'edit_wad' global).

------------------------------------------------------------------------
r1258 | ajapted | 2012-01-27

Eureka: new global 'Replacer' remembers when the user created a new map
(via File/New or CTRL-N) __AND__ it would replace an existing level in
the current PWAD.

When doing File/Save (CTRL-S), check for Replacer and confirm whether
the user really wants to replace the existing map.

Improved File/New operation to ask for a map name.

------------------------------------------------------------------------
r1257 | ajapted | 2012-01-27

Eureka: bit of work on wad handling, the 'base_wad' and 'edit_wad' global
variables have the current IWAD (required) and current PWAD (optional).

------------------------------------------------------------------------
r1256 | ajapted | 2012-01-27

Eureka / Games: renamed 'doom1.ugh' --> 'doom.ugh', to match the IWAD
filename (DOOM.WAD)

------------------------------------------------------------------------
r1255 | ajapted | 2012-01-27

Eureka / Games: added game definitions for FINAL DOOM (tnt.ugh and
plutonia.ugh).  They merely include the DOOM 2 definitions, although
eventually they will need stuff for their new textures.

------------------------------------------------------------------------
r1254 | ajapted | 2012-01-27

Eureka: tweaked color of camera arrow.

------------------------------------------------------------------------
r1253 | ajapted | 2012-01-27

Eureka: implemented 'Go To Camera' function (bound to END key).

------------------------------------------------------------------------
r1252 | ajapted | 2012-01-27

Eureka: version bump to 0.72

------------------------------------------------------------------------
r1251 | ajapted | 2012-01-27

Eureka / README: document middle click functions (scale etc).

------------------------------------------------------------------------
r1250 | ajapted | 2012-01-27

Eureka: TODO update.

------------------------------------------------------------------------
r1249 | ajapted | 2012-01-27

Eureka: show proper location and angle of camera.

------------------------------------------------------------------------
r1248 | ajapted | 2012-01-27

Eureka: size of the camera arrow now depends on current map scale.

------------------------------------------------------------------------
r1247 | ajapted | 2012-01-27

Eureka: partial work on drawing the camera (a pink arrow)...

------------------------------------------------------------------------
r1246 | ajapted | 2012-01-27

Eureka: worked on semantics for wad handling (the File/ menu) and how
the current "game" is defined.

------------------------------------------------------------------------
r1245 | ajapted | 2012-01-26

Eureka / Scaling: fixed bug where a rotation remains in-effect after
releasing the CTRL key.

------------------------------------------------------------------------
r1244 | ajapted | 2012-01-26

Eureka / Scaling: properly handle modifiers: none = keep_aspect,
SHIFT = any aspect, CTRL = rotate.

------------------------------------------------------------------------
r1243 | ajapted | 2012-01-26

Eureka / Scaling: various fixes...

------------------------------------------------------------------------
r1242 | ajapted | 2012-01-26

Eureka: use new scale_param_t stuff in UI_Canvas class.

------------------------------------------------------------------------
r1241 | ajapted | 2012-01-26

Eureka: added a scale_param_t structure with an Apply() method to
transform a coordinate value.  Updated all CMD_ScaleObjects2() code to
use this structure and method (rather than mid_x etc... parameters).

------------------------------------------------------------------------
r1240 | ajapted | 2012-01-26

TODO bits...

------------------------------------------------------------------------
r1239 | ajapted | 2012-01-26

Eureka: TODO update.

------------------------------------------------------------------------
r1238 | ajapted | 2012-01-26

Eureka: moved next/prev/jump code into CMD_NextObject(), CMD_PrevObject()
and CMD_JumpToObject() functions in e_path.cc/h file, and updated menu
to call them.

------------------------------------------------------------------------
r1237 | ajapted | 2012-01-26

Eureka: dead code removal.

------------------------------------------------------------------------
r1236 | ajapted | 2012-01-26

Eureka: use 'V' key for the mirror vertically function (not 'I').

------------------------------------------------------------------------
r1235 | ajapted | 2012-01-26

Eureka: Implemented 'Invert Selection' function (CTRL + I).

------------------------------------------------------------------------
r1234 | ajapted | 2012-01-26

Eureka: moved sel_op_e enum from main.h --> m_bitvec.h

------------------------------------------------------------------------
r1233 | ajapted | 2012-01-26

minor fix.

------------------------------------------------------------------------
r1232 | ajapted | 2012-01-26

WISH-LIST: console idea.

------------------------------------------------------------------------
r1231 | ajapted | 2012-01-25

tweaks.

------------------------------------------------------------------------
r1230 | ajapted | 2012-01-25

Eureka: for 'Export Map' function, properly handle CANCEL and ERROR
returns from the file chooser (notify user), and actually use the
filename selected, and notify user if creating the file failed.

------------------------------------------------------------------------
r1229 | ajapted | 2012-01-25

Eureka: factored out a Main_ConfirmQuit() function, and use it for the
'New Level' function too (so the user does not lose their changes).

------------------------------------------------------------------------
r1228 | ajapted | 2012-01-25

Eureka: TODO update (scaling stuff).

------------------------------------------------------------------------
r1227 | ajapted | 2012-01-25

Eureka / Scaling: experimental code for dynamic Rotation....

------------------------------------------------------------------------
r1226 | ajapted | 2012-01-25

Eureka / Scaling: fixed the scaling calculations in Scaled_Coord() and
UI_Canvas::ScaleUpdate().

------------------------------------------------------------------------
r1225 | ajapted | 2012-01-25

Eureka / Scaler: factored out some common mirror logic so it can be
used for the dynamic scaling code too (when scale_x or y is negative).

Implemented the actual scaling in new CMD_ScaleObjects2() function.

For some functions in x_mirror, pass 'selection_c' by reference
instead of as a pointer.

------------------------------------------------------------------------
r1224 | ajapted | 2012-01-25

Eureka / Scaling: properly compute middle point of objects.

------------------------------------------------------------------------
r1223 | ajapted | 2012-01-25

Eureka: renamed some stuff, e.g. centre_of_objs() --> Objs_CalcMiddle()
bbox_of_objects() --> Objs_CalcBBox(), and a few other things.

------------------------------------------------------------------------
r1222 | ajapted | 2012-01-25

Eureka / Scaling: added code to draw scaled LineDefs and Sectors.

------------------------------------------------------------------------
r1221 | ajapted | 2012-01-25

Eureka / Scaling: proper logic to draw the scaled selection, and added
support for a 'keep_aspect' mode (hold down SHIFT key).

------------------------------------------------------------------------
r1220 | ajapted | 2012-01-25

Eureka: initial work on ability to Scale objects via middle mouse button,
working very similarly to dragging objects...

------------------------------------------------------------------------
r1219 | ajapted | 2012-01-25

Eureka: WISHLIST bits...

------------------------------------------------------------------------
r1218 | ajapted | 2012-01-25

Eureka: improved Quantization algorithm, for vertices we analyse the
linedefs and remember the orientations (V_HORIZ, V_VERT etc), and have
better QuantSnapX/Y() grid methods.

------------------------------------------------------------------------
r1217 | ajapted | 2012-01-25

Eureka: for Quantization of vertices, added logic to keep horizontal
lines horizontal and vertical lines vertical.

------------------------------------------------------------------------
r1216 | ajapted | 2012-01-25

dead code removal.

------------------------------------------------------------------------
r1215 | ajapted | 2012-01-25

Eureka: preliminary code for Quantize_Vertices().

------------------------------------------------------------------------
r1214 | ajapted | 2012-01-24

Eureka: worked on Quantization function, for now only for Things.

The significant aspects are:
(1) leave the unsuccessfully moved things selected (and beep)
(2) never move a thing directly on top of another one
(3) if the nearest corner is unavailable, try the other corners

[these rules will apply to vertex quantization too, and then some]

------------------------------------------------------------------------
r1213 | ajapted | 2012-01-22

Eureka: TODO item.

------------------------------------------------------------------------
r1212 | ajapted | 2012-01-22

Eureka: notes for a better (feasible) quantization algorithm.

------------------------------------------------------------------------
r1211 | ajapted | 2012-01-22

Eureka: experimental code for the 'File/New' menu command, and tweaked
some other menu bits.

------------------------------------------------------------------------
r1210 | ajapted | 2012-01-22

Eureka / TODO: moved numerous items to the WISH-LIST, keeping the TODO
for stuff which I intend to implemented before the next test package.

------------------------------------------------------------------------
r1209 | ajapted | 2012-01-18

tweak.

------------------------------------------------------------------------
r1208 | ajapted | 2012-01-18

Eureka: call the FLTK load_system_icons() function in InitFLTK().
Doesn't seem to have done anything though (no icons in the file chooser).

------------------------------------------------------------------------
r1207 | ajapted | 2012-01-18

Eureka: better logic for menu 'Zoom In/Out' functions via CMD_Zoom()
and CMD_ZoomWholeLevel() functions.  Tweaked some other menu bits.

------------------------------------------------------------------------
r1206 | ajapted | 2012-01-18

Eureka: test code for using FL_Native_File_Chooser....

------------------------------------------------------------------------
r1205 | ajapted | 2012-01-18

Eureka: partial work on the "Export Map" function, i.e. saving the level
into a brand spanking new wad file.  No file selection dialog yet!

------------------------------------------------------------------------
r1204 | ajapted | 2012-01-18

Eureka: removed 'action' field from UI_MainWin class, have a 'want_quit'
global variable instead.

------------------------------------------------------------------------
r1203 | ajapted | 2012-01-17

Eureka: fixed (restored?) deleting things in a sector when deleting
that very sector.  The things are kept (with the linedefs) in the
"keep unused" mode, i.e. when the SHIFT key is held down.

------------------------------------------------------------------------
r1202 | ajapted | 2012-01-17

Eureka: various updates to README, TODO, WISHLIST.

------------------------------------------------------------------------
r1201 | ajapted | 2012-01-17

Eureka: fixed bug when saving a map more than once, the wrong lumps
could get removed and hence end up with multiple versions of the map
in the output wad file.

------------------------------------------------------------------------
r1200 | ajapted | 2012-01-17

minor code reformatting.

------------------------------------------------------------------------
r1199 | ajapted | 2012-01-17

Eureka: began work on texture alignment functions....

------------------------------------------------------------------------
r1198 | ajapted | 2012-01-17

Eureka / selection_c class: added a 'first_obj' field which remembers
the very first object added to the selection.  It is -1 for an empty
selection or when that object gets cleared.  The find_first() method
will return that object if valid, and the find_second() method had been
updated to handle it properly too.

Reduced MAX_STORE_SEL from 32 --> 24, as I think this will speed up
certain operations that make heavy use of selection queries.

Did some code formatting (like semicolons in for loops).

------------------------------------------------------------------------
r1197 | ajapted | 2012-01-17

Eureka: changed "rotate 90^ clockwise" key to 'R', leaving 'X' free for
texture alignment function.

------------------------------------------------------------------------
r1196 | ajapted | 2012-01-17

Eureka: made grid size button a bit wider.

------------------------------------------------------------------------
r1195 | ajapted | 2012-01-16

Eureka: kicked the "Auto" grid choice code to the curb.

------------------------------------------------------------------------
r1194 | ajapted | 2012-01-16

Eureka: mostly finished grid "AUTO" mode, but it sucks since you cannot
see what the current grid step is, so it's gonna get the boot.

------------------------------------------------------------------------
r1193 | ajapted | 2012-01-16

Eureka: fixed wrong initial color of Free/Snap button.

------------------------------------------------------------------------
r1192 | ajapted | 2012-01-16

Eureka: partial work on an "AUTO" mode for the grid, where the grid step
automatically follows the current scale.  It replaces the "locked" flag,
and is now a choice in the Grid setting, so removed the "Locked" choice
in the Snap widget.

------------------------------------------------------------------------
r1191 | ajapted | 2012-01-16

Eureka: added ToggleSnap() and ToggleAuto() methods to Grid_State_c.

------------------------------------------------------------------------
r1190 | ajapted | 2012-01-16

TODO update.

------------------------------------------------------------------------
r1189 | ajapted | 2012-01-16

Eureka: made the 'h' key toggle through the alternate grid mode too
(i.e. normal --> simple --> none).  This replaces the 'P' key function.

------------------------------------------------------------------------
r1188 | ajapted | 2012-01-16

Eureka: don't highlight a split_line if one of its vertices is selected.

------------------------------------------------------------------------
r1187 | ajapted | 2012-01-13

Eureka: in "simple" grid mode, make the X and Y axis lines (at X=0 and
at Y=0) a brighter blue than the rest.  Can help to orientate yourself.

------------------------------------------------------------------------
r1186 | ajapted | 2012-01-12

Eureka: default for grid snapping is now "FREE".

------------------------------------------------------------------------
r1185 | ajapted | 2012-01-11

Eureka: the digits '1' to '9' now set the GRID step, usually 2^n
(i.e. 2, 4, 8, etc) but '8' is 192 units and '9' is 256 units.

------------------------------------------------------------------------
r1184 | ajapted | 2012-01-09

Eureka: notes in TODO.txt and tidying up.

------------------------------------------------------------------------
r1183 | ajapted | 2012-01-09

Eureka: TODO update (iwad stuff, grid keys).

------------------------------------------------------------------------
r1182 | ajapted | 2012-01-08

Eureka: implemented auto-sectoring when EXTENDING off an existing
structure.

------------------------------------------------------------------------
r1181 | ajapted | 2012-01-08

Eureka: got automatic splitting of sectors working! :-)

------------------------------------------------------------------------
r1180 | ajapted | 2012-01-08

Eureka: TODO update.

------------------------------------------------------------------------
r1179 | ajapted | 2012-01-08

Eureka / basis: replaced LD_WhatSec() function with LineDef::WhatSector().

------------------------------------------------------------------------
r1178 | ajapted | 2012-01-08

Eureka / basis: changed TouchesSector() method to take a sector number
instead of a Sector pointer.

------------------------------------------------------------------------
r1177 | ajapted | 2012-01-08

Eureka: bit more work on ClosedLoop_Complex() logic....

------------------------------------------------------------------------
r1176 | ajapted | 2012-01-08

Eureka: began work on logic when adding a new linedef to a vertex with
two or more existing linedefs (auto-split OR auto-sectoring).
Wrote the TwoNeighboringLinedefs() code and tested it.

------------------------------------------------------------------------
r1175 | ajapted | 2012-01-08

Eureka / basis: added LineDef::TouchesVertex() method.

------------------------------------------------------------------------
r1174 | ajapted | 2012-01-08

Eureka / lineloop: fixed a logic error in LookForIsland() code.

------------------------------------------------------------------------
r1173 | ajapted | 2012-01-08

Eureka / lineloop: removed obsolete super_find_sector_model() code.

------------------------------------------------------------------------
r1172 | ajapted | 2012-01-08

Eureka / lineloop: implemented FacesSector() method for islands.

------------------------------------------------------------------------
r1171 | ajapted | 2012-01-08

Eureka: new Insert_LineDef() function factors out the linedef creation
bits from the Insert_Vertex() code.

Began work on logic to auto-insert and auto-split sectors when adding
new linedefs.  New ClosedSimpleLoop() function handles the case of
closing a simple loop (last vertex ends up with only two linedefs).

------------------------------------------------------------------------
r1170 | ajapted | 2012-01-08

Eureka / lineloop: made AssignSectorToLoop() part of public API.

------------------------------------------------------------------------
r1169 | ajapted | 2012-01-08

Eureka / lineloop: added clear() method, use it at start of TraceLineLoop().

------------------------------------------------------------------------
r1168 | ajapted | 2012-01-08

Eureka / lineloop: added AllNew() and NeighboringSector() methods.

------------------------------------------------------------------------
r1167 | ajapted | 2012-01-08

Eureka: added 'ignore_new' flag to TraceLineLoop() function, this will
cause "new" linedefs (ones without any sidedefs) to be ignored.

------------------------------------------------------------------------
r1166 | ajapted | 2012-01-06

Eureka / lineloop: added SameSector() method.

------------------------------------------------------------------------
r1165 | ajapted | 2012-01-06

Eureka / lineloop: added TotalLength() method.

------------------------------------------------------------------------
r1164 | ajapted | 2012-01-06

Eureka: updated README.txt

------------------------------------------------------------------------
r1163 | ajapted | 2012-01-06

Eureka / lineloop: determine the 'faces_outward' flag by computing the
average angle between lines in the loop (done in TraceLineLoop).

Fixed get() and get_just_line() methods to check the islands too,
which is vital to make FindIslands() work properly.

Fixed AssignSectorToSpace() to handle islands too.

------------------------------------------------------------------------
r1162 | ajapted | 2012-01-06

Eureka / lineloop: reworked TraceLineLoop() code for new class.

------------------------------------------------------------------------
r1161 | ajapted | 2012-01-06

Eureka / lineloop: reworked the FindIslands() logic for new class.

------------------------------------------------------------------------
r1160 | ajapted | 2012-01-06

Eureka / lineloop: destructor now frees the islands.  Moved code around.

------------------------------------------------------------------------
r1159 | ajapted | 2012-01-06

Eureka / lineloop: rewrote the CalcBounds() method, which was previously
a function called BoundsOfLinePath().

------------------------------------------------------------------------
r1158 | ajapted | 2012-01-06

Eureka: more work on lineloop_c code, e.g. get() and push_back() methods.

------------------------------------------------------------------------
r1157 | ajapted | 2012-01-06

Eureka: added #include "x_loop.h" where needed.

------------------------------------------------------------------------
r1156 | ajapted | 2012-01-06

Eureka: began work on a lineloop_c class for representing a line-loop
(an ordered list of linedef/side pairs).

------------------------------------------------------------------------
r1155 | ajapted | 2012-01-06

Eureka / Makefiles: added 'x_loop' code file to the build.

------------------------------------------------------------------------
r1154 | ajapted | 2012-01-06

Eureka: fixed #includes in x_loop.cc (restored needed, removed uneeded).

------------------------------------------------------------------------
r1153 | ajapted | 2012-01-06

Eureka: moved AssignSectorToSpace() function and related code from
s_misc.cc/h --> x_loop.cc/h (new files).

------------------------------------------------------------------------
r1152 | ajapted | 2012-01-05

Eureka / TODO: some notes about line-loop modalities....

------------------------------------------------------------------------
r1151 | ajapted | 2012-01-05

Eureka: fixed bug with dragging a vertex and splitting a line, the
dragged vertex was not moving to the new position.

------------------------------------------------------------------------
r1150 | ajapted | 2012-01-05

tweak.

------------------------------------------------------------------------
r1149 | ajapted | 2012-01-05

Eureka: (tentative commit) : for LoadDefinitions() allow a line or
thing or texture/flat to have an unknown group -- print a warning to
the log file instead of FatalError.

This was prompted by the issue where port-specific stuff (e.g. Boom)
was referencing groups that don't exist in a game (e.g. Heretic).
I will look for a cleaner way to handle that kind of incompatibility.

------------------------------------------------------------------------
r1148 | ajapted | 2012-01-05

Eureka / HERETIC: added missing 'sky_flat' value.

------------------------------------------------------------------------
r1147 | ajapted | 2012-01-05

Eureka: WISHLIST update.

------------------------------------------------------------------------
r1146 | ajapted | 2012-01-05

Eureka / Browser: implemented '!' in search box for negation.

------------------------------------------------------------------------
r1145 | ajapted | 2012-01-05

Eureka: minor TODO stuff.

------------------------------------------------------------------------
r1144 | ajapted | 2012-01-05

Eureka / DOOM: renamed category letters:
   l --> p (lifts)
   L --> l (light related)
   F --> r (raising floors)
   C --> h (crusher)
   E --> x (extrafloor)

------------------------------------------------------------------------
r1143 | ajapted | 2012-01-05

Eureka / HERETIC: changed stairs group letter to 'u' ("up"), and added a
new group 's' for 'Sounds' (which the ambient sounds were already using).

------------------------------------------------------------------------
r1142 | ajapted | 2012-01-05

Eureka / DOOM: sorted linetypes into groups, removed the 'D' group
(use 'd' for normal and fast doors), and have a single group 'k' for
keyed doors.  Moved linetype 85 (scroll wall right) into Boom defs.

------------------------------------------------------------------------
r1141 | ajapted | 2012-01-05

Eureka / HERETIC: finished adjusting the line types, using different
letters than Yadex did (e.g. 'h' for crushers, 'p' for lifts, 'r' for
raising floors -- avoiding upper case letters).

------------------------------------------------------------------------
r1140 | ajapted | 2012-01-05

Eureka / HERETIC: worked on linetypes, pasted line info from YADEX's
game definition and sorted them into groups.

------------------------------------------------------------------------
r1139 | ajapted | 2012-01-05

Eureka / HERETIC: finished thing sprites and added the correct sizes.
(It would've been a lot easier to copy/paste from YADEX, duh!).

------------------------------------------------------------------------
r1138 | ajapted | 2012-01-05

Eureka / HERETIC: a few more sprites....

------------------------------------------------------------------------
r1137 | ajapted | 2012-01-05

Eureka / HERETIC: worked on sprite names for things, and fixed the id
number for the 'Wings of Wrath' (was 23, should be 83).

------------------------------------------------------------------------
r1136 | ajapted | 2012-01-05

Eureka: worked on thing info for HERETIC game definition....

------------------------------------------------------------------------
r1135 | ajapted | 2012-01-05

Eureka: began work on a HERETIC game definition file....

------------------------------------------------------------------------
r1134 | ajapted | 2012-01-04

Eureka: fixed grid-toggle key ('h') not updating the infobar widget.

------------------------------------------------------------------------
r1133 | ajapted | 2012-01-04

Eureka: fixed the Grid menu's "OFF" choice.

------------------------------------------------------------------------
r1132 | ajapted | 2012-01-04

Eureka: WISHLIST update.

------------------------------------------------------------------------
r1131 | ajapted | 2012-01-04

Eureka: added new document 'NEW_WORKFLOW.txt', describing some of the
significant differences between Eureka and its precedessor Yadex.

------------------------------------------------------------------------
r1130 | ajapted | 2012-01-04

Eureka: TODO update.

------------------------------------------------------------------------
r1129 | ajapted | 2012-01-04

Eureka: updated MergeVertex() to handle a linedef which exists between
the two vertices -- the new logic ensures it gets deleted.

------------------------------------------------------------------------
r1128 | ajapted | 2012-01-04

Eureka: TODO update.

------------------------------------------------------------------------
r1127 | ajapted | 2012-01-04

Eureka: never highlight the same vertex as the one we are dragging,
preventing an fatal error when trying to merge a vertex onto itself.

------------------------------------------------------------------------
r1126 | ajapted | 2012-01-04

Eureka: implemented merging vertices when dragging a single vertex onto
an existing vertex.

------------------------------------------------------------------------
r1125 | ajapted | 2012-01-04

Eureka: fixed the UI_Canvas widget to draw both a a highlight and a
dragged selection at the same time.  The logic in UpdateHighlight() is
what's responsible for keeping it sane.

------------------------------------------------------------------------
r1124 | ajapted | 2012-01-04

tweaks.

------------------------------------------------------------------------
r1123 | ajapted | 2012-01-04

Eureka: improved the UpdateHighlight() code, with a check for dragging
and splitting off the panel stuff into a new UpdatePanel() function.

------------------------------------------------------------------------
r1122 | ajapted | 2012-01-04

Eureka: added Editor_State_c field 'drag_single_vertex', normally -1 but
contains a vertex number when dragging just a single vertex.

------------------------------------------------------------------------
r1121 | ajapted | 2012-01-04

Eureka: more DOOM definition tweaks....

------------------------------------------------------------------------
r1120 | ajapted | 2012-01-04

Eureka: moved most DOOM 2 specific textures and flats into doom2.ugh

------------------------------------------------------------------------
r1119 | ajapted | 2012-01-04

tidying up.

------------------------------------------------------------------------
r1118 | ajapted | 2012-01-04

Eureka: moved rest of BOOM stuff from doom_specials.ugh --> boom.ugh

------------------------------------------------------------------------
r1117 | ajapted | 2012-01-04

Eureka: moved all the EDGE-specific stuff and some BOOM-specific stuff
out of the DOOM game definitions and into their own port definitions.

------------------------------------------------------------------------
r1116 | ajapted | 2012-01-04

Eureka: moved DOOM 2 specific things from doom_common.ugh --> doom2.ugh,
which includes the Super Shotgun, Megasphere, Boss-brain stuff, extra
gore decorations, and the DOOM 2 specific monsters like the Archvile,
Mancubus etc....

------------------------------------------------------------------------
r1115 | ajapted | 2012-01-03

Eureka: merged 'doom_tex.ugh' back into 'doom_common.ugh'.

All these shenanigans is to allow some DOOM engine games (such as
Chex Quest, HacX, and Harmony) to use the common engine stuff but
specify their own thing types and flats/textures.

------------------------------------------------------------------------
r1114 | ajapted | 2012-01-03

Eureka: moved some stuff from doom_tex.ugh --> doom1/2.ugh

------------------------------------------------------------------------
r1113 | ajapted | 2012-01-03

Eureka: separated out the line/sector specials from doom_common.ugh
into a new file: 'doom_specials.ugh'.

------------------------------------------------------------------------
r1112 | ajapted | 2012-01-03

Eureka: moved the flat/texture definitions out of doom_common.ugh and
into a new file 'doom_tex.ugh'.

------------------------------------------------------------------------
r1111 | ajapted | 2012-01-03

Eureka: added 'doom1.ugh' and 'doom2.ugh' game definitions, which so
far do little more than simply include the common file.  Work still
needs to be done to properly separate everything....

------------------------------------------------------------------------
r1110 | ajapted | 2012-01-03

Eureka: renamed game config file: doom2.ugh --> doom_common.ugh
(as the bulk of that file will be stuff in common to both games).

------------------------------------------------------------------------
r1109 | ajapted | 2012-01-03

Eureka: implemented 'include' directive for ".ugh" definition files.

This will be handy for:
   (a) common stuff between DOOM 1 and DOOM 2
   (b) ports which are boom compatible

------------------------------------------------------------------------
r1108 | ajapted | 2012-01-03

Eureka: worked on "ugh" definition file loading, supply a folder name
as well as the filename to the LoadDefinitions() function, with some
test code which loads the "ports/boom" definition file.

------------------------------------------------------------------------
r1107 | ajapted | 2012-01-03

Eureka: added a mods/ directory.

------------------------------------------------------------------------
r1106 | ajapted | 2012-01-03

WISHLIST tweak.

------------------------------------------------------------------------
r1105 | ajapted | 2012-01-03

Eureka: renamed configs/ folder --> games/

------------------------------------------------------------------------
r1104 | ajapted | 2012-01-03

Eureka: moved BOOM and EDGE definition files --> ports/

------------------------------------------------------------------------
r1103 | ajapted | 2012-01-03

Eureka: added 'ports' directory, a place for source-port definitions.

------------------------------------------------------------------------
r1102 | ajapted | 2012-01-03

Eureka: added '192' as a grid size.

------------------------------------------------------------------------
r1101 | ajapted | 2012-01-03

Eureka: draw vertices in proper colors when selected and/or highlighted
(previously they remained green, only the box around them has the proper
color).  Also made vertices more visible (solid area at centre).

------------------------------------------------------------------------
r1100 | ajapted | 2012-01-03

TODO update.

------------------------------------------------------------------------
r1099 | ajapted | 2012-01-03

Eureka: reworked colors of linedefs (UI_Canvas), white is used for
single-sided lines (instead of lines with the blocking flag), and
white is used in VERTEX mode too now.

In LINEDEF mode, cyan is used for double-sided lines which have
the blocking flag.

------------------------------------------------------------------------
r1098 | ajapted | 2012-01-03

Eureka: implemented CMD_CorrectSector().

------------------------------------------------------------------------
r1097 | ajapted | 2012-01-03

Eureka: when splitting a linedef with a new vertex, ensure the vertex
lies directly on the linedef (i.e. not slightly off the side).  This
only applies when grid snapping is OFF.

------------------------------------------------------------------------
r1096 | ajapted | 2012-01-03

Eureka: began work to make 'c' key be a "correct sector" function.

------------------------------------------------------------------------
r1095 | ajapted | 2012-01-03

Eureka / Utilities: added PerpDist() and AlongDist(), and removed some
unused stuff.

------------------------------------------------------------------------
r1094 | ajapted | 2012-01-03

Eureka: implemented MoveCoordOntoLineDef() function.

------------------------------------------------------------------------
r1093 | ajapted | 2012-01-03

Eureka: experimented with an alternate grid (simple squares), which
can be toggled via 'P' key (need a better key or mechanism though).

------------------------------------------------------------------------
r1092 | ajapted | 2012-01-03

Eureka: made the single-quote key (') move the 3D camera to the cursor
position.

------------------------------------------------------------------------
r1091 | ajapted | 2012-01-03

Eureka: changed LighterColor() to be less bright.

------------------------------------------------------------------------
r1090 | ajapted | 2012-01-03

Eureka: added code to create a 'bright_map' table, which maps palette
colors to a brighter (closer to white) color in the palette.  This
could potentially be used in the 3D preview to highlight stuff.

------------------------------------------------------------------------
r1089 | ajapted | 2012-01-03

Eureka: deleting a single vertex attached to TWO linedefs (no more, no less)
is now a special case which merges the linedefs together.

------------------------------------------------------------------------
r1088 | ajapted | 2012-01-03

Eureka: TODO update.

------------------------------------------------------------------------
r1087 | ajapted | 2012-01-03

Eureka: changed DisconnectLineDefs logic so that the selected linedefs
get any new vertices (existing geometry keeps the existing vertices).

------------------------------------------------------------------------
r1086 | ajapted | 2012-01-03

Eureka: implemented the logic for 'DisconnectLineDefs', which works
somewhat different than disconnecting vertices since we want to keep
all linedefs in the selection connected and only disconnect from
linedefs NOT in the selection.

------------------------------------------------------------------------
r1085 | ajapted | 2012-01-03

tidy up.

------------------------------------------------------------------------
r1084 | ajapted | 2012-01-03

Eureka: added 'd' command to README.txt

------------------------------------------------------------------------
r1083 | ajapted | 2012-01-03

Eureka: fixed problems in the DisconnectVertex code, and improved the
logic in CalcDisconnectCoord().  Also assigned to 'd' key (was 'D').

------------------------------------------------------------------------
r1082 | ajapted | 2012-01-02

Eureka: implemented a 'D' command to Disconnect linedefs.  Untested.

------------------------------------------------------------------------
r1081 | ajapted | 2012-01-02

Eureka: version bump to 0.70 -- good progress with vertex stuff.

------------------------------------------------------------------------
r1080 | ajapted | 2012-01-02

Eureka: just some algorithm notes...

------------------------------------------------------------------------
r1079 | ajapted | 2012-01-02

Eureka: yet another TODO update.

------------------------------------------------------------------------
r1078 | ajapted | 2012-01-02

Eureka: when adding a linedef between two existing vertices, reselect
the second one IFF it was isolated (not connected to any linedefs).

------------------------------------------------------------------------
r1077 | ajapted | 2012-01-02

Eureka: minor renaming, CastVerty --> CastVert.

------------------------------------------------------------------------
r1076 | ajapted | 2012-01-02

Eureka: use RGB_RED() etc macros instead of directly manipulating color values.

------------------------------------------------------------------------
r1075 | ajapted | 2012-01-02

Eureka: added DarkerColor() function.

------------------------------------------------------------------------
r1074 | ajapted | 2012-01-02

Eureka: renamed pcolour_t --> rgb_color_t

------------------------------------------------------------------------
r1073 | ajapted | 2012-01-02

Eureka: made DARKGREY and LIGHTGREY a bit brighter, and DARKGREY is
used for things now (removed THING_REM constant).

------------------------------------------------------------------------
r1072 | ajapted | 2012-01-02

Eureka: implemented dragging a vertex onto a linedef to split it.

------------------------------------------------------------------------
r1071 | ajapted | 2012-01-02

Eureka: use "highlighted()" instead of "! highlighted.is_nil()"

------------------------------------------------------------------------
r1070 | ajapted | 2012-01-02

Eureka / Browser: added a 'X' close button at top right.

------------------------------------------------------------------------
r1069 | ajapted | 2012-01-02

Eureka: for user interface use 'Linedef' instead of 'LineDef'.

------------------------------------------------------------------------
r1068 | ajapted | 2012-01-02

Eureka: TODO update.

------------------------------------------------------------------------
r1067 | ajapted | 2012-01-02

Eureka: made ^U be the main key to unselect everything, instead of END.
The back-quota key (`) remains an alternative to ^U, as well as just
clicking in an empty spot.

Made the '0' key be an alternative for HOME key (centre map, zoom out).

------------------------------------------------------------------------
r1066 | ajapted | 2012-01-02

Eureka: when dragging, require the pointer to move at least 6 pixels
before the drag is considered valid.  This prevents accidentally moving
an object when all you wanted to do was select it.

------------------------------------------------------------------------
r1065 | ajapted | 2012-01-02

Eureka: TODO update.

------------------------------------------------------------------------
r1064 | ajapted | 2012-01-02

Eureka: never highlight a 'split_line' when a vertex is highlighted.

Fixed updating the split_line while dragging a single vertex (however
the ability to split the line after the drag is not implemented yet).

------------------------------------------------------------------------
r1063 | ajapted | 2012-01-02

Eureka: code reformatting of 'for' loops, have a space before the ';' separators.

------------------------------------------------------------------------
r1062 | ajapted | 2012-01-02

Eureka: added SIDE_RIGHT and SIDE_LEFT constants.

------------------------------------------------------------------------
r1061 | ajapted | 2012-01-02

Eureka: removed unused constant 'Y_NULL'.

------------------------------------------------------------------------
r1060 | ajapted | 2012-01-02

Eureka: TODO update.

------------------------------------------------------------------------
r1059 | ajapted | 2012-01-02

Eureka: when adding vertices, prevent creating zero-length linedefs,
and when a vertex is highlighted and nothing is selected then merely
select that vertex -- this allows using the SPACE key to begin the
process of adding linedefs, which is quite convenient.

------------------------------------------------------------------------
r1058 | ajapted | 2012-01-02

Eureka: when using 'x' key to split linedefs, don't selected the new
linedefs if they were not selected before.

------------------------------------------------------------------------
r1057 | ajapted | 2012-01-01

tweak.

------------------------------------------------------------------------
r1056 | ajapted | 2012-01-01

Eureka: pass size to CreateSquare().

------------------------------------------------------------------------
r1055 | ajapted | 2012-01-01

tweak.

------------------------------------------------------------------------
r1054 | ajapted | 2012-01-01

Eureka: got the 'Choose' buttons in the Line/Sector/Thing panels working
[they open up the browser on the appropriate list of types].

------------------------------------------------------------------------
r1053 | ajapted | 2012-01-01

tweak.

------------------------------------------------------------------------
r1052 | ajapted | 2012-01-01

Eureka / 3D View: removed "walking" mode, the 'w' key now just moves
the camera Z to the ground + viewheight.

------------------------------------------------------------------------
r1051 | ajapted | 2012-01-01

Eureka: changed the sector height +/- buttons step from 16 to 8.
(It needs to be configurable though).

------------------------------------------------------------------------
r1050 | ajapted | 2011-12-31

Eureka: fixed silly bug in Drag_UpdateObjectDist().

------------------------------------------------------------------------
r1049 | ajapted | 2011-12-31

Eureka: fixed dragging of objects to honor snapping, and use a focus
object as returned by GetDrawFocus().

------------------------------------------------------------------------
r1048 | ajapted | 2011-12-31

Eureka: fixed bug in GetDragFocus() -- uninitialized variables.

------------------------------------------------------------------------
r1047 | ajapted | 2011-12-31

Eureka: minor renaming: mapx --> map_x, mapy --> map_y

------------------------------------------------------------------------
r1046 | ajapted | 2011-12-31

Eureka: improved GetDragFocus() code in two major ways:
  (1) check ALL the objects in the selection

  (2) when snapping is active, check if the majority of the objects
      are on the grid -- if so then only pick a coordinate which is
      also on the grid.

------------------------------------------------------------------------
r1045 | ajapted | 2011-12-31

Eureka: added OnGrid() method to test if a point is on the grid.

------------------------------------------------------------------------
r1044 | ajapted | 2011-12-31

Eureka: implemented GetDragFocus() which returns the coordinate of
the selected object which will be used as the focus for dragging
(especially when grid-snapping, that coordinate will snap to the grid).

------------------------------------------------------------------------
r1043 | ajapted | 2011-12-30

Eureka: TODO update.

------------------------------------------------------------------------
r1042 | ajapted | 2011-12-30

Makefile: lowercased program name: Eureka --> eureka

------------------------------------------------------------------------
r972 | ajapted | 2011-12-11

Eureka: TODO update.

------------------------------------------------------------------------
r960 | ajapted | 2011-12-09

Eureka / Browser: ability to scroll browser with PGUP and PGDN keys.

------------------------------------------------------------------------
r959 | ajapted | 2011-12-09

Eureka: minor reformatting.

------------------------------------------------------------------------
r958 | ajapted | 2011-12-09

Eureka / Browser: fixed scrolling anomalies.

------------------------------------------------------------------------
r957 | ajapted | 2011-12-08

Eureka: mucho tweakage of 'About' window appearance.

------------------------------------------------------------------------
r956 | ajapted | 2011-12-08

Eureka: implemented a basic 'About' window.

New code files: ui_about.cc/h and ui_hyper.cc/h

------------------------------------------------------------------------
r955 | ajapted | 2011-12-07

Eureka: TODO update.

------------------------------------------------------------------------
r954 | ajapted | 2011-12-07

Eureka: when adding a vertex which BOTH splits a line and adds a line,
don't reselect the new vertex.

------------------------------------------------------------------------
r953 | ajapted | 2011-12-07

color tweak.

------------------------------------------------------------------------
r952 | ajapted | 2011-12-07

Eureka: implemented being able to split a linedef in Vertex mode by
simply hovering over a linedef and pressing INSERT.

------------------------------------------------------------------------
r951 | ajapted | 2011-12-07

Eureka: fixed the logic to highlight a to-be-split linedef.

------------------------------------------------------------------------
r950 | ajapted | 2011-12-07

Eureka: worked on logic to find the linedef which would be split by a new
vertex.

------------------------------------------------------------------------
r949 | ajapted | 2011-12-07

Eureka: worked on logic to highlight a linedef which would be split
by a newly inserted vertex.

------------------------------------------------------------------------
r948 | ajapted | 2011-12-07

Eureka: when adding linedefs in Vertex mode, don't select the second
vertex when it wasn't a new vertex (i.e. after closing off an area).

------------------------------------------------------------------------
r947 | ajapted | 2011-12-07

Eureka: TODO update.

------------------------------------------------------------------------
r946 | ajapted | 2011-12-07

Eureka / README: describe 'e' / 'E' keys for SECTOR mode.

------------------------------------------------------------------------
r945 | ajapted | 2011-12-07

Eureka: when selecting contiguous sectors, never go through closed doors.

------------------------------------------------------------------------
r944 | ajapted | 2011-12-07

Eureka: implemented new command 'e' / 'E' in SECTORS mode which selects
contiguous sectors with the same floor height / texture.

------------------------------------------------------------------------
r943 | ajapted | 2011-12-07

Eureka: implemented 'E' key which selects lines in a path which all
share the same texture.

------------------------------------------------------------------------
r942 | ajapted | 2011-12-07

Eureka: made 'e' key (Select-lines-in-path) use additive mode.

The CTRL-E key is also the same function (compatibility with Yadex),
though it still could be nabbed for a better use in the future.

------------------------------------------------------------------------
r941 | ajapted | 2011-12-07

Eureka: TODO + WISHLIST update.

------------------------------------------------------------------------
r940 | ajapted | 2011-12-07

Eureka: have a Browser_Key() and Grid_Key() function.

------------------------------------------------------------------------
r939 | ajapted | 2011-12-06

Eureka: worked on having a Global_Key() function which handles all
global stuff (such as 'b' to toggle the Browser panel).  Editor_Key()
will be reserved for commands that modify the map or grid.

------------------------------------------------------------------------
r938 | ajapted | 2011-12-06

Eureka: fixed sidedef info (in LineDef panel) not being updated when
picking new textures on selected linedefs.

------------------------------------------------------------------------
r937 | ajapted | 2011-12-06

Eureka: honor grid snapping when pasting + pointer is outside window.

------------------------------------------------------------------------
r936 | ajapted | 2011-12-06

Eureka: fixed Paste (^V) and Copy (o) commands to honor grid snapping,
and improved method to find the "centre" vertex or thing (return the
coordinate of an actual vertex or thing in the group) -- hence if the
copied group was all aligned to the grid, the pasted one will be too.

------------------------------------------------------------------------
r935 | ajapted | 2011-12-06

Eureka: provide a function to check if clipboard contains stuff.

------------------------------------------------------------------------
r934 | ajapted | 2011-12-06

Eureka: when inserting sectors, don't clone the currently selected one
unless the SHIFT key is pressed.  When inserting linedef, check whether
a linedef between the two vertices exists already.

Removed the crufty old InsertNewObject() code.

------------------------------------------------------------------------
r933 | ajapted | 2011-12-06

Eureka: implemented key (CTRL-U or CTRL-K) to clear the search box.

------------------------------------------------------------------------
r932 | ajapted | 2011-12-06

Eureka / Browser: implemented 'c' key to cycle through categories,
and the 'C' key to reset category to "ALL".

------------------------------------------------------------------------
r931 | ajapted | 2011-12-06

Eureka: yet another TODO / WISHLIST update.

------------------------------------------------------------------------
r930 | ajapted | 2011-12-06

Eureka / Browser: support categories for Thing Types and Line Types.

------------------------------------------------------------------------
r929 | ajapted | 2011-12-06

Eureka / Browser: support categories for Textures and Flats.

------------------------------------------------------------------------
r928 | ajapted | 2011-12-06

Eureka / Browser: worked on getting the Category / Search working, and
removed various old crud.

------------------------------------------------------------------------
r927 | ajapted | 2011-12-06

Eureka: version bump, really good progress with the Browser.

------------------------------------------------------------------------
r926 | ajapted | 2011-12-06

Eureka: show mid-masked textures with a bright CYAN background.

------------------------------------------------------------------------
r925 | ajapted | 2011-12-06

Eureka: added panel_W, browser_W fields to UI_Window class.

------------------------------------------------------------------------
r924 | ajapted | 2011-12-06

tweaks.

------------------------------------------------------------------------
r923 | ajapted | 2011-12-06

Eureka: force the Kromulent Factor (KF) = 1 for time being.

------------------------------------------------------------------------
r922 | ajapted | 2011-12-06

Eureka: TODO / WISHLIST update.

------------------------------------------------------------------------
r921 | ajapted | 2011-12-06

Eureka / Browser: make it wider, enough for 4 flats or two 128-wide textures.

------------------------------------------------------------------------
r920 | ajapted | 2011-12-06

Eureka: when loading textures, skip the very first entry (#0) since it's
not really usable -- in the DOOM engine the #0 texture is never drawn.

------------------------------------------------------------------------
r919 | ajapted | 2011-12-06

Eureka / Browser: have two constructors for Browser_Item: simple one
for text buttons (e.g. Thing Types) and second one for picture buttons
(Textures and Flats).  The textual buttons are now working again.

------------------------------------------------------------------------
r918 | ajapted | 2011-12-06

Eureka / Browser: show flat and texture names underneath the pic.

------------------------------------------------------------------------
r917 | ajapted | 2011-12-05

Eureka: TODO update.

------------------------------------------------------------------------
r916 | ajapted | 2011-12-05

Eureka / Browser: fixed bug with funny gaps at the top (the Filter method
was visited the scrollbar widgets since they were not the last ones).

Made the background of scrolling part be BLACK for textures and flats.
Various tweaks and tidying of the code.

------------------------------------------------------------------------
r915 | ajapted | 2011-12-05

Eureka / Browser: fixed the side-by-side packing logic in Filter().

------------------------------------------------------------------------
r914 | ajapted | 2011-12-05

Eureka / Menu: added FL_MENU_INACTIVE to the divider lines, and tidied
up some junk in there.

------------------------------------------------------------------------
r913 | ajapted | 2011-12-05

Eureka: TODO / WISHLIST stuff.

------------------------------------------------------------------------
r912 | ajapted | 2011-12-05

Eureka / Browser: worked on Filter() logic and side-by-side packing...

------------------------------------------------------------------------
r911 | ajapted | 2011-12-05

Eureka / Browser: partial work on handling the Category setting....

------------------------------------------------------------------------
r910 | ajapted | 2011-12-04

Eureka / Browser: code to setup the Category choices for each browser box.
(the choice is not used yet however).

------------------------------------------------------------------------
r909 | ajapted | 2011-12-04

Eureka / README: a couple more fixes.

------------------------------------------------------------------------
r908 | ajapted | 2011-12-04

Eureka / README: small fix.

------------------------------------------------------------------------
r907 | ajapted | 2011-12-04

Eureka / Browser: fixed the Texture/Flat browser not showing anything,
we need to Populate() the browser boxes _after_ loading all the flats
and textures from the wad(s).

------------------------------------------------------------------------
r906 | ajapted | 2011-12-04

Eureka / Browser: various fixes, the new structure is now working OK.

------------------------------------------------------------------------
r905 | ajapted | 2011-12-04

Eureka / Browser: worked on new structure, where UI_Browser is a container
widget which contains (and controls) a bunch of UI_Browser_Box widgets.

------------------------------------------------------------------------
r904 | ajapted | 2011-12-04

Eureka: created empty "boom.ugh" and "edge.ugh" engine config files
(in preparation to move the specific pieces out of doom2.ugh).

------------------------------------------------------------------------
r903 | ajapted | 2011-12-04

Eureka: moved DOOM2 game configuration file --> configs/ folder.

------------------------------------------------------------------------
r902 | ajapted | 2011-12-04

Eureka: addid configs/ folder.

------------------------------------------------------------------------
r901 | ajapted | 2011-12-04

Eureka: fixes for the new Browser menu...

------------------------------------------------------------------------
r900 | ajapted | 2011-12-04

Eureka: added a "Browser" menu on the main menu bar, worked on code to
support it.

------------------------------------------------------------------------
r899 | ajapted | 2011-12-04

Eureka / Canvas: tweaked size of Knobby lines.

------------------------------------------------------------------------
r898 | ajapted | 2011-12-04

Eureka / Browser: worked on a UI_Browser_Menu class.

------------------------------------------------------------------------
r897 | ajapted | 2011-12-04

Eureka: TODO update.

------------------------------------------------------------------------
r896 | ajapted | 2011-12-04

tweak.

------------------------------------------------------------------------
r895 | ajapted | 2011-12-03

Eureka: when making category menu strings, also return the group letters
so they can be used to filter the browser items.

------------------------------------------------------------------------
r894 | ajapted | 2011-12-03

tweak.

------------------------------------------------------------------------
r893 | ajapted | 2011-12-03

Eureka: capitalize 'OTHER' in browser categories.

------------------------------------------------------------------------
r892 | ajapted | 2011-12-03

Eureka: fixed missing '|' in category string conversion.

------------------------------------------------------------------------
r891 | ajapted | 2011-12-03

Eureka: added code to convert the descriptions in linegroups (etc)
into a menu string which can be used in an Fl_Choice widget.

------------------------------------------------------------------------
r890 | ajapted | 2011-12-03

Eureka: updated game config loader to handle 'texturegroup', 'texture'
and 'flat' definitions.

------------------------------------------------------------------------
r889 | ajapted | 2011-12-03

Eureka / DOOM2 config: use '-' (not 'x') as letter for "Other" category,
and added the '-' as a thinggroup and a texturegroup too.

------------------------------------------------------------------------
r888 | ajapted | 2011-12-03

Eureka / DOOM2 config: finished texture/flat section, tweaked things section.

------------------------------------------------------------------------
r887 | ajapted | 2011-12-02

Eureka / DOOM2 config: worked on texture categories.

------------------------------------------------------------------------
r886 | ajapted | 2011-11-30

Eureka / 3D view: experimental code to draw a highlight border around
a solid surface (lower, upper, floor, ceiling).

------------------------------------------------------------------------
r885 | ajapted | 2011-11-30

Eureka: moved some color #defines --> im_color.h

------------------------------------------------------------------------
r884 | ajapted | 2011-11-30

Eureka / DOOM2 config: tweaked descriptions of some linetypes.

------------------------------------------------------------------------
r883 | ajapted | 2011-11-30

Eureka / DOOM2 config: gave some things prefixes, e.g. "MON:" for monsters,
"PU:" for pickups and "WP:" for weapons.

------------------------------------------------------------------------
r882 | ajapted | 2011-11-30

Eureka / Browser: tweaked layout.

------------------------------------------------------------------------
r881 | ajapted | 2011-11-30

Eureka: made the Browser a bit wider (to make things fit more comfortably).

------------------------------------------------------------------------
r880 | ajapted | 2011-11-30

Version bump to 0.666 in honor of Texture/Flat browser working.

------------------------------------------------------------------------
r879 | ajapted | 2011-11-30

Eureka / Browser: only allow Right click to change sector ceilings
(not SHIFT or middle click) -- for consistency with linedef handling.

------------------------------------------------------------------------
r878 | ajapted | 2011-11-30

Eureka / Browser: imlemented logic for setting textures on two-sided
lines.  Left click adjusts lowers and Right click adjusts uppers, and
Middle click sets mid-masked textures (on both sides).  For lowers
and uppers we pick the side that faces out, but SHIFT key picks the
opposite side.  Also some logic for handling windows nicely (change
BOTH lower and upper, but only with Left click).

------------------------------------------------------------------------
r877 | ajapted | 2011-11-30

Eureka: the normal select-lines-in-path (on 'e' key) now doesn't unmerge
if the original line was selected, since the whole selection gets cleared
anyway.  New way is more useful when lots of lines are selected and you
only want the new path to be selected.

------------------------------------------------------------------------
r876 | ajapted | 2011-11-30

Eureka / Browser: got texture setting on one-sided linedefs working.

------------------------------------------------------------------------
r875 | ajapted | 2011-11-30

Eureka: tweaked UI_Sector:SetTexture() code (check if count > 0).

------------------------------------------------------------------------
r874 | ajapted | 2011-11-30

Eureka / Browser: got texture setting for floors and ceilings working,
where a left click sets the floor and a right click sets the ceilings.

------------------------------------------------------------------------
r873 | ajapted | 2011-11-30

Eureka / Browser: partial worked on ability to set flat and textures on
sectors and linedefs via the browser.  Changed button to Fl_Repeat_Button
since that widget lets us check what buttons / modifiers were used.
(The standard Fl_Button callback gets done on RELEASE --> no buttons).

------------------------------------------------------------------------
r872 | ajapted | 2011-11-30

Eureka: renamed code file: selpath --> e_path

------------------------------------------------------------------------
r871 | ajapted | 2011-11-30

Eureka: renamed code file: selpath --> e_path

------------------------------------------------------------------------
r870 | ajapted | 2011-11-30

Eureka: added keys for CMD_SelectLinesInPath : 'e' for normal mode,
CTRL-E for the additive mode.

------------------------------------------------------------------------
r869 | ajapted | 2011-11-30

Eureka: for selecting lines in a path, have 'additive' parameter which
does not forget the current selection.  The 'one_sided' mode proved to
be fairly useless, hence removed that logic.

------------------------------------------------------------------------
r868 | ajapted | 2011-11-30

Eureka: finished CMD_SelectLinesInPath() : logic to get starting line.

------------------------------------------------------------------------
r867 | ajapted | 2011-11-30

Eureka: added TwoSided() method to LineDef class.

------------------------------------------------------------------------
r866 | ajapted | 2011-11-30

Eureka: implemented 'one_sided' mode for CMD_SelectLinesInPath().

------------------------------------------------------------------------
r865 | ajapted | 2011-11-30

Eureka: wrote new logic for selecting linedefs in a path.

------------------------------------------------------------------------
r864 | ajapted | 2011-11-29

Eureka: changed INSERT alternate key from 'a' --> SPACE, and changed
the Clear Selection key from SPACE --> END or backquote.

------------------------------------------------------------------------
r863 | ajapted | 2011-11-29

Eureka / Browser: worked on positioning the Flat and Texture pics.

------------------------------------------------------------------------
r862 | ajapted | 2011-11-29

Eureka: made the browser panel a bit wider.

------------------------------------------------------------------------
r861 | ajapted | 2011-11-29

Eureka: upgrade to FLTK 1.3.0 (this is required since the texture browser
was overflowing the 16-bit widget coordinates of FLTK 1.1.x).

------------------------------------------------------------------------
r860 | ajapted | 2011-11-29

Eureka / Browser: fixed searching to handle '^' and '$' properly
(they are not handled by fl_filename_match).

------------------------------------------------------------------------
r859 | ajapted | 2011-11-29

Eureka: version bump, in honor of progress with the Browser.

------------------------------------------------------------------------
r858 | ajapted | 2011-11-29

Eureka: implemented setting Thing and Sector types via the browser.

------------------------------------------------------------------------
r857 | ajapted | 2011-11-29

Eureka: TODO update.

------------------------------------------------------------------------
r856 | ajapted | 2011-11-29

Eureka / 3D Preview: allow 'b' key to toggle the browser.

------------------------------------------------------------------------
r855 | ajapted | 2011-11-29

Eureka: saving the map now clears MadeChanges, preventing the wrong
message about the map having unsaved changes when going to quit.

------------------------------------------------------------------------
r854 | ajapted | 2011-11-29

Eureka: re-implemented a swap-flats command for sectors, bound to 'w' key.

------------------------------------------------------------------------
r853 | ajapted | 2011-11-28

Eureka: TODO updated.

------------------------------------------------------------------------
r852 | ajapted | 2011-11-28

Eureka / Browser: can now change Linedef types via the browser!

------------------------------------------------------------------------
r851 | ajapted | 2011-11-28

Eureka: ensure a new object (added with 'a' / INS) gets selected.

------------------------------------------------------------------------
r850 | ajapted | 2011-11-28

Eureka / Browser: clear search string when mode changes due to a new edit mode.

------------------------------------------------------------------------
r849 | ajapted | 2011-11-28

Eureka / Browser: make each browser item into a button.

------------------------------------------------------------------------
r848 | ajapted | 2011-11-28

Eureka: renamed methods: SetMode() --> NewEditMode()

------------------------------------------------------------------------
r847 | ajapted | 2011-11-28

Eureka / Browser: change the browser mode (Textures / Flats / Things)
when the edit mode changes to LineDefs / Sectors / Things bzw.

------------------------------------------------------------------------
r846 | ajapted | 2011-11-28

Eureka / Browser: worked on support for Textures and Flats.  Only the
names are being shown so far....

------------------------------------------------------------------------
r845 | ajapted | 2011-11-28

Eureka / Browser: clear search box when changing Mode.

------------------------------------------------------------------------
r844 | ajapted | 2011-11-28

Eureka / Browser: implemented the search function.

------------------------------------------------------------------------
r843 | ajapted | 2011-11-28

Eureka / Doom2 config: tweaked some descriptions, especially the zero
linedef type and sector type.

------------------------------------------------------------------------
r842 | ajapted | 2011-11-28

Eureka / Browser: fixed missing end() from Browser_Item constructor,
and for search box update the list whenever it changes.

------------------------------------------------------------------------
r841 | ajapted | 2011-11-28

Eureka / Browser: use to callback to update the list when the mode,
category or search box changes.

------------------------------------------------------------------------
r840 | ajapted | 2011-11-28

Eureka / Browser: code to populate the list with ThingTypes, LineTypes
and SectorTypes.

------------------------------------------------------------------------
r839 | ajapted | 2011-11-28

Eureka / Browser: began work to populate the browser with useful stuff
like line_types and thing_types.

------------------------------------------------------------------------
r838 | ajapted | 2011-11-28

Eureka: comment tweak.

------------------------------------------------------------------------
r837 | ajapted | 2011-11-28

Eureka: tweaked gap at bottom of side panel + right end of menu bar.

------------------------------------------------------------------------
r836 | ajapted | 2011-11-28

Eureka / Browser: dead code removal.

------------------------------------------------------------------------
r835 | ajapted | 2011-11-28

Eureka: worked on Browser widget, use Fl_Scroll for the scrolling list.

------------------------------------------------------------------------
r834 | ajapted | 2011-11-28

Eureka: more work to fix Browser size when resizing.

------------------------------------------------------------------------
r833 | ajapted | 2011-11-27

Eureka: needed to call init_sizes() in window's ShowBrowser() method
since the widgets got rearranged.

------------------------------------------------------------------------
r832 | ajapted | 2011-11-27

Eureka / README: minor fix.

------------------------------------------------------------------------
r831 | ajapted | 2011-11-27

Eureka / Makefile: fixed 'make clean' target.

------------------------------------------------------------------------
r830 | ajapted | 2011-11-27

Eureka: document tweaks.

------------------------------------------------------------------------
r829 | ajapted | 2011-11-27

Eureka: TODO update.

------------------------------------------------------------------------
r828 | ajapted | 2011-11-27

Eureka: make sure all quit methods (ESCAPE key, File menu, window close
button) work the same way, and ask for confirmation if the map has been
modified.

------------------------------------------------------------------------
r827 | ajapted | 2011-11-27

Eureka: fixed the current map name (right side of infobar).

------------------------------------------------------------------------
r826 | ajapted | 2011-11-27

Eureka: fixed the infobar "lock" widget to update the editor state
(i.e. grid.snap and grid.locked) when changed.

------------------------------------------------------------------------
r825 | ajapted | 2011-11-27

Eureka / README: note requirement of doom2.wad, various tweaks.

------------------------------------------------------------------------
r824 | ajapted | 2011-11-27

Eureka / README: added copyright / license section.

------------------------------------------------------------------------
r823 | ajapted | 2011-11-27

Eureka / README: more work, new "RUNNING" section etc...

------------------------------------------------------------------------
r822 | ajapted | 2011-11-27

Eureka: moved keyboard command list from FEATURES.txt --> README.txt
and added some extra ones (especially for 3D preview).

------------------------------------------------------------------------
r821 | ajapted | 2011-11-27

Eureka: began work on a basic README.txt document.

------------------------------------------------------------------------
r820 | ajapted | 2011-11-27

Eureka: added basic INSTALL.txt document.

------------------------------------------------------------------------
r819 | ajapted | 2011-11-27

Eureka: code formatting tweak.

------------------------------------------------------------------------
r818 | ajapted | 2011-11-27

Eureka: minor tweak

------------------------------------------------------------------------
r817 | ajapted | 2011-11-27

Eureka: version bump.

------------------------------------------------------------------------
r816 | ajapted | 2011-11-27

TODO / WISHLIST twiddling....

------------------------------------------------------------------------
r815 | ajapted | 2011-11-27

Eureka: fixed wrong values with light "-" button (in Sector panel).

------------------------------------------------------------------------
r814 | ajapted | 2011-11-27

Eureka / Render3D: implemented low-detail mode (toggle via F5 key).

------------------------------------------------------------------------
r813 | ajapted | 2011-11-27

Eureka / Render3D: implemented a "lo-res" mode.

------------------------------------------------------------------------
r812 | ajapted | 2011-11-27

Eureka: added 'lib_linux' folder.

------------------------------------------------------------------------
r811 | ajapted | 2011-11-27

Eureka: moved MEMORY.txt document --> attic/

------------------------------------------------------------------------
r810 | ajapted | 2011-11-27

Eureka: added 'attic' folder.

------------------------------------------------------------------------
r809 | ajapted | 2011-11-27

Eureka / Makefile: fixed location of exe.

------------------------------------------------------------------------
r808 | ajapted | 2011-11-27

Eureka / Makefile: updated for top-level and obj_linux folder.

------------------------------------------------------------------------
r807 | ajapted | 2011-11-27

Eureka: added 'obj_linux' folder for the build process.

------------------------------------------------------------------------
r806 | ajapted | 2011-11-27

Eureka: TODO update.

------------------------------------------------------------------------
r805 | ajapted | 2011-11-27

Eureka: moved Makefile to top level.

------------------------------------------------------------------------
r804 | ajapted | 2011-11-27

Eureka / Render3D: enable 'lighting' by default.

------------------------------------------------------------------------
r803 | ajapted | 2011-11-27

Eureka / Render3D: support for aspect-ratio correction.

------------------------------------------------------------------------
r802 | ajapted | 2011-11-27

Eureka / Render3D: tweaked mouse scrolling (future option to allow both
angular and Z movement at same time).

------------------------------------------------------------------------
r801 | ajapted | 2011-11-27

Eureka: fixed 3D preview to handle resizing the main window.

------------------------------------------------------------------------
r800 | ajapted | 2011-11-27

Eureka: draw "knobby" linedefs (only in LineDef and Vertex mode).

------------------------------------------------------------------------
r799 | ajapted | 2011-11-26

Eureka: fixed vertical stretching of info panels (Things etc) when
resizing the main window.

------------------------------------------------------------------------
r543 | ajapted | 2010-09-24

MEMORY doc: changed COPY_GROUP to a more general 'GROUP' object, and
renamed EDIT_GROUP --> EDIT_SET.

------------------------------------------------------------------------
r542 | ajapted | 2010-09-24

MEMORY doc: described the edit operations, added STRING objects.

------------------------------------------------------------------------
r541 | ajapted | 2010-09-24

MEMORY document: added lots more detail.

------------------------------------------------------------------------
r540 | ajapted | 2010-09-24

Added MEMORY.txt : document the memory model for map objects.

------------------------------------------------------------------------
r539 | ajapted | 2010-09-24

Makefile: library folder is now 'lib_linux'

------------------------------------------------------------------------
r538 | ajapted | 2010-09-24

FIXED (thank dog!) the ESCAPE key quitting unconditionally.

------------------------------------------------------------------------
r528 | ajapted | 2010-05-16

tweak

------------------------------------------------------------------------
r449 | ajapted | 2009-12-02

Eureka: temporary hack (level loading stuff).

------------------------------------------------------------------------
r448 | ajapted | 2009-12-02

Use FLTK 1.1.10

------------------------------------------------------------------------
r445 | ajapted | 2009-11-09

Eureka: implemented showing and hiding the Browser panel (via 'b' key).

------------------------------------------------------------------------
r444 | ajapted | 2009-11-09

Eureka: bit more work on Browser stuff.

------------------------------------------------------------------------
r443 | ajapted | 2009-11-09

Eureka: worked on the UI_Browser widget, the top section now has a choice
button for the current type (Textures, Flats, etc), plus a choice button
for the current group (useful for things), plus a search field, and lastly
a check button on whether to show images or not.  [PROTOTYPE ONLY]

------------------------------------------------------------------------
r442 | ajapted | 2009-11-08

Eureka: renamed UI_FlatTexList --> UI_Browser (et cetera).

------------------------------------------------------------------------
r441 | ajapted | 2009-11-08

Eureka: renamed code files: ui_flattex --> ui_browser

------------------------------------------------------------------------
r440 | ajapted | 2009-11-08

TODO update.

------------------------------------------------------------------------
r439 | ajapted | 2009-11-08

Eureka: draw an selected AND highlighted object in a different color, and
changed the selection color to a sky-blue.

------------------------------------------------------------------------
r438 | ajapted | 2009-11-08

Eureka: implemented mirror commands for the Edit menu.

------------------------------------------------------------------------
r437 | ajapted | 2009-11-08

Eureka: fixed Paste from the menu to place new items at centre of canvas.

------------------------------------------------------------------------
r436 | ajapted | 2009-11-08

noted a bug.

------------------------------------------------------------------------
r435 | ajapted | 2009-11-08

Eureka: implemented key to Flip linedefs.

------------------------------------------------------------------------
r434 | ajapted | 2009-11-08

todo tweakage.

------------------------------------------------------------------------
r433 | ajapted | 2009-11-08

Eureka: improved FindIslands() code to handle when the initial path is
itself an island, whereby it reaches out to the outer area.

------------------------------------------------------------------------
r432 | ajapted | 2009-11-08

Eureka: finding islands: fixed a bug (erroneous check on sidedefs).

------------------------------------------------------------------------
r431 | ajapted | 2009-11-08

Eureka: FindIslands() : recompute bbox on each call (it can change when
islands reach out to other geometry).

------------------------------------------------------------------------
r430 | ajapted | 2009-11-08

Eureka: further work on finding islands...

------------------------------------------------------------------------
r429 | ajapted | 2009-11-08

Eureka: fixed logic in OppositeLineDef() : result_side was wrong.

------------------------------------------------------------------------
r428 | ajapted | 2009-11-07

Eureka: preliminary work on Island-finding algorithm (for sector insertion).

------------------------------------------------------------------------
r427 | ajapted | 2009-11-07

Eureka: decreases the mapslack for highlighting a vertex, making it less
likely to accidentally join the wrong vertex while inserting lines (etc).

------------------------------------------------------------------------
r426 | ajapted | 2009-11-07

Eureka: fixed problem with "ugly" 45-degree lines, caused by width = 1
parameter in fl_line_style().  Using width = 0 produces nicer results.

------------------------------------------------------------------------
r425 | ajapted | 2009-11-07

Eureka: fixed bug with wrong initial grid step in the InfoBar.

------------------------------------------------------------------------
r424 | ajapted | 2009-11-07

Eureka: properly update the side panel after map changes.

------------------------------------------------------------------------
r423 | ajapted | 2009-11-07

Eureka: made sure linedefs inserted in vertex mode have Impassible flag.

------------------------------------------------------------------------
r422 | ajapted | 2009-11-07

Eureka: fixed re-selection after inserting a sector (into a space).

------------------------------------------------------------------------
r421 | ajapted | 2009-11-07

reformatted code.

------------------------------------------------------------------------
r420 | ajapted | 2009-11-07

Eureka: when inserting a sector, fixup linedefs which become 2-sided
(add 2S flag, clear impassible flag, make middle texture "-").

------------------------------------------------------------------------
r419 | ajapted | 2009-11-07

Eureka: version bumped to 0.61

------------------------------------------------------------------------
r418 | ajapted | 2009-11-07

Eureka: try harder to find a usable texture when linedef becomes
one-sided (check the to-be-removed sidedef too).

------------------------------------------------------------------------
r417 | ajapted | 2009-11-07

Eureka: for sector deletions, make sure to fix-up any linedefs which
become one-sided (update 2S and impassible flag, middle texture, and
flip if needed).

------------------------------------------------------------------------
r416 | ajapted | 2009-11-07

Eureka: e_cutpaste.cc : added new DoRemoveSideFromLine() function, and
moved all the CMD_Delete() code to the bottom of the file.

------------------------------------------------------------------------
r415 | ajapted | 2009-11-07

Eureka: made SHIFT + DELETE keep any unused bits (vertices etc).

------------------------------------------------------------------------
r414 | ajapted | 2009-11-07

Eureka: pass keymod_e to EditorKey() and similar functions.

------------------------------------------------------------------------
r413 | ajapted | 2009-11-07

Eureka: when deleting sectors, find and delete Linedefs which would be
unused afterwards -- and in turn unused vertices and sidedefs.

------------------------------------------------------------------------
r412 | ajapted | 2009-11-07

Eureka: remove unused sidedefs when deleting linedefs (same logic as
for vertices).

------------------------------------------------------------------------
r411 | ajapted | 2009-11-07

Eureka: reworked code to delete unused vertices when deleting linedefs.

------------------------------------------------------------------------
r410 | ajapted | 2009-11-07

Eureka: BASIS: no longer delete a linedef when it ends up with no sides,
that was too heavy handed (such linedefs are not valid for DOOM engines
but is allowed inside the editor).

------------------------------------------------------------------------
r409 | ajapted | 2009-11-07

Eureka: worked on making deletion of linedefs and sectors also remove
any vertices and/or sidedefs which would end up unused after deletion.
Also merged CMD_Delete() and CMD_FullDelete() into one function.

------------------------------------------------------------------------
r408 | ajapted | 2009-11-07

Eureka: ConvertSelection() now handles LINES->SIDES and SECTORS->SIDES.

------------------------------------------------------------------------
r407 | ajapted | 2009-11-07

Eureka: added new selection_c::unmerge() and intersect() methods.

------------------------------------------------------------------------
r406 | ajapted | 2009-11-06

TODO twiddling.

------------------------------------------------------------------------
r405 | ajapted | 2009-11-06

tweaks

------------------------------------------------------------------------
r404 | ajapted | 2009-11-06

Eureka: improved vertex insertion to merely add a linedef when two
vertices are selected (or one selected and one highlighted).

------------------------------------------------------------------------
r403 | ajapted | 2009-11-06

Eureka: added 'find_first' and 'find_second' methods to selection_c class.

------------------------------------------------------------------------
r402 | ajapted | 2009-11-06

Eureka: made the HOME key centre-and-zoom-out the map (instead of '0').

------------------------------------------------------------------------
r401 | ajapted | 2009-11-06

Eureka: the 'a' key is now equivalent to INSERT key (was 'i' before).

------------------------------------------------------------------------
r400 | ajapted | 2009-11-06

Eureka: bit more work on Sector insertions.

------------------------------------------------------------------------
r399 | ajapted | 2009-11-05

todo update.

------------------------------------------------------------------------
r398 | ajapted | 2009-11-05

Eureka: tweaked the key-binding list (FEATURES.txt)

------------------------------------------------------------------------
r397 | ajapted | 2009-11-05

Eureka: fixed some bugs in the AssignSectorToSpace() code.

------------------------------------------------------------------------
r396 | ajapted | 2009-11-05

Eureka: implemented DoAssignSector() function, for sector insertion code.

------------------------------------------------------------------------
r395 | ajapted | 2009-11-05

Eureka: worked on fixing the code which traces a closed path of linedefs
to determine where to place a new (or existing) sector reference.

------------------------------------------------------------------------
r394 | ajapted | 2009-11-05

tweaks.

------------------------------------------------------------------------
r393 | ajapted | 2009-11-05

Eureka: initial code for new OppositeLineDef() function.

------------------------------------------------------------------------
r392 | ajapted | 2009-11-05

Eureka: use new PointOutsideOfMap() check for creating a square when
inserting in Sector mode.

------------------------------------------------------------------------
r391 | ajapted | 2009-11-05

dead code removal.

------------------------------------------------------------------------
r390 | ajapted | 2009-11-05

Eureka: x_hover: added PointOutsideOfMap() utility function, and updated
the header file with the other new functions.

------------------------------------------------------------------------
r389 | ajapted | 2009-11-05

Eureka: improved get_cur_sector() logic by casting both vertical and
horizontal rays to find the closest linedef.

------------------------------------------------------------------------
r388 | ajapted | 2009-11-05

Eureka: fixed bugs in ClosestLine_CastingVerty() function.

------------------------------------------------------------------------
r387 | ajapted | 2009-11-05

Eureka: improved the ClosestLine_CastingXXX functions to (a) check both
casting directions, e.g. right AND left, and (b) return which side the
test point is on (1, 0, -1).

------------------------------------------------------------------------
r386 | ajapted | 2009-11-05

Eureka: x_hover.cc: separated code into new ClosestLineDef_CastingRight()
function, and added new ClosestLineDef_CastingUp() function.

------------------------------------------------------------------------
r385 | ajapted | 2009-11-05

Eureka: renamed map bounds global vars again: MapBound_[lh][xy]

------------------------------------------------------------------------
r384 | ajapted | 2009-11-05

code tidying.

------------------------------------------------------------------------
r383 | ajapted | 2009-11-05

Eureka: no need to invalidate the Selection when the inserted or deleted
object is above the max_obj().

------------------------------------------------------------------------
r382 | ajapted | 2009-11-05

Eureka: added fast max_obj() method to selection_c class, and renamed
the slow_count() method --> count_obj().

------------------------------------------------------------------------
r381 | ajapted | 2009-11-05

Eureka: further work on adjusting move/scroll speeds based on whether
SHIFT or CTRL keys are pressed.

------------------------------------------------------------------------
r380 | ajapted | 2009-11-04

Eureka render mode: more control over speed of forward/back/strafe keys
(CTRL faster, SHIFT slower).  Changed fly up/down keys to PGUP and PGDN.

Renamed key_mod_e --> keymod_e

------------------------------------------------------------------------
r379 | ajapted | 2009-11-04

Eureka: for 3D preview, made SHIFT and CTRL control the speed of moving
forward/backwards when using the mousewheel.

------------------------------------------------------------------------
r378 | ajapted | 2009-11-04

Eureka: added key_mod_e enumeration (KM_SHIFT, KM_CTRL etc).

------------------------------------------------------------------------
r377 | ajapted | 2009-11-04

Eureka: created new WISHLIST.txt document.

------------------------------------------------------------------------
r376 | ajapted | 2009-11-04

TODO update.

------------------------------------------------------------------------
r375 | ajapted | 2009-11-04

Eureka: made sane the usage of h1 and h2 fields of DrawSurf.

------------------------------------------------------------------------
r374 | ajapted | 2009-11-04

Eureka renderer: fixed y_offset for Mid-Masked textures, YAY!

------------------------------------------------------------------------
r373 | ajapted | 2009-11-04

Eureka: ignore self-referenced lines in 3D renderer.

------------------------------------------------------------------------
r372 | ajapted | 2009-11-04

Eureka: much better mid-masked textures in 3D preview.

------------------------------------------------------------------------
r371 | ajapted | 2009-11-04

reformatted some code.

------------------------------------------------------------------------
r370 | ajapted | 2009-11-04

Eureka: preliminary work on rendering mid-masked textures...

------------------------------------------------------------------------
r369 | ajapted | 2009-11-04

Eureka: worked on improving the x_hover.cc code.

------------------------------------------------------------------------
r368 | ajapted | 2009-11-04

Eureka: disabled experimental new 'get_cur_sector', which did not work
properly in several situations (cf MAP02 of TNT).

------------------------------------------------------------------------
r367 | ajapted | 2009-11-04

Eureka: renamed DistanceToLineDef() --> ApproxDistToLineDef().

------------------------------------------------------------------------
r366 | ajapted | 2009-11-04

Eureka: experimental new way to determine current sector at a point.

------------------------------------------------------------------------
r365 | ajapted | 2009-11-04

Eureka: removed unused utility function.

------------------------------------------------------------------------
r364 | ajapted | 2009-11-04

dead code removal.

------------------------------------------------------------------------
r363 | ajapted | 2009-11-04

Eureka: implemented a DistanceToLineDef() function.

Did some tidying in x_hover.cc

------------------------------------------------------------------------
r362 | ajapted | 2009-11-04

Eureka: moved some code in x_hover.cc

------------------------------------------------------------------------
r361 | ajapted | 2009-11-04

Eureka: make sure the Total value in each side panel is kept up-to-date.

------------------------------------------------------------------------
r360 | ajapted | 2009-11-04

Eureka: fixed input widgets on the side panels so that the ENTER key does
not jump to another widget, instead staying in that input widget.

------------------------------------------------------------------------
r359 | ajapted | 2009-11-04

Eureka: added list of needed Config items to the TODO.

------------------------------------------------------------------------
r358 | ajapted | 2009-11-04

Eureka: prevent ENTER key doing the 'Unselect All' command.

------------------------------------------------------------------------
r357 | ajapted | 2009-11-04

Eureka: tweaked speed of mouse-wheel forward/back in 3D preview.

------------------------------------------------------------------------
r356 | ajapted | 2009-11-04

Eureka: fixed (Un)select-All commands to update the side panel.

------------------------------------------------------------------------
r355 | ajapted | 2009-11-03

Eureka: show more info (strerror) in LOG.txt when a pwad cannot be opened.

------------------------------------------------------------------------
r354 | ajapted | 2009-11-03

tweak.

------------------------------------------------------------------------
r353 | ajapted | 2009-11-03

Eureka: fixed loading maps with lowercase texture or flat names in the
sidedefs or sectors -- they are silently converted to uppercase.

------------------------------------------------------------------------
r352 | ajapted | 2009-11-03

Eureka: support ON_CEILING things in the 3D preview.

------------------------------------------------------------------------
r351 | ajapted | 2009-11-03

Eureka: doom2 game config: lit up the keys and armor vests (added 'l' flag).

------------------------------------------------------------------------
r350 | ajapted | 2009-11-03

Eureka: draw Invis and Lit things properly in the 3D preview.

------------------------------------------------------------------------
r349 | ajapted | 2009-11-03

Eureka: game config: parse new 'l' and 'c' flags for things ('l' for Lit
things, 'c' for Ceiling things), and changed 's' --> 'i' (Invis).

------------------------------------------------------------------------
r348 | ajapted | 2009-11-03

Eureka: updated game file (doom2.ugh), giving lit objects the 'l' flags
and on-ceiling objects the 'c' flag, and changed 's' flag --> 'i'.

Also separated out the EDGE specific things.

------------------------------------------------------------------------
r347 | ajapted | 2009-11-03

Eureka: handle mouse motion/clicks better when the 3D preview is shown.

------------------------------------------------------------------------
r346 | ajapted | 2009-11-03

todo stuff

------------------------------------------------------------------------
r345 | ajapted | 2009-11-03

Eureka: renderer: better code to keep track of what sectors each thing
is in, recalculating when the number of things or sectors change, or
by the user pressing CTRL-L.

------------------------------------------------------------------------
r344 | ajapted | 2009-11-03

Eureka: can now bump gamma with F11 key (in 3D render view).

------------------------------------------------------------------------
r343 | ajapted | 2009-11-03

minor code reformatting.

------------------------------------------------------------------------
r342 | ajapted | 2009-11-03

Eureka: implemented renderer effect where N/S walls are brighter and
E/W walls are darker than normal.

------------------------------------------------------------------------
r341 | ajapted | 2009-11-03

Eureka: r_render.cc: misc tidying, replaced fucking 0 with NULL, etc..

------------------------------------------------------------------------
r340 | ajapted | 2009-11-02

todo tweak

------------------------------------------------------------------------
r339 | ajapted | 2009-11-02

Eureka: support for Lighting in the 3D preview.

------------------------------------------------------------------------
r338 | ajapted | 2009-11-02

Eureka: added code to load the COLORMAP lump.

------------------------------------------------------------------------
r337 | ajapted | 2009-11-02

Eureka: more reformatting in r_render.cc

------------------------------------------------------------------------
r336 | ajapted | 2009-11-02

Eureka: reformatted the code in r_render.cc

------------------------------------------------------------------------
r335 | ajapted | 2009-11-02

Eureka: added useful mode for Vertex/LineDef inserting: if _one_ vertex
is selected, then insert a new one, add a joining linedef, and re-select
the new vertex.  Also split thing, sector creation into separate funcs.

------------------------------------------------------------------------
r334 | ajapted | 2009-11-02

Eureka: added bare-bones code to create a new square-shape sector.

------------------------------------------------------------------------
r333 | ajapted | 2009-11-02

Eureka: renamed variables: MapMinX/Y, MapMaxX/Y --> Map_lx/y, Map_hx/y.

------------------------------------------------------------------------
r332 | ajapted | 2009-11-02

Eureka: debugging code to draw the level's Bounding box.

------------------------------------------------------------------------
r331 | ajapted | 2009-11-02

Eureka: implemented code (via MapStuff_NotifyXXX functions) to keep the
level bounds (MapMinX/Y and MapMaxX/Y globals) up-to-date.

------------------------------------------------------------------------
r330 | ajapted | 2009-11-02

Eureka: fixed Pasted objects to be selected (this broke due to recent
work on basis notifications).

------------------------------------------------------------------------
r329 | ajapted | 2009-11-02

Eureka: free textures at exit.

------------------------------------------------------------------------
r328 | ajapted | 2009-11-02

Eureka: fixed finding player for renderer when level has Voodoo dolls.

------------------------------------------------------------------------
r327 | ajapted | 2009-11-02

Eureka: fixed bugs in bitvec_c and selection_c classes.

------------------------------------------------------------------------
r326 | ajapted | 2009-11-02

Eureka: fixed memory leak in bitvec_c::resize() code.

------------------------------------------------------------------------
r325 | ajapted | 2009-11-02

Eureka: updated CMD_SelectAll() for recent selection_c changes.

------------------------------------------------------------------------
r324 | ajapted | 2009-11-02

Eureka: implemented new bitvec_c::resize() method.

------------------------------------------------------------------------
r323 | ajapted | 2009-11-02

Eureka: selection_c class: make the bitvector grow as needed, instead of
relying on NumObjects() which changes all the time.

------------------------------------------------------------------------
r322 | ajapted | 2009-11-01

TODO update.

------------------------------------------------------------------------
r321 | ajapted | 2009-11-01

Eureka: beginnings of the code for ObjectBox_NotifyXXX() functions.

------------------------------------------------------------------------
r320 | ajapted | 2009-11-01

Eureka: fixed assertion error due to recent changes.

------------------------------------------------------------------------
r319 | ajapted | 2009-11-01

Eureka: dead code removal (all the 'changed_a_xxxx' variables etc).

------------------------------------------------------------------------
r318 | ajapted | 2009-11-01

Eureka: implemented XXX_Notify() functions for the current Selection.

------------------------------------------------------------------------
r317 | ajapted | 2009-11-01

Eureka: call XXX_NotifyBegin() and XXX_NotifyEnd() functions from the Basis.

------------------------------------------------------------------------
r316 | ajapted | 2009-11-01

Eureka: more work on new BASIS notification framework (Clipboard bits).

------------------------------------------------------------------------
r315 | ajapted | 2009-11-01

Eureka: BASIS: partial work on new way of notifying other code about
changes/insertions/deletions of map structures.

------------------------------------------------------------------------
r314 | ajapted | 2009-11-01

Eureka: tweaked turning rate when using RMB.

------------------------------------------------------------------------
r313 | ajapted | 2009-11-01

Eureka: added NumObjects() utility function to the Basis.

------------------------------------------------------------------------
r312 | ajapted | 2009-11-01

Eureka: implemented the 'Select All' command (in edit menu).

------------------------------------------------------------------------
r311 | ajapted | 2009-11-01

Eureka: fixed a bug in selection_c::ConvertToBitvec().

------------------------------------------------------------------------
r310 | ajapted | 2009-11-01

Eureka: fixed bug using wrong NumXXX values in UI_ThingBox and UI_VertexBox.

------------------------------------------------------------------------
r309 | ajapted | 2009-11-01

todo tweak

------------------------------------------------------------------------
r308 | ajapted | 2009-11-01

Eureka: bit more work on having map changes updated all the widgets (etc).

------------------------------------------------------------------------
r307 | ajapted | 2009-11-01

Eureka: BASIS: new 'appended_an_object' variable.

------------------------------------------------------------------------
r306 | ajapted | 2009-10-31

Eureka: worked on a system (in the Basis) of remembering various types of
changes, so that various widgets (e.g. the canvas) can be updated with new
information automatically.

------------------------------------------------------------------------
r305 | ajapted | 2009-10-31

Eureka: can now turn and move up/down in the 3D preview with the mouse (RMB).

------------------------------------------------------------------------
r304 | ajapted | 2009-10-31

Eureka: UI_Nombre: improved the format (e.g. use '#' before the number).

------------------------------------------------------------------------
r303 | ajapted | 2009-10-31

Eureka: disabled the thing 'ExFloor' widget for now (punted feature).

------------------------------------------------------------------------
r302 | ajapted | 2009-10-31

Eureka: made '0' key be centre-and-zoom-out function, and disabled the
plain centre-map feature (on '`' key) as it seems not very useful.

------------------------------------------------------------------------
r301 | ajapted | 2009-10-31

Eureka: implemented ability to scroll the map with the mouse (RMB).

------------------------------------------------------------------------
r300 | ajapted | 2009-10-30

Eureka: fixed X-Offsets when splitting linedefs.

------------------------------------------------------------------------
r299 | ajapted | 2009-10-30

Eureka: re-implemented 'x' command to Split linedefs.

------------------------------------------------------------------------
r298 | ajapted | 2009-10-30

todo / docco update.

------------------------------------------------------------------------
r297 | ajapted | 2009-10-30

Eureka: the code trying to "fix" bad quantization didn't work and was very
inadequate.  Disabled for now, until better algorithms can be employed.

------------------------------------------------------------------------
r296 | ajapted | 2009-10-30

Eureka: worked on command to Quantize objects to the grid.

------------------------------------------------------------------------
r295 | ajapted | 2009-10-30

Eureka: added grid::ForceSnapX/Y methods.

------------------------------------------------------------------------
r294 | ajapted | 2009-10-30

Eureka: for 2x scaling, use the bottom left corner of the bbox as the
scaling origin, which is better at preserving grid snappage.

------------------------------------------------------------------------
r293 | ajapted | 2009-10-30

Eureka: implemented CMD_ScaleObjects() for 2x and 1/2 scaling.

------------------------------------------------------------------------
r292 | ajapted | 2009-10-30

Eureka: dead code removal (old flip_mirror stuff).

------------------------------------------------------------------------
r291 | ajapted | 2009-10-30

Eureka: implemented the Rotate-by-90-degrees commands.

------------------------------------------------------------------------
r290 | ajapted | 2009-10-30

Eureka: changed mirror keys to 'H' and 'I'.

------------------------------------------------------------------------
r289 | ajapted | 2009-10-30

Eureka: implemented Mirror command (horizontal and vertical).

------------------------------------------------------------------------
r288 | ajapted | 2009-10-30

Eureka: began work on commands to Mirror and Rotate90 objects.

------------------------------------------------------------------------
r287 | ajapted | 2009-10-30

Eureka: improved bbox_of_objects() to use the known radius of things.

------------------------------------------------------------------------
r286 | ajapted | 2009-10-30

Eureka: implemented new bbox_of_objects() function.

------------------------------------------------------------------------
r285 | ajapted | 2009-10-30

Eureka: re-implemented the centre_of_objects() function.

------------------------------------------------------------------------
r284 | ajapted | 2009-10-30

todo stuff.

------------------------------------------------------------------------
r283 | ajapted | 2009-10-30

commenting.

------------------------------------------------------------------------
r282 | ajapted | 2009-10-30

Eureka: implemented re-selected new objects after a Paste.

------------------------------------------------------------------------
r281 | ajapted | 2009-10-30

Eureka: added frob_range() method to selection_c class.

------------------------------------------------------------------------
r280 | ajapted | 2009-10-29

todo twiddle.

------------------------------------------------------------------------
r279 | ajapted | 2009-10-29

Eureka: began creating a list of keyboard commands.

------------------------------------------------------------------------
r278 | ajapted | 2009-10-29

todo twiddle.

------------------------------------------------------------------------
r277 | ajapted | 2009-10-29

debugging tidying.

------------------------------------------------------------------------
r276 | ajapted | 2009-10-29

Eureka: when dragging Sectors, drag their containing Things too.

------------------------------------------------------------------------
r275 | ajapted | 2009-10-29

Eureka: Dragging: actually move the objects after the drag.

------------------------------------------------------------------------
r274 | ajapted | 2009-10-29

Eureka: disable texture listbox for time being.

------------------------------------------------------------------------
r273 | ajapted | 2009-10-29

Eureka: worked on Dragging objects to new places.

------------------------------------------------------------------------
r272 | ajapted | 2009-10-29

Eureka: use 'obj_type_t' instead of 'int' for GetCurObject() parameter.

------------------------------------------------------------------------
r271 | ajapted | 2009-10-29

Eureka: use '0' key instead of '`' for zoom-and-centre-map function.

------------------------------------------------------------------------
r270 | ajapted | 2009-10-29

Eureka: removed unused variable: rulers.

------------------------------------------------------------------------
r269 | ajapted | 2009-10-29

Eureka: restored spin-thing keys to 'w' and 'x'.

------------------------------------------------------------------------
r268 | ajapted | 2009-10-29

Eureka: made clipboard handle sector Insertions like it handles deletions,
allowing the copied objects to survive longer (e.g. after undo).

------------------------------------------------------------------------
r267 | ajapted | 2009-10-29

Eureka: improved the way the clipboard reacts to Sector insertions and
deletions.  In particular, the clipboard can be preserved after a sector
is deleted (by adjusting the references).

------------------------------------------------------------------------
r266 | ajapted | 2009-10-29

Eureka: fixed thing positions when Pasting a copied sector.

------------------------------------------------------------------------
r265 | ajapted | 2009-10-29

debugging tweak.

------------------------------------------------------------------------
r264 | ajapted | 2009-10-29

Eureka: implemented Paste for linedefs and sectors (which involves creating
associated objects like vertices and sidedefs, and updating the references).

------------------------------------------------------------------------
r263 | ajapted | 2009-10-29

Eureka: further work on Cut'n'Paste code...

------------------------------------------------------------------------
r262 | ajapted | 2009-10-29

Eureka: implemented logic for Copying a group of linedefs or sectors
(and all associated objects) into the clipboard.

------------------------------------------------------------------------
r261 | ajapted | 2009-10-29

Eureka: Basis: no need to invalidate the clipboard when inserting new
Sectors at the very end of the array.

------------------------------------------------------------------------
r260 | ajapted | 2009-10-29

Eureka: support for Cut/Paste of vertices and RTS triggers.

------------------------------------------------------------------------
r259 | ajapted | 2009-10-29

Eureka: fixed pasting Things to move them to their new position (and
when multiple things are in the clipboard, find their centre).

------------------------------------------------------------------------
r258 | ajapted | 2009-10-29

Eureka: better handling of CTRL + letter keys.

------------------------------------------------------------------------
r257 | ajapted | 2009-10-29

Eureka: rewrote 'o' key command to use CMD_Copy + CMD_Paste.

------------------------------------------------------------------------
r256 | ajapted | 2009-10-29

Eureka: Basis: added RawCopy() methods to each class (Thing, Vertex etc).

------------------------------------------------------------------------
r255 | ajapted | 2009-10-29

Eureka: implemented CMD_Copy and CMD_Paste for THINGS.

------------------------------------------------------------------------
r254 | ajapted | 2009-10-29

Eureka: Basis: notify clipboard when sectors are deleted or inserted.

------------------------------------------------------------------------
r253 | ajapted | 2009-10-29

Eureka: fixed bugs in CMD_FullDelete().

------------------------------------------------------------------------
r252 | ajapted | 2009-10-29

Eureka: mainly commenting (new Cut'n'Paste code).

------------------------------------------------------------------------
r251 | ajapted | 2009-10-29

Eureka: moved CMD_Delete() code into e_cutpaste.cc file, and implemented
the CMD_FullDelete() which deletes things in sector mode.

------------------------------------------------------------------------
r250 | ajapted | 2009-10-28

Eureka: made ConvertSelection() into a general purpose function which
converts from one selection_c to another.

------------------------------------------------------------------------
r249 | ajapted | 2009-10-28

Eureka: BA_ClearAll() now clears the Clipboard too.

------------------------------------------------------------------------
r248 | ajapted | 2009-10-28

Eureka: preliminary clipboard_data_c class.

------------------------------------------------------------------------
r247 | ajapted | 2009-10-28

Eureka: updated menu code to use new Cut'n'Paste API.

------------------------------------------------------------------------
r246 | ajapted | 2009-10-28

update

------------------------------------------------------------------------
r245 | ajapted | 2009-10-28

Eureka: began work on Cut 'n' Paste functionality.

------------------------------------------------------------------------
r244 | ajapted | 2009-10-28

Eureka: properly handle mouse leaving the canvas area (e.g. unset the
currently highlighted object).

------------------------------------------------------------------------
r243 | ajapted | 2009-10-28

Eureka: force custom FLTK color scheme (default with Xfce looked pretty bad).

------------------------------------------------------------------------
r242 | ajapted | 2009-10-28

Eureka: fixed some warnings from GCC 4.3

------------------------------------------------------------------------
r241 | ajapted | 2009-10-26

Eureka: bit of work on SuperSectorSelector() code.

------------------------------------------------------------------------
r240 | ajapted | 2009-10-25

Eureka: changed default thing type to 2014 (from 3004).

------------------------------------------------------------------------
r239 | ajapted | 2009-10-25

Eureka: ability to Insert new things.

------------------------------------------------------------------------
r238 | ajapted | 2009-10-25

Eureka: for selection_c::clear() method, added unused but potentially
useful "slow" version which maintains the order of selections.

------------------------------------------------------------------------
r237 | ajapted | 2009-10-25

Eureka: ability to insert new vertices.

------------------------------------------------------------------------
r236 | ajapted | 2009-10-25

Eureka: don't push empty undo_group_cs onto the undo stack.

------------------------------------------------------------------------
r235 | ajapted | 2009-10-25

Eureka: began work on ability to insert new objects.

------------------------------------------------------------------------
r234 | ajapted | 2009-10-25

Eureka: small fix.

------------------------------------------------------------------------
r233 | ajapted | 2009-10-25

Eureka: implemented trickiest selection conversions: L->S and V->S.

------------------------------------------------------------------------
r232 | ajapted | 2009-10-25

Eureka: implemented V->L selection conversion.

------------------------------------------------------------------------
r231 | ajapted | 2009-10-25

Eureka: implemented S->L, S->V and L->V selection conversions.

------------------------------------------------------------------------
r230 | ajapted | 2009-10-25

Eureka: moved ConvertSelection() from editloop.cc --> selectn.cc

------------------------------------------------------------------------
r229 | ajapted | 2009-10-25

TODO update

------------------------------------------------------------------------
r228 | ajapted | 2009-10-25

Eureka: implemented selection conversion when going from sector mode to
things mode.  Made the SPACE key unselect everything.

------------------------------------------------------------------------
r227 | ajapted | 2009-10-25

Eureka: fixed BA_Delete() handling of bound objects, it was sufficient to
simply delete them before the main object.  Also changed sidedef deletion
behavior to delete the _linedef_ if it would end up with no sides at all.

------------------------------------------------------------------------
r226 | ajapted | 2009-10-25

Eureka: changed color of "error" linedefs to bright red (from pink).

------------------------------------------------------------------------
r225 | ajapted | 2009-10-25

Eureka: fixed bug in RawInsertLineDef() -- assertion checked wrong value.

------------------------------------------------------------------------
r224 | ajapted | 2009-10-25

Eureka: fixed BA_Delete() which was trying to delete the wrong bound
objects (they needed to be collected before applying the deletion).

------------------------------------------------------------------------
r223 | ajapted | 2009-10-25

Eureka: fix highlighted (Panel'd) object after deletion.

------------------------------------------------------------------------
r222 | ajapted | 2009-10-25

Eureka: move the DeleteFinally() stuff out of the edit_op_c destructor
and into a 'Destroy' method which gets called explicitly by the undo_group
destructor.  This fixes serious problems caused by the destructor being
called on temporaries of edit_op_c objects.

------------------------------------------------------------------------
r221 | ajapted | 2009-10-25

Eureka: reimplemented deletion of objects.

------------------------------------------------------------------------
r220 | ajapted | 2009-10-25

TODO tweak

------------------------------------------------------------------------
r219 | ajapted | 2009-10-25

Eureka: disable optimisations for time being (as a debugging aide).

------------------------------------------------------------------------
r218 | ajapted | 2009-10-25

Eureka: fixed problem in Undo/Redo code (clearing the history/future
arrays) that lead to assertion failures in subsequent operations.

------------------------------------------------------------------------
r217 | ajapted | 2009-10-25

Eureka: disabled some uncompilable code.

------------------------------------------------------------------------
r216 | ajapted | 2009-10-25

Eureka: TODO twiddles.

------------------------------------------------------------------------
r213 | ajapted | 2009-10-25

Moved 'eureka' folder to top level (out of tools/)

------------------------------------------------------------------------
r212 | ajapted | 2009-10-13

Eureka: version bump.

------------------------------------------------------------------------
r211 | ajapted | 2009-10-13

TODO update.

------------------------------------------------------------------------
r210 | ajapted | 2009-10-13

Eureka: fixed changing mode via the button on the Info Bar.

------------------------------------------------------------------------
r209 | ajapted | 2009-10-13

Eureka: fixed issues with initial editing mode.

------------------------------------------------------------------------
r208 | ajapted | 2009-10-13

Eureka: tweaked deltas for raising/lowering floors and ceilings.

------------------------------------------------------------------------
r207 | ajapted | 2009-10-13

Eureka: implemented typing in texture names in the SideDef panels.

------------------------------------------------------------------------
r206 | ajapted | 2009-10-13

Eureka: implemented x_offset/y_offset input boxes in SideDef panel.

------------------------------------------------------------------------
r205 | ajapted | 2009-10-13

updated TODO

------------------------------------------------------------------------
r204 | ajapted | 2009-10-13

Eureka: implemented sector input box for the SideDef Panel.

------------------------------------------------------------------------
r203 | ajapted | 2009-10-13

Eureka: updated UI_SideBox::TexFromWidget() to internalise the string.

------------------------------------------------------------------------
r202 | ajapted | 2009-10-13

Eureka: got the automap flags in the LineDef panel working.

------------------------------------------------------------------------
r201 | ajapted | 2009-10-13

Eureka: implemented ability in LineDef Panel to change type, tag and
most of the flags -- supporting multiple linedefs too.

------------------------------------------------------------------------
r200 | ajapted | 2009-10-13

Eureka: ui_thing.cc: renamed opt_callback_data_c --> thing_opt_CB_data_c

------------------------------------------------------------------------
r199 | ajapted | 2009-10-13

Dead code removal.

------------------------------------------------------------------------
r198 | ajapted | 2009-10-13

tweaks

------------------------------------------------------------------------
r197 | ajapted | 2009-10-13

Eureka: small fixes: made FlatFromWidget() uppercase the name, and fixed
GetCurrentObjects() to set the correct object type on the selection_c.

------------------------------------------------------------------------
r196 | ajapted | 2009-10-13

Eureka: implemented typing in texture names in the Sector panel.

------------------------------------------------------------------------
r195 | ajapted | 2009-10-13

Eureka: implemented the 'Type' and 'Tag' input boxes in the Sector panel.

------------------------------------------------------------------------
r194 | ajapted | 2009-10-13

minor fix

------------------------------------------------------------------------
r193 | ajapted | 2009-10-13

Eureka: implemented typing a value into light input box in Sector panel.

------------------------------------------------------------------------
r192 | ajapted | 2009-10-13

Eureka: implemented the light up/down buttons in the Sector panel,
via new CMD_AdjustLight() function in e_sector.cc

------------------------------------------------------------------------
r191 | ajapted | 2009-10-13

Eureka: moved CMD_MoveFloors() and CMD_MoveCeilings() into e_sector.cc

------------------------------------------------------------------------
r190 | ajapted | 2009-10-13

Eureka: renamed 'spin_things' function --> 'CMD_SpinThings', and moved
some of the logic there (GetCurrentObjects etc), simplifying other code.

------------------------------------------------------------------------
r189 | ajapted | 2009-10-13

Eureka: worked on keys and buttons to move sector floors/ceilings, via
new CMD_MoveFloors() and CMD_MoveCeilings() functions.

------------------------------------------------------------------------
r188 | ajapted | 2009-10-13

Eureka: reimplemented the floor_h, ceil_h and headroom input boxes in
the Sector Panel (support multiple selected sectors).

------------------------------------------------------------------------
r187 | ajapted | 2009-10-13

fixed small bug

------------------------------------------------------------------------
r186 | ajapted | 2009-10-13

Eureka: fixed CLAMP() macro.

------------------------------------------------------------------------
r185 | ajapted | 2009-10-13

Eureka: reimplemented editing X and Y values in Vertex Panel.

------------------------------------------------------------------------
r184 | ajapted | 2009-10-13

Eureka: Thing Panel: fixed the 'type' input callback (handle multiple things).

------------------------------------------------------------------------
r183 | ajapted | 2009-10-13

Eureka: Thing Panel: separated 'pos_callback' into X and Y versions, so
that multiple selected things can work properly.

------------------------------------------------------------------------
r182 | ajapted | 2009-10-13

Eureka: Think Panel: reimplemented option_callback, pass a new structure
as the 'data' parameter which contains the needed UI_ThingBox pointer.
Also fixed a bug (used F_ANGLE instead of F_OPTIONS).

------------------------------------------------------------------------
r181 | ajapted | 2009-10-13

Eureka: Thing Panel: implemented value propagation for X and Y edits.
Changed option_callback() method making the 'data' field a mask value,
allowing multiple things to be handled but only the apropos bits are
actually changed.

------------------------------------------------------------------------
r180 | ajapted | 2009-10-13

tweak.

------------------------------------------------------------------------
r179 | ajapted | 2009-10-13

Eureka: for angle input in Thing panel, implemented propagating the new
value to every thing in the current selection.  Simplified handling of
the < and > rotation buttons.

------------------------------------------------------------------------
r178 | ajapted | 2009-10-13

Eureka: implemented UI_LineBox::UpdateField() method.

------------------------------------------------------------------------
r177 | ajapted | 2009-10-13

Eureka: implemented UpdateField() method for UI_VertexBox and UI_SectorBox.

------------------------------------------------------------------------
r176 | ajapted | 2009-10-13

Eureka: disabled the KF auto-upsizing stuff for now.

------------------------------------------------------------------------
r175 | ajapted | 2009-10-13

Eureka: update Thing UI panel after spin_things.

------------------------------------------------------------------------
r174 | ajapted | 2009-10-13

Eureka: Thing info widget: added UpdateField() method for when a field
is changed externally.  Removed some dead code.

------------------------------------------------------------------------
r173 | ajapted | 2009-10-13

Eureka: restored keys for spin_things.

------------------------------------------------------------------------
r172 | ajapted | 2009-10-13

Fixed a few warnings.

------------------------------------------------------------------------
r171 | ajapted | 2009-10-13

Eureka: changed keys to spin things to '[' and ']'.  Added a function
GetCurrentObjects(), and simplified some code using it.

------------------------------------------------------------------------
r170 | ajapted | 2009-10-13

Eureka: improved handling of the current highlighted object and the
current selection (for the UI panel).

------------------------------------------------------------------------
r169 | ajapted | 2009-10-13

Eureka: UI_Canvas: renamed some confusing method names:
   HighlightObject() --> DrawHighlight()
   HighlightSelection() --> DrawSelection()

------------------------------------------------------------------------
r168 | ajapted | 2009-10-13

Eureka: fixed UI_Nombre::Update() logic.

------------------------------------------------------------------------
r167 | ajapted | 2009-10-13

Eureka: the UI panel should now show how many objects are selected,
with a red background to warn that multiple objects may get changed
when editing the values in the panel.

------------------------------------------------------------------------
r166 | ajapted | 2009-10-13

Eureka: added 'slow_count' method to selection_c class.

------------------------------------------------------------------------
r165 | ajapted | 2009-10-13

Eureka: updated UI_Nombre widget to support selections.

------------------------------------------------------------------------
r164 | ajapted | 2009-10-12

Eureka: allow 3D renderer to receive mousewheel events.

------------------------------------------------------------------------
r163 | ajapted | 2009-10-12

Eureka: version bump.

------------------------------------------------------------------------
r162 | ajapted | 2009-10-12

Eureka: TODO update.

------------------------------------------------------------------------
r161 | ajapted | 2009-10-12

Eureka: implemented SelectObjectsInBox() for SECTORS.

------------------------------------------------------------------------
r160 | ajapted | 2009-10-12

Eureka: fixed SelectObjectsInBox() for THINGS, LINEDEFS and VERTICES.

------------------------------------------------------------------------
r159 | ajapted | 2009-10-12

Eureka: fixed key handling so that Ctrl-Z (and other menu shortcuts) work.

------------------------------------------------------------------------
r158 | ajapted | 2009-10-12

Eureka: updated TODO, removed old crud.

------------------------------------------------------------------------
r157 | ajapted | 2009-10-12

Eureka: fixed editing of Thing angles in the UI panel.

------------------------------------------------------------------------
r156 | ajapted | 2009-10-12

Eureka: fixed Undo/Redo to redraw map.

------------------------------------------------------------------------
r155 | ajapted | 2009-10-12

tweak

------------------------------------------------------------------------
r154 | ajapted | 2009-10-12

Eureka: replaced 'MadeChanges = 1' with call to MarkChanges(), and
replaced 'MadeMapChanges = 1' with MarkChanges(2) function call.
This new function remembers to redraw the map too.

------------------------------------------------------------------------
r153 | ajapted | 2009-10-12

Renamed file: AJA_TODO.txt --> TODO.txt

------------------------------------------------------------------------
r152 | ajapted | 2009-10-12

Eureka: implemented 'spin_things' functionality using the BASIS system.

------------------------------------------------------------------------
r151 | ajapted | 2009-10-12

Eureka: implemented menu commands: 'Save', 'Undo' and 'Redo'.

------------------------------------------------------------------------
r150 | ajapted | 2009-10-12

Eureka: dead code removal.

------------------------------------------------------------------------
r149 | ajapted | 2009-10-12

Eureka: fixed bug in saving code (wrong number of linedefs).

------------------------------------------------------------------------
r148 | ajapted | 2009-10-12

Eureka: fixed Wad_file::RemoveLevel() for GL-Nodes, it should remove
the "GL_XXX" lumps after the normal level lumps too.

------------------------------------------------------------------------
r147 | ajapted | 2009-10-12

Eureka: load the specified PWADs.

------------------------------------------------------------------------
r4 | ajapted | 2009-09-07

Checked in sources to my 'Eureka DOOM Editor' program.

For a while this was developed in EDGE's SVN repository on SourceForge.
Before that is was just developed on my hard drive.  Eureka is a fork
of the Yadex editor (version 1.7.0).



====================================================
    DEVELOPMENT IN EDGE REPOSITORY
====================================================

------------------------------------------------------------------------
r5940 | ajapted | 2009-09-27 14:53:16

Removed eureka code from EDGE's SVN repository.  The code has moved to
AwwPort's BZR repository.

------------------------------------------------------------------------
r5919 | ajapted | 2009-08-10 16:23:40

Eureka: temporary disable spin_things().

------------------------------------------------------------------------
r5811 | ajapted | 2009-08-04 14:33:57

Eureka: tweaked Scale choices on the infobar.

------------------------------------------------------------------------
r5810 | ajapted | 2009-08-04 14:28:40

Eureka: fixed privacy of fields in Lump_c and Wad_file classes.

------------------------------------------------------------------------
r5809 | ajapted | 2009-08-03 23:07:55

Tweak.

------------------------------------------------------------------------
r5808 | ajapted | 2009-08-03 22:58:48

Eureka: removed Wad_name class (w_name.h)

------------------------------------------------------------------------
r5807 | ajapted | 2009-08-03 22:39:28

Eureka: dead code removal.

------------------------------------------------------------------------
r5806 | ajapted | 2009-08-03 22:19:51

Eureka: removed the old wad handling code files:
    w_wads.cc/h
    w_io.cc/h
    w_file.cc/h

------------------------------------------------------------------------
r5805 | ajapted | 2009-08-03 22:01:41

Eureka: yet more dead code removed.

------------------------------------------------------------------------
r5804 | ajapted | 2009-08-03 21:20:37

Eureka: removed old patch_dir code.

------------------------------------------------------------------------
r5803 | ajapted | 2009-08-03 20:38:32

Eureka: dead code removal.

------------------------------------------------------------------------
r5802 | ajapted | 2009-08-03 20:25:44

Tweaks.

------------------------------------------------------------------------
r5801 | ajapted | 2009-08-03 20:24:44

Eureka: enabled new texture loading code.

------------------------------------------------------------------------
r5800 | ajapted | 2009-08-03 19:19:13

Eureka: further work on texture loader...

------------------------------------------------------------------------
r5799 | ajapted | 2009-08-03 19:04:15

Eureka: initial work on new texture loading code...

------------------------------------------------------------------------
r5798 | ajapted | 2009-08-03 17:34:03

Eureka: sprite loader updated to use new LoadPicture() code.

------------------------------------------------------------------------
r5797 | ajapted | 2009-08-03 17:17:40

Eureka: new Wad_file function W_FindSpriteLump() which only checks
the valid sprites (S_START..S_END), and similarly W_FindPatchLump()
for patches.

------------------------------------------------------------------------
r5796 | ajapted | 2009-08-03 16:44:28

Eureka: worked on new LoadPicture() implementation.

------------------------------------------------------------------------
r5795 | ajapted | 2009-08-03 16:26:06

Eureka: added WAD utility function to load a lump into memory.

------------------------------------------------------------------------
r5794 | ajapted | 2009-08-03 14:44:47

Eureka: began work on a new LoadPicture() implementation.

------------------------------------------------------------------------
r5793 | ajapted | 2009-08-03 14:31:38

Eureka: renamed IMG_TRANSP --> TRANS_PIXEL.

------------------------------------------------------------------------
r5792 | ajapted | 2009-08-03 11:22:03

Eureka: updated W_LoadPalette() to use new Wad_file code.

------------------------------------------------------------------------
r5791 | ajapted | 2009-08-03 11:13:20

Eureka: new flat loading code (W_LoadFlats), replaces old stuff.

------------------------------------------------------------------------
r5790 | ajapted | 2009-08-03 10:18:21

Eureka: dead code removal.

------------------------------------------------------------------------
r5789 | ajapted | 2009-08-03 10:09:34

Eureka: replaced calls to 'get_thing_xxx' with new M_GetThingType().

------------------------------------------------------------------------
r5788 | ajapted | 2009-08-03 09:55:21

Eureka: added 'color' field to thingtype_t (copied from thinggroup).

------------------------------------------------------------------------
r5787 | ajapted | 2009-08-03 09:46:35

Eureka: worked on using std::map for the game def containters
(sector_types, line_types, thing_types etc).

------------------------------------------------------------------------
r5786 | ajapted | 2009-08-02 23:47:30

Tweaks.

------------------------------------------------------------------------
r5785 | ajapted | 2009-08-02 23:35:40

Eureka: reworked code which loads the game palette.

------------------------------------------------------------------------
r5784 | ajapted | 2009-08-02 22:52:11

Tweak.

------------------------------------------------------------------------
r5783 | ajapted | 2009-08-02 22:30:52

Eureka: finished new line descriptions for doom2 game def.

------------------------------------------------------------------------
r5782 | ajapted | 2009-08-02 22:11:55

Eureka: yet more line description improvements (doom2 game def).

------------------------------------------------------------------------
r5781 | ajapted | 2009-08-02 21:24:08

Eureka: further work on line descriptions in doom2 game def.

------------------------------------------------------------------------
r5780 | ajapted | 2009-08-02 20:44:25

Eureka: more work on line descriptions in doom2 game definition.

------------------------------------------------------------------------
r5779 | ajapted | 2009-08-02 20:12:16

Eureka: game definition file: for 'thing' commands, moved the sprite
name to occur before the description (instead of after it).

More work on updating 'line' commands for a single description.

------------------------------------------------------------------------
r5778 | ajapted | 2009-08-02 19:38:05

Eureka: game definitions: began work to make linetype commands only
have a single description (instead of short and long).

------------------------------------------------------------------------
r5777 | ajapted | 2009-08-02 19:20:11

Eureka: game definitions: made 'sector' command only have a single
description (instead of short and long).

------------------------------------------------------------------------
r5776 | ajapted | 2009-08-02 19:16:40

Eureka: removed acolour_t.

------------------------------------------------------------------------
r5775 | ajapted | 2009-08-02 18:56:31

Eureka: worked on game definition (.ugh) code, renamed some of the
commands e.g. ldt --> line and st --> sector, and moved a couple
functions into m_game.cc.

------------------------------------------------------------------------
r5774 | ajapted | 2009-08-02 18:12:54

Eureka: dead code removal.

------------------------------------------------------------------------
r5773 | ajapted | 2009-08-02 17:17:33

Eureka: small fixes.

------------------------------------------------------------------------
r5772 | ajapted | 2009-08-02 17:13:35

Eureka: prelim rework of w_texture code (split now complete).

------------------------------------------------------------------------
r5771 | ajapted | 2009-08-02 17:06:13

Eureka: prelim rework of w_sprite.cc code.

------------------------------------------------------------------------
r5770 | ajapted | 2009-08-02 16:59:19

Eureka: preliminary rework of w_flats code.

------------------------------------------------------------------------
r5769 | ajapted | 2009-08-02 16:49:38

Eureka: continued splitting r_images.cc into three files.

------------------------------------------------------------------------
r5768 | ajapted | 2009-08-02 16:48:15

Eureka: began splitting r_image.cc into three (Textures, Flats and Sprites).

------------------------------------------------------------------------
r5767 | ajapted | 2009-08-02 16:45:33

Eureka: dead code removal.

------------------------------------------------------------------------
r5766 | ajapted | 2009-08-02 15:09:30

Eureka: merged w_sprites.cc code into r_images.cc

------------------------------------------------------------------------
r5765 | ajapted | 2009-08-02 14:42:40

Eureka: misc tidying.

------------------------------------------------------------------------
r5764 | ajapted | 2009-08-02 14:27:02

Small fix.

------------------------------------------------------------------------
r5763 | ajapted | 2009-08-02 14:14:06

Eureka: improved canvas drawing, keep the map bbox in member fields
(instead of computing it at multiple places), and use a Vis() method
for checking if an item would be visible.

------------------------------------------------------------------------
r5762 | ajapted | 2009-08-02 13:28:49

Eureka: reformatted r_grid.h and removed two unused fields.

------------------------------------------------------------------------
r5761 | ajapted | 2009-08-02 13:21:31

Eureka: small fixes.

------------------------------------------------------------------------
r5760 | ajapted | 2009-08-02 12:50:07

Eureka: added constructors to the basis structures (Thing, LineDef etc).

------------------------------------------------------------------------
r5759 | ajapted | 2009-08-02 12:42:56

Eureka: new FreshLevel() function to create a very basic level.

------------------------------------------------------------------------
r5758 | ajapted | 2009-08-02 12:27:37

Eureka: new level load/save code is mostly done.

------------------------------------------------------------------------
r5757 | ajapted | 2009-08-01 15:50:29

Eureka: Wad_file: changed FindLevel() to return a lump index (instead
of a level number), which affects the parameter to FindLumpInLevel()
and RemoveLevel() as well.   Various code tidying.

------------------------------------------------------------------------
r5756 | ajapted | 2009-08-01 11:56:59

Eureka: implemented remaining functionality of Wad_file class.

------------------------------------------------------------------------
r5755 | ajapted | 2009-07-31 22:46:50

Eureka: more Wad_file goodness...

------------------------------------------------------------------------
r5754 | ajapted | 2009-07-31 22:18:34

Eureka: further work on WAD Writing implementation.  Fixed the fopen
mode string in Open() to "r+b", and in Create() to "w+b".

------------------------------------------------------------------------
r5753 | ajapted | 2009-07-31 19:25:14

Eureka: tweaked the menu.

------------------------------------------------------------------------
r5752 | ajapted | 2009-07-31 19:17:59

Eureka: partial work on fleshing out the Wad_file "Write interface".

------------------------------------------------------------------------
r5751 | ajapted | 2009-07-31 15:48:29

Eureka: created the "Write interface" for new Wad_file class.

------------------------------------------------------------------------
r5750 | ajapted | 2009-07-31 15:37:00

Eureka: fleshed out most of the new SaveLevel() code.

------------------------------------------------------------------------
r5749 | ajapted | 2009-07-30 23:06:51

Eureka: added skeletal SaveLevel() code.

------------------------------------------------------------------------
r5748 | ajapted | 2009-07-30 22:10:50

Eureka: wrote Wad_file::WasExternallyModified() method.

------------------------------------------------------------------------
r5747 | ajapted | 2009-07-30 21:45:53

Eureka: fixed Wad_file::Create() to set 'total_size' field.

------------------------------------------------------------------------
r5746 | ajapted | 2009-07-30 21:44:28

Eureka: determine total size of WAD when opening it.

------------------------------------------------------------------------
r5745 | ajapted | 2009-07-30 20:48:13

Eureka: dead code removal.

------------------------------------------------------------------------
r5744 | ajapted | 2009-07-30 20:47:25

Eureka: implemented Wad_file::ProcessNamespaces(), which handles the
S_START/S_END, P_START/P_END, F_START/F_END groups.

------------------------------------------------------------------------
r5743 | ajapted | 2009-07-30 19:53:38

Eureka: version bump, in honor of new WAD reading code.

------------------------------------------------------------------------
r5742 | ajapted | 2009-07-30 19:51:23

Eureka: implemented Wad_file::DetectLevels().

------------------------------------------------------------------------
r5741 | ajapted | 2009-07-30 19:25:37

Tweak.

------------------------------------------------------------------------
r5740 | ajapted | 2009-07-30 17:41:35

Eureka: preliminary implementation of Wad_file::ReadDirectory().

------------------------------------------------------------------------
r5739 | ajapted | 2009-07-30 16:51:59

Eureka: reworked LoadLevel() to use new Wad_file class.

------------------------------------------------------------------------
r5738 | ajapted | 2009-07-30 16:51:02

Eureka: mere reformatting.

------------------------------------------------------------------------
r5737 | ajapted | 2009-07-30 16:43:47

Eureka: added w_wad.o to the build, with minor fixes.

------------------------------------------------------------------------
r5736 | ajapted | 2009-07-30 16:42:37

Eureka: temp workaround for old Wad_file class clashing with new one.

------------------------------------------------------------------------
r5735 | ajapted | 2009-07-30 16:25:09

Eureka: new Wad_file class is coming along.

------------------------------------------------------------------------
r5734 | ajapted | 2009-07-30 15:57:08

Eureka: further work on new Wad_file class.

------------------------------------------------------------------------
r5732 | ajapted | 2009-07-30 14:52:33

Eureka: implemented RemoveUnusedVertices() for level loading.

------------------------------------------------------------------------
r5731 | ajapted | 2009-07-30 14:09:29

Eureka: #include math.h by default (via main.h).

------------------------------------------------------------------------
r5730 | ajapted | 2009-07-30 13:57:38

Eureka: bit more work on new Wad_file class.

------------------------------------------------------------------------
r5729 | ajapted | 2009-07-30 13:41:47

Eureka: added Adler-32 CRC code.

------------------------------------------------------------------------
r5728 | ajapted | 2009-07-30 13:36:27

Eureka: check-in of skeletal new Wad_file class.

------------------------------------------------------------------------
r5727 | ajapted | 2009-07-30 12:26:35

Eureka: more miscellaneous tidying.

------------------------------------------------------------------------
r5726 | ajapted | 2009-07-30 12:02:11

Eureka: replaced nf_bug() with BugError().

------------------------------------------------------------------------
r5725 | ajapted | 2009-07-30 11:55:25

Eureka: removed sys_assert.cc/h.  Began tidying the error/log stuff.

------------------------------------------------------------------------
r5724 | ajapted | 2009-07-29 23:35:22

Eureka: removed xref stuff (pretty useless).

------------------------------------------------------------------------
r5723 | ajapted | 2009-07-29 23:33:26

Eureka: moved some prototypes out of main.h

------------------------------------------------------------------------
r5722 | ajapted | 2009-07-29 23:17:29

Eureka: dead code removal.

------------------------------------------------------------------------
r5721 | ajapted | 2009-07-29 22:55:54

Eureka: more tidying / dead code removal.

------------------------------------------------------------------------
r5720 | ajapted | 2009-07-29 22:19:58

Eureka: fixed clashing definitions between w_rawdef.h and w_structs.h
and removed some typedefs.

------------------------------------------------------------------------
r5719 | ajapted | 2009-07-29 22:17:17

Eureka: Dead code removal.

------------------------------------------------------------------------
r5718 | ajapted | 2009-07-29 21:56:54

Eureka: fixed side-panel display of sector flats, sidedef textures.

------------------------------------------------------------------------
r5716 | ajapted | 2009-07-29 18:04:00

Eureka: dead code removal.

------------------------------------------------------------------------
r5715 | ajapted | 2009-07-29 16:33:54

Eureka: renamed file: e_load.cc --> e_loadsave.cc

------------------------------------------------------------------------
r5714 | ajapted | 2009-07-29 16:24:15

Eureka: renamed QF --> KF and QF_F --> KF_fonth.

------------------------------------------------------------------------
r5713 | ajapted | 2009-07-29 16:22:59

Eureka: fiddled with menu.

------------------------------------------------------------------------
r5712 | ajapted | 2009-07-29 15:13:17

Eureka: few more fixes to get compiling and running again.

------------------------------------------------------------------------
r5711 | ajapted | 2009-07-29 15:04:25

Eureka: fleshed out new LoadLevel() function, and removed the old crud.

------------------------------------------------------------------------
r5710 | ajapted | 2009-07-29 14:55:38

Eureka: fleshed out LoadThings(), LoadSideDefs() and LoadLineDefs().

------------------------------------------------------------------------
r5709 | ajapted | 2009-07-29 14:38:05

Eureka: yet more sticky-tape and bubble-gum workarounds...

------------------------------------------------------------------------
r5708 | ajapted | 2009-07-29 13:17:25

Eureka: added LineDef::TouchesSector() method.

------------------------------------------------------------------------
r5707 | ajapted | 2009-07-29 01:10:51

Eureka: more bubble gum patching just to get something to compile.

------------------------------------------------------------------------
r5706 | ajapted | 2009-07-29 00:51:38

Eureka: fleshed out sector loading: LoadSectors().

------------------------------------------------------------------------
r5705 | ajapted | 2009-07-29 00:48:09

Eureka: added convenience func: BA_InternaliseShortStr().

------------------------------------------------------------------------
r5704 | ajapted | 2009-07-29 00:09:27

Eureka: began work on new level loading code : e_load.cc

------------------------------------------------------------------------
r5703 | ajapted | 2009-07-29 00:08:32

Eureka: sticky-tape for editloop.cc

------------------------------------------------------------------------
r5702 | ajapted | 2009-07-28 23:04:51

Eureka: wrote a little Features / Requirements doc.

------------------------------------------------------------------------
r5701 | ajapted | 2009-07-28 22:58:06

Eureka: more sticky-tape and bubble-gum to get it compiling again.

------------------------------------------------------------------------
r5700 | ajapted | 2009-07-28 22:51:33

Eureka: fixes for r_images.cc

------------------------------------------------------------------------
r5699 | ajapted | 2009-07-28 22:47:36

Eureka: updated 3D render code for the Basis.

------------------------------------------------------------------------
r5698 | ajapted | 2009-07-28 22:45:19

Eureka: added e_basis.o to the build.

------------------------------------------------------------------------
r5697 | ajapted | 2009-07-28 22:29:31

Eureka: prelim work updating UI widgets for the Basis.

------------------------------------------------------------------------
r5696 | ajapted | 2009-07-28 22:16:50

Eureka: fixed ui_canvas.cc for new basic structs.

------------------------------------------------------------------------
r5695 | ajapted | 2009-07-28 21:53:58

Eureka: remove old defintions of LineDef, Sector (etc) structs.

------------------------------------------------------------------------
r5694 | ajapted | 2009-07-28 21:46:06

Eureka: fixed some things in e_basis.cc

------------------------------------------------------------------------
r5693 | ajapted | 2009-07-28 21:19:02

Eureka: reformatted top-of-file comments, added the word 'Copyright'
because the presence of mere '(C)' has no legal significance.

------------------------------------------------------------------------
r5692 | ajapted | 2009-07-28 21:12:18

Eureka: twiddled TODO

------------------------------------------------------------------------
r5525 | ajapted | 2009-07-17 15:27:57

Eureka: completed the BASIS implementation (Undo, Redo, etc).

------------------------------------------------------------------------
r5524 | ajapted | 2009-07-17 14:56:04

Eureka: fleshed out more of the BASIS implementation.

------------------------------------------------------------------------
r5523 | ajapted | 2009-07-17 14:29:00

Eureka: more work on BASIS implementation, moved or removed the
irrelevant code out of e_basis.cc.

------------------------------------------------------------------------
r5522 | ajapted | 2009-07-17 14:21:44

Eureka: fleshed out the BASIS API (BA_Begin, BA_Change, etc).

------------------------------------------------------------------------
r5521 | ajapted | 2009-07-17 00:48:52

Eureka: basis stuff yay.

------------------------------------------------------------------------
r5520 | ajapted | 2009-07-16 23:59:32

Eureka: further work on the basis (RawInsert and RawDelete).

------------------------------------------------------------------------
r5519 | ajapted | 2009-07-16 21:27:16

Eureka: removed unused OBJ_XXX constants, added rad-trig bits.

------------------------------------------------------------------------
r5518 | ajapted | 2009-07-16 21:24:38

Eureka: basis code: implemented the helper methods (FloorTex etc),
and removed more code that doesn't belong here.

------------------------------------------------------------------------
r5517 | ajapted | 2009-07-16 21:05:32

Eureka: fleshed out all basis InsertXXX() and DeleteXXX() functions.

------------------------------------------------------------------------
r5516 | ajapted | 2009-07-16 20:05:31

Eureka: updated the DeleteObject() code for new basis design.

------------------------------------------------------------------------
r5515 | ajapted | 2009-07-16 19:25:42

Eureka: bit more work on object basis.

------------------------------------------------------------------------
r5514 | ajapted | 2009-07-16 19:22:59

Eureka: updated basis header with design notes and some helper
methods in each structure (e.g. Sector::FloorTex).

------------------------------------------------------------------------
r5513 | ajapted | 2009-07-16 18:47:12

Eureka: updated makefile.

------------------------------------------------------------------------
r5512 | ajapted | 2009-07-16 17:28:42

Eureka: improved string table class to support "huge" strings.

------------------------------------------------------------------------
r5511 | ajapted | 2009-07-16 15:49:28

Eureka: fixed string table to find existing strings in add().

------------------------------------------------------------------------
r5510 | ajapted | 2009-07-16 15:30:11

Eureka: finished implementation of string table.

------------------------------------------------------------------------
r5509 | ajapted | 2009-07-16 15:11:15

Eureka: preliminary work on a string table.

------------------------------------------------------------------------
r5508 | ajapted | 2009-07-16 14:58:40

Eureka: added field enums (F_X, F_FLOOR_TEX, etc) to basis classes.

------------------------------------------------------------------------
r5507 | ajapted | 2009-07-16 14:45:10

Eureka: fleshed out new basis classes (class Thing etc).

------------------------------------------------------------------------
r5506 | ajapted | 2009-07-16 14:20:23

Eureka: began work on new 'e_basis' file for basic object handling.

------------------------------------------------------------------------
r5505 | ajapted | 2009-07-16 14:17:14

Eureka: removed 'ld - LineDefs' and 'sec - Sectors' pointer math.

------------------------------------------------------------------------
r5504 | ajapted | 2009-07-16 00:56:49

Eureka: removed unused 'things_angles' and 'things_types' vars.

------------------------------------------------------------------------
r5503 | ajapted | 2009-07-16 00:55:48

Eureka: fixed 'spin_things' code.

------------------------------------------------------------------------
r5494 | ajapted | 2009-07-14 23:52:22

Eureka: got the code compiling again (after SelPtr change).

------------------------------------------------------------------------
r5493 | ajapted | 2009-07-14 23:14:22

Eureka: partial work, updating all code to use new selection_c
class instead of old SelPtr stuff.

------------------------------------------------------------------------
r5492 | ajapted | 2009-07-14 22:56:36

Eureka: optional 'initial' value for selection_c constructor.

------------------------------------------------------------------------
r5491 | ajapted | 2009-07-14 22:48:07

Eureka: reworked InsertObject() code.

------------------------------------------------------------------------
r5490 | ajapted | 2009-07-14 22:23:14

Eureka: new and improved DeleteObjects() code is done.

------------------------------------------------------------------------
r5489 | ajapted | 2009-07-14 21:14:17

Eureka: preliminary rework of DeleteObjects() code.

------------------------------------------------------------------------
r5488 | ajapted | 2009-07-14 21:13:41

Eureka: reinstated objid.h (finished split from objects.h).

------------------------------------------------------------------------
r5487 | ajapted | 2009-07-14 20:33:38

Eureka: reinstated header file: objid.h

------------------------------------------------------------------------
r5486 | ajapted | 2009-07-14 19:43:32

Eureka: improved selection_c class, new change_type() and empty() methods.

------------------------------------------------------------------------
r5485 | ajapted | 2009-07-14 18:42:54

Eureka: new MAX_RADIUS constant.

------------------------------------------------------------------------
r5484 | ajapted | 2009-07-14 18:41:40

Eureka: code reformatting.

------------------------------------------------------------------------
r5483 | ajapted | 2009-07-14 16:54:15

Eureka: yet more reformatting, yay.

------------------------------------------------------------------------
r5482 | ajapted | 2009-07-14 16:28:55

Eureka: more reformatting.

------------------------------------------------------------------------
r5481 | ajapted | 2009-07-14 15:30:07

Eureka: code reformatting.

------------------------------------------------------------------------
r5480 | ajapted | 2009-07-14 15:16:39

Eureka: reformatted code.

------------------------------------------------------------------------
r5479 | ajapted | 2009-07-13 23:30:46

Eureka: implemented iterators for the new selection_c class,
with an API similar to (but not the same as) the STL.

------------------------------------------------------------------------
r5478 | ajapted | 2009-07-13 23:01:07

Eureka: fleshed out remaining selection_c methods.

------------------------------------------------------------------------
r5477 | ajapted | 2009-07-13 22:49:17

Eureka: preliminary new class for handling selections.

------------------------------------------------------------------------
r5476 | ajapted | 2009-07-13 22:34:39

Eureka: extended bitvec_c class with set_all(), clear_all(),
toggle_all() and merge() methods.

------------------------------------------------------------------------
r5475 | ajapted | 2009-07-13 22:12:38

Eureka: reworked bitvec_c implementation.

------------------------------------------------------------------------
r5474 | ajapted | 2009-07-13 21:47:01

Eureka: incorporated highlight code into UI_Canvas widget.

------------------------------------------------------------------------
r5473 | ajapted | 2009-07-13 20:03:23

Eureka: updated TODO

------------------------------------------------------------------------
r5472 | ajapted | 2009-07-13 19:57:18

Eureka: incorporated selection box functionality into UI_Canvas widget.

------------------------------------------------------------------------
r5471 | ajapted | 2009-07-13 19:20:22

Eureka: updated #includes for recent renamings.

------------------------------------------------------------------------
r5470 | ajapted | 2009-07-13 18:58:35

Eureka: moved levelname2levelno(), levelname2rank() from yutil --> levels.cc

------------------------------------------------------------------------
r5469 | ajapted | 2009-07-13 18:51:00

Eureka: renamed various files, now: e_checks, e_linedef, e_things,
e_sector, e_vertex, m_config, m_dialog and m_game.

------------------------------------------------------------------------
r5468 | ajapted | 2009-07-13 18:47:34

Eureka: make side panels wider on higher resolutions.

------------------------------------------------------------------------
r5467 | ajapted | 2009-07-13 18:38:32

Eureka: renamed Makefile.linux --> Makefile.unx

------------------------------------------------------------------------
r5466 | ajapted | 2009-07-13 18:36:07

Eureka: updated #includes for recent file renamings.

------------------------------------------------------------------------
r5465 | ajapted | 2009-07-13 17:46:42

Eureka: renamed files: gfx --> r_misc

------------------------------------------------------------------------
r5464 | ajapted | 2009-07-13 17:45:00

Eureka: dead code removal.

------------------------------------------------------------------------
r5463 | ajapted | 2009-07-13 17:36:33

Eureka: renamed files: grid2 --> r_grid

------------------------------------------------------------------------
r5462 | ajapted | 2009-07-13 17:30:26

Eureka: moved InitFLTK and TermFLTK from gfx.cc --> main.cc, and
removed some unused stuff.

------------------------------------------------------------------------
r5461 | ajapted | 2009-07-13 17:00:43

Eureka: merged l_super.h file --> linedefs.cc

------------------------------------------------------------------------
r5460 | ajapted | 2009-07-13 14:51:08

Eureka: merged e_names.cc file --> editobj.cc

------------------------------------------------------------------------
r5459 | ajapted | 2009-07-13 14:47:29

Eureka: merged edit2.h file --> editloop.h

------------------------------------------------------------------------
r5458 | ajapted | 2009-07-13 14:41:43

Eureka: merged gotoobj files --> objects.cc/h

------------------------------------------------------------------------
r5450 | ajapted | 2009-07-12 16:02:58

Eureka: code tidying, removed DRAWING_MAP hack.

------------------------------------------------------------------------
r5449 | ajapted | 2009-07-12 00:40:42

Eureka: renamed various fields of map structures:
   xoff, yoff    --> x_offset, y_offset
   ceilt, floort --> ceil_tex, floor_tex
   upper, lower  --> upper_tex, lower_tex
   middle        --> mid_tex
   sidedef1 / 2  --> side_R, side_L
   when, special --> options, type

------------------------------------------------------------------------
r5448 | ajapted | 2009-07-11 23:46:56

Eureka: Removed unused headers: spot.h and edwidget.h

------------------------------------------------------------------------
r5447 | ajapted | 2009-07-11 23:34:04

Eureka: more file merging, various reformatting and renaming.

------------------------------------------------------------------------
r5446 | ajapted | 2009-07-11 22:46:35

Eureka: reformatting...

------------------------------------------------------------------------
r5445 | ajapted | 2009-07-11 22:32:11

Eureka: more file shenanigans.

------------------------------------------------------------------------
r5444 | ajapted | 2009-07-11 22:22:36

Eureka: merged input.h and y_time.cc/h into other files.

------------------------------------------------------------------------
r5443 | ajapted | 2009-07-11 22:10:29

Eureka: scrollbar tweak.

------------------------------------------------------------------------
r5442 | ajapted | 2009-07-11 21:59:25

Eureka: new top-of-file comments (header files).

------------------------------------------------------------------------
r5441 | ajapted | 2009-07-11 21:44:52

Eureka: new top-of-file comment block.

------------------------------------------------------------------------
r5440 | ajapted | 2009-07-11 18:07:17

Eureka: more work on the Texture list widget.

------------------------------------------------------------------------
r5439 | ajapted | 2009-07-11 15:04:50

Eureka: bit more work on texture selector.

------------------------------------------------------------------------
r5438 | ajapted | 2009-07-11 14:42:58

Eureka: preliminary work on a flat/texture selection panel.

------------------------------------------------------------------------
r5437 | ajapted | 2009-07-11 14:10:45

Eureka: renamed more stuff.

------------------------------------------------------------------------
r5436 | ajapted | 2009-07-11 14:09:23

Eureka: renamed more stuff.

------------------------------------------------------------------------
r5435 | ajapted | 2009-07-11 00:32:21

Eureka: various tidying...

------------------------------------------------------------------------
r5434 | ajapted | 2009-07-11 00:06:45

Eureka: began work on using larger fonts (etc) on higher screen resolutions.

------------------------------------------------------------------------
r5433 | ajapted | 2009-07-10 23:35:44

Eureka: reformatting.

------------------------------------------------------------------------
r5432 | ajapted | 2009-07-10 22:44:04

Eureka: added vim editor settings to each file.

------------------------------------------------------------------------
r5431 | ajapted | 2009-07-10 22:15:48

Eureka: renamed files yadex --> main, merged objid.h into objects.h

------------------------------------------------------------------------
r5430 | ajapted | 2009-07-10 21:59:48

Eureka: tweaks.

------------------------------------------------------------------------
r5429 | ajapted | 2009-07-10 21:54:07

Eureka: yep more twiddling...

------------------------------------------------------------------------
r5428 | ajapted | 2009-07-10 21:38:01

Eureka: more tidying...

------------------------------------------------------------------------
r5427 | ajapted | 2009-07-10 19:31:40

Eureka: more file stuff....

------------------------------------------------------------------------
r5426 | ajapted | 2009-07-10 19:21:00

Eureka: merged files: im_appcol, im_gamecol, im_rgb --> im_color.

------------------------------------------------------------------------
r5425 | ajapted | 2009-07-10 19:08:03

Eureka: merged files: x_rotate, x_centre, x_exchg --> x_mirror.

------------------------------------------------------------------------
r5424 | ajapted | 2009-07-10 14:56:36

Eureka: finished merging v_* files.

------------------------------------------------------------------------
r5423 | ajapted | 2009-07-10 14:52:39

Eureka: began merging v_* files --> vertices.cc/h

------------------------------------------------------------------------
r5422 | ajapted | 2009-07-10 14:49:52

Eureka: merged s_* files into sectors.cc/h and s_misc.cc/h

------------------------------------------------------------------------
r5421 | ajapted | 2009-07-10 14:38:39

Eureka: merged s_split.cc, s_slice.cc into --> s_misc.cc

------------------------------------------------------------------------
r5420 | ajapted | 2009-07-10 14:33:32

Eureka: renamed files: s_centre --> sectors

------------------------------------------------------------------------
r5419 | ajapted | 2009-07-10 14:32:20

Eureka: renamed file --> s_misc.h

------------------------------------------------------------------------
r5418 | ajapted | 2009-07-10 14:29:40

Eureka: finished merging linedef stuff.

------------------------------------------------------------------------
r5417 | ajapted | 2009-07-10 14:23:12

Eureka: began merging linedef stuff into less files.

------------------------------------------------------------------------
r5416 | ajapted | 2009-07-10 00:38:58

Eureka: renamed file: memory --> ymemory

------------------------------------------------------------------------
r5415 | ajapted | 2009-07-10 00:34:54

Eureka: merged t_spin, t_flags, t_centre files --> things.cc/h

------------------------------------------------------------------------
r5414 | ajapted | 2009-07-10 00:25:51

Eureka: renamed GetFarMemory --> GetMemory (et al).

------------------------------------------------------------------------
r5413 | ajapted | 2009-07-10 00:17:55

Eureka: removed files: locate.cc/h and macro.cc/h

------------------------------------------------------------------------
r5390 | ajapted | 2009-07-09 01:36:07

Eureka: fixed the cpu hogging (use Fl::wait in main loop).

------------------------------------------------------------------------
r5389 | ajapted | 2009-07-09 01:16:45

Eureka: removed dummy atclib.h

------------------------------------------------------------------------
r5388 | ajapted | 2009-07-09 00:52:30

Checked in a map editor based on Yadex 1.7.0 but completely hacked
to pieces to work with the FLTK toolkit and removal of the atclib.

eureka-editor-eureka-2.0.2/htgen/Main_TODO.html000066400000000000000000000001001464327712600212340ustar00rootroot00000000000000

eureka-editor-eureka-2.0.2/htgen/VisExp_Main.html000066400000000000000000000075701464327712600217270ustar00rootroot00000000000000

Visplane Explorer

Introduction

Visplane Explorer is a stand-alone program to visualize possible visplane overflow (VPO) errors in DOOM maps. This is useful when mapping for vanilla DOOM, because when an overflow occurs the game simply quits with an error message (or crashes), which is pretty harsh on the person playing.

Visplane Explorer can check not only "visplanes", but also "draw-segs" and "solid-segs". When draw-segs overflow, it is not too bad since it just produces rendering glitches, but solid-seg overflow will corrupt memory and probably crash. Visplane Explorer works by using a stripped down version of the DOOM rendering code, with increased limits and extra checks to prevent overflowing the buffers and crashing.

Caveat : while this program is a useful tool, it cannot predict every situation (for example, an Archvile making the player jump in the air, which means more geometry can be seen and hence higher visplane counts). You should always test your map in the original game.

(Note: there is also a plugin for Doom Builder 2 called "Visplane Explorer", which was based on this program. If you are looking for that, then I suggest trying the Doom Builder website or forums.)

Screenshot

Downloads

Windows binary : visexp-1.0-win32.zip

MacOS X package : visexp-1.0-osx.dmg

Debian Linux package : visplane-explorer_1.0-1_i386.deb

Source code : visexp-1.0-source.tar.gz and

Summary of Keyboard and Mouse usage:

  • scroll map with mouse button or cursor keys
  • zoom with the mouse wheel or + / - keys
  • switch modes quickly with V / D / S keys

Credits

This GUI program was created by Andrew Apted (me).

The MacOS X package was made by Ioan Chera.

It includes a very stripped down version of the DOOM rendering code, which I took from Chocolate Doom (by Simon Howard), which in turn is based on the DOOM source code release by Id Software. Hence these guys are included in the copyright notice.

Copyright and License


  Visplane Explorer

  Copyright (C) 2012-2014 Andrew Apted
  Copyright (C) 2005-2008 Simon Howard
  Copyright (C) 1993-1996 Id Software, 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 of the License,
  or (at your option) any later version.

  This program is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.

See GNU General Public License for the full text.

eureka-editor-eureka-2.0.2/htgen/build.py000066400000000000000000000061731464327712600203260ustar00rootroot00000000000000import os import sys from bs4 import BeautifulSoup import shutil import errno import markdown cur_path = os.path.dirname(os.path.realpath(__file__)) out_path = os.path.join(cur_path, '..', 'htdocs-OUTPUT') os.makedirs(out_path, exist_ok=True) legacy_content = ( 'Docs_CommandList.html', 'Docs_Index.html', 'Docs_Invoking.html', 'Docs_Keys.html', 'Docs_KeySystem.html', 'index.html', 'Main_About.html', 'Main_Changes072.html', 'Main_Changes074.html', 'Main_Changes081.html', 'Main_Changes084.html', 'Main_Changes088.html', 'Main_Changes095.html', 'Main_Changes100.html', 'Main_Changes107.html', 'Main_Changes111.html', 'Main_Changes121.html', 'Main_Changes124.html', 'Main_Changes127.html', 'Main_Changes2.0.0.html', 'Main_Changes2.0.1.html', 'Main_Credits.html', 'Main_Download.html', 'Main_History.html', 'Main_SVN_Logs.html', 'Main_TODO.html', 'VisExp_Main.html', ) static_extra = ( 'shots', 'custom_logo.png', 'eureka.css', 'grid.png' ) template = 'template.html' with open(os.path.join(cur_path, template)) as f: template_data = f.read().replace(' ', ' ') template_soup = BeautifulSoup(template_data, 'html.parser') for item in legacy_content: path = os.path.join(cur_path, item) with open(os.path.join(cur_path, path)) as f: item_data = f.read().replace(' ', ' ') item_soup = BeautifulSoup(item_data, 'html.parser') if item == 'Main_TODO.html': with open(os.path.join(cur_path, '..', 'TODO.txt')) as f: todo_content = f.read() item_soup.pre.string = todo_content elif item == 'Main_Credits.html': with open(os.path.join(cur_path, '..', 'AUTHORS.md')) as f: authors_content = f.read() item_soup.div.append(BeautifulSoup(markdown.markdown(authors_content, extensions=['fenced_code']), 'html.parser')) elif item == 'Main_Changes2.0.0.html': with open(os.path.join(cur_path, '..', 'changelogs', '2.0.0.md')) as f: changes_content = f.read() item_soup.div.append(BeautifulSoup(markdown.markdown(changes_content, extensions=['fenced_code']), 'html.parser')) elif item == 'Main_Changes2.0.1.html': with open(os.path.join(cur_path, '..', 'changelogs', '2.0.1.md')) as f: changes_content = f.read() item_soup.div.append(BeautifulSoup(markdown.markdown(changes_content, extensions=['fenced_code']), 'html.parser')) template_soup.find(id='wikitext').replaceWith(item_soup) try: title = os.path.splitext(item)[0].split('_')[1] except: title = 'MainPage' # index.html only one with open(os.path.join(out_path, item), 'w') as f: f.write(str(template_soup).replace('$(TITLE)', title)) def copyanything(src, dst): try: if os.path.exists(dst): shutil.rmtree(dst) shutil.copytree(src, dst) except OSError as exc: # python >2.5 if exc.errno in (errno.ENOTDIR, errno.EINVAL): shutil.copy(src, dst) else: raise for extra in static_extra: copyanything(os.path.join(cur_path, extra), os.path.join(out_path, extra)) eureka-editor-eureka-2.0.2/htgen/custom_logo.png000066400000000000000000002210301464327712600217040ustar00rootroot00000000000000PNG  IHDR)sRGBbKGD pHYs  tIME 5:ϊ IDATxڔImۖ4fDĽV&"4Δ n) KDE!'RtlBr K,Liws^k9h/m9н}Y{c1f?>Q¢"FSDf&lW8GZbsVRMM̪t1.z2EJT;D@nfff6UJb nm]6 ,y9[k oJKE 2ƴ+ ɈUif @ELA1sQ̡&r׽l1`@Ƕm(3%|wqf&*XxǏ񱷇_R' U"3wWoAHIyf^̬"nvD$RU +Jl."8 quޚT֭"2^,(L"g֙D \_YCD;MlFc{U9OCD֕͝3UD! `@U+Uffd4L[UoVrEQfQAkMDT{"fTD*9猌twf"[7޺n**"~""2Wn."Z]_L3W3̮ޯ3ן!@fƜ͙:ުAl;,S\.Bҽ1U-)3bQ}ǜSUbjafk轓$ YD EŌd@sEPxj23o 3z5Uk]\}7S""Uf@"4[_23@fcŨd:&Z`o]TfD&"Tdsw" (UhfGM]E& U}Afu"̀3Zb H"`e{!Bp. ̊%"IwN [at<2F$[H(VRAJ21'ͽ.m S5j^H%*۷#ꙙϯuL) ffB`r5]/b֫"*b%&ԓpZLD ,̽r ] gb_V&Xs-iU\OEVό3rU8,M23sXź>>1,2P}뙹|d_i9*3Ȝs團TԳ0*Wz{`e۶fOU$5isNs b"@w$Q*ϱ3fsD{JUޥHTRQ[~oBP,V>ֻgsj["umU-2 Y1"fV J"8VUD|keu_'Y(QQ-(nif25-ʊsuoɬQ;,A%=5*ҭƙ,QTo'`XqA\lU&.&lr vk.f%4"c wGZ@e7"ff&heDe»9ݳz/:\JU3"#Ed%9Gk%V35CEJFk6PLSak'"B$]r93 }m"m 0}dG<@f"߽}w^z׶.v(7!ȢY&Ria<ǧ67Kf_:̚{mwdҨ .`-*r?umV\H^3geRjB-&G^U TT3/眦FPUJEy"TH@40Ii3cjEQyRHf7 FPPU۶m", f"EviV)?^0#3 0SS1@Wۚoۆ(SQ]Tk="}]rF arjڼDX 3Ef}e_LinX˻KGyyo~٥4x)\ӼtmԨ UTYeZҶ>+0mU\.tX/T$#̬V" -.YzUޚgH7׷2XjF̈Efef Tх3qZ"@Vq_{߻_ۧ6qVHkz7E[0DTME*^Y{fՔcc5i13<[6fD1*SE!2cfL{%RP&oKdf![Q`UU><,>13[k} ""T}1UQ@*nUsObDD|H%YD比ko0Dyc>bj@Sy& (7ik)戗y$6أUT!y*QSgFS3K90RF1"#81DU~=3x f~3DR9۪ldY*YNT7/^bjj*"[k1hN03Hc<_Y޵oI{*$[sΑ&rGe/]%73d=3bfV=c*92,3 ]Xs1ƌ\ kMI&k<]G}ivoR~c o{^oc,m*3\.=*|Qd.YykNQ3_=Ȭ$0B,YETĘZeeD1)3#nn|lۻy/$LT*434*u_we5u5DWxջ3|X* "S)HqVԂ MEjf\MSMG\T͛hpQyfޏ(22 /y/ھm۶쭍93"5yj[F@d&[{pTcPY/ޞ vT;{a0"^)z=wjd ԗ!g$rk]Ku^2UIn)B]\<22E=]/pDDZ`$ Ny-%]Ip!P8)fL:l -yY ʎ1/.FΙ/1XTf._%!"٭-B{dhkK8qJ lj0byNh2&fAzs5ˈhrpSD"qkRboyĢĬem97]T8|Ǐ1|^x[Som!U63K:K8*=S}0Fn͏؏~_ Lq<\õ7_]-0ݻL"KCRQ?n_e}T?3 U#mqh\ #5n9N*RnNXG3JDU+_< md^W1GFU2S7#SUQս (sVTjtQ1 {wUnU!= (q2Sg&%8Z}3՗XzҌxE-7iJ$EM)ba@7̒*d4) }1"dCtJaTA_\e@4̇}Yj@Ybyʫ2ZfȪJEUwO.xU L6Ǽ8ơRѺJYK#޿B}k{Է[c/xB6~͛ߎcsl&"<hj&z3UZ&b}M43>`ɾ<]|I.e:nub/;%l\][QA_޿j F:Id]6tLr1-R͖j$0Cڵw4IQ!9sۺj$2FfH3+oDMYnMDF̪PU,c*fաj !\$3*Y0# ~3n^/["{\w̢\U 3CfdOY2fP3r8m.ވwOLVYϷyD6GžAf~{~o}[8Tf`fA( jUo}B\SG}櫯*(e'u c*w{_$ek-9@*Qʨy,I) 7,9'E zo~܏XsH#T~īmXsVkNVSs+M QhjP^=[C Ez4fѽmG$ib⤩yTXTXLl"2Y1s K#rS,9GT<6OBEU"pRwH,jׇMYbm N)lު2FFq爙(&E3?Y2S9 ~/M3F qFԇ?/W{zw_~1GۿwDhY71$AʽWiv|o(NepUIWV.Ww1L RSw51K l[_$p%VڻAB ,^{*xzzٚvލqtޑ4&65nɭ5)RU&fMa)Rro*䠘ti+EI9Yg@zsodEURоEmiIPP!vIM}UZ,qixR*RUȂ QX<F*s.-\Tm TY+2Q L1gr5cߺ9<2Y!9==Iy&Y[m4 IV +Et3MMdeJS ƄSy5ط \KL,IZUhb4Ʃj8ϩ"M_mYcsmWwy9CMjփ)ΘK`̹m]E}ʏ'1m4wB(Bo }W Udk*X6ZSbj{(0sP5Q潷>Is$bn%)^(%ia gGUuyJ`0?gv}wS$1F~ ȢRRf˽z8q,oI+ͭuf~xpy&&NKhk9D@ Fdevc܏Ljѷv!_j? [yguq[9XLk~;ygvRUo`YY"$2hqfeTJ~nϟ>~{V|9Drj[%#p[]?8^r#KaE ^vq q=\29}̨ DefS_(r9pF,LeS1qv1Fr̚B!IьPs[biѦ%}r ȉn08ǜDAyE1$3ZKY/((h0 fAuI2f[^fԌ k^GfD f*|mMs>}Fq,b+~cpw1*E$Yu}2 V3dy  9r(*爀Pf&ȢLy0"86*(BC,޵B~ogLfk{{Jٷ$DM$ycND*xq,HUN3}BmF,%!ʘQ %YcFe9%`dLߴL>>X211rcfZ1@Z] kXsZw_8ieR@Ψ9 !yQH,T͌#'82 *BZD,Z8,6ߏ{S3;&UT{Qt /1tf_~Z Rgt վ~s//{~~{݋?۟Ώo.7o߽Λ_}ՏO}1KşU Z/~w;Qʯ{fjU B=f'oOr!+??6c  _;?wӧZo ͏_???_n??o3>٧9ӻfF#nƁ$HBoB ic 56^$[VꨌfF{=p*{=O2t,\GD) 47lZ;w:?5'L*KRp_pJxo\O|s__!"tCDCūc xr2 MN"Bc,mk~VE *hkC6gJxcg_k2zX]yvjW5-e:]{?pS_4?9StG]pfㆾ}?W/Oqԙ7MBUl.Hd&u-McrCw} : Wm۶icI`îuO3}iPVEgʅ{^>5a= T΍BKೀ E)K,\75n~8ד?xCWW>'HH;, X`j"y`,g֤;v)'Z[3ܩ8n{67^4{|ŋ$Ǡ~I})#p ۻp~4t'&2ccy{@(:6͌X~:π!3Wέ\L:ݲ 7ASOڱϨsϨZ).\Z|W*kWq&4FZg;6%kOrʎ*x(;:QqfgEc<~o&. mMe <]d·wA!CӃG2SS1&Xg͆#*,>@&_?vVu2(4еIqz@4۶ kٹvimW"2x-Jʠd* >E*L\+KޕMks.$ALxoxEel<ܒ^7cSWvܴ3/%{H++]]8{cw٥ө_ԚZTco.KӹSaW.Һ06Q)1k`4.reapamKF[B4Q`PiB}jv?h{x۽o]*` hj̎O;ky6_?*?}#Dz=a? GxP9v|=;ۻw_Go--+9wlM\$cTSm%ʜ3|?lJ265]'suɶXcKe?iËes<-P%xD@J5Jjz~\%h b,=1ږٟyf~WMFȆ3Wͦ+K兦 #{("e$ؾ!-dE2M]W_z1Q41;BHH1CB"X |3I'TaG;;!#Vj;zW&qu$=Z tT$&&'Nt>#mRwu9|G4o$ZGHCz6qaœfx0Q0KX[f!\ ("$`Y9 :)SIզזU54śG]=t3ӌ-S rw,\om`(*q/ 9zhMMmssO.e]޹539G^XY۳3O`g𕥅SŋP а}g0ik0c!H9 yxv5E}geTWܶanac6jG} 0 FEQ5!醡s!VW66%U#Ұy?8s滮b>g#É̹R#CjsWto]l[صoXkKͣo>/xVɕѡ}V(|όeWw;q6P%/kmv&.~zic١+K#JqϾ{+ifcP-z~v%Kjh#\m43?s,*Ĭ .Հ((b+ *:b11WXχ⍅@(L1cQ)˗21n1m~gSzMCslSJ9X oߵ*ٮ1&U\]ȋ/9:qj0:kΪ% o =ϫo0 n'@#0/_Ro۶ݷm&68db{ɐem{eTWK+SCgp2W)0Ff՝r}D?`F]rbR#ק).3/5 H$ S˥7eV;zbd ō_4nRˊQuU7O__,|ĥ|35ujrMO(ϯfqUD ު*ˁjlK!\ YWM+z TO/nݵӿ EkRXW}msܴ6쿽iJH~}qi4Z B(z 34]Z"uus.|Q5#3". U(!\*"ȖN*v!o˒B`m6/S"Q.BbSgәKt B ZptC tnzƑ>Ƙj˜ۙ`+\[ҟ(ܠVw>gLJp\cYU.SuyFF꺣@]Kr:mnx,MYFI P"hF VW-E;zSKuZq@S}[=ȡ| Cӯ$ㆈ$sבͽ2v\B=xCnHU >w^$A4"t$KS@aR r>W;~Yۚ];rpyَ;tr0 4ִnԓpƞ%&0p.QI-9x[y}S Q?c} ;SW/M/OOL^:sR~v:3z}̅ޏz':e;~LKI4b6c,Zܞpcop+  B49EH@۲q  fcjE+yۡ"  *ܘ7 ~'ܭizɩP-ZJ\ IuɔJ1HR ˫WO7h )LRQjRZe!)M GWOE@[(# )dyVjOT-ZȶXV4el?0qxCk1ljq5؁fgO--a iﯻ㞙׎ja-]8MJ-h˕B MbPB/qkmTً6oZ ѹkg6qS2ACυhZf}ɷK[MvDn1hh[jHpbf>ċMzgM[IFcCo윚p} ϵn̳…}}`pk_f:2;5^}wǎԹ7˩&y@2^,-(!p}*4wۃUfnnaidh:O?1>r&s"4>3#aԄ6T&f6B A m=2Z;w"vC+ *4Y fo`$/zu7zBJ )./[ }A,+^Wj0RKK*] HT]zR3Pc!E{l}ule!r$1 ј' Ր5v)ެf IDAT@ u-'Ҿg0B1 : G?;]W-ystC.ery}h*̴YP@1fW/ZvܤY8nܺmnA<زmA¸.%PU IEU@ZQ׻au#oη5g班\V'綨U_j{~QLЕ/\oL}wt7ck㇟} 6SK*Ni]G0 'rsygyA ɕɉe|088JN'ZZY &PhoFz<׭OO,- %V($,hAf4*dv8~l u*N1H p<_*y$hkU#,l*J@r̬!-^wu1@c&#ԅ@i-^dR ]*- ^.XGX8d lLV)Ҧe3kj!7* HV})c A %nϩS.UWRl`F)Zۘ]܄4:gPHo_0΅Qװc6c`[M.O?̶EWPG^ʹT"zg&S,3kM$|YR2h1t1%LuBa}q9RK+^z.]1JFa ƽ "ѭQBEZvX}e2y_ ׏oҲ:ݦ^8rKP#Teb1K $0<_/~s| 2*-ЀVX0H 8v΍oz胫*%Sbv)_ܽka~c8RR(u9 j* " 31ϥ]g8 P}}q}Qb5=tX> tì)>ti֥ 7 )աOa_q\3y]ׇ[=}"Z S K]19Ss4d$uA TDkdjRyǧ>7PK)zR&H2i 0V݊.`+om75lnartإW$zWkʲaSSjH ^( M]K#|*+0%@`䖽F﹯ocܕ_뷴'TMLBu.EH`~j+j#[o7mv7B ^9S/l޽oe1ӽsz'sA0%(B)]|m_Ǟfnfiejlnr}[g~TS$)`+KJqGh!L`(0ryƍZ :п0rshس;zU%% kF[=k]6zW9@US7UP TQ@}]Kt`2wtgg 2 Bw'ɥV7R7IΡw d(v׿bppeq\η#fv@ NUUu˲TU 3lYCfM40 á`2z< ECA+WB8Y> ό<dM1 Qח1 rU'KS_Y4xS3s;v^1 Nx<NDd~jO{~sx?K"K`C<&P--rV"Fg._ xG ٱC@rozӖ~`-*q-14ط?>]7uJ(R"LtL뒵 ,l٫J/smrc~C78#:n0МJDj0 [tqmίOBv,Q'4b55\GxQ@LUϜ;^XV2S&j6EACRE [ 18>'H+cP.ˉ1$TE#;S)EI~GL*^\588hmjՙsuJ moa1axMUB_F1t-ic{Tr0Be* MSO1R5P{[^R.t9ݽcWCrw"wْnRb P$ZC,7ljđ\8l~-pž%cpھT.э6zf?;uriea.)j+/~#iFhVj;gg9u흷Yj`#D9+y75;Q(ad_yYkUS'~Þ;6BIUԥm{3XF  s9:Z6winDcRnػO?q xL=͊ W)0M/jF@ըǽ]OSLUT]x"DJ)ԲL\,̯e6ܼ>6FQDR=a#*RTsOBP,CDrFHyΝ>{߭M*H}ؙ<`30RUEJ`iic² wC@XN ǘ,R™0'G|\doI/^X 2! -J,_ϦϰĐHx6Eitk#j#H4F:~bn-իGpdm|d}!8vJL7tV+3l:P׭vgV&z0&7")I_m'BדnoSæWv1 !Q6Sĥ5QLؑuLpLE<}ib{ f2%%TSvLt D1Is;I,';|,X;~Yۤ #a^z/ բ IFATkDD(BTJP pٕfˋZ>%n L 0c8`t!W}#KVqz`ry֏~˯++h{=!a*BԪ RwS]Q5MJ#B*[5&+ V4{FR`m乣n.W-饮|es󶶦D뤹Nhr|sXT i,^m%35[,z`Nj%*&\zj)gPOr]$k J"Z|gǣ6LLrZѺZ.F~Qz_H `/7')KK' kn.ř_ήYí/HKH *T*t^`l誛YrxJ1ňrgqF$6:=9^{܉֯z]߷I\:/9P`"R󥐘A7gH .STsc٥{n9oYXq.F*%JBq(%\0IF9sP$'\@[HC] ܼٺ3;1a>p?2-«6 :HhZ؅߮9:6mlْO^ R,5Db Su,3]Z_}ɽrfTnuȭ&&+sR!ȷJCoK5\0Q??u%|ޙS{ {&/ S](p~͠ѺkDc,8B2ƁȀ氥` k1iUU&ňU\M5X=|`#T6#(,S׾/(k4 7xCS#[yǗKf01~Y0sl]F}fܲ ikrZ*V|qT][[3SLHֲ|D69#O%D` )x>hUb)/VUU63l $T3$8J^%/E##grlD9_8]x{_/nO-L#UmP9a]!"P!b D\pES14']kN92dm칏c`mVPS|ejֱ)VP7_~_'~ᅱ_Y %Q2E%[~j>+kɦ]t9ګMїsb6v':7l1ԯw_-ǎti51S o:7! Xss[\"a)?//,?ǰFJX\JI2(qʶnV X\ .uC ⡢fʅitrZa3##N9Cv̦Π}jؗ·?6f2sWsS)WܺV&Qg$d F8+?R2 ȤW#% KйyC/ԤLw8u|)0FB B @J=aa=*& AUq}y`ZZѽsW/&Z4"xc9)ȫ RPt$L$>s/)\Fɬ{?ȯ>now\1 A@㊺yGvk?{w0B.?qڒmЈ|yeew|#X %}_W؟}mih9czŠ6l'޵:ym>mi|/4٣r\Ǯ-]FrtCQJ7LOBώu>_T_[c|e}wi%`RRaSS]RDr<1y%mq-< Rp嬤 d3ݖ:_f ~n'x4ijE){~ȯGаvyێ[f8a|Mm6X^snρg^|wVDHֽW喏?f #L ]ݷl0;nj&/_"Ag6x+TB@$@ɸ*g~u>GTT)q$(?7$o S;KR,[B\q@u`ڰe*Q(A L0B*" 7k=>}=jc e^q*žSCu}hF= js >:?<}7T]5"!8ksKkcxc#Ҩ-RΌ?dF7En~ަڲvƥkn>zssĥ鉕e8`>Q3sf3_;7^}_KWwP!*%V,lpaiW] '†b`WTbTeXH"!"R.k T7~|5@Xʥ+5'7W˳p?T+y1^?ن7+*W;#ym۶.ho x~esG^ 6뵍gwE99q# %Aj>{Kki#[1;'8s0}ɪ Bb&B@TB8B`Bhˁƞ߶ᄋKw>տj{WيxԪXm*L:~:xRQ$BU.DNqïwNܵZǿڥl_8@}HQ0DzR8#}<~{P@Êck?YN7v߮w+Ww7lۡD5#ڏ_ܴ/=6Z* D1bvk}㗿BϜ[PSܨ'Z2#޵?;zʩh @Dux3 ,Ԩb$bi-Ua66t]3 *[BKà'aaeM֘}f"5VJqޚ]R9 a>goJ|o~)#Mѕ|n<ę8*xo}nM7^E_]vݴ9B*&*>!(8uSԚU7.o IQ9*%,hU7A ?q/I]|.;6w=_լ=ljⱭW^~%C}w|/}/>زkӎחe29gY)TvAF#%Bן#?EZW"{z yC.2UD ** $-RT:ۂS=/MO.(`G#+} lu/}Aj-aԉhfz=5q-PM%>ppZ+} m+ҩ7?ĝ/ϣ7߱>/w|#zփ~G`{EO&W AqN~78 IDATǘF{ +ck/Jwmm>7Z^m|:S˷lޱwFk)z .A8S3tT3F+#BK͚OL*.P:Kw|S@0/3+ҩ?wFjΤ-J8 8svCy A4*R!Nxc)B=Ƌku{ox:?;jݞrSL9' BЋ~U(ņ W." "K @)I&gδS~{Zk<{֗>+NꖁO@C% e0.a}vs$ʹ67- jáXӬ@4lط% Qۊ`/IiXQ}'װ f@Fק=? T$neU8rxpz*ͪeߟxyEKc̹iΤ&/>Askfi\%*,ẘ3q2#F62ӆQ8]z9rtԱўnO w)7ܿcw|IՖ8,^W:e1_p$ ba\)d=$;rIs_:snUdD(I| tX?_ɭ5|tdtcՍHxr,fiԙ7MKZug*shecCSV"ضM_h !UX‘\9ZQS,ɍv|όcGoj" pJDYk-&\`3&BxBs\Je#h76ٴXM'\x-:t|M)Nb{vlߜ9o_UW^wݷx6%$F 0-% *5p'ĂBȁ @^`SJ!)%f0TTh:DU%cJ5}$_"a'78gִI!&Bn^s[uM2bvف=[z.x/~wϞ'~WgEMb@k13p}5!8Cm֏޻֮=79жmÆC|LK/1 (CܠYTJ Bqcvp, K^蕹q徟8N?rMþFX|!~qsR @+jFab*$g mk/MqMF׽7^O=^Wgj:w L]vІ/ZjUVہWW~!{컭 cZ Ci[

'/>p_)$g}gCw*-$%Q"Cι/?~~?>9 nh*Tw92BԈRc کQig[VvZb*Tǀ#5X-SXit$-dPvpɒƧ|ŷvy/z~%Xu$e1Wmo;ԵՓyn Y]g^cdR㔽1`Km= /]s١M%F oo@F_a<08ʶsLAb2‘(!^O@1 1V]:x)Yu{}}ǗBs";6av|ڽm{ӒL3?~'O)C(Q V48JJ(5ȱ-wՁ'"TaEE0.^5u! -_3Жi3&iGkb8H+xU莿|v"WeWV_ןDM߾?y9+Vtoٜ̘cP( ccޘ[g6oQm=ݭSZi_H 'k{C=CJMS}C4unp߯?fraynjPjA4Xw)4! ;З̏8S oq{}PERbfjB[`qW]2<|Ut6u>h/.4œ+];v5ʉn~DWExr3O7߲͛΃_}:SgKG]_}W_ZBζO?90j@PM `9ɄTr H*- dT*1z%Ϫj)ah6;d:G#Ρ\{ok K.\srx<رl;8E BiI)u+eI]Fԡy9R%EoZZ]ZI'l'_8-x֯|k̦p aMccbj%J[.uVNp0&YΚU'L[h57xYQCQr}/|Nj҆ -;mDz/Hrт hK.[( tkGt8| }f`5REccs4HVJL\;}dFv Z ~?]~۽K;os ˗13؉ԑ_#/XRs5 Sn,?Z* `R?#.Ĭ(@Rh@159/g4󾻞Y{-KΔ7?[I wIY'c^F]*.=q睯5m]8=|מqC'oXiliO{3V,\?aZXv4ؾ[̋7{L({ 3tsCQB mc7>EcK<&㖟q`{Ţz귿H/O7E10B"a(1EJs`CQ-8UQ]E&I0]Ѹmk ұBfkejR28/WN+}(^zشSDh ?7m8о3/I#Y=gNRδly%;83Z5sNտX}V c)$&RЄȞbDW T00ԠXc@ akSoKLS鴦Rο7]{L{Ec/`|_@GWH$lH"B4!@ai*S$5eLPLfbeĔ5 R%[\juEc#R^͞2} cau6bz / 9U+ϝ} } ;~8N7O>^]zk|;2.Rc;wyߨf0@#0/<\($Zr㾛}۶fyrWRڎD֬:~3ޱgމFB1Wk# EWTI(<)]"B!bH3# P9J-l|jË+-?=.8u9+,3H8veuE2"P8ɐN*#.} ۏhI7th0WprY]n\B:yx;{8aRiͷ~籟b?3٩cW_)Ѝ13`D}&-q%a XrEbi<89W>}\>=k"emɎ8 dHG_87ё٢ξo$[c" 3.xܶdc6f9Y9oLr;:fNR"r8g_Y*}/j,GoD=5e&kqj+Nmֿ`*S߾#?}-L֌hιR`&) (BX" BPJT Fx`dwL̈-€xQfP6<wK/Yh*ϘF$66hb0%PIDa 5hlŤ\.jJyFӒN=^ursہp`7?0>6?ܵ%{?_{_a >ԽMBsLLfP-!TcRJkkB0F'cI,SyC$=5_+=no\{ex4jRd:^Y!ZcڶFXaM8 R R +b$8]^o@3O]lݖ]IUaPaB!BD@ϰ҂>ܹS*=WxG?PJFÁa'6}n:& EP>6"c}ݱ|w@1j;q3Xu4xo"]>84ZkAoͬNeHM9RZਓ[_ӫ|J:kG{^#HĢmY!@`4_/Wp%?}?"(faťMDzuҔš*L9Ft<}jB<{`%{o'~TC䖡UՄf)ą/Hb'ah`;G?xyJ2yM򳧝rmW~|ѯT"_?RXu~lw;2s]p5 >q"9I`1BclB2lZac0x0BQX!Z) Tc$Sx9sZ % 8!(*ť֪)(1RKMe}yUc9VᎫ7Be: b&cX*j_Sa;wX47bZ|OǢ۶}So=$#|ƤFWYMMVcCӧ#PW. ȎLJꊨL/~hr͑sΒk:MYz%a _{g!/=oO bɿ~iSo:x__lۺ1R;bP .u  p EH2@-c ?c+0XlUդIG}\ф{zubhT; E( Dױ|!# /: >d٦6i’>m&"0PēcVf `cPibǺ^[>Ѵ>j*C<)oXg%/1Q //Gawτ$Q'p@}3M3 C* 5L$F(CFsQ+; tj^8"YSjw}E9x`Z] ds,ۯCjdR&\/0DdPJA ;ZX:ɯ|-R4qÍ0"!BKaifjز:z+)V4 *KA Bj!K*3{GUBwUKmbBRD4 rO_}y0/ynMޒϱjovu{i77XbU/31n0 u!&,TkI @ORFYZ# `̄ٲh?_y14Cu̎[Q6 ⸤΃GBAC eX@)B2- [E o3 24g)ۈB9_,dB-sKP S!g!"BHDj \IL0;mnAtv{]VJkJbDLP k-F)fd򤔣Μ a(3=&3S=c`wث!'|ʥ `W]wUc3m/` OAN" J AShk>vu6ӑW%/a]*\}[l`!X<^#"`BILf DQmĞKdx6$/6cLgMLbCQD0&ШDz:cFCx5e9@]5F<#U:*ݱuG;?ޒZ0wEwq?E󇳅yGǷB0 }A&}*R*!$`*ZJ#$Axn\ mU&|_}쟞ȹzJ fȥ]m4uL|Wo4O/Tѫ/Wv=(dB텦r_|aB< .AZ*]*#0F@+KE/g7Z&ES0-4Jv|n%rhDZܿ2i?sKΒq? @a5PDA5-ii:K#R5iS-Lx~W{t?Z4f@Kqj_>yiTDJ+|@HZ,1utOK: [=rdдmaOk|߰'Pɓ0@4?c@AXv9Ȉ$<&r%;-8ii$f,T9K!TW)mzxH֔SXu5ՁaTVTOlIu4Djjj*֭6|ۓ_ukh4}c}0DNP fL&@LJ0B%Fp`hۉ S"QM2f]-+ES3gyn9S3+/q> ;% è C0q5sOlJ75>q@H.cd `$\Ϲv10ƊAgjV;ljT]i O8)F*j+[f; Ф1r MQ:0>(oDDH.$& : ̙:sJefkEO: `GJJnXW_fM'^{k]uC ~iGxnu\ںgid,A\q4Nj;8Z|2 +0l AA(B4 :uӖO#ْQJV}CO-a|U"*›OlXo zFwg@c0^UQjFbL0:ۧNxy#dw3?ٓNc aȿZr'HaNܜ0atBфWS @J,\jYm&3<]FTӭe%)R//$TbhLs>ٻCn͛C*sB6/9F@)kL,TH#޲k.U>dw7k5ݏhv /4p?4NXp &<Q1zGp92-s몞,| 0<_(*ȊaTޑEǯ?gs:o8{j? 笼z(k+ RB };c̩m8BL`k'0 8c1k0a%%ABs+޼i=R0{zSA,qΣn ʁ,N y(YK1XQJKZ?zzy4l5-)$_*x9Lʊf,Q2}maTeH$ϩfdŌxHa% 0ถ\hNK ͐I8T)6q@A|Hb5(xucu*:N3j21XP}>jF./_p ):4b? n  $:/\)΍ZbAD@+}F0dRYagŪisF[m˚ BVRcD PKmEa)t  4Lj6!nOJ &bech7Y]pB, Tа5FBpu0D &wܙݘ*+;h\p/Wtm@)M!BV_cGBLRJ,%`&?޳|QSg_3H 2!}vJX3 @͊BTU'M兪!^(e0)@ӈcIp8nM5V2gG-^b7- Q,1X6s R\L`ZP7@;1 r5~w~p߿uieM pk@kϿMcwQ2AdD,TI sKs`vJ*n m^`K!)AG#]e[.g1cܘduUX޸3CxxAOʸ4G2,cŝg5Lςr!'@ m )E9T#^E}UܤyJ r&4W ʀ6KLd+xy =I~LN[, m8ahJL)Rzk>3Bʉ{۴3V 4P!$J&Z Zh%ACPx?ǝARj u@xX˒mc| PC<̘3U[:tN@{h.PRIgmEuOlfeR" eM;]*";}-|l䬹C~>L[1*IDKe^F*# n"٤q=R×! J,d))M|Djˮ\53(6<-tc溼-|T0χi2[U{.%Y -_k#ս7m[[¨T%AZ+eiKvBи(/pꏧz:|<FhXtŬ晍e3rcNPNCS M%ىz~HV" -mEї0NWdyq:*w0 EG>m]PhHYɑ^^@αd6d=V 3hBvs6W T k\Y]?Ⲏ( -> >:cdfH „HU1?k*{۞Ss3Q$@ cCbYi-H`,Xb+0#i齞^<Ϸe$^kf/2|=D$oGnwӋ~s lH̛uEwg_֭u" {3饧~ߋICLrq==a5`w'tpk7`.moAkdKfg֋S}6="چǞ7+wqx19~rojdo薱/$csz^\6*1a r|ҡ*ً{_ 6KynŸ[Crv>}9"i^kxss]?\ Xc+7\wz:NpM>q'O>t3;ѽwM_=?_z;ybN{$'o.4!Kqv鹧Ͻt.yꍚ{c:#ֹ1otGfz#sr=SbKz.~_!O>Ի{O?/+Odk:#u1oEAV`.` =:z Ɍ"L,wU>#9:&y RBB %9K[6yoRvcu:vvf)z %eY` 5 q""CK^\`X]iO?N?|l P 7ٖaFSvȘOJY{[>~lYK>_2/yZYYGkn n2±7Oc>zpІt+WH*0h@L 6Gtbb*%}@ҋٟ~\}@OqsUW?|RW/|9xjIGլgr1@]@R߻3ܿ|fw9{^>Hb-VXc0ի6¸>V.~^y}2w]dT1u_}&Cܞ,/_O rO-j폞K_z )n_y!;:X[(ƵhR.-)݇}Uݝ\9oO~: -^,ū@/8* `v^7m}z<۠wm`Kg[uY bQ ˇ66IYI .?HP66W3pdVMŃS~C_}6(Jb뺪(v }w 6`oaY"3dDwHDPbi}J@T 6B2XB>tjtc/Rw&]̬Y2Չp`~͉cYJbrhGg~DBlE \xï9vz<|>zّ\Gp("̦TE, IDAT)eqTa2('C1 1j *:2| OoSG֦x݇A.l{n}f?ФMSr5Pw0{ vi&O_ms;3c;{UoL?Ϡg[(aHD )AϽvu/X<{ן<7n=qJ4)K`-4vitp?3NIJ.5s`:ؿgMVK[M͸>!@XEUz:R*HƠd V E kZOnjD FY;nNj® 񅇟*'9U)vX8.2(L\7m||T4E3YKS/E~![rybXLƛkn"]C]B >?/gwޘ7V7c][Gkdf,Ww+=Ei)u)jN&1l6E`<W_?f%wM,˲P8O [pLij[9X;~rٌQF8DՅ'uCN[x/`P`DH޸u6!>i{DT\2;rN0crl<,lc2 XJԟ5_yBdEiY8,*}Oo=v팪QiZ"f;mHC"=[Zvig/|[~bm(3ﺏny^%x;^޸p۶'RWRi5\}癪ݿ4vxɯp|sh(F_cH]ܬJd2Dl,Tɷ~]ͩrTդmS)0˅eL y}Wȷ|_nZo0 S;p72$bG;h$kroWf &HEʎ}fӷxܺ20_ܕ{jAiY@9E=6?'3F g $&AnЃ(l) iLrew=pM;w" txr\ Xol̹ŭGFPoTDȉݼ$Vfm #kk>vFUGȑLgwc{9x=}.h̹Փ|ǟ?קwc\7.qRq` #:?u #k3^({w eUa.'{6y pPG' _ T7~hR"6Ӫ>/fG?73 dqs-qG~pOɭnT2G.v'|?#݃8yT$Uu]ڜ,qua0 ;Li0_x-K(<XAN9g$Y#D""$J)#N [x[W{*DZ-{CFT)򣦚OLb<΅G:~'`~ۚ?6(W{H1! L|YT-#fa0/!ue~ 1ώSkc޸5H<("w΀֥d67[NBfWZLP(BTQ`k[w8}D=\n\Q_xK㦖AmUYSG[Om}yࣿYu3?m7|ݿD.nܪR3ON?}m؞7Jg+_(p k]T8-LM\"F楝Um7/`܏G/KD%ExY?^#1)ǣq@)7ysvw=12D\‰eu8SO$Mwf_iL I#G8Pk-`~U{R+[7rvJ R.QePLKO#tUC+×e7+;٘TQ΀` ɏ9:>}[阮;s)30g^mnO࿔6&57qID#D 9FDlUxd:'.ԛ P`cφ󯎞rRˑ+gcUѨ5^mǣ_ꮾQj؍/\68j#$CP[cHURN8T }G, y[iTtzոHC]T[]`SC֚!&͙0T,a@yД`7ĿŷNn=Ulg.{6''cҒaJ%aBg`ƙ9 R]Δ 4ƅ^ua^08A ?w벏$)vejyh2*U]8ۇySǿƻ,'t²]ױ9g_<4*Í9_\YY?ą[N.]DdsJ`ΌHj 8DfEM0D)q0A8 s@XԡH&96$-l= ?7TkkJ\Ӵ٤rȔ3J sBsSla, o;Oê)M'Τh¢$1C bDt&I9&V ƕj>+#ӧc5og̘XcgVq4IY;FYf#37F f\zW3ԓq5d-'^v2Y%x}mQT2ĕlI>Q#h3HTdbKge iHr0Hcq4kgZWI]:;k$*HšXrÃQӑ=1ߞo_/ nNz8ެV_[b^- f!}lz|Gg_WB`"Y*DeOHU躷RJ`,[ka6.Mp܌0S"{]]tfʩ%fk?W7GZc+%Q㋸je3WUQMZ8B"* ו-+{߭cO8z$sg{?kɸ %圄0]GAsb6EejX-ӲWued\Pt>G&ܓY8EKX- RM!&ueR攒I ra p cOSc3kn=v'gC/2o*}''樜WŤ0Y-P1>15&}J9"u,hBtMFQ-kYkmiY4hʱEgMUy'*aڠ%)fMXhqxM\ݭ?~T_׺7qӤ!8$0^522&B./ʺՠpӶ TqHD1|v =MeYrJhEUK%|\kM3֔\xvlIN6-dmBC%zoz۶+Kv8Fu>ҧ(#tHwI)hdBlTQӉT*' [n2*=c&_o3T\b@UYB #\ D]thP/41< ;tj $a!yrN)Z*_Jf99Ox R1rVG_?\8V3fs Nb''1j! T-PIS E᝭òĦl-D`MYy2|b!T6CM`,:##gw9F)5~(tU>|g ~_@]YɯVkz׶/h ζmK::'z*fH0uClI(䔬1DF,pݿ-~ۇ7z&خzY,A)J,CҭC09zޙŏ=7-hi}rTvi@LEkII,w:p+cʢ3U <>hA A"g1eQRPk] 9^5ƥ)"-:Wz\)[wzax|;9;NJ@ނ)zPAuT0 "޾5ū}(iUL(fV&XCn)]d @*E8'b!TUk*kt$4AS}K~QcҰDjAPS`o)" : 2qYV&=&ֲ4LD9 YYbS C;aN)l @d2$A`|9f09='D!kL7pĘ>I9 M 3 =3&YsFfI ¨v?vtՏF#UeF& 4dnIP"@dBJSYa)'D"!FcJ4٣a93bZ L+cx}B`(PΞc}5^V66'M3 _&Ua@&#+Cl|/FҗF"OǕr`FU 4Ip%7U<#[5NDXC0 Y 9T 1Q!ǔr9!ۨ 0G,Jmј9 Ŷ ~)yH]ڶssUͽ0} `,5eYz]EUI &~H) C/H )G!yC09a!>!1hU}|U^[dt!y臬BDY1 1 tmLN#:ʔz!t!\OG"[7XX򮖥%P1qՔ@!c'%:C0\ R`cZ)ƔEi=s4D- ̨9;( Y\[:_!pnksZa/u:7='Ycǵ84eUzt b D0A" 2s6 r 1sv~RWme!*ZSɆI${X$lrFvdIfT\?t&xZΡ0HbN&p$Cg G.#(rf>B̜4d#GD#1> 7{{ݐf(eChm BF2x,0)(ńdA2Asj9t16D%/WΚ2vz!)3)'4H$Ơ)UHзUSZvF4&WzYv~ytsM[M ]ߜ i#`IYA&lШ1sI<A0U_Bd 鈗{ڿ?ُ?v;*\QPUK!f.k׶-r3AB .'C  *[ 9꜒vUd)e}}+D(U)%ȝa: |e7*0MmY3M9!8T%U$Eb?Hښ3!P3*14QS z!)abJICPHU@ qeAٸTm*lIb'pV2rΤ, ]_ fU4c  }B,h!(k .qцe# T!u8.ADYPO&̵cK:mctp-RY?t;`$Aɤh,˔z#-J!f"#)[j"]U Cr}jo0S[yEuAӦl*9{é_9w]跅%NȚdD3(#8CޛK}wLՠ2̣I1}RQ#W. 1ƁI1}|eq2 C9t!!v9 uarfZ벆ِᜃ.2dy0T$rQHCw8 O IDATjU`$ #xSNX%ŐW}0U$ES._ɸ9Hi@ vAjwsX0h1B7)t4;[c8D}7dY@ɀ1䝳d8'ι,C+")SDIU-*E!$nqB Tr!1DAJb&-dbS BDkZʒcLʬJJY9!2%RIm! (XR ~^7uf}VP0\R+TT2d !XkJ_%)%c|! HfclCS,M^][iZ@}%z2ƕDc 9bI 33U(,ESNhH$t1sTMj&FۈE7EC[U5EY9s *)qN1" 6+g. :캁l~,ZZ2Py vdeXRJrf4I,$`) K eFe$ʜO CG& }P16Đhcx[YX!sj^"u@8#"(,jTBB هDƪdFaAUjsRAkiu6c]Z{oJKj1>1?g;Ƶ;XAF $fMLQQ@B9EDc ^G[# zq=0BH ~+;?oS3M*ĉXs "4pH- Jar>u18A 3z "zU'>u1cXBD}AAr? Ӡb~:6c2t|ڢ˦ ,1QU|nC&SPRRY gCfpk‚Wzdͬ*$a.(*>KW9CaTW"GMY )'9e}b*2"$f6}ׇ{4a9$r(Ued$Ic9g\ 4pe`Z po-eW3P{{|t~2AwXk4CZvPu=&k+cEysr ""者WΝ&"l=qߙO[㱙V~"B(놅 ɚA2cf.[N`¹J503 (jWK¸tLIը؃2(yIE2; 1 FgD$b⵶Q|eZ{@1GXYcpV5 (D͆!X`Η>s60AVk5J9F̆J6X"sNTB>q&eQчÐ<${FMvU Hi4H$E0>ñ|#$M0>`",@@HFaf4{?kkuڽSTHzuė0l̴8e8R)(KqUq;T+dG@Х5p8M+ K1G!0~4h,fҩ Vy &&rw1Ƣֺ$bI)Ph۶UU!/)ƭ wF8{`qEbekYbJ"E2Tbfh 4]$0&e&(k"TxdP{.~\JL@ D&/ ) "b!t! `v^;AJRaFRSf W$a06 &XCͨA0v$@ .v.gP%$蘳DLB!R3{cH%Dj 9`ؗpJ813yA_Zvq @&kVFm8ARΕz*A#*vM) !1k"V^ɲLUҏ376)>u"{2ҀPY*%H»nXcȐQe-Lk; +ۯ([T.8/F*5Ec9 1fR,@$cHIYA@b="#pwEYԄ$ " U 212ΏR48HH2c@XB$QHBYLEhmAfY *ŘsT]%MmWAQ`6>qjɤGmBo <&;[ڞL c[c K/Sm (heQ:i$+ܶ])9gi!s,MLQU-&UHCb K̑UsfQB3۔R(`0Q*.3K4Zx\jSi`$ܴ 47F̥c *w^MMBafsdG :k$6a q\ q\:gYXDkR̩ҕ<%s#@{*܃rZ&"Gt6"Ĕ,1Dd1b>,l}o׫T!:@(Ir`A4QM0l qhc7 1 E`eQߵ"8aSnFf_SJuDUR:1J9% 0d)@"mA&Rafq ]׌lJurVUi3%c 䜐QYĜp3g$(fi<P%9-HU1G, UlTG]B#NmB ص6wvP.%--F99 ̍;Z-;f]ښ,FdfP^_C~;dZH9INsx![hSv'9j|+U 82l,k9.:CV!#\\e|gLA8'gZgsE*v.XAF]$}XoOV6+zeQD )H&Ke Z;#F@8fKDPFKAd5c]%;AY(t-ksЪ*2?.gBBmG^R4YNm.2CgFTP8o89匔SufHJ]j:G$A$8(ђI؎QAt".I-RBjBj%vP3!j#(( qg]s)$8"m, M eEf`]b!eT MHIhi`FQEQ"KleԴ1Bẗwq0B;cP*c.TdE)r‚"XYKD0"2,15MMT!6] Mٗ>+ u mؽ߿5g 1&-fGaeFfeYXW_ڿe2@K*I@bů90\0TLJdñ'_pY[pޜS p{ϼ|z*S{wC_[W #M/:27kw/ 8?9ַx`=kWjpPl;cqq|w~kj5yk[Oٰi̱9M1QzTLC2?cNy8P#I$Cî 9!6&މdT,Swy+/q7=H$yT% j銶eTȪ*#!䎼D֚-c PUg 8œ(W$(QBmPs_ܿG4:!z {[N7 /u3O?wzފ.G7MT+X93\k?}^ٹ8qO9>AOnOټfYs7,..n=9ҿy{_ ګοW9}Ǖ/x!g=2׾Ono{ukzW^rucG}UpNԫ>~pM<:;# lba}.oy<УD=sU+GsÅ3x|տu`k5n '{ޝ9v'];~w5扽eO_ZsR1~KsCGVm^=Z\X0ph/:=ַ83 F㳞~ǝto瞽Fr7mgn }L]T%@׎;R'h@‘K'*Cܥ 7܍ǀh-u!#(z~ϙ2D` A+DLiRfDt( P`ΒTDBȐ O8OtG WyvӥzS'7oU6sƭ녅 I&$|lbwwĝ8"oX1K/Ӷ ?#mvEz'mY λ͛'nqg~zhGGgׁ}ݚM#0~ _5_ tHƢ! B鲈$͡cW%9yK J9 ( YkLyx)T'k daFk+kPDޫ*!tU .f4&geZN)vp6< o٥.e {߶]9{rGn2 &o|vЪ;rwUEUNh_򙻒_{ζծ"+z䑇J;zy\W|G㎋_q֧>Gx k''/.<.̟#WϞ㩵Sh_?eex6>sSk^x|>m:ƹJd~r_>+{ Ω-+_|'?_d/n5~:o֡]78b=!uHR2LbbƠ6MZ ʅ/ UUElŘ;o p\Oƹ; 9d+ƗKdKm/d0rΜRؘMCSN|ݯqXoS'gv?-޸0_7?7ϹEyEng_pqK_Xt7ؓ@qgfW7cKx~mW5@Ze?Gk_xџDXN W]3q?{Yo憻߿gӨ)dbMB.p[?v_◟:ϫ(\U-DCF!)*iVbά"PSNFΎ9+?#˪h63#Rv{rα, *@ӌ@"S֛Rkdc*:fQ4hT:37mx&N8sC.{.㣇^N.]\3pw|,QP&?Q{^ع[3{o55Vݰw!Tv>0pV +V>vlo>TGwLGb5I 5SHK: WUj b"*sΈ*U EQDQc@8DF̬TcQQιn<J ʚaR@t]^^qpv<{wqǏZf'Gi>쨮 IDATRSnp?M;Q˶lP$^Э'ne]gt V=wKa7_<4٦|]wK=zM?,9X Y ٛӽ{w޼cώsv-h$x}G;0q?&/.v\KD7;0{hqԴAQpֶ;wqچ(K۩h;=9R{bȼԎ.|7^st"%G>˚3w3/^9Z8sOڰ9mڵǮkn.7ٕ5mՃ3KClC42 ̙USIYas:K&Ũ*!33D@*t1 ",],l;n^]ۖ1{ҪlfgrSZBpڇon{e#}֟ OxbOѶm^w©[=#G?6.{hú(U 9[__]c_7Trj㫞uޏc]]ݿݵWsǺ5Kp6w09I޾c˟$9 f]؀vqwu3p3.=_63XC~|˷9˃Dw;|#Nt/ڧʔ/ه]5ɨ̼Zhq('`RteVz3<ա= &kY% `x/WtWv~iŭg~tx  [8}9w?1jÆ+0tZ4Ue| 5acs̒4ǨȠʜdت)d$Wx1!kEUT1 0Jr^91XbʆeN2(pna˪*'$4x`~?؜r\<6{nJYo1ᡣo^537}rHN= LdEa87t~ӅKf} azP}zbnmgx9 ف2=xozΆW]{_rɫ}EDžw?s7=Ka%V-k獰߳ԍ!Ttus"}Oc ^;/<}xf7~m+.<߶ȧǻr?/Y_;}uK< NL۶?|}\{G#c-֫O}_X8}뾇vyZS KԣmMob^v=iDt)yzwrO.9؜Wظ|}q9ktj˯vlGgspyoϜx/ Oz)r.q{ Tߴ}?3_={}Vg毗kWxѪ;;w %UY7{wOOYOuhNRTTHMmqJEUDm 'frrt9U 2DrkLԬ"dֽ pQgkmY$1``]WU5CIш8 cL^/M(Uagw,-/͛lUL3c&ZAz`6 `˻ozhPj)kbóקn;6kyb&v).ZMKVl9 K })s*`8~_o_ܵ\0 jKmsŠƘSk/6N3o} vA91$Q1uWl^ab|}`S-.1Wonh|ٚDWvAįX8)zfovV:Qgԉ0=y)o8B΅5X9  Aă 8nv%׭\N+DOUc! R|ؑF oK΃]p҉`;=uM{j]3VMͼ0:xn}ֳӶL'S'΀[θ,&Jd]^a(DR1!/ç1I%l1!"Ɯ@1#zJ[F|Qp;BBpL~B"@Q"( pl'p,uɑIʜ*H a]9Dzʚh)Y8r}*z`Fl&mâqhv[2u1 Tn,$: h}eˈÐ=M}}e hK8_ccQBA)pNUX?KA= YX,uNA"Ou0\cp)\,#|OX4+qI4z܄zjruY aӶr i(Xy0D)>8@IYUmC]WXX@Q"眑,+"rびM"PIk6{|쬵>˚Y`*$_ҸɪKػQUU@Q( +19{r kʲpD^5lEBU,E h, jc *@|lKWd&8l RB袪Ƒ9z[9"%CTrP6,6B (s w(ҵ ^g ;fIM2M JĖ;%Sx^Ѩ0N*tp{nuPbcQTEeDf&"4Ke:V&HJJ@Κ66嘵0&QcAp~?!,*ֹqrfXVN?zVE%g{o ]I*aB 9wǙ̵eQ"ksvu-x1ޚ *+H'K(D(*I 9(Mc3е)Ff1̂"dN s&"\~ic,"1֒3䬱"@qY4'q2^T(kvX)^),]g Gy5E,LAuK{jg"c I5+MY^XQ, 9s ]C1Qc9_S(C P9#91֚AUYC .|E 9ދEKc0r*DI]fclv$pL彳zue)XxWXE`>-,/`,U*+AȓcAD07㱳t\AH9"areᕥ*],SfkA,-/ oPYEbMԯk -J@j";=Мct֪("*93@Hq33k ]4FT@ Φ-Fl"|eM)-C (¨ "]fάDF̜֚s0]c9FUe(&{=\✔W&) 'fO,.!B2EIDFhCgS!%!`IK[EN2Qpni&{5SH`ѐ)A”20K)%Lcoc(X{0BʪYDEPArmzuի1EΗ)TpU 2]"0;TsI!qU2  *qywJtJE,|a}ZVze_vl159EdyoZ Emz_vU xLu*56mSy35v#b 1ս. 8SҀ! mT,Xd|aRЊq)9c[IMԻ-ɭ[~ YErKnI"KTUu]؉@b^Z6**kTL\(8׌4]T5d+̼NedfVUՌI̮GĜ253+o;2]uTΫ FK6}۲9\G\-VN vm%J'1mvYUwemf|4ݣ:ln6#XęeUgjfQټ8BUr\jsL "* Us_@(1'L%LDڶX1 ѶmS11qܞפrmv>gfBVjtUڶ:ۜY|9 9ƌ:_sNWlvTU|<v;*nNZ͌g^٣">*gSccR)JzUMeȮ`נ+ѯvSz2a `.HQ3JBJTǏ䂻 0w֚Aۜy?ƌgZE4df$PWͿ=?ޮu^ߝ6߶Yrl$nd& x}> 2iMKx0+} EfDD3I9D" PĔYR*TemWWas?̓Krǘ5/"a~{ܟTL"?K??9g90YvTe&ZqHTL1WTz7kǾf-ϟ\U(W ]U[oyE3Upd$%I`̾YkW5Ϩ%ߡ{_c(BRb"ˈL"~1SMsUE RS&Ftsu9&lbY TUV1TVn. almksWLlj,* v^9Z lFrLqcY%&QUgS"PDq_ @D L\92FTۯ?Tտy^Uqn }ǹŨrc$M( 8PUL*fό@*mGP;p31Hf_HUR`q;Cݷ?vL53ecU.fDmzUD`qVU$UvW7 m'32r s*Me!"osbZY'QR"ܔADQy۶Q)Dn\I+S]83,#FM8LU 79ƷjHTTE# ~?ee')QZS73fߟOVy{NT \d68 b8Owzw*aFR!cD??>[+y&@mSUTmq眃n}DUUs00H*(5QPCeJXF1}==ƜwrĜ"J*\|;v!^nu%eSNSX[$gdz< 5~E|}( U79bfNo۶921sլ.lj ߌ L1w*5&f3Xw1 bRU}lfncmۘ%&"&.T׬ s+fP9 lgn*7ushEvxDyV͈9ΣomwFmTf <7B13qܚjju$1F7k,s}X IDATL&:_۶=MU(kLUI{F*)lST{QdU#?zlVvE0 T?~xOD͛ܵ9΀TY"KTD4#2c=yk̺uo}+q1=tmrYmwpe 1յPBT4Ƽި{PcrE\53\#+YUEL7s{%DdxȏBykjd~}8++ 3rs}3{D|DPU&T~ a&1ѺD3"E$6^U[ĵVRZ5f]+`H gսZ1:P߷Jٻ+0aT׫/GfU-tFߏ]ysk9W%D6`0b2krUcuq5ksι[8hL LLFR5lvg 5%9djDdLEw1ݛMS9Hȉ[kED|^ vxЬostE>gf|~\2qFEU<_gOT#C^.t|ӔQg敏6ro~YH{9ssW_{=UmcNwHTjTID&Q"2LSVUf>EHhmbN6F,Eg9Ƭ۶eTddVoqsGsgIY$sDs'"I,3 s_?kq܎8*YVXF3E>E"欈9(VًDI*xӪ֖6`o ĘϏu~{?;*5gZz+sVa1fb"rmmm~~~|q$(zsnE_V9&RWJ128&d9*^/E#LyC@V̬n󌈪L&:*@1';pdٜsgSbcf[L@%VaeDU *Lͤ͋ˣDrFMՈ& m>$UUB.tcfگȈ֣(,U+Wք•&=3Kl*D۱YeiUM瘪 #a?.jB1r*!b~;쑔YfpJjcп,[JGV{z)TLfffBo[j=Pugp *4 WB P3*%z4fS]Ud0ڗ+g$D).XGE8"UUID8sa">'*U$3Pio&w?ϓY札yF:?<3J*m$Y/f*$j}_ ̕x1g܏(WLd1_՘1!&ctbRQ62PFd",, oVcΪB+@쯩EIfU1EU+"vIeΙ}|smU~jAԯޟ9bb2 dDi׬%Qf,}\jyM )dSe; U%~-X@#G 9U1+L¼O36,9݌2!C,Īcǜ,ThAL>BD-k_̘b6VuR" ,PjSI #fdU219HaITֵz]B9E JL`>>~GQ32w|Y斑"udoۏ33!c وLDdD Fee(jQw=REn.,M]mfooq\gj  &k Jroϳ6t3TCn*7 ĊH&mj0eE&+? f>Yfjf(6ƾmc^L," Y93$F&F侵L0PnR(dr̭5d a"k,J®VE*V$SeJf3'0ԯND͌M*sJTM2gyO7.((A*?cfFQ$‘9@,ؽcΕ Uz+vB}83+3}YTY1m۷3ABycwsj$Ie %#95N$Ҟjn~MتN ;a.r~]WD|~|[r<VWMa _~v}<_L"9X4 k0188Ϯ2(_?J1Ig?(@YǸއ9EHoc*| q`꧙EV2eD5t31wfu7Z&jiXr%c]F WHT ry[ʹM(" 1WUsL " ƌ {@HUI.YYDu\n356`a793b[S*I*%=X^syf"ЌQ<" (/uoԝꘓY |⩉d"R$ ,36Be+0(,a(F2 *CU5MH|юD&m'7Tc3Tiv+Y2RE6N& k{&@i,UL}5 r&Ǘi1K_D:f0Ws&&㼵CyV!LEXDsNbkXU\՘2m`V(e35m1L~0hF6ofˋD,b*="##'/\)̈dS_%[difco"qAU犿TeY6%pjQ%̙nN$Ul3gENa1 kdI!n"Vf2T&pUjιQUT3<"̔Edf_=Y̋{U,Z{-zRp1خB(eV&U0+fE:R##D\ʌ"w$+m=z۷Ȭݝ:7"*b*V)3|͈m\pՅ2*W^K̕ Qp"YJL!Y"Qox81ǘٗg355,2f[VE1TZ@4gd]1׫1g[DYT휝D=V}w̮d;4g,-oss\snZc&@xRUeqw0*&XEl1^sN/ϯg}Ixy H~U/*\"7S&p $fN3""9ʌfBY2F1\ܷ>"V26Z=pcD%ul̑ܖ>ߎ}w,_]ydQ¼P0U DVtQ,`6| `L%*35Hwg@oowDOhU՚EKFڸPi"̈i(8fvoB ~]f#"6ⓉYWS1!r5HJ{D٘H"Lac"fRզU5e7d]1|>$ psm d0s! Tf3QJĦNm1K"1L,Dޚӫw*:ط",bb4QU~l*Y,+AU@e8(#ͤfcf{lRU#CEP=!a^;B,3D yPdQUSc)VN,PGfm?_5,aRmk`&ٶ5ej"eN}Hx133 lj\̙ڗ`i(+JB%LV*zLS*BDcawݰvZNy%E5}$pp Ung:gD&mkRD3DfLL2uMurb5zgBDtk4AAϴNbM!_L|:B*jv~+**T77VWQѦ6\ Hїs(LE,"_^>e^"RD "SXrAmςA(31U)^&=&O>%?$,IDATg̦*rϕr bO$ѨJkݧo BDJs e]۟& h EUInLgpl9VB7+}X,@ SU o<tnom1SLߞw03Y/n۶cb1cK0 I5s՛"ʋH{>E̬*38@.\\M\ o0 (j"hHs4ӅirQW[B+No`IENDB`eureka-editor-eureka-2.0.2/htgen/eureka.css000066400000000000000000000116711464327712600206420ustar00rootroot00000000000000/*** this CSS is based on pmwiki.css ***/ /* This sets the overall frame for the site */ body { margin:0px; background-color: black; font-family:Arial,Helvetica,sans-serif; font-size:14pt; color: #aaa; } /* These control the fixed-width text elements of the page */ textarea, pre, code { font-size:0.9em; } pre, code { font-family:'Lucida Console','Andale Mono','Courier New',Courier,monospace; } pre { line-height:1.2em; } pre code, code code, pre pre { font-size:100%; } /* These primarily adjust the size and spacing of heading elements, ** most browsers have atrocious defaults for these. */ h1, h2, h3, h4, h5, h6 { margin-top:1.0em; margin-bottom:0.6em; } h1, h2, h3, h6 { font-weight:normal; } h4, h5 { font-weight:bold; } h1 code, h2 code, h3 code, h4 code { font-size:1em; } h1 { font-size:1.90em; } h2 { font-size:1.50em; } h3 { font-size:1.25em; } h4 { font-size:1.10em; } h5 { font-size:1.0em; } h6 { font-size:1.0em; } #wikimid { table-layout: fixed; } /* The #wikilogo element is the logo from $PageLogoFmt */ #wikilogo { width=240px; margin:0px; padding:0px; background-color: black; border-bottom: 1px #aaa solid; text-align: center; } /* This controls the rest of the heading (primarily the search box) */ #wikihead { margin: 0px; /* position:absolute; right:10px; top:10px; font-family:Verdana,sans-serif; font-size:85%; */ } /* These are for the left-sidebar. */ #wikileft { width: 250px; min-width: 250px; max-width: 250px; margin: 0px; overflow: hidden; background-image: url("grid.png"); background-position: top; background-color: #002; } #wikileft2 { padding:5px; border-right:1px #aaa solid; padding-top: 15px; line-height:1.33em; font-size:14pt; font-family:Verdana,sans-serif; } #wikileft2 .vspace { margin-top:1.125em; } #wikileft2 a { text-decoration:none; color:#09c; } #wikileft2 a:hover { text-decoration:underline; color:#ee0; } #wikileft2 ul { list-style:none; padding:0px; margin:0px; } #wikileft2 li { margin:0px; padding-left: 6px; } .sidehead { margin:0px; padding:4px 2px 2px 2px; font-size:14pt; font-weight:bold; font-style:normal; } .sidehead a { color:#505050; font-weight:bold; font-style:normal; } /* These affect the main content area. */ #wikibody { margin: 0px; padding: 10px 10px 20px 20px; background-color: #f5f5f5; color: black; font-size:14pt; } #wikibody a:link { color:blue; text-decoration:none; } #wikibody a:visited { color:blue; text-decoration:none; } #wikibody a:hover { color:#07f; text-decoration:underline; } #wikicmds { float:right; white-space:nowrap; font-family:Verdana,sans-serif; font-size:80%; } #wikicmds a:link { color:#666; text-decoration:none; border:none; } #wikicmds a:visited { color:#666; text-decoration:none; border:none; } #wikicmds a:hover { text-decoration:underline; color:blue; } #wikicmds a.createlink { display:none; } #wikicmds ul { list-style:none; margin:0px; padding:0px; } #wikicmds li { display:inline; margin:0px 5px; } .pagegroup { margin-top:8px; margin-bottom:2px; } .pagetitle { line-height:1em; margin:0px; font-size:1.6em; font-weight:normal; } .wikiaction { margin-top:4px; margin-bottom:4px; } #wikitext { margin-top:12px; line-height:1.33em; } #wikitext table { font-size:100%; line-height:1.33em; } /* For MSIE 5.5 */ /* These are for the edit form. */ #wikiedit form { margin:0px; width:100%; } #wikiedit textarea { width:100%; } .wikimessage { margin-top:4px; margin-bottom:4px; font-style:italic; } /* These affect the lines at the very bottom. */ #wikifoot { padding-left:256px; padding-bottom:4px; border-top:1px #aaa solid; padding-top:0px; font-family:Verdana,sans-serif; font-size:80%; } #wikifoot input { font-size:85%; } #wikifoot a { color:#eb4; } /* andrewj's stuff */ .footerlinks { float: right; } .footnav { padding-top:4px; padding-bottom:10px } #cheatsheet { font-size: 85%; background-color: #ececfc; border: 1px #7e7e6e solid; padding: 0.3em; margin: 0.9em; line-height: 1.33em; } .cheatsheet ul { list-style:none; } .cheatbold { color: black; font-weight: bold; } .key { background-color: white; font-family: monospace; font-size: 90%; border: 1px #aaa solid; padding: 3px 6px 3px 6px; } #codebox { background-color: #fcfcec; font-family: monospace; font-size: 80%; border: 1px #8e8e7e solid; padding: 0.3em; margin: 0.6em; margin-left: 3.5em; } #noticebox { background-color: #ececfc; border: 1px #7e7e8e solid; padding: 0.3em; margin: 0.6em; } #warningbox { background-color: #fcdcdc; border: 1px #aa9999 solid; padding: 0.3em; margin: 0.6em; } .kw { color: #d00; font-family: monospace; } /* These affect the printed appearance of the web view (not the separate ** print view) of pages. The sidebar and action links aren't printed. */ @media print { body { width:auto; margin:0px; padding:0.5em; } #wikihead, #wikilogo, #wikileft2, #wikicmds, .footnav { display:none; } #wikifoot { padding:2px; } } eureka-editor-eureka-2.0.2/htgen/grid.png000066400000000000000000000006531464327712600203050ustar00rootroot00000000000000PNG  IHDRL\sRGB pHYs u u-xutIME  OtEXtCommentCreated with GIMPWIDATxݱ х oBFگqr-ɛ_l= @] 7: @t& t0An t ":@`@0An  |}& t0An t r@ L@`t0A@:@ @ l,W8JIENDB`eureka-editor-eureka-2.0.2/htgen/index.html000066400000000000000000000331341464327712600206470ustar00rootroot00000000000000

Eureka DOOM Editor

Eureka is a map editor for the classic DOOM games, and a few related games such as Heretic, Hexen and Strife. It supports Linux, Windows and macOS.

See the About page for more information and screenshots

The current version is 2.0.1 -- grab it on the Release page on GitHub.

Screenshot

News

07-Jul-2024 : Eureka 2.0.1 Released

Updated Eureka to fix bugs and issues observed after the 2.0.0 release. It is available to download on GitHub.

04-Jul-2024 : Eureka 2.0.0 Released

New version of the Eureka editor released. It is available to download on GitHub.

For Linux, the project can be built from source using CMake.

28-Apr-2020 : New Leadership

I want to make it clear I (Andrew Apted) am no longer working on Eureka, and I am walking away from it. Thanks to everybody for their support and contributions!

The good news is that printz (Ioan Chera) is taking over as the lead developer. I wish him lots of good fortune and happy coding!

06-Feb-2020 : Eureka 1.27 Released

Changes in 1.27 are here: Changes127

UPDATE Apr 2020: a patch release, 1.27b, is now available which fixes a crash bug.

05-Aug-2018 : Eureka 1.24 Released

This release is primarily about fixing bugs (especially the ones which cause a crash), optimising code, improving configs and general polishing. That said, it does include a couple nice new features!

See all changes here: Changes124

P.S. the MacOS X package is available now. We apologize for the delay.

16-May-2018 : Eureka now has a Manual

I'm delighted to announce that Eureka now has a proper user manual, including numerous tutorials for specific tasks like creating doors, stairs, sky areas, etc.... You can read it here: User Manual.

Huge thanks goes to Wesley Werner for writing it.

12-Jan-2017 : Eureka 1.21 Released

The highlights of this release are:

  • improved BSP code, can build nodes just for current map
  • a "Test Map" command for testing your map in the game
  • mouse buttons (and wheel) use the key binding system
  • line drawing now done with RMB (MOUSE3) button
  • an operation menu, bound to F1 key or CTRL-RMB
  • a ZDoom definition file (thanks to Slade3)
  • smooth navigation in 2D and 3D views
  • select/copy/paste textures in the 3D view

And much much more! see all the changes here: Changes121

26-Jan-2016 : Version 1.11 released

A new version of Eureka has just been released.

Major changes in v1.11 include:

  • Hexen support!
  • Boom generalized lines and sectors
  • Eternity port definition, thanks to printz
  • treat Freedoom Phase 1 and Phase 2 as separate games
  • rendering of sector flats or lighting in the 2D window
  • an easier vertex "drawing mode" using the LMB
  • fixed texture warping in 3D preview

Plus much more, see the full list of changes here: Changes111

BTW, the SVN repository has been transferred into a GIT repository.

18-Feb-2015 : New version 1.07 now available

I have just released version 1.07 of Eureka.

Windows users should note that there is no longer an installer, you can just download the win32 binary package, unzip it somewhere and run the Eureka executable (making a link in the Start menu should work too). For Linux users, there is no longer a pre-built binary, you will need to either build from source, or run the Windows package in Wine.

Major changes in this release:

  • full-featured Find and Replace
  • new RECENT category for the browser
  • Rename Map and Delete Map commands in File menu
  • improvements to key binding system
  • vertex reshaping commands (180 degree arc, etc...)
  • reworked Default Properties panel
  • option for smaller textures in the browser

Plus numerous other enhancements and bug fixes. See here for all the changes: Changes107

Jan-2015 : Eureka packaged for Debian

It was remiss of me to not make a news post about this earlier (much, much earlier...), but thanks to Fabian Greffrath there is now an official Debian package for Eureka!

It is a real honor for me to have my software become part of Debian. Thanks again Fabian.

25-Aug-2013 : Version 1.00 Released!

Version 1.00 of Eureka is now available for download. There have been a lot of changes in this release and numerous bugs fixed, as well some new features. The most significant changes are:

  • extensive map-checking functions
  • validate map data when loading a level
  • texture alignment commands for 3D view
  • splitting void islands now works as expected
  • improved grid, with configurable colors
  • scroll-bars for the map view (optional)

The full list of changes is here: Changes100

Thanks again to printz for creating the MacOS X package.

Now that this release is out, I plan to stop coding for a while and work primarily on the sorely-lacking documentation for Eureka. I hope you enjoy this release.

27-Jun-2013 : Site Redesign

For the last week or two I have been working on improving the look of this website, especially to incorporate an awesome logo which Jason R Johnston sent to me earlier this year. Many thanks Jason!

24-Feb-2013 : Eureka 0.95 Released

I'm excited to announce that Eureka is now available for Windows! You can find an installer on the download page. The installer is very bare-bones at the moment, since I'm still climbing that learning curve, but it will add Eureka as a program to the Start menu. So far it has been tested on Windows XP and Windows Vista, it should work on Windows 7 too, but I don't know whether Windows 95 or 98 are going to work (reports welcome, as always).

Other improvements include:

  • Preferences dialog
  • Key binding system, with GUI in preferences
  • Automatically back-up edited wads (multiple times)
  • Status area on info bar -- replaces map name
  • Prune command for removing unused sectors, sidedefs and vertices
  • Log viewer

Plus several bug fixes. The complete list of changes is here: Changes095

27-Dec-2012 : Update to the 0.88 version

Eureka 0.88c is a small update to the 0.88 release, which mainly fixes a few bugs, but it also adds a new port definition. The changes are:

  • support for Doom Legacy, thanks to Wesley Johnson
  • fixed the slime trails in the 3D view
  • fixed bug in 'Manage Wads' dialog resetting the port to 'boom'
  • fixed a compile problem on 64-bit machines

I have also made a Debian package for i386 architecture (32-bit machines). This is designed for the Debian 6.0 "Squeeze" distribution, but hopefully will work on other OSes too (Ubuntu, Arch, Mint, etc...). This is the first time I have made a debian package, and I welcome reports on whether or not it worked OK on your system.

23-Dec-2012 : Eureka 0.88 Released

Just in time for Chrissy, here is another Eureka!
Main changes in version 0.88 are:

  • large overhaul of file handling:
    • 'Manage Wads' dialog allows setting the IWAD, port and resource wads
    • 'Open Map' dialog, with buttons for easy map selection
    • 'Recent Files' dialog (CTRL-R or File menu)
    • the iwad/port/resource settings are saved in the PWAD
    • better 'Export Map' dialog
    • IWADs found by the user are remembered
  • new Default Properties panel (shown in vertex mode)
  • implemented picture mode for Thing browser
  • new Move/Scale/Rotate dialogs (via Edit menu)
  • HACX support (not quite finished, but usable)

Plus numerous smaller features and a few bug fixes too. The full list of changes can be found here: Changes088

01-Dec-2012 : MacOS X port!

I'm really stoked to announce that, thanks to printz, there is now a MacOS X port of Eureka! It features a very nifty setup dialog for selecting the IWAD, the wad and map to edit, any resource wads, and the port (engine). You can even control various editor settings there.

This is available from the Download page.

27-Nov-2012 : Eureka 0.84 Released

This release is dedicated to Dragonsbrethren (from the DW forums), who provided some really helpful feedback. Many of the improvements in the release are a response to those comments. I'm grateful for all the other feedback too :)

Summary of the main changes:

  • multi-select : LMB toggles each object (no need for CTRL key)
  • more intuitive use of the Texture browser
  • implemented a -merge option for resource wads
  • reload the wad/map after building the nodes (no longer exit)
  • plain MMB now inserts an object (like SPACE or INSERT key)
  • thing panel has radial arrow buttons for setting the angle
  • allow running locally (without a 'make install')

All the changes are listed here: Changes084

16-Nov-2012 : Eureka 0.81 Released

This marks the first official release of Eureka (not counting some testing packages made available on the DoomWorld forums).

The main changes since 0.74 are:

  • support a proper Unix-style installation
  • made a proper project and website (thanks to SourceForge)
  • a command to build nodes (via glBSP) and quit
  • the texture browser can be resized at the edge
  • in sectors mode, SPACE key now subsumes the "correct sector" function
  • better iwad handling, can place them in ~/.eureka/iwads

The full list of changes can be found here: Changes081  

eureka-editor-eureka-2.0.2/htgen/shots/000077500000000000000000000000001464327712600200065ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/htgen/shots/key_prefs.png000066400000000000000000001223621464327712600225110ustar00rootroot00000000000000PNG  IHDR/*!bKGDx ttEXtCommentCreated with GIMPW IDATxwEaFvQ$@2& PA1E1bVD0"ALTT lutOOXpAϛw.3uի^^8]7 w L?se % @sH $]B"qeJH@6-1- ӲzS]QQUE(BtkI"6VsA^KӊR+cCؖvtFAQ/3KL*[%؛p9e^~K(X8mp-E!UPxoko}3 >SO;]{rG,IJ-- t El]Jm÷*@u]V, ð&T*T MSPkԫĖ)V "Rb6i3-,n4UATtUAqO߲%ma(MQPU%+.wR"#}cxvv7x , C ,1:B!UCY|BK o1}(E,szpv VQT@ۊPs;mcY6ku"TMUʩLsA,UAM&fZ3^dg!p}PXD:WzmK(w\z6,?8Q \oΖӴhX+t&j[s(*s )%e1L>Ƕl+|UkPH鞺%Jb9RJ>R(JjܰELb L:NHtRHtYsV@Vt-~>BJ6`&66P4vr!5xy ˲)DP(@@ :-~" y!,,[`ЫCk~[׬¨݀p5tlˢ %H) h*X6F,::~s[*FDANF"DhR.k%?V<m.j 0Qh@U!jUxyڻX5/*)L*; j:X=  bE(A]'fdQiK #Q- hJq4F$CWUA$tT[UR?.i7}\? B!" b t]%byi9*zA:3_2Bt۹rU¡0a#L2U$BQ$h?/o WgncꇟւH3m[svףL5 w`Ÿn,(!4V>w c»_ ^\pˣ88^~ٺx\>fOp}W0zf:Ӓs9}h)׏ {F?)Zsމzs6KtNG0eLr 3wxZ\.}ͩ)2uUA ֭c9 רŬZŰyKG~+J0F hΰ–&E }.fWAI1wl3.K1%+Xo+*B@QU @Y3%wIIY3ѽ'@m44]Tfؼ0lP]TΤJ*^#3d3Ukv"@ºRXHFf<RQQIK|` ["B8`e\[פ*NφX%0UpKlY;ZS (Y1dFf7>⠐>i[&pp][ep&4UawoHoًؚ~ciQ;Y9 8SXb,$.9٢tפ7:2ϴ9 8sy9deydժQ?X:y?9WoKBdh0DUF*ׄ -")ԯY}`Y6mev8*4KPq A@Qg^w״%1Ӣ۷Q3h4xdYT%#=]۶q*;.9gMIKj?\%]z^|?M gpJ/Yz ,4zrmBqYq[/8xr>'}) [PO:&vO%هz>KػWIxm!5*WEQn-/?B xa .ʵOǑRѐ|z6oEZ0KZY== (]WYdɞJ&-Q>zx r_x$g6y ,3?gwiٴ64c@(2uoc+lݴ?WZԬND($30npfu( [7+VV]Ꞅeyt~2W޲O\;N-EIi|VvmHhjh4J.=0hR _Ȅy+Q*@y}6}HڷC"P&_QhDuB6EobM/'V( IicrLE@PJ gl/RQ;TSx/-4 "'NF[]%lWgUK' %fll8GUT]G2X6GNZN^$ .9c%kn(*)p7EQUf̙G^0FNamwȫWɒW&|)$FQU<=e |8e*(Lf}+F SlgxRa5ѐn+`WJUP4?]HQY "3/˓UT%6hecJضi1Y ӨjN|in"e'%ZV(T Ŵlۉٶ@TE "d8b"m9ȬC 1Bud󌤇) Ho8,oJb5 HE$eㆍ^Һ(躊iNӖe913?p׍K^_YII LEQT Rmc㦍m%ZFn,Q3lݸ[Z ꔋhׄp͙uskI 6UzXyIWTVڶ핗bn{0KٶeҠ{qO-3شq3)誆BIHC8=~0 C0z0H DY A|y;>gc΂-1$sHi`sӨ;8Ir-HVf&PPBfzW^3~HTʧ_%-& 1k@[rHw94LᕑiNҒIW׎z0G j NA AVV:$Wg3k BئW7smX;hpq*SBkXGnid.bh4d'( Y{ ֮_} UQф٣p`[6i:zeH[5t~ 9A Xج=[V/n9] ޣ+!1gd `N[ ++MS4~io/'mZnYlp’ˎOqw&Pm)QPIUTMU5 8Cx~lش!&/7QzuΦz!ȨwK~##.˖/Pf}ժEZZifvfyիQNmOrYqg`,;r5u( 1p\U9H^8!-#A"CZz/:JƇ"٨FfVjz5"9yqԴ\rr0w7:BJ Y ']wf5|IQ ެ:׬;,vPZ67< ]̘駞B˖U-GPo'Hp,G۞:\s-]:lZW&qțPҪ"DvF302ymFV^=D(ZjyCTWF^%ӊsz}W&#U[ f䍷2[B#zuzt&jԐkNד ## //fΐK.gĞ CF^\vl.boO.b=cfd"UBGs΢ZF,WNQfC< P5-iHWeUUu#[{%44F zF.Y99N3 ?Y`czz"г2*W~2iH)9<,Kq3?MZ5^3>ȍݥ*Y &gT'JM>'^ǘd Ϥ I p7.scQT':2a\t ?$RJ^{y^1̌ Zl?sMcs'\~ 4n|۷Iwc9笾Э =N?zg=9ԯO= 6|х2u’or #1r$]uUqᑄD !Ԭ%*?˪kk9߾_ðxw {i7hNJU2*OzUx|Zȸ'&+3͚i::wwOM@JIqqԭ' r܋g< ;"՚۷hH{-&kݖp8DNN O%llؕ<xj"=UVF;[RwEŅpUqB:P~]ccCJ X 㻑q/?+FԄqp2H` PT0tԁ SuD9y3zH|1.xIm~ظO^˲8#b皫ggP~]e4GjA 3+;vr*^>z´mm +E吝WޛFWeL֭tXF̠FZf~!3?л/y~4jzv슔/?Cn:=UdI̢mHY̆ 6{n_Qa-:ȭO)9i3tܠnEA_ؿ*Ƒ0aޤ .x׋Z*h̝gb.Gl31- Qày`] ۷dժU D۔C6%:1he5@eW b$}Z4S>K_GCxN.^u M ##ݹwf4Ao2᮸ތQoc7^!3زe ~>`т)DDQlw$77nM?1QFr3'҇bٲTIu9s}vbј>tg[&l4 H1:A|Hr IDATt*~|Jw![ǘo[n{:T_x9ݾ&nJ_WJζ߾i3go}ʤW_ˉ'2/bQhX4J̈2z-Nw?a2-w<C"*hqWdǟxudLz۲=mzݟjEqOAQa!G<5k׎|4c:}N}jD2kt=9uujBFr)ܺ4mf -W˲ xaFy6/˯L<dnfk35QL$ID㶐a‚"îD(] YB֯zS{0t`qBl'_}1O˵W_A~g]ygYiY?,0gW(v\ʂ@b 7g׻fzISݙDOAaQiמּEذWNٛ^=Nb`s)ص 46­R۶8&?5n#c"c3c#;"wxô=n2!& jר S+;of[-msxd7;#oip&{uѵsGf|k[7gUQ՗wEAgpG3Q<$ws\,z8]|1#ܘ(,_^~H1eiNR29UUЃq_ccs 镑(Ljg) cKy^Nꤟѭ3@#LrzgW7e?FA99$~h⯪Ͼ YBmKbZ&idzKIzL"e G |FӲ$2Ӹ{zpT%54gY#TƐC&im9 ry|# ӂTM㽙Ѥf&e]Q xpSܸjTE+ /ѤZI1bbQe۞:ky.'%'a'.AqB/9wKJW@ vQ9萾,'U2=i #F (.j{`N2x4!`k^T%aA+IESQLxaLd֭U6Lqʨ ?"F,J,⦔rJk)~cIۊ{uSsacO~& ƙʲA!Hh$)11=ˁ i5 (y5A@vIUAj$gmzN-Sx`dWI̲+e88 NnVxEVٱG﹓5Ŋ1"e2K[#$)_$BK]GAJRʕ/fL˶m6l Vˈ5L ڻNK#ix%UEh_No\hY4W];rsel J6JwI.#_OʫWYVݔ=΢YVkS'SUL+Ah!aJZzN4@k֒%{g=Np0"1Kg=/vۀd%ܱ+7춲}}ȿA>diCbJpw'CFw&*C9RvZ0)yJoʲ2uۯk}6y>߬?M7YB_VVɗLw?]8W.fi{i_(fEJr$SJRIIWJRx$%)II R$^)IIJmfKoߵLr*WJR3'%a%^2m'p* De#qR/RZo.2Ċn ^"O|YN%oy;wDb,]ל n8Fu+|皛axk 9KėGSӲP,%) Ù~ױt(bCgj0twyyd&Oy 0{"PU@q7ᬏ8lj @ s_ǽF v-C :BaPSHYDJRo/!=UA RT\x+Z޽Oh),Z8;MOKr! vn>O}ccx0)%cv<BN9 ?_q %]-ɶ듾x[hJ)IIJex1ބVFʘ;)"3#3>#8OMڐTH&ɫbY{=?D:mۿ6wMIJR/ND)M7Жܐ3מI@"R)IɿWRy$%)_^2UG6^='gr?]WT!M8yB` ) 2 .'`T!A #xNcy/EyO㧻@`.8Lz28 6.@l?P@7 $SKq ?gz-PD1 J0TEÌr &a(||]2 _5F&?Œ^y~ (Zo+Kw"1ep_r`%}Rw6T-;_1`A6x^p X.*@%Z| _#霽2{S2UEÑʩ/67u?coms;G3yPT))ٟw9X&38Xe6 ї`%;\YqJ4<(6'b v :yG1cزp!;- b۬}5׭cm׭y%Pc tag`_6j6mXХ _h͛Q[:r$_uHƍ^r뭨nSIb\='R(n[FtP+ǎW"4v, AW)cdwJGiB]Jf A|OpQ4ߪǟ+|P|Yĉ'N23V-HO?s!8EJvOw)ٱu+ }9ջv{/ʊw9sܙܵ YTD)SSQT`)Dc915Pzcת]t]9l`%Qf,߬Νm ˗cU.m֮nۖRR 2OߺN<='g 5{ub8b+Gڵd׭}Āc˖2gkTuzI/aB`{T.K=wG6G}Kq(O{G'#&d E "|9T.G͛{: o@WqQK㎣OsxojUKopVp->J~AAR:ef'J'rs[d{ArW^{n4UvkUroWmWGmCÎF3%AKb6ζ-޾) 4M!!<~⺔EtбѽJb(H.EI^"PU@PC h԰Yi:JPSNN%Y-m-uKmׄ?qW[Q(ўFbK0Ē~[kDDvIZH =)]v[[RJvNіb.ؾ=2]QCiw6dؒiS((2eN45L$baqbQvbΝHwrN*89_HNbɬ¬eQ칤WaWY4c1Ibj,ITQ+[EJڷ d?Q,p;][6rmw2{|إضD;^{y PTT*UՀ@D"LeVp|bk9Vj1`J_?-[:% tPYf ի3Ϝ7aoۘ6,t]cܵsT %bb"r s1,\8yy*N\5j4`Ҥge/ygٳ 3g. rJ~HYF{e^'v<.K(95PIKc᤯>eaˠŗ3tkH9(bp9ЀɓТxKBw݅yd}C9xXf;M7 z8묇پ~ڷ9FϞX :X,F߾?PēOv/Vӻ@\0d$i{Ql LӡJtR#;pwȷ^KGСCmz !0vw8k׿̡eLzhݺ5_#Z$s;+_p%toߊCٓ>)I[XyX08i`KEE4JIaDEN(aeV$9l⫯0aBo-t2Wp28q1иߩZ!^}FaeY0~y7!J6DYj6ӈF{s1b/K/}3!9_W, xxZz׮䓗K:;^abvlVmuu`(]DQ3<=1?^UWl.0@NCyxSY Tt%0ԨUY!ld9֬GIX5EUJ԰&iy' IDATJ0Й:u2oLɛS_rL=:Yƌ(gZeѳ~08e7欳(1#(ʜK./y~ZCyv ,JZ yy=v>P(T:_<)$ߺ(Bʙ4mM ck|1_440 _:( xwd;EuZ ˟,A4TKb6aQTd0>@vBRR!yQ,[_/k\g+qS>X7xl$!%H,}ss \|qo?~s#w^wI.G.Cׯ\qyurlIgܟ<^x-nĴi3hxbҶmW.r|rssyEun]w( $111(j,Xݨ1)1j6Ub`A#1KkMDz1+ Ysi9kzF+cG$ns_ƍkٺu+۷kwn塬Y?'|ЬY;CrD8 z ߮ivm'޳pUKžXuVڵN>aY~SǧY37\m9{$sLgs7[N|Ϳi#4_Q 27/qc87/矆f͚+<<0#CKzjdeAVf:]P?[D^razpvvg _mj 7={*T$~I:͕UV \NLax*99o{wps۟sPncL:gg'.\O ^z] 137׬=_oԒիQ*m۷Td aciժ ;v|Ȭ_ka'3SW}47D ;Ć [޾1?|O;Wڵu *rr9sSNmqVv?ӧ?9s&O>s;v {borC ƌĺukP*+kWd[ctJD39 y)LN,=z ;;;s8t(;vOhzZZhAl}r -B-_N4ןzINNF'gqL0h`s [ʕaMVV6xYb...xyyԩSG!I[[P,dQ[>.\MMXr˗ɩHJzo_~9sƏƍsUuG:/_A טqS/-- IR8p0rRRiV*լZΊ+qpp˫܀z} *j*evTff`xtt4V":˟.l, 's} ˗d\pIҥ ,s ضmM41;BV}a'ӓ`lقFϏX^z;v=  >Y={699iB5)>_jbV+/^… |'b ?J*q 8&&Yf>Sʔ) 0#Gr5WNjj8n]ښwYXX`iiYxdY~8q7n`nnԩS|ebTI¢bE6~NcҋV3 AՋ~ `???*T0|pINNfƍ2r|W^7?YiѢ:<|G9jHNN}:t{{{O~zn4 ѷo_pssCN˖-sk;s8p j FiΜ9C.]qo )3uTRRRXn;vs 5]2sL"##gggSNͷΟ~={(;B X[[@&M=y$ܻw#GbeeŨQ~:8;;0o<N8~ˉ~}}ރ=jj" }風z$қAѐi:ED\EG]99ZZgHϧ_aEJ2Kӏic@?NӦM9r={Ņ:`ooϡCpuueȐ!ܽ{o?~<۷篿͛899>OLLdqBB-Zܺu-[ҴiS^/;w"IgΜ)㱳Ņkז>ZDI0'O %%];l߾I/߯ ذi3>;tS0+$p-{"F{% BqE\\\HHHٳh4={@y뭷HLLdӦMEnO>TV}:nnnp|uydtºucҥOݻwsϬX"2e |VVV:qDq>uBa{E׮]K|~Nj6l~N7[T8QP(P*U*5*YcmcR\Z_*bŊXZZҦMY~=* 33"׮];hҤ m۶رcTV-{!Cq:::HPPW^yaܸqȲLpp0:kkk"##bŊ޽X:t(߿ Ҙ2e cƌAӱ+nILLDT-^uQeΝ=z&MqFN>Mll,z_GbŊ3eΟ?ϨQ;P`OPPcSo={l2q>7o/bkk˵kسg k׮܆o򆜜l~9'_o@OO=^kkk+KC\fGK!ЄF#_?SNr<w#ܹs!((^z1w\JKKСCx{{ I# xYqF~wQEDD V+R_5k 2WG8\]]qww>icĈ7U K^"7h}lmmaÆ2m߿i)(%B$*T0HY22RTiqݹ;HTZ'*U^R숎Ύ$ԩ_u,X5/_ΎMX_ƍݻ7Ge5kF6mySŇ'O_E֭ٿ? 4w,O:t9.XC,?$440lll ܹsm۶I入%FfVpww`޽_ѯarҥKYx1˖-c˖-,X\VOPxn=)zytZzݓ>x(QJ*Rz T %jRZDPJ,#O--zѧO[U,U9f<4昐&qIZha: (p6G 31ZQ(@Qܺ!hy)DT(t ϘŃ?cBBDRjր]V!MGƢRqumj;j$- -55wNȁIPU4s/!A:.7YIt^>UKeqq2&=OJJ iix6;WTʦZIhӺ5Js (-*p O9( wү@AT=(L۷ٹs u^8::?LT&M3hT{bas!K ⓾}s?_:%P(Qd%ѨaШoYq`mm{w$j_˒tQE1.\`ڵEN .k4hjǒ%K$22Dbbbذa(Їw^tT|J=ؽ{7gϞeȐ!,^VZٷo-[ :B`۶mlڴhڶm|DFFo߾|w?н{wt:+C^vJBa}u[:q@N;xkFE:S&yZ#@2֣6y= W..²R(b/l$ì,AZ… 4iYx"˖-RJ۷ڶm˩Spss#'';v@={)S߲alllطo_ǻgC4R۫^z4T*uxzyy婗#XYY 9Ʋ`AS"ZN R~M\S}^ߦK.ܸq# <"""ͭHWXX...E꼌~^RT 6ի }VG6ܽ{;wQub V\ j:u_yWNFx7`ժUj̝;w^KfJ/ˆɪI";U˿k~I *5kѮMkf~9sp$*TN77QaB:/___Jձ:F>|D:4O̙3sիW'&&Fɲ̱cԩ={D$FťK>|8Ge?~:uPredYĉ3N<)]fdd͎;(T7f <ӧ '53www kˋ:pܹ6Ϗ+Wi+M[rl ɸѣ =y$IK_zChe g":=}?Ml"=ʡCPTw^8Xt)Νח@bĉ\pA>PTl߾]}ٙP]Ftt4;ww,ݻ\,9|:'r%!qPPj]v:H8L4^{MLyCrRAsgcfnuB]Wc5I"Aa &zɓĠ.YfȲaB1W_Bhh(իWƍP*NFMҦM~Gf͚ő#G۷/v"..Py OOOg-]TqժUSŋ??gϞ~`Oe$UVm 222݈ʆ,И>LK}R/>{NXXNNNuV1Jh6ϯ[KRV-n޼)oҤ{"2qqqԭ[Bٳ9x CE=Dz=7&..NZ uW_akkիWٺu+K.FŸ n!.s}6ׯ/'L@HH׮]+0jWo(݋^,}3F2M^NbܸqB?r ΝO?חzꉾ}&L 0a Lj#rJ@>.]B;M2wB 1z=1k׮akkK^9r$ׯ_GOw(Ņ~;ZB}:"I,ڌQ|ii㋜δn:‚.]oQff&=>>ƍ>8991p@Fĉ=z4n:d?,0Den߾ŋQF>3f(5ktψKҥKrrr=z4&Mb\zUFǣh(;x]"c177:!$S ZܾNm9s&_|*5EIu^y%>o*gE780߇3f`ffptL:|ÿb >m۶ɀð#޽;VVV :> '''t:7&33_B[MzX cС/l{Ǐ̙3l۶4^ư7ӧO3dcFFHDZSN/T駟RfMfϞmbܛXC{8Q~{`2aPgmZZ{ 3`n޼RӬ]͛7HŊ_4iBihÄ7oαcXr%ԬYp֭xPP ,^ς}08p:u"..yӼys50իHĩSزe ;vGt^ݻwGxEkbԩE6uzdr*] l , uD' СcƌԨQ_|oʕT!S8q,_0u, @Y@LL NT*-[{ЬY3{E IDAT㱱{{{^Wرh ,h׮ƍ#::[[[,,,9s&۷',, WFy3CkԪU|:Ž߿Xh LȹQ_IRT)QԘ[`niZZFmEFVVQU(U**CD%IAU6Q|1;AnVKLL0{B0ޢE ?.tB999cy;.]B$Z*...F%$0B?&-=E $$JV-_9s֕I0\7b U8Fڤ2yo$I177G]RRs!Q+ON5J 9Fr;v}Kjj 11QdUdhLh6[aTK &`yu/9bu^oH7n%iiȲ̬1j,S~Akw7|1w8YiZicoǏiӦ9r={BСC&w}?s}~7\\\prrb>}Mk.f̘A@@L6L7o1x澏ݻqrruB///^|`m>|dY5ٟHMIDm[&)ч0he_8w1ʌ}Q{E\\\HHH MRgϞFٳg[oEbb"6mz!鼎9?qqqTR0tlZz${d6x]s2@ r6wv k+9evE{ؗZS</N+++q#XZZҦMQT.꼦L$I? h.^4ћ1ĥ%Y5sW._D޾ t:ZaѢΡs4n9''wIRT!HEoS|X3W(@dypA|}} T"OQT^u^ǎCVy|}}%((̙ٳ۟Zeģ:'NT*+22ˈs2w"Y~}.\ӞÇiذ!$;`ooϮ]8</^|%8FzI2tXL6ȍFwRUt"Ƃ>""  2QQQmۖ,B[m|(:uM6R/#Bu֯_Oll,nnnH駟hܸyURE&Mt^ 6 Zm>իV~M5''{Gtt45k?ydlmmݻ7Fbܸqy>|ȁD#F0m4kEcZWWrq}~O7y4(5)m#::;;;1N:xzz:`hmm˗\ejԨq˖-Yaoo֭[wѨQ#֮]iԨQ~^5j(`GW_ѡC3f 'Ndȑ+ ѣG277jנAvz"33S}:ӧO,1&D^/,,e'eZn.&OOOV???:ĪU8z(?H!::k[`}ÇGebccFPnbߥKr 5 6#Gd„ B5vX&L@Æ WV~߿m\|*/T,Uׯ_bܾ}wwwZl 9s8p j F#jNF9s.]p Eo)(ܹsz燕Fի < Fs޽PjzUVٙ~.璒Q,^: T %*IRDPV(P)UUEPT< ~O/}233!++{QreI1xQ~^"Unq%Hg}V*RD#f`ei[sLK 7=H0R9y+z}4 Ȳl".<5wNH5f(-AUgOѱ9 6`jd֯]5 %xlqxշuܻw׋'M͛7iҤ nnn_N#͚5c"jѢjzv܉$I9sD߿?vvv4mڔ{!駟ӄ2D\R@RQBE͝m#gj[o2f$Xr.e}ݻw#VʧgUN8xyر}k&==k͚5d6m `|̚5XQaBfNFjj*'OBc3P:Q!˒ nILXvr㛾qFocy<u^[l:XE_cǎѳg3fϞ->WF V[\\xkԨQܺu5kһwoƍǝ;whذrrrO:EPPP0Y;(cF(=v1ރ='M ߝ?DTt ,3b8[QchظҥtZ]?n[eq}}}}yM0ׯ3aO"""V[F; GGG\]]E\ڵk-$$͛7 GܹsTV͛ 5cƌʕ+  4/^zljj*nnn( jժ;w̙3ۿ>|8/_B4m>o)\)^9 ҭY`7c?GСCT*ٻw/ n ^^^,]sK`` xyy1qD.\ Rؾ}{=%A>}pvvf…\~(:v̙3C`рQ6Njz!eߟDaZfΝqHNNӴiӆ?_;v]y'y g{r}6Ǐ#RyUT$%(@)^+mlܸ1-hgAƍm}6/&22Fɓ'/oc͚5EgҥKҥ 999=I&1zhѷߟQFٷQ3t4nܘL~W nzilq0¶7~xΜ9ömHKKO>zZnͼy8}4C /(:fdd$IBթS'Ν;GÆ _[[[S+<7xW!&lAFRJR^z(jĿ7ԵW){Wј4iBipB:t ^OHHy;v+WM͚5  :nݺ`yCj8x III8pN:Ǽyi޼9 &CשSزe ;vGHN81%?=zw<>>߿? ?7=ʼ~  I~&?RBLL NT*-[5? f͚ >>>sU 輌7ǎzk׮ƍ#::[[[,,,9s&۷',, W^ļPxbjժEDDxlkk[?6G^%*Ae\T%fQWb%55hs9DĒp&5 a137Ccss fffT*Je.yjZQs)~^ \t IxKtΫsTR`lllL,7BJb$ \SQ[0@2@RWcg$uE$E]QUafxuJh*V4"}VF矤G]@eyUj XP?O׾}_8p III&* [V*TPIǑlH߻w߮X+V$$Tk`]}F$Hk6634*vl KB@@wߟd6n܈-#G̷z=vbryy͚5{퍃u^{+=z4*Uz:"2߿-[EժUX̋t^[laժU=+++`%yٱl2ޣUVJŪ @`[ouacmPJjZӬiS5culٟ֮߯M4aC;nJs1Že wFRPZ?y mD/^=&L ,TQoYidfeV?Ƅfϡo˄Bay0)ddd2aK";+N;T(177c_wOJ/+ΝG$z2UQެ\7߬Lg ic%k|-.^NDx6>vq6mʑ#Gٳ'...t{{{:}{NyUB7~xڷopqqɉɓ'pi6mʮ]1c3m4233i޼9|8pI_w899:!&{r#%N˴Ӑe,dYe:32pkӖy >j 6@e~=@{wT,׃$.^Dfj2zYӕʜ ŋCٳ ]IΞ=K`` {a[$&&iӦ2JW畒"~GJ*cիEU<dgLE'rTtYh3SfHA.33kh{eeJ#'#$z9|þxzz xqZYYҒ6mЧO֯_Jwwt^ja޽{HQI  ma 2:NVEբͳ:tZZVVg|.ڇtbO )߶U(mĈԩS$g/kՌ3 sL0gGIu^yO߇"2F`y+ m u|!:/^ bffN#==cǾT,/ z}h[EKYv1 d IDATc={4] jy[;wݝ;wpA\]]صkptt]vl۶zyf 'O.ƌC֭{n3J@|I>9sЧOq~ 6,gPjB~IB+J- ˣM8JSZfkÆ DGG닃C @XXk׮`tDV\xHHHy 0A޽z{%~6lȑ#!== g|}}y뭷%((zٵk7o?,>}Ç-Z$ڦW.|A|޶{n9[ܹs]zѮ]; ƍ_We6m bҥTV홢c E!I666DFFbeeŊ+ؽ{71118::2tPٿ?1e~ƌNZׯObb"*ӢȲ̊+x+Wm۶}7 2kkk͛WI&oߞ+VPR%݋))),_ӧO &1e>sh޼y?e4 ~~~ԯ_X<<|8.\`ԯ_cǎfXCWf͚T;i$MF\\mڴ!''F#߿֯_oMUvЯ_?ڵkի9uT?B۷o_pssCN˖-C!z888ЪU+4C3gХKnܸA``}7%e43f΀*$$3g0eٺu+gÃի5/۷ׯ_SNѳgOk3FKEZjiӆaÆЦMVZETTUV4iD JL0J ؐŽ{\餘D<륉L:̗f͚% &/LiзorasN$I̙3ϴwwwn߾qqqW^:[VZdO2l۶m:_o&P.K3mڴ|Af6lyj߾=`y5V={G%Jyedd`[ E͚5 ښ>iӦsNn޼YB߾}VQQQB$u^'O$,,Zj~ٴQPN̥q#2t: bccK2$ڵkWKVccc… y=ڵk:/#UR%m &;*oظq' !""^Oxxx:/YYzu:/WWWA$IO>!** //Bu^O72|plll^:~w B}M0<^QGu^7o6 /y;8;;>}&׳鼎9Bͱ?7ݙ&<&W)2$0I72St?ڵEW/ˈC&P.ɓSvmaRay\|݆L0(ٴ1Tay= ?KL&"2g͚5eDnܸLNNNzeR27~&.7y7ݏIl:/Yɉߦ;ӄK^G  ݏI~^#Ggm E*%t^&&C1&t^&`JpwwgoWCGΝM_ 囼Cǎ˅TL:gy?mfLx*ٴZj̘13grĉ2"M:gy#IaaaDGGbB2O٥(ӑ׌3de1鼞M5f.\իWرAZ5 Bz8V֖\rU"Y򊊊"==L.]T/"t^.\@Tbff&ׄP DT(P*В$d_ʊmRvmZmϟȑ#yׄ+99777BCCqww'+55VZ Ta:~yuؑƍWzy;vPWJâE ϨXpvvESNg}Ƙ1cڻw/ޙIQ]{{oU0!Ƨ>*#T@x*Yd A $bQaM/BAi\Pdu}ݳ TU>UsMAƒ$/!ソUd%(/2y޵Bpj FePTqrdgm:J5:0:/:K`ūdoN(pk5Z{stIUcRcY6ʁp8LyY1xQcA5`|KRPPM [U,fňG$1N,J!юr8NljIx$ЎKxD~* cD݄p%f͚EQQ|IΫ:/Oĉ())a_N;TA(ϻB,"!E8+P(D(²@cYm{\Cr +& a{[("dmܼZ+Rhf *2zX;ס鼤i s| B,X [Ҳ8RɺINN63z۴!hGޒ^] ō70|D!{ݜr{󮡐2o8JƯOt^Q^^ΪUZ׋Q7@J zZ f۶,Y<0WtڝJK G"8s۳/xh+qh36mGpbQxx Fuh:M2i$>6nHF4iRoQKq 5ߔrH$vQ)PG.H'Mdn+/Wp c;/O |\c…l۶-fϞRYfUZSTTTΫsA:sԆKA~Xr%kȐ!ڗ}"50ͯ6/ GRZ i Z^#=ž;kjF?ml׮\2oBSyۚ5kƎ;LNϧgϞi GyyKLW^D5EĘ[ҪnҌ{ QJgNOQ;et^2 f9Xv %g4g4+?Z/}#<\8\ޓFuat^5A>9H!=tqhV&>΁5:e TŋӦMx) 2z^/2:t믿~7lذ w49 xlSL(a<0N:G|^ ?6V=)ϣ7Q8v66ڎ_f,yZqQRR)R/nD˿k֬qx۶Yhݺu`Νz سgcƌ̀h߾ݻwlL2['~)SLG^`5Z6>$t۹iذ!ӦMcÆ0v8v͢E4ŋ+uӗo߾kמn]|5kлw/|Irrr9sзoߴѣivڶ)ݵ}{eߞ]&9UU3}t^~'މUػ;vEÆ ċb `ɮ&cʔɌu(Su`)P{''OMRjۇNJ iAR8#W2}BbI ;db+rXjD؊KRE|>nJ)跧P},Bw9nOKJWH>9.F+{?~U R Ak/wqEp 7H_o Jqh _p+.H Ok)>1wcd޽a|4(C 7jr^dzt-:fNvN<"ɝx(呖2>5 =76m?ӛߞTcjєvTYBj\0>SRG_ܩ>gOt)\FJ".+wnZL9+8X w–=ZEZFTIէ9҃0~NQZ#0,5ԀQ[u3R::'A |πA줏]{&"aA+Ibڍ=oҘ!/C^ <@U-$R(,!PpAzQ~cn-M*A@˲T6)Jxe'1ےV؛p+!!/( ()|9` 'ҽ{qh- %-ъ{^Pu^WU,05003H~p"NV?KZ6"$pm400KJT"z^RJ,^%C^uNb"v!4i !!d/ s ] 21B}Akc!/̸>,Ť$;ԩ] ydo項Ng^.?v'!/ܞ-mA+Ǩ3wJ)Q~=/%Ox=3a!/r4[>+eXnw˻Ps. 2~ɨ-U 8P-HyAR KOea!!)A9@m<h.5=b Sb$Ao(/G"qqCPbC WGhؔy0vnR$6&Wwᴋ!/LtɥqH$& 2Z)721[S RJJԷvHzRJ,BZK`~!H!]H鑗F+8 Jv>~2KJ*x\mcBnUM᥮)ʡ<} )QkMVn#֞2#0'S'?H;eҥsG^r]y2lkn.܍aŽ4d݅yw,_gfΦcB" t er bYf_.f Ì} oC}} K/5WǛw/^]_ۋ>4O֡C(_\ח7¶m`&LL#0¤iֲ e/n獿,gݺ4xc\,Jaqq!Jӭ'~uF ɍO>M22%`n ,zez]ߗgKէ/99鏂slҲ}}',}Kz\쒹w4e`P+Ron綤lϷ4n|29ǝ@h}oƸgXfeÏѬEzg) %n} 71W2oiǾ̛e`gZ3t`wʆ 24ÿ}t3qGm7 tv$⼷}q0cP do/t5]^t%ueWн[#/t9wXFIDATc"̞^`!/WRs޽8sسcǟH.h*ۿmkђ.=vV\ԃ'.fs]ŐAkݲ,81K$ ^ɥAGYO:˲]RUKqKUQJH8B"D²,*52Iz$x\9tw KYP׫AÏnB.AZV`.5[rVJ%0w'ޚ_V'^P$u9cEP:e!I"Y.&aƔAFKzt;c hעIڳe[sw8k# ׬JKݒUHi\sY3_ΫG6qޯ+%q(].mBߡMTLr^L5i+Pdzn3 gϣ ޾ÁY4S6T]ȮƭWRv8ȲiZ֫`n~~| Ca]HDUл+`δ/q9X(XCɧUhx~6&ca!}66G<5yF܍ HL 8|$?ob2m3Sqnm/i*Dq8L4y՘z W3p;Г{z~ v1-Ϋyk Kzm=Z_1k$K`~jARݺ,}!.35kJ0eӉPb@$GN$+9୽IK5[_""& _@N~>a2ɗqDTعh+ V̢LNP L$\]S?pqX}4EnK˛R#}zF25*ᬯ(#&v:qgԪ@5jQ{Y^1Ax;S"ܲ,\״3]A@iyA&~<bXu_\޽#,U3, buOp9p{,nOXcBgXj) $_رc ne1$TL8$YFeT5D .j(2Y) k_ב_D|l܋$\ a{^#'7q#-sB @͉|E U'as+(D$z1c?ɤҧY]7p(2gz~~έewz^0D(eAU¾|1fq;Ud0PNdYAI5[q=~^}cQ4>R}ԩ\Avv6s33ii1%QyB$Ƀ(qe 2aoYHl+-]'{zI" VƑD(7#",#;dY4B($:~XLfZDT I`7:6F:e$QBFQ(aruq(2ZTG7L""Je`S:,8\lɕMiq^Mƾ=۷RZ aٵg/+s{b ϩssIJ|WNQش }^Upy5ٖIMt0ȊvXf+ ,#%Bl\\69yܳmӭׯ.+_JUl<@)CamiVZ-˶gaY1e`6ikx@05 =ٓO""oJ=~fO>gTUĢ-2OjVJ G^Q[8d~;6R.5~C-p(rxR3%xdI1TlJU-j 8p(~)L qNzTp[l߳~9\TL`)WkU0'e۳lڼÚqTvdZ*۰+2ULBRHzmGT @LZ|խի0*\~^eaW˗#2gp`vr_~%rxgn& b!\Oz4UEǬQخ5 {HXn,6Ǒ46 saj,mĿEa}ܬwNy k EdE|HQE?!llJSU"EMTM66K>_?orBbVSfR+GtIu|Ola6nMBb*&/uj׶%cc") ǍAJT UjBS #sY:<[266! IH*w#>`f|R)YɢN[X6gĥ\zzjep*I|zQAz),,$!!)©= /Dzx;N4M;eœy&$$ eE%, "ipr0MP((Ht޻$I8FFۅEbZ,g=Yɋ/%ؽ1l('U'\ v:|inߑ[]A(Qe |1QN_z9W;reW+ FQgs(W\^.^)^O1`(y4f|*hjvDp8jZm;7YO<53.rQ$%{_n}nQE+K=we<:bEPDf\h8G.}w.ﹳ>/f_D"0e{УQ7w3YdIxU_˅ $}xi߮-(a&z9X,̞3M8S>Dev>~cƴO<ٳw/ F;u^㍷ATUe/eO?FL6E4}}6n|\}%I:S).&ۯWO$Itq|q{M̘5RbYH7~EQq#]n;^+מ{< ̚3L*Y2KO")1:_5]:s@YYeoM SR%^|Z^|I 7_ {O=طo??,csw2nY#,i!scǑĘ1PRS[.'yw$Rf a09z\ѶujӭG/*V+')5qM`Y,YYY< dddpםXwL}׮[Wի~$sA֩E äb|{3XrqYnWaOKG, Znf0d2_Y ߯g|r6m$̚ ,1cN,^|Yw7t`֬n4l#GaYG+~OQ#g;ougERF&KgvdTՉe \tѲL[:ЮIF<2l(eiǬi`M,1BW}J߹i }~A Yhܨ!1/=ڃZkS<ڲ,5wCZh޼)zUA3R2&/!ٳnWƒÃ f帊ڧBS5yQlظ ˲u}#>ڽŅȲC"==_Wƾa%qC C\b{^{\}["^eqCR2Ά ٺm[{@0 =C/NTq\4lr!۷ Ov!'|:]A4yhtzm vzu⋗b"m~{ԯ~ /ƏZu/ fҋ5qWߍá+(W>$zΘ7śoEϞٿ2ܷԺ=9~;͛ϣB|,i'aƌ y8q &!*uYs;\j&O X"n}fu[g˖syLޓ~ Cw(Ejj*i KRH+sd&SBmNՑd+[4K'c.5meiK~'O ]~+ݸ\.GNo 6Ӭ*&NȊ0a=r|+0my??t_9s2l؋QANEq'DRR99iYӘjp=hp~zh gѢK)_ ,ԯ{ҽLfϾ5kspyvMZ;8'2mZ/zzV4| ?̙ӕ>}>⋗b|ӑC2X5CB˖K2%q4?AMH" 5ύېQ9N/f_XHty>𤮢cP80RW,b]݇m۶o쨜'Cc;&L~7߼'׳kWM.{ԩt-総ѿ;LޓBu~x4ѨB&9MlXu r 3gv?iƎ}'2vÇ~f4k 3zkQ.fwߵw590II6k=fbŅ20zAt*U|yt{F;ڲx>S^{@c/E_y:^Z*#""@xMYq\K]fi&n;jIIN)~ ^$Xr/(p(2PEQb#4ʲPÁe(J,iʦク---=~˸Yr#{0J |53|UZ_J|9~uC \oѶ -dn;0 N#>H@|^ >hZ˯fUc͛7՝0M q3)0HӴJqG%~z]KM,,h4J48yckiMڞn_i9رTDmU àZ*慅؜뮛M|ո"J>\I2xGP e۶<# "mI'mEM_Z1l؋\z"+/oAŊYU|ks:Sfڴ^4h+c yeqʕͩ]{ W?k2?~͛ Z?^:9mobiYMf֬nTÐxѼP;o3uf]eAk~=Xq!-Z,MH#3a= 8]s:stJ}[&MVfM>e 吓F 9t('|'xꘁi;}ȲMx\xShѥ\rb~2ڷO۶3ujo|;|?_\C._Ư̬A͚0Ɵ'oC 5{(wn %sϔ={ѧ'K2eMԲ|Gx}Ihci>ӉWp&Ձ Ej{3UdqoMMA1 _ #2'./DeP[>6gɂŕ>Շmc?Ygw 3)ϦGޏnOLYy@;weuUK#w>nVdVn]VRe1h zEVg>?a„&W^y;w2n8Ly衇t4jԈA!IC%''<㤥#8pj1b9ڵk裏__P#GdϞ=we^{5ʕ+SO=Ž yܹ3}~MΝ;8p +W`0ȳ>?7B̝;knb͚5_M΃ boڴ)huW^UmuK둙Y%޽py}ۚիٷo?UT)ڵksWrfϞ @.]ؿ? 6dʔ)XO>Z ˢE?~< W^ԩoHIIA4} 2uofӦM۴iù瞋a]KZÇӧO222x' (Mv]EtBBBA֮]5\Sؚ5kJ}g=ۨQY&}ᥗ^::Kt=>f͚u]<@l7uF8rx<n ĉD"]Ub>n6nȊuK,I&4nܘѣGYfRZ5.\eYHVD",_תJ W?3eQNRRRXzu?>3nܸǏl޼?iB4ٕ&=vkKg޼y\tEgH@r~#GOp2M4UVQJƍILLhmt\8eMQx fn)beP uM2ӏy٣My2]+gUS=:w#Grҵ;7o(|' cRV-f*|hr-zeJ:5]וO>z)Kn!Io=^7e/p8xtfY9|8Zݘ= \N']_w;'//ZhblٲAv㝖wBg~)'Nǯ>}:_~%y70al߾ɓ'k׮e̙|~RRR48 48ϓO @Qf̘qF׶k׎Zja&˗g,Z;#a<$aP|yrIIMɧ|z:?4۶oU&'CPj/^̴ixwPU={N$֬YGnG,ӻ={tS(Ž;>S}> ɇTV>!;'{N{CC0SwgX";,;^l=zR [nA[lN)jEYn`ݺuxŸAr8r-Z@UU֮]!]iff͞c|֭߈az ZlKYa#}0Ƽ0 Ç݄~^e]?wnٲ 60uB?Y3>VtڵD8b&&U*WgRϨV*۶3o,vS?aEXO>NjUiyٕ| /1)T\F=]BnY񚦱hZ_yEj{' a}*t2`mƂ gOvUG|vQP̚,Ӯ];ظq L$}sZn[ٗw6lia&ݯ5kcFӶC'bv~?v+WdȐ!+ >]Ϝ9sʔ7ŒYp8tQ-{6A  !I"k;u E]H>7]s8;&%9 5o)!ύ:++7cva4g2I͡C8tY-Q4o4ڷ#!@ZZML$O /5*@ĒILLd%z+zkqXE0B%L" ÷__s*1\>= +1<E`0a%Qp66PNt:L|{t Ĩ?Q NJ4_eh1a%W 'T*-k[{/<$_Y-g"ccS8{z`O+sޱԪYL6lJgԮYızuf*L;vn:e[4?+=2kʝen+Ud,fNZk֠rJ%UZ}bժ2'uǿ[Zml Y PZ@*t[͙Pڜ'j+?BRӣ讶2Ô6Gi]me`c/AxhT#W Mdgg3{|%0qx%vl߁ݷ&ۓFE!Cp-%z8|0@O?w}s0lܸe˖~z^~e>̓O>I-{ٳs饗rM7A&MQq-ˊxٺu+se\~4i҄~QjU=\:ѣyb[66LˌBv9]>&=-$>C6mL xq( ֭)1qÑSF-=ZI[}\rlܸ\dYf̝;3yx ФI6m϶|@߾}q:9uRbEƌSaYyyyXzꑙIjՀߣĶi̙3ر#?'NmKFzB,S$IDZ4J . fذq#nZa\ӹqQK)p`," bYVT\$I"2x`^֭KKG$7t2zr۷/=KgjԨ5ѹsgrrr}:DӴ)SUUEuڵkNj/HZZZ܊+ү_?8!C3f ڵnݺ-AȠO>\wu3sS\; `РA|'| >yuȧ7o̸q>|ISgnoW=E`ccs&QK۵kGvlA%Jj+?LYZjszV666gM!ը62(XG42,380Cأ7[zo:o]IxO V[Y >ȞφqJ oZ58$'e yRY# n?-ꄉ9'l)25uS9` `?6662_Fn#W`2$DI2$m.`m CSGQfs"5<]5|dO~8Å@u! Q!J8FrzpJ*"Q(2,5L3j9 NƑ)QD h6QS\HN`D&U(8uAj&N R<~Q73AKb^Bؖ}S㠖[ ' ,vHV<4/箂n ZWe:;ݬ]628{)6o,!eR5)d&zRpTLMNa>WQIP@X!0`QNDXV]7"J>8$d UWp)*% ""BtUD1sd/ R RK "dQBp$ 9(qQ7Dہ@8* B3\HQJ~4!#hDzw^sm-'83!EEWe:;ݬ]62c`m?U(#!77V"ȱYaP2h>! #] |IC$;Xto.~AtD\Z␢8%܀Ԅ(`[$i°d&`Yi4s' ,,T݉׭AĴdbC(nNrR}A,BBPT%_gGx@՞'PͻT,Teeec+3B'h=C^pJ52J >AS0Q $: 9iCE54 Ǔϑ4LEKvUD$; ݄`xdq\J c nd?%GQuI%qBCR [x|tݍ@X4Kq~"@%I$ݛ[ 21BdҽydSDBQ^Qn$%']#ZgCۖ $mjԭHHKFhV˲HIN=LQ҂-e[28k8@\7j.$M܅Ȋ+tUN0͘Ʋ )ʼna8% Uw-E*&bZ%  I2Z"R,cY"#?J'4/  u/zE~j+7'}gB#dPLr5DX8ep|蚁)p T݅"i$ +?d 0 $":uU'"ra<ܓzS?9_Ä'iY 4M,0 4MGno8t0/sf~ΤwDcOLRoFeZ3`*h┣X`XBtl@@D̤ؒKA uY"%BqHHQu'$":|z.ew0$ru"X"UFIq`Y.E,t Xp"%CVqIa,[V 0^#fx䇓0Z4)i BL ݅EHдس EJD)E nh$ ,˜~'΂9ڳsa&@%;B9 C#QQ"GβG瞡m+ BǝcLgYeųb6LfC%u^Ir.!$?%G5,g%\R6EnЅ$Y8eDUw&N),KEKD-j"´dEA,@E x _" 8(]}$(bW EIr1؊ hnV4Dg5*z0 *ؼB*P 'h,:`Y&zb#PKD]S#2>wdS Jӏe >DLt@,B!$_ѩ9` KQ-9 z97~]*0Hvx(dKah;ޔJDmCEơHRH:u2 HDESl(](+v8aseUVeRH7qXJEF!HM7N\RIq&$ďaI(ROQ-Ė&(8EB}F8 BDu/.9ꐐ%hcMdHfJ"&D3\C.~Q'a,A늒L   dhXȊW8  yXID#-_M _O%cs VpJ`ŬE\N ymW}Yky;f?6$@FBRD!JTꎺQtVuTR& C'daxA_RЎ/lj˘"ML*"bHm,e{]^ƫ^u'i)x`&ۯiF|d/qħ>oa|sOc8WzSi+&ME]d\VXNRݱR75EQU ~2nAq=K`5yEVc~Vӷ*FKW#$" 8eFZ,xaTLQ[DbS̯sBk S9 u46,, 55'7%Jv/K+ G% 0c}FX k IDAT9-QI4c! ŔQ\1NﰔfY]/W:n]5 ?0pZYiyʱq@IZ)I`3AjA)t1UR@@QԴ=EZ8FNQTfXYJ \d5b8uFUH")<_&( R8rH3LF!U&YZOje˱1絑x:%L|_=7 4ZIL=oJaX:Ŵt))mN,kc)5{Igٗw (F!8%|c öI)qM_N@uQ:ybyѦ[ŌT59k뇹뮻l(ws]d\7+<\ L |$,,)IPϕ~fv1Ah!%$Ee teABئrS)JQA'6i;Ym% $A{ÌT˂LB%)k(3³\bmŨ`0vDÔ8DJ._ZRah$,G^Zq( .i#+iµR4BJy o9sady"E$W.:Q&5RF.F@\*qyk#Hg[!]86|d: 3_byi\[x8).m`낼r^N2$*۷Z%ںcuUtAn],[zJMň`8ʊ%Y.YemgLzH]0)!N;KR`8c0ZKb$٢#\-- ءK~BX*qNF^xiheM]e4b)a!U0M]&+iKٿ8ǸӠk=m*!_s3^*UK @)QU7,Bw ^_fv 5zńi`ߍa-DNMYh@K0T"|"X%\|*[ڦi) B+v` Ңu%5=*l&2"&{FU7#-<aY(LAgTZ-7;uN2IgR$NʨyԽLӲgԵƭ blQݢ,9ViBH ]F3&8*ģIBKSRsOAtMa@u"/5Ym6ͳ*/MI+^T^@2O|_ė#BIND֊v\f1K DcxϠjd$Wӷ݅)^xL,B0(~QKj8|c/>syƏ='w152x4`z xϰC5%mO4G`ӒTYi$AJVtJI!I [m22VG+dITE plMe,-58fN\(ʂlT&z>I,J-:Ni ʲ$JС5yeR<4y>Zkuַm ?y_G>L"z>ob|ɧz]^ض<Y ]R\|5!},( #jd{(h7c'ZÕSfT Qg>Qҍ؊bpqݔ8. M^q \<]i"G*ܢciʱaZORUeQ5eYbYir]ob0 sк_kz#VS]qL$ C}vww9|:}(fiO' 9rx<E&Qw≘$*mLӤT}T"`g8]Sd䵍Y ,Ll0ʌl|z閿JB/٦{#Y-ˣhYb1BbsXsxNj|ILruB',/y;/y6&3|V/SF Hj"N)WY,'L־u|gO~nT&}/7߾ș3|S|8LS~g׭Otu|9dO??o;?S?[5!ğ>7pK>^d`m>IV2T]7B -t 6-.Anc2iub܎eNVArEu"tBYiaDCCImIOӷVˆL!>h+WTbdT]dɘ=0fÅ+IFgE3KN[JP aA;.c&/!A, [4M,|2:wZ@ckaey7|O~y6n__̙3o~wEA1RJVV]*Rr>ȓO={xM7]#Gx0 1ra(QO䵍c|* Y\3i;r Ip 裏9ySUiR5Ajz*eӧYwHXYY!cZ Rr)ʺ tF()I^m`y},˨[_ L))ʒ5l&I0M<Ϲz*Oe@+D!&iLaJԔgcx>E4쒸)bYXeN\wH>6 jZOʇ>M{)jid3I1-6D~l*QW- /PoHx*&bZ!9 k4n`~~뮻wO$w}w_}dф .+8Ccuev^$ . 8""m<3@8JqE"R.q$`YVM+%n%d.=w2:Ru3-Xԩ눢mc|'"666;B֕6/_}V˗f3r0-Kʺf/c) 5l"ǶBV5SW)t-1ai=ѡ#$L3FeAQ9abs6%bwLAVvvu]'?nwy^ʤ eYRwռ'& #nl6x_җ_ewwz ˲x;oo}]x~u];oh4[&ݺR<xӛ~D6#x ]Һ&U.J7*=ڗԧ(#,UQU!R {eh]NǼG~!EQOEQ߰ji}{scs!,+1jK)"/4Fʲd:yeҪY J~$yRxo|~}hkd6/|E2hu1S=jLV:\[\iQХ ;XwXťK8va{!+ ˗ioo3϶yJkZE_}w;;Ν7U!TBXy xǍt>jH`Xh[4qC,AC,5@_4'w~9*|/Widȇk_}FwōOs"D1a!B:LҌ~G"\r!0H0(5B'd(KְK`.ql烨KgǶTSVq|25tjSmbUc!%m?ӧy-7q`L;`< X_?( hD)J`rM'+.e_#͗в`w'" >zJ RLh*_P@:~D~eoW-۾?S[?O;@,~mc =52v>v ,Ǥ޼,2) 6V:;1 ȈC pE)d2jqYn*ÀѿKVCJI= mn^UxL׶Y\Z"2s[[[dYs_;{ o@>aƋ}@&# 9+B7VlmQa5Xi<ٶia4rP^oL͇bX6WYXX* NSrYKeAxv* ڡcl2ΖlDQȪ%>+A+8Wse3Y/|*%"LJ~g92 1ꔺ4; bb d| v1H:PX : Rzak3'; r%faY]X]}et3ڼ* {0dt85&kJ;,aZoR4MSj }=~ǻFn`ۊJK$ acZy>af)RiDʊhMzlGNIY C"+ VbYc&ω= a\8 (w.\\= @O>ūWy}Q% 捅PC7R18 ؠ!}VC&~#t$s <ͩZb!ٌ td0P'N[o^/;˘5$!+},ApYNp@ͺyN>,>hH(&HGeE.-06(6\\8;szH2*2\&|Qu2zBPf$`eS%V:vl`ym|=Ar kd  ZT(32 1$‘ shcvx848,4jxG}y`n2 G!)9뺼}<_*GSn* vD/2WM\`y`n4V}l[m l^#͸'I߀wJl FJhsϴyNvsw͜dяR|xMpXш^M4+qLMQX$b]ܰr+aϣYuK W V\6&%*R{TY6,1O_feͫ_s)vH7e|e*mA*ܞ,(9cjʪb]d;n%!.#tf}^/gK- Lw&-GKS䳈Զi,],aĥZtS{S\d4ޙy,?!Եv ILZNHdXFqS{AEiHLQ)?SXC܀̳v2j;Z ]jB#ty[B$ic=F9ru}TF=,4TRӷ>n!u IX xgͱ ̗[|7c5Ǐus2aJ7f/seUUox[W 2Bve_rrp2KҥrQD1BHCj!xxo^~Ml0hw(6`㱝~>b"ڴ%df5reqa|1+ټկJDl@&عk!"AKKXMJE̢zbٳsDID \xnÇsc|apuB]k߱~$&K0!ANИ$$O^A(IJcOeQ~Ӕ>z A<{@2Q x @N<l3@ A\L︃x6㩧կ~5ٌ/K|qP i+lK~_v! ѐA؀~Əl4}FfRqsWrXsܾVp^JuY_[]Zb/Ig}# 'VƗΚ3iD#6wmf YLmIQÏ?pƛ9exi!kj"t8AviHbص ZKB,6°MBj<6^Ws9J fi$i櫶,R),v|<(MC(d]GD {%~}Bv.#.{=PZ;mBPʗ ?/(KP6E^`y#_Ԛ͇ؓOb fS7xC~u:l<fYlK:w5^{=!X^^f/3Vs {<;O <@6f <<ހ~&e_6|c}8 ~;ٌ|3:tGr49H2vcu4 niУ3䱽Mγ8\f]ji5};}9j9fP̆P,톸&<oy5<#vm""]qOrZ]ƘL`\∂Yb: ezkq]p~SDRhClR]D.F6r2b8.[Ck oO@M-ZuNd:B2V.NxeAxj&TyBXt-a`Ufl;KLS4aggcG:=VWqڑq]>w k1o4B u:@*]qepIVOӛL6fY}Yn}Vl^8dT4v/Cxs!> 5Nf >F =Ѽo5doxZfq`sfߤyNC &fO N u{r i;>Hq^˨BGftz iVac[~ OP ׍E=zGz${cYF#llj/${.F4`o]F]:͉uf5'^D1ƈı4 :RT:Smr0ȜlbӳsnS?g{CF3|K|NԹv05GLLֵj܃|s~=ws=w')!KY]"ɦ18 1hP>e 9lqWx~Z˙3g8qnI|gSB:?,gs.l} p`~n$+g\_Ь!}/o<{}Y3n[.57pYq!'$I4 v-Kutd깴yu|3U|6Xqfl-GL1-H(T0}Gש~M^ qz'DMlQuauy`)B2\$55ی6Nv ,o.ib;^/Q2g2O_Y!gتKnڧXL~bkh>m,oـjp%v՞Πowa$vűEPnLgȲ} UhVZ|6KF1iZ8bJFibHyH8/7Q} m]0PƉS4%%9v'xkɾ ٗI4G 4=2|WQamh9`նɱYL@ "2e!Yk%Y{fy(0zJbœb:%$Hɘ\i~\; b pq6KvNm=>K78u%K.vv#)BKMA֩ D׋QF! 2"^ѲSy!cYz .(2vߢfeB?$tbZ5GP" &G.d,\Z0R28.JN= }F KөX"vwD1\~c:!."gd,Y]"s%նAnw$IȲ3Ay7p1E "?p}8rB?D{n%\} &cE{?yH6riWZ)%7(*ko/l(NƥBfSuz4) VpM驭5N[MҴU؟61 A"D9Z26umKkJ0JG9x CL7Ra"ϻW4"!ĵ䒎)5Hd/ 3]^u3AL˧RbYt12mHPgr8B#ڃ.=!u j62>+rʩV@v$|?;Ni"%FmKNcH!^,3dȈznmтiK` RwLvlw`bk½3Qʗu;Fv>ˇ:[(BqE13*v&5CO* -9fV9 ,Ka)^'j))i\j-8V^J\4 A+p?Ǖd-+ld-9pq*ڷ'dKh[ri6*d B^+<%qFwIJ,ga] M7 ]ojt:]0tfH(cDFj1XQp#yg1=TEkzk /28ڪFOhADQ7q=1BErR/d.We1vx-7z=굓A 1YTR,p6a@1q vCP \s( "#m]yTw9vbX?=_[_jdYmqnc9^r^QnKN9J!_1DϙPx^ HPiceTK`j9N%JXi NLI4-n} HYCar1mB&-Mr7m^rm%ͧ^/m"ZrvKFxi`͊בӷVHee6+nA2|"\{8ݶzAncPFkJ y3жcr^_(2ԨY1!v+EVWqlJbe/<% ?pgD1YJ?-2d~$sQQ,Y\m#읷(#L}赺߿枯} By) 4٥ :=qj۴ɋm.!6yT WLjdZw`a ɘx x?uZPfat͔ϔK֛}`b4)l I[`#l<6kd|"pd)?R#21i–Mxȧ?{٥(e'scӐ%P 5^tHد ,m4!ìZ!HXRۦkyt &A8GתaFsdm!AcG&b`>HTzNh34eatգ,j؝]ړQUr%v"#pcVP={?[$Xg %5* aw/+G??6';K/7 r|aa;J¯`0`?g.B 8vwqo12\q׸|[_r8|(~Yy+o }^[O}ut]-o?dMl^j4M=>۹ۿV}7ceY=z^W.}{y ^>^:>a6zիx[3% KBy-H;/M7Q9+n܏oen FF?I<ĩg=$MϽ]A^%$LΞ9ʈ$'e"g3n^ [)]E[G%=iSE6} QBf&x lf-5 @.' ov;Y_q g =O5>H Tpd\.Y_M<[0\##yޢC|:5/ `n`HsƖ!XǔlǥWwg>n8t:{mYeiyVPD_Ô+Cx\#GNF_ = $@+d$ " iUY ]wBxboQ"~W‹.h7."\Mn1{ԻL.b9 ~Eadd)^f/|ݝ( XN ^7h4yG xb{䥀HmF9L0 C ,3 ' IDAT3ZdcHGCH5mUW`m sɨ2rq\סvUMPP U=]sX)&X[}b Eb$1TO}9;o#caqyA&anv?m;}mqizG8y$(\wuy睼mo`jjB;ΟHUe0jpAnɇiZk|mFN T>"3윟gCQsFvsTiI:7Mzb9vϗe &BI'B 6S156[D|@=6i*lƍ'cE~J2g>L2&gnӌoo NlfJrm'Y%%x3 ^g}Nr44 Q|k;bI]Zd^=5XN9mA@Lu%>Rɢ2acfT<ߧ, q31r|i"8B;]Y8u\.yK_̍38f=$;H gi}dK 7`[GϨ*i+O'pSaVXz׿pgv=4f#! *ei(V$XEWE͎z5 b})y7x͝O3xc^qw}n9ٳgE} aw.ƸYZZ"cJO뮻[󶽤1o}99CfğWp)ҷl.ܱOrav1+qrƇgtQ, ]1p=_e䢝ې:-k/~c-M ktiѶPLR攟l*'(lKLy9:`m3–BM%' [Onى,6- wU 6R?-K-k}LzI\J-$ܖx(P&t<)ծ3bd# G0+d8Vq 5*3Esgq(VVsX14["#4}Q%*꣨a icGYZ"iXvC ۗf\02c7c2o۾

4җ)e-/lf0K32.2Qk]cM2>W0&0 O@q$qE6Y=gfZe []6kR{j]|k{ !^n 1 F^2_(5A "acFzgӏ ;Acdd=Q'It4fCMtRa",A$!j.$1c0ؿvmCbGjrNOpш*Mm#d>dPf1rp!N&;vCZ<.y6ZET?Že$wWF϶@)!0cÕ):5Hsy }Ӧ-hN/GrB@ W*dLq,ZācO%\F@n}~Wf0_F^zKy_{!n|oT~7_W_m?y?p?>eg>sCO~ѧ戵+&'rSđ˶i>/k]_|?bc&V>p_~ 0}\cLFbwn}eG~81\e],uOdat[Ll,Jl Dk$MAD|i٬&\\~]  $ 41":b0ٳ@12z8244eYԺ]2͢izUhA{fa$YFtQUYQ(k!8q¨PNwQp1LÉ pl6 0en4!B(u2L F} GYz8b) 6"/}UQXlMT >]&DL,b hAD_Ԭ(BLegAYE~k_<3L^NVɓu-a8̪U#1 NO4+a&k5{2m6q=I1 ^GT.!2}EA$ضMT1 t8)r9:\pIټz=Y]]ebb=F\  hfq]f4<,X#MطAiTk5ǎE|Q Iz9?aPml,#~K"2ܳ,ӭ-D YڔLLD1eLMB, 1` c"h1^EץU]fjE(lȑMx.2*v "z@ɀF=w }ڭ12Xe[T18ŷJk}bscb&cu|Ⱦst{5oϑ)@Xe7?+t_?x)ˉ)g.r=ex})BktjKkG۴U)~e/Vo~v9ͧw\HmezAG yPٳ'lt9&hJ_z-&Z`Cy- C0X1uz33袈 *qSġCJ%Z~L&C94M#P*XZZBQ|}$If}8ٻw/Ql6ٻw/$yކܠ+,//( wec>r jn1 ˲40 \.iq`0 iCCCA|5 2,/WJG(j~ʖ SܱhT1سz|ET|6AL`ڄ}+ j-#ѠIW(1j  "Z8m v4m ?m#ChxwمD~ yU{yjRoB2š3Iuiz6Y!d9pK2rbYX@ǥV16cH%:sV-f(KLNβwnDQA tm=)LT#{x|W qmcv'/.yC2krY'φO>EFt\^Zn N˱.qY4F,Yd5,F, q=a 'qr6s gTCvq<9Huk 1~CFM:j&OWqYBp!#LbiEدak1EQd榙)ji4CR^Kc4PD`_|~Pe.O/3˒qdunvF'P=KU 0 ˵cnUז( >ku~I^{7n0\AV$(b3a@L(fsZi &b34MM[ tGGoPVYZ_G4A'266FT" CXYYaee\. t]84MDQ!b /Qe:623Ξ":wj4 qb"BQ-."Eqv8l8 aз,ZeNuE+ ѲTm/L&CE$>LDe:3??isp&\.3ϙ{!jJҹ4B쥨GBQ5E$1T&C =Ȍ!7br3p]ʊK !5Owff0/|G U7h'<򪏯ľ/7T)GG%ZR, .EIb]EuVjUC "#*᧹x-M':s@쀮ɄVqт\aDH؞o՗_.*n.;=nFN8`3bÃhB8~Hdra`{OrF A=`ka(\W5[\H1BF8^앨GD aI'!NN\y%nWs!DQdrrL&0n98}4J49y$(r5 J KKHDqxl#>b/-a2aй>\|5_ xVAUc#%4V l)r*$lGp(~c9.`{9Xc(b/`M <SѧڱԩSa)U* fff,{m%i:EGO6l9Tmt96XXT% R! Nҋhʱb&O!Tb :n0QHe"4o(@c HyF[d_/E\ bb٢@xX$QHW:޳ d{SaHgl \&824@E* nij^^82¶=DU%G pJ5("D0䄐}_rΛ ;ɜ׼[># 7Wg` T8qjm3t6@N {1;d]d &Mӣt"(>'ؽc/7Moe OYUF~ x߹8q> cxa=@?n)^JDCտCon)_+{/-5@R><+^ӏ?hO z=365Eݦ &*} qq 0#LH6rw<HQıN+ؽo.KO])o'!RD%E/x/YxܗDi>\9-JL ef|l/* j5FJ4=JMb=͛^y-GNxj C#o5^xcC;GBPA,>734ZC84\&r˙ d i34Ufa'e(3Xk%*1# }7~d o#wUǡtմggs4Mfff߹XQ?9A@|) 4%@1 ZlOc[ʞm8z(cct:qUW8\z|A@Mu 6@-6p E^J[aYu5Ɓlxɚ@Tof"(+K-oemI$IHۈ Ca5:Jazӧr,//3;;KV#zˉNYhY}] Ƹb(~[QE!P 0s -հA!=A1zH+K>`w n^CDN_066J&!7:!g]ZOQ(EDG&2Ld*DȀeRlAql#H"C r"L.ٳ<#DA#Wҥ*a6{2MJHJ*&EN`"c!޽HwU*( JHi+vAৰf׷j"t-IK2?#G-/I IDATsѥR.7&j5UZ.0]Q 뎌*fA7YJHq ;Ri<@% t%S%,mu8hu} Ѡ$H7b^ؾk2Y&*~`CKBq i8B݇8^Er},_dd ק{@Y?Kd>Z$вC%q5(I(A_q~ȑ#|~7><'F z?$}{}׽3U~~K_ժ1$1/3Z{R08S7]OlN0R)ѵ<Ըu;|C?9GX1lw0G9u]pP6̙E,:kRz,u zLR?4La}RˬmȩZ×p5 r⻏$XSS9ryFFFjxDZgym΁ .=};l鑸]ME[4Ro&փM_2u^/vUnz g|X+l2ډJ2-n, 8<wⷼGC0c{Xg0 .s;&Qeb-BSf{9$RD 0=\]Pqd2F,!AtZDWE'KgokEdIhw]([ ElDmEC]PA=솏n0IELL|OAC4^k~WFͺՠS/N )5TuGD\n_1M={x׻ŭ??222<[Ἃ/Y]a0|e_O`q)zl/^lOq3X?Ietn+ &>߽۩3=3B񑿿_y 8sfb>q?U/=ͯݼ'5r,.몌"b}#yLK^F*T*9SyPH)#!R$#L~҉3_%|H9~>"(ٵka>ffu7|Mb$%FtBc;ZqLbQaqga۶m}Z#W.(+y*yg$B"&nXډ-wȰg9 Li*^M&Q]*|+1O&GJJf:Mg aF&')r O^s ]={I{޺ٹ%"E'h„H9JA.[C9LیdDbH%wݝ=fwz3[EGܥ?`=U~˹ )JsT,9jC',t&aa$`䤳Mh)xiN,,vxDyG}{ϳ.Lh{D4f8MafDj]"L&dZB#իh#LbQo%U^oxiZd@ " ,zqDϘG;]\au1$QAy{GG5礳-ZtH=i?wЇ>Dm*ImSK$jj`:U9dYnt ~ӗ)4S7$Ld?7 FzNA9C7c4CFQWwy\p?rL /"K7# _{(h,8썦u۴"[5D6s<1?㰲]QQSb ªG$HPT %F_W!xGdYѳϢ<4?j{xq{ B``XS.X;'lޅSઢ3Ld3A@R{akk-& M2mwgeOxe0沗H`N߷P-Ҩ i/D s}ri\T @e8(l6G?oo__~0 nX{{{CgeB(tV֩T*oyM( 4E±T4M"RbaD!9^p.ԓ>Q ~!_j忸ۗ?/ywsO3x_׸d?RxǿY,'hhD9G!c?C-Bag|W ]`29Tk*"HрġЙ <p[EŘ0rڼv&@5Jk ֣ƻold`><,3$U!X%U<?ee.R/A2/sC`$yNdoo^{0 i6r%ϩ"$//SQK%(8U) ts"9VF+Bh';TlsJ=w()ehToRFSm7ޣ#nn"̙3\|Yyי3LobS{ 6e $q8;!-{([Y>CP5VW8wyPBaQFx\1SD)*)A*A^c9mшnn z4&,59"` E2 KL 9F /0X()XP_i);1Apw"1`p(X$MOZX[K/Gu7i}OEQB?(|;}cdYU|*7a<pp]-Y4LA`4C瘹J.)C[|P7Ox<ӭx|"<_~''.~cio!ɂ$YiU7Yc<Ȇ/лV {Ȓ?A33.OP57VZ*9ϋ'9Qe6C\$ ds+gpGr _"(<`E^yuT.pjF)^9ݶUEu⽫{l<ĩ\KyT]hlW9|IE/Tr,./zZ0 ӅhW<8QJPTCp2=ĕ+WTẆBrA(;!FKMK,//]iT Vl0ł$MSܣh 8@6ƳD6bO?&OU0$ ePn8IН%IȔ*183 ͢?~ SY%J-&>"ݺڽ&dK2%K|;sdBm膇DMhT $p'ˈYFNq}<t@Fc-(xлO"8~CǙS<#wp*O>$gG>WmZEqBP.uOXzb)$܀B{3ԇ8Vl߷2nOU˫|+;ɫd/ڭCU7H ukL/*Ic[INV1Qi9S̿b:wp!sGK&ąqojm4rYj OcQ~p71it`MWnR |gԖt3m?3à)Szse7Jow/xͅnf}o`$IX~aS.}ieKj^* kZeN4tҰKCJ ^}`gZ hyͩ=NY' {/V->яMlz#"˩wV-Tbʳc7 3N=©X䒂LPqGXJDE-G1^1 u d48WOOgL/:T A$L(2cTqntE\39/|._y:m"C/ CA*`1DLkt:xFQ FiJwCԼdeTy@[-@yG}mn<+-00ξƳy =g $x6e>/ȥ4!+gOYrWYQWOzb]"}FA?"T_?qv-4) 8o#Mi&,r?kJ8JYk/ӬD*aG6$B`f!d$ԘNUr7C/ *6U+-Wtk]iWf\+hԜwsN5f Q5q@(g3nSp}lq- r0M`VPW^ޡۮGfH6Q0eHEFE0HBda_DNd",u^pn[͛\8zN]_Kw 28"i|}ET E[|!y> }>+ԏdBo祗_O_}Z'w_;/oѮ#S߸1)hg6wn j3 ޼ދTdiJHqpHɢ)zk*\繨NiR2R,e:uET4)Zhb)qǼ~Sܽfᅛ4Fܽ=RY/h.,Kͯ,TGP^]%,ʹsܻŗ%nlcEf5W8?K].8^+ |!X.A|/Q$W)y3{wυ-Z5)~g~I|ej@)[!hxcL;f"@.RJ7 UQ!LIz6.U$CF8.GaȒ`6F.J`UiWRF]ߠj}ժa>@+Պ+))i$#.[L&Gbqg/q^z 8d" 0$+3¢#x~T2Axp8^=;)??ƿ'%C)Q+t籮] BaJogg.&1×;i)\p$ *x:5NC%WeZULÂA{ؖlձ6&S`qx8.A2fYY9QZ8N֊L*4H%OQ s~mpxcUt3a6P S_"</}}`ν$=8ez2NKu$Ikp*;DZz縌R{rqUJ10" 4m U'?y?88)*Pp20[ ZsJWaQZ :{>חl [51oXu[@p# EA c$ysli(Vn~ZcK>;/0bO3dET MVԐ[a,Q;d(RFTY\?0 ^2R*35 M_{&ħQ?gHSN VT#nz%KBd<&sig#^(S2{ ESxa)y3C&1;CB8 Jâ{>|];K(xsk_3Fa}Ϸ~?o!=o>*Wu$i#?Grǣ?78<<"ma+ˑnS/kOӯ*KW7  ]%L x7n L׮6rΔ{4^vZ8f?I,\""lW:RR;JSF3\?j=dBW4ΌWo(:vmkB šN9 Zߴ\6ρ@+ʝ`{7n!̙ ̋s|8OYQTeAfUl|+Y*Տdz,$&=r'hk 'Ș Ae/BvTi/ ۺ"+Mٽx++xt< (L&|"'$qHʈ Z"1JpƘ$sjUՕUTߧSQUNU,!$Z mT00L IDaiJf.3•iHLI)d8uA@,'/PqAJiyK!ffQd2aP%S?aJd{~<߭{z_-ays|Mf.픃ѿ+F0'}3x"Ky'Qڸa4[m0fs(l.s*#6VML.\4uFdL:k*qս.x}a/=nfDւG?+S' ^ yQ q@[C78%u 9%y2)SzL /ܷۮ\aw8}$-%BήHQtj*N͡dIzX>(@N dЬa^#;hjcf3©FDh锌 x|4 X¢ptLɭ+3\"1# *uXIRbIg-ꆏ809 > IDAT@1P53:yGѭ DƬu0cz"Siatp<0ExQ]B}o}gGt:mT>;c4blnnC^@nDit >bQ-[tMi1. BpysqF.m1AR qL%8pa[i4k:J 1GGePEqRg:~n4c)ՅΙi9+9` 4\+ex;^I8ip::(<'s gD ^Y V6oO]υo)V>]N|[N* w l} 峝 O%D\tH*طFh;QADz!N 5 an`øFUN1U$+! $$4!u^ DE c*ienDm 7UAdzP[z>k˩YWPv+co,r%SG01EL?r9~ܧ*[XZ$.V:OAθVY(F\X8xͽ#L*s{lh ss]\E*2UT姰+2qjr-:FIfle$$E',tMƱ` GPCIxB! _S{\zNB& ?Qȣ*Ыtg!o.t;|?&O.zIVrNv{Vh1Ӆ9ꥇ8ٹ~VMSڇFYo,D #1/xc4[,79?zEAlQ ڂq8mRK.=\߸UF4m9=!8(#k] =j}РnPe47k2ѭW_؃ ۶x1/^裏JQd9$Tհ),# RVmջ bn9%c?1ѤH"oa뗘X5Yc6g!wi+pdB{sR:J>.6gLJ ޲_mEA`(- `K238/@υf\9* Bm.|VSK#3B0 Cd!PY {8Gs$*Ȓ;P5LqH Ǹl=5P#|z:u4IUqc4BN7C`pĞQ:=qlN *3_b"4 ?B0[ ~Q5p1DbH(EURQ\zcЕB6 &A2:D@24#OF_XU M1[ ns婧'N(ZD0=N<`fJ$£q91]M;ņFI4)NaLoi{oJN(rbNJ_hжIqg<}u T>0δ155|c)yvűn\brZA (I(!ۻsp:NvujQU2~"jaFx"lju(ŕYSm*ܾzX.uPU28lȃma]$sl}i D륤O@A{t`7|Ñ%APwdMV9ߧbgyH?B>Cc4Ĵ d9$MUf;hhT Z4`45l'2fHhN·6>ŷƙO|/~N~w1;Ep~:U= EM3ppt*hvaA\ـ DSZf­;,^c_kEa `R y{it:e% ^ CLT=є$nMǎp-JQP B"I`g9ɔXHjs:#s:;kc:,zfU%K! L$&FQa9M[ ɋW'\8j0`U2dv `!Ih40%fj>zcEGQ8 f<i9Ue9vYW+u7x{wP9 CZr3T&GTf}VZKBGR>G=YQTn6b0T)Ӵe qSWzw ܆J1bI$TmUƌL1 SY.#dí`BEr:l%)TmQf6Z8NS,Uнn#+&yaV*ÔVA>5<$Le0pwD27gLrqwyot N\Iv-N,+Emǂ$y>/[,/0FHBs]N ekXrc946: ȊǴ-[ZkغOxѐ4$pYEg_d#R(`6Cb:>ċUp#q"y|̍ ~9IByQ8sФ;Gc)kKCg8J2J1a V; BHl"l z+Tc^ZeGH6mS'*Eg3 †/i$Eξd 'Qsn=W2,ʒt,Iw\23(? tJ 6biH'z\<[F7QZy=BӵiHp#*f#IѠ#O@G%e\\fAZio!q~&pA-ŀZaFb pu*57 3¡?3N`Z8G̘&@QPtdczN@&,%G*o3+8R 2uĥHtEH|C6yIJ1Ȳt:}KKĖ*'WYӬlܗP:T7|JWq` ²,6g3hA+~>4aI"MLR޸1P9*unWGYw#d]&ONU:EAM|ǪǝhLJgun^?t#V sDd522iar4U9TlniWɵ F+HQ)\ܡ[L1ęKƹ3diFfU?i U9sL}4fڶKXbZXU;s9wmu e:9q:gsJ={6RNA2Jh`,\SetҜ v![*=28 # ^,EhTAmVG eD4%S:ԍhǬ8L2ؿB'd)Xٔ-rM0L8%F-%2אQvJq ; }?p#0 MAa&G%U&AJIK:ьb)9ZrqgSJѸEAģ~,!ToQk\O?9,u)QkگO,//~Ο?G?Q8w\soo}+TG{x䔵  vo 8}yESkW~M"˦8_R Q$B!X r\ЖTξ3BUjQ] 4c|A\xsN6AE'S~0 $v^^CձI!R:Guj2ǽ* UF%M٬{=۠ję.vj蜩c,"MzQSh7m,F]F`ኃNIҝـi6/DYxb e-?`8m#*j) 7YBsLA)C)UKe,7-$oHkKe5P}dovjpSN[%(v}TNZhr:\7GBϼN,ϕF%*e\ M-S S U^K4:""("AVثȪF]5tM%t Sm!".DGx^LfbRD,Sߥ4ttDMD:ԝ㸅%$&C8gT e٨h4"MAj$q82T,t BA\T,0>pljSyG2gֹw>듚9-oַ+ne? ]%j3_]6t$qpѻbTw&r/ z=eM.Z˜fMbeχ?scJH'Ll (Bw쏇oȲ,XjXT 8Fx-rF͝FťZz ' Q$',l sƃk?I:+>YZi::;t6]wޠBO{!)恎r-U2` qSVQUN>$agb&,;K)eE^4.6PT]FE~VF]Ni|mvN!~ZA jG(8ɨL w(c*˄IÊi:A$P i aFf_B2:X,l2feUw $f,WHot"˨*c"[cLà&a+>ie2C&KSu}^B`0: &Ӝi0+[*O( &!# u{)ț,q$jx6bp niΒc[o!Yp5FFF [_">q^#2Ä\x SFm^ DB)~̇N߰1([8dH&ãvGEu06{fs( pJ} x!hzKf02N44h%A!hT TLuq1q@ɢ 2'W SUJ*CTV8(ҔB9MM'DP!Cu‚,kTY*PhY$M,u _=Xשּׁ}}93=ݣ0 A0Hp8)c$L,#]0,m-xYy a]ɠ1HFG>3+'Qy[^3 2oW̪̪=﷘/誅Jau׈'Pڬz]J Wc PC ¦e_ԺOfBt))HAyuZKITuMn#s֋žKE!t:.׽(~O5GijC|&͛lAeQ[R}er{$f1皶k V 1A[jT)ofs}tD٤2 @܊8rZ%&̎Ո'>Y %`OUXM}ټRg`*Zu~;snG?h_X}|S[H"+g(Ξ*{O9"+$IBQ! װR0EA3,Bo`9>t@['?NjzF.ٙٷ nתku9!'!0Y^fӔ4MYwk7P] YjgL p!+ vcy#Y _%.k':3rbGQ ZؒJĩ"0(ϴk,,"k`Uۢu\ r5'OիloosMN}|t:g>yu͕_dZSuI=˲.]B6sˢEW쳬TK;) Z~b?9C%zF'2y6c2mfTd{ǝ"%BԻW8qQZTu>eZmR@0q`[=(_FG,5D,Rfj*ɓ1+K+Y`eSf'(}T%"*г f5z[xLwYkZF~z-nmZI~1ƶ= ugy0] cF<`vbX潫\FP+0^Q_R@b~|TlgkZ$mԑE)k_O27[ .mYeY~S/Ly{)3W} O^mYk^?fG螸ဓOgt93yވ[9%K({6f<2^j|A X?t:ڢ}4eAU,VVV!u]/d>at a,h1` IDATr;4fqe% t|VAIX9&Gi{LU_xJai s@iU1J9P iYJбg$I`0`2ܞH))˒k׮kny饗eիW$Ix1RJ'G87Cp  +Z~B֜b#SA0|׿tC 2(f{qQIA!.B%mʢfg%&,98JlJ`%tBt8 ]v.3ZK']!GyEYfziQ燄^aY,=Lc;5$)T^E+p^akqJ#9; H`+=!n,|g4'.VMܺ6goUoP ]flte׌7di‡U_姞bEpg0 )8 8}4׮]nSU< Ng2(ƲŴ( ڱ}ՁjD-C:aiFmMB( בhUQ O@]ՠQCcsy0>By˴U_്sxkF#jql5R Cz,b4#HI第bI֚Eqdss!v͵k׸vm>ʲ$"YaYaC=tr]۶yON^!ɕѐ/! K[h2I׈ ]@p8}|8br"Cd)"ܦ3 "kY4ԙ"XS~4Nq Lݦ*¬5=Df9n7?#,=(p(Isi1:ĪJnuU%8&e:!eK{ayy AEZI2Sk_6]D=huދ6RAv5KjǂZTA\s)UMbpţ؆.]p~+UM7Ԫ !nUqy]眸 4C}f)l?×6xIblq!O$+,E f23-Y;D󚺘S@Ǎ(L =_f"5wYHAu Ԓ$\2^g>;zNۑ17orY.<BQ67>8/}&h`lP>S#_dԒ%OSH-&,}%ZNpDWPz'j %^! hXۀnBp ch5,cT@.gI(blêJP)Fe#%qCe9ַ) Ofw,1EqUΜ9rr8JTaB2Lg$F Zٴ9Q95qǕ!Noֳ(p$y22]ns/ :&RԑOFB5)"T3"!ɌM yB^Wԕ?1&@9Nw ]N@H2Ilp&psH{@£?/C-r,m?[]Yo\Tr3Z+w YzD"[mKW*dƜy9q­g2 z]܈ǯ 3ZŤf. `7>E ,.N5KH+$?Nt _ S%X~9Yœ0|`VRє |[I b]2%kE$mP|clDrCi "'$ _:l5J7e+ ^vZh|:@9bŰUauC'#C˄~e*CBuj2bV}@\ZY"~9u6%BFcC X^iEN( Ԁĕ9RK6_RlzXk~\I*AU'Y2fpױPM|Ef~oY>`9mX*vMjˢg {{hc6OZs?y c,ij)pҜNc.l B$.XQ-F2/=&7PyBO0 ۗLd yR]e3lEΘgE|k,l%,/`R|1O_L(K / ̎bС$efy^Z^Nmj FcpdpS'lֶoʰdrX @tA ca; ,)B{gI B 0Mvc66v 8ڬ, HJ^`ړj1jA( 4UY.8b^(\Z6yq=AU rY2K\Ϧ(~WqYւqػ n5h"ۛM{9<1)LؖD8hIͼ*PA h'$5/xHj.5N-qEL*(S##CZKj8z_4HG'}}Bp9xvFUz<[N`Aյ1{"Q@eT L>smEy22.jX cJLbZ-m$eUqx8ht#&E9P-K4wRzu[Y-!*Œ9`kI+4FP殾@JU/>iXFPxD4g}1[gArG'y8k8V OT@M֛rBi:GAe{9F f<5ڎ[UƼßwJ]r{T )=bw-hZL1VDL];#AyďvE9,H)#X7kd5. ZcњYw 3^n1tJ) mӧ|ԾD1JYoQMKk:gnuy2D:[ُ (uk9 YڀuѼ*rKnaYkzQR#ExtD0oRNlSERdGfS].$.p̄\ g#+KVRNPk|퇄SNg3bmN*kI@-(oW j[cKJ+<϶1S Kk6{=^L$*&CHmÙbW~ gzqJ f<,GO  [mʆƣLב"M*zwiڎA"]#R߶PMR(lmaiI<-S–*?DVẙm~L:8Mb0wsaiJ*썸þU6:QVCD.XY]#3J I0ưZ=rٵ T|\S iUCJB$&GmeڔKeʸ2A>6謉os͚ cߗqGbM釦7Nq,cQdR6䑋)G%ZGvSMz2iӶu-].;/"of+ݒD 69Qlo¥X|OvE<{kc[YeQ·‡|\qbPKks>V!y>҃\>kM^X*CA,!m;%^U-wB0bcyEjH|±}f,a DVy|Qmz_ 5;q(xٚ `/jIRz;p7JQ(9n'I<63pGI+/s⻡#.!+VNbz= ̢CIUY<Ä!:_t^dJ3W I2R61`s9$DVDjJ\$eȒZԨ& ]6Z!9"acݻ>f(=ݽJJXDqҒR`{$兌8Rqz4I*C8/YivG$YDh-S:4Nbc9Bٛ7WFhpex #ѷsbK3-C=.F {g@=ǣ,s8S@)'DÊuBb$IR|# !_7^m/svvv/ xk+{3 ><;Ο?ϓO>'N}O]y׻W 0)k6)_zw^.V=9}F [3XE5^='>JO1f?es)H }'#] -\W"-]!q+WGEׄ1Vi-kkjk[5p] ^^&XdEN#).^ZȦy,J=f6k<;%4.BJQJ+ ȜK@Ry:Ţ$ZXjB3UYoKw/Ki]܆J roeHT8άXC&tmR IcʦYH/͗s7|rmaW˽i9EUCᢈ3J ` 1-<ñ]2XYU5>3,!dRthpq"V'#G$\lُUdcdc_VnrܯgYYk6V]&wOsGOP+Bs49V%'͊}Y:vkMԩp6^Tsxx@R$Z!QeI$Ɍe\t:.7e,'`2$Kc*ǢJF՘Rgr c/;WZp5ja"plcZm B9+5=^"M )sI*ؖUD`PKAW㐧sLۖexey:AW?w)"D8::'?I9/^3{ؼ6±zM.m `kTe F?~oE:5u%"esdW%2H]v_A!0Ihu)E.5mHƊƭ&IhWt>`(z-j3 TYM8P5O(Tc-#0F`;^"mx|ty: ] s dee>4eY,_ou겼>RJ[Û5w^I`Y?c?G>.?0k6{z~꺷!l_b"W#6O,&'{f7g5yƉK`Sp %me9. G39sl 0\xN"W1fAk`u=n ! 0c :ǑYMn4Kzap{!pRkFEisa*jq ac`EӔ1Nq{1;CE"kB ʲ6)S"r2̣@1AUGjF 1J)KE=0yM[֋!3BQzN肏`;JeA,qGUQ}d27]dx=c,qC2_w_wI7'ITɪ4~#\Y9r8q7J7qg_<@TatК0-T<@͏N՞t6=afS'GJ0N*jU0)G0̜Ah#n1 7İv],FQՔeΰAx5`]lpիE-zLk,R9Q+j,i{2^˽1xP.Roof:+?;9{ Ē_}/$)-DU-ww>oqE^z%~Gccc o: z׻x;ٳgxk_˲Moz?S?W:3#qf{bs Rpw ==ߜo>:O%_Kqw1@6l^]tUcPX=YT`ZiFӕ!(ch%,QaYl-I>{?i#`h֖ﶀLTm0f:pt^S)I0m(ҊZ.xS EMôMX,oּ&j4u0.HSˬ5WcNur~Ԑ@˪7&}S!t)+IYkjY59tu Wop{N3Mhm-OEs8qꮒwz$\|:qŹ ~ޫ] />żэ{ϲ >"ݝF5CvF[̃^|^ȧK >5Ċ6bQNbe.Y3l(:+89n^d1+tBYrn[ćZnGysrekVW[\;Ēȃ2d -dzl &F ,.78f"#:]L1Uv YX]d=cUı>yX*vVJ񭍁X_Go#}ʲo]*[vi;?{''ןxEoYȏ{O]3?3QBꆼ=ƃ:3-Ȏ%١Ck\,t=ݐ2Q)YY?ox"e݆JkA`-JsN~Cg8<>b9="9q0>~^։J}ִ-l2,N='C2eMK0mfd*1˕>G#b4&%="Mn\ 1X JA, p1|O)fY1LgLK]t.P}&B4&p@ 6T2Rh,,3BREa-EL.%teodVypcR%%5k.#ܳNjtG7q<Щ \:('ycW^)X69v改R{()۵Ӽ7`O4QYV1{Z}faxdYOp.&=%U{P5ۦ8m&"ZX HͶoG["ɇXGw*X9Eu}rk>9{9ug)g$:TV3 ) H^LFf,o?^sa=8kdb3hKUQL\J>i>mff1(jV zv rZ4sU C/\{$'<{8: Y4atI_S'wfλV ꆋ3#d:(h:ҝ2d0+hn(=2823_],&\h48Bx+. åm)uajVDfa,viAP3Bik&~`yIO 9ePk)XAk2ӹ5ը$/J\a`b%iЬIN*",5$d/*$˹ 䩢g5ڞbY0X^S ;!ƣ0 Xaw )qBjkihaQzɴ˛hc*6;HY}O?rZzDQOv).>{u)x |Ja n~se0[iRΎ~giHN3XG-uwORՙJLu2ŠfE(2,4t oa=ⲎSd! v'u"3!d X|+5'eY2! U!Yf)-g!k#L炭f4Z8!te!)="OT,%aªH!f9Zo1+RLszacg )YvM<:?"Pڋa, a9G%\LrVm&+,Lm* fwzn]3Jfd(ʜkM`Fɀ<`!n%S-Ȉ)9*Lj8lIބlX1r݌4%Ng8R(搑:}X$S`@140۬6B+ ˵La@ V I""ꦃmU'^YY"C|5o xvy6SSBb,dH44V6Z.y UIڊߌX*i?PiWj}tUx3"c$UE! :ӀcZ%m&Ќg!9&%8T$"Tuz$Q/² $zr=(U` 0B]dsBR%*(Ub ,S9O>e1<a6~^$-1ᢪ ~6m8.MWp:i aH; nl6&ӧ8FNi Y `Yd`[$ʑ$bs:gMn=rb\X.K|'Bk,}pu?}_COy }*ī|#]|1HsȊTҵBmSZu5} SᬱbŔaNi)ihbM)]:kMD2&<--~%*K(f^0;1풆9¶lY a<Jv a{R|.K%PdElT tB|7YQ!{mʽosی u>7ޙb3ꫂވ 3k?M/TOp$6 dK ,8"²$*09<9rMAr'!ihq \aY,895yf2{Ă (1څ߷9@Ϸ5Mr @ rg YA`jA|H۝"Ys/ wQ/ ."8.Z xE-n8X#wP$Q>0,|49h#DInE,P"i6Dd񡋓C)A\;2]\Q0Nx<&j ’p4Rt)=J}.㎙ouc2O-2n:k!]Et|o4X$FVzC ȋ0"'9{2zd2:k;Sk4>ܣUwp!(5;S6-6kR38E->Ԗ)cI KA',<\i{mT n0O/'t}_ 4hx.R zQZF]Mq%Y4$sWY##)Y(M=_Dr=94uik<| bMsYeHf"SYGX!Mj:leS(6<2 5$,XkB J \8&J.)Rh7ی)9 2K (|l&#ϩ} _hQ`k1Y .62IՍa LoY+&]BYjKpa$')- 0t$Ŷ$-gtq94U46aiJQ,¢(KL`VDQ8,McT'.VawFb4c0#l82Iqӧs })IRqݻwY!vYyzsq\h6e)m~Nԑ qpl tRx<0 !4) [[ Dca!pfQP9eYx{TrͶLlӘe.z,K0 h8Q҄=V{] 벺h40spp@ѠhpڵJhpxxHV#"l{>y^Vo4$ Zk& zpHeEAۥVQ(˒p8hm<8kkksd្$ mWp] B:޽{8Cݮ=)Ð$I< ?zFǬ CI☢KuO>R< 0MV!ٌv:Z Kkf!mSUV}r"Z.!PJAcF+&B~qn@# |zjD*9W#Jt23a:dm Sr@Z[`?樓UR- -&y }> IVTkon)W=nKO&.Y#CO1:d8v|p\i;eTxDxMAMiFi<7!&N@c1 ᐋ0LR14n58Vuv j5vBhvpI @H`X^6 6Yb yF¶=d4X.XBQgӳ+ ,X__g0)f8iXeYUO,$Y$f3,4M$IT6nR)$IhqqH)Y__G)EEA@^*H)㸂gmΜ9R<ϫ:4MQJq5VVV㘫WM٬bVcoo˗/W)2 2.\PYﳱt:Eʹ߲m!A8y$ '''ʎm8"E3gŶmv jj#k?48H=j㖚]:@!)'hCrl'u1e ݤgr'd!R4HXr|/ f*%,5'8۽P%;BNخ-$ep -U9nK@`HB{O3Mk플H)-ʪQ k#*@cš;j/w>{=@,ONNzPUeY˗QJa6Y!dkk 5ׯ_ܹs4M)a1BLD)뺄aH4 &\opT\BCRJ666(˒hDQidYFU`̲ 0*HٳU% Zki1M~OΝ;U2<0,VqxxXu5ijPJq8FJh4BJYu@2Rf49`YVqrr, dBc𹏢NS=S۶$.i2HӔ^G^'",c}}tJ'677x\-4J{O?zIJ4qDZܚL=՚+^ yٔIz=P%(~mt=ip[;tlA |f/l739%!Xikp6Dt%m_PyHϑu5,ݥk$ Qfd 3 C+FyHKt9e2Hq 6JÁ",ۜ_p U (93۲Ȭ+5)()TV;L ڳ Lìpq0NuL&XEu0! ؃RJfz$IC2:CQUN|߯*$I* f<0 RiUq/=ٵ ʲ֚(]reYrY0u]yIITn{.=!(˲ àj$ Ie.J):Y9qyނXN&qLѨ&; ked2ja6e1yΕ+ gHΉ=Q\⹫!ߴܝOÉX:/zلƇ{)]xͫ̆;wAG8n30c4- Ub%-V4 S $3-ZꐂU&AHPHZm^/XvK[ Ik[Ee؅–`눈&jC&yiX@ QdF@ %= %1SUb&<<{2`*]t*5MǸKe$IRiʲݻU2eYA!A`f Oݻz=RUbÐLӬ8!!'''uRZ-aUk+w ,9e]B_APEufNSy1-;FQ-?<yB#̧C.a˵{dWlY >r=AJA<|}ߺ`kܮ&^{ӧ>F#3.QNz[$42ԹGu8vue~kK)!H#>uu) W eSmw<ߕ &AU,cX0 )˲ a)/VRAPaˠ&FQ#q4},*%&2N>8U2Xv5^pHQض]A4I`YVue]YYa0>ɄN`0 c)EQUSJaYRJą^a[ؖ -`=e, .z.X>+WAA};!6> .)"Rw"QVsb< TnDdj9^`򜷼7W] /% :4"[HLLOߝWAEۿ߇P*ŷ}k>ݻ\~KvyZR.٬ɗ0_bY>nd_K 28.GGGXy?Zu%EQF;1 ^iVv&.w! NZJS%٬"˲{)EQQ,|1!.\pioK~UysO>|2ɤ. lۮ:ejAPBKzTR"jeYEYItqttT$l6# j\>}4i"'55js.(/ L>5Ѹ&7Wn;o0 299`oeMa𑹁9ݧAxgvI#Ɯ[1)EOIVtv2Ȭyа3F8j8 .LhSRjʤdfReZ#LUN!,yz䅉DrQx$(Mrw~=|_z]~9mۼW}΀lKX6o }\ JF%SUwttTUK:XbшDk69DZitx:6* 5'Xta0EEoє`6× 7K71 clb0pj5C)E}v8S q3DQTuIpܹJuL*rz -;ZV)|EQ0 ^eExiJ\eY-!0 <,x888 %7py!Ǚ[71 X,JfZ 4Fj1 4Mw`mm`d2VUķyUAas^q9uTZv*EQTs\k41_8 yN}lCd2HyɱxҠ🼍*iT$7>N&LB!X}|v!W xuf-A1JřoB5uB41Gb>=ljbJh2%-"prtVmH$6mMϸcV fAvo_/h ꔿPb>gCg#۵yw|Kv=!$e9W} 9>i`.[[[}${ "R_Sv.S^\ʌYFzlS3X*܂W\ ofx)MS_g!L݌?qygZml `3IzS h֚2Z_zNa6U2X;w0 9<<$3)%uAH)+j6U`_%SeUJep^v˟7M,'@A٬[[[T`0`ggժpݹƲK[mn)K{5OS"~ya]$H j  a!SAIut"߫3]jfQDĥB'WVM&%ɲ5֙# @4&ObJ_lY&~߇* ~0pL>_˻?jKK<#< 77ׯc?cz/}",?vhE_򊗿Wꕟ+ܸy7W{y+C+o'G_udMSJiw5Ł5 e Hr+85_s٘sMS:$? ,)|F^Rv8GbWۘ`gzak:8&/*9u?PRE.>ɡյΐe!4/r]k&S|r{,Ja(8n%\vz?U8\3H%,&i8CEտ]&F(K$e=V:pLEf:#`rv4JKyE6499{=EƵ&\{ 9E^T".A>@ ܡ$(+e1JM1l 5m,y4H3RYRp"Ӵx $x~3o}O>4Gzw?ımj@Դ,~o𐗼lmmsM|k^׽<?w:|ӷ|;o_ Y[[{w?w&,vȏwvvd%"7)1s-X6]t Mpd4%&%~SAGnxGnSya /؝+|CO+o~TܜnY1dmynܻ^_s7C"is6v0>rՀ^9^{į?Oً]°,ERXjB{)sqxxXQm&I%]VY0*YV˩<+8g]׭ eP :k[&eR C$IRfY/咟Xv;󪽬8׮jյ]˒?i4YcDQxYG?iO~ 7/?Go;7v.^wu/soxNj^?XC:6/x#ݿfsshWwG덼]εC8o}˯도-Ro~*8g~gٟY^|~/o2'i`Y&.A~= K.~3o|_/(' uMl@9ʓy7w3e"Qp}!z]tM'~oB Z NDFAyVUl2" 3r#>]9ˡ;\"Pe`):*`K67"j۴"iVUfl?Ns:.ge.JhDTEJ)]p-^I#럥a%T f,Rɮ IDAT<ӱkuTP(_?iӟDDh O1eY}"m[7q %V<>JR,) VٖĀ3ワ}B;l¹.WGL`AP?e3of1դeC&(~efc[fQ#_PBP)J!86ѳ?Cn@'li/t{=N9i{w;bc'ssяXM7]$IVV߿p8̯}}|$w\Pݻva cLMM _t:e˖-|s7O~x"z+Ro7tMmow^Wow~|s |?t㏅|qmd(9Eؠ"mRQl39VWA$`J-|B^1pL:O 1DZLg<`ՄV$EP+2!xi5<wsd^mtm;|X)KOК)!| 2gtc{slϑjD/t)Tb8I*lk~\._+J:httU$R'''u\.!)B@  4ޟL&,K7VR n)˚ؖ\NjuQ9O߿d $ߜrgGL thZ$I}[%:i"m.ڸ( E>+!E2L"1s>5~9DmO%8&yQ"N{סa*4\\2CnPgXgq}#&~``Ư׫uA9m@ヴ^s]簸;V9|~}#b<뮻;ﺛksW裏==^ϧxM7m~{˯զ0Mun#]峟ٲ,,'N rwҗ|a}[?578s'X=%uun=l{ jI'OˡPHRl 1 hIAdI(R.i4t:ُViRbj3ML{)VdW/'9I^O7H$O5=}PJQVMўH$S=>mksirq5DD?Rz^OݠN8y#fĘ-ƒ->'TV WxvD[uqKa:b/X8aP3y='-.&:-ϹEEoxk$vpUWQ*?~)r|կz۶ly?}</yر};kNz/ż/?^Wo }{v|FGG7ݻ{طo%S<6oi211mk\s5<|K_C4=03 \vej\{+|Cq5Щ\)ʼn|ha'}B5|UfK׉ss4\TAgi/( ]s:U!:n0wD8M&;_[[]thdؠ1 V:zGg[S]! R$<go2:h=0):xt fhm-ko2XD'+g`#& {` Ҝ;,EJg(-ʧ+&!yG#[lK9F[Ul߸Q |#:ouu\.FC&_xՓ6(6_&A2P-=YkHog rM/I?닷|{w|ۼ/^[}g_Wxk_}~[nBw 1d,]7ipefhb>IE11ɍ ʊ(\;^~^FgtA!4iŤR.$-*?c$[R(xXO4O6xX 1ˋL\vGwT*iWs$ѱΝcxxXkejS_.!`Q]V/B!VWWfZ/ၶmSu2M7I3m":a5+*vM>ĸ( Ob0x⢎EJ''P( R6u]L듓pzfST(P# 6y"<,x pby&ÍUB 4+Q@ć љS/r-Z-Bțc!R,A*۷mȑ#6y| e'un|Go _xчft\CۭT>gzJXW@$`y\N78VTzDGhp6E9vL$Ws+lVι8. @} ӄ#C[zt;QFO*EVD*&u*iJfvB@vJ\4`*6[l+Nբik@R4Bʃ֞˛8tI)r022Z̕bJAI_k9)HxLXL+dRXj .ӽpAh4XZZIX`@y~ɂm15KpR6ΉKZQT*V2d8ݓ$wqq^Ȉ~Ҝ[HsTHRtTDbInJ!;L <"1 ?c'H8o6TN _p/p̙/_I {>zKpMcTOT>9p^}3PӚu8{O#4(x]4 qz>gK@FyKq3_bB09h`[ix`Yp. 7ns S N<=M\S`:~*X 6om^ˢtcu$`rk+ pxMthþb~.@f"ExKR=Zݰe2f/4)@Kx>Civh3<˲㜙$dY"Νp,J ẞ lذ"YR G7I>)`BJQ(ViAf $jDdY7a9~8a011t:8qD<a( }\Ig|a˖-4 0BrYA|^|=Y\\Ԅ|:VWn|J/hpO>RacAqɠZR,:04c}wl5Q=Ts] w?78y{/X: uV3[:C)R0#[Ü΅,lirCq;n"gvs0C pާqdIy8蚃Sp$aj"a)FXV@"GO.BC+a}ꖏ,UV*60]N]!e ,?kOؑy5x[ЎBu9tu0_ 6O\|;_:" sYlʊ,.b^]]Jkާj0k@ƁeEă"FD<^8("F@ֵn~&V-r ⒢eCa8G`9&$`$vNh2(`k_k<Ϭ2>>@f ,hHK )XZMk}ş Lʂ #S"bjzQ|M(AaY%14zLF7 BVh4z}VVV.2Y#4) :HP\%k=/',u/'(P(?v׶>ګygRK 813i)d#?3LJŤtG` #[BfD:CnB1pR&"ˣ~*\|Z$=Hn`&vĦRXfp&Xe1>{ vvNǏ7i//!4Tjzhx+YxK_LJ0\˧dЮ` BrIz*JzAb2cy4ϡ .@_ۇe=MCl\pݵ!t|[3ʦIGw 蓕iy,GJ˲c 1IS:J)Z2CCCzAE$ xD`I&uLR eҚ^&lB!BRn%\p{w]ZAoڴI?f‘H"Z|T/_qn[5)HF&MQ֎& lkRҵ,{;Ok#Eر㩃){hi fCݚfh4†EV+\(K~2)zn],$8bDku V9O<ϛ-_ 0/+YE:h \dfdbsw+'޳ȑ;088dt=2l^g"5>PsXDL&adgaپIb0oa9~؄L3ςQ4LEDz>i `3 ߜa,$J#pXJ%""e1>>'U Bޚͦ"Nu3t:Z*\.(8:'͛7_x'5Br9) \A$ahhVʊn$/a= 111qI0@ctdRףT*]rpY$Q̒b1-s%Kb1,tt*m|x>Z$E@Ƅ> 8EMl7 g" Y2$К(Ե4 y:)MӶm>O1_(wCO~#M\o}QS<O3<t ']gOq:h*;R,jB%"Z-J&6L&s=I,BN)#$(>d2zJf^HaMKֆ/έVKGKHz#̌&=ӋZm322bd"_ؖ_\"Õx (t3=Ĩj6ӌf$i}i$Fy#w01>/rԷ8}nE/5|o'^_k* ~—ﻛZSuH$«^;xoc~e/hk|Sz g/y/~Wo_2rn'~ Zn& 8pba.U;Lʖ/qK(bPw Ho Q7VH\Zd Ax 8 \&R>aq`fM[p2J+*0 p`"`b"Ibgljlo2laP6aP7Ў8ne<^!&7d6%INa]d=h,+ hg)S2Hh҄HtçX8ie5Xx0%go #lyN 6=jpuAU^gffFpXK;CZ>zNzR5 pp\VmJli߲,*5nkz,$Q9T/̎J.Q99Qj5HR$IWViyyՔlAp###:{xxNCauuUTFGGd2zodXY*`jVݻw1<<ķs'T۲(,.w7O,7lWy+~ؚY0Looyg+n3<<(߼@aaS芃.yMذa׽ %_]Otv`lPC:]fOq:dVztH囲 Y!PR{"Nw>g92c 323 翦<6T~ho. [Q6F~դxC;.B )uBv $obbBF ; IDAT|>MUNG쉉 o@Ѡhh~`dT~vvH Yu:::Ȉ3Nag^gllLdӱXLDm4&9)ZRD&!cccqvڥ?J ۶IRz=*Z|eϬ]VT*E`Ф>}Z7FIz BLMMi0?M?>Avlߦ?||?wX!ۿ{o"/}nxW2x[M덧tpq!c ) ߇=^!9gh(G& *! vU[ c5DSI:x4}6Ӈ  "@ x*X8Yg0^9mF-cq;e*C ۊ= E(5 R7BOgx츢8L(P_S|fP4PzRH2J7u8\÷αXT(0 هmu?AQJ"47yEffftӺk$I  mqqQxY b4M ,--i-ˑH$:I`#T*~J$d2-?bJ%ͦVO &Q9eȳV*m[ᰆd= qa 4]r_qQff42Ν;ϭ_wzj5S{w<58A(4Ps5M: ⿽^Z3_(淼i}O^O~d2wݻv[?~.I4uݧvXq4{뮽?)7 \xko̙|;?clތR׼/s{}JI-ArmY.S**q:i,m4?0rӊʣ; `ie1p`un1Khģ|i]Tg`4|<=E%{ iDYby[6cۇl] X],P: {-?`$qU=;k%bUP>btʠn<`^ S/=Y.1U30L`Njx4###h'&So\q G ċU6/!2whuuT*E(҆2%$ ժޛ-R.#9h%+I i23$ mKӚg\.3::gļ'Qދ @KfNiWD\j5[̌d%\| Ҵ d$j*y{/ZMg?o)ϤGz;\1[ʘ"f@Pbh7ơO@e=0|+g3="%1.Ҝu/a9w>[6A^l,¹4Ȏ#}E6aу a12ć,<4ۖw,j4ؽ= "5|ivЪT9>usp 6@l  Xs#"brU`e a>.%bGr0u`ħ| X\ﳺF2ʔ/I.L:f6"S룮ɤ.PlfYKKKi}Bh$ VWWb)lR\1m;&sI$lذA$"qpr% 6oެ4dg׍D-Fжmkm^gjjT*̌QЖXȞfizBF Ouqt^?o)Ϥ=#& cĶRz8DKyD3Q &9Sa3`+*;%}.{I -R@d9>w~EjGv).)Џ8f@W\f)*+Na'fBԀ^?ax/tNq-4{L^"Pyb mj!T#,£.%]=F 3(&QXg'M  j I{Io9\Ca WO?03G"EvF wԔ/%&2eJ#2@XyY#jnK2}ǡhh*p1e<6mٶDiFRG<#$Zġ-RDtZO.lV% &Qk0 :]L&4M:;wԄpCi-'9X#2 C"35W]7gfxÏ0dIo2ɢ|wspqѾ" 1Gf:JqfR8AR e&CFz<Q,[2N(EHz׽6JȎi׹x{fEѭXGh2DTHmR=Vdljd8ȌX?psաɚ'0 115hvx aFo8TqhVm `:, ?gRv@t RTY 9qٲ]/"DSq[u>9\2 M!0,J4a'1 齿VKw xv<Ƕm.)b41BMWAiON`E R(|5ENaCSZ!^ShBeGѤ 8]-rv[*HcH6 :4N4OŰMSIlsLjڃ18bP${̄dn̐-);f0A^s_ qK4mm":?'0mj _0%B u0C$!3> NMĮ+a\RT:)$T*TU ܲnݺUC1WG2)YSrד|^bR"k38sE>zh8 4Oo Izqt:P~\.FD4!XYYMR։Y Q,qGGK41i>b4؏-AiN`/qIM f}>d`R0(@Ç/);x}PwzĔ"ظw0#8 aNJZ PS| b0tkR 揟Keb`"S/.V?`27N_t9r<C5Bge~XHmo1vm&.2g ?ab=sE~v0w$[GSX1Z #ӣu, #!2ZSfWLzl6@EhT=t% gxxXG(ym' ui4!Tٳd2RKU-O"l@+Dm%'zN2UtA8DNC0 JVKg $^T*Id2I6B\.jrתTgR-Aa~ ~Qu2]I vNd6ߣk{M` ΘxK!+T`m,[,{ nG-mzc^1cn3Fۄ{t85Dy$nw DbIrScDSqUVfs.¢G`HZ +˃id X>S(Bq}$Em;m=N6~"BrSfN(&Gf 3ϡV4u"3H@[0s}pr]q8w5)ɲכ+OH 訞 l6.D"umfhhH9˞K"ՌFZ#ZJO,X pz*SRJ7N}{[ }9HK&uݨ MHm i>bQ5b#?l {nֹ0*EH[&-w3ȏ#!y}ꅀD6ьqtҀ06ƌot13+){̭} $E|*hztfmS.ŀa(E'p Ή퐜a6vȦ*ޒ> =`L :B)➕8 q 9,v-:`az9L>'J]"Ŕ+X_LBwnRSMc)Y84I$:#0??$:[N4CCCr"cL'9Ij4l0K™ MB&MC8 8HON|M6oO>gg8&–{( 9';עXph'#)%ςat]m6]5] סG\Al3 lzTV:.DSY{m?ztXV#]WCm! DXS1߫W.$Fw$1fCX aX|KA#M 1pĤu"ljt<ډc`Ț!k=m*G f]lq '瓭pվq]d [5BZJX[.'+>PMdbV[͋ޟ EN YDH&ڪ/i>Z\ MF:GBL2RCD9%X XZZҤcqqQ{ à277Ill6t:"Kbh h44,?!%O" 3{~"it-ObOj2p\>=S,n#< eb{3|"V$?tylH)g|.1h"&-p=D0T]-UJPoHME󈭝>}܋ `c$5pB<,&0ΈG8P*xG4|ozbpJQ̀G =8zniXqր;7G޽_9@=P8NM'WJjz^qd+>3|i8yRc6usV2$'k(v2.2d7 CDǹD٣ҒYqqMz GޛbjJ*X, "甓LMMf5vu3_A!_ d뺔J%XimNGdtr1|bGVl*>ΪEd#ayISw5@)ř,nբ E:l0{{tLP.4caHvѥXvۣeID;$MζzL}=DmMa0g>!Gz;αf4}z˺bc1r/$@)pIH czB kooGҨKBC z 蜣|>L"FvЌX,i=>ԓ73CO32IM$4w}6 >` >I8DzCMPcPJ z\\%fN w]\ Q P(T"W D$#ѺeYJ#Ia(|< \ L8du %b ]`/j$*Ծba4MHE)6ղk@:&b2QՔ2 ^7JP 7<(q~߈^}Mm2<>F g% .7&݈1Ҙ?%)=b,׀?&C3N*P[bt[NI\N/Oi}$=-qE<討d42A'Q9:G: Mâ3m0}0V';>bR@sM oFB p vW^!11gz+& :fcm{x^c,Н 9nqPBse@-bM' K*"*} m^"ŔSsE)H,I"fS I-?B sAl%JXG䯮RTJ/62U<55% !2SJ3> fS7R(; Qɜr\U"cV[nUF . DV\zo Llms䆐V1Js=2`ϙL 5'SBn$Kmڭٵ>Zb&oI;brP -QhPDZӸ]nE+Tf=nϔ(Ld!\q6_0LԷ-~brw⼃iߡ1ȏGdC 疏lFNrFX MMo ^!NO%tʻmͣx@dA5j},fT/PCIKujV@ \.UVjl'Z]I&E7mY% a*õZM%fɾ}Pu(z IDATN<$VR|'Q*p]Ek|U,Ug!ХCqG߸*KmVWW)*/..LI2,ĞZ!>&$$"4OD'dGwG 5 –$Qc}V;Zv`0yZ@ws#}M<ScvGg HQD\6;[뇬MRXo2l92_F S==}_`0sL6C>ߩؓyI]ӐQ82B4 |)Elf9nLȤ^^^VLâDǑ^&EW/ػt4MlV]T"ՔfƑufLNNT|J=R 9_۶rih4 1s(P}_PKŢO+'ݓ|lj |}Yz:k.*\)mȖ+Ł  Z o-t$r:QНt|Fa}ueEFFJ$Àc]_t323MOѝsIbl5k0MLdee)$뺬fU21Iq*_|WE)I q#K&"e,ӳzeYR(/"dRM[@ DeL*222 , (d+˩NAl%BNv0K (Kv;5N+t*ɾiB7M}MHd|?P&':ɠj7@`4'8:5D׫$"oiq'* c>f\7 X9(]t"bK RbuQk$adlھǖ񈌭o6oFoeQa( 3~E2;L\ztޒFsL듘b 96<{?$s:p]fӳ<QRy^ȦAbʤE~Kw3F֍Ag !F!lmތ8 P*P!eIC%0 hDdq&Q|(ͪ=ɀrC7yjQ %n6كiYF$6 VWWidYJ|qe?z!mN/kuVVVTP[B Rx!x7mڤlV0qzHfQ: Mqg ؟8x|eϻ38qK$^]~CnWT~ڣ;oU?S߼h\."IA/[FGGEE$I RJ!PDBʢ^XrWtQ/MNN*G8Z_d2+dr.S79ɴl2MS#$ J j]ؘvlڴIbVE&Q~$a(p*zN@[^WVLFuib-]Osݷҫ^ӞnG9~ i,-/xӸIOlq7s͵`zj˞Rck׬!J7Mٱ};m?H6!+^M6ߺfgö,? ? "Vm>- +J1{{\C$j69EcC:*Xd,d84#'nOcz,ܥM s\4==YcRK!Sǧ;hñFHkìEl{(DP=j4{LgS,:NĆg8&C!g`N8  }%CtSc; ӱ>.`Q]g l٥@&wt°ŹR4fggfdYUՋHDMTxsXh\.`jT`C~'nfjØb' D3<<8ʀMK"p"g-s$yQIHXj\Frm.TY s J{4M֮]˲XXXPWv #bM!Wك,;d&A%$4\9x0֭òL>zx^ׯ'?|~SSDa(ϹOx/ꥼ_WEˁy>ĻW'䲿 )M,7GP#ݤZu`r@JsN}}L>$h$Ͱq& klNtVd =͈m`YG`f}.:Be 6 8R@4(LLkmt+bwC7 ѭGe8 uNg5[h]jU] ;}JO hI}6L ;S  "KJY`UUJ0n@Y̕9 e㦐7qU8j\.SU-xrY>dRY=d۶2s8&Ȉ% Q,q|i\I.bQ( p b'uTJYE .HP /.Pt{G|z{IҸ^>O#HW[oMӸy211;5kf8s8|䨚t:{fַ1cn~3R)֯[iu/W]ť}w838 HF>,;6첸 a`:a.@&Hu#ֽơ[8hx:hz0fq5{ ҪL0kШ=4Ai刕Dh!i䁡:Y6-,B5<?dZm7 vh[.1!AGm@0U4LRhF\ DH{챐c&nHgeqAM3 ^M^g;1HiaomD@'uap{9(;ڠ@&EI4[/i/$g<7g .ޱ$ȧyx ^㜫fX"iU>0j;N1~͖'ԩI7;ܶu3#"LZ*HETdWBʀ|Y[)Pq_! t" ZZ{ _sxͦ]ZZRtBK-!,//+eYlقa ܒkJq.\꺮䴾+V6MS) !|eYx`=n6^ts83x;ގzu:gV¸w Rؚ QD 6!u< c!3LP2a;%*Gj jj=7CV.'`ta >D!e5g[N8ñ5L$L5;-&IpW4<ǡ/C'OG".RZtVk1|Ƒ$1L0' &/p/"lS=ıKi$Vja<8l6U5(M0>>rܾ@u*+hU# 2lUT7"|?tZU`KJb!XGhXT2Z#`IfJ$ATMRy%y")V>$X qڲ,:.`%8} JE%yBaJX ,+y#eX~p50#Xi:= Ԑ˶GfXp+cw]!5[kCc &ȕntkm~߾U͈58 !:~VD(^>cI$ʡݥ}n0(HiM kSn;jB3r}>J벘$nϡYJ:Jl8֦""e߁pz.;C`Յ6K:Z iA%Mn:K yw-ʊtRdK0Yh|Hf٬szʮBUR)ZzQS(ġTD"Ku[׉H  /APέh8hP(d2FGGu뺪I@@, ;jCkATBҝILT~ap;ˊSC#{OϪ|/TSVԎUeÕeZwr>c@U>7(|>OTB4/ E1cs2::0_)sPEU<.nhH$Gy0,o6I^+2\dyI<YI 4o\I%]XUȹu{I'!_IBK2}ߧnnSImEbQAm}, ۇ_CHvc5[4M ǀ{Z_(bS4EJ`ы=\ac?a1\dl&dȶ S!IKp[Ԩ =@uр:2YcʰؘQ;+STqt75 ELi6Qs]nGgOܐP+$t+O~#AqurZ*du*zju`Խ^RIQJh}VL8 9ڶR5SL!K,xx\!$8ԖNHp|Jg"3UIt.2%@|A ۶aNdx,$6>l6ׯWl?+Г$ Yf͏O JWH!?'_c9:/m`5ɠH5fp ॶFgz~&m74KՇaUl"? EAQx}2.ak=^kGi6$Ш.2zF%Zr Sױt-`(ț6S".n[Bz{c=t . A 0ChkfbkbQUZa|>Ą ZWRi7 ,RЎTvaTtE# blVzEJ"@VfS$  f.'Up %LRK \T2 V8]f; /Z}ddkhhj)Cl޼^GRQ U@FJG%;82FZr-D, }Π_H|?8E;;#Gg⧨=v?V?*gټy!a M Z߀|.KjTF/v!9aS0,GXפ91iN d`%A}M0 IDATe,BJC/4H\\$"V SXDF)nRAqܪN>GRi9Yځd~LCg%-g ̦IooNIH9 ƴ,ҶͲh5L/A@m[U|^U~[nUnEt:l6k =::ZTJ%|>fann7RT^Mk5얅W^"G>@9D';nEe:$IL\G,hHHU,L?V$S"5Mm۶ilZ;H$O42|f;?)d~:d"W~a>|Kt7|\t!O)?3ymtWxEߤ{N pؖ=;^60Ҧ%GZY֑.]a6GM@-Yf{.ᡑ`1OX4 ;MtM#EXQt!* m)5&Vڦ5ۡwߘR'lXG0LK]nE~]ށ1:Z)O%M0B zF&pj5lohS"uHИm5A7>_*R8"?4$Tݽ{7333jc\"NHexK*IW HU'|V#ڡ! ;wL&vq]WuOr}ߕE=1ER mg?.?!>O]@^fTw5Q\s'ٳw?z<|7V^|HaY&C266ƫ_ kg'2^ q>/r .4M>яqQ^a:8mw_JZ-e3\ U$/#;~dM _s>6}i +WՇdaezFwvy -jbF0>eXDNDu ְ$ݥ}gyGtAͳ}DzK4z8&N=Sm˘Lmmؤ6KJ$yh ECkyYING6DKIW4!3y/gioX,L&Yf QΥ"Y,ۨxض䉀 .( 2"e*vaaa5*p \`bTWp.FtǓKӊh** brD+| N@$?D%\t:gggTU5Z "}Ipk7_g>ϼW11>X(`޻xMߤnsYgJŴ7q=Ϲ>QR_a|_ZR*'͇?1'ocW_p)˼3]lt]5Mr={/—^rϺ2o/^JwrapEN7nZzS04ig=ݻߺ۷ `n;ZeDVCa.aQAaPE2 M.lbJ"mcE@A~4BnR8ܗ,ZFty%B1ll iE$KKOʟ *0==M$H0==$1B2 иy\Jd2 p1JΒ\ #ۄ/--H$LAFC_ÊE\c'l^?iyӟO8ll߶zAF/^¥ "TwsFͼt b0 `o cI=#HFHR^A#t4 ,bӦM=K EF|e Ð;v(xJeT$HŒHxJGL&yB ĺȑ#TO<2 ccc4 bxyӹxIq>>P5Moޥd^ke>Geiz?k#p]#G77|_?kn~#b1!_L8Fʼn5 ]W /^"6nbmώ 9ؾ}u\}/^WryyCYfM_SN9s9J'_$^qӷ _͛70<20;oc5l޴|{|[幗<̗W(33<﹗ʁ=h?SNSuiǹ~Y!V;Xe b<xC@ -?%xlLu &mlf.oaO8 BN{.覉LxKv ۠5MQ<ɃVtp"#']b/d6NJ:^.t8◧him )JIJ,岪 /c2T%Hb"'P!5M\.+x'OOOAB p\DֹvZ50ض2WXR뺮EC$P%ͩ-A[7yM䈟tBNM$O:VU,D s 6mRj 6مȗIqHuVWWչ畤-#9s-]dm'm0U>~^D"Mߺ'?_عZb֓{n\+*28FE㡣MqI?E\6C[d 9V>IrS^7D Pq 7tHjSQ-p r9l:.r̈s`@BOet aw3|aa#?7ȹ S,F$nAb(Wo# ۢ]P#?9JvtJg:8=knZ|v Ù jUi+K$h|D"A^WnLF-Ȉ2]*Iī&dkתthh8+fIT~"Iu뺮Y@2TUpNDFBdYD$թ$`IX6lPЙ\3%ya(hE5'V2%.^KxDbe-%IB8G% kWyth 9Wu(#,^l< dc~QI -3i?ҥ) q6SSS[Q_&=J"F2lbh{M&W,YHsX`)ّ!ur0at;x{u:dF+9Vo ѻ9tbhc&-5^ȚScX)Fw #.ma6;8p]iMr{zjCUj2^WtxH['Rt:^W3RkBvYy}l)AS6B-ZC,mljUq$JB?! (2Z89/0ȈJ qY<JPjU D{畝ʐR)v%%Iꏧ:,ʵn:z=֭7~.iGQ9g3}ҁ!QĈ uSh4mV4;/ДF2GFV =ݲ9tQ${j5B<=Cu=m.xKش= ـĸp:.Y_4|Z6\|hV*A2J&iz& GM8z"YeѢ™'e)BSOw>WA!J)XWv]A/E233O>WS2w8H,'$ƃ`] q\Y IR?aQ3ɵ^$l+M(IKTbx1PyIr%b8/`rnH䩢jӚid2q~y=+++|<7FoSo493yAã{l#/{0;kffزy-:?856LM>W?3"iTJ4'$Xk86nMwS;=i@0<!QIe24,įZ2=esμ<ˆ%Vϓ̦ۦ9\krV FڹM8z#tTĮLM̯hDVwޙIVVw{o{U ̰ ,3"Q(j/j!&5F$MT gPA6Ye}ڷ{oQuX)fŰjT"zdkGq.cT$C|f")4 Ed0Nc ݾ%v iftɡci^q=s=:2q?GQx3A4'V^3vBG)j ^#Q( xp^6JK%F)Q4@²Z݄+nBNU.RRgU<zĦh 18>K hBG4 fnt-C~&08D٬[(HsaLzCCC ͌3ܑ\E U0+ YΏYh+Yj`нn1_9C8d2b`x뗨X)gBA2rl^d8C!YFWWuY녩 ycAkluVN'\湪NP(WQilYuf͚˯ʧ,'| IDAT6nڌ-R$ͳ/p Q+FR 5p3zwS+(l/JYChmU(g |e CXU-Q 6Ƙ d58AtmfJ9s \Ϳe2`f4UQ֜x"=M |+U*BhVhXx<:iK)>KR{!hdhh85.nQ'[Š֎:>˹ؾ5Mkype|c1棣.";EqrXGǗN]6jU8}BQT%RFڥU8JBy*Jf {$CHRd2w~dq2TO9+?7{|+w@>c)T%'''$u 0|ŒKu]0›bD5kM4юL/֨k$zr&jߏɲWO$y G'qP4Q.c&vbrŢg`VL:g1hpCuU|&gh8Nà7ZXgTvuj~f ͩupy31֯\G$`Z!@4fk@]7ntV>fs@~ p1bHWW; X \1ʗqFGG] 2["H$u׸J4pDUe) lbIHUfLb.#J*ëJ3q+gON92w%W,uLjw8]9ٙIf./qBO"/r9$3gd$I*$Tk5N[~Nj55Ms%yf([י&NV= oB`ac>U0zC#U30* f`ӓXf- fS>OR).qUh,5Yj>)`l4ploX@ B(܆ ϶I1+ǶUZDt#`ӸAjfGkκŋo,ڪKTqw11."d'FA|>O*r y=2KW= /]PPT\IV;;;](Me2rD"A&qL&*!p1U*F4?CQ2 MQ!fwSTKî)rK4q&eqBUIqY |r|c$ϋz5v ֧31߈i'̀O"VO0C@xgbN(,i|F%:Ϡ{F Ƕ)'c5:% j&G'cŕ~,3͒xNOR:YԂ>Z`(Fl`1xͫQ+ڠUm*۷dvwwn!Y `"`#'pS5Mcƍ܂d27`ttԍ `jMB":;;ݚ̜O C4*O3Y2G"}3g, L%8hD gHa [~*uDAmx*J Pl<;Ba^Jt`ّ4ݳuu4 ĬTq4ŢbQ4M+`Tj::D88XIw?Xx|^|!{J :/QKA|QIgW'%=B(cџEX:TiGrK%c/ؘ $I^}UX,ED1"ht:mS;Jjx1-AD\v]$% U zyqnlT}ƌnpy 2a &Dw,엪uVb[(tGQ:d. =8in glleڛ8 t_x̬q7WEͤiL`AW߲,z{{]C-^QTm{)JܩY2KWőUJ)ɤ[LH8îsy:ӐcQ%WUOvT4u3)5N©=ܒNo髐LJŕfcx:HƖ8jvSn:z^tyt0ў8`m rkVsL.^cUR"cJf(-*R-"r8UT#p0ĠI3T dIm*b˖-ض2K8\.GwwNBѕ_PHboĉ2'!ٓPfCmBcDJBj-iS&$*V(dɞu|>:={kw+̿}Az>n۾o{I4Mo9C-35;dk-0[ t]C5@*Ioď?Q1tKƈgqں8y&3հ Y|>-k?Q }$zwnՉtnΫ=ǧSӨ1504ԭR 6*5pd,IRCy8vXѩdJh v!QRahs㸍T%hktyL5Ҕ$siVL&X,ك@̓U\F/A4٬;Vff Q 8U]TIeȼh˜a1;ͺ#6Ն.#)PK,X,Y8rq1B!˜,EWP.٠@qR'&ω8@ f9R?&)尻p8Lf2\ɿ}7b&^y/gbem;1W}N#pB7U$m͟IJjG u&۸pEFS4F'473Z({5|`ߏQ691Z o0] hǮ{K.=Bf n`pZP Dxѵ D`"Da{jC/댕chQäR)zPxuTe%aѨ42D1cccXT(B }{fRQĄKl4İʬ* rn7s{T\hS`o~>8E z;/UzZ>'QSM@`&[nehh.X⬽^/L=RU0vjx!WYK/}C b*W3 |=zҥfh4ntc4}>0fǨWmhƧ=g]FMhB5G5Wx `0u:`o0@%Gx05 N%@)OY7&Q4LM#H  6cG(Q0~]C9Gy,۲!R9Hοi;EH驑{,ˢ=a&Ba'#(DrKLX82DZLB ^ٳgLUGR.]y V *__뷝:Am0jDk_m*:@B΄bH4%͒N1MӽV+MmQ%ˌF.]XGM{Uywȶmַ_|jOf!K)W2rtu[0:=gӝ& dD b3zi:JۄA!E&6NjsZf/Axm#-N@5ߪQHWmFkޥ@0~1&xRV'_H$Slu;^L䝋bC=!(:::A--["yȅf~&+!q~- 41$KUl6gfbbm#UPOjgm,W'{8B\ sLͬѵdkiygL*V,돰|ǃ0 <,La:Qȑ_J^e|Mm>SҔh9p2Bz&ꦉ?/Q(lȯH&Aܱ^Z͌C$cօ5 _; yh xMHQdUVb xlݺEHF3VKDRfN_;vH@d i{v"#!5Mse)G/Ra d6tz3S2'Β$bq>d$\1RQڣb\s"(kz>mx\l[kyz38qaP)|:4s #a1{1{$ 1ǡ B5e{='I֐ϵ E$OIt/;kzg fP4JPx|>4AI?3\MS4|JDqv.@0t/$|A MOPa vM'7 ʑ+y!ʢhԕ.n+uƑ.c;(dӕƫvUUyOXt?]%ZM$DPCH$J"!(Z-p$L'GXtNpU"ϻ`u M1 ޓnr<5dG`T<~V A j YfTQy ~+ldlN)tĩF0QDE2B@$F`)p՞;3͆BfUh4:e=aW;):j]fH3T:v ZܻZbQ.]V`uRTKW=$naD1LAגTuEV4u8H0 ,Mcl8Bi,uNPEg";U>[>/0>su1:cLtYhMxƢ<+qkQ hfA +/Q5f߶E<㞡6A @ x!0OekA_#B))tlblCoâu#xMKyR?U%=Ҁx\a;r97,E2 ?Hsͮir7f7#,:YRUYOD-H+Wq ׈;q@CCC.CH`#1W.݌Ej)*MTZV<B&H>!$IJkgW Jt]g혦J\pzM} jyɆ䴁9$<ĦE 8>ǡ'_1 E$1'ceuj8"!<^ MT rtR+T1ku_!F<άS5"U:iGFPAF0VͦN)T*1 vMX4B:%QPB lꑮ\O,R\bw"󌏏Ӄg.L"]U9cr9w&bI;ί2pT)jz%Q"-]`q:;;zn W{[P(#*Ecɤ<LNNPm峔F7yN6݉$R?P'MU @>z`kz'Ṛ8 :PuhO2`˶m5X p*ɞ.jDa|?v q&:@1i#`P/y<M$V2t`kgѨM8F gmuR)Lf zۼPYs/)Ӽ䋪DRѽdoQ@1f14hQ<,u #Qu"`||n0>>Nww7j5RR'98KWa+Q&D߂ǧiwAN^\(YLSd?fxu]wZu$-ܧ&Nx+{ NW^8Q }zbĄhQUUGLN>wa'#1ñm/0GFtʼnW +c'L岃lp44ʹ"x1iJ$(Nd05&ǨSG@2N?^l HF)p#RTxY:~c WZB̪{e .NeUE۷ooߣjUhD wc B9a&@KvBI%7ĩr</*}8H$"-L9YB:MozM} r[:G+IqTcJs!>Ǩ}J7сͦIB=4&i|I:u=hAd~ :&x>(-%^͊`;` ?>McS@4)qM#$6'uF+6h2}Ivxz<@VEp|r! * PL *޼'K}\:G@DH&|9*8@oo/[lq ]]]nz1vN{(Cja qD"-R&|ɱv"2UA}_1̲,;#Am ,ˮ !H$dY .Gjj+ 3 4*uڧ`q0fMx{=G؇U/e05 );@iC^lM2 LEF+hbʅ"4Y0jBT6 y"h"4sDX4Jo >2#蚆^у" M CkixH4EM Q(D :SX*1jKQpƍx<wV,B%owRV39,˚(f0d!rlڍz̫u@ ;e Ʈ.mT?JI{,SJ6a||D"nF嘻H7:B)tzM} ʹ(8ސ+맶1+۾tcyh%h494:{ʅy`ZBiV)xq1i4 O_ױnj151IMw$1#Xl@Ka@ mr3Oed,3qW[HѴȤ/)KQ[g;ǧdҨz>ԙD2R|4Mc|||JHLu\LuT*G8D*<%SH& õ7G^/}}}МEJY-TO%)˹;݄63Icѻ!s B%O\nq`߹d D'hߴ`|$AM7 bvr6xS )U'{ȅüzTif#L*,FI|mRR\XTwH*C`)tK/$4Vՠ50 r\ˌƎd¬J, nTV8D– /\a(Pڙ^N$"ķ;G ρs#i;e;s">=J3>wuԱܪ %Lài$ LC=vyb#ԋ>"$~ *Bb(qȚkI8WaxSԆ11.#D%EV@1N{1b UڧZ]AD,1brҳJV^DN1˵UK@5"a!DHAŢѨ;0>>K͡l6Kww7eb1KԟN, 0MK1pt@O |Flg)Ny%?0,@YRC^k8jc>Ɔ4ɰn@C)A{!!>KL[ǻ(GaKX_]'jXMHh!qCo(zG=ǃf~uVW=SvfXEcJR5TA 4UVC#>JeNL"i5~ɖI-:FQ]PGztP/˲d2,^xNOt%WUjh;LM^j@%uWKe*dk*sj85jPse~?\n'^TG)oLQQuٓu!s)ceƟ ` @0XP=K&veY4mStMT|>meqK L9ZԠj-\BJ]~h4RPQ 4EA -LP.c)ZBNuGd066֒ HGbS۷owqtiIz{,$ &''w:H3O0$LR,]Iusit V+yFEBUe^k:Mw[bS!`:l 00C@ӡFyئ2\%uF۰!JkLmfx mif"ۀmFyq )E"TvoEtc_QHЎEGJ\%jr9&ϴT*isA^{siS1M"@{8~ M]]< 5kTGE&wm.{oXHqdMCī}h՚6, xӌ(HQݥiU! H",ѳ?Lr'r=" Ү(5l7DRu)k]U9j@,m2r;@($zSI& А8JˎnY i<Q?1'I?Pa%K&1.~rLJdR$֍ky{mFga33@ctbdx'w7 sT4Jgo-6{$$q*W?8)O0)o}4۬xP)c˂dE4]\ݛ"8uCg> (Km36vi 5 jFiYa6u:JT0 k u˺munJ2 aͳ I߃移hmcT*֘X7ɠ" DdJzݶ5a`0H(J)ohw4 qX,J3*vݦP( MUVUY0ta5Ck0L2Ɇ!׋eZf: bl9v8eZ Ý,Ϧ?@#4*N Yy: V7xGMJyMDXrw`AfӐpl l~5:6I #'aiV~5Fw얓O&%4 $"޻XL1IQΧqb14Ha᧝/i9͞ޫL@sv-WSv;ヲ~(]9m; ރ;k=^Ykǐս^q q0v!l8kdz_ V6M^9:sx<Vegzm^`}}~}հLw*¶g?|껄Ok16:`DZV <t{3_u‹VT'w~>_O%t|6w@iwsk/:Fi\1As Oy_3*͏F hW^j7Q 5c7>{36,2&ߘh7w3CٛTpnew<|׍7^ˉ^m)Po7?: }}1`}Mb<[g sߣ)U^n|C{f}^pK}ɧ8-'p nc̙X1Dїirwټy K|V[׷o}/}sm׍7dxahp]׹퇷+C9SW,!On|3WN˱N]::,c/6,{KaF6{ORp 7066yǑGIR?7of͢\.s7o 箻/g…ضw3<×?Yo|H$B(Kp7c1E^x[=wW,u,w^yN9.r.WrAOXj߯\L__#nF)y<^n{׵W\IRqի}] <_=I&qԱʫ;>r.erbx^BF-9g=nd)̻? /g{M7=|b2aF>?DuDo_Q</嘏3磡GK 4RzmoxSCFX,pB..RVZOǜp {9e4~u[to믇}k_"pYP8|r_@./qφ{/ࢋ*t5 V#hcOֶm,Zt0wvϛ o'gs_x1X~_9]f٩gꫫș׵WC.z-_nfϞE_o^eAf?usʩgOp-|3z3g /8Vd'?+~H$2sg7}'t";fs0o\zpF?=]бY]D"}p-Wv5_~;#ϏO_c?N~ߣMރ||<_H$S]S\_~җ>6ƿ~/l/1uŌ9 7-6_ERaƜ#>gƗxy{/Ek*/} >Yg?6\|1j~yO;7COpM~G?pW]Gq`Ӧ׿|ŇE2G?~6>xy6 >ƛn!};n_^!ƶ͝a{'&9zQ{5޸vGT\mJ] <~: ~GX|HO8o~x<ކR sLnz:k gx^B_z|nAE!e|>n;6ᄿ9ìSfށ?x/6'}.:{嵥-޹.4Y}smyt+W|JWZŪU8v7b]LLL{ʿ$#=ڶm7vN;8xwu0h@5N.J2Nl =1]H^ŲL޺ E 5{ɒ38YO.Ne] ᫮/=tW >IH>Xxm>Oū<_$qr+SF9"qEQ}{Ǟ`e-owϥ\ÿ5_W godP'I&hQG.SWQc9YSN:SN9p8KwߏiZ刹s8Δ8a՜r҉YRoNz*/ gq_we|&=tYCV o 1¢4^܌Sw?sfM0YfvZb+V[nk+`ӦMwyK}Xew4x쑇[ٯz!.".袝btt.N8iO8xwUVP(ؐatN^'$N3glrd2ʫi,9p.~,\{˪sqȢE 릛{fPt)\pOW x,\ب-pBALL7^ۺ~Xo/B 3f>3Dtg{: ,g?SW~[n/V^9<;w_!(4[}>O\װl|?`S[gRҋ/S`E|WÖ_| MљU#Mv\X|Q,: xګahu!7_ϲ-ͣ8;) ,`}p7OccZ^_}|_n'xKw~i* T믿-[p '㏳qFx饗vz\w,߲%-m\qaΜ9\y\pY nV"˲mcu{{[F;)+$ ;oP,_j\rW)sOį~N]1E'ž|vGm?Oa1O+wdw1䮟ȣq'Ӳ׾·oC/&/poS,:\0 RU8ge3+V,qͷrK]4-:Gmg.ci/>4]|wqga#4whK?ͷo<[n^K.iùx|݅7r{pԇB%g'ћ O\XcbdJ%/ZIJSNNkUj[(J|g<\~\{X>)߷W3*d__䑑mܹ݇b!F3XŪE'^>o}SO'wSNzKV|B}׭H(ktFm\˱:`(|Q6?z}mҥP?'p5?8pD~هncZj|0yP9_nqe] so_`=Xk݆ ,؋,7>ֽ3g)?{^3W6I̝37dӦM̛3i l˱O_<1a hex9oXyo9+_ߺa۶mYڗ188@ڇ׺wqX=g6<߯9KX? }N0<<}8wy5YIgox7G{ߧyeor;ׄ=^ziilq IDATeIENDB`eureka-editor-eureka-2.0.2/htgen/shots/shot1.png000066400000000000000000002153721464327712600215640ustar00rootroot00000000000000PNG  IHDRDAfu)sRGB pHYs u u-xutIME qtEXtCommentCreated with GIMPW IDATxwXǿWw^F1h,Q$K콥X_4j콣QlX zr;8<<;;sݙeA[n:v(AAAD݂U!>I"  Nq~DBq!$ (bAAA ,0b "F J  ,!@mc$ɤ#;Nvd';N`WM#!₧LK%qrr[‚J͂> `jb#=,4[{u[6d';Nv^}bmˋ}pcAѡIyHKFANx|(t tanisscp|~Փo0Nvd';NZc>}xp) 3BHA 33i*RsŅHMHEA~!͡ÁP^]K *)Z5oAvd';Nvm b"A-!|deAD% p|)l%7AAAhԗ/|ATR\ܜ<!'aP_l bK1mMZ_yZ)P <-q-:z=n1:U7f֎0 !_Ꮷ(旷̻6AkGSa^/FmFlLwDp#+X"5gޤaףx+^Vh?p> .w q>447@/wKjhZnDuQ/VʷS 󝴴J "^ _X[^^!v\V_. z}%Vw`tF|Ә,]^:H\:lMhoW_TDJ폿x۬dm 0njnƩfw ƺ&}S}L t!VF +kcid%k#me ̽lHSٺQϡu^n_>p(뿋;qqj̙+!*?+ fq.]a!g~B&vQo8/?/]o6 +-*C` "-B&Nd'{]w,js%IBXbA'w$'X/6+ۿ \LY[Qzc/p}&r apE"W\`T9Ű7FNGnE#:4Ĝjɿͷje|kC7A;g3De`pD wKLQ꿛`H\|BLn{xD?uz>νNŹT;2Pa?wu*}b"I}yQ/<O꿋k y2`X`q/%Kj_ [4-OMLoAY B/ 7\V^,$tő>Zbahlɹq\ 󙴎z \-ai܊ƻS$_ntl *Ob.g_@xY' 6Ƙ֪Wǩd|>ba+.Ka 3}+ϵmleJ.ba@c^ԫ$łNlBt=ٿcl[:R &_$XK[X`aF cFȴgu-To8 r2>xq~5B܋Š&=C%WTE^g)q*Qr82xPL`Ok hl/LV 2Uq0VpM6^džk9:f#=Lo㊮3CNb3;¢." *ׯ,&q9FHz`s^⣃Я5`xx5aK?WJUF( P㡄bΗϾcB?둽>qJԊx HbGվ.Et>fɤco*]} }@FA eMgcg Y .n81܌JhG;K:6c=,@iES_3{m߭^W\[ ;l+vuDsY ?KSɺq/Qg%e54Li쌙XhTh6D-:{c=fxڠ%/sO_>iY'xvJ'q9 KסvCO[v.Q!iocg_`c_ ª /d`r1bB?]Y|E}by}yjpX˻Őo(G}P ÑiTVhiwJ~3>c˕ 4,l|7ZwUGuWfN7DQai*}V{wXAl&{iyhhi_}ɼNk3DۻPW2~[vv{w7 XڸL?+Z:febg:]͝cP OD5}ߥ2WoS1#ٙ` l6 ]ܬSCw+y!D3RAr]D;Of)NiOkű6+?K#lv\8f`D3~Y+{BsYu7_K)GzZ33ۺcΙ07buﲺy[V7e hl{4kH*>uXJeb6ʨ bB'vj=LV;waw88 90_;aPg tv6,;S~x|,aB@8飓%x 2᝜UȡH-Ybe#yMʉF~ pY,d+F!"{=+W5DGt]JV ϓW,2%zc ) gv..VH`x}{lPh9lc+-*#<]Euս9>EDj^&ebΩ1sٝVXI"7&C)|,`a^⇞w0ƽh` !op0'hfvyhk2D}׭1MqU"~ Yp05Ҡ&e<1kk'{]W'^Q_^t_ZotEzCo/Ky!j8`3 $ 5|3:h&c xM,xwg.UNČN,oLoQJ]t MCdvє) ]r i uw1iML+>">ywvIgB B(`,L; l ;}DbgJʆ tY@((;oUhdG3emIH*`_ѿ>4l? 'j՟e/T YLxB8Or0?Pe_}ۣ~xL4eЮOHU򢾴*9lݗi"M"I2tʜx%`X`!so{m3:1E9r JxHoif>AƿoKoQU=<QI/>\ R15,[vM+HfeEm(dZW9imgFJ$54a`=doRmgv&i믓QX\I Y&E.͘xνJ@~1F\|_"~iOQ,Nfa1laEbZū8j9TpΤIUnOǨ!ۆ4܉JY VuRъFzl ^@tFJt?Fzgl{ s ْ燺+̓4G&1'GKG3cKl\/VPVz\Nu9Au y}bUŪ9*NcU//:DK˳ˇeyi^Qiek1wXzavW/'w~:nhj_PtvN sCzb3Ԯ_E9_~92#cqhlnv>1F$̻M䝳s|1Q‡P&dGStQj^/Īv//=r4HT[Ԕ9A|ʃ.lm-"M)+DfZ|BǘT Y,& qu.97^Ɗѱ-,3Z8m_Y *%]>Mѣ=W+Xv!zE"T_S2IbE 0& mܬ,>qyXH(tX"]*$Ց3t'eap1ıJc} ++u4 :SOq_U!bk9C(nI“.%[My>&fwJx<ƫ8"N pYT5y1; WÃ4lc:ˍa2a|ݣ 9ղt$,&=7^'w }E$fK83;\-pfJ7 G&Y㓑[`T.'":5OZ.د7/> lS$dhh V^+Rrb-XT_9%x W_jD2T_x~^}bپ|a՗V6%O<2ҿ,'"qab`h++SfHtԞ[d[[UFk}A,¾7+czW˦$?<ЭNrlA;///PeTPΗqJ\2`mmcc0JyEZb*Jejo Z_1/W>X^J_>FAԗW/ό]|B=][z)T|+DnV rņP}Ag 6|uAQˡF*2J}ADAA "6E   "   HњAAA7_ 7AAQ}"/ޓDp)  mmR`X;K|KVv-  Ԧ ) AF&006A66w_IL̐N! BmL̐@b -DiJ(:AAMqa! D0)sAATl~ bw/::pm  \ ͒ " Rp8ԇ B5fAAT ]} AZ;Z;+O#sM,楦򟑙 /fR.3+ ^>͐YT6B^ع7<*  *UJY;kԷ9iS ss9$ UŠaZ  BK TI_LQc1u$p8;á6, &&&оutL %5z%57x_ľsUGvBc/+~ƁJlw ƌYmu Ajj*~Z@>+}Eۧ7 ahh~}xl޺Jeu65p`an^A=qAWEsY/q 5_NUkR+IDb|"]dg]pL[ 6~w. o|뇢]k -@]?>=[>ƛW qm ':JߺYTN=,aĶvm[ci-*v&~X˖׬:e1qع7lPݹ7L9lvAy*ddf/^çÆb݈#223qml\ ??CaqV,^$Gزi>zbO˫TF///,̝= U:_&eqQTn۶sA({7 sD6,&xh^dW-~{0_(ѯ(~Cz.>XMJO6GXhc<Xl]> =܁g,x<n_jG!>jlO#6%YWhנ5&V- Gdf{JEoLptN3璎^+G\ 봨P<~($HFFZaX5tXl&1|Z툴tXYZ"-- /_tG>wr|\t1@swܺ eAdfj{wo))؞Acll!b3+wCq9jgXh1& ~ 9pع}kqHHHQ?fjb X[[tLMTƆ q^#2uhԶ8so٤(p}ɻRS`eeI$A5aj ; ţAxt%:-ڇ1B$>nyWppNA.qRK~\?Q.̃^9xbq`O䚄F^1h. n˟olcz]3m30xcf05ԅf?C#h {plo&^ `ƒرr\VZt~;ZgSzs556-],+ FA:vh׊t OȮZs? p8Ֆ>}PPP`ϫۡ+VF//`77Wf]3N-plE9q.\QWW>3z$ן8yt<_{ s]:wV %/ ‰?{[Qb7.#?OEq ݫYhSs)dwF 7sQ\7N{oJOl6Bnn'74mnpgGU*I>2Am_n{Xf] Ғ-4Cǝ^16NlJ]3G_lX2k##;`nN=PPѼs|/8~$󑟟7oa15_pa"77£OW]PX=+|1hnnU'ˆbӖmT2>7jt1E;:+LRj4SLeqy|gϝǏ?iST!>!|>iؾs7:uh_+꺾BCI\Ɩm1olj% qB^=m?w}k#.ڮCχL:厧;+v;1㻽vsҩv̶Hͽ&o-mNq d"b8V*N JQ{R$#yHm(%LUږW!c: B o#\*#Û(*<ԃ{DQcPQ8/(|O3]ƏqTY GNwlPlXZֱAof 8}¥+φ+}@``4^{4Ka䉘:yJ>tkVa݆Mh }a݆Mظn5: ʔq7sq9t GP_dffb׎m5~~kݚU[w8y ݨ$⃒jj(J;-%+S‚="zGH}t߬ W8)'0Wzd@KFq\bewHKHde85HPL7!yd#x~~8j+:+xK,\QA>Z1;uTZQ_l722'*JܷVsuء};th߮Bŷ:;V`5ظ~  >$ճm%!)(]|uT3ؖ-H1˴{w*]#_VW,+S`X;4ė؊ s.SĿeD]:3ac[>zkPa xxOcנP™uGUo`+HxfaS -Oa`T.}1x+_S*8\>8,%FyTŮ?hÃK #KͧY`2^7`Ղɸ^ +X`2,IqF@/F@v9ڄa|#Pw_B]P_u-ppvMDa/QU!wPt  Vm[|,GlܸК\78By=>_$CƞS)/o0K,KU &?4򊁫G巒"\zǷZU[慬1y/6w7hYK耋/d~ +]n]t-n^Ck2iV/^|Y@Oкs 6}5&TqpDf߷A UWW\SHuAp*mдe8\`j6K\F9fH-o6 HF1L7E[f@(dԡx ZS*QT;ޑ4QXajOF#-ڇl@PrD+ w^ \PTNkcEAz"BQA(*"%r@꟠'*ADmM!   BkkAD AAA   AAAD=!" A3E9M-6iIt# "  B51diP/ʚ(-)^;5M\k8y "  *CN~;#1V[ؔNX5qpjQD  χ~(sAAV"#3fIfRDBzů^Sy%T)~T? 6Soʪ+U :Dzů^IZR*GO#$Dz2eN[fÐ̩3DATJ7Nm{Qp,V͉/ siRk]=9p`VVVHJJu}cpEvt@|:w]rutDAhH q|'Hk{Z-dM25Jp8J "lݾOBTT4tI_GP:3m^J={0U>Q" zJobyyymLX;chծ#\ТM{눌s/kptqO,y\! ޼ys/J"5|~:_w"M8?iS'cL:Fpձ?]}s!"@SפQEbiM#fMƨ1O}{9`ص}+|Y&M&puf=֭^~~HLJ7 cv7_MP㏘3g m;v6-Vf:ٽzv&c`v5Vʪ|%`툋fNGSQH|ÏI&1}*HB\00go)YW"bH\>oAI]xFL6[PX(&N|_r9erl޺۰ 7E`?ttpqvu$U/^͛4iUr?{!::B>LvmHa_0ߟ<}B!bIZd ϟ}}}<-whR;'E4~\=b;w_V-GV-[`Xz-|r E `HJJwuB >SN{# *̀=?n=wރf8{|ǢEK4jJ2V˖#õ .].݂q$(ePOMƍp$Iv Ť0mLtE! E()a#__Nؿ5~X OD~~>q- 9F*ERݻw1cPi9 Ď]jW//ܾ"x7Q+ 4kӧMů҅3XnC~h/(QSU.@{ ŌVcG}9e2&MqprtĜ_a@`޹SG}7~Y3gυ@ @L6EcxzW]dڔIhP̚3SLDCǃo8~}M8.®[ѬiS<} ,W+ͧ#FaIhݪ%B!nܸ.ISA=bێ]8|p "  m@٢w_pƍqcG+ݾ][J".]DX p`s8jc`hS'a7a-[`ʤ/$)->|0bʴx gg̞>dV4&~7Cmqv킽{~/2e@Lr͒ "Z Ae?zvЀ {:cтohڲSTń mTOӻR;uBN3O  !U47Abahh;ɉBQ{b"ADR PLE4 pPYQBzzGaj3^Yom?}ݿ~!!MY6FԪk!b|j+8Z)b!#_QSŘZX!=9܉`jauBI[o5" rj: v"]]}C3K&̂NX5}WODA(CAUu&GU1AVz 2RUmC$  H(rD XRiZ\GAA " ("1DA4e K)$AP}C>CDb VFA *ɩ$ʊ W#1DQP}[z "DDAQ?C/*[ڝHhܸq*-R:_A^ z"n 4&HE9! mP Bג AD@? ґ"ТNl2GH=*Uґ">am|ׇ5|0hG`j{6. f``[[[4o~) eTǓ+QQQ9r$=z-ZhРW^ӧ̙CD=GGW>_#=DAAh HMȗ1 2;wOGBqqV!-- ׮]È#i&EEEuE1}tڵ+Oۇ ̜9.B " Bс#O@ Ķ$Ҝ;]{;|`+$:>b4=A}qI=zñACh|Ytu₡CX~=c- sss_~HNNf\.;v쀧' 8p044D6mOؽ{7<<<```&M`׮]2#̙k׮ T,\v#aA$[P=UOD/*JOY%B6?ŏq\.5vuf=֭^跑8^ Ǫk4cODϞ4>F`/+p)~e_-_Q_!Ƨ,Yf 43gDBB兹sJw1\pcT(,?ħ ~1bNha~ Tt|uv~pm{@bHK`ܒ%̶=KnnG?A_IMk{g~ QäIIIA>{Bn^ϾbԳRyG춾zr GRaggF!!!QpwwBfUٮ];,[ ={ŋ۷/]bӦMh֬&)) ZBLL <_5Zj\t æ IDATM0`mڴ7|+VÇ9s&L'ObҤIx!|+]\^q|~ݶwE!8" #~#ӧޫ/қd?4nA}00Zsptp`žS.**˛7o0k,ܾ}47DLLLnWgСd٥UVJc,Ǚzzz:t(1m4 07oƨQb hwe̟?z¥Kb L>N2$ QܳJAD ,96,/L>˖O~7oҥ+T̜-˓'O|=z4_666ׯ]5S  11U{luxtdaÆsc[p!Zj>}O>ٳgK>G$jGZ({wQ5)ywAXn= lo gϝgSoMѬiS@tL :v~uzѲ,[ Çgʕ+`||6mwAe*'ObرUˣG䊛Ob޽x1DBD- rJJxHHHĩCS&}ؿ5~X OD~~>q- 9IQv󑗗7n ct̝7oFqI ޽´K>kbQرc֭H,-ݸqcرxLRcVs٘>}:>|<|PbQXd ϟ#G //yyyr  ĵkאB\xF¼y$ L4 ?lmm;wƦMPTT 6K.t!$Fj.k Yam 7/?&<]]]&]NػO3]ƗfL9m&~o3c2޽nɏpkC}i,\.\.ԩߏiӦcoannc„ U>vE> ٳgcذa055ȑ#1c wGŮ]{{{Ϙ:uN2˖-lmmtR,_\[l!Əlۼy3Ν;sss\t [l ʜƨ̍7}VѶUxFEI*W]aiZ2FO_յ ʜ6#=aaatBM2G#DʢF.j6A!;v,"##L<~: -P:ӕѡgX ѣG 0QQQprr¸q0g AhU8  ˜1c0f AB{Gْgy}F7n2ۢADACS B "BNvCBPQc*LȕjuHAh7VHON 4DeT ATGhO=I%Kh "]]} A1DSY$>nG\*]ekCQ| ("ג ATQ#gX,=Uyw'>!w  #GB!-*"bHvרnOr{[GA|X48BĪghM+)B$72y&mKU>=}fhITw :#m@Re$2IEAA}3E9ij A3b*(" I1T_NON QD ">,WYQR"ey# ,8wvABCުo HziqT_7n@r: ADC|>޼ DA}⨪Ue<1DRE mԛ "VQY1wifo VL/S M! 1TӈDZt rX;W!l'&&hN1𧣫G'$t'u Bjb@V ̙3qAiȑ#֭[SE "6Lhr:!o" A扎~wPRRNc f6mABb1}|=FƍߣsΝ;ƍqA AhADrϞ=AQ==S&}O* <52'NbuvDm[yv?^zIl ݻwr:&թ|HcAu70xll۾cV\@`?V\O( T9APESDf޽yPu /oGBHS- QEUp`е@.QQXww?6<mH>#@|> D i Tgy>J{B,75wrS]<A*3ytn_GFFlǞȎlR-eBZw9iӤݥۘ-m K(4ܔҔʏ.m-wq-4-{)$Nǒ54&$?oNu;C!q|^{-=;v젿6~aPeBT9CU*qSaosyz&_[Qkp40xBBBBk6UWnme? _)9?s?mٲ-[A@$T(Hד9;;; jvR @:W"!!!B|v~ի9zy77D UDQ*Ӊ۷o/1 A)FfSK4l4sBBBB׽W4\_u~?#$Te*W*Tl!AC A(uzR"!!!۶m[EG jWZG@I0tcN R,B'$$$T:ϝ[4*$$H*T J3W(W]tlPYHHHHhxk Tux[+&PYK C34 M"+*C(:{vLPIxTӽ!mRQm!tBBBBEZ -l c"?C-u%v\'HH( / ;4C\j[~(#ʹOV qrW]oܿyvhRjkk}_+gY]}ǎ;^s 7o߾gW_}'!!!DBȆ-cl愡 T4(*& 5# eտK$$([Gx5.d++<ļ/wh߾}=3]vѣGiiifΝڵG}TL!!DByRQq0TLcxa`hnet;T(f= eHrI~sQ-RvZDE(*k΁[ "Wj* e&HHu\ӟ9B?駟gIN},$$$HUx:W^:R;OS}Jޡr[hUHHH(ݱv½<\nobQy5k@Q1*?&kvmݻ5kΝ;ټy"\=,ە "2TEϤ<93xrJUEx*R/} =s˧ng(4DSS;n/}/,CC! bhNK>NZN': A_~>v_q F/>Ƨw!,)&GQ틟K־*9F6s)kk/EM@g#cXؿ/g}|V>mfԒj3r>GQ9J&qgp]NeBs 7M9Ͼ"wؖ]43(=s@\ޡfi`c3dYpΧ97}]J⦀HK/T㟙D+qܹEss%'޾*"jBM+T ~Q)PI!r_XqӦMW6"焄H) JuQ]ЉQe>C'X@/KUM - b1 ךu.:wP`4 XP@ҥCeE0#E?W.Q@$T04!T Me+\_h# eCVP,Ϧ=HBy! r"^oJnGȥ@k ޮ2I`48"i BL)9-M`n9WHH*AAHh1hC٨jC9_c/V<ވb$O9 6 z:o*s *7y)rC庞~Xޡhn,.bz *wyݝJ4 [ ^=lV0sy鏥i4øN@$0`IrlP9τ(B_W?!&]{E^{vQq+(GBBBBB%!0T\L *!O?+=\0TYJ{n9,$$$$$HHPY-b%wuY 哴/ &T}XC3]w&/&~#!!!!"J-Rz'S!*cfMYPʰYܸUw}|)ZT04<.=kN(E"BмT)i`OK A]^El bn,rۋ *llMg|.cZHWYF 0dofדC'oc ZpZ(1 og4„ f4$,J :33MfڅrQ*/E=x0 C9<: y7yVJxL`xF c~y_K .we0WBBBB zl|HΟB\9̟Cf;miwʷK<]-{ y2l *{="Lr3όޠirȳIyqՎr'%*DE3 )۪~"HHHHHH⁡lU0T <9\$(Jkx`ar([Xa^/Ql!ŐS5-Y=sAK>E\sO Z|040&h-AjG>.4Miww|"YLjr SHp6~lt t"BBBBB <2o6((*dWPTHM~Lb sl m&P<=ܴ,IHHHHb!347 M!S2C`pm5ۋl rbF*Je4NY@Q<rIj5.XSYHN(o!DCPQ)! e}@!0XO7 bªE+xr}˹' 'M9Ðo*:  Z/۷gg-`l-AoB=ӎLB@R^ CL)RalxLN۔3 jlZЉ #&immaʠ(ۭ0|JcLieyaӂqoR#bܚXLf4F3TIO0Mx<㡡UkmꠎiPHRx<};i ͼ VPq<NzFgq.zo?Jd3<\=5%L)kPS.y9A3QU z#Mڭt쀙)DC/uP97--tg?y1$mcoZL3Nf +ʸVqHUBCW1!.+*/pqBPSSÒ%jSbV/!1dY׽`2\4}>?J-'$b1\gd7`Hב  4^VaXANEKuT2Lb0Hycx ~a|h=}GK4\.9ny8 '^= *02beةsPgWYS\T֎L(cZѕ @MbQ]cNKD\dԘ CHa60:9 ukCb))tBĮiW5hi31t22G$,0X۬~}$(Ӊ n B Y>TeP(h`y$HHǣ(Wᜩp(ThB,J_*E%v){A0\ggg6 <sRXeNW0&YRIl Uy>ZʚKײe_Uuڗ.cIM K-]ǒ :.[}e3َ5y{餵I0l:uOz+MN'M>EԩY=߁OP<MM|s}鲪O[9>&cI"vk| VO@LZIq\h}arӉ{fnbq L!z#4t I0SG8LH$%^3 1᳎9 ٓDQ k%4Sӑb:~{+' =aD\eYr1JPY'ib344ZWrк3ӂS(1X$,<ey({7PgϞOk֬H|{ćn1c*tEQ뮻n/~Tz.J{9?/|O?HouV6n/Lcc#uV^|yo};3}]wŎ;я~$&ydc4$Q%;'J3V4f>pU8F8# ~j8bW_6ڰt5O YTUe3 hs/<k2 r-/~eyE%2lMjT`WD!.[l*rysݻy.xݻws7kjj.^z锿k8pYhjj隣1c?3韗/_?LSST*FqL9tw]óGrb:NhЂ*?z|ʿ`_8]eN&`̺?ߡ4\ŊdfLA1U&1v @Qn7ˍ ->H{,P^FPxe$)!a9LUQMnn/jrtMY S2% Qap.|XbP 0 A 8O2|{߃n{Ń:Zw߳|񞻳:Ï<+7u>w'ۿ{Oln1 8_ҶL%I>̭O<ݻ?ѣ[^}֮]=g??^-ܥv(K$˃/3~}4ap!EEtn>]294A-f!#`.?駟gIg*cvW? T$^CD܄!Jm>dR+c/Ѧ\U2/ MX(-Iv^TNͺ'22BpF3 Ѧz=4J GIԤI;8`0YmȰɕ8 B!"M8ө_rQT"5-LMi tޑ«2&*ZFEl@cJ`\ dԎ2 O&C%֧wΟ}wqǎh]J"Ww}CNnlڴo v{e͚5sN6oޜ1_c˗]y-mcn eb1`ZG+ H$=ȵD ! 4lz#sL'kW82l44#fJ'v/ZE~SC'l;9>& 1"阦B,3|Ju=jДkU%X 8 lh{})h) R`Vsp&W*ʴ*\PBCPǙOp ϰy-[{Gogpp˖>.}}9Ǫ{?g)4Ud0*'rϳzu3G;T״pv =%'N%LN@2hp:fZ9?aЧ'-(na|8c1(I0dFzg_2x<2;mrͷ4\lD§952F\qjW{0xnuH#ș8C4.-^.Z e-X*V&Uӊ Hh(\s$04潯RPT 2R BzoJF_~>v_q F/>Ƨw͢}U1f MԯT畠(88LZz*[F'q:LwkT$CG2zrdUi6 E&hvڜ$<*iO.tG/ވZuWC%)ikUQvʶL/հC h8X!3`ъaB[F=scY(/L ޠ`T}|V>mx)y^_?V5\@_/cJ+ᄄax V Y4T4\tLdU҉ zFiwIǪNxp| '8"EmvayuP`0H<G bP%qϲedМ L"¾ZBE5 r7\ިHE}9}AbߥBu2C&Qx1Ο;sDGMšA(6TIOpX' [9F  G "Ԛ "~zr>N-$¨>׷50O.Qk_=ç4d0H0*8{+.7 EUBkVQEE$W:t4SsApRHd9i *&9N\I0P3:T]3wh!9TM`򋲕%|J÷RQB x[[5B ύg^,cJ+VdAh$*AB<vĈLkk+8FL7R}.E'3fO" 4y 9hC3@, 3U* !h)xLcHU.FSL5cj’6$jӍ騒:*J1Z~ YZ{r _P3+UzmYYYԁ+D.,AB\FBҥ!rR"tYBRApq* qfL-A$eB^, HM6ahɳxӿ'CvA$FdTj fտbC&&',%VSg}53҃FoDEO `&> ^%LCthgY{E), 'd8WE Ŗ9$ B5eBu_dPecXM  &42wUO_&!Ai#Jզ=X5 FxxuPo4\ƭ!Zԩֈ8>F#adY&P;b1&XZXOg; 쌝<:4Z0A B( UCQm *C TU׏+l6B@Q_y2ml֛m:n$U BUӚFyQPhUl Fn( 8ɥ!NA$O]Щ55j[ HHj>g@h3fyp!쐉L$C#J9RdvfYn1 @Lz tl9& cOrY5f ;c2z11X ed#bi&.-H@Q1M\o3ёߗB[s?79: []yۍYoa/4Q*Fk ꮉ (Oba}JK.8tJ:n+:( I.b1L']nt΀J$܏Cv!{ik3gk gdP 3ڰfHb S}IĂ8H$W(`DEd/QwwWP?9O5y-Bxlj_.ܶFgg۟Woֱ,s5ip3y4#CJ,W Jd]ב$ ǃi)Q"a SU2/Z )n)5dZ?, tcqW:e)^ZZoCg5ƌ8.r/c@")SFAo4-N{K2G@$CI7y*wܫ9t[__ @$ Re? /0.xRc{e*k0m-ÊGB'KrچUb)> E2.&= vXs(h~"Fp iB$N@gxxU:VZޑ T*Nv0'bW gQvhͼȺFC!N'NMJi~JC_ L@>o"B iGHR^"Z7h>ੴ +1:Y288- C55jlZ3grJPDޫ0|JCQ,½Dca\ @kYAu~?cygdZ[i\̦^^{u"v2G<ΠBQ.AeL_;ˍ ,3&9#{ &=Hxh ( b1 $ESD hz@h5u.V)j!`V Z0d몀0>JIW6h|`ܹsf "È E2.D"A<e5pCNmU}KKZ+WD#:57a60xX`Ձ$2 1 F:yNeX 1ê2'I*nO IDAT'c0ADtN.Urb1`C<u#b)H"Èc UARJC`>$BӢMfCb,G,m􋊓^L4\s kWԫaIM͢5\g9K%i]8d1|JrTedU IT) : M㭃X,Ƒ +3f"F3-H&SIM`1(l%Y92lw~`=шaX ?xhhh`0LE}3V.H7$8J5xaW';@T*ZJO7〭 *˘BxJy\D0*c(##3%9ٱy Ab" /4ƥRԦ1#f* qa@+>N8#8C'C`b`ڊWU( /*Jnc].$It"{qȯ'U{YWM&Tƌ$I֥9Ua+:"鵆jBkCՎH8.Z JhoE ] q) +``g[Zz c PNP8,QhV>KMӸ{yg}C|k_XLO???G[[_WټycfBȾtϝqp5/tE`Cbc4d̈3dĉ(K{UN^aG8Jkk+a {Jk +-;c{CAQ}0`4 I&Hc ʽM^DVсs$<&c8qF Z IJs%l\ K04iӦ_c``QvL]$l")l\ ErUlNbBQ¤dS#I%;:lݺ7/؈i<lݺ_|7|s㩧k|ͬZwoS*q)wAE!,Cgd7n3Ƙay^IĈ~Y @8lޫr˭rDM w;$2kGMqG>X39'0Mx<κ:_bI Etx]`GtYm[搑$;}zM,ouvI$X٦61>>>qP6ns/sJQBV#ZZ` ̵OAr~ Feԇ55R L+Ƚk8p ]u￟6_2]w]w_ٷoO=T۔r 2..EQu@,~PoR#&[U~FIb`EQ8#YN}yHta@*ǙIُADxEOCU\%X@_H*9 .>S^_}"#IWNO1n˫$a&`xM0+^أ"CBE,O r3wPS?&n`߾}ϮjCCCZ5uPVU:"1U4שb:SEbV5NAŘ3ĪDwJiī:Nm"+dkLWuqParVa4m|f8i @:MAJȄz< =Jgx`҃GϺV4x;峪v|de)`HPAa񊝳d6~zI]*M,bצkPv9pKa*:HhF#4(WabtCm[^HD%0M GM(YPpv r߲|oF`uIi躞. rjX7j5YA0i'&uF&ޟ6Df̓:;;nyl&U6_͡Y04?p:H,*· X7tm*FsNNC^kSx.Pa?1G˸Kڵk@ɓ' |{/~ ngkjQo YeH0HRbyO6O &0 ͞URAA+W˜8O_EoZU7HOO<fmInB"WarׯrA+rIvMxyix}uT\.A⽽ "Z-WVp Ol]O!Y? |5<7%Gz] {XwHJiؼy3v{e͚5s)}e۶m\ve_WO~64)bMW"@&Hd%4:|4{616 躎C&'a(`/4T'O߈xVUUQ Eޫz# s(o] E!VGÄOOq"8(KQ $DQ^F\ QZj;Rm\qlq63u϶E"5۷o:k/0ixƧB1޶9T3PoZmsVɲ @WKxgX")12#ۼ ߝG1Z6V1'(sƌ8-$R6;yCKb0l֮E[ 医A ;`V0\"Ea\1e͍j+7)(IO>wn1&$F7 LŲK*=qAє1+(:X2( pm(0?M %55,)q)|žH3c~ Vݸ$a7L~YۥB$NU1}S1 ^EI]NȰ : `*t.ڶj :|Ч~#{UX-oR!K `UxeczUz<ݎ~qQb7(l (R'((uu߸"y.'T">+9ΕCpܹy>6բL\ƥR!34dw}PJ$I8dDE7]iSL~""&5 +$:ZSv)PX׎,Hb I$$G"I$4ax~{шɐa$%%4Ӊi (GP-.2$Fd 2tN VVs,|t@T6 Tr vuM34&A *EnWѿg[W,xKr.]w犷) JuQMoxkv\*MV9q*Y=Vۊ$Iv. ikƒt8Buֶ53IȀ9%W'M8DNdyL岧 1t,oUjɋ& tl9J_i(%`%63)P ʷȘȩJ`FU[4G`<= *=*sV1P 3:2\setOKm\*Im(ᐇza39 M֏ΘaY46$MZ3E8yAH`̴l6[,N8~dىlUc'rt/ /`~ֵr rZ x6^e2Eڎ8t|;2 @y* t1+ZeG8xۘG/?ӊ6 Ƒg8ߟ=Y<~p.H|e^݋UX.̗9ymHYqk(Iy|j92bTSR q~W ;굯>Zuh_Xf ƧͽULTCh 4yb85r8x8ۏX &?{a^`a&Xг0YɯT7N8=-bbbs\3d=:;' c<]߆jU¯ƴؼVLS8O'8~FTx6m*R!JnEBsQPHlS.J1 BV|`kLzD%z$_s&#XSg"C.>y-\"=:*8yؔ_ߧZԸZG"݀Q=eBOyL, zntwk@#O 7ߎ\JJcidJ-KwcUNwCGM*fhhvÛ,Hqv"PL 1!- u'TU8b ~O1\s!9,'k y0Ѿ=Ey :oCy> <8 O`Ym!]f6d1|S/^<6P`rrPmC󘛚@O`cZLO`UGniYZ4ljj u㌓U<Ž9Ak{0Ӌ"s16Ҳ*;vPǷh_"I[?~"40sT::7;SA3pZmi^ #(㑉 (O/kju pT*#aSSOkc]t6HjytcbbEf2{SӚml{*K}8Xæ|gǃ9&uww-qF3826^RȜLNix*/2GVMMn>߿O7GM~i2X]~%)5We@N=.deJI<3HԸOKUNmFL'preݭRʚdY?l$[&;:4ڱxSSS^#ԑU=xXqygQ1nU40?<<yi_;%`UGݸpGOic.U{fƱ1vp:BATuHzbG["[dv#4a %6â!];Vq/C-G'#Ezɱ22z:AQ2jڐ_ql}уc@ ˡ9=RhiV^qʷcqe077ggx|СGƧ˨ci~~+^-4~m<,a?~Tݯ,R g0:34DZ[$)e]8l,V16ñcǰi&^ Y=~h. [녨_,E3Q4FG%Dc/GZ"FV"oaO0)rĨQehqq+WJ6W#ESSS\_tLE2] hѸ8m['T)j8WhS޽۲^d+ϵ:R*A5nlj6hkK̶$ɮ!v-5Լ/z*]__f󘛚É',L`Zߞ::C'џne;07E.׎B7fcn:*8GKtFO/^ܑ$k -,w<ถ^)^&fSkYr5 1 $]y(-G&RE]+r;O1;6lHfː, I#9ZaOlڢ%9JxqHr- IKJ `:6>|t`f8VuTq=^~k^eT_MsV2{]h lv< lyjN9k"}qq0,mn'Ry- Q?/ F̕64ӛƂq~Bc ~4eD կWq5mS*րH SN.E]_b]d>O`ll ?яqF:t]wpڞf;!RBD)kɪ' I0C9\B\"3 RD(E$TmO@Qh /_<8 UWⳟYI46Wہ?wގkGrxg088|e]?];w}G؄VBxww>xgôVY~7F|o Ep7ᩧF׷ݎOoUlxuma``w}wWwcaݺu;_O} wlχވVo`%vpb7)Df24)άzO}n&/ő#goM7߂?i;.K7·q7~7׸aN|w~'K_>eۿ{7[w&ϸ㮯_*^7-͇ىmoS۟wٻƅx{]r:[,?'_32 ~;!"+~>^~7" oGʐ'2ѡWt)H=1-?swoK^rAq͸߯ WZ3_t#.z v.—t#z_4,~X!7/t#.~EW_*|Ӎ[c3p-_Ɔj]~ͷ܆[+}ٯC@__waǎXr%+{z8sp!|ĄB! :#"6!v ̮3HAɕF|U :o淼~?y?::\9<NY~5 x%iZ]_w y1GPR6/7?V,..__qsSO=k^{-nvر]v&''qF|ŏcG!B2JPv%A~FjePjDsXO<[y]$H%7ŕN>-0.{[f>}/kŊ8o} gE=\|_UVᦛnM7TG?=\G!BD)HHh~II5xkʐ?)&\}󫌫淿ÿ/x=K_r~t˛/\7o\-~p/vy^j0ᄏz| gQmy)M GB$E]KQ( b2 5Ԗȧ?Q܅?{׻ٴq#^_?0կu+e}u+էg5ϸN+q5X\\ēO>=ꪫꟹꪫ xꩧ< >O8!"wQF8~..9=^p?GyPD #CCRd h.vxCӛ?MszOˏsV5,RZ}%/%޿a_ߊ}8}4^u+-;[я_/Ç?t >{!2bя|ygL};annGp8~Xτ_x;ށ{ k֬c׮]l۶ W_}5|I +Ğ={Q6!Ud'σ8(E>5mclf#Wp0m)"CfQOd>Z7N9?qd8Qظ_O3/vɁMPfq۩Kyf #$b?Ӌ8r){ ]?}40E(eF 1aٰp"Crȍ% JF;bQuLTb IQZEu=@BHr1,ÐTp+~fF崑TR|dߡxH N,t]FJ^DI(aIu7sp)Jb(Ebȍ EV\yFn^QG!$2\TCx-K`Vx"CC>X^E'\'/.bc{rL,O^/m9;/E1Fk*8"oxgtܷH\G cDqd)Ӌ8mI L ӷ$)izQf `Ȓ% Ӭb~ߓ4 )7B;1E"hCuN3((IQ5rƽ۬*k\!?5>:uڮT0YAFr RI2rgsRcDQNbڊBrX鈃Ȑׁb:IHڰ*m7MΖ%&Vme#|U\2!Yo #-:#FD)Wq BI DN$]Jۖ x.D +C*)ߋ1@y0:D9oi!S)j RdQ0$!EIٖ ɤ ]hIМZ3&'I*ѹ$<,m EIeID"?R!B):ȐrGVZLj)H$* ydV9-K޳t8fgّ" PdȨ1Im`tPΉ}G{zC(t1y^כE!1O YBfE[즿ӚI.gG;XYEZXM.HEtq+31!Ŏ7y'nYZ'CȤw@XBH,+A!~9zYyitr)IQ? ~KF6ߢ v1ٍ "Eh`tkȂizaQBG!&b Lo]DD8+!I*[ņ }f[OWVAato8H{!tb  1:DkQv مj=$.!$2葝I4?KqTKV/STԉƔzt!8#!2(++4'%R݌bboT~}dd9ί4w].3EHEHd^!6RF UQF&oe ;IY1:D+)´D4tV "Ŋ#D&Ϛ,LdRPBKo(D5M7j27(~op˷+^F헋-4yЭ>|2>'VMo{"7 7.=HU>BHX#t|F(!*9 9ߐ⽊PK' ]!(v7z0<<|jRݜo͌ɐ7"Te|8™_AL*Hs>lS3SNc zߜISHҬԈ"d rdH7YnMu*^ĄQ@Iyd~ "MΝ9 )r!X2wsuaW*|&;RzbO0+F4$ ȃ3N%NrJ J|]uPKXVTcES|""F!Z.R\(C00"Sjk˦b<G?e(EQ9.qCN?r:T ! ,T@]h.1P/`="-DaEdJ -EQ!!]; CATpbVы|(;Pehqq+WJžJQTKܐ#BbZ$Bd?e 1*aZjq|&u6Jy3*!w4H B!4B#E;2䤿#Cr1{b:e8l~[[VbYlgKHYAJD"+&1MU~۬\4BTi!rL 'VS !!Zm$,_ #|?E)ڹ? RZX.:UgX]eYϟ:e! YHIʜUj`K#3F̚KN!PPI2e1O}3ס1B%J}#*1Eλy"F6 u'm;JQj-3Ԭٲ+_P'? 7܀|jU{;vi&ڵ O<+<¤} pzq1%EM"H2]PN8ZSX'92>'Q&t"qȃ5h=If' r)%bR 54F"$2gB1!Q~ľ3(E ގl6e56`׮]qe)} s^Ļ.uY>sxߍo|xAr<JR$S*vr#FcRN0̉R"QFG܄iih2$;m$$Ȳ2Z%/)R'*irQ"JX贵eCkx; ;77qw{iu]m۶ᵯ}mK֐ A QzY$8PH<_QX %g5,IPN!mF$ ah ],ehK !n2GT׊rD@9/ *'D!1o-,þB$GTRin*Ϲ>C,E9dl߾wu֮]˝R)ecDjNa 951Ψd.9S-_Rq^|2dmT! 1*DHd۬K)rhٰvQ$"M?Қk֯_gy6l6>>OK/F\CzQ+)xЧx-Q>$QUS1*t?"GB(| 2˥3C,S$ki!FI =Kur4"S^ڞ={p%WIORd%T1c$3Xm } f$G"1T!>G*d2W?@ٙq!(CD#qv+_vP2ʈ2eaHc1sᦟVя~_pߏ/| >azUrj1Z\mNlUNɫ@+݇B]Һ?rB؆ 0("D{\j+qz˿ =z}=BC`ymX?`?I|p y/O{,WL_ܻ, E/3v}M3Yihf냡,ۍ0bdK.ߎk¦Mpw6AWӅUv=,߶>g"]}iЉGFnPҴxIhIZTy7β, ./ʑ!ȅŞ;$Sbc\*58⾭.EOE+}PgcMj#&xE.KǁmmEZNr\N*v GPbp*q+֩ 9; r;TI4g K6R#ـr"5 /j;UE*rB -Ce"Q[#Q:.rꏋ( b9.uh$GrX *-SirvS hK(@rHr*De_!EHs~nC NJ6'Bp"9-ݬb >XģARŢ&2-c DH<'7ug BPMZU(QBb2?EQG_ËX )Bpzq}$;"*%P0>t9h#9M~"eX9 1EPP2?/16{A5>:u9=k"{\F$.XB(M$Vcn7]puK?' 3)QN_oFJTOqB(CȐkJQ$KX p_J13qb:ݢ\*2'1Ă bY&qH< >7/HƗV{$Bi⠯)Wl y`TRd IDATPK@BJKxglQ]΢"NMPRu3[3q H5QTێB%BfrQ-szes\- ZDW܎]tV~.FVc\VKBPBNS*p{DuPF꟏JvqB`!F"#1*-6 ˩m9]$h`&J.n~i~E!B[^s,ˉFd1j9{XHX.[/݇8iT}rtUB^D3i $r"/ D-Gק~5EɐuW:]ԹA3j1jˎ6!IdVȍ,P\:b$GT.Ir}dAIrS1!#visEFI$׾RĨ!!?dHUeNCYLJlQVHQ+%()HjjQꚪ:h}w<{.}h TdʖSjl ݬɺ"$g-Z_inEORp7xqୄJA⏹h"Cf]{6W=eM?IZfgg+lM?77K/>,>8qw}Yoϊ655}|'N!{nz!'? ժm Α%eR!Cl+%ɗ^uNWA|b/Dn.mKS EE%^A~|$Bn.W,#Vz_&̓"O5eKvqk_pk_pq׿8з!bӦM馛Cٚ[n_b|[¹瞋+Ws7M{[]}Vdʕ8qW`8}4n?wc``mmmč7ވx'fioK!K!4d4$A]|ZL O @{oyc/D7Pnt{5!͟uq_R#_VB;FmfI\<EitK"EaE>13Wء'qWĭ߉vط?o86t(AZSO=믿mM']{fV,~211b??E=@)B$;F+p*K J;UO.9ZVZi}HnhהrՍK6Cqz0VO_lQJ:nic}ZJDTis_nů_o7| OmXaf ~[O}Sk[21RI~ $(M v͙,H YKt !"6%(z,䧸AC!~l$+A4lnHdÖؑ!EKTM#RqFVh]6{yf[lڴ WwشiϚ/zы ͛8sy!Y*6J qVQ]dDHu[eȬvW|* Z ]U##r#+v{ݞX5FI(NJQk[oۓ~C y<޼|/g?osW\qn6?4wgX\\Į]ggrJ^@B|D9+ٍXYDSk`EQ1p]= IM^Uqt7/ߓlup&X NXy)Llž)?>}_?*~\k>G1" OƁ~lkk>(XXXO<ZWYXX8^\z}cmۆg?_׸@,-. @-WSɐ2UZ;;lyYh!95?(Qqh U1G7HB8'F\F$kG'0mwl>q HC;ib!+Vo۱k.TUr9'?]uV9r>ctt,o2WZUCꪆ{^ر> 2 6oތBü~(HrŬBKΆ,D*PGT2$V\"8.'a@ihdFdw^M/h.Tb'ש !5/n)LO BWji>c̠*|3-܂[nr^v?kwmo{ Ա߲ YMBh$Ksw)dw(oV!EA딹ݻwvMWL+ӤSj)k2T*Ō !1 $"Rm`)5Hb#FyT;YWBjq!2ad2 RFPRt%GH=E쥗E$}BϹ^H~;d Ь 40.,ٍ-JUQ:G~MDʜxkL,dI5VVz|X:;R næ|w]ʁ*n(LD}YəH.*EENU䆠6ZUI Y x(D^{:Bo^׿ǝ-SlQ5x- ?~[qpϿfu?զOT"!߿`+bG6q]N/."wDH:b!E@sDj2ַ$CK뿏p,=v"T чG!ʄ:hu,? gʧp5ߍX4=~ c8f2F;fZ|G  oA(yDMY]ϝ"G?|ϚlϬBzr낺BEU!S&HGz_c2'*J?rJF)}'M8A`ʐQt4}Z2KR(EXj]p"ƴ9Rr*ʐkO5F5,VB7(M v-U$?c#DR^DAՀ@A6 L6[5d)"$mj/Pډd!JLKq,WeHa58Q2I˒SJbFrYyS+DbDAcqlԀTs?/ B( g%PT7I8|(wBDzZp/ uTjJŊ q38H!FY2@b)nsH²ݎG!-$Rݻw+ F+qh脵q.*;g$aRgU?lÓXC!")rz#Yus %+0bZa !ɑ\ٱ+:L#PhBoQXg aSBHQ"ɉҼ !$Bdu#*g&N*bVD֕Dw EIj<ƹ!(HEbn0kQIԷ7}.ڕoL r0"c>wa3B Aq&j@Z/ (=e"A^?5$8N!"Q 5 H)DLq_8*rKQyVq!{׾\OB!"#b@1NH(NR^PwB(D`uӎ[گƪ@"i#?EaI)Xː2ŸpگB(DxcaFilTnz0#ELsw 9BH„ )[2jvt6 D8Ux?s֘? ,_W쯿.E"wﶜn&D?}w%Yg !$BezʜFnNCHQ΂5&i7No-r4)Bd52{_+i_Zhq9*RDICP@V38gt tHJZ9`WI+~WsfG`O O#XQVDq2L&+vؗ!AFCDnc(B-]^cꇄq ̧>/ 3!BYT7l5T;9) :@qckPW!E5uN֚XC][nB(DBt_ G2ݎJH k0YB*Fa]eht4:2`70.\"ҟs&O~ Yad2E~ Q~~ߙɆJˌE`Q~ !H.BQsRnDٵvzSl:HqUգ\A(/7G`mA N3JXhۯ8!$*؇(R(>/Mק/A"ewzB_yQ{źV{S-C0.`&<4Ś8ʓQo+"ILʜYJs)p>43籜7I'Ђ~E b  Q(Jؽ{7&ťG+֑K(;F"VoPRy><! r)c9KI 91%"]vrEH1 5CD.>wY(H $FL"G$^B~,'u' Q8LQxT$!3)OK)"۬O BT*6 nox.미' =Jctl)""SĺBH/BBf1*ʎUrMzݻw" XDhaA!1&SwSԄˑIP#A&~%RB`c4BL‡ם^`"F! QP@iha"-?U |CHی1&EmDR(e%Uc9))R4/!Hh"]j P94DtLEL¡}])!‡;!Qih(*R c#;b 'b 9hIJketP(4G $"C)"&B+(4f "iu$ j NIHk[VCTbi>5[SBHBTi)r>6=q?NEoPB,EZo8Or B\4%C!" qѴ۷{M )oiyZ*=GTP+ň2LT|qB6c1P*UOj K_ߑ,zVOo,F牿b i׻yxӥZ[c?=+ɡBBuzપEu-oȥiBd<F ,Fk[R%wQ?˵HO/:x)9j!/b' -h!QlWxz"}ȁ.Ʉ"DA,W ɺ 4"Bi9H3&[ (} . ː*K>u1âjfd(2_BBZ'Drffpط,wm'ܟ>Rd!rѨrP=2è40%"*K< `^uV  Q-eq('&, }b%!B#DKTx,SC ͑cO!"/2TdxIuL1V' QX2FLaq DؼRJI7+ HjcEl! IN'M&A&۹#NJ fB O BND^.6w  !Z!bߓGVOڽ{w".mݽ{7S ,@0e*ZJDADuXm$VDQ"PiN{!Y"c!B!jjfR<}Oӻn1n\}g8Zcp}*/YhB!RR> ;Ki y""{y_Eq~tO8~!B( q;}|ٿ-'$f_;}BE}  \_SRAηPߢBbV}!BD<4}N!P r~#d1z0`V$BEPDZ)2$tpS HZTvz}_!BD\ɵ(Gߧ ۨx!Np}!BORP=kFA$Q(r"^zB(DĹrCIJ{?툎$JOY ZMiNԬ>}7A!Ȑ8O 3 Ņ%P3Y2D!i$ağB(D!M.f!XTE#H$2D!B!1,CbdI$Je2D! !C=Z$CŚ큩 YnsHr2%*2JsBE^L|r鄑!B!P}*J)sNDHVVI룒(Tc )B!BD2!7b$BEt$eG%DAE/?!BB=.g^{|[~q_Mgb=+nm.{ h g_~9d}@.?nnV_n][=|w{˲Zv^M=}pm{|?~O O! Y5E!iĴ:È,"5ZCt@#)y\7i)(j 9n#/OaBH\aDqbT) p?IҖ6 DB!$BTܒYJq_M!?% B!B!;O=Y!2!e^^JVӶCKZmݻwso7 !B(DL@kL)+x[Zmg=7;ޟ}}v!Bo 9O S2]dO!B!JHox)HĈ"s!Ե(! Qo"5 2Y7_kPpƮբu1Zd,ChL#BH(˲.`o]v[a|sArhBNeF>?"'ԄB%F)!f`Ґ7H])rNS2R*Eq"B!Pf5B$)EM"i[ľBBYEAmq6;)e(t; !B(D"4G 1U8s 0*:*QH}98+!BR)D`atf)?JFkoB! QD܈r$Zͼj #c]!B7}c$HH`j@Fϊ%P*[[LHo(}ǿssBH(geּu"2͕ˊFE挢[摢TssBH(Fl,K$լzz1%E E)K_ 'B!~ÔHQSp CMR%LB!T LfQ"uI"?$%2Lsc~aݣR]xI) rJxBIyqDȉX5dGo۞BL'#dHݘQ2vh 5BIHjعY(FY#IM! g$-EF:T q%oBIsR LP."5NnTрN!~~5 rVR0}*EcM!B~6} Lsw r~8Fߑ"F"B(D56J#%ŋɆ RԹh6Q(6$P15B(892:گP'U>Ua MTůmt;PDx !Pmڗ(gzYL?gs~.es=] N"A!B!~/XI%uE{%:D!CBy2"rk2+D) : qI?p11&-!ŗa:Qaն/yGfY2~-'gVع4Eozg~͎?ۿ۷5OLZ}l 5xOO!Lk/Zեx]_?؊ O,u.߼m.:no(o<^_FǺ?}'{O\7NkB])ې`zwH#,4 gby=㵌BH3(d-qنB7s% !PTw%\TKkIMu:i&E^d !B!J)fRԹ(t-"Jx"B!"FT; >e WcG (]B @yjXliĕRķP(/" J6q%B74x WtGUŽ0:DLWVB <( Gsݜj|I2ϔ!B!aJFR\53KA"JQ:96'CBH0BFGJ7\eJɯ_DH3X}Pr !P%~i /ce$1B%=x+Ӫ(A<B(DHͦਢF#Y~Qc"F-CB*7VdH #,N bW"ECB(D-b4mI=mn0RoPշ_rɈXJ]:Y~P`v3*a_OB!"HI'gw`v#ǯbɬ]7⛢F{#Yj ,ߞܷ맇齧{zBIeR>Lֿ`5l4=M+LgK%{4)r9rGc-x{^^?}!!xOO!"BZhiC FPPB)D@(®&tZ ԥUɃǒBXbԶY5 RbaD$:TĠR?4]Fy9H!  K[k>^(ϔCB(DI^m. P") lD'J!PogɲYt(UǙǔBkt46"=QR~ !  e2(-N}(AǙB6Z'O PycN!BDlt R`ѣ |=D=!  hD#Q+D|! 1ѡ6ԩuO qr B!"l$PZ=jeDD:_! !=.EZQMD|@!P%LKFϰj~aK|i3BR"D^f}H? ?o8YG<~? BR"DO?E2<~-~Rgx<鞞BZ N̄(\*G!BDg!6F!!B!BD!$22BEZMkHx1Ur1B-BR b! q#C~$VCB(DĖE !Dx!B!"!B ]oBؕ EBHdBS"$X BgQ(R)"'H҄B(D.ehhYp ߺ / (u) e BH2D!P|!+ Q!-#^{!P!_*4: DD(BHS!P @F)CbM/ ֡XԤ.Z{]ՂE("[;?*OA&P/K ŢiGBa4)Џ(ېƈЌW5>ʆ^f/j:!Pi}!irB(DvfI" Q!i!B!BdC04.HEz1uBȄ ɯ"HEˆ Q! B!0UBqLeqP(B!", ɖ$-鶕V!3:nFRQ!#^!Pa@vI/P(Y]*H,LP (d JE+ b! T*5CXkմ02 ߻)BtYB(D0>$L A]P(E{1uBȚBP8S1Զ$EhLs#BlTBb%A,M!B䞆ȏϙ$]idȶ-m?Qq_E{"B(D.eH!JE@^ک I!#^!PK&ɩsEEh@/(BH$rB(D~ u+&r4êu~Iѡe>o*G&ė~D|uv!8)k4usM?5:!OR6ۥ"Y; }5Bb S!CԪ,ARmY>NDA1ó;"$,~`w!BTentƝ`j;C|US)'~~$$BTg;g<3wXwթ42>zC/Jz_q?ֽBzL1H3g+ϳGg+E'aye|I|W뷼~]#.Ez#-͏|os?B!\W7NY>=tnϭ,+aNٕi߻6C%!%kCx%M_$j1"Ϫʩg0u*Ć4AdXnW@x*U4G^8U-] p)9j⤷Ы!&!88fy[BiT `e'1,fl=$.+WxXXZA^q$$e3A7tFsrr8}-Ӗb UHip6>> c֬YpBǎ+Wtˁh}{,^BBBŋEFLI4L, -a#0K] W ){~$PQ 'J쬀=t}Vr>tn7 VGh܈~ ~~,XL%ˊCXd[eս5{owuG~ĭ{t+m>>r7nĸqp-ݻwprr;KKK$&&" 8{,^-r#CCCx-޾} EEEhjjd"Y{I/oO!k,,af R">jXibjv 7c+PzCıyylj]A6X1T33sz fZdƘ!<Ð4IDAT (*l _x1J r_x1s-oMusەv[~߼a┳&+ttpiZo+;lE^^yxaMg{ERz w3h D)Ͳ6ODI|,殱ZZ0ZG4%aboOi뵫_\<ضmKaiii7oZ/;;ƍCAASr݃_\[uul2.=2Zߑ#GsQghh'b]Z]F\EXelQ\- %X҈D5L_M6?!2XkA(-YZZ;X7аphŰR6B Z:s~.\4,YFHahYXlFEEܣO1[bd]o "ҟV0a T1Xl9Ǝ[~T2YY0_{ Ҳ!" SglµGAGōGSBBB]+ * \**`muT`nbpC-܃и6CobU9`(+;6XANAbF`QcV8lٺ __h~lW0N{\wvY;;;So+nnn5ƺu뺌鍅 99cP[[azd7ozAAAb@\^^k͐RؾcjkkQQQ+!%e Z[-FHb),Y/^?{Z[CHNl(?{ 惇R:bUMmL7i/<?c^uˮ~L؁qP]]j<9Vw`##5vۡxO2E=N􂎋7n2,?B\+p0C'/aīZ  VBZ̒`EvܤoL¥+`s Ƙ1cZ l23-CEE}EGu׬6IS4yJCp1?zW_JJ dǎn1b 3fLGxp.pIl̙ӑ# L-l6cD%$ %!sttp{i?/_>ڼd /_cey nn.b4ܺ1QQe K`޼9Xt E]/vp,,7`1XkB84gtn=?Sks-KJr(,Y =J 9r U1eLg7ݹUw? Ps!s}$ZAIxE{C#.[BC㠥 v"7粊GR5)ʲxM/l6i\:45SkbSiϦKFfPw3Mv1c( v[6 aw3WܼwKjy_WUUvv">c i9g]UTT :)TUZx^Dt(۷o[S1-EmÕ&LIvtvߣx kɉ(h@w~;cC‹MO\eK)3Z6զCMk*hij@VF^p""hCG,Z4P[[Zիx ѣGd}ҥK;vtj<).CKS"H=2Z_wFGg62 U fd2=Շ,\QLy6ߎ7nv435ɆLj=`JgyF*BiYLĠA?ePTL6r4>9qBC][5R0F7Xn8dcǭĆ@Y:RR= > >|(ĸ 4 ~. ؝ *lS^'"rhc(SXXAZ~#^yU 򲑗z33lcx(w"Nx@Mu5Y:遳a4`g &&lhȠVeuys>6Xan7]..hL{58+RCoc$,нFVriib7%%E( `|ni#q/mݯ0-rŎx2<}{@[[۷oZ򂂂åK˴p㓡̙3[C}ܼ¢ ̺:>sbBG뱵PTD=ZXXtApVyLn-!4-O'qdaN߮{1帄iK TUfq[}=(O)ׯo_StCϷ02dp2я_PJ)#鍸w//K!*ʼcׯ7?c@WT\AAf3Ì)9xs­۱<`YpܶRc؊ n( M6ZO . l-yP;|XyvI'Rlc`) Q10ƨ/b7yyd 8qiStv3;v_-?Ye 5ÕX 9Iʥ|g\1n>K$>Y:G{-(**i:a>@WWnnnPQan/">}Ĵ\s~ڀ0 xqGFꓓCBB44([ό-h!)ʓ/CIiNxzیLk55Ȅϙ6˨/jaVzzvYv/\JDFTUW0sz<&꿍eX2B\#G~OW JJKae+}"ԫW/: Mv()-mzC[[L[AAAPXX˗/...L˭Z z****PQQ+WʪS@VFRAJYGF355Ǐb011ό-Q!/lcʹUkZ{60d`FiW9fn;R_5m7R͜'bx>^^.)CQ_RR2ÓXbxEX5F fIùw"@Nv թ2%&fbދx%jk4A -AI2@iiddj5,y+[ '߾}:nݎHIm 7-Hҋ]̄-""&TUUqaHHHt)gtl;pv0VWCy$9Y~>z: HHH`V3 @ݞM6DGP<<*XHuW|lW@ԝ)-GA!p7I0UyY, =I YvZK+@#$eCc=33ID'+ \*X:fvM =^aOQZZӾg?[LD XO8I:pbJWHMoOgqCUe&u# !H@ԑ8 #uJf(]{!v'z%W,"mJ QAfn٣SNpr=0B}yBD nP_37v~OGDęեuPGfj{`k=h著0>bhjV' z$H@2C~^C9x1  BA^6+~ RrH3=} b3պMPGD$"+EA(-'"zr0t\ZBbW+C (OJ@)OŃ;D"vqSIT@ @~L?t@ 9,kc‚`0t ?]iS]n2\p.e g A$&("v`kDme-v': p $hk @պuiw6-!!!!!!!!!q6@;_+V QkK+ շ%rSqMVX :Bwcgk+v2="qIJ -v*AN)Us13 _YpwϩIq/`%} -i}14&/n).{:F}Zܖɡ|[PvCs^: ňƅ^͎bK9f?$191Bd<+- Ӆ3.{bf'vē+<ə]Jjw˵544p@vv ^Awzvܕͳ#o]n6 G c٠!;ʄ( VW|qWGm;ڦǃXqBy?1؈dKc[WG?;K~w_`4 T[Ơ_nz?o|*& 3P? 6?Α ?{Z˟|Zӻ3sm QV  p8`kC)ap)V2UʇZ[FXǦ U~K[Ӧ:Ξ.Oiz*Ӊvr2\ \=l_6A F/<2&X|un&Ɗ z|S^aGF'bZJn/*x{xC(kA L0Lo6BQ AF ҺR~B+z|P5V<*' MҤ|{'/Ɇ=.J `B`as+9r~zxWnNZHZ>UݬZMYaڮrj!m$9huy=-f vgiyd ~8$}l }ߖ~#NIxtL`_y=YҶ!ە1޸wDoIAр*k+6WcC(kw 7n~f#-M6~)Ƽ HBZZXWy b .hPVЅ]ܥZvwY ϯVEC#zuTn9dc'BѠ1rצlz)a~^"=qp @qEa\%fᴶU^:-cX\P6/7eŢņy?X`ڪ#l(5c=Z8! "N 3p0)+N({_<<: Z/o:&u(k:DUjN;CB>C00rf.Gk<m(܇6]hV~DF E^T7tS#FyS>lD{+σLM ǘ!í-w[> Ԕۅn*ӓbV(Yvf#_T /;?>,g'Iikx}n1d"~>w&l-ٚZZgitZ''1Clsc7MSNx=S1FՍ{8hPcmFH4ӚDZ^]'t^˫=NC"Nr̬,YA:{Dz.ͦNŸ=n:MhCYzDf׻O[VVwV4ƹ-PŽnp׻%o b<=-f-pxCxrR_D{b| aBIs~Uߑ|~.,6 Fр'#+[Tc`t+txx| E!&m Q߉\yj?by,;nbf GxCx"&G* P=3BS|ԥmZچnKңpIzTSfa .N{_}r'Դb2;rvψD3"]Cڥo^0+Ý_D.Կ;.͆/uYB`VF 3*p*kv4?sB*b|R{~":''Ŵ(̞?ڡweٚX<qxgkyzWkiẶwݗtOp!RSm:Ze@ ze ;We j5Bl6(ڐ18[+6]A;=I%%+p:vf7&`c"M\-nrǙ%nוNwVv5c5p8p:i4vX@|xPD|_QknƱjkSVk2 MPmm[⯣p8R0YP^kUޟ;sV}R&]F_h'򣹹jD}`V;9"G^C@zPB?P׹͒8VkʿqLg hM#-=QRku9kn‘9wwB9Ӹi?K"jm?R%O=&=K.WAJ?hwםa\kŵyhkl+RޯllAAzZQ -Z1Pr/߅iи`W9~{Z{i:te-Ok鮤ӢkyhOB$ZwOȜYmVh5hhK}#rQOun(+k :J[7*Ͻ{Tik4Ӧ2v5/wiKHllFȯh[m1Q!nP_%;H&'m iRs}j(}aCq6vK *&\uҊaRJV嚡jB's6Ob~3[ң*;5M-A^3yu&G*_W롴>S,N8Rl]3-RKr_8,}h[Im7--xC3L>~q5T? < a~#q6lGwWŕ[jAFTF F Equ#(S *- CbUu>mrv4/2a qNۤ+}BB\5qW]]xdNZڗtw-mNN _Ee..NFAssSvCӡߞf{J+p~n/,, }Bq:' .r9z_&?+w=]>;lN\ۆ%bۋp{QO]ʧ.s+,B@3nw`u^)#pqhDT5ņ #^bP򻗵J)L 7 o?wOmhAsc= .BJ?4N'*m&L+M1o&F?a;xax?rƇ{X-c" ?Ƭl\3Y/ cD5]ZK1(kBZ >F!oGϯ{:Q]6[;vfOhdF0{;lgm<-cG;_@#t ./!eLrr5qwݵZZPɻw |OBvԷiY:4fPW[7Z[u3`m0-in :47qiwUM찻M{[pdNa鯫2\zUGcxB(?Ƀ 4r&E[Ќ9+ac u(@]:ͻx`kL*B&g݁RNyX\36e4,6 ) ʯ+&yjUQCC1!\-Ou$߶z |E"em3*qŶk{kMJ¤Czv?:vRJ^V&Tſ£3p4?>Ks@V`B O^wG|/V9W3vvzGƿ%1 3xK eۋpLHĺL) ^m{G\#tsWUT6 xxeynMܕ뺸;kysLjNCfA{vTlC~7X}Cj*k;tfL]I#O[ԧ !}QN.ϙCp ^:#hs/?'Wc՘=?.P?oT64ǼRnAF.](rʧ~Z~.Ór]sisE[p ]wN.n?GK?8keh`20j[6jIHHHHݤtgCnj\^CH<؊ո)^e/qHvyߏ@ƠHH.Ap58kη[dW|J>Zh4N4XPR3q8RLc9lڌISg W %~ !w' )5=0owuiHLVvwineI{ðQcۥWU]Cjk6lX;r鴂|AJv[{L~1S)/?9:FaĔt\yյXꯝL;+,*}"1%)?/_ΐ=7?}"GVeCO ޮĹO0vʯb=s QUl Q9e 9tos *vt!}Aprd : ;t9!'g/nYLh",ͷގH\t3ZÇpUѿ 9ka- IDAT,zq)?2G[ko`i.z]'$O?i3F_V/M Fzߴ"zً>ӧGgcԿ<_a#zCx0nOk=>Y#pp蟙^pXo[c򤋺_=l_=0ƍ WˑKΔg18[%?S#"*QW뇊$Apnl%˃; $?026 -j'ө0bݪ(: o&܄ ׄ3{Q{pſŽGbʡ()oۉ!@qb߰wG҆ȝ+ _އӧ2cSsN醨#-=^=w݉Mkp YW+hc\tDa}',p<ʦ3yp5`Raǟ⹹OcK?m'9-!1mvq_{M<DŽӧF~uܰq#=x{{`\']l_=tS1e cb/_Y(gJ IG p(?7}?ph][ҕo?~3NPu*(K-g#w}J+ו]OG糮Oy6Vm~/|[ V{BgQ]S ݆7z%ǎ!6&55yF,ikFl۾~ _y {D 2y4m߁W_^aSϜT?C߇訓ꯞ&D_ޒY*Ld+`o!/' kVDkkRǓ-HG{ ga;LЀ7#)tz;G"7ǿ|1S@r$n1ɗ֟wS Y䢵Up:n61؄2EVZ G [H!_.KoW9Xϵ щ o\ќTUU!<<ٙu\!G !!k~ܧ} EMħ>݂?Wͺo.?z. ^<>>>~3z|t†("";:{Z[o DB^4h Mӧ*ЮWO?Ɨ1PYY%gI nʢy\-P?L iw.G`HNc)cKoEC&bam9·o3vn釦FS}ρ=m3-`ݞ_B{dy{q|䌗%$$=wLW^~)>X+/'%,fg_|+`Yr|28,Y)=.RSSa6t',dBuuۅ`@I1))-/܏wCnWO?Ɨ~x%BCC,)!!qV ?~ V9Fy6P#w(ڧۿ-acw)! xc 80V1}j*#w,ֻ[^4@u؀9ѯ6<*p[7f`X-L _~6O ]R^ޭhnRI FV?n XUwt:vi+m` V+v˟OZF s}}>FGGw<|_z3"}o:,&@Pc.zF8)B#q@<*˃OYF&wnáŊ/Dm܌A70e%a(-q:Gށw_ң G3˿Bcc# xYxױQ__z,^v񝄄^i:8R޽;/?{'<5 jQ2U/.XxF!Պ ]vK޹gUJ[ ~j.ΓKIJ}cf3v;*Ƣ1f_Oھ}0~1^} Cw| Bsl6㫏.l ;|Fd]m`Õ\Z8|r 8S̆ Tcm x$}RO߀l,-7zW!17}!\aАؾ};^tm~X.KӅcFwXgLt4AgqO:yw8j9t;鸗Dډd2ap :,5&eWq踊n#b yWXQ9ض1m~'_}ө@]hnn 53r;gHBBBBBBB|GAn/ə8cX<gn:4}$- 3 ĸ[l3RIl@`p~[?FDǕc6'q)jwی|45z#g{)IsEې54p}69:N˻*=37DǦ S@^^T#ٲ!tR: x8{=DϻmA;FDǗǘؖfI51y-T.d-~LݺW  CǶ6 5He ͅ`ö_2N!>k-Z.ݦ\u/L,Dqtqsk~^5TNg͆HNtl(X[=|Jϧrm!!!qϛ60~$`G9?}3߹ttŤT!:/V& NJ#Xݖq^^` lͦCeym2`~eV@8Zl%wk:SXe0d?쨜 K i B9e~ ^v 8< /o) nG Pb5|۸,sN w=|7ʎqHx\ՇIHn'~XT\?"NIHHHHHHt!kn7ehQ>ElT‹ ȉtږPGA6݇"yݑ8E"X $3Mpص [e$;ٴ!:,#!!!!!!m-GueSC8z(Z6Ĺ!MQbjj*) | IHH9 ֺ}!00j3f2 uV@]Eo4j0Z/7II/kN@E,jro2[t`lV!O4/SO4|,nHۇ/&Kpd!<8!7y.>!YWۏr.  v icH(2>Ll YeeL_j >i,z#|啈3dŲwpb@H2Oi/crTk1 tx{T9s5>LufnӇpb(wS=Y{3k5ߤ&FZwl콠xN/N}m%1l)c寭)/*-¼AiQ;YȞr)_;ucX|Įi|zVڝ>1%x5(߸Ha>9|*dr?ZgqګM+oVn:!sq.?9 b713 <ߦ^j$s[8?kt۟cV#E1I,'l|{)ބSE hlCq}gy9yml4/]V$~i^ '{B2D-1D 5gܐ#[#?NQt-d#`Ma*MҘ)6&ELE~!bfrPϲF/)[l7+gCm78FOrȤ,)?k|Q4E%6A1"M}e%h2M=o5m,^B}3Ԧig5\Hg<|C9CKIږڥPr&k3\zPT=B>W >=bH #GO#[ i첽7 ybVѶ1zޟ5 8aYa4$7}kƑ3\cK<1,Mv"լqǝgωa,w"{agk0P- bX%qKQTj,^% 'G=նXdA6 C,fjkO8an4{9;N< b`6xP3a>|~bO1,nuNa~#8We~J'm hdwB.vyrUgbE#k/#gz6VdCgۗOQ4 rKLXD7+\H )2Uyć3{/l aSS؟_'m #[pW.РꗢmXIxA 1am!œ y Г(ʴ+|{5iɻ' ya **"MϘ{}=$f"zC#N&,)343@q[2b*\ߨNUev[ kb&ʣ^7umiX["+%J 2^ EI^3n5I㻶ƯA/\NքI퍋0xH#!SǞBf8ڼY6E/1.yD%0`%9s)2ll=(_*ψ,I A/e㙼Ř"b>JT^?Bu\HަÇIP2s4A$Mr63(dדW5^ 345s&[UiZa4Km~?G@VV&-̈12GdH3XHm (*#Kb?#)j/??>"\vUj 1snMbv `aag/4p rG^ l?nGܣB ibjUr"N=_[nս@=)T3gP=ibNۗ41vr]\fY{[p\od㿈r$pwn֮tZ2gkۘf󅚱N6F6^[-լ ϝ~|~,P1i\4zl ˄|I|Fڭ}l~ [' j?fCM `ۨ#L1Xƈ@ޏ{~-[ #+ޡFTpGsof>=WOo/Fqp7qAx~|INjp*^+gDj܈66H OD\-fH;?Qq(=zwVU@xtY) D vxyuZzĦ* ) {<݆HaL&+ӼLӗTc\ďp+R4YtsbfX5 i;WiW) qilm&y ^HsGoDriYio9wckbgH yrO1ALALf6VqYEM+1~Ջ4SlSo0!F4 e3?nn 6&1]+X)Lx?Wrɋ4oFpS;630l,h?/O]Zx7 ;@ׄR?3^jz%\Nܤ~}($6Oɽ)[Z{bƈaVb+61Y3w>6SiDhVVkWYqxQw IDAT찭U⽊^*{WM_dAڟV1[TX`)W<.4芍!F4 ş'LI>q@ЏڼKr}Ȗ.$j1Ԏ&#Yd[Di<m|T5o6d՜!TLKPNUN ?gElO?1LV{Fe\~;"y;pn#V)u(E=\ >fr[Ҝ'gvrlT_3:WmSO@G5UdЍF"dE 1P坲 | 6çf%N :ZkOٌmu-\IHHHHHHHHM\O9Xo<2m"pf(X:F 1#S]Ş9xW㚴H_{zlUo,Ju*LTp`p~qXN~C:uO"IŊr /_E)!<ސ^佇kyy=( 6n{[XuD(o*.`O^7D("zS [rgC JāJU߽cx{rn)٢tH0PCVj_~6Øv~(乽VnkjS߿DEJX>5t?U^=^ Dfssu!"H6oQ5yl6kTjJÙ b(\B{|\p9b li¼3o8Vt P9!8ۡE '̞=v,X(f 5k]yf{Xt) -[GLL 8gbӓOhC܌X/E ,~͘tхm bÐ433Azun;+IB(WJk6aE)C{|+:tO^&**ɷ۳8oOKg"[ תIL[f**i#yi|I#KWR}}eEM C?tCn|CY;3Dm_%[c<'ڲPAu,anxS*Q=1"gޠ^{_+y!$t&64r\Kg܆1ـk6Rylh`{h^jG'4%uʊj> )/!Zt8xϺ///yCC7/>7&=<}꫄VZyϿ|ګ£#_^gyʳ رccǎ? bҥ]s~KK f]}=$'w!11F+~۶ Nrl œ瞗sX4zƍ'hnbf4(gUMн /h@Ɠf4j.j(+R 9+-} D[5yNQۼg>d^O<5(HLWLj3勘,=C }@EE i擇xc DnԠ~E LPĨ\$M*S;=h^5֭KC_Mof/X) Mj=0E^%TX]Nd<fjok^$w-L E*4fs.cG9I~i'K``ږMͼhޣM|6Ĩ F=.T&FW{wG ڋZ|+WJLK1Կ 93g,cP{cRWǢGOr UـҼE'WD6>jWxUCPQG1EUw sks+}^.dKlr3MdAYf2^yEdʂG|\}y~1:KXsM&桄lYf4tDa>H{G1/J#NJoUufQ#JL5k5s`L:Ly!b [P]&PCLZkXrܫAH`qEϙ!*8V˹arV.Vkym&Pɳ:iރ-ޔJ>t֝zW8 O ?+/1Ѧ:Q!ͬ¬)3y!W*2P9IV]4ȎgD̄hsB(UtQm1:jF(6/MV.aUJGmg]!.[(QəA]Y{YahYj.ҋf0XhZ NxSm>?U 䗠?$޻d10l9 > W(>t/VH|Y ){&N?][np8o7\<.hZCJJ<** ǎCBB򬤤QQQ݊Cw)}oO ;0z!Ψ#/wO7a¤xt cF#eExäĒO yg@I1V~fN&oڼE˦-taw+W2 իW q{1[qaǎի(.=S9O>O?Z^1n$,|v"+FE\|B;՗kNQ 4trVkhICo3F4I% 0BLEcsX~ g&s?6a:5w& ne$ƓW0~7 d;@oHN7ӳ?|',xin_)v46oi-84ѭ n{eA^|Ydy՟4&gV~]Ȇ4\CH u?^HM=1W ĞtUN9?^ͷ656pX:+vݣm A۞hlٌ ^Zog^ ~ qhgzSqD-Aym7Eq%_HTWTYɒ0:-a?ֱ^Fߛ-̗5핰U:5sXBv"Adb]֮f &+V,]ˠ c}uSuG!""&yIy1Oڱt FL9n]lχA 8IqF l"ax y&xm 7W8(Q-(Ԇ ZK$2W"c3:pRvQk\a})R%}@@r˗柾늫߽H6Mּ\q/s=_=Z-wsw5ǽW/~r%̙3%Hcc\~r9c."?L2XjxC1K.#|~L,_Wv ΓsL8drw/Ϟqx;_B~eʴ:.r~}sΑ뮻Nƌ#rʼyo6s1ӟT,X rwaڕc,X 7tʘ1cn[nE>l?H +H|˥ERg._WwZ}l˪/I*U_+F:/%_ 2>|Ç<:; 䩹W])߿w|ڕ9r|1;J;Tprǿ6ۑ}zy֚L^;ZZGZm`p{ <݆",J|(t1b>yX#37`Bp}s/5+zjudND1'O##^@ ]%R:ݼAD q g / ~ "E?umo Z* \Vd"d#t=qdq"c^{m7^G;2CyB3Yg"D:HP;u9!l$rܰcEN?= AHO$S(֋PY{LlBeHw4jh],/92u|BW1ävX4J8M@ڽ6G[4\>1F/999{|qYYrpVolȇ>|@waoFVV@"^g qMM"DW+T$ )k| lHj>- \ 8+׋Qtf'N&^;Ztt޶P8HQ(RF >]\h/,S[C0Яdi64:MBZ)`hqAiT)a^D=/56#!Wzḫ]Lxl0Ր= /i3.]"`\mU{r<2h@bNAkyPX2t0@4qӯ Zm@{B!--D7KꇼEyu<&.6p\XSDn I^j0fo63+]7EZ1ay5'+|'#Xz7EhLUP/f۳A"mAv&]碋a[xbLtym =]׵W_=ѮKn, @ihGΛy]d)\eޏ5?,O}zIaD'!$sR=p1z_۩tp]ɌO0RĮ($v,z2nYR8a ;4uC#2I&S@IML( fft݉~?(9|=_ۇB v Swq&Llaذe}RXsОND"C_W 'Z2M9ٶd,>Ԏ:0NZǤj[1n]OjdTaxۛjpX!&=lԖ0*B.DE%ּ8%o0r00=9/aQ܉fLh60Fi=4L-(|Ç>{CH_olpc_~򅈈^m `֘STy'M@'Q$3d8:7:yal$AMxNddzp%{ldv\wW:~WNY3HG1=$4ܔϵ5btQ[Uf;L(=G oc=oCۏx߈Gv~^bv7"l҇tYFư[tw.L&s׵Iz훵|Vx#ẕ1]!|جXY3Q|^.d%!ʸuiyK  A uDyi+#XN$}_ӅL_HSd\/GF!Z=vYlk뱕k\L˭vf]b;>ua^&h ]w(G"nzԮyNjَcHzu{Q8"DJ|C qo>|Ç>|1,|#T7#dl""җ7tkhw#"LI7{ātjt>M Pz 8M!RO9FQصj΍zߺ"K.\/G?D''Af\\-˚m+'Q=v& [mס/Q}YKzqH%]Zme/ňfbd"l;nh ѝvLcd^pW#Aj{U .M}VΩnIt8[Ad\Vz> CD&~\UN*lMMY Iن~z6 rԿ 3i446bX4׃Xڑ.Np=h|^t,I&~tyǜ2M0Ωy[;`8r@W`+tFʭÇ >|Ç>>|8'BdE~joTd.2I9@ 2w*oAdH9V2d"Vp4E^iE*&B{!0V݉ӄx"hmR0ܝ@[f,F ZAO#R!&+Txֻsz\y"rAh,i#r<壖A{˙'>/ar~6y%fH.ߺW&H.%Id\ϳٸ`!])3D G}&_H$Iv"a@~h0EZ1>q'a"2/YNNyp"VK^A^H7]V?d DE2"2\$V@;2L.2EX([d7X:ol"t1kiiqYn/IMR&[B ]l7Lfɔs#p\2}_wd,lWM/,mXW4&%7MJ^i9=+-wCȟQJiGb8جnQZ癄z6ۛߗtÍ]C>`+v<$49L&۵:WyżlԴVZ0^tܴ#A]@iB>?0fj'Rm/-`j~:Ь}ؕc/E!Ç>|؋_k>|1v!{̪}FL@+D]'PH8E"_D )̗BdrK_e>=|e!BdK^ D{i\l=N }f;&(c~9s? JKlFHQt375˵= 8Ol..'QF&b>?=%gtZ'#`V$J4W7}&PՎdOCWsJ㾵UC-QFGCЅՀpj=44y Q.vj{w$@-@#]5arGBwK A`sLle Ƌ6Hhia6pj Iw, ƊP4j[#c  ֳ0D ~W2&uDկ\y; -ta>iyjqՈ!]=X'pɱy25ܠva62uFCN0/2V o`LW Q%(5mXu!]GsQcCwC>rϡuEf  (]7_~|FVV‡!ƞa_18ݏHv+>3OQڣ H"ZDƘ.M_APDYjT7ZE2L 9Ӌu LAy<}3%AƂػ9V ڂõ'Bm/"d҅I0S@U ,UaUwޱSDDdŊ"Av# )"/g}؞)8|2@R6RO:Ɍ^jxeJfbP6`O~@|:쿲<2az|Iv.,qԓ򅙇 @$#.NQc̚#] e<G΅@Ra|}ٌ{uw1мH QF߫@D͌]juߵ18fSXЮjd:0Nrl!t=H"VF5yz+c G-(={Aף>ZֆqOXJEZIe\ĸj)ɸ!µ1μmik|suXO @ȜM2&N`tWK`ޛ|@Ud]-1uO|^D2̸Q{g*""4Pko&Cd9Op[?I(֫2kx}d܈#eۛoN͍ȇ>|c_cǛ dh60E>:hC!J&rmɃ>(HDF)Gy\tE|f(g||sc Q]Fr@ Qڎ=ߩ)D$rX Dz)RDHbMDoA-O}t8i](p]]""R &\-/MyV.=a-i]pe ͳT.Ld@2 -7ڐ z 7\\7:7 ۋL\c\BV?$_h͸r= ոڥW@A&2Dj9Ncc6[f&y#cmk>83"ռ>#wÜQ{ [!wi 7}DYQN/@3q<;qW_q8ƫփH8/\~f~H{8j:nL73jVQ9O&Gc_1WǦ]$Qn˱!^2 K<Kj`f~Fh ͛eeغΓDjj#dhfLGbZ2FKQ\UN%?(=51128.$s>5ُd'nWaEMxuZ4?;p7^_2+uyFcߛo)'|{|Ç=FdgKqϞ&}䏲c[r=Z<ēOΕq3uK_rT79OÏyktʩ2nbͪ=R'RUU%/VF!O}J׿Z[[Hnn|3M6Y_"GuJee׿~{FB/˝s}IuuB!2e{;Ef͚%9992~xk r=ȡ*999RWW'/2uTɑzyv|@@x={JQQ̟?$CÍD䭹&KZ.Eg2dڨ1:j\O\)i\7!D;^ )\s}RWW'7n.HO.7t['x?2я~$wy̚5Kݲe9宻ٳgK__\}䡇'ؾ=̍;^">|72/i)3gIvv@&/ oUÃOZᰌΖ3qۏ(sN8^F!2zz?Kmmf'>!PHoz~-]w%'t9R&Ol^DDYhˈ#裏E…zz뭲h"9#eĈR__/-q-ȯ~+9#%;;[***{7q?C`0(^zlٲE^xa'"??}LF!%%%r뭷O?!c'hBE䎚"̠I%H/#ձV㪖#,"<y%ftQ5JD.<yZQid2U.}VF4bpc}ܽDܭ݊=bGg\V/Lk'1E]ڮGsTa,\ĕL"GR"dȘ.J&_Ur*H<\ĭqYjWY#c9DgvmWv+'Xz͸W,hvuQ3Y5VndɐrRslɓC313? 2feu'k=j$08ZHw~u2&ae\&"sJ^] m1lZo\MjN9?8X_~vSo&=Ǎu}C֟:gL_2i%A^ygW7d(2\be?V;ypY>w?΃!J$R];]X9TmS2tA1n=,=T5spq2,X4Y^[rF>eF%7o`sE"w+K.5}wAI ytuu픿1j(088(cƌ[klڴic8˓78'܁NJRL3}7|>WyǎܴF:dm͝ːM7\'>R1q<2';P;ydYvկ~U}="D3bWd@%:}n^D]q439HDި=.= Đgu)'r"r{q+*#à ӊ5F!r&wEH vj,ȼHj4-܆ fŲH,s]"B犐kgvgvwJ(#?Q+_nMIIe)܂-@ԩS POYvǣ[ &27-&` ^uPc qD뼝p"DRVjT&kW8~yD&edc$lDy *m7 ӫr+'AJTǢ>@]Fv4(FYQ #ª,(рAtM wJ2q-x]Xa} IDATm?%5v[@ 0GIZ7 zq}JXǨaº 5-f3gaGz8 yFpGގD-[yL =yy:j::m:l˱c=X-g# RC3[WQ[ #]Mgy:Ȥg2?Ot_e '9CKLd&cO`xP\.2גyP {o۷mD8滺#c?!g1ϝ~2pul[^s\|EDiK_?y/g! . Wg}0I?ߏ8.zs='s5=sFS):^N>d?:3gΔ?}îχ Ç>Hv_˼'"" =~u$?gAy˗Kɗϒ/yNe``@{y1Eߑ]q-7X'\xUFڝKE=\ijjT*%[l'xBN;4s\uus=L&I,X`]窫oMm&|0_tErʊ+$JɊ+ //K/ /PcX+|Pd``@}Yg?qWN j *R|'a@!Δ"p{ 2 UF^ gpdfq!J9B~E)1x E\rK6@zW Zj5s Bw;t}'jdWP&(jס恈1۫"=1/^m3ay6B\a%RYvOu_=V/ǭpvucsR?q2e0F Y(2 1@DɜnX%)e^Ah6d2z'j}"A$s ӛq XCa8v]؎ƝL1YǛV<8^[sa-3&0߸Eh%fu0Š\DFƅMw[j,mJYܣo3"5E ܪfut5U L׋:d`<C'WYkI0]GW6?3گt[Fb `*Z87=# a`-Oi;V:kIIjN*aD[~kx\g'v&X8>1]ryum/5oF- W9bcG9$f=_.>9k[ 'n/رCf͜!߹ B񭳿)Yj9R?J~SNT*-?Fiince?ԃ<3r뭷󥵵UF)rE~_g-W]u7N.Rwk~?$J=Yv7NYg%կ~UڤBJ&"/~Q3ϔ/\.s̉'(/oQoɎ;䨣.}îχBÇ>|?Į[=>vOt|}rg>Brʵ^;1GyYeo͛'wwyXo~o~sϵ>p 6|n8*"=H0MtY=IXզϝ+D$p%nidq]UhjB zDT]z]W;#v+.g#2-&oFBY0GC-,L+RKbhF|K-/H1nk6UcG9sFku;T 4 h׍| 3ǻ|s!" !{Nl EGrŐ(7! ܠ0&(ԁ7vv"."nQJ7'f9Ϯ7nA;0Z5菺:7ԚVP+Wj KݨL#sZ9\r ,]Xo׍aA0bKm&hPn2]Z(Ƒwe1IiBv~!eTUa^F9V{6o |GlJZc0uB"?NW4_/)7AkJk}6$+VXnZj:Ex(>Vhٟwʳ+L咦k|p %S}TWc*:SZס!,H=^4Wݓ5RKc6upK΁48q ۑv1;1:rdL+ _ `<ȇ>">|Ç>|CDͥ 17%HSYv[b6K=; Ӗ0{3ZU"r0\ހ:2(A#hN!ǦJWUw2dFg[&r?{Q4mUV} p#XXmKa@  }Nh繠^y-Z30{d22yp~D8{ yS6N&xZ2@`VuBsU`Ə_Y0}nPUvOnTj;;?I&jG[<;ȷڟ5O[94ځzSҰ'^oR(,Q+h*\ /;G#ȼ|7dvU1kA?خ4tMnUñÂz@u*5tߚC[qkj."кQdab\ 5mi)˸6ny887I(ʙcW!oyHHOU^́]` 㺲!7_QV\63Ĉ印mG~f;_(K`u&+Q5/i<`7/|3AUv$Ƽo\3"&=7daPr)9܅9:܋`jY>|G_|Ç>|cvٱ}o> B"GU*H".Es4*p=T)H^Q7Ϟ%" "HBҽ  /2(f 1CHzqZIU5"A0:qԻ6;OWWL\ jxR~FH(3u=>oV~uVx@N1Z\s)PukEc62i/)O(ci;Ϩ༳+pT >q'◢mے1|^DD>,yj$%kf"n2Df:gx"D^ v{ 3s33aD3If z"^o"{N.,r+4/ƨW <֓ZV`yrϽEZq̝ mOO& 7Ah&15yBv;ǰ<;tSiסּa שΘ}}{d<:yAȼѴ8uq@ä=ިs۩^{YSDTzFaᴞpXLѥpdd'U4ć\? :p1uALFyu<-O@.8#˘>i$uq(7ެf,`fU;OdVM96scc=|0x1zxyÇ>|c"b0xj* "z* QLAC "UU>;;ݛjGCKg 8fD3oz~r\A8>*z07"U$c@wK LSg$ѝ 2Re׍<;o-i}^/zc=rmܭ] m˕@Θ<1ȇV BfEʍb|2dVQ8L|FdV`>@Yz6S3 Ƃ߻*Njs Cw9 chA?FlMS,Pu(nk7XjvU4;9v槵mE^*a;Vޡ-t&Zp&+k`҄2!y9Su\l|;1DD䦕 Eԃس_!v>~|!ۗX^hk$za#2ƽ#y"׫x ף I) )Ž@*&ido6M6 w,6$drhP=D7\~'uE;O fo QqV"ԂDV,(lRH7/Έ3qkXM2C-8Nl~͙Vv^<;]kk+_<2wdZ)2A0?pb-i0uL ?t+xLYz f,/["QS8] m"h6OWF3~Zжz^jOR#XVI͜x=B}B9Y Fu]$W82cАAe82Cn#2vt'd6P3|?vbtm)#2 剤Qk֗ : @u|7Yq] z|\.ymmmhGquaڨ g'uuj{m҉=uS^P|:aptI: 6eoP ֏@zް\maYdy]BjFu.mdR Fi:qc4YX`3WQ51Gdb\WECk^|Ç>|=/Cv~RӵCOq| ѩ5JT kQ-F#ΞpjFuoǞ{" t܊JK$lLP eNIU 17|&BVm3`"ȅ!;oq"ui]DPEL۪y!hџsqzImO &"fˁ(YDX]-av2䚉Щ #2`D gF14+q6'bj`"qά5#1hI%fktpù1к.mvqcԋZ-xjJv%R]Sv Ab燑nM i;E$իm/]T;]σVTHqg\k;B Nto[ݎ20dXPG̓f`]k]KZ4mzG5/O۱ .jlƨat߷J?a0@d.ԖYmy{Ğpq ɶ'21 2cF48]*q=>8NsTQs2;T]n ͢G&3[i<0'!?RD0K`P yVtz <}s53ɠb!#u }^EvAF_(jhѭ 03 mf eeQ+ezXO_ox!Ç>|w m߾]FuN$n IhTއrұoy!z>R&"B3dv8n2_<>kݳ[ $HiM~g'פ:mX q')kJڜpX볤Qt58A8FD2gt ]{5t[eV!;{/ Tl&^ ps'Q$ӹQgw"p_By*%i ^L#Bלͦa5^oՏ~6%n Sr8=Mz2Cl7ɶ!P6VxFlD2jn~"腃/O0R:n]IP&UZ @d*LxDP`k*.ȷTRh3.SS*:@N^2i0^'3);J0"%b_cQ$&k23EZ1X u~׉2btt#Skb~'<Օvj^[ NpETAi7hyC5.iyl5}\֕zFce0WnR׶ќFUknu'YmUfze^ }[1;P4d7c<¼gd[f2,wno(Yt"YUWc\i )L:GfaFQ+A摚]BYYYrpVS!rCWwt~Uȇ>|ǻes^VV@>@/[έju/`nAow˲ʷWL:Kq"nflfx"^ϮR"]SԬF:*1AEO3MDDVL.3d~4w9W3gBLݸm/|" !3Ľnzj@jؒHh6 Ɓ{YO7/S1܏/m]\%2) -w\Kl';qOy2:z"A:AKQ2D;Ƿַ ^F0q23)g)eurpV<rmɲe$˼y?5*70m^\\l/""뮓H$"UUUrM7? IDAT;o_%=lIP5E_ ٻu|jȫ-y|Ç]rۏ(>?O.NYf ʂ cNs9}/_,wub1뮻 /+VA"-YnǗ!}!Xy?HH;5Ltj'!`$1 /+I 75 Z^㈜^|6S4(G3+2,\]A큽A|Q+ Y""rbegmhÌB ImyDXD^^!'=d6 sAB .KZ[r2J,h4a~ H X"UZNj"@Dd̗AryXoMSm̨<[[DJq x A#+1L9&]ᘲ-nHX9}&`ܭF%WB"KԕzFۓrJ)5P15[t$}hP%Rb _q(Äz\Gj*hOF:$ W}[q@&ejW/C !iC]W4GܸbsT9 aAG1z:HFf75&dbyps\Z"K& +}X1nz4YohtbX 5)`/>z72_΁F;ZL2pd>82T`c YZvd G}r#?v437w\Ǝ |s<vp4Χ w~$+xhVzs㢵Af"\q͕3Ϙ/?ů60w/E?G[dȑ9m?w""OX$Ψ?^s슫&O"r+/#l?nQ;ǿ9HDqijj2-\PZ9DDNkV.\(,ݢ|}n^nDDULu^Bxȇ>|_xPY_Ґ,d]YVG]i~?˝wL~yϤ5݋λ6=m?o&O<Yj=vc4$&nFK3ɖESN9:Oe˖bD0/2d^XvNڈ=Y^vl|E$"o}5YrI.:Kt9H982hs.XDL\e~Ն& SҢHO"Dȸ0 #egJw5X 2`^l"l7tul)}L^l[#䖓{܉t}nRlg2&KO$ F j&Q %;\6{*(BFt d,_f"Q bx8f;pߜ]cA&ڸFO;CŐquyq'd7;9NQtx׬nǠFe~,w]t~s&UJϧSW쏼7#uhc  \p?^]׹. E47cʬuG+vv?7Y.ۿ_q,hwnXaJē3O=.#eK_ɲr 0/%/oR}-}}2}ƑUw|4UW`ߗ_anp(?&9Zs|ww|OIc*hWh J`ȝ~,SNC$v455I0B%m[RćmoʎyPnXF|w^wǨcۛIn-|V;^]|ÇM<򩹧_/GSO?-~SC'8/4돲q?=o9O[oe;蠃… %W_=1_\qː};U-\l"Yrۏ~uR\ߋ}TiR{¼'[Ad:E C{y2 dmvF%}j?q3~l2ޗyxUHnomzb2(),.3d:t&f4[@w*aԬMrDm3j-X-|cY kkes/`JV;UQwty'>Gydзǵ^+eĈ;vG˓O>i}SO1ЇË~e3Pl0'f}l9)"D*MED$(Aބ6' JEםQZUP$$S{DVBVyC}faO9=H.ș@[ZD>g8"M ӆcߟ~Wk^V!Qjx~[N)N8PWNx[eko%nk6,~a9Od6唓?)zxs\˽?KW䊫+/L9| 2O_Z^~k{3<#w}xʍ m2pny_>W::es0'_ȏo].{c5s|{nϗ>=zRP1~ o6vc9F~ӟʂ U;:=YvGlwܷ*pe{ 1˜F_tUu!7@ VE"Q[ÊMrM7-"ߘyl!뺚]nGޱ l8%~0sr~vtui1 ݚ*}; G^k^.VanGp.ODZ Z{yB H>wMÔjMWA~*2qd0?67{:`B44;^.iw^ J\?\faޙCՈHF˹.yd` -a0 NŦ^4Kmh:jpۅJH8ܺG慌 Z<7]3L3fSkm}u"ըsaFyCFz}>9?˹pruL`¹?i?$2ּwz71>/*t{}\v|L|V.s^CÇ>|1D I\rٕ/;YY__{>*=齖ay,"{D4z*fv'PZH#?+kxau<&e+@7@=5D@* dJK $QO>.M NGF q^"!Cd^AF9 9a # ZO4j-kcԵ2.p&;ݕJ)vwݻ2݅d-qZFk^ Ɔ󏚫^0 ͝1EDD^x=f/40Vy61Gגü>z63d8Mad'u~"j 2Z>]\ݝV P41i^L+;Iɥ,}' T?&iش^nEC.3u {E]hE2sO2uc `y/~YY98k lK:7+kZ>">|Ç!KO/?7݊$ƌ$v!ڕnYT""s"!$I3ZL\sMFFn Hݎf3br nz7'<5d 6D$0`#3'%l7124DOa&^yu\:l _]a;oOQk.Rq'#xlki"ap#J)ݡFAV r;,$BYmkLfa0nO1yU:t G!nu J3yt2"Wr[FRHB:z:yCT`ʺ7s͵k4Dkyv|^D`--DCS#d)Lx!:A n-2'#@PjOsl2m)3t)ΣL/=ojetqeZN2{Ɖ * weX7>OG7y {14=V) $W45;5Q$v3e{ 9Ub$:n1鸮yQ`+hZ<_ʭ?X]oQ>cbg|ښ0/W /.=fc]Yg!+ᮊ󦖀}}|UvBgfI&MLڤ-P"WWwY?Е}u}(*-R&%!&i&3Ll?~efysd\݁zXw:+Fӽ]2=|X~{qso81#K;*~Ç>|F4V"R<;~\l FtɌz]mR=ۦ}G-* ZD}|"WׁLd"׮[{{բ:2y]2 d`;nh-,K+nŨk2H9b ڥs_p&]DZ*_~Xj{}"DYԍ}*߉F[džQa sD7zv2 $Qӆ 1^A􎃡^0YI}F3OL A׭E9+25.#82< L(8?d8?Γ e#jW0ѭ m=,miv#I\[J8L0Lnm?5oVc (.1{|nu1r0mO4D}du:v[߅Ē+X<~KP?,ӿyy:#?*.z:DO<:YA}'#15DGӏNCЏ^}ӯ8wT Ç>|qt(:^3Kmo1E҈F7B$_ZXA_Í\+*l]UIt?J|:7 u\dč;G)&4٠ێv*j:*I\赡"@;]Z'T7*C;dYOijDJq"MX8'"`9b1+"= Ϋ'._d&aʌ9udKs1"B&ІA5Jwc>}@3bԌpjy>d~ruxykKBO#`$Gc:Olb-en u dF* C5zY i?5uuASAtnhϝf|Ç>|8n"ZW^mȾ:uŊtJ ^k50nB2@("aud^Lagl܃f!2d: Rn_:Rf̍[_ǭ޷ \̺ (I^BK>nTi{ғkdTFjly3:[*38_*GBJ'=_0/$1i^21_9DdZzڵW(O%;l= .`e7dd2y\z/-S<;Z>Rh2jd'T19;n&qg"+Y/=?_ fpÇ"fWɑȇ>|q\Fjwke=_& "Ҝۛș["@AGfEn&I .+ +(\_" "ɥkC‚ =n4 #MbޔjGpJ.SS[qE("^L8\zbQljҽd6Y{jgZYDɔ 9o&;qP: TVb/<L@D¡a(1/E;nֹu6bEm}"mI2iqdZc"ڑfh{1@;1dE0\N=!+o˜&yAy9\ǺOn=% c|v\ds2t%6ź4Պ/5gSNJzOA0ٰ]DrH9{R1ϖMϳ5yV׵h(V5 \p3ql41=f1$\8uzy:s ̰,Qh{bd8?8>=5p,:l%}dғ׏+ve^E& ʔ@2E pdD uK{qgE(d &Z2w$aܙГuinc2`Q@VuڡO]K@Ë|8.6ZoKl/>_^"j0E$qv7½̊ͮ^h T()i簎$0) hiE PL0@jF9ʠ_\";ZW{Dd1|aK*ԵW^2jq?] wӠO}p\Q7nL^r;_Bq#Lz ฐ;b/q~6`>ء~΃}~rb}$MeՄ)zHQ2?c];w:=|qQ獈tzQSׇ>|qŴi䏦MϗsLAĽҬ|Fi""D׵Z; 9!Tu,k",g5B 8ufT(D?FfzK ^yrj , JtںaqeX,/R-~f.3r@DL"q-;7q{#)Nqւ.2lw"dnn 3<0YDy)CL ߑFs]bKyK~3bm$q\p\Ĝ,cme5V\Q^#sn4-m`^aօ>>!EX20Cbw9P2k̢qh΍Ϯdy|&' w"4B$%Ÿ^`{fI[k .x.a R{Ѐ}0rn\W4!`Xb9 T̺chA0d9L'ΝQc WXnj5p;?BG~ k+>_Ç>;aP3ΐO~F}$:sTVUU昞ҿK3G"R5gťJx|9"_^-7ƳY׿.552P-_.+7oo%Kϗ/&[V#k0Fϭj:Ie0P7ElF")2y@ Cև*ANyj1a'/ Ö 3@og](W\Rv:[XC=m51d7dTPN]c̛dKX2 Ʀ<&G6Ȃ,E0۾W[%"b=ߑBvR] Ck1sDR{Yiyu֧\'O?ou]'g}ߖ/˲j*I|E.r.H/_.O=K2oQ."ٴiU6͍Z<#R[[+r5HYYYzr_??{WVZAÇ>|qD&?}??$z x ^_Ϙ1CHUU9gm믗r?oRyyȟ\,۞|\N8QYz%VT}'wٳg+xT_/s|+_G;7 NV b%ވ"GyxmPlԺKP3C"HjCy$^[Ȳ2 3|ϩ7Ľnw"dLR`X5bv2[Gg!4JDt3X,)vnaӐYlB?tx?p{̙**@ (<3>.eexDH:h]8B1ׯ""VZ^~bX-M"y]D;f>}̳|BapyvmL"ںVKWj޴#?\̃HU_-A:L{I/]"z (YyyE&?n70p|}:S%vtA.D :3"?fa֙ʚcp=0bϷ †V b is/p Ds2 ڞ=~lG2]\0pXgS{HW>2occ߮7p8,?^ uS-[o.σCʫЁ?Td2S\ 7#_o~/7)ϛ'O:I~?+y?|y;1͛_wn<.v71ȇ>|qTGUe{򗟹B|j\~w5m7!_~yoڵi&;wp R]]-=y~Pĸ곗˝w#/r}?_.ߒYF.Ryògˎ0ymo>k?X>ؘr\) H7%wQ#PU""3S@Q3Awd22K}L–r;]"sY)^/""}cpd][G(p@Odv"}$ɧ2UtS(= E=hsSS ""/fɛ֚4M[Nm͊DZd9 U=9 X@#+cp9Kj'Q\A7e{ݺ%sa![2,@*ANkHx3۷k^8~b(I4u6u#(ލ|l(31Sv=#Pq'F2:׆h?,,ZѨ,2uatCUxuO9*e6jteni;Tj;[ !'!'Ǒ4M7sDQ&#e]--:Zm8RR FZx'-VyPV\hƩ ZFNYxiCtdF/w>zN 8q:zO3хTmD4xA%tO31Mf RWoJ]v\F̝b|_kŋHvoT*%_W\sݻF^xҗ$\sQ&ƻN?M塇=G/ˉ'.zKnkV>lZ?oڽ'?)we֬Y~P >|㘈Cdڴi3 ^oz_B O~"e޼y d@>?or\w-""~/>]; 7 DB2ܹSϟ/]裏{ 䩏WY7Vt8@tK( ?"LckBDD` bp/wd]Hi"Rؒv k;D~,Y~ $p=/ǽȤRi:`c},tvXTcbmr\Ƞ5q]'^B%yԓ]2)#"OP?~{1qHCWgFzҹ^S;Th~d 26`ڇ'qm$;,H$7h? JcH(p{ᮕ'1P8d@{Z ƛV訾&0R\/D]IslYD yFǀг-I)-(EZrje6%-u)YќًᤓN~ hBdp<4;D!Ҟ-*PGg]u'a=t滱u֬9GK>zAuixc$$Ȕ|sn4ֳ#1GDžFT+WM)S[F0is=uy2$5?|.#Q+f9|SŝY3V #Qkʼa=.N]oBdvSU:qh t#3z?X~?OdJ.'j^O?x@~_ɑvǛɧȣI|YvYud ~1yxȇ>|qTG"WrwI'5/^-{cfWmzG䮻_W2cƌI .3ZK/T.?orB!eg?yϙ'*of\|3 rWꫯq+Η(C=򰭇"""t6#ɺtSJceEͺjluWz0`iwխ:D6#Efƞn ucA- p9f*WQܺ75U桟H*S#U_/]jBuKC fJ WSjQUZuXI0:p;Q`1TR?^sm6J&Юah\X_G2}tM5έ? F/>e: C5:ie,dڲj3}̏0|9CTO]kIm"jUHp ։fUC <,N v\,!&"e XڀA׉oFmG6ۃ~(:%B>6'}b愩#C3j p2!d 8&Q ' ׼a0dZudHru !>W9ndxtYMjIpZ&KMij{ufd2v#㺞oJwv4iS{Mc;pdAÓCBʳ15 AbC< f3\ :ͬR$Mwϥx.{vd Kםޔ8NR箔S/S/q/mRv#5k}ǡCNfwq|k_3?}Ks /O|g5ke\RG">|Ç%"lܰ~x͟~"Wۖ(((o]nv?x'OJKK'|˫ƚ5k727vF"Df -C}9@^7BkB$zӌ:%pr(/1/ _RE=ⵅօhYEN#"D6ˠiD+z)A}a ΎIt0pꮳ#I'EDduR2rfH~E: } K1jp97'`FGa6:^>Z^a;f?)]5xMqքCfbZi@U[g9[d*pCUPvF Y o/}gP(%xA9\'~(,U4K78fOD3ӏ?%p[a_t.}4<Ϲx\^85555G&㪙"#L -GLA'McC852'dJ. ^02Mst>ޖ6%Q jqyuI0ztU#3EZ0xp#DuFƒrg^uyTMȺrf]#d:uZ,c!3=q#bHu !knw2wxc\|x=q@|%;AÇ>|DZʫ$??_wRUY;ADČ%Hyk&T6 ή{"o5aEvCN f*cNVY5C45Q{N>BZ+DDky!T8ں zZ Dwnl` E"JDnhH?QO?k[2C @$G{]" IDAT:EeoNA2iߧQshr<]h`LldDX0ofx3h?(ox<<{ ӵ +:?bzseP_jnjA WuiČs e`UUZ[ح?CfD<ռ=䖒<.PKXWH2']#ȿK&#{M>& =wģvb]&'3L +[6o"d49̺1B׮ɗH!ŴfޑviP2'L]8j#cT!hG1Bќ]A*qRsֻ#J֠\Pu>8i0X|U>شP1@,׎Tf8츬V&">|Ç{aþ#^c_>vΗ)6Uug^QR= ""t~u [8ED"uDXbF7.sOw%=T•ih$Bz21DdAm+vt"b)@ʲ%Av+.D4=SGfHz0NDe6cgwT2HHmA VɹcL 4 hFp?9}!zb(7IҔ5kPMNrt/f50A^hS`0Y!~,2s>p%1\? Ӌ^=2 \b#ØILa.h1!CJu# +ZBDD:;;1o4-ԁzus@"9fh*]2/7y5Zl9OyJ&\ca`]_|u|Ç/ |2!"⺄}zu( & ^"΋f)FDju# .p*. [M$Yqc4YV ,-\S)a/4>A2-cڮFctq=)]tf}#1FY^FiI&1ܡ4nq~jQQ3sϋ_o'M=lwyO'39zB=H&ʞ~-ԟ.5ع"ŬCZo]"Y䙭qҍ~5=  \b ux^ЈU).5'1Y[ﻨX!Z(+aZ$9g 7:Ks5=l]JjCjzY3.-CAZf.5A 2A c֭"cp~dxvd\fȍ.]O"" >|/ Sg1x#NMtߩ9~ 14L jPʐJ4cGs䴥\/l}$2l/4ezjGs*)Auw92 p k1 N8.X}?HnDv/d-m(&#ՒuXb8&zUl=*rM5K-6Uj{|84xm}9_ȇ>|pq~߸uSg"t3 2f!@.~C#!{ty1R&{⧣ dSL o LC[SDrW7jt+JKq ~lJ"l(kʩC3:H1^}KRݨ=6^\Y8MԘ9-SA nfch{Eev? ̻`*4Ov{♇z% ~Tuͳ?d聥t谝D:!w3 5 ;:)d7,:#@gƙЍEu`خEK1 LAf(шI@yʹB?af^]kb1b~u/&""EN^_XӵA& ܰgqݻ|NFi*Ƈ!Ir :*w%o߮akouo$źfs\9a e|[zm+ %QE}^bLuo!ո1C2G ?RCс3 L]p`84`c(|*y Mg>uWn\wUh^Tߧ%JZ\o>n{Sg,#d8϶# Oj\Q2>|qÇ>|㸍 20#fs5 t"F"pZƀH2GXGZ!%ԷcC,]BcD*y"dyj38H_20C@J{:q֏ p+|nvQuMrwFg7o`z0tbP#WLDt+W_IFcBsxX#~xi; "gBezt#bzQij&O"a0@pψx=dax `|eprHeJpQg`3}E0;57@3:@DKvN:t0/y`r?ַw껴tq٭C~uDVNڟd\QA狈H+/g8^ 2MV0M`eXիWHN{4oZPHcwcl?s_:c =YƓ\GGO$hOc1i2d,qɭKvdn%18 qP3ھ2_wyO3[+e0@]̯a! 3m}1j@7㹇yFsi>/qlww|;(/z8CMy0QOP/ۋ|qlg|Ç>|qD9 E";"Q1!\lu"mtU.hu〪M+)S݉W*`A"TÓw@As.] ؓ 4Qiwd\`5F~$/&R OpP||60R:|&6HCPF#ӭKVBq Fuc?w`s |nw\W$jX( qs]:99/Ϫ;ɬoM ,QO)^@ky9ڟ܎8@!4Ɠ=7zd7I8;fshG;t7틊g|qlg|Ç>|q6HZG\ZGTV:ĈuW\"sDUnOPpH'cls^"Szu#rJq +w5%5u1# .j8熡))Bي0z BhK%^6&$LĔfMՃ G˜~bx׮^gt"r~5ȯ,\y_tu^v⥔EL:iR~Xz0n+BK;vu/"Ԥ'Rq+bDû:=kKe2)DP:~uAJD?=[)2>]ɳЫiLf~D36f%{ZOt|r_,ϑya&eTts#CCf20:Gn,]us9hŒsSQQaF_6MyØyISyV5X58qXL l7^ vv VN}t6La|8bVy>|1?Oiι{QrHA"p%t}Xz6dd R+Ե_\[1;%e ɷBؽ9`P w{z]"԰O[p9k6Vg {^jcPgt!3]h:2Ep֭JEY l;o,SDxG)kτf{?DN*қWY0WDSwlԈDI!1#ghȠu'M>1 D.@{L$?qbExz795o\a0?5C C|ea h9 RXXhG盪25n]!G'KM 6ʕ+M\<ydNj\  UkŌq7'Ʉi?لu'J̸PsDDjF|qD:}BJ'=PJE 0. ȘmV݊,a]{:APj\X5jAX?Taw_HڝEd$]KOVA$C|*cѳBmESޤ_?e,pﲕ/9Y1 |Gnojo2gⵞ?ę]Fqm!"t6 瞮Ojn؟dvOOA]2!M.Kx;g-z%E]X"Ds.\VOa'?rk/J2K+̳sc^zCCC~j;3`ZSt,̼T瞡ja!F&EMTZ 2(|Ɍ  ga2yD$Wv ǍLK.ĴgD2 ˭83DDdϞ=""j*_)^ "=v=Fb]Qn<|>tȶnÚ_1^G1ϕHJUF֝cn|Avu+2"ߍfBJYaKbrݫzFpsfG5玧A*{CX{oVԶ#wKS[LF,X ȇmqg|ÇGM◿+.}ȃyw{C{޵wͷ&?ۿ{}w%ѱG7swSoJg{lyb(ꯃ?{{ltv7~kB[vɇ3&0DdRǙHu<'X {| +DײN"K+PڊJ[FVvtw]mT SuϱuX"6//7%b_mʹY0:D,y>a{F9U>!d1L+ۓ(0ĺ#-}/"-,e1ZDT7"^wWBƎyFmw lOh'Q.wdNX߉5rYk hGK2.CƺIL~螵Y5Dc8_y/!ӎ]#dJ&ceJ5| d>DWb]Ni<[DD;BvOtZ#24dN mnn?MެXœs(a)"͛gd>l#3ׁR㩧~?s=2a.~!>LQa뀑A_tdPCFmjRxpe-<҉zuQ'?[:yڞaW6ܭEkkRCHZ;;'1~p`3 Q͓8֏IE`Y4k~/?nwP;˼ݩ:E 'E NM_'KheKȍߺNnVy{M׻{?oN/unE.q߻.Go,^rJ}w%M|DZȇ>|XO@ǻN_!;UVtw.;w6(93g$"?C)Ҿl5`6ٻh~!SA3AԑYo&C A[WKHlc6%"CO) Uӭ umzb}}04 sV Y] &]_7WmGϿDjQΜ-8_^2Ԫ$._B9,Dz_Ti&L(]7 q&%xLrC **L-=p9ijRtN2Ǔ j\w4;dxX̍}~}'}vi|{1sˈ5*m޼YDD?rcIꬳy܌i!ѼLq}NS\ j?ŇuıΎ@bF8:8Xw?wkӇ<ȇ>|qI?[{?d{ kx"C_z dcO6?,Zu}I'UBZ[o1"2Hp,{aF`ZX4jHp נ ڀI$Q'"C+gȰR;!"dRY5W>\'ps괰Qsp' IDAT2DB΅ h~L\*▫5Oǥ*[mﯰ=WVį%AW'"ϴgv&3%.y1Q+R;~p~ؿ #è CZ+Z]NmϚuQ c]:>GɌa7lN|X_q<5GdLW`8ߨ"C 4|ba}Of0Zm#4bSe2otޮ۫[ u.{ʌѤ3$\RqOf<ƕW|F+篒*ۿ{|CE~~?nU>ы`o͞-`\ygW\)]]RYQ!_|_\qy' Ysх266&U-UU_e ^K\v_ȭ}Gl&ӧOV*1}pl\,;>.jU>yb]u"TDT @fH6mxY 4|M'[&pq&$2W^"Ty=ӈyCr{m} nu'_gkZ "t#A&Ȧ;D\]W#"9d5Xs&#=n6釩4`<Ш8Z,yĤN7}!c"dļ /p G!bJ1axXz?ihsi0 .3}VQ"nmևjw8Ndl5 Q!#@;~tHd~Ȉ>Y1\d^j~ZP厓ۯiOYWn١.]_\[_\0ZdsL>9j}8/Zߣ.to \nEKpNy݁:rt`gg220}0?euc^rUixC #q`5@WGg\|G">|Ç>|1a\0tA)?4`>'Bm#rp5;%YTDC6%"LffP%*"st]˹Q!c҃[l݌~6+2G$"`5u=vo&;}m׃Jꮻ^&8ݺ*3Ȗnvt08򘞧mdٴioWCC&cy}20Si$e|~ 3/ey2>s<:`|D_J*`6p>R0KWY|/F MtIyNf 98V2N:/ul؇ 6`兖9>\ z|> = #KsgZ۷àQV6ºnpKCԈe}` fZ[H_|㍈ #"91EbVp^pRэ@+4!!n4H_*i'bpp .= LLlH JxýiZm +*yz=Ɍ Z7H$X1SsPYlDϭm߫W^= 0&+۸.8!=x?bOpG .G J (= ]d%kbL~U"j:NǙXt MzP7yR:H2o5 CdFSJ9jXpuS-nr. S%25ɏ:uP\5~SN1}lݺuyyq*): ⧞z2KllǂjLm""`2C 2a<[Xg" Pt9o'Ϭ@EXdXdWcw&-ӳuݺPzqcü7a͌A7!Ӯ}]Wm܁ ̷t>'5{hLP%<u.lgwuDSkߏjzys #I?Ç5|Ç6&0Dn}">DyiH;뫸!)&c^EYL)HFȪ7M "eID hQ#QPXf>^[d^o|Z[o{ۥߠVuksfP5*B8J,u4Dvٿbܠ"{ík.4@.m۶Di;٦ӽkvDo^[2-0TbX,y7Kw6"#v֟a{(P2^Y @io=$2uǟ?\A(B%bK}5ϓ8Wt\BEW#vͬP yl|qg|Ç>|q(Z3"cT6CH%y'SQ .@zPD;mI)u}KA>5i̳Apen14 / 8Ld>t<82R֭3jʝ?evyD_M u翦{nP u:_wn߇޹%aHj$Ļ Oˮioy^' ML(m]`dNw`>3zjwv6Pc Ƥucqs;|qg|Ç>|qhc;O32C9D?%"Kdݩ(,S(O~ERɵ>Eس:(49J[f+]@ysYoA24D00DGۭȾ1z~˖Y$\Z ~~a;?S""pIH1CW3AѡǷ7 1SGxH~Pu` /|]^j8u443D;o5M j!uh(A=BҕwQڊ@ӄ㙿fb9@h,b"MI=4Cė i)]5y5Udސdw7G.,\6Ts<]'&suy鼆 ˨)_S10ݻwz ׳>yFC3w\پ}n^2>8-+t^kZ<2+yǺndv| #O)2;V -p+|%3zj2Ovݴvev5h]CX K^(fK XpщvanuPG "R٦~֗s,k;.i~z%=~nw,p=f}>Y>w):Ŵ;|h Ç>|㸍 0oFKBDnUP"}DH-nsh\q\O?'2OOH䐹[_ *z ]zX'+6v ]zS碶P0KPf%wCRۀWA7,"߮#;ωO9 N2BͫB]+B=ZG,Zڠ3QfHƵ}T~ ްgB؀54 2. ރ2i9i}5Ot64 ݘԢ-`%ɇ|Y7pB"j+z+ͳ~ݶ[m\& $dDH5W-?Uݤ]T z>n^SC43ˠevy~/u8 í`?>1JEEHkY*qYN<f=i{k#F0@\umȜ< }ӶLPfmd@ĺyVDLUXY̐tkd5;V ;q2y*~Βts6Dz%qKͣchf,y͇>D>|ÇR^hwGGĬ*9tms7e"Q ŊLj 22Kͽ|43^~aQLEzEDd~"XDĿ "DBW!iJ[#LtwgcD"dn\^>둜s9.D&MXG">PS$hmgQp@\z?MHfѸ_gNB~(rK4&*OS՚T:&ZdfևYwHL!L-"߳kAmF0>ӽ/JB#A)PJVHʘ.#dCuS1.Sj*1$.#?d\76W˔cudL|u6lؠ`p[7 !kL-1;N80I$~$sAv5jڱ.цCNGW:כyl];Y+bsu9 +e'3Ta\?#Rb;f Cy{N`C`9üO;7)\:l|8Ȝ6-WUy~ |1pZ s8@[3Tn]> PDO3@4q{tPP<NjȤfF,- EȎqOOIZ [a[7(pVqԵQenzmHa;\8ĝp"D] ?'bj"9$"mWr9&1g9?UsDDn"6 $Ji =Xi:M܏ROd L?p-uT![ϺQdTr u>8/"b]P 'CUBRh~,'WD%v½kYzp^hﰥ81!Xyf?8M"✟n]";e۶m"cZ<%DFy'T\ 2<O|_<>uoS~-Eُ?^SdWؼ$Ֆ.MMM:$ 48*<: H.d3i&r yߎuBt -#; 4R ӕ;pSRy,<_faC 'ډzVWp> j\?2>,'¨LJy;@ _?\-&E"5տJ0򵿽V6m~Lݫ%w~`޵#wKS[LF,X i.'pBpQYz%VTC# ʫ;-]]]RQQ!/%9nrpVytur]wK2y䖛n^蔛}tEʽkw+Tݎ|ODgܱnimmӧ˙-7 C!3D>|Çc6M&4bnoz #*7tKp>))=#w<#oF'2y{ϒ۞Ύ6oɃ̟7Ot_f/%?c5Sߑݻ=w!=r;[o_㦏^-ED~O^x~|OOW+/<[g5_ޯesǝr?|S:[epF\W}T;Ds#7K掏d,"PC^8Cu"yeQK\#ra ~5?on~BDDhREzAD,tWyZ9}AղTݣz?1'-;i#dsA77y~)'2HEԉ8O O̷V(1{_#2DR`_:ph{FE+S@MP<;4u>36@$vЭ$29غ?e{xF8ɴL]¦/4yj8w Cqq7?H0OUs]Pn.SJ3u\{|Mm;F,]r]y̔{=;O'-t M5oHWFG| j*ݻ 9M]̰pV6;1]f(/AIGJl7e b1񒈈uY"cxgn,+__wu""r mH#>?y=`ffoVɮWmƳϕXO]I;_w=(;vHOj{G;ǚ^zkc蝚_\Lt6wKuffVgGRR?cĸve6,yߧwvihd 5ѨTB!y[B7dɲ% C灑{r #s(' MuM`8zdQb}D=qp%'gg蘆p>0o{8:>9+|N&p̮*8o`Cя~ *yWP͛a&_G=m/R)( e E(gǞ>o?̦NBP%G-bDQޱ_K=(1(Ub(… ;'UXOcg2*yySڗx(}@Cku'B6(h U [ǨJ8N"ȎCKsP D}[BFPIqO? J/ypUhU؟4Z)*^Wv vLd{ aY7^\^Šb;mKOk.*;3n~ۭnaW6wb_7+/}J33Iw_ۧ?u>ۙǨs|7[oo{8p8c_ffg;uq{_05ƎqcÑ^UA}՞}yi`gf$G?=*ۮQWlqu'HslQ`9\O|H2yGYj>_!07}*Z ~sd*VK쉳%Jֵ {ij饨[ {P.JJy]^LiBy˚3#2c>`hݘ_&FPj*C ]Lvy|ާ@1^U! R\"-5#c ¼qi"wc`1t)g[Շ-kq`>`83b|oN>"(+u|\&21NT`?GEehcd_.aC0+yq;@8  ,>SG=2G(d/s }{ ] eCFYB!J۳>5*r#Gl02+6-DAėI}ԗJCυ2 *Xgy >go: |ٚ>xHTPJJSG|lXRT~I 5ai׭(=y><Ԏ??:yz%mcº\&#?r6  yĺ@Q*4?*p ϗQ!30ʛUkMɺ9ԔS. U|/]zw_;Mv~wяj&53.]~٥vܱ[oeSNC'?~/O]7g xs]{Wc9so1.:3N?n7k_jzfͲkaooGs8ñbm}6 [>_G8~#ƌ-}m;w?nCG]lEIO٭nÎcccz~/_hV>ߕ.Javg/睻ߌQg6vٸzӷ`Gw59ܮ+vW he< 4Sᵜ"K,F^bp6zPԡO6kYTNbeΉDr})ZN =F=;&棠<~Ҥyy(`Z?y^? F jllLMht*glF~06JpߢE2Bt(쪶>mߚ_mIhn(䳪[QO'S$l;~P>zŐ {W_ vWNHS*~_駟6r5K6ԇ'O#ji_;DĎ=cݫDc:{QrS;eA}t~=Ӓ4Kq D},EDI/( RT5aFy([zEAU=>Ӽ8ʾNT86#+}oyX*+Qrz'5v6 cxzA??q+g=谣;f8\3#ǟ2 p85lۺu#sWk}>F{>dZ\۱tqJ|!8x6zixyUE f*nLYs[`@`KPM`6)jR%2!AҼDVżD %+_! ޵i#"2r,`Шϙnh{|,rWafrfޗI×z, oPoU$S p})WZp1Jэ%=gnb'7Ee yQɛoW}zֶG_쨡SM>4oQbW><"\_w";o;.sɒ%ɼ52ԗTQVTp\P*)4ȰTq~^՗uѼc{nR`4 BH1O'A7}5K+=o]|Roаm,pbKA)Mtr#%&\Wϟbx]ۯCkk^xngꖤJՊ4rYdBOMjp`?yvCuRKQD ͺ=uюtzSq渾Iy?{%kzE7]?6;ρu~x]6a'΁mAp8ñ`_Cg/ȃ#:3ݱ.J L28ydUf%2Ǡ);0]E9MȄ#Pn6P|KbT)lfAihw=1 %Uw̡ձI7*GTkaW_1|L`U%fp>K,™u䒂3|HR LY}Vh?={313Bhyzzm|U12FR "yR`^g,yV5% z" %yr( T6. 㹢-Ã#c]xťq|a+>jsm[ G(3㳣.3gNvWUBQ^Wþ4S&j~%Ka(ܧTG}4*C:4  ~ϭ_N^_zۋż6(=r>2"zs,ΚBҶDbeU#'q[&WcU]lI܏[}3Z[ :а Ϗ=N8̊#z]}w]&PϕDž ~7'7|^wHJ=3ZwHd\_:imQ)7 7FF>Dp8cE;hOݨ~~q$XnXg#3x&& ,e>Ѻ֮L|qf:/)[C/#O}x=xL7$y)xdAȈx!y/!0ƅha9Eit9׼C|23lذ{y x#hD k!>3GŦgE&|φGe8]0m1UrHBdfGhSQ® ڼ90ͯVꢏҖͩ2z Aښt&~b:|16D;[/5I?Qe}M"JQ4 ~9= ʧڍC1@+b͚5]'3S0c{ڏd\Qܴt2G!QqQL w?ܬ]o'AqcVJLo >Go2Lڏ)a=zUU9"[:}r->Wx._';CܚvE] ñ"p8ñ"TA{X '`fe#3ŘɾiͳqV52ۤ/SfΠEbMuB/҆ L$\&Ç'7Mm G9F˃i#hE+$A}/˫W>V kd&>eyf_ku@R9眓|?rd`NQhF[SN{p=Ф(oƙra|**=} G2+F}CbT|YŘG%mSnCD?dޏn v]W%Z"_h u3;}16u u0^kO YgG"ځnPP.\hfeEC"%%򈦆BwUĴ~!g?73ĉI|uR%vq*B yT_Q#D;/m`gDc7Em`#tt=THRk ڹtq+92uk[G;]a~Ĭ}-UtQʧy/I9dzPI\LjC%6~ ahBX?={uU(83/- 9CKL q]m~jAz!Sŧ.y CS(2 ʽ{ӟK¸>!ss3(.D,j1/:n((C(=@1(ߣԲ6C6^GMTbTDB l*t8/( 2/͈VŊ9/mS&-W~~B3YMX?뾘XqߏBvԘ48MaF_k/ (9"N:y^#%Ő| 0{"YdZU8X}b>1L*)QP|NQM̀%zT&D{ {G^ rG_}͛7SO52cwW'3>`ho ~I9[F}#`/c3CczGC>qX0Y͕3m=>`fO9e .HP,`g܇¾}bҡ8O/ UX@߾?̬"K4<#HƁ}+Q\}cgU :\'K{QxQȞ{.{"+[7yF7UtmT,o /o*7Dc=및~ʂBQW5(0qb`m6OؿRcޢӎzoJ0 D\QϩqPuJIѷ6bo@CSekDUZ>DN jnؒ/%.\8G׌k9!"4<.'iskgkTȫ+"o+>vm۶ف^Wݫ\buk_5a -s=bÆ [nR^QFˆ yo龇~ľ}-`S._&;{[={7lРAvIՕszi>Mf/ 8`>qх;&m`J%etvMAv˿}{C/}1Fanׅ}?| o~FX嶪eY;F O?uN?;vf \!r8ñע[nv@_u ѭ[_k.z>x삏_l ޟ٫^, ~IkkZ?+;7R淓[o~x$kZvIr_w{%cOkt1@NuwNhuGi'Pg|JDNT-y_yZc+eGp%3 IDATTӦM3Bb+vI'YYaa|QTD}4?~T9B!<3糣IODS3?|~fVu[r]qL׵z4SS}œ7QX\Ϻb?EPXKTYEE[CÆ}~zc^6ks&'Z)'PPg(^뢒uAm2ӥZ:Y(᭘<_؟y.;yߞzd|5J%!u(3w Xn*D3n;D;l>9([jxއھoѣJZ86wVX|85My>v':Tj[w7މ9yvags]5gQwMt=o|MAv?k7'7r=lc#nѿn== ;|gƎtF ܆/l6c% l{+ (sp8ZT=Iѵbhŭ[lm;d8{y쭷*{{SfO9j[93w2lٯ̟oO:1_٥k̬9;wm؉R59;U ;+6jfTff}zNe{"Ar3J2SrL*CRԪGTĿ{-9~}tz8F_%1\ϞbPv߷sP0ȘF%#7ޚ!WmysH?qD3+$p=oDSc=0`,X|`i?>rWN(?k~bs`g*:)sU6Ǎvj`p}+hmWifS$K 1TI9 V>GIB|~qP$&!?z( (@DwCw5(Cj¸YW>m 벤W~za KLkþ^߷2Ұ7vX͚?+רE%g[zZcPRgsؾ`#>WևFc䇑*C=}u]ASQabw۷o/Ͷ>wrw᭷~TKs0;d?!p8ñ/!>q=kƌeO?)UUUn}|…3ڦ=5=#FSӟI>{gl#v3pNpl_AWl+U;ޫ hG|@2Yv|RG=-׳KR!@t`voݺ8T&#: 5S8mPa a1?K~elU\SPgDfw/Q<{P_(U~4:Y$~P>&J~m-(#L[5aq1/S,Q*Շ/(ҬJ֧`4*%UI(j|M]cXoyM(c>h&uD"ũ/a.c^bӄUږGc*¾}}s*(2QLo>F*khw֣G{_{y~ 6ؽ?]qev_OƎc̱k![f7~`5jf5;~O۝*ҵ۝׎?8k~n6eiweƎsؗpݵ2ro]Ѯ`Wxp8comlmu;{wۺJW2SOh?n>/ GUWZPrkYb ¾xuyM߶k>$ۺe 1ܮ 슫9x9g[[[ѾX]]} +}7mڴ.*{f4#tٕ.J{fk8篶{eQ0Jͮю`iׂ9S%hJz'J2GN U3vk0eNJw qP|>U4藶0.00Caax>sϙYg<HE=! QZ={?`Eu>_A %ѯrQ jh=PUt37s ԩS{awd!v `wWE|WOhLUruňzuR>3Jؕ:b^Q4$w}I"x~I(s5*Dm#(BO.x%*zLj+OHD|tb|P-OmI?uV/ݿY?W<"}>y2^o;eά.o"(sCp8cDMm?[Ŷn?2}|oXΙ3L0 J2\O=@/(9ƝrP눖>yV'|b Ha<7a8ܿM}Aq݅~5 &%iȔ)=:Ϫ,s>E|81حRE fjwi'CYz7ુ?fzG|( 'y;J4?cc>YD/4Da@aaE(o%9oua!=úp -1*ݒZwROH\\t}5#G r8~l:|v=!^g1SF\"1FeHa"kC4-Qe5%幁Գ2;0a33&>#R (,' J?1N\ўq7r2CUiCƙx4.o{/Y9 1FP(Cxک_xitoF'{ `U!,-ya=(jP5\oPUTu+{eNRר8Ur2@ycTgǍ?|>=vSx>/ujbԺ{Bm Dsg~WT T(gmA9zDǢ/(T5nK }dPji, `ჩ8ّog9Ǟ!r8p8-70z,R&_LPp0r.P?%y^ed2ƪ(542L)C (3L95QET_ Q~'탡ԫ Ieh/رcWqhm0\2ivF=SgXZ`q]UD72qUGD}c]gڴifVVP:.Po._ E~(|Z7bxؑ zQTQlryA4+jQ/ԇQMeI:ݼ)qUa AAA޽C}E'-)On ϫ~7hp1/ښM{-Q-_yb4f`MC-Űx*xj4K]7@+Oorppp8phqfIFhs0Y0[}`9ӌBGF9h |Or^SU9ּJ@ DgL2M7ѽ4:)A<S?Ы⡾yELb'sΗ"xRHn4_F;|BD=CՎ**:zcWC]]]2,0jgd^h0i|/B}h%… ;eWV}ո}#Fף_(PB3p`yyZ;父"Dځ;YχQ6r*RE(C1J\cU-^6Оd^|lُdГ}yBABd>5*R/鿶 Wp8~l@#^>׳0H00S0z͑Ƀт F\7$wo$!^}* ߜBA1ګ*fZ.|ڣ>NbQ2*=#GLWr^}EObϪH)C#J*eC!c:QF}Oqaվcp8co@aSay`+^'! 3>|Q`G723 3yvxمqN-g Y.&L?8묳J3~I'%r ,L2^efFLO|uv}"I9QCDT+mZџFO®`Ps+vF?tUPJPP**hJ}Ԯa5NgԣTq#ynLXW*sQV^w'&3Wn@n>g!U>}*X2ڬ}H YzV4- j 5eU[PbPmЮB7 9.CWla$-Qn$\x߷%;oBk/S(=i4F}sS{4z|zQIwwz͚-}p?Ļu鿺ATp8_du>T м=)|09_enaԗ'^@k%S4O&ؠh)c-+#H^^A=0z)ӯ|iAA"Ѿ70h:CeU)#<' zRfgGY}A:N933{;^юQh֯a|^է~OS@U}xT MiHU <'Ocu78ڂojקO__!\۴][ZVb4U1z\mߟÝ3Ehhpܨ옅׆Po G0E*iIalFw1>%I((q g_'|]?ķmfW{؛+[n{m믶S);_`ݻwO;nο쯩57ڴ[[[2$JAohwkYVug|{oؠA?1Agcտnoٝ6lrwW߽^_5~p]6d{׽c p8ݺu2{Ք;o7m3ӬA_r.>sy/+s_aC?'|~Cz{&YӒvwN9]d/Wb<v/Eq]{W|A8)Dz&\KR̓(4i(bu^.E^\T1L2[(C(T_;M0x͆a|"H8/_̻QqR_O_~UӨiO?eʱU(NK}(SGD^giJ) $`\sq`V\iffw\9ػ*1S. OU W\W>S)\O;QvJ`sZ?9Ňyf}^Wf^Wh;s]i9_gA}Nh>"^x!^Ee_z{|eqAY6(86bek&*a뚃=7bBP+ZYLm E@:tqIQ JPmUulgP^RיvR>{9J7yu 7~^]Wx9pڭ[>?Ɇ~xٸ-})o: IO_>]w5nlQ9z۷eDo:V߽߬1^yev-ߵ[oNȱG/{;p8ނہݻ'aw<_,um߶Oh6m*GXɮWmƳϕ(|{ޓ3Tȳ^OH t>AWNJ?|vc^?w8v"IYnBU4JpG?Q3+30xeK}Dlgay4jL20e01`a5 u.*p%)c?iRsqqPfGU `f(Vs|QOδðkT7yʐPJ 3(>(|LKѣG'v1޼k?TDŮQP3싀Q>@a:GsQ4>~è:^?Q֡;Ԏt_PeaG1+ʔO\c}Ř Nt~#ܬcC a4S'j Q$do 훟 b6-|^QA ӆ-2u IDAT[| m8.mZ|闌#B"<'WFSOyogUE!u}nbD=wv*1tяj&5_+.̮+Iw1cl9vu7?(c p8۷m۶-[Jj?ϟ[vE'>~Q|>{ݥۡCg]}>>V="y&_\4)@% v>Izfh/+|0`>) C}c4:Nzr+gsQ堸(S͔&躀9U)SP{ ̟*Æ=d`WQA.*~wWpOw:~/*4OQ>Z*/_G>~'sn]r2wn8>Ua\4y@(TXʘ˵o;:ڇ=nh 1ʭ!ա=VDZY1(Qm!8^ig#{Q晼 (84$\Li:``ڔ \f{aP Op2{ѰT1Z=>2|L< R?777'QƼFMT&T}>r(WyX\O9;1ٲe:17d/Rj#x5sC[u >ԧu[Ok>G r8~;|w\&v3L0!Uxe`)OϚ= cL~ /aL5zPEHi=6PQ+ESL+cpG.z2(A0єY]9%ZDGt>|h` IjT%ƔyŃvE.8x|~򓟘y3̇Fu3{bԎ4 /Eݨo\n_ ]uP@{\5Y~(ػصUt]-J_c/̏*G؍ŋ||r by[щ4t"V:V8i}(Na|Q=ԡ 7lMʭʖ*C[ R;!ROpip"p8ñߢBędezY\%KVz`:e$̡HPiGI"JL%|(9[/^O0)A$ 'W:>+;T 6D( wP8̪潡G:Wɸ2>5vS(y<'1O|82?ND}bcOQWƙ~UzUivw>˼|jt4^Q4Z*>4iOkQ zz⍒@{v:|H9cL)P[B!Qdz\,ۨP?>Mָ'uUUvhYKu2co(E+QCg}G}cGp8{:\!r8p8-)Dx׿6 2zF]D jfSYYɁiVePjSr;(e?T{/ei}2X9_4v\0.gT 78w\lҥ>I(pdlgsJh'uڃaW3 (C"F4fhE=Pڙ滁f0NgM}n4Z$3*3D3vJ>FU:+>ʖFyٗ*O2?g^?g5Oĉv{DѢm؎h~4؛'qvꚰ ʍ*(C(IQB[PXyHuR JU})}Ψ;;5*˪F \R p8oN!3+ӭ "Xi&v2ky,NCz /1֚'rtPLØQW9Ii9;RçLFR*ԷB{ʢTBrѻh*n\J``^5\BFSĮdG|$XnҀѣyŷjt+o@;#{fVVTqEW]}Kxi@OtYYrux~}G1\O WU sڿʨ/\r&YP$OWeI}Ӓ* 'U1OQmH_CEaZsdnU?֕γ*(71diy@L{Qߺ2#?yCLNDoƗV_&SEX~IQpf}cZ*F\(M/QuK^1䢃᫄}[}t^r:'Q v瀮UTuH7S|z 㰶5F"Ux/hUC_IDUA*`_hp:r|'UH]NMEp8tBp8p8[dRf̘afeFs12Ιpi4 *ΐ(g5* ;S &T#Ur F1הS';HU&`5jR(ß ըcQ(Sp?vQ`J5 R_Ɠk"Ѷ @vP \ UHsET),cG|YT)f)2|F#s4  + N.ʡ?GzOJ%[SzV>xn潜W*u"Pyv}on7NMbk&Q投A! vS NYVkQQ*[yǧGtcǪtsB[[\OQ}`Wԃ]j{:p8{\!r8p8- ̏FӼꫡgaa```rϛ73єJE"ZPhΔ'g,*qP,U4zB^yz*[onQ8rL"QV@)lj -gu'e>5WL}W0k*]'܇rCy(r4 bWiTK U:PrCn?7csy4 %TD}/UhN}LRF^KǨr<1C'eu>@|zg3vPw=֖sᾚ,GՇYYغ'a7*Seᾗb^Q(EDC‡ rsa߸^$ҧ̸st{U^7Xg|İ:E t8= 9p8x1H +# H(eK{30VLjt"ʅW%Ҝ4?ɓͬ0N3kogѯ`Q(eU2rJ2z}0;=6ʓ*ʜl*(*T|ΫfT׼FMI%/AGFl?q])/T_UϚ) 1BSO=5OEN!`|Lq!*"|w4:r?^O;`Pb?qFI@׼6ˡ2P@\Y|'vr^}rvrX +! ϫړ/@8R*ң>\\ʧRP 8̀ S=4@XI=vV n $]6MUYؑ<򈙕2/.g/ k=ѓZ^WVS p8oN!AB2H<4 H/ճ\Qה\UƎkff>$B8UCi>/9FW<UPZ *[.)U|'"=IOzlREMy \pӨz؝S'`NE<693'FW r%P{'ͬ}Pv`~`b]"xkަFs.PW.?[s_yh7 aʍjBVρ>"3-)eC ;WR= U*;^'l Z/M}CdclȰ+ ^jy srɸ`9p?ʐ>u|mñ"p8ñߢ}L2w0Eo&J3ky0ǫYdIS_lyVfvfVfvi 42DOQfX m㙫_=XhΘn WUTy|Lvw~i9U_Ut>e˖.W'/v c?k֬+_3Sq?mb1~/DΔ!cY٧TT`v.Y&LIn}0 ~0oz ڻsΜ9֣㍲Mbe^v4o v:wSffֶ.*518DG}JQ梢qc[\x1_د0n5+kC󟋲Qm27_>J"v@{XñAp8طпn_Aؓ Rea `PPt`ԗh3ͯK9>P>3ӹ:´¤k> q"UTY<0t9f1ƁO\Zq?ytԧgŹN5x+⁢ϊ[g( :7[&OP#imǍ!M5'VpUaDTeWdSyN+:X4=FOA>Dp8cEȜ20F(ni%$-e֔ SE{5@YzO׫Ds\^Xe7}>|p.O*'YYS&P@UF*B WRhUa>j2Th9I|{EBɥO` Rq\>+SO_ yU5Өi嗃EP0r.AdX/\P*ghRS_)S$|3I2A1[ =רFv{vübLKڪ֠hbPZ*E.֎/vaWpmBkz/ӲձަxEhRy_{wI|=ֻ yL}T9Ǟ Wp8~v h>P^[>רU0ʄ+J  PfUk#Q]el5L*\ϟ{93++ aUJ2ԯhW (bvϜ93ib9{R;>|2 hשE'Olfhsj73.^Ux(p Y}r^`g#Z3o0(o/b2( ꛨѨ[\rI2('|rC_3qT{ŞT˭GU&n+U7Tϰ/a'M}wX꭬nfee7<'+Th >Elp<(25U5+osW Ǚْz8jg]i*>>brr8;p8{\!r8p8-)DWpF3չ3F \mF1ӹDD 8q\=U(903f0Wy!䙀VryUk~UB`g5DKg_x!DQW_C{s>-l^.;FQ'it3/ z*wOGñ"p8ñߢS"<၁ҨUzF] Kv)=b ߟ`N  8EAW0⃅RN93;wڍ4| FSE-=[Q(ro`s,k UR]?9D}`iR%BǏ|#[k6H3`d>Ya:9|N1?<* Ӿ#/ʕ+;l yuL<1NԧUc>tec?>\-JK%)WǨ@yu<ڪ3 I"|Z,|X1 )׬:yO6F={vOG=c6zVEjhPNS!FˋC 5=;| G@m݇Fy}T>rx~tcO+Dp8cEևHi^*er5 ,B{a>e g9sYgӧ' &Pf|(W5U P`Gm IDAT(=0ˣ)|"0՜ݧ\ߜ˘wO{n2ݺu327`D*߈増p"FO=˯J(_kyfVfծ_˥]\>E؉ڿ3j` $a?j7O۫j˖-~v4fa'܏}NԾr:ݪSSN1vM'39 Hby^GՇv޸EgAUC EUQ)L0^1V9Z%E)({}dI!-&qPt؇xNs>> aԇ"sz4?ppp8phG/ga> * 1g5F fJ 3H;l: ]|/SJDx+c{QDa}0k0E~yQ0o<,sO;ԇG}'h'Sϫ*:(0^j':v}<8A}9e3ԫ"0\?{w`Cj?(CzTڐ 9'UTVF cʔ)?k>(ڭytuR vN\CycO|T)^m/C#^^Q?㢾K}s_N\| *"v`(s7Ю>s]rYee}Qz?=U 񛰯*]5)Kv5/_mqҁXw<_(O">gwm2ʔ p8oN!ك90}0NG)L20M0WMc 3(<0|YyըpHR\sSh/< 3#K40ULE~N0ߴ3r4!D;Ert4z*|c/M@UvOMc<~ yb:hd0 O?5k&{UrdX\ F./*ɌvD{zP2-G۫JGΧ =Q(;(rPO>gr {i5x_0z/BD;)fTK}t>̮JA_sI}SCyꓒkvwX+eb:UbNPXj_(bw&!.X|N=eWEqP#SXתf78nׅ|Cإ@@ua^4LmyPe\Jq?f޸OvMQUBbei7pۢ]mġ||PW($ֻ1+b:UUac]Yxh['M?K'ڥ{no۩DZw"p8ǟ~G 8n~{wK?)Dz^{fVf`,/_ 3"h44EJ^a)Gv\0G3QhFǃUavFP3sI!@ysKyjeJ5:LJH}h/ '\|nPo)?: ~0KP~*D곦? bF{gͬuCRF|rG}δ:^\Q4vC*{ADxPQsLV%.Qf 5T÷G (6P_#j).-bzެ~o 5 c~yh> 4'źg̻FK|asՈ{n빻v\!r8pmlٲ***7NֳͣgvAvk={ͣ^GZEEE6IcE;zS B,+CQwP 1:y#erFW20P\3|4`XUP_ cz&\(Ӯa4_~uZ*6u=SMہ8zh337o^.%CPeC_is]2j?u]b5Jʙs=/ʈ7Ԏ92i*\ S.`ޔ1֨R̿Fdt]O*\Tڰb?UP\4zroU/ֻ^l+ ݴR\|]W<UכSy%>X7ڒ5^RR%'݈C[BhgCpB_%P}zUVby2%wDUr}M':$ /$M0!r>vb?W]VVzYݨ-[t7~Wp8 b>kkkkKFWz۱BSGTĨ㤙s {F;`^,uNuU8P׿63'\G )Vc<`u>r}PWUxydVH@j^8Ϟ=;4SUWf_}TyA:oUlrQ>_'x>^{82]YǺVY/Vbq ILBNNB;iΐ+ii0} 3=4 O„Ix҄\ Vb;5bIK*]J*ɒך~J=}{To_޽?* ~&kBڕF".*)_W}y2l' 7~ N'UZ9**|\_4J_"B踇A}言鼥RwWNy8@{/"?l=!Tvv:z}uBܺi@N9$>D7\s>I窏L/W[wuv?F2P^8u:yF;|?p\cuX}<h{_ĖR)iTTTٗٗ۱zj=9NR "sz,x {055=y5ϟ7W***pyLOO*?_yjj%x?#KƏaX^B/7ߜe6,U5ZLkB}!Xo2`dNɌ$Igy?۷ګA_&~2+TBFPd2 `NaR(̱*[dݰ/qe{ȬOw )O Q}hQ:ESeOCsL19~rXe5>8b`7 3J8оhzQF\׃(}杇OW^r-0eX#̗L}LTqu88S%WQRE`)`fƇJQ~~0oOI$w@sb: %ͻ̊C,ˑT(|5~e\J*_v4Z%Q9j_GJYR?RD%H*@K+TK8P{}Ͼ܎K"Lbddd/p3JJ~c҃W<<<<<<<<<A"@*ug_۸LLLxtՁs7B3-q n2n4Ҋy7CHӈ yviGϟ?T*D" "2dPSBa$ȜF5:~89F dX>׼ aʓ#=[#sOVFhV.OyLJ>2T~TSgױ|׋g=K@ 2 0M^Shu~P <*aLP>^`9Uʪ*]S HLT0ht1վH rBœ|EG}N3Ǖ3<7oH۹esU3NB B>U @ŀh{?ͳ^ϊR+ NS ~-ɷ"k:_*QӟvQNq2uvd̍ kfSu3c6ծHhf/Y~^;ejtJ }4WyS}]Yw^G;vLXXd2axM\~5P*0B%>T(G"sâhOdp_5N]JER)cNs~A]q3_}tR|#O{ ST1!sqVXd0ҷ䥗^ <"cMŔ;OE `{w'0u3Z"AfJ)|QLL"|z"r|T'TW_%G>y#M_T·H}wWq}f_nϒ3eUxӢu qR!=Aq 뎮Txz,L-{2t9 <) 3Qm%WJGo=pe`F'HwEGƐ c{,*Idu<3}YW`?oAb}ɘ_~ͻD&T}ؿlO0=k.>2'U~JME!Lvq\ռK byYht"AQۭ`FR(j'~梀CuСswPF\}GEٳ'`WUM|chU @”1r?lީBQ)^?\*7aQGGJ"NhaA~ʪ* UâRK,)AGDX$J2o9˷ٸfҁ#*+TTI" Fub1ҥK-'Rӊǟڋ]uQޒލ=;whEWW*++ͯ/Dg-st3r=,,vݍidL^^RTv3D4OEYY***vZ 7^"C߄?f ^xΞ=vr6EXx1hz (!S|29ZS6 X:B]###٤|^"Xv3 zK,ʊ TWWctt8{,v~~H3WUgɠUPBh9wq %};/eJ7 'gyYi=OرK%,G}YԇK2)çQq%̳ݴ>L/Eo\}B¢FŊvèxǰ~Шrl턿1?'7vh&~O%.,_]ӧ &he7v*FwҤJۡ2z*$.'q|j}Ўn۶-`Z?[VReb('Dϕ慹V-Qi{w"Q3kKm{ zʅM'|?ټE;P剾B>Bl JX58&bFOk4*CjOULy 2WXgUt8EYķ8{,VZH$ ,Z?x!|p.Dܷ{7Ν(..Faa!pmrn3T^Z$,gQ91Q%>y1;;3ݻJSm/_lSNarr'i]"|$PYYpJ=Kߠ4?r]nԌ9uc{?l6ݮ|sddBi~!sQ Qѳ@&FE aV2Ww琱%sL&4,Y2g۷oCGۧѬBS_B|!oYrLqX']'Q!hah*4p|?N^WL3tUV_&*2TɸBS_ -W!*[O+Vm]w]?>ɥ"ʓ1n^yQ8^d:м: qO9k^4_E3$MRcT49:_ԧ+L)Tf&>㡾lO?ƅ1q _2tw*CTp(}諣%$uy,QK-v=Us?B+JDCIsu=GeN폟\Ԏ\ՇNׅ0{liq睘 /^/څ 1H ^09撰)G[mpx sy9>9H®]Boo/1<-z63Wg cC)d4gzf}j~v 2a(+SFƸ [G IDATb#df;4U*F(Y Q(&X0Q}lqGeD[PR3kt0$**aј~7oooP耼>?+?===9S!p|@Khy$AN}xX}(x,W1#U^ij@aש"tՇ5B}t#nN-7|U%CpFctM~g?Piq0ﻤ=!ϢîFsJ)}e%}b{6܇|y[}|]mz7y!V]”oާ2~*CZ>GYKGȤ1wTngf8w33Hnތ8z̅f9e@K+J07DdT(ieU1Peɀ*COWE!c%'szueVN墠2PBҡd9MNoѢEyW̑)dq>@2߇QG&ȑ#z(#Hfߓf>뭾ZM}333(_>ҥ '<Y*,h7U6 z*_|>)|CX>˥nm'}K|j9]oxܨEuaJ*;Kyԗ )}"X\ۣuʨ*{߿m~wfMwZW6؏cf6֣SVN*{ V|k a]XOW֯FS㱼dh~ف@;6Ƕ)I߽%~!sPO;/{(bwv(;߼Op?S$MR"}x K >sC =n4`hhEsmmDܜTܷ/7B@ڭՀEKz1Àú7DoΖq3*3Î=cpnsѳi 4_y%$܌tm-CC55!ݍM\`>lFK޴ ;:jjBCu5kku6Ad=6!ёUj'7:*)Jf3,220 2TJyBlz2`%)-/7F.2wT:>CDfJB}eبO }x?}>XC}C׉L"[2,ը~duv~c12̋Aڧt?L X2nVXF:2W}`w<09]o*H;9u9&YQ=| Fw2o.UP_/7߫OAK}N]rs>7LB;NFPi^,h7W^n֥Mvf~i{?:wʙ늫͇]T?✐fLIz:f|gw,p=o[|}Eo%֞8,ֻ@=fƬ~/mJ.*|/i^@})|r9_}pgTËE F6 f)9ɜMIB~3{QsF"8Ô6 MԹq3mmmv_$|$GGE*Da~>`mɝ 51c6!ё=6\+Rۀ~ކm4 op{&,ssKjjE!V܆lF}Sʫp)&H֢aZeh*A"|Dʢ80BftF'mmhض CGXj I @aQ^^V5@# 1wug҃6? zC0MKMC)b~2R]Ҥ ݌U S11ʣ4*.|SYrY2dީ=$Q(-W*1[l 7 OOEPeGP}5e οӺ X4j3QI}UaF_/GR-QljT"TIV SՇAoGM}j|*F|s<-JK*h.m-~\tk=xs6i>EgM)=h0!iS9D\!w]mw!Tab>b[ǂ"5xgg 3MIt;vټN;(xoTBWJ#>2JFP9|ר&"j lSW57k1mFQ^_8skkn]eQzO#j4vje96ٌ1z?h*}OvzTTU!>4f3S)4o*WznzŚѓ1N̥`'^"E\!nڛ5 PЀj!ݍ("@u58"W*8 Y_~ƺF'c]sNnDEUꛚ@OҩJ)."hhj 0aEs3"8}D}u.E[LKOԺ6Dd%vF_2TD & ,2d?pGwj]#t1xscy?O%tCKLI #Y2ߕc?zeE$ejâO---e{x2+wh7K'& },zs?13|7/<E}DUtܨ:e:>oݺu~QeШu,c^,2Ŵ*E/q١*G*oJr a#Ǔv6g:ȨO!ޯQ*u<'2o*aJ95 cT,O\wőqhpwqG`h "L ѥe|@ XFxv Lo/66bٺuD MM875D6*Hg2>zMN|mU i7U+˳GHf[pm ۋ>VWף EEH#//;2?Ĝ2ҵص9mX "liE) { Bu!?gfb"ǢbdQ\VKQti@1Jg2HX(@ϩSbU#F))AaQ3OM!=1R$NaŪUTTs>-_HIIV"287=##gf/e7C)s3bОwO>D/*/gU>d˃b=._z`;x ugl>^vk}Y2ψL*F2?eyxCB+.mݺOz}!z#!vs\|Ԟ}y`ԷM:?QPb;9\w|C`w+N&srXJ7n0 IO2۶m0h7~eԷCyU]T`4^8NT^R%_%#ꋨSU=BūmSenm>R!s0=oFg潟 >6|%o Y?7vXl:StoIpvmqT;.w}:e9 >'$o7a׸Y4 aܰnN~E NSs"ňTT4&ffD*+qAĺq>A.Y&D*+x-?vݸ˯U]MM!D4Z| 9zG\׆aT:`2@xFףBhlzk{UѥDGrUDԮ^9,렮\TRh&~V%Xp:뇮3O*ymrss=yh|"FqCR[Q\T9g+:jv߳u|IN*Iĉ|];&C\Tg¢j>3U\i-bINDCm@ yyF<Pg'ټHpiLMMéB)$8[k(,*BeٳH$0;;"74`q]*ѹo9_߂BbH$PPX%KPd ##PWWWϝV?YG0 v{, |is Nuw#fyGpM8r \s58cR)#51Lihl[gQЀsٳW^SЀAe7Cf>|9JY6l#xDT.) mA"3γ*k,Q"ìg4$äL2gML"zhS@0F{΀:-J,3Mzy7x=Y3!LBM6[.i!4FR#~vG}RRI+(ͮvqW^JML3~Wow/ kF^a@ RER~e}ޯ8 \C|Lˁz w@G&l#ǏW?'rj5 SNKx^:֋vs]~$>,6;ݙ15kB(gCw9Q~Tӳ)7ny0vYv;67F_3~֨s:qD·&LI"2`*C,>CS3 ܐgQJ'+P٭p=(ajGa^Ǽgl)穂qOڑ#G=݌h4d2ӧOcrr>I#oCQ~>"==Y˯%HONb;a_l}b}oa RY p #JajfT y*Wc``hFoo/8Z"U݉#G qƍθ lC1jGwKk6Ak@3#0ҷt=6ܠc\yAաk?*c1<ёTvIM bǎ ?}G ?cDz'1:2#P0H`zN\uUx##޽ 2 LNNb#7C4Nǔ#崏X@"ex2Ad4O^2|dNUq XZ2SXi2dP;cF.JB},TL(4r2e 3enj$P>G&̻f'KFKB0Z -!yFAgy8UC!4t>b;{HO)Dn_j6B7L]8\'XUC;}Lô IDATPED3n] Y{Lpw*E#QamqkQ_vn|ǭ є[le*Z7Qح^?T{VO_L\^NP9d9L)+_A'uh(^D"},Waaa?"sdp]AA~>%%os33H%0} ZXXA&#q``O'ֻm^!Ľ#@)6nڄeб!4aƷ<KdS+=˱}id2,^^veޏS@*#;dC&&wi$Eie%;rrHR8v݆}9vb7PgϢlճm6Xi&;: IZ[=Іtj6e41e852FE@_ bC s3֞c"UAux,}9 272Ī1 ljYO27(C9訏]v=sBQSrbn7;|{屟 9#:uخlvn*ʃKt,(LZ9k+aTsJ{FOy>wG(!^z}a pyKfqTb=Gti~/2󪰨"|j=|3ٟ''>_*5EU,SqҬp~S|*Ϟz. *5qJBY隗JY=J˃QwnmtIg7^SJ+M;M nك/6cByq{?XyV(XoyPM]u^?>_>Om]bXv,zqM@eG_;[n&2ۇbgvSԢ cccX^/ 6l6vt  RZ&T-Y[$򊋱+ x86;ӧOd{nŃe8*7qM7a޽8!\xq:Ζ&_.u(slD`*J/1ZϣgΜ8=V~M>:{ƞ=MMM())A"@WW8v n po4=q9sX#C`pBDGBC!8dT cD9˛Bg0 YtO_wo& /BII&9cSAmr /d@2jkXE *tܛnjdz7|3edٟdx 4yǰ|AF w>:ar,ƍYv< xS1܌9s-) K;|1CeRYUfw|cV6nk7U;tWNSC*e:WvMP*ҘN_V ]AQzRYBdGP} |4$?GU\Fa\Uo8u֏ϼ`Q| rȨoTb=w.pi?:oURSvjmA;e*Dh\f{UA*ht6b*SǎZ~CG,7O:/gy8~P܆!`m"` ݇m:|GŪ]mڀO]|ܺ666 cccnX H bڵ8{,^x~8|0bmۆ;kҊF\]p_G"ݻQ{7Ԯ^19F+C07DoCH@7fD&8O>0)m)1112`ñw6ݏG"#!TOW^y\bj|O331dȴ1wQ5>!$3GFu%d֮3gyw6|8\62Qxhvqq2|J5K>lL!_U8.O T*aۡ>Wu`Sa\_xq\*vZ-[O>v ^v߫P֭[E}|8>TFo:AXߪ'?l߾=Ч߫2ֿwuF`G,j^qj{$|5Y$а}ovTQl R{%uuyKE&: tKF3`Qկ'_{o4jnmcʩ`}8i7:ޜ\o]~K UZZ/u"6CSͨmh@ z~#ٍpGx塇u.”&| qD"<~ eW^y%m3 gPV3"8FQY^8aj@Pf<bMMXz5J0H,ΧF) pӦMڅ_<VZnR)iD",YpXx;V\T*tt|k|/~,ހ+,A$A:F*'P8)ܼku8;6?U98|!"JA-ֳ,{U&HL& {<*9Ơ]hۿp=>ócTQqAy,НT|Ȱ+r[svVЁ6^T^&zE=*q"e[P |~O/e,*|2= n;y>xGfKovJo¡NS^j֚@i)q&a>dNThf-|vGVK)[g>g_tؼ[[JZRq;ulJgj,i0JRby?{ځ*cs'o"4 S"ѷ¢ yWUUGTWߏ0EJf͚yMe]qSr1Sh'm]aڵ@id [׹|OP">>,EHS:=9!l]nvc9^y֏=AOfp~S S6N[9_7{h}Gwm](:q@^^.۶!֖S` ]qb{:qbTTT`ݺu) CEE(nӉ'ݐ]c0>>kr7B݇k02c[Qɠ w86FI̩C~ҊC޴ Wltt1Jhzat?`PGf8}4nP ב:T w>:qY4=0maJQͦM8с>[oŒիq7s$nstL8Z~fNldxθx^ϳMMMz2Xӳg1O MW\Jfic4Q#DL h_+6*79]~" _I;ĝy?)-7\w]q0h2SC~sL[ʐ"료wcN&ּ0*Yd4 A;&>2 ;Ƹy@9atXw,p?bQYӻДWsISFvgcZaS\iuZs޸).j"O丼՛"?ǁʖ+NjW RHP}Wzy!>_lU:8;v,pۯ/HJO;uSi'm7g:u*Yǃvp G18lr|~=~5tkFWsQ:YKFۋF]ޫ)KŁƨqT~ ~B}I#K}TC姨hUp8%h[ĝ8ZZhyd#y9hOz2!L䢷z\Hнn}2[:]P;M21Ɏtr[wBM5ed. WK 9Pfl ig}S>HKP7Do4 fZZ~ل ;:Mbp5 9.wFy&ebX4k]>WķmҚ >4d[~isVlz{, *d4k4<<>zf]}Ƃ WhYoJ mZk'6馏ƨc܊g"73D姸(OJW:f6夀髍Y#3Gs48>$ի?m;FG*C+tՓW_Udɬs+dFyT_Q!`0' =Qy1S%DP}sˡClsJ*ZT.(,v[D{W7,AEJ}yj'kZݰT~o'%?}eY9&`q]Ӂs=ȮW/nG} Q# L"B9|/*':c%)svngE_/*؜/Qxo`ONںCxօݮjiED\6+U\"n."939"npNk nwon ñjkMaZZ y, o)M m}!LMMavljs6ETI2Sn}j KlҲkڻQTTv'k~37Dd2 ($2{%"^m1q+2ŎQ(: g53ܼ~E͞θ;Uv{KgR0MdM/cB>cT_~>E[.pd:x(ӮM#̣C_ Rgևy(PZyWF 6i2_OFb\bv3|SfoǛ-[EW-/.)Tz_OK;>oX%N_9+{ V={' FPňL2}?%QECNh::J(0*E8ݴ_*jI ǥڳЩƴ}ꋣo*J?~㼦]Q=7%gL[^mϝqfܔ"iBׯέ{'<{L1)osbudc]:_**~mc@=nM-Ys}ǕGŝL8`!S-uorS{qڵXv- nS rW6G ҘKZ ;mv^p-{nxJGr MrOf==_:&? wǿ0==69qc䆸Nfv ̇h}lXs  ч?asM̞0)XLu,D?'b32E21Yn2lɿV'bOvX; f,vQ*]#f85%%U0 \13[B&r)+ j8&ӎOwbу KuwJFL)}5dT5_B$ &4 H^Gz7 #S$z &}GPf>%R܏9$P~C@{D{LlhS7ۮ?`f}Bl|ZY{Δ f)BG_?/;ꋠ2a~ x? |OsTy婢3S9|"߳<UF\[~ҼEmk4;U<7|s3Ke8,?=u3}M4j.T*w)):40oVry'BJ.*#}4jMxx~;|CaUcԘFg[m,2ح+yaz'jv_y~ՁwPsvKEsJͷ.k:oqLMMaddT* Azԝn "@ a8];0 r6Hiޥ|j%^M!JrK ^!WA*B*B"0Ov^]jG}6DM6q 㸻~?vK? #HdpqBJ3GB!x&9Q|w]'xf[A Pb8<;#A]^on1cq) -Ӈ3rXlL`s1g6I+Qz֘puQ %SH~yN/YR^$~2 H{e&h^G(cA(ޯyS,V%aVSfJP¹=_i>23sדe~CG~*YEZVm+O)=42*> AHP٠}*QlSj끁yM}RÇ}N",(}JN֏vKƚJ)C%xXڥ*?^x" igva{[;RIT4oYXrJھ}$8^_5 :eJ84N>lϫ(6E阳]7}>7ߍsFS"F]2{-kTU`QT q]2,S6^3y{NN47n^;]rx@4,za;m8=)ZH$FƮuxQX (Li%_}@voi0&$oiŖCx`I[]y-VOᡯ~ho_GiV\SyRKdK+zF@ ԟP,biΖV?ԎY.]nQE+=Ԏ{~(*C*͸MFkcYccȞv\,8?g.o;>j m7OZ&F,>eXi2Լј`1m`s@ym^bHQѡ2DX1llRN*V&O< N撌?y3dL*c DfV$dITr#MqT(gCDfE?d׉>D IDATFWUMkD:B9QE"#έ?S;ϚƭheƼXy7nhO* P!#~1_F;7*9 7Qi8LvP!!R_v)O:O85PؼQ_8F +WU~`M7QHoy]ڱT![`t=kw}Rxj^8pqQT?f/Rwl^= oqw&݉s=NXֲڭcBONߓ/Ή"+ߍSD;&?lj@q<ڡSU[ {P;[Z1SpMqܦc<pLizߡv~09U&v |?p~CCHK+^%C}/#1Vܕ;7Epϸ$s yK6D㘵UƬ_jQj2SLj 84FQ{gLnջ̗"ᔗ00}7}zNTf4m6}E*^(Ӊ7,|\6ay4o °Sʴk0YWIF2\2ün0Dž23 2E]ӳǑ$2T8~(1*W_nLsޫ^s m~OW5%frxb?&Hߔ(cvA&q e >䓁zzU~ma0*S{Q4?T@4Š>Dhr_Gf???QШrlED7RSe`a>ʥa[wKMqғ30o:^^PX򼥍y}Zގخ bt:*k F}t|S*u%E1gT{x(d9:Tiaywb6@ZǿhC1#-U p2RPLY46ܐnqs[ZZ˖wʕOe*] !l7*[@vc +rӟ5'FrE7 wt6}.,b>'`2pdTOEHh2dZ*S7||@'#y-ņ >TX.~!UdɬdoJ)T4"%~OhE< 8U󉠽/}KA%Up^hO/ogH H:FdtEzPI02P_)?W`E̎{H=TJʙFSO E+UU΄?<\u+}[?me8'?uQ чc4ʃG:LY|_>mOU~9; Nv #TX.%^Jfvvq>{ϴ_[*WSKs^spzi3^rtRkOe흛:*N7{ྪ3=%lْ6,[;q &f@ ]MCR*fS9Ṡ2:MwS48 !#l9l|-ٲ:}֣z{bg=駟&oݝ|(FD{;ϽvlO{_Ez_`k#@u>L7h^$ޓ4x`8wH>(9=(cGG`8wTI B8yW̙r(Lo͊~TxҨQ%Ca]n_B{G! 3Jyx.J$:UJ R9T=CzPuR竲TpgeUg\3(8oѿ}yW⋼ueWZCwLێmu=(BՒ*=sxmcd>:SOԞSG눽M?IK8cI2wd0#%=Qcǚ~33oU`ff'GE>>= fVa̪b?]y^`ԫX7cëL6:yF@XnsUξeKm]qlY0h UƉ60&ݙJ^avdԷ/++##seddddddddddutf(0y&28Ǟm'O^"\0ixwz%z pWz[p/тqш ]NA~ L~e& iՋ_FT^(r&6 #gfHWseE&zR.Pfߩ/Q`5 3 <)Sv<׿UG=U9H /їʢ8q%v z4Ɔ˼=#ИYixG!"W^M!!ƙqul6_`0 {"IEL$9ꣿH(e?zO5޼2E h> sZ3E)5:@cEСCI{svPOǿFny}N}eG(\m{v%̏~*AɋTyst=~5Nhs_X_?H /; _d5>]x=~n~|j? ̘;fb9De>="q#+D-)D0+o=h9W-=ڣ#L`/h4u{iܴџO69n3gQnPzT՝<|A@@Q}D6蓦9c [3+ ozvwˤ@Jê Xv< )|'0D :QQ.L4]aOgΝffv'(c(=*e,k2Ro=Ua ?{ٓ?)'ƍy{3o]mffM$vGka|+/xT .L*-xk8H (zAqQeJݠdPEQ6WQ4;ʈ*N((<_!PD!:d0nUiqUI1IX]nnWD[<ѕz-9:ºyeݠ~wsurƷ;b;xdW"oJ ,mnxWkFG^bk @u_H⻘O_&k2: F۟qN#+D-)D  ReTΜ[gƎvD((0t?l :"43'y썆SEh!Qƞhu=mU iOP6!ys)N3ePh+2`^)g\g湢@G@=BDRE T\(ex`([m;fzQz;uw{L\(N3ϩeh4Fu#wA|(OTwͫSx"  }_sWB4~Cz TYG_mNGH7(C:Ψ/m6lPeE#oCUy6?툂`Dͣ,CP:)Z{|jV|'=4J];jSxa=X76$Ggye ~?MQ5֥ +9ƇPzWךҫfD{x4% NwxГ\?++##sedddddddddd)awGXQ`L#E)0xY(`r5 ʌz, `a~/R33G3( 0+MxEHGٞZ^^Qf0#dvWǺCw0ܯQ*0D1ҙrJٽq=ќ8)=4or{:ht={$ߣC.XU0r2^#/PAFEߡ bʖWOYRP#+ec=}4:QШe(qƤ~ڃyi?o['xw/ _;sEfdhy,_]So1toqsU{{}]295 J_NybYɺG{yCr&'W/]cA 0P34/X!#?D@ס"#_?DE`SSkB"O;}0߽'Jmf Ml{(K]O%2ǃ"V̮q<jT2 gaXC`dˢ2oE;H^ *N0h{WJ:z!`ՓT[( '?ŸlR1&MT:O@J -XVv heO˯m@+G{\!<ޮ*=!eE!]n+/2uGȇ86H4U2ԋϼ`ffM/b+U(杮R>ɻ4u(##edddddddddd)Dkoz>_sl`3kD"L4ѺP`z{s&j|0i{cxmSO)QTql4gx&npgŎv~ k/7QzvnG_So_D~%?0,oRP0x`52+WLS2ڔ0 O=PP `UQཊe)Ah/eF}^ro 30U邮cRߟc*2Ğ|U~سw,K@QQ`ۏ~ҮگW*HBwTyT$kfVQ"Q`ã,?*ypZ/ޏ~{Q_5ځhnԧ,PR2W6_OY{1.|1[tY]ZT]+|}F9@=?xE󣏋͛}l[uަ#!2.r}[흷t=-n8 J {aGlB )I\ IDAT*Q|ꝁziq1ݹڙ/c3s"ԗnukg״ȕqa?JMK GtuO 2`XtPƇQaLƘD:̮z8wCp^{%z%n33F> ʃ)b=rPll{*6`bD3,zdG IzFkuX,vD?;:e( ڿxiCQREi:zܯ , ߟ멷zpE Oʏ*?yUBe^7<7v^(eMqeQ>*ko+#it(cOyc7{/XW_x ;^oy]#QY]zE9*GQVhtO=S3FC 9mzjTbk+m}o|ݽGx~ 2׺rtBqbB2NxfNL%̔Qf J*&0s0[wA^8Б+2>k+0Dzj$+;00ӀW`LQl<(IS"Ga!Dt1{N:;s>(L{5jOUd,8ꪫL>!&zu _> Fm3(1(Sbt֭I;3~waf]N ##߁(uCNq%GE}|9g+0xy~fft@{EAޚP\xOIy_|:tj?gk̎S2F=S!_Ѱ.څo۳9C~~G_=H#(AZ/JQߺw#ޮ˽߼O}E;GwZ(eQLU1bA!~>j|_8FMew(bDa8bK_cEnQَs Y!8oQYU(Cd>.UF`` 9s50af=6EQ f=Y#4!=8Bʣ};I"Q6Et' 0(B(F0E{ Oͬ8!p3_t`g̘affU' ;Q_pO`QP3MmOYųоٙ+7Jµ/}|ョgr|4 Uz4Qsɓu`|O~gUA*Gԇɪ'%cE U` E.4?J ?z',Jz_{Ү7yPV/Ν;XyǤ%2qޱ^|ޖxT֯I[~Q }|l,O`D]%jY矋h#X7n v.###EV22222222222[ SP:F^킱 CQ<>yZᅩ3™Nj/WΩZQ&Nc0t 1=erRGLϋ(N3"%]+"V'Q4 3J @[='Pf(WeL;ʂzEg};wnROT3Y>39AZ“~yk>]!rקmUi">~}DDӌrT{w(C)SxvmI!*QS}U DѨtx|\x4QSSSr^Rύ*.:.BIۗs5퍒+Rw$m2HeHuOE;)~ o[|Z?uOΫ?xQ QiPLl%FsuwJwPNeBa y~_쐠ƹθo~{_|7SENPvot-y&_0$_ӫkyhROLfddd QFFFFFFFFFFya Qi*E!o --I_3fZAsՃiSޢ~g`jܼ٣ɟz*N8H4KT}O^0 ]i7g3ֿLl:$L3L2&)Qe9Fa£˃Ҁ2Ѽ8FQ⽋]O!<= L14i? ;3$k^;|g*AcFx^hvrcQPPt* 㙕"xܧJ0G#Hi24!ɡn[qv]"8?`N;!H2?nQ#%Ekj|\wJ; \ucr,oP[i/{]w3U[Gm ՁT1;43#UP4:=``WWVFFY!8oQe&(//%hrϧ^RFfk<>}X6DԮLi^"ց4z^kmZ~gkػ>(h_LδTNg85Ptg5s`P!'z_<  Dx%Zd_G!;& ]*DZ7#ʐ_Q[~]ީڎw]޾jxy*y1JcD!0\3 ͞R]\~}Q:Pq)SvfJ'J(xԃ*Q(tx^JHUE׼BC0U8,ΣpѮ-ډq4 ӨmϠefU3x<%amoDY6<ʘc1nQ}$^';゗l{T]2>۶՟"[!v0h"o0Uțsвg&ןf}&{Z跻7wiRWVFFY!8o1L!*P uz8l}w^=|O̬¬NvkHEg3#utuY5Mos4~Wlx&o}eD{!O2NPx^xM]ΐjQ*:0(C0 &fZᢃA(3 < ў=iFe\ ZVLW'UOG+Xg$}Vﳧ9sC7U~P@SG{uuqQPgz89"Pms\mܾ4GxhGGԠ?Q U9<:((B ^h~b|sQdxɓi'V-q-vsǸ,i?iow(r(C+Q4 ~/Gywb8Ei򷵢w?ŘQwoGY56i*ǝH~Št@33/I=z3]#OOӢ F3%z;/:X7.j"zĺGŵ~Ĉ]\˿to4\RD$Qe222> QFFFFFFFFFFyRޠ#) +}E,"< ^L>8tvY7@4ߴwq@XZGhFO;Lޡ`aa|aa|{ O0LFz)Ori^ ceayP `aQo>61^贝:%^U]#v}̾O2/ܩe?PZ[Qf.I=>(7hpx&1Q4ijE9E>%L^/.u70h(֭[c>yt$rŃ:1nht8P%F5UNH Ƶ* 1N]#@~0+y+Steu(Cbj<~ӕ'j'~%2_0q|hOy,Ok׸'SUyάU^Ovzz ~+eN}Gu=_[4BqbBCM4 &ߓ_6ͿG!^26ڤ1 Ϙ١81=Z ^<x 4zʼx`7sw$ü?cff#$q(Z1]3x}xثCAZ4JtfݮPC/zyzpW'XcqEq}(7(67Gkzi09O(<]eW<kF<߶)+ys{F)((DcS%BH(2OIO,n۶-?QP`tܠ8QF!{e=P6l{+"GjzF /zb=?1(Q=K)~PVU*<Ҽ&Ƙ׉>>z}wa;uɺü}R_Y =F_Ea >V!&Ϲs{;-6'XQr4w.M~'Z*q0(O%ѨitsY!8o1L!ڷϣA"CueOsø 0ȍu1pɇA#^?4פyquӜknNS~}DsfqBDk=jͬ\Yie{"`a5P <>0xoߞ(SCByJP ˢQ!wxvD]a{aaqGqYX-c0#a8Q`TAa:ur*Q(K(yy(SE h,=DCyDRP]>OXcG`/UPBң B(Eq<7lb777JUr/FSʕ+Oq2A}(͵GB1= ]}@7{,>52n>ew0_5] Ba_! (&ٟo~ͽE 8FyAٿ3ňhd7.eZ Ce[xg5I;&mq~ՍK'}>|uWpa;-\fdddk QFFFFFFFFFFya&SCiy>n``5e?7qi\HxHf}vg҈bG9Q.$ xק,Q}x˜:v ә!xv%JSםA]^J S7Z/oN3Cؠ,%I3sh+#4 ":]Om̢p/:sҼ0ya;Mo4̡0QV8ҏPD^{͕oQP&(ofҟяy.J CgI(35(0(a\G48UTq֡;v7>os%@_ߵ>:q"+D-J =˖/I_n338U=z ytpD- & . F/gyȨ=Z4eHDS+1N:Ng,ǭWcwDIc".o:> F^øop&hrx44O Ids|UP `껢=v\!ȭ},O4cU)ffUha0/z&:a(<[i!йգMjq*Df6Gq9_D e|7Z)>W)ۤO:V"Q:GFA)M2>X\ƣ+M=+u|BE=[ QƇ~CQqúg4NM1߰~rak-B"jm+sb>na2_e(vq^M+Wy4çE{ӢSUɌsY!8o1L!*_*FaO5J:ԓ5>Ee`}&joڜZMg|}Pd68[篹<޹ H3;΄k-cl{YS(sD“5x8.< k&|}E*ʍz͏(FN[ Iy^k~u%=so*B3yR?gE{ʼGmmsѡP(P*:ϼIByUǡ%B*WG8wih(]('¡l).7<7hvxb2 P8?MI88+ǣ+NmDCP؀"Zf{Dqc7 ҉d\mTUew|w%wwpe_)q^$_ IDATAV]Ii|c-LR նX'PPVXWt= (I3t};Ih(7KVt^˼V9 {(F #Needd|.SߐzPr۬ `3!ƞg<=e'W z/-\ϝ<z L00{hW,'ty7Ͱs[Ҽ;00U&-U|"Fcځ >m{vڕ<f[kXXڑh#%Pڮ̼P/;Knn~=Ȱ(l8 F^ #]xYc<><_ u(A\Q~'O>#iH?}S|_ҿOUQV觪Я# F{(m(e u]gf/ީު.VAz%IqNgg-(N7?އKϏrw?m‹TV?hLHA*SdɯBy{;=ߒ P~DD!?q"ĸ9Pq L^#^2y:/JTZ/1^/qAJ+m %gD^u1q8/ǿ4dޤDӼF3K,Z֘G胞d= ;gƪ¤Q(ojK/{Μ6=^ ?ˤjTo}wc٢+}l_^hKr*Ld8Pñ%Nێ4lUyTMo߫ors,<D#*>c_!'[c;s$Rc6bRꕌiE3kAUffN6Nqy3D;C^c[CE1BA)aq! PH`zΝkf(RE{c N7iŊC! &}WPdb#^oU0xgw_7]7A[x0H4\UE)a~]m'Eh?)z?aG-G+(އ(GDB9B)"51u+L(۷FÂD(o]DDTEU?y.?w!JJ*C&1>y)E?qA8&R5k_'Q;=Pϟ|'4eƋoeJ.@jsړ[[_o7c:v!.X((Cs#X$6{ DhgGQb^|=/⋼>.؉JQm?>274ěnrn}kЍHOvn_w7jIy}~^osf'a^2Q/w|W?Ԗx2222Ud(##########L'~~`~D]z33['r*7> '(=x_V/*Eq(sLe   O.OӬ`0(MnOuc;sF w:sY/ѫhק[Ө|DI/˙\#uvHr}kɀlm;4q&K3PjPPz51yR\, kR}8.u_*߿Ϳ`(8J*G[#) 'p~QO(I%T=7zsKԸsE`ʕUd,EX:Z.ivaQ(DFҽq&i`|Dy-(]LU#i!UtOAxS#L*+JTwmfF&@V%0⿍|M00yjWD=U9{ɤ}ar՛4ZF$ڋ0xCgw~ %Lı*@_%nɩ(0\ʦ*O@ޑ?eTpZ_}?ͣ8n g0rn?H37*x# /= "z# Q)`eINg/8dsAhIQ<@FI)Se%^}SL12DPeU ?4؉8ׯxyJ4GCco>߭mM=~ W?2eO[8۾SW8NYw2ϣhMO-,^@xPXY'Y˺5Ryd^)#vJl;}=~?yUoLAsAWCn\mDk5EK~7{R4#_(F.~X@8בшY0.ΑgdceL"@s[?U:O)<~68]+ϯR0^ؔ)Ay}՟{Ԡ+xang^֑ψhJQЦM |تWB^d< нޛǃy/;&֣_ o XD)xCaLL#ǂₒoN^ߊwhI(^ (r0(8ǧf69PTe[TA:Nwmz5.no0J\ (H0՚dToC>BoFYw-ڰ 0W;U-yz1nܸgq⡇JGI^|PO=S(SQ<1~P| ֢,U4*#̕x|2W+R(>X#ʼwɞp{N)(1Y<~j^> Y5_l531"NOG#Q%*1}N!5 \ !l'41WFfVٙQ~C4ۢ}g&pq{d+~_gcGxz=s |W3yO/^&L6/ԟG~x>M222> QFFFFFFFFFFya (չ׿affRe8C 4zduirW#M&J ;i Pi00-U-΁-0bffuyBʢaX ̬ ՊQP渢IWR4oޢSO $:GP/邶юBSӛ]5C>~"͋8f(v`uynez^2>]فa5|æ[XR}#xUfVq"+D-{jLq/%MDrf3UD-Y*?(;Dy0{`3xhKK ]3L .G:To P`W5͏ӹkDY5y UL*QQDFޚF5y,ߪH M]hqi, c"ÃDcCsr [<[&nu>A31 7yGW42++##sedddddddddd9%B)y+G\s*{ak Sa'0 `:E24(F`I(HH"ϐzϏzu?H .oI)̓C]7zrkclk)ͧc\p?7<^] E!%**:D;.ړGKƁ@+JKpo @kT_╫`Ey59}GC!RD Wԙ~W_ ޟ~_|WTJyVH>|DzsyPBή U 0 Jo! >-=#j>st,=i4Өu%-ޡfW,ŋlR7|"jY{RD??Y! 6W/0008 &'iMj[S- eX镼%<o {WG>k'&DYAReQ_ݫ#-Ҥ'OEr mIVG=YEv?,ؙߧ,$ 3FNw?{3ZI1y6Ʒ}"PN*.(v%lZ^3;"smfãוA+Կ@,ZsCm(hCȟB767GBQS҃g %e0|<׳X2Ph21kъDz?^xʔagw8S.[ZuZ/{Nxvx#xW.5;_(wuedd0eyY% OAϠ3J y4vY%JrftdE>{3-0`JGE̕2\OtEE^Q<ňQ  $L+L+@K}(E_C뚇o53OoL$´yo™E3܃+\|Iz3l(Pt-<'Pe&OOw;U`J ,>A衰5Oi9e[_l-JK(Dxg2xiTyR J޽Dw9xy"*WGBø(QoUvQTKT⁢\E"f)9uBGA|c&yyy]DבԋyTyi˲FlP@/ WuLtj J3~{ҷ ,XQ;QvPn؁}[MW[/?ׁ)E>g&K>C>!N`>v+/ 4 cߡ"XʈBqC?:; `?ա# o ~ֲhia(L{|Pn/U+9e8w;2D}:lI ^_Q2ѫw4BFuL-|$RF'^X0: p]ǿ$J(#z)J7u21ʉABQ% h|q uxzwym}T-o"Gg(~N]S,Ea0(!(3/r:D>BEРp 7 JzPfF4/ &x<~zԣ{x8Vϓ*gRtƫ(5=eSyxPVż\Q{q<:T!^#zsT7ݚ.'ķ>nI"exx{Jс^x/peΣˍz(?]no3&"x޵%ɆsY!8o1L!tŃ|=@2G S'10i>âD))6di!K"E(5r4a\ZHZJJsO~o0 ?ӌUo><ԛRv]i=v+Sa5߶<>[=U;$/;7nn}- e t8y.ϊcϺxL_]Z2*Hš4WeJMQBh[(jTx+l /$塤h:ΫG)-(\(>ljrao%W((;k%͇ޞ)*ԻB)f:7\2n QFFFFFFFFFFyyV;-^`\RƬ,*PoF-=d 9*wRYt4 8Yʐ֛/]{:eJE򧏭EI|dtרG/ +џ(o{{OOrP?b/p9e߽$2`|7ΨMq+ӆ9}-i?%C#(} v\?sܢ r7qf\hy(LgDpx3F1B33[>ͽTj3w"ԫ{PNT!CzTxn(>C"/k)\}? iT;@lOgO<9拲̣xo6 WD7]C .V6[Hw)V(g6,j7R/ЭYEyƻ3sK4ݐ܏Wq¨q"SC!BQoQ`sT>ɩGrRũ^z^2ߍ7hf% YqDP7EuyiO-pD<_ .Fċ4N2D=xҝ a([=ćWibQob,@>]2jQ_6l}}>~_3(w8(D^":222> QFFFFFFFFFFyaofVar9#tՍ8"L{ȁ20YffGɅcOz`ښϲl/78۞nP>5Txx)C;ޟ=QPq}"Qss79T}Uf[zyzQ#)4k)2BOy6g{Z]zڭ0}Ӂ1 yWzxDʼDOW8w4\tBr=JG+>J]2nm~<:@ /3S"Zz9_3߈ISx]BBTE)?0ErC46UP\+Tus53 < T44#x=Kjk׮>]";,^)U@ǥF#("Yqޤ|#F C;W8!pͬ/μ']_Gƥ̈d;ɞ~(Qg qāLaf%GI{0Jx]'gJW0qQ)0Q_'4USn𜧘wF |5y<ji#!h&㣙=o9q-<~O'ǔf"BPHP( BPYil2dB2yG)ӄEfe8h\;.][u CXLbL匛9ɹ,""Z[ h( 8 wҭH+Yfdah|?-ጟzAԸ! W7I >* W*\8)i4~.׃tu3( I(,,sqs?M&WIΏ#F .-5گ;MPO핮x`$NLqH214=`xĀ٩B&aB=#USÚl"rO?{=븲A@Km=5/唛=2.!.M;ͧt o U -Ш[wJ` p~ZIx$Jbe:x|uJx|a铒=χ8o3Mhg\eyMhqHP B%P BP( BPi)Ӻu+ #e.  4#~ [ݛɀWW1P {d팮Դr?}`f S*$I)L !A3#!@IF(Q5Hp8Nr2klǠ}Oj:i@q 9S"xn!l}dNg kyݒ"NƁ&G2>`zx!PohN֞GDDXAˁ5?5?3nB[#\p%״hu}Hj77x=R%:d%yv*@)I&υOA355N.{=L N$>p$#0DRԝHItNɚLI)0N4I}~Ol@<|7%5A`jXk0Duuu{́ 8LG`~О;vԩSM汌K-oR !$ɜ;G #Q uPG̉> y@`G2 詛װ8NbBaysyܤu^0ExW,"Y갅` `G/zeS9B[.s BP( Ba!#*2Z`TFϘBDD)keB'3aI!Cf;dwrfN2C!p(̱פ#3:8}d(gE]&7#hSxYDTj7mp_3w<"l>nlHmϝu6̽n}>'_go7zMֆzȾݹLvWN&tv& f9CC%\=wekG m”-+|05F# <'W(Ƚ|Z:t8~%-[&;TwGp~.NL]yOgq}@ktr< JyoKINqQek&(0Oss`rRR؆.r`$¬C3CDDsrLfb>G|cL hBSM8@\q 0RKa$ZbQ3/*}4Ia+$n`_a1)̬?ό b0D{h;>J F0\>lpJ }}NjԾ4xu.2Ԏ`>cW+V)J0t5et_Y ⤀2D BP( "!B=!hijw2X ?y2`&Mm[d3g2ӏL'2gL۠k8`vD7JxO!3~`05 IDATJې['v+B&VBf6oV?Q7 MWJ~QoL̖ld9s*9ڣ/ y3ZΤ7= R 2t"`ykDaf >OQCՔ/YP(%Z2f}Mdz *.6nÇ[MN"0P@ʕV\]f^fA2RKEj.Wx9\c?'aKf~>Sh.KK 4?$Fͩ3Ss_qm1Vo=p\ġ\amD~ i/Uw`t&IeCL<W!ho392wO\5ŗ~Sm)^ e BP( EEC͂a@_26`d +XHDn5hcԵnG%t;ԍ0Nju* ^#J[~& klFCɌ-W@O $2CVș5fͼY_n2inEv{ND'ݨp}e#"nuNK̡_ZֺΐL㚸^ͮP|]%`t;yfN7 B"BP( Bgɵ‡5ups%]AV MwupP\X=cE{2fLĚ1Q8{I5_\drt82`̠BTɐQX?(52pQF|_S_e!^Q=B$60GRC&:U52 M2I҆+Z: | aڙ:"ńx'׋hm늈3dv;h41a|Hñ㰵+@ Vv#sJX7&;C/6*0`pMC_ Ihdn2uo70Crq ;]|u$i간-Ɵlg33Yg]:?\Ġ9aΜBK.s֭3qk9Ӛ^VƌL=^A WUvmd3ǚ;c.%"hR Õh_knW!.&`:1BDD1Yvf42Q&̲Re'.*6㣢]S5ܾ  m!jk9=:`>Ep"0C `詧.;&eЇJe z>`@.HIfTgIYGqc9fQG I*vv瑫Y]7*\_`ʹV"NA+V Ukb]fυպq';:nzv]aڿҸN:6LpЀgx%1Gpm|o/_i)R B8Y BP( BJˌ2]!sfKdQ'K0CBầٕ2m,"C:9P~[Q*:kr@H7uo]nk{[v%SB~=0o%`pi-("_Id`֐1N,޻JMV@ U+72~yȰ;k \0~'3)!av Y%+3pG2K;CtYN 4H@keᆹ ZWV<8~LuxZ%%#"1)%0?>5h Vɱc QgI5'L欺Cyk$*996 hlBDD' pn`ئ_0F8y- L+k#0!`4c^Yms@|q'hb;0.s[P5oyKxq50hJO55Yq?4::wn=+8D65_S:'?7Z"3y^ XP(z+!R( BP(}A QDi@]2CmLf#tKJʡ`t^g֘un28tK^L pFG9jr0+"DOBsC2O2TAed]'۝{opg3.k ݱnnzZ%ۏ( )uN@Jsw%m 4CF0.@ƶuhfȜgHDYi;W[ LPoDΉKf"" l-«՜0\ܠ)* L~qf&(hb|?BB_ jG'xw0DpF̙3yX1LJMu]l)̣kx!qz+#u&+.~!杸~XfBSZ+{:h#[6{`R=gM;=ݺ<̀~bC܂g@ 9Ώ6JFt;y)f W U 2Z yύ|lp3?:Yf>xp9"%$c90mU( e BP( EECT)\PAd̚ X*0 AS۝LVk%c#]2X:?@F\׎g"`=\9lm $נ(ira*;m !ё,̫i8wG2M0 F4>n3Xs dy}`%0P5p#LhC3S؅Rw0aa '{ kv\w6nר)V3ʵȰmo/3TT\8wH:ڶe?/(bBu]&cRjg)>h^f .T#7 a"9q\ױp>pDD>31o2ZKMm zn`Q9q 4 5rU #c?3:En<5|ϿCeWB8) BP( Bb Cffaf @kQu#batQZwung@\0M6S"(!I ':G#d'' KC}[K&223{Rn?28@/r/8*܃Jzȸ&?hncE9PfQs ~h/axu!Ld\ì7q <;?Ɍ'i\WaOT F^Xh_ʆL-Zى37Zi3Ď8^Z!8/ v] /5VWכh<3'>s#^SBmC`ɺa+~ |co.o,n+f lTofK-!]_`^mۣ!Q0H &('^8>u] L s>C|~ܒeDDt+Y3Z[fh6GD^ Ǘe4@ssʺG8:ZR+SwI2POǐB'pK>%'3sSU㒙Sg毰!1A?qm~?_>+ Eo2D BP( "!j wp˯.vk2캁ȄEkR9.b-uϱubE AoT<3;q Rf%#38^+ q=@:ٮ|s Љ5q.o〶GIMP!d67hUm:RWpf4W3@$4\qƝ}}6Y"Ψq0WmF%30i)P0xrɊ237.v3 '^(*V{Ox(^f3d\˔.""Rȅdh naX;l Y'蜋/K\wLRqCFҙ1*,]#67Ŭe^uTg\_L3&d$aYPGlBi_|_3GV`VIMNL1&"d+1#)j4#!vSVSjI0C|x\̼,_3)\w4d͏vHF<4C9O]͐}ݙBc%Q)2\d|ٸ"3P5 K&Z%Dw=vڬh硻jMָsZ&Y=,:Q "VlL_?oٕqӫ 333Pg ͚%)yک9:&-pgQߣ=| 4%LN;QV5ěLf0aPֺ`SnQ8ńx?F:mGŁ%ǽQj7͑iï…j{uM )\2"n^u}.-)*ՠ|`!.m5vp_{2AO]d<Njde%RV'ǝ۶{3B3%{۝nϫBK`mh-[SM0E7 )) BP(> JdαۯRSYܼ@"3>ġᐙh8{!H23H|p} kv*ءX;40Z!`PO畚F>~sѨR #."3`h *6uUPǩp)ZrbME%IOI3*y{к;Bwf.@F \b~`;h0O죑ChoG\(7M %S'̼2S lŸ>T2u*D#w]/0[C(/ndOs}^mt0\x}R`iw~]""xnӬ LxjLCb8yXC:EIugant Bۡ BP( Bbdt]Yqvzȵҗ 4TNCL_(sl8hXCNh.TG dlklZNGHU9,1JGVGk5稟' T):J՞ 7ykxuAkT'̸}JA8qaḑ38cf.mP~uK2C )?ęs 4 Hp/"igyν3M5k\l?x VPX&gAğ){?7j*{TnGF\p}.Lɵg'"cG9 &(I~ ]ڝؕۑqu6{!ǍO{< 2 Ĥ2`eFL`*yZ@':Ș9*{dT9P;n'Off t}5&^Q.dtm9DD (7q 0LNt;_wS>$4s7`35RS8NUaGxEۙfq$s9a1}M2PIu{umcIēyB׺ԇ ;wƏq.}J͑A0~u1E]T+nW7V:T IDATB!}<Ś#j [˚wOd=.hrUx>v񺳠:.몇lf񳻺L8Yk< dD9_RM|C46qm]_6C B8Y BP( Bb9Z0krfx \#o2"r׊#m #2[^T-ܜs*x{3`r|2R3%B`FEEw.\72`:u}Yt27$BJ.Q~4ǯ~ܙ?QB 5Y&x!s- }ěG?EFk>lc m̴ CL"䜁ﶆfdjl"'(#+#4|3:͍in3hqTu1$&2#鴃'icKmA\ F19AlgϞigʌxE=%:NȘ_O݊UYC#3d5vqx?YG _Py^d m¼D!īUW`b>˸&{\!w-WR]:^6SeR#9DQ)پ=`N.su%R|%tknD\hJ 5J"\P(z;!R( BP(}A 4$̧(8c6>H{iĩ d2tp}v0 y6dh5T)>2>D~a F dg>_77K`·LeC%ʺHQ+rU=lwn@zK3&ؙ]҇!Ǔ(ɳ_qײ:yzWo~p(6#)̨Fzn;`B'Ù6Ѭ0Uތ2[[3$PCw&:g? 2mmA-=.4VvX i.spkf{=55̸>v21 TCW/PҁwwĿ{Z<6Qh/43My`% ޝ^`5MV.*n[o7]h|dyuzFv.Ϸymqv5 7 ?XA~? d0GTDDtlo }_"3SCWB8) BP( BJ5N&~ |<0ǸAL! W}q8kM֢ĥkɫwv]j\$k1 \!\?2]/Αz̊d6D'ɬ! *_1v&σ&)İ)|cB#Y- 3R&]pZu s:'ݡf x0`6w4s~Gk+_o i?kQ ҈F d~H2~̖ty~.Q'HFP*ݷ'%z~^XX_GuaDDT@G:@DDXD8ua`N0v>(T>.tqKFy;[">'{j-͍K6Cƭ H9s{\ <.#u]-y:xNxYG E{:IQy)\D[}93eЊ9)ԣ&?_׈y aH9Q@S!hBPv(CP( BP(," ֧ͨgf: X#g*3ӒC>qW 03BgYחsV'e߃~cezxFL̄u6@Q*T'%} !ikgd.%3%32/ !3Qh?!x&JdMamL6VO,֤4楧0fsk  KL2h}0df.~> gFqb⹽?DLCh׈P~%ϡ(cd=j3{潭kgȦb1ě/Zc0ɭ3nfҌ0-p}#18g3-2p`x FJ2[2^ @[8:8 \HDBI}9|ƊyIVhvU>s +$W!F]9k,2|Xs&1֙뎶΃Thd?p-VDanMqŗ"!6aʩ6zm%EU`]b2gfcbXn\l Zg^ f@]#n?4}2`h\kf*hupqXmgٔdѐږ)7!ggg]!ܯ Iur!m^\_@Uiާ &)QhvP҄m3~H_VGJ=ƃ%5f`n~D"fk H~w$ݤL0`fqNRc4/}L$3HP:牰螢w=)yk[]y= M>G>TM LCqy`Cɐbcքb뺤K'\/y]`>fr=1 R;%?>dfVvn^Q W 3ui۷ȭt[Q -SAffϭR l7H՚[Sn)e BP( EEC$d7pk%d&LfeFYc$~3Ьx3gdOjNCW`Hu_Z1}h WQ pV1je ~s]~6t[7[عܮ$㹚#ܭd?ck{:;dR%#ݚzo`#)gk%!%ѝ ! |7H8'46<~`DfTZ ΆE&j""ڕ5vp %z8_.4s\`^4)C$/ho קim47V|kʹ̍< k> .g~qDC2W$-=@[3Ln/!a PqṾLS-2~A\dxЋb!^o2ƕu*Zo5k4kL7= sLTsm}]8\w,.ۍ0-q23y|=o~Nx{pws1Rry׈Єъ #Öw9_j/Oؾ`B"%ȟ6p\ٚw"@RkMd3!{ ̸Fha"1O1fO1@A|׷5?5]&}Κ΃Q&Q'y;fvNOr7muX| x{x(] &~>5<ˎK^ߗWq;*>0ןfCE<FE0`x">&_Y ⤀2D BP( · 2͆J\$ k98o+ODvpaY 7 ԏӒ`62v.#p[ؙZMs"Zt?&L K@떲St eu k?2Qv湲;S֝3 0WKm}lg?]vBS 30H-Zw XKmqP_8;T/޹KF}i<o%pk^)k05]^7㤊ڸJ3Tuꨤf "Wi8Qǫ?̻:8T 9Zgq#(Jm LA<#/wk4|^(xM{ĥ=2D@k'E4`"19 BPv(CP( BP(,"~q7j0 !cL%2xN 2a:QW]S/a>|ɨnjMPv]2 ^+jLtKS ⸨4f:'\p:I`JUl7oEqW$/x?RډU?ڻn9/9(]}EF7Ih.9>ڑ !s_Ms\\"Vng8.']0 `dFMa7o)U0A"fP.D]Ɲ`pjm& `0C4Q|hnc?GT""l7moj@`X[[[BbѮm|SO=?_SPrz+l&/y|KDD6Yq+x8n=ęg23 >wɊ?h)[[`~Ȳ┌sFRfl( yKR81j\ф 'aOyp|C|c)^e%Y8!AD;7Xg=п-|?$ > -=^p?מz|g14|QWDIjm=>ͤBP|PHP( BPY1DΚo>D=1Ádꑫ9cLIXC/3 "9B=[f9ÂL+2xplLsíW'\a~XSyvd++2æg^ۇnI@xzH½Ijpd"@g5t3P_/K'.)B{iʜ~4 {{y>1F 1߻w/=# 8 e˦""<5 -M&kSӿSsjZ02DGu!b+\/2}+63>%zzGSgcXc!3P' Nᆅ|LW4h}G<Lļ¼沾f&OֵiڗkXmcqyYlۜ9q%SÐv^[8DRc(!J%0{öftJ%s=K |)߉?6(+pUE?<`1oͼL rf8]0 B"BP( BgOڛ+LvȈuìIYi8Q@/0X[/3pL[+wQ?V閇:4>;$QNDx@k_z9|޷lQ^35(oX [CZq]-u-Ph$w338&!]ЪYUÇμ' na&L 43oŕ>7vE  mGA7&{wo3BMK.G0*OfgpfpJڅ"hoc2i)v}$hdv6UF5u9v̋s""n4 nÙ9v7M$hġ!~$06*h#y%$lZB[Cq.oiM0:oX9R(Ԙ%M3b}Pus)7p1 6a>}_=MDD|h20=uCHP(N(CP( BP(,"d6L_DȘAKMs7.bUn~Bd4yC?EBf Tg7)dF0[p[(@q*r5µN27t]^gw;p?PG k{]؞qW ]п-b!ekP21# :w$dL3kp?CfOQ!xdArTa7 1k}qǗnPɆ Tldt8u XsRgh'7ݡN?cƙ~L1x(xwu_]dƥfS+95a\w.7v[(ކf,ru5R '5sӞ= k> focء"jٝAk>H>f&3į:vud.nSY͉O8k8ljʗSH@} LOnUQ 135/녡V;ŗhI5B0 Bq@"BP( BgHr ACTR͙9dٔົڑ!DO2XszH Hv{>0C>kvZ#SA|.7 S*ÚzYnH҅WNd^e ɠ ppfZ#0_:6~ dqq).s=В՚ nޭ#eg/άPi9fNQ~Vo>ahn3-M0m2up$a?YHjh9h?fH q`~bHIc .U44X ~~.Z`$sʭeSc\3#L-03pusސ5x9Af^lnShZBc&q8%)1qJhJ}zyLR$▜.d3%>%AoL!,UblpC?@F*3&)6{RW WIwҪ60B2B^ o/~l55qHbZy*i!BqB"BP( Bg~FgсHj\\W1; 14033b2c5 m-L; 3G^.SQۙb a933Ty:nhg DO*!;͠@#|\8}dbUd%=x 6󳲘sX|+M{  `2(=dE`>ȸ! $30Haۿ61^X]? :^2. `P3 IDATraqe?zB~qO0ACEݤIZ;pg`l+kq^"dBc3Jy 8ߗagL=4h^A7#/$Y#$|(~ 0AF3 E ?)yi7ƗtO +zJ|nIHt].Ef'N9弒qI e BP( EEpŃ=iD}\)PQǗY!+/LЧ.ftvŭakd*:*cM>·LdC C9F lAfG`:v>kבIM3msX{h6lfbz8 _* ZYZ~~Rul9 ƗLm!^; >(Hm!c ȵ~q=\訩b2p<72ԂYLh:0Rhqa9)&y1B#70S)qbu:_q#J2Ai=v}-;0q&k5lJK&x(&9 uE]rxGf^2Y3&ў {0<.nh7)5`2@|vvCv|ͳeks(yٚPO$ q:36ɡY|[)R(' !R( BP(}A QӡDDt`)L\33Lh,d:E8C"?fF60Y_BjIK6Th&^@oRfR?q4fp]ҕ !3ˮF{?ngn1wAu@@j^/4X>@C]֩xdg)?m/Z9 ے~}uTm@fU2>r>ڃ@h{0SdvH&ddnxR椭 " 7R=fnzVlB2>)STeC I2 5}cuv2f&Ӫm\1"F sCc~i5vqǓuȰKjϘ~a fe8bx7x$t~0Fоn\]L=uOs)C7֠ʞnET7GC'Ow;HP,PHP( BPY1D-YFDusr-o̚j/>Ȱ.tޟKw%;W50!Xa'EȌd{θ9`&dqXr~\hdHELfkq?~Nvf6>/2Ibt=fׯ" =yF{ YKUTdWTddt&ca2tjb.G"80A "0C{.:R#!jHW\g3h]g)@=!hpݵw 5I`Hci~rtqɁh¼xk|pS"bޢ`8smw;hK*0)-b& Y0`)l [fdwngr_(79u尥}==dž9O֍sv%5ZS%2ԖupkuVV3_e,09g_L4͹ k{FZqGP(ND BP(';NP('"8vs6h1$3丣`ѻkb!wݝC |\jEw44J{ : Ñ{NS ӊ~[$|!3=m>_Zף)ܘ lĤZgms_d+>!3 W&dSn[La?d{dX[Y)벿+adkڸ0!2UTТ=ǃ.r{7099牨3$Svi \SQ |Z# 6iHXiW\\$C']#Ϗ&yyl3.bRc 5,"n8ٮ]DZ['Ӻ'Ԋ~2hIe}2'^WUjp}2I-bw07,rɨy``^qg O=bmZvϞ;<:J洟KxJy w_?f[HDD?93?Ys8BR('TCP( BP(,>GD~z}j,^Q( BP(HHJQHP( BPY"BP( B? BP( n~NG Ā+\;OLhg~8?y6gxǓ>su|E!  ??.Lz?ҏ8W;nHL;)~ OyGB}ln8:52ZG !T(j8 G%GO澷i^7HJFe? AtMM: NpT}Т8K|ǎ=9r1?ZQpv::١8֦AGNWOԯ_?:_>qO}שPZ('OR+zߵ_|/@^6GB ~`Co{ܧI@H ݩ24K_}GuӨ͍=a>3FHPcǴ{q?*DQBR*|˭]nsWF I''x)oC>߿nכ v'wb~`KS=R ̬1t7цo|"ď x~6sq)?{M#FsݯKqܣ}N`֯wiYSi <4&O=Xte  3fhȱ}kBӟi5泺_yOЦ ʲ')<47툈6)l=Y5tnݯ1mH߼q!?gW_'mIgwO ONɡ5kÇt}ѣ>Jw_A/ѽezC?\@Ǐb*..Ӆ^H|݌3VZEMMMO#=s$mٴ[uyTRWh{T},/0V??޽S3ݍJ?X]>|VXTD_֦||VuN:5"BD} {r) I9?;_ٍo&QctWogϦ@K~oӃO^~=ڏwߥ,vIn~pG @goYYPmmY 8._הOO>dtΣǎ}".sۏ?0SO=emw 7ФI}ߧ'V)((/ kqWїrk=OMMꯚ|~}Gf_p|~55"Φôv+t˃Y:}e4d2l;2ZʫAW@_ AOEZ[[[tEs(%m8x-_O#;u{F<^3θ,ËK}Tԣ}v+ﻆJCd-#-[.e%\BCd{o{1ԓ?.(qP9~ ,+XDǍ!/^XemSSSCJMϤcs;>9WTvM8w.~ڠqx?Wo)bJHJV;ߥ#Zmi,pg=$RCghhA,}Ї񛻿O?g/Fef̳ϦȈں-{H:TU~ O7r+>Gӗn#7$$cҥKG=!}[h=tիW_ӪUs;iiiAKz[?~B߼۔5E?^VZ4l(~(Aw[w,EC/_@ Hq~|}s/(&:\r=|,ys[o|coѢ;nT;6ŴͷJJU"]:gٙGl9t7ehصtWiߠ}qz>BR_K;?'Z/k"{Kwў?젳FIw<:֗""hPo]z ?}?>EN?3nWv]r\3jmxm/3zy^LgLOEiSsK3'xWk_^GfAӗMJmGѣGi;yt-_Ч6Ҭg>ЬgyLFOcѧW^#G~7w+KM\GK~PߞϿkvc(?W>Gvv>{]3>ޑ#Gh˖-t׾)44RSS믧}yc…tR\=Wr?._K׏{qm޽{N3WGw}:imwwo=}G7̣7^KboӤIigVڳ3.w]a}x|I|5nBBIS_b=%tE\r74У}=_~Zg7,͇Ur>#ҷZDs.ƌE?ɏ?Afw\Fp;O@e?\y¦W-wtôrb㻛hBa!&^HMc]WoX /oM?\IgLOí7.UIϠ~}ۇI=@K?A$տ׾LͿmxg. fEwr"~T:TNkIϰbz>M446O~3z~7w/<%4]_gM4qX꿄҅7D&'Rm g g;9s_H ^}<[-4 }֙#?Syp??XfD_ch}22-TQ_qB+fޠ0fhڲy#wE@^^ ]r\ʫ\Xmmmt ΦtJHJ̑TSS'5Z[[iu#>FO_/(x}w.$$'?ݶÐ =Eƛ?s1}6WhkLemPeH'DFEgTjSX|>UEvECMSmt0LLSskޞm~A4 {tƆ}XYS/ fxqy<}B=dWp&yv`AH;z (//GjZ:,[ MM(;;,>(700@IiHDN_~c<x?6aT9~QAVՕuE?Gcы99O Ŭms~jԼuH3IZ|؁ /|,FRF!-G?G!''o'Eՙ_b@6.`Ϡ8 {w!A E c.x'} cd$}ZX 9Ea?|X*ء叨-'55U%cn nFb]Xؿsqu *~=n,t+kXes@4<#=8Cj3I+H|}}}7 ~x~y`` bbb?2ǎvcT |fz͎bg\ؙgϞpttlvl*>7&kn!nQZf7#"*Xe}QXVyv#pDDY[[KGW^b*j픝\7qd&:ƺb%.;;Ǟ?WWWlڴIRU;* Ys qB.:t0lrOHaX IDAT fl_]$XYI˂ɹ믿F7"Iɂaزq=6o& L6oݎm7nhOϞ=#iGani Cp-lݼAz}̘AbbXV6`i6x{썩L{!yy&ԋs~x26C8~'8hR7/eň  V)1ߺ&Lêk=s@n]xz*rr`;|"v5?l>A;رu:q Σd3 󿝋׆„ɂ [x{Py} +;)v4"+;&{/&z1Yo^W) ܃9b4]HLM~>SG'غ'bvX>g6bk ޸Mn\LO®q"HUbx]`m8of KKKHIIABBF_ԾtRǣ_~qm믰nUI7n iSF[[Tؾ}{:u 7n܀ LLLpMdff o{.<<*i.~_7v4d(E?+K8BTWU 0U ޿v-&~+7>0|<. ]hI߽D N^. :Hj4W.JlءE玝MNع-u6z&f ڴ?q) ҩA*~mZd @?ݺ~"j|B>Nvg>SRR1C))iis3)iN"NjP+[+\ܜqqq@ڲb&c?]b.v]^}֗7/~(!)ٜC $$$:K?95IKMKKZ{Y)h-| ]b.vW"˛C/4jIHFR1d璲UJHV N(JKUF߂  P|}y ҘDYY$I(-iCN\/Zoy 8F {;Jc5VY} Buߑh Ϧ hA+'j:X&<6b;*zx7okIl?g^ V*'g\,ߜF&e^֧|}2ߝ)z16*5jcdTswΊ۩q>eǯ)zU[+!5y+~6ZHSk_,f:Kcr-%%mv6JH T`XXX`a*[xG-cbv]{T|8ZTv$ۑI;ϱ1Vŏa\ - i ңWs_͎slՖqRqZ9S!eǮ'!=hZ"^_H[_g}j:X3A "O@FTݞ4p孭yI1ϑ]U^SҾfn01SϷ9sy#DYgP( ;;uB\ܫB~ECBfFٹa;?W'-T(jA-ڷ 1S4oqҥثݰcQf2? D'nkĎiX:߰m.lf^v!*!*uf2+ \ONƊЃ-jL~ZJ"1w2vvmAl KqD%bK)\B7ozE_uRB㶄BW{I=#Vu`ʎH^%)]䡆tjԏ9syߟ5ϑ]U^>q"fBU[-6SAѨ D2[B@*y)iQw~fwvngk2o\܋ӷ/$rʼn:1c=LFO`m 7[KҲ{9.}'ȿɴQq?x)/B;gx>69{/и/C=)6d dj4P0xQEgf1y[8}xP(suG `n ncPÞO?դt|}P3rb:屫hrZX2S}V1S]\3Vv]r _8f,GX _:q^tZZ-RQ3,}vȫ\{Z9# m'!C Z-Լ# =x8g-ƴCg?WFǗs ` iÓ!5ifJ {k^iG7쭹h_SS*L܀kfSs5k| %ӑW7[F> kogn%3`x0sN$p2&Y._z٘B51nvdiRkPdrB{a1_^T] 2Oq򺾻N~ً 0v_e,fn/|*eː $c;V}_zbmwSs QԝKo=ĕ=*,r}}mZꯁ|y`^ZvYmV<؋~W[K]Kd杻NJf|ԣ{ps`Vx[m6񡩗#eiP*tΝ 5ѪѠW s1֨AO 5<R{ϙAms!37 ōcbOqۃ[(XpM9gt}9RwμƟq2G+ fʭ ukz|]>;tarZ',& e M7|e5_בN~n;~IoAa&_ȇs˟m1ˡCW3\N66ԍ>u[?ò h]dFRpEaupu.S͢)&үr4:ϙrJ[^i_jUlIC6`Pk_͟D_O_y,ě{ϡ FPGubӌ򔝭F_Uݮ8ٰl m?˵4j:aF fJ׆ _{5JLۋO+^T_^o9߆Jڗ þ.)L'4zQ6BR@*Pf(`"^ȹ;`jGAT@ι;S<_yDڑ˻|9|ːث]7$4mCʹ@{MHuҿLFlwRVޫN_K [El]0@;ۙn  ӊiD` GЭiY,758~%@n$q31MMy"'}T^Dtmsak5Y41?D}M@5cn[Tn9t7:Mh fA%r/ov;\MH^i_4( k1e"O`cS&Oi$]3_kV|}ă4p >-KJZf~MoK<ռ6C2p 4ߪQcS3vڂt9S%od8?ǿoΈ S0vyۛV&11Ȕ9WC>9I(D/KǷJI:mCIt"I/L':eԋY,  %5^jGgv!,5:*w~/ާRV(L屸2[:x:lKĭyO;Duv]ۢK[8G5{7fY{6|b[4r#zM3y =vRډafj{[D̵͆$g`1k_qˡK3LlJQڒ+q [uhuQ|u"e7)uR݊FJHK{HGfz "*>X~y=:~IGI7?G.r:&`o'qC:v\OeW }k xz3ŧ׉I@/icS2$꜎vqot o؎MYhBCC8~Q,gWd l-k]maѨl Ya쉼iS<gZ?swrՠ}]7]3珋2o^9Zm98VZ&n9Ok\7uZ@G7= >?ߕXwyKFe.C_i.Ȥ.Ŋa >| <cCi[O!GS iZM6/pwP:MRoS ))XZ[骗! c)$&F5~8 o>#qثdδPBk |w8ߍhY\L91wj䍻5)a'KEKvacLg2ܶlK@t\ &>Ѣ/&1%(;Z̀&XY|3ѱrbiu4+%M|yo]:k]V {doǹx+@]^7y{=֘]RgsjԈ~!s s7XuY_1\?^ꆟ=ʐ+2k:>|2Z,=<)rCĞ<ZN\OJcשܹBYUb'otmupNzG.2oYvFܤK_P^e'.ؗbU%|6%0MaN*m a >5pwwҏi ɱ''s& VA*JS`g4$uؽšk^dBn4 Aj٤/7B՚q|+&xx`k4"4L5&+#[{">(=~H90GgAvv җ/v_^?Bk[ZZ[ꈃXYh*Mv6i除x;jTi߂ ՙϟ A 5Ra%D   \AH  P]A$  "Y3@AAꆅ$"   TizmdC_WP?@"% Br1mH`Axx}0^>-AAJLzZ*bJ AD;b$AԨsUD R;:'A;:s뺈!A* JEΒ Pb2% TnALA.HMN*v/N P"n " KKTmAAJ޹4 2QA$ ]RIBJ.ll1A᮰ PiP޾f Ә\楼@`PS MH`PS=U~yg_.lKxK{I/ PUae?oRB~}X{^yE[~RiN08iZ9qLKobeɍkjy}`Kr'-\abfx.0-[DW?W$ - \ [|N|(yar8HSak[ΆSèߐzycxRRRLIELs (0dl3nߩx"+K]ֺ}'ΆyU*Q|SRRx4lR|[JSۿ!ҫlݶ˘ȄISh@k}߰1yn+ZT˛\_޾$''o߰1S8!- BFCsĄK>qSBO?Щaκ9JVGz1dxrF7}:*U6>o-;&wcV#^۟wjT<y){Gk$Er©Sy3s=w#y{~4^^t[ҥ(2I˥Ke^c9/ɂEK߯O_+/U< ڶ/ȖoҸQ` | IDAT;99Nɴ߷ݏIS׷7>+++={ط73:wοw˥kЧi̟oӳIw?GX7ѽD竹WqܹL_7lǟύ#- :MNk_1OX$sGp):o훮ٓ9v]>K@ҹϡB8ޡ}deYݸp];J5Ύ)\N='ݵYq[ٵQjakNh Vo$VZ3ß.:hP>kV}kЧwi-ߝld׷7q,XvmuǪ_cmm <ճGw*j.e}.ڢ50|S$%%1cl//- }&3R b^Pňy߁73>K jxi˳rGlA)"NYչTJe6}2f`ގlMN$׆4jz*MAt$mkۦ_|T WkOyy~ZT*5,]ϛ߾tW?J]d puqLY45O y%˖}||OH`}̟3 55ǎ3y{_)'mz0,|n{vgǟS5 j\\6Lws}=2xm.VR g+ {}x׾&KEzl؎, lB۝&En (8GΞϡPsԮw 2K|ٶ5W{}.魏 h{A{9hOYXhS0pt,ⴿ J-?j #+˂7_:ئ*3ҭ(MAt6+rK\\5jxnj[y!<ئqq;GwOgg'wƺQ#Y:;;;:vhs "O&IsWׂw\]]ILJ2~ yh:uhѢ}z_zZ\+eVR*S#ܬUYl^ڂrW3m mQ*e"88g?O?|o7U󵬮/X T% %+ӂG:ywӷގ2ҭؽ~{` 7țҼsSq'ɞ ԗoYwks~'kվ @twĿ]cXdr|0i/BPjnwGײÉ{OWpbdmboVsb/?}Ӈy<)ϳ$;DE}:='֙dg+ٸ!}!8666}xc,bks߳S^8 #93_vu-i~u̘_Ix* ? yQ^}}*xqq&.G,>/_EAߵ{}<-k4>ʈOӾ}[<=IHL䫯cv|-ر^V l; /aӆJ P帓!4|Ȱm,k@ `3e%YƵ 1QoYRN #t/{K[=MV6-2mf%9Di:˂Cu3zJcfWRDm~[^ʹ Rg,,<:b3hCW..!s_FÏ5 % )gs#J8 ߿.?_7lqx ǎcޜf?z{>u}3/ɦ?6B1DCq!X~}JޠQ}01/FGN;ks}N@PS2g̟3S'Mx?6oKԩC=/z?9fp?КMZ᷍J+)BC[ XFoaL ӗ@0})~ r e~*KK54G]51o4#5ZZ)/7BMW.DV.p@t;8>Zun*cWJq]g74Ӈʬ`%Y/81?]][qYѩcBp7YKnoo:(*m>ۧ蘗۵}E-*e^&̟;\F A*:q",}Gwpq򹭟fj$~nD{y{O )P.oB۞؁`m^AjSR[|  qX޳EݎWۨ,4Tٸz$ҼU_ΙR|12oH~qpL)nܓ߲`r?[_`WKv2c ̚|wLt eXXi)ﱆKw?S.S"c^9Tl|b?$Ŵg ԾQ -sgN L,,PTA&.Bi(G󎡲x_}!NàKmͳl6] jvkL|bx8{[VrwABFߋ[[uV ᵩx֝HbлEVaXZ9?T:/)UĠWkot ,(c 3s{zlD* T*'[[Iu_ UWU\S(u!BiTg+^5$$4/f(IsꅚxGV1.} 5[{^x{]-+.}16VYAF.{VU=i_YD--Is+Je6mO%h2:蜂Z" gkhrc^P^"ٵ qq\kxci%oAdefp|8 Wlަɴ_Ν*ʝ1턝owT2=틡1;BTYHAA(1J>B$T}*RBaR(U*TJzAdsBE%B([A#wwAAA> X]8 DGAsB7% TNAE$S  C TjA}а9j(*\VGѶ_WI  TL"AA"kkB!AA(}" "JY AAL1$  "D AAF2'  B")>Zս=59QK*D Y V㒞ʭTA "z:~Vs1*4ـWwK,7=ȥѤD ԗk~߲,5wxwy+Ƌ+D$řg.`휍8GBZ-[we/+ +Ũ+[R;M4 4+T.o -1vXؾ};… xyyѼysjuƌCD(␑%KYa#.EammEsP *J-mւ_/oA<ڂMpI_ȟ6`kkg֗P̎Vl3N`޼Zy+Ɓ2z})۲kX~S9~ $+xnŰyn:1'8vVVV)))j}h(ٟMg/z*>>>5 |b[bDG“O a҄fGnJڵk9{,tRƏʕ+Msy6o̙3g7(233y쉧iP>|RQkzU!H*||X`Ƽ̏kW /hmyW84lЀMԓ6N^=quq`%,[`N<_щ~}{c.>593g$$1L43gΤ z2BVB`߾}fG7;;; /Q˛nlIn]ޭQڟK <<kkktȬpw[oU,Xhjժ민p!I{ġNFxzo`M%({8m[2 6 J# a3CQk4}]pX[YlܼX[Y7LN+/Z4 '4ײ'014Wk++,,,Ar" -^j~dgNͱ|6S,Zϙ9 &Es,--93YúR!C9r$ΝCɨQ~gΜaϞ==Z*_yab|"2K9rp/}+Odg/Xu!% ?gμ_Kfs޽'҅f}6 m EԅH̘9՟"Adr)~{vEZP{`Y>=:ߩ,Z΢96drk g'G~߲LYW0Omc_[V%88HmiͩyS;qn=UO:ԨYMZpMvth޼y4nܘz{{{H>}.Uoccc#\9"vŴn+KK{n}lƧ<@(V|f/-/QWЯO$EsjyʄLJƔ?d#0 !>{NeO%0ȹ 9μ2}+h%ѭS;]bM,_!ѭS^eZ``|jW$( n@@,--D ,\{dgKvv6gN\&aƌ̘1Cm4lذ@Ǐs1VU }wqv&55Ulx8ڵ5JӾ][΄-Q= ]{}y :vf_k2B$m;vrMzFqؿعKs$;A?C.dmPp Q>B*V˚ؗG^gϱ\ >Ͼ?V_!Gt5s{ҿo#?p͚-%K0dȐ{=&OlHP_ϟb-/1Y;f۶tڃ 7y2_vUn]ROF(&&N/?)U*ϛͰge8%G0XU_pW>RRStN3INaڜhR]s"4^^ٍ~=}-s?wO(^,F<5^}C/ۓa4 ɓ=i2;Eo0M"666#Ge] .O0ydz*fڵk;X8@dd$|8NNNn݊Qw})STU*/xcx#"R3%¨=i2G'+KcǙ0ƌU4O<5w&55vދ_F~o={tru BESR!ZfGSV`ŚyEBbm{;; 5xo o"Q[?`Rddfcڵ*`k+-[4NrJ+Tn  Flώγ# 喝kۆ_^w/!Cm۶I%3fi7xvh`>tҫ\zھ}5^Fbܺ{wʪm[rU,[JEhJ%Mw辕<d:kEFFChVuK_jsLc Ŀw3ށ'0yink##WJӻW/šSǎtc]"TP)Kgd'[F;wLXgdffѿW7:7^}8Y0Ny׎mu%_֋*0~k!is a^{Aja .sevG^m<8޾ٱE֪%J,+J3D * ) IDATRےRK~`r4lmIӐFt`p%:~yi7_{QW81ϗ}[Z͎yZ]`{;|>- 1Owڵ 'Ate/oϟD>ޞ<آ)荛>ʼnP(jNs9KĬr5׆Hvm=DaRBc+УB8wqpv-]A|M9A4oӥZ?)>7ϚXY`ae]-ʬ E\+EnYKKkhK@VVNPnJ_o_ _A\8@0 ٗ!A;q7YZ2!9KPg  ,A)Q 9vRQ]z!A"AA≢Rʈ[ n,BeC"AAD(&D[ D5A)!AA"#D  HR|AaA$ Pb4'I.D  RK?/ AA('1hŒۂPV(A$BA(7\ BRT$pPi#H*)ܽ|$Bʭ9 tʜ5R}D @0:8I0rFM_Ee 5<< A4p —ʚAA_Y/ 2u#跇1x`Ξ=APE͚58p | ;zEwju_QF,,,Jo`ieMF#H0IN@zݺ.b<+:3uGcX:V++ _^zyf#A{nԩî]ю;իWh8w'N䥗^bʕ;"$A T:΄Gn&NEp'9'G0C6 )>:K!rҒZ>>_ }7^{Ef󖿘>s6C4a~$"2C!#=F+/2x#3g#YT*,_ JL7n|@XXnnn1?(SQ-,,Xx1s!**ڵk;0b#?˖-c\|:u0~xy#7k,͛Gtt4ZVݜBe_;lRvl7>cӺd[(ߟ^"_ 6qKMNBeaؤ?W.SXXX0aW;w٬̙9 lc#agÙ1s>͈Fѽ{7N;̥ l~ۨoݶ'{S&qY4:4ҥKRSSHHHի~ l+mTҼVv|P~" KKHOBpy`lsetћw&M+Gǜ66EsjYMseW;;;Zlݻݻ7{]vXZZҮ];v#<GPPvvv|h4Ο?τ ѣ=O?嫯iӦl2ZlԩS:… iٲ%Zb|G 4? Һukڴi… y'"ANq3k$ yFYv=؍ ڵgJ?:d8JU'N5\t7g=1>ݻ?2˾SaT*:kK#3| QWWaC4 c/Yw;lu~gLV/W䒛*EʍWэKspQN[>@0;(JY. RDEņ{K>{bQcQ$&hy-4 "EzY03lx~5i9{Nf8u_uC^hNlGʯ2c FΝqt/_F۶ymڴa?]tw-w^ݻpQ^;oժBBB'OkӦ =zĻVJ(>*OGE׿CO@t3³3~ڰiirO=X6bPqX`9wq#0wkvoŁ_7`_y6 ybPqxv޻zw;)/nhָ!dս <~NEY1n i(RqIqmt\P8Q2}{5K'N?7XF4l5jU;ZЏC("IUcSQ2=F͚yNN? AP|CL{F#&=gŲ%8opsuAPyi K.m۶x"C ibrn݂T*Ŏ;lONNLvjZVVNZVy$̨?3AbQͮv+S}756|add5\1ip>/L8}FQ)T1EmYǃסcѢyH`b"7F돿gѢyZhx⚜n=Ʒbڔx~߷lCЭ{ODsx9֯G0Μ=AA؛Wؾe3~ٹc4)z ?OF ࿧hL۠~}L0؎`lX/ʿWu"==?Fhh(;QF"##{xzz*Modd///9rHII)=7Ɖ'tʕ+˗/ue!88'88_|~ӠJ*dATADbbT!j{1ѹt9_$iC?o3/޵u?ËWo{!ѦeiΟx %|zW 140];`s۴1-?n e.066FX l9M? hvGjt!:M{as^ϣ"5~@ddN_ 7&g3d =~iiiHKKC+8d8gࡸx)iiid7W6|ڔI5g._YYx&L3ܹsg,YZh 6e˖pssC۶m lB-K.Ŝ9spAd2d2?ݻw/Rɓ'֭[͛71yd̜9 2e &O7oL:UիWǥKH:&=bW*>ƣƸ[هĤd,;N01 ;;И69%CFO+(9SxbAxMK/0G,wR{L9998 ,3Xd!_4Ø/b4kMWw'sKH?D"a_:ճwu+? ֮߀g!''M{a҄ql#6n;w!HӼѹSGde)hrxR3gLY]t>}~]oӦ .]gԨQ?>ƌSh[q!,_GFNN5k/?}t :v{, :2 Æ Chh(PA+WĈ#\i ADF=qCQ(MݾVclrͪ`϶07SIDLba*UZ@(%ܬJ%,7N9!z;jmk{{'$$G8G5{{yUV0)222ȹبpPmhc ګ՗]՗]'z衴#?sLBDUcǎwS'Zn i5cbرE!C`Ȑ!GAZFzJ: 9%Ui8w,EΞc\999JW]\yG-^ !/_Yo/SKt{wEϯ:H[YZHqaWjXr &1DA {wy|&RRePdgūXfvԳiؾk?SR&OAxn )0z؀^ؽ.^ g^c,X3|`o1=itq|0Oۣ+~{Woaz~&5\R {<U~I.sl`_K>{Nm8B)9c"y>6>mNQv_pcw7 ggg<~W. 2220|pر~~~j~:Nyq '''4kLtP/⧬P * (CNsN8},v 'wm+W:vRg>r :vkMķ .>}G㦾pt~ػwvĀ b.,?#W۷f͚0669`)>cOl\]Sv7c!kĮ]⊝ʕ+ö Zh1D=AH;u沇PԮUwnme4i_#O|ծ;wӓDh׮]ΛʅRpssc}RT8&;nɁԹFԬY3z~2GazS8r]E+7Q[[Iw9=޼ 3ko1xT7"/W1nBt-<lBRr2ݜ 5aU vrʨꌀip-pʜ: мШa"S'nܼŻ&}ЧOS}W#\twmoE׮]ѵkWq ADDiSR% = i㆘5y4,}F|PObr* o:i{!q}lߵz}}hW(}`)=c:\]]sL!PO " TӺE3:`X"wễ066;nw#jdТbH[mmQSH mZ€!}8R 4ƍ!ȟA*T[-떩qv dff]X8~ܾnW=-TԷ;6B@PCd4 *| IDATlIkhSPŝyz:>xGjtֵ+ {c\@QhfO`j=Ė_##.>:;|6F"?ޏ`WC$ԒldfdX"AfFB|M~N8x##CԯΝF7PEYJr;Kn } =q%t+h3yo % AT[/IsOM4UiӶ·ArBh_./D-__I?4GA5o?DHdf"46|:% M# ʄ(EЗoE+A~QA咊4[۾DAP HQa:U9Rc"4} (+" ʥ(HI AD" ʭ(" A1'  ADAA'.:Aup"ADAA%%ˇwPF-DAAQ$º*L-1{GgD "  ($fVHMг{.:> "  ($ qVdQCڽvwjRJhA;3b©!!-5Uh\9޿~&Ꞑ "JhAD< D+FF00w333qV;q>D|7oïeRɭ"B_vvrŊ"MrD$XH7=$ $~aA4{$\zMaaّkGީ'PܸtKq*U*C_TAD'44 C 7ZEll,/ξqS_8@S_?;o˗8xk{ԸhMLD8ylXP=~6 vذn B߼ęNX6ιaXp޽z׮xeF`cC_Jr;Kn }2#XSMa3tsp4i[iS\.G#o<ЩW?wr(]x aTM4PFR| L,`,1]?zG۶mԻ ԯ&M`șU>Xjի^A]@ׯz`ԱJ߼v"jתUݧ33=DvRgpOL$By~rNը|Yt[ԪXmzkZ$֟&~9Vvի: $f6f%`-F2d9(BƦWv.Kσ 6Fy,^8cHLNRExcld`lY O՞ai*VfHK!M"z2e0(KǭgD6>si/&-La=k|l STuZoC4c B@FFsC%se2$ /x&&&HlZe1PV[OΗظޅbEqRRR ?y xipݿ&к m;A@__K>{=Ci+BBߩ+w$bx1ZT[G͚s1ČӰ8 B߄_ViΞ9N;kgfc"wywOiD!>DS m,Q(ye JZX %10L+8$zV+/3gW$FPϼt2V10bHk>Blhh&*Cտ0v$o?999:*˖_|AAh2L8S'ODŐAi3p@NN? Uʩ\FWQjEVTVy5,DyE배 SsK{Gg=sFcUXG-d 2vt11K/>%rETcfSPX1efc,'DJr gȉX:pzV2cq12eۈ'O,*/ҧvHic*Vy┱AXOms6LNѪ222N2;w{MYxEIL΃:y"Qre W7n]@1ixc;6?NBoHQiQWU9b-KU]Ҧ DFR:,=aFh?.9v:7,A*Vf*G36;r -IƎH1cΙOaső6p)-)/mZ7M8.$9['ƎwyBeLnZ`d>Uճ0Y؎ #u߅bi,2TG&1jk8(R ,F>Kt b+\:)`l\6E(̜̔v҅o0fZXaD=T2ftEUE8H̛fܩL83fLY Naۙ8F2%UIYa6S $ =++K㺕UwPnڀ)f`ي:8`q`ޫHNJƷ# *: 7f-߉nÆq]H$4o~xAig.sƎ_wbƬ_}׮akkaA&2i"nݐEKJ0g,^y²t"0QQER|޷sR| ڋ5 AFG~8~PnN`- QqEHܻDְ.0jlm ـ m =1g P*te0SbJ,!_i+S`miF`zr LEaĴ uR[Ϣgh9;0 ?~ridʦQKM`፽ʥ#坏>#!ѡl"*6ڢmӶn݊4IeߠgCiXJR|4h q7TW=]<> 3tSи ;W?ΈFjs.f-QD5K/Pfr fOL6n='cLzf)gQ6pG xfUUČBDꩬVIS[( k#077gϕOIOOIe 佷"׿<0? Qlldkf({B pAˆ"eӯ<K?y/Fe:HԬ S^M wf̜`!mL #RZXOi|QdCefP#X1TcSD%i*}pXy]C#'՟ MXUGlT8̭l17/V. |!H>v/Ѣn 3d#!,pF/TuaiKv?wGKu5O %u?/ܐf&WO"ij/m LSiYO]gMpGDyffB3꺘8,C]=+z 'cC'h#* b_E 3­N6Rv9 iZ"xrYёDSɟ>3vA?kW 3 [wZ>)gJEbNR~j{nhhX ^I}YbAEVU!(`9`1º*-m:,jUINLN Mto^GyYbr y k9ةicdV`in0 HKQY Rga3AAy")ݍfSrUӨI7I__l;z꾝5ja HMM/h.qGhۡ3=z31q4׆g}/nݦ&<Ե5 L9=^gAFF%Y.mYi>BBP?@XS_?z{GDEE^z~0 -<>kM <몮lDQU^BBB gB^x/^~w .]Bzz:pT^]/>K.UX-枈mWeÇh֬{nllxך5k67n-OƦUfRk7pbݺ11Xf7AC\:g˾[K=\:߫cx gљ֬Crr ߾+p-" "2*]ͫVYdž]= ;7#"2@gaXz%ƎY ;53gallW\Eþ1<{<tYikgΞØQ#q9VDDG+011Ο UQL m@%(rssɽR)yԩr9K.i)߻w/*U#Fڵk.Æ pBON`cc˗SNxY)=toO\~3f̀B@˖--[ƍ044D~xHf‘#GpQ_򋫫 ǘQQh:7077999ijTPdm簾P(:8;껸8S_bbbʞ"&&ZǏp!~ځQCqZbd}.~޾[@.pm,nB>BZZۏ)J D Ν;Xz5j֬uZD>}o}B".333L:[;^xy)=so޽{ׯ_SN-[b׮]hٲ%sx=z .`ĉV044d7'$?pۉwV o@P|ClTSبhooDښ/nhhly%44Le9'񓧰evqLLLQ;wW#XYYaenԩ]]9fF7xtb"˧jg)AN>}`nn˗/#99 1=zݻwpܻw_umEjj*OiӦQ; h޼9ׯ 6jyO5ݛcذalZ ͛7Ppŋ1uTXs%ONvC[խ-~\.Gddf͞[ %8,X}z͈a>k޽ B0zۨػg,Zq񈋏׸"ak_Eѻg6|~`""#;9:}lܼE=qs ڵi hצ56nD70H`b"AX{̘b&ADDQFzY&BCC_ZL5bػw/FQd*U+++lٲvv?bȑ!Gc5ݛ[nBxx8޿4j]tQ-::;v EHdfCZ;fk3pn{_q|7E6Uml0/`'§y3;.0vDtEQEq^lUAв?4!S!ښ˂yfoo?xA a̞9ujBvѤ͈R87:6*-;$''AԶMk$';6ΦcepqY)l}_ҹH2~ar9ʢW)}zubG*Uccc_( 2ؗԚ"!!&&&zAN'Tb s]̽oF@@֮]&M@&F噚ر#޽{WzQs>&{fdcタjNꬶ.]+ <wn^-~ZDWATN:6mvvv?>߿1ݐ!COۇʖ}J@yl'e#s]{? ..\r9-[UVяL)<ُ [kpR$&%,Zݺv&",$}vXx56lAiL7bٳGN9R~C'Oxlmmna\Qۉ(=;v IIIr HHH'VZkHd:pqqAsVh++K̝3(Д9CS }FFDŁAAA|AAA$   HAAA "  (RAQINSz0[%ǟto$ תOFhAAej``:|OO "  |5;;[eV.3gý'k{b94ëׯQwtATT4WhƊYpQ N@jj*[ EvRgس7xyѥvGn_4{mL6l&1q4׆g}/nݦ&'k{YY ,Z mb $/;U?nguQN9_n/\ ,&Mtѥ}?IAA3sKVQz[)߯EdT4n]WZ066sA+Wc{ !.ƳGabbWn IDATe߭s=\:߫cx g_vW.ޭkkֳal\fSpu\7n?iovx. ޼y=a;zJbccm̟;cOBLL ܽs`ђem{'MEY}'Ɲ;wWK\:w[/+Q8^Yq~ jkL 2|3OML`h,QGlD8FMpߨYF 8x0vl߂_11ho /ok?jyxbbbڿ>ǖHlRvNꌗ ^Q[׮ݽ͛٧?B M6ƩcG xEO^@8_𨩴5Ï۞]jPMdffɵ&ܵfw4٤6nɓƣ[.prtԛm'uWAAbbbYnn{ p]L2 n݆\.{P ՜\Y rԉ!0R055Ba5c ..ZD ؿZ1$cc\d&۳\Фy 9{N/ "  %!,,[hhFLLLQ;wW#XYYaenԩ] I(Cj?cDbµghh\Ξ'$h]n=޿{F{{;'tbOa*9y0<-۶߀5}I֬TNDAAE$';[Qz-All,bcc1bك oѮMk@6qs Z?ߌݻP( ڞֽ'ZԺ.>͛eh탪660Kf̬ 6nݤ1 ɟt3Pv-iMzJp8x0oXvd&uߎ{m,[۷MrNT011Azz:@PАwnnnT67LY<u泴` GՎ]vתT o[SRRuUeB mN+W6T CCC2222 H`ffd51UP(xh 2LmP;騝k>ؤ@XQPyB٦ EW8x8ܼZڊMp!5 AT\n O]xIQZfaaSSS0yiIQVa #tK1ktdfdbђֵ3Qn AD[Ɉwt g>1Os##J &`jj \777La8Ӗkr7bdd^^ÜSamR^.%fa000}~C"X]UzMy dTMv*N,Qo+gdK玘;gV " 0W,;B)b MF@JJ RRRx"k73|^c-ҫSPVؤ,}aF(L0y0S566I$4I]b#վ HWlddvpVOxа@('V?~!\ ;*ۉvEI]zm:u1:D"a\6Q;A "B__]US3ժ$T=Vn)))T>!aBĚ6+SVVV:ιӭνƍ t/MUɴXՕCTpt:ѣlxff&&O-۶ "x0pG- eiUm 꼴`f:5تlmeSP(rRg):??)+SEnƦUf斅r1n]ǘ^ <3 ?GP ,c'NٳN?;w uy)BBi<{t&&&X*稇ek[.`|֬c׮ϞݛY 0]cGw4 ^?''kL5 [:ޭk>K SEҩ#TeKl[iZdVf9UUSSS!ɐ +++A²2h~xvm\U(4t66g;VX;;;aՊe8|h~g/zIQ|p{,2Z]<1%Q<]q qhU]ƂA&LteCO%OxbJ .cbnZpqx6|Ϯ_pb0wB-p9Qaڢ.Ȩ(ln ^i}Xnnɿo?…liF ;l5w7Տcx>% 2GP1;@qpvvp)Ue0SeFtȐ 377Gjj*lmmǻ| ۋNml[''#~mCyԯ__ H$u6mKT {waoodž3˗.Fv`aw^ۓ jFnn.wL'!4B.G/rVCj8pt?E='.vaΡZ5ã'F`mmIƫGhA_jZ5{^aaARO m3i-`2>T֏΅ik޽ B0zĥW1"66-F=aEDRR2.^K舓GqM6hKMՓm ":}ʶ~r>',^Il`6ڴ#dM#c+w;l333*/OP$1&+MbD{-\b)ʽڠv6t(23Vw4omڣ`^,6lӏp2FЬYS^n]:aķ^V„la-9}=ѭ{Ok)'§y3;.0vDtօ9?qY0/o?H?7C3gNZhӮ#4E !:ѿqa߰Qi9|G Rf 4_k_ҹH2"r9ʢW)}zՆ\]fZNORS( E+2zhΙO)d+S/FX1gM*tzalҔ> @T;?iO2իW8q"Zc_/B?ݸqCt~M4Qw*Sq.ظ0+LN\lOZCDaGOI~rѨPi] ʞ oԇ+Nֶ@*3==III尰6q맪NO'aMĴ: m~f _Q۩8` #'Bo5A?!,zn]Pjg4aOq}_ا­Ō)XDDV@bFSL\F &a])Nڌ?Ɵ?~'C?i.ډ B] !eӤꕽhQٮixDm[)+[[[pM988[ \d2ʊdKTwQ??印h:100`mUCw额 zCʈueUӟ-S0e<a("ӵmA$ ة;]q&vcq DLϜ<'`hh(a Zx\{W 11}s&m2mC_{Ra*:A։Ku.㡛ۖ~" (8/3?A ZB؊剷:iOڞ-HcC=y!m# tEċ;fc!JK IUl](yf4JkYr64~6>7l~2ꚤLdV?rrȞSUdC2,_?Hfvd墟 !"bڐTa85~S<%uq$юYL&vdV?9aY@rhLmA JMYI9=]CGYcL<1qv甮~:fs])TaeݞKevd墟 !"i% җ0+gB/{(;؎-tN@Hńf!s NT2ɬ~,Ccc,ٓ={g^Kt<*,Pg x6kߏɮT@AAv P2b)w @ f6OV?TLG;ylcHӝynA9DA@_[=g |CHAMs\d&X,93sD&ݻ7Y?'!{m˶ !""/:83ˬ񸺧\>t j !SIWߊldlSfNQ~6:+==ّgŞ-DAAAlSr6 e#i~m<׾ˇTit ӶSշ"36뛝'S~ %{#ϊ=i[. " X|H&Mԩvۚ1JU?x*$<}Wezt:5x\[4weYNcMzlcE+̎SNНl Øb휓=Ն! kz6Ve9A6Us"{{2:E>!c<'ڕE?Mw*kٞu\x陙b w|gJ*АSDQyf܇_ɨ 4?y2N9 _?k~3ث,$Xl6spIU?O&ݳ;w1YEXbp 4el˸>9D1PCaQNrd5c&0c|P3tF%U['zy1׫U¶k^Z_ߗdOcOk?> ;aٹڑ4ørO(A*(>̚%&^}75t +F2x1 A=wM[r5$ J,Y"Oq{C422_ÝUu),CDI2nHY,KMJqp8B}z'*4Lȍ=) X`hS+kq 2; *ǣ@}}W\6sω%{0 ;w2(-9Z[QQ_P96xǮp:Go ӄ]O>pÁ8.db_o~vv2(g Jrs g츽z 8ToS8 yb?.u(C n׎-Y,׿83q^!#NaC.>s(*+d,J)^[n<@KH]9u_}OnY?- 7yq|x}l2W^wCgtqmcK e^zm=p0k IDAT{?*k&vq$grc޾1U'u~nH[oo?c Xw :$izzx_~[G~Չ eS"vtBN4D&3<< QB\w}BTC>KvBdY, cvj 7L&q(-- N iSs"{ʽ=cIR6y\S:*k'ύ3 ڏV[Cz|0U+2q Yӛn7ϭЯ[%H ˗)zW6~8p3Fhl a<3r2C%vc Xv׉v,Y,l=۴g/fAK`DRhpgyp=ᄙbrq88k/Ձq0 8ށY.uatt&?iY+2z9" "``` 1*np=)d'#W':dkV㣏gPKWݏ!{#?]#׿sؾM^tw;!j,8<#6ǞN@d*/m.y2vO|KTY'?⚟zqwɥ>z*OG)x[YY﫣?R"N!"B#Yj\c][rƅґ<3+}c tmM4^]E-v___(DeeeI_GoS h%8g<كݶ: Zr5PQ<{<?|x獮Qn+9F3tn![__S3 MM2+k47J+5me+~]$agLJ[Ol1#~6fԙt嬼C 5(q`l1~bBbp\BIkpp0!t.پ4f5OwNdOtj:7k}br dz7J{fPfTcEtt8 x$o$u%\e.ddz{َ1~ ʕ#}=::c^τf״'1XT]ۙ:S(jO@Otv:0:j>WE]c068Nl|vHdsΙhhˢqgfQxn[W?p\ɔ^/HQ483+Id?s|ο]2㌯ ZV=;E0pX.oV6o [kGYhh;pr)IxSN]]#/Fy^ՙ n\.I:Kl˲UdM(='ۓQgډsͅ=䣟Rn ϋb!|NQG#mo o$=[m]}0{6\1+g ݳgڑuqqbAO"QRIzzgwY{k~o$Ad'Ugu2G1zHLOS-6gL(|Hw-Vj֞YATTT$ *U", Nln7lpd~&Jf> baklZU9Kn3f4-k$:NYF{CDD}gHTaUB#>?-fsڨў!$3Feeeg&cLdO)klT3T2'(N3- +ea,f(5Uu EKKB;a1G!jJmJv~dOoO1 chO,8p11%۾?"JM AIqurɧTiw_i[L*w߾} ZZZ &ܷoѨVWEn98Io\~&JdAETq!""@V?VCwfՍ"C?3.f3xU$ ,&VY!n7000*hoMZEQ0iSvdOiOFk.!DDqW e^ߔl]=!9DA`8XI*c%xuYa MSwu6wAj:udpp>/6 u"{ʯ=Msv!' )> f !#LǾ1f#WOM~SlIqH%r\[/W[mrNdO'c&d6Mf?ACDĤb|dQ}l*gt$;L,j3:FVڪRgy?!ZNTVVjI~D ?5t8p|ɞ&Ǟ6S{2:Vժ=mMצ| Mɿ_ŴD׃S^'rq0WC{#vQ̒ 9'a91} {PQRMsش4%i<02 XMY/t;Oΐ^ z됌O'3^;VdV߬tM aCf эg '7fMV=֞L,؇ښ$?2'38b0sLՐ%tuIF~~A~u`?f[r/:g63EdlcٶXiI?סV3V꧓Ҧɾ[RcOKQvK?V/to1+[ਵkQRZj/,'\sa+V_P._;DALS ,KIYZ G3KZYoEfmJW)wdtNss ̴M|o+ދp8{o? D n&|I+"yx& !pɯY}ׇͤ*gV&Y|PM'-80(++< w gdeզdɞ&ǞR V,9]:DQ? O>L'~ǝxλ ^{-֮]R]^{-.gaOwơKHX,>p?]Ooƃp_~2qq' ,\ 7-oǗN8uUxɧ2nK/>:O?4~_s>9<ذaÔ4#E%;n6ʇ9C܌.tuu!Ep $|ֿAaHI-O''6Wi޽JZmRdauid7~vz;w}?.<57|'pB±?oðydbl&ėO<r9w,m}ns+mph)';q?ʼ?p_kcO ^=VUf̘1k679D1MѯH f2y-'KXi~}Nu=vIoLMkC܃|λ_>۲:;;QWWptc[]{{ڱل /9|p(aY,_/7y7~qϱ|R,Ɔܵv<Ƅ2oG= %%%897sg .ݻ駟 /D0rכF1 j(5qfY(>Ô1dP˙U򗿐=̞P3k1CXd9FdNf?YUp);~% v 'Vq8N'p҉'Xh!]/r8l2=HlۆcO2`ttT{gh>ܾG&\^;]w/ MMMK/M" 2!{ :o&p($=p8سgo2jkkёpt}鍛pϧCn:l|7=/j߿;?چftw'؊6[ fp뭷(⣏>1)w!"i:/~7K?)NUxܬ\>t 8.SdCefhV[iMp߽xg_y/JFr?pO8 /#_9wwŖWSO2]db\KNj3oSm/[]zAǙg9wQ?z}G,~h#Yf\?y + Z/]q~>t;O쩐dmMgULW]~%~aC_=/~9̞5 8J_3<|0VZz 7x#}Ym:]x+36aGvspw//(l'fj~ ߹p?{[q'{VD{[;npG:"R: ?OpBaW^9wQ;DVՙPbtbyt{tԵ~ϗɚF=M=i:'Vjt<2هH_cMA\K0\{Op޷/_.!}:8y睸⋱w^̝;w}7V\I7Mmq޹X]s.px(--Vч#ÿm7+p.ʜx$?Fڹ WdwY߯[{.>S4443 /d\o 'i8pUZxm IVN_"\P˙'AT({;Ezwޱ,#L餔b͖s1`a۲q UUU~}XcSY}xٍ)˜zʗq)\t=<̄|iADp7jA=M&<ؙi-Ȼ\tvvOgt"|돛'?"gt,S1S٩@S6$0ɦ/tT6t܋zbAYb\cjv0]_6U9q1\>t:OPdmr qV3V%Kz;0lC]83r شi0DQĖ-[pꩧjwecv|׮]صkW±?0ahII BXՎ\۶m[)|xW "O5VgQ Q.:~M7zu*Ds1 q8ZDWd\]}WIWN 3ˇ#ox'q9,_>˗/s=O<&+㬳3!Saɘzbl+Om6ٓ5A9DALU?(Ӈ$!Dʙ3χd5G}8O~ro~x'& =c7{'q_8cMTA 7܀o9c=C9 à?=֞}$ըNbFөoT VnldYI{S{wdK .jKm8ζnM?U zdt-c<HGGPkP#6؊9K0,E-Xr!~d`XQy³FXvp=/!ȌItR@@*HgUdH.ӟ?)BMWs088~?QZ*ئML=֞xGq*l-d3ٕ @g> z ,TJŗHYΖ"_ޱ:ooaP-WNcXP`Fz2\ehiðp=sD!fy> 6s< Q 3" 1̙Q ?S(j IDATdnns[0::P9;cX~f ҇"% ;2 LΓ {*=7gY@eڗR.cp8l3-;8,AFN3ad9m9 aX AoFM|98,E18qKqF]Gr.J93R,C$p< g]ן)~c е7 }3FpL1GA"W\)v %2^ 8qъȲ C, Ts!ъ4+~Ȇ( nVɆи"m-1QbenA"(p$7xwrA%-Px}5]r,H 3f@ki* Ȟ&> vn=yl[>A-EuoIq"R`P:ٕW "SJ9x zp.l~ +TbVl~#Aܼ ]AQ!G49#*Z T_;lA,L ) ?S #w=A3,[P n *"GTh|5ϪĖ[p %@ \:D;[ ⃐$9{s7Cr߶QQfL+p.D dv.Ᵹ%&ӗ# "B n_sֱnUc[K& , u١drEA"32PU],]Ғ(DTPAL3OlOoS=MU/qA`>tXE=žuXx%˙&kJ+7 }CCC`=ھ=e" "SdAq-1uEQ!pzíy^e-Nk*Wbwa0 Fm,#* 1gn̟ Q#_p( !.>+VrfC)KވP$2dYNHSNR1:s#O}Tvd-į @EE~++)/j[Rn,]x#/oD=#h@\ep0 1FM]h O!7QO%+g;WR̭oݹy8֮X+?; IRG)Hr3" `i{rv~Ȕ& H j!dne xGqY0 8 7_ؽ0rxs6A1F# ǰA8̀6V A Ygr#ٕW, 6| 2 D!@,P[U+c˻$h`qѫ! &A}@mU%Pya7@Ic *0, 鶱e'.`X\ .,-~r(f;[|* {ʧ=ɲ I3m1BVdiS!Ψ^&sH{ e|@bҔ+ "mBm] n mz:,*z}Sy ͈ #Xb1娪AW0XT,G0,|%B "* ˒A)A,~r06Ð3+\>u |S*N[eڳ;KOP0Bw` y$a N2+~Ȇph! `ߞ!jFuEb=.cpxrdPJ_#z5&PY nʬOOw!""!Ȟ&ߞ30,Q>zN꧓M}߱#}Zjex0AAcٕWh ^.w^s 1̭bPUDb8;q>p>?:;pg{;d9Jj=zvO@ eߠ' i>m,fБ<9"{*=!նeJV?LڦBw)ٞP2AȆcҖ+DP󏥽8.A,!ooEG!,_B P >֮Xh4n.Ȳoo Dg!"b@6g]Vʥ{χڔX)Y^甮~:ٴ)TRDXP65muj'+7+Ċ+~B)bF#(rhk|rFBK TĢJ [_O\e=`GCD0ư}L'['mEdHvp )_*N[tZNfm*NFa<_T.yŢ ,?K^Ps/׎Tծ2^C[^0<30xdeTSf3D:wv|}{9%.ĢBg CD"j\ЇSY19455Mnꦞ6VlX];WVSScMVd[eѢES2iS. J iT9N4VAH>]˱#ؒWh EX.tvm-^=Q?WamVb*'+Oǎ揱lA5\e ala%ʓb IR90vHviؕW` =At Ϗ9KfU܍n6E`Xd(唿hݢS0ںĢшf3Bbb ; }R6weuđf cgZV?#QZZj~:v۔JQ*)dŹnu", t""58j8ZrvZ?Ad_ںFp |98^V[W^(sXP?pg%.ck|>;|-QB)kDAͣǻ " 4'AY7,(#:d<&08Ou,YL:[9N6R?M~?%=v_sat#"c?M9 &kxT:;o^(bRc34!ʀjn;>ކ'_ڎ}1';_4, (Hl!"B#"jTSW_fn&Kq<ԧ,qA̬oV>[q\mJFUaCCJV6 өl, H`=Jj m9A?AdOŻPys#UbB;Cq髱rB,?F# e "6 A I' 叡aGyÐl8|Hv)Jn~ֿCXoU6u'~;BÇ:c{3hOpXx\\& 2E6, xdvSH| 4ъm{>DGu]q7::1ĜM-!n+Py C(sAbh \PR9@HSNa Ci$MMPGq7%:)(|e V> h, 儵9f+9} ( h)=:>y fݶB  1YXDABo8j d{+8xQ#Š?3h Hqa~ct3V[iRbVXSpJ`'̦8NmP| -gW^D62 7BUbosƿvvGk7|u0h *y q +aifoըj`*L"flܸ:\s uS^PH4Vg<,@_rvK'l 1mOOvS^JP[W$ 1ɯCn`{ UWb0* W0Sbi5ntPg AQ4(*iN'dv.XYҦIWήB'l aG(xh!8ޅ%s@ [[1Ub> 3fٳqk7| eW]unf?Ɔ 0 ڰrJ`tt/o[zIp:B8!)6ؗ5kpW&; p7 3D"(--dOyz;,;K+WOp Xzk```@lu}|`K^TC(!cSy[Bq}c ðe 2A^ S^+c0*@aQ@8 5jQ" Y j g,۱"{[ԔR[?8~3QÞ={p '֬Y~k֬xصkZZZ4y۷o/K/Ԓ?o]ih_w>lx^Xyy9>lw}y^\}xb2m$"X9!՜ 5+[rvZ?Ad2F@Owj'((dTW?bGs7Q͗c˻|?Rk{ *l| FBT Ė-zaݺu(++ëH$71Lupc֭hkkC[[N~'pVZoV01\NkW\_t)|%C)BW*z{{]tv좋.³>^6%\2$)}?}$!PfSN'dv.X2;7!M4]9 a$Ϗ9sFtfb>ư`Ɏ-#?U%8u<h!֮PB>) \OAL1gewz455yt;<a͚5'g/W_}H$"8r\ 7nDrmo 5؀$(M(4Q1ӦO3܈UB{bhہ${*c]2.jA $pJޱLȏ%J!ߐ/bH "Z[ryEY /p 'r(++G?QN+O:/_.8gᤓN__礓N Q'g?/~ /gh3ϗΒ%KYdɀTWWom| =st4#b1cύ,((JG 뫦c=f1?TF.0jH !ML\Wsp/`"O![BhS-M\70uy#Щ6TEs^R#M I)5Kv .lrE Lz4YfپorG, ())S^ww> F端q=csfz}ŊXb|GP&7 Jyk+*RJ}rmo ٽ&OYLw,mZn WS/=@H)IUpvdʊ'܉W.⊄K H0X!@0Q|zJF@N:o Ah+(J㎖]nQKS]G Wgw !)jShB{\$9NU%e"V@  4ե +2Kn7jiQjFi|ccN |` hw(-jlR}QmQ$ɇl%>s"(AdKscǙ%{{kbEmE.PWD&  l | #B_qN7D(N z{ lrTbn‰;Zp˵/ cfV@Dhi=ZjnV*AAUô[hn܊JC<؂O=q$Tƺb3nƍ0C$ :;)'F=ڽ稧"h)k:}k{C-_ K*Q`KZ$fOVgw*QEwLd\Ԟ.KR"JMvq A4RG$IrE!3Λ˪wޥ8nfg?JE shfnp8 D 4IԢ(8e:/g0%hNW.C%J S+{DQzд%kK6#8⨩xe`j.)+R`zBنNpFs`tk1M{1K{A(A8Dr@K8(eT ԢBDO@ PXQ'Zs#\i<_ +0j{3#\m< gU #줠%gF1xWS Ϙ|,u%C`C!@0 1{rŗ0n|%E%|+1o.Ǹ/}ڭ۲~}LĿ^^죎/fQGҊWRۘƙlڼ%ۘ|_ySN"E%%^ƞ?B싸s'NƘ|u?欳DiX&~7C8D@ G1|9Y~=---q<裌1͐7qUUQUO>#:K_kXl`e˖q5ڶ}vN8D~饌7j9OUUspBvEmm-3g /}_v7Gs s纸??\V߯dcs=o~[׳rJVΰ_\|Ŝ|\~vy<hF{-dO?p8$Iԫ[ZRQC1;+vʥzU-=j,3KNzVhdi n'gz,CupH1(bȗeٸΌHkmg?>zzzʆٳg뮻ɓ'kjg̙Yj*~ayG?m<̚5+EQ|AN:$&اߏl?ӧOOW7pC}|י>}:&LCQ\\TU5f'C`kȆc5@pi/$4zJyGٱc[laĉ\xᅽ˘1tuuYd̘1)SUV^z%M477[onnNVUD"M2e rzµ^˕W^9S`l?\yu]i?7wMII %%%,Y_|Q8D`hs;ǓϦ\}dl%Ϩ'ɳ>G}qu8eF5@T"/3J>}|>|ٱO>CBOBOCIYY-?4lb9o˖-?~Λ7/ŀ{7o^ʹyyy԰|r:"HN|>7x#3x `}n}e7b H 8LLJC٧X,f1h;j=*^rLU|lm姛y{?ȷgr?ROpg[oijj?eoE]_'|bd[p!_3uH4…fq5C48P"7ZfUƣ.c/d9Yf^uY62 aY` $4zꋫoR9֮]O?mٳgs'x89ꨣXhѠa޼y+{@̫3VrLNK2J C f#ucҰ=$BY˗ͫcXZBOBOC'@ @ اNy]X<6el̥OɎl pkW"bvh$TU9SD_X|s{ն\p򅞄BO@ "@O5<.c}fٸR$Jf#rcS7!Fv1b#/$4z WT{l\R$I&tYR岦J [R ),_R٨/$4z }N_%,H>'Kc W%zZ=)v R DĠ7cbe"YГPI C$)$=<ɏ3qmKΐk"rFcFbDV~l6BOBO@ "@0❢Laic}rl϶ld=q.+E,zd1z5όKjE&zd ʺ6xٵeZL1 nUUM2"a|>np8\1z9(N y拢()(mSVօZ2E '!ѓ@ H w(\TwOi;ٴKtvk;^KEZ] ,5W$IBQD-pSei6>!NC~܈J5cSO@0!sl@ae476Ӵ1U.4? = = @8D`RMNt\Ǽ򒟟oׯK^4ʦOKn?=I IDATUUvSNodaÓ2v(lQUղmFҾߢjX'ԓ@  +I@ 9Nz( l̥ON ˕Fi6TUГI  _v~V@ :vi[t_O>n0% Y}=}ӼYFxQ8bʻה3I,X,Tf\/$4$34Pb'TtpAz.,.S\ %,ӵӆ]$Co%?13-g(Hc6ddZIi4T]PEuk;꪿b[} F-x%ȅ#3YJyj@NpAVUYS #LN-Iڹ%B~ƼmLB$K0`˷F>lzzR=%q.>yEC2ve$V>ͻ!й8x93\7>F!G]~(_fQ}8NrZt<{7[֤wQ:z?w&8N9~+%Wҵk=?oCtn<q^|<{xEؾ7@0HNEmZ?H$HZ=WU\QlR gc\r9s)?Pj̙3tDP^K[66RP6B0ۚzm+;5cRNjFc}"ޟߙ"_Ii(CSi/h8t?~_#cC ]soy rWJ㫌4BiA/Qnqӎ#N -0H8L:2ucp)2;CzH466Dرὔ6(Bҋb6iҴ]Tqʕ+-O*chޱl JJgcl 3^F5_9 ڈR8q9=\r]f&$Iԫ[U}L?r-bv+VڍЎK4wOG86f&oZ=0SfveِgmGB^bQ|!_e bM{}Г~SNKULyɭ]1߻\ Ҍcq^{y^#>vndLQ9n -k/܀ԯNO |HsB{VSƖxte솲* μ:U+h=t ^?P/ Z;[ۅuyM@QyJ[?eLIUw뻏ԝ8A!gzwyp^?D5[0,C:E&Jޜ=Mzq}@ POhM_%BTV7+VƦ5oSO"mF3UElk5xph;>v8a^ƺpTz׍V[*6R1qL :}E:/j 6 $QL&˲?ܛf'SnJWn/>N^S2߸ѭ&ڗuhq]CݴkDoou݃O?ֶy":ușKt~\ Řӵ?po{q^u7c&Π;Jǟ[gl~pX❿[RW %>newdnwh/y=Cr8ȗ IPݵ_ӽy e+;]ϕC$2̵|ɫCJU'7Uc\9t78 Tz2ȸT,O􅨩3zzڟXNv]t{]ާ[~_,9'qty)\]p;iqk^$3ݡF\eʐcisa][?"ӵ'@vo~Nz@Go7`ƔVjnG|_cIWokNO.E8{jWYt+_ \rNίD㷐ͦ."@0 &Q\ݻwCڏCd%<&>k7]q5Kx"PH'P&`W PZBCeX,f|jF4ňUUk ?$Ik#kƧc{zDYKi<h8H$kx $c Ly:8#|Emy$V,k{qRƼlj?=<ݿ݅籏 LGNϣWL_1fU຺g̀$\.%vg sû(ϵOx:׼,`RiTF Npɺ?c:Qii)m;^(WN3 T64l֢ӼK ǩzőzrٔ?h;&^lk<{O}{{qÔ ՜b/M=Vl<ƣ Y!Gp)]+&u]=eٸ BOBO~ްmKp獡sGIt-B urtĉt7۷=0ԍG}v7 ǿ:ϞCy}-g`̴nMk[F}E䛟Hgn|C$3dvt!ف hagR}JWR6ѹmlH"dݛڵ+Wm[H۴i3Z-ohPx"03dYEI"X~pß"v[Teڊ)*Y~ж>K'YcvNj[aĢW&5ko0oK!(JLפ7#_K2z(V8zzj=i!x,1q^8]JCߣ㙟2_㬫|6#OS;޹q8]h+oL!? !qy%oitǣ)GѧN{jt´w z-]z8x\7>FǟMEଫ~ØICLtɟ2;B7f/"*vob}Ȫ-{Iw,BìG<Aɗ$Ƙ]ğby=vsmw FϪ^'rU"= Aaaf<0CZ)Ll%;V_˦= !k7 T5\Vf7{.̸n rB3v)k3XfXjT+e0KF‰Ĥ2Ð;c% ^k\y]id5YLNbC>f YF!ŰS@Q|z j+s?0SO6|&K^s|rn9ӳ3|Bƽ@ӏӲw/LIv|[lpю^ѵ8NXhl5 x?s2gN O~_9DR*t Mtn"uI;ޅC$bg)2z̝94|n1 n| ϊA0P~T$VQQa>d^oJAV\c`3oW%Hoݘ@\A@  *}7׍٩oϰ#]]>*B6zVKFIi0$/csZ MX8+g䙸θ gItLZ2c~ H yvΆZwU=]\ӵ-ʺ}E#;/J =F @ouc\͠l&|=d*o`fbشgUU/$4zË|1YҔ}lͥ=lH$UF!FBUU "i%?61tm9II޶~6k$K-7LFa:S…f% %"aTYÔqdCTPӷzIW1o/$4z×1 H P.LJC'1׍ H ׻]IO+?oWv[ = = 𥫳ήy{ACM1%K$secސ?̜93x<)]jԦ^SBZv.MW1+ +?]@ew.Y35+ @|'Г@ ~Ӵ¢80 9Bcc#vg}|4X\6i ճر=&Πi:=kF>+WhF_=` jS#0\.,.Dn]j0jhNZBΥZ3)񲟍H5@qlmt = = uZ[ 57@ o)o|ȵ_ï^]'i<GOg{,=Cݎ2݄K,#mgS]k T6R1qLe q qJjW#bUuc,? jՀdRa jgEX/$4z)**)?޷C$B ^(/5{>Ow_6f*MT QS[gxxu L? 5XC¡j u0硶!3mTd8ECԟ}MLU[ڼyszVh`uzkk+Z֌m|u৕V܌>ZA~ST=il7Y{ 8iC/8jI ·=K;P0;v:!|$lQ$Cp' Z??yvl܃x*."@Q:˦+J(h8HrY?n Fzr?0$zՋDKstZr|>7.(iv)\f:$V鴾Bz\=dl`D~O[֏:#\5ZTͻLS5Ǥ#gN@vN@[E!9IyE\H7%`lu[UhHˣv RM0=C>m%Z4$z\=O.?d9&nۨ1xq$"`;CvNNV\V+Dz֭~ !sӦMgx?=u,x>YFn#\N2MnQYh٭f m$,Զؗ T~˗3:;;)(pﮢDG.CH' :DjaqP)u/(ճøn#~'m˸({ӝɲl{fvdWSٓ]K9Xux\)k3lltROE󊔤VYS{Ib1ՍdE5x .YJ>XW>lb`i?Cц1NyC$B!d0йB=Wj3/neMߕHbb1$IJ\*v)Sދ9l.k^v3IJfgڟE+,wT UԊs4[lS^z;B |chE@+zxVTcc6}I$}2H)B`IX=I׫[aVagBO83BCFjȒ1N#uC$BgH&SYYi1|2/eCEEEsɯ'zdY&ً;ڻ2T I8m_גm㚣q\SkY;X|jI؞k&4"ڜT^K)Ú1eO;b+rTPvH D bN\:u/3gUQ0MmK[YkI$YOGӘ_¢E;3/wQफsT7ys뭷zjv-ZO?Mss3SN?9v弾$"`nCarU2iVgrי{&3*hIp:M=vyE(ޏ4WٚzGX<ג,Zuwcq9yÍfq\?͏X?׮L} 5e mLjeM#I %jI;eEs)P6b13?ȍw} O3gV^׾5Ə1#0xpwO>~l߾L<[r7SQQGu;Q6_87I$8 cّR6 MBt:iKvrA7 R+,^fٕŧX͗<5\-š*=Y'I])gl|>Xr&Q"72|Ծ/ = x2W]q9]pqgo~$//.Xl~;>βex駅[>w>k{Ph4cݕoR lEwhǙ6m߹򥳍s^zy?=l޴ _o%b㥗W{cƍ-/o.W^{?lܸcHC9Gy,_K0k)œ3_*cS^3$鏓{<]tQ}9CUUb)tz|ԆSWt#If r;ZrZ014c}_yBOXOp\ IDATį早<9|=. iO]?Z:]w%,r>s&soxO;px K/+q)=+.֭p^{M~^nfΘ=[+cXyskn~^˸e;Nْ|ʕ#N@\6?V9vs455r6k,91_ X%io};^[#j{E]ĸq> OF{!\'ۇ GZw7rz[g9p_OHi)*+y[G7≠q9gƏo9VYYɞ={%]{57~| ?1Ď;9Ӎ}?sO10eKO-~.Ng4 ~} pWtR&M֭[馛R&C$~$IH$Ž ᯜFEE!4V4Uwokk/`Dmv0ROi,^ hkk/LƂ%~E]d766RVVOaJU$ha )Ƥ?eW0iPE][=A=Yp8LE wmðZY)ra9xB8+-86n[g?.Eq'ɓGDp$; N8g#Ys Aeuk71*) #I>v83jO2vn 3Ϥ=7Kދ49] S;Cz =wpG5[Y NQ!mI=P=dѝ35^)g(V&Wτ =?=eCcSָqؽ{7'N4ڵqƉ?o拧ʳW|21ȝ?YW;m^}5n'\kXoŦ?_4| \.nnؿoL2?F|щ]فH&FFI1_PIDZfdgh"N-9Uj!8DC\yw^7mt%WٶF̓wv2;CG}y6a1Әx4&[Q_%el y6c5v|O֓~3F~!շzL6^WyI^{~3w\VXa9+0o@霡F NK8W{la&Ljnk=w/[wjJJ? m4'e\wwy_3s ~\vUXvs_ς 6m;7k |5@8[䘣zսA|F5\.N;E kÏZFn!/sî]r齖}DTG?vuuu,Yݻw~W8D`1ɯjɲ9H{}´9&SnbW{O09d.ˮ,v@ 1rVOwWeʆiT4n6BsDbGu 3ɲl髢( btt=ɗ$ru)dYRk"<_Л>Ys=s=WA UHO 'c383HΘ8,X H 8H. !'#ߧ.=uQ%I2H3f`Ӛ7T)hutbV.zlxsniv3grs9| y{}4 P8t[ ZwS~h1xKkZ(cjx7l}xmG6:, ؇WzJNW=`+_YJui*kjn2; 'uOz|)njnz,iΟ^.!uH eUU5!TWUر^ʃt7%.O z-V{9篼:{<ڔZ8f #d.9<s61vFltLr\ .֞/h ݴZK3dwie+b; c5qYQ P.գ >wH53gSSUE'N'a:)QnϺyGgUwUzJv0}!BOIٸ*n7=TUV C$FS;C/~3SXXlZ{=<07zE8A+=CUK_t:3YEVjfOvVJ_ge7bkXCa y{sX`cў>˭K2vc QnLdr f_n'cޗz2*^%I,#'̜Ju?5UUTȼq+uh?7SYYI$z"a.c{t!a'DH /u;3^-|n'Nu'Pnxcm,˅Fee%=3sܺ8q2O#P4g| st˵zps`1_DhSWڽ6lnd۪ZpsI:jaA %eXbeұsպds+|_IDn$ RNp1TRU^֯~Ur´ɸ>cgst#UOvΈL蕯WI]tuvؾ6xq$"`:E:ɉ̏(++嚦9:"UI}ixf~>pX`gNd )sl֯6:T+۩9x`4 }fe *:Dvx|xwMU@oiӦU(KŁ Sĉ8ā*B@ԯ E@@TdZeSFP:L4Mޛ47y^y%99 @k #sZàC:^- :ߧ HZZ_~htWHl(Bb+v  {㣣quvGGcpt1ުzspPO1vqԩ)g#!}A.O3Ծk X ύbL@N8(;pCN.6HtH Z] sch9poo6dGNv1.ӈ#jA97fQr5(DsgV`zA9DAԹS$t焣*%)У3Nnq8nqmq:#b-|Obs:CΛ*p3U#KŠudQ]z).j[ga[L_xn '_lG;=skKO7!F44I.FL8ᯆ ߸rz:Hj9Y =y"42Y?!T?T?M~!"kJOB#gR"=<΍lrC 8FzAApySWjyghܸqX,s@*jc+mUaݷ˹1nLPn(;7er]BqhG'[8EYlj;HBH Zέ9]zr A9_0 IXN ,9D =Y-Qꧩ9Dpu!nGNg@"="WMS3;H֭[=Ͻ +|(a:Mc#k5K}t5&&Q7ЃDp4@(np\+)) `~Pz.pLs< V@GlVl\@(Q>NPozr.3 E, =A4hShN|5(j#gk`{y|W*8b& Οu·*J Fk%!ݑXubx[,۾kKz$ ILul5TkWSn7 \3Љ 8{JƉWc˹t=N_EJAЉ \3;uܻɹ@rVG~] @#ḎX,cWMDd"AJE5P ;Yj-QM"܍+1!Of: MizcZ۷Gjj[Hpd[ IQғnGNv1f(BEH(h(E\&IE{2UL .nД$lOC^]y΍|9NQ] " jG-:|pt0Lz~@6 Mw鼫 "Hٟi×WnZE3J0 0(BKZ?T~y):Ƕ݅`V`:/it=ED#@@P  jK)"aavSq(p)jjzjORo " j)'Ӏ~E+VJVItlsݖ)N5~\yp Ϯ؍k„ Ls@@ s< p5~~u#\ΛEEEUY>P>͹MG,z@`E6n KErG( aP FDž`ְxە,uN{>]{s)gMȯ =ACDD;A܆~Nwqؐ3JJJD4Jw'f~ls#e6e F,F[ST3轗omz2ae+{ lE:qU@rccZ{c*YF1f+r0P5Q=U֞A9DAԙS$r89sPI.O|$edW&CTɅ'4"3bZ%oT3lXmKJJx2** :CXGUxRe= WWzX.p ,v{ql2e,AıBy\TƦ'OIt؞ "AV]MaX\579Ҡ#V2?nڡ)NBLv;j5&2 F^j-_X²dNU[z ݎ,c rf(P((F Fɇ2j۴izjj !B#Dn2pNa2<፳X*yµFZ$sA <r%Z D#o:8:9 ?FF#łt,b]pW/˜T$ jb qYsƤ"ɘ+ځy5BE0.GlCv3db)R 9R{" :w7s$`2~<@gHbAII jC9$gaРA8p(}|L bCA C;’!=~BtG$ph;a62!(9q)sȕ4: H,[lE::a`XS`7"'$pTdX%%% όm=o)+Ov8B:-bu P(`ۑiFD:J7y=5D)sz;p nA%v ]v,lnH$ćC^FB|(_Fh|m/F#4%elCrF(Bbb"8H(!hNM"4 -FjA{&x?NJV]ohz2h%R/dRǮdl^U IDATI͆l^]ƥ<Lv;R/!詩' D۝%r7:Lnrb`@kU (헏| G.N6DN6~Pad\ _ b@.*xC|ߝn,Z-R=yH@9.F"WBK -=ȿԺu8HxBp1Ύ&">&n#ygꩩ' DuT9890Zk@h|1Kz\d *4h(,KJ/!%6p.~ aay; ?WʌNd IOAѝQh "A0rp{C3A9DA48uF|L ( MF\mgCU )9ؙ6, u`t 7^iw C;є"Q/7h4BC;sٝsӎjR>P>DAAuAwT3a7bE{Dވ* IHv ԡEBK 2= CDTlC;af ۇspM?KnDpd'nL Y,J Ow=_-ـ&=[OA zDwuDeee.q`78*K6ʮf ec )v"!>(v,24%oOsá]-tqZ-oDJ; #n@dyH, >I<ΓHO' rh0I سc#7"hU.H$aq80 10 ^sZlP; i.6)(6Ps$?Hq $)$ @pfV!3( yFԊ| R'=COAQ'pC܈Q"Y$kPLBTY/7ce#mwGS6`Y;ԡP ø ?ߋ;Yj `etF0 lzTUt, _# ˜lQk:8GolQы1;Vy9N`\c]VtV%wn2NHOu' rSgH)@@@p84=~JՎ<(%5?8U8ƊrDGEDD;_w& @֔9otܚ wƟ~J%a/~bzWnIOA9DA4(FYY"nFյY@j2J%;"iТ, ԺX~"ٰ5ڣ.j NQt,b\Q`- =9'SCADCv#&f˲s(V+sΟa\\a )edW&˛_Eλju=RV0=@pleF!vg4Fk%e;ߞDz" F y^2qƠpИ gY0n]0/jl n cNFET9Az"=է !"ޝ#(af)<);I}xğԓU` q ΃d+[㑓Fk, ???t)NE|a~!VWM@z"=դ !"Vq&'>DAApEs<ܦrӛ2 Gs)⋂}`Q|:F{tH{Y>[0Y.2|o Ǻ ANhscm˅Y& zIOA9DAԹ3<]͝3.Mz9yVLEUǞ|#@V#JPJ#:7\ J{q^_U%Cz"=դ !"vֵ!q^`XGOJpܘrSphZ~ѻ\*Z%>_/!ΰu'Dz=ACDD;nDytr[&lwq:Wٹ-µF }nLŲfX@*z5oTzsn _b4_;@vyٲP=B'S} " rvaR,7OZ2y*7H D1&!cFg%Ƹϰw>7F(_jH>Tz" :(OeץK)9[ƪrnu&ύf+I*1M|A}eHwLm WIOA9DA:ROSsq9=m*9ooΈU)xݹ1Sݹqwn[,HɒB(Dz=ACDD;C>{_UzS>9kJ8\ @1l:g#2b8~/))q+Dz=ACDD!ml3s|Gr^NޔIxO)Rk%!ݑXubx[@SWAX|a~`䓞HO' r5gnK:IB" 䤯LVUFqE1&邝z*v+g: b$%_+%߭kкOz"=Շ !"aYv].&9i:1ӛ20&'H."wQh T(qBC9}']T |>DAA &, 󴃜D\zgGSrdH9nr WU>\jrS~~~#b1:b%Y>Tz" ZG8Ísꔩ&!XA_(2"˕^Dz" F pR[V;;k{K)O[&wJmsV]Hgb=žqp]^uqIIdU!7ZV;;ɑ{+ Tz" :Cjԡ~gu䩌`X\4XS*rѠѻ1r9cUNnZFD˴Z CXlG2HOADC!Dy: \&\\-Lg]q;n$R j)BGސuV ???F#Y0&^ 1Hbs]=@tbAjP~yނ<˜T$sE;Tz" Z[nn  W*R&9yEh@rgpb+=Dg0 ƞ)8!)']eIE_RRQ]V灅gƐHO5' rk-i7\ \voS*R0.YfZRhf]\^rˤhd g@2 ɩ?ah<p@բt@rЎ?煛ΤU{;ʼnDzI=A4Dͼ]O..,| GnJL77, ???]{91 Dӓ(1e ߅SфI/7Oev#E풅Ɵ1+fXI<ΓHO' rҢE \<}Vep;T*]F_G^#:>ӹr$_ey{"xqP麀$)y8"n2bCd: Ød,6*d!ψZqAJ'S} " j_~ H 'AAk     "   r   !"     "   r   !"!zV{Ř1c׮] ӦMƍwaڴivK/2Lؽ{7v_5j/XV`Æ nP8K8wvظq#z)Ɏ;ЩS'Q1c )) 6 III=zKr1[]vř3g0tP媬7F=:u  ׯN<)['ACDDbÆ HIIAΝ `ƌҮ^7tڶmrm۶zj@-\^Bٳ֭=mԩSnn tޢE (J޽{K]v8r֯__0`VX3gBb̙Xb_PuAa˖-x7Yu~z<|܄t:$$$a'O<#hNpmĖ kW"?H! kP%xhuK:Mii)aX$_vw^9^}Ut::u .yxƨ#9q<9r$Ҽ2k!O=8p-¯M6!''뮻0zh̝;7|sյCԜi 7Ocg! >wu|M۷رc̙+W{cӦM6m}]E?#E3BJx=;;7p4hPw܁G"#=vƍW4<IޯlESt: D j/p7; =['OƯc8trUG'ACӔ! YYY:uW$4sƍ%wؽ{7>hO=[/Ӿ}{\z¥K\hZ<ꫯ^톦)So72eJFeXXzlzFBBB\znh:#{ذa3gZl}o*mÒ%KЫW/dddʕ+BϞ=q'¨/ 냦M2' VEM6D-0aL0ԩL&K|Z ^JUSn8"""),]1d^otel޼e ѸqܮC^ʞ2e .]QFQo,##CErr2sصkZn-~W(J>|s;#޽{l6cܸqՒWsm 8?u>̙9sޫV222~<u 22o?姡fҤIXnˎzWe˖O?_ .]Kb2d|}}q뭷bѢEXtisCґ\| f͚;w#2֭80 8,[ k֬imi2dO!Cy#.=^2^1ju꣹M#fg} _~lػw/&N6Z WZgOiXb,Y˗Ɔ еkWbnɓxg]Zz5>#||2b߾}2dY0qAL>˖-CǎqL6ͭm=7ysO6l@ii)mۆ{ ,… gDFFիXf ^{5Y͛7۷z[nL2E<)Ԕ2-ŌȘvV#TTͱ>hġ)sA wSSTj )JVZ5>>r}.sAA48||!D>>,AAW>>ꃨM  hCDAA9DAAA ZCDAD1LƲ,K >!" @FAAA4UoFAAA4 g($WivA#  /`^ ~#AACDM@ NA#  7fS|*A4U++t+"Gp8[6}O"ɢՅ07Q /.ꃨY 3DDsrJKz4>>k}A4Hj! SDQsAA4@: =%**F(0 9]H& k pX lV$!K`X&;*6#_P#dje@RVU}TF&; `% ">? V])p)uq2Us_-KO#Glmn}SndJcfFJsFtM l҇ApH(f3W/ؘQ^٠7!6!7Uj*w IϨ+fWX>T t0#?|݁FcXTT9D02dVT9Y el*ǶgϝAx^ߣhޜ4D1,C;00z}6@,*FYTXT\^_6 QȆ@ 6bm6d1v aGHGCBT10U\33y>Ht֎ 6I̤8AQsNQMk Vp gY5X*MkXd@Ma3՚ F$g0&:aE04 X=}*:&|Y#Z j q* EF PUglqz}v |.s^,6Пbth50|gxFzT#T_ |G`.)q }CD IDATW 4BD@@P0 WivY5 Ï,3iU8jihbP&  "   !"     !zZA 2W)@AN)A!=PW#L^MY߫Յ Y;D[ $"ZA f 5Cd^qޫ ^Ed܇njPpx-ͮ5cHU_  $,5;l¼v 4iCԻ9$Gzuknw8#ǧy1p5#ƍy#ACTchQ\THu}Ԯ]o/ޫڨ~O_VV__U\<鑜"~8磌e VKׁQ_2NAV{R{z^Yҫ{#=OZO#ACT#@uJ:0T/tEڼ~O>> Z6^9H+0 jg`k|l1 |j&Y/USo/ͥ=u4 yIc=)|fdCeeGxQhd NQi15Zؚ*|3KXU*2 N=[W l;EԌW_cCЪu;w}kGPʽ~Νn?bӳнW?amuުj&7嵗3hSRR1ŗg D6͘9kNFۂ7m]{8}/xr/-Z+1dhm;vŐ@M}|d\__mڌx7AK/c8aoBQcqJd\b7Mk-[M'|:#r+2pN}߾}8q""##޽{cqq=@A{+⎺2{ѣ4 4 z{ecDL6 qqqPT nݺ*[n~rMTΡ1u wZF篽9D逸nL!cO A+jn>ĩWUd~ 1h.:<'Wv|2l޲ ?]˩ۯ?CTb=7]1vp{}]PTo~ dG˯~n4WDt["zLSMwO?lĥH:q s0 =<=s6-Së~LJ{i"Y|;.[Mޕzpl\2oVAT'O=/E˖>etW'99e^ G_gw%W`d5@1~OuŭފBlݺEEEXj>#\RÆ C^T ÇGII o_X|9lقٳg{-ϢgϞ_`4qeXlx [n~rMTwAo0`op9>+fݷx{OcGqI8 RRd5iڈ-׮DX?~W=Pի9X _y=O͜%+?ozk*_hTHǖ R#hѢE乣rl˾Rm۶u?gQM<5UJ3t(,Z/y}%xeK:'=hFL*m͊jmv wmلH.z-_mS{63EDw{jx .]<פݜt~(y(Zĝ9/>>b{L0Eǹ-n X|vJV:)<>%u{M*o{^h*/2z-QNNNƸq㐜̇}8z(V^-B߾}3t:Μ9(Bnݠ@ܚ-ῲZeӣ;222гgO};'W U £LwfSȫKTyh򃓰iVqۮݸs84܅Ƣuhݮ#F]ww\2{An;u/l6;xo }4ZŶG>vu?XR<2zL=MIG#p<>:6ss96xs>~9XK^uGB8]#D-60uT&m3$zu)((@D )gJF9 ]V!Ӗ8yyyxi{ŗ^~}mD>}Y<6&:YY R_`lR Fl6c΋/c9UJFJj.j, !!e-}K\ 8 9yJvzt̜j9Cr%S "<2u-ri߱.Smۆɓ'!'c֭ںZZn]ӧ^}VaG\B!ڝ휟\}7b<7wC]ʫeYf̚u \m?su}'0q|K.{ǘѣqQ8zg{^$#Scgp9]5O?OӷW݉^so}mMk8iIxp۽xõشj]ћq ͸7 Ur1t;rFqr͛KWT٩M÷cǣ[..\JI{-6!GwB/$ƟvTl›o-̳6o;wᶡz}s΍_{!zfWpې[qQ#rEumKǦPZZR>rM{?HwwNɎ.&O?8 }O>0d:興qvSqOHJ:͇: }w,R۷oGnDagΜ_ٳg3fĉ?ff!11?z) +M"8q"xj߷‹^7߄Sc_$|x~[m1k ۷NgNŘQ0prz=wD`#랉xb4( v_Z_~v] ɧ1|QPDzO> ?<= L47a4y|- sfaݺvϗ㶡CTbGf;uOZ!<: жcWLN^n=a0]wbÏao11.zCxK}x 1ۧ7V-c9u09**ᄑ݌%Ȯv㷝D m)U%33 11^ۧY$gQ]=3q?$${ >nAoј?r늱c7¹ߩ\z=~$+Ϡsr T=WU}7$OAVbx|Z-3>gy+"WOhO}sgcQ]aȣ&-c\tO6Whp1 mKoÑ#G{ڇ w{xQ1b0qO?!\w2.T=7 ♊O 7weWP-ypٯڢ[H<s_| `5v9SY{h'86_+ip%99<}Ywgw#7a෽00Εމe˖X+xR߀2a<>vKܠ+~HJT<@yz5F .;c_+{~u]Xln*eҥ8wh/3gw߭5E`Sň*+e, ? %%-}{ʯ*nh*9%kHMm!2k>s_^%%%iVhѲ%zt`ԩs0˿T73&t:KNC( s;z3@۾ƺ?T(Uj*z z<>:AP7 =A!jarrNjKDAn닧& r.wG  s_/ NA.]9|B{腜\LI7_@3ȿIRϿзO4WqYD#PCVQ!){9Z.֬]/>C ZZ!kd}v0 󞘎.~E87Anhu0!8L8Pu^nX:KKq[g :vNVtwn܇BJ6(vcN>bWĢo55ʻ7 qOv$7Mfs nͳgB! ~ }a7z$ƉwM7H]f<)Uexü/+V~%9YYY=z4>zZ]ɓ6L\NB.]D~^\^˭k|fZ̞5wDxxzrzBnnnݷs~軩!׶/@HHpo8ϿЧOy4դ#D-Zb'Vړ;vJ좲sHHA &]tI֯R?t VK No|"iؽe=,bXZ\<}1q(U~SW#C-_ⷝPRR͆cf 8+^O?[8|(zbݡCckoPGqq1^g9SÇ*:g {:62;u‚a;HMMsf#-VJ}sFn{xbTLi/XVXVOL{)̘xw)>]=0v݇R}8;c>ݻwXÏϽݿNn7NhN55DgPT9/GZh CQF¼y0rJM:’%Kxb$&&͜9'OƮ]`X`XcL4 >r.1.K}/\wnȑغu+rssQVVlܸSLŋowSDmq1Ⱥo7O? S#)4v/c s`7&|0kU}>hΞKs{֥xͷw?P)3z$u嗔to-~/XE^x'0LyVv0'AxHje:_KKNšD,:]wN~}npu9RCFo{Tْ/W04 [a]-?WRХs<&?>Q+Ww瞽0Y3\*0۱hhߩ .HuڕA4~~xٲ~3HI>@mxsmM*O>_!/? @ &^BIDAT#ѕg7AN] ۦ UH.?">{d rgPfM967+WڟLf;'0acdV8h g+cھ<8:U&)Bp1z3?Ə?bAwg -p8S20FVu\7TZZȆN'9 D}8Ƌ/u>JygЊղ%oS` rAu+,sS+=7@2ԗ[ XEXw[Uh0i--뚡hlɑa D/P4 xyJ[#C*< ч=E^a({3ē#ǁ(_w\7|Mp@nX+5&⃎|o@ᆵy96Vy'+4xcz|SI*e0$O$iW?&fHݪBLT ZqM9IENDB`eureka-editor-eureka-2.0.2/htgen/shots/visexp1.png000066400000000000000000003556201464327712600221260ustar00rootroot00000000000000PNG  IHDR~k}sRGBbKGD pHYs u u-xutIME  7$}zjtEXtCommentCreated with GIMPW IDATx]wx~JIP" қg^AQ{v]D@z/@H9i~))69;~; p2jCTpcEcv§I g'~Ɋ 8У dgzcvY;k?LmDAD; & SB]0,+(! BUY^<^7RS|H\lcDY;kgc^ٻq٪Ʋ_V־gp@EJ"ׅ4'C0%2;ٜochsvY;k?;e}-B'"Г&bPB0B$X6.IΏv.Y;kg41ΒX6%~e:2ET  7@?]23S|Q6ÉY,j|'Gd+EKΛ&DݔۤY$($'Nyf8No-?-iDۣ!/m8+Xwp>Uz{5l,3Jg;4(XǛkcsQyԩ=#}. D0o{^k?ª:At/4hMׇBzx~.ܟ.if,Sw Z_ӓe.+v0_'ίvdg=9'a 0I6Lus6`M$$fЖ虛F Mfnp}򿸴}xy}Uk+Zgݿ]~,qc15,O\&O;s';ײɪ=hEVsmVy,\]"a$Yh=<,O6qu@׫M!sDuODd>5Uv|4H`wI:h. }AnR?.oX D|ߢ5Lܭ'h5WzG&+z5F纩ӭF~7t8eMî .،-Ehi&8n9Ho;m0!|{Uua. Q3}X?竍ݣ!5΀ $v(_Z|_ 'n9v~żgmO_uY?Ng}f)x>RVhRS4pNUrQ~fUwr eGD5k^4>8yE?8\W}:μ:> wh~M2?`Y^ ۋ!pi/x_\mR|<&p~,Q5) ˍxs^mcۀ6@I)~Sɿ@I{#9[ 1툨;us&+u,WIl1o;<8ɶ^ @n| Zmp89W~:1MG!|!oʣǡisM8`Ca9YyM~m= .hU; E}`:hY; a$!/6\ư(~8-6YzS>1?EU劂{㎹ƞhBk^0X_ :bo;168ym|?lH?m=[5DFXϯ%X]a`t|>Y&<"KdL7{a1HHG#mz}o1ؐoZFul_%sa1]-EͰsѱ>: %@y;WWGm~Ug|<4 8\:u6Yɀ,+%.8P/Ճ1g5FFJ8bN+ 43h_nW2|J|pgFUGzW[عC"}pÒW]B8 A綠*>y.M~ "ÈMY(ټm$d] 4l{v3hBSb}* ++ɍ/ݕW°uЧq.p%6*ǣ?lBJuƊ=83mV 6* 6BQ5:pm'Jx4H¸M!x{¹mk^=rQ+Y۽P ]60Ш\ X1Guʍґn R<Z/ ]Ÿ^9)ߢovᩁ-qWFnSt{g„A-X!A=¡o?( DгA-dyDb~%f|R=8fnopk萝BrWѵ^ohAڐ/vLcI-/hB}?:W:88ssuӝ^Mf-uWu#;Ko]֐>~#Ŋe{@&蘓f/~(}WvAE۲\u66 ?X'5^ɵ.>s7,STLTYn֪d wDєI0?! B̏cWIΘ㻦"'}lcȹvr^1JTw^gL!i?a=n`>b,9nc'>\e!xD2}OV/՘;,ۻ)n`l令5[zཥqP7ߌŴ%NKc.V+=sa_iWuS[٘hy% Q\ܹmpft9 [7q?uW%;!;*xCƙm ]ѠBGlx-Y䘇翻yKGnt^MP+8vUifn\cube$6>L|^ֽd``L,Zͳ&+!|j/%~u8lG8 qYL[=綪Z1lGT<2`RڞaTX d2'%*b 7Ix8^O h>3q8 sFP4߬/6jX p+b_ &>nKֵh 7`QcQ!6k^i.؈- &ƸC=uQ_U r'}rE-_҆|pTϋ}̥ampfn:c]>ݳ 2}g3שse{K:3-V6|*81K_w*BIT5[Q7Zv1~W%p[~q0e9nHUGn/ %/s'M*weĵ~n0\iwl;{6Wղ[Yu3CZjl),򽒀6y-sP/ OTYrܿC 2pYOndwc]ʡXPs[AߦPi&7Au2:uS :׭Z^ OO jNulo1:M`B*' ׯ9έDGi ׸QsCuvWXOe79߶cҰw۸wn xE"6KB8Wd^z}u]-tݑSV5Lis}4[cڦD_U{AMH{h[LW*+X6s[fὕ8E}<`y0Mwqgd&+:cr|^c{ O"5 I|M4ըw|P/قjGk~UrB4ih+Ҙ{ 2v-z6t'o<9Mb{W羒뫎n*u:Wջ֭*BP d)g!a2>ym:8<xC-f.`ۘsbھ>3) 2ٖ, [ꃭf\ IJ]~n^"]"gsu zq_g S;_Qn : y,-@A t̖ٸ@ TU*qm~jKσ^we+( bSAZI4⠌߁ѽaube(, 㫣#VXFu5k4*TSѮUQ1{.u.'Bx.6WjA4l{ZeҼհo?%:"X0f,ي5K@9)E䗅5IUD^Um6j5\qG5>_%m;%m>[_; .6٩bZxZ`7k_{#ㄜ:sapEJbT ejX,5-E]T|#ϥ~%s8eo;hQ˝,#jVGvZD~J_w"UBتYglG9 @{2H8Me|RWoΊ"8pp"<=v9-Ѱ?m+oѽԟ,빭s7}7@ "%bFMh}r%k"%n\EҼr"BͲ#E}U|Nm [[:( tbz2e&ay}VuRbڣ8Pf pnuӔH ? t2צR\B=GAT.;6>]'UEm#qdsa1`6׾]}p0w~h|w9ѵ!$+vƷ&cf&b1k4bǢ/j,ƿ̯ٚ#siҟ*s)=Q(f:F?ngneNSkr;g=ܣNyO;{Uxsj-f1d"o։2: 5xWGv>J6٦B+˪+(,(KF ) oDCƮCeaw㹋:uGߣX b(# Kw«l4x+.g5wџ기}}D J1}&3r}Y-<~{atVhW/};%i]w׮^u; 9Se?G{ WFXJ+:pa\6g9ε^.ꄳqX/_+۵{qw}.&=Gtk xm m"#5+$e7C. Q7ՋeA|j&G_߅팒CsΫypEmexWDÆ'?G}gA-4äX\ҹp'!m,VkiGi~%_rzs8\vqg\6ZhrDyx }GV9Lr"E1ỿۜ?83{;Ugn}=kO߱|r.o\AkY\}*<Cފ_HdVq]23SUOg-nHN~ '/1SFeD9;3qK:ѿE61;nœ'l. Yr]ueu-d4}è]sw]((..GQ!H]6IcK`]0np,|ɸFWM\` 2RgKMCia1Hd^7\!B4C*B(/#̤lS/,ڈmd01|B1Βջel00000000lͺ<FN;Ni8;B3aa```````80XòX7p㘦3~<Ĕ瞝C4k=n9{zL[ w~^z%Ûor*qF10000;I)i(/=̴p"++.L; P)@y|p(/cJ`````8O$ȴp'$AcHA/~cD'v ⩆fm`UN iC\o/9qϋ_ yiŘ̳XZ;'ס궝Nt1po{б};\;* ۇ!L"~Y;JJK>gc Nm_ ˯G~A!7j;o W++Q^Ql o))t?,_ƞyh Cۏ=6}61u͡ǎV7]T-x`$bݸmض}C՝ c <,^w]]Щc{|{q/Z1#Ԯ}zѷvfIyZb%q5>m~6X IDAT\;?cH$߂}59Y8_{ >#w߇d|Gr|هHNJw W%֫XWL4-!g/?߄}̽tVSO? ?5˗`cIXv pN^Xl zt?OLD9(-+(wcUʶ1gӽN7nڌǎAvvGNv6nlڴŦE$ m۴¬SwpE8;YKy1[ѽ[W\.t!`?1jUp]Xl="yq&F Pe:cΡHVgο3C=`8^"8 g JJKkIScؐAܩͅx7Уۙ5ǝߌz7fkoncA@x𾻱~FFE?-sScڔg{V,77mƳS?*򓓓qy~X~?III5SzP+=6n޽ ׬EfFխ{r˯ൗgax0u ̝7=O̙7f.^{L{i7_=,kqt8ySqѶM+6)3⡦s穩%/?֯B֭yy ~}V?, {G\8Z8ol~mނ8wJUUyy0uL٥IjUi3^ϣKN$ rs´)G4j58}{$},e1/qq" a@GbZ~DS&?.;%Iڥ3 f2{"ص{7;# Egx m*h]`Ҕ8y*NPcqBvm0yx0y :^~M<1a|E6G:Vk:{ʭoҨ!ܽ[Wx}^, {Aun٢GDZU̅`Ax}N nP>Y? {0uLL{%Lyӏ 4M kXW>B%UO{;bxWpvA(,<6wϳpAF mŧi~ }ZT>=ν:1yqagvpèo( al,q㨑x0_|wBƸx1\8x-7wtwzcOq8Q vI;1~:vw\zX/ Ѥ#E۶m0鹩LԩSڶ)S̮z8te ڶaOSJ+Cfg`?c-7}X0_rZ,vk?.Ry9\M=UqRXz>uoo@eH{sX}~})ts[sCD8Θ;ss~A8_U1t7:sshcؐAXn֭߈q0gq  %ʫG$''c[0dI5S~?F ?>}R?VUʞvvڍ ۶((˯[LQ\'&eAE5܇'&Lƚmr'LcLG0D0KF}lJq7ӗmN얇0dP<ؓؽg/TpC=x hj<Ę}>4n}/VdYƺq.ӈKbUe+V‹/<'ྻDfF GꌹgݷsSa=A4tw~Ǩ`s1駎J''){|ߑ[oͷ݁}_3.{"p]71aO>\.t^o@0{@zuqM>0jgȭ[7wr#%ExyTx':o .c(,<]ױmj7l s/(Dzuq ؓOzz!<7E\9z..FFZ6dk;k]c}ضc'j1w&3fkׂ84m߅.:#'b<4j'};sȚzp%m3Lb:cD>?W\z1|W^~1muB<؉ |0<ԩa1wcz+ Y`MJa3Ñp| p@^z%|֊:v"pAo3fmⅨ5NE'/O :vt&'UϧYNyp̉ bb`8N2IHxA3K,~ ǚi Y?ScNc`8O?pK!?S[ % \vZ1YS;o/e  '4gwZG}W[ "8(ʭ!w8z\R,N/Z!}2>~\g6N(B$hO+ x𼊈A%2@9qXLkJI!\p:аo6mK_ۑn/8SF>;.drvF*1XVO|;z|C A5h(AQ uUW}AF  'A$yʠjn;rw`tǺ̝nWϩ~3.G)X<̏G!K76H! ʒ 4A>gF,j*UMpg EqU@ j Lw'+WJ"MR0ȢbqsYW)m!y]ߕ{s ;8:wj8;Zͩ L9FGI%w k!q2ÉYqQ"+.DItTQ[Jp%ieO5Ȟ3,~L5'h'a^TdblW TBƱ|zDN2der&l$(f;Jphg4M@XIAQi#- 2dUiPT S2jdEɜ4+`8 :ٱos300000p\<4&{uW@0JHbaK A jpg[O$.o/]6iILbWa8B˜OȆUНiZ`/~* 1bEACdD-"qFGi)%DP%z,|{%So2 wfwK,[YOQ%$yR(2DѰ  ɀ+ mI1I%@0Io,+\j?)ʹ-L\j2Y9.뮀b\ 'B$xl] %OQ%ղIĽͫk[O K;XWn) H!+H*2=dMQ4Ȱ MhF\Ai B57"XAF˼"!QuOQ A~jo^"[V>Bt(T<Yq뮠4&kbG2{W@R=RdnEB JuMRoI\l| ‡ LC$QFqyv0JPİ*BVIF(2S3eoDQ ,Ώ1#[iwLD$i($U)ަ4G0l0P]+)s-FO "̉>ةAeKb} ,jfH ^lX90;|0Pi6xNE~q)ղ̦厐@ZP :D˭b|-%j<}%5 IWӌ"բ #9ȝh>{B$G ]נ%Ѫ.PY䑁t10TגOJx^٬a3!$I2dGũ˜PRcxfHQg秙DpIVag%`e!`b ㏮b;&2Rdyu=x]0WA1~vG,{Fs^Í.c?j#%Ge @-~&P Qw&S Q!2jmt9 nZ4 mA] gQfkY%PJ#qKEɨG<~ ,fe{-M5UxK,El@3000TP9ŠQAqU8(#A)ٱ% d 2b"tI(-iR8aS@ h/״>Xn^wA,zͤ !two) j*B\ j9:![xN}Sk*.LdzC|DdܢQon#1 /W"*DϨ7;\$9XaMD Df%+9.Keiy#)).p wLqW8ȟBmOtGf! sE!1Vaď?l4]?!AͲK#$rUq kQؖACE$o|AY1{rIm=B0mapL{>nm`*9FӐQ" M㑖Tds 8h1(K!bv'p(F<1#~L ZXh$*dDzL !icTTHB QK$<"R#)2IXTyrjѳq ζfIb|ԴfGd<,\%6 ukQ]:EBbeYc``HYuA6WPu^$@qċ#HX4TT Qi9; 73oSپCH6,}rU/oA6`wI4W 2rq;,?E(j7),pFDY$ϲ4VEQ]4&z6Yc``$)N"D!S!CGip~~R P=暴VdBQ]B(+. IDATlѵ{[ȝsٓ:D[f5`sn"~5K&-jY*=4NR]4iþt20M6ncu#~ 1z&Y&ˊY.G@_cJ)ЬX6(#q}D5 H8}%t6)'ZۉNIL !EݵM&<`X<~Rs3 R<@ d.FW=-MYHz rFYb)Sbw 8H(<Iz\9vBbwNj[#}C-. W(ȈtI!HL /f/I,"b5>@ k&YHV٧bs}5Y萔FYȊ'DD-Z%Vs%ꛁ?}rpjKBvtRLg(V\ K 8YK+2jRaك Í*DY'麼RmJZ?1bHj0A^K !3-*!WBIMʰ%XHo>d?zLh'F .@p uA6Ux vF@IϰFIH]p!Z0:X5Íl1kӺRy)& nN4d ^s4+!5_4#3JͰ}qj9X-%'  ZJ3qPcJ^ \b^Qt\v]Ha~hN $a{91000pI>da X[=:DGH!qC?{a$m6ȧ!_eUr !dw 5>,] !,!{tf*s/0Jpa%M@"]yD5tSGF˱>ufBAodsJb,ޏ?әi D"㪠$#d# ttbvK!|SZƌ1J"e`$MH!lG'E4\ήL+Ώ%Ju(r_. "!,G6%{(=Co٣.tE胋&وvm/f? c1w:rbi#O4 `<9Ad*(CG6.ӢSkL<~ټQ:T$kF* &"g;k4DLuIf[ SD,whX3YIFB(þCMMBB$53A4\늍5mnKs( #~ H&.I SwCibAC3~:t({̙ LHJqhHq Sid(ALB;4M,.e7²I:d =XB -hɢ Ӣ$XDpPǬ8Gn#HԺ;tii%paUjV```8e!200ć qT%B,9Dpöd.dd#a&aD-$yx5&n85趥ג<~Ȋᮕ e$5:}2en>oD#kWu5U0$PQOhHu^R^lANvފ 4˥+"̒(fݽ( )J +VsO]AhIb4%J qNjtЀ3ZMb'}3kX):>RflbI BGTp땸rhkl]| =b.[^dUiIֽdb2LP }M"!9^NG?@5-c`YJ kjâ˩V!b;:z| !ӌXB%(K< M[]{KsV۷?ճCZKQ)'!'r`BDA,ہAP‚؂8 1D,k $Gf &&!%JH4{US[uJ w}Fw[=}te܆n]~l9H_1Bz-0? 0 ;-m|Mn}E"HO$)'G#ۇ ut=USAe0B2it1*!^O1+.b賱9rg5G+ez] ItNRop~ЪUs yVr#b؊j=b+gE'+wCǡ/U^I-TR{~yV#d"HO$Yݏbʠfjv9Ujt8œ9|iϰjԪ 2|Z.<3_U<[˜,Dhsֶ9Y@]̹*]y@ T4އ0^ |_9)̒ w 7c" l9ψVG҉7'$D~"э:AL*V0؛-ի)3xoFf:y[]zڇ 3!LwgMR-8`9-.6}<(C8_‰c&S8)}zAq3GA:q"H C]X)E"HO$Aݏb0pa 8EK, ݦb?}߷{9aXsNajW6m= _ųK9}$ڷ ? U<ڿ;X;oXs vN"P͡]vq XބgD3j˃?ރGT"ZIrDD[ `Q1}zѷ0.5)ISWxF;z;O<]liu;k $2m PcUlڏ^p!:Y<~yehf[~AQGз7 Fhln;gi ED;*80`3~|z$XXU=G[;!{m&`Zoi}$NQŻ Jb bs i2Ӊ`+Y~"Z&@$z~A4 ZcQr/a\lu-FŔ$3Â1< UآaWǫ;; i|< m8bb>ȗ8cZn1-XwC#+WAٰq(%۔!}m -"HO$)?FE@ۗߩc`T0/ϠńA`0§˰mhԿF4j0/Ϸ>]灲Yɤ MU'b Mu֮ϧ!z(v @.ޟ8:jϝ"HO$)=C,)2CTm {3H'&DzޅRU3UhBԋ1gS$w; -!hηu%nVCBx8¦qn 4rG~ 6_q+Is*+Dtfbf˨n6w)*.FPrzU1b4mQNVN!Mr΀&/e@tn0`(%Nqx+uE<̹`&m-8 ; Aў}$|=~2ϋܼ㜊iX*~"&@$zw8I\\FPQ:m8GBjRmK%|yCahC.-Z3aKGkJi\T W.F/cT706 zWA(0TBOi'nuGm\ѣum-D"?&$=1ԬBעoQu<2 ]>nף6ijo1Q6qum47:"HO$1'I"_9)`2 x4摢hl.ho* 8wHuh䨚Y2WyAnfhZX "<צ@z?j4mgW8nx, l>=òK69 i[I!D"_EAF`Fmպ1P`闱NP Ky 2͐-tkT 6&UCZiO_[ T;jwRlj  lmHg8G(Z q5^IhR>ŋqk{] $՛.vi/U5y[}<+XT>/nV,Hu auсKQ-Z?mkV%Ȑ`2 yZt춭qD"?蚋Ԫ-:a+7!7]/2g;J$Y4Ƕ@f":pp&SE< ѕ۴E47>Ņ- ٿ'gNy恷A3|P5s; :z69U=z^<%GmN} ͧgduIumx'eqzbj[sslLPj<掵)!dsHN'IX=niq0aFkDT(nŰ@-qK;PXajG& 4Z8Ty 呃k-T4vZZcVH+#e (\ǿ9xܨI 2gs ߔA$] IO$zV/[Vvd[\D dMXxhiw]I_KBÌP<_[06ê̗x)]}2m\F(Cqk 1&ѭAóķ|y;X$D~Fp9U`5.SebA&m;>}^]7pٌ%hEr%MXM~,%P"]luco Z9̧̊g؛! *)s91 "HO$ `!FQ&tY'<J;n<ΩKS3˰ͯuW:?#_36CcA;ZOa.Ә* IDAT[/s$ SHSx]7njM#2 7$q$.VqUXBTIH$nh[1j9n0m1T(bHpbr痷b r[`W.77T!ӯiXZ#am 6C1YD'#+zq7)@b9ۀ1ϒ>sg/g:VY$grDoVle 7=X/W[g.G;>2n6 o`1.M1=y氺<<uޅ :z~<\y -<>jYCMXGL29_h% 90ZֶD%Dq+6Шjۿ*ܢ7(6GE@W0'iI.=su3C%ј M[m\sN#dv,ab^|\M[ ְf߶lTو5HUv_* >UbK0i iNcm|hxE"HtNQXnب#;v?x WܿjrC1qS+jtY4nyכ6BLϠ8㯣 Hs_1OK׎f|&l1Wv$gH|-wϘܼ~HNH$']w9cIȐ̹Me{3 W0\'g)7o.-n ,]NcYx/8\b[we´8.CN;/⭘[y iS+ٖLDz9`b9q`c`\[ݼN>pŶsIH4\b ~:|Ǐ_)9!D"Ht7xp@ˀ#% <;fú06Gs~ `{y_L%TaڽftNEoYպNPK̊EkQ7S?R0׎rv]ALlVᝬ=a-O=m &n- ,6g-08m~ݚͰn/@ ߎtEtqĂZ㫙sλz } bу%:|&h< Wav᷃QKƗM̻kP%') 1r6䥽sM׳lϯ[Оײ@N#,87CeO$ D\?b`=i㕿yhGZVpsn%XS7ϣ {uѼAm`j6˳7- Vb ~C{4֯mūÆyTO9)D"ѕzEgO?aWodDF 7l1s əlyҔhڽzy|fO|LK+L3c2,fٝ2$8\xV̩21~! S  oFT7PƖ.wnD8L9"H$']s5mXd@wyC3Rf'rM!AW8cX+yVcY}ElcE1E0?k㫁jzQޛY8m1|}Ll13]<s :L_RVb!d )6~:D"HtD`sDŢHx*[VO,MZ_[5:$$ΊE勭OzM[}hLyyu[ KLO_9Q8E^PutCg2<;St])$;MlO[Y6ZFZT D(A'#P(bb[AsBNK,-P.`DCJ@uܿ{8-OC|"V53%S8_B9Y1fOcWR֥cI3|܎⏍6eׄ{6տh"~aeWu vI91D"ѕTDg.UjB Vᣪf (ՠ9̶ٽ,T % o6}5zMË)Zt$aªޅ`A`0FPM_8k ޸r+< Z3Dc5]؀Bhuc3VcH$]UIO$zFգ}۠%e70 1[ g[%+mq7+jϰG@GnAyt\gߎ߇ :ۧ@4pyl8Ț[M"7ȣp8'o^666B:n󀬔wH$~nx]f8q)L\ʶs@q䦍b8-_*wqy*S(g5֡I3mi@E3x}O!f\!,&v=JphѡB?G3~|&0 ,m.D"Htݕv(HfvBhYeY9,nBL Gzf"V|4m_9Ybfo4^9|aspm $l&7\nbտK7>tBЧ-b [cYI!c"xەXEK's(qB\Yǰ29LRFnk39~մf[Xd5 >.}Uӹ !A\cUn ch لWXdz{4HwcD~"S0 FEKz4dZই 4az=CnްuiBi gw||)0-qbaI71 MUβ62tCo$#6 x}f7q8WM>|!D"?ѵS{1܍0(%13lS! |w^H9,Fc 0:U=:ݶPK@̖מl@V7xг-Ǧؒ{ȿ.663cJYt%p\&c~" IfDw)i<(qxMG N2"pl nrEj"9oH\T8_`:Xֻ)6Z޴L&ŢB82 qڜ}s&AV$G<fu|6D"UTDw5l'o1&8U &lhG[CjBp:O16EtP~5>},Og_@*hT+|KvcKL2cp>`30\0q츑CyFإI3el 8ٿd39)D"ѕTDwO⓱F2~ BUlqnϾ+F4eugxjĢ^-ֻtCyS"Kel_rTyktnX9ǠT.1GjVK`1} U7v>O>6,~*19)D"Htިm%aHc51ۻh-?UP53E&GXZ7SS>/<"NyW.WшBmyt|sߛ~7;`qif؝5xIZ4{;'h"V@P0 [§Ɵ <]qq3fl0I`Z]o:]^לf6tbc/-ZL?@ƟwB$ DUߋ8Yq![F R. ->Lt]> <_/[v<);Ӹ?r?u[:Sgl>j1m"q̏h64KVhP}(unA,[m .wP b/=6 b|4aܽ7rND+iDϠ bP'].H̵$q(u&$%qƦ+fNCۗ^9_KfX3Xr Vb^B%+s fޘɡPg89naCZOM!w .!׬UlH°,}~FOu*nL)3(D~"ѵ?I:0L7G߻㬘C Ei6IN `haSW]Ce^NW ߵW1.Z/psW 2;F*|:Aߋ,L2uKzܙK`@m_*V2K Ў_=H$ D7@n5+R R?Xc3i*Id6%=aMlQ,ԙ/Ezw G@2 IW#166|@ cAů5TC B j6n)m7R^+&&b5M:/z.iIƗ,|_A$ D7Ecs9xSݢa[-IG@ҴE_yXC]y1┵\EL' ]lIeopCt ם-V(%rxP7"hifI-cgRXi,e]c]4bK WZv#U3Ơڨ (9E"HO$ З[P氝fz0q9HF4M TQta2piG/|#裪b.# ^ ~bǡG{ðh3/w`4}6>.B?Fj0#H|wa4Rw=|FH$nI˵̗Tb01Yi$ :HI;PzPU*T[@ M~k=+kcQKzu33~C8=*O6uku,B9 },F OvS*ӰVȰ6fbCak8~*DQ$Dק!@$zD9Lbć&<췥j4fqAء3Շ;Yۗjpo(mT_7HnޒAWqw1[KC9fӗѴL.b͗:HR @Y'xubQGP$q0yZjJbΜی"HtrD2Lm^?+fcŎ*xL'Ԡ4fYXc?yaq= IDATt9=k}{3Igxx~8Qup_3ZVQ24,off( -iL^Ouuh 9(935şyۘ(D~ND@ :?7SV/e#_̰ _Hl'/Y`@UFۿK%zý0ƿ[GodG_"TeeGTһyIU,`8|?Gq`Z,nbv9(&KP%Ho.Uh/VWߟ| /D俎_?|dhJ9dmkl*lB剪{C;ٳh #`6FcQ|-X$gPiԮvwϱZN(s?wNR(3/ U+5:.y<._쀻. bWZ)71Tjj_aaOh mD~"g/sjW֦B6:t)nݩbm>(agЩQ5-`eq.t2#6aT=-ᅤEgq {[Ģ$E}k،*/ūp g7uxz.'Yx2 E#^y1x<~nyi1<Ja-3cXODZ^ .Z2Fyy*u}_iD"H$}_ǍvR/rϒ@guYydl7c}ED[8qqϽ 0sYat068L_CCNؽ1,^|tØMq[C+eYqE"HO$m桲V |լRØHÊx1D+a:[Th o<R`ovjc`\Q8V߸!<Z$ j?k`|oCcH$ D{s/"Mub2s֏ќݯ_׽奏w5./ Lm'_Cg?c:=pD>ūP/w7&I&:a,qrY8dMH$RbmS8̑ 42$PTL?_W\ػ[9h?8덯bsv<9-f;jջwV,BǍ&5:|` In4+& ^$ D|__L}+fX9A˘,LڃA{K3~n>SȳyhwYŋ F JvB +-2(k^b3c4=DWM$zUt*th,Сt6M?K\pQ7SX/?0/`/V\cV,Lm%_kq V3D_C*|&m* lDZR;>9\W!kKDㆇVi4mfxK FݬSXs {o c!,^9fz!cZ, N[%C WO$IO$zNuCm'6]ޔc°–g5aQC ht8Rȳzz6+wwW`K3s:+&BXnAk>HtS$?O Cׅp\HSEn1r&cdj/nHR꽬|ͷJ,n`&؛,ИdMUI*;ĥD"{"CWEofELcXq"SSӗDUĦ-p~y; vg0B1[g/7W .sBCKv6|ZRD7IR =ǪaS-Ni8hZ} վEh ߴXݽZ9XPa6q8n^9-'n'{n*KU,|Q M[jf)\C`HpNyc3<:y?vgAGz  l<7fD"MTD}ϩ{v.g>n߉Rݢj=/L&pD"H*~"M=t|.݃ eD"J*~"M9݃l9|T7hjo;k+n~9" =ХүmKu4w(5[6'L$D"ѕ=;ڇ*$[&0iv3UTD"MzE+/OW{$|>RU4:y%@I^`q<{wVȱq~|߇*j:52 `^ Ͽ''D~Uq>J\ `GXF 0 '/O&yiͰXoo2$vtuZH$z$^@ߕԚ}m@O`"khq;(2|?؟X.bޢ^d;鱱Č  GRZO$D7~ÌJqpx) :̡G0SG 8#ɀ{HR,s;(p ^2uZ$D+]9[ }oI->?~WvWW]?ߧlf5:}'HWapTD"h(jJf{708ݼƬ{I _=>8797Evcx@H$ D^shm_וՃۻg\hmcԢnfz-O<~{dH`ВD?U`7y z{w@c3 =ŋZXa箋02_ŋkcGQyWi5$'D~NW)Mf(tfJ9uIc2+)`RoK9V> . :;AJSQ0cFEX#F*"a2;Pamx ޯ> ̖STm#]Z| ހVnZ Gսf\(v ෾Q3/tiʛ/A{C$D^2w+nI6`真廬\_ixs*BRniAR)0 ,oG46n @*m]FQ¡@*(! `+G*Fgl>ס ?ziĢ^`7d|HRNuG_A`pc8%}7{rO$Do?Ss*8,BdR:(m3Lo wmczlc2is-gB7H~ίbU@]w  값s4V 4Sx 7 C mU`S8ƉJeMybUa,W< @sh x7rijOZ"H쒊ӳz66xu zr-PF@c2X<ƒcH<4mIV<m3ru*]_P< >[  1ˎ1Lv;P9W)eL"P` `K>֛>:Ý]_G4'JGH:}D",i<>>M:~jv͐^ǣ[:wSݢF_/[0(qmK֒ y):Zf;h?pyP$3PB2ݖZ-WP3$6a%X팋9}@hN}ϵkCKVhW ?o295{M;}_A$D\-=k>"2G@HsyM[nfHi "i"i吅F=DoE[T3a@oXayE=}T[Ŋ^@6tP?y`_ u4CL N97&q.*zaPe>J,^{̞t<5 H$ ]Y=v6;>o6|o_7mSXf>&@V69x` P*'D~gҳVzc݀>o ӬBW7 GF_)d~pV,y?:D0P} wڮs sCN =E}ux2@ ;9|>z g8d ^e` o!=7~C(Oca˙ç?>H$ DWHz7.ޣ*R*{UKhԴE\Fۚo3"qpNjf`̯ i)8ƌ?]%T3VCXP; AW]Ud wbco6? U ;'j5uICO&xQ_%1/3ZU?"H$ڔT+6*sԞsxzj=:._|0K}sې֎ރoP8Dwo$PyH {ɝw0Th.p%8p[jS _6Eca[X# N0=Rǿt, :g^4r2D"r\btCa4ycj6|ɑ&V I?srڼM ݁F[_A|k0ع. 2[j2B;H+|Ox"+Gp`YWzuࡧK_7'C`YUA9mZE"yTEQYβ?ygyCǚba ⴸRP /WLĂ'Rjۖ*rKN!(N^>[ʞ]f#˻nu7H$=GҳS wlPcxiP)g~n)8$zinPƽnq `4e0A 9|%| @n|Iȹ]< G8%ͣpD[8HK7r0U8)>~ r\#οAs]x@̿{~{˯=DDTRbz֊l4gNA),mVNr4DPE>vJ9Y1SϿC'x <0\ƑA%EB9Y#_qy9w2n'@AƑ#۴okOJEU: sZAJ2rD"ѕ?@;U>,"Q:< >+}"H.Ubc+yYj6nUŽq6p]oɳ;%| 4~|^7.hwP.0A y[Bk~&6a;73X÷ҵ7:[ѵkVڒ`ZF:D"I*~WLT|n ZVE9Y"OAj0>S3afr6G҇S8%RD3ɴXS53]<Cɽ GPx)Y# m݃m+`m4|< s>n˥Ù?C3C$DWSRbzg?e֬Qr}noYCBUcmc$94'3#pDΊP$%B\suV^-g 98?6lvdÐ'xZXy%#(QHJrgᴚ=UoěYY=dpf$*+32}%X0*c !^Prze/ XׇFydWwD3ghqx )< '1{΅¾DweB҅-v?MdU"̦Cv4t v5VVF+ S#fBŁ\QϛBaa@Y=FQ¿0alt'c);J0g70{[xh٧855N,dk|;}a ϶mwdk{Ev.#u'1}yBJ{_H=IS{PP Tin릔۬H͋JIfj_?}qװz l^3TN xqՇ=>|X482kJ\rϙyW 7!XyoS0{N0X5xM"S z$ːnSy=1f IDATb 7\z6[/Ʋ%^3Wm?(L@R5LNZ@Jv`]bޟZ&Z*! @57 69* }̓V`Cx@_,=E\z('<>=|i[ZƯmX~΁>be8yU IXAG62{&A>J0U1ta\0PHDIm $ iϊao&$@`}L}L(a 7؇Hq흽SֵO6[HLl$Ěȑٰ;t+ m_iY:eջ0+yt}l=}4)[!c(:/ 4FӼ/BSWae݊zlWBٟ|Aq S0㷬2u*\S#r9x܇gupl*K"JbA5q\:صȴb¿oVEDZ b TJ`> 7 U )2f6C\~w,ݨva{vncE;QXKR!ܔSp0>.49_prtE횐. 69堐>碮xQ8 B kгI/0kl#[0a]v LCl,;{_ o+mطmwTk& _D^m#gWd͢VUg 2DGPZNM2" Nb{ÚܴH~,Rd(PabKϥSH Yv˯ J>[N>{p+;8o 6O F{Bv$E(h69:B{a49kA%< %C8nT8&kU=RpoZƯmzzf}dylb2N͋ԩp_5t+Uػ҄ǥoSr$5,Yp׭BBcfBt HBgo3υ41pux&[i?1zݮ}f5m'diul^ " e$cD=hg,--!q70Ş׮<ݒGoפ}Kvp/D!60jb@~KjI0W Y#UCw,Lbm.5vI@"t,:A#EKccCH8.|96F>C Q ,|"kg,x0`-1 h+Y_>}࿛rǗ-~wg"̔{݇q !qtc@j)l"!$J<LO%CsbeoCK_Z׶ Aa՘GVQL%.?]aLOt?cTW$GЕ|aMaiM tG"2SF.Tfbl#ŭ[z~:"$`Ms1#b!F^؂>C"`b& U<~1(Þ]hVM-K7j^ sK@X1|UzU0`¼Ł7>K!ޠ0"+Og{e+C=wcH!`lmL7p{IK%߷]K|?X=N:B!ǀDJ3j؉4*vj.7ȓ?ɘ?o☔QJL{l9 qœ(mc93pz"2cZDTADZu9޵A"rp 0Ɵ1tՒkj t!_}P962gH ]X@[3y},p8ȭqg!`8c{6,F'Tyԡ+Z.칶݊f@ļCm) ~m痗2~]NK5o3Enjd:pZ Ch9PVg Mɴ>qQ S2/eZ{ua],=hz 3`VxgToE38d.Lo]x2}!Ю?b(&VlSJy~;{Iy}0'{bwcOr;n2u{cöj֯G1fQ;{ֶ[^x׭<3chb UK83]|Nd`ü}B(C6;Cԙ8so6IeTe/)[Nx#*$؟-|movUd)5jV 6a;H!ˀ @(#F \B D&gO9xQ*Pc2K5@,aȃ<51M5`6UpSx 8XHJ4"74dng!p~% \6;k[$lUSvVsĞ݋*&ZfQ\\K! ^$[$[5:ct1VХ)[&D3g/J "xk5lCp o~{uB[q`< k>/^57پDպqVBM%)s66$-I&18=ke3aKGCms7F,_x_ŭ/4oWIBe? J;)TlSPY6ڕFc#UnT;&9t7{;|O:"34b\Yf?Wrrfv؉/cGc2toTY8{co1@c)c, Vj@ F| # Z^U—nz@* /z>14ALo]l`:M]6~z9m{Ï۱cB>z:Y۶_Nڹ/CD8C7 j^j<7 TŘXCWg#(+9Jzi@"Nk}@Nk &*=SiEL1Vq8=q6,Qk9KԹuӲJ>A'6u!~: wy!Q*{89C X_YZg^h} ⮩+" 㝳U T+%_k+ze0;y<# 4V:jLa[yؗ HU<(W^(@|hj]^b8b IOUy~{։\FS=8WAzn/;Rq7;3tNy܉gnEoqo ZWڊ0l>{u`wxM5*qar-Bt N7o~  >. H8v/)O8Eu[wWX|ZƯm-k{n/<%ՑeCA9P[uiC`@rwôb ܙFTն 0A+/n=rF6Vacb&I9/.g2eɎf(lx%/`g/^!Y#7.* (OE<a]l-,OgI Ooc^>7[8Jb|>}5w;/}M[GrN)9ę1A+-fnM]f So*9|ףp/1~#Vb͜ F}ݷU:X%XAwe.C*FdG,r"G*v0V}ܿz g7v[GN!:^ w G|3- eC,wYr}? ;50jx Īwe13@Q@.}' {_2ɚR> ?#"w~=|uyfcQ~m;bЙcwN9[FJ$Yp Ȝi3@m \~d]r0HkŁ1cu9A/`@97oс?`Q_2@߂,9ob(橿ocVH1Ν9Wqq76 [y7 {M›=U`Ion38>x]@2n2F'G(wλf_~b4ſ1|O$,XiH :[Cs {lOTe W1~:qng%QamP PȗB|>ɘ u <)K6RLmM_Zط[e cyK|AR L>@KS8 6֮*qWpvm|?SJ˸8#Ǝ 71|(L,L83y$ ʶ :X }RORwq0v-6vu#t?Zpц.OЯg} П,.O6mK{兩tAX2E$Q…6d+uYc ۮ],Ls1f, (GQa/"*yZ/i}>~ D)Ɋ၂ MNaл8`coY DZy.){v4}w>K (2>OXbcoܹ5s9t" 4fE:'jA߷k}1ZþH[?Qqq}]60.uH8܃~ sd-z\5U=90ſO@uox4" }.݆뵪7s凴ds7ٯf.nuly>т}ObC"*z7 \bra a:fz>Eba_fD[V'p mJqiZUT3S'aBim5;$.n5pһ3mNhz tn2};3ݙ{wwLuF\Iz3wgs52nY^-g>0 >󻦟i<m:Z<\/\PT)c)yς-zL2p"ܰ}=DJ1oDaK 51"%Ɑ1٨E ;ψ9vR2XhnѾ=U@:i7+X{^}ǁ?'v\[Gd珼 Ƹ \J^^[7g\bL֗A8K WCvŸ 6)袛DEߘ "cj9^6g¹FgyY?7n܇&a!YәauIM {/Y}}bJ_ jJ\\"]tqbi*<^v[qsk* ܬ0]n1&/htI>޵훔e kƐug=C}ԀwxD ]eS&?{6;I=|ЍƓEul.y?ܠ? k@h8Bٱ߿SkТPWB_Ħ` `X;ey}RS +|9L.dI_D'& 1:"H%wo^+V+ê!f9udZ(dV&l?)'<w;?q6@ȕQh0?oXqv 1(O}(=lVV`#fcWJ@$ڃ>2'q?]?#U957p }Ob ~KkcUn @`}V?_PY[ȭ9=7_0~Lf ͵Yv"2'!@ d0 )3b`l]C6c>s,;c|O@zƀ9b;p<9^NkY<'x`$%/)¹Yw 0QG /FmbDAr=DYLk1Xԕk fE=h2WGJ~oi|ҲE%qU9ZѲ}ы`Q/ZKS6F4k|-Gڷ< Ue@ k[eC([`+kZ)3Vj͗k[a@]U}< A7Deyt!\X N*s(u_9M&&߻ѬH˴R83\:5hk]7dH i2FlM #I ϛlg.p&'O^ >PKeȲ^SoYO[q#+{bEEnkR7{% EYSw IDATijmW誡qk]J֕se-?nQg`hHMe,8ָr7I3`G #@jp#[v̧Z׶ikmG팁 `J. FVl1+&L`!zz[$ey%x9OPyd/͙57 fKxY_8OG.LiNA/17MƘcWv,kC6ԩw&"E/5*(]_-5u{>8y`b3Q)ęD ]0ӝ&8CM*u깜L`j^}ua"@rk1Xe\/,C}։/".[/6 s( |V޶c\Xcy/m7?61#j}WDn_>VPY3fi¾EЩ"`@W܍j>ǏpZsd,`Y`}<珇qo.ojlԒw6m})I9|d4pz a 5Bht )>u&b d3v s#I18Y1M}2a.-#5%٢a#׼l׋?}oB]ɿ$0xv0F!viYυ #rLL` lX_1B9ڳ=ɗ1FkEpPWdSV2n KFพ=#iYϴ{ٲa^gyN",.({\V{Ͽ 22fnջv4C)$Vx\p)npȕR@\8!_*UD3BngC61a¡+4zGfY0Hf#/V-E] }Z-}ZZ :U Tle%婎mbZL"E63;1Q5YkrqAp(F(q !q סpnWC9&n(A.*1ƞݮBVʮ I`cM.^q-W*]mqkŋт|Ĩ޿]d?/ Q,Xwh/<%rA*6OWd;F+@dwI/ U/v:pM j^A'qao g> \^seիK;c6M&c ׁ݃3&sk~#{QlĢ0&+˲|=/<+kLj_OM "Chr{!Q ԡEU:Fl̰;QB%K98@Ͽ׶=<`3;sa: H[;([8J*A Xn&,kCͅME=֛7GMa56oy?*?W򢟋g'0Xֿ/]EG0X;-׶lX#5y L/mHp! F>Zper骿\=α U`\S*tfܒmM'S6ж 5 .֩]cLpĥO8`ӄv  ZwqTL ig3F"2Lg=(P1xw>\{> D^:r!BƐާ/5 onQP}yrHK06b# QNc4e1FSY_? {9L lulqR~w{=W2Ă`<-쵱.#O`ocox6^ş߸*vTSE-x (qhcj-fCI1|OGE ,r`6)W'jcHB{YvQl` Ѱ(QGyaûA~K;cǦTg([V̴(++jn@ B?ުZfA Sm@`h sP]n.CSw0U=4~žmTM[ ƫfxIja%JNۜq- +f N'lUd|\I%6enMc|f1^]<[?8 HG@P2^6ee(ﱭ7 (vLڶKkU,/1E;&&l揖k~yb&JhO2x]}m` Jú+ǒȂ*1OӍ+KdqM9-0sC% &5r.,#:,vΘse.?nX}TcQDT8o=RRxŋ7~ZlUWa_ @ J[7Ԑ*ڂYcLjnէќ3v*w1'ϳHݦ)Idmߎux )tpy"50`#;v;D?%ns _v>4,yT0TCqlMO2&[-|CqמݥOe:볜*("AU;KS\,)9+Ho>mYlh0NQ %qVahl35?L9p ;~ gEj`Ȭl\H&#a]@U%M݇^H[[^)\J*FM;NLNRºʽōv0J}.n={ծ!'{dׇ9ٽYL²puJ]`j:lo1\~rb=ϫJmND:+m4h vǼ,[}_x64s_WHā+H{'_C3Fƺ% &:~pQQ)U !bf2M4TXW[}~`?ύS,Ngs\Ujdߩ1:=BU{M,`n9;Xl漼NN9>|m ]ۙ`j0vLAي5>YxX>0eպ;(rj޴"տy}"|!N qȞ?e} MՎf=!3vSn1#e|O2~=go<:41%cƶd$z k7DR>$y 2e~Q cv/}>o2G?I&JP-V!gP]xn[=ԻT6t½0p`cc ilbhܰ?ɍI>jTq65&bd^Ÿ`qPn*lq6@ɪ_ /n؃[DC3\-zع߳x{d< f@l@a=C*-/(w_j -0|Fba#O*H=C)DeM8(woOmH0{rPH‡ ŭg,2)̭vL:')j Hз p׏ŭ/fr-[kh&S}` 3ɝwZE …Ai4jܽX(􃒩z}; ,1tc󲎨B<`@Ah *}7,Rʼ~R/>rM2&M&Q#`H@u XwF;fXSOۉi+[&7Ope~O:Go{"[څ@cMoQT*s"0- Nmm;ڍ/ +UO {g;Ji6m%w⻼ etVMcTl.g"Mغ}n]`XxZS,,\o *9] -֝|82Bf! t@aޢ`많X8s5tPALе^߹9$[EÔn;A b圆p:Xk&댛c.px ??k*xt(5"|onk4~"c`rq\{Ð,b*qJgyB.-^b;po<3Z qV|3vM5_o[?~7(`eׇ×~|⹶C~>Q -b.wqqql#| Au3lV^ܺ; U 'X(dbBeP+=P!{;hfu:P 4UfQ̥3.=6g6OVګQZb4Poz+:h9^nGU2p~mbr_&cWKr>0Y>nkcge5x+cz>u|.hc͘>:lͥYKiO3af+ '6Klgd꘱~QeB^o *ŭ1+m~u#!+ֻZNׇg퉼#/u`8}Wm|#a˘bQc<2~orKJ\z~m;ԑ"4M &$'a%΃?k'|XP+ *H^'i`Yo>M9v@n4l!텕5L8#`6VljN W*HP ecf)&M&&5@Lv    uE]^W|{:?/𹗠_|al¼bՄ;v MU3 L_*DB}DJGP%/R2joI55jכ .bdMej^~13|=膅o?ڮqS 86,b 0ܸ{1 CuQG`2RK&nsş< QJ"*T}u ig^:B&c Y0GpbE#[8C"2:.csPU]k&c |ǘ̎EDa x邊Y[}Qf"OGtoh0i7s#E7vלsDٲk0z6nݒV t { Ɇ)po~7)yWW qc.&Y~<{8#P1q6\a_z=Ă qz ]l]k U^~'yLZw-n""|R\ģ,L>۷|%j(GbJ+ 雷2 [fr # "JKb)I%辛m?B#Zp߷|$of6#˘({)0ǪL0+R(kռeAP;sf2, wƗ(czń-xOj):GvͫyUa=[<eF5ۿbְ8[+W#-Dmɶ-bMN+Zռ#\@,\#FO2/LAAnJ1#dZw1|^c\((QMkW+T_%D ڶZ+\*D"5ͬ`@JBU&XaUԢH@$bee47;^[K!ĽF\OT.Eoz#= 4[){fh_E36 ف .̶89׿e@Zq`tt=pٰ.ĖnyrųٹA/όq0~EwU;>dZw+YsML)R@i9ΐA@8nN ^>'~A_FP|X}uB\4B'~[;R-d+ef m+ <Ѕk| y虭@l:qf3Z14-llף0!ډ3Dr[[DzhQ$ VT6CA[p>s8*M&cЉ3'VVQq)0aV`ەgBbٛ\1aQXT|>WTÅPOJH#qY>A/M>y:? 8 1RU>N6LՋxc;'Xak6bnMD89}ZWK- U0nx1kʯbefۧW\$ &Lf5 #fkbϪEgHIIEP0G5uv2xanZ3|8+3Z-tjG'Ӹu$ M&Fgwt;B9?<MN |nC!ĄsUC0J_wd{~Q6f>E]zzƼlXymaa^;x;F, 1pjck3vs 2`ОsUF+m]F*r V=|vU2k\p OX><^#fjZ|c5N]vIֿWpl+D)c[ˇJ=4y3b_ 財0V*Yԕ ¾[g2_y$4_3~'7ozCIJ_"ZŸԘ*v2lE@Ck6@LM P#w1}}7]J ޾KE€X{w1equ6R%]f 9mB P!𕧠u,JIRK t>qMl2K@s2 L5}O):XBc}pyb{H^~-;GOA×pq˔q4@[?+"s9? 0|)DNm[̼Z#.Y-qֶv|? Ŗ aĆJ(0BVPann*/CVycbG m 9]r[my;\EB$[-qkl&qCW⬔;|Ӱp4ϫ 7=(uaX X, 1}y]Ufg֏*cﲼoEG}sw 1{.~).C`!Duش``u ܩh`ghv_3Ҳ u`9FLvy[kb+_}GWk|3KXJ|y'_j+5pp~¿x=ٶu[l45ȫ,fhevs׿"I _},s_9F0/R2/\m 7_ť m5Mư/Y(ckے %2ຜF8y%qV հ (ͭHY*a8sT#T q3vtaM[TLS:40lNU BDw51mϟVnka&WL7^5Oغal>a_v|wv͈Cx/~Y#(V9&OEk5wUA瞣'R%5ՕR{ ЉCS,DT{mQS1Rt!b",.^g_,ki'C"%.Cܶ)J|c|][7Ϧc9B"b7_\„4118P}{n5 lsolp~_N,^a kkϷl{㛶( j Yjќ"d87`23c6}8($pC`.:bCI ߚ< ?|DZ0&fdƞg](}:!/R;۪ޞrg&+Qxغٮn>{@*W{8N(}ΰT mH[! ` wbA;Ƌ؞  u-(PO3c@2X>Nm;vy<L P:mGy&ܫ ȀOMrB+B!ɈuȂG6\Ě=E#+@+럫@`t1 o2ubv8vB{Yl^:rBٰ`Q!t91`ZY1ڊ}w{3+ CD=@q0qћ<`bv@5AtѦ'}@Lg=&1nhsǥQj\f>){09T!uȕU`9hXTfK^\=J*8lRR1tyĬ+'}ˀ(G.4c|p"c[?>&;@PHs"46;au16we ^i'Pjz%3mm'rnv3n#G8Чj "w]k&ACD*F̑D".&&F,Pg>r"̇nœZBȱ^Fh_63B<Uwg (K6BxF5a^tT7Uĥ>Q;tLfNA@Y(aV؃~Z jNmX),GjJA/$+9~bgG,*PHJ?}7%.@@49"5k)SJ23 pjW-9![]xD`r5% #Jo[ײ>wP8ѹ{2~xO^ ~3ېm"Ȅ}fEZa1.1Qu 5Bh2WI 9ܕ*\ aja.*2Y3畭 8`_`0o03dd%t'D 4fjؖ@z+_~ _jK1A# s^Ak ~;Q)i&.n޶oӯ[}igX7U˶r.I+elb8 H-tB%'B d'1 "+%gYDvR pM>k'~~2>DI60 t2Ǻp@?@,rdy+ȋIkp8=4#9 0X5w$|\ <ߎ%QJ45~5J&PX&tPX2΍NuPXAXY\d0:\=OS=S 8RؗXB&Q"eya1K} Cz 4BbZ?I#eyfpF/3҈Y*V::&vYDŜ}hcN/M:/O(q |RFR ֶhФu ~H&|G0P2z]D9[RM%TvsX}`/& 5h% 5O\.v[Ϲ v 䆇oK*۳>dD F"}aGZl—M$R23>X795N#X^i}tО\2$Hv\ہ`vrh-hz3?Ƽ_=| [C۟=Ϗvbȅ]u9gX $!}z8̟g8;Gk>?F#d&9<1+3u.Y `@2}١苙+2MƘԀh higRQ6Vv>dXQӅ ي^s{>Ϗ,`fT*]bn"`*t B23W |1>՜>GаSgFV$@@"$ گוUhAg2tX|>)cDָBt]LN5yO+e{`=z(îyE:-nC~=s0ksTG1] &Z4"Wn(Clb2FS HL>:/a௃Z)-Yy3Frb1ZGsQ0>rbнad3>hbwWm >bĪOgMՍO |0}A ]}l>3ޫ>%A.#C^|&D۝.0v>`@qZ|hK^ڏjyːlgNdrH-`ZxÈB/ "P1_tR j4o# U}gNNt)oTäU:> ?:V |$G ٧ Ae0H9vB֟$1kEvkդv߿qâˮ/vݘ޶xbA1">L4> _ҡW RŮ4&j0 eY!o<0 5sk]$Vȱ,RtMHFk, 49KuYvBܓg!\zu젟{p 3[!I\з9Ad.7n e=.nC4~Us͂ s)t_O9{&cwwΠs%|2{u3h:ƭdݹJ6Vƍ:d wDR2&;'dZƒG Tu= e2J\c݆wZ>Xͼʆ=ϥ |Sv/:z#WOq@m1~pu)=¨E"z?&Vo_n#{賏sTU)Tl d{ ?{o+Iv=uNUuuje~,?%p3d˄%! `'G@c$FI`?@ h~ĊDA"3B(ëhiH+jHpɝٽ{w޾]]ԩ8}{N.uzyY. hb;o}HqPv85,< *[p!"8ew4 ҿc_N%.e'{L BOsmo( 9G?~X&AK E y*^9=i"g"EC$")^{Mk@DMP&qVfe2iRڎ/yJ?ew܂M}~6qIs &PF!, ڕo֔+Lvwm]Ƌ/k|N]?/]A-6yܾX ؑ|~b%|jJuw!n*˧IJ .yd~7Kk>e8n(E~>tdZvZ|y\a̙Gg~[PPƭe\0֋79U_{7m\ZtO? s[Pli>밸배Юݩ#ٌ Ux'h;}7haCL`:]Ad~߾#T>|!,[@%zfkWU(Nnس7\. &GQ=JKkGo *"uwY)ÖKe(?r='^ݠYkG+ھƴ9囧p7В3{g;=#0l@x+O~+ğB#|5tyMqN]$HƍJ)cX$'0 4^ˎ0u`d7;ˬu.c -@./WNh۶o {tMq?p2v'3GB3ңc44t`)$fKp ;/p7u &uҠ+fvQb`*5 7+=/]vo15^/UO7=Xw؅h7N2CznuS@^ 5s\^ϻp_֘4Uhf1ce7Ļ AI/|I *|rrfGogxgeʡo/gwCYs SSh?Eܺ渧RzkҌK8j~w&id]+$Y 6K#h4R>99`~;kehOϟ_?rmA +z K!\=B]lT{C&$Ш PA r+ŏ5|0,^[n2P10r: bӥpgoŅxE߻oF#*Or-NX#QBaP>t]'Zށ($㼏v`:9,I|K`=$>3α ]b94fHV 昬XfY5dAQFs&`)+⑃@6 ˜yXK[6mǃ~+o\CFlv '}|>4ЄQl/ ?o`&~]\&ܙjc(r8$tN cVpᷟR9o?#d[Z( sΥMeIuGb®߶nh᳏*|T _Nnce4ly:,:]o@_)9W wALTºq%l06MY$E0Tn{k(f<#YlPrn,Q*KQ/lj`nfGUorЈ c)nL)ɣo`o;,Np_ _WpL7o_ .[h|vbUu"חnK{71'` `7A 0 ܓrwW\0`c}:zmoza9 :4bJatƭ+Ú]l{:y;gN,  c۱pwgyX{>Tcbgre0XO: ;KO=Vlkս?Q<|e҄ݠP`6B 8w(.A#1w_Շ7W#WPBQj_.OQnr:g=t/T~⥽|'u6c\XҺoމbٸ}c3?=V!>o6:bAY}^nWaWSYDa+vQ̺ 7p1?E8} ? pŤQTV٫-`;RP$ABUzU/ I0<bIUI(J)Zg(u+__}_To ƣƣC>f-^F%ds?g,t IDATS a l21td,c)ȫ{ħ0 l.rXQ-,pdu&?ѓ6E %aM;ކOX&>vlm tU =Cpz1?f;ao#A޺jy^`M1[\@]m _ɯjW)[/vS(Hr&S,pڊգ4LRwl?H(BUoB=hנdt](|3 [ʨG]AcZ /<3p ȽxΈ\]<K}Rk.$ 5ɀfE Cxee~|62z.+wlamw+գ!M-޵zA Gۇ#o%dJ@`zQU%~DȞmy `̊?y PQxE}4~ >_{!Yvm}w24˝,I6. GmEڎw`7YlxEW m,=4yk;mGjQʌЄhc+AJۺ)X t G1ÀKa.vǷa+~Cǁ1$Q>Vv={K\uDu"wĎ% ػG`Fw˿0? i;h]-M^S_}ϼ_zw/_ le UXvSkW=Ɨcg · Gs>J4al 5Rc46n]&Fң@P#x`CFnd_+J6c L 2oF`}},eBqi[;~>Ѯnn%evGPF-E@v5s nЉ`Ub ]s^\c˸i3ô9ŨlqwAfWP&v اZ\ (1‚ƟaN> ul)bOS!"5y;&wP8[^@3ZDEp`%\g.#SJ*z4*<7`." iu]%HrE $h"'!A\MS 9K79?ꥬy}ͭFEߟR»^?u/]{@0JRI~%>Z^n%nL={x)~KaRfI &+n 9xLc5 d&UFnDd˭xd;|xO.AR)QUTcTg^2c? = >pb>~|V*t۝lq]g e&( %fXn ~e b`橨~=]B'^\(E`Lb`9x Ąf>NCU lݪ{-I8W7Xx?wx}C "tp l90+'> 8*UAEMFY!a #~TF$xzK[x3]lvFoXg@Bpv3Iv@U#H[Dc#K/9?w'7jut]X1[=(&M^G/.WoB:rB @01 /C(+Ӡ*;4G+ӠZܚ] f'RC@}?`W;xڏyc8Mb çEO_GO>VPgR 2,ӉA0Mmg3'`c41]}hk]p)&5nw7ҧCE݂(Z"萊( BZ%vK$P|)Byu'KURi5"I#uu34ŻA,@%tR`JβuWRB'2$5e2M\迟Xv<mpanP@)ˉ0xnJԪ1l}F'٠_O5ճHw:aseTE4bvzwQaD{ldɓ{Mbh?6}[ أppXi{ Z9~;dYgSe  6al0:۾do$u=lyohbk(b{0C2lW8Ϩ9fvm`qb ^n njEŦJRB"`q|[jd +xEP7ȖAsoO%48KQL/z膽Ht5Wx@-ێVq&آ%,F "JүJ-GBn)ϝ&a`\3#;o2wɤb$SFezi{e\,uPE\bZ-Q+1c&;5*Aן=(@xw?jn3g+lh:k+A3^%yҝDe= A/#X,WSGs 9Fs,ڽK@Acwr+p9Ŋ ;ۏd?J|*/qm?<9U0T.S:Rz4MX [6*g8ckn`d}\7Wu`h_y]$ry3u?ro_SH{!2ڍ?l)sIq}\ML.g8|'7\pV#Lszo2z0}3j&9tn R֓k(Uدh][%F/:f^EMÃ|Z 쥒MlZ;Ns# ĸR&T;Fs똴H*mW#*9?}hα`"kJ^p#MN?{iܼ~>`RK]k`l m_1j K0F,)C/1TRv16n-*t,9R3j}Ϡ_#ُ$ ?v/_e0@BWF/9^ ;zOY'8VEs0 IF'-< R(Ƭ̔IT@7%% U+9W4> i ׏cXL,M;̪.#.1gq^t~PbǏAIk}R?״A7WhUAgD,=3AO㸿霆nÊrYoS̖]n2J:Ej*(2M&gH2@J2Tw/g s̘SlGG0g-:f5_gb{Ҩ8,A<ⱜ֙{e_~?1YQ2GPھB;fׯ nPgUN{= Zrc%u4)Pֻ 3M|9?GC2(/_]S?Wl KA ~WcR6C# '"w^~O8yauuU)CDvM0l]9m tɿ B|JzvHAt>|23zKF>ӹ]Ĝ㧘TO( uG&y:M}Wfnu?$W" ^" >#v0{e\d\%zޖݲkJޔu2`*#:b+eJ4"I^dT= GpX%x,hrw!GXBؿIQ{.Ho^mv<MTc[6)ۘ6KXQ "0@{䫴hݚ]$,zS :}Z@Hs̖ Ld̙$3_ 084c)4ps=}Ul8ߚ&Dd6o>Ygz\s()4h#oKч+ V}AL^Qeisd TT){*;|$Dws¡V-f3KY3ѷG $h9VBbM-,]d:3bR1$>ɴy]e4y$bP`#M'e_9Ʋ] )_/-anTxs(|0N[H&PB,fovhY+|5 U-&MMDr• S!~R ƴq6:@^gN F`tfgWl 8OR )I-?"ʌ Q~PcJP&q'2nkʌՊ$ln: փ8"d7* Ɠ =WTM%Y3lAOy=~rF%gsf8)x8K,g(6Up Lwo 0}6ncj/%XȮoQ:ɌVGf6Ηi/P]Bŀg¤,REDǰq@iS?#Uń(Y0`7sH@Hx'솾D{5\׾/P^x!; ڌ8-ێw@~+AUWuB+͛@/L2ձ{) ܢ<qyPECv0ak]y??b$ȥ \2-y҄dP98$\/S0*_u0rlU Z8hfs1 JL,U%l!er/?6\r|/4=vN0xhl4>^M fI0[gl SK1ϴ'h pΦ\[9v˕f/>`wޡ,$+A RsiP$oR7Yd=}gbSqcc;'|lKrGg pQb\+ TFՊ'*QzѨ]}z٣VE[*뚾>@he75Oy~Wݓ\Y#%YYld&,oO,L IN9`pS(kʑMd zѬ%-[H10X Ui;eK+X,4%l&O)USlF %ouIR%Kw=l0V 7a_WaU4<.<#f=7\_[жZ223ؚ֖)#tݸY@G=0"цq>#YyӹKùjwgM){~>[~@.s;npLis4F43r[TVLKz7wm̢ciز3{Q"r5EUv6,~f>R躗=#bF*r%(C((պ@"SMլwLFz੨F fNdC+>xRQa,7Ɍߔ Hq z-KNC YUEx썷4 I) hl^\nA|Eg}C^;އW'8شu(5 ܸcy^x8zжh4xױ?}6dڝ'c$۔L165R~)j 0)'׃Hn6}x;'t*30h[o ぇ, LU| 47rtIlA14*Z_H(=#6*0Ddo*=fÃJX>$9<XO ;GyT|܉uLe J ebse&9|Al(mJ!%0+cJ}l?h\bqGį'QDA1mi{ϲROeT>r/7 fט63b#GG%D4Mso'9@/>4Y?_Ǜ/lqvmv?Z͒׋t/#U8q4 K+솛Mc)X>ngR7 `֙p;\*3w/mdv0#.KM=rIfL,|:׀ӯgUf',x,?Բ.hRLrQ ?ow7;:l&=7hteUn@ >#O\uvh8hhY ߽wҧn\,DXR *35ѡi3A"K`\[x<jBOR^aK_7x  IDATcU([fTOOڊ$u; cUdi<|2A S_x^ΐYR`NgXW}B9N"ހt"\_> ٴw6,;'s(Q @?1 u{s9̀j6Z9'l2^/y@J#=N\wcٺZEɣ~ (Vq7KYԘ~1ɕJjpeS&kyR۴9]+ɒ, ӧ [uQgw l2#¡5xo ]*&z%c#=b1m>`cɋESٗ'{VǩF^N_wi2LQ6#&ȾEGRQ3*:LBYsɹD1gڐLfYl,('| I8l,uܚ]S e* TBUrsS7 G+W]S?3l ,Rʴ>$\THyIm]{NBoc'o[0hYokyᕙEd׈ G[63WH-m v1Cb S^˦9M90=,nv<,_>=?'|_m)H%Q|!SdO(8hBOG fڟ@IWQyJv-߼4ez'E_L$W`UyMy  P6Pi6{l$C29?3KU{ڗ1Xn]]< @됨|+E+~P2dY[!֡튿.p<nИ̡"Tb&?{u=?< 3vR1m^톲oƺESY˶%syqu9s<'+XJ5 %cܖzxu<%vc;ae6+yFeX=Ar]ZFf?D3zJH.ur MwŅ1nC6J,qo^ x~=>,^9K!wAG lLҊŜ+'R̞I&\y5bͭ7[xԻ7 7\[@~ J^צ*`:eV^0XLD܋ a01a'гo7WPT=ҟQ={.^2dj>kUBTLt<BgëD@Ar3giO&wq5O`OOFiڙ7⸬]ւs'_1;"7vR5؊;6o7FsY+yyXmvl}4{IE_>/E Mࢆ*OFG ϿA@_>`d8KF&@p!(H)S6؃>zfQR5\c5( [O~}<ٞ_Ï/؎;jw Ew&4۾F"0.{vh5f<4[LA_?dmD:ݒIswn &{ms?.Zf. + ۾@ˏJG1~Kͥ2c Lܠ6Hw] EO^FB~"U{jSǤ(4EfCckTeg7n 5/Sz,xJnVQIߙ&MQR8Rx6q.:;X7En?kvGw?#Wس/gWظLܲ%kpcu3ao_+9kXٸ4ǹq_czF _%'6d ,Y(}d@7cߕ9 R1Ei/ fGs]:$5gC4znPqÚTTj3owCK؝>*(&x62*'zpumx5 6(|jW3ۭ͟ #rZ{E7A%#,MbTrIQWm0Xؤ%QP(*6DqMyU۵ m f{*|և+z<4',=id2h9G۬ vl4wgPn"ؿOX#Jp }<ӡ_{B3 C#>u"I}$ Y b.tM&<OZtH`B,0b8'uէjYhN`iWz@G Sefq%`KF EijuFouyf^U0ϔ.2DAs/ǣ_S ,Ϲz8~7ß{f?(Z!URz<9뜆2YeKXJjhۙ?W`7h6Mdnrh)vƷqjLvq=TٴfCܦ>?]W̰)3 R2UXeb2ټ.3y^~۱>CYpI69R2lGe7}}+W1.+XkYQ`b˶2L0u+-ێXJ6hLܠQ&++/OO8*{pMQ5p1~`wCV7JpIsE%e7{eqt"NPEcY]I"ۨ(❪"B $%Rc1)@P?Wgpbb.M=vDzoQUɾ״W_)|G^Z9tFax1-R2yOd㲛b,kPnpd_`gĎcй?([q=Ǽ݃yݤe;+3{;]S\)>^@a `ʴ.B {${a m^MT24?y׆ 4{"{ro;k2`Z <9\& :+#3!JMuad'e70{b>6w1dx&IO|o`#ף2\'B!zT5<2d>CiyTѿyTYbpNɓ٫Xޕ%I! (d(U$9?EeT|ʲ9U%.4]E+|^i}kkFs+55+%MI^#5`AM_^!E30\ `ԝ VW>h깷1>6-807FQwmm6$k܍ٻDw34y M+m[$hlJw`P>bw9V޳o 4EL,\2 F`}0{5V"ox8?N%%16`)5W˲p"嫘G<3[ڛbbdys{h/Sey=E=s7ڑbs ީFjlHL ,9ȇ]n0!wTDYFVE90`'u-̄72~I]sO?g"sGOF04'@A9WYx{O҈9Y{U5$>AA>HI"j /.9%#!x*?XX$\h, ?/m}v7,J06D]  b 8l,C3 x=n{xp_gq^/r 90Ȋؾ/x;.JpǗ:E4cp `͈'' ,_Qn_Kq\'X >|dd]nU FNTRS]Ml}Q) @ @&=.e@bx}*b-KDP$1Q]R1zB'K;d$oO ~胔u!ƾ*LЗ&jzݼN"^'Qc)1Z/>>Z 8M򤐻ka#5t8?Nj[^Hx/zymk(3{x8dN==' zoXƣqrvj5ʡyCdzDaYĢr/M=! _RLS^c2 #{|Ae?2R`Pd^:Ve i,]LSJe_)ġ r6LAK@10NwClH=]}t;c cxϣ.clX܆2XD7$jM35O.0ap\\{GpaVx >(;>r8~EOsemɲ6'-%nU8\y,&4Ѕ% [FɜWكH}xֲZ"ӷ9oaPX ˿*QQkA`zL*PR$ ŭ`$3yiM_As**ET" G'!7T)/d" HmNTNc w*wF,+и$ԫ _"(+xB0H Gɛh\p.ˆ#08 l4^e~o{oj{зa|'61ORo{FQQ"'oBJlܣ^2k.dʪM@~8cٯB|즜 \E*Ƶ/))dl_^dul~':W{@ N.φ1&g6uZnJl<~eďp|sQuբ6PHdo^1-PU0@n@4[ܝ/Y1+YjC% l|U|b|/iBV(Y $jX0rbۭێ{d{U8͕ ,@FӨ%"ç&^@Q2$QU]`BeaҜB+̡VՄ˭¸ 畺Y$A>{K&H\WDKz酪qZ>jnͅ2 x}-rHu s'As?: *{edrhɢJR[UfF< sSm:FGK"OL ۭl]D*;kԏIǻbݽPF+a2]`QD@ j*M%!;M_j{ z CRl IDAT]4 ={\%`:5Opb.A㢘Hoxv m(-SP*?/*8Ň#gh̷o;<ȒEURegE"Z#'Ch$´v`xHesjn"JC,J&,gCTeN#!AAg s,1MتRpw3[b,QlD#gbte^~ ̾c3X>ov+QNK⭂Ŏݫ.QB+l G"a57vќ1.Y/ qi"˺ew3O?Zy'1lQf>v+a'n0 X~-p=H \a1R(MxP@4mvFW9<V5yW-L9-WD2# YfB"0F|gL/:VھBE@LD,(z¤MZ9LN>U8̻=P Lb8zG$N0}ew~֓WȀ[A*6*IK9Ma\8L|H &aQi{Qj>vXC=tteeofivy]4WVtQHc0[^`iߌ~#_*zV.څ&xm` tɈ2}D ,,pM(V38|a/A&BY` !)m/ďţ~؎s9IDr)#@ pG;NƞAY6$`#D঒t r5 k1YU~CdI8 %J{4IX*C}Nb :m_a؇>Z}.Y % 4˞+o7g{cg)k|F"j.G ?$ȗ)Xhۢ1-ۑ_r>i[xFLeI&ʿ7#vIb :bQ9e[5ƺpUKxm`kd2~#ٕL&eAS "8m)&l*ϷNfZ48.. !U/C3ddv AO:n৞5)x.Km>b\fږ &lD*%_%h#<ցC}4ZaYP¨Z>{&9!Y̼ޡۄRMrVq*d#n7(k uX xQ6J<,/ ,6b =$$IsweSv<zOã-ێȿY^o<FfUFƎX?gcIXUH"nV%1mnlRl|ډ7(Եa`BjVz萌A@gjl3|";V<6bhyZEq2Pp2|Sh9OUPeIh Z;\F SlB"KJ8`|ցU1'ʠ$ 6ov>4m(A71n+$&w POUŒu q 3d&ߤsU`DK)?㓧q3i_ ަlZ4ocv`Y|e|c^GϽ ~ܵp}l@X]DslU۱3z.U3tz 887S I@~4QP ɡh<=#u$186؛dYr屁=v''X&Tڄ~2Vr5 q{G%7ʊ I(;Q-ƴqOXpR\%>Tu`7ͻuv)@$lI'Z9>dϢ? ,m סg0#{5@X%DPdr7ub712v'鱴j `. DPzc09!#1`Y&v#jxMheየq %{P1~冿[cAW^]c9GpJXHGBiwj1W=U4n3FG@'m[t(:\H#=WWG]YL̗j˕B3^2hbwT1 Η1o.Là"[qeFϩW`UI,)ھ/y?kWkeoY }e7e )}ЧE#sNa+ڙ&(kNK!Fz9 RME+(fϠ ,,θOoȇ?Rvl{* 5s{2{cG0 V e,(I޳(u-5D}`JE'ՁE* 0Q .4rMbX}+Be4(CIUbC,yʭL^O$`i|X9kSJzc;BlxlL\喱Q'LKB %UކĂgryXǼJY҉eyzМ[^k7Q0|м`2y &f⁥l~|7dy^&5RJ|<,9-E.B-+e`e0R۰gXh L'T8ۖ|Dkf c ȆDM,gϞI_O#tA~K0`H%` 8VNڬŢ沋`[7=&dvKrN%6Mc5 o*HT(PW&gṂ/.`&og_Lt8Y0cůK;oS.c ˸£1gMZR@Zqmm[|=`HkB &>/9t! pߛy2?_W $KH~-% 6`F,Mgpx%. Fj`ɥe7c/@f- /BaWk%$hq .K}or2~۱/OYIfrA4U# *f1UG Q#փ?p1 ;os 3%sAYf>LRF9 eJdRR3I啵tjOd>:۬ \R,` n^1o߅+ӱ,*W:yS8ͬWdSl]C̀R/% e>^~u@z3R4[G@,)r.Jm|hs97x-6:}ٵjUܛ웣 Hy{,K!_L n+,X$#o>Re'~C)iPh4)W[w xx'#ؿ6 llxR-_ NC/Ϝ޾j/Q4@%]hj_A_S$~vҜ0L˯0՜3 P08ٓ&K(d#b@$s[f:Y9UxPρ%AX`XB5 Th:U8W:H1(\9v ̨LoxsJ1՞>v+pvk&a iM- 9*[G Y9(3Cf-`Q-֏^CqkT'vdSELS=f7p05 Fwy3p{A+v >~S u7?Uq8. AK -{IJčUY,vbs5zS$s˱w#iу Spn,?Ѓ};PЃֳ2aDC5#yIi8iY쮪{Ͻߍ̬n69Cv|FVOdDdVޓ9ﻚq Fj+GY;*uVłzEw_2ցmbXUfMƋ&xU?;G@0Bl_25`Vpf` rpǎ /\6얟Rer P0(3MOprv*ԍA۠&l EZ0>.I*ca+>gj;nyAw9~~3ZDTq{13aMHD"b- :ktyV6_ZhAe9 eꍝ)`a҈iQVzL[o%:JZd+g2J&u@6+ؐl3o]`ݬ.r1lW*o\ p,r}b{h+;A4"o "oڃBÛc֫.+^]c`Hס(Aٸtl(ZXr*NAJZ¶e'UόK'sUyVZl Y+\ƃ>i(,D"ǏUh:cD+N\AaOзtϩo &q(qc>]}ۮ~4"7PI9J\Dŀ1qQO`Rl2T0zh,/)^5,9 8< U(+;gm|2TKlSeA&m mg9G'AT$ tZ]ۥX.Ys~eYBYg>&,-fIxRvlsQ#OU{)*TԎ]ZI3f:Vaț(0cZFg[:)u :Z^3.3a0=}jO8ێ[x5~X86mb3zoZi` PDmK|jP=Q֝0j3E>mM;1)؝zWd@1^[w~ tqA#Ɗ did jb.q&Lw.Uȓ];O,[)ؠ#Zd.FT k$xߺ7E 趲Aa>>=C 5ggV'-jW.dE b1݃@J`74z>x-&U*:O[sIYܚ(+.m38 e%hud RдF9I4j n>0Xu/+z?* >kj(Xԁ2),vuڷ"usFDyѫ3[֌Y*=kUv?UMK+ϳ .;jx.E`DkjaclHj1U&J7atlalM|a2g7^e: >3x5k, ꘝ»ϢnXGVS#Gm&XpٸhH,d5ƨ3hg.:N&jHu_T̫3]y/V8;^h$}?~ΫoEYX8,`<ܰ7|73S\<j`!}d|ljkvLy]<(+&n"m"__ɌrӒy>V'WwYP:E@Ȗ8cL%Y>K5n{|5XA5`rQΠʛHLϰ&l_{\]c\_3:pob8 쥸yd3p{1փ1֙pVu 1 stlJS _2zl2]"jZ@g<۽/lt*52?@N5VѬY>Q02x#߶ K IDATFy4u0Ѽ]$,EKxn_WFE)"֨5GO@~/>iw,/i{xȌI#ꐊbL<,|d_{g2EE߭'[;.!u3m^ vI1Ji2˙kphZXpˁwܭ縗SC{k?'Y 5z6/Adד<LpB$'wj:Ce>ϙ*qn l{>EYO=7mMcb{ش:kG֘A@'Xg)oݚKwj7{(gɴJj/e(WS˙OkyV (gϦw6nöw[ IcNums 7ъĎV ]fNag7ï]5#[#kМłw5g1mVqT˔9'ȴw@wtMd!#Gsaz CEtޡc$Ok5:߳IhLq(+ ՛:+-IكDciR iڵQoڟ'~I;')\oX,f٦EV5=i^dE֧puϕg40)TJm^]I9F [aek|L|:ӕgTbsi3ndzA0%w1ojFη/J?E}E/|5[Soo'Bm\ `Ԉj`!=/LQu*to]l]}4;ZbF>5xzf,+GX#ԧ@ys?pugkbXuYZ{g%&Y8g%F:q re㻊:dzb>v[ 3C5'k4xFjԙ6 qG"y*Mv.Qjk:t%k0ٽKrF.f.0/w/qb+zF l%Ρ49 ޻o,0j`}2}ca^;B: b*x^SYhg&b"#'Ƌ<#ӷ:'#&>qoX-+E;J0~y`,<8yV¸x.<+Qƣ:jA41rގХ3f,g6G;k@]K|@NvKM$H>6s2w XNՁdpE|oaqh9lʌN|.,FϼQi` 0N3\}'jlrwD>5{˃OOIA&yp=X]='Z*SfY,W:j.+I4&-Dspvjekcg4R亄J vwPgHh 8?L(Veق-uM2[`#@ܥ.M{;Oo{ o`c^׎0z%IFO%}$L@R5?`ڙgj Tcð}jt_ܷtb4O4@aHM UEs}l%)c86^:Ε"D D1gg@s;x׍tAey-l*5s eԧTXcU ?G(xYO@B&4"6͈X3X":2+L!kjZ4ɨ>iEj C5j7ҥ729wi `ۥa1l6 (NxGs/1-ט}@lҟ[ R"uO - t堟[簏z#`\ިw^$LH0xʀG cuʛvHyü`ݱo.Aza)STeLטr, kjߎX@bXz E)`UДg~rWFYs8AB<+J8R5 ;OϚ5 ;GPMMerJpz7N3,;SLq_2g/XsiLNk 롕ֿ/> 'dȰyg4)@[B^s,o a%7rv@.Q9⥗Y{, g8?_{W_|QǶeq =ɔ{`h}*a!a e/ev%2 yc)EQYS0ԣZlr@>D\t0#xd( v0-mbfγ ={.X7dLQK֋mAlC.,̩c޼_7W>{-WvbJ eU&0s45i[߿iq̀IA:QH0d3eTʿT$1CrE(SpAiR5hɆ:$5^OTs-ՓxπܴoqlHh=Nx/Gxs)B2V.}x_p.~4/. o>?WbNmW.q\ d$p!.¬ʂ1|lkXx:\ ^og8,;`2NYOq('[Xѷm7<^G@F^4E`pO-$:z3lO/_ `gܼ MIR ñ(q)&2й3|ᔼʳj{y+)tAmK̹;u¾LV^pRc#@o%HrmJfTVsD!K@|rzxe?ٷ^,v߃m+Ĺh@2g}7j^=+?*ĭ;"xѧm߮-ՉM'|DU"ޮ `vmO1.RUa5U!DtYP>f:L0/=)szfh@ xQP+fT!{olǚ95m;>a XA2|n  3 5KEoѧ*2睷9Zgx@j⏗.Y-`쬠>|>͙.}\UԶ RҧF+%E 4_Kjns yT+"oEGt_g(00~C 13 y fg d`6.t]${]'mtxP}6y4@:?͇ӱ=?p^~b-jY|b!ãsbBsZ~rY\bCT'{`ϞZV Lo nlӨg1/(K2 2uIf׭_85VM Y79Z'}7)/.~Qعǝ^9{WptlG#v%Pxx'bI8({o>Fyկ!{uMPNBk'qԱuUg8]@nKJFv~L_* P? ڑB!ЫNB[UX? {Iv1DJ TR6XkLy}&yya-iRe8]Ųnj!- $;I5/`ۻKV4V(i1)1{ӤR.t \Gd "򖫩˶acRJb 5X΃dMpa*{~Mlܠ4=u^x٦hAզ(2ŒyR}EuI Лaz#}3/j[d6nhłD8)JgOc&TZ~H0_~Ͷb6g|,'DJw"8K,^~U']X4f֧\ M !*AR^LIg8f5.Q= -)&a_mRh7Xp+_COl~HPDYM])!P#6rY2Koy4CkA֚P7sb4s]Z4FAgUvB$h }ƚ9Aw7[nߔqc\XD9^8eڶYO#xzk{D_]T_ar=% o"V6_[{oQV"U-9_KϿ͠3}1 E|IV$pl#@ɼ d\ c7D"]> @ɳua1/O0g^BA`S edJ=~g/V4 "j N9?~@~`3_?o˲?w ڑa9=2T"0e@Pq6g.O73MhHe>ASYx b?ko ,gsF(?ʷǖ3 @N(7m@Qe- /pN0f(r_EWQ) ƃ@9Smi8>7op{4>u/JLߟ\w 1G#ry71UY /)Lhr5TByAlSkg7|r5sfY۶i.n7zbGJ+[2W/Dȶ~-ڰ&A1mأ d/LE-#%H]XcW t> |< CA5&GσW )Iv? e5iQuE61:FzQhOs&Q"{Fšǂ6Ub9:ܺ[٤U/ooCwy5:?j=mhA0{nӌI~XEl8ƁPj¶giZ5T&owrb' R}nSCIum&OZCMm]|3y $ ɄpLqIoI)tdL?nYvcԯy c\^}h} XH֍\_L6iPsF|ܯq-'SN"nS Xǎ#If[U Ωk1#jo ˪}3"g&zf~P־r1{W4i[.!g3,@\9&M}fZfUί IDAT:qZbw|*i1l2mE9!މ NX|`wCnښ=3hqE? Il݆[h9lRpL= Um &XkqA5 +U:5>qJm>9˶M&fo26Jn&ZR"jYFOX)j.;.XգH9.o.X"69tn'2Tgl.cP r9 3yO|>d='%yZو8r $A0uD2uR"E`VE\D~`K<cEuנ> xlsۥ5&; ;ђNg J0:u2ͥ=` 9ί%{NqǢ܅L&2{3i@˙#²0JZgk @AkZ,18Le5Eð9VzΪ{<}L1 Pe}]v?1߭ Fst8A;[ `̬ -R օZ\{ އ6=@ڟlzKV7A oGd&f!TK!5kBe#zN{90Ug $?Y7loftȂ.yUd:$FƁ!&2}{R82v![M4D9OǸ#w@%۱K[fQtͺ5 {|kzq^,гu, {`|X>g}tlL 䢥\x,|,_cow( rzDFJ3A%#ƐWfH/uyg&.}Ů=J܁Wvot0_@ϤS۟\]XL7h U)4b%5X??W7#hC c\t֛_r1 3gi %[ rK07GxSI*UYf3[ G7zs~,KV(oa᧲킂 |E &xaԜ::əIZU Fz/lT[6 Խ7y\Dx=yNn)pG k,-ahu˂ǑN%d ӱeoWq RyPo;}3]AgDw(ԢKBj|A[ۥHL1E4IebY H`Lf˶x4_ez  oGogBm\,S`&tZ#/jlXV^g.jڲ|]rabo0;8*,p'HE A|1lJ[kNݟ x? Q|f Loq!š/lTZmb^y.( yV@V![Z^v`^Ǘ|= n.Yͧ;śh};L3#@ !탮f @hI pI$C oUIy84M> S8p^lۣe{HȊC0ӰyhތmQp Xs&|8%cD5I}}E-Ug6]zۓ/#]=wb±?Kː/HRś1`)ia^St=7‰Bn`U`?ö{:ľnlI0f_f$._iM>:q `6=]bm[>dkEUmbCuī\kHT6Mտ=?&$ mx7 3*Ft>v jr5ŭ;O̢} c"ƹkm (asF/ڼY^+$5EzAJܓm~"Rb%3;ܽ1@FZ:[ۛw-;ي}7bo<66>{KPhD0h6:ۥ7 HPNyt+E2ƶVz‚7Iƴ5m}NEc(L0[dn2VdcӂUT-&9.E:*?@j_ `ʁc7 MeiBeinzcJGvOhX0z_şs,V˟|}tl|k Tb$AkGdPYJ1ޣm@M&U{1(}E|LX@Aæj^]x0Ǹ;GKeJяO=<'kCǖ*AE= s|Zl/l3OY;ZHCN(%#KA!\b.#3U]DLAPz,"Ͽߥz^fB;E%:4mt|돉YfrwU<_>:0:| \@nZs#o/M ݾy)Y_4Ko͉z^5-6$PTaPd9lQ~О9\8ƪVe;Oe8K <׎"j1]ya۴dGVs $H]9 wy}煳p浣bBUrcZ'JSaҳlG;"50zfMlAGCV蓏j+L3`F`5$({?grX#?F&d_nJ`>CyuZۘ邧ֵpmMBݵD imRDMqއl7,{ϭ70 o72 m=$5r57:EY Ӌ@LGᾪ5w'#O?Cck])fizeҺ"ɂ4w(տr8  $Osr*dZ`7:j^4KQ,q,_|{S:  dβ maz1?l'~UbĀogN{v!`hݩ#P9vsv)ęic혈ݧSrd^`[?e-(iafaLeef7#[G_:zV //΂I+/'xXIC~ >H0s|ڟU]\7!6|T0{i-EZfquQ&_L3/ FY1wݝo{ο,d|-x~ަ:m]?ۨrv#Sx'Y~{[? ^ }%=A kzܠUv -e5sS5 5D 8Z@ja54BZPB}_!c-'M<=`][cln_/cƼX\,[7Pk?kqlsa1mh t (;{=q[Gkj̀NH|e:HP}>mM`T` WZ [mOB : )%ri 9  NF\2d ս^mlvm/ (kleF8Y٧-/s{}&mO@, 83FA_x|@ܩV!ecpb2c7oݴcLRiL$µ|@+|y%AdVXT\9lm:۟7pO_ִؿ}}7ŋR=hr=zdYtz8SŘk{12{ROY .8?Ca͍=n͚I6Oe5 1 >ls{ɑ-^~s[@dяPςg"˝gdb<s'`dK8ǧyʥ~@T]NEJ(38@a:9ߗPk 6I_yV|,祆HH_ }hI|} {pu|]*~޴KPû` ~O?fad뎙+1u&t=a({9S(؍SNb-Ź> |eM`qI΅d#ᅲ\ 6N4q"x`252'+^62?G?/7i^5)4(@n3 X5Fʄ"GBDհ.MgFsD݆tese*d ,qe[v%R@HNϤ}X=sK/~G7F[X{Us/QXkS0Ev OrBY KEjӬ_U]D3~2oHihbAW&<vLHkoҴ@X\E8`vZȳBK}Fr0P5{ h(,gs\K{ o`jsj`v={{zq6廟MM#:.JU2|Q{g{VRd.%;xZɌ`o7nC9-dsr:`gȠIZʆ [h4mKmK=΀ KKp zge5v3yrCn%He|1X=o}'az0'g޲Iy g۾S_% kPCmgÇxOj/Ya4]:U,LmO `|˜\yW"led[}:of0gK<55s PÐ@М~'q}Pڍ Hvhې\e%FY 5?Tk*z^9ۗS|\L4ZU$+Q ,h60}VlaK\ln`?^>c>>WBrѲ.= o./}|ψafx<׎8/m_AIK F $}ʷ] D t_lZ*|4]- 8~߰WZmQDh¾A|> e@Q@Y,}IPiLB),p0>9^I =4'NkM?#o'wIO>tWXo8֏q&ݨK/\~:ܾ_z񚳲/-^<Pg[W3/Y_8SnT: #Ͳ ,X?׿?}ԧe(]v[̝Ct3vrvak`O2x kBks#sy_`1uA7'7օqib/K૗9,Fw4F&r?Os/&"b#JZ߿ivm@ ȼ[>9ntjv_}wҋ#m 5ԇʗNGv^ޘxSv $H\q9J5 :f ‰CRh];3?B(f ҥƯYV/KkTc5P^{8 KwO`o,[լ3K紴uͰ5ĪN @al=ԚMmtZ:1.B@2z/;*V@9Gppu+|&F/J4M%@J&q9Ka-^)HLh8_coTRBgkeO5 ghK[Ϊ ucU؛@#,]4x-ZeSؙ9پeH1Glaȃ> ^j X}xu&AIN~`zܝ3-P\ׄ\2R@oɐu˘5хMy(DN0~*E@F ^*&b4fױ_| ȪtףX2@QDuhJh9'(սr*uݾ\}'SI К;Unϭ-LZR+q/tIrٺHE2*<Z/~t6,gVجݖlSg~x_q}Cp zoӁgjˈ1mt|gu'sk,V&Y՛N\څN..h>mD$vжh+2BXp]xNRrg>)>6YD_5Ty:Ic\&|\2;v3ibQZKmٽ+xK,Xl=nn3Gl ݳ1njWgi@骡~5 z0$ü߇&Nǖrma[4%^tA g-2M 6SiT9Nm/ЃY"r|o?Dzfg ⲽx'[2ؚ>^•w0?gRqyN``pC2F@()&Ź^܃KQ&ȵ't}~-vvUzj8vmѡ,m^K/"u4t^}@ 5C+em9вsaȯ &qDg(6ݥݼ_rMm[s[v Ow;o 7Ծ Lr˽Eus ijO#cl^8&'0Fa7( %hԝcd6N+L3/}zȽ.3\ j!vܽtY7+ ģp: mbԩ@D >>$51|U"0W,h|:&R!f( /{1ǽFѹ8nNzUk0<63q3wR0–.WՅgD.v~3nLZPGZհ%MZi ?λ{Im%ihq>/ #8> _L^6"m oSv_DMc: d>g}p?G. 켃+DʶcXaR*5yr5r96G0V 4~Rx28D*1ȴ%ԺU]`^3>7,gx!=4{k萹ovo.k lXS?/ TC o}=>*W<[N:oά7d:ciNsYl׳YcE'f -r!x3|w _M$Kzo6JGr5NuϿI USx/>g&nr]+`JZm;+ҐAV:8 C޵tZ-;OB%63P/gx7;GGH_@ Fij{7s$!;^kw;s~ ano$n-лlz~C 1ZS0è}D?\KW*tUlW=$\J7z>e}-bV 2*\Zh aRj &ʵ2hD;kE>GKh]c^b?Dk"[q,-%+=,=H h̝p#w{1|H 50~C Ţ 3UOBZUls.?p`ՉeV_;]X1hhk'AOG@gV"˷LjC %/[Mg>->[T !#gհcLE:|[n3/Qtc`/`|h̃wybh u.Q;fvNpz];;lnUxKtq) q XFR!z״"j`zK mp~_qD2m: 7[Z`l_mڥDOzQmMԯ2uyX^n~ ::<_uRU|+Gc_= ]aJ}ҍkDB`I2ԫb Z"Ue Z2]ah ᱲ+E@YM3Pj-jM;XVSL3?W\c!˦`SElow,l7"f\l.`lAng%^zd ~GWlzIFIHe/yȃ>BKeM}|RqE]r;/:k 0A_B6s؋wq$P%@Q)+ wrzZEcc2y2}LHۓK2b' XArqsY`3 Z~x#cYSefig"$#.Σ Ђ,c[bri] > +8#gwIqs"yk :pΏ}^xͪ[ϯ^³U]v ]|KrV>/}}o֙p-u? x7~?S0bo.\wMC?`mvaNp)}}{N"JYwr@|p%%-*iQ qR!KU*zȕ)uMnZ2MEJO8Gq6?@fX58Ѻ1tyVb^zf!YΝLs/Pwݿ n2gNs뀢LEh;?9| 5#A1<2drІRP@@TTAkֳ)rɩ!*."* "D(f…$iPU |2w\[H(X⅝exR-"? A1 si}qغdB=%bX׏YOwjFWvV>q!DDQ_ו+1bYG#C1/}a 1;VEZ6V҅% Z(B+~#-yLh40\9RaQC"4 F33'@Pl:NnnRB?\le]COմPܾb(E&S(tK:?ewbt 5&"|:D,~5OnOZaB;`/? FI+[vzh&[Q/'XX|{޳~&Ͳ,v{b[H9Y2,xLK6=lv Tdg46Q\yF/bU)&Y*-*Ųy.(uH0luj[!7<삝/!l<Q#j4u,^e[w|,g o]u䘐3jIZyf wp,={p^1wpPٴ,YX?]Q\NC+C''e!>ﴑCRBY%ŦLFϗ>z|EO9Loq(cZI)a '(|T GdA)lJ b2 &` rG)Ղ ޻}u-д쉢==(Y;m ,+xl<_5O`W]@d bfxcu; ʇQ`&Jل)ضK`œ7XgqC()Z!A ruZBOod'nw p3u AJݻH$*1DŽ ['{O3E9uH\ֶhM"${x@2AXLbq?t9 BҌcg~OJI Q1eac;􀵇0C]Ϩ_u=(CtȼL:E(m-/Z!ɦA%4L0 (sz╁P !w#!v`";lT͏ GTЙXRI`cW^ϦĶ~_P_U5Ælu6O߫;0K(XGVe)U:S V>f.Z< ,2rW b.~"IDi$ CFe?|rIh zH0:kw@ 4t`Ϙ !d3 ?YҠ%.ov,E|Q(.Fx]Zǎ3>|QHq6Ήp [QmZXܙ` {0v4.P`:]qC\ja8d!4m5HT.X]be,D:MgXH ,I`%x~UmKNM6ݼ,37iXPXl >^F ?3.L_ӝ{1K[Fp2g*\Y2dp&2d(ā[c k(00 {M&X |G,[rڢmSl~tC%jd#,~K?;/b". q!d+'Xd+*BM97SIft05XޕzeϩePthؿp"4LY _F:{ Hg)xEK YR-?F?ADNСm\ez ١NXZ#Q AqUUeT&}z@i]s1Rgӌ$3èͧ~r0rR(O!ɡkw{"H'kFmhK-ߵ4O)>#.' H1)w1b\$x,~DSRY⏓+I1n2/,:x05 eEr`FSȼd)u EfeVf.-5$ffe66BO (@1zzy80q.D!&MD(nIe4 9 9q?K"lh0f$*'R?A2]vnHP,~1()0S aCStj%O,,xv9Us<ɳw{($HEC ЂF\l,b@z}MV@ɦ 1~nCc%Eq nxKu+GXe [x4wYj{㟓+^ :&|,#I"vʈ7lGULK+傹%n8.yCIDAT3Bĺ|8S܉Ot\!s$n.kIf1unV`"e̪(&%QBh&A/d#j!C)X6](b ngZa@;ܰ(Z%b W](L)DQPB!ճve,Y$d D<ƀpf1($\O1{,pKުEYeHE1˞ xݲV): "!Qmfx'Nyp. uT\2$4̭Fjs,M𘖾P A1i\r |gU3";,}i?E1>h`Hxv,hX ,."pV\P<юR/GYDM,~AX(+|K碲&]h  D6z w'Mh#Nf&/[ps!0ӴfiA'}X =E odZ^t?ٱ[dZbI IDsŴyyXDr[Un^ϯx}dӆB7T&@?Z)GǟU p HG셟IaI0b( oN4W! ͖{.#HQ(+ +G)|+6x`uz^y4U8u^MXٶMEjb6*p2tȐ9e @۴Y-ZM(trEIL8g Še]M)`J^"(E "!W/QUڅܽU'4/c#_ۦ J3NY!A 6@6]~ U5` {\K21:tSd?OPd?{K6bӃr:~ $juA/EMıuG/A]$jĠ5A瑠KA 1(4M|py_.HdY$uXƏG[v+8r=w{:vDǃ;b[?#G-Wgh#FxVV:xmץ;cߋ>!uMѳgqp:#>eZoD;twީ5o+^M0h`4n hߡ-^ g8&6mcNX[U>y$~?z~ . ]z\1Ŷ;k^ةSeNZd?Ogƾ>k^Lw_#ٳ1w3ZǤIp1|(,,Ę1c9߾};,]Xt)Ə;C!C عs'ׯ!CԸs77W^ :5~]3g.\X{0222p}aŊ1qDl۶Bl2}Q/?c aǺu7{jsrrгgO8lذ'Ok.0el:|/>?ގO׽c3ժ{Y$V^G|6UILzF2 s/#GYT5N oEQ9߉l'.GY;Xpd?CAcSаarσW C77 ]ko/e*`.wQR행@^^>lUŦkZ >y^XX ?XII:%7ߌkF=sشi^{5AVVneRSS\F{3^@43w1e? +*gea_C1{ޣؾsTUݺyШaC=v7 7;iX@0D>կ#Il <d?I18m &Ng[ks/,4o#㡙sG1rEe͡C-ƍoAΝw^\?uZlSN'OFvv6^|Zx}=ftf{ lh-0u#NZ4\N8|0Zj[Ny罿_d`o|c3^yav_ڸ '1ݻwpD}uaN,b.4MG |CGkFbbEAKa铏Uh?tEQаa2|/l^o4?:&=~{/D)qϜ93'/[bּ>oRرch֬Yc˗c˖-hٲ%Zjm۶aҥfB X^rV#㵫ѣepx1_㐱-${_۶峍`E!؊>zeV<@Kny;aZ /=N,fa޽6l]k7vXc.irExq]wz^=SLjw{ּ>?^f{pns,ϓׇha˺t?6v/'D^^|0]znlܴ[ ^xAɓ_~>?37nɓ'תIu8c'c8θKO ~Fl7ai.z,]5Hr .l\mu}";__EΝ,<&VqowӉ$W^i"*6mڠu^Gnn..]ছnju]ǪUzjc˖-8~8ƏOw0uX\r`W-__GJ\GY㶼c,$֬YS+srYq,.OB`شy .X1fʻɅcEΟB$(O D,^֭|Pl{qi3ϽJy}~?/m(O`}vYyy@عe#ׯqEvL%ޤI9r-[#GФxI$u331p@ 8͋zSRRl2>6Zj%Kʕ+N6LƐA7Dp{Q}q+1v&|w:L]Wm?;x׸Mk\|F O-ZwW˟+QVz"U_dl5W\_b+5k+3@8^/8z8vm߉~}y,/r_oOѣG:zm֖(e/u~w5$IO.^xxz9tꀳ5B /KSp gb㱴y㳍JNj.2m墝o*~֭6lP޽{;pۇ~Uh6mڄ^zQ,ΝkWbn{хؾ [hXeS.5^yR*Ld>L/3qزm;^/ u}vkҸ1v|/8EKyX8tLm/SС%oذ˖-|sqʲ;o~!գ•ѣ9 &`֬YȀGFFf͚e)gQF!33a߾}1bj*ǟn-w 1Vxoȏ}1-, zUo+{_aܤz_UoW(sʚ7}>Z ׋mwb uqϞ=?UUǟ0Ny~i 0ׯG^^esԸq0c l۶ ~[nŬY0a„b 96y 0 .ĸqʽcǎň#o>hb5zl9 ~)N@t:|gWˌ5Ϛ/w|@ ~rXH歭srUPePb)8|(7ka|[o²gWPpYXVB}c!++`9χŘQЩc{@q {Ͽ-֎ %T*eSNᬳβ|ĉhРA\_C!Ҋ{'xcƌpyᩧBnK,)SpUW!;;)))ؽb!7L >RR_~7ވ#))  *!=ǎ+f6i^SCl\U܅4N?nj*׸-(fd4'W%1GTZs59E>x%;c֋g~;y >`M/6oLt4jmƌ|?>]1_%uLc?{'NQn&=0 4MϿw!86l2^ j:ovn^Pwq".9pxyh4NQn#ƌǡGڤ1>Zy)Lʞ={$#r@)n7:A$]ӠkZ9V:} 4>juA¯.]ßYGѰq:uܱ|H%h"z(#AAn:4~ 4>躨t'+>]w?(&*7AAʾ݁AAv[{<+vuAA&B7Il3' ҷ6AAAQ{DM?qY" f`.,  0sqKP\AIENDB`eureka-editor-eureka-2.0.2/htgen/template.html000066400000000000000000000101601464327712600213450ustar00rootroot00000000000000 Eureka DOOM Editor | $(TITLE)
 

eureka-editor-eureka-2.0.2/mainroot.cc000066400000000000000000000023531464327712600177030ustar00rootroot00000000000000//------------------------------------------------------------------------ // MAIN PROGRAM //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2020 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ // Main entry point, not always used int main(int argc, char **argv) { extern int EurekaMain(int argc, char *argv[]); return EurekaMain(argc, argv); } eureka-editor-eureka-2.0.2/misc/000077500000000000000000000000001464327712600164745ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/misc/Checks.txt000066400000000000000000000023371464327712600204420ustar00rootroot00000000000000 LineDefs + linedefs without a right side + zero length linedefs + linedefs which directly overlap (share a pair of vertices) + linedefs which partially overlap / cross over [ties in with unclosed logic] - unknown specials - one-sided lines without IMPASS flag [FIX] - two-sided lines without 2S flag [FIX] Vertices + vertices at same location - unused vertices [REMOVE] Sectors + unclosed sectors + sectors with ceil_h < floor_h - sidedefs used on multiple lines (or same line twice) [UNPACK] - unknown specials - unused sectors [REMOVE] - unused sidedefs [REMOVE] Things + things stuck in walls or each other - things in the void - unknown things + no player 1 start - no player 2/3/4 start (merely show it) - no deathmatch starts (merely show it) Texturing - missing textures on solid walls [FIX] - mid-masked textures on solid walls [FIX] - valid flat names in sectors [FIX] - valid texture names in sidedefs [FIX] Tags - linedef with tag but no matching sector - sector with tag but no matching linedef - linedef which requires but lacks a tag - teleporter line with missing/multiple target thing. ? negative tag values ? list of used tag numbers eureka-editor-eureka-2.0.2/misc/New_Workflow.txt000066400000000000000000000026621464327712600216660ustar00rootroot00000000000000 WORKFLOW DIFFERENCES TO YADEX ----------------------------- (TODO: move this stuff to documentation) 1. can "draw" linedefs in VERTEX mode by pressing SPACE. can start in a blank spot or highlight a vertex to start at. after first vertex is selected, press SPACE again in a blank spot to add a new vertex and a new linedef to that vertex. can continue doing this until pressing SPACE on an existing vertex, which will finish the line drawing. If the last line creates a loop, a new sector will be added as well. 2. can insert a vertex on an orange highlighted linedef, causing that linedef to be split by the new vertex. 3. can drag a vertex onto an orange highlighted linedef and that linedef is automatically split by the dragged vertex. 4. can delete a vertex which is connected to TWO linedefs and those linedefs are merged into one. 5. can drag a vertex onto an existing vertex and the two vertices are automatically merged into one. plus, if the two vertices were the opposite ends of a linedef then that linedef is automatically deleted. 6. can split a sector by just adding one or more linedefs from one side of the sector to the another. 7. in SECTOR mode, can position the mouse pointer inside an sectorless area and press SPACE to insert a new sector. 8. in SECTOR mode, the SPACE key will "correct" an existing sector (which currently must be highlighted when pressing SPACE). eureka-editor-eureka-2.0.2/misc/Scripting.txt000066400000000000000000000036321464327712600212030ustar00rootroot00000000000000 Script API ========== Global Vars ----------- edit_mode = "line" or "sector" (etc) SELECT : the main selection NumThings, NumLines, NumSectors, NumVerts, NumRadTrigs Selection --------- These are methods of a selection object: sel_obj.is_empty() sel_obj.not_empty() sel_obj.count_obj() sel_obj.get(N) sel_obj.get_first() sel_obj.get_second() sel_obj.clear_all() sel_obj.set(N) sel_obj.clear(N) sel_obj.toggle(N) sel_obj.to_list() sel_obj.from_list(LIST) sel_obj.merge(SEL or LIST) sel_obj.unmerge(SEL or LIST) NewSelection(mode) : returns a new selection object Map Access ---------- Thing(N) : returns an object representing that thing, or nil if out of range Line(N) : returns an object representing that line, or nil Sector(N) : returns an object representing that sector, or nil Vertex(N) : returns an object representing that vertex, or nil SideDef(N) : returns an object representing that sidedef, or nil RadTrig(N) : returns an object representing that radius trigger, or nil These objects use metatables to allow reading and setting the fields of the actual map structures (setting will be via BA_ChangeXX). They will have an "id" pseudo-field (read only). They will also have some convenience functions, e.g. line_obj.Right() which is equivalent to SideDef(line_obj.right) Can assign references to certain fields, e.g. sidedef_obj.sector = Sector(3) Creating and Deleting --------------------- NewThing(), NewLine(), NewSector(), NewVertex(), NewRadTrig() : this will get default properties. linedefs will have no sidedefs. Copy(obj) : create new object with same properties as previous. for linedefs, this copies any sidedefs too. Delete(obj) Delete(SEL or LIST) Note that deleting objects can invalidate existing references. MarkDelete(obj) : delete the object when script finishes MarkDelete(SEL or LIST) User Interaction ---------------- TODO eureka-editor-eureka-2.0.2/misc/about_logo.png000066400000000000000000006503321464327712600213450ustar00rootroot00000000000000PNG  IHDR([sRGB pHYs  tIME?% IDATxDr%|"R?Z%OI=LF2&_1sW7#;# }RլǏ f2VwDjw>׊Ꮍ]DTVZD* (j gVUh;9 JTtM\]I1̈œUD$ }߭&Rr!FRa:Exo73f>?3SU=;Hu1__6Ԩ]MB x1LC82@]UjL U8/D{793ٽc$:"Xf&,,,",Y9___ jy5*:1PB?q=}o0|}|vG|! EV!I0jT%Dt߷G7^wzD%K??;}="_~ܽ N™nlgBt3^ӌ 73wwW1W?>~EDrD<̨x_["*,{@ !č uQ[UTޛ{VL2j3kGCn5GFtU~";ͬ[ɦiSLJ^KUr)`6pyU 01S+6@=ͶyB񨪈@QXU}oR0`25nf̕1Ǩʮ6` O&ĤP-,C,2*_D Udz* ddWe; ᮪I YwevJb~<~tu]YAE^Cq&xdffv7>&20  @w%Q}_~NSuͫw0$eư]#OQb"al3_fv&ϮS(lS13bWEÝ"kVwgo&^U__",c*8s΁{IEA%3}H!"jffEDc}o6ad`p_oЪz]q]vMV#䁝kk-iicׯ{E!04 TYy]W,LMґ2Y8=eADxclY3H33*<Ξ%ftKDAԧTyFD@]Uh&s}[U_94׵#U*"}<tFdfEHeU6Y٘c=؞$\bLmA&>#2*c .41{w3H2bd3@.:N(yxU{fCUcfv }bٰW,E`Dx<o)Ђ St4;2;Eݔ"0,ۉYGRf&!^Re`zMMɄnfZi:FG2*J~yyEq/tVǼD3ᡦ VDDE&ƾ)Zu=2΁VՈ8߯m6ȅy]s>ߟ r:;k*??ݛdwD1) ksݞ4lJ!5~r}R&2ט13FRw"adUh\؏Z#*5?K __l=Jϧ b&fi$fe%y}~jrv4SBﵶ|?ata{@5=Zw40-UP@1%T",~ۍZLfv@V VQdUl&@2vhGdr<Y[YTV(AtHPH aJOhp)wOfL`d uV"chGLqFYgwu_čvGsq\5TժھMATĨH&Fu3j}="2na);%L+m$^11o*I.Px0(? Z?%^H2@DBP!D A* &R"ҝĶLr/UUյP]E@\EtKǸjy@,L;M^E%{]ݙ$D_6Vj,~fUĆTfU{yeپ""gnbVBsy9142"U~2TLToku~}{$skϏe;]:p`۬pUsm|f6{Z;Td|(~}F: =EǏyܯWTnR`sh@T]c.:PmCwxZ+TuOWwa zGuUkcGyN8; uo0e罶!ݏp C(0kU0iWIQԨ 4{fHkpVus^%$CE+Q Q#1p7F.$Uij,1++2,;:[%2tUX.7|/(Ǣ XFιz2VpQLƜcp75S1|c! c[E*3A|n0Q֫3r8E,]8, " w2Gklf0`btﯯCT6V,#3F6"O9x#irήnhj_k ûY ߛp$b<|oY@aV0jTTcXD\cL1gU1y@9囌DfdDe R 6e6u9 -TKw1ڪ$X# }oܯ@ޏz^|XJ)xgyY/G?x뵖u{ZUTZZL,"qpFzHx 3qgƪ9lowc::DkGq{z[D fjjB|VWER`t:q_F SywDzî" {hJ&~u]]]YԭJBLFl3 Gj5Ī҆[(70e#+#ԲD9U& t7T`9Ggh4P&pz D$cDko;URt&V#( ++Y3@}.&b0g4/Ή^/5*3{'0 P#=$5/"ReBdvkC% AVp0UwUEu]EtG7놰vڝƃ$K|}+e|>h@cNH:ӘLm\GQDb‘b*0Ǡ!`3r3J5USux͢*:}(0c%x' tug$ Af(i*bjvhHФ:DbOFѽX{iHU))D&(mq=HH1UTŽ/;"WV32[sGmthTHCHET&BI5 3??{4Sp"mMjMb35N%3E=2BMfկ/\Ɔ.S9k ̊5 7fwvExW30c*M"HhwLSeP&h4 o cFXY b(ҩG[l(W<1?dFѹfD9N1^Uq"q?>YH"ZSq tdafU,|W;6s3Uwmfӻ %aqObHwac{gװJ:@F1kŦk׼"&"mb\@f >ab:QsTde6DDm[Q5:3 c;nzF2y=̺"*G^"k(('#sg1amǥf7Ъ[`P&{e=HOituwB2Y]~{zݏq]s98k=sѦǜݍ!lGdvJ~1jivOC}+0SWDchh]h1eшTs>r}Hk^}'uDwוݏke#\ƏKET@RRA]{ x/Sc"a1e&f{/UGc6kb*T?xa`óKbLDE"DV'!&ZYjvb6v6u7us_sʻY'=T#rBIШ尙ʬ* (ӜWl]#vfx}}=E!D讦>Y/ȣ@<^ ˿+rGO[/V})̑ĕDHd@%a@x~)2u1QWV3٤@eHvؾSYMH#ܝ@)"ۯkr:@ͺf:!ٙE;wE2}w 7P7s^{9 HUU'CFe3[@f, "PTӮn(֋cٍmciey !(L\}RDISeWcFf7نZh> Qe`󄄺[TU(Gkfss<{{/k!Ţr#jbn+iAD?uZKT l&wL6]5Ol>z>a&}鑕{ I l pܣUUީݦ  ]]UDVl,"pBȈf25coLgdE$>ֱ =8i!f"gWg%qn v?d6?TUO z-ۛqU5S\&}ZUk0p]WD9No& 5[d0`fĘ.#YkGﵩ(+߁QV%"M4fuΘsFId9.H"f8URDȷC8 yeƁL|q\OhE̙iŒ^Zo("4VbF"`m׸N|#ĴGf1pB1q!a6w‚~Wl"j".^fwje̢֡cqMDM}v)o.]L'ȪXTottx~|<}&&2KY:󚶣Dkjl% BP$uEı]L51e牲*Tukd[,2˩;"!z燪WlߛAOHHO T'DLE8`#@LIT{B*,r:_Yيʒ2 "e 5#U~<>›N8#k-{D !o2KU}1^,+G@.5STzw硫UbcUDx>魃𽖘>ޛ>_9T^ ",t!M{zQNpYN$y #JJtR D7;҄&%wwuO L|?(e^;^ݵ>0s>/QL<3oI(3U-3Sj,UUlfzǏǜ'ګ P a9AOKjޭ/UlʉЦV];B9#qu1 3Pǜg_>݇x է1MTĚBcZ{w&O!'UGC^@kݯX@WT! &&|=ھﷆ{Y.ZDҕ^UW1 :Lوϯ׉U6ut{W9/_ Z!a5m8RUV}̹ Bݽ2 &憘2Qz=WNB3ڑ$ujLh7@7?31D9TP} )sw: Pt't"*]V 銫*^Д az<9X9QWF@f5f@&**gG!{)MU<`2f*ذ3Pr47T5ܛ%"\WӉ{jE,Ӂ#Dvpgzp=O>DP=kjՑّA QEsW D蓜zg~G$"}/2Sk?v[]W3 cGw#N3蹗Gli= ! 娸dPԷGO21`Z'JDk-݇Y)[U[f}"@.y?DyX_ww#Ŵ< #*^uW;ջVWU  4wsV5QWLmw:$JL[t6;;w#Ehcd9C0^"RnO/¢ DJ7tldTE_e"Wzu{9i"_{="b&EU&B`{.b Se HH 4NDˮGFV%%|!KUO$nehuUJxkpFόUbE1D#A{3@^)ZqqPU^ i"VkT=toSS:>f#se_U=kΪڧˏć7^Y3L-O%Ts^)cK@mi`=9ݫQZ ;'rES "sp&jF]Lht!,ډԲ]\TDTGkZF{1ge sDsI9*`ЃNvw|Y_^$'t@h2ƛ~"#bӯqZQ?SePBL@$:}x}|.纰׾XEϥ{wVrUVYtu{yPUfU9}on sXyUwgޛw'\V+MX:8ݾ7QvIqA$jp޾QE T10{9F ~[|@{߉NU9璉+xTU,ki{yT%4U:/|(tF*}흕3"LMܙzX]UɄimߞ^Ťd)$_kw(^b$MEM$Bb*Fw= Y^"R oeA鰺jeΈ7`xg$M5}ϓ]b02*2N\άʌ\M?so$u-}Fh;@lE-G I3#!y4ЖF!F#Y,I3F $$v[F7RU{.ˆ'&&a[p}2wd=X{oeZ㇡`T9RmYL3Y,+e:\ DrrbO :G j/{dI9#r"9ƅCgRYh*kY$֠JY]h!d܏eAtD@"f?4!Z%#8uqTB"p!C?:r4mBnqMrSJ*%?!$NUq HW eg]kk6:_ȮuΠUͰs$8ם 8*3 ~!R=ܝ . :9䜳N|:'$J8ĺLu*({Y]& jsRI) @zXm#"c *1Z{WҽOn`#!,cL }(PIp.:$FCg `:C j!MSb \Rאs@ĀKAIj9CmW]cbEK%D#01-dR@@2g)0R4fDiܭ1C\s)QĸGIb0Np$)?SBm #pEIq Jj $9ZJ8i1( r$hqpIla⒎tu^R,q2 "!ej%0X:k!MX!Z@]'9,9ș`I,C4FKȠκTY'zDD]Jcb$;'q3"R$ӤcZ]^%Irѓ2ISTXfFu:c4 NjZ%rkcH," %Z'R0GZ!%0F) `"d$I+39G@(#F$c0Q \0 TD[ `LBbctI[+S\*bgKrzTР#)hKLfͶD$Ѻ Y9_`Ud8fdEnW~bt+5 |ΘEH"C\3z_e}aZ)N%;f2I C3l+@)cWP!Sws#sVxeW׿gp/{h`_g4fAt~p`H(Lf ,tك4"WY@DDɄDR{U.R1ε6iDSI2%9ZLJ闌,U "I uʸ^w) 3QI}4z̛ƈ`\ qaXr.퍗`3KR//I!|[3KCV 95)GDk ˯|rs#pv̷p&: $@ƢN 2Q#yoX.J$KLeʣ$NxIF-ߑsBHG(=/~ǯ<OZ G#z4~ u2 【nUn 縔aR1sk1攓oA!2JȮc.(~sW3e@sQXk=9H 8F 'N3)1McYѦP,8{+֎Y  _[wݝK$g " cDj u0:Ui<Ĭ#~uN]2tZ-yᝢ7[s#b)KU^_ 8B%c|tbGH!Ѹ6۶!oO?)o%(G8SBɩgIRXq5o+'ΥM_ȳL-  r#keeADit0rΥiA\ĺ `tlҦvm5N9$s: D\Ic" Bfa\3+\(/ֹzmr{јj39t˴׸A;N,џw^7;ygp{I._5V(/^' wr n' |o~ns{5,y8{q:뀄7_鲥* 7WS ###6 mrPԊ~bpFǾ/I {sEGSҗg%s/ҔRD9a39c?oocyzVmod26-Nt53mR!v.8+[ae$Lͭzػ:jojϻ_Z4<08}l//|ݍS?s6}g9+2ƶmww޷zCy䡇 7q*uF2Yc3']V읊fMWBu¹={v.;mdN K6yweɬsӣ'w1Q8\ mRJ#tNI%HhƑyKswq?GGBq'>9rݑ^~nk~Nxtt:.QG✞T=gBIq3O?-T ERT0xwZO鷝 #R-{ '&[;f77r,3R\R;wjӕ|7D\wu&TA*j5\+|ˇI3GFo~7gd,_?5ޓ]eF*1!D&R kY,;Zg0 :ǁ3/G?tcik&kZ[D$.[o,3;4s$L=;w(a۵H_t]{MnpKdߠJHmc~e|Is}azcffV毟U. sL^}X$@0סT O=ԁ;oxLqФF_{mcmi hii Kqݵ߬5W#(Ɠ3v(I""c0 CL{8쎟ǯ?dz̸hF^hIP+a syC9s͉y~`~fo(7OxɠT:r-g.[Vܹ;.~suř; 7_J,D͵Rn,תvQ~x8z-ǎ7 V%k+rj]w'~]]#R,N.-^z\n\כȫΝ#o`Br`\RrY}P[NK]7]7>zڹ+N? Ԧo|,X <]wr卓A_i]熂kĉqk~h͵=}`RV؎Pex\mRR/ .\G=׿vZ3I!( Ƚ)5W zm趐6V EURt HIKCgxL&gALh,Qw?Q܉BkQ, Kkc{w {Ra#!8Y|kyy)G ;8صwo| k9./?G.V]3w׿;zҬCaGxm EEKKu_dikk1H=cFvZR n7R`i'jW.\PɃ##k,+PJddzWDoՃ 9 8 9/TF'-Czpehxy܎?20w%H@IHdr4Eĥ0L{_bZ1vl\obd% oG&5~0}PJZs߯mW&&[p=x{T8xӵa)wO TiUciD}P܌&VGyOfm+T+yUi2C?˛Ã];̾~|xd"թ-ͭ,LNNF&76K11t&Ev7*h}~dx1s7|vT9X_Kf;[i57W[[ZV봛IgJk?=.ˀ;Pb蝷.}L,uijf[ |+\ΗY6tmmTal0F* ( 8gDSDyblki81D T c=oh̷D~ 2 zCrY.@}}Xno֭֊Z*9m9Il< *L/yC㓞2;1 Wq?SLK0MLJ[tvqpG)^)KF~ O\[YCF'zzuڽS;|gf2$`Ց_nLX&O'ݾ"#B.wc̽wwv5fPY\.QV6Z.+kܗܣFt>rW?fu|#M] PW^{j2Op)9eVqwNdryijf[d AdV;IW][[:M]Ŷ3<_H6ꭕZ}njx]Jj#r9cmLbsf G.7` j׎ JMjt:ܼ r&77;'%zsnq8r}q|OI͐F!1>tۦqR_5ČY<&ӳ.b`ڥY_xS]Y[}B!/1&k>y0ٹo)@P&X[E=~yn(;;w?|"ׯƳ.RvZ-k,\Vrͳ3?zϹA&wX娨67+k+;kͥL]_p2^Z8fΞhl\9,^3˛<6Ύ}{Z:{Vb W2eM7\\/{%_3?|yokkkkaTdI(7:FՑNy OJf#%h8#C3ٙY T>L281oץ Pa j?q!*G_qlzu@`r_ܯZ –sKr~^ضcxҎnJ sֹJ{ͷs#\7۩N燾i$mlj*yo0=N9) #F^g-͍J_ɩjn1xuʇ%9${YC(z\"F$ Jԉ[Xj9 9;7} {WDɦܶ Y7SV}R!IS456Ju:IsCWԛR!/4:wb{sLAF{ﴕke>9VJãg-xL>7ٽ{+F-`|`t˳゚;~g׾fn~ k#K1r{nv90?3; ca``oda8:gku]o_ Kj6 M~W~ktWK9|w?ptʅZ㾣|[n\ml]ި#4ɕ#M Vq/u[n*=fy lo +57hm+޾r_0ޚT벅S.P * ԒnngȞɹϴ۪md +oΑZ D˵Jx77.\Ra>m%.[Z웜xsqokvl\g#iB.1T֡R~' m4WSV\i+>(ϓan$Gu]]\pΝ{D~hw-e|%4DH]M[i0q~VvN>r6%Kw}Sz/խXCۏ<7נ^}h`|L8x |FFo:<Ձ\_7ll4N Al.ٸ͖ڬ7>X_y:6_=y?M}KK?G8_(UXܸr/U{Wᆃ>xsG>d=~یI7VWrTi7?k~짖^~ ћ@㻃Vd=!}C;5i <2*g :tHUo4+H3u7}fy U ؍VDH; mғB/V BigfL7۲4`ӂ SU(++C-{d<;OJnFB_~GO|xC& vQ|♯hIbE,[鞨-َv[3Tg \^8p4Zj  2ET*lh>0>bT4j/n%|.MZ)^9ozқX{01Q^J6?~cq/9s7'^y!nwbr,l]Y'^:5~o-+_.SOwokJ^ j}{W^ܭ5B$1L81f>js^I0KY6,VW_''S(3{&cÅفB!ρj6k5R bk!.}3kO^|ݗ_իW7'XuLYI|(8y׾:֥ő@#{iV#k0 dQjвD jbv305{sW0$ccgX`; vK)HTfE#+Cݟ%F`L b~ `^֜8aZi!\Fٗĕ4Pq8) fH 'Q}i5T̘)ZZI1Ɔcn5_3/38Ef﹓OʥJ{}{30iGv{MSeVSHն ԔHCZFFE0k,/.6ňb.O1DJ ksKn |IfBPBc/N|zF'#D0Aٶi9.LH!2-Kd!X3gxAP Oر0,ΦM-[sڪCC cI)4RJFDTֽگzega#S*0[Ċܷf34m[9jի)ݭ*%(.[ -Z=s_dK4SX_'f Ggl[4W&@j& BIFK.!N*X`"E'N i(m08N$٪trw1S'O߹}{#>l~vvtp7cAD౉(札mlݿW j6I0pR^N !jFdz{s>zǯ1y-nn.~EܻȡVQML~1ŅGۻ[f׿`F蘷|tg3~,;eIb}95JZ-g` @)؋fH0 SKɹHbV,RDB6U_jOy^:uw9rpZ:zvVTQc//"Mi l(;*bAFkL+qljIDBH!(GLWhSX@hDe)A޾}CC?kkw, *X 8y̡g^^{P8 "/h!1Ĝs)UGxN)-85#ZteM Գ_T\]7%y5=O2 PBKO0"PYhJ|i\kBj2@3 ڹlGԡtRtlb(H(ڥ)bAK[)k%!HƀTZ=sW_z}hxmu=#P nA$tygRe=VHqgʩaivBR8"dDKʧח$>4FmD~N뻟s:_Zv{ x_o}'zN-#PG,oW< 'o0cT.HonU f2ag|gИhZc_Y-`c~+aUC3(=јX6jnQث{ў޾|kkGw^+m@` ZA{qM uxBRJu+ذ[CӀwi8wG7?-yV v|jQMBM12X)T'ο?Ä- ;l4T&Fv޿淪'~_wō==o~yYOot>5Xp7^gފ3:>S|ɽb>50v-V)5rl޷Z(΁:|U*{}2p+ 4v9n#F3˱\.cY w~9Oۍӧϼ[NB>\Z8utB)G<Ӵ?`)g3RF\b{R@raXvĤ\of{<^Sc(9(-;a$s3 0Q`80o_rҒb0`6D@RӧO*^)(XqOis"BcA)Ti \w{~cAh0?? ^[KwܤϽZm]m/NX"H-)Z+1%$XR)̤UPRK}}5#R>nKnI\pt -6p'N;+[C#BhHf@)MX,K֝_ohtЄ4p;"L׉sێۯE;Z Kl;vG1;~` m;BQ\pk!V D1g#)UJa H x]]f}?ևWMoV wL{x48fb&ZvgG cy~ѕ+MgG+3>ͶӝIY; R_~mlg,N@صs-V*C,ȓ:cí BnܮUkxj')' C  Qϥ˛vH H 4$1)\) *'czy'GKu8@Ja* וf)9^~wە8]պ[iQAjk @!ȶ /Hbst kZ4#LLP{ս6wnN dI4ehM_~&g}r$yAiTo-V7Wd>,MוAF< T$eYKJhǦejH(1|yta#T ts ECWݺ3<=|^gΞx v}`ś7NNL|_Д=2{X/eQghvl.ߜqҕkv:Blgs)Pc=݂ َ)m5Ɩ [e7]::w0cTr#/}ni3>sNjlmf{^!D.>0:@!m7) LI 4,$i@1gفv_^ 8Q#%\ES-vzD.^_oz+;f Z:B4>T7olF I)cٖ WPwxJk Pݶ0y olZuwS,+V֧ϝ 6kV.QU!)vQ;3l-! ˀ P0Y lC8GE^[_Mg6] ^\TRT7]]jaJi r+LYaP( VW@@J?*mM0ik2/z{({'ELL;o.ӆpǯl'6LdGw4MB(Ui>RXA/#$l;igt"HY56o;nXu늁,3pJCв.s LO韞>wjoyuR?vtzD2"%ALLi \YikЄs20vzz?ka ÃO\ڪz0ŠA!@k%$QG1Mbwiݑƞ8>zȱϮ,ܮ*cJ)g}tMGV7wpSm IG؂0V\!A0W@k`*͝-J0Pئ],?<xw)8з{cn΁/-0]_㙻=<7V&2M.iLq'VւS御;3fLOLw6W>S]ye;JmPo֭Ru]{wݩW' °XܩzC+7CӥKnKK Qպ+//u0@F~@,C )[nĐƜII: =m=plrW>s7o <|?|7ט[ͣ$n{'5 W6cRe Yiȅb1;o7,{y}i}^6_n R "jꎓBdض`drnm6߮v.qgZfRZÔ#[YHvf-F]jn"BӨo|z#&G8}osWrnWA6fFfٟ-ٲ6-O{^ԗKO*󥩾cI{cdhZR6- c 0%D*mP,JP%H Y4ree>R=q,9(ܾ^cv7S偻ƤE + !M`AHi쨎Dm,0ztkd'Ξ# nͮɩ/\XVN~o TJaB)DJixX(џ,pBKT}2JcП-looL#N~7߹{&H$?5}wܵ9~Nw}ĢbOo+N?[Wof`%W+O>o hςk{[7vnD+6 Pzum)qaB4ZNve(ePԶ5BRJ0"C~`|Bc~}C37/|7~[5p="?:;M&9Y7CilƁЌMdJajĥjZL潏? @ʅTc?uD~X~ ?{o~u{D&\T'RI2) IDAT!-+bZ{߿HRi3۪,qZT? ["#%4+v'"pYRRP$Dác|soX[\,UʸPł&t4l2gb3CU 66P)b%B&&(AM`LP+lr7wTCC3wt(V {L&#`8_*rC71F0  Ț81N RR&EQCSn(hѳ!І34ܝIR&д-2ګiRg@x h>j`ƜRjfZn6p7WB)nJH0vP'+K Aҹ;$J)$%i 1ѷ_q$c} &h T2]mm&b%a&U"u0!m8V+ S]EvP nM6ع |֎Я}NQ@d _/+~ѥ奩G|FSOy',G^x|۟uQ$Nʉ4\nM`'N,Χ위FZF5ѻ~:TuGuЂُs+}_GR.<6ҷ#w5v2Fx:z`ށ፭t14 kMgw7YRI "PڲAoE0ǡ/)u9;wsO[vF0]bAs}'Ύ8m+hMyXnTMq CϝP]yI>32q??ࡾѩW>Z1ǎM-+5'|)NO$R{n~r}./Ѯ?g?ߨ=W(uGG}^poG|FΞ?=7@bB? 0ݍ8KVn>S{m،n4W7ҙ/|κї ˜8O~}㷿}S|rg^WSQ-@mJT hn8oNαT4% -_govM#0@(k%9Pb8WsȤ&Hn\dJH8|ǩ>@2V4=3[b2IoFe"[fJa 8\|!erV5Q(tk{NAd;.[bkvv}~(X)0T)̥i`yo7RA"fXm~>5Bar+עV4!VFa  K(V{%[^w+啕+_\Atl4|y bBHr @Zr) \k%O!GONM]2K3֔[ݏ?m≻.᥇ё'tz˟_>}CJ h$1vSvY_X09͵aAb}U"" {55/8ot>?B gnTٞYpM7>VV4a>Xzo;[ȎWs+|;ݧ"Hڍ`:-MRG&C 4C+W,G BR\j&l=sV76_꫇|?xek.V_\~置\īϯ|\edB->Xv&_zq᧿^A+p_+/ꌥ5MQcD, )'m՝@&eDEi]ٞop\KNW6~r00=qyp&i/q[(禫Bmc-Ӕ75{{AQ_2z DHl[:ڬE)  2M`"5l Q% KPǏFn,V'\4ע4yNF6Q 1$P2%$ډ8W?[P)Da@H8}JDl3`o}h(MNsT0`ű)GXZr+W9xzD K L dT-v.V˲,`s 0T m'tijC? 'bZK5Z?^W$F1L̻c ;o%%W9v s$CeGRqb~##۟o^݋װQ6cRVUkI%rzaV"ϔwa"P 6Y(u]D`hxxM"QTB41oq.]80r ^y -Gh:GG `)Bw$!qqg|wThܼɏ_պE{vׇH½$Lm|qm0 M5Pi`:TH+0BI DӞ>4;Z]Wk[ߘ}!n,?~' 'm_Ÿŭ7F`SONȓ>QXYԁhGׯ]xާorP}`X~m||5nN7C#l[ _lE%>X )9{;VJl뿛( x?r߃žIkUGHXZ{{IAHei?7"C }u3 E#(ثZ23/޾uc'<_=_xՓˏ7]0>0G2ҭq3w~;;WK_gDJCh$D8,4810, JoI?yÇ?9xqS3_x݅PaB*Kɶ+SνV=y cL?6⋿~F)%fO|ŴA++芅ݽ]Da2L^q@xaG)Updlxm$mgl]߽j{GcN^Rsһz?]˷Í*9&>y/=<40Pxԍ.pSi[#q!'ƔH}inm7fܕZ{6<ǹnmzTtUD:H&=;w^^{ݹ9Odwߚ=zhRsY^aLk_W{¯n*utp5)ªJbyrjPJ<]-̨DoΗ :#YiZ,\xj1t72ウF:*t-H##Z#sD7Z{gb1ޤ4sH!)*C;&z^YA ?XXXZ3o8??Dq~2c:P`2i3=nvl@XOU-ѩ.>=66>m{/`Nn\Q!bC<zNu\(d2%;^Kf@3,Z\HFs΍ N?1[f 9āg!&BRl~+|W|Wrc Ko˺6G?rK||s/S{ٿe𰇿Xv0;:Fd, &Ow|cm!A[]X>̣4Biy=~w.::$\ ^H\鶚Z6<:;-dZvllLs1Lf`S dX=İN3'FY24>^.U/yL> Jk"v1$eʼh󒤗fE Rp׭l۷੿uO2PrvCT.XIpT^ʖs:GC"oAEn!zQ(e ()RfSgAd,#Ƙ!qlIph8T`. `b2v,Ck„_(V~N*i5[ҷ =}aD+ kV+T`BDk fm7ZZMY7g\=yrW;Џ@` acE%*[БB?p} 7_ٱ>_I}ßɷOmO= r߽`ٱ[&gx;چTct}uHerhA|^QF*4<ܸswm&<;q=@M8\Ql$fIFtt|ʼh=kZs{vHWѻyL μx>T[N]t#?ZU|??Gۉ=K#28K0F kdWudvh{o~vCɒtӢ\xG_xEZbYq,^M.avy aQJRV9%(B[(d[zhԗV #[mX]OUT_kvl_^kͅ8:nr GQI'Rv{8Qj#r~/K aCcIȒϛ>*Rж6S*/A+<_+mq1`PypNTsQkFbcΜ5v62i/U *∌kD 1Rg8Iv?TiۯՑ=ֈ PJ1FP$@ŴiVsfrւa (RhPTpw%AJR.Sij0.-.'{a:gqI)I\7맹$z:R1~¸o raR@iCS!'!q=%А4*ONX>r!u<xiPc 3LIxVgV S$w8l\fʥ -ўvj+K m[!ptӭm]; bK!Q EzX Ф2 Իv} }|@AEbRt 9FI.7:wZ+.jy} F>Ϛ[J)&owCc!g8Xd?ϕ MGGyNgW[[sxTՓkW#ݹ˷͠ о0uQF|p񭣽F+WjWݾ|Rm C-㥵De{vn]YXz-ޘ9{v~=f=xO8, pښCH*I)mimhOs{ϦY֥ ?{nRУOoμn=[y}u^=E󅸷Q#mlT,4iрB"BV7M;2yإ=FK_sŐ|#8r8i:i#3[/4i'GwrCʚg l؃%g~C0X"@zVa#Oڛk{gfΟyꝵךekw=/B޶zl2IRQ& { ]ttW p1c.֘$Cu)/RZƘva@k}Ƈ7VWWyJ2iQ+#fVn/TsCbYgialŋozxHq@/`bmEJlwV wNڷg*~~>P< 6|i66no>wZ }۫5DoR[B Mc+ei4I`uWZJƀ֣۶mn.ߺz䱏ߵWV#}7‚bcs .Rc0!g4gc#9L1Ů֘szmQ>3s.nB?8 g柵xS:sqÇ{ʬ-J gXdy i!,IYfo=[.WZIZ-¨rikB.94i\Zwg?Y;N jĘ eϐ'uF)=.Dk'kj$4 @2өnܼrkf=ݸ<5YIxgaFkc=Oi5^x2k=JK?vѲ|c E03y=Q' fZc)&WQbLHx♙U)36nb.o2J1a4xڭw?;>@dbŅȷFԣ(υ@UsI"W?C7OcƴRIW o[N۽z<uRg1OjRJlo.5bgMdt[il|saapӀToْs4,biynkW 0i-,3oܾ'7yv ^ @Zk)؁BhcsKsC+SC` DĂP 8KRJ9lah?wG>HB&q$ ND0q'sM#;z%J+"I%X 14m F;e!M?KB,va B )Bqb5XA {|ht{?7}pnht;W,J09ܹl>oщvm6+@!(qyA'0@]\j w&{ l z#6>{Ž'=oUP#| {D9` #q`JQmUNۯ0X᭓V 03 '?:`V_^k΅^.wz6p <2 S Lq{Zrcans˕_4V\)vZY>zt-1ϡL+jHBfE98@T帯h HJ)m5QQ fّr憔v`m{j\*B^qn3ĺ`>mw`}c{w{PuԆ80Am,FD*P&EC b`O!BJ,8pȂ%Z@RؼCFG:/y8#JFZp}썛yZ1*NVC]o\NPX0Q.<*룃R9)%cO܌Q$2ƐC&1ƺf4z$4^=+ Ɔ2M&3=/RȄf4d~@0P%^ygvz EE$S! 6waιchq^02UZc}C!xLA.yLBdsSX#N 3 , J,G.T*F^$@97T~GҔé.O6)gk9slA[0ZDiL`3i޷/z޻<ť9^*=۟Ϗ~ͧ/W};w<ӯG/pњ`#j!/XZԟq\h; lɇu<_]XڹaZc"kmE B 4RD%MjFQ quƍr˗.cifm`̃8mA.(>>'rɤ(c)u/&d* F& Q Tk8ւ p fb}`;Fi5 Ʀnov|^EA6hRܺsg^OKaOzQvRƸPn^*O偹յϞ}DyjOs6lsCY5Z9[ <"0F) 2& eC+3J e1(V^!Սni1@SE7 R5rNjpGA_{ cX)R:gZ5u2 ccjJpZ1PJ1FJG;>\U_hCFm{rg;vnǚ7rz#ZdF>PrF01u&`}#E:((`<2BaGY`rbd (g 4V9q`:V40iՆ&GW뇞xjtV94+c.7G?_ﲍYe Ok*Ӕ%`Y&8'8!Xd-FX(c3EO ?ƞcwO]}3{l=pǾߵo.  ̴f492|7?ܼ*ܟ9ږ#e(m{)c^]vzà10d@X * 0ň 8<  ~b}aQ鴶4wͫ:`w:J޳{>vOomnp|pi}ͱt"K?{dzbf>tZl7o.-n?tw/^qo`(j lή*p2LIRGA4M1ƞ(Yk1%pIQqgi&~p'?)c/_=uҡCGxW*VZ8sn2:eollߖr>XV1򱔨zԊq\mB>78gAj5FFZ 0lkv׊=kaj 0,)! &DKM0A g)8fodni|px{~/թ2ccֹ\ |MJ +EN13\`t~`q`Bk8f ݺxa/ CK8Kb'KXk RFaNC1d &CځT32@R)5!X*l}ݍ뵫R*kLT*iwb9&Y[kfRy^RiUJQ:8B@(uRIι5se2G/n]w5Vll䎣w9dlRg8Idx/H1%x^1}71411ak9c!OP0TA8!QBp3Fe碐` Nbi-cL)wRe*O:Nym]ƞ|+xcF>2`MKyxUW닷nuQy~ *ԛJwJN2eQș{O\}orf{eٙӸys񵓯._j߸W>128-JZK )jc2:^v\= BgQ8mg{f0 =OϾ83OiwȎT6KKrOK]#5wJ'x}s'+[F7I:Q i\y::D`3@1u98c Dif2vx,LJV* ~w~M*bкX9|`57ssW?{?).'فGDŒTߛ†"XL2a |OvbXk$|^e捅ß©wMN-ި7jGÅ퉃t~}V$5 )ÃГTn)qYCOz/UyXM`fAsrF+x"e>CE̷asfy"KUaY][;{2g@dyéU92FA:o!()10}P!~]Wk)`T\$-/b^Z8;+/?;͙=;ht(?<]pH]D'cJL8,ˤ1Ιy[읰T9d` 8 #[;\ ?yk|.K/|g䋓?.ݘ_qpy4*cy֭(`l93 Ohpژ 2(&vl0Psd6៿}[7ך;8u`x 4~1߼7ӸD:V^8R` n#4:q³' Ih€:10%Jq``! 9n6#wm1ھ1 ﷥(Ƙ>Nc<0r^Hiqf%wE^S[+lŁ9 Ա~z2ZBr6}9osk1s&Kѧi@NKuNJ~Q>Ɍ({i16 s ÎYc080Fg`M?v=(e$_}Ruxl׾zpN^807 ^RΘ\i@9m*E| M%os[?䕟t7>6VfsAtZ@n׍6*hN+\eu~"^n;v$&q{ITLV[bccko>ӟR mr9kFA9IT+[^ 4M8fgq(SO{?}L 9۷w>17;xzݷDAZkn_c%zQ8 ;6齻ݬ;VKO]8|W~969=2umuKfgZsJ2N c,!;W6'th'F,gޞ~~ܩ}yln]'ݸl^ֹqݲmλ{W_>z9A{EY/'~|y䫿hom=?ꕇӞN[*r2s]{ű\YQ98&j ʤNk 7lSb[`a1fÙvlwjNQ$2q'_ڵ7ė]rۮY+V1q ̋|'3S9gL/iQ,,˽`c LR$ȓMfnذ!51`[%kh[>u8^;לڪwF7MFĩ.d<@Jn;w!eC`'džuV:XK3c0!@V[F)5~3DADI@jN T*vڱJ|aԩ4j&"M0jPAXQBN1&VzNݲoeNEcl k9wV݄VX9q*bj 8$#¸1=0Cy20eP6I}rҽwm;-^{~aw߼z:w+2AJ#F`AkB,ъTh\V많VFzGg^zew8y uiftʕ+/k!svu׮Kf.H4|^F ȱIQo)WHR!(0[cXK7Ͱ1`(hvި2d\ D$2JXHz|Y:l !c҈͵چk,>owʕ$@HShcXR`SWnJ=ѭD.;~|yy%Χ&֠hc i|B:N;\k]f?8G>DpY_x|P5rF)in3^X{L t_86 q"+V7 q]?mw~b'5ZmRLhi)K'dhߦ(vbhL~Ўv(4X`T j[0=e\1M,KaYJRJRq\?u%zq$+LԪT*1H5]pA9:=BiϝfScZ+gbd쌿e,u6b ;  x.$m412F"H GJǢ ƘZf/7ʁNʹ+m۴IRJ!HpL\ʔ݁}?I Rm c F'Ik>>P$-uk\H-Ƨ<߿XͅjuSشJg58ALV2rz8 $LrycBKj@8c&12$Ŕ0pw36~JkPЮûT.#rGb1Hq4f@Y,6d;v¡s/$ 'a%ozu#.^w=?eiZ`'B'IH)`(l%gHQ*NNpt߃_~y6\?~L1mכ+ht(ccOgfW|ۉgxy^l n>{_2 ccHԖzi4#?uus$Pq1N2(f=X[2 rtR4aR4wG~N>D?po c `$IDo?g1bG!,92Y3\y3YX,sў|/_V%*~}{\-=yv0!p9A*-4"\G@V>}ק>}_Mo(^id4BP^Y{͍1?S*Cq}Uhr`ddT;J "`4rsMae8w*&'Ϝ=-szd0"ĴUǤn7QR Cض Z`zJW IS9HoJ<|ޡLz7n{?=w\uԭw/?k>R6+#$Jh0b,)UZk$uHPG:OIg\qZY9'NbsR8N'vj S8\8W3Ƹ}i"tU (lW ᩁ NjChfg'AJ,1A5Yϸ2$}_])ZX/l~vj~9[kgX^ǩt8X Kb7?I_{쩹c"ܾez2ȱ>$˒K8pBʰJL' SP i3w{NµxM 3sk]072.]K#mR"uNi"ƗXc7Dk BwQeNW!aN"@~p]c{{GK˳::M+W.tjscg]Ns1T#Hf8u!@kB &Dc@16owq쓫~|rc>\cu}䆤J=KcN c!B$aueګB,_r鿸yqN*pF$۪zOG[ёS^HfxKbp%L;F)nnu`a_rZ)Gmǎ,({Ksc}^t89`Epά`6IRq0BHc;]}q]g PVSFǕJ 87ک7WڿD'bZ$XN(D?[זF?_>Ϳz,'S^vxFh&La,uXVfi޸/c [ UU!u>;Ꙙھ'aSq˶Ħ靼8 {Û\Û#ѡ7?ίߨY?Z.7a(5]-98:^7mzׇ>s0|x*(nJ~/-OҶHV*-asop0^loyWSJk C×֨xezCvoL=SO\~W~u~682 Omӟ[DQ]jfU~HSp/\2]Aֹ]\?#o,k=թ5JQ'.ƞ~?}vر`Ӷ]߱z5s( 86íifoV*Xw az7n L&s?}tzxI10d50hWWVc}n]˳;0<`HlUZQJ$Xrԇ~3\TY[3`ЪFB%lU'vkbb"LbL)al`h'y/}2HBREOvC.(k%`6ٮ!L8e=kmP>Rѵ&Rb~3{f)9rÝvvW$J8 P.Ow6()1t:"i$*) IDATB_c%'Ҫf F#F%"\'`^"ŇRS1 ;ʀQSR4N|"nZM=7߉cSަ5+ s;erLp֛;~kšryeT:*62&YTIo9]:*ŭ7$ai HQfh{}vMI RmB=]6i7h]w|/y a$].߶8+!Q-}/=1HTx[#Igw74vlefJwՋ+7 >زgg=Z}?2m܌.+gSЫZ2*ab:G>ySGȊԉU=-[0^ʂlfH6k5):'UJ8xlCwK1_9/;k噎B$O`,@QwD,}#:Smϭ9Hb0+0iìn!e$@83pƤ1Phß"H1,NK9HETpD ؽn-xC>vY>TMhFzhoG7WʼjOM?m1.lɮWwfwOn|뵯<7<*eHJ]Hƺr0.W.`bc80̎e ^ݾgۼ gNōfێ'}e͛wM0:"0r\" %TlSk!܉#V [C%3#{o^=E50XDR:L*(a@Zf!X^\Qe0(Le7ZuDJ`6Z[*0Za &ĉ&v%c1]۹T{RaJ0:;s,Nxw`ymm ccnY;wmn5W3NϿv:u.&YjmR ιҒ7T;3N)1B$,%'wA"Rckcbcf֫9˖=Z(%zǙBo{vmڭoS_0|3uͬ 9]3LQܡX7V1easןQz8+ggo"Oa`7o۩0NgVk'D<`ZFk4>/dKԑhMu-Tpk%'C !h8{ N1<`E2- OM͟_u ] O߸,3|g&4XBrꞏ穡1/~%d,Eg">v:u\Sht"m7 Nfvl?k4,}׻<2 uέ㻷6G+ۓ[}O~+?r9`ƌuB) Z(FЊ$t#Xk)c8!FQJ0&x1J9!V#B0ZՓ$Gu9qʨ=;s9 Pjɓ§׿5]y7sZ}*N!Y# fnkChꕧ<| ΀Z5g=MGvX8 ۡҎ\5\TRj{$[mB6Noa4&1lGn`h3VÛDl~h<¦+0Z%B}qQjpY[ƀÝ\Q'lɺ'qB8cBҀzF[DZJJ58-Z rN9FDT:PBMo4w97aӝo[Mv]"mB(1ҮٲJq w٢#GF^pQuV}~ޚ~2U}shg''f2= TĀ]PwNucd,XF`9""Q#`Jc c#DOk"l E`B@iBHnbt1c󚥵VYp?ؿwGG7z{ _\w{f/: yBC$c"$ΐ/"CcxijўOW+wl2;vv++nՉ}KTJI2T[aU¹}v2:Л___QT|37no^5W\={WTZ8SW.m@DZRJZ7]xz.Αϯ(b"Xq02>gʵEУ;X :;ގ3o=}~o?lT#t (CihvLH @B$TƸôJQjP@PɤJ) <7QsEOQƂE +WjoFHqjvZPt}O6E.%? +*Jm|pR`q~q@\ DLQSΘFcmg //)m62hjH"u?yvd䖻ػif-UᆭkcjP@026z3B"FGeU7Z򝁁}ozf^>3X@эFKCwg W}U$¿2Q,7wm}'1l瞫L~_6|֯\dVDx֪ˋqim|C^ش]Z׭F^Y]=p+Oo_qtQ"@O~ك[.9KB[Yk6ڔ9Ӕ)&5-/=_=y؞;_8nbqmTTvD_+U[-8ۧ6Xk Zc ƄR !ўX0#;:DJìL2Lʀ:珽2B1q=9Rc)Ō{3Tܽ'f>12L7r7r3>ydC7jGlU>#;`*7P %|*OfZ(Fp6+c#:r~z)HΩ?a3=:1'&𹤉Y۷_:AdE K!L)cTe'?xC(5/<}CvoI%@E!hmB@ ^Ek'IĠۥZʨ$Kk44$=lF[hKm]4X7"j}^nsk-ƔRZKCc! RJcBcQsĄ"Nс{o_ =PwZ>r^_- _عaeR)[(NO..[rPНN&D&H(IX&-0(Ƃ 0#0D, D +1!Q AJ 2BkC)VJZ-X) #RT' hU˽~m,mL]s/×?:#:A"99G_jsDXC9yJ] hud$hҖW'X)F4S|w&ݸ]nJvlݱtN7Pty[jGrI^VgGm:whci97ܼl0.@Fwo\gvl8hۮ[o =T.sϝ4c_pC).Lf C[μK/l_C}dF=NZ!ز98b ߑ޼gϝoM8sJ6:I0=y~ܨ\sO?j[6>R]-~`V)xظ{}wr׾L\à?OVZR_^8G;vn@ݖ V䋖JG :$ر`iDiNT1AEcGjQChhƪ8Ϭp ~91Z+BQ6e:jtIek2rO^ öY9vޛSlzpc;vl8~$hM߳]^>.j"WmSRd(,Q$ %]=в;ry~tv ;I^+e {Ctf|ۛ&ӏ:ُ R3 p"!ޔ͆M;w%ƶgW`#wx8=>UZHWW_*tcV:vlk锗ØX#d6Fil,%VU?Q-oz={xvd۶H,]~KTu$$r) %oRK*֜m,h۵?1Hc-@`YkI຺klqt1PBDgsI+I+Tbo?c^eFOͺi:Qu= CG_<''{z'cK+MQbɘ@GfJ;$#U(MKRP֜3։p (c4: J !L(371"BRB*00 McãN*#YT'^x'~:t+; W\槫a‹ɥlv]:v㏖W(ʍF@Z%:v/;][)ݵ5utKgy@#uœoe}7y韞p7_}>l-JjN: 8Y0uR1P:C!$}!k|N}ץ))XzZ ccMzx,J)QHZ̴E|dXJK6ZS M>~<A GR=3nBTZR.(u>j&RcۈvMeH&$m}L:_^`jdx@]8q*Kk~̹EsY@-kp.\4xmϜs ޷-%XL)`,YiMw"F˒9,՚{ bcm5cQʼn%Q5yPݱ0"6 r<79li"mXeuJ[-tܝKHůK 9Ƙz#Pc;%cҕS荾 JkRZi 6J&Q"Hc !D,Kzyf&GKnnغ)AP'WT^Yþzai-ŕHS 8uF`0$Pp1kׁS0FR&P*ŔsFF[yW?%nǂESFX`l.f%kivlei>.}^7 b aR7  Ōh ĀUF1B9sdQBG40?-wP6eW^|գt!.WDt_}Ov9rb~m_:f;@1M}i\Rk`q@&pYO<-޸kkGj)Jl t\ G+⸥X@Y)7U)^sD29cZEC`p5̲29gʚ`GÒ$R[ "T۝6Ji%MׄC`D7.<~`p8zz;R^|WQaAIbI9DlK =@QZo Zk8wC0Ji⹎p1a"6I)%D(]΀)iv[R":nkaݎGjx약oZ0)TЛ51.NwǖϞz5եӕvۑ t2aؑnzjGTZ*\J&J%BD\n%9T+rff0,":m_ ҉H&gWW8yn-fS =pRRp`Ӕߛ|KvzW CDke #a%Fvu] xTGXx#5ے:g^mOq/8sثR)47qf\ JFFV+`ptzҸ^ZvM1}?M:LZ`.ۗ+ZfpzGcG^D%]7/b :$ݘdZj6N T:C,Дmse(xWxGKvܕOco'ý5ghapKĹV&iՕt6lzӝqTO!^~}mʩS'=mٺMjq۔kxp8ϤsA^*eEGݱe~DO8_N~㐬-h+纔)aRq9c,89w#ixpwZbk9~ZXowZb#Ck ߿O_[oz*p9a8ط+SgH1=!4Z)).LӃ7.gߔrIZaLrcյD^8x3,o*jbA7̏,ocnTǵ냑QGpŭV󌷴]{99St1 ܣ IDATBQAKI5yMyF%FQ R0~3})w{?lqu.!'(]*!x#}sc+%XXE_`EH23+l^"±dB@>X)Qz -:>z:Q{Wv{pf5W^g:&B*$@PIJBB0!$(3T ϰ@)mN8/~-p?1҂o|W'jsɞpLxRpOl٩Xk@r&FBŔ5Ok34Wp˲:v,b57z3wi J)H) (꿲ry{̀|í 6xhr6﹪3205(8E) 0L)ȕ[_p Fbov$t6^j(\G0fr( BL ʓ'w wn랑gN8~ZP81r5vNSu'0b9tKOTf0mccBXC`>jB@P*Ob &p_wr!Afk<{"[^kg Ͻlyf@IRTi$ ӵ/ꗯX4'w?+N>uę<6m^ E/A[Z ̑sӹ0W}&2 YZQŅ%af( 3Vj$ѫ.,잩^<_< Q+^Ұ앗g{mo\i8ؽ? >qSJpizC=0Im.Ʈr)J0i.D:%cs$|eR8LR!L)րtk(y]/RT &bwߟl4VyE@yrM`nr*~ݡo߷?oÞ2ЃB-Q\G?|O~ύÚA=/w̥/jDpğ녏^F,T,7o&h rc!Kqb.V6mi% Rհm9ò%` R3}0YsIR*st\A !J"r4q}RjBR;`AQz|" }_0?ft<_/D!J`!\1\ 1u/U3^A c &r9uwܑ7HsWxKC^/힑&BX WhhjweiZH/޴{[qqֻ0dK04΁'m-VpZv'J7< :s alS ](!+۲=%()0AP W|4'*V[oGF ;>1(WNOv0eB9t܉M;\5WQC:"#AK*&8P12W#gq c1ZH<7⬺R-]j.w|Ս/o>ׂE&9,_vd]]Igҹx{m?/ (յPŷ#{-{Z|qfΏ=H,sR[ώ5te|zbr,qűY ǀR:% R[H%J))" !PcL_*ߗcR8$`mFv^!/j,o[>! qfqJ=O?92\HKՐ8xqtt q+)TO.֭1UZ#a<=j6A#CMȑjE|[mvT­"4 +%(BJ $: Ȧ",im޺l=F(iBQA(;w_2 ?Ҭ^rLMCFPX# _׾b\*t6nrV\斗Rܕxk R T( cC`[E%*1! U^RJX?TBP} TJ)_!A!)$&XPЁW|]GҦշ??䉦P&5,˼VΛ^@Zc'e(W>ziڍ [9@!a/lmжyX)::Zw%C깒 Kh@2QB@ 25@]PT)F(Ec~x>PHe3x kr:{>|ty6dG=_8~b|i2h(}֛K@$ޜ*ফ4XV`Cd:k` F(x kRDmd`(w R:҂e[La;!c;w+co.{5O~󠩃|cHL2(/鸉5{3ڰaglh0>xܹ1L Qym6~ +Lyw^/iغk{>l> 1b՚kdXQ `7[}xRHW8G,&PK1&ժi@@iU&70q=bv0  2bNqvtt8mCS(~aj۟}ݧWo'>h_9#-.WFNBIB#@@םzR Ji}%'r.J ͶtBWx)P%R/nf`BcK*Z%%.00l#S6v $r 7EAUQu"sUpD#hNqhŁf<΃F7+Lh)vӖR,|ia)K@x.cj; \b:c>AgkT($c(bwr߰}Y4<}ͷf2 E8p2?E܎q虦Gt QĐs0tM:Ns!DScR!_v ~Sk.ݶj Aa)2}a<ݳv}t4p%O&!L\.{Fo8RJ.%ڦB4y@"|7\kk:"%:7UCLs~yj @S MSA`v4OzE7bZf$R4PQ'Wަ^g}}_~!r"X =0mMt NL0$,;j0^[MRS]ӆ!"%Cz!d4|5Rlf`G4 $h,Bw+NЩ`WbB4%}w/,~ΞB"r6_^\L$-mW_w[wY湧+vz@"]|aI5 Y;8x٥5^{o}xeUqu !)UJ`PBP꺁0/’J)NM$ ,8+,p8P|Goo 1[/4+fgץ J(<krǧvu{GKHOU5;K{рmTA0a%"*]ʮWJݛcM&cmOzn,g ƻA.%;Y?a[2mJJ, E&i%A >#c#$zsiQN7Ry3 o9:d)/;b0UzMtKCap| B(qNxSsMWR+. ȧT(s78ʲe+(fΟ,;ZOL5/c 9@BuY7BHI5RJiPM NBq:BD4Z(Ɯq @;~P0tlmX_LR,[כo]Fv,DŽq|7YyTZnKYjq/ǖx{?C]W?/ks U.MMG} c1qjp( 8gQ?Z a9a(%5{ 9 U@m|o6qJ4Pe@D7W{^8`RyP $  +*%9As.PB*$C3 T*dZLඍ}lYQt. B[kW*תb2nYEkG,~c;v47 *KJ@ן|OstaU`6-=k<ēFڷn[|:%~KG ^tM܍}n,R[=jPieϱV@3+!@zhWw١;r+ъtJ @H! r(Pp^.4Ԡ RrƋLaVCMݫW]>~߶cSgk-n<23?EVUE{z"Rc _A޴y4t}wx놭vԸ4 H`&b( %1a)kdh:JbYS,} *%M`oĝ^`",ΧxR$ZpVln%YfFEjI_ڱ{n JWjJFC y)Éaͥ3QˌbGxΝ;L>wݗ!?]&\DXhkzaA7 @c IB S(@0>`9-M0Gȗ,\#RL=yC-[>;:QVn2g cę$J*ΤR!!Br [=kطv?{arijO`/NəLoc#H&'g+YnVBy5]CeӖd[ gL:D .J(uP4Zm:ZXhhi~޳\}}5W4Iᒐ* }4NpνRa7!)1XYM/}L]{ j!}O G.;yQ hsaE2lynqh539jrP.ԲiYBl.%du@ЩT~4{&K)@J R@Jl{ BpZb AR&K޵Kle{/_ckoK3 5jK/m~/wKcÆxe2wv4=|𑦶7YJg#-! M414TBJb) @J2 ŔR@w(B蜹bHUr0B:RfhvpeOeK!U[SڹS3S~,BzԿ>6+Vr9|0O]:7A)\=sU\4[$ȭg@xō$@(nr_%` !\ D"1&b }`dd*fu}я^HVf,‰-?xblnp&?b;vӎd A J) (!/] SϾknr]^xsk?|z],G}K Ft]7͛ыAnlLHÃ3fTG,F0iJ!R{+#``(%` $ 3H( 3!$gMıe冽Coޡ5qƞmΏPh˞^ةv&sz- Uk=_?|0ՖgNMU4Եv(jOM8>Kt5%p`E} mTj*✙};ϔJa_Js1.  $^-V "@!`NO,ۻzeza]2kHmRss|`bLN1}`\Ie+ê߱(ϠZŒv%kg&~ IDATޕgsBdCv]9Y#-؛tiF`@\6S-HHڍUQd9@h-^b`1yeIO`ZXX$` [549?K-_XމA+jz:!( EC.c S_!Wa q\MzE$H=Z(L+HIhsO Ø; Rh\Q)Ā[l? Њ+2D&J78;zz 8IڹmLm"5-dux}?{yͶO}~ò\,牀=Rs j|#ڵư\|XinVc Ee{`Cawff¶y q;nhu``Gab >5)1Jz)h5&]P;BQ=v7fƍTi.?f0 =;6/̧GFԼ+SK/եqgi65]7Hz%P)-gKG/Ym6RR)8CXHĈHT@H K(`¸eO{n m wTf5Ӵ|UaC+BrXuXn~M7ok;kQ]ȝ{'ü{9s^z3jWWrb|Z¹L@P}#q|M 钪YV0NN86Eułʕű BߴdijT*o[~O ]xիSϚaWA;Jz%%סljJAQm!Jq!DR x?y diD8>}|lX\s^Zn}~wZ[[z5hiWM;jÇ1Z$gi$mοKn[ p\*}; 0Ay#n JJA(=]ױRyʖ[o9\ղHDH\nhrх;綷%]Y؃ ܱ,h83B@ K$`[VAAꝿ?;-h#MS; ^LzUVw6 4 OB q[Bꎎ`qExp°!g 6nZ̓b/ß fx]{غWߜռk[Fd `>\ P{CśJ٬t,D(]ՠxzqAғbع#ǫ }@X% NHzbL %WBL]w\pf<]=w;cѱ}D>7mC}+\v۷t~>ɿ:skpffamof$bnG6l±ߟJ0"0H`TRJ!r!qܰmh"(!H !=Sb=NAcr=vT¾źUw̥9 =Du!kiR SD]wܽ3w>:uP_C=OP2/_uO-.6 h(`٣0f{*$P1ں38J{f1cu ^vX*$t]ʠ/=jےdS_?oj{Βet~4 [mCttغzyJ܃F.-7}dU22[@8n@kZOxj\?6lضR5\ -1拚]I#Pv?u4kJD1A0 n[nPmO"(&D "K)c>D cH(.Gq%Z wNdյ|)J:{d`%vr'_xx!i$퀂eB0axs3bduٵWVxn=!xY㦹xnd RX"Y"rt{}{aPI(PL5"uMr}{>`JBPPѮp|-"8V0/F=k^BN%w_=[>d,k ){:4B0uea05 ]#&AuHz1]^ew44zh+̈́͞vzl;:0q#7P$huQuC"^i&}zZ*to1e=wYV'LH%ngIWRi^gBq@ށPk|GJ/]N<&dUbiTDDC “ƖW.C. k*F>l*S]!- #G;ZbkWG;W= lo--`;Lp4,%W }=W2rb@qdƂw!Qjf ӵv{k1ı#B!x4(qWN~)ҵP%A#W# MA`\,'@Օ8QBFH+~I T Ĺ[` !tS D%byýgPb4ѹc[B&2HiDd8$k 3 rv@QЈ!E6\0 R$Ȫr؈yACXD94h4r\=-Jr%2gV2Z>dډœ jy_F0jXޑ?r6H̎ צq_}wEk޽O='~Д^wpɎf-ֺ4zz9 5$ ]݊^ d"hǢ֐/_K--uvv`>sh$x$lZ-_B+p1MJnNBAF4 c[B)AEQmOFz=ͤNlS87qՆ'yglqJn@}gyt;vLߺ-r<(--WJ3}Z|@b!G `sfRM*N5B!ń0\HB0&WF yBD0*jҼS `0ڨ#mcmzaDF;{&EzeZZZ Dey9%lmk]'ʵC7Ҷnww^V85)lJjىL/r2)kRxՍ_Er}~܅fGWT6\miQC%973y;w?u o2|oY  5xfyvԱ|:f-ˈ# By6g%ya]gْc®A22+nͧ=}D~/ǥgQFU5 'Cv {~ݱqxk-];Woް>1zU{Vk6xmWڐԌY /u7lz;tح|믿ؒDGf+3TH(hIK3 ac $}F GIwk\AW _* 1sY|ީcV(N--V,:72]qŝCʱsιABРDQxѣQ:8"&&CӉαBW];圳uk=ܷH)>?+/_wr-t/Sl.v ֥\8u>rD&Q*{c݈2 SQ64C?NF* !YRM˜X&ƴQ)d_gz|5k| V9q9Reeٱ.9#=[pG̮55@/Vm&N˶&$O$Dym+| O?WF0T32M;w,ݻϏn+v\dU/>v6λ~S4uj$ecjBڈCqO?H)_)ǀB~$ց4DP%&oFl:F"J04mk| CN) *! A)M!#%W]]wzKKS ]IjǓ}Oի3>w[7[rU #` Y6{E֬NwJQ R_/FM<*S4Z&x᳀ CXJ%@bJ~8PSWRëm86j{zaD ;<%:H4ǃa2V*ѯDgT@ PRGŴ.?{N!TwtTS*T%S5Bz~fQ)::Zkŀ\y[{.  D㈕48/ȷ+ڟRs%7/O}~5e?} GoguK7tК5FY&Z"KSy[bqbZPDثUȀ-XUCPlݳxK^acٳwh4C)3-ʯ,_{©DUaLHB< uoOx ̘:ᓧޚ<ړOK%KCo>T:xlёSǂO^{֯\斫꒨L2U)WCdZZu\uμ΍>[ ( ]-]'RDJN@ !!XBںfqŸA2r9_.} Xw &-+*L33}kW{ۯ[U(n;ۅNX.L.\stإ3x'OlپD_S:-!X7NUYu Q,f f|yUKZH 3-nꂜ4Vm]aAr( ȯre|u2(?cRHz[2w\u}(xfh4_B<}Uunsh:Gh7׹|?T P$j/͌M׶ac/ą3{[3gїzHitӰo3k*_w}5L&tfe7s|Q %!"()0 P2 3M,R"$P GPHH:<B !KM֮޾~:wna_ywvi .f1+O~ᕶ\E*`BXV$bLBt(fG/@p`8PV|WN5ӴRNB@(fLCTxݼ%fxy49w:zMѴCŦ޿W=POlYܸ“O8:qC_~g~sR^WVf|S3R%D]ޥ\T7e[]iQY,j Kx̎ҝW^RjY{vdı(SmjUѝr ^}u$U.lSk-7_:?:8>;aM\=}18[)r=ݜ\7::\>w2I-q$}Ϯ(xrP|5v[MR,TS/uѩYiPS*H a!I!0Bx$hRQA@k!Qd@g IDAT*۶k?tynF4vRn4:0"8לs to䗵ڔpB?pgggf&.x-Km~<fMdsOKǩQMh6 \P b ߘ`bT -w^+U=j%}m (JP $o !䂛Ź@I AhK8 s(s0΄aRJ3segؙ&n۰|lyCDO)4ҵzZ3YB C FٗO=i]283 @ TT .9W;T~M`ш1D8 ]ݑ];++|4s0 &WMYi+dS_tuwNTFmR!^ZkZP^MSVS.d0L>^`dۆEaP4 )}cDR 1QB! P L_/4UItW%[,S鬄TiiH{[!/iSj4I-囿Zuftqb8bF۷,N"cTÙ+e2|)h$qjh oPA41T*Sjsw6U BǕs6<439aeI |߭jƚCuv瞷㎩3'K(K"|d$bS/>]1{?oBXxX 7ds/?}Ύe|WT`Z6Ӻze*, 'D=Z͹ G^K@0{y|fVK&#>A1&B4M8&(FED*1R"0ϟ C u(HR @)ob̔yn~ßJjU?TSk7cnN "7#VHțgN.ھL0mL,n-}י$@P %j8 Bd԰ bfN`RRa&bRK_EOkכ9 0MV 0;\P/Dͼ^ 5Vu4+ B & ( !VA :[9<zѝ9t|zUiΗz h:``fE;Xuъݼw ͝}Ϭrsڹ_ۏyyfkع"(mi=\|u{vpLu2XjX-9;{:lcdq3b:"j:D u!c04MТ&H1zrHƃFPTn^VtJ7':CRZqc$s|iS3Q ]Ǥ\.ymscS=77l t*iDvdr~ɥ}ͽ"Fc1#f Q3(kȤu6\WY񤙈Nə 涳'kZW2ţ[U A7xցSz!Ƙ(B7ru7vogpEDosgϿzǞ Kt@U&76?kEcG _"X}c7N>4,o0ؼ~ݖ|ɿgcDY:LsuZ/V+JʤDZI3dSS;?#O:[?wyN,SRHMݠR2R) Y@(VBJ*.h*!)sT! %, RA@  qNfdڦ8$n4c lJ+#\o5?gҎ]WTmDN',lY{R*aYz]'¤8MDVځtRB`jq^zD) & ) D&X*'J E)#1 @^T^+;?p?M9=57eI(q B םjҀi! BJJ1B@piTpBB\֧K"5ݳrEa4A'iQG qMw|)-CgWޭf&=l% P `D5dH&u&F>%˧eygzӾwfr zt#V/ґ3z6pgߴ}6ޕgGjnذf7~Z[jZ\mmyՍw/~襣et%F 0@HH \ qJT2dB A4=X0AbDB?ĚV(TShjvпkhذ[ĩ27F2LYu dE.斫?s`Q(\5u#SK?/3=`Ϣ\s63fvsޭk5s53 6M5Z[3$ LLO'/[xf`F D4[Oq"g]bt~xҁrKJ7^5sa:S<1m[CZV,ϕ -ȳ?s] ;^KϿO$6]s͖n|y_.kJPpoZ(k2Bjq]߰㰫z=.^9Ijb&#(H0U+9# 6\ؠTr HDP0 s1FC R@EiAw:hW{Vg>(KUjb$`S A$;ꋈ WbFs-~OB枎?P QL NI,\a>߰a3HG0 CCbTwJ% 9Ґ‚siAPȈnCE0!O0! &0Du"LtҫoFcZ+ /Ud,0ߴ-+J'`E!(Vj+Dǐ)ܴE> Fu-Ӕ6t !PJHL$LӜijC4=4TB2%5".Ŀ fP2ӻ/\ꊽnrt쿀`sDkod:p]xʏMrk22^Ps/_Dx|ѩ»?x᧟w:t<njFs,Z0BCBB!kXI%@+% cLx C.ŕRcPɕJAdqli|ߥ*ڔn/f"|ڪCNͭ6шciھuyc=r&kB"k(绺{Bוn#iu)!!ˌxaYI( }4mJH kB$q1s$042ABaWm[B}w4Dy̭L=8E}Jp[&FZf[7 (JITF |1b,0@B(EBe얙'>O~=˒M PT] lhf[d\,,K&$!P* n)\$[0ԛ;RGM'D3'=;ZFz+*/`o|C_ˇw7%{?\_[v-w.D;WiѨ=o,wѴGrmh;Ԝ.bFtD~Zs°cy ` $\p!! ɈfD:>رh`xl-3Z8GN?Dמk|;ޱʵًZi\|_?d{"P$Z`C/8du5'6%@BdC%BXuR@H"}JL)RsQu\ۻŰ4PVڳj}5T]SiBsQp3nOp#0ժI|.BW-6׊E"^42w6XjrlۢZ)9;5L97ۺP <ϴl\ª,MٚS4ַDXFie330R}pE}N@S4jtծ?W=#Am~ sɖ {XNȟݣg;3ՒC_4 _|891lTQdђ6ﰠY8PsCFӏJݛԊ% ^K%jP()P4.%H"0`)L#H0&@(Bl8х}%PkT*囧O R~v՚T:5 c$_2?z-$^=~m\ṉl<;&L^qSs 4d~(GVLMd(EH)RB@RJ`d< 1œ:2skfZFX~R־|5ւQJ4PF5. @ S>Tھt29QTA %aeAӭ1؝(/okr4-q/^.Ղl:FD j8*6.4*ZLӳufQ @ePtݴ-݈$dv7m/?^FrKH+tn>k*l,nhɣ>ޘm̅^ ,ݼm7^ۯI6wJ5ox^<dZ\)iM͘B!Gb<CףVNv-1"d'Q>*F"W'<-l|w9{lv+ xg]CԞO|׶<<)\֝ͭPk(,_scz"uj`TkHqF C@ yL`PI.4}LPu T 9P ;3v)d1;4۶kSykD2.㙹F-۵Vmˆ'zѵk=h!.ũl%YQ/VTm@\Sa>p|J[Z,.-KD[ %F E F1 kZX\Q PXמ,GXc@[m a*n;?~n[Vʌ,c4%~cc3[іn̺/?p.2סߍ(YdƣW,}1u[X_^waٟ}=ףZ?wEX:?2 Uz# SBPa4*]QJABc PKI)B()MCG. "D09>^в͉K|!5 屺R(2|!|GİΟ9ٶj-jm/ƊVX?VLT,8(n?p?_KjO~fqhA"bH)a 4()q<Ǡ6 siBR@2J $h̸Q7_δ7s,s]'?Cߔ8icP-2ѼITW hՃP SJ@|?@!RڂcO9!X֎ _WU64cXNQVȳ͘e`b&1,%SRYݨ+:#9ݾG]ȲM$c߼|0U~M+;$eלҦ4}J X2m 4d(PrJ) J0 `\G}?L@ E B%\Be:u7<ͱԆSn²⒫Ju\nm1vmدGon=c:+BzPJhWk4TUU%e&0VtŒaZΌ)~0,B߭ZZZ%Ώ XX#'İ".3L1zHq|:_i_S8tO?n,ӓqse9 GWnO|]ac3gcBY}>/}j˷IF_X 57ɮJL0[2C&6?15w3Qa]z||'֭>/{N:u7 APca1s0!"¿?!o[1$XiJiA'\X'RƕA:::t?ȦyM71YpR^wl;b64 cV,jgӿ:mitJ@m IDAT߿pj;w? ##s&!3Aa PGkZjRig@J0ϋ؆RJ*ZhtcN\qgK}ݽR9tX&cZ3A(&/ͯ_zBxX3b12_ D~4nh` !B(DC$V8 ?J~.KhFg,k3_G$jL@;Q1E s# ?~ypٖ y}I]/bW60T!/tVw\\h4&&[5ڽOݠ[7lb\w7˺!v;ulW>|?R]&0FwnS4&v]}-p3#Faz5K:$:l ,W%}00&Ht!ff'{͌X0svo{W/< f׿ϿmZM˖T?5fX@A1x fgZc-a}&_V޶e>)Ԗ5_ses:Y_һf͌>{NDBDæ1̬%ꎉwL$ȶ`3&݆JPK9)P b(Ʌ?J@Jɔ)Ti892cAJDׂJ('cmiKGS\*2WΦn̤TG0X?QI ZEuM%=O#DXT1.N)wZKgxMZ|T鰋H<*c) @9ߘL}V*LMO- TRI1`r+2m9Ǧf^TԔ!zwkdŖH{(ox,4C:jv$um_y3}6~ xiɖ+޼}?yA#+V0'gK7nTѨܴ0 I=n>u"(T[n[[ sRJ+@0 @"! !H)ai 0(zAB? 9T`Pɸ!D) CRjT 60d by/@29Ԕ2xGzmjU RQ]ɼS O'h Y?C팊eB)D Ւc~$֖ց`Jd  l1 CPjF0b) (B`AMtB8pքkD,~&> j%ݺ|fd*މ#۶-[O!fL`CZ0A21ETJ}"9c_ :l_kW^T{KjCtVONuxysG?gkutpkjA*a@`hi\:U?&;QN.o_-z j(r^C"N3y.L7 H)[QG toB#?u|{=#?jO DQw@U˖t-vnטsZ]q-Mm a|G+1-ε/íwgז]gޱ玲[6zng|Kmܶa>?S+6j}?|w_Gcx@ak?;,֠0aiB%P AUǂ{YrwػstOF3BH !r-cxlC0||cdc# ,rN&L]q󷮫_ZzuPUm^k~ttZmq:vϞl<^7wn~"ʥp`!p>oo_0,g֏޶!rpī^çr,N6?_Eoazd FJk|xbdv&$&{s,^+C0ѐ$ȕR5a=|m'ykoyrz^Ӵyeb/Fgie>3:|D9E%(a۔iZ\Qr-ioNLOZ˧νtĞ~X?}][]%F96O< ;z6*^z7Rd#xk=ADKzd;,Q HLC[a%IBf(E fbh8ʄ٠MH:(SRH)ؘ, J:E4MS&޺uS':˫qNRK/ /:V"X6wm;K2׶ A` 3bqPP D@`mF` #X% %Bc RJ#e&kvcIc iͯV<旚;gqyr<8;hlַvYUznj{DC9[S%"(3ZsJ@Jm_D\Wްۭksg:lb/&~T׾`Aq8{뷦+8JiX?0˪UUg}ʼn+=o9rm+W׼[Rr[Aqb6bB(c"HD |eN }КڌSG0ћm @J{BHK)P(1(q4eGP7:;|{&[Jcnk&ڣ~S~w`7(cR q6R*q 20^6$ط;Qڂѳ~にpEz7r*m[;eg_Qu7r 6iP.:fkϟ)Nrߊ5nUYcZ.Z^#c Fγ;()n"A.0F-E]-gMtfDžGVd|)[U^-Kێ>>96KlΫm߾U.Y׋sWR^wn{]'=W}C)†c8]w nyͻ'V39^yWZR n+{37ڮIͳn(bX[CHs9Ǡ1 +Zc )l8&T+fFg QH@)&,beq2ʍ1yZjLsS)($  5%ƩoXnJŔ=b6%A/? yq!Z*3{rYN ԰](dn,-NT>Ͻp:)Q +KrPvֺHN ^z?A?W2WHll'+Ӵ.~b;! 6>1^0=S5ѥ}u;g>W?GN}OT?߭z>dSaBtM#ZtfwN~>e+:p}@J'sd2=TKPE00@}D1eK8S ۽A(RJAh~^.v@stl9``/[#VdQӷݽڊ+ZdDa>r\.Ge {._2Z c/ҕe:(W_<20S'/ 2;0`$En\f"jjl"}~"eœnxrw[ź[^vidž#*oh(7^9| $TaΆK"8ٛ/W{~#\Q.u7\M|K?*}O>?|ܳ">͓ǦNuc([TE0RhˢTzZ?i TV`IH8 !8v aFh Fny^R iSoo6XFRrfϱQBwyC3>rgiR?=֡0[&guz&v)e2eN%LKS^5B͛#i*dIjW˖{;krۤVl9}`ƺ5=2< el:֙J\0'qŰgqG|A$sF( [m:y.ĠUp J +7/,\>q.<MHLyiEڼXacS_S^o끫.W_{x |Of7Ǐ>~_˷*xj: IDAT#knTRsJ=۳RB0h43a ݅{mfG(vK7-oY^Ј牴?ՠ5W 9O4ڡy,GQ*&LfL)/ap=pyȵLkVp5L,Qz>~pȩAg(L,RYi9c)ι9bQ ]c[6〱4b! 8K;N @8I"+JngPU y.^yЖ~_)MDK/wk̶n}[122Ջgn|;oW's |?yF{u m*.nfĆuv3Pؒt}_  "9jCwwGvo?g6ltv9ǠV}pY[DARM[` IT)#QJ6orIMDJԏq) <)ecԶY>$YX)'BZHn{fVMPk/0`kǺJ{]I/.`0 cF"`dlR,S#D m T\iQ#fLi" RIAZ8to @(bԶmLʼnK1 *+NeE oiZ0ܶńiufe!,SZAiO]@FSL)Ħ/c mf(jid4(9{ٝ:}0fL7^7èQm9uWO/{lF"yXr4>}ttn%C2 ry ۷ث++unz2A+ F0 RD#@ N=rc|K Fk* @]^ŞjŃ`[ ؾȓO?# #ccvR|nV$05FGar׿疗m4R;wߖ4 R(VJ,zDŽ" JSh)VSL1ZUsN[|W˜&_~/]U815dZb  tJPc@%, ZkQb CPf3_o/fr:Mϴ'WS3NMWBH84MBg:iQm,Dh EI8- Vօbu_,zacd `"۶ض,\mZz Oz'9llo؉'=ۗx͟|6hf)(֛1TR+mm,J4MSιbЍܶm$c0&J"Eάb)஛ðFbk}#Eyu̽xAg>o:@[I$p\[ "G1B)e4H420ZI1RYYe JSgmg@sI$Z=tyPrԹq5TI}z1Q2<@c[\s(@[){˕-xva^[tݲ.wZHFv2\MpJ3T8h !8#D߱i-'Fgc/߯kOo׼q7lϯh<64F rLN?W>>{?DbsKŵl[yoz[rI3Agw|hSK_.=3t/֠H#ra*am3ޤq|D9z]jg|7\14Y٣[yR#0$rɤsdTe:~h!`2pR݋p=BFYϯ_~Ձ[n.Iך8o+n_U wJ-- m\Pu]$#DH!Ec\ ڲ,w7kJ"R lwJ*h4A1%*1&ÊlE4G.€24Ag!T*W3\yjZ53XNvB&jKT%_4Būӿ~/FmQwޟ~[T`u9F= xg۬/Vv1toŠW.ڴt[;cAy˕f]%IB#d'ٝ8%% MߢM֊q1R7KM<4J`@8PιZJYB0εH($-KrГYb8NFϏa 3 ?ͯA>_ 0+Xĥ֌aZ%F)T-6dP./"P};IFe(!2,׍YɳGS%ƹ9l>`LE41Pl摂Αss iP+cò828i\(TN˘CFU-8ΰ1R@pm Dg^^٭fɳ e^(6yܸ1ӍK3XPpkǤjL/B=ŝ}nr^ӴR{'oiF9qF̌Wإ߿͔>$T [;%)-ZP赺"F(z6p+<R?]) NG/8rz߇^g«xx'֎F |ekL̻mA-#ᚿ;f%^jF&F/[>{#;$|EAƜG_7}g?}鵆q)%,)eYYRJ1FMU MBR L0Fe Fh ZLkM\EqokF`͖C,KȸwVssL B )(j Xзo{6]rkȋ@^I;Z~\-j3\.[{zy'A gDJ!"MJk@ [ނ>=J;~crI"^ŖW %Mݳs ۦljk-.{#ecʩ F@Hf@PԱ0 zGZK<\vKCmFu+f[*AuswNBw}vlJ&6  %"_kNGDIذI**[(M2-\[UC$ T\Z*x<ϪƊ>HA ,h0[,MNqho+~N؞ou{oƱ?;4 ℐ,I!#fiQ~g6S2gc6B()%B &S KYV 8VS{60Kc}K{g?{c?yi7S'6y S4F[{+0cV&bdoC]HQ_3'JH,秗{w ?TJZ2dkNYE`-33O˜ El# `Y [  lnY&&$!K n3^#¬3GFlS+ [dХZnkXl\J _$AJD(JfE=oxhUgELʄ2"f1>H{*.фY5KWhX0OL"aʅzvl[LYߒb'ڽ/3'_6}+.9[(sOwEak[޲Xo_s.o ,jf9F)0N@K- JHcRys$Sܘ`RkfPXs9=s@)fk_,?|~팖K,tnBw"i 1w1u\A1R#gZE8HאKU{k;0`iί8>.yW'ޅTA@@Gr((ӴP%bR1n,GW5Hݹ6gL g.՟oF; "Oeå@zI|/ydgVkqQ 'k(j|:ſ `Iw/ZkIpOK'S q]D&n#T2눑&!6;==kkAɪCÜ0Lң#B҄YV׺M63Z.t.g|H*UN9Yv=صqC=_ ̷ w;\|HֽWLׁR 4,P&"fSJЛF[-KIQAiE UR*%Mg!R1Nq='V]YVn7y^nZseȲjȸr 3'уw=o Pq<)sJBf),A(6R6~J9qGQâOtDϴpg5Fw]t}kAxR,uG\?~RXVXlۣJe1z8kF9]cSV8~K?ǐC m_.~ܤ kK[C?ӅH: P iۜ#¹v.wp{v=udWl;~D8XϷbV!n ,Bu. nw]󑪥ܵ]AenŁ IDAT:jdWl9wգ+K B-4IrIQԏa۩TsstcjY3H,-Z2ڡ!gc* ZvW]&{2sn7r3cbg48Nujv"дd.͆MDAW# ijöEӇ>wwiĤo8׾o?{OOTQj0Հ Z!<02< CV>_B`mOB$ ˣfJ/.6$#־;R Ę'` i.!͒D޾:Ve!I,]Ls84z57ВfoaЗb2uM )OE]C  FPd[VuՆ֓^;S0PϻZ3w]ke:Z e6PF媇7>:g+SlyȢ8z70_8?h9~w%>?l Q ,@jCZzpN5 J! N6\$D(wձ:Tڵ^yPx=09OJ1Ji,h+Aq[jL5GJucP0Qkʓ[í<{ͨὦ ֳW =?1KM<-pWf:RHߕK]ӯz;ZBЃOx?+Vz]~mѩiwMsO|_M3ˁI%%9wH` {Zu4}B[]/-wX7bMllT*e(,ey.lNVN M)TɫH)R* "8˲< x?AUa&.p껺a=?xý}5uf.ꙔqY|Co{ɗ^{ōh-xw=s`ڳO5N`,raRbh}bmj_?]>1%c8UZBɋ?skYEyIyda\ RD\rvڅJ!`FnY( Ȉ~3s3`/O]_|/vN,3=K`G4 r`lu]721 ֜s!͸YQJYc8;!( hC:O3coy~~eT&sa] mQbS ax#,Z繄c i\Kun! (S/;g-h,} q52M*Ch x&lpI!Y!*?wWQolw|;^{v ])@XeDXZM2HNaґlyvrv Rfjъx};Ƚ j 7Vi5^EGKx/Kf fVfy) uG:4MOVʩSr1c)aqn2`k,C fw=/_<1  R"emgaq\UkKxn̈́녃H:4PL@2'b9]>0ڪ39Tar6.'/zscdadG`41S(l$@R[nubٗۃa$Mz%MoT;oIݛ[Ó'&xe#c,v D؏2F)e)q_֬!x??9K R _τ;ZGjd:p>VU`GR?qcF k1C5( ĥ{J8k:apuAY_[޺+k$.+K6ťMa}yPY x RkxgRa3믟YZV $eLѭ[_u$oƂ/3TMMi  y_('͒4K]׍XH63^dq)-Z| .u_Mtm.\{v^1S3UR'&dJkV<]령-@ p\`~8_5{#*={JlFʰRXmϡp+}HD5&)0KȨQ1!~-|| 7wEMŇQ]RU%NT":Y9{_?8r嗾^Pϧ'V0B,(_-A2 C(eicaRJ +D6c1iYJ[2@YLݏ߃hoz/HOv>=qˑ) ='(-gXq9ccg)cI$s%@[s`20{!u8s\ 9Uz.o`4*vN°1Qϊ lk&I^4H2=0rʐ\d ДFsWp[/l+N#̢F+`ͫ4C&ia'.nQl2D:s沬獝4X_ *aE#dIij^I}ٳaK@~WU.}{ H7 {"?|o}oKܬ~zܙ;.뭿qKc@(|F@6H[.,in(ݝ?.tƋ9ls<'JI'(6/J+ki(d(͵ a;q̗/.ĄcFV~Z@6 ijk_h4%zde@,o\}M=œ;3! nRʂҔR8ɴBH)ҫ쵵ѩe/KKnڟ_PM/xJkd/^x_^Ola, BKmELgsc7\ۣ)` 3dz\#FeyZKEcdI\wt{?hU+lюZ!SD1I`T!B1h1bB;ם΢7q8BJc xdW_ߟm/O4Ex͆_d{,6dJIm-Hiyg)m1ȋ4O*5 KB*/-ܙַ^\*Zi5f:JsF(&ʰ51 L4,,QYdW [lrs|vK䞙$xc 0k! XJ8LK> ۽c{Uv$)\z7/U +7G8Ǹ2;5sPFS@Õ!p n}-_hRdk~@5FsTi68+2 @061d !B5X+D&5yjb~}Д/]ݭVOtO6ŽSӫO}G?xqɗϟ;{N1ьG}i!o-}ۗ> 7,1ʳ<?[PGq{Y=d̘22H H];ߴ~1@]8~ P__-?;XU 7|1p,QJ0,$s? Ͼ_qtc7$\<5#uPJ)TQB*2p*Q$I0kP(0>GygcDj,s/-mlL4v?N?ϾrjO/-{8$׃0*3NW6i0 @ i2f< hFMŎP/O}J(SyitJ\iwn̻=>N7(ܯ^43R Z'YNk%[>Wp6XvX,S!DJ95Zcv˜$K1Hɋ&CCjy5W{ߌ<=y&orLj #=no\ys|~PũQH9H) <!亮v'J2Zk6RƔRDR!acR5S2L $YUeSjN8JWb<̧nϼa5_OQr2LP3.QA(lH)r @)㖣Hλ&<*sLgu=ԏ{+U>;5p,`BXTa VMۥRMj.績g6v^&L=1*؊R7F0Bw'eY[J\g^9~jΥjbYVFŅ DfkW0ug[h}KdzڠW! GL2#@A"+H g+92 A#b~0Z0B\4RobA+~1`$ $c-@#LqQI KJd$p~_(kUioܘ7^v5:ޛ~U<1-b2OB𓧟7=_x/QJO_G)VCq7?]䳟{*~kQ/W,$+S4"JhCz囯4M~U9܁A Bu*jyZnocB {Avz_&'* %FZ;k'ʡ:ᷚ_wh57OkWzӅ斿q{}ӝWOdÉf7Ix%4z΄el\s"2\+y^HQfr`0ݜA~-MI ~Qlpsjz; (/[EwQ˓%S*Ӆ+7rb:]akPmd>2ݘř-;e9r  j<ÄhR4M 1Z1Vr TUW;L>k&DT8_l?={{oq,5Zc H)6YqR1e[Hy25PZkc %R L1EC0$ Ĭ IDATRKÒ_ ʚg6SԹcOAD\}p'&YB%spQFeGaoM/*7KAwZ> uejJ%!#c "83BL 9˒hzvf{%\e0 ߿y[W?ӧ㍟ OӌݻGS*HY {ˍXIU2`*S/3/h<_>zOG_7>[,s.Y<l'6oEdLe M?6^iG*pt>=TBOxRYKh?E1sXU<խC7ń)^ykp `l4LjB&ikͣl|bK@*Rp(G QIQ92upvZ ժ׻FZOB={zTbF)H%ra4BHQ@ YER(HHI)ǜQ(j...bg?oc~+t¹#W\u鰗jmF$ںḣa,1B(eRNR)-e9BZ뺎5VkۉI!se. M__٧>} ߽҃'̤R9*HfyVsG\\<P bBQd4YRakr^+JBRj/ovۋ ;APR*am|kuhlw\ H*jӉaC65ڶSc:Q jH0RRiyjF֦iARFHk U$ 5HxS~N7(# ˒%X*<:;|(83.hAtYN\4V1 nGnͣE(s)e\{"Õuy PklIR"E;&X"%+EL]MTF.635әC&q[(夈ʁhaL6NbjvWp Ac;@]iʋD*iZ("0 &C|>rrFju{cM^{miяͶQ Ƕ8*4/o;vPɍut!Y߼e=0Ǟ8zE>nSazVkr(eָxdG< ?b;ŽspSu9%-gv57k&:F8r!(6zKmj2m-f1?5J^ߵei jC}Jm9Ea|/ Ixj(Y6jLV\Uo,_H.Al)%b Z j!U(Eul\͊Sӛ 4h{31~#w"잋kw$^ gI>Rh`rpIdi"$0D*۫0NIy4.pHrZUBN2rkre阹X &(!hyk7wk߼˯[;Hk3@wI a4XT³.Zo0vQas@J{J49w.f`̰@H;ByMryys7]pWV_DwyO|+2}. +wΉ5 |Zs<_)c"P>]bC1B@pEÕҌ1-1 lER0 #^G*u@z CAyP&,2ZY{fM1d2|lL#L/=sMp֯d|ib7QFlYXfn !ZPw=7\R.tDq5]l5NPJ28!%Ġ(l'*ܡbGl|SkW_8~ߑӝ#]?;Ú }Gg.wLWyz/3fԒs`&PFܚnIXGӡiIӕ% LJcde @y*kRJ qKFg:#1(Kb҅ޚZy$~mv".9gWcDK~43v%N)N|4~W :oq|𛮰a&Wn$Snhkie=/UÞ O]No hDX}IZu)P6%\RZĨhgޅ奺O=T\Ϋau u-vR+a/ 5V d N.9wGLkK81IʴEI}Uባ0>FJ1BH[`1FFƻ,+GRb3Mo׋ҁ߸~mOszM._vW]+{_ hduM:u'yOsNE*beA PAhqigVG{l[61v V)KiO~4?lOx~YϺǭA6䆛4qEa*ʴ6(e2ϦIuAxq%d".dsd%yE"%pW¦P7Q!&1b]i.6Q^??w7N햽[/<_JcQqy@GJAYqJ)J&1b,hM|sd|e(5}/ ~5ҮW&߽q#'O\xZ:5s9ːrJ,,}{5x,tsreN䯞0HΫJ)r(YjZ>9)mЪS/Hh';ojDRurD)+ea]O>,ՒꠟV {}7*/&gy_x)Nӏ|oѡkq {aEŗ_}(X9̜fɋ2*jr3v|\)9;_/f9*dt"0(mYK"](zwj/NTUi(9[q 1KR[A^@QIrPo7a\Z| yg0 G*sCAFZK2ZcB攕6##4+Er$f3{CR׷u}CMވ}J?k[x ?҅ e0֣ͽ;P|LsDI2 d>qBLdOK0zinL+ U(]q5t.|I%ҨC6+`)~|ҥkrUI)'j0xLtzlqƑӘP!\+< i\Ke*Jy~ҹ)v2CU}LBR ɊUzZ\nX;RVap$&!Sd!\ (JK&E{>G;s'N_}4#7Fg_=hG^'l>bd$- V~w?w/G.7r2GڔMV"f:m>oL+ZM&agr ^r(ި0<˺n=+sbY,ӕIj!vm A6Ueɓ3FhI+E Ì_[,qS`K@m<Qj=F*Ƙ)s2JƬ Yčo[SpeSn:}K^`l׷=t#JxfflruL\.LS6 ",_7}ɝ>~~JwZah>;0D]ze֓N/7n5H- D~[k[֢>=zyh-P: mugv镪y\cse^WY.6J.2 iw4P_]Űzq) sM9Ɔ䶘 ؝,.}\Ux!^@gfKqtIܗ,5_u˭YG[:ӻ?sr|p @5X&fH;rWYc=% ΀` ㍕6Ǒ.lM8bhֹV@N` Ï]dp4:4};U_vӉq΍Fo^xE P$d`i6Dk`$MH27+g.gxQN%{56 jEd 67g+U$9Bsٱx]gjx (K@k]Y9,PF*<+5kyFw%8H0ĀYVti{gom嗎w,,8cɹKC+JX{YpôHWNݛVyԧ__H yrv<0WljZoڳ_\awi=oE7IK g?kt4iн曱 (o.0iӷ{Wo9ڥXntjBBmu1%u$&_+MbZ婥4lEn,%$G~^w'{_wݲIE8(*$u/N4B BJJ#cR" M>Ao\;XG?>ǹ/$jOJɄnh^֔RA*por@ J!QG9pvio7&U ~{N^U_jׯൎ/4opwE %4=`!R&3JY{%-TL;z8|샷?a:8{r 9㢨Ҍ~_yC6r ?zFaL0FJB%":J:BdYv0 5X0Z@UUbFÕRXixt"w?cKfߡ'6n33u]nya7?xG_Ri4Ƴ^3$sں K'HF_IXjDLn[ ]ッ^ڸB}[H G /w"9MbQ;Rێ5hrJ̹H&we4G@%|+^s)Tazz7V){;NaCFWZJN (V幮w4+"hX1s+nG=wfi.|?>v/[z8 ".$0ŕc;T{ՠd Gic-` RoǣYӉQ,r\ؼ#sXcJbaD6VFaY=:M9`FwGF6lsAtZ W~3׾ziht2]bӝc֧^3W,qQ.#|V:3#h›Dmb\\x}M( 'ڋXM:ǚ=S͖-:w=pi|`˰Fһ)|cǏ=xs5ۊkWF4Iz!ݍ,9$4 I`C m zݠ𠗵6PA4BvU 18!\%d|p]IhnmXt]]% *F(F"iBK('i0MFR1G:,Ae󪔅TRA5ZU M Wq<߅}Ś3&L e/N=~B4NbFz]-iNnUlix ,E5FJk1`a0GnfW `F)fݨ~8o"b8߸=۟CL8G[@cEp)!¹Z[m~!1f(!ͷaoWI@S lЈ`H7o?<+6o~Fow޻Z\綜y9?b δ7`u./ThH,~09͕NɌ-,'Xd):ؿ]ZY&=?pK#ÖgMHmC{?>($q 0eLJ?=Ɯ:H&.xhx1L4[Sa&ẻJ=IgC*!3[D&,֘2c善lC)NT2W)ѣ$7>~}~Hp~o*+5B8L u+Ռ/,Ӣ幪]靺l2*x+%WJ^N\?m'gq);ZNڜH=wө3+oZV[SQk};zn_tj+6U r8aX[[H[f q5jF2Ƴ|b\bR9gWoO'xU7. 4v-C\)aEUXV (&JWS( @%|O8ɨ^rV1JqQESFRb|ޝO  zOO]." xXVڷwR*#i1$ВqѝcSu0ԀGLzH#ʸIaDW2ILKXmbW& $1UI-X(Mt|f(h RC׮Z`tpp3R-PͅX]̐{V:]RVmÝzڹ݇|s7&YQ<1:ZffEޯZuJ[7:E,tzmTn<ɜ( 1ɋ,)֘bҐʦHLBʥVԂ;~㫅Dx@*3@t<:FB_olw6kg7Ɨ.s21R4LتF{QKדJ7NN zͷ/3#:Yλ1!$xԈؠio4!4@9`1DdlfفaPP^:+S=M{=W#RHqƣm;(A0T^VqBPδ1J7c6APY9wcĺ|* ןV`'\Bx@X`yLJK(0D!'㎲dr0 `pήN;vˏ>x>4B(!J])c&lgژ4TJvC00ieO& K{[ơrf\=*frtXȼU&$  m .(S.8c'sxx8 c+:@a2-T&V  @0!xǔ1R R4F;̋K$Ux*o?:-VY`+K&'ח6%tEc0 <4 hwsaI'> /^#'M! pZf b's$,w疗/{!~! .O<>88!(j}" IDATr4ViA @Qy'm卓0'Fa=[m"u zA?1=Hvh)lږ3 ,̼iW#km@pFT]ۮ:,32+JF#칮49ǙþO?+`ך4N ĆYðaL!6# gO|oY[?Ĕ`aQe3K RWhq9y57$a7wK<1s: ,~д[@+Vjb"/Ke. |{&D0 2"4N=""O;4FRU4!h0B0Ƭ5%bd:Ck1u]FicRkmQU`)Ƹ @`* xGV.NgnaSьnX F\ѢJǓ!Tp($JdnLq@( CmvjڵиJ盝IgI2 l6&8tvK _ڇF̧K Qpz^oc.\KNݢZkvbo ؀]_pmqtdE4P/A!Ma/ٟX .BE5j B{{,' TyQ(+~ZlRCXO=^L m qY6_ (MVj39FZq\@B=BU37i)ˢPJjk(e2'ei03EUPu-kU5⎄8[[.=qf)}%x~#g~_~)񦏘Mak ў)MB\fqm9KVg>+h0ĵ4ܱSsz+]"8 qYײ4ShF1FVVRJi0r@+aMYjqK-(M!*ڧ8++T [`p& TAq%%%4C_q߮p~vj#BXkjRh뺄sLspŵQsd6O*K](i%4Gf7"JXܲ~MfHχMkxhP "Ŕ`LZ[YMS3beЮwO.IbRk=q4t=UqUb&󦽑,',gnQۭoSc p#toij;>P˥V'S =F)bbz0J.tu9.MN<~y[霿1\/uф:^ʌx2w1X F܎cM^pV|ƹF3rfiUbBcgJ {G5<1z]l-fEF$ cǣ.EGWpjʧt.-h 풗RieE.,-BJK1bB@8SKϋtaojg?OW!8vIh C16p`1`zpk,cs=k9bk?sFHq9,-"-LUDk}x+mJJJVU1z:Ue!fh02ia$PgCd٬jYrq`YhHDKY E-kŇZ>kև@^RJAc1EQbwDRaB틇*K) LYY K%lf 0 |22N,5ȷ iۼʕQyF6[s{vwx℻J3MAԻYj5˪(ƽrR|2.v&,+Ya D\6*Lj27Wf28\b w]PG,(NԍM~e *w.]jRM%&ˬx;'t=_65??WSۻJ0Xp&e&+K9 Hjiu Z9:3G9rTy8NEw]#`QN<l˜,ctoղZk$`YkZ+V+gyU@3'^s0p}"5~a~t6spv~yoO}NI8auC,kD.L:3l,|jM:X$[l 'b`2@ & 31@B`(0fh Ǝ-l˖e먜:?^?ZsW+=5aUcgvlq2?\_~۷<_<,dgT{|Nۓg/Eh:1ynHtuӶ/A/s">{rPխ]oa6߾5pv|6}M棉  !:1@D 15ù1R@$Bk[syY,@687և_٬[trL]4vܴ%Shl=M0T̝yfw+EnG3H/{sO\]hS^G'6 (n?GA n^lmͻj{gj̋0#.+ZךHDOADsQRz D$3 iά|t KC^A:Fds; m Eɧg|ï2^9}hk_YǷ{ÏB.Ɨ5uukw'6r]si3*4 ;Gޮ{s[xWPR 11R )t mΒWL!)n ڭ7_W&VݴݟĭG6/?†=͔e0?‡W>I1FDb#)||eV~RmhPfHy7Ϫ`ՠsoͣaoqܜ9Af/im uN2ό$,6Ѵ)#gLsgѹt$SN$`eHZg]Ayj15vkj1İݟ}\QhJR|[_]g:YYo{V϶աoαi()27G;< /o&C*)Oo>;O7OlLG6uLjmEs_]~k=Sw<?T3 ebR; pc&!"`)sɀH "i 50hXz3剛-Qfε'&V:'ܬ\3iZG)`Z*78ܾK[Z l!`=dngU*{7g"#HݵMAMac{Ǯ~yYCL `ihq e@f}%e|ޫd_5߹wzw{]|'NEFG0K74T ֟ݹ3A0eY'%:ۦu B컮*8Uw˪b>q'=殨<7f{츭b3[npo?ʏ&Fm? :x럙 !*,u.O"XEi}+x]~SƋޥrsE&B[j I+rcnM/:F' b] )7BL./ZsIm5G#⬑zuNZ7GJ#,n?gl$y'"XΈK W2K1R2A2!D53hܯ_߾־u33M}G#i`mf`һybr4z$ܢ"Y뭦A1\2q;ϫ<5 /_|a~ы7/^SlmEuO0~_߽6x5@CJ$$\+BP]WdE+ZsO'~/큶=p|˶G ~VVmtuP7}Osa~2ϫdV N܅۟xuY'_xiꓫ+w?Ǐ |~:~0=H+xLaИ׫U>Į&c@Xi]dLSZzH<Lh6a6p}ևwk™{bu7 xAutR)a$!)loܪ-}mtuj;+UUx'Թw5 G[,[o. |mbܾ`!b67gN[m[nYt~>5JGV6c~tyG#WW6gz~3*r8FJ&M7[qms5({xڗj=#ѓB` ;!6*Ql3Y޶$39ltk`{{3g+׿ P{³oCgo[*oR O'B¾\OݽhRG#[~}A E)sq6кDͼbR%!9sxxvxf+*bVr6 $[w fʲz*ՙ'>cOɕ[wJR %bUUhd!v'̞^L2ǽIoʵk)^;~(VvSPhvTغP'iDze<$zG?9"hmOˁ)2yQckyHAYZ 3"@z |hx/!>@*;/e MfJh[v`sOlqo 8`5<;۾۟62]hT}Id'nͷN棙90noF~.[aOq)Nh {d0{$RI B0 Cw# +k;ٝ_ 5! mٜ=]|w<=C(BJ:QK())EcL۶,8-LTCc߸?~vu?^` x9۰|Pg >*Ԯkf7Wpz|D2㧡?_#]oTF)c $q pPRsɘM"`AfdS +f+!Е1ըZ{ ?;s/~M~Rw#}f;?ϋX̧Tf 40hAk*ޘs= IDAT3U,aQ J*LgFBJi%%3zDN Xu6AXJ.zEgW=ѭCv ī/> $_X5SQL*beYJ:!OYlַq󾣯/eX2A,YBDm: eWk{7v3d-;m~fHz YB܈YJtq> Ӱtٵ 4dmEy)Gd\#B'c@,u7m:-qag= ʓC.c2L'ʐbX|<G~!bhp[T|Bs-0s.ezw]^olS̔HBQ,F& ڦ բς?/{5uSeL(R1&H(.J N 0)1E \ I. SIn ~'6[ktOVyn:2_xw]x?o*?yx0CPCȯSu' v{?x5b*3$gZ(ABJJ1::B)% y FmleʏȬ>lzkfSN[|\t:WF lמ~5nSzޭ c8ĂdLwK0Ɣ|!RbYIv-@\j 31L"(eadIh^ɳ>@@^PL@𐢤szX,6"Lft_,^3iG\)z/Pn>,JV%+UY2"smJqy R(mYLiRL$YN⋗Owwɪ[|K;c=\;.goƇ?|gvK'8E@!Udew~tf(RQd3EZ<ΔJT*}R`I)&)-}r @ JJB;N"&)ar[͏ֿ[@wAjwPSH!H Tv8R<&c8Q7(W\Gd& Q|ifʌLɻ.S,bsz57_}g<ĝgVٴG >LSgm Anᦳ霔F5j 5$n#X cPҹ`[+Xe@M/:Tޟ报Jk!uFxw`Ddyw]DY YZS9/nhyb.]} @ltl~?~\DZϝZcrNjh7+0B:[]Eۀ@l1s""Cpwg2ȏ?7<6<_|t7O]Q[辄y)Zk"IwR AbqM0|L!b1;<Mo|dn,xRд1@tPiz@z2<PzL!d7>N/#'])*,Rs)AjEb\13:떷""P )C)(YHQHf,CRB:!哋벼&7ns` f)"\%bkc1`o"TN {w҅~R p :)B ,!re·z #Rvu/}&!xTHuFӪkʕ^x^5ϭ3ʖ4{K_g_Gy[/YuEY5GU1[{^G0s4L )WJ0HDDޥyo9p$bD&Z КReI$D 5ྣo|||B7%P$EP*2B)bk RJv"DB&4R Q"*Dkܵ.'p}P|b;VAI*e,{6)6)I<6R%YW޵%1F8Ug԰]I(5Y6mc !XD,2!藝RrLRCIHٶ-b"; ՓCO_||8={vP]ÙUVm4Ӗ)g&wn8(WFcت_ ܪFJY yFlmh0L}^@Mi0;33Pz©zLUni{)e{U$ B*M:etk}IeYH{f> xČd\v^?{A_.)_XI9VRsD,tWRgO\`Sg,R2AbddȴB RJٖSJصB"H,SL|"I>4!F^1B $1EBLR+o0m0##3wcJѻcTqdMWOs.Ꭱ ,JHLH+ Ji)lQLk<LVV|{gm RZf D%{e_ +o[_cnZ]wAwQ]% z鶬Qqԍscg6QxJ #JR%$Mm )),캮}J!yL@`D=ђZKr t! $ Fr m(3>q08q:M $!DrMi(Nw${|'wsR!ﭒJKc8&)y|!aw(Xy}W4 "!\V+=t[wusFny'BDpy5{n_8]2=M3)!Ĕ.%p.նU}V:姺Q ,ٝE[y`^! '_цZ2k&)P*!SbLFWc n)Y]]B0Yah%!\IX5]]_W?`#xڀ-47ZkkuT|Z|Sڮc5B >xBBܞ>zz[ve|tP~SqL7? ! \FSq /dCXRR .FRRY)rƴ2(|ls6\9l:il<ɴEqf238~y,KVVVERZEϊLj!Fh:kҷ'>y ]]߱UjMf=t\U%St9M\.C,* Fc",!1C A^7ɲ8oNs<맺R raW>zssWUfNĔFL1"3JRb̌xg$6uR"K1"E2)DH)RLL$$K®ոW\!e % ;ECP\)B3NR,dY%" 2sL09&@<2{Rbp\2)Q&χ+EUR^ FdR@ &Q n5r# vCG,>}"Gc ^| wdځ^AO\JŜMePQ0FZHA\`R"Q b1CXR $B&@]b,: rkcJYX#uއ`I{U&R)r)6& zzgy+-$y (hw,@b:8"yHLG Bd&%h`JH~ix};gw03}%Sʜ˒խٗ?WNfUEfecm%lڝ]}C$Fr>A g4b{P=>cnF4:oPدA)U&SJ!0&!zPiSd!D1e/!EL1DH3-J*{XY~Y%`ZީjUT(TY뼫E^f]ޜN&~[b"$$ )ޝ ͪ^:s K? ^VT3~Y$d%$$H>8C6,1bdE $D]T Q NEWOu5@7ENѯ؀[O 'Ru˴}W7c7F5L9,%O>SM.JmuOHҺHz.$8D)UI"w.Kϳ8̹{+}pwvlزc'7"AH")D"R@"E ɑrŽ0c;v^k9\̿}n\ko|>o2Fcmd11Rr+xxT=piVB̜F70vXP=- όӔs"I h)g"֍rf$]#rkMGo8'mN%N7Gwq0΁N `j1C5V+o?_RW|>8>Ǜ/ݗ_~]{WS4Q>$NӡY2R&5\R*@n}QKa'&йD!#Y {cm@iCj\A'mK y84F"Ʃ┑C#J,LsYJ%yl= Do <@(%`-|ы_뫛'`_W?O6~CE{'?^##?Fm_K,+yv{#Zgk$ H}կУS{vk|⳯̋?ykʣK_d~kPB0;D$f "DKi{wj"d P?NyT|>xzusݯ2|q|z$«921f$@S=^pu4m;3G(o7Fh/>7ӟk\sa$H )LsʈzPsi4uLDI$"RWO:0}u RԶNa]R"&qϾ^۟^Wg^ܛ9 "%TGLӔXw-~\Dնm4K(Դm%`fPurjm :L_B˳1p`h IDAT$Tk˒4Mnm H=lfaȈC8Hji$N6& iuBۺv{w,>zhjIN%vۜ@|5So|^{rW>onB2CN+$""&LL\%Ax-ݽ|5Z*HhemdA r KMsx&]R1%fԇ}c},߽G~[ ])rYSDrΡA;G̶\XOǘx}"kpO2?|?Tr#oׯ?}^>ԛ#t|α 2@^$i13]Qf۶Ѿ?ރ@۶!nlb0Pw"0ewo}Wr jctG讇,NOs2 DIu@eYZֱ\P+p;ϒ=7^]ß9|_o}~8UfHŶmukei[G`)/"nSN7;)c97U'T`]/!0Kjco?jJ \~|zo?Qn~82UddB.!")'D31rNo/'!-OAD#](m*)=j>dbH@:2OY!ZP2y.'|w7rA$fC\[0ˆ[o XRj=P KuDѝœ>])ѡ Nl$?E ͗_/7_|5"v}<)q&Lm4"w3C wO)!n]"jLBd="`3!'ٕ2s w@"aJHvz@H)ޱLnZ%t_)BQG;J GWS`@ĎF23dR0 A<չa ӛt\BG8ε ]Go_|} xsRn}}l tHą"th\tq<HB)_K7e߅ nӌ!aj:m[]VUU Z 9܄eajBt35pRݓu'\C'k?k|5Dack:$8jB$- x{c۶um&ڙ%KчE9,fpHr߫QU )MO/~A~G{>)9)Ԑ1 INTh7=wJ!XdYq>j=M'՟ 5֏|£O @-UdSQD+51tlm)%F wSaf#""[f>(6MG4>YsC75e45ȩ0aD!\% ӮH@.ff!4UacRs-Y D"|!Defc @L%$ T)Dao)y-Iul6 둿>wtڿx_yYt;:<< wY 35#KJ,61࣯\ݛU*щ/WAHDcJ}|<ȶǣs?H߿T1:£s @ytZk#_UDG 1D z<_}X_ɫGy/p$f6tW9O2~S>Yo%r>q5ϮBJ!a*z? շ~{MƠ2c'2\b1^ M<|0 x12O휳X89 +B\kCy7n~k]ON;S ސXz|ƥl%e0MSoFJӛXc$@0w[8fQdp?>G03J%Ăi`[R;d:h g Hg(`N)3c(;.]] (ŵkyP6.uԒ[Hε^.5zI@1q^.RTp6)ۚ5#X IcmL:/}?/_篅:O@osNl,7\@ m[9 G r!bĕZo<%D3C"Z{ɕe]{Ha3y,$I8\3Q$ # (9c\]m9DɎHFkp03\.*l݈ѣm\ 92Re J3-DkRQ')xqrO}&˻׿}x_> ?>A{Ÿ<'И":Xб5HUC'+ce].ۧ^H->哛sӟO>zG?̿Xu!aV0jaT3 uuw7˥*09KDTwzADyXhG@w )&!ދ2i +#&\4%xqH;ˋ~~yttk.z̯ݤ>C Sw+saB](MB"9%|˼-DHd^Ηx8ϋ!EXsM˲[+]^\uodG/7,R)D%% (\O3ZGif>F3rFS(ejM ]-17}amYe<̧ZTSP+V<DH{0M9 \CTpb "g9ބy8SJS74} Hp9B5kݰO$;Zjd)a:9Lɵ#DL%5#!9 ?|Ɵ~oyI!NZdf70} OӬjHt;0>f N%CED݉Q#S><@˶MrY BB݆MNDHIC98J%4.[ nΠAzj>y{dYLYrMej}ur0Cadw(؟?Nǯ~)hS[;2a&Dfj8l\Ͼ'q[r0vxdɒ@_7cc|~'$#< q]^UGuE31s)w&ҽvùi.L[ n@6˽RH3ۖ'e$[?x/ӏ?p_R_}t}}<ÿ?mt$ at\h[9I!6uj$a9jn`@``\_=y=6RՃz۞&Pѳ wC}xbsa9g"ҡHc t!Op ,f<epSOE%oj.#{x8"aƋ! YP-1'Ąnqzkȕ7 0pT#5!ܗ1 [G)i 5"旑PSVT@jюSЉRJ,%H0" "Dn>IwacTBGk+[c1L] c ctp(zlX jmjGqo[br*9!&$(c4]#h]-x:Y "vzNIB Pu+y}M7k]P4|ygqy3K? Ӏe2 qGM2Os۶KO4,t:gɷ}P#l֚%$lY_s.Nj cw2M>}dw`2f}Xu/}~DTD2OJ%'ׁ=#JR"@MU&h`$7=Sre7YFoFLym)a{$ts:Ւ \2B)!)141D\J,sL(\8w}@r 32j$=,޻n7Cwćhm+J[̒4mpJ,9s#}I͜rN`w3yG@NMݝXy7@`k6lG:EızGBSm.9%& /%0SgA@K޶)g(B~̭dLS撈َ'JTrɒHuUuaYI/0s$"@_\h}CʔY-Ya2qډpH.2KW'$s-r' Rbb`#" `zGl;;i6siFttwc% TP)cСMf@~|'h*=ec* )z^uso8ȡmg'o}p$H_o<)Ex#pxp֛/ <[SFz2qh,Bs`ppmNY͝ԞtVM25fmu[ ц*`R"cվލb(@ģo-䐙O2c.DW!C\'@DRǒ{8$TH\6x(t7u]#%ɜM#n mtG9#d$J H4]p !̒La4^%-(:[5kc[u۶;R(T).ˆ0"sUE)(%.pvgwhm.rifzǒ)#Fcqux6See 2.RJ\|<|}2oŝv92r(2ߋ!%Y.5 L /ziZ:#"Xkը8AL w@/%U#l>眭wJ)ֶrH/Rx .BpyDǛ{I2o۳;ј<%d \o\J))to}O{W?[Wo 1?5ʟ}[^?|w(XJS-Ӕ Φfn/;^s_3ewrjaF%\ ǃֆ".nkߜcg9:\\w H3qY@h}pJ>ܾa:.gDG۶%K2UsZ'ffaB-"Ԍ+"1ꡇ:8xFD>0咸0'a,r>/D`cc{w8}k7Q :zڶ3E@xD@ݓY' A6E arDam$5bYZo[kx!e82?sfܗeOjM`*IkzӋ7ҿ-j=*Y@`(6B!þٶ^j-3&|ޭKru8!r1oke>\mI @ʄ5#"FwRm7G";R^yr'hc*|[{k_9kJY bewT7'N+c4~wN7Gu'>{^7iM0< soad& i) G~qXbw LD]ڷrז͑p8y6WCjmh:s\u>lDlH/B a*`B!gp$ $Hv5p\ז"2P&J n:<:k\Z?/+8  @oHؑZB#h6A4̗mK h* ;0Q:_6<="RhSBMSn%Mm5[bbp덓 @`$D!| Ú2 hmDYHb"2 9焉vL%%݈Pӝi6TM0gqnjãFD˺H.܇ŮxS#5u3]-P"0PT{y fBa14uytӦʒ65P89H. }X#b'I)ۆuSfJ"ND[B:ϵYۃϟ,{?ַٌh탏YmJ\,ȶ]uݞ|t&y.X[o2T2?{}3 \Ew6qJ)I*9^59H.%%798l[ۓ9ADh/5RJnpzѽ7Xэ.x^}ӧz<{WEG9hM@BZh+q%>?}vϿOB? ?,"nu#^eO=w4=CQTT'L@{$nYMug&]$puzĴ֭P쉗@K$";a0H޶>})Oưp˥z̆Rϗbr^9 W:D̬%@4 D^Ja$cƺm؆,T7$PE6&L'v8ź,k[# қ IDAT_/p,2zýN%%p7Dd:&L:4qΒ#lgl ,/kbBFm]wÈ%JIon뺖Z 0@h}S37ƃ9ܰȵ\5g2Z_{7@!Y^Z(z_-s-s 0@0T23GR܌M}zѺ]4fc nݡѭu"ct%aZr{s[`^F韁'b DpxVkeDk .}~tcFNUzm; ԆᲝG 8i;\G|,`[ v~~m|[!ێ@a6Fh!9IRi*z $ Oֶ1̓CL BХm*%=pC8\IZY0hCs߼{߱4mj# Amxl(-CZ674[ֵLu6&FsF qCLC9@FA{,M,7m/ֵk`w pzHyDP> asITL3sTًŷ)ʦW7'~Aaa]sI)RfcxP++-+v aD|#t3_.ć[>|}K(lwA0  s "INs{Wb%Q*i'BL93|!ٗe9#G޶mm77ף x\ }攀 P=J=|L+|zkX?NjN"Z$ F/w>m B ie\2"їuU&~H0 AfɉQp_nϟ?UC m ]sd$)%Tk}?"=ĴӼYYJɥ0'VfN9JcG,@WnT5)CPU[oM7.)90L,˺˶rTj E D~90Z+16 ljnmD{Ro#ܷ-lZVA4s"j!2Ad{Ωk RJ}"{9ߋק{tZsPP6: Lc1:T. em=,KUVí'BدOҬQo7ٷSݯzywo?gr<ͷ}mT"Έ֚vLdPbny<2RlV9"ާ3@ʴ)Vxgp~",pH*wOʺ` r>r-R'?wzlן_/l9Vgn2TBPzl 3$*E2 <6a˲YkOe!#W qU(R1@pt8ŋO>/?eL#`X jntnj)RuD"K9x>m:zt3 HYV"01z7$ dLaVD&Za 3$W/Ꚁ 1؏&E)=GXծG}?9ufV[k\ ZcR 2P0dfӰ"DB)rmĀE"<8-JVEnϛ@bX"S ʺX{ۿu{|w/ ?/?/<nw7|PfG۬|^q>)qi; g fD$163,E4 Wk ,߅)Tq-0`WZR0 K>#k) 祮u?GE=޾?sL \nyRW *BYD2\ួX04ِf-[V:nJ<B'~?x} >ׁۓ%tp-4 (a~w_mxbO^?)΃Ud?[U oi$zokұ w$βɰrluY 0)Dcv5\529I\(h):0}A1&}-"#MuՑH zݏko%.&q&f3rW/][@qCXV^RER$E"x{GHz6F:fMsua؅i8g,3ݡj&|%c%uJ"`D/>3WfYdI@!$*H'O6.$œ>AB:&^Ѓ,W\,cpMRms􆘂IPWpA3KB("u7gZ 1F`o/0~<(#+!%fJ(>:3eqJꦌMG7U ONn1z##$<-yudH%e+5U]HHP3wXw L> :L{ypu1Zk]S{t˽/k?D0h_;>{7E#Uux!?g{R&`-Y>zNDz +AH3+gcH}^@U=7I{+O }"|rc5 Ջ?䇟qo_) o/?w/NS*9×u!eBHBz89 ah Ԉ4u] 8m;SzHPSxDv$3'"3g(R=_].Lh`1Ѹ T.R`hKIJ|Z(sXst@bv6:̗ӫYwBJHBڶbHD1 ,S <ہY83} uYkE-b(QуPr#Hu}DZzÀkKɇ-eQaQJzfdRH5G RZ3xYq"5Go@2Ti;yĉf弽=H@6̘|TT0JunP\*M[fz9""TuJ($;"&Ѿ@52U"=CUs-̒Ts UM6u[B]%T+;EPݸ. "R#z) Հ nއ^wj) fvsZY(Yx0s$\=xYjccf&5@Lu]E6TĆ0Yu;x}{'?v%婴Оɲv5.r9!Ov; n%OKLaDA" aU=NH"DDD2;vuYqW a:ysԟ||>?->G}m4{W~{p{/쵿?e{r,UdJL$iL_n,a`VDt@fvxuCb0"l&FRTHf{z'f%"եZBF,֧O=2HC( 9ӳkPnC"ZgQ { v5eXX͇ͲE Ͷ8Dؠ 8m29!=L#tZKdDkBV GF̄(bVL%3#%" 1 U3R `!Rc`YưRJGpm}rPFa^˺F=J9ƈ`DDVb`nIH<:F&8nHgԟ~ʏ>xr{®phNrcFȓ7Up;ݹ˪TO+)ezBx1Jdew6n?[nIg]<Td†۞{g?>Ow[YVg7sϖso}o~_?<8?y}v{Bw5f0%̲]LC&µGZ,0! C),&dX3MFo,ĜqN'$@"$Af$6,\< ˺ ѲiKӶ- c0qo cj& >TBo/_]*q]S>=w C!mZ a9jèV `i:t90އYx]6N$fHa[cW$L>m˵?Dq4[1Z##5=2dup"vm*a]UTȨE:9FfB %0{u,#ˇ:AF.KE2Ͷ0 BGN:}=Û5>;_{'^o<7ow^8ⵖm9OEaZFBR%2p!W*Fp\Nm㼭ՎvLK:-L- ֥ g>Z"fv1KSCH,3k!RXݓTKFM@Z(Q#<6[mJn֢6a^GoB@݁B݆qa}\ vGzuv'k]R62 ,$R+BСQUCV"`d4S ۂBRPԈBeY,I=12A{w5Z߮)3\ ׺m,nDQYoIctD (R-ʋ0sZ<)1c ѵaaȓH1kIz,"PKZe「P6y*KcvaLG>FD P 3IJUV`.CÍ"q" vCDU|rÈĭnAP1"hc> DG' XEƺ.c D|*_:>{Gñx_y/.O姾q77NoI]N_ 0>r;o EL)f7 隖>F̎z(3"nL.-J/8bo6RnH.kO-7>Oϝ3BpP 7B@x\2"A*R!#CV${3RDy0##f "N@s-NHH"a?2Ij)ADD\YF6Pt^E-TG܇z3b-"`]$ʄ4 bCEњH9g*5F j? ]}f"pDT I4z[}ңEj]Q :gy`kdZeل8#9#A͌-ڎGiiﻫH* 3u[(,jঅ"jz{ σ洞Mc]OEbR'߿&3=k9{pܓxd$x康#2 ͣчVD}?ۄ|݁ " 2' ŤLrC  Ճ+";DfGkZu0 Qu{OZ̵Ejd2N dRQU3hU "-ápH $鄢T`Zi0sk: $<GJuE͇Zs4"H@ ifc',*"7&fD>|h'L"afq4dtsӡH\#"(r*Fd3_ Ww8c|*#zo}<΄ 5Is@pц!r SMjfϊ:7…p7U ԛUOݝLv5Rk] 6L-q<dΫqOY?oTjKkngmkނg/uͧw˯~ư˽[}u[<>KC@,e1}\O֖e 7HDLH[i$f `J̮c wUh׫닗WzmZRʶDUd)R֘h!LQHCD{l90qZkka }tS$ԢכֿI"ҏc!ʹ $ .uEcoG8>Zm Gu3{uN^$ a31K|fLM{ߛkt#<̑{CmRIX5 ۾u?CJqs0uk3OD 23dD)FH\Je;3bDRf!bLpO㢭C&F's"3WCF`K۶1ص!A@a t=,q'֚mۦL<\a8(2<̼D,Ha^щnC$P$ϐ Czc]9z,5gfoc^1TuRRg涮,5"z` ac~pѽuoK)ec4$$ R˕XT2*x[dt{:,u3a}mt !<\3mEa訟pN붢,Ow}W?G~K.bER꺞x`{'[ ƺO"L,_"f.f>/%&/IsL.nP=w.oVFb7|h_pΛRu)nRD4/ʈEcB38 0xA:%zMûwfa,n 3"!h$"²,T @c՚BX;:SBa~$G4 R]R}@ ataZ+j"<~9dY[j'"{@ 1Cx7'ᳶfxA\׭wÈk?V'O AtuC"ڶ ,UB˱c9F>p H+(ŝnH&wR5́ˢ#j&u=Ͻփ5-۝G8۶"RmǸ*CyP;к8 EA蚥0EygA3U`ÒJ4<f5hshsd\-"Ui14D9}zUBhZkˌ"1[ eHKWDҞ"aA#1(_ܿX#2)*^ !Rqsm #\!A70fNc?.C۲&>Ez-Dh) r=,/ǵ,fB4%DDsU3HRogކY e`e"Q8# B0R [2v& >pӽ>{?wi_}O)ݓrXPϷCM_>B]DHC U0NҜ,gkstƓ qNˡWW,g_K_?s ngGu~/~;_{Rc]RF7DdfɤȜ4ݔ SVH )3TK-(![;YX""tXpC|VWsPeUk;]=51M#2ya![hi19z{8b1t뺬CYyо_5a5M٪ $jj0sGqPC>1Sd0?<\5 !BfCm͝y)ڣbRr(,bߏ|I6Ca$nJ8wwC )uhc Ab&-fI(D{H2/cX&IBDZ !kH$t K@ݺGnN#&8Tu[@`} a:"LDFX e Ld Bz* `/"=1)m߯Q㊜Ŕ! &cwu]vP >o `Y NoBR"t_C[[wKGn5diYHU'n vNq^FS5Mwd37 T,T(zSWHDf0 m 6.)2E&YyK끸P})ZHH)l9m[F0!R"J%tROL$dBݣ%`hdE$#8O n "=LSz@FLp9۩zO/zLĮi f jaH,K7GD(%qaQa`LrO $OgH4އG @nn}a>/ֆr2izIy:“PJu#A)K #32U@BD!6$lc9x RK]#Mz}߯,rX%z:r z@B:: B4ǘ @Vo?^'OJ xe-0GDߏZں-pP*0JDjeuY"|V3/L˲7$ x "&")D8`M/7OQ_}3O|c77VyW|[^D02 1&Ӿ.!"SB ,ssDݒg; c"sZh7R(^zp }76&cQD2+;BNyݦj#!F{,Ee5}RI{%ca T23ʀL`e;#-4i-f(@z姼~d-/{/?qkx(w{1U "˲pyЬUDȘ@u{Ėb;JD7.;a {s}i[B ` bT qq9AIl%p`lq![ݭwZϔnsk=C@gC SjY koS{S&?z7_Q\]|d9 Lnxb,`yΥ Tz[C0\ !nF*0fBSw6 TЛ91r᢫D02#cc6ͩEdž5Qs*bJ|DS2AAUs.n9\pX$S7 Іtmi4 5Y[7^@ضfv*@FDerOLC̃\"r͍0"YTu{ ʵp04a]WǭC dfLd<ՄʘZ 7Rw.~h!'S Hn[9<|kR"S&1qբL斷r^ VNц8Z"a0;N⥦db@h.GD*!'F51 9My A3eu; á,ĭPw jM4L1E(% X& A1@M܅9F<չf" A@O]&;30@ 9v-Ű4D3,!]zSiJL]CIdy9`s亠Xv5{^7OptPJn 5_ɬ&<ӛ'_pA3!@<{V%y[R0%LLT#P[sHs œT\rBFt[2ZHuڥ:uuCb 䚻HcsI }屍hT"bMu8iKyYzĆcژDAj61;y %JKRr :SYoL0$vD@D]k@0uwOLàC![C6"xY5Z+!ޞT'se BH~.k>?,b1Pu5"@{o)U]f".%Q Q1՝ yRՍr&J`BN]CDXrN˲P.}愌f2.wsJK뎠CD»١7,)Lxj!<團{̉s.nWrN)sNz;4nu*û(P6u5o]͡uk#60"#ql9s}5[nЛVDpm2NIDv󎙉LkNfNdp2З9}9| ؽO_vW/] "Dp@Ɗ2J1IՈ3ZS y1R$\%y %Pn (!b ݴVT[2#UᆘxF\P3 C36phMU={oct tW] +gl;$~{]n^'4tD* t\y$V1H+b*J`Zu1ДX^&cDu2cIDLSN@D}Axb L$"ݎχZw}`y"?9,i`Sܪ *8pǡ!p*& SFd  "sjDt}AmXq#,[@j.j@n:8@[j1$R` "WEiP!>nPJ5m&"Mr82=c; IDAT$:h:(4li%ۭ!7ZCNDiMrb STi%$9Ya" b!$ ȺzHp_ñuGbr -`&NyJn%!D䜙0BJ})'^@Lql~~{_y#ӫo>ޕ\/~_/sv(4eH9q {"#m5"'S%"3"¼Ub=d3#!1nկcw]jG[} y|2gFc"913d_M:3Y[{:"![zxDG/ [su_ׁ>N\X E>ַ std mjM$ۺ e"1ˉ!"nn<1  afFZ"21QW_nnCn4ZRud335Q  @0 jaD,EM6:03! Z Ǧ>2c#%W@ks%Z%7G@24w@Se$3K/m D|bBNỈ݂T5U`Ŗ̛ADp 8;z@`ñZ m;.b.MT"H*"aߟ`"m'm(SmmzsW=>(]}tW\Y-))X-i?%@ʔpݽu".`(.CLeP@o5R)Li% &)ԋX/ 'чccyf.*hWo>x1ܥ#& +  9H# g9ⶢv{FX8%FG'~`뿹jǫCjIޝJ) 1%3/e8U0oRJvc"%nĀfUK Dᱮ*"cXDe n]: r/hn>D8B`"DDٚX̗e\|A< QV^[<ys8Fn桶(C**?X-tx7 TopuQ .BՈS`ZP!8n[f r[0sI*:B#|lE@dD @ Q \ʲp X3Ւ|X8rN5g@fQnȘcZU 4TÌÝ!l#`*Dj:D6z8SR53K)oM KĬr<, |SOâ-kt9-(p2ֆ:>̜91c)EݏcL {@FʹD[+q} K FtWp76Ul5Q17 $E`[2P0Cap@-D@\2*69 l?"JEuG  5\Ӵ71R:+~W g42ؿzᖞ$WF榪 "$klMDƜzΣ1z$""ǥup汴Vj5ӒK*nL09!brʦ=^\l(̜(Jbno\n2 LR#Vr7 $TV)maE Hꪈ`˛bmľxV5!ѶnDump70ۮ1WPֆok 8 $ D݂dTj)SoCV2\2{4d91#}*\E 6DZ77/ aYAͷYv*2s!1c1TcH mRnnS&BibcĴ&cCl"R 2#x0:ƺ*YqCdۘ QIR Fffb[l&5g/emFe7ǀd4nXM)^뒈:$aݺ4al ֢PzczlqB x{iC `)YDkacdNCC{S `wHaFoVsp0% 7R5Q)d2*JTCahx2\]L{k]ւE{l!r~q浵jFMDod1it 0T({?z vNF=(,ߞ#m@C-=J.bLHd*C0VYv[c=J.Ʊ>t 2D!u<H]8 1݀oDYtGűsn ש 2TTV tv&2ձTMݹVIӄ 9aILhe"L)T2ŷV%5w+*қW$%:M2l>.ӽE؝?vo}zuauNeUWڻv&$3#f@4ՉTJ^{gBwy7c0y|:V SMSNcPtܞ~Se4*n)0"PDw L颵)2sόC!1(<1zHQqbpB9]amPrrHr 0P Ti]܇seLbH+DhiM#cVk9vjt0xcWm)d,S.}4 T21[Szs=VۺfVjqM3Gw]{S̍<0G ݻFXxYn.}$su<,GȻi5D>뮐rqm"fLmm#m bޚU|Bp&D-w9Rs99ىY%\^hfȪ)EhjchӍA)Fz> Lq>fwϥӡD4Q^Η<ɡ-l t`Do SJy*ɆMᄠ,c~FQ.[%r+EygDlCf<847 Qk]Rfo(_Zmch-d(}T&P D؆޼ȝIYl`8uh(6kJB=<8 !]L`kZjȈ@ r;"T\#,cyq]n0LXrɹu *k)iػt4 "1TDTQî# gA9LSV̤X E36Qn=4bkLci[Ż F?D_@Eiaj]H i՜Ty̭q{dQ#-0 3-  S> K`"`dbuVFթ: ГiGj#!JcS8=VK3r4AG]բ&ͤSVS*Z22)yozp]l=O&}Z_z?m5_ܚ" ،f, I?G nK0BBy7A1f7}pNSZV(2Zr+v<_?$i}_1@yOg-O .[ܷVo7;/SN@܃$LD1J"zb[C4}Қ眶VQ”S@5+%R\r^d$B caMCUqs]^<-\E7C?&ʭRF`XU5~j9~%7٫nLcDn pNg_$ 5d+MSZ>O?`_sFRNO&9#E27&ğ>S 1dH-.Lד//8;‹/~ཿӆͻ W)P?L  O)H ?~ kjrzsG^s׵kbaS2`F4O&R&#sB7n\|뷮ϻ?٫P LE]dEoZ2Cs'0\aĔJ5͠EeƚK"O}?}Ɏv|炀Xe:na%u O؛B:SZZU#T ])a F  T_t}F?zΧ]@2]~6Ryl$"-ݬ^9jHi. -PKA ܙ ͻ2ș\% ̙j7NOK3aA̪@&c&wZm _q~ nyWy{̓w_[}~ߟk&gx Ĝ_ݻǼ S|h>~\]*W~7o~}n}9L;@˜K ~|Y](W>Ї~= 8B 2ٔRITS/*~7}}W On\?XS`R;>ƥ3O۲.^go}{'??_T'jZK=.Kצ;_YF{ww_+$C[l%O]y0u#޾-<߼ OC~wZ͔)L "ҹ!9K:e=_oׇeKk.Ü3OP*%z ~ֻ7o}BRiw<}J"ݨt?|#זA.sW_}֦Zb^ChNN~3|3~ Mwwq4K5NW>v|SO~G|2zny''gܩFN+W|ey;~o7]ԧ>ᇯ?S>3RsՋq졇z_#SP/|s?7?ĥ< X3pg}FԵ{-4MuHPs[bf90[`s[>?_}O>O?߸xEG==̥;ξ?˪v?'[_+{ɏ<{^]%3{Ygio;;ۋV5BH4j)ƽ'c;67H8 &6MA d z{>SC}?y*Y&zҜIT.1;5+/sNHta`p|dҫܰ{Hw451ۢ aP(۲)6Ô !# rÐK!)\ c4Fh " F#fddҒZ@ VR 58j&FZ2Ik)'0BJTa F ", a0hb`@HN`IJVJ*J#PJ4CqD:k#m!׉Q& .0˲0!S4X(8\46uvw  %+V8Taib#g89auRYIGrwϿGptl{aUK-|~O_KkgLʢylw4T T*G=+ IDAT']bL%,h#>]UЖe)XپhC=dTL 2X_8}ۗ4Ujq+#_z¹ld[Y̗܆v׿vez]ԲRZGzlccwNG?ٹgmw]+n١h#T'ovp ĮGuRr%nG-L!B)m`hO2 2Z_˶]~{W_fWl?{ā#3P,ML$`Mc;LZ0Y_ܚ/j$&_?_y[Z;*FX%cI'-0妦im3̇ݲn-Pz6zb_l2[|KlHÖWwוBB)#ڴ4U~x|olr_B߻cWF:Uӧ %T(UXk[1BW;}5{.{C1'SO̽gDK(g :cJ5Voܰ?ҌD< |C(2@u>s'n!/_?vOer0qc'Μ"Ö,Z=Wzsӳ7,LWM:ZO<1/Y!c/^aN,ɺlҷl?7Y!4E0BukYtBHQK#A!" ⑔J2FWJXr E0HJ-)Wʘ [LTɌ3]$jy#QK7lx/;|,L'e*cwz\a(|OҀrK`Ɇk6_sʊ:rѣI۝@iCT}~Oys3'3 WRn<Ń!Hα`/f <ڳO<=7.߰0Uz]Lϟ9&1XP˶0$FcFk`D$]s'8~G<>āÓSy]ugN"V:ϤElvTnn||5Fc'7~t{n޻7pŗovJ\yǻZ-]}eU^j:|洧ԂkϏM=Sg[}64\qoy+uv˲Y5f-|Ek yѽ/0ζn\Ǧf˲j垳|Vv<6<51_U2BE] ,j٥0vpl٪Wu8/ght"_ w?DP$!( D7E^  {uSʞZ-^_K{Z45u%mvc)(;h";-+bMfy-cdž˪ҽtXtWg9{@4;ӄq:8£gN !c0Am!dB8j`b0Xi򝂺@k۶1!ZT4BfقZCD+i!B F[K&%|` F5҈`%%LiZd\ ھv(ـ(IfATvG-@@aQ֊ AiP3]B AL#.#m` PR2 C52HH 1kVױhᅷڥw_ML&Lcg8t\61j:fd!_?SNKoT{џ7zOe'f"ib|k-Ϟ{l|۷. ̯W O3^%yC|u8;B^81#gN 6_޿ݵ2}o="=G`bӲ%Cى뉬<†RS=*PO֥%\ژl*N%K%FcM L8uNҋow~kSGoz#B 8e.yپ3uG3"J㟸;Wھ O~{Xw  P7\y5 pl\q_f}/w6;O}7M,:Lҋ?5'&[Z{=y&T_U_9^jy۞ R+/Gt^>wG߲coS_v=?q_ܧ>+/W]j^- .qLG${yﻇ !)?'9=voԍu0;~lu֋ִ iYռS`~Z\ş}?< c'3gջPWOƪ7ݰ\ f8p?7 o| Z_Cرˮ (é#Gڵ N>uC2HCJfǂ.3gw,vv?ă%o#hv:?5[Ɔ c 1te Fspo?:MvL0Fu::ĉs'.7֛q(ܮ'˘s~zmlaVgsq߿C"›{΁SPD s 08͇ Ƈ>ϟ:{{xO_gS@e~}ۧK؄u׾cC]ۻ߽,>¡yl}GS3 i֖Ehe#٦ަɡaXܡFSDfB !TR+eHֵJ-#B)0kR2Ri ƍdh1Fm e;2rc)%ԐƱ0RزBږJ3FB)rcm#4&p 1RʘJȲ1QcB BęFKU"fSqu(r;Rą W}Wxlb;M[Dqu^}@Ѕ Ʒt[Nys1pJ#*:wo}T&.d^`(D%x|t(Oh^mZ<734}:}@>RtcIy p{wCqp̉~ύ;}kgBbfH܂i> VSm;Mݽs#VC_}7y.{Ǐ|o @i|vOO)>'(r/jU3Jfgg#SzNS e - [gOl]1(bM.]T.(wӠ31z^\E5 %BF@QL B.VTjj+!)ƘBJj4(%#cj5mu])&XJ!b$hF !TIQkF) E2`VNR1`B0@ y< !tpLFS ckRc2d3j B#R?OqEUqKUڮƵ4e~PK(*°be?pc|e޺lȞZ(1v륦4yUoz6^6@#=7__* %Q87ŠN@b8β- pzw͟+?zEs;[?K{=qR9[XX1A:j0oXT`X Y<@: ]۞[79\io?W>|PڲaH&cƱ3#tْ\riZT JǧxG|VoJ}Og]c{vw2[a{^K_w*} Qi]SR lB#D) H! ^5\{G빧j^d"+7tSkԑ +g_; cM̵1,fࡔiBȄLs|[0.,CBl EJfX+C!@l*D(J^6h_]}h<]}>5mc^^q^}6&  wP)D#Jk10<(EոW_q Wt.JEgg?{˫\ fႣ?ɯƜF >6T[O$T~+`r5<7z̔״RR~l;P˲,l JSfiô6&`ą!RIi!C%5׈Z"XZc@5J֚sJBFJ`\FFږU;"k"F*0EV&KE |fHEV !1F4 i\ו@l(%6FGRc) (v)cF"0!hǵ)md,SJlEi%)aCw_`yȵ13Q |{re,Å4J]Hh|k&Yzca6r\cK}rF7^z`,TF9Q_<&#c?}qg4>9%@ ӯxƋ~㡰{j$uҬo-WmGQ?;7gtj׷] YpʹŮb.P@0 آw+_962|ggf}ٶV[߶pqx?\kSI^|x텝'^;^+?xkJT2|73+2-ˆz|Ůes+,A FFo'Oko0+ 1A`cj7q@1!H"㱪?fU?GQD}}[j8z{a7M_ĺfE#׵21sS. cJ`ODY~E=+T%JCW<ؾ8cZ+BIPkNW[gKJCNϤ^~llL/lrcOƛ3?ӯ輮nijfvbvvh6;23ַ1,%PZ2*͎҄]z5Wtz`9a{]qC>BD,]hƳoΤʅ -x46r£g^:׭|P1$px ÊWG 1w@kэo:b7ug>맶[9% yօk]Dk.Y.p)˜F2Z`10ě܆`𩱦kGKa/[8ԩ 4%Bl;@a .(m,sqqBDA(e_-`4+bhe!c Ccjr!BYLKDH m<"I@wbkul qj1&0ƶm!cLR `("!}ge#۲y$he!%Wc\c@Bj0F(D8J'dTab"fET~ð>\cӘv%Q)nj*ܹ-Ӕib겥 ʭKv31^8=>d;kU'P͝kkZLj]V}՛zRFQ/]5rvPK4\V(gbp0 F׌Q`c)#,FB9oɖ[۶^ᗾnDj ߛ[q[mF O΍_Ǿ=|`96/v>;#셑+WΎLtw,3`nzT:YGu}Z#10[05Z@@ rztncbXJշMwYT3^.4+60x!.yAPӬw{ςZ0{H+?џ[;ݭuY\,xӏ%7cmESFaJBwG^N5څg4"c%@1=Z=h?o? pj|1FI @FӠ)?hIqSXg: ʆNM*Á,˶0rEtz IDATǚWM8;;40Jb6cb P*Hzsxٙgz=qɳ޴O~ꎧl0lZx} Z ʢ}j5UẀ2h:ƼR%ݜ>i}GqTP3?,'Ӭa V pιր 0uc1q01J2[JAQ0۩ấ1KB0!Lp9'ZYLr: 0Be$9@d on1V3ei)c!#5B5H$јT3 2$FkJQJ5 aF ;(a̶]%6JHpFTU)Lf+)TDAx`L>p ssޔ܄ƌJֆĨ$5#-0\mkM5ՇBMM3N+UL}<2sٙb}jI02xs{!'X 0F40RH d#u2-E7M9֖p9`,fldw&/c0P\RAsbqht'~o$ t ΕN<MmV]қ{7|gϵXN[a{>Sp칉~:Hٳ/}#gC@I OLx1ORF#Z; clYFXA0BШ4;;r҅m+uD ,x{]|esbu/ Z0I\L9oȈ(Q,#-8'9>HΕg"XlZҵpYe(`PJJHhhqssYȢbҷpA(嚘O'Eɉ^knݺ41(#"jL<ӱXTK]LZ.قM4CD "s%F96Tn%qQT`:~ _[* `1 \F6B، ضE1JKm}umSG|n z̽7]@虿l_/q=usCQ)'v_?3tkvvw?(r_Ο9ʡ֦Tg[q<ܲ±^tyR^Z:5TƀvMĢ_w2;J*BXXIەQ! DT @[ F(a5$jJ B/RB(J !!DM[gc" 0BF `v i1 #1H[%R5!5FcB6 !F RB@JJ,@i ׸2ZǪ3zRB:U*U*T✑-fTOFcR@KQUɉ|g-qR) Tmq0gsV}2u54D>h!U2hE1xQFŝXI!ձRcӲup\ko7/GgKrhLgD`| (ta$t㮖#$s)Qmp4ku{.YLH$TU>7774twE*pZ|Ǜn4 ;L Z+b^Of`,h'[ :\?YL%$8ܤY1aBuC&$ 2m삮^Kcn3Pҕ) {[~}͏}#~B\[3J LcJ*@ڱmFkF Xh[Mr6[J r*x'4R5\K0ͽr"miTyv.oYK\52WF ڶ,Am ]sf[ѻW/]NOPVFΤx/MOʟ^xՊ5dg^R|I[:ʥ\.(cM;0,\\)Vs]K:̓ZQJؘ1 %BJ dWz)iףe,3oQ#Ask۶=r:/޺·$WF J:2ԟn^冬/_BiWs8t~/S BR3Fq/biq mU]-I\5u97МJ-?77omnSOn#RPƩJ=Wn:D~TƘ\'g82Wlb C>B]nXT@ B2aRW Pa`:䟪THC.]y$ @ ȁ(:?2b/[]o6_/fu!=~<ǷJnrfLD00ؙeK'dt㰱NUs%Q:I1fQRJTmjm:‹xÆ'rCYD FDRqjaLֆ 5B ^iՂtO[868ǟ>_ 9}7^x #d-JG+m& 签xks[oCl? r7KgcuK"j,q.AB1UJ@DBPJ rc4F#ĕKTRBdaPjFȚ5J֔RIp!s`C1FBHR: u3+03KFA =, X}cEV lD}Orۮ}E;<-0]ѻEDii==(M EvHcH(!eRZөxR!4REٕJl\}dӧ''й!Z2FF0PP ZZ+ZRDHgsg}]͗-\|zbt5n*'O>NJysff$b譲uMޟ jg{I|o| y5ˬ` .%z[YuλWu~SIAe3h0fK8RA@B!mEx[sPkeZ2mYeOca* bR+)FxCRM=1 tl|SKjQ򤰅!ಾ>VF߈˗*d}#C^%J1h !Ɣ" FsnrA]mvC(0TF^.bXxq/pCT|Q # 1a,c"ɡ\ZP%_')<$QT) :=Zq %܇p0b1(`I{gzN h(Us̄\<)bu&rK>5?jEx/8Y:s8OV.-Ic`֝ҩg9:\9z6 EQSϸy oyåB'ZC=ϧZJ0v{ʸs¤ qE"J() YD$JY1<` DB FȚDkz 9ghHT0ƭ $$@@46ƨx\5YDrBʒ{4!K6H$9&[tW7d%0JlV3C{i"J96I!`ؑ}S=;X]謽|BC@bJU`k[n4d&=trCn1fsG_x`UZ`y_䝟W?o8S^~w^;s紩1'Q MX7,rOݰwzj{ڱSF'~c`XRQسd/]صs+WfT5F2VVLueRA]©S*guq9o{}%5[=;wݵM~-~z䯧w^kG Nѯ=7l5;vnû/-/tW/B@x9(Oܟ)SQ,*E@J֚\ŭkW~׽pnO<7|S/O?:+:dπuc&~B{{gVoaؒ XO1/k{r^[^:~7}S-ql x7zmuvbg*Զ g|r@<`g^^=Kw=ެW161s*ljtǮ[} xnhƿ;y|w/jdFSK{SB4tXf6%x5ŭhw`gӗ.z W;,PmjxPӓ]M֕)5*@=gCH#gC7M<œz.܁avG>:'c6P5fQRUɪY* 1 Xrb\59 sVh\{)ܦfTg2NE ɲm\Ldiul֘[l% U~u-KD!GEW0k6Jc(2=3&Dm=1sH%asNIYAkmc"BD@i9Ɯ BN9`mBVJycE%Z3_mT)yIFݔwo;ql5d<xk羸k? IDAT/GkzlLxҹ矿8Q+w޷o_=#G+X~K8 @)k־gnK ʹkb X,HIksGKkoaDZv[S 4i_:sx n>zf ^c*ɷpgW;N+.&;t~(`@.olo5 c0DNPFbڜ?7gf^6z߱:|g7oV5dQd& !Ő${֨(0ǘ4Y5Gd 9%DҜch[wx,TŜS{|nˆ ,{ΉCƚv:rYĴh ǘȢVP k fJ9f0Z M]gvm1~0!pNs!>4gP$f$cCʊid,;<VNv FbOH" r3SzQgܮ/ZnDj6 7kӋO=${={3克cP]}@߽v|n8_{5ys^yr_y_(^Xoמ};riV=?z-&,W.iث'uKۧ ZduN涰]J޺3O^{0K~\^߿ժOرѷn'&s;ԋ+3tț5No:rdaS30?3ٻ`{\ڷN5|} oՖ:Egb8L"w,"@N^7 3E6_]{ǿ7}/tN/u۝o;y?]^:{۶=~3Һs]WlVz5fYmәssC_D^|OΞ]Grŋftz+k3w(+f_xznZ:ӗ7$q7S?3||]JɖE1cl28_Ƥ0/-m>7Z>̍{v|hpuJv1}ҺF?[o~k_*w~sOtރӑa$i{{jz*8p]s晗{7<+^|ܽ..fYÈsY|7xtTte)EA_xk:e(籠w2 ǣ޽\_ٟ~݃6q_ݝT~(I4kFb"3PHFs"ﲂ& 2 T SJj}DUHƐjKLZP,YE1&Dg @D΅!%"msޅ&bJIUQ&fzksiRYı*k 2) X4uݠEQBѻBHMZﹻyg-FJO̚'yy׎^ۘ_[2\G;3Yqh>=晇P1Yi';wn#/}+_]ufsmWzB]ы/=[byeicscrj,ZW;t vB/=K}3|zO~䥓fmѽs']pukh|߳s⧟:nwѝWr< 6FтB,o~33Ŏ[t:|`OϿ':{|ktO`ñB+WxYxk8Jy`/ S[j"-isgr!Yxo;u慨\=}o|ًMWW\WzIיm+ո0 se3Y5 saOݍW91 v"QO.ww4̖>m3bk?~aO^ɦ^8qFkr,wӛZ:pcCUZHlJfv9%l-v#dm{N>y6nUW>8'fx~ڹՕ{vىkK[::3[[[ezb=<{ni47'7ҳ_|ߴffO{ܥo8W5d;83wC'hqu\YQ% |9xxyy}I[8< O6>y3P,:Dvu)gì$1S] *IsR $MI17UU!ErkNsniggLVM!©J].M6WM!1c4b,\Q)jSBo (H Xe9&e_RE4iNĆ:McEr܀UuB5lAsQ1U"eQ@Lz'"331QhlQb;ςO?>wیCo>8ƀB`kλ܁]?l׿5ZOCO?7쾫SO]IH!'Mϥ7Bg~?<7]>:Z}un׺h&;s+Ϟ;{ߞf4kp,SG^[d30XĜj%{>/~擧&{g3cN/}y7n8|ۿq%:pc;N"&DglrvC ywo~םCמyzWv;օ}ˣkO’+  N~{ˇ[[yܧ~Nײ Sa/nXp<[n91X2˃n=nP '37-zy;un]ܙ3@vM 7Qu )'Pl2KN2dθx,ܖ 3 9'jD)%}knj]DZRWVUl9&&&&0Ʋ1u]Zesj@Ĉܺ EYH$ܤQJ)'"bs-"b@U&&mQ:hcF$@D"{~9H4$a]hX ''g|Y@%TTC,]q6T7D ssۘZŭYyo OW/wqX_U%wOM~00z aP{֎}359ع5`nX[h4ܺG-Ν5 K9aLڭm(c7A .V'_=p]ZcҌ {Lg!45unw#L$ӛ쑧_='=U#7?L(fo=螽Xon>9񯿶KUf(٠V޹ahL%i޻cTg89jppvg/.Xt9'91!9+84u؎c  9\|bεKҵ};1I+hf{ ;^nvb3ivz^^~q9=)N]c{,BJJ3EizˁݑOf T&4U,;@ f?svmty% f/n*.s/{ゥ3׌+G/{[޼{75riymם==\wdVWW{&3|ѻB7%1|aif9{HlLW^g7ҵv0Tn+>m7s L"/ٽ{G_^z+K}mUV2o?=|4o  2utbjsT DH1Q 1F[j4$w>Ir]b.1q$vXUTU8;AY !1#t km( Ddsm{n/[@}1fV1b{O1F1DS drΝvJzgYlkBM<-;ܙ(U~$awҰgXէC=X#L>}~^0aQ$3~a.e/uƀWV4+X[@T_YLcW Ly+/-oXst6]˯`Q3RQ8y?õˣ VWgv̝p޶ŕZ|@*zj<՟}]\;o}=v|;{c{vZFRJ`R68go?;o&`5%o:_nVY1Ɣݎ!RGuJ V;m+߶yk{xp솩 f;f:4 D``TA c+㿽扸EK5n2 C{qd;잁S/.ؽa|~KsbDpLk{p⅏>~W_<ɪvΪkYێf `!&ddcF1t%!uݜ"HJlm:g% IJ ducIƛE,#ofێ:/\q*Y֕JEȽf8!d,sԧٹ>1mJG-t`:;v:WugZVacy-Yxuytt[0؍Rj4tȞM48Szc8Ovf]=0q֘briy^f*Mճ֊>:޸tGeZc ʲolm䒦 ļT?m~h*0+/m}L]')3`SՆ!'뭋f6ѻmTle&6;"i$I+m+Az(jLJCұcGlU4<\n,%mޱlʵPD¹jӟ6 **J r֐$ДEQW"4!hC0HN93s{ e~bg"P"X$s';!cuƚ"1ijkmrViůC`"&[osJ*4M B͒s"51NP( -KH:P \q֜c@l861Dh s$D cN9Z9_g.RD@ '@@dhQQF"/l5"ڲ8$*cÜrvH⭅Ιs%J*#yfms71%`FՐifb'ɚ,MʩirT@k:dS ^8FD3^TTD$@:4ȜrnPB X8WcQ3}4I HĪuE&4W*̄@,()u]&+4F&SH޸fb 6޴[ "L) "mדd`$sj}kfqjHi\T8lبc2r8"q U8Rll֬S{U-5\b,G e4UlR=g/Y$7U41fk L +Րj/EuZ%! u JB̩Qu)F@0l4f1E!"ms1%VYu1 \i-6έaZ6Lĭ±{=$fZ-$*>:6I2 5 !l*cIJ BC @)fE*cS)%̭3{҄9cXE 9ea6"hwQ!*V0PQE@P6oR\qḦ`"CMSƚx4EDҶNl)Ȗj\RD"Ǒaf&ェJLʞJHxFUY ?!1ۋ"7Md焈 gĜsGwM\BM8p#SRX"yǘo@%DfQ3Y< <0 GsE t#1<*_T5"z *<$FzcǙ˦_{qٯD&"`$fF}*TucDP:3#&RUsHk SP (UEzdnB|R^|flP}{qwAĶ g[MUD{"-f6cO+39)g!B3vS90O"c0:;lqc 3kzGDW"PXUY]ì]DȊ5mBD, PB$kyDT Vl^ṋ?;Sꥆ-D^_8`dDMݪ#oa"+ }-D$afu={9g9܈bs"PfLXJ`fBHf=A2桽 lIVֽe[P8<p5Ej5jfٌfC䘓-8D2A&HHPP !L"* 㳘GI"#˜%~_U"2 wzHu= w9U* YLȢ,n'z#3 "D?7݄ME6c.(..Ϩ*^%ʿEĿΈψx^\ŀL$ UN bzL5t@1Fw3џ x6 d֡U ‰ `u]} QuAEV ?>?b᪊ʈ+©ؗV;)"<= `"0ۈ^-3)[0UHP}ض>w'pc{ײF`=F͢*bkjfD3?wlyBH(㩢"aum/[rn9 Z߷A101u>:"TUtücT:sZD$mqnECAj%a"Ue|>u]ue 2<< HʼG-#3 c09ƘJ^S{fܨkB` "bKffTաDP[ Ⱥ2#2dʈ H'`, eqS33$D#dDC&1W7/Q7D;OQ||o{H |x$|P"*wvD^kQ,:sE 92`.gkB,8tڽ D<+kN5[9Tv0$ &cǙP2ۙ±ʧ"zA]f5*dT <{ڀPX\jWnRs31Ԣ*d"[c,ǘy!49qGp'23kgO}V*3k7c 鏙dn̂FtK@(*D8$歬F#^{EH1y a{ovϡLHY\|dZ+ӕzQz1Kd.3dFSTѢ܏1c,J2UX*DH^U ~x~@|>XX,@̪X ?z#aFu´"8ΓTUX3JT{]tgA{Ns;]UZ@ݪ;*HXTr `*L@B vl"%D#DsIe,cň~ ocFDe!( A QGNPp_3ɽhMgTEDDcfexTU^9cs6(z efYS-5֪rVF4{s/uW鵬DH ^[1/QQb&6WYQu`cՕ2YqLoR^I=G%9p5LD 9&jL:` U5@&@ 47fH2$e6.؞ӽ8wb;-׿|>{Du8!ę -cZGw u'_ CsF} bΌ29!ce{AhUA ;0Z-݄:Mh/ @R/GAof*D`C y<;mC Ic贵Cw؅)w:`4 *J.7F,l=̎^8i)TBd2 YD83}# 1QUu)l3gV"+Lo{!! 3QaY8JEE%+*Iw?1%Ҿӡ8!ޖֆ<>RS` :oXY 最׾ #̗"[gcZk;)UydU9Cϟ?{/"Is+<J1u]\Un~wDiɖ0EBm!2CXwt6̇(15o,!E!1Akh\PxG<YTs~n+9hTBaPum9^IH\("#fa{ =(,L0 `S^kED!!a\`x!yw^E({;$sz}=OzY7q>·/#*6t!"3t l:#ID9u/aS7lCK yKU~O m*bĄH7/DzC0ݼj%C %bYK0 2DTt (qT Hd˂@ޛD$U77 )!DF8[.ފdVDEo/Lx{9x4 >E!>zmsٛ[AHu]]ǘw j!qDr_c̆TӼi*~(&(l&$LwUʐ -Z0u@LTN>q|^dvk{14 SYdQPNjl!۾ *#UI*<[Yug;o XǘHB!J>ZpT'=P9'3YϚv&ţQ7 Nn6(o?~+Pݻ1dbdjy("ǜݼU%*o^P]Go| Ī ?D|]׋ȳ6cDQPIa!UQF,H:`BD.w,uwx|}]{匿^ 쮵8mÂס:{ QNw@'sfxsG~3fE`Dd7HGcDBAH̬•P(7g$y#ƚPr2F YQ P@@@̚U<`&įeʧ Y)]#*ZnVm Gd%fҦ8̙9#ƐvzhTI8!{2'#@ztf3r0Wo3,2pKEZ2gK˘1'7H UlȌ_yb+M\K<χzuD<>QL(fWiW𲫥9z>c`I<0 1" "=gf5 UیUŭZy]W;md Q}"Qvb&8uLx@T&0IE6:5 -%)^4#;=0æqPk]f>%0f|LVb)D|tDI߀D^}>>ykC:w$GߢłĔ"y~~<'iek(d9 FD~$Ց1;-uLADTIeJnlS5hR$÷"Ƃhc A@"ef$@fӲB$"F՗[ ; '" %53bdw#DsRe{n4zFa; >ilDpde0ʨDVMl7[4_H^Vbd4 *kyG9s Kوp;}#UBU"@Oф 㨌`BSxX|}߯KϪ8x<@^oU#!@ȓbi_1Sk-!s?utYA;,$ފĈ~wDFn1gyEʘcD6 q9 |>Y3R cX"*Rd`<0ۧXzѝg kB!9 2}^HYA[O`mΑN QAm w!jC7 A@x>i%ďح7OxVhaj$DsNowB|tBvmkQ2~_{pwH, H8E1x]˪c $J¿,Zޙr:NVL3a21 L3sF}L<$ϸBE‘NU(,-uw2<_v[󙻧;$?@3;To9k bG 'k {GCOsl)iQ!QW !nyJyYFHc<9""#(w|W^ $vp<E0b *~g^^{̱5S>FrmV!Ȳn{}>N@Jx"B_Jmp-{t~x^}}|~c4p8O=Kq09"ޯWCh~烙ֺ_2kG*"bf@xVd=$\4QR: @"zDLD"U,rDHP2~w(Ҙ|f;`u}"z}*02 &"'񇎨0(*/@8|>}翔e_wsϏ?w"Jd"U@p(V1_;@X=LIIݡFE$<-#vFF`/T1&*dZ{-D\nrfF-*!^ʄ2IIP+Jx٦9@7+zj9~꾮yV0bUխ6C#BJ[ 5D^sՅ2"?i0?WIENDB`eureka-editor-eureka-2.0.2/misc/eureka.6000066400000000000000000000105311464327712600200370ustar00rootroot00000000000000.\" -*-nroff-*- .TH EUREKA "6" "August 2018" .SH NAME Eureka \- a DOOM map editor .SH SYNOPSIS .B eureka .RI "[" FILE "...]" .RI "[" OPTION "...]" .SH DESCRIPTION Eureka is a cross-platform map editor for the classic DOOM games. It features multiple-level undo and redo, a 3D preview, texture and thing browsers, a built-in nodes builder, panels for directly editing the properties of map objects, a flexible key binding system, and low system requirements (e.g. a 3D card is .I not required). .SH OPTIONS Note that long options are shown here with two dashes, but may also be used with a single dash for compatibility with the original DOOM binary and various source ports. .TP .BI "\-f, \-\-file" " ..." Wad file(s) to edit. This is mainly for compatibility with DOOM command-line syntax, since filenames are more easily provided without this option (i.e. directly after the program name). When no file is specified, Eureka will open the first map in the IWAD (game wad). .TP .BI "\-w, \-\-warp" " " Level to edit. This can be the full map name, e.g. "MAP12" or "E3M7", but can also be a single number like "12" or "37", or two separate numbers like "3 7" for compatibility with DOOM 1 and Ultimate DOOM. When absent, the first level found in the edited wad is used. .TP .BI "\-i, \-\-iwad" " " The name of the IWAD (game data). This also determines which game the map is for, e.g. "doom.wad" will mean the map is for DOOM 1, whereas "heretic.wad" will mean we are editing for the game Heretic. .TP .BI "\-m, \-\-merge" " ..." Resource file(s) to load. These can be wad files containing textures, flats, sprites (etc) but can also be Eureka definitions files (with ".ugh" extension). .TP .BI "\-p, \-\-port" " " Port (engine) name. The default port is "boom", but some other supported ports are "vanilla" (the original EXE), "odamex", "edge" and "legacy". .TP .B \-h, \-\-help Show usage summary .TP .B \-v, \-\-version Show the version .TP .B \-d, \-\-debug Enable debugging messages .TP .B \-q, \-\-quiet Quiet mode (no messages on stdout) .SH CONFIGURATION OPTIONS The following options control how Eureka finds some important files and directories. They are not particular useful per se, but may be needed for special circumstances. .TP .BI "\-\-install" " " The installation directory where game definition files, default key bindings, etc are stored. This defaults to .I $PREFIX/share/eureka (see FILES section below...) Specifying "." for the current directory is useful when testing a locally compiled version without doing "make install". In fact Eureka will try it automatically when it cannot find its normal installation directory. .TP .BI "\-\-home" " " The home directory where user settings, backups, etc are stored. This defaults to the .I "~/.eureka" directory. .TP .BI "\-\-log" " " File where all log messages are written. Defaults to "logs.txt" under the home directory. .TP .BI "\-\-config" " " The config file which stores the general user settings (but not key bindings). This file will loaded during startup, and also saved to when the user uses the Preferences dialog. .SH FILES .TP .I "$PREFIX/share/eureka/ The installation directory for Eureka. PREFIX is typically /usr or /usr/local, depending on how Eureka was installed. This directory contains the standard key bindings, plus all the definition files (with .ugh extension) for the supported games, ports and mods. .TP .I "~/.eureka/config.cfg" Contains user settings .TP .I "~/.eureka/bindings.cfg" Contains user key bindings .TP .I "~/.eureka/logs.txt" The logs from the previous session of Eureka, or the current one if Eureka is currently running. .TP .I "~/.eureka/backups" Whenever a file is saved, Eureka makes a backup of the existing file and stores it here, in a directory based on the filename. Multiple backups are made, up to a configurable limit on number and total size of the files. If something goes awry with your wad, look here! .TP .I "~/.eureka/iwads" IWAD files can be placed here and Eureka will find them automatically .SH "ENVIRONMENT" .TP .BI DOOMWADDIR If set, contains a single directory name where Eureka will look for IWADs. .TP .BI DOOMWADPATH If set, contains a colon-separated list of directories where Eureka will look for IWADs. .SH "SEE ALSO" .BR glbsp (6), .BR prboom (6), .BR deutex (6), .BR xwadtools (6) .PP Eureka site: http://eureka-editor.sourceforge.net/ eureka-editor-eureka-2.0.2/misc/eureka.desktop000066400000000000000000000004601464327712600213430ustar00rootroot00000000000000[Desktop Entry] Name=Eureka DOOM Editor GenericName=DOOM Editor Comment=Edit maps for the game DOOM Exec=eureka %f Icon=eureka Terminal=false Type=Application Categories=Game;ActionGame; StartupNotify=false MimeType=application/x-doom-wad; Keywords=doom;heretic;hexen;level;map;wad;editor;builder;yadex; eureka-editor-eureka-2.0.2/misc/eureka.ico000066400000000000000000001440761464327712600204600ustar00rootroot00000000000000(('m\"*D: 8$(Nz+5~`x3a ^L61:.g#1SMTC'$HW  OHTNHLA$ =l8LXDJ43#S0.IHVEGCCLG5F='p g-VOENGIHNFMWE9@]t o g4MTM9@CECGBGQQJTQ&&r$ ^V.G;2:96>7;98==?AJK;$8U W]0XS;BC9< p9E<0}*u-w(k#i*r-w+w43`w of,GIBF448$$}i ,. aBMMNMK6Q#mH:FQ?<=9>FA=JFRFO&,,Yet V%XXFEKDB,uKAGC8=@GC49>FGGHQ1HA %&R (] V,YDIETAH#n;AG@7812?:9>M@GL;KC3?64 !->1"_/OAEDH8@,uPE>3DA;90A@ACBH?BAK?OM70;w#1^ ` I/PCI,l(E>!*hS6VR>>:==)rDMA>FFI;CLBFCB<3;IO;1J8"tAU%YM&%DK ` `5aOKKEK4dK;AE@DFCMI=I'47EHJM&q1tE4>:KJQK<7.!b&%bM7QFMKWTH*m99HE=CFGKLOFC=B@==>14-y:*i<44@?7.7-D<88>9>:>C?F@U!{LH=@=CBLH99D<*pHGB:BG=>=D=JO=MIBEJ>BJEIBKJQ34!3?SH.\?GM7K6?Q.+CE9I95E,w+oJD4L?;@C@MJ;G?H%u.#\`d2nj IM*zROCF9[ENHAMNK8D>DENGPH?;P;GKJYC09$'D`NT G!hUPAZ"kD9?G8;5;7CDAM)~1q88J7B@I=;7DI>;;/MEA?;8K>B8@D@D>8GCx6ZSM ! W~#QY#n?<>N:-D;@18J8/@8>V7"_U2A6@=A;DJC8A@UJCF>TGZC99E>Ft;Q-2#!+,5ZNWBH;LY77G<94H6D=:U1/hT5Q>CCGD@@FDJD:C=;D>?B4?PE6J7HPEJ=x4YFCFQEDP]?5}>|+`S_Zf/[R(XMzN2vHLTTRLL]ZA2%^IPKTGNbP?9DBGLRB+._J'H$  8 6&lOXN%pEG<8@?1=5@EHFCF3<\8;THGKBXV>AF7?=EEUJ,?CUWPGNMG?7I;MG;G[ u*O H9cRKPK9X2X);14GMA+@IBBHQ99vZ?:@RXQYd&wPS[^KDRJ8E8DJXR1MG77JZL2XE\\=A>?IM;Mg64#l#"#"  > 5cHKHC3z2x`35>@7FA;?FNB=:F5{;sPGD>T^?=PGDM:L:C>N9?8AKGOFFB;H7:WSUL<>BFBAM=@V'\WR^A/(]!  L)bMONP7!v=%_'jGS25>2BNC6$xQ(bL0`L=SK$g*A ([ZNEAGNsM:{SMC:DVBQK7-g,h)i2s5uBHLTO@KOIBF;=AQF=>JQNB47>AFbJZWAAJVP??F:8@FH4UPL3h?}/d ,$- %+Y0,D6>??,?+`0uPLmLS#YArR:MO2~@JW.h^H7AUHIH>ESQL4@^D0>9TkY?DG]YZF;@@E=EN>HDF>QDKDDKb_OHlVCGH>VJPAQ[_>O9L9V$TOIVHe ^6*,(VA"9E=hrc]J==Dd"q=m!S5nT59-Z\Ds:zTRTfl]LE|=y-|BUQ8JLN>G7GEBBPGMRt]56'!n /&b]cNfLbM]IEJS X.t@X7t-u%k"a@z0h0mE;uF?|8s7q;) '&U:-03U0]4lFD{:p9uA|D~LAzIAx:s%_3hCt9jR5s)Ig3g2o1j,b;~4hBg+e+bV;k >K 2 5)%LBFuk²ln^#B8QAU:iL]KYLBO.Er:2*>83m!OJ7y0}?CD;qGZ+ 7)t:743s0mR;LB/t'n>5}=D9KBR]BH;7&(wzo?A9 B>IFUI"fVkNoNXOC`oT=B+v0jF6MD@C@fl, ",/ T RH;g:`J5RP WN/4~S;?[6~.|9?EB>2EWO-`W5zL bHJF\?vf!d VN[% =vo0kd-x9zo5gW'P=E:E9 H3 L8SH TX(Qt,h ^R?<dT>BskT'&!N6jJHP8:vC90yE1{G+k={-j<3z6}(dY1wbt%M@>Eno˹bUMI\S+OEja4~ICa\*91I;G7XB\EeO`Z2N;?;GJVo}@%+++ 6uKQ!-MJ-mG3=K/nX4xJ;=6<9:OFC7>KG7C60~GZD_?,^=n!I}`=l g2 %"VO/TH$JC PH%TP,OP*VS4D7!`G2XH OMJE#rj4GAI84~Hi%kE?DO@-s3|?0w9OE-zC;u Hc&N   +*da9b[+e^5]X7^U$;3}FTG'PF0OD[W#jf1MD$7&;14%H> RNO@ !c K F13.8-+.OHM:FP,{Q3};wWPBMFR6'yJ8}O;7{;zMCg= W} L &(SR,ZU)YU.PN4JDĺ٠q}[ʁuKD#@:%DEWO0NG%A:ZR,_X,lb0[PUJB8A6Q @Q//4; y!N[NP=>NSU5=\P8FRZIAAHSF[MB?JUy%D QM,[T,QM)OH-DARO"of2TVwt4XP%N@-PF-EDA>!<92-/&80LH'LDhc1z?wm!bADT'*/9~s4g#GJ*O(D"EH:IA%I<KBIAS)M9> IL(T=I(K4U4++) --%[U6KDC?SF#KG&7:6; HD(QN(TO+LF#OI%ZU/GA#OK+pk?XPZY!GC"E="81F;^J"0FU"*/<"8&R27:U!99MMA>).)I (FOGIH 9=95C$Q!['L &%UQ1\U-XS1UR-MI'E?D@#KG*LD+G@#GB!KH!nmBxs=ڍmh3QH/ŐF?8HFIHG8!n\\`%$                 RN.^W/UO-^Z5WR1SN-MG*=8@;!JE,OL/GE"78cXV7-! ܑP5+ ??MLUE) $p`2  e^;]Y,XV2WU)QO&QL*GB$B;LL(VV0MK*:80,0* Rݠ֗x\vl:IA5073RI! dY *  $!TN,NJ!SR/QL(PL)@;E@TO0PI31,1-LJ+QQ.MK*F?'94'" ) -!=8mf4U_MBH# >!8  ,'#bZ?SM(MJ*C;#D=$<5HC#[W2PM/C@%?<#3/3.A;$?7]X.lj>GB?7'%BwUMMG%^cݢVT& $%ed9a[-VQ1@:@;C>!D?"C<C?XU.XT2UN2G=&;5'%*$#:9!DG"QN_ӗBFL  !"b_:aZ0@9KE%SN.VQ1OJ)LG&E@'HC+?:?=DD"WU2RP-HF%EA(<5!1)GF/E;zE;ŸgR` 3 [X2OGIC)OL'RN*XU1UQ-PL(OP)DE$::@<(.)-%E='FDTS%VT.@;IK,0 00;8=3u $l   %#'!#TN\马]IJ&KG$OK(RM+OK(SO+FA#C=!GB#ZT5LG&MH'NI+E>$D>#@:!95UP.b^2_])XR"A5IY[abtt{?L NG#K'a&3v,uBWUj/;IKX|RW V X!M"GBI$NK#S&Y'['$W&\(=.4%cX$hC>A<C> JE(ID'<6:3-& :5PK+NI)TP0KF'72D@"E@#<:A;XMuh)s}zy|qv ' %}` ^ t~jz|%$! q d[ O U buz'u)o'<<>=3+1cڂvnCG~1A9WU+ur9up8vp4}Ay;~?{=y=|Bx>ok5ZW#GD>7kb2wIE@}>w9D~@~?zq5vo5f^!kZ _'aMS]WU*RP-II*@<JBwEWLpi=ICJG%0035/1B="YQ)PыیގǀZli0yv{8zt:\X)72)(@<`]4nk7c_)vm=vm=wo9wq|qDgb5aY2LB#?6C:#\X$hc0me2ne/^S$1,+4/$#wcahetr?Pw;;z0' RE,tk:Ŷxׇؑی{M>38-LH.[`6vu7}z?J{F}u@JMXYDa\55/1*95TV.ff5qn=tp=ro:}v?pl5ie.vp:zuEnj>\W.F?F@D;ODeV ) .2-;ZZ1=0D9 !+)iY:`ƻpf{G/0 OQ+xˀ׆ӀؐX^[,TO*ea1a`/TP'?720IF(id:|t@NMLRSQTPLwr?UP,,'3-MG)e^7mf:ib4xk@md7oh:lg9fb3e`6YT)JCc]+]Q tot$ #BC B=#XU8gb=C?IF"@> 2+##FC'Vumotb]T'JG#NN+d]=e^7ph;pg8{mAgg:DB!4,3-NO,}jFGI\]OM[UWXz@OA&0(,0AK&d_8njAe_5a]-^\*TI3HAc]#od'wd%s>D  )QDQ✥W8,58;9D;)?2PC#T|rm|ZLIZW%adTof0mc8ne?mg?2+I?#}rFMDS匪`lg/z|1ۃ}ԿobRLPU\rj%~}=biϽ\keyo=TI%YP+b_3MN)@;&F<)2+YTúsTE^S6[Z0^R5g[1|@ZcawELD89D;UL)kd=snAtqAol:ztAzn9pc0tEvn?jf7i_4dY0MK$DCZN-vn9rƳrU8UtψVmb3TP*^^3[P6sl1c%-*JG'OG${z3o@dߏꇯWvfBjiAYV0DBA?TQ1hjyo0~p0|'& '.H;^i\uk9/"&"rk@id>`[,caW.`b7bZ9sh6gbQT.*+ _V+gzf3<{d7oRZS8eb9liDkfEc[@OH/D:,81 QJ2b[->;#@9#GA&VP0gd:vr4 Q[#0D8L\k`7VP'<;72LAybsh+VdaN*VM/XX(fe2yK}pAzJpĴjxl5UR&YSS;5O  ,+)+-)-,& !]QiTId,@ 5 7   `'%& BBC;%DC&UZ+RP)MH(@4nb8ºtJ21 !)'>:%^Y5gc6jj5sr"E@(<6#63FF ôogR&=8,/5==yi?\[[zs#SV#UdX([M)tEgUMB)PL5RY/_Y(_b`,NP-ZR.d^-Zod+hk-z7&0+) /'>iiDE?<6 /(">=gpi;E8)%CWB5:0 =7 \S*fVR$TO1XR.a[0`v7d[%F. 7/!HpnFrl6h`8H@.826/nj5SffcA493JE%UL O;3H@(MI#X[%uh8WOG? 2#  2jj>mj4\R.H@\T3]T8GA'62YI%si3[\.(#JD*mj7ut<`_.5,:3(3655LJ%WQ"ti/LUSS!+_}?fW1l[)ZY:WY:te0TK^W36-SN$NxoG.(SO%O`xDaR'B7 75 F@M~]J "pr9Kc\mm?SX.DNNO'E>#i_2Yke3KA#}wJe]6\Q&EcTDD,/SO%H_ O .201-<)$#KG%4)!?FCpf>IK'|IX09ZW8{d@[ca,YW2^[sp7^Z,vPO-&56NLL&++p..d                      651)-BXTTEvk3{Mkn=DA:+!f`3uo9BLVLG=?05:>@<26:<566697-;:8;52:=BFH<;CD8@/7w22=?MJ,81=97LH*(V>>;14:<5*E?7A=IA+==!@8#C=JC$}~?ztC0*B?#YR(c4+4,.(PI-`Z9QJ&\V.tf5hmZ,ZN'5 RKIpl2MDUH$WC!SOHPGBG[S('UJEAFFFID8C;$;5::92MK#j_Eil2sn=?6'D?!^V)^D=B=(<7 /*C@.1. \A0u?8SI>B9E98ph:)" ke1KA:DDE<$MKr8227#?:_X*XGA!6162  &(46(1-zjSpf4b\li1tsh`[VUDLQNWV^^OTKNNOGKoe][SDFpPPVZVVQORSMRF>UOy?><@@VZMH'E>RI(VO li/Vxq7_\|Bma0vi5j`2kh=id5uk4kh6& ]W%}xA;3;;?6&DHKpodBJ]a/0]SRIDMIWSDgW9pa8dZ+kZ961.,rm=xsF6472[S+[<7;7&8<$% % (%un6L+(( $%&#4+ jc'OHzm6~s>w@}xAVRSK"xl?~z8[UD>JEZW-RQ TW TP'F?A:NIURVR#SM'RH*UM,JHJ?b[/Nb]3?:[V,^\2__8YY*{q8{FVS'wr>Q=.) ##% ?7 _Wb]Ylf%)L``RUYWhe[]X9z@ZN<;6/;>)+xt/XD?vn9QVK}|:<8VP-unDUO{=pk5YR+OF)VU,VS1 ^U0Ssm[cpo%-/kl`]c^uhOQly;32*97phDypGAC&11XK |oI !;9%98")%=<'!EBC85.,"$3+:-`Z&C<0%"xyG_Y'A3<1jd?urBNINF!SP KZU+OE*A;96LK*SN ~DWzA{w6SN_Y0WP,QK4d_:^[0`Z1[S.VP#{J~yM>3/&D>#\Y/PzJcU(TQ3lo/GthUhd}96]pqfntbwpiVQ)G9'" " ?=]]3b^6?7A<XS/ynH_V4,) ;:#@@#57**-!^W8\[6/%B@;54.SW#if>GBGA f`>d_7YX(UN(>5F>!e_7ke:ZP*A9>5=5IC+II(`W-Pjb1jg<\T3ME&<591&"HFba8a_0b_6^T5\Q4^T4]S.d\2ytCrrFEE%(%+&DD#kk:|lDa^i\qpabq{58MvyydlijGA#BVR$>4!@8)GF&~xL_W,94<7KC(E>!FI(>="96%  UQ&~PNE8627+oj7ll7E@'%)`T-Rkm3AD0-KD+LF$gc8uqGQJ)D8ZP.on>ss@^]7JE*RJ,cZ4pg=B==@!50NJ2@>%480 2*>6JD YO/]Z$a\+dY9_T6bY2`V+~rDQ[V)?9/(7.pp8t.e_@quB@hr}u|taN@"g^5QR%?:"cb6sn~IN~A@@jf8sl>=863(GD)ED'3/KE(NE)NF,F>#QL-WW.kl<}zCoi;]U.]U0ca5SP&SN%h`4yGzr;ia)QF2=AZM)vpcy::I{up]U*>8:2TR}yK_W3JD(A<"JB'F?ig8Nom;c^3fZ4k^;bW3^Q.NB QI.OM.=?^RH_X3R[V8HI"C8 SF$}yBCBK@.RM"~K\T3RJ+xLwq=lf2ld.KNC@"a\2lc9,'  *)LI-LL*KJ$E<pkCMHB;;0`\)RTN,3.GC'KH(`[7[T/_Y.ld5zC~wHT\^M#oc^==N}lH;SL!km9vqCC:80:5EEYT(ztFph>LC D7=5II%DC!OK-EA$NI.D;E>$?;!IBLI{pDrJZU%FG"DG!E?"XN)MB>@8!KF~MYP0=6SL%wo>TWql=KGEC$c^3h`7.)'&! .*?=%?/jb8Ryu7mb5vt@zwKC>!+&-)/*6/JE%PK&UO'XQ#kb5H~oJ|mPO\qmf9rk9KI41>;WR.pjC[W/B?B=%CA(@@#HI*KI2FA(OI,ME'ZP0E=F< @8B@"<=E?!GB#LI)LF)GB$<@OM%YP$UJD!LL(OL"}RVK%?:<:?<le4xq@MF%HB/.0 ^`)KD" "85#1...4530ng>O^X-C?*%5/:7;9622,&"30b^DtljiOID?73JHRP'nh?ph>YP)VM(`Y2SP%CBC@><SR!pn;ws>UQ^Z,E?F>!?;ON,ME*HB%>8B<"@:TM5UN$je,zM%#-)F@ W`V*OM#DB"E@g_1vn?G? <5#=9pn7md<)!  ,)9:79(."! & R461.2,<5@<_^-rpI|kvtk34- ySI&J@NJ&uy?il7NLd\6kb@MD$rk?IEZV):8ZMJ&(#"SL5Z;: # ;8HA/F@)C@$@>?@`[{xAVU'D?7*:0ja;c\9*& '&==%NM)sn;wpA@;60A9ne8qg:HCLJ(DE 76;8  "*$J@yJ20 +(83QK/rƿXUGHIZձиֈ}A:|r/u6VL(I?RG}tC}u@nc7]R"rc*Qg`3NI{s6Kup8a['yvAke1'90VL#TM XQ}yCeW:NE,  TH*~yKQO!/+   f^8ke5?>BD#C=wn>d],3.7:A<:7NM)NN&=@&#?<IDuo>rhVvo[qo` "ӪgcZ}z^~f}y\w~[[nqpdrmPzy[v|[}YalkCSU>e`I~flU`}vU|wWulPmfL|rMysTts\q_SO:JL9[XBifKgfFjgR_ZIhZVT c #5E5E5C", ", c #3A7078", "' c #E14B0E", ") c #816728", "! c #BE5E59", "~ c #8E7577", "{ c #807B68", "] c #FD5D51", "^ c #3F909C", "/ c #678E96", "( c #D7963C", "_ c #62B2C0", ": c #F29A42", "< c #83B1B7", "[ c #FF9B2F", "} c #A9ABA8", "| c #FDB44A", "1 c #79E0EB", "2 c #FFCB51", "3 c #C7E1E9", "4 c #FBE849", " ", " ", " 3<<<<,***,&***,,*##&*#,<> ", " >,&*#&&*&**,*,&&,*,,! ", " @***&@*@,/,>>,,,,,,*- ", " {*****^! .~~~ ~>>- ", " >,,*,,&- ", " >**_#,_= ", " >^&&^^^' ", " >/*_&,^,&@@,&@&% ", " >/_^&_*,,,^^_11] ", " >,,/__&*,1^,,**= ", " >/*,#,1_,,^^^^^% ", " >/*&&#&]%.+-+... ", " >*&&#*^- ", " >*&*,,*- +++++%+ ", " >*^_*$$% |2|:::|' ", " >_*$*)|[ %':::::::' ", " >^{:':|' ':|(((((::|' ", " %2|;|:(:22|||(|||::4[ ", " %|:::(:(((((((:|||[; ", " %|:[::(|||||:||4| ", " %2|||:(:|||224; ", " %2|((((|(:24% ", " %22:[[224( ", " %2|(||4; ", " %2244) ", " 244 ", " )( ", " ", " "}; eureka-editor-eureka-2.0.2/misc/fltk_menu_patch.diff000066400000000000000000000011771464327712600224770ustar00rootroot00000000000000=== modified file 'src/Fl_Menu.cxx' --- src/Fl_Menu.cxx 2012-12-04 10:41:23 +0000 +++ src/Fl_Menu.cxx 2012-12-04 10:49:26 +0000 @@ -467,10 +467,14 @@ } if (m->flags & FL_MENU_DIVIDER) { + int ofs = hh; + // center the dividing line if inactive and text == "" + if ((m->flags & FL_MENU_INACTIVE) && m->text && !m->text[0]) + ofs = hh/2; fl_color(FL_DARK3); - fl_xyline(BW-1, yy+hh+(LEADING-2)/2, W-2*BW+2); + fl_xyline(BW-1, yy+ofs+(LEADING-2)/2, W-2*BW+2); fl_color(FL_LIGHT3); - fl_xyline(BW-1, yy+hh+((LEADING-2)/2+1), W-2*BW+2); + fl_xyline(BW-1, yy+ofs+((LEADING-2)/2+1), W-2*BW+2); } } eureka-editor-eureka-2.0.2/misc/jasons_logo.jpg000066400000000000000000004537641464327712600215360ustar00rootroot00000000000000ExifII*Ducky<ohttp://ns.adobe.com/xap/1.0/ Adobed       z !1AQa"q2BR#b3r$CSc4%s5DUE&Tdt !1AQaq"2Rr#3B$4bSs%5C ?-`ew6ڑH'Bި0mRPm"Og*/5 : !;[v:SAkͤߥw܋Zn<-@1b;津:!WnIAv4c@ B[UEg8{ cA )CnzxSJ9-}B`XXu:Fn^(P'hsP#@kmOhv)=z[44#'^ WN ހRktV SH@cͧg;P>(QC@5j)~ژq:wLV@$(ÿz #ZGΠcueE2Eait[ޘcwZǸlb d j*re#z>UB{xP9Q~ f X@PLk[tH R (.Qjb##BA)dҁڧ4 x C &ڎ0 ZUMN|i 6;ztP\\N58@ (ƅ.~TG*]uCT]($|siƙ"nu!N:E< 3}iE&G@O T>TY?eL:~bdU ' Hb@Ve}L4Jb7h'4Qv`2/'   ש$߹a@u#@ :iT*A?]&ʂW2 ( ^"ܑPU*&"|E kB Ⱥ!OR6\%>t >`SF4 C.-5lրn@J|tKձڡ0Q@ y.ub2ֲրGAo:K9˜P3H$2B.jE" (n>PBX[Hw87@ХEU K)Iʘ qڐL?JP&Go,cG7%vwX 56֙,ktО/@\QSBzzoK_@ Qӱ<*(nJk>?h'I=-LBoڀ8 Pl w }2AhWF@1PHkihTH?q +]jCnBu'@dEVsS,ΐ-RR t)+s*S! tC!0ݨV*_of5.G0;jIMPS^E$N0zj 8_Zb#D5R(-Ԁ#QҘ|{iw@22Jܿd@ KƐLgd,ӧZqqA"s "7|"[_?ۨ-LEU!0T 1˜ BSDu[o~+ %t4 J.p)&(i o0Aʴ,hI=ƀ&cM:|) ^ LIvGcJChTP05G4!H4r5M!nkJPx/ޢ"jXPW9@W|zdDP~T&XQequ4Km*EPƄr'R{C\A7>-hń7UQdR15M¯KyD]4P-!9S@ܪ@\^:dU'@ U7֘ xR:P{ LAڭ) Da[d*/1P-J"ΔbG&ʘ[! {9t⢘Bw:ZpJb>]δ +@4P0NS$W詭E:@ ɡ@úi(@ GA C,U-zU6Vꨞ^pC:{!M0 HsIo42C" ?A@tw!biژ6jt_xxh;ާzCܟi;4*=h)6~h#֙# *R'Jb5{Hc&pPn%, ]+vcH|ҡl 6](,NF|Q׷2Elp.P4 |P]kl, )pB.~4{.HSDhG_-@=z!@ p!S@ˌ֠4yu\@ Nu ;k5_9wLo"Y`p.EPv15[#7R-7,l"@!ށ6sy@%^Iۀ'qS<-P.h8tށ0Mre$HcŎuQހJIjh 4:PuT5Z@4&LLF@!phpAap &@yݾdR#EĒ.P-(=đW5B˜]S@_?:`r/r mʔt_1ґAZɢiH)]G[SRRb9Evq:]z} +-h;NB9A}~oSƀ+ LT>4V\3QG>kcRif9Q{:GyJ[!P<8(„RGW|ttwj O>9T|EĿ(z02Jb` RHQzdaW6i@!) *^uƷ{u2S:^@C(@|ocx$S;4dtn{e ͅ] jiNq.$O_Q8|Lg_UѷCkVrEY)T:<5 i(2BHh!@m#wߢF@sNdLpE7MErc~6iD"ҕG0]"}-Pd1?gj{GiDɐޘRS.KiХSҀI >@T|jdi PzQ6ĉ]h}6(X6"}@24 7qVƮ:|htMh^ISo dtj~D~T J;@֑hvpE .mV`hO"\kx1k x~4ROhh3 L#OCץAZ :$tb:'@Pۥ1sƺW?A| =h(Kiҁ1Nք4 CAUƁfjg^`[xx!,z-4(@5&Oz`5~K@1"PԹhԒ!k@]o`;Bob+l㴩0hMöGH n ƀt!4!)`5?95(($߲P@ޢ};Ԡ1I)`.8=i5@j;S zC]tVV(Z?E!H#STLU9iKmRMX."8ZG@( crAuhmP _&4sv":JQ,dҁ23jd]GZl 9*Bgw1"4e`f-6=5ց1֪Oځ pCmiinۼ2ځq55zd2ڀ)75i,nBQi),SM 2-CHo>/Ph 8IviyywAۉԀ^U;R$dqs{~ mfש"%lY$<ݷBܓ9ozlMy$,O1zd@|#Ϡeq;ʝ @S#_@#TiP1HU{@JҡJL|nR!5*,5M:S&$\`m b$F m{9ALB"R#HREUP# {PP A@Fh'€Dn|isڀc,c@hzQ<1ni ^7v.N@ 3P~ :LBihΫ{ wL\ҠtLA7XTs (<*d/@l{w`lPץ2NjXOJum4cjalVΝ@ln@-E!p{H;(v]44 h|)v0j\2@7'}O!qހ Aڂ)0(D1$(:1/Ǣ~LIFtc: H9cuKSDs $ yRĭ֑I; @T@ȏ*7TK:$t&TFAHg8z-PRĻj y< S$,-@OH ;dT洗)+ҁI\EB^*d8;i(`z;VCP;Z@ǷV(hL^uژ- Ȁ!Sߵ1 =|(F^׫@rtՙH]l /^FZdȔ8;UKԖp~\43~mz!c}S#e_x.j&y;U˶4*Z:*&ƗuePn%^U"1^NE"o$FFH1Prޚ{Siaҁ 6h}X)PV(٨Eiƀ`qt˜<HdjT~Gs˭TA]Zd0)@ A(M5ւ"wZd,=VR .OaH H+6to4*P8sz C\:t Il@ 'EJ?O!5D? R*8:hf栠rPK#QPQ"4@(?k@U[4"G8u`IS|h.q^85];izkNI׵2Nk48;(SkP h.5AU Z1)LHqP4.@K@±H?iקHr[K#8-?dz|i sTRH4<}H)1WP>Thj0 2YȂ'@=: 81^#I: D74@$4Ie7R%DuS^ԊA :!G^'ui.=:TOz{_rzƥ#Wr&ECH'T\ %ͻ%{O]0a:۵odzMBށi [jP((i PHQ qLJw(%ݧ{߷jd ǂ/΁~: (c(CSЭcI|(6BAVSlc@ I~#,QSjCBkҁ@*> _:٥"*~b:"+P:hj@륅"%GzEȈ%4 sB"At j[Hb\P\>T mԊ8R P@ʼnHƁ}’4`⫯Z '&^l7 @odgME@0L1qґD喝ԊD9\1N7! ǥ1TGmƐX< j-ҐW^m!^^5A6:#~L"Sӭ_ kC`ew&bP4пpCztP'Rҁ!Q0" )Zۧ @֠P540\?} DuR4RΙ#qy7BC%h^1 5!P?]TJ`uҤAͬ=E!ԁLAcj}!WI#\Ҁ?hJFɧj s#pOڀ8i~-jLLjҀ!^ 8[KPbsr/N.Dp:4 dreU&$Xq:G&m%T;Quҕ "Guj0Z<4%!eT<(K/Ɓν|i S@)`<. ܭ H|TkHf;O 竃ZUlTkIց]+T cZM%N0 }Z-_(5] k'Tj4cn,m8~Cuhހ|N@4*H+5NN#$;\*vZ8Ȅ!SGnoӡh DȏeZdc\:\I "6Zhq(4p@ zBƚ*;.LGD~CGc:P[z+HBjy4C # _@LBiۥ@6΀](ASs CAQrJnT[F{:\ i(.mqFP1 \4tCT$t"[juLG.Vߦ0AZn uDܚFDK.|<;'zC` +xS dR,u_¨AzmZC`.J  B5I rA 7id*'3gXm:P#QnåL t@h\w'~4c@:b`ܦh$k@WZt]|M"-R(*@? d1OzkUֺ +N֭d&9?EOLBH;B9E2IPy)2) )t `q%;@-B #[ zba87*(V bi=xĕp )ޓ tQx hT+ ;hPes 8|iƁ=-P)uVtDrJ"'NHmu$15EfE2Z#lkEP:q)цAWEI⥔ S >4(ۭe41k@6JkTuRa"Nhjhz-2kNQ:ymZ4[dm;P=TPR 7:R)U)T2E/ra!~P41l!{kB*oI"( Hlb`Ͳhzj k4OS%*c6@}cOTPWZ;D1ۏҿ*(W];ژH^-@ ?{P!OS@f:\jxD[J AiƑBWj/u_EZ|ө4b4R~BA7(cԑZd-'[SD6%S TTZSdoEKw1%4v[Қ$qTCJPf4Ka;o@GX*_$3e!5ۭ!O)=MƐ  SZsg(c@#д}(ؿR?ƁYQ"P:wS$.~t85Q)%s&hq 6I !)JXLL-%nJd'\4H A@# .u:ܝuDZ "J^htM\4T=j@ܶӽIH|Ϸ] ސeMI#Ih _av})k_J 編&LLc@=HNNzP1Tu]~HD-#5(,&)[ґAgj@_,l{.؟LC$hMbʢ!wJi hu4T Oʥ"berj.D;Љl ARzZ#ӡXT0~TE/s%ҁ1"Xʻꖠ<{7%2#ܤTfD?-R6HM5!*GqP0N\@'J 9OPwH<8 x@°wğPHl hK&0-UFI*B@'x&dLcÐ Yt bco!\_ !4Rx|)%4ZC&ztCN:. a)C n|htBOb)_@~MIm9)h!SB!M1: HҐ'E#(I!;?}2-vؓץv놂{48GUM5@!.%E #7Z_  /h'vW^os׷Jb"_ₐTBQO~ {I( ҁH} CQt!m@䎚}h$U$;PPu*~4 P!SPP9ck#Xߵ2{X/eTXET < n_7k4{/CTS rwR*,I(GsԑLԟ W9@=_la-7 ;qB"N9#'@6K[!sI:cbnImj PJ+܂4c;J@!8Pu=E1 KwT!rZ !t@D# !"u$zt .^AY!K'O(vn{Pkh_@T uD 7*U)ζ9I`P!tw:y9#x=DuN@AcZlT](HG?Ehkځ3(+@#5>g#T7(mLBJ9A1CVˡ`nr|hԏӽqpȟGX`uZYѥq?գwWo\ohQ+!}ǵ?a|6̷FF;/)oi';q hXD{Qav4zb#!n&7 /kC51LTҢJНQP¦ʅ)+m@(*jhsnc@3ers\|3d7>#A@Vc+G/܍L/0 =_}ƟљFL?P"ܦ [F%_+wm#y\$f G8?$=L%fL?P,$' 7"]nhpvEYFz_Bu6_oh?]>>,Ý+\h@h]kѸ#Pͪ?uA@il O.%!Y){A9* ]I? =`12rW=zWl4m?h7tQ!pOo,vWEw䟸͟yfh'{r,O1dIF.v(*bF8(Zw6;E ,pB+@ɞ2EcH&{dq`lmR7m0P_h q8_oizaKmhq 0o6oib@#܅t.TDFWزLqcqa-Ѭٲ#đn\tq4'q=PlwTM@p{i72?Qqp|m7zcwУ/v# #@鄆OG&{ѥ_ $}b)N7zcw/܄S ~_V%~Ww[6 8~Dr*/Ѡ=dw>Da@z݂ȏqWf_4A  fL]~G `ԖCOڥe&P.:|*JB<([4JX|(tiLB-@RIkvnU9.;SNmGO~a~"(ȳ3B\_,M#N%?gbb6VcɽrֺcV2[ǝ;l:4L.G9q&lvAͷ6 St7΄O!獀pkCRseFO=r3qɎ$p] ^ִ&˜I& 9)ҫ/ˍ\|p,G:)Ԫeno7:Fryn͏1ԻKT./Wa=Ϲ&W%DHA-ڠ8t?6}kÝ8s䑮t"6%IԮ<;8E;ƀ2cْ!L!lmդr)lLt26bG 2oބJr?|nf~KY+UsܡuCVqʖG%kdqjUKIN{/vT͛,mQ9jJjĵ\KIRmX3gy:u2K H#"1ȖGu\31='-2۠jrTqLdYj -wVFi<2!Ep8yLZHP^q#k2jI<ޓ9y#v֎ǵ4){72yhlI~*.ѱxe9fX8ypafxW|YB[^/j9сQӼX> T5G<fO#ѐ H{ah}Ñ/ ns'АPXjL$<;/ /Λ 23N;sFz8vhNˊ4 #Q;']oHӯ}* 8#c|xn?!Zc"ij|+SL QK,/ <E͇gWJWg=ukd8ui(hq+'eJP4^q^cc+sovLѨ!l\p'>3!ɛ+^BAE҇oRc߇df;;lXfRn9ݼ._'s$v"\*>S q}!B}N b25kh(k]Ryx٧e }>k 30ͥa5N6G (WC8~<ZSjF̖wFClj,{{K%a#k#wXZ@{wopv6Kq+ TZG)1=3D933%;NحR1m>pHɘXuZj.l+=ŗ I'A=.cJtB*砙˜88G^ W];aۣsn*MrԱEoyc8ojµ;tt)#8|) 7܁P3Ge+Gp,DY o3W /&ܼ3? F=X 'B>nG#hdwZ(-L#p3HtPZ%&W%O Υ!ldu,\ըWUlpQ!ѵ$/q$ܩ5'qʼW<\Ew %\G) vL754w{x!9˝yn,d_͹=ChCw[ȑ~hlL45 FB'쪩+8rss|CaFdw-Tɺ۔332d9X&J\>f.FDф9OJLqtő1G7e٦G(#$S=c]l ,I\q㲲XCWiMD5%q<>3C%8璏)LT+K!p28R[es fNS?PB* ̨wNJIHZ{݅2b..Ti=3SO~nw$B9tpG +w mևV1Q՛xeٓH՘8H]OU-Dl<o"TDr@T۷J4(Md#} 2}vBbf*+뤊|^B9C#62 '~=QYj=<&G1mn6:;?Mn1_srs'?S͞_qG17q+D%.dsGȆe}V(q1B)khpܬE>N6N^dʂEbCUi*S/(ቊA;jk$,2v9]aIGWE04e/ yoe(|5'T^9\K 2 W4Ff03J }ב/BL~-͎4rˡxFKq>FQp []h|t*9X[i*ۙhgFլ:v*{B9oAFL2N<eT316^h+:(Ϗ+dy0eG (&6C K6נb>F>|cjwք|cpܮ.LYﻚTќnL ;.;RKƳr>y <#7"uX2XCsp3͟ GҖp]>Vc)Gq8V'dQP\>֑LgwJŔ" ]3~oz7x|L , 7dd8HjԥfK"? ˁłe#WIR.[XUyr)!$s55K Q5|lyβ!(]2YzIx`vZD\J9`ѳ ڄT!^Zn( _\bA}Ynk릶9QsC˸qZAo0h/zESg.`VlXLby /BPi'Myk5/.D 5@ڞ4Ėe9䱏|aE*JGVG c3zXuUŖsO P kTuXI%r>^!:y<à@Y?1Y;l.cB[ʔ%&ˌy2ƃ$Dwŧqq;}VI:$yY,%"kxС* X[x.HR;3sP~H! ^5gV4~k<u5ΏJd?gw/6y0X%͎:U"SӪ -9n$\.JI 1憷1P@RJU<$dSǎ&k`?p^~RId,sbď<]&;܋.يuqhJޞOĘ15kX浢g:cjL?޼ʹL̲=;ev4@!!%d42eo5KLȸ~|в1 hs$ VCe *_9p3% K^Ei })˟G61xLFDyp_+_ZD/ 2lfȕh!GaXX#Jn=ɾ칋3dzWs}ƴ<mcq8dȿfSX[ HxZb'&kH+W%s=->3r㶟? cDc2dav)6SL c .|vZT[3o6ɑ`KO.K.N\-1klFֳ~P'p!lNv6Cb-bbn#_ӥ*Qp2}L×^G5z9hZ„kd/'+tukjG󄻛uv\粬t<ʝc9"r\Tg+*+C: p #`ϦWarp,Y<[eid@i*LHRQy 8HľVwBMeCJK[$Ź,8ҧGxdQTm֌v[f?ꖨBu1Ъ{ַWk{А$f/2KD*CB9tM^%`aΔP{ZE4Yi71Ϻ-oEU [e!vB-##ȸpA⮐QT)E?˾BV،lof:W--g/ArU4*SNp]SCҁ `5ZsnQ ^YZKhr+VyglХ\<1$&ƓH+EҶ§٤qf:92@wJ Zv*&miÀ.S"/F?!s揕 QcB'k9cG5"tYy~C@ts5XHv ^SQ (9;?+3%͑#q-iqBRbkJt-+9gI,ĉ(AqG=IΚ_69̒` ͙鹫E.LD=X Fn&s ~c0^KvQ2WpyG[+ x(>q4bfMA/j{xv&=&rrⰣV#24Pib="3„NvsܚѰk{rB@ [s]xd<ߥsx4rgeU 7vlX,T?wCoX/+*! (fF+\‰`edɛ)n1hdE?K<ayz=>)INhs\yB5ooGzChhS5N[04cUa*kq:(hed;..uilMWʄȔ,Q,v`#;#k'EȊŽӮO/L8#;Pyi}2.,6xk0l+ԞT%@w†<_^L ]^,OVAcgs\I)g=[ޞb;"~B,].ҿI=~47P?;ZƷ2Q& 9adedGu*Y 30q; ˜j⇀Ȥėl0[mrA{BU6BѶ#qqy[3,}>n\;]i+9gb9H2u6I} GUE+Xx27j2(aSL3DHLXN%ڑuBQt@@Pǒ,ȡp16[\cT2j %kGt=ꑓ\Dss@1°m"/n\P =ZQtWrDnnMKufavlWt=hR&Vt&PS[\72 ș: jG,fEft4nnd'bJ$9!ŎoGJMs'X 'tν$TPRrrmil1SMcs#hsdN^j xo"N!r!)}kX cA.5J )<2׶45* cՉNQ8'f2Y4a8-ULBA)ꖍ7HֱM9P{{ɺTsk0:2m( ~@=) YLwӔq(t2vrlKJ3kxyח 9r:^$~\Ȓa֌n4/D"Բ)*º&#K\V4`fUE$O5>gd sZԐuYݫG^ʑ<`w+k3^,{e 8i+X%sr&i* ~Uu9YfÁ @"\鵢%WC9J|MN?YJJ;"PBI:ۭ)!tdC(-{wsmMfХB,\\͚I!-phPҊRi@"lm"6ldbe?Ҋ}+uja^ 'yj)#ABՔH܀^&̰uw%C,>Sj)jFr8YYǸ_8S/M$~JlhdM"Ie6O۷ Or~cۯϟEOCA8'ZuS[\ k@v)މP!> ]hUA~u-@l{ ηhR<~!<܇,k[numn5ܢBB`2cRâf$Cp9n<`<;OSČ~CiJR:+\B#1Ѱ98H k&ba021s~ʻ],pO8?l~;*+Ug4.E/. i"oWw5.upmyZ\z  ^n|iT٭VMi+y1:sKdui&JOpM\6s-[Es'mipӧO-n(L͡[9؍i"e2.ryM3&C؟U>uNKc@at2Jn I2$'A)^clqZ9S7iԗ{H< |3=0B٠_kOk-UQw#c;Mo,eG32$!!b4O B/Zq'Lp7c29rpR$N=G92繀]vST\tJ|llHIrFI LFxXSN8EL9-a @ RQ \ lŏs-gOCRfzN??#tqYuEMENk8gA[?! zb/r1dy,?'s/ Yʼnn;kMIWrqNT#dNd{"rP_'i+?)48Ν^:,۹ n2VQIoV=rqY"P:/]3vvڝs&EoSv=+J\x)]Ri奦Păq81Ǒf$x4E;AVe3cl}!.g{[->FC IRdi-5β;lhU44b ϭnng=T;$C㶴1dӉQ5^yy0M0d Fi\dmc sQZ#Ij#8,Boo率X˫G̸h݉g|,"  oyR6y}<ˡsY5Fi[_'4ݱ2QV/alx0֧n\dDdYuK1&xnjXn}g %wGOV@>;@FǍ%B|ʩv1BWA"bG$NCIfs]vj"̒bIh(`y.}:U)tV!A4f5ڻ|`ŹR2&vtsQiFY,r= Q"HB)-!mڀ7p@U|5CJJ>)O*knt*!)zPzt Aߧ@#?hL0s>cڵG-Vz y܆;Z#]oc=xŇv8r|Xsxs4%uwM+65|V~6a\A8FNֳ"֩`sNXfS{S R-vxWse K>nsiqkoVW3i*>v;vRz*6Epn)O]+;Zv״ #iMd%*TFҴӇrd-!;yJρXr LVX!ߑ#oxi*Y^^FvdFc޻F1_K巑okc@ZFJ6ɞ.#C"ۿlkXL.$y8lGe%Ғ4mVj" [ʴޮVkv+H*q1*3T(Cԕr `+]4^6 ?)ߊw&S {kNEɤqݸ8?[ɽJ0fw*9Drkzٺ|y89-6%5RJHBdQ ?>hmUY![Y>uB65%>;5gpTZ83\-cp`0ܬ{G!Ѭ[jTpux8m& \s ]{WtȜF^w(s3d%RBS)bꊶLx0^~^v s e hNh:<~e1=_!G]jRm?9fs7]=VNs;a~W5|llnLt N\I-%9(t}{z3JwBZohҝaĸZ32lY\ƟW[i[g⫀أlrcDaeQ-ȷY8v,P,Mj;)ԣ M {Om5̑;m"A6_r\c1d<@jN}_ )TqF#5^Pi_52G;41[#Hv7*pHnie`B22"υ,-dlR ߑ4)I2OC(\w)M LF￉cB`" :T^uGN*3)K摫j/GjyN}0J*kޢ*SLL,. kz=cRv_,$IM:)Ɣ<b|XEI 03Id.,oܩNT4 4Ѻ@cQ)&2^[% aw$z;tdsOY#P lxz/t~ N{^w(N^7УaJYҷkI# J+WQҴT0%hsm&DE'*1 k 7=^vRsƙ.?m9Μ!l++;|_Xp-%W }=ʤOcT;_֞YT>%vq`l},xxnԻEY {GsXMD2A1pЎ\*y4ESdr1]M .; ?8A&\bUZ1 P7ځ'ۙicʥ<{i2jڐƸ[@KlP[ *߸G-ק@ NKihQmzr9|(+8\M1?~L 0qITq%TOJ\'6Pu~U9H!s}x(Rw,g>~UEpEs\e2|Hيp78DqjM&d}>\XkD9QJoJ5\Lw[hģOʀ$Nk\H~3xxZ\^&uzK܂Ch:ex,O˃]Kz҆kI^^ C ƏA^=΄tg+.ȑavA?ʪ HDwu&VOĆK&wzNS $"ntRFg5%*ss9sLBodq]xBcW5B:\'!>4 Iܦ4A^^'-X~f#,n͐=Y [lQK"7BDy^SIcC"w,.=VU烣Ԍr,7C'zs`=LӋdy8ctʑ0h@#ۥsh=>Zpffb_帮P{MJ$6Nʳ4LYOhf.R߂t`'RÝ+}H^ SŽ:Mupn"Z%^s.-wM,e#F mU̫LSV0ѷwh~%\XI,̉9@>\|H^>UóYۊg!DӂV?j?dlqGBօmrdG,M8ɥ/ԧIIvdyYqdHc@.'s46hy!9a|+j#Tg㽯v|E%NZ&/sN#w ~Cȏf/BnIT3"4͞,w.}.+WBVit{KKR?$gϖX# |}QִHldУID=)0|4Y! mmhy?6+C6%kt$dm]#'R3an6 0C ;U0^e8*EI;=j&RKŏb3vs,wUҦ<28L`;7$n%ovDn.n#&'{Y҆sꪕ'ۆ1eYw.ޤ^{o kCqIR?mMd$l=Cn8`ʘ9R_ƠѲq K=Ll-`)ϰZ4͘o#[6\.?2`-&PD[tz[)rqDќxǃ6(״uJ敏9hiyj7P__Dr5dKu2N;vkPvLVF6-5t/x3c#W9LC+Qځ+'zaEKDJhr &) h5ְfUh~#C>T'HWUQjƗ89j~ڬQ|Oebg᳒2Y;&_GF[{*{&DF1!``ȅJ+J6'Tؙ\y+Fl^ք@oIeB| |se,cac|*XϩGU&^^ewccW /4z10TL Cp2ΧNl`qro(o(߆i)CC \wRwI?SҨPV`y'E?]* a*7zC B84>A[F8a)KPix0ܢ)KQJ$Yb-$!4g 2 -!kxk53X_#lLOA[MPp<^*ѡ'EosS)j,ܘ嗏$ԞtX'ebLJ1.,zRΑ:uF)b.8bqBKuE UqGԥ}(/L h4ZX/ԁQRͷ ҋu< HtY!҂ȿe4ɒ+9񒁗QVw"~Y#$lerX}1iyjyVXpK{QcIChjuk9qG y}7G)oӽU F~<8tQ5;Ի#:F܃0u7Uci@#m`hnEP1:hpFڸ =׫.>_/#FJ#30Hq]#`eXKOnI-_Yl~tc+"kHkʏ2k$<-#XMEj"ͼW~"VGVLL(^׆C)̟$Eshzh yM7rydTG1N[#sԂ1@jOe<$\<đb7 \&tU^Z-RĞ2!_1?A?%Rc7LGad͙qc._+EwBA)$5O8 g}<ݱZQ99#5##yvaȣson<ΪC͍bn3 ƛ# bj_ԚWFe;9ǐZݭ O RlmG#5A8z{Uxukˉt]? e-k\U+;jHu=Wd*r:]PpsNl|f r%y`aj/zמ(ix5J2wҕ +,sޭ!;W&,Oo:ɵȅ\O$~5I&6HƇݸ9Yd3V:G?鶋[A[rf,m_坠?҇M+K.T0yP'rHK^72AB(hDƘ@`+IQ -u#T=l%\@G,} /)RHCFH,-d.&ۼS%qf%A@R+{kq*M+ #iC4{ABBb` s̍f?:Ӌ̨kqq;8^9Vm $m1%9So||ҵG/31$Nk4Rs+ûb{ 8YhK:.ȝbToI'\ vy5^:CL R/ul< ū7I#k}ܿj.S1F3aGDiֽ+xBtFoE96n<tJG8d 8N2Xe$22B(lpQ5MEGG!|B=BmKO"4Ur? $(+$=}^d~2þaGzo X%zPWqg];ܱEu>`6s#729\]JT8sAA53ܾAH6ozI۵*[p:{Hx$l׾"aĈɐ==kíZřI4 1dp֔RŴ'$wvYIR]^1a~GWgZyT4էDkyJ"wHAnbHjoO)Xځrum*krz$f{n|r4i[jW3}qZ轼C'~T97g\ǼH{ĬK]EF8RIfB?ԒsTHnTɑBM.5s9`apldxsBJ UKVG>: >^Xi}!^¢Q6:g+Da'x /.k^ yWF,X79.&ĸ/z딖H!nIYjkLd+ng\x+є܎xT<1"@*NJ~ނn'E }ʛX"bqlNsi!Y!}r h!1,kվ:Ƨ+mh jJ<1^ TMGJLL5%$=|j@~i1LRQ*8,tU ^ ]t 9aVD#zG;ՠd_@Hg[i1"e7QfNqԨͷ q΂L~@[2M]o.W Y?*z9| đ1/F_"w4oT֔T9:f}:v@F'|Nj{ :y>̜Ȅ$xpm[/YC]x}.6ȌLcs?ôIk=#ܧG ckz7jZ$֧Čdm%K%brCJǐTA<?CI?lx uUq##&ϱ$$\ң O*1đb"8FIjnie)ƹ?IFq: 7qeP_عf%" .{mp+#9no RCfdۣowU`$,w!s:Y܂-x W!`h(!jZrGGN0Zm.Lmk4z3ȐTsnŏST 12mn.ֈ`'Akj[Rlq8Ta:C8p&4zeOo6!`Ht .yy2Wl,.ִ7ҤUoS$T3.¦ɱ,[hM9Jj~%f1' g4D4;u{WAq|Cr?2bОpFH֥ڶUj9e9RP$/s$nZ{uSd3XN&{O⬔"z|:dFcX9sdN)i[{Os ~\?S8xL\tKT6Z"eCԨJ (942F W|j(H/op98ḵq]L)y,`AaazŔ?{ AiQSV8X!WfA΅Z۽w p;¿^M_>c(˧>xQ_º$[mA@ Ԣmp5 |( źh1 PԆp 7:Qqc A?(XT9y\.Dy5^֖oړMUyBtbn.\>B .A(%h9<2kF+"0g1(O 2. I'5?.>C bx86{~Z&yF4iՕRIƐ ZOj%6ϼr1O^.֧QCZ|uCrT%)JMI3~ THdu*Z?"twOPDF⪤_ƲemЅUE>|AS[Z2Kϸ1i-p{ܭ!vCG%O5979 ۴_t3͉qqb V #:8*ULF\+E4O4X6# lyNBc>|_kNW\ZMovszf+76RsI]T+N^M6uf qƟ i}F aZ23^(GbY?3+;HAa]mv[Y#gjp}fy|G}?к"ު*Nzo{kqlC G S0,njtRdKVҕ !sfc>Y96r w:Hpu5XG֫ݥϹi!g!!fƹ B vh_z!?-MV:uoCF99'y?Hi_QA6>T&R˶Gp#*,Z]x8 8^-Rؠ?!JфN߰xEjPhP+֢X_Yl_.>Zd GrA<쉲w0]$˸Z~eMR[EvzLIl\|/$(q/3#٤4=!E`-ʥ9N|!X D{7}7t+u>G)GMrsqQti23g`N(cNS'cf.;4@VRDBrŕPY|[eitj ]Q+/!X\kUǾiETn;k, GEfYͺm@ҳY.;)/J($ HHݭh%`f9|/jv9w8Z8V&qG_iq7<'mkX9nX$e .$'^OO y)ٸ0^@PTdʞrhRy\*kCo^ORxaYas4<t_1I T2,)t&4 0nr#?ܣ |{!k]д5mߔ_w?b^*954#;PECjPq}@åɒHȾ`T=2R >9!zEIpnM+ϽW{}TƏs@)uw,W4lJ~noۡ*K%;r}t߭op?y!p+r4Rl8.s` $9d!.tG]UV̴:n'Evr-g^||Rc'1) ڄ^EZ3>˩nvr@_:P[o.rhq4U%ȗ4\0G,͊3 nir3;hjp̛ ފ 9y\lÚWC7s/EUGjq^VWyB1"h֐Rj- Jhڭ k<`2J5QFֻmw]-7{g;6XcB\;]ܵvZ}in¤0_K(}%2xEJpuH.gs8갯KZU[ȏş?λ޿²NĔ[t񬙲+/[菨j7V35O{mMV>o=G>߄eA;ftr%cvuY&V^l>1ɖK㔂/,n2XQ,*ꪇrXe8ȝ|aʽmYq䡜Ƈ#5Ej;+)*NMI\:2$ʕ-䄵C\4"ߠRu239$Xn[(quPNw[乱 4=lƀ\l)ӧ֢ZrDge͚yHtӽɴ78@+ڢ%#qH(7=FuiI1J s{p,<bq z*>rS3s\HQȈh= Tqě,E/ŗˈȲ vbA-?*n[Rs+75EbflQ6 N|QuXAPy kQnkh>x&62s_ԺЬ5 u4@8x w:'A:-]˒G mmaRMQA 78kxH$КͲ%; mjō { /n~A P55M(r!T2sDrPu?0Qeﶣd~6>y =*.߅ꛢ.wmU='8T\ŏ ҶMЂ*THagEޒs]C41=K)~{Q$LE3(\n_Iyv)< 6{ 6ha֖ %Z w)VҦ0#-r}Ab+{+*X_reƚ X4ZW07ͽK@+ud@sD[4!5R7=>O1O3: o~\c_:ɕ34ɇ"hP% }GA]g=r-)U0ܮ. ĉ׹kC H.GuZ㹾=AIF2W%gnGn\cdp5+SJԙI*Pvd1(鹥dvN7{Oq1#yMۼH|H$m5f̏{b6B!+λmvu~&W^8Q@PBzt } r m@#[|BzC=JZ0zdl Yu-l}qZ]tiy=Jn7S_e}`2`3+21c~Ɩx_p~hae;x\. C}I2]`IRuv":'&C6Lɑ}629$I<0)²ʇ{c)r3ź8:FnZA,0/?|lǡc4n4ڤ\,n6+ Yɒ06 l5Y5!)kf[e !;x?Zzpw3.*G*Y0;s h%P'Dⱓ&?mxJ]hSODgyITbb"WF=Bumg#&| Gh-CY2626 JRK6/M14U5Oԅ>5!of }M!0|m'%|P]$r]t%⛃yxLrEڄB ڌJ1u7,V9,3 S䍭{Q}|zEϏ[mJ21qDťwt%{vÞ~߬y1q-pKJ&~bՍW^¯#qN,E准\=CZG̩.\ ^7NO-yyn&0tU_.'K^JUK/C/ qyQnASH] ga%yZ<+$eff VWq[[Kv5PwdFjƺw?%0k&@>-ݑSaN'WWlUO7,L`~ȉ;G ~Ru<X_FЛwjuoU('6bHaӻ5?nPj-8rrq_[ cX?PT4iG-fִҮ:a~3 hخ? Mi!Knr#sHUԸTekV($)'bU./hoEI@@ݨ n)<x#6zd]Tw~[aO_mܚw^ˏ;#3#vTm*0PH7a\t#іoZ`v/3?7799 ,8 ob6ח<H͠X~DD4/dĝUls]F?? ޢ207dyn4ֶOϕ>g ?dc7A]u=AoQr؟(o'9q?n1W`Iv҉Ŀ 䱟+qps2f->-Tg%K2tҴf|Xtt᣻- @P9Ks/#J;~o4~[6ɤ. \0hFc7Ƒc1r %Z cS^ AҨ 5$[\[( ;n}UT?;k+ /1dh+dAZC9kdB(O.(6YnH4og:*L$d8g@4]zW//cbpYLd .V0m\l4{6w_f~K\?S;vyen^XgŬ J~VRiqe g3&v|E6~rҪtj{?;(xFFKEJ_+rQoќgGeb=8ms0<突M!sSrQ,5FC3@Gm UQPᏈ K'U{?23dke񃍗9cM;Q[JQdZIҘ19zqG Sc88J4XNԭqꚓBo&}-.]F_GstY綒zh#㜈#1Í BCˏ Fƽ;K 7ؔ)2'76,e ECʦ:YqP`3#p$5d+T+l! )7ɏPAH+B{աA'[-"čpCCMuO;u%D9Ѿ":|j2MgՍ a!Ȍ^r:n#?+z_ <ٗ<>R99r([r7N8ȋ]4mp}@W-fx^n+FEgkm+~{x_{)W#ΐ )~kS[Nm 8:w. kS=(W@ _6{ LG |:!IMn~T#2?͠S<!޿A.ZN#(U.+17%ҹ;@j~4(M#0= lTl ToAs_?y1mE>>_gϢoֳed!ےNYT }Z(i*[ZFoؾ} cqP4'/acbW6VrY qs9j @ѭrW7͗-LcżE#L1:-\UzO2+0GdK7VG@kbs~5茒3+ۣXдc'̉dq/!jn!٫oF(W X=ݽWvK蕤( 빞+4pgZL%{D+v?o>;:Q3h'$y$arڲ5Dk oҝw?/at w'2YA!< )f}OSo>'ĺ6qȏCFڸypjcFbc徾;v&o& 3ha-pZT# |ZPn.ѠiM8V/4^oL>lFoN뾨Fy/lޔ|~9y^[rv~^$ds~i>Aq A]G KOyqx;Y#zֻ$cĂ&c`qf9/qzS*芼c/ #q%) e[Jڦr,{5cl'lsoBޥAj>,nc7cĎƉW QN 9.3Is͌]ss\*J3iE8x8dq;IPi5AU`er=z]ہڗ4h˃){`ȎkKn:[P7sّ_'PP *5.AY<>kZcwi({ ,JRaq|h1ţq㻏O%MM1ίǖv}lb VҺ"L6޳3#̈pd:cГ _v:?xc:!vaw{ @Я qQumVT1#^O>64mk?  3V(}k;# %"FP b];F+/嶵I3a,'#A N^"KvKov0P| 191dY@slrZpƼ^ fd㝐ycs۹Z̓xI4362M oHyAk[(C*~6{]1Etgr 9 ;\ȱ/P]}NgMW7379*t{6t؈)'p,q@נ=+&l :ƤdIMV͙8%l^n\EN+_d; _/ I< 39?t+쑣k\mѵq9)GS.t2dG9%@#KSrFx'nD2K.A,ғӡNS+(qss?qX˜+r7==nsrt)q$jo~?q,Nja_1S .ZPj-j*g1J4J;Eiipw%e2'IP$G9ZA%k{ x6qty__:HNIkHM6,9N.:Vl;baDBTB!6ʉqw5WEB E SVe1q{ oAW#KfE7xd$wNw(k̻ͥǧᜫ3?κ(N4tր)U:%1 u& Gp$ @N~=(VGj(궠OmQm>4csfu%pXOw'="CEb՘w{YY>e9&`Z"{mݴ'UҔgrڌ[~,#2l+dYݿiK/vI`* #crrø UT-~H|sv%X{as?/bB% m^ǻRXR\H |DqGabr~i^g̪įՓVn[\NA|m 2&s4סQfW :("iGt{n,Qӌ""gA.RIfL),#?.rXd GNReW?/xJa=TbXKVG:n[-" hn/ʊ J<2!\%ZJJ"I8W̙ a07(j vZJ2cHq%xU=9Gr.rIX1H%S+byciK[1j>=a`ccgH9,r=ov3m#= l4Ø dʐᦩIiS{&cG :/S^S4t6Cgf79gniwUU#Ljq8Ot xFG@f3# r4W9ĔZ0O%^8T X9mCYnhf}y?+6Cd!,;q)}EͲ)2 ۏEGIb'R .~ab?ۆh-Z6%[n?d8X7mͳDJe6=*J =0 Bn˂#LR󩁬,ִ( DNy1p 挗=>4(lںWO/1~_qݨ,Ok!K\ݭr~u[JsLsOnjf QޅiJ~U !#D/]'"5W/ doOHȃBAG];V\-E,F{$+d["oTR)ً?x(}9<úvcg3qY7^RN4zkSt$O^5Мl|19T2yw_i?m+u,T#'#׌6jHq>"eUZ<>x =2V?-p!ftvؼ6[ dvLj:oޛKY*5ukrܻpp p{\ WZ+D)7ʓ4f.+q>$ΉlpXrf{bFfc !e &8gxWq蒡w(A񥡏Ե)cN!7=G k4/^|}&濲8  y%HCt©Pw29w#)Q bX+μx}tu*Z#AhMz[1 ڎB +ށ -V]4|*KGѩB[O]$鉎o#LAo Y;9ys{C3װXi*;IOUCkbpr">a[C B4ߧTQG)Jmr{{H1ۃf TFvhVtum8sp$_Oz֘4s;a9\"*cjN-WL\Hb=w;BTdܞsݑ .?LLU$fdQd\(J8OTs|M7&#Ǐdm GTА!۸ lqe\ytp)EIˌ~" Qێ,<ϮjQkCC}u[<\3EThg[^HKԔYVܶ?U)!Қ_熺G.sukJWd tq?3]c80ZjyJ.5xe(ɎH ; ;믔%ƕ8Tp|ӑfLXx;|FT-M½VF~Y ~ߞڷ-1g['ǍD/x6|o9Y>"@hzG7i8Fca17S'|gIG%2iyNXqdAɕPZ |TE$FfE&92K!=j Ygpky0KUsjYNϧTAy5533U̓3$o,#Ғ95TK sNcy}N,7;H3q|R |+""#{ypTTK])'dsv<7ېts!OjwUp(x̖6)p.8Xp Y4_lO9Ss[r7de^y tWbCY&ҡN&7jLpa7Ti+y,QK6:2T &L}hKyqbwAe&<#'[Qkx1(y/wsV,)7$hj$6Ts/66]>tѷ'XszIPIҬg{~1;%`lj.C]%/CbJKd.;r$%8 D^"RG\GIĹ<ڻ\LO,~_=FK x4, z-T:83\A҈osa͖9"6ԩx6K~Mmm]2gĽg"54DāZ"YB_U4TdhnR5+3 w4@s)2M4lH52K4}?D7WEs|>7F\H!& @Fz epKtMidȩ3BlfvWoHFV3])hǵۻs%buֵ31囓xf3 .*^TA'ETCxǎhϓƹ7"Ss~[wr84j#rEeO,>#>kX ŎkOSK6ND́F鼋-;]?]aF"eLYbK:㧈J2PW{f44$tulE Y8>g0?}E_qmXq>0 ӭbΨL, bEݴ ;nt3\$|~N&oGx~uX3ׇPyzw瑇}p|+ͭti7NPs<>M4tCs+T=cdcCP3Gôi4/rrq͸cO>W(B,YO{\|8ۢUt'=+L3GHsacAlg_3{f'ZJԝB2! ;XI2گf/)]mXC1 nF Fv5d{V'k|y?.ȑcX&V;QXlda& M71e&dq~݂Yx{"U"Fb5ڶ4_J),Ĥd$Ȗ)^ 9.k: r6 qǜwdDwp뭾19nOSҋ\09hn% ǑhƷo_k2JXS{0:=o(_mzQXnq881 'W[ݥUn?sLJm{Dޭ*ўceK6g;Kڰ<<n@Au;9`+oSs~ν31ؑh^m>l~.FbEhr-j`9ܛ@ uc@@-e@ 6ށ b-U DROE- KweCjpV1%F.֋TIwsR(? ;-N-qG+ ܷ#@xV37JIVԳ#g3)̑ %cQQȳ1+4핎>W3]ScTz2>"#_&8$t['Q#))ԗc-1GQ Og d_EMjU~7+_4ϙ*z6F%nL9x}sIحq+-9uĒdteׇ#-{N`zuH֘زV8 j3Mx򉿏YzoR-bBA:Nq|1'g Vm{=12<{|J5B#ȏt5U2# ETVl9$7:^Ee}~'<Ǒ.~H,׵NW31!0rcec9ۼF-*L+y)Kϙ0Ӽ- lm\Po2&f^b0Ml^oo{ʼn qc" ZZ<:!"ɹ /SC rM,ɍϑ7F7%S *oziQWCo*g3~^d>i#OB+/Í>>}M.'5~F9s?YM`\V7A+0`8#7Ǘ .@r+uYj3GG^nk>\3C>W>_vi_M T|T+MŪ>>L w{&s;&13lJ} M3X(OѾs{bix YΡ/=LA1*|Ƚ>5BU-쨥qqX?g3@;w AK&G' 7P6*(~F=0xH~mk$C޸?c]10u$,{ݜ{18܉ps!̩fRlqU̽L$gsǕɶ8rv꺟 в?0}2}c2aDK['$%+1Ueܓ+|CB]jװuRr| VOs{<\/{_! ]l5JZTcVZĻl>NB;rbi Bh ڤ^mx#^,O%x,fmEvI%|=ǟ9yS1d4{w_^'xneΊ,@D X挆i_2.j[kH}w7ί?&|Kwy뗖? m6&I. Ҽ}yb%Oc=Vgs՛e*۶jJ} (&Fv T=JLl2;~ YQxf-pZf?Dz]{W/_LE$nV8.eqWDcזx{l Hl/MDrmR7uA fs\8e~<ɊEaaxKSiiV*;Qcgo ;óp^nS5vR^Gm\N<2fߌl3#9 )`CB*"k3^^RF ׹|mkp+$#y;e\w%qNGsp48)'lj(eܣIZi:CUCX4:? lNcCġZ y1"c\w5ȁ8֊$9yC$ѳ[h $5{8_T=گy NNWc)k|u?Kml809`HI܈Z du_yJu>cCpk/:vGQ&6G򞃟&A :gtҹ_* ;zf_1R8rd3+#w iho)-}FǨqƒ|OU6-Q\=漌Ƚgi]%t9U%qy1ǗԞb qn`d4>|gb<?A?t8ڴo xnbgqj%ǔ^rP>( nRDxs}Վ3?'viL)WyXgy~#5?iFFOUz|j6fV922^Q:4tvu:#d_W!f55 @ḶaYL$y%lh/5lvû.|F'EB5pMP.\t6 ~}0=7mēB :(.&+!Y$kg\R#9Ky?0-3`7NABOӥv_09(ހpDB@jvJׁpBu"&)PJ"v_A5$IKdu69K*$QeT/rn (rmIlT2ok+2sA5`4 ߾&}:?Oj.Ǜo?a8\A3:6z8ZL_y(i^D揦n5\mF^L鿿mnT:)x/!vo)j)ܵTy~jвpv R(z?*g^9}ӇA,lh׃pGӎYUES+nq=HØCWq[Z*\SQL?!)sX qQX\E=q뒣Xo;LNة|k*[Go_7KIJ?#≱%d[PP7ye\X׮K\U;:q˃{{N9aْ߭O5wj~cue9i#-z{FtUvIܰd~}xsl'rB|;W qY{u4YfO'/z4sK29"|nj lld,ǛI#{7mcY OcҖZ W3~8^v7FmoRRs*d}=&aBr #[ҢSQ6qvF93Kn\J\?k(6{,}~r&zn9OJw%i$NDa!ZκYDly82)99acݐCyj@5|F3;ܟ#LOde K}5V mF{/y.Hsz 5qX#,[1YXyFy81~ձqmNſ=۰<&elp9&gH#qpZE6{{ΥvB4g 3lk䈻hOkZ=;Nx缲&|v]doc\r/oZܹܿܛ6dx9s1θWEF/ ҵ %%<(EOnн},s@%m$6=u.i?eb7#s mDSHW_[ey||y&>Qn1xx-['U{/cL3='m?ݎ[7:?W)+9%:*F6K&6lp,GD/hVmw5GQ8?qcp8mdlsUD+hNd׍dlˈxjpR|PJY'RnV NN~V6X͙ጕВǛkw8N$ޫ<' 5'B+\` W,/굷N5~7ܳ=3"! ;M=MՍGz?N_k޾#7s%|)䕬DDG)M2=ߊ_bdm \r4x3(:5$;^{&.TF8Z4}^R]3U)*2n'ΑI ]OdFas𲑤g(HQISK'Xޱ B\:U>hygGϸ'/ΗyuE ,Z=~%):'J/Q%@ue_Io^[ϹrɞF,'Y^4ګIhCָvq:z% 3=7dq=|Q8<9 J/ZrKJB\YŖ< 0MKJ[͸ՉT{ͥy5GNsf3qQd甓X4hcqvoJ\nc]VSfX[?2CcaҐ~&g'F/͛)9)%CSRh#pqrn,g okTl䔛mDsp~?.y7*ڪbf+&×nCSvkO@-ME,!+{y{,NKLa.z~ڳ ~?CVD nEwB#sX"ָ /;4/qwey\oSUDYnE'8bLܮ#k m5בc3z c` :XV z;ʗ''.3%s)IbAkEf!T-s[FDh+K$\)|ɓe{-d=ks 396ϥQHFN3"I=S#vvuݩK?MP_|/N/[R9.^֑UI\qOSEr.^R77ce#._!;J={T^GfKsZ)M}>Qnܗseկ{[^Ny;L:T>ωnW,;LjI$oikb8lOTRBɛ}VGk?RKGSjٳ}Lqn %8رʋZUT"Y#dLaU! .VJf⤚kc.Lߔ7 dn-v9)={ JV]^y mn[8`ǃ5vc#`-'6G[<< Pcrı39^'(Sօhd^R;}/UNL̬Lj2M&s]}}7XvUuv̺սgVOxO~TO|g;fC:9޵YNPM|&򖮸;8o鹠Ð4 ;3K/l32n,pOӷU-^ ,geۈ0p`{kMƊ6ƤmĆ 8Rli&{ۈk%l ǿsAnZIE*F&ƟYl~wKzdFҮ5Ob`ϕ"lNiZ F8mƺ`.'ddS'39Y4#Mtdy/i~͜%0Ǔ#;kˋs~ZJH||~|#ߟ31"cK @29.\UdO+G%[-ٲw㽤Ӹ{^j\TRq⹜gd̖͐,{ekHknk|{]+Jif_φvg; !u?j#KVms^F@vVDGRIllCeY&jo&RDģ>T9 a߭ls'*u)D̳-jFj(1P滢ʵF5׆aST׃wW^'NӽT %zW9ߍr_3,,] N; Jx{ l7bG d{,+LsN9|Ea)UPv c3 lCrCUaJr ' B<)ݮӭeqwt9k[P^ {HQQ-ƺ<":S6-ג"7(fU&MvY?}74F7iR{i^6י=Pf}O7Ii=>B;1xs& \T*+qn9AxX\7nDI cmz ^vqp8Ir4)('$UT4,O8]-%1+b~6Ȫ/N3Ԛ1v9dsDtle"Hdj SJtꔗʒyo7W/eT񕯥G7_s俨Ƃ,3<\%y۪zQ3_yQܣ{ Ǔ'1{ŸhB$ݵX#n2\"yޟ.˗V<?5x )K !cTʕrJ?H4{%aV:M,˔UGe2osqwKͮHNU<[+ڜ'LȀz&`ʫQnߓE;~G^WV)M?@hB,)#1 v.zC7o_^H~BB)'pM^g;WRM͇}WLkNև[#pŋ!;F{՘VBv1XJEWo7̜*_;E_R>*FǍxf S>7# <)FOV>$<%0x4:<0tu xVg[$*_kSh1wBM}zD4 D&@A:61Y unPh+fEVRFa5n?±h0dly$*Ph9ku"O){^ޚ-.ǀupWsw{nh#+3'%R[W-# iWXm'\ G=-+Dz(iG Z{lw vU>4m1>2 (V :^Obg{'L.ieR>rKVN MuMTIBeb٢DNS)S5cdFQ 5TJz3r\81%r1Wƻ,KrKiL96fI@꼋d\~<,k*zQ֫lor?%cZ|4I+9~oǓ'Z767B?:i%OOAdVH@ݍh~s>vmwO9pdqUZSNRk3cyx#0) `MaK#uۏ75a/g :\P $=PD.y =Oད:MߓGx O`)&T5gs>Xxx2chp:5|ORp^G ":6b;֏K7ȾLEĮM 뗨_n4νك`akX=&Q_ϽxdCcPyuQVǍ^!cesxxMs{#ya%q{W&i9z#g 6.̑Iߏ*uSL̏6 5S!b{,|\xsi u j]G-Nm'ϴ= Lhc\1klPS:msLG_ii$zaGFg /]z{52RKT?mK`/ǚXF8e{1>smBⲌrfpQ P4}>b=EE#Hf%}@i/M#MɉB3% h]{*vjN1hnRX`H(1d2σ~̈́ 4 1dF20y)wɢ5H@({W=̨z>z<)p6"@4@Bi^{D``?ºQ䲻>6V+X4TcD`Y&~KGwxF0{{v!ɥ<~b~o7=Ȍ&.@Z/Q퐖PѷrM[z@ׂ(~`4C .%Zb b%Dg} qqy{a`Daz]&nɯO)W"cG\/'{zFH:'2W_}wKǥSRqcoCP6*^!q%B8j'JEOśGc11/#- P75ڥU3[R"Ls52֗A$)hPʦԱ*9z0;vEߨ*P-շGϑ͸ک.:_/\`2#&F:0QGZ-WދF\?q;׭yFR*yF zy{kf_1;hl@G/nqhR]kKfp"6QJ>/}:z%2;+cIt*obSOf`~͒F҅WJET0OTyf8,c`Æ0]'iă7׹Kz$ҧfq//8nȜ<;'F+ߧd>pޮnK!X~kk[wJώ(o q\.%BݥTTpPQ(&gp9{v87ahqp]&v֞Ѽፘ1zcdN  턇y]~ugS=gEmI;Q<_Euo}kۿIs< >W!^"`È蚮V;KRDUw$d`iwi06K]p>|ݕawfCʆ8M_wu/Ư#ˁ%B^\OSJaWGqe$RtGrc; pDPdV{(dc.9ޭJ(KCjorynATi?}vQ[.ܗ+8ܾNVA '{3wmҸwR.mp=ߖ+oxA;_b1sShڼm*wbh,h]*{Zq75(ҷE)tȭhdi>ds KCSEMU9b<|qፒ5.j\ܭqS)҉Y=g:iX3tBΞ31eF"5RuMzDZ{o+׸;/ 0zs<Ρ};ͨ4`t?ڙ2ر@z-k> /z`dOYY5J']el^0#1lQJi-a_7 㙑"h Oҡ?O ;~gvNJ(rd19ΉFƶ ޸7z,_*L'CWy˽E>#;/a1~D/u·ƦEx{o]ď,r =uUҢ:ܾϗfN 9:gc^/p֩:ٚ]rE&\l)+:M1&NΟ? Ef5 Lj/J}^?oNsC4>; ;_:xx1;馝*9E@ TV%O#/cL)@ }­,/lx(7)hj4kaߪ,= Y`Ly-!bh|iٞvU&c佡 sb̓3@#^4{Fvtʌ堋,pHn:Ƈ^R!"ǒXb@C<ĴZ6܌wK3ȆFH2y0i 1$4:õ-%LOG9'<9܆{V&bJ/5-ws~]ec' {_/鴗8mI uEx?RXq>e~kRz|ǽl'T[W9'dsV3G$\@UޓQw6WYt{܁ޘ&l5+"cH\9Cphf}ñDQT/_Yݕ#Se=7+y[H3SqoW?%0 OGơ$Hż2X|7~t_i{rۂXG =f ;~ -4V[rg"{ds$k_$r5\sByR52̜怶)ęZ0uTee^xk>Tbd=]-V vp*K2J*2\j3ȋl(sdq&3G+h ?q= ‡0ןx;ȷюG I0 &ѷ%+Tl唝h87av&R jjrT&ܫTFyIى\Bp{rrĩ}wCF@3 `ʖXS˴s^]ҽ9(ן[㼴?jC8֐^Eyzk n/+-/8̌ٳ!&3 + |Q [Q|.FxcDl|m0fi(Ao5֋Tf\_Yt?8! εk@fK?1E*R/m9]n&;in#W\EۼEL048ϱ [SD6oNꌟ#įl B)KWӚvg~i_b$ۧU5xl(3#kT8  ^ZeEAL>X$WF#B\r9$Lrɓg4?acѿqrBZsmo3.e|܇GIZҒqIb=~_K+gvV),dІѵ KE8\x*1N.'+r/\9"bnvVW.E=*qyјJ9xlA1֝wZA4d֚$|,`9.5mSYwwPz^8#սn',$"8nU ]p;\W}Ȱ8YYL:64yʽJ?ʓdk#N̗?_FL4#&=5kv:_RJJ-TL6>c`Qe-\^! ;=֗FQԋY"'҉/ cnyAEa;JP 9P2x%uJ=(S]Ix3d>[\hD y1Gt3t=.b務} kw`\Lc EQ7Aa i0D\ 鵐Ѯ"deybCB}L zW"e฾k5Yc$sk$єsHr5k[hEqdpp\GE*1qiW4nۭ _N:ltRyv?#b"'J*O-[ۏQ3*_d*vn4b\^>ً|J]gOs|ԾzlÑ9yZ^ zݟGp884ug<8u6?VӦ\'](hdymg[$@vC=2E}_+X5-2VoSsc1xd֕bߪcŊy#?69n+Ƀ kZZW VXg;`K2~H:^Tu͗~زdo+ qt\Mw+щbd/sJWCo#QY[\\^F{nTY1ύnG jhe\gxgv-ԸBwၚ۷u[d&% kX텤w\XD`3q[z!?~> Efcg؋\]RI't=^]+ /D$tn#5MKHU".I7cx~Os66~'dcf׹u UNeA-d? dA1i4!g} NW!k$c3qӍū %(BJOf($2bFFs_ ǙAh)grpGSWU]U "=kL9(G1&GS[dxֱ"Fffd?i!QE^hG=2v9w͏J"ln-So2W9B {iʯpܴ32C7 #6FAIݎ ?͒'(_x5-?{+j%zs)Y70ZrT-Tn<1>X}u=>l?z ?7%>TB#{.e@Jח7P.Yܜ;' MFC5Ā;_Z'+iҁnZQn ]'P r?7)?͑/([,QƪtcY_CΆBD9v$7U5BIɺ1])qSJ5Wr?6Kœ4~4љ.-GC5PHkM+hF#,}O ya{anY(i`y=m.'s|:lɑM?ԙX|W*pnWn䦛lŚc|+.'lm%">+\xfrCG*FY?ժ楁4S!);rMJ-G #ea2BD/bz'J"-ʲxTOymfcL.n@ -USjo~Ӳ<Q]ӧA@ (EژS߲ߧj)7КJ{E@n"UMJAorTB6ّ,MCM |Il&qi8M݌F(:o2ue;ܔX\?q8bDI.n&7&dȡÞGIP͓ƨٟč9h< INзRtG]IF {q3,T& m~֔uΞZYI\cB½X7 VLi]bx֐l?^5s`. CD_3kLhN:8n( ;p7 #2<dit:71.( DQȽHE/\L* NV)! .(@QJu)}.VsJe!$I; uKj{~ar0!{Cbtqے z[lߌE*}89 yƄJ^J_ۯk1ʆHݥ]Aas? +߿đ=9/l;gDc3qAꣽyxw Y9Ʊ#O{ȉ vB-OmTjbeq4}oahP49(zz^Ϫqr^P:#ھcOB>SSic( .><<ɹD,آ`W8UUx$Ei%Y<6=]&8Z,禿{}_%}Hlk˄}3QcUl㹷xn.r s{86dz3!-,*#quDqݸGY;+˒!+rlXH@ZHNL9aUĖ80ZiaE\Ώ~vr!.GAzbF&P1SZ'ҟLݹ%T=oPKYr81\uN͟y[2wc\̘]8Py-S@4{\KqD;\BR5HӰ'nZbY25t$5\e xiZc8d7b\7ryHP?\Dxs$Y täo?=o+gG\[MEstob4R@W̽{wKOXq۸{G.fzYA6p]ρr>2W4/k$  J-\zC̓|,LL~_pb04Xrf;}HDyXȒ6R-*:}8rOòX!҇oR&wMt)ҳK㬥HہÁ7#?52sC">*Tq-IbMxx0H&8dBЁڻ"xe0A\FT7*y'4E0l WGjR-ʊ`9S=xxboMxC(V6{Ϡ}Sycˋx͛8 fKnRͨ`o_)re'>څ1Zb{O D\ZLj^ݮl*5oo}k˞CD[)IqOq}vJkNK"9[(HWd3vLhCϕ$y? /<(i<'V9#"Uۧt\~> y>MI-&<9t%5o6]l^'-9 i$|m{}\ׁbѨ%AUndwy!#hOO6_D.#OҺ6T-ZĆRa}1 @:V[}o/ٽ?ۘ3d$5W_vO<w|o?2܌I^MPw2Ruv^D h =?`mHᤅ;Ҵ#y.D|60f'4hyX6aXmFc,% ar$Zְ"\KxIr=.gg#,ƂS ZC_acW6~^&վ|d@u_}n?mg ?*h xlĂ$i!iߚk\RnR8#vq|txXƹ΀St6k-;snjuڭ](V{<$3@Frx28KB܏kq<hR 2:? ^X* OrD4 ƞ{-1JmnU=y_!G4 Ȃ?yҳa2~.aQ氤;'- \|tS/ p$\J:^ky^ﰚOr4RB)1@@Bn*uܿCXeR88BzRZP2O1#{ctRC{ 4&z' As8r e9q}M&mSI)О0d.9KfWCW"HD Pͯts;rX7ݖ6kv q'4 u'YO[V3RQkOa'k"/sZ:(CU ?r|38?Fސ7sGƼQ7}MuCϓꎻQ_fnH͔oYWUˑRtG53=eCWÑ13[624[ʧʾ{{×57{>0c01X #ʩEo_կMEKEL5Y./spC&;-ӥjf{I>/vߗ`{d7nwmW^/P#/Yo?%y\HFKVǹhp߸Q|oBe4bbq[XtҊ2'ǼҀQWjOuZ^oZ_X\2\F)OMҿ*rXbۍ)R2WDg-+CIJ\>^gܼlF88&.:'sB+8*Qz>6e8:ZϙJuE$g{{ <8lэcZ7 .7Im<9}fBf>)qk'Zb%%g'~œy1(-tJ궫$q$էCOm-&lR;;6iU=67ꮧSq,.qܮ - F|kZm]q;|1;!Η.r$q8^|P3取Ke:~{Bg 2hn+!1c|[Mk%J3Њ~H8YِɎ9c6R;:m]=XKy&'@ajO'uYUx"6,y,ϐP>5St]ꛢdq/EY} _g1w/we3]> ]ל6c62H5P#h?Y޺?1_lȐ\.4Sk͜H*Asnnw)-:(v;"7=" WTLrFi \UN 1"s湠0G:P&.mσ'wۣbk#!UhT.G?6 gdJ".}uˏG?>ߗvIw[^/RM>k'EŏgMwS^kg4WF> JȬ>,?7 Wad2km;GƷ&'%tULc#pqcHB# xSxJLqɴ^ZZJ(4nul494hǰm{?ɏqw]\i6S ](HܛZĆR`=P:) zl~hN74H=9F!rFdJndLqKO0Uy7 kBjmV)6'̟˰|j:7LȜp𒰱"2CWneR+VOȅ.dx,Ji! LXX -@W]mXn%USe<%go0?:i_qcWΟߗf82OV{}nQ݋ep)8%%_cȱҾim_W>gp=v I/R]-)X3cVx08"6s-Thhsf6Lɉ'5i.qߧzcv ksJ`Hwi}SLCZEE!*h.ڀA/}Ǻ&㙁tEDuSdI~=7y ȔlgK+ۤp<+qW)`d 7I(:"J*Lb6rX0;i_7ӗis}OOЇM g/wt!LoF֛7Dz{j{uv1Źעn ЛV~zhb=fL#/^BOTxꌕUQ޻"zC~_BJ#! NJU7>?fcd4|1[F\8gޑcjҌrXߙn/7Ǝ\3~cT! |u Z  n$`{ '8 nhxkHPEv8\d`Ydgr5ZD^ֲ.Fyw1nFd%B-G.CWbd)y&;!q.lpSsCf%ݮM ";đҵR6ZYrKGv3̂W RF B*<g{vK9kqa&5"4ؔ ƻNMj^2s\EI+}@Ik[bW*pnEg!mm89+flsߤU?ƶbtċ~"AifZEsуzg6N[27ebaGnL|GsZ\[ҡAES䫁߱9,X3c@/.+\SO%܏82{:8dnk3B7ggu[ž=ܿ!X}&Ḏf~'sP򴖹@?Uyw[={~ֈSqpؼdPCaktaK5rm+V.xRoUZɋZ\BpUH ?K'dŘJJ$RZǹ]TV--PSm>X Yj ZZ%bι<³᜞V)xVz |~zrs185$τm: At6:k &dl;!tч,`k$us`z2U$\'-ɼߕ;iwajuTs~]8 o c&oՓ>av AUWNUQ,x?N-ppkmˑG~w,6N9 qsXZ /J\8#qpv6]jUjnUȉ\2I  d"{U߄Bv)Qg!  [#K׭s\-9/5ԢO*E\BX ->a}} <[OF^c/ .9f(B ݿM F*s=$=9rhqdFcLjUPҽ (CnMb<9^L28b: lm]k7U+<-ȯ,j'ʾwncG BPwˍ mۥ^|`jcxpnT :vWԝ[A$8Z3"XֵsݠrjjUW#̃s||n4dGk"*ċ jD۹8d|6'*nKQˑ~y9T*NZ=9r|c\d0hTM(.CWa!vd;,x(אi&\^YHp'~43)XȢ @#m՜Q:.w\i3Dk~\~>x~ߗ=;qQ31ǰuEԞT-qrUҸqv tխeOSDj\W~)fBhWmsbA#V2#Ryp$!ɒXsacecCA%Fޝ)56a?I,V>lY񵙱@K+IQPZR -8CgFLX͏rnwP(A\db\jV1o#s^Ɖۥm5/ Iۦ)Y`nD09>GHù#+mƱVd1frr$|cs P[`I rӓ=.YIcx.tvnk~LuT/^\MW ~ imW͇E9La>VS#,ɞW50k+ϻnM.挢uehRVtV>2GǘvǙ eh>bIP=WƏN\*q*W{8)J8߽ZQAֵnJJ.SnTr4+t[~u͸.G+:GT?}w/r-h++T P5dY0%FD qa=swirxqBü1xRKUWF8Pu4lx)t4t^ˑf_/h h-s)(W IU4DJ.2iǑ=әF/,qKug/-զ_k|Pk+^h+yCtxF`ǒ:B,/y;'\n'~Lr8#%9dr92͌÷:"V((Q>}hir TLb:VL6HKPy{Ɓڟw _.ltS&NGL\Tᱵ^{|ˉ6<2y/yagzHX ZI u WW,;Bb3skRFʵO`femƚ >rwtp^FIU:XO X$|rB6Tsѷ+j3nTd7iÛ=)tHWk. }Guv[շRjz{g=mF8iOki^+G\z맀o=˲'܃mjm,^o|Ưak`څZ>\'kR\[%<[as.\d!,`UKoa3MlP|T3̜3g!yk6竾: 9PqtQ>õ9\[7 E5'M/;! >=z.zʣ830p[15q{@ՁNPԱ) D'G&'A*nx9O\~x[qŁ[寡{l~<>)=՞\m<+h=G L~&I`aFHrƾgMI/l9fzw765\KFK/˙ș">3]`\lRs2*E[ Z ZUҏR\؜{3߅ KЦ^S0iBܘLL1c M+A:1i)+[ru4wҜex ϊ7Ks.S:j3ҽ[p/Yi= $ԯ.g)6xCar q5Puo\'fmM<^dm c]*^&*`YjN[@\%EHh0-jhA ;%ZT Aּڲ{Wyx.+N a}^\s>|ҺVX1;2֝!r"hR\Z㣌f5ZI"6M;{(SUҢi< l`ikegcW&!9WEX''w#w2- .~ڻruB%$(#ο0=ff3LiG,@iPWoWZ?yYi;? 2y|b9^ v5ڀ,zױTjg~TtCti!ۜ⚆t>aӡ)Oͪ:cq.c6< +_;6zj>>+d1ޅԃZFo3+dEX~K`4JUp,zs3a29xykH@^ZM4ki*͌ lj;:wӞ}#ݒ yH=7;Z*^޹U 8|d(̏vn'_ժS:2$I'~3dXƐҬȋv>iIMЉ0G_77s\ƴ8=+ כkj+k:#e\F9F5 XpM+\7.4[ջ t#J=Y>!5]> p,emk\y\xZBoK&jY;9=)i kɨ{\X~1(= ,Kj塾m'r<{cb)rߤl'T{x 5_QVg8H"/Ȥ+&aelXl5:jç4z] /Ff^o`DžsܖyE1x2=P nBzT;q|v4OףmxOh8 BG#P .XH(]3x{1F>gۀHwWe֕*r&|B^wLY @T+e7%bњCQޖ<{&vAӵs)ʹӗ.Otp99 srJ+ҍh<;A$yCF"G])R/`jљ1*Z̟q`r) #w҇ Rjk=QOxd{oO옎1 (HQ |JK$O}16EoW`@_5)9i(-Q k~]R"3]T;7~&b@ܽX$sۃ)qMQ-\۫ݹIfCm{sO};H 7n<5>TMMV}1R)*$Xr9aIьy" [$ Yƀxb#ɺ81m ~^iUxbIx.L7$eFoKБTJy$2JEP쵬^1!"pXnI.h\u. mH޹MF$Hcek&ܳq -rޓԮ'DJ(~*7Fc=VII 1L$|ik} ږew$NC7=ԗC~ m{d*в# !BlC0018w/+쪩V5# -ȎH^qāX8,Wd pt׬b^8'!Pc] x= P5D_I.'$WyMn5Q4~\LmUVx鞍m3 ʄC4XyNxl28=7yM+溮v.ⸯyA;{JYzIV6y(l]oޗTNc\]Ѿvu4811Go,!kC@~Cv?cw5W([-KD4PrΎ\/k#!ůi!u^o)+O^ ҁ~Ua>BHX\lO&pi6/yWeߩ~qxfe@"pUjVH朗HdbҀob: QFT-pImJt]h apB UIU"< 9L(̉ǔ̧);n懁H+b͛"ܸS/rc' 7DD5|!eU.Rwֈym>Kn8d;ZkFtj<)*s|sqۉ&?!!$܆߮^̸NJMqػX'g0\ ]_xwoGXqmx!C l5+S :絤. zIBLwsYpMmkZƈ$X$u5QO°;6MT{0!j&tg=,.LMg4;#'cJ,O 4p. R+.{_͇tl7BcLY *!?}Tt^t, 6ɱFҠls3(5Tstv_Mp&tsݷv뱪|* VcZwA#Khmw4`= 1BᇊAW$cһvۥW9w;?px:rs'ʕdS>g1IZ 0PT|Eٹ&n-͋d &(4y.%xk5:ծG^f嵷/*~'`cDQ(C^ߟ33q fp6;k< HCj| lN)qEF,s4 &pN\ZX47hJuA?Ț$(C$$ FꦄŪ'5+IF c{Z Z-Yܰ/S% hcY"B51+$1s7 $q>w.Mď3^VJ\RTO>O-N6CY =-}uR*hZHפs79]m$k,qU1#\HCY*ZQZR\oC"81T8qPk+R>j-ޞj/qAz{のo Z`,ac.y[ާr-\_6 h 9q6~;q'`"|R7\Og}>uO}N1P('ɞ1h2Zۉ uܧLMgLPW]umtJ]_z_-h3ċ UFxr䟝Xq"|>U vp,\m'jWYOpw]lû<^޿c@ߣQ vt)15Ws s}9Ks u CBq|h!5N 1P𦘮CR)n59gPZHbkw 5д1& l~PbbA dQthjYh*W6Qz5tG78: up_uw/.|RĺdU\4ؑ_^OP+pu_}mu<. }LCRwZ n#Wh^P1 IKc@wt)dCQ׭([@Cn/ӵ&4^1ITTWo3ix}Er/tZ f}gQL(Y&0@>ޘmн$7u0\=F{Z1?rw/ϽMMxG簂z5BiV1[4 - &As֖$\xAsZ\TFEÇT}Ֆbo9Y.Rzua)TpB>$ w9ҊމPR8!Fƀ%;-*,zOcnKJq)8 ~OP:ַ_SHD cCbp~/XeM g8'Mąc۸75?PF2\wG4bgfy[b-SkܞjeeZ:~={v+1x]3\vZ8mY Mbk}fS7 Aa5Gx=C+]'˃ka՝%49]fba&<h uՇ|ԴQvVԼY6C;H>,t"|݈lbc6i2 (ppI.CnSrmw$x~!Z0|3 9aӗ\0-iD֮6lx kqqĆO^6I8^-#J'bU Wi6^oWJ}3㕎kWBmJJE+*w bW.L!5 ht .&F:7<]-ڱ! -9h@p֘J彈@=E%/{'γs.1~5rw7lx,ЀwJ4/V]˯o{ \ [0rrz0J6m}500X}/^j `ZzHt RdF~3dh,xMZdJ)˞<6%|r18M~Uo:d/>y۳/=\W~#8fF#ϝPHsuc踨_9[uELO,T +W>ڼLZtd^q,BG1w4 siWkFr \ o Ha:-E\yVXfx7~d !;k3|U_gr~#͠IJ Ɠ-VXp$.5ch׍ZbH:$ |8XCbvP_#og:*8]x}7szjHu߭ UҥO-,ljiKu]4j#)NZ-)3JݘÞGs,|P|xd< },mQ~I^_ee|PrkE$~MrCL}W{sN޷k(3_ =EnլYu L1FfsSQk=!Oo?ǷnPJk>z3 cC+Ad`3H3f||ma,nmkpjP&=Ly J#t%2HÂ![Ys=ON(rNvVLm\_dcB#"itm1?i#6y.LE!c; kMսe.dJF˚Wʊ@QGJL8a dn UD?2bn4J6pUa"±q5V%>LnṮzXrkpƽ}O{흲J>iXOr| 3IBD鍺6,BtQ}/zZ>>VFZ b\9f?vok[3ipcv̔s|,|MJ֤AldWi( :/Я/Vx:$Ӑ/KW]tFf ]>uHLNb;u@q}=ѿa;KJViV- C m !\.QsPhJ\|p23)[kZ#ZܖKmQ#)O}Ã8dgNр_b@;V^;呮gi jUa^&+#?Nr'oMF剝+6!f:`|m-w_лe5onL+rX=ЍQ44Q0-"?m:Kxk2džQv }{%yǵj<4Qu!Q-HtV(`(ToJYD>pDђ!7!k p51*BA%i 5Jmgb!3ʺB'K?߽k6B_Qϑ"J\F`GD)?CGod{-fXvn}$9'LN ۑmQ`J8  te32.>=HHq!s_ P2at&7s7 )# 'vr~ JjUo&78 <: &ZHEʘ9j>)OC߹gySUi֘m~;kx!ӨH֘oZ{qo?ǘݶA/۶ҹ*;eS :cENor;dOLj8yأvwX6}NsS/%irGPYi3IA?0ָ$]=bj6ړ9Yr_/`_\щ /rL~P61CR䈲Orpd13[# KP!t`syC7U]Vk-7,^eJױRcr1i qdtʔq}PCk mY7`;45dμ Qaw_Rp2Ғ8ssH J\&& g .3&K B@#Uo&D3R?G1e%7]ho?syH>VͤGͣ3S|GB6Ӏn,mZ{MJ]tW'*˄Vuq~[b \p E3z݄ͦ3go7SrY{y/C{:WbgBjzu f@\_4.}n[ے8bW8Avq c׼ogxc1t'(R;$i}7.uX v^P19%fӨpVj)OTy|/13b-9P!?•*crX#o A$5f ԓ &f:>'"n5@@s|e}E~䑇f@NU3$y!TT%lx|~7~0>$2^8TXj9speŖx#\Q0Q*f/QBCNX? 1t85E QW5Ed`zvk=;$Ooq -Aҽ]DU{ǑQs28LqYI^KKԚ,"1ŗP $!fȒJCcSRFɏaQaڮ,LvT l,5`.'5ٜD߇h_QFu+;az:fnNԵ[tC=~ g1Wi \SlZ[=͍|D+4ܮ~4# 80- ƢO #}1l|80\ixl|I'wI4_#%q{{Wt->o-ĝVR=|kLhE@]lM(eYq[塁gov؛wnw+MJ5z}.[^O?o1c7>87w _+v0Ϥܫ4\4 }HKD'k#X?pc?"L(?$D6Uk '^ͧHoMtF;-0~K{ݙ͟2F_-?+b_g*k6K[x鶩}j{F5؎V}1u9 b8?cC ɱZ %g(幩#nV>,N  %-[mm)JN,Wcdg>i_EoQ $ɵh kW#8&~y;Ƅ?PH/urvS3O6m/hDK^XdKv;ޖs-J\|& fTB[R`5{9HC}lh}Wʌp7F6.7cG|;O)P6Qeʶ /5-ƝjׂGE񮪜6Җqv*88ƍإZ*ҹw}WQtv4LgBaD }Ԋ(W{;NWKHb~S"kX7}[5Os91x6X_-'32#$ F!i>ztRN]O7koWD,\9\q:8MzڏQ)FW󪨚"LW&&d{<vnM4"H/c<dF@:89o47k|cu׏}V.mIa^f.O2A \iBΔΝA:|yv8K*4SQ2b`@!3⭹L9L LJ𐵱Jٚ)*᥈W !G;Ăֵs߳m;ut80\q g3_yw/۟Iyqɥhd>fҁƐx bll2_ut%Zs#}ͳ{0,taiNAP0g5;W$3[2ݏc;\CCPД\iSW1KK zj+Iʜ#u0S2: TC`nK]&GW!0A>AazA:oy>$&9ѻ noWQ{vHܤMg E־d.[\ڀki2TSLGlbĤIv_ybѻ~?Z HՐlG:֛srOoUY9 <͐ 1ھոZ")\+AueʎSRD#@zh-".(dr앛F uzɚ"oqy?i_JVdo_م蚪Wq-PtC=cy؎<lG5]O;O򻽕ͫ[|~Y36۸nsF gLls a_Ô Qb)PT"VVgYR\JW! pH=JF"ƾg\_ܥaË!b@k"4uIqE$V+ 3xеr:h!i#̊WTG 1\Ie{ *>o[").@;;+T9D?8ۉ̏ ]vmC޼mIOk?שSw.~mMbdVw59zxW+do?@O9t'X{|YIs?gh2KvJM^CE ہd72}yK%=tuV'7)4x Y Iv/¾*.wmMj-ܓ0Ǽy>dx濎uA?R6MEks>_ʽz˵$>*q8hdlRINV"|8ک105#kDd31T%fUdePHPs41W5DpM" g)%J}/O>fcjۣIrh?hsp ̒3qtlkE{n?޾C}X*|x}uƑ_,ׁ×ʛ39` uE9 PC6)c6K3pG1C=mU8ȘK5<܎C.2 kl%gCBQaZW/M Br|&nT/-k {j2J)=>/'3 F!Z9bm%vV-7/ij%;;yO}OB}؜@$ǀwVr>E}&aon>׸.x`",+*DI(5CHLlv47CZ"Q'`W XhD s1ZҕB!v h$m *>?1V@KrLDZ,qn6<ܲB8pdLF Ɂ04'n_¾k{.op=Qu5s<ݱA4~-ﭟ??gV Y L MfPn8n۸{ kCGѿˏݑ뼏+Ҥ6|,c~%WZa{[͸R7sV,~WҾg?w#'w ȁ8.@u뾧 .%,q@OT+s@nj**YPT:\)becH|J4v噫ޙ4zw=kF7/ci61e^7"O{m>ko.y;> /-ϡqgMЪ=W4.)dtN֖+%ͤuQh= ՠ6HE |’,C9 j*nTi<%ɒt"d^\3Zf?Y/JљYUKJD_o%J?!b=F*$#k\t(|l~I37dL-{Յi+).dNB4pFHoZ+iXӹ ;)YvKϊ7{qhc+HD?m^yokk>|Ԑ¾5BcnҁD"m(Tz^#T AnC8o!Ny>ↇ$#uquȟwz}P{j T*\|d[0@=vl!ޫ 㴞47tb:P;)3%k6)ǥڋrlRho' !9rt|w* ĀtAFCT̾ #˄#ʹ: ,eA!CE+HL4@Z*H$X u Ts Q!0H(PIͪst}>{ +D|˼|G!NǛ8 Yj fxW%+7Yxw8R@AZTqbr/\KlfaG'5?UfX\P2⫙KO׳ٌU8W۲kGL^4Qeyd^dXpܞOrxг&\pN9 K˺pn[]̬\W"kT/r٣?vfQwZ8ÊXڳ 1mi_,rTާ.i11jDBz3)"Kc qQmkD䁼#Zo2hPZ{+BVeo6\BOtUȍl>$Ucu~C1@i5Dlu(E ͳD><$|P3w$%XI4NY3g|Mr8\=ǰ͐D^d>mK{tk;Q;+nX&&3蕏ԔɸQ)nzwo:{~|Ia@aHBa' ƍrL T*շ'Cq!y:ZYDcGL)JNud5΃M14444=ER!rB{Vw-G=U sKJPpz~ڊ 5M0cHs]Q$s1l vODcjy/%捅s Pu ]kŷyIG8qA|+t BcWNr6M 5* SlV1Ӱmn̆.Ǒ:i_Z1[-!;,j O!Nhg#<%`q氿V^wUon73蛴oXtWM?RExqHir§U8ӭ0 q,4^,#W ݊3kq6NFL)=<E?9)W1;,p33b2C(sBAGVre'̔؜5زUPʍѦ?OisEe5 ~SMQJ~d_ 0GZK!_@hTHc;h }h$]H:tO/}k\<[Q}gѿ˷3n#8jnRn ξ2GUn2[$2n@=Hڹ 8JnbzRX̖D +{AYn~%wXp-2!%<5B܎[\}c31fR P'J[aN*汀W:bE%ΙdG.\D+ԝ([Uoe0:#C8xv7]'MZkgH?5Ϣ=ݽScoݶkBi^gDȠ-h(5'c0(xٲD1Т 7]K+c!J:R36UN>?ZfIcdLrn*,DF ;y#tInU:?͔4m~*Jiaepޞ4ÛI:oJ.,g9fg2wݪ@K=kѧZvzu_j+_.f|_}ÆMoʹKbZ\KzM{yj)j)TtX*U*X"UCk&kIq EAb5uS)P%z6fl!_i4J"[2EE؈bڟyD0 NXKK@P֚dЯ+pȒ*3@MH #q2"Q5ҎpĠMȣM= r\ l@mjb$%[m#[&`8,+DrTA+ddYllzt*;dD_j8 s35p mjPP Yj S+6rX @l(&=5PEƚVreG$saϻv5{\3YGu;OXGdF8>2{'*rz{Ut~dr]ѳ#>YfK֭Í%}ǣFw/wgmϖ9wXxƵ5q7$R׭9aǸ+:PEpcd4TtYɻO7h%$0y/{v#HYN +pv\E=,!~oPo6P($R]kL%W㥫t̅tOT$UbHǭc&lh1j+)2,Jɲ8G#NTdL>ZE tjdWߘʪ'hP٢EPYZͱА1UD^H΅d ;kx3)W}{}䟆 Ɏ5X\ I$|nèk]\WwgaTÑ =C'#J7 i,QNR %d(iP:.EMvgp db%_[^\`͂A4oK) ^kTK5[xS1}LN3k[^RX3J$Lnw^ߥ|RuF\FMDzꝖdYcH p)f6YRI=&-s¸onyk¶Ȅ̛ C)|I|[Ke~*:NZ54t¾41֨ }@={P:7֨@B*G~t/Vb]h8m_hD%~@]{&=;K|P7zq&}g" jL5ҽ'إqx4lq|puPr8 pXo`p(>WQ2p&ya[*OaD]簴U^›br<~&$md7={)6" IȆp| =#M^CץIocdt ^±* x_npΚ\?/ytn5T5tQ1^E-季%9Kl2N>qtq_a۱C>/w7S<Xt8eA-&6B !Da(SJ48kMC( HM (CŽi/ -+H)aL͏ĔSHHl{ k D,,{C s1VL$-4* 8lz; w0ClƭIWU|I<6Amh AAcT1wD11:uj"Pt!$  g#XK`RCPh 5ӯƙ,z^P3) GjdȀd , hddrڵC/㵠5$oMRI(fv *$+Ҵ!kWT feZ !CN0/Bk4fj ύaWY9@$Vfr@&P+hW8:4Z6Vgtv[Z´b4h#QAC0H.9oeJF f  Vre m!:jL(Ō}mn)eۄ^}4ժW>!GM^O #u\Hf0m`ٲA QЋẗl!sŠ%mmbc2R:DQ5/Nýq3#׿PAp" iP*vSoT4*DQ3%L& s[H3)tJIZ:~FA.~>k T@5H1kXKVh؉tVUO(RFtEɕLI(ҵHŰPbEDy|j:V6l݈@DD,G)#`-Iw#V& ڴ!S®4Z22q<6RGp˜إwSۿMw>(m~.g{+׺_N3WmkHp[[WIc?s>kU40<%rv''DDGx?_yG czT2nGH"&vDԂ7lp/l $,@<"ۋ}+n]=W"NG -9p(Wzq ZF?$Rw' ^mys .pF:SWJ;s ]]zjY{KG> Y/.kJu-~зWeh}R42PnM# xU1Mۡ`z;kD1Z} C먹 oS@ )n//{׈kB8 kG[L㉉ݩj-:WźQMbVdV>]*8t̐<{TQ[åƹ\:MEIBdV6Ӯh2q*b2k}L`2X%!7DFW/EW1B۔|ߺ2F?…|H _d!]J嫓zmxۻ{tX]g#,C>i Z:_Wj-GD9jⴀt׽S`",m!SAKQI1:x|h inRsaЊdGJAthI^=mRP\:&AdЍj%$4ֱfM&5ZXxHI 2g +q6.q$sIXX \ ɚt-);P8(Ej* 6ýZd4+nZC!Jv $RHkgCJ2j:S'JR쪡5( +6VLC%Z!\u5H.eܭA\Feoh#CVMsSiP!8(R$g"!W] 뉃 >pّn>bT":?k46dCӡ+<(ZřI RGQֵ2lD LQkd̚"L1Oc/뷐.vk1O#G!P ^2HXeuOFAͷVL -bYɚEc pzijʱ52Gr)|kf̒%Ǐk:l FzBrn߭bP9ތr|Z^!PkH?RP ۷[ ew7)lH;Hn!߹mos#8h_IkGR:m*UB6@K@Xt|)426"LzF\uAIf;lNHH)UJH`wԍ+FPOsȺبEhl<<6!G^Qe.d-~]0Fe\.[M [$b.vKWF#w<:V,c(h_!6Aڕԯh]\WjedTz֨Ͳ}I@,kddGv;ʌû=Zh܋b8Qt 'ͽ{܁]ox`%mTt@v)KQIl`!(zd{_R$G#+.=KHwH@W)YTƴkoV?ZxDUij*TJaSDߙAslpj6_[_Ye|G̡|B_© vL` mOZXuNLhH@/ߧƐ"h*B8t*t֘N [wZoy}gPW؜Lm#k0\B,H]FɈ<{ iǸcʼnA%r EUAx,h?BusN_ҡ@@Uj`:(.d-Bk<t<ɟi9nkf8йwy޽Ѫ=?ǝukr0a.qY.8&hXw b]QБU #=@+BQTEJ?k؝)"@LqnT5-I$HR(TNIB<=z!]*% :frC? {|FC'c@Eg,+h/1c;c\FǸ(lbu MLkZD"vZ͕dBTkRMM׵ /ǭ $9hp = #:AJ@$j|,i9l+GdLU@0,@ ڮH6Ptn+h.b. [kXj<9vl3*"G4%k]6̤eWȵ?v@)7v 0'Q\M(t*(,ΘH#K d̤ R[#3HKE]lDs"qr!9|GEOiZWVѽ1>2!!9Яk3D,y-ע5H6CAI}V Ci&6Oܦ:=fZw4ȅCwyؚ%J :ߘZ{἖fތ'|@K~|9&xL@|4)@ u(ıA0; BS3 .=h֓W1xTiv_)AؚGẇϧ8RANK'Ck]}.&D0an<|nq۴˴)֜cN'+![4 oa:Jh9vr.rA! x7QY;.~CtLv5*/ XwxIݚZCu{&h'6Czv-?ȵ{ooIߡwv?K*1Ɔ(`EQ,|**U o*OҨ?rڍ ?BގOSF* ~HyN55HL%_S$Cڋ֤{L=T}Kczh][DEn[5L70;DLdi2J5eZN$#H6'PI &$DcD{j,ޡ:jW,Ƿp?uhH0#h=HZ.?] qܭ]ER :ުPoc\ _QBlNUl|@sv4pWdUC9l:|V3LJr&eY ) ұh0͕CEJ%<~ [37Ew@+"=5e@RXEśn5+:p%QS&P˨ꭓ2,?rVf-dnA̤' `;>/3hd' GXmOЇnQVrbžctXɚ$oӭe#DE %( bMi",(!O_k2rM 7HHuVȝS` uE2:o1ZLU¦c48o/ ikgBe:5'iҡڒC` cKE@Hș BQf{? |o󮨣 2$$)VAyƀ/yF;65Q㠤HD%-e6j #iyh8HU-V KT c\U2Qm*: ~AF6}ꆕF^~Zqds\1&ڡx(ЇQ^7[#Ү'┧qz&,#zsc9{׍qg\ۨLqg>*%װ8!i%Lj;)zogIHfsOe(GT|9,[C:qh4=]'FlGߜhlˉ n#~eZF[7bo  ]R˭}O@ۧSM -SQU~ֵ1:"+@ùNO8X"/^Av}!r QQ?{q')}>I*S>v?f n+5G?0۽Ď4T稱c{_t UX6Sݼ d˙ q1i^ [,j,aĔs< =73x#CDHW-:a\_<קvU@=đk”Ed٢DitSPh ?I<(J<( S.H&M0FHEdBMV`$+MGʨ 15:HhHdYd'E&y^ 5!GV3P؝ʵekzW\Fe2KH$S&,8 Y;ޡ:w*I!6Bs @ְ&F$Sw[8 jJ,xH~UhqNqbtBw ly;߫%tNդYDw?x ,H Ou*ʛ̨ ƀ'biT6DӡZCMuNՋf $YH=6 ^¢HA*ԒЀ#D"CkP_(I.6C(*Ҫ &C~5Q-%CZ4MH/E4$.GG[Z@ML_;t[̙;htj.%e+thkPx.Դ:s ~ Dz44LcMiL9wjERR+RTD0.$\\Q1qv&ftD@Zu띣j<,E7H]@!V@Л5"g&P.2aak>"_63x2H: N zdJT +iKd)ۨD|mc!4M>ME´5RD.׿D81OTY:YSPL!}7*v/lf0#S5>YEen4\Uһ.Pz{czC2A2;F}\w2t:6vMʺpScg*4CBxyqCr5o}mҔ7 x$jǹ軀 Z*: ! R+Kuۀ1 ﴓE&ҋ!{y-sKvO ^3f kI !U+_6BI[x%R"A%~B!l 4KUۡLG/[|Vakt{(/)oR!o1cl aoBRּwFOz="ۖ=Aeq- vCX~3F#TԳ^wȟ6$I19F a6%ۧj.lRUὭ '"&\-&C iӺEr+! 4Ƣh29UGX4lh2,&K37¢TfaХZLks"@jJ e(fѭHlm˥q\XdI{> wUHGzUAIiX84JA/3me-EdRDЋVM>Ph:p`4OLXV'm Q))*#E !I!ݪصI eTRD6A2.C[AIq ~4*A\z%[i iK%n+Td)6ĠӵLQ&P?ʅTS'AU \)֩T}2+X+c$ZЂf(WYHHp@z°f dW5T RJP`Eu҄"MCVVeNJkCeiy/@iC:c'qJ kD<Q:8 VmgD t$ B44B|Y;2"{ʁ8F<]ZqWTMU<qz9!_x:8r&g?>Cwv1⻹<>~qWkx )Oz,cԭݽ\VX" "nIFg^'6,qOګ?es3십~|u'Q4kkU!p(V4L[iKk(W}) 3BƐjS^C^@4 P#տ __;侒 Xp9,>Mkq^HkO}=7Os8_qq>V(c<٠6Mz*Y#TKEzօJ-a)ZF$ɕR0IMTV&U bSS֭!THFzAhF*jţdpXޥlRڂݻIE ,KOEv!yA[{լQdBnZPL_[(h%@ҹkd`%(լhրͣO:"w::Rd69h|nt=h%S_/~KNLv0;1GD$Cu;Ww-ߢ^mcu+xK(<1PTf ǯ)B}+rv2G]I;I|WY3_`[cI:ijsm@`>Hu"pW z OE^1.Bw`%y =|h(*C $()~APf K#N?‹ܼ ;o̔%DMi ;X=fn+q ~z _Kz& aM!6DW)Uf/[NUPUi"jTHWUHUjtZh4NFz4K{J/I$7?TɐeT"̘WB *f{@+XiM!l@u+}!/XMKe꽏EHM!EED V-tb}ZBIn*"0$)`O4L̍I H "԰fPpChif:ӭCCd -BF5qF?*ʨ%'N_V*rcҭD%lT W5[#:w'U*: H:=nAiWj{2Kqa"Sk.hIdSmN7', u!i%~+Rj2'(bE7tSYL%SbXW= lx oe.@fI[OA $n?]hf!H\ &إGlhH2OtVm&%߷AzCt_ |Gr\,7ﭒ1!O$o {~"*Al o|*$ STZ-S>5#dJcׯõ&Q> -Jɖ|fPX"_$,h$ڴDh%袵DW/ge>NR9q!ND!]N&)q^UԪW}Otq>oW#H'z,SOGjū)\DZos T e񼴿\Oxŕ37hC ZoCmyfi|ZY C@r >t1Ut|;S@9Pw1z4CkiXBt!+ҁ/:!\-%  _|9lMQ-cCw!>gW8ae⓬;rY" lk̗DC$c$`T^yRLQhLj~#CE {/N4G۩QE1ӻly\S F-'$'mIZVԹǚ"sKxNѓU+RKdG rd_m'ԏ0ٽӍʿ"N* rR9Ӛ7dicȁRZe&sH=;n&C5Z@D)Ǒ-,~yۖI4#̙!^;('OF@u'5r?B ԏ0NyxFO*=H"we60dIv@ "T^\d+u!h?]c^s.!>/<7 (d{  P.?g*~_h k<ĄϓeAStB4(hjH,'5'㲲!w$P- rC}#1-6ֹk;-K5̛V9ihek\KqYdǗZj,Nk>歿_jN̍Kf:9Q~;('_BDU.ۦCW#\Î3㲍Ⱦ=*}7ȯYW4 'Ko"vZ| KW^Zx'TCw 1q*y?Qd9c0H61#dKG#n!k;-44*摺&VzkNǭdƋw~5 sJn6| i bn<*& nԷíZ f7ԏլId\OHN'%\?Dд׷G4X8\ZRqu=_|?q],n7+KE&MZEvUH[۶P*8WA8ٜy5G܌@"Mp {NkAqCsPbt;a#UorcgxiN]6jnm''٧Yo2;!bC`UU/1q3>EnOZ~a>i'*ź!NLHV [zs(Gf.c|tfTJ|lJ|MCu:g{DŽߙNs8U:GPSҝct4R2Bb.Vg}'+1=%Y«Q.#oµN/>,M䂊 \߫PNh3a{d8c;$s!FS!B<_Zsdd+v5%,VɛGY貲%tX'OƦbT945 uǏa9Y!2caM͗neyG-pnK.2E L1HxўwXJ~PU5>syG ۏsdQGN?:8 Άxl38!@y\q҈X tR0fzypegk44n 49>`!340Ώьy$k*7kB ʝp;ω\m{}QkZ֐ .=ƞGb3=;/<AmK{*Q4O<89 '63 !6mLn5(eύo<7\p&Zn=fG64cd1 'K= ڑO[O;r11,xŮlfWWh4Zr4CxI (|̂9v S q 7'wE#2pC6tgB8ι\r?0qCC~>D<[<;ܾÞFKM$$lfKA-p) ${򖵙epy%{%:Q$yܬcӓfCC;('EjyOK3"O䢣ҍ98*r%y42d9swN6n$ onH깷PPk9T>^F+xyc%db`t{vPؼ=;Z!$sFdJXp[\Xy;@s=rf <;Q4*NSŊX׌ = n0+jMO?q8f1rlG+ŒC= 0Nbp/#3Bxhc/=/PR6mZw_;~QJRr~ƛZblN 5Yf{ ]M-'ƨqaX/;pie8Cb[WpIs@╤]RfiRrX幇?c,E#)V)\Gs/ 9146LN>!{+voz$mu0Y>2Ey2iۋMS%_tmflӭKEFO&?}W4"'G¥:2漌|\Ll,$H'873J{ffW/.4I䙸*\(^7'.W5c`aV^F9@KE]ke7$cpId&dnMTC FIٍLJ4wsb`Rm%&RQFYr2g'0 sD-ПUՐACƶ,pc;W97*2O jdQ!>sbkزĜ/\Gd%\l.~FX-T>PxD>atHDI]=,Zȓ:Z$IYܯZ)q.)J"Y uAx։D}@n Hs 8pZuzZ''+#&l;3sB+0bb6۫ŀqUS[vH )i֘<*cB4R򦟢q;Fۭ!轨Vt$F6ҿ :3;Lȿ0yg# wyfgT#VsXNr^҉~dG1{8SoU^=k,ziP'{x9#d-ջL^?ZǎҖ;RVnQ>{Tb`Z+cYݵv1t49RQeʗh46}5-qumz3ɘg;WviDYQaq8 -BHlv9ƣGj"눒k3avSkٰ1szYz9xywr̆#b'Hk%r^Z{ooIWKd\{5dV]RV4'a጗;˃19|mL)B2vcsDI3_+ZU4Z[-W1xyGyzC.j;s\[` A[lY&=GkKo &kycFDFbꖉpi]s#o5ZKSrk#,nhLs5bpw5AQXػ\]Pfl?tIq #$K "aloiVop+Kxu_n/|MѰ )TpZ$dq8\cLdч \eG| /!2l+'U5G}YY.eR"&i3},,tљ$QY-|kJatg/΂؞ݱֻp[oMDRwp6.,2(91Ǹ49qoQA{ؕ?SE4̈́$R/i@Y_ݤʆ%:9H@E _`FU@%ق?cLg\K$@5,t8 a$ cJ#IU/(:kXnzQoZxϻʾ/8RňFfݠ!?kOe_kSeBT~NI9qs^NAkZ_ {AxC9?Yr!a)WJ5?Yyvk%8sZ#BjUUfgv/ nR5"NG'*, "bciΣ~0-@4Dr7HJ J)Xǹxcv&ā]3#k{矴B {Zr&(c {kf۫Ɇ['\־Cm7j,_3 1i ˉ0=?teþ4;C{Y6`6i"i,bȗjϫWC۹Q߽?,`{$͋gE;d,nISZ'H#=v84W(|-$3$Z F4pn ʱleG&LRW|ǹֲx3 i9$͆G-lo<5 c^u\VKKk؜< |fx!"&vSsirJRڋbGC!sY&T9ŏ2B#hշ͛qy>ZnRxb$ ǁ[m SR\ TcR&g)]5 >QCYwC_],x1X?(:YKb 6 ڼz1N.ojZt۝''lGB64SzٿL6 %"ȱ#|z|q'PMl<qCd |ИKD|+jZzt׏iG+E#Z=OP콟[oPIY^9}1!9,s,.VuB!Qqkj ̭cj~bFfS.DN 6U\I=Q3y3msċ8r^\t'A W,o3)%-Y9xm Ă\QwRrH?(l'}-{$F@ |RvbTwV< 3?$ftPok=*H{U< {󬛈#!<|LG/hjSzJcYkurU]KgENFX Ƽ^2@ko)Gm\?nG1aO͈Y cqp/ZB[KsٖF ~v)XT4UmT=} \F8\#2lr!E<|u$ȋt]EdGIPtWAm!JM>%kDH?uU$&GՈ(И8H 4'EӢS ">fXTPFm"HK# ýqHa“$֥9P}%,%FJB :"GBm(OU c@wL+ZV@m ǥERC%ҕQΑn4ޕ Ls䢉Ȋ|xCƼ?vbCa͓?mq:kЉ\yC0Ck+5 :Y݄ Cmkԕ9G' 1dĵ.(;.F,SSڵb3s.c9kZS˼ptu,x'VHA(ׯ_Z,02n}hǚ7uZpuuOK|Qŏ.R/oQ H-ζy;i^qWn̉%DLI; j-]6u :h11~%7oX\KĩD 4UvȑQdzںƽ{̗y`uuºNqKB||>$iC6?2YO3lŃݴ O^Qo!ߓeff&h2 -ѶJ w=p[&pkydpqey .z=VޑQYJfXnZX#INxGwZ#ƉߝR56, ۹T_ :sOwGMԿҏ ooҽCƝzki!i&<{&f\ܿ-aC475k go*mptX\`cXNz{AakZ]o]L 3/|R}+̵Urƶ.'=]nNc! Kºʏ.j`u{Z6=|]I yWDDO?_qaƷ3vy1#NccfvI{7!GZ;8|GB'1$%8!'mEx>\x}(HG2d?kMbmqRzRFdIϔ;'\w:a;Y z9\!֢av[ô&C[Zݐ봂G*UZ;GjTn)19.5YIKY,%UX4kKѩ^KĈÏ+&sb <6ڊf3ۚ9ID BfN}I7f\jK[ sE͙҅zY_%w&,6\Z% [צﺼOM׸g$o2 Gҙxס X34tE/x80=<&dD@to(^idjٛ2l@dnivQ uFfWm("ㄋFmv3DATc5 *T=rSaIK[y"էә(JBw^"cBizHr|6D`Py>#2yy\,Տ9͍Ė+tsܒyxK …̚X;Y\>m}[yGdrrs&.5^\Fqm-u wp`e1-ă5Ƌk;OtaZ'tU#K!pBYZ,U*2B~ʤIw UCdwHMRB6Ȫ UATE_HxRL@\I8UP-PS"'ʁ6x^JrJ{GT괆5W[}D#D0Ҡ /%t: SJ#4uZt9 ֚DI \8ۯ“@KC%)mKR=SSB8e?mr D+ԥy[ƈbWmhuލVu% |D)!| F;z-snGҗ]uI|]~-|eC zESHs(.x@*mUa┺"$q!QI weJ8;fq č$88:ǽXS\.jjH#+#%LJ@sM׾-.WWmxvM0ъFc*5"V2}N-ڡ=<Y,mdo3G#Q] A&WL\\%Z AO:3Nᠵu*ynʒX!#\s">9`+o]Kq׆HS`i,pwJzd= ^_wyHĮӭ{B,EPN.**J|G'3Gf3RP߫T#c/iOpX~n{ CDWctGn:ߚ\kJזlk̴\^}GSJ6([EϷ휜X`dy9=KA}G*jkqP KT;_8=c+˥Ǎh.'zn+pֹ[#KvpEW uB2&_@+}Z[i^SKh^FLGc$l0:r4> ߊf[q0qFĸ>&rlߩ+K偔+;%*} |h%Sv4͘? cL-&i vML*Δ_?p޾>^;ZU ͽVTumt5onJl7 e\;h7R޳\RW>,˂s ]LW S /ѷvD~)!Z_qA̫d^nV=h/g':N%;W6v1^bc<_*Ykk_Y6Po3n-ֺ KrJ!qݽH p+-2,\(%ۆ  ݜՒȲ33 qI,('POʧB\׸Fw8 xCQW r( sּP(%nmj_{qJ,=$,abti*<'?-]#xs\MpoY+ɷY_imڙpW8Bu -bԾ'r?*Ɗh3#ȖA磏?w=sT(t=*r8['fV L|8w[}UmM3UftNv^6hIY#! T+J*TxC=ƞH 9.% t25^mG e+rKW[G dLAumMKfSv#jT@d84YZi B4uiB*҅*JhFE%դK"bP~ݪx9pǭ_t[x%) B:Ё@逍h .*mM)Ի1 ,w E &25#1wO P =h5^2>PxkSz[4CQ@&tRɬ- lғCD[T .C 3BBYji]iܙ49Aq'F]K#쒑|dΘN7F8] JT;6[ml$Dip wߢjX&];t6f=|Bv|+ҷu\Qv\T_?9#39< NlZR\J/J0[r_/`?\T,̌丱CFOHN+%~F>LD7lTPY <'۱e2faCk)@Oe)'Yrܿ|]75Pf \Jݺ# <"n=,}gyd9Hkuq+QZ#36R~HϺr1:oI+MDj~Wna{2_a}=7\UC[۷zF_.~[a@knuRRuH8]h{ lE5{ꥼqFw1G~lٽ\zݭX7ꛉ/Hʰ<(V !2;PIȲg!IkYݷ4* ).s^縬yrZ#ƆB(ЅnM+n]sÓ>ʽkSeD\CcYr19CƵz.r7%#,ۥj3ŕ^{&lH֔֫D3qCG8-e;ܨ;(4?Ơ!'7Kܣ;u qJi{o OH/x v'`:.:"M}5,"v*Mo56&76K+ fJWrFcERI8V+38"uZR䃻|t[kJ~zZ[vR5<Lds7>VE=3wiڌ17oGJ~g?yr39k|c؄Fsmaiutn)M\V]p{sYqq Uܠs,ê˔8Xw[ M@%Z1u|ajvmVE)˕aC%0nҡcok6CUŎq92EO]us%ϓ l~&!<#^OSZ~ƏFr9)ʤkKa~!fzVבﹸf.&s&C=VUwg.7z4Φ;|y,F28,dnto**g;؏>48i^8Y yX|áiֳ I&QEq|hY{v…4 kɵsѓRť_*{8/'Vf׵k}-P;PT85ٝ&y9c9\`BlkthqK.l^,t_GeR]/Jn\YR5O92Et:tZNK;%2.|.Y8YKAc1ZLፄ4u-Y*4D3q;n&FHo7HֵKY/r޺aHvRMF)[2 z8P=':+i,/x|wq{w:cUoM'Ϲ9N 4ec@يTQڮ}i15^ᥐW/Ѱky ]1VQ_.@fP1I&}:4u:zb[e'½ ] \D<<};MgqV,j5V&LlqwjVtop6=G+  KN]o varC~CjcZ'Ѷ}v^Gu=kh)\PD)PuTM!6GMץh@|H+E*1jDt[Hc @M [ /} o]t뭨h5$JbH=]LE~b  ,`  G_JCB=&0GZ@ Gyty hE<| .!ʥTc#ր 괨2t *zRDH:RbE-G4u$)Yi`o`c:>b9Cʶ63.wneXs Й G!I}.v. ɖpb|A*{RW)t'>Al\&\#G4iANWS&;j2e9c9aacH+8^Áse~:><~fr3 "jj*MͽˍU%Z}_S|YyJS$.i&xWmJ Ŀj I|+CqY pPWljm4z~?ɶ7eo h/wmUkl~:[D'](foW/2WR\1x9Be,;\d-@ MT%qFP˓(dw!5 ZVq9?DZqs{7㕆v 'ߋ+{9A ]fb}{WG{T㵸^ v4qFm檤$c~^dxC$xk+k4zihl}3e_1% i#"evnp D̴?̖ 99 {J+f jy4L__:m7ׂlmFЮtK%/eY.6sT|6Zq3{ui\akݼ'ʡ<ʓl[qk^^8 GmY]r#DpqO*o!OG7x^zn?Od1;7㰰"nD,h`k}ԵRMTî^JZk<0Liz,'7yu4W!/U.8n2Y[w %+Sp>卥kŽg&)ydO,N&vIcnjJkg!,;7!>+]hOJ2'`!?C[#&#koLLw]H~4FO}M4&_Wg*$T SksՎgnǨ\J/5̽Y3yB^>i1Ѣ]:pi%}uKlÇ@I\PwNW)dwHsYT#{A^ĺa|AֆCn +uLbsKԨB 2"?O“UB=OὌ]\G8NI7X ywS`}Lllj_YCawd"Mc3$Iu*A֦w/}=dnR0Yf_-8̑ZzS\MԩuGJ+!O <.NG4d2sX@.+73G^yrĵAqp2?^j? ޭ[\|\rk}R|q,DDyrr` 〼``R:Zq>rre0Ysp0ɻ.P.մ(u[Ḻ< p%us;FTeJ6Y{c#?<\_$Z时hU߬Wu-OK+>|^{KsLdЂkO³~0}keRީQ,Ge-;*itruZL:NqpjJ;+H5xcqNmJGD NSkS]W:*h-#!@҃9i#Ƙ^SBb5$@ۄ@ TԳD+?ZB9T:0XrzP3v Okp `$ ֘2~: E* LH,,pz ]V-4.#^ 搖hDEBuҘhmA"#a\):j0ߨYM|8\l[S;HWh_(*B {JHdqUeQ4'L%u ;GAAHqxƸ8 55ցkB褔@ (:@ q"W c=$Ѷ5+uΩO k@n.!c% ^[Tرpq :-&ZC;rԌ6n:b Ҁ>(k@E* t$ޚ,h֙ E6] @P07=O~>&^Ȕ/P!ЏƘ;DB j_SFATT!Q(7]V4EC E([v*"Ɛ^ƙ#H;(O @K *E Cn p5nn)2 utJh1TL+@3\aJE\+USgv2)q@I@u}cBAC@P0Ԇ/tP Mƺ!O:+Ԉ,LIEm)71A0h=4ȈZP6G~曩jw&&h*l~TgcZOkĉGXXƤXUD`Sh10aojdPr5t=AF dy||ihHŮQ,T"Rs J8T wLoHOaL̾JE!5tpF"h@ dIڝEAhhNxLcJ$As֑@Ct1\@-t_$ *-zd5u'ƑgX @:=. +Ҷ+jUŬ@؀b>T:ut$b:}!!ihF*Z􆀾3(kL4GSo Z40P} !j1F!p}"R:U""zu=1H pGo KI/^HE9 Y櫺|* H{o  sB hVo@o~"T @CmujQcөJb/@=NM1% EVL8)1' iq sM0 #TFܖ{4 ԇi+};(|R E4@@rt`@0nsD&4*m@%Hѣ!@|0 W)tHd A@4:Cd]<ʊGH;nij  *R^,2ȅ<:P4 h+đUfCڙ Y"Ht7 ?UI bu@vNZE{CtS%WKCvNԐ k~0sڦ9BVĉ0}Nrh zC`\L6RJC078SO[(F\{@τ[fPVJ" EBB4Dn-?J]hx*aIx4MhF1@_IOdxrGr4Q@V'uK ZDwjFF\)T4F.Ж @ [j:L4u2SLLIAwCMԅA[PiE$^-KHTb6P:vft;Qi :E0nkB,~G-zPe!,OkG-YM!ԱfE>e:T h{S)p"O d JkH !-.6F CCc |mH|(({u j JABF[HcCrO DƁ1\Geb5p@|>t)nS! =}&PԚ"3KFD1Tj$Xl[lHwi׽ahMړҡ$ɂ2_)ł?VLhsH(1Mʁq[~@\ hu Н(Ch'vSH]^) ZIcQǵ1ݨ:贆6脐jZxP!%zI*tLh)f؎ [cv oo! t S@cȺwPiڀ\T(0@ sb@Jb W ^ӧƐ´{"! @Tr/ Jn:()!N61hNޙ,dmihMP # #O0a!)2!z e$:WeǴ@@]5%k7e֐lqi!R@ҘZdd_J1phth ,Må8HdN."I; s>v~GS$z1_#:h;F!`xbTC&l 4Ӎ D j|iKMR@:xY(cDdyoU4&DNU#Jd$ Zd2siԳD~3ýsq@|:ΠU-RCqG FJ|1eSKRf ЋBc׸*-xz)Chq%h,&⦈Ѝ4nwNZ4cTTRaZ؆BM#AȷLM]֯f=F'BPfP t=+R)0KǯHlCATHҨ/so;S4 !7A.KIOS4-54 fIs =~ĠhV%ktZ]ɥQ3#k@m. i`#Ҁ`5B[€@I:* !G€CjGe[]iǢJ iTF ^^ RE0J1OmMl۹c^d24[ \ @p.${'A7`4_CLCeܗ K5-7Zc[JOhjEtivomoM @7LcsAA>4%G7 Ȗo(){H75ucJi1 EzC;҆Q(Fe<}@) 1 !ihPjLHduRXX6S1R.k%?mԲA# p@wC^׸| M7OL@ T((;& pZdԃJdOHKvE%.)Cm<*M3) 1;JtU |^}<6.$:|(P Ck]MY'pl<V?mΣHh7UN:~@omˎG2X:[^$9@Psˀ_(_1y:`mhwծ@?@-7i_ROh!V@?}2Njt7N 4z1:;_n~d{ !Κ%w'&8v@>dwi49:H^DbGJ#X2v4`AMM(|) $nz"#9h$YvdP]\ڂ40AΠƁTY1I,Pj@B}E z&U1@  * Z"1E(W(Uת@U> @aX'ΑHk:?qf+YV6#\t)zCEJpn)C wa_dt hHk:I  #EE]m:vN44 :ҙ,Ḑ C8nPF6 Kd4|E"Э'${|i &#H 9 |鉅c߷aYi# 'O hLsdk!yjES)B ^ߧƐ\BAM>u]u)1Й4!HAd+-!P~/ #*!Ӧ vZ2'vT;c&eBH*~G<6 u3ln&M(蘒}րg1-")c~mHa鰀.n.B= **CLw'Sօ!;`rHͪkÞ^qD6 h Zd[PcBP2dQU">WmK n\)sd hA@-P EWptҁZOjYha`  Pu,M>c;A6V AOSqS@,iBKAkQIb mp 1JE!dAC@0AUO e/ʀB@0~4`-oJzR(VyvKLxM|iQ񢪧E|EG9څUMhh ZCAdzDI_Rl4l oLC Rn t`W>Er\ !SdtjM1 @];P!:|( Z,5J 29Hbʀb(A]3WMM&7>B9@%A 5U![plu:ҁPGZLj+‚"@%L6&zYi ~W%zC#K".[M120vlz_ZHRD’O:!d: (C`\H/L;ԓᨦIbO^ћ9˜ RG@mڐ} Vp>w 7zޙ,lrF!j/o H#95S# nhPnMQ#]ҪX DyCu"b4祵H,} ֓)lBw@s榈Lj%tZ$9@؂.HGJzA["Oݠ֝P_׏SP5Mh<T/tPcCa[1T(>X 9M2ZDZ6i [6q${S; Ȁ(60\4 GU",N]QjY>={*,."BA)U@R8n0=hG9v{\~  Ԃ,1½RY#%ۀDJ`E(w'4Jd6)!= t:4= u61E d|TI-SRPړF~2YikJdx>@ѩPl5s2X%9aHb/)u!_׭ @:R &.@7Ē€9"Ǧ@0jwXN dh*"qiK(/P|)U['0'hxuP)4HT.Rdրl wPOcL~sH Qc+AIrXDp(A!e,z4Na?vU*:2X0M/@p_21U(|(DeNp%-m0@7ց1.Iu0wu"f-c>tHh3rJi=hFs{tDGj5 V8-Y РG+Kܥ ƃ彈:(ǕcT,8FTN%a IUL.68}l@yzu0#o:SHL Wޔ@m{SDhOSruCƴ@"A.a]M Y?=4 <Ѕ;TT{SKNn F@jFIAe+I0ᄥ*,]d|h bu_H@B;X (='RlZ[$A sv(-FWzuIh~>5JD M_PIa@:8 .s-}j\hQ Qz(_QOҷ!f*R@1 mN ׁ"iOs\H/Rqb=)84hBsě%Z0K'ʁ3#TEi [TT4k ܇S3G]i2$tSu@xܞR4 ,-jԆ1 R7"#gm[֠Nn#J GCL P AӷO2FpХ ͸PMSQ@o⨟* *)HD6ױaڧz=v"@QLm[} kH^@soqK&kiށ{F@ k #A# ݫStJ~49 i{ޤ4Ӣ"<ipp |h𴸷4|Q K{@u ؝($t$ߡ1[߱!ŠuT( )D ,akI?P}ԊH!$,k#H%tsEͯ@C`+ л$l u>4X|gQ:%R,iXҐpf+hG4G+js\wܧR;Um)XR P1'k=) 2R+"iP CԵ{" nBxPvȎz+HQ߳P1: !5p>0?Mi (T6>7ҁ0K@u|oHhy{==-09 m '& #:|ސTHC?em8Oj̠{uP p *9>R@C)Қ A.sޤ~ {P1@|8k֘1vP+p,! ZztpZ4&CT=LJjdb t0$5tN񽮸* kUS_@| ^RҝP 7UaKK7\GPdƦP)6RC6O_ӥb\߷ꔨ-À7_y%ݺj( l5Mh he d:z@EK$;CGP +n 려P@2;$eP}(ΔGn!0e? b"H6K`B }C-:~b2ߨ1@6ýLCNHGm7AЧz9h M(dRMhDQA@R1,n7cz[ק@I@OLB?Une@>]iP>+ZlH;Bˡ4NƐƀMnh@1$AS@rޙ58>ɡMz*SBu64m춦HX!RhT j@#@ u趠`roS1lkڀՕHzH!RWpݻS5!Dq8Ii sGS^ rҺtryPL&:ʩ@%u2;۪XGJIH cL~>:ߒS:Ygh:&R2XV9M(k]F bL.;l540CwP(^;˶-2XbHH<(րfK7M;Sy8Cߎw:0F| : 3,^T?~#[OƠIcFJ}-Kuߋ: v0̉6 G>E.=t_Q[ު:?e87ցV/Mi׽ZA'R.⁈wtK;R, 1$+nAƀnb!FktLAnSkҐ I|6;_ZCpvܤGLG4@P.=i hHi6ƀ+Z*Ip]M~s_ (/j k_HpZb48;xPkUN {])3b{Gt$X_igoq@#ۺDnxb6A$25wҐc6å678{(_W@  %Nӽ1yAE@ڇNT'e Qu41J  t u^ uրCO~ЂBN*R +IҐ9r*b;*W}(I/PzS%2*tDI ښXq:ӓ %삤D ~ SAjZ@Aҁi O"LN { * L{%M0c @@iU@ 'ށi~sJ(Dsc|rI?eu*(O a>_*X4B2Ep4P'Kӭ9]"\m)yڋt*#Cå*0e TSL(Wy*Iڛ#79P[fťt#NiI @k|Pu BuA7 HhyPGpai?ů蔊]~|(`LDCBF%,E+kdЊC`KZL4$;M)P.Ƙ+6:FWҁG@uޘh"Xu4g+>l%?h(!i%@'ƀU>"9,(փ*o!oK/nԆ+cݠPm4K+ @ú™, 㧅1kP C /@-]v4 G$ހ㸞蝩0WC@|M":vyMaHʷk@&,|Pޘl.>WR~~! 3NJ\@ȁix=Hg G@Ƒ<) JG^ h .$(P~#z95:-@IRT˃$`A|(eDqrݶ) kk(7[=mEbĪQt )Bn4ИXwKꝨ_FӪ$6L݄S'4XydrAn:P zk%qPP'A{ijCAZ1t Pz'1 uh|*F)aUi0q=!> aLKPt65kQA)Pv+{ hP׾e[ wOC$=/C@v;̏KG$1!m> YuJ#ޣ@. s\ OUE RSR ￯Ƙ"|($PET Li1:ӨOAh ;@tR@ 7B֠E7@wI$t=9|ք)tܦ(DfȖ::# -9e>#!$5jbr~iMuK$4קjLqnVHjNc[*) ~_ dʃoCC%olFE6HHj/41ZTґDyNE2A:{_ìҝBCcڃeW7m[R? =TShzx@n/PPxd!,) sm>u@67ځPn¶ $^}4H8~T`oTCHۭ/UCwP \*xӠ u1]P!B'b=?K08<h  :N@J|) R/C@u*z'kJ8!Qo !P<ͻN5K"X )u u@GoLZށ-[P!cB|(GD:_f7 )0sK/H`nB2Y \)}Lp@_!@/Ha] +tE :t 9 k%A?A@lgTQePvB#qӯzbO!׿A@:Q ?uiz6XxRmå;U.(juPlF#/pT hoEX(,M$}4N, GLkP4?eHbeN& [|#]'k~P+hSt ۟:hGJn:55@ knTw ;G1ހ;)3Ti{$2ڒHCRQ PHq(z|s\74jJѵ)?P_Eˑgq& `HăC0)Czld" GN5q6)뀠(IQ@xՃq?tpӥ %%])R(\9b Ϝ&6ꩯAq@(!h.1qMRE!z-Poh]~" +eZ|JdkOE!EB Jpy..7(-Z[(9$xvN`s,AzC.KZD(c+t“'E{u($(M4+N Qǵ n0(uhD:B饩 #zǢ D)e nKjs0iAHrMƩ4BF-08cF^'@T>X' 3 AКE!uExP֗nWB9w LL~KZlZu1zP9p e€8 >@ oxԒR/Wm[4XP"+K|zP& 5ƙ#~=N׷@_9,zSvP̄|P>swKP($ҁ0@:`@;w~5րc\`@wRJw?,@j>43T*)C@O}5 p(6O@W 5!tFS"Cr5b];8"h&@Di!4T*{P8AKؔg~{F5ץG7bdgMM2t@Vi -PPA>a~@&'Ce: IGC@!]%#J˨@% 9I@h&`;'OCmA;@0$$iOU,$ѶLr\ȊYǷZdƁs_ n-@ `t4+(7"/1զh 6=:i֙,p:@UN Hd>3C) l*{bKOL47(Djhcl@PssBx S:X@48kZC >klO9qp=lLCni Vc\M@ \r%vPo0U#܇q'>4=ʊF t-D*CH ]@z|;Dr"ƀWցu@ܽ@1 bdR:'2D%j#B!?r#JC6 =&ݾC54@rӭ4&/snh`` oKށjDm\R>g )ׯz`F{G]N K"P&4]u/LHroqڀK0)NƐ5pj:"ݥj>+MPD!=4}$/}h7 cH {a$5'1k!PӮHcSE]L=?ObƘ8#4Nl m,t:xF{HcJ΁hý05ttAY])@g|hGt~szO€>HE ~t uM>tW. dCӾ`G_+tAB])-Ӧ|%Gïʀ_-i:G4a#) n4W˜A@?tҀ5@ƟENe!G~f_H4C'~?RQ_7_>4cFfqhN|hL_H$I_PP'ud#p_&7~?RJ!Z@tZhM ϡkI~##~t t >T zP[=j?U ?4ZCG;:|eWL xN3'CMh#?OY?Ҁ>u1B,{RDvte?oƁӦ0:ckƀN ~Wk@Ss?$:~ߕ1gOߍ8j?CCt:PA)^@3>hL??m&?@nz~@#>i>]?sր!:So]:PKHtS1ƔYj(|z2FZ=5@7J >Tw4B;^@ >ZwQ,Zb4g~LvLtAǥ14׮C:=] t@5NX>~1eureka-editor-eureka-2.0.2/misc/manage2.fl000066400000000000000000000042151464327712600203330ustar00rootroot00000000000000# data file for the Fltk User Interface Designer (fluid) version 1.0300 header_name {.h} code_name {.cxx} widget_class UI_ProjectInfo { label {PROJECT SETUP} callback load_res_callback open xywh {176 215 400 375} type Double visible } { Fl_Choice iwad_name { label {IWAD (Game) file: } callback iwad_callback open xywh {145 25 120 25} down_box BORDER_BOX } {} Fl_Choice port_name { label {Port (Engine) :} callback port_callback open xywh {145 60 120 25} down_box BORDER_BOX } {} Fl_Button {} { label Browse callback browse_callback xywh {285 25 100 25} } Fl_Group {} {open xywh {0 110 410 190} } { Fl_Box {} { label {Resource Wads:} xywh {15 110 185 35} align 20 } Fl_Output {res[0]} { label {1. } xywh {55 145 205 25} } Fl_Output {res[1]} { label {2. } xywh {55 180 205 25} } Fl_Output {res[2]} { label {3. } xywh {55 215 205 25} } Fl_Output {res[3]} { label {4. } xywh {55 250 205 25} } Fl_Button {} { label x callback kill_callback xywh {270 145 30 25} labelsize 20 } Fl_Button {} { label x callback kill_callback xywh {270 180 30 25} labelsize 20 } Fl_Button {} { label x callback kill_callback xywh {270 215 30 25} labelsize 20 } Fl_Button {} { label x callback kill_callback xywh {270 250 30 25} labelsize 20 } Fl_Button {} { label Load callback load_callback xywh {315 145 75 25} } Fl_Button {} { label Load callback load_callback xywh {315 180 75 25} } Fl_Button {} { label Load callback load_callback xywh {315 215 75 25} } Fl_Button {} { label Load callback load_callback xywh {315 250 75 25} } } Fl_Group {} {open xywh {0 315 400 60} box FLAT_BOX color 18 } { Fl_Button cancel { label Cancel callback close_callback selected xywh {165 330 80 35} } Fl_Button ok_but { label Use callback apply_callback xywh {290 330 80 35} labelfont 1 } } } eureka-editor-eureka-2.0.2/misc/pack-source.sh000077500000000000000000000012731464327712600212520ustar00rootroot00000000000000#!/bin/bash set -e if [ ! -d ports ]; then echo "Run this script from the top level." exit 1 fi echo "Creating source package for Eureka..." dest="eureka-X.XX-source" mkdir $dest # # Source code # cp -av Makefile* $dest/ cp -av src $dest/src cp -av osx $dest/osx cp -av misc $dest/misc mkdir $dest/obj_linux mkdir $dest/obj_win32 # # Data files # cp -av bindings.cfg $dest cp -av defaults.cfg $dest cp -av operations.cfg $dest cp -av common $dest/common cp -av games $dest/games cp -av ports $dest/ports # # Documentation # cp -av *.txt $dest cp -av docs $dest/docs cp -av changelogs $dest/changelogs # # all done # echo "------------------------------------" echo "All done." eureka-editor-eureka-2.0.2/misc/pack-win32.sh000077500000000000000000000011631464327712600207120ustar00rootroot00000000000000#!/bin/bash set -e if [ ! -d ports ]; then echo "Run this script from the top level." exit 1 fi echo "Creating WIN32 package for Eureka..." dest="Eureka-X.XX" mkdir $dest # # Executable(s) # cp -av Eureka.exe $dest # # Data files # cp -av common $dest/common cp -av games $dest/games cp -av ports $dest/ports cp -av bindings.cfg $dest cp -av defaults.cfg $dest cp -av operations.cfg $dest cp -av misc/about_logo.png $dest/common # # Documentation # cp -av *.txt $dest rm $dest/INSTALL.txt # # all done # echo "----------------------------------------" echo "zip -l -r eureka-XXX-win.zip Eureka-X.XX" echo "" eureka-editor-eureka-2.0.2/misc/pmconvert.sh000077500000000000000000000042131464327712600210500ustar00rootroot00000000000000#!/bin/bash set -e export PM_INDENT="" export PM_NEXT="" function process() { INFILE="${3}" OUTFILE="pm/${2}" export PM_BASE="${1}" export PM_PAGE="${2}" export PM_FILE="${3}" echo ==== ${OUTFILE} ==== echo "${PM_INDENT}* [[${2}]]" >> pm/Index cat ${INFILE} | awk '{ gsub(/`\\``/, "`backquote`") } { print }' | awk '{ gsub(/:kbd:/, ":sub:") } { print }' | awk '{ gsub(/:download:/, ":sup:") } { print }' | pandoc -f RST -t pmwiki.lua > ${OUTFILE} export PM_NEXT="$PM_PAGE" } echo "" > pm/Index # NOTE: disabled this one (to not clobber the edited version on the website) # process "index" "User.Index" "source/index.rst" # NOTE 2: we build the pages in reverse order, to ease adding "next" links # [ hence the pm/Index file is currently useless ] process "basics" "User.Basics" "source/basics/index.rst" process "concepts" "User.Concepts" "source/mapping-concepts/index.rst" process "management" "User.Projects" "source/project-management/index.rst" process "user_interface" "User.UI" "source/user-interface/index.rst" process "installation" "User.Installation" "source/installation.rst" process "intro" "User.Intro" "source/introduction.rst" echo "* Cookbook" >> pm/Index PM_INDENT=" " PM_NEXT="" process "ck_prefabs" "Cookbook.Prefabs" "source/cookbook/prefabs/index.rst" process "ck_traps" "Cookbook.Traps" "source/cookbook/traps/index.rst" process "ck_pool" "Cookbook.ToxicPool" "source/cookbook/toxic-pool/index.rst" process "ck_lifts" "Cookbook.Lifts" "source/cookbook/lifts/index.rst" process "ck_doors" "Cookbook.Doors" "source/cookbook/doors/index.rst" process "ck_teleport" "Cookbook.Teleporters" "source/cookbook/teleporters/index.rst" process "ck_altar" "Cookbook.Altar" "source/cookbook/altar/index.rst" process "ck_curve" "Cookbook.CurvedStairs" "source/cookbook/curved-stairs/index.rst" process "ck_stairs" "Cookbook.Stairs" "source/cookbook/stairs/index.rst" process "ck_sky" "Cookbook.Sky" "source/cookbook/sky/index.rst" echo "ALL DONE." eureka-editor-eureka-2.0.2/misc/pmwiki.lua000066400000000000000000000230061464327712600205000ustar00rootroot00000000000000-- This is a custom writer for pandoc producing pmWiki format. -- Created by Andrew Apted, May 2018, based on sample.lua. -- This script only works on the Eureka user manual -- (in conjunction with the pmconvert.sh script). WEBSITE = "http://eureka-editor.sourceforge.net/" DL_BASE = "http://sourceforge.net/projects/eureka-editor/files/Misc/Samples/" VERBOSE = false ANCHOR = 1 -- Character escaping local function escape(s, in_attribute) -- FIXME return s end local function copy_file(src, dest) -- NOTE: this will only work on Unix local cmd = string.format("cp -n '%s' '%s'", src, dest) if VERBOSE then io.stderr:write(cmd .. "\n") end os.execute(cmd) end -- stores a link into the "pm/Index" file. -- returns the anchor name, or nil if nothing happened. local function add_index_link(tit) -- skip it for the cookbook pages local pm_file = os.getenv("PM_FILE") if pm_file and string.match(pm_file, "cookbook/") then return end local pm_page = os.getenv("PM_PAGE") if not pm_page then return end local fp = io.open("pm/Index", "a") if not fp then if true then io.stderr:write("Failure appending to pm/Index\n") end return end local anchor = "anchor" .. ANCHOR ANCHOR = ANCHOR + 1 fp:write(string.format("** [[%s#%s | %s]]\n", pm_page, anchor, tit)) fp:close() return anchor end -- Blocksep is used to separate block elements. function Blocksep() return "\n" end -- This function is called once for the whole document -- (at the very end). body is a single string. function Doc(body, metadata, variables) local BACK_LINK = "[-[[User.Index | back to the Index]]-]" -- add link to the "next" page (when there is one) local next_page = os.getenv("PM_NEXT") if next_page and next_page ~= "" then BACK_LINK = BACK_LINK .. "   |   " .. "[-[[" .. next_page .. " | go to next page]]-]" end -- add links back to the index page (the TOC) body = BACK_LINK .. "\n\n" .. body .. "\n\n" .. BACK_LINK .. "\n" -- disable the usual pmWiki title body = "(:notitle:)\n" .. body -- convert to a raw pmWiki page file. -- several characters need to be escaped... body = string.gsub(body, "%%", "%%25") body = string.gsub(body, "<", "%%3c") body = string.gsub(body, "\n", "%%0a") return "version=pmwiki-2.2.43 urlencoded=1\n" .. "charset=UTF-8\n" .. "text=" .. body .. "\n" end -- The functions that follow render corresponding pandoc elements. -- s is always a string, attr is always a table of attributes, and -- items is always an array of strings (the items in a list) except -- for DefinitionList. function Str(s) return escape(s) end function Space() return " " end function SoftBreak() return "\n" end function LineBreak() return "\\" end function Emph(s) return "''" .. s .. "''" end function Strong(s) return "'''" .. s .. "'''" end -- this represents the :kbd: elements function Subscript(s) if s == nil or s == "" then return "" end -- handle menu references like "File -> Open Map" if string.match(s, "->") then return Strong(s) end local result = "" -- check for shift/control/alt local low = string.lower(s) if string.match(low, "^shift[ -_]") then s = string.sub(s, 7) return Subscript("shift") .. "-" .. Subscript(s) end if string.match(low, "^control[ -_]") then s = string.sub(s, 9) return Subscript("ctrl") .. "-" .. Subscript(s) end if string.match(low, "^ctrl[ -_]") then s = string.sub(s, 6) return Subscript("ctrl") .. "-" .. Subscript(s) end if string.match(low, "^alt[ -_]") then s = string.sub(s, 5) return Subscript("alt") .. "-" .. Subscript(s) end -- check for ranges if #s == 3 and string.sub(s, 2, 2) == "-" then local s1 = string.sub(s, 1, 1) local s2 = string.sub(s, 3, 3) return Subscript(s1) .. ".." .. Subscript(s2) end -- handle some other oddities if s == ",." then return Subscript(",") .. " " .. Subscript(".") end if s == "[]" then return Subscript("[") .. " " .. Subscript("]") end if low == "spacebar" then s = "space" end -- an awk scripts provide this -- (because it seems pandoc has an issue with `\`` in RST) if s == "backquote" then s = "`" end -- keys like "shift", "tab" (etc) should be uppercase if #s >= 2 then s = string.upper(s) end return "%key%" .. s .. "%%" end -- this represents the :download: elements function Superscript(s) local url = DL_BASE .. s .. "/download" -- copy the file too local dir = os.getenv("PM_FILE") if dir then dir = string.match(dir, "^(.*/)[^/]*$") end if dir then local src = dir .. s local dest = "pm/download/" .. s copy_file(src, dest) end return "[[" .. url .. " | " .. s .. "]]" end function SmallCaps(s) -- not needed return s end function Strikeout(s) -- probably not needed return s end function Link(s, src, tit, attr) -- currently only external links are handled properly. -- internal links (to other wiki pages) are not supported -- (and probably not needed). -- handle :target: weirdness in cookbook/traps if string.match(src, "_images/") then return s end return "[[" .. src .. " | " .. s .. "]]" end function Image(s, src, tit, attr) return CaptionedImage(src, tit, s, attr) end function CaptionedImage(src, tit, caption, attr) local url = src -- fix up some image filenames... if string.match(url, "capture_") then local base = os.getenv("PM_BASE") if base then url = string.gsub(url, "capture_", base .. "_") end end if string.match(url, "http:/") or string.match(url, "https:/") then -- Ok, we have an absolute URL else -- copy the image file too local dir = os.getenv("PM_FILE") if dir then dir = string.match(dir, "^(.*/)[^/]*$") end if dir then -- source must be original name, dest must be modified name local src_name = dir .. src local dest_name = "pm/user/" .. url copy_file(src_name, dest_name) end -- make an absolute URL url = WEBSITE .. "user/" .. url end if caption == "" or caption == "image" then -- ignore it else url = url .. '"' .. caption .. '"' end return url end function Code(s, attr) return "@@" .. escape(s) .. "@@" end function CodeBlock(s, attr) return "(:table id=codebox:)\n" .. "(:cell:)\n" .. escape(s) .. "\n(:tableend:)" end function InlineMath(s) -- not needed return escape(s) end function DisplayMath(s) -- not needed return escape(s) end function Note(s) -- not needed (footnotes) return "" end function Span(s, attr) -- not needed return s end function RawInline(format, str) if format == "html" then return str end end function Cite(s, cs) -- not needed return s end function Plain(s) return s end function Para(s) return s .. "\n" end -- lev is an integer >= 1 function Header(lev, s, attr) if lev <= 1 then return "!" .. s elseif lev <= 2 then local anchor = add_index_link(s) if anchor then return "[[#" .. anchor .. "]]\n" .. "!!" .. s end return "!!" .. s else return "!!!" .. s end end function BlockQuote(s) local class = "noticebox" local s2 = s if #s2 > 100 then s2 = string.sub(s, 1, 100) end s2 = string.lower(s2) if string.match(s2, "warning") then class = "warningbox" s = string.gsub(s, "warning", "Warning:", 1) elseif string.match(s2, "note") then s = string.gsub(s, "note", "Note:", 1) end return "(:table id=" .. class .. ":)\n" .. "(:cell:)\n" .. s .. "(:tableend:)" end function HorizontalRule() return "----" end function BulletList(items) local buffer = {} for _, item in pairs(items) do table.insert(buffer, "* " .. item) end return table.concat(buffer, "\n") .. "\n" end function OrderedList(items) local buffer = {} for _, item in pairs(items) do table.insert(buffer, "# " .. item) end return table.concat(buffer, "\n") .. "\n" end function DefinitionList(items) local buffer = {} for _,item in pairs(items) do for k, v in pairs(item) do table.insert(buffer, "\n:" .. k .. ": " .. table.concat(v, "\n")) end end return table.concat(buffer, "\n") .. "\n" end -- Caption is a string, aligns is an array of strings, -- widths is an array of floats, headers is an array of -- strings, rows is an array of arrays of strings. function Table(caption, aligns, widths, headers, rows) -- not needed (thankfully!) return "" end function RawBlock(format, str) if format == "html" then return str end end function Div(s, attr) -- probably not needed return "(:div:)" .. s .. "(:divend:)" end -- The following code will produce runtime warnings when you haven't defined -- all of the functions you need for the custom writer, so it's useful -- to include when you're working on a writer. local meta = {} meta.__index = function(_, key) io.stderr:write(string.format("WARNING: Undefined function '%s'\n",key)) return function() return "" end end setmetatable(_G, meta) eureka-editor-eureka-2.0.2/misc/prefs2.fl000066400000000000000000000133701464327712600202240ustar00rootroot00000000000000# data file for the Fltk User Interface Designer (fluid) version 1.0302 header_name {.h} code_name {.cxx} widget_class UI_Preferences { label PREFERENCES open xywh {376 124 600 500} type Double color 18 visible } { Fl_Tabs tabs {open xywh {0 0 590 435} } { Fl_Group {} { label { General } open xywh {0 25 590 405} labelsize 16 hide } { Fl_Box {} { label {GUI Appearance} xywh {25 50 145 30} labelfont 1 align 20 } Fl_Group {} { xywh {45 90 250 115} } { Fl_Round_Button theme_FLTK { label { FLTK theme} xywh {50 90 150 25} type Radio down_box ROUND_DOWN_BOX } Fl_Round_Button theme_GTK { label { GTK+ theme } xywh {50 120 150 25} type Radio down_box ROUND_DOWN_BOX } Fl_Round_Button theme_plastic { label { plastic theme } xywh {50 150 165 25} type Radio down_box ROUND_DOWN_BOX } } Fl_Group {} { xywh {220 90 190 90} } { Fl_Round_Button cols_default { label {default colors} xywh {245 90 135 25} type Radio down_box ROUND_DOWN_BOX } Fl_Round_Button cols_bright { label {bright colors} xywh {245 120 140 25} type Radio down_box ROUND_DOWN_BOX } Fl_Round_Button cols_custom { label {custom colors ---->} xywh {245 150 165 25} type Radio down_box ROUND_DOWN_BOX } } Fl_Group {} { xywh {385 80 205 100} color 50 align 22 } { Fl_Button bg_colorbox { label background xywh {430 90 45 25} box BORDER_BOX align 8 } Fl_Button ig_colorbox { label {input bg} xywh {430 120 45 25} box BORDER_BOX color 7 align 8 } Fl_Button fg_colorbox { label {text color} xywh {430 150 45 25} box BORDER_BOX color 32 align 8 } } Fl_Box {} { label {Map Grid and Scrolling} xywh {30 195 195 25} labelfont 1 align 20 } Fl_Check_Button grid_snap { label { default SNAP mode} xywh {50 230 235 25} down_box DOWN_BOX } Fl_Choice grid_size { label {default grid size } open xywh {435 230 85 25} down_box BORDER_BOX } {} Fl_Check_Button gen_digitzoom { label { digit keys zoom the map} xywh {50 265 240 25} down_box DOWN_BOX } Fl_Choice gen_smallscroll { label {small scroll step } open xywh {435 265 85 25} down_box BORDER_BOX } {} Fl_Choice gen_largescroll { label {large scroll step } open xywh {435 300 85 25} down_box BORDER_BOX } {} Fl_Check_Button gen_wheelscroll { label { mouse wheel scrolls the map} xywh {50 300 245 25} down_box DOWN_BOX } Fl_Box {} { label {Other Stuff} xywh {30 340 280 35} labelfont 1 align 20 } Fl_Check_Button gen_escapequit { label { Escape key can Quit the program} xywh {50 380 265 30} down_box DOWN_BOX } } Fl_Group {} { label { Editing } xywh {0 25 585 410} labelsize 16 hide } { Fl_Box {} { label {Editing Options} xywh {25 50 355 30} labelfont 1 align 20 } Fl_Check_Button edit_newislands { label { new islands have void interior} xywh {50 80 265 30} down_box DOWN_BOX } Fl_Check_Button edit_samemode { label { same mode key will clear selection} xywh {50 140 270 30} down_box DOWN_BOX } Fl_Check_Button edit_autoadjustX { label { auto-adjust X offsets} xywh {50 110 260 30} down_box DOWN_BOX } Fl_Check_Button edit_multiselect { label { multi-select requires a modifier key} xywh {50 170 275 30} down_box DOWN_BOX } Fl_Choice edit_modkey { label {----> } open xywh {370 170 95 30} down_box BORDER_BOX } {} Fl_Input edit_sectorsize { label {new sector size:} xywh {440 80 105 25} type Int } } Fl_Group {} { label { glBSP } open xywh {0 25 585 410} selection_color 50 labelsize 16 hide } { Fl_Box {} { label {glBSP Node Building Options} xywh {25 50 280 30} labelfont 1 align 20 } Fl_Check_Button glbsp_warn { label { Show all warning messages} xywh {60 90 220 30} down_box DOWN_BOX } Fl_Check_Button glbsp_verbose { label { Verbose -- show information about each level} xywh {60 120 350 30} down_box DOWN_BOX } Fl_Check_Button glbsp_fast { label { Fast -- build the fastest way, but nodes may not be as good} xywh {60 150 440 30} down_box DOWN_BOX } } Fl_Group {} { label { Keys } open xywh {0 25 585 410} selection_color 50 labelsize 16 } { Fl_Box {} { label {Key Bindings} xywh {10 46 440 29} labelfont 1 align 20 } Fl_Browser {} { xywh {25 116 555 238} type Hold } Fl_Button {} { label Add xywh {50 375 90 35} color 55 } Fl_Button {} { label {Change Key} xywh {290 375 122 35} color 55 } Fl_Button {} { label Edit xywh {175 375 83 35} color 55 } Fl_Button {} { label Remove xywh {440 375 104 35} color 55 } Fl_Button key_group { label Group xywh {25 87 125 28} color 231 align 20 } Fl_Button key_key { label Key xywh {150 87 150 28} color 231 align 20 } Fl_Button key_func { label Function selected xywh {300 87 260 28} color 231 align 20 } } } Fl_Button {} { label OK xywh {460 450 85 35} } } eureka-editor-eureka-2.0.2/misc/ugh.vim000066400000000000000000000024211464327712600177730ustar00rootroot00000000000000" Vim syntax file " Language: Eureka Definition (.ugh) " First Author: Andrew Apted " Last Change: 2018 Jun 18 " quit when a syntax file was already loaded if exists("b:current_syntax") finish endif syn case ignore syn match ughComment /#.*$/ syn keyword ughDirective include if else endif is syn keyword ughDirective set clear syn keyword ughSetting map_formats supported_games variant_of syn keyword ughSetting player_size sky_color sky_flat syn keyword ughSetting default_textures default_thing syn keyword ughSetting feature syn keyword ughEntry line linegroup special color syn keyword ughEntry sector thing thinggroup syn keyword ughEntry texture flat texturegroup syn keyword ughEntry gen_line gen_field syn keyword ughError spec_group default_port level_name syn region ughString start=/"/ skip=/\\[\\"]/ end=/"/ syn match ughNumber "\<-\?\d\+\>" syn keyword ughTodo containedin=ughComment TODO FIXME OPTIMISE OPTIMIZE WISH hi def link ughComment Comment hi def link ughConstant Constant hi def link ughDirective Special hi def link ughEntry Function hi def link ughError Error hi def link ughNumber Number hi def link ughSetting Statement hi def link ughString String hi def link ughTodo Todo let b:current_syntax = "ugh" " vim:ts=8 eureka-editor-eureka-2.0.2/misc/wiki/000077500000000000000000000000001464327712600174375ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/misc/wiki/eureka.css000066400000000000000000000117411464327712600214310ustar00rootroot00000000000000/*** this CSS is based on pmwiki.css ***/ /* This sets the overall frame for the site */ body { margin:0px; background-color: black; font-family:Arial,Helvetica,sans-serif; font-size:14pt; color: #aaa; } /* These control the fixed-width text elements of the page */ textarea, pre, code { font-size:0.9em; } pre, code { font-family:'Lucida Console','Andale Mono','Courier New',Courier,monospace; } pre { line-height:1.2em; } pre code, code code, pre pre { font-size:100%; } /* These primarily adjust the size and spacing of heading elements, ** most browsers have atrocious defaults for these. */ h1, h2, h3, h4, h5, h6 { margin-top:1.0em; margin-bottom:0.6em; } h1, h2, h3, h6 { font-weight:normal; } h4, h5 { font-weight:bold; } h1 code, h2 code, h3 code, h4 code { font-size:1em; } h1 { font-size:1.90em; } h2 { font-size:1.50em; } h3 { font-size:1.25em; } h4 { font-size:1.10em; } h5 { font-size:1.0em; } h6 { font-size:1.0em; } #wikimid { table-layout: fixed; } /* The #wikilogo element is the logo from $PageLogoFmt */ #wikilogo { width=240px; margin:0px; padding:0px; background-color: black; border-bottom: 1px #aaa solid; text-align: center; } /* This controls the rest of the heading (primarily the search box) */ #wikihead { margin: 0px; /* position:absolute; right:10px; top:10px; font-family:Verdana,sans-serif; font-size:85%; */ } /* These are for the left-sidebar. */ #wikileft { width: 250px; min-width: 250px; max-width: 250px; margin: 0px; overflow: hidden; background-image: url("http://eureka-editor.sourceforge.net/grid.png"); background-position: top; background-color: #002; } #wikileft2 { padding:5px; border-right:1px #aaa solid; padding-top: 15px; line-height:1.33em; font-size:14pt; font-family:Verdana,sans-serif; } #wikileft2 .vspace { margin-top:1.125em; } #wikileft2 a { text-decoration:none; color:#09c; } #wikileft2 a:hover { text-decoration:underline; color:#ee0; } #wikileft2 ul { list-style:none; padding:0px; margin:0px; } #wikileft2 li { margin:0px; padding-left: 6px; } .sidehead { margin:0px; padding:4px 2px 2px 2px; font-size:14pt; font-weight:bold; font-style:normal; } .sidehead a { color:#505050; font-weight:bold; font-style:normal; } /* These affect the main content area. */ #wikibody { margin: 0px; padding: 10px 10px 20px 20px; background-color: #f5f5f5; color: black; font-size:14pt; } #wikibody a:link { color:blue; text-decoration:none; } #wikibody a:visited { color:blue; text-decoration:none; } #wikibody a:hover { color:#07f; text-decoration:underline; } #wikicmds { float:right; white-space:nowrap; font-family:Verdana,sans-serif; font-size:80%; } #wikicmds a:link { color:#666; text-decoration:none; border:none; } #wikicmds a:visited { color:#666; text-decoration:none; border:none; } #wikicmds a:hover { text-decoration:underline; color:blue; } #wikicmds a.createlink { display:none; } #wikicmds ul { list-style:none; margin:0px; padding:0px; } #wikicmds li { display:inline; margin:0px 5px; } .pagegroup { margin-top:8px; margin-bottom:2px; } .pagetitle { line-height:1em; margin:0px; font-size:1.6em; font-weight:normal; } .wikiaction { margin-top:4px; margin-bottom:4px; } #wikitext { margin-top:12px; line-height:1.33em; } #wikitext table { font-size:100%; line-height:1.33em; } /* For MSIE 5.5 */ /* These are for the edit form. */ #wikiedit form { margin:0px; width:100%; } #wikiedit textarea { width:100%; } .wikimessage { margin-top:4px; margin-bottom:4px; font-style:italic; } /* These affect the lines at the very bottom. */ #wikifoot { padding-left:256px; padding-bottom:4px; border-top:1px #aaa solid; padding-top:0px; font-family:Verdana,sans-serif; font-size:80%; } #wikifoot input { font-size:85%; } #wikifoot a { color:#eb4; } /* andrewj's stuff */ .footerlinks { float: right; } .footnav { padding-top:4px; padding-bottom:10px } #cheatsheet { font-size: 85%; background-color: #ececfc; border: 1px #7e7e6e solid; padding: 0.3em; margin: 0.9em; line-height: 1.33em; } .cheatsheet ul { list-style:none; } .cheatbold { color: black; font-weight: bold; } .key { background-color: white; font-family: monospace; font-size: 90%; border: 1px #aaa solid; padding: 3px 6px 3px 6px; } #codebox { background-color: #fcfcec; font-family: monospace; font-size: 80%; border: 1px #8e8e7e solid; padding: 0.3em; margin: 0.6em; margin-left: 3.5em; } #noticebox { background-color: #ececfc; border: 1px #7e7e8e solid; padding: 0.3em; margin: 0.6em; } #warningbox { background-color: #fcdcdc; border: 1px #aa9999 solid; padding: 0.3em; margin: 0.6em; } .kw { color: #d00; font-family: monospace; } /* These affect the printed appearance of the web view (not the separate ** print view) of pages. The sidebar and action links aren't printed. */ @media print { body { width:auto; margin:0px; padding:0.5em; } #wikihead, #wikilogo, #wikileft2, #wikicmds, .footnav { display:none; } #wikifoot { padding:2px; } } eureka-editor-eureka-2.0.2/misc/wiki/eureka.tmpl000066400000000000000000000034421464327712600216140ustar00rootroot00000000000000 $WikiTitle | {$Title} $ActionTitle
 
$[Recent Changes]   $[Page last modified on {$LastModified}]
eureka-editor-eureka-2.0.2/operations.cfg000066400000000000000000000063661464327712600204200ustar00rootroot00000000000000# Eureka operation menus # vi:ts=12:noexpandtab # # ---- 3D View ------------ # menu render "3D Operations" c "Copy Texture" Clipboard_Copy p "Paste Texture" Clipboard_Paste x "Align X" 3D_Align /x y "Align Y" 3D_Align /y r "Align X (right)" 3D_Align /x /right e "Align Y (right)" 3D_Align /y /right z "Clear X offset" 3D_Align /x /clear 0 "Clear Y offset" 3D_Align /y /clear divider v "Drop to floor" 3D_DropToFloor g "Toggle gravity" 3D_Toggle grav t "Toggle textures" 3D_Toggle tex o "Toggle objects" 3D_Toggle obj l "Toggle lighting" 3D_Toggle light # # ---- Things mode ------------ # menu thing "Thing Operations" w "Spin 45° left" TH_Spin +45 x "Spin 45° right" TH_Spin -45 e "Spin 90° left" TH_Spin +90 c "Spin 90° right" TH_Spin -90 r "Rotate 180°" TH_Spin 180 divider h "Mirror (horiz)" Mirror horiz v "Invert (vert)" Mirror vert s "Toggle sprites" Toggle sprites # # ---- LineDefs mode ------------ # menu line "Line Operations" w "Flip" LIN_Flip e "Select path" LIN_SelectPath /add k "Split in half" LIN_SplitHalf a "Auto align" LIN_Align /x /y c "Clear offsets" LIN_Align /x /y /clear divider m "Merge" Merge d "Disconnect" Disconnect h "Mirror (horiz)" Mirror horiz v "Invert (vert)" Mirror vert # # ---- Sectors mode ------------ # menu sector "Sector Operations" w "Swap flats" SEC_SwapFlats e "Select same h" SEC_SelectGroup /floor_h f "Select same floor" SEC_SelectGroup /floor_tex c "Select same ceil" SEC_SelectGroup /ceil_tex divider m "Merge" Merge d "Disconnect" Disconnect h "Mirror (horiz)" Mirror horiz v "Invert (vert)" Mirror vert # # ---- Vertices mode ------------ # menu vertex "Vertex Operations" i "Shape line" VT_ShapeLine o "Shape circle" VT_ShapeArc 360 c "Shape half-circle" VT_ShapeArc 180 j "Shape 90° arc" VT_ShapeArc 90 divider m "Merge" Merge d "Disconnect" Disconnect q "Quantize (snap)" Quantize h "Mirror (horiz)" Mirror horiz v "Invert (vert)" Mirror vert # # ---- Edit mode ------------ # menu edit "Edit Mode" t "Things" EditMode thing w "Linedefs" EditMode line s "Sectors" EditMode sectors v "Vertices" EditMode vertices # # ---- Browser mode ----------- # menu browser "Browser Mode" t "Textures" BrowserMode tex f "Flats" BrowserMode flat d "Things" BrowserMode obj w "Line specials" BrowserMode line s "Sector specials" BrowserMode sec g "Generalized types" BrowserMode gen x "OFF" Set browser 0 # # ---- Ratio lock ------------ # menu ratio "Ratio Lock" u "None" Set ratio 0 1 "1:1 Ratio" Set ratio 1 2 "2:1 Ratio" Set ratio 2 4 "4:1 Ratio" Set ratio 3 8 "8:1 Ratio" Set ratio 4 5 "5:4 Ratio" Set ratio 5 7 "7:4 Ratio" Set ratio 6 s "User Ratio" Set ratio 7 # # ---- Sector rendering (2D mode) ---- # menu sec_render "Sector Rendering" n "PLAIN" Set sec_render 0 f "Floor" Set sec_render 1 c "Ceiling" Set sec_render 2 l "Lighting" Set sec_render 3 b "Floor Bright" Set sec_render 4 e "Ceil Bright" Set sec_render 5 s "Sound" Set sec_render 6 # # ---- Scale / zoom ------------- # menu scale "Scale Factor" t "12%" GRID_Zoom -7 q "25%" GRID_Zoom -4 h "50%" GRID_Zoom -2 1 "100%" GRID_Zoom 1 2 "200%" GRID_Zoom 2 3 "300%" GRID_Zoom 3 4 "400%" GRID_Zoom 4 divider f "Zoom in" Zoom +1 b "Zoom out" Zoom -1 w "Whole map" ZoomWholeMap s "Whole selection" ZoomSelection eureka-editor-eureka-2.0.2/osx/000077500000000000000000000000001464327712600163525ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/osx/.gitignore000066400000000000000000000000531464327712600203400ustar00rootroot00000000000000FL fltk-*-source.tar.gz fltk-*/ libfltk*.a eureka-editor-eureka-2.0.2/osx/CMakeLists.txt000066400000000000000000000000331464327712600211060ustar00rootroot00000000000000add_subdirectory(EurekaApp)eureka-editor-eureka-2.0.2/osx/EurekaApp/000077500000000000000000000000001464327712600202275ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/osx/EurekaApp/AppDelegate.h000066400000000000000000000023311464327712600225520ustar00rootroot00000000000000//------------------------------------------------------------------------ // OS X EDITOR APP DELEGATE INTERFACE //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2013 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ // // Module by Ioan Chera // #import @interface AppDelegate : NSObject @end eureka-editor-eureka-2.0.2/osx/EurekaApp/AppDelegate.mm000066400000000000000000000114021464327712600227330ustar00rootroot00000000000000//------------------------------------------------------------------------ // OS X EDITOR APP DELEGATE IMPLEMENTATION //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2013 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ // // Module by Ioan Chera // // Thanks to Darrell Walisser, Max Horn et al. for their SDLMain.m code - // reliable base for cross-platform apps ported to OS X. #import "AppDelegate.h" #include "main.h" static int gArgc; static char **gArgv; static BOOL gFinderLaunch; static BOOL gCalledAppMainline = FALSE; // Prototype to cross-platform main entry function int EurekaMain(int argc, char *argv[]); @implementation AppDelegate // // applicationDidFinishLaunching: // // After [NSApp run] was called. // launchMainLine not called immediately because I needed application:openFile: // - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // Set install_dir from here (it's dependent on project build settings) // Current value (might change): .app package root directory global::install_dir = [[[NSBundle mainBundle] resourcePath] cStringUsingEncoding:NSUTF8StringEncoding]; // home_dir is set inside the main program and doesn't depend on build // settings [self launchMainLine]; // start the program } // // launchMainLine // // Start the program and retrieve the exit code // - (void)launchMainLine { int exitcode = EurekaMain(gArgc, gArgv); exit(exitcode); } // // application:openFile: // // Handle OS X UI's non-command-line way of opening files. // FIXME: handle files open this way at runtime. // // Note: code has been borrowed from SDLMain.m. // SDL license is compatible with GPL v2 // - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename { const char *temparg; size_t arglen; char *arg; char **newargv; if (!gFinderLaunch) /* MacOS is passing command line args. */ return FALSE; if (gCalledAppMainline) /* app has started, ignore this document. */ return FALSE; temparg = [filename UTF8String]; arglen = strlen(temparg) + 1; arg = (char *) malloc(arglen); if (arg == NULL) return FALSE; newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2)); if (newargv == NULL) { free(arg); return FALSE; } gArgv = newargv; strlcpy(arg, temparg, arglen); gArgv[gArgc++] = arg; gArgv[gArgc] = NULL; return TRUE; } @end // // CustomApplicationMain // // Replacement for NSApplicationMain. Also borrowed from SDLMain.m // //static void CustomApplicationMain (int argc, char **argv) //{ // NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // AppDelegate *delegate; // // // Ensure the application object is initialised // [NSApplication sharedApplication]; // // // Set up the menubar // [NSApp setMainMenu:[[NSMenu alloc] init]]; // // // Create SDLMain and make it the app delegate // delegate = [[AppDelegate alloc] init]; // [[NSApplication sharedApplication] setDelegate:delegate]; // // // Start the main event loop // [NSApp run]; // // [delegate release]; // [pool release]; //} // // main // // Code borrowed from SDLMain.m // int main(int argc, char *argv[]) { if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { gArgv = (char **) malloc(sizeof (char *) * 2); gArgv[0] = argv[0]; gArgv[1] = NULL; gArgc = 1; gFinderLaunch = YES; } else { int i; gArgc = argc; gArgv = (char **) malloc(sizeof (char *) * (argc+1)); for (i = 0; i <= argc; i++) gArgv[i] = argv[i]; gFinderLaunch = NO; } // Set install_dir from here (it's dependent on project build settings) // Current value (might change): .app package root directory global::install_dir = [[[NSBundle mainBundle] resourcePath] cStringUsingEncoding:NSUTF8StringEncoding]; return EurekaMain(gArgc, gArgv); // CustomApplicationMain(gArgc, gArgv); } eureka-editor-eureka-2.0.2/osx/EurekaApp/CMakeLists.txt000066400000000000000000000011361464327712600227700ustar00rootroot00000000000000set(resource_mac "${CMAKE_CURRENT_SOURCE_DIR}/Eureka Doom EditorIcon.icns" CACHE FILEPATH "") set(source_mac AppDelegate.h AppDelegate.mm OSXCalls.h OSXCalls.mm ) add_library(eurekamac STATIC ${source_mac}) # Needed for macOS release archiving! set_target_properties(eurekamac PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/out/library) target_include_directories(eurekamac INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) # Need to silence OpenGL deprecation warnings (they tell us what we know and can't fix) target_compile_definitions(eurekamac PUBLIC "GL_SILENCE_DEPRECATION" ) eureka-editor-eureka-2.0.2/osx/EurekaApp/Eureka Doom Editor-Info.plist.in000066400000000000000000000037701464327712600261130ustar00rootroot00000000000000 CFBundleDevelopmentRegion en CFBundleDocumentTypes CFBundleTypeExtensions WAD CFBundleTypeIconFile EurekaIcon CFBundleTypeName Doom WAD File CFBundleTypeRole Editor LSHandlerRank Alternate CFBundleExecutable ${MACOSX_BUNDLE_EXECUTABLE_NAME} CFBundleGetInfoString ${MACOSX_BUNDLE_INFO_STRING} CFBundleIconFile ${MACOSX_BUNDLE_ICON_FILE} CFBundleIdentifier ${MACOSX_BUNDLE_GUI_IDENTIFIER} CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString ${MACOSX_BUNDLE_LONG_VERSION_STRING} CFBundleName ${MACOSX_BUNDLE_BUNDLE_NAME} CFBundlePackageType APPL CFBundleShortVersionString ${MACOSX_BUNDLE_SHORT_VERSION_STRING} CFBundleSignature ???? CFBundleVersion ${MACOSX_BUNDLE_BUNDLE_VERSION} CSResourcesFileMapped LSApplicationCategoryType public.app-category.entertainment NSHumanReadableCopyright ${MACOSX_BUNDLE_COPYRIGHT} NSHighResolutionCapable eureka-editor-eureka-2.0.2/osx/EurekaApp/Eureka Doom EditorIcon.icns000066400000000000000000001067741464327712600252370ustar00rootroot00000000000000icnsTOC it32Mt8mk@it32M6  !!"!! !! !" ""!"#EHҹ=HrURILTJeJJ\_^R?JdJHO409TZENDF?<=CJ^M-,3;7A9VI.CCURC>%1DG0(+ +C,)2<)::ZIQhb^!<',?.((.'###M'B+4#<'!=0'$)-EA()&!-4!#*7@-!/430#PAEI,3K>(5 #F $ 1&G-BG=0$ B0#5E@1*!"&%C/ $/?(!6E ~,P995,+!,07!J  +=  A:+1231-# "%?("'+!,81A  O;P:74!.9!G B)&tkwl[\~ne.%F+4&*'0))* 3@S_C"'>@$'A'1- &<,xH0 *!25Q",$)W"1Ȱ!-&+&J5 #> 4F &.< ;'7C-,- #?E--%#(I5w[ ('@DLn7-:CM^]H5ZW92;Z85Z^0%2B7(=0(/,#+S%+',CD5%!3\eQ A^ⶒÄcmxkC $-60:G+2K#'MK+"@@?\P      -BAA 77++# *CUUR@,HADŽ  /5V. 5H U&#%P,9") TF 6WF(%O#K"$, @6& 4>$;K+gR"GS $'<3;_Y*D= !  !! UQ0') L> "KZM-20"oR$+,*VQ!V(1+]C+,561$!&.+c?&,n4!("%-) >  BbEWL,EcwG( ()'S)_3SxH43%&/5)2+8aZbuK"7:1&&!> 1RYM[U0!(  b*%)&3JSP7 033-3-&61+(%#-aaF0,3%i]> '&4\YRlY%  (eljM('#3# #/&#,K?5);2$7>7D}P%(sl_SD : '=RO&>XX[eB#$ gO?4Gi#/3/+%plD=;H"2@JAAD_|-/Mxcx:  .B5__^bM(aP'Vqe*+#../--0i4rL?GDkb]kJPSD&,1/(*,1-)2M]{gECCJNA<;. $ > +0Fe]_cQ!/+.,3-"79;LL@>KFGH3+3)#!'l^ >"-& -O_U9 !govpH" &%-2?>=CDBDA=2"+-(2+--(* "_[_>'gSQWVd2@/0i !-gw|j>#*,2;82;>HI6)$)00.2*$.71$lmm > 7%'/i3"oP5ktqvvA-'2/661-. (+ 00-/.16)'&'%rp>m!# 7G=0 A{|~oJ&02#*-,/00)*,9+!33,(()aYb> #rS"" &Szk !-,)4/20041* ':731-632**WGK>/.%Rr/%!"#&#!"+&%$Bt{k}o+!),-+4.4% ()(2)26:0# \fSW ! %!c{hLJ_q\PH=BN`e`v[> IL!!)!#' {ǀ<6:Mb`m{җCE;628<:AFHDI.' &# #  `X  -%#& !&#$7nW{&  ,#&$&&N2 1 &$$1 5f "$ %'!#  )FO@o/ ."&  %  BgL-kPF #$#)&# !$R* A t\L &#&# !40}($8ZI   *!$!1G@  r׹| "" "'DF)""&2N1!i^ " $(r_Jpe%""& ?0?  dȀ  ,!)* k8%& O:5   , !"GV6$2.(  !0򟼺Ӽ $" (&)02 f!BٝcoέmmZtvfL  !$!/,!  M>1iȀ5uv|!(:5!  '}ߪ㽉 H 1&#-*  m'Wc*g1[˺#Ѐ$tՍzƎ6X[ #઄ރP!vdʫр}  Ƭس.Cκ}!.71QYrr(hAFpԹwf~-o!˩w^-txJrئnS亴yxOvrJĽ어s܁N|xFˬŽܜtfk͋Dij<؉ȋͅK?㵮ȽЀ́(?˺쿓ǯj9ˑֽ>:č{2޶؁W3͒0+-ضºǠ·½ƷľƿZ1͜㿶%͖ݶ֘t,ãǾ갞:%ė紃(ĥK%ʛ%$ärؚRݜ̻"ƹĵwC ` ր' E#iq  f, *6)(&"  " !! # "$! ! ""!  !!# !"" ""-IϿĿü¬KH|~ngkfkmnZfijvXDNkxlocdYS_``{p>  LS05/[K#,.*=>1.5\U\\ K 91:gZ@Pn\i>Qum{D+&AfE4.30UrZLHLE@39<1x8F{D9*6f31HJGBGD_oE+"]aM`j0Q^a]@+/KL*.B[D,1* EI 1("FT32NMG=(/MS?+((39ElPUC5(%6OMMB@BBJa_55YYLJ]\k*QYPbxg&*U]4%:\ ++.3w(! !H.fG&%Q_96?wD5-);=kgd{mG? :MIHB?hf&/GmgC@]vUOg(PNO; A4!B`6-@o( "3/Ci *cB `HCTuv39<~D54*)+h2FR~?<@'5EBYZ<2BRfnUEVi_E>OZ"QNGRFgl-4Va43@y(2(.?\#0 ap0[jE$Axd91*+,+?[rhXA6DBCuZBC;YpQ@]|W, *JOPA3319S Hj*,Fq2%&)"WSJWnQEA:;BH@;=:H?5=EA:?>-=/1I8/9>Wy^JiOVNVRXVEe&-)8w\7L#P564-(,&;LZ[)0Dz//*1#x$b1.2&0)"/%"%#*%-.)2$/66<;88GYwuGSx|g}{SB`USv,5.;_&8:"100/2/*/3la0Aw !9H:DSH=279!1&7HUXkPKQmB |LQp{(;Y483>?4>/'(0-4),*X|(ByEP69UPRSpC.-$!!,$9FW{G@PPKHScv^B4srF-"Zn:+*&0:(!BuXh\2 N\AF^LMJSt}rE8HqC $#!,0-->/*$+)$)$#$)$#)-0%..(#,4(-&5 &!77tS;is,EQOF]Hcs)<!!          `tZGo|>/MS2dK@n5$>jEIGGR{qE"=s\>ueA*(1 XXA1CB2&8VJ4WaM!&)(:@V [YN1&#W}'&5;u&19IU0 V0)/V*n($*BA>AIcI  >&0EF,ФXXRI̗EPHU|CDSQBPVSI8,%:IKl(:S[87/-+2?R_C> !ׯb*oْP?L?Y 77hmSVE30@XbU`ZpҐ<3&8arf\]i:k\9?M>-. C5AHAIid4,-;Q[^Ya[Pa[TMG;4=[m[f[U>  J0dɞJ .=P̹UI=QF2(4DRQR`cL^TE0 0_|{UjԵ7CQ> (;.m|F:CCyq>'',CSYZ[Wxl71;Wy~zYIzQ[e> hp$"a×P4܌!++-%3s9FSPRTRNRVOF,l㱉rU2!&;22HFHM5ab> 4/DP060 4C7=KLUTZU3!">Wzg2$;MWMKJ92KQQ/>!H$+Gh$@ЀI>ON?*$6Ratyyx_?"7LSPXQUUPNC4K@ > _mdv5XӼu&!8NbgqhbsuqJ#(ET[]\cYS]bWE01-4D> &8;:3iWJԜ"$9/cx]XZZgohhaF&.KYMZZ\^\\^PG3),FQSSB%>:LD?9.3d{mV47$(%/@w׼Wc`H5"':U]`bb^VX`jV<01>Hbea`\][>EA=>;+/#*,/4213ABHK%+D_]]jfkhfieXF5*Pdtojdokk^\L >. [;88,,/93>>;5*F0.054)&(;9?6&11,-=:7;<;>2/3C789//,(?LKA( @pK_e:%CU!7DjC'F73<=D@8 H<:-/(4E<1.##-*FW3*n<7L? =:A<<-1>9!":@;0'+S3+ LGED><3-HA=7*-5<5+E{ 0<5 & @DBA90174138Z`V8r*68* K       "C4067,-4=>69D2;XuoH4/%-9 @ ". #;!> 44(%2-6.0/$*8C9 Sta?1650+"$84QgZA ", S47;125)7/5*8/7;:',69@,69B!  ADD=4эj4,6>7,AFP?:*) $"-9~topxq~ux=c1 OILFD&w764FT4%/>1'!+7tgha}rdhjfeo|r?g9  LD>97E|sDXB54\S  )+.$7!%,xvy~wi|W}rs{m^gubm~eo_/K; >848??B)68=5Wug5%*5'O}a/-!!:|szYexi4?hmRFc>:'<\WB4UAI@ 2EAE??=;2;_bMlHn~zXg(!$ ^29qXqlzZEd|jnkn|tvtgM~yJE*<q\Re\E.,+&*8GaTIzyP\T<'-&$3Arv7zzhUm`xodzf{VgVlfjPaJ]:-c\+069D<<>NaUt|iNV*!>:/OI{E{hpujhqw~yzjsD=MDfOqp_NQ2aL*2,;:;?^z|uY=dhz~sZ.D ,-5Q|0lks[>`}stzl_rpp_Y?l|s_Yohq|s:E1Q K=;<8:lE^rD_`VMfTYlaoh_^! % (J^Yjλ4ei~|@[PjcwtmD;5HmI.+?sjdn7~|xAMrKQAzxtqMa̞G1{ko@PG{qy/ǍvuyB`9QCgQS3 J}buLVwulżO_}5~vL{P0T%Kfewp}~s}qz~}g_~5yIK R/L{uyp}ruppcQc<|qSX OU\|x~hg~wx}CtûCr_= ?*Liu}xu{}ihMSpyF<=ckKx |{G13J 1a_e\]eP\^V^Y\RQXZ`TIQask[bdWO^Mi_VZ`[^cOVVUZYVV_cqq[aNM`]`\mhopsgX./1 H D:v|{|qU||dn}0E9AXzwumw~~w~yL}~|e}{qlu!B<.PX~z|j^|}cw|E?8.]Z}ke{n֯N=04dxyf^qg\;;/k}sqc\zta{qDHL\94*ghz]¸}'697wrmfl3"S~flsl]kzpv}z~pteoV}wr|vnxp|zwO2J5oZt{~z{rbm~~zm390HHQn}^avغP -Q;w^pazθ՟5+H0ovVrYom)jGzvb|ŒӨa$%E>w[Ӗj0$]>r{b}Ѽ@!jIZHXNtWwvgyuV!?Frsv]uvjbdXV_ddxHe F>o}x*XP[YP{K<lizz X}|Ȼ t|§ S9-&HbӷO =I5Z7)('#" ""$"#$#" & $&""$" "$""$##$%#"$" $""!!&"%&#!#%Kɿ»#Ľ½½žŤFHvjojqt{_gspyYARr~lvjibZifa}wA9IVTWL}rDQceM]]ab`ihfxǁ@I8u2ilD9@jj[J_T=hxbNfX+DBFjR= Bk@#SX033dQ&*2,==.09b_c^KA9=bV=QX<_zsH,q<A- -86310MhD4*,WP.=`d1)2[^8;4*-9p& *@xFN>4*9A[]GDMA33/A]d~|K560><8/31BCWl"6wM>45Tc7..]Z!+*t'%&.1L_pc& }|Z_:'//E]I3A18:6>Gv9;>sD0.0Ye<8"K:*%"'&[|K3(,-)&&O~YQts8AXc3*,5Gg];4.94>5=4509u~hlH645Fr31:oG.Ad~}^:5PU""00WfZcg3 "#)9?CFXmks?Qyl~J/,BjL9296Vq\PSXOK=@>.y@L~I83Aj3:@mJ@ldYYvw3NY!;;:5]<3-MsB&7:MILYmkBK\t.Qqji=T@0P`Y;578;>?>NQcEVnIkb929Wl3:@qD9S5\tw1W`.)75&:==6@EXj\JJPAAUlgV@.Hcf|,QmfY 7qD/17kL+.:56/+Cs=*&\Y5 MvX2$:;Tb@4H\`K9@P]3.(=1'$&/9GJNQLOMkwI0#*]oR^r3Q][dD70JO02FfL!-1("KJ#3-'AV77SQGC/6RXH2/.99MwWWJ<.+8ONOKJKJQf_5 4XiNV^Ph(QXKm~Y&+]f2%Fi -+. 5l*"&,M3eL2.Wb==AxH>2+;Awqh~qLE@QKMIDlk/#4JssPBYaUn+QLY> G4Oh31Ip*"3(Lz 0gI$cLHa|69=J=8..+g6LcDJA(5HDgd?2CWlt]KateH?I]QMCUJl..]f28J|+2&*Fk)-es4cjN.Hye;4-./.Dbsl]G>DDKy`DA=avWJfX.&.?TQA4ET]QX)"_e)*I.-*b{ 'WgkpjDAekI49HABB62=CDA@C99OqO0IKLGhpDdt.0LKYQ@6B9819T+Go/0L{7))'%g]OYa`ND4@EL>:=7RI4?DD@A<6C01D<5@DYeLsZcWXVbXJj--04~]3K#P9693-,+=;@M^}~S[|oZIn]Xy245GSKAORMJUcv]A.mjF7&\r7).,:2 )FscwX4,SbGIfQSR\yCDTvI# (!02+,<8b#_VMרNMO`@" LghHRYXP>4*@ONv*=Xb@A5/17DTc@> ,̥d/yZBKI`"9>h~cWG42BU`R`Yy76,?b{rfkx:kɧfBGO<16&GBKIKTrr;*4CX`a\gg]ocWVQ<4Hcngtga > G9mܬR"-=TƍYOCWK0&8J\RVgs[cS?/&9jYgï8F2tƌK  }z#,lТVC`ѺDKMJX`d^P{1+vΝՖXl{QMj> @*(-40?Ώ;H\Z[ZTRUZRL4k򿗕}b9'.A90IJMU3E^>  33FT391&6ɝJ9=QR]]hT4'&=js>$!2Q[RNKB8P\d0&H.4 Vs#>*߆KBRNB0&9VidC!&!#s|oy$@ay/*;IcjtpjzN(%+BS^a_j]Vcg[J664>R >1:FBMveIڟ-'33nֆdXjipukpgJ*1M[PccddegiTN;03JUZ[K;NAEA919lw]99$GƔYfeN;%)>Yaegjd]bis]@35FMilhdbe`>aG@?=,0&-..3359HCHT/2Ebbcqmpnmpm\H7/Xowrpm{qrgcS >.&cC>@102>8EDA9.>JHJRϗm~yty~hMP32399.,",?=B:*45.2Fbɤjlx^   nsWi   > B9:>A>A637H;<=541+COLF2 9mIPa0 3D-;iA"I>9>AFC?>4,1""56BD19!$-. ON1:AD>;58004EA85.%75u¸A RND113433FFC7-,4@6  !OA<34.8I?30&&20JY70vC7*F"(0H7>]~tH75*6K6!# -    @I@>4@\dF=?52.&#*;;Uld4"#( 2(   AHG?9ے~˻:14E=2HLYIC32 #"' I>@00>BD)/J@+7AI9339B7I=31: QORJK-B?>IW<*-'8@> %""#9=-7@"A'.F?3=7A*:+?.*.=4U0 !OJE5D4MF>9_|r>26@*-3<" $:?6CE+3!*715>%./*$ 3FEIBDBA9AflZK_E80S?/5-9 $:/68?.44**0;8*4*%8I5M1!/N01[OWtrN+87FJRM=.1.8:E ' *=:#8'/;$(:./*/,-?74+0.?,7) DcXmgT?558;AB@" A1/C04 ( 0?8"5*<0>):9@+-4,%6&8!/".')G&8xl239CSX\F3C04!%7*=5242!+  .-:)A?>$(B.1I*#,1630&6"(<8:7J1 (;x[3@CVJG35-'!0+':*%145. .  !;H',7(2?86*+70* -*('%-<3$0)/5,;4 R#OPSOJ5B#2*#1%%6-71+* '%(75-,25<292-'4,(.,5-5,10'&%"-(3!!E- R)!DUK:0/5R(C),#IJ5`-. +04F6>=740CACTZK</#3D@+:<>08+8643@8=aK)*R ~q=#(9&\!S/6+C9BHM)* %.006>09570A5;55;PM?YE4890E:@3AJM0?,<,E>9E9"!!%"5*011"1!%@<[638>`-=4-5E4A;*"!&(494(+03P:IF33:E@117-+279(D<(V1$ S =?>@+/8B')0'3>4*e@.==)4Q'2JI+98,6/38.;42NIJM'B-@A9/CAG<5-4'>F70<%<0B;  T 9;94'&N')02*73.17>3/-7)-@850CL1/?85=-<-40>,1+3;8?73.9+-FBD68/+21&/)269747/6A&.>23430'/J+.C98;4GE037+1066:"14DF@8>=81+9.=8.8 NL7%;96-5>1-@047@65?K1)0 .?90BMH$IA&8P?1,538-#5.2&+:+$2+0E*D'2*2/3.5:4+32D:470C8I4,,60/5386@307a-@#'!BD@2H5,18+.).+453= %++:+329/.+590..$=631.+;03+25250+84*IB=@  ;:+4B'*61.+'+39)9(&<.31;+5056>8@91.@.8;:H4%,4& !A?47,I6>93/;;835"/$!>8<-//433-:18/6351/546?3E;;<>4A# = $J18=*;*1A#!46,9,)6"!:5(<1.242=:/33891/"89;?A0.819$ & : "=072D<9/2/43<9,,5. 983-38/0/5/:?/=936:03:694;:A()7 -C7+-;C94;1942D+4D$)/*A,779/3//4;123<6>4=A?27,.4 -4 &*<#&-',0/0&(#- .((21*#*#5.++0,0-041.71#%3+A7=;FC8 ,,96/478;.4713AB(0!60  )%?3659+1"@60'53.,%323449143;1?=+%.' "H596C38.382++&'1-,0=28<.;4(1*( "$GG76;53";384+0284(,07889A&93 "4==>=;*@9-7A1//,0730:7A7?#! "894/94.97,887./507((+   %GB.34,.,6.% " "!((   $8.&-,*0*.,+//13:;.(=C=,2464848AA:CA #E?6>899>7=F6-2 #99E6844<8)70 155)09=3 &B=C5  L<+&  (, !t8mk@icnV C eureka-editor-eureka-2.0.2/osx/EurekaApp/OSXCalls.h000066400000000000000000000031021464327712600220240ustar00rootroot00000000000000//------------------------------------------------------------------------ // MAC OS X NATIVE C-STYLE CALLS TO BE ACCESSED FROM THE MAIN PROGRAM //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2013 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ // // Module by Ioan Chera // #ifdef __APPLE__ #ifndef __Eureka_Doom_Editor__OSXCalls__ #define __Eureka_Doom_Editor__OSXCalls__ #include "filesystem.hpp" namespace fs = ghc::filesystem; class SString; // Currently used paths enum class macOSDirType { library, libraryAppSupport, libraryCache }; fs::path OSX_UserDomainDirectory(macOSDirType dirtype, const char *subdir); #endif /* defined(__Eureka_Doom_Editor__OSXCalls__) */ #endif eureka-editor-eureka-2.0.2/osx/EurekaApp/OSXCalls.mm000066400000000000000000000042551464327712600222200ustar00rootroot00000000000000//------------------------------------------------------------------------ // MAC OS X NATIVE C-STYLE CALLS TO BE ACCESSED FROM THE MAIN PROGRAM //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2013 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ // // Module by Ioan Chera // #ifdef __APPLE__ #include "m_strings.h" #import "Foundation/Foundation.h" #include "OSXCalls.h" // // OSX_UserDomainDirectory // // Returns the directory where to save configs // fs::path OSX_UserDomainDirectory(macOSDirType dirtype, const char *subdir) { NSSearchPathDirectory spd; switch (dirtype) { case macOSDirType::library: spd = NSLibraryDirectory; break; case macOSDirType::libraryAppSupport: spd = NSApplicationSupportDirectory; break; case macOSDirType::libraryCache: spd = NSCachesDirectory; break; } NSArray *paths = NSSearchPathForDirectoriesInDomains(spd, NSUserDomainMask, YES); if([paths count] <= 0) return "."; // shouldn't normally occur NSString *retDir = [paths objectAtIndex:0]; if(subdir) retDir = [retDir stringByAppendingPathComponent:[NSString stringWithCString:subdir encoding:NSUTF8StringEncoding]]; return [retDir cStringUsingEncoding:NSUTF8StringEncoding]; } #endif eureka-editor-eureka-2.0.2/osx/EurekaApp/eureka.entitlements000066400000000000000000000004021464327712600241340ustar00rootroot00000000000000 com.apple.security.cs.disable-library-validation eureka-editor-eureka-2.0.2/osx/README.rtf000066400000000000000000000025701464327712600200300ustar00rootroot00000000000000{\rtf1\mac\ansicpg10000\cocoartf1187\cocoasubrtf340 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \paperw11900\paperh16840\margl1440\margr1440\vieww12600\viewh7800\viewkind0 \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural \f0\b\fs32 \cf0 Eureka Editor - Mac OS X port \b0\fs24 \ \ This is a simple port to OS X of the Eureka Doom editor, originally for Linux, made by Andrew Apted.\ \ \b\fs28 \ul Installing \b0\fs24 \ulnone \ \ Just drag the Eureka Doom Editor (or Eureka Doom Editor.app) file to the Applications folder.\ \ \b\fs28 \ul Maintaining \b0\fs24 \ulnone \ \ Do note that Eureka for Mac stores its data inside \i (home folder)/Library/Application Support \i0 . From Finder, the \i Library \i0 folder may be hidden. Inside it you may look through the various game and mod editing settings and data.\ \ To access it, you need to press COMMAND-SHIFT-G from Finder to show the "Go To\'85" dialog, and type this inside the text field:\ \ \b ~/Library/Application Support/eureka-editor \b0 \ \ Don't worry about the "Library" name being localized (translated), the folder name can be written in English, and Finder will go to the correct location. For quick access to it, you can easily drag the folder icon from the Finder window title to the side bar.\ \ Text file and Mac porting by Ioan Chera.}eureka-editor-eureka-2.0.2/osx/TODO.txt000066400000000000000000000001021464327712600176510ustar00rootroot00000000000000- add support for opening files from drag-drop even after it's runeureka-editor-eureka-2.0.2/ports/000077500000000000000000000000001464327712600167105ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/ports/boom.ugh000066400000000000000000000177441464327712600203660ustar00rootroot00000000000000#------------------------------------------------------------------------ # BOOM definitions #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2018 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ supported_games doom doom2 #---- BOOM FEATURES ------------- feature gen_types 1 feature gen_sectors boom feature coop_dm_flags 1 feature pass_through 1 feature medusa_fixed 1 feature tuttifrutti_fixed 1 feature lax_sprites 1 #---- BOOM THINGS ------------- # Note: Boom and MBF just ignore the extra player starts thing 4001 p - 16 NULL "Player 5 start" thing 4002 p - 16 NULL "Player 6 start" thing 4003 p - 16 NULL "Player 7 start" thing 4004 p - 16 NULL "Player 8 start" thing 5001 - nv 20 NULL "BOOM: Point pusher" thing 5002 - nv 20 NULL "BOOM: Point puller" #---- BOOM LINETYPES ---------- # Modify the manual doors to support light_tag line 31 d "D1 Open and stay open" :tag line 1 d "DR Open door" :tag line 117 d "DR Open door /fast" :tag line 118 d "D1 Open and stay /fast" :tag line 26 k "DR Open blue door" :tag line 27 k "DR Open yellow door" :tag line 28 k "DR Open red door" :tag line 32 k "D1 Open blue door (stay)" :tag line 33 k "D1 Open red door (stay)" :tag line 34 k "D1 Open yellow door (stay)" :tag line 85 - "-- BOOM: Scroll Wall Right" line 191 - "SR BOOM: Donut" :tag line 146 - "W1 BOOM: Donut" :tag line 155 - "WR BOOM: Donut" :tag line 241 - "S1 BOOM: Floor Transfer /NXP" :tag line 189 - "S1 BOOM: Floor Transfer /TXP" :tag line 190 - "SR BOOM: Floor Transfer /TXP" :tag line 239 - "W1 BOOM: Floor Transfer /NXP" :tag line 153 - "W1 BOOM: Floor Transfer /TXP" :tag line 240 - "WR BOOM: Floor Transfer /NXP" :tag line 154 - "WR BOOM: Floor Transfer /TXP" :tag line 164 h "S1 BOOM: Crusher" :tag line 183 h "SR BOOM: Crusher" :tag line 184 h "SR BOOM: Crusher /slow" :tag line 165 h "S1 BOOM: Crusher /silent" :tag line 185 h "SR BOOM: Crusher /silent" :tag line 150 h "WR BOOM: Crusher /silent" :tag line 188 h "SR BOOM: Stop Crusher" :tag line 168 h "S1 BOOM: Stop Crusher" :tag line 160 g "S1 BOOM: Floor up 24 /TXP" :tag line 161 g "S1 BOOM: Floor up 24" :tag line 158 g "S1 BOOM: Floor up lowest tex" :tag line 179 g "SR BOOM: Floor up 24 /TXP" :tag line 180 g "SR BOOM: Floor up 24" :tag line 178 g "SR BOOM: Floor up 512" :tag line 176 g "SR BOOM: Floor up lowest tex" :tag line 142 g "W1 BOOM: Floor up 512" :tag line 147 g "WR BOOM: Floor up 512" :tag line 170 l "S1 BOOM: Light to 35" :tag line 171 l "S1 BOOM: Light to 255" :tag line 169 l "S1 BOOM: Light to highest nb" :tag line 173 l "S1 BOOM: Light to lowest nb" :tag line 192 l "SR BOOM: Light to highest nb" :tag line 194 l "SR BOOM: Light to lowest nb" :tag line 157 l "WR BOOM: Light to lowest nb" :tag line 172 l "S1 BOOM: Light Blinking" :tag line 193 l "SR BOOM: Light Blinking" :tag line 156 l "WR BOOM: Light Blinking" :tag line 167 c "S1 BOOM: Ceiling close flr+8" :tag line 204 c "S1 BOOM: Ceiling down HEF" :tag line 203 c "S1 BOOM: Ceiling down LEC" :tag line 166 c "S1 BOOM: Ceiling up HEC" :tag line 187 c "SR BOOM: Ceiling close flr+8" :tag line 206 c "SR BOOM: Ceiling down HEF" :tag line 205 c "SR BOOM: Ceiling down LEC" :tag line 186 c "SR BOOM: Ceiling up HEC" :tag line 145 c "W1 BOOM: Ceiling close" :tag line 200 c "W1 BOOM: Ceiling down HEF" :tag line 199 c "W1 BOOM: Ceiling down LEC" :tag line 152 c "WR BOOM: Ceiling close" :tag line 202 c "WR BOOM: Ceiling down HEF" :tag line 201 c "WR BOOM: Ceiling down LEC" :tag line 151 c "WR BOOM: Ceiling up HEC" :tag line 175 d "S1 BOOM: Close for 30s" :tag line 196 d "SR BOOM: Close for 30s" :tag line 197 e "g1 BOOM: Exit level" line 198 e "g1 BOOM: Secret exit" line 159 f "S1 BOOM: Floor down LEF /NX" :tag line 221 f "S1 BOOM: Floor down nlEF" :tag line 177 f "SR BOOM: Floor down LEF /NX" :tag line 222 f "SR BOOM: Floor down nlEF" :tag line 219 f "W1 BOOM: Floor down nlEF" :tag line 220 f "WR BOOM: Floor down nlEF" :tag line 143 p "W1 BOOM: Floor up 24 /TX" :tag line 148 p "WR BOOM: Floor up 24 /TX" :tag line 144 p "W1 BOOM: Floor up 32 /TX" :tag line 149 p "WR BOOM: Floor up 32 /TX" :tag line 162 m "S1 BOOM: Start Moving Floor" :tag line 181 m "SR BOOM: Start Moving Floor" :tag line 163 m "S1 BOOM: Stop Moving Floor" :tag line 182 m "SR BOOM: Stop Moving Floor" :tag line 211 m "SR BOOM: Floor Toggle" :tag line 212 m "WR BOOM: Floor Toggle" :tag line 213 l "-- BOOM: Transfer floor light" :tag line 261 l "-- BOOM: Transfer ceil light" :tag line 223 - "-- BOOM: Friction" :tag line 224 - "-- BOOM: Wind force" :tag line 225 - "-- BOOM: Current force" :tag line 226 - "-- BOOM: Point force" :tag line 242 - "-- BOOM: Deep water" :tag line 260 - "-- BOOM: Translucent" :line_id line 227 v "W1 BOOM: Elevator up" :tag line 228 v "WR BOOM: Elevator up" :tag line 229 v "S1 BOOM: Elevator up" :tag line 230 v "SR BOOM: Elevator up" :tag line 231 v "W1 BOOM: Elevator down" :tag line 232 v "WR BOOM: Elevator down" :tag line 233 v "S1 BOOM: Elevator down" :tag line 234 v "SR BOOM: Elevator down" :tag line 235 v "W1 BOOM: Elevator to trigger" :tag line 236 v "WR BOOM: Elevator to trigger" :tag line 237 v "S1 BOOM: Elevator to trigger" :tag line 238 v "SR BOOM: Elevator to trigger" :tag line 252 a "-- BOOM: Push floor" :tag line 216 a "-- BOOM: Push floor /accel" :tag line 247 a "-- BOOM: Push floor /disp" :tag line 253 a "-- BOOM: Push/Scr floor" :tag line 217 a "-- BOOM: Push/Scr floor /acc" :tag line 248 a "-- BOOM: Push/Scr floor /dis" :tag line 255 a "-- BOOM: Scroll X/Y offsets" line 254 a "-- BOOM: Scroll Wall /sync" :line_id line 214 a "-- BOOM: Scroll Ceil /accel" :tag line 245 a "-- BOOM: Scroll Ceil /disp" :tag line 250 a "-- BOOM: Scroll Ceil" :tag line 215 a "-- BOOM: Scroll Floor /accel" :tag line 246 a "-- BOOM: Scroll Floor /disp" :tag line 251 a "-- BOOM: Scroll Floor" :tag line 218 a "-- BOOM: Scroll Wall /accel" :line_id line 249 a "-- BOOM: Scroll Wall /disp" :line_id line 256 s "WR BOOM: Stair Raise 8" :tag line 257 s "WR BOOM: Stair Raise 16" :tag line 258 s "SR BOOM: Stair Raise 8" :tag line 259 s "SR BOOM: Stair Raise 16" :tag line 174 t "S1 BOOM: Teleport" :tag line 195 t "SR BOOM: Teleport" :tag line 268 t "W1 BOOM: Teleport /mon /silent" :tag line 269 t "WR BOOM: Teleport /mon /silent" :tag line 207 t "W1 BOOM: Teleport /silent /keepdir" :tag line 208 t "WR BOOM: Teleport /silent /keepdir" :tag line 209 t "S1 BOOM: Teleport /silent /keepdir" :tag line 210 t "SR BOOM: Teleport /silent /keepdir" :tag line 243 t "W1 BOOM: Teleport Line /silent /keepdir" :line_id line 244 t "WR BOOM: Teleport Line /silent /keepdir" :line_id line 262 t "W1 BOOM: Teleport Line /rev /silent /keepdir" :line_id line 263 t "WR BOOM: Teleport Line /rev /silent /keepdir" :line_id line 264 t "W1 BOOM: Teleport Line /rev /mon /silent /keepdir" :line_id line 265 t "WR BOOM: Teleport Line /rev /mon /silent /keepdir" :line_id line 266 t "W1 BOOM: Teleport Line /mon /silent /keepdir" :line_id line 267 t "WR BOOM: Teleport Line /mon /silent /keepdir" :line_id #---- GENERALIZED LINETYPES ---------- include "gen_types" eureka-editor-eureka-2.0.2/ports/edge.ugh000066400000000000000000000264161464327712600203320ustar00rootroot00000000000000#------------------------------------------------------------------------ # EDGE 1.35 definitions #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2016 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ if $ALLOW_BOOM is 1 include "mbf" endif feature tx_start 1 feature mix_textures_flats 1 feature extra_floors 1 feature slopes 1 #---- EDGE THINGS ---------- thing 7000 b n 20 NVSC "EDGE: Night vision" thing 7020 b n 20 JPCK "EDGE: Jetpack" thing 7015 k nl 20 YKEY "EDGE: Green keycard" thing 7017 k nl 20 YSKU "EDGE: Green skull key" thing 7031 h nl 20 ARM2 "EDGE: Purple armor" thing 7032 h nl 20 ARM1 "EDGE: Yellow armor" thing 7033 h nl 20 ARM1 "EDGE: Red armor" thing 7010 d - 16 SMT2 "EDGE: Grey stub" thing 7011 d - 10 BEXP "EDGE: Unstable barrel" thing 7041 - n 16 NULL "EDGE: Green glow" thing 7042 - n 16 NULL "EDGE: Red glow" thing 7043 - n 16 NULL "EDGE: Blue glow" thing 888 m - 16 SARGA3A7 "EDGE: Dog" thing 4050 m i 64 BSPI "EDGE: Stealth Arachnotron" thing 4051 m i 20 VILE "EDGE: Stealth Archvile" thing 4052 m i 24 BOSS "EDGE: Stealth Baron" thing 4053 m i 31 HEAD "EDGE: Stealth Cacodemon" thing 4054 m i 20 CPOS "EDGE: Stealth Chaingunner" thing 4055 m i 30 SARG "EDGE: Stealth Demon" thing 4056 m i 24 BOS2A1C1 "EDGE: Stealth Hell Knight" thing 4057 m i 20 TROO "EDGE: Stealth Imp" thing 4058 m i 48 FATT "EDGE: Stealth Mancubus" thing 4059 m i 20 SKEL "EDGE: Stealth Revenant" thing 4060 m i 20 SPOS "EDGE: Stealth Sargeant" thing 4061 m i 20 POSS "EDGE: Stealth Trooper" thing 7100 m - 20 SKELJ "EDGE: Revenant mkII" thing 7101 m n 64 TFOGB "EDGE: Imp spawner" thing 7102 m - 64 BSPIH "EDGE: Arachnotron mkII" thing 7103 m - 48 FATTH "EDGE: Mancubus mkII" #---- EDGE LINE TYPES ---------- linegroup b "Hubs" linegroup w "Sliding Door" line 400 y "-- EDGE: 3D Floor" :tag line 401 y "-- EDGE: 3D Floor /upper" :tag line 402 y "-- EDGE: 3D Floor /lower" :tag line 403 y "-- EDGE: Liquid" :tag line 404 y "-- EDGE: Liquid 80%" :tag line 405 y "-- EDGE: Liquid 60%" :tag line 406 y "-- EDGE: Liquid 40%" :tag line 407 y "-- EDGE: Liquid 20%" :tag line 408 y "-- EDGE: Liquid 0%" :tag line 413 y "-- EDGE: Thin 3D floor" :tag line 414 y "-- EDGE: Thin 3D floor 80%" :tag line 415 y "-- EDGE: Thin 3D floor 60%" :tag line 416 y "-- EDGE: Thin 3D floor 40%" :tag line 417 y "-- EDGE: Thin 3D floor 20%" :tag line 422 a "-- EDGE: Scroll right" line 423 a "-- EDGE: Scroll up" line 424 a "-- EDGE: Scroll down" line 425 a "-- EDGE: Scroll left/up" line 426 a "-- EDGE: Scroll left/down" line 427 a "-- EDGE: Scroll right/up" line 428 a "-- EDGE: Scroll right/down" line 409 r "-- EDGE: Translucency 80%" :line_id line 410 r "-- EDGE: Translucency 60%" :line_id line 411 r "-- EDGE: Translucency 40%" :line_id line 412 r "-- EDGE: Translucency 20%" :line_id line 567 s "-- EDGE: Slope Floor" line 568 s "-- EDGE: Slope Ceiling" line 569 s "-- EDGE: Slope F + C" line 442 w "DR Sliding door LEFT /mon" line 443 w "DR Sliding door LEFT" line 444 w "DR Sliding door LEFT /fast" line 445 w "D1 Sliding door LEFT" line 446 w "DR Sliding door RIGHT /mon" line 447 w "DR Sliding door RIGHT" line 448 w "DR Sliding door RIGHT /fast" line 449 w "D1 Sliding door RIGHT" line 450 w "DR Sliding door CENTER /mon" line 451 w "DR Sliding door CENTER" line 452 w "DR Sliding door CENTER /fast" line 453 w "D1 Sliding door CENTER" line 418 n "S1 EDGE: Enable RTS" :tag line 419 n "SR EDGE: Enable RTS" :tag line 420 n "W1 EDGE: Enable RTS" :tag line 421 n "WR EDGE: Enable RTS" :tag line 440 n "G1 EDGE: Enable RTS" :tag line 441 n "GR EDGE: Enable RTS" :tag line 454 n "W1 EDGE: Enable RTS /mon" :tag line 455 n "WR EDGE: Enable RTS /mon" :tag line 456 n "GR EDGE: Enable RTS /mon" :tag line 457 n "SR EDGE: DISABLE RTS" :tag line 458 n "WR EDGE: DISABLE RTS" :tag line 459 n "GR EDGE: DISABLE RTS" :tag line 460 n "WR EDGE: DISABLE RTS /mon" :tag line 461 n "GR EDGE: DISABLE RTS /mon" :tag line 470 s "-- EDGE: Ladder, 48 high" :tag line 471 s "-- EDGE: Ladder, 80 high" :tag line 472 s "-- EDGE: Ladder, 120 high" :tag line 473 s "-- EDGE: Ladder, 160 high" :tag line 474 s "-- EDGE: Ladder, 192 high" :tag line 475 s "-- EDGE: Ladder, 256 high" :tag line 476 s "-- EDGE: Ladder, 384 high" :tag line 477 s "-- EDGE: Ladder, 512 high" :tag line 478 s "-- EDGE: Ladder, 768 high" :tag line 479 s "-- EDGE: Ladder, no limit" :tag line 462 r "-- EDGE: Mirror" line 463 r "-- EDGE: Mirror /white" line 464 r "-- EDGE: Mirror /blue" line 465 r "-- EDGE: Mirror /red" line 466 r "-- EDGE: Mirror /green" line 480 r "-- EDGE: Portal /dark" :tag line 481 r "-- EDGE: Portal /light" :tag line 482 r "-- EDGE: Portal /light2" :tag line 483 r "-- EDGE: Portal /blue" :tag line 484 r "-- EDGE: Portal /green" :tag line 485 r "-- EDGE: Camera Portal" :tag line 486 r "-- EDGE: Camera Portal /white" :tag line 487 r "-- EDGE: Camera Portal /cyan" :tag line 488 r "-- EDGE: Camera Portal /rusty" :tag line 489 r "-- EDGE: Camera Portal /green" :tag line 501 b "WR Hub Exit to MAP01 / E1M1" line 502 b "WR Hub Exit to MAP02 / E1M2" line 503 b "WR Hub Exit to MAP03 / E1M3" line 504 b "WR Hub Exit to MAP04 / E1M4" line 505 b "WR Hub Exit to MAP05 / E1M5" line 506 b "WR Hub Exit to MAP06 / E1M6" line 507 b "WR Hub Exit to MAP07 / E1M7" line 508 b "WR Hub Exit to MAP08 / E1M8" line 509 b "WR Hub Exit to MAP09 / E1M9" line 510 b "WR Hub Exit to MAP10" line 511 b "WR Hub Exit to MAP11 / E2M1" line 512 b "WR Hub Exit to MAP12 / E2M2" line 513 b "WR Hub Exit to MAP13 / E2M3" line 514 b "WR Hub Exit to MAP14 / E2M4" line 515 b "WR Hub Exit to MAP15 / E2M5" line 516 b "WR Hub Exit to MAP16 / E2M6" line 517 b "WR Hub Exit to MAP17 / E2M7" line 518 b "WR Hub Exit to MAP18 / E2M8" line 519 b "WR Hub Exit to MAP19 / E2M9" line 520 b "WR Hub Exit to MAP20" line 521 b "WR Hub Exit to MAP21 / E3M1" line 522 b "WR Hub Exit to MAP22 / E3M2" line 523 b "WR Hub Exit to MAP23 / E3M3" line 524 b "WR Hub Exit to MAP24 / E3M4" line 525 b "WR Hub Exit to MAP25 / E3M5" line 526 b "WR Hub Exit to MAP26 / E3M6" line 527 b "WR Hub Exit to MAP27 / E3M7" line 528 b "WR Hub Exit to MAP28 / E3M8" line 529 b "WR Hub Exit to MAP29 / E3M9" line 530 b "WR Hub Exit to MAP30" line 531 b "WR Hub Exit to MAP31 / E4M1" line 532 b "WR Hub Exit to MAP32 / E4M2" line 533 b "WR Hub Exit to MAP33 / E4M3" line 534 b "WR Hub Exit to MAP34 / E4M4" line 535 b "WR Hub Exit to MAP35 / E4M5" line 536 b "WR Hub Exit to MAP36 / E4M6" line 537 b "WR Hub Exit to MAP37 / E4M7" line 538 b "WR Hub Exit to MAP38 / E4M8" line 539 b "WR Hub Exit to MAP39 / E4M9" line 490 d "DR EDGE: Green key door" line 491 d "D1 EDGE: Green key door" line 492 d "SR EDGE: Green key door" :tag line 493 d "S1 EDGE: Green key door" :tag line 494 d "D1 EDGE: Green key door /fast" line 580 d "DR EDGE: Gold key door" line 581 d "D1 EDGE: Gold key door" line 582 d "SR EDGE: Gold key door" :tag line 583 d "S1 EDGE: Gold key door" :tag line 584 d "DR EDGE: Silver key door" line 585 d "D1 EDGE: Silver key door" line 586 d "SR EDGE: Silver key door" :tag line 587 d "S1 EDGE: Silver key door" :tag line 588 d "DR EDGE: Brass key door" line 589 d "D1 EDGE: Brass key door" line 590 d "DR EDGE: Copper key door" line 591 d "D1 EDGE: Copper key door" line 592 d "DR EDGE: Steel key door" line 593 d "D1 EDGE: Steel key door" line 594 d "DR EDGE: Wooden key door" line 595 d "D1 EDGE: Wooden key door" line 596 d "DR EDGE: Fire key door" line 597 d "D1 EDGE: Fire key door" line 598 d "DR EDGE: Water key door" line 599 d "D1 EDGE: Water key door" line 800 a "-- EDGE: Align F1" :tag line 801 a "-- EDGE: Align F2" :tag line 802 a "-- EDGE: Align C1" :tag line 803 a "-- EDGE: Align C2" :tag line 804 a "-- EDGE: Align F1 + C1" :tag line 805 a "-- EDGE: Align F2 + C2" :tag line 810 a "-- EDGE: Align, scale F1" :tag line 811 a "-- EDGE: Align, scale F2" :tag line 812 a "-- EDGE: Align, scale C1" :tag line 813 a "-- EDGE: Align, scale C2" :tag line 814 a "-- EDGE: Align, scale F1 + C1" :tag line 815 a "-- EDGE: Align, scale C2 + C2" :tag line 820 a "-- EDGE: Scale F1" :tag line 821 a "-- EDGE: Scale F2" :tag line 822 a "-- EDGE: Scale C1" :tag line 823 a "-- EDGE: Scale C2" :tag line 824 a "-- EDGE: Scale F1 + C1" :tag line 825 a "-- EDGE: Scale F2 + C2" :tag # not in EDGE line 271 - "-- (Unsupported)" line 272 - "-- (Unsupported)" #---- EDGE SECTOR TYPES ---------- sector 29 "EDGE: Hub entry area" sector 4466 "EDGE Water" sector 4418 "EDGE Water + Current N" sector 4419 "EDGE Water + Current NE" sector 4420 "EDGE Water + Current E" sector 4421 "EDGE Water + Current SE" sector 4422 "EDGE Water + Current S" sector 4423 "EDGE Water + Current SW" sector 4424 "EDGE Water + Current W" sector 4425 "EDGE Water + Current NW" sector 4467 "EDGE Slime (no damage)" sector 4468 "EDGE Slime" sector 4426 "EDGE Slime + Current N" sector 4427 "EDGE Slime + Current NE" sector 4428 "EDGE Slime + Current E" sector 4429 "EDGE Slime + Current SE" sector 4430 "EDGE Slime + Current S" sector 4431 "EDGE Slime + Current SW" sector 4432 "EDGE Slime + Current W" sector 4433 "EDGE Slime + Current NW" sector 4469 "EDGE Lava (no damage)" sector 4470 "EDGE Lava" sector 4434 "EDGE Lava + Current N" sector 4435 "EDGE Lava + Current NE" sector 4436 "EDGE Lava + Current E" sector 4437 "EDGE Lava + Current SE" sector 4438 "EDGE Lava + Current S" sector 4439 "EDGE Lava + Current SW" sector 4440 "EDGE Lava + Current W" sector 4441 "EDGE Lava + Current NW" sector 4442 "EDGE Push N" sector 4443 "EDGE Push NE" sector 4444 "EDGE Push E" sector 4445 "EDGE Push SE" sector 4446 "EDGE Push S" sector 4447 "EDGE Push SW" sector 4448 "EDGE Push W" sector 4449 "EDGE Push NW" sector 4450 "EDGE Scroll Floor N" sector 4451 "EDGE Scroll Floor NE" sector 4452 "EDGE Scroll Floor E" sector 4453 "EDGE Scroll Floor SE" sector 4454 "EDGE Scroll Floor S" sector 4455 "EDGE Scroll Floor SW" sector 4456 "EDGE Scroll Floor W" sector 4457 "EDGE Scroll Floor NW" sector 4458 "EDGE Scroll + Push N" sector 4459 "EDGE Scroll + Push NE" sector 4460 "EDGE Scroll + Push E" sector 4461 "EDGE Scroll + Push SE" sector 4462 "EDGE Scroll + Push S" sector 4463 "EDGE Scroll + Push SW" sector 4464 "EDGE Scroll + Push W" sector 4465 "EDGE Scroll + Push NW" eureka-editor-eureka-2.0.2/ports/eternity.ugh000066400000000000000000000712511464327712600212660ustar00rootroot00000000000000#------------------------------------------------------------------------ # Eternity Source Port #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2015 Ioan Chera # Copyright (C) 2001-2019 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ # Pull in the Boom/MBF definitions, but only when Hexen-style # specials are not being used. if $MAP_FORMAT not DOOM set $ALLOW_BOOM 0 set $HEXEN_SPECIALS 1 endif if $ALLOW_BOOM is 1 include "mbf" endif map_formats DOOM UDMF supported_games doom doom2 heretic hexen strife udmf_namespace Eternity feature 3d_midtex 1 feature tx_start 1 feature mix_textures_flats 1 feature slopes 10 #TODO: thing flag 512 "Dormant" - like in Hexen #---- ETERNITY THINGS ------------------ thinggroup s DAD "Environment Sounds" thing 5003 - nv 20 NULL "EE: Camera spot" thing 5004 - nv 20 NULL "EE: ExtraData" thing 5006 - nv 20 NULL "EE: SkyBox camera" thing 5007 - nv 20 NULL "EE: Particle drip" thing 9001 - nv 20 _MSP "EE: Map spot" thing 9013 - nv 20 _MSP "EE: Map spot w/ gravity" thing 9027 - nv 20 NULL "EE: Red fountain" thing 9028 - nv 20 NULL "EE: Green fountain" thing 9029 - nv 20 NULL "EE: Blue fountain" thing 9030 - nv 20 NULL "EE: Yellow fountain" thing 9031 - nv 20 NULL "EE: Purple fountain" thing 9032 - nv 20 NULL "EE: Black fountain" thing 9033 - nv 20 NULL "EE: White fountain" thing 9300 - nv 16 NULL "EE: Polyobj anchor" thing 9301 - npv 16 NULL "EE: Polyobj spawnspot" thing 9302 - npv 16 NULL "EE: Polycrush spawnspot" thing 9303 - npv 16 NULL "EE: Polyburn spawnspot" thing 1200 s nv 16 NULL "EE: Enviro Sequence 00" thing 1201 s nv 16 NULL "EE: Enviro Sequence 01" thing 1202 s nv 16 NULL "EE: Enviro Sequence 02" thing 1203 s nv 16 NULL "EE: Enviro Sequence 03" thing 1204 s nv 16 NULL "EE: Enviro Sequence 04" thing 1205 s nv 16 NULL "EE: Enviro Sequence 05" thing 1206 s nv 16 NULL "EE: Enviro Sequence 06" thing 1207 s nv 16 NULL "EE: Enviro Sequence 07" thing 1208 s nv 16 NULL "EE: Enviro Sequence 08" thing 1209 s nv 16 NULL "EE: Enviro Sequence 09" thing 1210 s nv 16 NULL "EE: Enviro Sequence 10" thing 1211 s nv 16 NULL "EE: Enviro Sequence 11" thing 1212 s nv 16 NULL "EE: Enviro Sequence 12" thing 1213 s nv 16 NULL "EE: Enviro Sequence 13" thing 1214 s nv 16 NULL "EE: Enviro Sequence 14" thing 1215 s nv 16 NULL "EE: Enviro Sequence 15" thing 1216 s nv 16 NULL "EE: Enviro Sequence 16" thing 1217 s nv 16 NULL "EE: Enviro Sequence 17" thing 1218 s nv 16 NULL "EE: Enviro Sequence 18" thing 1219 s nv 16 NULL "EE: Enviro Sequence 19" thing 1220 s nv 16 NULL "EE: Enviro Sequence 20" thing 1221 s nv 16 NULL "EE: Enviro Sequence 21" thing 1222 s nv 16 NULL "EE: Enviro Sequence 22" thing 1223 s nv 16 NULL "EE: Enviro Sequence 23" thing 1224 s nv 16 NULL "EE: Enviro Sequence 24" thing 1225 s nv 16 NULL "EE: Enviro Sequence 25" thing 1226 s nv 16 NULL "EE: Enviro Sequence 26" thing 1227 s nv 16 NULL "EE: Enviro Sequence 27" thing 1228 s nv 16 NULL "EE: Enviro Sequence 28" thing 1229 s nv 16 NULL "EE: Enviro Sequence 29" thing 1230 s nv 16 NULL "EE: Enviro Sequence 30" thing 1231 s nv 16 NULL "EE: Enviro Sequence 31" thing 1232 s nv 16 NULL "EE: Enviro Sequence 32" thing 1233 s nv 16 NULL "EE: Enviro Sequence 33" thing 1234 s nv 16 NULL "EE: Enviro Sequence 34" thing 1235 s nv 16 NULL "EE: Enviro Sequence 35" thing 1236 s nv 16 NULL "EE: Enviro Sequence 36" thing 1237 s nv 16 NULL "EE: Enviro Sequence 37" thing 1238 s nv 16 NULL "EE: Enviro Sequence 38" thing 1239 s nv 16 NULL "EE: Enviro Sequence 39" thing 1240 s nv 16 NULL "EE: Enviro Sequence 40" thing 1241 s nv 16 NULL "EE: Enviro Sequence 41" thing 1242 s nv 16 NULL "EE: Enviro Sequence 42" thing 1243 s nv 16 NULL "EE: Enviro Sequence 43" thing 1244 s nv 16 NULL "EE: Enviro Sequence 44" thing 1245 s nv 16 NULL "EE: Enviro Sequence 45" thing 1246 s nv 16 NULL "EE: Enviro Sequence 46" thing 1247 s nv 16 NULL "EE: Enviro Sequence 47" thing 1248 s nv 16 NULL "EE: Enviro Sequence 48" thing 1249 s nv 16 NULL "EE: Enviro Sequence 49" thing 1250 s nv 16 NULL "EE: Enviro Sequence 50" thing 1251 s nv 16 NULL "EE: Enviro Sequence 51" thing 1252 s nv 16 NULL "EE: Enviro Sequence 52" thing 1253 s nv 16 NULL "EE: Enviro Sequence 53" thing 1254 s nv 16 NULL "EE: Enviro Sequence 54" thing 1255 s nv 16 NULL "EE: Enviro Sequence 55" thing 1256 s nv 16 NULL "EE: Enviro Sequence 56" thing 1257 s nv 16 NULL "EE: Enviro Sequence 57" thing 1258 s nv 16 NULL "EE: Enviro Sequence 58" thing 1259 s nv 16 NULL "EE: Enviro Sequence 59" thing 1260 s nv 16 NULL "EE: Enviro Sequence 60" thing 1261 s nv 16 NULL "EE: Enviro Sequence 61" thing 1262 s nv 16 NULL "EE: Enviro Sequence 62" thing 1263 s nv 16 NULL "EE: Enviro Sequence 63" thing 1264 s nv 16 NULL "EE: Enviro Sequence 64" thing 1265 s nv 16 NULL "EE: Enviro Sequence 65" thing 1266 s nv 16 NULL "EE: Enviro Sequence 66" thing 1267 s nv 16 NULL "EE: Enviro Sequence 67" thing 1268 s nv 16 NULL "EE: Enviro Sequence 68" thing 1269 s nv 16 NULL "EE: Enviro Sequence 69" thing 1270 s nv 16 NULL "EE: Enviro Sequence 70" thing 1271 s nv 16 NULL "EE: Enviro Sequence 71" thing 1272 s nv 16 NULL "EE: Enviro Sequence 72" thing 1273 s nv 16 NULL "EE: Enviro Sequence 73" thing 1274 s nv 16 NULL "EE: Enviro Sequence 74" thing 1275 s nv 16 NULL "EE: Enviro Sequence 75" thing 1276 s nv 16 NULL "EE: Enviro Sequence 76" thing 1277 s nv 16 NULL "EE: Enviro Sequence 77" thing 1278 s nv 16 NULL "EE: Enviro Sequence 78" thing 1279 s nv 16 NULL "EE: Enviro Sequence 79" thing 1280 s nv 16 NULL "EE: Enviro Sequence 80" thing 1281 s nv 16 NULL "EE: Enviro Sequence 81" thing 1282 s nv 16 NULL "EE: Enviro Sequence 82" thing 1283 s nv 16 NULL "EE: Enviro Sequence 83" thing 1284 s nv 16 NULL "EE: Enviro Sequence 84" thing 1285 s nv 16 NULL "EE: Enviro Sequence 85" thing 1286 s nv 16 NULL "EE: Enviro Sequence 86" thing 1287 s nv 16 NULL "EE: Enviro Sequence 87" thing 1288 s nv 16 NULL "EE: Enviro Sequence 88" thing 1289 s nv 16 NULL "EE: Enviro Sequence 89" thing 1290 s nv 16 NULL "EE: Enviro Sequence 90" thing 1291 s nv 16 NULL "EE: Enviro Sequence 91" thing 1292 s nv 16 NULL "EE: Enviro Sequence 92" thing 1293 s nv 16 NULL "EE: Enviro Sequence 93" thing 1294 s nv 16 NULL "EE: Enviro Sequence 94" thing 1295 s nv 16 NULL "EE: Enviro Sequence 95" thing 1296 s nv 16 NULL "EE: Enviro Sequence 96" thing 1297 s nv 16 NULL "EE: Enviro Sequence 97" thing 1298 s nv 16 NULL "EE: Enviro Sequence 98" thing 1299 s nv 16 NULL "EE: Enviro Sequence 99" thing 1300 s nv 16 NULL "EE: Enviro Sequence Ex" thing 1400 s nv 16 NULL "EE: Sector Sequence 00" thing 1401 s nv 16 NULL "EE: Sector Sequence 01" thing 1402 s nv 16 NULL "EE: Sector Sequence 02" thing 1403 s nv 16 NULL "EE: Sector Sequence 03" thing 1404 s nv 16 NULL "EE: Sector Sequence 04" thing 1405 s nv 16 NULL "EE: Sector Sequence 05" thing 1406 s nv 16 NULL "EE: Sector Sequence 06" thing 1407 s nv 16 NULL "EE: Sector Sequence 07" thing 1408 s nv 16 NULL "EE: Sector Sequence 08" thing 1409 s nv 16 NULL "EE: Sector Sequence 09" thing 1410 s nv 16 NULL "EE: Sector Sequence 10" thing 1411 s nv 16 NULL "EE: Sector Sequence 11" thing 1412 s nv 16 NULL "EE: Sector Sequence 12" thing 1413 s nv 16 NULL "EE: Sector Sequence 13" thing 1414 s nv 16 NULL "EE: Sector Sequence 14" thing 1415 s nv 16 NULL "EE: Sector Sequence 15" thing 1416 s nv 16 NULL "EE: Sector Sequence 16" thing 1417 s nv 16 NULL "EE: Sector Sequence 17" thing 1418 s nv 16 NULL "EE: Sector Sequence 18" thing 1419 s nv 16 NULL "EE: Sector Sequence 19" thing 1420 s nv 16 NULL "EE: Sector Sequence 20" thing 1421 s nv 16 NULL "EE: Sector Sequence 21" thing 1422 s nv 16 NULL "EE: Sector Sequence 22" thing 1423 s nv 16 NULL "EE: Sector Sequence 23" thing 1424 s nv 16 NULL "EE: Sector Sequence 24" thing 1425 s nv 16 NULL "EE: Sector Sequence 25" thing 1426 s nv 16 NULL "EE: Sector Sequence 26" thing 1427 s nv 16 NULL "EE: Sector Sequence 27" thing 1428 s nv 16 NULL "EE: Sector Sequence 28" thing 1429 s nv 16 NULL "EE: Sector Sequence 29" thing 1430 s nv 16 NULL "EE: Sector Sequence 30" thing 1431 s nv 16 NULL "EE: Sector Sequence 31" thing 1432 s nv 16 NULL "EE: Sector Sequence 32" thing 1433 s nv 16 NULL "EE: Sector Sequence 33" thing 1434 s nv 16 NULL "EE: Sector Sequence 34" thing 1435 s nv 16 NULL "EE: Sector Sequence 35" thing 1436 s nv 16 NULL "EE: Sector Sequence 36" thing 1437 s nv 16 NULL "EE: Sector Sequence 37" thing 1438 s nv 16 NULL "EE: Sector Sequence 38" thing 1439 s nv 16 NULL "EE: Sector Sequence 39" thing 1440 s nv 16 NULL "EE: Sector Sequence 40" thing 1441 s nv 16 NULL "EE: Sector Sequence 41" thing 1442 s nv 16 NULL "EE: Sector Sequence 42" thing 1443 s nv 16 NULL "EE: Sector Sequence 43" thing 1444 s nv 16 NULL "EE: Sector Sequence 44" thing 1445 s nv 16 NULL "EE: Sector Sequence 45" thing 1446 s nv 16 NULL "EE: Sector Sequence 46" thing 1447 s nv 16 NULL "EE: Sector Sequence 47" thing 1448 s nv 16 NULL "EE: Sector Sequence 48" thing 1449 s nv 16 NULL "EE: Sector Sequence 49" thing 1450 s nv 16 NULL "EE: Sector Sequence 50" thing 1451 s nv 16 NULL "EE: Sector Sequence 51" thing 1452 s nv 16 NULL "EE: Sector Sequence 52" thing 1453 s nv 16 NULL "EE: Sector Sequence 53" thing 1454 s nv 16 NULL "EE: Sector Sequence 54" thing 1455 s nv 16 NULL "EE: Sector Sequence 55" thing 1456 s nv 16 NULL "EE: Sector Sequence 56" thing 1457 s nv 16 NULL "EE: Sector Sequence 57" thing 1458 s nv 16 NULL "EE: Sector Sequence 58" thing 1459 s nv 16 NULL "EE: Sector Sequence 59" thing 1460 s nv 16 NULL "EE: Sector Sequence 60" thing 1461 s nv 16 NULL "EE: Sector Sequence 61" thing 1462 s nv 16 NULL "EE: Sector Sequence 62" thing 1463 s nv 16 NULL "EE: Sector Sequence 63" thing 1464 s nv 16 NULL "EE: Sector Sequence 64" thing 1465 s nv 16 NULL "EE: Sector Sequence 65" thing 1466 s nv 16 NULL "EE: Sector Sequence 66" thing 1467 s nv 16 NULL "EE: Sector Sequence 67" thing 1468 s nv 16 NULL "EE: Sector Sequence 68" thing 1469 s nv 16 NULL "EE: Sector Sequence 69" thing 1470 s nv 16 NULL "EE: Sector Sequence 70" thing 1471 s nv 16 NULL "EE: Sector Sequence 71" thing 1472 s nv 16 NULL "EE: Sector Sequence 72" thing 1473 s nv 16 NULL "EE: Sector Sequence 73" thing 1474 s nv 16 NULL "EE: Sector Sequence 74" thing 1475 s nv 16 NULL "EE: Sector Sequence 75" thing 1476 s nv 16 NULL "EE: Sector Sequence 76" thing 1477 s nv 16 NULL "EE: Sector Sequence 77" thing 1478 s nv 16 NULL "EE: Sector Sequence 78" thing 1479 s nv 16 NULL "EE: Sector Sequence 79" thing 1480 s nv 16 NULL "EE: Sector Sequence 80" thing 1481 s nv 16 NULL "EE: Sector Sequence 81" thing 1482 s nv 16 NULL "EE: Sector Sequence 82" thing 1483 s nv 16 NULL "EE: Sector Sequence 83" thing 1484 s nv 16 NULL "EE: Sector Sequence 84" thing 1485 s nv 16 NULL "EE: Sector Sequence 85" thing 1486 s nv 16 NULL "EE: Sector Sequence 86" thing 1487 s nv 16 NULL "EE: Sector Sequence 87" thing 1488 s nv 16 NULL "EE: Sector Sequence 88" thing 1489 s nv 16 NULL "EE: Sector Sequence 89" thing 1490 s nv 16 NULL "EE: Sector Sequence 90" thing 1491 s nv 16 NULL "EE: Sector Sequence 91" thing 1492 s nv 16 NULL "EE: Sector Sequence 92" thing 1493 s nv 16 NULL "EE: Sector Sequence 93" thing 1494 s nv 16 NULL "EE: Sector Sequence 94" thing 1495 s nv 16 NULL "EE: Sector Sequence 95" thing 1496 s nv 16 NULL "EE: Sector Sequence 96" thing 1497 s nv 16 NULL "EE: Sector Sequence 97" thing 1498 s nv 16 NULL "EE: Sector Sequence 98" thing 1499 s nv 16 NULL "EE: Sector Sequence 99" thing 1500 s nv 16 NULL "EE: Sector Sequence Ex" thing 14001 s nv 16 NULL "EE: Ambience 01" thing 14002 s nv 16 NULL "EE: Ambience 02" thing 14003 s nv 16 NULL "EE: Ambience 03" thing 14004 s nv 16 NULL "EE: Ambience 04" thing 14005 s nv 16 NULL "EE: Ambience 05" thing 14006 s nv 16 NULL "EE: Ambience 06" thing 14007 s nv 16 NULL "EE: Ambience 07" thing 14008 s nv 16 NULL "EE: Ambience 08" thing 14009 s nv 16 NULL "EE: Ambience 09" thing 14010 s nv 16 NULL "EE: Ambience 10" thing 14011 s nv 16 NULL "EE: Ambience 11" thing 14012 s nv 16 NULL "EE: Ambience 12" thing 14013 s nv 16 NULL "EE: Ambience 13" thing 14014 s nv 16 NULL "EE: Ambience 14" thing 14015 s nv 16 NULL "EE: Ambience 15" thing 14016 s nv 16 NULL "EE: Ambience 16" thing 14017 s nv 16 NULL "EE: Ambience 17" thing 14018 s nv 16 NULL "EE: Ambience 18" thing 14019 s nv 16 NULL "EE: Ambience 19" thing 14020 s nv 16 NULL "EE: Ambience 20" thing 14021 s nv 16 NULL "EE: Ambience 21" thing 14022 s nv 16 NULL "EE: Ambience 22" thing 14023 s nv 16 NULL "EE: Ambience 23" thing 14024 s nv 16 NULL "EE: Ambience 24" thing 14025 s nv 16 NULL "EE: Ambience 25" thing 14026 s nv 16 NULL "EE: Ambience 26" thing 14027 s nv 16 NULL "EE: Ambience 27" thing 14028 s nv 16 NULL "EE: Ambience 28" thing 14029 s nv 16 NULL "EE: Ambience 29" thing 14030 s nv 16 NULL "EE: Ambience 30" thing 14031 s nv 16 NULL "EE: Ambience 31" thing 14032 s nv 16 NULL "EE: Ambience 32" thing 14033 s nv 16 NULL "EE: Ambience 33" thing 14034 s nv 16 NULL "EE: Ambience 34" thing 14035 s nv 16 NULL "EE: Ambience 35" thing 14036 s nv 16 NULL "EE: Ambience 36" thing 14037 s nv 16 NULL "EE: Ambience 37" thing 14038 s nv 16 NULL "EE: Ambience 38" thing 14039 s nv 16 NULL "EE: Ambience 39" thing 14040 s nv 16 NULL "EE: Ambience 40" thing 14041 s nv 16 NULL "EE: Ambience 41" thing 14042 s nv 16 NULL "EE: Ambience 42" thing 14043 s nv 16 NULL "EE: Ambience 43" thing 14044 s nv 16 NULL "EE: Ambience 44" thing 14045 s nv 16 NULL "EE: Ambience 45" thing 14046 s nv 16 NULL "EE: Ambience 46" thing 14047 s nv 16 NULL "EE: Ambience 47" thing 14048 s nv 16 NULL "EE: Ambience 48" thing 14049 s nv 16 NULL "EE: Ambience 49" thing 14050 s nv 16 NULL "EE: Ambience 50" thing 14051 s nv 16 NULL "EE: Ambience 51" thing 14052 s nv 16 NULL "EE: Ambience 52" thing 14053 s nv 16 NULL "EE: Ambience 53" thing 14054 s nv 16 NULL "EE: Ambience 54" thing 14055 s nv 16 NULL "EE: Ambience 55" thing 14056 s nv 16 NULL "EE: Ambience 56" thing 14057 s nv 16 NULL "EE: Ambience 57" thing 14058 s nv 16 NULL "EE: Ambience 58" thing 14059 s nv 16 NULL "EE: Ambience 59" thing 14060 s nv 16 NULL "EE: Ambience 60" thing 14061 s nv 16 NULL "EE: Ambience 61" thing 14062 s nv 16 NULL "EE: Ambience 62" thing 14063 s nv 16 NULL "EE: Ambience 63" thing 14064 s nv 16 NULL "EE: Ambience 64" thing 14065 s nv 16 NULL "EE: Ambience Ex" #---- HEXEN-STYLE SPECIALS ---------- if $HEXEN_SPECIALS is 1 clear lines feature tag_666 0 feature strife_flags 0 feature gen_lines 0 feature gen_sectors zdoom include "hexen_groups" include "hexen_sectors" special 0 - "NOTHING" # Floors special 22 f "Floor_LowerToNearest" :tag speed change special 21 f "Floor_LowerToLowest" :tag speed change special 242 f "Floor_LowerToHighest" :tag speed lip adjust? special 20 f "Floor_LowerByValue" :tag speed dist change special 36 f "Floor_LowerByValueTimes8" :tag speed dist_x8 change special 66 f "Floor_LowerInstant" :tag - dist_x8 change special 25 f "Floor_RaiseToNearest" :tag speed change crush special 24 f "Floor_RaiseToHighest" :tag speed change crush special 238 f "Floor_RaiseToLowestCeiling" :tag speed change crush gap special 23 f "Floor_RaiseByValue" :tag speed dist change crush special 35 f "Floor_RaiseByValueTimes8" :tag speed dist_x8 change crush special 240 f "Floor_RaiseByTexture" :tag speed change crush special 67 f "Floor_RaiseInstant" :tag - dist_x8 change crush special 28 f "Floor_RaiseAndCrush" :tag speed damage special 46 f "Floor_CrushStop" :tag special 37 f "Floor_MoveToValue" :tag speed dist negate? change special 68 f "Floor_MoveToValueTimes8" :tag speed height_x8 negate? change special 250 f "Floor_Donut" :tag speed speed special 138 f "Floor_Waggle" :tag amp speed offset time special 235 f "Floor_TransferTrigger" :tag special 236 f "Floor_TransferNumeric" :tag # NOTE: specials above 255 can't be used in Hexen format. # Ceilings special 253 c "Ceiling_LowerToLowest" :tag speed change crush special 254 c "Ceiling_LowerToFloor" :tag speed change crush gap special 192 c "Ceiling_LowerToHighestFloor" :tag speed change crush gap special 40 c "Ceiling_LowerByValue" :tag speed dist change crush special 199 c "Ceiling_LowerByValueTimes8" :tag speed dist_x8 change crush special 193 c "Ceiling_LowerInstant" :tag - dist_x8 change crush special 252 c "Ceiling_RaiseToNearest" :tag speed change special 41 c "Ceiling_RaiseByValue" :tag speed dist change special 198 c "Ceiling_RaiseByValueTimes8" :tag speed dist_x8 change special 194 c "Ceiling_RaiseInstant" :tag - dist_x8 change special 47 c "Ceiling_MoveToValue" :tag speed height negate? change special 69 c "Ceiling_MoveToValueTimes8" :tag speed height_x8 negate? change special 38 c "Ceiling_Waggle" :tag amp speed offset time special 43 c "Ceiling_LowerAndCrush" :tag speed damage crush_mode special 97 c "Ceiling_LowerAndCrushDist" :tag speed damage gap crush_mode special 42 c "Ceiling_CrushAndRaise" :tag speed damage crush_mode special 196 c "Ceiling_CrushAndRaiseA" :tag down_speed up_speed damage crush_mode special 197 c "Ceiling_CrushAndRaiseSilentA" :tag down_speed up_speed damage crush_mode special 168 c "Ceiling_CrushAndRaiseDist" :tag gap speed damage crush_mode special 104 c "Ceiling_CrushAndRaiseSilentDist" :tag gap speed damage crush_mode special 45 c "Ceiling_CrushRaiseAndStay" :tag speed damage crush_mode special 195 c "Ceiling_CrushRaiseAndStayA" :tag down_speed up_speed damage crush_mode special 255 c "Ceiling_CrushRaiseAndStaySilA" :tag down_speed up_speed damage crush_mode special 44 c "Ceiling_CrushStop" :tag stop_mode # Doors special 12 d "Door_Raise" :tag speed delay light_tag:tag special 13 d "Door_LockedRaise" :tag speed delay lock light_tag:tag special 11 d "Door_Open" :tag speed light_tag:tag special 10 d "Door_Close" :tag speed light_tag:tag special 105 d "Door_WaitRaise" :tag speed delay wait light_tag:tag special 106 d "Door_WaitClose" :tag speed delay wait light_tag:tag special 249 d "Door_CloseWaitOpen" :tag speed delay light_tag:tag # Lifts special 62 g "Plat_DownWaitUpStay" :tag speed delay special 206 g "Plat_DownWaitUpStayLip" :tag speed delay lip sound_type special 63 g "Plat_DownByValue" :tag speed delay dist_x8 special 64 g "Plat_UpWaitDownStay" :tag speed delay special 65 g "Plat_UpByValue" :tag speed delay dist_x8 special 230 g "Plat_UpByValueStayTx" :tag speed dist_x8 special 228 g "Plat_RaiseAndStayTx0" :tag speed lock_out special 60 g "Plat_PerpetualRaise" :tag speed delay special 207 g "Plat_PerpetualRaiseLip" :tag speed delay lip special 231 g "Plat_ToggleCeiling" :tag special 61 g "Plat_Stop" :tag stop_mode # Elevators & Pillars special 95 e "FloorAndCeiling_LowerByValue" :tag speed dist special 96 e "FloorAndCeiling_RaiseByValue" :tag speed dist special 251 e "FloorAndCeiling_LowerRaise" :tag floor_speed ceil_speed boom_emu special 247 e "Elevator_LowerToNearest" :tag speed special 245 e "Elevator_RaiseToNearest" :tag speed special 246 e "Elevator_MoveToFloor" :tag speed special 30 e "Pillar_Open" :tag speed floor_dist ceil_dist special 29 e "Pillar_Build" :tag speed dist special 94 e "Pillar_BuildAndCrush" :tag speed dist damage # Stairs special 27 q "Stairs_BuildUp" :tag speed height delay reset_delay special 217 q "Stairs_BuildUpDoom" :tag speed height delay reset_delay # Sector special 181 s "Plane_Align" floor_side ceil_side special 118 s "Plane_Copy" front_floor_tag:tag front_ceil_tag:tag back_floor_tag:tag back_ceil_tag:tag share_flags special 190 s "Sky transfer" :line_id 255 sky_flip? special 140 s "Sector_ChangeSound" :tag sound_seq special 185 s "Sector_SetRotation" :tag floor_angle ceil_angle special 187 s "Sector_SetFloorPanning" :tag x_offset x_frac y_offset y_frac special 186 s "Sector_SetCeilingPanning" :tag x_offset x_frac y_offset y_frac special 218 s "Sector_SetWind" :tag force angle flags special 219 s "Sector_SetFriction" :tag special 220 s "Sector_SetCurrent" :tag force angle flags special 227 s "PointPush_SetForce" :tag :tid force use_line_angle? # Lighting special 233 l "Light_MinNeighbor" :tag special 111 l "Light_LowerByValue" :tag light special 234 l "Light_MaxNeighbor" :tag special 110 l "Light_RaiseByValue" :tag light special 112 l "Light_ChangeToValue" :tag light special 113 l "Light_Fade" :tag light time special 114 l "Light_Glow" :tag high low time special 115 l "Light_Flicker" :tag high low special 116 l "Light_Strobe" :tag high low high_time low_time special 232 l "Light_StrobeDoom" :tag high_time low_time # Teleporters special 70 u "Teleport" :tid :tag special 71 u "Teleport_NoFog" :tid use_angle? :tag keep_height special 215 u "Teleport_Line" - :line_id flip_180? # Things special 130 t "Thing_Activate" :tid special 131 t "Thing_Deactivate" :tid special 17 t "Thing_Raise" :tid special 135 t "Thing_Spawn" :tid type_id angle new_id special 137 t "Thing_SpawnNoFog" :tid type_id angle new_id special 134 t "Thing_Projectile" :tid type_id angle speed up_speed special 136 t "Thing_ProjectileGravity" :tid type_id angle speed up_speed special 248 t "HealThing" amount max_health special 73 t "DamageThing" damage damage_type special 119 t "Thing_Damage" :tid damage damage_type special 133 t "Thing_Destroy" :tid - :tag special 132 t "Thing_Remove" :tid special 72 t "ThrustThing" angle thrust - :tid special 128 t "ThrustThingZ" :tid thrust down? additive? special 19 t "Thing_Stop" :tid special 176 t "Thing_ChangeTID" :tid new_tid # Lines special 121 - "Line_SetIdent" line_id:self_line_id special 156 - "Line_SetPortal" target_id:line_id this_id:self_line_id type anchor special 48 - "Sector_Attach3dMidtex" :line_id :tag ceiling? # Animated special 102 a "Scroll_Texture_Up" speed special 103 a "Scroll_Texture_Down" speed special 100 a "Scroll_Texture_Left" speed special 101 a "Scroll_Texture_Right" speed special 225 a "Scroll_Texture_Offsets" special 222 a "Scroll_Texture_Model" :line_id kind special 223 a "Scroll_Floor" :tag kind push? x_speed y_speed special 224 a "Scroll_Ceiling" :tag tex_flags - x_speed y_speed # PolyObjects special 1 p "PolyObject Start Line" :po mirror_po:po sound_seq special 5 p "Polyobj_ExplicitLine" :po render_order mirror_po:po sound_seq special 2 p "Polyobj_RotateLeft" :po speed angle special 90 p "Polyobj_OR_RotateLeft" :po speed angle special 3 p "Polyobj_RotateRight" :po speed angle special 91 p "Polyobj_OR_RotateRight" :po speed angle special 4 p "Polyobj_Move" :po speed angle dist special 92 p "Polyobj_OR_Move" :po speed angle dist special 6 p "Polyobj_MoveTimes8" :po speed angle dist_x8 special 93 p "Polyobj_OR_MoveTimes8" :po speed angle dist_x8 special 7 p "Polyobj_DoorSwing" :po speed angle delay special 8 p "Polyobj_DoorSlide" :po speed angle dist delay special 86 p "Polyobj_MoveToSpot" :po speed :tid special 59 p "Polyobj_OR_MoveToSpot" :po speed :tid special 87 p "Polyobj_Stop" :po ## andrewj: leaving out specials 88/89 "Polyobj_MoveTo" because they ## seem designed for scripts -- when used in a map the target X/Y ## coordinates will be limited to the range 0-255. # Exits special 243 x "Exit_Normal" special 244 x "Exit_Secret" special 74 x "Teleport_NewMap" map special 75 x "Teleport_EndGame" # Renderer special 9 r "Line_Horizon" special 210 r "Transfer_FloorLight" :tag special 211 r "Transfer_CeilingLight" :tag special 57 r "Sector_SetPortal" :tag portal_type plane misc opacity special 209 r "Transfer_Heights" :tag # Scripting special 80 k "ACS_Execute" script map param1 param2 param3 special 83 k "ACS_LockedExecute" script map param1 param2 lock special 85 k "ACS_LockedExecuteDoor" script map param1 param2 lock special 84 k "ACS_ExecuteWithResult" script param1 param2 param3 special 226 k "ACS_ExecuteAlways" script map param1 param2 param3 special 81 k "ACS_Suspend" script map special 82 k "ACS_Terminate" script map special 179 - "ChangeSkill" skill special 120 - "Earthquake" intensity duration damrad tremrad :tid ## special 129 - "UsePuzzleItem" item script param1 param2 param3 # Boom Compatibility special 200 f "Generic_Floor" :tag speed dist target_type flags special 201 c "Generic_Ceiling" :tag speed dist target_type flags special 203 g "Generic_Lift" :tag speed delay_octics lift_type type0_height special 204 q "Generic_Stairs" :tag speed height flags reset_delay special 205 c "Generic_Crusher" :tag down_speed up_speed silent? damage ## special 202 d "Generic_Door" tag speed door_kind delay lock else #---- DOOM-STYLE SPECIALS ---------- linegroup o "Portals" line 283 o "-- EE: Plane portal /c" :tag line 284 o "-- EE: Plane portal /f" :tag line 285 o "-- EE: Plane portal" :tag line 286 o "-- EE: Horizon portal /c" :tag line 287 o "-- EE: Horizon portal /f" :tag line 288 o "-- EE: Horizon portal" :tag line 290 o "-- EE: Skybox portal /c" :tag line 291 o "-- EE: Skybox portal /f" :tag line 292 o "-- EE: Skybox portal" :tag line 450 o "-- EE: Horizon portal direct" line 295 o "-- EE: Anchor portal /c" :tag line 296 o "-- EE: Anchor portal /f" :tag line 297 o "-- EE: Anchor portal" :tag line 298 o "-- EE: Anch line for 295,297" :tag line 299 o "-- EE: Anch line for 296" :tag line 344 o "-- EE: 2-way anc prt /c" :tag line 345 o "-- EE: 2-way anc prt /f" :tag line 346 o "-- EE: Anch line for 344" :tag line 347 o "-- EE: Anch line for 345" :tag line 289 o "-- EE: Portal transfer" :tag line 358 o "-- EE: Linked portal /c" :tag line 359 o "-- EE: Linked portal /f" :tag line 360 o "-- EE: Link prt anch for 358" :tag line 361 o "-- EE: Link prt anch for 359" :tag line 376 o "-- EE: Link prt to tag lines" :line_id line 377 o "-- EE: Link prt anch for 376" line 385 o "-- EE: Link prt to front sec" :tag line 386 - "-- EE: Slope front floor" line 387 - "-- EE: Slope front ceil" line 388 - "-- EE: Slope front f & c" line 389 - "-- EE: Slope back floor" line 390 - "-- EE: Slope back ceil" line 391 - "-- EE: Slope back f & c" line 392 - "-- EE: Slope back f & front c" line 393 - "-- EE: Slope back c & front f" line 394 - "-- EE: Front f to tag slope" :tag line 395 - "-- EE: Front c to tag slope" :tag line 396 - "-- EE: Front f, c to tag slp" :tag line 280 n "WR EE: Exec Script" line 273 n "WR EE: Exec Script /1way" line 274 n "W1 EE: Exec Script" line 275 n "W1 EE: Exec Script /1way" line 276 n "SR EE: Exec Script" line 277 n "S1 EE: Exec Script" line 278 n "GR EE: Exec Script" line 279 n "G1 EE: Exec Script" line 270 - "-- EE: ExtraData linedef" line 401 - "-- EE: ExtraData sector" line 281 - "-- EE: 3D Midtex /f" :line_id line 282 - "-- EE: 3D Midtex /c" :line_id line 293 - "-- EE: Heretic wind" :tag line 294 - "-- EE: Heretic current" :tag line 379 - "-- EE: Attach set ceil ctrl" line 380 - "-- EE: Attach set floor ctrl" line 381 - "-- EE: Attach floor to ctrl" :line_id line 382 - "-- EE: Attach ceil to ctrl" :line_id line 383 - "-- EE: Mirror floor to ctrl" :line_id line 384 - "-- EE: Mirror ceil to ctrl" :line_id endif eureka-editor-eureka-2.0.2/ports/legacy.ugh000066400000000000000000000112771464327712600206710ustar00rootroot00000000000000#------------------------------------------------------------------------ # LEGACY 1.44 definitions #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2012 Wesley Johnson # Copyright (C) 2001-2013 Andrew Apted # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ if $ALLOW_BOOM is 1 include "mbf" endif feature extra_floors 2 #---- LEGACY THINGS ------------- thing 5003 - n 8 NULL "LEG: Camera" thing 5004 - n 16 NULL "LEG: Node" # JDS group player starts thing 4001 p - 16 NULL "Player 5 start" thing 4002 p - 16 NULL "Player 6 start" thing 4003 p - 16 NULL "Player 7 start" thing 4004 p - 16 NULL "Player 8 start" thing 4005 p - 16 NULL "Player 9 start" thing 4006 p - 16 NULL "Player 10 start" thing 4007 p - 16 NULL "Player 11 start" thing 4008 p - 16 NULL "Player 12 start" thing 4009 p - 16 NULL "Player 13 start" thing 4010 p - 16 NULL "Player 14 start" thing 4011 p - 16 NULL "Player 15 start" thing 4012 p - 16 NULL "Player 16 start" thing 4013 p - 16 NULL "Player 17 start" thing 4014 p - 16 NULL "Player 18 start" thing 4015 p - 16 NULL "Player 19 start" thing 4016 p - 16 NULL "Player 20 start" thing 4017 p - 16 NULL "Player 21 start" thing 4018 p - 16 NULL "Player 22 start" thing 4019 p - 16 NULL "Player 23 start" thing 4020 p - 16 NULL "Player 24 start" thing 4021 p - 16 NULL "Player 25 start" thing 4022 p - 16 NULL "Player 26 start" thing 4023 p - 16 NULL "Player 27 start" thing 4024 p - 16 NULL "Player 28 start" thing 4025 p - 16 NULL "Player 29 start" thing 4026 p - 16 NULL "Player 30 start" thing 4027 p - 16 NULL "Player 31 start" thing 4028 p - 16 NULL "Player 32 start" #---- LEGACY LINETYPES ---------- line 290 f "-- LEG: Instant lower floor" :tag line 291 c "-- LEG: Instant raise ceil" :tag line 284 r "-- LEG: Translucent MED" :line_id line 285 r "-- LEG: Translucent MORE" :line_id line 286 r "-- LEG: Translucent HI" :line_id line 287 r "-- LEG: Translucent FIRE" :line_id line 288 r "-- LEG: Translucent FX1 " :line_id line 280 r "-- LEG: Swim Water" :tag line 282 r "-- LEG: Gen Colormap #UML" :tag # side1 upper texture: #rrggbba ( or texture name ) Color # where: # rr, gg, bb= red, green, blue (hex 00..FF) # a= alpha (letter 'a'..'z') # side1 middle texture: #fssee ( or texture name ) # where: # f: (0,1) fog colormap # ss: (dec 0..32) Fade begin # ee: (dec 1..33) Fade end # side1 lower texture: #rrggbb ( or texture name ) Fade-to-color # where: # rr, gg, bb= red, green, blue (hex 00..FF) line 283 r "-- LEG: Fog sheet" :tag line 281 y "-- LEG: Floor Solid shadow" :tag line 289 y "-- LEG: Floor Solid" :tag line 300 y "-- LEG: Floor Trans #U" :tag # side1 upper texture: #aaa ( or texture name ) Alpha # where: aaa= alpha (0..255) line 301 y "-- LEG: 3d Water Translu #U" :tag # side1 upper texture: #aaaf ( or texture name ) Alpha # where: # aaa= alpha (0..255) # f= fog effect (letter 'A'..'F') line 304 y "-- LEG: 3d Water Opaque #U" :tag # side1 upper texture: #aaaf ( or texture name ) Alpha inside water # where: # aaa= alpha (0..255) # f= fog effect (letter 'A'..'F') line 302 y "-- LEG: 3d Fog #U" :tag # side1 upper texture: #aaaf ( or texture name ) Alpha inside water # where: # aaa= alpha (0..255) # f= fog effect (letter 'A'..'F') # Fog effect chart # 'A'= Clear, no fog # 'B'= Cast # 'C'= Colormap # 'D'= Fog inside # 'E'= Fog lite # 'F'= Fog dust # 'G'= Fog distance # 'H'= Fog fluid line 303 y "-- LEG: 3d Ceiling Light" :tag line 305 y "-- LEG: 3d Light Slab" :tag line 306 y "-- LEG: Floor Invisible" :tag # not in DoomLegacy line 271 - "-- (Unsupported)" # start the script with the tag number line 272 n "WR LEG: Script Trigger" line 273 n "WR LEG: Script 1-way" line 274 n "W1 LEG: Script Trigger" line 275 n "W1 LEG: Script 1-way" line 276 n "SR LEG: Script Trigger" line 277 n "S1 LEG: Script Trigger" line 278 n "GR LEG: Script Trigger" line 279 n "G1 LEG: Script Trigger" #---- LEGACY LINE FLAGS ---------- # Flag 1024 (0x400) "AllTrigger" eureka-editor-eureka-2.0.2/ports/mbf.ugh000066400000000000000000000021131464327712600201560ustar00rootroot00000000000000#------------------------------------------------------------------------ # MBF : Marine's Best Friend #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2016 Andrew Apted # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ include "boom" supported_games doom doom2 #---- FEATURES ---------- feature friend_flag 1 #---- THINGS ------------- thing 888 - - 12 DOGS "Dog (MBF)" #---- LINETYPES ---------- line 271 - "-- MBF: Transfer sky" :tag line 272 - "-- MBF: Mirror sky" :tag eureka-editor-eureka-2.0.2/ports/odamex.ugh000066400000000000000000000047601464327712600207010ustar00rootroot00000000000000#------------------------------------------------------------------------ # ODAMEX definitions #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2001-2013 Andrew Apted # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ if $ALLOW_BOOM is 1 include "mbf" endif feature slopes 4 #---- ODAMEX THINGS ---------- thing 4001 p - 16 PLAYA1 "Player 5 start" thing 4002 p - 16 PLAYA1 "Player 6 start" thing 4003 p - 16 PLAYA1 "Player 7 start" thing 4004 p - 16 PLAYA1 "Player 8 start" thing 5080 p - 16 PLAYF1 "ODAMEX: Blue start" thing 5081 p - 16 PLAYF1 "ODAMEX: Red start" thing 5130 k n 16 BFLG "ODAMEX: Blue flag" thing 5131 k n 16 RFLG "ODAMEX: Red flag" thing 9046 - n 16 NULL "ODAMEX: Secret" thing 9045 - n 16 NULL "ODAMEX: Water zone" thing 9026 d n 16 NULL "ODAMEX: Sparks" thing 9027 d n 16 NULL "ODAMEX: Fountain 1" thing 9028 d n 16 NULL "ODAMEX: Fountain 2" thing 9029 d n 16 NULL "ODAMEX: Fountain 3" thing 9030 d n 16 NULL "ODAMEX: Fountain 4" thing 9031 d n 16 NULL "ODAMEX: Fountain 5" thing 9032 d n 16 NULL "ODAMEX: Fountain 6" thing 9033 d n 16 NULL "ODAMEX: Fountain 7" # not here (require Hexen format) : # MT_CAMERA # MT_PATHNODE # MT_NODE # MT_ZDOOMBRIDGE # MT_BRIDGE8/16/32 #---- ODAMEX LINE TYPES ---------- line 333 - "-- ODAMEX: Init Gravity" :tag line 334 - "-- ODAMEX: Init Color" :tag line 335 - "-- ODAMEX: Init Damage" :tag line 340 s "-- ODAMEX: Slope F1" line 341 s "-- ODAMEX: Slope C1" line 342 s "-- ODAMEX: Slope F1 + C1" line 343 s "-- ODAMEX: Slope F2" line 344 s "-- ODAMEX: Slope C2" line 345 s "-- ODAMEX: Slope C2 + F2" line 346 s "-- ODAMEX: Slope C1 + F2" line 347 s "-- ODAMEX: Slope C2 + F1" #---- ODAMEX SECTOR TYPES ---------- sector 21 "ODAMEX: Light Phased" sector 22 "ODAMEX: LightSeq Start" sector 23 "ODAMEX: LightSeq Next 1" sector 24 "ODAMEX: LightSeq Next 2" # hmmm, can Sky2 and Scroll types be used too ??? eureka-editor-eureka-2.0.2/ports/vanilla.ugh000066400000000000000000000007031464327712600210430ustar00rootroot00000000000000#------------------------------------------------------------------------ # VANILLA (plain DOOM.EXE or HERETIC.EXE etc...) #------------------------------------------------------------------------ # # NOTE: # Vanilla means the engine (EXE) which came with the game. # # Hence it is not a real port, but a fake port which supports # all games, and is handled specially in the Eureka code. # # Don't add anything to this file! # eureka-editor-eureka-2.0.2/ports/xdoom.ugh000066400000000000000000000030631464327712600205450ustar00rootroot00000000000000#------------------------------------------------------------------------ # XDOOM (a port by Udo Monk) #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2013 Andrew Apted # Copyright (C) 1997-2003 André Majorel et al # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ # # Based on Yadex which incorporated code from DEU 5.21 that was put # in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. # #------------------------------------------------------------------------ supported_games doom doom2 #---- LINE TYPES ---------- linegroup x "XDoom" line 300 x "SR XDOOM: Sliding door" line 320 x "-- XDOOM: Laser barrier" line 321 x "SR XDOOM: Laser off /temp" line 322 x "G1 XDOOM: Laser off" line 333 x "S1 XDOOM: Laser off /msg" line 330 x "WR XDOOM: Message" line 331 x "W1 XDOOM: Message" line 334 x "M1 XDOOM: Message" line 332 x "S1 XDOOM: Teleport /msg" line 350 x "W1 XDOOM: Silent door" line 351 x "S1 XDOOM: Silent door" line 352 x "M1 XDOOM: Silent door" eureka-editor-eureka-2.0.2/ports/zdoom.ugh000066400000000000000000000634641464327712600205620ustar00rootroot00000000000000#------------------------------------------------------------------------ # ZDOOM Source Port #------------------------------------------------------------------------ # # Eureka DOOM Editor # # Copyright (C) 2015-2019 Andrew Apted # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # #------------------------------------------------------------------------ # # The action specials here were adapted (and condensed) from the # ZDoom config of SLADE, a map and resource editor by Simon Judd. # #------------------------------------------------------------------------ # Pull in the Boom/MBF definitions, but only when Hexen-style # specials are not being used. if $MAP_FORMAT not DOOM set $ALLOW_BOOM 0 set $HEXEN_SPECIALS 1 endif if $ALLOW_BOOM is 1 include "mbf" feature friend_flag 0 endif map_formats DOOM HEXEN UDMF supported_games doom doom2 heretic hexen strife udmf_namespace ZDoom feature tx_start 1 feature medusa_fixed 1 feature tuttifrutti_fixed 1 feature lax_sprites 1 feature mix_textures_flats 1 feature neg_patch_offsets 1 feature extra_floors 7 feature slopes 28 #---- ZDOOM THINGS ------------ thing 4001 p - 16 PLAYA1 "Player 5 start" thing 4002 p - 16 PLAYA1 "Player 6 start" thing 4003 p - 16 PLAYA1 "Player 7 start" thing 4004 p - 16 PLAYA1 "Player 8 start" thing 1400 - nv 16 NULL "Sound Sequence 0" thing 1401 - nv 16 NULL "Sound Sequence 1" thing 1402 - nv 16 NULL "Sound Sequence 2" thing 1403 - nv 16 NULL "Sound Sequence 3" thing 1404 - nv 16 NULL "Sound Sequence 4" thing 1405 - nv 16 NULL "Sound Sequence 5" thing 1406 - nv 16 NULL "Sound Sequence 6" thing 1407 - nv 16 NULL "Sound Sequence 7" thing 1408 - nv 16 NULL "Sound Sequence 8" thing 1409 - nv 16 NULL "Sound Sequence 9" thing 1411 - nv 16 NULL "Sound Sequence arg" thing 9300 - n 16 NULL "ZD: PolyObj Anchor" thing 9301 - npv 16 NULL "ZD: PolyObject" thing 9302 - npv 16 NULL "ZD: PolyObject /crush" thing 9303 - npv 16 NULL "ZD: PolyObject /burn" thing 1500 - n 16 NULL "ZD: Floor slope" thing 1501 - n 16 NULL "ZD: Ceil slope" thing 1504 - n 16 NULL "ZD: Floor vertex z" thing 1505 - n 16 NULL "ZD: Ceil vertex z" thing 9500 - n 16 NULL "ZD: Floor line" thing 9501 - nc 16 NULL "ZD: Ceiling line" thing 9502 - n 16 NULL "ZD: Floor tilt" thing 9503 - nc 16 NULL "ZD: Ceiling tilt" thing 9510 - n 16 NULL "ZD: Copy floor slope" thing 9511 - nc 16 NULL "ZD: Copy ceiling slope" thing 9027 - n 16 NULL "ZD: Red Fountain" thing 9028 - n 16 NULL "ZD: Green Fountain" thing 9029 - n 16 NULL "ZD: Blue Fountain" thing 9030 - n 16 NULL "ZD: Yellow Fountain" thing 9031 - n 16 NULL "ZD: Purple Fountain" thing 9032 - n 16 NULL "ZD: Black Fountain" thing 9033 - n 16 NULL "ZD: White Fountain" thing 5004 - n 16 _MSP "ZD: FS_Mapspot" thing 5006 - n 16 NULL "ZD: SkyCamCompat" thing 5061 - n 16 NULL "ZD: InvisibleBridge /32" thing 5064 - n 16 NULL "ZD: InvisibleBridge /16" thing 5065 - n 16 NULL "ZD: InvisibleBridge /8" thing 9990 - n 16 NULL "ZD: InvisibleBridge" thing 9991 - n 16 NULL "ZD: CustomBridge" thing 9001 - n 16 _MSP "ZD: MapSpot" thing 9013 - n 16 _MSP "ZD: MapSpot /gravity" thing 9024 - n 16 _MSP "ZD: PatrolPoint" thing 9025 - n 16 NULL "ZD: SecurityCamera" thing 9026 - n 16 NULL "ZD: Spark" thing 9037 - n 16 NULL "ZD: BetaSkull" thing 9038 - n 16 NULL "ZD: ColorSetter" thing 9039 - n 16 NULL "ZD: FadeSetter" thing 9040 - n 16 NULL "ZD: MapMarker" thing 9041 - n 16 NULL "ZD: SectorFlagSetter" thing 9043 - n 16 NULL "ZD: TeleportDest3" thing 9044 - n 16 NULL "ZD: TeleportDest2" thing 9045 - n 16 NULL "ZD: WaterZone" thing 9046 - n 16 NULL "ZD: SecretTrigger" thing 9047 - n 16 NULL "ZD: PatrolSpecial" thing 9048 - n 16 NULL "ZD: SoundEnvironment" thing 9070 - n 16 NULL "ZD: InterpolationPoint" thing 9071 - n 16 NULL "ZD: PathFollower" thing 9072 - n 16 NULL "ZD: MovingCamera" thing 9073 - n 16 NULL "ZD: AimingCamera" thing 9074 - n 16 NULL "ZD: ActorMover" thing 9075 - n 16 NULL "ZD: InterpolationSpecial" thing 9076 - n 16 NULL "ZD: HateTarget" thing 9077 - n 16 NULL "ZD: UpperStackLookOnly" thing 9078 - n 16 NULL "ZD: LowerStackLookOnly" thing 9080 - n 16 NULL "ZD: SkyViewpoint" thing 9081 - n 16 NULL "ZD: SkyPicker" thing 9082 - n 16 NULL "ZD: SectorSilencer" thing 9083 - n 16 NULL "ZD: SkyCamCompat" thing 9200 - n 16 NULL "ZD: Decal" thing 9988 - n 16 NULL "ZD: CustomSprite" thing 9982 - n 16 NULL "ZD: SecActEyesAboveC" thing 9983 - n 16 NULL "ZD: SecActEyesBelowC" thing 9989 - n 16 NULL "ZD: SecActHitFakeFloor" thing 9992 - n 16 NULL "ZD: SecActEyesSurface" thing 9993 - n 16 NULL "ZD: SecActEyesDive" thing 9994 - n 16 NULL "ZD: SecActUseWall" thing 9995 - n 16 NULL "ZD: SecActUse" thing 9996 - n 16 NULL "ZD: SecActHitCeil" thing 9997 - n 16 NULL "ZD: SecActExit" thing 9998 - n 16 NULL "ZD: SecActEnter" thing 9999 - n 16 NULL "ZD: SecActHitFloor" # GZDoom dynamic lights thing 9800 - ln 16 _LYT "ZD: PointLight" thing 9810 - ln 16 _LYT "ZD: PointLight /add" thing 9820 - ln 16 _LYT "ZD: PointLight /sub" thing 9802 - ln 16 _LYT "ZD: PointLight /flick" thing 9812 - ln 16 _LYT "ZD: PointLight /flick /add" thing 9804 - ln 16 _LYT "ZD: PointLight /flick /rand" thing 9814 - ln 16 _LYT "ZD: PointLight /flick /rand /add" thing 9824 - ln 16 _LYT "ZD: PointLight /flick /rand /sub" thing 9822 - ln 16 _LYT "ZD: PointLight /flick /sub" thing 9801 - ln 16 _LYT "ZD: PointLight /pulse" thing 9811 - ln 16 _LYT "ZD: PointLight /pulse /add" thing 9821 - ln 16 _LYT "ZD: PointLight /pulse /sub" thing 9803 - ln 16 _LYT "ZD: PointLight /sec" thing 9813 - ln 16 _LYT "ZD: PointLight /sec /add" thing 9823 - ln 16 _LYT "ZD: PointLight /sec /sub" # #---- HEXEN STYLE SPECIALS -------------- # if $HEXEN_SPECIALS is 1 clear lines sectors feature tag_666 0 feature strife_flags 0 feature gen_lines 0 feature gen_sectors zdoom include "hexen_groups" include "hexen_sectors" special 0 - "NOTHING" # Floors special 22 f "Floor_LowerToNearest" :tag speed special 21 f "Floor_LowerToLowest" :tag speed special 241 f "Floor_LowerToLowestTxTy" :tag speed special 242 f "Floor_LowerToHighest" :tag speed lip adjust? special 20 f "Floor_LowerByValue" :tag speed dist special 36 f "Floor_LowerByValueTimes8" :tag speed dist_x8 special 66 f "Floor_LowerInstant" :tag - dist_x8 special 25 f "Floor_RaiseToNearest" :tag speed special 24 f "Floor_RaiseToHighest" :tag speed special 238 f "Floor_RaiseToLowestCeiling" :tag speed special 23 f "Floor_RaiseByValue" :tag speed dist special 35 f "Floor_RaiseByValueTimes8" :tag speed dist_x8 special 239 f "Floor_RaiseByValueTxTy" :tag speed dist special 240 f "Floor_RaiseByTexture" :tag speed special 67 f "Floor_RaiseInstant" :tag - dist_x8 special 28 f "Floor_RaiseAndCrush" :tag speed damage crush_mode special 99 f "Floor_RaiseAndCrushDoom" :tag speed damage crush_mode special 46 f "Floor_CrushStop" :tag special 37 f "Floor_MoveToValue" :tag speed dist negate? special 68 f "Floor_MoveToValueTimes8" :tag speed dist_x8 negate? special 250 f "Floor_Donut" :tag speed speed special 138 f "Floor_Waggle" :tag amp speed offset time special 235 f "Floor_TransferTrigger" :tag special 236 f "Floor_TransferNumeric" :tag # Ceilings special 169 c "Generic_Crusher2" :tag down_speed up_speed silent? damage special 253 c "Ceiling_LowerToLowest" :tag speed special 254 c "Ceiling_LowerToFloor" :tag speed special 192 c "Ceiling_LowerToHighestFloor" :tag speed special 40 c "Ceiling_LowerByValue" :tag speed dist special 199 c "Ceiling_LowerByValueTimes8" :tag speed dist_x8 special 193 c "Ceiling_LowerInstant" :tag - dist_x8 special 252 c "Ceiling_RaiseToNearest" :tag speed special 41 c "Ceiling_RaiseByValue" :tag speed dist special 198 c "Ceiling_RaiseByValueTimes8" :tag speed dist_x8 special 194 c "Ceiling_RaiseInstant" :tag - dist_x8 special 47 c "Ceiling_MoveToValue" :tag speed dist negate? special 69 c "Ceiling_MoveToValueTimes8" :tag speed dist_x8 negate? special 38 c "Ceiling_Waggle" :tag amp speed offset time special 43 c "Ceiling_LowerAndCrush" :tag speed damage crush_mode special 97 c "Ceiling_LowerAndCrushDist" :tag speed damage height crush_mode special 42 c "Ceiling_CrushAndRaise" :tag speed damage crush_mode special 196 c "Ceiling_CrushAndRaiseA" :tag down_speed up_speed damage crush_mode special 197 c "Ceiling_CrushAndRaiseSilentA" :tag down_speed up_speed damage crush_mode special 168 c "Ceiling_CrushAndRaiseDist" :tag height speed damage crush_mode special 104 c "Ceiling_CrushAndRaiseSilentDist" :tag height speed damage crush_mode special 45 c "Ceiling_CrushRaiseAndStay" :tag speed damage crush_mode special 195 c "Ceiling_CrushRaiseAndStayA" :tag speed speed damage crush_mode special 255 c "Ceiling_CrushRaiseAndStaySilA" :tag speed speed damage crush_mode special 44 c "Ceiling_CrushStop" :tag # Doors special 12 d "Door_Raise" :tag speed delay light_tag:tag special 13 d "Door_LockedRaise" :tag speed delay lock light_tag:tag special 11 d "Door_Open" :tag speed light_tag:tag special 10 d "Door_Close" :tag speed light_tag:tag special 105 d "Door_WaitRaise" :tag speed delay wait light_tag:tag special 106 d "Door_WaitClose" :tag speed delay wait light_tag:tag special 249 d "Door_CloseWaitOpen" :tag speed delay light_tag:tag special 14 d "Door_Animated" :tag speed delay lock # Lifts special 62 g "Plat_DownWaitUpStay" :tag speed delay special 206 g "Plat_DownWaitUpStayLip" :tag speed delay lip sound_type special 63 g "Plat_DownByValue" :tag speed delay dist_x8 special 64 g "Plat_UpWaitDownStay" :tag speed delay special 172 g "Plat_UpNearestWaitDownStay" :tag speed delay special 65 g "Plat_UpByValue" :tag speed delay dist_x8 special 230 g "Plat_UpByValueStayTx" :tag speed dist_x8 special 228 g "Plat_RaiseAndStayTx0" :tag speed lockout special 60 g "Plat_PerpetualRaise" :tag speed delay special 207 g "Plat_PerpetualRaiseLip" :tag speed delay lip special 231 g "Plat_ToggleCeiling" :tag special 61 g "Plat_Stop" :tag # Elevators & Pillars special 95 e "Elevator_Lower" :tag speed dist special 96 e "Elevator_Raise" :tag speed dist special 251 e "FloorAndCeiling_LowerRaise" :tag floor_speed ceil_speed special 247 e "Elevator_LowerToNearest" :tag speed special 245 e "Elevator_RaiseToNearest" :tag speed special 246 e "Elevator_MoveToFloor" :tag speed special 30 e "Pillar_Open" :tag speed floor_dist ceil_dist special 29 e "Pillar_Build" :tag speed dist special 94 e "Pillar_BuildAndCrush" :tag speed dist damage crush_mode # Stairs special 26 q "Stairs_BuildDown" :tag speed height delay reset_delay special 31 q "Stairs_BuildDownSync" :tag speed height reset_delay special 27 q "Stairs_BuildUp" :tag speed height delay reset_delay special 32 q "Stairs_BuildUpSync" :tag speed height reset_delay special 217 q "Stairs_BuildUpDoom" :tag speed height delay reset_delay # Sector special 181 s "Plane_Align" floor_side ceil_side line_id:self_line_id special 118 s "Plane_Copy" front_floor_tag:tag front_ceil_tag:tag back_floor_tag:tag back_ceil_tag:tag share_flags special 160 s "Sector_Set3DFloor" :tag type flags opacity :tag_hi special 51 s "Sector_SetLink" control_tag:tag :tag ceiling? move_flags special 190 s "Static_Init" :tag property ceil_flip? move_flags special 54 s "Sector_ChangeFlags" :tag set_flags clear_flags special 140 s "Sector_ChangeSound" :tag sound_seq special 185 s "Sector_SetRotation" :tag floor_angle ceil_angle special 187 s "Sector_SetFloorPanning" :tag x_offset y_offset x_frac y_frac special 186 s "Sector_SetCeilingPanning" :tag x_offset y_offset x_frac y_frac special 189 s "Sector_SetFloorScale" :tag x_scale x_frac y_scale y_frac special 188 s "Sector_SetCeilingScale" :tag x_scale x_frac y_scale y_frac special 184 s "Line_AlignFloor" :line_id alignback? special 183 s "Line_AlignCeiling" :line_id alignback? special 212 s "Sector_SetColor" :tag red green blue desat special 213 s "Sector_SetFade" :tag red green blue special 214 s "Sector_SetDamage" :tag damage death_type special 216 s "Sector_SetGravity" :tag grav_mul grav_mul_frac special 218 s "Sector_SetWind" :tag strength angle use_line_angle? special 219 s "Sector_SetFriction" :tag friction special 220 s "Sector_SetCurrent" :tag strength angle use_line_angle? special 227 s "PointPush_SetForce" :tag :tid strength use_line_angle? ## andrewj: I have omitted special 161 "Sector_SetContents", since the ## ZDoom Wiki page for it says "this function is left undocumented at ## Graf Zahl's request" -- so it seems abandoned or deprecated. # Lighting special 233 l "Light_MinNeighbor" :tag special 111 l "Light_LowerByValue" :tag light special 234 l "Light_MaxNeighbor" :tag special 110 l "Light_RaiseByValue" :tag light special 112 l "Light_ChangeToValue" :tag light special 113 l "Light_Fade" :tag light time special 114 l "Light_Glow" :tag high low time special 115 l "Light_Flicker" :tag high low special 116 l "Light_Strobe" :tag high low high_time low_time special 232 l "Light_StrobeDoom" :tag high_time low_time special 117 l "Light_Stop" :tag special 109 l "Force_Lightning" mode # Teleporters special 70 u "Teleport" :tid :tag no_fog? special 71 u "Teleport_NoFog" :tid set_angle? :tag special 76 u "TeleportOther" :tid :tid fog? special 77 u "TeleportGroup" group_tid:tid source_tid:tid dest_tid:tid move_source? fog? special 78 u "TeleportInSector" :tag source_tid:tid dest_tid:tid fog? group_tid:tid special 154 u "Teleport_NoStop" dest_tid:tid :tag no_fog? special 215 u "Teleport_Line" source_line_id:self_line_id dest_line_id:line_id flip_180? special 39 u "Teleport_ZombieChanger" :tid :tag # Things special 130 t "Thing_Activate" :tid special 131 t "Thing_Deactivate" :tid special 17 t "Thing_Raise" :tid special 135 t "Thing_Spawn" :tid type_id angle new_id special 137 t "Thing_SpawnNoFog" :tid type_id angle new_id special 139 t "Thing_SpawnFacing" :tid type_id no_fog? new_id special 134 t "Thing_Projectile" :tid type_id angle speed up_speed special 136 t "Thing_ProjectileGravity" :tid type_id angle speed up_speed special 178 t "Thing_ProjectileAimed" :tid type_id speed target_tid:tid new_tid special 175 t "Thing_ProjectileIntercept" :tid type_id speed target_tid:tid new_tid special 248 t "HealThing" :tid health special 73 t "DamageThing" damage death_type special 119 t "Thing_Damage" :tid damage death_type special 133 t "Thing_Destroy" :tid extreme_damage? :tag special 132 t "Thing_Remove" :tid special 125 t "Thing_Move" :tid dest_tid:tid no_fog? special 72 t "ThrustThing" angle thrust unlimited? :tid special 128 t "ThrustThingZ" :tid thrust down? additive? special 19 t "Thing_Stop" :tid special 79 t "Thing_SetConversation" :tid conversation_id special 127 t "Thing_SetSpecial" :tid special arg1 arg2 arg3 special 176 t "Thing_ChangeTID" :tid new_tid special 177 t "Thing_Hate" :tid target_tid:tid hate_type special 180 t "Thing_SetTranslation" :tid translation special 229 t "Thing_SetGoal" :tid goal_tid delay no_stray? # Lines special 121 - "Line_SetIdent" line_id:self_line_id flags - - line_id_hi:self_line_id_hi special 55 - "Line_SetBlocking" :line_id set_flags clear_flags special 156 - "Line_SetPortal" target_id:line_id this_id:self_line_id type anchor special 107 - "Line_SetPortalTarget" source_id:line_id target_id:line_id special 33 - "ForceField" special 34 - "ClearForceField" :tag special 48 - "Attach3dMidtex" :line_id :tag ceiling? special 49 - "GlassBreak" no_shards? # Animated special 102 a "Scroll_Texture_Up" speed tex_flags special 103 a "Scroll_Texture_Down" speed tex_flags special 100 a "Scroll_Texture_Left" speed tex_flags special 101 a "Scroll_Texture_Right" speed tex_flags special 221 a "Scroll_Texture_Both" :line_id left_speed right_speed down_speed up_speed special 52 a "Scroll_Wall" :line_id x_speed y_speed back? tex_flags special 225 a "Scroll_Texture_Offsets" tex_flags special 222 a "Scroll_Texture_Model" :line_id flags special 223 a "Scroll_Floor" :tag tex_flags push? x_speed y_speed special 224 a "Scroll_Ceiling" :tag tex_flags - x_speed y_speed special 58 a "Sector_CopyScroller" :tag flags # PolyObjects special 1 p "PolyObject Start Line" :po mirror_po:po sound_seq special 5 p "Polyobj_ExplicitLine" :po render_order mirror_po:po sound_seq line_id:self_line_id special 2 p "Polyobj_RotateLeft" :po speed angle special 90 p "Polyobj_OR_RotateLeft" :po speed angle special 3 p "Polyobj_RotateRight" :po speed angle special 91 p "Polyobj_OR_RotateRight" :po speed angle special 4 p "Polyobj_Move" :po speed angle dist special 92 p "Polyobj_OR_Move" :po speed angle dist special 6 p "Polyobj_MoveTimes8" :po speed angle dist_x8 special 93 p "Polyobj_OR_MoveTimes8" :po speed angle dist_x8 special 7 p "Polyobj_DoorSwing" :po speed angle delay special 8 p "Polyobj_DoorSlide" :po speed angle dist delay special 86 p "Polyobj_MoveToSpot" :po speed :tid special 59 p "Polyobj_OR_MoveToSpot" :po speed :tid special 87 p "Polyobj_Stop" :po ## andrewj: leaving out specials 88/89 "Polyobj_MoveTo" because they ## seem designed for scripts -- when used in a map the target X/Y ## coordinates will be limited to the range 0-255. # Exits special 243 x "Exit_Normal" pos_arg0 special 244 x "Exit_Secret" pos_arg0 special 74 x "Exit_ToMap" map pos_arg0 keep_angle? special 75 x "End_Game" # Renderer special 9 r "Line_Horizon" special 182 r "Line_Mirror" special 16 r "Transfer_WallLight" :line_id flags special 210 r "Transfer_FloorLight" :tag special 211 r "Transfer_CeilingLight" :tag special 50 r "ExtraFloor_LightOnly" :tag light_type special 57 r "Sector_SetPortal" :tag portal_type plane misc opacity special 98 r "Sector_SetTranslucent" :tag ceiling? opacity special 157 r "SetGlobalFogParameter (OpenGL)" property value special 159 r "Sector_SetPlaneReflection (OpenGL)" :tag floor ceiling special 208 r "TranslucentLine" :line_id opacity additive? extra_flags special 209 r "Transfer_Heights" :tag flags # Scripting special 80 k "ACS_Execute" script map param1 param2 param3 special 83 k "ACS_LockedExecute" script map param1 param2 lock special 85 k "ACS_LockedExecuteDoor" script map param1 param2 lock special 84 k "ACS_ExecuteWithResult" script param1 param2 param3 special 226 k "ACS_ExecuteAlways" script map param1 param2 param3 special 81 k "ACS_Suspend" script map special 82 k "ACS_Terminate" script map special 158 k "FraggleScript" script front_only? lock remote_msg? # Boom Compatibility special 200 f "Generic_Floor" :tag speed dist target_type flags special 201 c "Generic_Ceiling" :tag speed dist target_type flags special 202 d "Generic_Door" :tag speed door_kind delay lock special 203 g "Generic_Lift" :tag speed delay_octics lift_type type0_height special 204 q "Generic_Stairs" :tag speed height flags reset_delay special 205 c "Generic_Crusher" :tag down_speed up_speed silent? damage # Miscellaneous special 191 - "SetPlayerProperty" all_players? turn_on? property special 237 - "ChangeCamera" :tid all_players? move_cancels? special 15 - "Autosave" special 179 - "ChangeSkill" skill special 18 - "StartConversation" :tid face_talker? special 120 - "Earthquake" intensity duration damrad tremrad :tid special 129 - "UsePuzzleItem" item script param1 param2 param3 special 173 - "NoiseAlert" target_tid:tid emitter_tid:tid special 174 - "SendToCommunicator" voc_id front_only? show_sender? no_log? # ZDoom sector specials sector 65 "ZD: Light Flicker" sector 66 "ZD: Light Strobe /fast" sector 67 "ZD: Light Strobe /slow" sector 68 "ZD: Light Strobe_/hurt" sector 72 "ZD: Light Glow" sector 76 "ZD: Light Strobe /slow /sync" sector 77 "ZD: Light Strobe /fast /sync" sector 81 "ZD: Light FireFlicker" sector 69 "ZD: Damage Hellslime" sector 80 "ZD: Damage Super Hellslime" sector 71 "ZD: Damage Nukage" sector 75 "ZD: Damage End" sector 82 "ZD: Damage Lava (Wimpy)" sector 83 "ZD: Damage Lava (Hefty)" sector 85 "ZD: Damage Sludge" sector 74 "ZD: Close after 30 sec" sector 78 "ZD: Open after 5 min" sector 84 "ZD: Scroll_E /damage" sector 87 "ZD: Outside" sector 195 "ZD: Hidden" sector 196 "ZD: Healing" sector 200 "ZD: Sky2" else # #---- DOOM STYLE SPECIALS ---------- # # most specials come from the game definition. # additional specials come from the MBF port. # Scripting line 273 n "WR FraggleScript Exec" line 274 n "W1 FraggleScript Exec" line 275 n "W1 FraggleScript Exec /front" line 276 n "SR FraggleScript Exec" line 277 n "S1 FraggleScript Exec" line 278 n "GR FraggleScript Exec" line 279 n "G1 FraggleScript Exec" # Renderer line 336 r "-- ZD: Line Mirror" line 337 r "-- ZD: Line Horizon" line 280 r "-- ZD: Transfer Heights /swim" :tag line 350 r "-- ZD: Transfer_Heights" :tag line 351 r "-- ZD: Transfer_Heights /clip" :tag line 284 r "-- LEG: Translucent 50%" :line_id line 285 r "-- LEG: Translucent 75%" :line_id line 286 r "-- LEG: Translucent 25%" :line_id line 287 r "-- LEG: Translucent 50% /additive" :line_id line 288 r "-- LEG: Translucent FX1" :line_id line 409 r "-- EDGE: Translucent 80%" :line_id line 410 r "-- EDGE: Translucent 60%" :line_id line 411 r "-- EDGE: Translucent 40%" :line_id line 412 r "-- EDGE: Translucent 20%" :line_id # Animated line 338 a "W1 ZD: Floor_Waggle /24" :tag line 339 a "W1 ZD: Floor_Waggle /12" :tag line 352 a "-- ZD: Copy scroller /ceil" :tag line 353 a "-- ZD: Copy scroller /floor" :tag line 354 a "-- ZD: Copy scroller /carry" :tag line 422 a "-- EDGE: Scroll right" line 423 a "-- EDGE: Scroll up" line 424 a "-- EDGE: Scroll down" line 425 a "-- EDGE: Scroll left/up" line 426 a "-- EDGE: Scroll left/down" line 427 a "-- EDGE: Scroll right/up" line 428 a "-- EDGE: Scroll right/down" # 3D Floors line 281 y "-- LEG: 3D Floor" :tag line 289 y "-- LEG: 3D Floor /unlit" :tag line 300 y "-- LEG: 3D Floor 50%" :tag line 301 y "-- LEG: 3D Floor 50% /swim" :tag line 302 y "-- LEG: 3D Floor 50% /fog" :tag line 303 y "-- LEG: 3D Floor /invis" :tag line 304 y "-- LEG: 3D Floor /swim" :tag line 305 y "-- LEG: 3D Floor /invis" :tag line 306 y "-- LEG: 3D Floor /solid /invis" :tag line 400 y "-- EDGE: 3D Floor" :tag line 401 y "-- EDGE: 3D Floor /upper" :tag line 402 y "-- EDGE: 3D Floor /lower" :tag line 403 y "-- EDGE: Liquid" :tag line 404 y "-- EDGE: Liquid 80%" :tag line 405 y "-- EDGE: Liquid 60%" :tag line 406 y "-- EDGE: Liquid 40%" :tag line 407 y "-- EDGE: Liquid 20%" :tag line 408 y "-- EDGE: Liquid 0%" :tag line 413 y "-- EDGE: Thin 3D floor" :tag line 414 y "-- EDGE: Thin 3D floor 80%" :tag line 415 y "-- EDGE: Thin 3D floor 60%" :tag line 416 y "-- EDGE: Thin 3D floor 40%" :tag line 417 y "-- EDGE: Thin 3D floor 20%" :tag # Sector Effects line 282 - "-- ZD: Set Light & Fog /rgb" :tag line 334 - "-- ZD: Set Light & Fog /rgb" :tag line 333 - "-- ZD: Set Gravity /length" :tag line 335 - "-- ZD: Set Damage /length" :tag # Slopes line 340 s "-- ZD: Slope front floor" line 341 s "-- ZD: Slope front ceiling" line 342 s "-- ZD: Slope front floor and ceiling" line 343 s "-- ZD: Slope back floor" line 344 s "-- ZD: Slope back ceiling" line 345 s "-- ZD: Slope back floor and ceiling" line 346 s "-- ZD: Slope back floor and front ceiling" line 347 s "-- ZD: Slope front floor and back ceiling" # Other line 348 - "W1 ZD: Autosave" line 349 - "S1 ZD: Autosave" ## andrewj: omitted the EDGE "Floor up 2" (types 434-439), as they ## have no practical use outside of EDGE's RTS scripting. # ZDoom DOOM sector specials if $BASE_GAME is Doom Doom2 sector 15 "ZD: Friction Low" sector 18 "ZD: Damage Lava (light)" sector 19 "ZD: Damage Lava (heavy)" sector 20 "ZD: Scroll East" sector 21 "ZD: Light Phased" sector 22 "ZD: Light Seq Start" sector 23 "ZD: Light Seq Next 1" sector 24 "ZD: Light Seq Next 2" endif endif eureka-editor-eureka-2.0.2/src/000077500000000000000000000000001464327712600163305ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/src/CMakeLists.txt000066400000000000000000000226731464327712600211020ustar00rootroot00000000000000 configure_file(version.h.in version.h) set(source_base dehconsts.h Document.cc Document.h DocumentModule.cc DocumentModule.h hdr_fltk.h Instance.cc Instance.h LineDef.cc LineDef.h main.cc main.h objid.h Sector.cc Sector.h Side.h SideDef.cc SideDef.h Thing.cc Thing.h Vertex.cc Vertex.h WadData.cc WadData.h ) set(source_thirdparty filesystem.hpp tl/optional.hpp ) set(source_bsp bsp_level.cc bsp_node.cc bsp_util.cc bsp.h ) set(source_e e_basis.cc e_basis.h e_checks.cc e_checks.h e_commands.cc e_cutpaste.cc e_cutpaste.h e_hover.cc e_hover.h e_linedef.cc e_linedef.h e_main.cc e_main.h e_objects.cc e_objects.h e_path.cc e_path.h e_select.cc e_sector.cc e_sector.h e_things.cc e_things.h e_vertex.cc e_vertex.h ) set(source_im im_color.cc im_color.h im_img.cc im_img.h ) set(source_lib lib_tga.cc lib_tga.h ) set(source_m m_config.cc m_config.h m_editlump.cc m_events.cc m_events.h m_files.cc m_files.h m_game.cc m_game.h m_keys.cc m_keys.h m_loadsave.cc m_loadsave.h m_nodes.cc m_nodes.h m_select.cc m_select.h m_testmap.cc m_testmap.h m_udmf.cc ) set(source_r r_grid.cc r_grid.h r_opengl.cc r_render.cc r_render.h r_software.cc r_subdiv.cc r_subdiv.h ) set(source_ui ui_about.cc ui_about.h ui_browser.cc ui_browser.h ui_canvas.cc ui_canvas.h ui_default.cc ui_default.h ui_dialog.cc ui_editor.cc ui_editor.h ui_file.cc ui_file.h ui_hyper.cc ui_hyper.h ui_infobar.cc ui_infobar.h ui_linedef.cc ui_linedef.h ui_menu.cc ui_menu.h ui_misc.cc ui_misc.h ui_nombre.cc ui_nombre.h ui_panelinput.cc ui_panelinput.h ui_pic.cc ui_pic.h ui_prefs.cc ui_prefs.h ui_replace.cc ui_replace.h ui_scroll.cc ui_scroll.h ui_sector.cc ui_sector.h ui_sidedef.cc ui_sidedef.h ui_thing.cc ui_thing.h ui_tile.cc ui_tile.h ui_vertex.cc ui_vertex.h ui_window.cc ui_window.h ) set(source_w w_dehacked.cc w_dehacked.h w_loadpic.cc w_loadpic.h w_rawdef.h w_texture.cc w_texture.h w_wad.cc w_wad.h ) add_library( eurekasrc STATIC ${source_base} ${source_bsp} ${source_e} ${source_im} ${source_lib} ${source_m} ${source_r} ${source_thirdparty} ${source_ui} ${source_w} ) add_library( eurekacore STATIC Errors.cc Errors.h filesystem.hpp FixedPoint.h lib_adler.cc lib_adler.h lib_file.cc lib_file.h lib_util.cc lib_util.h m_bitvec.cc m_bitvec.h m_strings.cc m_strings.h m_parse.cc m_parse.h m_streams.cc m_streams.h m_vector.cc m_vector.h PrintfMacros.h SafeOutFile.cc SafeOutFile.h sys_debug.cc sys_debug.h sys_endian.h sys_macro.h sys_type.h WindowsSanitization.h ) target_link_libraries(eurekasrc PRIVATE eurekacore) # Needed for macOS release archiving! set_target_properties(eurekasrc eurekacore PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/out/library) option(ENABLE_OPENGL "Use OpenGL instead of software rendering" ON) if(ENABLE_OPENGL) find_package(OpenGL REQUIRED) else() set(FLTK_SKIP_OPENGL TRUE) target_compile_definitions(eurekasrc PUBLIC NO_OPENGL) endif() if(APPLE OR WIN32) message(STATUS "Using local FLTK for portability.") set(LOCAL_FLTK_VERSION "1.3.8") set(LOCAL_FLTK_URL "https://www.fltk.org/pub/fltk/${LOCAL_FLTK_VERSION}/fltk-${LOCAL_FLTK_VERSION}-source.tar.gz") set(LOCAL_FLTK_MD5_HASH 84907602c2e50fadec3bc40fb61935cd) set(LOCAL_FLTK_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/fltk-${LOCAL_FLTK_VERSION}") set(LOCAL_FLTK_ARCHIVE "${CMAKE_CURRENT_BINARY_DIR}/fltk-${LOCAL_FLTK_VERSION}-source.tar.gz") set(LOCAL_FLTK_BUILD "${LOCAL_FLTK_SOURCE}/build") # Download it if not found if(NOT EXISTS "${LOCAL_FLTK_ARCHIVE}") message(STATUS "Downloading FLTK from ${LOCAL_FLTK_URL}") file( DOWNLOAD ${LOCAL_FLTK_URL} "${LOCAL_FLTK_ARCHIVE}" EXPECTED_HASH MD5=${LOCAL_FLTK_MD5_HASH} ) endif() if(NOT EXISTS "${LOCAL_FLTK_SOURCE}") message(STATUS "Extracting to ${LOCAL_FLTK_SOURCE}") execute_process( COMMAND "${CMAKE_COMMAND}" -E tar xzf "${LOCAL_FLTK_ARCHIVE}" WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" ) # Patch needed to prevent optimization bug if(APPLE) execute_process( COMMAND patch "${LOCAL_FLTK_SOURCE}/src/Fl_JPEG_Image.cxx" "${CMAKE_CURRENT_SOURCE_DIR}/fltk-patch/Fl_JPEG_Image-fltk1.3.8-macos.diff" ) endif() endif() if(NOT EXISTS "${LOCAL_FLTK_BUILD}/lib") message(STATUS "Building ${LOCAL_FLTK_SOURCE}") set(LOCAL_FLTK_DEFS -D CMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET} -D CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES} -D CMAKE_BUILD_TYPE=Release -D OPTION_USE_SYSTEM_LIBJPEG=OFF -D OPTION_USE_SYSTEM_LIBPNG=OFF -D OPTION_USE_SYSTEM_ZLIB=OFF ) if(CMAKE_GENERATOR_PLATFORM) list(APPEND LOCAL_FLTK_DEFS -A ${CMAKE_GENERATOR_PLATFORM}) endif() if(FLTK_SKIP_OPENGL) list(APPEND LOCAL_FLTK_DEFS -D OPTION_USE_GL=OFF) endif() if(WIN32) list(APPEND LOCAL_FLTK_DEFS -G ${CMAKE_GENERATOR}) endif() execute_process( COMMAND "${CMAKE_COMMAND}" -S "${LOCAL_FLTK_SOURCE}" -B "${LOCAL_FLTK_BUILD}" ${LOCAL_FLTK_DEFS} WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" ) include(ProcessorCount) ProcessorCount(nproc) message(STATUS "Building...") execute_process( COMMAND "${CMAKE_COMMAND}" --build "${LOCAL_FLTK_BUILD}" -j ${nproc} --config Release WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" ) endif() set(FLTK_INCLUDE_DIR "${LOCAL_FLTK_SOURCE};${LOCAL_FLTK_BUILD}") if(WIN32) set(FLTK_LIBRARIES "${LOCAL_FLTK_BUILD}/lib/Release/fltk.lib" "${LOCAL_FLTK_BUILD}/lib/Release/fltk_gl.lib" "${LOCAL_FLTK_BUILD}/lib/Release/fltk_images.lib" "${LOCAL_FLTK_BUILD}/lib/Release/fltk_jpeg.lib" "${LOCAL_FLTK_BUILD}/lib/Release/fltk_png.lib" "${LOCAL_FLTK_BUILD}/lib/Release/fltk_z.lib" ) target_include_directories(eurekasrc PUBLIC "${LOCAL_FLTK_SOURCE}/zlib") else() # APPLE set(FLTK_LIBRARIES "${LOCAL_FLTK_BUILD}/lib/libfltk.a" "${LOCAL_FLTK_BUILD}/lib/libfltk_gl.a" "${LOCAL_FLTK_BUILD}/lib/libfltk_images.a" "${LOCAL_FLTK_BUILD}/lib/libfltk_jpeg.a" "${LOCAL_FLTK_BUILD}/lib/libfltk_z.a" "${LOCAL_FLTK_BUILD}/lib/libfltk_png.a" ) # Need to link to them separately if FLTK is linked manually find_library(CARBON_FRAMEWORK Carbon) target_link_libraries(eurekasrc PUBLIC ${CARBON_FRAMEWORK}) find_library(COCOA_FRAMEWORK Cocoa) target_link_libraries(eurekasrc PUBLIC ${COCOA_FRAMEWORK}) find_library(APPSERVICES_FRAMEWORK ApplicationServices) target_link_libraries(eurekasrc PUBLIC ${APPSERVICES_FRAMEWORK}) endif() else() # UNIX/Linux find_package(FLTK REQUIRED) find_package(ZLIB REQUIRED) # ZLIB is expected on Linux separately from FLTK find_package(X11 REQUIRED) # also libXPM endif() target_link_libraries(eurekasrc PUBLIC ${FLTK_LIBRARIES} ${OPENGL_LIBRARIES}) if(UNIX AND NOT APPLE) # Linux target_link_libraries(eurekasrc PUBLIC ${X11_Xpm_LIB} ${ZLIB_LIBRARIES}) endif() target_include_directories(eurekasrc PUBLIC ${PROJECT_SOURCE_DIR} ${FLTK_INCLUDE_DIR} ${OPENGL_INCLUDE_DIR} ) # May be needed by files from other projects to find headers here target_include_directories(eurekasrc PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}") target_include_directories(eurekasrc PUBLIC "${CMAKE_CURRENT_BINARY_DIR}") if(MSVC) target_compile_options(eurekasrc PUBLIC "/MP") endif() if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" ) target_compile_options(eurekasrc PUBLIC "${CMAKE_CXX_FLAGS}" -Wall -Wextra -Werror -Wno-unused-parameter -Wno-missing-field-initializers -Wunused-variable) endif() if ( MSVC ) # TODO: make remove /W3 if there and set /W4 #target_compile_options(eurekasrc PUBLIC ${CMAKE_CXX_FLAGS} /W4) endif() source_group(bsp FILES ${source_bsp}) source_group("e_ source" FILES ${source_e}) source_group("im_ source" FILES ${source_im}) source_group("lib_ source" FILES ${source_lib}) source_group("im_ source" FILES ${source_im}) source_group("lib_ source" FILES ${source_lib}) source_group("m_ source" FILES ${source_m}) source_group("r_ source" FILES ${source_r}) source_group("ui_ source" FILES ${source_ui}) source_group("w_ source" FILES ${source_w}) source_group("third-party" FILES ${source_thirdparty}) # TODO: add the warnings and warnings-as-errors eureka-editor-eureka-2.0.2/src/Document.cc000066400000000000000000000124601464327712600204200ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2020 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Document.h" #include "lib_adler.h" #include "LineDef.h" #include "Sector.h" #include "SideDef.h" #include "Thing.h" #include "Vertex.h" // // Get number of objects based on enum // int Document::numObjects(ObjType type) const { switch(type) { case ObjType::things: return numThings(); case ObjType::linedefs: return numLinedefs(); case ObjType::sidedefs: return numSidedefs(); case ObjType::vertices: return numVertices(); case ObjType::sectors: return numSectors(); default: return 0; } } //------------------------------------------------------------------------ // CHECKSUM LOGIC //------------------------------------------------------------------------ static void ChecksumThing(crc32_c &crc, const Thing *T) { crc += T->raw_x.raw(); crc += T->raw_y.raw(); crc += T->angle; crc += T->type; crc += T->options; } static void ChecksumVertex(crc32_c &crc, const Vertex *V) { crc += V->raw_x.raw(); crc += V->raw_y.raw(); } static void ChecksumSector(crc32_c &crc, const Sector *sector) { crc += sector->floorh; crc += sector->ceilh; crc += sector->light; crc += sector->type; crc += sector->tag; crc += sector->FloorTex(); crc += sector->CeilTex(); } static void ChecksumSideDef(crc32_c &crc, const SideDef *S, const Document &doc) { crc += S->x_offset; crc += S->y_offset; crc += S->LowerTex(); crc += S->MidTex(); crc += S->UpperTex(); ChecksumSector(crc, &doc.getSector(*S)); } static void ChecksumLineDef(crc32_c &crc, const LineDef *L, const Document &doc) { crc += L->flags; crc += L->type; crc += L->tag; ChecksumVertex(crc, &doc.getStart(*L)); ChecksumVertex(crc, &doc.getEnd(*L)); if(doc.getRight(*L)) ChecksumSideDef(crc, doc.getRight(*L), doc); if(doc.getLeft(*L)) ChecksumSideDef(crc, doc.getLeft(*L), doc); } // // compute a checksum for the current level // void Document::getLevelChecksum(crc32_c &crc) const { // the following method conveniently skips any unused vertices, // sidedefs and sectors. It also adds each sector umpteen times // (for each line in the sector), but that should not affect the // validity of the final checksum. int i; for(i = 0; i < numThings(); i++) ChecksumThing(crc, things[i].get()); for(i = 0; i < numLinedefs(); i++) ChecksumLineDef(crc, linedefs[i].get(), *this); } const Sector &Document::getSector(const SideDef &side) const { return *sectors[side.sector]; } int Document::getSectorID(const LineDef &line, Side side) const { switch(side) { case Side::left: return getLeft(line) ? getLeft(line)->sector : -1; case Side::right: return getRight(line) ? getRight(line)->sector : -1; default: return -1; } } const Sector *Document::getSector(const LineDef &line, Side side) const { int sid = getSectorID(line, side); if(isSector(sid)) return sectors[sid].get(); return nullptr; } const Vertex &Document::getStart(const LineDef &line) const { return *vertices[line.start]; } const Vertex &Document::getEnd(const LineDef &line) const { return *vertices[line.end]; } const SideDef *Document::getRight(const LineDef &line) const { return line.right >= 0 ? sidedefs[line.right].get() : nullptr; } const SideDef *Document::getLeft(const LineDef &line) const { return line.left >= 0 ? sidedefs[line.left].get() : nullptr; } double Document::calcLength(const LineDef &line) const { double dx = getStart(line).x() - getEnd(line).x(); double dy = getStart(line).y() - getEnd(line).y(); return hypot(dx, dy); } bool Document::touchesCoord(const LineDef &line, FFixedPoint tx, FFixedPoint ty) const { return getStart(line).Matches(tx, ty) || getEnd(line).Matches(tx, ty); } bool Document::touchesSector(const LineDef &line, int secNum) const { if(line.right >= 0 && sidedefs[line.right]->sector == secNum) return true; if(line.left >= 0 && sidedefs[line.left]->sector == secNum) return true; return false; } bool Document::isZeroLength(const LineDef &line) const { return (getStart(line).raw_x == getEnd(line).raw_x) && (getStart(line).raw_y == getEnd(line).raw_y); } bool Document::isSelfRef(const LineDef &line) const { return (line.left >= 0) && (line.right >= 0) && sidedefs[line.left]->sector == sidedefs[line.right]->sector; } bool Document::isHorizontal(const LineDef &line) const { return (getStart(line).raw_y == getEnd(line).raw_y); } bool Document::isVertical(const LineDef &line) const { return (getStart(line).raw_x == getEnd(line).raw_x); } void Document::clear() { things.clear(); vertices.clear(); sectors.clear(); sidedefs.clear(); linedefs.clear(); headerData.clear(); behaviorData.clear(); scriptsData.clear(); basis.clear(); // TODO: other modules Clipboard_ClearLocals(); } eureka-editor-eureka-2.0.2/src/Document.h000066400000000000000000000152101464327712600202560ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2020 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef Document_hpp #define Document_hpp #include "e_basis.h" #include "e_checks.h" #include "e_hover.h" #include "e_linedef.h" #include "e_objects.h" #include "e_sector.h" #include "e_vertex.h" #include "LineDef.h" #include "Vertex.h" #include class crc32_c; class Instance; struct BadCount; // // The document associated with a file. All stuff will go here // struct Document { private: Instance &inst; // make this private because we don't want to access it from Document public: std::vector> things; std::vector> vertices; std::vector> sectors; std::vector> sidedefs; std::vector> linedefs; std::vector headerData; std::vector behaviorData; std::vector scriptsData; v2double_t Map_bound1 = { 32767, 32767 }; /* minimum XY value of map */ v2double_t Map_bound2 = { -32767, -32767 }; /* maximum XY value of map */ bool MadeChanges = false; Basis basis; ChecksModule checks; Hover hover; LinedefModule linemod; VertexModule vertmod; SectorModule secmod; ObjectsModule objects; explicit Document(Instance &inst) : inst(inst), basis(*this), checks(*this), hover(*this), linemod(*this), vertmod(*this), secmod(*this), objects(*this) { } Document(Document &&other) noexcept : inst(other.inst), basis(*this), checks(*this), hover(*this), linemod(*this), vertmod(*this), secmod(*this), objects(*this) { *this = std::move(other); } Document &operator = (Document &&other) noexcept { things = std::move(other.things); vertices = std::move(other.vertices); sectors = std::move(other.sectors); sidedefs = std::move(other.sidedefs); linedefs = std::move(other.linedefs); headerData = std::move(other.headerData); behaviorData = std::move(other.behaviorData); scriptsData = std::move(other.scriptsData); Map_bound1 = other.Map_bound1; Map_bound2 = other.Map_bound2; MadeChanges = other.MadeChanges; // TODO: basis basis = std::move(other.basis); return *this; } // // Count map objects // int numThings() const noexcept { return static_cast(things.size()); } int numVertices() const noexcept { return static_cast(vertices.size()); } int numSectors() const noexcept { return static_cast(sectors.size()); } int numSidedefs() const { return static_cast(sidedefs.size()); } int numLinedefs() const noexcept { return static_cast(linedefs.size()); } bool isThing(int n) const { return n >= 0 && n < numThings(); } bool isVertex(int n) const { return n >= 0 && n < numVertices(); } bool isSector(int n) const noexcept { return n >= 0 && n < numSectors(); } bool isSidedef(int n) const { return n >= 0 && n < numSidedefs(); } bool isLinedef(int n) const { return n >= 0 && n < numLinedefs(); } int numObjects(ObjType type) const; void getLevelChecksum(crc32_c &crc) const; const Sector &getSector(const SideDef &side) const; int getSectorID(const LineDef &line, Side side) const; const Sector *getSector(const LineDef &line, Side side) const; const Vertex &getStart(const LineDef &line) const; const Vertex &getEnd(const LineDef &line) const; const SideDef *getRight(const LineDef &line) const; SideDef *getRight(const LineDef &line) { return const_cast(static_cast(this)->getRight(line)); } const SideDef *getLeft(const LineDef &line) const; SideDef *getLeft(const LineDef &line) { return const_cast(static_cast(this)->getLeft(line)); } const SideDef *getSide(const LineDef &line, Side side) const { return side == Side::right ? getRight(line) : side == Side::left ? getLeft(line) : nullptr; } double calcLength(const LineDef &line) const; bool touchesCoord(const LineDef &line, FFixedPoint tx, FFixedPoint ty) const; bool touchesSector(const LineDef &line, int secNum) const; bool isZeroLength(const LineDef &line) const; bool isSelfRef(const LineDef &line) const; bool isHorizontal(const LineDef &line) const; bool isVertical(const LineDef &line) const; void LoadHeader(int loading_level, const Wad_file &load_wad); void LoadThings(int loading_level, const Wad_file *load_wad); void LoadThings_Hexen(int loading_level, const Wad_file *load_wad); void LoadVertices(int loading_level, const Wad_file *load_wad); void LoadLineDefs(int loading_level, const Wad_file *load_wad, const ConfigData &config, BadCount &bad); void LoadLineDefs_Hexen(int loading_level, const Wad_file *load_wad, const ConfigData &config, BadCount &bad); void LoadSectors(int loading_level, const Wad_file *load_wad); void LoadSideDefs(int loading_level, const Wad_file *load_wad, const ConfigData &config, BadCount &bad); void LoadBehavior(int loading_level, const Wad_file *load_wad); void LoadScripts(int loading_level, const Wad_file *load_wad); void RemoveUnusedVerticesAtEnd(); void CreateFallbackVertices(); void CreateFallbackSideDef(const ConfigData &config); void CreateFallbackSector(const ConfigData &config); void ValidateVertexRefs(LineDef &ld, int num, BadCount &bad); void ValidateSidedefRefs(LineDef &ld, int num, const ConfigData &config, BadCount &bad); void ValidateSectorRef(SideDef &sd, int num, const ConfigData &config, BadCount &bad); void ValidateLevel_UDMF(const ConfigData &config, BadCount &bad); void CalculateLevelBounds() noexcept; void UpdateLevelBounds(int start_vert) noexcept; int SaveHeader(Wad_file& wad, const SString& level) const; void SaveThings(Wad_file& wad) const; void SaveThings_Hexen(Wad_file& wad) const; void SaveLineDefs(Wad_file& wad) const; void SaveLineDefs_Hexen(Wad_file& wad) const; void SaveSideDefs(Wad_file& wad) const; void SaveVertices(Wad_file& wad) const; void SaveSectors(Wad_file& wad) const; void SaveBehavior(Wad_file& wad) const; void SaveScripts(Wad_file& wad) const; void clear(); bool Main_ConfirmQuit(const char* action) const; private: friend class DocumentModule; }; #endif /* Document_hpp */ eureka-editor-eureka-2.0.2/src/DocumentModule.cc000066400000000000000000000015301464327712600215620ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2020 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "DocumentModule.h" #include "Document.h" DocumentModule::DocumentModule(Document &doc) : inst(doc.inst), doc(doc) { }eureka-editor-eureka-2.0.2/src/DocumentModule.h000066400000000000000000000020211464327712600214200ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2020 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef DocumentModule_h #define DocumentModule_h struct Document; class Instance; // // This is an interface with direct references to Document's components, for less clutter // class DocumentModule { public: DocumentModule(Document &doc); Instance &inst; Document &doc; }; #endif /* DocumentModule_h */ eureka-editor-eureka-2.0.2/src/Errors.cc000066400000000000000000000056711464327712600201240ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2020 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include #ifdef _WIN32 #include #endif // // Throw an exception using format // void ThrowException(EUR_FORMAT_STRING(const char *fmt), ...) { char message[256]; va_list ap; va_start(ap, fmt); vsnprintf(message, sizeof(message), fmt, ap); va_end(ap); throw std::runtime_error(message); } void ThrowLogicException(EUR_FORMAT_STRING(const char *fmt), ...) { char message[256]; va_list ap; va_start(ap, fmt); vsnprintf(message, sizeof(message), fmt, ap); va_end(ap); throw std::logic_error(message); } #ifdef _WIN32 SString GetShellExecuteErrorMessage(HINSTANCE result) { INT_PTR val = (INT_PTR)result; if (val > 32) { return "OK"; } switch (val) { case 0: return "out of memory or resources"; case ERROR_FILE_NOT_FOUND: return "file not found"; case ERROR_PATH_NOT_FOUND: return "path not found"; case ERROR_BAD_FORMAT: return "invalid executable file"; case SE_ERR_ACCESSDENIED: return "access denied"; case SE_ERR_ASSOCINCOMPLETE: return "incomplete or invalid file name association"; case SE_ERR_DDEBUSY: return "DDE transaction busy"; case SE_ERR_DDEFAIL: return "DDE transaction failure"; case SE_ERR_DDETIMEOUT: return "DDE request time out"; case SE_ERR_DLLNOTFOUND: return "DLL not found"; case SE_ERR_NOASSOC: return "no app associated with given file name extension (or file is not printable)"; case SE_ERR_OOM: return "out of memory"; case SE_ERR_SHARE: return "a sharing violation occurred"; default: return SString::printf("unexpected error (code %zu)", (size_t)val); } } SString GetWindowsErrorMessage(DWORD error) { if (!error) { return "The operation completed successfully."; } LPSTR messageBuffer = nullptr; size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, nullptr); if (!size) { return SString::printf("(failed getting error message from %lu, reason of this failure having code %lu)", (unsigned long)error, (unsigned long)GetLastError()); } SString result(messageBuffer, (int)size); LocalFree(messageBuffer); result.trimTrailingSpaces(); return result; } #endif eureka-editor-eureka-2.0.2/src/Errors.h000066400000000000000000000023771464327712600177660ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2020 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef Errors_hpp #define Errors_hpp #include "PrintfMacros.h" #include "m_strings.h" #include #include #ifdef _WIN32 #include #endif #define BugError ThrowLogicException [[noreturn]] void ThrowException(EUR_FORMAT_STRING(const char *fmt), ...) EUR_PRINTF(1, 2); [[noreturn]] void ThrowLogicException(EUR_FORMAT_STRING(const char *fmt), ...) EUR_PRINTF(1, 2); #ifdef _WIN32 SString GetShellExecuteErrorMessage(HINSTANCE result); SString GetWindowsErrorMessage(DWORD error); #endif #endif /* Errors_hpp */ eureka-editor-eureka-2.0.2/src/FixedPoint.h000066400000000000000000000050371464327712600205570ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef FIXEDPOINT_H_ #define FIXEDPOINT_H_ #include "sys_macro.h" // The fraction unit static constexpr int kFracUnit = 4096; static constexpr double kFracUnitD = static_cast(kFracUnit); // // Type safe fixed point number // class FFixedPoint { public: FFixedPoint() = default; explicit FFixedPoint(double value) : value(iround(value * kFracUnitD)) { } explicit FFixedPoint(int value) : value(value * kFracUnit) { } int raw() const { return value; } bool operator == (FFixedPoint other) const { return value == other.value; } bool operator != (FFixedPoint other) const { return value != other.value; } bool operator < (FFixedPoint other) const { return value < other.value; } bool operator > (FFixedPoint other) const { return value > other.value; } FFixedPoint operator + (FFixedPoint other) const { FFixedPoint result; result.value = value + other.value; return result; } FFixedPoint operator - (FFixedPoint other) const { FFixedPoint result; result.value = value - other.value; return result; } FFixedPoint &operator += (FFixedPoint other) { value += other.value; return *this; } FFixedPoint &operator -= (FFixedPoint other) { value -= other.value; return *this; } FFixedPoint &operator /= (int factor) { value /= factor; return *this; } FFixedPoint operator * (int factor) const { FFixedPoint result; result.value = value * factor; return result; } explicit operator double() const { return value / kFracUnitD; } explicit operator int() const { return value / kFracUnit; } bool operator ! () const { return !value; } FFixedPoint abs() const { FFixedPoint result; result.value = ::abs(value); return result; } private: int value; }; static_assert(sizeof(FFixedPoint) == sizeof(int), "FixedPoint must be same size as int"); #endif eureka-editor-eureka-2.0.2/src/Instance.cc000066400000000000000000000014051464327712600204030ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2020 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Instance.h" Instance *gInstance; eureka-editor-eureka-2.0.2/src/Instance.h000066400000000000000000000353251464327712600202550ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2020 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef INSTANCE_H_ #define INSTANCE_H_ #include "bsp.h" #include "Document.h" #include "e_main.h" #include "im_img.h" #include "m_game.h" #include "m_loadsave.h" #include "m_nodes.h" #include "main.h" #include "r_grid.h" #include "r_render.h" #include "r_subdiv.h" #include "ui_file.h" #include "w_texture.h" #include "w_wad.h" #include "WadData.h" #include class Fl_RGB_Image; class Lump_c; class UI_NodeDialog; class UI_ProjectSetup; struct BadCount; struct NewDocument; struct v2double_t; struct v2int_t; // // For SelectNeighborLines and SelectNeighborSectors // enum SelectNeighborCriterion { height, texture, }; // // An instance with a document, holding all other associated data, such as the window reference, the // wad list. // class Instance : public grid::Listener { public: // E_COMMANDS void ACT_Click_release(); void ACT_Drag_release(); void ACT_SelectBox_release(); void ACT_Transform_release(); void ACT_AdjustOfs_release(); void CheckBeginDrag(); void CMD_AboutDialog(); void CMD_ACT_Drag(); void CMD_ACT_Click(); void CMD_ACT_SelectBox(); void CMD_ACT_Transform(); void CMD_AddBehaviorLump(); void CMD_ApplyTag(); void CMD_BR_ClearSearch(); void CMD_BR_CycleCategory(); void CMD_BR_Scroll(); void CMD_BrowserMode(); void CMD_BuildAllNodes(); void CMD_Clipboard_Copy(); void CMD_Clipboard_Cut(); void CMD_Clipboard_Paste(); void CMD_CopyAndPaste(); void CMD_CopyMap(); void CMD_CopyProperties(); void CMD_DefaultProps(); void CMD_Delete(); void CMD_DeleteMap(); void CMD_Disconnect(); void CMD_EditLump(); void CMD_EditMode(); void CMD_Enlarge(); void CMD_ExportMap(); void CMD_FindDialog(); void CMD_FindNext(); void CMD_FlipMap(); void CMD_FreshMap(); void CMD_GivenFile(); void CMD_GoToCamera(); void CMD_GRID_Bump(); void CMD_GRID_Set(); void CMD_GRID_Zoom(); void CMD_InvertSelection(); void CMD_JumpToObject(); void CMD_LastSelection(); void CMD_LIN_Align(); void CMD_LIN_Flip(); void CMD_LIN_SelectPath(); void CMD_LIN_SplitHalf(); void CMD_LIN_SwapSides(); void CMD_LogViewer(); void CMD_ManageProject(); void CMD_MapCheck(); void CMD_Merge(); void CMD_MetaKey(); void CMD_Mirror(); void CMD_MoveObjects_Dialog(); void CMD_NAV_MouseScroll(); void CMD_NAV_Scroll_Down(); void CMD_NAV_Scroll_Left(); void CMD_NAV_Scroll_Right(); void CMD_NAV_Scroll_Up(); void CMD_NewProject(); void CMD_Nothing(); void CMD_ObjectInsert(); void CMD_OnlineDocs(); void CMD_OpenMap(); void CMD_OperationMenu(); void CMD_PlaceCamera(); void CMD_Preferences(); void CMD_PruneUnused(); void CMD_Quantize(); void CMD_Quit(); void CMD_RecalcSectors(); void CMD_RenameMap(); void CMD_Redo(); void CMD_Rotate90(); void CMD_RotateObjects_Dialog(); void CMD_SaveMap(); void CMD_ScaleObjects_Dialog(); void CMD_Scroll(); void CMD_SEC_Ceil(); void CMD_SEC_Floor(); void CMD_SEC_Light(); void CMD_SEC_SelectGroup(); void CMD_SEC_SwapFlats(); void CMD_Select(); void CMD_SelectAll(); void CMD_SelectNeighbors(); void CMD_SetVar(); void CMD_Shrink(); void CMD_TestMap(); void CMD_ChangeTestSettings(); void CMD_TH_SpinThings(); void CMD_ToggleVar(); void CMD_Undo(); void CMD_UnselectAll(); void CMD_VT_ShapeArc(); void CMD_VT_ShapeLine(); void CMD_WHEEL_Scroll(); void CMD_Zoom(); void CMD_ZoomSelection(); void CMD_ZoomWholeMap(); void NAV_MouseScroll_release(); void NAV_Scroll_Left_release(); void NAV_Scroll_Right_release(); void NAV_Scroll_Up_release(); void NAV_Scroll_Down_release(); void R3D_ACT_AdjustOfs(); void R3D_Backward(); void R3D_Forward(); void R3D_Left(); void R3D_NAV_Forward(); void R3D_NAV_Forward_release(); void R3D_NAV_Back(); void R3D_NAV_Back_release(); void R3D_NAV_Right(); void R3D_NAV_Right_release(); void R3D_NAV_Left(); void R3D_NAV_Left_release(); void R3D_NAV_Up(); void R3D_NAV_Up_release(); void R3D_NAV_Down(); void R3D_NAV_Down_release(); void R3D_NAV_TurnLeft(); void R3D_NAV_TurnLeft_release(); void R3D_NAV_TurnRight(); void R3D_NAV_TurnRight_release(); void R3D_Down(); void R3D_DropToFloor(); void R3D_Right(); void R3D_Set(); void R3D_Toggle(); void R3D_Turn(); void R3D_Up(); void R3D_WHEEL_Move(); void Transform_Update(); // E_LINEDEF bool LD_RailHeights(int &z1, int &z2, const LineDef *L, const SideDef *sd, const Sector *front, const Sector *back) const; // E_MAIN void Editor_ChangeMode(char mode_char); void Editor_ChangeMode_Raw(ObjType new_mode); void Editor_ClearAction() noexcept; void Editor_Init(); bool Editor_ParseUser(const std::vector &tokens); void Editor_WriteUser(std::ostream &os) const; void MapStuff_NotifyBegin(); void MapStuff_NotifyChange(ObjType type, int objnum, int field); void MapStuff_NotifyDelete(ObjType type, int objnum); void MapStuff_NotifyEnd(); void MapStuff_NotifyInsert(ObjType type, int objnum); void ObjectBox_NotifyBegin(); void ObjectBox_NotifyChange(ObjType type, int objnum, int field); void ObjectBox_NotifyDelete(ObjType type, int objnum); void ObjectBox_NotifyEnd() const; void ObjectBox_NotifyInsert(ObjType type, int objnum); bool RecUsed_ParseUser(const std::vector &tokens); void RecUsed_WriteUser(std::ostream &os) const; void RedrawMap(); void Selection_Clear(bool no_save = false); void Selection_InvalidateLast() noexcept; void Selection_NotifyBegin(); void Selection_NotifyDelete(ObjType type, int objnum); void Selection_NotifyEnd(); void Selection_NotifyInsert(ObjType type, int objnum); void Selection_Push(); void UpdateHighlight(); void ZoomWholeMap(); // E_PATH void GoToErrors(); void GoToObject(const Objid &objid); void GoToSelection(); const byte *SoundPropagation(int start_sec); // M_CONFIG void M_DefaultUserState(); bool M_LoadUserState(); bool M_SaveUserState() const; // M_EVENTS void ClearStickyMod(); void Editor_ScrollMap(int mode, v2int_t dpos = {}, keycode_t mod = 0); void Editor_SetAction(EditorAction new_action); void EV_EscapeKey(); int EV_HandleEvent(int event); void M_LoadOperationMenus(); bool Nav_ActionKey(keycode_t key, nav_release_func_t func); void Nav_Clear(); void Nav_Navigate(); bool Nav_SetKey(keycode_t key, nav_release_func_t func); unsigned Nav_TimeDiff(); // M_FILES fs::path M_PickDefaultIWAD() const; bool M_TryOpenMostRecent(); // M_GAME bool is_sky(const SString &flat) const; char M_GetFlatType(const SString &name) const; const sectortype_t &M_GetSectorType(int type) const; char M_GetTextureType(const SString &name) const; SString M_LineCategoryString(SString &letters) const; SString M_TextureCategoryString(SString &letters, bool do_flats) const; SString M_ThingCategoryString(SString &letters) const; // M_KEYS void Beep(EUR_FORMAT_STRING(const char *fmt), ...) EUR_PRINTF(2, 3); bool Exec_HasFlag(const char *flag) const; bool ExecuteCommand(const editor_command_t *cmd, const SString ¶m1 = "", const SString ¶m2 = "", const SString ¶m3 = "", const SString ¶m4 = ""); bool ExecuteCommand(const SString &name, const SString ¶m1 = "", const SString ¶m2 = "", const SString ¶m3 = "", const SString ¶m4 = ""); bool ExecuteKey(keycode_t key, KeyContext context); // M_LOADSAVE NewDocument openDocument(const LoadingData &inLoading, const Wad_file &wad, int level); void LoadLevel(const Wad_file *wad, const SString &level) noexcept(false); void LoadLevelNum(const Wad_file *wad, int lev_num) noexcept(false); bool MissingIWAD_Dialog(); bool M_SaveMap(bool inhibit_node_build); void refreshViewAfterLoad(const BadCount& bad, const Wad_file* wad, const SString& map_name, bool new_resources); // M_NODES void BuildNodesAfterSave(int lev_idx, const LoadingData& loading, Wad_file &wad); void GB_PrintMsg(EUR_FORMAT_STRING(const char *str), ...) EUR_PRINTF(2, 3); // M_TESTMAP bool M_PortSetupDialog(const SString& port, const SString& game, const tl::optional &commandLine); // M_UDMF void UDMF_LoadLevel(int loading_level, const Wad_file *load_wad, Document &doc, LoadingData &loading, BadCount &bad) const; void UDMF_SaveLevel(const LoadingData &loading, Wad_file &wad) const; // MAIN fs::path Main_FileOpFolder() const; void Main_LoadResources(const LoadingData &loading) noexcept(false); void UpdateViewOnResources(); // R_RENDER void Render3D_CB_Copy() ; void Render3D_GetCameraPos(v2double_t &pos, float *angle) const; void Render3D_MouseMotion(v2int_t pos, keycode_t mod, v2int_t dpos); bool Render3D_ParseUser(const std::vector &tokens); void Render3D_SetCameraPos(const v2double_t &newpos); void Render3D_Setup(); void Render3D_UpdateHighlight(); void Render3D_WriteUser(std::ostream &os) const; // R_SOFTWARE bool SW_QueryPoint(Objid &hl, int qx, int qy); void SW_RenderWorld(int ox, int oy, int ow, int oh); // R_SUBDIV sector_3dfloors_c *Subdiv_3DFloorsForSector(int num); void Subdiv_InvalidateAll() noexcept; bool Subdiv_SectorOnScreen(int num, double map_lx, double map_ly, double map_hx, double map_hy); sector_subdivision_c *Subdiv_PolygonsForSector(int num); // UI_BROWSER void Browser_WriteUser(std::ostream &os) const; // UI_DEFAULT void Props_WriteUser(std::ostream &os) const; // UI_INFOBAR void Status_Set(EUR_FORMAT_STRING(const char *fmt), ...) const EUR_PRINTF(2, 3); void Status_Clear() const; // GridListener void gridRedrawMap() override { RedrawMap(); } void gridSetGrid(int grid) override { if (main_win) main_win->info_bar->SetGrid(grid); } void gridUpdateSnap() override { if (main_win) main_win->info_bar->UpdateSnap(); } void gridAdjustPos() override { if (main_win) main_win->scroll->AdjustPos(); } void gridPointerPos() override { if (main_win) main_win->canvas->PointerPos(); } void gridSetScale(double scale) override { if (main_win) main_win->info_bar->SetScale(scale); } void gridBeep(const char *message) override { Beep("%s", message); } void gridUpdateRatio() override { if(main_win) main_win->info_bar->UpdateRatio(); } private: // New private methods void navigationScroll(float *editNav, nav_release_func_t func); void navigation3DMove(float *editNav, nav_release_func_t func, bool fly); void navigation3DTurn(float *editNav, nav_release_func_t func); // E_COMMANDS void DoBeginDrag(); // E_CUTPASTE bool Clipboard_DoCopy(); bool Clipboard_DoPaste(); void ReselectGroup(); // E_LINEDEF void commandLinedefMergeTwo(); // E_MAIN void Editor_ClearErrorMode(); void UpdateDrawLine(); void zoom_fit(); void SelectNeighborSectors(int objnum, SelectNeighborCriterion option, byte parts); // E_SECTOR void commandSectorMerge(); // E_VERTEX void commandLineDisconnect(); void commandSectorDisconnect(); void commandVertexDisconnect(); void commandVertexMerge(); // M_EVENTS void Editor_Zoom(int delta, v2int_t mid); void EV_EnterWindow(); void EV_LeaveWindow(); void EV_MouseMotion(v2int_t pos, keycode_t mod, v2int_t dpos); int EV_RawButton(int event); int EV_RawKey(int event); int EV_RawMouse(int event); int EV_RawWheel(int event); void M_AddOperationMenu(const SString &context, Fl_Menu_Button *menu); bool M_ParseOperationFile(); // M_KEYS void DoExecuteCommand(const editor_command_t *cmd); // M_LOADSAVE void FreshLevel(); bool M_ExportMap(bool inhibit_node_build); void Navigate2D(); void Project_ApplyChanges(const UI_ProjectSetup::Result &result) noexcept(false); tl::optional Project_AskFile() const; void SaveLevel(LoadingData &loading, const SString &level, Wad_file &wad, bool inhibit_node_build); void ConfirmLevelSaveSuccess(const LoadingData &loading, const Wad_file &wad); void SaveLevelAndUpdateWindow(LoadingData& loading, const SString& level, Wad_file &wad, bool inhibit_node_build); // M_NODES build_result_e BuildAllNodes(nodebuildinfo_t *info); // R_GRID // R_RENDER StringID GrabSelectedFlat(); StringID GrabSelectedTexture(); int GrabSelectedThing(); StringID LD_GrabTex(const LineDef *L, int part) const; void Render3D_CB_Cut(); void Render3D_CB_Paste(); void Render3D_Navigate(); void StoreDefaultedFlats(); void StoreSelectedFlat(StringID new_tex); void StoreSelectedTexture(StringID new_tex); void StoreSelectedThing(int new_type); public: // will be private when we encapsulate everything Document level{*this}; // level data proper UI_MainWindow *main_win = nullptr; Editor_State_t edit = {}; // // Wad settings // LoadingData loaded; // // Game-dependent (thus instance dependent) defaults // ConfigData conf; // // Panel stuff // bool changed_panel_obj = false; bool changed_recent_list = false; bool invalidated_last_sel = false; bool invalidated_panel_obj = false; bool invalidated_selection = false; bool invalidated_totals = false; // // Selection stuff // tl::optional last_Sel; // // Document stuff // int moved_vertex_count = 0; int new_vertex_minimum = 0; bool recalc_map_bounds = false; // the containers for the textures (etc) Recently_used recent_flats{ *this }; Recently_used recent_textures{ *this }; Recently_used recent_things{ *this }; int last_given_file = 0; tl::optional nodeialog; nodebuildinfo_t *nb_info = nullptr; int tagInMemory = 0; WadData wad; // // Path stuff // bool sound_propagation_invalid = false; std::vector sound_prop_vec; std::vector sound_temp1_vec; std::vector sound_temp2_vec; int sound_start_sec = 0; // // IO stuff // nav_active_key_t cur_action_key = {}; bool in_operation_menu = false; v2int_t mouse_last_pos = {}; nav_active_key_t nav_actives[MAX_NAV_ACTIVE_KEYS] = {}; unsigned nav_time = 0; bool no_operation_cfg = false; std::unordered_map op_all_menus; // these are grabbed from FL_MOUSEWHEEL events v2int_t wheel_dpos = {}; // key or mouse button pressed for command, 0 when none keycode_t EXEC_CurKey = {}; // result from command function, 0 is OK int EXEC_Errno = 0; SString EXEC_Flags[MAX_EXEC_PARAM] = {}; SString EXEC_Param[MAX_EXEC_PARAM] = {}; // // Rendering // grid::State grid{ *this }; Render_View_t r_view{ *this }; sector_info_cache_c sector_info_cache{ *this }; }; extern Instance *gInstance; // for now we run with one instance, will have more for the MDI. #endif eureka-editor-eureka-2.0.2/src/LineDef.cc000066400000000000000000000017241464327712600201510ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "LineDef.h" #include "Errors.h" int LineDef::WhatSideDef(Side side) const { switch (side) { case Side::left: return left; case Side::right: return right; default: BugError("bad side : %d\n", (int)side); return -1; } } eureka-editor-eureka-2.0.2/src/LineDef.h000066400000000000000000000035471464327712600200200ustar00rootroot00000000000000 //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef LINEDEF_H_ #define LINEDEF_H_ #include "Side.h" class LineDef { public: int start = 0; int end = 0; int right = -1; int left = -1; int flags = 0; int type = 0; int tag = 0; // Hexen stuff [NOTE: tag is 'arg1'] int arg2 = 0; int arg3 = 0; int arg4 = 0; int arg5 = 0; enum { F_START, F_END, F_RIGHT, F_LEFT, F_FLAGS, F_TYPE, F_TAG, F_ARG2, F_ARG3, F_ARG4, F_ARG5 }; public: bool TouchesVertex(int v_num) const { return (start == v_num) || (end == v_num); } // // Assuming TouchesVertex(v_num), return the other one. Undefined otherwise. // int OtherVertex(int v_num) const { return start == v_num ? end : start; } bool NoSided() const { return (right < 0) && (left < 0); } bool OneSided() const { return (right >= 0) && (left < 0); } bool TwoSided() const { return (right >= 0) && (left >= 0); } // side is either SIDE_LEFT or SIDE_RIGHT int WhatSideDef(Side side) const; int Arg(int which /* 1..5 */) const { if (which == 1) return tag; if (which == 2) return arg2; if (which == 3) return arg3; if (which == 4) return arg4; if (which == 5) return arg5; return 0; } }; #endif eureka-editor-eureka-2.0.2/src/PrintfMacros.h000066400000000000000000000023751464327712600211170ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2020 Ioan Chera // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef PrintfMacros_h #define PrintfMacros_h // // Printf detection // #ifndef __GNUC__ #define EUR_PRINTF(f, a) #else #define EUR_PRINTF(f, a) __attribute__((format(printf, f, a))) #endif #if _MSC_VER >= 1400 && defined(_DEBUG) #include #if _MSC_VER > 1400 #define EUR_FORMAT_STRING(p) _Printf_format_string_ p #else #define EUR_FORMAT_STRING(p) __format_string p #endif #else #define EUR_FORMAT_STRING(p) p #endif #endif /* PrintfMacros_h */ eureka-editor-eureka-2.0.2/src/SafeOutFile.cc000066400000000000000000000030311464327712600210020ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2021 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "lib_file.h" #include "lib_util.h" #include "Errors.h" #include "SafeOutFile.h" #include "sys_debug.h" #include // // Writes data to file // void BufferedOutFile::write(const void *vdata, size_t size) { auto data = static_cast(vdata); mData.insert(mData.end(), data, data + size); } // WARNING: this throws. void BufferedOutFile::commit() { try { std::ofstream stream; stream.exceptions(std::ios::failbit); stream.open(mPath, std::ios::out | std::ios::binary); stream.write(reinterpret_cast(mData.data()), mData.size()); } catch(const std::ofstream::failure &e) { SString errorMessage = GetErrorMessage(e.code().value()); gLog.printf("Failed writing %s: %s\n", mPath.u8string().c_str(), errorMessage.c_str()); throw std::runtime_error(errorMessage.get()); } } eureka-editor-eureka-2.0.2/src/SafeOutFile.h000066400000000000000000000024611464327712600206520ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2021 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef SafeOutFile_h #define SafeOutFile_h #include "filesystem.hpp" namespace fs = ghc::filesystem; #include // // Exception-safe, atomic file writer. It starts by writing everything to an // authorized temp path, only replacing the target path by committing to it. // // Does NOT directly throw exceptions. // class BufferedOutFile { public: explicit BufferedOutFile(const fs::path& path) : mPath(path) { } void write(const void* data, size_t size); void commit(); private: const fs::path mPath; // the target path std::vector mData; }; #endif /* SafeOutFile_h */ eureka-editor-eureka-2.0.2/src/Sector.cc000066400000000000000000000023221464327712600200750ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Sector.h" #include "e_basis.h" #include "m_game.h" SString Sector::FloorTex() const noexcept { return BA_GetString(floor_tex); } SString Sector::CeilTex() const noexcept { return BA_GetString(ceil_tex); } void Sector::SetDefaults(const ConfigData &config) { floorh = global::default_floor_h; ceilh = global::default_ceil_h; floor_tex = BA_InternaliseString(config.default_floor_tex); ceil_tex = BA_InternaliseString(config.default_ceil_tex); light = global::default_light_level; } eureka-editor-eureka-2.0.2/src/Sector.h000066400000000000000000000023751464327712600177470ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef SECTOR_H_ #define SECTOR_H_ #include "m_strings.h" struct ConfigData; struct Sector { int floorh = 0; int ceilh = 0; StringID floor_tex; StringID ceil_tex; int light = 0; int type = 0; int tag = 0; enum IntAddress { F_FLOORH, F_CEILH, F_LIGHT = 4, F_TYPE, F_TAG, }; enum StringIDAddress { F_FLOOR_TEX = 2, F_CEIL_TEX = 3, }; SString FloorTex() const noexcept; SString CeilTex() const noexcept; int HeadRoom() const { return ceilh - floorh; } void SetDefaults(const ConfigData &config); }; #endif eureka-editor-eureka-2.0.2/src/Side.h000066400000000000000000000023101464327712600173610ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef SIDE_H_ #define SIDE_H_ enum class Side { right, left, neither }; static const Side kSides[] = { Side::right, Side::left }; inline static Side operator - (Side side) { if(side == Side::right) return Side::left; if(side == Side::left) return Side::right; return side; } inline static Side operator * (Side side1, Side side2) { if(side1 == Side::neither || side2 == Side::neither) return Side::neither; if(side1 != side2) return Side::left; return Side::right; } #endif eureka-editor-eureka-2.0.2/src/SideDef.cc000066400000000000000000000025061464327712600201450ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "SideDef.h" #include "Document.h" #include "e_basis.h" #include "m_game.h" #include "m_strings.h" SString SideDef::UpperTex() const { return BA_GetString(upper_tex); } SString SideDef::MidTex() const { return BA_GetString(mid_tex); } SString SideDef::LowerTex() const { return BA_GetString(lower_tex); } void SideDef::SetDefaults(const ConfigData &config, bool two_sided, StringID new_tex) { if (new_tex.get() < 0) new_tex = BA_InternaliseString(config.default_wall_tex); lower_tex = new_tex; upper_tex = new_tex; if (two_sided) mid_tex = BA_InternaliseString("-"); else mid_tex = new_tex; } eureka-editor-eureka-2.0.2/src/SideDef.h000066400000000000000000000025311464327712600200050ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef SIDEDEF_H_ #define SIDEDEF_H_ #include "m_strings.h" struct Sector; struct ConfigData; struct Document; struct SideDef { int x_offset = 0; int y_offset = 0; StringID upper_tex; StringID mid_tex; StringID lower_tex; int sector = 0; enum IntAddress { F_X_OFFSET, F_Y_OFFSET, F_SECTOR = 5, }; enum StringIDAddress { F_UPPER_TEX = 2, F_MID_TEX, F_LOWER_TEX, }; SString UpperTex() const; SString MidTex() const; SString LowerTex() const; // use new_tex when >= 0, otherwise use default_wall_tex void SetDefaults(const ConfigData &config, bool two_sided, StringID new_tex = StringID(-1)); }; #endif eureka-editor-eureka-2.0.2/src/Thing.cc000066400000000000000000000020111464327712600177020ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Thing.h" #include "e_basis.h" void Thing::SetRawX(MapFormat format, double x) { raw_x = MakeValidCoord(format, x); } void Thing::SetRawY(MapFormat format, double y) { raw_y = MakeValidCoord(format, y); } void Thing::SetRawH(MapFormat format, double h) { raw_h = MakeValidCoord(format, h); }eureka-editor-eureka-2.0.2/src/Thing.h000066400000000000000000000041221464327712600175510ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef THING_H_ #define THING_H_ #include "m_vector.h" #include "FixedPoint.h" // // Must be here due to dependencies // enum class MapFormat { invalid, doom, hexen, udmf }; struct Thing { FFixedPoint raw_x = {}; FFixedPoint raw_y = {}; int angle = 0; int type = 0; int options = 0; // Hexen stuff FFixedPoint raw_h = {}; int tid = 0; int special = 0; int arg1 = 0, arg2 = 0, arg3 = 0, arg4 = 0, arg5 = 0; enum IntAddress { F_ANGLE = 2, F_TYPE, F_OPTIONS, F_TID = 6, F_SPECIAL, F_ARG1, F_ARG2, F_ARG3, F_ARG4, F_ARG5, }; enum FixedPointAddress { F_X, F_Y, F_H = 5, }; inline double x() const { return static_cast(raw_x); } inline double y() const { return static_cast(raw_y); } inline double h() const { return static_cast(raw_h); } inline v2double_t xy() const { return { x(), y() }; } // these handle rounding to integer in non-UDMF mode void SetRawX(MapFormat format, double x); void SetRawY(MapFormat format, double y); void SetRawH(MapFormat format, double h); void SetRawXY(MapFormat format, const v2double_t &pos) { SetRawX(format, pos.x); SetRawY(format, pos.y); } int Arg(int which /* 1..5 */) const { if (which == 1) return arg1; if (which == 2) return arg2; if (which == 3) return arg3; if (which == 4) return arg4; if (which == 5) return arg5; return 0; } }; #endif eureka-editor-eureka-2.0.2/src/Vertex.cc000066400000000000000000000017321464327712600201170ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2023 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Vertex.h" // these handle rounding to integer in non-UDMF mode void Vertex::SetRawX(MapFormat format, double x) { raw_x = MakeValidCoord(format, x); } void Vertex::SetRawY(MapFormat format, double y) { raw_y = MakeValidCoord(format, y); }eureka-editor-eureka-2.0.2/src/Vertex.h000066400000000000000000000033171464327712600177620ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef VERTEX_H_ #define VERTEX_H_ #include "e_basis.h" #include "FixedPoint.h" #include "m_vector.h" class Instance; struct Vertex { FFixedPoint raw_x = {}; FFixedPoint raw_y = {}; enum { F_X, F_Y }; inline double x() const noexcept { return static_cast(raw_x); } inline double y() const noexcept { return static_cast(raw_y); } inline v2double_t xy() const noexcept { return { x(), y() }; } // these handle rounding to integer in non-UDMF mode void SetRawX(MapFormat format, double x); void SetRawY(MapFormat format, double y); void SetRawXY(MapFormat format, const v2double_t &pos) { SetRawX(format, pos.x); SetRawY(format, pos.y); } bool Matches(FFixedPoint ox, FFixedPoint oy) const { return (raw_x == ox) && (raw_y == oy); } bool operator == (const Vertex &other) const { return raw_x == other.raw_x && raw_y == other.raw_y; } bool operator != (const Vertex &other) const { return raw_x != other.raw_x || raw_y != other.raw_y; } }; #endif eureka-editor-eureka-2.0.2/src/WadData.cc000066400000000000000000000050571464327712600201530ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2021 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "WadData.h" #include "m_config.h" #include "m_loadsave.h" #include "w_wad.h" // // Comparator for the master directory lumps // bool LumpNameCompare::operator()(const Lump_c &lump1, const Lump_c &lump2) const { return lump1.Name() < lump2.Name(); } // // Locates the first four-stem sprite from the master dir // std::vector MasterDir::findFirstSpriteLump(const SString &stem) const { SString firstName; std::vector result; std::vector> wads = getAll(); for(auto it = wads.rbegin(); it != wads.rend(); ++it) { std::vector spriteset = (*it)->findFirstSpriteLump(stem); if(spriteset.empty()) continue; if(spriteset.size() == 1) return spriteset; if(result.empty()) result = spriteset; else { for(size_t i = 0; i < spriteset.size(); ++i) if(!result[i].lump && spriteset[i].lump) result[i] = spriteset[i]; } } return result; } void WadData::W_LoadPalette() noexcept(false) { const Lump_c *lump = master.findGlobalLump("PLAYPAL"); if(!lump) { ThrowException("PLAYPAL lump not found.\n"); } palette.loadPalette(*lump, config::usegamma, config::panel_gamma); images.IM_ResetDummyTextures(); } void WadData::reloadResources(const std::shared_ptr &gameWad, const ConfigData &config, const std::vector> &resourceWads) noexcept(false) { // reset the master directory WadData newWad = *this; try { newWad.master.setGameWad(gameWad); newWad.master.setResources(resourceWads); // finally, load textures and stuff... newWad.W_LoadPalette(); newWad.W_LoadColormap(); newWad.W_LoadFlats(); newWad.W_LoadTextures(config); newWad.images.W_ClearSprites(); } catch(const std::runtime_error &e) { gLog.printf("Failed reloading resources: %s", e.what()); throw; } // Commit *this = newWad; } eureka-editor-eureka-2.0.2/src/WadData.h000066400000000000000000000146161464327712600200160ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2021 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef WadData_h #define WadData_h #include "im_color.h" #include "im_img.h" #include "m_strings.h" #include "sys_type.h" #include "filesystem.hpp" namespace fs = ghc::filesystem; #include #include #include #include #include class Img_c; class Lump_c; class Palette; class Wad_file; struct ConfigData; struct LoadingData; struct SpriteLumpRef; // maps type number to an image typedef std::map> sprite_map_t; // can have one or eight images // // Wad image set // class ImageSet { public: const Img_c &IM_SpecialTex(const Palette &palette); Img_c &getMutableSpecialTexture(const Palette &palette) { return const_cast(IM_SpecialTex(palette)); } const Img_c &IM_MissingTex(const ConfigData &config); Img_c &getMutableMissingTexture(const ConfigData &config) { return const_cast(IM_MissingTex(config)); } const Img_c &IM_UnknownTex(const ConfigData &config); Img_c &getMutableUnknownTexture(const ConfigData &config) { return const_cast(IM_UnknownTex(config)); } const Img_c &IM_UnknownFlat(const ConfigData &config); Img_c &getMutableUnknownFlat(const ConfigData &config) { return const_cast(IM_UnknownFlat(config)); } Img_c &IM_UnknownSprite(const ConfigData &config); Img_c &IM_DigitFont_11x14(); Img_c &IM_DigitFont_14x19(); void IM_UnloadDummyTextures(); void IM_ResetDummyTextures(); void W_AddTexture(const SString &name, Img_c &&img, bool is_medusa); const Img_c *getTexture(const ConfigData &config, const SString &name, bool try_uppercase = false) const; Img_c *getMutableTexture(const ConfigData &config, const SString &name, bool try_uppercase = false) { return const_cast(getTexture(config, name, try_uppercase)); } int W_GetTextureHeight(const ConfigData &config, const SString &name) const; bool W_TextureCausesMedusa(const SString &name) const; bool W_TextureIsKnown(const ConfigData &config, const SString &name) const; void W_ClearTextures(); const std::map &getTextures() const { return textures; } void W_AddFlat(const SString &name, Img_c &&img); const Img_c *W_GetFlat(const ConfigData &config, const SString &name, bool try_uppercase = false) const noexcept; Img_c *getMutableFlat(const ConfigData &config, const SString &name, bool try_uppercase = false) { return const_cast(W_GetFlat(config, name, try_uppercase)); } bool W_FlatIsKnown(const ConfigData &config, const SString &name) const; void W_ClearFlats(); const std::map &getFlats() const { return flats; } void W_ClearSprites(); void W_UnloadAllTextures(); public: // TODO: make private sprite_map_t sprites; private: std::map textures; // textures which can cause the Medusa Effect in vanilla/chocolate DOOM std::map medusa_textures; std::map flats; int missing_tex_color = 0; tl::optional missing_tex_image; int unknown_tex_color = 0; tl::optional unknown_tex_image; int special_tex_color = 0; tl::optional special_tex_image; int unknown_flat_color = 0; tl::optional unknown_flat_image; int unknown_sprite_color = 0; tl::optional unknown_sprite_image; tl::optional digit_font_11x14; tl::optional digit_font_14x19; }; struct LumpNameCompare { bool operator()(const Lump_c &lump1, const Lump_c &lump2) const; }; // // Manages the WAD loading // class MasterDir { public: void setGameWad(const std::shared_ptr &gameWad) { game_wad = gameWad; } void RemoveEditWad() { edit_wad.reset(); } void ReplaceEditWad(const std::shared_ptr &wad) { edit_wad = wad; } void setResources(const std::vector> &wads) { resource_wads = wads; } void MasterDir_CloseAll(); bool MasterDir_HaveFilename(const SString &chk_path) const; const Lump_c *findGlobalLump(const SString &name) const; std::vector findFirstSpriteLump(const SString &stem) const; const std::shared_ptr &gameWad() const { return game_wad; } const std::shared_ptr &editWad() const noexcept { return edit_wad; } const std::shared_ptr &activeWad() const { return edit_wad ? edit_wad : game_wad; } const std::vector> &resourceWads() const { return resource_wads; } std::vector> getAll() const { std::vector> result; result.reserve(resource_wads.size() + 2); if(game_wad) result.push_back(game_wad); result.insert(result.end(), resource_wads.begin(), resource_wads.end()); if(edit_wad) result.push_back(edit_wad); return result; } private: // the current PWAD, or NULL for none. // when present it is also at master_dir.back() std::shared_ptr edit_wad; std::vector> resource_wads; std::shared_ptr game_wad; }; // // Wad data, loaded during resource setup // struct WadData { void loadDehacked(ConfigData &config); void W_LoadTextures(const ConfigData &config); const Img_c *getSprite(const ConfigData &config, int type, const LoadingData &loading, int rot); Img_c *getMutableSprite(const ConfigData &config, int type, const LoadingData &loading, int rot) { return const_cast(getSprite(config, type, loading, rot)); } void reloadResources(const std::shared_ptr &gameWad, const ConfigData &config, const std::vector> &resourceWads) noexcept(false); ImageSet images; Palette palette; MasterDir master; private: void W_LoadPalette() noexcept(false); void W_LoadColormap() { palette.loadColormap(master.findGlobalLump("COLORMAP")); } void W_LoadFlats(); }; #endif /* WadData_h */ eureka-editor-eureka-2.0.2/src/WindowsInclude.h000066400000000000000000000016131464327712600214400ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2020 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef WINDOWSINCLUDE_H_ #define WINDOWSINCLUDE_H_ #define WIN32_LEAN_AND_MEAN #include #ifndef WIN32 #define WIN32 #endif #include "WindowsSanitization.h" #endifeureka-editor-eureka-2.0.2/src/WindowsSanitization.h000066400000000000000000000112331464327712600225300ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2020 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // Cleans up all the pollution caused by Windows and Linux // Clear out X11 pollution #ifdef Bool #undef Bool #endif #ifdef None #undef None #endif #ifdef min #undef min #endif #ifdef max #undef max #endif #ifdef grp1 // // Constant Declarations. // #undef ctlFirst #undef ctlLast // // Push buttons. // #undef psh1 #undef psh2 #undef psh3 #undef psh4 #undef psh5 #undef psh6 #undef psh7 #undef psh8 #undef psh9 #undef psh10 #undef psh11 #undef psh12 #undef psh13 #undef psh14 #undef psh15 #undef pshHelp #undef psh16 // // Checkboxes. // #undef chx1 #undef chx2 #undef chx3 #undef chx4 #undef chx5 #undef chx6 #undef chx7 #undef chx8 #undef chx9 #undef chx10 #undef chx11 #undef chx12 #undef chx13 #undef chx14 #undef chx15 #undef chx16 // // Radio buttons. // #undef rad1 #undef rad2 #undef rad3 #undef rad4 #undef rad5 #undef rad6 #undef rad7 #undef rad8 #undef rad9 #undef rad10 #undef rad11 #undef rad12 #undef rad13 #undef rad14 #undef rad15 #undef rad16 // // Groups, frames, rectangles, and icons. // #undef grp1 #undef grp2 #undef grp3 #undef grp4 #undef frm1 #undef frm2 #undef frm3 #undef frm4 #undef rct1 #undef rct2 #undef rct3 #undef rct4 #undef ico1 #undef ico2 #undef ico3 #undef ico4 // // Static text. // #undef stc1 #undef stc2 #undef stc3 #undef stc4 #undef stc5 #undef stc6 #undef stc7 #undef stc8 #undef stc9 #undef stc10 #undef stc11 #undef stc12 #undef stc13 #undef stc14 #undef stc15 #undef stc16 #undef stc17 #undef stc18 #undef stc19 #undef stc20 #undef stc21 #undef stc22 #undef stc23 #undef stc24 #undef stc25 #undef stc26 #undef stc27 #undef stc28 #undef stc29 #undef stc30 #undef stc31 #undef stc32 // // Listboxes. // #undef lst1 #undef lst2 #undef lst3 #undef lst4 #undef lst5 #undef lst6 #undef lst7 #undef lst8 #undef lst9 #undef lst10 #undef lst11 #undef lst12 #undef lst13 #undef lst14 #undef lst15 #undef lst16 // // Combo boxes. // #undef cmb1 #undef cmb2 #undef cmb3 #undef cmb4 #undef cmb5 #undef cmb6 #undef cmb7 #undef cmb8 #undef cmb9 #undef cmb10 #undef cmb11 #undef cmb12 #undef cmb13 #undef cmb14 #undef cmb15 #undef cmb16 // // Edit controls. // #undef edt1 #undef edt2 #undef edt3 #undef edt4 #undef edt5 #undef edt6 #undef edt7 #undef edt8 #undef edt9 #undef edt10 #undef edt11 #undef edt12 #undef edt13 #undef edt14 #undef edt15 #undef edt16 // // Scroll bars. // #undef scr1 #undef scr2 #undef scr3 #undef scr4 #undef scr5 #undef scr6 #undef scr7 #undef scr8 // // Controls // #undef ctl1 #undef FILEOPENORD #undef MULTIFILEOPENORD #undef PRINTDLGORD #undef PRNSETUPDLGORD #undef FINDDLGORD #undef REPLACEDLGORD #undef FONTDLGORD #undef FORMATDLGORD31 #undef FORMATDLGORD30 #undef RUNDLGORD #if (WINVER >= 0x400) #undef PAGESETUPDLGORD #undef NEWFILEOPENORD #undef PRINTDLGEXORD #undef PAGESETUPDLGORDMOTIF #undef COLORMGMTDLGORD #undef NEWFILEOPENV2ORD #endif /* WINVER >= 0x400) */ // 1581 - 1590 #if (NTDDI_VERSION >= NTDDI_VISTA) #undef NEWFILEOPENV3ORD #endif // NTDDI_VISTA // 1591 - 1600 #if (NTDDI_VERSION >= NTDDI_WIN7) #undef NEWFORMATDLGWITHLINK #undef IDC_MANAGE_LINK #endif #endif // defined(grp1) eureka-editor-eureka-2.0.2/src/bsp.h000066400000000000000000000534271464327712600173000ustar00rootroot00000000000000//------------------------------------------------------------------------ // // AJ-BSP Copyright (C) 2000-2019 Andrew Apted, et al // Copyright (C) 1994-1998 Colin Reed // Copyright (C) 1997-1998 Lee Killough // // Originally based on the program 'BSP', version 2.3. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_BSP_H__ #define __EUREKA_BSP_H__ #include "lib_util.h" #include "m_strings.h" #include "sys_type.h" #include "Thing.h" #include #include struct ConfigData; class Instance; class Lump_c; struct Sector; enum class Side; struct Document; class Wad_file; struct LoadingData; // Node Build Information Structure // // Memory note: when changing the string values here (and in // nodebuildcomms_t) they should be freed using StringFree() and // allocated with StringDup(). The application has the final // responsibility to free the strings in here. // #define DEFAULT_FACTOR 11 struct nodebuildinfo_t { int factor = DEFAULT_FACTOR; bool gl_nodes = true; // when these two are false, they create an empty lump bool do_blockmap = true; bool do_reject = true; bool fast = false; bool warnings = false; bool force_v5 = false; bool force_xnod = false; bool force_compress = false; // the GUI can set this to tell the node builder to stop bool cancelled = false; // from here on, various bits of internal state int total_failed_maps = 0; int total_warnings = 0; }; enum build_result_e { // everything went peachy keen BUILD_OK = 0, // building was cancelled BUILD_Cancelled, // the WAD file was corrupt / empty / bad filename BUILD_BadFile, // when saving the map, one or more lumps overflowed BUILD_LumpOverflow }; build_result_e AJBSP_BuildLevel(nodebuildinfo_t *info, int lev_idx, Instance &inst, const Document &doc, const LoadingData& loading, Wad_file &wad); //====================================================================== // // INTERNAL STUFF FROM HERE ON // //====================================================================== namespace ajbsp { /* ----- basic types --------------------------- */ typedef double angle_g; // degrees, 0 is E, 90 is N // prefer not to split #define MLF_IS_PRECIOUS 0x40000000 // this is flag set when a linedef directly overlaps an earlier // one (a rarely-used trick to create higher mid-masked textures). // No segs should be created for these overlapping linedefs. #define MLF_IS_OVERLAP 0x20000000 //------------------------------------------------------------------------ // UTILITY : general purpose functions //------------------------------------------------------------------------ void PrintDetail(const char *fmt, ...); // allocate and clear some memory. guaranteed not to fail. void *UtilCalloc(int size); // re-allocate some memory. guaranteed not to fail. void *UtilRealloc(void *old, int size); // free some memory or a string. void UtilFree(void *data); // return an allocated string for the current data and time, // or NULL if an error occurred. SString UtilTimeString(void); // compute angle of line from (0,0) to (dx,dy) angle_g UtilComputeAngle(double dx, double dy); // checksum functions void Adler32_Begin(uint32_t *crc); void Adler32_AddBlock(uint32_t *crc, const uint8_t *data, int length); void Adler32_Finish(uint32_t *crc); //------------------------------------------------------------------------ // BLOCKMAP : Generate the blockmap //------------------------------------------------------------------------ // utility routines... void GetBlockmapBounds(int *x, int *y, int *w, int *h); int CheckLinedefInsideBox(int xmin, int ymin, int xmax, int ymax, int x1, int y1, int x2, int y2); //------------------------------------------------------------------------ // LEVEL : Level structures & read/write functions. //------------------------------------------------------------------------ struct node_t; class quadtree_c; // a wall-tip is where a wall meets a vertex struct walltip_t { // link in list. List is kept in ANTI-clockwise order. walltip_t *next; walltip_t *prev; // angle that line makes at vertex (degrees). angle_g angle; // whether each side of wall is OPEN or CLOSED. // left is the side of increasing angles, whereas // right is the side of decreasing angles. bool open_left; bool open_right; }; struct vertex_t { // coordinates double x, y; // vertex index. Always valid after loading and pruning of unused // vertices has occurred. int index; // vertex is newly created (from a seg split) bool is_new; // usually NULL, unless this vertex occupies the same location as a // previous vertex. when there are multiple vertices at one spot, // the second and third (etc) all refer to the first. struct vertex_t *overlap; // list of wall-tips walltip_t *tip_set; }; struct seg_t { // link for list struct seg_t *next; vertex_t *start; // from this vertex... vertex_t *end; // ... to this vertex // linedef that this seg goes along, or -1 if miniseg int linedef; // 0 for right, 1 for left int side; // seg on other side, or NULL if one-sided. This relationship is // always one-to-one -- if one of the segs is split, the partner seg // must also be split. struct seg_t *partner; // seg index. Only valid once the seg has been added to a // subsector. A negative value means it is invalid -- there // shouldn't be any of these once the BSP tree has been built. int index; // when 1, this seg has become zero length (integer rounding of the // start and end vertices produces the same location). It should be // ignored when writing the SEGS or V1 GL_SEGS lumps. [Note: there // won't be any of these when writing the V2 GL_SEGS lump]. bool is_degenerate; // the quad-tree node that contains this seg, or NULL if the seg // is now in a subsector. quadtree_c *quad; // precomputed data for faster calculations double psx, psy; double pex, pey; double pdx, pdy; double p_length; double p_para; double p_perp; // linedef that this seg initially comes from. For "real" segs, // this is just the same as the 'linedef' field above. For // "minisegs", this is the linedef of the partition line. int source_line; // this only used by ClockwiseOrder() angle_g cmp_angle; public: // compute the seg private info (psx/y, pex/y, pdx/y, etc). void Recompute(); // returns SIDE_LEFT, SIDE_RIGHT or 0 for being "on" the line. Side PointOnLineSide(double x, double y) const; // compute the parallel and perpendicular distances from a partition // line to a point. // inline double ParallelDist(double x, double y) const { return (x * pdx + y * pdy + p_para) / p_length; } inline double PerpDist(double x, double y) const { return (x * pdy - y * pdx + p_perp) / p_length; } }; // a seg with this index is removed by SortSegs(). // it must be a very high value. #define SEG_IS_GARBAGE (1 << 29) class LevelData; struct subsec_t { // list of segs seg_t *seg_list; // count of segs int seg_count; // subsector index. Always valid, set when the subsector is // initially created. int index; // approximate middle point double mid_x; double mid_y; public: void DetermineMiddle(); void ClockwiseOrder(const Document &doc); void RenumberSegs(); void RoundOff(LevelData &lev_data); void Normalise(); void SanityCheckClosed(); void SanityCheckHasRealSeg(); }; struct bbox_t { int minx, miny; int maxx, maxy; }; struct child_t { // child node or subsector (one must be NULL) node_t *node; subsec_t *subsec; // child bounding box bbox_t bounds; }; struct node_t { // these coordinates are high precision to support UDMF. // in non-UDMF maps, they will actually be integral since a // partition line *always* comes from a normal linedef. double x, y; // starting point double dx, dy; // offset to ending point // right & left children child_t r; child_t l; // node index. Only valid once the NODES or GL_NODES lump has been // created. int index; public: void SetPartition(LevelData &lev_data, const seg_t *part); }; class quadtree_c { public: // coordinates on map for this block, from lower-left corner to // upper-right corner. Fully inclusive, i.e (x,y) is inside this // block when x1 < x < x2 and y1 < y < y2. int x1, y1; int x2, y2; // sub-trees. NULL for leaf nodes. // [0] has the lower coordinates, and [1] has the higher coordinates. // Division of a square always occurs horizontally (e.g. 512x512 -> 256x512). quadtree_c *subs[2]; // count of real/mini segs contained in this node AND ALL CHILDREN. int real_num; int mini_num; // list of segs contained in this node itself. seg_t *list; public: quadtree_c(int _x1, int _y1, int _x2, int _y2); ~quadtree_c(); void AddSeg(seg_t *seg); void AddList(seg_t *list); inline bool Empty() const { return (real_num + mini_num) == 0; } void ConvertToList(seg_t **list); // check relationship between this box and the partition line. // returns SIDE_LEFT or SIDE_RIGHT if box is definitively on a // particular side, or 0 if the line intersects/touches the box. // Side OnLineSide(const seg_t *part) const; }; /* ----- Level data arrays ----------------------- */ class ZLibContext; struct intersection_t; struct eval_info_t; class LevelData { public: typedef std::function ReportFunc; LevelData(MapFormat format, Wad_file &wad, const Document &doc, const ConfigData &config, const ReportFunc &reportLog) : format(format), wad(wad), doc(doc), config(config), reportLog(reportLog) { } LevelData(const LevelData& other) = delete; LevelData& operator = (const LevelData& other) = delete; MapFormat GetFormat() const { return format; } const Document& GetDoc() const { return doc; } // return a new end vertex to compensate for a seg that would end up // being zero-length (after integer rounding). Doesn't compute the // wall-tip info (thus this routine should only be used _after_ node // building). // vertex_t *NewVertexDegenerate(vertex_t *start, vertex_t *end); // MAIN STUFF build_result_e BuildLevel(nodebuildinfo_t *info, int lev_idx); void Warning(EUR_FORMAT_STRING(const char *fmt), ...) EUR_PRINTF(2, 3); private: struct Block { void CreateMap(const Document &doc); void CompressMap(); void InitMap(const Document &doc); void FreeMap(); int block_x = 0; int block_y = 0; int block_w = 0; int block_h = 0; int block_count = 0; uint16_t ** block_lines = nullptr; uint16_t *block_ptrs = nullptr; uint16_t *block_dups = nullptr; int compression = 0; int overflowed = 0; private: void Add(int blk_num, int line_index); void AddLine(int line_index, const Document &doc); int Compare(const void *p1, const void *p2) const; }; struct Reject { void Init(const Document &doc); void Free(); void GroupSectors(const Document &doc); void ProcessSectors(const Document &doc); uint8_t *rej_matrix = nullptr; int rej_total_size = 0; // in bytes std::vector rej_sector_groups; }; /* ----- create blockmap ------------------------------------ */ void WriteBlockmap() const; void PutBlockmap(); // REJECT : Generate the reject table void Reject_WriteLump() const; void PutReject(); // allocation routines vertex_t *NewVertex(); seg_t *NewSeg(); subsec_t *NewSubsec(); node_t *NewNode(); walltip_t *NewWallTip(); /* ----- free routines ---------------------------- */ void FreeVertices(); void FreeSegs(); void FreeSubsecs(); void FreeNodes(); void FreeWallTips(); /* ----- reading routines ------------------------------ */ void GetVertices(); /* ----- writing routines ------------------------------ */ void MarkOverflow(int flags); void PutVertices(const char *name, int do_gl); void PutGLVertices(int do_v5) const; inline uint32_t VertexIndex_XNOD(const vertex_t *v) const noexcept { if (v->is_new) return (uint32_t) (num_old_vert + v->index); return (uint32_t) v->index; } void PutSegs(); void PutGLSegs() const; void PutGLSegs_V5() const; void PutSubsecs(const char *name, int do_gl); void PutGLSubsecs_V5() const; void PutNodes(const char *name, int do_v5, node_t *root); void PutOneNode(node_t *node, Lump_c *lump); void PutOneNode_V5(node_t *node, Lump_c *lump); void CheckLimits(bool& force_v5, bool& force_xnod); void SortSegs(); /* ----- ZDoom format writing --------------------------- */ void putZItems(std::vector& lumpData, node_t* root_node, bool do_xgl3); void PutZVertices(ZLibContext &zcontext) const noexcept(false); void PutZSubsecs(ZLibContext &zcontext) const noexcept(false); void PutZSegs(ZLibContext &zcontext) const noexcept(false); void PutXGL3Segs(ZLibContext &zcontext) const noexcept(false); void PutOneZNode(ZLibContext &zcontext, node_t *node, bool do_xgl3) noexcept(false); void PutZNodes(ZLibContext &zcontext, node_t *root, bool do_xgl3) noexcept(false); void SaveZDFormat(node_t *root_node); void SaveXGL3Format(node_t *root_node); /* ----- whole-level routines --------------------------- */ void LoadLevel(); void FreeLevel(); uint32_t CalcGLChecksum() const; inline SString CalcOptionsString() const { return SString::printf("--cost %d%s", cur_info->factor, cur_info->fast ? " --fast" : ""); } void UpdateGLMarker(Lump_c *marker) const; void AddMissingLump(const char *name, const char *after); build_result_e SaveLevel(node_t *root_node); build_result_e SaveUDMF(node_t *root_node); /* ---------------------------------------------------------------- */ Lump_c * FindLevelLump(const char *name) const noexcept; Lump_c & CreateLevelLump(const char *name) const; Lump_c & CreateGLMarker() const; // NODES seg_t * SplitSeg(seg_t *old_seg, double x, double y); void DivideOneSeg(seg_t *seg, seg_t *part, seg_t **left_list, seg_t **right_list, intersection_t ** cut_list); void SeparateSegs(quadtree_c *tree, seg_t *part, seg_t **left_list, seg_t **right_list, intersection_t ** cut_list); void AddMinisegs(intersection_t *cut_list, seg_t *part, seg_t **left_list, seg_t **right_list); // takes the seg list and determines if it is convex. When it is, the // segs are converted to a subsector, and '*S' is the new subsector // (and '*N' is set to NULL). Otherwise the seg list is divided into // two halves, a node is created by calling this routine recursively, // and '*N' is the new node (and '*S' is set to NULL). Normally // returns BUILD_OK, or BUILD_Cancelled if user stopped it. // build_result_e BuildNodes(seg_t *list, bbox_t *bounds /* output */, node_t ** N, subsec_t ** S, int depth); seg_t *CreateOneSeg(int line, vertex_t *start, vertex_t *end, int sidedef, int what_side /* 0 or 1 */); // scan all the linedef of the level and convert each sidedef into a // seg (or seg pair). Returns the list of segs. // seg_t *CreateSegs(); subsec_t *CreateSubsector(quadtree_c *tree); // put all the segs in each subsector into clockwise order, and renumber // the seg indices. // // [ This cannot be done DURING BuildNodes() since splitting a seg with // a partner will insert another seg into that partner's list, usually // in the wrong place order-wise. ] // void ClockwiseBspTree(); // traverse the BSP tree and do whatever is necessary to convert the // node information from GL standard to normal standard (for example, // removing minisegs). // void NormaliseBspTree() const; void RoundOffVertices(); // traverse the BSP tree, doing whatever is necessary to round // vertices to integer coordinates (for example, removing segs whose // rounded coordinates degenerate to the same point). // void RoundOffBspTree(); void MarkPolyobjPoint(double x, double y); // detection routines void DetectOverlappingVertices() const; void DetectPolyobjSectors(); int EvalPartitionWorker(quadtree_c *tree, seg_t *part, int best_cost, eval_info_t *info); int EvalPartition(quadtree_c *tree, seg_t *part, int best_cost); seg_t *FindFastSeg(quadtree_c *tree); bool PickNodeWorker(quadtree_c *part_list, quadtree_c *tree, seg_t ** best, int *best_cost); // scan all the segs in the list, and choose the best seg to use as a // partition line, returning it. If no seg can be used, returns NULL. // The 'depth' parameter is the current depth in the tree, used for // computing the current progress. // seg_t *PickNode(quadtree_c *tree, int depth); /* ----- vertex routines ------------------------------- */ void VertexAddWallTip(vertex_t *vert, double dx, double dy, int open_left, int open_right); // computes the wall tips for all of the vertices void CalculateWallTips(); // return a new vertex (with correct wall-tip info) for the split that // happens along the given seg at the given location. // vertex_t *NewVertexFromSplitSeg(seg_t *seg, double x, double y); void Failure(EUR_FORMAT_STRING(const char *fmt), ...) EUR_PRINTF(2, 3); void PrintMsg(EUR_FORMAT_STRING(const char *format), ...) const EUR_PRINTF(2, 3); Block block = {}; Reject rej = {}; SString current_name; int current_idx = 0; int current_start = 0; int overflows = 0; int num_old_vert = 0; int num_new_vert = 0; int num_real_lines = 0; int node_cur_index = 0; std::vector vertices; std::vector subsecs; std::vector segs; std::vector nodes; std::vector walltips; // internal storage of node building parameters nodebuildinfo_t * cur_info = NULL; const MapFormat format; Wad_file& wad; const Document& doc; const ConfigData &config; const ReportFunc reportLog; }; /* ----- function prototypes ----------------------- */ /* limit flags, to show what went wrong */ #define LIMIT_VERTEXES 0x000001 #define LIMIT_SECTORS 0x000002 #define LIMIT_SIDEDEFS 0x000004 #define LIMIT_LINEDEFS 0x000008 #define LIMIT_SEGS 0x000010 #define LIMIT_SSECTORS 0x000020 #define LIMIT_NODES 0x000040 #define LIMIT_GL_VERT 0x000100 #define LIMIT_GL_SEGS 0x000200 #define LIMIT_GL_SSECT 0x000400 #define LIMIT_GL_NODES 0x000800 //------------------------------------------------------------------------ // ANALYZE : Analyzing level structures //------------------------------------------------------------------------ // detection routines void DetectOverlappingLines(const Document &doc); // check whether a line with the given delta coordinates from this // vertex is open or closed. If there exists a walltip at same // angle, it is closed, likewise if line is in void space. // bool VertexCheckOpen(vertex_t *vert, double dx, double dy); //------------------------------------------------------------------------ // SEG : Choose the best Seg to use for a node line. //------------------------------------------------------------------------ #define IFFY_LEN 4.0 inline void ListAddSeg(seg_t **list_ptr, seg_t *seg) { seg->next = *list_ptr; *list_ptr = seg; } // an "intersection" remembers the vertex that touches a BSP divider // line (especially a new vertex that is created at a seg split). struct intersection_t { // link in list. The intersection list is kept sorted by // along_dist, in ascending order. intersection_t *next; intersection_t *prev; // vertex in question vertex_t *vertex; // how far along the partition line the vertex is. Zero is at the // partition seg's start point, positive values move in the same // direction as the partition's direction, and negative values move // in the opposite direction. double along_dist; // true if this intersection was on a self-referencing linedef bool self_ref; // status of each side of the vertex (along the partition), // true if OPEN and false if CLOSED. bool open_before; bool open_after; }; /* -------- functions ---------------------------- */ // compute the boundary of the list of segs void FindLimits2(seg_t *list, bbox_t *bbox); // take the given seg 'cur', compare it with the partition line, and // determine it's fate: moving it into either the left or right lists // (perhaps both, when splitting it in two). Handles partners as // well. Updates the intersection list if the seg lies on or crosses // the partition line. // void DivideOneSeg(seg_t *cur, seg_t *part, quadtree_c *left_quad, quadtree_c *right_quad, intersection_t ** cut_list); // remove all the segs from the list, partitioning them into the left // or right lists based on the given partition line. Adds any // intersections into the intersection list as it goes. // void SeparateSegs(quadtree_c *tree, seg_t *part, quadtree_c *left_quad, quadtree_c *right_quad, intersection_t ** cut_list); // analyse the intersection list, and add any needed minisegs to the // given seg lists (one miniseg on each side). All the intersection // structures will be freed back into a quick-alloc list. // void AddMinisegs(seg_t *part, quadtree_c *left_quad, quadtree_c *right_list, intersection_t *cut_list); // free the quick allocation cut list void FreeQuickAllocCuts(void); //------------------------------------------------------------------------ // NODE : Recursively create nodes and return the pointers. //------------------------------------------------------------------------ quadtree_c *TreeFromSegList(seg_t *list); // compute the height of the bsp tree, starting at 'node'. int ComputeBspHeight(node_t *node); // free all the superblocks on the quick-alloc list void FreeQuickAllocSupers(void); } // namespace ajbsp #endif /* __EUREKA_BSP_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/bsp_level.cc000066400000000000000000001353671464327712600206310ustar00rootroot00000000000000//------------------------------------------------------------------------ // // AJ-BSP Copyright (C) 2000-2019 Andrew Apted, et al // Copyright (C) 1994-1998 Colin Reed // Copyright (C) 1997-1998 Lee Killough // // Originally based on the program 'BSP', version 2.3. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "bsp.h" #include "Instance.h" #include "w_rawdef.h" #include namespace ajbsp { #define DEBUG_BLOCKMAP 0 #define DEBUG_REJECT 0 #define DEBUG_LOAD 0 #define DEBUG_BSP 0 #define BLOCK_LIMIT 16000 #define DUMMY_DUP 0xFFFF int CheckLinedefInsideBox(int xmin, int ymin, int xmax, int ymax, int x1, int y1, int x2, int y2) { int count = 2; int tmp; for (;;) { if (y1 > ymax) { if (y2 > ymax) return false; x1 = x1 + (int) ((x2-x1) * (double)(ymax-y1) / (double)(y2-y1)); y1 = ymax; count = 2; continue; } if (y1 < ymin) { if (y2 < ymin) return false; x1 = x1 + (int) ((x2-x1) * (double)(ymin-y1) / (double)(y2-y1)); y1 = ymin; count = 2; continue; } if (x1 > xmax) { if (x2 > xmax) return false; y1 = y1 + (int) ((y2-y1) * (double)(xmax-x1) / (double)(x2-x1)); x1 = xmax; count = 2; continue; } if (x1 < xmin) { if (x2 < xmin) return false; y1 = y1 + (int) ((y2-y1) * (double)(xmin-x1) / (double)(x2-x1)); x1 = xmin; count = 2; continue; } count--; if (count == 0) break; // swap end points tmp=x1; x1=x2; x2=tmp; tmp=y1; y1=y2; y2=tmp; } // linedef touches block return true; } /* ----- create blockmap ------------------------------------ */ #define BK_NUM 0 #define BK_MAX 1 #define BK_XOR 2 #define BK_FIRST 3 #define BK_QUANTUM 32 void LevelData::Block::Add(int blk_num, int line_index) { uint16_t *cur = block_lines[blk_num]; # if DEBUG_BLOCKMAP gLog.debugPrintf("Block %d has line %d\n", blk_num, line_index); # endif if (blk_num < 0 || blk_num >= block_count) BugError("BlockAdd: bad block number %d\n", blk_num); if (! cur) { // create empty block block_lines[blk_num] = cur = (uint16_t *)UtilCalloc(BK_QUANTUM * sizeof(uint16_t)); cur[BK_NUM] = 0; cur[BK_MAX] = BK_QUANTUM; cur[BK_XOR] = 0x1234; } if (BK_FIRST + cur[BK_NUM] == cur[BK_MAX]) { // no more room, so allocate some more... cur[BK_MAX] += BK_QUANTUM; block_lines[blk_num] = cur = (uint16_t *)UtilRealloc(cur, cur[BK_MAX] * sizeof(uint16_t)); } // compute new checksum cur[BK_XOR] = static_cast(((cur[BK_XOR] << 4) | (cur[BK_XOR] >> 12)) ^ line_index); cur[BK_FIRST + cur[BK_NUM]] = LE_U16(line_index); cur[BK_NUM]++; } void LevelData::Block::AddLine(int line_index, const Document &doc) { const auto L = doc.linedefs[line_index]; int x1 = (int) doc.getStart(*L).x(); int y1 = (int) doc.getStart(*L).y(); int x2 = (int) doc.getEnd(*L).x(); int y2 = (int) doc.getEnd(*L).y(); int bx1 = (std::min(x1,x2) - block_x) / 128; int by1 = (std::min(y1,y2) - block_y) / 128; int bx2 = (std::max(x1,x2) - block_x) / 128; int by2 = (std::max(y1,y2) - block_y) / 128; int bx, by; # if DEBUG_BLOCKMAP gLog.debugPrintf("BlockAddLine: %d (%d,%d) -> (%d,%d)\n", line_index, x1, y1, x2, y2); # endif // handle truncated blockmaps if (bx1 < 0) bx1 = 0; if (by1 < 0) by1 = 0; if (bx2 >= block_w) bx2 = block_w - 1; if (by2 >= block_h) by2 = block_h - 1; if (bx2 < bx1 || by2 < by1) return; // handle simple case #1: completely horizontal if (by1 == by2) { for (bx=bx1 ; bx <= bx2 ; bx++) { int blk_num = by1 * block_w + bx; Add(blk_num, line_index); } return; } // handle simple case #2: completely vertical if (bx1 == bx2) { for (by=by1 ; by <= by2 ; by++) { int blk_num = by * block_w + bx1; Add(blk_num, line_index); } return; } // handle the rest (diagonals) for (by=by1 ; by <= by2 ; by++) for (bx=bx1 ; bx <= bx2 ; bx++) { int blk_num = by * block_w + bx; int minx = block_x + bx * 128; int miny = block_y + by * 128; int maxx = minx + 127; int maxy = miny + 127; if (CheckLinedefInsideBox(minx, miny, maxx, maxy, x1, y1, x2, y2)) { Add(blk_num, line_index); } } } void LevelData::Block::CreateMap(const Document &doc) { block_lines = (uint16_t **) UtilCalloc(block_count * sizeof(uint16_t *)); for (int i=0 ; i < doc.numLinedefs() ; i++) { // ignore zero-length lines if (doc.isZeroLength(*doc.linedefs[i])) continue; AddLine(i, doc); } } int LevelData::Block::Compare(const void *p1, const void *p2) const { int blk_num1 = ((const uint16_t *) p1)[0]; int blk_num2 = ((const uint16_t *) p2)[0]; const uint16_t *A = block_lines[blk_num1]; const uint16_t *B = block_lines[blk_num2]; if (A == B) return 0; if (A == NULL) return -1; if (B == NULL) return +1; if (A[BK_NUM] != B[BK_NUM]) { return A[BK_NUM] - B[BK_NUM]; } if (A[BK_XOR] != B[BK_XOR]) { return A[BK_XOR] - B[BK_XOR]; } return memcmp(A+BK_FIRST, B+BK_FIRST, A[BK_NUM] * sizeof(uint16_t)); } void LevelData::Block::CompressMap() { int i; int cur_offset; int dup_count=0; (void)dup_count; int orig_size, new_size; block_ptrs = (uint16_t *)UtilCalloc(block_count * sizeof(uint16_t)); block_dups = (uint16_t *)UtilCalloc(block_count * sizeof(uint16_t)); // sort duplicate-detecting array. After the sort, all duplicates // will be next to each other. The duplicate array gives the order // of the blocklists in the BLOCKMAP lump. for (i=0 ; i < block_count ; i++) block_dups[i] = static_cast(i); std::sort(block_dups, block_dups + block_count, [this](uint16_t a, uint16_t b) { return Compare(&a, &b) < 0; }); // scan duplicate array and build up offset array cur_offset = 4 + block_count + 2; orig_size = 4 + block_count; new_size = cur_offset; for (i=0 ; i < block_count ; i++) { int blk_num = block_dups[i]; int count; // empty block ? if (block_lines[blk_num] == NULL) { block_ptrs[blk_num] = static_cast(4 + this->block_count); block_dups[i] = DUMMY_DUP; orig_size += 2; continue; } count = 2 + block_lines[blk_num][BK_NUM]; // duplicate ? Only the very last one of a sequence of duplicates // will update the current offset value. if (i+1 < this->block_count && Compare(block_dups + i, block_dups + i+1) == 0) { block_ptrs[blk_num] = static_cast(cur_offset); block_dups[i] = DUMMY_DUP; // free the memory of the duplicated block UtilFree(block_lines[blk_num]); block_lines[blk_num] = NULL; dup_count++; orig_size += count; continue; } // OK, this block is either the last of a series of duplicates, or // just a singleton. block_ptrs[blk_num] = static_cast(cur_offset); cur_offset += count; orig_size += count; new_size += count; } if (cur_offset > 65535) { overflowed = true; return; } # if DEBUG_BLOCKMAP gLog.debugPrintf("Blockmap: Last ptr = %d duplicates = %d\n", cur_offset, dup_count); # endif compression = (orig_size - new_size) * 100 / orig_size; // there's a tiny chance of new_size > orig_size if (compression < 0) compression = 0; } void LevelData::WriteBlockmap() const { int i; Lump_c &lump = CreateLevelLump("BLOCKMAP"); uint16_t null_block[2] = { 0x0000, 0xFFFF }; uint16_t m_zero = 0x0000; uint16_t m_neg1 = 0xFFFF; // fill in header raw_blockmap_header_t header; header.x_origin = LE_U16(block.block_x); header.y_origin = LE_U16(block.block_y); header.x_blocks = LE_U16(block.block_w); header.y_blocks = LE_U16(block.block_h); lump.Write(&header, sizeof(header)); // handle pointers for (i=0 ; i < block.block_count ; i++) { uint16_t ptr = LE_U16(block.block_ptrs[i]); if (ptr == 0) BugError("WriteBlockmap: offset %d not set.\n", i); lump.Write(&ptr, sizeof(uint16_t)); } // add the null block which *all* empty blocks will use lump.Write(null_block, sizeof(null_block)); // handle each block list for (i=0 ; i < block.block_count ; i++) { int blk_num = block.block_dups[i]; // ignore duplicate or empty blocks if (blk_num == DUMMY_DUP) continue; uint16_t *blk = block.block_lines[blk_num]; SYS_ASSERT(blk); lump.Write(&m_zero, sizeof(uint16_t)); lump.Write(blk + BK_FIRST, blk[BK_NUM] * sizeof(uint16_t)); lump.Write(&m_neg1, sizeof(uint16_t)); } } void LevelData::Block::FreeMap() { for (int i=0 ; i < block_count ; i++) { if (block_lines[i]) UtilFree(block_lines[i]); } UtilFree(block_lines); UtilFree(block_ptrs); UtilFree(block_dups); } static void FindMapLimits(bbox_t *bbox, const Document &doc) { bbox->minx = bbox->miny = SHRT_MAX; bbox->maxx = bbox->maxy = SHRT_MIN; for (int i=0 ; i < doc.numLinedefs() ; i++) { const auto L = doc.linedefs[i]; if (!doc.isZeroLength(*L)) { double x1 = doc.getStart(*L).x(); double y1 = doc.getStart(*L).y(); double x2 = doc.getEnd(*L).x(); double y2 = doc.getEnd(*L).y(); int lx = (int)floor(std::min(x1, x2)); int ly = (int)floor(std::min(y1, y2)); int hx = (int)ceil(std::max(x1, x2)); int hy = (int)ceil(std::max(y1, y2)); if (lx < bbox->minx) bbox->minx = lx; if (ly < bbox->miny) bbox->miny = ly; if (hx > bbox->maxx) bbox->maxx = hx; if (hy > bbox->maxy) bbox->maxy = hy; } } # if DEBUG_BLOCKMAP gLog.debugPrintf("Blockmap lines centered at (%d,%d)\n", block_mid_x, block_mid_y); # endif } // // compute blockmap origin & size (the block_x/y/w/h variables) // based on the set of loaded linedefs. // void LevelData::Block::InitMap(const Document &doc) { bbox_t map_bbox; // find limits of linedefs, and store as map limits FindMapLimits(&map_bbox, doc); PrintDetail("Map goes from (%d,%d) to (%d,%d)\n", map_bbox.minx, map_bbox.miny, map_bbox.maxx, map_bbox.maxy); block_x = map_bbox.minx - (map_bbox.minx & 0x7); block_y = map_bbox.miny - (map_bbox.miny & 0x7); block_w = ((map_bbox.maxx - block_x) / 128) + 1; block_h = ((map_bbox.maxy - block_y) / 128) + 1; block_count = block_w * block_h; } // // build the blockmap and write the data into the BLOCKMAP lump // void LevelData::PutBlockmap() { if (! cur_info->do_blockmap || doc.numLinedefs() == 0) { // just create an empty blockmap lump CreateLevelLump("BLOCKMAP"); return; } block.overflowed = false; // initial phase: create internal blockmap containing the index of // all lines in each block. block.CreateMap(doc); // -AJA- second phase: compress the blockmap. We do this by sorting // the blocks, which is a typical way to detect duplicates in // a large list. This also detects BLOCKMAP overflow. block.CompressMap(); // final phase: write it out in the correct format if (block.overflowed) { // leave an empty blockmap lump CreateLevelLump("BLOCKMAP"); Warning("Blockmap overflowed (lump will be empty)\n"); } else { WriteBlockmap(); PrintDetail("Completed blockmap, size %dx%d (compression: %d%%)\n", block.block_w, block.block_h, block.compression); } block.FreeMap(); } //------------------------------------------------------------------------ // REJECT : Generate the reject table //------------------------------------------------------------------------ // // Allocate the matrix, init sectors into individual groups. // void LevelData::Reject::Init(const Document &doc) { rej_total_size = (doc.numSectors() * doc.numSectors() + 7) / 8; rej_matrix = new uint8_t[rej_total_size]; memset(rej_matrix, 0, rej_total_size); rej_sector_groups.resize(doc.numSectors()); for (int i=0 ; i < doc.numSectors() ; i++) { rej_sector_groups[i] = i; } } void LevelData::Reject::Free() { delete[] rej_matrix; rej_matrix = NULL; rej_sector_groups.clear(); } // // Algorithm: Initially all sectors are in individual groups. // Now we scan the linedef list. For each two-sectored line, // merge the two sector groups into one. That's it! // void LevelData::Reject::GroupSectors(const Document &doc) { for(const auto &L : doc.linedefs) { if (L->right < 0 || L->left < 0) continue; int sec1 = doc.getRight(*L)->sector; int sec2 = doc.getLeft(*L) ->sector; if (sec1 < 0 || sec2 < 0 || sec1 == sec2) continue; // already in the same group ? int group1 = rej_sector_groups[sec1]; int group2 = rej_sector_groups[sec2]; if (group1 == group2) continue; // prefer the group numbers to become lower if (group1 > group2) std::swap(group1, group2); // merge the groups for (int s = 0 ; s < doc.numSectors() ; s++) if (rej_sector_groups[s] == group2) rej_sector_groups[s] = group1; } } #if DEBUG_REJECT static void Reject_DebugGroups() { // Note: this routine is destructive to the group numbers for (int i=0 ; i < doc.numSectors(); i++) { int group = rej_sector_groups[i]; int count = 0; if (group < 0) continue; for (int k = i ; k < doc.numSectors() ; k++) { if (rej_sector_groups[k] == group) { rej_sector_groups[k] = -1; count++; } } gLog.debugPrintf("Group %4d : Sectors %d\n", group, count); } } #endif void LevelData::Reject::ProcessSectors(const Document &doc) { for (int view=0 ; view < doc.numSectors() ; view++) { for (int target=0 ; target < view ; target++) { if (rej_sector_groups[view] == rej_sector_groups[target]) continue; int p1 = view * doc.numSectors() + target; int p2 = target * doc.numSectors() + view; // must do both directions at same time rej_matrix[p1 >> 3] |= (1 << (p1 & 7)); rej_matrix[p2 >> 3] |= (1 << (p2 & 7)); } } } void LevelData::Reject_WriteLump() const { Lump_c &lump = CreateLevelLump("REJECT"); lump.Write(rej.rej_matrix, rej.rej_total_size); } // // build the reject table and write it into the REJECT lump // // For now we only do very basic reject processing, limited to // determining all isolated groups of sectors (islands that are // surrounded by void space). // void LevelData::PutReject() { if (! cur_info->do_reject || doc.numSectors() == 0) { // just create an empty reject lump CreateLevelLump("REJECT"); return; } rej.Init(doc); rej.GroupSectors(doc); rej.ProcessSectors(doc); # if DEBUG_REJECT Reject_DebugGroups(); # endif Reject_WriteLump(); rej.Free(); PrintDetail("Added simple reject lump\n"); } //------------------------------------------------------------------------ // LEVEL : Level structure read/write functions. //------------------------------------------------------------------------ // Note: ZDoom format support based on code (C) 2002,2003 Randy Heit #define ALLOC_BLKNUM 1024 /* ----- allocation routines ---------------------------- */ vertex_t *LevelData::NewVertex() { vertex_t *V = (vertex_t *) UtilCalloc(sizeof(vertex_t)); vertices.push_back(V); return V; } seg_t *LevelData::NewSeg() { seg_t *S = (seg_t *) UtilCalloc(sizeof(seg_t)); segs.push_back(S); return S; } subsec_t *LevelData::NewSubsec() { subsec_t *S = (subsec_t *) UtilCalloc(sizeof(subsec_t)); subsecs.push_back(S); return S; } node_t *LevelData::NewNode() { node_t *N = (node_t *) UtilCalloc(sizeof(node_t)); nodes.push_back(N); return N; } walltip_t *LevelData::NewWallTip() { walltip_t *WT = (walltip_t *) UtilCalloc(sizeof(walltip_t)); walltips.push_back(WT); return WT; } /* ----- free routines ---------------------------- */ void LevelData::FreeVertices() { for (unsigned int i = 0 ; i < vertices.size() ; i++) UtilFree((void *) vertices[i]); vertices.clear(); } void LevelData::FreeSegs() { for (unsigned int i = 0 ; i < segs.size() ; i++) UtilFree((void *) segs[i]); segs.clear(); } void LevelData::FreeSubsecs() { for (unsigned int i = 0 ; i < subsecs.size() ; i++) UtilFree((void *) subsecs[i]); subsecs.clear(); } void LevelData::FreeNodes() { for (unsigned int i = 0 ; i < nodes.size() ; i++) UtilFree((void *) nodes[i]); nodes.clear(); } void LevelData::FreeWallTips() { for (unsigned int i = 0 ; i < walltips.size() ; i++) UtilFree((void *) walltips[i]); walltips.clear(); } /* ----- reading routines ------------------------------ */ void LevelData::GetVertices() { for (int i = 0 ; i < doc.numVertices() ; i++) { vertex_t *vert = NewVertex(); vert->x = doc.vertices[i]->x(); vert->y = doc.vertices[i]->y(); vert->index = i; } num_old_vert = (int)vertices.size(); } #if 0 static inline SideDef *SafeLookupSidedef(uint16_t num) { if (num == 0xFFFF) return NULL; if ((int)num >= doc.numSidedefs() && (int16_t)(num) < 0) return NULL; return SideDefs[num]; } #endif static inline int VanillaSegDist(const seg_t *seg, const Document &doc) { const auto L = doc.linedefs[seg->linedef]; double lx = seg->side ? doc.getEnd(*L).x() : doc.getStart(*L).x(); double ly = seg->side ? doc.getEnd(*L).y() : doc.getStart(*L).y(); // use the "true" starting coord (as stored in the wad) double sx = round(seg->start->x); double sy = round(seg->start->y); return (int) floor(hypot(sx - lx, sy - ly) + 0.5); } static inline int VanillaSegAngle(const seg_t *seg) { // compute the "true" delta double dx = round(seg->end->x) - round(seg->start->x); double dy = round(seg->end->y) - round(seg->start->y); double angle = UtilComputeAngle(dx, dy); if (angle < 0) angle += 360.0; int result = (int) floor(angle * 65536.0 / 360.0 + 0.5); return (result & 0xFFFF); } /* ----- writing routines ------------------------------ */ static const uint8_t *lev_v2_magic = (uint8_t *) "gNd2"; static const uint8_t *lev_v5_magic = (uint8_t *) "gNd5"; void LevelData::MarkOverflow(int flags) { // flags are ignored overflows++; } void LevelData::PutVertices(const char *name, int do_gl) { int count, i; Lump_c &lump = CreateLevelLump(name); for (i=0, count=0 ; i < (int)vertices.size() ; i++) { raw_vertex_t raw; vertex_t *vert = vertices[i]; if ((do_gl ? 1 : 0) != (vert->is_new ? 1 : 0)) { continue; } raw.x = LE_S16(iround(vert->x)); raw.y = LE_S16(iround(vert->y)); lump.Write(&raw, sizeof(raw)); count++; } if (count != (do_gl ? num_new_vert : num_old_vert)) BugError("PutVertices miscounted (%d != %d)\n", count, do_gl ? num_new_vert : num_old_vert); if (! do_gl && count > 65534) { Failure("Number of vertices has overflowed.\n"); MarkOverflow(LIMIT_VERTEXES); } } void LevelData::PutGLVertices(int do_v5) const { int count, i; Lump_c &lump = CreateLevelLump("GL_VERT"); if (do_v5) lump.Write(lev_v5_magic, 4); else lump.Write(lev_v2_magic, 4); for (i=0, count=0 ; i < (int)vertices.size() ; i++) { raw_v2_vertex_t raw; vertex_t *vert = vertices[i]; if (! vert->is_new) continue; raw.x = LE_S32((int)(vert->x * 65536.0)); raw.y = LE_S32((int)(vert->y * 65536.0)); lump.Write(&raw, sizeof(raw)); count++; } if (count != num_new_vert) BugError("PutGLVertices miscounted (%d != %d)\n", count, num_new_vert); } static inline uint16_t VertexIndex16Bit(const vertex_t *v) { if (v->is_new) return (uint16_t) (v->index | 0x8000U); return (uint16_t) v->index; } static inline uint32_t VertexIndex_V5(const vertex_t *v) { if (v->is_new) return (uint32_t) (v->index | 0x80000000U); return (uint32_t) v->index; } void LevelData::PutSegs() { int i, count; Lump_c &lump = CreateLevelLump("SEGS"); for (i=0, count=0 ; i < (int)segs.size() ; i++) { raw_seg_t raw; seg_t *seg = segs[i]; raw.start = LE_U16(VertexIndex16Bit(seg->start)); raw.end = LE_U16(VertexIndex16Bit(seg->end)); raw.angle = LE_U16(VanillaSegAngle(seg)); raw.linedef = LE_U16(seg->linedef); raw.flip = LE_U16(seg->side); raw.dist = LE_U16(VanillaSegDist(seg, doc)); lump.Write(&raw, sizeof(raw)); count++; # if DEBUG_BSP gLog.debugPrintf("PUT SEG: %04X Vert %04X->%04X Line %04X %s " "Angle %04X (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", seg->index, LE_U16(raw.start), LE_U16(raw.end), LE_U16(raw.linedef), seg->side ? "L" : "R", LE_U16(raw.angle), seg->start->x, seg->start->y, seg->end->x, seg->end->y); # endif } if (count != (int)segs.size()) BugError("PutSegs miscounted (%d != %d)\n", count, (int)segs.size()); if (count > 65534) { Failure("Number of segs has overflowed.\n"); MarkOverflow(LIMIT_SEGS); } } void LevelData::PutGLSegs() const { int i, count; Lump_c &lump = CreateLevelLump("GL_SEGS"); for (i=0, count=0 ; i < (int)segs.size() ; i++) { raw_gl_seg_t raw; seg_t *seg = segs[i]; raw.start = LE_U16(VertexIndex16Bit(seg->start)); raw.end = LE_U16(VertexIndex16Bit(seg->end)); raw.side = LE_U16(seg->side); if (seg->linedef >= 0) raw.linedef = LE_U16(seg->linedef); else raw.linedef = LE_U16(0xFFFF); if (seg->partner) raw.partner = LE_U16(seg->partner->index); else raw.partner = LE_U16(0xFFFF); lump.Write(&raw, sizeof(raw)); count++; # if DEBUG_BSP gLog.debugPrintf("PUT GL SEG: %04X Line %04X %s Partner %04X " "(%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", seg->index, LE_U16(raw.linedef), seg->side ? "L" : "R", LE_U16(raw.partner), seg->start->x, seg->start->y, seg->end->x, seg->end->y); # endif } if (count != (int)segs.size()) BugError("PutGLSegs miscounted (%d != %d)\n", count, (int)segs.size()); if (count > 65534) BugError("PutGLSegs with %d (> 65534) segs\n", count); } void LevelData::PutGLSegs_V5() const { int i, count; Lump_c &lump = CreateLevelLump("GL_SEGS"); for (i=0, count=0 ; i < (int)segs.size() ; i++) { raw_v5_seg_t raw; seg_t *seg = segs[i]; raw.start = LE_U32(VertexIndex_V5(seg->start)); raw.end = LE_U32(VertexIndex_V5(seg->end)); raw.side = LE_U16(seg->side); if (seg->linedef >= 0) raw.linedef = LE_U16(seg->linedef); else raw.linedef = LE_U16(0xFFFF); if (seg->partner) raw.partner = LE_U32(seg->partner->index); else raw.partner = LE_U32(0xFFFFFFFF); lump.Write(&raw, sizeof(raw)); count++; # if DEBUG_BSP gLog.debugPrintf("PUT V3 SEG: %06X Line %04X %s Partner %06X " "(%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", seg->index, LE_U16(raw.linedef), seg->side ? "L" : "R", LE_U32(raw.partner), seg->start->x, seg->start->y, seg->end->x, seg->end->y); # endif } if (count != (int)segs.size()) BugError("PutGLSegs miscounted (%d != %d)\n", count, (int)segs.size()); } void LevelData::PutSubsecs(const char *name, int do_gl) { int i; Lump_c & lump = CreateLevelLump(name); for (i=0 ; i < (int)subsecs.size() ; i++) { raw_subsec_t raw; subsec_t *sub = subsecs[i]; raw.first = LE_U16(sub->seg_list->index); raw.num = LE_U16(sub->seg_count); lump.Write(&raw, sizeof(raw)); # if DEBUG_BSP gLog.debugPrintf("PUT SUBSEC %04X First %04X Num %04X\n", sub->index, LE_U16(raw.first), LE_U16(raw.num)); # endif } if ((int)segs.size() > 32767) { Failure("Number of %s has overflowed.\n", do_gl ? "GL subsectors" : "subsectors"); MarkOverflow(do_gl ? LIMIT_GL_SSECT : LIMIT_SSECTORS); } } void LevelData::PutGLSubsecs_V5() const { int i; Lump_c &lump = CreateLevelLump("GL_SSECT"); for (i=0 ; i < (int)subsecs.size() ; i++) { raw_v5_subsec_t raw; subsec_t *sub = subsecs[i]; raw.first = LE_U32(sub->seg_list->index); raw.num = LE_U32(sub->seg_count); lump.Write(&raw, sizeof(raw)); # if DEBUG_BSP gLog.debugPrintf("PUT V3 SUBSEC %06X First %06X Num %06X\n", sub->index, LE_U32(raw.first), LE_U32(raw.num)); # endif } } void LevelData::PutOneNode(node_t *node, Lump_c *lump) { raw_node_t raw; if (node->r.node) PutOneNode(node->r.node, lump); if (node->l.node) PutOneNode(node->l.node, lump); node->index = node_cur_index++; // Note that x/y/dx/dy are always integral in non-UDMF maps raw.x = LE_S16(iround(node->x)); raw.y = LE_S16(iround(node->y)); raw.dx = LE_S16(iround(node->dx)); raw.dy = LE_S16(iround(node->dy)); raw.b1.minx = LE_S16(node->r.bounds.minx); raw.b1.miny = LE_S16(node->r.bounds.miny); raw.b1.maxx = LE_S16(node->r.bounds.maxx); raw.b1.maxy = LE_S16(node->r.bounds.maxy); raw.b2.minx = LE_S16(node->l.bounds.minx); raw.b2.miny = LE_S16(node->l.bounds.miny); raw.b2.maxx = LE_S16(node->l.bounds.maxx); raw.b2.maxy = LE_S16(node->l.bounds.maxy); if (node->r.node) raw.right = LE_U16(node->r.node->index); else if (node->r.subsec) raw.right = LE_U16(node->r.subsec->index | 0x8000); else BugError("Bad right child in node %d\n", node->index); if (node->l.node) raw.left = LE_U16(node->l.node->index); else if (node->l.subsec) raw.left = LE_U16(node->l.subsec->index | 0x8000); else BugError("Bad left child in node %d\n", node->index); lump->Write(&raw, sizeof(raw)); # if DEBUG_BSP gLog.debugPrintf("PUT NODE %04X Left %04X Right %04X " "(%d,%d) -> (%d,%d)\n", node->index, LE_U16(raw.left), LE_U16(raw.right), node->x, node->y, node->x + node->dx, node->y + node->dy); # endif } void LevelData::PutOneNode_V5(node_t *node, Lump_c *lump) { raw_v5_node_t raw; if (node->r.node) PutOneNode_V5(node->r.node, lump); if (node->l.node) PutOneNode_V5(node->l.node, lump); node->index = node_cur_index++; raw.x = LE_S16(iround(node->x)); raw.y = LE_S16(iround(node->y)); raw.dx = LE_S16(iround(node->dx)); raw.dy = LE_S16(iround(node->dy)); raw.b1.minx = LE_S16(node->r.bounds.minx); raw.b1.miny = LE_S16(node->r.bounds.miny); raw.b1.maxx = LE_S16(node->r.bounds.maxx); raw.b1.maxy = LE_S16(node->r.bounds.maxy); raw.b2.minx = LE_S16(node->l.bounds.minx); raw.b2.miny = LE_S16(node->l.bounds.miny); raw.b2.maxx = LE_S16(node->l.bounds.maxx); raw.b2.maxy = LE_S16(node->l.bounds.maxy); if (node->r.node) raw.right = LE_U32(node->r.node->index); else if (node->r.subsec) raw.right = LE_U32(node->r.subsec->index | 0x80000000U); else BugError("Bad right child in V5 node %d\n", node->index); if (node->l.node) raw.left = LE_U32(node->l.node->index); else if (node->l.subsec) raw.left = LE_U32(node->l.subsec->index | 0x80000000U); else BugError("Bad left child in V5 node %d\n", node->index); lump->Write(&raw, sizeof(raw)); # if DEBUG_BSP gLog.debugPrintf("PUT V5 NODE %08X Left %08X Right %08X " "(%d,%d) -> (%d,%d)\n", node->index, LE_U32(raw.left), LE_U32(raw.right), node->x, node->y, node->x + node->dx, node->y + node->dy); # endif } void LevelData::PutNodes(const char *name, int do_v5, node_t *root) { Lump_c &lump = CreateLevelLump(name); node_cur_index = 0; if (root) { if (do_v5) PutOneNode_V5(root, &lump); else PutOneNode(root, &lump); } if (node_cur_index != (int)nodes.size()) BugError("PutNodes miscounted (%d != %d)\n", node_cur_index, (int)nodes.size()); if (!do_v5 && node_cur_index > 32767) { Failure("Number of nodes has overflowed.\n"); MarkOverflow(LIMIT_NODES); } } void LevelData::CheckLimits(bool& force_v5, bool& force_xnod) { if (doc.numSectors() > 65534) { Failure("Map has too many sectors.\n"); MarkOverflow(LIMIT_SECTORS); } if (doc.numSidedefs() > 65534) { Failure("Map has too many sidedefs.\n"); MarkOverflow(LIMIT_SIDEDEFS); } if (doc.numLinedefs() > 65534) { Failure("Map has too many linedefs.\n"); MarkOverflow(LIMIT_LINEDEFS); } if (cur_info->gl_nodes && !cur_info->force_v5) { if (num_old_vert > 32767 || num_new_vert > 32767 || (int)segs.size() > 65534 || (int)nodes.size() > 32767) { Warning("Forcing V5 of GL-Nodes due to overflows.\n"); force_v5 = true; } } if (! cur_info->force_xnod) { if (num_old_vert > 32767 || num_new_vert > 32767 || (int)segs.size() > 32767 || (int)nodes.size() > 32767) { Warning("Forcing XNOD format nodes due to overflows.\n"); force_xnod = true; } } } struct seg_index_CMP_pred { inline bool operator() (const seg_t *A, const seg_t *B) const { return A->index < B->index; } }; void LevelData::SortSegs() { // do a sanity check for (int i = 0 ; i < (int)segs.size() ; i++) if (segs[i]->index < 0) BugError("Seg %d never reached a subsector!\n", i); // sort segs into ascending index std::sort(segs.begin(), segs.end(), seg_index_CMP_pred()); // remove unwanted segs while (segs.size() > 0 && segs.back()->index == SEG_IS_GARBAGE) { UtilFree((void *) segs.back()); segs.pop_back(); } } /* ----- ZDoom format writing --------------------------- */ class ZLibContext { public: class Compression { public: class Exception : public std::runtime_error { public: Exception(int result, const SString& message) : std::runtime_error(message.get() + ": " + std::to_string(result)) { } }; Compression(); ~Compression(); Compression(const Compression& other) = delete; Compression& operator = (const Compression& other) = delete; int deflate(int flush) { return ::deflate(&stream, flush); } void setNextOut(Bytef* out, uInt outSize) noexcept { stream.next_out = out; stream.avail_out = outSize; } uInt getAvailOut() const noexcept { return stream.avail_out; } void setNextIn(Bytef* in, uInt inSize) noexcept { stream.next_in = in; stream.avail_in = inSize; } uInt getAvailIn() const noexcept { return stream.avail_in; } private: z_stream stream{}; }; ZLibContext(bool compress, std::vector &data); void appendLump(const void *data, int length) noexcept(false); void finishLump() noexcept(false); private: std::vector &out_data; tl::optional compression; Bytef out_buffer[1024] = {}; }; ZLibContext::Compression::Compression() { int result = deflateInit(&stream, Z_DEFAULT_COMPRESSION); if (result != Z_OK) throw Exception(result, "Trouble setting up zlib compression"); } ZLibContext::Compression::~Compression() { int result = deflateEnd(&stream); if (result != Z_OK) gLog.printf("Error ending zlib compression: %d\n", result); } ZLibContext::ZLibContext(bool compress, std::vector &data) : out_data(data) { if(!compress) return; compression.emplace(); compression->setNextOut(out_buffer, sizeof(out_buffer)); } void ZLibContext::appendLump(const void *data, int length) noexcept(false) { if (! compression) { auto bdata = static_cast(data); out_data.insert(out_data.end(), bdata, bdata + length); return; } compression->setNextIn(const_cast(static_cast(data)), length); while (compression->getAvailIn() > 0) { int err = compression->deflate(Z_NO_FLUSH); if (err != Z_OK) { throw Compression::Exception(err, SString::printf("Trouble compressing %d bytes (zlib)", length)); } if (compression->getAvailOut() == 0) { out_data.insert(out_data.end(), out_buffer, out_buffer + sizeof(out_buffer)); compression->setNextOut(out_buffer, sizeof(out_buffer)); } } } void ZLibContext::finishLump() noexcept(false) { if (! compression) { return; } int left_over; // ASSERT(zout_stream.avail_out > 0) compression->setNextIn(Z_NULL, 0); for (;;) { int err = compression->deflate(Z_FINISH); if (err == Z_STREAM_END) break; if (err != Z_OK) { throw Compression::Exception(err, "Trouble finishing compression (zlib)"); } if (compression->getAvailOut() == 0) { out_data.insert(out_data.end(), out_buffer, out_buffer + sizeof(out_buffer)); compression->setNextOut(out_buffer, sizeof(out_buffer)); } } left_over = sizeof(out_buffer) - compression->getAvailOut(); if (left_over > 0) { out_data.insert(out_data.end(), out_buffer, out_buffer + left_over); } } static const uint8_t *lev_XNOD_magic = (uint8_t *) "XNOD"; static const uint8_t *lev_XGL3_magic = (uint8_t *) "XGL3"; static const uint8_t *lev_ZNOD_magic = (uint8_t *) "ZNOD"; void LevelData::PutZVertices(ZLibContext &zcontext) const noexcept(false) { int count, i; uint32_t orgverts = LE_U32(num_old_vert); uint32_t newverts = LE_U32(num_new_vert); zcontext.appendLump(&orgverts, 4); zcontext.appendLump(&newverts, 4); for (i=0, count=0 ; i < (int)vertices.size() ; i++) { raw_v2_vertex_t raw; const vertex_t *vert = vertices[i]; if (! vert->is_new) continue; raw.x = LE_S32(iround(vert->x * 65536.0)); raw.y = LE_S32(iround(vert->y * 65536.0)); zcontext.appendLump(&raw, sizeof(raw)); count++; } if (count != num_new_vert) BugError("PutZVertices miscounted (%d != %d)", count, num_new_vert); } void LevelData::PutZSubsecs(ZLibContext &zcontext) const noexcept(false) { int i; int count; uint32_t raw_num = LE_U32((int)subsecs.size()); int cur_seg_index = 0; zcontext.appendLump(&raw_num, 4); for (i=0 ; i < (int)subsecs.size() ; i++) { subsec_t *sub = subsecs[i]; seg_t *seg; raw_num = LE_U32(sub->seg_count); zcontext.appendLump(&raw_num, 4); // sanity check the seg index values count = 0; for (seg = sub->seg_list ; seg ; seg = seg->next, cur_seg_index++) { if (cur_seg_index != seg->index) { BugError("PutZSubsecs: seg index mismatch in sub %d (%d != %d)", i, cur_seg_index, seg->index); } count++; } if (count != sub->seg_count) BugError("PutZSubsecs: miscounted segs in sub %d (%d != %d)", i, count, sub->seg_count); } if (cur_seg_index != (int)segs.size()) BugError("PutZSubsecs miscounted segs (%d != %d)", cur_seg_index, (int)segs.size()); } void LevelData::PutZSegs(ZLibContext &zcontext) const noexcept(false) { int i, count; uint32_t raw_num = LE_U32((int)segs.size()); zcontext.appendLump(&raw_num, 4); for (i=0, count=0 ; i < (int)segs.size() ; i++) { seg_t *seg = segs[i]; if (count != seg->index) BugError("PutZSegs: seg index mismatch (%d != %d)", count, seg->index); { uint32_t v1 = LE_U32(VertexIndex_XNOD(seg->start)); uint32_t v2 = LE_U32(VertexIndex_XNOD(seg->end)); uint16_t line = LE_U16(seg->linedef); uint8_t side = static_cast(seg->side); zcontext.appendLump(&v1, 4); zcontext.appendLump(&v2, 4); zcontext.appendLump(&line, 2); zcontext.appendLump(&side, 1); } count++; } if (count != (int)segs.size()) BugError("PutZSegs miscounted (%d != %d)\n", count, (int)segs.size()); } void LevelData::PutXGL3Segs(ZLibContext &zcontext) const noexcept(false) { int i, count; uint32_t raw_num = LE_U32((int)segs.size()); zcontext.appendLump(&raw_num, 4); for (i=0, count=0 ; i < (int)segs.size() ; i++) { seg_t *seg = segs[i]; if (count != seg->index) { BugError("PutXGL3Segs: seg index mismatch (%d != %d)\n", count, seg->index); } { uint32_t v1 = LE_U32(VertexIndex_XNOD(seg->start)); uint32_t partner = LE_U32(seg->partner ? seg->partner->index : -1); uint32_t line = LE_U32(seg->linedef); uint8_t side = static_cast(seg->side); # if DEBUG_BSP fprintf(stderr, "SEG[%d] v1=%d partner=%d line=%d side=%d\n", i, v1, partner, line, side); # endif zcontext.appendLump(&v1, 4); zcontext.appendLump(&partner, 4); zcontext.appendLump(&line, 4); zcontext.appendLump(&side, 1); } count++; } if (count != (int)segs.size()) { BugError("PutXGL3Segs miscounted (%d != %d)\n", count, (int)segs.size()); } } void LevelData::PutOneZNode(ZLibContext &zcontext, node_t *node, bool do_xgl3) noexcept(false) { raw_v5_node_t raw; if (node->r.node) PutOneZNode(zcontext, node->r.node, do_xgl3); if (node->l.node) PutOneZNode(zcontext, node->l.node, do_xgl3); node->index = node_cur_index++; if (do_xgl3) { uint32_t x = LE_S32(iround(node->x * 65536.0)); uint32_t y = LE_S32(iround(node->y * 65536.0)); uint32_t dx = LE_S32(iround(node->dx * 65536.0)); uint32_t dy = LE_S32(iround(node->dy * 65536.0)); zcontext.appendLump(&x, 4); zcontext.appendLump(&y, 4); zcontext.appendLump(&dx, 4); zcontext.appendLump(&dy, 4); } else { raw.x = LE_S16(iround(node->x)); raw.y = LE_S16(iround(node->y)); raw.dx = LE_S16(iround(node->dx)); raw.dy = LE_S16(iround(node->dy)); zcontext.appendLump(&raw.x, 2); zcontext.appendLump(&raw.y, 2); zcontext.appendLump(&raw.dx, 2); zcontext.appendLump(&raw.dy, 2); } raw.b1.minx = LE_S16(node->r.bounds.minx); raw.b1.miny = LE_S16(node->r.bounds.miny); raw.b1.maxx = LE_S16(node->r.bounds.maxx); raw.b1.maxy = LE_S16(node->r.bounds.maxy); raw.b2.minx = LE_S16(node->l.bounds.minx); raw.b2.miny = LE_S16(node->l.bounds.miny); raw.b2.maxx = LE_S16(node->l.bounds.maxx); raw.b2.maxy = LE_S16(node->l.bounds.maxy); zcontext.appendLump(&raw.b1, sizeof(raw.b1)); zcontext.appendLump(&raw.b2, sizeof(raw.b2)); if (node->r.node) raw.right = LE_U32(node->r.node->index); else if (node->r.subsec) raw.right = LE_U32(node->r.subsec->index | 0x80000000U); else { BugError("Bad right child in V5 node %d\n", node->index); } if (node->l.node) raw.left = LE_U32(node->l.node->index); else if (node->l.subsec) raw.left = LE_U32(node->l.subsec->index | 0x80000000U); else BugError("Bad left child in V5 node %d\n", node->index); zcontext.appendLump(&raw.right, 4); zcontext.appendLump(&raw.left, 4); # if DEBUG_BSP gLog.debugPrintf("PUT Z NODE %08X Left %08X Right %08X " "(%d,%d) -> (%d,%d)\n", node->index, LE_U32(raw.left), LE_U32(raw.right), node->x, node->y, node->x + node->dx, node->y + node->dy); # endif } void LevelData::PutZNodes(ZLibContext &zcontext, node_t *root, bool do_xgl3) noexcept(false) { uint32_t raw_num = LE_U32((int)nodes.size()); zcontext.appendLump(&raw_num, 4); node_cur_index = 0; if (root) PutOneZNode(zcontext, root, do_xgl3); if (node_cur_index != (int)nodes.size()) { BugError("PutZNodes miscounted (%d != %d)\n", node_cur_index, (int)nodes.size()); } } void LevelData::putZItems(std::vector& lumpData, node_t* root_node, bool do_xgl3) { auto putTheStuff = [this, root_node, do_xgl3](ZLibContext &zlibContext) { PutZVertices(zlibContext); PutZSubsecs(zlibContext); if (do_xgl3) PutXGL3Segs(zlibContext); else PutZSegs(zlibContext); PutZNodes(zlibContext, root_node, do_xgl3); }; try { ZLibContext zlibContext(cur_info->force_compress, lumpData); putTheStuff(zlibContext); zlibContext.finishLump(); } catch (const ZLibContext::Compression::Exception& e) { PrintMsg("Cannot compress nodes: %s\n", e.what()); lumpData.clear(); ZLibContext zlibContext(false, lumpData); putTheStuff(zlibContext); zlibContext.finishLump(); } } void LevelData::SaveZDFormat(node_t *root_node) { // the ZLibXXX functions do no compression for XNOD format std::vector lumpData; putZItems(lumpData, root_node, false); // Commit // leave SEGS and SSECTORS empty CreateLevelLump("SEGS"); CreateLevelLump("SSECTORS"); Lump_c &lump = CreateLevelLump("NODES"); if (cur_info->force_compress) lump.Write(lev_ZNOD_magic, 4); else lump.Write(lev_XNOD_magic, 4); lump.Write(lumpData.data(), (int)lumpData.size()); } void LevelData::SaveXGL3Format(node_t *root_node) { // WISH : compute a max_size Lump_c &lump = CreateLevelLump("ZNODES"); lump.Write(lev_XGL3_magic, 4); // disable compression cur_info->force_compress = false; std::vector lumpData; putZItems(lumpData, root_node, true); lump.Write(lumpData.data(), (int)lumpData.size()); } /* ----- whole-level routines --------------------------- */ void LevelData::LoadLevel() { const Lump_c *LEV = wad.GetLump(current_start); current_name = LEV->Name(); overflows = 0; PrintMsg("Building nodes on %s\n", current_name.c_str()); num_new_vert = 0; num_real_lines = 0; GetVertices(); for(auto &L : doc.linedefs) { if (L->right >= 0 || L->left >= 0) num_real_lines++; // init some fake flags L->flags &= ~(MLF_IS_PRECIOUS | MLF_IS_OVERLAP); if (L->tag >= 900 && L->tag < 1000) L->flags |= MLF_IS_PRECIOUS; } PrintDetail("Loaded %d vertices, %d sectors, %d sides, %d lines, %d things\n", doc.numVertices(), doc.numSectors(), doc.numSidedefs(), doc.numLinedefs(), doc.numThings()); DetectOverlappingVertices(); DetectOverlappingLines(doc); CalculateWallTips(); if (format != MapFormat::doom) { // -JL- Find sectors containing polyobjs DetectPolyobjSectors(); } } void LevelData::FreeLevel(void) { FreeVertices(); FreeSegs(); FreeSubsecs(); FreeNodes(); FreeWallTips(); } uint32_t LevelData::CalcGLChecksum() const { uint32_t crc; Adler32_Begin(&crc); const Lump_c *lump = FindLevelLump("VERTEXES"); if (lump && lump->Length() > 0) { const uint8_t *data = lump->getData().data(); Adler32_AddBlock(&crc, data, lump->Length()); } lump = FindLevelLump("LINEDEFS"); if (lump && lump->Length() > 0) { const uint8_t *data = lump->getData().data(); Adler32_AddBlock(&crc, data, lump->Length()); } Adler32_Finish(&crc); return crc; } void LevelData::UpdateGLMarker(Lump_c *marker) const { // we *must* compute the checksum BEFORE (re)creating the lump // [ otherwise we write data into the wrong part of the file ] uint32_t crc = CalcGLChecksum(); // when original name is long, need to specify it here if (current_name.length() > 5) { marker->Printf("LEVEL=%s\n", current_name.c_str()); } marker->Printf("BUILDER=%s\n", "Eureka " EUREKA_VERSION); marker->Printf("OPTIONS=%s\n", CalcOptionsString().c_str()); SString time_str = UtilTimeString(); if (!time_str.empty()) { marker->Printf("TIME=%s\n", time_str.c_str()); } marker->Printf("CHECKSUM=0x%08x\n", crc); } void LevelData::AddMissingLump(const char *name, const char *after) { if (wad.LevelLookupLump(current_idx, name) >= 0) return; int exist = wad.LevelLookupLump(current_idx, after); // if this happens, the level structure is very broken if (exist < 0) { Warning("Missing %s lump -- level structure is broken\n", after); exist = wad.LevelLastLump(current_idx); } wad.InsertPoint(exist + 1); wad.AddLump(name); } build_result_e LevelData::SaveLevel(node_t *root_node) { // Note: root_node may be NULL // remove any existing GL-Nodes wad.RemoveGLNodes(current_idx); // ensure all necessary level lumps are present AddMissingLump("SEGS", "VERTEXES"); AddMissingLump("SSECTORS", "SEGS"); AddMissingLump("NODES", "SSECTORS"); AddMissingLump("REJECT", "SECTORS"); AddMissingLump("BLOCKMAP", "REJECT"); // user preferences bool force_v5 = cur_info->force_v5; bool force_xnod = cur_info->force_xnod; // check for overflows... // this sets the force_xxx vars if certain limits are breached CheckLimits(force_v5, force_xnod); /* --- GL Nodes --- */ Lump_c * gl_marker = NULL; if (cur_info->gl_nodes && num_real_lines > 0) { SortSegs(); // create empty marker now, flesh it out later gl_marker = &CreateGLMarker(); PutGLVertices(force_v5); if (force_v5) PutGLSegs_V5(); else PutGLSegs(); if (force_v5) PutGLSubsecs_V5(); else PutSubsecs("GL_SSECT", true); PutNodes("GL_NODES", force_v5, root_node); // -JL- Add empty PVS lump CreateLevelLump("GL_PVS"); } /* --- Normal nodes --- */ // remove all the mini-segs from subsectors NormaliseBspTree(); if (force_xnod && num_real_lines > 0) { SortSegs(); SaveZDFormat(root_node); } else { // reduce vertex precision for classic DOOM nodes. // some segs can become "degenerate" after this, and these // are removed from subsectors. RoundOffBspTree(); // this also removes minisegs and degenerate segs SortSegs(); PutVertices("VERTEXES", false); PutSegs(); PutSubsecs("SSECTORS", false); PutNodes("NODES", false, root_node); } PutBlockmap(); PutReject(); // keyword support (v5.0 of the specs). // must be done *after* doing normal nodes (for proper checksum). if (gl_marker) { UpdateGLMarker(gl_marker); } if (overflows > 0) { cur_info->total_failed_maps++; PrintMsg("FAILED with %d overflowed lumps\n", overflows); return BUILD_LumpOverflow; } return BUILD_OK; } build_result_e LevelData::SaveUDMF(node_t *root_node) { // remove any existing ZNODES lump wad.RemoveZNodes(current_idx); try { if (num_real_lines >= 0) { SortSegs(); SaveXGL3Format(root_node); } } catch (const std::runtime_error& e) { gLog.printf("Failed building UDMF nodes: %s\n", e.what()); throw; } if (overflows > 0) { cur_info->total_failed_maps++; PrintMsg("FAILED with %d overflowed lumps\n", overflows); return BUILD_LumpOverflow; } return BUILD_OK; } /* ---------------------------------------------------------------- */ Lump_c * LevelData::FindLevelLump(const char *name) const noexcept { int idx = wad.LevelLookupLump(current_idx, name); if (idx < 0) return NULL; return wad.GetLump(idx); } Lump_c & LevelData::CreateLevelLump(const char *name) const { // look for existing one Lump_c *lump = FindLevelLump(name); if(!lump) { int last_idx = wad.LevelLastLump(current_idx); // in UDMF maps, insert before the ENDMAP lump, otherwise insert // after the last known lump of the level. if (format != MapFormat::udmf) last_idx++; wad.InsertPoint(last_idx); lump = &wad.AddLump(name); } lump->clearData(); return *lump; } Lump_c & LevelData::CreateGLMarker() const { SString name_buf; if (current_name.length() <= 5) { name_buf = "GL_" + current_name; } else { // names longer than 5 chars use "GL_LEVEL" as marker name name_buf = "GL_LEVEL"; } int last_idx = wad.LevelLastLump(current_idx); wad.InsertPoint(last_idx + 1); return wad.AddLump(name_buf); } //------------------------------------------------------------------------ // MAIN STUFF //------------------------------------------------------------------------ build_result_e LevelData::BuildLevel(nodebuildinfo_t *info, int lev_idx) { cur_info = info; node_t *root_node = NULL; subsec_t *root_sub = NULL; bbox_t root_bbox; if (cur_info->cancelled) return BUILD_Cancelled; current_idx = lev_idx; current_start = wad.LevelHeader(lev_idx); LoadLevel(); block.InitMap(doc); build_result_e ret = BUILD_OK; if (num_real_lines > 0) { // create initial segs seg_t *list = CreateSegs(); // recursively create nodes ret = BuildNodes(list, &root_bbox, &root_node, &root_sub, 0); } if (ret == BUILD_OK) { PrintDetail("Built %d NODES, %d SSECTORS, %d SEGS, %d VERTEXES\n", (int)nodes.size(), (int)subsecs.size(), (int)segs.size(), num_old_vert + num_new_vert); if (root_node) { PrintDetail("Heights of left and right subtrees = (%d,%d)\n", ComputeBspHeight(root_node->r.node), ComputeBspHeight(root_node->l.node)); } ClockwiseBspTree(); try { if (format == MapFormat::udmf) ret = SaveUDMF(root_node); else ret = SaveLevel(root_node); } catch(const std::runtime_error &e) { PrintMsg("Failed saving after node-build: %s\n", e.what()); ret = BUILD_BadFile; } } else { /* build was Cancelled by the user */ } FreeLevel(); FreeQuickAllocCuts(); // clear some fake line flags for(auto &linedef : doc.linedefs) linedef->flags &= ~(MLF_IS_PRECIOUS | MLF_IS_OVERLAP); return ret; } } // namespace ajbsp build_result_e AJBSP_BuildLevel(nodebuildinfo_t *info, int lev_idx, Instance &inst, const Document &doc, const LoadingData& loading, Wad_file& wad) { ajbsp::LevelData lev_data(loading.levelFormat, wad, doc, inst.conf, [&inst](const SString &message){ inst.GB_PrintMsg("%s", message.c_str()); }); return lev_data.BuildLevel(info, lev_idx); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/bsp_node.cc000066400000000000000000001243761464327712600204450ustar00rootroot00000000000000//------------------------------------------------------------------------ // // AJ-BSP Copyright (C) 2000-2019 Andrew Apted, et al // Copyright (C) 1994-1998 Colin Reed // Copyright (C) 1997-1998 Lee Killough // // Originally based on the program 'BSP', version 2.3. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // To be able to divide the nodes down, this routine must decide which // is the best Seg to use as a nodeline. It does this by selecting the // line with least splits and has least difference of Segs on either // side of it. // // Credit to Raphael Quinet and DEU, this routine is a copy of the // nodeline picker used in DEU5beta. I am using this method because // the method I originally used was not so good. // // Rewritten by Lee Killough to significantly improve performance, // while not affecting results one bit in >99% of cases (some tiny // differences due to roundoff error may occur, but they are // insignificant). // // Rewritten again by Andrew Apted (-AJA-), 1999-2000. // #include "bsp.h" #include "Instance.h" #include "w_rawdef.h" namespace ajbsp { #define PRECIOUS_MULTIPLY 100 #define SEG_FAST_THRESHHOLD 200 #define DEBUG_BUILDER 0 #define DEBUG_SORTER 0 #define DEBUG_SUBSEC 0 #define DEBUG_PICKNODE 0 #define DEBUG_SPLIT 0 #define DEBUG_CUTLIST 0 // smallest distance between two points before being considered equal #define DIST_EPSILON (1.0 / 1024.0) static int current_seg_index; struct eval_info_t { int cost; int splits; int iffy; int near_miss; int real_left; int real_right; int mini_left; int mini_right; public: void BumpLeft(int linedef) { if (linedef >= 0) real_left++; else mini_left++; } void BumpRight(int linedef) { if (linedef >= 0) real_right++; else mini_right++; } }; static intersection_t *quick_alloc_cuts = NULL; static intersection_t *NewIntersection(void) { intersection_t *cut; if (quick_alloc_cuts) { cut = quick_alloc_cuts; quick_alloc_cuts = cut->next; } else { cut = (intersection_t *) UtilCalloc(sizeof(intersection_t)); } return cut; } void FreeQuickAllocCuts(void) { while (quick_alloc_cuts) { intersection_t *cut = quick_alloc_cuts; quick_alloc_cuts = cut->next; UtilFree(cut); } } // // Fill in the fields 'angle', 'len', 'pdx', 'pdy', etc... // void seg_t::Recompute() { psx = start->x; psy = start->y; pex = end->x; pey = end->y; pdx = pex - psx; pdy = pey - psy; p_length = hypot(pdx, pdy); if (p_length <= 0) BugError("Seg %p has zero p_length.\n", this); p_perp = psy * pdx - psx * pdy; p_para = -psx * pdx - psy * pdy; } // // -AJA- Splits the given seg at the point (x,y). The new seg is // returned. The old seg is shortened (the original start // vertex is unchanged), whereas the new seg becomes the cut-off // tail (keeping the original end vertex). // // If the seg has a partner, than that partner is also split. // NOTE WELL: the new piece of the partner seg is inserted into // the same list as the partner seg (and after it) -- thus ALL // segs (except the one we are currently splitting) must exist // on a singly-linked list somewhere. // seg_t * LevelData::SplitSeg(seg_t *old_seg, double x, double y) { seg_t *new_seg; vertex_t *new_vert; # if DEBUG_SPLIT if (old_seg->linedef >= 0) gLog.debugPrintf("Splitting Linedef %d (%p) at (%1.1f,%1.1f)\n", old_seg->linedef, old_seg, x, y); else gLog.debugPrintf("Splitting Miniseg %p at (%1.1f,%1.1f)\n", old_seg, x, y); # endif new_vert = NewVertexFromSplitSeg(old_seg, x, y); new_seg = NewSeg(); // copy seg info new_seg[0] = old_seg[0]; new_seg->next = NULL; old_seg->end = new_vert; new_seg->start = new_vert; old_seg->Recompute(); new_seg->Recompute(); # if DEBUG_SPLIT gLog.debugPrintf("Splitting Vertex is %04X at (%1.1f,%1.1f)\n", new_vert->index, new_vert->x, new_vert->y); # endif // handle partners if (old_seg->partner) { # if DEBUG_SPLIT gLog.debugPrintf("Splitting Partner %p\n", old_seg->partner); # endif new_seg->partner = NewSeg(); // copy seg info // [ including the "next" field ] new_seg->partner[0] = old_seg->partner[0]; // IMPORTANT: keep partner relationship valid. new_seg->partner->partner = new_seg; old_seg->partner->start = new_vert; new_seg->partner->end = new_vert; old_seg->partner->Recompute(); new_seg->partner->Recompute(); // link it into list old_seg->partner->next = new_seg->partner; } return new_seg; } // // -AJA- In the quest for slime-trail annihilation :->, this routine // calculates the intersection location between the current seg // and the partitioning seg, and takes advantage of some common // situations like horizontal/vertical lines. // static inline void ComputeIntersection(seg_t *seg, seg_t *part, double perp_c, double perp_d, double *x, double *y) { double ds; // horizontal partition against vertical seg if (part->pdy == 0 && seg->pdx == 0) { *x = seg->psx; *y = part->psy; return; } // vertical partition against horizontal seg if (part->pdx == 0 && seg->pdy == 0) { *x = part->psx; *y = seg->psy; return; } // 0 = start, 1 = end ds = perp_c / (perp_c - perp_d); if (seg->pdx == 0) *x = seg->psx; else *x = seg->psx + (seg->pdx * ds); if (seg->pdy == 0) *y = seg->psy; else *y = seg->psy + (seg->pdy * ds); } static void AddIntersection(intersection_t ** cut_list, vertex_t *vert, seg_t *part, bool self_ref) { bool open_before = VertexCheckOpen(vert, -part->pdx, -part->pdy); bool open_after = VertexCheckOpen(vert, part->pdx, part->pdy); double along_dist = part->ParallelDist(vert->x, vert->y); intersection_t *cut; intersection_t *after; /* merge with any existing vertex? */ for (cut=(*cut_list) ; cut ; cut=cut->next) { if (vert == cut->vertex) { return; } else if (fabs(along_dist - cut->along_dist) < DIST_EPSILON*2) { // an OPEN aspect always overrides a CLOSED one. // [ though a mismatch should only occur with broken geometry ] if (open_before) cut->open_before = true; if (open_after) cut->open_after = true; return; } } /* create new intersection */ cut = NewIntersection(); cut->vertex = vert; cut->along_dist = along_dist; cut->self_ref = self_ref; cut->open_before = open_before; cut->open_after = open_after; /* insert the new intersection into the list */ for (after=(*cut_list) ; after && after->next ; after=after->next) { } while (after && cut->along_dist < after->along_dist) after = after->prev; /* link it in */ cut->next = after ? after->next : (*cut_list); cut->prev = after; if (after) { if (after->next) after->next->prev = cut; after->next = cut; } else { if (*cut_list) (*cut_list)->prev = cut; (*cut_list) = cut; } } // // Returns true if a "bad seg" was found early. // int LevelData::EvalPartitionWorker(quadtree_c *tree, seg_t *part, int best_cost, eval_info_t *info) { double qnty; double a, b, fa, fb; int factor = cur_info->factor; // -AJA- this is the heart of the superblock idea, it tests the // *whole* quad against the partition line to quickly handle // all the segs within it at once. Only when the partition // line intercepts the box do we need to go deeper into it. switch (tree->OnLineSide(part)) { case Side::left: info->real_left += tree->real_num; info->mini_left += tree->mini_num; return false; case Side::right: info->real_right += tree->real_num; info->mini_right += tree->mini_num; return false; default: break; } /* check partition against all Segs */ seg_t *check; for (check=tree->list ; check ; check=check->next) { // This is the heart of my pruning idea - it catches // bad segs early on. Killough if (info->cost > best_cost) return true; /* get state of lines' relation to each other */ if (check->source_line == part->source_line) { a = b = fa = fb = 0; } else { a = part->PerpDist(check->psx, check->psy); b = part->PerpDist(check->pex, check->pey); fa = fabs(a); fb = fabs(b); } /* check for being on the same line */ if (fa <= DIST_EPSILON && fb <= DIST_EPSILON) { // this seg runs along the same line as the partition. Check // whether it goes in the same direction or the opposite. if (check->pdx*part->pdx + check->pdy*part->pdy < 0) { info->BumpLeft(check->linedef); } else { info->BumpRight(check->linedef); } continue; } // -AJA- check for passing through a vertex. Normally this is fine // (even ideal), but the vertex could on a sector that we // DONT want to split, and the normal linedef-based checks // may fail to detect the sector being cut in half. Thanks // to Janis Legzdinsh for spotting this obscure bug. if (fa <= DIST_EPSILON || fb <= DIST_EPSILON) { if (check->linedef >= 0 && (doc.linedefs[check->linedef]->flags & MLF_IS_PRECIOUS)) info->cost += 40 * factor * PRECIOUS_MULTIPLY; } /* check for right side */ if (a > -DIST_EPSILON && b > -DIST_EPSILON) { info->BumpRight(check->linedef); /* check for a near miss */ if ((a >= IFFY_LEN && b >= IFFY_LEN) || (a <= DIST_EPSILON && b >= IFFY_LEN) || (b <= DIST_EPSILON && a >= IFFY_LEN)) { continue; } info->near_miss++; // -AJA- near misses are bad, since they have the potential to // cause really short minisegs to be created in future // processing. Thus the closer the near miss, the higher // the cost. if (a <= DIST_EPSILON || b <= DIST_EPSILON) qnty = IFFY_LEN / std::max(a, b); else qnty = IFFY_LEN / std::min(a, b); info->cost += (int) (100 * factor * (qnty * qnty - 1.0)); continue; } /* check for left side */ if (a < DIST_EPSILON && b < DIST_EPSILON) { info->BumpLeft(check->linedef); /* check for a near miss */ if ((a <= -IFFY_LEN && b <= -IFFY_LEN) || (a >= -DIST_EPSILON && b <= -IFFY_LEN) || (b >= -DIST_EPSILON && a <= -IFFY_LEN)) { continue; } info->near_miss++; // the closer the miss, the higher the cost (see note above) if (a >= -DIST_EPSILON || b >= -DIST_EPSILON) qnty = IFFY_LEN / -std::min(a, b); else qnty = IFFY_LEN / -std::max(a, b); info->cost += (int) (70 * factor * (qnty * qnty - 1.0)); continue; } // When we reach here, we have a and b non-zero and opposite sign, // hence this seg will be split by the partition line. info->splits++; // If the linedef associated with this seg has a tag >= 900, treat // it as precious; i.e. don't split it unless all other options // are exhausted. This is used to protect deep water and invisible // lifts/stairs from being messed up accidentally by splits. if (check->linedef >= 0 && (doc.linedefs[check->linedef]->flags & MLF_IS_PRECIOUS)) info->cost += 100 * factor * PRECIOUS_MULTIPLY; else info->cost += 100 * factor; // -AJA- check if the split point is very close to one end, which // an undesirable situation (producing really short segs). // This is perhaps _one_ source of those darn slime trails. // Hence the name "IFFY segs", and a rather hefty surcharge. if (fa < IFFY_LEN || fb < IFFY_LEN) { info->iffy++; // the closer to the end, the higher the cost qnty = IFFY_LEN / std::min(fa, fb); info->cost += (int) (140 * factor * (qnty * qnty - 1.0)); } } /* handle sub-blocks recursively */ for (int c=0 ; c < 2 ; c++) { if (tree->subs[c] && !tree->subs[c]->Empty()) { if (EvalPartitionWorker(tree->subs[c], part, best_cost, info)) return true; } } /* no "bad seg" was found */ return false; } // // -AJA- Evaluate a partition seg & determine the cost, taking into // account the number of splits, difference between left & // right, and linedefs that are tagged 'precious'. // // Returns the computed cost, or a negative value if the seg should be // skipped altogether. // int LevelData::EvalPartition(quadtree_c *tree, seg_t *part, int best_cost) { eval_info_t info; /* initialise info structure */ info.cost = 0; info.splits = 0; info.iffy = 0; info.near_miss = 0; info.real_left = 0; info.real_right = 0; info.mini_left = 0; info.mini_right = 0; if (EvalPartitionWorker(tree, part, best_cost, &info)) return -1; /* make sure there is at least one real seg on each side */ if (info.real_left == 0 || info.real_right == 0) { # if DEBUG_PICKNODE gLog.debugPrintf("Eval : No real segs on %s%sside\n", info.real_left ? "" : "left ", info.real_right ? "" : "right "); # endif return -1; } /* increase cost by the difference between left & right */ info.cost += 100 * abs(info.real_left - info.real_right); // -AJA- allow miniseg counts to affect the outcome, but to a // lesser degree than real segs. info.cost += 50 * abs(info.mini_left - info.mini_right); // -AJA- Another little twist, here we show a slight preference for // partition lines that lie either purely horizontally or // purely vertically. if (part->pdx != 0 && part->pdy != 0) info.cost += 25; # if DEBUG_PICKNODE gLog.debugPrintf("Eval %p: splits=%d iffy=%d near=%d left=%d+%d right=%d+%d " "cost=%d.%02d\n", part, info.splits, info.iffy, info.near_miss, info.real_left, info.mini_left, info.real_right, info.mini_right, info.cost / 100, info.cost % 100); # endif return info.cost; } static void EvaluateFastWorker(quadtree_c *tree, seg_t **best_H, seg_t **best_V, int mid_x, int mid_y) { seg_t *part; for (part=tree->list ; part ; part = part->next) { /* ignore minisegs as partition candidates */ if (part->linedef < 0) continue; if (part->pdy == 0) { // horizontal seg if (! *best_H) { *best_H = part; } else { int old_dist = abs((int)(*best_H)->psy - mid_y); int new_dist = abs((int)( part)->psy - mid_y); if (new_dist < old_dist) *best_H = part; } } else if (part->pdx == 0) { // vertical seg if (! *best_V) { *best_V = part; } else { int old_dist = abs((int)(*best_V)->psx - mid_x); int new_dist = abs((int)( part)->psx - mid_x); if (new_dist < old_dist) *best_V = part; } } } /* handle sub-blocks recursively */ for (int c=0 ; c < 2 ; c++) { if (tree->subs[c] && !tree->subs[c]->Empty()) { EvaluateFastWorker(tree->subs[c], best_H, best_V, mid_x, mid_y); } } } seg_t *LevelData::FindFastSeg(quadtree_c *tree) { seg_t *best_H = NULL; seg_t *best_V = NULL; int mid_x = (tree->x1 + tree->x2) / 2; int mid_y = (tree->y1 + tree->y2) / 2; EvaluateFastWorker(tree, &best_H, &best_V, mid_x, mid_y); int H_cost = -1; int V_cost = -1; if (best_H) H_cost = EvalPartition(tree, best_H, 99999999); if (best_V) V_cost = EvalPartition(tree, best_V, 99999999); # if DEBUG_PICKNODE gLog.debugPrintf("FindFastSeg: best_H=%p (cost %d) | best_V=%p (cost %d)\n", best_H, H_cost, best_V, V_cost); # endif if (H_cost < 0 && V_cost < 0) return NULL; if (H_cost < 0) return best_V; if (V_cost < 0) return best_H; return (V_cost < H_cost) ? best_V : best_H; } /* returns false if cancelled */ bool LevelData::PickNodeWorker(quadtree_c *part_list, quadtree_c *tree, seg_t ** best, int *best_cost) { // try each partition for (seg_t *part=part_list->list ; part ; part = part->next) { if (cur_info->cancelled) return false; # if DEBUG_PICKNODE gLog.debugPrintf("PickNode: %sSEG %p (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", part->linedef >= 0 ? "" : "MINI", part, part->start->x, part->start->y, part->end->x, part->end->y); # endif /* ignore minisegs as partition candidates */ if (part->linedef < 0) continue; int cost = EvalPartition(tree, part, *best_cost); /* seg unsuitable or too costly ? */ if (cost < 0 || cost >= *best_cost) continue; /* we have a new better choice */ (*best_cost) = cost; /* remember which Seg */ (*best) = part; } /* recursively handle sub-blocks */ for (int c=0 ; c < 2 ; c++) { if (part_list->subs[c] && !part_list->subs[c]->Empty()) { PickNodeWorker(part_list->subs[c], tree, best, best_cost); } } return true; } // // Find the best seg in the seg_list to use as a partition line. // seg_t *LevelData::PickNode(quadtree_c *tree, int depth) { seg_t *best=NULL; int best_cost=INT_MAX; # if DEBUG_PICKNODE gLog.debugPrintf("PickNode: BEGUN (depth %d)\n", depth); # endif /* -AJA- here is the logic for "fast mode". We look for segs which * are axis-aligned and roughly divide the current group into * two halves. This can save *heaps* of times on large levels. */ if (cur_info->fast && tree->real_num >= SEG_FAST_THRESHHOLD) { # if DEBUG_PICKNODE gLog.debugPrintf("PickNode: Looking for Fast node...\n"); # endif best = FindFastSeg(tree); if (best) { # if DEBUG_PICKNODE gLog.debugPrintf("PickNode: Using Fast node (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", best->start->x, best->start->y, best->end->x, best->end->y); # endif return best; } } if (! PickNodeWorker(tree, tree, &best, &best_cost)) { /* hack here : BuildNodes will detect the cancellation */ return NULL; } # if DEBUG_PICKNODE if (! best) { gLog.debugPrintf("PickNode: NO BEST FOUND !\n"); } else { gLog.debugPrintf("PickNode: Best has score %d.%02d (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", best_cost / 100, best_cost % 100, best->start->x, best->start->y, best->end->x, best->end->y); } # endif return best; } // // Apply the partition line to the given seg, taking the necessary // action (moving it into either the left list, right list, or // splitting it). // // -AJA- I have rewritten this routine based on the EvalPartition // routine above (which I've also reworked, heavily). I think // it is important that both these routines follow the exact // same logic when determining which segs should go left, right // or be split. // void LevelData::DivideOneSeg(seg_t *seg, seg_t *part, seg_t **left_list, seg_t **right_list, intersection_t ** cut_list) { seg_t *new_seg; double x, y; /* get state of lines' relation to each other */ double a = part->PerpDist(seg->psx, seg->psy); double b = part->PerpDist(seg->pex, seg->pey); bool self_ref = (seg->linedef >= 0) ? doc.isSelfRef(*doc.linedefs[seg->linedef]) : false; if (seg->source_line == part->source_line) a = b = 0; /* check for being on the same line */ if (fabs(a) <= DIST_EPSILON && fabs(b) <= DIST_EPSILON) { AddIntersection(cut_list, seg->start, part, self_ref); AddIntersection(cut_list, seg->end, part, self_ref); // this seg runs along the same line as the partition. check // whether it goes in the same direction or the opposite. if (seg->pdx*part->pdx + seg->pdy*part->pdy < 0) { ListAddSeg(left_list, seg); } else { ListAddSeg(right_list, seg); } return; } /* check for right side */ if (a > -DIST_EPSILON && b > -DIST_EPSILON) { if (a < DIST_EPSILON) AddIntersection(cut_list, seg->start, part, self_ref); else if (b < DIST_EPSILON) AddIntersection(cut_list, seg->end, part, self_ref); ListAddSeg(right_list, seg); return; } /* check for left side */ if (a < DIST_EPSILON && b < DIST_EPSILON) { if (a > -DIST_EPSILON) AddIntersection(cut_list, seg->start, part, self_ref); else if (b > -DIST_EPSILON) AddIntersection(cut_list, seg->end, part, self_ref); ListAddSeg(left_list, seg); return; } // when we reach here, we have a and b non-zero and opposite sign, // hence this seg will be split by the partition line. ComputeIntersection(seg, part, a, b, &x, &y); new_seg = SplitSeg(seg, x, y); AddIntersection(cut_list, seg->end, part, self_ref); if (a < 0) { ListAddSeg(left_list, seg); ListAddSeg(right_list, new_seg); } else { ListAddSeg(right_list, seg); ListAddSeg(left_list, new_seg); } } void LevelData::SeparateSegs(quadtree_c *tree, seg_t *part, seg_t **left_list, seg_t **right_list, intersection_t ** cut_list) { while (tree->list != NULL) { seg_t *seg = tree->list; tree->list = seg->next; seg->quad = NULL; DivideOneSeg(seg, part, left_list, right_list, cut_list); } // recursively handle sub-blocks if (tree->subs[0]) { SeparateSegs(tree->subs[0], part, left_list, right_list, cut_list); SeparateSegs(tree->subs[1], part, left_list, right_list, cut_list); } // this quadtree_c is empty now } void FindLimits2(seg_t *list, bbox_t *bbox) { // empty list? if (list == NULL) { bbox->minx = 0; bbox->miny = 0; bbox->maxx = 2; bbox->maxy = 2; return; } bbox->minx = bbox->miny = SHRT_MAX; bbox->maxx = bbox->maxy = SHRT_MIN; for ( ; list != NULL ; list = list->next) { double x1 = list->start->x; double y1 = list->start->y; double x2 = list->end->x; double y2 = list->end->y; int lx = (int) floor(std::min(x1, x2) - 0.2); int ly = (int) floor(std::min(y1, y2) - 0.2); int hx = (int) ceil(std::max(x1, x2) + 0.2); int hy = (int) ceil(std::max(y1, y2) + 0.2); if (lx < bbox->minx) bbox->minx = lx; if (ly < bbox->miny) bbox->miny = ly; if (hx > bbox->maxx) bbox->maxx = hx; if (hy > bbox->maxy) bbox->maxy = hy; } } void LevelData::AddMinisegs(intersection_t *cut_list, seg_t *part, seg_t **left_list, seg_t **right_list) { if (! cut_list) return; intersection_t *cur, *next; seg_t *seg, *buddy; # if DEBUG_CUTLIST gLog.debugPrintf("CUT LIST:\n"); gLog.debugPrintf("PARTITION: (%1.1f,%1.1f) += (%1.1f,%1.1f)\n", part->psx, part->psy, part->pdx, part->pdy); for (cur=cut_list ; cur ; cur=cur->next) { gLog.debugPrintf(" Vertex %8X (%1.1f,%1.1f) Along %1.2f [%d/%d] %s\n", cur->vertex->index, cur->vertex->x, cur->vertex->y, cur->along_dist, cur->open_before ? 1 : 0, cur->open_after ? 1 : 0, cur->self_ref ? "SELFREF" : ""); } # endif // find open gaps in the intersection list, convert to minisegs for (cur = cut_list ; cur && cur->next ; cur = cur->next) { next = cur->next; // sanity check double len = next->along_dist - cur->along_dist; if (len < -0.01) BugError("Bad order in intersect list: %1.3f > %1.3f\n", cur->along_dist, next->along_dist); bool A = cur->open_after; bool B = next->open_before; // nothing possible is both ends are CLOSED if (! (A || B)) continue; if (A != B) { // a mismatch indicates something wrong with level geometry. // warning about it is probably not worth it, so ignore it. continue; } // righteo, here we have definite open space. // create a miniseg pair... seg = NewSeg(); buddy = NewSeg(); seg->partner = buddy; buddy->partner = seg; seg->start = cur->vertex; seg->end = next->vertex; buddy->start = next->vertex; buddy->end = cur->vertex; // leave 'side' as zero too (not needed for minisegs). seg->index = buddy->index = -1; seg->linedef = buddy->linedef = -1; seg->source_line = buddy->source_line = part->linedef; seg->Recompute(); buddy->Recompute(); // add the new segs to the appropriate list ListAddSeg(right_list, seg); ListAddSeg(left_list, buddy); # if DEBUG_CUTLIST gLog.debugPrintf("AddMiniseg: %p RIGHT (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", seg, seg->start->x, seg->start->y, seg->end->x, seg->end->y); gLog.debugPrintf("AddMiniseg: %p LEFT (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", buddy, buddy->start->x, buddy->start->y, buddy->end->x, buddy->end->y); # endif } // free intersection structures into quick-alloc list while (cut_list) { cur = cut_list; cut_list = cur->next; cur->next = quick_alloc_cuts; quick_alloc_cuts = cur; } } //------------------------------------------------------------------------ // NODE : Recursively create nodes and return the pointers. //------------------------------------------------------------------------ // // Split a list of segs into two using the method described at bottom // of the file, this was taken from OBJECTS.C in the DEU5beta source. // // This is done by scanning all of the segs and finding the one that // does the least splitting and has the least difference in numbers of // segs on either side. // // If the ones on the left side make a SSector, then create another SSector // else put the segs into lefts list. // If the ones on the right side make a SSector, then create another SSector // else put the segs into rights list. // // Rewritten by Andrew Apted (-AJA-), 1999-2000. // // // Returns SIDE_LEFT, SIDE_RIGHT, or 0 for intersect. // Side seg_t::PointOnLineSide(double x, double y) const { double perp = PerpDist(x, y); if (fabs(perp) <= DIST_EPSILON) return Side::neither; return (perp < 0) ? Side::left : Side::right; } Side quadtree_c::OnLineSide(const seg_t *part) const { double tx1 = (double)x1 - IFFY_LEN; double ty1 = (double)y1 - IFFY_LEN; double tx2 = (double)x2 + IFFY_LEN; double ty2 = (double)y2 + IFFY_LEN; Side p1, p2; // handle simple cases (vertical & horizontal lines) if (part->pdx == 0) { p1 = (tx1 > part->psx) ? Side::right : Side::left; p2 = (tx2 > part->psx) ? Side::right : Side::left; if (part->pdy < 0) { p1 = -p1; p2 = -p2; } } else if (part->pdy == 0) { p1 = (ty1 < part->psy) ? Side::right : Side::left; p2 = (ty2 < part->psy) ? Side::right : Side::left; if (part->pdx < 0) { p1 = -p1; p2 = -p2; } } // now handle the cases of positive and negative slope else if (part->pdx * part->pdy > 0) { p1 = part->PointOnLineSide(tx1, ty2); p2 = part->PointOnLineSide(tx2, ty1); } else // NEGATIVE { p1 = part->PointOnLineSide(tx1, ty1); p2 = part->PointOnLineSide(tx2, ty2); } // line goes through or touches the box? if (p1 != p2) return Side::neither; return p1; } #if 0 // DEBUG HELPER void quadtree_c::VerifySide(seg_t *part, int side) { for (seg_t *seg = list ; seg != NULL ; seg = seg->next) { Side p1 = part->PointOnLineSide(seg->psx, seg->psy); if (p1 != side) BugError("VerifySide failed.\n"); Side p2 = part->PointOnLineSide(seg->pex, seg->pey); if (p2 != side) BugError("VerifySide failed.\n"); } if (subs[0]) subs[0]->VerifySide(part, side); if (subs[1]) subs[1]->VerifySide(part, side); } #endif void node_t::SetPartition(LevelData &lev_data, const seg_t *part) { SYS_ASSERT(part->linedef >= 0); const auto part_L = lev_data.GetDoc().linedefs[part->linedef]; if (part->side == 0) /* right side */ { x = lev_data.GetDoc().getStart(*part_L).x(); y = lev_data.GetDoc().getStart(*part_L).y(); dx = lev_data.GetDoc().getEnd(*part_L).x() - x; dy = lev_data.GetDoc().getEnd(*part_L).y() - y; } else /* left side */ { x = lev_data.GetDoc().getEnd(*part_L).x(); y = lev_data.GetDoc().getEnd(*part_L).y(); dx = lev_data.GetDoc().getStart(*part_L).x() - x; dy = lev_data.GetDoc().getStart(*part_L).y() - y; } /* check for very long partition (overflow of dx,dy in NODES) */ if (fabs(dx) > 32000 || fabs(dy) > 32000) { if (lev_data.GetFormat() == MapFormat::udmf) { // XGL3 nodes are 16.16 fixed point, hence we still need // to reduce the delta. dx *= 0.5; dy *= 0.5; } else { if (((int)dx | (int)dy) & 1) { lev_data.Warning("Loss of accuracy on VERY long node: " "(%f,%f) -> (%f,%f)\n", x, y, x + dx, y+ dy); } dx = round(dx * 0.5); dy = round(dy * 0.5); } } } /* ----- quad-tree routines ------------------------------------ */ quadtree_c::quadtree_c(int _x1, int _y1, int _x2, int _y2) : x1(_x1), y1(_y1), x2(_x2), y2(_y2), real_num(0), mini_num(0), list(NULL) { int dx = x2 - x1; int dy = y2 - y1; if (dx <= 320 && dy <= 320) { // leaf node subs[0] = NULL; subs[1] = NULL; } else if (dx >= dy) { subs[0] = new quadtree_c(x1, y1, x1 + dx/2, y2); subs[1] = new quadtree_c(x1 + dx/2, y1, x2, y2); } else { subs[0] = new quadtree_c(x1, y1, x2, y1 + dy/2); subs[1] = new quadtree_c(x1, y1 + dy/2, x2, y2); } } quadtree_c::~quadtree_c() { if (subs[0] != NULL) delete subs[0]; if (subs[1] != NULL) delete subs[1]; } void quadtree_c::AddSeg(seg_t *seg) { // update seg counts if (seg->linedef >= 0) real_num++; else mini_num++; if (subs[0] != NULL) { double x_min = std::min(seg->start->x, seg->end->x); double y_min = std::min(seg->start->y, seg->end->y); double x_max = std::max(seg->start->x, seg->end->x); double y_max = std::max(seg->start->y, seg->end->y); if ((x2 - x1) >= (y2 - y1)) { if (x_min > subs[1]->x1) { subs[1]->AddSeg(seg); return; } else if (x_max < subs[0]->x2) { subs[0]->AddSeg(seg); return; } } else { if (y_min > subs[1]->y1) { subs[1]->AddSeg(seg); return; } else if (y_max < subs[0]->y2) { subs[0]->AddSeg(seg); return; } } } // link into this node ListAddSeg(&list, seg); seg->quad = this; } void quadtree_c::AddList(seg_t *_list) { while (_list != NULL) { seg_t *seg = _list; _list = seg->next; AddSeg(seg); } } void quadtree_c::ConvertToList(seg_t **_list) { while (list != NULL) { seg_t *seg = list; list = seg->next; ListAddSeg(_list, seg); } if (subs[0] != NULL) { subs[0]->ConvertToList(_list); subs[1]->ConvertToList(_list); } // this quadtree is empty now } seg_t *LevelData::CreateOneSeg(int line, vertex_t *start, vertex_t *end, int sidedef, int what_side /* 0 or 1 */) { const SideDef *sd = NULL; if (sidedef >= 0) sd = doc.sidedefs[sidedef].get(); // check for bad sidedef if (sd && !doc.isSector(sd->sector)) { Warning("Bad sidedef on linedef #%d (Z_CheckHeap error)\n", line); } // handle overlapping vertices, pick a nominal one if (start->overlap) start = start->overlap; if ( end->overlap) end = end->overlap; seg_t *seg = NewSeg(); seg->start = start; seg->end = end; seg->linedef = line; seg->side = what_side; seg->partner = NULL; seg->source_line = seg->linedef; seg->index = -1; seg->Recompute(); return seg; } // // Initially create all segs, one for each linedef. // Must be called *after* InitBlockmap(). // seg_t *LevelData::CreateSegs() { seg_t *list = NULL; for (int i=0 ; i < doc.numLinedefs() ; i++) { const auto line = doc.linedefs[i]; seg_t *left = NULL; seg_t *right = NULL; // ignore zero-length lines if (doc.isZeroLength(*line)) continue; // ignore overlapping lines if (line->flags & MLF_IS_OVERLAP) continue; // check for extremely long lines if (doc.calcLength(*line) >= 30000) Warning("Linedef #%d is VERY long, it may cause problems\n", i); if (line->right >= 0) { right = CreateOneSeg(i, vertices[line->start], vertices[line->end], line->right, 0); ListAddSeg(&list, right); } else { Warning("Linedef #%d has no right sidedef!\n", i); } if (line->left >= 0) { left = CreateOneSeg(i, vertices[line->end], vertices[line->start], line->left, 1); ListAddSeg(&list, left); if (right) { // -AJA- Partner segs. These always maintain a one-to-one // correspondence, so if one of the gets split, the // other one must be split too. left->partner = right; right->partner = left; } } else { if (line->flags & MLF_TwoSided) Warning("Linedef #%d is 2s but has no left sidedef\n", i); } } return list; } static quadtree_c *TreeFromSegList(seg_t *list, const bbox_t *bounds) { quadtree_c *tree = new quadtree_c(bounds->minx, bounds->miny, bounds->maxx, bounds->maxy); tree->AddList(list); return tree; } void subsec_t::DetermineMiddle() { mid_x = 0.0; mid_y = 0.0; int total=0; // compute middle coordinates for (seg_t *seg=seg_list ; seg ; seg=seg->next) { mid_x += seg->start->x + seg->end->x; mid_y += seg->start->y + seg->end->y; total += 2; } if (total > 0) { mid_x /= (double)total; mid_y /= (double)total; } } void subsec_t::ClockwiseOrder(const Document& doc) { seg_t *seg; # if DEBUG_SUBSEC gLog.debugPrintf("Subsec: Clockwising %d\n", index); # endif // count segs and create an array to manipulate them int total = 0; for (seg=seg_list ; seg ; seg=seg->next) total++; // use local array if large enough seg_t *seg_buffer[32]; seg_t ** array = seg_buffer; if (total > 32) array = new seg_t* [total]; int i = 0; for (seg=seg_list ; seg ; seg=seg->next) { array[i++] = seg; // compute angles now seg->cmp_angle = UtilComputeAngle(seg->start->x - mid_x, seg->start->y - mid_y); } if (i != total) BugError("ClockwiseOrder miscounted.\n"); // sort segs by angle (from the middle point to the start vertex). // the desired order (clockwise) means descending angles. // since # of segs is usually small, a bubble sort is fast enough. i = 0; while (i+1 < total) { seg_t *A = array[i]; seg_t *B = array[i+1]; if (A->cmp_angle < B->cmp_angle) { // swap 'em array[i] = B; array[i+1] = A; // bubble down if (i > 0) i--; } else { // bubble up i++; } } // choose the seg that will be first (the game engine will typically use // that to determine the sector). while we don't like self referencing // linedefs (they are often used for deep-water effects), we definitely // have to skip minisegs. int first = 0; int best_score = -1; for (i=0 ; i < total ; i++) { int cur_score = 3; // miniseg? if (array[i]->linedef < 0) cur_score = 0; else if (doc.isSelfRef(*doc.linedefs[array[i]->linedef])) cur_score = 2; if (cur_score > best_score) { first = i; best_score = cur_score; } } // transfer sorted array back into subsec_t seg_list = NULL; for (i=total-1 ; i >= 0 ; i--) { int k = (i + first) % total; ListAddSeg(&seg_list, array[k]); } // free seg array, unless local if (total > 32) delete[] array; # if DEBUG_SORTER gLog.debugPrintf("Sorted SEGS around (%1.1f,%1.1f)\n", mid_x, mid_y); for (seg=seg_list ; seg ; seg=seg->next) { gLog.debugPrintf(" Seg %p: Angle %1.6f (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", seg, seg->cmp_angle, seg->start->x, seg->start->y, seg->end->x, seg->end->y); } # endif } void subsec_t::SanityCheckClosed() { seg_t *seg, *next; int total=0, gaps=0; for (seg=seg_list ; seg ; seg=seg->next) { next = seg->next ? seg->next : seg_list; if (seg->end->x != next->start->x || seg->end->y != next->start->y) gaps++; total++; } if (gaps > 0) { gLog.debugPrintf("Subsector #%d near (%1.1f,%1.1f) is not closed " "(%d gaps, %d segs)\n", index, mid_x, mid_y, gaps, total); # if DEBUG_SUBSEC for (seg=seg_list ; seg ; seg=seg->next) { gLog.debugPrintf(" SEG %p (%1.1f,%1.1f) --> (%1.1f,%1.1f)\n", seg, seg->start->x, seg->start->y, seg->end->x, seg->end->y); } # endif } } void subsec_t::SanityCheckHasRealSeg() { seg_t *seg; for (seg=seg_list ; seg ; seg=seg->next) if (seg->linedef >= 0) return; BugError("Subsector #%d near (%1.1f,%1.1f) has no real seg!\n", index, mid_x, mid_y); } void subsec_t::RenumberSegs() { seg_t *seg; # if DEBUG_SUBSEC gLog.debugPrintf("Subsec: Renumbering %d\n", index); # endif seg_count = 0; for (seg=seg_list ; seg ; seg=seg->next) { seg->index = current_seg_index; current_seg_index++; seg_count++; # if DEBUG_SUBSEC gLog.debugPrintf("Subsec: %d: Seg %p Index %d\n", seg_count, seg, seg->index); # endif } } // // Create a subsector from a list of segs. // subsec_t *LevelData::CreateSubsector(quadtree_c *tree) { subsec_t *sub = NewSubsec(); // compute subsector's index sub->index = (int)subsecs.size() - 1; // copy segs into subsector // [ assumes seg_list field is NULL ] tree->ConvertToList(&sub->seg_list); sub->DetermineMiddle(); # if DEBUG_SUBSEC gLog.debugPrintf("Subsec: Creating %d\n", sub->index); # endif return sub; } int ComputeBspHeight(node_t *node) { if (node) { int left, right; right = ComputeBspHeight(node->r.node); left = ComputeBspHeight(node->l.node); return std::max(left, right) + 1; } return 1; } #if DEBUG_BUILDER static void DebugShowSegs(seg_t *list) { for ( ; list != NULL ; list = list->next) { seg_t *seg = list; gLog.debugPrintf("Build: %sSEG %p linedef=%d (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n", (seg->linedef >= 0) ? "" : "MINI", seg, seg->linedef, seg->start->x, seg->start->y, seg->end->x, seg->end->y); } } #endif build_result_e LevelData::BuildNodes(seg_t *list, bbox_t *bounds /* output */, node_t ** N, subsec_t ** S, int depth) { *N = NULL; *S = NULL; if (cur_info->cancelled) return BUILD_Cancelled; # if DEBUG_BUILDER gLog.debugPrintf("Build: BEGUN @ %d\n", depth); DebugShowSegs(list); # endif // determine bounds of segs FindLimits2(list, bounds); quadtree_c *tree = TreeFromSegList(list, bounds); /* pick partition line None indicates convexicity */ seg_t *part = PickNode(tree, depth); if (part == NULL) { # if DEBUG_BUILDER gLog.debugPrintf("Build: CONVEX\n"); # endif *S = CreateSubsector(tree); delete tree; if (cur_info->cancelled) return BUILD_Cancelled; return BUILD_OK; } # if DEBUG_BUILDER gLog.debugPrintf("Build: PARTITION %p (%1.0f,%1.0f) -> (%1.0f,%1.0f)\n", part, part->start->x, part->start->y, part->end->x, part->end->y); # endif node_t *node = NewNode(); *N = node; /* divide the segs into two lists: left & right */ seg_t *lefts = NULL; seg_t *rights = NULL; intersection_t *cut_list = NULL; SeparateSegs(tree, part, &lefts, &rights, &cut_list); delete tree; tree = NULL; /* sanity checks... */ if (rights == NULL) BugError("Separated seg-list has empty RIGHT side\n"); if (lefts == NULL) BugError("Separated seg-list has empty LEFT side\n"); AddMinisegs(cut_list, part, &lefts, &rights); node->SetPartition(*this, part); # if DEBUG_BUILDER gLog.debugPrintf("Build: Going LEFT\n"); # endif build_result_e ret; ret = BuildNodes(lefts, &node->l.bounds, &node->l.node, &node->l.subsec, depth+1); if (ret != BUILD_OK) return ret; # if DEBUG_BUILDER gLog.debugPrintf("Build: Going RIGHT\n"); # endif ret = BuildNodes(rights, &node->r.bounds, &node->r.node, &node->r.subsec, depth+1); # if DEBUG_BUILDER gLog.debugPrintf("Build: DONE\n"); # endif return ret; } void LevelData::ClockwiseBspTree() { current_seg_index = 0; for (int i=0 ; i < (int)subsecs.size() ; i++) { subsec_t *sub = subsecs[i]; sub->ClockwiseOrder(doc); sub->RenumberSegs(); // do some sanity checks sub->SanityCheckClosed(); sub->SanityCheckHasRealSeg(); } } void subsec_t::Normalise() { // use head + tail to maintain same order of segs seg_t *new_head = NULL; seg_t *new_tail = NULL; # if DEBUG_SUBSEC gLog.debugPrintf("Subsec: Normalising %d\n", index); # endif while (seg_list) { // remove head seg_t *seg = seg_list; seg_list = seg->next; // only add non-minisegs to new list if (seg->linedef < 0) { # if DEBUG_SUBSEC gLog.debugPrintf("Subsec: Removing miniseg %p\n", seg); # endif // this causes SortSegs() to remove the seg seg->index = SEG_IS_GARBAGE; continue; } // add it to new list seg->next = NULL; if (new_tail) new_tail->next = seg; else new_head = seg; new_tail = seg; // this updated later seg->index = -1; } if (new_head == NULL) BugError("Subsector %d normalised to being EMPTY\n", index); seg_list = new_head; } void LevelData::NormaliseBspTree() const { // unlinks all minisegs from each subsector current_seg_index = 0; for (int i=0 ; i < (int)subsecs.size() ; i++) { subsec_t *sub = subsecs[i]; sub->Normalise(); sub->RenumberSegs(); } } void LevelData::RoundOffVertices() { for (int i = 0 ; i < (int)vertices.size() ; i++) { vertex_t *vert = vertices[i]; if (vert->is_new) { vert->is_new = false; vert->index = num_old_vert; num_old_vert++; } } } void subsec_t::RoundOff(LevelData &lev_data) { // use head + tail to maintain same order of segs seg_t *new_head = NULL; seg_t *new_tail = NULL; seg_t *seg; seg_t *last_real_degen = NULL; int real_total = 0; int degen_total = 0; (void)degen_total; # if DEBUG_SUBSEC gLog.debugPrintf("Subsec: Rounding off %d\n", index); # endif // do an initial pass, just counting the degenerates for (seg=seg_list ; seg ; seg=seg->next) { // is the seg degenerate ? if (iround(seg->start->x) == iround(seg->end->x) && iround(seg->start->y) == iround(seg->end->y)) { seg->is_degenerate = true; if (seg->linedef >= 0) last_real_degen = seg; degen_total++; continue; } if (seg->linedef >= 0) real_total++; } # if DEBUG_SUBSEC gLog.debugPrintf("Subsec: degen=%d real=%d\n", degen_total, real_total); # endif // handle the (hopefully rare) case where all of the real segs // became degenerate. if (real_total == 0) { if (last_real_degen == NULL) BugError("Subsector %d rounded off with NO real segs\n", index); # if DEBUG_SUBSEC gLog.debugPrintf("Degenerate before: (%1.2f,%1.2f) -> (%1.2f,%1.2f)\n", last_real_degen->start->x, last_real_degen->start->y, last_real_degen->end->x, last_real_degen->end->y); # endif // create a new vertex for this baby last_real_degen->end = lev_data.NewVertexDegenerate( last_real_degen->start, last_real_degen->end); # if DEBUG_SUBSEC gLog.debugPrintf("Degenerate after: (%d,%d) -> (%d,%d)\n", iround(last_real_degen->start->x), iround(last_real_degen->start->y), iround(last_real_degen->end->x), iround(last_real_degen->end->y)); # endif last_real_degen->is_degenerate = false; } // second pass, remove the blighters... while (seg_list) { // remove head seg = seg_list; seg_list = seg->next; if (seg->is_degenerate) { # if DEBUG_SUBSEC gLog.debugPrintf("Subsec: Removing degenerate %p\n", seg); # endif // this causes SortSegs() to remove the seg seg->index = SEG_IS_GARBAGE; continue; } // add it to new list seg->next = NULL; if (new_tail) new_tail->next = seg; else new_head = seg; new_tail = seg; // this updated later seg->index = -1; } if (new_head == NULL) BugError("Subsector %d rounded off to being EMPTY\n", index); seg_list = new_head; } void LevelData::RoundOffBspTree() { current_seg_index = 0; RoundOffVertices(); for (int i=0 ; i < (int)subsecs.size() ; i++) { subsec_t *sub = subsecs[i]; sub->RoundOff(*this); sub->RenumberSegs(); } } } // namespace ajbsp //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/bsp_util.cc000066400000000000000000000432711464327712600204670ustar00rootroot00000000000000//------------------------------------------------------------------------ // // AJ-BSP Copyright (C) 2000-2019 Andrew Apted, et al // Copyright (C) 1994-1998 Colin Reed // Copyright (C) 1997-1998 Lee Killough // // Originally based on the program 'BSP', version 2.3. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "bsp.h" #include "Instance.h" struct ConfigData; namespace ajbsp { #define DEBUG_ENABLED 0 #define DEBUG_WALLTIPS 0 #define DEBUG_POLYOBJ 0 #define SYS_MSG_BUFLEN 4000 void PrintDetail(const char *fmt, ...) { (void) fmt; } void LevelData::Failure(EUR_FORMAT_STRING(const char *fmt), ...) { va_list args; va_start(args, fmt); SString message = SString::vprintf(fmt, args); va_end(args); if (cur_info->warnings) PrintMsg("Failure: %s", message.c_str()); cur_info->total_warnings++; #if DEBUG_ENABLED gLog.debugPrintf("Failure: %s", message.c_str()); #endif } void LevelData::PrintMsg(EUR_FORMAT_STRING(const char *format), ...) const { if(reportLog) { va_list ap; va_start(ap, format); reportLog(SString::vprintf(format, ap)); va_end(ap); } } void LevelData::Warning(EUR_FORMAT_STRING(const char *fmt), ...) { va_list args; va_start(args, fmt); SString message = SString::vprintf(fmt, args); va_end(args); if (cur_info->warnings) PrintMsg("Warning: %s", message.c_str()); cur_info->total_warnings++; #if DEBUG_ENABLED gLog.debugPrintf("Warning: %s", message.c_str()); #endif } //------------------------------------------------------------------------ // UTILITY : general purpose functions //------------------------------------------------------------------------ #ifndef WIN32 #include #endif // // Allocate memory with error checking. Zeros the memory. // void *UtilCalloc(int size) { void *ret = calloc(1, size); if (!ret) throw std::bad_alloc(); return ret; } // // Reallocate memory with error checking. // void *UtilRealloc(void *old, int size) { void *ret = realloc(old, size); if (!ret) throw std::bad_alloc(); return ret; } // // Free the memory with error checking. // void UtilFree(void *data) { if (data == NULL) BugError("Trying to free a NULL pointer\n"); free(data); } // // Translate (dx, dy) into an angle value (degrees) // angle_g UtilComputeAngle(double dx, double dy) { double angle; if (dx == 0) return (dy > 0) ? 90.0 : 270.0; angle = atan2(dy, dx) * 180.0 / M_PI; if (angle < 0) angle += 360.0; return angle; } SString UtilTimeString(void) { #ifdef WIN32 SYSTEMTIME sys_time; GetSystemTime(&sys_time); return SString::printf("%04d-%02d-%02d %02d:%02d:%02d.%04d", sys_time.wYear, sys_time.wMonth, sys_time.wDay, sys_time.wHour, sys_time.wMinute, sys_time.wSecond, sys_time.wMilliseconds * 10); #else // LINUX or MACOSX time_t epoch_time; struct tm *calend_time; if (time(&epoch_time) == (time_t)-1) return NULL; calend_time = localtime(&epoch_time); if (! calend_time) return NULL; return SString::printf("%04d-%02d-%02d %02d:%02d:%02d.%04d", calend_time->tm_year + 1900, calend_time->tm_mon + 1, calend_time->tm_mday, calend_time->tm_hour, calend_time->tm_min, calend_time->tm_sec, 0); #endif } //------------------------------------------------------------------------ // Adler-32 CHECKSUM Code //------------------------------------------------------------------------ void Adler32_Begin(uint32_t *crc) { *crc = 1; } void Adler32_AddBlock(uint32_t *crc, const uint8_t *data, int length) { uint32_t s1 = (*crc) & 0xFFFF; uint32_t s2 = ((*crc) >> 16) & 0xFFFF; for ( ; length > 0 ; data++, length--) { s1 = (s1 + *data) % 65521; s2 = (s2 + s1) % 65521; } *crc = (s2 << 16) | s1; } void Adler32_Finish(uint32_t *crc) { /* nothing to do */ } //------------------------------------------------------------------------ // ANALYZE : Analyzing level structures //------------------------------------------------------------------------ #define POLY_BOX_SZ 10 /* ----- polyobj handling ----------------------------- */ static void MarkPolyobjSector(int sector, const Document &doc) { int i; if (! doc.isSector(sector)) return; # if DEBUG_POLYOBJ gLog.debugPrintf(" Marking SECTOR %d\n", sector); # endif for (i = 0 ; i < doc.numLinedefs(); i++) { auto L = doc.linedefs[i]; if ((L->right >= 0 && doc.getRight(*L)->sector == sector) || (L->left >= 0 && doc.getLeft(*L)->sector == sector)) { L->flags |= MLF_IS_PRECIOUS; } } } void LevelData::MarkPolyobjPoint(double x, double y) { int i; int inside_count = 0; double best_dist = 999999; int best_match = -1; int sector = -1; double x1, y1; double x2, y2; double EPSILON = 0.01; // -AJA- First we handle the "awkward" cases where the polyobj sits // directly on a linedef or even a vertex. We check all lines // that intersect a small box around the spawn point. int bminx = (int) (x - POLY_BOX_SZ); int bminy = (int) (y - POLY_BOX_SZ); int bmaxx = (int) (x + POLY_BOX_SZ); int bmaxy = (int) (y + POLY_BOX_SZ); for (i = 0 ; i < doc.numLinedefs(); i++) { const auto L = doc.linedefs[i]; if (CheckLinedefInsideBox(bminx, bminy, bmaxx, bmaxy, (int) doc.getStart(*L).x(), (int) doc.getStart(*L).y(), (int) doc.getEnd(*L).x(), (int) doc.getEnd(*L).y())) { # if DEBUG_POLYOBJ gLog.debugPrintf(" Touching line was %d\n", L->index); # endif if (L->left >= 0) MarkPolyobjSector(doc.getLeft(*L)->sector, doc); if (L->right >= 0) MarkPolyobjSector(doc.getRight(*L)->sector, doc); inside_count++; } } if (inside_count > 0) return; // -AJA- Algorithm is just like in DEU: we cast a line horizontally // from the given (x,y) position and find all linedefs that // intersect it, choosing the one with the closest distance. // If the point is sitting directly on a (two-sided) line, // then we mark the sectors on both sides. for (i = 0 ; i < doc.numLinedefs(); i++) { const auto L = doc.linedefs[i]; double x_cut; x1 = doc.getStart(*L).x(); y1 = doc.getStart(*L).y(); x2 = doc.getEnd(*L).x(); y2 = doc.getEnd(*L).y(); /* check vertical range */ if (fabs(y2 - y1) < EPSILON) continue; if ((y > (y1 + EPSILON) && y > (y2 + EPSILON)) || (y < (y1 - EPSILON) && y < (y2 - EPSILON))) continue; x_cut = x1 + (x2 - x1) * (y - y1) / (y2 - y1) - x; if (fabs(x_cut) < fabs(best_dist)) { /* found a closer linedef */ best_match = i; best_dist = x_cut; } } if (best_match < 0) { Warning("Bad polyobj thing at (%1.0f,%1.0f).\n", x, y); return; } const auto best_ld = doc.linedefs[best_match]; y1 = doc.getStart(*best_ld).y(); y2 = doc.getEnd(*best_ld).y(); # if DEBUG_POLYOBJ gLog.debugPrintf(" Closest line was %d Y=%1.0f..%1.0f (dist=%1.1f)\n", best_match, y1, y2, best_dist); # endif /* sanity check: shouldn't be directly on the line */ # if DEBUG_POLYOBJ if (fabs(best_dist) < EPSILON) { gLog.debugPrintf(" Polyobj FAILURE: directly on the line (%d)\n", best_match); } # endif /* check orientation of line, to determine which side the polyobj is * actually on. */ if ((y1 > y2) == (best_dist > 0)) sector = (best_ld->right >= 0) ? doc.getRight(*best_ld)->sector : -1; else sector = (best_ld->left >= 0) ? doc.getLeft(*best_ld)->sector : -1; # if DEBUG_POLYOBJ gLog.debugPrintf(" Sector %d contains the polyobj.\n", sector); # endif if (sector < 0) { Warning("Invalid Polyobj thing at (%1.0f,%1.0f).\n", x, y); return; } MarkPolyobjSector(sector, doc); } // // Based on code courtesy of Janis Legzdinsh. // void LevelData::DetectPolyobjSectors() { int i; // -JL- There's a conflict between Hexen polyobj thing types and Doom thing // types. In Doom type 3001 is for Imp and 3002 for Demon. To solve // this problem, first we are going through all lines to see if the // level has any polyobjs. If found, we also must detect what polyobj // thing types are used - Hexen ones or ZDoom ones. That's why we // are going through all things searching for ZDoom polyobj thing // types. If any found, we assume that ZDoom polyobj thing types are // used, otherwise Hexen polyobj thing types are used. // -JL- First go through all lines to see if level contains any polyobjs for (i = 0 ; i < doc.numLinedefs(); i++) { const auto L = doc.linedefs[i]; const linetype_t *type = get(config.line_types, L->type); if(type && type->isPolyObjectSpecial()) break; } if (i == doc.numLinedefs()) { // -JL- No polyobjs in this level return; } # if DEBUG_POLYOBJ gLog.debugPrintf("Using %s style polyobj things\n", hexen_style ? "HEXEN" : "ZDOOM"); # endif for (i = 0 ; i < doc.numThings(); i++) { const auto T = doc.things[i]; double x = T->x(); double y = T->y(); // ignore everything except polyobj start spots const thingtype_t *type = get(config.thing_types, T->type); if(!type || !(type->flags & THINGDEF_POLYSPOT)) continue; # if DEBUG_POLYOBJ gLog.debugPrintf("Thing %d at (%1.0f,%1.0f) is a polyobj spawner.\n", i, x, y); # endif MarkPolyobjPoint(x, y); } } /* ----- analysis routines ----------------------------- */ static FFixedPoint VertexCompare(const Document &doc, const void *p1, const void *p2) { int vert1 = static_cast(p1)[0]; int vert2 = static_cast(p2)[0]; if (vert1 == vert2) return FFixedPoint{}; const auto A = doc.vertices[vert1]; const auto B = doc.vertices[vert2]; if (A->raw_x != B->raw_x) return A->raw_x - B->raw_x; return A->raw_y - B->raw_y; } void LevelData::DetectOverlappingVertices() const { SYS_ASSERT((int)vertices.size() == doc.numVertices()); uint16_t *array = new uint16_t[(int)vertices.size()]; // sort array of indices int i; for (i=0 ; i < (int)vertices.size() ; i++) array[i] = static_cast(i); std::sort(array, array + (int)vertices.size(), [this](uint16_t left, uint16_t right) { return VertexCompare(doc, &left, &right).raw() < 0; }); // now mark them off for (i=0 ; i < (int)vertices.size() - 1 ; i++) { if (VertexCompare(doc, array + i, array + i + 1).raw() == 0) { // found an overlap! vertex_t *A = vertices[array[i]]; vertex_t *B = vertices[array[i+1]]; B->overlap = A->overlap ? A->overlap : A; } } delete[] array; } static inline int LineVertexLowest(const Document &doc, const LineDef *L) { // returns the "lowest" vertex (normally the left-most, but if the // line is vertical, then the bottom-most) => 0 for start, 1 for end. return ( doc.getStart(*L).raw_x < doc.getEnd(*L).raw_x || (doc.getStart(*L).raw_x == doc.getEnd(*L).raw_x && doc.getStart(*L).raw_y < doc.getEnd(*L).raw_y)) ? 0 : 1; } static FFixedPoint LineStartCompare(const Document &doc, const void *p1, const void *p2) { int line1 = ((const int *) p1)[0]; int line2 = ((const int *) p2)[0]; if (line1 == line2) return FFixedPoint(); const auto A = doc.linedefs[line1]; const auto B = doc.linedefs[line2]; // determine left-most vertex of each line const Vertex *C = LineVertexLowest(doc, A.get()) ? &doc.getEnd(*A) : &doc.getStart(*A); const Vertex *D = LineVertexLowest(doc, B.get()) ? &doc.getEnd(*B) : &doc.getStart(*B); if (C->raw_x != D->raw_x) return C->raw_x - D->raw_x; return C->raw_y - D->raw_y; } static FFixedPoint LineEndCompare(const Document &doc, const void *p1, const void *p2) { int line1 = ((const int *) p1)[0]; int line2 = ((const int *) p2)[0]; if (line1 == line2) return FFixedPoint{}; const auto A = doc.linedefs[line1]; const auto B = doc.linedefs[line2]; // determine right-most vertex of each line const Vertex * C = LineVertexLowest(doc, A.get()) ? &doc.getStart(*A) : &doc.getEnd(*A); const Vertex * D = LineVertexLowest(doc, B.get()) ? &doc.getStart(*B) : &doc.getEnd(*B); if (C->raw_x != D->raw_x) return C->raw_x - D->raw_x; return C->raw_y - D->raw_y; } void DetectOverlappingLines(const Document &doc) { // Algorithm: // Sort all lines by left-most vertex. // Overlapping lines will then be near each other in this set. // Note: does not detect partially overlapping lines. int i; int *array = (int *)UtilCalloc(doc.numLinedefs() * sizeof(int)); int count = 0; // sort array of indices for (i=0 ; i < doc.numLinedefs(); i++) array[i] = i; std::sort(array, array + doc.numLinedefs(), [&doc](int left, int right) { return LineStartCompare(doc, &left, &right).raw() < 0; }); for (i=0 ; i < doc.numLinedefs() - 1 ; i++) { int j; for (j = i+1 ; j < doc.numLinedefs(); j++) { if (LineStartCompare(doc, array + i, array + j).raw() != 0) break; if (LineEndCompare(doc, array + i, array + j).raw() == 0) { // found an overlap ! auto L = doc.linedefs[array[j]]; L->flags |= MLF_IS_OVERLAP; count++; } } } if (count > 0) { PrintDetail("Detected %d overlapped linedefs\n", count); } UtilFree(array); } /* ----- vertex routines ------------------------------- */ // smallest degrees between two angles before being considered equal #define ANG_EPSILON (1.0 / 1024.0) void LevelData::VertexAddWallTip(vertex_t *vert, double dx, double dy, int open_left, int open_right) { if (vert->overlap) vert = vert->overlap; walltip_t *tip = NewWallTip(); walltip_t *after; tip->angle = UtilComputeAngle(dx, dy); tip->open_left = open_left; tip->open_right = open_right; // find the correct place (order is increasing angle) for (after=vert->tip_set ; after && after->next ; after=after->next) { } while (after && tip->angle + ANG_EPSILON < after->angle) after = after->prev; // link it in tip->next = after ? after->next : vert->tip_set; tip->prev = after; if (after) { if (after->next) after->next->prev = tip; after->next = tip; } else { if (vert->tip_set) vert->tip_set->prev = tip; vert->tip_set = tip; } } void LevelData::CalculateWallTips() { int i; for (i=0 ; i < doc.numLinedefs(); i++) { const auto L = doc.linedefs[i]; if ((L->flags & MLF_IS_OVERLAP) || doc.isZeroLength(*L)) continue; double x1 = doc.getStart(*L).x(); double y1 = doc.getStart(*L).y(); double x2 = doc.getEnd(*L).x(); double y2 = doc.getEnd(*L).y(); bool left = (L->left >= 0) && doc.isSector(doc.getLeft(*L)->sector); bool right = (L->right >= 0) && doc.isSector(doc.getRight(*L)->sector); VertexAddWallTip(vertices[L->start], x2-x1, y2-y1, left, right); VertexAddWallTip(vertices[L->end], x1-x2, y1-y2, right, left); } # if DEBUG_WALLTIPS for (i=0 ; i < num_vertices ; i++) { vertex_t *V = lev_vertices[i]; gLog.debugPrintf("WallTips for vertex %d:\n", i); for (walltip_t *tip = V->tip_set ; tip ; tip = tip->next) { gLog.debugPrintf(" Angle=%1.1f left=%d right=%d\n", tip->angle, tip->open_left ? 1 : 0, tip->open_right ? 1 : 0); } } # endif } vertex_t *LevelData::NewVertexFromSplitSeg(seg_t *seg, double x, double y) { vertex_t *vert = NewVertex(); vert->x = x; vert->y = y; vert->is_new = true; vert->index = num_new_vert; num_new_vert++; // compute wall-tip info if (seg->linedef < 0 || doc.linedefs[seg->linedef]->TwoSided()) { VertexAddWallTip(vert, -seg->pdx, -seg->pdy, true, true); VertexAddWallTip(vert, seg->pdx, seg->pdy, true, true); } else { const auto L = doc.linedefs[seg->linedef]; bool front_open = ((seg->side ? L->left : L->right) >= 0); VertexAddWallTip(vert, -seg->pdx, -seg->pdy, front_open, !front_open); VertexAddWallTip(vert, seg->pdx, seg->pdy, !front_open, front_open); } return vert; } vertex_t *LevelData::NewVertexDegenerate(vertex_t *start, vertex_t *end) { // this is only called when rounding off the BSP tree and // all the segs are degenerate (zero length), hence we need // to create at least one seg which won't be zero length. double dx = end->x - start->x; double dy = end->y - start->y; double dlen = hypot(dx, dy); vertex_t *vert = NewVertex(); vert->is_new = false; vert->index = num_old_vert; num_old_vert++; // compute new coordinates vert->x = start->x; vert->y = start->x; if (dlen == 0) BugError("NewVertexDegenerate: bad delta!\n"); dx /= dlen; dy /= dlen; while (iround(vert->x) == iround(start->x) && iround(vert->y) == iround(start->y)) { vert->x += dx; vert->y += dy; } return vert; } bool VertexCheckOpen(vertex_t *vert, double dx, double dy) { if (vert->overlap) vert = vert->overlap; walltip_t *tip; angle_g angle = UtilComputeAngle(dx, dy); // first check whether there's a wall-tip that lies in the exact // direction of the given direction (which is relative to the // vertex). for (tip=vert->tip_set ; tip ; tip=tip->next) { if (fabs(tip->angle - angle) < ANG_EPSILON || fabs(tip->angle - angle) > (360.0 - ANG_EPSILON)) { // found one, hence closed return false; } } // OK, now just find the first wall-tip whose angle is greater than // the angle we're interested in. Therefore we'll be on the RIGHT // side of that wall-tip. for (tip=vert->tip_set ; tip ; tip=tip->next) { if (angle + ANG_EPSILON < tip->angle) { // found it return tip->open_right; } if (! tip->next) { // no more tips, thus we must be on the LEFT side of the tip // with the largest angle. return tip->open_left; } } // usually won't get here return true; } } // namespace ajbsp //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/dehconsts.h000066400000000000000000000540061464327712600205000ustar00rootroot00000000000000//------------------------------------------------------------------------ // DEHACKED //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ // THANKS TO Isaac Colón (https://github.com/iccolon818) for this contribution, and compiling all // these data lists, as based on the data from the DOOM executable. I did reformatting. #ifndef __EUREKA_DEHCONSTS_H__ #define __EUREKA_DEHCONSTS_H__ #include "m_strings.h" #include "w_dehacked.h" namespace dehacked { static const int THING_NUM_TO_TYPE[] = { -1, -1, 3004, 9, 64, -1, 66, -1, -1, 67, -1, 65, 3001, 3002, 58, 3005, 3003, -1, 69, 3006, 7, 68, 16, 71, 84, 72, 88, 89, 87, -1, -1, 2035, // 32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 14, -1, 2018, 2019, 2014, 2015, 5, 13, 6, 39, 38, 40, 2011, 2012, 2013, 2022, 2023, 2024, 2025, 2026, 2045, 83, // 64 2007, 2048, 2010, 2046, 2047, 17, 2008, 2049, 8, 2006, 2002, 2005, 2003, 2004, 2001, 82, 85, 86, 2028, 30, 31, 32, 33, 37, 36, 41, 42, 43, 44, 45, 46, 55, // 96 56, 57, 47, 48, 34, 35, 49, 50, 51, 52, 53, 59, 60, 61, 62, 63, 22, 15, 18, 21, 23, 20, 19, 10, 12, 28, 24, 27, 29, 25, 26, 54, // 128 70, 73, 74, 75, 76, 77, 78, 79, // 136 80, 81, 5001, 5002, 888, -1, -1, 2016, // 144 2017 // 145 }; static const int THING_NUM_TO_SPRITE[] = { 0, 149, 174, 207, 241, 281, 321, 316, // 8 311, 362, 357, 406, 442, 475, 475, 502, // 16 527, 522, 556, 585, 601, 632, 674, 701, // 24 726, 763, 778, 784, 0, 787, 791, 806, // 32 97, 102, 114, 107, 115, 667, 93, 90, // 40 130, 142, 0, 123, 802, 804, 816, 822, // 48 828, 830, 832, 838, 836, 834, 840, 841, // 56 842, 848, 852, 853, 861, 862, 868, 857, // 64 870, 871, 872, 873, 874, 875, 876, 877, // 72 878, 879, 880, 881, 882, 883, 884, 885, // 80 959, 963, 886, 907, 908, 909, 910, 913, // 88 924, 917, 921, 914, 926, 930, 934, 938, // 96 942, 946, 906, 916, 911, 912, 888, 902, // 104 903, 904, 905, 902, 904, 903, 905, 888, // 112 515, 164, 193, 495, 600, 461, 226, 173, // 120 173, 894, 895, 896, 897, 899, 900, 915, // 128 813, 950, 951, 952, 953, 954, 955, 956, // 136 957, 958, 967, 967, 972, 1042, 1049, 1054, // 144 1055 // 145 }; static const frame_t FRAMES[] = { {0, 0, false}, {1, 4, false}, {2, 0, false}, {2, 0, false}, {2, 0, false}, {2, 1, false}, {2, 2, false}, {2, 3, false}, {2, 2, false}, {2, 1, false}, {3, 0, false}, {3, 0, false}, {3, 0, false}, {3, 0, false}, {3, 1, false}, {3, 2, false}, {3, 1, false}, {4, 0, true}, {1, 0, false}, {1, 0, false}, {1, 0, false}, {1, 0, false}, {1, 0, false}, {1, 1, false}, {1, 2, false}, {1, 3, false}, {1, 2, false}, {1, 1, false}, {1, 0, false}, {1, 0, false}, // 30 {5, 0, true}, {5, 1, true}, {6, 0, false}, {6, 0, false}, {6, 0, false}, {6, 0, false}, {6, 0, false}, {6, 1, false}, {6, 2, false}, {6, 3, false}, {6, 4, false}, {6, 5, false}, {6, 6, false}, {6, 7, false}, {6, 0, false}, {6, 1, false}, {6, 0, false}, {6, 8, true}, {6, 9, true}, {7, 0, false}, {7, 0, false}, {7, 0, false}, {7, 0, false}, {7, 1, false}, {7, 1, false}, {8, 0, true}, {8, 1, true}, {9, 0, false}, {9, 0, false}, {9, 0, false}, // 60 {9, 1, false}, {9, 1, false}, {9, 1, false}, {10, 0, true}, {10, 1, true}, {10, 2, true}, {10, 3, true}, {11, 2, false}, {11, 3, false}, {11, 2, false}, {11, 2, false}, {11, 0, false}, {11, 1, false}, {11, 1, false}, {12, 0, false}, {12, 0, false}, {12, 0, false}, {12, 0, false}, {12, 1, false}, {13, 0, true}, {13, 1, true}, {14, 0, false}, {14, 0, false}, {14, 0, false}, {14, 0, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {15, 0, true}, {15, 1, true}, // 90 {16, 2, false}, {16, 1, false}, {16, 0, false}, {17, 0, true}, {17, 1, false}, {17, 2, false}, {17, 3, false}, {18, 0, true}, {18, 1, true}, {18, 2, true}, {18, 3, true}, {18, 4, true}, {19, 0, true}, {19, 1, true}, {19, 2, true}, {19, 3, true}, {19, 4, true}, {20, 0, true}, {20, 1, true}, {21, 0, true}, {21, 1, true}, {21, 2, true}, {21, 3, true}, {21, 4, true}, {22, 0, true}, {23, 0, true}, {23, 1, true}, {24, 0, true}, {24, 1, true}, {24, 2, true}, // 120 {24, 3, true}, {24, 4, true}, {24, 5, true}, {25, 0, true}, {25, 1, true}, {25, 2, true}, {25, 3, true}, {22, 1, true}, {22, 2, true}, {22, 3, true}, {26, 0, true}, {26, 1, true}, {26, 0, true}, {26, 1, true}, {26, 2, true}, {26, 3, true}, {26, 4, true}, {26, 5, true}, {26, 6, true}, {26, 7, true}, {26, 8, true}, {26, 9, true}, {27, 0, true}, {27, 1, true}, {27, 0, true}, {27, 1, true}, {27, 2, true}, {27, 3, true}, {27, 4, true}, {28, 0, false}, // 150 {28, 0, false}, {28, 1, false}, {28, 2, false}, {28, 3, false}, {28, 4, false}, {28, 5, true}, {28, 6, false}, {28, 6, false}, {28, 7, false}, {28, 8, false}, {28, 9, false}, {28, 10, false}, {28, 11, false}, {28, 12, false}, {28, 13, false}, {28, 14, false}, {28, 15, false}, {28, 16, false}, {28, 17, false}, {28, 18, false}, {28, 19, false}, {28, 20, false}, {28, 21, false}, {28, 22, false}, {29, 0, false}, {29, 1, false}, {29, 0, false}, {29, 0, false}, {29, 1, false}, {29, 1, false}, // 180 {29, 2, false}, {29, 2, false}, {29, 3, false}, {29, 3, false}, {29, 4, false}, {29, 5, false}, {29, 4, false}, {29, 6, false}, {29, 6, false}, {29, 7, false}, {29, 8, false}, {29, 9, false}, {29, 10, false}, {29, 11, false}, {29, 12, false}, {29, 13, false}, {29, 14, false}, {29, 15, false}, {29, 16, false}, {29, 17, false}, {29, 18, false}, {29, 19, false}, {29, 20, false}, {29, 10, false}, {29, 9, false}, {29, 8, false}, {29, 7, false}, {30, 0, false}, {30, 1, false}, {30, 0, false}, // 210 {30, 0, false}, {30, 1, false}, {30, 1, false}, {30, 2, false}, {30, 2, false}, {30, 3, false}, {30, 3, false}, {30, 4, false}, {30, 5, true}, {30, 4, false}, {30, 6, false}, {30, 6, false}, {30, 7, false}, {30, 8, false}, {30, 9, false}, {30, 10, false}, {30, 11, false}, {30, 12, false}, {30, 13, false}, {30, 14, false}, {30, 15, false}, {30, 16, false}, {30, 17, false}, {30, 18, false}, {30, 19, false}, {30, 20, false}, {30, 11, false}, {30, 10, false}, {30, 9, false}, {30, 8, false}, // 240 {30, 7, false}, {31, 0, false}, {31, 1, false}, {31, 0, false}, {31, 0, false}, {31, 1, false}, {31, 1, false}, {31, 2, false}, {31, 2, false}, {31, 3, false}, {31, 3, false}, {31, 4, false}, {31, 4, false}, {31, 5, false}, {31, 5, false}, {31, 6, true}, {31, 6, true}, {31, 7, true}, {31, 8, true}, {31, 9, true}, {31, 10, true}, {31, 11, true}, {31, 12, true}, {31, 13, true}, {31, 14, true}, {31, 15, true}, {31, 26, true}, {31, 27, true}, {31, 28, true}, {31, 16, false}, // 270 {31, 16, false}, {31, 16, false}, {31, 17, false}, {31, 18, false}, {31, 19, false}, {31, 20, false}, {31, 21, false}, {31, 22, false}, {31, 23, false}, {31, 24, false}, {31, 25, false}, {32, 0, true}, {32, 1, true}, {32, 0, true}, {32, 1, true}, {32, 2, true}, {32, 1, true}, {32, 2, true}, {32, 1, true}, {32, 2, true}, {32, 3, true}, {32, 2, true}, {32, 3, true}, {32, 2, true}, {32, 3, true}, {32, 4, true}, {32, 3, true}, {32, 4, true}, {32, 3, true}, {32, 4, true}, // 300 {32, 5, true}, {32, 4, true}, {32, 5, true}, {32, 4, true}, {32, 5, true}, {32, 6, true}, {32, 7, true}, {32, 6, true}, {32, 7, true}, {32, 6, true}, {32, 7, true}, {17, 1, false}, {17, 2, false}, {17, 1, false}, {17, 2, false}, {17, 3, false}, {33, 0, true}, {33, 1, true}, {34, 0, true}, {34, 1, true}, {34, 2, true}, {35, 0, false}, {35, 1, false}, {35, 0, false}, {35, 0, false}, {35, 1, false}, {35, 1, false}, {35, 2, false}, {35, 2, false}, {35, 3, false}, // 330 {35, 3, false}, {35, 4, false}, {35, 4, false}, {35, 5, false}, {35, 5, false}, {35, 6, false}, {35, 6, false}, {35, 7, false}, {35, 8, false}, {35, 9, true}, {35, 9, true}, {35, 10, false}, {35, 10, false}, {35, 11, false}, {35, 11, false}, {35, 11, false}, {35, 12, false}, {35, 13, false}, {35, 14, false}, {35, 15, false}, {35, 16, false}, {35, 16, false}, {35, 15, false}, {35, 14, false}, {35, 13, false}, {35, 12, false}, {35, 11, false}, {36, 0, true}, {36, 1, true}, {22, 1, true}, // 360 {22, 2, true}, {22, 3, true}, {37, 0, false}, {37, 1, false}, {37, 0, false}, {37, 0, false}, {37, 1, false}, {37, 1, false}, {37, 2, false}, {37, 2, false}, {37, 3, false}, {37, 3, false}, {37, 4, false}, {37, 4, false}, {37, 5, false}, {37, 5, false}, {37, 6, false}, {37, 7, true}, {37, 8, false}, {37, 6, false}, {37, 7, true}, {37, 8, false}, {37, 6, false}, {37, 7, true}, {37, 8, false}, {37, 6, false}, {37, 9, false}, {37, 9, false}, {37, 10, false}, {37, 11, false}, // 390 {37, 12, false}, {37, 13, false}, {37, 14, false}, {37, 15, false}, {37, 16, false}, {37, 17, false}, {37, 18, false}, {37, 19, false}, {37, 17, false}, {37, 16, false}, {37, 15, false}, {37, 14, false}, {37, 13, false}, {37, 12, false}, {37, 11, false}, {37, 10, false}, {38, 0, false}, {38, 1, false}, {38, 0, false}, {38, 0, false}, {38, 1, false}, {38, 1, false}, {38, 2, false}, {38, 2, false}, {38, 3, false}, {38, 3, false}, {38, 4, false}, {38, 5, true}, {38, 4, true}, {38, 5, false}, // 420 {38, 6, false}, {38, 6, false}, {38, 7, false}, {38, 8, false}, {38, 9, false}, {38, 10, false}, {38, 11, false}, {38, 12, false}, {38, 13, false}, {38, 14, false}, {38, 15, false}, {38, 16, false}, {38, 17, false}, {38, 18, false}, {38, 19, false}, {38, 13, false}, {38, 12, false}, {38, 11, false}, {38, 10, false}, {38, 9, false}, {38, 8, false}, {38, 7, false}, {0, 0, false}, {0, 1, false}, {0, 0, false}, {0, 0, false}, {0, 1, false}, {0, 1, false}, {0, 2, false}, {0, 2, false}, // 450 {0, 3, false}, {0, 3, false}, {0, 4, false}, {0, 5, false}, {0, 6, false}, {0, 7, false}, {0, 7, false}, {0, 8, false}, {0, 9, false}, {0, 10, false}, {0, 11, false}, {0, 12, false}, {0, 13, false}, {0, 14, false}, {0, 15, false}, {0, 16, false}, {0, 17, false}, {0, 18, false}, {0, 19, false}, {0, 20, false}, {0, 12, false}, {0, 11, false}, {0, 10, false}, {0, 9, false}, {0, 8, false}, {39, 0, false}, {39, 1, false}, {39, 0, false}, {39, 0, false}, {39, 1, false}, // 480 {39, 1, false}, {39, 2, false}, {39, 2, false}, {39, 3, false}, {39, 3, false}, {39, 4, false}, {39, 5, false}, {39, 6, false}, {39, 7, false}, {39, 7, false}, {39, 8, false}, {39, 9, false}, {39, 10, false}, {39, 11, false}, {39, 12, false}, {39, 13, false}, {39, 13, false}, {39, 12, false}, {39, 11, false}, {39, 10, false}, {39, 9, false}, {39, 8, false}, {40, 0, false}, {40, 0, false}, {40, 1, false}, {40, 2, false}, {40, 3, true}, {40, 4, false}, {40, 4, false}, {40, 5, false}, // 510 {40, 6, false}, {40, 7, false}, {40, 8, false}, {40, 9, false}, {40, 10, false}, {40, 11, false}, {40, 11, false}, {40, 10, false}, {40, 9, false}, {40, 8, false}, {40, 7, false}, {40, 6, false}, {41, 0, true}, {41, 1, true}, {41, 2, true}, {41, 3, true}, {41, 4, true}, {42, 0, false}, {42, 1, false}, {42, 0, false}, {42, 0, false}, {42, 1, false}, {42, 1, false}, {42, 2, false}, {42, 2, false}, {42, 3, false}, {42, 3, false}, {42, 4, false}, {42, 5, false}, {42, 6, false}, // 540 {42, 7, false}, {42, 7, false}, {42, 8, false}, {42, 9, false}, {42, 10, false}, {42, 11, false}, {42, 12, false}, {42, 13, false}, {42, 14, false}, {42, 14, false}, {42, 13, false}, {42, 12, false}, {42, 11, false}, {42, 10, false}, {42, 9, false}, {42, 8, false}, {43, 0, false}, {43, 1, false}, {43, 0, false}, {43, 0, false}, {43, 1, false}, {43, 1, false}, {43, 2, false}, {43, 2, false}, {43, 3, false}, {43, 3, false}, {43, 4, false}, {43, 5, false}, {43, 6, false}, {43, 7, false}, // 570 {43, 7, false}, {43, 8, false}, {43, 9, false}, {43, 10, false}, {43, 11, false}, {43, 12, false}, {43, 13, false}, {43, 14, false}, {43, 14, false}, {43, 13, false}, {43, 12, false}, {43, 11, false}, {43, 10, false}, {43, 9, false}, {43, 8, false}, {44, 0, true}, {44, 1, true}, {44, 0, true}, {44, 1, true}, {44, 2, true}, {44, 3, true}, {44, 2, true}, {44, 3, true}, {44, 4, true}, {44, 4, true}, {44, 5, true}, {44, 6, true}, {44, 7, true}, {44, 8, true}, {44, 9, false}, // 600 {44, 10, false}, {45, 0, false}, {45, 1, false}, {45, 0, false}, {45, 0, false}, {45, 1, false}, {45, 1, false}, {45, 2, false}, {45, 2, false}, {45, 3, false}, {45, 3, false}, {45, 4, false}, {45, 4, false}, {45, 5, false}, {45, 5, false}, {45, 0, true}, {45, 6, true}, {45, 7, true}, {45, 7, true}, {45, 8, false}, {45, 8, false}, {45, 9, false}, {45, 10, false}, {45, 11, false}, {45, 12, false}, {45, 13, false}, {45, 14, false}, {45, 15, false}, {45, 16, false}, {45, 17, false}, // 630 {45, 18, false}, {45, 18, false}, {46, 0, false}, {46, 1, false}, {46, 0, false}, {46, 0, false}, {46, 0, false}, {46, 1, false}, {46, 1, false}, {46, 2, false}, {46, 2, false}, {46, 3, false}, {46, 3, false}, {46, 4, false}, {46, 4, false}, {46, 5, false}, {46, 5, false}, {46, 0, true}, {46, 6, true}, {46, 7, true}, {46, 7, true}, {46, 8, false}, {46, 8, false}, {46, 9, false}, {46, 10, false}, {46, 11, false}, {46, 12, false}, {46, 13, false}, {46, 14, false}, {46, 15, false}, // 660 {46, 15, false}, {46, 14, false}, {46, 13, false}, {46, 12, false}, {46, 11, false}, {46, 10, false}, {46, 9, false}, {47, 0, true}, {47, 1, true}, {48, 0, true}, {48, 1, true}, {48, 2, true}, {48, 3, true}, {48, 4, true}, {49, 0, false}, {49, 1, false}, {49, 0, false}, {49, 0, false}, {49, 1, false}, {49, 1, false}, {49, 2, false}, {49, 2, false}, {49, 3, false}, {49, 3, false}, {49, 4, false}, {49, 5, false}, {49, 4, false}, {49, 5, false}, {49, 4, false}, {49, 5, false}, // 690 {49, 6, false}, {49, 7, false}, {49, 8, false}, {49, 9, false}, {49, 10, false}, {49, 11, false}, {49, 12, false}, {49, 13, false}, {49, 14, false}, {49, 15, false}, {49, 15, false}, {50, 0, false}, {50, 0, false}, {50, 0, false}, {50, 1, false}, {50, 1, false}, {50, 2, false}, {50, 2, false}, {50, 3, false}, {50, 4, false}, {50, 5, true}, {50, 5, true}, {50, 6, false}, {50, 6, false}, {50, 7, true}, {50, 8, true}, {50, 9, true}, {50, 10, true}, {50, 11, true}, {50, 12, true}, // 720 {50, 12, false}, {50, 11, false}, {50, 10, false}, {50, 9, false}, {50, 8, false}, {50, 7, false}, {51, 0, false}, {51, 1, false}, {51, 0, false}, {51, 0, false}, {51, 1, false}, {51, 1, false}, {51, 2, false}, {51, 2, false}, {51, 3, false}, {51, 3, false}, {51, 4, false}, {51, 5, false}, {51, 6, true}, {51, 5, false}, {51, 6, true}, {51, 5, false}, {51, 7, false}, {51, 7, false}, {51, 8, false}, {51, 9, false}, {51, 10, false}, {51, 11, false}, {51, 12, false}, {51, 13, false}, // 750 {51, 14, false}, {51, 15, false}, {51, 16, false}, {51, 17, false}, {51, 18, false}, {51, 19, false}, {51, 20, false}, {51, 21, false}, {51, 12, false}, {51, 11, false}, {51, 10, false}, {51, 9, false}, {51, 8, false}, {52, 0, false}, {52, 0, false}, {52, 1, false}, {52, 2, false}, {52, 3, false}, {52, 4, false}, {52, 5, false}, {52, 6, false}, {52, 7, false}, {52, 8, false}, {52, 9, false}, {52, 10, false}, {52, 11, false}, {52, 12, false}, {52, 12, false}, {53, 0, false}, {53, 1, false}, // 780 {53, 0, false}, {53, 0, false}, {53, 0, false}, {53, 0, false}, {51, 0, false}, {51, 0, false}, {51, 0, false}, {54, 0, true}, {54, 1, true}, {54, 2, true}, {54, 3, true}, {32, 0, true}, {32, 1, true}, {32, 2, true}, {32, 3, true}, {32, 4, true}, {32, 5, true}, {32, 6, true}, {32, 7, true}, {22, 1, true}, {22, 2, true}, {22, 3, true}, {55, 0, false}, {55, 1, true}, {56, 0, false}, {56, 1, true}, {57, 0, false}, {57, 1, false}, {58, 0, true}, {58, 1, true}, // 810 {58, 2, true}, {58, 3, true}, {58, 4, true}, {59, 0, true}, {59, 1, true}, {59, 2, true}, {60, 0, false}, {60, 1, false}, {60, 2, false}, {60, 3, false}, {60, 2, false}, {60, 1, false}, {61, 0, false}, {61, 1, false}, {61, 2, false}, {61, 3, false}, {61, 2, false}, {61, 1, false}, {62, 0, false}, {62, 1, true}, {63, 0, false}, {63, 1, true}, {64, 0, false}, {64, 1, true}, {65, 0, false}, {65, 1, true}, {66, 0, false}, {66, 1, true}, {67, 0, false}, {67, 1, true}, // 840 {68, 0, false}, {69, 0, false}, {70, 0, true}, {70, 1, true}, {70, 2, true}, {70, 3, true}, {70, 2, true}, {70, 1, true}, {71, 0, true}, {71, 1, true}, {71, 2, true}, {71, 3, true}, {72, 0, true}, {73, 0, true}, {73, 1, true}, {73, 2, true}, {73, 3, true}, {74, 0, true}, {74, 1, true}, {74, 2, true}, {74, 3, true}, {75, 0, true}, {76, 0, true}, {76, 1, true}, {76, 2, true}, {76, 3, true}, {76, 2, true}, {76, 1, true}, {77, 0, true}, {77, 1, false}, // 870 {78, 0, false}, {79, 0, false}, {80, 0, false}, {81, 0, false}, {82, 0, false}, {83, 0, false}, {84, 0, false}, {85, 0, false}, {86, 0, false}, {87, 0, false}, {88, 0, false}, {89, 0, false}, {90, 0, false}, {91, 0, false}, {92, 0, false}, {93, 0, false}, {94, 0, true}, {95, 0, false}, {96, 0, false}, {96, 1, false}, {96, 2, false}, {96, 1, false}, {28, 13, false}, {28, 18, false}, {97, 0, false}, {98, 0, false}, {99, 0, false}, {100, 0, true}, {100, 0, true}, {101, 0, false}, // 900 {102, 0, false}, {102, 0, false}, {103, 0, false}, {104, 0, false}, {105, 0, false}, {106, 0, false}, {107, 0, false}, {108, 0, false}, {109, 0, false}, {110, 0, false}, {111, 0, false}, {112, 0, true}, {113, 0, true}, {114, 0, false}, {115, 0, false}, {116, 0, false}, {117, 0, false}, {118, 0, true}, {118, 1, true}, {118, 2, true}, {118, 1, true}, {119, 0, true}, {119, 1, true}, {119, 2, true}, {120, 0, false}, {120, 1, false}, {121, 0, true}, {121, 1, true}, {121, 2, true}, {121, 3, true}, // 930 {122, 0, true}, {122, 1, true}, {122, 2, true}, {122, 3, true}, {123, 0, true}, {123, 1, true}, {123, 2, true}, {123, 3, true}, {124, 0, true}, {124, 1, true}, {124, 2, true}, {124, 3, true}, {125, 0, true}, {125, 1, true}, {125, 2, true}, {125, 3, true}, {126, 0, true}, {126, 1, true}, {126, 2, true}, {126, 3, true}, {127, 0, false}, {128, 0, false}, {129, 0, false}, {130, 0, false}, {131, 0, false}, {132, 0, false}, {133, 0, false}, {134, 0, false}, {135, 0, false}, {136, 0, true}, // 960 {136, 1, true}, {136, 2, true}, {136, 3, true}, {137, 0, true}, {137, 1, true}, {137, 2, true}, {137, 3, true}, {138, 0, false}, {22, 1, true}, {22, 1, true}, {22, 2, true}, {22, 3, true}, {139, 0, false}, {139, 1, false}, {139, 0, false}, {139, 0, false}, {139, 1, false}, {139, 1, false}, {139, 2, false}, {139, 2, false}, {139, 3, false}, {139, 3, false}, {139, 4, false}, {139, 5, false}, {139, 6, false}, {139, 7, false}, {139, 7, false}, {139, 8, false}, {139, 9, false}, {139, 10, false}, // 990 {139, 11, false}, {139, 12, false}, {139, 13, false}, {139, 13, false}, {139, 12, false}, {139, 11, false}, {139, 10, false}, {139, 9, false}, {139, 8, false}, {14, 0, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, // 1020 {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {14, 1, false}, {140, 0, true}, {140, 1, true}, {140, 2, true}, {140, 3, true}, {140, 4, true}, {140, 5, true}, {140, 6, true}, {141, 0, true}, // 1050 {141, 1, true}, {141, 2, true}, {141, 3, true}, {141, 4, true}, {142, 0, false}, {143, 0, false}, {44, 0, false}, {44, 1, false}, {44, 2, false}, {44, 3, false}, {44, 0, false}, {44, 4, false}, {44, 5, false}, {44, 5, false}, {44, 6, false}, {44, 7, false}, {44, 8, false}, {44, 9, false}, {44, 10, false}, {44, 11, false}, {44, 12, false}, {44, 13, false}, {44, 14, false}, {44, 15, false}, {44, 16, false}, {22, 1, true}, {58, 0, false}, {144, 0, false}, {144, 1, false}, {144, 2, false}, // 1080 {144, 3, false}, {144, 4, false}, {144, 5, false}, {144, 6, false}, {144, 7, false}, {17, 0, true}, {17, 1, false}, {17, 2, false}, {17, 3, false}, {138, 0, false} // 1090 }; static const frame_t DEHEXTRA_FRAME = {138, 0, false}; static const SString SPRITE_BY_INDEX[] = { "TROO", "SHTG", "PUNG", "PISG", "PISF", "SHTF", "SHT2", "CHGG", "CHGF", "MISG", "MISF", "SAWG", "PLSG", "PLSF", "BFGG", "BFGF", "BLUD", "PUFF", "BAL1", "BAL2", "PLSS", "PLSE", "MISL", "BFS1", "BFE1", "BFE2", "TFOG", "IFOG", "PLAY", "POSS", "SPOS", "VILE", "FIRE", "FATB", "FBXP", // 35 "SKEL", "MANF", "FATT", "CPOS", "SARG", "HEAD", "BAL7", "BOSS", "BOS2", "SKUL", "SPID", "BSPI", "APLS", "APBX", "CYBR", "PAIN", "SSWV", "KEEN", "BBRN", "BOSF", "ARM1", "ARM2", "BAR1", "BEXP", "FCAN", "BON1", "BON2", "BKEY", "RKEY", "YKEY", "BSKU", "RSKU", "YSKU", "STIM", "MEDI", // 70 "SOUL", "PINV", "PSTR", "PINS", "MEGA", "SUIT", "PMAP", "PVIS", "CLIP", "AMMO", "ROCK", "BROK", "CELL", "CELP", "SHEL", "SBOX", "BPAK", "BFUG", "MGUN", "CSAW", "LAUN", "PLAS", "SHOT", "SGN2", "COLU", "SMT2", "GOR1", "POL2", "POL5", "POL4", "POL3", "POL1", "POL6", "GOR2", "GOR3", // 105 "GOR4", "GOR5", "SMIT", "COL1", "COL2", "COL3", "COL4", "CAND", "CBRA", "COL6", "TRE1", "TRE2", "ELEC", "CEYE", "FSKU", "COL5", "TBLU", "TGRN", "TRED", "SMBT", "SMGT", "SMRT", "HDB1", "HDB2", "HDB3", "HDB4", "HDB5", "HDB6", "POB1", "POB2", "BRS1", "TLMP", "TLP2", "TNT1", "DOGS", // 140 "PLS1", "PLS2", "BON3", "BON4" // 144 }; } #endif eureka-editor-eureka-2.0.2/src/e_basis.cc000066400000000000000000000542721464327712600202560ustar00rootroot00000000000000//------------------------------------------------------------------------ // BASIC OBJECT HANDLING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "e_basis.h" #include "Errors.h" #include "Instance.h" #include "LineDef.h" #include "main.h" #include "Sector.h" #include "SideDef.h" #include "Thing.h" #include "Vertex.h" // need these for the XXX_Notify() prototypes #include "r_render.h" int global::default_floor_h = 0; int global::default_ceil_h = 128; int global::default_light_level = 176; static StringTable basis_strtab; const char *NameForObjectType(ObjType type, bool plural) { switch (type) { case ObjType::things: return plural ? "things" : "thing"; case ObjType::linedefs: return plural ? "linedefs" : "linedef"; case ObjType::sidedefs: return plural ? "sidedefs" : "sidedef"; case ObjType::vertices: return plural ? "vertices" : "vertex"; case ObjType::sectors: return plural ? "sectors" : "sector"; default: BugError("NameForObjectType: bad type: %d\n", (int)type); return "XXX"; /* NOT REACHED */ } } StringID BA_InternaliseString(const SString &str) { return basis_strtab.add(str); } SString BA_GetString(StringID offset) noexcept { return basis_strtab.get(offset); } FFixedPoint MakeValidCoord(MapFormat format, double x) { if (format == MapFormat::udmf) return FFixedPoint(x); // in standard format, coordinates must be integral return FFixedPoint(round(x)); } //------------------------------------------------------------------------ //------------------------------------------------------------------------ // BASIS API IMPLEMENTATION //------------------------------------------------------------------------ // // Begin a group of operations that will become a single undo/redo // step. Any stored _redo_ steps will be forgotten. The BA_New, // BA_Delete, BA_Change and BA_Message functions must only be called // between BA_Begin() and BA_End() pairs. // void Basis::begin() { if(mCurrentGroup.isActive()) BugError("Basis::begin called twice without Basis::end\n"); while(!mRedoFuture.empty()) mRedoFuture.pop(); mCurrentGroup.activate(); doClearChangeStatus(); } // // finish a group of operations. // void Basis::end() { if(!mCurrentGroup.isActive()) BugError("Basis::end called without a previous Basis::begin\n"); mCurrentGroup.end(); if(mCurrentGroup.isEmpty()) mCurrentGroup.reset(); else { SString message = mCurrentGroup.getMessage(); SString menuDetail = mCurrentGroup.getMenuName(); mUndoHistory.push(std::move(mCurrentGroup)); if(inst.main_win) { Fl_Sys_Menu_Bar *bar = inst.main_win->menu_bar; menu::setUndoDetail(bar, menuDetail); menu::setRedoDetail(bar, ""); } inst.Status_Set("%s", message.c_str()); } doProcessChangeStatus(); } // // abort the group of operations -- the undo/redo history is not // modified and any changes since BA_Begin() are undone except // when 'keep_changes' is true. // void Basis::abort(bool keepChanges) { if(!mCurrentGroup.isActive()) BugError("Basis::abort called without a previous Basis::begin\n"); mCurrentGroup.end(); if(!keepChanges && !mCurrentGroup.isEmpty()) mCurrentGroup.reapply(*this); mCurrentGroup.reset(); mDidMakeChanges = false; doProcessChangeStatus(); } static SString makeInfinitive(const SString &phrase) { static const std::map map = { {"added", "Add"}, {"adjusted", "Adjust"}, {"aligned", "Align"}, {"cleared", "Clear"}, {"copied", "Copy"}, {"cut", "Cut"}, {"darkened", "Darken"}, {"defaulted", "Default"}, {"deleted", "Delete"}, {"disconnected", "Disconnect"}, {"edited", "Edit"}, {"enlarged", "Enlarge"}, {"fixed", "Fix"}, {"flipped", "Flip"}, {"halved", "Halve"}, {"lowered", "Lower"}, {"merge", "Merge"}, {"merged", "Merge"}, {"mirrored", "Mirror"}, {"moved", "Move"}, {"new", "Add New"}, {"pasted", "Paste"}, {"pruned", "Prune"}, {"quantized", "Quantize"}, {"raised", "Raise"}, {"removed", "Remove"}, {"replacement", "Replace"}, {"rotated", "Rotate"}, {"scaled", "Scale"}, {"set length", "Set Length"}, {"shaped", "Shape"}, {"shrunk", "Shrink"}, {"split", "Split"}, {"spun", "Spin"}, {"swapped", "Swap"}, {"unpacked", "Unpack"}, }; for(const auto &pair : map) { if(phrase.startsWith(pair.first.c_str())) return pair.second; } return ""; } // // assign a message to the current operation. // this can be called multiple times. // void Basis::setMessage(EUR_FORMAT_STRING(const char *format), ...) { SYS_ASSERT(format); SYS_ASSERT(mCurrentGroup.isActive()); va_list arg_ptr; va_start(arg_ptr, format); SString message = SString::vprintf(format, arg_ptr); mCurrentGroup.setMessage(message); va_end(arg_ptr); mCurrentGroup.setMenuName(makeInfinitive(message)); } // // Set a message for the selection // void Basis::setMessageForSelection(const char *verb, const selection_c &list, const char *suffix) { // utility for creating messages like "moved 3 things" int total = list.count_obj(); if(total < 1) // oops return; if(total == 1) { setMessage("%s %s #%d%s", verb, NameForObjectType(list.what_type()), list.find_first(), suffix); } else { setMessage("%s %d %s%s", verb, total, NameForObjectType(list.what_type(), true /* plural */), suffix); } } // // create a new object, returning its objnum. It is safe to // directly set the new object's fields after calling BA_New(). // int Basis::addNew(ObjType type) { SYS_ASSERT(mCurrentGroup.isActive()); EditUnit op; op.action = EditType::insert; op.objtype = type; switch(type) { case ObjType::things: op.objnum = doc.numThings(); op.thing = std::make_shared(); break; case ObjType::vertices: op.objnum = doc.numVertices(); op.vertex = std::make_shared(); break; case ObjType::sidedefs: op.objnum = doc.numSidedefs(); op.sidedef = std::make_shared(); break; case ObjType::linedefs: op.objnum = doc.numLinedefs(); op.linedef = std::make_shared(); break; case ObjType::sectors: op.objnum = doc.numSectors(); op.sector = std::make_shared(); break; default: BugError("Basis::addNew: unknown type\n"); } int objnum = op.objnum; mCurrentGroup.addApply(std::move(op), *this); return objnum; } // // deletes the given object, and in certain cases other types of // objects bound to it (e.g. deleting a vertex will cause all // bound linedefs to also be deleted). // void Basis::del(ObjType type, int objnum) { SYS_ASSERT(mCurrentGroup.isActive()); EditUnit op; op.action = EditType::del; op.objtype = type; op.objnum = objnum; // this must happen _before_ doing the deletion (otherwise // when we undo, the insertion will mess up the references). if(type == ObjType::sidedefs) { // unbind sidedef from any linedefs using it for(int n = doc.numLinedefs() - 1; n >= 0; n--) { const auto L = doc.linedefs[n]; if(L->right == objnum) changeLinedef(n, LineDef::F_RIGHT, -1); if(L->left == objnum) changeLinedef(n, LineDef::F_LEFT, -1); } } else if(type == ObjType::vertices) { // delete any linedefs bound to this vertex for(int n = doc.numLinedefs() - 1; n >= 0; n--) { const auto L = doc.linedefs[n]; if(L->start == objnum || L->end == objnum) del(ObjType::linedefs, n); } } else if(type == ObjType::sectors) { // delete the sidedefs bound to this sector for(int n = doc.numSidedefs() - 1; n >= 0; n--) if(doc.sidedefs[n]->sector == objnum) del(ObjType::sidedefs, n); } SYS_ASSERT(mCurrentGroup.isActive()); mCurrentGroup.addApply(std::move(op), *this); } // // change a field of an existing object. If the value was the // same as before, nothing happens and false is returned. // Otherwise returns true. // bool Basis::change(ObjType type, int objnum, byte field, int value) { // TODO: optimise, check whether value actually changes EditUnit op; op.action = EditType::change; op.objtype = type; op.field = field; op.objnum = objnum; op.value = value; SYS_ASSERT(mCurrentGroup.isActive()); mCurrentGroup.addApply(std::move(op), *this); return true; } // // Change thing // bool Basis::changeThing(int thing, Thing::IntAddress field, int value) { SYS_ASSERT(thing >= 0 && thing < doc.numThings()); if(field == Thing::F_TYPE) inst.recent_things.insert_number(value); return change(ObjType::things, thing, field, value); } bool Basis::changeThing(int thing, Thing::FixedPointAddress field, FFixedPoint value) { SYS_ASSERT(thing >= 0 && thing < doc.numThings()); return change(ObjType::things, thing, field, value.raw()); } // // Change vertex // bool Basis::changeVertex(int vert, byte field, FFixedPoint value) { SYS_ASSERT(vert >= 0 && vert < doc.numVertices()); SYS_ASSERT(field <= Vertex::F_Y); return change(ObjType::vertices, vert, field, value.raw()); } // // Change sector // bool Basis::changeSector(int sec, Sector::IntAddress field, int value) { SYS_ASSERT(sec >= 0 && sec < doc.numSectors()); return change(ObjType::sectors, sec, field, value); } bool Basis::changeSector(int sec, Sector::StringIDAddress field, StringID value) { SYS_ASSERT(sec >= 0 && sec < doc.numSectors()); inst.recent_flats.insert(BA_GetString(value)); return change(ObjType::sectors, sec, field, value.get()); } // // Change sidedef // bool Basis::changeSidedef(int side, SideDef::IntAddress field, int value) { SYS_ASSERT(side >= 0 && side < doc.numSidedefs()); return change(ObjType::sidedefs, side, field, value); } bool Basis::changeSidedef(int side, SideDef::StringIDAddress field, StringID value) { SYS_ASSERT(side >= 0 && side < doc.numSidedefs()); inst.recent_textures.insert(BA_GetString(value)); return change(ObjType::sidedefs, side, field, value.get()); } // // Change linedef // bool Basis::changeLinedef(int line, byte field, int value) { SYS_ASSERT(line >= 0 && line < doc.numLinedefs()); SYS_ASSERT(field <= LineDef::F_ARG5); return change(ObjType::linedefs, line, field, value); } // // attempt to undo the last normal or redo operation. Returns // false if the undo history is empty. // bool Basis::undo() { if(mUndoHistory.empty()) return false; doClearChangeStatus(); UndoGroup grp = std::move(mUndoHistory.top()); mUndoHistory.pop(); inst.Status_Set("UNDO: %s", grp.getMessage().c_str()); if(inst.main_win) { Fl_Sys_Menu_Bar *bar = inst.main_win->menu_bar; if(bar) { menu::setRedoDetail(bar, grp.getMenuName()); menu::setUndoDetail(bar, mUndoHistory.empty() ? "" : mUndoHistory.top().getMenuName()); } } grp.reapply(*this); mRedoFuture.push(std::move(grp)); doProcessChangeStatus(); return true; } // // attempt to re-do the last undo operation. Returns false if // there is no stored redo steps. // bool Basis::redo() { if(mRedoFuture.empty()) return false; doClearChangeStatus(); UndoGroup grp = std::move(mRedoFuture.top()); mRedoFuture.pop(); inst.Status_Set("Redo: %s", grp.getMessage().c_str()); if(inst.main_win) { Fl_Sys_Menu_Bar *bar = inst.main_win->menu_bar; if(bar) { menu::setUndoDetail(bar, grp.getMenuName()); menu::setRedoDetail(bar, mRedoFuture.empty() ? "" : mRedoFuture.top().getMenuName()); } } grp.reapply(*this); mUndoHistory.push(std::move(grp)); doProcessChangeStatus(); return true; } void Basis::clear() { while(!mUndoHistory.empty()) mUndoHistory.pop(); while(!mRedoFuture.empty()) mRedoFuture.pop(); if(inst.main_win) { menu::setUndoDetail(inst.main_win->menu_bar, ""); menu::setRedoDetail(inst.main_win->menu_bar, ""); } // Note: we don't clear the string table, since there can be // string references in the clipboard. } // // Execute the operation // void Basis::EditUnit::apply(Basis &basis) { switch(action) { case EditType::change: rawChange(basis); return; case EditType::del: rawDelete(basis); action = EditType::insert; // reverse the operation return; case EditType::insert: rawInsert(basis); action = EditType::del; // reverse the operation return; default: BugError("Basis::EditOperation::apply\n"); } } // // Destroy an inst.inst.edit operation // void Basis::EditUnit::destroy() { switch(action) { case EditType::insert: deleteFinally(); break; case EditType::del: break; default: break; } } // // Execute the raw change // void Basis::EditUnit::rawChange(Basis &basis) { int *pos = nullptr; switch(objtype) { case ObjType::things: SYS_ASSERT(0 <= objnum && objnum < basis.doc.numThings()); pos = reinterpret_cast(basis.doc.things[objnum].get()); break; case ObjType::vertices: SYS_ASSERT(0 <= objnum && objnum < basis.doc.numVertices()); pos = reinterpret_cast(basis.doc.vertices[objnum].get()); break; case ObjType::sectors: SYS_ASSERT(0 <= objnum && objnum < basis.doc.numSectors()); pos = reinterpret_cast(basis.doc.sectors[objnum].get()); break; case ObjType::sidedefs: SYS_ASSERT(0 <= objnum && objnum < basis.doc.numSidedefs()); pos = reinterpret_cast(basis.doc.sidedefs[objnum].get()); break; case ObjType::linedefs: SYS_ASSERT(0 <= objnum && objnum < basis.doc.numLinedefs()); pos = reinterpret_cast(basis.doc.linedefs[objnum].get()); break; default: BugError("Basis::EditOperation::rawChange: bad objtype %u\n", (unsigned)objtype); return; /* NOT REACHED */ } // TODO: CHANGE THIS TO A SAFER WAY! std::swap(pos[field], value); basis.mDidMakeChanges = true; // TODO: their modules Clipboard_NotifyChange(objtype, objnum, field); Selection_NotifyChange(objtype, objnum, field); basis.inst.MapStuff_NotifyChange(objtype, objnum, field); Render3D_NotifyChange(objtype, objnum, field); basis.inst.ObjectBox_NotifyChange(objtype, objnum, field); } // // Deletion operation // void Basis::EditUnit::rawDelete(Basis &basis) { basis.mDidMakeChanges = true; // TODO: their own modules Clipboard_NotifyDelete(objtype, objnum); basis.inst.Selection_NotifyDelete(objtype, objnum); basis.inst.MapStuff_NotifyDelete(objtype, objnum); Render3D_NotifyDelete(basis.doc, objtype, objnum); basis.inst.ObjectBox_NotifyDelete(objtype, objnum); switch(objtype) { case ObjType::things: thing = rawDeleteThing(basis.doc); return; case ObjType::vertices: vertex = rawDeleteVertex(basis.doc); return; case ObjType::sectors: sector = rawDeleteSector(basis.doc); return; case ObjType::sidedefs: sidedef = rawDeleteSidedef(basis.doc); return; case ObjType::linedefs: linedef = rawDeleteLinedef(basis.doc); return; default: BugError("Basis::EditOperation::rawDelete: bad objtype %u\n", (unsigned)objtype); return; /* NOT REACHED */ } } // // Thing deletion // std::shared_ptr Basis::EditUnit::rawDeleteThing(Document &doc) const { SYS_ASSERT(0 <= objnum && objnum < doc.numThings()); auto result = std::move(doc.things[objnum]); doc.things.erase(doc.things.begin() + objnum); return result; } // // Vertex deletion (and update linedef refs) // std::shared_ptr Basis::EditUnit::rawDeleteVertex(Document &doc) const { SYS_ASSERT(0 <= objnum && objnum < doc.numVertices()); auto result = std::move(doc.vertices[objnum]); doc.vertices.erase(doc.vertices.begin() + objnum); // fix the linedef references if(objnum < doc.numVertices()) { for(int n = doc.numLinedefs() - 1; n >= 0; n--) { auto L = doc.linedefs[n]; if(L->start > objnum) L->start--; if(L->end > objnum) L->end--; } } return result; } // // Raw delete sector (and update sidedef refs) // std::shared_ptr Basis::EditUnit::rawDeleteSector(Document &doc) const { SYS_ASSERT(0 <= objnum && objnum < doc.numSectors()); auto result = std::move(doc.sectors[objnum]); doc.sectors.erase(doc.sectors.begin() + objnum); // fix sidedef references if(objnum < doc.numSectors()) { for(int n = doc.numSidedefs() - 1; n >= 0; n--) { auto S = doc.sidedefs[n]; if(S->sector > objnum) S->sector--; } } return result; } // // Delete sidedef (and update linedef references) // std::shared_ptr Basis::EditUnit::rawDeleteSidedef(Document &doc) const { SYS_ASSERT(0 <= objnum && objnum < doc.numSidedefs()); auto result = std::move(doc.sidedefs[objnum]); doc.sidedefs.erase(doc.sidedefs.begin() + objnum); // fix the linedefs references if(objnum < doc.numSidedefs()) { for(int n = doc.numLinedefs() - 1; n >= 0; n--) { auto L = doc.linedefs[n]; if(L->right > objnum) L->right--; if(L->left > objnum) L->left--; } } return result; } // // Raw delete linedef // std::shared_ptr Basis::EditUnit::rawDeleteLinedef(Document &doc) const { SYS_ASSERT(0 <= objnum && objnum < doc.numLinedefs()); auto result = std::move(doc.linedefs[objnum]); doc.linedefs.erase(doc.linedefs.begin() + objnum); return result; } // // Insert operation // void Basis::EditUnit::rawInsert(Basis &basis) { basis.mDidMakeChanges = true; // TODO: their module Clipboard_NotifyInsert(basis.doc, objtype, objnum); basis.inst.Selection_NotifyInsert(objtype, objnum); basis.inst.MapStuff_NotifyInsert(objtype, objnum); Render3D_NotifyInsert(objtype, objnum); basis.inst.ObjectBox_NotifyInsert(objtype, objnum); switch(objtype) { case ObjType::things: rawInsertThing(basis.doc); thing.reset(); // normally already reset break; case ObjType::vertices: rawInsertVertex(basis.doc); vertex.reset(); break; case ObjType::sidedefs: rawInsertSidedef(basis.doc); sidedef.reset(); break; case ObjType::sectors: rawInsertSector(basis.doc); sector.reset(); break; case ObjType::linedefs: rawInsertLinedef(basis.doc); linedef.reset(); break; default: BugError("Basis::EditOperation::rawInsert: bad objtype %u\n", (unsigned)objtype); } } // // Thing insertion // void Basis::EditUnit::rawInsertThing(Document &doc) { SYS_ASSERT(0 <= objnum && objnum <= doc.numThings()); doc.things.insert(doc.things.begin() + objnum, std::move(thing)); } // // Vertex insertion // void Basis::EditUnit::rawInsertVertex(Document &doc) { SYS_ASSERT(0 <= objnum && objnum <= doc.numVertices()); doc.vertices.insert(doc.vertices.begin() + objnum, std::move(vertex)); // fix references in linedefs if(objnum + 1 < doc.numVertices()) { for(int n = doc.numLinedefs() - 1; n >= 0; n--) { auto L = doc.linedefs[n]; if(L->start >= objnum) L->start++; if(L->end >= objnum) L->end++; } } } // // Sector insertion // void Basis::EditUnit::rawInsertSector(Document &doc) { SYS_ASSERT(0 <= objnum && objnum <= doc.numSectors()); doc.sectors.insert(doc.sectors.begin() + objnum, std::move(sector)); // fix all sidedef references if(objnum + 1 < doc.numSectors()) { for(int n = doc.numSidedefs() - 1; n >= 0; n--) { auto S = doc.sidedefs[n]; if(S->sector >= objnum) S->sector++; } } } // // Sidedef insertion // void Basis::EditUnit::rawInsertSidedef(Document &doc) { SYS_ASSERT(0 <= objnum && objnum <= doc.numSidedefs()); doc.sidedefs.insert(doc.sidedefs.begin() + objnum, std::move(sidedef)); // fix the linedefs references if(objnum + 1 < doc.numSidedefs()) { for(int n = doc.numLinedefs() - 1; n >= 0; n--) { auto L = doc.linedefs[n]; if(L->right >= objnum) L->right++; if(L->left >= objnum) L->left++; } } } // // Linedef insertion // void Basis::EditUnit::rawInsertLinedef(Document &doc) { SYS_ASSERT(0 <= objnum && objnum <= doc.numLinedefs()); doc.linedefs.insert(doc.linedefs.begin() + objnum, std::move(linedef)); } // // Action to do on destruction of insert operation // void Basis::EditUnit::deleteFinally() { switch(objtype) { case ObjType::things: thing.reset(); break; case ObjType::vertices: vertex.reset(); break; case ObjType::sectors: sector.reset(); break; case ObjType::sidedefs: sidedef.reset(); break; case ObjType::linedefs: linedef.reset(); break; default: BugError("DeleteFinally: bad objtype %d\n", (int)objtype); } } // // Move operator // Basis::UndoGroup &Basis::UndoGroup::operator = (UndoGroup &&other) noexcept { mOps = std::move(other.mOps); mDir = other.mDir; mMessage = std::move(other.mMessage); mMenuName = std::move(other.mMenuName); other.reset(); // ensure the other goes into the default state return *this; } // // Reset to initial, inactive state // void Basis::UndoGroup::reset() { mOps.clear(); mDir = 0; mMessage = DEFAULT_UNDO_GROUP_MESSAGE; } // // Add and apply // void Basis::UndoGroup::addApply(EditUnit &&op, Basis &basis) { mOps.push_back(std::move(op)); mOps.back().apply(basis); } // // Reapply // void Basis::UndoGroup::reapply(Basis &basis) { if(mDir > 0) for(auto it = mOps.begin(); it != mOps.end(); ++it) it->apply(basis); else if(mDir < 0) for(auto it = mOps.rbegin(); it != mOps.rend(); ++it) it->apply(basis); // reverse the order for next time mDir = -mDir; } // // Clear change status // void Basis::doClearChangeStatus() { mDidMakeChanges = false; // TODO: these shall go to other modules Clipboard_NotifyBegin(); inst.Selection_NotifyBegin(); inst.MapStuff_NotifyBegin(); Render3D_NotifyBegin(); inst.ObjectBox_NotifyBegin(); } // // If we made changes, notify the others // void Basis::doProcessChangeStatus() const { if(mDidMakeChanges) { // TODO: the other modules doc.MadeChanges = true; inst.RedrawMap(); } Clipboard_NotifyEnd(); inst.Selection_NotifyEnd(); inst.MapStuff_NotifyEnd(); Render3D_NotifyEnd(inst); inst.ObjectBox_NotifyEnd(); } // // Set operation message // void EditOperation::setMessage(EUR_FORMAT_STRING(const char *format), ...) { va_list ap; va_start(ap, format); basis.setMessage("%s", SString::vprintf(format, ap).c_str()); va_end(ap); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_basis.h000066400000000000000000000214261464327712600201130ustar00rootroot00000000000000//------------------------------------------------------------------------ // BASIC OBJECT HANDLING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_E_BASIS_H__ #define __EUREKA_E_BASIS_H__ #include "DocumentModule.h" #include "LineDef.h" #include "m_strings.h" #include "objid.h" #include "Sector.h" #include "SideDef.h" #include "Thing.h" #include "Vertex.h" #include #include #define DEFAULT_UNDO_GROUP_MESSAGE "[something]" class selection_c; class LineDef; struct Vertex; namespace global { extern int default_floor_h; extern int default_ceil_h; extern int default_light_level; } // // DESIGN NOTES // // Every field in these structures are a plain 'int'. This is a // design decision aiming to simplify the logic and code for undo // and redo. // // Strings are represented as offsets into a string table. // // These structures are always ensured to have valid fields, e.g. // the LineDef vertex numbers are OK, the SideDef sector number is // valid, etc. For LineDefs, the left and right fields can contain // -1 to mean "no sidedef", but note that a missing right sidedef // can cause problems or crashes when playing the map in DOOM. // // See objid.h for obj_type_e (OBJ_THINGS etc) // E_BASIS FFixedPoint MakeValidCoord(MapFormat format, double x); // // Editor command manager, handles undo/redo // class Basis : public DocumentModule { public: Basis(Document &doc) : DocumentModule(doc) { } bool undo(); bool redo(); void clear(); Basis &operator = (Basis &&other) noexcept { mCurrentGroup = std::move(other.mCurrentGroup); mUndoHistory = std::move(other.mUndoHistory); mRedoFuture = std::move(other.mRedoFuture); mDidMakeChanges = other.mDidMakeChanges; return *this; } private: // // Edit change // enum class EditType : byte { none, // initial state (invalid) change, insert, del }; // // Edit operation // struct EditUnit { EditType action = EditType::none; ObjType objtype = ObjType::things; byte field = 0; int objnum = 0; std::shared_ptr thing; std::shared_ptr vertex; std::shared_ptr sector; std::shared_ptr sidedef; std::shared_ptr linedef; int value = 0; void apply(Basis &basis); void destroy(); private: void rawChange(Basis &basis); void rawDelete(Basis &basis); std::shared_ptr rawDeleteThing(Document &doc) const; std::shared_ptr rawDeleteVertex(Document &doc) const; std::shared_ptr rawDeleteSector(Document &doc) const; std::shared_ptr rawDeleteSidedef(Document &doc) const; std::shared_ptr rawDeleteLinedef(Document &doc) const; void rawInsert(Basis &basis); void rawInsertThing(Document &doc); void rawInsertVertex(Document &doc); void rawInsertSector(Document &doc); void rawInsertSidedef(Document &doc); void rawInsertLinedef(Document &doc); void deleteFinally(); }; friend class EditOperation; friend struct EditUnit; // // Undo operation group // class UndoGroup { public: UndoGroup() = default; ~UndoGroup() { for(auto it = mOps.rbegin(); it != mOps.rend(); ++it) it->destroy(); } // Ensure we only use move semantics UndoGroup(const UndoGroup &other) = delete; UndoGroup &operator = (const UndoGroup &other) = delete; // // Move constructor takes same semantics as operator // UndoGroup(UndoGroup &&other) noexcept { *this = std::move(other); } UndoGroup &operator = (UndoGroup &&other) noexcept; void reset(); // // Mark if active and ready to use // bool isActive() const { return !!mDir; } // // Start it // void activate() { mDir = +1; } // // Whether it's empty of data // bool isEmpty() const { return mOps.empty(); } void addApply(EditUnit &&op, Basis &basis); // // End current action // void end() { mDir = -1; } void reapply(Basis &basis); // // Get the message // const SString &getMessage() const { return mMessage; } // // Put the message // void setMessage(const SString &message) { mMessage = message; } void setMenuName(const SString &menuName) { mMenuName = menuName; } const SString &getMenuName() const { return mMenuName; } private: std::vector mOps; SString mMessage = DEFAULT_UNDO_GROUP_MESSAGE; SString mMenuName; int mDir = 0; // dir must be +1 or -1 if active }; // Called exclusively from friend class void begin(); void setMessage(EUR_FORMAT_STRING(const char *format), ...) EUR_PRINTF(2, 3); void setMessageForSelection(const char *verb, const selection_c &list, const char *suffix = ""); int addNew(ObjType type); bool change(ObjType type, int objnum, byte field, int value); bool changeThing(int thing, Thing::IntAddress field, int value); bool changeThing(int thing, Thing::FixedPointAddress field, FFixedPoint value); bool changeVertex(int vert, byte field, FFixedPoint value); bool changeSector(int sec, Sector::IntAddress field, int value); bool changeSector(int sec, Sector::StringIDAddress field, StringID value); bool changeSidedef(int side, SideDef::IntAddress field, int value); bool changeSidedef(int side, SideDef::StringIDAddress field, StringID value); bool changeLinedef(int line, byte field, int value); void del(ObjType type, int objnum); void end(); void abort(bool keepChanges); void doClearChangeStatus(); void doProcessChangeStatus() const; UndoGroup mCurrentGroup; // FIXME: use a better data type here std::stack mUndoHistory; std::stack mRedoFuture; bool mDidMakeChanges = false; }; // // Undo/redo operation // class EditOperation { public: EditOperation(Basis &basis) : doc(basis.doc), basis(basis) { basis.begin(); } ~EditOperation() { if(abort) basis.abort(abortKeepChanges); else basis.end(); } void setMessage(EUR_FORMAT_STRING(const char *format), ...) EUR_PRINTF(2, 3); void setMessageForSelection(const char *verb, const selection_c &list, const char *suffix = "") { basis.setMessageForSelection(verb, list, suffix); } int addNew(ObjType type) { return basis.addNew(type); } bool change(ObjType type, int objnum, byte field, int value) { return basis.change(type, objnum, field, value); } bool changeThing(int thing, Thing::IntAddress field, int value) { return basis.changeThing(thing, field, value); } bool changeThing(int thing, Thing::FixedPointAddress field, FFixedPoint value) { return basis.changeThing(thing, field, value); } bool changeVertex(int vert, byte field, FFixedPoint value) { return basis.changeVertex(vert, field, value); } bool changeSector(int sec, Sector::IntAddress field, int value) { return basis.changeSector(sec, field, value); } bool changeSector(int sec, Sector::StringIDAddress field, StringID value) { return basis.changeSector(sec, field, value); } bool changeSidedef(int side, SideDef::IntAddress field, int value) { return basis.changeSidedef(side, field, value); } bool changeSidedef(int side, SideDef::StringIDAddress field, StringID value) { return basis.changeSidedef(side, field, value); } bool changeLinedef(int line, byte field, int value) { return basis.changeLinedef(line, field, value); } void del(ObjType type, int objnum) { basis.del(type, objnum); } void setAbort(bool keepChanges) { abort = true; abortKeepChanges = keepChanges; } Document &doc; // convenience reference to doc private: Basis &basis; bool abort = false; bool abortKeepChanges = false; }; const char *NameForObjectType(ObjType type, bool plural = false); /* BASIS API */ // add this string to the basis string table (if it doesn't // already exist) and return its integer offset. StringID BA_InternaliseString(const SString &str); // get the string from the basis string table. SString BA_GetString(StringID offset) noexcept; #endif /* __EUREKA_E_BASIS_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_checks.cc000066400000000000000000003173151464327712600204150ustar00rootroot00000000000000//------------------------------------------------------------------------ // INTEGRITY CHECKS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2018 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include #include "e_checks.h" #include "e_cutpaste.h" #include "e_hover.h" #include "e_main.h" #include "e_path.h" #include "e_vertex.h" #include "LineDef.h" #include "m_game.h" #include "e_objects.h" #include "Sector.h" #include "SideDef.h" #include "Thing.h" #include "Vertex.h" #include "w_rawdef.h" #include "w_texture.h" #include "ui_window.h" #define ERROR_MSG_COLOR FL_RED #define WARNING_MSG_COLOR FL_BLUE #define CAMERA_PEST 32000 //------------------------------------------------------------------------ class UI_Check_base : public UI_Escapable_Window { protected: bool want_close; CheckResult user_action; Fl_Group *line_group; int cy; int worst_severity; private: static void close_callback(Fl_Widget *, void *); public: UI_Check_base(int W, int H, bool all_mode, const char *L, const char *header_txt); virtual ~UI_Check_base(); void Reset(); void AddGap(int H); void AddLine(const SString &msg, int severity = 0, int W = -1, const char *button1 = NULL, Fl_Callback *cb1 = NULL, const char *button2 = NULL, Fl_Callback *cb2 = NULL, const char *button3 = NULL, Fl_Callback *cb3 = NULL); CheckResult Run(); int WorstSeverity() const { return worst_severity; } }; //------------------------------------------------------------------------ // BASE CLASS //------------------------------------------------------------------------ void UI_Check_base::close_callback(Fl_Widget *w, void *data) { UI_Check_base *dialog = (UI_Check_base *)data; dialog->want_close = true; } UI_Check_base::UI_Check_base(int W, int H, bool all_mode, const char *L, const char *header_txt) : UI_Escapable_Window(W, H, L), want_close(false), user_action(CheckResult::ok), worst_severity(0) { cy = 10; callback(close_callback, this); int ey = h() - 66; Fl_Box *title = new Fl_Box(FL_NO_BOX, 10, cy, w() - 20, 30, header_txt); title->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); title->labelfont(FL_HELVETICA_BOLD); title->labelsize(FL_NORMAL_SIZE + 2); cy = 45; line_group = new Fl_Group(0, 0, w(), ey); line_group->end(); { Fl_Group *o = new Fl_Group(0, ey, w(), 66); o->box(FL_FLAT_BOX); o->color(WINDOW_BG, WINDOW_BG); int but_W = all_mode ? 110 : 70; { Fl_Button *ok_but; ok_but = new Fl_Button(w()/2 - but_W/2, ey + 18, but_W, 34, all_mode ? "Continue" : "OK"); ok_but->labelfont(1); ok_but->callback(close_callback, this); } o->end(); } end(); } UI_Check_base::~UI_Check_base() { } void UI_Check_base::Reset() { want_close = false; user_action = CheckResult::ok; cy = 45; line_group->clear(); redraw(); } void UI_Check_base::AddGap(int H) { cy += H; } void UI_Check_base::AddLine( const SString &msg, int severity, int W, const char *button1, Fl_Callback *cb1, const char *button2, Fl_Callback *cb2, const char *button3, Fl_Callback *cb3) { int cx = 30; if (W < 0) W = w() - 40; Fl_Box *box = new Fl_Box(FL_NO_BOX, cx, cy, W, 25, NULL); box->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT); box->copy_label(msg.c_str()); if (severity == 2) { box->labelcolor(ERROR_MSG_COLOR); box->labelfont(FL_HELVETICA_BOLD); } else if (severity == 1) { box->labelcolor(WARNING_MSG_COLOR); box->labelfont(FL_HELVETICA_BOLD); } line_group->add(box); cx += W; if (button1) { Fl_Button *but = new Fl_Button(cx, cy, 80, 25, button1); but->callback(cb1, this); line_group->add(but); cx += but->w() + 10; } if (button2) { Fl_Button *but = new Fl_Button(cx, cy, 80, 25, button2); but->callback(cb2, this); line_group->add(but); cx += but->w() + 10; } if (button3) { Fl_Button *but = new Fl_Button(cx, cy, 80, 25, button3); but->callback(cb3, this); line_group->add(but); } cy = cy + 30; if (severity > worst_severity) worst_severity = severity; } CheckResult UI_Check_base::Run() { set_modal(); show(); while (! (want_close || user_action != CheckResult::ok)) Fl::wait(0.2); if (user_action != CheckResult::ok) return user_action; switch (worst_severity) { case 0: return CheckResult::ok; case 1: return CheckResult::minorProblem; default: return CheckResult::majorProblem; } } //------------------------------------------------------------------------ static void Vertex_FindDanglers(selection_c& sel, const Document &doc) { sel.change_type(ObjType::vertices); if (doc.numVertices() == 0 || doc.numLinedefs() == 0) return; byte * line_counts = new byte[doc.numVertices()]; memset(line_counts, 0, doc.numVertices()); for (const auto &L : doc.linedefs) { int v1 = L->start; int v2 = L->end; // dangling vertices are fine for lines setting inside a sector // (i.e. with same sector on both sides) if (L->TwoSided() && (doc.getSectorID(*L, Side::left) == doc.getSectorID(*L, Side::right))) { line_counts[v1] = line_counts[v2] = 2; continue; } if (line_counts[v1] < 2) line_counts[v1] += 1; if (line_counts[v2] < 2) line_counts[v2] += 1; } for (int k = 0 ; k < doc.numVertices(); k++) { if (line_counts[k] == 1) sel.set(k); } delete[] line_counts; } static void Vertex_ShowDanglers(Instance &inst) { if (inst.edit.mode != ObjType::vertices) inst.Editor_ChangeMode('v'); Vertex_FindDanglers(*inst.edit.Selected, inst.level); inst.GoToErrors(); } struct vertex_X_CMP_pred { const Document &doc; explicit vertex_X_CMP_pred(const Document &doc) : doc(doc) { } inline bool operator() (int A, int B) const { const auto V1 = doc.vertices[A]; const auto V2 = doc.vertices[B]; return V1->raw_x < V2->raw_x; } }; void Vertex_FindOverlaps(selection_c& sel, const Document &doc) { // NOTE: when two or more vertices share the same coordinates, // only the second and subsequent ones are stored in 'sel'. sel.change_type(ObjType::vertices); if (doc.numVertices() < 2) return; // sort the vertices into order of the 'X' value. // hence any overlapping vertices will be near each other. std::vector sorted_list(doc.numVertices(), 0); for (int i = 0 ; i < doc.numVertices(); i++) sorted_list[i] = i; std::sort(sorted_list.begin(), sorted_list.end(), vertex_X_CMP_pred(doc)); #define VERT_K doc.vertices[sorted_list[k]] #define VERT_N doc.vertices[sorted_list[n]] for (int k = 0 ; k < doc.numVertices(); k++) { for (int n = k + 1 ; n < doc.numVertices() && VERT_N->raw_x == VERT_K->raw_x ; n++) { if (VERT_N->raw_y == VERT_K->raw_y) { sel.set(sorted_list[k]); } } } #undef VERT_K #undef VERT_N } static void Vertex_MergeOne(EditOperation &op, int idx, selection_c& merge_verts, Document &doc) { const auto V = doc.vertices[idx]; // find the base vertex (the one V is sitting on) for (int n = 0 ; n < doc.numVertices(); n++) { if (n == idx) continue; // skip any in the merge list if (merge_verts.get(n)) continue; const auto N = doc.vertices[n]; if (*N != *V) continue; // Ok, found it, so update linedefs for (int ld = 0 ; ld < doc.numLinedefs(); ld++) { const auto L = doc.linedefs[ld]; if (L->start == idx) op.changeLinedef(ld, LineDef::F_START, n); if (L->end == idx) op.changeLinedef(ld, LineDef::F_END, n); } return; } // SHOULD NOT GET HERE gLog.printf("VERTEX MERGE FAILURE.\n"); } static void Vertex_MergeOverlaps(Instance &inst) { selection_c verts; Vertex_FindOverlaps(verts, inst.level); { EditOperation op(inst.level.basis); op.setMessage("merged overlapping vertices"); for (sel_iter_c it(verts) ; !it.done() ; it.next()) { Vertex_MergeOne(op, *it, verts, inst.level); } // nothing should reference these vertices now inst.level.objects.del(op, verts); } inst.RedrawMap(); } static void Vertex_ShowOverlaps(Instance &inst) { if (inst.edit.mode != ObjType::vertices) inst.Editor_ChangeMode('v'); Vertex_FindOverlaps(*inst.edit.Selected, inst.level); inst.GoToErrors(); } static void Vertex_FindUnused(selection_c& sel, const Document &doc) { sel.change_type(ObjType::vertices); if (doc.numVertices() == 0) return; for (const auto &linedef : doc.linedefs) { sel.set(linedef->start); sel.set(linedef->end); } sel.frob_range(0, doc.numVertices() - 1, BitOp::toggle); } static void Vertex_RemoveUnused(Document &doc) { selection_c sel; Vertex_FindUnused(sel, doc); EditOperation op(doc.basis); op.setMessage("removed unused vertices"); doc.objects.del(op, sel); } static void Vertex_ShowUnused(Instance &inst) { if (inst.edit.mode != ObjType::vertices) inst.Editor_ChangeMode('v'); Vertex_FindUnused(*inst.edit.Selected, inst.level); inst.GoToErrors(); } //------------------------------------------------------------------------ class UI_Check_Vertices : public UI_Check_base { public: UI_Check_Vertices(bool all_mode, Instance &inst) : UI_Check_base(520, 224, all_mode, "Check : Vertices", "Vertex test results"), inst(inst) { } static void action_merge(Fl_Widget *w, void *data) { UI_Check_Vertices *dialog = (UI_Check_Vertices *)data; Vertex_MergeOverlaps(dialog->inst); dialog->user_action = CheckResult::tookAction; } static void action_highlight(Fl_Widget *w, void *data) { UI_Check_Vertices *dialog = (UI_Check_Vertices *)data; Vertex_ShowOverlaps(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_show_unused(Fl_Widget *w, void *data) { UI_Check_Vertices *dialog = (UI_Check_Vertices *)data; Vertex_ShowUnused(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_remove(Fl_Widget *w, void *data) { UI_Check_Vertices *dialog = (UI_Check_Vertices *)data; Vertex_RemoveUnused(dialog->inst.level); dialog->user_action = CheckResult::tookAction; } static void action_show_danglers(Fl_Widget *w, void *data) { UI_Check_Vertices *dialog = (UI_Check_Vertices *)data; Vertex_ShowDanglers(dialog->inst); dialog->user_action = CheckResult::highlight; } private: Instance &inst; }; CheckResult ChecksModule::checkVertices(int min_severity) const { UI_Check_Vertices *dialog = new UI_Check_Vertices(min_severity > 0, inst); selection_c sel; SString check_message; for (;;) { Vertex_FindOverlaps(sel, doc); if (sel.empty()) dialog->AddLine("No overlapping vertices"); else { check_message = SString::printf("%d overlapping vertices", sel.count_obj()); dialog->AddLine(check_message.c_str(), 2, 210, "Show", &UI_Check_Vertices::action_highlight, "Merge", &UI_Check_Vertices::action_merge); } Vertex_FindDanglers(sel, doc); if (sel.empty()) dialog->AddLine("No dangling vertices"); else { check_message = SString::printf("%d dangling vertices", sel.count_obj()); dialog->AddLine(check_message, 2, 210, "Show", &UI_Check_Vertices::action_show_danglers); } Vertex_FindUnused(sel, doc); if (sel.empty()) dialog->AddLine("No unused vertices"); else { check_message = SString::printf("%d unused vertices", sel.count_obj()); dialog->AddLine(check_message, 1, 210, "Show", &UI_Check_Vertices::action_show_unused, "Remove", &UI_Check_Vertices::action_remove); } // in "ALL" mode, just continue if not too severe if (dialog->WorstSeverity() < min_severity) { delete dialog; return CheckResult::ok; } CheckResult result = dialog->Run(); if (result == CheckResult::tookAction) { // repeat the tests dialog->Reset(); continue; } delete dialog; return result; } } //------------------------------------------------------------------------ static void Sectors_FindUnclosed(selection_c& secs, selection_c& verts, const Document &doc) { secs.change_type(ObjType::sectors); verts.change_type(ObjType::vertices); if (doc.numVertices() == 0 || doc.numSectors() == 0) return; byte *ends = new byte[doc.numVertices()]; int v; for (int s = 0 ; s < doc.numSectors(); s++) { // clear the "ends" array for (v = 0 ; v < doc.numVertices(); v++) ends[v] = 0; // for each sidedef bound to the Sector, store a "1" in the "ends" // array for its starting vertex, and a "2" for its ending vertex. for (const auto &L : doc.linedefs) { if (! doc.touchesSector(*L, s)) continue; // ignore lines with same sector on both sides if (L->left >= 0 && L->right >= 0 && doc.getLeft(*L)->sector == doc.getRight(*L)->sector) continue; if (L->right >= 0 && doc.getRight(*L)->sector == s) { ends[L->start] |= 1; ends[L->end] |= 2; } if (L->left >= 0 && doc.getLeft(*L)->sector == s) { ends[L->start] |= 2; ends[L->end] |= 1; } } // every entry in the "ends" array should be 0 or 3 for (v = 0 ; v < doc.numVertices(); v++) { if (ends[v] == 1 || ends[v] == 2) { secs.set(s); verts.set(v); } } } delete[] ends; } static void Sectors_ShowUnclosed(ObjType what, Instance &inst) { if (inst.edit.mode != what) inst.Editor_ChangeMode((what == ObjType::sectors) ? 's' : 'v'); selection_c other; if (what == ObjType::sectors) Sectors_FindUnclosed(*inst.edit.Selected, other, inst.level); else Sectors_FindUnclosed(other, *inst.edit.Selected, inst.level); inst.GoToErrors(); } static void Sectors_FindMismatches(selection_c& secs, selection_c& lines, Instance &inst) { // // Note from RQ: // This is a very simple idea, but it works! The first test (above) // checks that all Sectors are closed. But if a closed set of LineDefs // is moved out of a Sector and has all its "external" SideDefs pointing // to that Sector instead of the new one, then we need a second test. // That's why I check if the SideDefs facing each other are bound to // the same Sector. // // Other note from RQ: // Nowadays, what makes the power of a good editor is its automatic tests. // So, if you are writing another Doom editor, you will probably want // to do the same kind of tests in your program. Fine, but if you use // these ideas, don't forget to credit DEU... Just a reminder... :-) // secs.change_type(ObjType::sectors); lines.change_type(ObjType::linedefs); Document &doc = inst.level; if (doc.numLinedefs() == 0 || doc.numSectors() == 0) return; FastOppositeTree tree(inst); for (int n = 0 ; n < doc.numLinedefs(); n++) { const auto L = doc.linedefs[n]; if (L->right >= 0) { int s = doc.hover.getOppositeSector(n, Side::right, &tree); if (s < 0 || doc.getRight(*L)->sector != s) { secs.set(doc.getRight(*L)->sector); lines.set(n); } } if (L->left >= 0) { int s = doc.hover.getOppositeSector(n, Side::left, &tree); if (s < 0 || doc.getLeft(*L)->sector != s) { secs.set(doc.getLeft(*L)->sector); lines.set(n); } } } } static void Sectors_ShowMismatches(ObjType what, Instance &inst) { if (inst.edit.mode != what) inst.Editor_ChangeMode((what == ObjType::sectors) ? 's' : 'l'); selection_c other; if (what == ObjType::sectors) Sectors_FindMismatches(*inst.edit.Selected, other, inst); else Sectors_FindMismatches(other, *inst.edit.Selected, inst); inst.GoToErrors(); } static void bump_unknown_type(std::map& t_map, int type) { int count = 0; if (t_map.find(type) != t_map.end()) count = t_map[type]; t_map[type] = count + 1; } static void Sectors_FindUnknown(selection_c& list, std::map& types, const Instance &inst) { types.clear(); list.change_type(ObjType::sectors); int max_type = (inst.conf.features.gen_sectors == GenSectorFamily::zdoom) ? 8191 : 2047; for (int n = 0 ; n < inst.level.numSectors(); n++) { int type_num = inst.level.sectors[n]->type; // always ignore type #0 if (type_num == 0) continue; if (type_num < 0 || type_num > max_type) { bump_unknown_type(types, type_num); list.set(n); continue; } // Boom and ZDoom generalized sectors if (inst.conf.features.gen_sectors == GenSectorFamily::zdoom) type_num &= 255; else if (inst.conf.features.gen_sectors != GenSectorFamily::none) type_num &= 31; const sectortype_t &info = inst.M_GetSectorType(type_num); if (info.desc.startsWith("UNKNOWN")) { bump_unknown_type(types, type_num); list.set(n); } } } static void Sectors_ShowUnknown(Instance &inst) { if (inst.edit.mode != ObjType::sectors) inst.Editor_ChangeMode('s'); std::map types; Sectors_FindUnknown(*inst.edit.Selected, types, inst); inst.GoToErrors(); } static void Sectors_LogUnknown(const Instance &inst) { selection_c sel; std::map types; std::map::iterator IT; Sectors_FindUnknown(sel, types, inst); gLog.printf("\n"); gLog.printf("Unknown Sector Types:\n"); gLog.printf("{\n"); for (IT = types.begin() ; IT != types.end() ; IT++) gLog.printf(" %5d x %d\n", IT->first, IT->second); gLog.printf("}\n"); LogViewer_Open(); } static void Sectors_ClearUnknown(Instance &inst) { selection_c sel; std::map types; Sectors_FindUnknown(sel, types, inst); EditOperation op(inst.level.basis); op.setMessage("cleared unknown sector types"); for (sel_iter_c it(sel) ; !it.done() ; it.next()) op.changeSector(*it, Sector::F_TYPE, 0); } void Sectors_FindUnused(selection_c& sel, const Document &doc) { sel.change_type(ObjType::sectors); if (doc.numSectors() == 0) return; for (const auto &L : doc.linedefs) { if (L->left >= 0) sel.set(doc.getLeft(*L)->sector); if (L->right >= 0) sel.set(doc.getRight(*L)->sector); } sel.frob_range(0, doc.numSectors() - 1, BitOp::toggle); } static void Sectors_RemoveUnused(Document &doc) { selection_c sel; Sectors_FindUnused(sel, doc); EditOperation op(doc.basis); op.setMessage("removed unused sectors"); doc.objects.del(op, sel); } static void Sectors_FindBadCeil(selection_c& sel, const Document &doc) { sel.change_type(ObjType::sectors); if (doc.numSectors() == 0) return; for (int i = 0 ; i < doc.numSectors(); i++) { if (doc.sectors[i]->ceilh < doc.sectors[i]->floorh) sel.set(i); } } static void Sectors_FixBadCeil(Document &doc) { selection_c sel; Sectors_FindBadCeil(sel, doc); EditOperation op(doc.basis); op.setMessage("fixed bad sector heights"); for (int i = 0 ; i < doc.numSectors(); i++) { if (doc.sectors[i]->ceilh < doc.sectors[i]->floorh) { op.changeSector(i, Sector::F_CEILH, doc.sectors[i]->floorh); } } } static void Sectors_ShowBadCeil(Instance &inst) { if (inst.edit.mode != ObjType::sectors) inst.Editor_ChangeMode('s'); Sectors_FindBadCeil(*inst.edit.Selected, inst.level); inst.GoToErrors(); } static void SideDefs_FindUnused(selection_c& sel, const Document &doc) { sel.change_type(ObjType::sidedefs); if (doc.numSidedefs() == 0) return; for (const auto &L : doc.linedefs) { if (L->left >= 0) sel.set(L->left); if (L->right >= 0) sel.set(L->right); } sel.frob_range(0, doc.numSidedefs() - 1, BitOp::toggle); } static void SideDefs_RemoveUnused(Document &doc) { selection_c sel; SideDefs_FindUnused(sel, doc); EditOperation op(doc.basis); op.setMessage("removed unused sidedefs"); doc.objects.del(op, sel); } static void SideDefs_FindPacking(selection_c& sides, selection_c& lines, const Document &doc) { sides.change_type(ObjType::sidedefs); lines.change_type(ObjType::linedefs); for (int i = 0 ; i < doc.numLinedefs(); i++) for (int k = 0 ; k < i ; k++) { const auto A = doc.linedefs[i]; const auto B = doc.linedefs[k]; bool AA = (A->left >= 0 && A->left == A->right); bool AL = (A->left >= 0 && (A->left == B->left || A->left == B->right)); bool AR = (A->right >= 0 && (A->right == B->left || A->right == B->right)); if (AL || AA) sides.set(A->left); if (AR) sides.set(A->right); if (AL || AR) { lines.set(i); lines.set(k); } else if (AA) { lines.set(i); } } } static void SideDefs_ShowPacked(Instance &inst) { if (inst.edit.mode != ObjType::linedefs) inst.Editor_ChangeMode('l'); selection_c sides; SideDefs_FindPacking(sides, *inst.edit.Selected, inst.level); inst.GoToErrors(); } int ChecksModule::copySidedef(EditOperation &op, int num) const { int sd = op.addNew(ObjType::sidedefs); *doc.sidedefs[sd] = *doc.sidedefs[num]; return sd; } static const char *const unpack_confirm_message = "This map contains shared sidedefs. It it recommended to unpack " "them, otherwise it may cause unexpected behavior during editing " "(such as random walls changing their texture).\n\n" "Unpack the sidedefs now?"; void ChecksModule::sidedefsUnpack(bool is_after_load) const { selection_c sides; selection_c lines; SideDefs_FindPacking(sides, lines, doc); if (sides.empty()) return; if ((false) /* confirm_it */) { if (DLG_Confirm({ "&No Change", "&Unpack" }, unpack_confirm_message) <= 0) return; } { EditOperation op(doc.basis); for (int sd = 0 ; sd < doc.numSidedefs(); sd++) { if (! sides.get(sd)) continue; // find the first linedef which uses this sidedef int first; for (first = 0 ; first < doc.numLinedefs(); first++) { const auto F = doc.linedefs[first]; if (F->left == sd || F->right == sd) break; } if (first >= doc.numLinedefs()) continue; // handle it when first linedef uses sidedef on both sides if (doc.linedefs[first]->left == doc.linedefs[first]->right) { op.changeLinedef(first, LineDef::F_LEFT, copySidedef(op, sd)); } // duplicate any remaining references for (int ld = first + 1 ; ld < doc.numLinedefs(); ld++) { if (doc.linedefs[ld]->left == sd) op.changeLinedef(ld, LineDef::F_LEFT, copySidedef(op, sd)); if (doc.linedefs[ld]->right == sd) op.changeLinedef(ld, LineDef::F_RIGHT, copySidedef(op, sd)); } } if (is_after_load) { op.setAbort(true /* keep changes */); } else { op.setMessage("unpacked all sidedefs"); } } gLog.printf("Unpacked %d shared sidedefs --> %d\n", sides.count_obj(), doc.numSidedefs()); } //------------------------------------------------------------------------ class UI_Check_Sectors : public UI_Check_base { public: UI_Check_Sectors(bool all_mode, Instance &inst) : UI_Check_base(530, 346, all_mode, "Check : Sectors", "Sector test results"), inst(inst) { } static void action_remove(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; Sectors_RemoveUnused(dialog->inst.level); dialog->user_action = CheckResult::tookAction; } static void action_remove_sidedefs(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; SideDefs_RemoveUnused(dialog->inst.level); dialog->user_action = CheckResult::tookAction; } static void action_fix_ceil(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; Sectors_FixBadCeil(dialog->inst.level); dialog->user_action = CheckResult::tookAction; } static void action_show_ceil(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; Sectors_ShowBadCeil(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_unpack(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; dialog->inst.level.checks.sidedefsUnpack(false); dialog->user_action = CheckResult::highlight; } static void action_show_packed(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; SideDefs_ShowPacked(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_show_unclosed(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; Sectors_ShowUnclosed(ObjType::sectors, dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_show_un_verts(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; Sectors_ShowUnclosed(ObjType::vertices, dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_show_mismatch(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; Sectors_ShowMismatches(ObjType::sectors, dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_show_mis_lines(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; Sectors_ShowMismatches(ObjType::linedefs, dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_show_unknown(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; Sectors_ShowUnknown(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_log_unknown(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; Sectors_LogUnknown(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_clear_unknown(Fl_Widget *w, void *data) { UI_Check_Sectors *dialog = (UI_Check_Sectors *)data; Sectors_ClearUnknown(dialog->inst); dialog->user_action = CheckResult::tookAction; } private: Instance &inst; }; CheckResult ChecksModule::checkSectors(int min_severity) const { UI_Check_Sectors *dialog = new UI_Check_Sectors(min_severity > 0, inst); selection_c sel, other; std::map types; SString check_message; for (;;) { Sectors_FindUnclosed(sel, other, doc); if (sel.empty()) dialog->AddLine("No unclosed sectors"); else { check_message = SString::printf("%d unclosed sectors", sel.count_obj()); dialog->AddLine(check_message, 2, 220, "Show", &UI_Check_Sectors::action_show_unclosed, "Verts", &UI_Check_Sectors::action_show_un_verts); } Sectors_FindMismatches(sel, other, inst); if (sel.empty()) dialog->AddLine("No mismatched sectors"); else { check_message = SString::printf("%d mismatched sectors", sel.count_obj()); dialog->AddLine(check_message, 2, 220, "Show", &UI_Check_Sectors::action_show_mismatch, "Lines", &UI_Check_Sectors::action_show_mis_lines); } Sectors_FindBadCeil(sel, doc); if (sel.empty()) dialog->AddLine("No sectors with ceil < floor"); else { check_message = SString::printf("%d sectors with ceil < floor", sel.count_obj()); dialog->AddLine(check_message, 2, 220, "Show", &UI_Check_Sectors::action_show_ceil, "Fix", &UI_Check_Sectors::action_fix_ceil); } dialog->AddGap(10); Sectors_FindUnknown(sel, types, inst); if (sel.empty()) dialog->AddLine("No unknown sector types"); else { check_message = SString::printf("%d unknown sector types", (int)types.size()); dialog->AddLine(check_message, 2, 220, "Show", &UI_Check_Sectors::action_show_unknown, "Log", &UI_Check_Sectors::action_log_unknown, "Clear", &UI_Check_Sectors::action_clear_unknown); } SideDefs_FindPacking(sel, other, doc); if (sel.empty()) dialog->AddLine("No shared sidedefs"); else { int approx_num = sel.count_obj(); check_message = SString::printf("%d shared sidedefs", approx_num); dialog->AddLine(check_message, 1, 200, "Show", &UI_Check_Sectors::action_show_packed, "Unpack", &UI_Check_Sectors::action_unpack); } Sectors_FindUnused(sel, doc); if (sel.empty()) dialog->AddLine("No unused sectors"); else { check_message = SString::printf("%d unused sectors", sel.count_obj()); dialog->AddLine(check_message, 1, 170, "Remove", &UI_Check_Sectors::action_remove); } SideDefs_FindUnused(sel, doc); if (sel.empty()) dialog->AddLine("No unused sidedefs"); else { check_message = SString::printf("%d unused sidedefs", sel.count_obj()); dialog->AddLine(check_message, 1, 170, "Remove", &UI_Check_Sectors::action_remove_sidedefs); } // in "ALL" mode, just continue if not too severe if (dialog->WorstSeverity() < min_severity) { delete dialog; return CheckResult::ok; } CheckResult result = dialog->Run(); if (result == CheckResult::tookAction) { // repeat the tests dialog->Reset(); continue; } delete dialog; return result; } } //------------------------------------------------------------------------ void Things_FindUnknown(selection_c& list, std::map& types, const Instance &inst) { types.clear(); list.change_type(ObjType::things); for (int n = 0 ; n < inst.level.numThings() ; n++) { const thingtype_t &info = inst.conf.getThingType(inst.level.things[n]->type); if (info.desc.startsWith("UNKNOWN")) { bump_unknown_type(types, inst.level.things[n]->type); list.set(n); } } } static void Things_ShowUnknown(Instance &inst) { if (inst.edit.mode != ObjType::things) inst.Editor_ChangeMode('t'); std::map types; Things_FindUnknown(*inst.edit.Selected, types, inst); inst.GoToErrors(); } static void Things_LogUnknown(const Instance &inst) { selection_c sel; std::map types; std::map::iterator IT; Things_FindUnknown(sel, types, inst); gLog.printf("\n"); gLog.printf("Unknown Things:\n"); gLog.printf("{\n"); for (IT = types.begin() ; IT != types.end() ; IT++) gLog.printf(" %5d x %d\n", IT->first, IT->second); gLog.printf("}\n"); LogViewer_Open(); } void Things_RemoveUnknown(Instance &inst) { selection_c sel; std::map types; Things_FindUnknown(sel, types, inst); EditOperation op(inst.level.basis); op.setMessage("removed unknown things"); inst.level.objects.del(op, sel); } // this returns a bitmask : bits 0..3 for players 1..4 static int Things_FindStarts(int *dm_num, const Document &doc) { *dm_num = 0; int mask = 0; for(const auto &T : doc.things) { // ideally, these type numbers would not be hard-coded.... switch (T->type) { case 1: mask |= (1 << 0); break; case 2: mask |= (1 << 1); break; case 3: mask |= (1 << 2); break; case 4: mask |= (1 << 3); break; case 11: *dm_num += 1; break; } } return mask; } static void Things_FindInVoid(selection_c& list, const Instance &inst) { list.change_type(ObjType::things); for (int n = 0 ; n < inst.level.numThings() ; n++) { v2double_t pos = inst.level.things[n]->xy(); Objid obj = hover::getNearestSector(inst.level, pos); if (! obj.is_nil()) continue; // allow certain things in the void (Heretic sounds) const thingtype_t &info = inst.conf.getThingType(inst.level.things[n]->type); if (info.flags & THINGDEF_VOID) continue; // check more coords around the thing's centre, to be sure int out_count = 0; for (int corner = 0 ; corner < 4 ; corner++) { v2double_t pos2 = pos + v2double_t{ corner & 1 ? -4.0 : +4.0, corner & 2 ? -4.0 : +4.0 }; obj = hover::getNearestSector(inst.level, pos2); if (obj.is_nil()) out_count++; } if (out_count == 4) list.set(n); } } static void Things_ShowInVoid(Instance &inst) { if (inst.edit.mode != ObjType::things) inst.Editor_ChangeMode('t'); Things_FindInVoid(*inst.edit.Selected, inst); inst.GoToErrors(); } static void Things_RemoveInVoid(Instance &inst) { selection_c sel; Things_FindInVoid(sel, inst); EditOperation op(inst.level.basis); op.setMessage("removed things in the void"); inst.level.objects.del(op, sel); } // returns true if the game engine ALWAYS spawns this thing // (i.e. the skill-flags and mode-flags are ignored). static bool TH_always_spawned(const Instance &inst, int type) { const thingtype_t &info = inst.conf.getThingType(type); // a player? if (1 <= type && type <= 4) return true; // a deathmatch start? if (type == 11) return true; // Polyobject things if (info.desc.find("Polyobj") != SString::npos || info.desc.find("PolyObj") != SString::npos) { return true; } // ambient sounds in Heretic and Hexen if (info.desc.find("Snd") != SString::npos || info.desc.find("Sound") != SString::npos) return true; return false; } static void Things_FindDuds(const Instance &inst, selection_c& list) { list.change_type(ObjType::things); for (int n = 0 ; n < inst.level.numThings() ; n++) { const auto T = inst.level.things[n]; if (T->type == CAMERA_PEST) continue; int skills = T->options & (MTF_Easy | MTF_Medium | MTF_Hard); int modes = 1; int classes = 1; if (inst.loaded.levelFormat != MapFormat::doom) { modes = T->options & (MTF_Hexen_SP | MTF_Hexen_COOP | MTF_Hexen_DM); } else if (inst.conf.features.coop_dm_flags) { modes = (~T->options) & (MTF_Not_SP | MTF_Not_COOP | MTF_Not_DM); } if (inst.loaded.levelFormat != MapFormat::doom) { classes = T->options & (MTF_Hexen_Cleric | MTF_Hexen_Fighter | MTF_Hexen_Mage); } if (skills == 0 || modes == 0 || classes == 0) { if (! TH_always_spawned(inst, T->type)) list.set(n); } } } static void Things_ShowDuds(Instance &inst) { if (inst.edit.mode != ObjType::things) inst.Editor_ChangeMode('t'); Things_FindDuds(inst, *inst.edit.Selected); inst.GoToErrors(); } void Things_FixDuds(Instance &inst) { EditOperation op(inst.level.basis); op.setMessage("fixed unspawnable things"); for (int n = 0 ; n < inst.level.numThings() ; n++) { const auto T = inst.level.things[n]; // NOTE: we also "fix" things that are always spawned //// if (TH_always_spawned(T->type)) continue; if (T->type == CAMERA_PEST) continue; int new_options = T->options; int skills = T->options & (MTF_Easy | MTF_Medium | MTF_Hard); int modes = 1; int classes = 1; if (skills == 0) new_options |= MTF_Easy | MTF_Medium | MTF_Hard; if (inst.loaded.levelFormat != MapFormat::doom) { modes = T->options & (MTF_Hexen_SP | MTF_Hexen_COOP | MTF_Hexen_DM); if (modes == 0) new_options |= MTF_Hexen_SP | MTF_Hexen_COOP | MTF_Hexen_DM; } else if (inst.conf.features.coop_dm_flags) { modes = (~T->options) & (MTF_Not_SP | MTF_Not_COOP | MTF_Not_DM); if (modes == 0) new_options &= ~(MTF_Not_SP | MTF_Not_COOP | MTF_Not_DM); } if (inst.loaded.levelFormat != MapFormat::doom) { classes = T->options & (MTF_Hexen_Cleric | MTF_Hexen_Fighter | MTF_Hexen_Mage); if (classes == 0) new_options |= MTF_Hexen_Cleric | MTF_Hexen_Fighter | MTF_Hexen_Mage; } if (new_options != T->options) { op.changeThing(n, Thing::F_OPTIONS, new_options); } } } //------------------------------------------------------------------------ static void CollectBlockingThings(std::vector& list, std::vector& sizes, const Instance &inst) { for (int n = 0 ; n < inst.level.numThings() ; n++) { const auto T = inst.level.things[n]; const thingtype_t &info = inst.conf.getThingType(T->type); if (info.flags & THINGDEF_PASS) continue; // ignore unknown things if (info.desc.startsWith("UNKNOWN")) continue; // TODO: config option: treat ceiling things as non-blocking list.push_back(n); sizes.push_back(info.radius); } } /* andrewj: the DOOM movement code for monsters works by moving the actor by a stepping distance which is based on its 'speed' value. The move is allowed when the *new position* has no blocking things or walls, which means that things can overlap a short distance and won't be stuck. Properly taking this into account requires knowing the speed of each individual monster, but we don't have that information here. Hence I've chosen a conservative value based on the speed of the slowest monster (8 units). TODO: make it either game config or user preference. */ #define MONSTER_STEP_DIST 8 static bool ThingStuckInThing(const Instance &inst, const Thing *T1, const thingtype_t *info1, const Thing *T2, const thingtype_t *info2) { SYS_ASSERT(T1 != T2); // require one thing to be a monster or player bool is_actor1 = (info1->group == 'm' || info1->group == 'p'); bool is_actor2 = (info2->group == 'm' || info2->group == 'p'); if (! (is_actor1 || is_actor2)) return false; // check if T1 is stuck in T2 int r1 = info1->radius; int r2 = info2->radius; if (info1->group == 'm' && info2->group != 'p') r1 = std::max(4, r1 - MONSTER_STEP_DIST); else if (info2->group == 'm' && info1->group != 'p') r2 = std::max(4, r2 - MONSTER_STEP_DIST); if (T1->x() - r1 >= T2->x() + r2) return false; if (T1->y() - r1 >= T2->y() + r2) return false; if (T1->x() + r1 <= T2->x() - r2) return false; if (T1->y() + r1 <= T2->y() - r2) return false; // teleporters and DM starts can safely overlap moving actors if ((info1->flags & THINGDEF_TELEPT) && is_actor2) return false; if ((info2->flags & THINGDEF_TELEPT) && is_actor1) return false; // check skill bits, except for players int opt1 = T1->options; int opt2 = T2->options; if (inst.loaded.levelFormat != MapFormat::doom) { if (info1->group == 'p') opt1 |= 0x7E7; if (info2->group == 'p') opt2 |= 0x7E7; // check skill bits if ((opt1 & opt2 & 0x07) == 0) return false; // check class bits if ((opt1 & opt2 & 0xE0) == 0) return false; // check game mode if ((opt1 & opt2 & 0x700) == 0) return false; } else { // invert game-mode bits (MTF_Not_COOP etc) opt1 ^= 0x70; opt2 ^= 0x70; if (info1->group == 'p') opt1 |= 0x77; if (info2->group == 'p') opt2 |= 0x77; // check skill bits if ((opt1 & opt2 & 0x07) == 0) return false; // check game mode if ((opt1 & opt2 & 0x70) == 0) return false; } return true; } static inline bool LD_is_blocking(const LineDef *L, const Document &doc) { #define MONSTER_HEIGHT 36 // ignore virtual linedefs if (L->right < 0 && L->left < 0) return false; if (L->right < 0 || L->left < 0) return true; const auto &S1 = doc.getSector(*doc.getRight(*L)); const auto &S2 = doc.getSector(*doc.getLeft(*L)); int f_max = std::max(S1.floorh, S2.floorh); int c_min = std::min(S1.ceilh, S2.ceilh); return (c_min < f_max + MONSTER_HEIGHT); } static bool ThingStuckInWall(const Thing *T, int r, char group, const Document &doc) { // only check players and monsters if (! (group == 'p' || group == 'm')) return false; if (group == 'm') r = std::max(4, r - MONSTER_STEP_DIST); // shrink a tiny bit, because we need to find lines which CROSS the // bounding box, not just touch it. r = r - 1; double x1 = T->x() - r; double y1 = T->y() - r; double x2 = T->x() + r; double y2 = T->y() + r; for (int n = 0 ; n < doc.numLinedefs(); n++) { const auto L = doc.linedefs[n]; if (! LD_is_blocking(L.get(), doc)) continue; if (doc.objects.lineTouchesBox(n, x1, y1, x2, y2)) return true; } return false; } static void Things_FindStuckies(selection_c& list, const Instance &inst) { list.change_type(ObjType::things); std::vector blockers; std::vector sizes; CollectBlockingThings(blockers, sizes, inst); for (int n = 0 ; n < (int)blockers.size() ; n++) { const auto T = inst.level.things[blockers[n]]; const thingtype_t &info = inst.conf.getThingType(T->type); if (ThingStuckInWall(T.get(), info.radius, info.group, inst.level)) list.set(blockers[n]); for (int n2 = n + 1 ; n2 < (int)blockers.size() ; n2++) { const auto T2 = inst.level.things[blockers[n2]]; const thingtype_t &info2 = inst.conf.getThingType(T2->type); if (ThingStuckInThing(inst, T.get(), &info, T2.get(), &info2)) list.set(blockers[n]); } } } static void Things_ShowStuckies(Instance &inst) { if (inst.edit.mode != ObjType::things) inst.Editor_ChangeMode('t'); Things_FindStuckies(*inst.edit.Selected, inst); inst.GoToErrors(); } //------------------------------------------------------------------------ class UI_Check_Things : public UI_Check_base { public: UI_Check_Things(bool all_mode, Instance &inst) : UI_Check_base(520, 316, all_mode, "Check : Things", "Thing test results"), inst(inst) { } public: static void action_show_unknown(Fl_Widget *w, void *data) { UI_Check_Things *dialog = (UI_Check_Things *)data; Things_ShowUnknown(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_log_unknown(Fl_Widget *w, void *data) { UI_Check_Things *dialog = (UI_Check_Things *)data; Things_LogUnknown(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_remove_unknown(Fl_Widget *w, void *data) { UI_Check_Things *dialog = (UI_Check_Things *)data; Things_RemoveUnknown(dialog->inst); dialog->user_action = CheckResult::tookAction; } static void action_show_void(Fl_Widget *w, void *data) { UI_Check_Things *dialog = (UI_Check_Things *)data; Things_ShowInVoid(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_remove_void(Fl_Widget *w, void *data) { UI_Check_Things *dialog = (UI_Check_Things *)data; Things_RemoveInVoid(dialog->inst); dialog->user_action = CheckResult::tookAction; } static void action_show_stuck(Fl_Widget *w, void *data) { UI_Check_Things *dialog = (UI_Check_Things *)data; Things_ShowStuckies(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_show_duds(Fl_Widget *w, void *data) { UI_Check_Things *dialog = (UI_Check_Things *)data; Things_ShowDuds(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_fix_duds(Fl_Widget *w, void *data) { UI_Check_Things *dialog = (UI_Check_Things *)data; Things_FixDuds(dialog->inst); dialog->user_action = CheckResult::tookAction; } private: Instance &inst; }; CheckResult ChecksModule::checkThings(int min_severity) const { UI_Check_Things *dialog = new UI_Check_Things(min_severity > 0, inst); selection_c sel; std::map types; SString check_message; for (;;) { Things_FindUnknown(sel, types, inst); if (sel.empty()) dialog->AddLine("No unknown thing types"); else { check_message = SString::printf("%d unknown things", (int)types.size()); dialog->AddLine(check_message, 2, 200, "Show", &UI_Check_Things::action_show_unknown, "Log", &UI_Check_Things::action_log_unknown, "Remove", &UI_Check_Things::action_remove_unknown); } Things_FindStuckies(sel, inst); if (sel.empty()) dialog->AddLine("No stuck actors"); else { check_message = SString::printf("%d stuck actors", sel.count_obj()); dialog->AddLine(check_message, 2, 200, "Show", &UI_Check_Things::action_show_stuck); } Things_FindInVoid(sel, inst); if (sel.empty()) dialog->AddLine("No things in the void"); else { check_message = SString::printf("%d things in the void", sel.count_obj()); dialog->AddLine(check_message, 1, 200, "Show", &UI_Check_Things::action_show_void, "Remove", &UI_Check_Things::action_remove_void); } Things_FindDuds(inst, sel); if (sel.empty()) dialog->AddLine("No unspawnable things -- skill flags are OK"); else { check_message = SString::printf("%d unspawnable things", sel.count_obj()); dialog->AddLine(check_message, 1, 200, "Show", &UI_Check_Things::action_show_duds, "Fix", &UI_Check_Things::action_fix_duds); } dialog->AddGap(10); int dm_num, mask; mask = Things_FindStarts(&dm_num, doc); if (inst.conf.features.no_need_players) dialog->AddLine("Player starts not needed, no check done"); else if (! (mask & 1)) dialog->AddLine("Player 1 start is missing!", 2); else if (! (mask & 2)) dialog->AddLine("Player 2 start is missing", 1); else if (! (mask & 4)) dialog->AddLine("Player 3 start is missing", 1); else if (! (mask & 8)) dialog->AddLine("Player 4 start is missing", 1); else dialog->AddLine("Found all 4 player starts"); if (inst.conf.features.no_need_players) { // leave a blank space } else if (dm_num == 0) { dialog->AddLine("Map is missing deathmatch starts", 1); } else if (dm_num < inst.conf.miscInfo.min_dm_starts) { check_message = SString::printf("Found %d deathmatch starts -- need at least %d", dm_num, inst.conf.miscInfo.min_dm_starts); dialog->AddLine(check_message, 1); } else if (dm_num > inst.conf.miscInfo.max_dm_starts) { check_message = SString::printf("Found %d deathmatch starts -- maximum is %d", dm_num, inst.conf.miscInfo.max_dm_starts); dialog->AddLine(check_message, 2); } else { check_message = SString::printf("Found %d deathmatch starts -- OK", dm_num); dialog->AddLine(check_message); } // in "ALL" mode, just continue if not too severe if (dialog->WorstSeverity() < min_severity) { delete dialog; return CheckResult::ok; } CheckResult result = dialog->Run(); if (result == CheckResult::tookAction) { // repeat the tests dialog->Reset(); continue; } delete dialog; return result; } } //------------------------------------------------------------------------ static void LineDefs_FindZeroLen(selection_c& lines, const Document &doc) { lines.change_type(ObjType::linedefs); for (int n = 0 ; n < doc.numLinedefs(); n++) if (doc.isZeroLength(*doc.linedefs[n])) lines.set(n); } static void LineDefs_RemoveZeroLen(Document &doc) { selection_c lines(ObjType::linedefs); for (int n = 0 ; n < doc.numLinedefs(); n++) { if (doc.isZeroLength(*doc.linedefs[n])) lines.set(n); } EditOperation op(doc.basis); op.setMessage("removed zero-len linedefs"); // NOTE: the vertex overlapping test handles cases where the // vertices of other lines joining a zero-length one // need to be merged. DeleteObjects_WithUnused(op, doc, lines, false, false, false); } static void LineDefs_ShowZeroLen(Instance &inst) { if (inst.edit.mode != ObjType::vertices) inst.Editor_ChangeMode('v'); selection_c sel; LineDefs_FindZeroLen(sel, inst.level); ConvertSelection(inst.level, sel, *inst.edit.Selected); inst.GoToErrors(); } static void LineDefs_FindMissingRight(selection_c& lines, const Document &doc) { lines.change_type(ObjType::linedefs); for (int n = 0 ; n < doc.numLinedefs(); n++) if (doc.linedefs[n]->right < 0) lines.set(n); } static void LineDefs_ShowMissingRight(Instance &inst) { if (inst.edit.mode != ObjType::linedefs) inst.Editor_ChangeMode('l'); LineDefs_FindMissingRight(*inst.edit.Selected, inst.level); inst.GoToErrors(); } static void LineDefs_FindManualDoors(selection_c& lines, const Instance &inst) { // find D1/DR manual doors on one-sided linedefs lines.change_type(ObjType::linedefs); for (int n = 0 ; n < inst.level.numLinedefs(); n++) { const auto L = inst.level.linedefs[n]; if (L->type <= 0) continue; if (L->left >= 0) continue; const linetype_t &info = inst.conf.getLineType(L->type); if (info.desc[0] == 'D' && (info.desc[1] == '1' || info.desc[1] == 'R')) { lines.set(n); } } } static void LineDefs_ShowManualDoors(Instance &inst) { if (inst.edit.mode != ObjType::linedefs) inst.Editor_ChangeMode('l'); LineDefs_FindManualDoors(*inst.edit.Selected, inst); inst.GoToErrors(); } static void LineDefs_FixManualDoors(Instance &inst) { EditOperation op(inst.level.basis); op.setMessage("fixed manual doors"); for (int n = 0 ; n < inst.level.numLinedefs(); n++) { const auto L = inst.level.linedefs[n]; if (L->type <= 0 || L->left >= 0) continue; const linetype_t &info = inst.conf.getLineType(L->type); if (info.desc[0] == 'D' && (info.desc[1] == '1' || info.desc[1] == 'R')) { op.changeLinedef(n, LineDef::F_TYPE, 0); } } } static void LineDefs_FindLackImpass(selection_c& lines, const Document &doc) { lines.change_type(ObjType::linedefs); for (int n = 0 ; n < doc.numLinedefs(); n++) { const auto L = doc.linedefs[n]; if (L->OneSided() && (L->flags & MLF_Blocking) == 0) lines.set(n); } } static void LineDefs_ShowLackImpass(Instance &inst) { if (inst.edit.mode != ObjType::linedefs) inst.Editor_ChangeMode('l'); LineDefs_FindLackImpass(*inst.edit.Selected, inst.level); inst.GoToErrors(); } static void LineDefs_FixLackImpass(Document &doc) { EditOperation op(doc.basis); op.setMessage("fixed impassible flags"); for (int n = 0 ; n < doc.numLinedefs(); n++) { const auto L = doc.linedefs[n]; if (L->OneSided() && (L->flags & MLF_Blocking) == 0) { int new_flags = L->flags | MLF_Blocking; op.changeLinedef(n, LineDef::F_FLAGS, new_flags); } } } static void LineDefs_FindBad2SFlag(selection_c& lines, const Document &doc) { lines.change_type(ObjType::linedefs); for (int n = 0 ; n < doc.numLinedefs(); n++) { const auto L = doc.linedefs[n]; if (L->OneSided() && (L->flags & MLF_TwoSided)) lines.set(n); if (L->TwoSided() && ! (L->flags & MLF_TwoSided)) lines.set(n); } } static void LineDefs_ShowBad2SFlag(Instance &inst) { if (inst.edit.mode != ObjType::linedefs) inst.Editor_ChangeMode('l'); LineDefs_FindBad2SFlag(*inst.edit.Selected, inst.level); inst.GoToErrors(); } static void LineDefs_FixBad2SFlag(Document &doc) { EditOperation op(doc.basis); op.setMessage("fixed two-sided flags"); for (int n = 0 ; n < doc.numLinedefs(); n++) { const auto L = doc.linedefs[n]; if (L->OneSided() && (L->flags & MLF_TwoSided)) op.changeLinedef(n, LineDef::F_FLAGS, L->flags & ~MLF_TwoSided); if (L->TwoSided() && ! (L->flags & MLF_TwoSided)) op.changeLinedef(n, LineDef::F_FLAGS, L->flags | MLF_TwoSided); } } static void bung_unknown_type(std::map& t_map, int type) { int count = 0; if (t_map.find(type) != t_map.end()) count = t_map[type]; t_map[type] = count + 1; } static void LineDefs_FindUnknown(selection_c& list, std::map& types, const Instance &inst) { types.clear(); list.change_type(ObjType::linedefs); for (int n = 0 ; n < inst.level.numLinedefs(); n++) { int type_num = inst.level.linedefs[n]->type; // always ignore type #0 if (type_num == 0) continue; const linetype_t &info = inst.conf.getLineType(type_num); // Boom generalized line type? if (inst.conf.features.gen_types && is_genline(type_num)) continue; if (info.desc.startsWith("UNKNOWN")) { bung_unknown_type(types, type_num); list.set(n); } } } static void LineDefs_ShowUnknown(Instance &inst) { if (inst.edit.mode != ObjType::linedefs) inst.Editor_ChangeMode('l'); std::map types; LineDefs_FindUnknown(*inst.edit.Selected, types, inst); inst.GoToErrors(); } static void LineDefs_LogUnknown(const Instance &inst) { selection_c sel; std::map types; std::map::iterator IT; LineDefs_FindUnknown(sel, types, inst); gLog.printf("\n"); gLog.printf("Unknown Line Types:\n"); gLog.printf("{\n"); for (IT = types.begin() ; IT != types.end() ; IT++) gLog.printf(" %5d x %d\n", IT->first, IT->second); gLog.printf("}\n"); LogViewer_Open(); } static void LineDefs_ClearUnknown(Instance &inst) { selection_c sel; std::map types; LineDefs_FindUnknown(sel, types, inst); EditOperation op(inst.level.basis); op.setMessage("cleared unknown line types"); for (sel_iter_c it(sel) ; !it.done() ; it.next()) op.changeLinedef(*it, LineDef::F_TYPE, 0); } //------------------------------------------------------------------------ static int linedef_pos_cmp(int A, int B, const Document &doc) { const auto AL = doc.linedefs[A]; const auto BL = doc.linedefs[B]; int A_x1 = static_cast(doc.getStart(*AL).x()); int A_y1 = static_cast(doc.getStart(*AL).y()); int A_x2 = static_cast(doc.getEnd(*AL).x()); int A_y2 = static_cast(doc.getEnd(*AL).y()); int B_x1 = static_cast(doc.getStart(*BL).x()); int B_y1 = static_cast(doc.getStart(*BL).y()); int B_x2 = static_cast(doc.getEnd(*BL).x()); int B_y2 = static_cast(doc.getEnd(*BL).y()); if (A_x1 > A_x2 || (A_x1 == A_x2 && A_y1 > A_y2)) { std::swap(A_x1, A_x2); std::swap(A_y1, A_y2); } if (B_x1 > B_x2 || (B_x1 == B_x2 && B_y1 > B_y2)) { std::swap(B_x1, B_x2); std::swap(B_y1, B_y2); } // the "normalized" X1 coordinates is the most significant thing in // this comparison function. if (A_x1 != B_x1) return A_x1 - B_x1; if (A_y1 != B_y1) return A_y1 - B_y1; if (A_x2 != B_x2) return A_x2 - B_x2; if (A_y2 != B_y2) return A_y2 - B_y2; return 0; // equal : lines are overlapping } struct linedef_pos_CMP_pred { const Document &doc; inline bool operator() (int A, int B) const { return linedef_pos_cmp(A, B, doc) < 0; } }; struct linedef_minx_CMP_pred { const Document &doc; inline bool operator() (int A, int B) const { const auto AL = doc.linedefs[A]; const auto BL = doc.linedefs[B]; FFixedPoint A_x = std::min(doc.getStart(*AL).raw_x, doc.getEnd(*AL).raw_x); FFixedPoint B_x = std::min(doc.getStart(*BL).raw_x, doc.getEnd(*BL).raw_x); return A_x < B_x; } }; static void LineDefs_FindOverlaps(selection_c& lines, const Document &doc) { // we only find directly overlapping linedefs here lines.change_type(ObjType::linedefs); if (doc.numLinedefs() < 2) return; int n; // sort linedefs by their position. overlapping lines will end up // adjacent to each other after the sort. std::vector sorted_list(doc.numLinedefs(), 0); for (n = 0 ; n < doc.numLinedefs(); n++) sorted_list[n] = n; std::sort(sorted_list.begin(), sorted_list.end(), linedef_pos_CMP_pred{ doc }); for (n = 0 ; n < doc.numLinedefs() - 1 ; n++) { int ld1 = sorted_list[n]; int ld2 = sorted_list[n + 1]; // ignore zero-length lines if (doc.isZeroLength(*doc.linedefs[ld2])) continue; // only the second (or third, etc) linedef is stored if (linedef_pos_cmp(ld1, ld2, doc) == 0) lines.set(ld2); } } static void LineDefs_ShowOverlaps(Instance &inst) { if (inst.edit.mode != ObjType::linedefs) inst.Editor_ChangeMode('l'); LineDefs_FindOverlaps(*inst.edit.Selected, inst.level); inst.GoToErrors(); } static void LineDefs_RemoveOverlaps(Document &doc) { selection_c lines, unused_verts; LineDefs_FindOverlaps(lines, doc); UnusedVertices(doc, lines, unused_verts); EditOperation op(doc.basis); op.setMessage("removed overlapping lines"); doc.objects.del(op, lines); doc.objects.del(op, unused_verts); } static int CheckLinesCross(int A, int B, const Document &doc) { // return values: // 0 : the lines do not cross // 1 : A is sitting on B (a 'T' junction) // 2 : B is sitting on A (a 'T' junction) // 3 : the lines cross each other (an 'X' junction) // 4 : the lines are co-linear and partially overlap const double epsilon = 0.02; SYS_ASSERT(A != B); const auto AL = doc.linedefs[A]; const auto BL = doc.linedefs[B]; // ignore zero-length lines if (doc.isZeroLength(*AL) || doc.isZeroLength(*BL)) return 0; // ignore directly overlapping here if (linedef_pos_cmp(A, B, doc) == 0) return 0; // bbox test // // the algorithm in LineDefs_FindCrossings() ensures that A and B // already overlap on the X axis. hence only check Y axis here. if (std::min(doc.getStart(*AL).raw_y, doc.getEnd(*AL).raw_y) > std::max(doc.getStart(*BL).raw_y, doc.getEnd(*BL).raw_y)) { return 0; } if (std::min(doc.getStart(*BL).raw_y, doc.getEnd(*BL).raw_y) > std::max(doc.getStart(*AL).raw_y, doc.getEnd(*AL).raw_y)) { return 0; } // precise (but slower) intersection test v2double_t av1 = doc.getStart(*AL).xy(); v2double_t av2 = doc.getEnd(*AL).xy(); v2double_t bv1 = doc.getStart(*BL).xy(); v2double_t bv2 = doc.getEnd(*BL).xy(); double c = PerpDist(bv1, av1, av2); double d = PerpDist(bv2, av1, av2); int c_side = (c < -epsilon) ? -1 : (c > epsilon) ? +1 : 0; int d_side = (d < -epsilon) ? -1 : (d > epsilon) ? +1 : 0; if (c_side != 0 && c_side == d_side) return 0; double e = PerpDist(av1, bv1, bv2); double f = PerpDist(av2, bv1, bv2); int e_side = (e < -epsilon) ? -1 : (e > epsilon) ? +1 : 0; int f_side = (f < -epsilon) ? -1 : (f > epsilon) ? +1 : 0; if (e_side != 0 && e_side == f_side) return 0; // check whether the two lines definitely cross each other // at a single point (like an 'X' shape), or not. bool a_crossed = (c_side * d_side != 0); bool b_crossed = (e_side * f_side != 0); if (a_crossed && b_crossed) return 3; // are the two lines are co-linear (or very close to it) ? // if so, check the separation between them... if ((c_side == 0 && d_side == 0) || (e_side == 0 && f_side == 0)) { // choose longest line as the measuring stick if (doc.calcLength(*AL) < doc.calcLength(*BL)) { std::swap(av1, bv1); std::swap(av2, bv2); // A, B, AL, BL should not be used from here on! } c = AlongDist(bv1, av1, av2); d = AlongDist(bv2, av1, av2); e = AlongDist(av2, av1, av2); // just the length if (std::max(c, d) < epsilon) return 0; if (std::min(c, d) > e - epsilon) return 0; // colinear and partially overlapping return 4; } // this handles the case where the two linedefs meet at a vertex // but are not overlapping at all. if (! a_crossed && ! b_crossed) return 0; // in this case we have a 'T' junction, where the end-point of // one linedef is sitting along the other one. return a_crossed ? 2 : 1; } static void LineDefs_FindCrossings(selection_c& lines, const Document &doc) { lines.change_type(ObjType::linedefs); if (doc.numLinedefs() < 2) return; int n; // sort linedefs by their position. linedefs which cross will be // near each other in this list. std::vector sorted_list(doc.numLinedefs(), 0); for (n = 0 ; n < doc.numLinedefs(); n++) sorted_list[n] = n; std::sort(sorted_list.begin(), sorted_list.end(), linedef_minx_CMP_pred{ doc }); for (n = 0 ; n < doc.numLinedefs(); n++) { int n2 = sorted_list[n]; const auto L1 = doc.linedefs[n2]; FFixedPoint max_x = std::max(doc.getStart(*L1).raw_x, doc.getEnd(*L1).raw_x); for (int k = n + 1 ; k < doc.numLinedefs(); k++) { int k2 = sorted_list[k]; const auto L2 = doc.linedefs[k2]; FFixedPoint min_x = std::min(doc.getStart(*L2).raw_x, doc.getEnd(*L2).raw_x); // stop when all remaining linedefs are to the right of L1 if (min_x > max_x) break; int res = CheckLinesCross(n2, k2, doc); if (res) { lines.set(n2); lines.set(k2); } } } } static void LineDefs_ShowCrossings(Instance &inst) { if (inst.edit.mode != ObjType::linedefs) inst.Editor_ChangeMode('l'); LineDefs_FindCrossings(*inst.edit.Selected, inst.level); inst.GoToErrors(); } //------------------------------------------------------------------------ class UI_Check_LineDefs : public UI_Check_base { public: UI_Check_LineDefs(bool all_mode, Instance &inst) : UI_Check_base(530, 370, all_mode, "Check : LineDefs", "LineDef test results"), inst(inst) { } public: static void action_show_zero(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_ShowZeroLen(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_remove_zero(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_RemoveZeroLen(dialog->inst.level); dialog->user_action = CheckResult::tookAction; } static void action_show_mis_right(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_ShowMissingRight(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_show_manual_doors(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_ShowManualDoors(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_fix_manual_doors(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_FixManualDoors(dialog->inst); dialog->user_action = CheckResult::tookAction; } static void action_show_lack_impass(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_ShowLackImpass(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_fix_lack_impass(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_FixLackImpass(dialog->inst.level); dialog->user_action = CheckResult::tookAction; } static void action_show_bad_2s_flag(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_ShowBad2SFlag(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_fix_bad_2s_flag(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_FixBad2SFlag(dialog->inst.level); dialog->user_action = CheckResult::tookAction; } static void action_show_unknown(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_ShowUnknown(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_log_unknown(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_LogUnknown(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_clear_unknown(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_ClearUnknown(dialog->inst); dialog->user_action = CheckResult::tookAction; } static void action_remove_overlap(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_RemoveOverlaps(dialog->inst.level); dialog->user_action = CheckResult::tookAction; } static void action_show_overlap(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_ShowOverlaps(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_show_crossing(Fl_Widget *w, void *data) { UI_Check_LineDefs *dialog = (UI_Check_LineDefs *)data; LineDefs_ShowCrossings(dialog->inst); dialog->user_action = CheckResult::highlight; } private: Instance &inst; }; CheckResult ChecksModule::checkLinedefs(int min_severity) const { UI_Check_LineDefs *dialog = new UI_Check_LineDefs(min_severity > 0, inst); selection_c sel, other; std::map types; SString check_buffer; for (;;) { LineDefs_FindZeroLen(sel, doc); if (sel.empty()) dialog->AddLine("No zero-length linedefs"); else { check_buffer = SString::printf("%d zero-length linedefs", sel.count_obj()); dialog->AddLine(check_buffer, 2, 220, "Show", &UI_Check_LineDefs::action_show_zero, "Remove", &UI_Check_LineDefs::action_remove_zero); } LineDefs_FindOverlaps(sel, doc); if (sel.empty()) dialog->AddLine("No overlapping linedefs"); else { check_buffer = SString::printf("%d overlapping linedefs", sel.count_obj()); dialog->AddLine(check_buffer, 2, 220, "Show", &UI_Check_LineDefs::action_show_overlap, "Remove", &UI_Check_LineDefs::action_remove_overlap); } LineDefs_FindCrossings(sel, doc); if (sel.empty()) dialog->AddLine("No criss-crossing linedefs"); else { check_buffer = SString::printf("%d criss-crossing linedefs", sel.count_obj()); dialog->AddLine(check_buffer, 2, 220, "Show", &UI_Check_LineDefs::action_show_crossing); } dialog->AddGap(10); LineDefs_FindUnknown(sel, types, inst); if (sel.empty()) dialog->AddLine("No unknown line types"); else { check_buffer = SString::printf("%d unknown line types", (int)types.size()); dialog->AddLine(check_buffer, 1, 210, "Show", &UI_Check_LineDefs::action_show_unknown, "Log", &UI_Check_LineDefs::action_log_unknown, "Clear", &UI_Check_LineDefs::action_clear_unknown); } LineDefs_FindMissingRight(sel, doc); if (sel.empty()) dialog->AddLine("No linedefs without a right side"); else { check_buffer = SString::printf("%d linedefs without right side", sel.count_obj()); dialog->AddLine(check_buffer, 2, 300, "Show", &UI_Check_LineDefs::action_show_mis_right); } LineDefs_FindManualDoors(sel, inst); if (sel.empty()) dialog->AddLine("No manual doors on 1S linedefs"); else { check_buffer = SString::printf("%d manual doors on 1S linedefs", sel.count_obj()); dialog->AddLine(check_buffer, 2, 300, "Show", &UI_Check_LineDefs::action_show_manual_doors, "Fix", &UI_Check_LineDefs::action_fix_manual_doors); } LineDefs_FindLackImpass(sel, doc); if (sel.empty()) dialog->AddLine("No non-blocking one-sided linedefs"); else { check_buffer = SString::printf("%d non-blocking one-sided linedefs", sel.count_obj()); dialog->AddLine(check_buffer, 1, 300, "Show", &UI_Check_LineDefs::action_show_lack_impass, "Fix", &UI_Check_LineDefs::action_fix_lack_impass); } LineDefs_FindBad2SFlag(sel, doc); if (sel.empty()) dialog->AddLine("No linedefs with wrong 2S flag"); else { check_buffer = SString::printf("%d linedefs with wrong 2S flag", sel.count_obj()); dialog->AddLine(check_buffer, 1, 300, "Show", &UI_Check_LineDefs::action_show_bad_2s_flag, "Fix", &UI_Check_LineDefs::action_fix_bad_2s_flag); } // in "ALL" mode, just continue if not too severe if (dialog->WorstSeverity() < min_severity) { delete dialog; return CheckResult::ok; } CheckResult result = dialog->Run(); if (result == CheckResult::tookAction) { // repeat the tests dialog->Reset(); continue; } delete dialog; return result; } } //------------------------------------------------------------------------ void ChecksModule::tagsUsedRange(int *min_tag, int *max_tag) const { int i; *min_tag = INT_MAX; *max_tag = INT_MIN; for (i = 0 ; i < doc.numLinedefs(); i++) { int tag = doc.linedefs[i]->tag; if (tag > 0) { *min_tag = std::min(*min_tag, tag); *max_tag = std::max(*max_tag, tag); } } for (i = 0 ; i < doc.numSectors() ; i++) { int tag = doc.sectors[i]->tag; // ignore special tags if (inst.conf.features.tag_666 != Tag666Rules::disabled && (tag == 666 || tag == 667)) continue; if (tag > 0) { *min_tag = std::min(*min_tag, tag); *max_tag = std::max(*max_tag, tag); } } // none at all? if (*min_tag > *max_tag) { *min_tag = *max_tag = 0; } } void ChecksModule::tagsApplyNewValue(int new_tag) { // uses the current selection (caller must set it up) bool changed = false; { EditOperation op(doc.basis); op.setMessageForSelection("new tag for", *inst.edit.Selected); for (sel_iter_c it(*inst.edit.Selected); !it.done(); it.next()) { if (inst.edit.mode == ObjType::linedefs) { op.changeLinedef(*it, LineDef::F_TAG, new_tag); changed = true; } else if (inst.edit.mode == ObjType::sectors) { op.changeSector(*it, Sector::F_TAG, new_tag); changed = true; } } } if(changed) inst.tagInMemory = new_tag; } void Instance::CMD_ApplyTag() { if (! (edit.mode == ObjType::sectors || edit.mode == ObjType::linedefs)) { Beep("ApplyTag: wrong mode"); return; } bool do_last = false; SString mode = EXEC_Param[0]; if (mode.empty() || mode.noCaseEqual("fresh")) { // fresh tag } else if (mode.noCaseEqual("last")) { do_last = true; } else { Beep("ApplyTag: unknown keyword: %s\n", mode.c_str()); return; } SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { Beep("ApplyTag: nothing selected"); return; } int new_tag; if(do_last) new_tag = tagInMemory; else new_tag = findFreeTag(*this, edit.mode == ObjType::sectors); if (new_tag <= 0) { Beep("No last tag"); } else if (new_tag > 32767) { Beep("Out of tag numbers"); } else { level.checks.tagsApplyNewValue(new_tag); } if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); } static bool LD_tag_exists(int tag, const Document &doc) { for (const auto &linedef : doc.linedefs) if (linedef->tag == tag) return true; return false; } static bool SEC_tag_exists(int tag, const Document &doc) { for (const auto §or : doc.sectors) if (sector->tag == tag) return true; return false; } static void Tags_FindUnmatchedSectors(selection_c& secs, const Instance &inst) { secs.change_type(ObjType::sectors); for (int s = 0 ; s < inst.level.numSectors(); s++) { int tag = inst.level.sectors[s]->tag; if (tag <= 0) continue; // DOOM and Heretic use tag #666 to open doors (etc) on the // death of boss monsters. if (inst.conf.features.tag_666 != Tag666Rules::disabled && (tag == 666 || tag == 667)) continue; if (! LD_tag_exists(tag, inst.level)) secs.set(s); } } static void Tags_FindUnmatchedLineDefs(selection_c& lines, const Document &doc, const ConfigData &config) { lines.change_type(ObjType::linedefs); for (int n = 0 ; n < doc.numLinedefs(); n++) { const auto L = doc.linedefs[n]; if (L->tag <= 0) continue; if (L->type <= 0) continue; SpecialTagInfo info = {}; bool hasinfo = getSpecialTagInfo(ObjType::linedefs, n, L->type, L.get(), config, info); if(!hasinfo) continue; for(int i = 0; i < info.numtags; ++i) { if(!SEC_tag_exists(info.tags[i], doc)) { lines.set(n); goto nextline; } } for(int i = 0; i < info.numlineids; ++i) { if(!LD_tag_exists(info.lineids[i], doc)) { lines.set(n); goto nextline; } } nextline: ; } } static void Tags_ShowUnmatchedSectors(Instance &inst) { if (inst.edit.mode != ObjType::sectors) inst.Editor_ChangeMode('s'); Tags_FindUnmatchedSectors(*inst.edit.Selected, inst); inst.GoToErrors(); } static void Tags_ShowUnmatchedLineDefs(Instance &inst) { if (inst.edit.mode != ObjType::linedefs) inst.Editor_ChangeMode('l'); Tags_FindUnmatchedLineDefs(*inst.edit.Selected, inst.level, inst.conf); inst.GoToErrors(); } static void Tags_FindMissingTags(selection_c& lines, const Instance &inst) { lines.change_type(ObjType::linedefs); for (int n = 0 ; n < inst.level.numLinedefs(); n++) { const auto L = inst.level.linedefs[n]; if (L->type <= 0) continue; if (L->tag > 0) continue; // use type description to determine if a tag is needed // e.g. D1, DR, --, and lowercase first letter all mean "no tag". // TODO: boom generalized manual doors (etc??) const linetype_t &info = inst.conf.getLineType(L->type); if(info.desc.empty()) { gLog.printf("WARNING: invalid empty description for line type %d\n", L->type); continue; } char first = info.desc[0]; if (first == 'D' || first == '-' || ('a' <= first && first <= 'z')) continue; lines.set(n); } } static void Tags_ShowMissingTags(Instance &inst) { if (inst.edit.mode != ObjType::linedefs) inst.Editor_ChangeMode('l'); Tags_FindMissingTags(*inst.edit.Selected, inst); inst.GoToErrors(); } static bool SEC_check_beast_mark(int tag, const Instance &inst) { if (inst.conf.features.tag_666 == Tag666Rules::disabled) return true; if (tag == 667) { // tag #667 can only be used on MAP07 return inst.loaded.levelName.noCaseEqual("MAP07"); } if (tag == 666) { // for Heretic, the map must be an end-of-episode map: ExM8 if (inst.conf.features.tag_666 == Tag666Rules::heretic) { if (inst.loaded.levelName.length() != 4) return false; return (inst.loaded.levelName[3] == '8'); } // for Doom, either need a particular map, or the presence // of a KEEN thing. if (inst.loaded.levelName.noCaseEqual("E1M8") || inst.loaded.levelName.noCaseEqual("E4M6") || inst.loaded.levelName.noCaseEqual("E4M8") || inst.loaded.levelName.noCaseEqual("MAP07")) { return true; } for (const auto &thing : inst.level.things) { const thingtype_t &info = inst.conf.getThingType(thing->type); if (info.desc.noCaseEqual("Commander Keen")) return true; } return false; } return true; // Ok } static void Tags_FindBeastMarks(selection_c& secs, const Instance &inst) { secs.change_type(ObjType::sectors); for (int s = 0 ; s < inst.level.numSectors(); s++) { int tag = inst.level.sectors[s]->tag; if (! SEC_check_beast_mark(tag, inst)) secs.set(s); } } static void Tags_ShowBeastMarks(Instance &inst) { if (inst.edit.mode != ObjType::sectors) inst.Editor_ChangeMode('s'); Tags_FindBeastMarks(*inst.edit.Selected, inst); inst.GoToErrors(); } //------------------------------------------------------------------------ class UI_Check_Tags : public UI_Check_base { public: int fresh_tag = 0; UI_Check_Tags(bool all_mode, Instance &inst) : UI_Check_base(520, 326, all_mode, "Check : Tags", "Tag test results"), inst(inst) { } static void action_fresh_tag(Fl_Widget *w, void *data) { UI_Check_Tags *dialog = (UI_Check_Tags *)data; // fresh_tag is set externally dialog->inst.level.checks.tagsApplyNewValue(dialog->fresh_tag); dialog->want_close = true; } static void action_show_unmatch_sec(Fl_Widget *w, void *data) { UI_Check_Tags *dialog = (UI_Check_Tags *)data; Tags_ShowUnmatchedSectors(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_show_unmatch_line(Fl_Widget *w, void *data) { UI_Check_Tags *dialog = (UI_Check_Tags *)data; Tags_ShowUnmatchedLineDefs(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_show_missing_tag(Fl_Widget *w, void *data) { UI_Check_Tags *dialog = (UI_Check_Tags *)data; Tags_ShowMissingTags(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_show_beast_marks(Fl_Widget *w, void *data) { UI_Check_Tags *dialog = (UI_Check_Tags *)data; Tags_ShowBeastMarks(dialog->inst); dialog->user_action = CheckResult::highlight; } private: Instance &inst; }; CheckResult ChecksModule::checkTags(int min_severity) const { UI_Check_Tags dialog(min_severity > 0, inst); selection_c sel; SString check_buffer; for (;;) { Tags_FindMissingTags(sel, inst); if (sel.empty()) dialog.AddLine("No linedefs missing a needed tag"); else { check_buffer = SString::printf("%d linedefs missing a needed tag", sel.count_obj()); dialog.AddLine(check_buffer, 2, 320, "Show", &UI_Check_Tags::action_show_missing_tag); } Tags_FindUnmatchedLineDefs(sel, doc, inst.conf); if (sel.empty()) dialog.AddLine("No tagged linedefs w/o a matching sector"); else { check_buffer = SString::printf("%d tagged linedefs w/o a matching sector", sel.count_obj()); dialog.AddLine(check_buffer, 2, 350, "Show", &UI_Check_Tags::action_show_unmatch_line); } Tags_FindUnmatchedSectors(sel, inst); if (sel.empty()) dialog.AddLine("No tagged sectors w/o a matching linedef"); else { check_buffer = SString::printf("%d tagged sectors w/o a matching linedef", sel.count_obj()); dialog.AddLine(check_buffer, 1, 350, "Show", &UI_Check_Tags::action_show_unmatch_sec); } Tags_FindBeastMarks(sel, inst); if (sel.empty()) dialog.AddLine("No sectors with tag 666 or 667 used on the wrong map"); else { check_buffer = SString::printf("%d sectors have an invalid 666/667 tag", sel.count_obj()); dialog.AddLine(check_buffer, 1, 350, "Show", &UI_Check_Tags::action_show_beast_marks); } dialog.AddGap(10); int min_tag, max_tag; tagsUsedRange(&min_tag, &max_tag); if (max_tag <= 0) dialog.AddLine("No tags are in use"); else { check_buffer = SString::printf("Lowest tag: %d Highest tag: %d", min_tag, max_tag); dialog.AddLine(check_buffer); } if ((inst.edit.mode == ObjType::linedefs || inst.edit.mode == ObjType::sectors) && inst.edit.Selected->notempty()) { // always assume sector beastmark tags here dialog.fresh_tag = findFreeTag(inst, true); dialog.AddGap(10); dialog.AddLine("Apply a fresh tag to the selection", 0, 250, "Apply", &UI_Check_Tags::action_fresh_tag); } if (dialog.WorstSeverity() < min_severity) return CheckResult::ok; CheckResult result = dialog.Run(); if (result == CheckResult::tookAction) { // repeat the tests dialog.Reset(); continue; } return result; } } //------------------------------------------------------------------------ static void bump_unknown_name(std::map& list, const SString &name) { int count = 0; if (list.find(name) != list.end()) count = list[name]; list[name] = count + 1; } static void Textures_FindMissing(const Instance &inst, selection_c& lines) { lines.change_type(ObjType::linedefs); for (int n = 0 ; n < inst.level.numLinedefs(); n++) { const auto L = inst.level.linedefs[n]; if (L->right < 0) continue; if (L->OneSided()) { if (is_null_tex(inst.level.getRight(*L)->MidTex())) lines.set(n); } else // Two Sided { const Sector &front = inst.level.getSector(*inst.level.getRight(*L)); const Sector &back = inst.level.getSector(*inst.level.getLeft(*L)); if (front.floorh < back.floorh && is_null_tex(inst.level.getRight(*L)->LowerTex())) lines.set(n); if (back.floorh < front.floorh && is_null_tex(inst.level.getLeft(*L)->LowerTex())) lines.set(n); // missing uppers are OK when between two sky ceilings if (inst.is_sky(front.CeilTex()) && inst.is_sky(back.CeilTex())) continue; if (front.ceilh > back.ceilh && is_null_tex(inst.level.getRight(*L)->UpperTex())) lines.set(n); if (back.ceilh > front.ceilh && is_null_tex(inst.level.getLeft(*L)->UpperTex())) lines.set(n); } } } static void Textures_ShowMissing(Instance &inst) { if (inst.edit.mode != ObjType::linedefs) inst.Editor_ChangeMode('l'); Textures_FindMissing(inst, *inst.edit.Selected); inst.GoToErrors(); } static void Textures_FixMissing(Instance &inst) { StringID new_wall = BA_InternaliseString(inst.conf.default_wall_tex); EditOperation op(inst.level.basis); op.setMessage("fixed missing textures"); for (const auto &L : inst.level.linedefs) { if (L->right < 0) continue; if (L->OneSided()) { if (is_null_tex(inst.level.getRight(*L)->MidTex())) op.changeSidedef(L->right, SideDef::F_MID_TEX, new_wall); } else // Two Sided { const Sector &front = inst.level.getSector(*inst.level.getRight(*L)); const Sector &back = inst.level.getSector(*inst.level.getLeft(*L)); if (front.floorh < back.floorh && is_null_tex(inst.level.getRight(*L)->LowerTex())) op.changeSidedef(L->right, SideDef::F_LOWER_TEX, new_wall); if (back.floorh < front.floorh && is_null_tex(inst.level.getLeft(*L)->LowerTex())) op.changeSidedef(L->left, SideDef::F_LOWER_TEX, new_wall); // missing uppers are OK when between two sky ceilings if (inst.is_sky(front.CeilTex()) && inst.is_sky(back.CeilTex())) continue; if (front.ceilh > back.ceilh && is_null_tex(inst.level.getRight(*L)->UpperTex())) op.changeSidedef(L->right, SideDef::F_UPPER_TEX, new_wall); if (back.ceilh > front.ceilh && is_null_tex(inst.level.getLeft(*L)->UpperTex())) op.changeSidedef(L->left, SideDef::F_UPPER_TEX, new_wall); } } } static bool is_transparent(const Instance &inst, const SString &tex) { // ignore lack of texture here // [ technically "-" is the poster-child of transparency, // but it is handled by the Missing Texture checks ] if (is_null_tex(tex)) return false; const Img_c *img = inst.wad.images.getTexture(inst.conf, tex); if (! img) return false; // note : this is slow return img->has_transparent(); } static int check_transparent(const Instance &inst, const SString &tex, std::map& names) { if (is_transparent(inst, tex)) { bump_unknown_name(names, tex); return 1; } return 0; } static void Textures_FindTransparent(Instance &inst, selection_c& lines, std::map& names) { lines.change_type(ObjType::linedefs); names.clear(); for (int n = 0 ; n < inst.level.numLinedefs(); n++) { const auto L = inst.level.linedefs[n]; if (L->right < 0) continue; if (L->OneSided()) { if (check_transparent(inst, inst.level.getRight(*L)->MidTex(), names)) lines.set(n); } else // Two Sided { // note : plain OR operator here to check all parts (do NOT want short-circuit) if (check_transparent(inst, inst.level.getRight(*L)->LowerTex(), names) | check_transparent(inst, inst.level.getRight(*L)->UpperTex(), names) | check_transparent(inst, inst.level.getLeft(*L)->LowerTex(), names) | check_transparent(inst, inst.level.getLeft(*L)->UpperTex(), names)) { lines.set(n); } } } } static void Textures_ShowTransparent(Instance &inst) { if (inst.edit.mode != ObjType::linedefs) inst.Editor_ChangeMode('l'); std::map names; Textures_FindTransparent(inst, *inst.edit.Selected, names); inst.GoToErrors(); } static void Textures_FixTransparent(Instance &inst) { SString new_tex = inst.conf.default_wall_tex; // do something reasonable if default wall is transparent if (is_transparent(inst, new_tex)) { if (inst.wad.images.W_TextureIsKnown(inst.conf, "SANDSQ2")) new_tex = "SANDSQ2"; // Heretic else if (inst.wad.images.W_TextureIsKnown(inst.conf, "CASTLE07")) new_tex = "CASTLE07"; // Hexen else if (inst.wad.images.W_TextureIsKnown(inst.conf, "BRKBRN02")) new_tex = "BRKBRN02"; // Strife else new_tex = "GRAY1"; // Doom } StringID new_wall = BA_InternaliseString(new_tex); EditOperation op(inst.level.basis); op.setMessage("fixed transparent textures"); for (const auto &L : inst.level.linedefs) { if (L->right < 0) continue; if (L->OneSided()) { if (is_transparent(inst, inst.level.getRight(*L)->MidTex())) op.changeSidedef(L->right, SideDef::F_MID_TEX, new_wall); } else // Two Sided { if (is_transparent(inst, inst.level.getLeft(*L)->LowerTex())) op.changeSidedef(L->left, SideDef::F_LOWER_TEX, new_wall); if (is_transparent(inst, inst.level.getLeft(*L)->UpperTex())) op.changeSidedef(L->left, SideDef::F_UPPER_TEX, new_wall); if (is_transparent(inst, inst.level.getRight(*L)->LowerTex())) op.changeSidedef(L->right, SideDef::F_LOWER_TEX, new_wall); if (is_transparent(inst, inst.level.getRight(*L)->UpperTex())) op.changeSidedef(L->right, SideDef::F_UPPER_TEX, new_wall); } } } static void Textures_LogTransparent(Instance &inst) { selection_c sel; std::map names; std::map::iterator IT; Textures_FindTransparent(inst, sel, names); gLog.printf("\n"); gLog.printf("Transparent textures on solid walls:\n"); gLog.printf("{\n"); for (IT = names.begin() ; IT != names.end() ; IT++) gLog.printf(" %-9s x %d\n", IT->first.c_str(), IT->second); gLog.printf("}\n"); LogViewer_Open(); } static int check_medusa(const WadData &wad, const SString &tex, std::map& names) { if (is_null_tex(tex) || is_special_tex(tex)) return 0; if (! wad.images.W_TextureCausesMedusa(tex)) return 0; bump_unknown_name(names, tex); return 1; } static void Textures_FindMedusa(selection_c& lines, std::map& names, const Instance &inst) { lines.change_type(ObjType::linedefs); names.clear(); for (int n = 0 ; n < inst.level.numLinedefs(); n++) { const auto L = inst.level.linedefs[n]; if (L->right < 0 || L->left < 0) continue; if (check_medusa(inst.wad, inst.level.getRight(*L)->MidTex(), names) | /* plain OR */ check_medusa(inst.wad, inst.level.getLeft(*L)->MidTex(), names)) { lines.set(n); } } } static void Textures_ShowMedusa(Instance &inst) { if (inst.edit.mode != ObjType::linedefs) inst.Editor_ChangeMode('l'); std::map names; Textures_FindMedusa(*inst.edit.Selected, names, inst); inst.GoToErrors(); } static void Textures_RemoveMedusa(Instance &inst) { StringID null_tex = BA_InternaliseString("-"); std::map names; EditOperation op(inst.level.basis); op.setMessage("fixed medusa textures"); for (const auto &L : inst.level.linedefs) { if (L->right < 0 || L->left < 0) continue; if (check_medusa(inst.wad, inst.level.getRight(*L)->MidTex(), names)) { op.changeSidedef(L->right, SideDef::F_MID_TEX, null_tex); } if (check_medusa(inst.wad, inst.level.getLeft(*L)->MidTex(), names)) { op.changeSidedef(L->left, SideDef::F_MID_TEX, null_tex); } } } static void Textures_LogMedusa(const Instance &inst) { selection_c sel; std::map names; std::map::iterator IT; Textures_FindMedusa(sel, names, inst); gLog.printf("\n"); gLog.printf("Medusa effect textures:\n"); gLog.printf("{\n"); for (IT = names.begin() ; IT != names.end() ; IT++) gLog.printf(" %-9s x %d\n", IT->first.c_str(), IT->second); gLog.printf("}\n"); LogViewer_Open(); } static void Textures_FindTuttiFrutti(selection_c& lines, const Instance& inst) { lines.change_type(ObjType::linedefs); for (int n = 0; n < inst.level.numLinedefs(); n++) { const auto L = inst.level.linedefs[n]; if (L->right < 0) continue; if (L->left < 0) // single sided { const Img_c* texture = inst.wad.images.getTexture(inst.conf, inst.level.getRight(*L)->MidTex()); if (!texture) continue; if (texture->has_transparent()) { lines.set(n); continue; } if (texture->height() >= 128) continue; const SideDef* side = inst.level.getSide(*L, Side::right); if (!side) continue; const Sector §or = inst.level.getSector(*side); int headroom = sector.ceilh - sector.floorh; if (headroom > texture->height() || (L->flags & MLF_LowerUnpegged && (side->y_offset > 0 || side->y_offset < texture->height() - headroom)) || (!(L->flags & MLF_LowerUnpegged) && (side->y_offset < 0 || side->y_offset > texture->height() - headroom))) { lines.set(n); } continue; } // two sided // TODO } } static void Textures_ShowTuttiFrutti(Instance& inst) { if (inst.edit.mode != ObjType::linedefs) inst.Editor_ChangeMode('l'); Textures_FindTuttiFrutti(*inst.edit.Selected, inst); inst.GoToErrors(); } static void Textures_FindUnknownTex(selection_c& lines, std::map& names, const Instance &inst) { lines.change_type(ObjType::linedefs); names.clear(); for (int n = 0 ; n < inst.level.numLinedefs(); n++) { const auto L = inst.level.linedefs[n]; for (int side = 0 ; side < 2 ; side++) { const SideDef *SD = side ? inst.level.getLeft(*L) : inst.level.getRight(*L); if (! SD) continue; for (int part = 0 ; part < 3 ; part++) { SString tex = (part == 0) ? SD->LowerTex() : (part == 1) ? SD->UpperTex() : SD->MidTex(); if (! inst.wad.images.W_TextureIsKnown(inst.conf, tex)) { bump_unknown_name(names, tex); lines.set(n); } } } } } static void Textures_FindUnknownFlat(selection_c& secs, std::map& names, const Instance &inst) { secs.change_type(ObjType::sectors); names.clear(); for (int s = 0 ; s < inst.level.numSectors(); s++) { const auto S = inst.level.sectors[s]; for (int part = 0 ; part < 2 ; part++) { SString flat = part ? S->CeilTex() : S->FloorTex(); if (! inst.wad.images.W_FlatIsKnown(inst.conf, flat)) { bump_unknown_name(names, flat); secs.set(s); } } } } static void Textures_ShowUnknownTex(Instance &inst) { if (inst.edit.mode != ObjType::linedefs) inst.Editor_ChangeMode('l'); std::map names; Textures_FindUnknownTex(*inst.edit.Selected, names, inst); inst.GoToErrors(); } static void Textures_ShowUnknownFlat(Instance &inst) { if (inst.edit.mode != ObjType::sectors) inst.Editor_ChangeMode('s'); std::map names; Textures_FindUnknownFlat(*inst.edit.Selected, names, inst); inst.GoToErrors(); } static void Textures_LogUnknown(bool do_flat, const Instance &inst) { selection_c sel; std::map names; std::map::iterator IT; if (do_flat) Textures_FindUnknownFlat(sel, names, inst); else Textures_FindUnknownTex(sel, names, inst); gLog.printf("\n"); gLog.printf("Unknown %s:\n", do_flat ? "Flats" : "Textures"); gLog.printf("{\n"); for (IT = names.begin() ; IT != names.end() ; IT++) gLog.printf(" %-9s x %d\n", IT->first.c_str(), IT->second); gLog.printf("}\n"); LogViewer_Open(); } static void Textures_FixUnknownTex(Instance &inst) { StringID new_wall = BA_InternaliseString(inst.conf.default_wall_tex); StringID null_tex = BA_InternaliseString("-"); EditOperation op(inst.level.basis); op.setMessage("fixed unknown textures"); for (const auto &L : inst.level.linedefs) { bool two_sided = L->TwoSided(); for (int side = 0 ; side < 2 ; side++) { int sd_num = side ? L->left : L->right; if (sd_num < 0) continue; const auto SD = inst.level.sidedefs[sd_num]; if (! inst.wad.images.W_TextureIsKnown(inst.conf, SD->LowerTex())) op.changeSidedef(sd_num, SideDef::F_LOWER_TEX, new_wall); if (!inst.wad.images.W_TextureIsKnown(inst.conf, SD->UpperTex())) op.changeSidedef(sd_num, SideDef::F_UPPER_TEX, new_wall); if (!inst.wad.images.W_TextureIsKnown(inst.conf, SD->MidTex())) op.changeSidedef(sd_num, SideDef::F_MID_TEX, two_sided ? null_tex : new_wall); } } } static void Textures_FixUnknownFlat(Instance &inst) { StringID new_floor = BA_InternaliseString(inst.conf.default_floor_tex); StringID new_ceil = BA_InternaliseString(inst.conf.default_ceil_tex); EditOperation op(inst.level.basis); op.setMessage("fixed unknown flats"); for (int s = 0 ; s < inst.level.numSectors(); s++) { const auto S = inst.level.sectors[s]; if (! inst.wad.images.W_FlatIsKnown(inst.conf, S->FloorTex())) op.changeSector(s, Sector::F_FLOOR_TEX, new_floor); if (!inst.wad.images.W_FlatIsKnown(inst.conf, S->CeilTex())) op.changeSector(s, Sector::F_CEIL_TEX, new_ceil); } } static bool is_switch_tex(const SString &tex) { // we only check if the name begins with "SW" and a digit or // an underscore. that is sufficient for DOOM and Heretic, and // most Hexen switches, but misses a lot in Strife. return (tex[0] == 'S') && (tex[1] == 'W') && (tex[2] == '_' || isdigit(tex[2])); } static void Textures_FindDupSwitches(selection_c& lines, const Document &doc) { lines.change_type(ObjType::linedefs); for (int n = 0 ; n < doc.numLinedefs(); n++) { const auto L = doc.linedefs[n]; // only check lines with a special if (! L->type) continue; if (L->right < 0) continue; // switch textures only work on the front side // (no need to look at the back side) bool lower = is_switch_tex(doc.getRight(*L)->LowerTex()); bool upper = is_switch_tex(doc.getRight(*L)->UpperTex()); bool mid = is_switch_tex(doc.getRight(*L)->MidTex()); int count = (lower ? 1:0) + (upper ? 1:0) + (mid ? 1:0); if (count > 1) lines.set(n); } } static void Textures_ShowDupSwitches(Instance &inst) { if (inst.edit.mode != ObjType::linedefs) inst.Editor_ChangeMode('l'); Textures_FindDupSwitches(*inst.edit.Selected, inst.level); inst.GoToErrors(); } static void Textures_FixDupSwitches(Instance &inst) { StringID null_tex = BA_InternaliseString("-"); SString new_tex = inst.conf.default_wall_tex; // do something reasonable if default wall is a switch if (is_switch_tex(new_tex)) { if (inst.wad.images.W_TextureIsKnown(inst.conf, "SANDSQ2")) new_tex = "SANDSQ2"; // Heretic else if (inst.wad.images.W_TextureIsKnown(inst.conf, "CASTLE07")) new_tex = "CASTLE07"; // Hexen else if (inst.wad.images.W_TextureIsKnown(inst.conf, "BRKBRN02")) new_tex = "BRKBRN02"; // Strife else new_tex = "GRAY1"; // Doom } StringID new_wall = BA_InternaliseString(new_tex); EditOperation op(inst.level.basis); op.setMessage("fixed non-animating switches"); for (const auto &L : inst.level.linedefs) { // only check lines with a special if (! L->type) continue; if (L->right < 0) continue; // switch textures only work on the front side // (hence no need to look at the back side) bool lower = is_switch_tex(inst.level.getRight(*L)->LowerTex()); bool upper = is_switch_tex(inst.level.getRight(*L)->UpperTex()); bool mid = is_switch_tex(inst.level.getRight(*L)->MidTex()); int count = (lower ? 1:0) + (upper ? 1:0) + (mid ? 1:0); if (count < 2) continue; if (L->OneSided()) { // we don't care if "mid" is not a switch op.changeSidedef(L->right, SideDef::F_LOWER_TEX, null_tex); op.changeSidedef(L->right, SideDef::F_UPPER_TEX, null_tex); continue; } const Sector &front = inst.level.getSector(*inst.level.getRight(*L)); const Sector &back = inst.level.getSector(*inst.level.getLeft(*L)); bool lower_vis = (front.floorh < back.floorh); bool upper_vis = (front.ceilh > back.ceilh); if (count >= 2 && upper && !upper_vis) { op.changeSidedef(L->right, SideDef::F_UPPER_TEX, null_tex); upper = false; count--; } if (count >= 2 && lower && !lower_vis) { op.changeSidedef(L->right, SideDef::F_LOWER_TEX, null_tex); lower = false; count--; } if (count >= 2 && mid) { op.changeSidedef(L->right, SideDef::F_MID_TEX, null_tex); mid = false; count--; } if (count >= 2) { op.changeSidedef(L->right, SideDef::F_UPPER_TEX, new_wall); upper = false; count--; } } } //------------------------------------------------------------------------ class UI_Check_Textures : public UI_Check_base { public: UI_Check_Textures(bool all_mode, Instance &inst) : UI_Check_base(580, 386, all_mode, "Check : Textures", "Texture test results"), inst(inst) { } static void action_show_unk_tex(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_ShowUnknownTex(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_log_unk_tex(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_LogUnknown(false, dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_fix_unk_tex(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_FixUnknownTex(dialog->inst); dialog->user_action = CheckResult::tookAction; } static void action_show_unk_flat(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_ShowUnknownFlat(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_log_unk_flat(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_LogUnknown(true, dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_fix_unk_flat(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_FixUnknownFlat(dialog->inst); dialog->user_action = CheckResult::tookAction; } static void action_show_missing(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_ShowMissing(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_fix_missing(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_FixMissing(dialog->inst); dialog->user_action = CheckResult::tookAction; } static void action_show_transparent(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_ShowTransparent(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_fix_transparent(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_FixTransparent(dialog->inst); dialog->user_action = CheckResult::tookAction; } static void action_log_transparent(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_LogTransparent(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_show_dup_switch(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_ShowDupSwitches(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_fix_dup_switch(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_FixDupSwitches(dialog->inst); dialog->user_action = CheckResult::tookAction; } static void action_show_medusa(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_ShowMedusa(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_show_tuttifrutti(Fl_Widget* w, void* data) { auto dialog = static_cast(data); Textures_ShowTuttiFrutti(dialog->inst); dialog->user_action = CheckResult::highlight; } static void action_remove_medusa(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_RemoveMedusa(dialog->inst); dialog->user_action = CheckResult::tookAction; } static void action_log_medusa(Fl_Widget *w, void *data) { UI_Check_Textures *dialog = (UI_Check_Textures *)data; Textures_LogMedusa(dialog->inst); dialog->user_action = CheckResult::highlight; } private: Instance &inst; }; CheckResult ChecksModule::checkTextures(int min_severity) const { UI_Check_Textures *dialog = new UI_Check_Textures(min_severity > 0, inst); selection_c sel; std::map names; SString check_buffer; for (;;) { Textures_FindUnknownTex(sel, names, inst); if (sel.empty()) dialog->AddLine("No unknown textures"); else { check_buffer = SString::printf("%d unknown textures", (int)names.size()); dialog->AddLine(check_buffer, 2, 200, "Show", &UI_Check_Textures::action_show_unk_tex, "Log", &UI_Check_Textures::action_log_unk_tex, "Fix", &UI_Check_Textures::action_fix_unk_tex); } Textures_FindUnknownFlat(sel, names, inst); if (sel.empty()) dialog->AddLine("No unknown flats"); else { check_buffer = SString::printf("%d unknown flats", (int)names.size()); dialog->AddLine(check_buffer, 2, 200, "Show", &UI_Check_Textures::action_show_unk_flat, "Log", &UI_Check_Textures::action_log_unk_flat, "Fix", &UI_Check_Textures::action_fix_unk_flat); } if (! inst.conf.features.medusa_fixed) { Textures_FindMedusa(sel, names, inst); if (sel.empty()) dialog->AddLine("No textures causing Medusa Effect"); else { check_buffer = SString::printf("%d Medusa textures", (int)names.size()); dialog->AddLine(check_buffer, 2, 200, "Show", &UI_Check_Textures::action_show_medusa, "Log", &UI_Check_Textures::action_log_medusa, "Fix", &UI_Check_Textures::action_remove_medusa); } } if (!inst.conf.features.tuttifrutti_fixed) { Textures_FindTuttiFrutti(sel, inst); if (sel.empty()) dialog->AddLine("No tutti-frutti walls"); else { check_buffer = SString::printf("%d tutti-frutti walls", sel.count_obj()); dialog->AddLine(check_buffer, 2, 200, "Show", &UI_Check_Textures::action_show_tuttifrutti); } } dialog->AddGap(10); Textures_FindMissing(inst, sel); if (sel.empty()) dialog->AddLine("No missing textures on walls"); else { check_buffer = SString::printf("%d missing textures on walls", sel.count_obj()); dialog->AddLine(check_buffer, 1, 275, "Show", &UI_Check_Textures::action_show_missing, "Fix", &UI_Check_Textures::action_fix_missing); } Textures_FindTransparent(inst, sel, names); if (sel.empty()) dialog->AddLine("No transparent textures on solids"); else { check_buffer = SString::printf("%d transparent textures on solids", sel.count_obj()); dialog->AddLine(check_buffer, 1, 275, "Show", &UI_Check_Textures::action_show_transparent, "Fix", &UI_Check_Textures::action_fix_transparent, "Log", &UI_Check_Textures::action_log_transparent); } Textures_FindDupSwitches(sel, doc); if (sel.empty()) dialog->AddLine("No non-animating switch textures"); else { check_buffer = SString::printf("%d non-animating switch textures", sel.count_obj()); dialog->AddLine(check_buffer, 1, 275, "Show", &UI_Check_Textures::action_show_dup_switch, "Fix", &UI_Check_Textures::action_fix_dup_switch); } if (dialog->WorstSeverity() < min_severity) { delete dialog; return CheckResult::ok; } CheckResult result = dialog->Run(); if (result == CheckResult::tookAction) { // repeat the tests dialog->Reset(); continue; } delete dialog; return result; } } //------------------------------------------------------------------------ void ChecksModule::checkAll(bool major_stuff) const { bool no_worries = true; int min_severity = major_stuff ? 2 : 1; CheckResult result; result = checkVertices(min_severity); if (result == CheckResult::highlight) return; if (result != CheckResult::ok) no_worries = false; result = checkSectors(min_severity); if (result == CheckResult::highlight) return; if (result != CheckResult::ok) no_worries = false; result = checkLinedefs(min_severity); if (result == CheckResult::highlight) return; if (result != CheckResult::ok) no_worries = false; result = checkThings(min_severity); if (result == CheckResult::highlight) return; if (result != CheckResult::ok) no_worries = false; result = checkTextures(min_severity); if (result == CheckResult::highlight) return; if (result != CheckResult::ok) no_worries = false; result = checkTags(min_severity); if (result == CheckResult::highlight) return; if (result != CheckResult::ok) no_worries = false; if (no_worries) { DLG_Notify(major_stuff ? "No major problems." : "All tests were successful."); } } void Instance::CMD_MapCheck() { SString what = EXEC_Param[0]; if (what.empty()) { Beep("MapCheck: missing keyword"); return; } else if (what.noCaseEqual("all")) { level.checks.checkAll(false); } else if (what.noCaseEqual("major")) { level.checks.checkAll(true); } else if (what.noCaseEqual("vertices")) { level.checks.checkVertices(0); } else if (what.noCaseEqual("sectors")) { level.checks.checkSectors(0); } else if (what.noCaseEqual("linedefs")) { level.checks.checkLinedefs(0); } else if (what.noCaseEqual("things")) { level.checks.checkThings(0); } else if (what.noCaseEqual("current")) // current editing mode { switch (edit.mode) { case ObjType::vertices: level.checks.checkVertices(0); break; case ObjType::sectors: level.checks.checkSectors(0); break; case ObjType::linedefs: level.checks.checkLinedefs(0); break; case ObjType::things: level.checks.checkThings(0); break; default: Beep("Nothing to check"); break; } } else if (what.noCaseEqual("textures")) { level.checks.checkTextures(0); } else if (what.noCaseEqual("tags")) { level.checks.checkTags(0); } else { Beep("MapCheck: unknown keyword: %s\n", what.c_str()); } } void Debug_CheckUnusedStuff(Document &doc) { selection_c sel; Sectors_FindUnused(sel, doc); int num = sel.count_obj(); if (num > 0) { fl_beep(); DLG_Notify("Operation left %d sectors unused.", num); Sectors_RemoveUnused(doc); return; } SideDefs_FindUnused(sel, doc); num = sel.count_obj(); if (num > 0) { fl_beep(); DLG_Notify("Operation left %d sidedefs unused.", num); SideDefs_RemoveUnused(doc); return; } } // // Finds a free tag. Doesn't care about limits at this point // int findFreeTag(const Instance &inst, bool forsector) { std::unordered_set tags; int freetag = 0; const auto &doc = inst.level; auto addtag = [&tags, &freetag](int tag) { tags.insert(tag); if(tag == freetag) ++freetag; // raise if if we know it's there }; for(int i = 0; i < doc.numLinedefs(); ++i) addtag(doc.linedefs[i]->tag); for(int i = 0; i < doc.numSectors(); ++i) addtag(doc.sectors[i]->tag); while(tags.count(freetag) || (forsector && inst.conf.features.tag_666 != Tag666Rules::disabled && (freetag == 666 || freetag == 667))) { ++freetag; // now raise it as necessary } return freetag; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_checks.h000066400000000000000000000045161464327712600202530ustar00rootroot00000000000000//------------------------------------------------------------------------ // INTEGRITY CHECKS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2009 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_E_CHECKS_H__ #define __EUREKA_E_CHECKS_H__ #include "DocumentModule.h" #include "ui_window.h" // the CHECK_xxx functions return the following values: enum class CheckResult { ok, // no issues at all minorProblem, // only minor issues majorProblem, // some major problems highlight, // need to highlight stuff (skip further checks) tookAction // [internal use : user took some action] }; // // The map checking module // class ChecksModule : public DocumentModule { friend class Instance; public: ChecksModule(Document &doc) : DocumentModule(doc) { } void sidedefsUnpack(bool is_after_load) const; void tagsApplyNewValue(int new_tag); void tagsUsedRange(int *min_tag, int *max_tag) const; private: void checkAll(bool majorStuff) const; CheckResult checkVertices(int minSeverity) const; CheckResult checkSectors(int minSeverity) const; CheckResult checkThings(int minSeverity) const; CheckResult checkLinedefs(int minSeverity) const; CheckResult checkTags(int minSeverity) const; CheckResult checkTextures(int minSeverity) const; int copySidedef(EditOperation &op, int num) const; }; int findFreeTag(const Instance &inst, bool forsector); #endif /* __EUREKA_E_CHECKS_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_commands.cc000066400000000000000000001006131464327712600207450ustar00rootroot00000000000000//------------------------------------------------------------------------ // COMMAND FUNCTIONS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2018 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Instance.h" #include "main.h" #include "e_main.h" #include "e_path.h" #include "LineDef.h" #include "m_config.h" #include "m_loadsave.h" #include "m_vector.h" #include "r_render.h" #include "r_subdiv.h" #include "Sector.h" #include "Thing.h" #include "ui_about.h" #include "ui_misc.h" #include "ui_prefs.h" #include "Vertex.h" // config items int config::minimum_drag_pixels = 5; void Instance::CMD_Nothing() { /* hey jude, don't make it bad */ } void Instance::CMD_MetaKey() { if (edit.sticky_mod) { ClearStickyMod(); return; } Status_Set("META..."); edit.sticky_mod = EMOD_META; } void Instance::CMD_EditMode() { char mode = static_cast(tolower(EXEC_Param[0][0])); if (! mode || ! strchr("lstvr", mode)) { Beep("Bad parameter for EditMode: '%s'", EXEC_Param[0].c_str()); return; } Editor_ChangeMode(mode); } void Instance::CMD_Select() { if (edit.render3d) return; // FIXME : action in effect? // FIXME : split_line in effect? if (edit.highlight.is_nil()) { Beep("Nothing under cursor"); return; } edit.Selection_Toggle(edit.highlight); RedrawMap(); } void Instance::CMD_SelectAll() { Editor_ClearErrorMode(); int total = level.numObjects(edit.mode); Selection_Push(); edit.Selected->change_type(edit.mode); edit.Selected->frob_range(0, total-1, BitOp::add); RedrawMap(); } void Instance::CMD_UnselectAll() { Editor_ClearErrorMode(); if (edit.action == EditorAction::drawLine || edit.action == EditorAction::transform) { Editor_ClearAction(); } Selection_Clear(); RedrawMap(); } void Instance::CMD_InvertSelection() { // do not clear selection when in error mode edit.error_mode = false; int total = level.numObjects(edit.mode); if (edit.Selected->what_type() != edit.mode) { // convert the selection selection_c prev_sel = *edit.Selected; edit.Selected.emplace(edit.mode, true /* extended */); ConvertSelection(level, prev_sel, *edit.Selected); } edit.Selected->frob_range(0, total-1, BitOp::toggle); RedrawMap(); } void Instance::CMD_Quit() { Main_Quit(); } void Instance::CMD_Undo() { if (! level.basis.undo()) { Beep("No operation to undo"); return; } RedrawMap(); main_win->UpdatePanelObj(); } void Instance::CMD_Redo() { if (! level.basis.redo()) { Beep("No operation to redo"); return; } RedrawMap(); main_win->UpdatePanelObj(); } static void SetGamma(Instance &inst, int new_val) { config::usegamma = clamp(0, new_val, 4); inst.wad.palette.updateGamma(config::usegamma, config::panel_gamma); // for OpenGL, need to reload all images if (inst.main_win && inst.main_win->canvas) inst.main_win->canvas->DeleteContext(); inst.Status_Set("gamma level %d", config::usegamma); inst.RedrawMap(); } void Instance::CMD_SetVar() { SString var_name = EXEC_Param[0]; SString value = EXEC_Param[1]; if (var_name.empty()) { Beep("Set: missing var name"); return; } if (value.empty()) { Beep("Set: missing value"); return; } int int_val = atoi(value); bool bool_val = (int_val > 0); if (var_name.noCaseEqual("3d")) { Render3D_Enable(*this, bool_val); } else if (var_name.noCaseEqual("browser")) { Editor_ClearAction(); int want_vis = bool_val ? 1 : 0; int is_visible = main_win->browser->visible() ? 1 : 0; if (want_vis != is_visible) main_win->BrowserMode(BrowserMode::toggle); } else if (var_name.noCaseEqual("grid")) { grid.SetShown(bool_val); } else if (var_name.noCaseEqual("snap")) { grid.SetSnap(bool_val); } else if (var_name.noCaseEqual("sprites")) { edit.thing_render_mode = int_val; RedrawMap(); } else if (var_name.noCaseEqual("obj_nums")) { edit.show_object_numbers = bool_val; RedrawMap(); } else if (var_name.noCaseEqual("gamma")) { SetGamma(*this, int_val); } else if (var_name.noCaseEqual("ratio")) grid.configureRatio(clamp(0, int_val, 7), true); else if (var_name.noCaseEqual("sec_render")) { int_val = clamp(0, int_val, (int)SREND_SoundProp); edit.sector_render_mode = (sector_rendering_mode_e) int_val; if (edit.render3d) Render3D_Enable(*this, false); // need sectors mode for sound propagation display if (edit.sector_render_mode == SREND_SoundProp && edit.mode != ObjType::sectors) Editor_ChangeMode('s'); RedrawMap(); } else { Beep("Set: unknown var: %s", var_name.c_str()); } } void Instance::CMD_ToggleVar() { SString var_name = EXEC_Param[0]; if (var_name.empty()) { Beep("Toggle: missing var name"); return; } if (var_name.noCaseEqual("3d")) { Render3D_Enable(*this, ! edit.render3d); } else if (var_name.noCaseEqual("browser")) { Editor_ClearAction(); main_win->BrowserMode(BrowserMode::toggle); } else if (var_name.noCaseEqual("recent")) { main_win->browser->ToggleRecent(); } else if (var_name.noCaseEqual("grid")) { grid.ToggleShown(); } else if (var_name.noCaseEqual("snap")) { grid.ToggleSnap(); } else if (var_name.noCaseEqual("sprites")) { edit.thing_render_mode = ! edit.thing_render_mode; RedrawMap(); } else if (var_name.noCaseEqual("obj_nums")) { edit.show_object_numbers = ! edit.show_object_numbers; RedrawMap(); } else if (var_name.noCaseEqual("gamma")) { SetGamma(*this, (config::usegamma >= 4) ? 0 : config::usegamma + 1); } else if (var_name.noCaseEqual("ratio")) grid.configureRatio(grid.getRatio() >= 7 ? 0 : grid.getRatio() + 1, true); else if (var_name.noCaseEqual("sec_render")) { if (edit.sector_render_mode >= SREND_SoundProp) edit.sector_render_mode = SREND_Nothing; else edit.sector_render_mode = (sector_rendering_mode_e)(1 + (int)edit.sector_render_mode); RedrawMap(); } else { Beep("Toggle: unknown var: %s", var_name.c_str()); } } void Instance::CMD_BrowserMode() { if (EXEC_Param[0].empty()) { Beep("BrowserMode: missing mode"); return; } char modeChar = static_cast(toupper(EXEC_Param[0][0])); if (!charMapsToSpecificBrowserMode(modeChar)) { Beep("Unknown browser mode: %s", EXEC_Param[0].c_str()); return; } BrowserMode mode = charToBrowserMode(modeChar); // if that browser is already open, close it now if (main_win->browser->visible() && main_win->browser->GetMode() == mode && ! Exec_HasFlag("/force") && ! Exec_HasFlag("/recent")) { main_win->BrowserMode(BrowserMode::hide); return; } main_win->BrowserMode(mode); if (Exec_HasFlag("/recent")) { main_win->browser->ToggleRecent(true /* force */); } } void Instance::CMD_Scroll() { // these are percentages v2double_t delta = { atof(EXEC_Param[0]), atof(EXEC_Param[1]) }; if (!delta) { Beep("Bad parameter to Scroll: '%s' %s'", EXEC_Param[0].c_str(), EXEC_Param[1].c_str()); return; } int base_size = (main_win->canvas->w() + main_win->canvas->h()) / 2; delta *= base_size / 100.0 / grid.getScale(); grid.Scroll(delta); } void Instance::NAV_Scroll_Left_release() { edit.nav.left = 0; } // // Scroll in any direction as dictated by CMD_Nav_Scroll_* // void Instance::navigationScroll(float *editNav, nav_release_func_t func) { if(!EXEC_CurKey) return; if(!edit.is_navigating) edit.clearNav(); float perc = static_cast(atof(EXEC_Param[0])); int base_size = (main_win->canvas->w() + main_win->canvas->h()) / 2; *editNav = static_cast(perc * base_size / 100.0 / grid.getScale()); Nav_SetKey(EXEC_CurKey, func); } void Instance::CMD_NAV_Scroll_Left() { navigationScroll(&edit.nav.left, &Instance::NAV_Scroll_Left_release); } void Instance::NAV_Scroll_Right_release() { edit.nav.right = 0; } void Instance::CMD_NAV_Scroll_Right() { navigationScroll(&edit.nav.right, &Instance::NAV_Scroll_Right_release); } void Instance::NAV_Scroll_Up_release() { edit.nav.up = 0; } void Instance::CMD_NAV_Scroll_Up() { navigationScroll(&edit.nav.up, &Instance::NAV_Scroll_Up_release); } void Instance::NAV_Scroll_Down_release() { edit.nav.down = 0; } void Instance::CMD_NAV_Scroll_Down() { navigationScroll(&edit.nav.down, &Instance::NAV_Scroll_Down_release); } void Instance::NAV_MouseScroll_release() { Editor_ScrollMap(+1); } void Instance::CMD_NAV_MouseScroll() { if (! EXEC_CurKey) return; edit.panning_speed = static_cast(atof(EXEC_Param[0])); edit.panning_lax = Exec_HasFlag("/LAX"); if (! edit.is_navigating) edit.clearNav(); if (Nav_SetKey(EXEC_CurKey, &Instance::NAV_MouseScroll_release)) { // begin Editor_ScrollMap(-1); } } void Instance::CheckBeginDrag() { if (! edit.clicked.valid()) return; if (! edit.click_check_drag) return; // can drag things and sector planes in 3D mode if (edit.render3d && !(edit.mode == ObjType::things || edit.mode == ObjType::sectors)) return; v2int_t pixel_dpos = { Fl::event_x() - edit.click_screen_pos.x, Fl::event_y() - edit.click_screen_pos.y }; if (pixel_dpos.chebyshev() < config::minimum_drag_pixels) return; // if highlighted object is in selection, we drag the selection, // otherwise we drag just this one object. if (edit.click_force_single || !edit.Selected->get(edit.clicked.num)) edit.dragged = edit.clicked; else edit.dragged.clear(); DoBeginDrag(); } void Instance::DoBeginDrag() { edit.drag_start = edit.drag_cur = edit.click_map; edit.drag_screen_dpos = {}; edit.drag_thing_num = -1; edit.drag_other_vert = -1; // the focus is only used when grid snapping is on edit.drag_focus.xy = level.objects.getDragFocus(edit.click_map.xy); if (edit.render3d) { if (edit.mode == ObjType::sectors) edit.drag_sector_dz = 0; if (edit.mode == ObjType::things) { edit.drag_thing_num = edit.clicked.num; edit.drag_thing_floorh = static_cast(edit.drag_start.z); edit.drag_thing_up_down = (loaded.levelFormat != MapFormat::doom && !grid.snaps()); // get thing's floor if (edit.drag_thing_num >= 0) { const auto T = level.things[edit.drag_thing_num]; Objid sec = hover::getNearestSector(level, T->xy()); if (sec.valid()) edit.drag_thing_floorh = static_cast(level.sectors[sec.num]->floorh); } } } // in vertex mode, show all the connected lines too if (edit.drag_lines) { delete edit.drag_lines; edit.drag_lines = NULL; } if (edit.mode == ObjType::vertices) { edit.drag_lines = new selection_c(ObjType::linedefs); ConvertSelection(level, *edit.Selected, *edit.drag_lines); // find opposite end-point when dragging a single vertex if (edit.dragged.valid()) edit.drag_other_vert = level.vertmod.findDragOther(edit.dragged.num); } edit.clicked.clear(); Editor_SetAction(EditorAction::drag); main_win->canvas->redraw(); } void Instance::ACT_SelectBox_release() { // check if cancelled or overridden if (edit.action != EditorAction::selbox) return; Editor_ClearAction(); Editor_ClearErrorMode(); // a mere click and release will unselect everything v2double_t pos1 = {}; v2double_t pos2 = {}; if (!main_win->canvas->SelboxGet(pos1, pos2)) { ExecuteCommand("UnselectAll"); return; } SelectObjectsInBox(level, &*edit.Selected, edit.mode, pos1, pos2); RedrawMap(); } void Instance::ACT_Drag_release() { // check if cancelled or overridden if (edit.action != EditorAction::drag) { edit.dragged.clear(); return; } if (edit.render3d) { if (edit.mode == ObjType::things) Render3D_DragThings(*this); if (edit.mode == ObjType::sectors) Render3D_DragSectors(*this); } // note: DragDelta needs inst.edit.dragged v2double_t delta = main_win->canvas->DragDelta(); Objid dragged(edit.dragged); edit.dragged.clear(); if (edit.drag_lines) edit.drag_lines->clear_all(); if (! edit.render3d && delta.nonzero()) { if (dragged.valid()) level.objects.singleDrag(dragged, v3double_t(delta)); else level.objects.move(*edit.Selected, v3double_t(delta)); } Editor_ClearAction(); RedrawMap(); } void Instance::ACT_Click_release() { Objid click_obj(edit.clicked); edit.clicked.clear(); edit.click_check_drag = false; if (edit.action == EditorAction::selbox) { ACT_SelectBox_release(); return; } else if (edit.action == EditorAction::drag) { ACT_Drag_release(); return; } // check if cancelled or overridden if (edit.action != EditorAction::click) return; if (edit.click_check_select && click_obj.valid()) { // only toggle selection if it's the same object as before Objid near_obj; if (edit.render3d) near_obj = edit.highlight; else near_obj = hover::getNearbyObject(edit.mode, level, conf, grid, edit.map.xy); if (near_obj.num == click_obj.num) edit.Selection_Toggle(click_obj); } Editor_ClearAction(); Editor_ClearErrorMode(); RedrawMap(); } void Instance::CMD_ACT_Click() { if (! EXEC_CurKey) return; // require a highlighted object in 3D mode if (edit.render3d && edit.highlight.is_nil()) return; if (! Nav_ActionKey(EXEC_CurKey, &Instance::ACT_Click_release)) return; edit.click_check_select = ! Exec_HasFlag("/noselect"); edit.click_check_drag = ! Exec_HasFlag("/nodrag"); edit.click_force_single = false; // remember some state (for drag detection) edit.click_screen_pos.x = Fl::event_x(); edit.click_screen_pos.y = Fl::event_y(); edit.click_map = edit.map; // handle 3D mode, skip stuff below which only makes sense in 2D if (edit.render3d) { if (edit.highlight.type == ObjType::things) { const auto T = level.things[edit.highlight.num]; edit.drag_point_dist = static_cast(r_view.DistToViewPlane(T->xy())); } else { edit.drag_point_dist = static_cast(r_view.DistToViewPlane(edit.map.xy)); } edit.clicked = edit.highlight; Editor_SetAction(EditorAction::click); return; } // check for splitting a line, and ensure we can drag the vertex if (! Exec_HasFlag("/nosplit") && edit.mode == ObjType::vertices && edit.split_line.valid() && edit.action != EditorAction::drawLine) { int split_ld = edit.split_line.num; edit.click_force_single = true; // if drag vertex, force single-obj mode edit.click_check_select = false; // do NOT select the new vertex // check if both ends are in selection, if so (and only then) // shall we select the new vertex const auto L = level.linedefs[split_ld]; bool want_select = edit.Selected->get(L->start) && edit.Selected->get(L->end); int new_vert; { EditOperation op(level.basis); op.setMessage("split linedef #%d", split_ld); new_vert = op.addNew(ObjType::vertices); auto V = level.vertices[new_vert]; V->SetRawXY(loaded.levelFormat, edit.split); level.linemod.splitLinedefAtVertex(op, split_ld, new_vert); } if (want_select) edit.Selected->set(new_vert); edit.clicked = Objid(ObjType::vertices, new_vert); Editor_SetAction(EditorAction::click); RedrawMap(); return; } // find the object under the pointer. edit.clicked = hover::getNearbyObject(edit.mode, level, conf, grid, edit.map.xy); // clicking on an empty space starts a new selection box if (edit.click_check_select && edit.clicked.is_nil()) { edit.selbox1 = edit.selbox2 = edit.map.xy; Editor_SetAction(EditorAction::selbox); return; } Editor_SetAction(EditorAction::click); } void Instance::CMD_ACT_SelectBox() { if (edit.render3d) return; if (! EXEC_CurKey) return; if (! Nav_ActionKey(EXEC_CurKey, &Instance::ACT_SelectBox_release)) return; edit.selbox1 = edit.selbox2 = edit.map.xy; Editor_SetAction(EditorAction::selbox); } void Instance::CMD_ACT_Drag() { if (! EXEC_CurKey) return; if (edit.Selected->empty()) { Beep("Nothing to drag"); return; } if (! Nav_ActionKey(EXEC_CurKey, &Instance::ACT_Drag_release)) return; // we only drag the selection, never a single object edit.dragged.clear(); DoBeginDrag(); } void Instance::Transform_Update() { v2double_t dv1 = edit.map.xy - edit.trans_param.mid; v2double_t dv0 = edit.trans_start - edit.trans_param.mid; edit.trans_param.scale = { 1.0, 1.0 }; edit.trans_param.skew = {}; edit.trans_param.rotate = 0; if (edit.trans_mode == TRANS_K_Rotate || edit.trans_mode == TRANS_K_RotScale) { double angle[2] = { dv1.atan2(), dv0.atan2() }; edit.trans_param.rotate = angle[1] - angle[0]; // fprintf(stderr, "angle diff : %1.2f\n", inst.edit.trans_rotate * 360.0 / 65536.0); } switch (edit.trans_mode) { case TRANS_K_Scale: case TRANS_K_RotScale: dv1.x = std::max(fabs(dv1.x), fabs(dv1.y)); dv0.x = std::max(fabs(dv0.x), fabs(dv0.y)); if (dv0.x) { edit.trans_param.scale.x = dv1.x / dv0.x; edit.trans_param.scale.y = edit.trans_param.scale.x; } break; case TRANS_K_Stretch: if (dv0.x) edit.trans_param.scale.x = dv1.x / dv0.x; if (dv0.y) edit.trans_param.scale.y = dv1.y / dv0.y; break; case TRANS_K_Rotate: // already done break; case TRANS_K_Skew: if (fabs(dv0.x) >= fabs(dv0.y)) { if (dv0.x) edit.trans_param.skew.y = (dv1.y - dv0.y) / (float)dv0.x; } else { if (dv0.y) edit.trans_param.skew.x = (dv1.x - dv0.x) / (float)dv0.y; } break; } main_win->canvas->redraw(); } void Instance::ACT_Transform_release() { // check if cancelled or overridden if (edit.action != EditorAction::transform) return; if (edit.trans_lines) edit.trans_lines->clear_all(); level.objects.transform(edit.trans_param); Editor_ClearAction(); RedrawMap(); } void Instance::CMD_ACT_Transform() { if (edit.render3d) return; if (! EXEC_CurKey) return; if (edit.Selected->empty()) { Beep("Nothing to scale"); return; } SString keyword = EXEC_Param[0]; transform_keyword_e mode; if (keyword.empty()) { Beep("ACT_Transform: missing keyword"); return; } else if (keyword.noCaseEqual("scale")) { mode = TRANS_K_Scale; } else if (keyword.noCaseEqual("stretch")) { mode = TRANS_K_Stretch; } else if (keyword.noCaseEqual("rotate")) { mode = TRANS_K_Rotate; } else if (keyword.noCaseEqual("rotscale")) { mode = TRANS_K_RotScale; } else if (keyword.noCaseEqual("skew")) { mode = TRANS_K_Skew; } else { Beep("ACT_Transform: unknown keyword: %s", keyword.c_str()); return; } if (! Nav_ActionKey(EXEC_CurKey, &Instance::ACT_Transform_release)) return; v2double_t middle = level.objects.calcMiddle(*edit.Selected); edit.trans_mode = mode; edit.trans_start = edit.map.xy; edit.trans_param.Clear(); edit.trans_param.mid = middle; if (edit.trans_lines) { delete edit.trans_lines; edit.trans_lines = NULL; } if (edit.mode == ObjType::vertices) { edit.trans_lines = new selection_c(ObjType::linedefs); ConvertSelection(level, *edit.Selected, *edit.trans_lines); } Editor_SetAction(EditorAction::transform); } void Instance::CMD_WHEEL_Scroll() { float speed = static_cast(atof(EXEC_Param[0])); if (Exec_HasFlag("/LAX")) { keycode_t mod = Fl::event_state() & EMOD_ALL_MASK; if (mod & EMOD_SHIFT) speed /= 3.0f; else if (mod & EMOD_COMMAND) speed *= 3.0f; } v2double_t delta = { static_cast(wheel_dpos.x), static_cast(-wheel_dpos.y) }; int base_size = (main_win->canvas->w() + main_win->canvas->h()) / 2; speed = static_cast(speed * base_size / 100.0 / grid.getScale()); grid.Scroll(delta * speed); } void Instance::CMD_Merge() { switch (edit.mode) { case ObjType::vertices: commandVertexMerge(); break; case ObjType::linedefs: commandLinedefMergeTwo(); break; case ObjType::sectors: commandSectorMerge(); break; case ObjType::things: CMD_TH_Merge(*this); break; default: Beep("Cannot merge that"); break; } } void Instance::CMD_Disconnect() { switch (edit.mode) { case ObjType::vertices: commandVertexDisconnect(); break; case ObjType::linedefs: commandLineDisconnect(); break; case ObjType::sectors: commandSectorDisconnect(); break; case ObjType::things: CMD_TH_Disconnect(*this); break; default: Beep("Cannot disconnect that"); break; } } void Instance::CMD_Zoom() { int delta = atoi(EXEC_Param[0]); if (delta == 0) { Beep("Zoom: bad or missing value"); return; } auto mid = v2int_t(edit.map.xy); if (Exec_HasFlag("/center")) mid = grid.getOrig().iround(); Editor_Zoom(delta, mid); } void Instance::CMD_ZoomWholeMap() { if (edit.render3d) Render3D_Enable(*this, false); ZoomWholeMap(); } void Instance::CMD_ZoomSelection() { if (edit.Selected->empty()) { Beep("No selection to zoom"); return; } GoToSelection(); } void Instance::CMD_GoToCamera() { if (edit.render3d) Render3D_Enable(*this, false); v2double_t pos; float angle; Render3D_GetCameraPos(pos, &angle); grid.MoveTo(pos); RedrawMap(); } void Instance::CMD_PlaceCamera() { if (edit.render3d) { Beep("Not supported in 3D view"); return; } if (! edit.pointer_in_window) { // IDEA: turn cursor into cross, wait for click in map window Beep("Mouse is not over map"); return; } Render3D_SetCameraPos(edit.map.xy); if (Exec_HasFlag("/open3d")) { Render3D_Enable(*this, true); } RedrawMap(); } void Instance::CMD_MoveObjects_Dialog() { SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { Beep("Nothing to move"); return; } bool want_dz = (edit.mode == ObjType::sectors); // can move things vertically in Hexen/UDMF formats if (edit.mode == ObjType::things && loaded.levelFormat != MapFormat::doom) want_dz = true; UI_MoveDialog * dialog = new UI_MoveDialog(*this, want_dz); dialog->Run(); delete dialog; if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); } void Instance::CMD_ScaleObjects_Dialog() { SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { Beep("Nothing to scale"); return; } UI_ScaleDialog * dialog = new UI_ScaleDialog(*this); dialog->Run(); delete dialog; if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); } void Instance::CMD_RotateObjects_Dialog() { SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { Beep("Nothing to rotate"); return; } UI_RotateDialog * dialog = new UI_RotateDialog(*this); dialog->Run(); delete dialog; if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); } void Instance::CMD_GRID_Bump() { int delta = atoi(EXEC_Param[0]); delta = (delta >= 0) ? +1 : -1; grid.AdjustStep(delta); } void Instance::CMD_GRID_Set() { int step = atoi(EXEC_Param[0]); if (step < 2 || step > 4096) { Beep("Bad grid step"); return; } grid.ForceStep(step); } void Instance::CMD_GRID_Zoom() { // target scale is positive for NN:1 and negative for 1:NN double scale = atof(EXEC_Param[0]); if (scale == 0) { Beep("Bad scale"); return; } if (scale < 0) scale = -1.0 / scale; float S1 = static_cast(grid.getScale()); grid.NearestScale(scale); grid.RefocusZoom(edit.map.xy, S1); } void Instance::CMD_BR_CycleCategory() { if (!main_win->browser->visible()) { Beep("Browser not open"); return; } int dir = (atoi(EXEC_Param[0]) >= 0) ? +1 : -1; main_win->browser->CycleCategory(dir); } void Instance::CMD_BR_ClearSearch() { if (!main_win->browser->visible()) { Beep("Browser not open"); return; } main_win->browser->ClearSearchBox(); } void Instance::CMD_BR_Scroll() { if (!main_win->browser->visible()) { Beep("Browser not open"); return; } if (EXEC_Param[0].empty()) { Beep("BR_Scroll: missing value"); return; } int delta = atoi(EXEC_Param[0]); main_win->browser->Scroll(delta); } void Instance::CMD_DefaultProps() { main_win->ShowDefaultProps(); } void Instance::CMD_FindDialog() { main_win->ShowFindAndReplace(); } void Instance::CMD_FindNext() { main_win->find_box->FindNext(); } void Instance::CMD_RecalcSectors() { Subdiv_InvalidateAll(); RedrawMap(); } void Instance::CMD_LogViewer() { LogViewer_Open(); } void Instance::CMD_OnlineDocs() { int rv = fl_open_uri("http://eureka-editor.sourceforge.net/?n=Docs.Index"); if (rv == 1) Status_Set("Opened web browser"); else Beep("Failed to open web browser"); } void Instance::CMD_AboutDialog() { DLG_AboutText(); } //------------------------------------------------------------------------ namespace global { static editor_command_t command_table[] = { /* ---- miscellaneous / UI stuff ---- */ { "Nothing", "Misc", &Instance::CMD_Nothing }, { "Set", "Misc", &Instance::CMD_SetVar, /* flags */ NULL, /* keywords */ "3d browser gamma grid obj_nums ratio sec_render snap sprites" }, { "Toggle", "Misc", &Instance::CMD_ToggleVar, /* flags */ NULL, /* keywords */ "3d browser gamma grid obj_nums ratio sec_render snap recent sprites" }, { "MetaKey", "Misc", &Instance::CMD_MetaKey }, { "EditMode", "Misc", &Instance::CMD_EditMode, /* flags */ NULL, /* keywords */ "thing line sector vertex" }, { "OpMenu", "Misc", &Instance::CMD_OperationMenu }, { "MapCheck", "Misc", &Instance::CMD_MapCheck, /* flags */ NULL, /* keywords */ "all major vertices sectors linedefs things textures tags current" }, /* ----- 2D canvas ----- */ { "Scroll", "2D View", &Instance::CMD_Scroll }, { "GRID_Bump", "2D View", &Instance::CMD_GRID_Bump }, { "GRID_Set", "2D View", &Instance::CMD_GRID_Set }, { "GRID_Zoom", "2D View", &Instance::CMD_GRID_Zoom }, { "ACT_SelectBox", "2D View", &Instance::CMD_ACT_SelectBox }, { "WHEEL_Scroll", "2D View", &Instance::CMD_WHEEL_Scroll }, { "NAV_Scroll_Left", "2D View", &Instance::CMD_NAV_Scroll_Left }, { "NAV_Scroll_Right", "2D View", &Instance::CMD_NAV_Scroll_Right }, { "NAV_Scroll_Up", "2D View", &Instance::CMD_NAV_Scroll_Up }, { "NAV_Scroll_Down", "2D View", &Instance::CMD_NAV_Scroll_Down }, { "NAV_MouseScroll", "2D View", &Instance::CMD_NAV_MouseScroll }, /* ----- FILE menu ----- */ { "NewProject", "File", &Instance::CMD_NewProject }, { "ManageProject", "File", &Instance::CMD_ManageProject }, { "OpenMap", "File", &Instance::CMD_OpenMap }, { "GivenFile", "File", &Instance::CMD_GivenFile, /* flags */ NULL, /* keywords */ "next prev first last current" }, { "FlipMap", "File", &Instance::CMD_FlipMap, /* flags */ NULL, /* keywords */ "next prev first last" }, { "SaveMap", "File", &Instance::CMD_SaveMap }, { "ExportMap", "File", &Instance::CMD_ExportMap }, { "FreshMap", "File", &Instance::CMD_FreshMap }, { "CopyMap", "File", &Instance::CMD_CopyMap }, { "RenameMap", "File", &Instance::CMD_RenameMap }, { "DeleteMap", "File", &Instance::CMD_DeleteMap }, { "Quit", "File", &Instance::CMD_Quit }, /* ----- EDIT menu ----- */ { "Undo", "Edit", &Instance::CMD_Undo }, { "Redo", "Edit", &Instance::CMD_Redo }, { "Insert", "Edit", &Instance::CMD_ObjectInsert, /* flags */ "/continue /nofill" }, { "Delete", "Edit", &Instance::CMD_Delete, /* flags */ "/keep" }, { "Clipboard_Cut", "Edit", &Instance::CMD_Clipboard_Cut }, { "Clipboard_Copy", "Edit", &Instance::CMD_Clipboard_Copy }, { "Clipboard_Paste", "Edit", &Instance::CMD_Clipboard_Paste }, { "Select", "Edit", &Instance::CMD_Select }, { "SelectAll", "Edit", &Instance::CMD_SelectAll }, { "UnselectAll", "Edit", &Instance::CMD_UnselectAll }, { "SelectNeighbors", "Edit", &Instance::CMD_SelectNeighbors, /* flags */ NULL, /* keywords */ "height texture" }, { "InvertSelection", "Edit", &Instance::CMD_InvertSelection }, { "LastSelection", "Edit", &Instance::CMD_LastSelection }, { "CopyAndPaste", "Edit", &Instance::CMD_CopyAndPaste }, { "CopyProperties", "Edit", &Instance::CMD_CopyProperties, /* flags */ "/reverse" }, { "PruneUnused", "Edit", &Instance::CMD_PruneUnused }, { "MoveObjectsDialog", "Edit", &Instance::CMD_MoveObjects_Dialog }, { "ScaleObjectsDialog", "Edit", &Instance::CMD_ScaleObjects_Dialog }, { "RotateObjectsDialog", "Edit", &Instance::CMD_RotateObjects_Dialog }, /* ----- VIEW menu ----- */ { "Zoom", "View", &Instance::CMD_Zoom, /* flags */ "/center" }, { "ZoomWholeMap", "View", &Instance::CMD_ZoomWholeMap }, { "ZoomSelection", "View", &Instance::CMD_ZoomSelection }, { "DefaultProps", "View", &Instance::CMD_DefaultProps }, { "FindDialog", "View", &Instance::CMD_FindDialog }, { "FindNext", "View", &Instance::CMD_FindNext }, { "GoToCamera", "View", &Instance::CMD_GoToCamera }, { "PlaceCamera", "View", &Instance::CMD_PlaceCamera, /* flags */ "/open3d" }, { "JumpToObject", "View", &Instance::CMD_JumpToObject }, /* ------ TOOLS menu ------ */ { "PreferenceDialog", "Tools", &Instance::CMD_Preferences }, { "TestMap", "Tools", &Instance::CMD_TestMap }, { "ChangeTestSettings", "Tools", &Instance::CMD_ChangeTestSettings }, { "RecalcSectors", "Tools", &Instance::CMD_RecalcSectors }, { "BuildAllNodes", "Tools", &Instance::CMD_BuildAllNodes }, { "EditLump", "Tools", &Instance::CMD_EditLump, /* flags */ "/header /scripts" }, { "AddBehavior", "Tools", &Instance::CMD_AddBehaviorLump }, { "LogViewer", "Tools", &Instance::CMD_LogViewer }, /* ------ HELP menu ------ */ { "OnlineDocs", "Help", &Instance::CMD_OnlineDocs }, { "AboutDialog", "Help", &Instance::CMD_AboutDialog }, /* ----- general operations ----- */ { "Merge", "General", &Instance::CMD_Merge, /* flags */ "/keep" }, { "Disconnect", "General", &Instance::CMD_Disconnect }, { "Mirror", "General", &Instance::CMD_Mirror, /* flags */ NULL, /* keywords */ "horiz vert" }, { "Rotate90", "General", &Instance::CMD_Rotate90, /* flags */ NULL, /* keywords */ "cw acw" }, { "Enlarge", "General", &Instance::CMD_Enlarge }, { "Shrink", "General", &Instance::CMD_Shrink }, { "Quantize", "General", &Instance::CMD_Quantize }, { "ApplyTag", "General", &Instance::CMD_ApplyTag, /* flags */ NULL, /* keywords */ "fresh last" }, { "ACT_Click", "General", &Instance::CMD_ACT_Click, /* flags */ "/noselect /nodrag /nosplit" }, { "ACT_Drag", "General", &Instance::CMD_ACT_Drag }, { "ACT_Transform", "General", &Instance::CMD_ACT_Transform, /* flags */ NULL, /* keywords */ "scale stretch rotate rotscale skew" }, /* ------ LineDef mode ------ */ { "LIN_Align", NULL, &Instance::CMD_LIN_Align, /* flags */ "/x /y /right /clear" }, { "LIN_Flip", NULL, &Instance::CMD_LIN_Flip, /* flags */ "/force" }, { "LIN_SwapSides", NULL, &Instance::CMD_LIN_SwapSides }, { "LIN_SplitHalf", NULL, &Instance::CMD_LIN_SplitHalf }, { "LIN_SelectPath", NULL, &Instance::CMD_LIN_SelectPath, /* flags */ "/fresh /onesided /sametex" }, /* ------ Sector mode ------ */ { "SEC_Floor", NULL, &Instance::CMD_SEC_Floor }, { "SEC_Ceil", NULL, &Instance::CMD_SEC_Ceil }, { "SEC_Light", NULL, &Instance::CMD_SEC_Light }, { "SEC_SelectGroup", NULL, &Instance::CMD_SEC_SelectGroup, /* flags */ "/fresh /can_walk /doors /floor_h /floor_tex /ceil_h /ceil_tex /light /tag /special" }, { "SEC_SwapFlats", NULL, &Instance::CMD_SEC_SwapFlats }, /* ------ Thing mode ------ */ { "TH_Spin", NULL, &Instance::CMD_TH_SpinThings }, /* ------ Vertex mode ------ */ { "VT_ShapeLine", NULL, &Instance::CMD_VT_ShapeLine }, { "VT_ShapeArc", NULL, &Instance::CMD_VT_ShapeArc }, /* -------- Browser -------- */ { "BrowserMode", "Browser", &Instance::CMD_BrowserMode, /* flags */ "/recent", /* keywords */ "obj tex flat line sec genline" }, { "BR_CycleCategory", "Browser", &Instance::CMD_BR_CycleCategory }, { "BR_ClearSearch", "Browser", &Instance::CMD_BR_ClearSearch }, { "BR_Scroll", "Browser", &Instance::CMD_BR_Scroll }, // end of command list { NULL, NULL, 0, NULL } }; } // namespace global void Editor_RegisterCommands() { M_RegisterCommandList(global::command_table); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_cutpaste.cc000066400000000000000000000635111464327712600210010ustar00rootroot00000000000000//------------------------------------------------------------------------ // LEVEL CUT 'N' PASTE //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2009-2019 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Instance.h" #include "LineDef.h" #include "Sector.h" #include "SideDef.h" #include "Thing.h" #include "Vertex.h" #define INVALID_SECTOR (-999999) class clipboard_data_c { public: // the mode used when the objects were Copied const ObjType mode; // NOTE: // // The references here normally refer to other objects in here // (as though this was a little self-contained map). For example, // the LineDef::right field is an index into sides[]. // // The exception is sector references in the SideDefs. These // values refer to the real map when >= 0, and refer to local // sectors when < 0 (negate and add 1). // // That's because we generally want a copy'n'pasted piece of the // map (linedefs or sectors) to "fit in" with nearby sections of // the map. const bool uses_real_sectors; std::vector things; std::vector verts; std::vector sectors; std::vector sides; std::vector lines; public: explicit clipboard_data_c(ObjType mode) : mode(mode), uses_real_sectors(mode == ObjType::linedefs || mode == ObjType::sectors) { } int TotalSize() const { size_t num = things.size() + verts.size() + sectors.size() + sides.size() + lines.size(); return (int)num; } void Paste_BA_Message(EditOperation &op) const { size_t t = things.size(); size_t v = verts.size(); size_t s = sectors.size(); size_t l = lines.size(); if (s > 0) { const char *name = NameForObjectType(ObjType::sectors, s != 1); op.setMessage("pasted %zu %s", s, name); } else if (l > 0) { const char *name = NameForObjectType(ObjType::linedefs, l != 1); op.setMessage("pasted %zu %s", l, name); } else if (t > 0) { const char *name = NameForObjectType(ObjType::things, t != 1); op.setMessage("pasted %zu %s", t, name); } else if (v > 0) { const char *name = NameForObjectType(ObjType::vertices, v != 1); op.setMessage("pasted %zu %s", v, name); } else { op.setMessage("pasted something"); } } void InsertRealSector(int snum) { if (! uses_real_sectors) return; for (SideDef &side : sides) { if (side.sector >= snum) side.sector++; } } void DeleteRealSector(int snum) { if (! uses_real_sectors) return; for (SideDef &side : sides) { if (side.sector == snum) side.sector = INVALID_SECTOR; else if (side.sector > snum) side.sector--; } } void RemoveSectorRefs() { if (! uses_real_sectors) return; for (SideDef &side : sides) { if (side.sector >= 0) side.sector = INVALID_SECTOR; } } }; static clipboard_data_c * clip_board; static bool clip_doing_paste; // // this remove sidedefs which refer to local sectors, allowing the // clipboard geometry to persist when changing maps. // void Clipboard_ClearLocals() { if (clip_board) clip_board->RemoveSectorRefs(); } static bool Clipboard_HasStuff() { return clip_board ? true : false; } void Clipboard_NotifyBegin() { } void Clipboard_NotifyEnd() { } void Clipboard_NotifyInsert(const Document &doc, ObjType type, int objnum) { // this function notifies us that a new sector is about to be // inserted in the map (causing other sectors to be moved). if (type != ObjType::sectors) return; if (! clip_board) return; // paste operations should only insert new sectors at the end if (objnum < doc.numSectors()) { SYS_ASSERT(! clip_doing_paste); } clip_board->InsertRealSector(objnum); } void Clipboard_NotifyDelete(ObjType type, int objnum) { // this function notifies us that a sector is about to be deleted // (causing other sectors to be moved). if (type != ObjType::sectors) return; if (! clip_board) return; SYS_ASSERT(! clip_doing_paste); clip_board->DeleteRealSector(objnum); } void Clipboard_NotifyChange(ObjType type, int objnum, int field) { // field changes never affect the clipboard } //---------------------------------------------------------------------- // Texture Clipboard //---------------------------------------------------------------------- namespace tex_clipboard { SString tex; SString flat; int thing; }; void Texboard_Clear() { tex_clipboard::tex.clear(); tex_clipboard::flat.clear(); tex_clipboard::thing = 0; } StringID Texboard_GetTexNum(const ConfigData &config) { if (tex_clipboard::tex.empty()) tex_clipboard::tex = config.default_wall_tex; return BA_InternaliseString(tex_clipboard::tex); } StringID Texboard_GetFlatNum(const ConfigData &config) { if (tex_clipboard::flat.empty()) tex_clipboard::flat = config.default_floor_tex; return BA_InternaliseString(tex_clipboard::flat); } int Texboard_GetThing(const ConfigData &config) { if (tex_clipboard::thing == 0) return config.default_thing; return tex_clipboard::thing; } void Texboard_SetTex(const SString &new_tex, const ConfigData &config) { tex_clipboard::tex = new_tex; if (config.features.mix_textures_flats) tex_clipboard::flat = new_tex; } void Texboard_SetFlat(const SString &new_flat, const ConfigData &config) { tex_clipboard::flat = new_flat; if (config.features.mix_textures_flats) tex_clipboard::tex = new_flat; } void Texboard_SetThing(int new_id) { tex_clipboard::thing = new_id; } //------------------------------------------------------------------------ static void CopyGroupOfObjects(const Document &doc, const selection_c &list) { // this is used for LineDefs and Sectors, where we need to copy // groups of objects and create internal references between them. bool is_sectors = list.what_type() == ObjType::sectors; selection_c vert_sel(ObjType::vertices); selection_c side_sel(ObjType::sidedefs); selection_c line_sel(ObjType::linedefs); ConvertSelection(doc, list, line_sel); ConvertSelection(doc, line_sel, vert_sel); // determine needed sidedefs for (sel_iter_c it(line_sel) ; !it.done() ; it.next()) { const auto L = doc.linedefs[*it]; if (L->right >= 0) side_sel.set(L->right); if (L->left >= 0) side_sel.set(L->left); } // these hold the mapping from real index --> clipboard index std::map vert_map; std::map sector_map; std::map side_map; for (sel_iter_c it(vert_sel) ; !it.done() ; it.next()) { vert_map[*it] = (int)clip_board->verts.size(); clip_board->verts.push_back(*doc.vertices[*it]); } if (is_sectors) { for (sel_iter_c it(list) ; !it.done() ; it.next()) { sector_map[*it] = (int)clip_board->sectors.size(); clip_board->sectors.push_back(*doc.sectors[*it]); } } for (sel_iter_c it(side_sel) ; !it.done() ; it.next()) { side_map[*it] = (int)clip_board->sides.size(); clip_board->sides.push_back(*doc.sidedefs[*it]); SideDef &SD = clip_board->sides.back(); // adjust sector references, if needed if (is_sectors && list.get(SD.sector)) { SYS_ASSERT(sector_map.find(SD.sector) != sector_map.end()); SD.sector = -1 - sector_map[SD.sector]; } } for (sel_iter_c it(line_sel) ; !it.done() ; it.next()) { clip_board->lines.push_back(*doc.linedefs[*it]); LineDef &L = clip_board->lines.back(); // adjust vertex references SYS_ASSERT(vert_map.find(L.start) != vert_map.end()); SYS_ASSERT(vert_map.find(L.end) != vert_map.end()); L.start = vert_map[L.start]; L.end = vert_map[L.end ]; // adjust sidedef references if (L.right >= 0) { SYS_ASSERT(side_map.find(L.right) != side_map.end()); L.right = side_map[L.right]; } if (L.left >= 0) { SYS_ASSERT(side_map.find(L.left) != side_map.end()); L.left = side_map[L.left]; } } // in sectors mode, copy things too if (is_sectors) { selection_c thing_sel(ObjType::things); ConvertSelection(doc, list, thing_sel); for (sel_iter_c it(thing_sel) ; !it.done() ; it.next()) clip_board->things.push_back(*doc.things[*it]); } } bool Instance::Clipboard_DoCopy() { SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) return false; // create storage for the copied objects if (clip_board) delete clip_board; bool result = true; clip_board = new clipboard_data_c(edit.mode); switch (edit.mode) { case ObjType::things: for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) clip_board->things.push_back(*level.things[*it]); break; case ObjType::vertices: for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) clip_board->verts.push_back(*level.vertices[*it]); break; case ObjType::linedefs: case ObjType::sectors: CopyGroupOfObjects(level, *edit.Selected); break; default: result = false; break; } int total = edit.Selected->count_obj(); if (total == 1) Status_Set("copied %s #%d", NameForObjectType(edit.Selected->what_type()), edit.Selected->find_first()); else Status_Set("copied %d %s", total, NameForObjectType(edit.Selected->what_type(), true /* plural */)); if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); return result; } //------------------------------------------------------------------------ template static v2double_t CentreOfPointObjects(const std::vector &list) { if (list.empty()) return {}; v2double_t sum = {}; for (const T &object : list) sum += object.xy(); sum /= (double)list.size(); return sum; } static void PasteGroupOfObjects(EditOperation &op, MapFormat format, const v2double_t &pos) { v2double_t cpos = CentreOfPointObjects(clip_board->verts); // these hold the mapping from clipboard index --> real index std::map vert_map; std::map sector_map; std::map side_map; unsigned int i; for (i = 0 ; i < clip_board->verts.size() ; i++) { int new_v = op.addNew(ObjType::vertices); auto V = op.doc.vertices[new_v]; vert_map[i] = new_v; *V = clip_board->verts[i]; V->SetRawXY(format, V->xy() + pos - cpos); } for (i = 0 ; i < clip_board->sectors.size() ; i++) { int new_s = op.addNew(ObjType::sectors); auto S = op.doc.sectors[new_s]; sector_map[i] = new_s; *S = clip_board->sectors[i]; } for (i = 0 ; i < clip_board->sides.size() ; i++) { // handle invalidated sectors (as if sidedef had been deleted) if (clip_board->sides[i].sector == INVALID_SECTOR) { side_map[i] = -1; continue; } int new_sd = op.addNew(ObjType::sidedefs); auto SD = op.doc.sidedefs[new_sd]; side_map[i] = new_sd; *SD = clip_board->sides[i]; if (SD->sector < 0) { int local = -1 - SD->sector; SYS_ASSERT(sector_map.find(local) != sector_map.end()); SD->sector = sector_map[local]; } } for (i = 0 ; i < clip_board->lines.size() ; i++) { int new_l = op.addNew(ObjType::linedefs); auto L = op.doc.linedefs[new_l]; *L = clip_board->lines[i]; // adjust vertex references SYS_ASSERT(vert_map.find(L->start) != vert_map.end()); SYS_ASSERT(vert_map.find(L->end) != vert_map.end()); L->start = vert_map[L->start]; L->end = vert_map[L->end ]; // adjust sidedef references if (op.doc.getRight(*L)) { SYS_ASSERT(side_map.find(L->right) != side_map.end()); L->right = side_map[L->right]; } if (op.doc.getLeft(*L)) { SYS_ASSERT(side_map.find(L->left) != side_map.end()); L->left = side_map[L->left]; } // flip linedef if necessary if (op.doc.getLeft(*L) && ! op.doc.getRight(*L)) { op.doc.linemod.flipLinedef(op, new_l); } // if the linedef lost a side, fix texturing if (L->OneSided() && is_null_tex(op.doc.getRight(*L)->MidTex())) op.doc.linemod.fixForLostSide(op, new_l); } for (i = 0 ; i < clip_board->things.size() ; i++) { int new_t = op.addNew(ObjType::things); auto T = op.doc.things[new_t]; *T = clip_board->things[i]; T->SetRawXY(format, T->xy() + pos - cpos); } } void Instance::ReselectGroup() { // this assumes all the new objects are at the end of their // array (currently true, but not a guarantee of BA_New). if (edit.mode == ObjType::things) { if (clip_board->mode == ObjType::things || clip_board->mode == ObjType::sectors) { int count = (int)clip_board->things.size(); Selection_Clear(); edit.Selected->frob_range(level.numThings() - count, level.numThings()-1, BitOp::add); } return; } bool was_mappy = (clip_board->mode == ObjType::vertices || clip_board->mode == ObjType::linedefs || clip_board->mode == ObjType::sectors); bool is_mappy = (edit.mode == ObjType::vertices || edit.mode == ObjType::linedefs || edit.mode == ObjType::sectors); if (! (was_mappy && is_mappy)) return; selection_c new_sel(clip_board->mode); if (clip_board->mode == ObjType::vertices) { int count = (int)clip_board->verts.size(); new_sel.frob_range(level.numVertices() - count, level.numVertices() -1, BitOp::add); } else if (clip_board->mode == ObjType::linedefs) { // Note: this doesn't behave as expected if the editing mode is // SECTORS, because the pasted lines do not completely surround // the sectors (non-pasted lines refer to them too). int count = (int)clip_board->lines.size(); new_sel.frob_range(level.numLinedefs() - count, level.numLinedefs() -1, BitOp::add); } else { SYS_ASSERT(clip_board->mode == ObjType::sectors); int count = (int)clip_board->sectors.size(); new_sel.frob_range(level.numSectors() - count, level.numSectors() -1, BitOp::add); } Selection_Clear(); ConvertSelection(level, new_sel, *edit.Selected); } bool Instance::Clipboard_DoPaste() { bool reselect = true; // CONFIG TODO unsigned int i; if (! Clipboard_HasStuff()) return false; // figure out where to put stuff v2double_t pos = edit.map.xy; if (! edit.pointer_in_window) { pos = grid.getOrig(); } // honor the grid snapping setting pos = grid.Snap(pos); { EditOperation op(level.basis); clip_board->Paste_BA_Message(op); clip_doing_paste = true; switch (clip_board->mode) { case ObjType::things: { v2double_t cpos = CentreOfPointObjects(clip_board->things); for (unsigned int i = 0 ; i < clip_board->things.size() ; i++) { int new_t = op.addNew(ObjType::things); auto T = level.things[new_t]; *T = clip_board->things[i]; T->SetRawXY(loaded.levelFormat, T->xy() + pos - cpos); recent_things.insert_number(T->type); } break; } case ObjType::vertices: { v2double_t cpos = CentreOfPointObjects(clip_board->verts); for (i = 0 ; i < clip_board->verts.size() ; i++) { int new_v = op.addNew(ObjType::vertices); auto V = level.vertices[new_v]; *V = clip_board->verts[i]; V->SetRawXY(loaded.levelFormat, V->xy() + pos - cpos); } break; } case ObjType::linedefs: case ObjType::sectors: { PasteGroupOfObjects(op, loaded.levelFormat, pos); break; } default: break; } clip_doing_paste = false; } edit.error_mode = false; if (reselect) ReselectGroup(); return true; } //------------------------------------------------------------------------ void Instance::CMD_CopyAndPaste() { if (edit.Selected->empty() && edit.highlight.is_nil()) { Beep("Nothing to copy and paste"); return; } if (Clipboard_DoCopy()) { Clipboard_DoPaste(); } } void Instance::CMD_Clipboard_Cut() { if (main_win->ClipboardOp(EditCommand::cut)) return; if (edit.render3d && edit.mode != ObjType::things) { Render3D_CB_Cut(); return; } if (! Clipboard_DoCopy()) { Beep("Nothing to cut"); return; } ExecuteCommand("Delete"); } void Instance::CMD_Clipboard_Copy() { if (main_win->ClipboardOp(EditCommand::copy)) return; if (edit.render3d && edit.mode != ObjType::things) { Render3D_CB_Copy(); return; } if (! Clipboard_DoCopy()) { Beep("Nothing to copy"); return; } } void Instance::CMD_Clipboard_Paste() { if (main_win->ClipboardOp(EditCommand::paste)) return; if (edit.render3d && edit.mode != ObjType::things) { Render3D_CB_Paste(); return; } if (! Clipboard_DoPaste()) { Beep("Clipboard is empty"); return; } } //------------------------------------------------------------------------ void UnusedVertices(const Document &doc, const selection_c &lines, selection_c &result) { SYS_ASSERT(lines.what_type() == ObjType::linedefs); ConvertSelection(doc, lines, result); for (int n = 0 ; n < doc.numLinedefs(); n++) { // we are interested in the lines we are NOT deleting if (lines.get(n)) continue; const auto L = doc.linedefs[n]; result.clear(L->start); result.clear(L->end); } } void UnusedSideDefs(const Document &doc, const selection_c &lines, const selection_c *secs, selection_c &result) { SYS_ASSERT(lines.what_type() == ObjType::linedefs); ConvertSelection(doc, lines, result); for (int n = 0 ; n < doc.numLinedefs(); n++) { // we are interested in the lines we are NOT deleting if (lines.get(n)) continue; const auto L = doc.linedefs[n]; if (doc.getRight(*L)) result.clear(L->right); if (doc.getLeft(*L)) result.clear(L->left); } for (int i = 0 ; i < doc.numSidedefs(); i++) { const auto SD = doc.sidedefs[i]; if (secs && secs->get(SD->sector)) result.set(i); } } static void UnusedLineDefs(const Document &doc, const selection_c §ors, selection_c &result) { SYS_ASSERT(sectors.what_type() == ObjType::sectors); for (int n = 0 ; n < doc.numLinedefs(); n++) { const auto L = doc.linedefs[n]; // check if touches a to-be-deleted sector // -1 : no side // 0 : deleted side // +1 : kept side int right_m = (L->right < 0) ? -1 : sectors.get(doc.getRight(*L)->sector) ? 0 : 1; int left_m = (L->left < 0) ? -1 : sectors.get(doc.getLeft(*L) ->sector) ? 0 : 1; if (std::max(right_m, left_m) == 0) { result.set(n); } } } static void DuddedSectors(const Document &doc, const selection_c &verts, const selection_c &lines, selection_c &result) { SYS_ASSERT(verts.what_type() == ObjType::vertices); SYS_ASSERT(lines.what_type() == ObjType::linedefs); // collect all the sectors that touch a linedef being removed. bitvec_c del_lines(doc.numLinedefs()); for (int n = 0 ; n < doc.numLinedefs(); n++) { const auto linedef = doc.linedefs[n]; if (lines.get(n) || verts.get(linedef->start) || verts.get(linedef->end)) { del_lines.set(n); if (doc.getSectorID(*linedef, Side::left) >= 0) result.set(doc.getSectorID(*linedef, Side::left)); if (doc.getSectorID(*linedef, Side::right) >= 0) result.set(doc.getSectorID(*linedef, Side::right)); } } // visit all linedefs NOT being removed, and see if the sector(s) // on it will actually be OK after the delete. for (int n = 0 ; n < doc.numLinedefs(); n++) { if(result.empty()) // stop looking if there's nothing else to remove return; const auto linedef = doc.linedefs[n]; if (lines.get(n) || verts.get(linedef->start) || verts.get(linedef->end)) continue; for (Side what_side : kSides) { int sec_num = doc.getSectorID(*linedef, what_side); if (sec_num < 0) continue; // skip sectors that are not potentials for removal, // and prevent the expensive tests below... if (! result.get(sec_num)) continue; // check if the linedef opposite faces this sector (BUT // IGNORING any lines being deleted). when found, we // know that this sector should be kept. Side opp_side; int opp_ld = doc.hover.getOppositeLinedef(n, what_side, &opp_side, &del_lines, nullptr); if (opp_ld < 0) continue; const auto oppositeLinedef = doc.linedefs[opp_ld]; if (doc.getSectorID(*oppositeLinedef, opp_side) == sec_num) result.clear(sec_num); } } } static void FixupLineDefs(EditOperation &op, const Document &doc, selection_c *lines, selection_c *sectors) { for (sel_iter_c it(lines) ; !it.done() ; it.next()) { const auto L = doc.linedefs[*it]; // the logic is ugly here mainly to handle flipping (in particular, // not to flip the line when _both_ sides are unlinked). bool do_right = doc.getRight(*L) ? sectors->get(doc.getRight(*L)->sector) : false; bool do_left = doc.getLeft(*L) ? sectors->get(doc.getLeft(*L) ->sector) : false; // line shouldn't be in list unless it touches the sector SYS_ASSERT(do_right || do_left); if (do_right && do_left) { doc.linemod.removeSidedef(op, *it, Side::right); doc.linemod.removeSidedef(op, *it, Side::left); } else if (do_right) { doc.linemod.removeSidedef(op, *it, Side::right); doc.linemod.flipLinedef(op, *it); } else // do_left { doc.linemod.removeSidedef(op, *it, Side::left); } } } static bool DeleteVertex_MergeLineDefs(Document &doc, int v_num) { // returns true if OK, false if would create an overlapping linedef // [ meaning the vertex should be deleted normally ] // find the linedefs int ld1 = -1; int ld2 = -1; for (int n = 0 ; n < doc.numLinedefs(); n++) { const auto L = doc.linedefs[n]; if (L->start == v_num || L->end == v_num) { SYS_ASSERT(ld2 < 0); if (ld1 < 0) ld1 = n; else ld2 = n; } } SYS_ASSERT(ld1 >= 0); SYS_ASSERT(ld2 >= 0); const LineDef *L1 = doc.linedefs[ld1].get(); const LineDef *L2 = doc.linedefs[ld2].get(); // we merge L2 into L1, unless L1 is significantly shorter if (doc.calcLength(*L1) < doc.calcLength(*L2) * 0.7) { std::swap(ld1, ld2); std::swap(L1, L2); } // determine the remaining vertices int v1 = (L1->start == v_num) ? L1->end : L1->start; int v2 = (L2->start == v_num) ? L2->end : L2->start; // ensure we don't create two directly overlapping linedefs if (doc.linemod.linedefAlreadyExists(v1, v2)) return false; // see what sidedefs would become unused selection_c line_sel(ObjType::linedefs); selection_c side_sel(ObjType::sidedefs); line_sel.set(ld2); UnusedSideDefs(doc, line_sel, NULL /* sec_sel */, side_sel); EditOperation op(doc.basis); op.setMessage("deleted vertex #%d\n", v_num); if (L1->start == v_num) op.changeLinedef(ld1, LineDef::F_START, v2); else op.changeLinedef(ld1, LineDef::F_END, v2); // NOT-DO: update X offsets on existing linedef op.del(ObjType::linedefs, ld2); op.del(ObjType::vertices, v_num); doc.objects.del(op, side_sel); return true; } void DeleteObjects_WithUnused(EditOperation &op, const Document &doc, const selection_c &list, bool keep_things, bool keep_verts, bool keep_lines) { selection_c vert_sel(ObjType::vertices); selection_c side_sel(ObjType::sidedefs); selection_c line_sel(ObjType::linedefs); selection_c sec_sel(ObjType::sectors); switch (list.what_type()) { case ObjType::vertices: vert_sel.merge(list); break; case ObjType::linedefs: line_sel.merge(list); break; case ObjType::sectors: sec_sel.merge(list); break; default: /* OBJ_THINGS or OBJ_SIDEDEFS */ doc.objects.del(op, list); return; } if (list.what_type() == ObjType::vertices) { for (int n = 0 ; n < doc.numLinedefs(); n++) { const auto L = doc.linedefs[n]; if (list.get(L->start) || list.get(L->end)) line_sel.set(n); } } if (!keep_lines && list.what_type() == ObjType::sectors) { UnusedLineDefs(doc, sec_sel, line_sel); if (line_sel.notempty()) { UnusedSideDefs(doc, line_sel, &sec_sel, side_sel); if (!keep_verts) UnusedVertices(doc, line_sel, vert_sel); } } if (!keep_verts && list.what_type() == ObjType::linedefs) { UnusedVertices(doc, line_sel, vert_sel); } // try to detect sectors that become "dudded", where all the // remaining linedefs of the sector face into the void. if (list.what_type() == ObjType::vertices || list.what_type() == ObjType::linedefs) { DuddedSectors(doc, vert_sel, line_sel, sec_sel); UnusedSideDefs(doc, line_sel, &sec_sel, side_sel); } // delete things from each deleted sector if (!keep_things && sec_sel.notempty()) { selection_c thing_sel(ObjType::things); ConvertSelection(doc, sec_sel, thing_sel); doc.objects.del(op, thing_sel); } // perform linedef fixups here (when sectors get removed) if (sec_sel.notempty()) { selection_c fixups(ObjType::linedefs); ConvertSelection(doc, sec_sel, fixups); // skip lines which will get deleted fixups.unmerge(line_sel); FixupLineDefs(op, doc, &fixups, &sec_sel); } // actually delete stuff, in the correct order doc.objects.del(op, line_sel); doc.objects.del(op, side_sel); doc.objects.del(op, vert_sel); doc.objects.del(op, sec_sel); } void Instance::CMD_Delete() { if (main_win && main_win->ClipboardOp(EditCommand::del)) return; SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { Beep("Nothing to delete"); return; } bool keep = Exec_HasFlag("/keep"); auto clearSelection = [this]() { Editor_ClearAction(); // always clear the selection (deleting objects invalidates it) Selection_Clear(); edit.highlight.clear(); edit.split_line.clear(); }; // special case for a single vertex connected to two linedefs, // we delete the vertex but merge the two linedefs. if (edit.mode == ObjType::vertices && edit.Selected->count_obj() == 1) { int v_num = edit.Selected->find_first(); SYS_ASSERT(v_num >= 0); if (level.vertmod.howManyLinedefs(v_num) == 2) { if (DeleteVertex_MergeLineDefs(level, v_num)) { clearSelection(); RedrawMap(); } } // delete vertex normally } { EditOperation op(level.basis); op.setMessageForSelection("deleted", *edit.Selected); selection_c deleteList = *edit.Selected; clearSelection(); DeleteObjects_WithUnused(op, level, deleteList, keep, false /* keep_verts */, keep); } RedrawMap(); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_cutpaste.h000066400000000000000000000045261464327712600206440ustar00rootroot00000000000000//------------------------------------------------------------------------ // LEVEL CUT 'N' PASTE //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2009-2019 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_E_CUTPASTE_H__ #define __EUREKA_E_CUTPASTE_H__ #include "objid.h" class EditOperation; class selection_c; class SString; class StringID; struct ConfigData; struct Document; // // Edit menu command // enum class EditCommand { cut, copy, paste, del }; void Clipboard_ClearLocals(); void Clipboard_NotifyBegin(); void Clipboard_NotifyInsert(const Document &doc, ObjType type, int objnum); void Clipboard_NotifyDelete(ObjType type, int objnum); void Clipboard_NotifyChange(ObjType type, int objnum, int field); void Clipboard_NotifyEnd(); void UnusedVertices(const Document &doc, const selection_c &lines, selection_c &result); void UnusedSideDefs(const Document &doc, const selection_c &lines, const selection_c *secs, selection_c &result); void DeleteObjects_WithUnused(EditOperation &op, const Document &doc, const selection_c &list, bool keep_things, bool keep_verts , bool keep_lines ); //---------------------------------------------------------------------- // Texture Clipboard //---------------------------------------------------------------------- void Texboard_Clear(); StringID Texboard_GetFlatNum(const ConfigData &config); StringID Texboard_GetTexNum(const ConfigData &config); int Texboard_GetThing(const ConfigData &config); void Texboard_SetFlat(const SString &new_flat, const ConfigData &config); void Texboard_SetTex(const SString &new_tex, const ConfigData &config); void Texboard_SetThing(int new_id); #endif /* __EUREKA_E_CUTPASTE_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_hover.cc000066400000000000000000000706061464327712600202770ustar00rootroot00000000000000//------------------------------------------------------------------------ // HIGHLIGHT HELPER //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include #include "e_hover.h" #include "e_linedef.h" // SplitLineDefAtVertex() #include "e_main.h" // Map_bound_xxx #include "LineDef.h" #include "m_game.h" #include "r_grid.h" #include "Thing.h" #include "Vertex.h" extern int vertex_radius(double scale); //------------------------------------------------------------------------ #define FASTOPP_DIST 320 struct opp_test_state_t { int ld = 0; Side ld_side = Side::right; // a SIDE_XXX value Side * result_side = nullptr; double dx = 0, dy = 0; // origin of casting line double x = 0, y = 0; // casting line is horizontal? bool cast_horizontal = false; int best_match = 0; double best_dist = 0; const Document &doc; public: explicit opp_test_state_t(const Document &doc) : doc(doc) { } void ComputeCastOrigin() { SYS_ASSERT(ld >= 0 && ld < doc.numLinedefs()); // choose a coordinate on the source line near the middle, but make // sure the casting line is not integral (i.e. lies between two lines // on the unit grid) so that we never directly hit a vertex. const auto L = doc.linedefs[ld]; dx = doc.getEnd(*L).x() - doc.getStart(*L).x(); dy = doc.getEnd(*L).y() - doc.getStart(*L).y(); cast_horizontal = fabs(dy) >= fabs(dx); x = doc.getStart(*L).x() + dx * 0.5; y = doc.getStart(*L).y() + dy * 0.5; if (cast_horizontal && fabs(dy) > 0) { if (fabs(dy) >= 2.0) { y = y + 0.4; x = x + 0.4 * dx / dy; } } if (!cast_horizontal && fabs(dx) > 0) { if (fabs(dx) >= 2.0) { x = x + 0.4; y = y + 0.4 * dy / dx; } } } void ProcessLine(int n) { if (ld == n) // ignore input line return; double nx1 = doc.getStart(*doc.linedefs[n]).x(); double ny1 = doc.getStart(*doc.linedefs[n]).y(); double nx2 = doc.getEnd(*doc.linedefs[n]).x(); double ny2 = doc.getEnd(*doc.linedefs[n]).y(); if (cast_horizontal) { if (ny1 == ny2) return; if (std::min(ny1, ny2) > y || std::max(ny1, ny2) < y) return; double dist = nx1 + (nx2 - nx1) * (y - ny1) / (ny2 - ny1) - x; if ( (dy < 0) == (ld_side == Side::right) ) dist = -dist; if (dist > 0 && dist < best_dist) { best_match = n; best_dist = dist; if (result_side) { if ( (dy > 0) != (ny2 > ny1) ) *result_side = ld_side; else *result_side = -ld_side; } } } else // casting a vertical ray { if (nx1 == nx2) return; if (std::min(nx1, nx2) > x || std::max(nx1, nx2) < x) return; double dist = ny1 + (ny2 - ny1) * (x - nx1) / (nx2 - nx1) - y; if ( (dx > 0) == (ld_side == Side::right) ) dist = -dist; if (dist > 0 && dist < best_dist) { best_match = n; best_dist = dist; if (result_side) { if ( (dx > 0) != (nx2 > nx1) ) *result_side = ld_side; else *result_side = -ld_side; } } } } }; void fastopp_node_c::Subdivide() { if (hi - lo <= FASTOPP_DIST) return; lo_child = std::make_unique(lo, mid, doc); hi_child = std::make_unique(mid, hi, doc); } void fastopp_node_c::AddLine_X(int ld, int x1, int x2) { if (lo_child && (x1 > lo_child->lo) && (x2 < lo_child->hi)) { lo_child->AddLine_X(ld, x1, x2); return; } if (hi_child && (x1 > hi_child->lo) && (x2 < hi_child->hi)) { hi_child->AddLine_X(ld, x1, x2); return; } lines.push_back(ld); } void fastopp_node_c::AddLine_X(int ld) { const auto L = doc.linedefs[ld]; // can ignore purely vertical lines if (doc.isVertical(*L)) return; double x1 = std::min(doc.getStart(*L).x(), doc.getEnd(*L).x()); double x2 = std::max(doc.getStart(*L).x(), doc.getEnd(*L).x()); AddLine_X(ld, (int)floor(x1), (int)ceil(x2)); } void fastopp_node_c::AddLine_Y(int ld, int y1, int y2) { if (lo_child && (y1 > lo_child->lo) && (y2 < lo_child->hi)) { lo_child->AddLine_Y(ld, y1, y2); return; } if (hi_child && (y1 > hi_child->lo) && (y2 < hi_child->hi)) { hi_child->AddLine_Y(ld, y1, y2); return; } lines.push_back(ld); } void fastopp_node_c::AddLine_Y(int ld) { const auto L = doc.linedefs[ld]; // can ignore purely horizonal lines if (doc.isHorizontal(*L)) return; double y1 = std::min(doc.getStart(*L).y(), doc.getEnd(*L).y()); double y2 = std::max(doc.getStart(*L).y(), doc.getEnd(*L).y()); AddLine_Y(ld, (int)floor(y1), (int)ceil(y2)); } void fastopp_node_c::Process(opp_test_state_t& test, double coord) const { for (unsigned int k = 0 ; k < lines.size() ; k++) test.ProcessLine(lines[k]); if (! lo_child) return; // the AddLine() methods ensure that lines are not added // into a child bucket unless the end points are completely // inside it -- and one unit away from the extremes. // // hence we never need to recurse down BOTH sides here. if (coord < (double)mid) lo_child->Process(test, coord); else hi_child->Process(test, coord); } // result: -1 for back, +1 for front, 0 for _exactly_on_ the line Side PointOnLineSide(double x, double y, double lx1, double ly1, double lx2, double ly2) { x -= lx1; y -= ly1; lx2 -= lx1; ly2 -= ly1; double tmp = (x * ly2 - y * lx2); return (tmp < 0) ? Side::left : (tmp > 0) ? Side::right : Side::neither; } //------------------------------------------------------------------------ struct thing_comparer_t { public: double distance = 9e9; bool inside = false; int radius = 1 << 30; bool operator<= (const thing_comparer_t& other) const { // being inside is always better if (inside && ! other.inside) return true; if (! inside && other.inside) return false; // small objects should "mask" large objects if (radius < other.radius) return true; if (radius > other.radius) return false; return (distance <= other.distance); } }; static Objid getNearestThing(const Document &doc, const ConfigData &config, const grid::State &grid, const v2double_t &pos); static Objid getNearestVertex(const Document &doc, const grid::State &grid, const v2double_t &pos); static Objid getNearestLinedef(const Document &doc, const grid::State &grid, const v2double_t &pos); // // Returns the object which is under the pointer at the given // coordinates. When several objects are close, the smallest // is chosen. // Objid hover::getNearbyObject(ObjType type, const Document &doc, const ConfigData &config, const grid::State &grid, const v2double_t &pos) { switch(type) { case ObjType::things: return getNearestThing(doc, config, grid, pos); case ObjType::vertices: return getNearestVertex(doc, grid, pos); case ObjType::linedefs: return getNearestLinedef(doc, grid, pos); case ObjType::sectors: return getNearestSector(doc, pos); default: BugError("Hover::getNearbyObject: bad objtype %d\n", (int)type); return Objid(); /* NOT REACHED */ } } // // Get the closest line, by casting horizontally // int hover::getClosestLine_CastingHoriz(const Document &doc, v2double_t pos, Side *side) { int best_match = -1; double best_dist = 9e9; // most lines have integral X coords, so offset slightly to // avoid hitting vertices. pos.y += 0.04; for(int n = 0; n < doc.numLinedefs(); n++) { v2double_t lpos1, lpos2; lpos1.y = doc.getStart(*doc.linedefs[n]).y(); lpos2.y = doc.getEnd(*doc.linedefs[n]).y(); // ignore purely horizontal lines if(lpos1.y == lpos2.y) continue; // does the linedef cross the horizontal ray? if(std::min(lpos1.y, lpos2.y) >= pos.y || std::max(lpos1.y, lpos2.y) <= pos.y) continue; lpos1.x = doc.getStart(*doc.linedefs[n]).x(); lpos2.x = doc.getEnd(*doc.linedefs[n]).x(); double dist = lpos1.x - pos.x + (lpos2.x - lpos1.x) * (pos.y - lpos1.y) / (lpos2.y - lpos1.y); if(fabs(dist) < best_dist) { best_match = n; best_dist = fabs(dist); if(side) { if(best_dist < 0.01) *side = Side::neither; // on the line else if((lpos1.y > lpos2.y) == (dist > 0)) *side = Side::right; // right side else *side = Side::left; // left side } } } return best_match; } // // Gets the closest line, casting vertically // static int getClosestLine_CastingVert(const Document &doc, v2double_t pos, Side *side) { int best_match = -1; double best_dist = 9e9; // most lines have integral X coords, so offset slightly to // avoid hitting vertices. pos.x += 0.04; for(int n = 0; n < doc.numLinedefs(); n++) { v2double_t lpos1, lpos2; lpos1.x = doc.getStart(*doc.linedefs[n]).x(); lpos2.x = doc.getEnd(*doc.linedefs[n]).x(); // ignore purely vertical lines if(lpos1.x == lpos2.x) continue; // does the linedef cross the vertical ray? if(std::min(lpos1.x, lpos2.x) >= pos.x || std::max(lpos1.x, lpos2.x) <= pos.x) continue; lpos1.y = doc.getStart(*doc.linedefs[n]).y(); lpos2.y = doc.getEnd(*doc.linedefs[n]).y(); double dist = lpos1.y - pos.y + (lpos2.y - lpos1.y) * (pos.x - lpos1.x) / (lpos2.x - lpos1.x); if(fabs(dist) < best_dist) { best_match = n; best_dist = fabs(dist); if(side) { if(best_dist < 0.01) *side = Side::neither; // on the line else if((lpos1.x > lpos2.x) == (dist < 0)) *side = Side::right; // right side else *side = Side::left; // left side } } } return best_match; } static Objid getNearestSplitLine(const Document &doc, MapFormat format, const grid::State &grid, const v2double_t &pos, int ignore_vert); // // Finds a split line // Objid hover::findSplitLine(const Document &doc, MapFormat format, const Editor_State_t &edit, const grid::State &grid, v2double_t &out_pos, const v2double_t &ptr, int ignore_vert) { out_pos = {}; Objid out = getNearestSplitLine(doc, format, grid, ptr, ignore_vert); if(!out.valid()) return Objid(); const auto L = doc.linedefs[out.num]; v2double_t v1 = doc.getStart(*L).xy(); v2double_t v2 = doc.getEnd(*L).xy(); double len = (v2 - v1).hypot(); if(grid.getRatio() > 0 && edit.action == EditorAction::drawLine) { const auto V = doc.vertices[edit.drawLine.from.num]; // convert ratio into a vector, use it to intersect the linedef v2double_t ppos1 = V->xy(); v2double_t ppos2 = ptr; grid.RatioSnapXY(ppos2, ppos1); if(fabs(ppos1.x - ppos2.x) < 0.1 && fabs(ppos1.y - ppos2.y) < 0.1) return Objid(); // compute intersection point double c = PerpDist(v1, ppos1, ppos2); double d = PerpDist(v2, ppos1, ppos2); int c_side = (c < -0.02) ? -1 : (c > 0.02) ? +1 : 0; int d_side = (d < -0.02) ? -1 : (d > 0.02) ? +1 : 0; if(c_side * d_side >= 0) return Objid(); c = c / (c - d); out_pos = v1 + (v2 - v1) * c; } else if(grid.snaps()) { // don't highlight the line if the new vertex would snap onto // the same coordinate as the start or end of the linedef. // [ I tried a bbox test here, but it was bad for axis-aligned lines ] out_pos = v2double_t(grid.ForceSnap(ptr)); // snapped onto an end point? if(doc.touchesCoord(*L, FFixedPoint(out_pos.x), FFixedPoint(out_pos.y))) return Objid(); // require snap coordinate be not TOO FAR from the line double perp = PerpDist(out_pos, v1, v2); if(fabs(perp) > len * 0.2) return Objid(); } else { // in FREE mode, ensure split point is directly on the linedef out_pos = ptr; linemod::moveCoordOntoLinedef(doc, out.num, out_pos); } // always ensure result is along the linedef (not off the ends) double along = AlongDist(out_pos, v1, v2); if(along < 0.05 || along > len - 0.05) return Objid(); return out; } // // Find a split line for a dangling vertex // Objid hover::findSplitLineForDangler(const Document &doc, MapFormat format, const grid::State &grid, int v_num) { return getNearestSplitLine(doc, format, grid, doc.vertices[v_num]->xy(), v_num); } // // Get the opposite linedef // int Hover::getOppositeLinedef(int ld, Side ld_side, Side *result_side, const bitvec_c *ignore_lines, FastOppositeTree *tree) const { // ld_side is either SIDE_LEFT or SIDE_RIGHT. // result_side uses the same values (never 0). opp_test_state_t test(doc); test.ld = ld; test.ld_side = ld_side; test.result_side = result_side; // this sets dx and dy test.ComputeCastOrigin(); if(test.dx == 0 && test.dy == 0) return -1; test.best_match = -1; test.best_dist = 9e9; if(tree) { // fast way : use the binary tree SYS_ASSERT(ignore_lines == NULL); if(test.cast_horizontal) tree->m_fastopp_Y_tree->Process(test, test.y); else tree->m_fastopp_X_tree->Process(test, test.x); } else { // normal way : test all linedefs for(int n = 0; n < doc.numLinedefs(); n++) { if(ignore_lines && ignore_lines->get(n)) continue; test.ProcessLine(n); } } return test.best_match; } // // Get oppossite sector // int Hover::getOppositeSector(int ld, Side ld_side, FastOppositeTree *tree) const { Side opp_side; int opp = getOppositeLinedef(ld, ld_side, &opp_side, nullptr, tree); // can see the void? if(opp < 0) return -1; return doc.getSectorID(*doc.linedefs[opp], opp_side); } // // Begin fast-opposite mode // FastOppositeTree::FastOppositeTree(Instance &inst) { inst.level.CalculateLevelBounds(); Document &doc = inst.level; m_fastopp_X_tree.emplace(static_cast(inst.level.Map_bound1.x - 8), static_cast(inst.level.Map_bound2.x + 8), doc); m_fastopp_Y_tree.emplace(static_cast(inst.level.Map_bound1.y - 8), static_cast(inst.level.Map_bound2.y + 8), doc); for(int n = 0; n < doc.numLinedefs(); n++) { m_fastopp_X_tree->AddLine_X(n); m_fastopp_Y_tree->AddLine_Y(n); } } // // whether point is outside of map // bool hover::isPointOutsideOfMap(const Document &doc, const v2double_t &v) { // this keeps track of directions tested int dirs = 0; // most end-points will be integral, so look in-between v2double_t v2 = v + v2double_t{ 0.04, 0.04 }; for(int n = 0; n < doc.numLinedefs(); n++) { v2double_t lv1 = doc.getStart(*doc.linedefs[n]).xy(); v2double_t lv2 = doc.getEnd(*doc.linedefs[n]).xy(); // does the linedef cross the horizontal ray? if(std::min(lv1.y, lv2.y) < v2.y && std::max(lv1.y, lv2.y) > v2.y) { double dist = lv1.x - v.x + (lv2.x - lv1.x) * (v2.y - lv1.y) / (lv2.y - lv1.y); dirs |= (dist < 0) ? 1 : 2; if(dirs == 15) return false; } // does the linedef cross the vertical ray? if(std::min(lv1.x, lv2.x) < v2.x && std::max(lv1.x, lv2.x) > v2.x) { double dist = lv1.y - v.y + (lv2.y - lv1.y) * (v2.x - lv1.x) / (lv2.x - lv1.x); dirs |= (dist < 0) ? 4 : 8; if(dirs == 15) return false; } } return true; } #define CROSSING_EPSILON 0.2 #define ALONG_EPSILON 0.1 // // Find crossing points // void Hover::findCrossingPoints(crossing_state_c &cross, v2double_t p1, int possible_v1, v2double_t p2, int possible_v2) const { cross.clear(); cross.start = p1; cross.end = p2; // when zooming out, make it easier to hit a vertex double close_dist = 4 * sqrt(1.0 / inst.grid.getScale()); close_dist = clamp(1.0, close_dist, 12.0); double dx = p2.x - p1.x; double dy = p2.y - p1.y; double length = hypot(dx, dy); // same coords? (sanity check) if(length < 0.01) return; /* must do all vertices FIRST */ for(int v = 0; v < doc.numVertices(); v++) { if(v == possible_v1 || v == possible_v2) continue; const auto VC = doc.vertices[v]; // ignore vertices at same coordinates as v1 or v2 if(VC->Matches(FFixedPoint(p1.x), FFixedPoint(p1.y)) || VC->Matches(FFixedPoint(p2.x), FFixedPoint(p2.y))) continue; // is this vertex sitting on the line? double perp = PerpDist(VC->xy(), p1, p2); if(fabs(perp) > close_dist) continue; double along = AlongDist(VC->xy(), p1, p2); if(along > ALONG_EPSILON && along < length - ALONG_EPSILON) { cross.add_vert(v, along); } } cross.Sort(); /* process each pair of adjacent vertices to find split lines */ v2double_t cur_pos1 = p1; int cur_v = possible_v1; // grab number of points now, since we will adding split points // (at the end) and we only want vertices here. size_t num_verts = cross.points.size(); for(size_t k = 0; k < num_verts; k++) { v2double_t next_pos2 = cross.points[k].pos; double next_v = cross.points[k].vert; findCrossingLines(cross, cur_pos1, static_cast(cur_v), next_pos2, static_cast(next_v)); cur_pos1 = next_pos2; cur_v = static_cast(next_v); } findCrossingLines(cross, cur_pos1, cur_v, p2, possible_v2); cross.Sort(); } // // determine which thing is under the mouse pointer // static Objid getNearestThing(const Document &doc, const ConfigData &config, const grid::State &grid, const v2double_t &pos) { double mapslack = 1 + 16.0f / grid.getScale(); double max_radius = MAX_RADIUS + ceil(mapslack); v2double_t lpos = pos - v2double_t(max_radius); v2double_t hpos = pos + v2double_t(max_radius); int best = -1; thing_comparer_t best_comp; for(int n = 0; n < doc.numThings(); n++) { const auto thing = doc.things[n]; v2double_t tpos = thing->xy(); // filter out things that are outside the search bbox. // this search box is enlarged by MAX_RADIUS. if(!tpos.inbounds(lpos, hpos)) continue; const thingtype_t &info = config.getThingType(thing->type); // more accurate bbox test using the real radius double r = info.radius + mapslack; if(!pos.inbounds(tpos - v2double_t(r + mapslack), tpos + v2double_t(r + mapslack))) continue; thing_comparer_t th_comp; th_comp.distance = (pos - tpos).hypot(); th_comp.radius = (int)r; th_comp.inside = pos.inboundsStrict(tpos - v2double_t(r), tpos + v2double_t(r)); if(best < 0 || th_comp <= best_comp) { best = n; best_comp = th_comp; } } if(best >= 0) return Objid(ObjType::things, best); // none found return Objid(); } // // determine which vertex is under the pointer // static Objid getNearestVertex(const Document &doc, const grid::State &grid, const v2double_t &pos) { const int screen_pix = vertex_radius(grid.getScale()); double mapslack = 1 + (4 + screen_pix) / grid.getScale(); // workaround for overly zealous highlighting when zoomed in far if(grid.getScale() >= 15.0) mapslack *= 0.7; if(grid.getScale() >= 31.0) mapslack *= 0.5; v2double_t lpos = pos - v2double_t(mapslack + 0.5); v2double_t hpos = pos + v2double_t(mapslack + 0.5); int best = -1; double best_dist = 9e9; for(int n = 0; n < doc.numVertices(); n++) { v2double_t vpos = doc.vertices[n]->xy(); // filter out vertices that are outside the search bbox if(!vpos.inbounds(lpos, hpos)) continue; double dist = (pos - vpos).hypot(); if(dist > mapslack) continue; // use "<=" because if there are superimposed vertices, we want // to return the highest-numbered one. if(dist <= best_dist) { best = n; best_dist = dist; } } if(best >= 0) return Objid(ObjType::vertices, best); // none found return Objid(); } static double getApproximateDistanceToLinedef(const Document &doc, const LineDef &line, const v2double_t &pos); // // determine which linedef is under the pointer // static Objid getNearestLinedef(const Document &doc, const grid::State &grid, const v2double_t &pos) { // slack in map units double mapslack = 2.5 + 16.0f / grid.getScale(); v2double_t lpos = pos - v2double_t(mapslack); v2double_t hpos = pos + v2double_t(mapslack); int best = -1; double best_dist = 9e9; for(int n = 0; n < doc.numLinedefs(); n++) { v2double_t pos1 = doc.getStart(*doc.linedefs[n]).xy(); v2double_t pos2 = doc.getEnd(*doc.linedefs[n]).xy(); // Skip all lines of which all points are more than // units away from (x,y). In a typical level, this test will // filter out all the linedefs but a handful. if(std::max(pos1.x, pos2.x) < lpos.x || std::min(pos1.x, pos2.x) > hpos.x || std::max(pos1.y, pos2.y) < lpos.y || std::min(pos1.y, pos2.y) > hpos.y) continue; double dist = getApproximateDistanceToLinedef(doc, *doc.linedefs[n], pos); if(dist > mapslack) continue; // use "<=" because if there are overlapping linedefs, we want // to return the highest-numbered one. if(dist <= best_dist) { best = n; best_dist = dist; } } if(best >= 0) return Objid(ObjType::linedefs, best); // none found return Objid(); } // // determine which sector is under the pointer // Objid hover::getNearestSector(const Document &doc, const v2double_t &pos) { /* hack, hack... I look for the first LineDef crossing an horizontal half-line drawn from the cursor */ // -AJA- updated this to look in four directions (N/S/E/W) and // grab the closest linedef. Now it is possible to access // self-referencing lines, even purely horizontal ones. Side side1, side2; int line1 = hover::getClosestLine_CastingHoriz(doc, pos, &side1); int line2 = getClosestLine_CastingVert(doc, pos, &side2); if(line2 < 0) { /* nothing needed */ } else if(line1 < 0 || getApproximateDistanceToLinedef(doc, *doc.linedefs[line2], pos) < getApproximateDistanceToLinedef(doc, *doc.linedefs[line1], pos)) { line1 = line2; side1 = side2; } // grab the sector reference from the appropriate side // (Note that side1 = +1 for right, -1 for left, 0 for "on"). if(line1 >= 0) { int sd_num = (side1 == Side::left) ? doc.linedefs[line1]->left : doc.linedefs[line1]->right; if(sd_num >= 0) return Objid(ObjType::sectors, doc.sidedefs[sd_num]->sector); } // none found return Objid(); } // // Gets an approximate distance from a point to a linedef // static double getApproximateDistanceToLinedef(const Document &doc, const LineDef &line, const v2double_t &pos) { v2double_t pos1 = doc.getStart(line).xy(); v2double_t pos2 = doc.getEnd(line).xy(); v2double_t dpos = pos2 - pos1; if(fabs(dpos.x) > fabs(dpos.y)) { // The linedef is rather horizontal // case 1: x is to the left of the linedef // hence return distance to the left-most vertex if(pos.x < (dpos.x > 0 ? pos1.x : pos2.x)) return hypot(pos.x - (dpos.x > 0 ? pos1.x : pos2.x), pos.y - (dpos.x > 0 ? pos1.y : pos2.y)); // case 2: x is to the right of the linedef // hence return distance to the right-most vertex if(pos.x > (dpos.x > 0 ? pos2.x : pos1.x)) return hypot(pos.x - (dpos.x > 0 ? pos2.x : pos1.x), pos.y - (dpos.x > 0 ? pos2.y : pos1.y)); // case 3: x is in-between (and not equal to) both vertices // hence use slope formula to get intersection point double y3 = pos1.y + (pos.x - pos1.x) * dpos.y / dpos.x; return fabs(y3 - pos.y); } else { // The linedef is rather vertical if(pos.y < (dpos.y > 0 ? pos1.y : pos2.y)) return hypot(pos.x - (dpos.y > 0 ? pos1.x : pos2.x), pos.y - (dpos.y > 0 ? pos1.y : pos2.y)); if(pos.y > (dpos.y > 0 ? pos2.y : pos1.y)) return hypot(pos.x - (dpos.y > 0 ? pos2.x : pos1.x), pos.y - (dpos.y > 0 ? pos2.y : pos1.y)); double x3 = pos1.x + (pos.y - pos1.y) * dpos.x / dpos.y; return fabs(x3 - pos.x); } } // // determine which linedef would be split if a new vertex were // added at the given coordinates. // static Objid getNearestSplitLine(const Document &doc, MapFormat format, const grid::State &grid, const v2double_t &pos, int ignore_vert) { // slack in map units double mapslack = 1.5 + ceil(8.0f / grid.getScale()); v2double_t lpos = pos - v2double_t(mapslack); v2double_t hpos = pos + v2double_t(mapslack); int best = -1; double best_dist = 9e9; double too_small = (format == MapFormat::udmf) ? 0.2 : 4.0; for(int n = 0; n < doc.numLinedefs(); n++) { const auto L = doc.linedefs[n]; if(L->start == ignore_vert || L->end == ignore_vert) continue; v2double_t pos1 = doc.getStart(*L).xy(); v2double_t pos2 = doc.getEnd(*L).xy(); if(std::max(pos1.x, pos2.x) < lpos.x || std::min(pos1.x, pos2.x) > hpos.x || std::max(pos1.y, pos2.y) < lpos.y || std::min(pos1.y, pos2.y) > hpos.y) continue; // skip linedef if given point matches a vertex if(pos == pos1 || pos == pos2) continue; // skip linedef if too small to split if(fabs(pos2.x - pos1.x) < too_small && fabs(pos2.y - pos1.y) < too_small) continue; double dist = getApproximateDistanceToLinedef(doc, *L, pos); if(dist > mapslack) continue; if(dist <= best_dist) { best = n; best_dist = dist; } } if(best >= 0) return Objid(ObjType::linedefs, best); // none found return Objid(); } // // Find crossing lines // void Hover::findCrossingLines(crossing_state_c &cross, const v2double_t &pos1, int possible_v1, const v2double_t &pos2, int possible_v2) const { // this could happen when two vertices are overlapping if((pos1 - pos2).chebyshev() < ALONG_EPSILON) return; // distances along WHOLE original line for this segment double along1 = AlongDist(pos1, cross.start, cross.end); double along2 = AlongDist(pos2, cross.start, cross.end); // bounding box of segment const v2double_t bbox1 = { std::min(pos1.x, pos2.x) - 0.25, std::min(pos1.y, pos2.y) - 0.25 }; const v2double_t bbox2 = { std::max(pos1.x, pos2.x) + 0.25, std::max(pos1.y, pos2.y) + 0.25 }; for (int ld = 0 ; ld < doc.numLinedefs() ; ld++) { const auto L = doc.linedefs[ld]; v2double_t lpos1 = doc.getStart(*L).xy(); v2double_t lpos2 = doc.getEnd(*L).xy(); // bbox test -- eliminate most lines from consideration if (std::max(lpos1.x,lpos2.x) < bbox1.x || std::min(lpos1.x,lpos2.x) > bbox2.x || std::max(lpos1.y,lpos2.y) < bbox1.y || std::min(lpos1.y,lpos2.y) > bbox2.y) { continue; } if (doc.isZeroLength(*L)) continue; if (cross.HasLine(ld)) continue; // skip linedef if an end-point is one of the vertices already // in the crossing state (including the very start or very end). if (cross.HasVertex(L->start) || cross.HasVertex(L->end)) continue; // only need to handle cases where this linedef distinctly crosses // the new line (i.e. start and end are clearly on opposite sides). double a = PerpDist(lpos1, pos1, pos2); double b = PerpDist(lpos2, pos1, pos2); if (! ((a < -CROSSING_EPSILON && b > CROSSING_EPSILON) || (a > CROSSING_EPSILON && b < -CROSSING_EPSILON))) { continue; } // compute intersection point double l_along = a / (a - b); v2double_t newpos = lpos1 + (lpos2 - lpos1) * l_along; double along = AlongDist(newpos, cross.start, cross.end); // ensure new vertex lies within this segment (and not too close to ends) if (along > along1 + ALONG_EPSILON && along < along2 - ALONG_EPSILON) { cross.add_line(ld, newpos, along); } } } //------------------------------------------------------------------------ void crossing_state_c::clear() { points.clear(); } void crossing_state_c::add_vert(int v, double dist) { cross_point_t pt; pt.vert = v; pt.ld = -1; pt.pos = inst.level.vertices[v]->xy(); pt.dist = dist; points.push_back(pt); } void crossing_state_c::add_line(int ld, const v2double_t &newpos, double dist) { cross_point_t pt; pt.vert = -1; pt.ld = ld; pt.pos = newpos; pt.dist = dist; points.push_back(pt); } bool crossing_state_c::HasVertex(int v) const { for (unsigned int k = 0 ; k < points.size() ; k++) if (points[k].vert == v) return true; return false; // NOPE! } bool crossing_state_c::HasLine(int ld) const { for (unsigned int k = 0 ; k < points.size() ; k++) if (points[k].ld == ld) return true; return false; // NO WAY! } void crossing_state_c::Sort() { std::sort(points.begin(), points.end(), point_CMP()); } void crossing_state_c::SplitAllLines(EditOperation &op) { for (unsigned int i = 0 ; i < points.size() ; i++) { if (points[i].ld >= 0) { points[i].vert = op.addNew(ObjType::vertices); auto V = inst.level.vertices[points[i].vert]; V->SetRawXY(inst.loaded.levelFormat, points[i].pos); inst.level.linemod.splitLinedefAtVertex(op, points[i].ld, points[i].vert); } } } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_hover.h000066400000000000000000000112021464327712600201240ustar00rootroot00000000000000//------------------------------------------------------------------------ // HIGHLIGHT HELPER //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_X_HOVER_H__ #define __EUREKA_X_HOVER_H__ #include "DocumentModule.h" #include "m_vector.h" #include "objid.h" #include "tl/optional.hpp" #include #include namespace grid { class State; } class bitvec_c; class crossing_state_c; class EditOperation; class fastopp_node_c; class LineDef; class Objid; enum class MapFormat; enum class Side; struct ConfigData; struct Editor_State_t; struct v2double_t; namespace hover { Objid findSplitLine(const Document &doc, MapFormat format, const Editor_State_t &edit, const grid::State &grid, v2double_t &out_pos, const v2double_t &ptr, int ignore_vert); Objid findSplitLineForDangler(const Document &doc, MapFormat format, const grid::State &grid, int v_num); int getClosestLine_CastingHoriz(const Document &doc, v2double_t pos, Side *side); Objid getNearbyObject(ObjType type, const Document &doc, const ConfigData &config, const grid::State &grid, const v2double_t &pos); Objid getNearestSector(const Document &doc, const v2double_t &pos); bool isPointOutsideOfMap(const Document &doc, const v2double_t &v); } struct opp_test_state_t; class fastopp_node_c { public: int lo, hi; // coordinate range int mid; std::unique_ptr lo_child; std::unique_ptr hi_child; std::vector lines; const Document &doc; public: fastopp_node_c(int _low, int _high, const Document &doc) : lo(_low), hi(_high), mid((_low + _high) / 2), doc(doc) { Subdivide(); } private: void Subdivide(); public: /* horizontal tree */ void AddLine_X(int ld, int x1, int x2); void AddLine_X(int ld); /* vertical tree */ void AddLine_Y(int ld, int y1, int y2); void AddLine_Y(int ld); void Process(opp_test_state_t& test, double coord) const; }; struct FastOppositeTree { explicit FastOppositeTree(Instance &inst); tl::optional m_fastopp_X_tree; tl::optional m_fastopp_Y_tree; }; // // The hover module // class Hover : public DocumentModule { public: Hover(Document &doc) : DocumentModule(doc) { } int getOppositeLinedef(int ld, Side ld_side, Side *result_side, const bitvec_c *ignore_lines, FastOppositeTree *tree) const; int getOppositeSector(int ld, Side ld_side, FastOppositeTree *tree) const; void findCrossingPoints(crossing_state_c &cross, v2double_t p1, int possible_v1, v2double_t p2, int possible_v2) const; private: void findCrossingLines(crossing_state_c &cross, const v2double_t &pos1, int possible_v1, const v2double_t &pos2, int possible_v2) const; }; // result: -1 for back, +1 for front, 0 for _exactly_on_ the line Side PointOnLineSide(double x, double y, double lx1, double ly1, double lx2, double ly2); struct cross_point_t { int vert; // >= 0 when we hit a vertex int ld; // >= 0 when we hit a linedef instead v2double_t pos; // coordinates of line split point double dist; }; class crossing_state_c { public: std::vector< cross_point_t > points; // the start/end coordinates of the whole tested line v2double_t start = {}; v2double_t end = {}; Instance &inst; public: explicit crossing_state_c(Instance &inst) : inst(inst) { } void clear(); void add_vert(int v, double dist); void add_line(int ld, const v2double_t &newpos, double dist); bool HasVertex(int v) const; bool HasLine(int ld) const; void Sort(); void SplitAllLines(EditOperation &op); private: struct point_CMP { inline bool operator() (const cross_point_t &A, const cross_point_t& B) const { return A.dist < B.dist; } }; }; #endif /* __EUREKA_X_HOVER_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_linedef.cc000066400000000000000000001101551464327712600205540ustar00rootroot00000000000000//------------------------------------------------------------------------ // LINEDEFS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include "e_cutpaste.h" #include "e_linedef.h" #include "e_main.h" #include "im_img.h" #include "LineDef.h" #include "m_config.h" #include "m_game.h" #include "e_objects.h" #include "Sector.h" #include "SideDef.h" #include "Vertex.h" #include "w_rawdef.h" #include "w_texture.h" // config items bool config::leave_offsets_alone = true; // // If linedef already exists // bool LinedefModule::linedefAlreadyExists(int v1, int v2) const { for (int n = 0 ; n < doc.numLinedefs() ; n++) { const auto L = doc.linedefs[n]; if (L->start == v1 && L->end == v2) return true; if (L->start == v2 && L->end == v1) return true; } return false; } //------------------------------------------------------------------------ // // Get pointer // inline const LineDef * LinedefModule::pointer(const Objid& obj) const { return doc.linedefs[obj.num].get(); } // // Get sidedef pointer // inline const SideDef * LinedefModule::sidedefPointer(const Objid& obj) const { Side where = (obj.parts & PART_LF_ALL) ? Side::left : Side::right; int sd = pointer(obj)->WhatSideDef(where); return (sd >= 0) ? doc.sidedefs[sd].get() : nullptr; } // disabled this partial texture comparison, as it can lead to // unexpected results. [ perhaps have an option for it? ] #if 1 inline static int PartialTexEqual(const SString &a, const SString &b) { return a.noCaseEqual(b); } #else static int PartialTexCmp(const char *A, const char *B) { // only compare the first 6 characters char A2[64]; char B2[64]; strcpy(A2, A); strcpy(B2, B); A2[6] = B2[6] = 0; return y_stricmp(A2, B2); } #endif bool LinedefModule::partIsVisible(const Objid& obj, Part part) const { const LineDef *L = pointer(obj); const SideDef *SD = sidedefPointer(obj); if (! L->TwoSided()) return (part == Part::lower); const Sector *front = &doc.getSector(*doc.getRight(*L)); const Sector *back = &doc.getSector(*doc.getLeft(*L)); if (obj.parts & PART_LF_ALL) std::swap(front, back); // ignore sky walls if (part == Part::upper && inst.is_sky(front->CeilTex()) && inst.is_sky(back->CeilTex())) return false; if (part == Part::lower) { if (is_null_tex(SD->LowerTex())) return false; return back->floorh > front->floorh; } else { if (is_null_tex(SD->UpperTex())) return false; return back->ceilh < front->ceilh; } } // // calculate vertical range that the given surface occupies. // when part is zero, we use obj.type instead. // void LinedefModule::partCalcExtent(const Objid& obj, Part part, int *z1, int *z2) const { const LineDef *L = pointer(obj); const SideDef *SD = sidedefPointer(obj); if (! L->TwoSided()) { if (SD) { *z1 = doc.getSector(*SD).floorh; *z2 = doc.getSector(*SD).ceilh; } else { *z1 = *z2 = 0; } return; } if (part == Part::unspecified) { if (obj.parts & (PART_RT_UPPER | PART_LF_UPPER)) part = Part::upper; else if (obj.parts & (PART_RT_RAIL | PART_LF_RAIL)) part = Part::rail; else part = Part::lower; } const Sector *front = &doc.getSector(*doc.getRight(*L)); const Sector *back = &doc.getSector(*doc.getLeft(*L)); if (obj.parts & PART_LF_ALL) std::swap(front, back); if (part == Part::rail) { *z1 = std::max(front->floorh, back->floorh); *z2 = std::min(front->ceilh, back->ceilh); } else if (part == Part::upper) { *z2 = front->ceilh; *z1 = std::min(*z2, back->ceilh); } else // part == Part::lower { *z1 = front->floorh; *z2 = std::max(*z1, back->floorh); } } // // Score texture match // int LinedefModule::scoreTextureMatch(const Objid& adj, const Objid& cur) const { // result is in the range 1..999 const LineDef *L = pointer(cur); const SideDef *LS = sidedefPointer(cur); const LineDef *N = pointer(adj); const SideDef *NS = sidedefPointer(adj); int adj_z1, adj_z2; int cur_z1, cur_z2; partCalcExtent(adj, Part::unspecified, &adj_z1, &adj_z2); partCalcExtent(cur, Part::unspecified, &cur_z1, &cur_z2); // adjacent surface is not visible? if (adj_z2 <= adj_z1) return 1; // no overlap? int overlap = std::min(adj_z2, cur_z2) - std::max(adj_z1, cur_z1); if (overlap <= 0) return 2; SString adj_tex = NS->MidTex(); if (N->TwoSided()) { if (adj.parts & (PART_RT_LOWER | PART_LF_LOWER)) adj_tex = NS->LowerTex(); else if (adj.parts & (PART_RT_UPPER | PART_LF_UPPER)) adj_tex = NS->UpperTex(); } if (is_null_tex(adj_tex)) return 3; SString cur_tex = LS->MidTex(); if (L->TwoSided()) { if (cur.parts & (PART_RT_LOWER | PART_LF_LOWER)) cur_tex = LS->LowerTex(); else if (cur.parts & (PART_RT_UPPER | PART_LF_UPPER)) cur_tex = LS->UpperTex(); } if (!PartialTexEqual(cur_tex, adj_tex)) return 4; // return a score based on length of line shared between the // two surfaces overlap = overlap / 8; if (overlap > 900) overlap = 900; return 10 + overlap; } // // Evaluate whether the given adjacent surface is a good (or even // possible) candidate to align with. // // Having a matching texture is the primary component of the score. // The secondary component is the angle between the lines (we prefer // this angle to be close to 180 degrees). // // TODO : have a preference for the same sector ?? // // Returns < 0 for surfaces that cannot be used. // int LinedefModule::scoreAdjoiner(const Objid& adj, const Objid& cur, int align_flags) const { bool do_right = (align_flags & LINALIGN_Right) ? true : false; const LineDef *L = pointer(cur); const SideDef *LS = sidedefPointer(cur); const LineDef *N = pointer(adj); const SideDef *NS = sidedefPointer(adj); // major fail by caller of Line_AlignOffsets() if (! LS) return -3; // no sidedef on adjoining line? if (! NS) return -2; // does the adjoiner sidedef actually mate up with the sidedef // we are aligning (and is on the wanted side) ? int v1 = (((cur.parts & PART_LF_ALL) ? 0:1) == (do_right ? 1:0)) ? L->end : L->start; int v2 = (((adj.parts & PART_LF_ALL) ? 0:1) == (do_right ? 1:0)) ? N->start : N->end; if (v1 != v2) return -1; /* Ok, we have a potential candidate */ int v0 = (v1 == L->end) ? L->start : L->end; int v3 = (v2 == N->end) ? N->start : N->end; double ang = angleBetweenLines(v0, v1, v3); int score = scoreTextureMatch(adj, cur); score = score * 1000 + 500 - (int)fabs(ang - 180.0); return score; } // // Determine the adjoining surface to align with. // // Returns a nil Objid for none. // void LinedefModule::determineAdjoiner(Objid& result, const Objid& cur, int align_flags) const { int best_score = 0; const LineDef *L = pointer(cur); for (int n = 0 ; n < doc.numLinedefs() ; n++) { const auto N = doc.linedefs[n]; if (N.get() == L) continue; if (doc.isZeroLength(*N)) continue; if (! (N->TouchesVertex(L->start) || N->TouchesVertex(L->end))) continue; static const int partsList[] = { PART_RT_LOWER, PART_RT_UPPER, PART_RT_RAIL }; for (int side = 0 ; side < 2 ; side++) for (int curParts : partsList) { Objid adj; adj.type = ObjType::linedefs; adj.num = n; adj.parts = curParts; if (side == 1) adj.parts = adj.parts << PART_LEFT_SHIFT; int score = scoreAdjoiner(adj, cur, align_flags); if (score > best_score) { result = adj; best_score = score; } } } } // // Calculate reference H // int LinedefModule::calcReferenceH(const Objid& obj) const { const LineDef *L = pointer(obj); const SideDef *SD = sidedefPointer(obj); if (! L->TwoSided()) { if (! SD) return 256; const Sector &front = doc.getSector(*SD); if (L->flags & MLF_LowerUnpegged) return front.floorh + inst.wad.images.W_GetTextureHeight(inst.conf, SD->MidTex()); return front.ceilh; } const Sector *front = &doc.getSector(*doc.getRight(*L)); const Sector *back = &doc.getSector(*doc.getLeft(*L)); if (obj.parts & PART_LF_ALL) std::swap(front, back); SYS_ASSERT(front); SYS_ASSERT(back); if (obj.parts & (PART_RT_UPPER | PART_LF_UPPER)) { if (! (L->flags & MLF_UpperUnpegged)) return back->ceilh + inst.wad.images.W_GetTextureHeight(inst.conf, SD->UpperTex()); return front->ceilh; } else { // TODO : verify if this correct for RAIL if (! (L->flags & MLF_LowerUnpegged)) return back->floorh; return front->ceilh; } } void LinedefModule::doAlignX(EditOperation &op, const Objid& cur, const Objid& adj, int align_flags) const { const LineDef *cur_L = pointer(cur); const LineDef *adj_L = pointer(adj); const SideDef *adj_SD = sidedefPointer(adj); bool on_left = adj_L->TouchesVertex((cur.parts & PART_LF_ALL) ? cur_L->end : cur_L->start); int new_offset = adj_SD->x_offset; if (on_left) { new_offset += iround(doc.calcLength(*adj_L)); if (new_offset > 0) new_offset &= 1023; } else { new_offset -= iround(doc.calcLength(*cur_L)); if (new_offset < 0) new_offset = - (-new_offset & 1023); } Side where = (cur.parts & PART_LF_ALL) ? Side::left : Side::right; int sd = cur_L->WhatSideDef(where); op.changeSidedef(sd, SideDef::F_X_OFFSET, new_offset); } void LinedefModule::doAlignY(EditOperation &op, const Objid& cur, const Objid& adj, int align_flags) const { const LineDef *L = pointer(cur); const SideDef *SD = sidedefPointer(cur); // const LineDef *adj_L = LD_ptr(adj); const SideDef *adj_SD = sidedefPointer(adj); bool lower_vis = partIsVisible(cur, Part::lower); bool upper_vis = partIsVisible(cur, Part::upper); bool lower_unpeg = (L->flags & MLF_LowerUnpegged) ? true : false; bool upper_unpeg = (L->flags & MLF_UpperUnpegged) ? true : false; // check for windows (set the unpeg flags) int new_flags = L->flags; if ((align_flags & LINALIGN_Unpeg) && L->TwoSided() && lower_vis && upper_vis && (! lower_unpeg || ! upper_unpeg) && PartialTexEqual(SD->LowerTex(), SD->UpperTex()) && is_null_tex(SD->MidTex()) /* no rail */) { new_flags |= MLF_LowerUnpegged; new_flags |= MLF_UpperUnpegged; } // requirement: adj_tex_h + adj_y_off = cur_tex_h + cur_y_off int cur_texh = calcReferenceH(cur); int adj_texh = calcReferenceH(adj); int new_offset = adj_texh + adj_SD->y_offset - cur_texh; // normalize value [TODO: handle BOOM non-power-of-two heights] if (new_offset < 0) new_offset = - (-new_offset & 255); else new_offset &= 255; Side where = (cur.parts & PART_LF_ALL) ? Side::left : Side::right; int sd = L->WhatSideDef(where); op.changeSidedef(sd, SideDef::F_Y_OFFSET, new_offset); if (new_flags != L->flags) { op.changeLinedef(cur.num, LineDef::F_FLAGS, new_flags); } } // // Clear offsets // void LinedefModule::doClearOfs(EditOperation &op, const Objid& cur, int align_flags) const { Side where = (cur.parts & PART_LF_ALL) ? Side::left : Side::right; int sd = pointer(cur)->WhatSideDef(where); if (sd < 0) // should not happen return; if (align_flags & LINALIGN_X) { // when the /right flag is used, make the texture end at the right side // (whereas zero makes it begin at the left side) if (align_flags & LINALIGN_Right) op.changeSidedef(sd, SideDef::F_X_OFFSET, 0 - iround(doc.calcLength(*pointer(cur)))); else op.changeSidedef(sd, SideDef::F_X_OFFSET, 0); } if (align_flags & LINALIGN_Y) op.changeSidedef(sd, SideDef::F_Y_OFFSET, 0); } // // Align the X and/or Y offets on the given surface. // // The given flags control which stuff to change, and where // to look for the surface to align with. // bool LinedefModule::alignOffsets(EditOperation &op, const Objid& obj, int align_flags) const { if (align_flags & LINALIGN_Clear) { doClearOfs(op, obj, align_flags); return true; } Objid adj; determineAdjoiner(adj, obj, align_flags); if (! adj.valid()) return false; if (align_flags & LINALIGN_X) doAlignX(op, obj, adj, align_flags); if (align_flags & LINALIGN_Y) doAlignY(op, obj, adj, align_flags); return true; } // returns true if the surface at 'k' MUST be aligned before the // surface at 'j'. bool LinedefModule::alignCheckAdjacent(const std::vector & group, int j, int k, bool do_right) const { const Objid& ob_j = group[j]; const Objid& ob_k = group[k]; int vj = 0; if (((ob_j.parts & PART_LF_ALL) ? 0 : 1) == (do_right ? 1 : 0)) vj = doc.linedefs[ob_j.num]->end; else vj = doc.linedefs[ob_j.num]->start; int vk = 0; if (((ob_k.parts & PART_LF_ALL) ? 0 : 1) == (do_right ? 1 : 0)) vk = doc.linedefs[ob_k.num]->start; else vk = doc.linedefs[ob_k.num]->end; return (vj == vk); } // // find an unvisited surface that has no possible dependency on // any other unvisited surface. In the case of loops, we pick // an arbitrary surface. // int LinedefModule::alignPickNextSurface(const std::vector & group, const std::vector& seen, bool do_right) const { int fallback = -1; for (int j = 0 ; j < (int)group.size() ; j++) { if (seen[j]) continue; if (! group[j].valid()) continue; if (fallback < 0) fallback = j; bool has_better = false; for (int k = 0 ; k < (int)group.size() ; k++) { if (k == j) continue; if (seen[k]) continue; if (! group[k].valid()) continue; if (alignCheckAdjacent(group, j, k, do_right)) { has_better = true; break; } } if (! has_better) return j; } // this will be -1 when there is no more surfaces left return fallback; } // // Align group // void LinedefModule::alignGroup(EditOperation &op, const std::vector & group, int align_flags) const { // we will do each surface in the selection one-by-one, // and the order is significant when doing X offsets, so // mark them off via this array. std::vector seen; seen.resize(group.size()); unsigned int k; for (k = 0 ; k < group.size() ; k++) seen[k] = 0; bool do_right = (align_flags & LINALIGN_Right) ? true : false; for (;;) { // get next unvisited surface int n = alignPickNextSurface(group, seen, do_right); if (n < 0) break; // mark it seen seen[n] = 1; alignOffsets(op, group[n], align_flags); } } void Instance::CMD_LIN_Align() { // parse the flags bool do_X = Exec_HasFlag("/x"); bool do_Y = Exec_HasFlag("/y"); if (! (do_X || do_Y)) { Beep("LIN_Align: need x or y flag"); return; } bool do_clear = Exec_HasFlag("/clear"); bool do_right = Exec_HasFlag("/right"); bool do_unpeg = true; // TODO a flag to disable int align_flags = 0; if (do_X) align_flags = align_flags | LINALIGN_X; if (do_Y) align_flags = align_flags | LINALIGN_Y; if (do_right) align_flags |= LINALIGN_Right; if (do_unpeg) align_flags |= LINALIGN_Unpeg; if (do_clear) align_flags |= LINALIGN_Clear; SelectHighlight unselect = edit.SelectionOrHighlight(); if (edit.mode != ObjType::linedefs || unselect == SelectHighlight::empty) { Beep("no lines to align"); return; } /* convert selection to group of surfaces */ std::vector< Objid > group; for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { int parts = edit.Selected->get_ext(*it); parts &= ~1; const auto L = level.linedefs[*it]; // safety check if (L->left < 0) parts &= ~PART_LF_ALL; if (L->right < 0) parts &= ~PART_RT_ALL; Objid obj(ObjType::linedefs, *it); // handle lines with individual parts selected if (parts != 0) { for (int bit = 0x02 ; bit <= 0x80 ; bit <<= 1) { if (parts & bit) { obj.parts = parts & bit; group.push_back(obj); } } continue; } // handle "simply selected" lines, determine parts to use for (int pass = 0 ; pass < 2 ; pass++) { Side where = pass ? Side::left : Side::right; if (L->WhatSideDef(where) < 0) continue; // decide whether to use upper or lower // WISH : this could be smarter.... bool lower_vis = level.linemod.partIsVisible(obj, LinedefModule::Part::lower); bool upper_vis = level.linemod.partIsVisible(obj, LinedefModule::Part::upper); if (! (lower_vis || upper_vis)) continue; obj.parts = lower_vis ? PART_RT_LOWER : PART_RT_UPPER; if (where == Side::left) obj.parts = obj.parts << 4; group.push_back(obj); } } if (group.empty()) { Beep("no visible surfaces"); if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); return; } { EditOperation op(level.basis); level.linemod.alignGroup(op, group, align_flags); if (do_clear) op.setMessage("cleared offsets"); else op.setMessage("aligned offsets"); } if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); } //------------------------------------------------------------------------ // // Flip vertices of linedef // void LinedefModule::flipLine_verts(EditOperation &op, int ld) const { int old_start = doc.linedefs[ld]->start; int old_end = doc.linedefs[ld]->end; op.changeLinedef(ld, LineDef::F_START, old_end); op.changeLinedef(ld, LineDef::F_END, old_start); } // // Flip sides of linedef // void LinedefModule::flipLine_sides(EditOperation &op, int ld) const { int old_right = doc.linedefs[ld]->right; int old_left = doc.linedefs[ld]->left; op.changeLinedef(ld, LineDef::F_RIGHT, old_left); op.changeLinedef(ld, LineDef::F_LEFT, old_right); } // // Flip linedef // void LinedefModule::flipLinedef(EditOperation &op, int ld) const { flipLine_verts(op, ld); flipLine_sides(op, ld); } void LinedefModule::flipLinedef_safe(EditOperation &op, int ld) const { // this avoids creating a linedef with only a left side (no right) flipLine_verts(op, ld); if (!doc.linedefs[ld]->OneSided()) flipLine_sides(op, ld); } // // Flip linedef group // void LinedefModule::flipLinedefGroup(EditOperation &op, const selection_c *flip) const { for (sel_iter_c it(flip) ; !it.done() ; it.next()) { flipLinedef(op, *it); } } // // flip the orientation of some LineDefs // void Instance::CMD_LIN_Flip() { SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { Beep("No lines to flip"); return; } bool force_it = Exec_HasFlag("/force"); { EditOperation op(level.basis); op.setMessageForSelection("flipped", *edit.Selected); for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { if (force_it) level.linemod.flipLinedef(op, *it); else level.linemod.flipLinedef_safe(op, *it); } } if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); } void Instance::CMD_LIN_SwapSides() { SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { Beep("No lines to swap sides"); return; } { EditOperation op(level.basis); op.setMessageForSelection("swapped sides on", *edit.Selected); for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { level.linemod.flipLine_sides(op, *it); } } if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); } // // Return the tile width for computing auto-offset modulus // static int getTileWidth(const SideDef &side, const ImageSet &images, const ConfigData &config) { const Img_c *upper = images.getTexture(config, side.UpperTex()); const Img_c *mid = images.getTexture(config, side.MidTex()); const Img_c *lower = images.getTexture(config, side.LowerTex()); int upperWidth = upper ? upper->width() : 1; int midWidth = mid ? mid->width() : 1; int lowerWidth = lower ? lower->width() : 1; // Make sure it's at least 1 return std::max({1, upperWidth, midWidth, lowerWidth}); } // // Split linedef at vertex // int LinedefModule::splitLinedefAtVertex(EditOperation &op, int ld, int new_v) const { const auto L = doc.linedefs[ld]; // create new linedef int new_l = op.addNew(ObjType::linedefs); auto L2 = doc.linedefs[new_l]; // it is OK to directly set fields of newly created objects *L2 = *L; L2->start = new_v; L2->end = L->end; int orig_length = iround(doc.calcLength(*L)); // update vertex on original line op.changeLinedef(ld, LineDef::F_END, new_v); // compute lengths (to update sidedef X offsets) int new_length = iround(doc.calcLength(*L)); // update sidedefs if (doc.getRight(*L)) { L2->right = op.addNew(ObjType::sidedefs); *doc.getRight(*L2) = *doc.getRight(*L); if (! config::leave_offsets_alone) { doc.getRight(*L2)->x_offset += new_length; int width = getTileWidth(*doc.getRight(*L2), inst.wad.images, inst.conf); doc.getRight(*L2)->x_offset %= width; } } if (doc.getLeft(*L)) { L2->left = op.addNew(ObjType::sidedefs); *doc.getLeft(*L2) = *doc.getLeft(*L); if (! config::leave_offsets_alone) { int new_x_ofs = doc.getLeft(*L)->x_offset + orig_length - new_length; int width = getTileWidth(*doc.getLeft(*L), inst.wad.images, inst.conf); new_x_ofs %= width; op.changeSidedef(L->left, SideDef::F_X_OFFSET, new_x_ofs); } } return new_l; } bool LinedefModule::doSplitLineDef(EditOperation &op, int ld) const { const auto L = doc.linedefs[ld]; // prevent creating tiny lines (especially zero-length) if (fabs(doc.getStart(*L).x() - doc.getEnd(*L).x()) < 4 && fabs(doc.getStart(*L).y() - doc.getEnd(*L).y()) < 4) return false; v2double_t new_p = (doc.getStart(*L).xy() + doc.getEnd(*L).xy()) / 2; int new_v = op.addNew(ObjType::vertices); auto V = doc.vertices[new_v]; V->SetRawXY(inst.loaded.levelFormat, new_p); splitLinedefAtVertex(op, ld, new_v); return true; } // // split one or more LineDefs in two, adding new Vertices in the middle // void Instance::CMD_LIN_SplitHalf() { SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { Beep("No lines to split"); return; } int new_first = level.numLinedefs(); int new_count = 0; { EditOperation op(level.basis); for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { if (level.linemod.doSplitLineDef(op, *it)) new_count++; } op.setMessage("halved %d lines", new_count); } // Hmmmmm -- should abort early if some lines are too short?? if (new_count < edit.Selected->count_obj()) Beep("Some lines were too short!"); if (unselect == SelectHighlight::unselect) { Selection_Clear(true /* nosave */); } else if (new_count > 0) { edit.Selected->frob_range(new_first, new_first + new_count - 1, BitOp::add); } } // // Add second sidedef // void LinedefModule::addSecondSidedef(EditOperation &op, int ld, int new_sd, int other_sd) const { const auto L = doc.linedefs[ld]; auto SD = doc.sidedefs[new_sd]; int new_flags = L->flags; new_flags |= MLF_TwoSided; new_flags &= ~MLF_Blocking; op.changeLinedef(ld, LineDef::F_FLAGS, new_flags); // TODO: make this a global pseudo-constant StringID null_tex = BA_InternaliseString("-"); const auto other = doc.sidedefs[other_sd]; if (! is_null_tex(other->MidTex())) { SD->lower_tex = other->mid_tex; SD->upper_tex = other->mid_tex; op.changeSidedef(other_sd, SideDef::F_LOWER_TEX, other->mid_tex); op.changeSidedef(other_sd, SideDef::F_UPPER_TEX, other->mid_tex); op.changeSidedef(other_sd, SideDef::F_MID_TEX, null_tex); } else { SD->lower_tex = other->lower_tex; SD->upper_tex = other->upper_tex; } } void LinedefModule::mergedSecondSidedef(EditOperation &op, int ld) const { // similar to above, but with existing sidedefs const auto L = doc.linedefs[ld]; SYS_ASSERT(L->TwoSided()); int new_flags = L->flags; new_flags |= MLF_TwoSided; new_flags &= ~MLF_Blocking; op.changeLinedef(ld, LineDef::F_FLAGS, new_flags); // TODO: make this a global pseudo-constant StringID null_tex = BA_InternaliseString("-"); // determine textures for each side StringID left_tex; StringID right_tex; if (! is_null_tex(doc.getLeft(*L)->MidTex())) left_tex = doc.getLeft(*L)->mid_tex; if (! is_null_tex(doc.getRight(*L)->MidTex())) right_tex = doc.getRight(*L)->mid_tex; if (! left_tex) left_tex = right_tex; if (! right_tex) right_tex = left_tex; // use default texture if both sides are empty if (! left_tex) { left_tex = BA_InternaliseString(inst.conf.default_wall_tex); right_tex = left_tex; } op.changeSidedef(L->left, SideDef::F_MID_TEX, null_tex); op.changeSidedef(L->right, SideDef::F_MID_TEX, null_tex); op.changeSidedef(L->left, SideDef::F_LOWER_TEX, left_tex); op.changeSidedef(L->left, SideDef::F_UPPER_TEX, left_tex); op.changeSidedef(L->right, SideDef::F_LOWER_TEX, right_tex); op.changeSidedef(L->right, SideDef::F_UPPER_TEX, right_tex); } // // Remove sidedef // void LinedefModule::removeSidedef(EditOperation &op, int ld, Side ld_side) const { const auto L = doc.linedefs[ld]; int gone_sd = (ld_side == Side::right) ? L->right : L->left; int other_sd = (ld_side == Side::right) ? L->left : L->right; if (ld_side == Side::right) op.changeLinedef(ld, LineDef::F_RIGHT, -1); else op.changeLinedef(ld, LineDef::F_LEFT, -1); if (other_sd < 0) return; // The line is changing from TWO SIDED --> ONE SIDED. // Hence we need to: // (1) clear the Two-Sided flag // (2) set the Impassible flag // (3) flip the linedef if right side was removed // (4) set the middle texture int new_flags = L->flags; new_flags &= ~MLF_TwoSided; new_flags |= MLF_Blocking; op.changeLinedef(ld, LineDef::F_FLAGS, new_flags); // FIXME: if sidedef is shared, either don't modify it _OR_ duplicate it const SideDef *SD = doc.sidedefs[other_sd].get(); StringID new_tex = BA_InternaliseString(inst.conf.default_wall_tex); // grab new texture from lower or upper if possible if (! is_null_tex(SD->LowerTex())) new_tex = SD->lower_tex; else if (! is_null_tex(SD->UpperTex())) new_tex = SD->upper_tex; else if (gone_sd >= 0) { SD = doc.sidedefs[gone_sd].get(); if (! is_null_tex(SD->LowerTex())) new_tex = SD->lower_tex; else if (! is_null_tex(SD->UpperTex())) new_tex = SD->upper_tex; } op.changeSidedef(other_sd, SideDef::F_MID_TEX, new_tex); } void Instance::commandLinedefMergeTwo() { if (edit.Selected->count_obj() == 1 && edit.highlight.valid()) { edit.Selection_AddHighlighted(); } if (edit.Selected->count_obj() != 2) { Beep("Need 2 linedefs to merge (got %d)", edit.Selected->count_obj()); return; } // we will merge the second into the first int ld2 = edit.Selected->find_first(); int ld1 = edit.Selected->find_second(); const auto L1 = level.linedefs[ld1]; const auto L2 = level.linedefs[ld2]; if (! (L1->OneSided() && L2->OneSided())) { Beep("Linedefs to merge must be single sided."); return; } Selection_Clear(true); EditOperation op(level.basis); // ld2 steals the sidedef from ld1 op.changeLinedef(ld2, LineDef::F_LEFT, L1->right); op.changeLinedef(ld1, LineDef::F_RIGHT, -1); level.linemod.mergedSecondSidedef(op, ld2); // fix existing lines connected to ld1 : reconnect to ld2 for (int n = 0 ; n < level.numLinedefs(); n++) { if (n == ld1 || n == ld2) continue; const auto L = level.linedefs[n]; if (L->start == L1->start) op.changeLinedef(n, LineDef::F_START, L2->end); else if (L->start == L1->end) op.changeLinedef(n, LineDef::F_START, L2->start); if (L->end == L1->start) op.changeLinedef(n, LineDef::F_END, L2->end); else if (L->end == L1->end) op.changeLinedef(n, LineDef::F_END, L2->start); } // delete ld1 and any unused vertices selection_c del_line(ObjType::linedefs); del_line.set(ld1); DeleteObjects_WithUnused(op, level, del_line, false, false, false); op.setMessage("merged two linedefs"); } // // Move coordinate into linedef // void linemod::moveCoordOntoLinedef(const Document &doc, int ld, v2double_t &v) { const auto L = doc.linedefs[ld]; v2double_t v1 = doc.getStart(*L).xy(); v2double_t v2 = doc.getEnd(*L).xy(); v2double_t dv = v2 - v1; double len_squared = pow(dv.hypot(), 2); SYS_ASSERT(len_squared > 0); // compute along distance double along = (v - v1) * dv; // result = start + along * line unit vector v = v1 + dv * along / len_squared; } // // Linedef start will be moved // bool LinedefModule::linedefStartWillBeMoved(int ld, selection_c &list) const { for (sel_iter_c it(list) ; !it.done() ; it.next()) { const auto L = doc.linedefs[*it]; if (*it != ld && L->end == doc.linedefs[ld]->start) return true; } return false; } // // Linedef end will be moved // bool LinedefModule::linedefEndWillBeMoved(int ld, selection_c &list) const { for (sel_iter_c it(list) ; !it.done() ; it.next()) { const auto L = doc.linedefs[*it]; if (*it != ld && L->start == doc.linedefs[ld]->end) return true; } return false; } // // Pick linedef to extend // int LinedefModule::pickLinedefToExtend(selection_c &list, bool moving_start) const { // We want a line whose new length is not going to be wrecked // by a change to a later linedef. However we must handle loops! for (sel_iter_c it(list) ; !it.done() ; it.next()) { if (moving_start) { if (! linedefEndWillBeMoved(*it, list)) return *it; } else { if (! linedefStartWillBeMoved(*it, list)) return *it; } } return list.find_first(); } // // Set linedef length // void LinedefModule::linedefSetLength(EditOperation &op, int ld, int new_len, double angle) const { // the 'new_len' parameter can be negative, which means move // the start vertex instead of the end vertex. const auto L = doc.linedefs[ld]; double dx = abs(new_len) * cos(angle); double dy = abs(new_len) * sin(angle); int idx = iround(dx); int idy = iround(dy); if (idx == 0 && idy == 0) { if (dx < 0) idx = (int)floor(dx); else idx = (int)ceil(dx); if (dy < 0) idy = (int)floor(dy); else idy = (int)ceil(dy); } if (idx == 0 && idy == 0) idx = 1; if (new_len < 0) { op.changeVertex(L->start, Vertex::F_X, doc.getEnd(*L).raw_x - FFixedPoint(idx)); op.changeVertex(L->start, Vertex::F_Y, doc.getEnd(*L).raw_y - FFixedPoint(idy)); } else { op.changeVertex(L->end, Vertex::F_X, doc.getStart(*L).raw_x + FFixedPoint(idx)); op.changeVertex(L->end, Vertex::F_Y, doc.getStart(*L).raw_y + FFixedPoint(idy)); } } // // Set linedef length // void LinedefModule::setLinedefsLength(int new_len) const { // this works on the current selection (caller must set it up) // use a copy of the selection selection_c list(ObjType::linedefs); ConvertSelection(doc, *inst.edit.Selected, list); if (list.empty()) return; // remember angles std::vector angles(doc.numLinedefs()); for (int n = 0 ; n < doc.numLinedefs() ; n++) { const auto L = doc.linedefs[n]; angles[n] = atan2(doc.getEnd(*L).y() - doc.getStart(*L).y(), doc.getEnd(*L).x() - doc.getStart(*L).x()); } EditOperation op(doc.basis); op.setMessageForSelection("set length of", list); while (! list.empty()) { int ld = pickLinedefToExtend(list, new_len < 0 /* moving_start */); list.clear(ld); linedefSetLength(op, ld, new_len, angles[ld]); } } // // Fix for a lost side // void LinedefModule::fixForLostSide(EditOperation &op, int ld) const { const auto L = doc.linedefs[ld]; SYS_ASSERT(doc.getRight(*L)); StringID tex; if (! is_null_tex(doc.getRight(*L)->LowerTex())) tex = doc.getRight(*L)->lower_tex; else if (! is_null_tex(doc.getRight(*L)->UpperTex())) tex = doc.getRight(*L)->upper_tex; else tex = BA_InternaliseString(inst.conf.default_wall_tex); op.changeSidedef(L->right, SideDef::F_MID_TEX, tex); } // // Compute the angle between lines AB and BC, going anticlockwise. // result is in degrees in the range [0, 360). // // A, B and C are VERTEX indices. // // -AJA- 2001-05-09 // double LinedefModule::angleBetweenLines(int A, int B, int C) const { double a_dx = doc.vertices[B]->x() - doc.vertices[A]->x(); double a_dy = doc.vertices[B]->y() - doc.vertices[A]->y(); double c_dx = doc.vertices[B]->x() - doc.vertices[C]->x(); double c_dy = doc.vertices[B]->y() - doc.vertices[C]->y(); double AB_angle = (a_dx == 0) ? (a_dy >= 0 ? 90 : -90) : atan2(a_dy, a_dx) * 180 / M_PI; double CB_angle = (c_dx == 0) ? (c_dy >= 0 ? 90 : -90) : atan2(c_dy, c_dx) * 180 / M_PI; double result = CB_angle - AB_angle; while (result >= 360.0) result -= 360.0; while (result < 0) result += 360.0; #if 0 // DEBUGGING gLog.debugPrintf("ANGLE %1.6f (%d,%d) -> (%d,%d) -> (%d,%d)\n", result, Vertices[A].x, Vertices[A].y, Vertices[B].x, Vertices[B].y, Vertices[C].x, Vertices[C].y); #endif return result; } SString LD_RatioName(FFixedPoint idx, FFixedPoint idy, bool number_only) { idx = idx.abs(); idy = idy.abs(); if (!idx && !idy) { if (number_only) return "0:0"; else return "zero-len"; } else if (!idx) { if (number_only) return "1:0"; else return "vertical"; } else if (!idy) { if (number_only) return "0:1"; else return "horizontal"; } // compute the greatest common divisor FFixedPoint a = idx; FFixedPoint b = idy; int gcd = 1; for (;;) { if (a > b) a -= b; else if (b > a) b -= a; else { gcd = a.raw(); break; } } idx /= gcd; idy /= gcd; // if ratio is really complex, it isn't worth showing if (idx.raw() > 999 || idy.raw() > 999) return SString("---"); char buffer[256]; snprintf(buffer, sizeof(buffer), "%s%d:%d", number_only ? "" : "ratio ", idx.raw(), idy.raw()); return SString(buffer); } bool Instance::LD_RailHeights(int& z1, int& z2, const LineDef *L, const SideDef *sd, const Sector *front, const Sector *back) const { SString rail_tex = sd->MidTex(); if (is_null_tex(rail_tex)) return false; z1 = std::max(front->floorh, back->floorh); z2 = std::min(front->ceilh, back->ceilh); if (z2 <= z1) return false; int img_h = wad.images.W_GetTextureHeight(conf, rail_tex); if (L->flags & MLF_LowerUnpegged) { z1 = z1 + sd->y_offset; z2 = z1 + img_h; } else { z2 = z2 + sd->y_offset; z1 = z2 - img_h; } return true; } // SideDef packing logic -- raw from glBSP #if 0 static int SidedefCompare(const void *p1, const void *p2) { int comp; int side1 = ((const uint16_t *) p1)[0]; int side2 = ((const uint16_t *) p2)[0]; sidedef_t *A = lev_sidedefs[side1]; sidedef_t *B = lev_sidedefs[side2]; if (side1 == side2) return 0; // don't merge sidedefs on special lines if (A->on_special || B->on_special) return side1 - side2; if (A->sector != B->sector) { if (A->sector == NULL) return -1; if (B->sector == NULL) return +1; return (A->sector->index - B->sector->index); } if ((int)A->x_offset != (int)B->x_offset) return A->x_offset - (int)B->x_offset; if ((int)A->y_offset != B->y_offset) return (int)A->y_offset - (int)B->y_offset; // compare textures comp = memcmp(A->upper_tex, B->upper_tex, sizeof(A->upper_tex)); if (comp) return comp; comp = memcmp(A->lower_tex, B->lower_tex, sizeof(A->lower_tex)); if (comp) return comp; comp = memcmp(A->mid_tex, B->mid_tex, sizeof(A->mid_tex)); if (comp) return comp; // sidedefs must be the same return 0; } void DetectDuplicateSidedefs(void) { int i; uint16_t *array = (uint16_t *)UtilCalloc(num_sidedefs * sizeof(uint16_t)); GB_DisplayTicker(); // sort array of indices for (i=0; i < num_sidedefs; i++) array[i] = i; qsort(array, num_sidedefs, sizeof(uint16_t), SidedefCompare); // now mark them off for (i=0; i < num_sidedefs - 1; i++) { // duplicate ? if (SidedefCompare(array + i, array + i+1) == 0) { sidedef_t *A = lev_sidedefs[array[i]]; sidedef_t *B = lev_sidedefs[array[i+1]]; // found a duplicate ! B->equiv = A->equiv ? A->equiv : A; } } UtilFree(array); // update all linedefs for (i=0, new_num=0; i < num_linedefs; i++) { linedef_t *L = lev_linedefs[i]; // handle duplicated sidedefs while (L->right && L->right->equiv) { L->right->ref_count--; L->right = L->right->equiv; L->right->ref_count++; } while (L->left && L->left->equiv) { L->left->ref_count--; L->left = L->left->equiv; L->left->ref_count++; } } } #endif //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_linedef.h000066400000000000000000000106771464327712600204260ustar00rootroot00000000000000//------------------------------------------------------------------------ // LINEDEF OPERATIONS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_E_LINEDEF_H__ #define __EUREKA_E_LINEDEF_H__ #include "Side.h" #include "DocumentModule.h" #include "sys_type.h" #include class EditOperation; class FFixedPoint; class LineDef; class Objid; class selection_c; class SString; struct v2double_t; struct SideDef; namespace linemod { void moveCoordOntoLinedef(const Document &doc, int ld, v2double_t &v); } class LinedefModule : public DocumentModule { friend class Instance; public: enum class Part { unspecified, upper, rail, lower }; LinedefModule(Document &doc) : DocumentModule(doc) { } void flipLinedef(EditOperation &op, int ld) const; void flipLinedefGroup(EditOperation &op, const selection_c *flip) const; void setLinedefsLength(int new_len) const; bool linedefAlreadyExists(int v1, int v2) const; int splitLinedefAtVertex(EditOperation &op, int ld, int v_idx) const; void addSecondSidedef(EditOperation &op, int ld, int new_sd, int other_sd) const; void removeSidedef(EditOperation &op, int ld, Side ld_side) const; void fixForLostSide(EditOperation &op, int ld) const; double angleBetweenLines(int A, int B, int C) const; private: void flipLine_verts(EditOperation &op, int ld) const; void flipLine_sides(EditOperation &op, int ld) const; void flipLinedef_safe(EditOperation &op, int ld) const; int pickLinedefToExtend(selection_c& list, bool moving_start) const; bool linedefEndWillBeMoved(int ld, selection_c &list) const; bool linedefStartWillBeMoved(int ld, selection_c &list) const; void linedefSetLength(EditOperation &op, int ld, int new_len, double angle) const; bool alignOffsets(EditOperation &op, const Objid& obj, int align_flags) const; void alignGroup(EditOperation &op, const std::vector & group, int align_flags) const; void doClearOfs(EditOperation &op, const Objid& cur, int align_flags) const; void doAlignX(EditOperation &op, const Objid &cur, const Objid &adj, int align_flags) const; void doAlignY(EditOperation &op, const Objid& cur, const Objid& adj, int align_flags) const; inline const LineDef *pointer(const Objid &obj) const; inline const SideDef *sidedefPointer(const Objid &obj) const; void determineAdjoiner(Objid& result, const Objid& cur, int align_flags) const; int scoreAdjoiner(const Objid &adj, const Objid &cur, int align_flags) const; int scoreTextureMatch(const Objid &adj, const Objid &cur) const; void partCalcExtent(const Objid &obj, Part part, int *z1, int *z2) const; bool partIsVisible(const Objid& obj, Part part) const; int calcReferenceH(const Objid& obj) const; bool alignCheckAdjacent(const std::vector & group, int j, int k, bool do_right) const; int alignPickNextSurface(const std::vector & group, const std::vector& seen, bool do_right) const; bool doSplitLineDef(EditOperation &op, int ld) const; void mergedSecondSidedef(EditOperation &op, int ld) const; }; SString LD_RatioName(FFixedPoint idx, FFixedPoint idy, bool number_only); enum linedef_align_flag_e { LINALIGN_X = (1 << 0), // align the X offset LINALIGN_Y = (1 << 1), // align the Y offset LINALIGN_Clear = (1 << 2), // clear the offset(s), instead of aligning LINALIGN_Unpeg = (1 << 3), // change the unpegging flags LINALIGN_Right = (1 << 4) // align with sidedef on RIGHT of this one [ otherwise do LEFT ] }; #endif /* __EUREKA_E_LINEDEF_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_main.cc000066400000000000000000000671721464327712600201040ustar00rootroot00000000000000//------------------------------------------------------------------------ // LEVEL MISC STUFF //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include "LineDef.h" #include "m_bitvec.h" #include "m_config.h" #include "m_game.h" #include "e_hover.h" #include "e_linedef.h" #include "e_main.h" #include "e_path.h" #include "e_things.h" #include "e_vertex.h" #include "r_render.h" #include "r_subdiv.h" #include "Sector.h" #include "SideDef.h" #include "Thing.h" #include "Vertex.h" #include "w_rawdef.h" #include "WadData.h" #include "ui_window.h" #include // config items int config::default_edit_mode = 3; // Vertices bool config::same_mode_clears_selection = false; int config::sector_render_default = (int)SREND_Floor; int config::thing_render_default = 1; // // adjust zoom factor to make whole map fit in window // void Instance::zoom_fit() { if (level.numVertices() == 0) return; v2double_t zoom = { 1, 1 }; v2int_t ScrMax = { main_win->canvas->w(), main_win->canvas->h() }; if (level.Map_bound1.x < level.Map_bound2.x) zoom.x = ScrMax.x / (level.Map_bound2.x - level.Map_bound1.x); if (level.Map_bound1.y < level.Map_bound2.y) zoom.y = ScrMax.y / (level.Map_bound2.y - level.Map_bound1.y); grid.NearestScale(std::min(zoom.x, zoom.y)); grid.MoveTo((level.Map_bound1 + level.Map_bound2) / 2); } void Instance::ZoomWholeMap() { if (level.MadeChanges) level.CalculateLevelBounds(); zoom_fit(); RedrawMap(); } void Instance::RedrawMap() { UpdateHighlight(); if(main_win) { main_win->scroll->UpdateRenderMode(); main_win->info_bar->UpdateSecRend(); main_win->status_bar->redraw(); main_win->canvas->redraw(); } } static int Selection_FirstLine(const Document &doc, const selection_c &list); static void UpdatePanel(const Instance &inst) { // -AJA- I think the highlighted object is always the same type as // the current editing mode. But do this check for safety. if (inst.edit.highlight.valid() && inst.edit.highlight.type != inst.edit.mode) return; // Choose object to show in right-hand panel: // - the highlighted object takes priority // - otherwise show the selection (first + count) // // It's a little more complicated since highlight may or may not // be part of the selection. int obj_idx = inst.edit.highlight.num; int obj_count = inst.edit.Selected->count_obj(); // the highlight is usually turned off when dragging, so compensate if (obj_idx < 0 && inst.edit.action == EditorAction::drag) obj_idx = inst.edit.dragged.num; if (obj_idx >= 0) { if (! inst.edit.Selected->get(obj_idx)) obj_count = 0; } else if (obj_count > 0) { // in linedef mode, we prefer showing a two-sided linedef if (inst.edit.mode == ObjType::linedefs && obj_count > 1) obj_idx = Selection_FirstLine(inst.level, *inst.edit.Selected); else obj_idx = inst.edit.Selected->find_first(); } if(inst.main_win) { switch (inst.edit.mode) { case ObjType::things: inst.main_win->thing_box->SetObj(obj_idx, obj_count); break; case ObjType::linedefs: inst.main_win->line_box->SetObj(obj_idx, obj_count); break; case ObjType::sectors: inst.main_win->sec_box->SetObj(obj_idx, obj_count); break; case ObjType::vertices: inst.main_win->vert_box->SetObj(obj_idx, obj_count); break; default: break; } } } void Instance::UpdateDrawLine() { if (edit.action != EditorAction::drawLine || edit.drawLine.from.is_nil()) return; const auto V = level.vertices[edit.drawLine.from.num]; v2double_t newpos = edit.map.xy; if (grid.getRatio() > 0) { grid.RatioSnapXY(newpos, V->xy()); } else if (edit.highlight.valid()) { newpos = level.vertices[edit.highlight.num]->xy(); } else if (edit.split_line.valid()) { newpos = edit.split; } else { newpos = grid.Snap(newpos); } edit.drawLine.to = newpos; // when drawing mode, highlight a vertex at the snap position if (grid.snaps() && edit.highlight.is_nil() && edit.split_line.is_nil()) { int near_vert = level.vertmod.findExact(FFixedPoint(newpos.x), FFixedPoint(newpos.y)); if (near_vert >= 0) { edit.highlight = Objid(ObjType::vertices, near_vert); } } // never highlight the vertex we are drawing from if (edit.drawLine.from.valid() && edit.drawLine.from == edit.highlight) { edit.highlight.clear(); } } static void UpdateSplitLine(Instance &inst, const v2double_t &map) { inst.edit.split_line.clear(); // splitting usually disabled while dragging stuff, EXCEPT a single vertex if (inst.edit.action == EditorAction::drag && inst.edit.dragged.is_nil()) goto done; // in vertex mode, see if there is a linedef which would be split by // adding a new vertex. if (inst.edit.mode == ObjType::vertices && inst.edit.pointer_in_window && inst.edit.highlight.is_nil()) { inst.edit.split_line = hover::findSplitLine(inst.level, inst.loaded.levelFormat, inst.edit, inst.grid, inst.edit.split, map, inst.edit.dragged.num); // NOTE: OK if the split line has one of its vertices selected // (that case is handled by Insert_Vertex) } done: if(inst.main_win) inst.main_win->canvas->UpdateHighlight(); } void Instance::UpdateHighlight() { if (edit.render3d) { Render3D_UpdateHighlight(); UpdatePanel(*this); return; } // find the object to highlight edit.highlight.clear(); // don't highlight when dragging, EXCEPT when dragging a single vertex if (edit.pointer_in_window && (edit.action != EditorAction::drag || (edit.mode == ObjType::vertices && edit.dragged.valid()) )) { edit.highlight = hover::getNearbyObject(edit.mode, level, conf, grid, edit.map.xy); // guarantee that we cannot drag a vertex onto itself if (edit.action == EditorAction::drag && edit.dragged.valid() && edit.highlight.valid() && edit.dragged.num == edit.highlight.num) { edit.highlight.clear(); } // if drawing a line and ratio lock is ON, only highlight a // vertex if it is *exactly* the right ratio. if (grid.getRatio() > 0 && edit.action == EditorAction::drawLine && edit.mode == ObjType::vertices && edit.highlight.valid()) { const auto V = level.vertices[edit.highlight.num]; const auto S = level.vertices[edit.drawLine.from.num]; v2double_t vpos = V->xy(); grid.RatioSnapXY(vpos, S->xy()); if (MakeValidCoord(loaded.levelFormat, vpos.x) != V->raw_x || MakeValidCoord(loaded.levelFormat, vpos.y) != V->raw_y) { edit.highlight.clear(); } } } UpdateSplitLine(*this, edit.map.xy); UpdateDrawLine(); if(main_win) { main_win->canvas->UpdateHighlight(); main_win->canvas->CheckGridSnap(); } UpdatePanel(*this); } void Instance::Editor_ClearErrorMode() { if (edit.error_mode) { Selection_Clear(); } } void Instance::Editor_ChangeMode_Raw(ObjType new_mode) { // keep selection after a "Find All" and user dismisses panel if (new_mode == edit.mode && main_win->isSpecialPanelShown()) edit.error_mode = false; edit.mode = new_mode; Editor_ClearAction(); Editor_ClearErrorMode(); edit.highlight.clear(); edit.split_line.clear(); } void Instance::Editor_ChangeMode(char mode_char) { ObjType prev_type = edit.mode; // Set the object type according to the new mode. switch (mode_char) { case 't': Editor_ChangeMode_Raw(ObjType::things); break; case 'l': Editor_ChangeMode_Raw(ObjType::linedefs); break; case 's': Editor_ChangeMode_Raw(ObjType::sectors); break; case 'v': Editor_ChangeMode_Raw(ObjType::vertices); break; default: Beep("Unknown mode: %c\n", mode_char); return; } if (prev_type != edit.mode) { Selection_Push(); main_win->NewEditMode(edit.mode); // convert the selection selection_c prev_sel = *edit.Selected; edit.Selected.emplace(edit.mode, true /* extended */); ConvertSelection(level, prev_sel, *edit.Selected); } else if (main_win->isSpecialPanelShown()) { // same mode, but this removes the special panel main_win->NewEditMode(edit.mode); } // -AJA- Yadex (DEU?) would clear the selection if the mode didn't // change. We optionally emulate that behavior here. else if (config::same_mode_clears_selection) { Selection_Clear(); } RedrawMap(); } //------------------------------------------------------------------------ void Document::UpdateLevelBounds(int start_vert) noexcept { for(int i = start_vert; i < numVertices(); i++) { const auto V = vertices[i]; if (V->x() < Map_bound1.x) Map_bound1.x = V->x(); if (V->y() < Map_bound1.y) Map_bound1.y = V->y(); if (V->x() > Map_bound2.x) Map_bound2.x = V->x(); if (V->y() > Map_bound2.y) Map_bound2.y = V->y(); } } void Document::CalculateLevelBounds() noexcept { if (numVertices() == 0) { Map_bound1.x = Map_bound2.x = 0; Map_bound1.y = Map_bound2.y = 0; return; } Map_bound1.x = 32767; Map_bound2.x = -32767; Map_bound1.y = 32767; Map_bound2.y = -32767; UpdateLevelBounds(0); } void Instance::MapStuff_NotifyBegin() { recalc_map_bounds = false; new_vertex_minimum = -1; moved_vertex_count = 0; sound_propagation_invalid = true; } void Instance::MapStuff_NotifyInsert(ObjType type, int objnum) { if (type == ObjType::vertices) { if (new_vertex_minimum < 0 || objnum < new_vertex_minimum) new_vertex_minimum = objnum; } } void Instance::MapStuff_NotifyDelete(ObjType type, int objnum) { if (type == ObjType::vertices) { recalc_map_bounds = true; if (edit.action == EditorAction::drawLine && edit.drawLine.from.num == objnum) { Editor_ClearAction(); } } } void Instance::MapStuff_NotifyChange(ObjType type, int objnum, int field) { if (type == ObjType::vertices) { // NOTE: for performance reasons we don't recalculate the // map bounds when only moving a few vertices. moved_vertex_count++; const auto V = level.vertices[objnum]; if (V->x() < level.Map_bound1.x) level.Map_bound1.x = V->x(); if (V->y() < level.Map_bound1.y) level.Map_bound1.y = V->y(); if (V->x() > level.Map_bound2.x) level.Map_bound2.x = V->x(); if (V->y() > level.Map_bound2.y) level.Map_bound2.y = V->y(); // TODO: only invalidate sectors touching vertex Subdiv_InvalidateAll(); } if (type == ObjType::sidedefs && field == SideDef::F_SECTOR) Subdiv_InvalidateAll(); if (type == ObjType::linedefs && (field == LineDef::F_LEFT || field == LineDef::F_RIGHT || field == LineDef::F_START || field == LineDef::F_END)) Subdiv_InvalidateAll(); if (type == ObjType::sectors && (field == Sector::F_FLOORH || field == Sector::F_CEILH)) Subdiv_InvalidateAll(); } void Instance::MapStuff_NotifyEnd() { if (recalc_map_bounds || moved_vertex_count > 10) // TODO: CONFIG { level.CalculateLevelBounds(); } else if (new_vertex_minimum >= 0) { level.UpdateLevelBounds(new_vertex_minimum); } } //------------------------------------------------------------------------ // ObjectBox Notification handling //------------------------------------------------------------------------ void Instance::ObjectBox_NotifyBegin() { invalidated_totals = false; invalidated_panel_obj = false; changed_panel_obj = false; changed_recent_list = false; } void Instance::ObjectBox_NotifyInsert(ObjType type, int objnum) { invalidated_totals = true; if (type != edit.mode) return; if (objnum > main_win->GetPanelObjNum()) return; invalidated_panel_obj = true; } void Instance::ObjectBox_NotifyDelete(ObjType type, int objnum) { invalidated_totals = true; if (type != edit.mode) return; if (main_win && objnum > main_win->GetPanelObjNum()) return; invalidated_panel_obj = true; } void Instance::ObjectBox_NotifyChange(ObjType type, int objnum, int field) { if (type != edit.mode || !main_win) return; if (objnum != main_win->GetPanelObjNum()) return; changed_panel_obj = true; } void Instance::ObjectBox_NotifyEnd() const { if(!main_win) return; if (invalidated_totals) main_win->UpdateTotals(level); if (invalidated_panel_obj) { main_win->InvalidatePanelObj(); } else if (changed_panel_obj) { main_win->UpdatePanelObj(); } if (changed_recent_list) main_win->browser->RecentUpdate(); } //------------------------------------------------------------------------ // Selection Notification, ETC //------------------------------------------------------------------------ void Instance::Selection_NotifyBegin() { invalidated_selection = false; invalidated_last_sel = false; } void Instance::Selection_NotifyInsert(ObjType type, int objnum) { if (edit.Selected && type == edit.Selected->what_type() && objnum <= edit.Selected->max_obj()) { invalidated_selection = true; } if (last_Sel && type == last_Sel->what_type() && objnum <= last_Sel->max_obj()) { invalidated_last_sel = true; } } void Instance::Selection_NotifyDelete(ObjType type, int objnum) { if (edit.Selected && objnum <= edit.Selected->max_obj()) { invalidated_selection = true; } if (last_Sel && type == last_Sel->what_type() && objnum <= last_Sel->max_obj()) { invalidated_last_sel = true; } } void Selection_NotifyChange(ObjType type, int objnum, int field) { // field changes never affect the current selection } void Instance::Selection_NotifyEnd() { if (invalidated_selection) { // this clears AND RESIZES the selection_c object edit.Selected->change_type(edit.mode); } if (invalidated_last_sel) Selection_InvalidateLast(); } // // list the contents of a selection (for debugging) // void DumpSelection(selection_c * list) { SYS_ASSERT(list); printf("Selection:"); for (sel_iter_c it(list); ! it.done(); it.next()) printf(" %d", *it); printf("\n"); } void ConvertSelection(const Document &doc, const selection_c & src, selection_c & dest) { if (src.what_type() == dest.what_type()) { dest.merge(src); return; } if (src.what_type() == ObjType::sectors && dest.what_type() == ObjType::things) { for (int t = 0 ; t < doc.numThings() ; t++) { const auto T = doc.things[t]; Objid obj = hover::getNearestSector(doc, T->xy()); if (! obj.is_nil() && src.get(obj.num)) { dest.set(t); } } return; } if (src.what_type() == ObjType::sectors && dest.what_type() == ObjType::linedefs) { for (int l = 0 ; l < doc.numLinedefs(); l++) { const auto L = doc.linedefs[l]; if ( (doc.getRight(*L) && src.get(doc.getRight(*L)->sector)) || (doc.getLeft(*L) && src.get(doc.getLeft(*L)->sector)) ) { dest.set(l); } } return; } if (src.what_type() == ObjType::sectors && dest.what_type() == ObjType::vertices) { for (const auto &L : doc.linedefs) { if ( (doc.getRight(*L) && src.get(doc.getRight(*L)->sector)) || (doc.getLeft(*L) && src.get(doc.getLeft(*L)->sector)) ) { dest.set(L->start); dest.set(L->end); } } return; } if (src.what_type() == ObjType::linedefs && dest.what_type() == ObjType::sidedefs) { for (sel_iter_c it(src); ! it.done(); it.next()) { const auto L = doc.linedefs[*it]; if (doc.getRight(*L)) dest.set(L->right); if (doc.getLeft(*L)) dest.set(L->left); } return; } if (src.what_type() == ObjType::sectors && dest.what_type() == ObjType::sidedefs) { for (int n = 0 ; n < doc.numSidedefs(); n++) { const auto SD = doc.sidedefs[n]; if (src.get(SD->sector)) dest.set(n); } return; } if (src.what_type() == ObjType::linedefs && dest.what_type() == ObjType::vertices) { for (sel_iter_c it(src); ! it.done(); it.next()) { const auto L = doc.linedefs[*it]; dest.set(L->start); dest.set(L->end); } return; } if (src.what_type() == ObjType::vertices && dest.what_type() == ObjType::linedefs) { // select all linedefs that have both ends selected for (int l = 0 ; l < doc.numLinedefs(); l++) { const auto L = doc.linedefs[l]; if (src.get(L->start) && src.get(L->end)) { dest.set(l); } } } // remaining conversions are L->S and V->S if (dest.what_type() != ObjType::sectors) return; if (src.what_type() != ObjType::linedefs && src.what_type() != ObjType::vertices) return; // step 1: select all sectors (except empty ones) int l; for (l = 0 ; l < doc.numLinedefs() ; l++) { const auto L = doc.linedefs[l]; if (doc.getRight(*L)) dest.set(doc.getRight(*L)->sector); if (doc.getLeft(*L)) dest.set(doc.getLeft(*L)->sector); } // step 2: unselect any sectors if a component is not selected for (l = 0 ; l < doc.numLinedefs(); l++) { const auto L = doc.linedefs[l]; if (src.what_type() == ObjType::vertices) { if (src.get(L->start) && src.get(L->end)) continue; } else { if (src.get(l)) continue; } if (doc.getRight(*L)) dest.clear(doc.getRight(*L)->sector); if (doc.getLeft(*L)) dest.clear(doc.getLeft(*L)->sector); } } // // Return the line to show in the LineDef panel from the selection. // When the selection is a mix of one-sided and two-sided lines, then // we want the first TWO-SIDED line. // // NOTE: this is slow, as it may need to search the whole list. // static int Selection_FirstLine(const Document &doc, const selection_c &list) { for (sel_iter_c it(list); ! it.done(); it.next()) { const auto L = doc.linedefs[*it]; if (L->TwoSided()) return *it; } // return first entry (a one-sided line) return list.find_first(); } // // This is a helper to handle performing an operation on the // selection if it is non-empty, otherwise the highlight. // Returns false if both selection and highlight are empty. // SelectHighlight Editor_State_t::SelectionOrHighlight() { if(!Selected->empty()) return SelectHighlight::ok; if (highlight.valid()) { Selection_AddHighlighted(); return SelectHighlight::unselect; } return SelectHighlight::empty; } // // select all objects inside a given box // void SelectObjectsInBox(const Document &doc, selection_c *list, ObjType objtype, v2double_t pos1, v2double_t pos2) { if (pos2.x < pos1.x) std::swap(pos1.x, pos2.x); if (pos2.y < pos1.y) std::swap(pos1.y, pos2.y); switch (objtype) { case ObjType::things: for (int n = 0 ; n < doc.numThings() ; n++) { const auto T = doc.things[n]; v2double_t tpos = T->xy(); if(tpos.inbounds(pos1, pos2)) list->toggle(n); } break; case ObjType::vertices: for (int n = 0 ; n < doc.numVertices(); n++) { const auto V = doc.vertices[n]; v2double_t vpos = V->xy(); if(vpos.inbounds(pos1, pos2)) list->toggle(n); } break; case ObjType::linedefs: for (int n = 0 ; n < doc.numLinedefs(); n++) { const auto L = doc.linedefs[n]; /* the two ends of the line must be in the box */ if(doc.getStart(*L).xy().inbounds(pos1, pos2) && doc.getEnd(*L).xy().inbounds(pos1, pos2)) { list->toggle(n); } } break; case ObjType::sectors: { selection_c in_sectors(ObjType::sectors); selection_c out_sectors(ObjType::sectors); for (int n = 0 ; n < doc.numLinedefs(); n++) { const auto L = doc.linedefs[n]; // Get the numbers of the sectors on both sides of the linedef int s1 = doc.getRight(*L) ? doc.getRight(*L)->sector : -1; int s2 = doc.getLeft(*L) ? doc.getLeft(*L) ->sector : -1; if(doc.getStart(*L).xy().inbounds(pos1, pos2) && doc.getEnd(*L).xy().inbounds(pos1, pos2)) { if (s1 >= 0) in_sectors.set(s1); if (s2 >= 0) in_sectors.set(s2); } else { if (s1 >= 0) out_sectors.set(s1); if (s2 >= 0) out_sectors.set(s2); } } for (int i = 0 ; i < doc.numSectors(); i++) if (in_sectors.get(i) && ! out_sectors.get(i)) list->toggle(i); break; } default: break; } } void Instance::Selection_InvalidateLast() noexcept { last_Sel.reset(); } void Instance::Selection_Push() { if (edit.Selected->empty()) return; if (last_Sel && last_Sel->test_equal(*edit.Selected)) return; // OK copy it last_Sel.emplace(edit.Selected->what_type(), true); last_Sel->merge(*edit.Selected); } void Instance::Selection_Clear(bool no_save) { if (! no_save) Selection_Push(); // this always clears it edit.Selected->change_type(edit.mode); edit.error_mode = false; if (main_win) main_win->UnselectPics(); RedrawMap(); } void Editor_State_t::Selection_AddHighlighted() { Objid &obj = highlight; // validate the mode is correct if (obj.type != mode) return; if (obj.parts == 0) { // ignore the add if object is already set. // [ since the selection may have parts, and we don't want to // forget those parts ] if (! Selected->get(obj.num)) Selected->set(obj.num); return; } byte cur = Selected->get_ext(obj.num); cur = static_cast(1 | obj.parts); Selected->set_ext(obj.num, cur); } void Editor_State_t::Selection_Toggle(Objid& obj) { if (obj.type != mode) return; if (obj.parts == 0) { Selected->toggle(obj.num); return; } byte cur = Selected->get_ext(obj.num); // if object was simply selected, then just clear it if (cur == 1) { Selected->clear(obj.num); return; } cur = static_cast(1 | (cur ^ obj.parts)); // if we toggled off all the parts, then unset the object itself if (cur == 1) cur = 0; Selected->set_ext(obj.num, cur); } static void Selection_Validate(Instance &inst) { int num_obj = inst.level.numObjects(inst.edit.mode); if (inst.edit.Selected->max_obj() >= num_obj) { inst.edit.Selected->frob_range(num_obj, inst.edit.Selected->max_obj(), BitOp::remove); inst.Beep("BUG: invalid selection"); } } void Instance::CMD_LastSelection() { if (! last_Sel) { Beep("No last selection (or was invalidated)"); return; } bool changed_mode = false; if (last_Sel->what_type() != edit.mode) { changed_mode = true; Editor_ChangeMode_Raw(last_Sel->what_type()); main_win->NewEditMode(edit.mode); } last_Sel.swap(edit.Selected); // ensure everything is kosher Selection_Validate(*this); if (changed_mode) GoToSelection(); RedrawMap(); } //------------------------------------------------------------------------ // RECENTLY USED TEXTURES (etc) //------------------------------------------------------------------------ int Recently_used::find(const SString &name) { for (int k = 0 ; k < size ; k++) if (name_set[k].noCaseEqual(name)) return k; return -1; // not found } int Recently_used::find_number(int val) { return find(SString::printf("%d", val)); } void Recently_used::insert(const SString &name) { // ignore '-' texture if (is_null_tex(name)) return; // ignore empty strings to prevent potential problems if (name.empty()) return; int idx = find(name); // optimisation if (idx >= 0 && idx < 4) return; if (idx >= 0) erase(idx); push_front(name); // mark browser for later update // [ this method may be called very often by basis, too expensive to // update the browser here ] inst.changed_recent_list = true; } void Recently_used::insert_number(int val) { insert(SString::printf("%d", val)); } void Recently_used::erase(int index) { SYS_ASSERT(0 <= index && index < size); size--; for ( ; index < size ; index++) { name_set[index] = name_set[index + 1]; } name_set[index].clear(); } void Recently_used::push_front(const SString &name) { if (size >= keep_num) { erase(keep_num - 1); } // shift elements up for (int k = size - 1 ; k >= 0 ; k--) { name_set[k + 1] = name_set[k]; } name_set[0] = name; size++; } void Recently_used::clear() { size = 0; for(SString &name : name_set) name.clear(); } static void RecUsed_ClearAll(Instance &inst) { inst.recent_textures.clear(); inst.recent_flats .clear(); inst.recent_things .clear(); if (inst.main_win) inst.main_win->browser->RecentUpdate(); } /* --- Save and Restore --- */ void Recently_used::WriteUser(std::ostream &os, char letter) const { for (int i = 0 ; i < size ; i++) { os << "recent_used " << letter << " \"" << name_set[i].getTidy() << "\"\n"; } } void Instance::RecUsed_WriteUser(std::ostream &os) const { os << "\nrecent_used clear\n"; recent_textures.WriteUser(os, 'T'); recent_flats.WriteUser(os, 'F'); recent_things.WriteUser(os, 'O'); } bool Instance::RecUsed_ParseUser(const std::vector &tokens) { if (tokens[0] != "recent_used" || tokens.size() < 2) return false; if (tokens[1] == "clear") { RecUsed_ClearAll(*this); return true; } // syntax is: recent_used if (tokens.size() < 3) return false; switch (tokens[1][0]) { case 'T': recent_textures.insert(tokens[2]); break; case 'F': recent_flats.insert(tokens[2]); break; case 'O': recent_things.insert(tokens[2]); break; default: // ignore it break; } if (main_win) main_win->browser->RecentUpdate(); return true; } //------------------------------------------------------------------------ // this in e_commands.cc void Editor_RegisterCommands(); void Instance::Editor_Init() { switch (config::default_edit_mode) { case 1: edit.mode = ObjType::linedefs; break; case 2: edit.mode = ObjType::sectors; break; case 3: edit.mode = ObjType::vertices; break; default: edit.mode = ObjType::things; break; } edit.render3d = false; edit.defaultState(); Nav_Clear(); edit.pointer_in_window = false; edit.map = { 0, 0, -1 }; edit.Selected.emplace(edit.mode, true /* extended */); edit.highlight.clear(); edit.split_line.clear(); edit.clicked.clear(); grid.Init(); level.MadeChanges = false; Editor_RegisterCommands(); Render3D_RegisterCommands(); } void Editor_State_t::defaultState() { action = EditorAction::nothing; sticky_mod = 0; is_panning = false; dragged.clear(); drawLine.from.clear(); error_mode = false; show_object_numbers = false; sector_render_mode = config::sector_render_default; thing_render_mode = config::thing_render_default; } bool Instance::Editor_ParseUser(const std::vector &tokens) { if (tokens[0] == "edit_mode" && tokens.size() >= 2) { Editor_ChangeMode(tokens[1][0]); return true; } if (tokens[0] == "render_mode" && tokens.size() >= 2) { edit.render3d = atoi(tokens[1]); RedrawMap(); return true; } if (tokens[0] == "sector_render_mode" && tokens.size() >= 2) { edit.sector_render_mode = atoi(tokens[1]); RedrawMap(); return true; } if (tokens[0] == "thing_render_mode" && tokens.size() >= 2) { edit.thing_render_mode = atoi(tokens[1]); RedrawMap(); return true; } if (tokens[0] == "show_object_numbers" && tokens.size() >= 2) { edit.show_object_numbers = atoi(tokens[1]); RedrawMap(); return true; } return false; } // // Write editor state // void Instance::Editor_WriteUser(std::ostream &os) const { switch (edit.mode) { case ObjType::things: os << "edit_mode t\n"; break; case ObjType::linedefs: os << "edit_mode l\n"; break; case ObjType::sectors: os << "edit_mode s\n"; break; case ObjType::vertices: os << "edit_mode v\n"; break; default: break; } os << "render_mode " << (edit.render3d ? 1 : 0) << '\n'; os << "sector_render_mode " << edit.sector_render_mode << '\n'; os << "thing_render_mode " << edit.thing_render_mode << '\n'; os << "show_object_numbers " << (edit.show_object_numbers ? 1 : 0) << '\n'; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_main.h000066400000000000000000000134441464327712600177370ustar00rootroot00000000000000//------------------------------------------------------------------------ // LEVEL MISC STUFF //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_LEVELS_H__ #define __EUREKA_LEVELS_H__ #include #include "tl/optional.hpp" #include "m_events.h" #include "e_objects.h" #include "e_things.h" #include "m_select.h" #include "m_vector.h" class SaveBucket_c; class selection_c; typedef enum { SREND_Nothing = 0, SREND_Floor, SREND_Ceiling, SREND_Lighting, SREND_FloorBright, SREND_CeilBright, SREND_SoundProp } sector_rendering_mode_e; // // When using editor // enum class SelectHighlight { ok, // using selection, nothing else needed unselect, // using highlight, must unselect at end empty // both selection or highlight are empty }; // // line drawing stuff (EditorAction::drawLine) // struct DrawLineState { Objid from; // the vertex we are drawing a line from v2double_t to; // target coordinate of current line }; // // Navigation state // struct Navigation { float fwd, back; float left, right; float up, down; float turn_L, turn_R; bool lax; }; // // this holds some important editor state // struct Editor_State_t { SelectHighlight SelectionOrHighlight(); void Selection_AddHighlighted(); void Selection_Toggle(Objid &obj); void defaultState(); void clearNav() { nav = {}; } ObjType mode; // current mode (OBJ_LINEDEFS, OBJ_SECTORS, etc...) bool render3d; // 3D view is active EditorAction action; // an in-progress action, usually EditorAction::nothing keycode_t sticky_mod; // if != 0, waiting for next key (fake meta) bool pointer_in_window; // whether the mouse is over the 2D/3D view v3double_t map; // map coordinates of pointer (no Z in 2D) tl::optional Selected; // all selected objects (usually empty) Objid highlight; // the highlighted object Objid split_line; // linedef which would be split by a new vertex v2double_t split; /* rendering stuff */ bool error_mode; // draw selection in red? int sector_render_mode; // one of the SREND_XXX values int thing_render_mode; bool show_object_numbers; /* navigation stuff */ bool is_navigating; // user is holding down a navigation key bool is_panning; // user is panning the map (turning in 3D) via RMB Navigation nav; float panning_speed; bool panning_lax; /* click stuff (EditorAction::click) */ Objid clicked; // object under the pointer when ACT_Click occurred v2int_t click_screen_pos; // screen coord of the click v3double_t click_map; // location of the click bool click_check_drag; bool click_check_select; bool click_force_single; /* line drawing stuff (EditorAction::drawLine) */ DrawLineState drawLine; /* selection-box stuff (EditorAction::selbox) */ v2double_t selbox1; // map coords v2double_t selbox2; /* transforming state (EditorAction::transform) */ v2double_t trans_start; transform_keyword_e trans_mode; transform_t trans_param; selection_c *trans_lines; /* dragging state (EditorAction::drag) */ Objid dragged; // the object we are dragging, or nil for whole selection v2int_t drag_screen_dpos; v3double_t drag_start; v3double_t drag_focus; v3double_t drag_cur; float drag_point_dist; float drag_sector_dz; int drag_other_vert; // used to ratio-lock a dragged vertex int drag_thing_num; float drag_thing_floorh; bool drag_thing_up_down; selection_c *drag_lines; /* adjusting state (EditorAction::adjustOfs) */ float adjust_dx, adjust_dy; bool adjust_lax; SaveBucket_c * adjust_bucket; struct { float x1, y1, x2, y2; } adjust_bbox; }; void Selection_NotifyChange(ObjType type, int objnum, int field); void DumpSelection (selection_c * list); void ConvertSelection(const Document &doc, const selection_c & src, selection_c & dest); void SelectObjectsInBox(const Document &doc, selection_c *list, ObjType objtype, v2double_t pos1, v2double_t pos2); //---------------------------------------------------------------------- // Helper for handling either the highlight or selection //---------------------------------------------------------------------- //---------------------------------------------------------------------- // Recently used textures, flats and things //---------------------------------------------------------------------- #define RECENTLY_USED_MAX 32 class Recently_used { private: int size = 0; int keep_num = RECENTLY_USED_MAX - 2; SString name_set[RECENTLY_USED_MAX]; Instance &inst; public: explicit Recently_used(Instance &inst) : inst(inst) { } int find(const SString &name); int find_number(int val); void insert(const SString &name); void insert_number(int val); void clear(); void WriteUser(std::ostream &os, char letter) const; private: void erase(int index); void push_front(const SString &name); }; #endif /* __EUREKA_LEVELS_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_objects.cc000066400000000000000000001643651464327712600206130ustar00rootroot00000000000000//------------------------------------------------------------------------ // OBJECT OPERATIONS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include #include "e_hover.h" #include "e_linedef.h" #include "e_main.h" #include "e_sector.h" #include "e_things.h" #include "e_vertex.h" #include "LineDef.h" #include "m_config.h" #include "m_game.h" #include "m_vector.h" #include "e_objects.h" #include "r_grid.h" #include "Sector.h" #include "SideDef.h" #include "Thing.h" #include "Vertex.h" #include "w_rawdef.h" #include "ui_window.h" // config items int config::new_sector_size = 128; // // delete a group of objects. // this is very raw, e.g. it does not check for stuff that will // remain unused afterwards. // void ObjectsModule::del(EditOperation &op, const selection_c &list) const { // we need to process the object numbers from highest to lowest, // because each deletion invalidates all higher-numbered refs // in the selection. Our selection iterator cannot give us // what we need, hence put them into a vector for sorting. if (list.empty()) return; std::vector objnums; for (sel_iter_c it(list) ; !it.done() ; it.next()) objnums.push_back(*it); std::sort(objnums.begin(), objnums.end()); for (int i = (int)objnums.size()-1 ; i >= 0 ; i--) op.del(list.what_type(), objnums[i]); } void ObjectsModule::createSquare(EditOperation &op, int model) const { int new_sec = op.addNew(ObjType::sectors); if (model >= 0) *doc.sectors[new_sec] = *doc.sectors[model]; else doc.sectors[new_sec]->SetDefaults(inst.conf); double x1 = inst.grid.QuantSnapX(inst.edit.map.x, false); double y1 = inst.grid.QuantSnapX(inst.edit.map.y, false); double x2 = x1 + config::new_sector_size; double y2 = y1 + config::new_sector_size; for (int i = 0 ; i < 4 ; i++) { int new_v = op.addNew(ObjType::vertices); auto V = doc.vertices[new_v]; V->SetRawX(inst.loaded.levelFormat, (i >= 2) ? x2 : x1); V->SetRawY(inst.loaded.levelFormat, (i==1 || i==2) ? y2 : y1); int new_sd = op.addNew(ObjType::sidedefs); doc.sidedefs[new_sd]->SetDefaults(inst.conf, false); doc.sidedefs[new_sd]->sector = new_sec; int new_ld = op.addNew(ObjType::linedefs); auto L = doc.linedefs[new_ld]; L->start = new_v; L->end = (i == 3) ? (new_v - 3) : new_v + 1; L->flags = MLF_Blocking; L->right = new_sd; } // select it inst.Selection_Clear(); inst.edit.Selected->set(new_sec); } void ObjectsModule::insertThing() const { int model = -1; if (inst.edit.Selected->notempty()) model = inst.edit.Selected->find_first(); int new_t; { EditOperation op(doc.basis); new_t = op.addNew(ObjType::things); auto T = doc.things[new_t]; if(model >= 0) *T = *doc.things[model]; else { T->type = inst.conf.default_thing; T->options = MTF_Easy | MTF_Medium | MTF_Hard; if (inst.loaded.levelFormat != MapFormat::doom) { T->options |= MTF_Hexen_SP | MTF_Hexen_COOP | MTF_Hexen_DM; T->options |= MTF_Hexen_Fighter | MTF_Hexen_Cleric | MTF_Hexen_Mage; } } T->SetRawX(inst.loaded.levelFormat, inst.grid.SnapX(inst.edit.map.x)); T->SetRawY(inst.loaded.levelFormat, inst.grid.SnapY(inst.edit.map.y)); inst.recent_things.insert_number(T->type); op.setMessage("added thing #%d", new_t); } // select it inst.Selection_Clear(); inst.edit.Selected->set(new_t); } int ObjectsModule::sectorNew(EditOperation &op, int model, int model2, int model3) const { int new_sec = op.addNew(ObjType::sectors); if (model < 0) model = model2; if (model < 0) model = model3; if (model < 0) doc.sectors[new_sec]->SetDefaults(inst.conf); else *doc.sectors[new_sec] = *doc.sectors[model]; return new_sec; } bool ObjectsModule::checkClosedLoop(EditOperation &op, int new_ld, int v1, int v2, selection_c &flip) const { // returns true if we assigned a sector (so drawing should stop) struct check_closed_data_t { lineloop_c loop; bool ok; // what sector we face, -1 for VOID int sec; double length; } left{ lineloop_c(doc) }, right{ lineloop_c(doc) }; // trace the loops on either side of the new line left.ok = doc.secmod.traceLineLoop(new_ld, Side::left, left.loop); right.ok = doc.secmod.traceLineLoop(new_ld, Side::right, right.loop); #ifdef DEBUG_LOOP fprintf(stderr, "CLOSED LOOP : left_ok:%d right_ok:%d\n", left.ok ? 1 : 0, right.ok ? 1 : 0); #endif if (! (left.ok && right.ok)) { // this is harder to trigger than you might think. // TODO : find some cases, see what is needed #ifdef DEBUG_LOOP fprintf(stderr, "--> bad bad bad bad bad <--\n"); #endif return false; } // check if the loops are the same, which means we have NOT // split the sector (or created a new one) if ( left.loop.get(right.loop.lines[0], right.loop.sides[0]) || right.loop.get( left.loop.lines[0], left.loop.sides[0])) { // nothing to do, let user keep drawing return false; } #ifdef DEBUG_LOOP fprintf(stderr, "--> %s / %s\n", left.loop.faces_outward ? "OUTIE" : "innie", right.loop.faces_outward ? "OUTIE" : "innie"); #endif left.sec = left.loop.DetermineSector(); right.sec = right.loop.DetermineSector(); #ifdef DEBUG_LOOP fprintf(stderr, "sec %d / %d\n", left.sec, right.sec); #endif left.length = left.loop.TotalLength(); right.length = right.loop.TotalLength(); if (! left.loop.faces_outward) left.loop.FindIslands(); if (! right.loop.faces_outward) right.loop.FindIslands(); /* --- handle outie --- */ // it is probably impossible for both loops to face outward, so // we only need to handle two cases: both innie, or innie + outie. if (left.loop.faces_outward && left.sec >= 0) { left.loop.AssignSector(op, left.sec, flip); } else if (right.loop.faces_outward && right.sec >= 0) { right.loop.AssignSector(op, right.sec, flip); } // create a void island when drawing anti-clockwise inside an // existing sector, unless new island surrounds other islands. if (right.loop.faces_outward && right.sec >= 0 && left.loop.AllBare() && left.loop.islands.empty()) { return true; } if (left.loop.faces_outward || right.loop.faces_outward) { lineloop_c& innie = left.loop.faces_outward ? right.loop : left.loop; // TODO : REVIEW NeighboringSector(), it's a bit random what we get int new_sec = sectorNew(op, innie.NeighboringSector(), -1, -1); innie.AssignSector(op, new_sec, flip); return true; } /* --- handle two innies --- */ // check if the sectors in each loop are different. // this is not the usual situation! we assume the user has // deleted a linedef or two and is correcting the geometry. if (left.sec != right.sec) { if (right.sec >= 0) right.loop.AssignSector(op, right.sec, flip); if ( left.sec >= 0) left.loop.AssignSector(op, left.sec, flip); return true; } // we are creating a NEW sector in one loop (the smallest), // and updating the other loop (unless it is VOID). // the ordering here is significant, and ensures that the // new linedef usually ends at v2 (the final vertex). if (left.length < right.length) { int new_sec = sectorNew(op, left.sec, right.sec, left.loop.NeighboringSector()); if (right.sec >= 0) right.loop.AssignSector(op, right.sec, flip); left.loop.AssignSector(op, new_sec, flip); } else { int new_sec = sectorNew(op, right.sec, left.sec, right.loop.NeighboringSector()); right.loop.AssignSector(op, new_sec, flip); if (left.sec >= 0) left.loop.AssignSector(op, left.sec, flip); } return true; } void ObjectsModule::insertLinedef(EditOperation &op, int v1, int v2, bool no_fill) const { if (doc.linemod.linedefAlreadyExists(v1, v2)) return; int new_ld = op.addNew(ObjType::linedefs); auto L = doc.linedefs[new_ld]; L->start = v1; L->end = v2; L->flags = MLF_Blocking; if (no_fill) return; if (doc.vertmod.howManyLinedefs(v1) >= 2 && doc.vertmod.howManyLinedefs(v2) >= 2) { selection_c flip(ObjType::linedefs); checkClosedLoop(op, new_ld, v1, v2, flip); doc.linemod.flipLinedefGroup(op, &flip); } } void ObjectsModule::insertLinedefAutosplit(EditOperation &op, int v1, int v2, bool no_fill) const { // Find a linedef which this new line would cross, and if it exists // add a vertex there and create TWO lines. Also handle a vertex // that this line crosses (sits on) similarly. /// fprintf(stderr, "Insert_LineDef_autosplit %d..%d\n", v1, v2); crossing_state_c cross(inst); doc.hover.findCrossingPoints(cross, doc.vertices[v1]->xy(), v1, doc.vertices[v2]->xy(), v2); cross.SplitAllLines(op); int cur_v = v1; for (unsigned int k = 0 ; k < cross.points.size() ; k++) { int next_v = cross.points[k].vert; SYS_ASSERT(next_v != v1); SYS_ASSERT(next_v != v2); insertLinedef(op, cur_v, next_v, no_fill); cur_v = next_v; } insertLinedef(op, cur_v, v2, no_fill); } void ObjectsModule::insertVertex(bool force_continue, bool no_fill) const { bool closed_a_loop = false; // when these both >= 0, we will add a linedef between them int old_vert = -1; int new_vert = -1; v2double_t newpos = inst.grid.Snap(inst.edit.map.xy); int orig_num_sectors = doc.numSectors(); // are we drawing a line? if (inst.edit.action == EditorAction::drawLine) { old_vert = inst.edit.drawLine.from.num; newpos = inst.edit.drawLine.to; } // a linedef which we are splitting (usually none) int split_ld = inst.edit.split_line.valid() ? inst.edit.split_line.num : -1; if (split_ld >= 0) { newpos = inst.edit.split; // prevent creating an overlapping line when splitting if (old_vert >= 0 && doc.linedefs[split_ld]->TouchesVertex(old_vert)) { old_vert = -1; } } else { // not splitting a line. // check if there is a "nearby" vertex (e.g. the highlighted one) if (inst.edit.highlight.valid()) new_vert = inst.edit.highlight.num; // if no highlight, look for a vertex at snapped coord if (new_vert < 0 && inst.grid.snaps() && ! (inst.edit.action == EditorAction::drawLine)) new_vert = doc.vertmod.findExact(FFixedPoint(newpos.x), FFixedPoint(newpos.y)); // // handle a highlighted/snapped vertex. // either start drawing from it, or finish a loop at it. // if (new_vert >= 0) { // just ignore when highlight is same as drawing-start if (old_vert >= 0 && *doc.vertices[old_vert] == *doc.vertices[new_vert]) { inst.edit.Selected->set(old_vert); return; } // a plain INSERT will attempt to fix a dangling vertex if (inst.edit.action == EditorAction::nothing) { if (doc.vertmod.tryFixDangler(new_vert)) { // a vertex was deleted, selection/highlight is now invalid return; } } // our insertion point is an existing vertex, and we are not // in drawing mode, so there is no inst.edit operation to perform. if (old_vert < 0) { old_vert = new_vert; new_vert = -1; goto begin_drawing; } // handle case where a line already exists between the two vertices if (doc.linemod.linedefAlreadyExists(old_vert, new_vert)) { // just continue drawing from the second vertex inst.edit.drawLine.from = Objid(ObjType::vertices, new_vert); inst.edit.Selected->set(new_vert); return; } } } // at here: if new_vert >= 0, then old_vert >= 0 and split_ld < 0 // would we create a new vertex on top of an existing one? if (new_vert < 0 && old_vert >= 0 && doc.vertices[old_vert]->Matches(MakeValidCoord(inst.loaded.levelFormat, newpos.x), MakeValidCoord(inst.loaded.levelFormat, newpos.y))) { inst.edit.Selected->set(old_vert); return; } { EditOperation op(doc.basis); if (new_vert < 0) { new_vert = op.addNew(ObjType::vertices); auto V = doc.vertices[new_vert]; V->SetRawXY(inst.loaded.levelFormat, newpos); inst.edit.drawLine.from = Objid(ObjType::vertices, new_vert); inst.edit.Selected->set(new_vert); // splitting an existing line? if (split_ld >= 0) { doc.linemod.splitLinedefAtVertex(op, split_ld, new_vert); op.setMessage("split linedef #%d", split_ld); } else { op.setMessage("added vertex #%d", new_vert); } } if (old_vert < 0) { // there is no starting vertex, therefore no linedef can be added old_vert = new_vert; new_vert = -1; } else { // closing a loop? if (!force_continue && doc.vertmod.howManyLinedefs(new_vert) > 0) { closed_a_loop = true; } // // adding a linedef // SYS_ASSERT(old_vert != new_vert); // this can make new sectors too insertLinedefAutosplit(op, old_vert, new_vert, no_fill); op.setMessage("added linedef"); inst.edit.drawLine.from = Objid(ObjType::vertices, new_vert); inst.edit.Selected->set(new_vert); } } begin_drawing: // begin drawing mode? if (inst.edit.action == EditorAction::nothing && !closed_a_loop && old_vert >= 0 && new_vert < 0) { inst.Selection_Clear(); inst.edit.drawLine.from = Objid(ObjType::vertices, old_vert); inst.edit.Selected->set(old_vert); inst.edit.drawLine.to = doc.vertices[old_vert]->xy(); inst.Editor_SetAction(EditorAction::drawLine); } // stop drawing mode? if (closed_a_loop && !force_continue) { inst.Editor_ClearAction(); } // select vertices of a newly created sector? if (closed_a_loop && doc.numSectors() > orig_num_sectors) { selection_c sel(ObjType::sectors); // more than one sector may have been created, pick the last sel.set(doc.numSectors() - 1); inst.edit.Selected->change_type(inst.edit.mode); ConvertSelection(doc, sel, *inst.edit.Selected); } inst.RedrawMap(); } void ObjectsModule::insertSector() const { int sel_count = inst.edit.Selected->count_obj(); if (sel_count > 1) { inst.Beep("Too many sectors to copy from"); return; } // if outside of the map, create a square if (hover::isPointOutsideOfMap(doc, inst.edit.map.xy)) { EditOperation op(doc.basis); op.setMessage("added sector (outside map)"); int model = -1; if (sel_count > 0) model = inst.edit.Selected->find_first(); createSquare(op, model); return; } // --- adding a NEW sector to the area --- // determine a model sector to copy properties from int model; if (sel_count > 0) model = inst.edit.Selected->find_first(); else if (inst.edit.highlight.valid()) model = inst.edit.highlight.num; else model = -1; // look for a neighbor to copy bool ok; { EditOperation op(doc.basis); op.setMessage("added new sector"); ok = doc.secmod.assignSectorToSpace(op, inst.edit.map.xy, -1 /* create */, model); } // select the new sector if (ok) { inst.Selection_Clear(); inst.edit.Selected->set(doc.numSectors() - 1); } inst.RedrawMap(); } void Instance::CMD_ObjectInsert() { bool force_cont; bool no_fill; if (edit.render3d && edit.mode != ObjType::things) { Beep("Cannot insert in this mode"); return; } switch (edit.mode) { case ObjType::things: level.objects.insertThing(); break; case ObjType::vertices: force_cont = Exec_HasFlag("/continue"); no_fill = Exec_HasFlag("/nofill"); level.objects.insertVertex(force_cont, no_fill); break; case ObjType::sectors: level.objects.insertSector(); break; default: Beep("Cannot insert in this mode"); break; } RedrawMap(); } // // check if any part of a LineDef is inside the given box // bool ObjectsModule::lineTouchesBox(int ld, double x0, double y0, double x1, double y1) const { double lx0 = doc.getStart(*doc.linedefs[ld]).x(); double ly0 = doc.getStart(*doc.linedefs[ld]).y(); double lx1 = doc.getEnd(*doc.linedefs[ld]).x(); double ly1 = doc.getEnd(*doc.linedefs[ld]).y(); double i; // start is entirely inside the square? if (lx0 >= x0 && lx0 <= x1 && ly0 >= y0 && ly0 <= y1) return true; // end is entirely inside the square? if (lx1 >= x0 && lx1 <= x1 && ly1 >= y0 && ly1 <= y1) return true; if ((ly0 > y0) != (ly1 > y0)) { i = lx0 + (y0 - ly0) * (lx1 - lx0) / (ly1 - ly0); if (i >= x0 && i <= x1) return true; /* the linedef crosses the left side */ } if ((ly0 > y1) != (ly1 > y1)) { i = lx0 + (y1 - ly0) * (lx1 - lx0) / (ly1 - ly0); if (i >= x0 && i <= x1) return true; /* the linedef crosses the right side */ } if ((lx0 > x0) != (lx1 > x0)) { i = ly0 + (x0 - lx0) * (ly1 - ly0) / (lx1 - lx0); if (i >= y0 && i <= y1) return true; /* the linedef crosses the bottom side */ } if ((lx0 > x1) != (lx1 > x1)) { i = ly0 + (x1 - lx0) * (ly1 - ly0) / (lx1 - lx0); if (i >= y0 && i <= y1) return true; /* the linedef crosses the top side */ } return false; } // // Move a single vertex, without depending on the user interface highlighting // static void doMoveVertex(EditOperation &op, Instance &inst, const int vertexID, const v2double_t &delta, int &deletedVertexID, const selection_c &movingGroup) { const Vertex &vertex = *inst.level.vertices[vertexID]; deletedVertexID = -1; v2double_t dest = vertex.xy() + delta; Objid obj = hover::getNearbyObject(ObjType::vertices, inst.level, inst.conf, inst.grid, dest); if(obj.valid() && obj.num != vertexID && !movingGroup.get(obj.num)) { // Vertex merging // TODO: messaging selection_c del_list; selection_c verts(ObjType::vertices); verts.set(obj.num); verts.set(vertexID); inst.level.vertmod.mergeList(op, verts, &del_list); deletedVertexID = del_list.find_first(); return; } v2double_t splitPoint; int splitLine = -1; obj = hover::findSplitLine(inst.level, inst.loaded.levelFormat, inst.edit, inst.grid, splitPoint, dest, vertexID); if(obj.valid()) { const auto& L = inst.level.linedefs[obj.num]; assert(L); if (!movingGroup.get(L->start) && !movingGroup.get(L->end)) { splitLine = obj.num; if (inst.level.objects.findLineBetweenLineAndVertex(splitLine, vertexID) >= 0) { // TODO: messaging selection_c del_list; inst.level.objects.splitLinedefAndMergeSandwich(op, splitLine, vertexID, delta, &del_list); deletedVertexID = del_list.find_first(); return; } inst.level.linemod.splitLinedefAtVertex(op, splitLine, vertexID); } } op.changeVertex(vertexID, Thing::F_X, vertex.raw_x + MakeValidCoord(inst.loaded.levelFormat, delta.x)); op.changeVertex(vertexID, Thing::F_Y, vertex.raw_y + MakeValidCoord(inst.loaded.levelFormat, delta.y)); } void ObjectsModule::doMoveObjects(EditOperation &op, const selection_c &list, const v3double_t &delta) const { switch (list.what_type()) { case ObjType::things: { FFixedPoint fdx = MakeValidCoord(inst.loaded.levelFormat, delta.x); FFixedPoint fdy = MakeValidCoord(inst.loaded.levelFormat, delta.y); FFixedPoint fdz = MakeValidCoord(inst.loaded.levelFormat, delta.z); for (sel_iter_c it(list) ; !it.done() ; it.next()) { const auto T = doc.things[*it]; op.changeThing(*it, Thing::F_X, T->raw_x + fdx); op.changeThing(*it, Thing::F_Y, T->raw_y + fdy); op.changeThing(*it, Thing::F_H, std::max(FFixedPoint{}, T->raw_h + fdz)); } break; } case ObjType::vertices: { // We need the selection list as an array so we can easily modify it during iteration std::vector sel = list.asArray(); selection_c movingGroup = list; for(auto it = sel.begin(); it != sel.end(); ++it) { int deletedVertex = -1; doMoveVertex(op, inst, *it, delta.xy, deletedVertex, movingGroup); if (deletedVertex >= 0 && deletedVertex < list.max_obj()) for (auto jt = it + 1; jt != sel.end(); ++jt) if (*jt > deletedVertex) { movingGroup.clear(*jt); --*jt; movingGroup.set(*jt); } movingGroup.clear(*it); } break; } case ObjType::sectors: // apply the Z delta first for (sel_iter_c it(list) ; !it.done() ; it.next()) { const auto S = doc.sectors[*it]; op.changeSector(*it, Sector::F_FLOORH, S->floorh + (int)delta.z); op.changeSector(*it, Sector::F_CEILH, S->ceilh + (int)delta.z); } /* FALL-THROUGH !! */ case ObjType::linedefs: { selection_c verts(ObjType::vertices); ConvertSelection(doc, list, verts); doMoveObjects(op, verts, delta); } break; default: break; } } void ObjectsModule::move(const selection_c &list, const v3double_t &delta) const { if (list.empty()) return; EditOperation op(doc.basis); op.setMessageForSelection("moved", list); int objectsBeforeMoving = 0; if(inst.edit.Selected) objectsBeforeMoving = doc.numObjects(inst.edit.Selected->what_type()); // move things in sectors too (must do it _before_ moving the // sectors, otherwise we fail trying to determine which sectors // each thing is in). if (inst.edit.mode == ObjType::sectors) { selection_c thing_sel(ObjType::things); ConvertSelection(doc, list, thing_sel); doMoveObjects(op, thing_sel, { delta.x, delta.y, 0.0 }); } doMoveObjects(op, list, delta); // We must invalidate the selection if the moving resulted in invalidation if(inst.edit.Selected && doc.numObjects(inst.edit.Selected->what_type()) < objectsBeforeMoving) inst.Selection_Clear(true); // no save } // // Returns, if found, a linedef ID between a given line and vertex, if existing. // Only returns the first one found, if multiple available. // Normally only 2 can exist, when there's a triangle between lineID and vertID. // // Returns -1 if none found // int ObjectsModule::findLineBetweenLineAndVertex(int lineID, int vertID) const { for(int i = 0; i < doc.numLinedefs(); ++i) { const auto otherLine = doc.linedefs[i]; if(!otherLine->TouchesVertex(vertID) || i == lineID) continue; // We have a linedef that is going to overlap the other one to be // split. We need to handle it like above, with merging vertices // Identify the hinge, common vertex int otherLineOtherVertexID = otherLine->OtherVertex(vertID); if(!doc.linedefs[lineID]->TouchesVertex(otherLineOtherVertexID)) continue; // not a hinge between them return i; } return -1; } // // Splits a linedef while also considering resulted merged lines. // It needs delta_x and delta_y in order to properly merge sandwich linedefs. // void ObjectsModule::splitLinedefAndMergeSandwich(EditOperation &op, int splitLineID, int vertID, const v2double_t &delta, selection_c *delResultList) const { // Add a vertex there and do the split int newVID = op.addNew(ObjType::vertices); auto newV = doc.vertices[newVID]; *newV = *doc.vertices[vertID]; // Move it to the actual destination newV->raw_x += MakeValidCoord(inst.loaded.levelFormat, delta.x); newV->raw_y += MakeValidCoord(inst.loaded.levelFormat, delta.y); doc.linemod.splitLinedefAtVertex(op, splitLineID, newVID); // Now merge the vertices selection_c verts(ObjType::vertices); verts.set(newVID); verts.set(vertID); doc.vertmod.mergeList(op, verts, delResultList); } // // Move a single vertex, splitting as necessary // static void singleDragVertex(Instance &inst, const int vertexID, const v2double_t &delta) { EditOperation op(inst.level.basis); int did_split_line = -1; // handle a single vertex merging onto an existing one if (inst.edit.highlight.valid()) { op.setMessage("merge vertex #%d", vertexID); SYS_ASSERT(vertexID != inst.edit.highlight.num); selection_c verts(ObjType::vertices); verts.set(inst.edit.highlight.num); // keep the highlight verts.set(vertexID); inst.level.vertmod.mergeList(op, verts, nullptr); return; } // handle a single vertex splitting a linedef if (inst.edit.split_line.valid()) { did_split_line = inst.edit.split_line.num; // Check if it's actually a case of splitting a neighbouring linedef if(inst.level.objects.findLineBetweenLineAndVertex(did_split_line, vertexID) >= 0) { // Alright, we got it op.setMessage("split linedef #%d", did_split_line); inst.level.objects.splitLinedefAndMergeSandwich(op, did_split_line, vertexID, delta, nullptr); return; } inst.level.linemod.splitLinedefAtVertex(op, did_split_line, vertexID); // now move the vertex! } const Vertex &vertex = *inst.level.vertices[vertexID]; op.changeVertex(vertexID, Thing::F_X, vertex.raw_x + MakeValidCoord(inst.loaded.levelFormat, delta.x)); op.changeVertex(vertexID, Thing::F_Y, vertex.raw_y + MakeValidCoord(inst.loaded.levelFormat, delta.y)); if (did_split_line >= 0) op.setMessage("split linedef #%d", did_split_line); else { selection_c list(inst.edit.mode); list.set(vertexID); op.setMessageForSelection("moved", list); } } void ObjectsModule::singleDrag(const Objid &obj, const v3double_t &delta) const { if (inst.edit.mode != ObjType::vertices) { selection_c list(inst.edit.mode); list.set(obj.num); doc.objects.move(list, delta); return; } /* move a single vertex */ singleDragVertex(inst, obj.num, delta.xy); } void ObjectsModule::transferThingProperties(EditOperation &op, int src_thing, int dest_thing) const { const auto T = doc.things[src_thing]; op.changeThing(dest_thing, Thing::F_TYPE, T->type); op.changeThing(dest_thing, Thing::F_OPTIONS, T->options); // BA_ChangeTH(dest_thing, Thing::F_ANGLE, T->angle); op.changeThing(dest_thing, Thing::F_TID, T->tid); op.changeThing(dest_thing, Thing::F_SPECIAL, T->special); op.changeThing(dest_thing, Thing::F_ARG1, T->arg1); op.changeThing(dest_thing, Thing::F_ARG2, T->arg2); op.changeThing(dest_thing, Thing::F_ARG3, T->arg3); op.changeThing(dest_thing, Thing::F_ARG4, T->arg4); op.changeThing(dest_thing, Thing::F_ARG5, T->arg5); } void ObjectsModule::transferSectorProperties(EditOperation &op, int src_sec, int dest_sec) const { const auto sector = doc.sectors[src_sec]; op.changeSector(dest_sec, Sector::F_FLOORH, sector->floorh); op.changeSector(dest_sec, Sector::F_FLOOR_TEX, sector->floor_tex); op.changeSector(dest_sec, Sector::F_CEILH, sector->ceilh); op.changeSector(dest_sec, Sector::F_CEIL_TEX, sector->ceil_tex); op.changeSector(dest_sec, Sector::F_LIGHT, sector->light); op.changeSector(dest_sec, Sector::F_TYPE, sector->type); op.changeSector(dest_sec, Sector::F_TAG, sector->tag); } #define LINEDEF_FLAG_KEEP (MLF_Blocking + MLF_TwoSided) void ObjectsModule::transferLinedefProperties(EditOperation &op, int src_line, int dest_line, bool do_tex) const { const auto L1 = doc.linedefs[src_line]; const auto L2 = doc.linedefs[dest_line]; // don't transfer certain flags int flags = doc.linedefs[dest_line]->flags; flags = (flags & LINEDEF_FLAG_KEEP) | (L1->flags & ~LINEDEF_FLAG_KEEP); // handle textures if (do_tex && doc.getRight(*L1) && doc.getRight(*L2)) { /* There are four cases, depending on number of sides: * * (a) single --> single : easy * * (b) single --> double : copy mid_tex to both sides upper and lower * [alternate idea: copy mid_tex to VISIBLE sides] * * (c) double --> single : pick a texture (e.g. visible lower) to copy * * (d) double --> double : copy each side, but possibly flip the * second linedef based on floor or ceil diff. */ if (! doc.getLeft(*L1)) { StringID tex = doc.getRight(*L1)->mid_tex; if (! doc.getLeft(*L2)) { op.changeSidedef(L2->right, SideDef::F_MID_TEX, tex); } else { op.changeSidedef(L2->right, SideDef::F_LOWER_TEX, tex); op.changeSidedef(L2->right, SideDef::F_UPPER_TEX, tex); op.changeSidedef(L2->left, SideDef::F_LOWER_TEX, tex); op.changeSidedef(L2->left, SideDef::F_UPPER_TEX, tex); // this is debatable.... CONFIG ITEM? flags |= MLF_LowerUnpegged; flags |= MLF_UpperUnpegged; } } else if (! doc.getLeft(*L2)) { /* pick which texture to copy */ const Sector &front = doc.getSector(*doc.getRight(*L1)); const Sector &back = doc.getSector(*doc.getLeft(*L1)); StringID f_l = doc.getRight(*L1)->lower_tex; StringID f_u = doc.getRight(*L1)->upper_tex; StringID b_l = doc.getLeft(*L1)->lower_tex; StringID b_u = doc.getLeft(*L1)->upper_tex; // ignore missing textures if (is_null_tex(BA_GetString(f_l))) f_l = StringID(); if (is_null_tex(BA_GetString(f_u))) f_u = StringID(); if (is_null_tex(BA_GetString(b_l))) b_l = StringID(); if (is_null_tex(BA_GetString(b_u))) b_u = StringID(); // try hard to find a usable texture StringID tex = StringID(-1); if (front.floorh < back.floorh && f_l.hasContent()) tex = f_l; else if (front.floorh > back.floorh && b_l.hasContent()) tex = b_l; else if (front. ceilh > back. ceilh && f_u.hasContent()) tex = f_u; else if (front. ceilh < back. ceilh && b_u.hasContent()) tex = b_u; else if (f_l.hasContent()) tex = f_l; else if (b_l.hasContent()) tex = b_l; else if (f_u.hasContent()) tex = f_u; else if (b_u.hasContent()) tex = b_u; if (tex.hasContent()) { op.changeSidedef(L2->right, SideDef::F_MID_TEX, tex); } } else { const SideDef *RS = doc.getRight(*L1); const SideDef *LS = doc.getLeft(*L1); const Sector *F1 = &doc.getSector(*doc.getRight(*L1)); const Sector *B1 = &doc.getSector(*doc.getLeft(*L1)); const Sector *F2 = &doc.getSector(*doc.getRight(*L2)); const Sector *B2 = &doc.getSector(*doc.getLeft(*L2)); // logic to determine which sides we copy int f_diff1 = B1->floorh - F1->floorh; int f_diff2 = B2->floorh - F2->floorh; int c_diff1 = B1->ceilh - F1->ceilh; int c_diff2 = B2->ceilh - F2->ceilh; if (f_diff1 * f_diff2 > 0) { /* no change */ } else if (f_diff1 * f_diff2 < 0) std::swap(LS, RS); else if (c_diff1 * c_diff2 > 0) { /* no change */ } else if (c_diff1 * c_diff2 < 0) std::swap(LS, RS); else if (L1->start == L2->end || L1->end == L2->start) { /* no change */ } else if (L1->start == L2->start || L1->end == L2->end) std::swap(LS, RS); else if (F1 == F2 || B1 == B2) { /* no change */ } else if (F1 == B1 || F1 == B2 || F2 == B1 || F2 == B2) std::swap(LS, RS); // TODO; review if we should copy '-' into lowers or uppers op.changeSidedef(L2->right, SideDef::F_LOWER_TEX, RS->lower_tex); op.changeSidedef(L2->right, SideDef::F_MID_TEX, RS->mid_tex); op.changeSidedef(L2->right, SideDef::F_UPPER_TEX, RS->upper_tex); op.changeSidedef(L2->left, SideDef::F_LOWER_TEX, LS->lower_tex); op.changeSidedef(L2->left, SideDef::F_MID_TEX, LS->mid_tex); op.changeSidedef(L2->left, SideDef::F_UPPER_TEX, LS->upper_tex); } } op.changeLinedef(dest_line, LineDef::F_FLAGS, flags); op.changeLinedef(dest_line, LineDef::F_TYPE, L1->type); op.changeLinedef(dest_line, LineDef::F_TAG, L1->tag); op.changeLinedef(dest_line, LineDef::F_ARG2, L1->arg2); op.changeLinedef(dest_line, LineDef::F_ARG3, L1->arg3); op.changeLinedef(dest_line, LineDef::F_ARG4, L1->arg4); op.changeLinedef(dest_line, LineDef::F_ARG5, L1->arg5); } void Instance::CMD_CopyProperties() { if (edit.highlight.is_nil()) { Beep("No target for CopyProperties"); return; } if (edit.Selected->empty()) { Beep("No source for CopyProperties"); return; } if (edit.mode == ObjType::vertices) { Beep("No properties to copy"); return; } /* normal mode, SEL --> HILITE */ if (! Exec_HasFlag("/reverse")) { if (edit.Selected->count_obj() != 1) { Beep("Too many sources for CopyProperties"); return; } int source = edit.Selected->find_first(); int target = edit.highlight.num; // silently allow copying onto self if (source == target) return; EditOperation op(level.basis); op.setMessage("copied properties"); switch (edit.mode) { case ObjType::sectors: level.objects.transferSectorProperties(op, source, target); break; case ObjType::things: level.objects.transferThingProperties(op, source, target); break; case ObjType::linedefs: level.objects.transferLinedefProperties(op, source, target, true /* do_tex */); break; default: break; } } else /* reverse mode, HILITE --> SEL */ { if (edit.Selected->count_obj() == 1 && edit.Selected->find_first() == edit.highlight.num) { Beep("No selection for CopyProperties"); return; } int source = edit.highlight.num; EditOperation op(level.basis); op.setMessage("copied properties"); for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { if (*it == source) continue; switch (edit.mode) { case ObjType::sectors: level.objects.transferSectorProperties(op, source, *it); break; case ObjType::things: level.objects.transferThingProperties(op, source, *it); break; case ObjType::linedefs: level.objects.transferLinedefProperties(op, source, *it, true /* do_tex */); break; default: break; } } } } void ObjectsModule::dragCountOnGridWorker(ObjType obj_type, int objnum, int *count, int *total) const { switch (obj_type) { case ObjType::things: *total += 1; if (inst.grid.OnGrid(doc.things[objnum]->x(), doc.things[objnum]->y())) *count += 1; break; case ObjType::vertices: *total += 1; if (inst.grid.OnGrid(doc.vertices[objnum]->x(), doc.vertices[objnum]->y())) *count += 1; break; case ObjType::linedefs: dragCountOnGridWorker(ObjType::vertices, doc.linedefs[objnum]->start, count, total); dragCountOnGridWorker(ObjType::vertices, doc.linedefs[objnum]->end, count, total); break; case ObjType::sectors: for (int n = 0 ; n < doc.numLinedefs(); n++) { const auto L = doc.linedefs[n]; if (! doc.touchesSector(*L, objnum)) continue; dragCountOnGridWorker(ObjType::linedefs, n, count, total); } break; default: break; } } void ObjectsModule::dragCountOnGrid(int *count, int *total) const { // Note: the results are approximate, vertices can be counted two // or more times. for (sel_iter_c it(*inst.edit.Selected) ; !it.done() ; it.next()) { dragCountOnGridWorker(inst.edit.mode, *it, count, total); } } void ObjectsModule::dragUpdateCurrentDist(ObjType obj_type, int objnum, double *x, double *y, double *best_dist, double ptr_x, double ptr_y, bool only_grid) const { double x2, y2; switch (obj_type) { case ObjType::things: x2 = doc.things[objnum]->x(); y2 = doc.things[objnum]->y(); break; case ObjType::vertices: x2 = doc.vertices[objnum]->x(); y2 = doc.vertices[objnum]->y(); break; case ObjType::linedefs: { const auto L = doc.linedefs[objnum]; dragUpdateCurrentDist(ObjType::vertices, L->start, x, y, best_dist, ptr_x, ptr_y, only_grid); dragUpdateCurrentDist(ObjType::vertices, L->end, x, y, best_dist, ptr_x, ptr_y, only_grid); } return; case ObjType::sectors: // recursively handle all vertices belonging to the sector // (some vertices can be processed two or more times, that // won't matter though). for (int n = 0 ; n < doc.numLinedefs(); n++) { const auto L = doc.linedefs[n]; if (! doc.touchesSector(*L, objnum)) continue; dragUpdateCurrentDist(ObjType::linedefs, n, x, y, best_dist, ptr_x, ptr_y, only_grid); } return; default: return; } // handle OBJ_THINGS and OBJ_VERTICES if (only_grid && !inst.grid.OnGrid(x2, y2)) return; double dist = hypot(x2 - ptr_x, y2 - ptr_y); if (dist < *best_dist) { *x = x2; *y = y2; *best_dist = dist; } } // // Determine the focus coordinate for dragging multiple objects. // The focus only has an effect when grid snapping is on, and // allows a mostly-grid-snapped set of objects to stay snapped // to the grid. // v2double_t ObjectsModule::getDragFocus(const v2double_t &ptr) const { v2double_t result = {}; // determine whether a majority of the object(s) are already on // the grid. If they are, then pick a coordinate that also lies // on the grid. bool only_grid = false; int count = 0; int total = 0; if (inst.grid.snaps()) { dragCountOnGrid(&count, &total); if (total > 0 && count > total / 2) only_grid = true; } // determine object which is closest to mouse pointer AND which // honors the 'only_grid' property (when set). double best_dist = 9e9; if (inst.edit.dragged.valid()) // a single object { dragUpdateCurrentDist(inst.edit.mode, inst.edit.dragged.num, &result.x, &result.y, &best_dist, ptr.x, ptr.y, only_grid); return result; } for (sel_iter_c it(*inst.edit.Selected) ; !it.done() ; it.next()) { dragUpdateCurrentDist(inst.edit.mode, *it, &result.x, &result.y, &best_dist, ptr.x, ptr.y, only_grid); } return result; } //------------------------------------------------------------------------ void transform_t::Clear() { mid = {}; scale = { 1.0, 1.0 }; skew = {}; rotate = 0; } void transform_t::Apply(double *x, double *y) const { double x0 = *x - mid.x; double y0 = *y - mid.y; if (rotate) { double s = sin(rotate); double c = cos(rotate); double x1 = x0; double y1 = y0; x0 = x1 * c - y1 * s; y0 = y1 * c + x1 * s; } if (skew.nonzero()) { double x1 = x0; double y1 = y0; x0 = x1 + y1 * skew.x; y0 = y1 + x1 * skew.y; } *x = mid.x + x0 * scale.x; *y = mid.y + y0 * scale.y; } // // Return the coordinate of the centre of a group of objects. // // This is computed using an average of all the coordinates, which can // often give a different result than using the middle of the bounding // box. // v2double_t ObjectsModule::calcMiddle(const selection_c & list) const { v2double_t result = {}; if (list.empty()) return result; double sum_x = 0; double sum_y = 0; int count = 0; switch (list.what_type()) { case ObjType::things: { for (sel_iter_c it(list) ; !it.done() ; it.next(), ++count) { sum_x += doc.things[*it]->x(); sum_y += doc.things[*it]->y(); } break; } case ObjType::vertices: { for (sel_iter_c it(list) ; !it.done() ; it.next(), ++count) { sum_x += doc.vertices[*it]->x(); sum_y += doc.vertices[*it]->y(); } break; } // everything else: just use the vertices default: { selection_c verts(ObjType::vertices); ConvertSelection(doc, list, verts); return calcMiddle(verts); } } SYS_ASSERT(count > 0); result.x = sum_x / count; result.y = sum_y / count; return result; } // // returns a bounding box that completely includes a list of objects. // when the list is empty, bottom-left coordinate is arbitrary. // void ObjectsModule::calcBBox(const selection_c & list, v2double_t &pos1, v2double_t &pos2) const { if (list.empty()) { pos1 = {}; pos2 = {}; return; } pos1 = { +9e9, +9e9 }; pos2 = { -9e9, -9e9 }; switch (list.what_type()) { case ObjType::things: { for (sel_iter_c it(list) ; !it.done() ; it.next()) { const auto T = doc.things[*it]; double Tx = T->x(); double Ty = T->y(); const thingtype_t &info = inst.conf.getThingType(T->type); int r = info.radius; if (Tx - r < pos1.x) pos1.x = Tx - r; if (Ty - r < pos1.y) pos1.y = Ty - r; if (Tx + r > pos2.x) pos2.x = Tx + r; if (Ty + r > pos2.y) pos2.y = Ty + r; } break; } case ObjType::vertices: { for (sel_iter_c it(list) ; !it.done() ; it.next()) { const auto V = doc.vertices[*it]; double Vx = V->x(); double Vy = V->y(); if (Vx < pos1.x) pos1.x = Vx; if (Vy < pos1.y) pos1.y = Vy; if (Vx > pos2.x) pos2.x = Vx; if (Vy > pos2.y) pos2.y = Vy; } break; } // everything else: just use the vertices default: { selection_c verts(ObjType::vertices); ConvertSelection(doc, list, verts); calcBBox(verts, pos1, pos2); return; } } SYS_ASSERT(pos1.x <= pos2.x); SYS_ASSERT(pos1.y <= pos2.y); } void ObjectsModule::doMirrorThings(EditOperation &op, const selection_c &list, bool is_vert, double mid_x, double mid_y) const { FFixedPoint fix_mx = MakeValidCoord(inst.loaded.levelFormat, mid_x); FFixedPoint fix_my = MakeValidCoord(inst.loaded.levelFormat, mid_y); for (sel_iter_c it(list) ; !it.done() ; it.next()) { const auto T = doc.things[*it]; if (is_vert) { op.changeThing(*it, Thing::F_Y, fix_my * 2 - T->raw_y); if (T->angle != 0) op.changeThing(*it, Thing::F_ANGLE, 360 - T->angle); } else { op.changeThing(*it, Thing::F_X, fix_mx * 2 - T->raw_x); if (T->angle > 180) op.changeThing(*it, Thing::F_ANGLE, 540 - T->angle); else op.changeThing(*it, Thing::F_ANGLE, 180 - T->angle); } } } void ObjectsModule::doMirrorVertices(EditOperation &op, const selection_c &list, bool is_vert, double mid_x, double mid_y) const { FFixedPoint fix_mx = MakeValidCoord(inst.loaded.levelFormat, mid_x); FFixedPoint fix_my = MakeValidCoord(inst.loaded.levelFormat, mid_y); selection_c verts(ObjType::vertices); ConvertSelection(doc, list, verts); for (sel_iter_c it(verts) ; !it.done() ; it.next()) { const auto V = doc.vertices[*it]; if (is_vert) op.changeVertex(*it, Vertex::F_Y, fix_my * 2 - V->raw_y); else op.changeVertex(*it, Vertex::F_X, fix_mx * 2 - V->raw_x); } // flip linedefs too !! selection_c lines(ObjType::linedefs); ConvertSelection(doc, verts, lines); for (sel_iter_c it(lines) ; !it.done() ; it.next()) { const auto L = doc.linedefs[*it]; int start = L->start; int end = L->end; op.changeLinedef(*it, LineDef::F_START, end); op.changeLinedef(*it, LineDef::F_END, start); } } void ObjectsModule::doMirrorStuff(EditOperation &op, const selection_c &list, bool is_vert, double mid_x, double mid_y) const { if (inst.edit.mode == ObjType::things) { doMirrorThings(op, list, is_vert, mid_x, mid_y); return; } // everything else just modifies the vertices if (inst.edit.mode == ObjType::sectors) { // handle things in Sectors mode too selection_c things(ObjType::things); ConvertSelection(doc, list, things); doMirrorThings(op, things, is_vert, mid_x, mid_y); } doMirrorVertices(op, list, is_vert, mid_x, mid_y); } void Instance::CMD_Mirror() { SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { Beep("No objects to mirror"); return; } bool is_vert = false; if (tolower(EXEC_Param[0][0]) == 'v') is_vert = true; v2double_t mid = level.objects.calcMiddle(*edit.Selected); { EditOperation op(level.basis); op.setMessageForSelection("mirrored", *edit.Selected, is_vert ? " vertically" : " horizontally"); level.objects.doMirrorStuff(op, *edit.Selected, is_vert, mid.x, mid.y); } if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); } void ObjectsModule::doRotate90Things(EditOperation &op, const selection_c &list, bool anti_clockwise, double mid_x, double mid_y) const { FFixedPoint fix_mx = MakeValidCoord(inst.loaded.levelFormat, mid_x); FFixedPoint fix_my = MakeValidCoord(inst.loaded.levelFormat, mid_y); for (sel_iter_c it(list) ; !it.done() ; it.next()) { const auto T = doc.things[*it]; FFixedPoint old_x = T->raw_x; FFixedPoint old_y = T->raw_y; if (anti_clockwise) { op.changeThing(*it, Thing::F_X, fix_mx - old_y + fix_my); op.changeThing(*it, Thing::F_Y, fix_my + old_x - fix_mx); op.changeThing(*it, Thing::F_ANGLE, calc_new_angle(T->angle, +90)); } else { op.changeThing(*it, Thing::F_X, fix_mx + old_y - fix_my); op.changeThing(*it, Thing::F_Y, fix_my - old_x + fix_mx); op.changeThing(*it, Thing::F_ANGLE, calc_new_angle(T->angle, -90)); } } } void Instance::CMD_Rotate90() { if (EXEC_Param[0].empty()) { Beep("Rotate90: missing keyword"); return; } bool anti_clockwise = (tolower(EXEC_Param[0][0]) == 'a'); SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { Beep("No objects to rotate"); return; } v2double_t mid = level.objects.calcMiddle(*edit.Selected); { EditOperation op(level.basis); op.setMessageForSelection("rotated", *edit.Selected, anti_clockwise ? " anti-clockwise" : " clockwise"); if (edit.mode == ObjType::things) { level.objects.doRotate90Things(op, *edit.Selected, anti_clockwise, mid.x, mid.y); } else { // handle things inside sectors if (edit.mode == ObjType::sectors) { selection_c things(ObjType::things); ConvertSelection(level, *edit.Selected, things); level.objects.doRotate90Things(op, things, anti_clockwise, mid.x, mid.y); } // everything else just rotates the vertices selection_c verts(ObjType::vertices); ConvertSelection(level, *edit.Selected, verts); FFixedPoint fix_mx = MakeValidCoord(loaded.levelFormat, mid.x); FFixedPoint fix_my = MakeValidCoord(loaded.levelFormat, mid.y); for (sel_iter_c it(verts) ; !it.done() ; it.next()) { const auto V = level.vertices[*it]; FFixedPoint old_x = V->raw_x; FFixedPoint old_y = V->raw_y; if (anti_clockwise) { op.changeVertex(*it, Vertex::F_X, fix_mx - old_y + fix_my); op.changeVertex(*it, Vertex::F_Y, fix_my + old_x - fix_mx); } else { op.changeVertex(*it, Vertex::F_X, fix_mx + old_y - fix_my); op.changeVertex(*it, Vertex::F_Y, fix_my - old_x + fix_mx); } } } } if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); } void ObjectsModule::doScaleTwoThings(EditOperation &op, const selection_c &list, transform_t& param) const { for (sel_iter_c it(list) ; !it.done() ; it.next()) { const auto T = doc.things[*it]; double new_x = T->x(); double new_y = T->y(); param.Apply(&new_x, &new_y); op.changeThing(*it, Thing::F_X, MakeValidCoord(inst.loaded.levelFormat, new_x)); op.changeThing(*it, Thing::F_Y, MakeValidCoord(inst.loaded.levelFormat, new_y)); float rot1 = static_cast(param.rotate / (M_PI / 4)); int ang_diff = static_cast(roundf(rot1) * 45.0); if (ang_diff) { op.changeThing(*it, Thing::F_ANGLE, calc_new_angle(T->angle, ang_diff)); } } } void ObjectsModule::doScaleTwoVertices(EditOperation &op, const selection_c &list, transform_t& param) const { selection_c verts(ObjType::vertices); ConvertSelection(doc, list, verts); for (sel_iter_c it(verts) ; !it.done() ; it.next()) { const auto V = doc.vertices[*it]; double new_x = V->x(); double new_y = V->y(); param.Apply(&new_x, &new_y); op.changeVertex(*it, Vertex::F_X, MakeValidCoord(inst.loaded.levelFormat, new_x)); op.changeVertex(*it, Vertex::F_Y, MakeValidCoord(inst.loaded.levelFormat, new_y)); } } void ObjectsModule::doScaleTwoStuff(EditOperation &op, const selection_c &list, transform_t& param) const { if (inst.edit.mode == ObjType::things) { doScaleTwoThings(op, list, param); return; } // everything else just modifies the vertices if (inst.edit.mode == ObjType::sectors) { // handle things in Sectors mode too selection_c things(ObjType::things); ConvertSelection(doc, list, things); doScaleTwoThings(op, things, param); } doScaleTwoVertices(op, list, param); } void ObjectsModule::transform(transform_t& param) const { // this is called by the MOUSE2 dynamic scaling code SYS_ASSERT(inst.edit.Selected->notempty()); EditOperation op(doc.basis); op.setMessageForSelection("scaled", *inst.edit.Selected); if (param.scale.x < 0) { param.scale.x = -param.scale.x; doMirrorStuff(op, *inst.edit.Selected, false /* is_vert */, param.mid.x, param.mid.y); } if (param.scale.y < 0) { param.scale.y = -param.scale.y; doMirrorStuff(op, *inst.edit.Selected, true /* is_vert */, param.mid.x, param.mid.y); } doScaleTwoStuff(op, *inst.edit.Selected, param); } void ObjectsModule::determineOrigin(transform_t& param, double pos_x, double pos_y) const { if (pos_x == 0 && pos_y == 0) { param.mid = doc.objects.calcMiddle(*inst.edit.Selected); return; } v2double_t lpos, hpos; doc.objects.calcBBox(*inst.edit.Selected, lpos, hpos); if (pos_x < 0) param.mid.x = lpos.x; else if (pos_x > 0) param.mid.x = hpos.x; else param.mid.x = lpos.x + (hpos.x - lpos.x) / 2; if (pos_y < 0) param.mid.y = lpos.y; else if (pos_y > 0) param.mid.y = hpos.y; else param.mid.y = lpos.y + (hpos.y - lpos.y) / 2; } void ObjectsModule::scale3(double scale_x, double scale_y, double pos_x, double pos_y) const { SYS_ASSERT(scale_x > 0); SYS_ASSERT(scale_y > 0); transform_t param; param.Clear(); param.scale.x = scale_x; param.scale.y = scale_y; determineOrigin(param, pos_x, pos_y); EditOperation op(doc.basis); op.setMessageForSelection("scaled", *inst.edit.Selected); { doScaleTwoStuff(op, *inst.edit.Selected, param); } } void ObjectsModule::doScaleSectorHeights(EditOperation &op, const selection_c &list, double scale_z, int pos_z) const { SYS_ASSERT(! list.empty()); // determine Z range and origin int lz = +99999; int hz = -99999; for (sel_iter_c it(list) ; !it.done() ; it.next()) { const auto S = doc.sectors[*it]; lz = std::min(lz, S->floorh); hz = std::max(hz, S->ceilh); } int mid_z; if (pos_z < 0) mid_z = lz; else if (pos_z > 0) mid_z = hz; else mid_z = lz + (hz - lz) / 2; // apply the scaling for (sel_iter_c it(list) ; !it.done() ; it.next()) { const auto S = doc.sectors[*it]; int new_f = mid_z + iround((S->floorh - mid_z) * scale_z); int new_c = mid_z + iround((S-> ceilh - mid_z) * scale_z); op.changeSector(*it, Sector::F_FLOORH, new_f); op.changeSector(*it, Sector::F_CEILH, new_c); } } void ObjectsModule::scale4(double scale_x, double scale_y, double scale_z, double pos_x, double pos_y, double pos_z) const { SYS_ASSERT(inst.edit.mode == ObjType::sectors); transform_t param; param.Clear(); param.scale.x = scale_x; param.scale.y = scale_y; determineOrigin(param, pos_x, pos_y); EditOperation op(doc.basis); op.setMessageForSelection("scaled", *inst.edit.Selected); { doScaleTwoStuff(op, *inst.edit.Selected, param); doScaleSectorHeights(op, *inst.edit.Selected, scale_z, static_cast(pos_z)); } } void ObjectsModule::rotate3(double deg, double pos_x, double pos_y) const { transform_t param; param.Clear(); param.rotate = deg * M_PI / 180.0; determineOrigin(param, pos_x, pos_y); EditOperation op(doc.basis); op.setMessageForSelection("rotated", *inst.edit.Selected); { doScaleTwoStuff(op, *inst.edit.Selected, param); } } bool ObjectsModule::spotInUse(ObjType obj_type, int x, int y) const { switch (obj_type) { case ObjType::things: for (const auto &thing : doc.things) if (iround(thing->x()) == x && iround(thing->y()) == y) return true; return false; case ObjType::vertices: for (const auto &vertex : doc.vertices) if (iround(vertex->x()) == x && iround(vertex->y()) == y) return true; return false; default: BugError("IsSpotVacant: bad object type\n"); return false; } } void ObjectsModule::doEnlargeOrShrink(bool do_shrink) const { // setup transform parameters... float mul = 2.0; if (inst.EXEC_Param[0].good()) { mul = static_cast(atof(inst.EXEC_Param[0])); if (mul < 0.02 || mul > 50) { inst.Beep("bad factor: %s", inst.EXEC_Param[0].c_str()); return; } } if (do_shrink) mul = 1.0f / mul; transform_t param; param.Clear(); param.scale = { mul, mul }; SelectHighlight unselect = inst.edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { inst.Beep("No objects to %s", do_shrink ? "shrink" : "enlarge"); return; } // TODO: CONFIG ITEM (or FLAG) if ((true)) { param.mid = calcMiddle(*inst.edit.Selected); } else { v2double_t lpos, hpos; calcBBox(*inst.edit.Selected, lpos, hpos); param.mid = lpos + (hpos - lpos) / 2; } { EditOperation op(doc.basis); op.setMessageForSelection(do_shrink ? "shrunk" : "enlarged", *inst.edit.Selected); doScaleTwoStuff(op, *inst.edit.Selected, param); } if (unselect == SelectHighlight::unselect) inst.Selection_Clear(true /* nosave */); } void Instance::CMD_Enlarge() { level.objects.doEnlargeOrShrink(false /* do_shrink */); } void Instance::CMD_Shrink() { level.objects.doEnlargeOrShrink(true /* do_shrink */); } void ObjectsModule::quantizeThings(EditOperation &op, selection_c &list) const { // remember the things which we moved // (since we cannot modify the selection while we iterate over it) selection_c moved(list.what_type()); for (sel_iter_c it(list) ; !it.done() ; it.next()) { const auto T = doc.things[*it]; if (inst.grid.OnGrid(T->x(), T->y())) { moved.set(*it); continue; } for (int pass = 0 ; pass < 4 ; pass++) { int new_x = inst.grid.QuantSnapX(T->x(), pass & 1); int new_y = inst.grid.QuantSnapY(T->y(), pass & 2); if (! spotInUse(ObjType::things, new_x, new_y)) { op.changeThing(*it, Thing::F_X, MakeValidCoord(inst.loaded.levelFormat, new_x)); op.changeThing(*it, Thing::F_Y, MakeValidCoord(inst.loaded.levelFormat, new_y)); moved.set(*it); break; } } } list.unmerge(moved); if (! list.empty()) inst.Beep("Quantize: could not move %d things", list.count_obj()); } void ObjectsModule::quantizeVertices(EditOperation &op, selection_c &list) const { // first : do an analysis pass, remember vertices that are part // of a horizontal or vertical line (and both in the selection) // and limit the movement of those vertices to ensure the lines // stay horizontal or vertical. enum { V_HORIZ = (1 << 0), V_VERT = (1 << 1), V_DIAG_NE = (1 << 2), V_DIAG_SE = (1 << 3) }; byte * vert_modes = new byte[doc.numVertices()]; for (const auto &L : doc.linedefs) { // require both vertices of the linedef to be in the selection if (! (list.get(L->start) && list.get(L->end))) continue; // IDEA: make this a method of LineDef double x1 = doc.getStart(*L).x(); double y1 = doc.getStart(*L).y(); double x2 = doc.getEnd(*L).x(); double y2 = doc.getEnd(*L).y(); if (doc.isHorizontal(*L)) { vert_modes[L->start] |= V_HORIZ; vert_modes[L->end] |= V_HORIZ; } else if (doc.isVertical(*L)) { vert_modes[L->start] |= V_VERT; vert_modes[L->end] |= V_VERT; } else if ((x1 < x2 && y1 < y2) || (x1 > x2 && y1 > y2)) { vert_modes[L->start] |= V_DIAG_NE; vert_modes[L->end] |= V_DIAG_NE; } else { vert_modes[L->start] |= V_DIAG_SE; vert_modes[L->end] |= V_DIAG_SE; } } // remember the vertices which we moved // (since we cannot modify the selection while we iterate over it) selection_c moved(list.what_type()); for (sel_iter_c it(list) ; !it.done() ; it.next()) { const auto V = doc.vertices[*it]; if (inst.grid.OnGrid(V->x(), V->y())) { moved.set(*it); continue; } byte mode = vert_modes[*it]; for (int pass = 0 ; pass < 4 ; pass++) { int x_dir, y_dir; double new_x = inst.grid.QuantSnapX(V->x(), pass & 1, &x_dir); double new_y = inst.grid.QuantSnapY(V->y(), pass & 2, &y_dir); // keep horizontal lines horizontal if ((mode & V_HORIZ) && (pass & 2)) continue; // keep vertical lines vertical if ((mode & V_VERT) && (pass & 1)) continue; // TODO: keep diagonal lines diagonal... if (! spotInUse(ObjType::vertices, static_cast(new_x), static_cast(new_y))) { op.changeVertex(*it, Vertex::F_X, MakeValidCoord(inst.loaded.levelFormat, new_x)); op.changeVertex(*it, Vertex::F_Y, MakeValidCoord(inst.loaded.levelFormat, new_y)); moved.set(*it); break; } } } delete[] vert_modes; list.unmerge(moved); if (list.notempty()) inst.Beep("Quantize: could not move %d vertices", list.count_obj()); } void Instance::CMD_Quantize() { if (edit.Selected->empty()) { if (edit.highlight.is_nil()) { Beep("Nothing to quantize"); return; } edit.Selection_AddHighlighted(); } { EditOperation op(level.basis); op.setMessageForSelection("quantized", *edit.Selected); switch (edit.mode) { case ObjType::things: level.objects.quantizeThings(op, *edit.Selected); break; case ObjType::vertices: level.objects.quantizeVertices(op, *edit.Selected); break; // everything else merely quantizes vertices default: { selection_c verts(ObjType::vertices); ConvertSelection(level, *edit.Selected, verts); level.objects.quantizeVertices(op, verts); Selection_Clear(); break; } } } edit.error_mode = true; } // // Get the tag info here. Returns true if available and sets the output argument. // bool getSpecialTagInfo(ObjType objtype, int objnum, int special, const void *obj, const ConfigData &config, SpecialTagInfo &info) { if(special <= 0) return false; auto getArg = [objtype, obj](int index) { if(objtype == ObjType::things) return static_cast(obj)->Arg(index); if(objtype == ObjType::linedefs) return static_cast(obj)->Arg(index); return 0; }; // First try generalized for(int i = 0; i < config.num_gen_linetypes; ++i) { const generalized_linetype_t &type = config.gen_linetypes[i]; if(special >= type.base && special < type.base + type.length) { info = {}; info.type = objtype; info.objnum = objnum; info.numtags = 1; info.tags[0] = getArg(1); return true; } } // Now try individual specials, including parameterized auto it = config.line_types.find(special); if(it == config.line_types.end()) return false; info = {}; info.type = objtype; info.objnum = objnum; for(int i = 0; i < (int)lengthof(it->second.args); ++i) { int arg = getArg(i + 1); switch(it->second.args[i].type) { case SpecialArgType::tag: info.tags[info.numtags++] = arg; break; case SpecialArgType::tag_hi: info.tags[info.hitags++] += 256 * arg; // add 256*i to corresponding regular tag break; case SpecialArgType::tid: info.tids[info.numtids++] = arg; break; case SpecialArgType::line_id: info.lineids[info.numlineids++] = arg; break; case SpecialArgType::self_line_id: info.selflineid = arg; break; case SpecialArgType::self_line_id_hi: info.selflineid += 256 * arg; break; case SpecialArgType::po: info.po[info.numpo++] = arg; break; default: break; } } return true; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_objects.h000066400000000000000000000132411464327712600204370ustar00rootroot00000000000000//------------------------------------------------------------------------ // OBJECT STUFF //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_OBJECTS_H__ #define __EUREKA_OBJECTS_H__ #include "DocumentModule.h" #include "m_vector.h" #include "objid.h" class EditOperation; class selection_c; struct ConfigData; struct transform_t { public: v2double_t mid; v2double_t scale; v2double_t skew; double rotate; // radians public: void Clear(); void Apply(double *x, double *y) const; }; // // e_objects module // class ObjectsModule : public DocumentModule { friend class Instance; public: explicit ObjectsModule(Document &doc) : DocumentModule(doc) { } void move(const selection_c &list, const v3double_t &delta) const; void singleDrag(const Objid &obj, const v3double_t &delta) const; void del(EditOperation &op, const selection_c &list) const; bool lineTouchesBox(int ld, double x0, double y0, double x1, double y1) const; v2double_t getDragFocus(const v2double_t &ptr) const; v2double_t calcMiddle(const selection_c &list) const; void calcBBox(const selection_c &list, v2double_t &pos1, v2double_t &pos2) const; void transform(transform_t ¶m) const; void scale3(double scale_x, double scale_y, double pos_x, double pos_y) const; void scale4(double scale_x, double scale_y, double scale_z, double pos_x, double pos_y, double pos_z) const; void rotate3(double deg, double pos_x, double pos_y) const; int findLineBetweenLineAndVertex(int lineID, int vertID) const; void splitLinedefAndMergeSandwich(EditOperation &op, int splitLineID, int vertID, const v2double_t &delta, selection_c *delResultList) const; private: void insertSector() const; void createSquare(EditOperation &op, int model) const; void insertThing() const; void insertVertex(bool force_continue, bool no_fill) const; void insertLinedefAutosplit(EditOperation &op, int v1, int v2, bool no_fill) const; void insertLinedef(EditOperation &op, int v1, int v2, bool no_fill) const; bool checkClosedLoop(EditOperation &op, int new_ld, int v1, int v2, selection_c &flip) const; int sectorNew(EditOperation &op, int model, int model2, int model3) const; void doMoveObjects(EditOperation &op, const selection_c &list, const v3double_t &delta) const; void transferThingProperties(EditOperation &op, int src_thing, int dest_thing) const; void transferSectorProperties(EditOperation &op, int src_sec, int dest_sec) const; void transferLinedefProperties(EditOperation &op, int src_line, int dest_line, bool do_tex) const; void dragCountOnGrid(int *count, int *total) const; void dragCountOnGridWorker(ObjType obj_type, int objnum, int *count, int *total) const; void dragUpdateCurrentDist(ObjType obj_type, int objnum, double *x, double *y, double *best_dist, double ptr_x, double ptr_y, bool only_grid) const; void doMirrorThings(EditOperation &op, const selection_c &list, bool is_vert, double mid_x, double mid_y) const; void doMirrorStuff(EditOperation &op, const selection_c &list, bool is_vert, double mid_x, double mid_y) const; void doMirrorVertices(EditOperation &op, const selection_c &list, bool is_vert, double mid_x, double mid_y) const; void doRotate90Things(EditOperation &op, const selection_c &list, bool anti_clockwise, double mid_x, double mid_y) const; void doEnlargeOrShrink(bool do_shrink) const; void doScaleTwoThings(EditOperation &op, const selection_c &list, transform_t ¶m) const; void doScaleTwoStuff(EditOperation &op, const selection_c &list, transform_t ¶m) const; void doScaleTwoVertices(EditOperation &op, const selection_c &list, transform_t ¶m) const; void determineOrigin(transform_t ¶m, double pos_x, double pos_y) const; void doScaleSectorHeights(EditOperation &op, const selection_c &list, double scale_z, int pos_z) const; void quantizeThings(EditOperation &op, selection_c &list) const; void quantizeVertices(EditOperation &op, selection_c &list) const; bool spotInUse(ObjType obj_type, int x, int y) const; }; enum transform_keyword_e { TRANS_K_Scale = 0, // scale and keep aspect TRANS_K_Stretch, // scale X and Y independently TRANS_K_Rotate, // rotate TRANS_K_RotScale, // rotate and scale at same time TRANS_K_Skew // skew (shear) along an axis }; // // Information gathered from a linedef with a special // struct SpecialTagInfo { ObjType type; int objnum; int tags[5]; int numtags = 0; int hitags = 0; int tids[5]; int numtids = 0; int lineids[5]; int numlineids = 0; int selflineid = 0; int po[5]; int numpo = 0; }; bool getSpecialTagInfo(ObjType objtype, int objnum, int special, const void *obj, const ConfigData &config, SpecialTagInfo &info); #endif /* __EUREKA_OBJECTS_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_path.cc000066400000000000000000000333321464327712600201030ustar00rootroot00000000000000//------------------------------------------------------------------------ // LINEDEF PATHS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include "LineDef.h" #include "m_bitvec.h" #include "e_main.h" #include "e_objects.h" #include "e_path.h" #include "m_game.h" #include "r_grid.h" #include "r_render.h" #include "Sector.h" #include "w_rawdef.h" #include "ui_window.h" #include "ui_misc.h" #include typedef enum { SLP_Normal = 0, SLP_SameTex = (1 << 1), // require lines have same textures SLP_OneSided = (1 << 2), // only handle one-sided lines } select_lines_in_path_flag_e; static bool MatchingTextures(const Document &doc, int index1, int index2) { const auto L1 = doc.linedefs[index1]; const auto L2 = doc.linedefs[index2]; // lines with no sidedefs only match each other if (! doc.getRight(*L1) || ! doc.getRight(*L2)) return doc.getRight(*L1) == doc.getRight(*L2); // determine texture to match from first line StringID texture; if (! L1->TwoSided()) { texture = doc.getRight(*L1)->mid_tex; } else { int f_diff = doc.getSector(*doc.getLeft(*L1)).floorh - doc.getSector(*doc.getRight(*L1)).floorh; int c_diff = doc.getSector(*doc.getLeft(*L1)).ceilh - doc.getSector(*doc.getRight(*L1)).ceilh; if (f_diff == 0 && c_diff != 0) texture = (c_diff > 0) ? doc.getLeft(*L1)->upper_tex : doc.getRight(*L1)->upper_tex; else texture = (f_diff < 0) ? doc.getLeft(*L1)->lower_tex : doc.getRight(*L1)->lower_tex; } // match texture with other line if (! L2->TwoSided()) { return (doc.getRight(*L2)->mid_tex == texture); } else { int f_diff = doc.getSector(*doc.getLeft(*L2)).floorh - doc.getSector(*doc.getRight(*L2)).floorh; int c_diff = doc.getSector(*doc.getLeft(*L2)).ceilh - doc.getSector(*doc.getRight(*L2)).ceilh; if (c_diff != 0) if (texture == ((c_diff > 0) ? doc.getLeft(*L2)->upper_tex : doc.getRight(*L2)->upper_tex)) return true; if (f_diff != 0) if (texture == ((f_diff < 0) ? doc.getLeft(*L2)->lower_tex : doc.getRight(*L2)->lower_tex)) return true; return false; } } static bool OtherLineDef(const Document &doc, int L, int V, int *L_other, int *V_other, int match, int start_L) { *L_other = -1; *V_other = -1; for (int n = 0 ; n < doc.numLinedefs(); n++) { if (n == L) continue; if ((match & SLP_OneSided) && !doc.linedefs[n]->OneSided()) continue; for (int k = 0 ; k < 2 ; k++) { int v1 = doc.linedefs[n]->start; int v2 = doc.linedefs[n]->end; if (k == 1) std::swap(v1, v2); if (v1 != V) continue; if ((match & SLP_SameTex) && ! MatchingTextures(doc, start_L, n)) continue; if (*L_other >= 0) // There is a fork in the path. Stop here. return false; *L_other = n; *V_other = v2; } } return (*L_other >= 0); } // // This routine looks for all linedefs other than 'L' which use // the vertex 'V'. If there are none or more than one, the search // stops there and nothing else happens. If there is exactly one, // then it is added to the selection and we continue from the new // linedef and vertex. // static void SelectLinesInHalfPath(const Document &doc, int L, int V, selection_c& seen, int match) { int start_L = L; for (;;) { int L_other, V_other; // does not exist or is forky if (! OtherLineDef(doc, L, V, &L_other, &V_other, match, start_L)) break; // already seen? if (seen.get(L_other)) break; seen.set(L_other); L = L_other; V = V_other; } } // // select/unselect all linedefs in a non-forked path. // void Instance::CMD_LIN_SelectPath() { // determine starting linedef if (edit.highlight.is_nil()) { Beep("No highlighted line"); return; } bool fresh_sel = Exec_HasFlag("/fresh"); int match = 0; if (Exec_HasFlag("/onesided")) match |= SLP_OneSided; if (Exec_HasFlag("/sametex")) match |= SLP_SameTex; int start_L = edit.highlight.num; if ((match & SLP_OneSided) && !level.linedefs[start_L]->OneSided()) return; bool unset_them = false; if (!fresh_sel && edit.Selected->get(start_L)) unset_them = true; selection_c seen(ObjType::linedefs); seen.set(start_L); SelectLinesInHalfPath(level, start_L, level.linedefs[start_L]->start, seen, match); SelectLinesInHalfPath(level, start_L, level.linedefs[start_L]->end, seen, match); Editor_ClearErrorMode(); if (fresh_sel) Selection_Clear(); if (unset_them) edit.Selected->unmerge(seen); else edit.Selected->merge(seen); RedrawMap(); } //------------------------------------------------------------------------ #define PLAYER_STEP_H 24 static bool GrowContiguousSectors(const Instance &inst, selection_c &seen) { // returns TRUE when some new sectors got added bool changed = false; bool can_walk = inst.Exec_HasFlag("/can_walk"); bool allow_doors = inst.Exec_HasFlag("/doors"); bool do_floor_h = inst.Exec_HasFlag("/floor_h"); bool do_floor_tex = inst.Exec_HasFlag("/floor_tex"); bool do_ceil_h = inst.Exec_HasFlag("/ceil_h"); bool do_ceil_tex = inst.Exec_HasFlag("/ceil_tex"); bool do_light = inst.Exec_HasFlag("/light"); bool do_tag = inst.Exec_HasFlag("/tag"); bool do_special = inst.Exec_HasFlag("/special"); for (const auto &L : inst.level.linedefs) { if (! L->TwoSided()) continue; int sec1 = inst.level.getRight(*L)->sector; int sec2 = inst.level.getLeft(*L)->sector; if (sec1 == sec2) continue; const auto S1 = inst.level.sectors[sec1]; const auto S2 = inst.level.sectors[sec2]; // skip closed doors if (! allow_doors && (S1->floorh >= S1->ceilh || S2->floorh >= S2->ceilh)) continue; if (can_walk) { if (L->flags & MLF_Blocking) continue; // too big a step? if (abs(S1->floorh - S2->floorh) > PLAYER_STEP_H) continue; // player wouldn't fit vertically? int f_max = std::max(S1->floorh, S2->floorh); int c_min = std::min(S1-> ceilh, S2-> ceilh); if (c_min - f_max < inst.conf.miscInfo.player_h) { // ... but allow doors if (! (allow_doors && (S1->floorh == S1->ceilh || S2->floorh == S2->ceilh))) continue; } } /* perform match */ if (do_floor_h && (S1->floorh != S2->floorh)) continue; if (do_ceil_h && (S1->ceilh != S2->ceilh)) continue; if (do_floor_tex && (S1->floor_tex != S2->floor_tex)) continue; if (do_ceil_tex && (S1->ceil_tex != S2->ceil_tex)) continue; if (do_light && (S1->light != S2->light)) continue; if (do_tag && (S1->tag != S2->tag )) continue; if (do_special && (S1->type != S2->type)) continue; // check if only one of the sectors is part of current set // (doing this _AFTER_ the matches since this can be a bit slow) bool got1 = seen.get(sec1); bool got2 = seen.get(sec2); if (got1 == got2) continue; seen.set(got1 ? sec2 : sec1); changed = true; } return changed; } // // select/unselect a contiguous group of sectors. // void Instance::CMD_SEC_SelectGroup() { // determine starting sector if (edit.highlight.is_nil()) { Beep("No highlighted sector"); return; } bool fresh_sel = Exec_HasFlag("/fresh"); int start_sec = edit.highlight.num; bool unset_them = false; if (!fresh_sel && edit.Selected->get(start_sec)) unset_them = true; selection_c seen(ObjType::sectors); seen.set(start_sec); while (GrowContiguousSectors(*this, seen)) { } Editor_ClearErrorMode(); if (fresh_sel) Selection_Clear(); if (unset_them) edit.Selected->unmerge(seen); else edit.Selected->merge(seen); RedrawMap(); } //------------------------------------------------------------------------ void Instance::GoToSelection() { if (edit.render3d) Render3D_Enable(*this, false); v2double_t pos1, pos2; level.objects.calcBBox(*edit.Selected, pos1, pos2); v2double_t mid = (pos1 + pos2) / 2; grid.MoveTo(mid); // zoom out until selected objects fit on screen for (int loop = 0 ; loop < 30 ; loop++) { int eval = main_win->canvas->ApproxBoxSize(static_cast(pos1.x), static_cast(pos1.y), static_cast(pos2.x), static_cast(pos2.y)); if (eval <= 0) break; grid.AdjustScale(-1); } // zoom in when bbox is very small (say < 20% of window) for (int loop = 0 ; loop < 30 ; loop++) { if (grid.getScale() >= 1.0) break; int eval = main_win->canvas->ApproxBoxSize(static_cast(pos1.x), static_cast(pos1.y), static_cast(pos2.x), static_cast(pos2.y)); if (eval >= 0) break; grid.AdjustScale(+1); } RedrawMap(); } void Instance::GoToErrors() { edit.error_mode = true; GoToSelection(); } // // centre the map around the object and zoom in if necessary // void Instance::GoToObject(const Objid& objid) { Selection_Clear(); edit.Selected->set(objid.num); GoToSelection(); } // // Allow going to multiple objects // void goToMultipleObjects(Instance &inst, const std::vector &items) { inst.Selection_Clear(); for(int index : items) inst.edit.Selected->set(index); inst.GoToSelection(); } void Instance::CMD_JumpToObject() { int total = level.numObjects(edit.mode); if (total <= 0) { Beep("No objects!"); return; } std::vector nums; { auto dialog = std::make_unique(NameForObjectType(edit.mode), total - 1); nums = dialog->Run(); } if (nums.empty()) // cancelled return; // this is guaranteed by the dialog for(int num : nums) { (void)num; assert(num >= 0 && num < total); } goToMultipleObjects(*this, nums); } void Instance::CMD_PruneUnused() { selection_c used_secs (ObjType::sectors); selection_c used_sides(ObjType::sidedefs); selection_c used_verts(ObjType::vertices); for (const auto &L : level.linedefs) { used_verts.set(L->start); used_verts.set(L->end); if (L->left >= 0) { used_sides.set(L->left); used_secs.set(level.getLeft(*L)->sector); } if (L->right >= 0) { used_sides.set(L->right); used_secs.set(level.getRight(*L)->sector); } } used_secs .frob_range(0, level.numSectors() -1, BitOp::toggle); used_sides.frob_range(0, level.numSidedefs() -1, BitOp::toggle); used_verts.frob_range(0, level.numVertices()-1, BitOp::toggle); int num_secs = used_secs .count_obj(); int num_sides = used_sides.count_obj(); int num_verts = used_verts.count_obj(); if (num_verts == 0 && num_sides == 0 && num_secs == 0) { Beep("Nothing to prune"); return; } EditOperation op(level.basis); op.setMessage("pruned %d objects", num_secs + num_sides + num_verts); level.objects.del(op, used_sides); level.objects.del(op, used_secs); level.objects.del(op, used_verts); } //------------------------------------------------------------------------ static void CalcPropagation(const Instance &inst, std::vector& vec, bool ignore_doors) { bool changes; for (int k = 0 ; k < inst.level.numSectors(); k++) vec[k] = 0; vec[inst.sound_start_sec] = 2; do { changes = false; for (const auto &L : inst.level.linedefs) { if (! L->TwoSided()) continue; int sec1 = inst.level.getSectorID(*L, Side::right); int sec2 = inst.level.getSectorID(*L, Side::left); SYS_ASSERT(sec1 >= 0); SYS_ASSERT(sec2 >= 0); // check for doors if (!ignore_doors && (std::min(inst.level.sectors[sec1]->ceilh, inst.level.sectors[sec2]->ceilh) <= std::max(inst.level.sectors[sec1]->floorh, inst.level.sectors[sec2]->floorh))) { continue; } int val1 = vec[sec1]; int val2 = vec[sec2]; int new_val = std::max(val1, val2); if (L->flags & MLF_SoundBlock) new_val -= 1; if (new_val > val1 || new_val > val2) { if (new_val > val1) vec[sec1] = static_cast(new_val); if (new_val > val2) vec[sec2] = static_cast(new_val); changes = true; } } } while (changes); } static void CalcFinalPropagation(Instance &inst) { for (int s = 0 ; s < inst.level.numSectors(); s++) { int t1 = inst.sound_temp1_vec[s]; int t2 = inst.sound_temp2_vec[s]; if (t1 != t2) { if (t1 == 0 || t2 == 0) { inst.sound_prop_vec[s] = PGL_Maybe; continue; } t1 = std::min(t1, t2); } switch (t1) { case 0: inst.sound_prop_vec[s] = PGL_Never; break; case 1: inst.sound_prop_vec[s] = PGL_Level_1; break; case 2: inst.sound_prop_vec[s] = PGL_Level_2; break; } } } const byte *Instance::SoundPropagation(int start_sec) { if ((int)sound_prop_vec.size() != level.numSectors()) { sound_prop_vec .resize(level.numSectors()); sound_temp1_vec.resize(level.numSectors()); sound_temp2_vec.resize(level.numSectors()); sound_propagation_invalid = true; } if (sound_propagation_invalid || sound_start_sec != start_sec) { // cannot used cached data, recompute it sound_start_sec = start_sec; sound_propagation_invalid = false; CalcPropagation(*this, sound_temp1_vec, false); CalcPropagation(*this, sound_temp2_vec, true); CalcFinalPropagation(*this); } return &sound_prop_vec[0]; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_path.h000066400000000000000000000026401464327712600177430ustar00rootroot00000000000000//------------------------------------------------------------------------ // LINEDEF PATHS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_E_PATH_H__ #define __EUREKA_E_PATH_H__ enum propagate_level_e { PGL_Never = 0, // can never be heared PGL_Maybe, // a possibility of being heared PGL_Level_1, // reduced by a single level PGL_Level_2 // no blocking at all }; #endif /* __EUREKA_E_PATH_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_sector.cc000066400000000000000000000656131464327712600204550ustar00rootroot00000000000000//------------------------------------------------------------------------ // SECTOR STUFF //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2017 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include #include "LineDef.h" #include "m_bitvec.h" #include "Sector.h" #include "SideDef.h" #include "w_rawdef.h" #include "e_cutpaste.h" #include "e_hover.h" #include "e_linedef.h" #include "e_main.h" #include "e_objects.h" #include "e_sector.h" #include "e_vertex.h" #include "Vertex.h" #include "ui_window.h" // this function ensures that sector won't get floor > ceil void SectorModule::safeRaiseLower(EditOperation &op, int sec, int parts, int dz) const { if (parts == 0) parts = PART_FLOOR | PART_CEIL; int f = doc.sectors[sec]->floorh; int c = doc.sectors[sec]->ceilh; if ((parts & PART_FLOOR) != 0 && (parts & PART_CEIL) != 0) { f += dz; c += dz; // this won't usually happen, only if original sector was bad if (f > c) f = c; } else if (parts & PART_FLOOR) { f += dz; if (f > c) f = c; } else if (parts & PART_CEIL) { c += dz; if (c < f) c = f; } if (parts & PART_FLOOR) op.changeSector(sec, Sector::F_FLOORH, f); if (parts & PART_CEIL) op.changeSector(sec, Sector::F_CEILH, c); } void Instance::CMD_SEC_Floor() { int diff = atoi(EXEC_Param[0]); if (diff == 0) { Beep("SEC_Floor: bad parameter '%s'", EXEC_Param[0].c_str()); return; } SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { Beep("No sectors to move"); return; } { EditOperation op(level.basis); op.setMessageForSelection(diff < 0 ? "lowered floor of" : "raised floor of", *edit.Selected); for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { const auto S = level.sectors[*it]; int new_h = clamp(-32767, S->floorh + diff, S->ceilh); op.changeSector(*it, Sector::F_FLOORH, new_h); } } main_win->sec_box->UpdateField(Sector::F_FLOORH); if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); } void Instance::CMD_SEC_Ceil() { int diff = atoi(EXEC_Param[0]); if (diff == 0) { Beep("SEC_Ceil: bad parameter '%s'", EXEC_Param[0].c_str()); return; } SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { Beep("No sectors to move"); return; } { EditOperation op(level.basis); op.setMessageForSelection(diff < 0 ? "lowered ceil of" : "raised ceil of", *edit.Selected); for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { const auto S = level.sectors[*it]; int new_h = clamp(S->floorh, S->ceilh + diff, 32767); op.changeSector(*it, Sector::F_CEILH, new_h); } } main_win->sec_box->UpdateField(Sector::F_CEILH); if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); } static int light_add_delta(int level, int delta) { // NOTE: delta is assumed to be a power of two if (abs(delta) <= 1) { level += delta; } else if (delta > 0) { level = (level | (delta-1)) + 1; } else { level = (level - 1) & ~(abs(delta)-1); } return clamp(0, level, 255); } void SectorModule::sectorsAdjustLight(int delta) const { // this uses the current selection (caller must set it up) if (inst.edit.Selected->empty()) return; { EditOperation op(doc.basis); op.setMessageForSelection(delta < 0 ? "darkened" : "brightened", *inst.edit.Selected); for (sel_iter_c it(*inst.edit.Selected) ; !it.done() ; it.next()) { const auto S = doc.sectors[*it]; int new_lt = light_add_delta(S->light, delta); op.changeSector(*it, Sector::F_LIGHT, new_lt); } } inst.main_win->sec_box->UpdateField(Sector::F_LIGHT); } void Instance::CMD_SEC_Light() { int diff = atoi(EXEC_Param[0]); if (diff == 0) { Beep("SEC_Light: bad parameter '%s'", EXEC_Param[0].c_str()); return; } SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { Beep("No sectors to adjust light"); return; } level.secmod.sectorsAdjustLight(diff); if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); } void Instance::CMD_SEC_SwapFlats() { SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { Beep("No sectors to swap"); return; } { EditOperation op(level.basis); op.setMessageForSelection("swapped flats in", *edit.Selected); for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { const auto S = level.sectors[*it]; StringID floor_tex = S->floor_tex; StringID ceil_tex = S->ceil_tex; op.changeSector(*it, Sector::F_FLOOR_TEX, ceil_tex); op.changeSector(*it, Sector::F_CEIL_TEX, floor_tex); } } main_win->sec_box->UpdateField(Sector::F_FLOOR_TEX); main_win->sec_box->UpdateField(Sector::F_CEIL_TEX); if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); } void SectorModule::linedefsBetweenSectors(selection_c *list, int sec1, int sec2) const { for (int i = 0 ; i < doc.numLinedefs() ; i++) { const auto L = doc.linedefs[i]; if (! (doc.getLeft(*L) && doc.getRight(*L))) continue; if ((doc.getLeft(*L)->sector == sec1 && doc.getRight(*L)->sector == sec2) || (doc.getLeft(*L)->sector == sec2 && doc.getRight(*L)->sector == sec1)) { list->set(i); } } } void SectorModule::replaceSectorRefs(EditOperation &op, int old_sec, int new_sec) const { for (int i = 0 ; i < doc.numSidedefs() ; i++) { const auto sd = doc.sidedefs[i]; if (sd->sector == old_sec) { op.changeSidedef(i, SideDef::F_SECTOR, new_sec); } } } void Instance::commandSectorMerge() { // need a selection if (edit.Selected->count_obj() == 1 && edit.highlight.valid()) { edit.Selection_AddHighlighted(); } if (edit.Selected->count_obj() < 2) { Beep("Need 2 or more sectors to merge"); return; } int first = edit.Selected->find_first(); bool keep_common_lines = Exec_HasFlag("/keep"); // we require the *lowest* numbered sector, otherwise we can // select the wrong sector afterwards (due to renumbering). int new_sec = edit.Selected->max_obj(); for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { new_sec = std::min(new_sec, *it); } selection_c common_lines(ObjType::linedefs); selection_c unused_secs (ObjType::sectors); { EditOperation op(level.basis); op.setMessageForSelection("merged", *edit.Selected); // keep the properties of the first selected sector if (new_sec != first) { const auto ref = level.sectors[first]; op.changeSector(new_sec, Sector::F_FLOORH, ref->floorh); op.changeSector(new_sec, Sector::F_FLOOR_TEX, ref->floor_tex); op.changeSector(new_sec, Sector::F_CEILH, ref->ceilh); op.changeSector(new_sec, Sector::F_CEIL_TEX, ref->ceil_tex); op.changeSector(new_sec, Sector::F_LIGHT, ref->light); op.changeSector(new_sec, Sector::F_TYPE, ref->type); op.changeSector(new_sec, Sector::F_TAG, ref->tag); } for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { int old_sec = *it; if (old_sec == new_sec) continue; level.secmod.linedefsBetweenSectors(&common_lines, old_sec, new_sec); level.secmod.replaceSectorRefs(op, old_sec, new_sec); unused_secs.set(old_sec); } level.objects.del(op, unused_secs); if (! keep_common_lines) { DeleteObjects_WithUnused(op, level, common_lines, false, false, false); } } // re-select the final sector Selection_Clear(true /* no_save */); edit.Selected->set(new_sec); } //------------------------------------------------------------------------ // #define DEBUG_LINELOOP 1 void lineloop_c::clear() { lines.clear(); sides.clear(); faces_outward = false; for (unsigned int i = 0 ; i < islands.size() ; i++) delete islands[i]; islands.clear(); } void lineloop_c::push_back(int ld, Side side) { lines.push_back(ld); sides.push_back(side); } bool lineloop_c::get(int ld, Side side) const { for (unsigned int k = 0 ; k < lines.size() ; k++) if (lines[k] == ld && sides[k] == side) return true; for (unsigned int i = 0 ; i < islands.size() ; i++) if (islands[i]->get(ld, side)) return true; return false; } bool lineloop_c::get_just_line(int ld) const { for (unsigned int k = 0 ; k < lines.size() ; k++) if (lines[k] == ld) return true; for (unsigned int i = 0 ; i < islands.size() ; i++) if (islands[i]->get_just_line(ld)) return true; return false; } double lineloop_c::TotalLength() const { // NOTE: does NOT include islands double result = 0; for (unsigned int k = 0 ; k < lines.size() ; k++) { const auto L = doc.linedefs[lines[k]]; result += doc.calcLength(*L); } return result; } bool lineloop_c::SameSector(int *sec_num) const { // NOTE: does NOT include islands SYS_ASSERT(lines.size() > 0); int sec = doc.getSectorID(*doc.linedefs[lines[0]], sides[0]); for (unsigned int k = 0 ; k < lines.size() ; k++) { if (sec != doc.getSectorID(*doc.linedefs[lines[k]], sides[k])) return false; } if (sec_num) *sec_num = sec; return true; } bool lineloop_c::AllBare() const { int sec_num; if (! SameSector(&sec_num)) return false; return (sec_num < 0); } int lineloop_c::NeighboringSector() const { // pick the longest linedef with a sector on the other side // NOTE: it does not make sense to handle islands here. int best = -1; double best_len = -1; for (unsigned int i = 0 ; i < lines.size() ; i++) { const auto L = doc.linedefs[lines[i]]; // we assume here that SIDE_RIGHT == 0 - SIDE_LEFT int sec = doc.getSectorID(*doc.linedefs[lines[i]], - sides[i]); if (sec < 0) continue; double len = doc.calcLength(*L); if (len > best_len) { best = sec; best_len = len; } } return best; } int lineloop_c::IslandSector() const { // test is only valid for islands if (! faces_outward) return -1; // we might need to check multiple lines, as the first line could // be facing a linedef which is ALSO part of the island. for (unsigned int i = 0 ; i < lines.size() ; i++) { Side opp_side; int opp_ld = doc.hover.getOppositeLinedef(lines[i], sides[i], &opp_side, nullptr, nullptr); // can see "the void" ? // this means the geometry around here is broken, but for // the usages of this method we can ignore it. if (opp_ld < 0) continue; // part of the island itself? if (get_just_line(opp_ld)) continue; return doc.getSectorID(*doc.linedefs[opp_ld], opp_side); } return -1; } int lineloop_c::DetermineSector() const { if (faces_outward) return IslandSector(); for (unsigned int k = 0 ; k < lines.size() ; k++) { int sec = doc.getSectorID(*doc.linedefs[lines[k]], sides[k]); if (sec >= 0) return sec; } return -1; // VOID } void lineloop_c::CalcBounds(double *x1, double *y1, double *x2, double *y2) const { SYS_ASSERT(lines.size() > 0); *x1 = +9e9; *y1 = +9e9; *x2 = -9e9; *y2 = -9e9; for (unsigned int i = 0 ; i < lines.size() ; i++) { const auto L = doc.linedefs[lines[i]]; *x1 = std::min(*x1, std::min(doc.getStart(*L).x(), doc.getEnd(*L).x())); *y1 = std::min(*y1, std::min(doc.getStart(*L).y(), doc.getEnd(*L).y())); *x2 = std::max(*x2, std::max(doc.getStart(*L).x(), doc.getEnd(*L).x())); *y2 = std::max(*y2, std::max(doc.getStart(*L).y(), doc.getEnd(*L).y())); } } void lineloop_c::GetAllSectors(selection_c *list) const { // assumes the given selection is empty (this adds to it) for (unsigned int k = 0 ; k < lines.size() ; k++) { int sec = doc.getSectorID(*doc.linedefs[lines[k]], sides[k]); if (sec >= 0) list->set(sec); } for (unsigned int i = 0 ; i < islands.size() ; i++) { islands[i]->GetAllSectors(list); } } // // Follows the path clockwise from the given start line, adding each // line into the appropriate set. Returns true if the path was closed, // or false for failure (in which case the lineloop_c object will not // be in a valid state). // // side is either SIDE_LEFT or SIDE_RIGHT. // // -AJA- 2001-05-09 // bool SectorModule::traceLineLoop(int ld, Side side, lineloop_c& loop, bool ignore_bare) const { int start_ld = ld; Side start_side = side; loop.clear(); int cur_vert; int prev_vert; if (side == Side::right) { cur_vert = doc.linedefs[ld]->end; prev_vert = doc.linedefs[ld]->start; } else { cur_vert = doc.linedefs[ld]->start; prev_vert = doc.linedefs[ld]->end; } #ifdef DEBUG_LINELOOP gLog.debugPrintf("TRACE PATH: line:%d side:%d cur_vert:%d\n", ld, side, cur_vert); #endif // check for an isolated line if (doc.vertmod.howManyLinedefs( cur_vert) == 1 && doc.vertmod.howManyLinedefs(prev_vert) == 1) return false; // compute the average angle over all the lines double average_angle = 0; for (;;) { loop.push_back(ld, side); int next_line = -1; int next_vert = -1; Side next_side = Side::neither; double best_angle = 9999; // look for the next linedef in the path, one using the // current vertex and having the smallest interior angle. // it *can* be the exact same linedef (when hitting a dangling // vertex). for (int n = 0 ; n < doc.numLinedefs() ; n++) { const auto N = doc.linedefs[n]; if (! N->TouchesVertex(cur_vert)) continue; if (ignore_bare && !doc.getLeft(*N) && !doc.getRight(*N)) continue; int other_vert; Side which_side; if (N->start == cur_vert) { other_vert = N->end; which_side = Side::right; } else /* (N->end == cur_vert) */ { other_vert = N->start; which_side = Side::left; } double angle; if (n == ld) angle = 361.0; else angle = doc.linemod.angleBetweenLines(prev_vert, cur_vert, other_vert); if (next_line < 0 || angle < best_angle) { next_line = n; next_vert = other_vert; next_side = which_side; best_angle = angle; } } #ifdef DEBUG_LINELOOP gLog.debugPrintf("PATH NEXT: line:%d side:%d vert:%d angle:%1.6f\n", next_line, next_side, next_vert, best_angle); #endif // no next line? path cannot be closed if (next_line < 0) return false; // we have come back to the start, so terminate if (next_line == start_ld && next_side == start_side) break; // this won't happen under normal circumstances, but it *can* // happen and indicates a non-closed structure. if (loop.get(next_line, next_side)) return false; // OK ld = next_line; side = next_side; prev_vert = cur_vert; cur_vert = next_vert; average_angle += best_angle; } // this might happen if there are overlapping linedefs if (loop.lines.size() < 3) return false; average_angle = average_angle / (double)loop.lines.size(); loop.faces_outward = (average_angle >= 180.0); #ifdef DEBUG_LINELOOP gLog.debugPrintf("PATH CLOSED! average_angle:%1.2f\n", average_angle); #endif return true; } bool lineloop_c::LookForIsland() { // ALGORITHM: // Iterate over all lines within the bounding box of the // current path (but not *on* the current path). // // Use OppositeLineDef() to find starting lines, and trace them. // Tracing is necessary because in certain shapes the opposite // lines will be part of the island too. // // Returns: true if found one, false otherwise. // // calc bounding box double bbox_x1, bbox_y1, bbox_x2, bbox_y2; CalcBounds(&bbox_x1, &bbox_y1, &bbox_x2, &bbox_y2); int count = 0; for (int ld = 0 ; ld < doc.numLinedefs() ; ld++) { const auto L = doc.linedefs[ld]; double x1 = doc.getStart(*L).x(); double y1 = doc.getStart(*L).y(); double x2 = doc.getEnd(*L).x(); double y2 = doc.getEnd(*L).y(); if (std::max(x1, x2) < bbox_x1 || std::min(x1, x2) > bbox_x2 || std::max(y1, y2) < bbox_y1 || std::min(y1, y2) > bbox_y2) continue; // ouch, this is gonna be SLOW for (int where = 0 ; where < 2 ; where++) { Side ld_side = where ? Side::right : Side::left; Side opp_side; int opp = doc.hover.getOppositeLinedef(ld, ld_side, &opp_side, nullptr, nullptr); if (opp < 0) continue; bool ld_in_path = get(ld, ld_side); bool opp_in_path = get(opp, opp_side); // need one in the current loop, and the other NOT in it if (ld_in_path == opp_in_path) continue; #ifdef DEBUG_LINELOOP gLog.debugPrintf("Found line:%d side:%d <--> opp:%d opp_side:%d us:%d them:%d\n", ld, ld_side, opp, opp_side, ld_in_path?1:0, opp_in_path?1:0); #endif lineloop_c *island = new lineloop_c(doc); // treat isolated linedefs like islands if (! ld_in_path && doc.vertmod.howManyLinedefs(doc.linedefs[ld]->start) == 1 && doc.vertmod.howManyLinedefs(doc.linedefs[ld]->end) == 1) { island->push_back(ld, Side::right); island->push_back(ld, Side::left); islands.push_back(island); count++; continue; } bool ok; if (ld_in_path) ok = doc.secmod.traceLineLoop(opp, opp_side, *island); else ok = doc.secmod.traceLineLoop(ld, ld_side, *island); if (ok && island->faces_outward) { islands.push_back(island); count++; } else { delete island; } } } return (count > 0); } void lineloop_c::FindIslands() { // Look for "islands", closed linedef paths that lie completely // inside the area, i.e. not connected to the main path. // // Repeat these steps until no more islands are found. // (This is needed to handle e.g. a big room full of pillars, // since the pillars in the middle won't "see" the outer sector // until the neighboring pillars are added). // // Example: the two pillars at the start of MAP01 of DOOM 2. // // use a counter for safety for (int loop = 0 ; loop < 200 ; loop++) { if (! LookForIsland()) break; } } void lineloop_c::Dump() const { gLog.debugPrintf("Lineloop %p : %zu lines, %zu islands\n", this, lines.size(), islands.size()); for (unsigned int i = 0 ; i < lines.size() ; i++) { const auto L = doc.linedefs[lines[i]]; gLog.debugPrintf(" %s of line #%d : (%f %f) --> (%f %f)\n", sides[i] == Side::left ? " LEFT" : "RIGHT", lines[i], doc.getStart(*L).x(), doc.getStart(*L).y(), doc.getEnd(*L).x(), doc.getEnd(*L).y()); } } inline bool SectorModule::willBeTwoSided(int ld, Side side) const { const auto L = doc.linedefs[ld]; if (L->WhatSideDef(side) < 0) { return (L->right >= 0) || (L->left >= 0); } return L->TwoSided(); } void SectorModule::determineNewTextures(lineloop_c& loop, std::vector& lower_texs, std::vector& upper_texs) const { unsigned int total = static_cast(loop.lines.size()); SYS_ASSERT(lower_texs.size() == total); StringID null_tex = BA_InternaliseString("-"); StringID def_lower = BA_InternaliseString(inst.conf.default_wall_tex); StringID def_upper = def_lower; unsigned int k; unsigned int pass; // look for emergency fallback texture for (pass = 0 ; pass < 2 ; pass++) { for (k = 0 ; k < total ; k++) { int ld = loop.lines[k]; Side side = loop.sides[k]; // check back sides in *first* pass // (to allow second pass to override) if (pass == 0) side = -side; int sd = doc.linedefs[ld]->WhatSideDef(side); if (sd < 0) continue; const auto SD = doc.sidedefs[sd]; if (doc.linedefs[ld]->TwoSided()) { if (SD->lower_tex == null_tex) continue; if (SD->upper_tex == null_tex) continue; def_lower = SD->lower_tex; def_upper = SD->upper_tex; } else { if (SD->mid_tex == null_tex) continue; def_lower = SD->mid_tex; def_upper = SD->mid_tex; } // stop once we found something break; } } // reset "bare" lines to -1, // and grab the textures of other lines for (k = 0 ; k < total ; k++) { int ld = loop.lines[k]; int sd = doc.linedefs[ld]->WhatSideDef(loop.sides[k]); if (sd < 0) { lower_texs[k] = upper_texs[k] = StringID(-1); continue; } const auto SD = doc.sidedefs[sd]; if (doc.linedefs[ld]->TwoSided()) { lower_texs[k] = SD->lower_tex; upper_texs[k] = SD->upper_tex; } else { lower_texs[k] = upper_texs[k] = SD->mid_tex; } // prevent the "-" null texture if (lower_texs[k] == null_tex) lower_texs[k] = def_lower; if (upper_texs[k] == null_tex) upper_texs[k] = def_upper; } // transfer nearby textures to blank spots for (pass = 0 ; pass < total*2 ; pass++) { for (k = 0 ; k < total ; k++) { if (lower_texs[k].isValid()) continue; // next and previous line indices unsigned int p = (k > 0) ? (k - 1) : total - 1; unsigned int n = (k < total - 1) ? (k + 1) : 0; bool two_k = willBeTwoSided(loop.lines[k], loop.sides[k]); bool two_p = willBeTwoSided(loop.lines[p], loop.sides[p]); bool two_n = willBeTwoSided(loop.lines[n], loop.sides[n]); // prefer same sided-ness of lines if (pass < total) { if (two_p != two_k) p = total; if (two_n != two_k) n = total; } // disable p or n if there is no texture there yet if (p < total && lower_texs[p].isInvalid()) p = total; if (n < total && lower_texs[n].isInvalid()) n = total; if (p == total && n == total) continue; // if p and n both usable, p trumps n if (p == total) p = n; lower_texs[k] = lower_texs[p]; upper_texs[k] = upper_texs[p]; } } // lastly, ensure all textures are valid for (k = 0 ; k < total ; k++) { if (lower_texs[k].isInvalid()) lower_texs[k] = def_lower; if (upper_texs[k].isInvalid()) upper_texs[k] = def_upper; } } // // update the side on a single linedef, using the given sector // reference, and creating a new sidedef if necessary. // void SectorModule::doAssignSector(EditOperation &op, int ld, Side side, int new_sec, StringID new_lower, StringID new_upper, selection_c &flip) const { // gLog.debugPrintf("DoAssignSector %d ---> line #%d, side %d\n", new_sec, ld, side); const auto L = doc.linedefs[ld]; int sd_num = (side == Side::right) ? L->right : L->left; int other_sd = (side == Side::right) ? L->left : L->right; if (sd_num >= 0) { op.changeSidedef(sd_num, SideDef::F_SECTOR, new_sec); return; } // if we're adding a sidedef to a line that has no sides, and // the sidedef would be the 2nd one, then flip the linedef. // Thus we don't end up with invalid lines -- i.e. ones with a // left side but no right side. if (side == Side::left && other_sd < 0) flip.set(ld); else flip.clear(ld); SYS_ASSERT(new_lower.isValid()); SYS_ASSERT(new_upper.isValid()); // create new sidedef int new_sd = op.addNew(ObjType::sidedefs); auto SD = doc.sidedefs[new_sd]; if (other_sd >= 0) { // linedef will be two-sided SD->lower_tex = new_lower; SD->upper_tex = new_upper; SD-> mid_tex = BA_InternaliseString("-"); } else { // linedef will be one-sided SD->lower_tex = new_lower; SD->upper_tex = new_lower; SD-> mid_tex = new_lower; } SD->sector = new_sec; if (side == Side::right) op.changeLinedef(ld, LineDef::F_RIGHT, new_sd); else op.changeLinedef(ld, LineDef::F_LEFT, new_sd); // if we're adding a second side to the linedef, clear out some // of the properties that aren't needed anymore: middle texture, // two-sided flag, and impassible flag. if (other_sd >= 0) doc.linemod.addSecondSidedef(op, ld, new_sd, other_sd); } void lineloop_c::AssignSector(EditOperation &op, int new_sec, selection_c &flip) { std::vector lower_texs(lines.size()); std::vector upper_texs(lines.size()); doc.secmod.determineNewTextures(*this, lower_texs, upper_texs); for (unsigned int k = 0 ; k < lines.size() ; k++) { doc.secmod.doAssignSector(op, lines[k], sides[k], new_sec, lower_texs[k], upper_texs[k], flip); } for (unsigned int i = 0 ; i < islands.size() ; i++) { islands[i]->AssignSector(op, new_sec, flip); } } bool SectorModule::getLoopForSpace(const v2double_t &map, lineloop_c& loop) const { selection_c seen_lines(ObjType::linedefs); int ld; Side side; ld = hover::getClosestLine_CastingHoriz(doc, map, &side); gLog.debugPrintf("GetLoopForSpace : hit line #%d, side %d\n", ld, (int)side); while (ld >= 0) { // never try this line again seen_lines.set(ld); if (! traceLineLoop(ld, side, loop)) { gLog.debugPrintf("Area is not closed (tracing a loop failed)\n"); return false; } // not an island? GOOD! if (! loop.faces_outward) { return true; } gLog.debugPrintf(" hit island\n"); // ensure we don't try any lines of this island unsigned int k; for (k = 0 ; k < loop.lines.size() ; k++) seen_lines.set(loop.lines[k]); // look for the surrounding line loop... ld = -1; for (k = 0 ; k < loop.lines.size() ; k++) { int new_ld; Side new_side; new_ld = doc.hover.getOppositeLinedef(loop.lines[k], loop.sides[k], &new_side, nullptr, nullptr); if (new_ld < 0) continue; if (seen_lines.get(new_ld)) continue; // try again... ld = new_ld; side = new_side; gLog.debugPrintf(" trying again with line #%d, side %d\n", ld, (int)side); break; } } gLog.debugPrintf("Area is not closed (can see infinity)\n"); return false; } // // the "space" here really means a bunch of sidedefs that all face // inward to the current area under the mouse cursor. // // the 'new_sec' can be < 0 to create a new sector. // // the 'model' is what properties to use for a new sector, < 0 means // look for a neighboring sector to copy. // bool SectorModule::assignSectorToSpace(EditOperation &op, const v2double_t &map, int new_sec, int model) const { lineloop_c loop(doc); if (! getLoopForSpace(map, loop)) { inst.Beep("Area is not closed"); return false; } loop.FindIslands(); if (new_sec < 0) { new_sec = op.addNew(ObjType::sectors); if (model < 0) model = loop.NeighboringSector(); if (model < 0) doc.sectors[new_sec]->SetDefaults(inst.conf); else *doc.sectors[new_sec] = *doc.sectors[model]; } selection_c flip(ObjType::linedefs); selection_c unused(ObjType::sectors); loop.GetAllSectors(&unused); loop.AssignSector(op, new_sec, flip); doc.linemod.flipLinedefGroup(op, &flip); // detect any sectors which have become unused, and delete them for (int n = 0 ; n < doc.numLinedefs() ; n++) { const auto L = doc.linedefs[n]; if (doc.getSectorID(*L, Side::left) >= 0) unused.clear(doc.getSectorID(*L, Side::left)); if (doc.getSectorID(*L, Side::right) >= 0) unused.clear(doc.getSectorID(*L, Side::right)); } doc.objects.del(op, unused); return true; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_sector.h000066400000000000000000000114201464327712600203020ustar00rootroot00000000000000//------------------------------------------------------------------------ // SECTOR OPERATIONS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_E_SECTOR_H__ #define __EUREKA_E_SECTOR_H__ #include "DocumentModule.h" class lineloop_c { public: // This contains the linedefs in the line loop, beginning with // the first line and going in order until the last line. There // will be at least 3 lines in the loop. It is possible for a // linedef to be present twice (a loop traversing both sides). std::vector< int > lines; // This contains which side of the linedefs in 'lines'. // Guaranteed to be the same size as 'lines'. // Each value is either SIDE_LEFT or SIDE_RIGHT. std::vector< Side > sides; // true if the lines face outward (average angle > 180 degrees) // false if the lines face inward (average angle < 180 degrees) bool faces_outward = false; // Islands are outward facing line-loops which lie inside this one // (which must be inward facing). This list is only created by // calling FindIslands() method, which can be very expensive. std::vector< lineloop_c * > islands; const Document &doc; public: lineloop_c(const Document &doc) : doc(doc) { } ~lineloop_c() { clear(); } void clear(); void push_back(int ld, Side side); // test if the given line/side combo is in the loop bool get(int ld, Side side) const; bool get_just_line(int ld) const; void FindIslands(); double TotalLength() const; // checks if all lines in the loop are facing the same sector. // when true, returns that sector via 'sec_num' (if not null). // the 'sec_num' value may be -1 if all lines are "bare". // NOTE : does not test the islands. bool SameSector(int *sec_num = NULL) const; // true if all lines in the loop are facing nothing. bool AllBare() const; // find a sector that neighbors this line loop, i.e. is on the other // side of one of the lines. If there are multiple neighbors, then // only one of them is returned. If there are none, returns -1. int NeighboringSector() const; // check if an island lies inside a sector, returning the sector // number if true, otherwise -1. int IslandSector() const; int DetermineSector() const; // return all the sectors which the lineloop faces void GetAllSectors(selection_c *list) const; // assign a new sector to the whole loop, including islands. // the 'flip' parameter will contain lines that should be flipped // afterwards (to ensure it has a valid right side). // 'new_sec' MUST be a valid sector number. void AssignSector(EditOperation &op, int new_sec, selection_c &flip); void Dump() const; private: bool LookForIsland(); void CalcBounds(double *x1, double *y1, double *x2, double *y2) const; }; // // Sector module // class SectorModule : public DocumentModule { friend class Instance; public: SectorModule(Document &doc) : DocumentModule(doc) { } bool traceLineLoop(int ld, Side side, lineloop_c& loop, bool ignore_bare = false) const; bool assignSectorToSpace(EditOperation &op, const v2double_t &map, int new_sec = -1, int model = -1) const; void sectorsAdjustLight(int delta) const; void safeRaiseLower(EditOperation &op, int sec, int parts, int dz) const; private: friend class lineloop_c; void linedefsBetweenSectors(selection_c *list, int sec1, int sec2) const; void replaceSectorRefs(EditOperation &op, int old_sec, int new_sec) const; inline bool willBeTwoSided(int ld, Side side) const; void determineNewTextures(lineloop_c& loop, std::vector& lower_texs, std::vector& upper_texs) const; void doAssignSector(EditOperation &op, int ld, Side side, int new_sec, StringID new_lower, StringID new_upper, selection_c &flip) const; bool getLoopForSpace(const v2double_t &map, lineloop_c& loop) const; }; #endif /* __EUREKA_E_SECTOR_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_select.cc000066400000000000000000000337571464327712600204410ustar00rootroot00000000000000//------------------------------------------------------------------------ // LEVEL MISC STUFF //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2023 Ioan Chera // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Instance.h" #include "w_rawdef.h" #include struct SideIteration { byte parts; Side side; byte lower; byte rail; byte upper; }; // // Given a source line, a next line, and their facing sides, it returns the visible faces which // touch each other for selecting neighbors by texture. // struct WallContinuity { WallContinuity &moveLeft(Side side); byte otherParts(byte parts, const SideIteration &iteration) const; byte top, middle, bottom; }; WallContinuity &WallContinuity::moveLeft(Side side) { if(side == Side::left) { top *= PART_LF_LOWER / PART_RT_LOWER; // gross hack to move flags middle *= PART_LF_LOWER / PART_RT_LOWER; bottom *= PART_LF_LOWER / PART_RT_LOWER; } return *this; } byte WallContinuity::otherParts(byte parts, const SideIteration &iteration) const { return (parts & iteration.lower ? bottom : 0) | (parts & iteration.rail ? middle : 0) | (parts & iteration.upper ? top : 0); } static WallContinuity getWallTextureContinuity(const Instance &inst, const LineDef &source, Side sourceSide, const LineDef &next, Side nextSide) { const Document &doc = inst.level; WallContinuity result = {}; const SideDef *sourceFront = doc.getSide(source, sourceSide); const Sector *sourceFrontSector = sourceFront ? &doc.getSector(*sourceFront) : nullptr; const SideDef *sourceBack = doc.getSide(source, -sourceSide); const Sector *sourceBackSector = sourceBack ? &doc.getSector(*sourceBack) : nullptr; const SideDef *nextFront = doc.getSide(next, nextSide); const Sector *nextFrontSector = nextFront ? &doc.getSector(*nextFront) : nullptr; const SideDef *nextBack = doc.getSide(next, -nextSide); const Sector *nextBackSector = nextBack ? &doc.getSector(*nextBack) : nullptr; // Shut lines are over. Same if they have no common heights. if(!sourceFrontSector || !nextFrontSector || sourceFrontSector->ceilh <= sourceFrontSector->floorh || nextFrontSector->ceilh <= nextFrontSector->floorh || sourceFrontSector->floorh >= nextFrontSector->ceilh || nextFrontSector->floorh >= sourceFrontSector->ceilh) { return result; } // WARNING: one-sided lines actually use the lower part, not the rail! // If source is two-sided... if(sourceBackSector) { // We have top, so check it if(sourceFrontSector->ceilh > sourceBackSector->ceilh) { // 1-sided next if(!nextBackSector) { if(nextFrontSector->ceilh > sourceBackSector->ceilh && nextFront->MidTex() == sourceFront->UpperTex()) { result.top |= PART_RT_LOWER; } } else // 2-sided next { // Continuous top facet if(nextFrontSector->ceilh > nextBackSector->ceilh && nextFrontSector->ceilh > sourceBackSector->ceilh && sourceFrontSector->ceilh > nextBackSector->ceilh && nextFront->UpperTex() == sourceFront->UpperTex()) { result.top |= PART_RT_UPPER; } // Continuous top to bottom facet. Cannot match with railings this way (extremities // already tested) if(nextBackSector->floorh > nextFrontSector->floorh && nextBackSector->floorh > sourceBackSector->ceilh && nextFront->LowerTex() == sourceFront->UpperTex()) { result.top |= PART_RT_LOWER; } } } // We have bottom, so check it if(sourceBackSector->floorh > sourceFrontSector->floorh) { // 1-sided next if(!nextBackSector) { if(sourceBackSector->floorh > nextFrontSector->floorh && nextFront->MidTex() == sourceFront->LowerTex()) { result.bottom |= PART_RT_LOWER; } } else // 2-sided next { // Continuous bottom facet if(nextBackSector->floorh > nextFrontSector->floorh && nextBackSector->floorh > sourceFrontSector->floorh && sourceBackSector->floorh > nextFrontSector->floorh && nextFront->LowerTex() == sourceFront->LowerTex()) { result.bottom |= PART_RT_LOWER; } // Continuous bottom to top facet. Same thing about railings not being compatible. if(nextFrontSector->ceilh > nextBackSector->ceilh && sourceBackSector->floorh > nextBackSector->ceilh && nextFront->UpperTex() == sourceFront->LowerTex()) { result.bottom |= PART_RT_UPPER; } } } // We have window, so check middle (railing) continuity if(sourceBackSector->ceilh > sourceBackSector->floorh && nextBackSector && nextBackSector->ceilh > nextBackSector->floorh && sourceBackSector->ceilh > nextBackSector->floorh && nextBackSector->ceilh > sourceBackSector->floorh && nextFront->MidTex() == sourceFront->MidTex()) { result.middle |= PART_RT_RAIL; } } else // 1-sided source { // simple wall-wall continuity if(!nextBackSector) { if(nextFront->MidTex() == sourceFront->MidTex()) result.bottom |= PART_RT_LOWER; } else // wall - 2-sided continuity { // wall - top continuity if(nextFrontSector->ceilh > nextBackSector->ceilh && sourceFrontSector->ceilh > nextBackSector->ceilh && nextFront->UpperTex() == sourceFront->MidTex()) { result.bottom |= PART_RT_UPPER; } if(nextBackSector->floorh > nextFrontSector->floorh && nextBackSector->floorh > sourceFrontSector->floorh && nextFront->LowerTex() == sourceFront->MidTex()) { result.bottom |= PART_RT_LOWER; } } } return result.moveLeft(nextSide); } static WallContinuity matchingWallHeights(const Instance &inst, const LineDef &source, Side sourceSide, const LineDef &next, Side nextSide) { WallContinuity result = {}; const Document &doc = inst.level; const SideDef *sourceSidedef = doc.getSide(source, sourceSide); const SideDef *nextSidedef = doc.getSide(next, nextSide); if(!sourceSidedef || !nextSidedef) return result; const Sector &sourceSector = doc.getSector(*sourceSidedef); const Sector &nextSector = doc.getSector(*nextSidedef); // Any shut sector is removed if(sourceSector.floorh >= sourceSector.ceilh || nextSector.floorh >= nextSector.ceilh) return result; const SideDef *sourceBack = doc.getSide(source, -sourceSide); const SideDef *nextBack = doc.getSide(next, -nextSide); const Sector *sourceBackSector = sourceBack ? &doc.getSector(*sourceBack) : nullptr; const Sector *nextBackSector = nextBack ? &doc.getSector(*nextBack) : nullptr; // Check lower int bottom, top; auto checkNextLine = [&bottom, &top, nextBack, &nextSector, nextBackSector]() -> byte { if(nextBack) { if(std::max(nextSector.floorh, nextBackSector->ceilh) == bottom && nextSector.ceilh == top) return PART_RT_UPPER; if(std::min(nextSector.ceilh, nextBackSector->floorh) == top && nextSector.floorh == bottom) return PART_RT_LOWER; } else { if(nextSector.ceilh == top && nextSector.floorh == bottom) return PART_RT_LOWER; } return 0; }; if(sourceBack) { if(sourceBackSector->floorh > sourceSector.floorh) { bottom = sourceSector.floorh; top = std::min(sourceSector.ceilh, sourceBackSector->floorh); result.bottom = checkNextLine(); } if(sourceBackSector->ceilh < sourceSector.ceilh) { bottom = std::max(sourceSector.floorh, sourceBackSector->ceilh); top = sourceSector.ceilh; result.top = checkNextLine(); } if(sourceBackSector->ceilh > sourceSector.floorh && sourceSector.ceilh > sourceBackSector->floorh && sourceBackSector->ceilh > sourceBackSector->floorh && nextBack) { int lowestceil1 = std::min(sourceSector.ceilh, sourceBackSector->ceilh); int highestfloor1 = std::max(sourceSector.floorh, sourceBackSector->floorh); int midheight1 = lowestceil1 - highestfloor1; int lowestceil2 = std::min(nextSector.ceilh, nextBackSector->ceilh); int highestfloor2 = std::max(nextSector.floorh, nextBackSector->floorh); int midheight2 = lowestceil2 - highestfloor2; int texheight1 = inst.wad.images.W_GetTextureHeight(inst.conf, sourceSidedef->MidTex()); int texheight2 = inst.wad.images.W_GetTextureHeight(inst.conf, nextSidedef->MidTex()); auto translatedOffset = [](const LineDef &line, const SideDef &side, int midheight, int texheight) { if(line.flags & MLF_LowerUnpegged) return texheight - midheight + side.y_offset; return side.y_offset; }; if(midheight1 == midheight2 && midheight1 <= std::min(texheight1, texheight2) && lowestceil1 == lowestceil2 && highestfloor1 == highestfloor2) { result.middle = PART_RT_RAIL; } else if(texheight1 == texheight2 && texheight1 <= std::min(midheight1, midheight2) && translatedOffset(source, *sourceSidedef, midheight1, texheight1) == translatedOffset(next, *nextSidedef, midheight2, texheight2)) { result.middle = PART_RT_RAIL; } } } else { // single sided bottom = sourceSector.floorh; top = sourceSector.ceilh; result.bottom = checkNextLine(); } return result.moveLeft(nextSide); } static std::vector> makeVertexLineMap(const Document &doc) { std::vector> result; result.resize(doc.numVertices()); for(int i = 0; i < doc.numLinedefs(); ++i) { const auto line = doc.linedefs[i]; for(int vertNum : {line->start, line->end}) if(doc.isVertex(vertNum)) result[vertNum].push_back(i); } return result; } static void selectNeighborLines(Instance &inst, int objnum, byte parts, WallContinuity (*func)( const Instance &inst, const LineDef &source, Side sourceSide, const LineDef &next, Side nextSide)) { const Document &doc = inst.level; if(!doc.isLinedef(objnum) || !(parts & (PART_RT_ALL | PART_LF_ALL))) return; auto vertLineMap = makeVertexLineMap(doc); const auto source = doc.linedefs[objnum]; struct Entry { const LineDef *line; byte parts; }; std::queue queue; queue.push({source.get(), parts}); // Also select the current line inst.edit.Selected->set_ext(objnum, inst.edit.Selected->get_ext(objnum) | parts); while(!queue.empty()) { Entry entry = queue.front(); queue.pop(); for(int vertNum : {entry.line->start, entry.line->end}) { for(int neigh : vertLineMap[vertNum]) { const auto otherLine = doc.linedefs[neigh]; if(otherLine.get() == entry.line) continue; bool flipped = otherLine->start == entry.line->start || otherLine->end == entry.line->end; for(auto iteration : {SideIteration{PART_RT_ALL, Side::right, PART_RT_LOWER, PART_RT_RAIL, PART_RT_UPPER}, SideIteration{PART_LF_ALL, Side::left, PART_LF_LOWER, PART_LF_RAIL, PART_LF_UPPER}}) { if(entry.parts & iteration.parts) { WallContinuity continuity = func(inst, *entry.line, iteration.side, *otherLine, flipped ? -iteration.side : iteration.side); byte otherParts = continuity.otherParts(entry.parts, iteration); byte otherCurrentlySelected = inst.edit.Selected->get_ext(neigh); if((otherCurrentlySelected & otherParts) < otherParts) { inst.edit.Selected->set_ext(neigh, otherCurrentlySelected | otherParts); queue.push({otherLine.get(), otherParts}); } } } } } } } void Instance::SelectNeighborSectors(int objnum, SelectNeighborCriterion option, byte parts) { const auto sector1 = level.sectors[objnum]; for (const auto &line : level.linedefs) { if (!line->TwoSided()) continue; if (level.getRight(*line)->sector == objnum || level.getLeft(*line)->sector == objnum) { const Sector *sector2; int sectornum; bool match = false; if (level.getRight(*line)->sector == objnum) { sector2 = &level.getSector(*level.getLeft(*line)); sectornum = level.getLeft(*line)->sector; } else { sector2 = &level.getSector(*level.getRight(*line)); sectornum = level.getRight(*line)->sector; } if (edit.Selected->get(sectornum)) continue; if (option == SelectNeighborCriterion::texture) { if (parts & PART_FLOOR) match = (sector1->FloorTex() == sector2->FloorTex()); else match = (sector1->CeilTex() == sector2->CeilTex()); } else { if (parts & PART_FLOOR) match = (sector1->floorh == sector2->floorh); else match = (sector1->ceilh == sector2->ceilh); } if (match) { edit.Selected->set_ext(sectornum, parts); SelectNeighborSectors(sectornum, option, parts); } } } } void Instance::CMD_SelectNeighbors() { SString option = EXEC_Param[0]; if (edit.mode != ObjType::linedefs && edit.mode != ObjType::sectors) return; if (option != "height" && option != "texture") return; SelectNeighborCriterion criterion = option == "height" ? SelectNeighborCriterion::height : SelectNeighborCriterion::texture; if (edit.highlight.num < 0) return; int num = edit.highlight.num; byte parts = static_cast(edit.highlight.parts); if (edit.Selected->get(num) && edit.Selected->get_ext(num) & parts) { CMD_UnselectAll(); } else { edit.Selected->set_ext(num, edit.Selected->get_ext(num) | parts); if (edit.mode == ObjType::linedefs) { if(criterion == SelectNeighborCriterion::texture) selectNeighborLines(*this, num, parts, getWallTextureContinuity); else selectNeighborLines(*this, num, parts, matchingWallHeights); } else { SelectNeighborSectors(num, criterion, parts); } } RedrawMap(); } eureka-editor-eureka-2.0.2/src/e_things.cc000066400000000000000000000117771464327712600204540ustar00rootroot00000000000000//------------------------------------------------------------------------ // THING OPERATIONS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Instance.h" #include "main.h" #include "m_game.h" #include "e_things.h" #include "e_main.h" #include "m_bitvec.h" #include "Thing.h" #include "w_rawdef.h" #include "ui_window.h" int calc_new_angle(int angle, int diff) { angle += diff; while (angle < 0) angle += 360000000; return angle % 360; } // // spin_thing - change the angle of things // void Instance::CMD_TH_SpinThings() { int degrees = atoi(EXEC_Param[0]); if (! degrees) degrees = +45; SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { Beep("No things to spin"); return; } { EditOperation op(level.basis); op.setMessageForSelection("spun", *edit.Selected); for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { const auto T = level.things[*it]; op.changeThing(*it, Thing::F_ANGLE, calc_new_angle(T->angle, degrees)); } } main_win->thing_box->UpdateField(Thing::F_ANGLE); if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); } static bool ThingsAtSameLoc(const Document &doc, int th1, int th2) { const auto T1 = doc.things[th1]; const auto T2 = doc.things[th2]; double dx = fabs(T1->x() - T2->x()); double dy = fabs(T1->y() - T2->y()); return (dx < 8 && dy < 8); } static void CollectOverlapGroup(const Instance &inst, selection_c& list) { int first = inst.edit.Selected->find_first(); list.set(first); for (int k = 0 ; k < inst.level.numThings() ; k++) if (k != first && ThingsAtSameLoc(inst.level, k, first)) list.set(k); } static void MoveOverlapThing(EditOperation &op, Instance &inst, int th, int mid_x, int mid_y, int n, int total) { float angle = static_cast(n * 360 / total); float vec_x = static_cast(cos(angle * M_PI / 180.0)); float vec_y = static_cast(sin(angle * M_PI / 180.0)); float dist = static_cast(8 + 6 * std::min(100, total)); FFixedPoint fdx = MakeValidCoord(inst.loaded.levelFormat, static_cast(vec_x) * dist); FFixedPoint fdy = MakeValidCoord(inst.loaded.levelFormat, static_cast(vec_y) * dist); const auto T = inst.level.things[th]; op.changeThing(th, Thing::F_X, T->raw_x + fdx); op.changeThing(th, Thing::F_Y, T->raw_y + fdy); } // // all things lying at same location (or very near) to the selected // things are moved so they are more distinct -- about 8 units away // from that location. // void CMD_TH_Disconnect(Instance &inst) { SelectHighlight unselect = inst.edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { inst.Beep("No vertices to disconnect"); return; } EditOperation op(inst.level.basis); op.setMessageForSelection("disconnected", *inst.edit.Selected); while (!inst.edit.Selected->empty()) { selection_c overlaps(ObjType::things); CollectOverlapGroup(inst, overlaps); // remove these from the selection inst.edit.Selected->unmerge(overlaps); int total = overlaps.count_obj(); if (total < 2) continue; v2double_t mid = inst.level.objects.calcMiddle(overlaps); int n = 0; for (sel_iter_c it(overlaps) ; !it.done() ; it.next(), n++) { MoveOverlapThing(op, inst, *it, static_cast(mid.x), static_cast(mid.y), n, total); } } } // // place all selected things at same location // void CMD_TH_Merge(Instance &inst) { if (inst.edit.Selected->count_obj() == 1 && inst.edit.highlight.valid()) { inst.edit.Selection_AddHighlighted(); } if (inst.edit.Selected->count_obj() < 2) { inst.Beep("Need 2 or more things to merge"); return; } v2double_t mid = inst.level.objects.calcMiddle(*inst.edit.Selected); EditOperation op(inst.level.basis); op.setMessageForSelection("merged", *inst.edit.Selected); for (sel_iter_c it(*inst.edit.Selected) ; !it.done() ; it.next()) { op.changeThing(*it, Thing::F_X, MakeValidCoord(inst.loaded.levelFormat, mid.x)); op.changeThing(*it, Thing::F_Y, MakeValidCoord(inst.loaded.levelFormat, mid.y)); } } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_things.h000066400000000000000000000034761464327712600203130ustar00rootroot00000000000000//------------------------------------------------------------------------ // THING OPERATIONS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_E_THINGS_H__ #define __EUREKA_E_THINGS_H__ #include "im_color.h" /* starting areas */ #define THING_PLAYER1 1 #define THING_PLAYER2 2 #define THING_PLAYER3 3 #define THING_PLAYER4 4 #define THING_DEATHMATCH 11 #define MAX_RADIUS 128 class Instance; /* * angle_to_direction - convert angle to direction (0-7) * * Return a value that is guaranteed to be within [0-7]. */ inline int angle_to_direction (int angle) { return ((unsigned) angle / 45) % 8; } int calc_new_angle(int angle, int diff); /* commands */ void CMD_TH_Disconnect(Instance &inst); void CMD_TH_Merge(Instance &inst); #endif /* __EUREKA_E_THINGS_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_vertex.cc000066400000000000000000000706101464327712600204640ustar00rootroot00000000000000//------------------------------------------------------------------------ // VERTEX OPERATIONS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include "e_cutpaste.h" #include "e_hover.h" #include "e_linedef.h" #include "e_main.h" #include "e_objects.h" #include "e_vertex.h" #include "LineDef.h" #include "m_bitvec.h" #include "r_grid.h" #include "m_game.h" #include "e_objects.h" #include "SideDef.h" #include "Thing.h" #include "Vertex.h" #include "w_rawdef.h" #include int VertexModule::findExact(FFixedPoint fx, FFixedPoint fy) const { for (int i = 0 ; i < doc.numVertices() ; i++) { if (doc.vertices[i]->Matches(fx, fy)) return i; } return -1; // not found } int VertexModule::findDragOther(int v_num) const { // we always return the START of a linedef if possible, but // if that doesn't occur then return the END of a linedef. int fallback = -1; for (int i = 0 ; i < doc.numLinedefs() ; i++) { const auto L = doc.linedefs[i]; if (L->end == v_num) return L->start; if (L->start == v_num && fallback < 0) fallback = L->end; } return fallback; } int VertexModule::howManyLinedefs(int v_num) const { int count = 0; for (int n = 0 ; n < doc.numLinedefs() ; n++) { const auto L = doc.linedefs[n]; if (L->start == v_num || L->end == v_num) count++; } return count; } // // two linedefs are being sandwiched together. // vertex 'v' is the shared vertex (the "hinge"). // to prevent an overlap, we merge ld1 into ld2. // void VertexModule::mergeSandwichLines(EditOperation &op, int ld1, int ld2, int v, selection_c& del_lines) const { const auto L1 = doc.linedefs[ld1]; const auto L2 = doc.linedefs[ld2]; bool ld1_onesided = L1->OneSided(); bool ld2_onesided = L2->OneSided(); StringID new_mid_tex = (ld1_onesided) ? doc.getRight(*L1)->mid_tex : (ld2_onesided) ? doc.getRight(*L2)->mid_tex : StringID(); // flip L1 so it would be parallel with L2 (after merging the other // endpoint) but going the opposite direction. if ((L2->end == v) == (L1->end == v)) { doc.linemod.flipLinedef(op, ld1); } bool same_left = (doc.getSectorID(*L2, Side::left) == doc.getSectorID(*L1, Side::left)); bool same_right = (doc.getSectorID(*L2, Side::right) == doc.getSectorID(*L1, Side::right)); if (same_left && same_right) { // the merged line would have the same thing on both sides // (possibly VOID space), so the linedefs both "vanish". del_lines.set(ld1); del_lines.set(ld2); return; } if (same_left) { op.changeLinedef(ld2, LineDef::F_LEFT, L1->right); } else if (same_right) { op.changeLinedef(ld2, LineDef::F_RIGHT, L1->left); } else { // geometry was broken / unclosed sector(s) } del_lines.set(ld1); // fix orientation of remaining linedef if needed if (doc.getLeft(*L2) && ! doc.getRight(*L2)) { doc.linemod.flipLinedef(op, ld2); } if (L2->OneSided() && new_mid_tex.hasContent()) { op.changeSidedef(L2->right, SideDef::F_MID_TEX, new_mid_tex); } // fix flags of remaining linedef int new_flags = L2->flags; if (L2->TwoSided()) { new_flags |= MLF_TwoSided; new_flags &= ~MLF_Blocking; } else { new_flags &= ~MLF_TwoSided; new_flags |= MLF_Blocking; } op.changeLinedef(ld2, LineDef::F_FLAGS, new_flags); } // // merge v1 into v2 // void VertexModule::doMergeVertex(EditOperation &op, int v1, int v2, selection_c& del_lines) const { SYS_ASSERT(v1 >= 0 && v2 >= 0); SYS_ASSERT(v1 != v2); // check if two linedefs would overlap after the merge // [ but ignore lines already marked for deletion ] int sandwichesMerged = 0; for (int n = 0 ; n < doc.numLinedefs() ; n++) { const auto L = doc.linedefs[n]; if (! L->TouchesVertex(v1)) continue; if (del_lines.get(n)) continue; int v3 = (L->start == v1) ? L->end : L->start; int found = -1; for (int k = 0 ; k < doc.numLinedefs(); k++) { if (k == n) continue; const auto K = doc.linedefs[k]; if ((K->start == v3 && K->end == v2) || (K->start == v2 && K->end == v3)) { found = k; break; } } if (found >= 0 && ! del_lines.get(found)) { mergeSandwichLines(op, n, found, v3, del_lines); if(++sandwichesMerged == 2) // can't have more than two, on each side break; } } // update all linedefs which use V1 to use V2 instead, and // delete any line that exists between the two vertices. for (int n = 0 ; n < doc.numLinedefs() ; n++) { const auto L = doc.linedefs[n]; // change *ALL* references, this is critical // [ to-be-deleted lines will get start == end, that is OK ] if (L->start == v1) op.changeLinedef(n, LineDef::F_START, v2); if (L->end == v1) op.changeLinedef(n, LineDef::F_END, v2); if (L->start == v2 && L->end == v2) del_lines.set(n); } } // // the first vertex is kept, all the other vertices are deleted // (after fixing the attached linedefs). // void VertexModule::mergeList(EditOperation &op, selection_c &verts, selection_c *delResultList) const { if (verts.count_obj() < 2) return; int v = verts.find_first(); #if 0 double new_x, new_y; Objs_CalcMiddle(verts, &new_x, &new_y); BA_ChangeVT(v, Vertex::F_X, MakeValidCoord(new_x)); BA_ChangeVT(v, Vertex::F_Y, MakeValidCoord(new_y)); #endif verts.clear(v); selection_c del_lines(ObjType::linedefs); // this prevents unnecessary sandwich mergers ConvertSelection(doc, verts, del_lines); for (sel_iter_c it(verts) ; !it.done() ; it.next()) { doMergeVertex(op, *it, v, del_lines); } // all these vertices will be unused now, hence this call // shouldn't kill any other objects. doc.objects.del(op, verts); // we NEED to keep unused vertices here, otherwise we can merge // all vertices of an isolated sector and end up with NOTHING! DeleteObjects_WithUnused(op, doc, del_lines, false /* keep_things */, true /* keep_verts */, false /* keep_lines */); if(delResultList) { delResultList->clear_all(); delResultList->change_type(ObjType::vertices); delResultList->merge(verts); } verts.clear_all(); } void Instance::commandVertexMerge() { if (edit.Selected->count_obj() == 1 && edit.highlight.valid()) { edit.Selection_AddHighlighted(); } if (edit.Selected->count_obj() < 2) { Beep("Need 2 or more vertices to merge"); return; } { EditOperation op(level.basis); op.setMessageForSelection("merged", *edit.Selected); level.vertmod.mergeList(op, *edit.Selected, nullptr); } Selection_Clear(true /* no_save */); } bool VertexModule::tryFixDangler(int v_num) const { // see if this vertex is sitting on another one (or very close to it) int v_other = -1; int max_dist = 2; for (int i = 0 ; i < doc.numVertices() ; i++) { if (i == v_num) continue; double dx = doc.vertices[v_num]->x() - doc.vertices[i]->x(); double dy = doc.vertices[v_num]->y() - doc.vertices[i]->y(); if (fabs(dx) <= max_dist && fabs(dy) <= max_dist && !doc.linemod.linedefAlreadyExists(v_num, v_other)) { v_other = i; break; } } // check for a dangling vertex if (howManyLinedefs(v_num) != 1) { if (v_other >= 0 && howManyLinedefs(v_other) == 1) std::swap(v_num, v_other); else return false; } if (v_other >= 0) { inst.Selection_Clear(true /* no_save */); // delete highest numbered one [ so the other index remains valid ] if (v_num < v_other) std::swap(v_num, v_other); #if 0 // DEBUG fprintf(stderr, "Vertex_TryFixDangler : merge vert %d onto %d\n", v_num, v_other); #endif { EditOperation op(doc.basis); op.setMessage("merged dangling vertex #%d\n", v_num); selection_c list(ObjType::vertices); list.set(v_other); // first one is the one kept list.set(v_num); mergeList(op, list, nullptr); } inst.edit.Selected->set(v_other); inst.Beep("Merged a dangling vertex"); return true; } #if 0 // find the line joined to this vertex int joined_ld = -1; for (int n = 0 ; n < doc.numLinedefs(); n++) { if (LineDefs[n]->TouchesVertex(v_num)) { joined_ld = n; break; } } SYS_ASSERT(joined_ld >= 0); #endif // see if vertex is sitting on a line Objid line_obj = hover::findSplitLineForDangler(doc, inst.loaded.levelFormat, inst.grid, v_num); if (! line_obj.valid()) return false; #if 0 // DEBUG fprintf(stderr, "Vertex_TryFixDangler : split linedef %d with vert %d\n", line_obj.num, v_num); #endif EditOperation op(doc.basis); op.setMessage("split linedef #%d\n", line_obj.num); doc.linemod.splitLinedefAtVertex(op, line_obj.num, v_num); // no vertices were added or removed, hence can continue Insert_Vertex return false; } void VertexModule::calcDisconnectCoord(const LineDef *L, int v_num, double *x, double *y) const { const auto V = doc.vertices[v_num]; double dx = doc.getEnd(*L).x() - doc.getStart(*L).x(); double dy = doc.getEnd(*L).y() - doc.getStart(*L).y(); if (L->end == v_num) { dx = -dx; dy = -dy; } if (fabs(dx) < 4 && fabs(dy) < 4) { dx = dx / 2; dy = dy / 2; } else if (fabs(dx) < 16 && fabs(dy) < 16) { dx = dx / 4; dy = dy / 4; } else if (fabs(dx) >= fabs(dy)) { dy = dy * 8 / fabs(dx); dx = (dx < 0) ? -8 : 8; } else { dx = dx * 8 / fabs(dy); dy = (dy < 0) ? -8 : 8; } *x = V->x() + dx; *y = V->y() + dy; } void VertexModule::doDisconnectVertex(EditOperation &op, int v_num, int num_lines) const { int which = 0; for (int n = 0 ; n < doc.numLinedefs() ; n++) { const auto L = doc.linedefs[n]; if (L->start == v_num || L->end == v_num) { double new_x, new_y; calcDisconnectCoord(L.get(), v_num, &new_x, &new_y); // the _LAST_ linedef keeps the current vertex, the rest // need a new one. if (which != num_lines-1) { int new_v = op.addNew(ObjType::vertices); doc.vertices[new_v]->SetRawXY(inst.loaded.levelFormat, { new_x, new_y }); if (L->start == v_num) op.changeLinedef(n, LineDef::F_START, new_v); else op.changeLinedef(n, LineDef::F_END, new_v); } else { op.changeVertex(v_num, Vertex::F_X, MakeValidCoord(inst.loaded.levelFormat, new_x)); op.changeVertex(v_num, Vertex::F_Y, MakeValidCoord(inst.loaded.levelFormat, new_y)); } which++; } } } void Instance::commandVertexDisconnect() { if (edit.Selected->empty()) { if (edit.highlight.is_nil()) { Beep("Nothing to disconnect"); return; } edit.Selection_AddHighlighted(); } bool seen_one = false; { EditOperation op(level.basis); op.setMessageForSelection("disconnected", *edit.Selected); for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { int v_num = *it; // nothing to do unless vertex has 2 or more linedefs int num_lines = level.vertmod.howManyLinedefs(*it); if (num_lines < 2) continue; level.vertmod.doDisconnectVertex(op, v_num, num_lines); seen_one = true; } if (! seen_one) Beep("Nothing was disconnected"); } Selection_Clear(true); } void VertexModule::doDisconnectLinedef(EditOperation &op, int ld, int which_vert, bool *seen_one) const { const auto L = doc.linedefs[ld]; int v_num = which_vert ? L->end : L->start; // see if there are any linedefs NOT in the selection which are // connected to this vertex. bool touches_non_sel = false; for (int n = 0 ; n < doc.numLinedefs(); n++) { if (inst.edit.Selected->get(n)) continue; const auto N = doc.linedefs[n]; if (N->start == v_num || N->end == v_num) { touches_non_sel = true; break; } } if (! touches_non_sel) return; double new_x, new_y; calcDisconnectCoord(doc.linedefs[ld].get(), v_num, &new_x, &new_y); int new_v = op.addNew(ObjType::vertices); doc.vertices[new_v]->SetRawXY(inst.loaded.levelFormat, { new_x, new_y }); // fix all linedefs in the selection to use this new vertex for (sel_iter_c it(*inst.edit.Selected) ; !it.done() ; it.next()) { const auto L2 = doc.linedefs[*it]; if (L2->start == v_num) op.changeLinedef(*it, LineDef::F_START, new_v); if (L2->end == v_num) op.changeLinedef(*it, LineDef::F_END, new_v); } *seen_one = true; } void Instance::commandLineDisconnect() { // Note: the logic here is significantly different than the logic // in VT_Disconnect, since we want to keep linedefs in the // selection connected, and only disconnect from linedefs // NOT in the selection. // // Hence need separate code for this. SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { Beep("Nothing to disconnect"); return; } bool seen_one = false; { EditOperation op(level.basis); op.setMessageForSelection("disconnected", *edit.Selected); for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { level.vertmod.doDisconnectLinedef(op, *it, 0, &seen_one); level.vertmod.doDisconnectLinedef(op, *it, 1, &seen_one); } } if (! seen_one) Beep("Nothing was disconnected"); if (unselect == SelectHighlight::unselect) Selection_Clear(true /* no save */); } void VertexModule::verticesOfDetachableSectors(selection_c &verts) const { SYS_ASSERT(doc.numVertices() > 0); bitvec_c in_verts(doc.numVertices()); bitvec_c out_verts(doc.numVertices()); for (int n = 0 ; n < doc.numLinedefs() ; n++) { const auto L = doc.linedefs[n]; // only process lines which touch a selected sector bool left_in = doc.getLeft(*L) && inst.edit.Selected->get(doc.getLeft(*L)->sector); bool right_in = doc.getRight(*L) && inst.edit.Selected->get(doc.getRight(*L)->sector); if (! (left_in || right_in)) continue; bool innie = false; bool outie = false; if (doc.getRight(*L)) { if (right_in) innie = true; else outie = true; } if (doc.getLeft(*L)) { if (left_in) innie = true; else outie = true; } if (innie) { in_verts.set(L->start); in_verts.set(L->end); } if (outie) { out_verts.set(L->start); out_verts.set(L->end); } } for (int k = 0 ; k < doc.numVertices() ; k++) { if (in_verts.get(k) && out_verts.get(k)) verts.set(k); } } void VertexModule::DETSEC_SeparateLine(EditOperation &op, int ld_num, int start2, int end2, Side in_side) const { const auto L1 = doc.linedefs[ld_num]; int new_ld = op.addNew(ObjType::linedefs); int lost_sd; const auto L2 = doc.linedefs[new_ld]; if (in_side == Side::left) { L2->start = end2; L2->end = start2; L2->right = L1->left; lost_sd = L1->left; } else { L2->start = start2; L2->end = end2; L2->right = L1->right; lost_sd = L1->right; doc.linemod.flipLinedef(op, ld_num); } op.changeLinedef(ld_num, LineDef::F_LEFT, -1); // determine new flags int new_flags = L1->flags; new_flags &= ~MLF_TwoSided; new_flags |= MLF_Blocking; op.changeLinedef(ld_num, LineDef::F_FLAGS, new_flags); L2->flags = L1->flags; // fix the first line's textures StringID tex = BA_InternaliseString(inst.conf.default_wall_tex); const SideDef * SD = doc.sidedefs[L1->right].get(); if (! is_null_tex(SD->LowerTex())) tex = SD->lower_tex; else if (! is_null_tex(SD->UpperTex())) tex = SD->upper_tex; op.changeSidedef(L1->right, SideDef::F_MID_TEX, tex); // now fix the second line's textures SD = doc.sidedefs[lost_sd].get(); if (! is_null_tex(SD->LowerTex())) tex = SD->lower_tex; else if (! is_null_tex(SD->UpperTex())) tex = SD->upper_tex; op.changeSidedef(lost_sd, SideDef::F_MID_TEX, tex); } void VertexModule::DETSEC_CalcMoveVector(const selection_c & detach_verts, double * dx, double * dy) const { v2double_t det_mid = doc.objects.calcMiddle(detach_verts); v2double_t sec_mid = doc.objects.calcMiddle(*inst.edit.Selected); *dx = sec_mid.x - det_mid.x; *dy = sec_mid.y - det_mid.y; // avoid moving perfectly horizontal or vertical // (also handes the case of dx == dy == 0) if (fabs(*dx) > fabs(*dy)) { *dx = (*dx < 0) ? -9 : +9; *dy = (*dy < 0) ? -5 : +5; } else { *dx = (*dx < 0) ? -5 : +5; *dy = (*dy < 0) ? -9 : +9; } if (fabs(*dx) < 2) *dx = (*dx < 0) ? -2 : +2; if (fabs(*dy) < 4) *dy = (*dy < 0) ? -4 : +4; double mul = 1.0 / clamp(0.25, inst.grid.getScale(), 1.0); *dx = (*dx) * mul; *dy = (*dy) * mul; } void Instance::commandSectorDisconnect() { if (level.numVertices() == 0) { Beep("No sectors to disconnect"); return; } SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { Beep("No sectors to disconnect"); return; } int n; // collect all vertices which need to be detached selection_c detach_verts(ObjType::vertices); level.vertmod.verticesOfDetachableSectors(detach_verts); if (detach_verts.empty()) { Beep("Already disconnected"); if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); return; } // determine vector to move the detach coords double move_dx, move_dy; level.vertmod.DETSEC_CalcMoveVector(detach_verts, &move_dx, &move_dy); { EditOperation op(level.basis); op.setMessageForSelection("disconnected", *edit.Selected); // create new vertices, and a mapping from old --> new int * mapping = new int[level.numVertices()]; for (n = 0 ; n < level.numVertices(); n++) mapping[n] = -1; for (sel_iter_c it(detach_verts) ; !it.done() ; it.next()) { int new_v = op.addNew(ObjType::vertices); mapping[*it] = new_v; auto newbie = level.vertices[new_v]; *newbie = *level.vertices[*it]; } // update linedefs, creating new ones where necessary // (go backwards so we don't visit newly created lines) for (n = level.numLinedefs() -1 ; n >= 0 ; n--) { const auto L = level.linedefs[n]; // only process lines which touch a selected sector bool left_in = level.getLeft(*L) && edit.Selected->get(level.getLeft(*L)->sector); bool right_in = level.getRight(*L) && edit.Selected->get(level.getRight(*L)->sector); if (! (left_in || right_in)) continue; bool between_two = (left_in && right_in); int start2 = mapping[L->start]; int end2 = mapping[L->end]; if (start2 >= 0 && end2 >= 0 && L->TwoSided() && ! between_two) { level.vertmod.DETSEC_SeparateLine(op, n, start2, end2, left_in ? Side::left : Side::right); } else { if (start2 >= 0) op.changeLinedef(n, LineDef::F_START, start2); if (end2 >= 0) op.changeLinedef(n, LineDef::F_END, end2); } } delete[] mapping; // finally move all vertices of selected sectors selection_c all_verts(ObjType::vertices); ConvertSelection(level, *edit.Selected, all_verts); for (sel_iter_c it(all_verts) ; !it.done() ; it.next()) { const auto V = level.vertices[*it]; op.changeVertex(*it, Vertex::F_X, V->raw_x + MakeValidCoord(loaded.levelFormat, move_dx)); op.changeVertex(*it, Vertex::F_Y, V->raw_y + MakeValidCoord(loaded.levelFormat, move_dy)); } } if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); } //------------------------------------------------------------------------ // RESHAPING STUFF //------------------------------------------------------------------------ static double WeightForVertex(const Vertex *V, /* bbox: */ double x1, double y1, double x2, double y2, double width, double height, int side) { double dist; double extent; if (width >= height) { dist = (side < 0) ? (V->x() - x1) : (x2 - V->x()); extent = width; } else { dist = (side < 0) ? (V->y() - y1) : (y2 - V->y()); extent = height; } if (dist > extent * 0.66) return 0; if (dist > extent * 0.33) return 0.25; return 1.0; } struct vert_along_t { int vert_num; double along; public: vert_along_t(int num, double _along) : vert_num(num), along(_along) { } struct CMP { inline bool operator() (const vert_along_t &A, const vert_along_t& B) const { return A.along < B.along; } }; }; void Instance::CMD_VT_ShapeLine() { if (edit.Selected->count_obj() < 3) { Beep("Need 3 or more vertices to shape"); return; } // determine orientation and position of the line v2double_t pos1, pos2; level.objects.calcBBox(*edit.Selected, pos1, pos2); double width = pos2.x - pos1.x; double height = pos2.y - pos1.y; if (width < 4 && height < 4) { Beep("Too small"); return; } // The method here is where split the vertices into two groups and // use the center of each group to form the infinite line. I have // modified that a bit, the vertices in a band near the middle all // participate in the sum but at 0.25 weighting. -AJA- double ax = 0; double ay = 0; double a_total = 0; double bx = 0; double by = 0; double b_total = 0; for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { const auto V = level.vertices[*it]; double weight = WeightForVertex(V.get(), pos1.x,pos1.y, pos2.x,pos2.y, width,height, -1); if (weight > 0) { ax += V->x() * weight; ay += V->y() * weight; a_total += weight; } weight = WeightForVertex(V.get(), pos1.x,pos1.y, pos2.x,pos2.y, width,height, +1); if (weight > 0) { bx += V->x() * weight; by += V->y() * weight; b_total += weight; } } SYS_ASSERT(a_total > 0); SYS_ASSERT(b_total > 0); ax /= a_total; ay /= a_total; bx /= b_total; by /= b_total; // check the two end points are not too close double unit_x = (bx - ax); double unit_y = (by - ay); double unit_len = hypot(unit_x, unit_y); if (unit_len < 2) { Beep("Cannot determine line"); return; } unit_x /= unit_len; unit_y /= unit_len; // collect all vertices and determine where along the line they are, // then sort them based on their along value. std::vector< vert_along_t > along_list; for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { const auto V = level.vertices[*it]; vert_along_t ALONG(*it, AlongDist(V->xy(), { ax,ay }, { bx, by })); along_list.push_back(ALONG); } std::sort(along_list.begin(), along_list.end(), vert_along_t::CMP()); // compute proper positions for start and end of the line const auto V1 = level.vertices[along_list.front().vert_num]; const auto V2 = level.vertices[along_list. back().vert_num]; double along1 = along_list.front().along; double along2 = along_list. back().along; if ((true) /* don't move first and last vertices */) { ax = V1->x(); ay = V1->y(); bx = V2->x(); by = V2->y(); } else { bx = ax + along2 * unit_x; by = ay + along2 * unit_y; ax = ax + along1 * unit_x; ay = ay + along1 * unit_y; } EditOperation op(level.basis); op.setMessage("shaped %d vertices", (int)along_list.size()); for (unsigned int i = 0 ; i < along_list.size() ; i++) { double frac; if ((true) /* regular spacing */) frac = i / (double)(along_list.size() - 1); else frac = (along_list[i].along - along1) / (along2 - along1); // ANOTHER OPTION: use distances between neighbor verts... double nx = ax + (bx - ax) * frac; double ny = ay + (by - ay) * frac; op.changeVertex(along_list[i].vert_num, Thing::F_X, MakeValidCoord(loaded.levelFormat, nx)); op.changeVertex(along_list[i].vert_num, Thing::F_Y, MakeValidCoord(loaded.levelFormat, ny)); } } static double BiggestGapAngle(std::vector< vert_along_t > &along_list, unsigned int *start_idx) { double best_diff = 0; double best_low = 0; *start_idx = 0; for (unsigned int i = 0 ; i < along_list.size() ; i++) { unsigned int k = i + 1; if (k >= along_list.size()) k = 0; double low = along_list[i].along; double high = along_list[k].along; if (high < low) high = high + M_PI * 2.0; double ang_diff = high - low; if (ang_diff > best_diff) { best_diff = ang_diff; best_low = low; *start_idx = k; } } double best = best_low + best_diff * 0.5; return best; } double VertexModule::evaluateCircle(EditOperation *op, double mid_x, double mid_y, double r, std::vector< vert_along_t > &along_list, unsigned int start_idx, double arc_rad, double ang_offset /* radians */, bool move_vertices) const { double cost = 0; bool partial_circle = (arc_rad < M_PI * 1.9); for (unsigned int i = 0 ; i < along_list.size() ; i++) { unsigned int k = (start_idx + i) % along_list.size(); const auto V = doc.vertices[along_list[k].vert_num]; double frac = i / (double)(along_list.size() - (partial_circle ? 1 : 0)); double ang = arc_rad * frac + ang_offset; double new_x = mid_x + cos(ang) * r; double new_y = mid_y + sin(ang) * r; if (move_vertices) { op->changeVertex(along_list[k].vert_num, Thing::F_X, MakeValidCoord(inst.loaded.levelFormat, new_x)); op->changeVertex(along_list[k].vert_num, Thing::F_Y, MakeValidCoord(inst.loaded.levelFormat, new_y)); } else { double dx = new_x - V->x(); double dy = new_y - V->y(); cost = cost + (dx*dx + dy*dy); } } return cost; } void Instance::CMD_VT_ShapeArc() { if (EXEC_Param[0].empty()) { Beep("VT_ShapeArc: missing angle parameter"); return; } int arc_deg = atoi(EXEC_Param[0]); if (arc_deg < 30 || arc_deg > 360) { Beep("VT_ShapeArc: bad angle: %s", EXEC_Param[0].c_str()); return; } double arc_rad = arc_deg * M_PI / 180.0; if (edit.Selected->count_obj() < 3) { Beep("Need 3 or more vertices to shape"); return; } // determine middle point for circle v2double_t pos1, pos2; level.objects.calcBBox(*edit.Selected, pos1, pos2); double width = pos2.x - pos1.x; double height = pos2.y - pos1.y; if (width < 4 && height < 4) { Beep("Too small"); return; } v2double_t mid = (pos1 + pos2) * 0.5; // collect all vertices and determine their angle (in radians), // and sort them. // // also determine radius of circle -- average of distances between // the computed mid-point and each vertex. double r = 0; std::vector< vert_along_t > along_list; for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { const auto V = level.vertices[*it]; double dx = V->x() - mid.x; double dy = V->y() - mid.y; double dist = hypot(dx, dy); if (dist < 4) { Beep("Strange shape"); return; } r += dist; double angle = atan2(dy, dx); vert_along_t ALONG(*it, angle); along_list.push_back(ALONG); } r /= (double)along_list.size(); std::sort(along_list.begin(), along_list.end(), vert_along_t::CMP()); // where is the biggest gap? unsigned int start_idx; unsigned int end_idx; double gap_angle = BiggestGapAngle(along_list, &start_idx); double gap_dx = cos(gap_angle); double gap_dy = sin(gap_angle); if (start_idx > 0) end_idx = start_idx - 1; else end_idx = static_cast(along_list.size() - 1); const auto start_V = level.vertices[along_list[start_idx].vert_num]; const auto end_V = level.vertices[along_list[ end_idx].vert_num]; double start_end_dist = hypot(end_V->x() - start_V->x(), end_V->y() - start_V->y()); // compute new mid-point and radius (except for a full circle) // and also compute starting angle. double best_offset = 0; double best_cost = 1e30; if (arc_deg < 360) { mid = (start_V->xy() + end_V->xy()) * 0.5; r = start_end_dist * 0.5; double dx = gap_dx; double dy = gap_dy; if (arc_deg > 180) { dx = -dx; dy = -dy; } double theta = fabs(arc_rad - M_PI) / 2.0; double away = r * tan(theta); mid.x += dx * away; mid.y += dy * away; r = hypot(r, away); best_offset = atan2(start_V->y() - mid.y, start_V->x() - mid.x); } else { // find the best orientation, the one that minimises the distances // which vertices move. We try 1000 possibilities. for (int pos = 0 ; pos < 1000 ; pos++) { double ang_offset = pos * M_PI * 2.0 / 1000.0; double cost = level.vertmod.evaluateCircle(nullptr, mid.x, mid.y, r, along_list, start_idx, arc_rad, ang_offset, false); if (cost < best_cost) { best_offset = ang_offset; best_cost = cost; } } } // actually move stuff now EditOperation op(level.basis); op.setMessage("shaped %d vertices", (int)along_list.size()); level.vertmod.evaluateCircle(&op, mid.x, mid.y, r, along_list, start_idx, arc_rad, best_offset, true); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/e_vertex.h000066400000000000000000000051211464327712600203210ustar00rootroot00000000000000//------------------------------------------------------------------------ // VERTEX STUFF //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_E_VERTEX_H__ #define __EUREKA_E_VERTEX_H__ #include "DocumentModule.h" struct vert_along_t; class VertexModule : public DocumentModule { friend class Instance; public: VertexModule(Document &doc) : DocumentModule(doc) { } int findExact(FFixedPoint fx, FFixedPoint fy) const; int findDragOther(int v_num) const; int howManyLinedefs(int v_num) const; void mergeList(EditOperation &op, selection_c &list, selection_c *deletedResultList) const; bool tryFixDangler(int v_num) const; private: void mergeSandwichLines(EditOperation &op, int ld1, int ld2, int v, selection_c &del_lines) const; void doMergeVertex(EditOperation &op, int v1, int v2, selection_c &del_lines) const; void calcDisconnectCoord(const LineDef *L, int v_num, double *x, double *y) const; void doDisconnectVertex(EditOperation &op, int v_num, int num_lines) const; void doDisconnectLinedef(EditOperation &op, int ld, int which_vert, bool *seen_one) const; void verticesOfDetachableSectors(selection_c &verts) const; void DETSEC_SeparateLine(EditOperation &op, int ld_num, int start2, int end2, Side in_side) const; void DETSEC_CalcMoveVector(const selection_c &detach_verts, double *dx, double *dy) const; double evaluateCircle(EditOperation *op, double mid_x, double mid_y, double r, std::vector< vert_along_t > &along_list, unsigned int start_idx, double arc_rad, double ang_offset /* radians */, bool move_vertices = false) const; }; #endif /* __EUREKA_E_VERTEX_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/filesystem.hpp000066400000000000000000005637251464327712600212470ustar00rootroot00000000000000//--------------------------------------------------------------------------------------- // // ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14/C++17/C++20 // //--------------------------------------------------------------------------------------- // // Copyright (c) 2018, Steffen Schümann // // 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 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // //--------------------------------------------------------------------------------------- // // To dynamically select std::filesystem where available on most platforms, // you could use: // // #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include) // #if __has_include() && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) // #define GHC_USE_STD_FS // #include // namespace fs = std::filesystem; // #endif // #endif // #ifndef GHC_USE_STD_FS // #include // namespace fs = ghc::filesystem; // #endif // //--------------------------------------------------------------------------------------- #ifndef GHC_FILESYSTEM_H #define GHC_FILESYSTEM_H // #define BSD manifest constant only in // sys/param.h #ifndef _WIN32 #include #endif #ifndef GHC_OS_DETECTED #if defined(__APPLE__) && defined(__MACH__) #define GHC_OS_MACOS #elif defined(__linux__) #define GHC_OS_LINUX #if defined(__ANDROID__) #define GHC_OS_ANDROID #endif #elif defined(_WIN64) #define GHC_OS_WINDOWS #define GHC_OS_WIN64 #elif defined(_WIN32) #define GHC_OS_WINDOWS #define GHC_OS_WIN32 #elif defined(__CYGWIN__) #define GHC_OS_CYGWIN #elif defined(__sun) && defined(__SVR4) #define GHC_OS_SOLARIS #elif defined(__svr4__) #define GHC_OS_SYS5R4 #elif defined(BSD) #define GHC_OS_BSD #elif defined(__EMSCRIPTEN__) #define GHC_OS_WEB #include #elif defined(__QNX__) #define GHC_OS_QNX #else #error "Operating system currently not supported!" #endif #define GHC_OS_DETECTED #if (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) #if _MSVC_LANG == 201703L #define GHC_FILESYSTEM_RUNNING_CPP17 #else #define GHC_FILESYSTEM_RUNNING_CPP20 #endif #elif (defined(__cplusplus) && __cplusplus >= 201703L) #if __cplusplus == 201703L #define GHC_FILESYSTEM_RUNNING_CPP17 #else #define GHC_FILESYSTEM_RUNNING_CPP20 #endif #endif #endif #if defined(GHC_FILESYSTEM_IMPLEMENTATION) #define GHC_EXPAND_IMPL #define GHC_INLINE #ifdef GHC_OS_WINDOWS #ifndef GHC_FS_API #define GHC_FS_API #endif #ifndef GHC_FS_API_CLASS #define GHC_FS_API_CLASS #endif #else #ifndef GHC_FS_API #define GHC_FS_API __attribute__((visibility("default"))) #endif #ifndef GHC_FS_API_CLASS #define GHC_FS_API_CLASS __attribute__((visibility("default"))) #endif #endif #elif defined(GHC_FILESYSTEM_FWD) #define GHC_INLINE #ifdef GHC_OS_WINDOWS #ifndef GHC_FS_API #define GHC_FS_API extern #endif #ifndef GHC_FS_API_CLASS #define GHC_FS_API_CLASS #endif #else #ifndef GHC_FS_API #define GHC_FS_API extern #endif #ifndef GHC_FS_API_CLASS #define GHC_FS_API_CLASS #endif #endif #else #define GHC_EXPAND_IMPL #define GHC_INLINE inline #ifndef GHC_FS_API #define GHC_FS_API #endif #ifndef GHC_FS_API_CLASS #define GHC_FS_API_CLASS #endif #endif #ifdef GHC_EXPAND_IMPL #ifdef GHC_OS_WINDOWS #include // additional includes #include #include #include #include #include #else #include #include #include #include #include #include #include #include #ifdef GHC_OS_ANDROID #include #if __ANDROID_API__ < 12 #include #endif #include #define statvfs statfs #else #include #endif #ifdef GHC_OS_CYGWIN #include #endif #if !defined(__ANDROID__) || __ANDROID_API__ >= 26 #include #endif #endif #ifdef GHC_OS_MACOS #include #endif #if defined(__cpp_impl_three_way_comparison) && defined(__has_include) #if __has_include() #define GHC_HAS_THREEWAY_COMP #include #endif #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #else // GHC_EXPAND_IMPL #if defined(__cpp_impl_three_way_comparison) && defined(__has_include) #if __has_include() #define GHC_HAS_THREEWAY_COMP #include #endif #endif #include #include #include #include #include #include #include #ifdef GHC_OS_WINDOWS #include #endif #endif // GHC_EXPAND_IMPL // After standard library includes. // Standard library support for std::string_view. #if defined(__cpp_lib_string_view) #define GHC_HAS_STD_STRING_VIEW #elif defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 4000) && (__cplusplus >= 201402) #define GHC_HAS_STD_STRING_VIEW #elif defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE >= 7) && (__cplusplus >= 201703) #define GHC_HAS_STD_STRING_VIEW #elif defined(_MSC_VER) && (_MSC_VER >= 1910 && _MSVC_LANG >= 201703) #define GHC_HAS_STD_STRING_VIEW #endif // Standard library support for std::experimental::string_view. #if defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 3700 && _LIBCPP_VERSION < 7000) && (__cplusplus >= 201402) #define GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW #elif defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4)) && (__cplusplus >= 201402) #define GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW #elif defined(__GLIBCXX__) && defined(_GLIBCXX_USE_DUAL_ABI) && (__cplusplus >= 201402) // macro _GLIBCXX_USE_DUAL_ABI is always defined in libstdc++ from gcc-5 and newer #define GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW #endif #if defined(GHC_HAS_STD_STRING_VIEW) #include #elif defined(GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW) #include #endif #if !defined(GHC_OS_WINDOWS) && !defined(PATH_MAX) #define PATH_MAX 4096 #endif //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Behaviour Switches (see README.md, should match the config in test/filesystem_test.cpp): //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Enforce C++17 API where possible when compiling for C++20, handles the following cases: // * fs::path::u8string() returns std::string instead of std::u8string // #define GHC_FILESYSTEM_ENFORCE_CPP17_API //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // LWG #2682 disables the since then invalid use of the copy option create_symlinks on directories // configure LWG conformance () #define LWG_2682_BEHAVIOUR //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // LWG #2395 makes crate_directory/create_directories not emit an error if there is a regular // file with that name, it is superseded by P1164R1, so only activate if really needed // #define LWG_2935_BEHAVIOUR //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // LWG #2936 enables new element wise (more expensive) path comparison // * if this->root_name().native().compare(p.root_name().native()) != 0 return result // * if this->has_root_directory() and !p.has_root_directory() return -1 // * if !this->has_root_directory() and p.has_root_directory() return -1 // * else result of element wise comparison of path iteration where first comparison is != 0 or 0 // if all comparisons are 0 (on Windows this implementation does case-insensitive root_name() // comparison) #define LWG_2936_BEHAVIOUR //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2) #define LWG_2937_BEHAVIOUR //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // UTF8-Everywhere is the original behaviour of ghc::filesystem. But since v1.5 the Windows // version defaults to std::wstring storage backend. Still all std::string will be interpreted // as UTF-8 encoded. With this define you can enforce the old behavior on Windows, using // std::string as backend and for fs::path::native() and char for fs::path::c_str(). This // needs more conversions, so it is (and was before v1.5) slower, bot might help keeping source // homogeneous in a multi-platform project. // #define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Raise errors/exceptions when invalid unicode codepoints or UTF-8 sequences are found, // instead of replacing them with the unicode replacement character (U+FFFD). // #define GHC_RAISE_UNICODE_ERRORS //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Automatic prefix windows path with "\\?\" if they would break the MAX_PATH length. // instead of replacing them with the unicode replacement character (U+FFFD). #ifndef GHC_WIN_DISABLE_AUTO_PREFIXES #define GHC_WIN_AUTO_PREFIX_LONG_PATH #endif // GHC_WIN_DISABLE_AUTO_PREFIXES //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch) #define GHC_FILESYSTEM_VERSION 10512L #if !defined(GHC_WITH_EXCEPTIONS) && (defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)) #define GHC_WITH_EXCEPTIONS #endif #if !defined(GHC_WITH_EXCEPTIONS) && defined(GHC_RAISE_UNICODE_ERRORS) #error "Can't raise unicode errors with exception support disabled" #endif namespace ghc { namespace filesystem { #if defined(GHC_HAS_CUSTOM_STRING_VIEW) #define GHC_WITH_STRING_VIEW #elif defined(GHC_HAS_STD_STRING_VIEW) #define GHC_WITH_STRING_VIEW using std::basic_string_view; #elif defined(GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW) #define GHC_WITH_STRING_VIEW using std::experimental::basic_string_view; #endif // temporary existing exception type for yet unimplemented parts class GHC_FS_API_CLASS not_implemented_exception : public std::logic_error { public: not_implemented_exception() : std::logic_error("function not implemented yet.") { } }; template class path_helper_base { public: using value_type = char_type; #ifdef GHC_OS_WINDOWS static constexpr value_type preferred_separator = '\\'; #else static constexpr value_type preferred_separator = '/'; #endif }; #if __cplusplus < 201703L template constexpr char_type path_helper_base::preferred_separator; #endif #ifdef GHC_OS_WINDOWS class path; namespace detail { bool has_executable_extension(const path& p); } #endif // [fs.class.path] class path class GHC_FS_API_CLASS path #if defined(GHC_OS_WINDOWS) && !defined(GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE) #define GHC_USE_WCHAR_T #define GHC_NATIVEWP(p) p.c_str() #define GHC_PLATFORM_LITERAL(str) L##str : private path_helper_base { public: using path_helper_base::value_type; #else #define GHC_NATIVEWP(p) p.wstring().c_str() #define GHC_PLATFORM_LITERAL(str) str : private path_helper_base { public: using path_helper_base::value_type; #endif using string_type = std::basic_string; using path_helper_base::preferred_separator; // [fs.enum.path.format] enumeration format /// The path format in which the constructor argument is given. enum format { generic_format, ///< The generic format, internally used by ///< ghc::filesystem::path with slashes native_format, ///< The format native to the current platform this code ///< is build for auto_format, ///< Try to auto-detect the format, fallback to native }; template struct _is_basic_string : std::false_type { }; template struct _is_basic_string> : std::true_type { }; template struct _is_basic_string, std::allocator>> : std::true_type { }; #ifdef GHC_WITH_STRING_VIEW template struct _is_basic_string> : std::true_type { }; template struct _is_basic_string>> : std::true_type { }; #endif template using path_type = typename std::enable_if::value, path>::type; template #if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) using path_from_string = typename std::enable_if<_is_basic_string::value || std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value, path>::type; template using path_type_EcharT = typename std::enable_if::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value, path>::type; #else using path_from_string = typename std::enable_if<_is_basic_string::value || std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value, path>::type; template using path_type_EcharT = typename std::enable_if::value || std::is_same::value || std::is_same::value || std::is_same::value, path>::type; #endif // [fs.path.construct] constructors and destructor path() noexcept; path(const path& p); path(path&& p) noexcept; path(string_type&& source, format fmt = auto_format); template > path(const Source& source, format fmt = auto_format); template path(InputIterator first, InputIterator last, format fmt = auto_format); #ifdef GHC_WITH_EXCEPTIONS template > path(const Source& source, const std::locale& loc, format fmt = auto_format); template path(InputIterator first, InputIterator last, const std::locale& loc, format fmt = auto_format); #endif ~path(); // [fs.path.assign] assignments path& operator=(const path& p); path& operator=(path&& p) noexcept; path& operator=(string_type&& source); path& assign(string_type&& source); template path& operator=(const Source& source); template path& assign(const Source& source); template path& assign(InputIterator first, InputIterator last); // [fs.path.append] appends path& operator/=(const path& p); template path& operator/=(const Source& source); template path& append(const Source& source); template path& append(InputIterator first, InputIterator last); // [fs.path.concat] concatenation path& operator+=(const path& x); path& operator+=(const string_type& x); #ifdef GHC_WITH_STRING_VIEW path& operator+=(basic_string_view x); #endif path& operator+=(const value_type* x); path& operator+=(value_type x); template path_from_string& operator+=(const Source& x); template path_type_EcharT& operator+=(EcharT x); template path& concat(const Source& x); template path& concat(InputIterator first, InputIterator last); // [fs.path.modifiers] modifiers void clear() noexcept; path& make_preferred(); path& remove_filename(); path& replace_filename(const path& replacement); path& replace_extension(const path& replacement = path()); void swap(path& rhs) noexcept; // [fs.path.native.obs] native format observers const string_type& native() const noexcept; const value_type* c_str() const noexcept; operator string_type() const; template , class Allocator = std::allocator> std::basic_string string(const Allocator& a = Allocator()) const; std::string string() const; std::wstring wstring() const; #if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) std::u8string u8string() const; #else std::string u8string() const; #endif std::u16string u16string() const; std::u32string u32string() const; // [fs.path.generic.obs] generic format observers template , class Allocator = std::allocator> std::basic_string generic_string(const Allocator& a = Allocator()) const; std::string generic_string() const; std::wstring generic_wstring() const; #if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) std::u8string generic_u8string() const; #else std::string generic_u8string() const; #endif std::u16string generic_u16string() const; std::u32string generic_u32string() const; // [fs.path.compare] compare int compare(const path& p) const noexcept; int compare(const string_type& s) const; #ifdef GHC_WITH_STRING_VIEW int compare(basic_string_view s) const; #endif int compare(const value_type* s) const; // [fs.path.decompose] decomposition path root_name() const; path root_directory() const; path root_path() const; path relative_path() const; path parent_path() const; path filename() const; path stem() const; path extension() const; // [fs.path.query] query bool empty() const noexcept; bool has_root_name() const; bool has_root_directory() const; bool has_root_path() const; bool has_relative_path() const; bool has_parent_path() const; bool has_filename() const; bool has_stem() const; bool has_extension() const; bool is_absolute() const; bool is_relative() const; // [fs.path.gen] generation path lexically_normal() const; path lexically_relative(const path& base) const; path lexically_proximate(const path& base) const; // [fs.path.itr] iterators class iterator; using const_iterator = iterator; iterator begin() const; iterator end() const; private: using impl_value_type = value_type; using impl_string_type = std::basic_string; friend class directory_iterator; void append_name(const value_type* name); static constexpr impl_value_type generic_separator = '/'; template class input_iterator_range { public: typedef InputIterator iterator; typedef InputIterator const_iterator; typedef typename InputIterator::difference_type difference_type; input_iterator_range(const InputIterator& first, const InputIterator& last) : _first(first) , _last(last) { } InputIterator begin() const { return _first; } InputIterator end() const { return _last; } private: InputIterator _first; InputIterator _last; }; friend void swap(path& lhs, path& rhs) noexcept; friend size_t hash_value(const path& p) noexcept; friend path canonical(const path& p, std::error_code& ec); friend bool create_directories(const path& p, std::error_code& ec) noexcept; string_type::size_type root_name_length() const noexcept; void postprocess_path_with_format(format fmt); void check_long_path(); impl_string_type _path; #ifdef GHC_OS_WINDOWS void handle_prefixes(); friend bool detail::has_executable_extension(const path& p); #ifdef GHC_WIN_AUTO_PREFIX_LONG_PATH string_type::size_type _prefixLength{0}; #else // GHC_WIN_AUTO_PREFIX_LONG_PATH static const string_type::size_type _prefixLength{0}; #endif // GHC_WIN_AUTO_PREFIX_LONG_PATH #else static const string_type::size_type _prefixLength{0}; #endif }; // [fs.path.nonmember] path non-member functions GHC_FS_API void swap(path& lhs, path& rhs) noexcept; GHC_FS_API size_t hash_value(const path& p) noexcept; #ifdef GHC_HAS_THREEWAY_COMP GHC_FS_API std::strong_ordering operator<=>(const path& lhs, const path& rhs) noexcept; #endif GHC_FS_API bool operator==(const path& lhs, const path& rhs) noexcept; GHC_FS_API bool operator!=(const path& lhs, const path& rhs) noexcept; GHC_FS_API bool operator<(const path& lhs, const path& rhs) noexcept; GHC_FS_API bool operator<=(const path& lhs, const path& rhs) noexcept; GHC_FS_API bool operator>(const path& lhs, const path& rhs) noexcept; GHC_FS_API bool operator>=(const path& lhs, const path& rhs) noexcept; GHC_FS_API path operator/(const path& lhs, const path& rhs); // [fs.path.io] path inserter and extractor template std::basic_ostream& operator<<(std::basic_ostream& os, const path& p); template std::basic_istream& operator>>(std::basic_istream& is, path& p); // [pfs.path.factory] path factory functions template > #if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) [[deprecated("use ghc::filesystem::path::path() with std::u8string instead")]] #endif path u8path(const Source& source); template #if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) [[deprecated("use ghc::filesystem::path::path() with std::u8string instead")]] #endif path u8path(InputIterator first, InputIterator last); // [fs.class.filesystem_error] class filesystem_error class GHC_FS_API_CLASS filesystem_error : public std::system_error { public: filesystem_error(const std::string& what_arg, std::error_code ec); filesystem_error(const std::string& what_arg, const path& p1, std::error_code ec); filesystem_error(const std::string& what_arg, const path& p1, const path& p2, std::error_code ec); const path& path1() const noexcept; const path& path2() const noexcept; const char* what() const noexcept override; private: std::string _what_arg; std::error_code _ec; path _p1, _p2; }; class GHC_FS_API_CLASS path::iterator { public: using value_type = const path; using difference_type = std::ptrdiff_t; using pointer = const path*; using reference = const path&; using iterator_category = std::bidirectional_iterator_tag; iterator(); iterator(const path& p, const impl_string_type::const_iterator& pos); iterator& operator++(); iterator operator++(int); iterator& operator--(); iterator operator--(int); bool operator==(const iterator& other) const; bool operator!=(const iterator& other) const; reference operator*() const; pointer operator->() const; private: friend class path; impl_string_type::const_iterator increment(const impl_string_type::const_iterator& pos) const; impl_string_type::const_iterator decrement(const impl_string_type::const_iterator& pos) const; void updateCurrent(); impl_string_type::const_iterator _first; impl_string_type::const_iterator _last; impl_string_type::const_iterator _prefix; impl_string_type::const_iterator _root; impl_string_type::const_iterator _iter; path _current; }; struct space_info { uintmax_t capacity; uintmax_t free; uintmax_t available; }; // [fs.enum] enumerations // [fs.enum.file_type] enum class file_type { none, not_found, regular, directory, symlink, block, character, fifo, socket, unknown, }; // [fs.enum.perms] enum class perms : uint16_t { none = 0, owner_read = 0400, owner_write = 0200, owner_exec = 0100, owner_all = 0700, group_read = 040, group_write = 020, group_exec = 010, group_all = 070, others_read = 04, others_write = 02, others_exec = 01, others_all = 07, all = 0777, set_uid = 04000, set_gid = 02000, sticky_bit = 01000, mask = 07777, unknown = 0xffff }; // [fs.enum.perm.opts] enum class perm_options : uint16_t { replace = 3, add = 1, remove = 2, nofollow = 4, }; // [fs.enum.copy.opts] enum class copy_options : uint16_t { none = 0, skip_existing = 1, overwrite_existing = 2, update_existing = 4, recursive = 8, copy_symlinks = 0x10, skip_symlinks = 0x20, directories_only = 0x40, create_symlinks = 0x80, #ifndef GHC_OS_WEB create_hard_links = 0x100 #endif }; // [fs.enum.dir.opts] enum class directory_options : uint16_t { none = 0, follow_directory_symlink = 1, skip_permission_denied = 2, }; // [fs.class.file_status] class file_status class GHC_FS_API_CLASS file_status { public: // [fs.file_status.cons] constructors and destructor file_status() noexcept; explicit file_status(file_type ft, perms prms = perms::unknown) noexcept; file_status(const file_status&) noexcept; file_status(file_status&&) noexcept; ~file_status(); // assignments: file_status& operator=(const file_status&) noexcept; file_status& operator=(file_status&&) noexcept; // [fs.file_status.mods] modifiers void type(file_type ft) noexcept; void permissions(perms prms) noexcept; // [fs.file_status.obs] observers file_type type() const noexcept; perms permissions() const noexcept; friend bool operator==(const file_status& lhs, const file_status& rhs) noexcept { return lhs.type() == rhs.type() && lhs.permissions() == rhs.permissions(); } private: file_type _type; perms _perms; }; using file_time_type = std::chrono::time_point; // [fs.class.directory_entry] Class directory_entry class GHC_FS_API_CLASS directory_entry { public: // [fs.dir.entry.cons] constructors and destructor directory_entry() noexcept = default; directory_entry(const directory_entry&) = default; directory_entry(directory_entry&&) noexcept = default; #ifdef GHC_WITH_EXCEPTIONS explicit directory_entry(const path& p); #endif directory_entry(const path& p, std::error_code& ec); ~directory_entry(); // assignments: directory_entry& operator=(const directory_entry&) = default; directory_entry& operator=(directory_entry&&) noexcept = default; // [fs.dir.entry.mods] modifiers #ifdef GHC_WITH_EXCEPTIONS void assign(const path& p); void replace_filename(const path& p); void refresh(); #endif void assign(const path& p, std::error_code& ec); void replace_filename(const path& p, std::error_code& ec); void refresh(std::error_code& ec) noexcept; // [fs.dir.entry.obs] observers const filesystem::path& path() const noexcept; operator const filesystem::path&() const noexcept; #ifdef GHC_WITH_EXCEPTIONS bool exists() const; bool is_block_file() const; bool is_character_file() const; bool is_directory() const; bool is_fifo() const; bool is_other() const; bool is_regular_file() const; bool is_socket() const; bool is_symlink() const; uintmax_t file_size() const; file_time_type last_write_time() const; file_status status() const; file_status symlink_status() const; #endif bool exists(std::error_code& ec) const noexcept; bool is_block_file(std::error_code& ec) const noexcept; bool is_character_file(std::error_code& ec) const noexcept; bool is_directory(std::error_code& ec) const noexcept; bool is_fifo(std::error_code& ec) const noexcept; bool is_other(std::error_code& ec) const noexcept; bool is_regular_file(std::error_code& ec) const noexcept; bool is_socket(std::error_code& ec) const noexcept; bool is_symlink(std::error_code& ec) const noexcept; uintmax_t file_size(std::error_code& ec) const noexcept; file_time_type last_write_time(std::error_code& ec) const noexcept; file_status status(std::error_code& ec) const noexcept; file_status symlink_status(std::error_code& ec) const noexcept; #ifndef GHC_OS_WEB #ifdef GHC_WITH_EXCEPTIONS uintmax_t hard_link_count() const; #endif uintmax_t hard_link_count(std::error_code& ec) const noexcept; #endif #ifdef GHC_HAS_THREEWAY_COMP std::strong_ordering operator<=>(const directory_entry& rhs) const noexcept; #endif bool operator<(const directory_entry& rhs) const noexcept; bool operator==(const directory_entry& rhs) const noexcept; bool operator!=(const directory_entry& rhs) const noexcept; bool operator<=(const directory_entry& rhs) const noexcept; bool operator>(const directory_entry& rhs) const noexcept; bool operator>=(const directory_entry& rhs) const noexcept; private: friend class directory_iterator; #ifdef GHC_WITH_EXCEPTIONS file_type status_file_type() const; #endif file_type status_file_type(std::error_code& ec) const noexcept; filesystem::path _path; file_status _status; file_status _symlink_status; uintmax_t _file_size = static_cast(-1); #ifndef GHC_OS_WINDOWS uintmax_t _hard_link_count = static_cast(-1); #endif time_t _last_write_time = 0; }; // [fs.class.directory.iterator] Class directory_iterator class GHC_FS_API_CLASS directory_iterator { public: class GHC_FS_API_CLASS proxy { public: const directory_entry& operator*() const& noexcept { return _dir_entry; } directory_entry operator*() && noexcept { return std::move(_dir_entry); } private: explicit proxy(const directory_entry& dir_entry) : _dir_entry(dir_entry) { } friend class directory_iterator; friend class recursive_directory_iterator; directory_entry _dir_entry; }; using iterator_category = std::input_iterator_tag; using value_type = directory_entry; using difference_type = std::ptrdiff_t; using pointer = const directory_entry*; using reference = const directory_entry&; // [fs.dir.itr.members] member functions directory_iterator() noexcept; #ifdef GHC_WITH_EXCEPTIONS explicit directory_iterator(const path& p); directory_iterator(const path& p, directory_options options); #endif directory_iterator(const path& p, std::error_code& ec) noexcept; directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept; directory_iterator(const directory_iterator& rhs); directory_iterator(directory_iterator&& rhs) noexcept; ~directory_iterator(); directory_iterator& operator=(const directory_iterator& rhs); directory_iterator& operator=(directory_iterator&& rhs) noexcept; const directory_entry& operator*() const; const directory_entry* operator->() const; #ifdef GHC_WITH_EXCEPTIONS directory_iterator& operator++(); #endif directory_iterator& increment(std::error_code& ec) noexcept; // other members as required by [input.iterators] #ifdef GHC_WITH_EXCEPTIONS proxy operator++(int) { proxy p{**this}; ++*this; return p; } #endif bool operator==(const directory_iterator& rhs) const; bool operator!=(const directory_iterator& rhs) const; private: friend class recursive_directory_iterator; class impl; std::shared_ptr _impl; }; // [fs.dir.itr.nonmembers] directory_iterator non-member functions GHC_FS_API directory_iterator begin(directory_iterator iter) noexcept; GHC_FS_API directory_iterator end(const directory_iterator&) noexcept; // [fs.class.re.dir.itr] class recursive_directory_iterator class GHC_FS_API_CLASS recursive_directory_iterator { public: using iterator_category = std::input_iterator_tag; using value_type = directory_entry; using difference_type = std::ptrdiff_t; using pointer = const directory_entry*; using reference = const directory_entry&; // [fs.rec.dir.itr.members] constructors and destructor recursive_directory_iterator() noexcept; #ifdef GHC_WITH_EXCEPTIONS explicit recursive_directory_iterator(const path& p); recursive_directory_iterator(const path& p, directory_options options); #endif recursive_directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept; recursive_directory_iterator(const path& p, std::error_code& ec) noexcept; recursive_directory_iterator(const recursive_directory_iterator& rhs); recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept; ~recursive_directory_iterator(); // [fs.rec.dir.itr.members] observers directory_options options() const; int depth() const; bool recursion_pending() const; const directory_entry& operator*() const; const directory_entry* operator->() const; // [fs.rec.dir.itr.members] modifiers recursive_directory_iterator& recursive_directory_iterator& operator=(const recursive_directory_iterator& rhs); recursive_directory_iterator& operator=(recursive_directory_iterator&& rhs) noexcept; #ifdef GHC_WITH_EXCEPTIONS recursive_directory_iterator& operator++(); #endif recursive_directory_iterator& increment(std::error_code& ec) noexcept; #ifdef GHC_WITH_EXCEPTIONS void pop(); #endif void pop(std::error_code& ec); void disable_recursion_pending(); // other members as required by [input.iterators] #ifdef GHC_WITH_EXCEPTIONS directory_iterator::proxy operator++(int) { directory_iterator::proxy proxy{**this}; ++*this; return proxy; } #endif bool operator==(const recursive_directory_iterator& rhs) const; bool operator!=(const recursive_directory_iterator& rhs) const; private: struct recursive_directory_iterator_impl { directory_options _options; bool _recursion_pending; std::stack _dir_iter_stack; recursive_directory_iterator_impl(directory_options options, bool recursion_pending) : _options(options) , _recursion_pending(recursion_pending) { } }; std::shared_ptr _impl; }; // [fs.rec.dir.itr.nonmembers] directory_iterator non-member functions GHC_FS_API recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept; GHC_FS_API recursive_directory_iterator end(const recursive_directory_iterator&) noexcept; // [fs.op.funcs] filesystem operations #ifdef GHC_WITH_EXCEPTIONS GHC_FS_API path absolute(const path& p); GHC_FS_API path canonical(const path& p); GHC_FS_API void copy(const path& from, const path& to); GHC_FS_API void copy(const path& from, const path& to, copy_options options); GHC_FS_API bool copy_file(const path& from, const path& to); GHC_FS_API bool copy_file(const path& from, const path& to, copy_options option); GHC_FS_API void copy_symlink(const path& existing_symlink, const path& new_symlink); GHC_FS_API bool create_directories(const path& p); GHC_FS_API bool create_directory(const path& p); GHC_FS_API bool create_directory(const path& p, const path& attributes); GHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink); GHC_FS_API void create_symlink(const path& to, const path& new_symlink); GHC_FS_API path current_path(); GHC_FS_API void current_path(const path& p); GHC_FS_API bool exists(const path& p); GHC_FS_API bool equivalent(const path& p1, const path& p2); GHC_FS_API uintmax_t file_size(const path& p); GHC_FS_API bool is_block_file(const path& p); GHC_FS_API bool is_character_file(const path& p); GHC_FS_API bool is_directory(const path& p); GHC_FS_API bool is_empty(const path& p); GHC_FS_API bool is_fifo(const path& p); GHC_FS_API bool is_other(const path& p); GHC_FS_API bool is_regular_file(const path& p); GHC_FS_API bool is_socket(const path& p); GHC_FS_API bool is_symlink(const path& p); GHC_FS_API file_time_type last_write_time(const path& p); GHC_FS_API void last_write_time(const path& p, file_time_type new_time); GHC_FS_API void permissions(const path& p, perms prms, perm_options opts = perm_options::replace); GHC_FS_API path proximate(const path& p, const path& base = current_path()); GHC_FS_API path read_symlink(const path& p); GHC_FS_API path relative(const path& p, const path& base = current_path()); GHC_FS_API bool remove(const path& p); GHC_FS_API uintmax_t remove_all(const path& p); GHC_FS_API void rename(const path& from, const path& to); GHC_FS_API void resize_file(const path& p, uintmax_t size); GHC_FS_API space_info space(const path& p); GHC_FS_API file_status status(const path& p); GHC_FS_API file_status symlink_status(const path& p); GHC_FS_API path temp_directory_path(); GHC_FS_API path weakly_canonical(const path& p); #endif GHC_FS_API path absolute(const path& p, std::error_code& ec); GHC_FS_API path canonical(const path& p, std::error_code& ec); GHC_FS_API void copy(const path& from, const path& to, std::error_code& ec) noexcept; GHC_FS_API void copy(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept; GHC_FS_API bool copy_file(const path& from, const path& to, std::error_code& ec) noexcept; GHC_FS_API bool copy_file(const path& from, const path& to, copy_options option, std::error_code& ec) noexcept; GHC_FS_API void copy_symlink(const path& existing_symlink, const path& new_symlink, std::error_code& ec) noexcept; GHC_FS_API bool create_directories(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool create_directory(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool create_directory(const path& p, const path& attributes, std::error_code& ec) noexcept; GHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept; GHC_FS_API void create_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept; GHC_FS_API path current_path(std::error_code& ec); GHC_FS_API void current_path(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool exists(file_status s) noexcept; GHC_FS_API bool exists(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool equivalent(const path& p1, const path& p2, std::error_code& ec) noexcept; GHC_FS_API uintmax_t file_size(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool is_block_file(file_status s) noexcept; GHC_FS_API bool is_block_file(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool is_character_file(file_status s) noexcept; GHC_FS_API bool is_character_file(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool is_directory(file_status s) noexcept; GHC_FS_API bool is_directory(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool is_empty(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool is_fifo(file_status s) noexcept; GHC_FS_API bool is_fifo(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool is_other(file_status s) noexcept; GHC_FS_API bool is_other(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool is_regular_file(file_status s) noexcept; GHC_FS_API bool is_regular_file(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool is_socket(file_status s) noexcept; GHC_FS_API bool is_socket(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool is_symlink(file_status s) noexcept; GHC_FS_API bool is_symlink(const path& p, std::error_code& ec) noexcept; GHC_FS_API file_time_type last_write_time(const path& p, std::error_code& ec) noexcept; GHC_FS_API void last_write_time(const path& p, file_time_type new_time, std::error_code& ec) noexcept; GHC_FS_API void permissions(const path& p, perms prms, std::error_code& ec) noexcept; GHC_FS_API void permissions(const path& p, perms prms, perm_options opts, std::error_code& ec) noexcept; GHC_FS_API path proximate(const path& p, std::error_code& ec); GHC_FS_API path proximate(const path& p, const path& base, std::error_code& ec); GHC_FS_API path read_symlink(const path& p, std::error_code& ec); GHC_FS_API path relative(const path& p, std::error_code& ec); GHC_FS_API path relative(const path& p, const path& base, std::error_code& ec); GHC_FS_API bool remove(const path& p, std::error_code& ec) noexcept; GHC_FS_API uintmax_t remove_all(const path& p, std::error_code& ec) noexcept; GHC_FS_API void rename(const path& from, const path& to, std::error_code& ec) noexcept; GHC_FS_API void resize_file(const path& p, uintmax_t size, std::error_code& ec) noexcept; GHC_FS_API space_info space(const path& p, std::error_code& ec) noexcept; GHC_FS_API file_status status(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool status_known(file_status s) noexcept; GHC_FS_API file_status symlink_status(const path& p, std::error_code& ec) noexcept; GHC_FS_API path temp_directory_path(std::error_code& ec) noexcept; GHC_FS_API path weakly_canonical(const path& p, std::error_code& ec) noexcept; #ifndef GHC_OS_WEB #ifdef GHC_WITH_EXCEPTIONS GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link); GHC_FS_API uintmax_t hard_link_count(const path& p); #endif GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link, std::error_code& ec) noexcept; GHC_FS_API uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept; #endif // Non-C++17 add-on std::fstream wrappers with path template > class basic_filebuf : public std::basic_filebuf { public: basic_filebuf() {} ~basic_filebuf() override {} basic_filebuf(const basic_filebuf&) = delete; const basic_filebuf& operator=(const basic_filebuf&) = delete; basic_filebuf* open(const path& p, std::ios_base::openmode mode) { #if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__) return std::basic_filebuf::open(p.wstring().c_str(), mode) ? this : 0; #else return std::basic_filebuf::open(p.string().c_str(), mode) ? this : 0; #endif } }; template > class basic_ifstream : public std::basic_ifstream { public: basic_ifstream() {} #if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__) explicit basic_ifstream(const path& p, std::ios_base::openmode mode = std::ios_base::in) : std::basic_ifstream(p.wstring().c_str(), mode) { } void open(const path& p, std::ios_base::openmode mode = std::ios_base::in) { std::basic_ifstream::open(p.wstring().c_str(), mode); } #else explicit basic_ifstream(const path& p, std::ios_base::openmode mode = std::ios_base::in) : std::basic_ifstream(p.string().c_str(), mode) { } void open(const path& p, std::ios_base::openmode mode = std::ios_base::in) { std::basic_ifstream::open(p.string().c_str(), mode); } #endif basic_ifstream(const basic_ifstream&) = delete; const basic_ifstream& operator=(const basic_ifstream&) = delete; ~basic_ifstream() override {} }; template > class basic_ofstream : public std::basic_ofstream { public: basic_ofstream() {} #if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__) explicit basic_ofstream(const path& p, std::ios_base::openmode mode = std::ios_base::out) : std::basic_ofstream(p.wstring().c_str(), mode) { } void open(const path& p, std::ios_base::openmode mode = std::ios_base::out) { std::basic_ofstream::open(p.wstring().c_str(), mode); } #else explicit basic_ofstream(const path& p, std::ios_base::openmode mode = std::ios_base::out) : std::basic_ofstream(p.string().c_str(), mode) { } void open(const path& p, std::ios_base::openmode mode = std::ios_base::out) { std::basic_ofstream::open(p.string().c_str(), mode); } #endif basic_ofstream(const basic_ofstream&) = delete; const basic_ofstream& operator=(const basic_ofstream&) = delete; ~basic_ofstream() override {} }; template > class basic_fstream : public std::basic_fstream { public: basic_fstream() {} #if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__) explicit basic_fstream(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_fstream(p.wstring().c_str(), mode) { } void open(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { std::basic_fstream::open(p.wstring().c_str(), mode); } #else explicit basic_fstream(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_fstream(p.string().c_str(), mode) { } void open(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { std::basic_fstream::open(p.string().c_str(), mode); } #endif basic_fstream(const basic_fstream&) = delete; const basic_fstream& operator=(const basic_fstream&) = delete; ~basic_fstream() override {} }; typedef basic_filebuf filebuf; typedef basic_filebuf wfilebuf; typedef basic_ifstream ifstream; typedef basic_ifstream wifstream; typedef basic_ofstream ofstream; typedef basic_ofstream wofstream; typedef basic_fstream fstream; typedef basic_fstream wfstream; class GHC_FS_API_CLASS u8arguments { public: u8arguments(int& argc, char**& argv); ~u8arguments() { _refargc = _argc; _refargv = _argv; } bool valid() const { return _isvalid; } private: int _argc; char** _argv; int& _refargc; char**& _refargv; bool _isvalid; #ifdef GHC_OS_WINDOWS std::vector _args; std::vector _argp; #endif }; //------------------------------------------------------------------------------------------------- // Implementation //------------------------------------------------------------------------------------------------- namespace detail { enum utf8_states_t { S_STRT = 0, S_RJCT = 8 }; GHC_FS_API void appendUTF8(std::string& str, uint32_t unicode); GHC_FS_API bool is_surrogate(uint32_t c); GHC_FS_API bool is_high_surrogate(uint32_t c); GHC_FS_API bool is_low_surrogate(uint32_t c); GHC_FS_API unsigned consumeUtf8Fragment(const unsigned state, const uint8_t fragment, uint32_t& codepoint); enum class portable_error { none = 0, exists, not_found, not_supported, not_implemented, invalid_argument, is_a_directory, }; GHC_FS_API std::error_code make_error_code(portable_error err); #ifdef GHC_OS_WINDOWS GHC_FS_API std::error_code make_system_error(uint32_t err = 0); #else GHC_FS_API std::error_code make_system_error(int err = 0); template struct has_d_type : std::false_type{}; template struct has_d_type : std::true_type {}; template GHC_INLINE file_type file_type_from_dirent_impl(const T&, std::false_type) { return file_type::none; } template GHC_INLINE file_type file_type_from_dirent_impl(const T& t, std::true_type) { switch (t.d_type) { #ifdef DT_BLK case DT_BLK: return file_type::block; #endif #ifdef DT_CHR case DT_CHR: return file_type::character; #endif #ifdef DT_DIR case DT_DIR: return file_type::directory; #endif #ifdef DT_FIFO case DT_FIFO: return file_type::fifo; #endif #ifdef DT_LNK case DT_LNK: return file_type::symlink; #endif #ifdef DT_REG case DT_REG: return file_type::regular; #endif #ifdef DT_SOCK case DT_SOCK: return file_type::socket; #endif #ifdef DT_UNKNOWN case DT_UNKNOWN: return file_type::none; #endif default: return file_type::unknown; } } template GHC_INLINE file_type file_type_from_dirent(const T& t) { return file_type_from_dirent_impl(t, has_d_type{}); } #endif } // namespace detail namespace detail { #ifdef GHC_EXPAND_IMPL GHC_INLINE std::error_code make_error_code(portable_error err) { #ifdef GHC_OS_WINDOWS switch (err) { case portable_error::none: return std::error_code(); case portable_error::exists: return std::error_code(ERROR_ALREADY_EXISTS, std::system_category()); case portable_error::not_found: return std::error_code(ERROR_PATH_NOT_FOUND, std::system_category()); case portable_error::not_supported: return std::error_code(ERROR_NOT_SUPPORTED, std::system_category()); case portable_error::not_implemented: return std::error_code(ERROR_CALL_NOT_IMPLEMENTED, std::system_category()); case portable_error::invalid_argument: return std::error_code(ERROR_INVALID_PARAMETER, std::system_category()); case portable_error::is_a_directory: #ifdef ERROR_DIRECTORY_NOT_SUPPORTED return std::error_code(ERROR_DIRECTORY_NOT_SUPPORTED, std::system_category()); #else return std::error_code(ERROR_NOT_SUPPORTED, std::system_category()); #endif } #else switch (err) { case portable_error::none: return std::error_code(); case portable_error::exists: return std::error_code(EEXIST, std::system_category()); case portable_error::not_found: return std::error_code(ENOENT, std::system_category()); case portable_error::not_supported: return std::error_code(ENOTSUP, std::system_category()); case portable_error::not_implemented: return std::error_code(ENOSYS, std::system_category()); case portable_error::invalid_argument: return std::error_code(EINVAL, std::system_category()); case portable_error::is_a_directory: return std::error_code(EISDIR, std::system_category()); } #endif return std::error_code(); } #ifdef GHC_OS_WINDOWS GHC_INLINE std::error_code make_system_error(uint32_t err) { return std::error_code(err ? static_cast(err) : static_cast(::GetLastError()), std::system_category()); } #else GHC_INLINE std::error_code make_system_error(int err) { return std::error_code(err ? err : errno, std::system_category()); } #endif #endif // GHC_EXPAND_IMPL template using EnableBitmask = typename std::enable_if::value || std::is_same::value || std::is_same::value || std::is_same::value, Enum>::type; } // namespace detail template constexpr detail::EnableBitmask operator&(Enum X, Enum Y) { using underlying = typename std::underlying_type::type; return static_cast(static_cast(X) & static_cast(Y)); } template constexpr detail::EnableBitmask operator|(Enum X, Enum Y) { using underlying = typename std::underlying_type::type; return static_cast(static_cast(X) | static_cast(Y)); } template constexpr detail::EnableBitmask operator^(Enum X, Enum Y) { using underlying = typename std::underlying_type::type; return static_cast(static_cast(X) ^ static_cast(Y)); } template constexpr detail::EnableBitmask operator~(Enum X) { using underlying = typename std::underlying_type::type; return static_cast(~static_cast(X)); } template detail::EnableBitmask& operator&=(Enum& X, Enum Y) { X = X & Y; return X; } template detail::EnableBitmask& operator|=(Enum& X, Enum Y) { X = X | Y; return X; } template detail::EnableBitmask& operator^=(Enum& X, Enum Y) { X = X ^ Y; return X; } #ifdef GHC_EXPAND_IMPL namespace detail { GHC_INLINE bool in_range(uint32_t c, uint32_t lo, uint32_t hi) { return (static_cast(c - lo) < (hi - lo + 1)); } GHC_INLINE bool is_surrogate(uint32_t c) { return in_range(c, 0xd800, 0xdfff); } GHC_INLINE bool is_high_surrogate(uint32_t c) { return (c & 0xfffffc00) == 0xd800; } GHC_INLINE bool is_low_surrogate(uint32_t c) { return (c & 0xfffffc00) == 0xdc00; } GHC_INLINE void appendUTF8(std::string& str, uint32_t unicode) { if (unicode <= 0x7f) { str.push_back(static_cast(unicode)); } else if (unicode >= 0x80 && unicode <= 0x7ff) { str.push_back(static_cast((unicode >> 6) + 192)); str.push_back(static_cast((unicode & 0x3f) + 128)); } else if ((unicode >= 0x800 && unicode <= 0xd7ff) || (unicode >= 0xe000 && unicode <= 0xffff)) { str.push_back(static_cast((unicode >> 12) + 224)); str.push_back(static_cast(((unicode & 0xfff) >> 6) + 128)); str.push_back(static_cast((unicode & 0x3f) + 128)); } else if (unicode >= 0x10000 && unicode <= 0x10ffff) { str.push_back(static_cast((unicode >> 18) + 240)); str.push_back(static_cast(((unicode & 0x3ffff) >> 12) + 128)); str.push_back(static_cast(((unicode & 0xfff) >> 6) + 128)); str.push_back(static_cast((unicode & 0x3f) + 128)); } else { #ifdef GHC_RAISE_UNICODE_ERRORS throw filesystem_error("Illegal code point for unicode character.", str, std::make_error_code(std::errc::illegal_byte_sequence)); #else appendUTF8(str, 0xfffd); #endif } } // Thanks to Bjoern Hoehrmann (https://bjoern.hoehrmann.de/utf-8/decoder/dfa/) // and Taylor R Campbell for the ideas to this DFA approach of UTF-8 decoding; // Generating debugging and shrinking my own DFA from scratch was a day of fun! GHC_INLINE unsigned consumeUtf8Fragment(const unsigned state, const uint8_t fragment, uint32_t& codepoint) { static const uint32_t utf8_state_info[] = { // encoded states 0x11111111u, 0x11111111u, 0x77777777u, 0x77777777u, 0x88888888u, 0x88888888u, 0x88888888u, 0x88888888u, 0x22222299u, 0x22222222u, 0x22222222u, 0x22222222u, 0x3333333au, 0x33433333u, 0x9995666bu, 0x99999999u, 0x88888880u, 0x22818108u, 0x88888881u, 0x88888882u, 0x88888884u, 0x88888887u, 0x88888886u, 0x82218108u, 0x82281108u, 0x88888888u, 0x88888883u, 0x88888885u, 0u, 0u, 0u, 0u, }; uint8_t category = fragment < 128 ? 0 : (utf8_state_info[(fragment >> 3) & 0xf] >> ((fragment & 7) << 2)) & 0xf; codepoint = (state ? (codepoint << 6) | (fragment & 0x3fu) : (0xffu >> category) & fragment); return state == S_RJCT ? static_cast(S_RJCT) : static_cast((utf8_state_info[category + 16] >> (state << 2)) & 0xf); } GHC_INLINE bool validUtf8(const std::string& utf8String) { std::string::const_iterator iter = utf8String.begin(); unsigned utf8_state = S_STRT; std::uint32_t codepoint = 0; while (iter < utf8String.end()) { if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast(*iter++), codepoint)) == S_RJCT) { return false; } } if (utf8_state) { return false; } return true; } } // namespace detail #endif namespace detail { template ::value && (sizeof(typename Utf8String::value_type) == 1) && (sizeof(typename StringType::value_type) == 1)>::type* = nullptr> inline StringType fromUtf8(const Utf8String& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) { return StringType(utf8String.begin(), utf8String.end(), alloc); } template ::value && (sizeof(typename Utf8String::value_type) == 1) && (sizeof(typename StringType::value_type) == 2)>::type* = nullptr> inline StringType fromUtf8(const Utf8String& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) { StringType result(alloc); result.reserve(utf8String.length()); auto iter = utf8String.cbegin(); unsigned utf8_state = S_STRT; std::uint32_t codepoint = 0; while (iter < utf8String.cend()) { if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast(*iter++), codepoint)) == S_STRT) { if (codepoint <= 0xffff) { result += static_cast(codepoint); } else { codepoint -= 0x10000; result += static_cast((codepoint >> 10) + 0xd800); result += static_cast((codepoint & 0x3ff) + 0xdc00); } codepoint = 0; } else if (utf8_state == S_RJCT) { #ifdef GHC_RAISE_UNICODE_ERRORS throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence)); #else result += static_cast(0xfffd); utf8_state = S_STRT; codepoint = 0; #endif } } if (utf8_state) { #ifdef GHC_RAISE_UNICODE_ERRORS throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence)); #else result += static_cast(0xfffd); #endif } return result; } template ::value && (sizeof(typename Utf8String::value_type) == 1) && (sizeof(typename StringType::value_type) == 4)>::type* = nullptr> inline StringType fromUtf8(const Utf8String& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) { StringType result(alloc); result.reserve(utf8String.length()); auto iter = utf8String.cbegin(); unsigned utf8_state = S_STRT; std::uint32_t codepoint = 0; while (iter < utf8String.cend()) { if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast(*iter++), codepoint)) == S_STRT) { result += static_cast(codepoint); codepoint = 0; } else if (utf8_state == S_RJCT) { #ifdef GHC_RAISE_UNICODE_ERRORS throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence)); #else result += static_cast(0xfffd); utf8_state = S_STRT; codepoint = 0; #endif } } if (utf8_state) { #ifdef GHC_RAISE_UNICODE_ERRORS throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence)); #else result += static_cast(0xfffd); #endif } return result; } template inline StringType fromUtf8(const charT (&utf8String)[N]) { #ifdef GHC_WITH_STRING_VIEW return fromUtf8(basic_string_view(utf8String, N - 1)); #else return fromUtf8(std::basic_string(utf8String, N - 1)); #endif } template ::value && (sizeof(typename strT::value_type) == 1), int>::type size = 1> inline std::string toUtf8(const strT& unicodeString) { return std::string(unicodeString.begin(), unicodeString.end()); } template ::value && (sizeof(typename strT::value_type) == 2), int>::type size = 2> inline std::string toUtf8(const strT& unicodeString) { std::string result; for (auto iter = unicodeString.begin(); iter != unicodeString.end(); ++iter) { char32_t c = *iter; if (is_surrogate(c)) { ++iter; if (iter != unicodeString.end() && is_high_surrogate(c) && is_low_surrogate(*iter)) { appendUTF8(result, (char32_t(c) << 10) + *iter - 0x35fdc00); } else { #ifdef GHC_RAISE_UNICODE_ERRORS throw filesystem_error("Illegal code point for unicode character.", result, std::make_error_code(std::errc::illegal_byte_sequence)); #else appendUTF8(result, 0xfffd); if (iter == unicodeString.end()) { break; } #endif } } else { appendUTF8(result, c); } } return result; } template ::value && (sizeof(typename strT::value_type) == 4), int>::type size = 4> inline std::string toUtf8(const strT& unicodeString) { std::string result; for (auto c : unicodeString) { appendUTF8(result, static_cast(c)); } return result; } template inline std::string toUtf8(const charT* unicodeString) { #ifdef GHC_WITH_STRING_VIEW return toUtf8(basic_string_view>(unicodeString)); #else return toUtf8(std::basic_string>(unicodeString)); #endif } #ifdef GHC_USE_WCHAR_T template ::value && (sizeof(typename WString::value_type) == 2) && (sizeof(typename StringType::value_type) == 1), bool>::type = false> inline StringType fromWChar(const WString& wString, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) { auto temp = toUtf8(wString); return StringType(temp.begin(), temp.end(), alloc); } template ::value && (sizeof(typename WString::value_type) == 2) && (sizeof(typename StringType::value_type) == 2), bool>::type = false> inline StringType fromWChar(const WString& wString, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) { return StringType(wString.begin(), wString.end(), alloc); } template ::value && (sizeof(typename WString::value_type) == 2) && (sizeof(typename StringType::value_type) == 4), bool>::type = false> inline StringType fromWChar(const WString& wString, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) { auto temp = toUtf8(wString); return fromUtf8(temp, alloc); } template ::value && (sizeof(typename strT::value_type) == 1), bool>::type = false> inline std::wstring toWChar(const strT& unicodeString) { return fromUtf8(unicodeString); } template ::value && (sizeof(typename strT::value_type) == 2), bool>::type = false> inline std::wstring toWChar(const strT& unicodeString) { return std::wstring(unicodeString.begin(), unicodeString.end()); } template ::value && (sizeof(typename strT::value_type) == 4), bool>::type = false> inline std::wstring toWChar(const strT& unicodeString) { auto temp = toUtf8(unicodeString); return fromUtf8(temp); } template inline std::wstring toWChar(const charT* unicodeString) { #ifdef GHC_WITH_STRING_VIEW return toWChar(basic_string_view>(unicodeString)); #else return toWChar(std::basic_string>(unicodeString)); #endif } #endif // GHC_USE_WCHAR_T } // namespace detail #ifdef GHC_EXPAND_IMPL namespace detail { template ::value, bool>::type = true> GHC_INLINE bool startsWith(const strT& what, const strT& with) { return with.length() <= what.length() && equal(with.begin(), with.end(), what.begin()); } template ::value, bool>::type = true> GHC_INLINE bool endsWith(const strT& what, const strT& with) { return with.length() <= what.length() && what.compare(what.length() - with.length(), with.size(), with) == 0; } } // namespace detail GHC_INLINE void path::check_long_path() { #if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) if (is_absolute() && _path.length() >= MAX_PATH - 12 && !detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL("\\\\?\\")))) { postprocess_path_with_format(native_format); } #endif } GHC_INLINE void path::postprocess_path_with_format(path::format fmt) { #ifdef GHC_RAISE_UNICODE_ERRORS if (!detail::validUtf8(_path)) { path t; t._path = _path; throw filesystem_error("Illegal byte sequence for unicode character.", t, std::make_error_code(std::errc::illegal_byte_sequence)); } #endif switch (fmt) { #ifdef GHC_OS_WINDOWS case path::native_format: case path::auto_format: case path::generic_format: for (auto& c : _path) { if (c == generic_separator) { c = preferred_separator; } } #ifdef GHC_WIN_AUTO_PREFIX_LONG_PATH if (is_absolute() && _path.length() >= MAX_PATH - 12 && !detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL("\\\\?\\")))) { _path = GHC_PLATFORM_LITERAL("\\\\?\\") + _path; } #endif handle_prefixes(); break; #else case path::auto_format: case path::native_format: case path::generic_format: // nothing to do break; #endif } if (_path.length() > _prefixLength + 2 && _path[_prefixLength] == preferred_separator && _path[_prefixLength + 1] == preferred_separator && _path[_prefixLength + 2] != preferred_separator) { impl_string_type::iterator new_end = std::unique(_path.begin() + static_cast(_prefixLength) + 2, _path.end(), [](path::value_type lhs, path::value_type rhs) { return lhs == rhs && lhs == preferred_separator; }); _path.erase(new_end, _path.end()); } else { impl_string_type::iterator new_end = std::unique(_path.begin() + static_cast(_prefixLength), _path.end(), [](path::value_type lhs, path::value_type rhs) { return lhs == rhs && lhs == preferred_separator; }); _path.erase(new_end, _path.end()); } } #endif // GHC_EXPAND_IMPL template inline path::path(const Source& source, format fmt) #ifdef GHC_USE_WCHAR_T : _path(detail::toWChar(source)) #else : _path(detail::toUtf8(source)) #endif { postprocess_path_with_format(fmt); } template inline path u8path(const Source& source) { return path(source); } template inline path u8path(InputIterator first, InputIterator last) { return path(first, last); } template inline path::path(InputIterator first, InputIterator last, format fmt) : path(std::basic_string::value_type>(first, last), fmt) { // delegated } #ifdef GHC_EXPAND_IMPL namespace detail { GHC_INLINE bool equals_simple_insensitive(const path::value_type* str1, const path::value_type* str2) { #ifdef GHC_OS_WINDOWS #ifdef __GNUC__ while (::tolower((unsigned char)*str1) == ::tolower((unsigned char)*str2++)) { if (*str1++ == 0) return true; } return false; #else // __GNUC__ #ifdef GHC_USE_WCHAR_T return 0 == ::_wcsicmp(str1, str2); #else // GHC_USE_WCHAR_T return 0 == ::_stricmp(str1, str2); #endif // GHC_USE_WCHAR_T #endif // __GNUC__ #else // GHC_OS_WINDOWS return 0 == ::strcasecmp(str1, str2); #endif // GHC_OS_WINDOWS } GHC_INLINE int compare_simple_insensitive(const path::value_type* str1, size_t len1, const path::value_type* str2, size_t len2) { while (len1 > 0 && len2 > 0 && ::tolower(static_cast(*str1)) == ::tolower(static_cast(*str2))) { --len1; --len2; ++str1; ++str2; } if (len1 && len2) { return *str1 < *str2 ? -1 : 1; } if (len1 == 0 && len2 == 0) { return 0; } return len1 == 0 ? -1 : 1; } GHC_INLINE const char* strerror_adapter(char* gnu, char*) { return gnu; } GHC_INLINE const char* strerror_adapter(int posix, char* buffer) { if (posix) { return "Error in strerror_r!"; } return buffer; } template GHC_INLINE std::string systemErrorText(ErrorNumber code = 0) { #if defined(GHC_OS_WINDOWS) LPVOID msgBuf; DWORD dw = code ? static_cast(code) : ::GetLastError(); FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&msgBuf, 0, NULL); std::string msg = toUtf8(std::wstring((LPWSTR)msgBuf)); LocalFree(msgBuf); return msg; #else char buffer[512]; return strerror_adapter(strerror_r(code ? code : errno, buffer, sizeof(buffer)), buffer); #endif } #ifdef GHC_OS_WINDOWS using CreateSymbolicLinkW_fp = BOOLEAN(WINAPI*)(LPCWSTR, LPCWSTR, DWORD); using CreateHardLinkW_fp = BOOLEAN(WINAPI*)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES); GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, bool to_directory, std::error_code& ec) { std::error_code tec; auto fs = status(target_name, tec); if ((fs.type() == file_type::directory && !to_directory) || (fs.type() == file_type::regular && to_directory)) { ec = detail::make_error_code(detail::portable_error::not_supported); return; } #if defined(__GNUC__) && __GNUC__ >= 8 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-function-type" #endif static CreateSymbolicLinkW_fp api_call = reinterpret_cast(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateSymbolicLinkW")); #if defined(__GNUC__) && __GNUC__ >= 8 #pragma GCC diagnostic pop #endif if (api_call) { if (api_call(GHC_NATIVEWP(new_symlink), GHC_NATIVEWP(target_name), to_directory ? 1 : 0) == 0) { auto result = ::GetLastError(); if (result == ERROR_PRIVILEGE_NOT_HELD && api_call(GHC_NATIVEWP(new_symlink), GHC_NATIVEWP(target_name), to_directory ? 3 : 2) != 0) { return; } ec = detail::make_system_error(result); } } else { ec = detail::make_system_error(ERROR_NOT_SUPPORTED); } } GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlink, std::error_code& ec) { #if defined(__GNUC__) && __GNUC__ >= 8 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-function-type" #endif static CreateHardLinkW_fp api_call = reinterpret_cast(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW")); #if defined(__GNUC__) && __GNUC__ >= 8 #pragma GCC diagnostic pop #endif if (api_call) { if (api_call(GHC_NATIVEWP(new_hardlink), GHC_NATIVEWP(target_name), NULL) == 0) { ec = detail::make_system_error(); } } else { ec = detail::make_system_error(ERROR_NOT_SUPPORTED); } } GHC_INLINE path getFullPathName(const wchar_t* p, std::error_code& ec) { ULONG size = ::GetFullPathNameW(p, 0, 0, 0); if (size) { std::vector buf(size, 0); ULONG s2 = GetFullPathNameW(p, size, buf.data(), nullptr); if (s2 && s2 < size) { return path(std::wstring(buf.data(), s2)); } } ec = detail::make_system_error(); return path(); } #else GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, bool, std::error_code& ec) { if (::symlink(target_name.c_str(), new_symlink.c_str()) != 0) { ec = detail::make_system_error(); } } #ifndef GHC_OS_WEB GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlink, std::error_code& ec) { if (::link(target_name.c_str(), new_hardlink.c_str()) != 0) { ec = detail::make_system_error(); } } #endif #endif template GHC_INLINE file_status file_status_from_st_mode(T mode) { #ifdef GHC_OS_WINDOWS file_type ft = file_type::unknown; if ((mode & _S_IFDIR) == _S_IFDIR) { ft = file_type::directory; } else if ((mode & _S_IFREG) == _S_IFREG) { ft = file_type::regular; } else if ((mode & _S_IFCHR) == _S_IFCHR) { ft = file_type::character; } perms prms = static_cast(mode & 0xfff); return file_status(ft, prms); #else file_type ft = file_type::unknown; if (S_ISDIR(mode)) { ft = file_type::directory; } else if (S_ISREG(mode)) { ft = file_type::regular; } else if (S_ISCHR(mode)) { ft = file_type::character; } else if (S_ISBLK(mode)) { ft = file_type::block; } else if (S_ISFIFO(mode)) { ft = file_type::fifo; } else if (S_ISLNK(mode)) { ft = file_type::symlink; } else if (S_ISSOCK(mode)) { ft = file_type::socket; } perms prms = static_cast(mode & 0xfff); return file_status(ft, prms); #endif } #ifdef GHC_OS_WINDOWS class unique_handle { public: typedef HANDLE element_type; unique_handle() noexcept : _handle(INVALID_HANDLE_VALUE) { } explicit unique_handle(element_type h) noexcept : _handle(h) { } unique_handle(unique_handle&& u) noexcept : _handle(u.release()) { } ~unique_handle() { reset(); } unique_handle& operator=(unique_handle&& u) noexcept { reset(u.release()); return *this; } element_type get() const noexcept { return _handle; } explicit operator bool() const noexcept { return _handle != INVALID_HANDLE_VALUE; } element_type release() noexcept { element_type tmp = _handle; _handle = INVALID_HANDLE_VALUE; return tmp; } void reset(element_type h = INVALID_HANDLE_VALUE) noexcept { element_type tmp = _handle; _handle = h; if (tmp != INVALID_HANDLE_VALUE) { CloseHandle(tmp); } } void swap(unique_handle& u) noexcept { std::swap(_handle, u._handle); } private: element_type _handle; }; #ifndef REPARSE_DATA_BUFFER_HEADER_SIZE typedef struct _REPARSE_DATA_BUFFER { ULONG ReparseTag; USHORT ReparseDataLength; USHORT Reserved; union { struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; ULONG Flags; WCHAR PathBuffer[1]; } SymbolicLinkReparseBuffer; struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; WCHAR PathBuffer[1]; } MountPointReparseBuffer; struct { UCHAR DataBuffer[1]; } GenericReparseBuffer; } DUMMYUNIONNAME; } REPARSE_DATA_BUFFER; #ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE #define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024) #endif #endif template struct free_deleter { void operator()(T* p) const { std::free(p); } }; GHC_INLINE std::unique_ptr> getReparseData(const path& p, std::error_code& ec) { unique_handle file(CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0)); if (!file) { ec = detail::make_system_error(); return nullptr; } std::unique_ptr> reparseData(reinterpret_cast(std::calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE))); ULONG bufferUsed; if (DeviceIoControl(file.get(), FSCTL_GET_REPARSE_POINT, 0, 0, reparseData.get(), MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bufferUsed, 0)) { return reparseData; } else { ec = detail::make_system_error(); } return nullptr; } #endif GHC_INLINE path resolveSymlink(const path& p, std::error_code& ec) { #ifdef GHC_OS_WINDOWS path result; auto reparseData = detail::getReparseData(p, ec); if (!ec) { if (reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag)) { switch (reparseData->ReparseTag) { case IO_REPARSE_TAG_SYMLINK: { auto printName = std::wstring(&reparseData->SymbolicLinkReparseBuffer.PathBuffer[reparseData->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)], reparseData->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(WCHAR)); auto substituteName = std::wstring(&reparseData->SymbolicLinkReparseBuffer.PathBuffer[reparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)], reparseData->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR)); if (detail::endsWith(substituteName, printName) && detail::startsWith(substituteName, std::wstring(L"\\??\\"))) { result = printName; } else { result = substituteName; } if (reparseData->SymbolicLinkReparseBuffer.Flags & 0x1 /*SYMLINK_FLAG_RELATIVE*/) { result = p.parent_path() / result; } break; } case IO_REPARSE_TAG_MOUNT_POINT: result = detail::getFullPathName(GHC_NATIVEWP(p), ec); // result = std::wstring(&reparseData->MountPointReparseBuffer.PathBuffer[reparseData->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)], reparseData->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR)); break; default: break; } } } return result; #else size_t bufferSize = 256; while (true) { std::vector buffer(bufferSize, static_cast(0)); auto rc = ::readlink(p.c_str(), buffer.data(), buffer.size()); if (rc < 0) { ec = detail::make_system_error(); return path(); } else if (rc < static_cast(bufferSize)) { return path(std::string(buffer.data(), static_cast(rc))); } bufferSize *= 2; } return path(); #endif } #ifdef GHC_OS_WINDOWS GHC_INLINE time_t timeFromFILETIME(const FILETIME& ft) { ULARGE_INTEGER ull; ull.LowPart = ft.dwLowDateTime; ull.HighPart = ft.dwHighDateTime; return static_cast(ull.QuadPart / 10000000ULL - 11644473600ULL); } GHC_INLINE void timeToFILETIME(time_t t, FILETIME& ft) { LONGLONG ll; ll = Int32x32To64(t, 10000000) + 116444736000000000; ft.dwLowDateTime = static_cast(ll); ft.dwHighDateTime = static_cast(ll >> 32); } template GHC_INLINE uintmax_t hard_links_from_INFO(const INFO* info) { return static_cast(-1); } template <> GHC_INLINE uintmax_t hard_links_from_INFO(const BY_HANDLE_FILE_INFORMATION* info) { return info->nNumberOfLinks; } template GHC_INLINE DWORD reparse_tag_from_INFO(const INFO*) { return 0; } template <> GHC_INLINE DWORD reparse_tag_from_INFO(const WIN32_FIND_DATAW* info) { return info->dwReserved0; } template GHC_INLINE file_status status_from_INFO(const path& p, const INFO* info, std::error_code& ec, uintmax_t* sz = nullptr, time_t* lwt = nullptr) { file_type ft = file_type::unknown; if (sizeof(INFO) == sizeof(WIN32_FIND_DATAW)) { if (detail::reparse_tag_from_INFO(info) == IO_REPARSE_TAG_SYMLINK) { ft = file_type::symlink; } } else { if ((info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { auto reparseData = detail::getReparseData(p, ec); if (!ec && reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag) && reparseData->ReparseTag == IO_REPARSE_TAG_SYMLINK) { ft = file_type::symlink; } } } if (ft == file_type::unknown) { if ((info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { ft = file_type::directory; } else { ft = file_type::regular; } } perms prms = perms::owner_read | perms::group_read | perms::others_read; if (!(info->dwFileAttributes & FILE_ATTRIBUTE_READONLY)) { prms = prms | perms::owner_write | perms::group_write | perms::others_write; } if (has_executable_extension(p)) { prms = prms | perms::owner_exec | perms::group_exec | perms::others_exec; } if (sz) { *sz = static_cast(info->nFileSizeHigh) << (sizeof(info->nFileSizeHigh) * 8) | info->nFileSizeLow; } if (lwt) { *lwt = detail::timeFromFILETIME(info->ftLastWriteTime); } return file_status(ft, prms); } #endif GHC_INLINE bool is_not_found_error(std::error_code& ec) { #ifdef GHC_OS_WINDOWS return ec.value() == ERROR_FILE_NOT_FOUND || ec.value() == ERROR_PATH_NOT_FOUND || ec.value() == ERROR_INVALID_NAME; #else return ec.value() == ENOENT || ec.value() == ENOTDIR; #endif } GHC_INLINE file_status symlink_status_ex(const path& p, std::error_code& ec, uintmax_t* sz = nullptr, uintmax_t* nhl = nullptr, time_t* lwt = nullptr) noexcept { #ifdef GHC_OS_WINDOWS file_status fs; WIN32_FILE_ATTRIBUTE_DATA attr; if (!GetFileAttributesExW(GHC_NATIVEWP(p), GetFileExInfoStandard, &attr)) { ec = detail::make_system_error(); } else { ec.clear(); fs = detail::status_from_INFO(p, &attr, ec, sz, lwt); if (nhl) { *nhl = 0; } } if (detail::is_not_found_error(ec)) { return file_status(file_type::not_found); } return ec ? file_status(file_type::none) : fs; #else (void)sz; (void)nhl; (void)lwt; struct ::stat fs; auto result = ::lstat(p.c_str(), &fs); if (result == 0) { ec.clear(); file_status f_s = detail::file_status_from_st_mode(fs.st_mode); return f_s; } ec = detail::make_system_error(); if (detail::is_not_found_error(ec)) { return file_status(file_type::not_found, perms::unknown); } return file_status(file_type::none); #endif } GHC_INLINE file_status status_ex(const path& p, std::error_code& ec, file_status* sls = nullptr, uintmax_t* sz = nullptr, uintmax_t* nhl = nullptr, time_t* lwt = nullptr, int recurse_count = 0) noexcept { ec.clear(); #ifdef GHC_OS_WINDOWS if (recurse_count > 16) { ec = detail::make_system_error(0x2A9 /*ERROR_STOPPED_ON_SYMLINK*/); return file_status(file_type::unknown); } WIN32_FILE_ATTRIBUTE_DATA attr; if (!::GetFileAttributesExW(GHC_NATIVEWP(p), GetFileExInfoStandard, &attr)) { ec = detail::make_system_error(); } else if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { auto reparseData = detail::getReparseData(p, ec); if (!ec && reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag) && reparseData->ReparseTag == IO_REPARSE_TAG_SYMLINK) { path target = resolveSymlink(p, ec); file_status result; if (!ec && !target.empty()) { if (sls) { *sls = status_from_INFO(p, &attr, ec); } return detail::status_ex(target, ec, nullptr, sz, nhl, lwt, recurse_count + 1); } return file_status(file_type::unknown); } } if (ec) { if (detail::is_not_found_error(ec)) { return file_status(file_type::not_found); } return file_status(file_type::none); } if (nhl) { *nhl = 0; } return detail::status_from_INFO(p, &attr, ec, sz, lwt); #else (void)recurse_count; struct ::stat st; auto result = ::lstat(p.c_str(), &st); if (result == 0) { ec.clear(); file_status fs = detail::file_status_from_st_mode(st.st_mode); if (sls) { *sls = fs; } if (fs.type() == file_type::symlink) { result = ::stat(p.c_str(), &st); if (result == 0) { fs = detail::file_status_from_st_mode(st.st_mode); } else { ec = detail::make_system_error(); if (detail::is_not_found_error(ec)) { return file_status(file_type::not_found, perms::unknown); } return file_status(file_type::none); } } if (sz) { *sz = static_cast(st.st_size); } if (nhl) { *nhl = st.st_nlink; } if (lwt) { *lwt = st.st_mtime; } return fs; } else { ec = detail::make_system_error(); if (detail::is_not_found_error(ec)) { return file_status(file_type::not_found, perms::unknown); } return file_status(file_type::none); } #endif } } // namespace detail GHC_INLINE u8arguments::u8arguments(int& argc, char**& argv) : _argc(argc) , _argv(argv) , _refargc(argc) , _refargv(argv) , _isvalid(false) { #ifdef GHC_OS_WINDOWS LPWSTR* p; p = ::CommandLineToArgvW(::GetCommandLineW(), &argc); _args.reserve(static_cast(argc)); _argp.reserve(static_cast(argc)); for (size_t i = 0; i < static_cast(argc); ++i) { _args.push_back(detail::toUtf8(std::wstring(p[i]))); _argp.push_back((char*)_args[i].data()); } argv = _argp.data(); ::LocalFree(p); _isvalid = true; #else std::setlocale(LC_ALL, ""); #if defined(__ANDROID__) && __ANDROID_API__ < 26 _isvalid = true; #else if (detail::equals_simple_insensitive(::nl_langinfo(CODESET), "UTF-8")) { _isvalid = true; } #endif #endif } //----------------------------------------------------------------------------- // [fs.path.construct] constructors and destructor GHC_INLINE path::path() noexcept {} GHC_INLINE path::path(const path& p) : _path(p._path) #if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) , _prefixLength(p._prefixLength) #endif { } GHC_INLINE path::path(path&& p) noexcept : _path(std::move(p._path)) #if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) , _prefixLength(p._prefixLength) #endif { } GHC_INLINE path::path(string_type&& source, format fmt) : _path(std::move(source)) { postprocess_path_with_format(fmt); } #endif // GHC_EXPAND_IMPL #ifdef GHC_WITH_EXCEPTIONS template inline path::path(const Source& source, const std::locale& loc, format fmt) : path(source, fmt) { std::string locName = loc.name(); if (!(locName.length() >= 5 && (locName.substr(locName.length() - 5) == "UTF-8" || locName.substr(locName.length() - 5) == "utf-8"))) { throw filesystem_error("This implementation only supports UTF-8 locales!", path(_path), detail::make_error_code(detail::portable_error::not_supported)); } } template inline path::path(InputIterator first, InputIterator last, const std::locale& loc, format fmt) : path(std::basic_string::value_type>(first, last), fmt) { std::string locName = loc.name(); if (!(locName.length() >= 5 && (locName.substr(locName.length() - 5) == "UTF-8" || locName.substr(locName.length() - 5) == "utf-8"))) { throw filesystem_error("This implementation only supports UTF-8 locales!", path(_path), detail::make_error_code(detail::portable_error::not_supported)); } } #endif #ifdef GHC_EXPAND_IMPL GHC_INLINE path::~path() {} //----------------------------------------------------------------------------- // [fs.path.assign] assignments GHC_INLINE path& path::operator=(const path& p) { _path = p._path; #if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) _prefixLength = p._prefixLength; #endif return *this; } GHC_INLINE path& path::operator=(path&& p) noexcept { _path = std::move(p._path); #if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) _prefixLength = p._prefixLength; #endif return *this; } GHC_INLINE path& path::operator=(path::string_type&& source) { return assign(source); } GHC_INLINE path& path::assign(path::string_type&& source) { _path = std::move(source); postprocess_path_with_format(native_format); return *this; } #endif // GHC_EXPAND_IMPL template inline path& path::operator=(const Source& source) { return assign(source); } template inline path& path::assign(const Source& source) { #ifdef GHC_USE_WCHAR_T _path.assign(detail::toWChar(source)); #else _path.assign(detail::toUtf8(source)); #endif postprocess_path_with_format(native_format); return *this; } template <> inline path& path::assign(const path& source) { _path = source._path; #if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) _prefixLength = source._prefixLength; #endif return *this; } template inline path& path::assign(InputIterator first, InputIterator last) { _path.assign(first, last); postprocess_path_with_format(native_format); return *this; } #ifdef GHC_EXPAND_IMPL //----------------------------------------------------------------------------- // [fs.path.append] appends GHC_INLINE path& path::operator/=(const path& p) { if (p.empty()) { // was: if ((!has_root_directory() && is_absolute()) || has_filename()) if (!_path.empty() && _path[_path.length() - 1] != preferred_separator && _path[_path.length() - 1] != ':') { _path += preferred_separator; } return *this; } if ((p.is_absolute() && (_path != root_name()._path || p._path != "/")) || (p.has_root_name() && p.root_name() != root_name())) { assign(p); return *this; } if (p.has_root_directory()) { assign(root_name()); } else if ((!has_root_directory() && is_absolute()) || has_filename()) { _path += preferred_separator; } auto iter = p.begin(); bool first = true; if (p.has_root_name()) { ++iter; } while (iter != p.end()) { if (!first && !(!_path.empty() && _path[_path.length() - 1] == preferred_separator)) { _path += preferred_separator; } first = false; _path += (*iter++).native(); } check_long_path(); return *this; } GHC_INLINE void path::append_name(const value_type* name) { if (_path.empty()) { this->operator/=(path(name)); } else { if (_path.back() != path::preferred_separator) { _path.push_back(path::preferred_separator); } _path += name; check_long_path(); } } #endif // GHC_EXPAND_IMPL template inline path& path::operator/=(const Source& source) { return append(source); } template inline path& path::append(const Source& source) { return this->operator/=(path(source)); } template <> inline path& path::append(const path& p) { return this->operator/=(p); } template inline path& path::append(InputIterator first, InputIterator last) { std::basic_string::value_type> part(first, last); return append(part); } #ifdef GHC_EXPAND_IMPL //----------------------------------------------------------------------------- // [fs.path.concat] concatenation GHC_INLINE path& path::operator+=(const path& x) { return concat(x._path); } GHC_INLINE path& path::operator+=(const string_type& x) { return concat(x); } #ifdef GHC_WITH_STRING_VIEW GHC_INLINE path& path::operator+=(basic_string_view x) { return concat(x); } #endif GHC_INLINE path& path::operator+=(const value_type* x) { #ifdef GHC_WITH_STRING_VIEW basic_string_view part(x); #else string_type part(x); #endif return concat(part); } GHC_INLINE path& path::operator+=(value_type x) { #ifdef GHC_OS_WINDOWS if (x == generic_separator) { x = preferred_separator; } #endif if (_path.empty() || _path.back() != preferred_separator) { _path += x; } check_long_path(); return *this; } #endif // GHC_EXPAND_IMPL template inline path::path_from_string& path::operator+=(const Source& x) { return concat(x); } template inline path::path_type_EcharT& path::operator+=(EcharT x) { #ifdef GHC_WITH_STRING_VIEW basic_string_view part(&x, 1); #else std::basic_string part(1, x); #endif concat(part); return *this; } template inline path& path::concat(const Source& x) { path p(x); _path += p._path; postprocess_path_with_format(native_format); return *this; } template inline path& path::concat(InputIterator first, InputIterator last) { _path.append(first, last); postprocess_path_with_format(native_format); return *this; } #ifdef GHC_EXPAND_IMPL //----------------------------------------------------------------------------- // [fs.path.modifiers] modifiers GHC_INLINE void path::clear() noexcept { _path.clear(); #if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) _prefixLength = 0; #endif } GHC_INLINE path& path::make_preferred() { // as this filesystem implementation only uses generic_format // internally, this must be a no-op return *this; } GHC_INLINE path& path::remove_filename() { if (has_filename()) { _path.erase(_path.size() - filename()._path.size()); } return *this; } GHC_INLINE path& path::replace_filename(const path& replacement) { remove_filename(); return append(replacement); } GHC_INLINE path& path::replace_extension(const path& replacement) { if (has_extension()) { _path.erase(_path.size() - extension()._path.size()); } if (!replacement.empty() && replacement._path[0] != '.') { _path += '.'; } return concat(replacement); } GHC_INLINE void path::swap(path& rhs) noexcept { _path.swap(rhs._path); #if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) std::swap(_prefixLength, rhs._prefixLength); #endif } //----------------------------------------------------------------------------- // [fs.path.native.obs] native format observers GHC_INLINE const path::string_type& path::native() const noexcept { return _path; } GHC_INLINE const path::value_type* path::c_str() const noexcept { return native().c_str(); } GHC_INLINE path::operator path::string_type() const { return native(); } #endif // GHC_EXPAND_IMPL template inline std::basic_string path::string(const Allocator& a) const { #ifdef GHC_USE_WCHAR_T return detail::fromWChar>(_path, a); #else return detail::fromUtf8>(_path, a); #endif } #ifdef GHC_EXPAND_IMPL GHC_INLINE std::string path::string() const { #ifdef GHC_USE_WCHAR_T return detail::toUtf8(native()); #else return native(); #endif } GHC_INLINE std::wstring path::wstring() const { #ifdef GHC_USE_WCHAR_T return native(); #else return detail::fromUtf8(native()); #endif } #if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) GHC_INLINE std::u8string path::u8string() const { #ifdef GHC_USE_WCHAR_T return std::u8string(reinterpret_cast(detail::toUtf8(native()).c_str())); #else return std::u8string(reinterpret_cast(c_str())); #endif } #else GHC_INLINE std::string path::u8string() const { #ifdef GHC_USE_WCHAR_T return detail::toUtf8(native()); #else return native(); #endif } #endif GHC_INLINE std::u16string path::u16string() const { // TODO: optimize return detail::fromUtf8(string()); } GHC_INLINE std::u32string path::u32string() const { // TODO: optimize return detail::fromUtf8(string()); } #endif // GHC_EXPAND_IMPL //----------------------------------------------------------------------------- // [fs.path.generic.obs] generic format observers template inline std::basic_string path::generic_string(const Allocator& a) const { #ifdef GHC_OS_WINDOWS #ifdef GHC_USE_WCHAR_T auto result = detail::fromWChar, path::string_type>(_path, a); #else auto result = detail::fromUtf8>(_path, a); #endif for (auto& c : result) { if (c == preferred_separator) { c = generic_separator; } } return result; #else return detail::fromUtf8>(_path, a); #endif } #ifdef GHC_EXPAND_IMPL GHC_INLINE std::string path::generic_string() const { #ifdef GHC_OS_WINDOWS return generic_string(); #else return _path; #endif } GHC_INLINE std::wstring path::generic_wstring() const { #ifdef GHC_OS_WINDOWS return generic_string(); #else return detail::fromUtf8(_path); #endif } // namespace filesystem #if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) GHC_INLINE std::u8string path::generic_u8string() const { #ifdef GHC_OS_WINDOWS return generic_string(); #else return std::u8string(reinterpret_cast(_path.c_str())); #endif } #else GHC_INLINE std::string path::generic_u8string() const { #ifdef GHC_OS_WINDOWS return generic_string(); #else return _path; #endif } #endif GHC_INLINE std::u16string path::generic_u16string() const { #ifdef GHC_OS_WINDOWS return generic_string(); #else return detail::fromUtf8(_path); #endif } GHC_INLINE std::u32string path::generic_u32string() const { #ifdef GHC_OS_WINDOWS return generic_string(); #else return detail::fromUtf8(_path); #endif } //----------------------------------------------------------------------------- // [fs.path.compare] compare GHC_INLINE int path::compare(const path& p) const noexcept { #ifdef LWG_2936_BEHAVIOUR auto rnl1 = root_name_length(); auto rnl2 = p.root_name_length(); #ifdef GHC_OS_WINDOWS auto rnc = detail::compare_simple_insensitive(_path.c_str(), rnl1, p._path.c_str(), rnl2); #else auto rnc = _path.compare(0, rnl1, p._path, 0, (std::min(rnl1, rnl2))); #endif if (rnc) { return rnc; } bool hrd1 = has_root_directory(), hrd2 = p.has_root_directory(); if (hrd1 != hrd2) { return hrd1 ? 1 : -1; } if (hrd1) { ++rnl1; ++rnl2; } auto iter1 = _path.begin() + static_cast(rnl1); auto iter2 = p._path.begin() + static_cast(rnl2); while (iter1 != _path.end() && iter2 != p._path.end() && *iter1 == *iter2) { ++iter1; ++iter2; } if (iter1 == _path.end()) { return iter2 == p._path.end() ? 0 : -1; } if (iter2 == p._path.end()) { return 1; } if (*iter1 == preferred_separator) { return -1; } if (*iter2 == preferred_separator) { return 1; } return *iter1 < *iter2 ? -1 : 1; #else // LWG_2936_BEHAVIOUR #ifdef GHC_OS_WINDOWS auto rnl1 = root_name_length(); auto rnl2 = p.root_name_length(); auto rnc = detail::compare_simple_insensitive(_path.c_str(), rnl1, p._path.c_str(), rnl2); if (rnc) { return rnc; } return _path.compare(rnl1, std::string::npos, p._path, rnl2, std::string::npos); #else return _path.compare(p._path); #endif #endif } GHC_INLINE int path::compare(const string_type& s) const { return compare(path(s)); } #ifdef GHC_WITH_STRING_VIEW GHC_INLINE int path::compare(basic_string_view s) const { return compare(path(s)); } #endif GHC_INLINE int path::compare(const value_type* s) const { return compare(path(s)); } //----------------------------------------------------------------------------- // [fs.path.decompose] decomposition #ifdef GHC_OS_WINDOWS GHC_INLINE void path::handle_prefixes() { #if defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) _prefixLength = 0; if (_path.length() >= 6 && _path[2] == '?' && std::toupper(static_cast(_path[4])) >= 'A' && std::toupper(static_cast(_path[4])) <= 'Z' && _path[5] == ':') { if (detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL("\\\\?\\"))) || detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL("\\??\\")))) { _prefixLength = 4; } } #endif // GHC_WIN_AUTO_PREFIX_LONG_PATH } #endif GHC_INLINE path::string_type::size_type path::root_name_length() const noexcept { #ifdef GHC_OS_WINDOWS if (_path.length() >= _prefixLength + 2 && std::toupper(static_cast(_path[_prefixLength])) >= 'A' && std::toupper(static_cast(_path[_prefixLength])) <= 'Z' && _path[_prefixLength + 1] == ':') { return 2; } #endif if (_path.length() > _prefixLength + 2 && _path[_prefixLength] == preferred_separator && _path[_prefixLength + 1] == preferred_separator && _path[_prefixLength + 2] != preferred_separator && std::isprint(_path[_prefixLength + 2])) { impl_string_type::size_type pos = _path.find(preferred_separator, _prefixLength + 3); if (pos == impl_string_type::npos) { return _path.length(); } else { return pos; } } return 0; } GHC_INLINE path path::root_name() const { return path(_path.substr(_prefixLength, root_name_length()), native_format); } GHC_INLINE path path::root_directory() const { if (has_root_directory()) { static const path _root_dir(std::string(1, preferred_separator), native_format); return _root_dir; } return path(); } GHC_INLINE path path::root_path() const { return path(root_name().string() + root_directory().string(), native_format); } GHC_INLINE path path::relative_path() const { auto rootPathLen = _prefixLength + root_name_length() + (has_root_directory() ? 1 : 0); return path(_path.substr((std::min)(rootPathLen, _path.length())), generic_format); } GHC_INLINE path path::parent_path() const { auto rootPathLen = _prefixLength + root_name_length() + (has_root_directory() ? 1 : 0); if (rootPathLen < _path.length()) { if (empty()) { return path(); } else { auto piter = end(); auto iter = piter.decrement(_path.end()); if (iter > _path.begin() + static_cast(rootPathLen) && *iter != preferred_separator) { --iter; } return path(_path.begin(), iter, native_format); } } else { return *this; } } GHC_INLINE path path::filename() const { return !has_relative_path() ? path() : path(*--end()); } GHC_INLINE path path::stem() const { impl_string_type fn = filename().native(); if (fn != "." && fn != "..") { impl_string_type::size_type pos = fn.rfind('.'); if (pos != impl_string_type::npos && pos > 0) { return path{fn.substr(0, pos), native_format}; } } return path{fn, native_format}; } GHC_INLINE path path::extension() const { if (has_relative_path()) { auto iter = end(); const auto& fn = *--iter; impl_string_type::size_type pos = fn._path.rfind('.'); if (pos != std::string::npos && pos > 0) { return path(fn._path.substr(pos), native_format); } } return path(); } #ifdef GHC_OS_WINDOWS namespace detail { GHC_INLINE bool has_executable_extension(const path& p) { if (p.has_relative_path()) { auto iter = p.end(); const auto& fn = *--iter; auto pos = fn._path.find_last_of('.'); if (pos == std::string::npos || pos == 0 || fn._path.length() - pos != 3) { return false; } const path::value_type* ext = fn._path.c_str() + pos + 1; if (detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("exe")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("cmd")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("bat")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("com"))) { return true; } } return false; } } // namespace detail #endif //----------------------------------------------------------------------------- // [fs.path.query] query GHC_INLINE bool path::empty() const noexcept { return _path.empty(); } GHC_INLINE bool path::has_root_name() const { return root_name_length() > 0; } GHC_INLINE bool path::has_root_directory() const { auto rootLen = _prefixLength + root_name_length(); return (_path.length() > rootLen && _path[rootLen] == preferred_separator); } GHC_INLINE bool path::has_root_path() const { return has_root_name() || has_root_directory(); } GHC_INLINE bool path::has_relative_path() const { auto rootPathLen = _prefixLength + root_name_length() + (has_root_directory() ? 1 : 0); return rootPathLen < _path.length(); } GHC_INLINE bool path::has_parent_path() const { return !parent_path().empty(); } GHC_INLINE bool path::has_filename() const { return has_relative_path() && !filename().empty(); } GHC_INLINE bool path::has_stem() const { return !stem().empty(); } GHC_INLINE bool path::has_extension() const { return !extension().empty(); } GHC_INLINE bool path::is_absolute() const { #ifdef GHC_OS_WINDOWS return has_root_name() && has_root_directory(); #else return has_root_directory(); #endif } GHC_INLINE bool path::is_relative() const { return !is_absolute(); } //----------------------------------------------------------------------------- // [fs.path.gen] generation GHC_INLINE path path::lexically_normal() const { path dest; bool lastDotDot = false; for (string_type s : *this) { if (s == ".") { dest /= ""; continue; } else if (s == ".." && !dest.empty()) { auto root = root_path(); if (dest == root) { continue; } else if (*(--dest.end()) != "..") { if (dest._path.back() == preferred_separator) { dest._path.pop_back(); } dest.remove_filename(); continue; } } if (!(s.empty() && lastDotDot)) { dest /= s; } lastDotDot = s == ".."; } if (dest.empty()) { dest = "."; } return dest; } GHC_INLINE path path::lexically_relative(const path& base) const { if (root_name() != base.root_name() || is_absolute() != base.is_absolute() || (!has_root_directory() && base.has_root_directory())) { return path(); } const_iterator a = begin(), b = base.begin(); while (a != end() && b != base.end() && *a == *b) { ++a; ++b; } if (a == end() && b == base.end()) { return path("."); } int count = 0; for (const auto& element : input_iterator_range(b, base.end())) { if (element != "." && element != "" && element != "..") { ++count; } else if (element == "..") { --count; } } if (count < 0) { return path(); } path result; for (int i = 0; i < count; ++i) { result /= ".."; } for (const auto& element : input_iterator_range(a, end())) { result /= element; } return result; } GHC_INLINE path path::lexically_proximate(const path& base) const { path result = lexically_relative(base); return result.empty() ? *this : result; } //----------------------------------------------------------------------------- // [fs.path.itr] iterators GHC_INLINE path::iterator::iterator() {} GHC_INLINE path::iterator::iterator(const path& p, const impl_string_type::const_iterator& pos) : _first(p._path.begin()) , _last(p._path.end()) , _prefix(_first + static_cast(p._prefixLength)) , _root(p.has_root_directory() ? _first + static_cast(p._prefixLength + p.root_name_length()) : _last) , _iter(pos) { if (pos != _last) { updateCurrent(); } } GHC_INLINE path::impl_string_type::const_iterator path::iterator::increment(const path::impl_string_type::const_iterator& pos) const { path::impl_string_type::const_iterator i = pos; bool fromStart = i == _first || i == _prefix; if (i != _last) { if (fromStart && i == _first && _prefix > _first) { i = _prefix; } else if (*i++ == preferred_separator) { // we can only sit on a slash if it is a network name or a root if (i != _last && *i == preferred_separator) { if (fromStart && !(i + 1 != _last && *(i + 1) == preferred_separator)) { // leadind double slashes detected, treat this and the // following until a slash as one unit i = std::find(++i, _last, preferred_separator); } else { // skip redundant slashes while (i != _last && *i == preferred_separator) { ++i; } } } } else { if (fromStart && i != _last && *i == ':') { ++i; } else { i = std::find(i, _last, preferred_separator); } } } return i; } GHC_INLINE path::impl_string_type::const_iterator path::iterator::decrement(const path::impl_string_type::const_iterator& pos) const { path::impl_string_type::const_iterator i = pos; if (i != _first) { --i; // if this is now the root slash or the trailing slash, we are done, // else check for network name if (i != _root && (pos != _last || *i != preferred_separator)) { #ifdef GHC_OS_WINDOWS static const impl_string_type seps = GHC_PLATFORM_LITERAL("\\:"); i = std::find_first_of(std::reverse_iterator(i), std::reverse_iterator(_first), seps.begin(), seps.end()).base(); if (i > _first && *i == ':') { i++; } #else i = std::find(std::reverse_iterator(i), std::reverse_iterator(_first), preferred_separator).base(); #endif // Now we have to check if this is a network name if (i - _first == 2 && *_first == preferred_separator && *(_first + 1) == preferred_separator) { i -= 2; } } } return i; } GHC_INLINE void path::iterator::updateCurrent() { if ((_iter == _last) || (_iter != _first && _iter != _last && (*_iter == preferred_separator && _iter != _root) && (_iter + 1 == _last))) { _current.clear(); } else { _current.assign(_iter, increment(_iter)); } } GHC_INLINE path::iterator& path::iterator::operator++() { _iter = increment(_iter); while (_iter != _last && // we didn't reach the end _iter != _root && // this is not a root position *_iter == preferred_separator && // we are on a separator (_iter + 1) != _last // the slash is not the last char ) { ++_iter; } updateCurrent(); return *this; } GHC_INLINE path::iterator path::iterator::operator++(int) { path::iterator i{*this}; ++(*this); return i; } GHC_INLINE path::iterator& path::iterator::operator--() { _iter = decrement(_iter); updateCurrent(); return *this; } GHC_INLINE path::iterator path::iterator::operator--(int) { auto i = *this; --(*this); return i; } GHC_INLINE bool path::iterator::operator==(const path::iterator& other) const { return _iter == other._iter; } GHC_INLINE bool path::iterator::operator!=(const path::iterator& other) const { return _iter != other._iter; } GHC_INLINE path::iterator::reference path::iterator::operator*() const { return _current; } GHC_INLINE path::iterator::pointer path::iterator::operator->() const { return &_current; } GHC_INLINE path::iterator path::begin() const { return iterator(*this, _path.begin()); } GHC_INLINE path::iterator path::end() const { return iterator(*this, _path.end()); } //----------------------------------------------------------------------------- // [fs.path.nonmember] path non-member functions GHC_INLINE void swap(path& lhs, path& rhs) noexcept { swap(lhs._path, rhs._path); } GHC_INLINE size_t hash_value(const path& p) noexcept { return std::hash()(p.generic_string()); } #ifdef GHC_HAS_THREEWAY_COMP GHC_INLINE std::strong_ordering operator<=>(const path& lhs, const path& rhs) noexcept { return lhs.compare(rhs) <=> 0; } #endif GHC_INLINE bool operator==(const path& lhs, const path& rhs) noexcept { return lhs.compare(rhs) == 0; } GHC_INLINE bool operator!=(const path& lhs, const path& rhs) noexcept { return !(lhs == rhs); } GHC_INLINE bool operator<(const path& lhs, const path& rhs) noexcept { return lhs.compare(rhs) < 0; } GHC_INLINE bool operator<=(const path& lhs, const path& rhs) noexcept { return lhs.compare(rhs) <= 0; } GHC_INLINE bool operator>(const path& lhs, const path& rhs) noexcept { return lhs.compare(rhs) > 0; } GHC_INLINE bool operator>=(const path& lhs, const path& rhs) noexcept { return lhs.compare(rhs) >= 0; } GHC_INLINE path operator/(const path& lhs, const path& rhs) { path result(lhs); result /= rhs; return result; } #endif // GHC_EXPAND_IMPL //----------------------------------------------------------------------------- // [fs.path.io] path inserter and extractor template inline std::basic_ostream& operator<<(std::basic_ostream& os, const path& p) { os << "\""; auto ps = p.string(); for (auto c : ps) { if (c == '"' || c == '\\') { os << '\\'; } os << c; } os << "\""; return os; } template inline std::basic_istream& operator>>(std::basic_istream& is, path& p) { std::basic_string tmp; charT c; is >> c; if (c == '"') { auto sf = is.flags(); is >> std::noskipws; while (is) { auto c2 = is.get(); if (is) { if (c2 == '\\') { c2 = is.get(); if (is) { tmp += static_cast(c2); } } else if (c2 == '"') { break; } else { tmp += static_cast(c2); } } } if ((sf & std::ios_base::skipws) == std::ios_base::skipws) { is >> std::skipws; } p = path(tmp); } else { is >> tmp; p = path(static_cast(c) + tmp); } return is; } #ifdef GHC_EXPAND_IMPL //----------------------------------------------------------------------------- // [fs.class.filesystem_error] Class filesystem_error GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, std::error_code ec) : std::system_error(ec, what_arg) , _what_arg(what_arg) , _ec(ec) { } GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const path& p1, std::error_code ec) : std::system_error(ec, what_arg) , _what_arg(what_arg) , _ec(ec) , _p1(p1) { if (!_p1.empty()) { _what_arg += ": '" + _p1.string() + "'"; } } GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const path& p1, const path& p2, std::error_code ec) : std::system_error(ec, what_arg) , _what_arg(what_arg) , _ec(ec) , _p1(p1) , _p2(p2) { if (!_p1.empty()) { _what_arg += ": '" + _p1.string() + "'"; } if (!_p2.empty()) { _what_arg += ", '" + _p2.string() + "'"; } } GHC_INLINE const path& filesystem_error::path1() const noexcept { return _p1; } GHC_INLINE const path& filesystem_error::path2() const noexcept { return _p2; } GHC_INLINE const char* filesystem_error::what() const noexcept { return _what_arg.c_str(); } //----------------------------------------------------------------------------- // [fs.op.funcs] filesystem operations #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE path absolute(const path& p) { std::error_code ec; path result = absolute(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE path absolute(const path& p, std::error_code& ec) { ec.clear(); #ifdef GHC_OS_WINDOWS if (p.empty()) { return absolute(current_path(ec), ec) / ""; } ULONG size = ::GetFullPathNameW(GHC_NATIVEWP(p), 0, 0, 0); if (size) { std::vector buf(size, 0); ULONG s2 = GetFullPathNameW(GHC_NATIVEWP(p), size, buf.data(), nullptr); if (s2 && s2 < size) { path result = path(std::wstring(buf.data(), s2)); if (p.filename() == ".") { result /= "."; } return result; } } ec = detail::make_system_error(); return path(); #else path base = current_path(ec); if (!ec) { if (p.empty()) { return base / p; } if (p.has_root_name()) { if (p.has_root_directory()) { return p; } else { return p.root_name() / base.root_directory() / base.relative_path() / p.relative_path(); } } else { if (p.has_root_directory()) { return base.root_name() / p; } else { return base / p; } } } ec = detail::make_system_error(); return path(); #endif } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE path canonical(const path& p) { std::error_code ec; auto result = canonical(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE path canonical(const path& p, std::error_code& ec) { if (p.empty()) { ec = detail::make_error_code(detail::portable_error::not_found); return path(); } path work = p.is_absolute() ? p : absolute(p, ec); path result; auto fs = status(work, ec); if (ec) { return path(); } if (fs.type() == file_type::not_found) { ec = detail::make_error_code(detail::portable_error::not_found); return path(); } bool redo; do { auto rootPathLen = work._prefixLength + work.root_name_length() + (work.has_root_directory() ? 1 : 0); redo = false; result.clear(); for (auto pe : work) { if (pe.empty() || pe == ".") { continue; } else if (pe == "..") { result = result.parent_path(); continue; } else if ((result / pe).string().length() <= rootPathLen) { result /= pe; continue; } auto sls = symlink_status(result / pe, ec); if (ec) { return path(); } if (is_symlink(sls)) { redo = true; auto target = read_symlink(result / pe, ec); if (ec) { return path(); } if (target.is_absolute()) { result = target; continue; } else { result /= target; continue; } } else { result /= pe; } } work = result; } while (redo); ec.clear(); return result; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void copy(const path& from, const path& to) { copy(from, to, copy_options::none); } GHC_INLINE void copy(const path& from, const path& to, copy_options options) { std::error_code ec; copy(from, to, options, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec); } } #endif GHC_INLINE void copy(const path& from, const path& to, std::error_code& ec) noexcept { copy(from, to, copy_options::none, ec); } GHC_INLINE void copy(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept { std::error_code tec; file_status fs_from, fs_to; ec.clear(); if ((options & (copy_options::skip_symlinks | copy_options::copy_symlinks | copy_options::create_symlinks)) != copy_options::none) { fs_from = symlink_status(from, ec); } else { fs_from = status(from, ec); } if (!exists(fs_from)) { if (!ec) { ec = detail::make_error_code(detail::portable_error::not_found); } return; } if ((options & (copy_options::skip_symlinks | copy_options::create_symlinks)) != copy_options::none) { fs_to = symlink_status(to, tec); } else { fs_to = status(to, tec); } if (is_other(fs_from) || is_other(fs_to) || (is_directory(fs_from) && is_regular_file(fs_to)) || (exists(fs_to) && equivalent(from, to, ec))) { ec = detail::make_error_code(detail::portable_error::invalid_argument); } else if (is_symlink(fs_from)) { if ((options & copy_options::skip_symlinks) == copy_options::none) { if (!exists(fs_to) && (options & copy_options::copy_symlinks) != copy_options::none) { copy_symlink(from, to, ec); } else { ec = detail::make_error_code(detail::portable_error::invalid_argument); } } } else if (is_regular_file(fs_from)) { if ((options & copy_options::directories_only) == copy_options::none) { if ((options & copy_options::create_symlinks) != copy_options::none) { create_symlink(from.is_absolute() ? from : canonical(from, ec), to, ec); } #ifndef GHC_OS_WEB else if ((options & copy_options::create_hard_links) != copy_options::none) { create_hard_link(from, to, ec); } #endif else if (is_directory(fs_to)) { copy_file(from, to / from.filename(), options, ec); } else { copy_file(from, to, options, ec); } } } #ifdef LWG_2682_BEHAVIOUR else if (is_directory(fs_from) && (options & copy_options::create_symlinks) != copy_options::none) { ec = detail::make_error_code(detail::portable_error::is_a_directory); } #endif else if (is_directory(fs_from) && (options == copy_options::none || (options & copy_options::recursive) != copy_options::none)) { if (!exists(fs_to)) { create_directory(to, from, ec); if (ec) { return; } } for (auto iter = directory_iterator(from, ec); iter != directory_iterator(); iter.increment(ec)) { if (!ec) { copy(iter->path(), to / iter->path().filename(), options | static_cast(0x8000), ec); } if (ec) { return; } } } return; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool copy_file(const path& from, const path& to) { return copy_file(from, to, copy_options::none); } GHC_INLINE bool copy_file(const path& from, const path& to, copy_options option) { std::error_code ec; auto result = copy_file(from, to, option, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec); } return result; } #endif GHC_INLINE bool copy_file(const path& from, const path& to, std::error_code& ec) noexcept { return copy_file(from, to, copy_options::none, ec); } GHC_INLINE bool copy_file(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept { std::error_code tecf, tect; auto sf = status(from, tecf); auto st = status(to, tect); bool overwrite = false; ec.clear(); if (!is_regular_file(sf)) { ec = tecf; return false; } if (exists(st) && (!is_regular_file(st) || equivalent(from, to, ec) || (options & (copy_options::skip_existing | copy_options::overwrite_existing | copy_options::update_existing)) == copy_options::none)) { ec = tect ? tect : detail::make_error_code(detail::portable_error::exists); return false; } if (exists(st)) { if ((options & copy_options::update_existing) == copy_options::update_existing) { auto from_time = last_write_time(from, ec); if (ec) { ec = detail::make_system_error(); return false; } auto to_time = last_write_time(to, ec); if (ec) { ec = detail::make_system_error(); return false; } if (from_time <= to_time) { return false; } } overwrite = true; } #ifdef GHC_OS_WINDOWS if (!::CopyFileW(GHC_NATIVEWP(from), GHC_NATIVEWP(to), !overwrite)) { ec = detail::make_system_error(); return false; } return true; #else std::vector buffer(16384, '\0'); int in = -1, out = -1; if ((in = ::open(from.c_str(), O_RDONLY)) < 0) { ec = detail::make_system_error(); return false; } int mode = O_CREAT | O_WRONLY | O_TRUNC; if (!overwrite) { mode |= O_EXCL; } if ((out = ::open(to.c_str(), mode, static_cast(sf.permissions() & perms::all))) < 0) { ec = detail::make_system_error(); ::close(in); return false; } ssize_t br, bw; while ((br = ::read(in, buffer.data(), buffer.size())) > 0) { ssize_t offset = 0; do { if ((bw = ::write(out, buffer.data() + offset, static_cast(br))) > 0) { br -= bw; offset += bw; } else if (bw < 0) { ec = detail::make_system_error(); ::close(in); ::close(out); return false; } } while (br); } ::close(in); ::close(out); return true; #endif } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void copy_symlink(const path& existing_symlink, const path& new_symlink) { std::error_code ec; copy_symlink(existing_symlink, new_symlink, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), existing_symlink, new_symlink, ec); } } #endif GHC_INLINE void copy_symlink(const path& existing_symlink, const path& new_symlink, std::error_code& ec) noexcept { ec.clear(); auto to = read_symlink(existing_symlink, ec); if (!ec) { if (exists(to, ec) && is_directory(to, ec)) { create_directory_symlink(to, new_symlink, ec); } else { create_symlink(to, new_symlink, ec); } } } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool create_directories(const path& p) { std::error_code ec; auto result = create_directories(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE bool create_directories(const path& p, std::error_code& ec) noexcept { path current; ec.clear(); bool didCreate = false; auto rootPathLen = p._prefixLength + p.root_name_length() + (p.has_root_directory() ? 1 : 0); current = p.native().substr(0, rootPathLen); path folders(p._path.substr(rootPathLen)); for (path::string_type part : folders) { current /= part; std::error_code tec; auto fs = status(current, tec); if (tec && fs.type() != file_type::not_found) { ec = tec; return false; } if (!exists(fs)) { create_directory(current, ec); if (ec) { std::error_code tmp_ec; if (is_directory(current, tmp_ec)) { ec.clear(); } else { return false; } } didCreate = true; } #ifndef LWG_2935_BEHAVIOUR else if (!is_directory(fs)) { ec = detail::make_error_code(detail::portable_error::exists); return false; } #endif } return didCreate; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool create_directory(const path& p) { std::error_code ec; auto result = create_directory(p, path(), ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE bool create_directory(const path& p, std::error_code& ec) noexcept { return create_directory(p, path(), ec); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool create_directory(const path& p, const path& attributes) { std::error_code ec; auto result = create_directory(p, attributes, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE bool create_directory(const path& p, const path& attributes, std::error_code& ec) noexcept { std::error_code tec; ec.clear(); auto fs = status(p, tec); #ifdef LWG_2935_BEHAVIOUR if (status_known(fs) && exists(fs)) { return false; } #else if (status_known(fs) && exists(fs) && is_directory(fs)) { return false; } #endif #ifdef GHC_OS_WINDOWS if (!attributes.empty()) { if (!::CreateDirectoryExW(GHC_NATIVEWP(attributes), GHC_NATIVEWP(p), NULL)) { ec = detail::make_system_error(); return false; } } else if (!::CreateDirectoryW(GHC_NATIVEWP(p), NULL)) { ec = detail::make_system_error(); return false; } #else ::mode_t attribs = static_cast(perms::all); if (!attributes.empty()) { struct ::stat fileStat; if (::stat(attributes.c_str(), &fileStat) != 0) { ec = detail::make_system_error(); return false; } attribs = fileStat.st_mode; } if (::mkdir(p.c_str(), attribs) != 0) { ec = detail::make_system_error(); return false; } #endif return true; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void create_directory_symlink(const path& to, const path& new_symlink) { std::error_code ec; create_directory_symlink(to, new_symlink, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), to, new_symlink, ec); } } #endif GHC_INLINE void create_directory_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept { detail::create_symlink(to, new_symlink, true, ec); } #ifndef GHC_OS_WEB #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void create_hard_link(const path& to, const path& new_hard_link) { std::error_code ec; create_hard_link(to, new_hard_link, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), to, new_hard_link, ec); } } #endif GHC_INLINE void create_hard_link(const path& to, const path& new_hard_link, std::error_code& ec) noexcept { detail::create_hardlink(to, new_hard_link, ec); } #endif #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void create_symlink(const path& to, const path& new_symlink) { std::error_code ec; create_symlink(to, new_symlink, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), to, new_symlink, ec); } } #endif GHC_INLINE void create_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept { detail::create_symlink(to, new_symlink, false, ec); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE path current_path() { std::error_code ec; auto result = current_path(ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), ec); } return result; } #endif GHC_INLINE path current_path(std::error_code& ec) { ec.clear(); #ifdef GHC_OS_WINDOWS DWORD pathlen = ::GetCurrentDirectoryW(0, 0); std::unique_ptr buffer(new wchar_t[size_t(pathlen) + 1]); if (::GetCurrentDirectoryW(pathlen, buffer.get()) == 0) { ec = detail::make_system_error(); return path(); } return path(std::wstring(buffer.get()), path::native_format); #else size_t pathlen = static_cast(std::max(int(::pathconf(".", _PC_PATH_MAX)), int(PATH_MAX))); std::unique_ptr buffer(new char[pathlen + 1]); if (::getcwd(buffer.get(), pathlen) == nullptr) { ec = detail::make_system_error(); return path(); } return path(buffer.get()); #endif } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void current_path(const path& p) { std::error_code ec; current_path(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } } #endif GHC_INLINE void current_path(const path& p, std::error_code& ec) noexcept { ec.clear(); #ifdef GHC_OS_WINDOWS if (!::SetCurrentDirectoryW(GHC_NATIVEWP(p))) { ec = detail::make_system_error(); } #else if (::chdir(p.string().c_str()) == -1) { ec = detail::make_system_error(); } #endif } GHC_INLINE bool exists(file_status s) noexcept { return status_known(s) && s.type() != file_type::not_found; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool exists(const path& p) { return exists(status(p)); } #endif GHC_INLINE bool exists(const path& p, std::error_code& ec) noexcept { file_status s = status(p, ec); if (status_known(s)) { ec.clear(); } return exists(s); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool equivalent(const path& p1, const path& p2) { std::error_code ec; bool result = equivalent(p1, p2, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p1, p2, ec); } return result; } #endif GHC_INLINE bool equivalent(const path& p1, const path& p2, std::error_code& ec) noexcept { ec.clear(); #ifdef GHC_OS_WINDOWS detail::unique_handle file1(::CreateFileW(GHC_NATIVEWP(p1), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)); auto e1 = ::GetLastError(); detail::unique_handle file2(::CreateFileW(GHC_NATIVEWP(p2), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)); if (!file1 || !file2) { #ifdef LWG_2937_BEHAVIOUR ec = detail::make_system_error(e1 ? e1 : ::GetLastError()); #else if (file1 == file2) { ec = detail::make_system_error(e1 ? e1 : ::GetLastError()); } #endif return false; } BY_HANDLE_FILE_INFORMATION inf1, inf2; if (!::GetFileInformationByHandle(file1.get(), &inf1)) { ec = detail::make_system_error(); return false; } if (!::GetFileInformationByHandle(file2.get(), &inf2)) { ec = detail::make_system_error(); return false; } return inf1.ftLastWriteTime.dwLowDateTime == inf2.ftLastWriteTime.dwLowDateTime && inf1.ftLastWriteTime.dwHighDateTime == inf2.ftLastWriteTime.dwHighDateTime && inf1.nFileIndexHigh == inf2.nFileIndexHigh && inf1.nFileIndexLow == inf2.nFileIndexLow && inf1.nFileSizeHigh == inf2.nFileSizeHigh && inf1.nFileSizeLow == inf2.nFileSizeLow && inf1.dwVolumeSerialNumber == inf2.dwVolumeSerialNumber; #else struct ::stat s1, s2; auto rc1 = ::stat(p1.c_str(), &s1); auto e1 = errno; auto rc2 = ::stat(p2.c_str(), &s2); if (rc1 || rc2) { #ifdef LWG_2937_BEHAVIOUR ec = detail::make_system_error(e1 ? e1 : errno); #else if (rc1 && rc2) { ec = detail::make_system_error(e1 ? e1 : errno); } #endif return false; } return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino && s1.st_size == s2.st_size && s1.st_mtime == s2.st_mtime; #endif } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE uintmax_t file_size(const path& p) { std::error_code ec; auto result = file_size(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE uintmax_t file_size(const path& p, std::error_code& ec) noexcept { ec.clear(); #ifdef GHC_OS_WINDOWS WIN32_FILE_ATTRIBUTE_DATA attr; if (!GetFileAttributesExW(GHC_NATIVEWP(p), GetFileExInfoStandard, &attr)) { ec = detail::make_system_error(); return static_cast(-1); } return static_cast(attr.nFileSizeHigh) << (sizeof(attr.nFileSizeHigh) * 8) | attr.nFileSizeLow; #else struct ::stat fileStat; if (::stat(p.c_str(), &fileStat) == -1) { ec = detail::make_system_error(); return static_cast(-1); } return static_cast(fileStat.st_size); #endif } #ifndef GHC_OS_WEB #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE uintmax_t hard_link_count(const path& p) { std::error_code ec; auto result = hard_link_count(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept { ec.clear(); #ifdef GHC_OS_WINDOWS uintmax_t result = static_cast(-1); detail::unique_handle file(::CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)); BY_HANDLE_FILE_INFORMATION inf; if (!file) { ec = detail::make_system_error(); } else { if (!::GetFileInformationByHandle(file.get(), &inf)) { ec = detail::make_system_error(); } else { result = inf.nNumberOfLinks; } } return result; #else uintmax_t result = 0; file_status fs = detail::status_ex(p, ec, nullptr, nullptr, &result, nullptr); if (fs.type() == file_type::not_found) { ec = detail::make_error_code(detail::portable_error::not_found); } return ec ? static_cast(-1) : result; #endif } #endif GHC_INLINE bool is_block_file(file_status s) noexcept { return s.type() == file_type::block; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool is_block_file(const path& p) { return is_block_file(status(p)); } #endif GHC_INLINE bool is_block_file(const path& p, std::error_code& ec) noexcept { return is_block_file(status(p, ec)); } GHC_INLINE bool is_character_file(file_status s) noexcept { return s.type() == file_type::character; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool is_character_file(const path& p) { return is_character_file(status(p)); } #endif GHC_INLINE bool is_character_file(const path& p, std::error_code& ec) noexcept { return is_character_file(status(p, ec)); } GHC_INLINE bool is_directory(file_status s) noexcept { return s.type() == file_type::directory; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool is_directory(const path& p) { return is_directory(status(p)); } #endif GHC_INLINE bool is_directory(const path& p, std::error_code& ec) noexcept { return is_directory(status(p, ec)); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool is_empty(const path& p) { if (is_directory(p)) { return directory_iterator(p) == directory_iterator(); } else { return file_size(p) == 0; } } #endif GHC_INLINE bool is_empty(const path& p, std::error_code& ec) noexcept { auto fs = status(p, ec); if (ec) { return false; } if (is_directory(fs)) { directory_iterator iter(p, ec); if (ec) { return false; } return iter == directory_iterator(); } else { auto sz = file_size(p, ec); if (ec) { return false; } return sz == 0; } } GHC_INLINE bool is_fifo(file_status s) noexcept { return s.type() == file_type::fifo; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool is_fifo(const path& p) { return is_fifo(status(p)); } #endif GHC_INLINE bool is_fifo(const path& p, std::error_code& ec) noexcept { return is_fifo(status(p, ec)); } GHC_INLINE bool is_other(file_status s) noexcept { return exists(s) && !is_regular_file(s) && !is_directory(s) && !is_symlink(s); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool is_other(const path& p) { return is_other(status(p)); } #endif GHC_INLINE bool is_other(const path& p, std::error_code& ec) noexcept { return is_other(status(p, ec)); } GHC_INLINE bool is_regular_file(file_status s) noexcept { return s.type() == file_type::regular; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool is_regular_file(const path& p) { return is_regular_file(status(p)); } #endif GHC_INLINE bool is_regular_file(const path& p, std::error_code& ec) noexcept { return is_regular_file(status(p, ec)); } GHC_INLINE bool is_socket(file_status s) noexcept { return s.type() == file_type::socket; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool is_socket(const path& p) { return is_socket(status(p)); } #endif GHC_INLINE bool is_socket(const path& p, std::error_code& ec) noexcept { return is_socket(status(p, ec)); } GHC_INLINE bool is_symlink(file_status s) noexcept { return s.type() == file_type::symlink; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool is_symlink(const path& p) { return is_symlink(symlink_status(p)); } #endif GHC_INLINE bool is_symlink(const path& p, std::error_code& ec) noexcept { return is_symlink(symlink_status(p, ec)); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE file_time_type last_write_time(const path& p) { std::error_code ec; auto result = last_write_time(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE file_time_type last_write_time(const path& p, std::error_code& ec) noexcept { time_t result = 0; ec.clear(); file_status fs = detail::status_ex(p, ec, nullptr, nullptr, nullptr, &result); return ec ? (file_time_type::min)() : std::chrono::system_clock::from_time_t(result); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void last_write_time(const path& p, file_time_type new_time) { std::error_code ec; last_write_time(p, new_time, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } } #endif GHC_INLINE void last_write_time(const path& p, file_time_type new_time, std::error_code& ec) noexcept { ec.clear(); auto d = new_time.time_since_epoch(); #ifdef GHC_OS_WINDOWS detail::unique_handle file(::CreateFileW(GHC_NATIVEWP(p), FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL)); FILETIME ft; auto tt = std::chrono::duration_cast(d).count() * 10 + 116444736000000000; ft.dwLowDateTime = static_cast(tt); ft.dwHighDateTime = static_cast(tt >> 32); if (!::SetFileTime(file.get(), 0, 0, &ft)) { ec = detail::make_system_error(); } #elif defined(GHC_OS_MACOS) #ifdef __MAC_OS_X_VERSION_MIN_REQUIRED #if __MAC_OS_X_VERSION_MIN_REQUIRED < 101300 struct ::stat fs; if (::stat(p.c_str(), &fs) == 0) { struct ::timeval tv[2]; tv[0].tv_sec = fs.st_atimespec.tv_sec; tv[0].tv_usec = static_cast(fs.st_atimespec.tv_nsec / 1000); tv[1].tv_sec = std::chrono::duration_cast(d).count(); tv[1].tv_usec = static_cast(std::chrono::duration_cast(d).count() % 1000000); if (::utimes(p.c_str(), tv) == 0) { return; } } ec = detail::make_system_error(); return; #else struct ::timespec times[2]; times[0].tv_sec = 0; times[0].tv_nsec = UTIME_OMIT; times[1].tv_sec = std::chrono::duration_cast(d).count(); times[1].tv_nsec = 0; // std::chrono::duration_cast(d).count() % 1000000000; if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) { ec = detail::make_system_error(); } return; #endif #endif #else #ifndef UTIME_OMIT #define UTIME_OMIT ((1l << 30) - 2l) #endif struct ::timespec times[2]; times[0].tv_sec = 0; times[0].tv_nsec = UTIME_OMIT; times[1].tv_sec = static_cast(std::chrono::duration_cast(d).count()); times[1].tv_nsec = static_cast(std::chrono::duration_cast(d).count() % 1000000000); #if defined(__ANDROID_API__) && __ANDROID_API__ < 12 if (syscall(__NR_utimensat, AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) { #else if (::utimensat((int)AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) { #endif ec = detail::make_system_error(); } return; #endif } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void permissions(const path& p, perms prms, perm_options opts) { std::error_code ec; permissions(p, prms, opts, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } } #endif GHC_INLINE void permissions(const path& p, perms prms, std::error_code& ec) noexcept { permissions(p, prms, perm_options::replace, ec); } GHC_INLINE void permissions(const path& p, perms prms, perm_options opts, std::error_code& ec) noexcept { if (static_cast(opts & (perm_options::replace | perm_options::add | perm_options::remove)) == 0) { ec = detail::make_error_code(detail::portable_error::invalid_argument); return; } auto fs = symlink_status(p, ec); if ((opts & perm_options::replace) != perm_options::replace) { if ((opts & perm_options::add) == perm_options::add) { prms = fs.permissions() | prms; } else { prms = fs.permissions() & ~prms; } } #ifdef GHC_OS_WINDOWS #ifdef __GNUC__ auto oldAttr = GetFileAttributesW(GHC_NATIVEWP(p)); if (oldAttr != INVALID_FILE_ATTRIBUTES) { DWORD newAttr = ((prms & perms::owner_write) == perms::owner_write) ? oldAttr & ~(static_cast(FILE_ATTRIBUTE_READONLY)) : oldAttr | FILE_ATTRIBUTE_READONLY; if (oldAttr == newAttr || SetFileAttributesW(GHC_NATIVEWP(p), newAttr)) { return; } } ec = detail::make_system_error(); #else int mode = 0; if ((prms & perms::owner_read) == perms::owner_read) { mode |= _S_IREAD; } if ((prms & perms::owner_write) == perms::owner_write) { mode |= _S_IWRITE; } if (::_wchmod(p.wstring().c_str(), mode) != 0) { ec = detail::make_system_error(); } #endif #else if ((opts & perm_options::nofollow) != perm_options::nofollow) { if (::chmod(p.c_str(), static_cast(prms)) != 0) { ec = detail::make_system_error(); } } #endif } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE path proximate(const path& p, std::error_code& ec) { auto cp = current_path(ec); if (!ec) { return proximate(p, cp, ec); } return path(); } #endif #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE path proximate(const path& p, const path& base) { return weakly_canonical(p).lexically_proximate(weakly_canonical(base)); } #endif GHC_INLINE path proximate(const path& p, const path& base, std::error_code& ec) { return weakly_canonical(p, ec).lexically_proximate(weakly_canonical(base, ec)); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE path read_symlink(const path& p) { std::error_code ec; auto result = read_symlink(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE path read_symlink(const path& p, std::error_code& ec) { file_status fs = symlink_status(p, ec); if (fs.type() != file_type::symlink) { ec = detail::make_error_code(detail::portable_error::invalid_argument); return path(); } auto result = detail::resolveSymlink(p, ec); return ec ? path() : result; } GHC_INLINE path relative(const path& p, std::error_code& ec) { return relative(p, current_path(ec), ec); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE path relative(const path& p, const path& base) { return weakly_canonical(p).lexically_relative(weakly_canonical(base)); } #endif GHC_INLINE path relative(const path& p, const path& base, std::error_code& ec) { return weakly_canonical(p, ec).lexically_relative(weakly_canonical(base, ec)); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool remove(const path& p) { std::error_code ec; auto result = remove(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE bool remove(const path& p, std::error_code& ec) noexcept { ec.clear(); #ifdef GHC_OS_WINDOWS #ifdef GHC_USE_WCHAR_T auto cstr = p.c_str(); #else std::wstring np = detail::fromUtf8(p.u8string()); auto cstr = np.c_str(); #endif DWORD attr = GetFileAttributesW(cstr); if (attr == INVALID_FILE_ATTRIBUTES) { auto error = ::GetLastError(); if (error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND) { return false; } ec = detail::make_system_error(error); } else if (attr & FILE_ATTRIBUTE_READONLY) { auto new_attr = attr & ~static_cast(FILE_ATTRIBUTE_READONLY); if (!SetFileAttributesW(cstr, new_attr)) { auto error = ::GetLastError(); ec = detail::make_system_error(error); } } if (!ec) { if (attr & FILE_ATTRIBUTE_DIRECTORY) { if (!RemoveDirectoryW(cstr)) { ec = detail::make_system_error(); } } else { if (!DeleteFileW(cstr)) { ec = detail::make_system_error(); } } } #else if (::remove(p.c_str()) == -1) { auto error = errno; if (error == ENOENT) { return false; } ec = detail::make_system_error(); } #endif return ec ? false : true; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE uintmax_t remove_all(const path& p) { std::error_code ec; auto result = remove_all(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE uintmax_t remove_all(const path& p, std::error_code& ec) noexcept { ec.clear(); uintmax_t count = 0; if (p == "/") { ec = detail::make_error_code(detail::portable_error::not_supported); return static_cast(-1); } std::error_code tec; auto fs = symlink_status(p, tec); if (exists(fs) && is_directory(fs)) { for (auto iter = directory_iterator(p, ec); iter != directory_iterator(); iter.increment(ec)) { if (ec && !detail::is_not_found_error(ec)) { break; } bool is_symlink_result = iter->is_symlink(ec); if (ec) return static_cast(-1); if (!is_symlink_result && iter->is_directory(ec)) { count += remove_all(iter->path(), ec); if (ec) { return static_cast(-1); } } else { if (!ec) { remove(iter->path(), ec); } if (ec) { return static_cast(-1); } ++count; } } } if (!ec) { if (remove(p, ec)) { ++count; } } if (ec) { return static_cast(-1); } return count; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void rename(const path& from, const path& to) { std::error_code ec; rename(from, to, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec); } } #endif GHC_INLINE void rename(const path& from, const path& to, std::error_code& ec) noexcept { ec.clear(); #ifdef GHC_OS_WINDOWS if (from != to) { if (!MoveFileExW(GHC_NATIVEWP(from), GHC_NATIVEWP(to), (DWORD)MOVEFILE_REPLACE_EXISTING)) { ec = detail::make_system_error(); } } #else if (from != to) { if (::rename(from.c_str(), to.c_str()) != 0) { ec = detail::make_system_error(); } } #endif } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void resize_file(const path& p, uintmax_t size) { std::error_code ec; resize_file(p, size, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } } #endif GHC_INLINE void resize_file(const path& p, uintmax_t size, std::error_code& ec) noexcept { ec.clear(); #ifdef GHC_OS_WINDOWS LARGE_INTEGER lisize; lisize.QuadPart = static_cast(size); if (lisize.QuadPart < 0) { #ifdef ERROR_FILE_TOO_LARGE ec = detail::make_system_error(ERROR_FILE_TOO_LARGE); #else ec = detail::make_system_error(223); #endif return; } detail::unique_handle file(CreateFileW(GHC_NATIVEWP(p), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)); if (!file) { ec = detail::make_system_error(); } else if (SetFilePointerEx(file.get(), lisize, NULL, FILE_BEGIN) == 0 || SetEndOfFile(file.get()) == 0) { ec = detail::make_system_error(); } #else if (::truncate(p.c_str(), static_cast(size)) != 0) { ec = detail::make_system_error(); } #endif } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE space_info space(const path& p) { std::error_code ec; auto result = space(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE space_info space(const path& p, std::error_code& ec) noexcept { ec.clear(); #ifdef GHC_OS_WINDOWS ULARGE_INTEGER freeBytesAvailableToCaller = {{ 0, 0 }}; ULARGE_INTEGER totalNumberOfBytes = {{ 0, 0 }}; ULARGE_INTEGER totalNumberOfFreeBytes = {{ 0, 0 }}; if (!GetDiskFreeSpaceExW(GHC_NATIVEWP(p), &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes)) { ec = detail::make_system_error(); return {static_cast(-1), static_cast(-1), static_cast(-1)}; } return {static_cast(totalNumberOfBytes.QuadPart), static_cast(totalNumberOfFreeBytes.QuadPart), static_cast(freeBytesAvailableToCaller.QuadPart)}; #else struct ::statvfs sfs; if (::statvfs(p.c_str(), &sfs) != 0) { ec = detail::make_system_error(); return {static_cast(-1), static_cast(-1), static_cast(-1)}; } return {static_cast(sfs.f_blocks) * static_cast(sfs.f_frsize), static_cast(sfs.f_bfree) * static_cast(sfs.f_frsize), static_cast(sfs.f_bavail) * static_cast(sfs.f_frsize)}; #endif } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE file_status status(const path& p) { std::error_code ec; auto result = status(p, ec); if (result.type() == file_type::none) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE file_status status(const path& p, std::error_code& ec) noexcept { return detail::status_ex(p, ec); } GHC_INLINE bool status_known(file_status s) noexcept { return s.type() != file_type::none; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE file_status symlink_status(const path& p) { std::error_code ec; auto result = symlink_status(p, ec); if (result.type() == file_type::none) { throw filesystem_error(detail::systemErrorText(ec.value()), ec); } return result; } #endif GHC_INLINE file_status symlink_status(const path& p, std::error_code& ec) noexcept { return detail::symlink_status_ex(p, ec); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE path temp_directory_path() { std::error_code ec; path result = temp_directory_path(ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), ec); } return result; } #endif GHC_INLINE path temp_directory_path(std::error_code& ec) noexcept { ec.clear(); #ifdef GHC_OS_WINDOWS wchar_t buffer[512]; auto rc = GetTempPathW(511, buffer); if (!rc || rc > 511) { ec = detail::make_system_error(); return path(); } return path(std::wstring(buffer)); #else static const char* temp_vars[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr}; const char* temp_path = nullptr; for (auto temp_name = temp_vars; *temp_name != nullptr; ++temp_name) { temp_path = std::getenv(*temp_name); if (temp_path) { return path(temp_path); } } return path("/tmp"); #endif } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE path weakly_canonical(const path& p) { std::error_code ec; auto result = weakly_canonical(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE path weakly_canonical(const path& p, std::error_code& ec) noexcept { path result; ec.clear(); bool scan = true; for (auto pe : p) { if (scan) { std::error_code tec; if (exists(result / pe, tec)) { result /= pe; } else { if (ec) { return path(); } scan = false; if (!result.empty()) { result = canonical(result, ec) / pe; if (ec) { break; } } else { result /= pe; } } } else { result /= pe; } } if (scan) { if (!result.empty()) { result = canonical(result, ec); } } return ec ? path() : result.lexically_normal(); } //----------------------------------------------------------------------------- // [fs.class.file_status] class file_status // [fs.file_status.cons] constructors and destructor GHC_INLINE file_status::file_status() noexcept : file_status(file_type::none) { } GHC_INLINE file_status::file_status(file_type ft, perms prms) noexcept : _type(ft) , _perms(prms) { } GHC_INLINE file_status::file_status(const file_status& other) noexcept : _type(other._type) , _perms(other._perms) { } GHC_INLINE file_status::file_status(file_status&& other) noexcept : _type(other._type) , _perms(other._perms) { } GHC_INLINE file_status::~file_status() {} // assignments: GHC_INLINE file_status& file_status::operator=(const file_status& rhs) noexcept { _type = rhs._type; _perms = rhs._perms; return *this; } GHC_INLINE file_status& file_status::operator=(file_status&& rhs) noexcept { _type = rhs._type; _perms = rhs._perms; return *this; } // [fs.file_status.mods] modifiers GHC_INLINE void file_status::type(file_type ft) noexcept { _type = ft; } GHC_INLINE void file_status::permissions(perms prms) noexcept { _perms = prms; } // [fs.file_status.obs] observers GHC_INLINE file_type file_status::type() const noexcept { return _type; } GHC_INLINE perms file_status::permissions() const noexcept { return _perms; } //----------------------------------------------------------------------------- // [fs.class.directory_entry] class directory_entry // [fs.dir.entry.cons] constructors and destructor // directory_entry::directory_entry() noexcept = default; // directory_entry::directory_entry(const directory_entry&) = default; // directory_entry::directory_entry(directory_entry&&) noexcept = default; #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE directory_entry::directory_entry(const filesystem::path& p) : _path(p) , _file_size(static_cast(-1)) #ifndef GHC_OS_WINDOWS , _hard_link_count(static_cast(-1)) #endif , _last_write_time(0) { refresh(); } #endif GHC_INLINE directory_entry::directory_entry(const filesystem::path& p, std::error_code& ec) : _path(p) , _file_size(static_cast(-1)) #ifndef GHC_OS_WINDOWS , _hard_link_count(static_cast(-1)) #endif , _last_write_time(0) { refresh(ec); } GHC_INLINE directory_entry::~directory_entry() {} // assignments: // directory_entry& directory_entry::operator=(const directory_entry&) = default; // directory_entry& directory_entry::operator=(directory_entry&&) noexcept = default; // [fs.dir.entry.mods] directory_entry modifiers #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void directory_entry::assign(const filesystem::path& p) { _path = p; refresh(); } #endif GHC_INLINE void directory_entry::assign(const filesystem::path& p, std::error_code& ec) { _path = p; refresh(ec); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void directory_entry::replace_filename(const filesystem::path& p) { _path.replace_filename(p); refresh(); } #endif GHC_INLINE void directory_entry::replace_filename(const filesystem::path& p, std::error_code& ec) { _path.replace_filename(p); refresh(ec); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void directory_entry::refresh() { std::error_code ec; refresh(ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), _path, ec); } } #endif GHC_INLINE void directory_entry::refresh(std::error_code& ec) noexcept { #ifdef GHC_OS_WINDOWS _status = detail::status_ex(_path, ec, &_symlink_status, &_file_size, nullptr, &_last_write_time); #else _status = detail::status_ex(_path, ec, &_symlink_status, &_file_size, &_hard_link_count, &_last_write_time); #endif } // [fs.dir.entry.obs] directory_entry observers GHC_INLINE const filesystem::path& directory_entry::path() const noexcept { return _path; } GHC_INLINE directory_entry::operator const filesystem::path&() const noexcept { return _path; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE file_type directory_entry::status_file_type() const { return _status.type() != file_type::none ? _status.type() : filesystem::status(path()).type(); } #endif GHC_INLINE file_type directory_entry::status_file_type(std::error_code& ec) const noexcept { if (_status.type() != file_type::none) { ec.clear(); return _status.type(); } return filesystem::status(path(), ec).type(); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::exists() const { return status_file_type() != file_type::not_found; } #endif GHC_INLINE bool directory_entry::exists(std::error_code& ec) const noexcept { return status_file_type(ec) != file_type::not_found; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_block_file() const { return status_file_type() == file_type::block; } #endif GHC_INLINE bool directory_entry::is_block_file(std::error_code& ec) const noexcept { return status_file_type(ec) == file_type::block; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_character_file() const { return status_file_type() == file_type::character; } #endif GHC_INLINE bool directory_entry::is_character_file(std::error_code& ec) const noexcept { return status_file_type(ec) == file_type::character; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_directory() const { return status_file_type() == file_type::directory; } #endif GHC_INLINE bool directory_entry::is_directory(std::error_code& ec) const noexcept { return status_file_type(ec) == file_type::directory; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_fifo() const { return status_file_type() == file_type::fifo; } #endif GHC_INLINE bool directory_entry::is_fifo(std::error_code& ec) const noexcept { return status_file_type(ec) == file_type::fifo; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_other() const { auto ft = status_file_type(); return ft != file_type::none && ft != file_type::not_found && ft != file_type::regular && ft != file_type::directory && !is_symlink(); } #endif GHC_INLINE bool directory_entry::is_other(std::error_code& ec) const noexcept { auto ft = status_file_type(ec); bool other = ft != file_type::none && ft != file_type::not_found && ft != file_type::regular && ft != file_type::directory && !is_symlink(ec); return !ec && other; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_regular_file() const { return status_file_type() == file_type::regular; } #endif GHC_INLINE bool directory_entry::is_regular_file(std::error_code& ec) const noexcept { return status_file_type(ec) == file_type::regular; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_socket() const { return status_file_type() == file_type::socket; } #endif GHC_INLINE bool directory_entry::is_socket(std::error_code& ec) const noexcept { return status_file_type(ec) == file_type::socket; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_symlink() const { return _symlink_status.type() != file_type::none ? _symlink_status.type() == file_type::symlink : filesystem::is_symlink(symlink_status()); } #endif GHC_INLINE bool directory_entry::is_symlink(std::error_code& ec) const noexcept { if (_symlink_status.type() != file_type::none) { ec.clear(); return _symlink_status.type() == file_type::symlink; } return filesystem::is_symlink(symlink_status(ec)); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE uintmax_t directory_entry::file_size() const { if (_file_size != static_cast(-1)) { return _file_size; } return filesystem::file_size(path()); } #endif GHC_INLINE uintmax_t directory_entry::file_size(std::error_code& ec) const noexcept { if (_file_size != static_cast(-1)) { ec.clear(); return _file_size; } return filesystem::file_size(path(), ec); } #ifndef GHC_OS_WEB #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE uintmax_t directory_entry::hard_link_count() const { #ifndef GHC_OS_WINDOWS if (_hard_link_count != static_cast(-1)) { return _hard_link_count; } #endif return filesystem::hard_link_count(path()); } #endif GHC_INLINE uintmax_t directory_entry::hard_link_count(std::error_code& ec) const noexcept { #ifndef GHC_OS_WINDOWS if (_hard_link_count != static_cast(-1)) { ec.clear(); return _hard_link_count; } #endif return filesystem::hard_link_count(path(), ec); } #endif #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE file_time_type directory_entry::last_write_time() const { if (_last_write_time != 0) { return std::chrono::system_clock::from_time_t(_last_write_time); } return filesystem::last_write_time(path()); } #endif GHC_INLINE file_time_type directory_entry::last_write_time(std::error_code& ec) const noexcept { if (_last_write_time != 0) { ec.clear(); return std::chrono::system_clock::from_time_t(_last_write_time); } return filesystem::last_write_time(path(), ec); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE file_status directory_entry::status() const { if (_status.type() != file_type::none && _status.permissions() != perms::unknown) { return _status; } return filesystem::status(path()); } #endif GHC_INLINE file_status directory_entry::status(std::error_code& ec) const noexcept { if (_status.type() != file_type::none && _status.permissions() != perms::unknown) { ec.clear(); return _status; } return filesystem::status(path(), ec); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE file_status directory_entry::symlink_status() const { if (_symlink_status.type() != file_type::none && _symlink_status.permissions() != perms::unknown) { return _symlink_status; } return filesystem::symlink_status(path()); } #endif GHC_INLINE file_status directory_entry::symlink_status(std::error_code& ec) const noexcept { if (_symlink_status.type() != file_type::none && _symlink_status.permissions() != perms::unknown) { ec.clear(); return _symlink_status; } return filesystem::symlink_status(path(), ec); } #ifdef GHC_HAS_THREEWAY_COMP GHC_INLINE std::strong_ordering directory_entry::operator<=>(const directory_entry& rhs) const noexcept { return _path <=> rhs._path; } #endif GHC_INLINE bool directory_entry::operator<(const directory_entry& rhs) const noexcept { return _path < rhs._path; } GHC_INLINE bool directory_entry::operator==(const directory_entry& rhs) const noexcept { return _path == rhs._path; } GHC_INLINE bool directory_entry::operator!=(const directory_entry& rhs) const noexcept { return _path != rhs._path; } GHC_INLINE bool directory_entry::operator<=(const directory_entry& rhs) const noexcept { return _path <= rhs._path; } GHC_INLINE bool directory_entry::operator>(const directory_entry& rhs) const noexcept { return _path > rhs._path; } GHC_INLINE bool directory_entry::operator>=(const directory_entry& rhs) const noexcept { return _path >= rhs._path; } //----------------------------------------------------------------------------- // [fs.class.directory_iterator] class directory_iterator #ifdef GHC_OS_WINDOWS class directory_iterator::impl { public: impl(const path& p, directory_options options) : _base(p) , _options(options) , _dirHandle(INVALID_HANDLE_VALUE) { if (!_base.empty()) { ZeroMemory(&_findData, sizeof(WIN32_FIND_DATAW)); if ((_dirHandle = FindFirstFileW(GHC_NATIVEWP((_base / "*")), &_findData)) != INVALID_HANDLE_VALUE) { if (std::wstring(_findData.cFileName) == L"." || std::wstring(_findData.cFileName) == L"..") { increment(_ec); } else { _dir_entry._path = _base / std::wstring(_findData.cFileName); copyToDirEntry(_ec); } } else { auto error = ::GetLastError(); _base = filesystem::path(); if (error != ERROR_ACCESS_DENIED || (options & directory_options::skip_permission_denied) == directory_options::none) { _ec = detail::make_system_error(); } } } } impl(const impl& other) = delete; ~impl() { if (_dirHandle != INVALID_HANDLE_VALUE) { FindClose(_dirHandle); _dirHandle = INVALID_HANDLE_VALUE; } } void increment(std::error_code& ec) { if (_dirHandle != INVALID_HANDLE_VALUE) { do { if (FindNextFileW(_dirHandle, &_findData)) { _dir_entry._path = _base; #ifdef GHC_USE_WCHAR_T _dir_entry._path.append_name(_findData.cFileName); #else #ifdef GHC_RAISE_UNICODE_ERRORS try { _dir_entry._path.append_name(detail::toUtf8(_findData.cFileName).c_str()); } catch (filesystem_error& fe) { ec = fe.code(); return; } #else _dir_entry._path.append_name(detail::toUtf8(_findData.cFileName).c_str()); #endif #endif copyToDirEntry(ec); } else { auto err = ::GetLastError(); if (err != ERROR_NO_MORE_FILES) { _ec = ec = detail::make_system_error(err); } FindClose(_dirHandle); _dirHandle = INVALID_HANDLE_VALUE; _dir_entry._path.clear(); break; } } while (std::wstring(_findData.cFileName) == L"." || std::wstring(_findData.cFileName) == L".."); } else { ec = _ec; } } void copyToDirEntry(std::error_code& ec) { if (_findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { _dir_entry._status = detail::status_ex(_dir_entry._path, ec, &_dir_entry._symlink_status, &_dir_entry._file_size, nullptr, &_dir_entry._last_write_time); } else { _dir_entry._status = detail::status_from_INFO(_dir_entry._path, &_findData, ec, &_dir_entry._file_size, &_dir_entry._last_write_time); _dir_entry._symlink_status = _dir_entry._status; } if (ec) { if (_dir_entry._status.type() != file_type::none && _dir_entry._symlink_status.type() != file_type::none) { ec.clear(); } else { _dir_entry._file_size = static_cast(-1); _dir_entry._last_write_time = 0; } } } path _base; directory_options _options; WIN32_FIND_DATAW _findData; HANDLE _dirHandle; directory_entry _dir_entry; std::error_code _ec; }; #else // POSIX implementation class directory_iterator::impl { public: impl(const path& path, directory_options options) : _base(path) , _options(options) , _dir(nullptr) , _entry(nullptr) { if (!path.empty()) { _dir = ::opendir(path.native().c_str()); if (!_dir) { auto error = errno; _base = filesystem::path(); if ((error != EACCES && error != EPERM) || (options & directory_options::skip_permission_denied) == directory_options::none) { _ec = detail::make_system_error(); } } else { increment(_ec); } } } impl(const impl& other) = delete; ~impl() { if (_dir) { ::closedir(_dir); } } void increment(std::error_code& ec) { if (_dir) { bool skip; do { skip = false; errno = 0; _entry = ::readdir(_dir); if (_entry) { _dir_entry._path = _base; _dir_entry._path.append_name(_entry->d_name); copyToDirEntry(); if (ec && (ec.value() == EACCES || ec.value() == EPERM) && (_options & directory_options::skip_permission_denied) == directory_options::skip_permission_denied) { ec.clear(); skip = true; } } else { ::closedir(_dir); _dir = nullptr; _dir_entry._path.clear(); if (errno) { ec = detail::make_system_error(); } break; } } while (skip || std::strcmp(_entry->d_name, ".") == 0 || std::strcmp(_entry->d_name, "..") == 0); } } void copyToDirEntry() { _dir_entry._symlink_status.permissions(perms::unknown); auto ft = detail::file_type_from_dirent(*_entry); _dir_entry._symlink_status.type(ft); if (ft != file_type::symlink) { _dir_entry._status = _dir_entry._symlink_status; } else { _dir_entry._status.type(file_type::none); _dir_entry._status.permissions(perms::unknown); } _dir_entry._file_size = static_cast(-1); _dir_entry._hard_link_count = static_cast(-1); _dir_entry._last_write_time = 0; } path _base; directory_options _options; DIR* _dir; struct ::dirent* _entry; directory_entry _dir_entry; std::error_code _ec; }; #endif // [fs.dir.itr.members] member functions GHC_INLINE directory_iterator::directory_iterator() noexcept : _impl(new impl(path(), directory_options::none)) { } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE directory_iterator::directory_iterator(const path& p) : _impl(new impl(p, directory_options::none)) { if (_impl->_ec) { throw filesystem_error(detail::systemErrorText(_impl->_ec.value()), p, _impl->_ec); } _impl->_ec.clear(); } GHC_INLINE directory_iterator::directory_iterator(const path& p, directory_options options) : _impl(new impl(p, options)) { if (_impl->_ec) { throw filesystem_error(detail::systemErrorText(_impl->_ec.value()), p, _impl->_ec); } } #endif GHC_INLINE directory_iterator::directory_iterator(const path& p, std::error_code& ec) noexcept : _impl(new impl(p, directory_options::none)) { if (_impl->_ec) { ec = _impl->_ec; } } GHC_INLINE directory_iterator::directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept : _impl(new impl(p, options)) { if (_impl->_ec) { ec = _impl->_ec; } } GHC_INLINE directory_iterator::directory_iterator(const directory_iterator& rhs) : _impl(rhs._impl) { } GHC_INLINE directory_iterator::directory_iterator(directory_iterator&& rhs) noexcept : _impl(std::move(rhs._impl)) { } GHC_INLINE directory_iterator::~directory_iterator() {} GHC_INLINE directory_iterator& directory_iterator::operator=(const directory_iterator& rhs) { _impl = rhs._impl; return *this; } GHC_INLINE directory_iterator& directory_iterator::operator=(directory_iterator&& rhs) noexcept { _impl = std::move(rhs._impl); return *this; } GHC_INLINE const directory_entry& directory_iterator::operator*() const { return _impl->_dir_entry; } GHC_INLINE const directory_entry* directory_iterator::operator->() const { return &_impl->_dir_entry; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE directory_iterator& directory_iterator::operator++() { std::error_code ec; _impl->increment(ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_entry._path, ec); } return *this; } #endif GHC_INLINE directory_iterator& directory_iterator::increment(std::error_code& ec) noexcept { _impl->increment(ec); return *this; } GHC_INLINE bool directory_iterator::operator==(const directory_iterator& rhs) const { return _impl->_dir_entry._path == rhs._impl->_dir_entry._path; } GHC_INLINE bool directory_iterator::operator!=(const directory_iterator& rhs) const { return _impl->_dir_entry._path != rhs._impl->_dir_entry._path; } // [fs.dir.itr.nonmembers] directory_iterator non-member functions GHC_INLINE directory_iterator begin(directory_iterator iter) noexcept { return iter; } GHC_INLINE directory_iterator end(const directory_iterator&) noexcept { return directory_iterator(); } //----------------------------------------------------------------------------- // [fs.class.rec.dir.itr] class recursive_directory_iterator GHC_INLINE recursive_directory_iterator::recursive_directory_iterator() noexcept : _impl(new recursive_directory_iterator_impl(directory_options::none, true)) { _impl->_dir_iter_stack.push(directory_iterator()); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p) : _impl(new recursive_directory_iterator_impl(directory_options::none, true)) { _impl->_dir_iter_stack.push(directory_iterator(p)); } GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options) : _impl(new recursive_directory_iterator_impl(options, true)) { _impl->_dir_iter_stack.push(directory_iterator(p, options)); } #endif GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept : _impl(new recursive_directory_iterator_impl(options, true)) { _impl->_dir_iter_stack.push(directory_iterator(p, options, ec)); } GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, std::error_code& ec) noexcept : _impl(new recursive_directory_iterator_impl(directory_options::none, true)) { _impl->_dir_iter_stack.push(directory_iterator(p, ec)); } GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const recursive_directory_iterator& rhs) : _impl(rhs._impl) { } GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept : _impl(std::move(rhs._impl)) { } GHC_INLINE recursive_directory_iterator::~recursive_directory_iterator() {} // [fs.rec.dir.itr.members] observers GHC_INLINE directory_options recursive_directory_iterator::options() const { return _impl->_options; } GHC_INLINE int recursive_directory_iterator::depth() const { return static_cast(_impl->_dir_iter_stack.size() - 1); } GHC_INLINE bool recursive_directory_iterator::recursion_pending() const { return _impl->_recursion_pending; } GHC_INLINE const directory_entry& recursive_directory_iterator::operator*() const { return *(_impl->_dir_iter_stack.top()); } GHC_INLINE const directory_entry* recursive_directory_iterator::operator->() const { return &(*(_impl->_dir_iter_stack.top())); } // [fs.rec.dir.itr.members] modifiers recursive_directory_iterator& GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator=(const recursive_directory_iterator& rhs) { _impl = rhs._impl; return *this; } GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator=(recursive_directory_iterator&& rhs) noexcept { _impl = std::move(rhs._impl); return *this; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator++() { std::error_code ec; increment(ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_iter_stack.empty() ? path() : _impl->_dir_iter_stack.top()->path(), ec); } return *this; } #endif GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::increment(std::error_code& ec) noexcept { bool isSymLink = (*this)->is_symlink(ec); bool isDir = !ec && (*this)->is_directory(ec); if (isSymLink && detail::is_not_found_error(ec)) { ec.clear(); } if (!ec) { if (recursion_pending() && isDir && (!isSymLink || (options() & directory_options::follow_directory_symlink) != directory_options::none)) { _impl->_dir_iter_stack.push(directory_iterator((*this)->path(), _impl->_options, ec)); } else { _impl->_dir_iter_stack.top().increment(ec); } if (!ec) { while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) { _impl->_dir_iter_stack.pop(); _impl->_dir_iter_stack.top().increment(ec); } } else if (!_impl->_dir_iter_stack.empty()) { _impl->_dir_iter_stack.pop(); } _impl->_recursion_pending = true; } return *this; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void recursive_directory_iterator::pop() { std::error_code ec; pop(ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_iter_stack.empty() ? path() : _impl->_dir_iter_stack.top()->path(), ec); } } #endif GHC_INLINE void recursive_directory_iterator::pop(std::error_code& ec) { if (depth() == 0) { *this = recursive_directory_iterator(); } else { do { _impl->_dir_iter_stack.pop(); _impl->_dir_iter_stack.top().increment(ec); } while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()); } } GHC_INLINE void recursive_directory_iterator::disable_recursion_pending() { _impl->_recursion_pending = false; } // other members as required by [input.iterators] GHC_INLINE bool recursive_directory_iterator::operator==(const recursive_directory_iterator& rhs) const { return _impl->_dir_iter_stack.top() == rhs._impl->_dir_iter_stack.top(); } GHC_INLINE bool recursive_directory_iterator::operator!=(const recursive_directory_iterator& rhs) const { return _impl->_dir_iter_stack.top() != rhs._impl->_dir_iter_stack.top(); } // [fs.rec.dir.itr.nonmembers] directory_iterator non-member functions GHC_INLINE recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept { return iter; } GHC_INLINE recursive_directory_iterator end(const recursive_directory_iterator&) noexcept { return recursive_directory_iterator(); } #endif // GHC_EXPAND_IMPL } // namespace filesystem } // namespace ghc // cleanup some macros #undef GHC_INLINE #undef GHC_EXPAND_IMPL #endif // GHC_FILESYSTEM_H eureka-editor-eureka-2.0.2/src/fltk-patch/000077500000000000000000000000001464327712600203655ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/src/fltk-patch/Fl_JPEG_Image-fltk1.3.8-macos.diff000066400000000000000000000015561464327712600261240ustar00rootroot00000000000000131a132,134 > > volatile char *volatile_max_finish_decompress_err = max_finish_decompress_err; > volatile char *volatile_max_destroy_decompress_err = max_destroy_decompress_err; 139c142 < if ( ((*max_finish_decompress_err)-- > 0) && array) --- > if ( ((*volatile_max_finish_decompress_err)-- > 0) && array) 141c144 < if ( (*max_destroy_decompress_err)-- > 0) --- > if ( (*volatile_max_destroy_decompress_err)-- > 0) 319a323,325 > > volatile char *volatile_max_finish_decompress_err = max_finish_decompress_err; > volatile char *volatile_max_destroy_decompress_err = max_destroy_decompress_err; 327c333 < if ( ((*max_finish_decompress_err)-- > 0) && array) --- > if ( ((*volatile_max_finish_decompress_err)-- > 0) && array) 329c335 < if ( (*max_destroy_decompress_err)-- > 0) --- > if ( (*volatile_max_destroy_decompress_err)-- > 0) eureka-editor-eureka-2.0.2/src/hdr_fltk.h000066400000000000000000000043151464327712600203010ustar00rootroot00000000000000//------------------------------------------------------------------------ // FLTK INCLUDES //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2008 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_HDR_FLTK__ #define __EUREKA_HDR_FLTK__ /* FLTK - Widget Library */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "WindowsSanitization.h" #endif /* __EUREKA_HDR_FLTK__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/im_color.cc000066400000000000000000000307441464327712600204520ustar00rootroot00000000000000//------------------------------------------------------------------------ // COLORS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Instance.h" #include "im_color.h" #include "m_config.h" // config item int config::usegamma = 2; int config::panel_gamma = 2; bool Palette::updateGamma(int usegamma, int panel_gamma) { if(usegamma < 0 || panel_gamma < 0 || usegamma >= (int)lengthof(gammatable) || panel_gamma >= (int)lengthof(gammatable)) { return false; } for (int c = 0 ; c < 256 ; c++) { byte r = raw_palette[c][0]; byte g = raw_palette[c][1]; byte b = raw_palette[c][2]; byte r2 = static_cast(gammatable[usegamma][r]); byte g2 = static_cast(gammatable[usegamma][g]); byte b2 = static_cast(gammatable[usegamma][b]); palette[c] = rgbMake(r2, g2, b2); r2 = static_cast(gammatable[panel_gamma][r]); g2 = static_cast(gammatable[panel_gamma][g]); b2 = static_cast(gammatable[panel_gamma][b]); palette_medium[c] = rgbMake(r2, g2, b2); } for (int d = 0 ; d < 32 ; d++) { int i = d * 255 / 31; rgb555_gamma [d] = static_cast(gammatable[usegamma][i]); rgb555_medium[d] = static_cast(gammatable[panel_gamma][i]); } return true; } bool Palette::loadPalette(const Lump_c &lump, int usegamma, int panel_gamma) { if(lump.getData().size() < sizeof(raw_palette)) { gLog.printf("PLAYPAL: read error\n"); return false; } memcpy(raw_palette, lump.getData().data(), sizeof(raw_palette)); // find the colour closest to TRANS_PIXEL byte tr = raw_palette[TRANS_PIXEL][0]; byte tg = raw_palette[TRANS_PIXEL][1]; byte tb = raw_palette[TRANS_PIXEL][2]; trans_replace = findPaletteColor(tr, tg, tb); if(!updateGamma(usegamma, panel_gamma)) return false; createBrightMap(); return true; } void Palette::loadColormap(const Lump_c *lump) { if (! lump) { ThrowException("COLORMAP lump not found.\n"); return; } LumpInputStream stream(*lump); if (! stream.read(raw_colormap, sizeof(raw_colormap))) { gLog.printf("COLORMAP: read error\n"); return; } // ensure colormap does not transparent pixel for (int i = 0 ; i < 32 ; i++) for (int c = 0 ; c < 256 ; c++) { if (raw_colormap[i][c] == TRANS_PIXEL) raw_colormap[i][c] = static_cast(trans_replace); } // workaround for Harmony having a bugged colormap if (raw_palette[0][0] == 0 && raw_palette[0][1] == 0 && raw_palette[0][2] == 0) { for (int k = 0 ; k < 32 ; k++) raw_colormap[k][0] = 0; } } rgb_color_t DarkerColor(rgb_color_t col) { int r = RGB_RED(col); int g = RGB_GREEN(col); int b = RGB_BLUE(col); return fl_rgb_color(static_cast(r*2/3), static_cast(g*2/3), static_cast(b*2/3)); } static rgb_color_t LighterColor(rgb_color_t col) { int r = RGB_RED(col); int g = RGB_GREEN(col); int b = RGB_BLUE(col); r = r * 13 / 16 + 48; g = g * 13 / 16 + 48; b = b * 13 / 16 + 48; return rgbMake(r, g, b); } byte Palette::findPaletteColor(int r, int g, int b) const { int best = 0; int best_dist = (1 << 30); for (int c = 0 ; c < 256 ; c++) { if (c == TRANS_PIXEL) continue; int dr = r - (int)raw_palette[c][0]; int dg = g - (int)raw_palette[c][1]; int db = b - (int)raw_palette[c][2]; int dist = dr*dr + dg*dg + db*db; if (dist < best_dist) { best = c; best_dist = dist; } } return static_cast(best); } void Palette::createBrightMap() { for (int c = 0 ; c < 256 ; c++) { byte r = raw_palette[c][0]; byte g = raw_palette[c][1]; byte b = raw_palette[c][2]; rgb_color_t col = LighterColor(rgbMake(r, g, b)); r = RGB_RED(col); g = RGB_GREEN(col); b = RGB_BLUE(col); bright_map[c] = findPaletteColor(r, g, b); } } rgb_color_t ParseColor(const SString &cstr) { SString str(cstr); if(str[0] == '#') str.erase(0, 1); if (str.length() >= 6) // long form #rrggbb { int number = (int)strtol(str, NULL, 16); int r = (number & 0xFF0000) >> 16; int g = (number & 0x00FF00) >> 8; int b = (number & 0x0000FF); return fl_rgb_color(static_cast(r), static_cast(g), static_cast(b)); } else // short form: #rgb { int number = (int)strtol(str, NULL, 16); int r = (number & 0xF00) >> 8; int g = (number & 0x0F0) >> 4; int b = (number & 0x00F); return fl_rgb_color(static_cast(r*17), static_cast(g*17), static_cast(b*17)); } } rgb_color_t SectorLightColor(int light) { int lt = light; // sample three distances, produce average lt = R_DoomLightingEquation(light, 60.0) + R_DoomLightingEquation(light, 160.0) + R_DoomLightingEquation(light, 560.0); lt = (93 - lt) * 255 / 93; // need to gamma-correct the light level if (config::usegamma > 0) lt = gammatable[config::usegamma][lt]; return rgbMake(lt, lt, lt); } int HashedPalColor(const SString &name, const int *cols) { // cols is array of two elements: start and end color. // this returns a palette color somewhere between start // and end, depending on the texture name. int len = (int)name.length(); int hash = name[0]*41; if (len >= 2) hash += name[2]*13; if (len >= 4) hash += name[4]*17; if (len >= 5) hash += name[5]*7; if (len >= 7) hash += name[7]*3; hash ^= (hash >> 5); int c1 = cols[0]; int c2 = cols[1]; if (c1 > c2) std::swap(c1, c2); if (c1 == c2) return c1; return c1 + hash % (c2 - c1 + 1); } //------------------------------------------------------------------------ const int gammatable[5][256] = { { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 }, { 2, 4, 5, 7, 8, 10, 11, 12, 14, 15, 16, 18, 19, 20, 21, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 41, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224, 225, 226, 227, 228, 229, 230, 230, 231, 232, 233, 234, 235, 236, 237, 237, 238, 239, 240, 241, 242, 243, 244, 245, 245, 246, 247, 248, 249, 250, 251, 252, 252, 253, 254, 255 }, { 4, 7, 9, 11, 13, 15, 17, 19, 21, 22, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 40, 42, 43, 45, 46, 47, 48, 50, 51, 52, 54, 55, 56, 57, 59, 60, 61, 62, 63, 65, 66, 67, 68, 69, 70, 72, 73, 74, 75, 76, 77, 78, 79, 80, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 153, 154, 155, 156, 157, 158, 159, 160, 160, 161, 162, 163, 164, 165, 166, 166, 167, 168, 169, 170, 171, 172, 172, 173, 174, 175, 176, 177, 178, 178, 179, 180, 181, 182, 183, 183, 184, 185, 186, 187, 188, 188, 189, 190, 191, 192, 193, 193, 194, 195, 196, 197, 197, 198, 199, 200, 201, 201, 202, 203, 204, 205, 206, 206, 207, 208, 209, 210, 210, 211, 212, 213, 213, 214, 215, 216, 217, 217, 218, 219, 220, 221, 221, 222, 223, 224, 224, 225, 226, 227, 228, 228, 229, 230, 231, 231, 232, 233, 234, 235, 235, 236, 237, 238, 238, 239, 240, 241, 241, 242, 243, 244, 244, 245, 246, 247, 247, 248, 249, 250, 251, 251, 252, 253, 254, 254, 255 }, { 8, 12, 16, 19, 22, 24, 27, 29, 31, 34, 36, 38, 40, 41, 43, 45, 47, 49, 50, 52, 53, 55, 57, 58, 60, 61, 63, 64, 65, 67, 68, 70, 71, 72, 74, 75, 76, 77, 79, 80, 81, 82, 84, 85, 86, 87, 88, 90, 91, 92, 93, 94, 95, 96, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 135, 136, 137, 138, 139, 140, 141, 142, 143, 143, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 160, 160, 161, 162, 163, 164, 165, 165, 166, 167, 168, 169, 169, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, 185, 186, 186, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, 195, 195, 196, 197, 197, 198, 199, 200, 200, 201, 202, 202, 203, 204, 205, 205, 206, 207, 207, 208, 209, 210, 210, 211, 212, 212, 213, 214, 214, 215, 216, 216, 217, 218, 219, 219, 220, 221, 221, 222, 223, 223, 224, 225, 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235, 235, 236, 237, 237, 238, 238, 239, 240, 240, 241, 242, 242, 243, 244, 244, 245, 246, 246, 247, 247, 248, 249, 249, 250, 251, 251, 252, 253, 253, 254, 254, 255 }, { 16, 23, 28, 32, 36, 39, 42, 45, 48, 50, 53, 55, 57, 60, 62, 64, 66, 68, 69, 71, 73, 75, 76, 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 93, 94, 96, 97, 98, 100, 101, 102, 103, 105, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 128, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 143, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 159, 160, 161, 162, 163, 163, 164, 165, 166, 166, 167, 168, 169, 169, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 177, 178, 179, 180, 180, 181, 182, 182, 183, 184, 184, 185, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 193, 194, 195, 195, 196, 196, 197, 198, 198, 199, 200, 200, 201, 202, 202, 203, 203, 204, 205, 205, 206, 207, 207, 208, 208, 209, 210, 210, 211, 211, 212, 213, 213, 214, 214, 215, 216, 216, 217, 217, 218, 219, 219, 220, 220, 221, 221, 222, 223, 223, 224, 224, 225, 225, 226, 227, 227, 228, 228, 229, 229, 230, 230, 231, 232, 232, 233, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 239, 239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 254, 254, 255, 255 } }; //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/im_color.h000066400000000000000000000122241464327712600203050ustar00rootroot00000000000000//------------------------------------------------------------------------ // COLORS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_IM_COLOR_H__ #define __EUREKA_IM_COLOR_H__ #include "sys_macro.h" #include "sys_type.h" #include "WindowsSanitization.h" // needed for Windows #include class Lump_c; class SString; struct WadData; typedef uint32_t rgb_color_t; #define RGB_RED(col) ((col >> 24) & 255) #define RGB_GREEN(col) ((col >> 16) & 255) #define RGB_BLUE(col) ((col >> 8) & 255) // // Constexpr maker // static constexpr rgb_color_t rgbMake(int r, int g, int b) { return static_cast(r << 24 | g << 16 | b << 8); } // this is a version of rgb_color_t with an alpha channel // [ currently only used by the TGA loading code ] typedef uint32_t rgba_color_t; #define RGBA_ALPHA(col) ((col) & 255) #define RGBA_MAKE(r, g, b, a) (((r) << 24) | ((g) << 16) | ((b) << 8) | (a)) namespace config { extern int usegamma; } extern const int gammatable[5][256]; // make the color darker rgb_color_t DarkerColor(rgb_color_t col); rgb_color_t ParseColor(const SString &str); rgb_color_t SectorLightColor(int light); int HashedPalColor(const SString &name, const int *cols); inline int R_DoomLightingEquation(int L, float dist) { /* L in the range 0 to 256 */ L >>= 2; int min_L = clamp(0, 36 - L, 31); int index = (59 - L) - int(1280 / std::max(1.0f, dist)); /* result is colormap index (0 bright .. 31 dark) */ return clamp(min_L, index, 31); } // this is a 16-bit value: // - when high bit is clear, it is a palette index 0-255 // (value 255 is used to represent fully transparent). // - when high bit is set, the remainder is 5:5:5 RGB typedef unsigned short img_pixel_t; // // Wad palette info // class Palette { public: bool updateGamma(int usegamma, int panel_gamma); void decodePixel(img_pixel_t p, byte &r, byte &g, byte &b) const; void decodePixelMedium(img_pixel_t p, byte &r, byte &g, byte &b) const noexcept; void createBrightMap(); rgb_color_t getPaletteColor(int index) const { return palette[index]; } bool loadPalette(const Lump_c &lump, int usegamma, int panel_gamma); void loadColormap(const Lump_c *lump); byte findPaletteColor(int r, int g, int b) const; rgb_color_t pixelToRGB(img_pixel_t p) const; byte getColormapIndex(int cmap, int pos) const { return raw_colormap[cmap][pos]; } int getTransReplace() const { return trans_replace; } private: // this palette has the gamma setting applied rgb_color_t palette[256] = {}; rgb_color_t palette_medium[256] = {}; byte rgb555_gamma[32]; byte rgb555_medium[32]; byte bright_map[256] = {}; byte raw_palette[256][3] = {}; byte raw_colormap[32][256] = {}; // the palette color closest to what TRANS_PIXEL really is int trans_replace = 0; }; //------------------------------------------------------------// #define BLACK FL_BLACK #define BLUE FL_BLUE #define GREEN FL_GREEN #define CYAN FL_CYAN #define RED FL_RED #define MAGENTA FL_MAGENTA #define BROWN FL_DARK_RED #define YELLOW fl_rgb_color(255,255,0) #define WHITE FL_WHITE #define LIGHTGREY fl_rgb_color(144,144,144) #define DARKGREY fl_rgb_color(80,80,80) #define LIGHTBLUE fl_rgb_color(128,128,255) #define LIGHTGREEN fl_rgb_color(128,255,128) #define LIGHTCYAN fl_rgb_color(128,255,255) #define LIGHTRED fl_rgb_color(255,128,128) #define LIGHTMAGENTA fl_rgb_color(255,128,255) #define OBJECT_NUM_COL fl_rgb_color(0x44, 0xdd, 0xff) #define CLR_ERROR fl_rgb_color(0xff, 0, 0) #define SECTOR_TAG fl_rgb_color(0x00, 0xff, 0x00) #define SECTOR_TAGTYPE fl_rgb_color(0x00, 0xe0, 0xe0) #define SECTOR_TYPE fl_rgb_color(0x00, 0x80, 0xff) #define SEL_COL fl_rgb_color(128,192,255) #define SEL3D_COL fl_rgb_color(128,255,128) #define HI_COL fl_rgb_color(255,255,0) #define HI_AND_SEL_COL fl_rgb_color(255,128,0) #define THING_MODE_COL fl_rgb_color(255,64,255) #define LINE_MODE_COL fl_rgb_color(0,160,255) #define SECTOR_MODE_COL fl_rgb_color(255,255,0) #define VERTEX_MODE_COL fl_rgb_color(0,255,128) #endif /* __EUREKA_IM_COLOR_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/im_img.cc000066400000000000000000000673371464327712600201200ustar00rootroot00000000000000//------------------------------------------------------------------------ // IMAGES //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include "im_img.h" #include "m_game.h" #include "tl/optional.hpp" #ifndef NO_OPENGL // need this for GL_UNSIGNED_INT_8_8_8_8_REV #ifdef __APPLE__ #include #else #include "GL/glext.h" #endif #endif #define DIGIT_FONT_COLOR rgbMake(68, 221, 255) rgb_color_t Palette::pixelToRGB(img_pixel_t p) const { if (p & IS_RGB_PIXEL) { byte r = static_cast(IMG_PIXEL_RED(p) << 3); byte g = static_cast(IMG_PIXEL_GREEN(p) << 3); byte b = static_cast(IMG_PIXEL_BLUE(p) << 3); return rgbMake(r, g, b); } else { byte r = raw_palette[p][0]; byte g = raw_palette[p][1]; byte b = raw_palette[p][2]; return rgbMake(r, g, b); } } // // a constructor with dimensions // Img_c::Img_c(int width, int height, bool _dummy) { resize(width, height); setSpriteOffset(width / 2, height); } // // return a const pointer on the buffer. // if the image is null, return a NULL pointer. // const img_pixel_t *Img_c::buf() const noexcept { return pixels.data(); } // // return a writable pointer on the buffer. // if the image is null, return a NULL pointer. // img_pixel_t *Img_c::wbuf() { return pixels.data(); } // // clear the image to fully transparent // void Img_c::clear() { img_pixel_t *dest = pixels.data(); img_pixel_t *dest_end = dest + (w * h); for ( ; dest < dest_end ; dest++) *dest = TRANS_PIXEL; } // // resize the image. if either dimension is zero, // the image becomes a null image. // void Img_c::resize(int new_width, int new_height) { if (new_width == w && new_height == h) return; // unallocate old buffer pixels.clear(); // Is it a null image ? if (new_width == 0 || new_height == 0) { w = h = 0; return; } // Allocate new buffer w = new_width; h = new_height; pixels.resize(w * h + 10); // Some slack clear(); } void Img_c::compose(const Img_c &other, int x, int y) { int W = width(); int H = height(); int OW = other.width(); int OH = other.height(); for (int oy = 0 ; oy < OH ; oy++) { int iy = y + oy; if (iy < 0 || iy >= H) continue; const img_pixel_t *src = other.buf() + oy * OW; img_pixel_t *dest = wbuf() + iy * W; for (int ox = 0 ; ox < OW ; ox++, src++) { int ix = x + ox; if (ix < 0 || ix >= W) continue; if (*src != TRANS_PIXEL) dest[ix] = *src; } } } void Img_c::flipHorizontally() { assert((int)pixels.size() >= w * h); for(int y = 0; y < h; ++y) for(int x = 0; x < w / 2; ++x) { assert(y * w + x >= 0 && y * w + x < (int)pixels.size()); assert(y * w + w - x - 1 >= 0 && y * w + w - x - 1 < (int)pixels.size()); std::swap(pixels[y * w + x], pixels[y * w + w - x - 1]); } } // // make a game image look vaguely like a spectre // Img_c Img_c::spectrify(const ConfigData &config) const { Img_c omg(width(), height()); omg.spriteOffsetX = spriteOffsetX; omg.spriteOffsetY = spriteOffsetY; int invis_start = config.miscInfo.invis_colors[0]; int invis_len = config.miscInfo.invis_colors[1] - invis_start + 1; if (invis_len < 1) invis_len = 1; int W = width(); int H = height(); const img_pixel_t *src = buf(); img_pixel_t *dest = omg.wbuf(); for (int y = 0 ; y < H ; y++) for (int x = 0 ; x < W ; x++) { assert(y * W + x >= 0 && y * W + x < (int)pixels.size()); img_pixel_t pix = src[y * W + x]; if (pix != TRANS_PIXEL) pix = static_cast(invis_start + (rand() >> 4) % invis_len); assert(y * W + x >= 0 && y * W + x < (int)omg.pixels.size()); dest[y * W + x] = pix; } return omg; } // // copy the image, remapping pixels in the range 'src1..src2' to the // range 'targ1..targ2'. // // TODO : make it work with RGB pixels (find nearest in palette). // Img_c Img_c::color_remap(int src1, int src2, int targ1, int targ2) const { SYS_ASSERT( src1 <= src2); SYS_ASSERT(targ1 <= targ2); Img_c omg(width(), height()); omg.spriteOffsetX = spriteOffsetX; omg.spriteOffsetY = spriteOffsetY; int W = width(); int H = height(); const img_pixel_t *src = buf(); img_pixel_t *dest = omg.wbuf(); for (int y = 0 ; y < H ; y++) for (int x = 0 ; x < W ; x++) { img_pixel_t pix = src[y * W + x]; if (src1 <= pix && pix <= src2) { int diff = pix - src1; pix = static_cast(targ1 + diff * (targ2 - targ1 + 1) / (src2 - src1 + 1)); } dest[y * W + x] = pix; } return omg; } bool Img_c::has_transparent() const { int W = width(); int H = height(); const img_pixel_t *src = buf(); for (int y = 0 ; y < H ; y++) for (int x = 0 ; x < W ; x++) { if (src[y * W + x] == TRANS_PIXEL) return true; } return false; } #ifdef NO_OPENGL void Img_c::load_gl(const WadData &wad) {} void Img_c::unload_gl(bool can_delete) {} void Img_c::bind_gl(const WadData &wad) {} #else void Img_c::load_gl(const WadData &wad) { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glGenTextures(1, &gl_tex); glBindTexture(GL_TEXTURE_2D, gl_tex); // construct a power-of-two sized bottom-up RGBA image int tw, th; if (global::use_npot_textures) { tw = w; th = h; } else { tw = RoundPOW2(w); th = RoundPOW2(h); } byte *rgba = new byte[tw * th * 4]; memset(rgba, 0, (size_t)(tw * th * 4)); bool has_trans = has_transparent(); int ex = has_trans ? w : tw; int ey = has_trans ? h : th; int x, y; for (y = 0 ; y < ey ; y++) { // invert source Y for OpenGL int sy = h - 1 - y; if (sy < 0) sy += h; for (x = 0 ; x < ex ; x++) { int sx = x; if (sx >= w) sx = x - w; // convert pixel to RGBA const img_pixel_t pix = buf()[sy*w + sx]; if (pix != TRANS_PIXEL) { byte r, g, b; wad.palette.decodePixel(pix, r, g, b); byte *dest = rgba + (y*tw + x) * 4; dest[0] = b; dest[1] = g; dest[2] = r; dest[3] = 255; } } } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0 /* mip */, GL_RGBA8, tw, th, 0 /* border */, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, rgba); delete[] rgba; } void Img_c::unload_gl(bool can_delete) { if (can_delete && gl_tex != 0) { glDeleteTextures(1, &gl_tex); } gl_tex = 0; } void Img_c::bind_gl(const WadData &wad) { // create the GL texture if we haven't already if (gl_tex == 0) { // this will do a glBindTexture load_gl(wad); return; } glBindTexture(GL_TEXTURE_2D, gl_tex); } #endif //------------------------------------------------------------------------ void ImageSet::IM_ResetDummyTextures() { missing_tex_color = -1; unknown_tex_color = -1; special_tex_color = -1; unknown_flat_color = -1; unknown_sprite_color = -1; } void ImageSet::IM_UnloadDummyTextures() { bool can_delete = false; if (missing_tex_image) missing_tex_image->unload_gl(can_delete); if (unknown_tex_image) unknown_tex_image->unload_gl(can_delete); if (special_tex_image) special_tex_image->unload_gl(can_delete); if (unknown_flat_image) unknown_flat_image->unload_gl(can_delete); if (unknown_sprite_image) unknown_sprite_image->unload_gl(can_delete); if (digit_font_11x14) digit_font_11x14->unload_gl(can_delete); if (digit_font_14x19) digit_font_14x19->unload_gl(can_delete); } static const byte unknown_graphic[16 * 16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, 0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0, 0,0,1,1,1,1,0,0,0,0,0,1,1,1,0,0, 0,0,0,1,1,0,0,0,0,0,0,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0, 0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0, 0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; static const byte missing_graphic[16 * 16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; static Img_c IM_CreateDummyTex(const byte *data, int bg, int fg) { Img_c omg(64, 64, true); img_pixel_t *obuf = omg.wbuf(); for (int y = 0 ; y < 64 ; y++) for (int x = 0 ; x < 64 ; x++) { obuf[y * 64 + x] = static_cast(data[((y/2) & 15 ) * 16 + ((x/2) & 15)] ? fg : bg); } return omg; } const Img_c &ImageSet::IM_MissingTex(const ConfigData &config) { if (!missing_tex_image || missing_tex_color != config.miscInfo.missing_color) { missing_tex_color = config.miscInfo.missing_color; missing_tex_image = IM_CreateDummyTex(missing_graphic, missing_tex_color, 0); } return missing_tex_image.value(); } const Img_c &ImageSet::IM_UnknownTex(const ConfigData &config) { if (!unknown_tex_image || unknown_tex_color != config.miscInfo.unknown_tex) { unknown_tex_color = config.miscInfo.unknown_tex; unknown_tex_image = IM_CreateDummyTex(unknown_graphic, unknown_tex_color, 0); } return unknown_tex_image.value(); } const Img_c &ImageSet::IM_SpecialTex(const Palette &palette) { if (special_tex_color < 0) { special_tex_color = palette.findPaletteColor(192, 0, 192); special_tex_image.reset(); } if (!special_tex_image) special_tex_image = IM_CreateDummyTex(unknown_graphic, special_tex_color, palette.findPaletteColor(255, 255, 255)); return special_tex_image.value(); } const Img_c &ImageSet::IM_UnknownFlat(const ConfigData &config) { if (!unknown_flat_image || unknown_flat_color != config.miscInfo.unknown_flat) { unknown_flat_color = config.miscInfo.unknown_flat; unknown_flat_image = IM_CreateDummyTex(unknown_graphic, unknown_flat_color, 0); } return unknown_flat_image.value(); } Img_c &ImageSet::IM_UnknownSprite(const ConfigData &config) { int unk_col = config.miscInfo.unknown_thing; if (unk_col == 0) unk_col = config.miscInfo.unknown_tex; if (!unknown_sprite_image || unknown_sprite_color != unk_col) { unknown_sprite_color = unk_col; unknown_sprite_image = Img_c(64, 64, true); img_pixel_t *obuf = unknown_sprite_image->wbuf(); for (int y = 0 ; y < 64 ; y++) for (int x = 0 ; x < 64 ; x++) { obuf[y * 64 + x] = static_cast(unknown_graphic[(y/4) * 16 + (x/4)] ? unknown_sprite_color : TRANS_PIXEL); } } return unknown_sprite_image.value(); } Img_c Img_c::createFromText(const Palette &pal, int W, int H, const char * const*text, const rgb_color_t *palette, int pal_size) { Img_c result(W, H); result.clear(); // translate colors to current palette std::vector conv_palette; conv_palette.reserve(pal_size); for (int c = 0 ; c < pal_size ; c++) { conv_palette.push_back(pal.findPaletteColor(RGB_RED(palette[c]), RGB_GREEN(palette[c]), RGB_BLUE(palette[c]))); } for (int y = 0 ; y < H ; y++) for (int x = 0 ; x < W ; x++) { int ch = text[y][x] & 0x7f; if (ch == ' ') continue; // leave transparent if (ch < 'a' || ch >= 'a' + pal_size) BugError("Bad character (dec #%d) in built-in image.\n", ch); result.wbuf() [y * W + x] = conv_palette[ch - 'a']; } return result; } static Img_c IM_CreateFont(int W, int H, const char *const *text, const int *intensities, int ity_size, rgb_color_t color) { Img_c result(W, H); result.clear(); for (int y = 0 ; y < H ; y++) for (int x = 0 ; x < W ; x++) { int ch = text[y][x] & 0x7f; if (ch == ' ') continue; // leave transparent if (ch < 'a' || ch >= 'a' + ity_size) BugError("Bad character (dec #%d) in built-in font.\n", ch); int ity = intensities[ch - 'a']; int r = (RGB_RED(color) * ity) >> 11; int g = (RGB_GREEN(color) * ity) >> 11; int b = (RGB_BLUE(color) * ity) >> 11; result.wbuf() [y * W + x] = pixelMakeRGB(r, g, b); } return result; } tl::optional IM_ConvertRGBImage(const Fl_RGB_Image &src) { int W = src.w(); int H = src.h(); int D = src.d(); int LD = src.ld(); LD += W; auto data = static_cast(src.array); if (! data) return {}; if (! (D == 3 || D == 4)) return {}; Img_c img(W, H); for (int y = 0 ; y < H ; y++) for (int x = 0 ; x < W ; x++) { const byte *src_pix = data + (y * LD + x) * D; int r = src_pix[0]; int g = src_pix[1]; int b = src_pix[2]; int a = (D == 3) ? 255 : src_pix[3]; img_pixel_t dest_pix = TRANS_PIXEL; if (a & 128) { // TODO : a preference to palettize it // dest_pix = W_FindPaletteColor(r, g, b); dest_pix = pixelMakeRGB(r >> 3, g >> 3, b >> 3); } img.wbuf() [ y * W + x ] = dest_pix; } return img; } Img_c IM_ConvertTGAImage(const rgba_color_t * data, int W, int H) { Img_c img(W, H); img_pixel_t *dest = img.wbuf(); for (int i = W * H ; i > 0 ; i--, data++, dest++) { if (RGBA_ALPHA(*data) & 128) { byte r = RGB_RED( *data) >> 3; byte g = RGB_GREEN(*data) >> 3; byte b = RGB_BLUE( *data) >> 3; *dest = pixelMakeRGB(r, g, b); } else { *dest = TRANS_PIXEL; } } return img; } //------------------------------------------------------------------------ // // eight basic arrow sprites, made by Andrew Apted, public domain. // /* XPM */ extern const char *const arrow_0_xpm[] = { "12 12 2 1", " c None", "1 c #000000", " 1 ", " 11 ", " 111 ", " 1111 ", " 11111 ", "111111111111", "111111111111", " 11111 ", " 1111 ", " 111 ", " 11 ", " 1 " }; /* XPM */ extern const char *const arrow_45_xpm[] = { "12 12 2 1", " c None", "1 c #000000", " ", " 11111111 ", " 1111111 ", " 111111 ", " 11111 ", " 111111 ", " 111 111 ", " 111 11 ", " 111 1 ", " 111 ", " 11 ", " " }; /* XPM */ extern const char *const arrow_90_xpm[] = { "12 12 2 1", " c None", "1 c #000000", " 11 ", " 1111 ", " 111111 ", " 11111111 ", " 1111111111 ", "111111111111", " 11 ", " 11 ", " 11 ", " 11 ", " 11 ", " 11 " }; /* XPM */ extern const char *const arrow_135_xpm[] = { "12 12 2 1", " c None", "1 c #000000", " ", " 11111111 ", " 1111111 ", " 111111 ", " 11111 ", " 111111 ", " 111 111 ", " 11 111 ", " 1 111 ", " 111 ", " 11 ", " " }; /* XPM */ extern const char *const arrow_180_xpm[] = { "12 12 2 1", " c None", "1 c #000000", " 1 ", " 11 ", " 111 ", " 1111 ", " 11111 ", "111111111111", "111111111111", " 11111 ", " 1111 ", " 111 ", " 11 ", " 1 " }; /* XPM */ extern const char *const arrow_225_xpm[] = { "12 12 2 1", " c None", "1 c #000000", " ", " 11 ", " 111 ", " 1 111 ", " 11 111 ", " 111 111 ", " 111111 ", " 11111 ", " 111111 ", " 1111111 ", " 11111111 ", " " }; /* XPM */ extern const char *const arrow_270_xpm[] = { "12 12 2 1", " c None", "1 c #000000", " 11 ", " 11 ", " 11 ", " 11 ", " 11 ", " 11 ", "111111111111", " 1111111111 ", " 11111111 ", " 111111 ", " 1111 ", " 11 " }; /* XPM */ extern const char *const arrow_315_xpm[] = { "12 12 2 1", " c None", "1 c #000000", " ", " 11 ", " 111 ", " 111 1 ", " 111 11 ", " 111 111 ", " 111111 ", " 11111 ", " 111111 ", " 1111111 ", " 11111111 ", " " }; //------------------------------------------------------------------------ // // This dog sprite was sourced from OpenGameArt.org // Authors are 'Benalene' and 'qudobup' (users on the OGA site). // License is CC-BY 3.0 (Creative Commons Attribution license). // static const rgb_color_t dog_palette[] = { 0x302020ff, 0x944921ff, 0x000000ff, 0x844119ff, 0x311800ff, 0x4A2400ff, 0x633119ff, }; static const char *const dog_image_text[] = { " aaaa ", " abbbba ", " abbbbbba ", " aaaabcbbbbbda ", "aeedbbbfbbbbda ", "aegdddbbdbbdbbaaaaaaaaaaaaaaaaa a ", "affggddbgddgbccceeeeeeeeeeeeeeeaa aba", " affgggdfggfccceeeeeeeeeeeeeefffgaaa aaba ", " afffaafgecccefffffffffffffffggggddaaabbba ", " aaa aeeccggggffffffffffffggddddbbbbbaa ", " accbdddggfffffffffffggdbbbbbbba ", " aabbdbddgfffffffffggddbaaaaaa ", " abbbbdddfffffffggdbbba ", " abbbbbbdddddddddddbbba ", " aeebbbbbbbbaaaabbbbbbbba ", " aeebbbbbaaa aeebbbbbba ", " afebbbbaa affeebbbba ", " agfbbbaa aggffabbbba ", " agfebba aggggaabbba ", " aadgfabba addda abba ", " abbddaabbbaa adddaabba ", " abbbba abbbba adbbaabba ", " aaaa abbba abbba abba ", " aaa abbba abba ", " abbba abbba ", " aaa aaa " }; Img_c Img_c::createDogSprite(const Palette &pal) { return createFromText(pal, 44, 26, dog_image_text, dog_palette, 7); } //------------------------------------------------------------------------ Img_c Img_c::createLightSprite(const Palette &palette) { static const int W = 11; static const int H = 11; Img_c result(W, H); result.clear(); for (int y = 0 ; y < H ; y++) for (int x = 0 ; x < W ; x++) { byte pix = TRANS_PIXEL; float dx = (W - 2*x) / (float)W; float dy = (H - 2*y) / (float)H; float dist = sqrt((dx) * (dx) + (dy) * (dy)); float ity = 1.0f / (dist + 0.5f) / (dist + 0.5f); if (ity < 0.5) continue; ity = (ity - 0.4f) / (1.0f - 0.4f); int r = static_cast(255 * ity); int g = static_cast(235 * ity); int b = static_cast(90 * ity); pix = palette.findPaletteColor(r, g, b); result.wbuf() [ y * W + x ] = pix; } return result; } Img_c Img_c::createMapSpotSprite(const Palette &pal, int base_r, int base_g, int base_b) { int W = 32; int H = 32; Img_c result(W, H); result.clear(); for (int y = 4 ; y < H ; y++) for (int x = 0 ; x < W ; x++) { byte pix = TRANS_PIXEL; int cx1 = y/2; int cx2 = W - y/2; if (cx1 <= x && x <= cx2) { float dx = static_cast(std::min(x - cx1, cx2 - x)); //float dy = MIN(abs(y - 4), abs(y - W)); float ity = 0.3f + dx / 14.0f; if (ity > 1.0) ity = 1.0; int r = static_cast(base_r * ity); int g = static_cast(base_g * ity); int b = static_cast(base_b * ity); pix = pal.findPaletteColor(r, g, b); } result.wbuf() [ y * W + x ] = pix; } return result; } //------------------------------------------------------------------------ /* a digit-only font, in two sizes */ static const int digit_font_intensities[] = { 0x00, 0x16, 0x24, 0x32, 0x3f, 0x4c, 0x58, 0x65, 0x72, 0x7e, 0x8b, 0x98, 0xa4, 0xb0, 0xbc, 0xc9, 0xd6, 0xe2, 0xef, 0xfc, }; static const char *const digit_11x14_text[] = { " aaaaaaa ", " aaaaaaa aaaaaa aaaaaaaa aaaaaaa aaaaa aaaaaaa aaaaaa aaaaaaaa aaaaaaa aaaaaaa agqspda ", " agqspda alprga aeorsoca apsspfa aalrga aprrrka aanssna afrrrrqa ajrsqha aajrspca aaqogqoa ", " aaqogqoa aontha ahojirna amiiqpa aertha asmkkga aanrjika adkkkpqa aasnfora adsmgqoa aaaa afteaitaa ", " afteaitaa aaatha aaaaamqa aaaakra aaomtha ashaaaa absiaaaa aaaaarma adtcahta aksaajsaa ahfa agtcagtba ", " ajsaaatga atha aaooa ahjqna ahratha asrqmaa agtmrpfa agtea aarnhopa akraajtda arma aarlanqaa ", " akraaatha atha aajtha aqssha aaqjathaa ankmsna ajtqjpraa anqaa aaktssiaa aftjaptga ajga aaaaaa ajtssha ", " aksaaatga atha aagskaa aaanra akqeetiba aaaalsa ajthactga aarla aftialsba aalstotca aaaa amrrla aadhcaa ", " agtcagtba atha aaermaa aaaaagta antttttka aaaaajsa afteaatha ahtca aksaaatga aaaajsaa aaaa aaaa agjjfa aaaaa ", " aarlanqaa aaathaa acroaaaa afhaanra aaaaathaa aegacpqa aarmaksba aopaa agthaktba agadrna amia anha aaaaaa ", " ajtssha aqtttsa ajttttra ahtstsia atha ahtstrga aisrtlaa aska aantrtmaa arstpba arma aska ", " aadhcaa aaaaaaa aaaaaaaa aabhgaaa aaaa aachfaaa aachcaa aaaa aadhdaa abhfaaa aaaa aaaa ", " aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa ", " " }; static const char *const digit_14x19_text[] = { " aaaaaa ", " aaaaaa aaaaa aaaaaaa aaaaaaa aaaaa aaaaaaaaa aaaaaa aaaaaaaaaa aaaaaa aaaaaa aadklgaa ", " aadklgaa aaaafhca aacjlkeaa aadjlkfaa adhga adhhhhhhaa aagllhaa afhhhhhhga aafklhaaa aaglleaa aajstttnaa ", " aajstttnaa agqsttja ansttttlaa altttttoaa aaqtra akttttttda aaottttna aqttttttsa aanttttqda aaottttlaa adssjgqtja ", " adssjgqtja ajtrrtja arqlilstia alokikrtma aakttra aktommmmba aaotpjjnma akmmmmntpa aktrigotoa altqhirtha amtkaaetqa ", " amtkaaetqa acbamtja afaaaajtoa aaaaaaetqa acsosra aktjaaaaaa ahtpaaaaaa aaaaaamtka aotgaaarsa arsdaaftpa aaaaa aptcaaaqsa ", " aqtbaaaqtaa aaaamtja aaa actpa aasqa aansdsra aktjaaaa anthaaaaa aarsba aptcaaarsa atqaaaarsaa adlia altlaaftqa ", " arraaaaotga amtja aitna aaaamtma aftmasra aktpqpkaa aqsfoqohaa agtpaa aktmaahtpa atqaaaartea agtpa abssljrtia ", " asqa antia amtja aaqtga aorstnaa aapraasra aktssttqaa arsssrttja antja aantrqsqda assaaadstha afsoa aahstttlaa ", " asqa amtja amtja aantnaa aorstqda ajtjaasra agiaafqtma astrdaissaa aarsaa aanssstqea aotoabpttia aaaaa aaaaaaaa aaaijdaa ", " asqa antia amtja aaltpaa aaaaltpa aarpaaasraaa aaaaaaetra astjaaaotia ahtoa antnaaisqaa adrttttqtga ahqqqqda aaaaa ", " arraaaaotga amtja aajtrca aaqsa aitqppptspja aarsa artea amtka aotia arsaaaaotfa aablongptba airrrrda ", " aptcaaaqsaa amtja aahsreaa aaa aaqta aisssssttsma aaa aassa aotga antka aassaa asraaaantia aaaaaasraa aaaaa aaaaa aaaaaaaa ", " altlaaftqa aaamtjaaa afssgaaaaa abaaaaessa aaaaaaasraaa abaaaajtpa aktmaaaqtea aitoa arseaaaqtfa aaaaaamtma ackha aekga ", " abssljrtia aooqtpona aqtqooooma aqpmknstma asra aqplknttia aartmjotpaa aotha amtrkjotqaa aiplkotraa agtpa aktna ", " aahstttlaa attttttra arttttttqa apttttsmaa asra apttttskaa agrtttpda asraa aaottttqfa aittttpea agtpa aktna ", " aaaijdaa aaaaaaaaa aaaaaaaaaa aadijibaa aaaa aadijhaaa aaahjfaaa aaaa aadjjfaaa aacijfaaa aaaaa aaaaa ", " aaaaa aaaaaaa aaaaaa aaaaa aaaaaa aaaaaa ", " ", }; Img_c &ImageSet::IM_DigitFont_11x14() { if (!digit_font_11x14) { digit_font_11x14 = IM_CreateFont(11*14, 14, digit_11x14_text, digit_font_intensities, 20, DIGIT_FONT_COLOR); } return digit_font_11x14.value(); } Img_c &ImageSet::IM_DigitFont_14x19() { if (!digit_font_14x19) { digit_font_14x19 = IM_CreateFont(14*14, 19, digit_14x19_text, digit_font_intensities, 20, DIGIT_FONT_COLOR); } return digit_font_14x19.value(); } // this one applies the current gamma. // for rendering the 3D view or the 2D sectors and sprites. void Palette::decodePixel(img_pixel_t p, byte &r, byte &g, byte &b) const { if(p & IS_RGB_PIXEL) { r = rgb555_gamma[IMG_PIXEL_RED(p)]; g = rgb555_gamma[IMG_PIXEL_GREEN(p)]; b = rgb555_gamma[IMG_PIXEL_BLUE(p)]; } else { const rgb_color_t col = palette[p]; r = RGB_RED(col); g = RGB_GREEN(col); b = RGB_BLUE(col); } } // this applies a constant gamma. // for textures/flats/things in the browser and panels. void Palette::decodePixelMedium(img_pixel_t p, byte &r, byte &g, byte &b) const noexcept { if(p & IS_RGB_PIXEL) { r = rgb555_medium[IMG_PIXEL_RED(p)]; g = rgb555_medium[IMG_PIXEL_GREEN(p)]; b = rgb555_medium[IMG_PIXEL_BLUE(p)]; } else { const rgb_color_t col = palette_medium[p]; r = RGB_RED(col); g = RGB_GREEN(col); b = RGB_BLUE(col); } } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/im_img.h000066400000000000000000000075171464327712600177540ustar00rootroot00000000000000//------------------------------------------------------------------------ // IMAGES //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_IM_IMG_H__ #define __EUREKA_IM_IMG_H__ #include "im_color.h" #ifdef NO_OPENGL typedef unsigned int GLuint; #else #include "FL/gl.h" #endif #include "tl/optional.hpp" #include #include static constexpr img_pixel_t IS_RGB_PIXEL = 0x8000; #define IMG_PIXEL_RED(col) (((col) >> 10) & 31) #define IMG_PIXEL_GREEN(col) (((col) >> 5) & 31) #define IMG_PIXEL_BLUE(col) (((col) ) & 31) static constexpr img_pixel_t pixelMakeRGB(int r, int g, int b) { return static_cast(IS_RGB_PIXEL | r << 10 | g << 5 | b); } // the color number used to represent transparent pixels in an Img_c. const img_pixel_t TRANS_PIXEL = 255; class Fl_RGB_Image; class Instance; class Palette; struct ConfigData; struct WadData; class Img_c { private: std::vector pixels; int w = 0; // Width int h = 0; // Height int spriteOffsetX = 0; int spriteOffsetY = 0; // texture identifier for OpenGL, 0 if not uploaded yet GLuint gl_tex = 0; public: Img_c() = default; Img_c(int width, int height, bool _dummy = false); static Img_c createLightSprite(const Palette &palette); static Img_c createMapSpotSprite(const Palette &pal, int base_r, int base_g, int base_b); static Img_c createDogSprite(const Palette &pal); inline bool is_null() const { return pixels.empty(); } inline int width() const noexcept { return w; } inline int height() const noexcept { return h; } GLuint gl_texture() const { return gl_tex; } // read access const img_pixel_t *buf() const noexcept; // read/write access img_pixel_t *wbuf(); // set all pixels to TRANS_PIXEL void clear(); void resize(int new_width, int new_height); // paste a copy of another image into this one, but skip any // transparent pixels. void compose(const Img_c &other, int x, int y); void flipHorizontally(); Img_c spectrify(const ConfigData &config) const; Img_c color_remap(int src1, int src2, int targ1, int targ2) const; bool has_transparent() const; // upload to OpenGL, overwriting 'gl_tex' field. void load_gl(const WadData &wad); // invalidate the 'gl_tex' field, deleting old texture if possible. void unload_gl(bool can_delete); void bind_gl(const WadData &wad); void setSpriteOffset(int x, int y) { spriteOffsetX = x; spriteOffsetY = y; } void getSpriteOffset(int& x, int& y) const { x = spriteOffsetX; y = spriteOffsetY; } private: static Img_c createFromText(const Palette &pal, int W, int H, const char * const*text, const rgb_color_t *palette, int pal_size); }; tl::optional IM_ConvertRGBImage(const Fl_RGB_Image &src); Img_c IM_ConvertTGAImage(const rgba_color_t *data, int W, int H); #endif /* __EUREKA_IM_IMG_H__*/ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/lib_adler.cc000066400000000000000000000052041464327712600205550ustar00rootroot00000000000000//------------------------------------------------------------------------ // ADLER-32 CHECKSUM //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2012 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // This is the Adler-32 algorithm as described in RFC-1950. // // The 'extra' field is my own adaptation to provide an extra 32 bits // of checksum. This should make collisions a lot less likely (though // how much remains to be seen -- definitely not the full 32 bits!). // //------------------------------------------------------------------------ #include "lib_adler.h" #include // ---- Primitive routines ---- crc32_c& crc32_c::operator+= (uint8_t data) { uint32_t s1 = raw & 0xFFFF; uint32_t s2 = (raw >> 16) & 0xFFFF; s1 = (s1 + data) % 65521; s2 = (s2 + s1) % 65521; raw = (s2 << 16) | s1; extra += s2; // modulo the extra value by a large prime number if (extra >= 0xFFFEFFF9) extra -= 0xFFFEFFF9; return *this; } crc32_c& crc32_c::AddBlock(const uint8_t *data, int len) { uint32_t s1 = raw & 0xFFFF; uint32_t s2 = (raw >> 16) & 0xFFFF; for (; len > 0; data++, len--) { s1 = (s1 + *data) % 65521; s2 = (s2 + s1) % 65521; extra += s2; if (extra >= 0xFFFEFFF9) extra -= 0xFFFEFFF9; } raw = (s2 << 16) | s1; return *this; } // ---- Non-primitive routines ---- crc32_c& crc32_c::operator+= (uint16_t value) { *this += (uint8_t) (value >> 8); *this += (uint8_t) (value); return *this; } crc32_c& crc32_c::operator+= (uint32_t value) { *this += (uint8_t) (value >> 24); *this += (uint8_t) (value >> 16); *this += (uint8_t) (value >> 8); *this += (uint8_t) (value); return *this; } crc32_c& crc32_c::operator+= (float value) { bool neg = (value < 0.0f); value = (float)fabs(value); int exp; uint32_t mant = (uint32_t) (ldexp(frexp(value, &exp), 30)); *this += (uint8_t) (neg ? '-' : '+'); *this += (uint32_t) exp; *this += mant; return *this; } crc32_c& crc32_c::AddCStr(const char *str) { return AddBlock((const uint8_t *) str, (int)strlen(str)); } eureka-editor-eureka-2.0.2/src/lib_adler.h000066400000000000000000000055321464327712600204230ustar00rootroot00000000000000//------------------------------------------------------------------------ // ADLER-32 CHECKSUM //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2012 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // This is the Adler-32 algorithm as described in RFC-1950. // // The 'extra' field is my own adaptation to provide an extra 32 bits // of checksum. This should make collisions a lot less likely (though // how much remains to be seen -- definitely not the full 32 bits!). // //------------------------------------------------------------------------ #ifndef __LIB_CRC_H__ #define __LIB_CRC_H__ #include "m_strings.h" #include #include "filesystem.hpp" namespace fs = ghc::filesystem; class crc32_c { private: uint32_t raw; uint32_t extra; static const uint32_t INIT_VALUE = 1; public: crc32_c() : raw(INIT_VALUE), extra(0) { } crc32_c(const crc32_c &rhs) { raw = rhs.raw; extra = rhs.extra; } ~crc32_c() { } void Reset(void) { raw = INIT_VALUE; extra = 0; } crc32_c& operator+= (uint8_t value); crc32_c& operator+= (int8_t value); crc32_c& operator+= (uint16_t value); crc32_c& operator+= (int16_t value); crc32_c& operator+= (uint32_t value); crc32_c& operator+= (int32_t value); crc32_c& operator+= (float value); crc32_c& operator+= (bool value); crc32_c &operator+= (const char *value) { return AddCStr(value); } crc32_c &operator+= (const SString &value) { return AddCStr(value.c_str()); } crc32_c& AddBlock(const uint8_t *data, int len); crc32_c& AddCStr(const char *str); fs::path getPath() const { return SString::printf("%08X%08X.dat", extra, raw).get(); } // TODO: operator== and operator!= }; //------------------------------------------------------------------------ // IMPLEMENTATION //------------------------------------------------------------------------ inline crc32_c& crc32_c::operator+= (int8_t value) { *this += (uint8_t) value; return *this; } inline crc32_c& crc32_c::operator+= (int16_t value) { *this += (uint16_t) value; return *this; } inline crc32_c& crc32_c::operator+= (int32_t value) { *this += (uint32_t) value; return *this; } inline crc32_c& crc32_c::operator+= (bool value) { *this += (value ? (uint8_t)1 : (uint8_t)0); return *this; } #endif // __LIB_CRC_H__ eureka-editor-eureka-2.0.2/src/lib_file.cc000066400000000000000000000212731464327712600204110ustar00rootroot00000000000000//------------------------------------------------------------------------ // File Utilities //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include "lib_file.h" #include "sys_debug.h" #ifdef WIN32 #include #include "m_strings.h" #else // UNIX or MACOSX #include #include #include #include #endif #ifdef __APPLE__ #include #include // _NSGetExecutablePath #endif #ifndef PATH_MAX #define PATH_MAX 2048 #endif bool FileExists(const fs::path &filename) { try { return fs::is_regular_file(filename); } catch(const fs::filesystem_error &e) { // Let's print any errors before we throw anything gLog.printf("File check error: %s\n", e.what()); return false; } } bool HasExtension(const fs::path &filename) { fs::path extension = filename.extension(); return extension != "." && !extension.empty(); } // // MatchExtension // // When ext is NULL, checks if the file has no extension. // bool MatchExtensionNoCase(const fs::path &filename, const char *extension) { if (!extension || !*extension) return ! HasExtension(filename); if(!HasExtension(filename)) return false; return SString(filename.extension().u8string()).noCaseEqual(extension); } // // ReplaceExtension // // When ext is NULL, any existing extension is removed. // // Returned string is a COPY. // fs::path ReplaceExtension(const fs::path &filename, const char *extension) { if(filename.filename() == ".." && (!extension || !*extension)) return filename; fs::path result(filename); result.replace_extension(extension ? extension : ""); return result; } // // Get the basename of a path // fs::path GetBaseName(const fs::path &path) { // Find the base name of the file (i.e. without any path). // The result always points within the given string. // // Example: "C:\Foo\Bar.wad" -> "Bar.wad" return path.filename(); } bool FilenameIsBare(const fs::path &filename) { return !filename.has_extension() && filename == filename.filename(); } static void FilenameStripBase(char *buffer) { if(!*buffer) { return; // empty buffer, can't do much } char *pos = buffer + strlen(buffer) - 1; for (; pos > buffer ; pos--) { if (*pos == '/') break; #ifdef WIN32 if (*pos == '\\') break; if (*pos == ':') { pos[1] = 0; return; } #endif } if (pos > buffer) *pos = 0; else { // At this point it's guaranteed not to be empty buffer[0] = '.'; buffer[1] = 0; } } // // Clears the basename // static void FilenameStripBase(SString &path) { if(path.empty()) { path = "."; return; } #ifdef _WIN32 size_t seppos = path.find_last_of("\\/"); size_t colonpos = path.rfind(':'); if(seppos != SString::npos) { if(colonpos != SString::npos && colonpos > seppos) { if(colonpos < path.size() - 1) path.erase(colonpos + 1, SString::npos); return; } if(seppos == 0) { path = "\\"; return; } path.erase(seppos, SString::npos); return; } path = "."; return; #else size_t seppos = path.find_last_of("/"); if(seppos != SString::npos) { if(seppos == 0) { path = "/"; return; } path.erase(seppos, SString::npos); return; } path = "."; return; #endif } // // Get path // fs::path FilenameGetPath(const fs::path &filename) { fs::path parent(filename.parent_path()); return parent.empty() ? "." : parent; } // // Safe wrapper around fl_filename_absolute // fs::path GetAbsolutePath(const fs::path &path) { return fs::absolute(path); } bool FileDelete(const fs::path &filename) { #ifdef WIN32 // TODO: set wide character here return (::DeleteFileW(filename.c_str()) != 0); #else // UNIX or MACOSX return (remove(filename.c_str()) == 0); #endif } bool FileChangeDir(const fs::path &dir_name) { try { fs::current_path(dir_name); } catch(const fs::filesystem_error &e) { gLog.printf("Error changing directory to %s: %s\n", dir_name.u8string().c_str(), e.what()); return false; } return true; } bool FileMakeDir(const fs::path &dir_name) { try { return fs::create_directory(dir_name); } catch(const fs::filesystem_error &e) { gLog.printf("Error creating directory %s: %s\n", dir_name.u8string().c_str(), e.what()); return false; } } bool FileLoad(const fs::path &filename, std::vector &data) { try { // Don't try to read unusual files if(!fs::is_regular_file(filename)) return false; uintmax_t size = fs::file_size(filename); std::ifstream stream(filename, std::ios::binary); if(!stream.is_open()) return false; std::vector trydata; trydata.resize(size); size_t pos = 0; while(!stream.eof() && pos < size) { if(!stream.read(reinterpret_cast(trydata.data() + pos), size - pos)) return false; pos += stream.gcount(); } data = std::move(trydata); } catch(const fs::filesystem_error &e) { gLog.printf("Error loading file %s: %s\n", filename.u8string().c_str(), e.what()); return false; } return true; } //------------------------------------------------------------------------ // // Scan a directory // int ScanDirectory(const fs::path &path, const std::function &func) { try { int count = 0; for(const auto &dir_entry : fs::directory_iterator(path)) { int flags = 0; if(fs::is_directory(dir_entry)) flags |= SCAN_F_IsDir; if((fs::status(dir_entry).permissions() & (fs::perms::owner_write | fs::perms::group_write | fs::perms::others_write)) == fs::perms::none) { flags |= SCAN_F_ReadOnly; } fs::path entry_name = dir_entry.path().filename(); SString entry_string = entry_name.u8string(); if(entry_string.length() >= 2 && entry_string[0] == '.' && isalnum(entry_string[1])) { flags |= SCAN_F_Hidden; } func(entry_name, flags); ++count; } return count; } catch(const fs::filesystem_error &e) { gLog.printf("%s (%d)\n", e.what(), e.code().value()); if(!fs::exists(path)) return SCAN_ERR_NoExist; if(!fs::is_directory(path)) return SCAN_ERR_NotDir; return SCAN_ERROR; } } int ScanDirectory(const fs::path &path, directory_iter_f func, void *priv_dat) { return ScanDirectory(path, [func, priv_dat](const fs::path &name, int flags) { func(name, flags, priv_dat); }); } //------------------------------------------------------------------------ fs::path GetExecutablePath(const char *argv0) { SString path; #ifdef WIN32 wchar_t wpath[PATH_MAX / 2 + 1]; DWORD length = GetModuleFileNameW(GetModuleHandleW(nullptr), wpath, _countof(wpath)); if(length > 0 && length < PATH_MAX / 2) { if(_waccess(wpath, 0) == 0) { SString retpath = WideToUTF8(wpath); FilenameStripBase(retpath); return fs::u8path(retpath.get()); } } #elif !defined(__APPLE__) // UNIX char rawpath[PATH_MAX+2]; int length = readlink("/proc/self/exe", rawpath, PATH_MAX); if (length > 0) { rawpath[length] = 0; // add the missing NUL if (access(rawpath, 0) == 0) // sanity check { FilenameStripBase(rawpath); return fs::u8path(rawpath); } } #else /* from http://www.hmug.org/man/3/NSModule.html extern int _NSGetExecutablePath(char *buf, uint32_t *bufsize); _NSGetExecutablePath copies the path of the executable into the buffer and returns 0 if the path was successfully copied in the provided buffer. If the buffer is not large enough, -1 is returned and the expected buffer size is copied in *bufsize. */ uint32_t pathlen = PATH_MAX * 2; char rawpath[2 * PATH_MAX + 2]; if (0 == _NSGetExecutablePath(rawpath, &pathlen)) { // FIXME: will this be _inside_ the .app folder??? FilenameStripBase(rawpath); return fs::u8path(rawpath); } #endif // fallback method: use argv[0] path = argv0; #ifdef __APPLE__ // FIXME: check if _inside_ the .app folder #endif FilenameStripBase(path); return fs::u8path(path.get()); } // // Helper to escape path for writing. It adds quotes if needed, and any internal quotes are doubled // (like in MS-DOS) // SString escape(const fs::path &path) { std::string str = path.generic_u8string(); return SString(str).spaceEscape(); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/lib_file.h000066400000000000000000000054661464327712600202610ustar00rootroot00000000000000//------------------------------------------------------------------------ // File Utilities //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2012 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __LIB_FILE_H__ #define __LIB_FILE_H__ #include #include #include #include "filesystem.hpp" namespace fs = ghc::filesystem; #ifdef WIN32 #define DIR_SEP_CH '\\' #define DIR_SEP_STR "\\" #else #define DIR_SEP_CH '/' #define DIR_SEP_STR "/" #endif class SString; // filename functions bool HasExtension(const fs::path &filename); bool MatchExtensionNoCase(const fs::path &filename, const char *extension); fs::path ReplaceExtension(const fs::path &filename, const char *extension); fs::path GetBaseName(const fs::path &path); bool FilenameIsBare(const fs::path &filename); fs::path FilenameGetPath(const fs::path &filename); fs::path GetAbsolutePath(const fs::path &path); // file utilities bool FileExists(const fs::path &filename); bool FileDelete(const fs::path &filename); bool FileChangeDir(const fs::path &dir_name); bool FileMakeDir(const fs::path &dir_name); bool FileLoad(const fs::path &filename, std::vector &data); // miscellaneous fs::path GetExecutablePath(const char *argv0); //------------------------------------------------------------------------ enum scan_flags_e { SCAN_F_IsDir = (1 << 0), SCAN_F_Hidden = (1 << 1), SCAN_F_ReadOnly = (1 << 2), }; enum scan_error_e { SCAN_ERROR = -1, // general catch-all SCAN_ERR_NoExist = -2, // could not find given path SCAN_ERR_NotDir = -3, // path was not a directory }; typedef void (* directory_iter_f)(const fs::path &name, int flags, void *priv_dat); int ScanDirectory(const fs::path &path, directory_iter_f func, void *priv_dat); int ScanDirectory(const fs::path &path, const std::function &func); // scan the directory with the given path and call the given // function (passing the private data pointer to it) for each // entry in the directory. Returns the total number of entries, // or a negative value on error (SCAN_ERR_xx value). SString escape(const fs::path &path); #endif /* __LIB_FILE_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/lib_tga.cc000066400000000000000000000231131464327712600202400ustar00rootroot00000000000000//------------------------------------------------------------------------ // TGA (Targa) IMAGE LOADING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2013-2016 Andrew Apted // Copyright (C) 1997-2001 Id Software, 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 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // NOTE: this is based on the TGA loading code from Quake 2. // //------------------------------------------------------------------------ #include "Errors.h" #include "main.h" #include "lib_tga.h" struct targa_header_t { uint8_t id_length; uint8_t colormap_type; uint8_t image_type; uint16_t colormap_start; uint16_t colormap_length; uint8_t colormap_bits; uint16_t x_origin; uint16_t y_origin; uint16_t width; uint16_t height; uint8_t pixel_bits; uint8_t attributes; }; enum tga_type_e { TGA_INDEXED = 1, TGA_INDEXED_RLE = 9, TGA_RGB = 2, TGA_RGB_RLE = 10, TGA_BW = 3, TGA_BW_RLE = 11 }; rgba_color_t * TGA_DecodeImage(const byte *buffer, size_t length, int& width, int& height) { const byte * buf_p = buffer; const byte * buf_end = buffer + length; // decode the TGA header targa_header_t targa_header = {}; if(length < 18) return nullptr; targa_header.id_length = *buf_p++; targa_header.colormap_type = *buf_p++; targa_header.image_type = *buf_p++; targa_header.colormap_start = static_cast((buf_p[0]) | (buf_p[1] << 8)); buf_p += 2; targa_header.colormap_length = static_cast((buf_p[0]) | (buf_p[1] << 8)); buf_p += 2; targa_header.colormap_bits = *buf_p++; targa_header.x_origin = static_cast((buf_p[0]) | (buf_p[1] << 8)); buf_p += 2; targa_header.y_origin = static_cast((buf_p[0]) | (buf_p[1] << 8)); buf_p += 2; targa_header.width = static_cast((buf_p[0]) | (buf_p[1] << 8)); buf_p += 2; targa_header.height = static_cast((buf_p[0]) | (buf_p[1] << 8)); buf_p += 2; targa_header.pixel_bits = *buf_p++; targa_header.attributes = *buf_p++; if(buf_p + targa_header.id_length > buf_end) return nullptr; if (targa_header.id_length != 0) buf_p += targa_header.id_length; // skip TARGA image comment if (targa_header.image_type != TGA_INDEXED && targa_header.image_type != TGA_INDEXED_RLE && targa_header.image_type != TGA_RGB && targa_header.image_type != TGA_RGB_RLE) { gLog.printf("Bad tga file: type %d is not supported\n", targa_header.image_type); return NULL; } width = targa_header.width; height = targa_header.height; if (width == 0 || height == 0) { gLog.printf("Bad tga file: width or height is zero\n"); return NULL; } bool is_masked = false; // opacity testing bool is_complex = false; // // decode the palette, if any rgba_color_t palette[256]; if (targa_header.image_type == TGA_INDEXED || targa_header.image_type == TGA_INDEXED_RLE) { if (targa_header.colormap_type != 1) { gLog.printf("Bad tga file: colormap type != 1\n"); return NULL; } if (targa_header.colormap_length > 256) { gLog.printf("Bad tga file: too many colors (over 256)\n"); return NULL; } if (targa_header.pixel_bits != 8 || targa_header.colormap_bits < 24) { gLog.printf("Bad tga file: unsupported colormap size\n"); return NULL; } memset(palette, 255, sizeof(palette)); int cm_start = targa_header.colormap_start; int cm_end = cm_start + targa_header.colormap_length; for (int n = cm_start ; n < cm_end ; n++) { if(buf_p + 3 > buf_end) return nullptr; byte b = *buf_p++; byte g = *buf_p++; byte r = *buf_p++; byte a = 255; if (targa_header.colormap_bits == 32) { if(buf_p >= buf_end) return nullptr; a = *buf_p++; } palette[n] = RGBA_MAKE(r, g, b, a); } } // decode the pixel stream rgba_color_t * pixels = new rgba_color_t[width * height]; rgba_color_t * dest = pixels; rgba_color_t * p; if (targa_header.image_type == TGA_RGB) // Uncompressed, RGB images { if (targa_header.pixel_bits != 24 && targa_header.pixel_bits != 32) { gLog.printf("Bad tga file: only 24 or 32 bit images supported\n"); delete[] pixels; return NULL; } for (int y = height-1 ; y >= 0 ; y--) { p = dest + y * width; for (int x = 0 ; x < width ; x++) { if(buf_p + 3 > buf_end) { delete[] pixels; return nullptr; } byte b = *buf_p++; byte g = *buf_p++; byte r = *buf_p++; byte a = 255; if (targa_header.pixel_bits == 32) { if(buf_p >= buf_end) { delete[] pixels; return nullptr; } a = *buf_p++; } *p++ = RGBA_MAKE(r, g, b, a); if (a == 0) is_masked = true; else if (a != 255) is_complex = true; } } } else if (targa_header.image_type == TGA_RGB_RLE) // Runlength encoded RGB images { if (targa_header.pixel_bits != 24 && targa_header.pixel_bits != 32) { gLog.printf("Bad tga file: only 24 or 32 bit images supported\n"); delete[] pixels; return NULL; } byte r=0, g=0, b=0, a=0; byte packet_header, packet_size; for (int y = height-1 ; y >= 0 ; y--) { p = dest + y * width; for (int x = 0 ; x < width ; ) { if(buf_p >= buf_end) { delete[] pixels; return nullptr; } packet_header = *buf_p++; packet_size = 1 + (packet_header & 0x7f); if (packet_header & 0x80) // run-length packet { if(buf_p + 3 > buf_end) { delete[] pixels; return nullptr; } b = *buf_p++; g = *buf_p++; r = *buf_p++; a = 255; if (targa_header.pixel_bits == 32) { if(buf_p >= buf_end) { delete[] pixels; return nullptr; } a = *buf_p++; } if (a == 0) is_masked = true; else if (a != 255) is_complex = true; for (int j = 0 ; j < packet_size ; j++) { *p++ = RGBA_MAKE(r, g, b, a); x++; if (x == width) // run spans across edge { x = 0; if (y > 0) y--; else goto breakOut; p = dest + y*width; } } } else // not a run-length packet { for (int j = 0 ; j < packet_size; j++) { if(buf_p + 3 > buf_end) { delete[] pixels; return nullptr; } b = *buf_p++; g = *buf_p++; r = *buf_p++; a = 255; if (targa_header.pixel_bits == 32) { if(buf_p >= buf_end) { delete[] pixels; return nullptr; } a = *buf_p++; } *p++ = RGBA_MAKE(r, g, b, a); if (a == 0) is_masked = true; else if (a != 255) is_complex = true; x++; if (x == width) // pixel packet run spans across edge { x = 0; if (y > 0) y--; else goto breakOut; p = dest + y * width; } } } } breakOut: ; } } else if (targa_header.image_type == TGA_INDEXED) // Uncompressed, colormapped images { for (int y = height-1 ; y >= 0 ; y--) { p = dest + y * width; for (int x = 0 ; x < width ; x++) { if(buf_p >= buf_end) { delete[] pixels; return nullptr; } rgba_color_t col = palette[*buf_p++]; *p++ = col; byte a = RGBA_ALPHA(col); if (a == 0) is_masked = true; else if (a != 255) is_complex = true; } } } else if (targa_header.image_type == TGA_INDEXED_RLE) // Runlength encoded colormapped image { byte packet_header, packet_size; for (int y = height-1 ; y >= 0 ; y--) { p = dest + y * width; for (int x = 0 ; x < width ; ) { if(buf_p >= buf_end) { delete[] pixels; return nullptr; } packet_header = *buf_p++; packet_size = 1 + (packet_header & 0x7f); if (packet_header & 0x80) // run-length packet { if(buf_p >= buf_end) { delete[] pixels; return nullptr; } rgba_color_t col = palette[*buf_p++]; byte a = RGBA_ALPHA(col); if (a == 0) is_masked = true; else if (a != 255) is_complex = true; for (int j = 0 ; j < packet_size ; j++) { *p++ = col; x++; if (x == width) // run spans across edge { x = 0; if (y > 0) y--; else goto breakOut2; p = dest + y*width; } } } else // not a run-length packet { for (int j = 0 ; j < packet_size; j++) { if(buf_p >= buf_end) { delete[] pixels; return nullptr; } rgba_color_t col = palette[*buf_p++]; *p++ = col; byte a = RGBA_ALPHA(col); if (a == 0) is_masked = true; else if (a != 255) is_complex = true; x++; if (x == width) // pixel packet run spans across edge { x = 0; if (y > 0) y--; else goto breakOut2; p = dest + y * width; } } } } breakOut2: ; } } // just shut the fuck up, compiler (void) is_masked; (void) is_complex; return pixels; } void TGA_FreeImage(rgba_color_t *pixels) { SYS_ASSERT(pixels); delete[] pixels; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/lib_tga.h000066400000000000000000000022171464327712600201040ustar00rootroot00000000000000//------------------------------------------------------------------------ // TGA (Targa) IMAGE LOADING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2013-2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_TGA_LOADER_H__ #define __EUREKA_TGA_LOADER_H__ #include "im_color.h" rgba_color_t * TGA_DecodeImage(const byte *buffer, size_t length, int& width, int& height); void TGA_FreeImage(rgba_color_t *pixels); #endif /* __EUREKA_TGA_LOADER_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/lib_util.cc000066400000000000000000000075471464327712600204570ustar00rootroot00000000000000//------------------------------------------------------------------------ // UTILITIES //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Errors.h" #include "m_vector.h" #include "sys_debug.h" #include "sys_macro.h" #ifndef _MSC_VER #include #endif #include #include "m_strings.h" #include "w_rawdef.h" void TimeDelay(unsigned int millies) { SYS_ASSERT(millies < 300000); #ifdef WIN32 ::Sleep(millies); #else // LINUX or MacOSX usleep(millies * 1000); #endif } unsigned int TimeGetMillies() { // Note: you *MUST* handle overflow (it *WILL* happen) #ifdef WIN32 return GetTickCount(); #else struct timeval tv; struct timezone tz; gettimeofday(&tv, &tz); return ((int)tv.tv_sec * 1000 + (int)tv.tv_usec / 1000); #endif } // // sanity checks for the sizes and properties of certain types. // useful when porting. // #define assert_size(type,size) \ do \ { \ if (sizeof (type) != size) \ ThrowException("sizeof " #type " is %d (should be " #size ")\n", \ (int) sizeof (type)); \ } \ while (0) #define assert_wrap(type,high,low) \ do \ { \ type n = high; \ if (++n != low) \ FatalError("Type " #type " wraps around to %lu (should be " #low ")\n",\ (unsigned long) n); \ } \ while (0) void CheckTypeSizes() { assert_size(uint8_t, 1); assert_size(int8_t, 1); assert_size(uint16_t, 2); assert_size(int16_t, 2); assert_size(uint32_t, 4); assert_size(int32_t, 4); assert_size(raw_linedef_t, 14); assert_size(raw_sector_s, 26); assert_size(raw_sidedef_t, 30); assert_size(raw_thing_t, 10); assert_size(raw_vertex_t, 4); } double PerpDist(v2double_t v, v2double_t v1, v2double_t v2) { v -= v1; v2 -= v1; double len = v2.hypot(); SYS_ASSERT(len > 0); return (v.x * v2.y - v.y * v2.x) / len; } double AlongDist(v2double_t v, v2double_t v1, v2double_t v2) { v -= v1; v2 -= v1; double len = v2.hypot(); SYS_ASSERT(len > 0); return (v.x * v2.x + v.y * v2.y) / len; } // // rounds the value _up_ to the nearest power of two. // int RoundPOW2(int x) { if (x <= 2) return x; x--; for (int tmp = x >> 1 ; tmp ; tmp >>= 1) x |= tmp; return x + 1; } // // Thread-safe way to get error message, instead of strerror // SString GetErrorMessage(int errorNumber) { #ifdef _WIN32 char message[256]; errno_t result = strerror_s(message, errorNumber); if(result) return SString::printf("other error (%d)", errorNumber); return message; #elif defined __APPLE__ char message[256] = {}; int result = strerror_r(errorNumber, message, 256); message[255] = 0; if(result) return SString::printf("other error (%d)", errorNumber); return message; #else // TODO: use the threadsafe method return strerror(errorNumber); #endif } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/lib_util.h000066400000000000000000000044001464327712600203020ustar00rootroot00000000000000//------------------------------------------------------------------------ // UTILITIES //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2013 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_LIB_UTIL_H__ #define __EUREKA_LIB_UTIL_H__ #include "PrintfMacros.h" #include #include #include #include #include class SString; struct v2double_t; void CheckTypeSizes(); void TimeDelay(unsigned int millies); unsigned int TimeGetMillies(); double PerpDist(v2double_t v, /* coord to test */ v2double_t v1, v2double_t v2 /* line */); double AlongDist(v2double_t v, /* coord to test */ v2double_t v1, v2double_t v2 /* line */); // round a positive value up to the nearest power of two int RoundPOW2(int x); SString GetErrorMessage(int errorNumber); template const V *get(const std::map &map, const K &key) { auto it = map.find(key); if(it == map.end()) return nullptr; return &it->second; } /* * y_isident - return true iff is one of a-z, A-Z, 0-9 or "_". * * Intentionally not using isalpha() and co. because I * don't want the results to depend on the locale. */ #define IDENT_SET "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_" #endif /* __EUREKA_YUTIL_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_bitvec.cc000066400000000000000000000053461464327712600204370ustar00rootroot00000000000000//------------------------------------------------------------------------ // BIT VECTORS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2015 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Errors.h" #include "m_bitvec.h" #include "sys_debug.h" bitvec_c::bitvec_c(int n_elements) : num_elem(n_elements) { int total = (num_elem / 8) + 1; data.resize(total); clear_all(); } void bitvec_c::resize(int n_elements) { SYS_ASSERT(n_elements > 0); int old_elem = num_elem; int new_total = (n_elements / 8) + 1; // don't bother re-allocating unless shrinking by a large amount if (num_elem / 2 < n_elements && n_elements < num_elem) { num_elem = n_elements; return; } num_elem = n_elements; data.resize(new_total); // make sure the bits near the old top are clear for (int i = 0 ; i < 8 ; i++) { if (old_elem + i < num_elem) raw_clear(old_elem + i); } } bool bitvec_c::get(int n) const noexcept { SYS_ASSERT(n >= 0); if (n >= num_elem) return 0; return raw_get(n); } void bitvec_c::set(int n) { SYS_ASSERT(n >= 0); while (n >= num_elem) { resize(num_elem * 3 / 2 + 16); } raw_set(n); } void bitvec_c::clear(int n) noexcept { SYS_ASSERT(n >= 0); if (n >= num_elem) return; raw_clear(n); } void bitvec_c::toggle(int n) { if (get(n)) clear(n); else set(n); } void bitvec_c::frob(int n, BitOp op) { switch (op) { case BitOp::add: set(n); break; case BitOp::remove: clear(n); break; default: toggle(n); break; } } void bitvec_c::set_all() { // Note: this will set some extra bits (over num_elem). // the get() functions (etc) make sure to never use them. memset(data.data(), 0xff, data.size()); } void bitvec_c::clear_all() { memset(data.data(), 0, data.size()); } void bitvec_c::toggle_all() { for(byte &b : data) b ^= 0xff; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_bitvec.h000066400000000000000000000053701464327712600202760ustar00rootroot00000000000000//------------------------------------------------------------------------ // BIT VECTORS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2015 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_M_BITVEC_H__ #define __EUREKA_M_BITVEC_H__ #include "sys_type.h" #include enum class BitOp { add, // Add to selection remove, // Remove from selection toggle // If not in selection, add it, else remove it }; class bitvec_c { // // Although this bit-vector has a current size, it acts as though it // was infinitely sized and all bits past the end are zero. When // setting a bit past the end, it will automatically resize itself. // private: std::vector data; int num_elem; public: explicit bitvec_c(int n_elements = 64); bitvec_c(const bitvec_c &other) = default; bitvec_c(bitvec_c &&other) : data(std::move(other.data)), num_elem(other.num_elem) { other.num_elem = 0; } bitvec_c &operator = (bitvec_c &&other) = default; inline int size() const { return num_elem; } bool get(int n) const noexcept; // Get bit void set(int n); // Set bit to 1 void clear(int n) noexcept; // Set bit to 0 void toggle(int n); // Toggle bit void frob(int n, BitOp op); void set_all(); void clear_all(); void toggle_all(); private: /* NOTE : these functions do no range checking! */ inline bool raw_get(int n) const noexcept { return !!(data[n >> 3] & (1 << (n & 7))); } inline void raw_set(int n) { data[n >> 3] |= (1 << (n & 7)); } inline void raw_clear(int n) noexcept { data[n >> 3] &= ~(1 << (n & 7)); } inline void raw_toggle(int n) { data[n >> 3] ^= (1 << (n & 7)); } inline int getByteCount() const { return num_elem / 8 + 1; } // this preserves existing elements void resize(int n_elements); }; #endif /* __EUREKA_M_BITVEC_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_config.cc000066400000000000000000000600211464327712600204170ustar00rootroot00000000000000//------------------------------------------------------------------------ // CONFIG FILE //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2018 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Instance.h" #include "lib_adler.h" #include "m_config.h" #include "m_parse.h" #include "m_streams.h" #include "filesystem.hpp" namespace fs = ghc::filesystem; namespace config { LoadingData preloading; } //------------------------------------------------------------------------ const opt_desc_t options[] = { // // A few options must be handled in an early pass // { "home", 0, OptFlag_pass1, "Home directory", "", &global::home_dir }, { "install", 0, OptFlag_pass1, "Installation directory", "", &global::install_dir }, { "log", 0, OptFlag_pass1, "Log messages to specified file", "", &global::log_file }, { "config", 0, OptFlag_pass1 | OptFlag_helpNewline, "Config file to load / save", "", &global::config_file }, { "help", "h", OptFlag_pass1, "Show usage summary", NULL, &global::show_help }, { "version", "v", OptFlag_pass1, "Show the version", NULL, &global::show_version }, { "debug", "d", OptFlag_pass1, "Enable debugging messages", NULL, &global::Debugging }, { "quiet", "q", OptFlag_pass1, "Quiet mode (no messages on stdout)", NULL, &global::Quiet }, // // Normal options from here on.... // { "file", "f", 0, "Wad file(s) to edit", "...", &global::Pwad_list }, { "merge", "m", 0, "Resource file(s) to load", "...", &config::preloading.resourceList }, { "iwad", "i", 0, "The name of the IWAD (game data)", "", &config::preloading.iwadName // TODO: same deal }, { "port", "p", 0, "Port (engine) name", "", &config::preloading.portName // TODO: same deal }, { "warp", "w", OptFlag_warp | OptFlag_helpNewline, "Select level to edit", "", &config::preloading.levelName // TODO: this will need to work only for first instance }, { "udmftest", 0, OptFlag_hide, "Enable the unfinished UDMF support", NULL, &global::udmf_testing }, /* ------------ Preferences ------------ */ { "auto_load_recent", 0, OptFlag_preference, "When no given files, load the most recent one saved", NULL, &config::auto_load_recent }, { "begin_maximized", 0, OptFlag_preference, "Maximize the window when Eureka starts", NULL, &config::begin_maximized }, { "backup_max_files", 0, OptFlag_preference, "Maximum copies to make when backing up a wad", NULL, &config::backup_max_files }, { "backup_max_space", 0, OptFlag_preference, "Maximum space to use (in MB) when backing up a wad", NULL, &config::backup_max_space }, { "browser_combine_tex", 0, OptFlag_preference, "Combine flats and textures in a single browser", NULL, &config::browser_combine_tex }, { "browser_small_tex", 0, OptFlag_preference, "Show smaller (more compact) textures in the browser", NULL, &config::browser_small_tex }, { "bsp_on_save", 0, OptFlag_preference, "Node building: always build the nodes after saving", NULL, &config::bsp_on_save }, { "bsp_fast", 0, OptFlag_preference, "Node building: enable fast mode (may be lower quality)", NULL, &config::bsp_fast }, { "bsp_warnings", 0, OptFlag_preference, "Node building: show all warning messages", NULL, &config::bsp_warnings }, { "bsp_split_factor", 0, OptFlag_preference, "Node building: seg splitting factor", NULL, &config::bsp_split_factor }, { "bsp_gl_nodes", 0, OptFlag_preference, "Node building: build GL-Nodes", NULL, &config::bsp_gl_nodes }, { "bsp_force_v5", 0, OptFlag_preference, "Node building: force V5 of GL-Nodes", NULL, &config::bsp_force_v5 }, { "bsp_force_zdoom", 0, OptFlag_preference, "Node building: force ZDoom format for normal nodes", NULL, &config::bsp_force_zdoom }, { "bsp_compressed", 0, OptFlag_preference, "Node building: force zlib compression of ZDoom nodes", NULL, &config::bsp_compressed }, { "default_gamma", 0, OptFlag_preference, "Default gamma for images and 3D view (0..4)", NULL, &config::usegamma }, { "default_edit_mode", 0, OptFlag_preference, "Default editing mode: 0..3 = Th / Lin / Sec / Vt", NULL, &config::default_edit_mode }, { "default_port", 0, OptFlag_preference, "Default port (engine) name", NULL, &config::default_port }, { "dotty_axis_col", 0, OptFlag_preference, "axis color for the dotty style grid", NULL, &config::dotty_axis_col }, { "dotty_major_col", 0, OptFlag_preference, "major color for the dotty style grid", NULL, &config::dotty_major_col }, { "dotty_minor_col", 0, OptFlag_preference, "minor color for the dotty style grid", NULL, &config::dotty_minor_col }, { "dotty_point_col", 0, OptFlag_preference, "point color for the dotty style grid", NULL, &config::dotty_point_col }, { "floor_bump_small", 0, OptFlag_preference, "distance for '+' and '-' buttons in sector panel while SHIFT is pressed", NULL, &config::floor_bump_small }, { "floor_bump_medium", 0, OptFlag_preference, "distance for '+' and '-' buttons in sector panel without any modifier keys", NULL, &config::floor_bump_medium }, { "floor_bump_large", 0, OptFlag_preference, "distance for '+' and '-' buttons in sector panel while CTRL is pressed", NULL, &config::floor_bump_large }, { "grid_default_mode", 0, OptFlag_preference, "Default grid mode: 0 = OFF, 1 = normal", NULL, &config::grid_default_mode }, { "grid_default_size", 0, OptFlag_preference, "Default grid size", NULL, &config::grid_default_size }, { "grid_default_snap", 0, OptFlag_preference, "Default grid snapping", NULL, &config::grid_default_snap }, { "grid_hide_in_free_mode", 0, OptFlag_preference, "hide the grid in FREE mode", NULL, &config::grid_hide_in_free_mode }, { "grid_ratio_high", 0, OptFlag_preference, "custom grid ratio : high value (numerator)", NULL, &config::grid_ratio_high }, { "grid_ratio_low", 0, OptFlag_preference, "custom grid ratio : low value (denominator)", NULL, &config::grid_ratio_low }, { "grid_snap_indicator", 0, OptFlag_preference, "show a cross at the grid-snapped location", NULL, &config::grid_snap_indicator }, { "grid_style", 0, OptFlag_preference, "grid style : 0 = squares, 1 = dotty", NULL, &config::grid_style }, { "gui_theme", 0, OptFlag_preference, "GUI widget theme: 0 = fltk, 1 = gtk+, 2 = plastic", NULL, &config::gui_scheme }, { "gui_color_set", 0, OptFlag_preference, "GUI color set: 0 = fltk default, 1 = bright, 2 = custom", NULL, &config::gui_color_set }, { "gui_custom_bg", 0, OptFlag_preference, "GUI custom background color", NULL, &config::gui_custom_bg }, { "gui_custom_ig", 0, OptFlag_preference, "GUI custom input color", NULL, &config::gui_custom_ig }, { "gui_custom_fg", 0, OptFlag_preference, "GUI custom foreground (text) color", NULL, &config::gui_custom_fg }, { "highlight_line_info", 0, OptFlag_preference, "Info drawn near a highlighted line (0 = nothing)", NULL, &config::highlight_line_info }, { "leave_offsets_alone", 0, OptFlag_preference, "Do not adjust offsets when splitting lines (etc)", NULL, &config::leave_offsets_alone }, { "light_bump_small", 0, OptFlag_preference, "light step for '+' and '-' buttons in sector panel while SHIFT is pressed", NULL, &config::light_bump_small }, { "light_bump_medium", 0, OptFlag_preference, "light step for '+' and '-' buttons in sector panel without any modifier keys", NULL, &config::light_bump_medium }, { "light_bump_large", 0, OptFlag_preference, "light step for '+' and '-' buttons in sector panel while CTRL is pressed", NULL, &config::light_bump_large }, { "map_scroll_bars", 0, OptFlag_preference, "Enable scroll-bars for the map view", NULL, &config::map_scroll_bars }, { "minimum_drag_pixels", 0, OptFlag_preference, "Minimum distance to move mouse to drag an object (in pixels)", NULL, &config::minimum_drag_pixels }, { "new_sector_size", 0, OptFlag_preference, "Size of sector rectangles created outside of the map", NULL, &config::new_sector_size }, { "normal_axis_col", 0, OptFlag_preference, "axis color for the normal grid", NULL, &config::normal_axis_col }, { "normal_main_col", 0, OptFlag_preference, "main color for the normal grid", NULL, &config::normal_main_col }, { "normal_flat_col", 0, OptFlag_preference, "flat color for the normal grid", NULL, &config::normal_flat_col }, { "normal_small_col", 0, OptFlag_preference, "small color for the normal grid", NULL, &config::normal_small_col }, { "panel_gamma", 0, OptFlag_preference, "Gamma for images in the panels and the browser (0..4)", NULL, &config::panel_gamma }, { "render_pix_aspect", 0, OptFlag_preference, "Aspect ratio of pixels for 3D view (100 * width / height)", NULL, &config::render_pixel_aspect }, { "render_far_clip", 0, OptFlag_preference, "Distance of far clip plane for 3D rendering", NULL, &config::render_far_clip }, { "render_high_detail", 0, OptFlag_preference, "Use highest detail when rendering 3D view (software mode)", NULL, &config::render_high_detail }, { "render_lock_gravity", 0, OptFlag_preference, "Locked gravity in 3D view -- cannot move up or down", NULL, &config::render_lock_gravity }, { "render_missing_bright", 0, OptFlag_preference, "Render the missing texture as fullbright", NULL, &config::render_missing_bright }, { "render_unknown_bright", 0, OptFlag_preference, "Render the unknown texture as fullbright", NULL, &config::render_unknown_bright }, { "same_mode_clears_selection", 0, OptFlag_preference, "Clear the selection when entering the same mode", NULL, &config::same_mode_clears_selection }, { "sector_render_default", 0, OptFlag_preference, "Default sector rendering mode: 0 = NONE, 1 = floor, 2 = ceiling", NULL, &config::sector_render_default }, { "show_full_one_sided", 0, OptFlag_preference, "Show all textures on one-sided lines in the Linedef panel", NULL, &config::show_full_one_sided }, { "sidedef_add_del_buttons", 0, OptFlag_preference, "Show the ADD and DEL buttons in Sidedef panels", NULL, &config::sidedef_add_del_buttons }, { "thing_render_default", 0, OptFlag_preference, "Default thing rendering mode: 0 = boxes, 1 = sprites", NULL, &config::thing_render_default }, { "transparent_col", 0, OptFlag_preference, "color used to represent transparent pixels in textures", NULL, &config::transparent_col }, { "swap_sidedefs", 0, OptFlag_preference, "Swap upper and lower sidedefs in the Linedef panel", NULL, &config::swap_sidedefs }, // // That's all there is // { 0, 0, 0, 0, 0, nullptr } }; //------------------------------------------------------------------------ // // Parse config line from file // static int parse_config_line_from_file(const SString &line, const fs::path &basename, int lnum, const opt_desc_t *options) { TokenWordParse parse(line, true); SString key; if(!parse.getNext(key)) // empty line return 0; SString value; if(!parse.getNext(value)) { gLog.printf("WARNING: %s(%u): bad line, missing option value.\n", basename.u8string().c_str(), lnum); return 0; } const opt_desc_t *opt; for(opt = options;; opt++) { if ( !opt->long_name && !opt->short_name) // end { gLog.printf("WARNING: %s(%u): invalid option '%s', skipping\n", basename.u8string().c_str(), lnum, line.c_str()); return 0; } if(!opt->long_name || key != opt->long_name) continue; // pre-pass options (like --help) don't make sense in a config file if (opt->flags & OptFlag_pass1) { gLog.printf("WARNING: %s(%u): cannot use option '%s' in config " "files.\n", basename.u8string().c_str(), lnum, line.c_str()); return 0; } // found it break; } if(auto ptr = std::get_if(&opt->data_ptr)) { if(value.noCaseEqual("no") || value.noCaseEqual("false") || value.noCaseEqual("off") || value.noCaseEqual("0")) { **ptr = false; } else // anything else is TRUE **ptr = true; } else if(auto ptr = std::get_if(&opt->data_ptr)) **ptr = atoi(value); else if(auto ptr = std::get_if(&opt->data_ptr)) **ptr = ParseColor(value); else if(auto ptr = std::get_if(&opt->data_ptr)) **ptr = value; else if(auto ptr = std::get_if(&opt->data_ptr)) **ptr = fs::u8path(value.get()); else if(auto ptr = std::get_if *>(&opt->data_ptr)) { if(value != "{}") { do (*ptr)->push_back(value); while(parse.getNext(value)); } } else if(auto ptr = std::get_if *>(&opt->data_ptr)) { if(value != "{}") { fs::path pathvalue = fs::u8path(value.get()); do (*ptr)->push_back(pathvalue); while(parse.getNext(pathvalue)); } } return 0; // OK } // // try to parse a config file by pathname. // // Return 0 on success, negative value on failure. // static int parse_a_config_file(std::istream &is, const fs::path &filename, const opt_desc_t *options) { fs::path basename = filename.filename(); // handle one line on each iteration SString line; for(int lnum = 1; M_ReadTextLine(line, is); lnum++) { int ret = parse_config_line_from_file(line, basename, lnum, options); if (ret != 0) return ret; } return 0; // OK } // // parses the config file (either a user-specific one or the default one). // // return 0 on success, negative value on error. // int M_ParseConfigFile(const fs::path &path, const opt_desc_t *options) { std::ifstream is(path); gLog.printf("Reading config file: %s\n", path.u8string().c_str()); if (!is.is_open()) { gLog.printf("--> %s\n", GetErrorMessage(errno).c_str()); return -1; } return parse_a_config_file(is, path, options); } // // check certain environment variables... // void M_ParseEnvironmentVars() { #if 0 char *value; value = getenv ("EUREKA_GAME"); if (value != NULL) Game = value; #endif } // // Common function to populate a list of strings or paths // template static void readArgsForList(bool ignore, int &argc, const char *const *&argv, const ArgData &data_ptr) { if(argc < 2) { ThrowException("missing argument after '%s'\n", argv[0]); /* NOT REACHED */ } while(argc > 1 && argv[1][0] != '-' && argv[1][0] != '+') { argv++; argc--; if (! ignore) { auto list = std::get *>(data_ptr); list->push_back(argv[0]); } } } // // parses the command line options // // If is set to 1, ignores all options except those // that have the "1" flag (the "early" options). // // Otherwise, ignores all options that have the "1" flag. // void M_ParseCommandLine(int argc, const char *const *argv, CommandLinePass pass, std::vector &Pwad_list, const opt_desc_t *options) { const opt_desc_t *o; while (argc > 0) { bool ignore; // is it actually an option? if (argv[0][0] != '-') { // this is a loose file, handle it now if (pass == CommandLinePass::normal) Pwad_list.push_back(fs::u8path(argv[0])); argv++; argc--; continue; } // Which option is this? for (o = options; ; o++) { if (std::get_if(&o->data_ptr)) { ThrowException("unknown option: '%s'\n", argv[0]); /* NOT REACHED */ } if ( (o->short_name && strcmp (argv[0]+1, o->short_name) == 0) || (o->long_name && strcmp (argv[0]+1, o->long_name ) == 0) || (o->long_name && argv[0][1] == '-' && strcmp (argv[0]+2, o->long_name ) == 0) ) break; } // ignore options which are not meant for this pass ignore = !!(o->flags & OptFlag_pass1) != (pass == CommandLinePass::early); if(auto ptr = std::get_if(&o->data_ptr)) { // -AJA- permit a following value if (argc >= 2 && argv[1][0] != '-') { argv++; argc--; if (ignore) break; if (y_stricmp(argv[0], "no") == 0 || y_stricmp(argv[0], "false") == 0 || y_stricmp(argv[0], "off") == 0 || y_stricmp(argv[0], "0") == 0) { **ptr = false; } else // anything else is TRUE { **ptr = true; } } else if (! ignore) { **ptr = true; } } else if(auto ptr = std::get_if(&o->data_ptr)) { if (argc < 2) { ThrowException("missing argument after '%s'\n", argv[0]); /* NOT REACHED */ } argv++; argc--; if (! ignore) { **ptr = atoi(argv[0]); } } else if(auto ptr = std::get_if(&o->data_ptr)) { if (argc < 2) { ThrowException("missing argument after '%s'\n", argv[0]); /* NOT REACHED */ } argv++; argc--; if (! ignore) { **ptr = ParseColor(argv[0]); } } else if(auto ptr = std::get_if(&o->data_ptr)) { if (argc < 2) { ThrowException("missing argument after '%s'\n", argv[0]); /* NOT REACHED */ } argv++; argc--; if(!ignore) **ptr = argv[0]; // support two numeric values after -warp if (o->flags & OptFlag_warp && isdigit(argv[0][0]) && argc > 1 && isdigit(argv[1][0])) { if (! ignore) { **ptr = SString(argv[0]) + argv[1]; } argv++; argc--; } } else if(auto ptr = std::get_if(&o->data_ptr)) { if(argc < 2) { ThrowException("missing argument after '%s'\n", argv[0]); } ++argv; --argc; if(!ignore) **ptr = fs::u8path(argv[0]); } else if(auto ptr = std::get_if *>(&o->data_ptr)) readArgsForList(ignore, argc, argv, *ptr); else if(auto ptr = std::get_if *>(&o->data_ptr)) readArgsForList(ignore, argc, argv, *ptr); argv++; argc--; } } // // print a list of all command line options (usage message). // void M_PrintCommandLineOptions() { const opt_desc_t *o; int name_maxlen = 0; for (o = options; !std::get_if(&o->data_ptr); o++) { int len; if (o->flags & (OptFlag_preference | OptFlag_hide)) continue; if (o->long_name) { len = (int)strlen (o->long_name); name_maxlen = std::max(name_maxlen, len); } if (o->arg_desc) len = (int)strlen (o->arg_desc); } for (int pass = 0 ; pass < 2 ; pass++) for (o = options; !std::get_if(&o->data_ptr); o++) { if (o->flags & (OptFlag_preference | OptFlag_hide)) continue; if ((o->flags & OptFlag_pass1 ? 1 : 0) != pass) continue; if (o->short_name) printf (" -%-3s ", o->short_name); else printf (" "); if (o->long_name) printf ("--%-*s ", name_maxlen, o->long_name); else printf ("%*s ", name_maxlen + 2, ""); if (o->arg_desc) printf ("%-12s", o->arg_desc); else { if(std::get_if(&o->data_ptr)) printf (" "); else if(std::get_if(&o->data_ptr)) printf (" "); else if(std::get_if(&o->data_ptr)) printf (" "); else if(std::get_if(&o->data_ptr)) printf (" "); else if(std::get_if(&o->data_ptr)) printf(" "); else if(std::get_if *>(&o->data_ptr)) printf (" ..."); else if(std::get_if *>(&o->data_ptr)) printf(" ..."); } printf (" %s\n", o->desc); if (o->flags & OptFlag_helpNewline) printf ("\n"); } } // // Given a list of strings or paths, writes them to a config file // static void writeListToConfig(const std::vector &list, std::ofstream &os) { if (list.empty()) os << "{}"; else for (const SString &item : list) os << item.spaceEscape() << ' '; } static void writeListToConfig(const std::vector &list, std::ofstream &os) { if (list.empty()) os << "{}"; else for (const fs::path &item : list) os << escape(item) << ' '; } int M_WriteConfigFile(const fs::path &path, const opt_desc_t *options) { gLog.printf("Writing config file: %s\n", path.u8string().c_str()); std::ofstream os(path, std::ios::trunc); if (! os.is_open()) { gLog.printf("--> %s\n", GetErrorMessage(errno).c_str()); return -1; } os << "# Eureka configuration (local)\n"; const opt_desc_t *o; for (o = options; !std::get_if(&o->data_ptr); o++) { if (!(o->flags & OptFlag_preference)) continue; if (! o->long_name) continue; os << o->long_name << ' '; if(auto ptr = std::get_if(&o->data_ptr)) os << (**ptr ? "1" : "0"); else if(auto ptr = std::get_if(&o->data_ptr)) os << (*ptr)->spaceEscape(); else if(auto ptr = std::get_if(&o->data_ptr)) os << escape(**ptr); else if(auto ptr = std::get_if(&o->data_ptr)) os << **ptr; else if(auto ptr = std::get_if(&o->data_ptr)) os << SString::printf("%06x", **ptr >> 8); else if(auto ptr = std::get_if *>(&o->data_ptr)) writeListToConfig(**ptr, os); else if(auto ptr = std::get_if *>(&o->data_ptr)) writeListToConfig(**ptr, os); os << '\n'; } return 0; // OK } //------------------------------------------------------------------------ // USER STATE HANDLING //------------------------------------------------------------------------ static fs::path PersistFilename(const crc32_c& crc) { return global::cache_dir / "cache" / crc.getPath(); } #define MAX_TOKENS 10 bool Instance::M_LoadUserState() { crc32_c crc; level.getLevelChecksum(crc); fs::path filename = PersistFilename(crc); LineFile file(filename); if (! file.isOpen()) return false; gLog.printf("Loading user state from: %s\n", filename.u8string().c_str()); SString line; while (file.readLine(line)) { TokenWordParse parse(line, true); SString word; std::vector tokens; while (parse.getNext(word)) tokens.push_back(word); int num_tok = (int)tokens.size(); if (num_tok == 0) continue; if (num_tok < 0) { gLog.printf("Error in persistent data: %s\n", line.c_str()); continue; } if ( Editor_ParseUser(tokens) || grid.parseUser(tokens) || Render3D_ParseUser(tokens) || Browser_ParseUser(*this, tokens) || Props_ParseUser(*this, tokens) || RecUsed_ParseUser(tokens)) { // Ok } else { gLog.printf("Unknown persistent data: %s\n", line.c_str()); } } file.close(); if(main_win) main_win->propsLoadValues(); return true; } // // user state persistence (stuff like camera pos, grid settings, ...) // bool Instance::M_SaveUserState() const { crc32_c crc; level.getLevelChecksum(crc); fs::path filename = PersistFilename(crc); gLog.printf("Save user state to: %s\n", filename.u8string().c_str()); std::ofstream os(filename, std::ios::trunc); if (! os.is_open()) { gLog.printf("--> FAILED! (%s)\n", GetErrorMessage(errno).c_str()); return false; } Editor_WriteUser(os); grid.writeUser(os); Render3D_WriteUser(os); Browser_WriteUser(os); Props_WriteUser(os); RecUsed_WriteUser(os); return true; } void Instance::M_DefaultUserState() { grid.Init(); ZoomWholeMap(); Render3D_Setup(); edit.defaultState(); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_config.h000066400000000000000000000114031464327712600202610ustar00rootroot00000000000000//------------------------------------------------------------------------ // CONFIG FILE //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2018 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_M_CONFIG_H__ #define __EUREKA_M_CONFIG_H__ #include "im_color.h" #include #include #include "filesystem.hpp" namespace fs = ghc::filesystem; struct LoadingData; /* ==== CONFIG VARIABLES ==================== */ enum { OptFlag_pass1 = 1 << 0, OptFlag_helpNewline = 1 << 1, OptFlag_preference = 1 << 2, OptFlag_warp = 1 << 3, OptFlag_hide = 1 << 4, }; typedef std::variant *, std::vector *, std::nullptr_t> ArgData; struct opt_desc_t { const char *long_name; // Command line arg. or keyword const char *short_name; // Abbreviated command line argument unsigned flags; // Flags for this option : // '1' : process only on pass 1 of parse_command_line_options() // '<' : print extra newline after this option (when dumping) // 'v' : a real variable (preference setting) // 'w' : warp hack -- accept two numeric args // 'H' : hide option from --help display const char *desc; // Description of the option const char *arg_desc; // Description of the argument (NULL --> none or default) // Pointer to the data ArgData data_ptr; }; namespace config { extern SString default_port; extern int default_edit_mode; extern bool auto_load_recent; extern bool begin_maximized; extern bool map_scroll_bars; extern bool leave_offsets_alone; extern bool same_mode_clears_selection; extern bool swap_sidedefs; extern bool show_full_one_sided; extern bool sidedef_add_del_buttons; extern int gui_scheme; extern int gui_color_set; extern rgb_color_t gui_custom_bg; extern rgb_color_t gui_custom_ig; extern rgb_color_t gui_custom_fg; extern int panel_gamma; extern int minimum_drag_pixels; extern int highlight_line_info; extern int new_sector_size; extern int sector_render_default; extern int thing_render_default; extern int grid_style; extern bool grid_default_mode; extern bool grid_default_snap; extern int grid_default_size; extern bool grid_hide_in_free_mode; extern bool grid_snap_indicator; extern int grid_ratio_high; extern int grid_ratio_low; extern rgb_color_t dotty_axis_col; extern rgb_color_t dotty_major_col; extern rgb_color_t dotty_minor_col; extern rgb_color_t dotty_point_col; extern rgb_color_t normal_axis_col; extern rgb_color_t normal_main_col; extern rgb_color_t normal_flat_col; extern rgb_color_t normal_small_col; extern int backup_max_files; extern int backup_max_space; extern bool browser_small_tex; extern bool browser_combine_tex; extern int floor_bump_small; extern int floor_bump_medium; extern int floor_bump_large; extern int light_bump_small; extern int light_bump_medium; extern int light_bump_large; extern int render_pixel_aspect; extern int render_far_clip; extern bool render_high_detail; extern bool render_lock_gravity; extern bool render_missing_bright; extern bool render_unknown_bright; extern rgb_color_t transparent_col; extern bool bsp_on_save; extern bool bsp_fast; extern bool bsp_warnings; extern int bsp_split_factor; extern bool bsp_gl_nodes; extern bool bsp_force_v5; extern bool bsp_force_zdoom; extern bool bsp_compressed; extern LoadingData preloading; } extern const opt_desc_t options[]; enum class CommandLinePass { early, normal }; /* ==== FUNCTIONS ==================== */ int M_ParseConfigFile(const fs::path &path, const opt_desc_t *options); int M_WriteConfigFile(const fs::path &path, const opt_desc_t *options); void M_ParseEnvironmentVars(); void M_ParseCommandLine(int argc, const char *const *argv, CommandLinePass pass, std::vector &Pwad_list, const opt_desc_t *options); void M_PrintCommandLineOptions(); #endif /* __EUREKA_M_CONFIG_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_editlump.cc000066400000000000000000000265561464327712600210140ustar00rootroot00000000000000//------------------------------------------------------------------------ // TEXT LUMP EDITOR //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2018 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include "w_wad.h" #include "ui_window.h" #define BUTTON_COL FL_YELLOW // special (not real) lump names #define EDLUMP_HEADER "MapHeader" #define EDLUMP_SCRIPTS "MapScripts" // Various lumps that definitely should not be edited as text. // Note: this list is not meant to be exhaustive. static const char *const invalid_text_lumps[] = { // editor stuff EUREKA_LUMP, // map lumps "THINGS", "VERTEXES", "LINEDEFS", "SECTORS", "SIDEDEFS", "SEGS", "SSECTORS", "NODES", "REJECT", "BLOCKMAP", "BEHAVIOR", "SCRIPTS", "TEXTMAP", "ENDMAP", "ZNODES", // various binary lumps "PLAYPAL", "COLORMAP", "TINTTAB", "PNAMES", "TEXTURE1", "TEXTURE2", "GENMIDI", "DMXGUS", "DMXGUSC", "DEMO1", "DEMO2", "DEMO3", "DEMO4", "ENDOOM", "ENDBOOM", // various graphics "HELP", "HELP1", "CREDIT", "CONBACK", "VICTORY", "VICTORY2", "BOSSBACK", "TITLEPIC", "INTERPIC", "ENDPIC", "STBAR", "M_DOOM", "M_EPI1", "M_EPI2", "M_EPI3", "M_EPI4", // source port stuff "TRANMAP", "WATERMAP", "FOGMAP", "ANIMATED", "SWITCHES", "DIALOGUE", "SNDCURVE", "TITLEMAP", "AUTOPAGE", "STARTUP", // the end NULL }; // TODO : ideally put these in an external file static const char *const common_text_lumps[] = { // Hexen (plus source-port variants) "MAPINFO", "ZMAPINFO", "EMAPINFO", // Boom / MBF "DEHACKED", "OPTIONS", // Eternity "MUSINFO", // EDGE "RSCRIPT", // Legacy "S_SKIN", "", // ZDoom and derivatives "DECORATE", "LANGUAGE", "SNDINFO", "ANIMDEFS", "GLDEFS", "SBARINFO", "DECALDEFS", "FONTDEFS", "MODELDEF", // the end NULL }; static bool ValidLumpToEdit(const SString &p) { size_t len = p.length(); if (len == 0 || len > 8) return false; // check known binary lumps for (int i = 0 ; invalid_text_lumps[i] ; i++) if (p.noCaseEqual(invalid_text_lumps[i])) return false; // markers like S_START and FF_END are not allowed if (len >= 4) { size_t startFind = p.findNoCase("_START"); size_t endFind = p.findNoCase("_END"); if(startFind == 1 || endFind == 1 || startFind == 2 || endFind == 2) return false; } // check for bad characters [ p is *invalid* afterwards ] for (const char &c : p) if (! (isalnum(c) || c == '_')) return false; return true; } //------------------------------------------------------------------------ class UI_ChooseTextLump : public UI_Escapable_Window { private: Fl_Input *lump_name; Fl_Group *lump_buttons; Fl_Return_Button *ok_but; enum { ACT_none = 0, ACT_CLOSE, ACT_ACCEPT }; int action; public: explicit UI_ChooseTextLump(MapFormat levelFormat); // returns lump name on success, NULL on cancel SString Run(); private: void CheckInput(); void PopulateButtons(); static void ok_callback(Fl_Widget *, void *); static void close_callback(Fl_Widget *, void *); static void button_callback(Fl_Widget *, void *); static void input_callback(Fl_Widget *, void *); static void header_callback(Fl_Widget *, void *); static void script_callback(Fl_Widget *, void *); }; UI_ChooseTextLump::UI_ChooseTextLump(MapFormat levelFormat) : UI_Escapable_Window(420, 385, "Choose Text Lump"), action(ACT_none) { resizable(NULL); callback(close_callback, this); lump_name = new Fl_Input(170, 20, 120, 25, "Enter lump name: "); lump_name->labelfont(FL_HELVETICA_BOLD); lump_name->when(FL_WHEN_CHANGED); lump_name->callback(input_callback, this); FLFocusOnCreation(lump_name); { Fl_Box* o = new Fl_Box(15, 55, 270, 25, "Or select one of these lumps:"); o->labelfont(FL_HELVETICA_BOLD); o->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); } // all the map buttons go into this group lump_buttons = new Fl_Group(0, 90, w(), 205, ""); lump_buttons->align(FL_ALIGN_TOP | FL_ALIGN_INSIDE); { int mhy = lump_buttons->y() + lump_buttons->h() - 25; Fl_Button *b1 = new Fl_Button(60, mhy, 120, 25, "Map Header"); b1->callback(header_callback, this); b1->color(BUTTON_COL); Fl_Button *b2 = new Fl_Button(230, mhy, 120, 25, "Map Scripts"); b2->callback(script_callback, this); if (levelFormat == MapFormat::hexen) b2->color(BUTTON_COL); else b2->deactivate(); PopulateButtons(); } lump_buttons->end(); { int bottom_y = 320; Fl_Group* o = new Fl_Group(0, bottom_y, 420, 65); o->box(FL_FLAT_BOX); o->color(WINDOW_BG, WINDOW_BG); ok_but = new Fl_Return_Button(260, bottom_y + 17, 100, 35, "OK"); ok_but->labelfont(FL_HELVETICA_BOLD); ok_but->callback(ok_callback, this); ok_but->deactivate(); Fl_Button *cancel = new Fl_Button(75, bottom_y + 17, 100, 35, "Cancel"); cancel->callback(close_callback, this); o->end(); } end(); } void UI_ChooseTextLump::PopulateButtons() { int col = 0; int row = 0; int but_W = 100; for (int i = 0 ; common_text_lumps[i] ; i++) { const char *name = common_text_lumps[i]; if (name[0] != 0) { int bx = 40 + col * (but_W + 20); int by = lump_buttons->y() + row * 25; if (row >= 3) by += 15; Fl_Button *but = new Fl_Button(bx, by, but_W, 20, name); but->color(BUTTON_COL); but->callback(button_callback, this); // NOTE: no need to add() it } col++; if (col >= 3) { col = 0; row += 1; } } } void UI_ChooseTextLump::close_callback(Fl_Widget *w, void *data) { UI_ChooseTextLump *win = (UI_ChooseTextLump *)data; win->action = ACT_CLOSE; } void UI_ChooseTextLump::ok_callback(Fl_Widget *w, void *data) { UI_ChooseTextLump * win = (UI_ChooseTextLump *)data; // sanity check if (ValidLumpToEdit(win->lump_name->value())) win->action = ACT_ACCEPT; else fl_beep(); } void UI_ChooseTextLump::input_callback(Fl_Widget *w, void *data) { UI_ChooseTextLump *win = (UI_ChooseTextLump *)data; win->CheckInput(); } void UI_ChooseTextLump::CheckInput() { bool was_valid = ok_but->active(); bool is_valid = ValidLumpToEdit(lump_name->value()); if (was_valid == is_valid) return; if (is_valid) { ok_but->activate(); lump_name->textcolor(FL_FOREGROUND_COLOR); } else { ok_but->deactivate(); lump_name->textcolor(FL_RED); } lump_name->redraw(); } void UI_ChooseTextLump::header_callback(Fl_Widget *w, void *data) { UI_ChooseTextLump *win = (UI_ChooseTextLump *)data; win->lump_name->value(EDLUMP_HEADER); win->action = ACT_ACCEPT; } void UI_ChooseTextLump::script_callback(Fl_Widget *w, void *data) { UI_ChooseTextLump *win = (UI_ChooseTextLump *)data; win->lump_name->value(EDLUMP_SCRIPTS); win->action = ACT_ACCEPT; } void UI_ChooseTextLump::button_callback(Fl_Widget *w, void *data) { Fl_Button *but = (Fl_Button *)w; UI_ChooseTextLump *win = (UI_ChooseTextLump *)data; // the button's label is the lump name win->lump_name->value(but->label()); win->action = ACT_ACCEPT; } SString UI_ChooseTextLump::Run() { set_modal(); show(); while (action == ACT_none) { Fl::wait(0.2); } if (action == ACT_CLOSE) return ""; const char *name = lump_name->value(); if (name[0] == 0) return ""; // return a copy of the name return name; } //------------------------------------------------------------------------ void Instance::CMD_EditLump() { SString lump_name = EXEC_Param[0]; if (Exec_HasFlag("/header")) { lump_name = EDLUMP_HEADER; } else if (Exec_HasFlag("/scripts")) { lump_name = EDLUMP_SCRIPTS; } if (lump_name[0] == 0 || lump_name[0] == '/') { // ask for the lump name lump_name = UI_ChooseTextLump(loaded.levelFormat).Run(); if (lump_name.empty()) return; // check if user typed name of current level if (lump_name.noCaseEqual(loaded.levelName)) lump_name = EDLUMP_HEADER; } // NOTE: there are two special cases for lump_name: // (1) EDLUMP_HEADER --> edit the HeaderData buffer // (2) EDLUMP_SCRIPTS --> edit the ScriptsData buffer bool special = lump_name == EDLUMP_HEADER || lump_name == EDLUMP_SCRIPTS; // uppercase the lump name // [ another small memory leak ] if (!special) lump_name = lump_name.asUpper(); // only create a per-level SCRIPTS lump in a Hexen map // [ the UI_ChooseTextLump already prevents this, but we need to // handle the /scripts option of the EditLump command ] if (lump_name == EDLUMP_SCRIPTS && loaded.levelFormat != MapFormat::hexen) { DLG_Notify("A per-level SCRIPTS lump can only be created " "on a Hexen format map."); return; } if (!special && !ValidLumpToEdit(lump_name)) { Beep("Invalid lump: '%s'", lump_name.c_str()); return; } Wad_file* wad = this->wad.master.activeWad().get(); // create the editor window UI_TextEditor editor(*this); if (!this->wad.master.editWad() || this->wad.master.editWad()->IsReadOnly()) editor.SetReadOnly(); // if lump exists, load the contents if (lump_name == EDLUMP_HEADER) { editor.LoadMemory(level.headerData); editor.SetTitle(loaded.levelName); } else if (lump_name == EDLUMP_SCRIPTS) { editor.LoadMemory(level.scriptsData); editor.SetTitle("SCRIPTS"); } else { if (!editor.LoadLump(wad, lump_name)) { // something went wrong return; } editor.SetTitle(lump_name); } // run the text editor for (;;) { int res = editor.Run(); if (res != UI_TextEditor::RUN_Save) break; SYS_ASSERT(wad == this->wad.master.editWad().get()); if (lump_name == EDLUMP_HEADER) { editor.SaveMemory(level.headerData); level.MadeChanges = true; } else if (lump_name == EDLUMP_SCRIPTS) { editor.SaveMemory(level.scriptsData); level.MadeChanges = true; } else { editor.SaveLump(wad, lump_name); } } } //------------------------------------------------------------------------ void Instance::CMD_AddBehaviorLump() { if (loaded.levelFormat != MapFormat::hexen) { DLG_Notify("A BEHAVIOR lump can only be added to a Hexen format map."); return; } Fl_Native_File_Chooser chooser; chooser.title("Pick bytecode file to insert"); chooser.type(Fl_Native_File_Chooser::BROWSE_FILE); chooser.directory(Main_FileOpFolder().u8string().c_str()); switch (chooser.show()) { case -1: DLG_Notify("Unable to open the file:\n\n%s", chooser.errmsg()); return; case 1: // cancelled return; default: // Ok break; } SString filename = chooser.filename(); std::vector data; bool success = FileLoad(filename.get(), data); if (! success) { DLG_Notify("Read error while loading file."); return; } if (data.size() < 24 || data[0] != 'A' || data[1] != 'C' || data[2] != 'S') { const char *reason = "bad header marker"; if (data.empty()) reason = "file is empty"; else if (data.size() < 24) reason = "file is too short / truncated"; DLG_Notify("This file is not valid ACS bytecode.\n(%s)", reason); return; } level.behaviorData = std::move(data); level.MadeChanges = true; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_events.cc000066400000000000000000000454561464327712600204750ustar00rootroot00000000000000//------------------------------------------------------------------------ // EVENT HANDLING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2018 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "m_events.h" #include "e_main.h" #include "e_hover.h" #include "Errors.h" #include "Instance.h" #include "m_parse.h" #include "m_streams.h" #include "main.h" #include "r_render.h" #include "ui_window.h" #include "ui_misc.h" void Instance::ClearStickyMod() { if (edit.sticky_mod) Status_Clear(); edit.sticky_mod = 0; } void Instance::Editor_ClearAction() noexcept { switch (edit.action) { case EditorAction::nothing: return; case EditorAction::adjustOfs: main_win->SetCursor(FL_CURSOR_DEFAULT); break; default: /* no special for the rest */ break; } edit.action = EditorAction::nothing; } void Instance::Editor_SetAction(EditorAction new_action) { Editor_ClearAction(); edit.action = new_action; switch (edit.action) { case EditorAction::nothing: return; case EditorAction::adjustOfs: mouse_last_pos.x = Fl::event_x(); mouse_last_pos.y = Fl::event_y(); main_win->SetCursor(FL_CURSOR_HAND); break; default: /* no special for the rest */ break; } } void Instance::Editor_Zoom(int delta, v2int_t mid) { float S1 = static_cast(grid.getScale()); grid.AdjustScale(delta); grid.RefocusZoom(v2double_t(mid), S1); } // this is only used for mouse scrolling void Instance::Editor_ScrollMap(int mode, v2int_t dpos, keycode_t mod) { // started? if (mode < 0) { edit.is_panning = true; main_win->SetCursor(FL_CURSOR_HAND); return; } // finished? if (mode > 0) { edit.is_panning = false; main_win->SetCursor(FL_CURSOR_DEFAULT); return; } if (! edit.panning_lax) mod = 0; if (!dpos) return; if (edit.render3d) { Render3D_ScrollMap(*this, dpos, mod); } else { float speed = static_cast(edit.panning_speed / grid.getScale()); v2double_t delta = { ((double) -dpos.x * speed), ((double) dpos.y * speed) }; grid.Scroll(delta); } } void Instance::Navigate2D() { float delay_ms = static_cast(Nav_TimeDiff()); delay_ms = delay_ms / 1000.0f; keycode_t mod = 0; if (edit.nav.lax) mod = M_ReadLaxModifiers(); float mod_factor = 1.0; if (mod & EMOD_SHIFT) mod_factor = 0.5; if (mod & EMOD_COMMAND) mod_factor = 2.0; if (edit.nav.left || edit.nav.right || edit.nav.up || edit.nav.down) { v2double_t delta = { edit.nav.right - edit.nav.left, edit.nav.up - edit.nav.down }; delta *= static_cast(mod_factor) * delay_ms; grid.Scroll(delta); } RedrawMap(); } void Instance::Nav_Clear() { edit.clearNav(); memset(nav_actives, 0, sizeof(nav_actives)); edit.is_navigating = false; } void Instance::Nav_Navigate() { if (edit.render3d) Render3D_Navigate(); else Navigate2D(); } bool Instance::Nav_SetKey(keycode_t key, nav_release_func_t func) { // when starting a navigation, grab the current time if (! edit.is_navigating) Nav_TimeDiff(); keycode_t lax_mod = 0; edit.nav.lax = Exec_HasFlag("/LAX"); if (edit.nav.lax) lax_mod = EMOD_SHIFT | EMOD_COMMAND; edit.is_navigating = true; int free_slot = -1; for (int i = 0 ; i < MAX_NAV_ACTIVE_KEYS ; i++) { nav_active_key_t& N = nav_actives[i]; if (! N.key) { if (free_slot < 0) free_slot = i; continue; } // already active? if ((N.key | N.lax_mod) == (key | N.lax_mod) && N.release == func) return false; // if it's the same physical key, release the previous action if ((N.key & FL_KEY_MASK) == (key & FL_KEY_MASK)) { (this->*N.release)(); N.key = 0; } } if (free_slot >= 0) { nav_active_key_t& N = nav_actives[free_slot]; N.key = key; N.release = func; N.lax_mod = lax_mod; } return true; } bool Instance::Nav_ActionKey(keycode_t key, nav_release_func_t func) { keycode_t lax_mod = 0; if (Exec_HasFlag("/LAX")) lax_mod = EMOD_SHIFT | EMOD_COMMAND; nav_active_key_t& N = cur_action_key; if (N.key) { // already active? if ((N.key | N.lax_mod) == (key | N.lax_mod) && N.release == func) return false; // release the existing action (this->*N.release)(); } N.key = key; N.release = func; N.lax_mod = lax_mod; return true; } static inline bool CheckKeyPressed(nav_active_key_t& N) { #if 0 // IGNORE MODIFIER CHANGES keycode_t mod = N.key & EMOD_ALL_MASK; // grab current modifiers, but simplify to a single one keycode_t cur_mod = M_TranslateKey(0, Fl::event_state()); if ((mod | N.lax_mod) != (cur_mod | N.lax_mod)) return false; #endif keycode_t base = N.key & FL_KEY_MASK; if (is_mouse_button(base)) { if (Fl::event_buttons() & FL_BUTTON(base - FL_Button)) return true; } else if (is_mouse_wheel(base)) { return false; } else // key on keyboard { if (Fl::event_key(base)) return true; } return false; } static void Nav_UpdateActionKey(Instance &inst) { nav_active_key_t& N = inst.cur_action_key; if (! N.key) return; if (! CheckKeyPressed(N)) { (inst.*N.release)(); N.key = 0; } } static void Nav_UpdateKeys(Instance &inst) { // ensure the currently active keys are still pressed // [ call this after getting each keyboard event from FLTK ] Nav_UpdateActionKey(inst); if (! inst.edit.is_navigating) return; // we rebuilt this value inst.edit.is_navigating = false; for (int i = 0 ; i < MAX_NAV_ACTIVE_KEYS ; i++) { nav_active_key_t& N = inst.nav_actives[i]; if (! N.key) continue; if (! CheckKeyPressed(N)) { // call release function, clear the slot (inst.*N.release)(); N.key = 0; continue; } // at least one navigation key is still active inst.edit.is_navigating = true; } } // returns number of milliseconds since the previous call unsigned int Instance::Nav_TimeDiff() { unsigned int old_time = nav_time; nav_time = TimeGetMillies(); // handle overflow if (nav_time < old_time) return 10; unsigned int diff = (nav_time - old_time); // clamp large values if (diff > 250) diff = 250; return diff; } //------------------------------------------------------------------------ // EVENT HANDLING //------------------------------------------------------------------------ void Instance::EV_EnterWindow() { if (!global::app_has_focus) { edit.pointer_in_window = false; return; } edit.pointer_in_window = true; main_win->canvas->PointerPos(true /* in_event */); // restore keyboard focus to the canvas Fl_Widget * foc = main_win->canvas; if (Fl::focus() != foc) foc->take_focus(); RedrawMap(); } void Instance::EV_LeaveWindow() { // ignore FL_LEAVE event when doing a popup operation menu, // otherwise we lose the highlight and kill drawing mode. if (in_operation_menu) return; edit.pointer_in_window = false; // this offers a handy way to get out of drawing mode if (edit.action == EditorAction::drawLine) Editor_ClearAction(); // this will update (disable) any current highlight RedrawMap(); } void Instance::EV_EscapeKey() { Nav_Clear(); ClearStickyMod(); Editor_ClearAction(); Status_Clear(); edit.clicked.clear(); edit.dragged.clear(); edit.split_line.clear(); edit.drawLine.from.clear(); UpdateHighlight(); RedrawMap(); } void Instance::EV_MouseMotion(v2int_t pos, keycode_t mod, v2int_t dpos) { // this is probably redundant, as we generally shouldn't get here // unless the mouse is in the 2D/3D view (or began a drag there). edit.pointer_in_window = true; main_win->canvas->PointerPos(true /* in_event */); // fprintf(stderr, "MOUSE MOTION: (%d %d) map: (%1.2f %1.2f)\n", x, y, inst.edit.map_x, inst.edit.map_y); if (edit.is_panning) { Editor_ScrollMap(0, dpos, mod); return; } main_win->info_bar->SetMouse(); if (edit.action == EditorAction::transform) { Transform_Update(); return; } if (edit.action == EditorAction::drawLine) { // this calls UpdateHighlight() which updates inst.edit.draw_to_x/y RedrawMap(); return; } if (edit.action == EditorAction::selbox) { edit.selbox2 = edit.map.xy; main_win->canvas->redraw(); return; } if (edit.action == EditorAction::drag) { edit.drag_screen_dpos = pos - edit.click_screen_pos; edit.drag_cur.xy = edit.map.xy; // if dragging a single vertex, update the possible split_line. // Note: ratio-lock is handled in UI_Canvas::DragDelta if (edit.mode == ObjType::vertices && edit.dragged.valid()) UpdateHighlight(); main_win->canvas->redraw(); return; } // begin dragging? if (edit.action == EditorAction::click) { CheckBeginDrag(); } // in general, just update the highlight, split-line (etc) UpdateHighlight(); } //------------------------------------------------------------------------ keycode_t M_RawKeyForEvent(int event) { // event must be FL_KEYDOWN, FL_PUSH or FL_MOUSEWHEEL if (event == FL_PUSH) { // convert mouse button to a fake key return FL_Button + Fl::event_button(); } if (event == FL_MOUSEWHEEL) { int dx = Fl::event_dx(); int dy = Fl::event_dy(); // convert wheel direction to a fake key if (abs(dx) > abs(dy)) return dx < 0 ? FL_WheelLeft : FL_WheelRight; return dy < 0 ? FL_WheelUp : FL_WheelDown; } return Fl::event_key(); } keycode_t M_CookedKeyForEvent(int event) { int raw_key = M_RawKeyForEvent(event); int raw_state = Fl::event_state(); return M_TranslateKey(raw_key, raw_state); } keycode_t M_ReadLaxModifiers() { // this is a workaround for X-windows, where we don't get new // modifier state until the event *after* the shift key is // pressed or released. #if defined(WIN32) || defined(__APPLE__) return Fl::event_state() & (EMOD_COMMAND | EMOD_SHIFT); #else /* Linux and X-Windows */ // we only need FLTK to read the true keyboard state *once* // from the X server, which is what this Fl::get_key() is // doing here (with an arbitrary key). Fl::get_key('1'); keycode_t result = 0; if (Fl::event_key(FL_Shift_L) || Fl::event_key(FL_Shift_R)) result |= EMOD_SHIFT; if (Fl::event_key(FL_Control_L) || Fl::event_key(FL_Control_R)) result |= EMOD_COMMAND; return result; #endif } int Instance::EV_RawKey(int event) { Nav_UpdateKeys(*this); if (event == FL_KEYUP || event == FL_RELEASE) return 0; int raw_key = M_RawKeyForEvent(event); int raw_state = Fl::event_state(); int old_sticky_mod = edit.sticky_mod; if (edit.sticky_mod) { raw_state = edit.sticky_mod; ClearStickyMod(); } keycode_t key = M_TranslateKey(raw_key, raw_state); if (key == 0) return 1; #if 0 // DEBUG fprintf(stderr, "Key code: 0x%08x : %s\n", key, M_KeyToString(key).c_str()); #endif // keyboard propagation logic if (main_win->browser->visible() && ExecuteKey(key, KeyContext::browser)) return 1; if (edit.render3d && ExecuteKey(key, KeyContext::render)) return 1; if (ExecuteKey(key, M_ModeToKeyContext(edit.mode))) return 1; if (ExecuteKey(key, KeyContext::general)) return 1; // always eat mouse buttons if (event == FL_PUSH) return 1; // NOTE: the key may still get handled by something (e.g. Menus) // fprintf(stderr, "Unknown key %d (0x%04x)\n", key, key); // prevent a META-fied key from being sent elsewhere, because it // won't really be META-fied anywhere else -- including the case // of it being sent back to this function as a SHORTCUT event. return old_sticky_mod ? 1 : 0; } int Instance::EV_RawWheel(int event) { ClearStickyMod(); // ensure we zoom from correct place main_win->canvas->PointerPos(true /* in_event */); wheel_dpos.x = Fl::event_dx(); wheel_dpos.y = Fl::event_dy(); if (!wheel_dpos) return 1; EV_RawKey(FL_MOUSEWHEEL); return 1; } int Instance::EV_RawButton(int event) { ClearStickyMod(); main_win->canvas->PointerPos(true /* in_event */); // Hack Alert : this is required to support pressing two buttons at the // same time. Without this, FLTK does not send us the second button // release event, because when the first button is released the "pushed" // widget becomes NULL. if (Fl::event_buttons() != 0) Fl::pushed(main_win->canvas); int button = Fl::event_button(); if (button < 1 || button > 8) return 0; return EV_RawKey(event); } int Instance::EV_RawMouse(int event) { if (!global::app_has_focus) return 1; int mod = Fl::event_state() & EMOD_ALL_MASK; v2int_t dpos = { Fl::event_x() - mouse_last_pos.x, Fl::event_y() - mouse_last_pos.y }; if (edit.render3d) { Render3D_MouseMotion({ Fl::event_x(), Fl::event_y() }, mod, dpos); } else { EV_MouseMotion({ Fl::event_x(), Fl::event_y() }, mod, dpos); } mouse_last_pos.x = Fl::event_x(); mouse_last_pos.y = Fl::event_y(); return 1; } int Instance::EV_HandleEvent(int event) { //// fprintf(stderr, "HANDLE EVENT %d\n", event); switch (event) { case FL_FOCUS: return 1; case FL_ENTER: EV_EnterWindow(); return 1; case FL_LEAVE: EV_LeaveWindow(); return 1; case FL_KEYDOWN: case FL_KEYUP: case FL_SHORTCUT: return EV_RawKey(event); case FL_PUSH: case FL_RELEASE: return EV_RawButton(event); case FL_MOUSEWHEEL: return EV_RawWheel(event); case FL_DRAG: case FL_MOVE: return EV_RawMouse(event); default: // pass on everything else break; } return 0; } //------------------------------------------------------------------------ // OPERATION MENU(S) //------------------------------------------------------------------------ struct operation_command_t { const editor_command_t *cmd = nullptr; SString param[MAX_EXEC_PARAM]; }; static void ParseOperationLine(const std::vector &tokens, Fl_Menu_Button *menu) { // just a divider? if (tokens[0].noCaseEqual("divider")) { menu->add("", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE); return; } // parse the key int shortcut = 0; if (!tokens[0].noCaseEqual("UNBOUND")) { keycode_t key = M_ParseKeyString(tokens[0]); if (key != 0) shortcut = M_KeyToShortcut(key); } // parse the command and its parameters... if (tokens.size() < 2) ThrowException("operations.cfg: entry missing description.\n"); if (tokens.size() < 3) ThrowException("operations.cfg: entry missing command name.\n"); const editor_command_t *cmd = FindEditorCommand(tokens[2]); if (! cmd) { gLog.printf("operations.cfg: unknown function: %s\n", tokens[2].c_str()); return; } operation_command_t * info = new operation_command_t; info->cmd = cmd; for (int p = 0 ; p < MAX_EXEC_PARAM ; p++) if ((int)tokens.size() >= 4 + p) info->param[p] = tokens[3 + p]; menu->add(tokens[1].c_str(), shortcut, 0 /* callback */, (void *)info, 0 /* flags */); } void Instance::M_AddOperationMenu(const SString &context, Fl_Menu_Button *menu) { if (menu->size() < 2) { ThrowException("operations.cfg: no %s items.\n", context.c_str()); return; } // enable the menu // this is quite hacky, use button 7 as the trigger button(s) since // we don't actually want mouse buttons to directly open it, rather // we want to open it explictly by our own code. menu->type(0x40); // the boxtype MUST be FL_NO_BOX menu->box(FL_NO_BOX); menu->textsize(16); // NOTE: we cannot show() this menu, as that will interfere with // mouse motion events [ canvas will get FL_LEAVE when the mouse // enters this menu's bbox ] menu->hide(); op_all_menus[context] = menu; main_win->add(menu); } #define MAX_TOKENS 30 bool Instance::M_ParseOperationFile() { // open the file and build all the menus it contains. // look in user's $HOME directory first fs::path filename = global::home_dir / "operations.cfg"; LineFile file(filename); // otherwise load it from the installation directory if (! file.isOpen()) { filename = global::install_dir / "operations.cfg"; file.open(filename); } if (! file.isOpen()) return false; // parse each line SString line; std::vector tokens; Fl_Menu_Button *menu = NULL; SString context; while (file.readLine(line)) { int num_tok = M_ParseLine(line, tokens, ParseOptions::haveStrings); if (num_tok == 0) continue; if (num_tok < 0) { gLog.printf("operations.cfg: failed parsing a line\n"); continue; } if (tokens[0].noCaseEqual("menu")) { if (num_tok < 3) { gLog.printf("operations.cfg: bad menu line\n"); continue; } if (menu != NULL) M_AddOperationMenu(context, menu); // create new menu menu = new Fl_Menu_Button(0, 0, 99, 99, ""); menu->copy_label(tokens[2].c_str()); menu->clear(); context = tokens[1]; continue; } if (menu != NULL) ParseOperationLine(tokens, menu); } file.close(); if (menu != NULL) M_AddOperationMenu(context, menu); return true; } void Instance::M_LoadOperationMenus() { gLog.printf("Loading Operation menus...\n"); if (! M_ParseOperationFile()) { no_operation_cfg = true; DLG_Notify("Installation problem: cannot find \"operations.cfg\" file!"); } } void Instance::CMD_OperationMenu() { if (no_operation_cfg) return; SString context = EXEC_Param[0]; // if no context given, pick one based on editing mode if (context.empty()) { if (edit.render3d) { context = "render"; } else { switch (edit.mode) { case ObjType::linedefs: context = "line"; break; case ObjType::sectors: context = "sector"; break; case ObjType::vertices: context = "vertex"; break; default: context = "thing"; } } } Fl_Menu_Button *menu = op_all_menus[context]; if (menu == NULL) { Beep("no such menu: %s", context.c_str()); return; } SYS_ASSERT(menu); // forget the last chosen command in this menu, otherwise FLTK // positions the menu to point at that item, which can be annoying // especially if the last command was destructive. menu->value((const Fl_Menu_Item *)NULL); // the pop-up menu will cause an FL_LEAVE event on the canvas, // which we need to ignore to prevent forgetting the current // highlight or killing line drawing mode. in_operation_menu = true; const Fl_Menu_Item *item = menu->popup(); in_operation_menu = false; if (item) { operation_command_t *info = (operation_command_t *)item->user_data(); SYS_ASSERT(info); ExecuteCommand(info->cmd, info->param[0], info->param[1], info->param[2], info->param[3]); } } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_events.h000066400000000000000000000042241464327712600203230ustar00rootroot00000000000000//------------------------------------------------------------------------ // EVENT HANDLING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_M_EVENTS_H__ #define __EUREKA_M_EVENTS_H__ #include "m_keys.h" #define MAX_NAV_ACTIVE_KEYS 20 enum class EditorAction { nothing, click, // user has clicked on something selbox, // user is outlining a selection box drag, // user is dragging some objects transform, // user is scaling/rotating some objects adjustOfs, // user is adjusting the offsets on a sidedef drawLine, // user is drawing a new line }; typedef void (Instance:: *nav_release_func_t)(); struct nav_active_key_t { // key or button code, including any modifier. // zero when this slot is unused. keycode_t key; // function to call when user releases the key or button. nav_release_func_t release; // modifiers that can change state without a keypress // being considered as a new command. keycode_t lax_mod; }; void Editor_UpdateFromScroll(); /* raw input handling */ keycode_t M_RawKeyForEvent(int event); keycode_t M_CookedKeyForEvent(int event); keycode_t M_ReadLaxModifiers(); #endif /* __EUREKA_M_EVENTS_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_files.cc000066400000000000000000000545141464327712600202660ustar00rootroot00000000000000//------------------------------------------------------------------------ // RECENT FILES / KNOWN IWADS / BACKUPS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2018 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include "m_config.h" #include "m_files.h" #include "m_game.h" #include "m_loadsave.h" #include "m_parse.h" #include "m_streams.h" #include "m_testmap.h" #include "w_wad.h" #include "ui_window.h" #include "filesystem.hpp" namespace fs = ghc::filesystem; // list of known iwads (mapping GAME name --> PATH) void RecentKnowledge::addIWAD(const fs::path &path) { fs::path absolute_name = fs::absolute(path); const SString &game = GameNameFromIWAD(path); known_iwads[game] = absolute_name; } // returns a string, with each name separated by a '|' character, // hence directly usable with the FL_Choice::add() method. // SString RecentKnowledge::collectGamesForMenu(int *exist_val, const char *exist_name) const { std::map::const_iterator KI; SString result; result.reserve(2000); int index = 0; for (KI = known_iwads.begin() ; KI != known_iwads.end() ; KI++, index++) { const SString &name = KI->first; if (result[0]) result += '|'; result += name; if (name.noCaseEqual(exist_name)) *exist_val = index; } return result; } void RecentKnowledge::writeKnownIWADs(std::ostream &os) const { std::map::const_iterator KI; for (KI = known_iwads.begin() ; KI != known_iwads.end() ; KI++) { os << "known_iwad " << KI->first.spaceEscape() << " " << escape(KI->second) << std::endl; } } void M_ValidateGivenFiles() { for (const fs::path &pwad : global::Pwad_list) { if (! Wad_file::Validate(pwad)) ThrowException("Given pwad does not exist or is invalid: %s\n", pwad.u8string().c_str()); } } int M_FindGivenFile(const fs::path &filename) { for (int i = 0 ; i < (int)global::Pwad_list.size() ; i++) if (global::Pwad_list[i] == filename) return i; return -1; // Not Found } //------------------------------------------------------------------------ // PORT PATH HANDLING //------------------------------------------------------------------------ // // Parse port path // void RecentKnowledge::parsePortPath(const SString &name, const SString &cpath) { SString path(cpath); path.trimLeadingSpaces(); size_t pos = path.find('|'); if(pos == std::string::npos) { // TODO : Warn return; } // terminate arguments path.erase(0, pos + 1); setPortPath(name, fs::u8path(path.get())); if(gInstance && gInstance->main_win) testmap::updateMenuName(gInstance->main_win->menu_bar, gInstance->loaded); // parse any other arguments // [ none needed atm.... ] } void RecentKnowledge::writePortPaths(std::ostream &os) const { std::map::const_iterator IT; for (IT = port_paths.begin() ; IT != port_paths.end() ; IT++) { const fs::path& info = IT->second; os << "port_path " << IT->first.spaceEscape() << " |" << escape(info) << std::endl; } } // Recent files RecentFiles_c::Deque::iterator RecentFiles_c::find(const fs::path &file) { // ignore the path when matching filenames SString A = file.filename().u8string(); for(auto it = list.begin(); it != list.end(); ++it) { SString B = it->file.filename().u8string(); if(!A.noCaseEqual(B)) continue; return it; } return list.end(); // not found } void RecentFiles_c::push_front(const fs::path &file, const SString &map) { if(list.size() >= MAX_RECENT) { list.pop_back(); } list.push_front({file, map}); } void RecentFiles_c::insert(const fs::path &file, const SString &map) { // ensure filename (without any path) is unique auto it = find(file); if(it != list.end()) list.erase(it); push_front(file, map); } void RecentFiles_c::Write(std::ostream &stream) const { // file is in opposite order, newest at the end // (this allows the parser to merely insert() items in the // order they are read). for(auto it = list.rbegin(); it != list.rend(); ++it) stream << "recent " << it->map.spaceEscape() << " " << escape(it->file) << std::endl; } SString RecentFiles_c::Format(int index) const { SYS_ASSERT(index < (int)list.size()); SString name = list[index].file.filename().u8string(); return SString::printf("%s%s%d: %-.42s", (index < 9) ? " " : "", (index < 9) ? "&" : "", 1 + index, name.c_str()); } const RecentMap &RecentFiles_c::Lookup(int index) const { SYS_ASSERT(index >= 0); SYS_ASSERT(index < (int)list.size()); return list[index]; } namespace global { RecentKnowledge recent; } // // Parse miscellaneous config // void RecentKnowledge::parseMiscConfig(std::istream &is) { SString line; while(M_ReadTextLine(line, is)) { SString keyword; TokenWordParse parse(line, true); if(!parse.getNext(keyword)) continue; // blank line if(keyword == "recent") { SString map; fs::path path; if(!parse.getNext(map)) { gLog.printf("Expected map name after 'recent' in recents config\n"); continue; } if(!parse.getNext(path)) { gLog.printf("Expected WAD path as second arg in 'recent' in recents config\n"); continue; } if(Wad_file::Validate(path)) files.insert(path, map); else gLog.printf(" no longer exists: %s\n", path.u8string().c_str()); } else if(keyword == "known_iwad") { SString name; fs::path path; if(!parse.getNext(name)) { gLog.printf("Expected IWAD name after 'known_iwad' in recents config\n"); continue; } if(!parse.getNext(path)) { gLog.printf("Expected WAD path as second arg in 'known_iwad' in recents config\n"); continue; } // ignore plain freedoom.wad (backwards compatibility) if(name.noCaseEqual("freedoom")) gLog.printf(" ignoring for compatibility: %s\n", path.u8string().c_str()); else if(Wad_file::Validate(path)) known_iwads[name] = path; else gLog.printf(" no longer exists: %s\n", path.u8string().c_str()); } else if(keyword == "port_path") { SString name, barpath, path; if(!parse.getNext(name)) { gLog.printf("Expected port name after 'port_path' in recents config\n"); continue; } if(!parse.getNext(barpath)) { gLog.printf("Expected | followed by port path after port name\n"); continue; } if(parse.getNext(path)) // allow space after | barpath += path; parsePortPath(name, barpath); } else gLog.printf("Unknown keyword '%s' in recents config\n", keyword.c_str()); } } void RecentKnowledge::load(const fs::path &home_dir) { fs::path filename = home_dir / "misc.cfg"; std::ifstream is(filename); if(!is.is_open()) { gLog.printf("No recent list at: %s\n", filename.u8string().c_str()); return; } gLog.printf("Reading recent list from: %s\n", filename.u8string().c_str()); files.clear(); known_iwads.clear(); port_paths.clear(); parseMiscConfig(is); } void RecentKnowledge::save(const fs::path &home_dir) const { fs::path filename = home_dir / "misc.cfg"; std::ofstream os(filename, std::ios::trunc); if(!os.is_open()) { gLog.printf("Failed to save recent list to: %s\n", filename.u8string().c_str()); return; } gLog.printf("Writing recent list to: %s\n", filename.u8string().c_str()); os << "# Eureka miscellaneous stuff" << std::endl; files.Write(os); writeKnownIWADs(os); writePortPaths(os); } void M_OpenRecentFromMenu(void *priv_data) { SYS_ASSERT(priv_data); RecentMap *data = (RecentMap *)priv_data; try { OpenFileMap(data->file, data->map); } catch (const std::runtime_error& e) { DLG_ShowError(false, "Could not open %s of %s: %s", data->map.c_str(), data->file.u8string().c_str(), e.what()); } } void RecentKnowledge::addRecent(const fs::path &filename, const SString &map_name, const fs::path &home_dir) { files.insert(GetAbsolutePath(filename), map_name); save(home_dir); // why wait? } bool Instance::M_TryOpenMostRecent() { if (global::recent.getFiles().getSize() == 0) return false; RecentMap recentMap = global::recent.getFiles().Lookup(0); // M_LoadRecent has already validated the filename, so this should // normally work. std::shared_ptr wad = Wad_file::loadFromFile(recentMap.file); if (! wad) { gLog.printf("Failed to load most recent pwad: %s\n", recentMap.file.u8string().c_str()); return false; } // make sure at least one level can be loaded if (wad->LevelCount() == 0) { gLog.printf("No levels in most recent pwad: %s\n", recentMap.file.u8string().c_str()); return false; } /* -- OK -- */ if (wad->LevelFind(recentMap.map) >= 0) loaded.levelName = recentMap.map; else loaded.levelName.clear(); this->wad.master.ReplaceEditWad(wad); return true; } //------------------------------------------------------------------------ // EUREKA LUMP HANDLING //------------------------------------------------------------------------ #ifdef WIN32 #define PATH_SEPARATOR ';' #else #define PATH_SEPARATOR ':' #endif // // Parses the DOOMWADPATH environment variable content. In it, the ; or : path separator (depending // on system) acts as a strict separator. Everything between two successive ; or : signs is a path. // Beware that this means you can't have a path containing those special characters. // static std::vector parseDoomWadPathEnvVar(const SString &doomwadpath) { std::vector result; size_t pos = 0, curpos = 0; do { pos = doomwadpath.find(PATH_SEPARATOR, curpos); SString entry; if(pos != std::string::npos) { entry = doomwadpath.substr(curpos, pos - curpos); curpos = pos + 1; } else entry = doomwadpath.substr(curpos); result.push_back(fs::u8path(entry.get())); } while(pos != std::string::npos); return result; } static fs::path SearchDirForIWAD(const fs::path &dir_name, const SString &game) { fs::path name = dir_name / fs::u8path((game + ".wad").get()); gLog.debugPrintf(" trying: %s\n", name.u8string().c_str()); if (Wad_file::Validate(name)) return name; // try uppercasing the name, to find e.g. DOOM2.WAD name = dir_name / fs::u8path((game.asUpper() + ".WAD").get()); gLog.debugPrintf(" trying: %s\n", name.u8string().c_str()); if (Wad_file::Validate(name)) return name; return ""; } static fs::path SearchForIWAD(const fs::path &home_dir, const SString &game) { gLog.debugPrintf("Searching for '%s' IWAD\n", game.c_str()); fs::path dir_name; // 1. look in ~/.eureka/iwads first dir_name = home_dir / "iwads"; fs::path path = SearchDirForIWAD(dir_name, game); if (!path.empty()) return path; // 2. look in $DOOMWADPATH const char *doomwadpath = getenv("DOOMWADPATH"); if (doomwadpath) { std::vector paths = parseDoomWadPathEnvVar(doomwadpath); for(const fs::path &wadpath : paths) { path = SearchDirForIWAD(wadpath, game); if(!path.empty()) return path; } } // 3. look in $DOOMWADDIR const char *doomwaddir = getenv("DOOMWADDIR"); if (doomwaddir) { path = SearchDirForIWAD(fs::u8path(doomwaddir), game); if (!path.empty()) return path; } // 4. look in various standard places /* WISH: check the Steam folder(s) for WIN32 */ static const char *standard_iwad_places[] = { #ifdef WIN32 "c:/doom", "c:/doom2", "c:/doom95", #else "/usr/share/games/doom", "/usr/share/doom", "/usr/local/share/games/doom", "/usr/local/games/doom", #endif NULL }; for (int i = 0 ; standard_iwad_places[i] ; i++) { path = SearchDirForIWAD(standard_iwad_places[i], game); if (!path.empty()) return path; } // 5. last resort : the current directory path = SearchDirForIWAD(".", game); if (!path.empty()) return path; return ""; // not found } // // search for iwads in various places // void RecentKnowledge::lookForIWADs(const fs::path &install_dir, const fs::path &home_dir) { gLog.printf("Looking for IWADs....\n"); std::vector game_list = M_CollectKnownDefs({install_dir, home_dir}, "games"); for (const SString &game : game_list) { // already have it? if (queryIWAD(game)) continue; fs::path path = SearchForIWAD(home_dir, game); if (!path.empty()) { gLog.printf("Found '%s' IWAD file: %s\n", game.c_str(), path.u8string().c_str()); addIWAD(path); } } save(home_dir); } fs::path Instance::M_PickDefaultIWAD() const { // guess either DOOM or DOOM 2 based on level names const char *default_game = "doom2"; if (!loaded.levelName.empty() && toupper(loaded.levelName[0]) == 'E') { default_game = "doom"; } else if (wad.master.editWad()) { int idx = wad.master.editWad()->LevelFindFirst(); if (idx >= 0) { idx = wad.master.editWad()->LevelHeader(idx); const SString &name = wad.master.editWad()->GetLump(idx)->Name(); if (toupper(name[0]) == 'E') default_game = "doom"; } } gLog.debugPrintf("pick default iwad, trying: '%s'\n", default_game); const fs::path *result; result = global::recent.queryIWAD(default_game); if (result) return *result; // try FreeDoom if (strcmp(default_game, "doom") == 0) default_game = "freedoom1"; else default_game = "freedoom2"; gLog.debugPrintf("pick default iwad, trying: '%s'\n", default_game); result = global::recent.queryIWAD(default_game); if (result) return *result; // try any known iwad gLog.debugPrintf("pick default iwad, trying first known iwad...\n"); result = global::recent.getFirstIWAD(); if (result) return *result; // nothing left to try gLog.debugPrintf("pick default iwad failed.\n"); return ""; } static void M_AddResource_Unique(LoadingData &loading, const fs::path & filename) { // check if base filename (without path) already exists for (const fs::path &resource : loading.resourceList) { SString A = filename.filename().u8string(); SString B = resource.filename().u8string(); if(A.noCaseEqual(B)) return; // found it } loading.resourceList.push_back(filename); } // // returns false if user wants to cancel the load // bool LoadingData::parseEurekaLump(const fs::path &home_dir, const fs::path &install_dir, const RecentKnowledge &recent, const Wad_file *wad, bool keep_cmd_line_args) { gLog.printf("Parsing '%s' lump\n", EUREKA_LUMP); const Lump_c * lump = wad->FindLump(EUREKA_LUMP); if (! lump) { gLog.printf("--> does not exist.\n"); return true; } LumpInputStream stream(*lump); const fs::path *new_iwad = nullptr; SString new_port; std::vector new_resources; SString line; tl::optional testingCommandLine; while (stream.readLine(line)) { TokenWordParse parse(line, true); SString key, value; if(!parse.getNext(key)) continue; // empty line if(!parse.getNext(value)) { gLog.printf("WARNING: bad syntax in %s lump\n", EUREKA_LUMP); continue; } if (key == "game") { if (! M_CanLoadDefinitions(home_dir, install_dir, GAMES_DIR, value)) { gLog.printf(" unknown game: %s\n", value.c_str() /* show full path */); int res = DLG_Confirm({ "&Ignore", "&Cancel Load" }, "Warning: the pwad specifies an unsupported " "game:\n\n %s", value.c_str()); if (res == 1) return false; } else { new_iwad = recent.queryIWAD(value); if (!new_iwad) { int res = DLG_Confirm({ "&Ignore", "&Cancel Load" }, "Warning: the pwad specifies an IWAD " "which cannot be found:\n\n %s.wad", value.c_str()); if (res == 1) return false; } } } else if (key == "resource") { fs::path resourcePath = fs::u8path(value.get()); if(resourcePath.is_relative()) { fs::path wadDirPath = wad->PathName().parent_path(); resourcePath = (wadDirPath / resourcePath).lexically_normal(); } // if not found at expected location, try same place as PWAD if (!fs::exists(resourcePath)) { gLog.printf(" file not found: %s\n", resourcePath.u8string().c_str()); fs::path wadDirPath = wad->PathName().parent_path(); resourcePath = wadDirPath / resourcePath.filename(); gLog.printf(" trying: %s\n", resourcePath.u8string().c_str()); } // Still doesn't exist? Try IWAD path, if any if (!fs::exists(resourcePath) && new_iwad) { fs::path wadDirPath = new_iwad->parent_path(); resourcePath = wadDirPath / resourcePath.filename(); gLog.printf(" trying: %s\n", resourcePath.u8string().c_str()); } if (fs::exists(resourcePath)) new_resources.push_back(resourcePath); else { DLG_Notify("Warning: the pwad specifies a resource " "which cannot be found:\n\n%s", value.c_str()); } } else if (key == "port") { if (M_CanLoadDefinitions(home_dir, install_dir, PORTS_DIR, value)) new_port = value; else { gLog.printf(" unknown port: %s\n", value.c_str()); DLG_Notify("Warning: the pwad specifies an unknown port:\n\n%s", value.c_str()); } } else if (key == "testing_command_line") { testingCommandLine = value; } else { gLog.printf("WARNING: unknown keyword '%s' in %s lump\n", key.c_str(), EUREKA_LUMP); continue; } } /* OK */ // When 'keep_cmd_line_args' is true, we do not override any value which // has been set via command line arguments. In other words, cmd line // arguments will override the EUREKA_LUMP. // // Resources are trickier, we merge the EUREKA_LUMP resources into the ones // supplied on the command line, ensuring that we don't get any duplicates. if (new_iwad) { if (! (keep_cmd_line_args && !iwadName.empty())) iwadName = *new_iwad; } if (!new_port.empty()) { if (! (keep_cmd_line_args && !portName.empty())) portName = new_port; } if (testingCommandLine.has_value()) this->testingCommandLine = *testingCommandLine; if (! keep_cmd_line_args) resourceList.clear(); for (const fs::path &resource : new_resources) { M_AddResource_Unique(*this, resource); } return true; } void LoadingData::writeEurekaLump(Wad_file &wad) const { gLog.printf("Writing '%s' lump\n", EUREKA_LUMP); int oldie = wad.FindLumpNum(EUREKA_LUMP); if (oldie >= 0) wad.RemoveLumps(oldie, 1); Lump_c &lump = wad.AddLump(EUREKA_LUMP); lump.Printf("# Eureka project info\n"); if (!gameName.empty()) lump.Printf("game %s\n", gameName.c_str()); lump.Printf("testing_command_line %s\n", testingCommandLine.spaceEscape().c_str()); if (!portName.empty()) lump.Printf("port %s\n", portName.c_str()); fs::path pwadPath = fs::absolute(wad.PathName()).remove_filename(); for (const fs::path &resource : resourceList) { fs::path absoluteResourcePath = fs::absolute(resource); fs::path relative = fs::proximate(absoluteResourcePath, pwadPath); lump.Printf("resource %s\n", escape(relative).c_str()); } } //------------------------------------------------------------------------ // BACKUP SYSTEM //------------------------------------------------------------------------ // config variables int config::backup_max_files = 30; int config::backup_max_space = 60; // MB struct backup_scan_data_t { int low; int high; }; static void backup_scan_file(const fs::path &name, int flags, void *priv_dat) { backup_scan_data_t * data = (backup_scan_data_t *)priv_dat; if (flags & SCAN_F_Hidden) return; if (flags & SCAN_F_IsDir) return; if (! isdigit(name.u8string()[0])) return; int num = atoi(name.u8string()); data->low = std::min(data->low, num); data->high = std::max(data->high, num); } inline static fs::path Backup_Name(const fs::path &dir_name, int slot) { return dir_name / fs::u8path(SString::printf("%d.wad", slot).get()); } static void Backup_Prune(const fs::path &dir_name, int b_low, int b_high, int wad_size) { // Note: the logic here for checking space is very crude, it assumes // all existing backups have the same size as the currrent wad. // do calculations in KB units wad_size = wad_size / 1024 + 1; int backup_num = 2 + config::backup_max_space * 1024 / wad_size; if (backup_num > config::backup_max_files) backup_num = config::backup_max_files; for ( ; b_low <= b_high - backup_num + 1 ; b_low++) { FileDelete(Backup_Name(dir_name, b_low)); } } void M_BackupWad(const Wad_file *wad) { // disabled ? if (config::backup_max_files <= 0 || config::backup_max_space <= 0) return; // convert wad filename to a directory name in $cache_dir/backups fs::path filename = global::cache_dir / "backups" / wad->PathName().filename(); fs::path dir_name = ReplaceExtension(filename, NULL); gLog.debugPrintf("dir_name for backup: '%s'\n", dir_name.u8string().c_str()); // create the directory if it doesn't already exist // (this will fail if it DOES already exist, but that's OK) FileMakeDir(dir_name); // scan directory to determine lowest and highest numbers in use backup_scan_data_t scan_data; scan_data.low = (1 << 30); scan_data.high = 0; if (ScanDirectory(dir_name, backup_scan_file, &scan_data) < 0) { // Hmmm, show a dialog ?? gLog.printf("WARNING: backup failed (cannot scan dir)\n"); return; } int b_low = scan_data.low; int b_high = scan_data.high; // actually back-up the file fs::path dest_name = Backup_Name(dir_name, b_high + 1); bool copiedReadOnly = false; if(wad->IsReadOnly()) { try { fs::copy(wad->PathName(), dest_name); copiedReadOnly = true; } catch(const std::runtime_error &e) { gLog.printf("Failed copying directly %s to %s (%s). Trying to re-save the WAD.\n", wad->PathName().u8string().c_str(), dest_name.u8string().c_str(), e.what()); } } if (!copiedReadOnly && ! wad->Backup(dest_name)) { // Hmmm, show a dialog ?? gLog.printf("WARNING: backup failed (cannot copy file)\n"); return; } // Now do the pruning: if (b_low < b_high) { int wad_size = wad->TotalSize(); Backup_Prune(dir_name, b_low, b_high, wad_size); } gLog.printf("Backed up wad to: %s\n", dest_name.u8string().c_str()); } bool RecentKnowledge::hasIwadByPath(const fs::path &path) const { for(const auto &pair : known_iwads) if(SString(GetAbsolutePath(pair.second).u8string()).noCaseEqual(SString(GetAbsolutePath(path).u8string()))) return true; return false; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_files.h000066400000000000000000000067531464327712600201320ustar00rootroot00000000000000//------------------------------------------------------------------------ // RECENT FILES / KNOWN IWADS / BACKUPS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2013 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_M_FILES_H__ #define __EUREKA_M_FILES_H__ #include "lib_util.h" #include "m_strings.h" #include "sys_type.h" #include #include #include "filesystem.hpp" namespace fs = ghc::filesystem; class Wad_file; //------------------------------------------------------------------------ // RECENT FILE HANDLING //------------------------------------------------------------------------ #define MAX_RECENT 24 // this is for the "File/Recent" menu callbacks struct RecentMap { fs::path file; SString map; }; class RecentFiles_c { private: typedef std::deque Deque; void push_front(const fs::path &file, const SString &map); Deque::iterator find(const fs::path &file); Deque list; public: int getSize() const { return (int)list.size(); } void clear() { list.clear(); } void insert(const fs::path &file, const SString &map); void Write(std::ostream &stream) const; SString Format(int index) const; const RecentMap &Lookup(int index) const; }; // // Holds recently collected knowledge // class RecentKnowledge { public: void load(const fs::path &home_dir); void save(const fs::path &home_dir) const; void addRecent(const fs::path &filename, const SString &map_name, const fs::path &home_dir); const fs::path *queryIWAD(const SString &game) const { return get(known_iwads, game); } void lookForIWADs(const fs::path &install_dir, const fs::path &home_dir); void addIWAD(const fs::path &path); SString collectGamesForMenu(int *exist_val, const char *exist_name) const; const fs::path *getFirstIWAD() const { return known_iwads.empty() ? nullptr : &known_iwads.begin()->second; } // // Query port path // const fs::path *queryPortPath(const SString &name) const { return get(port_paths, name); } // // Changes the port path from name // void setPortPath(const SString &name, const fs::path &path) { port_paths[name] = path; } // // Constant getter of recent files // const RecentFiles_c &getFiles() const { return files; } bool hasIwadByPath(const fs::path &path) const; private: void parseMiscConfig(std::istream &is); void writeKnownIWADs(std::ostream &os) const; void parsePortPath(const SString &name, const SString &cpath); void writePortPaths(std::ostream &os) const; RecentFiles_c files; std::map known_iwads; std::map port_paths; }; void M_OpenRecentFromMenu(void *priv_data); void M_ValidateGivenFiles(); int M_FindGivenFile(const fs::path &filename); void M_BackupWad(const Wad_file *wad); namespace global { extern RecentKnowledge recent; } #endif /* __EUREKA_M_FILES_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_game.cc000066400000000000000000001042141464327712600200660ustar00rootroot00000000000000//------------------------------------------------------------------------ // GAME DEFINITION //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Instance.h" #include "m_parse.h" #include "m_streams.h" #include #define MAX_TOKENS 30 /* tokens per line */ #define UNKNOWN_THING_RADIUS 16 #define UNKNOWN_THING_COLOR fl_rgb_color(0,255,255) namespace global { // all the game and port definitions and previously loaded static std::unordered_map sLoadedGameDefs; static std::map loaded_port_defs; // the information being loaded for PURPOSE_GameInfo / PortInfo // TODO : move into parser_state_c static PortInfo_c loading_Port; } enum class ParsingCondition { none, reading, skipping }; struct parsing_cond_state_t { ParsingCondition cond; int start_line; void Toggle() { cond = (cond == ParsingCondition::reading) ? ParsingCondition::skipping : ParsingCondition::reading; } }; class parser_state_c { public: // the line parsed into tokens int argc = 0; const char * argv[MAX_TOKENS] = {}; // state for handling if/else/endif std::vector cond_stack; // BOOM generalized linedef stuff int current_gen_line = -1; explicit parser_state_c(const fs::path &filename) : fname(filename) { } bool HaveAnySkipping() const { for (size_t i = 0 ; i < cond_stack.size() ; i++) if (cond_stack[i].cond == ParsingCondition::skipping) return true; return false; } const fs::path &file() const { return fname; } bool readLine(LineFile &file) { bool result = file.readLine(readstring); if(result) ++lineno; return result; } void tokenize(); int line() const { return lineno; } void fail(EUR_FORMAT_STRING(const char *format), ...) const EUR_PRINTF(2, 3); private: // filename for error messages (lacks the directory) const fs::path fname; // buffer containing the raw line SString readstring; // current line number int lineno = 0; std::vector args; }; void PortInfo_c::AddSupportedGame(const SString &game) { if (! SupportsGame(game)) supported_games.push_back(game); } bool PortInfo_c::SupportsGame(const SString &game) const { for (const SString &supportedGame : supported_games) if (supportedGame.noCaseEqual(game)) return true; return false; } // // Called only from Main_LoadResources // std::unordered_map LoadingData::prepareConfigVariables() const { std::unordered_map parse_vars; switch (levelFormat) { case MapFormat::doom: parse_vars["$MAP_FORMAT"] = "DOOM"; break; case MapFormat::hexen: parse_vars["$MAP_FORMAT"] = "HEXEN"; break; case MapFormat::udmf: parse_vars["$MAP_FORMAT"] = "UDMF"; break; default: break; } if (!udmfNamespace.empty()) { parse_vars["$UDMF_NAMESPACE"] = udmfNamespace; } if (!gameName.empty()) { parse_vars["$GAME_NAME"] = gameName; if (M_CanLoadDefinitions(global::home_dir, global::install_dir, GAMES_DIR, gameName)) { SString base_game = M_GetBaseGame(gameName); parse_vars["$BASE_GAME"] = base_game; } } if (!portName.empty()) { parse_vars["$PORT_NAME"] = portName; } return parse_vars; } static short ParseThingdefFlags(const char *s) { short flags = 0; if (strchr(s, 'i')) flags |= THINGDEF_INVIS; if (strchr(s, 'c')) flags |= THINGDEF_CEIL; if (strchr(s, 'l')) flags |= THINGDEF_LIT; if (strchr(s, 'n')) flags |= THINGDEF_PASS; if (strchr(s, 'v')) flags |= THINGDEF_VOID; if (strchr(s, 't')) flags |= THINGDEF_TELEPT; if (strchr(s, 'p')) flags |= THINGDEF_POLYSPOT; return flags; } static void ParseColorDef(ConfigData &config, const char ** argv, int argc) { if (y_stricmp(argv[0], "sky") == 0) { config.miscInfo.sky_color = atoi(argv[1]); } else if (y_stricmp(argv[0], "wall") == 0) { config.miscInfo.wall_colors[0] = atoi(argv[1]); config.miscInfo.wall_colors[1] = atoi(argv[(argc < 2) ? 1 : 2]); } else if (y_stricmp(argv[0], "floor") == 0) { config.miscInfo.floor_colors[0] = atoi(argv[1]); config.miscInfo.floor_colors[1] = atoi(argv[(argc < 2) ? 1 : 2]); } else if (y_stricmp(argv[0], "invis") == 0) { config.miscInfo.invis_colors[0] = atoi(argv[1]); config.miscInfo.invis_colors[1] = atoi(argv[(argc < 2) ? 1 : 2]); } else if (y_stricmp(argv[0], "missing") == 0) { config.miscInfo.missing_color = atoi(argv[1]); } else if (y_stricmp(argv[0], "unknown_tex") == 0) { config.miscInfo.unknown_tex = atoi(argv[1]); } else if (y_stricmp(argv[0], "unknown_flat") == 0) { config.miscInfo.unknown_flat = atoi(argv[1]); } else if (y_stricmp(argv[0], "unknown_thing") == 0) { config.miscInfo.unknown_thing = atoi(argv[1]); } else { gLog.printf("unknown color keyword: '%s'\n", argv[0]); } } static map_format_bitset_t ParseMapFormats(parser_state_c *pst, const char ** argv, int argc) { map_format_bitset_t result = 0; for ( ; argc > 0 ; argv++, argc--) { if (y_stricmp(argv[0], "DOOM") == 0) result |= (1 << static_cast(MapFormat::doom)); else if (y_stricmp(argv[0], "HEXEN") == 0) result |= (1 << static_cast(MapFormat::hexen)); else if (y_stricmp(argv[0], "UDMF") == 0) result |= (1 << static_cast(MapFormat::udmf)); else pst->fail("Unknown map format '%s' in definition file.", argv[0]); } return result; } static void ParseClearKeywords(ConfigData &config, const char ** argv, int argc, parser_state_c *pst) { for ( ; argc > 0 ; argv++, argc--) { if (y_stricmp(argv[0], "lines") == 0) { config.line_groups.clear(); config.line_types.clear(); } else if (y_stricmp(argv[0], "sectors") == 0) { config.sector_types.clear(); } else if (y_stricmp(argv[0], "things") == 0) { config.thing_groups.clear(); config.thing_types.clear(); } else if (y_stricmp(argv[0], "textures") == 0) { config.texture_groups.clear(); config.texture_categories.clear(); config.flat_categories.clear(); } else pst->fail("Unknown clear keyword '%s' in definition file.", argv[0]); } } // // Mapping from UGH to value // struct FeatureMapping { const char *const name; int port_features_t::*field; int (*converter)(const char *); }; // // Text // static int GenSectorConvert(const char *text) { if(!y_stricmp(text, "boom")) return static_cast(GenSectorFamily::boom); if(!y_stricmp(text, "zdoom")) return static_cast(GenSectorFamily::zdoom); return static_cast(GenSectorFamily::none); } // // The available feature mappings // static const FeatureMapping skFeatureMappings[] = { #define MAPPING(a) { #a, &port_features_t::a } MAPPING(gen_types), { "gen_sectors", reinterpret_cast(&port_features_t::gen_sectors), GenSectorConvert }, MAPPING(img_png), MAPPING(tx_start), MAPPING(coop_dm_flags), MAPPING(friend_flag), MAPPING(pass_through), { "3d_midtex", &port_features_t::midtex_3d }, MAPPING(strife_flags), MAPPING(medusa_fixed), MAPPING(tuttifrutti_fixed), MAPPING(lax_sprites), MAPPING(no_need_players), { "tag_666", &port_features_t::tag_666raw }, MAPPING(mix_textures_flats), MAPPING(neg_patch_offsets), MAPPING(extra_floors), MAPPING(slopes), #undef MAPPING }; // // Parses features // static void ParseFeatureDef(ConfigData &config, const char **argv, int argc) { bool found = false; for(const FeatureMapping &mapping : skFeatureMappings) if(!y_stricmp(argv[0], mapping.name)) { char *endptr = nullptr; long val = strtol(argv[1], &endptr, 10); if(endptr == argv[1] && mapping.converter) config.features.*mapping.field = mapping.converter(argv[1]); else config.features.*mapping.field = static_cast(val); found = true; break; } if(!found) gLog.printf("unknown feature keyword: '%s'\n", argv[0]); } // // Finds a definition file in a given subpath under either the home or system install folder // Both strings are required // Returns "" if not found. // static tl::optional FindDefinitionFile(const fs::path &home_dir, const fs::path &install_dir, const fs::path &folder, const SString &name) { SYS_ASSERT(!folder.empty() && name.good()); const fs::path lookupDirs[] = { home_dir, install_dir }; for (const fs::path &base_dir : lookupDirs) { if (base_dir.empty()) continue; fs::path filename = base_dir / folder / (name + ".ugh").get(); gLog.debugPrintf(" trying: %s\n", filename.u8string().c_str()); if (FileExists(filename)) return filename; } return {}; } bool M_CanLoadDefinitions(const fs::path &home_dir, const fs::path &install_dir, const fs::path &folder, const SString &name) { tl::optional filename = FindDefinitionFile(home_dir, install_dir, folder, name); return filename.has_value(); } // // Returns true if this is a polyobject source line // bool linetype_t::isPolyObjectSpecial() const { for(const SpecialArg &arg : args) if(arg.type == SpecialArgType::po) return true; return false; } // // Loads a definition file. The ".ugh" extension is added. // Will try the "common" folder if not found in the given one. // // Examples: "games" + "doom2" // "ports" + "edge" // void readConfiguration(std::unordered_map &parse_vars, const fs::path &folder, const SString &name, ConfigData &config) noexcept(false) { // this is for error messages & debugging fs::path prettyname = folder / fs::u8path((name + ".ugh").get()); gLog.printf("Loading Definitions : %s\n", prettyname.u8string().c_str()); tl::optional filename = FindDefinitionFile(global::home_dir, global::install_dir, folder, name); if (!filename) { throw ParseException(SString::printf("Cannot find definition file: %s", prettyname.u8string().c_str())); } gLog.debugPrintf(" found at: %s\n", filename->u8string().c_str()); M_ParseDefinitionFile(parse_vars, ParsePurpose::normal, &config, *filename, folder, prettyname); } #define MAX_INCLUDE_LEVEL 10 // // Fails with a ParseException // void parser_state_c::fail(EUR_FORMAT_STRING(const char *format), ...) const { va_list ap; va_start(ap, format); SString ss = SString::vprintf(format, ap); va_end(ap); SString prefix = SString::printf("%s(%d): ", file().u8string().c_str(), line()); throw ParseException(prefix + ss); } static const char *const bad_arg_count_fail = "directive \"%s\" takes %d parameters"; void parser_state_c::tokenize() { // break the line into whitespace-separated tokens. // whitespace can be enclosed in double quotes. TokenWordParse parse(readstring, true); SString word; args.clear(); argc = 0; while(parse.getNext(word)) { if(args.size() >= MAX_TOKENS) fail("more than %d tokens on the line", MAX_TOKENS); args.push_back(word); } argc = (int)args.size(); for(int i = 0; i < argc; ++i) argv[i] = args[i].c_str(); // safe if we lock the std::vector } // // Parses an arg string. Will return true and populate arg if successful // static bool parseArg(const char *text, SpecialArg &arg) { assert(!!text); const char *pos = strchr(text, ':'); if(!pos) { arg.name = text; arg.type = SpecialArgType::generic; return true; } const char *type = pos + 1; // Either use whatever's before the colon, or the type name if empty. arg.name = pos == text ? type : SString(text, (int)(pos - text)); if(!strcmp(type, "tag")) arg.type = SpecialArgType::tag; else if(!strcmp(type, "tag_hi")) arg.type = SpecialArgType::tag_hi; else if(!strcmp(type, "line_id")) arg.type = SpecialArgType::line_id; else if(!strcmp(type, "self_line_id")) arg.type = SpecialArgType::self_line_id; else if(!strcmp(type, "self_line_id_hi")) arg.type = SpecialArgType::self_line_id_hi; else if(!strcmp(type, "tid")) arg.type = SpecialArgType::tid; else if(!strcmp(type, "po")) arg.type = SpecialArgType::po; else // error return false; return true; } static void M_ParseNormalLine(parser_state_c *pst, ConfigData &config) { const char **argv = pst->argv; int nargs = pst->argc - 1; // these are handled by other passes if (y_stricmp(argv[0], "base_game") == 0 || y_stricmp(argv[0], "map_formats") == 0 || y_stricmp(argv[0], "supported_games") == 0 || y_stricmp(argv[0], "udmf_namespace") == 0) { return; } if (y_stricmp(argv[0], "player_size") == 0) { if (nargs != 3) pst->fail(bad_arg_count_fail, argv[0], 1); config.miscInfo.player_r = atoi(argv[1]); config.miscInfo.player_h = atoi(argv[2]); config.miscInfo.view_height = atoi(argv[3]); } else if (y_stricmp(argv[0], "sky_color") == 0) // back compat { if (nargs != 1) pst->fail(bad_arg_count_fail, argv[0], 1); config.miscInfo.sky_color = atoi(argv[1]); } else if (y_stricmp(argv[0], "sky_flat") == 0) { if (nargs != 1) pst->fail(bad_arg_count_fail, argv[0], 1); config.miscInfo.sky_flat = argv[1]; } else if (y_stricmp(argv[0], "color") == 0) { if (nargs < 2) pst->fail(bad_arg_count_fail, argv[0], 2); ParseColorDef(config, pst->argv + 1, nargs); } else if (y_stricmp(argv[0], "feature") == 0) { if (nargs < 2) pst->fail(bad_arg_count_fail, argv[0], 2); ParseFeatureDef(config, pst->argv + 1, nargs); } else if (y_stricmp(argv[0], "default_textures") == 0) { if (nargs != 3) pst->fail(bad_arg_count_fail, argv[0], 3); config.default_wall_tex = argv[1]; config.default_floor_tex = argv[2]; config.default_ceil_tex = argv[3]; } else if (y_stricmp(argv[0], "default_thing") == 0) { if (nargs != 1) pst->fail(bad_arg_count_fail, argv[0], 1); config.default_thing = atoi(argv[1]); } else if (y_stricmp(argv[0], "linegroup") == 0 || y_stricmp(argv[0], "spec_group") == 0) { if (nargs != 2) pst->fail(bad_arg_count_fail, argv[0], 2); linegroup_t lg = {}; lg.group = argv[1][0]; lg.desc = argv[2]; config.line_groups[lg.group] = lg; } else if (y_stricmp(argv[0], "line") == 0 || y_stricmp(argv[0], "special") == 0) { if (nargs < 3) pst->fail(bad_arg_count_fail, argv[0], 3); linetype_t info = {}; int number = atoi(argv[1]); info.group = argv[2][0]; info.desc = argv[3]; int arg_count = std::min(nargs - 3, 5); for (int i = 0 ; i < arg_count ; i++) { if (argv[4 + i][0] != '-') { if(!parseArg(argv[4 + i], info.args[i])) pst->fail("invalid arg type \"%s\"", argv[4 + i]); } } if (config.line_groups.find( info.group) == config.line_groups.end()) { gLog.printf("%s(%d): unknown line group '%c'\n", pst->file().u8string().c_str(), pst->line(), info.group); } else config.line_types[number] = info; } else if (y_stricmp(argv[0], "sector") == 0) { if (nargs != 2) pst->fail(bad_arg_count_fail, argv[0], 2); int number = atoi(argv[1]); sectortype_t info = {}; info.desc = argv[2]; config.sector_types[number] = info; } else if (y_stricmp(argv[0], "thinggroup") == 0) { if (nargs != 3) pst->fail(bad_arg_count_fail, argv[0], 3); thinggroup_t tg = {}; tg.group = argv[1][0]; tg.color = ParseColor(argv[2]); tg.desc = argv[3]; config.thing_groups[tg.group] = tg; } else if (y_stricmp(argv[0], "thing") == 0) { if (nargs < 6) pst->fail(bad_arg_count_fail, argv[0], 6); thingtype_t info = {}; int number = atoi(argv[1]); info.group = argv[2][0]; info.flags = ParseThingdefFlags(argv[3]); info.radius = static_cast(atoi(argv[4])); info.sprite = argv[5]; info.desc = argv[6]; info.scale = static_cast((nargs >= 7) ? atof(argv[7]) : 1.0); int arg_count = std::min(nargs - 7, 5); for (int i = 0 ; i < arg_count ; i++) { if (argv[8 + i][0] != '-') info.args[i] = argv[8 + i]; } if (config.thing_groups.find(info.group) == config.thing_groups.end()) { gLog.printf("%s(%d): unknown thing group '%c'\n", pst->file().u8string().c_str(), pst->line(), info.group); } else { info.color = config.thing_groups[info.group].color; config.thing_types[number] = info; } } else if (y_stricmp(argv[0], "texturegroup") == 0) { if (nargs != 2) pst->fail(bad_arg_count_fail, argv[0], 2); texturegroup_t tg = {}; tg.group = argv[1][0]; tg.desc = argv[2]; config.texture_groups[tg.group] = tg; } else if (y_stricmp(argv[0], "texture") == 0) { if (nargs != 2) pst->fail(bad_arg_count_fail, argv[0], 2); char group = argv[1][0]; SString name = SString(argv[2]); if (config.texture_groups.find((char)tolower(group)) == config.texture_groups.end()) { gLog.printf("%s(%d): unknown texture group '%c'\n", pst->file().u8string().c_str(), pst->line(), group); } else config.texture_categories[name] = group; } else if (y_stricmp(argv[0], "flat") == 0) { if (nargs != 2) pst->fail(bad_arg_count_fail, argv[0], 2); char group = argv[1][0]; SString name = SString(argv[2]); if (config.texture_groups.find((char)tolower(group)) == config.texture_groups.end()) { gLog.printf("%s(%d): unknown texture group '%c'\n", pst->file().u8string().c_str(), pst->line(), group); } else config.flat_categories[name] = group; } else if (y_stricmp(argv[0], "gen_line") == 0) { if (nargs != 4) pst->fail(bad_arg_count_fail, argv[0], 4); pst->current_gen_line = config.num_gen_linetypes; config.num_gen_linetypes++; if (config.num_gen_linetypes > MAX_GEN_NUM_TYPES) pst->fail("too many gen_line definitions"); generalized_linetype_t *def = &config.gen_linetypes[pst->current_gen_line]; def->key = argv[1][0]; // use strtol() to support "0x" notation def->base = static_cast(strtol(argv[2], NULL, 0)); def->length = static_cast(strtol(argv[3], NULL, 0)); def->name = argv[4]; def->fields.clear(); } else if (y_stricmp(argv[0], "gen_field") == 0) { if (nargs < 5) pst->fail(bad_arg_count_fail, argv[0], 5); if (pst->current_gen_line < 0) pst->fail("gen_field used outside of a gen_line definition"); generalized_linetype_t *def = &config.gen_linetypes[pst->current_gen_line]; def->fields.push_back({}); generalized_field_t *field = &def->fields.back(); if (def->fields.size() > MAX_GEN_NUM_FIELDS) pst->fail("too many fields in gen_line definition"); field->bits = atoi(argv[1]); field->shift = atoi(argv[2]); field->mask = ((1 << field->bits) - 1) << field->shift; field->default_val = atoi(argv[3]); field->name = argv[4]; // grab the keywords int num_keywords = std::min(nargs - 4, MAX_GEN_FIELD_KEYWORDS); field->keywords.reserve(num_keywords); for (int i = 0 ; i < num_keywords ; i++) { field->keywords.push_back(argv[5 + i]); } } else if (y_stricmp(argv[0], "clear") == 0) { if (nargs < 1) pst->fail(bad_arg_count_fail, argv[0], 2); ParseClearKeywords(config, pst->argv + 1, nargs, pst); } /* FIXME else { FatalError("%s(%d): unknown directive: %.32s\n", pst->fname, pst->lineno, argv[0]); } */ } static void M_ParseGameInfoLine(parser_state_c *pst, GameInfo &loadingGame) { const char **argv = pst->argv; int nargs = pst->argc - 1; if (y_stricmp(argv[0], "map_formats") == 0 || y_stricmp(argv[0], "supported_games") == 0 || y_stricmp(argv[0], "udmf_namespace") == 0) { pst->fail("%s can only be used in port definitions", argv[0]); } if (y_stricmp(argv[0], "base_game") == 0) { if (nargs < 1) pst->fail(bad_arg_count_fail, argv[0], 1); loadingGame.baseGame = SString(argv[1]).asLower(); } } static void M_ParsePortInfoLine(parser_state_c *pst, PortInfo_c &port) { const char **argv = pst->argv; int nargs = pst->argc - 1; if (y_stricmp(argv[0], "base_game") == 0) pst->fail("%s can only be used in game definitions", argv[0]); if (y_stricmp(argv[0], "supported_games") == 0) { if (nargs < 1) pst->fail(bad_arg_count_fail, argv[0], 1); for (argv++ ; nargs > 0 ; argv++, nargs--) port.AddSupportedGame(SString(*argv).asLower()); } else if (y_stricmp(argv[0], "map_formats") == 0) { if (nargs < 1) pst->fail(bad_arg_count_fail, argv[0], 1); port.formats = ParseMapFormats(pst, argv + 1, nargs); } else if (y_stricmp(argv[0], "udmf_namespace") == 0) { if (nargs != 1) pst->fail(bad_arg_count_fail, argv[0], 1); // want to preserve the case here port.udmf_namespace = argv[1]; } } static ParsingCondition M_ParseConditional(const std::unordered_map &parse_vars, parser_state_c *pst) { // returns the result of the "IF" test, true or false. const char **argv = pst->argv + 1; int nargs = pst->argc - 1; bool op_is = (nargs >= 3 && y_stricmp(argv[1], "is") == 0); bool op_not = (nargs >= 3 && y_stricmp(argv[1], "not") == 0); if (op_is || op_not) { if (strlen(argv[0]) < 2 || argv[0][0] != '$') pst->fail("expected variable in if statement"); // tokens are stored in pst->tokenbuf, so this is OK SString argvUpper = argv[0]; argvUpper = argvUpper.asUpper(); auto it = parse_vars.find(argvUpper); if(it != parse_vars.end()) { const SString &var_value = it->second; // test multiple values, only need one to succeed for (int i = 2 ; i < nargs ; i++) if (var_value.noCaseEqual(argv[i])) return op_is ? ParsingCondition::reading : ParsingCondition::skipping; } return op_not ? ParsingCondition::reading : ParsingCondition::skipping; } pst->fail("syntax error in if statement"); return ParsingCondition::skipping; } static void M_ParseSetVar(std::unordered_map &parse_vars, parser_state_c *pst) { const char **argv = pst->argv + 1; int nargs = pst->argc - 1; if (nargs != 2) pst->fail(bad_arg_count_fail, pst->argv[0], 1); if (strlen(argv[0]) < 2 || argv[0][0] != '$') pst->fail("variable name too short or lacks '$' prefix"); SString argvUpper = SString(argv[0]).asUpper(); parse_vars[argvUpper] = argv[1]; } // // this is main function for parsing a definition file. // // when purpose is PURPOSE_GameInfo or PURPOSE_PortInfo, then // only minimal parsing occurs, in particular the "include", "set" // and "if".."endif" directives are NOT handled. // void M_ParseDefinitionFile(std::unordered_map &parse_vars, const ParsePurpose purpose, ParseTarget target, const fs::path &filename, const fs::path &cfolder, const fs::path &cprettyname, int include_level) { SYS_ASSERT(!filename.empty()); fs::path folder = cfolder; if (folder.empty()) folder = "common"; fs::path prettyname = cprettyname; if (prettyname.empty()) prettyname = filename.filename(); parser_state_c parser_state(prettyname); // this is a bit silly, but makes it easier to move code around parser_state_c *const pst = &parser_state; // read the definition file, line by line LineFile file(filename); if (! file.isOpen()) throw ParseException(SString::printf("Cannot open %s: %s", filename.u8string().c_str(), GetErrorMessage(errno).c_str())); while (pst->readLine(file)) { pst->tokenize(); // skip empty lines and comments if (pst->argc == 0) continue; int nargs = pst->argc - 1; // handle conditionals: if...else...endif if (y_stricmp(pst->argv[0], "if") == 0) { parsing_cond_state_t cst; cst.cond = M_ParseConditional(parse_vars, pst); cst.start_line = pst->line(); pst->cond_stack.push_back(cst); continue; } if (y_stricmp(pst->argv[0], "else") == 0) { if (pst->cond_stack.empty()) pst->fail("else without if"); // toggle the mode pst->cond_stack.back().Toggle(); continue; } if (y_stricmp(pst->argv[0], "endif") == 0) { if (pst->cond_stack.empty()) pst->fail("endif without if"); pst->cond_stack.pop_back(); continue; } // skip lines when ANY if statement is in skip mode if (pst->HaveAnySkipping()) continue; // handle setting variables if (y_stricmp(pst->argv[0], "set") == 0) { M_ParseSetVar(parse_vars, pst); continue; } // handle includes if (y_stricmp(pst->argv[0], "include") == 0) { if (nargs != 1) pst->fail(bad_arg_count_fail, pst->argv[0], 1); if (include_level >= MAX_INCLUDE_LEVEL) pst->fail("Too many includes (check for a loop)"); fs::path new_folder = folder; tl::optional new_name = FindDefinitionFile(global::home_dir, global::install_dir, new_folder, pst->argv[1]); // if not found, check the common/ folder if (!new_name && folder != "common") { new_folder = "common"; new_name = FindDefinitionFile(global::home_dir, global::install_dir, new_folder, pst->argv[1]); } if (!new_name) pst->fail("Cannot find include file: %s.ugh", pst->argv[1]); M_ParseDefinitionFile(parse_vars, purpose, target, *new_name, new_folder, "" /* prettyname */, include_level + 1); continue; } if (purpose == ParsePurpose::gameInfo) { M_ParseGameInfoLine(pst, *target.game); continue; } if (purpose == ParsePurpose::portInfo) { M_ParsePortInfoLine(pst, *target.port); continue; } // handle everything else M_ParseNormalLine(pst, *target.config); } // check for an unterminated conditional if (! pst->cond_stack.empty()) pst->fail("Missing endif statement"); } // // Load game info // static GameInfo M_LoadGameInfo(const SString &game) noexcept(false) { // already loaded? auto it = global::sLoadedGameDefs.find(game); if(it != global::sLoadedGameDefs.end()) return it->second; tl::optional filename = FindDefinitionFile(global::home_dir, global::install_dir, GAMES_DIR, game); if(!filename) return {}; GameInfo loadingGame = GameInfo(game); std::unordered_map empty_vars; M_ParseDefinitionFile(empty_vars, ParsePurpose::gameInfo, &loadingGame, *filename, "games", ""); if(loadingGame.baseGame.empty()) throw ParseException(SString::printf("Game definition for '%s' does " "not set base_game\n", game.c_str())); global::sLoadedGameDefs[game] = loadingGame; return loadingGame; } const PortInfo_c * M_LoadPortInfo(const SString &port) noexcept(false) { std::map::iterator IT; IT = global::loaded_port_defs.find(port); if (IT != global::loaded_port_defs.end()) return &IT->second; tl::optional filename = FindDefinitionFile(global::home_dir, global::install_dir, PORTS_DIR, port); if (!filename) return NULL; global::loading_Port = PortInfo_c(port); std::unordered_map empty_vars; M_ParseDefinitionFile(empty_vars, ParsePurpose::portInfo, &global::loading_Port, *filename, "ports", ""); // default is to support both Doom and Doom2 if (global::loading_Port.supported_games.empty()) { global::loading_Port.supported_games.push_back("doom"); global::loading_Port.supported_games.push_back("doom2"); } global::loaded_port_defs[port] = global::loading_Port; return &global::loaded_port_defs[port]; } //------------------------------------------------------------------------ // // Collect known definitions from folder // std::vector M_CollectKnownDefs(const std::initializer_list &dirList, const fs::path &folder) { std::vector temp_list; // gLog.debugPrintf("M_CollectKnownDefs for: %d\n", folder); auto scanner_add_file = [&temp_list](const fs::path &name, int flags) { if (flags & (SCAN_F_IsDir | SCAN_F_Hidden)) return; if (! MatchExtensionNoCase(name, ".ugh")) return; temp_list.push_back(ReplaceExtension(name, NULL).u8string()); }; for(const fs::path &parentPath : dirList) { fs::path path = parentPath / folder; ScanDirectory(path, scanner_add_file); } std::sort(temp_list.begin(), temp_list.end(), [](const SString &a, const SString &b) { return a.noCaseCompare(b) < 0; }); // transfer to passed list, removing duplicates as we go size_t pos; // FIXME: use some thing here std::vector list; list.reserve(temp_list.size()); for (pos = 0 ; pos < temp_list.size() ; pos++) { if (pos + 1 < temp_list.size() && temp_list[pos].noCaseEqual(temp_list[pos + 1])) { continue; } list.push_back(temp_list[pos]); } return list; } SString M_GetBaseGame(const SString &game) noexcept(false) { GameInfo ginfo = M_LoadGameInfo(game); SYS_ASSERT(ginfo.isSet()); return ginfo.baseGame; } map_format_bitset_t M_DetermineMapFormats(const char *game, const char *port) { const PortInfo_c *pinfo = M_LoadPortInfo(port); if (pinfo && pinfo->formats != 0) return pinfo->formats; // a bit hacky, maybe should do it a better way... if (strcmp(game, "hexen") == 0) return (1 << static_cast(MapFormat::hexen)); return (1 << static_cast(MapFormat::doom)); } bool M_CheckPortSupportsGame(const SString &base_game, const SString &port) noexcept(false) { if (port == "vanilla") { // Vanilla means the engine that comes with the game, hence // it supports everything. return true; } const PortInfo_c *pinfo = M_LoadPortInfo(port); if (! pinfo) return false; return pinfo->SupportsGame(base_game); } // find all the ports which support the given base game.. // // result will be '|' separated (ready for Fl_Choice::add) // returns the empty string when nothing found. // The result should be freed with StringFree(). // // will also find an existing name, storing its index in 'exist_val' // (when not found, the value in 'exist_val' is not changed at all) SString M_CollectPortsForMenu(const char *base_game, int *exist_val, const char *exist_name) noexcept(false) { std::vector list = M_CollectKnownDefs({global::install_dir, global::home_dir}, "ports"); if (list.empty()) return ""; // determine final length int length = 2 + (int)list.size(); unsigned int i; for (i = 0 ; i < list.size() ; i++) length += static_cast(list[i].length()); SString result; result.reserve(length); int entry_id = 0; for (i = 0 ; i < list.size() ; i++) { if (! M_CheckPortSupportsGame(base_game, list[i])) continue; if (result[0]) result += '|'; result += list[i]; if (list[i].noCaseEqual(exist_name)) *exist_val = entry_id; entry_id++; } // gLog.debugPrintf( "RESULT = '%s'\n", result); return result; } //------------------------------------------------------------------------ // is this flat a sky? bool Instance::is_sky(const SString &flat) const { return flat.noCaseEqual(conf.miscInfo.sky_flat); } bool is_null_tex(const SString &tex) { return tex.good() && tex[0] == '-'; } bool is_special_tex(const SString &tex) { return tex.good() && tex[0] == '#'; } const sectortype_t &Instance::M_GetSectorType(int type) const { std::map::const_iterator SI; SI = conf.sector_types.find(type); if (SI != conf.sector_types.end()) return SI->second; static sectortype_t dummy_type = { "UNKNOWN TYPE" }; return dummy_type; } const linetype_t &ConfigData::getLineType(int type) const { std::map::const_iterator LI; LI = line_types.find(type); if (LI != line_types.end()) return LI->second; static const linetype_t dummy_type = { 0, "UNKNOWN TYPE" }; return dummy_type; } const thingtype_t &ConfigData::getThingType(int type) const { const thingtype_t *existing = get(thing_types, type); if(existing) return *existing; static thingtype_t dummy_type = { 0, 0, UNKNOWN_THING_RADIUS, 1.0f, "UNKNOWN TYPE", "NULL", UNKNOWN_THING_COLOR }; return dummy_type; } char Instance::M_GetTextureType(const SString &name) const { std::map::const_iterator TI; TI = conf.texture_categories.find(name); if (TI != conf.texture_categories.end()) return TI->second; return '-'; // the OTHER category } char Instance::M_GetFlatType(const SString &name) const { std::map::const_iterator TI; TI = conf.flat_categories.find(name); if (TI != conf.flat_categories.end()) return TI->second; return '-'; // the OTHER category } // // Generic for types // template static bool Category_IsUsed(const std::map &types, char group) { for (const auto &type : types) if(type.second.group == group) return true; return false; } static bool Category_IsUsed(const std::map &categories, char group) { for (const auto &category : categories) if(category.second == group) return true; return false; } // // Produces the category menu string and its associated letters // template static SString M_CategoryString(SString &letters, bool recent, const std::map &groups, const Categories &categories) { SString buffer; buffer.reserve(2000); // the "ALL" category is always first buffer = "ALL"; letters = "*"; letters.reserve(64); if(recent) { buffer += "|RECENT"; letters.push_back('^'); } typename std::map::const_iterator IT; for (IT = groups.begin() ; IT != groups.end() ; IT++) { const Group &G = IT->second; // the "Other" category is always at the end if (G.group == '-') continue; if (! Category_IsUsed(categories, G.group)) continue; // FIXME: potential for buffer overflow here buffer += '|'; buffer += G.desc; letters.push_back(IT->first); } buffer += "|Other"; letters.push_back('-'); return buffer; } SString Instance::M_LineCategoryString(SString &letters) const { return M_CategoryString(letters, false, conf.line_groups, conf.line_types); } SString Instance::M_ThingCategoryString(SString &letters) const { return M_CategoryString(letters, true, conf.thing_groups, conf.thing_types); } SString Instance::M_TextureCategoryString(SString &letters, bool do_flats) const { return M_CategoryString(letters, true, conf.texture_groups, do_flats ? conf.flat_categories : conf.texture_categories); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_game.h000066400000000000000000000234701464327712600177340ustar00rootroot00000000000000//------------------------------------------------------------------------ // GAME DEFINITION //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_M_GAME_H__ #define __EUREKA_M_GAME_H__ #include "im_color.h" #include "m_strings.h" #include #include #include #include "filesystem.hpp" namespace fs = ghc::filesystem; struct ConfigData; class Instance; struct LoadingData; // for this, set/clear/test bits using (1 << MAPF_xxx) typedef int map_format_bitset_t; /* * Data structures for game definition data */ // linegroup struct linegroup_t { char group; SString desc; }; // // Special arg type // enum class SpecialArgType { generic, tag, tag_hi, line_id, self_line_id, self_line_id_hi, tid, po }; // // Argument type // struct SpecialArg { SString name; SpecialArgType type = SpecialArgType::generic; }; // line [ arg1 .. arg5 ] struct linetype_t { bool isPolyObjectSpecial() const; char group; SString desc; SpecialArg args[5]; }; // sector struct sectortype_t { SString desc; }; // thinggroup struct thinggroup_t { char group; // group letter rgb_color_t color; // RGB colour SString desc; // Description of thing group }; // thing [] [ arg1..arg5 ] struct thingtype_t { char group; // group letter short flags; // flags (THINGDEF_XXX) short radius; // radius of thing float scale; // scaling (1.0 is normal) SString desc; // short description of the thing SString sprite; // name of sprite (frame and rot are optional) rgb_color_t color; // RGB color (from group) SString args[5]; // args used when spawned (Hexen) }; enum thingdef_flags_e { THINGDEF_INVIS = (1 << 0), // partially invisible THINGDEF_CEIL = (1 << 1), // hangs from ceiling THINGDEF_LIT = (1 << 2), // always bright THINGDEF_PASS = (1 << 3), // non-blocking THINGDEF_VOID = (1 << 4), // can exist in the void THINGDEF_TELEPT = (1 << 5), // teleport dest, can overlap certain things THINGDEF_POLYSPOT= (1 << 6), // polyobject spawn spot, tagging & BSP }; // texturegroup struct texturegroup_t { char group; SString desc; }; /* * Global variables that contain game definition data */ struct misc_info_t { enum { DEFAULT_PLAYER_RADIUS = 16, DEFAULT_PLAYER_HEIGHT = 56, DEFAULT_PLAYER_VIEW_HEIGHT = 41, DEFAULT_MINIMUM_DEATHMATCH_STARTS = 4, DEFAULT_MAXIMUM_DEATHMATCH_STARTS = 10 }; int sky_color = 0; SString sky_flat; int wall_colors[2] = {}; int floor_colors[2] = {}; int invis_colors[2] = {}; int missing_color = 0; int unknown_tex = 0; int unknown_flat = 0; int unknown_thing = 0; int player_r = DEFAULT_PLAYER_RADIUS; int player_h = DEFAULT_PLAYER_HEIGHT; int view_height = DEFAULT_PLAYER_VIEW_HEIGHT; int min_dm_starts = DEFAULT_MINIMUM_DEATHMATCH_STARTS; int max_dm_starts = DEFAULT_MAXIMUM_DEATHMATCH_STARTS; }; // // Type of generalized sectors for port // enum class GenSectorFamily : int { none, // not set boom, // original Boom generalized sectors zdoom // ZDoom shifted Boom generalized sectors }; // // Tag 666 rules. Mapped from the UGH file. // enum class Tag666Rules : int { disabled = 0, doom = 1, heretic = 2, }; struct port_features_t { // NOTE: values here are generally 0 or 1, but some can be higher int gen_types; // BOOM generalized linedef types GenSectorFamily gen_sectors; // BOOM and ZDoom sector flags (damage, secret, ...) int tx_start; // textures in TX_START .. TX_END int img_png; // PNG format for various graphics int coop_dm_flags; // MTF_NOT_COOP and MTF_NOT_DM for things int friend_flag; // MTF_FRIEND thing flag from MBF int pass_through; // Boom's MTF_PASSTHRU line flag int midtex_3d; // Eternity's ML_3DMIDTEX line flag int strife_flags; // Strife flags int medusa_fixed; // the Medusa Effect has been fixed (cannot occur) int tuttifrutti_fixed; // the tutti-frutti effect has been fixed (Boom and modern ZDoom) int lax_sprites; // sprites can be found outside of S_START..S_END int mix_textures_flats; // allow mixing textures and flats (adv. ports) int neg_patch_offsets; // honors negative patch offsets in textures (ZDoom) int no_need_players; // having no players is OK (Things checker) union // game uses tag 666 and 667 for special FX (type Tag666Rules) { int tag_666raw; Tag666Rules tag_666; }; int extra_floors; // bitmask: +1 EDGE, +2 Legacy, +4 for ZDoom in Hexen format int slopes; // bitmask: +1 EDGE, +2 Eternity, +4 Odamex, // +8 for ZDoom in Hexen format, +16 ZDoom things }; // // Game info // struct GameInfo { SString name; SString baseGame; GameInfo() = default; explicit GameInfo(const SString &name): name(name) { } bool isSet() const { return name.good() && baseGame.good(); } }; class PortInfo_c { public: SString name; map_format_bitset_t formats = 0; // 0 if not specified std::vector supported_games; SString udmf_namespace; public: PortInfo_c() = default; explicit PortInfo_c(SString _name) : name(_name) { } bool SupportsGame(const SString &game) const; void AddSupportedGame(const SString &game); }; //------------------------------------------------------------------------ /* Boom generalized types */ #define MAX_GEN_FIELD_BITS 4 #define MAX_GEN_FIELD_KEYWORDS (1 << MAX_GEN_FIELD_BITS) #define MAX_GEN_NUM_FIELDS 16 #define MAX_GEN_NUM_TYPES 16 struct generalized_field_t { int bits; // int mask; // the bit-field info int shift; // int default_val; SString name; std::vector keywords; }; struct generalized_linetype_t { char key; int base; int length; SString name; std::vector fields; }; //------------------------------------------------------------------------ // Standard directory names static const char GAMES_DIR[] = "games"; static const char PORTS_DIR[] = "ports"; bool M_CanLoadDefinitions(const fs::path &home_dir, const fs::path &install_dir, const fs::path &folder, const SString &name); void readConfiguration(std::unordered_map &parse_vars, const fs::path &folder, const SString &name, ConfigData &config) noexcept(false); enum class ParsePurpose { normal, // normal loading, update everything resource, // as a resource file gameInfo, // load a GameInfo portInfo // load a PortInfo_c }; // // Exception throwable by M_ParseDefinitionFile. Meant to be caught by parties // who don't want the app to terminate suddenly. // class ParseException : public std::runtime_error { public: ParseException(const SString &msg) : std::runtime_error(msg.c_str()) { } }; // // Target for M_ParseDefinitionFile // struct ConfigData { misc_info_t miscInfo = {}; port_features_t features = {}; SString default_wall_tex = "GRAY1"; SString default_floor_tex = "FLAT1"; SString default_ceil_tex = "FLAT1"; int default_thing = 2001; std::map flat_categories; std::map line_groups; std::map line_types; std::map sector_types; std::map texture_categories; std::map texture_groups; std::map thing_groups; std::map thing_types; int num_gen_linetypes = 0; generalized_linetype_t gen_linetypes[MAX_GEN_NUM_TYPES] = {}; // BOOM Generalized Lines const thingtype_t &getThingType(int type) const; const linetype_t &getLineType(int type) const; }; // // Generic parse target, depending on ParsePurpose // union ParseTarget { ParseTarget(GameInfo *game) : game(game) { } ParseTarget(PortInfo_c *port) : port(port) { } ParseTarget(ConfigData *config) : config(config) { } ParseTarget() = default; GameInfo *game; PortInfo_c *port; ConfigData *config; }; void M_ParseDefinitionFile(std::unordered_map &parse_vars, ParsePurpose purpose, ParseTarget target, const fs::path &filename, const fs::path &folder = "", const fs::path &prettyname = "", int include_level = 0); const PortInfo_c * M_LoadPortInfo(const SString &port) noexcept(false); std::vector M_CollectKnownDefs(const std::initializer_list &dirList, const fs::path &folder); bool M_CheckPortSupportsGame(const SString &base_game, const SString &port) noexcept(false); SString M_CollectPortsForMenu(const char *base_game, int *exist_val, const char *exist_name) noexcept(false); SString M_GetBaseGame(const SString &game) noexcept(false); map_format_bitset_t M_DetermineMapFormats(const char *game, const char *port); bool is_null_tex(const SString &tex); // the "-" texture bool is_special_tex(const SString &tex); // begins with "#" #endif /* __EUREKA_M_GAME_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_keys.cc000066400000000000000000000726571464327712600201470ustar00rootroot00000000000000//------------------------------------------------------------------------ // KEY BINDINGS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2013-2019 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include "m_parse.h" #include #include // this fake mod represents the "LAX-" prefix and is NOT used // anywhere except in the key_binding_t structure. #define MOD_LAX_SHIFTCTRL FL_SCROLL_LOCK namespace global { static std::vector< editor_command_t * > all_commands; } static KeyContext RequiredContextFromName(const char *name) { if (strncmp(name, "LIN_", 4) == 0) return KeyContext::line; if (strncmp(name, "SEC_", 4) == 0) return KeyContext::sector; if (strncmp(name, "TH_", 3) == 0) return KeyContext::thing; if (strncmp(name, "VT_", 3) == 0) return KeyContext::vertex; // we don't need anything for KCTX_Browser or KCTX_Render return KeyContext::none; } static const char * CalcGroupName(const char *given, KeyContext ctx) { if (given) return given; switch (ctx) { case KeyContext::line: return "Line"; case KeyContext::sector: return "Sector"; case KeyContext::thing: return "Thing"; case KeyContext::vertex: return "Vertex"; case KeyContext::render: return "3D View"; case KeyContext::browser: return "Browser"; default: return "General"; } } // // this should only be called during startup // void M_RegisterCommandList(editor_command_t * list) { // the structures are used directly for ( ; list->name ; list++) { list->req_context = RequiredContextFromName(list->name); list->group_name = CalcGroupName(list->group_name, list->req_context); global::all_commands.push_back(list); } } const editor_command_t * FindEditorCommand(SString name) { // backwards compatibility if (name.noCaseEqual("GRID_Step")) name = "GRID_Bump"; else if (name.noCaseEqual("Check")) name = "MapCheck"; else if (name.noCaseEqual("3D_Click")) name = "ACT_Click"; else if (name.noCaseEqual("3D_NAV_MouseMove")) name = "NAV_MouseScroll"; else if (name.noCaseEqual("OperationMenu")) name = "OpMenu"; for (const editor_command_t *command : global::all_commands) if (name.noCaseEqual(command->name)) return command; return NULL; } const editor_command_t * LookupEditorCommand(int idx) { if (idx >= (int)global::all_commands.size()) return NULL; return global::all_commands[idx]; } //------------------------------------------------------------------------ struct key_mapping_t { const keycode_t key; const char *const name; }; static const key_mapping_t s_key_map[] = { { ' ', "SPACE" }, { '"', "DBLQUOTE" }, { FL_BackSpace, "BS" }, { FL_Tab, "TAB" }, { FL_Enter, "ENTER" }, { FL_Pause, "PAUSE" }, { FL_Escape, "ESC" }, { FL_Left, "LEFT" }, { FL_Up, "UP" }, { FL_Right, "RIGHT" }, { FL_Down, "DOWN" }, { FL_Page_Up, "PGUP" }, { FL_Page_Down, "PGDN" }, { FL_Home, "HOME" }, { FL_End, "END" }, { FL_Print, "PRINT" }, { FL_Insert, "INS" }, { FL_Delete, "DEL" }, { FL_Menu, "MENU" }, { FL_Help, "HELP" }, { FL_KP_Enter, "KP_Enter"}, { FL_Volume_Down, "VOL_DOWN" }, { FL_Volume_Mute, "VOL_MUTE" }, { FL_Volume_Up, "VOL_UP" }, { FL_Media_Play, "CD_PLAY" }, { FL_Media_Stop, "CD_STOP" }, { FL_Media_Prev, "CD_PREV" }, { FL_Media_Next, "CD_NEXT" }, { FL_Home_Page, "HOME_PAGE" }, { FL_Mail, "MAIL" }, { FL_Search, "SEARCH" }, { FL_Back, "BACK" }, { FL_Forward, "FORWARD" }, { FL_Stop, "STOP" }, { FL_Refresh, "REFRESH" }, { FL_Sleep, "SLEEP" }, { FL_Favorites, "FAVORITES" }, // special stuff (not in FLTK) { FL_WheelUp, "WHEEL_UP" }, { FL_WheelDown, "WHEEL_DOWN" }, { FL_WheelLeft, "WHEEL_LEFT" }, { FL_WheelRight, "WHEEL_RIGHT" }, // some synonyms for user input { ' ', "SPC" }, { FL_BackSpace, "BACKSPACE" }, { FL_Enter, "RETURN" }, { FL_Escape, "ESCAPE" }, { FL_Insert, "INSERT" }, { FL_Delete, "DELETE" }, { FL_Page_Up, "PAGEUP" }, { FL_Page_Down, "PAGEDOWN" }, { 0, NULL } // the end }; bool is_mouse_wheel(keycode_t key) { key &= FL_KEY_MASK; return (FL_WheelUp <= key && key <= FL_WheelRight); } bool is_mouse_button(keycode_t key) { key &= FL_KEY_MASK; return (FL_Button < key && key <= FL_Button + 8); } // // returns zero (an invalid key) if parsing fails // keycode_t M_ParseKeyString(const SString &mstr) { int key = 0; // for EMOD_COMMAND, accept both CMD and CTRL prefixes SString str = mstr; if (str.noCaseStartsWith("CMD-")) { key |= EMOD_COMMAND; str.erase(0, 4); } else if (str.noCaseStartsWith("CTRL-")) { key |= EMOD_COMMAND; str.erase(0, 5); } else if (str.noCaseStartsWith("META-")) { key |= EMOD_META; str.erase(0, 5); } else if (str.noCaseStartsWith("ALT-")) { key |= EMOD_ALT; str.erase(0, 4); } else if (str.noCaseStartsWith("SHIFT-")) { key |= EMOD_SHIFT; str.erase(0, 6); } else if (str.noCaseStartsWith("LAX-")) { key |= MOD_LAX_SHIFTCTRL; str.erase(0, 4); } // convert uppercase letter --> lowercase + EMOD_SHIFT if (str.length() == 1 && str[0] >= 'A' && str[0] <= 'Z') return EMOD_SHIFT | (unsigned char) tolower(str[0]); if (str.length() == 1 && str[0] > 32 && str[0] < 127 && isprint(str[0])) return key | (unsigned char) str[0]; if (str.noCaseStartsWith("F") && isdigit(str[1])) return key | (FL_F + atoi(str.c_str() + 1)); if (str.noCaseStartsWith("MOUSE") && isdigit(str[5])) return key | (FL_Button + atoi(str.c_str() + 5)); // find name in mapping table for (int k = 0 ; s_key_map[k].name ; k++) if (str.noCaseEqual(s_key_map[k].name)) return key | s_key_map[k].key; if (str.noCaseStartsWith("KP_") && 33 < str[3] && (FL_KP + str[3]) <= FL_KP_Last) return key | (FL_KP + str[3]); if (str[0] == '0' && str[1] == 'x') return key | (int)strtol(str.c_str(), NULL, 0); return 0; } static SString BareKeyName(keycode_t key) { if(key < 127 && key > 32 && isprint(key) && key != '"') return SString(static_cast(key)); if(FL_F < key && key <= FL_F_Last) return SString::printf("F%d", key - FL_F); if(is_mouse_button(key)) return SString::printf("MOUSE%d", key - FL_Button); // find key in mapping table for(int k = 0; s_key_map[k].name; k++) if(key == s_key_map[k].key) return s_key_map[k].name; if(FL_KP + 33 <= key && key <= FL_KP_Last) return SString::printf("KP_%c", (char)(key & 127)); // fallback : hex code return SString::printf("0x%04x", key); } static const char *ModName_Dash(keycode_t mod) { #ifdef __APPLE__ if (mod & EMOD_COMMAND) return "CMD-"; #else if (mod & EMOD_COMMAND) return "CTRL-"; #endif if (mod & EMOD_META) return "META-"; if (mod & EMOD_ALT) return "ALT-"; if (mod & EMOD_SHIFT) return "SHIFT-"; if (mod & MOD_LAX_SHIFTCTRL) return "LAX-"; return ""; } static const char *ModName_Space(keycode_t mod) { #ifdef __APPLE__ if (mod & EMOD_COMMAND) return "CMD "; #else if (mod & EMOD_COMMAND) return "CTRL "; #endif if (mod & EMOD_META) return "META "; if (mod & EMOD_ALT) return "ALT "; if (mod & EMOD_SHIFT) return "SHIFT "; if (mod & MOD_LAX_SHIFTCTRL) return "LAX "; return ""; } SString M_KeyToString(keycode_t key) { // convert SHIFT + letter --> uppercase letter if ((key & EMOD_ALL_MASK) == EMOD_SHIFT && (key & FL_KEY_MASK) < 127 && isalpha(key & FL_KEY_MASK)) { return SString::printf("%c", toupper(key & FL_KEY_MASK)); } return SString::printf("%s%s", ModName_Dash(key), BareKeyName(key & FL_KEY_MASK).c_str()); } int M_KeyCmp(keycode_t A, keycode_t B) { keycode_t A_mod = A & EMOD_ALL_MASK; keycode_t B_mod = B & EMOD_ALL_MASK; A &= FL_KEY_MASK; B &= FL_KEY_MASK; // make mouse buttons separate from everything else if (is_mouse_button(A) || is_mouse_wheel(A)) A += 0x10000; if (is_mouse_button(B) || is_mouse_wheel(B)) B += 0x10000; // base key is most important if (A != B) return (int)A - (int)B; // modifiers are the least important return (int)A_mod - (int)B_mod; } //------------------------------------------------------------------------ KeyContext M_ParseKeyContext(const SString &str) { if (str.noCaseEqual("browser")) return KeyContext::browser; if (str.noCaseEqual("render")) return KeyContext::render; if (str.noCaseEqual("general")) return KeyContext::general; if (str.noCaseEqual("line")) return KeyContext::line; if (str.noCaseEqual("sector")) return KeyContext::sector; if (str.noCaseEqual("thing")) return KeyContext::thing; if (str.noCaseEqual("vertex")) return KeyContext::vertex; return KeyContext::none; } const char * M_KeyContextString(KeyContext context) { switch (context) { case KeyContext::browser: return "browser"; case KeyContext::render: return "render"; case KeyContext::general: return "general"; case KeyContext::line: return "line"; case KeyContext::sector: return "sector"; case KeyContext::thing: return "thing"; case KeyContext::vertex: return "vertex"; default: break; } return "INVALID"; } //------------------------------------------------------------------------ struct key_binding_t { keycode_t key; KeyContext context; const editor_command_t *cmd; SString param[MAX_EXEC_PARAM]; // this field ONLY used by M_DetectConflictingBinds() bool is_duplicate; }; namespace global { static std::vector all_bindings; static std::vector install_binds; } // // Helper for the predicates looking for the binding // struct KeyBindLookup { const keycode_t key; const KeyContext context; bool operator()(const key_binding_t &bind) { return bind.key == key && bind.context == context; } }; bool M_IsKeyBound(keycode_t key, KeyContext context) { return std::any_of(global::all_bindings.begin(), global::all_bindings.end(), KeyBindLookup{key, context}); } void M_RemoveBinding(keycode_t key, KeyContext context) { auto it = std::remove_if(global::all_bindings.begin(), global::all_bindings.end(), KeyBindLookup{key, context}); // there should never be more than one assert(it == global::all_bindings.end() || it + 1 == global::all_bindings.end()); global::all_bindings.erase(it, global::all_bindings.end()); } static void ParseKeyBinding(const std::vector &tokens) { // this ensures all parameters are NUL terminated key_binding_t temp = {}; assert(tokens.size() >= 2); temp.key = M_ParseKeyString(tokens[1]); if (! temp.key) { gLog.printf("bindings.cfg: cannot parse key name: %s\n", tokens[1].c_str()); return; } temp.context = M_ParseKeyContext(tokens[0]); if (temp.context == KeyContext::none) { gLog.printf("bindings.cfg: unknown context: %s\n", tokens[0].c_str()); return; } // handle un-bound keys assert(tokens.size() >= 3); if (tokens[2].noCaseEqual("UNBOUND")) { #if 0 fprintf(stderr, "REMOVED BINDING key:%04x (%s)\n", temp.key, tokens[0].c_str()); #endif M_RemoveBinding(temp.key, temp.context); return; } temp.cmd = FindEditorCommand(tokens[2]); if (! temp.cmd) { gLog.printf("bindings.cfg: unknown function: %s\n", tokens[2].c_str()); return; } if (temp.cmd->req_context != KeyContext::none && temp.context != temp.cmd->req_context) { gLog.printf("bindings.cfg: function '%s' in wrong context '%s'\n", tokens[2].c_str(), tokens[0].c_str()); return; } for (int p = 0 ; p < MAX_EXEC_PARAM ; p++) if((int)tokens.size() >= 4 + p) temp.param[p] = tokens[3 + p]; #if 0 // DEBUG fprintf(stderr, "ADDED BINDING key:%04x --> %s\n", temp.key, tokens[2].c_str()); #endif M_RemoveBinding(temp.key, temp.context); global::all_bindings.push_back(temp); } #define MAX_TOKENS (MAX_EXEC_PARAM + 8) static bool LoadBindingsFromPath(const SString &path, bool required) { SString filename = path + "/bindings.cfg"; std::ifstream fp(filename.c_str()); if(!fp.is_open()) { if (! required) return false; ThrowException("Missing key bindings file:\n\n%s\n", filename.c_str()); } gLog.printf("Reading key bindings from: %s\n", filename.c_str()); while (! fp.eof()) { SString line; std::getline(fp, line.get()); std::vector tokens; int num_tok = M_ParseLine(line, tokens, ParseOptions::haveStringsKeepQuotes); if (num_tok == 0) continue; if (num_tok < 3) { gLog.printf("Syntax error in bindings: %s\n", line.c_str()); continue; } ParseKeyBinding(tokens); } return true; } static void CopyInstallBindings() { global::install_binds = global::all_bindings; } static bool BindingExists(std::vector& list, const key_binding_t& bind, bool full_match) { for (const key_binding_t &other : list) { if (bind.key != other.key) continue; if (bind.context != other.context) continue; if (! full_match) return true; if (bind.cmd != other.cmd) continue; bool same_params = true; for (int p = 0 ; p < MAX_EXEC_PARAM ; p++) { if (bind.param[p] != other.param[p]) { same_params = false; break; } } if (same_params) return true; } return false; } void M_LoadBindings() { global::all_bindings.clear(); LoadBindingsFromPath(global::install_dir.u8string(), true /* required */); // keep a copy of the install_dir bindings CopyInstallBindings(); LoadBindingsFromPath(global::home_dir.u8string(), false); if(gInstance->main_win) menu::updateBindings(gInstance->main_win->menu_bar); } void M_SaveBindings() { SString filename = (global::home_dir / "bindings.cfg").u8string(); std::ofstream os(filename.get(), std::ios::trunc); if (! os.is_open()) { gLog.printf("Failed to save key bindings to: %s\n", filename.c_str()); DLG_Notify("Warning: failed to save key bindings\n" "(filename: %s)", filename.c_str()); return; } gLog.printf("Writing key bindings to: %s\n", filename.c_str()); os << "# Eureka key bindings (local)\n"; os << "# vi:ts=16:noexpandtab\n\n"; for (KeyContext ctx : validKeyContexts) { int count = 0; for (const key_binding_t &bind : global::all_bindings) { if (bind.context != ctx) continue; // no need to write it if unchanged from install_dir if (BindingExists(global::install_binds, bind, true /* full match */)) continue; os << M_KeyContextString(bind.context) << '\t' << M_KeyToString(bind.key) << '\t' << bind.cmd->name; for (int p = 0 ; p < MAX_EXEC_PARAM ; p++) { if (bind.param[p].good()) os << '\t' << bind.param[p]; } os << '\n'; count++; } // find un-bound keys (relative to installation) for (unsigned int i = 0 ; i < global::install_binds.size() ; i++) { const key_binding_t& bind = global::install_binds[i]; if (bind.context != ctx) continue; if (! BindingExists(global::all_bindings, bind, false /* full match */)) { os << M_KeyContextString(bind.context) << '\t' << M_KeyToString(bind.key) << '\t' << "UNBOUND" << '\n'; count++; } } if (count > 0) os << '\n'; } } //------------------------------------------------------------------------ // PREFERENCE DIALOG STUFF //------------------------------------------------------------------------ namespace global { // local copy of the bindings // these only become live after M_ApplyBindings() static std::vector pref_binds; } void M_CopyBindings(bool from_defaults) { // returns # of bindings global::pref_binds = from_defaults ? global::install_binds : global::all_bindings; } void M_ApplyBindings() { global::all_bindings = global::pref_binds; if(gInstance->main_win) menu::updateBindings(gInstance->main_win->menu_bar); } int M_NumBindings() { return (int)global::pref_binds.size(); } struct KeyBind_CMP_pred { private: char column; public: KeyBind_CMP_pred(char _col) : column(_col) { } inline bool operator() (const key_binding_t& k1, const key_binding_t& k2) const { if (column == 'c' && k1.context != k2.context) return k1.context > k2.context; if (column != 'f' && k1.key != k2.key) return M_KeyCmp(k1.key, k2.key) < 0; /// if (column == 'k' && k1.context != k2.context) /// return k1.context > k2.context; if (k1.cmd != k2.cmd) return y_stricmp(k1.cmd->name, k2.cmd->name) < 0; for (int p = 0 ; p < MAX_EXEC_PARAM ; p++) { int cmp = k1.param[p].noCaseCompare(k2.param[p]); if (cmp != 0) return cmp < 0; } if (column == 'f' && k1.key != k2.key) return M_KeyCmp(k1.key, k2.key) < 0; return k1.context < k2.context; } }; void M_SortBindings(char column, bool reverse) { std::sort(global::pref_binds.begin(), global::pref_binds.end(), KeyBind_CMP_pred(column)); if (reverse) std::reverse(global::pref_binds.begin(), global::pref_binds.end()); } void M_DetectConflictingBinds() { // copy the local bindings and sort them. // duplicate bindings will be contiguous in the list. std::vector list; for (unsigned int i = 0 ; i < global::pref_binds.size() ; i++) { global::pref_binds[i].is_duplicate = false; list.push_back(global::pref_binds[i]); } std::sort(list.begin(), list.end(), KeyBind_CMP_pred('c')); for (unsigned int k = 0 ; k + 1 < list.size() ; k++) { if (! (list[k].key == list[k+1].key && list[k].context == list[k+1].context)) continue; // mark these in the local bindings for (unsigned int n = 0 ; n < global::pref_binds.size() ; n++) { if (global::pref_binds[n].key == list[k].key && global::pref_binds[n].context == list[k].context) { global::pref_binds[n].is_duplicate = true; } } } } SString M_StringForFunc(int index) { SString buffer; buffer.reserve(2048); SYS_ASSERT(index >= 0 && index < static_cast(global::pref_binds.size())); const key_binding_t& bind = global::pref_binds[index]; SYS_ASSERT(!!bind.cmd); buffer = bind.cmd->name; // add the parameters for (int k = 0 ; k < MAX_EXEC_PARAM ; k++) { const SString ¶m = bind.param[k]; if (param.empty()) break; if (k == 0) buffer.push_back(':'); buffer.push_back(' '); buffer += SString::printf("%.30s", param.c_str()); } return buffer; } const char * M_StringForBinding(int index, bool changing_key) { SYS_ASSERT(index < (int)global::pref_binds.size()); const key_binding_t& bind = global::pref_binds[index]; static char buffer[600]; // we prefer the UI to say "3D view" instead of "render" const char *ctx_name = M_KeyContextString(bind.context); if (y_stricmp(ctx_name, "render") == 0) ctx_name = "3D view"; // display SHIFT + letter as an uppercase letter keycode_t tempk = bind.key; if ((tempk & EMOD_ALL_MASK) == EMOD_SHIFT && (tempk & FL_KEY_MASK) < 127 && isalpha(tempk & FL_KEY_MASK)) { tempk = toupper(tempk & FL_KEY_MASK); } snprintf(buffer, sizeof(buffer), "%s%6.6s%-10.10s %-9.9s %.32s", bind.is_duplicate ? "@C1" : "", changing_key ? "" : BareKeyName(tempk & FL_KEY_MASK).c_str(), ctx_name, M_StringForFunc(index).c_str() ); return buffer; } void M_GetBindingInfo(int index, keycode_t *key, KeyContext *context) { // hmmm... exposing key_binding_t may have been easier... *key = global::pref_binds[index].key; *context = global::pref_binds[index].context; } void M_ChangeBindingKey(int index, keycode_t key) { SYS_ASSERT(0 <= index && index < (int)global::pref_binds.size()); SYS_ASSERT(key != 0); global::pref_binds[index].key = key; } static const char * DoParseBindingFunc(key_binding_t& bind, const SString & func_str) { static char error_msg[1024]; // convert the brackets and commas into spaces and use the // line tokeniser. SString buffer = func_str; for (char &c : buffer) if (c == ',' || c == ':') c = ' '; std::vector tokens; int num_tok = M_ParseLine(buffer, tokens, ParseOptions::haveStringsKeepQuotes); if (num_tok <= 0) return "Missing function name"; const editor_command_t * cmd = FindEditorCommand(tokens[0]); if (! cmd) { snprintf(error_msg, sizeof(error_msg), "Unknown function name: %s", tokens[0].c_str()); return error_msg; } // check context is suitable if (cmd->req_context != KeyContext::none && bind.context != cmd->req_context) { SString mode = SString(M_KeyContextString(cmd->req_context)).asUpper(); snprintf(error_msg, sizeof(error_msg), "%s can only be used in %s mode", tokens[0].c_str(), mode.c_str()); return error_msg; } /* OK : change the binding function */ bind.cmd = cmd; for(SString ¶m : bind.param) param.clear(); for(int p = 0; p < MAX_EXEC_PARAM; p++) if(num_tok >= 2 + p) bind.param[p] = tokens[1 + p]; return NULL; } // returns an error message, or NULL if OK const char * M_SetLocalBinding(int index, keycode_t key, KeyContext context, const SString &func_str) { SYS_ASSERT(0 <= index && index < (int)global::pref_binds.size()); global::pref_binds[index].key = key; global::pref_binds[index].context = context; const char *err_msg = DoParseBindingFunc(global::pref_binds[index], func_str); return err_msg; } const char * M_AddLocalBinding(int after, keycode_t key, KeyContext context, const char *func_str) { // this ensures the parameters are NUL terminated key_binding_t temp = {}; temp.key = key; temp.context = context; const char *err_msg = DoParseBindingFunc(temp, func_str); if (err_msg) return err_msg; if (after < 0) global::pref_binds.push_back(temp); else global::pref_binds.insert(global::pref_binds.begin() + (1 + after), temp); return NULL; // OK } void M_DeleteLocalBinding(int index) { SYS_ASSERT(0 <= index && index < (int)global::pref_binds.size()); global::pref_binds.erase(global::pref_binds.begin() + index); } //------------------------------------------------------------------------ // COMMAND EXECUTION STUFF //------------------------------------------------------------------------ keycode_t M_TranslateKey(int key, int state) { // ignore modifier keys themselves switch (key) { case FL_Num_Lock: case FL_Caps_Lock: case FL_Shift_L: case FL_Control_L: case FL_Shift_R: case FL_Control_R: case FL_Meta_L: case FL_Alt_L: case FL_Meta_R: case FL_Alt_R: return 0; } if (key == '\t') key = FL_Tab; if (key == '\b') key = FL_BackSpace; // modifier logic -- only allow a single one if (state & EMOD_COMMAND) key |= EMOD_COMMAND; else if (state & EMOD_META) key |= EMOD_META; else if (state & EMOD_ALT) key |= EMOD_ALT; else if (state & EMOD_SHIFT) key |= EMOD_SHIFT; return key; } int M_KeyToShortcut(keycode_t key) { int shortcut = key & FL_KEY_MASK; if (key & EMOD_COMMAND) shortcut |= EMOD_COMMAND; else if (key & EMOD_ALT) shortcut |= EMOD_ALT; else if (key & EMOD_SHIFT) shortcut |= EMOD_SHIFT; return shortcut; } KeyContext M_ModeToKeyContext(ObjType mode) { switch (mode) { case ObjType::things: return KeyContext::thing; case ObjType::linedefs: return KeyContext::line; case ObjType::sectors: return KeyContext::sector; case ObjType::vertices: return KeyContext::vertex; default: break; } return KeyContext::none; /* shouldn't happen */ } bool Instance::Exec_HasFlag(const char *flag) const { // the parameter should include a leading '/' for (int i = 0 ; i < MAX_EXEC_PARAM ; i++) { if (EXEC_Flags[i].empty()) break; if (EXEC_Flags[i].noCaseEqual(flag)) return true; } return false; } extern void Debug_CheckUnusedStuff(Document &doc); void Instance::DoExecuteCommand(const editor_command_t *cmd) { (this->*cmd->func)(); // Debug_CheckUnusedStuff(); } static const key_binding_t *FindBinding(keycode_t key, KeyContext context, bool lax_only) { for (const key_binding_t &bind : global::all_bindings) { SYS_ASSERT(bind.cmd); if (bind.context != context) continue; // match modifiers "loosely" for certain commands (esp. NAV_xxx) bool is_lax = !!(bind.key & MOD_LAX_SHIFTCTRL); if (lax_only != is_lax) continue; keycode_t key1 = key; keycode_t key2 = bind.key; if (is_lax) { key1 &= ~ (EMOD_SHIFT | EMOD_COMMAND | MOD_LAX_SHIFTCTRL); key2 &= ~ (EMOD_SHIFT | EMOD_COMMAND | MOD_LAX_SHIFTCTRL); } if (key1 != key2) continue; // found a match return &bind; } // not found return nullptr; } bool Instance::ExecuteKey(keycode_t key, KeyContext context) { for (int p = 0 ; p < MAX_EXEC_PARAM ; p++) { EXEC_Param[p].clear(); EXEC_Flags[p].clear(); } EXEC_Errno = 0; // this logic means we only use a LAX binding if an exact match // could not be found. const key_binding_t *bind = FindBinding(key, context, false); if (!bind) bind = FindBinding(key, context, true); if (!bind) return false; int p_idx = 0; int f_idx = 0; for (int p = 0 ; p < MAX_EXEC_PARAM ; p++) { if (! bind->param[p][0]) break; // separate flags from normal parameters if (bind->param[p][0] == '/') EXEC_Flags[f_idx++] = bind->param[p]; else EXEC_Param[p_idx++] = bind->param[p]; } EXEC_CurKey = key; // commands can test for LAX mode via a special flag bool is_lax = (bind->key & MOD_LAX_SHIFTCTRL) ? true : false; if (is_lax && f_idx < MAX_EXEC_PARAM) { EXEC_Flags[f_idx++] = "/LAX"; } DoExecuteCommand(bind->cmd); return true; } bool Instance::ExecuteCommand(const editor_command_t *cmd, const SString ¶m1, const SString ¶m2, const SString ¶m3, const SString ¶m4) { for (int p = 0 ; p < MAX_EXEC_PARAM ; p++) { EXEC_Param[p].clear(); EXEC_Flags[p].clear(); } // separate flags from normal parameters int p_idx = 0; int f_idx = 0; if (param1[0] == '/') EXEC_Flags[f_idx++] = param1; else if (param1[0]) EXEC_Param[p_idx++] = param1; if (param2[0] == '/') EXEC_Flags[f_idx++] = param2; else if (param2[0]) EXEC_Param[p_idx++] = param2; if (param3[0] == '/') EXEC_Flags[f_idx++] = param3; else if (param3[0]) EXEC_Param[p_idx++] = param3; if (param4[0] == '/') EXEC_Flags[f_idx++] = param4; else if (param4[0]) EXEC_Param[p_idx++] = param4; EXEC_Errno = 0; EXEC_CurKey = 0; DoExecuteCommand(cmd); return true; } bool Instance::ExecuteCommand(const SString &name, const SString ¶m1, const SString ¶m2, const SString ¶m3, const SString ¶m4) { const editor_command_t * cmd = FindEditorCommand(name); if (! cmd) return false; return ExecuteCommand(cmd, param1, param2, param3, param4); } // // play a fascinating tune // void Instance::Beep(EUR_FORMAT_STRING(const char *fmt), ...) { va_list arg_ptr; va_start(arg_ptr, fmt); SString text = SString::vprintf(fmt, arg_ptr); va_end(arg_ptr); Status_Set("%s", text.c_str()); gLog.printf("BEEP: %s\n", text.c_str()); fl_beep(); EXEC_Errno = 1; } // // True if the given shortcut can really show up on menu, instead of garbage // static bool canShowUpOnMenu(keycode_t code) { code &= FL_KEY_MASK; // All plats switch(code) { case FL_Iso_Key: case FL_WheelUp: case FL_WheelDown: case FL_WheelLeft: case FL_WheelRight: return false; } // Try and pick as many buttons if(code >= FL_Button && code <= FL_Button + 9) return false; // For the macOS menu, don't show any fake unicode #ifdef __APPLE__ switch(code) { case FL_Button: case FL_Iso_Key: case FL_Pause: case FL_Scroll_Lock: case FL_Kana: case FL_Eisu: case FL_Yen: case FL_JIS_Underscore: case FL_Print: case FL_Insert: case FL_Menu: case FL_Help: case FL_Num_Lock: case FL_Shift_L: case FL_Shift_R: case FL_Control_L: case FL_Control_R: case FL_Caps_Lock: case FL_Meta_L: case FL_Meta_R: case FL_Alt_L: case FL_Alt_R: case FL_Volume_Down: case FL_Volume_Mute: case FL_Volume_Up: case FL_Media_Play: case FL_Media_Stop: case FL_Media_Prev: case FL_Media_Next: case FL_Home_Page: case FL_Mail: case FL_Search: case FL_Back: case FL_Forward: case FL_Stop: case FL_Refresh: case FL_Sleep: case FL_Favorites: return false; } if(code >= FL_KP && code <= FL_KP_Last) return false; #endif return true; } // // Finds key code for given command name // bool findKeyCodeForCommandName(const char *command, const char *params[MAX_EXEC_PARAM], keycode_t *code) { assert(!!code); *code = UINT_MAX; for(const key_binding_t &binding : global::all_bindings) { if(y_stricmp(binding.cmd->name, command)) continue; bool skip = false; for(int i = 0; i < MAX_EXEC_PARAM; ++i) { if(CSTRING_EMPTY(params[i]) ^ binding.param[i].empty()) { skip = true; break; } if(CSTRING_EMPTY(params[i]) && binding.param[i].empty()) break; if(!binding.param[i].noCaseEqual(params[i])) { skip = true; break; } } if(skip) continue; if(canShowUpOnMenu(binding.key) && binding.key < *code) *code = binding.key; // Continue looking until we find the lowest numbered key code. That is the smallest ASCII // character with no shortcut keys } return *code < UINT_MAX; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_keys.h000066400000000000000000000110651464327712600177730ustar00rootroot00000000000000//------------------------------------------------------------------------ // KEY BINDINGS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2013-2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_M_KEYS_H__ #define __EUREKA_M_KEYS_H__ #include "m_strings.h" #include "objid.h" class Instance; /* Key value: * - can be a printable ASCII character, e.g. 'a', '2', ';' * - spacebar is ' ' (ASCII code 32) * - letter keys are lowercase * - all other keys use the FLTK code (e.g. FL_Enter, FL_Up, etc) * - control keys (like CTRL-A) use EMOD_COMMAND flag (never '\001') * * Modifier (MOD_XXXX value) is or-ed with the bare key. * - uppercase letters are the lowercase letter + EMOD_SHIFT * - can extract bare key with FL_KEY_MASK * - can extract modifier with EMOD_ALL_MASK * - only a single modifier can be present: * EMOD_COMMAND > EMOD_META > EMOD_ALT > EMOD_SHIFT * - using my own names since "FL_CONTROL" is fucking confusing */ typedef unsigned int keycode_t; #define EMOD_none 0 #define EMOD_COMMAND FL_COMMAND #define EMOD_META FL_CONTROL #define EMOD_ALT FL_ALT #define EMOD_SHIFT FL_SHIFT #define EMOD_ALL_MASK (EMOD_COMMAND | EMOD_META | EMOD_ALT | EMOD_SHIFT) // made-up values to represent the mouse wheel #define FL_WheelUp 0xEF91 #define FL_WheelDown 0xEF92 #define FL_WheelLeft 0xEF93 #define FL_WheelRight 0xEF94 bool is_mouse_wheel (keycode_t key); bool is_mouse_button(keycode_t key); enum class KeyContext { none, // INVALID browser, render, vertex, thing, sector, line, general }; inline constexpr KeyContext validKeyContexts[] = { KeyContext::browser, KeyContext::render, KeyContext::vertex, KeyContext::thing, KeyContext::sector, KeyContext::line, KeyContext::general }; /* --- general manipulation --- */ int M_KeyCmp(keycode_t A, keycode_t B); KeyContext M_ParseKeyContext(const SString &str); const char * M_KeyContextString(KeyContext context); keycode_t M_ParseKeyString(const SString &str); SString M_KeyToString(keycode_t key); keycode_t M_TranslateKey(int key, int state); int M_KeyToShortcut(keycode_t key); KeyContext M_ModeToKeyContext(ObjType mode); /* --- preferences dialog stuff --- */ void M_CopyBindings(bool from_defaults = false); void M_SortBindings(char column, bool reverse); void M_ApplyBindings(); int M_NumBindings(); void M_DetectConflictingBinds(); SString M_StringForFunc(int index); const char * M_StringForBinding(int index, bool changing_key = false); void M_GetBindingInfo(int index, keycode_t *key, KeyContext *context); void M_ChangeBindingKey(int index, keycode_t key); const char * M_SetLocalBinding(int index, keycode_t key, KeyContext context, const SString &func_str); const char * M_AddLocalBinding(int after, keycode_t key, KeyContext context, const char *func_str); void M_DeleteLocalBinding(int index); void M_LoadBindings(); void M_SaveBindings(); bool M_IsKeyBound (keycode_t key, KeyContext context); void M_RemoveBinding(keycode_t key, KeyContext context); /* --- command execution stuff --- */ typedef void (Instance::*command_func_t)(); struct editor_command_t { const char *const name; // used in the Key binding preferences // when NULL, will be computed from 'req_context' const char *group_name; command_func_t func; const char *const flag_list; const char *const keyword_list; // this value is computed when registering KeyContext req_context; }; void M_RegisterCommandList(editor_command_t * list); const editor_command_t * FindEditorCommand(SString name); const editor_command_t * LookupEditorCommand(int index); // parameter(s) for command function -- must be valid strings #define MAX_EXEC_PARAM 16 #define MAX_BIND_LENGTH 64 bool findKeyCodeForCommandName(const char *command, const char *params[MAX_EXEC_PARAM], keycode_t *code); #endif /* __EUREKA_M_KEYS_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_loadsave.cc000066400000000000000000001376771464327712600207760ustar00rootroot00000000000000//------------------------------------------------------------------------ // LEVEL LOAD / SAVE / NEW //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 2015 Ioan Chera // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include "lib_adler.h" #include "e_basis.h" #include "e_checks.h" #include "e_main.h" // CalculateLevelBounds() #include "LineDef.h" #include "m_config.h" #include "m_files.h" #include "m_loadsave.h" #include "m_testmap.h" #include "r_subdiv.h" #include "Sector.h" #include "SideDef.h" #include "Thing.h" #include "Vertex.h" #include "w_rawdef.h" #include "w_wad.h" #include "ui_window.h" #include "ui_file.h" #include static const char overwrite_message[] = "The %s PWAD already contains this map. " "This operation will destroy that map (overwrite it)." "\n\n" "Are you sure you want to continue?"; static Document makeFreshDocument(Instance &inst, const ConfigData &config, MapFormat levelFormat) { Document doc(inst); auto sec = std::make_unique(); sec->SetDefaults(config); doc.sectors.push_back(std::move(sec)); for (int i = 0 ; i < 4 ; i++) { auto v = std::make_shared(); v->SetRawX(levelFormat, (i >= 2) ? 256 : -256); v->SetRawY(levelFormat, (i==1 || i==2) ? 256 :-256); doc.vertices.push_back(std::move(v)); auto sd = std::make_shared(); sd->SetDefaults(config, false); doc.sidedefs.push_back(std::move(sd)); auto ld = std::make_shared(); ld->start = i; ld->end = (i+1) % 4; ld->flags = MLF_Blocking; ld->right = i; doc.linedefs.push_back(std::move(ld)); } for (int pl = 1 ; pl <= 4 ; pl++) { auto th = std::make_unique(); th->type = pl; th->angle = 90; th->SetRawX(levelFormat, (pl == 1) ? 0 : (pl - 3) * 48); th->SetRawY(levelFormat, (pl == 1) ? 48 : (pl == 3) ? -48 : 0); doc.things.push_back(std::move(th)); } doc.CalculateLevelBounds(); return doc; } void Instance::FreshLevel() { level.clear(); level = makeFreshDocument(*this, conf, loaded.levelFormat); ZoomWholeMap(); edit.defaultState(); } tl::optional Instance::Project_AskFile() const { // this returns false if user cancelled Fl_Native_File_Chooser chooser; chooser.title("Pick file to create"); chooser.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); chooser.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM); chooser.filter("Wads\t*.wad"); chooser.directory(Main_FileOpFolder().u8string().c_str()); // Show native chooser switch (chooser.show()) { case -1: gLog.printf("New Project: error choosing file:\n"); gLog.printf(" %s\n", chooser.errmsg()); DLG_Notify("Unable to create a new project:\n\n%s", chooser.errmsg()); return {}; case 1: gLog.printf("New Project: cancelled by user\n"); return {}; default: break; // OK } // if extension is missing, add ".wad" fs::path filename = fs::u8path(chooser.filename()); fs::path extension = filename.extension(); if(extension.empty()) filename = fs::u8path(filename.u8string() + ".wad"); return filename; } static void updateLoading(const UI_ProjectSetup::Result &result, LoadingData &loading) { loading.gameName = result.game; loading.portName = result.port; const fs::path *iwad = global::recent.queryIWAD(result.game); SYS_ASSERT(iwad); loading.iwadName = *iwad; loading.levelFormat = result.mapFormat; loading.udmfNamespace = result.nameSpace; loading.resourceList.clear(); for(int i = 0; i < UI_ProjectSetup::RES_NUM; ++i) if(!result.resources[i].empty()) loading.resourceList.push_back(result.resources[i]); } void Instance::Project_ApplyChanges(const UI_ProjectSetup::Result &result) noexcept(false) { LoadingData loading = loaded; updateLoading(result, loading); Fl::wait(0.1); Main_LoadResources(loading); Fl::wait(0.1); } void Instance::CMD_ManageProject() { try { UI_ProjectSetup dialog(*this, false /* new_project */, false /* is_startup */); tl::optional result = dialog.Run(); if (result) { Project_ApplyChanges(*result); } } catch(const std::runtime_error &e) { DLG_ShowError(false, "Error managing project: %s", e.what()); } } void Instance::CMD_NewProject() { NewResources newres{}; ConfigData backupConfig = conf; LoadingData backupLoading = loaded; WadData backupWadData = wad; tl::optional backupDoc; try { if (!level.Main_ConfirmQuit("create a new project")) return; /* first, ask for the output file */ tl::optional filename = Project_AskFile(); if (!filename) return; if(global::recent.hasIwadByPath(*filename)) { DLG_Notify("Cannot overwrite a game IWAD: %s", filename.value().u8string().c_str()); return; } /* second, query what Game, Port and Resources to use */ // TODO: new instance UI_ProjectSetup dialog(*this, true /* new_project */, false /* is_startup */); tl::optional result = dialog.Run(); if (!result) { return; } if(FileExists(*filename)) { if(!DLG_Confirm({"Cancel", "&Overwrite"}, "Are you sure you want to overwrite %s with a new project?", filename.value().u8string().c_str())) { return; } } // Backup existing file before overwriting try { std::shared_ptr oldFile = Wad_file::Open(*filename, WadOpenMode::read); if(oldFile) { if(oldFile->IsIWAD()) { DLG_Notify("Overwriting game IWAD files is not allowed: %s", filename->u8string().c_str()); return; } M_BackupWad(oldFile.get()); } } catch(const std::runtime_error &e) { gLog.printf("Error reading old WAD %s: %s\n", filename->u8string().c_str(), e.what()); } LoadingData loading = loaded; updateLoading(*result, loading); newres = loadResources(loading, wad); // determine map name (same as first level in the IWAD) SString map_name = "MAP01"; int idx = newres.waddata.master.gameWad()->LevelFindFirst(); if (idx >= 0) { idx = newres.waddata.master.gameWad()->LevelHeader(idx); map_name = newres.waddata.master.gameWad()->GetLump(idx)->Name(); } gLog.printf("Creating New File : %s in %s\n", map_name.c_str(), filename->u8string().c_str()); std::shared_ptr wad = Wad_file::Open(*filename, WadOpenMode::write); if (!wad) { DLG_Notify("Unable to create the new WAD file."); return; } backupDoc = std::move(level); level = makeFreshDocument(*this, newres.config, newres.loading.levelFormat); conf = std::move(newres.config); loaded = std::move(newres.loading); if(main_win) testmap::updateMenuName(main_win->menu_bar, loaded); this->wad = std::move(newres.waddata); SaveLevel(loaded, map_name, *wad, false); this->wad.master.ReplaceEditWad(wad); ConfirmLevelSaveSuccess(loaded, *wad); UpdateViewOnResources(); RedrawMap(); } catch(const std::runtime_error &e) { conf = std::move(backupConfig); loaded = std::move(backupLoading); wad = std::move(backupWadData); if(backupDoc) level = std::move(backupDoc.value()); if(main_win) testmap::updateMenuName(main_win->menu_bar, loaded); DLG_ShowError(false, "Could not create new project: %s", e.what()); } } bool Instance::MissingIWAD_Dialog() { UI_ProjectSetup dialog(*this, false /* new_project */, true /* is_startup */); tl::optional result = dialog.Run(); if (result) { loaded.gameName = result->game; SYS_ASSERT(!loaded.gameName.empty()); const fs::path *iwad = global::recent.queryIWAD(loaded.gameName); SYS_ASSERT(!!iwad); loaded.iwadName = *iwad; if(main_win) testmap::updateMenuName(main_win->menu_bar, loaded); } return result.has_value(); } void Instance::CMD_FreshMap() { tl::optional backupDoc; try { if (!wad.master.editWad()) { DLG_Notify("Cannot create a fresh map unless editing a PWAD."); return; } if (wad.master.editWad()->IsReadOnly()) { DLG_Notify("Cannot create a fresh map: file is read-only."); return; } if (!level.Main_ConfirmQuit("create a fresh map")) return; SString map_name; { UI_ChooseMap dialog(loaded.levelName.c_str()); dialog.PopulateButtons(static_cast(toupper(loaded.levelName[0])), wad.master.editWad().get()); map_name = dialog.Run(); } // cancelled? if (map_name.empty()) return; // would this replace an existing map? if (wad.master.editWad()->LevelFind(map_name) >= 0) { if (DLG_Confirm({ "Cancel", "&Overwrite" }, overwrite_message, "current") <= 0) { return; } } M_BackupWad(wad.master.editWad().get()); gLog.printf("Created NEW map : %s\n", map_name.c_str()); // TODO: make this allow running another level backupDoc = std::move(level); FreshLevel(); // save it now : sets Level_name and window title SaveLevelAndUpdateWindow(loaded, map_name, *wad.master.editWad(), false); } catch (const std::runtime_error& e) { if(backupDoc) level = std::move(*backupDoc); DLG_ShowError(false, "Could not create fresh map: %s", e.what()); } } //------------------------------------------------------------------------ // LOADING CODE //------------------------------------------------------------------------ static void UpperCaseShortStr(char *buf, int max_len) { for (int i = 0 ; (i < max_len) && buf[i] ; i++) { buf[i] = static_cast(toupper(buf[i])); } } const Lump_c *Load_LookupAndSeek(int loading_level, const Wad_file *load_wad, const char *name) { int idx = load_wad->LevelLookupLump(loading_level, name); if (idx < 0) return NULL; const Lump_c *lump = load_wad->GetLump(idx); return lump; } void Document::LoadVertices(int loading_level, const Wad_file *load_wad) { const Lump_c *lump = Load_LookupAndSeek(loading_level, load_wad, "VERTEXES"); if (! lump) ThrowException("No vertex lump!\n"); int count = lump->Length() / sizeof(raw_vertex_t); # if DEBUG_LOAD PrintDebug("GetVertices: num = %d\n", count); # endif vertices.reserve(count); LumpInputStream stream(*lump); for (int i = 0 ; i < count ; i++) { raw_vertex_t raw; if (! stream.read(&raw, sizeof(raw))) ThrowException("Error reading vertices.\n"); auto vert = std::make_unique(); vert->raw_x = FFixedPoint(LE_S16(raw.x)); vert->raw_y = FFixedPoint(LE_S16(raw.y)); vertices.push_back(std::move(vert)); } } void Document::LoadSectors(int loading_level, const Wad_file *load_wad) { const Lump_c *lump = Load_LookupAndSeek(loading_level, load_wad, "SECTORS"); if (! lump) ThrowException("No sector lump!\n"); int count = lump->Length() / sizeof(raw_sector_t); # if DEBUG_LOAD PrintDebug("GetSectors: num = %d\n", count); # endif sectors.reserve(count); LumpInputStream stream(*lump); for (int i = 0 ; i < count ; i++) { raw_sector_t raw; if (! stream.read(&raw, sizeof(raw))) ThrowException("Error reading sectors.\n"); auto sec = std::make_shared(); sec->floorh = LE_S16(raw.floorh); sec->ceilh = LE_S16(raw.ceilh); UpperCaseShortStr(raw.floor_tex, 8); UpperCaseShortStr(raw. ceil_tex, 8); sec->floor_tex = BA_InternaliseString(SString(raw.floor_tex, 8)); sec->ceil_tex = BA_InternaliseString(SString(raw.ceil_tex, 8)); sec->light = LE_U16(raw.light); sec->type = LE_U16(raw.type); sec->tag = LE_S16(raw.tag); sectors.push_back(std::move(sec)); } } void Document::CreateFallbackSector(const ConfigData &config) { gLog.printf("Creating a fallback sector.\n"); auto sec = std::make_shared(); sec->SetDefaults(config); sectors.push_back(std::move(sec)); } void Document::CreateFallbackSideDef(const ConfigData &config) { // we need a valid sector too! if (numSectors() == 0) CreateFallbackSector(config); gLog.printf("Creating a fallback sidedef.\n"); auto sd = std::make_shared(); sd->SetDefaults(config, false); sidedefs.push_back(std::move(sd)); } void Document::CreateFallbackVertices() { gLog.printf("Creating two fallback vertices.\n"); auto v1 = std::make_unique(); auto v2 = std::make_unique(); v1->raw_x = FFixedPoint(-777); v1->raw_y = FFixedPoint(-777); v2->raw_x = FFixedPoint(555); v2->raw_y = FFixedPoint(555); vertices.push_back(std::move(v1)); vertices.push_back(std::move(v2)); } void Document::ValidateSidedefRefs(LineDef & ld, int num, const ConfigData &config, BadCount &bad) { if (ld.right >= numSidedefs() || ld.left >= numSidedefs()) { gLog.printf("WARNING: linedef #%d has invalid sidedefs (%d / %d)\n", num, ld.right, ld.left); bad.sidedef_refs++; // ensure we have a usable sidedef if (numSidedefs() == 0) CreateFallbackSideDef(config); if (ld.right >= numSidedefs()) ld.right = 0; if (ld.left >= numSidedefs()) ld.left = 0; } } void Document::ValidateVertexRefs(LineDef &ld, int num, BadCount &bad) { if (ld.start >= numVertices() || ld.end >= numVertices() || ld.start == ld.end) { gLog.printf("WARNING: linedef #%d has invalid vertices (%d -> %d)\n", num, ld.start, ld.end); bad.linedef_count++; // ensure we have a valid vertex if (numVertices() < 2) CreateFallbackVertices(); ld.start = 0; ld.end = numVertices() - 1; } } void Document::ValidateSectorRef(SideDef &sd, int num, const ConfigData &config, BadCount &bad) { if (sd.sector >= numSectors()) { gLog.printf("WARNING: sidedef #%d has invalid sector (%d)\n", num, sd.sector); bad.sector_refs++; // ensure we have a valid sector if (numSectors() == 0) CreateFallbackSector(config); sd.sector = 0; } } void Document::LoadHeader(int loading_level, const Wad_file &load_wad) { const Lump_c *lump = load_wad.GetLump(load_wad.LevelHeader(loading_level)); headerData = lump->getData(); } void Document::LoadBehavior(int loading_level, const Wad_file *load_wad) { // IOANCH 9/2015: support Hexen maps const Lump_c *lump = Load_LookupAndSeek(loading_level, load_wad, "BEHAVIOR"); if (! lump) ThrowException("No BEHAVIOR lump!\n"); behaviorData = lump->getData(); } void Document::LoadScripts(int loading_level, const Wad_file *load_wad) { // the SCRIPTS lump is usually absent const Lump_c *lump = Load_LookupAndSeek(loading_level, load_wad, "SCRIPTS"); if (! lump) return; scriptsData = lump->getData(); } void Document::LoadThings(int loading_level, const Wad_file *load_wad) { const Lump_c *lump = Load_LookupAndSeek(loading_level, load_wad, "THINGS"); if (! lump) ThrowException("No things lump!\n"); int count = lump->Length() / sizeof(raw_thing_t); # if DEBUG_LOAD PrintDebug("GetThings: num = %d\n", count); # endif LumpInputStream stream(*lump); for (int i = 0 ; i < count ; i++) { raw_thing_t raw; if (! stream.read(&raw, sizeof(raw))) ThrowException("Error reading things.\n"); auto th = std::make_unique(); th->raw_x = FFixedPoint(LE_S16(raw.x)); th->raw_y = FFixedPoint(LE_S16(raw.y)); th->angle = LE_U16(raw.angle); th->type = LE_U16(raw.type); th->options = LE_U16(raw.options); things.push_back(std::move(th)); } } // IOANCH 9/2015 void Document::LoadThings_Hexen(int loading_level, const Wad_file *load_wad) { const Lump_c *lump = Load_LookupAndSeek(loading_level, load_wad, "THINGS"); if (! lump) ThrowException("No things lump!\n"); int count = lump->Length() / sizeof(raw_hexen_thing_t); # if DEBUG_LOAD PrintDebug("GetThings: num = %d\n", count); # endif LumpInputStream stream(*lump); for (int i = 0; i < count; ++i) { raw_hexen_thing_t raw; if (! stream.read(&raw, sizeof(raw))) ThrowException("Error reading things.\n"); auto th = std::make_unique(); th->tid = LE_S16(raw.tid); th->raw_x = FFixedPoint(LE_S16(raw.x)); th->raw_y = FFixedPoint(LE_S16(raw.y)); th->raw_h = FFixedPoint(LE_S16(raw.height)); th->angle = LE_U16(raw.angle); th->type = LE_U16(raw.type); th->options = LE_U16(raw.options); th->special = raw.special; th->arg1 = raw.args[0]; th->arg2 = raw.args[1]; th->arg3 = raw.args[2]; th->arg4 = raw.args[3]; th->arg5 = raw.args[4]; things.push_back(std::move(th)); } } void Document::LoadSideDefs(int loading_level, const Wad_file *load_wad, const ConfigData &config, BadCount &bad) { const Lump_c *lump = Load_LookupAndSeek(loading_level, load_wad, "SIDEDEFS"); if(!lump) ThrowException("No sidedefs lump!\n"); int count = lump->Length() / sizeof(raw_sidedef_t); # if DEBUG_LOAD PrintDebug("GetSidedefs: num = %d\n", count); # endif LumpInputStream stream(*lump); for (int i = 0 ; i < count ; i++) { raw_sidedef_t raw; if (! stream.read(&raw, sizeof(raw))) ThrowException("Error reading sidedefs.\n"); auto sd = std::make_shared(); sd->x_offset = LE_S16(raw.x_offset); sd->y_offset = LE_S16(raw.y_offset); UpperCaseShortStr(raw.upper_tex, 8); UpperCaseShortStr(raw.lower_tex, 8); UpperCaseShortStr(raw. mid_tex, 8); sd->upper_tex = BA_InternaliseString(SString(raw.upper_tex, 8)); sd->lower_tex = BA_InternaliseString(SString(raw.lower_tex, 8)); sd-> mid_tex = BA_InternaliseString(SString(raw. mid_tex, 8)); sd->sector = LE_U16(raw.sector); ValidateSectorRef(*sd, i, config, bad); sidedefs.push_back(std::move(sd)); } } void Document::LoadLineDefs(int loading_level, const Wad_file *load_wad, const ConfigData &config, BadCount &bad) { const Lump_c *lump = Load_LookupAndSeek(loading_level, load_wad, "LINEDEFS"); if (! lump) ThrowException("No linedefs lump!\n"); int count = lump->Length() / sizeof(raw_linedef_t); # if DEBUG_LOAD PrintDebug("GetLinedefs: num = %d\n", count); # endif if (count == 0) return; LumpInputStream stream(*lump); for (int i = 0 ; i < count ; i++) { raw_linedef_t raw; if (! stream.read(&raw, sizeof(raw))) ThrowException("Error reading linedefs.\n"); auto ld = std::make_shared(); ld->start = LE_U16(raw.start); ld->end = LE_U16(raw.end); ld->flags = LE_U16(raw.flags); ld->type = LE_U16(raw.type); ld->tag = LE_S16(raw.tag); ld->right = LE_U16(raw.right); ld->left = LE_U16(raw.left); if (ld->right == 0xFFFF) ld->right = -1; if (ld-> left == 0xFFFF) ld-> left = -1; ValidateVertexRefs(*ld, i, bad); ValidateSidedefRefs(*ld, i, config, bad); linedefs.push_back(std::move(ld)); } } // IOANCH 9/2015 void Document::LoadLineDefs_Hexen(int loading_level, const Wad_file *load_wad, const ConfigData &config, BadCount &bad) { const Lump_c *lump = Load_LookupAndSeek(loading_level, load_wad, "LINEDEFS"); if (! lump) ThrowException("No linedefs lump!\n"); int count = lump->Length() / sizeof(raw_hexen_linedef_t); # if DEBUG_LOAD PrintDebug("GetLinedefs: num = %d\n", count); # endif if (count == 0) return; LumpInputStream stream(*lump); for (int i = 0 ; i < count ; i++) { raw_hexen_linedef_t raw; if (! stream.read(&raw, sizeof(raw))) ThrowException("Error reading linedefs.\n"); auto ld = std::make_shared(); ld->start = LE_U16(raw.start); ld->end = LE_U16(raw.end); ld->flags = LE_U16(raw.flags); ld->type = raw.type; ld->tag = raw.args[0]; ld->arg2 = raw.args[1]; ld->arg3 = raw.args[2]; ld->arg4 = raw.args[3]; ld->arg5 = raw.args[4]; ld->right = LE_U16(raw.right); ld->left = LE_U16(raw.left); if (ld->right == 0xFFFF) ld->right = -1; if (ld-> left == 0xFFFF) ld-> left = -1; ValidateVertexRefs(*ld, i, bad); ValidateSidedefRefs(*ld, i, config, bad); linedefs.push_back(std::move(ld)); } } void Document::RemoveUnusedVerticesAtEnd() { if (numVertices() == 0) return; bitvec_c used_verts(numVertices()); for (const auto &linedef : linedefs) { used_verts.set(linedef->start); used_verts.set(linedef->end); } int new_count = numVertices(); while (new_count > 2 && !used_verts.get(new_count-1)) new_count--; // we directly modify the vertex array here (which is not // normally kosher, but level loading is a special case). if (new_count < numVertices()) { gLog.printf("Removing %d unused vertices at end\n", numVertices() - new_count); vertices.resize(new_count); } } static void ShowLoadProblem(const BadCount &bad) { gLog.printf("Map load problems:\n"); gLog.printf(" %d linedefs with bad vertex refs\n", bad.linedef_count); gLog.printf(" %d linedefs with bad sidedef refs\n", bad.sidedef_refs); gLog.printf(" %d sidedefs with bad sector refs\n", bad.sector_refs); SString message; if (bad.linedef_count > 0) { message = SString::printf("Found %d linedefs with bad vertex references.\n" "These references have been replaced.", bad.linedef_count); } else { message = SString::printf("Found %d bad sector refs, %d bad sidedef refs.\n" "These references have been replaced.", bad.sector_refs, bad.sidedef_refs); } DLG_Notify("Map validation report:\n\n%s", message.c_str()); } // // Read in the level data // void Instance::LoadLevel(const Wad_file *wad, const SString &level) noexcept(false) { int lev_num = wad->LevelFind(level); if (lev_num < 0) ThrowException("No such map: %s\n", level.c_str()); LoadLevelNum(wad, lev_num); // reset various editor state Editor_ClearAction(); Selection_InvalidateLast(); edit.Selected->clear_all(); edit.highlight.clear(); if (main_win) { main_win->UpdateTotals(this->level); main_win->UpdateGameInfo(loaded, conf); main_win->InvalidatePanelObj(); main_win->redraw(); main_win->SetTitle(wad->PathName().u8string(), level, wad->IsReadOnly()); // load the user state associated with this map if (! M_LoadUserState()) { M_DefaultUserState(); } } loaded.levelName = level.asUpper(); Status_Set("Loaded %s", loaded.levelName.c_str()); RedrawMap(); } NewDocument Instance::openDocument(const LoadingData &inLoading, const Wad_file &wad, int level) { assert(level >= 0 && level < wad.LevelCount()); NewDocument newdoc = { Document(*this), inLoading, BadCount() }; Document& doc = newdoc.doc; LoadingData& loading = newdoc.loading; BadCount& bad = newdoc.bad; loading.levelFormat = wad.LevelFormat(level); doc.LoadHeader(level, wad); if(loading.levelFormat == MapFormat::udmf) { UDMF_LoadLevel(level, &wad, doc, loading, bad); } else try { if(loading.levelFormat == MapFormat::hexen) doc.LoadThings_Hexen(level, &wad); else doc.LoadThings(level, &wad); doc.LoadVertices(level, &wad); doc.LoadSectors(level, &wad); doc.LoadSideDefs(level, &wad, conf, bad); if(loading.levelFormat == MapFormat::hexen) { doc.LoadLineDefs_Hexen(level, &wad, conf, bad); doc.LoadBehavior(level, &wad); doc.LoadScripts(level, &wad); } else doc.LoadLineDefs(level, &wad, conf, bad); } catch(const std::runtime_error &e) { gLog.printf("%s\n", e.what()); throw; } doc.RemoveUnusedVerticesAtEnd(); doc.checks.sidedefsUnpack(true); doc.CalculateLevelBounds(); doc.MadeChanges = false; return newdoc; } void Instance::LoadLevelNum(const Wad_file *wad, int lev_num) noexcept(false) { NewDocument newdoc = openDocument(loaded, *wad, lev_num); if (newdoc.bad.linedef_count || newdoc.bad.sector_refs || newdoc.bad.sidedef_refs) { ShowLoadProblem(newdoc.bad); } loaded = newdoc.loading; level = std::move(newdoc.doc); if(main_win) testmap::updateMenuName(main_win->menu_bar, loaded); Subdiv_InvalidateAll(); } void Instance::refreshViewAfterLoad(const BadCount& bad, const Wad_file *wad, const SString &map_name, bool new_resources) { if (bad.exists()) ShowLoadProblem(bad); Subdiv_InvalidateAll(); // reset various editor state Editor_ClearAction(); Selection_InvalidateLast(); edit.Selected->clear_all(); edit.highlight.clear(); if (main_win) { main_win->UpdateTotals(level); main_win->UpdateGameInfo(loaded, conf); main_win->InvalidatePanelObj(); main_win->redraw(); main_win->SetTitle(wad->PathName().u8string(), map_name, wad->IsReadOnly()); // load the user state associated with this map if (!M_LoadUserState()) M_DefaultUserState(); } loaded.levelName = map_name.asUpper(); Status_Set("Loaded %s", loaded.levelName.c_str()); RedrawMap(); if (new_resources && main_win) { if (main_win->canvas) main_win->canvas->DeleteContext(); main_win->browser->Populate(); // TODO: only call this when the IWAD has changed main_win->propsLoadValues(); } } // // open a new wad file. // when 'map_name' is not NULL, try to open that map. // void OpenFileMap(const fs::path &filename, const SString &map_namem) noexcept(false) { // TODO: change this to start a new instance SString map_name = map_namem; if (! gInstance->level.Main_ConfirmQuit("open another map")) return; std::shared_ptr wad; // make sure file exists, as Open() with 'a' would create it otherwise if (FileExists(filename)) { wad = Wad_file::loadFromFile(filename); } if (! wad) { // FIXME: get an error message, add it here DLG_Notify("Unable to open that WAD file."); return; } // determine which level to use int lev_num = -1; if (map_name.good()) { lev_num = wad->LevelFind(map_name); } if (lev_num < 0) { lev_num = wad->LevelFindFirst(); } if (lev_num < 0) { DLG_Notify("No levels found in that WAD."); return; } LoadingData loading = gInstance->loaded; if (wad->FindLump(EUREKA_LUMP)) { if (! loading.parseEurekaLump(global::home_dir, global::install_dir, global::recent, wad.get())) { return; } } /* OK, open it */ // this wad replaces the current PWAD // always grab map_name from the actual level { int idx = wad->LevelHeader(lev_num); map_name = wad->GetLump(idx)->Name(); } gLog.printf("Loading Map : %s of %s\n", map_name.c_str(), wad->PathName().u8string().c_str()); // These 2 may throw, but it's safe here NewDocument newdoc = gInstance->openDocument(loading, *wad, lev_num); NewResources newres = loadResources(newdoc.loading, gInstance->wad); gInstance->level = std::move(newdoc.doc); gInstance->conf = std::move(newres.config); gInstance->loaded = std::move(newres.loading); gInstance->wad = std::move(newres.waddata); gInstance->wad.master.ReplaceEditWad(wad); if(gInstance->main_win) testmap::updateMenuName(gInstance->main_win->menu_bar, gInstance->loaded); gInstance->refreshViewAfterLoad(newdoc.bad, wad.get(), map_name, true); } void Instance::CMD_OpenMap() { if (!level.Main_ConfirmQuit("open another map")) return; SString map_name; bool did_load = false; std::shared_ptr wad = UI_OpenMap(*this).Run(&map_name, &did_load); if (! wad) // cancelled return; // this shouldn't happen -- but just in case... int lev_num = wad->LevelFind(map_name); if (lev_num < 0) { DLG_Notify("Hmmmm, cannot find that map !?!"); return; } LoadingData loading = loaded; if (did_load && wad->FindLump(EUREKA_LUMP) && !loading.parseEurekaLump(global::home_dir, global::install_dir, global::recent, wad.get())) { return; } // does this wad replace the currently edited wad? bool new_resources = false; std::shared_ptr newEditWad; bool removeEditWad = false; if (did_load) { SYS_ASSERT(wad != this->wad.master.editWad()); SYS_ASSERT(wad != this->wad.master.gameWad()); newEditWad = wad; new_resources = true; } // ...or does it remove the edit_wad? (e.g. wad == game_wad) else if (this->wad.master.editWad() && wad != this->wad.master.editWad()) { removeEditWad = true; new_resources = true; } gLog.printf("Loading Map : %s of %s\n", map_name.c_str(), wad->PathName().u8string().c_str()); NewDocument newdoc = { Document(*this), LoadingData(), BadCount() }; try { newdoc = openDocument(loading, *wad, lev_num); } catch (const std::runtime_error& e) { DLG_ShowError(false, "Could not open %s of %s. %s", map_name.c_str(), wad->PathName().u8string().c_str(), e.what()); return; } if (new_resources) { // TODO: call a safe version of Main_LoadResources NewResources newres = {}; try { newres = loadResources(newdoc.loading, this->wad); } catch (const std::runtime_error& e) { DLG_ShowError(false, "Could not reload resources: %s", e.what()); return; } // success loading resources conf = std::move(newres.config); loaded = std::move(newres.loading); this->wad = std::move(newres.waddata); if(main_win) testmap::updateMenuName(main_win->menu_bar, loaded); gLog.printf("--- DONE ---\n"); gLog.printf("\n"); } // on success if (removeEditWad) this->wad.master.RemoveEditWad(); else if (newEditWad) this->wad.master.ReplaceEditWad(newEditWad); level = std::move(newdoc.doc); if(!new_resources) // we already updated loaded with resources loaded = std::move(newdoc.loading); if(main_win) testmap::updateMenuName(main_win->menu_bar, loaded); refreshViewAfterLoad(newdoc.bad, wad.get(), map_name, new_resources); } void Instance::CMD_GivenFile() { SString mode = EXEC_Param[0]; int index = last_given_file; if (mode.empty() || mode.noCaseEqual("current")) { // index = index + 0; } else if (mode.noCaseEqual("next")) { index = index + 1; } else if (mode.noCaseEqual("prev")) { index = index - 1; } else if (mode.noCaseEqual("first")) { index = 0; } else if (mode.noCaseEqual("last")) { index = (int)global::Pwad_list.size() - 1; } else { Beep("GivenFile: unknown keyword: %s", mode.c_str()); return; } if (index < 0 || index >= (int)global::Pwad_list.size()) { Beep("No more files"); return; } last_given_file = index; // TODO: remember last map visited in this wad try { OpenFileMap(global::Pwad_list[index], NULL); } catch (const std::runtime_error& e) { gLog.printf("%s\n", e.what()); DLG_ShowError(false, "Cannot load given file %s: %s", global::Pwad_list[index].u8string().c_str(), e.what()); } } void Instance::CMD_FlipMap() { SString mode = EXEC_Param[0]; if (mode.empty()) { Beep("FlipMap: missing keyword"); return; } if (!level.Main_ConfirmQuit("open another map")) return; const Wad_file *wad = this->wad.master.activeWad().get(); // the level might not be found (lev_num < 0) -- that is OK int lev_idx = wad->LevelFind(loaded.levelName); int max_idx = wad->LevelCount() - 1; if (max_idx < 0) { Beep("No maps ?!?"); return; } SYS_ASSERT(lev_idx <= max_idx); if (mode.noCaseEqual("next")) { if (lev_idx < 0) lev_idx = 0; else if (lev_idx < max_idx) lev_idx++; else { Beep("No more maps"); return; } } else if (mode.noCaseEqual("prev")) { if (lev_idx < 0) lev_idx = max_idx; else if (lev_idx > 0) lev_idx--; else { Beep("No more maps"); return; } } else if (mode.noCaseEqual("first")) { lev_idx = 0; } else if (mode.noCaseEqual("last")) { lev_idx = max_idx; } else { Beep("FlipMap: unknown keyword: %s", mode.c_str()); return; } SYS_ASSERT(lev_idx >= 0); SYS_ASSERT(lev_idx <= max_idx); int lump_idx = wad->LevelHeader(lev_idx); Lump_c * lump = wad->GetLump(lump_idx); const SString &map_name = lump->Name(); gLog.printf("Flipping Map to : %s\n", map_name.c_str()); LoadLevel(wad, map_name); } //------------------------------------------------------------------------ // SAVING CODE //------------------------------------------------------------------------ int Document::SaveHeader(Wad_file& wad, const SString &level) const { int size = (int)headerData.size(); int saving_level; Lump_c *lump = wad.AddLevel(level, &saving_level); if (size > 0) { lump->Write(&headerData[0], size); } return saving_level; } void Document::SaveBehavior(Wad_file &wad) const { int size = (int)behaviorData.size(); Lump_c &lump = wad.AddLump("BEHAVIOR"); if (size > 0) { lump.Write(&behaviorData[0], size); } } void Document::SaveScripts(Wad_file& wad) const { int size = (int)scriptsData.size(); if (size > 0) { Lump_c &lump = wad.AddLump("SCRIPTS"); lump.Write(&scriptsData[0], size); } } void Document::SaveVertices(Wad_file &wad) const { Lump_c &lump = wad.AddLump("VERTEXES"); for (const auto &vert : vertices) { raw_vertex_t raw{}; raw.x = LE_S16(static_cast(vert->raw_x)); raw.y = LE_S16(static_cast(vert->raw_y)); lump.Write(&raw, sizeof(raw)); } } void Document::SaveSectors(Wad_file &wad) const { Lump_c &lump = wad.AddLump("SECTORS"); for (const auto& sec : sectors) { raw_sector_t raw{}; raw.floorh = LE_S16(sec->floorh); raw.ceilh = LE_S16(sec->ceilh); W_StoreString(raw.floor_tex, sec->FloorTex(), sizeof(raw.floor_tex)); W_StoreString(raw.ceil_tex, sec->CeilTex(), sizeof(raw.ceil_tex)); raw.light = LE_U16(sec->light); raw.type = LE_U16(sec->type); raw.tag = LE_U16(sec->tag); lump.Write(&raw, sizeof(raw)); } } void Document::SaveThings(Wad_file &wad) const { Lump_c &lump = wad.AddLump("THINGS"); for (const auto &th : things) { raw_thing_t raw{}; raw.x = LE_S16(static_cast(th->raw_x)); raw.y = LE_S16(static_cast(th->raw_y)); raw.angle = LE_U16(th->angle); raw.type = LE_U16(th->type); raw.options = LE_U16(th->options); lump.Write(&raw, sizeof(raw)); } } // IOANCH 9/2015 void Document::SaveThings_Hexen(Wad_file& wad) const { Lump_c &lump = wad.AddLump("THINGS"); for (const auto &th : things) { raw_hexen_thing_t raw{}; raw.tid = LE_S16(th->tid); raw.x = LE_S16(static_cast(th->raw_x)); raw.y = LE_S16(static_cast(th->raw_y)); raw.height = LE_S16(static_cast(th->raw_h)); raw.angle = LE_U16(th->angle); raw.type = LE_U16(th->type); raw.options = LE_U16(th->options); raw.special = static_cast(th->special); raw.args[0] = static_cast(th->arg1); raw.args[1] = static_cast(th->arg2); raw.args[2] = static_cast(th->arg3); raw.args[3] = static_cast(th->arg4); raw.args[4] = static_cast(th->arg5); lump.Write(&raw, sizeof(raw)); } } void Document::SaveSideDefs(Wad_file &wad) const { Lump_c &lump = wad.AddLump("SIDEDEFS"); for (const auto &side : sidedefs) { raw_sidedef_t raw{}; raw.x_offset = LE_S16(side->x_offset); raw.y_offset = LE_S16(side->y_offset); W_StoreString(raw.upper_tex, side->UpperTex(), sizeof(raw.upper_tex)); W_StoreString(raw.lower_tex, side->LowerTex(), sizeof(raw.lower_tex)); W_StoreString(raw.mid_tex, side->MidTex(), sizeof(raw.mid_tex)); raw.sector = LE_U16(side->sector); lump.Write(&raw, sizeof(raw)); } } void Document::SaveLineDefs(Wad_file &wad) const { Lump_c &lump = wad.AddLump("LINEDEFS"); for (const auto &ld : linedefs) { raw_linedef_t raw{}; raw.start = LE_U16(ld->start); raw.end = LE_U16(ld->end); raw.flags = LE_U16(ld->flags); raw.type = LE_U16(ld->type); raw.tag = LE_S16(ld->tag); raw.right = (ld->right >= 0) ? LE_U16(ld->right) : 0xFFFF; raw.left = (ld->left >= 0) ? LE_U16(ld->left) : 0xFFFF; lump.Write(&raw, sizeof(raw)); } } // IOANCH 9/2015 void Document::SaveLineDefs_Hexen(Wad_file &wad) const { Lump_c &lump = wad.AddLump("LINEDEFS"); for (const auto &ld : linedefs) { raw_hexen_linedef_t raw{}; raw.start = LE_U16(ld->start); raw.end = LE_U16(ld->end); raw.flags = LE_U16(ld->flags); raw.type = static_cast(ld->type); raw.args[0] = static_cast(ld->tag); raw.args[1] = static_cast(ld->arg2); raw.args[2] = static_cast(ld->arg3); raw.args[3] = static_cast(ld->arg4); raw.args[4] = static_cast(ld->arg5); raw.right = (ld->right >= 0) ? LE_U16(ld->right) : 0xFFFF; raw.left = (ld->left >= 0) ? LE_U16(ld->left) : 0xFFFF; lump.Write(&raw, sizeof(raw)); } } static void EmptyLump(Wad_file& wad, const char *name) { wad.AddLump(name); } void Instance::SaveLevel(LoadingData& loading, const SString &level, Wad_file &wad, bool inhibit_node_build) { // set global level name now (for debugging code) loading.levelName = level.asUpper(); // remove previous version of level (if it exists) int lev_num = wad.LevelFind(level); int level_lump = -1; if (lev_num >= 0) { level_lump = wad.LevelHeader(lev_num); wad.RemoveLevel(lev_num); } wad.InsertPoint(level_lump); int saving_level = this->level.SaveHeader(wad, level); if (loading.levelFormat == MapFormat::udmf) { UDMF_SaveLevel(loading, wad); } else { // IOANCH 9/2015: save Hexen format maps if (loading.levelFormat == MapFormat::hexen) { this->level.SaveThings_Hexen(wad); this->level.SaveLineDefs_Hexen(wad); } else { this->level.SaveThings(wad); this->level.SaveLineDefs(wad); } this->level.SaveSideDefs(wad); this->level.SaveVertices(wad); EmptyLump(wad, "SEGS"); EmptyLump(wad, "SSECTORS"); EmptyLump(wad, "NODES"); this->level.SaveSectors(wad); EmptyLump(wad, "REJECT"); EmptyLump(wad, "BLOCKMAP"); if (loading.levelFormat == MapFormat::hexen) { this->level.SaveBehavior(wad); this->level.SaveScripts(wad); } } // build the nodes if (config::bsp_on_save && ! inhibit_node_build) { BuildNodesAfterSave(saving_level, loading, wad); } // this is mainly for Next/Prev-map commands // [ it doesn't change the on-disk wad file at all ] wad.SortLevels(); loading.writeEurekaLump(wad); wad.writeToDisk(); } void Instance::ConfirmLevelSaveSuccess(const LoadingData &loading, const Wad_file &wad) { global::recent.addRecent(wad.PathName(), loading.levelName, global::home_dir); Status_Set("Saved %s", loading.levelName.c_str()); if (main_win) { main_win->SetTitle(wad.PathName().u8string(), loading.levelName, false); // save the user state associated with this map M_SaveUserState(); } this->level.MadeChanges = false; } // // Write out the level data // void Instance::SaveLevelAndUpdateWindow(LoadingData& loading, const SString &level, Wad_file &wad, bool inhibit_node_build) { SaveLevel(loading, level, wad, inhibit_node_build); ConfirmLevelSaveSuccess(loading, wad); } // these return false if user cancelled bool Instance::M_SaveMap(bool inhibit_node_build) { // we require a wad file to save into. // if there is none, then need to create one via Export function. if (!wad.master.editWad()) { return M_ExportMap(inhibit_node_build); } if (wad.master.editWad()->IsReadOnly()) { if (DLG_Confirm({ "Cancel", "&Export" }, "The current pwad is a READ-ONLY file. " "Do you want to export this map into a new file?") <= 0) { return false; } return M_ExportMap(inhibit_node_build); } M_BackupWad(wad.master.editWad().get()); gLog.printf("Saving Map : %s in %s\n", loaded.levelName.c_str(), wad.master.editWad()->PathName().u8string().c_str()); try { SaveLevelAndUpdateWindow(loaded, loaded.levelName, *wad.master.editWad(), inhibit_node_build); } catch(const std::runtime_error &e) { DLG_ShowError(false, "Could not save map: %s", e.what()); return false; } return true; } bool Instance::M_ExportMap(bool inhibit_node_build) { Fl_Native_File_Chooser chooser; chooser.title("Pick file to export to"); chooser.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); chooser.filter("Wads\t*.wad"); chooser.directory(Main_FileOpFolder().u8string().c_str()); // Show native chooser switch (chooser.show()) { case -1: gLog.printf("Export Map: error choosing file:\n"); gLog.printf(" %s\n", chooser.errmsg()); DLG_Notify("Unable to export the map:\n\n%s", chooser.errmsg()); return false; case 1: gLog.printf("Export Map: cancelled by user\n"); return false; default: break; // OK } // if extension is missing then add ".wad" fs::path filename = fs::u8path(chooser.filename()); fs::path extension = filename.extension(); if(extension.empty()) filename = fs::u8path(filename.u8string() + ".wad"); // don't export into a file we currently have open if (wad.master.MasterDir_HaveFilename(filename.u8string())) { DLG_Notify("Unable to export the map:\n\nFile already in use"); return false; } std::shared_ptr wad = Wad_file::Open(filename, WadOpenMode::append); if (!wad) { DLG_Notify("Unable to export the map:\n\n%s", "Error creating output file"); return false; } if (wad->IsReadOnly()) { DLG_Notify("Cannot export the map into a READ-ONLY file."); return false; } // adopt iwad/port/resources of the target wad LoadingData loading = loaded; if (wad->FindLump(EUREKA_LUMP)) { if (!loading.parseEurekaLump(global::home_dir, global::install_dir, global::recent, wad.get())) return false; } // ask user for map name SString map_name; { UI_ChooseMap dialog(loading.levelName.c_str()); dialog.PopulateButtons(static_cast(toupper(loading.levelName[0])), wad.get()); map_name = dialog.Run(); } // cancelled? if (map_name.empty()) { return false; } // we will write into the chosen wad. // however if the level already exists, get confirmation first if (wad->LevelFind(map_name) >= 0) { if (DLG_Confirm({ "Cancel", "&Overwrite" }, overwrite_message, "selected") <= 0) { return false; } } // back-up an existing wad if (wad->NumLumps() > 0) { M_BackupWad(wad.get()); } gLog.printf("Exporting Map : %s in %s\n", map_name.c_str(), wad->PathName().u8string().c_str()); try { SaveLevel(loading, map_name, *wad, inhibit_node_build); } catch(const std::runtime_error &e) { DLG_ShowError(false, "Could not export map: %s", e.what()); return false; } try { // do this after the save (in case it fatal errors) Main_LoadResources(loading); } catch(const std::runtime_error &e) { DLG_ShowError(false, "Successfully exported map, but could not load the new resources: %s", e.what()); return false; } // the new wad replaces the current PWAD this->wad.master.ReplaceEditWad(wad); ConfirmLevelSaveSuccess(loaded, *wad); return true; } void Instance::CMD_SaveMap() { M_SaveMap(false); } void Instance::CMD_ExportMap() { M_ExportMap(false); } //------------------------------------------------------------------------ // COPY, RENAME and DELETE MAP //------------------------------------------------------------------------ void Instance::CMD_CopyMap() { try { if (!wad.master.editWad()) { DLG_Notify("Cannot copy a map unless editing a PWAD."); return; } if (wad.master.editWad()->IsReadOnly()) { DLG_Notify("Cannot copy map: file is read-only."); return; } // ask user for map name SString new_name; { auto dialog = std::make_unique(loaded.levelName.c_str(), wad.master.editWad()); dialog->PopulateButtons(static_cast(toupper(loaded.levelName[0])), wad.master.editWad().get()); new_name = dialog->Run(); } // cancelled? if (new_name.empty()) return; // sanity check that the name is different // (should be prevented by the choose-map dialog) if (y_stricmp(new_name.c_str(), loaded.levelName.c_str()) == 0) { Beep("Name is same!?!"); return; } // perform the copy (just a save) gLog.printf("Copying Map : %s --> %s\n", loaded.levelName.c_str(), new_name.c_str()); SaveLevelAndUpdateWindow(loaded, new_name, *wad.master.editWad(), false); Status_Set("Copied to %s", loaded.levelName.c_str()); } catch (const std::runtime_error& e) { DLG_ShowError(false, "Could not copy map: %s", e.what()); } } void Instance::CMD_RenameMap() { tl::optional backupName; tl::optional backupIndex; try { if(!wad.master.gameWad()) { gLog.printf("No IWAD file!\n"); return; } if (!wad.master.editWad()) { DLG_Notify("Cannot rename a map unless editing a PWAD."); return; } if (wad.master.editWad()->IsReadOnly()) { DLG_Notify("Cannot rename map : file is read-only."); return; } // ask user for map name SString new_name; { auto dialog = std::make_unique(loaded.levelName.c_str(), wad.master.editWad() /* rename_wad */); // pick level format from the IWAD // [ user may be trying to rename map after changing the IWAD ] char format = 'M'; { int idx = wad.master.gameWad()->LevelFindFirst(); if (idx >= 0) { idx = wad.master.gameWad()->LevelHeader(idx); const SString& name = wad.master.gameWad()->GetLump(idx)->Name(); format = static_cast(toupper(name[0])); } } dialog->PopulateButtons(format, wad.master.editWad().get()); new_name = dialog->Run(); } // cancelled? if (new_name.empty()) return; // sanity check that the name is different // (should be prevented by the choose-map dialog) if (y_stricmp(new_name.c_str(), loaded.levelName.c_str()) == 0) { Beep("Name is same!?!"); return; } // perform the rename int lev_num = wad.master.editWad()->LevelFind(loaded.levelName); if (lev_num >= 0) { int level_lump = wad.master.editWad()->LevelHeader(lev_num); backupIndex = level_lump; backupName = wad.master.editWad()->GetLump(level_lump)->Name(); wad.master.editWad()->RenameLump(level_lump, new_name.c_str()); wad.master.editWad()->writeToDisk(); } loaded.levelName = new_name.asUpper(); main_win->SetTitle(wad.master.editWad()->PathName().u8string(), loaded.levelName, false); Status_Set("Renamed to %s", loaded.levelName.c_str()); } catch (const std::runtime_error& e) { if(backupIndex && backupName) wad.master.editWad()->RenameLump(*backupIndex, backupName->c_str()); DLG_ShowError(false, "Could not rename map: %s", e.what()); } } void Instance::CMD_DeleteMap() { if (!wad.master.editWad()) { DLG_Notify("Cannot delete a map unless editing a PWAD."); return; } if (wad.master.editWad()->IsReadOnly()) { DLG_Notify("Cannot delete map : file is read-only."); return; } if (wad.master.editWad()->LevelCount() < 2) { // perhaps ask either to Rename map, or Delete the file (and Eureka will shut down) DLG_Notify("Cannot delete the last map in a PWAD."); return; } if (DLG_Confirm({ "Cancel", "&Delete" }, "Are you sure you want to delete this map? " "It will be permanently removed from the current PWAD.") <= 0) { return; } gLog.printf("Deleting Map : %s...\n", loaded.levelName.c_str()); int lev_num = wad.master.editWad()->LevelFind(loaded.levelName); if (lev_num < 0) { Beep("No such map ?!?"); return; } M_BackupWad(wad.master.editWad().get()); // kick it to the curb int backupPoint = wad.master.editWad()->LevelHeader(lev_num); std::vector backupLumps = wad.master.editWad()->RemoveLevel(lev_num); try { wad.master.editWad()->writeToDisk(); } catch (const std::runtime_error& e) { // Restore deleted lumps wad.master.editWad()->InsertPoint(backupPoint); for (const Lump_c& backup : backupLumps) { if(&backup == &backupLumps[0]) wad.master.editWad()->AddLevel(backup.Name())->Write(backup.getData().data(), (int)backup.getData().size()); else wad.master.editWad()->AddLump(backup.Name()).Write(backup.getData().data(), (int)backup.getData().size()); } wad.master.editWad()->SortLevels(); DLG_ShowError(false, "Cannot delete map: %s", e.what()); return; } // choose a new level to load try { if (lev_num >= wad.master.editWad()->LevelCount()) lev_num = wad.master.editWad()->LevelCount() - 1; int lump_idx = wad.master.editWad()->LevelHeader(lev_num); const Lump_c* lump = wad.master.editWad()->GetLump(lump_idx); const SString& map_name = lump->Name(); gLog.printf("OK. Loading : %s....\n", map_name.c_str()); // TODO: overhaul the interface to NOT go back to the IWAD LoadLevel(wad.master.editWad().get(), map_name); } catch (const std::runtime_error& e) { DLG_ShowError(false, "Failed changing map after deleting a level: %s\n\nThe PWAD will be closed.", e.what()); if (!wad.master.gameWad()) throw; int lump_idx = wad.master.gameWad()->LevelHeader(0); const Lump_c* lump = wad.master.gameWad()->GetLump(lump_idx); if (!lump) throw; wad.master.RemoveEditWad(); const SString& map_name = lump->Name(); LoadLevel(wad.master.gameWad().get(), map_name); } } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_loadsave.h000066400000000000000000000053441464327712600206210ustar00rootroot00000000000000//------------------------------------------------------------------------ // LEVEL LOAD / SAVE / NEW //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_E_LOADSAVE_H__ #define __EUREKA_E_LOADSAVE_H__ #include "Document.h" #include "m_game.h" #include "w_wad.h" #include "WadData.h" #include class RecentKnowledge; // // Background loading data for Main_LoadResources // struct LoadingData { std::unordered_map prepareConfigVariables() const; bool parseEurekaLump(const fs::path &home_dir, const fs::path &install_dir, const RecentKnowledge &recent, const Wad_file *wad, bool keep_cmd_line_args = false); void writeEurekaLump(Wad_file &wad) const; SString gameName; // Name of game "doom", "doom2", "heretic", ... SString portName; // Name of source port "vanilla", "boom", ... fs::path iwadName; // Filename of the iwad SString levelName; // Name of map lump we are editing SString udmfNamespace; // for UDMF, the current namespace std::vector resourceList; MapFormat levelFormat = {}; // format of current map SString testingCommandLine; // command-line for testing map (stored in Eureka lump due to possible port and mod-specific features) }; struct NewResources { ConfigData config; LoadingData loading; WadData waddata; }; struct BadCount { bool exists() const { return linedef_count || sector_refs || sidedef_refs; } int linedef_count; int sector_refs; int sidedef_refs; }; struct NewDocument { Document doc; LoadingData loading; BadCount bad; }; void OpenFileMap(const fs::path &filename, const SString &map_name = "") noexcept(false); const Lump_c *Load_LookupAndSeek(int loading_level, const Wad_file *load_wad, const char *name); #endif /* __EUREKA_E_LOADSAVE_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_nodes.cc000066400000000000000000000211441464327712600202650ustar00rootroot00000000000000//------------------------------------------------------------------------ // BUILDING NODES / PLAY THE MAP //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2019 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include "m_config.h" #include "m_loadsave.h" #include "e_main.h" #include "w_wad.h" #include "ui_window.h" #include "bsp.h" // config items bool config::bsp_on_save = true; bool config::bsp_fast = false; bool config::bsp_warnings = false; int config::bsp_split_factor = DEFAULT_FACTOR; bool config::bsp_gl_nodes = true; bool config::bsp_force_v5 = false; bool config::bsp_force_zdoom = false; bool config::bsp_compressed = false; #define NODE_PROGRESS_COLOR fl_color_cube(2,6,2) // // Callbacks // void UI_NodeDialog::close_callback(Fl_Widget *w, void *data) { UI_NodeDialog * that = (UI_NodeDialog *)data; that->want_close = true; if (! that->finished) that->want_cancel = true; } void UI_NodeDialog::button_callback(Fl_Widget *w, void *data) { UI_NodeDialog * that = (UI_NodeDialog *)data; if (that->finished) that->want_close = true; else that->want_cancel = true; } // // Constructor // UI_NodeDialog::UI_NodeDialog() : Fl_Double_Window(400, 400, "Building Nodes") { size_range(w(), h()); callback((Fl_Callback *) close_callback, this); color(WINDOW_BG, WINDOW_BG); browser = new Fl_Browser(0, 0, w(), h() - 100); Fl_Box * ptext = new Fl_Box(FL_NO_BOX, 10, h() - 80, 80, 20, "Progress:"); (void) ptext; progress = new Fl_Progress(100, h() - 80, w() - 120, 20); progress->align(FL_ALIGN_INSIDE); progress->box(FL_FLAT_BOX); progress->color(FL_LIGHT2, NODE_PROGRESS_COLOR); progress->minimum(0.0); progress->maximum(100.0); progress->value(0.0); button = new Fl_Button(w() - 100, h() - 46, 80, 30, "Cancel"); button->callback(button_callback, this); end(); resizable(browser); } int UI_NodeDialog::handle(int event) { if (event == FL_KEYDOWN && Fl::event_key() == FL_Escape) { if (finished) want_close = true; else want_cancel = true; return 1; } return Fl_Double_Window::handle(event); } void UI_NodeDialog::SetProg(int perc) { if (perc == cur_prog) return; cur_prog = perc; snprintf(prog_label, sizeof(prog_label), "%d%%", perc); progress->value(static_cast(perc)); progress->label(prog_label); Fl::check(); } void UI_NodeDialog::Print(const char *str) { // split lines static char buffer[256]; snprintf(buffer, sizeof(buffer), "%s", str); buffer[sizeof(buffer) - 1] = 0; char * pos = buffer; char * next; while (pos && *pos) { next = strchr(pos, '\n'); if (next) *next++ = 0; browser->add(pos); pos = next; } browser->bottomline(browser->size()); Fl::check(); } void UI_NodeDialog::Finish_OK() { finished = true; button->label("Close"); progress->value(100); progress->label("Success"); progress->color(FL_BLUE, FL_BLUE); } void UI_NodeDialog::Finish_Cancel() { finished = true; button->label("Close"); progress->value(0); progress->label("Cancelled"); progress->color(FL_RED, FL_RED); } void UI_NodeDialog::Finish_Error() { finished = true; button->label("Close"); progress->value(100); progress->label("ERROR"); progress->color(FL_RED, FL_RED); } //------------------------------------------------------------------------ static const char *build_ErrorString(build_result_e ret) { switch (ret) { case BUILD_OK: return "OK"; // building was cancelled case BUILD_Cancelled: return "Cancelled by User"; // the WAD file was corrupt / empty / bad filename case BUILD_BadFile: return "Bad File"; default: return "Unknown Error"; } } void Instance::GB_PrintMsg(EUR_FORMAT_STRING(const char *str), ...) { va_list args; va_start(args, str); SString message_buf = SString::vprintf(str, args); va_end(args); if (nodeialog) nodeialog->Print(message_buf.c_str()); gLog.printf("BSP: %s\n", message_buf.c_str()); } static void PrepareInfo(nodebuildinfo_t *info) { info->factor = clamp(1, config::bsp_split_factor, 31); info->gl_nodes = config::bsp_gl_nodes; info->fast = config::bsp_fast; info->warnings = config::bsp_warnings; info->force_v5 = config::bsp_force_v5; info->force_xnod = config::bsp_force_zdoom; info->force_compress = config::bsp_compressed; info->total_failed_maps = 0; info->total_warnings = 0; // clear cancelled flag info->cancelled = false; } build_result_e Instance::BuildAllNodes(nodebuildinfo_t *info) { gLog.printf("\n"); // sanity check SYS_ASSERT(1 <= info->factor && info->factor <= 32); int num_levels = wad.master.editWad()->LevelCount(); SYS_ASSERT(num_levels > 0); GB_PrintMsg("\n"); nodeialog->SetProg(0); build_result_e ret; // loop over each level in the wad for (int n = 0 ; n < num_levels ; n++) { // load level try { NewDocument newdoc = openDocument(loaded, *wad.master.editWad(), n); ret = AJBSP_BuildLevel(info, n, *this, newdoc.doc, newdoc.loading, *wad.master.editWad()); } catch(const std::runtime_error &e) { GB_PrintMsg("Failed building nodes for level %d: %s\n", n, e.what()); continue; } // don't fail on maps with overflows // [ Note that 'total_failed_maps' keeps a tally of these ] if (ret == BUILD_LumpOverflow) ret = BUILD_OK; if (ret != BUILD_OK) break; nodeialog->SetProg(100 * (n + 1) / num_levels); Fl::check(); if (nodeialog->WantCancel()) { nb_info->cancelled = true; } } try { wad.master.editWad()->writeToDisk(); } catch(const std::runtime_error &e) { GB_PrintMsg("ERROR: could not save %s: %s\n", wad.master.editWad()->PathName().u8string().c_str(), e.what()); ret = BUILD_BadFile; } if (ret == BUILD_OK) { GB_PrintMsg("\n"); if (info->total_failed_maps == 0) GB_PrintMsg("All maps built successfully, %d warnings\n", info->total_warnings); else GB_PrintMsg("%d failed maps, %d warnings\n", info->total_failed_maps, info->total_warnings); } else if (ret == BUILD_Cancelled) { GB_PrintMsg("\n"); GB_PrintMsg("Building CANCELLED.\n\n"); } else { // build nodes failed GB_PrintMsg("\n"); GB_PrintMsg("Building FAILED: %s\n", build_ErrorString(ret)); } return ret; } void Instance::BuildNodesAfterSave(int lev_idx, const LoadingData& loading, Wad_file &wad) { nodeialog.reset(); nodebuildinfo_t nb_info; PrepareInfo(&nb_info); build_result_e ret = AJBSP_BuildLevel(&nb_info, lev_idx, *this, level, loading, wad); // TODO : maybe print # of serious/minor warnings if (ret != BUILD_OK) gLog.printf("NODES FAILED TO FAILED.\n"); } void Instance::CMD_BuildAllNodes() { if (!wad.master.editWad()) { DLG_Notify("Cannot build nodes unless you are editing a PWAD."); return; } if (wad.master.editWad()->IsReadOnly()) { DLG_Notify("Cannot build nodes on a read-only file."); return; } if (level.MadeChanges) { if (DLG_Confirm({ "Cancel", "&Save" }, "You have unsaved changes, do you want to save them now " "and then build all the nodes?") <= 0) { return; } bool save_result = M_SaveMap(true); // user cancelled the save? if (!save_result) return; } // this probably cannot happen, but check anyway if (wad.master.editWad()->LevelCount() == 0) { DLG_Notify("Cannot build nodes: no levels found!"); return; } // remember current level SString CurLevel(loaded.levelName); // reset various editor state Editor_ClearAction(); Selection_InvalidateLast(); edit.Selected->clear_all(); edit.highlight.clear(); nodeialog.emplace(); nodeialog->set_modal(); nodeialog->show(); Fl::check(); nodebuildinfo_t nb_info; PrepareInfo(&nb_info); build_result_e ret = BuildAllNodes(&nb_info); if (ret == BUILD_OK) { nodeialog->Finish_OK(); Status_Set("Built nodes OK"); } else if (nb_info.cancelled) { nodeialog->Finish_Cancel(); Status_Set("Cancelled building nodes"); } else { nodeialog->Finish_Error(); Status_Set("Error building nodes"); } while (!nodeialog->WantClose()) { Fl::wait(0.2); } nodeialog.reset(); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_nodes.h000066400000000000000000000031751464327712600201330ustar00rootroot00000000000000//------------------------------------------------------------------------ // BUILDING NODES / PLAY THE MAP //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2023 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #pragma once #include #include #include #include #include class UI_NodeDialog : public Fl_Double_Window { public: Fl_Browser *browser; Fl_Progress *progress; Fl_Button * button; int cur_prog = -1; char prog_label[64]; bool finished = false; bool want_cancel = false; bool want_close = false; public: UI_NodeDialog(); /* FLTK method */ int handle(int event); public: void SetProg(int perc); void Print(const char *str); void Finish_OK(); void Finish_Cancel(); void Finish_Error(); bool WantCancel() const { return want_cancel; } bool WantClose() const { return want_close; } private: static void close_callback(Fl_Widget *, void *); static void button_callback(Fl_Widget *, void *); }; eureka-editor-eureka-2.0.2/src/m_parse.cc000066400000000000000000000105621464327712600202710ustar00rootroot00000000000000//------------------------------------------------------------------------ // STRING PARSING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2021 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "m_parse.h" #include "Errors.h" #include "m_strings.h" #include "sys_debug.h" // // returns number of tokens, zero for comment, negative on error // int M_ParseLine(const SString &cline, std::vector &tokens, ParseOptions options) { // when do_strings == 2, string tokens keep their quotes. SString tokenbuf; tokenbuf.reserve(256); bool nexttoken = true; bool in_string = false; tokens.clear(); // skip leading whitespace SString line = cline; line.trimLeadingSpaces(); line.trimTrailingSpaces(); // blank line or comment line? if (line.empty() || line[0] == '#') return 0; for(size_t i = 0; i <= line.size(); ++i) { // This will also cover the null terminator char ch = line.c_str()[i]; if (nexttoken) // looking for a new token { SYS_ASSERT(!in_string); // end of line? if yes, break out of for loop if (ch == 0 || ch == '\n') break; if (isspace(ch)) continue; nexttoken = false; // begin a string? if (ch == '"' && options != ParseOptions::noStrings) { in_string = true; if (options != ParseOptions::haveStringsKeepQuotes) continue; } // begin a normal token tokenbuf.push_back(ch); continue; } if (in_string && ch == '"') { // end of string in_string = false; if (options == ParseOptions::haveStringsKeepQuotes) tokenbuf.push_back(ch); } else if (ch == 0 || ch == '\n') { // end of line } else if (! in_string && isspace(ch)) { // end of token } else { tokenbuf.push_back(ch); continue; } if (in_string) // ERROR: non-terminated string return ParseLine_stringError; nexttoken = true; tokens.push_back(tokenbuf); tokenbuf.clear(); // end of line? if yes, we are done if (ch == 0 || ch == '\n') break; } return static_cast(tokens.size()); } // // Get the next word from a token list // bool TokenWordParse::getNext(SString &word) { SString item; for(; mPos < (int)mLine.length(); ++mPos) { char c = mLine[mPos]; switch(mState) { case State::open: if(isspace(c)) continue; if(c == '"') { mState = State::multiWord; continue; } if(mHasComments && c == '#') { mState = State::comment; return false; } mState = State::singleWord; item.push_back(c); continue; case State::singleWord: if(isspace(c)) { mState = State::open; ++mPos; word = std::move(item); return true; } if(c == '"') { mState = State::multiWord; ++mPos; word = std::move(item); return true; } if(mHasComments && c == '#') { mState = State::comment; word = std::move(item); return true; } item.push_back(c); continue; case State::multiWord: if(c == '"') { mState = State::firstQuoteInString; continue; } item.push_back(c); continue; case State::firstQuoteInString: if(c == '"') { item.push_back('"'); mState = State::multiWord; continue; } if(mHasComments && c == '#') { mState = State::comment; word = std::move(item); return true; } mState = State::open; word = std::move(item); return true; case State::comment: return false; } } // Now past the end switch(mState) { case State::open: case State::comment: break; case State::singleWord: case State::multiWord: case State::firstQuoteInString: word = std::move(item); mState = State::open; return true; } return false; } bool TokenWordParse::getNext(fs::path &path) { SString word; bool result = getNext(word); if(result) path = fs::u8path(word.get()); return result; } eureka-editor-eureka-2.0.2/src/m_parse.h000066400000000000000000000036061464327712600201340ustar00rootroot00000000000000//------------------------------------------------------------------------ // STRING PARSING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2021 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "m_strings.h" #include #include "filesystem.hpp" namespace fs = ghc::filesystem; class SString; // // Options for M_ParseLine // enum class ParseOptions { noStrings, haveStrings, haveStringsKeepQuotes, }; enum { ParseLine_stringError = -3, // return value in case of unterminated string }; int M_ParseLine(const SString &cline, std::vector &tokens, ParseOptions options); // // Line of token words. A token word if it has spaces will be surrounded by // quotes. Any literal quotes within it will be doubled. A word without spaces // but with a literal quote will have that quote doubled and the word itself // within quotes. // class TokenWordParse { public: TokenWordParse(const SString &line, bool hasComments) : mLine(line), mHasComments(hasComments) { } bool getNext(SString &word); bool getNext(fs::path &path); private: enum class State { open, singleWord, multiWord, firstQuoteInString, comment, }; const SString mLine; int mPos = 0; State mState = State::open; // state can be left in other states bool mHasComments = false; }; eureka-editor-eureka-2.0.2/src/m_select.cc000066400000000000000000000176351464327712600204460ustar00rootroot00000000000000//------------------------------------------------------------------------ // SELECTION SET //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Errors.h" #include "sys_debug.h" #include "m_select.h" //#define NEED_SLOW_CLEAR #define INITIAL_BITVEC_SIZE 1024 #define INITIAL_EXTENDED_SIZE 256 selection_c::selection_c(ObjType type, bool extended) : type(type) { if(extended) { this->extended.emplace(INITIAL_EXTENDED_SIZE); } } void selection_c::change_type(ObjType new_type) noexcept { type = new_type; clear_all(); } bool selection_c::empty() const noexcept { return count == 0; } int selection_c::count_obj() const { return count; } bool selection_c::get(int n) const noexcept { if (extended) return get_ext(n) != 0; if (bv) return bv->get(n); for (int i = 0 ; i < count ; i++) if (objs[i] == n) return true; return false; } void selection_c::set(int n) { if (extended) { set_ext(n, 1); return; } if (get(n)) return; if (maxobj < n) maxobj = n; if (first_obj < 0 && empty()) first_obj = n; if (!bv && count >= MAX_STORE_SEL) { ConvertToBitvec(); } if (bv) { bv->set(n); count++; return; } objs[count++] = n; } void selection_c::clear(int n) noexcept { if (extended) { if (get_ext(n) == 0) return; // n should be safe to access directly, due to above check (*extended)[n] = 0; count--; } else if (bv) { if (! get(n)) return; bv->clear(n); count--; } else { int i; for (i = 0 ; i < count ; i++) if (objs[i] == n) break; if (i >= count) return; // not present count--; #ifdef NEED_SLOW_CLEAR for ( ; i < count ; i++) objs[i] = objs[i+1]; #else if (i < count) objs[i] = objs[count]; #endif } if (maxobj == n) RecomputeMaxObj(); if (first_obj == n) first_obj = -1; } void selection_c::toggle(int n) { if (get(n)) clear(n); else set(n); } void selection_c::clear_all() noexcept { count = 0; maxobj = -1; first_obj = -1; if (extended) { std::fill(extended->begin(), extended->end(), 0); } bv.reset(); } byte selection_c::get_ext(int n) const noexcept { if (! extended) return get(n) ? 255 : 0; if (n >= (int)extended->size()) return 0; return (*extended)[n]; } void selection_c::set_ext(int n, byte value) { // set_ext() should not be used with plain selections if (! extended) return; if (value == 0) { clear(n); return; } if (maxobj < n) maxobj = n; if (first_obj < 0 && empty()) first_obj = n; // need to resize the array? while (n >= (int)extended->size()) { ResizeExtended((int)extended->size() * 2); } if ((*extended)[n] == 0) count++; (*extended)[n] = value; } void selection_c::frob(int n, BitOp op) { switch (op) { case BitOp::add: set(n); break; case BitOp::remove: clear(n); break; default: toggle(n); break; } } void selection_c::frob_range(int n1, int n2, BitOp op) { for ( ; n1 <= n2 ; n1++) { frob(n1, op); } } void selection_c::merge(const selection_c& other) { if (extended && other.extended) { for (int i = 0 ; i <= other.maxobj ; i++) { byte value = other.get_ext(i); set_ext(i, get_ext(i) | value); } } else if (other.bv || other.extended) { for (int i = 0 ; i <= other.maxobj ; i++) if (other.get(i) && !get(i)) set(i); } else { for (int i = 0 ; i < other.count ; i++) if (!get(other.objs[i])) set(other.objs[i]); } } void selection_c::unmerge(const selection_c& other) { if (other.bv || other.extended) { for (int i = 0 ; i <= other.maxobj ; i++) if (other.get(i)) clear(i); } else { for (int i = 0 ; i < other.count ; i++) clear(other.objs[i]); } } void selection_c::intersect(const selection_c& other) { for (int i = 0 ; i <= maxobj ; i++) if (get(i) && !other.get(i)) clear(i); } bool selection_c::test_equal(const selection_c& other) { if (type != other.type) return false; if (maxobj != other.maxobj) return false; if (count_obj() != other.count_obj()) return false; // the quick tests have passed, now perform the expensive one for (sel_iter_c it(this) ; !it.done() ; it.next()) if (! other.get(*it)) return false; return true; } void selection_c::ConvertToBitvec() { SYS_ASSERT(! bv); int size = INITIAL_BITVEC_SIZE; if (size < maxobj+1) size = maxobj+1; bv.emplace(size); for (int i = 0 ; i < count ; i++) { bv->set(objs[i]); } } void selection_c::RecomputeMaxObj() noexcept { maxobj = -1; if (extended) { // search backwards so we can early out for (int i = (int)extended->size() - 1; i >= 0; i--) { if (get_ext(i)) { maxobj = i; break; } } } else if (bv) { // search backwards so we can early out for (int i = bv->size()-1 ; i >= 0 ; i--) { if (bv->get(i)) { maxobj = i; break; } } } else { // cannot optimise here, values are not sorted for (int i = 0 ; i < count ; i++) { maxobj = std::max(maxobj, objs[i]); } } } void selection_c::ResizeExtended(int new_size) { SYS_ASSERT(new_size > 0); extended->resize(new_size); } int selection_c::find_first() const { if (first_obj >= 0) { SYS_ASSERT(get(first_obj)); return first_obj; } sel_iter_c it(this); return it.done() ? -1 : *it; } int selection_c::find_second() const { sel_iter_c it(this); if (it.done()) return -1; // the logic here is trickier than it looks. // // When first_obj exists AND is the same as the very first object // in the group, then this test fails and we move onto the next // object in the group. if (first_obj >= 0 && *it != first_obj) return *it; it.next(); return it.done() ? -1 : *it; } // // Converts selection to array list. // std::vector selection_c::asArray() const { std::vector result; result.reserve(count_obj()); for(sel_iter_c it(this); !it.done(); it.next()) { result.push_back(*it); } return result; } //------------------------------------------------------------------------ // ITERATOR STUFF //------------------------------------------------------------------------ sel_iter_c::sel_iter_c(const selection_c *_sel) : sel(_sel), pos(0) { if (sel->bv || sel->extended) { // for bit vector, need to find the first one bit. // Note: this logic is slightly hacky... pos = -1; next(); } } sel_iter_c::sel_iter_c(const selection_c& _sel) : sel(&_sel), pos(0) { if (sel->bv || sel->extended) { pos = -1; next(); } } bool sel_iter_c::done() const { SYS_ASSERT(sel); if (sel->extended) return (pos >= (int)sel->extended->size()); else if (sel->bv) return (pos >= sel->bv->size()); else return (pos >= sel->count); } int sel_iter_c::operator* () const { SYS_ASSERT(sel); if (sel->bv || sel->extended) return pos; else return sel->objs[pos]; } void sel_iter_c::next() { SYS_ASSERT(sel); pos++; if (sel->extended) { while (pos < (int)sel->extended->size() && (*sel->extended)[pos] == 0) pos++; } else if (sel->bv) { // this could be optimised.... while (pos < sel->bv->size() && !sel->bv->get(pos)) pos++; } } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_select.h000066400000000000000000000102151464327712600202730ustar00rootroot00000000000000//------------------------------------------------------------------------ // SELECTION SET //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_M_SELECT_H__ #define __EUREKA_M_SELECT_H__ #include "m_bitvec.h" #include "objid.h" #include #include "tl/optional.hpp" class sel_iter_c; #define MAX_STORE_SEL 24 class selection_c { friend class sel_iter_c; private: ObjType type; // number of objects in the selection int count = 0; int objs[MAX_STORE_SEL] = {}; // use a bit vector when needed, NULL otherwise tl::optional bv; // an extended mode selection can access 8-bits per object tl::optional> extended; // the highest object in the selection, or -1 int maxobj = -1; // the very first object selected, or -1. // NOTE: this is only updated on a set() when selection is empty. int first_obj = -1; public: selection_c(ObjType type = ObjType::things, bool extended = false); selection_c(const selection_c &other) = default; selection_c(selection_c &&other) = default; selection_c &operator = (selection_c &&other) = default; ObjType what_type() const { return type; } // this also clears the selection void change_type(ObjType new_type) noexcept; void clear_all() noexcept; bool empty() const noexcept; bool notempty() const noexcept { return ! empty(); } // return the number of selected objects int count_obj() const; // return the highest selected object, or -1 if none int max_obj() const { return maxobj; } bool get(int n) const noexcept; void set(int n); void clear(int n) noexcept; void toggle(int n); // in extended mode, we can read and write 8-bits per object. // using set_ext() with zero value is equivalent to a clear(). // NOTE: using these on normal selections is not guaranteed // to do anything useful. byte get_ext(int n) const noexcept; void set_ext(int n, byte value); void frob(int n, BitOp op); void frob_range(int n1, int n2, BitOp op); // set all the objects from the other selection void merge(const selection_c& other); // clear all the objects from the other selection void unmerge(const selection_c& other); // only keep values that are in both selections void intersect(const selection_c& other); bool test_equal(const selection_c& other); // these return -1 if there is no first or second int find_first() const; int find_second() const; std::vector asArray() const; private: void ConvertToBitvec(); void RecomputeMaxObj() noexcept; void ResizeExtended(int new_size); }; class sel_iter_c { private: const selection_c *sel = nullptr; // this is position in the objs[] array when there is no // bit vector, otherwise it is the object number itself // (and the corresponding bit will be one). int pos = -777777; // dummy values -- cannot use a bare iterator public: // creates an iterator object for iterating over all the // object numbers contained in the given selection. // NOTE: modifying the selection is NOT ALLOWED during a traversal. explicit sel_iter_c(const selection_c *_sel); explicit sel_iter_c(const selection_c& _sel); bool done() const; void next(); int operator* () const; }; #endif /* __EUREKA_M_SELECT_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_streams.cc000066400000000000000000000030431464327712600206310ustar00rootroot00000000000000//------------------------------------------------------------------------ // STREAMS HANDLING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2021 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "m_streams.h" #include "m_strings.h" // // this automatically strips CR/LF from the line. // returns true if ok, false on EOF or error. // bool M_ReadTextLine(SString &string, std::istream &is) { string.clear(); std::getline(is, string.get()); if(is.bad() || is.fail()) return false; if(is.eof() && string.empty()) return false; if(string.substr(0, 3) == "\xef\xbb\xbf") string.erase(0, 3); string.trimTrailingSpaces(); return true; } // // Opens the file // bool LineFile::open(const fs::path &path) noexcept { is.close(); is.open(path); return is.is_open(); } // // Close if out of scope // void LineFile::close() noexcept { if(is.is_open()) is.close(); } eureka-editor-eureka-2.0.2/src/m_streams.h000066400000000000000000000032021464327712600204700ustar00rootroot00000000000000//------------------------------------------------------------------------ // STREAMS HANDLING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2021 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef M_STREAMS_H_ #define M_STREAMS_H_ #include #include #include "filesystem.hpp" namespace fs = ghc::filesystem; class SString; // returns true if ok, false on EOF or error bool M_ReadTextLine(SString &string, std::istream &is); // // File to be read by line (encapsulated) // class LineFile { public: // // Read one line // bool readLine(SString &line) { return M_ReadTextLine(line, is); } bool open(const fs::path &path) noexcept; void close() noexcept; LineFile() = default; explicit LineFile(const fs::path &path) noexcept { open(path); } ~LineFile() noexcept { close(); } // // Easy check // bool isOpen() const noexcept { return is.is_open(); } private: std::ifstream is; }; #endif eureka-editor-eureka-2.0.2/src/m_strings.cc000066400000000000000000000235201464327712600206460ustar00rootroot00000000000000//------------------------------------------------------------------------ // STRING TABLE //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2009 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include "m_strings.h" #include "sys_debug.h" #include #include #ifdef _WIN32 #include #endif //------------------------------------------------------------------------ // // a case-insensitive strcmp() // int y_stricmp(const char *s1, const char *s2) noexcept { for (;;) { if (tolower(*s1) != tolower(*s2)) return (int)(unsigned char)(tolower(*s1)) - (int)(unsigned char)(tolower(*s2)); if (*s1 && *s2) { s1++; s2++; continue; } // both *s1 and *s2 must be zero return 0; } } // // a case-insensitive strncmp() // int y_strnicmp(const char *s1, const char *s2, size_t len) noexcept { SYS_ASSERT(len != 0); while (len-- > 0) { if (tolower(*s1) != tolower(*s2)) return (int)(unsigned char)(tolower(*s1)) - (int)(unsigned char)(tolower(*s2)); if (*s1 && *s2) { s1++; s2++; continue; } // both *s1 and *s2 must be zero return 0; } return 0; } // // upper-case a string (in situ) // void y_strupr(char *str) { for ( ; *str ; str++) { *str = static_cast(toupper(*str)); } } // // lower-case a string (in situ) // void y_strlowr(char *str) { for ( ; *str ; str++) { *str = static_cast(tolower(*str)); } } char *StringNew(int length) { // length does not include the trailing NUL. SYS_ASSERT(length >= 0); char *s = (char *) calloc(length + 1, 1); if (! s) ThrowException("Out of memory (%d bytes for string)\n", length); return s; } char *StringDup(const char *orig, int limit) { if (! orig) return nullptr; if (limit < 0) { auto s = static_cast(malloc(strlen(orig) + 1)); if (! s) ThrowException("Out of memory (copy string)\n"); strcpy(s, orig); return s; } char * s = StringNew(limit+1); strncpy(s, orig, limit); s[limit] = 0; return s; } // // Safe, cross-platform version of strncpy // void StringCopy(char *buffer, size_t size, const SString &source) { if(!size) return; // trivial strncpy(buffer, source.c_str(), size); buffer[size - 1] = 0; } // // Produces a string by joining multiple substrings by a separator // SString joined(const char *sep, const char **strlist, int listlen) { assert(sep && strlist); SString result; for(int i = 0; i < listlen; ++i) { if(i >= 1) result += sep; assert(strlist[i]); result += strlist[i]; } return result; } // // Make a SString from printf format // SString SString::printf(EUR_FORMAT_STRING(const char *format), ...) { // Algorithm: keep doubling the allocated buffer size // until the output fits. Based on code by Darren Salt. char *buf = NULL; int buf_size = 128; for (;;) { va_list args; int out_len; buf_size *= 2; buf = (char*)realloc(buf, buf_size); if (!buf) ThrowException("Out of memory (formatting string)\n"); va_start(args, format); out_len = vsnprintf(buf, buf_size, format, args); va_end(args); // old versions of vsnprintf() simply return -1 when // the output doesn't fit. if (out_len < 0 || out_len >= buf_size) continue; SString result(buf); free(buf); return result; } } SString SString::vprintf(const char *format, va_list ap) { // Algorithm: keep doubling the allocated buffer size // until the output fits. Based on code by Darren Salt. std::vector buf; int buf_size = 128; for (;;) { int out_len; buf_size *= 2; buf.resize(buf_size); out_len = vsnprintf(buf.data(), buf_size, format, ap); // old versions of vsnprintf() simply return -1 when // the output doesn't fit. if (out_len < 0 || out_len >= buf_size) continue; SString result(buf.data()); return result; } } // // Checks if a string ends with, no-case // bool SString::noCaseEndsWith(const SString &text) const { if(text.empty()) return true; size_t textLength = text.length(); if(length() < textLength) return false; return !y_stricmp(c_str() + length() - textLength, text.c_str()); } // // Constructs a string from a raw buffer with limited length // Unlike std::string, this one trims the string at any potential NUL // SString::SString(const char *buffer, int length) { if(!buffer || length <= 0) { data = ""; return; } data.reserve(length); for(int i = 0; i < length; ++i) { if(!buffer[i]) break; data.push_back(buffer[i]); } } // // Cuts a string at position "pos", removing the respective character too // void SString::getCutWithSpace(size_t pos, SString *word0, SString *word1) const { SYS_ASSERT(pos < length()); if(word0) *word0 = SString(data.substr(0, pos)); if(word1) *word1 = SString(data.substr(pos + 1)); } // // This one cuts self // void SString::cutWithSpace(size_t pos, SString *second) { SYS_ASSERT(pos < length()); if(second) *second = SString(data.substr(pos + 1)); erase(pos, npos); } // // Trim leading spaces // void SString::trimLeadingSpaces() { size_t i = 0; for(i = 0; i < length(); ++i) if(!isspace(data[i])) break; if(i) erase(0, i); } // // Trim trailing spaces // void SString::trimTrailingSpaces() { while(good() && isspace(data.back())) data.pop_back(); } // // Trim trailing characters from set // void SString::trimTrailingSet(const char *set) { while(good() && strchr(set, data.back())) data.pop_back(); } // // As title // SString SString::asTitle() const { SString result(*this); if(result.good()) result[0] = static_cast(toupper(result[0])); return result; } // // Lower case // SString SString::asLower() const { SString result(*this); for(char &c : result) c = static_cast(tolower(c)); return result; } // // Upper case // SString SString::asUpper() const { SString result(*this); for(char &c : result) c = static_cast(toupper(c)); return result; } // // Get the version with just the printable characters and without the included bad characters. // SString SString::getTidy(const char *badChars) const { SString buf; buf.reserve(length() + 2); for(const char &c : *this) if(isprint(c) && (!badChars || !strchr(badChars, c))) buf.push_back(c); return buf; } // // Finds the first space // size_t SString::findSpace() const { for(size_t i = 0; i < length(); ++i) { if(isspace(data[i])) return i; } return std::string::npos; } size_t SString::findDigit() const { for(size_t i = 0; i < length(); ++i) { if(isdigit(data[i])) return i; } return std::string::npos; } // // Add a text // StringID StringTable::add(const SString &text) { int index = 0; for(const SString &string : mStrings) { if(string == text) // this should also cover "" === 0 return StringID(index); ++index; } mStrings.push_back(text); return StringID((int)mStrings.size() - 1); } // // Get a text (handle it robustly) // SString StringTable::get(StringID offset) const noexcept { // this should never happen // [ but handle it gracefully, for the sake of robustness ] if(offset.isInvalid() || offset.get() >= (int)mStrings.size()) return "???ERROR"; return mStrings[offset.get()]; } // // If string has spaces, surrounds it in double quotes. If there are any quotes, it doubles them (MS-DOS convention) // SString SString::spaceEscape(bool backslash) const { if(empty()) return "\"\""; bool needsQuotes = false; for(char c : data) if(isspace(c) || c == '"' || c == '#') { needsQuotes = true; break; } SString result(*this); if(needsQuotes) { size_t pos = std::string::npos; while((pos = result.data.find('"', pos == std::string::npos ? 0 : pos + 2)) != std::string::npos) result.data.insert(result.data.begin() + pos, backslash ? '\\' : '"'); return "\"" + result + "\""; } return result; } #ifdef _WIN32 // // Fail safe so we avoid failures // static SString FailSafeWideToUTF8(const wchar_t *text) { size_t len = wcslen(text); SString result; result.reserve(len); for(size_t i = 0; i < len; ++i) { result.push_back(static_cast(text[i])); } return result; } // // Converts wide characters to UTF8. Mainly for Windows // SString WideToUTF8(const wchar_t *text) { char *buffer; int n = WideCharToMultiByte(CP_UTF8, 0, text, -1, nullptr, 0, nullptr, nullptr); if(!n) { return FailSafeWideToUTF8(text); } buffer = new char[n]; n = WideCharToMultiByte(CP_UTF8, 0, text, -1, buffer, n, nullptr, nullptr); if(!n) { delete[] buffer; return FailSafeWideToUTF8(text); } SString result = buffer; delete[] buffer; return result; } // // Fail safe so we avoid failures // static std::wstring FailSafeUTF8ToWide(const char* text) { size_t len = strlen(text); std::wstring result; result.reserve(len); for (size_t i = 0; i < len; ++i) { result.push_back(static_cast(text[i])); } return result; } // // Converts UTF8 characters to wide. Mainly for Windows // std::wstring UTF8ToWide(const char* text) { wchar_t* buffer; int n = MultiByteToWideChar(CP_UTF8, 0, text, -1, nullptr, 0); if (!n) { return FailSafeUTF8ToWide(text); } buffer = new wchar_t[n]; n = MultiByteToWideChar(CP_UTF8, 0, text, -1, buffer, n); if (!n) { delete[] buffer; return FailSafeUTF8ToWide(text); } std::wstring result = buffer; delete[] buffer; return result; } #endif //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_strings.h000066400000000000000000000214541464327712600205140ustar00rootroot00000000000000//------------------------------------------------------------------------ // STRING TABLE //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2009 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_M_STRINGS_H__ #define __EUREKA_M_STRINGS_H__ #include "PrintfMacros.h" #include #include #include #include // Helper to treat nullptr char* the same as "" #define CSTRING_EMPTY(string) (!(string) || !*(string)) class SString; int y_stricmp (const char *s1, const char *s2) noexcept; int y_strnicmp (const char *s1, const char *s2, size_t len) noexcept; void y_strupr (char *str); void y_strlowr (char *str); char *StringNew(int length); char *StringDup(const char *orig, int limit = -1); void StringCopy(char *buffer, size_t size, const SString &source); // // Safe string: doesn't crash if given NULL (can happen due to refactoring old "char *" code. // Also enforces null-terminated strings: can't contain NUL inside the string. // class SString { public: SString() = default; SString(const char *cstring) : data(cstring ? cstring : "") { } SString(const std::string &cppstring) : data(cppstring) { } SString(const char *buffer, int length); explicit SString(char c) { data.push_back(c); } SString(std::string &&consume) : data(std::move(consume)) { } explicit SString(int number) : data(std::to_string(number)) { } static SString printf(EUR_FORMAT_STRING(const char *format), ...) EUR_PRINTF(1, 2); static SString vprintf(const char *format, va_list ap); bool empty() const { return data.empty(); } bool noCaseEqual(const SString &c) const noexcept { return noCaseEqual(c.c_str()); } bool noCaseEqual(const char *c) const noexcept { return !y_stricmp(data.c_str(), c ? c : ""); } int noCaseCompare(const SString &other) const noexcept { return y_stricmp(data.c_str(), other.c_str()); } bool noCaseStartsWith(const char *c, int pos = 0) const noexcept { return !y_strnicmp(data.c_str() + pos, c ? c : "", c ? strlen(c) : 0); } bool noCaseEndsWith(const SString &text) const; size_t findNoCase(const char *c) const { SString upperme = asUpper(); SString upperthem = SString(c).asUpper(); return upperme.find(upperthem); } bool startsWith(const char *c) const { return !strncmp(data.c_str(), c ? c : "", c ? strlen(c) : 0); } bool operator != (const char *c) const { return data != (c ? c : ""); } bool operator == (const char *c) const { return data == (c ? c : ""); } bool operator == (const SString &other) const { return data == other.data; } bool operator != (const SString &other) const { return data != other.data; } bool operator < (const SString &other) const { return data < other.data; } char operator[](int n) const { return n >= 0 ? data[n] : data[data.length() - abs(n)]; } char &operator[](int n) { return n >= 0 ? data[n] : data[data.length() - abs(n)]; } char operator[](size_t n) const { return data[n]; } char &operator[](size_t n) { return data[n]; } char back() const { return data.back(); } char &back() { return data.back(); } const char *c_str() const noexcept { return data.c_str(); } char *ptr() const { return const_cast(data.data()); } size_t find(const char *s) const { return data.find(s ? s : ""); } size_t find(const SString &s) const { return data.find(s.data); } size_t find(char c, size_t pos = 0) const { return data.find(c, pos); } size_t find_first_of(const char *s, size_t pos = 0) const { return data.find_first_of(s ? s : "", pos); } size_t find_first_not_of(const char *s, size_t pos = 0) const { return data.find_first_not_of(s ? s : "", pos); } size_t find_last_of(const char *s) const { return data.find_last_of(s ? s : ""); } size_t length() const noexcept { return data.length(); } size_t size() const noexcept { return data.size(); } SString operator + (const char *s) const { SString result; result.data = data + (s ? s : ""); return result; } SString operator + (const SString &other) const { SString result; result.data = data + other.data; return result; } SString operator + (char c) const { SString result; result.data = data + c; return result; } SString &operator += (char c) { if(c) // disallow NULL addition! data += c; return *this; } SString &operator += (const char *c) { data += (c ? c : ""); return *this; } SString &operator += (const SString &other) { data += other.data; return *this; } SString &insert(size_t pos, const char *s) { data.insert(pos, s ? s : ""); return *this; } SString substr(size_t pos = 0, size_t len = std::string::npos) const { return data.substr(pos, len); } void clear() noexcept { data.clear(); } void erase(size_t n, size_t len) { data.erase(n, len); } void pop_back() { data.pop_back(); } void push_back(char c) { data.push_back(c); } void reserve(size_t n) { data.reserve(n); } size_t rfind(char c) const { return data.rfind(c); } std::string::iterator begin() noexcept { return data.begin(); } std::string::const_iterator begin() const noexcept { return data.begin(); } std::string::iterator end() noexcept { return data.end(); } std::string::const_iterator end() const noexcept { return data.end(); } // // Convenience to avoid double negation // bool good() const { return !empty(); } enum { npos = std::string::npos }; std::string &get() { return data; } const std::string &get() const { return data; } void getCutWithSpace(size_t pos, SString *word0, SString *word1) const; void cutWithSpace(size_t pos, SString *second); void trimLeadingSpaces(); void trimTrailingSpaces(); void trimTrailingSet(const char *set); // // Capitalizes first letter // SString asTitle() const; SString asLower() const; SString asUpper() const; SString getTidy(const char *badChars = nullptr) const; size_t findSpace() const; size_t findDigit() const; SString spaceEscape(bool backslash = false) const; private: std::string data; }; // // Convenience stuff // inline static SString operator + (const char *cstring, const SString &sstring) { return SString(cstring) + sstring; } inline static std::ostream &operator<<(std::ostream &os, const SString &str) { os << str.get(); return os; } SString joined(const char *sep, const char **strlist, int listlen); // // Variant of joined which accepts a lambda for each item // template SString joined(const char *sep, const T *items, int listlen, C &&func) { SString result; for(int i = 0; i < listlen; ++i) { if(i >= 1) result += sep; result += func(items[i]); } return result; } namespace std { template <> struct hash { size_t operator()(const SString & x) const { return hash()(x.get()); } }; } // // Convenience // inline static int atoi(const SString &string) { return atoi(string.c_str()); } inline static double atof(const SString &string) { return atof(string.c_str()); } inline static long strtol(const SString &string, char **endptr, int radix) { return strtol(string.c_str(), endptr, radix); } // // Opaque identifier for string. Maps to an int. // class StringID { public: StringID() = default; explicit StringID(int num) : num(num) { } int get() const noexcept { return num; } bool operator == (StringID other) const { return num == other.num; } bool operator != (StringID other) const { return num != other.num; } bool operator ! () const { return !num; } bool isValid() const { return num >= 0; } bool isInvalid() const noexcept { return num < 0; } bool hasContent() const { return num > 0; } private: int num = 0; }; static_assert(sizeof(StringID) == sizeof(int), "StringID must be size of int"); // // String storage table // class StringTable { public: StringID add(const SString &str); SString get(StringID offset) const noexcept; private: // Must start with an empty string, so get(0) gets "". std::vector mStrings = { "" }; }; #ifdef _WIN32 SString WideToUTF8(const wchar_t *text); std::wstring UTF8ToWide(const char* text); #endif #endif /* __EUREKA_M_STRINGS_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_testmap.cc000066400000000000000000000407051464327712600206360ustar00rootroot00000000000000//------------------------------------------------------------------------ // TEST (PLAY) THE MAP //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include "m_files.h" #include "m_loadsave.h" #include "m_parse.h" #include "m_testmap.h" #include "w_wad.h" #include "ui_menu.h" #include "ui_window.h" #ifdef __APPLE__ #include #endif class DirChangeContext { public: explicit DirChangeContext(const fs::path &path); ~DirChangeContext(); private: char old_dir[FL_PATH_MAX] = {}; }; DirChangeContext::DirChangeContext(const fs::path &path) { // remember the previous working directory if(!getcwd(old_dir, sizeof(old_dir))) old_dir[0] = '\0'; old_dir[FL_PATH_MAX - 1] = '\0'; // just in case gLog.printf("Changing current dir to: %s\n", path.u8string().c_str()); if(!FileChangeDir(path)) throw std::runtime_error("Failed changing directory to port location"); } DirChangeContext::~DirChangeContext() { // restore previous working directory if(*old_dir) FileChangeDir(fs::u8path(old_dir)); } static SString QueryName(const SString &port, const SString &cgame) { SYS_ASSERT(port.good()); SString game = cgame; if (port.noCaseEqual("vanilla")) { if (game.empty()) game = "doom2"; return "vanilla_" + game; } return port; } static bool isMacOSAppBundle(const fs::path &path) { #ifdef __APPLE__ CFStringRef pathString = CFStringCreateWithCString(kCFAllocatorDefault, path.u8string().c_str(), kCFStringEncodingUTF8); if(!pathString) { gLog.printf("ERROR: Failed allocating macOS app bundle path CF string: %s\n", path.u8string().c_str()); return false; } CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, pathString, kCFURLPOSIXPathStyle, true); CFRelease(pathString); if(!url) { gLog.printf("ERROR: Failed allocating macOS app bundle CF URL: %s\n", path.u8string().c_str()); return false; } CFBundleRef bundle = CFBundleCreate(kCFAllocatorDefault, url); CFRelease(url); if(!bundle) { gLog.printf("Could not load, or invalid macOS app CF bundle: %s\n", path.u8string().c_str()); return false; } CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle); CFRelease(bundle); return !!infoDict; #else return false; #endif } class UI_PortPathDialog : public UI_Escapable_Window { public: static const int PADDING = 20; static const int LABEL_HEIGHT = 30; static const int INTER_LABEL_SPACE = 5; static const int LABEL_TEXT_BOX_SPACE = 15; static const int TEXT_BOX_LEFT = 118; static const int TEXT_BOX_HEIGHT = 26; static const int TEXT_BOX_BUTTON_SPACE = 22; static const int TEXT_BOX_BUTTON_WIDTH = 60; static const int PADDING_BEFORE_BOTTOM = 55; static const int BOTTOM_BAR_HEIGHT = 70; static const int BOTTOM_BAR_OUTSET = 10; static const int BOTTOM_BUTTON_WIDTH = 95; static const int BOTTOM_BUTTON_HEIGHT = 30; static const int BOTTOM_PADDING = 15; static const int BOTTOM_RIGHT_PADDING = 25; static const int BOTTOM_BUTTON_SPACING = 45; Fl_Output *exe_display; Fl_Button *ok_but; Fl_Button *cancel_but; // the chosen EXE name, or NULL if cancelled fs::path exe_name; bool want_close = false; const Instance& inst; private: Fl_Input* other_args; SString command_line; public: void SetEXE(const fs::path &newbie) { exe_name = newbie; // NULL is ok here exe_display->value(exe_name.u8string().c_str()); if (!exe_name.empty() && (FileExists(exe_name) || isMacOSAppBundle(exe_name))) ok_but->activate(); else ok_but->deactivate(); } void SetCommandLine(const SString& command_line) { this->command_line = command_line; other_args->value(command_line.c_str()); } void HideCommandLine() { other_args->deactivate(); } const char* getCommandLine() const { return other_args->value(); } static void ok_callback(Fl_Widget *w, void *data) { UI_PortPathDialog * that = (UI_PortPathDialog *)data; that->want_close = true; } static void close_callback(Fl_Widget *w, void *data) { UI_PortPathDialog * that = (UI_PortPathDialog *)data; that->SetEXE(""); that->want_close = true; } static void find_callback(Fl_Widget *w, void *data) { UI_PortPathDialog * that = (UI_PortPathDialog *)data; Fl_Native_File_Chooser chooser; chooser.title("Pick the executable file"); chooser.type(Fl_Native_File_Chooser::BROWSE_FILE); #ifdef WIN32 chooser.filter("Executables\t*.exe"); #endif // FIXME : if we have an exe_filename already, and folder exists, go there // [ especially for vanilla -- look in path of Iwad_name ] chooser.directory(that->inst.Main_FileOpFolder().u8string().c_str()); switch (chooser.show()) { case -1: // error DLG_Notify("Unable to use that exe:\n\n%s", chooser.errmsg()); return; case 1: // cancelled return; default: break; // OK } // we assume the chosen file exists that->SetEXE(fs::u8path(chooser.filename())); } public: UI_PortPathDialog(const SString &port_name, const Instance &inst) : UI_Escapable_Window(580, PADDING + LABEL_HEIGHT * 2 + INTER_LABEL_SPACE + 2 * (LABEL_TEXT_BOX_SPACE + TEXT_BOX_HEIGHT) + PADDING_BEFORE_BOTTOM + BOTTOM_BAR_HEIGHT, "Port Settings"), inst(inst) { char message_buf[256]; snprintf(message_buf, sizeof(message_buf), "Setting up location of the executable (EXE) for %s.", port_name.c_str()); Fl_Box *header = new Fl_Box(FL_NO_BOX, PADDING, PADDING, w() - 2 * PADDING, LABEL_HEIGHT, ""); header->copy_label(message_buf); header->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT); header = new Fl_Box(FL_NO_BOX, PADDING, header->y() + header->h() + INTER_LABEL_SPACE, w() - 2 * PADDING, LABEL_HEIGHT, "This is only needed for the Test Map command."); header->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT); exe_display = new Fl_Output(TEXT_BOX_LEFT, header->y() + header->h() + LABEL_TEXT_BOX_SPACE, w() - TEXT_BOX_LEFT - PADDING - TEXT_BOX_BUTTON_WIDTH - TEXT_BOX_BUTTON_SPACE, TEXT_BOX_HEIGHT, "Exe path: "); other_args = new Fl_Input(TEXT_BOX_LEFT, exe_display->y() + exe_display->h() + LABEL_TEXT_BOX_SPACE, w() - TEXT_BOX_LEFT - PADDING, TEXT_BOX_HEIGHT, "Command line: "); Fl_Button *find_but = new Fl_Button(w()-TEXT_BOX_BUTTON_WIDTH-PADDING, exe_display->y(), TEXT_BOX_BUTTON_WIDTH, TEXT_BOX_HEIGHT, "Find"); find_but->callback((Fl_Callback*)find_callback, this); /* bottom buttons */ Fl_Group * grp = new Fl_Group(0, h() - BOTTOM_BAR_HEIGHT + BOTTOM_BAR_OUTSET, w(), BOTTOM_BAR_HEIGHT); grp->box(FL_FLAT_BOX); grp->color(WINDOW_BG, WINDOW_BG); { cancel_but = new Fl_Button(w() - BOTTOM_RIGHT_PADDING - BOTTOM_BUTTON_WIDTH * 2 - BOTTOM_BUTTON_SPACING, h() - BOTTOM_BUTTON_HEIGHT - BOTTOM_PADDING, BOTTOM_BUTTON_WIDTH, BOTTOM_BUTTON_HEIGHT, "Cancel"); cancel_but->callback(close_callback, this); ok_but = new Fl_Button(w() - BOTTOM_BUTTON_WIDTH - BOTTOM_RIGHT_PADDING, h() - BOTTOM_BUTTON_HEIGHT - BOTTOM_PADDING, BOTTOM_BUTTON_WIDTH, BOTTOM_BUTTON_HEIGHT, "OK"); ok_but->labelfont(FL_HELVETICA_BOLD); ok_but->callback(ok_callback, this); ok_but->shortcut(FL_Enter); ok_but->deactivate(); } grp->end(); end(); resizable(NULL); callback(close_callback, this); } virtual ~UI_PortPathDialog() { } // returns true if user clicked OK bool Run() { set_modal(); show(); while (! want_close) Fl::wait(0.2); return !exe_name.empty(); } }; bool Instance::M_PortSetupDialog(const SString &port, const SString &game, const tl::optional& commandLine) { SString name_buf; if (port.noCaseEqual("vanilla")) name_buf = "vanilla " + game.asTitle(); else if (port.noCaseEqual("mbf")) // temp hack for aesthetics name_buf = "MBF"; else name_buf = port.asTitle(); UI_PortPathDialog dialog(name_buf, *this); // populate the EXE name from existing info, if exists const fs::path *info = global::recent.queryPortPath(QueryName(port, game)); if (info && !info->empty()) dialog.SetEXE(*info); if (commandLine) dialog.SetCommandLine(*commandLine); else dialog.HideCommandLine(); bool ok = dialog.Run(); if (ok) { // persist the new port settings global::recent.setPortPath(QueryName(port, game), GetAbsolutePath(dialog.exe_name)); if(main_win) testmap::updateMenuName(main_win->menu_bar, loaded); global::recent.save(global::home_dir); if (commandLine) loaded.testingCommandLine = dialog.getCommandLine(); } return ok; } //------------------------------------------------------------------------ static void CalcWarpString(const SString& levelName, std::vector &args) { SYS_ASSERT(!levelName.empty()); // FIXME : EDGE allows a full name: -warp MAP03 // Eternity too. // ZDOOM too, but different syntax: +map MAP03 // most common syntax is "MAP##" or "MAP###" if (levelName.length() >= 4 && levelName.noCaseStartsWith("MAP") && isdigit(levelName[3])) { long number = strtol(levelName.c_str() + 3, nullptr, 10); args.push_back("-warp"); args.push_back(std::to_string(number)); return; } // detect "E#M#" syntax of Ultimate-Doom and Heretic, which need // a pair of numbers after -warp if (levelName.length() >= 4 && !isdigit(levelName[0]) && isdigit(levelName[1]) && !isdigit(levelName[2]) && isdigit(levelName[3])) { args.push_back("-warp"); args.push_back(SString::printf("%c", levelName[1])); args.push_back(levelName.c_str() + 3); return; } // map name is non-standard, find the first digit group and hope // for the best... size_t digitPos = levelName.findDigit(); if (digitPos != std::string::npos) { args.push_back("-warp"); args.push_back(levelName.c_str() + digitPos); return; } // no digits at all, oh shit! } static void GrabWadNamesArgs(const Instance& inst, std::vector &args) { bool has_file = false; int use_merge = 0; // see if we should use the "-merge" parameter, which is // required for Chocolate-Doom and derivates like Crispy Doom. // TODO : is there a better way to do this? if (inst.loaded.portName.noCaseEqual("vanilla")) { use_merge = 1; } // always specify the iwad if (inst.wad.master.gameWad()) { args.push_back("-iwad"); args.push_back(inst.wad.master.gameWad()->PathName().u8string()); } // add any resource wads for (const std::shared_ptr& wad : inst.wad.master.resourceWads()) { if (use_merge == 1) args.push_back("-merge"); else if (!use_merge && !has_file) args.push_back("-file"); args.push_back(wad->PathName().u8string()); if (use_merge) use_merge++; else has_file = true; } // the current PWAD, if exists, must be last if (inst.wad.master.editWad()) { if (!has_file) args.push_back("-file"); args.push_back(inst.wad.master.editWad()->PathName().u8string()); } } static SString buildArgString(const std::vector& args, bool backslash) { SString result; for (const SString& arg : args) { if (!result.empty()) result += " "; result += arg.spaceEscape(backslash); } return result; } static void logArgs(const SString& args) { gLog.printf("Testing map using the following command:\n"); gLog.printf("--> %s\n", args.c_str()); } #ifdef _WIN32 // On Windows the process is started as if user ran it individually static void testMapOnWindows(const Instance &inst, const fs::path& portPath) { std::vector args; GrabWadNamesArgs(inst, args); CalcWarpString(inst.loaded.levelName, args); SString argString = inst.loaded.testingCommandLine + " " + buildArgString(args, false); logArgs(argString); std::wstring argsWide = UTF8ToWide(argString.c_str()); HINSTANCE result = ShellExecuteW(nullptr, L"open", portPath.wstring().c_str(), argsWide.c_str(), FilenameGetPath(portPath).wstring().c_str(), SW_SHOW); if ((INT_PTR)result <= 32) { DWORD error = GetLastError(); ThrowException("Failed starting %s: error %s\n\n%s", portPath.u8string().c_str(), GetShellExecuteErrorMessage(result).c_str(), GetWindowsErrorMessage(error).c_str()); } inst.Status_Set("Started the game"); } #else static void testMapOnMacBundle(const Instance &inst, const fs::path& portPath) { std::vector args; GrabWadNamesArgs(inst, args); CalcWarpString(inst.loaded.levelName, args); SString argString = SString("/usr/bin/open -a ") + SString(portPath.u8string()).spaceEscape(true) + " --args " + inst.loaded.testingCommandLine + " " + buildArgString(args, true); logArgs(argString); system(argString.c_str()); } static void testMapOnPOSIX(const Instance &inst, const fs::path& portPath) { std::vector args; GrabWadNamesArgs(inst, args); CalcWarpString(inst.loaded.levelName, args); SString arg; TokenWordParse parse(inst.loaded.testingCommandLine, false); while(parse.getNext(arg)) args.push_back(arg); args.insert(args.begin(), portPath.u8string()); std::vector argv; argv.reserve(args.size() + 2); fs::path portName = portPath.filename(); SString argString; for(SString &arg : args) { argString += arg + " "; argv.push_back(arg.get().data()); } argv.push_back(nullptr); logArgs(argString); pid_t pid = fork(); if(pid == -1) { // fail ThrowException("Failed forking to start %s: %s", portName.u8string().c_str(), GetErrorMessage(errno).c_str()); } else if(pid == 0) { // child process try { DirChangeContext dirChangeContext(FilenameGetPath(portPath)); execvp(portPath.u8string().c_str(), argv.data()); // on failure int err = errno; gLog.printf("--> Failed starting %s: %s\n", portName.u8string().c_str(), GetErrorMessage(err).c_str()); _exit(err); } catch(const std::exception &e) { gLog.printf("--> Failed starting %s: %s\n", portName.u8string().c_str(), e.what()); _exit(EXIT_FAILURE); } catch(...) { // Need to guard it best here _exit(EXIT_FAILURE); } } // Parent process. Continue work. } #endif void Instance::CMD_ChangeTestSettings() { try { M_PortSetupDialog(loaded.portName, loaded.gameName, loaded.testingCommandLine); } catch (const std::runtime_error& e) { Beep("Failed: %s\n", e.what()); } } static bool M_IsPortPathValid(const fs::path &path) { if(path.u8string().length() < 2) return false; if (! FileExists(path) && !isMacOSAppBundle(path)) return false; return true; } void Instance::CMD_TestMap() { try { if (level.MadeChanges) { if (DLG_Confirm({ "Cancel", "&Save" }, "You have unsaved changes, do you want to save them now " "and build the nodes?") <= 0) { return; } if (!M_SaveMap(false)) return; } // check if we know the executable path, if not then ask const fs::path* info = global::recent.queryPortPath(QueryName(loaded.portName, loaded.gameName)); if (!info || !M_IsPortPathValid(*info)) { if (!M_PortSetupDialog(loaded.portName, loaded.gameName, loaded.testingCommandLine)) return; info = global::recent.queryPortPath(QueryName(loaded.portName, loaded.gameName)); } // this generally can't happen, but we check anyway... if (!info || !M_IsPortPathValid(*info)) { Beep("invalid path to executable"); return; } Status_Set("TESTING MAP"); if(main_win) main_win->redraw(); Fl::wait(0.1); Fl::wait(0.1); #ifdef _WIN32 testMapOnWindows(*this, *info); #else if(isMacOSAppBundle(*info)) testMapOnMacBundle(*this, *info); else testMapOnPOSIX(*this, *info); #endif if(main_win) main_win->redraw(); Fl::wait(0.1); Fl::wait(0.1); } catch(const std::runtime_error &e) { Status_Set("Failed testing map"); DLG_ShowError(false, "Could not start map for testing: %s", e.what()); } } namespace testmap { void updateMenuName(Fl_Sys_Menu_Bar *bar, const LoadingData &loading) { if(loading.portName.empty() || loading.gameName.empty()) return; // premature const fs::path* info = global::recent.queryPortPath(QueryName(loading.portName, loading.gameName)); if(!info || !M_IsPortPathValid(*info)) menu::setTestMapDetail(bar, ""); else menu::setTestMapDetail(bar, SString(info->filename().replace_extension().u8string())); } } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_testmap.h000066400000000000000000000020041464327712600204660ustar00rootroot00000000000000//------------------------------------------------------------------------ // TEST (PLAY) THE MAP //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef M_TESTMAP_H_ #define M_TESTMAP_H_ #include "FL/Fl_Sys_Menu_Bar.H" struct LoadingData; namespace testmap { void updateMenuName(Fl_Sys_Menu_Bar *bar, const LoadingData &loading); } #endif eureka-editor-eureka-2.0.2/src/m_udmf.cc000066400000000000000000000506761464327712600201240ustar00rootroot00000000000000//------------------------------------------------------------------------ // UDMF PARSING / WRITING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2019 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Instance.h" #include "main.h" #include "LineDef.h" #include "m_game.h" #include "Sector.h" #include "SideDef.h" #include "Thing.h" #include "Vertex.h" #include "w_rawdef.h" #include "w_texture.h" #include "w_wad.h" #include "ui_window.h" class Udmf_Token { private: // empty means EOF SString text; public: Udmf_Token(const char *str) : text(str) { } Udmf_Token(const char *str, int len) : text(str, len) { } const char *c_str() const { return text.c_str(); } bool IsEOF() const { return text.empty(); } bool IsIdentifier() const { if (text.size() == 0) return false; char ch = text[0]; return isalpha(ch) || ch == '_'; } bool IsString() const { return text.size() > 0 && text[0] == '"'; } bool Match(const char *name) const { return y_stricmp(text.c_str(), name) == 0; } int DecodeInt() const { return atoi(text); } double DecodeFloat() const { return atof(text); } SString DecodeString() const { if (! IsString() || text.size() < 2) { // TODO warning return SString(); } SString string = text; string.erase(0, 1); string.pop_back(); return string; } FFixedPoint DecodeCoord() const { return MakeValidCoord(MapFormat::udmf, DecodeFloat()); } StringID DecodeTexture() const { SString buffer; if (! IsString()) { // TODO warning buffer = "-"; } else { int use_len = 8; if (text.size() < 10) use_len = (int)text.size() - 2; buffer = text; buffer.erase(0, 1); buffer.erase(use_len, SString::npos); } return BA_InternaliseString(NormalizeTex(buffer)); } }; // since UDMF lumps can be very large, we read chunks of it // as-needed instead of loading the whole thing into memory. // the buffer size should be over 2x maximum token length. #define U_BUF_SIZE 16384 class Udmf_Parser { private: LumpInputStream stream; // reached EOF or a file read error bool done = false; // we have seen a "/*" but not the closing "*/" bool in_comment = false; // number of remaining bytes int remaining; // read buffer char buffer[U_BUF_SIZE]; // position in buffer and used size of buffer int b_pos = 0; int b_size = 0; public: Udmf_Parser(const Lump_c &_lump) : stream(_lump) { remaining = _lump.Length(); } Udmf_Token Next() { for (;;) { if (done) return Udmf_Token(""); // when position reaches half-way point, shift buffer down if (b_pos >= U_BUF_SIZE/2) { memmove(buffer, buffer + U_BUF_SIZE/2, U_BUF_SIZE/2); b_pos -= U_BUF_SIZE/2; b_size -= U_BUF_SIZE/2; } // top up the buffer if (remaining > 0 && b_size < U_BUF_SIZE) { int want = U_BUF_SIZE - b_size; if (want > remaining) want = remaining; if (! stream.read(buffer + b_size, want)) { // TODO mark error somewhere, show dialog later done = true; continue; } remaining -= want; b_size += want; } // end of file? if (remaining <= 0 && b_pos >= b_size) { done = true; continue; } if (in_comment) { // end of multi-line comment? if (b_pos+2 <= b_size && buffer[b_pos] == '*' && buffer[b_pos+1] == '/') { in_comment = false; b_pos += 2; continue; } b_pos++; continue; } // check for multi-line comment if (b_pos+2 <= b_size && buffer[b_pos] == '/' && buffer[b_pos+1] == '*') { in_comment = true; b_pos += 2; continue; } // check for single-line comment if (b_pos+2 <= b_size && buffer[b_pos] == '/' && buffer[b_pos+1] == '/') { SkipToEOLN(); continue; } // skip whitespace (assumes ASCII) int start = b_pos; unsigned char ch = buffer[b_pos]; if ((ch <= 32) || (ch >= 127 && ch <= 160)) { b_pos++; continue; } // an actual token, yay! // is it a string? if (ch == '"') { b_pos++; while (b_pos < b_size) { // skip escapes if (buffer[b_pos] == '\\' && b_pos+1 < b_size) { b_pos += 2; continue; } if (buffer[b_pos] == '"') { // include trailing double quote b_pos++; break; } b_pos++; } return Udmf_Token(buffer+start, b_pos - start); } // is it a identifier or number? if (isalnum(ch) || ch == '_' || ch == '-' || ch == '+') { b_pos++; while (b_pos < b_size) { char ch = buffer[b_pos]; if (isalnum(ch) || ch == '_' || ch == '-' || ch == '+' || ch == '.') { b_pos++; continue; } break; } return Udmf_Token(buffer+start, b_pos - start); } // it must be a symbol, such as '{' or '}' b_pos++; return Udmf_Token(buffer+start, 1); } } bool Expect(const char *name) { Udmf_Token tok = Next(); return tok.Match(name); } void SkipToEOLN() { while (b_pos < b_size && buffer[b_pos] != '\n') b_pos++; } }; static void UDMF_ParseGlobalVar(LoadingData &loading, Udmf_Parser& parser, const Udmf_Token& name) { Udmf_Token value = parser.Next(); if (value.IsEOF()) { // TODO mark error return; } if (!parser.Expect(";")) { // TODO mark error parser.SkipToEOLN(); return; } if (name.Match("namespace")) { // TODO : check if namespace is supported by current port // [ if not, show a dialog with some options ] loading.udmfNamespace = value.DecodeString(); } else if (name.Match("ee_compat")) { // odd Eternity thing, ignore it } else { gLog.printf("skipping unknown global '%s' in UDMF\n", name.c_str()); } } static void UDMF_ParseThingField(const Document &doc, Thing *T, const Udmf_Token& field, const Udmf_Token& value) { // just ignore any setting with the "false" keyword if (value.Match("false")) return; // TODO hexen options // TODO strife options if (field.Match("x")) T->raw_x = value.DecodeCoord(); else if (field.Match("y")) T->raw_y = value.DecodeCoord(); else if (field.Match("height")) T->raw_h = value.DecodeCoord(); else if (field.Match("type")) T->type = value.DecodeInt(); else if (field.Match("angle")) T->angle = value.DecodeInt(); else if (field.Match("id")) T->tid = value.DecodeInt(); else if (field.Match("special")) T->special = value.DecodeInt(); else if (field.Match("arg0")) T->arg1 = value.DecodeInt(); else if (field.Match("arg1")) T->arg2 = value.DecodeInt(); else if (field.Match("arg2")) T->arg3 = value.DecodeInt(); else if (field.Match("arg3")) T->arg4 = value.DecodeInt(); else if (field.Match("arg4")) T->arg5 = value.DecodeInt(); else if (field.Match("skill2")) T->options |= MTF_Easy; else if (field.Match("skill3")) T->options |= MTF_Medium; else if (field.Match("skill4")) T->options |= MTF_Hard; else if (field.Match("ambush")) T->options |= MTF_Ambush; else if (field.Match("friend")) T->options |= MTF_Friend; else if (field.Match("single")) T->options &= ~MTF_Not_SP; else if (field.Match("coop")) T->options &= ~MTF_Not_COOP; else if (field.Match("dm")) T->options &= ~MTF_Not_DM; else { gLog.debugPrintf("thing #%d: unknown field '%s'\n", doc.numThings()-1, field.c_str()); } } static void UDMF_ParseVertexField(const Document &doc, Vertex *V, const Udmf_Token& field, const Udmf_Token& value) { if (field.Match("x")) V->raw_x = value.DecodeCoord(); else if (field.Match("y")) V->raw_y = value.DecodeCoord(); else { gLog.debugPrintf("vertex #%d: unknown field '%s'\n", doc.numVertices()-1, field.c_str()); } } static void UDMF_ParseLinedefField(const Document &doc, LineDef *LD, const Udmf_Token& field, const Udmf_Token& value) { // Note: vertex and sidedef numbers are validated later on // just ignore any setting with the "false" keyword if (value.Match("false")) return; // TODO hexen flags // TODO strife flags if (field.Match("v1")) LD->start = value.DecodeInt(); else if (field.Match("v2")) LD->end = value.DecodeInt(); else if (field.Match("sidefront")) LD->right = value.DecodeInt(); else if (field.Match("sideback")) LD->left = value.DecodeInt(); else if (field.Match("special")) LD->type = value.DecodeInt(); else if (field.Match("arg0")) LD->tag = value.DecodeInt(); else if (field.Match("arg1")) LD->arg2 = value.DecodeInt(); else if (field.Match("arg2")) LD->arg3 = value.DecodeInt(); else if (field.Match("arg3")) LD->arg4 = value.DecodeInt(); else if (field.Match("arg4")) LD->arg5 = value.DecodeInt(); else if (field.Match("blocking")) LD->flags |= MLF_Blocking; else if (field.Match("blockmonsters")) LD->flags |= MLF_BlockMonsters; else if (field.Match("twosided")) LD->flags |= MLF_TwoSided; else if (field.Match("dontpegtop")) LD->flags |= MLF_UpperUnpegged; else if (field.Match("dontpegbottom")) LD->flags |= MLF_LowerUnpegged; else if (field.Match("secret")) LD->flags |= MLF_Secret; else if (field.Match("blocksound")) LD->flags |= MLF_SoundBlock; else if (field.Match("dontdraw")) LD->flags |= MLF_DontDraw; else if (field.Match("mapped")) LD->flags |= MLF_Mapped; else if (field.Match("passuse")) LD->flags |= MLF_Boom_PassThru; else { gLog.debugPrintf("linedef #%d: unknown field '%s'\n", doc.numVertices() -1, field.c_str()); } } static void UDMF_ParseSidedefField(const Document &doc, SideDef *SD, const Udmf_Token& field, const Udmf_Token& value) { // Note: sector numbers are validated later on // TODO: consider how to handle "offsetx_top" (etc), if at all if (field.Match("sector")) SD->sector = value.DecodeInt(); else if (field.Match("texturetop")) SD->upper_tex = value.DecodeTexture(); else if (field.Match("texturebottom")) SD->lower_tex = value.DecodeTexture(); else if (field.Match("texturemiddle")) SD->mid_tex = value.DecodeTexture(); else if (field.Match("offsetx")) SD->x_offset = value.DecodeInt(); else if (field.Match("offsety")) SD->y_offset = value.DecodeInt(); else { gLog.debugPrintf("sidedef #%d: unknown field '%s'\n", doc.numVertices() -1, field.c_str()); } } static void UDMF_ParseSectorField(const Document &doc, Sector *S, const Udmf_Token& field, const Udmf_Token& value) { if (field.Match("heightfloor")) S->floorh = value.DecodeInt(); else if (field.Match("heightceiling")) S->ceilh = value.DecodeInt(); else if (field.Match("texturefloor")) S->floor_tex = value.DecodeTexture(); else if (field.Match("textureceiling")) S->ceil_tex = value.DecodeTexture(); else if (field.Match("lightlevel")) S->light = value.DecodeInt(); else if (field.Match("special")) S->type = value.DecodeInt(); else if (field.Match("id")) S->tag = value.DecodeInt(); else { gLog.debugPrintf("sector #%d: unknown field '%s'\n", doc.numVertices() -1, field.c_str()); } } static void UDMF_ParseObject(Document &doc, Udmf_Parser& parser, const Udmf_Token& name) { // create a new object of the specified type Objid kind; Thing *new_T = NULL; Vertex *new_V = NULL; LineDef *new_LD = NULL; SideDef *new_SD = NULL; Sector *new_S = NULL; if (name.Match("thing")) { kind = Objid(ObjType::things, 1); auto addedThing = std::make_unique(); addedThing->options = MTF_Not_SP | MTF_Not_COOP | MTF_Not_DM; doc.things.push_back(std::move(addedThing)); new_T = doc.things.back().get(); } else if (name.Match("vertex")) { kind = Objid(ObjType::vertices, 1); auto addedVertex = std::make_unique(); doc.vertices.push_back(std::move(addedVertex)); new_V = doc.vertices.back().get(); } else if (name.Match("linedef")) { kind = Objid(ObjType::linedefs, 1); auto addedLine = std::make_shared(); doc.linedefs.push_back(std::move(addedLine)); new_LD = doc.linedefs.back().get(); } else if (name.Match("sidedef")) { kind = Objid(ObjType::sidedefs, 1); auto addedSide = std::make_shared(); addedSide->mid_tex = BA_InternaliseString("-"); addedSide->lower_tex = addedSide->mid_tex; addedSide->upper_tex = addedSide->mid_tex; doc.sidedefs.push_back(std::move(addedSide)); new_SD = doc.sidedefs.back().get(); } else if (name.Match("sector")) { kind = Objid(ObjType::sectors, 1); auto addedSector = std::make_shared(); addedSector->light = 160; doc.sectors.push_back(std::move(addedSector)); new_S = doc.sectors.back().get(); } if (!kind.valid()) { // unknown object kind gLog.printf("skipping unknown block '%s' in UDMF\n", name.c_str()); } for (;;) { Udmf_Token tok = parser.Next(); if (tok.IsEOF()) break; if (tok.Match("}")) break; if (! parser.Expect("=")) { // TODO mark error parser.SkipToEOLN(); continue; } Udmf_Token value = parser.Next(); if (value.IsEOF()) break; if (! parser.Expect(";")) { // TODO mark error parser.SkipToEOLN(); continue; } if (new_T) UDMF_ParseThingField(doc, new_T, tok, value); if (new_V) UDMF_ParseVertexField(doc, new_V, tok, value); if (new_LD) UDMF_ParseLinedefField(doc, new_LD, tok, value); if (new_SD) UDMF_ParseSidedefField(doc, new_SD, tok, value); if (new_S) UDMF_ParseSectorField(doc, new_S, tok, value); } } void Document::ValidateLevel_UDMF(const ConfigData &config, BadCount &bad) { for (int n = 0 ; n < numSidedefs() ; n++) { ValidateSectorRef(*sidedefs[n], n, config, bad); } for (int n = 0 ; n < numLinedefs(); n++) { auto L = linedefs[n]; ValidateVertexRefs(*L, n, bad); ValidateSidedefRefs(*L, n, config, bad); } } void Instance::UDMF_LoadLevel(int loading_level, const Wad_file *load_wad, Document& doc, LoadingData &loading, BadCount &bad) const { const Lump_c *lump = Load_LookupAndSeek(loading_level, load_wad, "TEXTMAP"); // we assume this cannot happen if (! lump) return; // NOTE: this must be a pointer to heap, due to stack size. auto parser = std::make_unique(*lump); for (;;) { Udmf_Token tok = parser->Next(); if (tok.IsEOF()) break; if (! tok.IsIdentifier()) { // something has gone wrong // TODO mark the error somehow, pop-up dialog later parser->SkipToEOLN(); continue; } Udmf_Token tok2 = parser->Next(); if (tok2.IsEOF()) break; if (tok2.Match("=")) { UDMF_ParseGlobalVar(loading, *parser, tok); continue; } if (tok2.Match("{")) { UDMF_ParseObject(doc, *parser, tok); continue; } // unexpected symbol // TODO mark the error somehow, show dialog later parser->SkipToEOLN(); } doc.ValidateLevel_UDMF(conf, bad); } //---------------------------------------------------------------------- static inline void WrFlag(Lump_c *lump, int flags, const char *name, int mask) { if ((flags & mask) != 0) { lump->Printf("%s = true;\n", name); } } static void UDMF_WriteInfo(const LoadingData &loading, Lump_c *lump) { lump->Printf("namespace = \"%s\";\n\n", loading.udmfNamespace.c_str()); } static void UDMF_WriteThings(const Instance &inst, Lump_c *lump) { for (int i = 0 ; i < inst.level.numThings() ; i++) { lump->Printf("thing // %d\n", i); lump->Printf("{\n"); const auto th = inst.level.things[i]; lump->Printf("x = %1.3f;\n", th->x()); lump->Printf("y = %1.3f;\n", th->y()); if (th->raw_h != FFixedPoint{}) lump->Printf("height = %1.3f;\n", th->h()); lump->Printf("angle = %d;\n", th->angle); lump->Printf("type = %d;\n", th->type); // thing options WrFlag(lump, th->options, "skill1", MTF_Easy); WrFlag(lump, th->options, "skill2", MTF_Easy); WrFlag(lump, th->options, "skill3", MTF_Medium); WrFlag(lump, th->options, "skill4", MTF_Hard); WrFlag(lump, th->options, "skill5", MTF_Hard); WrFlag(lump, ~ th->options, "single", MTF_Not_SP); WrFlag(lump, ~ th->options, "coop", MTF_Not_COOP); WrFlag(lump, ~ th->options, "dm", MTF_Not_DM); WrFlag(lump, th->options, "ambush", MTF_Ambush); if (inst.conf.features.friend_flag) WrFlag(lump, th->options, "friend", MTF_Friend); // TODO Hexen flags // TODO Strife flags // TODO Hexen special and args lump->Printf("}\n\n"); } } static void UDMF_WriteVertices(const Document &doc, Lump_c *lump) { for (int i = 0 ; i < doc.numVertices(); i++) { lump->Printf("vertex // %d\n", i); lump->Printf("{\n"); const auto vert = doc.vertices[i]; lump->Printf("x = %1.3f;\n", vert->x()); lump->Printf("y = %1.3f;\n", vert->y()); lump->Printf("}\n\n"); } } static void UDMF_WriteLineDefs(const Instance &inst, Lump_c *lump) { for (int i = 0 ; i < inst.level.numLinedefs(); i++) { lump->Printf("linedef // %d\n", i); lump->Printf("{\n"); const auto ld = inst.level.linedefs[i]; lump->Printf("v1 = %d;\n", ld->start); lump->Printf("v2 = %d;\n", ld->end); if (ld->right >= 0) lump->Printf("sidefront = %d;\n", ld->right); if (ld->left >= 0) lump->Printf("sideback = %d;\n", ld->left); if (ld->type != 0) lump->Printf("special = %d;\n", ld->type); if (ld->tag != 0) lump->Printf("arg0 = %d;\n", ld->tag); if (ld->arg2 != 0) lump->Printf("arg1 = %d;\n", ld->arg2); if (ld->arg3 != 0) lump->Printf("arg2 = %d;\n", ld->arg3); if (ld->arg4 != 0) lump->Printf("arg3 = %d;\n", ld->arg4); if (ld->arg5 != 0) lump->Printf("arg4 = %d;\n", ld->arg5); // linedef flags WrFlag(lump, ld->flags, "blocking", MLF_Blocking); WrFlag(lump, ld->flags, "blockmonsters", MLF_BlockMonsters); WrFlag(lump, ld->flags, "twosided", MLF_TwoSided); WrFlag(lump, ld->flags, "dontpegtop", MLF_UpperUnpegged); WrFlag(lump, ld->flags, "dontpegbottom", MLF_LowerUnpegged); WrFlag(lump, ld->flags, "secret", MLF_Secret); WrFlag(lump, ld->flags, "blocksound", MLF_SoundBlock); WrFlag(lump, ld->flags, "dontdraw", MLF_DontDraw); WrFlag(lump, ld->flags, "mapped", MLF_Mapped); if (inst.conf.features.pass_through) WrFlag(lump, ld->flags, "passuse", MLF_Boom_PassThru); if (inst.conf.features.midtex_3d) WrFlag(lump, ld->flags, "midtex3d", MLF_Eternity_3DMidTex); // TODO : hexen stuff (SPAC flags, etc) // TODO : strife stuff // TODO : zdoom stuff lump->Printf("}\n\n"); } } static void UDMF_WriteSideDefs(const Document &doc, Lump_c *lump) { for (int i = 0 ; i < doc.numSidedefs(); i++) { lump->Printf("sidedef // %d\n", i); lump->Printf("{\n"); const auto side = doc.sidedefs[i]; lump->Printf("sector = %d;\n", side->sector); if (side->x_offset != 0) lump->Printf("offsetx = %d;\n", side->x_offset); if (side->y_offset != 0) lump->Printf("offsety = %d;\n", side->y_offset); // use NormalizeTex to ensure no double quote if (side->UpperTex() != "-") lump->Printf("texturetop = \"%s\";\n", NormalizeTex(side->UpperTex()).c_str()); if (side->LowerTex() != "-") lump->Printf("texturebottom = \"%s\";\n", NormalizeTex(side->LowerTex()).c_str()); if (side->MidTex() != "-") lump->Printf("texturemiddle = \"%s\";\n", NormalizeTex(side->MidTex()).c_str()); lump->Printf("}\n\n"); } } static void UDMF_WriteSectors(const Document &doc, Lump_c *lump) { for (int i = 0 ; i < doc.numSectors(); i++) { lump->Printf("sector // %d\n", i); lump->Printf("{\n"); const auto sec = doc.sectors[i]; lump->Printf("heightfloor = %d;\n", sec->floorh); lump->Printf("heightceiling = %d;\n", sec->ceilh); // use NormalizeTex to ensure no double quote lump->Printf("texturefloor = \"%s\";\n", NormalizeTex(sec->FloorTex()).c_str()); lump->Printf("textureceiling = \"%s\";\n", NormalizeTex(sec->CeilTex()).c_str()); lump->Printf("lightlevel = %d;\n", sec->light); if (sec->type != 0) lump->Printf("special = %d;\n", sec->type); if (sec->tag != 0) lump->Printf("id = %d;\n", sec->tag); lump->Printf("}\n\n"); } } void Instance::UDMF_SaveLevel(const LoadingData& loading, Wad_file& wad) const { Lump_c &lump = wad.AddLump("TEXTMAP"); UDMF_WriteInfo(loading, &lump); UDMF_WriteThings(*this, &lump); UDMF_WriteVertices(level, &lump); UDMF_WriteLineDefs(*this, &lump); UDMF_WriteSideDefs(level, &lump); UDMF_WriteSectors(level, &lump); wad.AddLump("ENDMAP"); } //---------------------------------------------------------------------- //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/m_vector.cc000066400000000000000000000013571464327712600204630ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "m_vector.h" eureka-editor-eureka-2.0.2/src/m_vector.h000066400000000000000000000067571464327712600203360ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef M_VECTOR_H_ #define M_VECTOR_H_ #include "sys_macro.h" #include #include "WindowsSanitization.h" #include struct v2int_t; struct v2double_t { v2double_t() = default; v2double_t(double x, double y) : x(x), y(y) { } explicit v2double_t(double block) : x(block), y(block) { } explicit inline v2double_t(v2int_t v2); bool nonzero() const { return x || y; } bool inbounds(const v2double_t &bottomleft, const v2double_t &topright) const { return x >= bottomleft.x && x <= topright.x && y >= bottomleft.y && y <= topright.y; } bool inboundsStrict(const v2double_t &bottomleft, const v2double_t &topright) const { return x > bottomleft.x && x < topright.x && y > bottomleft.y && y < topright.y; } bool operator == (const v2double_t &other) const { return x == other.x && y == other.y; } v2double_t &operator += (const v2double_t &other) { x += other.x; y += other.y; return *this; } v2double_t &operator -= (const v2double_t &other) { x -= other.x; y -= other.y; return *this; } v2double_t &operator /= (double val) { x /= val; y /= val; return *this; } v2double_t &operator *= (double val) { x *= val; y *= val; return *this; } v2double_t operator + (const v2double_t &other) const { return { x + other.x, y + other.y }; } v2double_t operator - (const v2double_t &other) const { return { x - other.x, y - other.y }; } double operator * (const v2double_t &other) const { return x * other.x + y * other.y; } v2double_t operator * (double val) const { return { x * val, y * val }; } v2double_t operator / (double val) const { return { x / val, y / val }; } double atan2() const { return ::atan2(y, x); } double hypot() const { return ::hypot(x, y); } inline v2int_t iround() const; double chebyshev() const { return fmax(fabs(x), fabs(y)); } bool operator ! () const { return !x && !y; } double x, y; }; struct v2int_t { v2int_t() = default; v2int_t(int x, int y) : x(x), y(y) { } explicit v2int_t(const v2double_t &v2) : x(static_cast(v2.x)), y(static_cast(v2.y)) { } bool operator!() const { return !x && !y; } v2int_t operator - (v2int_t other) const { return { x - other.x, y - other.y }; } double chebyshev() const { return std::max(abs(x), abs(y)); } int x, y; }; inline v2double_t::v2double_t(v2int_t v2) : x(v2.x), y(v2.y) { } inline v2int_t v2double_t::iround() const { return { ::iround(x), ::iround(y) }; } struct v3double_t { v3double_t() = default; v3double_t(double x, double y, double z) : x(x), y(y), z(z) { } v3double_t(int x, int y, int z) : x(x), y(y), z(z) { } explicit v3double_t(const v2double_t &v2) : x(v2.x), y(v2.y), z(0) { } union { struct { double x, y; }; v2double_t xy; }; double z; }; #endif eureka-editor-eureka-2.0.2/src/main.cc000066400000000000000000000761511464327712600175750ustar00rootroot00000000000000//------------------------------------------------------------------------ // MAIN PROGRAM //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2020 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include #include #include #include "im_color.h" #include "m_config.h" #include "m_game.h" #include "m_files.h" #include "m_loadsave.h" #include "m_testmap.h" #include "e_main.h" #include "m_events.h" #include "m_strings.h" #include "r_render.h" #include "r_subdiv.h" #include "w_dehacked.h" #include "w_rawdef.h" #include "w_texture.h" #include "w_wad.h" #include "ui_window.h" #include "ui_about.h" #include "ui_file.h" #ifndef WIN32 #include #ifndef __APPLE__ #ifndef Bool #define Bool int // We need some pollutants back for the following include #endif #include // for the window icon #undef Bool #endif #endif // IOANCH: be able to call OSX specific routines (needed for ~/Library) #ifdef __APPLE__ #include "OSXCalls.h" #include #elif defined(_WIN32) #else #include #include #endif // // global variables // bool global::want_quit = false; bool global::app_has_focus = false; namespace signalling { #ifndef _WIN32 static bool hasChildProcessStatus; static int childProcessStatus; #endif } fs::path global::config_file; fs::path global::log_file; fs::path global::install_dir; fs::path global::home_dir; fs::path global::cache_dir; std::vector global::Pwad_list; // // config items // bool config::auto_load_recent = false; bool config::begin_maximized = false; bool config::map_scroll_bars = true; SString config::default_port = "vanilla"; int config::gui_scheme = 1; // gtk+ int config::gui_color_set = 1; // bright rgb_color_t config::gui_custom_bg = rgbMake(0xCC, 0xD5, 0xDD); rgb_color_t config::gui_custom_ig = rgbMake(255, 255, 255); rgb_color_t config::gui_custom_fg = rgbMake(0, 0, 0); // Progress during initialisation: // 0 = nothing yet // 1 = read early options, set up logging // 2 = parsed all options, inited FLTK // 3 = opened the main window enum class ProgressStatus { nothing, early, loaded, window }; static ProgressStatus init_progress; bool global::show_help; bool global::show_version; static void RemoveSingleNewlines(SString &buffer) { for (size_t i = 0; i < buffer.length(); ++i) { if(buffer[i] == '\n' && buffer[i + 1] == '\n') while(buffer[i] == '\n') i++; if(buffer[i] == '\n') buffer[i] = ' '; } } // // show an error message and terminate the program // void FatalError(EUR_FORMAT_STRING(const char *fmt), ...) { va_list arg_ptr; va_start(arg_ptr, fmt); SString buffer = SString::vprintf(fmt, arg_ptr); va_end(arg_ptr); // re-entered here? ouch! if (global::in_fatal_error) { fprintf(stderr, "\nERROR LOOP DETECTED!\n"); fflush(stderr); gLog.close(); exit(4); } // minimise chance of a infinite loop of errors global::in_fatal_error = true; gLog.markFatalError(); if (init_progress == ProgressStatus::nothing || global::Quiet || !global::log_file.empty()) { fprintf(stderr, "\nFATAL ERROR: %s", buffer.c_str()); } if (init_progress >= ProgressStatus::early) { gLog.printf("\nFATAL ERROR: %s\n", buffer.c_str()); } if (init_progress >= ProgressStatus::loaded) { RemoveSingleNewlines(buffer); DLG_ShowError(true, "%s", buffer.c_str()); init_progress = ProgressStatus::early; } #ifdef WIN32 else { MessageBox(NULL, buffer.c_str(), "Eureka : Error", MB_ICONEXCLAMATION | MB_OK | MB_SYSTEMMODAL | MB_SETFOREGROUND); } #endif init_progress = ProgressStatus::nothing; global::app_has_focus = false; // TODO: ALL instances. This is death. gLog.close(); exit(2); } static void CreateHomeDirs() { SYS_ASSERT(!global::home_dir.empty()); fs::path dir_name; #ifdef __APPLE__ // IOANCH 20130825: modified to use name-independent calls dir_name = OSX_UserDomainDirectory(macOSDirType::library, nullptr); FileMakeDir(dir_name); dir_name = OSX_UserDomainDirectory(macOSDirType::libraryAppSupport, nullptr); FileMakeDir(dir_name); dir_name = OSX_UserDomainDirectory(macOSDirType::libraryCache, nullptr); FileMakeDir(dir_name); #endif // try to create home_dir (doesn't matter if it already exists) FileMakeDir(global::home_dir); FileMakeDir(global::cache_dir); static const fs::path subdirs[] = { // these under $cache_dir "cache", "backups", // these under $home_dir "iwads", "games", "ports" }; for (int i = 0 ; i < (int)lengthof(subdirs) ; i++) { dir_name = (i < 2 ? global::cache_dir : global::home_dir) / subdirs[i]; FileMakeDir(dir_name); } } static void Determine_HomeDir(const char *argv0) noexcept(false) { // already set by cmd-line option? if (global::home_dir.empty()) { #if defined(WIN32) // get the %APPDATA% location // if that fails, use a folder at the EXE location wchar_t *wpath = nullptr; if(SUCCEEDED(SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &wpath))) { global::home_dir = fs::path(wpath) / "EurekaEditor"; CoTaskMemFree(wpath); } else { SYS_ASSERT(!global::install_dir.empty()); global::home_dir = global::install_dir / "app_data"; } wpath = nullptr; if(SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &wpath))) { global::cache_dir = fs::path(wpath) / "EurekaEditor"; CoTaskMemFree(wpath); } #elif defined(__APPLE__) fs::path path = OSX_UserDomainDirectory(macOSDirType::libraryAppSupport, "eureka-editor"); global::home_dir = path; path = OSX_UserDomainDirectory(macOSDirType::libraryCache, "eureka-editor"); global::cache_dir = path; #else // UNIX char path[FL_PATH_MAX + 4]; if (fl_filename_expand(path, "$HOME/.eureka")) global::home_dir = path; #endif } if (global::home_dir.empty()) ThrowException("Unable to find home directory!\n"); if (global::cache_dir.empty()) global::cache_dir = global::home_dir; gLog.printf("Home dir: %s\n", global::home_dir.u8string().c_str()); gLog.printf("Cache dir: %s\n", global::cache_dir.u8string().c_str()); // create cache directory (etc) CreateHomeDirs(); // determine log filename global::log_file = global::home_dir / "logs.txt"; } static void Determine_InstallPath(const char *argv0) noexcept(false) { // already set by cmd-line option? if (global::install_dir.empty()) { #ifdef WIN32 global::install_dir = GetExecutablePath(argv0); #else static const fs::path prefixes[] = { "/usr/local", "/usr", "/opt", }; for (const fs::path &prefix : prefixes) { global::install_dir = prefix / "share" / "eureka"; fs::path filename = global::install_dir / "games" / "doom2.ugh"; gLog.debugPrintf("Trying install path: %s\n", global::install_dir.u8string().c_str()); gLog.debugPrintf(" looking for file: %s\n", filename.u8string().c_str()); bool exists = FileExists(filename); if (exists) break; global::install_dir.clear(); } #endif } // fallback : look in current directory if (global::install_dir.empty()) { if (FileExists("./games/doom2.ugh")) global::install_dir = "."; } if (global::install_dir.empty()) ThrowException("Unable to find install directory!\n"); gLog.printf("Install dir: %s\n", global::install_dir.u8string().c_str()); } SString GameNameFromIWAD(const fs::path &iwad_name) { return SString(iwad_name.stem().u8string()).asLower(); } static bool DetermineIWAD(Instance &inst) { // this mainly handles a value specified on the command-line, // since values in a EUREKA_LUMP are already vetted. Hence // producing a fatal error here is OK. if (!inst.loaded.iwadName.empty() && FilenameIsBare(inst.loaded.iwadName)) { // a bare name (e.g. "heretic") is treated as a game name SString game = SString(inst.loaded.iwadName.u8string()).asLower(); // make lowercase inst.loaded.iwadName = fs::u8path(game.get()); if (! M_CanLoadDefinitions(global::home_dir, global::install_dir, GAMES_DIR, game)) ThrowException("Unknown game '%s' (no definition file)\n", game.c_str()); const fs::path *path = global::recent.queryIWAD(game); if (!path) ThrowException("Cannot find IWAD for game '%s'\n", game.c_str()); inst.loaded.iwadName = *path; } else if (!inst.loaded.iwadName.empty()) { // if extension is missing, add ".wad" if (! HasExtension(inst.loaded.iwadName)) inst.loaded.iwadName = ReplaceExtension(inst.loaded.iwadName, "wad"); if (! Wad_file::Validate(inst.loaded.iwadName)) ThrowException("IWAD does not exist or is invalid: %s\n", inst.loaded.iwadName.u8string().c_str()); SString game = GameNameFromIWAD(inst.loaded.iwadName); if (! M_CanLoadDefinitions(global::home_dir, global::install_dir, GAMES_DIR, game)) ThrowException("Unknown game '%s' (no definition file)\n", inst.loaded.iwadName.u8string().c_str()); global::recent.addIWAD(inst.loaded.iwadName); global::recent.save(global::home_dir); } else { inst.loaded.iwadName = inst.M_PickDefaultIWAD(); if (inst.loaded.iwadName.empty()) { // show the "Missing IWAD!" dialog. // if user cancels it, we have no choice but to quit. if (! inst.MissingIWAD_Dialog()) return false; } } inst.loaded.gameName = GameNameFromIWAD(inst.loaded.iwadName); return true; } static void DeterminePort(Instance &inst) { // user supplied value? // NOTE: values from the EUREKA_LUMP are already verified. if (!inst.loaded.portName.empty()) { if (! M_CanLoadDefinitions(global::home_dir, global::install_dir, PORTS_DIR, inst.loaded.portName)) ThrowException("Unknown port '%s' (no definition file)\n", inst.loaded.portName.c_str()); return; } SString base_game = M_GetBaseGame(inst.loaded.gameName); // ensure the 'default_port' value is OK if (config::default_port.empty()) { gLog.printf("WARNING: Default port is empty, using vanilla.\n"); config::default_port = "vanilla"; } else if (! M_CanLoadDefinitions(global::home_dir, global::install_dir, PORTS_DIR, config::default_port)) { gLog.printf("WARNING: Default port '%s' is unknown, using vanilla.\n", config::default_port.c_str()); config::default_port = "vanilla"; } else if (! M_CheckPortSupportsGame(base_game, config::default_port)) { gLog.printf("WARNING: Default port '%s' not compatible with '%s'\n", config::default_port.c_str(), inst.loaded.gameName.c_str()); config::default_port = "vanilla"; } inst.loaded.portName = config::default_port; if(inst.main_win) testmap::updateMenuName(inst.main_win->menu_bar, inst.loaded); } static SString DetermineLevel(const Instance &inst) { // most of the logic here is to handle a numeric level number // e.g. -warp 15 // // DOOM 1 level number is 10 * episode + map, e.g. 23 --> E2M3 // (there is logic in command-line parsing to handle two numbers after -warp) int level_number = 0; if (!inst.loaded.levelName.empty()) { if (! isdigit(inst.loaded.levelName[0])) return inst.loaded.levelName.asUpper(); level_number = atoi(inst.loaded.levelName); } for (int pass = 0 ; pass < 2 ; pass++) { std::shared_ptr wad = (pass == 0) ? inst.wad.master.editWad() : inst.wad.master.gameWad(); if (! wad) continue; int lev_num; if (level_number > 0) { lev_num = wad->LevelFindByNumber(level_number); if (lev_num < 0) ThrowException("Level '%d' not found (no matches)\n", level_number); } else { lev_num = wad->LevelFindFirst(); if (lev_num < 0) ThrowException("No levels found in the %s!\n", (pass == 0) ? "PWAD" : "IWAD"); } int idx = wad->LevelHeader(lev_num); Lump_c *lump = wad->GetLump(idx); SYS_ASSERT(lump); return lump->Name(); } // cannot get here return "XXX"; } // this is mainly to prevent ESCAPE key from quitting int Main_key_handler(int event) { if (event != FL_SHORTCUT) return 0; if (Fl::event_key() == FL_Escape) { // TODO: use the currently active instance instead gInstance->EV_EscapeKey(); return 1; } return 0; } // see comment in Main_SetupFLTK... #if !defined(WIN32) && !defined(__APPLE__) int x11_check_focus_change(void *xevent, void *data) { // TODO: get multiple windows if (gInstance->main_win != NULL) { const XEvent *xev = (const XEvent *)xevent; Window xid = xev->xany.window; if (fl_find(xid) == gInstance->main_win) { switch (xev->type) { case FocusIn: global::app_has_focus = true; // fprintf(stderr, "** app_has_focus: TRUE **\n"); break; case FocusOut: global::app_has_focus = false; // fprintf(stderr, "** app_has_focus: false **\n"); break; default: break; } } } // we never eat the event return 0; } #endif static void Main_SetupFLTK() { Fl::visual(FL_DOUBLE | FL_RGB); #ifndef NO_OPENGL Fl::gl_visual(FL_RGB); #endif // disable keyboard navigation, as it often interferes with our // user interface, especially TAB key for toggling the 3D view. Fl::option(Fl::OPTION_VISIBLE_FOCUS, false); if (config::gui_color_set == 0) { // use default colors } else if (config::gui_color_set == 1) { Fl::background(236, 232, 228); Fl::background2(255, 255, 255); Fl::foreground(0, 0, 0); } else { // custom colors Fl::background (RGB_RED(config::gui_custom_bg), RGB_GREEN(config::gui_custom_bg), RGB_BLUE(config::gui_custom_bg)); Fl::background2(RGB_RED(config::gui_custom_ig), RGB_GREEN(config::gui_custom_ig), RGB_BLUE(config::gui_custom_ig)); Fl::foreground (RGB_RED(config::gui_custom_fg), RGB_GREEN(config::gui_custom_fg), RGB_BLUE(config::gui_custom_fg)); } if (config::gui_scheme == 0) { // use default scheme } else if (config::gui_scheme == 1) { Fl::scheme("gtk+"); } else { Fl::scheme("plastic"); } // for Linux + X11, add a system event handler that detects // when our main window gains or loses focus. We need to do // it this way since FLTK is so broken. #if !defined(WIN32) && !defined(__APPLE__) Fl::add_system_handler(x11_check_focus_change, NULL); #endif #ifndef WIN32 Fl_File_Icon::load_system_icons(); #endif int screen_w = Fl::w(); int screen_h = Fl::h(); gLog.printf("Detected Screen Size: %dx%d\n", screen_w, screen_h); } // // Creates the main window // static void Main_OpenWindow(Instance &inst) { inst.main_win = new UI_MainWindow(inst); // Set menu bindings now that we have them. menu::updateBindings(inst.main_win->menu_bar); inst.main_win->label("Eureka v" EUREKA_VERSION); #if !defined(__APPLE__) && !defined(_WIN32) #include "../misc/eureka.xpm" // needed if display has not been previously opened fl_open_display(); Pixmap pm, mask; std::vector localmodified; localmodified.resize(sizeof(logo_E4_32x32_xpm)); memcpy(localmodified.data(), logo_E4_32x32_xpm, localmodified.size()); XpmCreatePixmapFromData(fl_display, DefaultRootWindow(fl_display), const_cast(logo_E4_32x32_xpm), &pm, &mask, NULL); inst.main_win->icon((char *)pm); #endif #ifdef _WIN32 #include "../misc/eureka.xpm" Fl_Pixmap pixmap(logo_E4_32x32_xpm); Fl_RGB_Image image(&pixmap); inst.main_win->icon(&image); #endif // show window (pass some dummy arguments) { int argc = 1; char *argv[2]; argv[0] = StringDup("Eureka.exe"); argv[1] = NULL; inst.main_win->show(argc, argv); #ifndef NO_OPENGL inst.main_win->canvas->show(); // needed for OpenGL #endif global::app_has_focus = true; } #if !defined(__APPLE__) && !defined(_WIN32) // read in the current window hints, then modify them to // support icon transparency (make sure that transparency // mask is enabled in the XPM icon) XWMHints* hints = XGetWMHints(fl_display, fl_xid(inst.main_win)); hints->flags |= IconMaskHint; hints->icon_mask = mask; XSetWMHints(fl_display, fl_xid(inst.main_win), hints); XFree(hints); #endif // kill the stupid bright background of the "plastic" scheme if (config::gui_scheme == 2) { delete Fl::scheme_bg_; Fl::scheme_bg_ = NULL; inst.main_win->image(NULL); } Fl::check(); InitAboutDialog(); if (config::begin_maximized) inst.main_win->Maximize(); log_viewer = new UI_LogViewer(*gInstance); gLog.openWindow([](const SString &text, void *userData) { LogViewer_AddLine(text.c_str()); }, nullptr); Fl::add_handler(Main_key_handler); inst.main_win->BrowserMode(BrowserMode::hide); inst.main_win->NewEditMode(inst.edit.mode); // allow processing keyboard events, even before the mouse // pointer has entered our window. Fl::focus(inst.main_win->canvas); Fl::check(); } void Main_Quit() { global::want_quit = true; } // used for 'New Map' / 'Open Map' functions too bool Document::Main_ConfirmQuit(const char *action) const { if (! MadeChanges) return true; SString secondButton = SString::printf("&%s", action); // convert action string like "open a new map" to a simple "Open" // string for the yes choice. if (secondButton.size() >= 2) { secondButton[1] = static_cast(toupper(secondButton[1])); size_t pos = secondButton.find(' '); if (pos != SString::npos) secondButton.erase(pos, SString::npos); } if (DLG_Confirm({ "Cancel", secondButton }, "You have unsaved changes. " "Do you really want to %s?", action) == 1) { return true; } return false; } // // the directory we should use for a file open/save operation. // returns NULL when not sure. // fs::path Instance::Main_FileOpFolder() const { if (wad.master.editWad()) return FilenameGetPath(wad.master.editWad()->PathName()); return ""; } static void updateStatusByChildProcesses(const Instance &inst) { #ifdef _WIN32 #else if(signalling::hasChildProcessStatus) { signalling::hasChildProcessStatus = false; int status = signalling::childProcessStatus; SString message; if(WIFEXITED(status)) { message = SString::printf("Exited with status %d", WEXITSTATUS(status)); } else if(WIFSIGNALED(status)) { message = SString::printf("Signalled by %d", WTERMSIG(status)); } if(message.good()) { inst.Status_Set("%s", message.c_str()); gLog.printf("--> %s\n", message.c_str()); } } #endif } void Main_Loop() { // TODO: must think this through gInstance->RedrawMap(); for (;;) { // TODO: determine the active instance if (gInstance->edit.is_navigating) { gInstance->Nav_Navigate(); Fl::wait(0); if (global::want_quit) break; } else { Fl::wait(0.2); } if (global::want_quit) { if (gInstance->level.Main_ConfirmQuit("quit")) break; global::want_quit = false; } // TODO: handle these in a better way // TODO: HANDLE ALL INSTANCES gInstance->main_win->UpdateTitle(gInstance->level.MadeChanges ? '*' : 0); gInstance->main_win->scroll->UpdateBounds(); if (gInstance->edit.Selected->empty()) gInstance->edit.error_mode = false; updateStatusByChildProcesses(*gInstance); } } static void readGameInfo(std::unordered_map &parseVars, LoadingData &loading, ConfigData &config) noexcept(false) { loading.gameName = GameNameFromIWAD(loading.iwadName); gLog.printf("Game name: '%s'\n", loading.gameName.c_str()); gLog.printf("IWAD file: '%s'\n", loading.iwadName.u8string().c_str()); readConfiguration(parseVars, "games", loading.gameName, config); } static void readPortInfo(std::unordered_map &parseVars, LoadingData &loading, ConfigData &config) noexcept(false) { // we assume that the port name is valid, i.e. a config file // exists for it. That is checked by DeterminePort() and // the EUREKA_LUMP parsing code. SYS_ASSERT(!loading.portName.empty()); SString base_game = M_GetBaseGame(loading.gameName); // warn user if this port is incompatible with the game if (! M_CheckPortSupportsGame(base_game, loading.portName)) { gLog.printf("WARNING: the port '%s' is not compatible with the game " "'%s'\n", loading.portName.c_str(), loading.gameName.c_str()); int res = DLG_Confirm({ "&vanilla", "No Change" }, "Warning: the given port '%s' is not compatible " "with this game (%s)." "\n\n" "To prevent seeing invalid line and sector " "types, it is recommended to reset the port to " "something valid.\n" "Select a new port now?", loading.portName.c_str(), loading.gameName.c_str()); if (res == 0) { loading.portName = "vanilla"; } } gLog.printf("Port name: '%s'\n", loading.portName.c_str()); readConfiguration(parseVars, "ports", loading.portName, config); // prevent UI weirdness if the port is forced to BOOM / MBF if (config.features.strife_flags) { config.features.pass_through = 0; config.features.coop_dm_flags = 0; config.features.friend_flag = 0; } } NewResources loadResources(const LoadingData& loading, const WadData &waddata) noexcept(false) { auto newres = NewResources(); newres.loading = loading; newres.waddata = waddata; gLog.printf("\n"); gLog.printf("----- Loading Resources -----\n"); // clear the parse variables, pre-set a few vars std::unordered_map parseVars = loading.prepareConfigVariables(); std::vector> resourceWads; try { readGameInfo(parseVars, newres.loading, newres.config); readPortInfo(parseVars, newres.loading, newres.config); for (const fs::path& resource : newres.loading.resourceList) { if(fs::is_directory(resource)) { std::shared_ptr wad = Wad_file::readFromDir(resource); if(!wad) gLog.printf("Failed opening directory: %s\n", resource.u8string().c_str()); else { resourceWads.push_back(wad); } continue; } if (MatchExtensionNoCase(resource, ".ugh")) { M_ParseDefinitionFile(parseVars, ParsePurpose::resource, &newres.config, resource); continue; } if(MatchExtensionNoCase(resource, ".deh") || MatchExtensionNoCase(resource, ".bex")) { if(!dehacked::loadFile(resource, newres.config)) gLog.printf("Error loading Dehacked file %s\n", resource.u8string().c_str()); continue; } // Otherwise wad if (!Wad_file::Validate(resource)) ThrowException("Invalid resource WAD file: %s", resource.u8string().c_str()); std::shared_ptr wad = Wad_file::Open(resource, WadOpenMode::read); if (!wad) ThrowException("Cannot load resource: %s", resource.u8string().c_str()); resourceWads.push_back(wad); } std::shared_ptr gameWad = Wad_file::Open(newres.loading.iwadName, WadOpenMode::read); if (!gameWad) ThrowException("Could not load IWAD file"); newres.waddata.reloadResources(gameWad, newres.config, resourceWads); dehacked::loadLumps(newres.waddata.master, newres.config); } catch (const std::runtime_error&e ) { gLog.printf("%s\n", e.what()); throw; } return newres; } // // load all game/port definitions (*.ugh). // open all wads in the master directory. // read important content from the wads (palette, textures, etc). // void Instance::Main_LoadResources(const LoadingData &loading) noexcept(false) { auto newres = loadResources(loading, wad); // Commit it wad = std::move(newres.waddata); conf = std::move(newres.config); loaded = std::move(newres.loading); if(main_win) testmap::updateMenuName(main_win->menu_bar, loaded); UpdateViewOnResources(); } void Instance::UpdateViewOnResources() { // Must deselect now if(edit.Selected) edit.Selected->clear_all(); gLog.printf("--- DONE ---\n"); gLog.printf("\n"); // reset sector info (for slopes and 3D floors) Subdiv_InvalidateAll(); if (main_win) { // kill all loaded OpenGL images if (main_win->canvas) main_win->canvas->DeleteContext(); main_win->UpdateGameInfo(loaded, conf); main_win->browser->Populate(); // TODO: only call this when the IWAD has changed main_win->propsLoadValues(); } } /* ----- user information ----------------------------- */ static void ShowHelp() { printf( "\n" "*** " EUREKA_TITLE " v" EUREKA_VERSION " (C) 2020 The Eureka Team ***\n" "\n"); printf( "Eureka is free software, under the terms of the GNU General\n" "Public License (GPL), and comes with ABSOLUTELY NO WARRANTY.\n" "Home page: http://eureka-editor.sf.net/\n" "\n"); printf( "USAGE: eureka [options...] [FILE...]\n" "\n" "Available options are:\n"); M_PrintCommandLineOptions(); fflush(stdout); } static void ShowVersion() { printf("Eureka version " EUREKA_VERSION " (" __DATE__ ")\n"); fflush(stdout); } static void ShowTime() { #ifdef WIN32 SYSTEMTIME sys_time; GetSystemTime(&sys_time); gLog.printf("Current time: %02d:%02d on %04d/%02d/%02d\n", sys_time.wHour, sys_time.wMinute, sys_time.wYear, sys_time.wMonth, sys_time.wDay); #else // LINUX or MACOSX time_t epoch_time; struct tm *calend_time; if (time(&epoch_time) == (time_t)-1) return; calend_time = localtime(&epoch_time); if (! calend_time) return; gLog.printf("Current time: %02d:%02d on %04d/%02d/%02d\n", calend_time->tm_hour, calend_time->tm_min, calend_time->tm_year + 1900, calend_time->tm_mon + 1, calend_time->tm_mday); #endif } // // Sets up the config path before using it // static void prepareConfigPath() { if (global::config_file.empty()) { if(global::home_dir.empty()) ThrowException("Home directory not set."); global::config_file = global::home_dir / "config.cfg"; } } static void setupSignalHandlers() { #ifdef _WIN32 #else struct sigaction action = {}; action.sa_handler = [](int signalNumber) { int status; pid_t pid; while((pid = waitpid(-1, &status, WNOHANG)) > 0) { signalling::hasChildProcessStatus = true; signalling::childProcessStatus = status; } }; action.sa_flags = SA_RESTART | SA_NOCLDSTOP; int r = sigaction(SIGCHLD, &action, nullptr); if (r == -1) { ThrowException("Failed setting up process reaper signal handler: %s", GetErrorMessage(errno).c_str()); } #endif } // // Common entry point, called by main or other handlers depending on system // int EurekaMain(int argc, char *argv[]) { try { try { setupSignalHandlers(); } catch(const std::runtime_error &e) { // non-critical error, may cause issues gLog.printf("WARNING: %s\n", e.what()); } init_progress = ProgressStatus::nothing; Instance instance; gInstance = &instance; // a quick pass through the command line arguments // to handle special options, like --help, --install, --config M_ParseCommandLine(argc - 1, argv + 1, CommandLinePass::early, global::Pwad_list, options); if (global::show_help) { ShowHelp(); return 0; } if (global::show_version) { ShowVersion(); return 0; } init_progress = ProgressStatus::early; gLog.printf("\n"); gLog.printf("*** " EUREKA_TITLE " v" EUREKA_VERSION " (C) 2020 The Eureka Team ***\n"); gLog.printf("\n"); // sanity checks type sizes (useful when porting) CheckTypeSizes(); ShowTime(); Determine_InstallPath(argv[0]); Determine_HomeDir(argv[0]); if(!gLog.openFile(global::log_file)) gLog.printf("WARNING: failed opening log file '%s'\n", global::log_file.u8string().c_str()); // load all the config settings config::preloading = gInstance->loaded; prepareConfigPath(); M_ParseConfigFile(global::config_file, options); // environment variables can override them M_ParseEnvironmentVars(); // and command line arguments will override both M_ParseCommandLine(argc - 1, argv + 1, CommandLinePass::normal, global::Pwad_list, options); gInstance->loaded = config::preloading; // update state now // TODO: create a new instance gInstance->Editor_Init(); Main_SetupFLTK(); init_progress = ProgressStatus::loaded; global::recent.load(global::home_dir); M_LoadBindings(); global::recent.lookForIWADs(global::install_dir, global::home_dir); Main_OpenWindow(*gInstance); init_progress = ProgressStatus::window; gInstance->M_LoadOperationMenus(); // open a specified PWAD now // [ the map is loaded later.... ] if (!global::Pwad_list.empty()) { // this fatal errors on any missing file // [ hence the Open() below is very unlikely to fail ] M_ValidateGivenFiles(); // TODO: main instance std::shared_ptr editWad = Wad_file::Open(global::Pwad_list[0], WadOpenMode::append); if(!editWad) { ThrowException("Cannot load pwad: %s\n", global::Pwad_list[0].u8string().c_str()); } // Note: the Main_LoadResources() call will ensure this gets // placed at the correct spot (at the end) gInstance->wad.master.ReplaceEditWad(editWad); } // don't auto-load when --iwad or --warp was used on the command line else if (config::auto_load_recent && ! (!gInstance->loaded.iwadName.empty() || !gInstance->loaded.levelName.empty())) { gInstance->M_TryOpenMostRecent(); } // Handle the '__EUREKA' lump. It is almost equivalent to using the // -iwad, -merge and -port command line options, but with extra // checks (to allow editing a wad containing dud information). // // Note: there is logic in M_ParseEurekaLump() to ensure that command // line arguments can override the EUREKA_LUMP values. if (gInstance->wad.master.editWad()) { if (! gInstance->loaded.parseEurekaLump(global::home_dir, global::install_dir, global::recent, gInstance->wad.master.editWad().get(), true /* keep_cmd_line_args */)) { // user cancelled the load gInstance->wad.master.RemoveEditWad(); } } // determine which IWAD to use // TODO: instance management std::shared_ptr gameWad; if (! DetermineIWAD(*gInstance)) goto quit; gameWad = Wad_file::Open(gInstance->loaded.iwadName, WadOpenMode::read); if(!gameWad) goto quit; DeterminePort(*gInstance); // temporarily load the iwad, the following few functions need it. // it will get loaded again in Main_LoadResources(). // TODO: check result gInstance->wad.master.setGameWad(gameWad); gameWad.reset(); // load the initial level // TODO: first instance gInstance->loaded.levelName = DetermineLevel(*gInstance); gLog.printf("Loading initial map : %s\n", gInstance->loaded.levelName.c_str()); // TODO: the first instance gInstance->LoadLevel(gInstance->wad.master.activeWad().get(), gInstance->loaded.levelName); // do this *after* loading the level, since config file parsing // can depend on the map format and UDMF namespace. gInstance->Main_LoadResources(gInstance->loaded); // TODO: instance management Main_Loop(); quit: /* that's all folks! */ gLog.printf("Quit\n"); init_progress = ProgressStatus::nothing; global::app_has_focus = false; // TODO: all instances gLog.close(); return 0; } catch(const std::exception &e) { FatalError("%s\n", e.what()); } } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/main.h000066400000000000000000000074771464327712600174440ustar00rootroot00000000000000//------------------------------------------------------------------------ // MAIN DEFINITIONS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2020 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_MAIN_H__ #define __EUREKA_MAIN_H__ #define EUREKA_TITLE "Eureka DOOM Editor" #include "version.h" #define EUREKA_LUMP "__EUREKA" /* * Windows support */ #if defined(WIN32) || defined(_WIN32) || defined(_WIN64) #include "WindowsInclude.h" #endif #ifdef None #undef None #endif #include "PrintfMacros.h" /* * Standard headers */ #include #include #include #include #include #include #include #include #include #include #ifndef WIN32 #include #else #ifdef _MSC_VER #include #define getcwd _getcwd #endif #endif #include #include #include #include /* * Additional libraries */ #include "hdr_fltk.h" /* * Commonly-used headers */ #include "sys_type.h" #include "sys_macro.h" #include "sys_endian.h" #include "sys_debug.h" #include "objid.h" #include "m_bitvec.h" #include "m_select.h" #include "lib_util.h" #include "lib_file.h" #include "e_basis.h" #include "m_keys.h" #include "e_objects.h" /* * Miscellaneous */ typedef std::vector< const char * > string_list_t; /* * Interfile global variables */ namespace global { extern bool want_quit; extern bool app_has_focus; extern fs::path install_dir; // install dir (e.g. /usr/share/eureka) extern fs::path home_dir; // home dir (e.g. $HOME/.eureka) extern fs::path cache_dir; // for caches and backups, can be same as home_dir } namespace global { extern fs::path config_file; // Name of the configuration file, or NULL extern fs::path log_file; // Name of log file, or NULL } namespace global { extern std::vector Pwad_list; } namespace global { extern bool show_help; // Print usage message and exit. extern bool show_version; // Print version info and exit. } struct LoadingData; struct NewResources; struct WadData; NewResources loadResources(const LoadingData& loading, const WadData& waddata) noexcept(false); /* * Various global functions */ void Main_Quit(); [[noreturn]] void FatalError(EUR_FORMAT_STRING(const char *fmt), ...) EUR_PRINTF(1, 2); void DLG_ShowError(bool fatal, EUR_FORMAT_STRING(const char *msg), ...) EUR_PRINTF(2, 3); void DLG_Notify(EUR_FORMAT_STRING(const char *msg), ...) EUR_PRINTF(1, 2); int DLG_Confirm(const std::vector &buttons, EUR_FORMAT_STRING(const char *msg), ...) EUR_PRINTF(2, 3); extern std::function DLG_Notify_Override; extern std::function &buttons, const char *msg, va_list ap)> DLG_Confirm_Override; SString GameNameFromIWAD(const fs::path &iwad_name); #endif /* __EUREKA_MAIN_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/main.rc.in000066400000000000000000000024251464327712600202120ustar00rootroot00000000000000// // --- Eureka Editor --- // // Windows Resources // #define MAIN_MENU 100 #define MAIN_MENU_FILE_EXIT 1001 #define MAIN_ICON 1 MAIN_MENU MENU DISCARDABLE { POPUP "File" { MENUITEM "Exit", MAIN_MENU_FILE_EXIT } } MAIN_ICON ICON "misc/eureka.ico" 1 VERSIONINFO FILEVERSION @PROJECT_VERSION_MAJOR@, @PROJECT_VERSION_MINOR@, @PROJECT_VERSION_PATCH@ PRODUCTVERSION @PROJECT_VERSION_MAJOR@, @PROJECT_VERSION_MINOR@, @PROJECT_VERSION_PATCH@ FILEFLAGSMASK 0x0 FILEOS 0x40004 // VOS_NT_WINDOWS32 FILETYPE 1 // VFT_APP FILESUBTYPE 0 // VFT_UNKNOWN BEGIN BLOCK "StringFileInfo" BEGIN // 0409 means "US English"; 04B0 means "Unicode encoding" BLOCK "040904B0" BEGIN VALUE "CompanyName", "Eureka Team\0" VALUE "FileDescription", "Eureka DOOM Editor\0" VALUE "FileVersion", "@PROJECT_VERSION@\0" VALUE "InternalName", "Eureka\0" VALUE "LegalCopyright", "\251 Eureka Team, GNU General Public License\0" VALUE "OriginalFilename", "Eureka.EXE\0" VALUE "ProductName", "Eureka\0" VALUE "ProductVersion", "@PROJECT_VERSION@\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 0x04B0 END END //--- editor settings --- // vi:ts=2:sw=2:expandtab:filetype=rc eureka-editor-eureka-2.0.2/src/objid.h000066400000000000000000000053031464327712600175710ustar00rootroot00000000000000//------------------------------------------------------------------------ // OBJECT IDENTIFICATION //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_OBJ_ID_H__ #define __EUREKA_OBJ_ID_H__ #include "sys_type.h" // main kinds of objects enum class ObjType : byte { things, linedefs, sidedefs, vertices, sectors }; // special object number for "NONE" #define NIL_OBJ -1 // bit flags for object parts (bit zero is reserved) #define PART_FLOOR 0x02 #define PART_CEIL 0x04 #define PART_SEC_ALL (PART_FLOOR + PART_CEIL) #define PART_RT_LOWER 0x02 #define PART_RT_UPPER 0x04 #define PART_RT_RAIL 0x08 #define PART_RT_ALL (PART_RT_LOWER | PART_RT_UPPER | PART_RT_RAIL) #define PART_LF_LOWER 0x20 #define PART_LF_UPPER 0x40 #define PART_LF_RAIL 0x80 #define PART_LF_ALL (PART_LF_LOWER | PART_LF_UPPER | PART_LF_RAIL) static const int PART_LEFT_SHIFT = 4; class Objid { public: ObjType type = ObjType::things; int num = NIL_OBJ; // this is some combination of PART_XXX flags, or 0 which // represents the object as a whole. int parts = 0; public: Objid() = default; Objid(ObjType t, int n) : type(t), num(n) { } Objid(ObjType t, int n, int p) : type(t), num(n), parts(p) { } Objid(const Objid &other) = default; Objid &operator = (const Objid &other) = default; void clear() noexcept { num = NIL_OBJ; parts = 0; } bool valid() const { return num >= 0; } bool is_nil() const { return num < 0; } bool operator== (const Objid& other) const { return (other.type == type) && (other.num == num) && (other.parts == parts); } private: // not generally available bool operator!= (const Objid& other) const { return false; } }; #endif /* __EUREKA_OBJ_ID_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/r_grid.cc000066400000000000000000000311731464327712600201120ustar00rootroot00000000000000//------------------------------------------------------------------------ // GRID STUFF //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Errors.h" #include "r_grid.h" #include "m_config.h" #include "sys_debug.h" // config items int config::grid_default_size = 64; bool config::grid_default_snap = false; bool config::grid_default_mode = false; int config::grid_style; // 0 = squares, 1 = dotty bool config::grid_hide_in_free_mode = false; bool config::grid_snap_indicator = true; int config::grid_ratio_high = 3; // custom ratio (high must be >= low) int config::grid_ratio_low = 1; // (low must be > 0) void grid::State::Init() { step = config::grid_default_size; if (step < 1) step = 1; if (step > values[0]) step = values[0]; shown = true; // prevent a beep in AdjustStep AdjustStep(0); // correct step to power of two if (!config::grid_default_mode) { shown = false; listener.gridSetGrid(-1); } else { shown = true; } snap = config::grid_default_snap; listener.gridUpdateSnap(); } void grid::State::MoveTo(const v2double_t &pos) { // no change? if (fabs(pos.x - orig.x) < 0.01 && fabs(pos.y - orig.y) < 0.01) return; orig.x = pos.x; orig.y = pos.y; listener.gridAdjustPos(); listener.gridPointerPos(); listener.gridRedrawMap(); } void grid::State::Scroll(const v2double_t &delta) { MoveTo(orig + delta); } int grid::State::ForceSnapX(double map_x) const { return static_cast(step * round(map_x / (double)step)); } int grid::State::ForceSnapY(double map_y) const { return static_cast(step * round(map_y / (double)step)); } double grid::State::SnapX(double map_x) const { if (! snap || step == 0) return map_x; return ForceSnapX(map_x); } double grid::State::SnapY(double map_y) const { if (! snap || step == 0) return map_y; return ForceSnapY(map_y); } void grid::State::RatioSnapXY(v2double_t& var, const v2double_t &start) const { // snap first, otherwise we lose the ratio var = Snap(var); double dx = var.x - start.x; double dy = var.y - start.y; double len = std::max(fabs(dx), fabs(dy)); int sign_x = (dx >= 0) ? +1 : -1; int sign_y = (dy >= 0) ? +1 : -1; double custom; switch (ratio) { case 0: // unlocked break; case 1: // 1:1 (45 degrees) + axis aligned if (fabs(dx) * 2 < fabs(dy)) { var.x = start.x; } else if (fabs(dy) * 2 < fabs(dx)) { var.y = start.y; } else { var.x = start.x + sign_x * len; var.y = start.y + sign_y * len; } break; case 2: // 2:1 + axis aligned if (fabs(dx) * 4 < fabs(dy)) { var.x = start.x; } else if (fabs(dy) * 4 < fabs(dx)) { var.y = start.y; } else if (fabs(dx) < fabs(dy)) { var.x = start.x + sign_x * len * 0.5; var.y = start.y + sign_y * len; } else { var.x = start.x + sign_x * len; var.y = start.y + sign_y * len * 0.5; } break; case 3: // 4:1 + axis aligned if (fabs(dx) * 8 < fabs(dy)) { var.x = start.x; } else if (fabs(dy) * 8 < fabs(dx)) { var.y = start.y; } else if (fabs(dx) < fabs(dy)) { var.x = start.x + sign_x * len * 0.25; var.y = start.y + sign_y * len; } else { var.x = start.x + sign_x * len; var.y = start.y + sign_y * len * 0.25; } break; case 4: // 8:1 + axis aligned if (fabs(dx) * 16 < fabs(dy)) { var.x = start.x; } else if (fabs(dy) * 16 < fabs(dx)) { var.y = start.y; } else if (fabs(dx) < fabs(dy)) { var.x = start.x + sign_x * len * 0.125; var.y = start.y + sign_y * len; } else { var.x = start.x + sign_x * len; var.y = start.y + sign_y * len * 0.125; } break; case 5: // 5:4 + axis aligned if (fabs(dx) * 3 < fabs(dy)) { var.x = start.x; } else if (fabs(dy) * 3 < fabs(dx)) { var.y = start.y; } else if (fabs(dx) < fabs(dy)) { var.x = start.x + sign_x * len * 0.8; var.y = start.y + sign_y * len; } else { var.x = start.x + sign_x * len; var.y = start.y + sign_y * len * 0.8; } break; case 6: // 7:4 + axis aligned if (fabs(dx) * 3 < fabs(dy)) { var.x = start.x; } else if (fabs(dy) * 3 < fabs(dx)) { var.y = start.y; } else if (fabs(dx) < fabs(dy)) { var.x = start.x + sign_x * len * 4 / 7; var.y = start.y + sign_y * len; } else { var.x = start.x + sign_x * len; var.y = start.y + sign_y * len * 4 / 7; } break; default: // USER SETTING if (config::grid_ratio_low < 1) config::grid_ratio_low = 1; if (config::grid_ratio_high < config::grid_ratio_low) config::grid_ratio_high = config::grid_ratio_low; custom = (double)config::grid_ratio_low / (double)config::grid_ratio_high; if (custom > 0.1 && fabs(dx) < fabs(dy) * custom * 0.3) { var.x = start.x; } else if (custom > 0.1 && fabs(dy) < fabs(dx) * custom * 0.3) { var.y = start.y; } else if (fabs(dx) < fabs(dy)) { var.x = start.x + sign_x * len * custom; var.y = start.y + sign_y * len; } else { var.x = start.x + sign_x * len; var.y = start.y + sign_y * len * custom; } } } int grid::State::QuantSnapX(double map_x, bool want_furthest, int *dir) const { if (OnGridX(map_x)) { if (dir) *dir = 0; return static_cast(map_x); } int new_x = ForceSnapX(map_x); if (dir) { if (new_x < map_x) *dir = -1; else *dir = +1; } if (! want_furthest) return new_x; if (new_x < map_x) return ForceSnapX(map_x + (step - 1)); else return ForceSnapX(map_x - (step - 1)); } int grid::State::QuantSnapY(double map_y, bool want_furthest, int *dir) const { // this is sufficient since the grid is always square return QuantSnapX(map_y, want_furthest, dir); } void grid::State::NaturalSnapXY(double& var_x, double& var_y) const { // this is only used by UI_Canvas::PointerPos() double nat_step = 1.0; while (nat_step * 2.0 <= Scale) nat_step = nat_step * 2.0; while (nat_step * 0.5 >= Scale) nat_step = nat_step * 0.5; var_x = round(var_x * nat_step) / nat_step; var_y = round(var_y * nat_step) / nat_step; } bool grid::State::OnGridX(double map_x) const { if (map_x < 0) map_x = -map_x; int map_x2 = (int)map_x; if (map_x != (double)map_x2) return false; return (map_x2 % step) == 0; } bool grid::State::OnGridY(double map_y) const { if (map_y < 0) map_y = -map_y; int map_y2 = (int)map_y; if (map_y != (double)map_y2) return false; return (map_y2 % step) == 0; } bool grid::State::OnGrid(double map_x, double map_y) const { return OnGridX(map_x) && OnGridY(map_y); } void grid::State::configureGrid(int step, bool shown) { this->step = step; RawSetShown(shown); listener.gridRedrawMap(); } void grid::State::configureSnap(bool snap) { this->snap = snap; listener.gridUpdateSnap(); } void grid::State::configureRatio(int ratio, bool redraw) { this->ratio = ratio; listener.gridUpdateRatio(); if(redraw) listener.gridRedrawMap(); } void grid::State::RefocusZoom(const v2double_t &map, float before_Scale) { double dist_factor = (1.0 - before_Scale / Scale); orig.x += (map.x - orig.x) * dist_factor; orig.y += (map.y - orig.y) * dist_factor; listener.gridPointerPos(); listener.gridRedrawMap(); } const double grid::State::scale_values[] = { 32.0, 16.0, 8.0, 6.0, 4.0, 3.0, 2.0, 1.5, 1.0, 1.0 / 1.5, 1.0 / 2.0, 1.0 / 3.0, 1.0 / 4.0, 1.0 / 6.0, 1.0 / 8.0, 1.0 / 16.0, 1.0 / 32.0, 1.0 / 64.0 }; const int grid::State::digit_scales[] = { 1, 3, 5, 7, 9, 11, 13, 14, 15 /* index into scale_values[] */ }; #define NUM_SCALE_VALUES 18 #define NUM_GRID_VALUES 12 void grid::State::RawSetScale(int i) { SYS_ASSERT(0 <= i && i < NUM_SCALE_VALUES); Scale = scale_values[i]; listener.gridAdjustPos(); listener.gridPointerPos(); listener.gridSetScale(Scale); listener.gridRedrawMap(); } void grid::State::RawSetStep(int i) { SYS_ASSERT(0 <= i && i < NUM_GRID_VALUES); if (i == NUM_GRID_VALUES-1) /* OFF */ { shown = false; listener.gridSetGrid(-1); } else { shown = true; step = values[i]; listener.gridSetGrid(step); } if (config::grid_hide_in_free_mode) SetSnap(shown); listener.gridRedrawMap(); } void grid::State::ForceStep(int new_step) { step = new_step; shown = true; listener.gridSetGrid(step); if (config::grid_hide_in_free_mode) SetSnap(shown); listener.gridRedrawMap(); } void grid::State::StepFromScale() { int pixels_min = 16; int result = 0; for (int i = 0 ; i < NUM_GRID_VALUES-1 ; i++) { result = i; if (values[i] * Scale / 2 < pixels_min) break; } if (step == values[result]) return; // no change step = values[result]; listener.gridRedrawMap(); } void grid::State::AdjustStep(int delta) { if (! shown) { listener.gridBeep("Grid is off (cannot change step)"); return; } int result = -1; if (delta > 0) { for (int i = NUM_GRID_VALUES-2 ; i >= 0 ; i--) { if (values[i] > step) { result = i; break; } } } else if(!delta) // this is for snapping to the closest grid { for (int i = NUM_GRID_VALUES-2 ; i >= 0 ; i--) { if (values[i] >= step) { result = i; break; } } } else // (delta < 0) { for (int i = 0 ; i < NUM_GRID_VALUES-1 ; i++) { if (values[i] < step) { result = i; break; } } } // already at the extreme end? if (result < 0) return; RawSetStep(result); } void grid::State::AdjustScale(int delta) { int result = -1; if (delta > 0) { for (int i = NUM_SCALE_VALUES-1 ; i >= 0 ; i--) { if (scale_values[i] > Scale*1.01) { result = i; break; } } } else // (delta < 0) { for (int i = 0 ; i < NUM_SCALE_VALUES ; i++) { if (scale_values[i] < Scale*0.99) { result = i; break; } } } // already at the extreme end? if (result < 0) return; RawSetScale(result); } void grid::State::RawSetShown(bool new_value) { shown = new_value; listener.gridSetGrid(shown ? step : -1); listener.gridRedrawMap(); } std::string grid::getValuesFLTKMenuString() { std::string result; result.reserve(5 * lengthof(values)); for(size_t i = 0; i < lengthof(values); ++i) { int value = values[i]; if(value >= 0) result += SString::printf("%d", value).get(); else result += "OFF"; if(i < lengthof(values) - 1) result += '|'; } return result; } void grid::State::SetShown(bool enable) { RawSetShown(enable); if (config::grid_hide_in_free_mode) SetSnap(enable); } void grid::State::ToggleShown() { SetShown(!shown); } void grid::State::SetSnap(bool enable) { if (snap == enable) return; snap = enable; if (config::grid_hide_in_free_mode && snap != shown) SetShown(snap); listener.gridUpdateSnap(); listener.gridRedrawMap(); } void grid::State::ToggleSnap() { SetSnap(! snap); } void grid::State::NearestScale(double want_scale) { int best = 0; for (int i = 0 ; i < NUM_SCALE_VALUES ; i++) { best = i; if (scale_values[i] < want_scale * 1.1) break; } RawSetScale(best); } bool grid::State::parseUser(const std::vector &tokens) { if (tokens[0] == "map_pos" && tokens.size() >= 4) { double x = atof(tokens[1]); double y = atof(tokens[2]); MoveTo({ x, y }); double new_scale = atof(tokens[3]); NearestScale(new_scale); listener.gridRedrawMap(); return true; } if (tokens[0] == "grid" && tokens.size() >= 4) { bool t_shown = atoi(tokens[1]) ? true : false; configureGrid(atoi(tokens[3]), t_shown); // tokens[2] was grid.mode, currently unused return true; } if (tokens[0] == "snap" && tokens.size() >= 2) { configureSnap(!!atoi(tokens[1])); return true; } return false; } void grid::State::writeUser(std::ostream &os) const { os << "map_pos " << SString::printf("%1.0f %1.0f %1.6f", getOrig().x, getOrig().y, getScale()) << '\n'; os << "grid " << (isShown() ? 1 : 0) << ' ' << (config::grid_style ? 0 : 1) << ' ' << getStep() << '\n'; os << "snap " << (snaps() ? 1 : 0) << '\n'; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/r_grid.h000066400000000000000000000113401464327712600177460ustar00rootroot00000000000000//------------------------------------------------------------------------ // GRID STUFF //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_R_GRID_H__ #define __EUREKA_R_GRID_H__ #include "m_vector.h" #include "m_strings.h" class Instance; namespace grid { static const int values[] = { 1024, 512, 256, 192, 128, 64, 32, 16, 8, 4, 2, -1 // off }; class Listener { public: virtual void gridRedrawMap() = 0; virtual void gridSetGrid(int grid) = 0; virtual void gridUpdateSnap() = 0; virtual void gridAdjustPos() = 0; virtual void gridPointerPos() = 0; virtual void gridSetScale(double scale) = 0; virtual void gridBeep(const char *message) = 0; virtual void gridUpdateRatio() = 0; }; class State final { private: // the actual grid step (64, 128, etc) int step = 64; // if true, new and moved objects are forced to be on the grid bool snap = true; // if non-zero, new lines will be forced to have a certain ratio int ratio = 0; // whether the grid is being displayed or not. bool shown = true; // map coordinates for centre of canvas v2double_t orig = {}; // scale for drawing map // (multiply a map coordinate by this to get a screen coord) double Scale = 1.0; public: explicit State(Listener& listener) : listener(listener) { } public: void Init(); inline bool isShown() const { return shown; } void SetShown(bool enable); void SetSnap (bool enable); void ToggleShown(); void ToggleSnap(); // change the view so that the map coordinates (x, y) // appear at the centre of the window void MoveTo(const v2double_t &newpos); void Scroll(const v2double_t &delta); // move the origin so that the focus point of the last zoom // operation (scale change) is map_x/y. void RefocusZoom(const v2double_t &map, float before_Scale); // choose the scale nearest to (and less than) the wanted one void NearestScale(double want_scale); // force grid stepping size to arbitrary value void ForceStep(int new_step); // compute new grid step from current scale void StepFromScale(); // increase or decrease the grid size. The 'delta' parameter // is positive to increase it, negative to decrease it. void AdjustStep (int delta); void AdjustScale(int delta); // return X/Y coordinate snapped to grid // (or unchanged is the 'snap' flag is off) double SnapX(double map_x) const; double SnapY(double map_y) const; v2double_t Snap(const v2double_t &map) const { return { SnapX(map.x), SnapY(map.y) }; } // return X/Y coordinate snapped to grid (always) int ForceSnapX(double map_x) const; int ForceSnapY(double map_y) const; v2int_t ForceSnap(const v2double_t map) const { return v2int_t{ ForceSnapX(map.x), ForceSnapX(map.y) }; } // snap X/Y coordinate to ratio lock // (unchanged is the ratio snapping is off) void RatioSnapXY(v2double_t& var, const v2double_t &start) const; // quantization snap, can pick coordinate on other side int QuantSnapX(double map_x, bool want_furthest, int *dir = NULL) const; int QuantSnapY(double map_y, bool want_furthest, int *dir = NULL) const; // snap to the natural resolution of canvas void NaturalSnapXY(double& var_x, double& var_y) const; // check if the X/Y coordinate is on a grid point bool OnGridX(double map_x) const; bool OnGridY(double map_y) const; bool OnGrid(double map_x, double map_y) const; void configureRatio(int ratio, bool redraw); int getStep() const { return step; } bool snaps() const { return snap; } int getRatio() const { return ratio; } const v2double_t &getOrig() const { return orig; } double getScale() const { return Scale; } bool parseUser(const std::vector &tokens); void writeUser(std::ostream &os) const; private: void RawSetStep(int i); void RawSetScale(int i); void RawSetShown(bool new_shown); void configureGrid(int step, bool shown); void configureSnap(bool snap); static const double scale_values[]; static const int digit_scales[]; Listener& listener; }; std::string getValuesFLTKMenuString(); } // namespace grid #endif /* __EUREKA_R_GRID_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/r_opengl.cc000066400000000000000000001341111464327712600204450ustar00rootroot00000000000000//------------------------------------------------------------------------ // 3D RENDERING : OPENGL //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2020 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef NO_OPENGL #include "Instance.h" #include "main.h" #include #include #include "FL/gl.h" #include "e_main.h" #include "e_hover.h" // PointOnLineSide #include "e_linedef.h" // LD_RailHeights #include "LineDef.h" #include "m_config.h" #include "m_game.h" #include "m_bitvec.h" #include "Sector.h" #include "SideDef.h" #include "Thing.h" #include "Vertex.h" #include "w_rawdef.h" #include "w_texture.h" #include "r_render.h" #include "r_subdiv.h" #include "ui_window.h" // convert from our coordinate system (looking along +X) // to OpenGL's coordinate system (looking down -Z). static const GLdouble flip_matrix[16] = { 0, 0, -1, 0, -1, 0, 0, 0, 0, +1, 0, 0, 0, 0, 0, +1 }; // The emulation of DOOM lighting here targets a very basic // version of OpenGL: 1.2 or so. It works by clipping walls // and sector triangles against a small set of infinite lines // at specific distances from the camera. Once clipped, the // light level of a primitive is constant, determined from // the pair of clipping lines it ends up in. #define LCLIP_NUM 14 static const float light_clip_dists[LCLIP_NUM] = { 1280, 640, 428, 320, 256, 216, 176, 144, 120, 104, 88, 72, 60, 40 }; static float DoomLightToFloat(int light, float dist) { int map = R_DoomLightingEquation(light, dist); int level = (31 - map) * 8 + 7; // need to gamma-correct the light level if (config::usegamma > 0) level = gammatable[config::usegamma][level]; return level / 255.0f; } struct RendInfo3D { public: // we don't test the visibility of sectors directly, instead we // mark sectors as visible when any linedef that touches the // sector is on-screen. bitvec_c seen_sectors; private: Instance &inst; public: explicit RendInfo3D(Instance &inst) : seen_sectors(inst.level.numSectors() + 1), inst(inst) { } ~RendInfo3D() { } inline float PointToAngle(float x, float y) { if (-0.01 < x && x < 0.01) return static_cast((y > 0) ? M_PI/2 : (3 * M_PI/2)); float angle = atan2(y, x); if (angle < 0) angle += static_cast(2*M_PI); return angle; } inline int AngleToX(float ang) { float t = static_cast(tan(M_PI/2 - ang)); int x = int(inst.r_view.aspect_sw * t); x = (inst.r_view.screen_w + x) / 2; if (x < 0) x = 0; else if (x > inst.r_view.screen_w) x = inst.r_view.screen_w; return x; } inline int DeltaToX(double iz, float tx) { int x = int(static_cast(inst.r_view.aspect_sw) * tx * iz); x = (x + inst.r_view.screen_w) / 2; return x; } Img_c *FindFlat(const SString &fname, byte& r, byte& g, byte& b, bool& fullbright) { fullbright = false; if (inst.is_sky(fname)) { fullbright = true; glBindTexture(GL_TEXTURE_2D, 0); inst.wad.palette.decodePixel(static_cast(inst.conf.miscInfo.sky_color), r, g, b); return NULL; } if (! inst.r_view.texturing) { glBindTexture(GL_TEXTURE_2D, 0); int col; // when lighting and no texturing, use a single color if (inst.r_view.lighting) col = inst.conf.miscInfo.floor_colors[1]; else col = HashedPalColor(fname, inst.conf.miscInfo.floor_colors); inst.wad.palette.decodePixel(static_cast(col), r, g, b); return NULL; } Img_c *img = inst.wad.images.getMutableFlat(inst.conf, fname); if (! img) { img = &inst.wad.images.getMutableUnknownFlat(inst.conf); fullbright = config::render_unknown_bright; } img->bind_gl(inst.wad); r = g = b = 255; return img; } Img_c *FindTexture(const SString &tname, byte& r, byte& g, byte& b, bool& fullbright) { fullbright = false; if (! inst.r_view.texturing) { glBindTexture(GL_TEXTURE_2D, 0); int col; // when lighting and no texturing, use a single color if (inst.r_view.lighting) col = inst.conf.miscInfo.wall_colors[1]; else col = HashedPalColor(tname, inst.conf.miscInfo.wall_colors); inst.wad.palette.decodePixel(static_cast(col), r, g, b); return NULL; } Img_c *img; if (is_null_tex(tname)) { img = &inst.wad.images.getMutableMissingTexture(inst.conf); fullbright = config::render_missing_bright; } else if (is_special_tex(tname)) { img = &inst.wad.images.getMutableSpecialTexture(inst.wad.palette); } else { img = inst.wad.images.getMutableTexture(inst.conf, tname); if (! img) { img = &inst.wad.images.getMutableUnknownTexture(inst.conf); fullbright = config::render_unknown_bright; } } img->bind_gl(inst.wad); r = g = b = 255; return img; } void RawClippedTriangle(float ax, float ay, float az, float atx, float aty, float bx, float by, float bz, float btx, float bty, float cx, float cy, float cz, float ctx, float cty, float r, float g, float b, float level) { glColor3f(level * r, level * g, level * b); glBegin(GL_POLYGON); glTexCoord2f(atx, aty); glVertex3f(ax, ay, az); glTexCoord2f(btx, bty); glVertex3f(bx, by, bz); glTexCoord2f(ctx, cty); glVertex3f(cx, cy, cz); glEnd(); } void LightClippedTriangle(double ax, double ay, float az, float atx, float aty, double bx, double by, float bz, float btx, float bty, double cx, double cy, float cz, float ctx, float cty, int clip, float r, float g, float b, int light) { float level = DoomLightToFloat(light, light_clip_dists[LCLIP_NUM-1] + 2.0f); for ( ; clip < LCLIP_NUM ; clip++) { float cdist = light_clip_dists[clip]; level = DoomLightToFloat(light, cdist + 2.0f); // coordinates of an infinite clipping line float c_x = static_cast(inst.r_view.x + inst.r_view.Cos * cdist); float c_y = static_cast(inst.r_view.y + inst.r_view.Sin * cdist); // vector of clipping line (if camera is north, this is east) float c_dx = static_cast(inst.r_view.Sin); float c_dy = static_cast(- inst.r_view.Cos); // check which side the triangle points are on double p1 = (ay - c_y) * c_dx - (ax - c_x) * c_dy; double p2 = (by - c_y) * c_dx - (bx - c_x) * c_dy; double p3 = (cy - c_y) * c_dx - (cx - c_x) * c_dy; int cat1 = (p1 < -0.1) ? -1 : (p1 > 0.1) ? +1 : 0; int cat2 = (p2 < -0.1) ? -1 : (p2 > 0.1) ? +1 : 0; int cat3 = (p3 < -0.1) ? -1 : (p3 > 0.1) ? +1 : 0; // completely on far side? if (cat1 >= 0 && cat2 >= 0 && cat3 >= 0) break; // completely on near side? if (cat1 <= 0 && cat2 <= 0 && cat3 <= 0) continue; // handle cases where partition goes through a vertex AND // cuts the opposite edge. if (cat1 == 0 || cat2 == 0 || cat3 == 0) { // rotate triangle so that C is on the partition, // and the edge AB is crossing the partition. if (cat1 == 0) { float _x = static_cast(cx); float _y = static_cast(cy); float _z = cz; float _tx = ctx; float _ty = cty; cx = ax; cy = ay; cz = az; ctx = atx; cty = aty; ax = bx; ay = by; az = bz; atx = btx; aty = bty; bx = _x; by = _y; bz = _z; btx = _tx; bty = _ty; p1 = p2; p2 = p3; cat1 = cat2; } else if (cat2 == 0) { float _x = static_cast(cx); float _y = static_cast(cy); float _z = cz; float _tx = ctx; float _ty = cty; cx = bx; cy = by; cz = bz; ctx = btx; cty = bty; bx = ax; by = ay; bz = az; btx = atx; bty = aty; ax = _x; ay = _y; az = _z; atx = _tx; aty = _ty; p2 = p1; p1 = p3; cat1 = cat3; } // compute intersection point double along = p1 / (p1 - p2); double ix = ax + (bx - ax) * along; double iy = ay + (by - ay) * along; double iz = az + (bz - az) * along; float itx = static_cast(atx + (btx - atx) * along); float ity = static_cast(aty + (bty - aty) * along); // draw the piece on FAR side of the clipping line, // and keep going with the piece on the NEAR side. if (cat1 > 0) { RawClippedTriangle(static_cast(ix), static_cast(iy), static_cast(iz), itx, ity, static_cast(cx), static_cast(cy), cz, ctx, cty, static_cast(ax), static_cast(ay), az, atx, aty, r, g, b, level); ax = ix; ay = iy; az = static_cast(iz); atx = itx; aty = ity; } else { RawClippedTriangle(static_cast(ix), static_cast(iy), static_cast(iz), itx, ity, static_cast(cx), static_cast(cy), cz, ctx, cty, static_cast(bx), static_cast(by), bz, btx, bty, r, g, b, level); bx = ix; by = iy; bz = static_cast(iz); btx = itx; bty = ity; } continue; } // AT HERE, the partition definitely cuts two edges. // The cut produces a triangle piece and a quadrilateral // piece. int combo = ((cat3>0)?4:0) | ((cat2>0)?2:0) | ((cat1>0)?1:0); // rotate triangle so that C is the tip of the triangle piece. if (combo == 1 || combo == 6) { float _x = static_cast(cx); float _y = static_cast(cy); float _z = cz; float _tx = ctx; float _ty = cty; double _p = p3; cx = ax; cy = ay; cz = az; ctx = atx; cty = aty; p3 = p1; ax = bx; ay = by; az = bz; atx = btx; aty = bty; p1 = p2; bx = _x; by = _y; bz = _z; btx = _tx; bty = _ty; p2 = _p; } else if (combo == 2 || combo == 5) { float _x = static_cast(cx); float _y = static_cast(cy); float _z = cz; float _tx = ctx; float _ty = cty; double _p = p3; cx = bx; cy = by; cz = bz; ctx = btx; cty = bty; p3 = p2; bx = ax; by = ay; bz = az; btx = atx; bty = aty; p2 = p1; ax = _x; ay = _y; az = _z; atx = _tx; aty = _ty; p1 = _p; } // compute intersection points double ac_along = p1 / (p1 - p3); double bc_along = p2 / (p2 - p3); double ac_x = ax + (cx - ax) * ac_along; double ac_y = ay + (cy - ay) * ac_along; double ac_z = az + (cz - az) * ac_along; double bc_x = bx + (cx - bx) * bc_along; double bc_y = by + (cy - by) * bc_along; double bc_z = bz + (cz - bz) * bc_along; float ac_tx = static_cast(atx + (ctx - atx) * ac_along); float ac_ty = static_cast(aty + (cty - aty) * ac_along); float bc_tx = static_cast(btx + (ctx - btx) * bc_along); float bc_ty = static_cast(bty + (cty - bty) * bc_along); // handle cases where triangle piece is on NEAR side. if (combo == 3 || combo == 5 || combo == 6) { RawClippedTriangle(static_cast(ax), static_cast(ay), az, atx, aty, static_cast(bx), static_cast(by), bz, btx, bty, static_cast(ac_x), static_cast(ac_y), static_cast(ac_z), ac_tx, ac_ty, r, g, b, level); RawClippedTriangle(static_cast(bx), static_cast(by), bz, btx, bty, static_cast(bc_x), static_cast(bc_y), static_cast(bc_z), bc_tx, bc_ty, static_cast(ac_x), static_cast(ac_y), static_cast(ac_z), ac_tx, ac_ty, r, g, b, level); ax = ac_x; ay = ac_y; az = static_cast(ac_z); atx = ac_tx; aty = ac_ty; bx = bc_x; by = bc_y; bz = static_cast(bc_z); btx = bc_tx; bty = bc_ty; continue; } // handle cases where triangle piece is on FAR side. // these cases require recursion to deal with the // quadrilateral on the near side. { RawClippedTriangle(static_cast(cx), static_cast(cy), cz, ctx, cty, static_cast(ac_x), static_cast(ac_y), static_cast(ac_z), ac_tx, ac_ty, static_cast(bc_x), static_cast(bc_y), static_cast(bc_z), bc_tx, bc_ty, r, g, b, level); // recurse! LightClippedTriangle(ax, ay, az, atx, aty, ac_x, ac_y, static_cast(ac_z), ac_tx, ac_ty, bc_x, bc_y, static_cast(bc_z), bc_tx, bc_ty, (clip + 1), r, g, b, light); cx = bc_x; cy = bc_y; cz = static_cast(bc_z); ctx = bc_tx; cty = bc_ty; } } RawClippedTriangle(static_cast(ax), static_cast(ay), az, atx, aty, static_cast(bx), static_cast(by), bz, btx, bty, static_cast(cx), static_cast(cy), cz, ctx, cty, r, g, b, level); } void RawClippedQuad(float x1, float y1, const slope_plane_c *p1, float x2, float y2, const slope_plane_c *p2, float tx1, float tx2, float tex_top, float tex_scale, char where, float r, float g, float b, float level) { float za1 = static_cast(p1->SlopeZ(x1, y1)); float za2 = static_cast(p2->SlopeZ(x1, y1)); float zb1 = static_cast(p1->SlopeZ(x2, y2)); float zb2 = static_cast(p2->SlopeZ(x2, y2)); // check heights [ for sides of slopes ] if (za2 <= za1 && zb2 <= zb1) { return; } else if (za2 < za1) { if (where == 'U') za2 = za1; else za1 = za2; } else if (zb2 < zb1) { if (where == 'U') zb2 = zb1; else zb1 = zb2; } glColor3f(level * r, level * g, level * b); glBegin(GL_QUADS); glTexCoord2f(tx1, (za1 - tex_top) * tex_scale); glVertex3f(x1, y1, za1); glTexCoord2f(tx1, (za2 - tex_top) * tex_scale); glVertex3f(x1, y1, za2); glTexCoord2f(tx2, (zb2 - tex_top) * tex_scale); glVertex3f(x2, y2, zb2); glTexCoord2f(tx2, (zb1 - tex_top) * tex_scale); glVertex3f(x2, y2, zb1); glEnd(); } void LightClippedQuad(double x1, double y1, const slope_plane_c *p1, double x2, double y2, const slope_plane_c *p2, float tx1, float tx2, float tex_top, float tex_scale, char where, float r, float g, float b, int light) { float level = DoomLightToFloat(light, light_clip_dists[LCLIP_NUM-1] + 2.0f); for (int clip = 0 ; clip < LCLIP_NUM ; clip++) { float cdist = light_clip_dists[clip]; level = DoomLightToFloat(light, cdist + 2.0f); // coordinates of an infinite clipping line float c_x = static_cast(inst.r_view.x + inst.r_view.Cos * cdist); float c_y = static_cast(inst.r_view.y + inst.r_view.Sin * cdist); // vector of clipping line (if camera is north, this is east) float c_dx = static_cast(inst.r_view.Sin); float c_dy = static_cast(- inst.r_view.Cos); // check which side the start/end point is on double n1 = (y1 - c_y) * c_dx - (x1 - c_x) * c_dy; double n2 = (y2 - c_y) * c_dx - (x2 - c_x) * c_dy; int cat1 = (n1 < -0.1) ? -1 : (n1 > 0.1) ? +1 : 0; int cat2 = (n2 < -0.1) ? -1 : (n2 > 0.1) ? +1 : 0; // completely on far side? if (cat1 >= 0 && cat2 >= 0) break; // does it cross the partition? if ((cat1 < 0 && cat2 > 0) || (cat1 > 0 && cat2 < 0)) { // compute intersection point double along = n1 / (n1 - n2); double ix = x1 + (x2 - x1) * along; double iy = y1 + (y2 - y1) * along; float itx = static_cast(tx1 + (tx2 - tx1) * along); // draw the piece on FAR side of the clipping line, // and keep going with the piece on the NEAR side. if (cat2 > 0) { RawClippedQuad(static_cast(ix), static_cast(iy),p1, static_cast(x2), static_cast(y2),p2, itx,tx2,tex_top,tex_scale, where, r,g,b, level); x2 = ix; y2 = iy; tx2 = itx; } else { RawClippedQuad(static_cast(x1), static_cast(y1),p1, static_cast(ix), static_cast(iy),p2, tx1,itx,tex_top,tex_scale, where, r,g,b, level); x1 = ix; y1 = iy; tx1 = itx; } } } RawClippedQuad(static_cast(x1), static_cast(y1),p1, static_cast(x2), static_cast(y2),p2, tx1,tx2,tex_top,tex_scale, where, r,g,b, level); } inline bool IsPolygonClipped(const sector_polygon_t *poly) { int p; for (p = 0 ; p < poly->count ; p++) { float px = poly->mx[p]; float py = poly->my[p]; double dist = (py - inst.r_view.y) * inst.r_view.Sin + (px - inst.r_view.x) * inst.r_view.Cos; if (dist < config::render_far_clip + 1) break; } // whole polygon was beyond the far clip? if (p == poly->count) return true; return false; } void DrawSectorPolygons(const Sector *sec, sector_subdivision_c *subdiv, const slope_plane_c *plane, int znormal, float z, const SString &fname) { bool is_slope = plane && plane->sloped; // check if camera is behind plane if (! is_slope) { if (znormal > 0 && inst.r_view.z < z) return; if (znormal < 0 && inst.r_view.z > z) return; } byte r0, g0, b0; bool fullbright; Img_c *img = FindFlat(fname, r0, g0, b0, fullbright); float r = r0 / 255.0f; float g = g0 / 255.0f; float b = b0 / 255.0f; for (unsigned int i = 0 ; i < subdiv->polygons.size() ; i++) { const sector_polygon_t *poly = &subdiv->polygons[i]; // not sure this is worth it, just let OpenGL clip it #if 0 if (IsPolygonClipped(poly)) continue; #endif if (inst.r_view.lighting && !fullbright) { float ax = poly->mx[0]; float ay = poly->my[0]; float az = static_cast(plane ? plane->SlopeZ(ax, ay) : z); float atx = ax / 64.0f; // see note below float aty = ay / 64.0f; float bx = poly->mx[1]; float by = poly->my[1]; float bz = static_cast(plane ? plane->SlopeZ(bx, by) : z); float btx = bx / 64.0f; // see note below float bty = by / 64.0f; float cx = poly->mx[2]; float cy = poly->my[2]; float cz = static_cast(plane ? plane->SlopeZ(cx, cy) : z); float ctx = cx / 64.0f; float cty = cy / 64.0f; LightClippedTriangle(ax, ay, az, atx, aty, bx, by, bz, btx, bty, cx, cy, cz, ctx, cty, 0, r, g, b, sec->light); if (poly->count == 4) { float dx = poly->mx[3]; float dy = poly->my[3]; float dz = static_cast(plane ? plane->SlopeZ(dx, dy) : z); float dtx = dx / 64.0f; float dty = dy / 64.0f; LightClippedTriangle(ax, ay, az, atx, aty, cx, cy, cz, ctx, cty, dx, dy, dz, dtx, dty, 0, r, g, b, sec->light); } } else { glColor3f(r, g, b); glBegin(GL_POLYGON); for (int p = 0 ; p < poly->count ; p++) { float px = poly->mx[p]; float py = poly->my[p]; float pz = static_cast(plane ? plane->SlopeZ(px, py) : z); if (img) { // this logic follows ZDoom, which scales large flats to // occupy a 64x64 unit area. I presume wall textures // used on floors or ceilings is the same.... glTexCoord2f(px / 64.0f, py / 64.0f); } glVertex3f(px, py, pz); } glEnd(); } } } // the "where" parameter can be: // - 'W' for one-sided wall // - 'L' for lower // - 'U' for upper // - 'E' for extrafloor side void DrawSide(char where, const LineDef *ld, const SideDef *sd, const SString &texname, const Sector *front, const Sector *back, bool sky_upper, float ld_length, float x1, float y1, const slope_plane_c *p1, float x2, float y2, const slope_plane_c *p2) { byte r, g, b; bool fullbright = true; Img_c *img = NULL; if (sky_upper && where == 'U') { glBindTexture(GL_TEXTURE_2D, 0); inst.wad.palette.decodePixel(static_cast(inst.conf.miscInfo.sky_color), r, g, b); } else { img = FindTexture(texname, r, g, b, fullbright); } // compute texture coords float tx1 = 0.0; float tx2 = 1.0; float tex_top = 0; float tex_scale = 1.0 / 128.0; if (img) { float img_w = static_cast(img->width()); float img_h = static_cast(img->height()); float img_tw, img_th; if (global::use_npot_textures) { img_tw = img_w; img_th = img_h; } else { img_tw = static_cast(RoundPOW2(static_cast(img_w))); img_th = static_cast(RoundPOW2(static_cast(img_h))); } tx1 = 0; tx2 = tx1 + ld_length; tex_top = static_cast(front->ceilh); if (where == 'W' && (ld->flags & MLF_LowerUnpegged)) { tex_top = front->floorh + img_h; } if (where == 'L') { if (0 == (ld->flags & MLF_LowerUnpegged)) { tex_top = static_cast(back->floorh); } else { // an unpegged lower will align with a normal 1S wall, // unless both front/back ceilings are sky.... tex_top = static_cast(sky_upper ? back->ceilh : front->ceilh); } } if (where == 'U' && (0 == (ld->flags & MLF_UpperUnpegged))) { tex_top = back->ceilh + img_h; } tx1 = (tx1 + sd->x_offset) / img_tw; tx2 = (tx2 + sd->x_offset) / img_tw; tex_top += (img_th - img_h); tex_top += sd->y_offset; tex_scale = 1.0f / img_th; } glDisable(GL_ALPHA_TEST); double r0 = (double)r / 255.0; double g0 = (double)g / 255.0; double b0 = (double)b / 255.0; if (inst.r_view.lighting && !fullbright) { int light = front->light; // add "fake constrast" for axis-aligned walls if (inst.level.isVertical(*ld)) light += 16; else if (inst.level.isHorizontal(*ld)) light -= 16; LightClippedQuad(x1,y1,p1, x2,y2,p2, tx1,tx2,tex_top,tex_scale, where, static_cast(r0), static_cast(g0), static_cast(b0), light); } else { RawClippedQuad(x1,y1,p1, x2,y2,p2, tx1,tx2,tex_top,tex_scale, where, static_cast(r0), static_cast(g0), static_cast(b0), 1.0); } } void DrawMidMasker(const LineDef *ld, const SideDef *sd, const Sector *front, const Sector *back, bool sky_upper, float ld_length, float x1, float y1, float x2, float y2) { byte r, g, b; bool fullbright; Img_c *img; img = FindTexture(sd->MidTex(), r, g, b, fullbright); if (img == NULL) return; float img_w = static_cast(img->width()); float img_h = static_cast(img->height()); float img_tw, img_th; if (global::use_npot_textures) { img_tw = img_w; img_th = img_h; } else { img_tw = static_cast(RoundPOW2(static_cast(img_w))); img_th = static_cast(RoundPOW2(static_cast(img_h))); } // compute Z coords and texture coords float z1 = static_cast(std::max(front->floorh, back->floorh)); float z2 = static_cast(std::min(front->ceilh, back->ceilh)); if (z2 <= z1) return; float tx1 = 0.0; float tx2 = tx1 + ld_length; tx1 = (tx1 + sd->x_offset) / img_tw; tx2 = (tx2 + sd->x_offset) / img_tw; if (ld->flags & MLF_LowerUnpegged) { z1 = z1 + sd->y_offset; z2 = z1 + img_h; } else { z2 = z2 + sd->y_offset; z1 = z2 - img_h; } glEnable(GL_ALPHA_TEST); slope_plane_c p1; p1.Init(z1); slope_plane_c p2; p2.Init(z2); double r0 = (double)r / 255.0; double g0 = (double)g / 255.0; double b0 = (double)b / 255.0; float tex_scale = 1.0f / img_th; if (inst.r_view.lighting && !fullbright) { int light = inst.level.getSector(*sd).light; // add "fake constrast" for axis-aligned walls if (inst.level.isVertical(*ld)) light += 16; else if (inst.level.isHorizontal(*ld)) light -= 16; LightClippedQuad(x1,y1,&p1, x2,y2,&p2, tx1,tx2,z1,tex_scale, 'R', static_cast(r0), static_cast(g0), static_cast(b0), light); } else { RawClippedQuad(x1,y1,&p1, x2,y2,&p2, tx1,tx2,z1,tex_scale, 'R', static_cast(r0), static_cast(g0), static_cast(b0), 1.0); } } void DrawLine(int ld_index) { const auto ld = inst.level.linedefs[ld_index]; if (!inst.level.isVertex(ld->start) || !inst.level.isVertex(ld->end)) return; if (! inst.level.getRight(*ld)) return; float x1 = static_cast(inst.level.getStart(*ld).x() - inst.r_view.x); float y1 = static_cast(inst.level.getStart(*ld).y() - inst.r_view.y); float x2 = static_cast(inst.level.getEnd(*ld).x() - inst.r_view.x); float y2 = static_cast(inst.level.getEnd(*ld).y() - inst.r_view.y); float tx1 = static_cast(x1 * inst.r_view.Sin - y1 * inst.r_view.Cos); float ty1 = static_cast(x1 * inst.r_view.Cos + y1 * inst.r_view.Sin); float tx2 = static_cast(x2 * inst.r_view.Sin - y2 * inst.r_view.Cos); float ty2 = static_cast(x2 * inst.r_view.Cos + y2 * inst.r_view.Sin); // reject line if complete behind viewplane if (ty1 <= 0 && ty2 <= 0) return; // too far away? if (std::min(ty1, ty2) > config::render_far_clip) return; float angle1 = PointToAngle(tx1, ty1); float angle2 = PointToAngle(tx2, ty2); float span = angle1 - angle2; if (span < 0) span += static_cast(2*M_PI); Side side = Side::right; if (span >= M_PI) side = Side::left; // ignore the line when there is no facing sidedef const SideDef *sd = (side == Side::left) ? inst.level.getLeft(*ld) : inst.level.getRight(*ld); if (! sd) return; if (side == Side::left) { float tmp = angle1; angle1 = angle2; angle2 = tmp; } // clip angles to view volume float leftclip = static_cast((3 * M_PI / 4)); float rightclip = static_cast(M_PI / 4); float tspan1 = angle1 - rightclip; float tspan2 = leftclip - angle2; if (tspan1 < 0) tspan1 += static_cast(2*M_PI); if (tspan2 < 0) tspan2 += static_cast(2*M_PI); if (tspan1 > M_PI/2) { // Totally off the left edge? if (tspan2 >= M_PI) return; angle1 = leftclip; } if (tspan2 > M_PI/2) { // Totally off the left edge? if (tspan1 >= M_PI) return; angle2 = rightclip; } // convert angles to on-screen X positions int sx1 = AngleToX(angle1); int sx2 = AngleToX(angle2); if (sx1 > sx2) return; // compute distance from eye to wall float wdx = x2 - x1; float wdy = y2 - y1; float wlen = sqrt(wdx * wdx + wdy * wdy); float dist = fabs((y1 * wdx / wlen) - (x1 * wdy / wlen)); if (dist < 0.01) return; bool self_ref = false; if (inst.level.getLeft(*ld) && inst.level.getRight(*ld) && inst.level.getLeft(*ld)->sector == inst.level.getRight(*ld)->sector) self_ref = true; // mark sectors to be drawn // [ this method means we don't need to check visibility of sectors ] if (! self_ref) { if (inst.level.getLeft(*ld) && inst.level.isSector(inst.level.getLeft(*ld)->sector)) seen_sectors.set(inst.level.getLeft(*ld)->sector); if (inst.level.getRight(*ld) && inst.level.isSector(inst.level.getRight(*ld)->sector)) seen_sectors.set(inst.level.getRight(*ld)->sector); } /* actually draw it... */ x1 = static_cast(inst.level.getStart(*ld).x()); y1 = static_cast(inst.level.getStart(*ld).y()); x2 = static_cast(inst.level.getEnd(*ld).x()); y2 = static_cast(inst.level.getEnd(*ld).y()); if (side == Side::left) { std::swap(x1, x2); std::swap(y1, y2); } float ld_len = hypotf(x2 - x1, y2 - y1); const Sector *front = sd ? &inst.level.getSector(*sd) : NULL; bool sky_front = inst.is_sky(front->CeilTex()); bool sky_upper = false; if (ld->OneSided()) { sector_3dfloors_c *ex = inst.Subdiv_3DFloorsForSector(sd->sector); DrawSide('W', ld.get(), sd, sd->MidTex(), front, NULL, false, ld_len, x1, y1, &ex->f_plane, x2, y2, &ex->c_plane); } else { const SideDef *sd_back = (side == Side::left) ? inst.level.getRight(*ld) : inst.level.getLeft(*ld); const Sector *back = sd_back ? &inst.level.getSector(*sd_back) : NULL; sky_upper = sky_front && inst.is_sky(back->CeilTex()); // check for BOOM 242 invisible platforms bool invis_back = false; sector_3dfloors_c *b_ex = inst.Subdiv_3DFloorsForSector(sd_back->sector); if (b_ex->heightsec >= 0) { const auto dummy = inst.level.sectors[b_ex->heightsec]; if (dummy->floorh < back->floorh) invis_back = true; } sector_3dfloors_c *f_ex = inst.Subdiv_3DFloorsForSector(sd->sector); slope_plane_c *f_floorp = &f_ex->f_plane; slope_plane_c dummy_fp; if (f_ex->heightsec >= 0) { const auto dummy = inst.level.sectors[f_ex->heightsec]; if (dummy->floorh < front->floorh) { dummy_fp.Init(static_cast(dummy->floorh)); f_floorp = &dummy_fp; } } // we skip height check for slopes, but RawClippedQuad will handle it bool f_sloped = f_ex->f_plane.sloped || b_ex->f_plane.sloped; bool c_sloped = f_ex->c_plane.sloped || b_ex->c_plane.sloped; // lower part if ((back->floorh > front->floorh || f_sloped) && !self_ref && !invis_back) DrawSide('L', ld.get(), sd, sd->LowerTex(), front, back, sky_upper, ld_len, x1, y1, f_floorp, x2, y2, &b_ex->f_plane); // upper part if ((back->ceilh < front->ceilh || c_sloped) && !self_ref && !sky_upper) DrawSide('U', ld.get(), sd, sd->UpperTex(), front, back, sky_upper, ld_len, x1, y1, &b_ex->c_plane, x2, y2, &f_ex->c_plane); // railing tex if (!is_null_tex(sd->MidTex()) && inst.r_view.texturing) DrawMidMasker(ld.get(), sd, front, back, sky_upper, ld_len, x1, y1, x2, y2); // draw sides of extrafloors if (front->tag != back->tag) { for (size_t k = 0 ; k < b_ex->floors.size() ; k++) { const extrafloor_c& EF = b_ex->floors[k]; const auto ef_sd = inst.level.sidedefs[EF.sd]; const auto dummy = inst.level.sectors[ef_sd->sector]; if (EF.flags & (EXFL_TOP | EXFL_BOTTOM)) continue; int top_h = dummy->ceilh; int bottom_h = dummy->floorh; if (EF.flags & EXFL_VAVOOM) std::swap(top_h, bottom_h); if (top_h <= bottom_h) continue; SString tex = "-"; if (EF.flags & EXFL_UPPER) tex = sd->UpperTex(); else if (EF.flags & EXFL_LOWER) tex = sd->LowerTex(); else tex = ef_sd->MidTex(); slope_plane_c p1; p1.Init(static_cast(bottom_h)); slope_plane_c p2; p2.Init(static_cast(top_h)); DrawSide('E', ld.get(), sd, tex, front, back, false, ld_len, x1, y1, &p1, x2, y2, &p2); } } } /* EMULATE VANILLA SKIES */ // we don't draw the skies as polygons, nor do we draw the upper // of a linedef which has sky on both sides. instead we draw a // very tall quad (like a wall part) above a solid wall where it // meets a sky sector. if (sky_front && !sky_upper) { slope_plane_c p1; p1.Init(static_cast(front->ceilh)); slope_plane_c p2; p2.Init(static_cast(front->ceilh + 16384.0)); DrawSide('U', ld.get(), sd, "-", front, NULL, true /* sky_upper */, ld_len, x1, y1, &p1, x2, y2, &p2); } } void DrawSector(int sec_index) { sector_subdivision_c *subdiv = inst.Subdiv_PolygonsForSector(sec_index); if (! subdiv) return; const auto sec = inst.level.sectors[sec_index]; sector_3dfloors_c *exfloor = inst.Subdiv_3DFloorsForSector(sec_index); glColor3f(1, 1, 1); // support for BOOM's 242 "transfer heights" line type if (exfloor->heightsec >= 0) { const auto dummy = inst.level.sectors[exfloor->heightsec]; if (dummy->floorh > sec->floorh && inst.r_view.z < dummy->floorh) { // space C : underwater DrawSectorPolygons(sec.get(), subdiv, NULL, -1, static_cast(dummy->floorh), dummy->CeilTex()); DrawSectorPolygons(sec.get(), subdiv, NULL, +1, static_cast(sec->floorh), dummy->FloorTex()); // this helps the view to not look weird when clipping around if (dummy->ceilh > sec->floorh) DrawSectorPolygons(sec.get(), subdiv, NULL, -1, static_cast(dummy->ceilh), sec->CeilTex()); } else if (dummy->ceilh < sec->ceilh && inst.r_view.z > dummy->ceilh) { // space A : head over ceiling DrawSectorPolygons(sec.get(), subdiv, NULL, -1, static_cast(dummy->ceilh), dummy->FloorTex()); DrawSectorPolygons(sec.get(), subdiv, NULL, -1, static_cast(sec->ceilh), dummy->CeilTex()); if (dummy->floorh < sec->ceilh) DrawSectorPolygons(sec.get(), subdiv, NULL, +1, static_cast(dummy->floorh), sec->FloorTex()); } else if (dummy->floorh < sec->floorh) { // invisible platform DrawSectorPolygons(sec.get(), subdiv, NULL, +1, static_cast(dummy->floorh), sec->FloorTex()); if (!inst.is_sky(sec->CeilTex())) DrawSectorPolygons(sec.get(), subdiv, NULL, -1, static_cast(dummy->ceilh), sec->CeilTex()); } else { // space B : normal DrawSectorPolygons(sec.get(), subdiv, NULL, +1, static_cast(dummy->floorh), sec->FloorTex()); if (!inst.is_sky(sec->CeilTex())) DrawSectorPolygons(sec.get(), subdiv, NULL, -1, static_cast(dummy->ceilh), sec->CeilTex()); } } else { // normal sector DrawSectorPolygons(sec.get(), subdiv, &exfloor->f_plane, +1, static_cast(sec->floorh), sec->FloorTex()); if (!inst.is_sky(sec->CeilTex())) DrawSectorPolygons(sec.get(), subdiv, &exfloor->c_plane, -1, static_cast(sec->ceilh), sec->CeilTex()); } // draw planes of 3D floors for (size_t k = 0 ; k < exfloor->floors.size() ; k++) { const extrafloor_c& EF = exfloor->floors[k]; const auto dummy = inst.level.sectors[inst.level.sidedefs[EF.sd]->sector]; // TODO: supporting translucent surfaces is non-trivial and needs // to be done in separate pass with a depth sort. bool is_trans = (EF.flags & EXFL_TRANSLUC) != 0; (void) is_trans; int top_h = dummy->ceilh; int bottom_h = dummy->floorh; SString top_tex = dummy->CeilTex(); SString bottom_tex = dummy->FloorTex(); if (EF.flags & EXFL_TOP) bottom_h = top_h; else if (EF.flags & EXFL_BOTTOM) top_h = bottom_h; else if (EF.flags & EXFL_VAVOOM) { std::swap(top_h, bottom_h); std::swap(top_tex, bottom_tex); } DrawSectorPolygons(sec.get(), subdiv, NULL, +1, static_cast(top_h), top_tex); DrawSectorPolygons(sec.get(), subdiv, NULL, -1, static_cast(bottom_h), bottom_tex); } } void DrawThing(int th_index) { const auto th = inst.level.things[th_index]; const thingtype_t &info = inst.conf.getThingType(th->type); // project sprite to check if it is off-screen float x = static_cast(th->x() - inst.r_view.x); float y = static_cast(th->y() - inst.r_view.y); float tx = static_cast(x * inst.r_view.Sin - y * inst.r_view.Cos); float ty = static_cast(x * inst.r_view.Cos + y * inst.r_view.Sin); // sprite is complete behind viewplane? if (ty < 4) return; if (config::render_far_clip > 0 && ty > config::render_far_clip) return; bool fullbright = false; if (info.flags & THINGDEF_LIT) fullbright = true; float scale = info.scale; Img_c *img = inst.wad.getMutableSprite(inst.conf, th->type, inst.loaded, Render3D_CalcRotation(inst.r_view.angle, th->angle)); if (! img) { img = &inst.wad.images.IM_UnknownSprite(inst.conf); fullbright = true; scale = 0.33f; } int offsetX, offsetY; img->getSpriteOffset(offsetX, offsetY); float scale_w = img->width() * scale; float scale_h = img->height() * scale; float tx1 = tx - scale_w * 0.5f; float tx2 = tx + scale_w * 0.5f; float ty1, ty2; double iz = 1 / ty; int sx1 = DeltaToX(iz, tx1); int sx2 = DeltaToX(iz, tx2); if (sx2 < 0 || sx1 > inst.r_view.screen_w) return; // sprite is potentially visible, so draw it // choose X/Y coordinates so quad faces the camera float x1 = static_cast(th->x() - inst.r_view.Sin * scale_w * 0.5); float y1 = static_cast(th->y() + inst.r_view.Cos * scale_w * 0.5); float x2 = static_cast(th->x() + inst.r_view.Sin * scale_w * 0.5); float y2 = static_cast(th->y() - inst.r_view.Cos * scale_w * 0.5); int sec_num = inst.r_view.thing_sectors[th_index]; float z1, z2; if (info.flags & THINGDEF_CEIL) { // IOANCH 9/2015: add thing z (for Hexen format) z2 = static_cast((inst.level.isSector(sec_num) ? inst.level.sectors[sec_num]->ceilh : 192) - th->h()); z1 = z2 - scale_h; } else { z1 = static_cast((inst.level.isSector(sec_num) ? inst.level.sectors[sec_num]->floorh : 0) + th->h() + std::max(0, offsetY - img->height())); z2 = z1 + scale_h; } // bind the sprite image (upload it to OpenGL if needed) img->bind_gl(inst.wad); // choose texture coords based on image size tx1 = 0.0; ty1 = 0.0; if (global::use_npot_textures) { tx2 = 1.0; ty2 = 1.0; } else { tx2 = (float)img->width() / (float)RoundPOW2(img->width()); ty2 = (float)img->height() / (float)RoundPOW2(img->height()); } // lighting float L = 1.0; if (inst.r_view.lighting && !fullbright) { int light = inst.level.isSector(sec_num) ? inst.level.sectors[sec_num]->light : 255; L = DoomLightToFloat(light, ty /* dist */); } glColor3f(L, L, L); glBegin(GL_QUADS); glTexCoord2f(tx1, ty1); glVertex3f(x1, y1, z1); glTexCoord2f(tx1, ty2); glVertex3f(x1, y1, z2); glTexCoord2f(tx2, ty2); glVertex3f(x2, y2, z2); glTexCoord2f(tx2, ty1); glVertex3f(x2, y2, z1); glEnd(); } void HighlightLine(int ld_index, int part) { const auto L = inst.level.linedefs[ld_index]; Side side = (part & PART_LF_ALL) ? Side::left : Side::right; const SideDef *sd = (side == Side::left) ? inst.level.getLeft(*L) : inst.level.getRight(*L); if (sd == NULL) return; float x1 = static_cast(inst.level.getStart(*L).x()); float y1 = static_cast(inst.level.getStart(*L).y()); float x2 = static_cast(inst.level.getEnd(*L).x()); float y2 = static_cast(inst.level.getEnd(*L).y()); // check that this side is facing the camera Side cam_side = PointOnLineSide(inst.r_view.x, inst.r_view.y, x1,y1,x2,y2); if (cam_side != side) return; const SideDef *sd_back = (side == Side::left) ? inst.level.getRight(*L) : inst.level.getLeft(*L); const Sector *front = &inst.level.getSector(*sd); const Sector *back = sd_back ? &inst.level.getSector(*sd_back) : NULL; float z1, z2; if (L->TwoSided()) { if (part & (PART_RT_LOWER | PART_LF_LOWER)) { z1 = static_cast(std::min(front->floorh, back->floorh)); z2 = static_cast(std::max(front->floorh, back->floorh)); } else if (part & (PART_RT_UPPER | PART_LF_UPPER)) { z1 = static_cast(std::min(front->ceilh, back->ceilh)); z2 = static_cast(std::max(front->ceilh, back->ceilh)); } else { int zi1, zi2; if (! inst.LD_RailHeights(zi1, zi2, L.get(), sd, front, back)) return; z1 = static_cast(zi1); z2 = static_cast(zi2); } } else // one-sided line { if (0 == (part & (PART_RT_LOWER | PART_LF_LOWER))) return; z1 = static_cast(front->floorh); z2 = static_cast(front->ceilh); } glBegin(GL_LINE_LOOP); glVertex3f(x1, y1, z1); glVertex3f(x1, y1, z2); glVertex3f(x2, y2, z2); glVertex3f(x2, y2, z1); glEnd(); } void HighlightSector(int sec_index, int part) { const auto sec = inst.level.sectors[sec_index]; float z = static_cast((part == PART_CEIL) ? sec->ceilh : sec->floorh); // are we dragging this surface? if (inst.edit.action == EditorAction::drag && (!inst.edit.dragged.valid() || (inst.edit.dragged.num == sec_index && (inst.edit.dragged.parts == 0 || (inst.edit.dragged.parts & part)) ))) { z = z + inst.edit.drag_sector_dz; } else { // check that plane faces the camera if (part == PART_FLOOR && (inst.r_view.z < z + 0.2)) return; if (part == PART_CEIL && (inst.r_view.z > z - 0.2)) return; } for (const auto &L : inst.level.linedefs) { if (inst.level.touchesSector(*L, sec_index)) { float x1 = static_cast(inst.level.getStart(*L).x()); float y1 = static_cast(inst.level.getStart(*L).y()); float x2 = static_cast(inst.level.getEnd(*L).x()); float y2 = static_cast(inst.level.getEnd(*L).y()); glBegin(GL_LINE_STRIP); glVertex3f(x1, y1, z); glVertex3f(x2, y2, z); glEnd(); } } } void HighlightThing(int th_index) { const auto th = inst.level.things[th_index]; float tx = static_cast(th->x()); float ty = static_cast(th->y()); float drag_dz = 0; if (inst.edit.action == EditorAction::drag && (!inst.edit.dragged.valid() || inst.edit.dragged.num == th_index)) { tx += static_cast(inst.edit.drag_cur.x - inst.edit.drag_start.x); ty += static_cast(inst.edit.drag_cur.y - inst.edit.drag_start.y); drag_dz = static_cast(inst.edit.drag_cur.z - inst.edit.drag_start.z); } const thingtype_t &info = inst.conf.getThingType(th->type); float scale = info.scale; const Img_c *img = inst.wad.getSprite(inst.conf, th->type, inst.loaded, Render3D_CalcRotation(inst.r_view.angle, th->angle)); if (! img) { img = &inst.wad.images.IM_UnknownSprite(inst.conf); scale = 0.33f; } float scale_w = img->width() * scale; float scale_h = img->height() * scale; // choose X/Y coordinates so quad faces the camera float x1 = static_cast(tx - inst.r_view.Sin * scale_w * 0.5); float y1 = static_cast(ty + inst.r_view.Cos * scale_w * 0.5); float x2 = static_cast(tx + inst.r_view.Sin * scale_w * 0.5); float y2 = static_cast(ty - inst.r_view.Cos * scale_w * 0.5); int sec_num = inst.r_view.thing_sectors[th_index]; float z1, z2; if (info.flags & THINGDEF_CEIL) { // IOANCH 9/2015: add thing z (for Hexen format) z2 = static_cast((inst.level.isSector(sec_num) ? inst.level.sectors[sec_num]->ceilh : 192) - th->h()); z1 = z2 - scale_h; } else { z1 = static_cast((inst.level.isSector(sec_num) ? inst.level.sectors[sec_num]->floorh : 0) + th->h()); z2 = z1 + scale_h; } z1 += drag_dz; z2 += drag_dz; glBegin(GL_LINE_LOOP); glVertex3f(x1, y1, z1); glVertex3f(x1, y1, z2); glVertex3f(x2, y2, z2); glVertex3f(x2, y2, z1); glEnd(); } void HighlightObject(Objid& obj) { if (!obj.valid()) return; if (obj.type == ObjType::things) { HighlightThing(obj.num); } else if (obj.type == ObjType::sectors) { if (obj.parts == 0 || (obj.parts & PART_FLOOR)) HighlightSector(obj.num, PART_FLOOR); if (obj.parts == 0 || (obj.parts & PART_CEIL)) HighlightSector(obj.num, PART_CEIL); } else if (obj.type == ObjType::linedefs) { /* right side */ if (obj.parts == 0 || (obj.parts & PART_RT_LOWER)) HighlightLine(obj.num, PART_RT_LOWER); if (obj.parts == 0 || (obj.parts & PART_RT_UPPER)) HighlightLine(obj.num, PART_RT_UPPER); if (obj.parts & PART_RT_RAIL) HighlightLine(obj.num, PART_RT_RAIL); /* left side */ if (obj.parts == 0 || (obj.parts & PART_LF_LOWER)) HighlightLine(obj.num, PART_LF_LOWER); if (obj.parts == 0 || (obj.parts & PART_LF_UPPER)) HighlightLine(obj.num, PART_LF_UPPER); if (obj.parts & PART_LF_RAIL) HighlightLine(obj.num, PART_LF_RAIL); } } void Highlight() { glDisable(GL_TEXTURE_2D); glDisable(GL_DEPTH_TEST); glDisable(GL_ALPHA_TEST); glLineWidth(2); /* do the selection */ bool saw_hl = false; for (sel_iter_c it(*inst.edit.Selected) ; !it.done() ; it.next()) { if (inst.edit.highlight.valid() && *it == inst.edit.highlight.num) { saw_hl = true; // can skip drawing twice for things, but not other stuff if (inst.edit.mode == ObjType::things) continue; } byte parts = inst.edit.Selected->get_ext(*it); if (parts > 1) { gl_color(SEL3D_COL); } else { gl_color(SEL_COL); parts = 0; } Objid obj(inst.edit.mode, *it, parts & ~1); HighlightObject(obj); } /* do the highlight */ gl_color(saw_hl ? HI_AND_SEL_COL : HI_COL); if (inst.edit.action == EditorAction::drag && inst.edit.dragged.valid()) HighlightObject(inst.edit.dragged); else HighlightObject(inst.edit.highlight); glLineWidth(1); } void MarkCameraSector() { Objid obj = hover::getNearestSector(inst.level, { inst.r_view.x, inst.r_view.y }); if (obj.valid()) seen_sectors.set(obj.num); } void Render() { // always draw the sector the camera is in MarkCameraSector(); for (int i=0 ; i < inst.level.numLinedefs(); i++) DrawLine(i); glDisable(GL_ALPHA_TEST); for (int s=0 ; s < inst.level.numSectors(); s++) if (seen_sectors.get(s)) DrawSector(s); glEnable(GL_ALPHA_TEST); if (inst.r_view.sprites) for (int t=0 ; t < inst.level.numThings() ; t++) DrawThing(t); } void Begin(int ow, int oh) { glClearColor(0.2f, 0.2f, 0.2f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); glEnable(GL_ALPHA_TEST); glDisable(GL_CULL_FACE); glAlphaFunc(GL_GREATER, 0.5); // setup projection // Note: this crud is a workaround for retina displays on MacOS Fl::use_high_res_GL(true); int pix = iround(inst.main_win->canvas->pixels_per_unit()); Fl::use_high_res_GL(false); glViewport(0, 0, ow * pix, oh * pix); GLdouble angle = inst.r_view.angle * 180.0 / M_PI; // the model-view matrix does three things: // 1. translates X/Y/Z by view position // 2. rotates around Y axis by view angle // 3. flips coordinates so camera looks down -Z // // due to how matrix multiplication works, these things // must be specified in the reverse order as above. glMatrixMode(GL_MODELVIEW); glLoadMatrixd(flip_matrix); glRotated(-angle, 0, 0, +1); glTranslated(-inst.r_view.x, -inst.r_view.y, -inst.r_view.z); // the projection matrix creates the 3D perspective glMatrixMode(GL_PROJECTION); float x_slope = 100.0f / config::render_pixel_aspect; float y_slope = (float)oh / (float)ow; // this matches behavior of S/W renderer. // [ currently it is important since we use the S/W path // for querying what the mouse is pointing at ] float z_near = x_slope; float z_far = config::render_far_clip - 8.0f; glLoadIdentity(); glFrustum(-x_slope, +x_slope, -y_slope, +y_slope, z_near, z_far); } void Finish() { // reset state glDisable(GL_TEXTURE_2D); glDisable(GL_DEPTH_TEST); glDisable(GL_ALPHA_TEST); // reset matrices glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } }; void RGL_RenderWorld(Instance &inst, int ox, int oy, int ow, int oh) { RendInfo3D rend(inst); rend.Begin(ow, oh); rend.Render(); rend.Highlight(); rend.Finish(); } #endif /* NO_OPENGL */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/r_render.cc000066400000000000000000001277731464327712600204600ustar00rootroot00000000000000//------------------------------------------------------------------------ // 3D RENDERING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include #include #ifndef NO_OPENGL #include "FL/gl.h" #endif #include "e_basis.h" #include "e_cutpaste.h" #include "e_hover.h" #include "e_linedef.h" #include "e_sector.h" #include "e_main.h" #include "LineDef.h" #include "m_config.h" #include "m_game.h" #include "m_events.h" #include "m_vector.h" #include "r_render.h" #include "r_subdiv.h" #include "Sector.h" #include "SideDef.h" #include "Thing.h" #include "ui_window.h" #include "Vertex.h" // config items rgb_color_t config::transparent_col = rgbMake(0, 255, 255); bool config::render_high_detail = false; bool config::render_lock_gravity = false; bool config::render_missing_bright = true; bool config::render_unknown_bright = true; int config::render_far_clip = 32768; // in original DOOM pixels were 20% taller than wide, giving 0.83 // as the pixel aspect ratio. int config::render_pixel_aspect = 83; // 100 * width / height bool global::use_npot_textures; namespace thing_sec_cache { int invalid_low, invalid_high; void ResetRange() { invalid_low = 999999999; invalid_high = -1; } void InvalidateThing(int th) { invalid_low = std::min(invalid_low, th); invalid_high = std::max(invalid_high, th); } void InvalidateAll(const Document &doc, bool upcomingDelete) { invalid_low = 0; invalid_high = doc.numThings() - (upcomingDelete ? 2 : 1); } void Update(Instance &inst); }; void Render_View_t::SetAngle(float new_ang) { angle = new_ang; if (angle >= 2*M_PI) angle -= 2*M_PI; else if (angle < 0) angle += 2*M_PI; Sin = sin(angle); Cos = cos(angle); } void Render_View_t::FindGroundZ() { // test a grid of points on the player's bounding box, and // use the maximum floor of all contacted sectors. double max_floor = -9e9; bool hit_something = false; for (int dx = -2 ; dx <= 2 ; dx++) for (int dy = -2 ; dy <= 2 ; dy++) { double test_x = x + dx * 8; double test_y = y + dy * 8; Objid o = hover::getNearestSector(inst.level, { test_x, test_y }); if (o.num >= 0) { double z = inst.level.sectors[o.num]->floorh; { sector_3dfloors_c *ex = inst.Subdiv_3DFloorsForSector(o.num); if (ex->f_plane.sloped) z = ex->f_plane.SlopeZ(test_x, test_y); } max_floor = std::max(max_floor, z); hit_something = true; } } if (hit_something) z = max_floor + inst.conf.miscInfo.view_height; } void Render_View_t::CalcAspect() { aspect_sw = static_cast(screen_w); // things break if these are different aspect_sh = screen_w / (config::render_pixel_aspect / 100.0f); } double Render_View_t::DistToViewPlane(v2double_t map) { map.x -= x; map.y -= y; return map.x * Cos + map.y * Sin; } void Render_View_t::UpdateScreen(int ow, int oh) { // in low detail mode, setup size so that expansion always covers // our window (i.e. we draw a bit more than we need). int new_sw = config::render_high_detail ? ow : (ow + 1) / 2; int new_sh = config::render_high_detail ? oh : (oh + 1) / 2; if (!screen || screen_w != new_sw || screen_h != new_sh) { screen_w = new_sw; screen_h = new_sh; if (screen) { delete[] screen; screen = NULL; } } // we don't need a screen buffer when using OpenGL #ifdef NO_OPENGL if (!screen) screen = new img_pixel_t [screen_w * screen_h]; #endif CalcAspect(); } void Render_View_t::PrepareToRender(int ow, int oh) { thing_sec_cache::Update(inst); UpdateScreen(ow, oh); if (gravity) FindGroundZ(); } static const Thing *FindPlayer(const Document &doc, int typenum) { // need to search backwards (to handle Voodoo dolls properly) for ( int i = doc.numThings()-1 ; i >= 0 ; i--) if (doc.things[i]->type == typenum) return doc.things[i].get(); return nullptr; // not found } //------------------------------------------------------------------------ namespace thing_sec_cache { void Update(Instance &inst) { // guarantee that thing_sectors has the correct size. // [ prevent a potential crash ] if (inst.level.numThings() != (int)inst.r_view.thing_sectors.size()) { inst.r_view.thing_sectors.resize(inst.level.numThings()); thing_sec_cache::InvalidateAll(inst.level, false); } // nothing changed? if (invalid_low > invalid_high) return; for (int i = invalid_low ; i <= invalid_high ; i++) { Objid obj = hover::getNearestSector(inst.level, inst.level.things[i]->xy()); inst.r_view.thing_sectors[i] = obj.num; } thing_sec_cache::ResetRange(); } } void Render3D_NotifyBegin() { thing_sec_cache::ResetRange(); } void Render3D_NotifyInsert(ObjType type, int objnum) { if (type == ObjType::things) thing_sec_cache::InvalidateThing(objnum); } void Render3D_NotifyDelete(const Document &doc, ObjType type, int objnum) { if (type == ObjType::things || type == ObjType::sectors) thing_sec_cache::InvalidateAll(doc, true); } void Render3D_NotifyChange(ObjType type, int objnum, int field) { if (type == ObjType::things && (field == Thing::F_X || field == Thing::F_Y)) { thing_sec_cache::InvalidateThing(objnum); } } void Render3D_NotifyEnd(Instance &inst) { thing_sec_cache::Update(inst); } int Render3D_CalcRotation(double viewAngle_rad, int thingAngle_deg) { // thingAngle(deg) - viewAngle(deg) // 1: front. 45 degrees around 180 difference. 157d30': 202d30' // 2: front-left 112d30': 157d30' // 3: left 67d30': 112d30' // 4: back-left 22d30': 67d30' // 5: back -22d30': 22d30' // 6: back-right -67d30': -22d30' // 7: right -112d30': -67d30' // 8: front-right. -157d30':-112d30' double thingAngle_rad = M_PI / 180.0 * thingAngle_deg; double angleDelta_rad = thingAngle_rad - viewAngle_rad; while(angleDelta_rad > 202.5 * M_PI / 180.0) angleDelta_rad -= 2 * M_PI; while(angleDelta_rad < -157.5 * M_PI / 180.0) angleDelta_rad += 2 * M_PI; return clamp((int)floor((202.5 * M_PI / 180.0 - angleDelta_rad) / (M_PI / 4.0) + 1.0), 1, 8); } //------------------------------------------------------------------------ class save_obj_field_c { public: int obj; // object number (SaveBucket::type is the type) int field; // e.g. Thing::F_X int value; // the saved value public: save_obj_field_c(int _obj, int _field, int _value) : obj(_obj), field(_field), value(_value) { } ~save_obj_field_c() { } }; class SaveBucket_c { private: ObjType type; std::vector< save_obj_field_c > fields; Instance &inst; public: SaveBucket_c(ObjType type, Instance &inst) : type(type), inst(inst) { } ~SaveBucket_c() { } void Clear() { fields.clear(); } void Save(int obj, int field) { // is it already saved? for (size_t i = 0 ; i < fields.size() ; i++) if (fields[i].obj == obj && fields[i].field == field) return; int value = RawGet(obj, field); fields.push_back(save_obj_field_c(obj, field, value)); } void RestoreAll() { for (size_t i = 0 ; i < fields.size() ; i++) { RawSet(fields[i].obj, fields[i].field, fields[i].value); } } void ApplyTemp(int field, int delta) { for (size_t i = 0 ; i < fields.size() ; i++) { if (fields[i].field == field) RawSet(fields[i].obj, field, fields[i].value + delta); } } void ApplyToBasis(EditOperation &op, int field, int delta) { for (size_t i = 0 ; i < fields.size() ; i++) { if (fields[i].field == field) { op.change(type, fields[i].obj, (byte)field, fields[i].value + delta); } } } private: int * RawObjPointer(int objnum) { switch (type) { case ObjType::things: return reinterpret_cast(inst.level.things[objnum].get()); case ObjType::vertices: return reinterpret_cast(inst.level.vertices[objnum].get()); case ObjType::sectors: return reinterpret_cast(inst.level.sectors[objnum].get()); case ObjType::sidedefs: return reinterpret_cast(inst.level.sidedefs[objnum].get()); case ObjType::linedefs: return reinterpret_cast(inst.level.linedefs[objnum].get()); default: BugError("SaveBucket with bad mode\n"); return NULL; /* NOT REACHED */ } } int RawGet(int objnum, int field) { int *ptr = RawObjPointer(objnum) + field; return *ptr; } void RawSet(int objnum, int field, int value) { int *ptr = RawObjPointer(objnum) + field; *ptr = value; } }; static void AdjustOfs_UpdateBBox(Instance &inst, int ld_num) { const auto L = inst.level.linedefs[ld_num]; float lx1 = static_cast(inst.level.getStart(*L).x()); float ly1 = static_cast(inst.level.getStart(*L).y()); float lx2 = static_cast(inst.level.getEnd(*L).x()); float ly2 = static_cast(inst.level.getEnd(*L).y()); if (lx1 > lx2) std::swap(lx1, lx2); if (ly1 > ly2) std::swap(ly1, ly2); inst.edit.adjust_bbox.x1 = std::min(inst.edit.adjust_bbox.x1, lx1); inst.edit.adjust_bbox.y1 = std::min(inst.edit.adjust_bbox.y1, ly1); inst.edit.adjust_bbox.x2 = std::max(inst.edit.adjust_bbox.x2, lx2); inst.edit.adjust_bbox.y2 = std::max(inst.edit.adjust_bbox.y2, ly2); } static void AdjustOfs_CalcDistFactor(const Instance &inst, float& dx_factor, float& dy_factor) { // this computes how far to move the offsets for each screen pixel // the mouse moves. we want it to appear as though each texture // is being dragged by the mouse, e.g. if you click on the middle // of a switch, that switch follows the mouse pointer around. // such an effect can only be approximate though. float dx = static_cast((inst.r_view.x < inst.edit.adjust_bbox.x1) ? (inst.edit.adjust_bbox.x1 - inst.r_view.x) : (inst.r_view.x > inst.edit.adjust_bbox.x2) ? (inst.r_view.x - inst.edit.adjust_bbox.x2) : 0); float dy = static_cast((inst.r_view.y < inst.edit.adjust_bbox.y1) ? (inst.edit.adjust_bbox.y1 - inst.r_view.y) : (inst.r_view.y > inst.edit.adjust_bbox.y2) ? (inst.r_view.y - inst.edit.adjust_bbox.y2) : 0); float dist = hypot(dx, dy); dist = clamp(20.f, dist, 1000.f); dx_factor = dist / inst.r_view.aspect_sw; dy_factor = dist / inst.r_view.aspect_sh; } static void AdjustOfs_Add(Instance &inst, int ld_num, int part) { if (! inst.edit.adjust_bucket) return; const auto L = inst.level.linedefs[ld_num]; // ignore invalid sides (sanity check) int sd_num = (part & PART_LF_ALL) ? L->left : L->right; if (sd_num < 0) return; // TODO : UDMF ports can allow full control over each part inst.edit.adjust_bucket->Save(sd_num, SideDef::F_X_OFFSET); inst.edit.adjust_bucket->Save(sd_num, SideDef::F_Y_OFFSET); } static void AdjustOfs_Begin(Instance &inst) { if (inst.edit.adjust_bucket) delete inst.edit.adjust_bucket; inst.edit.adjust_bucket = new SaveBucket_c(ObjType::sidedefs, inst); inst.edit.adjust_lax = inst.Exec_HasFlag("/LAX"); int total_lines = 0; // we will compute the bbox of selected lines inst.edit.adjust_bbox.x1 = inst.edit.adjust_bbox.y1 = static_cast(+9e9); inst.edit.adjust_bbox.x2 = inst.edit.adjust_bbox.y2 = static_cast(-9e9); // find the sidedefs to adjust if (! inst.edit.Selected->empty()) { for (sel_iter_c it(*inst.edit.Selected) ; !it.done() ; it.next()) { int ld_num = *it; byte parts = inst.edit.Selected->get_ext(ld_num); // handle "simply selected" linedefs if (parts <= 1) { parts |= PART_RT_LOWER | PART_RT_UPPER; parts |= PART_LF_LOWER | PART_LF_UPPER; } total_lines++; AdjustOfs_UpdateBBox(inst, ld_num); if (parts & PART_RT_LOWER) AdjustOfs_Add(inst, ld_num, PART_RT_LOWER); if (parts & PART_RT_UPPER) AdjustOfs_Add(inst, ld_num, PART_RT_UPPER); if (parts & PART_RT_RAIL) AdjustOfs_Add(inst, ld_num, PART_RT_RAIL); if (parts & PART_LF_LOWER) AdjustOfs_Add(inst, ld_num, PART_LF_LOWER); if (parts & PART_LF_UPPER) AdjustOfs_Add(inst, ld_num, PART_LF_UPPER); if (parts & PART_LF_RAIL) AdjustOfs_Add(inst, ld_num, PART_LF_RAIL); } } else if (inst.edit.highlight.valid()) { int ld_num = inst.edit.highlight.num; byte parts = static_cast(inst.edit.highlight.parts); if (parts >= 2) { AdjustOfs_Add(inst, ld_num, parts); AdjustOfs_UpdateBBox(inst, ld_num); total_lines++; } } if (total_lines == 0) { inst.Beep("nothing to adjust"); return; } inst.edit.adjust_dx = 0; inst.edit.adjust_dy = 0; inst.edit.adjust_lax = inst.Exec_HasFlag("/LAX"); inst.Editor_SetAction(EditorAction::adjustOfs); } static void AdjustOfs_Finish(Instance &inst) { if (! inst.edit.adjust_bucket) { inst.Editor_ClearAction(); return; } int dx = iround(inst.edit.adjust_dx); int dy = iround(inst.edit.adjust_dy); if (dx || dy) { EditOperation op(inst.level.basis); op.setMessage("adjusted offsets"); inst.edit.adjust_bucket->ApplyToBasis(op, SideDef::F_X_OFFSET, dx); inst.edit.adjust_bucket->ApplyToBasis(op, SideDef::F_Y_OFFSET, dy); } delete inst.edit.adjust_bucket; inst.edit.adjust_bucket = NULL; inst.Editor_ClearAction(); } static void AdjustOfs_Delta(Instance &inst, int dx, int dy) { if (! inst.edit.adjust_bucket) return; if (dx == 0 && dy == 0) return; bool force_one_dir = true; if (force_one_dir) { if (abs(dx) >= abs(dy)) dy = 0; else dx = 0; } keycode_t mod = inst.edit.adjust_lax ? M_ReadLaxModifiers() : 0; float factor = (mod & EMOD_SHIFT) ? 0.5f : 2.0f; if (!config::render_high_detail) factor = factor * 0.5f; float dx_factor, dy_factor; AdjustOfs_CalcDistFactor(inst, dx_factor, dy_factor); inst.edit.adjust_dx -= dx * factor * dx_factor; inst.edit.adjust_dy -= dy * factor * dy_factor; inst.RedrawMap(); } static void AdjustOfs_RenderAnte(const Instance &inst) { if (inst.edit.action == EditorAction::adjustOfs && inst.edit.adjust_bucket) { int dx = iround(inst.edit.adjust_dx); int dy = iround(inst.edit.adjust_dy); // change it temporarily (just for the render) inst.edit.adjust_bucket->ApplyTemp(SideDef::F_X_OFFSET, dx); inst.edit.adjust_bucket->ApplyTemp(SideDef::F_Y_OFFSET, dy); } } static void AdjustOfs_RenderPost(const Instance &inst) { if (inst.edit.action == EditorAction::adjustOfs && inst.edit.adjust_bucket) { inst.edit.adjust_bucket->RestoreAll(); } } //------------------------------------------------------------------------ void Render3D_Draw(Instance &inst, int ox, int oy, int ow, int oh) { inst.r_view.PrepareToRender(ow, oh); AdjustOfs_RenderAnte(inst); #ifdef NO_OPENGL inst.SW_RenderWorld(ox, oy, ow, oh); #else RGL_RenderWorld(inst, ox, oy, ow, oh); #endif AdjustOfs_RenderPost(inst); } static bool Render3D_Query(Instance &inst, Objid& hl, int sx, int sy) { int ow = inst.main_win->canvas->w(); int oh = inst.main_win->canvas->h(); #ifdef NO_OPENGL // in OpenGL mode, UI_Canvas is a window and that means the // event X/Y values are relative to *it* and not the main window. // hence the following is only needed in software mode. int ox = inst.main_win->canvas->x(); int oy = inst.main_win->canvas->y(); sx -= ox; sy -= oy; #endif // force high detail mode for OpenGL, so we don't lose // precision when performing the query. #ifndef NO_OPENGL config::render_high_detail = true; #endif hl.clear(); if (! inst.edit.pointer_in_window) return false; inst.r_view.PrepareToRender(ow, oh); return inst.SW_QueryPoint(hl, sx, sy); } void Instance::Render3D_Setup() { thing_sec_cache::InvalidateAll(level, false); r_view.thing_sectors.resize(0); if (! r_view.p_type) { r_view.p_type = THING_PLAYER1; r_view.px = 99999; } const Thing *player = FindPlayer(level, r_view.p_type); if (! player) { if (r_view.p_type != THING_DEATHMATCH) r_view.p_type = THING_DEATHMATCH; player = FindPlayer(level, r_view.p_type); } if (player && !(r_view.px == player->x() && r_view.py == player->y())) { // if player moved, re-create view parameters r_view.x = r_view.px = player->x(); r_view.y = r_view.py = player->y(); r_view.FindGroundZ(); r_view.SetAngle(static_cast(player->angle * M_PI / 180.0)); } else { r_view.x = 0; r_view.y = 0; r_view.z = 64; r_view.SetAngle(0); } r_view.screen_w = -1; r_view.screen_h = -1; r_view.texturing = true; r_view.sprites = true; r_view.lighting = true; } void Render3D_Enable(Instance &inst, bool _enable) { inst.Editor_ClearAction(); inst.edit.render3d = _enable; inst.edit.highlight.clear(); inst.edit.clicked.clear(); inst.edit.dragged.clear(); // give keyboard focus to the appropriate large widget Fl::focus(inst.main_win->canvas); inst.main_win->scroll->UpdateRenderMode(); inst.main_win->info_bar->UpdateSecRend(); if (inst.edit.render3d) { inst.main_win->info_bar->SetMouse(); // TODO: ideally query this, like code in PointerPos inst.r_view.mouse_x = inst.r_view.mouse_y = -1; } else { inst.main_win->canvas->PointerPos(); inst.main_win->info_bar->SetMouse(); } inst.RedrawMap(); } void Render3D_ScrollMap(Instance &inst, v2int_t dpos, keycode_t mod) { // we separate the movement into either turning or moving up/down // (never both at the same time : CONFIG IT THOUGH). bool force_one_dir = true; if (force_one_dir) { if (abs(dpos.x) >= abs(dpos.y)) dpos.y = 0; else dpos.x = 0; } bool is_strafe = (mod & EMOD_ALT) ? true : false; float mod_factor = 1.0; if (mod & EMOD_SHIFT) mod_factor = 0.4f; if (mod & EMOD_COMMAND) mod_factor = 2.5f; float speed = inst.edit.panning_speed * mod_factor; if (is_strafe) { inst.r_view.x += inst.r_view.Sin * dpos.x * mod_factor; inst.r_view.y -= inst.r_view.Cos * dpos.x * mod_factor; } else // turn camera { double d_ang = dpos.x * speed * M_PI / 480.0; inst.r_view.SetAngle(static_cast(inst.r_view.angle - d_ang)); } dpos.y = -dpos.y; //TODO CONFIG ITEM if (is_strafe) { inst.r_view.x += inst.r_view.Cos * dpos.y * mod_factor; inst.r_view.y += inst.r_view.Sin * dpos.y * mod_factor; } else if (! (config::render_lock_gravity && inst.r_view.gravity)) { inst.r_view.z += dpos.y * speed * 0.75; inst.r_view.gravity = false; } inst.main_win->info_bar->SetMouse(); inst.RedrawMap(); } static void DragSectors_Update(Instance &inst) { float ow = static_cast(inst.main_win->canvas->w()); float x_slope = 100.0f / config::render_pixel_aspect; float factor = static_cast(clamp(20.f, inst.edit.drag_point_dist, 1000.f) / (ow * x_slope * 0.5)); float map_dz = -inst.edit.drag_screen_dpos.y * factor; float step = 8.0; // TODO config item if (map_dz > step*0.25) inst.edit.drag_sector_dz = step * (int)ceil(map_dz / step); else if (map_dz < step*-0.25) inst.edit.drag_sector_dz = step * (int)floor(map_dz / step); else inst.edit.drag_sector_dz = 0; } void Render3D_DragSectors(Instance &inst) { int dz = iround(inst.edit.drag_sector_dz); if (dz == 0) return; EditOperation op(inst.level.basis); if (dz > 0) op.setMessage("raised sectors"); else op.setMessage("lowered sectors"); if (inst.edit.dragged.valid()) { int parts = inst.edit.dragged.parts; inst.level.secmod.safeRaiseLower(op, inst.edit.dragged.num, parts, dz); } else { for (sel_iter_c it(*inst.edit.Selected) ; !it.done() ; it.next()) { int parts = inst.edit.Selected->get_ext(*it); parts &= ~1; inst.level.secmod.safeRaiseLower(op, *it, parts, dz); } } } static void DragThings_Update(Instance &inst) { float ow = static_cast(inst.main_win->canvas->w()); // float oh = main_win->canvas->h(); float x_slope = 100.0f / config::render_pixel_aspect; // float y_slope = (float)oh / (float)ow; float dist = clamp(20.f, inst.edit.drag_point_dist, 1000.f); float x_factor = dist / (ow * 0.5f); float y_factor = dist / (ow * x_slope * 0.5f); if (inst.edit.drag_thing_up_down) { // vertical positioning in Hexen and UDMF formats float map_dz = -inst.edit.drag_screen_dpos.y * y_factor; // final result is in drag_cur_x/y/z inst.edit.drag_cur.x = inst.edit.drag_start.x; inst.edit.drag_cur.y = inst.edit.drag_start.y; inst.edit.drag_cur.z = inst.edit.drag_start.z + map_dz; return; } /* move thing around XY plane */ inst.edit.drag_cur.z = inst.edit.drag_start.z; // vectors for view camera double fwd_vx = inst.r_view.Cos; double fwd_vy = inst.r_view.Sin; double side_vx = fwd_vy; double side_vy = -fwd_vx; double dx = inst.edit.drag_screen_dpos.x * static_cast(x_factor); double dy = -inst.edit.drag_screen_dpos.y * y_factor * 2.0; // this usually won't happen, but is a reasonable fallback... if (inst.edit.drag_thing_num < 0) { inst.edit.drag_cur.x = inst.edit.drag_start.x + dx * side_vx + dy * fwd_vx; inst.edit.drag_cur.y = inst.edit.drag_start.y + dx * side_vy + dy * fwd_vy; return; } // old code for depth calculation, works well in certain cases // but very poorly in other cases. #if 0 int sy1 = inst.edit.click_screen_y; int sy2 = sy1 + inst.edit.drag_screen_dy; if (sy1 >= oh/2 && sy2 >= oh/2) { double d1 = (inst.edit.drag_thing_floorh - r_view.z) / (oh - sy1*2.0); double d2 = (inst.edit.drag_thing_floorh - r_view.z) / (oh - sy2*2.0); d1 = d1 * ow; d2 = d2 * ow; dy = (d2 - d1) * 0.5; } #endif const auto T = inst.level.things[inst.edit.drag_thing_num]; float old_x = static_cast(T->x()); float old_y = static_cast(T->y()); float new_x = static_cast(old_x + dx * side_vx); float new_y = static_cast(old_y + dx * side_vy); // recompute forward/back vector fwd_vx = new_x - inst.r_view.x; fwd_vy = new_y - inst.r_view.y; double fwd_len = hypot(fwd_vx, fwd_vy); if (fwd_len < 1) fwd_len = 1; new_x = static_cast(new_x + dy * fwd_vx / fwd_len); new_y = static_cast(new_y + dy * fwd_vy / fwd_len); // handle a change in floor height Objid old_sec = hover::getNearestSector(inst.level, { old_x, old_y }); Objid new_sec = hover::getNearestSector(inst.level, { new_x, new_y }); if (old_sec.valid() && new_sec.valid()) { float old_z = static_cast(inst.level.sectors[old_sec.num]->floorh); float new_z = static_cast(inst.level.sectors[new_sec.num]->floorh); // intent here is to show proper position, NOT raise/lower things. // [ perhaps add a new variable? ] inst.edit.drag_cur.z += (new_z - old_z); } inst.edit.drag_cur.x = inst.edit.drag_start.x + new_x - old_x; inst.edit.drag_cur.y = inst.edit.drag_start.y + new_y - old_y; } void Render3D_DragThings(Instance &inst) { v3double_t delta; delta.x = inst.edit.drag_cur.x - inst.edit.drag_start.x; delta.y = inst.edit.drag_cur.y - inst.edit.drag_start.y; delta.z = inst.edit.drag_cur.z - inst.edit.drag_start.z; // for movement in XY plane, ensure we don't raise/lower things if (! inst.edit.drag_thing_up_down) delta.z = 0.0; if (inst.edit.dragged.valid()) { selection_c sel(ObjType::things); sel.set(inst.edit.dragged.num); inst.level.objects.move(sel, delta); } else { inst.level.objects.move(*inst.edit.Selected, delta); } inst.RedrawMap(); } void Instance::Render3D_MouseMotion(v2int_t pos, keycode_t mod, v2int_t dpos) { edit.pointer_in_window = true; // save position for Render3D_UpdateHighlight r_view.mouse_x = pos.x; r_view.mouse_y = pos.y; if (edit.is_panning) { Editor_ScrollMap(0, dpos, mod); return; } else if (edit.action == EditorAction::adjustOfs) { AdjustOfs_Delta(*this, dpos.x, dpos.y); return; } if (edit.action == EditorAction::click) { CheckBeginDrag(); } else if (edit.action == EditorAction::drag) { // get the latest map_x/y/z coordinates Objid unused_hl; Render3D_Query(*this, unused_hl, pos.x, pos.y); edit.drag_screen_dpos = pos - edit.click_screen_pos; edit.drag_cur.x = edit.map.x; edit.drag_cur.y = edit.map.y; if (edit.mode == ObjType::sectors) DragSectors_Update(*this); if (edit.mode == ObjType::things) DragThings_Update(*this); main_win->canvas->redraw(); main_win->status_bar->redraw(); return; } UpdateHighlight(); } void Instance::Render3D_UpdateHighlight() { edit.highlight.clear(); edit.split_line.clear(); if (edit.pointer_in_window && r_view.mouse_x >= 0 && edit.action != EditorAction::drag) { Objid current_hl; // this also updates inst.edit.map_x/y/z Render3D_Query(*this, current_hl, r_view.mouse_x, r_view.mouse_y); if (current_hl.type == edit.mode) edit.highlight = current_hl; } main_win->canvas->UpdateHighlight(); main_win->canvas->redraw(); main_win->status_bar->redraw(); } void Instance::Render3D_Navigate() { float delay_ms = static_cast(Nav_TimeDiff()); delay_ms = delay_ms / 1000.0f; keycode_t mod = 0; if (edit.nav.lax) mod = M_ReadLaxModifiers(); float mod_factor = 1.0; if (mod & EMOD_SHIFT) mod_factor = 0.5; if (mod & EMOD_COMMAND) mod_factor = 2.0; if (edit.nav.fwd || edit.nav.back || edit.nav.right || edit.nav.left) { float fwd = edit.nav.fwd - edit.nav.back; float right = edit.nav.right - edit.nav.left; float dx = static_cast(r_view.Cos * fwd + r_view.Sin * right); float dy = static_cast(r_view.Sin * fwd - r_view.Cos * right); dx = dx * mod_factor * mod_factor; dy = dy * mod_factor * mod_factor; r_view.x += static_cast(dx) * delay_ms; r_view.y += static_cast(dy) * delay_ms; } if (edit.nav.up || edit.nav.down) { float dz = (edit.nav.up - edit.nav.down); r_view.z += static_cast(dz) * mod_factor * delay_ms; } if (edit.nav.turn_L || edit.nav.turn_R) { float dang = (edit.nav.turn_L - edit.nav.turn_R); dang = dang * mod_factor * delay_ms; dang = clamp(-90.f, dang, 90.f); r_view.SetAngle(static_cast(r_view.angle + dang)); } main_win->info_bar->SetMouse(); RedrawMap(); } // returns -1 if nothing in selection or highlight, -2 if multiple // things are selected and they have different types. int Instance::GrabSelectedThing() { int result = -1; if (edit.Selected->empty()) { if (edit.highlight.is_nil()) { Beep("no things for copy/cut type"); return -1; } result = level.things[edit.highlight.num]->type; } else { for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { const auto T = level.things[*it]; if (result >= 0 && T->type != result) { Beep("multiple thing types"); return -2; } result = T->type; } } Status_Set("copied type %d", result); return result; } void Instance::StoreSelectedThing(int new_type) { // this code is similar to code in UI_Thing::type_callback(), // but here we must handle a highlighted object. SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { Beep("no things for paste type"); return; } { EditOperation op(level.basis); op.setMessageForSelection("pasted type of", *edit.Selected); for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { op.changeThing(*it, Thing::F_TYPE, new_type); } } if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); Status_Set("pasted type %d", new_type); } static StringID SEC_GrabFlat(const Sector *S, int part) { if (part & PART_CEIL) return S->ceil_tex; if (part & PART_FLOOR) return S->floor_tex; return S->floor_tex; } // returns -1 if nothing in selection or highlight, -2 if multiple // sectors are selected and they have different flats. StringID Instance::GrabSelectedFlat() { StringID result(-1); if (edit.Selected->empty()) { if (edit.highlight.is_nil()) { Beep("no sectors for copy/cut flat"); return StringID(-1); } const auto S = level.sectors[edit.highlight.num]; result = SEC_GrabFlat(S.get(), edit.highlight.parts); } else { for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { const auto S = level.sectors[*it]; byte parts = edit.Selected->get_ext(*it); StringID tex = SEC_GrabFlat(S.get(), parts & ~1); if (result.isValid() && tex != result) { Beep("multiple flats present"); return StringID(-2); } result = tex; } } if (result.isValid()) Status_Set("copied %s", BA_GetString(result).c_str()); return result; } void Instance::StoreSelectedFlat(StringID new_tex) { SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { Beep("no sectors for paste flat"); return; } { EditOperation op(level.basis); op.setMessageForSelection("pasted flat to", *edit.Selected); for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { byte parts = edit.Selected->get_ext(*it); if (parts == 1 || (parts & PART_FLOOR)) op.changeSector(*it, Sector::F_FLOOR_TEX, new_tex); if (parts == 1 || (parts & PART_CEIL)) op.changeSector(*it, Sector::F_CEIL_TEX, new_tex); } } if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); Status_Set("pasted %s", BA_GetString(new_tex).c_str()); } void Instance::StoreDefaultedFlats() { SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { Beep("no sectors for default"); return; } StringID floor_tex = BA_InternaliseString(conf.default_floor_tex); StringID ceil_tex = BA_InternaliseString(conf.default_ceil_tex); { EditOperation op(level.basis); op.setMessageForSelection("defaulted flat in", *edit.Selected); for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { byte parts = edit.Selected->get_ext(*it); if (parts == 1 || (parts & PART_FLOOR)) op.changeSector(*it, Sector::F_FLOOR_TEX, floor_tex); if (parts == 1 || (parts & PART_CEIL)) op.changeSector(*it, Sector::F_CEIL_TEX, ceil_tex); } } if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); Status_Set("defaulted flats"); } StringID Instance::LD_GrabTex(const LineDef *L, int part) const { if (L->NoSided()) return BA_InternaliseString(conf.default_wall_tex); if (L->OneSided()) return level.getRight(*L)->mid_tex; if (part & PART_RT_LOWER) return level.getRight(*L)->lower_tex; if (part & PART_RT_UPPER) return level.getRight(*L)->upper_tex; if (part & PART_LF_LOWER) return level.getLeft(*L)->lower_tex; if (part & PART_LF_UPPER) return level.getLeft(*L)->upper_tex; if (part & PART_RT_RAIL) return level.getRight(*L)->mid_tex; if (part & PART_LF_RAIL) return level.getLeft(*L) ->mid_tex; // pick something reasonable for a simply selected line if (level.getSector(*level.getLeft(*L)).floorh > level.getSector(*level.getRight(*L)).floorh) return level.getRight(*L)->lower_tex; if (level.getSector(*level.getLeft(*L)).ceilh < level.getSector(*level.getRight(*L)).ceilh) return level.getRight(*L)->upper_tex; if (level.getSector(*level.getLeft(*L)).floorh < level.getSector(*level.getRight(*L)).floorh) return level.getLeft(*L)->lower_tex; if (level.getSector(*level.getLeft(*L)).ceilh > level.getSector(*level.getRight(*L)).ceilh) return level.getLeft(*L)->upper_tex; // emergency fallback return level.getRight(*L)->lower_tex; } // returns -1 if nothing in selection or highlight, -2 if multiple // linedefs are selected and they have different textures. StringID Instance::GrabSelectedTexture() { StringID result = StringID(-1); if (edit.Selected->empty()) { if (edit.highlight.is_nil()) { Beep("no linedefs for copy/cut tex"); return StringID(-1); } const auto L = level.linedefs[edit.highlight.num]; result = LD_GrabTex(L.get(), edit.highlight.parts); } else { for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { const auto L = level.linedefs[*it]; byte parts = edit.Selected->get_ext(*it); StringID tex = LD_GrabTex(L.get(), parts & ~1); if (result.isValid() && tex != result) { Beep("multiple textures present"); return StringID(-2); } result = tex; } } if (result.isValid()) Status_Set("copied %s", BA_GetString(result).c_str()); return result; } void Instance::StoreSelectedTexture(StringID new_tex) { SelectHighlight unselect = edit.SelectionOrHighlight(); if (unselect == SelectHighlight::empty) { Beep("no linedefs for paste tex"); return; } { EditOperation op(level.basis); op.setMessageForSelection("pasted tex to", *edit.Selected); for (sel_iter_c it(*edit.Selected) ; !it.done() ; it.next()) { const auto L = level.linedefs[*it]; byte parts = edit.Selected->get_ext(*it); if (L->NoSided()) continue; if (L->OneSided()) { op.changeSidedef(L->right, SideDef::F_MID_TEX, new_tex); continue; } /* right side */ if (parts == 1 || (parts & PART_RT_LOWER)) op.changeSidedef(L->right, SideDef::F_LOWER_TEX, new_tex); if (parts == 1 || (parts & PART_RT_UPPER)) op.changeSidedef(L->right, SideDef::F_UPPER_TEX, new_tex); if (parts & PART_RT_RAIL) op.changeSidedef(L->right, SideDef::F_MID_TEX, new_tex); /* left side */ if (parts == 1 || (parts & PART_LF_LOWER)) op.changeSidedef(L->left, SideDef::F_LOWER_TEX, new_tex); if (parts == 1 || (parts & PART_LF_UPPER)) op.changeSidedef(L->left, SideDef::F_UPPER_TEX, new_tex); if (parts & PART_LF_RAIL) op.changeSidedef(L->left, SideDef::F_MID_TEX, new_tex); } } if (unselect == SelectHighlight::unselect) Selection_Clear(true /* nosave */); Status_Set("pasted %s", BA_GetString(new_tex).c_str()); } void Instance::Render3D_CB_Copy() { StringID num; int thingnum; switch (edit.mode) { case ObjType::things: thingnum = GrabSelectedThing(); if (thingnum >= 0) Texboard_SetThing(thingnum); break; case ObjType::sectors: num = GrabSelectedFlat(); if (num.isValid()) Texboard_SetFlat(BA_GetString(num), conf); break; case ObjType::linedefs: num = GrabSelectedTexture(); if (num.isValid()) Texboard_SetTex(BA_GetString(num), conf); break; default: break; } } void Instance::Render3D_CB_Paste() { switch (edit.mode) { case ObjType::things: StoreSelectedThing(Texboard_GetThing(conf)); break; case ObjType::sectors: StoreSelectedFlat(Texboard_GetFlatNum(conf)); break; case ObjType::linedefs: StoreSelectedTexture(Texboard_GetTexNum(conf)); break; default: break; } } void Instance::Render3D_CB_Cut() { // this is repurposed to set the default texture/thing switch (edit.mode) { case ObjType::things: StoreSelectedThing(conf.default_thing); break; case ObjType::sectors: StoreDefaultedFlats(); break; case ObjType::linedefs: StoreSelectedTexture(BA_InternaliseString(conf.default_wall_tex)); break; default: break; } } void Instance::Render3D_SetCameraPos(const v2double_t &newpos) { r_view.x = newpos.x; r_view.y = newpos.y; r_view.FindGroundZ(); } void Instance::Render3D_GetCameraPos(v2double_t &pos, float *angle) const { pos.x = r_view.x; pos.y = r_view.y; // convert angle from radians to degrees *angle = static_cast(r_view.angle * 180.0 / M_PI); } bool Instance::Render3D_ParseUser(const std::vector &tokens) { if (tokens[0] == "camera" && tokens.size() >= 5) { r_view.x = atof(tokens[1]); r_view.y = atof(tokens[2]); r_view.z = atof(tokens[3]); r_view.SetAngle(static_cast(atof(tokens[4]))); return true; } if (tokens[0] == "r_modes" && tokens.size() >= 4) { r_view.texturing = atoi(tokens[1]) ? true : false; r_view.sprites = atoi(tokens[2]) ? true : false; r_view.lighting = atoi(tokens[3]) ? true : false; return true; } if (tokens[0] == "r_gravity" && tokens.size() >= 2) { r_view.gravity = atoi(tokens[1]) ? true : false; return true; } if (tokens[0] == "low_detail" && tokens.size() >= 2) { // ignored for compatibility return true; } if (tokens[0] == "gamma" && tokens.size() >= 2) { config::usegamma = std::max(0, atoi(tokens[1])) % 5; wad.palette.updateGamma(config::usegamma, config::panel_gamma); return true; } return false; } void Instance::Render3D_WriteUser(std::ostream &os) const { os << "camera " << SString::printf("%1.2f %1.2f %1.2f %1.2f", r_view.x, r_view.y, r_view.z, r_view.angle) << '\n'; os << "r_modes " << (r_view.texturing ? 1 : 0) << ' ' << (r_view.sprites ? 1 : 0) << ' ' << (r_view.lighting ? 1 : 0) << '\n'; os << "r_gravity " << (r_view.gravity ? 1 : 0) << '\n'; os << "gamma " << config::usegamma << '\n'; } //------------------------------------------------------------------------ // COMMAND FUNCTIONS //------------------------------------------------------------------------ void Instance::R3D_Forward() { float dist = static_cast(atof(EXEC_Param[0])); r_view.x += r_view.Cos * dist; r_view.y += r_view.Sin * dist; main_win->info_bar->SetMouse(); RedrawMap(); } void Instance::R3D_Backward() { float dist = static_cast(atof(EXEC_Param[0])); r_view.x -= r_view.Cos * dist; r_view.y -= r_view.Sin * dist; main_win->info_bar->SetMouse(); RedrawMap(); } void Instance::R3D_Left() { float dist = static_cast(atof(EXEC_Param[0])); r_view.x -= r_view.Sin * dist; r_view.y += r_view.Cos * dist; main_win->info_bar->SetMouse(); RedrawMap(); } void Instance::R3D_Right() { float dist = static_cast(atof(EXEC_Param[0])); r_view.x += r_view.Sin * dist; r_view.y -= r_view.Cos * dist; main_win->info_bar->SetMouse(); RedrawMap(); } void Instance::R3D_Up() { if (r_view.gravity && config::render_lock_gravity) { Beep("Gravity is on"); return; } r_view.gravity = false; float dist = static_cast(atof(EXEC_Param[0])); r_view.z += dist; RedrawMap(); } void Instance::R3D_Down() { if (r_view.gravity && config::render_lock_gravity) { Beep("Gravity is on"); return; } r_view.gravity = false; float dist = static_cast(atof(EXEC_Param[0])); r_view.z -= dist; RedrawMap(); } void Instance::R3D_Turn() { float angle = static_cast(atof(EXEC_Param[0])); // convert to radians angle = static_cast(angle * M_PI / 180.0); r_view.SetAngle(static_cast(r_view.angle + angle)); RedrawMap(); } void Instance::R3D_DropToFloor() { r_view.FindGroundZ(); RedrawMap(); } void Instance::R3D_NAV_Forward_release() { edit.nav.fwd = 0; } // // For 3D movement control // void Instance::navigation3DMove(float *editNav, nav_release_func_t func, bool fly) { if(!EXEC_CurKey) return; if(fly) { if(r_view.gravity && config::render_lock_gravity) { Beep("Gravity is on"); return; } r_view.gravity = false; } if(!edit.is_navigating) edit.clearNav(); *editNav = static_cast(atof(EXEC_Param[0])); Nav_SetKey(EXEC_CurKey, func); } // // Applies turning adjustment // void Instance::navigation3DTurn(float *editNav, nav_release_func_t func) { navigation3DMove(editNav, func, false); *editNav = static_cast(*editNav * M_PI / 180.0f); // convert it to radians now } void Instance::R3D_NAV_Forward() { navigation3DMove(&edit.nav.fwd, &Instance::R3D_NAV_Forward_release, false); } void Instance::R3D_NAV_Back_release() { edit.nav.back = 0; } void Instance::R3D_NAV_Back() { navigation3DMove(&edit.nav.back, &Instance::R3D_NAV_Back_release, false); } void Instance::R3D_NAV_Right_release() { edit.nav.right = 0; } void Instance::R3D_NAV_Right() { navigation3DMove(&edit.nav.right, &Instance::R3D_NAV_Right_release, false); } void Instance::R3D_NAV_Left_release() { edit.nav.left = 0; } void Instance::R3D_NAV_Left() { navigation3DMove(&edit.nav.left, &Instance::R3D_NAV_Left_release, false); } void Instance::R3D_NAV_Up_release() { edit.nav.up = 0; } void Instance::R3D_NAV_Up() { navigation3DMove(&edit.nav.up, &Instance::R3D_NAV_Up_release, true); } void Instance::R3D_NAV_Down_release() { edit.nav.down = 0; } void Instance::R3D_NAV_Down() { navigation3DMove(&edit.nav.down, &Instance::R3D_NAV_Down_release, true); } void Instance::R3D_NAV_TurnLeft_release() { edit.nav.turn_L = 0; } void Instance::R3D_NAV_TurnLeft() { navigation3DTurn(&edit.nav.turn_L, &Instance::R3D_NAV_TurnLeft_release); } void Instance::R3D_NAV_TurnRight_release() { edit.nav.turn_R = 0; } void Instance::R3D_NAV_TurnRight() { navigation3DTurn(&edit.nav.turn_R, &Instance::R3D_NAV_TurnRight_release); } void Instance::ACT_AdjustOfs_release() { // check if cancelled or overridden if (edit.action != EditorAction::adjustOfs) return; AdjustOfs_Finish(*this); } void Instance::R3D_ACT_AdjustOfs() { if (! EXEC_CurKey) return; if (! Nav_ActionKey(EXEC_CurKey, &Instance::ACT_AdjustOfs_release)) return; if (edit.mode != ObjType::linedefs) { Beep("not in linedef mode"); return; } AdjustOfs_Begin(*this); } void Instance::R3D_Set() { SString var_name = EXEC_Param[0]; SString value = EXEC_Param[1]; if (var_name.empty()) { Beep("3D_Set: missing var name"); return; } if (value.empty()) { Beep("3D_Set: missing value"); return; } int int_val = atoi(value); bool bool_val = (int_val > 0); if (var_name.noCaseEqual("tex")) { r_view.texturing = bool_val; } else if (var_name.noCaseEqual("obj")) { r_view.sprites = bool_val; } else if (var_name.noCaseEqual("light")) { r_view.lighting = bool_val; } else if (var_name.noCaseEqual("grav")) { r_view.gravity = bool_val; } else { Beep("3D_Set: unknown var: %s", var_name.c_str()); return; } RedrawMap(); } void Instance::R3D_Toggle() { SString var_name = EXEC_Param[0]; if (var_name.empty()) { Beep("3D_Toggle: missing var name"); return; } if (var_name.noCaseEqual("tex")) { r_view.texturing = ! r_view.texturing; } else if (var_name.noCaseEqual("obj")) { r_view.sprites = ! r_view.sprites; } else if (var_name.noCaseEqual("light")) { r_view.lighting = ! r_view.lighting; } else if (var_name.noCaseEqual("grav")) { r_view.gravity = ! r_view.gravity; } else { Beep("3D_Toggle: unknown var: %s", var_name.c_str()); return; } RedrawMap(); } void Instance::R3D_WHEEL_Move() { float dx = static_cast(Fl::event_dx()); float dy = static_cast(Fl::event_dy()); dy = 0 - dy; float speed = static_cast(atof(EXEC_Param[0])); if (Exec_HasFlag("/LAX")) { keycode_t mod = Fl::event_state() & EMOD_ALL_MASK; if (mod == EMOD_SHIFT) speed /= 4.0f; else if (mod == EMOD_COMMAND) speed *= 4.0f; } r_view.x += speed * (r_view.Cos * dy + r_view.Sin * dx); r_view.y += speed * (r_view.Sin * dy - r_view.Cos * dx); main_win->info_bar->SetMouse(); RedrawMap(); } //------------------------------------------------------------------------ static editor_command_t render_commands[] = { { "3D_Set", NULL, &Instance::R3D_Set, /* flags */ NULL, /* keywords */ "tex obj light grav" }, { "3D_Toggle", NULL, &Instance::R3D_Toggle, /* flags */ NULL, /* keywords */ "tex obj light grav" }, { "3D_Forward", NULL, &Instance::R3D_Forward }, { "3D_Backward", NULL, &Instance::R3D_Backward }, { "3D_Left", NULL, &Instance::R3D_Left }, { "3D_Right", NULL, &Instance::R3D_Right }, { "3D_Up", NULL, &Instance::R3D_Up }, { "3D_Down", NULL, &Instance::R3D_Down }, { "3D_Turn", NULL, &Instance::R3D_Turn }, { "3D_DropToFloor", NULL, &Instance::R3D_DropToFloor }, { "3D_ACT_AdjustOfs", NULL, &Instance::R3D_ACT_AdjustOfs }, { "3D_WHEEL_Move", NULL, &Instance::R3D_WHEEL_Move }, { "3D_NAV_Forward", NULL, &Instance::R3D_NAV_Forward }, { "3D_NAV_Back", NULL, &Instance::R3D_NAV_Back }, { "3D_NAV_Right", NULL, &Instance::R3D_NAV_Right }, { "3D_NAV_Left", NULL, &Instance::R3D_NAV_Left }, { "3D_NAV_Up", NULL, &Instance::R3D_NAV_Up }, { "3D_NAV_Down", NULL, &Instance::R3D_NAV_Down }, { "3D_NAV_TurnLeft", NULL, &Instance::R3D_NAV_TurnLeft }, { "3D_NAV_TurnRight", NULL, &Instance::R3D_NAV_TurnRight }, // backwards compatibility. // [ we cannot remap this in FindEditorCommand, it fails the context check ] { "3D_Align", NULL, &Instance::CMD_LIN_Align, /* flags */ "/x /y /right /clear" }, // end of command list { NULL, NULL, 0, NULL } }; void Render3D_RegisterCommands() { M_RegisterCommandList(render_commands); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/r_render.h000066400000000000000000000066051464327712600203100ustar00rootroot00000000000000//------------------------------------------------------------------------ // 3D RENDERING //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_R_RENDER__ #define __EUREKA_R_RENDER__ #include "im_img.h" struct Render_View_t { public: // player type and position. int p_type = 0; double px = 0.0, py = 0.0; // view position. double x = 0.0, y = 0.0, z = 0.0; // view direction. angle is in radians double angle = 0.0; double Sin = 0.0, Cos = 0.0; // screen buffer. int screen_w = 0, screen_h = 0; img_pixel_t *screen = nullptr; float aspect_sh; float aspect_sw; // screen_w * aspect_ratio bool texturing = false; bool sprites = false; bool lighting = false; bool gravity = true; // when true, walk on ground std::vector thing_sectors; // current mouse coords (in window), invalid if -1 int mouse_x = -1, mouse_y = -1; private: Instance &inst; public: explicit Render_View_t(Instance &inst) : inst(inst) { } void SetAngle(float new_ang); void FindGroundZ(); void CalcAspect(); void UpdateScreen(int ow, int oh); void PrepareToRender(int ow, int oh); double DistToViewPlane(v2double_t map); /* r_editing_info_t stuff */ void AddAdjustSide(const Objid& obj); float AdjustDistFactor(float view_x, float view_y); }; namespace global { extern bool use_npot_textures; }; void Render3D_RegisterCommands(); void Render3D_Enable(Instance &inst, bool _enable); // this is basically the FLTK draw() method void Render3D_Draw(Instance &inst, int ox, int oy, int ow, int oh); // perform a query to see what the mouse pointer is over. // returns true if something was hit, false otherwise. // [ see the struct definition for more details... ] bool Render3D_Query(Instance &inst, Objid& hl, int sx, int sy, int ox, int oy, int ow, int oh); void Render3D_ScrollMap(Instance &inst, v2int_t dpos = {}, keycode_t mod = 0); void Render3D_DragThings(Instance &inst); void Render3D_DragSectors(Instance &inst); void Render3D_NotifyBegin(); void Render3D_NotifyInsert(ObjType type, int objnum); void Render3D_NotifyDelete(const Document &doc, ObjType type, int objnum); void Render3D_NotifyChange(ObjType type, int objnum, int field); void Render3D_NotifyEnd(Instance &inst); int Render3D_CalcRotation(double viewAngle_rad, int thingAngle_deg); /* API for rendering a scene (etc) */ void RGL_RenderWorld(Instance &inst, int ox, int oy, int ow, int oh); #endif /* __EUREKA_R_RENDER__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/r_software.cc000066400000000000000000001334601464327712600210210ustar00rootroot00000000000000//------------------------------------------------------------------------ // 3D RENDERING : SOFTWARE MODE //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include #include #ifndef NO_OPENGL #include "FL/gl.h" #endif #include "im_color.h" #include "im_img.h" #include "e_hover.h" #include "e_linedef.h" #include "e_main.h" #include "LineDef.h" #include "m_config.h" #include "m_game.h" #include "w_rawdef.h" #include "w_texture.h" #include "r_render.h" #include "r_subdiv.h" #include "Sector.h" #include "SideDef.h" #include "Thing.h" #include "Vertex.h" static img_pixel_t DoomLightRemap(const Instance &inst, int light, float dist, img_pixel_t pixel) { int map = R_DoomLightingEquation(light, dist); if (pixel & IS_RGB_PIXEL) { map = (map ^ 31) + 1; int r = IMG_PIXEL_RED(pixel); int g = IMG_PIXEL_GREEN(pixel); int b = IMG_PIXEL_BLUE(pixel); r = (r * map) >> 5; g = (g * map) >> 5; b = (b * map) >> 5; return pixelMakeRGB(r, g, b); } else { return inst.wad.palette.getColormapIndex(map, pixel); } } struct DrawSurf { public: enum { K_INVIS = 0, K_FLAT, K_TEXTURE }; int kind; // heights for the surface (h1 is below h2) int h1, h2, tex_h; const Img_c *img; img_pixel_t col; /* used when no image */ enum { SOLID_ABOVE = 1, SOLID_BELOW = 2 }; int y_clip; bool fullbright; Instance &inst; public: explicit DrawSurf(Instance &inst) : kind(K_INVIS), h1(), h2(), tex_h(), img(NULL), col(), y_clip(), fullbright(false), inst(inst) { } ~DrawSurf() { } void FindFlat(const SString & fname) { fullbright = false; if (inst.is_sky(fname)) { col = static_cast(inst.conf.miscInfo.sky_color); fullbright = true; return; } if (inst.r_view.texturing) { img = inst.wad.images.W_GetFlat(inst.conf, fname); if (! img) { img = &inst.wad.images.IM_UnknownFlat(inst.conf); fullbright = config::render_unknown_bright; } return; } // when lighting and no texturing, use a single color if (inst.r_view.lighting) col = static_cast(inst.conf.miscInfo.floor_colors[1]); else col = static_cast(HashedPalColor(fname, inst.conf.miscInfo.floor_colors)); } void FindTex(const SString & tname, LineDef *ld) { fullbright = false; if (inst.r_view.texturing) { if (is_null_tex(tname)) { img = &inst.wad.images.IM_MissingTex(inst.conf); fullbright = config::render_missing_bright; return; } else if (is_special_tex(tname)) { img = &inst.wad.images.IM_SpecialTex(inst.wad.palette); return; } img = inst.wad.images.getTexture(inst.conf, tname); if (! img) { img = &inst.wad.images.IM_UnknownTex(inst.conf); fullbright = config::render_unknown_bright; } return; } // when lighting and no texturing, use a single color if (inst.r_view.lighting) col = static_cast(inst.conf.miscInfo.wall_colors[1]); else col = static_cast(HashedPalColor(tname, inst.conf.miscInfo.wall_colors)); } }; struct DrawWall { public: typedef std::vector vec_t; // when 'th' is >= 0, this is actually a sprite, and 'ld' and // 'sd' will be NULL. Sprites use the info in the 'ceil' surface. int th; LineDef *ld; SideDef *sd; const Sector *sec; // which side this wall faces (SIDE_LEFT or SIDE_RIGHT) // for sprites: a copy of the thinginfo flags Side side; unsigned thingFlags; // the linedef index int ld_index; // lighting for wall, adjusted for N/S and E/W walls int wall_light; // line constants float delta_ang; float dist, t_dist; float normal; // scale for things // distance values (inverted, so they can be lerped) double iz1, iz2; double diz, cur_iz; double mid_iz; // translate coord, for sprite float spr_tx1; // screen X coordinates int sx1, sx2; // for sprites, the remembered open space to clip to int oy1, oy2; /* surfaces */ DrawSurf ceil; DrawSurf upper; DrawSurf lower; DrawSurf floor; DrawSurf rail; Instance &inst; explicit DrawWall(Instance &inst) : ceil(inst), upper(inst), lower(inst), floor(inst), rail(inst), inst(inst) { } // IsCloser tests if THIS wall (wall A) is closer to the camera // than the given wall (wall B). // // Note that it is NOT suitable as a predicate for std::sort() // since it does not guarantee a linear order (total order) of // the elements. Hence the need for our own sorting code. inline bool IsCloser(const DrawWall *const B) const { const DrawWall *const A = this; if (A == B) return false; if (A->ld && B->ld) { // handle cases where two linedefs share a vertex, since that // is where slime-trails would otherwise occur. // if they do share a vertex, we check if the other vertex of // wall A and the camera position are both on the same side of // wall B (extended to infinity). int A_other = -1; if (B->ld->TouchesVertex(A->ld->start)) A_other = A->ld->end; else if (B->ld->TouchesVertex(A->ld->end)) A_other = A->ld->start; if (A_other >= 0) { int ax = static_cast(inst.level.vertices[A_other]->x()); int ay = static_cast(inst.level.vertices[A_other]->y()); int bx1 = static_cast(inst.level.getStart(*B->ld).x()); int by1 = static_cast(inst.level.getStart(*B->ld).y()); int bx2 = static_cast(inst.level.getEnd(*B->ld).x()); int by2 = static_cast(inst.level.getEnd(*B->ld).y()); int cx = (int)inst.r_view.x; // camera int cy = (int)inst.r_view.y; Side A_side = PointOnLineSide(ax, ay, bx1, by1, bx2, by2); Side C_side = PointOnLineSide(cx, cy, bx1, by1, bx2, by2); return (A_side * C_side != Side::left); } } else if (A->th >= 0 && B->th >= 0) { // prevent two things at same location from flickering const auto TA = inst.level.things[A->th]; const auto TB = inst.level.things[B->th]; if (TA->raw_x == TB->raw_x && TA->raw_y == TB->raw_y) return A->th > B->th; } return A->cur_iz > B->cur_iz; } /* PREDICATES */ struct MidDistCmp { inline bool operator() (const DrawWall * A, const DrawWall * B) const { return A->mid_iz > B->mid_iz; } }; struct SX1Cmp { inline bool operator() (const DrawWall * A, const DrawWall * B) const { return A->sx1 < B->sx1; } inline bool operator() (const DrawWall * A, int x) const { return A->sx1 < x; } inline bool operator() (int x, const DrawWall * A) const { return x < A->sx1; } }; struct SX2Less { int x; SX2Less(int _x) : x(_x) { } inline bool operator() (const DrawWall * A) const { return A->sx2 < x; } }; /* methods */ const Sector *Boom242Sector(const Sector *real, Sector *temp, const Sector *dummy) { *temp = *real; temp->floorh = dummy->floorh; temp->ceilh = dummy->ceilh; if (dummy->floorh > real->floorh && inst.r_view.z < dummy->floorh) { // space C : underwater temp->floorh = real->floorh; temp->ceilh = dummy->floorh; temp->floor_tex = dummy->floor_tex; temp->ceil_tex = dummy->ceil_tex; } else if (dummy->ceilh < real->ceilh && inst.r_view.z > dummy->ceilh) { // space A : head above ceiling temp->floorh = dummy->ceilh; temp->ceilh = real->ceilh; temp->floor_tex = dummy->floor_tex; temp->ceil_tex = dummy->ceil_tex; } else { // space B : normal } return temp; } void ComputeWallSurface() { const Sector *front = sec; const Sector *back = NULL; SideDef *back_sd = (side == Side::left) ? inst.level.getRight(*ld) : inst.level.getLeft(*ld); if (back_sd) back = inst.level.sectors[back_sd->sector].get(); // support for BOOM's 242 "transfer heights" line type Sector temp_front; Sector temp_back; sector_3dfloors_c *exfloor = inst.Subdiv_3DFloorsForSector(sd->sector); if (exfloor->heightsec >= 0) { const auto dummy = inst.level.sectors[exfloor->heightsec]; front = Boom242Sector(front, &temp_front, dummy.get()); } if (back != NULL) { exfloor = inst.Subdiv_3DFloorsForSector(back_sd->sector); if (exfloor->heightsec >= 0) { const auto dummy = inst.level.sectors[exfloor->heightsec]; back = Boom242Sector(back, &temp_back, dummy.get()); } } bool sky_upper = back && inst.is_sky(front->CeilTex()) && inst.is_sky(back->CeilTex()); bool self_ref = (front == back) ? true : false; if ((front->ceilh > inst.r_view.z || inst.is_sky(front->CeilTex())) && ! sky_upper && ! self_ref) { ceil.kind = DrawSurf::K_FLAT; ceil.h1 = front->ceilh; ceil.h2 = +99999; ceil.tex_h = ceil.h1; ceil.y_clip = DrawSurf::SOLID_ABOVE; ceil.FindFlat(front->CeilTex()); } if (front->floorh < inst.r_view.z && ! self_ref) { floor.kind = DrawSurf::K_FLAT; floor.h1 = -99999; floor.h2 = front->floorh; floor.tex_h = floor.h2; floor.y_clip = DrawSurf::SOLID_BELOW; floor.FindFlat(front->FloorTex()); } if (! back) { /* ONE-sided line */ lower.kind = DrawSurf::K_TEXTURE; lower.h1 = front->floorh; lower.h2 = front->ceilh; lower.y_clip = DrawSurf::SOLID_ABOVE | DrawSurf::SOLID_BELOW; lower.FindTex(sd->MidTex(), ld); if (lower.img && (ld->flags & MLF_LowerUnpegged)) lower.tex_h = lower.h1 + lower.img->height(); else lower.tex_h = lower.h2; lower.tex_h += sd->y_offset; return; } /* TWO-sided line */ if (back->ceilh < front->ceilh && ! sky_upper && ! self_ref) { upper.kind = DrawSurf::K_TEXTURE; upper.h1 = back->ceilh; upper.h2 = front->ceilh; upper.y_clip = DrawSurf::SOLID_ABOVE; upper.FindTex(sd->UpperTex(), ld); if (upper.img && ! (ld->flags & MLF_UpperUnpegged)) upper.tex_h = upper.h1 + upper.img->height(); else upper.tex_h = upper.h2; upper.tex_h += sd->y_offset; } if (back->floorh > front->floorh && ! self_ref) { lower.kind = DrawSurf::K_TEXTURE; lower.h1 = front->floorh; lower.h2 = back->floorh; lower.y_clip = DrawSurf::SOLID_BELOW; lower.FindTex(sd->LowerTex(), ld); // note "sky_upper" here, needed to match original DOOM behavior if (ld->flags & MLF_LowerUnpegged) lower.tex_h = sky_upper ? back->ceilh : front->ceilh; else lower.tex_h = lower.h2; lower.tex_h += sd->y_offset; } /* Mid-Masked texture */ if (! inst.r_view.texturing) return; if (is_null_tex(sd->MidTex())) return; rail.FindTex(sd->MidTex(), ld); if (! rail.img) return; front = sec; back = inst.level.sectors[back_sd->sector].get(); int c_h = std::min(front->ceilh, back->ceilh); int f_h = std::max(front->floorh, back->floorh); int r_h = rail.img->height(); if (f_h >= c_h) return; if (ld->flags & MLF_LowerUnpegged) { rail.h1 = f_h + sd->y_offset; rail.h2 = rail.h1 + r_h; } else { rail.h2 = c_h + sd->y_offset; rail.h1 = rail.h2 - r_h; } rail.kind = DrawSurf::K_TEXTURE; rail.y_clip = 0; rail.tex_h = rail.h2; // clip railing, unless sectors on both sides are identical or // we have a sky upper if (! (sky_upper || (back->ceilh == front->ceilh && back->ceil_tex == front->ceil_tex && back->light == front->light))) { rail.h2 = std::min(c_h, rail.h2); } if (! (back->floorh == front->floorh && back->floor_tex == front->floor_tex && back->light == front->light)) { rail.h1 = std::max(f_h, rail.h1); } } }; struct RendInfo { public: // complete set of walls/sprites to draw. DrawWall::vec_t walls; // the active list. Pointers here are always duplicates of ones in // the walls list (no need to 'delete' any of them). DrawWall::vec_t active; // query state int query_mode; // 0 for normal render int query_sx; int query_sy; Objid query_result; float query_map_x; float query_map_y; float query_map_z; // inverse distances over X range, 0 when empty. std::vector depth_x; // vertical clip window, an inclusive range int open_y1; int open_y2; // these used by Highlight() int hl_ox, hl_oy; int hl_thick; Fl_Color hl_color; Instance &inst; private: static void DeleteWall(DrawWall *P) { delete P; } public: explicit RendInfo(Instance &inst) : walls(), active(), query_mode(0), query_sx(), query_sy(), depth_x(), open_y1(), open_y2(), inst(inst) { } ~RendInfo() { std::for_each(walls.begin(), walls.end(), DeleteWall); walls.clear (); active.clear (); } void InitDepthBuf (int width) { depth_x.resize(width); std::fill_n(depth_x.begin(), width, 0); } void DrawHighlightLine(int sx1, int sy1, int sx2, int sy2) { if (! config::render_high_detail) { sx1 *= 2; sy1 *= 2; sx2 *= 2; sy2 *= 2; } fl_color(hl_color); if (hl_thick) fl_line_style(FL_SOLID, 2); fl_line(hl_ox + sx1, hl_oy + sy1, hl_ox + sx2, hl_oy + sy2); if (hl_thick) fl_line_style(0); } static inline float PointToAngle(float x, float y) { if (-0.01 < x && x < 0.01) return static_cast((y > 0) ? M_PI/2 : (3 * M_PI/2)); float angle = atan2(y, x); if (angle < 0) angle += static_cast(2*M_PI); return angle; } inline int AngleToX(float ang) { float t = static_cast(tan(M_PI/2 - ang)); int x = int(inst.r_view.aspect_sw * t); x = (inst.r_view.screen_w + x) / 2; if (x < 0) x = 0; else if (x > inst.r_view.screen_w) x = inst.r_view.screen_w; return x; } inline float XToAngle(int x) { x = x * 2 - inst.r_view.screen_w; float ang = static_cast(M_PI/2 + atan(x / inst.r_view.aspect_sw)); if (ang < 0) ang = 0; else if (ang > M_PI) ang = static_cast(M_PI); return ang; } inline int DeltaToX(double iz, float tx) { int x = int(static_cast(inst.r_view.aspect_sw) * tx * iz); x = (x + inst.r_view.screen_w) / 2; return x; } inline float XToDelta(int x, double iz) { x = x * 2 - inst.r_view.screen_w; float tx = static_cast(x / iz / inst.r_view.aspect_sw); return tx; } inline int DistToY(double iz, int sec_h) { if (sec_h > 32770) return -9999; if (sec_h < -32770) return +9999; int y = int(inst.r_view.aspect_sh * (sec_h - inst.r_view.z) * iz); return (inst.r_view.screen_h - y) / 2; } inline float YToDist(int y, int sec_h) { y = inst.r_view.screen_h - y * 2; if (y == 0) return 999999; return static_cast(inst.r_view.aspect_sh * (sec_h - inst.r_view.z) / y); } inline float YToSecH(int y, double iz) { y = y * 2 - inst.r_view.screen_h; return static_cast(inst.r_view.z - (float(y) / inst.r_view.aspect_sh / iz)); } void AddLine(int ld_index) { const auto ld = inst.level.linedefs[ld_index]; if (!inst.level.isVertex(ld->start) || !inst.level.isVertex(ld->end)) return; if (! inst.level.getRight(*ld)) return; float x1 = static_cast(inst.level.getStart(*ld).x() - inst.r_view.x); float y1 = static_cast(inst.level.getStart(*ld).y() - inst.r_view.y); float x2 = static_cast(inst.level.getEnd(*ld).x() - inst.r_view.x); float y2 = static_cast(inst.level.getEnd(*ld).y() - inst.r_view.y); float tx1 = static_cast(x1 * inst.r_view.Sin - y1 * inst.r_view.Cos); float ty1 = static_cast(x1 * inst.r_view.Cos + y1 * inst.r_view.Sin); float tx2 = static_cast(x2 * inst.r_view.Sin - y2 * inst.r_view.Cos); float ty2 = static_cast(x2 * inst.r_view.Cos + y2 * inst.r_view.Sin); // reject line if complete behind viewplane if (ty1 <= 0 && ty2 <= 0) return; float angle1 = PointToAngle(tx1, ty1); float angle2 = PointToAngle(tx2, ty2); float span = angle1 - angle2; if (span < 0) span += static_cast(2*M_PI); Side side = Side::right; if (span >= M_PI) side = Side::left; // ignore the line when there is no facing sidedef SideDef *sd = (side == Side::left) ? inst.level.getLeft(*ld) : inst.level.getRight(*ld); if (! sd) return; if (side == Side::left) { float tmp = angle1; angle1 = angle2; angle2 = tmp; } // clip angles to view volume float base_ang = angle1; float leftclip = static_cast(3 * M_PI / 4); float rightclip = static_cast(M_PI / 4); float tspan1 = angle1 - rightclip; float tspan2 = leftclip - angle2; if (tspan1 < 0) tspan1 += static_cast(2*M_PI); if (tspan2 < 0) tspan2 += static_cast(2*M_PI); if (tspan1 > M_PI/2) { // Totally off the left edge? if (tspan2 >= M_PI) return; angle1 = leftclip; } if (tspan2 > M_PI/2) { // Totally off the left edge? if (tspan1 >= M_PI) return; angle2 = rightclip; } // convert angles to on-screen X positions int sx1 = AngleToX(angle1); int sx2 = AngleToX(angle2) - 1; if (sx1 > sx2) return; // optimisation for query mode if (query_mode && (sx2 < query_sx || sx1 > query_sx)) return; // compute distance from eye to wall float wdx = x2 - x1; float wdy = y2 - y1; float wlen = sqrt(wdx * wdx + wdy * wdy); float dist = fabs((y1 * wdx / wlen) - (x1 * wdy / wlen)); if (dist < 0.01) return; // compute normal of wall (translated coords) float normal; if (side == Side::left) normal = PointToAngle(ty2 - ty1, tx1 - tx2); else normal = PointToAngle(ty1 - ty2, tx2 - tx1); // compute inverse distances double iz1 = cos(normal - angle1) / dist / cos(M_PI/2 - angle1); double iz2 = cos(normal - angle2) / dist / cos(M_PI/2 - angle2); double diz = (iz2 - iz1) / std::max(1, sx2 - sx1); // create drawwall structure DrawWall *dw = new DrawWall(inst); dw->th = -1; dw->ld = ld.get(); dw->ld_index = ld_index; dw->sd = sd; dw->sec = &inst.level.getSector(*sd); dw->side = side; dw->thingFlags = 0; dw->wall_light = dw->sec->light; // add "fake constrast" for axis-aligned walls if (inst.level.isVertical(*ld)) dw->wall_light += 16; else if (inst.level.isHorizontal(*ld)) dw->wall_light -= 16; dw->delta_ang = angle1 + XToAngle(sx1) - normal; dw->dist = dist; dw->normal = normal; dw->t_dist = tan(base_ang - normal) * dist; dw->iz1 = iz1; dw->iz2 = iz2; dw->diz = diz; dw->mid_iz = iz1 + (sx2 - sx1 + 1) * diz / 2; dw->sx1 = sx1; dw->sx2 = sx2; walls.push_back(dw); } void AddThing(int th_index) { const auto th = inst.level.things[th_index]; const thingtype_t &info = inst.conf.getThingType(th->type); float x = static_cast(th->x() - inst.r_view.x); float y = static_cast(th->y() - inst.r_view.y); float tx = static_cast(x * inst.r_view.Sin - y * inst.r_view.Cos); float ty = static_cast(x * inst.r_view.Cos + y * inst.r_view.Sin); // reject sprite if complete behind viewplane if (ty < 4) return; bool is_unknown = false; float scale = info.scale; const Img_c *sprite = inst.wad.getSprite(inst.conf, th->type, inst.loaded, Render3D_CalcRotation(inst.r_view.angle, th->angle)); if (! sprite) { sprite = &inst.wad.images.IM_UnknownSprite(inst.conf); is_unknown = true; scale = 0.33f; } float tx1 = tx - sprite->width() * scale / 2.0f; float tx2 = tx + sprite->width() * scale / 2.0f; double iz = 1 / ty; int sx1 = DeltaToX(iz, tx1); int sx2 = DeltaToX(iz, tx2) - 1; if (sx1 < 0) sx1 = 0; if (sx2 >= inst.r_view.screen_w) sx2 = inst.r_view.screen_w - 1; if (sx1 > sx2) return; // optimisation for query mode if (query_mode && (sx2 < query_sx || sx1 > query_sx)) return; int thsec = inst.r_view.thing_sectors[th_index]; // check if thing is hidden by BOOM deep water if (inst.level.isSector(thsec)) { sector_3dfloors_c *exfloor = inst.Subdiv_3DFloorsForSector(thsec); if (inst.level.isSector(exfloor->heightsec)) { const auto real = inst.level.sectors[thsec]; const auto dummy = inst.level.sectors[exfloor->heightsec]; if (dummy->floorh > real->floorh && inst.r_view.z > dummy->floorh && !(info.flags & THINGDEF_CEIL)) { return; } } } int h1, h2; if (info.flags & THINGDEF_CEIL) { // IOANCH 9/2015: also add z h2 = static_cast((inst.level.isSector(thsec) ? inst.level.sectors[thsec]->ceilh : 192) - th->h()); h1 = static_cast(h2 - sprite->height() * scale); } else { h1 = static_cast((inst.level.isSector(thsec) ? inst.level.sectors[thsec]->floorh : 0) + th->h()); h2 = static_cast(h1 + sprite->height() * scale); } // create drawwall structure DrawWall *dw = new DrawWall(inst); dw->th = th_index; dw->ld_index = -1; dw->ld = NULL; dw->sd = NULL; dw->sec = NULL; dw->side = Side::neither; dw->thingFlags = info.flags; if (is_unknown && config::render_unknown_bright) dw->thingFlags |= THINGDEF_LIT; dw->spr_tx1 = tx1; dw->normal = scale; dw->iz1 = dw->mid_iz = iz; dw->diz = 0; dw->sx1 = sx1; dw->sx2 = sx2; dw->ceil.img = sprite; dw->ceil.h1 = h1; dw->ceil.h2 = h2; walls.push_back(dw); } void ComputeSurfaces() { DrawWall::vec_t::iterator S; for (S = walls.begin() ; S != walls.end() ; S++) { if ((*S)->ld) (*S)->ComputeWallSurface(); } } void QueryCalcCoord(const DrawWall *dw, ObjType what, int part) { float dist = static_cast(1.0 / dw->cur_iz); if (what == ObjType::sectors) { // sky surfaces require a check on Z height if (part == PART_CEIL && dw->sec->ceilh > inst.r_view.z + 1) dist = YToDist(query_sy, dw->sec->ceilh); else if (part == PART_FLOOR && dw->sec->floorh < inst.r_view.z - 1) dist = YToDist(query_sy, dw->sec->floorh); } if (dist < 4.0) dist = 4.0; float ang = XToAngle(query_sx); float modv = static_cast(cos(ang - M_PI/2)); float t_cos = static_cast(cos(M_PI + -inst.r_view.angle + ang) / modv); float t_sin = static_cast(sin(M_PI + -inst.r_view.angle + ang) / modv); query_map_x = static_cast(inst.r_view.x - static_cast(t_sin) * dist); query_map_y = static_cast(inst.r_view.y - static_cast(t_cos) * dist); query_map_z = YToSecH(query_sy, 1.0 / dist); // ensure we never produce X == 0 if (query_map_x == 0) query_map_x = 0.01f; } void HighlightWallBit(const DrawWall *dw, int ld_index, int part) { // check the part is on the side facing the camera Side p_side = (part & PART_LF_ALL) ? Side::left : Side::right; if (dw->side != p_side) return; int z1, z2; if (dw->ld->TwoSided()) { const Sector &front = inst.level.getSector(*inst.level.getRight(*dw->ld)); const Sector &back = inst.level.getSector(*inst.level.getLeft(*dw->ld)); if (part & (PART_RT_LOWER | PART_LF_LOWER)) { z1 = std::min(front.floorh, back.floorh); z2 = std::max(front.floorh, back.floorh); } else if (part & (PART_RT_UPPER | PART_LF_UPPER)) { z1 = std::min(front.ceilh, back.ceilh); z2 = std::max(front.ceilh, back.ceilh); } else { if (! inst.LD_RailHeights(z1, z2, dw->ld, dw->sd, &front, &back)) return; } } else { if (0 == (part & (PART_RT_LOWER | PART_LF_LOWER))) return; z1 = inst.level.getSector(*dw->sd).floorh; z2 = inst.level.getSector(*dw->sd).ceilh; } int x1 = dw->sx1; int x2 = dw->sx2 + 1; int ly1 = DistToY(dw->iz1, z2); int ly2 = DistToY(dw->iz1, z1); int ry1 = DistToY(dw->iz2, z2); int ry2 = DistToY(dw->iz2, z1); // workaround for crappy line clipping in X windows if (ly1 < -5000 || ly2 < -5000 || ly1 > 5000 || ly2 > 5000 || ry1 < -5000 || ry2 < -5000 || ry1 > 5000 || ry2 > 5000) return; DrawHighlightLine(x1, ly1, x1, ly2); DrawHighlightLine(x2, ry1, x2, ry2); DrawHighlightLine(x1, ly1, x2, ry1); DrawHighlightLine(x1, ly2, x2, ry2); } void HighlightLines(int ld_index, int parts) { DrawWall::vec_t::iterator S; for (S = walls.begin() ; S != walls.end() ; S++) { const DrawWall *dw = (*S); if (! dw->ld) continue; int line2 = ld_index; int parts2 = parts; if (ld_index >= 0) { if (dw->ld_index != ld_index) continue; } else { line2 = dw->ld_index; parts2 = inst.edit.Selected->get_ext(line2); if (parts2 == 0) continue; if (parts2 == 1) { parts2 = 0; hl_color = SEL_COL; } else { hl_color = SEL3D_COL; } } /* right side */ if (parts2 == 0 || (parts2 & PART_RT_LOWER)) HighlightWallBit(dw, line2, PART_RT_LOWER); if (parts2 == 0 || (parts2 & PART_RT_UPPER)) HighlightWallBit(dw, line2, PART_RT_UPPER); if (parts2 & PART_RT_RAIL) HighlightWallBit(dw, line2, PART_RT_RAIL); /* left side */ if (parts2 == 0 || (parts2 & PART_LF_LOWER)) HighlightWallBit(dw, line2, PART_LF_LOWER); if (parts2 == 0 || (parts2 & PART_LF_UPPER)) HighlightWallBit(dw, line2, PART_LF_UPPER); if (parts2 & PART_LF_RAIL) HighlightWallBit(dw, line2, PART_LF_RAIL); } } void HighlightSectorBit(const DrawWall *dw, int sec_index, int part) { const auto S = inst.level.sectors[sec_index]; int z = (part == PART_CEIL) ? S->ceilh : S->floorh; // are we dragging this surface? if (inst.edit.action == EditorAction::drag && (!inst.edit.dragged.valid() || (inst.edit.dragged.num == sec_index && (inst.edit.dragged.parts == 0 || (inst.edit.dragged.parts & part)) ))) { z = z + (int)inst.edit.drag_sector_dz; } else { // check that plane faces the camera if (part == PART_FLOOR && (inst.r_view.z < z + 0.2)) return; if (part == PART_CEIL && (inst.r_view.z > z - 0.2)) return; } int sy1 = DistToY(dw->iz1, z); int sy2 = DistToY(dw->iz2, z); // workaround for crappy line clipping in X windows if (sy1 < -5000 || sy2 < -5000 || sy1 > 5000 || sy2 > 5000) return; DrawHighlightLine(dw->sx1, sy1, dw->sx2, sy2); } void HighlightSectors(int sec_index, int parts) { DrawWall::vec_t::iterator S; for (S = walls.begin() ; S != walls.end() ; S++) { const DrawWall *dw = (*S); if (! dw->ld) continue; if (sec_index >= 0) { if (! inst.level.touchesSector(*dw->ld, sec_index)) continue; // Note: hl_color already set by caller if (parts == 0 || (parts & PART_FLOOR)) HighlightSectorBit(dw, sec_index, PART_FLOOR); if (parts == 0 || (parts & PART_CEIL)) HighlightSectorBit(dw, sec_index, PART_CEIL); continue; } /* doing the selection */ for (int what_side = 0 ; what_side < 2 ; what_side++) { const SideDef *sd_front = inst.level.getRight(*dw->ld); const SideDef *sd_back = inst.level.getLeft(*dw->ld); if (sd_front && sd_back && sd_front == sd_back) break; if (what_side == 1) std::swap(sd_front, sd_back); if (sd_front == NULL) continue; int sec2 = sd_front->sector; parts = inst.edit.Selected->get_ext(sec2); if (parts == 0) continue; if (parts == 1) { parts = PART_FLOOR | PART_CEIL; hl_color = SEL_COL; } else { hl_color = SEL3D_COL; } if (parts & PART_FLOOR) HighlightSectorBit(dw, sec2, PART_FLOOR); if (parts & PART_CEIL) HighlightSectorBit(dw, sec2, PART_CEIL); } } } void HighlightThings(int th_index) { DrawWall::vec_t::iterator S; for (S = walls.begin() ; S != walls.end() ; S++) { const DrawWall *dw = (*S); if (dw->th < 0) continue; if (th_index >= 0) { if (dw->th != th_index) continue; } else { if (! inst.edit.Selected->get(dw->th)) continue; } int x1 = dw->sx1 - 1; int x2 = dw->sx2 + 1; int h1 = dw->ceil.h1 - 1; int h2 = dw->ceil.h2 + 1; int y1 = DistToY(dw->iz1, h2); int y2 = DistToY(dw->iz1, h1); if (inst.edit.action == EditorAction::drag && (!inst.edit.dragged.valid() || inst.edit.dragged.num == th_index)) { // re-project thing onto the viewplane float dx = static_cast(inst.edit.drag_cur.x - inst.edit.drag_start.x); float dy = static_cast(inst.edit.drag_cur.y - inst.edit.drag_start.y); float dz = static_cast(inst.edit.drag_cur.z - inst.edit.drag_start.z); const auto T = inst.level.things[dw->th]; float x = static_cast(T->x() + dx - inst.r_view.x); float y = static_cast(T->y() + dy - inst.r_view.y); float tx = static_cast(x * inst.r_view.Sin - y * inst.r_view.Cos); float ty = static_cast(x * inst.r_view.Cos + y * inst.r_view.Sin); if (ty < 1) ty = 1; float scale = dw->normal; const Img_c *sprite = dw->ceil.img; float tx1 = static_cast(tx - sprite->width() * scale / 2.0); float tx2 = static_cast(tx + sprite->width() * scale / 2.0); double iz = 1 / ty; x1 = DeltaToX(iz, tx1) - 1; x2 = DeltaToX(iz, tx2) + 1; int thsec = inst.r_view.thing_sectors[th_index]; if (dw->thingFlags & THINGDEF_CEIL) { h2 = static_cast((inst.level.isSector(thsec) ? inst.level.sectors[thsec]->ceilh : 192) - T->h()); h1 = static_cast(h2 - sprite->height() * scale); } else { h1 = static_cast((inst.level.isSector(thsec) ? inst.level.sectors[thsec]->floorh : 0) + T->h()); h2 = static_cast(h1 + sprite->height() * scale); } h1 = static_cast(h1 + dz - 1); h2 = static_cast(h2 + dz + 1); y1 = DistToY(iz, h2); y2 = DistToY(iz, h1); } DrawHighlightLine(x1, y1, x1, y2); DrawHighlightLine(x2, y1, x2, y2); DrawHighlightLine(x1, y1, x2, y1); DrawHighlightLine(x1, y2, x2, y2); } } void Highlight(int ox, int oy) { hl_ox = ox; hl_oy = oy; hl_thick = 2; switch (inst.edit.mode) { case ObjType::things: hl_color = SEL_COL; HighlightThings(-1); hl_color = HI_COL; if (inst.edit.action == EditorAction::drag && inst.edit.dragged.valid()) { HighlightThings(inst.edit.dragged.num); } else if (inst.edit.highlight.valid()) { if (inst.edit.Selected->get(inst.edit.highlight.num)) hl_color = HI_AND_SEL_COL; HighlightThings(inst.edit.highlight.num); } break; case ObjType::sectors: HighlightSectors(-1, -1); hl_color = HI_COL; if (inst.edit.action == EditorAction::drag && inst.edit.dragged.valid()) { HighlightSectors(inst.edit.dragged.num, inst.edit.dragged.parts); } else if (inst.edit.highlight.valid()) { if (inst.edit.Selected->get(inst.edit.highlight.num)) hl_color = HI_AND_SEL_COL; HighlightSectors(inst.edit.highlight.num, inst.edit.highlight.parts); } break; case ObjType::linedefs: HighlightLines(-1, -1); hl_color = HI_COL; if (inst.edit.action == EditorAction::drag && inst.edit.dragged.valid()) { if (inst.edit.Selected->get(inst.edit.highlight.num)) hl_color = HI_AND_SEL_COL; HighlightLines(inst.edit.highlight.num, inst.edit.highlight.parts); } break; default: break; } } void ClipSolids() { // perform a rough depth sort of the walls and sprites. std::sort(walls.begin(), walls.end(), DrawWall::MidDistCmp()); // go forwards, from closest to furthest away DrawWall::vec_t::iterator S; for (S = walls.begin() ; S != walls.end() ; S++) { DrawWall *dw = (*S); if (! dw) continue; int one_sided = dw->ld && ! inst.level.getLeft(*dw->ld); int vis_count = dw->sx2 - dw->sx1 + 1; for (int x = dw->sx1 ; x <= dw->sx2 ; x++) { double iz = dw->iz1 + (dw->diz * (x - dw->sx1)); if (iz < depth_x[x]) vis_count--; else if (one_sided) depth_x[x] = iz; } if (vis_count == 0) { delete dw; (*S) = NULL; } } // remove null pointers S = std::remove(walls.begin(), walls.end(), (DrawWall *) NULL); walls.erase(S, walls.end()); } void RenderFlatColumn(DrawWall *dw, DrawSurf& surf, int x, int y1, int y2) { img_pixel_t *dest = inst.r_view.screen; const img_pixel_t *src = surf.img->buf(); int tw = surf.img->width(); int th = surf.img->height(); float ang = XToAngle(x); float modv = static_cast(cos(ang - M_PI/2)); float t_cos = static_cast(cos(M_PI + -inst.r_view.angle + ang) / modv); float t_sin = static_cast(sin(M_PI + -inst.r_view.angle + ang) / modv); dest += x + y1 * inst.r_view.screen_w; int light = dw->sec->light; for ( ; y1 <= y2 ; y1++, dest += inst.r_view.screen_w) { float dist = YToDist(y1, surf.tex_h); int tx = int( inst.r_view.x - static_cast(t_sin) * dist) & (tw - 1); int ty = int(-inst.r_view.y + static_cast(t_cos) * dist) & (th - 1); *dest = src[ty * tw + tx]; if (inst.r_view.lighting && ! surf.fullbright) *dest = DoomLightRemap(inst, light, dist, *dest); } } void RenderTexColumn(DrawWall *dw, DrawSurf& surf, int x, int y1, int y2) { img_pixel_t *dest = inst.r_view.screen; const img_pixel_t *src = surf.img->buf(); int tw = surf.img->width(); int th = surf.img->height(); int light = dw->wall_light; float dist = static_cast(1.0 / dw->cur_iz); /* compute texture X coord */ float cur_ang = dw->delta_ang - XToAngle(x); int tx = int(dw->t_dist - tan(cur_ang) * dw->dist); tx = (dw->sd->x_offset + tx) & (tw - 1); /* compute texture Y coords */ float hh = surf.tex_h - YToSecH(y1, dw->cur_iz); float dh = surf.tex_h - YToSecH(y2, dw->cur_iz); dh = (dh - hh) / std::max(1, y2 - y1); hh += 0.2f; src += tx; dest += x + y1 * inst.r_view.screen_w; for ( ; y1 <= y2 ; y1++, hh += dh, dest += inst.r_view.screen_w) { int ty = int(floor(hh)) % th; // handle negative values (use % twice) ty = (ty + th) % th; img_pixel_t pix = src[ty * tw]; if (pix == TRANS_PIXEL) continue; if (inst.r_view.lighting && ! surf.fullbright) *dest = DoomLightRemap(inst, light, dist, pix); else *dest = pix; } } void SolidFlatColumn(DrawWall *dw, DrawSurf& surf, int x, int y1, int y2) { img_pixel_t *dest = inst.r_view.screen; dest += x + y1 * inst.r_view.screen_w; int light = dw->sec->light; for ( ; y1 <= y2 ; y1++, dest += inst.r_view.screen_w) { float dist = YToDist(y1, surf.tex_h); if (inst.r_view.lighting && ! surf.fullbright) *dest = DoomLightRemap(inst, light, dist, surf.col); else *dest = surf.col; } } void SolidTexColumn(DrawWall *dw, DrawSurf& surf, int x, int y1, int y2) { int light = dw->wall_light; float dist = static_cast(1.0 / dw->cur_iz); img_pixel_t *dest = inst.r_view.screen; dest += x + y1 * inst.r_view.screen_w; for ( ; y1 <= y2 ; y1++, dest += inst.r_view.screen_w) { if (inst.r_view.lighting && ! surf.fullbright) *dest = DoomLightRemap(inst, light, dist, surf.col); else *dest = surf.col; } } inline void RenderWallSurface(DrawWall *dw, DrawSurf& surf, int x, ObjType what, int part) { if (surf.kind == DrawSurf::K_INVIS) return; int y1 = DistToY(dw->cur_iz, surf.h2); int y2 = DistToY(dw->cur_iz, surf.h1) - 1; // clip to the open region if (y1 < open_y1) y1 = open_y1; if (y2 > open_y2) y2 = open_y2; // update open region based on ends which are "solid" if (surf.y_clip & DrawSurf::SOLID_ABOVE) open_y1 = std::max(open_y1, y2 + 1); if (surf.y_clip & DrawSurf::SOLID_BELOW) open_y2 = std::min(open_y2, y1 - 1); if (y1 > y2) return; /* query mode : is mouse over this wall part? */ if (query_mode) { if (y1 <= query_sy && query_sy <= y2) { if (what == ObjType::linedefs) { if (dw->side == Side::left) part <<= 4; query_result = Objid(what, dw->ld_index, part); } else if (dw->sd != NULL) { query_result = Objid(what, dw->sd->sector, part); } QueryCalcCoord(dw, what, part); } return; } /* fill pixels */ if (! surf.img) { if (surf.kind == DrawSurf::K_FLAT) SolidFlatColumn(dw, surf, x, y1, y2); else SolidTexColumn(dw, surf, x, y1, y2); } else switch (surf.kind) { case DrawSurf::K_FLAT: RenderFlatColumn(dw, surf, x, y1, y2); break; case DrawSurf::K_TEXTURE: RenderTexColumn(dw, surf, x, y1, y2); break; } } inline void RenderSprite(DrawWall *dw, int x) { int y1 = DistToY(dw->cur_iz, dw->ceil.h2); int y2 = DistToY(dw->cur_iz, dw->ceil.h1) - 1; if (y1 < dw->oy1) y1 = dw->oy1; if (y2 > dw->oy2) y2 = dw->oy2; if (y1 > y2) return; if (query_mode) { if (y1 <= query_sy && query_sy <= y2 && inst.edit.mode == ObjType::things) { query_result = Objid(ObjType::things, dw->th); } return; } int tw = dw->ceil.img->width(); int th = dw->ceil.img->height(); float scale = dw->normal; int tx = int((XToDelta(x, dw->cur_iz) - dw->spr_tx1) / scale); if (tx < 0 || tx >= tw) return; float hh = dw->ceil.h2 - YToSecH(y1, dw->cur_iz); float dh = dw->ceil.h2 - YToSecH(y2, dw->cur_iz); dh = (dh - hh) / std::max(1, y2 - y1); int thsec = inst.r_view.thing_sectors[dw->th]; int light = inst.level.isSector(thsec) ? inst.level.sectors[thsec]->light : 255; float dist = static_cast(1.0 / dw->cur_iz); /* fill pixels */ img_pixel_t *dest = inst.r_view.screen; dest += x + y1 * inst.r_view.screen_w; const img_pixel_t *src = dw->ceil.img->buf(); src += tx; for ( ; y1 <= y2 ; y1++, hh += dh, dest += inst.r_view.screen_w) { int ty = int(hh / scale); if (ty < 0 || ty >= th) continue; img_pixel_t pix = src[ty * tw]; if (pix == TRANS_PIXEL) continue; if (dw->thingFlags & THINGDEF_INVIS) { if(*dest & IS_RGB_PIXEL) *dest = IS_RGB_PIXEL | ((*dest & 0x7bde) >> 1); else *dest = inst.wad.palette.getColormapIndex(14, *dest); continue; } *dest = pix; if (inst.r_view.lighting && ! (dw->thingFlags & THINGDEF_LIT)) *dest = DoomLightRemap(inst, light, dist, *dest); } } inline void RenderMidMasker(DrawWall *dw, DrawSurf& surf, int x) { if (surf.kind == DrawSurf::K_INVIS) return; if (! surf.img) return; int y1 = DistToY(dw->cur_iz, surf.h2); int y2 = DistToY(dw->cur_iz, surf.h1) - 1; if (y1 < dw->oy1) y1 = dw->oy1; if (y2 > dw->oy2) y2 = dw->oy2; if (y1 > y2) return; if (query_mode) { if (y1 <= query_sy && query_sy <= y2 && inst.edit.mode == ObjType::linedefs) { int part = (dw->side == Side::left) ? PART_LF_RAIL : PART_RT_RAIL; query_result = Objid(ObjType::linedefs, dw->ld_index, part); } return; } /* fill pixels */ RenderTexColumn(dw, surf, x, y1, y2); } inline void Sort_Swap(int i, int k) { DrawWall *A = active[i]; DrawWall *B = active[k]; active[k] = A; active[i] = B; } int Sort_Partition(int lo, int hi, int pivot_idx) { /* this is Hoare's algorithm */ const DrawWall *pivot = active[pivot_idx]; int s = lo; int e = hi; for (;;) { while (s <= e && active[s]->IsCloser(pivot)) s++; if (s > hi) { // all values were < pivot, including the pivot itself! if (pivot_idx != hi) Sort_Swap(pivot_idx, hi); return hi - 1; } while (e >= s && ! active[e]->IsCloser(pivot)) e--; if (e < lo) { // all values were >= pivot if (pivot_idx != lo) Sort_Swap(pivot_idx, lo); return lo; } if (s < e) { Sort_Swap(s, e); s++; e--; continue; } /* NOT NEEDED (it seems) if (s == e && active[s]->IsCloser(pivot)) s++; */ return s - 1; } } void Sort_Range(int s, int e) { SYS_ASSERT(s <= e); while (s < e) { // previously there was a bubble sort here, but timing // tests showed that it was overkill. This is enough. if (s == e-1) { const DrawWall *const A = active[s]; const DrawWall *const B = active[e]; if (B->IsCloser(A)) Sort_Swap(s, e); return; } // since we are usually sorting a mostly-sorted list, the // wall in the middle is highly likely to be a good pivot. int pivot_idx = (s + e) >> 1; int mid = Sort_Partition(s, e, pivot_idx); // handle degenerate cases if (mid <= s) { s++; continue; } else if (mid+1 >= e) { e--; continue; } // only use recursion on the smallest group // [ it helps to limit stack usage ] if ((mid - s) < (e - mid)) { Sort_Range(s, mid); s = mid+1; } else { Sort_Range(mid+1, e); e = mid; } } } void SortActiveList() { // this uses the Quicksort algorithm to sort the active list. // // Note that this sorting code has been written assuming some // limitations of the DrawWall::IsCloser() method -- see the // description of that method for more details. if (active.size() < 2) return; Sort_Range(0, (int)active.size() - 1); } #define IZ_EPSILON 1e-5 void UpdateActiveList(int x) { DrawWall::vec_t::iterator S, E, P; bool changes = false; // remove walls that have finished. S = active.begin(); E = active.end(); S = std::remove_if (S, E, DrawWall::SX2Less(x)); if (S != E) { active.erase(S, E); changes = true; } // add new walls that start in this column. S = walls.begin(); E = walls.end(); S = std::lower_bound(S, E, x, DrawWall::SX1Cmp()); E = std::upper_bound(S, E, x, DrawWall::SX1Cmp()); if (S != E) changes = true; for ( ; S != E ; S++) { active.push_back(*S); } // calculate new depth values S = active.begin(); E = active.end(); for (P=S ; (P != E) ; P++) { DrawWall *dw = (*P); dw->cur_iz = dw->iz1 + dw->diz * (x - dw->sx1); if (P != S && (*(P-1))->cur_iz < dw->cur_iz + IZ_EPSILON) changes = true; } // if there are changes, re-sort the active list... if (changes && active.size() > 0) { SortActiveList(); } } void RenderWalls() { // sort walls by their starting column, to allow binary search. std::sort(walls.begin(), walls.end(), DrawWall::SX1Cmp()); active.clear(); for (int x=0 ; x < inst.r_view.screen_w ; x++) { // clear vertical depth buffer open_y1 = 0; open_y2 = inst.r_view.screen_h - 1; UpdateActiveList(x); // in query mode, only care about a single column if (query_mode && x != query_sx) continue; // render, front to back int activeSize = (int)active.size(); int position; for (position = 0; position < activeSize; ++position) { DrawWall *dw = active[position]; // for things, just remember the open space { dw->oy1 = open_y1; dw->oy2 = open_y2; } if (dw->th >= 0) continue; RenderWallSurface(dw, dw->ceil, x, ObjType::sectors, PART_CEIL); RenderWallSurface(dw, dw->floor, x, ObjType::sectors, PART_FLOOR); RenderWallSurface(dw, dw->upper, x, ObjType::linedefs, PART_RT_UPPER); RenderWallSurface(dw, dw->lower, x, ObjType::linedefs, PART_RT_LOWER); if (open_y1 > open_y2) break; } // now render things, back to front // (mid-masked textures are done here too) if (position == activeSize) position--; for ( ; position >= 0; --position) { DrawWall *dw = active[position]; if (dw->th >= 0) RenderSprite(dw, x); else RenderMidMasker(dw, dw->rail, x); } } } void ClearScreen() { // color #0 is black (DOOM, Heretic, Hexen) // [ other colors won't work here, since img_pixel_t is 16 bits ] byte COLOR = 0; size_t total = static_cast(inst.r_view.screen_w) * inst.r_view.screen_h; memset(inst.r_view.screen, COLOR, total * sizeof(inst.r_view.screen[0])); } void Render() { if (! query_mode) ClearScreen(); InitDepthBuf(inst.r_view.screen_w); for (int i=0 ; i < inst.level.numLinedefs(); i++) AddLine(i); if (inst.r_view.sprites) for (int k=0 ; k < inst.level.numThings() ; k++) AddThing(k); ClipSolids(); ComputeSurfaces(); RenderWalls(); } void Query(int qx, int qy) { query_mode = 1; query_sx = qx; query_sy = qy; query_result.clear(); query_map_x = 0; query_map_y = 0; query_map_z = 0; Render(); query_mode = 0; } }; static void BlitHires(const Instance &inst, int ox, int oy, int ow, int oh) { uint8_t *line_rgb = new uint8_t[inst.r_view.screen_w * 3]; for (int ry = 0 ; ry < inst.r_view.screen_h ; ry++) { uint8_t *dest = line_rgb; uint8_t *dest_end = line_rgb + inst.r_view.screen_w * 3; const img_pixel_t *src = inst.r_view.screen + ry * inst.r_view.screen_w; for ( ; dest < dest_end ; dest += 3, src++) { inst.wad.palette.decodePixel(*src, dest[0], dest[1], dest[2]); } fl_draw_image(line_rgb, ox, oy+ry, inst.r_view.screen_w, 1); } delete[] line_rgb; } static void BlitLores(const Instance &inst, int ox, int oy, int ow, int oh) { // if destination width is odd, we store an extra pixel here uint8_t *line_rgb = new uint8_t[(ow + 1) * 3]; for (int ry = 0 ; ry < inst.r_view.screen_h ; ry++) { const img_pixel_t *src = inst.r_view.screen + ry * inst.r_view.screen_w; uint8_t *dest = line_rgb; uint8_t *dest_end = line_rgb + ow * 3; for (; dest < dest_end ; dest += 6, src++) { inst.wad.palette.decodePixel(*src, dest[0], dest[1], dest[2]); inst.wad.palette.decodePixel(*src, dest[3], dest[4], dest[5]); } fl_draw_image(line_rgb, ox, oy + ry*2, ow, 1); if (ry * 2 + 1 < oh) { fl_draw_image(line_rgb, ox, oy + ry*2 + 1, ow, 1); } } delete[] line_rgb; } void Instance::SW_RenderWorld(int ox, int oy, int ow, int oh) { RendInfo rend(*this); fl_push_clip(ox, oy, ow, oh); rend.Render(); if (config::render_high_detail) BlitHires(*this, ox, oy, ow, oh); else BlitLores(*this, ox, oy, ow, oh); rend.Highlight(ox, oy); fl_pop_clip(); } bool Instance::SW_QueryPoint(Objid& hl, int qx, int qy) { if (! config::render_high_detail) { qx = qx / 2; qy = qy / 2; } RendInfo rend(*this); // this runs the renderer, but *no* drawing is done rend.Query(qx, qy); if (rend.query_map_x != 0) { edit.map.x = rend.query_map_x; edit.map.y = rend.query_map_y; edit.map.z = rend.query_map_z; } if (! rend.query_result.valid()) { // nothing was hit return false; } hl = rend.query_result; return true; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/r_subdiv.cc000066400000000000000000000526511464327712600204650ustar00rootroot00000000000000//------------------------------------------------------------------------ // SECTOR SUBDIVISION //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2020 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include #include "e_basis.h" #include "e_hover.h" #include "LineDef.h" #include "m_game.h" #include "r_subdiv.h" #include "Sector.h" #include "SideDef.h" #include "Thing.h" #include "Vertex.h" /* This file contains code for subdividing map sectors into a set of polygons, and also the logic for caching these subdivisions and rebuilding them whenever necessary. */ void sector_subdivision_c::Clear() { polygons.clear(); } void sector_subdivision_c::AddPolygon(float lx1, float lx2, float low_y, float hx1, float hx2, float high_y) { // determine if low or high are a single vertex bool l_single = fabs(lx2 - lx1) < 0.2; bool h_single = fabs(hx2 - hx1) < 0.2; // skip a degenerate polygon if (l_single && h_single) return; sector_polygon_t poly; poly.count = (l_single || h_single) ? 3 : 4; // add vertices in clockwise order int pos = 0; poly.mx[pos] = lx1; poly.my[pos] = low_y; pos++; poly.mx[pos] = hx1; poly.my[pos] = high_y; pos++; if (! h_single) { poly.mx[pos] = hx2; poly.my[pos] = high_y; pos++; } if (! l_single) { poly.mx[pos] = lx2; poly.my[pos] = low_y; pos++; } polygons.push_back(poly); } // this represents a segment of a linedef bounding a sector. struct sector_edge_t { const LineDef * line; // coordinates of line, possibly flipped. // we always have: y1 <= y2. int x1, y1; int x2, y2; // has the line been flipped (coordinates were swapped) ? short flipped; // what side this edge faces (SIDE_LEFT or SIDE_RIGHT) Side side; // comparison for CMP_X float cmp_x; float CalcX(float y) const { return x1 + (x2 - x1) * (float)(y - y1) / (float)(y2 - y1); } struct CMP_Y { inline bool operator() (const sector_edge_t &A, const sector_edge_t& B) const { // NULL not allowed here return A.y1 < B.y1; } }; struct CMP_X { inline bool operator() (const sector_edge_t *A, const sector_edge_t *B) const { // NULL is always > than a valid pointer if (A == NULL) return false; if (B == NULL) return true; return A->cmp_x < B->cmp_x; } }; }; // // Update // void sector_info_cache_c::Update() { if (total != inst.level.numSectors()) { total = inst.level.numSectors(); infos.resize((size_t) total); Rebuild(); } } void sector_info_cache_c::Rebuild() { int sec; for (sec = 0 ; sec < total ; sec++) { const auto S = inst.level.sectors[sec]; infos[sec].Clear(); infos[sec].floors.f_plane.Init(static_cast(S->floorh)); infos[sec].floors.c_plane.Init(static_cast(S->ceilh)); } for (int n = 0 ; n < inst.level.numLinedefs(); n++) { const auto L = inst.level.linedefs[n]; CheckBoom242(L.get()); CheckExtraFloor(L.get(), n); CheckLineSlope(L.get()); for (int side = 0 ; side < 2 ; side++) { int sd_num = side ? L->left : L->right; if (sd_num < 0) continue; sec = inst.level.sidedefs[sd_num]->sector; sector_extra_info_t& info = infos[sec]; info.AddLine(n); info.AddVertex(&inst.level.getStart(*L)); info.AddVertex(&inst.level.getEnd(*L)); } } for (const auto &thing : inst.level.things) { CheckSlopeThing(thing.get()); } for (const auto &thing : inst.level.things) { CheckSlopeCopyThing(thing.get()); } for (const auto &linedef : inst.level.linedefs) { CheckPlaneCopy(linedef.get()); } } void sector_info_cache_c::CheckBoom242(const LineDef *L) { if (inst.conf.features.gen_types && (L->type == 242 || L->type == 280)) { /* ok */ } else if (inst.loaded.levelFormat != MapFormat::doom && L->type == 209) { /* ok */ } else return; if (L->tag <= 0 || L->right < 0) return; int dummy_sec = inst.level.getRight(*L)->sector; for (int n = 0 ; n < inst.level.numSectors(); n++) { if (inst.level.sectors[n]->tag == L->tag) infos[n].floors.heightsec = dummy_sec; } } void sector_info_cache_c::CheckExtraFloor(const LineDef *L, int ld_num) { if (L->tag <= 0 || L->right < 0) return; int flags = -1; int sec_tag = L->tag; // EDGE style if (inst.loaded.levelFormat == MapFormat::doom && (inst.conf.features.extra_floors & 1)) { switch (L->type) { case 400: flags = 0; break; case 401: flags = EXFL_UPPER; break; case 402: flags = EXFL_LOWER; break; case 403: flags = EXFL_BOTTOM; break; // liquid case 413: flags = EXFL_BOTTOM; break; // thin and solid case 404: case 405: case 406: case 407: case 408: // liquid case 414: case 415: case 416: case 417: // thin and solid flags = EXFL_BOTTOM | EXFL_TRANSLUC; break; default: break; } } // Legacy style if (inst.loaded.levelFormat == MapFormat::doom && (inst.conf.features.extra_floors & 2)) { switch (L->type) { case 281: flags = 0; break; case 289: flags = 0; break; case 300: flags = EXFL_TRANSLUC; break; case 301: flags = EXFL_TOP | EXFL_TRANSLUC; break; case 304: flags = EXFL_TOP; break; case 306: flags = EXFL_TOP | EXFL_TRANSLUC; break; // invisible floor default: break; } } // ZDoom style if (inst.loaded.levelFormat != MapFormat::doom && (inst.conf.features.extra_floors & 4)) { if (L->type != 160) return; flags = 0; if ((L->arg2 & 3) == 0) flags |= EXFL_VAVOOM; if (L->arg3 & 8) flags |= EXFL_TOP; if (L->arg3 & 16) flags |= EXFL_UPPER; if (L->arg3 & 32) flags |= EXFL_LOWER; if ((L->arg2 & 8) == 0) sec_tag |= (L->arg5 << 8); } if (flags < 0) return; extrafloor_c EF; EF.ld = ld_num; EF.sd = L->right; EF.flags = flags; // find all matching sectors for (int n = 0 ; n < inst.level.numSectors(); n++) { if (inst.level.sectors[n]->tag == sec_tag) infos[n].floors.floors.push_back(EF); } } void sector_info_cache_c::CheckLineSlope(const LineDef *L) { // EDGE style if (inst.loaded.levelFormat == MapFormat::doom && (inst.conf.features.slopes & 1)) { switch (L->type) { case 567: PlaneAlign(L, 2, 0); break; case 568: PlaneAlign(L, 0, 2); break; case 569: PlaneAlign(L, 2, 2); break; default: break; } } // Eternity style if (inst.loaded.levelFormat == MapFormat::doom && (inst.conf.features.slopes & 2)) { switch (L->type) { case 386: PlaneAlign(L, 1, 0); break; case 387: PlaneAlign(L, 0, 1); break; case 388: PlaneAlign(L, 1, 1); break; case 389: PlaneAlign(L, 2, 0); break; case 390: PlaneAlign(L, 0, 2); break; case 391: PlaneAlign(L, 2, 2); break; case 392: PlaneAlign(L, 2, 1); break; case 393: PlaneAlign(L, 1, 2); break; default: break; } } // Odamex and ZDoom style if (inst.loaded.levelFormat == MapFormat::doom && (inst.conf.features.slopes & 4)) { switch (L->type) { case 340: PlaneAlign(L, 1, 0); break; case 341: PlaneAlign(L, 0, 1); break; case 342: PlaneAlign(L, 1, 1); break; case 343: PlaneAlign(L, 2, 0); break; case 344: PlaneAlign(L, 0, 2); break; case 345: PlaneAlign(L, 2, 2); break; case 346: PlaneAlign(L, 2, 1); break; case 347: PlaneAlign(L, 1, 2); break; default: break; } } // ZDoom (in hexen format) if (inst.loaded.levelFormat != MapFormat::doom && (inst.conf.features.slopes & 8)) { if (L->type == 181) PlaneAlign(L, L->tag, L->arg2); } } void sector_info_cache_c::CheckPlaneCopy(const LineDef *L) { // Eternity style if (inst.loaded.levelFormat == MapFormat::doom && (inst.conf.features.slopes & 2)) { switch (L->type) { case 394: PlaneCopy(L, L->tag, 0, 0, 0, 0); break; case 395: PlaneCopy(L, 0, L->tag, 0, 0, 0); break; case 396: PlaneCopy(L, L->tag, L->tag, 0, 0, 0); break; default: break; } } // ZDoom (in hexen format) if (inst.loaded.levelFormat != MapFormat::doom && (inst.conf.features.slopes & 8)) { if (L->type == 118) PlaneCopy(L, L->tag, L->arg2, L->arg3, L->arg4, L->arg5); } } void sector_info_cache_c::CheckSlopeThing(const Thing *T) { if (inst.loaded.levelFormat != MapFormat::doom && (inst.conf.features.slopes & 16)) { switch (T->type) { // TODO 1500, 1501 Vavoom style // TODO 1504, 1505 Vertex height (triangle sectors) // TODO 9500, 9501 Line slope things case 9502: PlaneTiltByThing(T, 0); break; case 9503: PlaneTiltByThing(T, 1); break; default: break; } } } void sector_info_cache_c::CheckSlopeCopyThing(const Thing *T) { if (inst.loaded.levelFormat != MapFormat::doom && (inst.conf.features.slopes & 16)) { switch (T->type) { case 9510: PlaneCopyFromThing(T, 0); break; case 9511: PlaneCopyFromThing(T, 1); break; default: break; } } } void sector_info_cache_c::PlaneAlign(const LineDef *L, int floor_mode, int ceil_mode) { if (L->left < 0 || L->right < 0) return; // support undocumented special case from ZDoom if (ceil_mode == 0 && (floor_mode & 0x0C) != 0) ceil_mode = (floor_mode >> 2); switch (floor_mode & 3) { case 1: PlaneAlignPart(L, Side::right, 0 /* floor */); break; case 2: PlaneAlignPart(L, Side::left, 0); break; default: break; } switch (ceil_mode & 3) { case 1: PlaneAlignPart(L, Side::right, 1 /* ceil */); break; case 2: PlaneAlignPart(L, Side::left, 1); break; default: break; } } void sector_info_cache_c::PlaneAlignPart(const LineDef *L, Side side, int plane) { int sec_num = inst.level.getSectorID(*L, side); const auto front = inst.level.sectors[inst.level.getSectorID(*L, side)]; const auto back = inst.level.sectors[inst.level.getSectorID(*L, -side)]; // find a vertex belonging to sector and is far from the line const Vertex *v = NULL; double best_dist = 0.1; double lx1 = inst.level.getStart(*L).x(); double ly1 = inst.level.getStart(*L).y(); double lx2 = inst.level.getEnd(*L).x(); double ly2 = inst.level.getEnd(*L).y(); if (side == Side::left) { std::swap(lx1, lx2); std::swap(ly1, ly2); } for (const auto &L2 : inst.level.linedefs) { if (inst.level.touchesSector(*L2, sec_num)) { for (int pass = 0 ; pass < 2 ; pass++) { const Vertex *v2 = pass ? &inst.level.getEnd(*L2) : &inst.level.getStart(*L2); double dist = PerpDist(v2->xy(), v2double_t{ lx1,ly1 }, v2double_t{ lx2, ly2 }); if (dist > best_dist) { v = v2; best_dist = dist; } } } } if (v == NULL) return; // compute point at 90 degrees to the linedef double ldx = (ly2 - ly1); double ldy = (lx1 - lx2); double ldh = hypot(ldx, ldy); double vx = lx1 + ldx * best_dist / ldh; double vy = ly1 + ldy * best_dist / ldh; if (plane > 0) { // ceiling SlopeFromLine(infos[sec_num].floors.c_plane, lx1, ly1, back->ceilh, vx, vy, front->ceilh); } else { // floor SlopeFromLine(infos[sec_num].floors.f_plane, lx1, ly1, back->floorh, vx, vy, front->floorh); } } void sector_info_cache_c::PlaneCopy(const LineDef *L, int f1_tag, int c1_tag, int f2_tag, int c2_tag, int share) { for (int n = 0 ; n < inst.level.numSectors(); n++) { if (f1_tag > 0 && inst.level.sectors[n]->tag == f1_tag && inst.level.getRight(*L)) { infos[inst.level.getRight(*L)->sector].floors.f_plane.Copy(infos[n].floors.f_plane); f1_tag = 0; } if (c1_tag > 0 && inst.level.sectors[n]->tag == c1_tag && inst.level.getRight(*L)) { infos[inst.level.getRight(*L)->sector].floors.c_plane.Copy(infos[n].floors.c_plane); c1_tag = 0; } if (f2_tag > 0 && inst.level.sectors[n]->tag == f2_tag && inst.level.getLeft(*L)) { infos[inst.level.getLeft(*L)->sector].floors.f_plane.Copy(infos[n].floors.f_plane); f2_tag = 0; } if (c2_tag > 0 && inst.level.sectors[n]->tag == c2_tag && inst.level.getLeft(*L)) { infos[inst.level.getLeft(*L)->sector].floors.c_plane.Copy(infos[n].floors.c_plane); c2_tag = 0; } } if (L->left >= 0 && L->right >= 0) { int front_sec = inst.level.getRight(*L)->sector; int back_sec = inst.level.getLeft(*L)->sector; switch (share & 3) { case 1: infos[ back_sec].floors.f_plane.Copy(infos[front_sec].floors.f_plane); break; case 2: infos[front_sec].floors.f_plane.Copy(infos[ back_sec].floors.f_plane); break; default: break; } switch (share & 12) { case 4: infos[ back_sec].floors.c_plane.Copy(infos[front_sec].floors.c_plane); break; case 8: infos[front_sec].floors.c_plane.Copy(infos[ back_sec].floors.c_plane); break; default: break; } } } void sector_info_cache_c::PlaneCopyFromThing(const Thing *T, int plane) { if (T->arg1 == 0) return; // find sector containing the thing Objid o = hover::getNearestSector(inst.level, T->xy()); if (!o.valid()) return; for (int n = 0 ; n < inst.level.numSectors(); n++) { if (inst.level.sectors[n]->tag == T->arg1) { if (plane > 0) infos[o.num].floors.c_plane.Copy(infos[n].floors.c_plane); else infos[o.num].floors.f_plane.Copy(infos[n].floors.f_plane); return; } } } void sector_info_cache_c::PlaneTiltByThing(const Thing *T, int plane) { double tx = T->x(); double ty = T->y(); // find sector containing the thing Objid o = hover::getNearestSector(inst.level, { tx, ty }); if (!o.valid()) return; sector_3dfloors_c *ex = &infos[o.num].floors; double tz = ex->PlaneZ(plane ? -1 : +1, tx, ty) + T->h(); // vector for direction of thing double tdx = cos(T->angle * M_PI / 180.0); double tdy = sin(T->angle * M_PI / 180.0); // get slope angle. // when arg1 < 90, a point on plane in front of thing has lower Z. int slope_ang = T->arg1 - 90; slope_ang = clamp(-89, slope_ang, 89); double az = sin(slope_ang * M_PI / 180.0); // FIXME support tilting an existing slope #if 1 tdx *= 128.0; tdy *= 128.0; az *= 128.0; if (plane > 0) SlopeFromLine(ex->c_plane, tx,ty,tz, tx+tdx, ty+tdy, tz+az); else SlopeFromLine(ex->f_plane, tx,ty,tz, tx+tdx, ty+tdy, tz+az); #else // get normal of existing plane double nx, ny, nz; if (plane == 0) { ex->f_plane.GetNormal(nx, ny, nz); } else { ex->c_plane.GetNormal(nx, ny, nz); nx = -nx; ny = -ny; nz = -nz; } #endif } void sector_info_cache_c::SlopeFromLine(slope_plane_c& pl, double x1, double y1, double z1, double x2, double y2, double z2) { double dx = x2 - x1; double dy = y2 - y1; double dz = z2 - z1; if (fabs(dz) < 0.5) return; // make (dx dy) be a unit vector double dlen = hypot(dx, dy); dx /= dlen; dy /= dlen; // we want SlopeZ() to compute z1 at (x1 y1) and z2 at (x2 y2). // assume xm = (dx * A) and ym = (dy * A) and zadd = B // that leads to two simultaneous equations: // x1 * dx * A + y1 * dy * A + B = z1 // x2 * dx * A + y2 * dy * A + B = z2 // which we need to solve for A and B.... double E = (x1 * dx + y1 * dy); double F = (x2 * dx + y2 * dy); double A = (z2 -z1) / (F - E); double B = z1 - A * E; pl.xm = static_cast(dx * A); pl.ym = static_cast(dy * A); pl.zadd = static_cast(B); pl.sloped = true; } static void R_SubdivideSector(Instance &inst, int num, sector_extra_info_t& exinfo) { if (exinfo.first_line < 0) return; /* DEBUG fprintf(stderr, "R_SubdivideSector %d\n", num); */ /*** Part 1 : visit linedefs and create edges ***/ std::vector edgelist; for (int n = exinfo.first_line ; n <= exinfo.last_line ; n++) { const auto L = inst.level.linedefs[n]; if (! inst.level.touchesSector(*L, num)) continue; // ignore 2S lines with same sector on both sides if (inst.level.getSectorID(*L, Side::left) == inst.level.getSectorID(*L, Side::right)) continue; sector_edge_t edge; edge.x1 = static_cast(inst.level.getStart(*L).x()); edge.y1 = static_cast(inst.level.getStart(*L).y()); edge.x2 = static_cast(inst.level.getEnd(*L).x()); edge.y2 = static_cast(inst.level.getEnd(*L).y()); // skip purely horizontal lines if (edge.y1 == edge.y2) continue; edge.line = L.get(); edge.flipped = 0; if (edge.y1 > edge.y2) { std::swap(edge.x1, edge.x2); std::swap(edge.y1, edge.y2); edge.flipped = 1; } // compute side bool is_right = (inst.level.getSectorID(*L, Side::right) == num); if (edge.flipped) is_right = !is_right; edge.side = is_right ? Side::right : Side::left; /* DEBUG fprintf(stderr, "Line %d mapped coords (%d %d) .. (%d %d) flipped:%d sec:%d/%d\n", n, edge.x1, edge.y1, edge.x2, edge.y2, edge.flipped, L->WhatSector(SIDE_RIGHT), L->WhatSector(SIDE_LEFT)); */ // add the edge edgelist.push_back(edge); } if (edgelist.empty()) return; // sort edges into vertical order (using 'y1' field) std::sort(edgelist.begin(), edgelist.end(), sector_edge_t::CMP_Y()); /*** Part 2 : traverse edge list and create trapezoids ***/ std::vector active_edges; if (edgelist.empty()) return; unsigned int pos = 0; // this Y is minimal (guaranteed by sorting the edgelist) int low_y = edgelist[pos].y1; for (;;) { // remove old edges from active list for (unsigned int i = 0 ; i < active_edges.size() ; i++) { sector_edge_t *A = active_edges[i]; if (A != NULL && A->y2 <= low_y) active_edges[i] = NULL; } // add new edges to active list for ( ; pos < edgelist.size() && edgelist[pos].y1 == low_y ; pos++) { active_edges.push_back(&edgelist[pos]); } // find next highest Y int high_y = (1 << 30); int active_num = 0; if (pos < edgelist.size()) high_y = edgelist[pos].y1; for (unsigned int k = 0 ; k < active_edges.size() ; k++) { sector_edge_t *A = active_edges[k]; if (A != NULL) { active_num++; if (A->y1 > low_y) high_y = std::min(high_y, A->y1); if (A->y2 > low_y) high_y = std::min(high_y, A->y2); } } /* DEBUG fprintf(stderr, " active_num:%d low_y:%d high_y:%d\n", active_num, low_y, high_y); */ if (active_num == 0) { while (pos < edgelist.size() && edgelist[pos].y1 <= low_y) pos++; // terminating condition : no more rows if (pos >= edgelist.size()) break; low_y = edgelist[pos].y1; continue; } // compute a comparison X coordinate for each active edge float mid_y = low_y + (high_y - low_y) * 0.5f; for (unsigned int k = 0 ; k < active_edges.size() ; k++) { sector_edge_t *A = active_edges[k]; if (A != NULL) A->cmp_x = A->CalcX(mid_y); } // sort edges horizontally std::sort(active_edges.begin(), active_edges.end(), sector_edge_t::CMP_X()); // remove NULLs while (active_edges.size() > 0 && active_edges.back() == NULL) active_edges.pop_back(); // visit pairs of edges for (unsigned int i = 1 ; i < active_edges.size() ; i++) { const sector_edge_t * E1 = active_edges[i - 1]; const sector_edge_t * E2 = active_edges[i]; #if 1 if (E1 == NULL || E2 == NULL) BugError("RenderSector: did not delete NULLs properly!\n"); #endif /* DEBUG fprintf(stderr, "E1 @ x=%1.2f side=%d | E2 @ x=%1.2f side=%d\n", E1->cmp_x, E1->side, E2->cmp_x, E2->side); */ if (! (E1->side == Side::right && E2->side == Side::left)) continue; // treat lines without a right side as dead // [ NOTE that we don't ignore them ] if (E1->line->right < 0) continue; if (E2->line->right < 0) continue; float lx1 = static_cast(E1->CalcX(static_cast(low_y))); float hx1 = static_cast(E1->CalcX(static_cast(high_y))); float lx2 = static_cast(E2->CalcX(static_cast(low_y))); float hx2 = static_cast(E2->CalcX(static_cast(high_y))); exinfo.sub.AddPolygon(lx1, lx2, static_cast(low_y), hx1, hx2, static_cast(high_y)); } // ok, repeat process for next row low_y = high_y; } } void Instance::Subdiv_InvalidateAll() noexcept { // invalidate everything sector_info_cache.total = -1; } bool Instance::Subdiv_SectorOnScreen(int num, double map_lx, double map_ly, double map_hx, double map_hy) { sector_info_cache.Update(); sector_extra_info_t& exinfo = sector_info_cache.infos[num]; if (exinfo.bound_x1 > map_hx || exinfo.bound_x2 < map_lx || exinfo.bound_y1 > map_hy || exinfo.bound_y2 < map_ly) { // sector is off-screen return false; } return true; } sector_subdivision_c *Instance::Subdiv_PolygonsForSector(int num) { sector_info_cache.Update(); sector_extra_info_t& exinfo = sector_info_cache.infos[num]; if (! exinfo.built) { R_SubdivideSector(*this, num, exinfo); exinfo.built = true; } return &exinfo.sub; } void sector_extra_info_t::AddVertex(const Vertex *V) { bound_x1 = std::min(bound_x1, V->x()); bound_y1 = std::min(bound_y1, V->y()); bound_x2 = std::max(bound_x2, V->x()); bound_y2 = std::max(bound_y2, V->y()); } //------------------------------------------------------------------------ // 3D Floor and Slope stuff //------------------------------------------------------------------------ void sector_3dfloors_c::Clear() { heightsec = -1; floors.clear(); f_plane.Init(-2); c_plane.Init(-1); } void slope_plane_c::Init(float height) { sloped = false; xm = ym = 0; zadd = height; } void slope_plane_c::Copy(const slope_plane_c& other) { sloped = other.sloped; xm = other.xm; ym = other.ym; zadd = other.zadd; } sector_3dfloors_c *Instance::Subdiv_3DFloorsForSector(int num) { sector_info_cache.Update(); sector_extra_info_t& exinfo = sector_info_cache.infos[num]; return &exinfo.floors; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/r_subdiv.h000066400000000000000000000116631464327712600203250ustar00rootroot00000000000000//------------------------------------------------------------------------ // SECTOR SUBDIVISION //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2008-2019 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_R_SUBDIV_H__ #define __EUREKA_R_SUBDIV_H__ struct sector_polygon_t { // number of sides, either 3 or 4 int count; // the map coordinates. // // NOTE: this shape is actually a trapezoid where the top and // bottom are always purely horizontal, only the sides // can be sloped. the software renderer relies on this. float mx[4]; float my[4]; }; class sector_subdivision_c { public: std::vector polygons; public: void Clear(); void AddPolygon(float lx1, float lx2, float low_y, float hx1, float hx2, float high_y); }; sector_subdivision_c *Subdiv_PolygonsForSector(Instance &inst, int num); class extrafloor_c { public: int ld = -1; // linedef in the dummy sector int sd = -1; // first sidedef of that line int flags = 0; // bitmask of EXFL_XXX values }; // vavoom style, dummy sector has floorh > ceilh #define EXFL_VAVOOM (1 << 0) // only draw a single surface (the ceiling of dummy sector) #define EXFL_TOP (1 << 1) // only draw a single surface (the floor of dummy sector) #define EXFL_BOTTOM (1 << 2) // side texture is from upper on sidedef (not middle tex) #define EXFL_UPPER (1 << 3) // side texture is from lower on sidedef (not middle tex) #define EXFL_LOWER (1 << 4) // the 3D floor is translucent #define EXFL_TRANSLUC (1 << 5) class slope_plane_c { public: bool sloped = false; // if false, no slope is active float xm = 0, ym = 0, zadd = 0; public: void Init(float height); void Copy(const slope_plane_c& other); inline double SlopeZ(double x, double y) const { return (x * xm) + (y * ym) + zadd; } void GetNormal(double& nx, double& ny, double& nz) const; }; class sector_3dfloors_c { public: // this is -1 or a sector number of a BOOM 242 dummy sector int heightsec = -1; std::vector< extrafloor_c > floors; slope_plane_c f_plane; slope_plane_c c_plane; public: void Clear(); inline double FloorZ(double x, double y) const { return f_plane.SlopeZ(x, y); } inline double CeilZ(double x, double y) const { return c_plane.SlopeZ(x, y); } inline double PlaneZ(int znormal, double x, double y) const { if (znormal > 0) return f_plane.SlopeZ(x, y); else return c_plane.SlopeZ(x, y); } }; struct sector_extra_info_t { // these are < 0 when the sector has no lines int first_line; int last_line; // these are random junk when sector has no lines double bound_x1, bound_x2; double bound_y1, bound_y2; sector_subdivision_c sub; sector_3dfloors_c floors; // true when polygons have been built for this sector. bool built; void Clear() { first_line = last_line = -1; bound_x1 = 32767; bound_y1 = 32767; bound_x2 = -32767; bound_y2 = -32767; sub.Clear(); floors.Clear(); built = false; } void AddLine(int n) { if (first_line < 0 || first_line > n) first_line = n; if (last_line < n) last_line = n; } void AddVertex(const Vertex *V); }; // // Sector info cache // class sector_info_cache_c { public: int total = -1; std::vector infos; public: explicit sector_info_cache_c(const Instance &inst) : inst(inst) { } sector_info_cache_c(const sector_info_cache_c &other) = default; sector_info_cache_c &operator = (const sector_info_cache_c &other) { total = other.total; infos = other.infos; return *this; } public: void Update(); private: void Rebuild(); void CheckBoom242(const LineDef *L); void CheckExtraFloor(const LineDef *L, int ld_num); void CheckLineSlope(const LineDef *L); void CheckPlaneCopy(const LineDef *L); void CheckSlopeThing(const Thing *T); void CheckSlopeCopyThing(const Thing *T); void PlaneAlign(const LineDef *L, int floor_mode, int ceil_mode); void PlaneAlignPart(const LineDef *L, Side side, int plane); void PlaneCopy(const LineDef *L, int f1_tag, int c1_tag, int f2_tag, int c2_tag, int share); void PlaneCopyFromThing(const Thing *T, int plane); void PlaneTiltByThing(const Thing *T, int plane); void SlopeFromLine(slope_plane_c& pl, double x1, double y1, double z1, double x2, double y2, double z2); const Instance &inst; }; #endif /* __EUREKA_R_SUBDIV_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/sys_debug.cc000066400000000000000000000072171464327712600206320ustar00rootroot00000000000000//------------------------------------------------------------------------ // Debugging support //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2013 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include "m_strings.h" #include "sys_debug.h" #include #include #include bool global::Quiet = false; bool global::Debugging = false; bool global::in_fatal_error; // FIXME: make this a local entity passed to interested parties Log gLog; // hack here to avoid bringing in ui_window.h and FLTK headers extern void LogViewer_AddLine(const char *str); // // Open a file // bool Log::openFile(const fs::path &filename) { log_fp = fopen(filename.u8string().c_str(), "w+"); if (! log_fp) return false; fprintf(log_fp, "======= START OF LOGS =======\n\n"); // add all messages saved so far for (const SString &message : kept_messages) fputs(message.c_str(), log_fp); return true; } // // Open a window // void Log::openWindow() { log_window_open = true; // retrieve all messages saved so far if(windowAdd) for (const SString &message : kept_messages) windowAdd(message, windowAddUserData); } void Log::openWindow(WindowAddCallback callback, void *userData) { setWindowAddCallback(callback, userData); openWindow(); } // // Close the file // void Log::close() { if (log_fp) { fprintf(log_fp, "\n\n======== END OF LOGS ========\n"); fclose(log_fp); log_fp = nullptr; } log_window_open = false; kept_messages.clear(); } // // Printf to log // void Log::printf(EUR_FORMAT_STRING(const char *str), ...) { va_list args; va_start(args, str); SString buffer = SString::vprintf(str, args); va_end(args); if (log_fp) { fputs(buffer.c_str(), log_fp); fflush(log_fp); } if (windowAdd && log_window_open && !inFatalError) windowAdd(buffer, windowAddUserData); kept_messages.push_back(buffer); if (! global::Quiet) { fputs(buffer.c_str(), stdout); fflush(stdout); } } // // Debug printf // void Log::debugPrintf(EUR_FORMAT_STRING(const char *str), ...) { if (global::Debugging && log_fp) { va_list args; va_start(args, str); SString buffer = SString::vprintf(str, args); va_end(args); // prefix each debugging line with a special symbol size_t index = 0; size_t startpos = 0; while(index < buffer.length()) { index = buffer.find('\n', startpos); if(index == SString::npos) index = buffer.length(); if(index == buffer.length() && startpos == index) break; SString fragment(buffer.c_str() + startpos, static_cast(index - startpos)); fprintf(log_fp, "# %s\n", fragment.c_str()); fflush(log_fp); if (! global::Quiet) fprintf(stderr, "# %s\n", fragment.c_str()); startpos = index + 1; } } } // // Save the log so far to another file // void Log::saveTo(std::ostream &os) const { os << "======= START OF LOGS =======\n\n"; // add all messages saved so far for (const SString &message : kept_messages) os << message; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/sys_debug.h000066400000000000000000000053421464327712600204710ustar00rootroot00000000000000//------------------------------------------------------------------------ // Debugging support //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2013 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __SYS_DEBUG_H__ #define __SYS_DEBUG_H__ #include "filesystem.hpp" namespace fs = ghc::filesystem; #include "WindowsSanitization.h" #include #include "PrintfMacros.h" #include #include #define MSG_BUF_LEN 1024 class SString; namespace global { extern bool Quiet; extern bool Debugging; extern bool in_fatal_error; } // // Log controller // class Log { public: typedef void (*WindowAddCallback)(const SString &text, void *userData); bool openFile(const fs::path &filename); void openWindow(); void openWindow(WindowAddCallback callback, void *userData); void close(); void printf(EUR_FORMAT_STRING(const char *str), ...) EUR_PRINTF(2, 3); void debugPrintf(EUR_FORMAT_STRING(const char *str), ...) EUR_PRINTF(2, 3); void saveTo(std::ostream &os) const; // // Mark the error // void markFatalError() { inFatalError = true; } private: // // Callback setter // void setWindowAddCallback(WindowAddCallback callback, void *userData) { windowAdd = callback; windowAddUserData = userData; } WindowAddCallback windowAdd = nullptr; void *windowAddUserData = nullptr; bool inFatalError = false; bool log_window_open = false; FILE *log_fp = nullptr; std::vector kept_messages; }; extern Log gLog; // -------- assertion macros -------- #ifdef NDEBUG #define SYS_ASSERT(cond) ((void) 0) #elif defined(__GNUC__) #define SYS_ASSERT(cond) ((cond) ? (void)0 : \ BugError("Assertion (%s) failed\nIn function %s (%s:%d)\n", #cond , __func__, __FILE__, __LINE__)) #else #define SYS_ASSERT(cond) ((cond) ? (void)0 : \ BugError("Assertion (%s) failed\nIn file %s:%d\n", #cond , __FILE__, __LINE__)) #endif // NDEBUG #define SYS_NULL_CHECK(ptr) SYS_ASSERT((ptr) != NULL) #define SYS_ZERO_CHECK(value) SYS_ASSERT((value) != 0) #endif /* __SYS_DEBUG_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/sys_endian.h000066400000000000000000000073071464327712600206440ustar00rootroot00000000000000//------------------------------------------------------------------------ // EDGE Endian handling //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2008 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Using code from SDL_byteorder.h and SDL_endian.h. // Copyright (C) 1997-2004 Sam Lantinga. // //------------------------------------------------------------------------ #ifndef __SYS_ENDIAN_H__ #define __SYS_ENDIAN_H__ // ---- determine byte order ---- #define UT_LIL_ENDIAN 1234 #define UT_BIG_ENDIAN 4321 #if defined(__LITTLE_ENDIAN__) || defined(WIN32) || \ defined(__i386__) || defined(__i386) || \ defined(__ia64__) || defined(__x86_64__) || \ defined(__alpha__) || defined(__alpha) || \ defined(__arm__) || defined(__SYMBIAN32__) || \ (defined(__mips__) && defined(__MIPSEL__)) #define UT_BYTEORDER UT_LIL_ENDIAN #else #define UT_BYTEORDER UT_BIG_ENDIAN #endif // ---- the gruntwork of swapping ---- #if defined(__GNUC__) && defined(__i386__) static inline uint16_t UT_Swap16(uint16_t x) { __asm__("xchgb %b0,%h0" : "=q" (x) : "0" (x)); return x; } #elif defined(__GNUC__) && defined(__x86_64__) static inline uint16_t UT_Swap16(uint16_t x) { __asm__("xchgb %b0,%h0" : "=Q" (x) : "0" (x)); return x; } #elif defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__)) static inline uint16_t UT_Swap16(uint16_t x) { uint16_t result; __asm__("rlwimi %0,%2,8,16,23" : "=&r" (result) : "0" (x >> 8), "r" (x)); return result; } #else static inline uint16_t UT_Swap16(uint16_t x) { return(uint16_t)((x<<8)|(x>>8)); } #endif #if defined(__GNUC__) && defined(__i386__) static inline uint32_t UT_Swap32(uint32_t x) { __asm__("bswap %0" : "=r" (x) : "0" (x)); return x; } #elif defined(__GNUC__) && defined(__x86_64__) static inline uint32_t UT_Swap32(uint32_t x) { __asm__("bswapl %0" : "=r" (x) : "0" (x)); return x; } #elif defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__)) static inline uint32_t UT_Swap32(uint32_t x) { uint32_t result; __asm__("rlwimi %0,%2,24,16,23" : "=&r" (result) : "0" (x>>24), "r" (x)); __asm__("rlwimi %0,%2,8,8,15" : "=&r" (result) : "0" (result), "r" (x)); __asm__("rlwimi %0,%2,24,0,7" : "=&r" (result) : "0" (result), "r" (x)); return result; } #else static inline uint32_t UT_Swap32(uint32_t x) { return ((x<<24)|((x<<8)&0x00FF0000)|((x>>8)&0x0000FF00)|(x>>24)); } #endif // ---- byte swap from specified endianness to native ---- #if (UT_BYTEORDER == UT_LIL_ENDIAN) #define LE_U16(X) ((uint16_t)(X)) #define LE_U32(X) ((uint32_t)(X)) #define BE_U16(X) UT_Swap16(X) #define BE_U32(X) UT_Swap32(X) #else #define LE_U16(X) UT_Swap16(X) #define LE_U32(X) UT_Swap32(X) #define BE_U16(X) ((uint16_t)(X)) #define BE_U32(X) ((uint32_t)(X)) #endif // signed versions of the above #define LE_S16(X) ((int16_t) LE_U16((uint16_t) (X))) #define LE_S32(X) ((int32_t) LE_U32((uint32_t) (X))) #define BE_S16(X) ((int16_t) BE_U16((uint16_t) (X))) #define BE_S32(X) ((int32_t) BE_U32((uint32_t) (X))) #endif // __SYS_ENDIAN_H__ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/sys_macro.h000066400000000000000000000036241464327712600205050ustar00rootroot00000000000000//------------------------------------------------------------------------ // Macros //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2008 Andrew Apted // Copyright (C) 2005 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __SYS_MACRO_H__ #define __SYS_MACRO_H__ #include // basic macros #ifndef M_PI #define M_PI 3.14159265358979323846 #endif // // Concise round() cast to int // inline static int iround(double x) { return static_cast(round(x)); } inline static int iround(float x) { return static_cast(roundf(x)); } template inline static T clamp(const T &low, const T &x, const T &high) { return x < low ? low : x > high ? high : x; } // // The packed attribute forces structures to be packed into the minimum // space necessary. If this is not done, the compiler may align structure // fields differently to optimize memory access, inflating the overall // structure size. It is important to use the packed attribute on certain // structures where alignment is important, particularly data read/written // to disk. // #ifdef __GNUC__ #define PACKEDATTR __attribute__((packed)) #else #define PACKEDATTR #endif #define lengthof(x) (sizeof(x) / sizeof(*(x))) #endif /* __SYS_MACRO_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/sys_type.h000066400000000000000000000017571464327712600203720ustar00rootroot00000000000000//------------------------------------------------------------------------ // Type definitions //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2008 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __SYS_TYPE_H__ #define __SYS_TYPE_H__ #include typedef uint8_t byte; #endif /* __SYS_TYPE_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/tl/000077500000000000000000000000001464327712600167475ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/src/tl/optional.hpp000066400000000000000000002175601464327712600213200ustar00rootroot00000000000000 /// // optional - An implementation of std::optional with extensions // Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama) // // Documentation available at https://tl.tartanllama.xyz/ // // To the extent possible under law, the author(s) have dedicated all // copyright and related and neighboring rights to this software to the // public domain worldwide. This software is distributed without any warranty. // // You should have received a copy of the CC0 Public Domain Dedication // along with this software. If not, see // . /// #ifndef TL_OPTIONAL_HPP #define TL_OPTIONAL_HPP #define TL_OPTIONAL_VERSION_MAJOR 1 #define TL_OPTIONAL_VERSION_MINOR 1 #define TL_OPTIONAL_VERSION_PATCH 0 #include #include #include #include #include #if (defined(_MSC_VER) && _MSC_VER == 1900) #define TL_OPTIONAL_MSVC2015 #endif #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ !defined(__clang__)) #define TL_OPTIONAL_GCC49 #endif #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \ !defined(__clang__)) #define TL_OPTIONAL_GCC54 #endif #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \ !defined(__clang__)) #define TL_OPTIONAL_GCC55 #endif #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ !defined(__clang__)) // GCC < 5 doesn't support overloading on const&& for member functions #define TL_OPTIONAL_NO_CONSTRR // GCC < 5 doesn't support some standard C++11 type traits #define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ std::has_trivial_copy_constructor::value #define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::has_trivial_copy_assign::value // This one will be different for GCC 5.7 if it's ever supported #define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible::value // GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks std::vector // for non-copyable types #elif (defined(__GNUC__) && __GNUC__ < 8 && \ !defined(__clang__)) #ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX #define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX namespace tl { namespace detail { template struct is_trivially_copy_constructible : std::is_trivially_copy_constructible{}; #ifdef _GLIBCXX_VECTOR template struct is_trivially_copy_constructible> : std::is_trivially_copy_constructible{}; #endif } } #endif #define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ tl::detail::is_trivially_copy_constructible::value #define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ std::is_trivially_copy_assignable::value #define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible::value #else #define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ std::is_trivially_copy_constructible::value #define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ std::is_trivially_copy_assignable::value #define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible::value #endif #if __cplusplus > 201103L #define TL_OPTIONAL_CXX14 #endif // constexpr implies const in C++11, not C++14 #if (__cplusplus == 201103L || defined(TL_OPTIONAL_MSVC2015) || \ defined(TL_OPTIONAL_GCC49)) #define TL_OPTIONAL_11_CONSTEXPR #else #define TL_OPTIONAL_11_CONSTEXPR constexpr #endif namespace tl { #ifndef TL_MONOSTATE_INPLACE_MUTEX #define TL_MONOSTATE_INPLACE_MUTEX /// Used to represent an optional with no data; essentially a bool class monostate {}; /// A tag type to tell optional to construct its value in-place struct in_place_t { explicit in_place_t() = default; }; /// A tag to tell optional to construct its value in-place static constexpr in_place_t in_place{}; #endif template class optional; namespace detail { #ifndef TL_TRAITS_MUTEX #define TL_TRAITS_MUTEX // C++14-style aliases for brevity template using remove_const_t = typename std::remove_const::type; template using remove_reference_t = typename std::remove_reference::type; template using decay_t = typename std::decay::type; template using enable_if_t = typename std::enable_if::type; template using conditional_t = typename std::conditional::type; // std::conjunction from C++17 template struct conjunction : std::true_type {}; template struct conjunction : B {}; template struct conjunction : std::conditional, B>::type {}; #if defined(_LIBCPP_VERSION) && __cplusplus == 201103L #define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND #endif // In C++11 mode, there's an issue in libc++'s std::mem_fn // which results in a hard-error when using it in a noexcept expression // in some cases. This is a check to workaround the common failing case. #ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND template struct is_pointer_to_non_const_member_func : std::false_type{}; template struct is_pointer_to_non_const_member_func : std::true_type{}; template struct is_pointer_to_non_const_member_func : std::true_type{}; template struct is_pointer_to_non_const_member_func : std::true_type{}; template struct is_pointer_to_non_const_member_func : std::true_type{}; template struct is_pointer_to_non_const_member_func : std::true_type{}; template struct is_pointer_to_non_const_member_func : std::true_type{}; template struct is_const_or_const_ref : std::false_type{}; template struct is_const_or_const_ref : std::true_type{}; template struct is_const_or_const_ref : std::true_type{}; #endif // std::invoke from C++17 // https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround template ::value && is_const_or_const_ref::value)>, #endif typename = enable_if_t>::value>, int = 0> constexpr auto invoke(Fn &&f, Args &&... args) noexcept( noexcept(std::mem_fn(f)(std::forward(args)...))) -> decltype(std::mem_fn(f)(std::forward(args)...)) { return std::mem_fn(f)(std::forward(args)...); } template >::value>> constexpr auto invoke(Fn &&f, Args &&... args) noexcept( noexcept(std::forward(f)(std::forward(args)...))) -> decltype(std::forward(f)(std::forward(args)...)) { return std::forward(f)(std::forward(args)...); } // std::invoke_result from C++17 template struct invoke_result_impl; template struct invoke_result_impl< F, decltype(detail::invoke(std::declval(), std::declval()...), void()), Us...> { using type = decltype(detail::invoke(std::declval(), std::declval()...)); }; template using invoke_result = invoke_result_impl; template using invoke_result_t = typename invoke_result::type; #if defined(_MSC_VER) && _MSC_VER <= 1900 // TODO make a version which works with MSVC 2015 template struct is_swappable : std::true_type {}; template struct is_nothrow_swappable : std::true_type {}; #else // https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept namespace swap_adl_tests { // if swap ADL finds this then it would call std::swap otherwise (same // signature) struct tag {}; template tag swap(T &, T &); template tag swap(T (&a)[N], T (&b)[N]); // helper functions to test if an unqualified swap is possible, and if it // becomes std::swap template std::false_type can_swap(...) noexcept(false); template (), std::declval()))> std::true_type can_swap(int) noexcept(noexcept(swap(std::declval(), std::declval()))); template std::false_type uses_std(...); template std::is_same(), std::declval())), tag> uses_std(int); template struct is_std_swap_noexcept : std::integral_constant::value && std::is_nothrow_move_assignable::value> {}; template struct is_std_swap_noexcept : is_std_swap_noexcept {}; template struct is_adl_swap_noexcept : std::integral_constant(0))> {}; } // namespace swap_adl_tests template struct is_swappable : std::integral_constant< bool, decltype(detail::swap_adl_tests::can_swap(0))::value && (!decltype(detail::swap_adl_tests::uses_std(0))::value || (std::is_move_assignable::value && std::is_move_constructible::value))> {}; template struct is_swappable : std::integral_constant< bool, decltype(detail::swap_adl_tests::can_swap(0))::value && (!decltype( detail::swap_adl_tests::uses_std(0))::value || is_swappable::value)> {}; template struct is_nothrow_swappable : std::integral_constant< bool, is_swappable::value && ((decltype(detail::swap_adl_tests::uses_std(0))::value &&detail::swap_adl_tests::is_std_swap_noexcept::value) || (!decltype(detail::swap_adl_tests::uses_std(0))::value && detail::swap_adl_tests::is_adl_swap_noexcept::value))> { }; #endif #endif // std::void_t from C++17 template struct voider { using type = void; }; template using void_t = typename voider::type; // Trait for checking if a type is a tl::optional template struct is_optional_impl : std::false_type {}; template struct is_optional_impl> : std::true_type {}; template using is_optional = is_optional_impl>; // Change void to tl::monostate template using fixup_void = conditional_t::value, monostate, U>; template > using get_map_return = optional>>; // Check if invoking F for some Us returns void template struct returns_void_impl; template struct returns_void_impl>, U...> : std::is_void> {}; template using returns_void = returns_void_impl; template using enable_if_ret_void = enable_if_t::value>; template using disable_if_ret_void = enable_if_t::value>; template using enable_forward_value = detail::enable_if_t::value && !std::is_same, in_place_t>::value && !std::is_same, detail::decay_t>::value>; template using enable_from_other = detail::enable_if_t< std::is_constructible::value && !std::is_constructible &>::value && !std::is_constructible &&>::value && !std::is_constructible &>::value && !std::is_constructible &&>::value && !std::is_convertible &, T>::value && !std::is_convertible &&, T>::value && !std::is_convertible &, T>::value && !std::is_convertible &&, T>::value>; template using enable_assign_forward = detail::enable_if_t< !std::is_same, detail::decay_t>::value && !detail::conjunction, std::is_same>>::value && std::is_constructible::value && std::is_assignable::value>; template using enable_assign_from_other = detail::enable_if_t< std::is_constructible::value && std::is_assignable::value && !std::is_constructible &>::value && !std::is_constructible &&>::value && !std::is_constructible &>::value && !std::is_constructible &&>::value && !std::is_convertible &, T>::value && !std::is_convertible &&, T>::value && !std::is_convertible &, T>::value && !std::is_convertible &&, T>::value && !std::is_assignable &>::value && !std::is_assignable &&>::value && !std::is_assignable &>::value && !std::is_assignable &&>::value>; // The storage base manages the actual storage, and correctly propagates // trivial destruction from T. This case is for when T is not trivially // destructible. template ::value> struct optional_storage_base { TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept : m_dummy(), m_has_value(false) {} template TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u) : m_value(std::forward(u)...), m_has_value(true) {} ~optional_storage_base() { if (m_has_value) { m_value.~T(); m_has_value = false; } } struct dummy {}; union { dummy m_dummy; T m_value; }; bool m_has_value; }; // This case is for when T is trivially destructible. template struct optional_storage_base { TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept : m_dummy(), m_has_value(false) {} template TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u) : m_value(std::forward(u)...), m_has_value(true) {} // No destructor, so this class is trivially destructible struct dummy {}; union { dummy m_dummy; T m_value; }; bool m_has_value = false; }; // This base class provides some handy member functions which can be used in // further derived classes template struct optional_operations_base : optional_storage_base { using optional_storage_base::optional_storage_base; void hard_reset() noexcept { get().~T(); this->m_has_value = false; } template void construct(Args &&... args) { new (std::addressof(this->m_value)) T(std::forward(args)...); this->m_has_value = true; } template void assign(Opt &&rhs) { if (this->has_value()) { if (rhs.has_value()) { this->m_value = std::forward(rhs).get(); } else { this->m_value.~T(); this->m_has_value = false; } } else if (rhs.has_value()) { construct(std::forward(rhs).get()); } } bool has_value() const { return this->m_has_value; } TL_OPTIONAL_11_CONSTEXPR T &get() & { return this->m_value; } TL_OPTIONAL_11_CONSTEXPR const T &get() const & { return this->m_value; } TL_OPTIONAL_11_CONSTEXPR T &&get() && { return std::move(this->m_value); } #ifndef TL_OPTIONAL_NO_CONSTRR constexpr const T &&get() const && { return std::move(this->m_value); } #endif }; // This class manages conditionally having a trivial copy constructor // This specialization is for when T is trivially copy constructible template struct optional_copy_base : optional_operations_base { using optional_operations_base::optional_operations_base; }; // This specialization is for when T is not trivially copy constructible template struct optional_copy_base : optional_operations_base { using optional_operations_base::optional_operations_base; optional_copy_base() = default; optional_copy_base(const optional_copy_base &rhs) : optional_operations_base() { if (rhs.has_value()) { this->construct(rhs.get()); } else { this->m_has_value = false; } } optional_copy_base(optional_copy_base &&rhs) = default; optional_copy_base &operator=(const optional_copy_base &rhs) = default; optional_copy_base &operator=(optional_copy_base &&rhs) = default; }; // This class manages conditionally having a trivial move constructor // Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it // doesn't implement an analogue to std::is_trivially_move_constructible. We // have to make do with a non-trivial move constructor even if T is trivially // move constructible #ifndef TL_OPTIONAL_GCC49 template ::value> struct optional_move_base : optional_copy_base { using optional_copy_base::optional_copy_base; }; #else template struct optional_move_base; #endif template struct optional_move_base : optional_copy_base { using optional_copy_base::optional_copy_base; optional_move_base() = default; optional_move_base(const optional_move_base &rhs) = default; optional_move_base(optional_move_base &&rhs) noexcept( std::is_nothrow_move_constructible::value) { if (rhs.has_value()) { this->construct(std::move(rhs.get())); } else { this->m_has_value = false; } } optional_move_base &operator=(const optional_move_base &rhs) = default; optional_move_base &operator=(optional_move_base &&rhs) = default; }; // This class manages conditionally having a trivial copy assignment operator template struct optional_copy_assign_base : optional_move_base { using optional_move_base::optional_move_base; }; template struct optional_copy_assign_base : optional_move_base { using optional_move_base::optional_move_base; optional_copy_assign_base() = default; optional_copy_assign_base(const optional_copy_assign_base &rhs) = default; optional_copy_assign_base(optional_copy_assign_base &&rhs) = default; optional_copy_assign_base &operator=(const optional_copy_assign_base &rhs) { this->assign(rhs); return *this; } optional_copy_assign_base & operator=(optional_copy_assign_base &&rhs) = default; }; // This class manages conditionally having a trivial move assignment operator // Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it // doesn't implement an analogue to std::is_trivially_move_assignable. We have // to make do with a non-trivial move assignment operator even if T is trivially // move assignable #ifndef TL_OPTIONAL_GCC49 template ::value &&std::is_trivially_move_constructible::value &&std::is_trivially_move_assignable::value> struct optional_move_assign_base : optional_copy_assign_base { using optional_copy_assign_base::optional_copy_assign_base; }; #else template struct optional_move_assign_base; #endif template struct optional_move_assign_base : optional_copy_assign_base { using optional_copy_assign_base::optional_copy_assign_base; optional_move_assign_base() = default; optional_move_assign_base(const optional_move_assign_base &rhs) = default; optional_move_assign_base(optional_move_assign_base &&rhs) = default; optional_move_assign_base & operator=(const optional_move_assign_base &rhs) = default; optional_move_assign_base & operator=(optional_move_assign_base &&rhs) noexcept( std::is_nothrow_move_constructible::value &&std::is_nothrow_move_assignable::value) { this->assign(std::move(rhs)); return *this; } }; // optional_delete_ctor_base will conditionally delete copy and move // constructors depending on whether T is copy/move constructible template ::value, bool EnableMove = std::is_move_constructible::value> struct optional_delete_ctor_base { optional_delete_ctor_base() = default; optional_delete_ctor_base(const optional_delete_ctor_base &) = default; optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = default; optional_delete_ctor_base & operator=(const optional_delete_ctor_base &) = default; optional_delete_ctor_base & operator=(optional_delete_ctor_base &&) noexcept = default; }; template struct optional_delete_ctor_base { optional_delete_ctor_base() = default; optional_delete_ctor_base(const optional_delete_ctor_base &) = default; optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = delete; optional_delete_ctor_base & operator=(const optional_delete_ctor_base &) = default; optional_delete_ctor_base & operator=(optional_delete_ctor_base &&) noexcept = default; }; template struct optional_delete_ctor_base { optional_delete_ctor_base() = default; optional_delete_ctor_base(const optional_delete_ctor_base &) = delete; optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = default; optional_delete_ctor_base & operator=(const optional_delete_ctor_base &) = default; optional_delete_ctor_base & operator=(optional_delete_ctor_base &&) noexcept = default; }; template struct optional_delete_ctor_base { optional_delete_ctor_base() = default; optional_delete_ctor_base(const optional_delete_ctor_base &) = delete; optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = delete; optional_delete_ctor_base & operator=(const optional_delete_ctor_base &) = default; optional_delete_ctor_base & operator=(optional_delete_ctor_base &&) noexcept = default; }; // optional_delete_assign_base will conditionally delete copy and move // constructors depending on whether T is copy/move constructible + assignable template ::value && std::is_copy_assignable::value), bool EnableMove = (std::is_move_constructible::value && std::is_move_assignable::value)> struct optional_delete_assign_base { optional_delete_assign_base() = default; optional_delete_assign_base(const optional_delete_assign_base &) = default; optional_delete_assign_base(optional_delete_assign_base &&) noexcept = default; optional_delete_assign_base & operator=(const optional_delete_assign_base &) = default; optional_delete_assign_base & operator=(optional_delete_assign_base &&) noexcept = default; }; template struct optional_delete_assign_base { optional_delete_assign_base() = default; optional_delete_assign_base(const optional_delete_assign_base &) = default; optional_delete_assign_base(optional_delete_assign_base &&) noexcept = default; optional_delete_assign_base & operator=(const optional_delete_assign_base &) = default; optional_delete_assign_base & operator=(optional_delete_assign_base &&) noexcept = delete; }; template struct optional_delete_assign_base { optional_delete_assign_base() = default; optional_delete_assign_base(const optional_delete_assign_base &) = default; optional_delete_assign_base(optional_delete_assign_base &&) noexcept = default; optional_delete_assign_base & operator=(const optional_delete_assign_base &) = delete; optional_delete_assign_base & operator=(optional_delete_assign_base &&) noexcept = default; }; template struct optional_delete_assign_base { optional_delete_assign_base() = default; optional_delete_assign_base(const optional_delete_assign_base &) = default; optional_delete_assign_base(optional_delete_assign_base &&) noexcept = default; optional_delete_assign_base & operator=(const optional_delete_assign_base &) = delete; optional_delete_assign_base & operator=(optional_delete_assign_base &&) noexcept = delete; }; } // namespace detail /// A tag type to represent an empty optional struct nullopt_t { struct do_not_use {}; constexpr explicit nullopt_t(do_not_use, do_not_use) noexcept {} }; /// Represents an empty optional static constexpr nullopt_t nullopt{nullopt_t::do_not_use{}, nullopt_t::do_not_use{}}; class bad_optional_access : public std::exception { public: bad_optional_access() = default; const char *what() const noexcept { return "Optional has no value"; } }; /// An optional object is an object that contains the storage for another /// object and manages the lifetime of this contained object, if any. The /// contained object may be initialized after the optional object has been /// initialized, and may be destroyed before the optional object has been /// destroyed. The initialization state of the contained object is tracked by /// the optional object. template class optional : private detail::optional_move_assign_base, private detail::optional_delete_ctor_base, private detail::optional_delete_assign_base { using base = detail::optional_move_assign_base; static_assert(!std::is_same::value, "instantiation of optional with in_place_t is ill-formed"); static_assert(!std::is_same, nullopt_t>::value, "instantiation of optional with nullopt_t is ill-formed"); public: // The different versions for C++14 and 11 are needed because deduced return // types are not SFINAE-safe. This provides better support for things like // generic lambdas. C.f. // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0.html #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) /// Carries out some operation which returns an optional on the stored /// object if there is one. template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) & { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) && { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : result(nullopt); } template constexpr auto and_then(F &&f) const & { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } #ifndef TL_OPTIONAL_NO_CONSTRR template constexpr auto and_then(F &&f) const && { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : result(nullopt); } #endif #else /// Carries out some operation which returns an optional on the stored /// object if there is one. template TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) & { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } template TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) && { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : result(nullopt); } template constexpr detail::invoke_result_t and_then(F &&f) const & { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } #ifndef TL_OPTIONAL_NO_CONSTRR template constexpr detail::invoke_result_t and_then(F &&f) const && { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : result(nullopt); } #endif #endif #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) /// Carries out some operation on the stored object if there is one. template TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) & { return optional_map_impl(*this, std::forward(f)); } template TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) && { return optional_map_impl(std::move(*this), std::forward(f)); } template constexpr auto map(F &&f) const & { return optional_map_impl(*this, std::forward(f)); } template constexpr auto map(F &&f) const && { return optional_map_impl(std::move(*this), std::forward(f)); } #else /// Carries out some operation on the stored object if there is one. template TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval(), std::declval())) map(F &&f) & { return optional_map_impl(*this, std::forward(f)); } template TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval(), std::declval())) map(F &&f) && { return optional_map_impl(std::move(*this), std::forward(f)); } template constexpr decltype(optional_map_impl(std::declval(), std::declval())) map(F &&f) const & { return optional_map_impl(*this, std::forward(f)); } #ifndef TL_OPTIONAL_NO_CONSTRR template constexpr decltype(optional_map_impl(std::declval(), std::declval())) map(F &&f) const && { return optional_map_impl(std::move(*this), std::forward(f)); } #endif #endif #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) /// Carries out some operation on the stored object if there is one. template TL_OPTIONAL_11_CONSTEXPR auto transform(F&& f) & { return optional_map_impl(*this, std::forward(f)); } template TL_OPTIONAL_11_CONSTEXPR auto transform(F&& f) && { return optional_map_impl(std::move(*this), std::forward(f)); } template constexpr auto transform(F&& f) const & { return optional_map_impl(*this, std::forward(f)); } template constexpr auto transform(F&& f) const && { return optional_map_impl(std::move(*this), std::forward(f)); } #else /// Carries out some operation on the stored object if there is one. template TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval(), std::declval())) transform(F&& f) & { return optional_map_impl(*this, std::forward(f)); } template TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval(), std::declval())) transform(F&& f) && { return optional_map_impl(std::move(*this), std::forward(f)); } template constexpr decltype(optional_map_impl(std::declval(), std::declval())) transform(F&& f) const & { return optional_map_impl(*this, std::forward(f)); } #ifndef TL_OPTIONAL_NO_CONSTRR template constexpr decltype(optional_map_impl(std::declval(), std::declval())) transform(F&& f) const && { return optional_map_impl(std::move(*this), std::forward(f)); } #endif #endif /// Calls `f` if the optional is empty template * = nullptr> optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { if (has_value()) return *this; std::forward(f)(); return nullopt; } template * = nullptr> optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { return has_value() ? *this : std::forward(f)(); } template * = nullptr> optional or_else(F &&f) && { if (has_value()) return std::move(*this); std::forward(f)(); return nullopt; } template * = nullptr> optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) && { return has_value() ? std::move(*this) : std::forward(f)(); } template * = nullptr> optional or_else(F &&f) const & { if (has_value()) return *this; std::forward(f)(); return nullopt; } template * = nullptr> optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) const & { return has_value() ? *this : std::forward(f)(); } #ifndef TL_OPTIONAL_NO_CONSTRR template * = nullptr> optional or_else(F &&f) const && { if (has_value()) return std::move(*this); std::forward(f)(); return nullopt; } template * = nullptr> optional or_else(F &&f) const && { return has_value() ? std::move(*this) : std::forward(f)(); } #endif /// Maps the stored value with `f` if there is one, otherwise returns `u`. template U map_or(F &&f, U &&u) & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u); } template U map_or(F &&f, U &&u) && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u); } template U map_or(F &&f, U &&u) const & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u); } #ifndef TL_OPTIONAL_NO_CONSTRR template U map_or(F &&f, U &&u) const && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u); } #endif /// Maps the stored value with `f` if there is one, otherwise calls /// `u` and returns the result. template detail::invoke_result_t map_or_else(F &&f, U &&u) & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u)(); } template detail::invoke_result_t map_or_else(F &&f, U &&u) && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u)(); } template detail::invoke_result_t map_or_else(F &&f, U &&u) const & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u)(); } #ifndef TL_OPTIONAL_NO_CONSTRR template detail::invoke_result_t map_or_else(F &&f, U &&u) const && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u)(); } #endif /// Returns `u` if `*this` has a value, otherwise an empty optional. template constexpr optional::type> conjunction(U &&u) const { using result = optional>; return has_value() ? result{u} : result{nullopt}; } /// Returns `rhs` if `*this` is empty, otherwise the current value. TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) & { return has_value() ? *this : rhs; } constexpr optional disjunction(const optional &rhs) const & { return has_value() ? *this : rhs; } TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) && { return has_value() ? std::move(*this) : rhs; } #ifndef TL_OPTIONAL_NO_CONSTRR constexpr optional disjunction(const optional &rhs) const && { return has_value() ? std::move(*this) : rhs; } #endif TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) & { return has_value() ? *this : std::move(rhs); } constexpr optional disjunction(optional &&rhs) const & { return has_value() ? *this : std::move(rhs); } TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) && { return has_value() ? std::move(*this) : std::move(rhs); } #ifndef TL_OPTIONAL_NO_CONSTRR constexpr optional disjunction(optional &&rhs) const && { return has_value() ? std::move(*this) : std::move(rhs); } #endif /// Takes the value out of the optional, leaving it empty optional take() { optional ret = std::move(*this); reset(); return ret; } using value_type = T; /// Constructs an optional that does not contain a value. constexpr optional() noexcept = default; constexpr optional(nullopt_t) noexcept {} /// Copy constructor /// /// If `rhs` contains a value, the stored value is direct-initialized with /// it. Otherwise, the constructed optional is empty. TL_OPTIONAL_11_CONSTEXPR optional(const optional &rhs) = default; /// Move constructor /// /// If `rhs` contains a value, the stored value is direct-initialized with /// it. Otherwise, the constructed optional is empty. TL_OPTIONAL_11_CONSTEXPR optional(optional &&rhs) = default; /// Constructs the stored value in-place using the given arguments. template constexpr explicit optional( detail::enable_if_t::value, in_place_t>, Args &&... args) : base(in_place, std::forward(args)...) {} template TL_OPTIONAL_11_CONSTEXPR explicit optional( detail::enable_if_t &, Args &&...>::value, in_place_t>, std::initializer_list il, Args &&... args) { this->construct(il, std::forward(args)...); } /// Constructs the stored value with `u`. template < class U = T, detail::enable_if_t::value> * = nullptr, detail::enable_forward_value * = nullptr> constexpr optional(U &&u) : base(in_place, std::forward(u)) {} template < class U = T, detail::enable_if_t::value> * = nullptr, detail::enable_forward_value * = nullptr> constexpr explicit optional(U &&u) : base(in_place, std::forward(u)) {} /// Converting copy constructor. template < class U, detail::enable_from_other * = nullptr, detail::enable_if_t::value> * = nullptr> optional(const optional &rhs) { if (rhs.has_value()) { this->construct(*rhs); } } template * = nullptr, detail::enable_if_t::value> * = nullptr> explicit optional(const optional &rhs) { if (rhs.has_value()) { this->construct(*rhs); } } /// Converting move constructor. template < class U, detail::enable_from_other * = nullptr, detail::enable_if_t::value> * = nullptr> optional(optional &&rhs) { if (rhs.has_value()) { this->construct(std::move(*rhs)); } } template < class U, detail::enable_from_other * = nullptr, detail::enable_if_t::value> * = nullptr> explicit optional(optional &&rhs) { if (rhs.has_value()) { this->construct(std::move(*rhs)); } } /// Destroys the stored value if there is one. ~optional() = default; /// Assignment to empty. /// /// Destroys the current value if there is one. optional &operator=(nullopt_t) noexcept { if (has_value()) { this->m_value.~T(); this->m_has_value = false; } return *this; } /// Copy assignment. /// /// Copies the value from `rhs` if there is one. Otherwise resets the stored /// value in `*this`. optional &operator=(const optional &rhs) = default; /// Move assignment. /// /// Moves the value from `rhs` if there is one. Otherwise resets the stored /// value in `*this`. optional &operator=(optional &&rhs) = default; /// Assigns the stored value from `u`, destroying the old value if there was /// one. template * = nullptr> optional &operator=(U &&u) { if (has_value()) { this->m_value = std::forward(u); } else { this->construct(std::forward(u)); } return *this; } /// Converting copy assignment operator. /// /// Copies the value from `rhs` if there is one. Otherwise resets the stored /// value in `*this`. template * = nullptr> optional &operator=(const optional &rhs) { if (has_value()) { if (rhs.has_value()) { this->m_value = *rhs; } else { this->hard_reset(); } } else if (rhs.has_value()) { this->construct(*rhs); } return *this; } // TODO check exception guarantee /// Converting move assignment operator. /// /// Moves the value from `rhs` if there is one. Otherwise resets the stored /// value in `*this`. template * = nullptr> optional &operator=(optional &&rhs) { if (has_value()) { if (rhs.has_value()) { this->m_value = std::move(*rhs); } else { this->hard_reset(); } } else if (rhs.has_value()) { this->construct(std::move(*rhs)); } return *this; } /// Constructs the value in-place, destroying the current one if there is /// one. template T &emplace(Args &&... args) { static_assert(std::is_constructible::value, "T must be constructible with Args"); *this = nullopt; this->construct(std::forward(args)...); return value(); } template detail::enable_if_t< std::is_constructible &, Args &&...>::value, T &> emplace(std::initializer_list il, Args &&... args) { *this = nullopt; this->construct(il, std::forward(args)...); return value(); } /// Swaps this optional with the other. /// /// If neither optionals have a value, nothing happens. /// If both have a value, the values are swapped. /// If one has a value, it is moved to the other and the movee is left /// valueless. void swap(optional &rhs) noexcept(std::is_nothrow_move_constructible::value &&detail::is_nothrow_swappable::value) { using std::swap; if (has_value()) { if (rhs.has_value()) { swap(**this, *rhs); } else { new (std::addressof(rhs.m_value)) T(std::move(this->m_value)); this->m_value.T::~T(); } } else if (rhs.has_value()) { new (std::addressof(this->m_value)) T(std::move(rhs.m_value)); rhs.m_value.T::~T(); } swap(this->m_has_value, rhs.m_has_value); } /// Returns a pointer to the stored value constexpr const T *operator->() const { return std::addressof(this->m_value); } TL_OPTIONAL_11_CONSTEXPR T *operator->() { return std::addressof(this->m_value); } /// Returns the stored value TL_OPTIONAL_11_CONSTEXPR T &operator*() & { return this->m_value; } constexpr const T &operator*() const & { return this->m_value; } TL_OPTIONAL_11_CONSTEXPR T &&operator*() && { return std::move(this->m_value); } #ifndef TL_OPTIONAL_NO_CONSTRR constexpr const T &&operator*() const && { return std::move(this->m_value); } #endif /// Returns whether or not the optional has a value constexpr bool has_value() const noexcept { return this->m_has_value; } constexpr explicit operator bool() const noexcept { return this->m_has_value; } /// Returns the contained value if there is one, otherwise throws bad_optional_access TL_OPTIONAL_11_CONSTEXPR T &value() & { if (has_value()) return this->m_value; throw bad_optional_access(); } TL_OPTIONAL_11_CONSTEXPR const T &value() const & { if (has_value()) return this->m_value; throw bad_optional_access(); } TL_OPTIONAL_11_CONSTEXPR T &&value() && { if (has_value()) return std::move(this->m_value); throw bad_optional_access(); } #ifndef TL_OPTIONAL_NO_CONSTRR TL_OPTIONAL_11_CONSTEXPR const T &&value() const && { if (has_value()) return std::move(this->m_value); throw bad_optional_access(); } #endif /// Returns the stored value if there is one, otherwise returns `u` template constexpr T value_or(U &&u) const & { static_assert(std::is_copy_constructible::value && std::is_convertible::value, "T must be copy constructible and convertible from U"); return has_value() ? **this : static_cast(std::forward(u)); } template TL_OPTIONAL_11_CONSTEXPR T value_or(U &&u) && { static_assert(std::is_move_constructible::value && std::is_convertible::value, "T must be move constructible and convertible from U"); return has_value() ? std::move(**this) : static_cast(std::forward(u)); } /// Destroys the stored value if one exists, making the optional empty void reset() noexcept { if (has_value()) { this->m_value.~T(); this->m_has_value = false; } } }; // namespace tl /// Compares two optional objects template inline constexpr bool operator==(const optional &lhs, const optional &rhs) { return lhs.has_value() == rhs.has_value() && (!lhs.has_value() || *lhs == *rhs); } template inline constexpr bool operator!=(const optional &lhs, const optional &rhs) { return lhs.has_value() != rhs.has_value() || (lhs.has_value() && *lhs != *rhs); } template inline constexpr bool operator<(const optional &lhs, const optional &rhs) { return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs); } template inline constexpr bool operator>(const optional &lhs, const optional &rhs) { return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs); } template inline constexpr bool operator<=(const optional &lhs, const optional &rhs) { return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs); } template inline constexpr bool operator>=(const optional &lhs, const optional &rhs) { return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs); } /// Compares an optional to a `nullopt` template inline constexpr bool operator==(const optional &lhs, nullopt_t) noexcept { return !lhs.has_value(); } template inline constexpr bool operator==(nullopt_t, const optional &rhs) noexcept { return !rhs.has_value(); } template inline constexpr bool operator!=(const optional &lhs, nullopt_t) noexcept { return lhs.has_value(); } template inline constexpr bool operator!=(nullopt_t, const optional &rhs) noexcept { return rhs.has_value(); } template inline constexpr bool operator<(const optional &, nullopt_t) noexcept { return false; } template inline constexpr bool operator<(nullopt_t, const optional &rhs) noexcept { return rhs.has_value(); } template inline constexpr bool operator<=(const optional &lhs, nullopt_t) noexcept { return !lhs.has_value(); } template inline constexpr bool operator<=(nullopt_t, const optional &) noexcept { return true; } template inline constexpr bool operator>(const optional &lhs, nullopt_t) noexcept { return lhs.has_value(); } template inline constexpr bool operator>(nullopt_t, const optional &) noexcept { return false; } template inline constexpr bool operator>=(const optional &, nullopt_t) noexcept { return true; } template inline constexpr bool operator>=(nullopt_t, const optional &rhs) noexcept { return !rhs.has_value(); } /// Compares the optional with a value. template inline constexpr bool operator==(const optional &lhs, const U &rhs) { return lhs.has_value() ? *lhs == rhs : false; } template inline constexpr bool operator==(const U &lhs, const optional &rhs) { return rhs.has_value() ? lhs == *rhs : false; } template inline constexpr bool operator!=(const optional &lhs, const U &rhs) { return lhs.has_value() ? *lhs != rhs : true; } template inline constexpr bool operator!=(const U &lhs, const optional &rhs) { return rhs.has_value() ? lhs != *rhs : true; } template inline constexpr bool operator<(const optional &lhs, const U &rhs) { return lhs.has_value() ? *lhs < rhs : true; } template inline constexpr bool operator<(const U &lhs, const optional &rhs) { return rhs.has_value() ? lhs < *rhs : false; } template inline constexpr bool operator<=(const optional &lhs, const U &rhs) { return lhs.has_value() ? *lhs <= rhs : true; } template inline constexpr bool operator<=(const U &lhs, const optional &rhs) { return rhs.has_value() ? lhs <= *rhs : false; } template inline constexpr bool operator>(const optional &lhs, const U &rhs) { return lhs.has_value() ? *lhs > rhs : false; } template inline constexpr bool operator>(const U &lhs, const optional &rhs) { return rhs.has_value() ? lhs > *rhs : true; } template inline constexpr bool operator>=(const optional &lhs, const U &rhs) { return lhs.has_value() ? *lhs >= rhs : false; } template inline constexpr bool operator>=(const U &lhs, const optional &rhs) { return rhs.has_value() ? lhs >= *rhs : true; } template ::value> * = nullptr, detail::enable_if_t::value> * = nullptr> void swap(optional &lhs, optional &rhs) noexcept(noexcept(lhs.swap(rhs))) { return lhs.swap(rhs); } namespace detail { struct i_am_secret {}; } // namespace detail template ::value, detail::decay_t, T>> inline constexpr optional make_optional(U &&v) { return optional(std::forward(v)); } template inline constexpr optional make_optional(Args &&... args) { return optional(in_place, std::forward(args)...); } template inline constexpr optional make_optional(std::initializer_list il, Args &&... args) { return optional(in_place, il, std::forward(args)...); } #if __cplusplus >= 201703L template optional(T)->optional; #endif /// \exclude namespace detail { #ifdef TL_OPTIONAL_CXX14 template (), *std::declval())), detail::enable_if_t::value> * = nullptr> constexpr auto optional_map_impl(Opt &&opt, F &&f) { return opt.has_value() ? detail::invoke(std::forward(f), *std::forward(opt)) : optional(nullopt); } template (), *std::declval())), detail::enable_if_t::value> * = nullptr> auto optional_map_impl(Opt &&opt, F &&f) { if (opt.has_value()) { detail::invoke(std::forward(f), *std::forward(opt)); return make_optional(monostate{}); } return optional(nullopt); } #else template (), *std::declval())), detail::enable_if_t::value> * = nullptr> constexpr auto optional_map_impl(Opt &&opt, F &&f) -> optional { return opt.has_value() ? detail::invoke(std::forward(f), *std::forward(opt)) : optional(nullopt); } template (), *std::declval())), detail::enable_if_t::value> * = nullptr> auto optional_map_impl(Opt &&opt, F &&f) -> optional { if (opt.has_value()) { detail::invoke(std::forward(f), *std::forward(opt)); return monostate{}; } return nullopt; } #endif } // namespace detail /// Specialization for when `T` is a reference. `optional` acts similarly /// to a `T*`, but provides more operations and shows intent more clearly. template class optional { public: // The different versions for C++14 and 11 are needed because deduced return // types are not SFINAE-safe. This provides better support for things like // generic lambdas. C.f. // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0.html #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) /// Carries out some operation which returns an optional on the stored /// object if there is one. template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) & { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) && { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } template constexpr auto and_then(F &&f) const & { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } #ifndef TL_OPTIONAL_NO_CONSTRR template constexpr auto and_then(F &&f) const && { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } #endif #else /// Carries out some operation which returns an optional on the stored /// object if there is one. template TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) & { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } template TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) && { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } template constexpr detail::invoke_result_t and_then(F &&f) const & { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), **this) : result(nullopt); } #ifndef TL_OPTIONAL_NO_CONSTRR template constexpr detail::invoke_result_t and_then(F &&f) const && { using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : result(nullopt); } #endif #endif #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) /// Carries out some operation on the stored object if there is one. template TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) & { return detail::optional_map_impl(*this, std::forward(f)); } template TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) && { return detail::optional_map_impl(std::move(*this), std::forward(f)); } template constexpr auto map(F &&f) const & { return detail::optional_map_impl(*this, std::forward(f)); } template constexpr auto map(F &&f) const && { return detail::optional_map_impl(std::move(*this), std::forward(f)); } #else /// Carries out some operation on the stored object if there is one. template TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval(), std::declval())) map(F &&f) & { return detail::optional_map_impl(*this, std::forward(f)); } template TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval(), std::declval())) map(F &&f) && { return detail::optional_map_impl(std::move(*this), std::forward(f)); } template constexpr decltype(detail::optional_map_impl(std::declval(), std::declval())) map(F &&f) const & { return detail::optional_map_impl(*this, std::forward(f)); } #ifndef TL_OPTIONAL_NO_CONSTRR template constexpr decltype(detail::optional_map_impl(std::declval(), std::declval())) map(F &&f) const && { return detail::optional_map_impl(std::move(*this), std::forward(f)); } #endif #endif #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) /// Carries out some operation on the stored object if there is one. template TL_OPTIONAL_11_CONSTEXPR auto transform(F&& f) & { return detail::optional_map_impl(*this, std::forward(f)); } template TL_OPTIONAL_11_CONSTEXPR auto transform(F&& f) && { return detail::optional_map_impl(std::move(*this), std::forward(f)); } template constexpr auto transform(F&& f) const & { return detail::optional_map_impl(*this, std::forward(f)); } template constexpr auto transform(F&& f) const && { return detail::optional_map_impl(std::move(*this), std::forward(f)); } #else /// Carries out some operation on the stored object if there is one. template TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval(), std::declval())) transform(F&& f) & { return detail::optional_map_impl(*this, std::forward(f)); } /// \group map /// \synopsis template auto transform(F &&f) &&; template TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval(), std::declval())) transform(F&& f) && { return detail::optional_map_impl(std::move(*this), std::forward(f)); } template constexpr decltype(detail::optional_map_impl(std::declval(), std::declval())) transform(F&& f) const & { return detail::optional_map_impl(*this, std::forward(f)); } #ifndef TL_OPTIONAL_NO_CONSTRR template constexpr decltype(detail::optional_map_impl(std::declval(), std::declval())) transform(F&& f) const && { return detail::optional_map_impl(std::move(*this), std::forward(f)); } #endif #endif /// Calls `f` if the optional is empty template * = nullptr> optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { if (has_value()) return *this; std::forward(f)(); return nullopt; } template * = nullptr> optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { return has_value() ? *this : std::forward(f)(); } template * = nullptr> optional or_else(F &&f) && { if (has_value()) return std::move(*this); std::forward(f)(); return nullopt; } template * = nullptr> optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) && { return has_value() ? std::move(*this) : std::forward(f)(); } template * = nullptr> optional or_else(F &&f) const & { if (has_value()) return *this; std::forward(f)(); return nullopt; } template * = nullptr> optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) const & { return has_value() ? *this : std::forward(f)(); } #ifndef TL_OPTIONAL_NO_CONSTRR template * = nullptr> optional or_else(F &&f) const && { if (has_value()) return std::move(*this); std::forward(f)(); return nullopt; } template * = nullptr> optional or_else(F &&f) const && { return has_value() ? std::move(*this) : std::forward(f)(); } #endif /// Maps the stored value with `f` if there is one, otherwise returns `u` template U map_or(F &&f, U &&u) & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u); } template U map_or(F &&f, U &&u) && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u); } template U map_or(F &&f, U &&u) const & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u); } #ifndef TL_OPTIONAL_NO_CONSTRR template U map_or(F &&f, U &&u) const && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u); } #endif /// Maps the stored value with `f` if there is one, otherwise calls /// `u` and returns the result. template detail::invoke_result_t map_or_else(F &&f, U &&u) & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u)(); } template detail::invoke_result_t map_or_else(F &&f, U &&u) && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u)(); } template detail::invoke_result_t map_or_else(F &&f, U &&u) const & { return has_value() ? detail::invoke(std::forward(f), **this) : std::forward(u)(); } #ifndef TL_OPTIONAL_NO_CONSTRR template detail::invoke_result_t map_or_else(F &&f, U &&u) const && { return has_value() ? detail::invoke(std::forward(f), std::move(**this)) : std::forward(u)(); } #endif /// Returns `u` if `*this` has a value, otherwise an empty optional. template constexpr optional::type> conjunction(U &&u) const { using result = optional>; return has_value() ? result{u} : result{nullopt}; } /// Returns `rhs` if `*this` is empty, otherwise the current value. TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) & { return has_value() ? *this : rhs; } constexpr optional disjunction(const optional &rhs) const & { return has_value() ? *this : rhs; } TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) && { return has_value() ? std::move(*this) : rhs; } #ifndef TL_OPTIONAL_NO_CONSTRR constexpr optional disjunction(const optional &rhs) const && { return has_value() ? std::move(*this) : rhs; } #endif TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) & { return has_value() ? *this : std::move(rhs); } constexpr optional disjunction(optional &&rhs) const & { return has_value() ? *this : std::move(rhs); } TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) && { return has_value() ? std::move(*this) : std::move(rhs); } #ifndef TL_OPTIONAL_NO_CONSTRR constexpr optional disjunction(optional &&rhs) const && { return has_value() ? std::move(*this) : std::move(rhs); } #endif /// Takes the value out of the optional, leaving it empty optional take() { optional ret = std::move(*this); reset(); return ret; } using value_type = T &; /// Constructs an optional that does not contain a value. constexpr optional() noexcept : m_value(nullptr) {} constexpr optional(nullopt_t) noexcept : m_value(nullptr) {} /// Copy constructor /// /// If `rhs` contains a value, the stored value is direct-initialized with /// it. Otherwise, the constructed optional is empty. TL_OPTIONAL_11_CONSTEXPR optional(const optional &rhs) noexcept = default; /// Move constructor /// /// If `rhs` contains a value, the stored value is direct-initialized with /// it. Otherwise, the constructed optional is empty. TL_OPTIONAL_11_CONSTEXPR optional(optional &&rhs) = default; /// Constructs the stored value with `u`. template >::value> * = nullptr> constexpr optional(U &&u) noexcept : m_value(std::addressof(u)) { static_assert(std::is_lvalue_reference::value, "U must be an lvalue"); } template constexpr explicit optional(const optional &rhs) noexcept : optional(*rhs) {} /// No-op ~optional() = default; /// Assignment to empty. /// /// Destroys the current value if there is one. optional &operator=(nullopt_t) noexcept { m_value = nullptr; return *this; } /// Copy assignment. /// /// Rebinds this optional to the referee of `rhs` if there is one. Otherwise /// resets the stored value in `*this`. optional &operator=(const optional &rhs) = default; /// Rebinds this optional to `u`. template >::value> * = nullptr> optional &operator=(U &&u) { static_assert(std::is_lvalue_reference::value, "U must be an lvalue"); m_value = std::addressof(u); return *this; } /// Converting copy assignment operator. /// /// Rebinds this optional to the referee of `rhs` if there is one. Otherwise /// resets the stored value in `*this`. template optional &operator=(const optional &rhs) noexcept { m_value = std::addressof(rhs.value()); return *this; } /// Rebinds this optional to `u`. template >::value> * = nullptr> optional &emplace(U &&u) noexcept { return *this = std::forward(u); } void swap(optional &rhs) noexcept { std::swap(m_value, rhs.m_value); } /// Returns a pointer to the stored value constexpr const T *operator->() const noexcept { return m_value; } TL_OPTIONAL_11_CONSTEXPR T *operator->() noexcept { return m_value; } /// Returns the stored value TL_OPTIONAL_11_CONSTEXPR T &operator*() noexcept { return *m_value; } constexpr const T &operator*() const noexcept { return *m_value; } constexpr bool has_value() const noexcept { return m_value != nullptr; } constexpr explicit operator bool() const noexcept { return m_value != nullptr; } /// Returns the contained value if there is one, otherwise throws bad_optional_access TL_OPTIONAL_11_CONSTEXPR T &value() { if (has_value()) return *m_value; throw bad_optional_access(); } TL_OPTIONAL_11_CONSTEXPR const T &value() const { if (has_value()) return *m_value; throw bad_optional_access(); } /// Returns the stored value if there is one, otherwise returns `u` template constexpr T value_or(U &&u) const & noexcept { static_assert(std::is_copy_constructible::value && std::is_convertible::value, "T must be copy constructible and convertible from U"); return has_value() ? **this : static_cast(std::forward(u)); } /// \group value_or template TL_OPTIONAL_11_CONSTEXPR T value_or(U &&u) && noexcept { static_assert(std::is_move_constructible::value && std::is_convertible::value, "T must be move constructible and convertible from U"); return has_value() ? **this : static_cast(std::forward(u)); } /// Destroys the stored value if one exists, making the optional empty void reset() noexcept { m_value = nullptr; } private: T *m_value; }; // namespace tl } // namespace tl namespace std { // TODO SFINAE template struct hash> { ::std::size_t operator()(const tl::optional &o) const { if (!o.has_value()) return 0; return std::hash>()(*o); } }; } // namespace std #endif eureka-editor-eureka-2.0.2/src/ui_about.cc000066400000000000000000000113531464327712600204510ustar00rootroot00000000000000//------------------------------------------------------------------------ // ABOUT WINDOW //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "main.h" #include "ui_window.h" #include "ui_about.h" #define ABOUT_W (440) // matches logo image #define ABOUT_H (230 + 290) class UI_About : public UI_Escapable_Window { private: static UI_About * _instance; static Fl_RGB_Image *about_img; UI_About(int W, int H, const char *label = NULL); virtual ~UI_About() { // nothing needed } static void LoadImage() { static char filename[FL_PATH_MAX]; // FIXME : use this location for all platforms #ifdef WIN32 snprintf(filename, sizeof(filename), "%s/common/about_logo.png", global::install_dir.u8string().c_str()); #else snprintf(filename, sizeof(filename), "%s/about_logo.png", global::install_dir.u8string().c_str()); #endif filename[FL_PATH_MAX-1] = 0; if (FileExists(filename)) { about_img = new Fl_PNG_Image(filename); } } public: static void Open() { if (_instance) // already up? return; if (! about_img) LoadImage(); _instance = new UI_About(ABOUT_W, ABOUT_H, "About Eureka v" EUREKA_VERSION); _instance->show(); } private: static void close_callback(Fl_Widget *w, void *data) { if (_instance) { _instance->default_callback(_instance, data); _instance = NULL; } } static const char *Text1; static const char *Text2; static const char *URL; }; UI_About * UI_About::_instance; Fl_RGB_Image * UI_About::about_img; const char *UI_About::Text1 = "EUREKA is a map editor for classic DOOM\n" "It uses code from the Yadex editor"; const char *UI_About::Text2 = "Copyright (C) 2014-2024 Ioan Chera \n" "Copyright (C) 2001-2020 Andrew Apted, et al\n" "Copyright (C) 1997-2003 André Majorel, et al\n" "\n" "This program is free software, and may be\n" "distributed and modified under the terms of\n" "the GNU General Public License\n" "\n" "There is ABSOLUTELY NO WARRANTY\n" "Use at your OWN RISK"; const char *UI_About::URL = "http://awwports.sf.net/eureka"; // // Constructor // UI_About::UI_About(int W, int H, const char *label) : UI_Escapable_Window(W, H, label) { // non-resizable size_range(W, H, W, H); callback(close_callback, this); // nice big logo image Fl_Box *box = new Fl_Box(FL_NO_BOX, 0, 0, W, 230, NULL); box->align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER); box->color(FL_BLACK, FL_BLACK); if (about_img) { box->image(about_img); // overlay a small version number in bottom right corner Fl_Box *v_box = new Fl_Box(FL_NO_BOX, 0, 0, W - 2, 230, ""); v_box->label("v" EUREKA_VERSION); v_box->labelsize(20); v_box->labelcolor(fl_rgb_color(160, 255, 128)); v_box->align(FL_ALIGN_INSIDE | FL_ALIGN_RIGHT | FL_ALIGN_BOTTOM); } else { box->box(FL_FLAT_BOX); box->label("EUREKA\nDoom Editor\nv" EUREKA_VERSION); box->labelsize(40); box->labelcolor(fl_rgb_color(255, 200, 100)); } int cy = 240; // the very informative text int pad = 26; box = new Fl_Box(FL_NO_BOX, pad, cy, W-pad-pad, 44, Text1); box->align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER); box->labelfont(FL_HELVETICA_BOLD); cy += box->h(); box = new Fl_Box(FL_NO_BOX, pad, cy, W-pad-pad, 186, Text2); box->align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER); box->labelfont(FL_HELVETICA); cy += box->h(); #if 0 // website address UI_HyperLink *link = new UI_HyperLink(10, cy, W-20, 30, URL, URL); link->align(FL_ALIGN_CENTER); link->labelsize(20); link->color(color()); cy += link->h() + 16; #endif // finally add an "OK" button int bw = 70; int bh = 33; cy += (H - cy - bh) / 2 - 6; Fl_Color but_color = fl_rgb_color(128, 208, 255); Fl_Button *button = new Fl_Button((W-10-bw)/2, cy, bw, bh, "OK!"); button->color(but_color, but_color); button->callback(close_callback, this); end(); } void DLG_AboutText(void) { UI_About::Open(); } #ifdef __APPLE__ static void about_callback_macosx(Fl_Widget *, void *) { UI_About::Open(); } #endif void InitAboutDialog() { #ifdef __APPLE__ fl_mac_set_about(about_callback_macosx, NULL); #endif } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_about.h000066400000000000000000000020071464327712600203070ustar00rootroot00000000000000//------------------------------------------------------------------------ // ABOUT WINDOW //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_ABOUT_H__ #define __EUREKA_UI_ABOUT_H__ void InitAboutDialog(); void DLG_AboutText(void); #endif /* __EUREKA_UI_ABOUT_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_browser.cc000066400000000000000000001124441464327712600210250ustar00rootroot00000000000000//------------------------------------------------------------------------ // BROWSER for TEXTURES / FLATS / THINGS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2019 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include #include #include "ui_window.h" #include "ui_browser.h" #include "im_img.h" #include "im_color.h" #include "m_config.h" #include "m_game.h" #include "e_main.h" // recent_xxx #include "e_things.h" #include "w_rawdef.h" #include "w_texture.h" #define BROWBACK_COL (config::gui_scheme == 2 ? FL_DARK3 : FL_DARK2) // config items bool config::browser_small_tex = false; bool config::browser_combine_tex = false; // sort methods enum sort_method_e { SOM_Numeric = 0, SOM_Alpha, SOM_AlphaSkip, // skip the S1, WR (etc) of linedef descriptions SOM_Recent }; bool Texture_MatchPattern(const char *tex, const char *pattern) { // Note: an empty pattern matches NOTHING SString local_pat; local_pat.reserve(256); // add '*' to the start and end of the pattern // (unless it uses the ^ or $ anchors) bool negated = false; if (pattern[0] == '!') { pattern++; negated = true; } if (pattern[0] == '^') pattern++; else local_pat = "*"; local_pat += pattern; size_t len = local_pat.length(); if (len == 0) return false; if (local_pat.back() == '$') local_pat.pop_back(); else local_pat += '*'; bool result = !!fl_filename_match(tex, local_pat.c_str()); return negated ? !result : result; } // // this sub-class of button prevents grabbing the keyboard focus, // which is mainly useful for the Find/Replace panel, as it needs // to know which input box (Find or Replace) was last active. // class Browser_Button : public Fl_Button { public: Browser_Button(int X, int Y, int W, int H, const char *L) : Fl_Button(X, Y, W, H, L) { } virtual ~Browser_Button() { } int handle(int event) { if (event == FL_FOCUS) return 0; return Fl_Button::handle(event); } }; static char browserModeToChar(BrowserMode mode) { switch(mode) { case BrowserMode::textures: return 'T'; case BrowserMode::flats: return 'F'; case BrowserMode::things: return 'O'; case BrowserMode::lineTypes: return 'L'; case BrowserMode::sectorTypes: return 'S'; case BrowserMode::generalized: return 'G'; default: return '?'; } } BrowserMode charToBrowserMode(char c) { switch(c) { case 'T': return BrowserMode::textures; case 'F': return BrowserMode::flats; case 'O': return BrowserMode::things; case 'L': return BrowserMode::lineTypes; case 'S': return BrowserMode::sectorTypes; case 'G': return BrowserMode::generalized; case '-': case 0: return BrowserMode::hide; case '/': return BrowserMode::toggle; default: return BrowserMode::invalid; } } bool charMapsToSpecificBrowserMode(char c) { BrowserMode mode = charToBrowserMode(c); switch(mode) { case BrowserMode::textures: case BrowserMode::flats: case BrowserMode::things: case BrowserMode::lineTypes: case BrowserMode::sectorTypes: case BrowserMode::generalized: return true; default: return false; } } /* text item */ Browser_Item::Browser_Item(Instance &inst, int X, int Y, int W, int H, const SString &_desc, const SString &_realname, int _num, BrowserMode _kind, char _category) : Fl_Group(X, Y, W, H, ""), desc(_desc), real_name(_realname), number(_num), kind(_kind), category(_category), inst(inst) { end(); button = new Browser_Button(X + 4, Y + 1, W - 8, H - 2, desc.c_str()); button->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT); button->labelfont(FL_COURIER); button->labelsize(14); button->when(FL_WHEN_CHANGED); add(button); } /* image item */ Browser_Item::Browser_Item(Instance &inst, int X, int Y, int W, int H, const SString &_desc, const SString &_realname, int _num, BrowserMode _kind, char _category, int pic_w, int pic_h, UI_Pic *_pic) : Fl_Group(X, Y, W, H, ""), desc(_desc), real_name(_realname), number(_num), kind(_kind), category(_category), pic(_pic), inst(inst) { end(); add(pic); Fl_Box *box = new Fl_Box(FL_NO_BOX, X + 4, Y + H - 28, W - 4, 24, desc.c_str()); box->align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER); box->labelcolor(FL_WHITE); box->labelsize(12); add(box); resizable(NULL); } Browser_Item::~Browser_Item() { // TODO } bool Browser_Item::MatchName(const char *name) const { return (y_stricmp(real_name.c_str(), name) == 0); } void Browser_Item::texture_callback(Fl_Widget *w, void *data) { auto item = static_cast(data); item->inst.main_win->BrowsedItem(BrowserMode::textures, 0, item->mPicCallbackString.c_str(), Fl::event_state()); } void Browser_Item::flat_callback(Fl_Widget *w, void *data) { auto item = static_cast(data); item->inst.main_win->BrowsedItem(BrowserMode::flats, 0, item->mPicCallbackString.c_str(), Fl::event_state()); } void Browser_Item::thing_callback(Fl_Widget *w, void *data) { Browser_Item * item = (Browser_Item *) data; item->inst.main_win->BrowsedItem(BrowserMode::things, item->number, "", Fl::event_state()); } void Browser_Item::line_callback(Fl_Widget *w, void *data) { Browser_Item * item = (Browser_Item *) data; item->inst.main_win->BrowsedItem(BrowserMode::lineTypes, item->number, "", Fl::event_state()); } void Browser_Item::sector_callback(Fl_Widget *w, void *data) { Browser_Item * item = (Browser_Item *) data; item->inst.main_win->BrowsedItem(BrowserMode::sectorTypes, item->number, "", Fl::event_state()); } //------------------------------------------------------------------------ inline static bool isGraphicsMode(BrowserMode mode) { return mode == BrowserMode::textures || mode == BrowserMode::flats; } UI_Browser_Box::UI_Browser_Box(Instance &inst, int X, int Y, int W, int H, const char *label, BrowserMode _kind) : Fl_Group(X, Y, W, H, NULL), kind(_kind), pic_mode(false), inst(inst) { end(); // cancel begin() in Fl_Group constructor box(FL_FLAT_BOX); color(BROWBACK_COL, BROWBACK_COL); cat_letters = "*"; int cx = X + 88; int cy = Y + 4; Fl_Box *title = new Fl_Box(X + 34, cy, W - 90, 26, label); title->labelsize(24); add(title); Fl_Button *hide_button = new Fl_Button(X + 8, cy+2, 22, 22, "X"); hide_button->callback(hide_callback, this); hide_button->labelsize(14); add(hide_button); cy += title->h() + 6; category = new Fl_Choice(cx, cy, 160, 22, "Category:"); category->align(FL_ALIGN_LEFT); category->add("ALL"); category->value(0); category->labelsize(16); category->textsize(16); category->callback(category_callback, this); add(category); cy += category->h() + 9; search = new Fl_Input(cx, cy, 120, 22, "Match:"); search->align(FL_ALIGN_LEFT); search->callback(search_callback, this); search->when(FL_WHEN_CHANGED); add(search); cy += search->h() + 6; alpha = NULL; if (!isGraphicsMode(kind)) { alpha = new Fl_Check_Button(cx, cy, 75, 22, " Alpha"); // things need to repopulate (in picture mode anyway) if (kind == BrowserMode::things) alpha->callback(repop_callback, this); else alpha->callback(sort_callback, this); // things usually show pics (with sprite name), so want alpha if (kind == BrowserMode::things) alpha->value(1); add(alpha); } pics = NULL; if (kind == BrowserMode::things) { pics = new Fl_Check_Button(X+172, cy, 64, 22, " Pics"); pics->value(1); pics->callback(repop_callback, this); add(pics); } do_flats = NULL; do_tex = NULL; if (kind == BrowserMode::textures) { do_tex = new Fl_Check_Button(X+86, cy, 64, 22, " Tex"); do_tex->value(1); do_tex->callback(repop_callback, this); do_flats = new Fl_Check_Button(X+162, cy, 64, 22, " Flats"); do_flats->value(1); do_flats->callback(repop_callback, this); add(do_tex); add(do_flats); if (! config::browser_combine_tex) { do_tex->hide(); do_flats->hide(); } } cy += 30; int top_H = cy - Y; scroll = new UI_Scroll(X, cy, W, H-3 - top_H, -1 /* bar_side */); scroll->box(FL_FLAT_BOX); add(scroll); // resize box Fl_Box * rs_box = new Fl_Box(FL_NO_BOX, X + W - 10, Y + top_H, 8, H - top_H, NULL); resizable(rs_box); } void UI_Browser_Box::resize(int X, int Y, int W, int H) { Fl_Group::resize(X, Y, W, H); Fl_Widget * rs_box = resizable(); rs_box->resize(X + W - 10, Y + rs_box->h(), 8, H - rs_box->h()); // rearrange images if (pic_mode) { Filter(); } } void UI_Browser_Box::category_callback(Fl_Widget *w, void *data) { UI_Browser_Box *that = (UI_Browser_Box *)data; that->ClearSearchBox(); that->Filter(); } void UI_Browser_Box::search_callback(Fl_Widget *w, void *data) { UI_Browser_Box *that = (UI_Browser_Box *)data; that->Filter(); } void UI_Browser_Box::hide_callback(Fl_Widget *w, void *data) { auto box = static_cast(data); box->inst.main_win->BrowserMode(BrowserMode::hide); } void UI_Browser_Box::repop_callback(Fl_Widget *w, void *data) { UI_Browser_Box *that = (UI_Browser_Box *)data; that->Populate(); } void UI_Browser_Box::sort_callback(Fl_Widget *w, void *data) { UI_Browser_Box *that = (UI_Browser_Box *)data; that->Sort(); } bool UI_Browser_Box::Filter(bool force_update) { bool changes = false; int left_X = scroll->x() + SBAR_W; int right_X = left_X + scroll->w() - SBAR_W; // current position int cx = left_X; int cy = scroll->y(); // the highest visible widget on the current line int highest = 0; for (int i = 0 ; i < scroll->Children() ; i++) { Browser_Item *item = (Browser_Item *)scroll->Child(i); item->redraw(); bool keep = SearchMatch(item); if (keep != (item->visible() ? true : false)) { if (keep) item->show(); else item->hide(); changes = true; } if (! keep) { item->position(cx, cy); continue; } // can it fit on the current row? if (pic_mode && (cx <= left_X || (cx + item->w()) <= right_X)) { // Yes } else { // No, move down to the next row cx = left_X; cy += highest; highest = 0; } // update position item->position(cx, cy); cx += item->w(); highest = std::max(highest, item->h()); } scroll->Init_sizes(); scroll->redraw(); return changes; } bool UI_Browser_Box::SearchMatch(Browser_Item *item) const { if (config::browser_combine_tex && kind == BrowserMode::textures) { if (item->kind == BrowserMode::textures && !do_tex->value()) return false; if (item->kind == BrowserMode::flats && !do_flats->value()) return false; } if (category->value() > 0) { char cat = cat_letters[category->value()]; // special logic for RECENT category [ignore search box] if (cat == '^') return (item->recent_idx >= 0); if (! (cat == tolower(item->category) || (cat == 'X' && isupper(item->category)))) return false; } // here an empty pattern matches EVERYTHING // [ different to Texture_MatchPattern semantics ] if (search->size() == 0) return true; const char *pattern = search->value(); if (isGraphicsMode(kind)) return Texture_MatchPattern(item->real_name.c_str(), pattern); return Texture_MatchPattern(item->desc.c_str(), pattern); } bool UI_Browser_Box::Recent_UpdateItem(Browser_Item *item) { // returns true if the index changed int new_idx = -1; switch (item->kind) { case BrowserMode::textures: new_idx = inst.recent_textures.find(item->real_name); if (new_idx < 0) new_idx = inst.recent_flats.find(item->real_name); break; case BrowserMode::flats: new_idx = inst.recent_flats.find(item->real_name); if (new_idx < 0) new_idx = inst.recent_textures.find(item->real_name); break; case BrowserMode::things: new_idx = inst.recent_things.find_number(item->number); break; default: return false; } if (item->recent_idx == new_idx) return false; item->recent_idx = new_idx; return true; } static int SortCmp(const Browser_Item *A, const Browser_Item *B, sort_method_e method) { const char *sa = A->desc.c_str(); const char *sb = B->desc.c_str(); if (method == SOM_Numeric) { return (A->number - B->number); } else if (method == SOM_Recent) { return (A->recent_idx - B->recent_idx); } if (strchr(sa, '/')) sa = strchr(sa, '/') + 1; if (strchr(sb, '/')) sb = strchr(sb, '/') + 1; // Alphabetical in LINEDEF mode, skip trigger type (SR etc) if (method == SOM_AlphaSkip) { while (isspace(*sa)) sa++; while (isspace(*sb)) sb++; if (sa[0] && sa[1] && sa[2] == ' ') while (! isspace(*sa)) sa++; if (sb[0] && sb[1] && sb[2] == ' ') while (! isspace(*sb)) sb++; } return strcmp(sa, sb); } static void SortPass(std::vector< Browser_Item * >& ARR, int gap, int total, sort_method_e method) { int i, k; for (i = gap ; i < total ; i++) { Browser_Item * temp = ARR[i]; for (k = i ; k >= gap && SortCmp(ARR[k - gap], temp, method) > 0 ; k -= gap) ARR[k] = ARR[k - gap]; ARR[k] = temp; } } void UI_Browser_Box::Sort() { int total = scroll->Children(); // transfer widgets to a local vector std::vector< Browser_Item * > ARR; for (int i = 0 ; i < total ; i++) { ARR.push_back( (Browser_Item *) scroll->Child(0)); scroll->Remove_first(); } char cat = cat_letters[category->value()]; sort_method_e method = SOM_Alpha; if (cat == '^') method = SOM_Recent; else if (alpha && ! alpha->value()) method = SOM_Numeric; else if (kind == BrowserMode::lineTypes) method = SOM_AlphaSkip; // shell sort SortPass(ARR, 9, total, method); SortPass(ARR, 4, total, method); SortPass(ARR, 1, total, method); // transfer them back to the scroll widget for (int i = 0 ; i < total ; i++) scroll->Add(ARR[i]); // reposition them all Filter(true); } SString TidyLineDesc(const char *name) { // escapes any '&' characters for FLTK if (! strchr(name, '&')) return name; SString buffer; for (const char *src = name ; *src ; src++) { if (*src == '&') { buffer += '&'; buffer += '&'; continue; } buffer += *src; } return buffer; } void UI_Browser_Box::Populate_Images(BrowserMode imkind, const std::map & img_list) { /* Note: the side-by-side packing is done in Filter() method */ pic_mode = true; scroll->color(FL_BLACK, FL_BLACK); scroll->resize_horiz(false); scroll->Line_size(98); std::map::const_iterator TI; int cx = scroll->x() + SBAR_W; int cy = scroll->y(); char full_desc[256]; for (TI = img_list.begin() ; TI != img_list.end() ; TI++) { const SString &name = TI->first; const Img_c &image = TI->second; if ((false)) /* NO PICS */ snprintf(full_desc, sizeof(full_desc), "%-8s : %3dx%d", name.c_str(), image.width(), image.height()); else snprintf(full_desc, sizeof(full_desc), "%-8s", name.c_str()); int pic_w = (kind == BrowserMode::flats || image.width() <= 64) ? 64 : 128; // MIN(128, MAX(4, image->width())); int pic_h = (kind == BrowserMode::flats) ? 64 : std::min(128, std::max(4, image.height())); if (config::browser_small_tex && imkind == BrowserMode::textures) { pic_w = 64; pic_h = std::min(64, std::max(4, image.height())); } if (image.width() >= 256 && image.height() == 128) { pic_w = 128; pic_h = 64; } int item_w = 8 + std::max(pic_w, 64) + 2; int item_h = 4 + std::max(pic_h, 16) + 2 + 24 + 4; char item_cat = 0; UI_Pic *pic = new UI_Pic(inst, cx + 8, cy + 4, pic_w, pic_h); if (imkind == BrowserMode::flats) item_cat = inst.M_GetFlatType(name); else if (imkind == BrowserMode::textures) item_cat = inst.M_GetTextureType(name); Browser_Item *item = new Browser_Item(inst, cx, cy, item_w, item_h, full_desc, name, 0 /* num */, imkind, item_cat, pic_w, pic_h, pic); if(imkind == BrowserMode::flats) { pic->GetFlat(name); item->setPicCallbackString(name); pic->callback(Browser_Item::flat_callback, item); } else if(imkind == BrowserMode::textures) { pic->GetTex(name); item->setPicCallbackString(name); pic->callback(Browser_Item::texture_callback, item); } scroll->Add(item); } } void UI_Browser_Box::Populate_Sprites() { /* Note: the side-by-side packing is done in Filter() method */ pic_mode = true; scroll->color(FL_BLACK, FL_BLACK); scroll->resize_horiz(false); scroll->Line_size(98); std::map::iterator TI; int cx = scroll->x() + SBAR_W; int cy = scroll->y(); char full_desc[256]; for (TI = inst.conf.thing_types.begin() ; TI != inst.conf.thing_types.end() ; TI++) { const thingtype_t &info = TI->second; // ignore sprite-less things if (y_stricmp(info.sprite.c_str(), "NULL") == 0) continue; if (alpha->value() == 0) snprintf(full_desc, sizeof(full_desc), "%d", TI->first); else snprintf(full_desc, sizeof(full_desc), "%s", info.sprite.c_str()); int pic_w = 64; int pic_h = 72; int item_w = 8 + std::max(pic_w, 64) + 2; int item_h = 4 + std::max(pic_h, 16) + 2 + 24 + 4; UI_Pic *pic = new UI_Pic(inst, cx + 8, cy + 4, pic_w, pic_h); pic->GetSprite(TI->first, FL_BLACK); Browser_Item *item = new Browser_Item(inst, cx, cy, item_w, item_h, full_desc, "", TI->first, kind, info.group, pic_w, pic_h, pic); pic->callback(Browser_Item::thing_callback, item); scroll->Add(item); } } void UI_Browser_Box::Populate_ThingTypes() { std::map::iterator TI; int y = scroll->y(); int mx = scroll->x() + SBAR_W; int mw = scroll->w() - SBAR_W; char full_desc[256]; for (TI = inst.conf.thing_types.begin() ; TI != inst.conf.thing_types.end() ; TI++) { const thingtype_t &info = TI->second; snprintf(full_desc, sizeof(full_desc), "%4d/ %s", TI->first, info.desc.c_str()); Browser_Item *item = new Browser_Item(inst, mx, y, mw, 24, full_desc, "", TI->first, kind, info.group); item->button->callback(Browser_Item::thing_callback, item); scroll->Add(item); } } void UI_Browser_Box::Populate_LineTypes() { std::map::iterator TI; int y = scroll->y(); int mx = scroll->x() + SBAR_W; int mw = scroll->w() - SBAR_W; char full_desc[256]; for (TI = inst.conf.line_types.begin() ; TI != inst.conf.line_types.end() ; TI++) { const linetype_t &info = TI->second; snprintf(full_desc, sizeof(full_desc), "%3d/ %s", TI->first, TidyLineDesc(info.desc.c_str()).c_str()); Browser_Item *item = new Browser_Item(inst, mx, y, mw, 24, full_desc, "", TI->first, kind, info.group); item->button->callback(Browser_Item::line_callback, item); scroll->Add(item); } } void UI_Browser_Box::Populate_SectorTypes() { std::map::iterator TI; int y = scroll->y(); int mx = scroll->x() + SBAR_W; int mw = scroll->w() - SBAR_W; char full_desc[256]; for (TI = inst.conf.sector_types.begin() ; TI != inst.conf.sector_types.end() ; TI++) { const sectortype_t &info = TI->second; snprintf(full_desc, sizeof(full_desc), "%3d/ %s", TI->first, info.desc.c_str()); Browser_Item *item = new Browser_Item(inst, mx, y, mw, 24, full_desc, "", TI->first, kind, 0 /* cat */); item->button->callback(Browser_Item::sector_callback, item); scroll->Add(item); } } void UI_Browser_Box::Populate() { // delete existing ones scroll->Remove_all(); // default background and scroll rate scroll->color(WINDOW_BG, WINDOW_BG); scroll->resize_horiz(true); scroll->Line_size(24 * 2); // handle changes to combine-tex preference if (kind == BrowserMode::textures) { if (config::browser_combine_tex) { do_tex->show(); do_flats->show(); } else { do_tex->hide(); do_flats->hide(); } } pic_mode = false; switch (kind) { case BrowserMode::textures: if (config::browser_combine_tex) Populate_Images(BrowserMode::flats, inst.wad.images.getFlats()); Populate_Images(BrowserMode::textures, inst.wad.images.getTextures()); break; case BrowserMode::flats: // the flat browser is never used when combine-tex is enabled if (! config::browser_combine_tex) Populate_Images(BrowserMode::flats, inst.wad.images.getFlats()); break; case BrowserMode::things: if (pics->value()) Populate_Sprites(); else Populate_ThingTypes(); break; case BrowserMode::lineTypes: Populate_LineTypes(); break; case BrowserMode::sectorTypes: Populate_SectorTypes(); break; default: break; } RecentUpdate(); // this calls Filter to reposition the widgets Sort(); } void UI_Browser_Box::SetCategories(const SString &cats, const SString &letters) { cat_letters = letters; category->clear(); category->add(cats.c_str()); category->value(0); redraw(); } void UI_Browser_Box::CycleCategory(int dir) { // need '- 1' since the size() includes the empty terminator int total_cats = category->size() - 1; if (total_cats <= 1) return; int new_cat = category->value(); for (int loop = 0 ; loop < 2 ; loop++) { if (dir > 0) { new_cat = (new_cat + 1) % total_cats; } else if (dir < 0) { new_cat = (new_cat + total_cats - 1) % total_cats; } // skip the RECENT category if (new_cat != 1) break; } if (category->value(new_cat)) { Filter(); } } bool UI_Browser_Box::CategoryByLetter(char letter) { // need '- 1' since the size() includes the empty terminator int total_cats = category->size() - 1; for (int i = 0 ; i < total_cats ; i++) { if (cat_letters[i] == letter) { category->value(i); Filter(); return true; } } return false; } void UI_Browser_Box::ClearSearchBox() { if (search->size() > 0) { search->value(""); Filter(); } } void UI_Browser_Box::JumpToTex(const char *tex_name) { if (!isGraphicsMode(kind)) return; for (int i = 0 ; i < scroll->Children() ; i++) { Browser_Item *item = (Browser_Item *)scroll->Child(i); // REVIEW THIS if (! item->visible()) continue; if (item->MatchName(tex_name)) { scroll->JumpToChild(i); break; } } } void UI_Browser_Box::JumpToValue(int value) { if (isGraphicsMode(kind)) return; for (int i = 0 ; i < scroll->Children() ; i++) { Browser_Item *item = (Browser_Item *)scroll->Child(i); // REVIEW THIS if (! item->visible()) continue; if (item->number == value) { scroll->JumpToChild(i); break; } } } void UI_Browser_Box::Scroll(int delta) { scroll->Scroll(delta); } void UI_Browser_Box::RecentUpdate() { bool changes = false; for (int i = 0 ; i < scroll->Children() ; i++) { Browser_Item *item = (Browser_Item *)scroll->Child(i); if (Recent_UpdateItem(item)) changes = true; } char cat = cat_letters[category->value()]; if (changes && cat == '^') Sort(); } void UI_Browser_Box::ToggleRecent(bool force_recent) { char cat = cat_letters[category->value()]; if (cat == '^' && force_recent) { Filter(); return; } // this logic assumes first category is ALL, second is RECENT if (cat_letters[1] != '^') return; int new_cat = (cat == '^') ? 0 : 1; category->value(new_cat); Sort(); } //------------------------------------------------------------------------ class UI_Generalized_Item : public Fl_Choice { public: const generalized_field_t field; public: UI_Generalized_Item(int X, int Y, int W, int H, const generalized_field_t *_field) : Fl_Choice(X, Y, W, H, ""), field(*_field) { char label_buf[256]; snprintf(label_buf, sizeof(label_buf), "%s: ", field.name.c_str()); copy_label(label_buf); for (const auto &keyword : field.keywords) { add(keyword.c_str()); } Reset(); } ~UI_Generalized_Item() { } int Compute() const { return (value() << field.shift) & field.mask; } void Decode(int line_type) { value((line_type & field.mask) >> field.shift); } void Reset() { int def_val = clamp(0, field.default_val, static_cast(field.keywords.size()) - 1); value(def_val); } }; class UI_Generalized_Page : public Fl_Group { public: int t_base; int t_length; UI_Generalized_Item * items[MAX_GEN_NUM_FIELDS]; int num_items; // index for the "Change", "Model", "Monster" triplet, usually -1 int change_index; UI_Generalized_Item *change_widget; private: static void item_callback(Fl_Widget *w, void *data) { UI_Generalized_Page *page = (UI_Generalized_Page *)data; if (w == page->change_widget) page->UpdateChange(); page->do_callback(); } public: UI_Generalized_Page(int X, int Y, int W, int H, const generalized_linetype_t *info) : Fl_Group(X, Y, W, H), t_base(info->base), t_length(info->length), num_items(0), change_index(-1), change_widget(NULL) { #if 0 box(FL_FLAT_BOX); color(FL_BLUE, FL_BLUE); #endif memset(items, 0, sizeof(items)); num_items = (int)info->fields.size(); Y += 5; for (int i = 0 ; i < num_items ; i++) { bool is_change = (y_stricmp(info->fields[i].name.c_str(), "Change") == 0); if (is_change) Y += 10; items[i] = new UI_Generalized_Item(X + 100, Y, 120, 22, &info->fields[i]); items[i]->callback(item_callback, this); if (is_change && (i+2) < num_items) { change_index = i; change_widget = items[i]; } if (change_index >= 0 && i == change_index+1) items[i]->deactivate(); Y += 30; } end(); } ~UI_Generalized_Page() { } void UpdateChange() { if (change_index < 0) return; if (items[change_index]->value() == 0) { items[change_index+1]->deactivate(); items[change_index+2]-> activate(); } else { items[change_index+1]-> activate(); items[change_index+2]->deactivate(); } } int ComputeType() const { int value = 0; for (int i = 0 ; i < num_items ; i++) { if (items[i]->active()) value = value | items[i]->Compute(); } return t_base + value; } void DecodeType(int line_type) { line_type -= t_base; for (int i = 0 ; i < num_items ; i++) { items[i]->Decode(line_type); } UpdateChange(); } void ResetFields() { for (int i = 0 ; i < num_items ; i++) { items[i]->Reset(); } } }; UI_Generalized_Box::UI_Generalized_Box(Instance &inst, int X, int Y, int W, int H, const char *label) : Fl_Group(X, Y, W, H, NULL), num_pages(0), in_update(false), inst(inst) { box(FL_FLAT_BOX); color(BROWBACK_COL, BROWBACK_COL); memset(pages, 0, sizeof(pages)); int orig_X = X; /// X = X + (W - MIN_BROWSER_W); Y += 10; Fl_Box *title = new Fl_Box(X + 30, Y, W - 114, 26, label); title->labelsize(24); Fl_Button *hide_button = new Fl_Button(X + 8, Y+2, 22, 22, "X"); hide_button->callback(hide_callback, this); hide_button->labelsize(14); Y += title->h() + 6; no_boom = new Fl_Box(FL_NO_BOX, X + 2, Y + 40, W - 60, 60, "This requires BOOM\n(or a compatible port)"); no_boom->labelsize(18); no_boom->labelcolor(FL_BLUE); no_boom->align(FL_ALIGN_INSIDE); Y += 10; category = new Fl_Choice(X + 40, Y, 170, 30); category->callback(cat_callback, this); category->textsize(16); end(); // resize box Fl_Box * rs_box = new Fl_Box(FL_NO_BOX, orig_X + W - 10, Y + H - 10, 8, 8, NULL); resizable(rs_box); } UI_Generalized_Box::~UI_Generalized_Box() { // nothing needed } void UI_Generalized_Box::Populate() { if (! inst.conf.features.gen_types) { no_boom->show(); category->hide(); for (int i = 0 ; i < num_pages ; i++) pages[i]->hide(); } else { // we only create the pages once // [ not strictly correct, but the generalized types never change ] if (! pages[0]) CreatePages(); no_boom->hide(); category->show(); for (int i = 0 ; i < num_pages ; i++) { if (i == category->value() - 1) pages[i]->show(); else pages[i]->hide(); } } redraw(); } void UI_Generalized_Box::CreatePages() { memset(pages, 0, sizeof(pages)); num_pages = 0; category->clear(); category->add("NONE"); int X = x(); /// + (w() - MIN_BROWSER_W); for (int i = 0 ; i < inst.conf.num_gen_linetypes ; i++) { const generalized_linetype_t *info = &inst.conf.gen_linetypes[i]; category->add(info->name.c_str()); pages[i] = new UI_Generalized_Page(X + 10, y() + 100, 230, 300, info); pages[i]->callback(edit_callback, this); add(pages[i]); num_pages += 1; } category->value(0); } int UI_Generalized_Box::ComputeType() const { int cur_page = category->value(); if (cur_page == 0) return 0; return pages[cur_page - 1]->ComputeType(); } void UI_Generalized_Box::UpdateGenType(int line_type) { if (in_update) return; if (no_boom->visible() || num_pages == 0) return; int new_page = -1; for (int i = 0 ; i < num_pages ; i++) { if (pages[i]->t_base <= line_type && line_type < pages[i]->t_base + pages[i]->t_length) { new_page = i; break; } } if (new_page < 0) { for (int k = 0 ; k < num_pages ; k++) pages[k]->ResetFields(); if (category->value() != 0) { category->value(0); Populate(); } return; } if (category->value() != new_page + 1) { category->value(new_page + 1); Populate(); } pages[new_page]->DecodeType(line_type); } void UI_Generalized_Box::hide_callback(Fl_Widget *w, void *data) { auto box = static_cast(data); box->inst.main_win->BrowserMode(BrowserMode::hide); } void UI_Generalized_Box::cat_callback(Fl_Widget *w, void *data) { UI_Generalized_Box *box = (UI_Generalized_Box *)data; int new_page = box->category->value() - 1; for (int i = 0 ; i < box->num_pages ; i++) { if (i == new_page) box->pages[i]->show(); else box->pages[i]->hide(); } edit_callback(w, (void *)box); box->redraw(); } void UI_Generalized_Box::edit_callback(Fl_Widget *w, void *data) { UI_Generalized_Box *box = (UI_Generalized_Box *)data; if (box->no_boom->visible() || box->num_pages == 0) return; box->in_update = true; // prevent some useless work { int line_type = box->ComputeType(); box->inst.main_win->BrowsedItem(BrowserMode::lineTypes, line_type, "", 0); } box->in_update = false; } //------------------------------------------------------------------------ UI_Browser::UI_Browser(Instance &inst, int X, int Y, int W, int H, const char *label) : Fl_Group(X, Y, W, H, label), inst(inst) { // create each browser box BrowserMode modes[5] = { BrowserMode::textures, BrowserMode::flats, BrowserMode::things, BrowserMode::lineTypes, BrowserMode::sectorTypes }; const char *mode_titles[5] = { "Textures", "Flats", "Things", "Line Specials", "Sector Types" }; for (int i = 0 ; i < 5 ; i++) { browsers[i] = new UI_Browser_Box(inst, X, Y, W, H, mode_titles[i], modes[i]); if (i != active) browsers[i]->hide(); } gen_box = new UI_Generalized_Box(inst, X, Y, W, H, "Generalized"); gen_box->hide(); end(); } void UI_Browser::Populate() { for (int i = 0 ; i < 5 ; i++) { browsers[i]->Populate(); } gen_box->Populate(); // setup the categories SString letters; SString tex_cats = inst.M_TextureCategoryString(letters, false); browsers[0]->SetCategories(tex_cats, letters); SString flat_cats = inst.M_TextureCategoryString(letters, true); browsers[1]->SetCategories(flat_cats, letters); SString thing_cats = inst.M_ThingCategoryString(letters); browsers[2]->SetCategories(thing_cats, letters); SString line_cats = inst.M_LineCategoryString(letters); browsers[3]->SetCategories(line_cats, letters); // TODO: sector_cats // no ceiling_cats, fortunately :) } void UI_Browser::SetActive(int new_active) { if (new_active == active) return; if (active < ACTIVE_GENERALIZED) browsers[active]->hide(); else gen_box->hide(); active = new_active; if (active < ACTIVE_GENERALIZED) { browsers[active]->show(); browsers[active]->RecentUpdate(); } else { gen_box->show(); } if (new_active == ACTIVE_GENERALIZED) inst.main_win->tile->MinimiseRight(); } BrowserMode UI_Browser::GetMode() const { switch (active) { case 0: return BrowserMode::textures; case 1: return BrowserMode::flats; case 2: return BrowserMode::things; case 3: return BrowserMode::lineTypes; case 4: return BrowserMode::sectorTypes; default: return BrowserMode::generalized; } } void UI_Browser::ChangeMode(BrowserMode new_mode) { if (config::browser_combine_tex && new_mode == BrowserMode::flats) new_mode = BrowserMode::textures; switch (new_mode) { case BrowserMode::textures: SetActive(0); break; // TEXTURES case BrowserMode::flats: SetActive(1); break; // FLATS case BrowserMode::things: SetActive(2); break; // THINGS (Objects) case BrowserMode::lineTypes: SetActive(3); break; // LINE TYPES case BrowserMode::sectorTypes: SetActive(4); break; // SECTOR TYPES case BrowserMode::generalized: SetActive(ACTIVE_GENERALIZED); break; default: break; } } void UI_Browser::NewEditMode(ObjType edit_mode) { switch (edit_mode) { case ObjType::linedefs: // if on LINE TYPES, stay there // otherwise go to TEXTURES if (! (active == 3 || active == ACTIVE_GENERALIZED)) SetActive(0); break; case ObjType::sectors: // if on SECTOR TYPES, stay there // otherwise go to FLATS if (active != 4) SetActive(config::browser_combine_tex ? 0 : 1); break; case ObjType::things: SetActive(2); break; default: /* no change */ break; } } void UI_Browser::JumpToTex(const char *tex_name) { if (active < ACTIVE_GENERALIZED) { browsers[active]->JumpToTex(tex_name); } } void UI_Browser::JumpToValue(int value) { if (active < ACTIVE_GENERALIZED) { browsers[active]->JumpToValue(value); } } void UI_Browser::CycleCategory(int dir) { if (active < ACTIVE_GENERALIZED) { browsers[active]->CycleCategory(dir); } } void UI_Browser::ClearSearchBox() { if (active < ACTIVE_GENERALIZED) { browsers[active]->ClearSearchBox(); } // idea : reset generalized info } void UI_Browser::Scroll(int delta) { if (active < ACTIVE_GENERALIZED) { browsers[active]->Scroll(delta); } } void UI_Browser::RecentUpdate() { if (active < ACTIVE_GENERALIZED) { UI_Browser_Box *box = browsers[active]; box->RecentUpdate(); } } void UI_Browser::ToggleRecent(bool force_recent) { // show browser if hidden [ and then force the RECENT category ] if (! visible()) { inst.main_win->BrowserMode(BrowserMode::toggle); force_recent = true; } if (active < ACTIVE_GENERALIZED) { browsers[active]->ToggleRecent(force_recent); } } void UI_Browser::UpdateGenType(int line_type) { gen_box->UpdateGenType(line_type); } //------------------------------------------------------------------------ bool UI_Browser_Box::ParseUser(const std::vector &tokens) { // syntax is: browser if (tokens.size() < 3) return false; if (tokens[0] != "browser") return false; if (tokens[1][0] != browserModeToChar(kind)) return false; size_t num_tok = tokens.size() - 2; if (tokens[2] == "cat" && num_tok >= 2) { CategoryByLetter(tokens[3][0]); return true; } if (tokens[2] == "sort" && num_tok >= 2 && alpha) { alpha->value(atoi(tokens[3]) ? 0 : 1); Sort(); return true; } if (tokens[2] == "search" && num_tok >= 2) { search->value(tokens[3].c_str()); Filter(); return true; } if (tokens[2] == "pics" && num_tok >= 2 && pics) { pics->value(atoi(tokens[3]) ? 1 : 0); return true; } if (tokens[2] == "do_flats" && num_tok >= 2 && do_flats) { do_flats->value(atoi(tokens[3]) ? 1 : 0); return true; } if (tokens[2] == "do_tex" && num_tok >= 2 && do_tex) { do_tex->value(atoi(tokens[3]) ? 1 : 0); Filter(); return true; } return true; } void UI_Browser_Box::WriteUser(std::ostream &os) { char cat = cat_letters[category->value()]; if(isprint(cat)) os << "browser " << browserModeToChar(kind) << " cat " << cat << '\n'; if(alpha) os << "browser " << browserModeToChar(kind) << " sort " << static_cast(1 - alpha->value()) << '\n'; os << "browser " << browserModeToChar(kind) << " search \"" << SString(search->value()).getTidy("\"") << "\"\n"; if(pics) os << "browser " << browserModeToChar(kind) << " pics " << static_cast(pics->value()) << '\n'; if(do_flats) { os << "browser " << browserModeToChar(kind) << " do_flats " << static_cast(do_flats->value()) << '\n'; os << "browser " << browserModeToChar(kind) << " do_tex " << static_cast(do_tex->value()) << '\n'; } } bool UI_Browser::ParseUser(const std::vector &tokens) { if (tokens[0] == "open_browser" && tokens.size() >= 2) { inst.main_win->BrowserMode(charToBrowserMode(tokens[1][0])); return true; } for (int i = 0 ; i < 5 ; i++) { if (browsers[i]->ParseUser(tokens)) return true; } return false; } void UI_Browser::WriteUser(std::ostream &os) { os << "\nopen_browser " << (!visible() ? '-' : active >= ACTIVE_GENERALIZED ? 'G' : browserModeToChar(browsers[active]->GetKind())) << '\n'; for(int i = 0; i < 5; i++) { browsers[i]->WriteUser(os); } // generalized box is not saved (not needed) } bool Browser_ParseUser(Instance &inst, const std::vector &tokens) { if (inst.main_win) { if (inst.main_win->tile->ParseUser(tokens)) return true; if (inst.main_win->browser->ParseUser(tokens)) return true; } return false; } void Instance::Browser_WriteUser(std::ostream &os) const { if (main_win) { main_win->tile->WriteUser(os); main_win->browser->WriteUser(os); } } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_browser.h000066400000000000000000000147171464327712600206730ustar00rootroot00000000000000//------------------------------------------------------------------------ // BROWSER for TEXTURES / FLATS / THINGS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2019 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_BROWSER_H__ #define __EUREKA_UI_BROWSER_H__ #include #include #include class Browser_Button; class Fl_Check_Button; class Fl_Choice; enum class BrowserMode { textures, flats, things, lineTypes, sectorTypes, generalized, invalid, hide, toggle }; class Browser_Item : public Fl_Group { private: public: SString desc; SString real_name; // for textures and flats only int number; BrowserMode kind; // generally matches browser kind: T/F/O/S/L char category; int recent_idx = -2; Browser_Button * button = nullptr; UI_Pic *pic = nullptr; SString mPicCallbackString; // optional, storage for callback data string Instance &inst; public: // this constructor makes a simple text button Browser_Item(Instance &inst, int X, int Y, int W, int H, const SString &_desc, const SString &_realname, int _num, BrowserMode _kind, char _category); // this constructor makes a picture with a text label below it Browser_Item(Instance &inst, int X, int Y, int W, int H, const SString &_desc, const SString &_realname, int _num, BrowserMode _kind, char _category, int pic_w, int pic_h, UI_Pic *_pic); virtual ~Browser_Item(); bool MatchName(const char *name) const; // // Assigns the given string and returns the pointer to it (can't be const due to void*) // void setPicCallbackString(const SString &text) { mPicCallbackString = text; } public: static void texture_callback(Fl_Widget *w, void *data); static void flat_callback(Fl_Widget *w, void *data); static void thing_callback(Fl_Widget *w, void *data); static void line_callback(Fl_Widget *w, void *data); static void sector_callback(Fl_Widget *w, void *data); private: }; class UI_Browser_Box : public Fl_Group { private: BrowserMode kind; Fl_Choice *category; Fl_Input *search; Fl_Check_Button *alpha; Fl_Check_Button *pics; Fl_Check_Button *do_tex; Fl_Check_Button *do_flats; UI_Scroll *scroll; bool pic_mode; SString cat_letters; Instance &inst; public: UI_Browser_Box(Instance &inst, int X, int Y, int W, int H, const char *label, BrowserMode _kind); /* FLTK method */ void resize(int X, int Y, int W, int H); public: void Populate(); void SetCategories(const SString &cats, const SString &letters); void CycleCategory(int dir); void ToggleRecent(bool force_recent); void ClearSearchBox(); void Scroll(int delta); BrowserMode GetKind() const { return kind; } // ensure the given texture or type/special is visible void JumpToTex(const char *tex_name); void JumpToValue(int value); void RecentUpdate(); bool ParseUser(const std::vector &tokens); void WriteUser(std::ostream &os); private: // adjust the widgets in the Fl_Scroll based on current search // parameters. Returns true if something changed. bool Filter(bool force_update = false); void Sort(); bool SearchMatch(Browser_Item *item) const; void Populate_Images(BrowserMode imkind, const std::map & img_list); void Populate_Sprites(); void Populate_ThingTypes(); void Populate_LineTypes(); void Populate_SectorTypes(); bool Recent_UpdateItem(Browser_Item *item); bool CategoryByLetter(char letter); static void category_callback(Fl_Widget *w, void *data); static void search_callback(Fl_Widget *w, void *data); static void hide_callback(Fl_Widget *w, void *data); static void repop_callback(Fl_Widget *w, void *data); static void sort_callback(Fl_Widget *w, void *data); }; class UI_Generalized_Page; class UI_Generalized_Box : public Fl_Group { private: // overall kind of line (DOOR, LIFT, etc...) Fl_Choice * category; // this is shown when not in Boom mode Fl_Box * no_boom; enum { MAX_PAGES = 16 }; UI_Generalized_Page * pages[MAX_PAGES]; int num_pages; int in_update; Instance &inst; public: UI_Generalized_Box(Instance &inst, int X, int Y, int W, int H, const char *label); virtual ~UI_Generalized_Box(); void Populate(); void UpdateGenType(int line_type); private: void CreatePages(); int ComputeType() const; static void hide_callback(Fl_Widget *w, void *data); static void cat_callback(Fl_Widget *w, void *data); static void edit_callback(Fl_Widget *w, void *data); }; class UI_Browser : public Fl_Group { /* this widget basically just contains all the browser boxes, * and controls which one is visible at any time. */ private: UI_Browser_Box *browsers[5]; UI_Generalized_Box *gen_box; enum { ACTIVE_GENERALIZED = 5 }; // currently active browser box (may be hidden though) int active = 2; Instance &inst; public: UI_Browser(Instance &inst, int X, int Y, int W, int H, const char *label = NULL); public: void Populate(); void SetActive(int new_active); BrowserMode GetMode() const; void ChangeMode(BrowserMode new_mode); void NewEditMode(ObjType edit_mode); // ensure the given texture or type/special is visible void JumpToTex(const char *tex_name); void JumpToValue(int value); // dir is +1 or -1, or 0 to set the category to "ALL" void CycleCategory(int dir); void ToggleRecent(bool force_recent = false); void ClearSearchBox(); void Scroll(int delta); // recently used textures (etc) has changed void RecentUpdate(); // for the generalized box void UpdateGenType(int line_type); bool ParseUser(const std::vector &tokens); void WriteUser(std::ostream &os); private: // static void mode_callback(Fl_Widget *w, void *data); }; bool Browser_ParseUser(Instance &inst, const std::vector &tokens); BrowserMode charToBrowserMode(char c); bool charMapsToSpecificBrowserMode(char c); #endif /* __EUREKA_UI_BROWSER_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_canvas.cc000066400000000000000000002026561464327712600206220ustar00rootroot00000000000000//------------------------------------------------------------------------ // EDITING CANVAS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2019 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Instance.h" #include "main.h" #include #ifndef NO_OPENGL #include "FL/gl.h" #include "FL/glu.h" #endif #include "ui_window.h" #include "m_events.h" #include "e_main.h" #include "e_hover.h" #include "e_linedef.h" #include "e_sector.h" #include "e_things.h" #include "e_path.h" // SoundPropagation #include "im_color.h" #include "im_img.h" #include "LineDef.h" #include "m_config.h" #include "m_game.h" #include "m_vector.h" #include "r_grid.h" #include "r_subdiv.h" #include "r_render.h" #include "Sector.h" #include "SideDef.h" #include "Thing.h" #include "Vertex.h" #include "w_rawdef.h" // MLF_xxx #include "w_texture.h" #include #define CAMERA_COLOR fl_rgb_color(255, 192, 255) typedef enum { LINFO_Nothing = 0, LINFO_Length, LINFO_Angle, LINFO_Ratio, LINFO_Length_Angle, LINFO_Length_Ratio } line_info_mode_e; // config items rgb_color_t config::dotty_axis_col = rgbMake(0, 128, 255); rgb_color_t config::dotty_major_col = rgbMake(0, 0, 238); rgb_color_t config::dotty_minor_col = rgbMake(0, 0, 187); rgb_color_t config::dotty_point_col = rgbMake(0, 0, 255); rgb_color_t config::normal_axis_col = rgbMake(0, 128, 255); rgb_color_t config::normal_main_col = rgbMake(0, 0, 238); rgb_color_t config::normal_flat_col = rgbMake(60, 60, 120); rgb_color_t config::normal_small_col = rgbMake(60, 60, 120); int config::highlight_line_info = (int)LINFO_Length; int vertex_radius(double scale); UI_Canvas::UI_Canvas(Instance &inst, int X, int Y, int W, int H, const char *label) : #ifdef NO_OPENGL Fl_Widget(X, Y, W, H, label), #else Fl_Gl_Window(X, Y, W, H), #endif last_highlight(), last_splitter(-1), last_split_x(), last_split_y(), snap_x(-1), snap_y(-1), seen_sectors(), inst(inst) { #ifdef NO_OPENGL rgb_buf = NULL; #endif } UI_Canvas::~UI_Canvas() { } void UI_Canvas::DeleteContext() { #ifndef NO_OPENGL context(NULL, 0); // ensure W_UnloadAllTextures() gets called on next draw() invalidate(); #endif } void UI_Canvas::resize(int X, int Y, int W, int H) { #ifdef NO_OPENGL Fl_Widget::resize(X, Y, W, H); #else Fl_Gl_Window::resize(X, Y, W, H); #endif } void UI_Canvas::draw() { #ifndef NO_OPENGL if (! valid()) { // reset the 'gl_tex' field of all loaded images, as the value // belongs to a context which was (probably) just deleted and // hence refer to textures which no longer exist. inst.wad.images.W_UnloadAllTextures(); } #ifndef _WIN32 // TODO: #56: reenable this for Windows static bool tried; if(!tried) { tried = true; const GLubyte *strExt = glGetString(GL_EXTENSIONS); if(strExt) global::use_npot_textures = gluCheckExtension((const GLubyte *)"GL_ARB_texture_non_power_of_two", strExt) == GLU_TRUE; } #endif #endif if (inst.edit.render3d) { Render3D_Draw(inst, x(), y(), w(), h()); return; } #ifdef NO_OPENGL xx = x(); yy = y(); map_lx = floor(MAPX(xx)); map_ly = floor(MAPY(yy + h())); map_hx = ceil(MAPX(xx + w())); map_hy = ceil(MAPY(yy)); #else // OpenGL xx = yy = 0; map_lx = floor(MAPX(0)); map_ly = floor(MAPY(0)); map_hx = ceil(MAPX(w())); map_hy = ceil(MAPY(h())); // setup projection matrix for 2D drawing // Note: this crud is a workaround for retina displays on MacOS Fl::use_high_res_GL(true); int pix = iround(inst.main_win->canvas->pixels_per_unit()); Fl::use_high_res_GL(false); glLoadIdentity(); glViewport(0, 0, w() * pix, h() * pix); glOrtho(0, w(), 0, h(), -1, 1); #endif PrepareToDraw(); RenderColor(FL_WHITE); RenderThickness(1); // default font (for showing object numbers) int font_size = (inst.grid.getScale() < 0.9) ? 14 : 19; RenderFontSize(font_size); DrawEverything(); Blit(); } int UI_Canvas::handle(int event) { if (inst.EV_HandleEvent(event)) return 1; return Fl_Widget::handle(event); } int UI_Canvas::NORMALX(int len, double dx, double dy) { #ifdef NO_OPENGL double res = -dy; #else double res = dy; #endif double got_len = hypot(dx, dy); if (got_len < 0.01) return 0; return iround(res * len / got_len); } int UI_Canvas::NORMALY(int len, double dx, double dy) { #ifdef NO_OPENGL double res = dx; #else double res = -dx; #endif double got_len = hypot(dx, dy); if (got_len < 0.01) return 0; return iround(res * len / got_len); } #ifdef NO_OPENGL // convert screen coordinates to map coordinates inline double UI_Canvas::MAPX(int sx) const { return inst.grid.getOrig().x + (sx - w() / 2 - x()) / inst.grid.getScale(); } inline double UI_Canvas::MAPY(int sy) const { return inst.grid.getOrig().y + (h() / 2 - sy + y()) / inst.grid.getScale(); } // convert map coordinates to screen coordinates inline int UI_Canvas::SCREENX(double mx) const { return (x() + w() / 2 + iround((mx - inst.grid.getOrig().x) * inst.grid.getScale())); } inline int UI_Canvas::SCREENY(double my) const { return (y() + h() / 2 + iround((inst.grid.getOrig().y - my) * inst.grid.getScale())); } #else // convert GL coordinates to map coordinates inline double UI_Canvas::MAPX(int sx) const { return inst.grid.getOrig().x + (sx - w() / 2) / inst.grid.getScale(); } inline double UI_Canvas::MAPY(int sy) const { return inst.grid.getOrig().y + (sy - h() / 2) / inst.grid.getScale(); } // convert map coordinates to GL coordinates inline int UI_Canvas::SCREENX(double mx) const { return (w() / 2 + iround((mx - inst.grid.getOrig().x) * inst.grid.getScale())); } inline int UI_Canvas::SCREENY(double my) const { return (h() / 2 + iround((my - inst.grid.getOrig().y) * inst.grid.getScale())); } #endif void UI_Canvas::PointerPos(bool in_event) { if (inst.edit.render3d) return; // we read current position outside of FLTK's event propagation. int raw_x, raw_y; Fl::get_mouse(raw_x, raw_y); #ifdef NO_OPENGL raw_x -= inst.main_win->x_root(); raw_y -= inst.main_win->y_root(); inst.edit.map.x = MAPX(raw_x); inst.edit.map.y = MAPY(raw_y); #else // OpenGL raw_x -= x_root(); raw_y -= y_root(); inst.edit.map.x = MAPX(raw_x); inst.edit.map.y = MAPY(h() - 1 - raw_y); #endif inst.grid.NaturalSnapXY(inst.edit.map.x, inst.edit.map.y); // no Z coord with the 2D map view inst.edit.map.z = -1; } int UI_Canvas::ApproxBoxSize(int mx1, int my1, int mx2, int my2) { if (mx2 < mx1) std::swap(mx1, mx2); if (my2 < my1) std::swap(my1, my2); int x1 = SCREENX(mx1); int x2 = SCREENX(mx2); int y1 = SCREENY(my2); int y2 = SCREENY(my1); if (x1 < 8 || x2 > w() - 8 || y1 < 8 || y2 > h() - 8) return 1; // too big float x_ratio = std::max(4, x2 - x1) / (float)std::max(4, w()); float y_ratio = std::max(4, y2 - y1) / (float)std::max(4, h()); if (std::max(x_ratio, y_ratio) < 0.25) return -1; // too small return 0; } //------------------------------------------------------------------------ void UI_Canvas::DrawEverything() { // setup for drawing sector numbers if (inst.edit.show_object_numbers && inst.edit.mode == ObjType::sectors) { seen_sectors.clear_all(); } DrawMap(); DrawSelection(&*inst.edit.Selected); if (inst.edit.action == EditorAction::drag && !inst.edit.dragged.valid() && inst.edit.drag_lines != NULL) DrawSelection(inst.edit.drag_lines); else if (inst.edit.action == EditorAction::transform && inst.edit.trans_lines != NULL) DrawSelection(inst.edit.trans_lines); if (inst.edit.action == EditorAction::drag && inst.edit.dragged.valid()) { v2double_t delta = DragDelta(); if (inst.edit.mode == ObjType::vertices) RenderColor(HI_AND_SEL_COL); else RenderColor(HI_COL); if (inst.edit.mode == ObjType::linedefs || inst.edit.mode == ObjType::sectors) RenderThickness(2); DrawHighlight(inst.edit.mode, inst.edit.dragged.num, false /* skip_lines */, delta.x, delta.y); if (inst.edit.mode == ObjType::vertices && inst.edit.highlight.valid()) { RenderColor(HI_COL); DrawHighlight(inst.edit.highlight.type, inst.edit.highlight.num); } RenderThickness(1); // when ratio lock is on, want to see the new line if (inst.edit.mode == ObjType::vertices && inst.grid.getRatio() > 0 && inst.edit.drag_other_vert >= 0) { const auto v0 = inst.level.vertices[inst.edit.drag_other_vert]; const auto v1 = inst.level.vertices[inst.edit.dragged.num]; RenderColor(RED); DrawKnobbyLine(v0->x(), v0->y(), v1->x() + delta.x, v1->y() + delta.y); DrawLineInfo(v0->x(), v0->y(), v1->x() + delta.x, v1->y() + delta.y, true); } } else if (inst.edit.highlight.valid()) { if (inst.edit.action != EditorAction::drawLine && inst.edit.Selected->get(inst.edit.highlight.num)) RenderColor(HI_AND_SEL_COL); else RenderColor(HI_COL); if (inst.edit.highlight.type == ObjType::linedefs || inst.edit.highlight.type == ObjType::sectors) RenderThickness(2); DrawHighlight(inst.edit.highlight.type, inst.edit.highlight.num); if (! inst.edit.error_mode) { RenderColor(LIGHTRED); DrawTagged(inst.edit.highlight.type, inst.edit.highlight.num); } if (inst.edit.mode == ObjType::linedefs && !inst.edit.show_object_numbers) { const auto L = inst.level.linedefs[inst.edit.highlight.num]; DrawLineInfo(inst.level.getStart(*L).x(), inst.level.getStart(*L).y(), inst.level.getEnd(*L).x(), inst.level.getEnd(*L).y(), false); } RenderThickness(1); } if (inst.edit.action == EditorAction::selbox) SelboxDraw(); if (inst.edit.action == EditorAction::drawLine) DrawCurrentLine(); } // // draw the whole map, except for hilight/selection/selbox // void UI_Canvas::DrawMap() { RenderColor(FL_BLACK); RenderRect(xx, yy, w(), h()); if (inst.edit.sector_render_mode && ! inst.edit.error_mode) { for (int n = 0 ; n < inst.level.numSectors(); n++) RenderSector(n); } // draw the grid first since it's in the background if (inst.grid.isShown()) { if (config::grid_style == 0) DrawGrid_Normal(); else DrawGrid_Dotty(); } if (global::Debugging) DrawMapBounds(); DrawCamera(); if (inst.edit.mode != ObjType::things) DrawThings(); if (inst.grid.snaps() && config::grid_snap_indicator) DrawSnapPoint(); DrawLinedefs(); if (inst.edit.mode == ObjType::vertices) DrawVertices(); if (inst.edit.mode == ObjType::things) { if (inst.edit.thing_render_mode > 0) { DrawThings(); DrawThingSprites(); } else { DrawThingBodies(); DrawThings(); } } } // // draw the grid in the background of the inst.edit window // void UI_Canvas::DrawGrid_Normal() { float pixels_1 = static_cast(inst.grid.getStep() * inst.grid.getScale()); if (pixels_1 < 1.6) { RenderColor(DarkerColor(DarkerColor(config::normal_main_col))); RenderRect(xx, yy, w(), h()); DrawAxes(config::normal_axis_col); return; } int flat_step = 64; float pixels_2 = static_cast(flat_step * inst.grid.getScale()); Fl_Color flat_col = (inst.grid.getStep() < 64) ? config::normal_main_col : config::normal_flat_col; if (pixels_2 < 2.2) flat_col = DarkerColor(flat_col); RenderColor(flat_col); if (pixels_2 < 1.6) { RenderRect(xx, yy, w(), h()); } else { int gx = static_cast(floor(map_lx / flat_step) * flat_step); for (; gx <= map_hx; gx += flat_step) DrawMapLine(gx, map_ly, gx, map_hy); int gy = static_cast(floor(map_ly / flat_step) * flat_step); for (; gy <= map_hy; gy += flat_step) DrawMapLine(map_lx, gy, map_hx, gy); } Fl_Color main_col = (inst.grid.getStep() < 64) ? config::normal_small_col : config::normal_main_col; float pixels_3 = static_cast(inst.grid.getStep() * inst.grid.getScale()); if (pixels_3 < 4.2) main_col = DarkerColor(main_col); RenderColor(main_col); { int gx = static_cast(floor(map_lx / inst.grid.getStep()) * inst.grid.getStep()); for (; gx <= map_hx; gx += inst.grid.getStep()) if ((inst.grid.getStep() >= 64 || (gx & 63) != 0) && (gx != 0)) DrawMapLine(gx, map_ly, gx, map_hy); int gy = static_cast(floor(map_ly / inst.grid.getStep()) * inst.grid.getStep()); for (; gy <= map_hy; gy += inst.grid.getStep()) if ((inst.grid.getStep() >= 64 || (gy & 63) != 0) && (gy != 0)) DrawMapLine(map_lx, gy, map_hx, gy); } DrawAxes(config::normal_axis_col); } void UI_Canvas::DrawGrid_Dotty() { int grid_step_1 = 1 * inst.grid.getStep(); // Map units between dots int grid_step_2 = 8 * grid_step_1; // Map units between dim lines int grid_step_3 = 8 * grid_step_2; // Map units between bright lines float pixels_1 = static_cast(inst.grid.getStep() * inst.grid.getScale()); if (pixels_1 < 1.6) { RenderColor(DarkerColor(DarkerColor(config::dotty_point_col))); RenderRect(xx, yy, w(), h()); DrawAxes(config::dotty_axis_col); return; } RenderColor(config::dotty_major_col); { int gx = static_cast(floor(map_lx / grid_step_3) * grid_step_3); for (; gx <= map_hx; gx += grid_step_3) DrawMapLine(gx, map_ly-2, gx, map_hy+2); int gy = static_cast(floor(map_ly / grid_step_3) * grid_step_3); for (; gy <= map_hy; gy += grid_step_3) DrawMapLine(map_lx, gy, map_hx, gy); } DrawAxes(config::dotty_axis_col); RenderColor(config::dotty_minor_col); { int gx = static_cast(floor(map_lx / grid_step_2) * grid_step_2); for (; gx <= map_hx; gx += grid_step_2) if (gx % grid_step_3 != 0) DrawMapLine(gx, map_ly, gx, map_hy); int gy = static_cast(floor(map_ly / grid_step_2) * grid_step_2); for (; gy <= map_hy; gy += grid_step_2) if (gy % grid_step_3 != 0) DrawMapLine(map_lx, gy, map_hx, gy); } if (pixels_1 < 4.02) RenderColor(DarkerColor(config::dotty_point_col)); else RenderColor(config::dotty_point_col); { int gx = static_cast(floor(map_lx / grid_step_1) * grid_step_1); int gy = static_cast(floor(map_ly / grid_step_1) * grid_step_1); for (int ny = gy; ny <= map_hy; ny += grid_step_1) for (int nx = gx; nx <= map_hx; nx += grid_step_1) { int sx = SCREENX(nx); int sy = SCREENY(ny); if (pixels_1 < 24.1) RenderRect(sx, sy, 1, 1); else RenderRect(sx, sy, 2, 2); } } } void UI_Canvas::DrawAxes(Fl_Color col) { RenderColor(col); DrawMapLine(0, map_ly, 0, map_hy); DrawMapLine(map_lx, 0, map_hx, 0); } void UI_Canvas::DrawMapBounds() { RenderColor(FL_RED); DrawMapLine(inst.level.Map_bound1.x, inst.level.Map_bound1.y, inst.level.Map_bound2.x, inst.level.Map_bound1.y); DrawMapLine(inst.level.Map_bound1.x, inst.level.Map_bound2.y, inst.level.Map_bound2.x, inst.level.Map_bound2.y); DrawMapLine(inst.level.Map_bound1.x, inst.level.Map_bound1.y, inst.level.Map_bound1.x, inst.level.Map_bound2.y); DrawMapLine(inst.level.Map_bound2.x, inst.level.Map_bound1.y, inst.level.Map_bound2.x, inst.level.Map_bound2.y); } // // the apparent radius of a vertex, in pixels // int vertex_radius(double scale) { int r = static_cast(6 * (0.26 + scale / 2)); if (r > 12) r = 12; return r; } // // draw the vertices, and possibly their numbers // void UI_Canvas::DrawVertex(double map_x, double map_y, int r) { int scrx = SCREENX(map_x); int scry = SCREENY(map_y); // BLOBBY TEST #if 0 RenderLine(scrx - 1, scry - 2, scrx + 1, scry - 2); RenderLine(scrx - 2, scry - 1, scrx + 2, scry - 1); RenderLine(scrx - 2, scry + 0, scrx + 2, scry + 0); RenderLine(scrx - 2, scry + 1, scrx + 2, scry + 1); RenderLine(scrx - 1, scry + 2, scrx + 1, scry + 2); #else RenderLine(scrx - r, scry - r, scrx + r, scry + r); RenderLine(scrx + r, scry - r, scrx - r, scry + r); RenderLine(scrx - 1, scry, scrx + 1, scry); RenderLine(scrx, scry - 1, scrx, scry + 1); #endif } void UI_Canvas::DrawVertices() { const int r = vertex_radius(inst.grid.getScale()); RenderColor(FL_GREEN); for (const auto &vertex : inst.level.vertices) { double x = vertex->x(); double y = vertex->y(); if (Vis(x, y, r)) { DrawVertex(x, y, r); } } if (inst.edit.show_object_numbers) { for (int n = 0 ; n < inst.level.numVertices(); n++) { double x = inst.level.vertices[n]->x(); double y = inst.level.vertices[n]->y(); if (! Vis(x, y, r)) continue; int sx = SCREENX(x) + r * 3; int sy = SCREENY(y) + r * 3; DrawNumber(sx, sy, n); } } } // // draw all the linedefs // void UI_Canvas::DrawLinedefs() { for (int n = 0 ; n < inst.level.numLinedefs(); n++) { const auto L = inst.level.linedefs[n]; double x1 = inst.level.getStart(*L).x(); double y1 = inst.level.getStart(*L).y(); double x2 = inst.level.getEnd(*L).x(); double y2 = inst.level.getEnd(*L).y(); if (! Vis(std::min(x1,x2), std::min(y1,y2), std::max(x1,x2), std::max(y1,y2))) continue; bool one_sided = (! inst.level.getLeft(*L)); Fl_Color col = LIGHTGREY; // 'p' for plain, 'k' for knobbly, 's' for split char line_kind = 'p'; switch (inst.edit.mode) { case ObjType::vertices: { if (n == inst.edit.split_line.num) col = HI_AND_SEL_COL; else if (inst.edit.error_mode) col = LIGHTGREY; else if (L->right < 0) col = RED; else if (one_sided) col = WHITE; if (n == inst.edit.split_line.num) line_kind = 's'; else line_kind = 'k'; // show info of last four added lines if (n != inst.edit.split_line.num && n >= (inst.level.numLinedefs() - 4) && !inst.edit.show_object_numbers) { DrawLineInfo(x1, y1, x2, y2, false); } } break; case ObjType::linedefs: { if (inst.edit.error_mode) col = LIGHTGREY; else if (! inst.level.getRight(*L)) // no first sidedef? col = RED; else if (L->type != 0) { if (L->tag != 0) col = LIGHTMAGENTA; else col = LIGHTGREEN; } else if (one_sided) col = WHITE; else if (L->flags & MLF_Blocking) col = FL_CYAN; line_kind = 'k'; } break; case ObjType::sectors: { int sd1 = L->right; int sd2 = L->left; int s1 = (sd1 < 0) ? NIL_OBJ : inst.level.sidedefs[sd1]->sector; int s2 = (sd2 < 0) ? NIL_OBJ : inst.level.sidedefs[sd2]->sector; if (inst.edit.error_mode) col = LIGHTGREY; else if (sd1 < 0) col = RED; else if (inst.edit.sector_render_mode == SREND_SoundProp) { if (L->flags & MLF_SoundBlock) col = FL_MAGENTA; else if (one_sided) col = WHITE; } else { bool have_tag = false; bool have_type = false; if (inst.level.sectors[s1]->tag != 0) have_tag = true; if (inst.level.sectors[s1]->type != 0) have_type = true; if (s2 >= 0) { if (inst.level.sectors[s2]->tag != 0) have_tag = true; if (inst.level.sectors[s2]->type != 0) have_type = true; } if (have_tag && have_type) col = SECTOR_TAGTYPE; else if (have_tag) col = SECTOR_TAG; else if (have_type) col = SECTOR_TYPE; else if (one_sided) col = WHITE; } if (inst.edit.show_object_numbers) { if (s1 != NIL_OBJ) DrawSectorNum(static_cast(x1), static_cast(y1), static_cast(x2), static_cast(y2), Side::right, s1); if (s2 != NIL_OBJ) DrawSectorNum(static_cast(x1), static_cast(y1), static_cast(x2), static_cast(y2), Side::left, s2); } } break; // OBJ_THINGS default: { if (one_sided && ! inst.edit.error_mode) col = WHITE; } break; } RenderColor(col); switch (line_kind) { case 'p': DrawMapLine(x1, y1, x2, y2); break; case 'k': DrawKnobbyLine(x1, y1, x2, y2); break; case 's': DrawSplitLine(x1, y1, x2, y2); break; } } // draw the linedef numbers if (inst.edit.mode == ObjType::linedefs && inst.edit.show_object_numbers) { for (int n = 0 ; n < inst.level.numLinedefs(); n++) { double x1 = inst.level.getStart(*inst.level.linedefs[n]).x(); double y1 = inst.level.getStart(*inst.level.linedefs[n]).y(); double x2 = inst.level.getEnd(*inst.level.linedefs[n]).x(); double y2 = inst.level.getEnd(*inst.level.linedefs[n]).y(); if (! Vis(std::min(x1,x2), std::min(y1,y2), std::max(x1,x2), std::max(y1,y2))) continue; DrawLineNumber(static_cast(x1), static_cast(y1), static_cast(x2), static_cast(y2), Side::neither, n); } } } void UI_Canvas::DrawThing(double x, double y, int r, int angle, bool big_arrow) { DrawMapLine(x-r, y-r, x-r, y+r); DrawMapLine(x-r, y+r, x+r, y+r); DrawMapLine(x+r, y+r, x+r, y-r); DrawMapLine(x+r, y-r, x-r, y-r); if (big_arrow) { DrawMapArrow(x, y, r * 2, angle); } else { int dir = angle_to_direction(angle); static const short xsign[] = { 1, 1, 0, -1, -1, -1, 0, 1, 0 }; static const short ysign[] = { 0, 1, 1, 1, 0, -1, -1, -1, 0 }; int corner_x = r * xsign[dir]; int corner_y = r * ysign[dir]; DrawMapLine(x, y, x + corner_x, y + corner_y); } } // // draw things as squares (outlines) // void UI_Canvas::DrawThings() { if (inst.edit.mode != ObjType::things) RenderColor(DARKGREY); else if (inst.edit.error_mode) RenderColor(LIGHTGREY); for (const auto &thing : inst.level.things) { double x = thing->x(); double y = thing->y(); if (! Vis(x, y, MAX_RADIUS)) continue; const thingtype_t &info = inst.conf.getThingType(thing->type); if (inst.edit.mode == ObjType::things && !inst.edit.error_mode) { Fl_Color col = (Fl_Color)info.color; RenderColor(col); } int r = info.radius; DrawThing(x, y, r, thing->angle, false); } // draw the thing numbers if (inst.edit.mode == ObjType::things && inst.edit.show_object_numbers) { for (int n = 0 ; n < inst.level.numThings(); n++) { double x = inst.level.things[n]->x(); double y = inst.level.things[n]->y(); if (! Vis(x, y, MAX_RADIUS)) continue; const thingtype_t &info = inst.conf.getThingType(inst.level.things[n]->type); x += info.radius + 8; y += info.radius + 8; DrawNumber(SCREENX(x), SCREENY(y), n); } } } // // draw bodies of things (solid boxes, darker than the outline) // void UI_Canvas::DrawThingBodies() { if (inst.edit.error_mode) return; for (const auto &thing : inst.level.things) { double x = thing->x(); double y = thing->y(); if (! Vis(x, y, MAX_RADIUS)) continue; const thingtype_t &info = inst.conf.getThingType(thing->type); Fl_Color col = (Fl_Color)info.color; RenderColor(DarkerColor(DarkerColor(col))); int r = info.radius; int sx1 = SCREENX(x - r); int sy1 = SCREENY(y + r); int sx2 = SCREENX(x + r); int sy2 = SCREENY(y - r); RenderRect(sx1, sy1, sx2 - sx1 + 1, sy2 - sy1 + 1); } } static int calcThingRotation(int angle) { // 1: south, 247.5:292.5 // 2: southwest, 202.5:247.5 // 3: west, 157.5:202.5 // 4: northwest, 112.5:157.5 // 5: north, 67.5:112.5 // 6: northeast, 22.5: 67.5 // 7: east, -22.5: 22.5 // 8: southeast, -67.5:-22.5 or rather 292.5 : 337.5 while(angle < 0) angle += 360; while(angle > 360) angle -= 360; if(angle >= 338 || angle < 23) return 7; if(angle < 68) return 6; if(angle < 113) return 5; if(angle < 158) return 4; if(angle < 203) return 3; if(angle < 248) return 2; if(angle < 293) return 1; // if(angle < 338) return 8; } void UI_Canvas::DrawThingSprites() { #ifndef NO_OPENGL glEnable(GL_TEXTURE_2D); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.5); #endif for (const auto &thing : inst.level.things) { double x = thing->x(); double y = thing->y(); if (! Vis(x, y, MAX_RADIUS)) continue; const thingtype_t &info = inst.conf.getThingType(thing->type); float scale = info.scale; Img_c *sprite = inst.wad.getMutableSprite(inst.conf, thing->type, inst.loaded, calcThingRotation(thing->angle)); if (! sprite) { sprite = &inst.wad.images.IM_UnknownSprite(inst.conf); scale = 0.66f; } int sx = SCREENX(x); int sy = SCREENY(y); RenderSprite(sx, sy, static_cast(scale * inst.grid.getScale()), sprite); } #ifndef NO_OPENGL glDisable(GL_ALPHA_TEST); glDisable(GL_TEXTURE_2D); #endif } void UI_Canvas::RenderSprite(int sx, int sy, float scale, Img_c *img) { int W = img->width(); int H = img->height(); scale = scale * 0.5f; #ifdef NO_OPENGL // software rendering int bx1 = sx + (int)floor(-W * scale) - rgb_x; int bx2 = sx + (int)ceil ( W * scale) - rgb_x; int by1 = sy + (int)floor(-H * scale) - rgb_y; int by2 = sy + (int)ceil ( H * scale) - rgb_y; // prevent division by zero if (bx2 <= bx1) bx2 = bx1 + 1; if (by2 <= by1) by2 = by1 + 1; // clip to screen int rx1 = std::max(bx1, 0); int ry1 = std::max(by1, 0); int rx2 = std::min(bx2, rgb_w) - 1; int ry2 = std::min(by2, rgb_h) - 1; if (rx1 >= rx2 || ry1 >= ry2) return; for (int ry = ry1 ; ry <= ry2 ; ry++) { byte *dest = rgb_buf + 3 * (rx1 + ry * rgb_w); for (int rx = rx1 ; rx <= rx2 ; rx++, dest += 3) { int ix = W * (rx - bx1) / (bx2 - bx1); int iy = H * (ry - by1) / (by2 - by1); ix = clamp(0, ix, W - 1); iy = clamp(0, iy, H - 1); img_pixel_t pix = img->buf()[iy * W + ix]; if (pix != TRANS_PIXEL) { inst.wad.palette.decodePixel(pix, dest[0], dest[1], dest[2]); } } } #else // OpenGL int bx1 = sx + (int)floor(-W * scale); int bx2 = sx + (int)ceil ( W * scale); int by1 = sy + (int)floor(-H * scale); int by2 = sy + (int)ceil ( H * scale); // don't make too small if (bx2 <= bx1) bx2 = bx1 + 1; if (by2 <= by1) by2 = by1 + 1; // bind the sprite image (upload it to OpenGL if needed) img->bind_gl(inst.wad); // choose texture coords based on image size float tx1 = 0.0; float ty1 = 0.0; float tx2, ty2; if (global::use_npot_textures) { tx2 = 1.0; ty2 = 1.0; } else { tx2 = (float)img->width() / (float)RoundPOW2(img->width()); ty2 = (float)img->height() / (float)RoundPOW2(img->height()); } glColor3f(1, 1, 1); glBegin(GL_QUADS); glTexCoord2f(tx1, ty1); glVertex2i(bx1, by1); glTexCoord2f(tx1, ty2); glVertex2i(bx1, by2); glTexCoord2f(tx2, ty2); glVertex2i(bx2, by2); glTexCoord2f(tx2, ty1); glVertex2i(bx2, by1); glEnd(); #endif } void UI_Canvas::DrawSectorNum(int mx1, int my1, int mx2, int my2, Side side, int n) { // only draw a number for the first linedef actually visible if (seen_sectors.get(n)) return; seen_sectors.set(n); DrawLineNumber(mx1, my1, mx2, my2, side, n); } void UI_Canvas::DrawLineNumber(int mx1, int my1, int mx2, int my2, Side side, int n) { int x1 = SCREENX(mx1); int y1 = SCREENY(my1); int x2 = SCREENX(mx2); int y2 = SCREENY(my2); int sx = (x1 + x2) / 2; int sy = (y1 + y2) / 2; // normally draw line numbers on back of line int want_len = static_cast(-16 * clamp(0.25, inst.grid.getScale(), 1.0)); // for sectors, draw closer and on sector side if (side != Side::neither) { want_len = static_cast(2 + 12 * clamp(0.25, inst.grid.getScale(), 1.0)); if (side == Side::left) want_len = -want_len; } sx += NORMALX(want_len*2, x2 - x1, y2 - y1); sy += NORMALY(want_len, x2 - x1, y2 - y1); DrawNumber(sx, sy, n); } void UI_Canvas::DrawLineInfo(double map_x1, double map_y1, double map_x2, double map_y2, bool force_ratio) { line_info_mode_e info = (line_info_mode_e)config::highlight_line_info; if (info == LINFO_Nothing) return; int x1 = SCREENX(map_x1); int y1 = SCREENY(map_y1); int x2 = SCREENX(map_x2); int y2 = SCREENY(map_y2); int sx = (x1 + x2) / 2; int sy = (y1 + y2) / 2; // if midpoint is off the screen, try to find a better one double mx = (map_x1 + map_x2) / 2.0; double my = (map_y1 + map_y2) / 2.0; if (mx < map_lx + 4 || mx > map_hx - 4 || my < map_ly + 4 || my > map_hy - 4) { double best_dist = 9e9; for (double p = 0.1 ; p < 0.91 ; p += 0.1) { mx = map_x1 + (map_x2 - map_x1) * p; my = map_y1 + (map_y2 - map_y1) * p; double dist_x = mx * 2.0 - (map_lx + map_hx); double dist_y = my * 2.0 - (map_ly + map_hy); double dist = hypot(dist_x, dist_y); if (dist < best_dist) { sx = static_cast(x1 + (x2 - x1) * p); sy = static_cast(y1 + (y2 - y1) * p); best_dist = dist; } } } // back of line is best place, no knob getting in the way int want_len = static_cast(-16 * clamp(0.25, inst.grid.getScale(), 1.0)); sx += NORMALX(want_len*2, x2 - x1, y2 - y1); sy += NORMALY(want_len, x2 - x1, y2 - y1); /* length */ FFixedPoint idx = MakeValidCoord(inst.loaded.levelFormat, map_x2) - MakeValidCoord(inst.loaded.levelFormat, map_x1); FFixedPoint idy = MakeValidCoord(inst.loaded.levelFormat, map_y2) - MakeValidCoord(inst.loaded.levelFormat, map_y1); if (info == LINFO_Length || info >= LINFO_Length_Angle) { double length = hypot(static_cast(idx), static_cast(idy)); if (length > 0.1) { char buffer[64]; snprintf(buffer, sizeof(buffer), "%1.1f", length); RenderNumString(sx, sy, buffer); sy = sy - cur_font; } } /* angle */ if (info == LINFO_Angle || info == LINFO_Length_Angle) { double dx = static_cast(idx); double dy = static_cast(idy); int degrees = (int)round(atan2(dy, dx) * 180.0 / M_PI); if (degrees < 0) degrees += 360; char buffer[64]; snprintf(buffer, sizeof(buffer), "%d^", degrees); RenderNumString(sx, sy, buffer); } /* ratio */ if (info == LINFO_Ratio || info == LINFO_Length_Ratio) { if (idx != FFixedPoint{} && idy != FFixedPoint{}) { SString ratio_name = LD_RatioName(idx, idy, true); RenderNumString(sx, sy, ratio_name.c_str()); } } } // // draw a number centered at screen coordinate (x, y) // void UI_Canvas::DrawNumber(int x, int y, int num) { char buffer[64]; snprintf(buffer, sizeof(buffer), "%d", num); #if 0 /* DEBUG */ RenderColor(FL_RED); RenderRect(x - 1, y - 1, 3, 3); return; #endif RenderNumString(x, y, buffer); } void UI_Canvas::CheckGridSnap() { if (!inst.grid.snaps() || !config::grid_snap_indicator) return; double new_snap_x = inst.grid.SnapX(inst.edit.map.x); double new_snap_y = inst.grid.SnapY(inst.edit.map.y); if (snap_x == new_snap_x && snap_y == new_snap_y) return; snap_x = new_snap_x; snap_y = new_snap_y; redraw(); } void UI_Canvas::UpdateHighlight() { bool changes = false; if (! (last_highlight == inst.edit.highlight)) { last_highlight = inst.edit.highlight; changes = true; } int new_ld = inst.edit.split_line.valid() ? inst.edit.split_line.num : -1; if (! (last_splitter == new_ld && last_split_x == inst.edit.split.x && last_split_y == inst.edit.split.y)) { last_splitter = new_ld; last_split_x = inst.edit.split.x; last_split_y = inst.edit.split.y; changes = true; } if (changes) redraw(); } // // draw the given object in highlight color // void UI_Canvas::DrawHighlight(ObjType objtype, int objnum, bool skip_lines, double dx, double dy) { // color and line thickness have been set by caller // fprintf(stderr, "DrawHighlight: %d\n", objnum); switch (objtype) { case ObjType::things: { double x = dx + inst.level.things[objnum]->x(); double y = dy + inst.level.things[objnum]->y(); if (! Vis(x, y, MAX_RADIUS)) break; const thingtype_t &info = inst.conf.getThingType(inst.level.things[objnum]->type); int r = info.radius; if (inst.edit.error_mode) DrawThing(x, y, r, inst.level.things[objnum]->angle, false /* big_arrow */); r += r / 10 + 4; DrawThing(x, y, r, inst.level.things[objnum]->angle, true); } break; case ObjType::linedefs: { double x1 = dx + inst.level.getStart(*inst.level.linedefs[objnum]).x(); double y1 = dy + inst.level.getStart(*inst.level.linedefs[objnum]).y(); double x2 = dx + inst.level.getEnd(*inst.level.linedefs[objnum]).x(); double y2 = dy + inst.level.getEnd(*inst.level.linedefs[objnum]).y(); if (! Vis(std::min(x1,x2), std::min(y1,y2), std::max(x1,x2), std::max(y1,y2))) break; DrawMapVector(x1, y1, x2, y2); } break; case ObjType::vertices: { double x = dx + inst.level.vertices[objnum]->x(); double y = dy + inst.level.vertices[objnum]->y(); int vert_r = vertex_radius(inst.grid.getScale()); if (! Vis(x, y, vert_r)) break; DrawVertex(x, y, vert_r); int r = vert_r * 3 / 2; int sx1 = SCREENX(x) - r; int sy1 = SCREENY(y) - r; int sx2 = SCREENX(x) + r; int sy2 = SCREENY(y) + r; RenderLine(sx1, sy1, sx2, sy1); RenderLine(sx2, sy1, sx2, sy2); RenderLine(sx2, sy2, sx1, sy2); RenderLine(sx1, sy2, sx1, sy1); } break; case ObjType::sectors: { for (const auto &L : inst.level.linedefs) { if (! inst.level.touchesSector(*L, objnum)) continue; bool reverse = false; // skip lines if both sides are in the selection if (skip_lines && L->TwoSided()) { int sec1 = inst.level.getRight(*L)->sector; int sec2 = inst.level.getLeft(*L)->sector; if ((sec1 == objnum || inst.edit.Selected->get(sec1)) && (sec2 == objnum || inst.edit.Selected->get(sec2))) continue; if (sec1 != objnum) reverse = true; } double x1 = dx + inst.level.getStart(*L).x(); double y1 = dy + inst.level.getStart(*L).y(); double x2 = dx + inst.level.getEnd(*L).x(); double y2 = dy + inst.level.getEnd(*L).y(); if (! Vis(std::min(x1,x2), std::min(y1,y2), std::max(x1,x2), std::max(y1,y2))) continue; if (skip_lines) DrawKnobbyLine(x1, y1, x2, y2, reverse); else DrawMapLine(x1, y1, x2, y2); } } break; default: break; } } void UI_Canvas::DrawHighlightTransform(ObjType objtype, int objnum) { // color and line thickness have been set by caller switch (objtype) { case ObjType::things: { double x = inst.level.things[objnum]->x(); double y = inst.level.things[objnum]->y(); inst.edit.trans_param.Apply(&x, &y); if (! Vis(x, y, MAX_RADIUS)) break; const thingtype_t &info = inst.conf.getThingType(inst.level.things[objnum]->type); int r = info.radius; DrawThing(x, y, r * 3 / 2, inst.level.things[objnum]->angle, true); } break; case ObjType::vertices: { double x = inst.level.vertices[objnum]->x(); double y = inst.level.vertices[objnum]->y(); int vert_r = vertex_radius(inst.grid.getScale()); inst.edit.trans_param.Apply(&x, &y); if (! Vis(x, y, vert_r)) break; DrawVertex(x, y, vert_r); int r = vert_r * 3 / 2; int sx1 = SCREENX(x) - r; int sy1 = SCREENY(y) - r; int sx2 = SCREENX(x) + r; int sy2 = SCREENY(y) + r; RenderLine(sx1, sy1, sx2, sy1); RenderLine(sx2, sy1, sx2, sy2); RenderLine(sx2, sy2, sx1, sy2); RenderLine(sx1, sy2, sx1, sy1); } break; case ObjType::linedefs: { double x1 = inst.level.getStart(*inst.level.linedefs[objnum]).x(); double y1 = inst.level.getStart(*inst.level.linedefs[objnum]).y(); double x2 = inst.level.getEnd(*inst.level.linedefs[objnum]).x(); double y2 = inst.level.getEnd(*inst.level.linedefs[objnum]).y(); inst.edit.trans_param.Apply(&x1, &y1); inst.edit.trans_param.Apply(&x2, &y2); if (! Vis(std::min(x1,x2), std::min(y1,y2), std::max(x1,x2), std::max(y1,y2))) break; DrawMapVector(x1, y1, x2, y2); } break; case ObjType::sectors: { for (const auto &linedef : inst.level.linedefs) { if (! inst.level.touchesSector(*linedef, objnum)) continue; double x1 = inst.level.getStart(*linedef).x(); double y1 = inst.level.getStart(*linedef).y(); double x2 = inst.level.getEnd(*linedef).x(); double y2 = inst.level.getEnd(*linedef).y(); inst.edit.trans_param.Apply(&x1, &y1); inst.edit.trans_param.Apply(&x2, &y2); if (! Vis(std::min(x1,x2), std::min(y1,y2), std::max(x1,x2), std::max(y1,y2))) continue; DrawMapLine(x1, y1, x2, y2); } } break; default: break; } } void UI_Canvas::DrawTagged(ObjType objtype, int objnum) { // color has been set by caller // handle tagged linedefs : show matching sector(s) // // Highlight tagged items now // auto highlightTaggedItems = [this](const SpecialTagInfo &info) { if(info.numtags) for (int m = 0 ; m < inst.level.numSectors(); m++) if(inst.level.sectors[m]->tag > 0) for(int i = 0; i < info.numtags; ++i) if (inst.level.sectors[m]->tag == info.tags[i]) DrawHighlight(ObjType::sectors, m); if(info.numtids) for(int m = 0; m < inst.level.numThings(); m++) if(inst.level.things[m]->tid > 0) { if(info.type == ObjType::things && info.objnum == m) continue; // don't highlight the trigger again for(int i = 0; i < info.numtids; ++i) if(inst.level.things[m]->tid == info.tids[i]) DrawHighlight(ObjType::things, m); } if(info.numlineids) { for(int m = 0; m < inst.level.numLinedefs(); ++m) { if(info.type == ObjType::linedefs && info.objnum == m) continue; // don't highlight the trigger again const LineDef &line = *inst.level.linedefs[m]; if(inst.loaded.levelFormat == MapFormat::doom) { if(line.tag > 0) { for(int i = 0; i < info.numlineids; ++i) if(line.tag == info.lineids[i]) DrawHighlight(ObjType::linedefs, m); } } else if(inst.loaded.levelFormat == MapFormat::hexen) { SpecialTagInfo linfo; if(!getSpecialTagInfo(ObjType::linedefs, m, line.type, &line, inst.conf, linfo) || linfo.selflineid <= 0) { continue; } for(int i = 0; i < info.numlineids; ++i) if(linfo.selflineid == info.lineids[i]) DrawHighlight(ObjType::linedefs, m); } // TODO: also handle UDMF. } } if(info.numpo) for(int m = 0; m < inst.level.numThings(); ++m) { const Thing &thing = *inst.level.things[m]; const thingtype_t *type = get(inst.conf.thing_types, thing.type); if(!type || !(type->flags & THINGDEF_POLYSPOT)) continue; for(int i = 0; i < info.numpo; ++i) if(info.po[i] == thing.angle) DrawHighlight(ObjType::things, m); } }; // // Look for all the tagging things // auto highlightTaggingTriggers = [this, objnum, objtype](int tag, int (SpecialTagInfo::*tags)[5], int SpecialTagInfo::*numtags) { if(tag <= 0) return; for (int m = 0 ; m < inst.level.numLinedefs(); m++) { if(objtype == ObjType::linedefs && m == objnum) continue; const auto line = inst.level.linedefs[m]; assert(line); SpecialTagInfo info; if(!getSpecialTagInfo(ObjType::linedefs, m, line->type, line.get(), inst.conf, info)) continue; for(int i = 0; i < info.*numtags; ++i) if((info.*tags)[i] == tag) { DrawHighlight(ObjType::linedefs, m); break; } } if(inst.loaded.levelFormat == MapFormat::doom) return; for (int m = 0 ; m < inst.level.numThings(); m++) { if(objtype == ObjType::things && m == objnum) continue; const auto thing = inst.level.things[m]; assert(thing); SpecialTagInfo info; if(!getSpecialTagInfo(ObjType::things, m, thing->special, thing.get(), inst.conf, info)) continue; for(int i = 0; i < info.*numtags; ++i) if((info.*tags)[i] == tag) { DrawHighlight(ObjType::things, m); break; } } }; if (objtype == ObjType::linedefs) { const auto line = inst.level.linedefs[objnum]; assert(line); SpecialTagInfo info; if(getSpecialTagInfo(objtype, objnum, line->type, line.get(), inst.conf, info)) highlightTaggedItems(info); if(inst.loaded.levelFormat == MapFormat::doom) { highlightTaggingTriggers(line->tag, &SpecialTagInfo::lineids, &SpecialTagInfo::numlineids); } else { SpecialTagInfo linfo; if(!getSpecialTagInfo(objtype, objnum, line->type, line.get(), inst.conf, linfo)) return; // TODO: also UDMF line ID if(inst.loaded.levelFormat == MapFormat::hexen && linfo.selflineid > 0) { highlightTaggingTriggers(linfo.selflineid, &SpecialTagInfo::lineids, &SpecialTagInfo::numlineids); } } } else if(inst.loaded.levelFormat != MapFormat::doom && objtype == ObjType::things) { const auto thing = inst.level.things[objnum]; assert(thing); SpecialTagInfo info; if(getSpecialTagInfo(objtype, objnum, thing->special, thing.get(), inst.conf, info)) highlightTaggedItems(info); highlightTaggingTriggers(thing->tid, &SpecialTagInfo::tids, &SpecialTagInfo::numtids); const thingtype_t *type = get(inst.conf.thing_types, thing->type); if(type && type->flags & THINGDEF_POLYSPOT) highlightTaggingTriggers(thing->angle, &SpecialTagInfo::po, &SpecialTagInfo::numpo); } else if (objtype == ObjType::sectors) { highlightTaggingTriggers(inst.level.sectors[objnum]->tag, &SpecialTagInfo::tags, &SpecialTagInfo::numtags); } } void UI_Canvas::DrawSectorSelection(selection_c *list, double dx, double dy) { // color and line thickness have been set by caller for (const auto &L : inst.level.linedefs) { double x1 = dx + inst.level.getStart(*L).x(); double y1 = dy + inst.level.getStart(*L).y(); double x2 = dx + inst.level.getEnd(*L).x(); double y2 = dy + inst.level.getEnd(*L).y(); if (! Vis(std::min(x1,x2), std::min(y1,y2), std::max(x1,x2), std::max(y1,y2))) continue; if (L->right < 0 && L->left < 0) continue; int sec1 = -1; int sec2 = -1; if (L->right >= 0) sec1 = inst.level.getRight(*L)->sector; if (L->left >= 0) sec2 = inst.level.getLeft(*L) ->sector; bool touches1 = (sec1 >= 0) && list->get(sec1); bool touches2 = (sec2 >= 0) && list->get(sec2); if (! (touches1 || touches2)) continue; // skip lines if both sides are in the selection if (touches1 && touches2) continue; bool reverse = !touches1; DrawKnobbyLine(x1, y1, x2, y2, reverse); } } // // draw selected objects in light blue // void UI_Canvas::DrawSelection(selection_c * list) { if (! list || list->empty()) return; if (inst.edit.action == EditorAction::transform) { RenderColor(SEL_COL); if (list->what_type() == ObjType::linedefs || list->what_type() == ObjType::sectors) RenderThickness(2); for (sel_iter_c it(list) ; !it.done() ; it.next()) { DrawHighlightTransform(list->what_type(), *it); } RenderThickness(1); return; } v2double_t delta = {}; if (inst.edit.action == EditorAction::drag && inst.edit.dragged.is_nil()) { delta = DragDelta(); } RenderColor(inst.edit.error_mode ? FL_RED : SEL_COL); if (list->what_type() == ObjType::linedefs || list->what_type() == ObjType::sectors) RenderThickness(2); // special case when we have many sectors if (list->what_type() == ObjType::sectors && list->count_obj() > MAX_STORE_SEL) { DrawSectorSelection(list, delta.x, delta.y); } else { for (sel_iter_c it(list) ; !it.done() ; it.next()) { DrawHighlight(list->what_type(), *it, true /* skip_lines */, delta.x, delta.y); } } if (! inst.edit.error_mode && delta.x == 0 && delta.y == 0) { RenderColor(LIGHTRED); for (sel_iter_c it(list) ; !it.done() ; it.next()) { DrawTagged(list->what_type(), *it); } } RenderThickness(1); } // // draw a plain line at the given map coords // void UI_Canvas::DrawMapLine(double map_x1, double map_y1, double map_x2, double map_y2) { RenderLine(SCREENX(map_x1), SCREENY(map_y1), SCREENX(map_x2), SCREENY(map_y2)); } // // draw a line with a "knob" showing the right (front) side // void UI_Canvas::DrawKnobbyLine(double map_x1, double map_y1, double map_x2, double map_y2, bool reverse) { // color and thickness has been set by caller int x1 = SCREENX(map_x1); int y1 = SCREENY(map_y1); int x2 = SCREENX(map_x2); int y2 = SCREENY(map_y2); if (reverse) { std::swap(x1, x2); std::swap(y1, y2); } RenderLine(x1, y1, x2, y2); // indicate direction of line int mx = (x1 + x2) / 2; int my = (y1 + y2) / 2; int len = std::max(abs(x2 - x1), abs(y2 - y1)); int want_len = std::min(12, len / 5); int dx = NORMALX(want_len, x2 - x1, y2 - y1); int dy = NORMALY(want_len, x2 - x1, y2 - y1); if (! (dx == 0 && dy == 0)) { RenderLine(mx, my, mx + dx, my + dy); } } void UI_Canvas::DrawSplitPoint(const v2double_t &map_pos) { int sx = SCREENX(map_pos.x); int sy = SCREENY(map_pos.y); int size = (inst.grid.getScale() >= 5.0) ? 9 : (inst.grid.getScale() >= 1.0) ? 7 : 5; // color set by caller #ifdef NO_OPENGL RenderRect(sx - size/2, sy - size/2, size, size); #else glPointSize(static_cast(size)); glBegin(GL_POINTS); glVertex2i(sx, sy); glEnd(); glPointSize(1.0); #endif } void UI_Canvas::DrawSplitLine(double map_x1, double map_y1, double map_x2, double map_y2) { // show how and where the line will be split // color has been set by caller int scr_x1 = SCREENX(map_x1); int scr_y1 = SCREENY(map_y1); int scr_x2 = SCREENX(map_x2); int scr_y2 = SCREENY(map_y2); int scr_mx = SCREENX(inst.edit.split.x); int scr_my = SCREENY(inst.edit.split.y); RenderLine(scr_x1, scr_y1, scr_mx, scr_my); RenderLine(scr_x2, scr_y2, scr_mx, scr_my); if (! inst.edit.show_object_numbers) { double len1 = hypot(map_x1 - inst.edit.split.x, map_y1 - inst.edit.split.y); double len2 = hypot(map_x2 - inst.edit.split.x, map_y2 - inst.edit.split.y); DrawLineNumber(static_cast(map_x1), static_cast(map_y1), static_cast(inst.edit.split.x), static_cast(inst.edit.split.y), Side::neither, iround(len1)); DrawLineNumber(static_cast(map_x2), static_cast(map_y2), static_cast(inst.edit.split.x), static_cast(inst.edit.split.y), Side::neither, iround(len2)); } RenderColor(HI_AND_SEL_COL); DrawSplitPoint(inst.edit.split); } // // draw a bolder linedef with an arrow on the end // (used for highlighted / selected lines) // void UI_Canvas::DrawMapVector(double map_x1, double map_y1, double map_x2, double map_y2) { int x1 = SCREENX(map_x1); int y1 = SCREENY(map_y1); int x2 = SCREENX(map_x2); int y2 = SCREENY(map_y2); RenderLine(x1, y1, x2, y2); // knob int mx = (x1 + x2) / 2; int my = (y1 + y2) / 2; int klen = std::max(abs(x2 - x1), abs(y2 - y1)); int want_len = clamp(12, klen / 4, 40); int kx = NORMALX(want_len, x2 - x1, y2 - y1); int ky = NORMALY(want_len, x2 - x1, y2 - y1); RenderLine(mx, my, mx + kx, my + ky); // arrow double r2 = hypot((double) (x1 - x2), (double) (y1 - y2)); if (r2 < 1.0) r2 = 1.0; double len = clamp(6.0, r2 / 10.0, 24.0); int dx = (int) (len * (x1 - x2) / r2); int dy = (int) (len * (y1 - y2) / r2); x1 = x2 + 2 * dx; y1 = y2 + 2 * dy; RenderLine(x1 - dy, y1 + dx, x2, y2); RenderLine(x1 + dy, y1 - dx, x2, y2); } // // draw an arrow // void UI_Canvas::DrawMapArrow(double map_x1, double map_y1, int r, int angle) { float dx = static_cast(r * cos(angle * M_PI / 180.0)); float dy = static_cast(r * sin(angle * M_PI / 180.0)); float map_x2 = static_cast(map_x1 + dx); float map_y2 = static_cast(map_y1 + dy); DrawMapLine(map_x1, map_y1, map_x2, map_y2); // arrow head float x3 = static_cast(map_x2 - dx * 0.3 + dy * 0.3); float y3 = static_cast(map_y2 - dy * 0.3 - dx * 0.3); DrawMapLine(map_x2, map_y2, x3, y3); x3 = map_x2 - dx * 0.3f - dy * 0.3f; y3 = map_y2 - dy * 0.3f + dx * 0.3f; DrawMapLine(map_x2, map_y2, x3, y3); } void UI_Canvas::DrawCamera() { v2double_t map_pos; float angle; inst.Render3D_GetCameraPos(map_pos, &angle); float mx = static_cast(map_pos.x); float my = static_cast(map_pos.y); float r = static_cast(40.0 / sqrt(inst.grid.getScale())); float dx = static_cast(r * cos(angle * M_PI / 180.0)); float dy = static_cast(r * sin(angle * M_PI / 180.0)); // arrow body float x1 = mx - dx; float y1 = my - dy; float x2 = mx + dx; float y2 = my + dy; RenderColor(CAMERA_COLOR); RenderThickness(1); DrawMapLine(x1, y1, x2, y2); // arrow head float x3 = static_cast(x2 - dx * 0.6 + dy * 0.4); float y3 = static_cast(y2 - dy * 0.6 - dx * 0.4); DrawMapLine(x2, y2, x3, y3); x3 = static_cast(x2 - dx * 0.6 - dy * 0.4); y3 = static_cast(y2 - dy * 0.6 + dx * 0.4); DrawMapLine(x2, y2, x3, y3); // notches on body DrawMapLine(mx - dy * 0.4, my + dx * 0.4, mx + dy * 0.4, my - dx * 0.4); mx = static_cast(mx - dx * 0.2); my = static_cast(my - dy * 0.2); DrawMapLine(mx - dy * 0.4, my + dx * 0.4, mx + dy * 0.4, my - dx * 0.4); RenderThickness(1); } void UI_Canvas::DrawSnapPoint() { // don't draw if an action is occurring if (inst.edit.action != EditorAction::nothing) return; if (inst.edit.split_line.valid()) return; if (! Vis(snap_x, snap_y, 10)) return; RenderColor(FL_CYAN); int sx = SCREENX(snap_x); int sy = SCREENY(snap_y); RenderRect(sx, sy-2, 2, 6); RenderRect(sx-2, sy, 6, 2); } void UI_Canvas::DrawCurrentLine() { if (inst.edit.drawLine.from.is_nil()) return; const auto V = inst.level.vertices[inst.edit.drawLine.from.num]; v2double_t newpos = inst.edit.drawLine.to; // should draw a vertex? if (! (inst.edit.highlight.valid() || inst.edit.split_line.valid())) { RenderColor(FL_GREEN); DrawVertex(newpos.x, newpos.y, vertex_radius(inst.grid.getScale())); } RenderColor(RED); DrawKnobbyLine(V->x(), V->y(), newpos.x, newpos.y); DrawLineInfo(V->x(), V->y(), newpos.x, newpos.y, inst.grid.getRatio() > 0); // draw all the crossing points crossing_state_c cross(inst); inst.level.hover.findCrossingPoints(cross, V->xy(), inst.edit.drawLine.from.num, newpos, inst.edit.highlight.valid() ? inst.edit.highlight.num : -1); for (unsigned int k = 0 ; k < cross.points.size() ; k++) { cross_point_t& point = cross.points[k]; // ignore current split line (what new vertex is sitting on) if (point.ld >= 0 && point.ld == inst.edit.split_line.num) continue; if (point.vert >= 0) RenderColor(FL_GREEN); else RenderColor(HI_AND_SEL_COL); DrawSplitPoint(point.pos); } } bool UI_Canvas::SelboxGet(v2double_t &pos1, v2double_t &pos2) { pos1.x = std::min(inst.edit.selbox1.x, inst.edit.selbox2.x); pos1.y = std::min(inst.edit.selbox1.y, inst.edit.selbox2.y); pos2.x = std::max(inst.edit.selbox1.x, inst.edit.selbox2.x); pos2.y = std::max(inst.edit.selbox1.y, inst.edit.selbox2.y); int scr_dx = abs(SCREENX(pos2.x) - SCREENX(pos1.x)); int scr_dy = abs(SCREENY(pos2.y) - SCREENY(pos1.y)); // small boxes should be ignored (treated as a click + release) if (scr_dx < 5 && scr_dy < 5) return false; return true; // Ok } void UI_Canvas::SelboxDraw() { double x1 = std::min(inst.edit.selbox1.x, inst.edit.selbox2.x); double x2 = std::max(inst.edit.selbox1.x, inst.edit.selbox2.x); double y1 = std::min(inst.edit.selbox1.y, inst.edit.selbox2.y); double y2 = std::max(inst.edit.selbox1.y, inst.edit.selbox2.y); RenderColor(FL_CYAN); DrawMapLine(x1, y1, x2, y1); DrawMapLine(x2, y1, x2, y2); DrawMapLine(x2, y2, x1, y2); DrawMapLine(x1, y2, x1, y1); } v2double_t UI_Canvas::DragDelta() { v2double_t result = inst.edit.drag_cur.xy - inst.edit.drag_start.xy; v2double_t pixel_dpos = result * inst.grid.getScale(); // check that we have moved far enough from the start position, // giving the user the option to select the original place. if (std::max(fabs(pixel_dpos.x), fabs(pixel_dpos.y)) < config::minimum_drag_pixels*2) { return {}; } // handle ratio-lock of a single dragged vertex if (inst.edit.mode == ObjType::vertices && inst.grid.getRatio() > 0 && inst.edit.dragged.num >= 0 && inst.edit.drag_other_vert >= 0) { const auto v0 = inst.level.vertices[inst.edit.drag_other_vert]; const auto v1 = inst.level.vertices[inst.edit.dragged.num]; v2double_t newpos = inst.edit.drag_cur.xy; inst.grid.RatioSnapXY(newpos, v0->xy()); return newpos - v1->xy(); } if (inst.grid.getRatio() > 0) { v2double_t newpos = inst.edit.drag_cur.xy; inst.grid.RatioSnapXY(newpos, inst.edit.drag_start.xy); return newpos - inst.edit.drag_start.xy; } if (inst.grid.snaps()) { v2double_t focus = inst.edit.drag_focus.xy + result; result = inst.grid.Snap(focus) - inst.edit.drag_focus.xy; } return result; } //------------------------------------------------------------------------ void UI_Canvas::RenderSector(int num) { if (! inst.Subdiv_SectorOnScreen(num, map_lx, map_ly, map_hx, map_hy)) return; sector_subdivision_c *subdiv = inst.Subdiv_PolygonsForSector(num); if (! subdiv) return; /// fprintf(stderr, "RenderSector %d\n", num); rgb_color_t light_col = SectorLightColor(inst.level.sectors[num]->light); bool light_and_tex = false; SString tex_name; Img_c * img = NULL; if (inst.edit.sector_render_mode == SREND_Lighting) { RenderColor(light_col); } else if (inst.edit.sector_render_mode == SREND_SoundProp) { if (inst.edit.mode != ObjType::sectors || !inst.edit.highlight.valid()) return; const byte * prop = inst.SoundPropagation(inst.edit.highlight.num); switch ((propagate_level_e) prop[num]) { case PGL_Never: return; case PGL_Maybe: RenderColor(fl_rgb_color(64,64,192)); break; case PGL_Level_1: RenderColor(fl_rgb_color(192,32,32)); break; case PGL_Level_2: RenderColor(fl_rgb_color(192,96,32)); break; } } else { if (inst.edit.sector_render_mode <= SREND_Ceiling) light_and_tex = true; if (inst.edit.sector_render_mode == SREND_Ceiling || inst.edit.sector_render_mode == SREND_CeilBright) tex_name = inst.level.sectors[num]->CeilTex(); else tex_name = inst.level.sectors[num]->FloorTex(); if (inst.is_sky(tex_name)) { RenderColor(inst.wad.palette.getPaletteColor(inst.conf.miscInfo.sky_color)); } else { img = inst.wad.images.getMutableFlat(inst.conf, tex_name); if (! img) { img = &inst.wad.images.getMutableUnknownTexture(inst.conf); } } } #ifdef NO_OPENGL int tw = img ? img->width() : 1; int th = img ? img->height() : 1; const img_pixel_t *src_pix = img ? img->buf() : NULL; for (unsigned int i = 0 ; i < subdiv->polygons.size() ; i++) { sector_polygon_t *poly = &subdiv->polygons[i]; float py1 = poly->my[1]; // north most float py2 = poly->my[0]; int sy1 = SCREENY(py1); int sy2 = SCREENY(py2); // clip range to screen sy1 = std::max(sy1, y()); sy2 = std::min(sy2, y() + h() - 1); // reject polygons vertically off the screen if (sy1 > sy2) continue; // get left and right edges, unpacking a triangle if necessary float lx1 = poly->mx[1]; float lx2 = poly->mx[0]; float rx1 = poly->mx[2]; float rx2 = poly->mx[3]; if (poly->count == 3) { if (poly->my[2] == poly->my[0]) { rx1 = poly->mx[1]; rx2 = poly->mx[2]; } else // my[2] == my[1] { rx2 = poly->mx[0]; } } // visit each screen row for (short y = (short)sy1 ; y <= (short)sy2 ; y++) { // compute horizontal span float map_y = (float)MAPY(y); float lx = lx1 + (lx2 - lx1) * (map_y - py1) / (py2 - py1); float rx = rx1 + (rx2 - rx1) * (map_y - py1) / (py2 - py1); int sx1 = SCREENX(lx); int sx2 = SCREENX(rx); // clip span to screen sx1 = std::max(sx1, x()); sx2 = std::min(sx2, x() + w() - 1); // reject spans completely off the screen if (sx2 < sx1) continue; /// fprintf(stderr, " span : y=%d x=%d..%d\n", y, x1, x2); // solid color? if (! img) { RenderRect(sx1, y, sx2 - sx1 + 1, 1); continue; } int x = sx1; int span_w = sx2 - sx1 + 1; uint8_t *dest = rgb_buf + ((x - rgb_x) + (y - rgb_y) * rgb_w) * 3; uint8_t *dest_end = dest + span_w * 3; // the logic here for non-64x64 textures matches the software // 3D renderer, but is different than ZDoom (which scales them). int ty = (0 - (int)MAPY(y)) & (th - 1); if (light_and_tex) { int r = RGB_RED(light_col) * 0x101; int g = RGB_GREEN(light_col) * 0x101; int b = RGB_BLUE(light_col) * 0x101; for (; dest < dest_end ; dest += 3, x++) { int tx = (int)MAPX(x) & (tw - 1); img_pixel_t pix = src_pix[ty * tw + tx]; inst.wad.palette.decodePixel(pix, dest[0], dest[1], dest[2]); dest[0] = (uint8_t)(((int)dest[0] * r) >> 16); dest[1] = (uint8_t)(((int)dest[1] * g) >> 16); dest[2] = (uint8_t)(((int)dest[2] * b) >> 16); } } else // fullbright version { for (; dest < dest_end ; dest += 3, x++) { int tx = (int)MAPX(x) & (tw - 1); img_pixel_t pix = src_pix[ty * tw + tx]; inst.wad.palette.decodePixel(pix, dest[0], dest[1], dest[2]); } } } } #else // OpenGL if (img) { if (light_and_tex) RenderColor(light_col); else glColor3f(1, 1, 1); glEnable(GL_TEXTURE_2D); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.5); img->bind_gl(inst.wad); } else { // color was set above, set texture to solid white glBindTexture(GL_TEXTURE_2D, 0); } for (unsigned int i = 0 ; i < subdiv->polygons.size() ; i++) { sector_polygon_t *poly = &subdiv->polygons[i]; // draw polygon glBegin(GL_POLYGON); for (int p = 0 ; p < poly->count ; p++) { int sx = SCREENX(poly->mx[p]); int sy = SCREENY(poly->my[p]); if (img) { // this logic follows ZDoom, which scales large flats to // occupy a 64x64 unit area. I presume wall textures are // handled similarily.... glTexCoord2f(poly->mx[p] / 64.0f, poly->my[p] / 64.0f); } glVertex2i(sx, sy); } glEnd(); } if (img) { glDisable(GL_TEXTURE_2D); glDisable(GL_ALPHA_TEST); } #endif } //------------------------------------------------------------------------ // CUSTOM S/W DRAWING CODE //------------------------------------------------------------------------ void UI_Canvas::PrepareToDraw() { #ifdef NO_OPENGL rgb_x = x(); rgb_y = y(); if (rgb_w != w() || rgb_h != h()) { if (rgb_buf) delete[] rgb_buf; rgb_w = w(); rgb_h = h(); rgb_buf = new byte[rgb_w * rgb_h * 3]; } #endif } void UI_Canvas::Blit() { #ifdef NO_OPENGL fl_draw_image(rgb_buf, x(), y(), w(), h()); #endif } void UI_Canvas::RenderColor(Fl_Color c) { #ifdef NO_OPENGL Fl::get_color(c, cur_col.r, cur_col.g, cur_col.b); #else gl_color(c); #endif } void UI_Canvas::RenderFontSize(int size) { cur_font = size; } void UI_Canvas::RenderThickness(int w) { #ifdef NO_OPENGL thickness = (w < 2) ? 1 : 2; #else glLineWidth(static_cast(w)); #endif } void UI_Canvas::RenderRect(int rx, int ry, int rw, int rh) { #ifndef NO_OPENGL gl_rectf(rx, ry, rw, rh); #else // software version rx -= rgb_x; ry -= rgb_y; // clip to screen if (rx + rw > rgb_w) { rw = rgb_w - rx; } if (rx < 0) { rw += rx; rx = 0; } if (rw <= 0) return; if (ry + rh > rgb_h) { rh = rgb_h - ry; } if (ry < 0) { rh += ry; ry = 0; } if (rh <= 0) return; // fast method for greyscale (especially BLACK) if (cur_col.r == cur_col.g && cur_col.g == cur_col.b) { byte *dest = rgb_buf + (ry * rgb_w * 3) + (rx * 3); for ( ; rh > 0 ; rh--, dest += (rgb_w * 3)) memset(dest, cur_col.r, rw * 3); return; } // slower method for all other colors byte *base = rgb_buf + (ry * rgb_w * 3) + (rx * 3); for ( ; rh > 0 ; rh--, base += (rgb_w * 3)) { byte *dest = base; for (int w2 = rw ; w2 > 0 ; w2--) { *dest++ = cur_col.r; *dest++ = cur_col.g; *dest++ = cur_col.b; } } #endif } #ifdef NO_OPENGL enum outcode_flags_e { O_TOP = 1, O_BOTTOM = 2, O_LEFT = 4, O_RIGHT = 8, }; int UI_Canvas::Calc_Outcode(int x, int y) { return ((y < 0) ? O_TOP : 0) | ((y >= rgb_h) ? O_BOTTOM : 0) | ((x < 0) ? O_LEFT : 0) | ((x >= rgb_w) ? O_RIGHT : 0); } #endif // NO_OPENGL void UI_Canvas::RenderLine(int x1, int y1, int x2, int y2) { #ifndef NO_OPENGL glBegin(GL_LINE_STRIP); glVertex2i(x1, y1); glVertex2i(x2, y2); glEnd(); #else // software line drawing if (x1 == x2) { if (y1 > y2) std::swap(y1, y2); RenderRect(x1, y1, thickness, y2 - y1 + thickness); return; } if (y1 == y2) { if (x1 > x2) std::swap(x1, x2); RenderRect(x1, y1, x2 - x1 + thickness, thickness); return; } // completely off the screen? x1 -= rgb_x; y1 -= rgb_y; x2 -= rgb_x; y2 -= rgb_y; int out1 = Calc_Outcode(x1, y1); int out2 = Calc_Outcode(x2, y2); if (out1 & out2) return; // clip diagonal line to the map // (this is the Cohen-Sutherland clipping algorithm) while (out1 | out2) { // may be partially inside box, find an outside point int outside = (out1 ? out1 : out2); int dx = x2 - x1; int dy = y2 - y1; // this almost certainly cannot happen, but for the sake of // robustness we check anyway (just in case) if (dx == 0 && dy == 0) return; int new_x, new_y; // clip to each side if (outside & O_TOP) { new_y = 0; new_x = x1 + dx * (new_y - y1) / dy; } else if (outside & O_BOTTOM) { new_y = rgb_h-1; new_x = x1 + dx * (new_y - y1) / dy; } else if (outside & O_LEFT) { new_x = 0; new_y = y1 + dy * (new_x - x1) / dx; } else { SYS_ASSERT(outside & O_RIGHT); new_x = rgb_w-1; new_y = y1 + dy * (new_x - x1) / dx; } if (out1) { x1 = new_x; y1 = new_y; out1 = Calc_Outcode(x1, y1); } else { SYS_ASSERT(out2); x2 = new_x; y2 = new_y; out2 = Calc_Outcode(x2, y2); } if (out1 & out2) return; } // this is the Bresenham line drawing algorithm // (based on code from am_map.c in the GPL DOOM source) int dx = x2 - x1; int dy = y2 - y1; int ax = 2 * (dx < 0 ? -dx : dx); int ay = 2 * (dy < 0 ? -dy : dy); int sx = dx < 0 ? -1 : 1; int sy = dy < 0 ? -1 : 1; int x = x1; int y = y1; if (ax > ay) // horizontal stepping { int d = ay - ax/2; raw_pixel(x, y); if (thickness == 2 && y+1 < rgb_h) raw_pixel(x, y+1); while (x != x2) { if (d>=0) { y += sy; d -= ax; } x += sx; d += ay; raw_pixel(x, y); if (thickness == 2 && y+1 < rgb_h) raw_pixel(x, y+1); } } else // vertical stepping { int d = ax - ay/2; raw_pixel(x, y); if (thickness == 2 && x+1 < rgb_w) raw_pixel(x+1, y); while (y != y2) { if (d >= 0) { x += sx; d -= ay; } y += sy; d += ax; raw_pixel(x, y); if (thickness == 2 && x+1 < rgb_w) raw_pixel(x+1, y); } } #endif } void UI_Canvas::RenderNumString(int x, int y, const char *s) { // NOTE: string is limited to the digits '0' to '9', spaces, // and the characters '-', '.' and ':'. Img_c *font_img; int font_cw; int font_ch; int font_step; if (cur_font < 17) { font_img = &inst.wad.images.IM_DigitFont_11x14(); font_cw = 11; font_ch = 14; font_step = font_cw - 2; } else { font_img = &inst.wad.images.IM_DigitFont_14x19(); font_cw = 14; font_ch = 19; font_step = font_cw - 2; } #ifndef NO_OPENGL glEnable(GL_TEXTURE_2D); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.5); // bind the sprite image (upload it to OpenGL if needed) font_img->bind_gl(inst.wad); #endif // compute total size int total_w = static_cast(strlen(s) * font_step + 2); // center the string at the given coordinate x -= total_w / 2; y -= font_ch / 2; for ( ; *s ; s++, x += font_step) { int ch = (*s & 0x7f); if (ch == ' ') continue; if ('0' <= ch && ch <= '9') ch -= '0'; else if (ch == ':') ch = 10; else if (ch == '.') ch = 11; else if (ch == '^') ch = 13; else // '-' ch = 12; RenderFontChar(x, y, font_img, ch * font_cw, 0, font_cw, font_ch); } #ifndef NO_OPENGL glDisable(GL_ALPHA_TEST); glDisable(GL_TEXTURE_2D); #endif } void UI_Canvas::RenderFontChar(int rx, int ry, Img_c *img, int ix, int iy, int iw, int ih) { #ifdef NO_OPENGL // software rendering rx -= rgb_x; ry -= rgb_y; // clip to screen int sx1 = std::max(rx, 0); int sy1 = std::max(ry, 0); int sx2 = std::min(rx + iw, rgb_w) - 1; int sy2 = std::min(ry + ih, rgb_h) - 1; if (sx1 >= sx2 || sy1 >= sy2) return; for (int sy = sy1 ; sy <= sy2 ; sy++, iy++) { const img_pixel_t *src = img->buf() + (ix + iy * img->width()); byte *dest = rgb_buf + 3 * (sx1 + sy * rgb_w); for (int sx = sx1 ; sx <= sx2 ; sx++, dest += 3) { img_pixel_t pix = *src++; if (pix != TRANS_PIXEL) { inst.wad.palette.decodePixel(pix, dest[0], dest[1], dest[2]); } } } #else // OpenGL int rx2 = rx + iw; int ry2 = ry + ih; int img_w, img_h; if (global::use_npot_textures) { img_w = img->width(); img_h = img->height(); } else { img_w = RoundPOW2(img->width()); img_h = RoundPOW2(img->height()); } float tx1 = (float)ix / (float)img_w; float ty1 = (float)iy / (float)img_h; float tx2 = (float)(ix + iw) / (float)img_w; float ty2 = (float)(iy + ih) / (float)img_h; glColor3f(1, 1, 1); glBegin(GL_QUADS); glTexCoord2f(tx1, ty1); glVertex2i(rx, ry); glTexCoord2f(tx1, ty2); glVertex2i(rx, ry2); glTexCoord2f(tx2, ty2); glVertex2i(rx2, ry2); glTexCoord2f(tx2, ty1); glVertex2i(rx2, ry); glEnd(); #endif } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_canvas.h000066400000000000000000000140461464327712600204560ustar00rootroot00000000000000//------------------------------------------------------------------------ // EDITING CANVAS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2008-2019 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_CANVAS_H__ #define __EUREKA_UI_CANVAS_H__ #ifndef NO_OPENGL #include #else #include #endif #include "m_events.h" #include "m_select.h" #include "e_objects.h" #include "r_grid.h" #include "sys_macro.h" class Img_c; enum class Side; struct v2double_t; #ifdef NO_OPENGL class UI_Canvas : public Fl_Widget #else class UI_Canvas : public Fl_Gl_Window #endif { private: // this is used to detect changes in inst.edit.highlight // [ to prevent unnecessary redraws ] Objid last_highlight; // this is used to detect changes in inst.edit.split_line (etc) // [ to prevent unnecessary redraws ] int last_splitter; double last_split_x; double last_split_y; // this is the cached grid-snap position double snap_x, snap_y; // drawing state only double map_lx, map_ly; double map_hx, map_hy; bitvec_c seen_sectors; // a copy of x() and y() for software renderer, 0 for OpenGL int xx, yy; // state for the custom S/W rendering code #ifdef NO_OPENGL byte *rgb_buf; int rgb_x, rgb_y; int rgb_w, rgb_h; int thickness; struct { byte r, g, b; } cur_col; #endif int cur_font; // 14 or 19 public: UI_Canvas(Instance &inst, int X, int Y, int W, int H, const char *label = NULL); virtual ~UI_Canvas(); public: // FLTK virtual method for handling input events. int handle(int event); // FLTK virtual method for resizing. void resize(int X, int Y, int W, int H); // delete any OpenGL context which is assigned to the window. // call this whenever OpenGL textures need to be reloaded. void DeleteContext(); void DrawEverything(); void UpdateHighlight(); void CheckGridSnap(); void DrawSelection(selection_c *list); void DrawSectorSelection(selection_c *list, double dx, double dy); void DrawHighlight(ObjType objtype, int objnum, bool skip_lines = false, double dx=0, double dy=0); void DrawHighlightTransform(ObjType objtype, int objnum); void DrawTagged(ObjType objtype, int objnum); // returns true if ok, false if box was very small bool SelboxGet(v2double_t &pos1, v2double_t &pos2); v2double_t DragDelta(); void PointerPos(bool in_event = false); // return -1 if too small, 0 is OK, 1 is too big to fit int ApproxBoxSize(int mx1, int my1, int mx2, int my2); private: // FLTK virtual method for drawing void draw(); void DrawMap(); void DrawGrid_Dotty(); void DrawGrid_Normal(); void DrawAxes(Fl_Color col); void DrawMapBounds(); void DrawVertices(); void DrawLinedefs(); void DrawThings(); void DrawThingBodies(); void DrawThingSprites(); void DrawMapLine(double map_x1, double map_y1, double map_x2, double map_y2); void DrawMapVector(double map_x1, double map_y1, double map_x2, double map_y2); void DrawMapArrow(double map_x1, double map_y1, int r, int angle); void DrawKnobbyLine(double map_x1, double map_y1, double map_x2, double map_y2, bool reverse = false); void DrawSplitLine(double map_x1, double map_y1, double map_x2, double map_y2); void DrawSplitPoint(const v2double_t &map_pos); void DrawVertex(double map_x, double map_y, int r); void DrawThing(double map_x, double map_y, int r, int angle, bool big_arrow); void DrawCamera(); void DrawSectorNum(int mx1, int my1, int mx2, int my2, Side side, int n); void DrawLineNumber(int mx1, int my1, int mx2, int my2, Side side, int n); void DrawLineInfo(double map_x1, double map_y1, double map_x2, double map_y2, bool force_ratio); void DrawNumber(int x, int y, int num); void DrawCurrentLine(); void DrawSnapPoint(); void SelboxDraw(); // calc screen-space normal of a line int NORMALX(int len, double dx, double dy); int NORMALY(int len, double dx, double dy); #ifdef NO_OPENGL // convert screen coordinates to map coordinates inline double MAPX(int sx) const; inline double MAPY(int sy) const; // convert map coordinates to screen coordinates inline int SCREENX(double mx) const; inline int SCREENY(double my) const; #else // convert GL coordinates to map coordinates inline double MAPX(int sx) const; inline double MAPY(int sy) const; // convert map coordinates to GL coordinates inline int SCREENX(double mx) const; inline int SCREENY(double my) const; #endif inline bool Vis(double x, double y, int r) const { return (x+r >= map_lx) && (x-r <= map_hx) && (y+r >= map_ly) && (y-r <= map_hy); } inline bool Vis(double x1, double y1, double x2, double y2) const { return (x2 >= map_lx) && (x1 <= map_hx) && (y2 >= map_ly) && (y1 <= map_hy); } void PrepareToDraw(); void Blit(); void RenderColor(Fl_Color c); void RenderThickness(int w); void RenderFontSize(int size); void RenderLine(int x1, int y1, int x2, int y2); void RenderRect(int rx, int ry, int rw, int rh); void RenderNumString(int x, int y, const char *s); void RenderFontChar(int rx, int ry, Img_c *img, int ix, int iy, int iw, int ih); void RenderSprite(int sx, int sy, float scale, Img_c *img); void RenderSector(int num); #ifdef NO_OPENGL int Calc_Outcode(int x, int y); // this is raw, it does no checking! inline void raw_pixel(int rx, int ry) const { byte *dest = rgb_buf + (rx + ry * rgb_w) * 3; dest[0] = cur_col.r; dest[1] = cur_col.g; dest[2] = cur_col.b; } #endif Instance &inst; }; #endif /* __EUREKA_UI_CANVAS_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_default.cc000066400000000000000000000320261464327712600207630ustar00rootroot00000000000000//------------------------------------------------------------------------ // DEFAULT PROPERTIES //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Instance.h" #include "main.h" #include "ui_misc.h" #include "ui_window.h" #include "e_main.h" #include "e_cutpaste.h" #include "m_config.h" // gui_scheme #include "m_game.h" #include "r_render.h" #include "w_rawdef.h" #include "w_texture.h" #define HIDE_BG (config::gui_scheme == 2 ? FL_DARK3 : FL_DARK1) UI_DefaultProps::UI_DefaultProps(Instance &inst, int X, int Y, int W, int H) : Fl_Group(X, Y, W, H, NULL), inst(inst) { box(FL_FLAT_BOX); Fl_Button *hide_button = new Fl_Button(X + 14, Y + 14, 22, 22, "X"); hide_button->color(HIDE_BG, HIDE_BG); hide_button->labelsize(14); hide_button->callback(hide_callback, this); Fl_Box *title = new Fl_Box(X + 60, Y + 10, W - 70, 30, "Default Properties"); title->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); title->labelsize(22); Y += 35; H -= 35; X += 6; W -= 12; // ---- LINEDEF TEXTURES ------------ Y += 32; w_pic = new UI_Pic(inst, X+W-76, Y, 64, 64); w_pic->callback(tex_callback, this); w_pic->AllowHighlight(true); Y += 20; w_tex = new UI_DynInput(X+68, Y, 108, 24, "Wall: "); w_tex->callback(tex_callback, this); w_tex->callback2(dyntex_callback, this); w_tex->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); Y += w_tex->h() + 50; // ---- SECTOR PROPS -------------- c_pic = new UI_Pic(inst, X+W-76, Y+2, 64, 64); f_pic = new UI_Pic(inst, X+W-76, Y+78, 64, 64); c_pic->callback(flat_callback, this); f_pic->callback(flat_callback, this); f_pic->AllowHighlight(true); c_pic->AllowHighlight(true); c_tex = new UI_DynInput(X+68, Y, 108, 24, "Ceiling: "); c_tex->align(FL_ALIGN_LEFT); c_tex->callback(flat_callback, this); c_tex->callback2(dyntex_callback, this); c_tex->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); Y += c_tex->h() + 3; ceil_h = new UI_DynIntInput(X+68, Y, 64, 24, ""); ceil_h->align(FL_ALIGN_LEFT); ceil_h->callback(height_callback, this); ceil_h->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); ce_down = new Fl_Button(X+24, Y+1, 30, 22, "-"); ce_up = new Fl_Button(X+68+68, Y+1, 30, 22, "+"); ce_down->labelfont(FL_HELVETICA_BOLD); ce_up ->labelfont(FL_HELVETICA_BOLD); ce_down->labelsize(16); ce_up ->labelsize(16); ce_down->callback(button_callback, this); ce_up ->callback(button_callback, this); Y += ceil_h->h() + 8; floor_h = new UI_DynIntInput(X+68, Y, 64, 24, ""); floor_h->align(FL_ALIGN_LEFT); floor_h->callback(height_callback, this); floor_h->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); fl_down = new Fl_Button(X+24, Y+1, 30, 22, "-"); fl_up = new Fl_Button(X+68+68, Y+1, 30, 22, "+"); fl_down->labelfont(FL_HELVETICA_BOLD); fl_up ->labelfont(FL_HELVETICA_BOLD); fl_down->labelsize(16); fl_up ->labelsize(16); fl_down->callback(button_callback, this); fl_up ->callback(button_callback, this); Y += floor_h->h() + 3; f_tex = new UI_DynInput(X+68, Y, 108, 24, "Floor: "); f_tex->align(FL_ALIGN_LEFT); f_tex->callback(flat_callback, this); f_tex->callback2(dyntex_callback, this); f_tex->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); Y += f_tex->h() + 8; light = new UI_DynIntInput(X+68, Y, 64, 24, "Light: "); light->align(FL_ALIGN_LEFT); light->callback(height_callback, this); light->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); Y += light->h() + 40; // ---- THING PROPS -------------- thing = new UI_DynInput(X+60, Y+20, 64, 24, "Thing: "); thing->align(FL_ALIGN_LEFT); thing->callback(thing_callback, this); thing->callback2(dynthing_callback, this); thing->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); thing->type(FL_INT_INPUT); th_desc = new Fl_Output(X+60, Y+80-26, 122, 24); th_sprite = new UI_Pic(inst, X+W-90, Y, 80,80, "Sprite"); th_sprite->callback(thing_callback, this); resizable(NULL); mFixUp.loadFields({ w_tex, ceil_h, light, floor_h, c_tex, f_tex, thing }); end(); } UI_DefaultProps::~UI_DefaultProps() { } void UI_DefaultProps::hide_callback(Fl_Widget *w, void *data) { auto props = static_cast(data); props->inst.main_win->HideSpecialPanel(); } void UI_DefaultProps::SetIntVal(Fl_Int_Input *w, int value) { w->value(std::to_string(value).c_str()); } void UI_DefaultProps::UpdateThingDesc() { const thingtype_t &info = inst.conf.getThingType(inst.conf.default_thing); th_desc->value(info.desc.c_str()); th_sprite->GetSprite(inst.conf.default_thing, FL_DARK2); } void UI_DefaultProps::SetThing(int number) { inst.conf.default_thing = number; mFixUp.setInputValue(thing, SString(inst.conf.default_thing).c_str()); UpdateThingDesc(); } SString UI_DefaultProps::Normalize_and_Dup(UI_DynInput *w) { SString normalized = NormalizeTex(w->value()); mFixUp.setInputValue(w, normalized.c_str()); return normalized; } void UI_DefaultProps::tex_callback(Fl_Widget *w, void *data) { UI_DefaultProps *box = (UI_DefaultProps *)data; if (w == box->w_pic) { UI_Pic * pic = (UI_Pic *) w; pic->Selected(! pic->Selected()); if (pic->Selected()) box->inst.main_win->BrowserMode(BrowserMode::textures); return; } if (w == box->w_tex) { box->inst.conf.default_wall_tex = box->Normalize_and_Dup(box->w_tex); } box->w_pic->GetTex(box->w_tex->value()); } void UI_DefaultProps::flat_callback(Fl_Widget *w, void *data) { UI_DefaultProps *box = (UI_DefaultProps *)data; if (w == box->f_pic || w == box->c_pic) { UI_Pic * pic = (UI_Pic *) w; pic->Selected(! pic->Selected()); if (pic->Selected()) box->inst.main_win->BrowserMode(BrowserMode::flats); return; } if (w == box->f_tex) box->inst.conf.default_floor_tex = box->Normalize_and_Dup(box->f_tex); if (w == box->c_tex) box->inst.conf.default_ceil_tex = box->Normalize_and_Dup(box->c_tex); box->f_pic->GetFlat(box->f_tex->value()); box->c_pic->GetFlat(box->c_tex->value()); } void UI_DefaultProps::dyntex_callback(Fl_Widget *w, void *data) { UI_DefaultProps *box = (UI_DefaultProps *)data; if (w == box->w_tex) { box->w_pic->GetTex(box->w_tex->value()); } else if (w == box->f_tex) { box->f_pic->GetFlat(box->f_tex->value()); } else if (w == box->c_tex) { box->c_pic->GetFlat(box->c_tex->value()); } } void UI_DefaultProps::button_callback(Fl_Widget *w, void *data) { UI_DefaultProps *box = (UI_DefaultProps *)data; keycode_t mod = Fl::event_state() & EMOD_ALL_MASK; int diff = 8; if (mod & EMOD_SHIFT) diff = 1; else if (mod & EMOD_COMMAND) diff = 64; box->mFixUp.checkDirtyFields(); if (w == box->fl_up) global::default_floor_h += diff; if (w == box->fl_down) global::default_floor_h -= diff; if (w == box->ce_up) global::default_ceil_h += diff; if (w == box->ce_down) global::default_ceil_h -= diff; box->SetIntVal(box->floor_h, global::default_floor_h); box->SetIntVal(box-> ceil_h, global::default_ceil_h); } void UI_DefaultProps::height_callback(Fl_Widget *w, void *data) { UI_DefaultProps *box = (UI_DefaultProps *)data; global::default_floor_h = atoi(box->floor_h->value()); global::default_ceil_h = atoi(box-> ceil_h->value()); global::default_light_level = atoi(box->light->value()); } void UI_DefaultProps::thing_callback(Fl_Widget *w, void *data) { UI_DefaultProps *box = (UI_DefaultProps *)data; if (w == box->th_sprite) { box->inst.main_win->BrowserMode(BrowserMode::things); return; } box->inst.conf.default_thing = atoi(box->thing->value()); box->UpdateThingDesc(); } void UI_DefaultProps::dynthing_callback(Fl_Widget *w, void *data) { UI_DefaultProps *box = (UI_DefaultProps *)data; int value = atoi(box->thing->value()); const thingtype_t &info = box->inst.conf.getThingType(value); box->th_desc->value(info.desc.c_str()); box->th_sprite->GetSprite(value, FL_DARK2); } void UI_DefaultProps::LoadValues() { mFixUp.setInputValue(w_tex, inst.conf.default_wall_tex.c_str()); mFixUp.setInputValue(f_tex, inst.conf.default_floor_tex.c_str()); mFixUp.setInputValue(c_tex, inst.conf.default_ceil_tex.c_str()); w_pic->GetTex (w_tex->value()); f_pic->GetFlat(f_tex->value()); c_pic->GetFlat(c_tex->value()); SetIntVal(floor_h, global::default_floor_h); SetIntVal( ceil_h, global::default_ceil_h); SetIntVal( light, global::default_light_level); mFixUp.setInputValue(thing, SString(inst.conf.default_thing).c_str()); UpdateThingDesc(); } void UI_DefaultProps::CB_Copy(int sel_pics) { const char *name = NULL; switch (sel_pics) { case 1: name = f_tex->value(); break; case 2: name = c_tex->value(); break; case 4: name = w_tex->value(); break; default: inst.Beep("multiple textures"); return; } if (sel_pics & 4) Texboard_SetTex(name, inst.conf); else Texboard_SetFlat(name, inst.conf); } void UI_DefaultProps::CB_Paste(int sel_pics) { if (sel_pics & 1) { mFixUp.setInputValue(f_tex, BA_GetString(Texboard_GetFlatNum(inst.conf)).c_str()); f_tex->do_callback(); } if (sel_pics & 2) { mFixUp.setInputValue(c_tex, BA_GetString(Texboard_GetFlatNum(inst.conf)).c_str()); c_tex->do_callback(); } if (sel_pics & 4) { mFixUp.setInputValue(w_tex, BA_GetString(Texboard_GetTexNum(inst.conf)).c_str()); w_tex->do_callback(); } } void UI_DefaultProps::CB_Delete(int sel_pics) { // we abuse the delete function to turn sector ceilings into sky if (sel_pics & 1) { mFixUp.setInputValue(f_tex, inst.conf.miscInfo.sky_flat.c_str()); f_tex->do_callback(); } if (sel_pics & 2) { mFixUp.setInputValue(c_tex, inst.conf.miscInfo.sky_flat.c_str()); c_tex->do_callback(); } } // // Clipboard operation // bool UI_DefaultProps::ClipboardOp(EditCommand op) { int sel_pics = (f_pic->Selected() ? 1 : 0) | (c_pic->Selected() ? 2 : 0) | (w_pic->Selected() ? 4 : 0); if (sel_pics == 0) { sel_pics = (f_pic->Highlighted() ? 1 : 0) | (c_pic->Highlighted() ? 2 : 0) | (w_pic->Highlighted() ? 4 : 0); } if(sel_pics == 0) return false; switch(op) { case EditCommand::copy: CB_Copy(sel_pics); break; case EditCommand::paste: CB_Paste(sel_pics); break; case EditCommand::cut: inst.Beep("cannot cut that"); break; case EditCommand::del: CB_Delete(sel_pics); break; } return true; } void UI_DefaultProps::BrowsedItem(BrowserMode kind, int number, const char *name, int e_state) { if (kind == BrowserMode::things) { SetThing(number); return; } if (! (kind == BrowserMode::textures || kind == BrowserMode::flats)) return; int sel_pics = (f_pic->Selected() ? 1 : 0) | (c_pic->Selected() ? 2 : 0) | (w_pic->Selected() ? 4 : 0); if (sel_pics == 0) { if (kind == BrowserMode::textures) sel_pics = 4; else sel_pics = (e_state & FL_BUTTON3) ? 2 : 1; } if (sel_pics & 1) { mFixUp.setInputValue(f_tex, name); f_tex->do_callback(); } if (sel_pics & 2) { mFixUp.setInputValue(c_tex, name); c_tex->do_callback(); } if (sel_pics & 4) { mFixUp.setInputValue(w_tex, name); w_tex->do_callback(); } } void UI_DefaultProps::UnselectPics() { w_pic->Unhighlight(); f_pic->Unhighlight(); c_pic->Unhighlight(); w_pic->Selected(false); f_pic->Selected(false); c_pic->Selected(false); } //------------------------------------------------------------------------ bool Props_ParseUser(Instance &inst, const std::vector &tokens) { // syntax is: default if (tokens.size() < 3) return false; if (tokens[0] != "default") return false; if (tokens[1] == "floor_h") global::default_floor_h = atoi(tokens[2]); if (tokens[1] == "ceil_h") global::default_ceil_h = atoi(tokens[2]); if (tokens[1] == "light_level") global::default_light_level = atoi(tokens[2]); if (tokens[1] == "thing") inst.conf.default_thing = atoi(tokens[2]); if (tokens[1] == "floor_tex") inst.conf.default_floor_tex = tokens[2]; if (tokens[1] == "ceil_tex") inst.conf.default_ceil_tex = tokens[2]; if (tokens[1] == "mid_tex") inst.conf.default_wall_tex = tokens[2]; return true; } void Instance::Props_WriteUser(std::ostream &os) const { os << '\n'; os << "default floor_h " << global::default_floor_h << '\n'; os << "default ceil_h " << global::default_ceil_h << '\n'; os << "default light_level " << global::default_light_level << '\n'; os << "default thing " << conf.default_thing << '\n'; os << "default mid_tex \"" << conf.default_wall_tex.getTidy("\"") << "\"\n"; os << "default floor_tex \"" << conf.default_floor_tex.getTidy("\"") << "\"\n"; os << "default ceil_tex \"" << conf.default_ceil_tex.getTidy("\"") << "\"\n"; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_default.h000066400000000000000000000051151464327712600206240ustar00rootroot00000000000000//------------------------------------------------------------------------ // DEFAULT PROPERTIES //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_DEFAULT_H__ #define __EUREKA_UI_DEFAULT_H__ #include "e_cutpaste.h" #include "ui_panelinput.h" class Fl_Int_Input; class Fl_Output; class UI_DynIntInput; class UI_DefaultProps : public Fl_Group { private: UI_Pic *w_pic; UI_DynInput *w_tex; UI_DynIntInput *ceil_h; UI_DynIntInput *light; UI_DynIntInput *floor_h; Fl_Button *ce_down, *ce_up; Fl_Button *fl_down, *fl_up; UI_Pic *c_pic; UI_DynInput *c_tex; UI_Pic *f_pic; UI_DynInput *f_tex; UI_DynInput *thing; Fl_Output *th_desc; UI_Pic *th_sprite; Instance &inst; PanelFieldFixUp mFixUp; public: UI_DefaultProps(Instance &inst, int X, int Y, int W, int H); virtual ~UI_DefaultProps(); // see ui_window.h for description of these two methods bool ClipboardOp(EditCommand op); void BrowsedItem(BrowserMode kind, int number, const char *name, int e_state); void UnselectPics(); void LoadValues(); private: void SetIntVal(Fl_Int_Input *w, int value); void UpdateThingDesc(); void SetThing(int number); void CB_Copy (int sel_pics); void CB_Paste (int sel_pics); void CB_Delete(int sel_pics); SString Normalize_and_Dup(UI_DynInput *w); private: static void hide_callback(Fl_Widget *w, void *data); static void tex_callback(Fl_Widget *w, void *data); static void dyntex_callback(Fl_Widget *w, void *data); static void flat_callback(Fl_Widget *w, void *data); static void button_callback(Fl_Widget *w, void *data); static void height_callback(Fl_Widget *w, void *data); static void thing_callback(Fl_Widget *w, void *data); static void dynthing_callback(Fl_Widget *w, void *data); }; bool Props_ParseUser(Instance &inst, const std::vector &tokens); #endif /* __EUREKA_UI_DEFAULT_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_dialog.cc000066400000000000000000000171011464327712600205730ustar00rootroot00000000000000//------------------------------------------------------------------------ // DIALOG when all fucked up //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2013 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include "main.h" #include "ui_window.h" #define BUT_W 100 #define BUT_H 26 #define ICON_W 40 #define ICON_H 40 #define FONT_SIZE 16 // // Dialog box callback context // struct DialogContext { int result; std::vector buttons; }; static void dialog_close_callback(Fl_Widget *w, void *data) { auto context = static_cast(data); context->result = 0; } static void dialog_button_callback(Fl_Widget *w, void *data) { auto context = static_cast(data); auto it = std::find(context->buttons.begin(), context->buttons.end(), w); SYS_ASSERT(it != context->buttons.end()); context->result = static_cast(it - context->buttons.begin()); } // // Message box icon // enum class MessageBoxIcon { information, exclamation, question }; static int DialogShowAndRun( MessageBoxIcon icon_type, const SString &message, const SString &title, const SString &link_title = NULL, const SString &link_url = NULL, const std::vector *labels = NULL) { DialogContext context = {}; context.result = -1; // determine required size int mesg_W = 480; // NOTE: fl_measure will wrap to this! int mesg_H = 0; fl_font(FL_HELVETICA, FONT_SIZE); fl_measure(message.c_str(), mesg_W, mesg_H); if (mesg_W < 200) mesg_W = 200; if (mesg_H < 60) mesg_H = 60; // add a little wiggle room mesg_W += 16; mesg_H += 8; int total_W = 10 + ICON_W + 10 + mesg_W + 10; int total_H = 10 + mesg_H + 10; if (link_title.good()) total_H += FONT_SIZE + 8; total_H += 12 + BUT_H + 12; // create window... UI_Escapable_Window *dialog = new UI_Escapable_Window(total_W, total_H, title.c_str()); dialog->size_range(total_W, total_H, total_W, total_H); dialog->callback((Fl_Callback *) dialog_close_callback, &context); // create the error icon... Fl_Box *icon = new Fl_Box(10, 10 + (10 + mesg_H - ICON_H) / 2, ICON_W, ICON_H, ""); icon->box(FL_OVAL_BOX); icon->align(FL_ALIGN_INSIDE | FL_ALIGN_CLIP); icon->labelfont(FL_HELVETICA_BOLD); icon->labelsize(26); switch (icon_type) { case MessageBoxIcon::exclamation: icon->label("!"); icon->color(FL_RED, FL_RED); icon->labelcolor(FL_WHITE); break; case MessageBoxIcon::question: icon->label("?"); icon->color(FL_GREEN, FL_GREEN); icon->labelcolor(FL_BLACK); break; case MessageBoxIcon::information: default: icon->label("i"); icon->color(FL_BLUE, FL_BLUE); icon->labelcolor(FL_WHITE); break; } // create the message area... Fl_Box *box = new Fl_Box(ICON_W + 20, 10, mesg_W, mesg_H, message.c_str()); box->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE | FL_ALIGN_WRAP); box->labelfont(FL_HELVETICA); box->labelsize(FONT_SIZE); // create the hyperlink... if (link_title.good()) { SYS_ASSERT(link_url.good()); UI_HyperLink *link = new UI_HyperLink(ICON_W + 20, 10 + mesg_H, mesg_W, 24, link_title.c_str(), link_url.c_str()); link->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT); link->labelfont(FL_HELVETICA); link->labelsize(FONT_SIZE); } // create buttons... int GROUP_H = BUT_H + 12 * 2; Fl_Button *focus_button = NULL; Fl_Group *b_group = new Fl_Group(0, total_H - GROUP_H, total_W, GROUP_H); b_group->box(FL_FLAT_BOX); b_group->color(WINDOW_BG, WINDOW_BG); b_group->end(); int but_count = labels ? (int)labels->size() : 1; context.buttons.resize(but_count); // we'll fill it end to start int but_x = total_W - 40; int but_y = b_group->y() + 12; for (int b = but_count - 1 ; b >= 0 ; b--) { const char *text = labels ? (*labels)[b].c_str() : (icon_type == MessageBoxIcon::question) ? "OK" : "Close"; int b_width = static_cast(fl_width(text) + 20); Fl_Button *button = new Fl_Button(but_x - b_width, but_y, b_width, BUT_H, text); context.buttons[b] = button; button->align(FL_ALIGN_INSIDE | FL_ALIGN_CLIP); button->callback((Fl_Callback *) dialog_button_callback, &context); b_group->insert(*button, 0); but_x = but_x - b_width - 40; // left-most button should get the focus focus_button = button; } dialog->end(); // show time! if (focus_button) dialog->hotspot(focus_button); dialog->set_modal(); dialog->show(); if (icon_type == MessageBoxIcon::exclamation) fl_beep(); if (focus_button) Fl::focus(focus_button); // run the GUI and let user make their choice while (context.result < 0) { Fl::wait(); } // delete window (automatically deletes child widgets) delete dialog; return context.result; } static void ParseHyperLink(SString &message, SString &url, SString &linkTitle) { // the syntax for a hyperlink is similar to HTML :- // Title SString text = message; size_t pos = text.find("< a"); if(pos == SString::npos) return; // terminate the rest of the message here message = text; message.erase(pos, SString::npos); message.push_back('\n'); url = text; url.erase(0, pos + 3); pos = url.find('>'); if(pos == SString::npos) // malformed : oh well return; linkTitle = url; linkTitle.erase(0, pos + 1); // terminate the URL here url.erase(pos, SString::npos); pos = linkTitle.find('<'); if(pos != SString::npos) linkTitle.erase(pos, SString::npos); } //------------------------------------------------------------------------ void DLG_ShowError(bool fatal, EUR_FORMAT_STRING(const char *msg), ...) { va_list arg_pt; va_start (arg_pt, msg); SString dialog_buffer = SString::vprintf(msg, arg_pt); va_end (arg_pt); // handle error messages with a hyperlink at the end SString linkTitle; SString linkURL; ParseHyperLink(dialog_buffer, linkTitle, linkURL); gLog.printf("Error: %s\n", dialog_buffer.c_str()); DialogShowAndRun(MessageBoxIcon::exclamation, dialog_buffer, fatal ? "Eureka - Fatal Error" : "Eureka - Error", linkTitle, linkURL); } std::function DLG_Notify_Override; void DLG_Notify(EUR_FORMAT_STRING(const char *msg), ...) { va_list arg_pt; va_start (arg_pt, msg); if(DLG_Notify_Override) { DLG_Notify_Override(msg, arg_pt); va_end(arg_pt); return; } SString dialog_buffer = SString::vprintf(msg, arg_pt); va_end (arg_pt); DialogShowAndRun(MessageBoxIcon::information, dialog_buffer, "Eureka - Notification"); } std::function &buttons, const char *msg, va_list ap)> DLG_Confirm_Override; int DLG_Confirm(const std::vector& buttons, EUR_FORMAT_STRING(const char *msg), ...) { va_list arg_pt; va_start (arg_pt, msg); if(DLG_Confirm_Override) { int result = DLG_Confirm_Override(buttons, msg, arg_pt); va_end(arg_pt); return result; } SString dialog_buffer = SString::vprintf(msg, arg_pt); va_end (arg_pt); return DialogShowAndRun(MessageBoxIcon::question, dialog_buffer, "Eureka - Confirmation", NULL, NULL, &buttons); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_editor.cc000066400000000000000000000411371464327712600206300ustar00rootroot00000000000000//------------------------------------------------------------------------ // TEXT EDITOR WINDOW //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2018 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include "m_streams.h" #include "w_wad.h" #include "ui_window.h" class UI_TedStatusBar : public Fl_Group { private: Fl_Box *row_col; Fl_Box *mod_box; int cur_row; int cur_column; bool cur_modified; public: UI_TedStatusBar(int X, int Y, int W, int H, const char *label = NULL) : Fl_Group(X, Y, W, H, label), cur_row(1), cur_column(1), cur_modified(false) { box(FL_UP_BOX); row_col = new Fl_Box(FL_FLAT_BOX, X, Y+1, W*2/3, H-2, ""); row_col->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT); mod_box = new Fl_Box(FL_FLAT_BOX, X+W*2/3, Y+1, W/3, H-2, ""); mod_box->align(FL_ALIGN_INSIDE | FL_ALIGN_RIGHT); end(); Update(); } virtual ~UI_TedStatusBar() { } public: void SetPosition(int row, int column) { if (row != cur_row || column != cur_column) { cur_row = row; cur_column = column; Update(); } } void SetModified(bool modified) { if (modified != cur_modified) { cur_modified = modified; Update(); } } private: void Update() { static char buffer[256]; snprintf(buffer, sizeof(buffer), " Line: %-6d Col: %d", cur_row, cur_column); row_col->copy_label(buffer); if (cur_modified) mod_box->label("MODIFIED "); else mod_box->label(""); // ensure background gets redrawn redraw(); } }; //------------------------------------------------------------------------ // andrewj: this class only exists because a very useful method of // Fl_Text_Display is not public. FFS. class UI_TedWrapper : public Fl_Text_Editor { public: UI_TedWrapper(int X, int Y, int W, int H, const char *l=0) : Fl_Text_Editor(X, Y, W, H, l) { } virtual ~UI_TedWrapper() { } bool GetLineAndColumn(int *line, int *col) { if (position_to_linecol(insert_position(), line, col) == 0) return false; *col += 1; return true; } }; //------------------------------------------------------------------------ void UI_TextEditor::menu_do_save(Fl_Widget *w, void *data) { UI_TextEditor *win = (UI_TextEditor *)data; SYS_ASSERT(win); if (win->read_only) { if (DLG_Confirm({ "Cancel", "&Export" }, "The current wad is READ-ONLY. " "Do you want to export the text into a new file?") == 1) { menu_do_export(w, data); } return; } win->want_save = true; } void UI_TextEditor::menu_do_insert(Fl_Widget *w, void *data) { UI_TextEditor *win = (UI_TextEditor *)data; SYS_ASSERT(win); win->InsertFile(); } void UI_TextEditor::menu_do_export(Fl_Widget *w, void *data) { UI_TextEditor *win = (UI_TextEditor *)data; SYS_ASSERT(win); win->ExportToFile(); } void UI_TextEditor::menu_do_close(Fl_Widget *w, void *data) { UI_TextEditor *win = (UI_TextEditor *)data; SYS_ASSERT(win); // this asks for confirmation if changes have been made win->close_callback(win, win); } void UI_TextEditor::menu_do_undo(Fl_Widget *w, void *data) { UI_TextEditor *win = (UI_TextEditor *)data; SYS_ASSERT(win); Fl_Text_Editor::kf_undo(0, win->ted); } void UI_TextEditor::menu_do_cut(Fl_Widget *w, void *data) { UI_TextEditor *win = (UI_TextEditor *)data; SYS_ASSERT(win); Fl_Text_Editor::kf_cut(0, win->ted); } void UI_TextEditor::menu_do_copy(Fl_Widget *w, void *data) { UI_TextEditor *win = (UI_TextEditor *)data; SYS_ASSERT(win); Fl_Text_Editor::kf_copy(0, win->ted); } void UI_TextEditor::menu_do_paste(Fl_Widget *w, void *data) { UI_TextEditor *win = (UI_TextEditor *)data; SYS_ASSERT(win); Fl_Text_Editor::kf_paste(0, win->ted); } void UI_TextEditor::menu_do_delete(Fl_Widget *w, void *data) { UI_TextEditor *win = (UI_TextEditor *)data; SYS_ASSERT(win); win->tbuf->remove_selection(); } void UI_TextEditor::menu_do_select_all(Fl_Widget *w, void *data) { UI_TextEditor *win = (UI_TextEditor *)data; SYS_ASSERT(win); Fl_Text_Editor::kf_select_all(0, win->ted); } void UI_TextEditor::menu_do_unselect_all(Fl_Widget *w, void *data) { UI_TextEditor *win = (UI_TextEditor *)data; SYS_ASSERT(win); win->tbuf->unselect(); } void UI_TextEditor::menu_do_find(Fl_Widget *w, void *data) { UI_TextEditor *win = (UI_TextEditor *)data; SYS_ASSERT(win); if (! win->AskFindString()) return; win->FindNext(+2); } void UI_TextEditor::menu_do_find_next(Fl_Widget *w, void *data) { UI_TextEditor *win = (UI_TextEditor *)data; SYS_ASSERT(win); if (win->find_string.empty()) { if (! win->AskFindString()) return; } win->FindNext(+1); } void UI_TextEditor::menu_do_find_prev(Fl_Widget *w, void *data) { UI_TextEditor *win = (UI_TextEditor *)data; SYS_ASSERT(win); if (win->find_string.empty()) { if (! win->AskFindString()) return; } win->FindNext(-1); } void UI_TextEditor::menu_do_goto_top(Fl_Widget *w, void *data) { UI_TextEditor *win = (UI_TextEditor *)data; SYS_ASSERT(win); win->tbuf->unselect(); win->ted->insert_position(0); win->ted->show_insert_position(); } void UI_TextEditor::menu_do_goto_bottom(Fl_Widget *w, void *data) { UI_TextEditor *win = (UI_TextEditor *)data; SYS_ASSERT(win); win->tbuf->unselect(); int len = win->tbuf->length(); win->ted->insert_position(len); win->ted->show_insert_position(); } #undef FCAL #define FCAL (Fl_Callback *) static const Fl_Menu_Item ted_menu_items[] = { { "&File", 0, 0, 0, FL_SUBMENU }, { "&Insert File...", FL_COMMAND + 'i', FCAL UI_TextEditor::menu_do_insert }, { "&Export to File... ", FL_COMMAND + 'e', FCAL UI_TextEditor::menu_do_export }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Save Lump", FL_COMMAND + 's', FCAL UI_TextEditor::menu_do_save }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Close", FL_COMMAND + 'q', FCAL UI_TextEditor::menu_do_close }, { 0 }, { "&Edit", 0, 0, 0, FL_SUBMENU }, { "&Undo", FL_COMMAND + 'z', FCAL UI_TextEditor::menu_do_undo }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "Cu&t", FL_COMMAND + 'x', FCAL UI_TextEditor::menu_do_cut }, { "&Copy", FL_COMMAND + 'c', FCAL UI_TextEditor::menu_do_copy }, { "&Paste", FL_COMMAND + 'v', FCAL UI_TextEditor::menu_do_paste }, { "&Delete", 0, FCAL UI_TextEditor::menu_do_delete }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "Select &All", FL_COMMAND + 'a', FCAL UI_TextEditor::menu_do_select_all }, { "Unselect All ", FL_COMMAND + 'u', FCAL UI_TextEditor::menu_do_unselect_all }, { 0 }, { "&Search", 0, 0, 0, FL_SUBMENU }, { "&Find", FL_COMMAND + 'f', FCAL UI_TextEditor::menu_do_find }, { "Find &Next", FL_COMMAND + 'g', FCAL UI_TextEditor::menu_do_find_next }, { "Find &Prev", FL_COMMAND + 'p', FCAL UI_TextEditor::menu_do_find_prev }, // { "&Replace", FL_COMMAND + 'r', FCAL menu_PLACEHOLDER }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "Go to &Top", FL_COMMAND + 't', FCAL UI_TextEditor::menu_do_goto_top }, { "Go to &Bottom ", FL_COMMAND + 'b', FCAL UI_TextEditor::menu_do_goto_bottom }, { 0 }, #if 0 { "&View", 0, 0, 0, FL_SUBMENU }, // Todo: flesh these out [ will need config-file vars too ] { "Colors", 0, FCAL menu_PLACEHOLDER }, { "Font", 0, FCAL menu_PLACEHOLDER }, { "Line Numbers", 0, FCAL menu_PLACEHOLDER }, { 0 }, #endif { 0 } }; //------------------------------------------------------------------------ UI_TextEditor::UI_TextEditor(const Instance &inst) : Fl_Double_Window(600, 400, ""), want_close(false), want_save(false), is_new(true), read_only(false), has_changes(false), inst(inst) { size_range(520, 200); callback((Fl_Callback *) close_callback, this); color(WINDOW_BG, WINDOW_BG); int MW = w() / 2; menu_bar = new Fl_Menu_Bar(0, 0, MW, 28); menu_bar->copy(ted_menu_items, this /* userdata for every menu item */); status = new UI_TedStatusBar(MW, 0, w() - MW, 28); ted = new UI_TedWrapper(0, 28, w(), h() - 28); ted->color(FL_BLACK, FL_BLUE); ted->textfont(FL_COURIER); ted->textsize(18); ted->textcolor(fl_rgb_color(192,192,192)); ted->cursor_color(FL_RED); ted->cursor_style(Fl_Text_Display::HEAVY_CURSOR); tbuf = new Fl_Text_Buffer(); tbuf->add_modify_callback(text_modified_callback, this); ted->buffer(tbuf); resizable(ted); end(); } UI_TextEditor::~UI_TextEditor() { ted->buffer(NULL); delete tbuf; tbuf = NULL; } int UI_TextEditor::Run() { // it is safe to call these a second/third/etc time. set_modal(); show(); // reset this here, as LoadLump() sets it to true, and we // want to reset it after a RUN_Save as well. has_changes = false; for (;;) { if (want_save) { want_save = false; return RUN_Save; } if (want_close) return RUN_Quit; Fl::wait(0.2); UpdateStatus(); } /* NOT REACHED */ return RUN_Error; } void UI_TextEditor::close_callback(Fl_Widget *w, void *data) { UI_TextEditor * win = (UI_TextEditor *)data; if (win->has_changes) { if (DLG_Confirm({ "Cancel", "&Discard" }, "You have unsaved changes to this lump. " "Are you sure you want to discard them?") <= 0) { return; } } win->want_close = true; } void UI_TextEditor::text_modified_callback(int, int nInserted, int nDeleted, int, const char*, void *data) { UI_TextEditor * win = (UI_TextEditor *)data; if (nInserted + nDeleted > 0) win->has_changes = true; } bool UI_TextEditor::LoadLump(const Wad_file *wad, const SString &lump_name) { if(!wad) { DLG_Notify("Cannot load lump; no WAD has been loaded."); return false; } const Lump_c * lump = wad->FindLump(lump_name); // if the lump does not exist, we will create it if (! lump) { if (read_only) { DLG_Notify("The %s lump does not exist, and it cannot be " "created since the current wad is READ-ONLY.", lump_name.c_str()); return false; } return true; } gLog.printf("Reading '%s' text lump\n", lump_name.c_str()); LumpInputStream stream(*lump); SString line; while (stream.readLine(line)) { line.trimTrailingSpaces(); tbuf->append(line.c_str()); tbuf->append("\n"); } is_new = false; return true; } void UI_TextEditor::LoadMemory(const std::vector &buf) { // this code is slow, but simple char charbuf[2]; charbuf[1] = 0; unsigned int len = static_cast(buf.size()); for (unsigned int k = 0 ; k < len ; k++) { // ignore NULs and CRs if (buf[k] == 0 || buf[k] == '\r') continue; charbuf[0] = buf[k]; tbuf->append(charbuf); } is_new = false; } void UI_TextEditor::SaveLump(Wad_file *wad, const SString &lump_name) { if(!wad) { return; } gLog.printf("Writing '%s' text lump\n", lump_name.c_str()); int oldie = wad->FindLumpNum(lump_name); if (oldie >= 0) wad->RemoveLumps(oldie, 1); Lump_c &lump = wad->AddLump(lump_name); int len = tbuf->length(); for (int i = 0 ; i < len ; i++) { // this is not optimal (one byte at a time), but is adequate byte ch = tbuf->byte_at(i); // ignore NULs and CRs if (ch == 0 || ch == '\r') continue; lump.Write(&ch, 1); } try { wad->writeToDisk(); } catch(const std::runtime_error &e) { DLG_ShowError(false, "Failed saving lump %s: %s", lump_name.c_str(), e.what()); } } void UI_TextEditor::SaveMemory(std::vector &buf) { buf.clear(); int len = tbuf->length(); for (int i = 0 ; i < len ; i++) { byte ch = tbuf->byte_at(i); // ignore NULs and CRs if (ch == 0 || ch == '\r') continue; buf.push_back(ch); } } void UI_TextEditor::SetTitle(const SString &lump_name) { static char title_buf[256]; const char *suffix = ""; if (is_new) suffix = " [NEW]"; else if (read_only) suffix = " [Read-Only]"; snprintf(title_buf, sizeof(title_buf), "Editing '%s' lump%s", lump_name.c_str(), suffix); copy_label(title_buf); } void UI_TextEditor::UpdateStatus() { int row, column; if (ted->GetLineAndColumn(&row, &column)) status->SetPosition(row, column); status->SetModified(has_changes); } void UI_TextEditor::InsertFile() { Fl_Native_File_Chooser chooser; chooser.title("Pick file to insert"); chooser.type(Fl_Native_File_Chooser::BROWSE_FILE); chooser.directory(inst.Main_FileOpFolder().u8string().c_str()); switch (chooser.show()) { case -1: DLG_Notify("Unable to open the file:\n\n%s", chooser.errmsg()); return; case 1: // cancelled return; default: // Ok break; } // if a selection is active, delete that text tbuf->remove_selection(); SString line; fs::path filename = fs::u8path(chooser.filename()); // TODO: for WIN32, ideally examine the file and determine // whether the charset is UTF-8 or CP-1252, based on // quantity of invalid UTF-8 sequences. // open file in binary mode (we handle CR/LF ourselves) LineFile file(filename); if (!file.isOpen()) { line = GetErrorMessage(errno); DLG_Notify("Unable to open text file:\n\n%s", line.c_str()); return; } gLog.printf("Reading text from file: %s\n", filename.u8string().c_str()); int pos = ted->insert_position(); while (file.readLine(line)) { tbuf->insert(pos, line.c_str()); pos += static_cast(line.length()); tbuf->insert(pos, "\n"); pos += 1; } } void UI_TextEditor::ExportToFile() { Fl_Native_File_Chooser chooser; chooser.title("Pick file to export to"); chooser.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); chooser.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM); chooser.directory(inst.Main_FileOpFolder().u8string().c_str()); switch (chooser.show()) { case -1: DLG_Notify("Unable to export the file:\n\n%s", chooser.errmsg()); return; case 1: // cancelled return; default: // Ok break; } const char *filename = chooser.filename(); // open file in binary mode (we handle CR/LF ourselves) FILE * fp = fopen(filename, "wb"); if (fp == NULL) { DLG_Notify("Unable to create output file:\n\n%s", GetErrorMessage(errno).c_str()); return; } gLog.printf("Writing text to file: %s\n", filename); int len = tbuf->length(); for (int p = 0 ; p < len ; p++) { byte ch = (byte) tbuf->byte_at(p); // skip raw CR characters if (ch == '\r') continue; #ifdef WIN32 // under Windows, convert LF --> CR/LF if (ch == '\n') { fputc('\r', fp); } #endif if (fputc(ch, fp) == EOF) { DLG_Notify("A write error occurred:\n\n%s", GetErrorMessage(errno).c_str()); fclose(fp); return; } } fclose(fp); has_changes = false; } // returns false if the user cancelled bool UI_TextEditor::AskFindString() { // we don't pre-seed with the last search string, because FLTK does // not select the text and it is a pain to delete it first. const char *str = fl_input("Find what:", find_string.c_str()); if (str == NULL || str[0] == 0) return false; SetFindString(str); return true; } void UI_TextEditor::SetFindString(const char *str) { if (str) find_string = str; else find_string.clear(); } bool UI_TextEditor::FindNext(int dir) { SYS_ASSERT(!find_string.empty()); int pos = ted->insert_position(); // int len = tbuf->length(); int new_pos; int found; if (dir >= 2 && !tbuf->selected()) // a normal "Find" can match at exactly the starting spot found = tbuf->search_forward(pos, find_string.c_str(), &new_pos); else if (dir > 0) found = tbuf->search_forward(pos+1, find_string.c_str(), &new_pos); else found = tbuf->search_backward(pos-1, find_string.c_str(), &new_pos); if (! found && dir > 0 && pos > 0) { fl_beep(); if (DLG_Confirm({ "Cancel", "&Search" }, "No more results.\n\n" "Search again from the top?") <= 0) { return false; } pos = 0; found = tbuf->search_forward(pos, find_string.c_str(), &new_pos); } if (! found) { fl_beep(); DLG_Notify("No %sresults.", (dir > 0 && pos == 0) ? "" : "more "); return false; } // found it, so select the text int end_pos = static_cast(new_pos + find_string.length()); tbuf->select(new_pos, end_pos); ted->insert_position(new_pos); ted->show_insert_position(); return true; } bool UI_TextEditor::ContainsUnicode() const { int len = tbuf->length(); for (int i = 0 ; i < len ; i++) if ((byte)tbuf->byte_at(i) & 0x80) return true; return false; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_editor.h000066400000000000000000000064731464327712600204760ustar00rootroot00000000000000//------------------------------------------------------------------------ // TEXT EDITOR WINDOW //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2018 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_EDITOR_H__ #define __EUREKA_UI_EDITOR_H__ #include "FL/Fl_Double_Window.H" class Fl_Menu_Bar; class Fl_Text_Buffer; class Wad_file; class UI_TedStatusBar; class UI_TedWrapper; class UI_TextEditor : public Fl_Double_Window { private: bool want_close; bool want_save; bool is_new; bool read_only; bool has_changes; private: Fl_Menu_Bar *menu_bar; UI_TedStatusBar *status; UI_TedWrapper *ted; Fl_Text_Buffer *tbuf; // use SetFindString() to set this SString find_string; const Instance& inst; public: UI_TextEditor(const Instance &inst); virtual ~UI_TextEditor(); void SetReadOnly() { read_only = true; } void SetTitle(const SString &lump_name); bool LoadLump(const Wad_file *wad, const SString &lump_name); void SaveLump(Wad_file *wad, const SString &lump_name); void LoadMemory(const std::vector &buf); void SaveMemory(std::vector &buf); enum { RUN_Quit = 0, RUN_Save = 1, RUN_Error = 2 }; // returns a RUN_XXX value. // when RUN_Save is returned, Run() should be re-entered. int Run(); void InsertFile(); void ExportToFile(); private: bool AskFindString(); void SetFindString(const char *str); // dir should be +1 for forward, -1 for backward bool FindNext(int dir); void UpdateStatus(); bool ContainsUnicode() const; static void close_callback(Fl_Widget *, void *); static void button_callback(Fl_Widget *, void *); static void text_modified_callback(int, int nInserted, int nDeleted, int, const char*, void *); public: // File menu static void menu_do_save(Fl_Widget *w, void *data); static void menu_do_insert(Fl_Widget *w, void *data); static void menu_do_export(Fl_Widget *w, void *data); static void menu_do_close(Fl_Widget *w, void *data); // Edit menu static void menu_do_undo(Fl_Widget *w, void *data); static void menu_do_cut(Fl_Widget *w, void *data); static void menu_do_copy(Fl_Widget *w, void *data); static void menu_do_paste(Fl_Widget *w, void *data); static void menu_do_delete(Fl_Widget *w, void *data); static void menu_do_select_all(Fl_Widget *w, void *data); static void menu_do_unselect_all(Fl_Widget *w, void *data); // Search menu static void menu_do_find(Fl_Widget *w, void *data); static void menu_do_find_next(Fl_Widget *w, void *data); static void menu_do_find_prev(Fl_Widget *w, void *data); static void menu_do_goto_top(Fl_Widget *w, void *data); static void menu_do_goto_bottom(Fl_Widget *w, void *data); }; #endif /* __EUREKA_UI_EDITOR_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_file.cc000066400000000000000000000634151464327712600202640ustar00rootroot00000000000000//------------------------------------------------------------------------ // FILE-RELATED DIALOGS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2019 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include "m_config.h" #include "m_files.h" #include "m_game.h" #include "w_wad.h" #include "ui_window.h" #include "ui_file.h" #include #define FREE_COL fl_rgb_color(0x33, 0xFF, 0xAA) #define USED_COL (config::gui_scheme == 2 ? fl_rgb_color(0xFF, 0x11, 0x11) : fl_rgb_color(0xFF, 0x88, 0x88)) // TODO: find a better home for this bool ValidateMapName(const char *p) { size_t len = strlen(p); if (len == 0 || len > 8) return false; if (! isalpha(*p)) return false; for ( ; *p ; p++) if (! (isalnum(*p) || *p == '_')) return false; return true; } UI_ChooseMap::UI_ChooseMap(const char *initial_name, const std::shared_ptr &_rename_wad) : UI_Escapable_Window(420, 385, "Choose Map"), rename_wad(_rename_wad) { resizable(NULL); callback(close_callback, this); { map_name = new Fl_Input(120, 35, 120, 25, "Map slot: "); map_name->labelfont(FL_HELVETICA_BOLD); } map_name->when(FL_WHEN_CHANGED); map_name->callback(input_callback, this); map_name->value(initial_name); FLFocusOnCreation(map_name); map_buttons = new Fl_Group(x(), y() + 60, w(), y() + 320); map_buttons->end(); { int bottom_y = 320; Fl_Group* o = new Fl_Group(0, bottom_y, 420, 65); o->box(FL_FLAT_BOX); o->color(WINDOW_BG, WINDOW_BG); ok_but = new Fl_Return_Button(260, bottom_y + 17, 100, 35, "OK"); ok_but->labelfont(FL_HELVETICA_BOLD); ok_but->callback(ok_callback, this); Fl_Button *cancel = new Fl_Button(75, bottom_y + 17, 100, 35, "Cancel"); cancel->callback(close_callback, this); o->end(); } end(); CheckMapName(); } void UI_ChooseMap::PopulateButtons(char format, const Wad_file *test_wad) { int but_W = 60; for (int col = 0 ; col < 5 ; col++) for (int row = 0 ; row < 8 ; row++) { int cx = x() + 30 + col * (but_W + but_W / 5); int cy = y() + 80 + row * 24 + (row / 2) * 10; char name_buf[20]; if (format == 'E') { int epi = 1 + row / 2; int map = 1 + col + (row & 1) * 5; if (map > 9) continue; snprintf(name_buf, sizeof(name_buf), "E%dM%d", epi, map); } else { int map = 1 + col + row * 5; // this logic matches UI_OpenMap on the IWAD if (row >= 2) map--; else if (row == 1 && col == 4) continue; if (map < 1 || map > 32) continue; snprintf(name_buf, sizeof(name_buf), "MAP%02d", map); } Fl_Button * but = new Fl_Button(cx, cy, 60, 20); but->copy_label(name_buf); but->callback(button_callback, this); if (test_wad && test_wad->LevelFind(name_buf) >= 0) { if (rename_wad) but->deactivate(); else but->color(USED_COL); } else but->color(FREE_COL); map_buttons->add(but); } } SString UI_ChooseMap::Run() { set_modal(); show(); while (action == ACT_none) { Fl::wait(0.2); } if (action == ACT_CANCEL) return ""; return SString(map_name->value()).asUpper(); } void UI_ChooseMap::close_callback(Fl_Widget *w, void *data) { UI_ChooseMap * that = (UI_ChooseMap *)data; that->action = ACT_CANCEL; } void UI_ChooseMap::ok_callback(Fl_Widget *w, void *data) { UI_ChooseMap * that = (UI_ChooseMap *)data; // sanity check if (ValidateMapName(that->map_name->value())) that->action = ACT_ACCEPT; else fl_beep(); } void UI_ChooseMap::button_callback(Fl_Widget *w, void *data) { UI_ChooseMap * that = (UI_ChooseMap *)data; that->map_name->value(w->label()); that->action = ACT_ACCEPT; } void UI_ChooseMap::input_callback(Fl_Widget *w, void *data) { UI_ChooseMap * that = (UI_ChooseMap *)data; that->CheckMapName(); } void UI_ChooseMap::CheckMapName() { bool was_valid = ok_but->active(); bool is_valid = ValidateMapName(map_name->value()); if (rename_wad && is_valid) { if (rename_wad->LevelFind(map_name->value()) >= 0) is_valid = false; } if (was_valid == is_valid) return; if (is_valid) { ok_but->activate(); map_name->textcolor(FL_FOREGROUND_COLOR); } else { ok_but->deactivate(); map_name->textcolor(FL_RED); } map_name->redraw(); } //------------------------------------------------------------------------ UI_OpenMap::UI_OpenMap(Instance &inst) : UI_Escapable_Window(420, 475, "Open Map"), inst(inst) { resizable(NULL); callback(close_callback, this); { look_where = new Fl_Choice(130, 80, 190, 25, "Find map in: "); look_where->labelfont(FL_HELVETICA_BOLD); look_where->add("the PWAD above|the Game IWAD|the Resource wads"); look_where->callback(look_callback, this); look_where->value(inst.wad.master.editWad() ? LOOK_PWad : LOOK_IWad); } { Fl_Box* o = new Fl_Box(15, 15, 270, 20, "PWAD file:"); o->labelfont(FL_HELVETICA_BOLD); o->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); } pwad_name = new Fl_Output(20, 40, 295, 26); Fl_Button *load_but = new Fl_Button(330, 39, 65, 28, "Load"); load_but->callback(load_callback, this); map_name = new Fl_Input(99, 125, 100, 26, "Map slot: "); map_name->labelfont(FL_HELVETICA_BOLD); map_name->when(FL_WHEN_CHANGED); map_name->callback(input_callback, this); { Fl_Box *o = new Fl_Box(230, 125, 180, 26, "Available maps:"); // o->labelfont(FL_HELVETICA_BOLD); o->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); } // all the map buttons go into this group button_grp = new UI_Scroll(5, 165, w()-10, 230, +1 /* bar_side */); button_grp->align(FL_ALIGN_TOP | FL_ALIGN_INSIDE); button_grp->resize_horiz(false); button_grp->Line_size(24); button_grp->box(FL_FLAT_BOX); /* bottom buttons */ { int bottom_y = h() - 70; Fl_Group* o = new Fl_Group(0, bottom_y, w(), 70); o->box(FL_FLAT_BOX); o->color(WINDOW_BG, WINDOW_BG); ok_but = new Fl_Return_Button(260, bottom_y + 20, 100, 34, "OK"); ok_but->labelfont(FL_HELVETICA_BOLD); ok_but->callback(ok_callback, this); Fl_Button * cancel = new Fl_Button(75, bottom_y + 20, 100, 35, "Cancel"); cancel->callback(close_callback, this); o->end(); } end(); CheckMapName(); } UI_OpenMap::~UI_OpenMap() { } std::shared_ptr UI_OpenMap::Run(SString* map_v, bool * did_load) { map_v->clear(); *did_load = false; if (inst.wad.master.editWad()) SetPWAD(inst.wad.master.editWad()->PathName().u8string()); Populate(); set_modal(); show(); while (action == Action::none) { Fl::wait(0.2); } if (action != Action::accept) using_wad.reset(); if (using_wad) { *map_v = SString(map_name->value()).asUpper(); if (using_wad == loaded_wad) { *did_load = true; loaded_wad.reset(); } } // if we are not returning a pwad which got loaded, e.g. because // the user cancelled or chose the game IWAD, then close it now. loaded_wad.reset(); return using_wad; } void UI_OpenMap::CheckMapName() { bool was_valid = ok_but->active(); bool is_valid = using_wad && ValidateMapName(map_name->value()) && (using_wad->LevelFind(map_name->value()) >= 0); if (was_valid == is_valid) return; if (is_valid) { ok_but->activate(); map_name->textcolor(FL_FOREGROUND_COLOR); } else { ok_but->deactivate(); map_name->textcolor(FL_RED); } map_name->redraw(); } void UI_OpenMap::Populate() { button_grp->label("\n\n\n\n\nNO MAPS FOUND"); button_grp->Remove_all(); using_wad.reset(); if (look_where->value() == LOOK_IWad) { using_wad = inst.wad.master.gameWad(); PopulateButtons(); } else if (look_where->value() >= LOOK_Resource) { // we simply use the last resource which contains levels // TODO: probably should collect ones with a map, add to look_where choices for (auto it = inst.wad.master.resourceWads().rbegin(); it != inst.wad.master.resourceWads().rend(); ++it) { if ((*it)->LevelCount() >= 0) { using_wad = *it; PopulateButtons(); break; } } } else if (loaded_wad) { using_wad = loaded_wad; PopulateButtons(); } else if (inst.wad.master.editWad()) { using_wad = inst.wad.master.editWad(); PopulateButtons(); } button_grp->Init_sizes(); button_grp->redraw(); } static bool DifferentEpisode(const char *A, const char *B) { if (A[0] != B[0]) return true; // handle ExMx if (toupper(A[0]) == 'E') { return A[1] != B[1]; } // handle MAPxx if (strlen(A) < 4 && strlen(B) < 4) return false; return A[3] != B[3]; } void UI_OpenMap::PopulateButtons() { std::shared_ptr wad = using_wad; SYS_ASSERT(wad); int num_levels = wad->LevelCount(); if (num_levels == 0) return; button_grp->label(""); std::set level_names; for (int lev = 0 ; lev < num_levels ; lev++) { Lump_c *lump = wad->GetLump(wad->LevelHeader(lev)); level_names.insert(lump->Name()); } int cx_base = button_grp->x() + 25; int cy_base = button_grp->y() + 5; int but_W = 60; // create them buttons!! int row = 0; int col = 0; SString last_name; for (const SString &name : level_names) { if (col > 0 && !last_name.empty() && DifferentEpisode(last_name.c_str(), name.c_str())) { col = 0; row++; } int cx = cx_base + col * (but_W + but_W / 5); int cy = cy_base + row * 24 + (row / 2) * 8; Fl_Button * but = new Fl_Button(cx, cy, but_W, 20); but->copy_label(name.c_str()); but->color(FREE_COL); but->callback(button_callback, this); button_grp->Add(but); col++; if (col >= 5) { col = 0; row++; } last_name = name; } redraw(); } void UI_OpenMap::SetPWAD(const SString &name) { pwad_name->value(fl_filename_name(name.c_str())); } void UI_OpenMap::close_callback(Fl_Widget *w, void *data) { UI_OpenMap * that = (UI_OpenMap *)data; that->action = Action::cancel; } void UI_OpenMap::ok_callback(Fl_Widget *w, void *data) { UI_OpenMap * that = (UI_OpenMap *)data; // sanity check if (that->using_wad && ValidateMapName(that->map_name->value())) that->action = Action::accept; else fl_beep(); } void UI_OpenMap::button_callback(Fl_Widget *w, void *data) { auto that = (UI_OpenMap *)data; // sanity check if (! that->using_wad) return; that->map_name->value(w->label()); that->action = Action::accept; } void UI_OpenMap::input_callback(Fl_Widget *w, void *data) { UI_OpenMap * that = (UI_OpenMap *)data; that->CheckMapName(); } void UI_OpenMap::look_callback(Fl_Widget *w, void *data) { UI_OpenMap * that = (UI_OpenMap *)data; that->Populate(); that->CheckMapName(); } void UI_OpenMap::load_callback(Fl_Widget *w, void *data) { UI_OpenMap * that = (UI_OpenMap *)data; that->LoadFile(); that->CheckMapName(); } void UI_OpenMap::LoadFile() { Fl_Native_File_Chooser chooser; chooser.title("Pick file to open"); chooser.type(Fl_Native_File_Chooser::BROWSE_FILE); chooser.filter("Wads\t*.wad"); chooser.directory(inst.Main_FileOpFolder().u8string().c_str()); // Show native chooser switch (chooser.show()) { case -1: gLog.printf("Open Map: error choosing file:\n"); gLog.printf(" %s\n", chooser.errmsg()); DLG_Notify("Unable to open the map:\n\n%s", chooser.errmsg()); return; case 1: gLog.printf("Open Map: cancelled by user\n"); return; default: break; // OK } std::shared_ptr wad = Wad_file::Open(fs::u8path(chooser.filename()), WadOpenMode::append); if (! wad) { // FIXME: get an error message, add it here DLG_Notify("Unable to open the chosen WAD file.\n\n" "Please try again."); return; } if (wad->LevelCount() < 0) { DLG_Notify("The chosen WAD contains no levels.\n\n" "Please try again."); return; } // replace existing one loaded_wad = wad; SetPWAD(loaded_wad->PathName().u8string()); if (using_wad == loaded_wad) using_wad = wad; // change the "Find map in ..." setting look_where->value(LOOK_PWad); Populate(); } //------------------------------------------------------------------------ #define STARTUP_MSG "No IWADs could be found." UI_ProjectSetup::UI_ProjectSetup(Instance &inst, bool new_project, bool is_startup) : UI_Escapable_Window(is_startup ? 400 : 500, is_startup ? 200 : 440, new_project ? "New Project" : "Manage Project"), inst(inst) { callback(close_callback, this); resizable(NULL); int by = 0; if (is_startup) { Fl_Box * message = new Fl_Box(FL_FLAT_BOX, 15, 15, 370, 46, STARTUP_MSG); message->align(FL_ALIGN_INSIDE); message->color(FL_RED, FL_RED); message->labelcolor(FL_YELLOW); message->labelsize(18); by += 60; } game_choice = new Fl_Choice(140, by+25, 150, 29, "Game IWAD: "); game_choice->labelfont(FL_HELVETICA_BOLD); game_choice->down_box(FL_BORDER_BOX); game_choice->callback((Fl_Callback*)game_callback, this); { Fl_Button* o = new Fl_Button(305, by+27, 75, 25, "Find"); o->callback((Fl_Callback*)find_callback, this); } port_choice = new Fl_Choice(140, by+62, 150, 29, "Source Port: "); port_choice->labelfont(FL_HELVETICA_BOLD); port_choice->down_box(FL_BORDER_BOX); port_choice->callback((Fl_Callback*)port_callback, this); { Fl_Button* o = new Fl_Button(305, by+64, 75, 25, "Setup"); o->callback((Fl_Callback*)setup_callback, this); if (is_startup) o->hide(); } format_choice = new Fl_Choice(140, by+99, 150, 29, "Map Type: "); format_choice->labelfont(FL_HELVETICA_BOLD); format_choice->down_box(FL_BORDER_BOX); format_choice->callback((Fl_Callback*)format_callback, this); #if 0 // Disabled for now namespace_choice = new Fl_Choice(140, by+140, 150, 29, "Namespace: "); namespace_choice->labelfont(FL_HELVETICA_BOLD); namespace_choice->down_box(FL_BORDER_BOX); namespace_choice->callback((Fl_Callback*)namespace_callback, this); namespace_choice->hide(); #endif if (is_startup) { port_choice->hide(); format_choice->hide(); } // Resource section if (! is_startup) { Fl_Box *res_title = new Fl_Box(15, by+190, 185, 30, "Resource Files or Folders:"); res_title->labelfont(FL_HELVETICA_BOLD); res_title->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); } for (int r = 0 ; r < RES_NUM ; r++) { result.resources[r].clear(); if (is_startup) continue; int cy = by + 220 + r * 35; char res_label[64]; snprintf(res_label, sizeof(res_label), "%d. ", 1 + r); res_name[r] = new Fl_Output(55, cy, 205, 25); res_name[r]->copy_label(res_label); Fl_Button *kill = new Fl_Button(270, cy, 30, 25, "x"); mClearButtons[r] = kill; kill->labelsize(20); kill->callback((Fl_Callback*)kill_callback, this); // NOTE: on Apple, when selecting a folder picker, we can already pick files too, so unify the buttons #ifdef __APPLE__ Fl_Button *load = new Fl_Button(315, cy, 75 + 10 + 90, 25, "Load File or Folder"); mResourceFileButtons[r] = load; load->callback((Fl_Callback*)load_callback, this); #else Fl_Button *load = new Fl_Button(315, cy, 75, 25, "Load File"); mResourceFileButtons[r] = load; load->callback((Fl_Callback*)load_callback, this); load = new Fl_Button(load->x() + load->w() + 10, cy, 90, 25, "Load Folder"); mResourceDirButtons[r] = load; load->callback((Fl_Callback*)load_callback, this); #endif } // bottom buttons { by += is_startup ? 80 : 375; Fl_Group *g = new Fl_Group(0, by, w(), h() - by); g->box(FL_FLAT_BOX); g->color(WINDOW_BG, WINDOW_BG); const char *cancel_text = is_startup ? "Quit" : "Cancel"; cancel = new Fl_Button(90, g->y() + 14, 80, 35, cancel_text); cancel->callback((Fl_Callback*)close_callback, this); const char *ok_text = (is_startup | new_project) ? "OK" : "Use"; ok_but = new Fl_Button(w() - 160, g->y() + 14, 80, 35, ok_text); ok_but->labelfont(FL_HELVETICA_BOLD); ok_but->callback((Fl_Callback*)use_callback, this); g->end(); } end(); } tl::optional UI_ProjectSetup::Run() { PopulateIWADs(); PopulatePort(); PopulateMapFormat(); PopulateResources(); set_modal(); show(); while (action == Action::none) { Fl::wait(0.2); } return (action == Action::accept) ? result : tl::optional{}; } void UI_ProjectSetup::PopulateIWADs() { // This is called (a) when dialog is first opened, or (b) when // the user has found a new iwad. For the latter case, we want // to show the newly found game. SString prev_game = result.game; if (prev_game.empty()) prev_game = inst.loaded.gameName; if (prev_game.empty()) prev_game = "doom2"; result.game.clear(); game_choice->clear(); SString menu_string; int menu_value = 0; menu_string = global::recent.collectGamesForMenu(&menu_value, prev_game.c_str()); if (!menu_string.empty()) { game_choice->add(menu_string.c_str()); game_choice->value(menu_value); result.game = game_choice->mvalue()->text; } if (!result.game.empty()) ok_but->activate(); else ok_but->deactivate(); } void UI_ProjectSetup::PopulatePort() { SString prev_port; if (port_choice->mvalue()) prev_port = port_choice->mvalue()->text; if (prev_port.empty()) prev_port = inst.loaded.portName; if (prev_port.empty()) prev_port = "vanilla"; result.port = "vanilla"; port_choice->clear(); // if no game, port doesn't matter if (result.game.empty()) return; SString base_game; if (game_choice->mvalue()) base_game = M_GetBaseGame(game_choice->mvalue()->text); else if (!inst.loaded.gameName.empty()) base_game = M_GetBaseGame(inst.loaded.gameName); if (base_game.empty()) base_game = "doom2"; int menu_value = 0; SString menu_string = M_CollectPortsForMenu(base_game.c_str(), &menu_value, prev_port.c_str()); if (!menu_string.empty()) { port_choice->add (menu_string.c_str()); port_choice->value(menu_value); result.port = port_choice->mvalue()->text; } } void UI_ProjectSetup::PopulateMapFormat() { MapFormat prev_fmt = result.mapFormat; if (prev_fmt == MapFormat::invalid) prev_fmt = inst.loaded.levelFormat; format_choice->clear(); // if no game, format doesn't matter if (result.game.empty()) { result.mapFormat = MapFormat::doom; result.nameSpace = ""; return; } // determine the usable formats, from current game and port const char *c_game = "doom2"; const char *c_port = "vanilla"; if (game_choice->mvalue()) c_game = game_choice->mvalue()->text; if (port_choice->mvalue()) c_port = port_choice->mvalue()->text; usable_formats = M_DetermineMapFormats(c_game, c_port); SYS_ASSERT(usable_formats != 0); // reconstruct the menu int menu_value = 0; int entry_id = 0; if (usable_formats & (1 << static_cast(MapFormat::doom))) { format_choice->add("Doom Format"); entry_id++; } if (usable_formats & (1 << static_cast(MapFormat::hexen))) { if (prev_fmt == MapFormat::hexen) menu_value = entry_id; format_choice->add("Hexen Format"); entry_id++; } if (global::udmf_testing && (usable_formats & (1 << static_cast(MapFormat::udmf)))) { if (prev_fmt == MapFormat::udmf) menu_value = entry_id; format_choice->add("UDMF"); entry_id++; } format_choice->value(menu_value); // set map_format field based on current menu entry. format_callback(format_choice, (void *)this); // determine the UDMF namespace result.nameSpace = ""; const PortInfo_c *pinfo = M_LoadPortInfo(port_choice->mvalue()->text); if (pinfo) result.nameSpace = pinfo->udmf_namespace; // don't leave namespace as "" when chosen format is UDMF. // [ this is to handle broken config files somewhat sanely ] if (result.nameSpace.empty() && result.mapFormat == MapFormat::udmf) result.nameSpace = "Hexen"; } void UI_ProjectSetup::PopulateNamespaces() { #if 0 // Disabled for now if (map_format != MAPF_UDMF) { namespace_choice->hide(); return; } namespace_choice->show(); // get previous value const char *prev_ns = name_space.c_str(); if (prev_ns[0] == 0) prev_ns = Udmf_namespace.c_str(); namespace_choice->clear(); if (! port_choice->mvalue()) return; PortInfo_c *pinfo = M_LoadPortInfo(port_choice->mvalue()->text); if (! pinfo) return; int menu_value = 0; for (int i = 0 ; i < (int)pinfo->namespaces.size() ; i++) { const char * ns = pinfo->namespaces[i].c_str(); namespace_choice->add(ns); // keep same entry as before, when possible if (strcmp(prev_ns, ns) == 0) menu_value = i; } namespace_choice->value(menu_value); if (menu_value < (int)pinfo->namespaces.size()) name_space = pinfo->namespaces[menu_value]; #endif } inline static fs::path fileOrDirName(const fs::path &path) { return path.has_filename() ? path.filename() : path.parent_path().filename(); } void UI_ProjectSetup::PopulateResources() { // Note: these resource wads may be invalid (not exist) during startup. // This is probably NOT the place to validate them... for (int r = 0 ; r < RES_NUM ; r++) { // the resource widgets are not created for the missing-iwad dialog if (! res_name[r]) continue; if (r < (int)inst.loaded.resourceList.size()) { result.resources[r] = inst.loaded.resourceList[r]; res_name[r]->value(fileOrDirName(result.resources[r]).u8string().c_str()); } } } void UI_ProjectSetup::close_callback(Fl_Widget *w, void *data) { UI_ProjectSetup * that = (UI_ProjectSetup *)data; that->action = Action::cancel; } void UI_ProjectSetup::use_callback(Fl_Button *w, void *data) { UI_ProjectSetup * that = (UI_ProjectSetup *)data; that->action = Action::accept; } void UI_ProjectSetup::game_callback(Fl_Choice *w, void *data) { UI_ProjectSetup * that = (UI_ProjectSetup *)data; const char * name = w->mvalue()->text; if (global::recent.queryIWAD(name)) { that->result.game = name; that->ok_but->activate(); } else { that->result.game.clear(); that->ok_but->deactivate(); } that->PopulatePort(); that->PopulateMapFormat(); } void UI_ProjectSetup::port_callback(Fl_Choice *w, void *data) { UI_ProjectSetup * that = (UI_ProjectSetup *)data; const char * name = w->mvalue()->text; that->result.port = name; that->PopulateMapFormat(); } void UI_ProjectSetup::format_callback(Fl_Choice *w, void *data) { UI_ProjectSetup * that = (UI_ProjectSetup *)data; const char * fmt_str = w->mvalue()->text; if (strstr(fmt_str, "UDMF")) that->result.mapFormat = MapFormat::udmf; else if (strstr(fmt_str, "Hexen")) that->result.mapFormat = MapFormat::hexen; else that->result.mapFormat = MapFormat::doom; that->PopulateNamespaces(); } void UI_ProjectSetup::namespace_callback(Fl_Choice *w, void *data) { UI_ProjectSetup * that = (UI_ProjectSetup *)data; that->result.nameSpace = w->mvalue()->text; } void UI_ProjectSetup::find_callback(Fl_Button *w, void *data) { UI_ProjectSetup * that = (UI_ProjectSetup *)data; Fl_Native_File_Chooser chooser; chooser.title("Pick file to open"); chooser.type(Fl_Native_File_Chooser::BROWSE_FILE); chooser.filter("Wads\t*.wad"); chooser.directory(that->inst.Main_FileOpFolder().u8string().c_str()); switch (chooser.show()) { case -1: // error DLG_Notify("Unable to open that wad:\n\n%s", chooser.errmsg()); return; case 1: // cancelled return; default: break; // OK } // check that a game definition exists SString game = GameNameFromIWAD(fs::u8path(chooser.filename())); if (! M_CanLoadDefinitions(global::home_dir, global::install_dir, GAMES_DIR, game)) { DLG_Notify("That game is not supported (no definition file).\n\n" "Please try again."); return; } global::recent.addIWAD(fs::u8path(chooser.filename())); global::recent.save(global::home_dir); that->result.game = game; that->PopulateIWADs(); that->PopulatePort(); that->PopulateMapFormat(); } void UI_ProjectSetup::setup_callback(Fl_Button *w, void *data) { UI_ProjectSetup * that = (UI_ProjectSetup *)data; // FIXME : deactivate button when this is true if (that->result.game.empty() || that->result.port.empty()) { fl_beep(); return; } that->inst.M_PortSetupDialog(that->result.port, that->result.game, {}); } void UI_ProjectSetup::load_callback(Fl_Button *w, void *data) { auto that = static_cast(data); int r; bool isdir = false; for (r = 0; r < RES_NUM; ++r) if (w == that->mResourceFileButtons[r] || w == that->mResourceDirButtons[r]) { isdir = w == that->mResourceDirButtons[r]; break; } SYS_ASSERT(0 <= r && r < RES_NUM); SYS_ASSERT(that); const char *title = isdir ? "Pick folder to open" : "Pick file to open"; #ifdef __APPLE__ title = "Pick file or folder to open"; isdir = true; #endif Fl_Native_File_Chooser chooser; chooser.title(title); if(isdir) { chooser.type(Fl_Native_File_Chooser::BROWSE_DIRECTORY); #ifdef __APPLE__ chooser.filter("Wads\t*.wad\nEureka defs\t*.ugh\nDehacked files\t*.deh\nBEX files\t*.bex"); #endif } else { chooser.type(Fl_Native_File_Chooser::BROWSE_FILE); chooser.filter("Wads\t*.wad\nEureka defs\t*.ugh\nDehacked files\t*.deh\nBEX files\t*.bex"); } chooser.directory(that->inst.Main_FileOpFolder().u8string().c_str()); switch (chooser.show()) { case -1: // error DLG_Notify("Unable to open that wad:\n\n%s", chooser.errmsg()); return; case 1: // cancelled return; default: break; // OK } that->result.resources[r] = fs::u8path(chooser.filename()); that->res_name[r]->value(fileOrDirName(that->result.resources[r]).u8string().c_str()); } void UI_ProjectSetup::kill_callback(Fl_Button *w, void *data) { auto that = static_cast(data); int r; for (r = 0; r < RES_NUM; ++r) if (w == that->mClearButtons[r]) break; SYS_ASSERT(0 <= r && r < RES_NUM); SYS_ASSERT(that); if (!that->result.resources[r].empty()) { that->result.resources[r].clear(); that->res_name[r]->value(""); } } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_file.h000066400000000000000000000120411464327712600201130ustar00rootroot00000000000000//------------------------------------------------------------------------ // FILE-RELATED DIALOGS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2019 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_FILE_H__ #define __EUREKA_UI_FILE_H__ class UI_ChooseMap : public UI_Escapable_Window { private: Fl_Input *map_name; Fl_Group *map_buttons; Fl_Return_Button *ok_but; // normally NULL, when present will prevent using an existing level name std::shared_ptr rename_wad; enum { ACT_none = 0, ACT_CANCEL, ACT_ACCEPT }; int action = ACT_none; void CheckMapName(); public: UI_ChooseMap(const char *initial_name = "", const std::shared_ptr &_rename_wad = NULL); virtual ~UI_ChooseMap() { } // format is 'E' for ExMx, or 'M' for MAPxx void PopulateButtons(char format, const Wad_file *test_wad = NULL); // returns map name on success, NULL on cancel SString Run(); private: static void ok_callback(Fl_Widget *, void *); static void close_callback(Fl_Widget *, void *); static void button_callback(Fl_Widget *, void *); static void input_callback(Fl_Widget *, void *); static void new_callback(Fl_Widget *, void *); }; //------------------------------------------------------------------------ class UI_OpenMap : public UI_Escapable_Window { private: enum { LOOK_PWad = 0, LOOK_IWad, LOOK_Resource }; Fl_Output *pwad_name; Fl_Choice *look_where; Fl_Input *map_name; UI_Scroll *button_grp; Fl_Return_Button *ok_but; enum class Action { none, cancel, accept }; Action action = Action::none; // the WAD file opened by the "Load" button (initially NULL) std::shared_ptr loaded_wad; // the WAD file which we are showing map buttons for. // can be the "game_wad" or "edit_wad" globals, the "loaded_wad" // field above, or NULL. std::shared_ptr using_wad; Instance &inst; public: UI_OpenMap(Instance &inst); virtual ~UI_OpenMap(); // Run the dialog and return an opened wad (from Wad_file::Open) // or edit_wad/game_wad, or NULL if the user cancelled. // // "map_v" parameter must be non-NULL, it receives the chosen map // name, or set to NULL when cancelled. // // "did_load" is true when the user loaded a new pwad and this // method returned it. It should become the next edit_wad. // std::shared_ptr Run(SString* map_v, bool * did_load); private: void Populate(); void PopulateButtons(); void LoadFile(); void SetPWAD(const SString &name); void CheckMapName(); private: static void ok_callback(Fl_Widget *, void *); static void close_callback(Fl_Widget *, void *); static void look_callback(Fl_Widget *, void *); static void button_callback(Fl_Widget *, void *); static void input_callback(Fl_Widget *, void *); static void load_callback(Fl_Widget *, void *); }; //------------------------------------------------------------------------ class UI_ProjectSetup : public UI_Escapable_Window { public: enum { RES_NUM = 4 }; struct Result { SString game; SString port; MapFormat mapFormat = MapFormat::invalid; SString nameSpace; fs::path resources[RES_NUM]; }; private: Fl_Choice *game_choice; Fl_Choice *port_choice; Fl_Choice *format_choice; Fl_Output *res_name[RES_NUM]; Fl_Button *ok_but; Fl_Button *cancel; map_format_bitset_t usable_formats; enum class Action { none, cancel, accept }; Action action = Action::none; static void game_callback(Fl_Choice*, void*); static void port_callback(Fl_Choice*, void*); static void format_callback(Fl_Choice*, void*); static void namespace_callback(Fl_Choice*, void*); static void find_callback(Fl_Button*, void*); static void setup_callback(Fl_Button*, void*); static void kill_callback(Fl_Button*, void*); static void load_callback(Fl_Button*, void*); static void close_callback(Fl_Widget*, void*); static void use_callback(Fl_Button*, void*); void PopulateIWADs(); void PopulatePort(); void PopulateMapFormat(); void PopulateNamespaces(); void PopulateResources(); Result result; Fl_Button* mResourceFileButtons[RES_NUM] = {}; Fl_Button* mResourceDirButtons[RES_NUM] = {}; Fl_Button* mClearButtons[RES_NUM] = {}; Instance &inst; public: UI_ProjectSetup(Instance &inst, bool new_project = false, bool is_startup = false); // returns true if something changed tl::optional Run(); }; #endif /* __EUREKA_UI_FILE_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_hyper.cc000066400000000000000000000070641464327712600204720ustar00rootroot00000000000000//------------------------------------------------------------------------ // Hyperlinks //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2011 Andrew Apted // Copyright (C) 2002 Jason Bryan // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Used some code from Jason Bryan's FLU (FLTK Utility Widgets), // which is under the the GNU LGPL license (same as FLTK itself). // //------------------------------------------------------------------------ #include "main.h" #include "ui_window.h" #define LINK_BLUE FL_BLUE // fl_rgb_color(0,0,192) UI_HyperLink::UI_HyperLink(int x, int y, int w, int h, const char *label, const char *_url) : Fl_Button(x, y, w, h, label), hover(false), label_X(0), label_Y(0), label_W(0), label_H(0) { // copy the URL string url = strdup(_url); box(FL_FLAT_BOX); color(FL_GRAY); labelcolor(LINK_BLUE); // setup the callback callback(callback_Link, NULL); } UI_HyperLink::~UI_HyperLink() { free((void *)url); } void UI_HyperLink::checkLink() { // change the cursor if the mouse is over the link. // the 'hover' variable reduces the number of times fl_cursor() // needs to be called (since it can be expensive). if (Fl::event_inside(x()+label_X, y()+label_Y, label_W, label_H)) { if (! hover) fl_cursor(FL_CURSOR_HAND); hover = true; } else { if (hover) fl_cursor(FL_CURSOR_DEFAULT); hover = false; } } int UI_HyperLink::handle(int event) { if (!active_r()) return Fl_Button::handle(event); switch (event) { case FL_MOVE: { checkLink(); return 1; } case FL_ENTER: { checkLink(); redraw(); return 1; } break; case FL_LEAVE: { checkLink(); redraw(); return 1; } default: break; } return Fl_Button::handle(event); } void UI_HyperLink::draw() { if (type() == FL_HIDDEN_BUTTON) return; // determine where to draw the label label_X = label_Y = label_W = label_H = 0; fl_font(labelfont(), labelsize()); fl_measure(label(), label_W, label_H, 1); if (align() & FL_ALIGN_LEFT) label_X = 2; else if (align() & FL_ALIGN_RIGHT) label_X = w() - label_W - 2; else label_X = (w() - label_W) / 2; label_Y += h() / 2 - labelsize() / 2 - 2; // draw the link text fl_draw_box(box(), x(), y(), w(), h(), color()); fl_color(labelcolor()); fl_draw(label(), x() + label_X, y() + label_Y, label_W, label_H, FL_ALIGN_LEFT); // draw the underline if (! value()) { int yy = y() + label_Y + label_H-2; fl_line_style(FL_SOLID); fl_line(x() + label_X, yy, x() + label_X + label_W, yy); fl_line_style(0); } /* if (Fl::focus() == this) draw_focus(); */ } void UI_HyperLink::callback_Link(Fl_Widget *w, void *data) { UI_HyperLink *link = (UI_HyperLink *)w; if (! fl_open_uri(link->url)) { gLog.printf("\n"); gLog.printf("Open URL failed: %s\n", link->url); gLog.printf("\n"); } } eureka-editor-eureka-2.0.2/src/ui_hyper.h000066400000000000000000000030261464327712600203260ustar00rootroot00000000000000//------------------------------------------------------------------------ // Hyperlinks //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2011 Andrew Apted // Copyright (C) 2002 Jason Bryan // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_HYPER_H__ #define __EUREKA_UI_HYPER_H__ #include "FL/Fl_Button.H" class UI_HyperLink : public Fl_Button { private: // true when mouse is over this widget bool hover; // area containing the label int label_X, label_Y, label_W, label_H; // the URL to visit when clicked const char *url; public: UI_HyperLink(int x, int y, int w, int h, const char *label, const char *_url); virtual ~UI_HyperLink(); public: // FLTK overrides int handle(int event); void draw(); private: void checkLink(); static void callback_Link(Fl_Widget *w, void *data); }; #endif /* __EUREKA_UI_HYPER_H__ */ //--- editor settings --- // vi:ts=2:sw=2:expandtab eureka-editor-eureka-2.0.2/src/ui_infobar.cc000066400000000000000000000414321464327712600207600ustar00rootroot00000000000000//------------------------------------------------------------------------ // Information Bar (bottom of window) //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2019 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Instance.h" #include "main.h" #include "ui_window.h" #include "e_main.h" #include "e_linedef.h" #include "LineDef.h" #include "m_config.h" #include "m_game.h" #include "m_vector.h" #include "r_grid.h" #include "r_render.h" #include "SideDef.h" #include "Vertex.h" #define SNAP_COLOR (config::gui_scheme == 2 ? fl_rgb_color(255,96,0) : fl_rgb_color(255, 96, 0)) #define FREE_COLOR (config::gui_scheme == 2 ? fl_rgb_color(0,192,0) : fl_rgb_color(128, 255, 128)) #define RATIO_COLOR FL_YELLOW const char *UI_InfoBar::scale_options_str = " 6%| 12%| 25%| 33%| 50%|100%|200%|400%|800%"; const double UI_InfoBar::scale_amounts[9] = { 0.0625, 0.125, 0.25, 0.33333, 0.5, 1.0, 2.0, 4.0, 8.0 }; // // UI_InfoBar Constructor // UI_InfoBar::UI_InfoBar(Instance &inst, int X, int Y, int W, int H, const char *label) : Fl_Group(X, Y, W, H, label), inst(inst) { box(FL_FLAT_BOX); // Fitts' law : keep buttons flush with bottom of window Y += 4; H -= 4; Fl_Box *mode_lab = new Fl_Box(FL_NO_BOX, X, Y, 56, H, "Mode:"); mode_lab->align(FL_ALIGN_RIGHT | FL_ALIGN_INSIDE); mode_lab->labelsize(16); mode = new Fl_Menu_Button(X+58, Y, 96, H, "Things"); mode->align(FL_ALIGN_INSIDE); mode->add("Things|Linedefs|Sectors|Vertices"); mode->callback(mode_callback, this); mode->labelsize(16); X = mode->x() + mode->w() + 10; Fl_Box *scale_lab = new Fl_Box(FL_NO_BOX, X, Y, 58, H, "Scale:"); scale_lab->align(FL_ALIGN_RIGHT | FL_ALIGN_INSIDE); scale_lab->labelsize(16); scale = new Fl_Menu_Button(X+60+26, Y, 78, H, "100%"); scale->align(FL_ALIGN_INSIDE); scale->add(scale_options_str); scale->callback(scale_callback, this); scale->labelsize(16); Fl_Button *sc_minus, *sc_plus; sc_minus = new Fl_Button(X+60, Y+1, 24, H-2, "-"); sc_minus->callback(sc_minus_callback, this); sc_minus->labelfont(FL_HELVETICA_BOLD); sc_minus->labelsize(16); sc_plus = new Fl_Button(X+60+26+80, Y+1, 24, H-2, "+"); sc_plus->callback(sc_plus_callback, this); sc_plus->labelfont(FL_HELVETICA_BOLD); sc_plus->labelsize(16); X = sc_plus->x() + sc_plus->w() + 12; Fl_Box *gs_lab = new Fl_Box(FL_NO_BOX, X, Y, 42, H, "Grid:"); gs_lab->align(FL_ALIGN_RIGHT | FL_ALIGN_INSIDE); gs_lab->labelsize(16); grid_size = new Fl_Menu_Button(X+44, Y, 72, H, "OFF"); grid_size->align(FL_ALIGN_INSIDE); grid_size->add(grid::getValuesFLTKMenuString().c_str()); grid_size->callback(grid_callback, this); grid_size->labelsize(16); X = grid_size->x() + grid_size->w() + 12; grid_snap = new Fl_Toggle_Button(X+4, Y, 72, H); grid_snap->value(inst.grid.snaps() ? 1 : 0); grid_snap->color(FREE_COLOR); grid_snap->selection_color(SNAP_COLOR); grid_snap->callback(snap_callback, this); grid_snap->labelsize(16); UpdateSnapText(); X = grid_snap->x() + grid_snap->w() + 12; Fl_Box *ratio_lab = new Fl_Box(FL_NO_BOX, X, Y, 52, H, "Ratio:"); ratio_lab->align(FL_ALIGN_RIGHT | FL_ALIGN_INSIDE); ratio_lab->labelsize(16); ratio_lock = new Fl_Menu_Button(X+54, Y, 106, H, "UNLOCK"); ratio_lock->align(FL_ALIGN_INSIDE); ratio_lock->add("UNLOCK|1:1|2:1|4:1|8:1|5:4|7:4|User Value"); ratio_lock->callback(ratio_callback, this); ratio_lock->labelsize(16); X = ratio_lock->x() + ratio_lock->w() + 12; Fl_Box *rend_lab = new Fl_Box(FL_FLAT_BOX, X, Y, 56, H, "Rend:"); rend_lab->align(FL_ALIGN_RIGHT | FL_ALIGN_INSIDE); rend_lab->labelsize(16); sec_rend = new Fl_Menu_Button(X+58, Y, 96, H, "PLAIN"); sec_rend->align(FL_ALIGN_INSIDE); sec_rend->add("PLAIN|Floor|Ceiling|Lighting|Floor Bright|Ceil Bright|Sound|3D VIEW"); sec_rend->callback(rend_callback, this); sec_rend->labelsize(16); X = sec_rend->x() + rend_lab->w() + 10; resizable(NULL); end(); } // // UI_InfoBar Destructor // UI_InfoBar::~UI_InfoBar() { } int UI_InfoBar::handle(int event) { return Fl_Group::handle(event); } void UI_InfoBar::mode_callback(Fl_Widget *w, void *data) { Fl_Menu_Button *mode = (Fl_Menu_Button *)w; static const char *mode_keys = "tlsvr"; auto bar = static_cast(data); bar->inst.Editor_ChangeMode(mode_keys[mode->value()]); } void UI_InfoBar::rend_callback(Fl_Widget *w, void *data) { Fl_Menu_Button *sec_rend = (Fl_Menu_Button *)w; auto bar = static_cast(data); // last option is 3D mode if (sec_rend->value() > SREND_SoundProp) { Render3D_Enable(bar->inst, true); return; } switch (sec_rend->value()) { case 1: bar->inst.edit.sector_render_mode = SREND_Floor; break; case 2: bar->inst.edit.sector_render_mode = SREND_Ceiling; break; case 3: bar->inst.edit.sector_render_mode = SREND_Lighting; break; case 4: bar->inst.edit.sector_render_mode = SREND_FloorBright; break; case 5: bar->inst.edit.sector_render_mode = SREND_CeilBright; break; case 6: bar->inst.edit.sector_render_mode = SREND_SoundProp; break; default: bar->inst.edit.sector_render_mode = SREND_Nothing; break; } if (bar->inst.edit.render3d) Render3D_Enable(bar->inst, false); // need sectors mode for sound propagation display if (bar->inst.edit.sector_render_mode == SREND_SoundProp && bar->inst.edit.mode != ObjType::sectors) bar->inst.Editor_ChangeMode('s'); bar->inst.RedrawMap(); } void UI_InfoBar::scale_callback(Fl_Widget *w, void *data) { auto bar = static_cast(data); Fl_Menu_Button *scale = (Fl_Menu_Button *)w; double new_scale = scale_amounts[scale->value()]; bar->inst.grid.NearestScale(new_scale); } void UI_InfoBar::sc_minus_callback(Fl_Widget *w, void *data) { auto bar = static_cast(data); bar->inst.ExecuteCommand("Zoom", "-1", "/center"); } void UI_InfoBar::sc_plus_callback(Fl_Widget *w, void *data) { auto bar = static_cast(data); bar->inst.ExecuteCommand("Zoom", "+1", "/center"); } void UI_InfoBar::grid_callback(Fl_Widget *w, void *data) { auto bar = static_cast(data); Fl_Menu_Button *gsize = (Fl_Menu_Button *)w; int new_step = grid::values[gsize->value()]; if (new_step < 0) bar->inst.grid.SetShown(false); else bar->inst.grid.ForceStep(new_step); } void UI_InfoBar::snap_callback(Fl_Widget *w, void *data) { auto bar = static_cast(data); Fl_Toggle_Button *grid_snap = (Fl_Toggle_Button *)w; // update editor state bar->inst.grid.SetSnap(grid_snap->value() ? true : false); } void UI_InfoBar::ratio_callback(Fl_Widget *w, void *data) { Fl_Menu_Button *ratio_lock = (Fl_Menu_Button *)w; auto bar = static_cast(data); bar->inst.grid.configureRatio(ratio_lock->value(), false); } //------------------------------------------------------------------------ void UI_InfoBar::NewEditMode(ObjType new_mode) { switch (new_mode) { case ObjType::things: mode->value(0); break; case ObjType::linedefs: mode->value(1); break; case ObjType::sectors: mode->value(2); break; case ObjType::vertices: mode->value(3); break; default: break; } UpdateModeColor(); } void UI_InfoBar::SetMouse() { // TODO this method should go away inst.main_win->status_bar->redraw(); } void UI_InfoBar::SetScale(double new_scale) { double perc = new_scale * 100.0; char buffer[64]; if (perc < 10.0) snprintf(buffer, sizeof(buffer), "%1.1f%%", perc); else snprintf(buffer, sizeof(buffer), "%3d%%", (int)perc); scale->copy_label(buffer); } void UI_InfoBar::SetGrid(int new_step) { if (new_step < 0) { grid_size->label("OFF"); } else { char buffer[64]; snprintf(buffer, sizeof(buffer), "%d", new_step); grid_size->copy_label(buffer); } } void UI_InfoBar::UpdateSnap() { grid_snap->value(inst.grid.snaps() ? 1 : 0); UpdateSnapText(); } void UI_InfoBar::UpdateSecRend() { if (inst.edit.render3d) { sec_rend->label("3D VIEW"); return; } switch (inst.edit.sector_render_mode) { case SREND_Floor: sec_rend->label("Floor"); break; case SREND_Ceiling: sec_rend->label("Ceiling"); break; case SREND_Lighting: sec_rend->label("Lighting"); break; case SREND_FloorBright: sec_rend->label("Floor Brt"); break; case SREND_CeilBright: sec_rend->label("Ceil Brt"); break; case SREND_SoundProp: sec_rend->label("Sound"); break; default: sec_rend->label("PLAIN"); break; } } void UI_InfoBar::UpdateRatio() { if (inst.grid.getRatio() == 0) ratio_lock->color(FL_BACKGROUND_COLOR); else ratio_lock->color(RATIO_COLOR); if (inst.grid.getRatio() == 7) { char buffer[256]; snprintf(buffer, sizeof(buffer), "Usr %d:%d", config::grid_ratio_high, config::grid_ratio_low); // drop the "Usr" part when overly long if (strlen(buffer) > 9) ratio_lock->copy_label(buffer+4); else ratio_lock->copy_label(buffer); } else { ratio_lock->copy_label(ratio_lock->text(inst.grid.getRatio())); } } void UI_InfoBar::UpdateModeColor() { switch (mode->value()) { case 0: mode->label("Things"); mode->color(THING_MODE_COL); break; case 1: mode->label("Linedefs"); mode->color(LINE_MODE_COL); break; case 2: mode->label("Sectors"); mode->color(SECTOR_MODE_COL); break; case 3: mode->label("Vertices"); mode->color(VERTEX_MODE_COL); break; } } void UI_InfoBar::UpdateSnapText() { if (grid_snap->value()) { grid_snap->label("SNAP"); } else { grid_snap->label("Free"); } grid_snap->redraw(); } //------------------------------------------------------------------------ #define INFO_TEXT_COL fl_rgb_color(192, 192, 192) #define INFO_DIM_COL fl_rgb_color(128, 128, 128) UI_StatusBar::UI_StatusBar(Instance &inst, int X, int Y, int W, int H, const char *label) : Fl_Widget(X, Y, W, H, label), status(), inst(inst) { box(FL_NO_BOX); } UI_StatusBar::~UI_StatusBar() { } int UI_StatusBar::handle(int event) { // this never handles any events return 0; } void UI_StatusBar::draw() { fl_color(fl_rgb_color(64, 64, 64)); fl_rectf(x(), y(), w(), h()); fl_color(fl_rgb_color(96, 96, 96)); fl_rectf(x(), y() + h() - 1, w(), 1); fl_push_clip(x(), y(), w(), h()); fl_font(FL_COURIER, 16); int cx = x() + 10; int cy = y() + 20; if (inst.edit.render3d) { IB_Number(cx, cy, "x", iround(inst.r_view.x), 5); IB_Number(cx, cy, "y", iround(inst.r_view.y), 5); IB_Number(cx, cy, "z", iround(inst.r_view.z) - inst.conf.miscInfo.view_height, 4); // use less space when an action is occurring if (inst.edit.action == EditorAction::nothing) { int ang = iround(inst.r_view.angle * 180 / M_PI); if (ang < 0) ang += 360; IB_Number(cx, cy, "ang", ang, 3); cx += 2; IB_Flag(cx, cy, inst.r_view.gravity, "GRAV", "grav"); #if 0 IB_Number(cx, cy, "gamma", usegamma, 1); #endif } cx += 4; } else // 2D view { float mx = static_cast(inst.grid.SnapX(inst.edit.map.x)); float my = static_cast(inst.grid.SnapY(inst.edit.map.y)); mx = clamp(-32767.f, mx, 32767.f); my = clamp(-32767.f, my, 32767.f); IB_Coord(cx, cy, "x", mx); IB_Coord(cx, cy, "y", my); cx += 10; #if 0 IB_Number(cx, cy, "gamma", usegamma, 1); cx += 10; #endif } /* status message */ IB_Flag(cx, cy, true, "|", "|"); fl_color(INFO_TEXT_COL); switch (inst.edit.action) { case EditorAction::drag: IB_ShowDrag(cx, cy); break; case EditorAction::transform: IB_ShowTransform(cx, cy); break; case EditorAction::adjustOfs: IB_ShowOffsets(cx, cy); break; case EditorAction::drawLine: IB_ShowDrawLine(cx, cy); break; default: fl_draw(status.c_str(), cx, cy); break; } fl_pop_clip(); } void UI_StatusBar::IB_ShowDrag(int cx, int cy) { if (inst.edit.render3d && inst.edit.mode == ObjType::sectors) { IB_Number(cx, cy, "raise delta", iround(inst.edit.drag_sector_dz), 4); return; } if (inst.edit.render3d && inst.edit.mode == ObjType::things && inst.edit.drag_thing_up_down) { double dz = inst.edit.drag_cur.z - inst.edit.drag_start.z; IB_Number(cx, cy, "raise delta", iround(dz), 4); return; } v2double_t delta; if (inst.edit.render3d) { delta.x = inst.edit.drag_cur.x - inst.edit.drag_start.x; delta.y = inst.edit.drag_cur.y - inst.edit.drag_start.y; } else { delta = inst.main_win->canvas->DragDelta(); } IB_Coord(cx, cy, "dragging delta x", static_cast(delta.x)); IB_Coord(cx, cy, "y", static_cast(delta.y)); } void UI_StatusBar::IB_ShowTransform(int cx, int cy) { int rot_degrees; switch (inst.edit.trans_mode) { case TRANS_K_Scale: IB_Coord(cx, cy, "scale by", static_cast(inst.edit.trans_param.scale.x)); break; case TRANS_K_Stretch: IB_Coord(cx, cy, "stretch x", static_cast(inst.edit.trans_param.scale.x)); IB_Coord(cx, cy, "y", static_cast(inst.edit.trans_param.scale.y)); break; case TRANS_K_Rotate: case TRANS_K_RotScale: rot_degrees = static_cast(round(inst.edit.trans_param.rotate * (180 / M_PI))); IB_Number(cx, cy, "rotate by", rot_degrees, 3); break; case TRANS_K_Skew: IB_Coord(cx, cy, "skew x", static_cast(inst.edit.trans_param.skew.x)); IB_Coord(cx, cy, "y", static_cast(inst.edit.trans_param.skew.y)); break; } if (inst.edit.trans_mode == TRANS_K_RotScale) IB_Coord(cx, cy, "scale", static_cast(inst.edit.trans_param.scale.x)); } void UI_StatusBar::IB_ShowOffsets(int cx, int cy) { int dx = iround(inst.edit.adjust_dx); int dy = iround(inst.edit.adjust_dy); Objid hl = inst.edit.highlight; if (! inst.edit.Selected->empty()) { if (inst.edit.Selected->count_obj() == 1) { int first = inst.edit.Selected->find_first(); int parts = inst.edit.Selected->get_ext(first); hl = Objid(inst.edit.mode, first, parts); } else { hl.clear(); } } if (hl.valid() && hl.parts >= 2) { const auto L = inst.level.linedefs[hl.num]; int x_offset = 0; int y_offset = 0; const SideDef *SD = NULL; if (hl.parts & PART_LF_ALL) SD = inst.level.getLeft(*L); else SD = inst.level.getRight(*L); if (SD != NULL) { x_offset = SD->x_offset; y_offset = SD->y_offset; IB_Number(cx, cy, "new ofs x", x_offset + dx, 4); IB_Number(cx, cy, "y", y_offset + dy, 4); } } IB_Number(cx, cy, "delta x", dx, 4); IB_Number(cx, cy, "y", dy, 4); } void UI_StatusBar::IB_ShowDrawLine(int cx, int cy) { if (! inst.edit.drawLine.from.valid()) return; const auto V = inst.level.vertices[inst.edit.drawLine.from.num]; v2double_t dv = inst.edit.drawLine.to - V->xy(); // show a ratio value FFixedPoint fdx = FFixedPoint(dv.x); FFixedPoint fdy = FFixedPoint(dv.y); SString ratio_name = LD_RatioName(fdx, fdy, false); int old_cx = cx; IB_String(cx, cy, ratio_name.c_str()); cx = std::max(cx+12, old_cx + 170); IB_Coord(cx, cy, "delta x", static_cast(dv.x)); IB_Coord(cx, cy, "y", static_cast(dv.y)); } void UI_StatusBar::IB_Number(int& cx, int& cy, const char *label, int value, int size) { char buffer[256]; // negative size means we require a sign if (size < 0) snprintf(buffer, sizeof(buffer), "%s:%-+*d ", label, -size + 1, value); else snprintf(buffer, sizeof(buffer), "%s:%-*d ", label, size, value); fl_color(INFO_TEXT_COL); fl_draw(buffer, cx, cy); cx = static_cast(cx + fl_width(buffer)); } void UI_StatusBar::IB_Coord(int& cx, int& cy, const char *label, float value) { char buffer[256]; snprintf(buffer, sizeof(buffer), "%s:%-8.2f ", label, value); fl_color(INFO_TEXT_COL); fl_draw(buffer, cx, cy); cx = static_cast(cx + fl_width(buffer)); } void UI_StatusBar::IB_String(int& cx, int& cy, const char *str) { fl_draw(str, cx, cy); cx = static_cast(cx + fl_width(str)); } void UI_StatusBar::IB_Flag(int& cx, int& cy, bool value, const char *label_on, const char *label_off) { const char *label = value ? label_on : label_off; fl_color(value ? INFO_TEXT_COL : INFO_DIM_COL); fl_draw(label, cx, cy); cx = static_cast(cx + fl_width(label) + 20); } void UI_StatusBar::SetStatus(const char *str) { if (status == str) return; status = str; redraw(); } void Instance::Status_Set(EUR_FORMAT_STRING(const char *fmt), ...) const { if (!main_win) return; va_list arg_ptr; va_start(arg_ptr, fmt); SString text = SString::vprintf(fmt, arg_ptr);; va_end(arg_ptr); main_win->status_bar->SetStatus(text.c_str()); } void Instance::Status_Clear() const { if (!main_win) return; main_win->status_bar->SetStatus(""); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_infobar.h000066400000000000000000000060751464327712600206260ustar00rootroot00000000000000//------------------------------------------------------------------------ // Information Bar (bottom of window) //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2019 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_INFOBAR_H__ #define __EUREKA_UI_INFOBAR_H__ #include class Fl_Menu_Button; class Fl_Toggle_Button; class UI_InfoBar : public Fl_Group { public: UI_InfoBar(Instance &inst, int X, int Y, int W, int H, const char *label = NULL); virtual ~UI_InfoBar(); private: Fl_Menu_Button *mode; Fl_Menu_Button *scale; Fl_Menu_Button *grid_size; Fl_Menu_Button *sec_rend; Fl_Menu_Button *ratio_lock; Fl_Toggle_Button *grid_snap; public: // FLTK virtual method for handling input events. int handle(int event); public: void NewEditMode(ObjType new_mode); void SetMouse(); void SetScale(double new_scale); void SetGrid(int new_step); void UpdateSnap(); void UpdateSecRend(); void UpdateRatio(); private: static const char *scale_options_str; static const double scale_amounts[9]; void UpdateModeColor(); void UpdateSnapText(); static void mode_callback(Fl_Widget *, void *); static void rend_callback(Fl_Widget *, void *); static void scale_callback(Fl_Widget *, void *); static void sc_minus_callback(Fl_Widget *, void *); static void sc_plus_callback(Fl_Widget *, void *); static void grid_callback(Fl_Widget *, void *); static void snap_callback(Fl_Widget *, void *); static void ratio_callback(Fl_Widget *, void *); Instance &inst; }; //------------------------------------------------------------------------ class UI_StatusBar : public Fl_Widget { private: SString status; Instance &inst; public: UI_StatusBar(Instance &inst, int X, int Y, int W, int H, const char *label = NULL); virtual ~UI_StatusBar(); public: // FLTK methods void draw(); int handle(int event); // this only used by Status_Set() and Status_Clear() void SetStatus(const char *str); private: void IB_ShowDrag(int cx, int cy); void IB_ShowTransform(int cx, int cy); void IB_ShowOffsets(int cx, int cy); void IB_ShowDrawLine(int cx, int cy); void IB_String(int& cx, int& cy, const char *str); void IB_Number(int& cx, int& cy, const char *label, int value, int size); void IB_Coord (int& cx, int& cy, const char *label, float value); void IB_Flag (int& cx, int& cy, bool value, const char *label_on, const char *label_off); }; #endif /* __EUREKA_UI_INFOBAR_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_linedef.cc000066400000000000000000000606361464327712600207550ustar00rootroot00000000000000//------------------------------------------------------------------------ // LINEDEF PANEL //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2018 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include "ui_misc.h" #include "ui_window.h" #include "e_checks.h" #include "e_cutpaste.h" #include "e_linedef.h" #include "e_main.h" #include "e_things.h" #include "LineDef.h" #include "m_game.h" #include "Sector.h" #include "SideDef.h" #include "w_rawdef.h" #include "w_rawdef.h" #define MLF_ALL_AUTOMAP \ MLF_Secret | MLF_Mapped | MLF_DontDraw | MLF_XDoom_Translucent enum { INSET_LEFT = 6, INSET_TOP = 6, INSET_RIGHT = 6, INSET_BOTTOM = 5, SPACING_BELOW_NOMBRE = 4, TYPE_INPUT_X = 58, TYPE_INPUT_WIDTH = 75, TYPE_INPUT_HEIGHT = 24, BUTTON_SPACING = 10, CHOOSE_BUTTON_WIDTH = 80, GEN_BUTTON_WIDTH = 55, GEN_BUTTON_RIGHT_PADDING = 10, INPUT_SPACING = 2, DESC_INSET = 10, DESC_WIDTH = 48, SPAC_WIDTH = 57, TAG_WIDTH = 64, ARG_WIDTH = 42, ARG_PADDING = 5, }; class line_flag_CB_data_c { public: UI_LineBox *parent; int mask; line_flag_CB_data_c(UI_LineBox *_parent, int _mask) : parent(_parent), mask(_mask) { } }; // // UI_LineBox Constructor // UI_LineBox::UI_LineBox(Instance &inst, int X, int Y, int W, int H, const char *label) : MapItemBox(inst, X, Y, W, H, label) { box(FL_FLAT_BOX); // (FL_THIN_UP_BOX); X += INSET_LEFT; Y += INSET_TOP; W -= INSET_LEFT + INSET_RIGHT; H -= INSET_TOP + INSET_BOTTOM; which = new UI_Nombre(X + NOMBRE_INSET, Y, W - 2 * NOMBRE_INSET, NOMBRE_HEIGHT, "Linedef"); Y += which->h() + SPACING_BELOW_NOMBRE; type = new UI_DynInput(X + TYPE_INPUT_X, Y, TYPE_INPUT_WIDTH, TYPE_INPUT_HEIGHT, "Type: "); type->align(FL_ALIGN_LEFT); type->callback(type_callback, this); type->callback2(dyntype_callback, this); type->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); type->type(FL_INT_INPUT); choose = new Fl_Button(type->x() + type->w() + BUTTON_SPACING, Y, CHOOSE_BUTTON_WIDTH, TYPE_INPUT_HEIGHT, "Choose"); choose->callback(button_callback, this); gen = new Fl_Button(choose->x() + choose->w() + BUTTON_SPACING, Y, GEN_BUTTON_WIDTH, TYPE_INPUT_HEIGHT, "Gen"); gen->callback(button_callback, this); Y += type->h() + INPUT_SPACING; new Fl_Box(FL_NO_BOX, X + DESC_INSET, Y, DESC_WIDTH, TYPE_INPUT_HEIGHT, "Desc: "); desc = new Fl_Output(type->x(), Y, W - type->x(), TYPE_INPUT_HEIGHT); desc->align(FL_ALIGN_LEFT); actkind = new Fl_Choice(type->x(), Y, SPAC_WIDTH, TYPE_INPUT_HEIGHT); // this order must match the SPAC_XXX constants actkind->add("W1|WR|S1|SR|M1|MR|G1|GR|P1|PR|X1|XR|??"); actkind->value(12); actkind->callback(flags_callback, new line_flag_CB_data_c(this, MLF_Activation | MLF_Repeatable)); actkind->deactivate(); actkind->hide(); Y += desc->h() + INPUT_SPACING; tag = new UI_DynIntInput(type->x(), Y, TAG_WIDTH, TYPE_INPUT_HEIGHT, "Tag: "); tag->align(FL_ALIGN_LEFT); tag->callback(tag_callback, this); tag->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); length = new UI_DynIntInput(type->x() + W/2, Y, TAG_WIDTH, TYPE_INPUT_HEIGHT, "Length: "); length->align(FL_ALIGN_LEFT); length->callback(length_callback, this); length->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); for (int a = 0 ; a < 5 ; a++) { args[a] = new UI_DynIntInput(type->x() + (ARG_WIDTH + ARG_PADDING) * a, Y, ARG_WIDTH, TYPE_INPUT_HEIGHT); args[a]->callback(args_callback, new line_flag_CB_data_c(this, a)); args[a]->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); args[a]->hide(); } args[0]->label("Args: "); Y += tag->h() + 10; Fl_Box *flags = new Fl_Box(FL_FLAT_BOX, X+10, Y, 64, 24, "Flags: "); flags->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT); f_automap = new Fl_Choice(X+W-118, Y, 104, 22, "Vis: "); f_automap->add("Normal|Invisible|Mapped|Secret"); f_automap->value(0); f_automap->callback(flags_callback, new line_flag_CB_data_c(this, MLF_ALL_AUTOMAP)); Y += flags->h() - 1; static const int FW = 110; auto addCheckBox = [this, &X, &Y, &W](bool right, const char *text, int flag) { auto check = new Fl_Check_Button(X + (right ? W - 120 : 28), Y + 2, FW, 20, text); check->labelsize(12); check->callback(flags_callback, new line_flag_CB_data_c(this, flag)); return check; }; f_upper = addCheckBox(false, "upper unpeg", MLF_UpperUnpegged); f_walk = addCheckBox(true, "impassable", MLF_Blocking); Y += 19; f_lower = addCheckBox(false, "lower unpeg", MLF_LowerUnpegged); f_mons = addCheckBox(true, "block mons", MLF_BlockMonsters); Y += 19; f_passthru = addCheckBox(false, "pass thru", MLF_Boom_PassThru); f_passthru->hide(); f_jumpover = addCheckBox(false, "jump over", MLF_Strife_JumpOver); f_jumpover->hide(); f_sound = addCheckBox(true, "sound block", MLF_SoundBlock); Y += 19; f_3dmidtex = addCheckBox(true, "3D MidTex", MLF_Eternity_3DMidTex); f_3dmidtex->hide(); f_trans1 = addCheckBox(false, "", MLF_Strife_Translucent1); f_trans1->hide(); f_trans2 = new Fl_Check_Button(X+44, Y+2, FW, 20, "translucency"); f_trans2->labelsize(12); f_trans2->callback(flags_callback, new line_flag_CB_data_c(this, MLF_Strife_Translucent2)); f_trans2->hide(); f_flyers = addCheckBox(true, "block flyers", MLF_Strife_BlockFloaters); f_flyers->hide(); Y += 29; front = new UI_SideBox(inst, x(), Y, w(), 140, 0); Y += front->h() + 14; back = new UI_SideBox(inst, x(), Y, w(), 140, 1); Y += back->h(); mFixUp.loadFields({type, length, tag, args[0], args[1], args[2], args[3], args[4]}); end(); resizable(nullptr); } void UI_LineBox::type_callback(Fl_Widget *w, void *data) { UI_LineBox *box = (UI_LineBox *)data; // support hexadecimal int new_type = (int)strtol(box->type->value(), NULL, 0); if (! box->inst.edit.Selected->empty()) { EditOperation op(box->inst.level.basis); op.setMessageForSelection("edited type of", *box->inst.edit.Selected); for (sel_iter_c it(*box->inst.edit.Selected) ; !it.done() ; it.next()) { op.changeLinedef(*it, LineDef::F_TYPE, new_type); } } // update description box->UpdateField(LineDef::F_TYPE); } void UI_LineBox::dyntype_callback(Fl_Widget *w, void *data) { UI_LineBox *box = (UI_LineBox *)data; if (box->obj < 0) return; // support hexadecimal int new_type = (int)strtol(box->type->value(), NULL, 0); const char *gen_desc = box->GeneralizedDesc(new_type); if (gen_desc) { box->desc->value(gen_desc); } else { const linetype_t &info = box->inst.conf.getLineType(new_type); box->desc->value(info.desc.c_str()); } box->inst.main_win->browser->UpdateGenType(new_type); } void UI_LineBox::SetTexOnLine(EditOperation &op, int ld, StringID new_tex, int e_state, int parts) { bool opposite = (e_state & FL_SHIFT); const auto L = inst.level.linedefs[ld]; // handle the selected texture boxes if (parts != 0) { if (L->OneSided()) { if (parts & PART_RT_LOWER) op.changeSidedef(L->right, SideDef::F_MID_TEX, new_tex); if (parts & PART_RT_UPPER) op.changeSidedef(L->right, SideDef::F_UPPER_TEX, new_tex); return; } if (inst.level.getRight(*L)) { if (parts & PART_RT_LOWER) op.changeSidedef(L->right, SideDef::F_LOWER_TEX, new_tex); if (parts & PART_RT_UPPER) op.changeSidedef(L->right, SideDef::F_UPPER_TEX, new_tex); if (parts & PART_RT_RAIL) op.changeSidedef(L->right, SideDef::F_MID_TEX, new_tex); } if (inst.level.getLeft(*L)) { if (parts & PART_LF_LOWER) op.changeSidedef(L->left, SideDef::F_LOWER_TEX, new_tex); if (parts & PART_LF_UPPER) op.changeSidedef(L->left, SideDef::F_UPPER_TEX, new_tex); if (parts & PART_LF_RAIL) op.changeSidedef(L->left, SideDef::F_MID_TEX, new_tex); } return; } // middle click : set mid-masked texture on both sides if (e_state & FL_BUTTON2) { if (! L->TwoSided()) return; // convenience: set lower unpeg on first change if (! (L->flags & MLF_LowerUnpegged) && is_null_tex(inst.level.getRight(*L)->MidTex()) && is_null_tex(inst.level.getLeft(*L)->MidTex()) ) { op.changeLinedef(ld, LineDef::F_FLAGS, L->flags | MLF_LowerUnpegged); } op.changeSidedef(L->left, SideDef::F_MID_TEX, new_tex); op.changeSidedef(L->right, SideDef::F_MID_TEX, new_tex); return; } // one-sided case: set the middle texture only if (! L->TwoSided()) { int sd = (L->right >= 0) ? L->right : L->left; if (sd < 0) return; op.changeSidedef(sd, SideDef::F_MID_TEX, new_tex); return; } // modify an upper texture int sd1 = L->right; int sd2 = L->left; if (e_state & FL_BUTTON3) { // back ceiling is higher? if (inst.level.getSector(*inst.level.getLeft(*L)).ceilh > inst.level.getSector(*inst.level.getRight(*L)).ceilh) std::swap(sd1, sd2); if (opposite) std::swap(sd1, sd2); op.changeSidedef(sd1, SideDef::F_UPPER_TEX, new_tex); } // modify a lower texture else { // back floor is lower? if (inst.level.getSector(*inst.level.getLeft(*L)).floorh < inst.level.getSector(*inst.level.getRight(*L)).floorh) std::swap(sd1, sd2); if (opposite) std::swap(sd1, sd2); const auto S = inst.level.sidedefs[sd1]; // change BOTH upper and lower when they are the same // (which is great for windows). // // Note: we only do this for LOWERS (otherwise it'd be // impossible to set them to different textures). if (S->lower_tex == S->upper_tex) op.changeSidedef(sd1, SideDef::F_UPPER_TEX, new_tex); op.changeSidedef(sd1, SideDef::F_LOWER_TEX, new_tex); } } // // Check sidedefs dirty fields // void UI_LineBox::checkSidesDirtyFields() { front->checkDirtyFields(); back->checkDirtyFields(); } void UI_LineBox::SetTexture(const char *tex_name, int e_state, int parts) { StringID new_tex = BA_InternaliseString(tex_name); // this works a bit differently than other ways, we don't modify a // widget and let it update the map, instead we update the map and // let the widget(s) get updated. That's because we do different // things depending on whether the line is one-sided or two-sided. if (! inst.edit.Selected->empty()) { mFixUp.checkDirtyFields(); checkSidesDirtyFields(); EditOperation op(inst.level.basis); op.setMessageForSelection("edited texture on", *inst.edit.Selected); for (sel_iter_c it(*inst.edit.Selected) ; !it.done() ; it.next()) { int p2 = inst.edit.Selected->get_ext(*it); // only use parts explicitly selected in 3D view when no // parts in the linedef panel are selected. if (! (parts == 0 && p2 > 1)) p2 = parts; SetTexOnLine(op, *it, new_tex, e_state, p2); } } UpdateField(); UpdateSides(); redraw(); } void UI_LineBox::SetLineType(int new_type) { if (obj < 0) { /// Beep("No lines selected"); return; } auto buffer = SString(new_type); mFixUp.checkDirtyFields(); checkSidesDirtyFields(); mFixUp.setInputValue(type, buffer.c_str()); type->do_callback(); } void UI_LineBox::CB_Copy(int parts) { // determine which sidedef texture to grab from const char *name = NULL; mFixUp.checkDirtyFields(); checkSidesDirtyFields(); for (int pass = 0 ; pass < 2 ; pass++) { UI_SideBox *SD = (pass == 0) ? front : back; for (int b = 0 ; b < 3 ; b++) { int try_part = PART_RT_LOWER << (b + pass * 4); if ((parts & try_part) == 0) continue; const char *b_name = (b == 0) ? SD->l_tex->value() : (b == 1) ? SD->u_tex->value() : SD->r_tex->value(); SYS_ASSERT(b_name); if (name && y_stricmp(name, b_name) != 0) { inst.Beep("multiple textures"); return; } name = b_name; } } Texboard_SetTex(name, inst.conf); inst.Status_Set("copied %s", name); } void UI_LineBox::CB_Paste(int parts, StringID new_tex) { // iterate over selected linedefs if (inst.edit.Selected->empty()) return; mFixUp.checkDirtyFields(); checkSidesDirtyFields(); { EditOperation op(inst.level.basis); op.setMessage("pasted %s", BA_GetString(new_tex).c_str()); for (sel_iter_c it(*inst.edit.Selected) ; !it.done() ; it.next()) { const auto L = inst.level.linedefs[*it]; for (int pass = 0 ; pass < 2 ; pass++) { int sd = (pass == 0) ? L->right : L->left; if (sd < 0) continue; int parts2 = pass ? (parts >> 4) : parts; if (L->TwoSided()) { if (parts2 & PART_RT_LOWER) op.changeSidedef(sd, SideDef::F_LOWER_TEX, new_tex); if (parts2 & PART_RT_UPPER) op.changeSidedef(sd, SideDef::F_UPPER_TEX, new_tex); if (parts2 & PART_RT_RAIL) op.changeSidedef(sd, SideDef::F_MID_TEX, new_tex); } else // one-sided line { if (parts2 & PART_RT_LOWER) op.changeSidedef(sd, SideDef::F_MID_TEX, new_tex); } } } } UpdateField(); UpdateSides(); redraw(); } bool UI_LineBox::ClipboardOp(EditCommand op) { if (obj < 0) return false; int parts = front->GetSelectedPics() | (back->GetSelectedPics() << 4); if (parts == 0) parts = front->GetHighlightedPics() | (back->GetHighlightedPics() << 4); if (parts == 0) return false; switch (op) { case EditCommand::copy: CB_Copy(parts); break; case EditCommand::paste: CB_Paste(parts, Texboard_GetTexNum(inst.conf)); break; case EditCommand::cut: // Cut CB_Paste(parts, BA_InternaliseString(inst.conf.default_wall_tex)); break; case EditCommand::del: // Delete CB_Paste(parts, BA_InternaliseString("-")); break; } return true; } void UI_LineBox::BrowsedItem(BrowserMode kind, int number, const char *name, int e_state) { if (kind == BrowserMode::textures || kind == BrowserMode::flats) { int front_pics = front->GetSelectedPics(); int back_pics = back->GetSelectedPics(); // this can be zero, invoking special behavior (based on mouse button) int parts = front_pics | (back_pics << 4); SetTexture(name, e_state, parts); } else if (kind == BrowserMode::lineTypes) { SetLineType(number); } } void UI_LineBox::tag_callback(Fl_Widget *w, void *data) { UI_LineBox *box = (UI_LineBox *)data; int new_tag = atoi(box->tag->value()); if (! box->inst.edit.Selected->empty()) box->inst.level.checks.tagsApplyNewValue(new_tag); } void UI_LineBox::flags_callback(Fl_Widget *w, void *data) { line_flag_CB_data_c *l_f_c = (line_flag_CB_data_c *)data; UI_LineBox *box = l_f_c->parent; int mask = l_f_c->mask; int new_flags = box->CalcFlags(); if (! box->inst.edit.Selected->empty()) { box->mFixUp.checkDirtyFields(); box->checkSidesDirtyFields(); EditOperation op(box->inst.level.basis); op.setMessageForSelection("edited flags of", *box->inst.edit.Selected); for (sel_iter_c it(*box->inst.edit.Selected); !it.done(); it.next()) { const auto L = box->inst.level.linedefs[*it]; // only change the bits specified in 'mask'. // this is important when multiple linedefs are selected. op.changeLinedef(*it, LineDef::F_FLAGS, (L->flags & ~mask) | (new_flags & mask)); } } } void UI_LineBox::args_callback(Fl_Widget *w, void *data) { line_flag_CB_data_c *l_f_c = (line_flag_CB_data_c *)data; UI_LineBox *box = l_f_c->parent; int arg_idx = l_f_c->mask; int new_value = atoi(box->args[arg_idx]->value()); new_value = clamp(0, new_value, 255); if (! box->inst.edit.Selected->empty()) { EditOperation op(box->inst.level.basis); op.setMessageForSelection("edited args of", *box->inst.edit.Selected); for (sel_iter_c it(*box->inst.edit.Selected); !it.done(); it.next()) { op.changeLinedef(*it, static_cast(LineDef::F_TAG + arg_idx), new_value); } } } void UI_LineBox::length_callback(Fl_Widget *w, void *data) { UI_LineBox *box = (UI_LineBox *)data; int new_len = atoi(box->length->value()); // negative values are allowed, it moves the start vertex new_len = clamp(-32768, new_len, 32768); box->inst.level.linemod.setLinedefsLength(new_len); } void UI_LineBox::button_callback(Fl_Widget *w, void *data) { UI_LineBox *box = (UI_LineBox *)data; if (w == box->choose) { box->inst.main_win->BrowserMode(BrowserMode::lineTypes); return; } if (w == box->gen) { box->inst.main_win->BrowserMode(BrowserMode::generalized); return; } } //------------------------------------------------------------------------ void UI_LineBox::UpdateField(int field) { if (field < 0 || field == LineDef::F_START || field == LineDef::F_END) { if(inst.level.isLinedef(obj)) CalcLength(); else mFixUp.setInputValue(length, ""); } if (field < 0 || (field >= LineDef::F_TAG && field <= LineDef::F_ARG5)) { for (int a = 0 ; a < 5 ; a++) { mFixUp.setInputValue(args[a], ""); args[a]->tooltip(NULL); args[a]->textcolor(FL_BLACK); } if (inst.level.isLinedef(obj)) { const auto L = inst.level.linedefs[obj]; mFixUp.setInputValue(tag, SString(inst.level.linedefs[obj]->tag).c_str()); const linetype_t &info = inst.conf.getLineType(L->type); if (inst.loaded.levelFormat != MapFormat::doom) { for (int a = 0 ; a < 5 ; a++) { int arg_val = L->Arg(1 + a); if(arg_val || L->type) mFixUp.setInputValue(args[a], SString(arg_val).c_str()); // set the tooltip if (!info.args[a].name.empty()) args[a]->copy_tooltip(info.args[a].name.c_str()); else args[a]->textcolor(fl_rgb_color(160,160,160)); } } } else { mFixUp.setInputValue(length, ""); mFixUp.setInputValue(tag, ""); } } if (field < 0 || field == LineDef::F_RIGHT || field == LineDef::F_LEFT) { if (inst.level.isLinedef(obj)) { const auto L = inst.level.linedefs[obj]; int right_mask = SolidMask(L.get(), Side::right); int left_mask = SolidMask(L.get(), Side::left); front->SetObj(L->right, right_mask, L->TwoSided()); back->SetObj(L->left, left_mask, L->TwoSided()); } else { front->SetObj(SETOBJ_NO_LINE, 0, false); back->SetObj(SETOBJ_NO_LINE, 0, false); } } if (field < 0 || field == LineDef::F_TYPE) { if (inst.level.isLinedef(obj)) { int type_num = inst.level.linedefs[obj]->type; mFixUp.setInputValue(type, SString(type_num).c_str()); const char *gen_desc = GeneralizedDesc(type_num); if (gen_desc) { desc->value(gen_desc); } else { const linetype_t &info = inst.conf.getLineType(type_num); desc->value(info.desc.c_str()); } inst.main_win->browser->UpdateGenType(type_num); } else { mFixUp.setInputValue(type, ""); desc->value(""); choose->label("Choose"); inst.main_win->browser->UpdateGenType(0); } } if (field < 0 || field == LineDef::F_FLAGS) { if (inst.level.isLinedef(obj)) { actkind->activate(); FlagsFromInt(inst.level.linedefs[obj]->flags); } else { FlagsFromInt(0); actkind->value(12); // show as "??" actkind->deactivate(); } } } void UI_LineBox::UpdateSides() { front->UpdateField(); back->UpdateField(); } void UI_LineBox::UnselectPics() { front->UnselectPics(); back->UnselectPics(); } void UI_LineBox::CalcLength() { // ASSERT(obj >= 0); int n = obj; float len_f = static_cast(inst.level.calcLength(*inst.level.linedefs[n])); char buffer[128]; snprintf(buffer, sizeof(buffer), "%1.0f", len_f); mFixUp.setInputValue(length, buffer); } void UI_LineBox::FlagsFromInt(int lineflags) { // compute activation if (inst.loaded.levelFormat != MapFormat::doom) { int new_act = (lineflags & MLF_Activation) >> 9; new_act |= (lineflags & MLF_Repeatable) ? 1 : 0; // show "??" for unknown values if (new_act > 12) new_act = 12; actkind->value(new_act); } if (lineflags & MLF_Secret) f_automap->value(3); else if (lineflags & MLF_DontDraw) f_automap->value(1); else if (lineflags & MLF_Mapped) f_automap->value(2); else f_automap->value(0); f_upper ->value((lineflags & MLF_UpperUnpegged) ? 1 : 0); f_lower ->value((lineflags & MLF_LowerUnpegged) ? 1 : 0); f_passthru->value((lineflags & MLF_Boom_PassThru) ? 1 : 0); f_3dmidtex->value((lineflags & MLF_Eternity_3DMidTex) ? 1 : 0); f_jumpover->value((lineflags & MLF_Strife_JumpOver) ? 1 : 0); f_trans1 ->value((lineflags & MLF_Strife_Translucent1) ? 1 : 0); f_trans2 ->value((lineflags & MLF_Strife_Translucent2) ? 1 : 0); f_walk ->value((lineflags & MLF_Blocking) ? 1 : 0); f_mons ->value((lineflags & MLF_BlockMonsters) ? 1 : 0); f_sound ->value((lineflags & MLF_SoundBlock) ? 1 : 0); f_flyers->value((lineflags & MLF_Strife_BlockFloaters) ? 1 : 0); } int UI_LineBox::CalcFlags() const { int lineflags = 0; switch (f_automap->value()) { case 0: /* Normal */; break; case 1: /* Invisible */ lineflags |= MLF_DontDraw; break; case 2: /* Mapped */ lineflags |= MLF_Mapped; break; case 3: /* Secret */ lineflags |= MLF_Secret; break; } if (f_upper->value()) lineflags |= MLF_UpperUnpegged; if (f_lower->value()) lineflags |= MLF_LowerUnpegged; if (f_walk->value()) lineflags |= MLF_Blocking; if (f_mons->value()) lineflags |= MLF_BlockMonsters; if (f_sound->value()) lineflags |= MLF_SoundBlock; if (inst.loaded.levelFormat != MapFormat::doom) { int actval = actkind->value(); if (actval >= 12) actval = 0; lineflags |= (actval << 9); } else { if (inst.conf.features.pass_through && f_passthru->value()) lineflags |= MLF_Boom_PassThru; if (inst.conf.features.midtex_3d && f_3dmidtex->value()) lineflags |= MLF_Eternity_3DMidTex; if (inst.conf.features.strife_flags) { if (f_jumpover->value()) lineflags |= MLF_Strife_JumpOver; if (f_flyers->value()) lineflags |= MLF_Strife_BlockFloaters; if (f_trans1->value()) lineflags |= MLF_Strife_Translucent1; if (f_trans2->value()) lineflags |= MLF_Strife_Translucent2; } } return lineflags; } void UI_LineBox::UpdateTotal(const Document &doc) noexcept { which->SetTotal(doc.numLinedefs()); } int UI_LineBox::SolidMask(const LineDef *L, Side side) const { SYS_ASSERT(L); if (L->left < 0 && L->right < 0) return 0; if (L->left < 0 || L->right < 0) return SOLID_MID; const Sector *right = &inst.level.getSector(*inst.level.getRight(*L)); const Sector * left = &inst.level.getSector(*inst.level.getLeft(*L)); if (side == Side::left) std::swap(left, right); int mask = 0; if (right->floorh < left->floorh) mask |= SOLID_LOWER; // upper texture of "-" is OK between two skies bool two_skies = inst.is_sky(right->CeilTex()) && inst.is_sky(left->CeilTex()); if (right-> ceilh > left-> ceilh && !two_skies) mask |= SOLID_UPPER; return mask; } void UI_LineBox::UpdateGameInfo(const LoadingData &loaded, const ConfigData &config) { choose->label("Choose"); if (loaded.levelFormat != MapFormat::doom) { tag->hide(); length->hide(); gen->hide(); actkind->show(); desc->resize(type->x() + 65, desc->y(), w()-78-65, desc->h()); f_passthru->hide(); f_3dmidtex->hide(); } else { tag->show(); length->show(); actkind->hide(); desc->resize(type->x(), desc->y(), w()-78, desc->h()); if (config.features.pass_through) f_passthru->show(); else f_passthru->hide(); if (config.features.midtex_3d) f_3dmidtex->show(); else f_3dmidtex->hide(); if (config.features.strife_flags) { f_jumpover->show(); f_flyers->show(); f_trans1->show(); f_trans2->show(); } else { f_jumpover->hide(); f_flyers->hide(); f_trans1->hide(); f_trans2->hide(); } if (config.features.gen_types) gen->show(); else gen->hide(); } for (int a = 0 ; a < 5 ; a++) { if (loaded.levelFormat != MapFormat::doom) args[a]->show(); else args[a]->hide(); } redraw(); } const char * UI_LineBox::GeneralizedDesc(int type_num) { if (! inst.conf.features.gen_types) return NULL; static char desc_buffer[256]; for (int i = 0 ; i < inst.conf.num_gen_linetypes ; i++) { const generalized_linetype_t *info = &inst.conf.gen_linetypes[i]; if (type_num >= info->base && type_num < (info->base + info->length)) { // grab trigger name (we assume it is first field) if (info->fields.size() < 1 || info->fields[0].keywords.size() < 8) return NULL; const char *trigger = info->fields[0].keywords[type_num & 7].c_str(); snprintf(desc_buffer, sizeof(desc_buffer), "%s GENTYPE: %s", trigger, info->name.c_str()); return desc_buffer; } } return NULL; // not a generalized linetype } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_linedef.h000066400000000000000000000063451464327712600206140ustar00rootroot00000000000000//------------------------------------------------------------------------ // LINEDEF PANEL //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2018 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_LINEDEF_H__ #define __EUREKA_UI_LINEDEF_H__ #include "e_cutpaste.h" #include "ui_panelinput.h" class UI_DynIntInput; struct LoadingData; class UI_LineBox : public MapItemBox { private: UI_DynInput *type; Fl_Button *choose; Fl_Button *gen; Fl_Output *desc; Fl_Choice *actkind; UI_DynIntInput *length; UI_DynIntInput *tag; UI_DynIntInput *args[5]; UI_SideBox *front; UI_SideBox *back; // Flags Fl_Choice *f_automap; Fl_Check_Button *f_upper; Fl_Check_Button *f_lower; Fl_Check_Button *f_passthru; Fl_Check_Button *f_3dmidtex; // Eternity Fl_Check_Button *f_jumpover; // Fl_Check_Button *f_trans1; // Strife Fl_Check_Button *f_trans2; // Fl_Check_Button *f_walk; Fl_Check_Button *f_mons; Fl_Check_Button *f_sound; Fl_Check_Button *f_flyers; // Strife public: UI_LineBox(Instance &inst, int X, int Y, int W, int H, const char *label = nullptr); // call this if the linedef was externally changed. // -1 means "all fields" void UpdateField(int field = -1) override; // call this is the linedef's sides were externally modified. void UpdateSides(); void UpdateTotal(const Document &doc) noexcept override; // see ui_window.h for description of these two methods bool ClipboardOp(EditCommand op); void BrowsedItem(BrowserMode kind, int number, const char *name, int e_state); void UnselectPics() override; void UpdateGameInfo(const LoadingData &loaded, const ConfigData &config) override; void checkDirtyFields() { mFixUp.checkDirtyFields(); } private: void CalcLength(); int CalcFlags() const; void FlagsFromInt(int flags); void CB_Copy(int parts); void CB_Paste(int parts, StringID new_tex); void SetTexture(const char *tex_name, int e_state, int parts); void SetTexOnLine(EditOperation &op, int ld, StringID new_tex, int e_state, int parts); void SetLineType(int new_type); int SolidMask(const LineDef *L, Side side) const; void checkSidesDirtyFields(); const char *GeneralizedDesc(int type_num); static void type_callback(Fl_Widget *, void *); static void dyntype_callback(Fl_Widget *, void *); static void tag_callback(Fl_Widget *, void *); static void flags_callback(Fl_Widget *, void *); static void args_callback(Fl_Widget *, void *); static void length_callback(Fl_Widget *, void *); static void button_callback(Fl_Widget *, void *); }; #endif /* __EUREKA_UI_LINEDEF_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_menu.cc000066400000000000000000000673371464327712600203200ustar00rootroot00000000000000//------------------------------------------------------------------------ // MENUS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2018 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include "ui_window.h" #include "e_main.h" #include "m_files.h" #include "m_loadsave.h" //------------------------------------------------------------------------ // FILE MENU //------------------------------------------------------------------------ // TODO: detect the right instance static void file_do_new_project(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("NewProject"); } static void file_do_manage_project(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("ManageProject"); } static void file_do_open(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("OpenMap"); } static void file_do_save(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("SaveMap"); } static void file_do_export(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("ExportMap"); } static void file_do_fresh_map(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("FreshMap"); } static void file_do_copy_map(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("CopyMap"); } static void file_do_rename(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("RenameMap"); } static void file_do_delete(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("DeleteMap"); } static void file_do_load_given(Fl_Widget *w, void *data) { auto filename = static_cast(data); assert(filename); int given_idx = M_FindGivenFile(*filename); // TODO: think up the right instance to get this if (given_idx >= 0) gInstance->last_given_file = given_idx; try { OpenFileMap(*filename); } catch (const std::runtime_error& e) { gLog.printf("%s\n", e.what()); DLG_ShowError(false, "Cannot load %s: %s", filename->u8string().c_str(), e.what()); } } static void file_do_load_recent(Fl_Widget *w, void *data) { M_OpenRecentFromMenu(data); } static void file_do_quit(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("Quit"); } //------------------------------------------------------------------------ // EDIT MENU //------------------------------------------------------------------------ static void edit_do_undo(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("Undo"); } static void edit_do_redo(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("Redo"); } static void edit_do_cut(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("Clipboard_Cut"); } static void edit_do_copy(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("Clipboard_Copy"); } static void edit_do_paste(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("Clipboard_Paste"); } static void edit_do_delete(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("Delete"); } static void edit_do_select_all(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("SelectAll"); } static void edit_do_unselect_all(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("UnselectAll"); } static void edit_do_invert_sel(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("InvertSelection"); } static void edit_do_last_sel(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("LastSelection"); } static void edit_do_op_menu(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("OpMenu"); } static void edit_do_move(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("MoveObjectsDialog"); } static void edit_do_scale(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("ScaleObjectsDialog"); } static void edit_do_rotate(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("RotateObjectsDialog"); } static void edit_do_mirror_horiz(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("Mirror", "horiz"); } static void edit_do_mirror_vert(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("Mirror", "vert"); } //------------------------------------------------------------------------ // VIEW MENU //------------------------------------------------------------------------ static void view_do_zoom_in(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("Zoom", "+1", "/center"); } static void view_do_zoom_out(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("Zoom", "-1", "/center"); } static void view_do_whole_map(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("ZoomWholeMap"); } static void view_do_whole_selection(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("ZoomSelection"); } static void view_do_camera_pos(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("GoToCamera"); } static void view_do_toggle_3d(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("Toggle", "3d"); } static void view_do_object_nums(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("Toggle", "obj_nums"); } static void view_do_sprites(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("Toggle", "sprites"); } static void view_do_gamma(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("Toggle", "gamma"); } static void view_do_default_props(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("DefaultProps"); } static void view_do_find(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("FindDialog"); } static void view_do_next(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("FindNext"); } static void view_do_jump(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("JumpToObject"); } //------------------------------------------------------------------------ // BROWSER MENU //------------------------------------------------------------------------ static void browser_do_textures(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("BrowserMode", "T"); } static void browser_do_flats(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("BrowserMode", "F"); } static void browser_do_things(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("BrowserMode", "O"); } static void browser_do_lines(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("BrowserMode", "L"); } static void browser_do_sectors(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("BrowserMode", "S"); } static void browser_do_gen_types(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("BrowserMode", "G"); } static void browser_do_recent_tex(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("BrowserMode", "T", "/recent"); } static void browser_do_recent_flats(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("BrowserMode", "F", "/recent"); } static void browser_do_recent_things(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("BrowserMode", "O", "/recent"); } static void browser_hide(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("Set", "browser", "0"); } //------------------------------------------------------------------------ // CHECK MENU //------------------------------------------------------------------------ static void checks_do_all(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("MapCheck", "all"); } static void checks_do_major(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("MapCheck", "major"); } static void checks_do_vertices(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("MapCheck", "vertices"); } static void checks_do_sectors(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("MapCheck", "sectors"); } static void checks_do_linedefs(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("MapCheck", "linedefs"); } static void checks_do_things(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("MapCheck", "things"); } static void checks_do_textures(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("MapCheck", "textures"); } static void checks_do_tags(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("MapCheck", "tags"); } //------------------------------------------------------------------------ // TOOLS MENU //------------------------------------------------------------------------ static void tools_do_preferences(Fl_Widget *w, void * data) { // FIXME: this uses the global instance because it's also used globally on Mac gInstance->ExecuteCommand("PreferenceDialog"); } static void tools_do_build_nodes(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("BuildAllNodes"); } static void tools_do_test_map(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("TestMap"); } static void tools_do_change_test_settings(Fl_Widget* w, void* data) { static_cast(data)->ExecuteCommand("ChangeTestSettings"); } static void tools_do_lump_editor(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("EditLump"); } static void tools_do_add_behavior(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("AddBehavior"); } static void tools_do_view_logs(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("LogViewer"); } static void tools_do_recalc_sectors(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("RecalcSectors"); } //------------------------------------------------------------------------ // HELP MENU //------------------------------------------------------------------------ static void help_do_online_docs(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("OnlineDocs"); } static void help_do_about(Fl_Widget *w, void * data) { static_cast(data)->ExecuteCommand("AboutDialog"); } //------------------------------------------------------------------------ // Bindings from commands to function names //------------------------------------------------------------------------ struct MenuCommand { const char *const command; const char * param[MAX_EXEC_PARAM]; // can't put const because of errors elsewhere }; static std::unordered_map s_menu_command_map = { {file_do_new_project, {"NewProject"} }, {file_do_manage_project, {"ManageProject"} }, {file_do_open, {"OpenMap"} }, {file_do_save, {"SaveMap"} }, {file_do_export, {"ExportMap"} }, {file_do_fresh_map, {"FreshMap"} }, {file_do_copy_map, {"CopyMap"} }, {file_do_rename, {"RenameMap"} }, {file_do_delete, {"DeleteMap"} }, // given and recent don't have direct commands {file_do_quit, {"Quit"} }, {edit_do_undo, {"Undo"} }, {edit_do_redo, {"Redo"} }, {edit_do_cut, {"Clipboard_Cut"} }, {edit_do_copy, {"Clipboard_Copy"} }, {edit_do_paste, {"Clipboard_Paste"} }, {edit_do_delete, {"Delete"} }, {edit_do_select_all, {"SelectAll"} }, {edit_do_unselect_all, {"UnselectAll"} }, {edit_do_invert_sel, {"InvertSelection"} }, {edit_do_last_sel, {"LastSelection"} }, {edit_do_op_menu, {"OpMenu"} }, {edit_do_move, {"MoveObjectsDialog"} }, {edit_do_scale, {"ScaleObjectsDialog"} }, {edit_do_rotate, {"RotateObjectsDialog"} }, {edit_do_mirror_horiz, {"Mirror", {"horiz"}} }, {edit_do_mirror_vert, {"Mirror", {"vert"}} }, {view_do_zoom_in, {"Zoom", {"+1", "/center"}} }, {view_do_zoom_out, {"Zoom", {"-1", "/center"}} }, {view_do_whole_map, {"ZoomWholeMap"} }, {view_do_whole_selection, {"ZoomSelection"} }, {view_do_camera_pos, {"GoToCamera"} }, {view_do_toggle_3d, {"Toggle", {"3d"}} }, {view_do_object_nums, {"Toggle", {"obj_nums"}} }, {view_do_sprites, {"Toggle", {"sprites"}} }, {view_do_gamma, {"Toggle", {"gamma"}} }, {view_do_default_props, {"DefaultProps"} }, {view_do_find, {"FindDialog"} }, {view_do_next, {"FindNext"} }, {view_do_jump, {"JumpToObject"} }, {browser_do_textures, {"BrowserMode", {"T"}} }, {browser_do_flats, {"BrowserMode", {"F"}} }, {browser_do_things, {"BrowserMode", {"O"}} }, {browser_do_lines, {"BrowserMode", {"L"}} }, {browser_do_sectors, {"BrowserMode", {"S"}} }, {browser_do_gen_types, {"BrowserMode", {"G"}}, }, {browser_do_recent_tex, {"BrowserMode", {"T", "/recent"}} }, {browser_do_recent_flats, {"BrowserMode", {"F", "/recent"}} }, {browser_do_recent_things, {"BrowserMode", {"O", "/recent"}} }, {browser_hide, {"Set", {"browser", "0"}} }, {checks_do_all, {"MapCheck", {"all"}} }, {checks_do_major, {"MapCheck", {"major"}} }, {checks_do_vertices, {"MapCheck", {"vertices"}} }, {checks_do_sectors, {"MapCheck", {"sectors"}} }, {checks_do_linedefs, {"MapCheck", {"linedefs"}} }, {checks_do_things, {"MapCheck", {"things"}} }, {checks_do_textures, {"MapCheck", {"textures"}} }, {checks_do_tags, {"MapCheck", {"tags"}} }, {tools_do_preferences, {"PreferenceDialog"} }, {tools_do_build_nodes, {"BuildAllNodes"} }, {tools_do_test_map, {"TestMap"} }, {tools_do_change_test_settings, {"ChangeTestSettings"}}, {tools_do_lump_editor, {"EditLump"} }, {tools_do_add_behavior, {"AddBehavior"} }, {tools_do_view_logs, {"LogViewer"} }, {tools_do_recalc_sectors, {"RecalcSectors"} }, {help_do_online_docs, {"OnlineDocs"} }, {help_do_about, {"AboutDialog"} } }; #define M_GIVEN_FILES "&Given Files" #define M_RECENT_FILES "&Recent Files" #undef FCAL #define FCAL (Fl_Callback *) // Note that the spaces at end of some menu strings are there to // prevent FLTK drawing the key binding hard against the item's // text. static Fl_Menu_Item menu_items[] = { { "&File", 0, 0, 0, FL_SUBMENU }, { "&New Project ", FL_COMMAND + 'n', FCAL file_do_new_project }, { "&Manage Project ", FL_COMMAND + 'm', FCAL file_do_manage_project }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Open Map", FL_COMMAND + 'o', FCAL file_do_open }, { M_GIVEN_FILES, 0, 0, 0, FL_SUBMENU|FL_MENU_INACTIVE }, { 0 }, { M_RECENT_FILES, 0, 0, 0, FL_SUBMENU|FL_MENU_INACTIVE }, { 0 }, { "&Save Map", FL_COMMAND + 's', FCAL file_do_save }, { "&Export Map", FL_COMMAND + 'e', FCAL file_do_export }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Fresh Map", 0, FCAL file_do_fresh_map }, { "&Copy Map", 0, FCAL file_do_copy_map }, { "Rename Map", 0, FCAL file_do_rename }, { "Delete Map", 0, FCAL file_do_delete }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Quit", FL_COMMAND + 'q', FCAL file_do_quit }, { 0 }, { "&Edit", 0, 0, 0, FL_SUBMENU }, { "&Undo", FL_COMMAND + 'z', FCAL edit_do_undo }, { "&Redo", FL_COMMAND + 'y', FCAL edit_do_redo }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "Cu&t", FL_COMMAND + 'x', FCAL edit_do_cut }, { "&Copy", FL_COMMAND + 'c', FCAL edit_do_copy }, { "&Paste", FL_COMMAND + 'v', FCAL edit_do_paste }, { "&Delete", FL_Delete, FCAL edit_do_delete }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "Select &All", FL_COMMAND + 'a', FCAL edit_do_select_all }, { "Unselect All", FL_COMMAND + 'u', FCAL edit_do_unselect_all }, { "&Invert Selection", FL_COMMAND + 'i', FCAL edit_do_invert_sel }, { "&Last Selection", FL_COMMAND + 'l', FCAL edit_do_last_sel }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Operation Menu", FL_F+1, FCAL edit_do_op_menu }, { "&Move Objects...", FL_F+2, FCAL edit_do_move }, { "&Scale Objects...", FL_F+3, FCAL edit_do_scale }, { "Rotate Objects...", FL_F+4, FCAL edit_do_rotate }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "Mirror &Horizontally", 0, FCAL edit_do_mirror_horiz }, { "Mirror &Vertically", 0, FCAL edit_do_mirror_vert }, { 0 }, { "&View", 0, 0, 0, FL_SUBMENU }, // Note: FL_Tab cannot be used as a shortcut here, as it // invokes FLTK's hard-coded navigation stuff. { "Toggle S&prites", FL_F+10, FCAL view_do_sprites }, { "Toggle &Gamma", FL_F+11, FCAL view_do_gamma }, { "Toggle Object Nums", FL_F+12, FCAL view_do_object_nums }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "Zoom &In", 0, FCAL view_do_zoom_in }, { "Zoom &Out", 0, FCAL view_do_zoom_out }, { "&Whole Map", 0, FCAL view_do_whole_map }, { "Whole &Selection", 0, FCAL view_do_whole_selection }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Default Props ", FL_COMMAND + 'd', FCAL view_do_default_props }, { "Toggle &3D View", 0, FCAL view_do_toggle_3d }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Find / Replace", FL_COMMAND + 'f', FCAL view_do_find }, { "Find &Next", FL_COMMAND + 'g', FCAL view_do_next }, { "Go to &Camera", 0, FCAL view_do_camera_pos }, { "&Jump to Objects", 0, FCAL view_do_jump }, { 0 }, { "&Browser", 0, 0, 0, FL_SUBMENU }, { "&Textures", FL_F+5, FCAL browser_do_textures }, { "&Flats", FL_F+6, FCAL browser_do_flats }, { "Thin&gs", FL_F+7, FCAL browser_do_things }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Line Specials", 0, FCAL browser_do_lines }, { "&Sector Types", 0, FCAL browser_do_sectors }, { "&Generalized Types", 0, FCAL browser_do_gen_types }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Recent Textures", 0, FCAL browser_do_recent_tex }, { "Recent Flats", 0, FCAL browser_do_recent_flats }, { "Recent Things", 0, FCAL browser_do_recent_things }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Hide", 0, FCAL browser_hide }, { 0 }, { "&Check", 0, 0, 0, FL_SUBMENU }, { "&ALL", FL_F+9, FCAL checks_do_all }, { "&Major stuff ", 0, FCAL checks_do_major }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Vertices", 0, FCAL checks_do_vertices }, { "&Sectors", 0, FCAL checks_do_sectors }, { "&LineDefs", 0, FCAL checks_do_linedefs }, { "&Things", 0, FCAL checks_do_things }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "Te&xtures", 0, FCAL checks_do_textures }, { "Ta&gs", 0, FCAL checks_do_tags }, { 0 }, { "&Tools", 0, 0, 0, FL_SUBMENU }, #ifndef __APPLE__ // for macOS it will be in the app menu { "&Preferences", FL_COMMAND + 'p', FCAL tools_do_preferences }, #endif { "&View Logs", 0, FCAL tools_do_view_logs }, { "&Recalc Sectors", 0, FCAL tools_do_recalc_sectors }, { "", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE }, { "&Test in Game", FL_COMMAND + 't', FCAL tools_do_test_map }, { "&Change Test Settings...", 0, FCAL tools_do_change_test_settings }, { "", 0, 0, 0, FL_MENU_DIVIDER | FL_MENU_INACTIVE }, { "&Build All Nodes ", FL_COMMAND + 'b', FCAL tools_do_build_nodes }, { "&Edit Text Lump ", 0, FCAL tools_do_lump_editor }, { "&Add BEHAVIOR Lump ", 0, FCAL tools_do_add_behavior }, { 0 }, { "&Help", 0, 0, 0, FL_SUBMENU }, { "&Online Docs...", 0, FCAL help_do_online_docs }, { "&About Eureka...", 0, FCAL help_do_about }, { 0 }, { 0 } }; //------------------------------------------------------------------------ #define MAX_PWAD_LIST 20 // // allow the hard-coded menu shortcuts to be bind to other functions // by the user, hence we remove those shortcuts when this happens. // static void Menu_RemovedBoundKeys(Fl_Menu_Item *items) { int total = items[0].size(); // includes {0} at end for (int i = 0 ; i < total ; i++) { if (! items[i].text) continue; int shortcut = items[i].shortcut_; if (! shortcut) continue; // convert to a Eureka key code keycode_t key = shortcut & FL_KEY_MASK; if (shortcut & FL_COMMAND) key |= EMOD_COMMAND; else if (shortcut & FL_META) key |= EMOD_META; else if (shortcut & FL_ALT) key |= EMOD_ALT; if (M_IsKeyBound(key, KeyContext::general)) items[i].shortcut_ = 0; } } // // remove the blank menu items with FL_MENU_DIVIDER flag, and // setting the flag on the previous item. those blank lines // make for nicer looking menus in Windows/Linux, but are not // needed for the MacOS system menu bar. // #ifdef __APPLE__ static void Menu_PackForMac(Fl_Menu_Item *src) { int depth = 0; Fl_Menu_Item *dest = src; for (;;) { if (src->text == NULL) { *dest++ = *src++; if (depth == 0) break; depth--; continue; } if (src->flags & FL_SUBMENU) { *dest++ = *src++; depth++; continue; } if (src->text[0] == 0 && (src->flags & FL_MENU_DIVIDER)) { dest[-1].flags |= FL_MENU_DIVIDER; src++; continue; } *dest++ = *src++; } } #endif static int Menu_FindItem(const Fl_Menu_Item *items, const char *text) { int total = items[0].size(); // includes {0} at end for (int i = 0 ; i < total ; i++) if (items[i].text && y_stricmp(items[i].text, text) == 0) return i; return -1; // not found } static void Menu_CopyItem(Fl_Menu_Item* &pos, const Fl_Menu_Item &orig) { memcpy(pos, &orig, sizeof(orig)); pos++; } static void Menu_AddItem(Fl_Menu_Item* &pos, const char *text, Fl_Callback *cb, void *data, int flags) { Fl_Menu_Item item; memset(&item, 0, sizeof(item)); item.text = StringDup(text); item.flags = flags; item.callback_ = cb; item.user_data_ = data; Menu_CopyItem(pos, item); } static Fl_Menu_Item * Menu_PopulateGivenFiles(Fl_Menu_Item *items) { int count = (int)global::Pwad_list.size(); if (count < 2) return items; // silently ignore excess pwads if (count > MAX_PWAD_LIST) count = MAX_PWAD_LIST; // find Given Files sub-menu and activate it int menu_pos = Menu_FindItem(items, M_GIVEN_FILES); if (menu_pos < 0) // [should not happen] return items; items[menu_pos++].activate(); // create new array int total = items[0].size(); // includes {0} at end Fl_Menu_Item * new_array = new Fl_Menu_Item[total + count]; Fl_Menu_Item * pos = new_array; for (int i = 0 ; i < menu_pos ; i++) Menu_CopyItem(pos, items[i]); for (int k = 0 ; k < count ; k++) { SString short_name = fl_filename_name(global::Pwad_list[k].u8string().c_str()); short_name = SString::printf("%s%s%d: %s", (k < 9) ? " " : "", (k < 9) ? "&" : "", 1+k, short_name.c_str()); Menu_AddItem(pos, short_name.c_str(), FCAL file_do_load_given, &global::Pwad_list[k], 0); } for ( ; menu_pos < total ; menu_pos++) Menu_CopyItem(pos, items[menu_pos]); return new_array; } static Fl_Menu_Item * Menu_PopulateRecentFiles(Fl_Menu_Item *items, Fl_Callback *cb) { int count = global::recent.getFiles().getSize(); if (count < 1) return items; // find Recent Files sub-menu and activate it int menu_pos = Menu_FindItem(items, M_RECENT_FILES); if (menu_pos < 0) // [should not happen] return items; items[menu_pos++].activate(); // create new array int total = items[0].size(); // includes {0} at end Fl_Menu_Item * new_array = new Fl_Menu_Item[total + count]; Fl_Menu_Item * pos = new_array; for (int i = 0 ; i < menu_pos ; i++) Menu_CopyItem(pos, items[i]); for (int k = 0 ; k < count ; k++) { SString name = global::recent.getFiles().Format(k); auto data = new RecentMap(global::recent.getFiles().Lookup(k)); Menu_AddItem(pos, name.c_str(), cb, data, 0); } for ( ; menu_pos < total ; menu_pos++) Menu_CopyItem(pos, items[menu_pos]); return new_array; } namespace menu { static int locateMenuItem(const Fl_Sys_Menu_Bar &bar, Fl_Callback_p callback) { int menuSize = bar.size(); const Fl_Menu_Item *items = bar.menu(); for(int i = 0; i < menuSize; ++i) { const Fl_Menu_Item &item = items[i]; if(item.callback() == callback) return i; } return -1; } void setTestMapDetail(Fl_Sys_Menu_Bar *bar, const SString &text) { if(!bar) return; int index = locateMenuItem(*bar, tools_do_test_map); if(index < 0) return; static std::unordered_map testMapDetailStorage; if(text.good()) testMapDetailStorage[bar] = SString::printf("&Test in Game (%s)", text.c_str()); else testMapDetailStorage[bar] = "&Test in Game"; bar->replace(index, testMapDetailStorage[bar].c_str()); } void setUndoDetail(Fl_Sys_Menu_Bar *bar, const SString &verb) { if(!bar) return; int index = locateMenuItem(*bar, edit_do_undo); if(index < 0) return; static std::unordered_map undoDetailStorage; if(verb.good()) undoDetailStorage[bar] = SString("&Undo ") + verb; else undoDetailStorage[bar] = "&Undo"; bar->replace(index, undoDetailStorage[bar].c_str()); } void setRedoDetail(Fl_Sys_Menu_Bar *bar, const SString &verb) { if(!bar) return; int index = locateMenuItem(*bar, edit_do_redo); if(index < 0) return; static std::unordered_map redoDetailStorage; if(verb.good()) redoDetailStorage[bar] = SString("&Redo ") + verb; else redoDetailStorage[bar] = "&Redo"; bar->replace(index, redoDetailStorage[bar].c_str()); } Fl_Sys_Menu_Bar *create(int x, int y, int w, int h, void *userData) { Fl_Sys_Menu_Bar *bar = new Fl_Sys_Menu_Bar(x, y, w, h); Fl_Menu_Item* items; // TODO: make this an instance vector items = new Fl_Menu_Item[sizeof(menu_items) / sizeof(menu_items[0])]; memcpy(items, menu_items, sizeof(menu_items)); #ifdef __APPLE__ Menu_PackForMac(items); #else bar->textsize(16); #endif Menu_RemovedBoundKeys(items); items = Menu_PopulateGivenFiles(items); items = Menu_PopulateRecentFiles(items, FCAL file_do_load_recent); SYS_ASSERT(items != menu_items); // by now we know we made one for ourselves int total = items[0].size(); for(int i = 0; i < total; ++i) if(items[i].text && items[i].callback_ && !items[i].user_data_) items[i].user_data_ = userData; bar->menu(items); // for macOS, the preferences shall be in the app menu #ifdef __APPLE__ static const Fl_Menu_Item macPreferencesItem[] = { { "&Preferences\u2026", FL_COMMAND + ',', FCAL tools_do_preferences }, {0} }; Fl_Mac_App_Menu::custom_application_menu_items(macPreferencesItem); #endif return bar; } // // Update all the menu shortcut displays after all_bindings got updated // void updateBindings(Fl_Sys_Menu_Bar *bar) { // If window not made yet, it will call this itself if(!bar) return; int menuSize = bar->size(); const Fl_Menu_Item *items = bar->menu(); for(int i = 0; i < menuSize; ++i) { auto it = s_menu_command_map.find(items[i].callback()); if(it == s_menu_command_map.end()) continue; MenuCommand &command = it->second; // can't put const because of error keycode_t code; if(!findKeyCodeForCommandName(command.command, command.param, &code)) continue; // Convert Eureka code to FLTK code if(code & EMOD_COMMAND) code = (code & ~EMOD_COMMAND) | FL_COMMAND; if(code & EMOD_META) code = (code & ~EMOD_META) | FL_META; if(code & EMOD_ALT) code = (code & ~EMOD_ALT) | FL_ALT; bar->shortcut(i, code); } } } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_menu.h000066400000000000000000000025221464327712600201430ustar00rootroot00000000000000//------------------------------------------------------------------------ // MENUS //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2009 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_MENU_H__ #define __EUREKA_UI_MENU_H__ #include "FL/Fl_Sys_Menu_Bar.H" class Fl_Menu_Bar; class SString; namespace menu { Fl_Sys_Menu_Bar *create(int x, int y, int w, int h, void *userData); void updateBindings(Fl_Sys_Menu_Bar *bar); void setTestMapDetail(Fl_Sys_Menu_Bar *bar, const SString &text); void setUndoDetail(Fl_Sys_Menu_Bar *bar, const SString &verb); void setRedoDetail(Fl_Sys_Menu_Bar *bar, const SString &verb); } #endif /* __EUREKA_UI_MENU_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_misc.cc000066400000000000000000000253371464327712600203010ustar00rootroot00000000000000//------------------------------------------------------------------------ // Miscellaneous UI Dialogs //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "ui_misc.h" #include "Errors.h" #include "Instance.h" #include "e_main.h" #include "m_vector.h" #include "main.h" #include UI_MoveDialog::UI_MoveDialog(Instance &inst, bool want_dz) : UI_Escapable_Window(360, 205, "Move Objects"), inst(inst) { Fl_Box *title = new Fl_Box(10, 11, w() - 20, 32, "Enter the offset to move objects:"); title->labelsize(16); title->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); delta_x = new Fl_Int_Input(95, 55, 65, 25, "delta x:"); delta_y = new Fl_Int_Input(95, 85, 65, 25, "delta y:"); delta_z = new Fl_Int_Input(240, 85, 65, 25, "delta z:"); delta_x->value("0"); delta_y->value("0"); delta_z->value("0"); if (! want_dz) delta_z->hide(); Fl_Group * grp = new Fl_Group(0, h() - 70, w(), 70); grp->box(FL_FLAT_BOX); grp->color(WINDOW_BG, WINDOW_BG); { cancel_but = new Fl_Button(30, grp->y() + 20, 95, 30, "Cancel"); cancel_but->callback(close_callback, this); ok_but = new Fl_Button(245, grp->y() + 20, 95, 30, "Move"); ok_but->labelfont(FL_HELVETICA_BOLD); ok_but->callback(ok_callback, this); grp->end(); } end(); resizable(NULL); callback(close_callback, this); } void UI_MoveDialog::Run() { set_modal(); show(); while (! want_close) { Fl::wait(0.2); } } void UI_MoveDialog::close_callback(Fl_Widget *w, void *data) { UI_MoveDialog * that = (UI_MoveDialog *)data; that->want_close = true; } void UI_MoveDialog::ok_callback(Fl_Widget *w, void *data) { UI_MoveDialog * that = (UI_MoveDialog *)data; int delta_x = atoi(that->delta_x->value()); int delta_y = atoi(that->delta_y->value()); int delta_z = atoi(that->delta_z->value()); that->inst.level.objects.move(*that->inst.edit.Selected, { delta_x, delta_y, delta_z }); that->want_close = true; } //------------------------------------------------------------------------ UI_ScaleDialog::UI_ScaleDialog(Instance &inst) : UI_Escapable_Window(360, 270, "Scale Objects"), inst(inst) { Fl_Box *title = new Fl_Box(10, 11, w() - 20, 32, "Enter the scale amount:"); title->labelsize(16); title->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); scale_x = new Fl_Input( 95, 55, 85, 25, "scale x:"); scale_y = new Fl_Input( 95, 85, 85, 25, "scale y:"); scale_z = new Fl_Input( 95, 115, 85, 25, "scale z:"); scale_x->value("1"); scale_y->value("1"); scale_z->value("1"); origin_x = new Fl_Choice(234, 55, 100, 25, "from:"); origin_y = new Fl_Choice(234, 85, 100, 25, "from:"); origin_z = new Fl_Choice(234, 115, 100, 25, "from:"); origin_x->add("Left|Centre|Right"); origin_x->value(1); origin_y->add("Bottom|Centre|Top"); origin_y->value(1); origin_z->add("Bottom|Middle|Top"); origin_z->value(0); Fl_Group * grp = new Fl_Group(0, 160, w(), h() - 160); grp->box(FL_FLAT_BOX); grp->color(WINDOW_BG, WINDOW_BG); { Fl_Box * help = new Fl_Box(10, 175, w() - 20, 40); help->label("Scale Values:\n" " can be real: 0.25 or 3.7\n" " or percentages: 25%\n" " or fractions: 3 / 4"); help->align(FL_ALIGN_LEFT | FL_ALIGN_TOP | FL_ALIGN_INSIDE); cancel_but = new Fl_Button(245, 180, 95, 30, "Cancel"); cancel_but->callback(close_callback, this); ok_but = new Fl_Button(245, 225, 95, 30, "Scale"); ok_but->labelfont(FL_HELVETICA_BOLD); ok_but->callback(ok_callback, this); grp->end(); } end(); resizable(NULL); callback(close_callback, this); } void UI_ScaleDialog::Run() { if (inst.edit.mode != ObjType::sectors) { scale_z->hide(); origin_z->hide(); } set_modal(); show(); while (! want_close) { Fl::wait(0.2); } } static double ParseScaleStr(const char * s) { // handle percentages if (strchr(s, '%')) { double val; if (sscanf(s, " %lf %% ", &val) != 1) return -1; return val / 100.0; } // handle fractions if (strchr(s, '/')) { double num, denom; if (sscanf(s, " %lf / %lf ", &num, &denom) != 2) return -1; if (denom <= 0) return -1; return num / denom; } return atof(s); } void UI_ScaleDialog::close_callback(Fl_Widget *w, void *data) { UI_ScaleDialog * that = (UI_ScaleDialog *)data; that->want_close = true; } void UI_ScaleDialog::ok_callback(Fl_Widget *w, void *data) { UI_ScaleDialog * that = (UI_ScaleDialog *)data; double scale_x = ParseScaleStr(that->scale_x->value()); double scale_y = ParseScaleStr(that->scale_y->value()); double scale_z = ParseScaleStr(that->scale_z->value()); if (scale_x <= 0 || scale_y <= 0 || scale_z <= 0) { // WISH: deactivate OK button instead (don't get here) that->inst.Beep("bad scaling value"); that->want_close = true; return; } int pos_x = that->origin_x->value() - 1; int pos_y = that->origin_y->value() - 1; int pos_z = that->origin_z->value() - 1; if (that->inst.edit.mode == ObjType::sectors) that->inst.level.objects.scale4(scale_x, scale_y, scale_z, pos_x, pos_y, pos_z); else that->inst.level.objects.scale3(scale_x, scale_y, pos_x, pos_y); that->want_close = true; } //------------------------------------------------------------------------ UI_RotateDialog::UI_RotateDialog(Instance &inst) : UI_Escapable_Window(360, 200, "Rotate Objects"), want_close(false), inst(inst) { Fl_Box *title = new Fl_Box(10, 11, w() - 20, 32, "Enter # of degrees to rotate objects:"); title->labelsize(16); title->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); angle = new Fl_Float_Input(95, 55, 65, 25, "angle:"); angle->value("0"); dir = new Fl_Choice(170, 55, 140, 25); dir->add("Clockwise|Anti-clockwise"); dir->value(0); origin = new Fl_Choice(95, 90, 140, 25, "origin:"); origin->add("Bottom Left|Bottom|Bottom Right|" "Left|Centre|Right|" "Top Left|Top|Top Right"); origin->value(4); Fl_Group * grp = new Fl_Group(0, h() - 70, w(), 70); grp->box(FL_FLAT_BOX); grp->color(WINDOW_BG, WINDOW_BG); { cancel_but = new Fl_Button(30, grp->y() + 20, 95, 30, "Cancel"); cancel_but->callback(close_callback, this); ok_but = new Fl_Button(245, grp->y() + 20, 95, 30, "Rotate"); ok_but->labelfont(FL_HELVETICA_BOLD); ok_but->callback(ok_callback, this); grp->end(); } end(); resizable(NULL); callback(close_callback, this); } UI_RotateDialog::~UI_RotateDialog() { } void UI_RotateDialog::Run() { set_modal(); show(); while (! want_close) { Fl::wait(0.2); } } void UI_RotateDialog::close_callback(Fl_Widget *w, void *data) { UI_RotateDialog * that = (UI_RotateDialog *)data; that->want_close = true; } void UI_RotateDialog::ok_callback(Fl_Widget *w, void *data) { UI_RotateDialog * that = (UI_RotateDialog *)data; float angle = static_cast(atof(that->angle->value())); if (that->dir->value() == 0) angle = -angle; int pos_x = (that->origin->value() % 3) - 1; int pos_y = (that->origin->value() / 3) - 1; that->inst.level.objects.rotate3(angle, pos_x, pos_y); that->want_close = true; } //------------------------------------------------------------------------ UI_JumpToDialog::UI_JumpToDialog(const char *_objname, int _limit) : UI_Escapable_Window(380, 175, "Jump to Objects"), limit(_limit) { SYS_ASSERT(limit >= 0); char descript[300]; snprintf(descript, sizeof(descript), "Enter one or more %s numbers (each 0 - %d)\n", _objname, limit); Fl_Box *title = new Fl_Box(10, 11, w() - 20, 32, NULL); title->copy_label(descript); title->labelsize(16); title->align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE); input = new Fl_Input(145, 55, 90, 25, "index: "); input->when(FL_WHEN_CHANGED | FL_WHEN_ENTER_KEY_ALWAYS); input->callback(input_callback, this); Fl_Group * grp = new Fl_Group(0, h() - 70, w(), 70); grp->box(FL_FLAT_BOX); grp->color(WINDOW_BG, WINDOW_BG); { cancel_but = new Fl_Button(30, grp->y() + 20, 95, 30, "Cancel"); cancel_but->callback(close_callback, this); ok_but = new Fl_Button(245, grp->y() + 20, 95, 30, "Jump"); ok_but->labelfont(FL_HELVETICA_BOLD); ok_but->callback(ok_callback, this); ok_but->deactivate(); grp->end(); } end(); resizable(NULL); callback(close_callback, this); } std::vector UI_JumpToDialog::Run() { set_modal(); show(); Fl::focus(input); while (! want_close) Fl::wait(0.2); return result; } void UI_JumpToDialog::close_callback(Fl_Widget *w, void *data) { UI_JumpToDialog * that = (UI_JumpToDialog *)data; that->want_close = true; } // // Parse a value into a list of integers // static std::vector parseValueList(const char *text) { assert(text); // Parse strictly numbers std::vector result; const char *end = text + strlen(text); while(text < end) { char *endptr; long value = strtol(text, &endptr, 10); if(endptr == text) { ++text; continue; } result.push_back((int)value); text = endptr; } return result; } void UI_JumpToDialog::ok_callback(Fl_Widget *w, void *data) { UI_JumpToDialog * that = (UI_JumpToDialog *)data; that->result = parseValueList(that->input->value()); that->want_close = true; } void UI_JumpToDialog::input_callback(Fl_Widget *w, void *data) { UI_JumpToDialog * that = (UI_JumpToDialog *)data; auto disable = [that]() { that->input->textcolor(FL_RED); that->input->redraw(); that->ok_but->deactivate(); }; // this is slightly hacky bool was_enter = (Fl::event_key() == FL_Enter || Fl::event_key() == FL_KP_Enter); std::vector values = parseValueList(that->input->value()); if(values.empty()) { disable(); return; } for(int value : values) { if (value < 0 || value > that->limit) { disable(); return; } } that->input->textcolor(FL_FOREGROUND_COLOR); that->input->redraw(); that->ok_but->activate(); if (was_enter) that->ok_callback(w, data); } // // Handler for the dynamic int input // int UI_DynIntInput::handle(int event) { int res = Fl_Int_Input::handle(event); if((event == FL_KEYBOARD || event == FL_PASTE) && mCallback2) { mCallback2(this, mData2); } return res; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_misc.h000066400000000000000000000074741464327712600201450ustar00rootroot00000000000000//------------------------------------------------------------------------ // Miscellaneous UI Dialogs //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_MISC_H__ #define __EUREKA_UI_MISC_H__ #include "ui_window.h" #include "FL/Fl_Int_Input.H" class Fl_Float_Input; class UI_MoveDialog : public UI_Escapable_Window { private: Fl_Int_Input *delta_x; Fl_Int_Input *delta_y; Fl_Int_Input *delta_z; Fl_Button *ok_but; Fl_Button *cancel_but; bool want_close = false; Instance &inst; public: UI_MoveDialog(Instance &inst, bool want_dz); void Run(); private: static void ok_callback(Fl_Widget *, void *); static void close_callback(Fl_Widget *, void *); }; //------------------------------------------------------------------------ class UI_ScaleDialog : public UI_Escapable_Window { private: Fl_Input *scale_x; Fl_Input *scale_y; Fl_Input *scale_z; Fl_Choice *origin_x; Fl_Choice *origin_y; Fl_Choice *origin_z; Fl_Button *ok_but; Fl_Button *cancel_but; bool want_close = false; Instance &inst; public: explicit UI_ScaleDialog(Instance &inst); void Run(); private: static void ok_callback(Fl_Widget *, void *); static void close_callback(Fl_Widget *, void *); }; //------------------------------------------------------------------------ class UI_RotateDialog : public UI_Escapable_Window { private: Fl_Float_Input *angle; Fl_Choice *dir; Fl_Choice *origin; Fl_Button *ok_but; Fl_Button *cancel_but; bool want_close; Instance &inst; public: explicit UI_RotateDialog(Instance &inst); virtual ~UI_RotateDialog(); void Run(); private: static void ok_callback(Fl_Widget *, void *); static void close_callback(Fl_Widget *, void *); }; //------------------------------------------------------------------------ class UI_JumpToDialog : public UI_Escapable_Window { private: Fl_Input *input; Fl_Button *ok_but; Fl_Button *cancel_but; bool want_close = false; int limit; std::vector result; public: UI_JumpToDialog(const char *_objname, int _limit); virtual ~UI_JumpToDialog() { } // returns the typed number, or -1 if cancelled std::vector Run(); private: static void ok_callback(Fl_Widget *, void *); static void close_callback(Fl_Widget *, void *); static void input_callback(Fl_Widget *, void *); }; // // Similar to UI_DynInput but for Fl_Int_Input // class UI_DynIntInput : public Fl_Int_Input, public ICallback2 { public: UI_DynIntInput(int X, int Y, int W, int H, const char *L = nullptr) : Fl_Int_Input(X, Y, W, H, L) { } int handle(int event) override; // // Assign the change callback // void callback2(Fl_Callback *callback, void *data) override { mCallback2 = callback; mData2 = data; } Fl_Callback *callback2() const override { return mCallback2; } void *user_data2() const override { return mData2; } const char *value() const { return Fl_Int_Input::value(); } ICALLBACK2_BOILERPLATE() private: void value(const char *s) // prevent direct editing { Fl_Int_Input::value(s); } Fl_Callback *mCallback2 = nullptr; void *mData2 = nullptr; }; #endif /* __EUREKA_UI_MISC_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_nombre.cc000066400000000000000000000044301464327712600206170ustar00rootroot00000000000000//------------------------------------------------------------------------ // Information Bar (bottom of window) //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2009 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "main.h" #include "m_config.h" #include "ui_window.h" #include "ui_nombre.h" #define NOMBRBACK_COL (config::gui_scheme == 2 ? FL_GRAY0+1 : FL_GRAY0+3) // // UI_Nombre Constructor // UI_Nombre::UI_Nombre(int X, int Y, int W, int H, const char *what) : Fl_Box(FL_FLAT_BOX, X, Y, W, H, "") { type_name = what; align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT); color(NOMBRBACK_COL); labelfont(FL_COURIER_BOLD); labelsize(19); Update(); } void UI_Nombre::Update() noexcept { char buffer[256]; if (index < 0) snprintf(buffer, sizeof(buffer), "No %s / %d\n", type_name.c_str(), total); else if (selected > 1) snprintf(buffer, sizeof(buffer), "%s #%-4d + %d more\n", type_name.c_str(), index, selected-1); else snprintf(buffer, sizeof(buffer), "%s #%-4d / %d\n", type_name.c_str(), index, total); if (index < 0 || total == 0) labelcolor(FL_DARK1); else labelcolor(FL_YELLOW); if (index < 0 || total == 0) color(NOMBRBACK_COL); else if (selected == 0) color(NOMBRBACK_COL); // same as above else if (selected == 1) color(FL_BLUE); else color(FL_RED); copy_label(buffer); } void UI_Nombre::SetIndex(int _idx) { if (index != _idx) { index = _idx; Update(); } } void UI_Nombre::SetTotal(int _tot) noexcept { if (total != _tot) { total = _tot; Update(); } } void UI_Nombre::SetSelected(int _sel) { if (selected != _sel) { selected = _sel; Update(); } } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_nombre.h000066400000000000000000000025721464327712600204660ustar00rootroot00000000000000//------------------------------------------------------------------------ // Information Bar (bottom of window) //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2009 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_NOMBRE_H__ #define __EUREKA_UI_NOMBRE_H__ #include "m_strings.h" #include "FL/Fl_Box.H" class UI_Nombre : public Fl_Box { private: int index = -1; int total = 0; int selected = 0; SString type_name; void Update() noexcept; public: UI_Nombre(int X, int Y, int W, int H, const char *what = NULL); public: void SetIndex(int _idx); // _idx < 0 means "no index" void SetTotal(int _tot) noexcept; void SetSelected(int _sel); }; #endif /* __EUREKA_UI_NOMBRE_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_panelinput.cc000066400000000000000000000064341464327712600215220ustar00rootroot00000000000000//------------------------------------------------------------------------ // Panel input fixing of problems //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "ui_panelinput.h" #include "ui_nombre.h" // // Given a list of fields, assigns secondary callbacks // void PanelFieldFixUp::loadFields(std::initializer_list fields) { for(ICallback2 *field : fields) { if(field->getMainCallback()) mOriginalCallbacks[field] = { field->getMainCallback(), field->getMainUserData() }; field->setMainCallback(clearDirtyCallback, this); if(field->callback2()) mOriginalCallbacks2[field] = { field->callback2(), field->user_data2() }; field->callback2(setDirtyCallback, this); mAsCallback2[field->asWidget()] = field; mAsWidget[field] = field->asWidget(); } } // // Check all dirty flags and calls the callbacks. Meant to be called before // any non-edit action! // void PanelFieldFixUp::checkDirtyFields() { while(!mDirtyFields.empty()) { ICallback2 *input = *mDirtyFields.begin(); input->getMainCallback()(mAsWidget[input], this); } } // // Convenience that also sets the dirty field. Only use it for targeted fields // void PanelFieldFixUp::setInputValue(ICallback2 *input, const char *value) noexcept { input->setValue(value); mDirtyFields.erase(input); } // // Set-callback for this // void PanelFieldFixUp::setDirtyCallback(Fl_Widget *widget, void *data) { auto fixup = static_cast(data); auto control = fixup->mAsCallback2[widget]; fixup->mDirtyFields.insert(control); // Now also call its original one auto it = fixup->mOriginalCallbacks2.find(control); if(it != fixup->mOriginalCallbacks2.end()) it->second.callback(widget, it->second.data); } // // Clear-callback for this // void PanelFieldFixUp::clearDirtyCallback(Fl_Widget *widget, void *data) { auto fixup = static_cast(data); auto control = fixup->mAsCallback2[widget]; fixup->mDirtyFields.erase(control); // Now also call its original one auto it = fixup->mOriginalCallbacks.find(control); if(it != fixup->mOriginalCallbacks.end()) it->second.callback(widget, it->second.data); } void MapItemBox::SetObj(int _index, int _count) { if (obj == _index && count == _count) return; obj = _index; count = _count; which->SetIndex(obj); which->SetSelected(count); UpdateField(); if (obj < 0) UnselectPics(); redraw(); } eureka-editor-eureka-2.0.2/src/ui_panelinput.h000066400000000000000000000103011464327712600213500ustar00rootroot00000000000000//------------------------------------------------------------------------ // Panel input fixing of problems //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_PANELINPUT_H__ #define __EUREKA_UI_PANELINPUT_H__ #include "FL/Fl_Group.H" #include "FL/Fl_Input.H" #include #include class Instance; class UI_Nombre; struct ConfigData; struct Document; struct LoadingData; enum { NOMBRE_INSET = 6, NOMBRE_HEIGHT = 28 }; // // Interface for providing "callback2" to controls // class ICallback2 { public: virtual void callback2(Fl_Callback *callback, void *data) = 0; virtual Fl_Callback *callback2() const = 0; virtual void *user_data2() const = 0; // Necessary indicators for our task. Oh, boilerplate :( virtual Fl_Callback *getMainCallback() const = 0; virtual void *getMainUserData() const = 0; virtual void setMainCallback(Fl_Callback *callback, void *data) = 0; virtual void setValue(const char *value) = 0; virtual Fl_Widget *asWidget() = 0; }; #define ICALLBACK2_BOILERPLATE() \ Fl_Callback *getMainCallback() const override { return callback(); } \ void *getMainUserData() const override { return user_data(); } \ void setMainCallback(Fl_Callback *cb, void *data) override { callback(cb, data); } \ void setValue(const char *v) override { value(v); } \ Fl_Widget *asWidget() override { return static_cast(this); } // // Fix-up class for panel fields to make sure they work as expected when clicking buttons // class PanelFieldFixUp { public: void loadFields(std::initializer_list fields); // Call it before starting basis void checkDirtyFields(); void setInputValue(ICallback2 *input, const char *value) noexcept; private: // // Callback info, for storage // struct CallbackInfo { Fl_Callback *callback; void *data; }; static void setDirtyCallback(Fl_Widget *widget, void *data); static void clearDirtyCallback(Fl_Widget *widget, void *data); std::unordered_map mOriginalCallbacks; std::unordered_map mOriginalCallbacks2; std::unordered_map mAsCallback2; std::unordered_map mAsWidget; // Set of "dirty" edit fields. The rule is as such: // - Add them to list when user writes text without exiting or pressing ENTER // (that's why they need to be UI_DynInput or UI_DynIntInput) // - Remove them from list when their callback is invoked (caution: only for them) // - Remove them from list when their value() is changed externally. // - Before any basis.begin() or external function which does that, call checkDirtyFields() std::unordered_set mDirtyFields; }; class MapItemBox : public Fl_Group { public: MapItemBox(Instance &inst, int X, int Y, int W, int H, const char *label = nullptr) : Fl_Group(X, Y, W, H, label), inst(inst) { } void SetObj(int _index, int _count); int GetObj() const { return obj; } virtual void UpdateField(int field = -1) = 0; virtual void UnselectPics() = 0; virtual void UpdateTotal(const Document &doc) noexcept = 0; virtual void UpdateGameInfo(const LoadingData &loaded, const ConfigData &config) = 0; protected: Instance &inst; int obj = -1; int count = 0; UI_Nombre *which = nullptr; PanelFieldFixUp mFixUp; }; #endif eureka-editor-eureka-2.0.2/src/ui_pic.cc000066400000000000000000000151071464327712600201130ustar00rootroot00000000000000//------------------------------------------------------------------------ // Information Bar (bottom of window) //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Instance.h" #include "main.h" #include "ui_pic.h" #include "ui_window.h" #include "im_img.h" #include "im_color.h" #include "m_config.h" #include "m_game.h" #include "e_things.h" #include "w_rawdef.h" #include "w_texture.h" // // UI_Pic Constructor // UI_Pic::UI_Pic(Instance &inst, int X, int Y, int W, int H, const char *L) : Fl_Box(FL_BORDER_BOX, X, Y, W, H, ""), inst(inst) { color(FL_DARK2); what_text = L; what_color = (config::gui_color_set == 1) ? (FL_GRAY0 + 4) : FL_BACKGROUND_COLOR; label(what_text.c_str()); labelcolor(what_color); labelsize(16); align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER); } void UI_Pic::Clear() noexcept { color(FL_DARK2); labelcolor(what_color); labelsize(16); label(what_text.c_str()); rgb.reset(); redraw(); } void UI_Pic::MarkUnknown() noexcept { Clear(); color(FL_CYAN); labelcolor(FL_BLACK); labelsize(40); label("?"); redraw(); } void UI_Pic::MarkMissing() { Clear(); color(fl_rgb_color(255, 128, 0)); labelcolor(FL_BLACK); labelsize(40); label("!"); redraw(); } void UI_Pic::MarkSpecial() { Clear(); color(fl_rgb_color(192, 0, 192)); labelcolor(FL_WHITE); labelsize(40); label("?"); redraw(); } void UI_Pic::GetFlat(const SString & fname) noexcept { const Img_c *img = inst.wad.images.W_GetFlat(inst.conf, fname, true /* try_uppercase */); TiledImg(img); } void UI_Pic::GetTex(const SString & tname) { if (is_special_tex(tname)) { MarkSpecial(); return; } else if (is_null_tex(tname)) { Clear(); return; } const Img_c *img = inst.wad.images.getTexture(inst.conf, tname, true /* try_uppercase */); TiledImg(img); } void UI_Pic::GetSprite(int type, Fl_Color back_color) { Clear(); const Img_c *img = inst.wad.getSprite(inst.conf, type, inst.loaded, 1); tl::optional new_img; if (! img || img->width() < 1 || img->height() < 1) { MarkUnknown(); return; } const thingtype_t &info = inst.conf.getThingType(type); uint32_t back = Fl::get_color(back_color); int iw = img->width(); int ih = img->height(); int nw = w(); int nh = h(); float scale = info.scale; float fit_x = iw * scale / (float)nw; float fit_y = ih * scale / (float)nh; // shrink if too big if (fit_x > 1.00 || fit_x > 1.00) scale = scale / std::max(fit_x, fit_y); // enlarge if too small if (fit_x < 0.4 && fit_y < 0.4) scale = scale / (2.5f * std::max(fit_x, fit_y)); std::vector buf; buf.resize(nw * nh * 3); for (int y = 0 ; y < nh ; y++) for (int x = 0 ; x < nw ; x++) { byte *dest = buf.data() + ((y * nw + x) * 3); // black border if (x == 0 || x == nw-1 || y == 0 || y == nh-1) { dest[0] = 0; dest[1] = 0; dest[2] = 0; continue; } int ix = static_cast(x / scale - (nw / scale - iw) / 2); int iy = static_cast(y / scale - (nh / scale - ih) / 2); img_pixel_t pix = TRANS_PIXEL; if (ix >= 0 && ix < iw && iy >= 0 && iy < ih) { pix = img->buf() [iy * iw + ix]; } if (pix == TRANS_PIXEL) { dest[0] = RGB_RED(back); dest[1] = RGB_GREEN(back); dest[2] = RGB_BLUE(back); } else { inst.wad.palette.decodePixelMedium(pix, dest[0], dest[1], dest[2]); } } UploadRGB(std::move(buf), 3); } void UI_Pic::TiledImg(const Img_c *img) noexcept { color(FL_DARK2); Clear(); if (! img || img->width() < 1 || img->height() < 1) { MarkUnknown(); return; } int iw = img->width(); int ih = img->height(); int nw = w(); int nh = h(); int scale = 1; while (nw*scale < iw || nh*scale < ih) scale = scale * 2; const uint32_t back = config::transparent_col; std::vector buf; buf.resize(nw * nh * 3); for (int y = 0 ; y < nh ; y++) for (int x = 0 ; x < nw ; x++) { int ix = (x * scale) % iw; int iy = (y * scale) % ih; img_pixel_t pix = img->buf() [iy*iw+ix]; byte *dest = buf.data() + ((y * nw + x) * 3); if (pix == TRANS_PIXEL) { dest[0] = RGB_RED(back); dest[1] = RGB_GREEN(back); dest[2] = RGB_BLUE(back); } else { inst.wad.palette.decodePixelMedium(pix, dest[0], dest[1], dest[2]); } } UploadRGB(std::move(buf), 3); } void UI_Pic::UploadRGB(std::vector &&buf, int depth) noexcept { rgbBuffer = std::move(buf); rgb = std::make_unique(rgbBuffer.data(), w(), h(), depth, 0); // remove label label(""); redraw(); } //------------------------------------------------------------------------ int UI_Pic::handle(int event) { switch (event) { case FL_ENTER: inst.main_win->SetCursor(FL_CURSOR_HAND); highlighted = true; redraw(); return 1; case FL_LEAVE: if (highlighted) { inst.main_win->SetCursor(FL_CURSOR_DEFAULT); highlighted = false; redraw(); } return 1; case FL_PUSH: do_callback(); return 1; default: break; } return 0; // unused } void UI_Pic::draw() { if (rgb) rgb->draw(x(), y()); else Fl_Box::draw(); if (selected) draw_selected(); else if (Highlighted()) draw_highlighted(); } void UI_Pic::draw_highlighted() { int X = x(); int Y = y(); int W = w(); int H = h(); fl_rect(X+0, Y+0, W-0, H-0, FL_YELLOW); fl_rect(X+1, Y+1, W-2, H-2, FL_YELLOW); fl_rect(X+2, Y+2, W-4, H-4, FL_BLACK); } void UI_Pic::draw_selected() { int X = x(); int Y = y(); int W = w(); int H = h(); fl_rect(X+0, Y+0, W-0, H-0, FL_RED); fl_rect(X+1, Y+1, W-2, H-2, FL_RED); fl_rect(X+2, Y+2, W-4, H-4, FL_BLACK); } void UI_Pic::Selected(bool _val) { if (selected != _val) redraw(); selected = _val; } void UI_Pic::Unhighlight() { handle(FL_LEAVE); } //------------------------------------------------------------------------ int UI_DynInput::handle(int event) { int res = Fl_Input::handle(event); if ((event == FL_KEYBOARD || event == FL_PASTE) && callback2_) { callback2_(this, data2_); } return res; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_pic.h000066400000000000000000000062141464327712600177540ustar00rootroot00000000000000//------------------------------------------------------------------------ // Information Bar (bottom of window) //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_PIC_H__ #define __EUREKA_UI_PIC_H__ #include "ui_panelinput.h" #include "FL/Fl_Input.H" #include "FL/Fl_RGB_Image.H" #include class Img_c; class UI_Pic : public Fl_Box { private: std::unique_ptr rgb; std::vector rgbBuffer; bool allow_hl = false; bool highlighted = false; bool selected = false; SString what_text; Fl_Color what_color = {}; Instance &inst; public: UI_Pic(Instance &inst, int X, int Y, int W, int H, const char *L = ""); // FLTK method for event handling int handle(int event); public: void Clear() noexcept; void MarkUnknown() noexcept; void MarkMissing(); void MarkSpecial(); void GetFlat(const SString & fname) noexcept; void GetTex (const SString & tname); void GetSprite(int type, Fl_Color back_color); void AllowHighlight(bool enable) { allow_hl = enable; redraw(); } bool Highlighted() const { return allow_hl && highlighted; } void Unhighlight(); bool Selected() const { return selected; } void Selected(bool _val); private: // FLTK virtual method for drawing. void draw(); void draw_highlighted(); void draw_selected(); void UploadRGB(std::vector &&buf, int depth) noexcept; void TiledImg(const Img_c *img) noexcept; }; //------------------------------------------------------------------------ class UI_DynInput : public Fl_Input, public ICallback2 { /* this widget provides a secondary callback which can be * used to dynamically update a picture or description. */ private: Fl_Callback *callback2_ = nullptr; void *data2_ = nullptr; public: UI_DynInput(int X, int Y, int W, int H, const char *L = nullptr) : Fl_Input(X, Y, W, H, L) { } // FLTK method for event handling int handle(int event) override; // main callback is done on ENTER or RELEASE, but this // secondary callback is done on each change by the user. void callback2(Fl_Callback *cb, void *data) override { callback2_ = cb; data2_ = data; } Fl_Callback *callback2() const override { return callback2_; } void *user_data2() const override { return data2_; } const char *value() const { return Fl_Input::value(); } ICALLBACK2_BOILERPLATE() private: void value(const char *s) // prevent direct editing { Fl_Input::value(s); } }; #endif /* __EUREKA_UI_PIC_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_prefs.cc000066400000000000000000001302741464327712600204620ustar00rootroot00000000000000//------------------------------------------------------------------------ // PREFERENCES DIALOG //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2019 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include "m_config.h" #include "m_parse.h" #include #include "ui_window.h" #include "ui_prefs.h" #include #define PREF_WINDOW_W 600 #define PREF_WINDOW_H 520 #define PREF_WINDOW_TITLE "Eureka Preferences" static int last_active_tab = 0; class UI_EditKey : public UI_Escapable_Window { private: bool want_close; bool cancelled; bool awaiting_key; keycode_t key; Fl_Input *key_name; Fl_Button *grab_but; Fl_Output *func_name; Fl_Menu_Button *func_choose; Fl_Choice *context; Fl_Input *params; const editor_command_t *cur_cmd; Fl_Menu_Button *keyword_menu; Fl_Menu_Button *flag_menu; Fl_Button *cancel; Fl_Button *ok_but; private: void BeginGrab() { SYS_ASSERT(! awaiting_key); awaiting_key = true; key_name->color(FL_YELLOW, FL_YELLOW); key_name->value("<\077\077\077>"); key_name->textcolor(FL_FOREGROUND_COLOR); grab_but->deactivate(); Fl::focus(this); redraw(); } void FinishGrab() { if (! awaiting_key) return; awaiting_key = false; key_name->color(FL_BACKGROUND2_COLOR, FL_SELECTION_COLOR); grab_but->activate(); redraw(); } int handle(int event) { if (awaiting_key) { // escape key cancels if (event == FL_KEYDOWN && Fl::event_key() == FL_Escape) { FinishGrab(); if (key) key_name->value(M_KeyToString(key).c_str()); // if previous key was invalid, need to re-enable OK button validate_callback(this, this); return 1; } if (event == FL_KEYDOWN || event == FL_PUSH || event == FL_MOUSEWHEEL) { keycode_t new_key = M_CookedKeyForEvent(event); if (new_key) { FinishGrab(); key = new_key; key_name->value(M_KeyToString(key).c_str()); // if previous key was invalid, need to re-enable OK button validate_callback(this, this); return 1; } } } return UI_Escapable_Window::handle(event); } private: struct name_CMP_pred { inline bool operator() (const char * A, const char * B) const { return (strcmp(A, B) < 0); } }; // need this because menu is in reverse order KeyContext ContextFromMenu() { int i = context->value(); SYS_ASSERT(i >= 0 && i <= 6); return (KeyContext)((int)KeyContext::general - i); } void SetContext(KeyContext ctx) { int i = (int)KeyContext::general - (int)ctx; SYS_ASSERT(i >= 0 && i <= 6); context->value(i); } void AddContextToMenu(const char *lab, KeyContext ctx, KeyContext limit_ctx) { int flags = 0; if (limit_ctx != KeyContext::none && ctx != limit_ctx) { flags = FL_MENU_INACTIVE; } context->add(lab, 0, 0, 0, flags); } void PopulateContextMenu(KeyContext want_ctx) { KeyContext limit_ctx = KeyContext::none; if (cur_cmd && cur_cmd->req_context != KeyContext::none) limit_ctx = cur_cmd->req_context; context->clear(); AddContextToMenu("General (Any)", KeyContext::general, limit_ctx); AddContextToMenu("Linedefs", KeyContext::line, limit_ctx); AddContextToMenu("Sectors", KeyContext::sector, limit_ctx); AddContextToMenu("Things", KeyContext::thing, limit_ctx); AddContextToMenu("Vertices", KeyContext::vertex, limit_ctx); AddContextToMenu("3D View", KeyContext::render, limit_ctx); AddContextToMenu("Browser", KeyContext::browser, limit_ctx); if (want_ctx != KeyContext::none) SetContext(want_ctx); } void PopulateFuncMenu(const char *find_name = NULL) { func_choose->clear(); cur_cmd = NULL; // add names to menu, and find the current function char buffer[512]; bool did_separator = false; for (int i = 0 ; ; i++) { const editor_command_t *cmd = LookupEditorCommand(i); if (! cmd) break; if (! did_separator && y_stricmp(cmd->group_name, "General") == 0) { func_choose->add("", 0, 0, 0, FL_MENU_DIVIDER|FL_MENU_INACTIVE); did_separator = true; } snprintf(buffer, sizeof(buffer), "%s/%s", cmd->group_name, cmd->name); func_choose->add(buffer, 0, 0, (void *)(intptr_t)i, 0 /* flags */); if (find_name && strcmp(cmd->name, find_name) == 0) { cur_cmd = cmd; } } if (cur_cmd) func_name->value(cur_cmd->name); else func_name->value(""); } void Decode(KeyContext ctx, const char *str) { while (isspace(*str)) str++; char func_buf[100]; unsigned int pos = 0; while (*str && ! (isspace(*str) || *str == ':' || *str == '/') && pos + 4 < sizeof(func_buf)) { func_buf[pos++] = *str++; } func_buf[pos] = 0; // this sets the 'cur_cmd' variable PopulateFuncMenu(func_buf); PopulateMenuList(keyword_menu, cur_cmd ? cur_cmd->keyword_list : NULL); PopulateMenuList( flag_menu, cur_cmd ? cur_cmd-> flag_list : NULL); if (*str == ':') str++; while (isspace(*str)) str++; params->value(str); } SString Encode() { SString buffer; buffer.reserve(1024); // should not happen if (! cur_cmd) return "ERROR"; buffer = cur_cmd->name; buffer += ": "; buffer += params->value(); return buffer; } void PopulateMenuList(Fl_Menu_Button *menu, const char *list) { menu->clear(); if (! list || ! list[0]) { menu->deactivate(); return; } std::vector tokens; int num_tok = M_ParseLine(list, tokens, ParseOptions::noStrings); if (num_tok < 1) // shouldn't happen { menu->deactivate(); return; } for (int i = 0 ; i < num_tok ; i++) menu->add(tokens[i].c_str()); menu->activate(); } bool ValidateKey() { keycode_t new_key = M_ParseKeyString(key_name->value()); if (new_key > 0) { key = new_key; return true; } return false; } static void validate_callback(Fl_Widget *w, void *data) { UI_EditKey *dialog = (UI_EditKey *)data; bool valid_key = dialog->ValidateKey(); dialog->key_name->textcolor(valid_key ? FL_FOREGROUND_COLOR : FL_RED); // need to redraw the input box (otherwise get a mix of colors) dialog->key_name->redraw(); if (valid_key) dialog->ok_but->activate(); else dialog->ok_but->deactivate(); } static void grab_key_callback(Fl_Button *w, void *data) { UI_EditKey *dialog = (UI_EditKey *)data; dialog->BeginGrab(); } static void close_callback(Fl_Widget *w, void *data) { UI_EditKey *dialog = (UI_EditKey *)data; dialog->want_close = true; dialog->cancelled = true; } static void ok_callback(Fl_Button *w, void *data) { UI_EditKey *dialog = (UI_EditKey *)data; dialog->want_close = true; } void SetNewFunction(int cmd_index) { const editor_command_t *old_cmd = cur_cmd; cur_cmd = LookupEditorCommand(cmd_index); if (! cur_cmd) // shouldn't happen return; func_name->value(cur_cmd->name); KeyContext want_ctx = ContextFromMenu(); if (cur_cmd->req_context != KeyContext::none) want_ctx = cur_cmd->req_context; else if (y_strnicmp(cur_cmd->name, "BR_", 3) == 0) want_ctx = KeyContext::browser; else if (old_cmd && old_cmd->req_context != KeyContext::none) want_ctx = KeyContext::general; PopulateContextMenu(want_ctx); PopulateMenuList(keyword_menu, cur_cmd ? cur_cmd->keyword_list : NULL); PopulateMenuList( flag_menu, cur_cmd ? cur_cmd-> flag_list : NULL); redraw(); } static void func_callback(Fl_Menu_Button *w, void *data) { UI_EditKey *dialog = (UI_EditKey *)data; int cmd_index = (int)(intptr_t)w->mvalue()->user_data_; SYS_ASSERT(cmd_index >= 0); dialog->SetNewFunction(cmd_index); } void ReplaceKeyword(const char *new_word) { // delete existing keyword, if any if (isalnum(params->value()[0])) { const char *str = params->value(); int len = 0; while (str[len] && (isalnum(str[len]) || str[len] == '_')) len++; while (str[len] && isspace(str[len])) len++; params->replace(0, len, NULL); } if (params->size() > 0) params->replace(0, 0, " "); params->replace(0, 0, new_word); } void ReplaceFlag(const char *new_flag) { const char *str = params->value(); // if flag is already present, remove it const char *pos = strstr(str, new_flag); if (pos) { int a = (int)(pos - str); int b = a + (int)strlen(new_flag); while (str[b] && isspace(str[b])) b++; params->replace(a, b, NULL); return; } // append the flag, adding a space if necessary int a = params->size(); if (a > 0 && !isspace(str[a-1])) { params->replace(a, a, " "); a += 1; } params->replace(a, a, new_flag); } static void keyword_callback(Fl_Menu_Button *w, void *data) { UI_EditKey *dialog = (UI_EditKey *)data; dialog->ReplaceKeyword(w->text()); } static void flag_callback(Fl_Menu_Button *w, void *data) { UI_EditKey *dialog = (UI_EditKey *)data; dialog->ReplaceFlag(w->text()); } public: UI_EditKey(keycode_t _key, KeyContext ctx, const char *_funcname) : UI_Escapable_Window(400, 306, "Edit Key Binding"), want_close(false), cancelled(false), awaiting_key(false), key(_key) { // _key may be zero (when "Add" button is used) if (ctx == KeyContext::none) ctx = KeyContext::general; callback(close_callback, this); key_name = new Fl_Input(85, 25, 150, 25, "Key:"); key_name->when(FL_WHEN_CHANGED); key_name->callback((Fl_Callback*)validate_callback, this); if (key) key_name->value(M_KeyToString(key).c_str()); grab_but = new Fl_Button(255, 25, 90, 25, "Re-bind"); grab_but->callback((Fl_Callback*)grab_key_callback, this); func_name = new Fl_Output(85, 65, 150, 25, "Function:"); func_choose = new Fl_Menu_Button(255, 65, 90, 25, "Choose"); func_choose->callback((Fl_Callback*) func_callback, this); context = new Fl_Choice(85, 105, 150, 25, "Mode:"); params = new Fl_Input(85, 145, 300, 25, "Params:"); params->value(""); params->when(FL_WHEN_CHANGED); keyword_menu = new Fl_Menu_Button( 85, 180, 135, 25, "Keywords..."); keyword_menu->callback((Fl_Callback*) keyword_callback, this); flag_menu = new Fl_Menu_Button(250, 180, 135, 25, "Flags..."); flag_menu->callback((Fl_Callback*) flag_callback, this); { Fl_Group *o = new Fl_Group(0, 240, 400, 66); o->box(FL_FLAT_BOX); o->color(WINDOW_BG, WINDOW_BG); cancel = new Fl_Button(170, 254, 80, 35, "Cancel"); cancel->callback((Fl_Callback*)close_callback, this); ok_but = new Fl_Button(295, 254, 80, 35, "OK"); ok_but->labelfont(FL_BOLD); ok_but->callback((Fl_Callback*)ok_callback, this); ok_but->deactivate(); o->end(); } end(); // parse line into function name and parameters Decode(ctx, _funcname); PopulateContextMenu(ctx == KeyContext::none ? KeyContext::general : ctx); } bool Run(keycode_t *key_v, KeyContext *ctx_v, SString *func_v, bool start_grabbed) { *key_v = 0; *ctx_v = KeyContext::none; func_v->clear(); // check the initial state validate_callback(this, this); set_modal(); show(); // need this for the 'start_grabbed' feature, get FLTK to // actually put (map) the window onto the screen. Fl::wait(0.1); Fl::wait(0.1); if (start_grabbed) BeginGrab(); else Fl::focus(params); while (! want_close) { Fl::wait(0.2); } if (cancelled) return false; *key_v = key; *ctx_v = ContextFromMenu(); *func_v = Encode(); return true; } }; //------------------------------------------------------------------------ class UI_Preferences : public Fl_Double_Window { private: bool want_quit; bool want_discard; char key_sort_mode; bool key_sort_rev; // normally zero (not waiting for a key) int awaiting_line; const opt_desc_t *const options; static void close_callback(Fl_Widget *w, void *data); static void color_callback(Fl_Button *w, void *data); static void sort_key_callback(Fl_Button *w, void *data); static void bind_key_callback(Fl_Button *w, void *data); static void edit_key_callback(Fl_Button *w, void *data); static void del_key_callback(Fl_Button *w, void *data); static void reset_callback(Fl_Button *w, void *data); public: UI_Preferences(const opt_desc_t *options); void Run(); void LoadValues(); void SaveValues(); void LoadKeys(); void ReloadKeys(); int GridSizeToChoice(int size); /* FLTK override */ int handle(int event); void ClearWaiting(); void SetBinding(keycode_t key); void EnsureKeyVisible(int line); public: Fl_Tabs *tabs; Fl_Button *apply_but; Fl_Button *discard_but; /* General Tab */ Fl_Round_Button *theme_plastic; Fl_Round_Button *theme_GTK; Fl_Round_Button *theme_FLTK; Fl_Round_Button *cols_bright; Fl_Round_Button *cols_default; Fl_Round_Button *cols_custom; Fl_Button *bg_colorbox; Fl_Button *ig_colorbox; Fl_Button *fg_colorbox; Fl_Check_Button *gen_autoload; Fl_Check_Button *gen_maximized; Fl_Check_Button *gen_swapsides; /* Keys Tab */ Fl_Hold_Browser *key_list; Fl_Button *key_group; Fl_Button *key_key; Fl_Button *key_func; Fl_Button *key_add; Fl_Button *key_copy; Fl_Button *key_edit; Fl_Button *key_delete; Fl_Button *key_rebind; /* Edit Tab */ Fl_Input *edit_def_port; Fl_Choice *edit_def_mode; Fl_Check_Button *edit_samemode; Fl_Check_Button *edit_autoadjustX; Fl_Check_Button *edit_add_del; Fl_Check_Button *edit_full_1S; Fl_Int_Input *edit_sectorsize; Fl_Input *edit_userratio; Fl_Choice *edit_lineinfo; Fl_Check_Button *brow_smalltex; Fl_Check_Button *brow_combo; /* Grid Tab */ Fl_Check_Button *gen_scrollbars; Fl_Choice *grid_cur_style; Fl_Check_Button *grid_snap; Fl_Check_Button *grid_enabled; Fl_Choice *grid_size; Fl_Check_Button *grid_hide_free; Fl_Check_Button *grid_flatrender; Fl_Check_Button *grid_spriterend; Fl_Check_Button *grid_indicator; Fl_Button *dotty_axis; Fl_Button *dotty_major; Fl_Button *dotty_minor; Fl_Button *dotty_point; Fl_Button *normal_axis; Fl_Button *normal_main; Fl_Button *normal_flat; Fl_Button *normal_small; /* 3D Tab */ Fl_Float_Input *rend_aspect;; Fl_Check_Button *rend_high_detail; Fl_Check_Button *rend_lock_grav; Fl_Choice *rend_far_clip; /* Nodes Tab */ Fl_Check_Button *nod_on_save; Fl_Check_Button *nod_fast; Fl_Check_Button *nod_warn; Fl_Choice *nod_factor; Fl_Check_Button *nod_gl_nodes; Fl_Check_Button *nod_force_v5; Fl_Check_Button *nod_force_zdoom; Fl_Check_Button *nod_compress; /* Other Tab */ Fl_Button * reset_conf; Fl_Button * reset_keys; }; #define R_SPACES " " UI_Preferences::UI_Preferences(const opt_desc_t *options) : Fl_Double_Window(PREF_WINDOW_W, PREF_WINDOW_H, PREF_WINDOW_TITLE), want_quit(false), want_discard(false), key_sort_mode('k'), key_sort_rev(false), awaiting_line(0), options(options) { if (config::gui_color_set == 2) color(fl_gray_ramp(4)); else color(WINDOW_BG); callback(close_callback, this); { tabs = new Fl_Tabs(0, 0, PREF_WINDOW_W-15, PREF_WINDOW_H-70); // tabs->selection_color(FL_WHITE); /* ---- General Tab ---- */ { Fl_Group* o = new Fl_Group(0, 25, 585, 405, " General" R_SPACES); o->labelsize(16); o->selection_color(FL_DARK2); // o->hide(); { Fl_Box* o = new Fl_Box(25, 45, 145, 30, "GUI Appearance"); o->labelfont(FL_BOLD); o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); } { Fl_Group* o = new Fl_Group(45, 90, 250, 115); { theme_plastic = new Fl_Round_Button(50, 120, 165, 25, " Plastic theme "); theme_plastic->type(102); theme_plastic->down_box(FL_ROUND_DOWN_BOX); } { theme_GTK = new Fl_Round_Button(50, 90, 150, 25, " GTK+ theme "); theme_GTK->type(102); theme_GTK->down_box(FL_ROUND_DOWN_BOX); } { theme_FLTK = new Fl_Round_Button(50, 150, 150, 25, " FLTK theme"); theme_FLTK->type(102); theme_FLTK->down_box(FL_ROUND_DOWN_BOX); } o->end(); } { Fl_Group* o = new Fl_Group(220, 90, 190, 90); { cols_bright = new Fl_Round_Button(245, 90, 140, 25, "bright colors"); cols_bright->type(102); cols_bright->down_box(FL_ROUND_DOWN_BOX); } { cols_default = new Fl_Round_Button(245, 120, 135, 25, "default colors"); cols_default->type(102); cols_default->down_box(FL_ROUND_DOWN_BOX); } { cols_custom = new Fl_Round_Button(245, 150, 165, 25, "custom colors ---->"); cols_custom->type(102); cols_custom->down_box(FL_ROUND_DOWN_BOX); } o->end(); } { Fl_Group* o = new Fl_Group(385, 80, 205, 100); o->color(FL_LIGHT1); o->align(Fl_Align(FL_ALIGN_BOTTOM_LEFT|FL_ALIGN_INSIDE)); { bg_colorbox = new Fl_Button(430, 90, 45, 25, "background"); bg_colorbox->box(FL_BORDER_BOX); bg_colorbox->align(Fl_Align(FL_ALIGN_RIGHT)); bg_colorbox->callback((Fl_Callback*)color_callback, this); } { ig_colorbox = new Fl_Button(430, 120, 45, 25, "input bg"); ig_colorbox->box(FL_BORDER_BOX); ig_colorbox->color(FL_BACKGROUND2_COLOR); ig_colorbox->align(Fl_Align(FL_ALIGN_RIGHT)); ig_colorbox->callback((Fl_Callback*)color_callback, this); } { fg_colorbox = new Fl_Button(430, 150, 45, 25, "text color"); fg_colorbox->box(FL_BORDER_BOX); fg_colorbox->color(FL_GRAY0); fg_colorbox->align(Fl_Align(FL_ALIGN_RIGHT)); fg_colorbox->callback((Fl_Callback*)color_callback, this); } o->end(); } { Fl_Box* o = new Fl_Box(30, 240, 280, 35, "Miscellaneous"); o->labelfont(FL_BOLD); o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); } { gen_autoload = new Fl_Check_Button(50, 280, 380, 25, " automatically open the most recent pwad"); } { gen_swapsides = new Fl_Check_Button(50, 310, 380, 25, " swap upper and lower sidedefs in Linedef panel"); } { gen_maximized = new Fl_Check_Button(50, 340, 380, 25, " maximize the window when Eureka starts"); // not supported on MacOS X // (on that platform we should restore last window position, but I don't // know how to code that) #ifdef __APPLE__ gen_maximized->hide(); #endif } o->end(); } /* ---- Key bindings Tab ---- */ { Fl_Group* o = new Fl_Group(0, 25, 585, 410, " Keys" R_SPACES); o->labelsize(16); o->selection_color(FL_DARK2); o->hide(); { Fl_Box* o = new Fl_Box(20, 45, 355, 30, "Key Bindings"); o->labelfont(FL_BOLD); o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); } { key_key = new Fl_Button(25, 87, 125, 25, "KEY"); key_key->color((Fl_Color)231); key_key->align(Fl_Align(FL_ALIGN_INSIDE)); key_key->callback((Fl_Callback*)sort_key_callback, this); } { key_group = new Fl_Button(155, 87, 75, 25, "MODE"); key_group->color((Fl_Color)231); key_group->align(Fl_Align(FL_ALIGN_INSIDE)); key_group->callback((Fl_Callback*)sort_key_callback, this); } { key_func = new Fl_Button(235, 87, 205, 25, "FUNCTION"); key_func->color((Fl_Color)231); key_func->align(Fl_Align(FL_ALIGN_INSIDE)); key_func->callback((Fl_Callback*)sort_key_callback, this); } { key_list = new Fl_Hold_Browser(20, 115, 442, 308); key_list->textfont(FL_COURIER); key_list->has_scrollbar(Fl_Browser_::VERTICAL); } { key_add = new Fl_Button(480, 155, 85, 30, "&Add"); key_add->callback((Fl_Callback*)edit_key_callback, this); } { key_copy = new Fl_Button(480, 195, 85, 30, "&Copy"); key_copy->callback((Fl_Callback*)edit_key_callback, this); } { key_edit = new Fl_Button(480, 235, 85, 30, "&Edit"); key_edit->callback((Fl_Callback*)edit_key_callback, this); } { key_delete = new Fl_Button(480, 275, 85, 30, "Delete"); key_delete->callback((Fl_Callback*)del_key_callback, this); key_delete->shortcut(FL_Delete); } { key_rebind = new Fl_Button(480, 370, 85, 30, "&Re-bind"); key_rebind->callback((Fl_Callback*)bind_key_callback, this); // key_rebind->shortcut(FL_Enter); } o->end(); } /* ---- Editing Tab ---- */ { Fl_Group* o = new Fl_Group(0, 25, 585, 410, " Editing" R_SPACES); o->labelsize(16); o->selection_color(FL_DARK2); o->hide(); { Fl_Box* o = new Fl_Box(25, 45, 355, 30, "Editing Options"); o->labelfont(FL_BOLD); o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); } { edit_def_port = new Fl_Input(150, 85, 95, 25, "default port: "); edit_def_port->align(FL_ALIGN_LEFT); } { edit_def_mode = new Fl_Choice(440, 85, 105, 25, "default edit mode: "); edit_def_mode->align(FL_ALIGN_LEFT); edit_def_mode->add("Things|Linedefs|Sectors|Vertices"); } { edit_autoadjustX = new Fl_Check_Button(50, 150, 260, 30, " auto-adjust X offsets"); } { edit_samemode = new Fl_Check_Button(50, 180, 270, 30, " same mode key will clear selection"); } { edit_add_del = new Fl_Check_Button(50, 210, 270, 30, " enable sidedef ADD / DEL buttons"); } { edit_full_1S = new Fl_Check_Button(50, 240, 270, 30, " show all textures on a one-sided linedef"); } { edit_sectorsize = new Fl_Int_Input(440, 120, 105, 25, "new sector size:"); } { edit_userratio = new Fl_Input(440, 150, 105, 25, "user ratio:"); } { edit_lineinfo = new Fl_Choice(440, 180, 105, 25, "line info:"); edit_lineinfo->add("NONE|Length|Angle|Ratio|Len+Ang|Len+Ratio"); } { Fl_Box* o = new Fl_Box(25, 295, 355, 30, "Browser Options"); o->labelfont(FL_BOLD); o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); } { brow_smalltex = new Fl_Check_Button(50, 330, 265, 30, " smaller textures"); } { brow_combo = new Fl_Check_Button(50, 360, 265, 30, " combine flats and textures in a single browser"); } o->end(); } /* ---- Grid Tab ---- */ { Fl_Group* o = new Fl_Group(0, 25, 585, 410, " Grid" R_SPACES); o->labelsize(16); o->selection_color(FL_DARK2); o->hide(); { Fl_Box* o = new Fl_Box(25, 45, 355, 30, "Map Grid and Scrolling"); o->labelfont(FL_BOLD); o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); } { grid_cur_style = new Fl_Choice(125, 90, 95, 25, "grid style "); grid_cur_style->add("Squares|Dotty"); } { grid_enabled = new Fl_Check_Button(50, 125, 95, 25, " default grid to ON"); } { grid_snap = new Fl_Check_Button(50, 155, 235, 25, " default snap to ON"); } { grid_flatrender = new Fl_Check_Button(50, 185, 270, 25, " default sector-render to ON"); } { grid_spriterend = new Fl_Check_Button(50, 215, 270, 25, " default sprites to ON"); } { grid_size = new Fl_Choice(420, 90, 95, 25, "default grid size "); grid_size->add("1024|512|256|192|128|64|32|16|8|4|2"); } { gen_scrollbars = new Fl_Check_Button(300, 125, 245, 25, " enable scroll-bars for map view"); } { grid_indicator = new Fl_Check_Button(300, 155, 245, 25, " enable snap-pos indicator"); } { grid_hide_free = new Fl_Check_Button(300, 185, 245, 25, " hide grid in FREE mode"); } { Fl_Box* o = new Fl_Box(25, 270, 355, 30, "Grid Colors"); o->labelfont(FL_BOLD); o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); } { normal_axis = new Fl_Button(150 + 0*55, 300, 45, 25, "Normal Grid : "); normal_axis->box(FL_BORDER_BOX); normal_axis->align(FL_ALIGN_LEFT); normal_axis->callback((Fl_Callback*)color_callback, this); normal_axis->tooltip("X/Y axis color"); } { normal_main = new Fl_Button(150 + 1*55, 300, 45, 25, ""); normal_main->box(FL_BORDER_BOX); normal_main->align(FL_ALIGN_RIGHT); normal_main->callback((Fl_Callback*)color_callback, this); normal_main->tooltip("large square color"); } { normal_flat = new Fl_Button(150 + 2*55, 300, 45, 25, ""); normal_flat->box(FL_BORDER_BOX); normal_flat->align(FL_ALIGN_RIGHT); normal_flat->callback((Fl_Callback*)color_callback, this); normal_flat->tooltip("64x64 square color"); } { normal_small = new Fl_Button(150 + 3*55, 300, 45, 25, ""); normal_small->box(FL_BORDER_BOX); normal_small->align(FL_ALIGN_RIGHT); normal_small->callback((Fl_Callback*)color_callback, this); normal_small->tooltip("small square color"); } { dotty_axis = new Fl_Button(150 + 0*55, 340, 45, 25, "Dotty Grid : "); dotty_axis->box(FL_BORDER_BOX); dotty_axis->align(FL_ALIGN_LEFT); dotty_axis->callback((Fl_Callback*)color_callback, this); dotty_axis->tooltip("X/Y axis color"); } { dotty_major = new Fl_Button(150 + 1*55, 340, 45, 25, ""); dotty_major->box(FL_BORDER_BOX); dotty_major->align(FL_ALIGN_RIGHT); dotty_major->callback((Fl_Callback*)color_callback, this); dotty_major->tooltip("large square color"); } { dotty_minor = new Fl_Button(150 + 2*55, 340, 45, 25, ""); dotty_minor->box(FL_BORDER_BOX); dotty_minor->align(FL_ALIGN_RIGHT); dotty_minor->callback((Fl_Callback*)color_callback, this); dotty_minor->tooltip("small square color"); } { dotty_point = new Fl_Button(150 + 3*55, 340, 45, 25, ""); dotty_point->box(FL_BORDER_BOX); dotty_point->align(FL_ALIGN_RIGHT); dotty_point->callback((Fl_Callback*)color_callback, this); dotty_point->tooltip("dot color"); } o->end(); } /* ---- 3D Tab ---- */ { Fl_Group* o = new Fl_Group(0, 25, 585, 410, " 3D View" R_SPACES); o->labelsize(16); o->selection_color(FL_DARK2); o->hide(); { Fl_Box* o = new Fl_Box(25, 45, 280, 30, "3D View Settings"); o->labelfont(FL_BOLD); o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); } { rend_aspect = new Fl_Float_Input(190, 90, 95, 25, "Pixel aspect ratio: "); Fl_Box* o = new Fl_Box(300, 90, 150, 25, "(higher is wider, default is 0.83)"); o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); } { rend_lock_grav = new Fl_Check_Button(50, 125, 360, 30, " Locked gravity -- cannot move up or down"); } { rend_high_detail = new Fl_Check_Button(50, 155, 360, 30, " High detail -- slower but looks better"); #ifndef NO_OPENGL rend_high_detail->hide(); #endif } { rend_far_clip = new Fl_Choice(195, 160, 100, 30, "Far clip distance: "); rend_far_clip->add("32768|16384|8192|4096|2048|1024"); #ifdef NO_OPENGL rend_far_clip->hide(); #endif } o->end(); } /* ---- Nodes Tab ---- */ { Fl_Group* o = new Fl_Group(0, 25, 585, 410, " Nodes" R_SPACES); o->labelsize(16); o->selection_color(FL_DARK2); o->hide(); { Fl_Box* o = new Fl_Box(25, 45, 280, 30, "Node Building"); o->labelfont(FL_BOLD); o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); } { nod_on_save = new Fl_Check_Button(50, 80, 220, 30, " Always build nodes after saving (recommended)"); } { nod_fast = new Fl_Check_Button(50, 110, 440, 30, " Fast mode (the nodes may not be as good)"); } { nod_warn = new Fl_Check_Button(50, 140, 220, 30, " Warning messages in the logs"); } { Fl_Box* o = new Fl_Box(25, 205, 250, 30, "Advanced BSP Settings"); o->labelfont(FL_BOLD); o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); } { nod_gl_nodes = new Fl_Check_Button(50, 245, 150, 30, " Build GL-Nodes"); } { nod_force_v5 = new Fl_Check_Button(50, 275, 250, 30, " Force V5 of GL-Nodes"); } { nod_force_zdoom = new Fl_Check_Button(50, 305, 250, 30, " Force ZDoom format of normal nodes"); } // CURRENTLY HIDDEN -- NOT SURE IT IS WORTH HAVING { nod_compress = new Fl_Check_Button(50, 335, 250, 30, " Force zlib compression"); nod_compress->hide(); } { nod_factor = new Fl_Choice(160, 345, 180, 30, "Seg split logic: "); nod_factor->add("NORMAL|Minimize Splits|Balance BSP Tree"); } o->end(); } /* ---- Other Tab ---- */ { Fl_Group* o = new Fl_Group(0, 25, 585, 410, " Other" R_SPACES); o->labelsize(16); o->selection_color(FL_DARK2); o->hide(); { Fl_Box* o = new Fl_Box(25, 255, 280, 30, "Configuration Reset"); o->labelfont(FL_BOLD); o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); } { reset_conf = new Fl_Button(100, 290, 200, 30, "Reset Config Settings"); reset_conf->callback((Fl_Callback*)reset_callback, this); } { reset_keys = new Fl_Button(100, 330, 200, 30, "Reset Key Bindings"); reset_keys->callback((Fl_Callback*)reset_callback, this); } o->end(); } tabs->end(); } { apply_but = new Fl_Button(PREF_WINDOW_W-150, PREF_WINDOW_H-50, 95, 35, "Apply"); apply_but->labelfont(FL_BOLD); apply_but->callback(close_callback, this); } { discard_but = new Fl_Button(PREF_WINDOW_W-290, PREF_WINDOW_H-50, 95, 35, "Discard"); discard_but->callback(close_callback, this); } end(); } //------------------------------------------------------------------------ void UI_Preferences::close_callback(Fl_Widget *w, void *data) { UI_Preferences *prefs = (UI_Preferences *)data; prefs->want_quit = true; if (w == prefs->discard_but) prefs->want_discard = true; } void UI_Preferences::color_callback(Fl_Button *w, void *data) { // UI_Preferences *dialog = (UI_Preferences *)data; uchar r, g, b; Fl::get_color(w->color(), r, g, b); if (! fl_color_chooser("New color:", r, g, b, 3)) return; w->color(fl_rgb_color(r, g, b)); w->redraw(); } void UI_Preferences::bind_key_callback(Fl_Button *w, void *data) { UI_Preferences *prefs = (UI_Preferences *)data; int line = prefs->key_list->value(); if (line < 1) { fl_beep(); return; } prefs->EnsureKeyVisible(line); int bind_idx = line - 1; // show we're ready to accept a new key const char *str = M_StringForBinding(bind_idx, true /* changing_key */); SYS_ASSERT(str); prefs->key_list->text(line, str); prefs->key_list->selection_color(FL_YELLOW); Fl::focus(prefs); prefs->awaiting_line = line; } void UI_Preferences::sort_key_callback(Fl_Button *w, void *data) { UI_Preferences *prefs = (UI_Preferences *)data; if (w == prefs->key_group) { if (prefs->key_sort_mode != 'c') { prefs->key_sort_mode = 'c'; prefs->key_sort_rev = false; } else prefs->key_sort_rev = !prefs->key_sort_rev; } else if (w == prefs->key_key) { if (prefs->key_sort_mode != 'k') { prefs->key_sort_mode = 'k'; prefs->key_sort_rev = false; } else prefs->key_sort_rev = !prefs->key_sort_rev; } else if (w == prefs->key_func) { if (prefs->key_sort_mode != 'f') { prefs->key_sort_mode = 'f'; prefs->key_sort_rev = false; } else prefs->key_sort_rev = !prefs->key_sort_rev; } prefs->LoadKeys(); } void UI_Preferences::edit_key_callback(Fl_Button *w, void *data) { UI_Preferences *prefs = (UI_Preferences *)data; bool is_add = (w == prefs->key_add); bool is_copy = (w == prefs->key_copy); keycode_t new_key = 0; KeyContext new_context = KeyContext::general; SString new_func = "Nothing"; int bind_idx = -1; if (! is_add) { int line = prefs->key_list->value(); if (line < 1) { fl_beep(); return; } prefs->EnsureKeyVisible(line); bind_idx = line - 1; SYS_ASSERT(bind_idx >= 0); M_GetBindingInfo(bind_idx, &new_key, &new_context); new_func = M_StringForFunc(bind_idx); } bool start_grabbed = false; //??? is_add || is_copy; UI_EditKey *dialog = new UI_EditKey(new_key, new_context, new_func.c_str()); bool was_ok = dialog->Run(&new_key, &new_context, &new_func, start_grabbed); if (was_ok) { // assume we can set it, since the dialog validated it if (is_add || is_copy) { M_AddLocalBinding(bind_idx, new_key, new_context, new_func.c_str()); if (is_copy) bind_idx++; else bind_idx = M_NumBindings() - 1; } else { M_SetLocalBinding(bind_idx, new_key, new_context, new_func); } } delete dialog; // for a new binding, make sure it is visible and selected if ((is_add || is_copy) && was_ok && bind_idx >= 0) { // expand the browser size with a dummy line // [ the ReloadKeys() below will grab the correct text ] prefs->key_list->add(""); SYS_ASSERT(bind_idx >= 0); int line = 1 + bind_idx; prefs->key_list->select(line); prefs->EnsureKeyVisible(line); } prefs->ReloadKeys(); prefs->redraw(); Fl::focus(prefs->key_list); } void UI_Preferences::del_key_callback(Fl_Button *w, void *data) { UI_Preferences *prefs = (UI_Preferences *)data; int line = prefs->key_list->value(); if (line < 1) { fl_beep(); return; } M_DeleteLocalBinding(line - 1); prefs->key_list->remove(line); prefs->ReloadKeys(); if (line <= prefs->key_list->size()) { prefs->key_list->select(line); Fl::focus(prefs->key_list); } } void UI_Preferences::reset_callback(Fl_Button *w, void *data) { UI_Preferences *prefs = (UI_Preferences *)data; bool is_keys = (w == prefs->reset_keys); int res = DLG_Confirm({ "Cancel", "&Reset" }, "This will reset all %s to their default values, " "removing any changes you may have made." "\n\n" "If you continue, you can still back out by " "using the \"Discard\" button at the bottom of " "the Preferences window." "\n ", is_keys ? "key bindings" : "preferences"); if (res <= 0) return; if (is_keys) { M_CopyBindings(true /* from_defaults */); prefs->LoadKeys(); } else { if (M_ParseConfigFile(global::install_dir / "defaults.cfg", prefs->options) != 0) { DLG_Notify("Installation problem: failed to find the \"defaults.cfg\" file!"); } else { prefs->LoadValues(); } } } void UI_Preferences::Run() { if (last_active_tab < tabs->children()) tabs->value(tabs->child(last_active_tab)); M_CopyBindings(); LoadValues(); LoadKeys(); set_modal(); show(); while (! want_quit) { Fl::wait(0.2); } last_active_tab = tabs->find(tabs->value()); if (want_discard) { gLog.printf("Preferences: discarded changes\n"); return; } SaveValues(); if(global::config_file.empty()) DLG_ShowError(false, "Configuration file not initialized."); else M_WriteConfigFile(global::config_file, options); M_ApplyBindings(); M_SaveBindings(); } int UI_Preferences::GridSizeToChoice(int size) { if (size > 512) return 0; if (size > 256) return 1; if (size > 128) return 2; if (size > 64) return 3; if (size > 32) return 4; if (size > 16) return 5; if (size > 8) return 6; if (size > 4) return 7; if (size > 2) return 8; return 9; } void UI_Preferences::LoadValues() { /* Theme stuff */ switch (config::gui_scheme) { case 0: theme_FLTK->value(1); break; case 1: theme_GTK->value(1); break; case 2: theme_plastic->value(1); break; } switch (config::gui_color_set) { case 0: cols_default->value(1); break; case 1: cols_bright->value(1); break; case 2: cols_custom->value(1); break; } bg_colorbox->color(config::gui_custom_bg); ig_colorbox->color(config::gui_custom_ig); fg_colorbox->color(config::gui_custom_fg); /* General Tab */ gen_autoload ->value(config::auto_load_recent ? 1 : 0); gen_maximized ->value(config::begin_maximized ? 1 : 0); gen_swapsides ->value(config::swap_sidedefs ? 1 : 0); /* Edit Tab */ edit_def_port->value(config::default_port.c_str()); edit_def_mode->value(clamp(0, config::default_edit_mode, 3)); edit_lineinfo->value(clamp(0, config::highlight_line_info, 5)); edit_sectorsize->value(SString(config::new_sector_size).c_str()); edit_samemode->value(config::same_mode_clears_selection ? 1 : 0); edit_add_del->value(config::sidedef_add_del_buttons ? 1 : 0); edit_full_1S->value(config::show_full_one_sided ? 1 : 0); edit_autoadjustX->value(config::leave_offsets_alone ? 0 : 1); brow_smalltex->value(config::browser_small_tex ? 1 : 0); brow_combo->value(config::browser_combine_tex ? 1 : 0); char ratio_buf[256]; snprintf(ratio_buf, sizeof(ratio_buf), "%d:%d", config::grid_ratio_high, config::grid_ratio_low); edit_userratio->value(ratio_buf); /* Grid Tab */ if (config::grid_style < 0 || config::grid_style > 1) config::grid_style = 1; grid_cur_style->value(config::grid_style); grid_enabled->value(config::grid_default_mode ? 1 : 0); grid_snap->value(config::grid_default_snap ? 1 : 0); grid_size->value(GridSizeToChoice(config::grid_default_size)); grid_hide_free ->value(config::grid_hide_in_free_mode ? 1 : 0); grid_flatrender->value(config::sector_render_default ? 1 : 0); grid_spriterend->value(config::thing_render_default ? 1 : 0); grid_indicator->value(config::grid_snap_indicator ? 1 : 0); gen_scrollbars ->value(config::map_scroll_bars ? 1 : 0); dotty_axis ->color(config::dotty_axis_col); dotty_major->color(config::dotty_major_col); dotty_minor->color(config::dotty_minor_col); dotty_point->color(config::dotty_point_col); normal_axis ->color(config::normal_axis_col); normal_main ->color(config::normal_main_col); normal_flat ->color(config::normal_flat_col); normal_small->color(config::normal_small_col); /* 3D Tab */ config::render_pixel_aspect = clamp(25, config::render_pixel_aspect, 400); char aspect_buf[64]; snprintf(aspect_buf, sizeof(aspect_buf), "%1.2f", config::render_pixel_aspect / 100.0); rend_aspect->value(aspect_buf); rend_high_detail->value(config::render_high_detail ? 1 : 0); rend_lock_grav->value(config::render_lock_gravity ? 1 : 0); if (config::render_far_clip > 24000) rend_far_clip->value(0); else if (config::render_far_clip > 12000) rend_far_clip->value(1); else if (config::render_far_clip > 6000) rend_far_clip->value(2); else if (config::render_far_clip > 3000) rend_far_clip->value(3); else if (config::render_far_clip > 1500) rend_far_clip->value(4); else rend_far_clip->value(5); /* Nodes Tab */ nod_on_save->value(config::bsp_on_save ? 1 : 0); nod_fast->value(config::bsp_fast ? 1 : 0); nod_warn->value(config::bsp_warnings ? 1 : 0); if (config::bsp_split_factor < 7) nod_factor->value(2); // Balanced BSP tree else if (config::bsp_split_factor > 15) nod_factor->value(1); // Minimize Splits else nod_factor->value(0); // NORMAL nod_gl_nodes->value(config::bsp_gl_nodes ? 1 : 0); nod_force_v5->value(config::bsp_force_v5 ? 1 : 0); nod_force_zdoom->value(config::bsp_force_zdoom ? 1 : 0); nod_compress->value(config::bsp_compressed ? 1 : 0); /* Other Tab */ } void UI_Preferences::SaveValues() { /* Theme stuff */ if (theme_FLTK->value()) config::gui_scheme = 0; else if (theme_GTK->value()) config::gui_scheme = 1; else config::gui_scheme = 2; if (cols_default->value()) config::gui_color_set = 0; else if (cols_bright->value()) config::gui_color_set = 1; else config::gui_color_set = 2; config::gui_custom_bg = (rgb_color_t) bg_colorbox->color(); config::gui_custom_ig = (rgb_color_t) ig_colorbox->color(); config::gui_custom_fg = (rgb_color_t) fg_colorbox->color(); // update the colors // FIXME: how to reset the "default" colors?? if (config::gui_color_set == 1) { Fl::background(236, 232, 228); Fl::background2(255, 255, 255); Fl::foreground(0, 0, 0); // TODO: update for ALL windows gInstance->main_win->redraw(); } else if (config::gui_color_set == 2) { Fl::background (RGB_RED(config::gui_custom_bg), RGB_GREEN(config::gui_custom_bg), RGB_BLUE(config::gui_custom_bg)); Fl::background2(RGB_RED(config::gui_custom_ig), RGB_GREEN(config::gui_custom_ig), RGB_BLUE(config::gui_custom_ig)); Fl::foreground (RGB_RED(config::gui_custom_fg), RGB_GREEN(config::gui_custom_fg), RGB_BLUE(config::gui_custom_fg)); // TODO: update for ALL windows gInstance->main_win->redraw(); } /* General Tab */ config::auto_load_recent = gen_autoload ->value() ? true : false; config::begin_maximized = gen_maximized ->value() ? true : false; config::swap_sidedefs = gen_swapsides ->value() ? true : false; /* Edit Tab */ config::default_port = edit_def_port->value(); config::default_edit_mode = edit_def_mode->value(); config::highlight_line_info = edit_lineinfo->value(); config::new_sector_size = atoi(edit_sectorsize->value()); config::new_sector_size = clamp(4, config::new_sector_size, 8192); config::same_mode_clears_selection = edit_samemode->value() ? true : false; config::sidedef_add_del_buttons = !!edit_add_del->value(); config::show_full_one_sided = edit_full_1S->value() ? true : false; config::leave_offsets_alone = edit_autoadjustX->value() ? false : true; // changing this requires re-populating the browser bool new_small_tex = brow_smalltex->value() ? true : false; bool new_combo = brow_combo->value() ? true : false; if (new_small_tex != config::browser_small_tex || new_combo != config::browser_combine_tex) { config::browser_small_tex = new_small_tex; config::browser_combine_tex = new_combo; // TODO: update for ALL windows gInstance->main_win->browser->Populate(); } // decode the user ratio config::grid_ratio_low = config::grid_ratio_high = -1; sscanf(edit_userratio->value(), "%d:%d", &config::grid_ratio_high, &config::grid_ratio_low); if (config::grid_ratio_high < 1) config::grid_ratio_high = 3; if (config::grid_ratio_low < 1) config::grid_ratio_low = 1; if (config::grid_ratio_low > config::grid_ratio_high) std::swap(config::grid_ratio_low, config::grid_ratio_high); // TODO: update for ALL windows gInstance->main_win->info_bar->UpdateRatio(); /* Grid Tab */ config::grid_style = grid_cur_style->value(); config::grid_default_mode = !!grid_enabled->value(); config::grid_default_snap = grid_snap->value() ? true : false; config::grid_default_size = atoi(grid_size->mvalue()->text); config::grid_hide_in_free_mode = grid_hide_free ->value() ? true : false; config::grid_snap_indicator = grid_indicator ->value() ? true : false; config::sector_render_default = grid_flatrender->value() ? 1 : 0; config::thing_render_default = grid_spriterend->value() ? 1 : 0; config::map_scroll_bars = gen_scrollbars ->value() ? true : false; config::dotty_axis_col = (rgb_color_t) dotty_axis ->color(); config::dotty_major_col = (rgb_color_t) dotty_major->color(); config::dotty_minor_col = (rgb_color_t) dotty_minor->color(); config::dotty_point_col = (rgb_color_t) dotty_point->color(); config::normal_axis_col = (rgb_color_t) normal_axis ->color(); config::normal_main_col = (rgb_color_t) normal_main ->color(); config::normal_flat_col = (rgb_color_t) normal_flat ->color(); config::normal_small_col = (rgb_color_t) normal_small->color(); /* Nodes Tab */ config::bsp_on_save = nod_on_save->value() ? true : false; config::bsp_fast = nod_fast->value() ? true : false; config::bsp_warnings = nod_warn->value() ? true : false; if (nod_factor->value() == 1) // Minimize Splits config::bsp_split_factor = 29; else if (nod_factor->value() == 2) // Balanced BSP tree config::bsp_split_factor = 2; else config::bsp_split_factor = 11; config::bsp_gl_nodes = nod_gl_nodes->value() ? true : false; config::bsp_force_v5 = nod_force_v5->value() ? true : false; config::bsp_force_zdoom = nod_force_zdoom->value() ? true : false; config::bsp_compressed = nod_compress->value() ? true : false; /* Other Tab */ config::render_pixel_aspect = (int)(100 * atof(rend_aspect->value()) + 0.2); config::render_pixel_aspect = clamp(25, config::render_pixel_aspect, 400); config::render_high_detail = rend_high_detail->value() ? true : false; config::render_lock_gravity = rend_lock_grav->value() ? true : false; config::render_far_clip = atoi(rend_far_clip->mvalue()->text); } void UI_Preferences::LoadKeys() { M_SortBindings(key_sort_mode, key_sort_rev); M_DetectConflictingBinds(); key_list->clear(); for (int i = 0 ; i < M_NumBindings() ; i++) { const char *str = M_StringForBinding(i); SYS_ASSERT(str); key_list->add(str); } key_list->select(1); } void UI_Preferences::ReloadKeys() { M_DetectConflictingBinds(); for (int i = 0 ; i < M_NumBindings() ; i++) { const char *str = M_StringForBinding(i); key_list->text(i + 1, str); } } void UI_Preferences::EnsureKeyVisible(int line) { if (! key_list->displayed(line)) { key_list->middleline(line); } } void UI_Preferences::ClearWaiting() { if (awaiting_line > 0) { // restore the text line ReloadKeys(); Fl::focus(key_list); } awaiting_line = 0; key_list->selection_color(FL_SELECTION_COLOR); } void UI_Preferences::SetBinding(keycode_t key) { int bind_idx = awaiting_line - 1; M_ChangeBindingKey(bind_idx, key); ClearWaiting(); } int UI_Preferences::handle(int event) { if (awaiting_line > 0) { // escape key cancels if (event == FL_KEYDOWN && Fl::event_key() == FL_Escape) { ClearWaiting(); return 1; } if (event == FL_KEYDOWN || event == FL_PUSH || event == FL_MOUSEWHEEL) { keycode_t new_key = M_CookedKeyForEvent(event); if (new_key) { SetBinding(new_key); return 1; } } } return Fl_Double_Window::handle(event); } //------------------------------------------------------------------------ void Instance::CMD_Preferences() { UI_Preferences * dialog = new UI_Preferences(options); dialog->Run(); delete dialog; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_prefs.h000066400000000000000000000017251464327712600203220ustar00rootroot00000000000000//------------------------------------------------------------------------ // PREFERENCES DIALOG //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_PREFS_H__ #define __EUREKA_UI_PREFS_H__ #endif /* __EUREKA_UI_PREFS_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_replace.cc000066400000000000000000001106461464327712600207570ustar00rootroot00000000000000//------------------------------------------------------------------------ // FIND AND REPLACE //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2015-2020 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include "ui_window.h" #include "e_cutpaste.h" // Texboard_XX #include "e_path.h" // GoToObject #include "e_main.h" // Selection_Clear #include "LineDef.h" #include "m_config.h" // gui_scheme #include "m_game.h" #include "r_render.h" #include "Sector.h" #include "SideDef.h" #include "Thing.h" #include "w_rawdef.h" #include "w_texture.h" #include class number_group_c { // This represents a small group of numbers and number ranges, // which the user can type into the Match input box. #define NUMBER_GROUP_MAX 40 private: int size; int ranges[NUMBER_GROUP_MAX][2]; bool everything; public: number_group_c() : size(0), everything(false) { } ~number_group_c() { } void clear() { size = 0; everything = false; } bool is_single() const { return (size == 1) && (ranges[0][0] == ranges[0][1]); } bool is_everything() const { return everything; } int grab_first() const { if (size == 0) return 0; return ranges[0][0]; } void insert(int low, int high) { // overflow is silently ignored if (size >= NUMBER_GROUP_MAX) return; // TODO : try to merge with existing range ranges[size][0] = low; ranges[size][1] = high; size++; } bool get(int num) const { for (int i = 0 ; i < size ; i++) { if (ranges[i][0] <= num && num <= ranges[i][1]) return true; } return false; } // // Parse a string like "1,3-5,9" and add the numbers (or ranges) // to this group. Returns false for malformed strings. // An empty string is considered invalid. // bool ParseString(const char *str) { char *endptr; for (;;) { // support an asterix to mean everything // (useful when using filters) if (*str == '*') { insert(INT_MIN, INT_MAX); everything = true; return true; } int low = (int)strtol(str, &endptr, 0 /* allow hex */); int high = low; if (endptr == str) return false; str = endptr; while (isspace(*str)) str++; // check for range if (*str == '-' || (str[0] == '.' && str[1] == '.')) { str += (*str == '-') ? 1 : 2; while (isspace(*str)) str++; high = (int)strtol(str, &endptr, 0 /* allow hex */); if (endptr == str) return false; str = endptr; // valid range? if (high < low) return false; while (isspace(*str)) str++; } insert(low, high); if (*str == 0) return true; // OK // // valid separator? if (*str == ',' || *str == '/' || *str == '|') str++; else return false; } } }; //------------------------------------------------------------------------ class UI_TripleCheckButton : public Fl_Group { /* this button has three states to represent how a search should check against a boolean value: 1. want value to be FALSE (show with red 'X') 2. want value to be TRUE (show with green tick) 3. don't care about value (show with black '?') */ private: int _value; // -1, 0, +1 Fl_Button * false_but; Fl_Button * true_but; Fl_Button * other_but; void Update() { false_but->hide(); true_but->hide(); other_but->hide(); if (_value < 0) false_but->show(); else if (_value > 0) true_but->show(); else other_but->show(); redraw(); } void BumpValue() { _value = (_value < 0) ? 0 : (_value == 0) ? 1 : -1; Update(); } static void button_callback(Fl_Widget *w, void *data) { UI_TripleCheckButton *G = (UI_TripleCheckButton *)data; G->BumpValue(); G->do_callback(); } public: UI_TripleCheckButton(int X, int Y, int W, int H, const char *label = NULL) : Fl_Group(X, Y, W, H), _value(0) { if (label) { Fl_Box *box = new Fl_Box(FL_NO_BOX, X, Y, W, H, label); box->align(FL_ALIGN_LEFT); } false_but = new Fl_Button(X, Y, W, H, "N"); false_but->labelcolor(FL_RED); false_but->labelsize(H*2/3); false_but->callback(button_callback, this); true_but = new Fl_Button(X, Y, W, H, "Y"); true_but->labelfont(FL_HELVETICA_BOLD); true_but->labelcolor(fl_rgb_color(0, 176, 0)); true_but->labelsize(H*2/3); true_but->callback(button_callback, this); other_but = new Fl_Button(X, Y, W, H, "-"); other_but->labelsize(H*3/4); other_but->callback(button_callback, this); end(); resizable(NULL); Update(); } virtual ~UI_TripleCheckButton() { } public: int value() const { return _value; } void value(int new_value) { _value = new_value; Update(); } }; //------------------------------------------------------------------------ enum { WHAT_TEXT_SIZE = 17, }; #define HIDE_BG (config::gui_scheme == 2 ? FL_DARK3 : FL_DARK1) UI_FindAndReplace::UI_FindAndReplace(Instance &inst, int X, int Y, int W, int H) : Fl_Group(X, Y, W, H, NULL), cur_obj(), find_numbers(new number_group_c), tag_numbers(new number_group_c), whatDefs { { "Things", THING_MODE_COL, ObjType::things, WF_WANT_DESC, BrowserMode::things, &UI_FindAndReplace::Match_Thing, {} }, { "Line Textures", LINE_MODE_COL, ObjType::linedefs, 0, BrowserMode::textures, &UI_FindAndReplace::Match_LineDef, {} }, { "Sector Flats", SECTOR_MODE_COL, ObjType::sectors, 0, BrowserMode::flats, &UI_FindAndReplace::Match_Sector, {} }, { "Lines by Type", FL_GREEN, ObjType::linedefs, WF_WANT_DESC, BrowserMode::lineTypes, &UI_FindAndReplace::Match_LineType, {} }, { "Sectors by Type", fl_rgb_color(255,160,0), ObjType::sectors, WF_WANT_DESC, BrowserMode::sectorTypes, &UI_FindAndReplace::Match_SectorType, {} } }, inst(inst) { box(FL_FLAT_BOX); color(WINDOW_BG, WINDOW_BG); /* ---- FIND AREA ---- */ Fl_Group *grp1 = new Fl_Group(X, Y, W, 210); grp1->box(FL_UP_BOX); { Fl_Button *hide_button = new Fl_Button(X + 8, Y + 12, 22, 22, "X"); hide_button->color(HIDE_BG, HIDE_BG); hide_button->labelsize(14); hide_button->callback(hide_callback, this); Fl_Box *title = new Fl_Box(X + 60, Y + 10, W - 70, 30, "Find and Replace"); title->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); title->labelsize(22); what = new Fl_Choice(X+60, Y+46, W - 120, 33); what->textsize(WHAT_TEXT_SIZE); what->add(joined("|", whatDefs, NUM_What, [](const auto &def){ return def.label; }).c_str()); what->value(What_things); what->callback(what_kind_callback, this); UpdateWhatColor(); find_match = new Fl_Input(X+75, Y+95, 135, 25, "Match: "); find_match->when(FL_WHEN_CHANGED); find_match->callback(find_match_callback, this); find_desc = new Fl_Output(X+75, Y+125, 135, 25, "Desc: "); find_pic = new UI_Pic(inst, X+225, Y+95, 64, 64, "Choose"); find_pic->callback((Fl_Callback *)choose_callback, this); // NOTE: no point allowing highlight when copy'n'paste don't work // find_pic->AllowHighlight(true); find_but = new Fl_Button(X+50, Y+165, 90, 30, "Find"); find_but->labelfont(FL_HELVETICA_BOLD); find_but->callback(find_but_callback, this); select_all_but = new Fl_Button(X+160, Y+165, 105, 30, "Select All"); select_all_but->callback(select_all_callback, this); } grp1->end(); /* ---- REPLACE AREA ---- */ Fl_Group *grp2 = new Fl_Group(X, Y + 214, W, 132); grp2->box(FL_UP_BOX); { rep_value = new Fl_Input(X+75, Y+230, 135, 25, "New: "); rep_value->when(FL_WHEN_CHANGED); rep_value->callback(rep_value_callback, this); rep_desc = new Fl_Output(X+75, Y+260, 135, 25, "Desc: "); rep_pic = new UI_Pic(inst, X+225, Y+230, 64, 64, "Choose"); rep_pic->callback((Fl_Callback *)choose_callback, this); // rep_pic->AllowHighlight(true); apply_but = new Fl_Button(X+45, Y+300, 90, 30, "Replace"); apply_but->labelfont(FL_HELVETICA_BOLD); apply_but->callback(apply_but_callback, this); replace_all_but = new Fl_Button(X+160, Y+300, 105, 30, "Replace All"); replace_all_but->callback(replace_all_callback, this); } grp2->end(); /* ---- FILTER AREA ---- */ Fl_Group *grp3 = new Fl_Group(X, Y + 350, W, H - 350); grp3->box(FL_UP_BOX); { filter_toggle = new Fl_Toggle_Button(X+15, Y+356, 30, 30, "v"); filter_toggle->labelsize(16); filter_toggle->color(FL_DARK3, FL_DARK3); filter_toggle->callback(filter_toggle_callback, this); filter_toggle->clear_visible_focus(); Fl_Box *f_text = new Fl_Box(X+60, Y+356, 200, 30, "Search Filters"); f_text->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); f_text->labelsize(16); filter_group = new Fl_Group(X, Y+391, W, H-391); { // common stuff restrict_to_sel = new Fl_Check_Button(X+10, Y+390, 80, 22, " Restrict to Selection"); previous_sel = new selection_c(); tag_input = new Fl_Input(X+117, Y+417, 130, 24, "Tag match:"); tag_input->when(FL_WHEN_CHANGED); tag_input->callback(tag_input_callback, this); // thing stuff o_easy = new UI_TripleCheckButton(X+105, Y+444, 28, 26, "easy: "); o_medium = new UI_TripleCheckButton(X+105, Y+474, 28, 26, "medium: "); o_hard = new UI_TripleCheckButton(X+105, Y+504, 28, 26, "hard: "); o_sp = new UI_TripleCheckButton(X+220, Y+444, 28, 26, "sp: "); o_coop = new UI_TripleCheckButton(X+220, Y+474, 28, 26, "coop: "); o_dm = new UI_TripleCheckButton(X+220, Y+504, 28, 26, "dm: "); // sector stuff o_floors = new Fl_Check_Button(X+45, Y+448, 80, 22, " floors"); o_ceilings = new Fl_Check_Button(X+45, Y+470, 80, 22, " ceilings"); o_skies = new Fl_Check_Button(X+45, Y+492, 80, 22, " skies"); // linedef stuff o_lowers = new Fl_Check_Button(X+45, Y+448, 80, 22, " lowers"); o_uppers = new Fl_Check_Button(X+45, Y+470, 80, 22, " uppers"); o_rails = new Fl_Check_Button(X+45, Y+492, 80, 22, " rail"); o_one_sided = new Fl_Check_Button(X+155, Y+448, 80, 22, " one-sided"); o_two_sided = new Fl_Check_Button(X+155, Y+470, 80, 22, " two-sided"); } filter_group->end(); filter_group->hide(); UpdateWhatFilters(); } grp3->end(); grp3->resizable(NULL); resizable(grp3); end(); Clear(); } UI_FindAndReplace::~UI_FindAndReplace() { delete tag_numbers; delete find_numbers; } void UI_FindAndReplace::hide_callback(Fl_Widget *w, void *data) { auto box = static_cast(data); box->inst.main_win->HideSpecialPanel(); } void UI_FindAndReplace::UpdateWhatColor() { auto value = static_cast(what->value()); assert(value >= 0 && value < NUM_What); what->color(whatDefs[value].color); } // // Initializes the dynamic fields of the whatDefs if not made already // void UI_FindAndReplace::ensureInitWhatFilters() { if(initializedWhatWidgets) return; initializedWhatWidgets = true; whatDefs[What_things].filterWidgets = { o_easy, o_medium, o_hard, o_sp, o_coop, o_dm }; whatDefs[What_lineTextures].filterWidgets = { o_lowers, o_uppers, o_rails, o_one_sided, o_two_sided }; whatDefs[What_sectorFlats].filterWidgets = { o_floors, o_ceilings, o_skies }; whatDefs[What_linesByType].filterWidgets = { o_one_sided, o_two_sided }; } void UI_FindAndReplace::UpdateWhatFilters() { ensureInitWhatFilters(); auto x = static_cast(what->value()); // common stuff if (x == What_things && inst.loaded.levelFormat == MapFormat::doom) { tag_input->deactivate(); tag_input->value(""); } else { tag_input->activate(); } for(int whatVal = 0; whatVal < NUM_What; ++whatVal) if(x != whatVal) for(Fl_Widget *widget : whatDefs[whatVal].filterWidgets) widget->hide(); for(Fl_Widget *widget : whatDefs[x].filterWidgets) widget->show(); // vanilla DOOM : always hide SP and COOP flags if (x == What_things && ! inst.conf.features.coop_dm_flags && inst.loaded.levelFormat == MapFormat::doom) { o_sp->hide(); o_coop->hide(); } } void UI_FindAndReplace::rawShowFilter(int value) { if (value) { filter_toggle->label("^"); filter_group->show(); } else { filter_toggle->label("v"); filter_group->hide(); } } void UI_FindAndReplace::filter_toggle_callback(Fl_Widget *w, void *data) { UI_FindAndReplace *box = (UI_FindAndReplace *)data; Fl_Toggle_Button *toggle = (Fl_Toggle_Button *)w; box->rawShowFilter(toggle->value()); } void UI_FindAndReplace::what_kind_callback(Fl_Widget *w, void *data) { UI_FindAndReplace *box = (UI_FindAndReplace *)data; ObjType prev_type = box->cur_obj.type; bool want_descs = true; auto value = static_cast(box->what->value()); assert(value >= 0 && value < NUM_What); box->cur_obj.type = box->whatDefs[value].type; want_descs = !!(box->whatDefs[value].flags & WF_WANT_DESC); // only clear everything when type changes if (prev_type != box->cur_obj.type) { box->Clear(); } box->UpdateWhatColor(); box->UpdateWhatFilters(); if (want_descs) { box->find_desc->activate(); box-> rep_desc->activate(); } else { box->find_desc->deactivate(); box-> rep_desc->deactivate(); } } void UI_FindAndReplace::Open() { show(); WhatFromEditMode(); // this will do a Clear() for us what->do_callback(); Fl::focus(find_match); UnselectPics(); } void UI_FindAndReplace::Clear() { cur_obj.clear(); find_match->value(""); find_desc->value(""); find_but->label("Find"); find_pic->Clear(); rep_value->value(""); rep_desc->value(""); rep_pic->Clear(); UnselectPics(); find_but->deactivate(); select_all_but->deactivate(); apply_but->deactivate(); replace_all_but->deactivate(); filter_toggle->value(0); filter_toggle->do_callback(); ResetFilters(); } void UI_FindAndReplace::ResetFilters() { tag_input->value(""); tag_numbers->clear(); restrict_to_sel->value(0); // thing filters o_easy ->value(0); o_medium->value(0); o_hard ->value(0); o_sp ->value(0); o_coop->value(0); o_dm ->value(0); ComputeFlagMask(); // sector filters o_floors ->value(1); o_ceilings->value(1); o_skies ->value(1); // linedef filters o_lowers->value(1); o_uppers->value(1); o_rails ->value(1); o_one_sided->value(1); o_two_sided->value(1); } bool UI_FindAndReplace::WhatFromEditMode() { for(int whatType = 0; whatType < NUM_What; ++whatType) if(inst.edit.mode == whatDefs[whatType].type) { what->value(whatType); return true; } return false; } void UI_FindAndReplace::find_but_callback(Fl_Widget *w, void *data) { UI_FindAndReplace *box = (UI_FindAndReplace *)data; box->FindNext(); } void UI_FindAndReplace::select_all_callback(Fl_Widget *w, void *data) { UI_FindAndReplace *box = (UI_FindAndReplace *)data; box->DoAll(false /* replace */); } void UI_FindAndReplace::apply_but_callback(Fl_Widget *w, void *data) { UI_FindAndReplace *box = (UI_FindAndReplace *)data; box->DoReplace(); } void UI_FindAndReplace::replace_all_callback(Fl_Widget *w, void *data) { UI_FindAndReplace *box = (UI_FindAndReplace *)data; box->DoAll(true /* replace */); } void UI_FindAndReplace::find_match_callback(Fl_Widget *w, void *data) { UI_FindAndReplace *box = (UI_FindAndReplace *)data; bool is_valid = box->CheckInput(box->find_match, box->find_desc, box->find_pic, box->find_numbers); if (is_valid) { box->find_but->activate(); box->select_all_but->activate(); box->find_match->textcolor(FL_FOREGROUND_COLOR); box->find_match->redraw(); } else { box->find_but->deactivate(); box->select_all_but->deactivate(); box->find_match->textcolor(FL_RED); box->find_match->redraw(); } // update Replace section too box->rep_value->do_callback(); } void UI_FindAndReplace::rep_value_callback(Fl_Widget *w, void *data) { UI_FindAndReplace *box = (UI_FindAndReplace *)data; bool is_valid = box->CheckInput(box->rep_value, box->rep_desc, box->rep_pic); if (is_valid) { box->rep_value->textcolor(FL_FOREGROUND_COLOR); box->rep_value->redraw(); } else { box->rep_value->textcolor(FL_RED); box->rep_value->redraw(); } bool is_usable = (is_valid && box->find_but->active()); if (is_usable) box->replace_all_but->activate(); else box->replace_all_but->deactivate(); // require an found object too before 'Replace' button can be used if (box->cur_obj.is_nil()) is_usable = false; if (is_usable) box->apply_but->activate(); else box->apply_but->deactivate(); } bool UI_FindAndReplace::CheckInput(Fl_Input *w, Fl_Output *desc, UI_Pic *pic, number_group_c *num_grp) { const char *inp_text = w->value(); if (strlen(inp_text) == 0) { desc->value(""); pic->Clear(); return false; } // Line Textures if (what->value() == What_lineTextures) { pic->GetTex(inp_text); return true; } // Sector Flats if (what->value() == What_sectorFlats) { pic->GetFlat(inp_text); return true; } // for numeric types, parse the number(s) and/or ranges int type_num = 0; if (! num_grp) { char *endptr; type_num = static_cast(strtol(inp_text, &endptr, 0 /* allow hex */)); // just check the number is valid if (*endptr != 0) { desc->value("(parse error)"); return false; } } else { num_grp->clear(); if (! num_grp->ParseString(inp_text)) { desc->value("(parse error)"); return false; } if (num_grp->is_everything()) { desc->value("(everything)"); return true; } else if (! num_grp->is_single()) { desc->value("(multi-match)"); return true; } type_num = num_grp->grab_first(); } switch (what->value()) { case What_things: // Things { const thingtype_t &info = inst.conf.getThingType(type_num); desc->value(info.desc.c_str()); pic->GetSprite(type_num, FL_DARK2); break; } case What_linesByType: // Lines by Type { const linetype_t &info = inst.conf.getLineType(type_num); desc->value(info.desc.c_str()); break; } case What_sectorsByType: // Sectors by Type { int mask = (inst.conf.features.gen_sectors == GenSectorFamily::zdoom) ? 255 : (inst.conf.features.gen_sectors != GenSectorFamily::none) ? 31 : 65535; const sectortype_t & info = inst.M_GetSectorType(type_num & mask); desc->value(info.desc.c_str()); break; } default: break; } return true; } void UI_FindAndReplace::tag_input_callback(Fl_Widget *w, void *data) { UI_FindAndReplace *box = (UI_FindAndReplace *)data; bool is_valid = box->CheckNumberInput(box->tag_input, box->tag_numbers); if (is_valid) { box->tag_input->textcolor(FL_FOREGROUND_COLOR); box->tag_input->redraw(); } else { // uhhh, cannot disable all the search buttons [ too hard ] // so..... showing red is the all we can do.... box->tag_input->textcolor(FL_RED); box->tag_input->redraw(); } } bool UI_FindAndReplace::CheckNumberInput(Fl_Input *w, number_group_c *num_grp) { num_grp->clear(); // an empty string will mean match everything if (w->size() == 0) return true; if (num_grp->ParseString(w->value())) return true; return false; } //------------------------------------------------------------------------ BrowserMode UI_FindAndReplace::GetKind() { // these letters are same as the Browser uses auto v = static_cast(what->value()); if (v < 0 || v >= NUM_What) return BrowserMode::invalid; return whatDefs[v].browserMode; } bool UI_FindAndReplace::ClipboardOp(EditCommand op) { // NOTE: the logic below is disabled since texture copy'n'paste // simply does not work properly when an input widget has // the focus (especially paste). #if 1 return false; #else // current mode must be Line Textures or Sector Flats if (what->value() < 1 || what->value() > 2) return false; bool is_replace = false; // a highlighted pic overrides any selected one if (find_pic->Highlighted()) is_replace = false; else if (rep_pic->Highlighted()) is_replace = true; else if (find_pic->Selected()) is_replace = false; else if (rep_pic->Selected()) is_replace = true; else return false; switch (op) { case 'c': CB_Copy(is_replace); break; case 'v': CB_Paste(is_replace); break; case 'x': Beep("cannot cut that"); break; case 'd': CB_Delete(is_replace); break; } return true; #endif } void UI_FindAndReplace::CB_Copy(bool is_replace) { const char *tex_name = is_replace ? rep_value->value() : find_match->value(); // check for a valid, single name if (strchr(tex_name, ',') != NULL) tex_name = ""; if (is_null_tex(tex_name)) tex_name = ""; if (tex_name[0]) { bool is_known = (what->value() == What_lineTextures) ? inst.wad.images.W_TextureIsKnown(inst.conf, tex_name) : inst.wad.images.W_FlatIsKnown(inst.conf, tex_name); if (!is_known) tex_name = ""; } if (tex_name[0] == 0) { inst.Beep("invalid texture name"); return; } if (what->value() == What_lineTextures) Texboard_SetTex(tex_name, inst.conf); else Texboard_SetFlat(tex_name, inst.conf); } void UI_FindAndReplace::CB_Paste(bool is_replace) { Fl_Input *inp = is_replace ? rep_value : find_match; StringID tex_num = (what->value() == What_lineTextures) ? Texboard_GetTexNum(inst.conf) : Texboard_GetFlatNum(inst.conf); SString tex_name = BA_GetString(tex_num); InsertName(inp, false /* append */, tex_name); } void UI_FindAndReplace::CB_Delete(bool is_replace) { if (!is_replace) { find_match->value(""); find_pic->Selected(false); find_match_callback(find_match, this); } else { rep_value->value(""); rep_pic->Selected(false); rep_value_callback(rep_value, this); } } void UI_FindAndReplace::BrowsedItem(BrowserMode kind, int number, const char *name, int e_state) { if (kind == BrowserMode::flats) kind = BrowserMode::textures; if (kind != GetKind()) { if (kind == BrowserMode::textures && GetKind() == BrowserMode::flats) { /* ok */ } else { return; } } // determine which box the user intended int sel_pics = find_pic->Selected() ? 1 : rep_pic->Selected() ? 2 : 0; if (sel_pics == 0) { sel_pics = (Fl::focus() == find_match || Fl::focus() == find_desc) ? 1 : (Fl::focus() == rep_value || Fl::focus() == rep_desc) ? 2 : 0; } if (sel_pics == 0) sel_pics = 1; bool is_replace = (sel_pics == 2); char append = 0; // only append when SHIFT key was pressed if ((e_state & FL_SHIFT) && !is_replace) { append = ','; } // insert the chosen item Fl_Input *inp = is_replace ? rep_value : find_match; if (kind == BrowserMode::textures || kind == BrowserMode::flats) { InsertName(inp, append, name); } else { // already present? if (! is_replace && find_numbers->get(number)) return; InsertNumber(inp, append, number); } } void UI_FindAndReplace::InsertName(Fl_Input *inp, char append, const SString &name) { if (append) { int len = inp->size(); // insert a separator, unless user has already put one there if (NeedSeparator(inp)) { char buf[4]; buf[0] = append; buf[1] = 0; inp->replace(len, len, buf); len += 1; } inp->replace(len, len, name.c_str()); } else { inp->value(name.c_str()); } inp->do_callback(); Fl::focus(inp); inp->redraw(); } void UI_FindAndReplace::InsertNumber(Fl_Input *inp, char append, int number) { InsertName(inp, append, SString::printf("%d", number)); } bool UI_FindAndReplace::NeedSeparator(Fl_Input *inp) const { const char *str = inp->value(); // nothing but whitespace? --> no need while (isspace(*str)) str++; if (str[0] == 0) return false; // ends with a punctuation symbol? --> no need int p = (int)strlen(str) - 1; while (p >= 0 && isspace(str[p])) p--; if (p >= 0) { if (str[p] == '_') return true; if (str[p] == '*') return true; if (ispunct(str[p])) return false; } return true; } void UI_FindAndReplace::UnselectPics() { find_pic->Selected(false); rep_pic->Selected(false); } void UI_FindAndReplace::choose_callback(UI_Pic *w, void *data) { UI_FindAndReplace *box = (UI_FindAndReplace *)data; // ensure corresponding input widget has the focus if (w == box->find_pic) { box->find_pic->Selected(! box->find_pic->Selected()); if (box->find_pic->Selected()) { box->inst.main_win->BrowserMode(box->GetKind()); Fl::focus(box->find_match); box->find_match->redraw(); box->rep_pic->Selected(false); } } else { box->rep_pic->Selected(! box->rep_pic->Selected()); if (box->rep_pic->Selected()) { box->inst.main_win->BrowserMode(box->GetKind()); Fl::focus(box->rep_value); box->rep_value->redraw(); box->find_pic->Selected(false); } } } //------------------------------------------------------------------------ bool UI_FindAndReplace::FindNext() { // this can happen via CTRL-G shortcut (View / Go to next) if (strlen(find_match->value()) == 0) { inst.Beep("No find active!"); return false; } ComputeFlagMask(); if (cur_obj.type != inst.edit.mode) { inst.Editor_ChangeMode_Raw(cur_obj.type); } bool is_first = cur_obj.is_nil(); // grab the selection *once*, on the first find if (is_first) { previous_sel->change_type(inst.edit.mode); previous_sel->merge(*inst.edit.Selected); // catch a common user mistake if (filter_toggle->value() && restrict_to_sel->value() && inst.edit.Selected->empty()) { inst.Beep("EMPTY SELECTION!"); return false; } } inst.Selection_Clear(); int start_at = cur_obj.is_nil() ? 0 : (cur_obj.num + 1); int total = inst.level.numObjects(cur_obj.type); for (int idx = start_at ; idx < total ; idx++) { if (! MatchesObject(idx)) continue; if (! Filter_PrevSel(idx)) continue; // found! { cur_obj.num = idx; if (is_first) { find_but->label("Next"); rep_value->do_callback(); } inst.GoToObject(cur_obj); inst.Status_Set("found #%d", idx); return true; } } // nothing (else) was found cur_obj.clear(); find_but->label("Find"); rep_value->do_callback(); if (is_first) inst.Beep("Nothing found"); else inst.Beep("No more found"); return false; } void UI_FindAndReplace::DoReplace() { // sanity check [ should never happen ] if (strlen(find_match->value()) == 0 || strlen( rep_value->value()) == 0) { inst.Beep("Bad replace"); return; } // this generally can't happen either if (cur_obj.is_nil()) { inst.Beep("No object to replace!"); return; } StringID replace_tex_id = BA_InternaliseString(NormalizeTex(rep_value->value())); { EditOperation op(inst.level.basis); op.setMessage("replacement in %s #%d", NameForObjectType(cur_obj.type), cur_obj.num); ApplyReplace(op, cur_obj.num, replace_tex_id); } // move onto next object FindNext(); } bool UI_FindAndReplace::MatchesObject(int idx) { auto value = static_cast(what->value()); if(value < 0 || value >= NUM_What) return false; return (this->*whatDefs[value].match)(idx); } void UI_FindAndReplace::ApplyReplace(EditOperation &op, int idx, StringID new_tex) { SYS_ASSERT(idx >= 0); switch (what->value()) { case What_things: // Things Replace_Thing(op, idx); break; case What_lineTextures: // LineDefs (texturing) Replace_LineDef(op, idx, new_tex); break; case What_sectorFlats: // Sectors (texturing) Replace_Sector(op, idx, new_tex); break; case What_linesByType: // Lines by Type Replace_LineType(op, idx); break; case What_sectorsByType: // Sectors by Type Replace_SectorType(op, idx); break; default: break; } } void UI_FindAndReplace::DoAll(bool replace) { if (strlen(find_match->value()) == 0) { inst.Beep("No find active!"); return; } // catch a common user mistake if (filter_toggle->value() && restrict_to_sel->value() && inst.edit.Selected->empty()) { inst.Beep("EMPTY SELECTION!"); return; } ComputeFlagMask(); if (cur_obj.type != inst.edit.mode) inst.Editor_ChangeMode_Raw(cur_obj.type); StringID replace_tex_id; EditOperation *op; // hackish way to control lifetime if (replace) { replace_tex_id = BA_InternaliseString(NormalizeTex(rep_value->value())); op = new EditOperation(inst.level.basis); } // we select objects even in REPLACE mode // (gives the user a visual indication that stuff was done) previous_sel->change_type(inst.edit.mode); previous_sel->merge(*inst.edit.Selected); // this clears the selection inst.edit.Selected->change_type(inst.edit.mode); int total = inst.level.numObjects(cur_obj.type); int count = 0; for (int idx = 0 ; idx < total ; idx++) { if (! MatchesObject(idx)) continue; if (! Filter_PrevSel(idx)) continue; count++; if (replace) ApplyReplace(*op, idx, replace_tex_id); inst.edit.Selected->set(idx); } if (count == 0) inst.Beep("Nothing found"); else inst.Status_Set("found %d objects", count); if (replace) { op->setMessageForSelection("replacement in", *inst.edit.Selected); delete op; } if (count > 0) { inst.GoToSelection(); inst.edit.error_mode = true; } if (replace) { cur_obj.clear(); rep_value->do_callback(); } inst.RedrawMap(); } //------------------------------------------------------------------------ // MATCHING METHODS //------------------------------------------------------------------------ bool UI_FindAndReplace::Match_Thing(int idx) { const auto T = inst.level.things[idx]; if (! find_numbers->get(T->type)) return false; // skill/mode flag filter if ((T->options & options_mask) != options_value) return false; if (inst.loaded.levelFormat == MapFormat::hexen && ! Filter_Tag(T->tid)) return false; return true; } bool UI_FindAndReplace::Match_LineDef(int idx) { const auto L = inst.level.linedefs[idx]; if (! Filter_Tag(L->tag) || ! Filter_Sides(L.get())) return false; const char *pattern = find_match->value(); for (int pass = 0 ; pass < 2 ; pass++) { const SideDef *SD = (pass == 0) ? inst.level.getRight(*L) : inst.level.getLeft(*L); if (! SD) continue; SString L_tex = SD->LowerTex(); SString U_tex = SD->UpperTex(); SString R_tex = SD->MidTex(); if (! L->TwoSided()) { L_tex = R_tex; R_tex = U_tex = NULL; } if (!filter_toggle->value() || o_lowers->value()) if (L_tex.good() && Pattern_Match(L_tex, pattern)) return true; if (!filter_toggle->value() || o_uppers->value()) if (U_tex.good() && Pattern_Match(U_tex, pattern)) return true; if (!filter_toggle->value() || o_rails->value()) if (R_tex.good() && Pattern_Match(R_tex, pattern, true /* is_rail */)) return true; } return false; } bool UI_FindAndReplace::Match_Sector(int idx) { const auto sector = inst.level.sectors[idx]; if (! Filter_Tag(sector->tag)) return false; const char *pattern = find_match->value(); if (!filter_toggle->value() || o_floors->value()) if (Pattern_Match(sector->FloorTex(), pattern)) return true; SString ceil_tex = sector->CeilTex(); if (!filter_toggle->value() || (!inst.is_sky(ceil_tex) && o_ceilings->value()) || (inst.is_sky(ceil_tex) && o_skies->value()) ) if (Pattern_Match(ceil_tex, pattern)) return true; return false; } bool UI_FindAndReplace::Match_LineType(int idx) { const auto L = inst.level.linedefs[idx]; if (! find_numbers->get(L->type)) return false; if (! Filter_Tag(L->tag) || ! Filter_Sides(L.get())) return false; return true; } bool UI_FindAndReplace::Match_SectorType(int idx) { const auto sector = inst.level.sectors[idx]; int mask = (inst.conf.features.gen_sectors == GenSectorFamily::zdoom) ? 255 : (inst.conf.features.gen_sectors != GenSectorFamily::none) ? 31 : 65535; if (! find_numbers->get(sector->type & mask)) return false; if (! Filter_Tag(sector->tag)) return false; return true; } bool UI_FindAndReplace::Filter_PrevSel(int idx) { if (! filter_toggle->value()) return true; if (! restrict_to_sel->value()) return true; return previous_sel->get(idx); } bool UI_FindAndReplace::Filter_Tag(int tag) { if (! filter_toggle->value()) return true; // an empty string means everything (same as '*') if (tag_input->size() == 0) return true; return tag_numbers->get(tag); } bool UI_FindAndReplace::Filter_Sides(const LineDef *L) { if (filter_toggle->value()) { if (! o_one_sided->value() && L->OneSided()) return false; if (! o_two_sided->value() && L->TwoSided()) return false; } return true; } void UI_FindAndReplace::ComputeFlagMask() { options_mask = 0; options_value = 0; if (! filter_toggle->value()) { // this will always succeed return; } #define FLAG_FROM_WIDGET(w, mul, flag) \ if ((w)->value() != 0) \ { \ options_mask |= (flag); \ if ((w)->value() * (mul) > 0) \ options_value |= (flag); \ } FLAG_FROM_WIDGET( o_easy, 1, MTF_Easy); FLAG_FROM_WIDGET(o_medium, 1, MTF_Medium); FLAG_FROM_WIDGET( o_hard, 1, MTF_Hard); if (inst.conf.features.coop_dm_flags) { FLAG_FROM_WIDGET( o_sp, -1, MTF_Not_SP); FLAG_FROM_WIDGET(o_coop, -1, MTF_Not_COOP); FLAG_FROM_WIDGET( o_dm, -1, MTF_Not_DM); } else // vanilla DOOM { FLAG_FROM_WIDGET(o_dm, 1, MTF_Not_SP); } #undef FLAG_FROM_WIDGET } bool UI_FindAndReplace::Pattern_Match(const SString &tex, const SString &pattern, bool is_rail) { // allow multiple names (simple patterns) separated by commas. // they can include '*' as a wildcard. SString local_pat; int patternIndex = 0; for (;;) { char patternChar = pattern[patternIndex]; if (patternChar == 0 || patternChar == ',' || patternChar == '/' || patternChar == '|') { // do not match the empty rail texture against the "*" wildcard. // [ this is debatable, but I think this prevents making changes // which the user really didn't want or expect ] if (is_rail && is_null_tex(tex) && local_pat[0] == '*') { // no match } else { if (fl_filename_match(tex.c_str(), local_pat.c_str())) return true; } if (patternChar == 0) return false; // begin new part, skip comma local_pat.clear(); patternIndex++; } local_pat.push_back(patternChar); ++patternIndex; } } //------------------------------------------------------------------------ // REPLACE METHODS //------------------------------------------------------------------------ void UI_FindAndReplace::Replace_Thing(EditOperation &op, int idx) { int new_type = atoi(rep_value->value()); op.changeThing(idx, Thing::F_TYPE, new_type); } void UI_FindAndReplace::Replace_LineDef(EditOperation &op, int idx, StringID new_tex) { const auto L = inst.level.linedefs[idx]; const char *pattern = find_match->value(); for (int pass = 0 ; pass < 2 ; pass++) { int sd_num = (pass == 0) ? L->right : L->left; const SideDef *SD = (pass == 0) ? inst.level.getRight(*L) : inst.level.getLeft(*L); if (! SD) continue; SString L_tex = SD->LowerTex(); SString U_tex = SD->UpperTex(); SString R_tex = SD->MidTex(); if (! L->TwoSided()) { if (!filter_toggle->value() || o_lowers->value()) if (R_tex.good() && Pattern_Match(R_tex, pattern)) op.changeSidedef(sd_num, SideDef::F_MID_TEX, new_tex); continue; } if (!filter_toggle->value() || o_lowers->value()) if (L_tex.good() && Pattern_Match(L_tex, pattern)) op.changeSidedef(sd_num, SideDef::F_LOWER_TEX, new_tex); if (!filter_toggle->value() || o_uppers->value()) if (U_tex.good() && Pattern_Match(U_tex, pattern)) op.changeSidedef(sd_num, SideDef::F_UPPER_TEX, new_tex); if (!filter_toggle->value() || o_rails->value()) if (R_tex.good() && Pattern_Match(R_tex, pattern, true /* is_rail */)) op.changeSidedef(sd_num, SideDef::F_MID_TEX, new_tex); } } void UI_FindAndReplace::Replace_Sector(EditOperation &op, int idx, StringID new_tex) { const auto sector = inst.level.sectors[idx]; const char *pattern = find_match->value(); if (!filter_toggle->value() || o_floors->value()) if (Pattern_Match(sector->FloorTex(), pattern)) op.changeSector(idx, Sector::F_FLOOR_TEX, new_tex); SString ceil_tex = sector->CeilTex(); if (!filter_toggle->value() || (!inst.is_sky(ceil_tex) && o_ceilings->value()) || (inst.is_sky(ceil_tex) && o_skies->value()) ) if (Pattern_Match(ceil_tex, pattern)) op.changeSector(idx, Sector::F_CEIL_TEX, new_tex); } void UI_FindAndReplace::Replace_LineType(EditOperation &op, int idx) { int new_type = atoi(rep_value->value()); op.changeLinedef(idx, LineDef::F_TYPE, new_type); } void UI_FindAndReplace::Replace_SectorType(EditOperation &op, int idx) { int mask = (inst.conf.features.gen_sectors == GenSectorFamily::zdoom) ? 255 : (inst.conf.features.gen_sectors != GenSectorFamily::none) ? 31 : 65535; int old_type = inst.level.sectors[idx]->type; int new_type = atoi(rep_value->value()); op.changeSector(idx, Sector::F_TYPE, (old_type & ~mask) | (new_type & mask)); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_replace.h000066400000000000000000000127471464327712600206240ustar00rootroot00000000000000//------------------------------------------------------------------------ // FIND AND REPLACE //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2015-2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_REPLACE_H__ #define __EUREKA_UI_REPLACE_H__ #include "e_cutpaste.h" class Fl_Choice; class Fl_Output; class LineDef; class number_group_c; class UI_TripleCheckButton; class UI_FindAndReplace : public Fl_Group { private: enum What { What_things, What_lineTextures, What_sectorFlats, What_linesByType, What_sectorsByType, NUM_What }; enum WhatFlags { WF_WANT_DESC = 1 }; enum { NUM_FILTER_WIDGETS = 7 }; struct WhatDef { const char *label; Fl_Color color; ObjType type; unsigned flags; BrowserMode browserMode; bool (UI_FindAndReplace::*match)(int idx); std::vector filterWidgets; }; // object kind we are finding / replacing Fl_Choice *what; // current (found) object Objid cur_obj; // --- FIND AREA --- Fl_Input *find_match; UI_Pic *find_pic; Fl_Output *find_desc; Fl_Button *find_but; Fl_Button *select_all_but; // for numeric types, this contains the number(s) to match number_group_c *find_numbers; // --- REPLACE AREA --- Fl_Input *rep_value; UI_Pic *rep_pic; Fl_Output *rep_desc; Fl_Button *apply_but; Fl_Button *replace_all_but; // --- FILTER AREA --- Fl_Toggle_Button *filter_toggle; Fl_Group *filter_group; // common stuff Fl_Input * tag_input; number_group_c * tag_numbers; Fl_Check_Button *restrict_to_sel; selection_c *previous_sel; // thing stuff UI_TripleCheckButton *o_easy; UI_TripleCheckButton *o_medium; UI_TripleCheckButton *o_hard; UI_TripleCheckButton *o_sp; UI_TripleCheckButton *o_coop; UI_TripleCheckButton *o_dm; int options_mask; int options_value; // sector filters Fl_Check_Button *o_floors; Fl_Check_Button *o_ceilings; Fl_Check_Button *o_skies; // linedef filters Fl_Check_Button *o_lowers; Fl_Check_Button *o_uppers; Fl_Check_Button *o_rails; Fl_Check_Button *o_one_sided; Fl_Check_Button *o_two_sided; WhatDef whatDefs[NUM_What]; bool initializedWhatWidgets = false; public: UI_FindAndReplace(Instance &inst, int X, int Y, int W, int H); virtual ~UI_FindAndReplace(); void Open(); BrowserMode GetKind(); // same as browser : 'O' 'T' 'F' 'L' 'S' // called by "Find" button in here, or CTRL-G shortcut bool FindNext(); bool ClipboardOp(EditCommand op); void BrowsedItem(BrowserMode kind, int number, const char *name, int e_state); private: void ensureInitWhatFilters(); void Clear(); void ResetFilters(); bool WhatFromEditMode(); void UpdateWhatColor(); void UpdateWhatFilters(); void ComputeFlagMask(); void UnselectPics(); void InsertName (Fl_Input *inp, char append, const SString &name); void InsertNumber(Fl_Input *inp, char append, int number); bool NeedSeparator(Fl_Input *inp) const; void rawShowFilter(int value); bool MatchesObject(int idx); void ApplyReplace (EditOperation &op, int idx, StringID new_tex); void DoReplace(); void DoAll(bool replace); // validate input and update desc and the picture bool CheckInput(Fl_Input *w, Fl_Output *desc, UI_Pic *pic, number_group_c *num_grp = NULL); // this used for Tag number bool CheckNumberInput(Fl_Input *w, number_group_c *num_grp); bool Pattern_Match(const SString &tex, const SString &pattern, bool is_rail = false); // specialized functions for each search modality bool Match_Thing(int idx); bool Match_LineDef(int idx); bool Match_LineType(int idx); bool Match_Sector(int idx); bool Match_SectorType(int idx); // return 'true' for pass, 'false' to reject bool Filter_Tag(int tag); bool Filter_Sides(const LineDef *L); bool Filter_PrevSel(int idx); void Replace_Thing(EditOperation &op, int idx); void Replace_LineDef(EditOperation &op, int idx, StringID new_tex); void Replace_LineType(EditOperation &op, int idx); void Replace_Sector(EditOperation &op, int idx, StringID new_tex); void Replace_SectorType(EditOperation &op, int idx); // clipboard stuff void CB_Copy(bool is_replace); void CB_Paste(bool is_replace); void CB_Delete(bool is_replace); private: static void hide_callback(Fl_Widget *w, void *data); static void what_kind_callback(Fl_Widget *w, void *data); static void choose_callback(UI_Pic *w, void *data); static void find_match_callback(Fl_Widget *w, void *data); static void find_but_callback(Fl_Widget *w, void *data); static void select_all_callback(Fl_Widget *w, void *data); static void rep_value_callback(Fl_Widget *w, void *data); static void apply_but_callback(Fl_Widget *w, void *data); static void replace_all_callback(Fl_Widget *w, void *data); static void filter_toggle_callback(Fl_Widget *w, void *data); static void tag_input_callback(Fl_Widget *w, void *data); Instance &inst; }; #endif /* __EUREKA_UI_REPLACE_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_scroll.cc000066400000000000000000000225461464327712600206430ustar00rootroot00000000000000//------------------------------------------------------------------------ // A decent scrolling widget //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2019 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include "m_config.h" #include "e_main.h" // Map_bound_xxx #include "r_render.h" #include "ui_window.h" #define HUGE_DIST (1 << 24) #define SCRBAR_BACK (config::gui_scheme == 2 ? FL_DARK3 : FL_DARK2) #define SCRBAR_COL (config::gui_scheme == 2 ? FL_DARK1 : FL_BACKGROUND_COLOR) // // UI_Scroll Constructor // UI_Scroll::UI_Scroll(int X, int Y, int W, int H, int _bar_side) : Fl_Group(X, Y, W, H, NULL), bar_side(_bar_side), resize_horiz_(false), top_y(0), bottom_y(0) { end(); if (_bar_side < 0) scrollbar = new Fl_Scrollbar(X, Y, SBAR_W, H, NULL); else scrollbar = new Fl_Scrollbar(X + W - SBAR_W, Y, SBAR_W, H, NULL); scrollbar->align(FL_ALIGN_LEFT); scrollbar->color(SCRBAR_BACK, SCRBAR_BACK); scrollbar->selection_color(SCRBAR_COL); scrollbar->callback(bar_callback, this); add(scrollbar); clip_children(1); resizable(NULL); } // // UI_Scroll Destructor // UI_Scroll::~UI_Scroll() { } void UI_Scroll::resize(int X, int Y, int W, int H) { // int ox = x(); // int oy = y(); // int oh = h(); int ow = w(); Fl_Group::resize(X, Y, W, H); if (bar_side < 0) scrollbar->resize(X, Y, SBAR_W, H); else scrollbar->resize(X+W-SBAR_W, Y, SBAR_W, H); int total_h = bottom_y - top_y; scrollbar->value(0, h(), 0, std::max(h(), total_h)); if (ow != W && resize_horiz_) { for (int i = 0 ; i < Children() ; i++) { Fl_Widget * w = Child(i); w->resize(X + (bar_side < 0 ? SBAR_W : 0), w->y(), W - SBAR_W, w->h()); } } } int UI_Scroll::handle(int event) { return Fl_Group::handle(event); } void UI_Scroll::bar_callback(Fl_Widget *w, void *data) { UI_Scroll * that = (UI_Scroll *)data; that->do_scroll(); } void UI_Scroll::do_scroll() { int pos = scrollbar->value(); int total_h = bottom_y - top_y; scrollbar->value(pos, h(), 0, std::max(h(), total_h)); reposition_all(y() - pos); redraw(); } void UI_Scroll::calc_extents() { if (Children() == 0) { top_y = bottom_y = 0; return; } top_y = HUGE_DIST; bottom_y = -HUGE_DIST; for (int i = 0 ; i < Children() ; i++) { Fl_Widget * w = Child(i); if (! w->visible()) continue; top_y = std::min(top_y, w->y()); bottom_y = std::max(bottom_y, w->y() + w->h()); } } void UI_Scroll::reposition_all(int start_y) { for (int i = 0 ; i < Children() ; i++) { Fl_Widget * w = Child(i); int y = start_y + (w->y() - top_y); w->position(w->x(), y); } calc_extents(); init_sizes(); } void UI_Scroll::Scroll(int delta) { int pixels; int line_size = scrollbar->linesize(); if (abs(delta) <= 1) pixels = std::max(1, line_size / 4); else if (abs(delta) == 2) pixels = line_size; else if (abs(delta) == 3) pixels = std::max(h() - line_size / 2, h() * 2 / 3); else pixels = HUGE_DIST; if (delta < 0) pixels = -pixels; ScrollByPixels(pixels); } void UI_Scroll::ScrollByPixels(int pixels) { int pos = scrollbar->value() + pixels; int total_h = bottom_y - top_y; if (pos > total_h - h()) pos = total_h - h(); if (pos < 0) pos = 0; scrollbar->value(pos, h(), 0, std::max(h(), total_h)); reposition_all(y() - pos); redraw(); } void UI_Scroll::JumpToChild(int i) { const Fl_Widget * w = Child(i); int diff = w->y() - top_y - scrollbar->value(); ScrollByPixels(diff); } //------------------------------------------------------------------------ // // PASS-THROUGHS // void UI_Scroll::Add(Fl_Widget *w) { add(w); } void UI_Scroll::Remove(Fl_Widget *w) { remove(w); } void UI_Scroll::Remove_first() { // skip scrollbar remove(1); } void UI_Scroll::Remove_all() { remove(scrollbar); clear(); resizable(NULL); add(scrollbar); } int UI_Scroll::Children() const { // ignore scrollbar return children() - 1; } Fl_Widget * UI_Scroll::Child(int i) const { SYS_ASSERT(child(0) == scrollbar); // skip scrollbar return child(1 + i); } void UI_Scroll::Init_sizes() { calc_extents(); init_sizes(); int total_h = bottom_y - top_y; scrollbar->value(0, h(), 0, std::max(h(), total_h)); } void UI_Scroll::Line_size(int pixels) { scrollbar->linesize(pixels); } //------------------------------------------------------------------------ #define INFO_BAR_H 30 UI_CanvasScroll::UI_CanvasScroll(Instance &inst, int X, int Y, int W, int H) : Fl_Group(X, Y, W, H), enable_bars(true), bound_x1(0), bound_x2(100), bound_y1(0), bound_y2(100), mInstance(inst) { for (int i = 0 ; i < 4 ; i++) last_bounds[i] = 12345678; box(FL_NO_BOX); vert = new Fl_Scrollbar(X, Y + INFO_BAR_H, SBAR_W, H - SBAR_W - INFO_BAR_H, NULL); vert->type(FL_VERTICAL); vert->align(FL_ALIGN_LEFT); vert->color(SCRBAR_BACK, SCRBAR_BACK); vert->selection_color(SCRBAR_COL); vert->callback(bar_callback, this); horiz = new Fl_Scrollbar(X + SBAR_W, Y + H - SBAR_W, W - SBAR_W, SBAR_W, NULL); horiz->type(FL_HORIZONTAL); horiz->align(FL_ALIGN_LEFT); horiz->color(SCRBAR_BACK, SCRBAR_BACK); horiz->selection_color(SCRBAR_COL); horiz->callback(bar_callback, this); canvas = new UI_Canvas(mInstance, X + SBAR_W, Y, W - SBAR_W, H - SBAR_W); resizable(canvas); status = new UI_StatusBar(inst, X, Y, W, INFO_BAR_H); end(); } UI_CanvasScroll::~UI_CanvasScroll() { } void UI_CanvasScroll::UpdateRenderMode() { int old_bars = enable_bars ? 1 : 0; int new_bars = config::map_scroll_bars && !mInstance.edit.render3d ? 1 : 0; int old_rend = status->visible() ? 1 : 0; int new_rend = mInstance.edit.render3d ? 1 : 0; // nothing changed? if (old_bars == new_bars && old_rend == new_rend) return; bool show_info = true; int I = show_info ? INFO_BAR_H : 0; int B = new_bars ? SBAR_W : 0; canvas->resize(x() + B, y() + I, w() - B, h() - B - I); enable_bars = new_bars; if (enable_bars) { vert->show(); horiz->show(); } else { vert->hide(); horiz->hide(); } if (show_info) status->show(); else status->hide(); init_sizes(); } void UI_CanvasScroll::UpdateBounds() { UpdateBounds_X(); UpdateBounds_Y(); } void UI_CanvasScroll::UpdateBounds_X() { if (last_bounds[0] == mInstance.level.Map_bound1.x && last_bounds[1] == mInstance.level.Map_bound2.x) { return; } last_bounds[0] = static_cast(mInstance.level.Map_bound1.x); last_bounds[1] = static_cast(mInstance.level.Map_bound2.x); int expand = static_cast(512 + (mInstance.level.Map_bound2.x - mInstance.level.Map_bound1.x) / 8); bound_x1 = static_cast(mInstance.level.Map_bound1.x - expand); bound_x2 = static_cast(mInstance.level.Map_bound2.x + expand); Adjust_X(); } void UI_CanvasScroll::UpdateBounds_Y() { if (last_bounds[2] == mInstance.level.Map_bound1.y && last_bounds[3] == mInstance.level.Map_bound2.y) { return; } last_bounds[2] = static_cast(mInstance.level.Map_bound1.y); last_bounds[3] = static_cast(mInstance.level.Map_bound2.y); int expand = static_cast(512 + (mInstance.level.Map_bound2.y - mInstance.level.Map_bound1.y) / 8); bound_y1 = static_cast(mInstance.level.Map_bound1.y - expand); bound_y2 = static_cast(mInstance.level.Map_bound2.y + expand); Adjust_Y(); } void UI_CanvasScroll::AdjustPos() { Adjust_X(); Adjust_Y(); } void UI_CanvasScroll::Adjust_X() { int cw = canvas->w(); int map_w = iround(cw / mInstance.grid.getScale()); int map_x = static_cast(mInstance.grid.getOrig().x - map_w / 2); if (map_x > bound_x2 - map_w) map_x = bound_x2 - map_w; if (map_x < bound_x1) map_x = bound_x1; horiz->value(map_x, map_w, bound_x1, bound_x2 - bound_x1); } void UI_CanvasScroll::Adjust_Y() { int ch = canvas->h(); int map_h = iround(ch / mInstance.grid.getScale()); int map_y = static_cast(mInstance.grid.getOrig().y - map_h / 2); // invert, since screen coords are the reverse of map coords map_y = bound_y2 - map_h - (map_y - bound_y1); if (map_y > bound_y2 - map_h) map_y = bound_y2 - map_h; if (map_y < bound_y1) map_y = bound_y1; vert->value(map_y, map_h, bound_y1, bound_y2 - bound_y1); } void UI_CanvasScroll::Scroll_X() { int pos = horiz->value(); double map_w = canvas->w() / mInstance.grid.getScale(); double new_x = pos + map_w / 2.0; mInstance.grid.MoveTo({ new_x, mInstance.grid.getOrig().y }); } void UI_CanvasScroll::Scroll_Y() { int pos = vert->value(); double map_h = canvas->h() / mInstance.grid.getScale(); double new_y = bound_y2 - map_h / 2.0 - (pos - bound_y1); mInstance.grid.MoveTo({ mInstance.grid.getOrig().x, new_y }); } void UI_CanvasScroll::bar_callback(Fl_Widget *w, void *data) { UI_CanvasScroll * that = (UI_CanvasScroll *)data; if (w == that->horiz) that->Scroll_X(); if (w == that->vert) that->Scroll_Y(); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_scroll.h000066400000000000000000000056271464327712600205060ustar00rootroot00000000000000//------------------------------------------------------------------------ // A decent scrolling widget //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_SCROLL_H__ #define __EUREKA_UI_SCROLL_H__ #define SBAR_W 16 class Fl_Scrollbar; class UI_Scroll : public Fl_Group { private: Fl_Scrollbar * scrollbar; int bar_side; bool resize_horiz_; int top_y, bottom_y; public: UI_Scroll(int X, int Y, int W, int H, int _bar_side = -1); virtual ~UI_Scroll(); /* FLTK methods */ void resize(int X, int Y, int W, int H); int handle(int event); public: void resize_horiz(bool r) { resize_horiz_ = r; } void Add(Fl_Widget *w); void Remove(Fl_Widget *w); void Remove_first(); void Remove_all(); int Children() const; Fl_Widget * Child(int i) const; void Init_sizes(); void Line_size(int pixels); // delta is positive to move further down the list, negative to // move further up. Its absolute value can be: // 1 : scroll by a small amount // 2 : scroll by one "line" // 3 : scroll to next/previous page // 4 : scroll to end void Scroll(int delta); // scroll so that a certain child widget can be seen. // currently it is placed at top of scroll area, or as close // as possible. void JumpToChild(int i); private: void ScrollByPixels(int pixels); void do_scroll(); void calc_extents(); void reposition_all(int start_y); static void bar_callback(Fl_Widget *, void *); }; //------------------------------------------------------------------------ class UI_Canvas; class UI_CanvasScroll : public Fl_Group { public: UI_Canvas * canvas; UI_StatusBar * status; private: Fl_Scrollbar * horiz; Fl_Scrollbar * vert; bool enable_bars; int bound_x1, bound_x2; int bound_y1, bound_y2; int last_bounds[4]; public: UI_CanvasScroll(Instance &inst, int X, int Y, int W, int H); virtual ~UI_CanvasScroll(); public: void UpdateRenderMode(); void UpdateBounds(); void AdjustPos(); private: void Adjust_X(); void Adjust_Y(); void UpdateBounds_X(); void UpdateBounds_Y(); void Scroll_X(); // callback helpers void Scroll_Y(); static void bar_callback(Fl_Widget *, void *); Instance &mInstance; }; #endif /* __EUREKA_UI_SCROLL_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_sector.cc000066400000000000000000000535731464327712600206500ustar00rootroot00000000000000//------------------------------------------------------------------------ // SECTOR PANEL //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2019 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Instance.h" #include "main.h" #include "ui_misc.h" #include "ui_window.h" #include "e_checks.h" #include "e_cutpaste.h" #include "e_main.h" #include "e_sector.h" #include "e_things.h" #include "m_config.h" #include "m_game.h" #include "r_render.h" #include "Sector.h" #include "w_rawdef.h" #include "w_texture.h" // config items int config::floor_bump_small = 1; int config::floor_bump_medium = 8; int config::floor_bump_large = 64; int config::light_bump_small = 4; int config::light_bump_medium = 16; int config::light_bump_large = 64; //TODO make these configurable static const int headroom_presets[UI_SectorBox::HEADROOM_BUTTONS] = { 0, 64, 96, 128, 192, 256 }; // // UI_SectorBox Constructor // UI_SectorBox::UI_SectorBox(Instance &inst, int X, int Y, int W, int H, const char *label) : MapItemBox(inst, X, Y, W, H, label) { box(FL_FLAT_BOX); // (FL_THIN_UP_BOX); X += 6; Y += 6; W -= 12; H -= 10; which = new UI_Nombre(X+NOMBRE_INSET, Y, W-2*NOMBRE_INSET, NOMBRE_HEIGHT, "Sector"); Y += which->h() + 4; type = new UI_DynInput(X+70, Y, 70, 24, "Type: "); type->align(FL_ALIGN_LEFT); type->callback(type_callback, this); type->callback2(dyntype_callback, this); type->type(FL_INT_INPUT); type->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); choose = new Fl_Button(X+W/2, Y, 80, 24, "Choose"); choose->callback(button_callback, this); Y += type->h() + 4; desc = new Fl_Output(X+70, Y, W-78, 24, "Desc: "); desc->align(FL_ALIGN_LEFT); Y += desc->h() + 12; tag = new UI_DynIntInput(X+70, Y, 64, 24, "Tag: "); tag->align(FL_ALIGN_LEFT); tag->callback(tag_callback, this); tag->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); fresh_tag = new Fl_Button(tag->x() + tag->w() + 20, Y+1, 64, 22, "fresh"); fresh_tag->callback(button_callback, this); Y += tag->h() + 4; light = new UI_DynIntInput(X+70, Y, 64, 24, "Light: "); light->align(FL_ALIGN_LEFT); light->callback(light_callback, this); light->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); lt_down = new Fl_Button(light->x() + light->w() + 20, Y+1, 30, 22, "-"); lt_up = new Fl_Button(light->x() + light->w() + 60, Y+1, 30, 22, "+"); lt_down->labelfont(FL_HELVETICA_BOLD); lt_up ->labelfont(FL_HELVETICA_BOLD); lt_down->labelsize(16); lt_up ->labelsize(16); lt_down->callback(button_callback, this); lt_up ->callback(button_callback, this); Y += light->h() + 20; c_pic = new UI_Pic(inst, X+W-82, Y-2, 64, 64, "Ceil"); f_pic = new UI_Pic(inst, X+W-82, Y+74, 64, 64, "Floor"); c_pic->callback(tex_callback, this); f_pic->callback(tex_callback, this); Y += 10; c_tex = new UI_DynInput(X+70, Y-5, 108, 24, "Ceiling: "); c_tex->align(FL_ALIGN_LEFT); c_tex->callback(tex_callback, this); c_tex->callback2(dyntex_callback, this); c_tex->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); Y += c_tex->h() + 3; ceil_h = new UI_DynIntInput(X+70, Y, 64, 24, ""); ceil_h->align(FL_ALIGN_LEFT); ceil_h->callback(height_callback, this); ceil_h->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); ce_down = new Fl_Button(X+28, Y+1, 30, 22, "-"); ce_up = new Fl_Button(X+145, Y+1, 30, 22, "+"); ce_down->labelfont(FL_HELVETICA_BOLD); ce_up ->labelfont(FL_HELVETICA_BOLD); ce_down->labelsize(16); ce_up ->labelsize(16); ce_down->callback(button_callback, this); ce_up ->callback(button_callback, this); Y += ceil_h->h() + 10; floor_h = new UI_DynIntInput(X+70, Y, 64, 24, ""); floor_h->align(FL_ALIGN_LEFT); floor_h->callback(height_callback, this); floor_h->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); fl_down = new Fl_Button(X+28, Y+1, 30, 22, "-"); fl_up = new Fl_Button(X+145, Y+1, 30, 22, "+"); fl_down->labelfont(FL_HELVETICA_BOLD); fl_up ->labelfont(FL_HELVETICA_BOLD); fl_down->labelsize(16); fl_up ->labelsize(16); fl_down->callback(button_callback, this); fl_up ->callback(button_callback, this); Y += floor_h->h() + 3; f_tex = new UI_DynInput(X+70, Y+5, 108, 24, "Floor: "); f_tex->align(FL_ALIGN_LEFT); f_tex->callback(tex_callback, this); f_tex->callback2(dyntex_callback, this); f_tex->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); Y += f_tex->h() + 33; headroom = new UI_DynIntInput(X+100, Y, 56, 24, "Headroom: "); headroom->align(FL_ALIGN_LEFT); headroom->callback(headroom_callback, this); headroom->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); for (int i = 0 ; i < HEADROOM_BUTTONS ; i++) { int hx = (i < 2) ? (X + 170 + i * 60) : (X + 50 + (i-2) * 60); int hy = Y + 28 * ((i < 2) ? 0 : 1); hd_buttons[i] = new Fl_Button(hx, hy+1, 45, 22); hd_buttons[i]->copy_label(SString(headroom_presets[i]).c_str()); hd_buttons[i]->callback(headroom_callback, this); } Y += headroom->h() + 50; // generalized sector stuff bm_title = new Fl_Box(FL_NO_BOX, X+10, Y, 100, 24, "Boom flags:"); bm_title->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT); Y += 28; bm_damage = new Fl_Choice(X+W - 95, Y, 80, 24, "Damage: "); bm_damage->add("NONE|5 hp|10 hp|20 hp"); bm_damage->value(0); bm_damage->callback(type_callback, this); bm_secret = new Fl_Check_Button(X+28, Y, 94, 20, "Secret"); bm_secret->labelsize(12); bm_secret->callback(type_callback, this); bm_friction = new Fl_Check_Button(X+28, Y+20, 94, 20, "Friction"); bm_friction->labelsize(12); bm_friction->callback(type_callback, this); bm_wind = new Fl_Check_Button(X+28, Y+40, 94, 20, "Wind"); bm_wind->labelsize(12); bm_wind->callback(type_callback, this); mFixUp.loadFields({ type, light, tag, ceil_h, floor_h, c_tex, f_tex, headroom }); end(); resizable(NULL); } //------------------------------------------------------------------------ void UI_SectorBox::height_callback(Fl_Widget *w, void *data) { UI_SectorBox *box = (UI_SectorBox *)data; int f_h = atoi(box->floor_h->value()); int c_h = atoi(box->ceil_h->value()); f_h = clamp(-32767, f_h, 32767); c_h = clamp(-32767, c_h, 32767); if (! box->inst.edit.Selected->empty()) { { EditOperation op(box->inst.level.basis); if (w == box->floor_h) op.setMessageForSelection("edited floor of", *box->inst.edit.Selected); else op.setMessageForSelection("edited ceiling of", *box->inst.edit.Selected); for (sel_iter_c it(*box->inst.edit.Selected); !it.done(); it.next()) { if (w == box->floor_h) op.changeSector(*it, Sector::F_FLOORH, f_h); else op.changeSector(*it, Sector::F_CEILH, c_h); } } box->mFixUp.setInputValue(box->floor_h, SString(f_h).c_str()); box->mFixUp.setInputValue(box->ceil_h, SString(c_h).c_str()); box->mFixUp.setInputValue(box->headroom, SString(c_h - f_h).c_str()); } } void UI_SectorBox::headroom_callback(Fl_Widget *w, void *data) { UI_SectorBox *box = (UI_SectorBox *)data; int room = atoi(box->headroom->value()); // handle the shortcut buttons for (int i = 0 ; i < HEADROOM_BUTTONS ; i++) { if (w == box->hd_buttons[i]) { room = atoi(w->label()); } } if (!box->inst.edit.Selected->empty()) { box->mFixUp.checkDirtyFields(); { EditOperation op(box->inst.level.basis); op.setMessageForSelection("edited headroom of", *box->inst.edit.Selected); for (sel_iter_c it(*box->inst.edit.Selected); !it.done(); it.next()) { int new_h = box->inst.level.sectors[*it]->floorh + room; new_h = clamp(-32767, new_h, 32767); op.changeSector(*it, Sector::F_CEILH, new_h); } } box->UpdateField(); } } void UI_SectorBox::tex_callback(Fl_Widget *w, void *data) { UI_SectorBox *box = (UI_SectorBox *)data; if (box->obj < 0) return; bool is_pic = (w == box->f_pic || w == box->c_pic); bool is_floor = (w == box->f_pic || w == box->f_tex); // MMB on ceiling flat image sets to sky if (w == box->c_pic && Fl::event_button() == FL_MIDDLE_MOUSE) { box->SetFlat(box->inst.conf.miscInfo.sky_flat, PART_CEIL); return; } // LMB on the flat image just selects/unselects it (red border) if (is_pic && Fl::event_button() != FL_RIGHT_MOUSE) { auto pic = static_cast(w); pic->Selected(! pic->Selected()); if (pic->Selected()) box->inst.main_win->BrowserMode(BrowserMode::flats); return; } SString new_flat; // right click sets to default value // [ Note the 'is_pic' check prevents a bug when using RMB in browser ] if (is_pic && Fl::event_button() == FL_RIGHT_MOUSE) new_flat = is_floor ? box->inst.conf.default_floor_tex : box->inst.conf.default_ceil_tex; else if (is_floor) new_flat = NormalizeTex(box->f_tex->value()); else new_flat = NormalizeTex(box->c_tex->value()); box->InstallFlat(new_flat, is_floor ? PART_FLOOR : PART_CEIL); } void UI_SectorBox::InstallFlat(const SString &name, int filter_parts) { StringID tex_num = BA_InternaliseString(name); if (! inst.edit.Selected->empty()) { mFixUp.checkDirtyFields(); EditOperation op(inst.level.basis); op.setMessageForSelection("edited texture on", *inst.edit.Selected); for (sel_iter_c it(*inst.edit.Selected) ; !it.done() ; it.next()) { int parts = inst.edit.Selected->get_ext(*it); if (parts == 1) parts = filter_parts; if (parts & filter_parts & PART_FLOOR) op.changeSector(*it, Sector::F_FLOOR_TEX, tex_num); if (parts & filter_parts & parts & PART_CEIL) op.changeSector(*it, Sector::F_CEIL_TEX, tex_num); } } UpdateField(); } void UI_SectorBox::dyntex_callback(Fl_Widget *w, void *data) { // change picture to match the input, BUT does not change the map UI_SectorBox *box = (UI_SectorBox *)data; if (box->obj < 0) return; if (w == box->f_tex) { box->f_pic->GetFlat(box->f_tex->value()); } else if (w == box->c_tex) { box->c_pic->GetFlat(box->c_tex->value()); } } void UI_SectorBox::SetFlat(const SString &name, int parts) { if(parts & PART_FLOOR) mFixUp.setInputValue(f_tex, name.c_str()); if(parts & PART_CEIL) mFixUp.setInputValue(c_tex, name.c_str()); InstallFlat(name, parts); } void UI_SectorBox::type_callback(Fl_Widget *w, void *data) { UI_SectorBox *box = (UI_SectorBox *)data; int mask = 65535; int value = atoi(box->type->value()); int gen_mask = (box->inst.conf.features.gen_sectors == GenSectorFamily::zdoom) ? 255 : 31; // when generalize sectors active, typing a low value (which does // not touch any bitflags) should just update the TYPE part, and // leave the existing bitflags alone. if (w == box->type && value > gen_mask) { // the value is too large and can affect the bitflags, so we // update the WHOLE sector type. If generalized sectors are // active, then the panel will reinterpret the typed value. } else if (box->inst.conf.features.gen_sectors != GenSectorFamily::none) { // Boom and ZDoom generalized sectors mask = 0; if (w == box->bm_damage) { mask = BoomSF_DamageMask; value = box->bm_damage->value() << 5; } else if (w == box->bm_secret) { mask = BoomSF_Secret; value = box->bm_secret->value() << 7; } else if (w == box->bm_friction) { mask = BoomSF_Friction; value = box->bm_friction->value() << 8; } else if (w == box->bm_wind) { mask = BoomSF_Wind; value = box->bm_wind->value() << 9; } if (mask == 0) { mask = gen_mask; } else if (box->inst.conf.features.gen_sectors == GenSectorFamily::zdoom) { // for ZDoom in Hexen mode, shift up 3 bits mask <<= 3; value <<= 3; } } box->InstallSectorType(mask, value); } void UI_SectorBox::InstallSectorType(int mask, int value) { value &= mask; if (! inst.edit.Selected->empty()) { mFixUp.checkDirtyFields(); EditOperation op(inst.level.basis); op.setMessageForSelection("edited type of", *inst.edit.Selected); for (sel_iter_c it(*inst.edit.Selected) ; !it.done() ; it.next()) { int old_type = inst.level.sectors[*it]->type; op.changeSector(*it, Sector::F_TYPE, (old_type & ~mask) | value); } } // update the description UpdateField(Sector::F_TYPE); } void UI_SectorBox::dyntype_callback(Fl_Widget *w, void *data) { UI_SectorBox *box = (UI_SectorBox *)data; if (box->obj < 0) return; int value = atoi(box->type->value()); // when generalize sectors in effect, the name should just // show the TYPE part of the sector type. if (box->inst.conf.features.gen_sectors != GenSectorFamily::none) { int gen_mask = (box->inst.conf.features.gen_sectors == GenSectorFamily::zdoom) ? 255 : 31; value &= gen_mask; } const sectortype_t &info = box->inst.M_GetSectorType(value); box->desc->value(info.desc.c_str()); } void UI_SectorBox::SetSectorType(int new_type) { if (obj < 0) return; auto buffer = SString(new_type); mFixUp.setInputValue(type, buffer.c_str()); // was updated by this int mask = (inst.conf.features.gen_sectors == GenSectorFamily::zdoom) ? 255 : (inst.conf.features.gen_sectors == GenSectorFamily::boom) ? 31 : 65535; InstallSectorType(mask, new_type); } void UI_SectorBox::light_callback(Fl_Widget *w, void *data) { UI_SectorBox *box = (UI_SectorBox *)data; int new_lt = atoi(box->light->value()); // we allow 256 if explicitly typed, otherwise limit to 255 if (new_lt > 256) new_lt = 255; if (new_lt < 0) new_lt = 0; if (!box->inst.edit.Selected->empty()) { EditOperation op(box->inst.level.basis); op.setMessageForSelection("edited light of", *box->inst.edit.Selected); for (sel_iter_c it(*box->inst.edit.Selected); !it.done(); it.next()) { op.changeSector(*it, Sector::F_LIGHT, new_lt); } } } void UI_SectorBox::tag_callback(Fl_Widget *w, void *data) { UI_SectorBox *box = (UI_SectorBox *)data; int new_tag = atoi(box->tag->value()); new_tag = clamp(-32767, new_tag, 32767); if (!box->inst.edit.Selected->empty()) box->inst.level.checks.tagsApplyNewValue(new_tag); } void UI_SectorBox::FreshTag() { mFixUp.checkDirtyFields(); int new_tag = findFreeTag(inst, true); if (new_tag > 32767) { inst.Beep("Out of tag numbers"); return; } if(!inst.edit.Selected->empty()) { inst.level.checks.tagsApplyNewValue(new_tag); } } void UI_SectorBox::button_callback(Fl_Widget *w, void *data) { UI_SectorBox *box = (UI_SectorBox *)data; box->mFixUp.checkDirtyFields(); if (w == box->choose) { box->inst.main_win->BrowserMode(BrowserMode::sectorTypes); return; } if (w == box->fresh_tag) { box->FreshTag(); return; } keycode_t mod = Fl::event_state() & EMOD_ALL_MASK; int lt_step = config::light_bump_medium; if (mod & EMOD_SHIFT) lt_step = config::light_bump_small; else if (mod & EMOD_COMMAND) lt_step = config::light_bump_large; if (w == box->lt_up) { box->inst.level.secmod.sectorsAdjustLight(+lt_step); return; } else if (w == box->lt_down) { box->inst.level.secmod.sectorsAdjustLight(-lt_step); return; } int mv_step = config::floor_bump_medium; if (mod & EMOD_SHIFT) mv_step = config::floor_bump_small; else if (mod & EMOD_COMMAND) mv_step = config::floor_bump_large; if (w == box->ce_up) { box->inst.ExecuteCommand("SEC_Ceil", SString(+mv_step)); return; } else if (w == box->ce_down) { box->inst.ExecuteCommand("SEC_Ceil", SString(-mv_step)); return; } if (w == box->fl_up) { box->inst.ExecuteCommand("SEC_Floor", SString(+mv_step)); return; } else if (w == box->fl_down) { box->inst.ExecuteCommand("SEC_Floor", SString(-mv_step)); return; } } //------------------------------------------------------------------------ void UI_SectorBox::UpdateField(int field) { const Sector *sector = inst.level.isSector(obj) ? inst.level.sectors[obj].get() : nullptr; if (field < 0 || field == Sector::F_FLOORH || field == Sector::F_CEILH) { if (inst.level.isSector(obj)) { mFixUp.setInputValue(floor_h, SString(sector->floorh).c_str()); mFixUp.setInputValue(ceil_h, SString(sector->ceilh).c_str()); mFixUp.setInputValue(headroom, SString(sector->HeadRoom()).c_str()); } else { mFixUp.setInputValue(floor_h, ""); mFixUp.setInputValue(ceil_h, ""); mFixUp.setInputValue(headroom, ""); } } if (field < 0 || field == Sector::F_FLOOR_TEX || field == Sector::F_CEIL_TEX) { if (inst.level.isSector(obj)) { mFixUp.setInputValue(f_tex, sector->FloorTex().c_str()); mFixUp.setInputValue(c_tex, sector->CeilTex().c_str()); f_pic->GetFlat(sector->FloorTex()); c_pic->GetFlat(sector->CeilTex()); f_pic->AllowHighlight(true); c_pic->AllowHighlight(true); } else { mFixUp.setInputValue(f_tex, ""); mFixUp.setInputValue(c_tex, ""); f_pic->Clear(); c_pic->Clear(); f_pic->AllowHighlight(false); c_pic->AllowHighlight(false); } } if (field < 0 || field == Sector::F_TYPE) { bm_damage->value(0); bm_secret->value(0); bm_friction->value(0); bm_wind->value(0); if (inst.level.isSector(obj)) { int value = sector->type; int mask = (inst.conf.features.gen_sectors == GenSectorFamily::zdoom) ? 255 : (inst.conf.features.gen_sectors != GenSectorFamily::none) ? 31 : 65535; mFixUp.setInputValue(type, SString(value & mask).c_str()); const sectortype_t &info = inst.M_GetSectorType(value & mask); desc->value(info.desc.c_str()); if (inst.conf.features.gen_sectors != GenSectorFamily::none) { if (inst.conf.features.gen_sectors == GenSectorFamily::zdoom) value >>= 3; bm_damage->value((value >> 5) & 3); bm_secret->value((value >> 7) & 1); bm_friction->value((value >> 8) & 1); bm_wind ->value((value >> 9) & 1); } } else { mFixUp.setInputValue(type, ""); desc->value(""); } } if (field < 0 || field == Sector::F_LIGHT || field == Sector::F_TAG) { if (inst.level.isSector(obj)) { mFixUp.setInputValue(light, SString(sector->light).c_str()); mFixUp.setInputValue(tag, SString(sector->tag).c_str()); } else { mFixUp.setInputValue(light, ""); mFixUp.setInputValue(tag, ""); } } } int UI_SectorBox::GetSelectedPics() const { return (f_pic->Selected() ? PART_FLOOR : 0) | (c_pic->Selected() ? PART_CEIL : 0); } int UI_SectorBox::GetHighlightedPics() const { return (f_pic->Highlighted() ? PART_FLOOR : 0) | (c_pic->Highlighted() ? PART_CEIL : 0); } void UI_SectorBox::CB_Copy(int parts) { if (parts == (PART_FLOOR | PART_CEIL)) { inst.Beep("multiple textures"); return; } const char *name = NULL; if (parts == PART_CEIL) name = c_tex->value(); else name = f_tex->value(); Texboard_SetFlat(name, inst.conf); inst.Status_Set("copied %s", name); } void UI_SectorBox::CB_Paste(int parts, StringID new_tex) { if (inst.edit.Selected->empty()) return; mFixUp.checkDirtyFields(); { EditOperation op(inst.level.basis); op.setMessage("pasted %s", BA_GetString(new_tex).c_str()); for (sel_iter_c it(*inst.edit.Selected) ; !it.done() ; it.next()) { if (parts & PART_FLOOR) op.changeSector(*it, Sector::F_FLOOR_TEX, new_tex); if (parts & PART_CEIL) op.changeSector(*it, Sector::F_CEIL_TEX, new_tex); } } UpdateField(); } void UI_SectorBox::CB_Cut(int parts) { StringID new_floor = BA_InternaliseString(inst.conf.default_floor_tex); StringID new_ceil = BA_InternaliseString(inst.conf.default_ceil_tex); if (! inst.edit.Selected->empty()) { mFixUp.checkDirtyFields(); { EditOperation op(inst.level.basis); op.setMessageForSelection("cut texture on", *inst.edit.Selected); for (sel_iter_c it(*inst.edit.Selected) ; !it.done() ; it.next()) { if (parts & PART_FLOOR) op.changeSector(*it, Sector::F_FLOOR_TEX, new_floor); if (parts & PART_CEIL) op.changeSector(*it, Sector::F_CEIL_TEX, new_ceil); } } UpdateField(); } } // // Sector box clipboard operation // bool UI_SectorBox::ClipboardOp(EditCommand op) { if (obj < 0) return false; int parts = GetSelectedPics(); if (parts == 0) parts = GetHighlightedPics(); if (parts == 0) return false; switch (op) { case EditCommand::copy: CB_Copy(parts); break; case EditCommand::paste: CB_Paste(parts, Texboard_GetFlatNum(inst.conf)); break; case EditCommand::cut: CB_Cut(parts); break; case EditCommand::del: // abuse the delete function to turn sector ceilings into sky CB_Paste(parts, BA_InternaliseString(inst.conf.miscInfo.sky_flat)); break; } return true; } void UI_SectorBox::BrowsedItem(BrowserMode kind, int number, const char *name, int e_state) { if (obj < 0) return; if (kind == BrowserMode::flats || kind == BrowserMode::textures) { int parts = GetSelectedPics(); if (parts == 0) { if (inst.edit.render3d) parts = PART_FLOOR | PART_CEIL; else if (inst.edit.sector_render_mode == SREND_Ceiling) parts = PART_CEIL; else if (e_state & FL_BUTTON3) parts = PART_CEIL; else parts = PART_FLOOR; } SetFlat(name, parts); } else if (kind == BrowserMode::sectorTypes) { SetSectorType(number); } } void UI_SectorBox::UnselectPics() { f_pic->Unhighlight(); c_pic->Unhighlight(); f_pic->Selected(false); c_pic->Selected(false); } // FIXME: make a method of Sector class void UI_SectorBox::UpdateTotal(const Document &doc) noexcept { which->SetTotal(doc.numSectors()); } void UI_SectorBox::UpdateGameInfo(const LoadingData &loaded, const ConfigData &config) { if (config.features.gen_sectors != GenSectorFamily::none) { if (config.features.gen_sectors == GenSectorFamily::zdoom) bm_title->label("ZDoom flags:"); else bm_title->label("Boom flags:"); bm_title->show(); bm_damage->show(); bm_secret->show(); bm_friction->show(); bm_wind->show(); } else { bm_title->hide(); bm_damage->hide(); bm_secret->hide(); bm_friction->hide(); bm_wind->hide(); } UpdateField(); redraw(); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_sector.h000066400000000000000000000062451464327712600205040ustar00rootroot00000000000000//------------------------------------------------------------------------ // SECTOR PANEL //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2018 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_SECTOR_H__ #define __EUREKA_UI_SECTOR_H__ #include "e_cutpaste.h" #include "ui_panelinput.h" class UI_DynIntInput; class UI_SectorBox : public MapItemBox { public: UI_DynInput *type; Fl_Output *desc; Fl_Button *choose; UI_DynIntInput *light; UI_DynIntInput *tag; Fl_Button *fresh_tag; Fl_Button *lt_down, *lt_up; UI_DynIntInput *ceil_h; UI_DynIntInput *floor_h; Fl_Button *ce_down, *ce_up; Fl_Button *fl_down, *fl_up; UI_DynInput *c_tex; UI_Pic *c_pic; UI_DynInput *f_tex; UI_Pic *f_pic; UI_DynIntInput *headroom; enum { HEADROOM_BUTTONS = 6 }; Fl_Button * hd_buttons[HEADROOM_BUTTONS]; // Boom generalized sectors Fl_Box * bm_title; Fl_Choice * bm_damage; Fl_Check_Button * bm_secret; Fl_Check_Button * bm_friction; Fl_Check_Button * bm_wind; public: UI_SectorBox(Instance &inst, int X, int Y, int W, int H, const char *label = NULL); public: // call this if the thing was externally changed. // -1 means "all fields" void UpdateField(int field = -1) override; void UpdateTotal(const Document &doc) noexcept override; void UpdateGameInfo(const LoadingData &loaded, const ConfigData &config) override; // see ui_window.h for description of these two methods bool ClipboardOp(EditCommand op); void BrowsedItem(BrowserMode kind, int number, const char *name, int e_state); void UnselectPics() override; private: void CB_Copy(int parts); void CB_Paste(int parts, StringID new_tex); void CB_Cut(int parts); // returns either zero or a combination of PART_FLOOR and PART_CEIL int GetSelectedPics() const; int GetHighlightedPics() const; void SetFlat(const SString &name, int parts); void SetSectorType(int new_type); void InstallFlat(const SString &name, int parts); void InstallSectorType(int mask, int value); void FreshTag(); static void height_callback(Fl_Widget *, void *); static void headroom_callback(Fl_Widget *, void *); static void tex_callback(Fl_Widget *, void *); static void dyntex_callback(Fl_Widget *, void *); static void type_callback(Fl_Widget *, void *); static void dyntype_callback(Fl_Widget *, void *); static void light_callback(Fl_Widget *, void *); static void tag_callback(Fl_Widget *, void *); static void button_callback(Fl_Widget *, void *); }; #endif /* __EUREKA_UI_SECTOR_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_sidedef.cc000066400000000000000000000346101464327712600207430ustar00rootroot00000000000000//------------------------------------------------------------------------ // SIDEDEF INFORMATION //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Instance.h" #include "main.h" #include "ui_misc.h" #include "ui_window.h" #include "e_hover.h" // OppositeSector #include "e_linedef.h" #include "e_main.h" #include "LineDef.h" #include "m_config.h" #include "m_game.h" #include "r_render.h" #include "Sector.h" #include "SideDef.h" #include "w_rawdef.h" #include "w_texture.h" enum { TEXTURE_TILE_OUTSET = 8 }; // config item bool config::swap_sidedefs = false; bool config::show_full_one_sided = false; bool config::sidedef_add_del_buttons = false; // // Check dirty fields for the linedef panel // inline static void checkLinedefDirtyFields(const Instance &inst) { inst.main_win->line_box->checkDirtyFields(); } // // Constructor // UI_SideBox::UI_SideBox(Instance &inst, int X, int Y, int W, int H, int _side) : Fl_Group(X, Y, W, H), is_front(_side == 0), inst(inst) { box(FL_FLAT_BOX); // FL_UP_BOX align(FL_ALIGN_INSIDE | FL_ALIGN_TOP | FL_ALIGN_LEFT); if (is_front) labelcolor(FL_BLUE); else labelcolor(fl_rgb_color(224,64,0)); add_button = new Fl_Button(X + W - 120, Y, 50, 20, "ADD"); add_button->labelcolor(labelcolor()); add_button->callback(add_callback, this); del_button = new Fl_Button(X + W - 65, Y, 50, 20, "DEL"); del_button->labelcolor(labelcolor()); del_button->callback(delete_callback, this); X += 6; Y += 6 + 16; // space for label W -= 12; H -= 12; int MX = X + W/2; x_ofs = new UI_DynIntInput(X+28, Y, 52, 24, "x:"); y_ofs = new UI_DynIntInput(MX-20, Y, 52, 24, "y:"); sec = new UI_DynIntInput(X+W-59, Y, 52, 24, "sec:"); x_ofs->align(FL_ALIGN_LEFT); y_ofs->align(FL_ALIGN_LEFT); sec ->align(FL_ALIGN_LEFT); x_ofs->callback(offset_callback, this); y_ofs->callback(offset_callback, this); sec ->callback(sector_callback, this); x_ofs->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); y_ofs->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); sec ->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); Y += x_ofs->h() + 6; int LX = X+16; int UX = X+W-64-16; MX = MX-32; if (config::swap_sidedefs) { std::swap(UX, LX); } l_pic = new UI_Pic(inst, LX, Y, 64, 64, "Lower"); u_pic = new UI_Pic(inst, UX, Y, 64, 64, "Upper"); r_pic = new UI_Pic(inst, MX, Y, 64, 64, "Rail"); l_pic->callback(tex_callback, this); u_pic->callback(tex_callback, this); r_pic->callback(tex_callback, this); Y += 65; l_tex = new UI_DynInput(LX - TEXTURE_TILE_OUTSET, Y, 80, 20); u_tex = new UI_DynInput(UX - TEXTURE_TILE_OUTSET, Y, 80, 20); r_tex = new UI_DynInput(MX - TEXTURE_TILE_OUTSET, Y, 80, 20); l_tex->textsize(12); u_tex->textsize(12); r_tex->textsize(12); l_tex->callback(tex_callback, this); u_tex->callback(tex_callback, this); r_tex->callback(tex_callback, this); l_tex->callback2(dyntex_callback, this); u_tex->callback2(dyntex_callback, this); r_tex->callback2(dyntex_callback, this); l_tex->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); u_tex->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); r_tex->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); mFixUp.loadFields({ x_ofs, y_ofs, sec, l_tex, u_tex, r_tex }); end(); UpdateHiding(); UpdateLabel(); UpdateAddDel(); } void UI_SideBox::tex_callback(Fl_Widget *w, void *data) { UI_SideBox *box = (UI_SideBox *)data; if (box->obj < 0) return; if (Fl::event_button() != FL_RIGHT_MOUSE && (w == box->l_pic || w == box->u_pic || w == box->r_pic)) { UI_Pic * pic = (UI_Pic *)w; pic->Selected(! pic->Selected()); if (pic->Selected()) box->inst.main_win->BrowserMode(BrowserMode::textures); return; } StringID new_tex; box->mFixUp.checkDirtyFields(); // fine to do it here checkLinedefDirtyFields(box->inst); // right click sets to default value, "-" for rail if (Fl::event_button() == FL_RIGHT_MOUSE) { if (w == box->r_pic) new_tex = BA_InternaliseString("-"); else new_tex = BA_InternaliseString(box->inst.conf.default_wall_tex); } else { if (w == box->l_tex) new_tex = BA_InternaliseString(NormalizeTex(box->l_tex->value())); else if (w == box->u_tex) new_tex = BA_InternaliseString(NormalizeTex(box->u_tex->value())); else new_tex = BA_InternaliseString(NormalizeTex(box->r_tex->value())); } // iterate over selected linedefs if (!box->inst.edit.Selected->empty()) { { EditOperation op(box->inst.level.basis); op.setMessageForSelection("edited texture on", *box->inst.edit.Selected); for (sel_iter_c it(*box->inst.edit.Selected) ; !it.done() ; it.next()) { const auto L = box->inst.level.linedefs[*it]; int sd = box->is_front ? L->right : L->left; if (box->inst.level.isSidedef(sd)) { bool lower = (w == box->l_tex || w == box->l_pic); bool upper = (w == box->u_tex || w == box->u_pic); bool rail = (w == box->r_tex || w == box->r_pic); if (lower) { op.changeSidedef(sd, SideDef::F_LOWER_TEX, new_tex); } else if (upper) { op.changeSidedef(sd, SideDef::F_UPPER_TEX, new_tex); } else if (rail) { op.changeSidedef(sd, SideDef::F_MID_TEX, new_tex); } } } } box->UpdateField(); } } void UI_SideBox::dyntex_callback(Fl_Widget *w, void *data) { // change picture to match the input, BUT does not change the map UI_SideBox *box = (UI_SideBox *)data; if (box->obj < 0) return; if (w == box->l_tex) { box->l_pic->GetTex(box->l_tex->value()); } else if (w == box->u_tex) { box->u_pic->GetTex(box->u_tex->value()); } else if (w == box->r_tex) { box->r_pic->GetTex(box->r_tex->value()); } } void UI_SideBox::add_callback(Fl_Widget *w, void *data) { UI_SideBox *box = (UI_SideBox *)data; box->mFixUp.checkDirtyFields(); checkLinedefDirtyFields(box->inst); if (box->obj >= 0) return; if (box->inst.edit.Selected->empty()) return; // iterate over selected linedefs int field = box->is_front ? LineDef::F_RIGHT : LineDef::F_LEFT; { EditOperation op(box->inst.level.basis); // make sure we have a fallback sector to use if (box->inst.level.numSectors() == 0) { int new_sec = op.addNew(ObjType::sectors); box->inst.level.sectors[new_sec]->SetDefaults(box->inst.conf); } for (sel_iter_c it(*box->inst.edit.Selected) ; !it.done() ; it.next()) { const auto L = box->inst.level.linedefs[*it]; int sd = box->is_front ? L->right : L->left; int other = box->is_front ? L->left : L->right; // skip lines which already have this sidedef if (box->inst.level.isSidedef(sd)) continue; // determine what sector to use int new_sec = box->inst.level.hover.getOppositeSector(*it, box->is_front ? Side::right : Side::left, nullptr); if (new_sec < 0) new_sec = box->inst.level.numSectors() - 1; // create the new sidedef sd = op.addNew(ObjType::sidedefs); box->inst.level.sidedefs[sd]->SetDefaults(box->inst.conf, other >= 0); box->inst.level.sidedefs[sd]->sector = new_sec; op.changeLinedef(*it, static_cast(field), sd); if (other >= 0) box->inst.level.linemod.addSecondSidedef(op, *it, sd, other); } op.setMessageForSelection("added sidedef to", *box->inst.edit.Selected); } box->inst.main_win->line_box->UpdateField(); box->inst.main_win->line_box->UpdateSides(); } void UI_SideBox::delete_callback(Fl_Widget *w, void *data) { UI_SideBox *box = (UI_SideBox *)data; box->mFixUp.checkDirtyFields(); checkLinedefDirtyFields(box->inst); if (box->obj < 0) return; if (box->inst.edit.Selected->empty()) return; // iterate over selected linedefs { EditOperation op(box->inst.level.basis); for (sel_iter_c it(*box->inst.edit.Selected) ; !it.done() ; it.next()) { const auto L = box->inst.level.linedefs[*it]; int sd = box->is_front ? L->right : L->left; if (sd < 0) continue; // NOTE WELL: the actual sidedef is not deleted (it might be shared) box->inst.level.linemod.removeSidedef(op, *it, box->is_front ? Side::right : Side::left); } op.setMessageForSelection("deleted sidedef from", *box->inst.edit.Selected); } box->inst.main_win->line_box->UpdateField(); box->inst.main_win->line_box->UpdateSides(); } void UI_SideBox::offset_callback(Fl_Widget *w, void *data) { UI_SideBox *box = (UI_SideBox *)data; int new_x_ofs = atoi(box->x_ofs->value()); int new_y_ofs = atoi(box->y_ofs->value()); // iterate over selected linedefs if (!box->inst.edit.Selected->empty()) { EditOperation op(box->inst.level.basis); if (w == box->x_ofs) op.setMessageForSelection("edited X offset on", *box->inst.edit.Selected); else op.setMessageForSelection("edited Y offset on", *box->inst.edit.Selected); for (sel_iter_c it(*box->inst.edit.Selected); !it.done(); it.next()) { const auto L = box->inst.level.linedefs[*it]; int sd = box->is_front ? L->right : L->left; if (box->inst.level.isSidedef(sd)) { if (w == box->x_ofs) op.changeSidedef(sd, SideDef::F_X_OFFSET, new_x_ofs); else op.changeSidedef(sd, SideDef::F_Y_OFFSET, new_y_ofs); } } } } void UI_SideBox::sector_callback(Fl_Widget *w, void *data) { UI_SideBox *box = (UI_SideBox *)data; int new_sec = atoi(box->sec->value()); new_sec = clamp(0, new_sec, box->inst.level.numSectors() -1); // iterate over selected linedefs if (!box->inst.edit.Selected->empty()) { EditOperation op(box->inst.level.basis); op.setMessageForSelection("edited sector-ref on", *box->inst.edit.Selected); for (sel_iter_c it(*box->inst.edit.Selected); !it.done(); it.next()) { const auto L = box->inst.level.linedefs[*it]; int sd = box->is_front ? L->right : L->left; if (box->inst.level.isSidedef(sd)) op.changeSidedef(sd, SideDef::F_SECTOR, new_sec); } } } //------------------------------------------------------------------------ void UI_SideBox::SetObj(int index, int solid_mask, bool two_sided) { if (obj == index && what_is_solid == solid_mask && on_2S_line == two_sided) return; bool hide_change = !(obj == index && on_2S_line == two_sided); obj = index; what_is_solid = solid_mask; on_2S_line = two_sided; if (hide_change) UpdateHiding(); UpdateLabel(); UpdateAddDel(); UpdateField(); if (obj < 0) UnselectPics(); redraw(); } void UI_SideBox::UpdateField() { if (inst.level.isSidedef(obj)) { const auto sd = inst.level.sidedefs[obj]; mFixUp.setInputValue(x_ofs, SString(sd->x_offset).c_str()); mFixUp.setInputValue(y_ofs, SString(sd->y_offset).c_str()); mFixUp.setInputValue(sec, SString(sd->sector).c_str()); SString lower = sd->LowerTex(); SString rail = sd->MidTex(); SString upper = sd->UpperTex(); mFixUp.setInputValue(l_tex, lower.c_str()); mFixUp.setInputValue(u_tex, upper.c_str()); mFixUp.setInputValue(r_tex, rail.c_str()); l_pic->GetTex(lower); u_pic->GetTex(upper); r_pic->GetTex(rail); if ((what_is_solid & SOLID_LOWER) && is_null_tex(lower)) l_pic->MarkMissing(); if ((what_is_solid & SOLID_UPPER) && is_null_tex(upper)) u_pic->MarkMissing(); if (is_special_tex(lower)) l_pic->MarkSpecial(); if (is_special_tex(upper)) u_pic->MarkSpecial(); if (is_special_tex(rail)) r_pic->MarkSpecial(); l_pic->AllowHighlight(true); u_pic->AllowHighlight(true); r_pic->AllowHighlight(true); } else { mFixUp.setInputValue(x_ofs, ""); mFixUp.setInputValue(y_ofs, ""); mFixUp.setInputValue(sec, ""); mFixUp.setInputValue(l_tex, ""); mFixUp.setInputValue(u_tex, ""); mFixUp.setInputValue(r_tex, ""); l_pic->Clear(); u_pic->Clear(); r_pic->Clear(); l_pic->AllowHighlight(false); u_pic->AllowHighlight(false); r_pic->AllowHighlight(false); } } void UI_SideBox::UpdateLabel() { if (!inst.level.isSidedef(obj)) { label(is_front ? " No Front Sidedef" : " No Back Sidedef"); return; } char buffer[200]; snprintf(buffer, sizeof(buffer), " %s Sidedef: #%d\n", is_front ? "Front" : "Back", obj); copy_label(buffer); } void UI_SideBox::UpdateAddDel() { if (obj == SETOBJ_NO_LINE || ! config::sidedef_add_del_buttons) { add_button->hide(); del_button->hide(); } else if (!inst.level.isSidedef(obj)) { add_button->show(); del_button->hide(); } else { add_button->hide(); del_button->show(); } } // // Get X position of midtex tile // int UI_SideBox::getMidTexX(int position) const { if(position == 0) return config::swap_sidedefs ? u_pic->x() : l_pic->x(); return (l_pic->x() + u_pic->x()) / 2; } void UI_SideBox::UpdateHiding() { if (obj < 0) { x_ofs->hide(); y_ofs->hide(); sec->hide(); l_tex->hide(); u_tex->hide(); r_tex->hide(); l_pic->hide(); u_pic->hide(); r_pic->hide(); } else { x_ofs->show(); y_ofs->show(); sec->show(); r_tex->show(); r_pic->show(); if (on_2S_line || config::show_full_one_sided) { r_pic->position(getMidTexX(1), r_pic->y()); r_tex->Fl_Widget::position(getMidTexX(1) - TEXTURE_TILE_OUTSET, r_tex->y()); l_tex->show(); u_tex->show(); l_pic->show(); u_pic->show(); } else { r_pic->position(getMidTexX(0), r_pic->y()); r_tex->Fl_Widget::position(getMidTexX(0) - TEXTURE_TILE_OUTSET, r_tex->y()); l_tex->hide(); u_tex->hide(); l_pic->hide(); u_pic->hide(); l_pic->Unhighlight(); u_pic->Unhighlight(); l_pic->Selected(false); u_pic->Selected(false); } } } int UI_SideBox::GetSelectedPics() const { if (obj < 0) return 0; return (l_pic->Selected() ? PART_RT_LOWER : 0) | (u_pic->Selected() ? PART_RT_UPPER : 0) | (r_pic->Selected() ? PART_RT_RAIL : 0); } int UI_SideBox::GetHighlightedPics() const { if (obj < 0) return 0; return (l_pic->Highlighted() ? PART_RT_LOWER : 0) | (u_pic->Highlighted() ? PART_RT_UPPER : 0) | (r_pic->Highlighted() ? PART_RT_RAIL : 0); } void UI_SideBox::UnselectPics() { l_pic->Unhighlight(); u_pic->Unhighlight(); r_pic->Unhighlight(); l_pic->Selected(false); u_pic->Selected(false); r_pic->Selected(false); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_sidedef.h000066400000000000000000000052331464327712600206040ustar00rootroot00000000000000//------------------------------------------------------------------------ // SIDEDEF INFORMATION //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_SIDEDEF_H__ #define __EUREKA_UI_SIDEDEF_H__ #include "ui_panelinput.h" #define SETOBJ_NO_LINE -2 class UI_DynIntInput; // solid_mask bits : when set, that part requires a texture enum { SOLID_LOWER = (1 << 0), SOLID_MID = (1 << 1), SOLID_UPPER = (1 << 2) }; class UI_SideBox : public Fl_Group { private: int obj = SETOBJ_NO_LINE; bool is_front; int what_is_solid; bool on_2S_line = false; public: UI_DynIntInput *x_ofs; UI_DynIntInput *y_ofs; UI_DynIntInput *sec; UI_Pic *l_pic; UI_Pic *u_pic; UI_Pic *r_pic; UI_DynInput *l_tex; UI_DynInput *u_tex; UI_DynInput *r_tex; Fl_Button *add_button; Fl_Button *del_button; Instance &inst; private: PanelFieldFixUp mFixUp; public: UI_SideBox(Instance &inst, int X, int Y, int W, int H, int _side); public: // this can be a sidedef number or -1 for none, or the special // value SETOBJ_NO_LINE when there is no linedef at all. // solid_mask is a bit field of parts which require a texture. // two_sided is from the linedef, will show all parts if true. void SetObj(int index, int solid_mask, bool two_sided); void UpdateField(); // returns a bitmask of PART_RT_XXX values. int GetSelectedPics() const; int GetHighlightedPics() const; void UnselectPics(); // // Forward to the fixup // void checkDirtyFields() { mFixUp.checkDirtyFields(); } private: void UpdateLabel(); void UpdateHiding(); void UpdateAddDel(); int getMidTexX(int position) const; static void tex_callback(Fl_Widget *, void *); static void dyntex_callback(Fl_Widget *, void *); static void offset_callback(Fl_Widget *, void *); static void sector_callback(Fl_Widget *, void *); static void add_callback(Fl_Widget *, void *); static void delete_callback(Fl_Widget *, void *); }; #endif /* __EUREKA_UI_SIDEDEF_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_thing.cc000066400000000000000000000616511464327712600204560ustar00rootroot00000000000000//------------------------------------------------------------------------ // THING PANEL //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2018 Andrew Apted // Copyright (C) 2015 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Instance.h" #include "main.h" #include "ui_misc.h" #include "ui_window.h" #include "e_main.h" #include "m_config.h" #include "m_game.h" #include "Thing.h" #include "w_rawdef.h" #include class thing_opt_CB_data_c { public: UI_ThingBox *parent; int mask; public: thing_opt_CB_data_c(UI_ThingBox *_parent, int _mask) : parent(_parent), mask(_mask) { } }; extern const char *const arrow_0_xpm[]; extern const char *const arrow_45_xpm[]; extern const char *const arrow_90_xpm[]; extern const char *const arrow_135_xpm[]; extern const char *const arrow_180_xpm[]; extern const char *const arrow_225_xpm[]; extern const char *const arrow_270_xpm[]; extern const char *const arrow_315_xpm[]; extern const char *const *arrow_pixmaps[8]; const char *const *arrow_pixmaps[8] = { arrow_0_xpm, arrow_45_xpm, arrow_90_xpm, arrow_135_xpm, arrow_180_xpm, arrow_225_xpm, arrow_270_xpm, arrow_315_xpm }; // // UI_ThingBox Constructor // UI_ThingBox::UI_ThingBox(Instance &inst, int X, int Y, int W, int H, const char *label) : MapItemBox(inst, X, Y, W, H, label) { box(FL_FLAT_BOX); X += 6; Y += 6; W -= 12; H -= 10; which = new UI_Nombre(X+6, Y, W-12, 28, "Thing"); Y = Y + which->h() + 4; type = new UI_DynInput(X+70, Y, 70, 24, "Type: "); type->align(FL_ALIGN_LEFT); type->callback(type_callback, this); type->callback2(dyntype_callback, this); type->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); type->type(FL_INT_INPUT); choose = new Fl_Button(X+W/2, Y, 80, 24, "Choose"); choose->callback(button_callback, this); Y = Y + type->h() + 4; desc = new Fl_Output(X+70, Y, W-78, 24, "Desc: "); desc->align(FL_ALIGN_LEFT); Y = Y + desc->h() + 4; sprite = new UI_Pic(inst, X + W - 120, Y + 10, 100,100, "Sprite"); sprite->callback(button_callback, this); Y = Y + 10; pos_x = new UI_DynIntInput(X+70, Y, 70, 24, "x: "); pos_y = new UI_DynIntInput(X+70, Y + 28, 70, 24, "y: "); pos_z = new UI_DynIntInput(X+70, Y + 28*2, 70, 24, "z: "); pos_z->hide(); pos_x->align(FL_ALIGN_LEFT); pos_y->align(FL_ALIGN_LEFT); pos_z->align(FL_ALIGN_LEFT); pos_x->callback(x_callback, this); pos_y->callback(y_callback, this); pos_z->callback(z_callback, this); pos_x->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); pos_y->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); pos_z->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); Y = Y + 105; // IOANCH 9/2015: TID tid = new UI_DynIntInput(X+70, Y, 64, 24, "TID: "); tid->align(FL_ALIGN_LEFT); tid->callback(tid_callback, this); tid->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); Y = Y + tid->h() + 4; angle = new UI_DynIntInput(X+70, Y, 64, 24, "Angle: "); angle->align(FL_ALIGN_LEFT); angle->callback(angle_callback, this); angle->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); int ang_mx = X + W - 75; int ang_my = Y + 17; for (int i = 0 ; i < 8 ; i++) { int dist = (i == 2 || i == 6) ? 32 : 35; int x = static_cast(ang_mx + dist * cos(i * 45 * M_PI / 180.0)); int y = static_cast(ang_my - dist * sin(i * 45 * M_PI / 180.0)); ang_buts[i] = new Fl_Button(x - 9, y - 9, 24, 24, 0); ang_buts[i]->image(new Fl_Pixmap(arrow_pixmaps[i])); ang_buts[i]->align(FL_ALIGN_CENTER); ang_buts[i]->clear_visible_focus(); ang_buts[i]->callback(button_callback, this); } Y = Y + 50; Fl_Box *opt_lab = new Fl_Box(X+10, Y, W, 22, "Options Flags:"); opt_lab->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT); Y = Y + opt_lab->h() + 2; // when appear: two rows of three on/off buttons int AX = X+W/3+4; int BX = X+2*W/3-20; int FW = W/3 - 12; int AY = Y+22; int BY = Y+22*2; o_easy = new Fl_Check_Button( X+28, Y, FW, 22, "easy"); o_medium = new Fl_Check_Button( X+28, AY, FW, 22, "medium"); o_hard = new Fl_Check_Button( X+28, BY, FW, 22, "hard"); o_sp = new Fl_Check_Button(AX+28, Y, FW, 22, "sp"); o_coop = new Fl_Check_Button(AX+28, AY, FW, 22, "coop"); o_dm = new Fl_Check_Button(AX+28, BY, FW, 22, "dm"); // this is shown only for Vanilla DOOM (instead of the above three). // it is also works differently, no negated like the above. o_vanilla_dm = new Fl_Check_Button(AX+28, BY, FW, 22, "dm"); o_easy ->value(1); o_sp ->value(1); o_medium->value(1); o_coop->value(1); o_hard ->value(1); o_dm ->value(1); o_vanilla_dm->value(0); o_easy ->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Easy)); o_medium->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Medium)); o_hard ->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Hard)); o_sp ->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Not_SP)); o_coop ->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Not_COOP)); o_dm ->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Not_DM)); o_vanilla_dm->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Not_SP)); // Hexen class flags o_fight = new Fl_Check_Button(BX+28, Y, FW, 22, "Fighter"); o_cleric = new Fl_Check_Button(BX+28, AY, FW, 22, "Cleric"); o_mage = new Fl_Check_Button(BX+28, BY, FW, 22, "Mage"); o_fight ->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Hexen_Fighter)); o_cleric->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Hexen_Cleric)); o_mage ->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Hexen_Mage)); o_fight ->hide(); o_cleric->hide(); o_mage ->hide(); // Strife flags o_sf_shadow = new Fl_Check_Button(BX+28, AY, FW, 22, "shadow"); o_sf_altvis = new Fl_Check_Button(BX+28, BY, FW, 22, "alt-vis"); o_sf_shadow->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Strife_Shadow)); o_sf_altvis->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Strife_AltVis)); o_sf_shadow->hide(); o_sf_altvis->hide(); Y = BY + 35; o_ambush = new Fl_Check_Button( X+28, Y, FW, 22, "ambush"); o_friend = new Fl_Check_Button(AX+28, Y, FW, 22, "friend"); o_dormant = new Fl_Check_Button(BX+28, Y, FW, 22, "dormant"); o_ambush ->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Ambush)); o_friend ->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Friend)); o_dormant->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Hexen_Dormant)); o_dormant->hide(); o_sf_ambush = new Fl_Check_Button( X+28, Y, FW, 22, "ambush"); o_sf_friend = new Fl_Check_Button(AX+28, Y, FW, 22, "friend"); o_sf_stand = new Fl_Check_Button( X+28, Y+22, FW, 22, "stand"); o_sf_ambush->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Strife_Ambush)); o_sf_friend->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Strife_Friend)); o_sf_stand ->callback(option_callback, new thing_opt_CB_data_c(this, MTF_Strife_Stand)); o_sf_ambush->hide(); o_sf_friend->hide(); o_sf_stand ->hide(); Y = Y + 45; exfloor = new UI_DynIntInput(X+84, Y, 64, 24, "3D Floor: "); exfloor->align(FL_ALIGN_LEFT); exfloor->callback(option_callback, new thing_opt_CB_data_c(this, MTF_EXFLOOR_MASK)); exfloor->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); efl_down = new Fl_Button(X+165, Y+1, 30, 22, "-"); efl_up = new Fl_Button(X+210, Y+1, 30, 22, "+"); efl_down->labelfont(FL_HELVETICA_BOLD); efl_up ->labelfont(FL_HELVETICA_BOLD); efl_down->labelsize(16); efl_up ->labelsize(16); efl_down->callback(button_callback, this); efl_up ->callback(button_callback, this); #if 0 Y = Y + exfloor->h() + 10; #else exfloor->hide(); efl_down->hide(); efl_up->hide(); #endif // Hexen thing specials spec_type = new UI_DynInput(X+74, Y, 64, 24, "Special: "); spec_type->align(FL_ALIGN_LEFT); spec_type->callback(spec_callback, this); spec_type->callback2(dynspec_callback, this); spec_type->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); spec_type->type(FL_INT_INPUT); spec_type->hide(); spec_choose = new Fl_Button(X+W/2+24, Y, 80, 24, "Choose"); spec_choose->callback(button_callback, this); spec_choose->hide(); Y = Y + spec_type->h() + 2; spec_desc = new Fl_Output(X+74, Y, W-86, 24, "Desc: "); spec_desc->align(FL_ALIGN_LEFT); spec_desc->hide(); Y = Y + spec_desc->h() + 2; for (int a = 0 ; a < 5 ; a++) { args[a] = new UI_DynIntInput(X+74+43*a, Y, 39, 24); args[a]->callback(args_callback, new thing_opt_CB_data_c(this, a)); args[a]->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); args[a]->hide(); } args[0]->label("Args: "); mFixUp.loadFields({type, angle, tid, exfloor, pos_x, pos_y, pos_z, spec_type, args[0], args[1], args[2], args[3], args[4]}); end(); resizable(NULL); } void UI_ThingBox::type_callback(Fl_Widget *w, void *data) { UI_ThingBox *box = (UI_ThingBox *)data; int new_type = atoi(box->type->value()); const thingtype_t &info = box->inst.conf.getThingType(new_type); box->desc->value(info.desc.c_str()); box->sprite->GetSprite(new_type, FL_DARK2); if (!box->inst.edit.Selected->empty()) { EditOperation op(box->inst.level.basis); op.setMessageForSelection("edited type of", *box->inst.edit.Selected); for (sel_iter_c it(*box->inst.edit.Selected) ; !it.done() ; it.next()) { op.changeThing(*it, Thing::F_TYPE, new_type); } } } void UI_ThingBox::dyntype_callback(Fl_Widget *w, void *data) { UI_ThingBox *box = (UI_ThingBox *)data; if (box->obj < 0) return; int value = atoi(box->type->value()); const thingtype_t &info = box->inst.conf.getThingType(value); box->desc->value(info.desc.c_str()); box->sprite->GetSprite(value, FL_DARK2); } void UI_ThingBox::spec_callback(Fl_Widget *w, void *data) { UI_ThingBox *box = (UI_ThingBox *)data; int new_type = atoi(box->spec_type->value()); const linetype_t &info = box->inst.conf.getLineType(new_type); if (new_type == 0) box->spec_desc->value(""); else box->spec_desc->value(info.desc.c_str()); if (!box->inst.edit.Selected->empty()) { EditOperation op(box->inst.level.basis); op.setMessageForSelection("edited special of", *box->inst.edit.Selected); for (sel_iter_c it(*box->inst.edit.Selected) ; !it.done() ; it.next()) { op.changeThing(*it, Thing::F_SPECIAL, new_type); } } } void UI_ThingBox::dynspec_callback(Fl_Widget *w, void *data) { UI_ThingBox *box = (UI_ThingBox *)data; if (box->obj < 0 || box->inst.loaded.levelFormat == MapFormat::doom) return; int value = atoi(box->spec_type->value()); if (value) { const linetype_t &info = box->inst.conf.getLineType(value); box->spec_desc->value(info.desc.c_str()); } else { box->spec_desc->value(""); } } void UI_ThingBox::SetThingType(int new_type) { if (obj < 0) return; char buffer[64]; snprintf(buffer, sizeof(buffer), "%d", new_type); mFixUp.checkDirtyFields(); mFixUp.setInputValue(type, buffer); type->do_callback(); } void UI_ThingBox::SetSpecialType(int new_type) { if (obj < 0) return; char buffer[64]; snprintf(buffer, sizeof(buffer), "%d", new_type); mFixUp.checkDirtyFields(); mFixUp.setInputValue(spec_type, buffer); spec_type->do_callback(); } // // Thing box clipboard operation // bool UI_ThingBox::ClipboardOp(EditCommand op) { return false; } void UI_ThingBox::BrowsedItem(BrowserMode kind, int number, const char *name, int e_state) { if (kind == BrowserMode::things) { SetThingType(number); } else if (kind == BrowserMode::lineTypes && inst.loaded.levelFormat != MapFormat::doom) { SetSpecialType(number); } } void UI_ThingBox::angle_callback(Fl_Widget *w, void *data) { UI_ThingBox *box = (UI_ThingBox *)data; int new_ang = atoi(box->angle->value()); if (!box->inst.edit.Selected->empty()) { EditOperation op(box->inst.level.basis); op.setMessageForSelection("edited angle of", *box->inst.edit.Selected); for (sel_iter_c it(*box->inst.edit.Selected); !it.done(); it.next()) { op.changeThing(*it, Thing::F_ANGLE, new_ang); } } } // IOANCH 9/2015 void UI_ThingBox::tid_callback(Fl_Widget *w, void *data) { UI_ThingBox *box = (UI_ThingBox *)data; int new_tid = atoi(box->tid->value()); if (!box->inst.edit.Selected->empty()) { EditOperation op(box->inst.level.basis); op.setMessageForSelection("edited TID of", *box->inst.edit.Selected); for (sel_iter_c it(*box->inst.edit.Selected); !it.done(); it.next()) { op.changeThing(*it, Thing::F_TID, new_tid); } } } void UI_ThingBox::x_callback(Fl_Widget *w, void *data) { UI_ThingBox *box = (UI_ThingBox *)data; int new_x = atoi(box->pos_x->value()); if (!box->inst.edit.Selected->empty()) { EditOperation op(box->inst.level.basis); op.setMessageForSelection("edited X of", *box->inst.edit.Selected); for (sel_iter_c it(*box->inst.edit.Selected); !it.done(); it.next()) op.changeThing(*it, Thing::F_X, MakeValidCoord(box->inst.loaded.levelFormat, new_x)); } } void UI_ThingBox::y_callback(Fl_Widget *w, void *data) { UI_ThingBox *box = (UI_ThingBox *)data; int new_y = atoi(box->pos_y->value()); if (!box->inst.edit.Selected->empty()) { EditOperation op(box->inst.level.basis); op.setMessageForSelection("edited Y of", *box->inst.edit.Selected); for (sel_iter_c it(*box->inst.edit.Selected); !it.done(); it.next()) op.changeThing(*it, Thing::F_Y, MakeValidCoord(box->inst.loaded.levelFormat, new_y)); } } void UI_ThingBox::z_callback(Fl_Widget *w, void *data) { UI_ThingBox *box = (UI_ThingBox *)data; int new_h = atoi(box->pos_z->value()); if (!box->inst.edit.Selected->empty()) { EditOperation op(box->inst.level.basis); op.setMessageForSelection("edited Z of", *box->inst.edit.Selected); for (sel_iter_c it(*box->inst.edit.Selected); !it.done(); it.next()) op.changeThing(*it, Thing::F_H, FFixedPoint(new_h)); } } void UI_ThingBox::option_callback(Fl_Widget *w, void *data) { thing_opt_CB_data_c *ocb = (thing_opt_CB_data_c *)data; UI_ThingBox *box = ocb->parent; int mask = ocb->mask; int new_opts = box->CalcOptions(); if (!box->inst.edit.Selected->empty()) { box->mFixUp.checkDirtyFields(); EditOperation op(box->inst.level.basis); op.setMessageForSelection("edited flags of", *box->inst.edit.Selected); for (sel_iter_c it(*box->inst.edit.Selected); !it.done(); it.next()) { const auto T = box->inst.level.things[*it]; // only change the bits specified in 'mask'. // this is important when multiple things are selected. op.changeThing(*it, Thing::F_OPTIONS, (T->options & ~mask) | (new_opts & mask)); } } } void UI_ThingBox::button_callback(Fl_Widget *w, void *data) { UI_ThingBox *box = (UI_ThingBox *)data; if (w == box->efl_down) box->AdjustExtraFloor(-1); if (w == box->efl_up) box->AdjustExtraFloor(+1); if (w == box->choose || w == box->sprite) box->inst.main_win->BrowserMode(BrowserMode::things); if (w == box->spec_choose) box->inst.main_win->BrowserMode(BrowserMode::lineTypes); box->mFixUp.checkDirtyFields(); // check for the angle buttons for (int i = 0 ; i < 8 ; i++) { if (w == box->ang_buts[i]) { char buffer[64]; snprintf(buffer, sizeof(buffer), "%d", i * 45); box->mFixUp.setInputValue(box->angle, buffer); angle_callback(box->angle, box); } } } void UI_ThingBox::args_callback(Fl_Widget *w, void *data) { thing_opt_CB_data_c *ocb = (thing_opt_CB_data_c *)data; UI_ThingBox *box = ocb->parent; int arg_idx = ocb->mask; int new_value = atoi(box->args[arg_idx]->value()); assert(arg_idx >= 0 && arg_idx <= 4); new_value = clamp(0, new_value, 255); if (!box->inst.edit.Selected->empty()) { EditOperation op(box->inst.level.basis); op.setMessageForSelection("edited args of", *box->inst.edit.Selected); for (sel_iter_c it(*box->inst.edit.Selected); !it.done(); it.next()) { op.changeThing(*it, static_cast(Thing::F_ARG1 + arg_idx), new_value); } } } void UI_ThingBox::AdjustExtraFloor(int dir) { if (!inst.level.isThing(obj)) return; int old_fl = atoi(exfloor->value()); int new_fl = (old_fl + dir) & 15; if(new_fl) mFixUp.setInputValue(exfloor, SString(new_fl).c_str()); else mFixUp.setInputValue(exfloor, ""); thing_opt_CB_data_c ocb(this, MTF_EXFLOOR_MASK); option_callback(this, &ocb); } void UI_ThingBox::OptionsFromInt(int options) { o_easy ->value((options & MTF_Easy) ? 1 : 0); o_medium->value((options & MTF_Medium) ? 1 : 0); o_hard ->value((options & MTF_Hard) ? 1 : 0); o_ambush->value((options & MTF_Ambush) ? 1 : 0); if (inst.loaded.levelFormat != MapFormat::doom) { o_sp ->value((options & MTF_Hexen_SP) ? 1 : 0); o_coop->value((options & MTF_Hexen_COOP) ? 1 : 0); o_dm ->value((options & MTF_Hexen_DM) ? 1 : 0); o_fight ->value((options & MTF_Hexen_Fighter) ? 1 : 0); o_cleric->value((options & MTF_Hexen_Cleric) ? 1 : 0); o_mage ->value((options & MTF_Hexen_Mage) ? 1 : 0); o_dormant->value((options & MTF_Hexen_Dormant) ? 1 : 0); } else { o_sp ->value((options & MTF_Not_SP) ? 0 : 1); o_coop->value((options & MTF_Not_COOP) ? 0 : 1); o_dm ->value((options & MTF_Not_DM) ? 0 : 1); o_vanilla_dm->value((options & MTF_Not_SP) ? 1 : 0); } if (inst.loaded.levelFormat == MapFormat::doom) { o_friend->value((options & MTF_Friend) ? 1 : 0); if(options & MTF_EXFLOOR_MASK) mFixUp.setInputValue(exfloor, SString((options & MTF_EXFLOOR_MASK) >> MTF_EXFLOOR_SHIFT).c_str()); else mFixUp.setInputValue(exfloor, ""); } if (inst.conf.features.strife_flags) { o_sf_ambush->value((options & MTF_Strife_Ambush) ? 1 : 0); o_sf_friend->value((options & MTF_Strife_Friend) ? 1 : 0); o_sf_shadow->value((options & MTF_Strife_Shadow) ? 1 : 0); o_sf_altvis->value((options & MTF_Strife_AltVis) ? 1 : 0); o_sf_stand ->value((options & MTF_Strife_Stand) ? 1 : 0); } } int UI_ThingBox::CalcOptions() const { int options = 0; if (o_easy ->value()) options |= MTF_Easy; if (o_medium->value()) options |= MTF_Medium; if (o_hard ->value()) options |= MTF_Hard; if (inst.conf.features.strife_flags) { if (o_sf_ambush->value()) options |= MTF_Strife_Ambush; if (o_sf_friend->value()) options |= MTF_Strife_Friend; if (o_sf_shadow->value()) options |= MTF_Strife_Shadow; if (o_sf_altvis->value()) options |= MTF_Strife_AltVis; if (o_sf_stand ->value()) options |= MTF_Strife_Stand; } else { if (o_ambush->value()) options |= MTF_Ambush; } if (inst.loaded.levelFormat != MapFormat::doom) { if (o_sp ->value()) options |= MTF_Hexen_SP; if (o_coop->value()) options |= MTF_Hexen_COOP; if (o_dm ->value()) options |= MTF_Hexen_DM; if (o_fight ->value()) options |= MTF_Hexen_Fighter; if (o_cleric->value()) options |= MTF_Hexen_Cleric; if (o_mage ->value()) options |= MTF_Hexen_Mage; if (o_dormant->value()) options |= MTF_Hexen_Dormant; } else if (inst.conf.features.coop_dm_flags) { if (0 == o_sp ->value()) options |= MTF_Not_SP; if (0 == o_coop->value()) options |= MTF_Not_COOP; if (0 == o_dm ->value()) options |= MTF_Not_DM; } else { if (o_vanilla_dm->value()) options |= MTF_Not_SP; } if (inst.loaded.levelFormat == MapFormat::doom) { if (inst.conf.features.friend_flag && o_friend->value()) options |= MTF_Friend; #if 0 int exfl_num = atoi(exfloor->value()); if (exfl_num > 0) { options |= (exfl_num << MTF_EXFLOOR_SHIFT) & MTF_EXFLOOR_MASK; } #endif } return options; } void UI_ThingBox::UpdateField(int field) { if (field < 0 || field == Thing::F_X || field == Thing::F_Y || field == Thing::F_H) { if (inst.level.isThing(obj)) { const auto T = inst.level.things[obj]; // @@ FIXME show decimals in UDMF mFixUp.setInputValue(pos_x, SString(static_cast(T->x())).c_str()); mFixUp.setInputValue(pos_y, SString(static_cast(T->y())).c_str()); mFixUp.setInputValue(pos_z, SString(static_cast(T->h())).c_str()); } else { mFixUp.setInputValue(pos_x, ""); mFixUp.setInputValue(pos_y, ""); mFixUp.setInputValue(pos_z, ""); } } if (field < 0 || field == Thing::F_ANGLE) { if(inst.level.isThing(obj)) mFixUp.setInputValue(angle, SString(inst.level.things[obj]->angle).c_str()); else mFixUp.setInputValue(angle, ""); } // IOANCH 9/2015 if (field < 0 || field == Thing::F_TID) { if(inst.level.isThing(obj)) mFixUp.setInputValue(tid, SString(inst.level.things[obj]->tid).c_str()); else mFixUp.setInputValue(tid, ""); } if (field < 0 || field == Thing::F_TYPE) { if (inst.level.isThing(obj)) { const thingtype_t &info = inst.conf.getThingType(inst.level.things[obj]->type); desc->value(info.desc.c_str()); mFixUp.setInputValue(type, SString(inst.level.things[obj]->type).c_str()); sprite->GetSprite(inst.level.things[obj]->type, FL_DARK2); } else { mFixUp.setInputValue(type, ""); desc ->value(""); sprite->Clear(); } } if (field < 0 || field == Thing::F_OPTIONS) { if (inst.level.isThing(obj)) OptionsFromInt(inst.level.things[obj]->options); else OptionsFromInt(0); } if (inst.loaded.levelFormat == MapFormat::doom) return; if (field < 0 || field == Thing::F_SPECIAL) { if (inst.level.isThing(obj) && inst.level.things[obj]->special) { const linetype_t &info = inst.conf.getLineType(inst.level.things[obj]->special); spec_desc->value(info.desc.c_str()); mFixUp.setInputValue(spec_type, SString(inst.level.things[obj]->special).c_str()); } else { mFixUp.setInputValue(spec_type, ""); spec_desc->value(""); } } if (field < 0 || (field >= Thing::F_ARG1 && field <= Thing::F_ARG5)) { for (int a = 0 ; a < 5 ; a++) { mFixUp.setInputValue(args[a], ""); args[a]->tooltip(NULL); args[a]->textcolor(FL_BLACK); } if (inst.level.isThing(obj)) { const auto T = inst.level.things[obj]; const thingtype_t &info = inst.conf.getThingType(T->type); const linetype_t &spec = inst.conf.getLineType (T->special); // set argument values and tooltips for (int a = 0 ; a < 5 ; a++) { int arg_val = T->Arg(1 + a); if (T->special) { mFixUp.setInputValue(args[a], SString(arg_val).c_str()); if (!spec.args[a].name.empty()) args[a]->copy_tooltip(spec.args[a].name.c_str()); else args[a]->textcolor(fl_rgb_color(160,160,160)); } else { // spawn arguments if(arg_val || !info.args[a].empty()) mFixUp.setInputValue(args[a], SString(arg_val).c_str()); if (!info.args[a].empty()) args[a]->copy_tooltip(info.args[a].c_str()); else args[a]->textcolor(fl_rgb_color(160,160,160)); } } } } } void UI_ThingBox::UpdateTotal(const Document &doc) noexcept { which->SetTotal(doc.numThings()); } void UI_ThingBox::UpdateGameInfo(const LoadingData &loaded, const ConfigData &config) { if (config.features.coop_dm_flags || loaded.levelFormat != MapFormat::doom) { o_sp ->show(); o_coop->show(); o_dm ->show(); o_vanilla_dm->hide(); } else { // this is appropriate for Strife too o_vanilla_dm->show(); o_sp ->hide(); o_coop->hide(); o_dm ->hide(); } if (config.features.friend_flag && !config.features.strife_flags) o_friend->show(); else o_friend->hide(); if (config.features.strife_flags) { o_ambush->hide(); o_sf_ambush->show(); o_sf_friend->show(); o_sf_shadow->show(); o_sf_altvis->show(); o_sf_stand ->show(); } else { o_ambush->show(); o_sf_ambush->hide(); o_sf_friend->hide(); o_sf_shadow->hide(); o_sf_altvis->hide(); o_sf_stand ->hide(); } /* map format stuff */ thing_opt_CB_data_c *ocb; if (loaded.levelFormat != MapFormat::doom) { pos_z->show(); tid->show(); o_fight ->show(); o_cleric->show(); o_mage ->show(); o_dormant->show(); spec_type ->show(); spec_choose->show(); spec_desc ->show(); for (int a = 0 ; a < 5 ; a++) args[a]->show(); // fix the masks for SP/COOP/DM ocb = (thing_opt_CB_data_c *) o_sp ->user_data(); ocb->mask = MTF_Hexen_SP; ocb = (thing_opt_CB_data_c *) o_coop->user_data(); ocb->mask = MTF_Hexen_COOP; ocb = (thing_opt_CB_data_c *) o_dm ->user_data(); ocb->mask = MTF_Hexen_DM; } else { pos_z->hide(); tid->hide(); o_fight ->hide(); o_cleric->hide(); o_mage ->hide(); o_dormant->hide(); spec_type ->hide(); spec_choose->hide(); spec_desc ->hide(); for (int a = 0 ; a < 5 ; a++) args[a]->hide(); // fix the masks for SP/COOP/DM ocb = (thing_opt_CB_data_c *) o_sp ->user_data(); ocb->mask = MTF_Not_SP; ocb = (thing_opt_CB_data_c *) o_coop->user_data(); ocb->mask = MTF_Not_COOP; ocb = (thing_opt_CB_data_c *) o_dm ->user_data(); ocb->mask = MTF_Not_DM; } redraw(); } void UI_ThingBox::UnselectPics() { sprite->Unhighlight(); sprite->Selected(false); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_thing.h000066400000000000000000000070661464327712600203200ustar00rootroot00000000000000//------------------------------------------------------------------------ // THING PANEL //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2018 Andrew Apted // Copyright (C) 2015 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_THING_H__ #define __EUREKA_UI_THING_H__ #include "e_cutpaste.h" #include "ui_panelinput.h" class Sticker; class UI_DynIntInput; class UI_ThingBox : public MapItemBox { private: UI_DynInput *type; Fl_Output *desc; Fl_Button *choose; UI_DynIntInput *angle; Fl_Button *ang_buts[8]; UI_DynIntInput *tid; UI_DynIntInput *exfloor; Fl_Button *efl_down; Fl_Button *efl_up; UI_DynIntInput *pos_x; UI_DynIntInput *pos_y; UI_DynIntInput *pos_z; // Options Fl_Check_Button *o_easy; Fl_Check_Button *o_medium; Fl_Check_Button *o_hard; Fl_Check_Button *o_sp; Fl_Check_Button *o_coop; Fl_Check_Button *o_dm; Fl_Check_Button *o_vanilla_dm; Fl_Check_Button *o_fight; // Fl_Check_Button *o_cleric; // Hexen Fl_Check_Button *o_mage; // Fl_Check_Button *o_ambush; Fl_Check_Button *o_friend; // Boom / MBF / Strife Fl_Check_Button *o_dormant; // Hexen Fl_Check_Button *o_sf_shadow; // Fl_Check_Button *o_sf_altvis; // Fl_Check_Button *o_sf_stand; // Strife Fl_Check_Button *o_sf_ambush; // Fl_Check_Button *o_sf_friend; // UI_Pic *sprite; // more Hexen stuff UI_DynInput *spec_type; Fl_Button *spec_choose; Fl_Output *spec_desc; UI_DynIntInput *args[5]; public: UI_ThingBox(Instance &inst, int X, int Y, int W, int H, const char *label = NULL); public: // call this if the thing was externally changed. // -1 means "all fields" void UpdateField(int field = -1) override; void UpdateTotal(const Document &doc) noexcept override; // see ui_window.h for description of these two methods bool ClipboardOp(EditCommand op); void BrowsedItem(BrowserMode kind, int number, const char *name, int e_state); void UpdateGameInfo(const LoadingData &loaded, const ConfigData &config) override; void UnselectPics() override; private: void SetThingType(int new_type); void SetSpecialType(int new_type); void AdjustExtraFloor(int dir); int CalcOptions() const; void OptionsFromInt(int options); private: static void x_callback(Fl_Widget *w, void *data); static void y_callback(Fl_Widget *w, void *data); static void z_callback(Fl_Widget *w, void *data); static void type_callback(Fl_Widget *w, void *data); static void dyntype_callback(Fl_Widget *, void *); static void angle_callback(Fl_Widget *w, void *data); static void tid_callback(Fl_Widget *w, void *data); static void option_callback(Fl_Widget *w, void *data); static void button_callback(Fl_Widget *w, void *data); static void spec_callback(Fl_Widget *w, void *data); static void dynspec_callback(Fl_Widget *w, void *data); static void args_callback(Fl_Widget *w, void *data); }; #endif /* __EUREKA_UI_THING_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_tile.cc000066400000000000000000000064401464327712600202750ustar00rootroot00000000000000//------------------------------------------------------------------------ // Adjustable border (variation of Fl_Tile) //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012-2013 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "main.h" #include "ui_tile.h" #include "ui_window.h" // // UI_Tile Constructor // UI_Tile::UI_Tile(int X, int Y, int W, int H, const char *what, Fl_Widget * _left, Fl_Widget * _right) : Fl_Tile(X, Y, W, H, what), left(_left), right(_right) { end(); add(left); add(right); right_W = right->w(); limiter = new Fl_Box(FL_NO_BOX, X + 32, Y, W - 32 - MIN_BROWSER_W, H, NULL); limiter->clear_visible(); // prevent this fucker from stealing events add(limiter); resizable(limiter); } // // UI_Tile Destructor // UI_Tile::~UI_Tile() { } void UI_Tile::resize(int X, int Y, int W, int H) { // resize ourself (skip the Fl_Group resize) Fl_Widget::resize(X, Y, W, H); // update limiter limiter->resize(X+32, Y, W - 32 - MIN_BROWSER_W, H); if (find(right) >= children()) { left->resize(X, Y, W, H); return; } // determine the width of the browser right_W = right->w(); if (right_W > w() - 32) right_W = w() - 32; if (right_W < MIN_BROWSER_W) right_W = MIN_BROWSER_W; left->resize(X, Y, W - right_W, H); right->resize(X + W - right_W, Y, right_W, H); } void UI_Tile::ResizeBoth() { right->resize(x() + w() - right_W, y(), right_W, h()); right->show(); right->redraw(); left->resize(x(), y(), w() - right_W, h()); left->redraw(); init_sizes(); } void UI_Tile::ShowRight() { if (find(right) < children()) return; // determine the width of the browser right_W = clamp(MIN_BROWSER_W, right_W, w() - 32); add(right); ResizeBoth(); } void UI_Tile::HideRight() { if (find(right) >= children()) return; // remember old width right_W = right->w(); right->hide(); remove(right); left->size(w(), h()); left->redraw(); // widgets in our group (the window) got rearranged, tell FLTK init_sizes(); } void UI_Tile::MinimiseRight() { if (find(right) >= children()) return; right_W = MIN_BROWSER_W; ResizeBoth(); } void UI_Tile::MaximiseRight() { if (find(right) >= children()) return; right_W = w() - 32; ResizeBoth(); } bool UI_Tile::ParseUser(const std::vector &tokens) { if (tokens[0] == "br_width" && tokens.size() >= 2) { bool was_visible = right->visible(); if (was_visible) HideRight(); right_W = atoi(tokens[1]); if (was_visible) ShowRight(); return true; } return false; } void UI_Tile::WriteUser(std::ostream &os) { os << "br_width " << (right->visible() ? right->w() : right_W) << '\n'; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_tile.h000066400000000000000000000033511464327712600201350ustar00rootroot00000000000000//------------------------------------------------------------------------ // Adjustable border (variation of Fl_Tile) //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2012 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_TILE_H__ #define __EUREKA_UI_TILE_H__ #include "FL/Fl_Tile.H" class UI_Tile : public Fl_Tile { private: Fl_Widget * left; Fl_Widget * right; Fl_Box * limiter; // when the right widget (the browser) is hidden, this remembers // how much of the available width it was using, so can restore it // where the user expects. // // NOTE: not set or used while right widget is visible. int right_W; public: UI_Tile(int X, int Y, int W, int H, const char *what, Fl_Widget *_left, Fl_Widget *_right); virtual ~UI_Tile(); /* FLTK method */ void resize(int, int, int, int); public: void ShowRight(); void HideRight(); void MinimiseRight(); void MaximiseRight(); bool ParseUser(const std::vector &tokens); void WriteUser(std::ostream &os); private: void ResizeBoth(); }; #endif /* __EUREKA_UI_TILE_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_vertex.cc000066400000000000000000000121331464327712600206510ustar00rootroot00000000000000//------------------------------------------------------------------------ // VERTEX PANEL //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Instance.h" #include "main.h" #include "ui_misc.h" #include "ui_window.h" #include "e_main.h" #include "m_game.h" #include "Vertex.h" #include "w_rawdef.h" // config items [ TODO ] int vertex_bump_small = 1; int vertex_bump_medium = 4; int vertex_bump_large = 16; extern const char *const *arrow_pixmaps[8]; // // UI_VertexBox Constructor // UI_VertexBox::UI_VertexBox(Instance &inst, int X, int Y, int W, int H, const char *label) : MapItemBox(inst,X, Y, W, H, label) { box(FL_FLAT_BOX); X += 6; Y += 6; W -= 12; H -= 10; which = new UI_Nombre(X+6, Y, W-12, 28, "Vertex"); Y += which->h() + 8; pos_x = new UI_DynIntInput(X + 64, Y, 75, 24, "x: "); pos_y = new UI_DynIntInput(X + 64, Y + 28, 75, 24, "y: "); pos_x->align(FL_ALIGN_LEFT); pos_y->align(FL_ALIGN_LEFT); pos_x->callback(x_callback, this); pos_y->callback(y_callback, this); int MX = X + W*2/3; move_left = new Fl_Button(MX - 30, Y + 14, 24, 24); move_left->image(new Fl_Pixmap(arrow_pixmaps[4])); move_left->align(FL_ALIGN_CENTER); move_left->callback(button_callback, this); move_up = new Fl_Button(MX, Y, 24, 24); move_up->image(new Fl_Pixmap(arrow_pixmaps[2])); move_up->align(FL_ALIGN_CENTER); move_up->callback(button_callback, this); move_down = new Fl_Button(MX, Y + 28, 24, 24); move_down->image(new Fl_Pixmap(arrow_pixmaps[6])); move_down->align(FL_ALIGN_CENTER); move_down->callback(button_callback, this); move_right = new Fl_Button(MX + 30, Y + 14, 24, 24); move_right->image(new Fl_Pixmap(arrow_pixmaps[0])); move_right->align(FL_ALIGN_CENTER); move_right->callback(button_callback, this); mFixUp.loadFields({pos_x, pos_y}); end(); resizable(NULL); } int UI_VertexBox::handle(int event) { return Fl_Group::handle(event); } void UI_VertexBox::x_callback(Fl_Widget *w, void *data) { UI_VertexBox *box = (UI_VertexBox *)data; int new_x = atoi(box->pos_x->value()); if (!box->inst.edit.Selected->empty()) { EditOperation op(box->inst.level.basis); op.setMessage("edited X of"/*, inst.edit.Selected*/); for (sel_iter_c it(*box->inst.edit.Selected); !it.done(); it.next()) { op.changeVertex(*it, Vertex::F_X, MakeValidCoord(box->inst.loaded.levelFormat, new_x)); } } } void UI_VertexBox::y_callback(Fl_Widget *w, void *data) { UI_VertexBox *box = (UI_VertexBox *)data; int new_y = atoi(box->pos_y->value()); if (!box->inst.edit.Selected->empty()) { EditOperation op(box->inst.level.basis); op.setMessage("edited Y of"/*, inst.edit.Selected*/); for (sel_iter_c it(*box->inst.edit.Selected); !it.done(); it.next()) { op.changeVertex(*it, Vertex::F_Y, MakeValidCoord(box->inst.loaded.levelFormat, new_y)); } } } void UI_VertexBox::button_callback(Fl_Widget *w, void *data) { UI_VertexBox *box = (UI_VertexBox *)data; int dx = 0; int dy = 0; if (w == box->move_left) dx = -1; if (w == box->move_right) dx = +1; if (w == box->move_up) dy = +1; if (w == box->move_down) dy = -1; keycode_t mod = Fl::event_state() & EMOD_ALL_MASK; int step = vertex_bump_medium; if (mod & EMOD_SHIFT) step = vertex_bump_small; else if (mod & EMOD_COMMAND) step = vertex_bump_large; if (!box->inst.edit.Selected->empty()) { FFixedPoint fdx = MakeValidCoord(box->inst.loaded.levelFormat, dx * step); FFixedPoint fdy = MakeValidCoord(box->inst.loaded.levelFormat, dy * step); box->mFixUp.checkDirtyFields(); EditOperation op(box->inst.level.basis); op.setMessage("adjusted"/*, inst.edit.Selected*/); for (sel_iter_c it(*box->inst.edit.Selected); !it.done(); it.next()) { const auto V = box->inst.level.vertices[*it]; op.changeVertex(*it, Vertex::F_X, V->raw_x + fdx); op.changeVertex(*it, Vertex::F_Y, V->raw_y + fdy); } } } //------------------------------------------------------------------------ void UI_VertexBox::UpdateField(int) { if (inst.level.isVertex(obj)) { // @@ FIXME show decimals in UDMF mFixUp.setInputValue(pos_x, SString(static_cast(inst.level.vertices[obj]->x())).c_str()); mFixUp.setInputValue(pos_y, SString(static_cast(inst.level.vertices[obj]->y())).c_str()); } else { mFixUp.setInputValue(pos_x, ""); mFixUp.setInputValue(pos_y, ""); } } void UI_VertexBox::UpdateTotal(const Document &doc) noexcept { which->SetTotal(doc.numVertices()); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_vertex.h000066400000000000000000000034351464327712600205200ustar00rootroot00000000000000//------------------------------------------------------------------------ // VERTEX PANEL //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2015 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_VERTEX_H__ #define __EUREKA_UI_VERTEX_H__ #include "ui_panelinput.h" class UI_DynIntInput; class UI_VertexBox : public MapItemBox { public: UI_DynIntInput *pos_x; UI_DynIntInput *pos_y; Fl_Button *move_left; Fl_Button *move_right; Fl_Button *move_up; Fl_Button *move_down; UI_VertexBox(Instance &inst, int X, int Y, int W, int H, const char *label = NULL); int handle(int event) override; // FLTK virtual method for handling input events. // call this if the vertex was externally changed. void UpdateField(int field = -1) override; void UnselectPics() override { } void UpdateGameInfo(const LoadingData &, const ConfigData &) override { } void UpdateTotal(const Document &doc) noexcept override; private: static void x_callback(Fl_Widget *, void *); static void y_callback(Fl_Widget *, void *); static void button_callback(Fl_Widget *, void *); }; #endif /* __EUREKA_UI_VERTEX_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_window.cc000066400000000000000000000365341464327712600206560ustar00rootroot00000000000000//------------------------------------------------------------------------ // MAIN WINDOW //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Instance.h" #include "main.h" #include "e_main.h" #include "m_config.h" #include "m_testmap.h" #include "r_render.h" #include "ui_window.h" #include "w_wad.h" #ifndef WIN32 #include #endif #if (FL_MAJOR_VERSION != 1 || FL_MINOR_VERSION < 3) #error "Require FLTK version 1.3.0 or later" #endif #define WINDOW_MIN_W 928 #define WINDOW_MIN_H 640 // // MainWin Constructor // UI_MainWindow::UI_MainWindow(Instance &inst) : Fl_Double_Window(WINDOW_MIN_W, WINDOW_MIN_H, EUREKA_TITLE), cursor_shape(FL_CURSOR_DEFAULT), mInstance(inst) { end(); // cancel begin() in Fl_Group constructor size_range(WINDOW_MIN_W, WINDOW_MIN_H); callback((Fl_Callback *) quit_callback); color(WINDOW_BG, WINDOW_BG); int cy = 0; int ey = h(); panel_W = 308; /* ---- Menu bar ---- */ { menu_bar = menu::create(0, 0, w()-3 - panel_W, 31, &mInstance); add(menu_bar); testmap::updateMenuName(menu_bar, inst.loaded); #ifndef __APPLE__ cy += menu_bar->h(); #endif } info_bar = new UI_InfoBar(mInstance, 0, ey - 31, w(), 31); add(info_bar); ey = ey - info_bar->h(); int browser_W = MIN_BROWSER_W + 66; int cw = w() - panel_W - browser_W; int ch = ey - cy; scroll = new UI_CanvasScroll(mInstance, 0, cy, cw, ch); // UI_CanvasScroll creates these, we mirror them for easier access canvas = scroll->canvas; status_bar = scroll->status; browser = new UI_Browser(inst, w() - panel_W - browser_W, cy, browser_W, ey - cy); tile = new UI_Tile(0, cy, w() - panel_W, ey - cy, NULL, scroll, browser); add(tile); resizable(tile); int BY = 0; // cy+2 int BH = ey-4; // ey-BY-2 thing_box = new UI_ThingBox(inst, w() - panel_W, BY, panel_W, BH); thing_box->hide(); add(thing_box); line_box = new UI_LineBox(inst, w() - panel_W, BY, panel_W, BH); line_box->hide(); add(line_box); sec_box = new UI_SectorBox(inst, w() - panel_W, BY, panel_W, BH); sec_box->hide(); add(sec_box); vert_box = new UI_VertexBox(inst, w() - panel_W, BY, panel_W, BH); add(vert_box); props_box = new UI_DefaultProps(inst, w() - panel_W, BY, panel_W, BH); props_box->hide(); add(props_box); find_box = new UI_FindAndReplace(inst, w() - panel_W, BY, panel_W, BH); find_box->hide(); add(find_box); mapItemBoxes[0] = thing_box; mapItemBoxes[1] = line_box; mapItemBoxes[2] = sec_box; mapItemBoxes[3] = vert_box; } // // MainWin Destructor // UI_MainWindow::~UI_MainWindow() { } void UI_MainWindow::quit_callback(Fl_Widget *w, void *data) { Main_Quit(); } void UI_MainWindow::NewEditMode(ObjType mode) { UnselectPics(); thing_box->hide(); line_box->hide(); sec_box->hide(); vert_box->hide(); props_box->hide(); find_box->hide(); switch (mode) { case ObjType::things: thing_box->show(); break; case ObjType::linedefs: line_box->show(); break; case ObjType::sectors: sec_box->show(); break; case ObjType::vertices: vert_box->show(); break; default: break; } info_bar->NewEditMode(mode); browser ->NewEditMode(mode); redraw(); } void UI_MainWindow::SetCursor(Fl_Cursor shape) noexcept { if (shape == cursor_shape) return; cursor_shape = shape; cursor(shape); } void UI_MainWindow::BrowserMode(::BrowserMode kind) { bool is_visible = browser->visible() ? true : false; if (is_visible && kind == ::BrowserMode::toggle) kind = ::BrowserMode::hide; bool want_visible = (kind != ::BrowserMode::hide) ? true : false; if (is_visible != want_visible) { if (want_visible) tile->ShowRight(); else tile->HideRight(); //?? // hiding the browser also clears any pic selection //?? if (! want_visible) //?? UnselectPics(); } if (kind != ::BrowserMode::hide && kind != ::BrowserMode::toggle) { browser->ChangeMode(kind); } } void UI_MainWindow::HideSpecialPanel() { props_box->hide(); find_box->hide(); switch (mInstance.edit.mode) { case ObjType::things: thing_box->show(); break; case ObjType::linedefs: line_box->show(); break; case ObjType::vertices: vert_box->show(); break; case ObjType::sectors: sec_box->show(); break; default: break; } redraw(); } void UI_MainWindow::ShowDefaultProps() { // already shown? if (props_box->visible()) { HideSpecialPanel(); return; } thing_box->hide(); line_box->hide(); sec_box->hide(); vert_box->hide(); find_box->hide(); props_box->show(); redraw(); } void UI_MainWindow::ShowFindAndReplace() { // already shown? if (find_box->visible()) { HideSpecialPanel(); return; } thing_box->hide(); line_box->hide(); sec_box->hide(); vert_box->hide(); props_box->hide(); find_box->Open(); redraw(); } void UI_MainWindow::UpdateTotals(const Document &doc) noexcept { for(MapItemBox *box : mapItemBoxes) box->UpdateTotal(doc); } int UI_MainWindow::GetPanelObjNum() const { // FIXME: using 'inst.edit' here feels like a hack or mis-design switch (mInstance.edit.mode) { case ObjType::things: return thing_box->GetObj(); case ObjType::vertices: return vert_box->GetObj(); case ObjType::sectors: return sec_box->GetObj(); case ObjType::linedefs: return line_box->GetObj(); default: return -1; } } void UI_MainWindow::InvalidatePanelObj() { for(MapItemBox *box : mapItemBoxes) if(box->visible()) box->SetObj(-1, 0); } void UI_MainWindow::UpdatePanelObj() { if (thing_box->visible()) thing_box->UpdateField(); if (line_box->visible()) { line_box->UpdateField(); line_box->UpdateSides(); } if (sec_box->visible()) sec_box->UpdateField(); if (vert_box->visible()) vert_box->UpdateField(); } void UI_MainWindow::UnselectPics() { for(MapItemBox *box : mapItemBoxes) box->UnselectPics(); } void UI_MainWindow::SetTitle(const SString &wad_namem, const SString &map_name, bool read_only) { static char title_buf[FL_PATH_MAX]; SString wad_name(wad_namem); if (wad_name.good()) { wad_name = fl_filename_name(wad_name.c_str()); snprintf(title_buf, sizeof(title_buf), "%s (%s)%s", wad_name.c_str(), map_name.c_str(), read_only ? " [Read-Only]" : ""); } else { snprintf(title_buf, sizeof(title_buf), "Unsaved %s", map_name.c_str()); } copy_label(title_buf); } void UI_MainWindow::UpdateTitle(char want_prefix) { if (! label()) return; char got_prefix = label()[0]; if (! ispunct(got_prefix)) got_prefix = 0; if (got_prefix == want_prefix) return; SString title_buf; const char *src = label() + (got_prefix ? 1 : 0); if (want_prefix) { title_buf.push_back(want_prefix); } title_buf.insert(title_buf.length(), src); copy_label(title_buf.c_str()); } /* DISABLED, since it fails miserably on every platform void UI_MainWindow::ToggleFullscreen() { if (last_w) { fullscreen_off(last_x, last_y, last_w, last_h); last_w = last_h = 0; } else { last_x = x(); last_y = y(); last_w = w(); last_h = h(); fullscreen(); } } */ // // see if one of the panels wants to perform a clipboard op, // because a texture is highlighted or selected (for example). // bool UI_MainWindow::ClipboardOp(EditCommand op) { if(props_box->visible()) return props_box->ClipboardOp(op); if(find_box->visible()) return find_box->ClipboardOp(op); if(line_box->visible()) return line_box->ClipboardOp(op); if(sec_box->visible()) return sec_box->ClipboardOp(op); if(thing_box->visible()) return thing_box->ClipboardOp(op); // no panel wanted it return false; } void UI_MainWindow::BrowsedItem(::BrowserMode kind, int number, const char *name, int e_state) { // fprintf(stderr, "BrowsedItem: kind '%c' --> %d / \"%s\"\n", kind, number, name); if (props_box->visible()) { props_box->BrowsedItem(kind, number, name, e_state); } else if (find_box->visible()) { find_box->BrowsedItem(kind, number, name, e_state); } else if (line_box->visible()) { line_box->BrowsedItem(kind, number, name, e_state); } else if (sec_box->visible()) { sec_box->BrowsedItem(kind, number, name, e_state); } else if (thing_box->visible()) { thing_box->BrowsedItem(kind, number, name, e_state); } else { mInstance.Beep("no target for browsed item"); } } void UI_MainWindow::Maximize() { #if defined(WIN32) HWND hWnd = fl_xid(this); ShowWindow(hWnd, SW_MAXIMIZE); #elif defined(__APPLE__) // FIXME : something like this... (AFAIK) // // Window handle = fl_xid(this); // really an NSWindow * // // if (! [handle isZoomed]) // [handle zoom:nil]; #else /* Linux + X11 */ Window xid = fl_xid(this); Atom wm_state = XInternAtom(fl_display, "_NET_WM_STATE", False); Atom vmax = XInternAtom(fl_display, "_NET_WM_STATE_MAXIMIZED_VERT", False); Atom hmax = XInternAtom(fl_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False); XEvent xev; memset(&xev, 0, sizeof(xev)); xev.type = ClientMessage; xev.xclient.window = xid; xev.xclient.message_type = wm_state; xev.xclient.format = 32; xev.xclient.data.l[0] = 2; xev.xclient.data.l[1] = hmax; xev.xclient.data.l[2] = vmax; XSendEvent(fl_display, DefaultRootWindow(fl_display), False, SubstructureNotifyMask, &xev); Delay(3); #endif } void UI_MainWindow::Delay(int steps) { for (; steps > 0 ; steps--) { TimeDelay(100); Fl::check(); } } void UI_MainWindow::UpdateGameInfo(const LoadingData &loading, const ConfigData &config) { for(MapItemBox *box : mapItemBoxes) box->UpdateGameInfo(loading, config); } // draw() and handle() are overridden here merely to prevent fatal // errors becoming infinite loops. That can happen because we use // FLTK to show a dialog with the error message, and the same code // which triggered the fatal error can be re-entered. int UI_MainWindow::handle(int event) { if (global::in_fatal_error) return 0; return Fl_Double_Window::handle(event); } void UI_MainWindow::draw() { if (global::in_fatal_error) return; return Fl_Double_Window::draw(); } //------------------------------------------------------------------------ int UI_Escapable_Window::handle(int event) { if (event == FL_KEYDOWN && Fl::event_key() == FL_Escape) { do_callback(); return 1; } return Fl_Double_Window::handle(event); } //------------------------------------------------------------------------ #define MAX_LOG_LINES 1000 UI_LogViewer * log_viewer; UI_LogViewer::UI_LogViewer(Instance &inst) : UI_Escapable_Window(580, 400, "Eureka Log Viewer"), inst(inst) { box(FL_NO_BOX); size_range(480, 200); int ey = h() - 65; browser = new Fl_Multi_Browser(0, 0, w(), ey); browser->textsize(16); browser->callback(select_callback, this); resizable(browser); { Fl_Group *o = new Fl_Group(0, ey, w(), h() - ey); o->box(FL_FLAT_BOX); if (config::gui_color_set == 2) o->color(fl_gray_ramp(4)); else o->color(WINDOW_BG); int bx = w() - 110; int bx2 = bx; { Fl_Button * but = new Fl_Button(bx, ey + 15, 80, 35, "Close"); but->labelfont(1); but->callback(ok_callback, this); } bx = 30; { Fl_Button * but = new Fl_Button(bx, ey + 15, 80, 35, "Save..."); but->callback(save_callback, this); } bx += 105; { Fl_Button * but = new Fl_Button(bx, ey + 15, 80, 35, "Clear"); but->callback(clear_callback, this); } bx += 105; { copy_but = new Fl_Button(bx, ey + 15, 80, 35, "Copy"); copy_but->callback(copy_callback, this); copy_but->shortcut(FL_CTRL + 'c'); copy_but->deactivate(); } bx += 80; Fl_Group *resize_box = new Fl_Group(bx + 10, ey + 2, bx2 - bx - 20, h() - ey - 4); resize_box->box(FL_NO_BOX); o->resizable(resize_box); o->end(); } end(); } UI_LogViewer::~UI_LogViewer() { } void UI_LogViewer::Deselect() { browser->deselect(); copy_but->deactivate(); } void UI_LogViewer::JumpEnd() { if (browser->size() > 0) { browser->bottomline(browser->size()); } } int UI_LogViewer::CountSelectedLines() const { int count = 0; for (int i = 1 ; i <= browser->size() ; i++) if (browser->selected(i)) count++; return count; } SString UI_LogViewer::GetSelectedText() const { SString buf; for (int i = 1 ; i <= browser->size() ; i++) { if (! browser->selected(i)) continue; const char *line_text = browser->text(i); if (! line_text) continue; // append current line onto previous ones SString new_buf = buf + line_text; if (!new_buf.empty() && new_buf.back() != '\n') new_buf.push_back('\n'); buf = new_buf; } return buf; } void UI_LogViewer::Add(const char *line) { browser->add(line); if (browser->size() > MAX_LOG_LINES) browser->remove(1); if (shown()) browser->bottomline(browser->size()); } void LogViewer_AddLine(const char *str) { if (log_viewer) log_viewer->Add(str); } void UI_LogViewer::ok_callback(Fl_Widget *w, void *data) { UI_LogViewer *that = (UI_LogViewer *)data; that->do_callback(); } void UI_LogViewer::clear_callback(Fl_Widget *w, void *data) { UI_LogViewer *that = (UI_LogViewer *)data; that->browser->clear(); that->copy_but->deactivate(); that->Add(""); } void UI_LogViewer::select_callback(Fl_Widget *w, void *data) { UI_LogViewer *that = (UI_LogViewer *)data; // require 2 or more lines to activate Copy button if (that->CountSelectedLines() >= 2) that->copy_but->activate(); else that->copy_but->deactivate(); } void UI_LogViewer::copy_callback(Fl_Widget *w, void *data) { UI_LogViewer *that = (UI_LogViewer *)data; SString text = that->GetSelectedText(); if (!text.empty()) { Fl::copy(text.c_str(), (int)text.length(), 1); } } void UI_LogViewer::save_callback(Fl_Widget *w, void *data) { Fl_Native_File_Chooser chooser; auto viewer = static_cast(data); chooser.title("Pick file to save to"); chooser.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); chooser.filter("Text files\t*.txt"); chooser.directory(viewer->inst.Main_FileOpFolder().u8string().c_str()); switch (chooser.show()) { case -1: DLG_Notify("Unable to save the log file:\n\n%s", chooser.errmsg()); return; case 1: // cancelled return; default: break; // OK } // add an extension if missing SString filename = chooser.filename(); if(!HasExtension(filename.get())) filename += ".txt"; // TODO: #55 std::ofstream os(filename.c_str(), std::ios::trunc); if (! os.is_open()) { filename = GetErrorMessage(errno); DLG_Notify("Unable to save the log file:\n\n%s", filename.c_str()); return; } gLog.saveTo(os); } void LogViewer_Open() { if (! log_viewer) return; // always call show() -- to raise the window log_viewer->show(); log_viewer->Deselect(); log_viewer->JumpEnd(); } // // Executes Fl::Focus if safe to do so. ONLY NEEDED to be called during window setup. // // Under the ratpoison Linux desktop environment it has been seen to block drawing of other // controls. // void FLFocusOnCreation(Fl_Widget *widget) { #if defined(_WIN32) || defined(__APPLE__) Fl::focus(widget); #endif } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/ui_window.h000066400000000000000000000123731464327712600205130ustar00rootroot00000000000000//------------------------------------------------------------------------ // MAIN WINDOW //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2006-2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_UI_WINDOW_H__ #define __EUREKA_UI_WINDOW_H__ #include "e_cutpaste.h" #include "ui_menu.h" #include "ui_canvas.h" #include "ui_infobar.h" #include "ui_hyper.h" #include "ui_nombre.h" #include "ui_pic.h" #include "ui_scroll.h" #include "ui_tile.h" #include "ui_browser.h" #include "ui_default.h" #include "ui_editor.h" #include "ui_replace.h" #include "ui_thing.h" #include "ui_sector.h" #include "ui_sidedef.h" #include "ui_linedef.h" #include "ui_vertex.h" #include "FL/Fl_Sys_Menu_Bar.H" #include #define WINDOW_BG FL_DARK3 #define MIN_BROWSER_W 250 class Fl_Multi_Browser; class Wad_file; void LogViewer_AddLine(const char *str); class UI_MainWindow : public Fl_Double_Window { public: // main child widgets Fl_Sys_Menu_Bar *menu_bar; int panel_W; UI_Tile * tile; UI_CanvasScroll *scroll; UI_Canvas *canvas; UI_Browser *browser; UI_InfoBar *info_bar; UI_StatusBar *status_bar; UI_ThingBox *thing_box; UI_LineBox *line_box; UI_SectorBox *sec_box; UI_VertexBox *vert_box; UI_FindAndReplace *find_box; private: UI_DefaultProps *props_box; // active cursor Fl_Cursor cursor_shape; // remember window size/position after going fullscreen. // the 'last_w' and 'last_h' fields are zero when not fullscreen // int last_x = 0, last_y = 0, last_w = 0, last_h = 0; MapItemBox *mapItemBoxes[4] = {}; public: explicit UI_MainWindow(Instance &inst); virtual ~UI_MainWindow(); // FLTK methods int handle(int event); void draw(); void propsLoadValues() { assert(props_box); props_box->LoadValues(); } public: void SetTitle(const SString &wad_name, const SString &map_name, bool read_only); // add or remove the '*' (etc) in the title void UpdateTitle(char want_prefix = 0); void Maximize(); void NewEditMode(ObjType mode); // this is a wrapper around the FLTK cursor() method which // prevents the possibly expensive call when the shape hasn't // changed. void SetCursor(Fl_Cursor shape) noexcept; // show or hide the Browser panel. // kind is NUL or '-' to hide, '/' to toggle, 'T' for textures, 'F' flats, // 'O' for thing types, 'L' line types, 'S' sector types. void BrowserMode(::BrowserMode kind); void ShowDefaultProps(); void ShowFindAndReplace(); void UpdateTotals(const Document &doc) noexcept; int GetPanelObjNum() const; void InvalidatePanelObj(); void UpdatePanelObj(); void UnselectPics(); void HideSpecialPanel(); bool isSpecialPanelShown() { return props_box->visible() || find_box->visible(); } void Delay(int steps); // each step is 1/10th second // see if one of the panels wants to perform a clipboard op, // because a texture is highlighted or selected (for example). // op == 'c' for copy, 'x' cut, 'v' paste, 'd' delete. bool ClipboardOp(EditCommand op); // this is used by the browser when user clicks on an entry. // kind == 'T' for textures (etc... as above) void BrowsedItem(::BrowserMode kind, int number, const char *name, int e_state); // this is called when game_info changes (in Main_LoadResources) // and can enable / disable stuff in the panels. void UpdateGameInfo(const LoadingData &loading, const ConfigData &config); private: static void quit_callback(Fl_Widget *w, void *data); Instance &mInstance; }; //------------------------------------------------------------------------ class UI_Escapable_Window : public Fl_Double_Window { public: UI_Escapable_Window(int W, int H, const char *L = NULL) : Fl_Double_Window(W, H, L) { } virtual ~UI_Escapable_Window() { } public: // FLTK event handling method int handle(int event); }; //------------------------------------------------------------------------ class UI_LogViewer : public UI_Escapable_Window { private: Fl_Multi_Browser * browser; Fl_Button * copy_but; Instance& inst; public: UI_LogViewer(Instance &inst); virtual ~UI_LogViewer(); void Add(const char *line); void Deselect(); // ensure the very last line is visible void JumpEnd(); private: int CountSelectedLines() const; SString GetSelectedText() const; static void ok_callback(Fl_Widget *, void *); static void clear_callback(Fl_Widget *, void *); static void save_callback(Fl_Widget *, void *); static void select_callback(Fl_Widget *, void *); static void copy_callback(Fl_Widget *, void *); }; extern UI_LogViewer * log_viewer; void LogViewer_Open(); void FLFocusOnCreation(Fl_Widget *widget); #endif /* __EUREKA_UI_WINDOW_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/version.h.in000066400000000000000000000004561464327712600206000ustar00rootroot00000000000000#ifndef VERSION_H_ #define VERSION_H_ #define EUREKA_VERSION "@PROJECT_VERSION@" #define EUREKA_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ #define EUREKA_VERSION_MINOR @PROJECT_VERSION_MINOR@ #define EUREKA_VERSION_PATCH @PROJECT_VERSION_PATCH@ #define EUREKA_VERSION_TWEAK @PROJECT_VERSION_TWEAK@ #endif eureka-editor-eureka-2.0.2/src/w_dehacked.cc000066400000000000000000000241561464327712600207250ustar00rootroot00000000000000//------------------------------------------------------------------------ // DEHACKED //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ // THANKS TO Isaac Colón (https://github.com/iccolon818) for this contribution. I added reformatting // and some input checking. #include "w_dehacked.h" #include "dehconsts.h" #include "lib_util.h" #include "m_game.h" #include "m_parse.h" #include "m_streams.h" #include "m_strings.h" #include "sys_debug.h" #include "w_wad.h" #include "WadData.h" #include #include #include #include namespace dehacked { //Relevant DEH values for editor things enum { // Things SPAWNFRAME = 0, RADIUS, ID, FLAGS, //Frames SPRITENUM, SUBSPRITENUM }; enum { SOLID = 1 << 1, SPAWNCEILING = 1 << 8, SHADOW = 1 << 18 }; static const char* FIELDS[] = { "Initial frame = ", "Width = ", "ID # = ", "Bits = ", "Sprite number = ", "Sprite subnumber = " }; struct thing_t { thingtype_t thing; int spawnframenum; }; inline const struct {SString cat; char group;} DB_CATEGORIES[] = { {"Monsters", 'm'}, {"Weapons", 'w'}, {"Ammunition", 'a'}, {"Health and Armor", 'h'}, {"Powerups", 'b'}, {"Keys", 'k'}, {"Obstacles", 'd'}, {"Light sources", 'l'}, {"Decoration", 'g'} }; static void readThing(std::istream &is, const ConfigData &config, thing_t &newthing, int &newthingid) { const thingtype_t *configThing = get(config.thing_types, newthingid); thingtype_t thing = {}; if(configThing) thing = *configThing; SString dehline; bool morelines = M_ReadTextLine(dehline, is); while(dehline.good() && morelines) { if (dehline.startsWith(FIELDS[SPAWNFRAME])) newthing.spawnframenum = atoi(dehline.substr(dehline.find("=") + 2)); else if (dehline.startsWith(FIELDS[RADIUS])) thing.radius = (short)(atoi(dehline.substr(dehline.find("=") + 2)) >> 16); else if (dehline.startsWith(FIELDS[ID])) newthingid = atoi(dehline.substr(dehline.find("=") + 2)); else if (dehline.startsWith(FIELDS[FLAGS])) { SString dehbits = dehline.substr(dehline.find("=") + 2); bool vanillabits = true; for (int i = 0; (size_t)i < dehbits.length(); i++) { if (dehbits[i] < '0' || dehbits[i] > '9') vanillabits = false; } if (vanillabits) { int bits = atoi(dehbits); if (bits ^ SOLID) thing.flags |= THINGDEF_PASS; else thing.flags &= ~THINGDEF_PASS; if (bits & SPAWNCEILING) thing.flags |= THINGDEF_CEIL; else thing.flags &= ~THINGDEF_CEIL; if (bits & SHADOW) thing.flags |= THINGDEF_INVIS; else thing.flags &= ~THINGDEF_INVIS; } else { if (dehbits.find("SOLID") != std::string::npos) thing.flags |= THINGDEF_PASS; else thing.flags &= ~THINGDEF_PASS; if (dehbits.find("SPAWNCEILING") != std::string::npos) thing.flags |= THINGDEF_CEIL; else thing.flags &= ~THINGDEF_CEIL; if (dehbits.find("SHADOW") != std::string::npos) thing.flags |= THINGDEF_INVIS; else thing.flags &= ~THINGDEF_INVIS; } } else if (dehline.startsWith("#$Editor category = ")) { SString category = dehline.substr(dehline.find("=") + 2); for (int i = 0; i < 9; i++) { if (category == DB_CATEGORIES[i].cat) { thing.group = DB_CATEGORIES[i].group; break; } } } morelines = M_ReadTextLine(dehline, is); } newthing.thing = thing; } static SString thingName(std::vector tokens) { SString ret = ""; for (int i = 2; (size_t)i < tokens.size(); i++) { ret += tokens[i]; if ((long unsigned int)i != tokens.size()-1) ret += " "; } return ret.substr(1, ret.length()-2); } static void readFrame(std::istream &is, frame_t &frame) { SString dehline; bool morelines = M_ReadTextLine(dehline, is); while(dehline.good() && morelines) { if (dehline.startsWith(FIELDS[SPRITENUM])) frame.spritenum = atoi(dehline.substr(dehline.find("=") + 2)); else if (dehline.startsWith(FIELDS[SUBSPRITENUM])) { int subnumber = atoi(dehline.substr(dehline.find("=") + 2)); if (subnumber & 0x8000) { frame.bright = true; subnumber &= (~0x8000); } frame.subspritenum = subnumber; } morelines = M_ReadTextLine(dehline, is); } } static void read(std::istream &is, ConfigData &config) { SString dehline; bool morelines; std::map deh_things; std::map spawn_frames; std::map dsdhacked_sprites; std::map renamed_sprites; auto checkCount = [](int count, const char *label) { assert(count >= 0); if(count <= 1) { gLog.printf("Missing number for %s\n", label); return false; } return true; }; auto getNum = [](const std::vector &tokens, const char *label, int &dehnum) { char *endptr = nullptr; dehnum = (int)strtol(tokens[1].c_str(), &endptr, 10); if(endptr == tokens[1].c_str()) { gLog.printf("Invalid %s number %s\n", label, tokens[1].c_str()); return false; } return true; }; for(morelines = M_ReadTextLine(dehline, is); morelines; morelines = M_ReadTextLine(dehline, is)) { //Get Dehacked Thing if (dehline.startsWith("Thing")) { std::vector tokens; int count = M_ParseLine(dehline, tokens, ParseOptions::noStrings); if(!checkCount(count, "Thing")) continue; thing_t newthing = {}; int dehnum; if(!getNum(tokens, "Thing", dehnum)) continue; int newthingid = -1; if (dehnum < (int)lengthof(THING_NUM_TO_TYPE)) newthingid = THING_NUM_TO_TYPE[dehnum]; if(dehnum < (int)lengthof(THING_NUM_TO_SPRITE)) newthing.spawnframenum = THING_NUM_TO_SPRITE[dehnum]; int oldthingid = newthingid; readThing(is, config, newthing, newthingid); newthing.thing.desc = thingName(tokens); //No things with DoomEd Number -1 if (newthingid == -1) config.thing_types.erase(newthingid); else { if(newthingid != oldthingid) config.thing_types.erase(oldthingid); deh_things[newthingid] = newthing; } } //Get Dehacked Frame else if (dehline.startsWith("Frame")) { std::vector tokens; int count = M_ParseLine(dehline, tokens, ParseOptions::noStrings); if(!checkCount(count, "Frame")) continue; int framenum; if(!getNum(tokens, "Frame", framenum)) continue; frame_t frame = {}; if (framenum < (int)(lengthof(FRAMES) - 1)) frame = FRAMES[framenum]; //Init with default value else frame = DEHEXTRA_FRAME; readFrame(is, frame); spawn_frames[framenum] = frame; } //Get changed sprite names else if (dehline == "Text 4 4") { morelines = M_ReadTextLine(dehline, is); if (morelines) { SString oldname = dehline.substr(0, 4); SString newname = dehline.substr(4, 4); renamed_sprites[oldname] = newname; } } //Read DSDHacked sprites table else if (dehline == "[SPRITES]") { morelines = M_ReadTextLine(dehline, is); while(morelines && dehline.good()) { std::vector tokens; int count = M_ParseLine(dehline, tokens, ParseOptions::noStrings); assert(count >= 0); if(count < 3) { gLog.printf("Invalid [SPRITES] syntax, found only %d words\n", count); continue; } int spritenum = atoi(tokens[0]); dsdhacked_sprites[spritenum] = tokens[2]; morelines = M_ReadTextLine(dehline, is); } } } //Apply DEHACKED things to editor config for (std::map::iterator it = deh_things.begin(); it != deh_things.end(); it++) { int spawnframenum = it->second.spawnframenum; frame_t spawnframe = {}; if (spawn_frames.find(spawnframenum) != spawn_frames.end()) spawnframe = spawn_frames[spawnframenum]; else if (spawnframenum < (int)(lengthof(FRAMES) - 1)) spawnframe = FRAMES[spawnframenum]; //Get default else spawnframe = DEHEXTRA_FRAME; if (spawnframe.bright) it->second.thing.flags |= THINGDEF_LIT; else it->second.thing.flags &= ~THINGDEF_LIT; SString sprite = ""; if (dsdhacked_sprites.find(spawnframe.spritenum) != dsdhacked_sprites.end()) sprite = dsdhacked_sprites[spawnframe.spritenum]; else if (spawnframe.spritenum < (int)lengthof(SPRITE_BY_INDEX)) sprite = SPRITE_BY_INDEX[spawnframe.spritenum]; else if (spawnframe.spritenum < (int)(lengthof(SPRITE_BY_INDEX) + 10)) sprite = "SP0" + std::to_string(spawnframe.spritenum - lengthof(SPRITE_BY_INDEX)); else if (spawnframe.spritenum < (int)(lengthof(SPRITE_BY_INDEX) + 99)) sprite = "SP" + std::to_string(spawnframe.spritenum - lengthof(SPRITE_BY_INDEX)); if (renamed_sprites.find(sprite) != renamed_sprites.end()) { sprite = renamed_sprites[sprite]; } //This shouldn't happen. if (sprite.empty()) continue; if (spawnframe.subspritenum > 0) sprite += char('A' + spawnframe.subspritenum); it->second.thing.sprite = sprite; config.thing_types[it->first] = it->second.thing; } } bool loadFile(const fs::path &resource, ConfigData &config) { std::ifstream ifs(resource); if(!ifs.is_open()) return false; read(ifs, config); return true; } void loadLumps(const MasterDir &master, ConfigData &config) { auto wads = master.getAll(); for (const auto &wad : wads) { const Lump_c *dehlump = wad->FindLump("DEHACKED"); if (!dehlump) continue; std::istringstream iss(std::string(reinterpret_cast(dehlump->getData().data()), dehlump->Length())); read(iss, config); } } } eureka-editor-eureka-2.0.2/src/w_dehacked.h000066400000000000000000000031121464327712600205540ustar00rootroot00000000000000//------------------------------------------------------------------------ // DEHACKED //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ // THANKS TO Isaac Colón (https://github.com/iccolon818) for this contribution. I added reformatting // and some input checking. #ifndef __EUREKA_W_DEHACKED_H__ #define __EUREKA_W_DEHACKED_H__ #include "filesystem.hpp" namespace fs = ghc::filesystem; class MasterDir; struct ConfigData; namespace dehacked { struct frame_t { int spritenum; int subspritenum; bool bright; }; bool loadFile(const fs::path &resource, ConfigData &config); void loadLumps(const MasterDir &master, ConfigData &config); } #endif eureka-editor-eureka-2.0.2/src/w_loadpic.cc000066400000000000000000000241261464327712600206050ustar00rootroot00000000000000//------------------------------------------------------------------------ // WAD PIC LOADER //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2020 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include "im_color.h" /* trans_replace */ #include "im_img.h" #include "lib_tga.h" #include "m_game.h" #include "w_loadpic.h" #include "w_rawdef.h" #include "w_wad.h" // posts are runs of non masked source pixels struct post_t { // offset down from top. P_SENTINEL terminates the list. byte topdelta; // length data bytes follows byte length; /* byte pixels[length+2] */ }; #define P_SENTINEL 0xFF static void DrawColumn(const Palette &pal, const ConfigData &config,Img_c& img, const post_t *column, int x, int y) { SYS_ASSERT(column); int W = img.width(); int H = img.height(); // clip horizontally if (x < 0 || x >= W) return; while (column->topdelta != P_SENTINEL) { int top = y + (int) column->topdelta; int count = column->length; byte *src = (byte *) column + 3; img_pixel_t *dest = img.wbuf() + x; if (top < 0) { // The original DOOM did not honor negative y-offsets for // patches but some ports like ZDoom do. if (config.features.neg_patch_offsets) src -= top; count += top; top = 0; } if (top + count > H) count = H - top; // copy the pixels, remapping any TRANS_PIXEL values for (; count > 0; count--, top++) { byte pix = *src++; if (pix == TRANS_PIXEL) pix = static_cast(pal.getTransReplace()); dest[top * W] = pix; } column = (const post_t *) ((const byte *) column + column->length + 4); } } tl::optional LoadImage_PNG(const Lump_c &lump, const SString &name) { // load the raw data const std::vector &tex_data = lump.getData(); // pass it to FLTK for decoding Fl_PNG_Image fltk_img(NULL, tex_data.data(), (int)tex_data.size()); if (fltk_img.w() <= 0) { // failed to decode gLog.printf("Failed to decode PNG image in '%s' lump.\n", name.c_str()); return {}; } // convert it return IM_ConvertRGBImage(fltk_img); } tl::optional LoadImage_JPEG(const Lump_c &lump, const SString &name) { // load the raw data const std::vector &tex_data = lump.getData(); // pass it to FLTK for decoding Fl_JPEG_Image fltk_img(NULL, tex_data.data()); if (fltk_img.w() <= 0) { // failed to decode gLog.printf("Failed to decode JPEG image in '%s' lump.\n", name.c_str()); return {}; } // convert it return IM_ConvertRGBImage(fltk_img); } tl::optional LoadImage_TGA(const Lump_c &lump, const SString &name) { // load the raw data const std::vector &tex_data = lump.getData(); // decode it int width; int height; rgba_color_t * rgba = TGA_DecodeImage(tex_data.data(), tex_data.size(), width, height); if (! rgba) { // failed to decode gLog.printf("Failed to decode TGA image in '%s' lump.\n", name.c_str()); return {}; } // convert it Img_c img = IM_ConvertTGAImage(rgba, width, height); TGA_FreeImage(rgba); return img; } static bool ComposePicture(Img_c& dest, const tl::optional &sub, int pic_x_offset, int pic_y_offset, int *pic_width, int *pic_height) { if (!sub) return false; int width = sub->width(); int height = sub->height(); if (pic_width) *pic_width = width; if (pic_height) *pic_height = height; if (dest.is_null()) { // our new image will be completely transparent dest.resize (width, height); } dest.compose(*sub, pic_x_offset, pic_y_offset); return true; } // // LoadPicture - read a picture from a wad file into an Img_c object // // If img->is_null() is false, LoadPicture() does not allocate the // buffer itself. The buffer and the picture don't have to have the // same dimensions. Thanks to this, it can also be used to compose // textures : you allocate a single buffer for the whole texture // and then you call LoadPicture() on it once for each patch. // LoadPicture() takes care of all the necessary clipping. // // If img->is_null() is true, LoadPicture() sets the size of img // to match that of the picture. This is useful in display_pic(). // // Return true on success, false on failure. // bool LoadPicture(const Palette &pal, const ConfigData &config, Img_c& dest, // image to load picture into const Lump_c &lump, const SString &pic_name, // picture name (for messages) int pic_x_offset, // coordinates of top left corner of picture int pic_y_offset, // relative to top left corner of buffer int *pic_width, // To return the size of the picture int *pic_height) // (can be NULL) { ImageFormat img_fmt = W_DetectImageFormat(lump); tl::optional sub; bool result; int localPicWidth = 0, localPicHeight = 0; switch (img_fmt) { case ImageFormat::doom: // use the code below to load/compose the DOOM format break; case ImageFormat::png: sub = LoadImage_PNG(lump, pic_name); result = ComposePicture(dest, sub, pic_x_offset, pic_y_offset, &localPicWidth, &localPicHeight); if (pic_width) *pic_width = localPicWidth; if (pic_height) *pic_height = localPicHeight; dest.setSpriteOffset(localPicWidth / 2, localPicHeight); return result; case ImageFormat::jpeg: sub = LoadImage_JPEG(lump, pic_name); result = ComposePicture(dest, sub, pic_x_offset, pic_y_offset, &localPicWidth, &localPicHeight); if (pic_width) *pic_width = localPicWidth; if (pic_height) *pic_height = localPicHeight; dest.setSpriteOffset(localPicWidth / 2, localPicHeight); return result; case ImageFormat::tga: sub = LoadImage_TGA(lump, pic_name); result = ComposePicture(dest, sub, pic_x_offset, pic_y_offset, &localPicWidth, &localPicHeight); if (pic_width) *pic_width = localPicWidth; if (pic_height) *pic_height = localPicHeight; dest.setSpriteOffset(localPicWidth / 2, localPicHeight); return result; case ImageFormat::unrecognized: gLog.printf("Unknown image format in '%s' lump\n", pic_name.c_str()); return false; default: gLog.printf("Unsupported image format in '%s' lump\n", pic_name.c_str()); return false; } /* DOOM format */ const std::vector &raw_data = lump.getData(); auto pat = reinterpret_cast(raw_data.data()); int width = LE_S16(pat->width); int height = LE_S16(pat->height); int offset_x = LE_S16(pat->leftoffset); int offset_y = LE_S16(pat->topoffset); dest.setSpriteOffset(offset_x, offset_y); // FIXME: validate values (in case we got flat data or so) if (pic_width) *pic_width = width; if (pic_height) *pic_height = height; if (dest.is_null()) { // our new image will be completely transparent dest.resize (width, height); } for (int x = 0 ; x < width ; x++) { int offset = LE_S32(pat->columnofs[x]); if (offset < 0 || offset >= lump.Length()) { gLog.printf("WARNING: bad image offset 0x%08x in patch [%s]\n", offset, pic_name.c_str()); return false; } const post_t *column = (const post_t *) ((const byte *)pat + offset); DrawColumn(pal, config, dest, column, pic_x_offset + x, pic_y_offset); } return true; } ImageFormat W_DetectImageFormat(const Lump_c &lump) { int length = lump.Length(); if (length < 20) return ImageFormat::unrecognized; const byte *header = lump.getData().data(); // PNG is clearly marked in the header, so check it first. if (header[0] == 0x89 && header[1] == 'P' && header[2] == 'N' && header[3] == 'G' && header[4] == 0x0D && header[5] == 0x0A) { return ImageFormat::png; /* PNG */ } // check some other common image formats.... if (header[0] == 0xFF && header[1] == 0xD8 && header[2] == 0xFF && header[3] >= 0xE0 && ((header[6] == 'J' && header[7] == 'F') || (header[6] == 'E' && header[7] == 'x'))) { return ImageFormat::jpeg; /* JPEG */ } if (header[0] == 'G' && header[1] == 'I' && header[2] == 'F' && header[3] == '8' && header[4] >= '7' && header[4] <= '9' && header[5] == 'a') { return ImageFormat::gif; /* GIF */ } if (header[0] == 'D' && header[1] == 'D' && header[2] == 'S' && header[3] == 0x20 && header[4] == 124 && header[5] == 0 && header[6] == 0) { return ImageFormat::dds; /* DDS (DirectDraw Surface) */ } // TGA (Targa) is not clearly marked, but better than Doom patches, // so check it next. int width = (int)header[12] + (int)(header[13] << 8); int height = (int)header[14] + (int)(header[15] << 8); byte cmap_type = header[1]; byte img_type = header[2]; byte depth = header[16]; if (width > 0 && width <= 2048 && height > 0 && height <= 2048 && (cmap_type == 0 || cmap_type == 1) && ((img_type | 8) >= 8 && (img_type | 8) <= 11) && (depth == 8 || depth == 15 || depth == 16 || depth == 24 || depth == 32)) { return ImageFormat::tga; /* TGA */ } // check for raw patches last width = (int)header[0] + (int)(header[1] << 8); height = (int)header[2] + (int)(header[3] << 8); int ofs_x = (int)header[4] + (int)((signed char)header[5] * 256); int ofs_y = (int)header[6] + (int)((signed char)header[7] * 256); if (width > 0 && width <= 2048 && abs(ofs_x) <= 2048 && height > 0 && height <= 512 && abs(ofs_y) <= 512 && length > width * 4 /* columnofs */) { return ImageFormat::doom; /* Doom patch */ } return ImageFormat::unrecognized; // unknown! } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/w_loadpic.h000066400000000000000000000041431464327712600204440ustar00rootroot00000000000000//------------------------------------------------------------------------ // WAD PIC LOADER //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_W_LOADPIC_H__ #define __EUREKA_W_LOADPIC_H__ #include "im_img.h" #include "w_wad.h" #include "tl/optional.hpp" // Determine the image format of the given wad lump. // // Return values are: // 'p' : PNG format // 't' : TGA (Targa) format // 'd' : Doom patch // // 'j' : JPEG // 'g' : GIF // 's' : DDS // // NUL : unrecognized // enum class ImageFormat { unrecognized, png, tga, doom, jpeg, gif, dds, }; ImageFormat W_DetectImageFormat(const Lump_c &lump); tl::optional LoadImage_JPEG(const Lump_c &lump, const SString &name); tl::optional LoadImage_PNG(const Lump_c &lump, const SString &name); tl::optional LoadImage_TGA(const Lump_c &lump, const SString &name); bool LoadPicture(const Palette &pal, const ConfigData &config, Img_c &dest, const Lump_c &lump, const SString &pic_name, int pic_x_offset, int pic_y_offset, int *pic_width = nullptr, int *pic_height = nullptr); #endif /* __EUREKA_W_LOADPIC_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/w_rawdef.h000066400000000000000000000276131464327712600203100ustar00rootroot00000000000000//------------------------------------------------------------------------ // RAWDEF : Doom structures, raw on-disk layout //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2007-2016 Andrew Apted // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef __EUREKA_W_RAWDEF_H__ #define __EUREKA_W_RAWDEF_H__ /* ----- The wad structures ---------------------- */ #define WAD_TEX_NAME 8 #define WAD_FLAT_NAME 8 // wad header typedef struct raw_wad_header_s { char ident[4]; uint32_t num_entries; uint32_t dir_start; } PACKEDATTR raw_wad_header_t; // directory entry typedef struct raw_wad_entry_s { uint32_t pos; uint32_t size; char name[8]; } PACKEDATTR raw_wad_entry_t; // Lump order in a map WAD: each map needs a couple of lumps // to provide a complete scene geometry description. enum lump_order_e { LL_LABEL=0, // A separator name, ExMx or MAPxx LL_THINGS, // Monsters, items.. LL_LINEDEFS, // LineDefs, from editing LL_SIDEDEFS, // SideDefs, from editing LL_VERTEXES, // Vertices, edited and BSP splits generated LL_SEGS, // LineSegs, from LineDefs split by BSP LL_SSECTORS, // SubSectors, list of LineSegs LL_NODES, // BSP nodes LL_SECTORS, // Sectors, from editing LL_REJECT, // LUT, sector-sector visibility LL_BLOCKMAP, // LUT, motion clipping, walls/grid element LL_BEHAVIOR // Hexen scripting stuff }; /* ----- The level structures ---------------------- */ typedef struct raw_vertex_s { int16_t x, y; } PACKEDATTR raw_vertex_t; typedef struct raw_v2_vertex_s { int32_t x, y; } PACKEDATTR raw_v2_vertex_t; typedef struct raw_linedef_s { uint16_t start; // from this vertex... uint16_t end; // ... to this vertex uint16_t flags; // linedef flags (impassible, etc) uint16_t type; // special type (0 for none, 97 for teleporter, etc) int16_t tag; // this linedef activates the sector with same tag uint16_t right; // right sidedef uint16_t left; // left sidedef (only if this line adjoins 2 sectors) } PACKEDATTR raw_linedef_t; typedef struct raw_hexen_linedef_s { uint16_t start; // from this vertex... uint16_t end; // ... to this vertex uint16_t flags; // linedef flags (impassible, etc) uint8_t type; // special type uint8_t args[5]; // special arguments uint16_t right; // right sidedef uint16_t left; // left sidedef } PACKEDATTR raw_hexen_linedef_t; typedef struct raw_sidedef_s { int16_t x_offset; // X offset for texture int16_t y_offset; // Y offset for texture char upper_tex[8]; // texture name for the part above char lower_tex[8]; // texture name for the part below char mid_tex[8]; // texture name for the regular part uint16_t sector; // adjacent sector } PACKEDATTR raw_sidedef_t; typedef struct raw_sector_s { int16_t floorh; // floor height int16_t ceilh; // ceiling height char floor_tex[8]; // floor texture char ceil_tex[8]; // ceiling texture uint16_t light; // light level (0-255) uint16_t type; // special type (0 = normal, 9 = secret, ...) int16_t tag; // sector activated by a linedef with same tag } PACKEDATTR raw_sector_t; typedef struct raw_thing_s { int16_t x, y; // position of thing int16_t angle; // angle thing faces (degrees) uint16_t type; // type of thing uint16_t options; // when appears, deaf, etc.. } PACKEDATTR raw_thing_t; // -JL- Hexen thing definition typedef struct raw_hexen_thing_s { int16_t tid; // tag id (for scripts/specials) int16_t x, y; // position int16_t height; // start height above floor int16_t angle; // angle thing faces uint16_t type; // type of thing uint16_t options; // when appears, deaf, dormant, etc.. uint8_t special; // special type uint8_t args[5]; // special arguments } PACKEDATTR raw_hexen_thing_t; /* ----- The BSP tree structures ----------------------- */ typedef struct raw_seg_s { uint16_t start; // from this vertex... uint16_t end; // ... to this vertex uint16_t angle; // angle (0 = east, 16384 = north, ...) uint16_t linedef; // linedef that this seg goes along uint16_t flip; // true if not the same direction as linedef uint16_t dist; // distance from starting point } PACKEDATTR raw_seg_t; typedef struct raw_gl_seg_s { uint16_t start; // from this vertex... uint16_t end; // ... to this vertex uint16_t linedef; // linedef that this seg goes along, or -1 uint16_t side; // 0 if on right of linedef, 1 if on left uint16_t partner; // partner seg number, or -1 } PACKEDATTR raw_gl_seg_t; typedef struct raw_v5_seg_s { uint32_t start; // from this vertex... uint32_t end; // ... to this vertex uint16_t linedef; // linedef that this seg goes along, or -1 uint16_t side; // 0 if on right of linedef, 1 if on left uint32_t partner; // partner seg number, or -1 } PACKEDATTR raw_v5_seg_t; typedef struct raw_zdoom_seg_s { uint32_t start; // from this vertex... uint32_t end; // ... to this vertex uint16_t linedef; // linedef that this seg goes along, or -1 uint8_t side; // 0 if on right of linedef, 1 if on left } PACKEDATTR raw_zdoom_seg_t; typedef struct raw_bbox_s { int16_t maxy, miny; int16_t minx, maxx; } PACKEDATTR raw_bbox_t; typedef struct raw_node_s { int16_t x, y; // starting point int16_t dx, dy; // offset to ending point raw_bbox_t b1, b2; // bounding rectangles uint16_t right, left; // children: Node or SSector (if high bit is set) } PACKEDATTR raw_node_t; typedef struct raw_subsec_s { uint16_t num; // number of Segs in this Sub-Sector uint16_t first; // first Seg } PACKEDATTR raw_subsec_t; typedef struct raw_v5_subsec_s { uint32_t num; // number of Segs in this Sub-Sector uint32_t first; // first Seg } PACKEDATTR raw_v5_subsec_t; typedef struct raw_zdoom_subsec_s { uint32_t segnum; // NOTE : no "first" value, segs must be contiguous and appear // in an order dictated by the subsector list, e.g. all // segs of the second subsector must appear directly after // all segs of the first subsector. } PACKEDATTR raw_zdoom_subsec_t; typedef struct raw_v5_node_s { // this structure used by ZDoom nodes too int16_t x, y; // starting point int16_t dx, dy; // offset to ending point raw_bbox_t b1, b2; // bounding rectangles uint32_t right, left; // children: Node or SSector (if high bit is set) } PACKEDATTR raw_v5_node_t; typedef struct raw_blockmap_header_s { int16_t x_origin, y_origin; int16_t x_blocks, y_blocks; } PACKEDATTR raw_blockmap_header_t; /* ----- Graphical structures ---------------------- */ typedef struct { int16_t x_origin; int16_t y_origin; uint16_t pname; // index into PNAMES uint16_t stepdir; // NOT USED uint16_t colormap; // NOT USED } PACKEDATTR raw_patchdef_t; typedef struct { int16_t x_origin; int16_t y_origin; uint16_t pname; // index into PNAMES } PACKEDATTR raw_strife_patchdef_t; // Texture definition. // // Each texture is composed of one or more patches, // with patches being lumps stored in the WAD. // typedef struct { char name[8]; uint32_t masked; // NOT USED uint16_t width; uint16_t height; uint16_t column_dir[2]; // NOT USED uint16_t patch_count; raw_patchdef_t patches[1]; } PACKEDATTR raw_texture_t; typedef struct { char name[8]; uint32_t masked; // NOT USED uint16_t width; uint16_t height; uint16_t patch_count; raw_strife_patchdef_t patches[1]; } PACKEDATTR raw_strife_texture_t; // Patches. // // A patch holds one or more columns. // Patches are used for sprites and all masked pictures, // and we compose textures from the TEXTURE1/2 lists // of patches. // typedef struct patch_s { // bounding box size int16_t width; int16_t height; // pixels to the left of origin int16_t leftoffset; // pixels below the origin int16_t topoffset; uint32_t columnofs[1]; // only [width] used } PACKEDATTR patch_t; // // LineDef attributes. // enum lineflag_e { // solid, is an obstacle MLF_Blocking = 0x0001, // blocks monsters only MLF_BlockMonsters = 0x0002, // backside will not be present at all if not two sided MLF_TwoSided = 0x0004, // If a texture is pegged, the texture will have // the end exposed to air held constant at the // top or bottom of the texture (stairs or pulled // down things) and will move with a height change // of one of the neighbor sectors. // // Unpegged textures allways have the first row of // the texture at the top pixel of the line for both // top and bottom textures (use next to windows). // upper texture unpegged MLF_UpperUnpegged = 0x0008, // lower texture unpegged MLF_LowerUnpegged = 0x0010, // in AutoMap: don't map as two sided: IT'S A SECRET! MLF_Secret = 0x0020, // sound rendering: don't let sound cross two of these MLF_SoundBlock = 0x0040, // don't draw on the automap at all MLF_DontDraw = 0x0080, // set as if already seen, thus drawn in automap MLF_Mapped = 0x0100, // -AJA- this one is from Boom. Allows multiple lines to // be pushed simultaneously. MLF_Boom_PassThru = 0x0200, }; enum eternity_lineflag_e { MLF_Eternity_3DMidTex = 0x0400, }; enum xdoom_lineflag_e { // -AJA- these three are from XDoom MLF_XDoom_Translucent = 0x0400, MLF_XDoom_ShootBlock = 0x0800, MLF_XDoom_SightBlock = 0x1000, }; enum hexen_lineflag_e { // flags 0x001 .. 0x200 are same as DOOM above MLF_Repeatable = 0x0200, MLF_Activation = 0x1c00, }; enum strife_lineflag_e { MLF_Strife_JumpOver = 0x0200, MLF_Strife_BlockFloaters = 0x0400, MLF_Strife_Translucent1 = 0x0800, MLF_Strife_Translucent2 = 0x1000, }; enum zdoom_lineflag_e { // these are supported by ZDoom (and derived ports) MLF_ZDoom_MonCanActivate = 0x2000, MLF_ZDoom_BlockPlayers = 0x4000, MLF_ZDoom_BlockEverything = 0x8000, }; #define BOOM_GENLINE_FIRST 0x2f80 #define BOOM_GENLINE_LAST 0x7fff #define is_genline(tp) ((tp) >= BOOM_GENLINE_FIRST && (tp) <= BOOM_GENLINE_LAST) enum hexen_activation_e { SPAC_Cross = 0, // when line is crossed (W1 / WR) SPAC_Use = 1, // when line is used (S1 / SR) SPAC_Monster = 2, // when monster walks over line SPAC_Impact = 3, // when bullet/projectile hits line (G1 / GR) SPAC_Push = 4, // when line is bumped (player is stopped) SPAC_PCross = 5, // when projectile crosses the line }; // // Sector attributes. // enum boom_sectorflag_e { BoomSF_TypeMask = 0x001F, BoomSF_DamageMask = 0x0060, BoomSF_Secret = 0x0080, BoomSF_Friction = 0x0100, BoomSF_Wind = 0x0200, BoomSF_NoSounds = 0x0400, BoomSF_QuietPlane = 0x0800 }; #define MSF_BoomFlags 0x0FE0 // // Thing attributes. // enum thing_option_e { // these four used in Hexen too MTF_Easy = 1, MTF_Medium = 2, MTF_Hard = 4, MTF_Ambush = 8, MTF_Not_SP = 16, MTF_Not_DM = 32, MTF_Not_COOP = 64, MTF_Friend = 128, MTF_Reserved = 256, }; #define MTF_EXFLOOR_MASK 0x3C00 #define MTF_EXFLOOR_SHIFT 10 enum hexen_option_e { MTF_Hexen_Dormant = 16, MTF_Hexen_Fighter = 32, MTF_Hexen_Cleric = 64, MTF_Hexen_Mage = 128, MTF_Hexen_SP = 256, MTF_Hexen_COOP = 512, MTF_Hexen_DM = 1024, }; enum strife_option_e { MTF_Strife_Stand = 8, MTF_Strife_Ambush = 32, MTF_Strife_Friend = 64, MTF_Strife_Shadow = 256, MTF_Strife_AltVis = 512, }; #endif /* __EUREKA_W_RAWDEF_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/w_texture.cc000066400000000000000000000510611464327712600206700ustar00rootroot00000000000000//------------------------------------------------------------------------ // TEXTURES / FLATS / SPRITES //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2020 Andrew Apted // Copyright (C) 1997-2003 Andr Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphal Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "Errors.h" #include "Instance.h" #include "main.h" #include #include #include #include "m_game.h" /* yg_picture_format */ #include "w_loadpic.h" #include "w_rawdef.h" #include "w_texture.h" //---------------------------------------------------------------------- // TEXTURE HANDLING //---------------------------------------------------------------------- void ImageSet::W_ClearTextures() { textures.clear(); medusa_textures.clear(); } void ImageSet::W_AddTexture(const SString &name, Img_c &&img, bool is_medusa) { // free any existing one with the same name textures[name] = std::move(img); medusa_textures[name] = is_medusa ? 1 : 0; } static bool CheckTexturesAreStrife(const byte *tex_data, int tex_length, int num_tex, bool skip_first) { // we follow the ZDoom logic here: check ALL the texture entries // assuming DOOM format, and if any have a patch_count of zero or // the last two bytes of columndir are non-zero then assume Strife. const int32_t *tex_data_s32 = (const int32_t *)tex_data; for (int n = skip_first ? 1 : 0 ; n < num_tex ; n++) { int offset = LE_S32(tex_data_s32[1 + n]); // ignore invalid offsets here [ caught later ] if (offset < 4 * num_tex || offset >= tex_length) continue; const raw_texture_t *raw = (const raw_texture_t *)(tex_data + offset); if (LE_S16(raw->patch_count) <= 0) return true; if (raw->column_dir[1] != 0) return true; } return false; } static void LoadTextureEntry_Strife(WadData &wad, const ConfigData &config, const byte *tex_data, int tex_length, int offset, const byte *pnames, int pname_size, bool skip_first) { const raw_strife_texture_t *raw = (const raw_strife_texture_t *)(tex_data + offset); // create the new image int width = LE_U16(raw->width); int height = LE_U16(raw->height); gLog.debugPrintf("Texture [%.8s] : %dx%d\n", raw->name, width, height); if (width == 0 || height == 0) ThrowException("W_LoadTextures: Texture '%.8s' has zero size\n", raw->name); Img_c img(width, height, false); bool is_medusa = false; // apply all the patches int num_patches = LE_S16(raw->patch_count); if (! num_patches) ThrowException("W_LoadTextures: Texture '%.8s' has no patches\n", raw->name); const raw_strife_patchdef_t *patdef = (const raw_strife_patchdef_t *) & raw->patches[0]; if (num_patches >= 2) is_medusa = true; for (int j = 0 ; j < num_patches ; j++, patdef++) { int xofs = LE_S16(patdef->x_origin); int yofs = LE_S16(patdef->y_origin); int pname_idx = LE_U16(patdef->pname); if (yofs < 0) yofs = 0; if (pname_idx >= pname_size) { gLog.printf("Invalid pname in texture '%.8s'\n", raw->name); continue; } char picname[16]; memcpy(picname, pnames + 8*pname_idx, 8); picname[8] = 0; const Lump_c *lump = wad.master.findGlobalLump(picname); if (! lump || ! LoadPicture(wad.palette, config, img, *lump, picname, xofs, yofs)) { gLog.printf("texture '%.8s': patch '%.8s' not found.\n", raw->name, picname); } } // store the new texture char namebuf[16]; memcpy(namebuf, raw->name, 8); namebuf[8] = 0; wad.images.W_AddTexture(namebuf, std::move(img), is_medusa); } static void LoadTextureEntry_DOOM(WadData &wad, const ConfigData &config, const byte *tex_data, int tex_length, int offset, const byte *pnames, int pname_size, bool skip_first) { const raw_texture_t *raw = (const raw_texture_t *)(tex_data + offset); // create the new image int width = LE_U16(raw->width); int height = LE_U16(raw->height); gLog.debugPrintf("Texture [%.8s] : %dx%d\n", raw->name, width, height); if (width == 0 || height == 0) ThrowException("W_LoadTextures: Texture '%.8s' has zero size\n", raw->name); Img_c img(width, height, false); bool is_medusa = false; // apply all the patches int num_patches = LE_S16(raw->patch_count); if (! num_patches) ThrowException("W_LoadTextures: Texture '%.8s' has no patches\n", raw->name); const raw_patchdef_t *patdef = (const raw_patchdef_t *) & raw->patches[0]; // andrewj: this is not strictly correct, the Medusa Effect is only // triggered when multiple patches occupy a single column of // the texture. But checking for that is a major pain since // we don't know the width of each patch here.... if (num_patches >= 2) is_medusa = true; for (int j = 0 ; j < num_patches ; j++, patdef++) { int xofs = LE_S16(patdef->x_origin); int yofs = LE_S16(patdef->y_origin); int pname_idx = LE_U16(patdef->pname); if (pname_idx >= pname_size) { gLog.printf("Invalid pname in texture '%.8s'\n", raw->name); continue; } char picname[16]; memcpy(picname, pnames + 8*pname_idx, 8); picname[8] = 0; //gLog.debugPrintf("-- %d patch [%s]\n", j, picname); const Lump_c *lump = wad.master.findGlobalLump(picname); if (! lump || ! LoadPicture(wad.palette, config, img, *lump, picname, xofs, yofs)) { gLog.printf("texture '%.8s': patch '%.8s' not found.\n", raw->name, picname); } } // store the new texture char namebuf[16]; memcpy(namebuf, raw->name, 8); namebuf[8] = 0; wad.images.W_AddTexture(namebuf, std::move(img), is_medusa); } static void LoadTexturesLump(WadData &wad, const ConfigData &config, const Lump_c &lump, const byte *pnames, int pname_size, bool skip_first) { // TODO : verify size word at front of PNAMES ?? // skip size word at front of PNAMES pnames += 4; pname_size /= 8; // load TEXTUREx data into memory for easier processing const std::vector &tex_data = lump.getData(); // at the front of the TEXTUREx lump are some 4-byte integers int32_t *tex_data_s32 = (int32_t *)tex_data.data(); int num_tex = LE_S32(tex_data_s32[0]); // it seems having a count of zero is valid if (num_tex == 0) { return; } if (num_tex < 0 || num_tex > (1<<20)) ThrowException("W_LoadTextures: TEXTURE1/2 lump is corrupt, bad count.\n"); bool is_strife = CheckTexturesAreStrife(tex_data.data(), (int)tex_data.size(), num_tex, skip_first); // Note: we skip the first entry (e.g. AASHITTY) which is not really // usable (in the DOOM engine the #0 texture means "do not draw"). for (int n = skip_first ? 1 : 0 ; n < num_tex ; n++) { int offset = LE_S32(tex_data_s32[1 + n]); if (offset < 4 * num_tex || offset >= (int)tex_data.size()) ThrowException("W_LoadTextures: TEXTURE1/2 lump is corrupt, bad offset.\n"); if (is_strife) LoadTextureEntry_Strife(wad, config, tex_data.data(), (int)tex_data.size(), offset, pnames, pname_size, skip_first); else LoadTextureEntry_DOOM(wad, config, tex_data.data(), (int)tex_data.size(), offset, pnames, pname_size, skip_first); } } static void W_LoadTextures_TX_START(WadData &wad, const ConfigData &config, const Wad_file *wf) { for(const LumpRef &lumpRef : wf->getDir()) { if(lumpRef.ns != WadNamespace::TextureLumps) continue; const Lump_c *lump = lumpRef.lump.get(); ImageFormat img_fmt = W_DetectImageFormat(*lump); const SString &name = lump->Name(); tl::optional img; switch (img_fmt) { case ImageFormat::doom: /* Doom patch */ img = Img_c(); if (! LoadPicture(wad.palette, config, *img, *lump, name, 0, 0)) { img.reset(); } break; case ImageFormat::png: /* PNG */ img = LoadImage_PNG(*lump, name); break; case ImageFormat::tga: /* TGA */ img = LoadImage_TGA(*lump, name); break; case ImageFormat::jpeg: /* JPEG */ img = LoadImage_JPEG(*lump, name); break; case ImageFormat::unrecognized: gLog.printf("Unknown texture format in '%s' lump\n", name.c_str()); break; default: gLog.printf("Unsupported texture format in '%s' lump\n", lump->Name().c_str()); break; } // if we successfully loaded the texture, add it if (img) { wad.images.W_AddTexture(name, std::move(*img), false /* is_medusa */); } } } void WadData::W_LoadTextures(const ConfigData &config) { images.W_ClearTextures(); std::vector> wads = master.getAll(); for (int i = 0 ; i < (int)wads.size() ; i++) { gLog.printf("Loading Textures from WAD #%d\n", i+1); const Lump_c *pnames = wads[i]->FindLumpInNamespace("PNAMES", WadNamespace::Global); const Lump_c *texture1 = wads[i]->FindLumpInNamespace("TEXTURE1", WadNamespace::Global); const Lump_c *texture2 = wads[i]->FindLumpInNamespace("TEXTURE2", WadNamespace::Global); // Note that we _require_ the PNAMES lump to exist along // with the TEXTURE1/2 lump which uses it. Probably a // few wads exist which lack the PNAMES lump (relying on // the one in the IWAD), however this practice is too // error-prone (using the wrong IWAD will break it), // so I think supporting it is a bad idea. -- AJA if (pnames) { const std::vector &pname_data = pnames->getData(); if (texture1) LoadTexturesLump(*this, config, *texture1, pname_data.data(), (int)pname_data.size(), true); if (texture2) LoadTexturesLump(*this, config, *texture2, pname_data.data(), (int)pname_data.size(), false); } if (config.features.tx_start) { W_LoadTextures_TX_START(*this, config, wads[i].get()); } } } const Img_c * ImageSet::getTexture(const ConfigData &config, const SString &name, bool try_uppercase) const { if (is_null_tex(name)) return NULL; if (name.empty()) return NULL; SString t_str = name; std::map::const_iterator P = textures.find(t_str); if (P != textures.end()) return &P->second; if (try_uppercase) { return getTexture(config, NormalizeTex(name), false); } if (config.features.mix_textures_flats) { std::map::const_iterator P = flats.find(t_str); if (P != flats.end()) return &P->second; } return NULL; } int ImageSet::W_GetTextureHeight(const ConfigData &config, const SString &name) const { const Img_c *img = getTexture(config, name); if (! img) return 128; return img->height(); } // accepts "-", "#xxxx" or an existing texture name bool ImageSet::W_TextureIsKnown(const ConfigData &config, const SString &name) const { if (is_null_tex(name) || is_special_tex(name)) return true; if (name.empty()) return false; std::map::const_iterator P = textures.find(name); if (P != textures.end()) return true; if (config.features.mix_textures_flats) { std::map::const_iterator P = flats.find(name); if (P != flats.end()) return true; } return false; } bool ImageSet::W_TextureCausesMedusa(const SString &name) const { std::map::const_iterator P = medusa_textures.find(name); return (P != medusa_textures.end() && P->second > 0); } SString NormalizeTex(const SString &name) { if (name[0] == 0) return "-"; SString buffer; for (size_t i = 0 ; i < WAD_TEX_NAME && name[i]; i++) { buffer.push_back(name[i]); // remove double quotes if (buffer[i] == '"') buffer[i] = '_'; else buffer[i] = static_cast(toupper(buffer[i])); } return buffer; } //---------------------------------------------------------------------- // FLAT HANDLING //---------------------------------------------------------------------- void ImageSet::W_ClearFlats() { flats.clear(); } void ImageSet::W_AddFlat(const SString &name, Img_c &&img) { // find any existing one with same name, and free it flats[name] = std::move(img); } static Img_c LoadFlatImage(const WadData &wad, const SString &name, const Lump_c *lump) { // TODO: check size == 64*64 Img_c img(64, 64, false); int size = 64 * 64; byte *raw = new byte[size]; LumpInputStream stream(*lump); if (! stream.read(raw, size)) { gLog.printf("%s: flat '%s' is too small, should be at least %d.\n", __func__, name.c_str(), size); int smallsize = lump->Length(); if(smallsize > 0) memset(raw + smallsize, raw[smallsize - 1], size - smallsize); else memset(raw, 0, size); } for (int i = 0 ; i < size ; i++) { img_pixel_t pix = raw[i]; if (pix == TRANS_PIXEL) pix = static_cast(wad.palette.getTransReplace()); img.wbuf() [i] = pix; } delete[] raw; return img; } void WadData::W_LoadFlats() { images.W_ClearFlats(); std::vector> wads = master.getAll(); for (int i = 0 ; i < (int)wads.size() ; i++) { gLog.printf("Loading Flats from WAD #%d\n", i+1); const Wad_file *wf = wads[i].get(); for(const LumpRef &lumpRef : wf->getDir()) { if(lumpRef.ns != WadNamespace::Flats) continue; const Lump_c *lump = lumpRef.lump.get(); images.W_AddFlat(lump->Name(), LoadFlatImage(*this, lump->Name(), lump)); } } } const Img_c * ImageSet::W_GetFlat(const ConfigData &config, const SString &name, bool try_uppercase) const noexcept { std::map::const_iterator P = flats.find(name); if (P != flats.end()) return &P->second; if (config.features.mix_textures_flats) { std::map::const_iterator P = textures.find(name); if (P != textures.end()) return &P->second; } if (try_uppercase) { return W_GetFlat(config, NormalizeTex(name), false); } return NULL; } bool ImageSet::W_FlatIsKnown(const ConfigData &config, const SString &name) const { // sectors do not support "-" (but our code can make it) if (is_null_tex(name)) return false; if (name.empty()) return false; std::map::const_iterator P = flats.find(name); if (P != flats.end()) return true; if (config.features.mix_textures_flats) { std::map::const_iterator P = textures.find(name); if (P != textures.end()) return true; } return false; } //---------------------------------------------------------------------- // SPRITE HANDLING //---------------------------------------------------------------------- void ImageSet::W_ClearSprites() { sprites.clear(); } // find sprite by prefix static std::vector Sprite_loc_by_root (const MasterDir &master, const ConfigData &config, const SString &name) { // first look for one in the sprite namespace (S_START..S_END), // only if that fails do we check the whole wad. SString buffer; buffer.reserve(16); buffer = name; std::vector spriteset = master.findFirstSpriteLump(buffer); if (!spriteset.empty()) return spriteset; // check outside of the sprite namespace... const Lump_c *lump = nullptr; if (config.features.lax_sprites) { buffer = name; if(buffer.length() == 4) buffer += 'A'; if(buffer.length() == 5) buffer += '0'; lump = master.findGlobalLump(buffer); if (! lump) { if(buffer.length() >= 6) buffer[5] = '1'; lump = master.findGlobalLump(buffer); } // TODO: verify lump is OK (size etc) if (lump) { gLog.printf("WARNING: using sprite '%s' outside of S_START..S_END\n", name.c_str()); } } if (!lump) { // Still no lump? Try direct lookup // TODO: verify lump is OK (size etc) lump = master.findGlobalLump(name); } return lump ? std::vector{{lump, false}} : std::vector{}; } const Img_c *WadData::getSprite(const ConfigData &config, int type, const LoadingData &loading, int rotation) { assert(rotation >= 1 && rotation <= 8); const std::vector *existing = get(images.sprites, type); if(existing) { assert(existing->size() <= 1 || existing->size() == 8); return existing->empty() ? nullptr : existing->size() == 1 ? &(*existing)[0] : &(*existing)[rotation - 1]; } // sprite not in the list yet. Add it. const thingtype_t &info = config.getThingType(type); std::vector result; if (info.desc.startsWith("UNKNOWN")) { // leave as NULL } else if (info.sprite.noCaseEqual("_LYT")) { result = {Img_c::createLightSprite(palette)}; } else if (info.sprite.noCaseEqual("_MSP")) { result = {Img_c::createMapSpotSprite(palette, 0, 255, 0)}; } else if (info.sprite.noCaseEqual("NULL")) { result = {Img_c::createMapSpotSprite(palette, 70, 70, 255)}; } else { std::vector spriteset = Sprite_loc_by_root(master, config, info.sprite); if (spriteset.empty()) { // for the MBF dog, create our own sprite for it, since // it is defined in the Boom definition file and the // missing sprite looks ugly in the thing browser. if (info.sprite.noCaseEqual("DOGS")) result = {Img_c::createDogSprite(palette)}; else gLog.printf("Sprite not found: '%s'\n", info.sprite.c_str()); } else { if(spriteset.size() == 1) { result.resize(1); result[0] = Img_c(); assert(spriteset[0].lump); if (! LoadPicture(palette, config, result[0], *spriteset[0].lump, info.sprite, 0, 0)) { result.clear(); } else if(spriteset[0].flipped) result[0].flipHorizontally(); } else if(spriteset.size() == 8) { result.resize(8); int firstRot = -1; for(int i = 0; i < 8; ++i) { if(!spriteset[i].lump) continue; if (! LoadPicture(palette, config, result[i], *spriteset[i].lump, info.sprite, 0, 0)) { gLog.printf("Failed loading %s rotation %d\n", info.sprite.c_str(), i + 1); } else { firstRot = i; if(spriteset[i].flipped) { result[i].flipHorizontally(); } } } // Now sweep them for missing images if(firstRot == -1) // nothing found result.clear(); else for(Img_c &img : result) if(!img.width()) img = result[firstRot]; } } } // player color remapping // [ FIXME : put colors into game definition file ] if (!result.empty()) { if(info.flags & THINGDEF_INVIS) { for(Img_c &img : result) img = img.spectrify(config); } else if(info.group == 'p') { tl::optional new_img; int src1, src2; int targ1[4], targ2[4]; if (M_GetBaseGame(loading.gameName) == "heretic") { src1 = 225; src2 = 240; targ1[0] = 114; targ2[0] = 129; targ1[1] = 145; targ2[1] = 160; targ1[2] = targ1[3] = 190; targ2[2] = targ2[3] = 205; } else { src1 = 0x70; src2 = 0x7f; targ1[0] = 0x60; targ2[0] = 0x6f; targ1[1] = 0x40; targ2[1] = 0x4f; targ1[2] = 0x20; targ2[2] = 0x2f; targ1[3] = 0xc4; targ2[3] = 0xcf; } for(Img_c &img : result) { switch (type) { case 1: // no change break; case 2: new_img = img.color_remap(src1, src2, targ1[0], targ2[0]); break; case 3: new_img = img.color_remap(src1, src2, targ1[1], targ2[1]); break; case 4: new_img = img.color_remap(src1, src2, targ1[2], targ2[2]); break; // blue for the extra coop starts case 4001: case 4002: case 4003: case 4004: new_img = img.color_remap(src1, src2, targ1[3], targ2[3]); break; } if (new_img) { img = std::move(*new_img); } } } } // note that a NULL image is OK. Our renderer will just ignore the // missing sprite. images.sprites[type] = result; std::vector &sprites = images.sprites[type]; return sprites.empty() ? nullptr : sprites.size() == 8 ? &sprites[rotation - 1] : &sprites[0]; } //---------------------------------------------------------------------- static void UnloadTex(std::map::value_type& P) { P.second.unload_gl(false); } static void UnloadFlat(std::map::value_type& P) { P.second.unload_gl(false); } static void UnloadSprite(sprite_map_t::value_type& P) { for(Img_c &img : P.second) img.unload_gl(false); } void ImageSet::W_UnloadAllTextures() { std::for_each(textures.begin(), textures.end(), UnloadTex); std::for_each(flats.begin(), flats.end(), UnloadFlat); std::for_each(sprites.begin(), sprites.end(), UnloadSprite); IM_UnloadDummyTextures(); } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/w_texture.h000066400000000000000000000027041464327712600205320ustar00rootroot00000000000000//------------------------------------------------------------------------ // TEXTURES / FLATS / SPRITES //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_W_TEXTURE_H__ #define __EUREKA_W_TEXTURE_H__ #include "im_img.h" // this truncates the name to 8 chars, and makes it uppercase. // [ result is a static buffer, copy if necessary! ] SString NormalizeTex(const SString &name); /* ---- SPRITES ---- */ #endif /* __EUREKA_W_TEXTURE_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/w_wad.cc000066400000000000000000000677441464327712600177620ustar00rootroot00000000000000//------------------------------------------------------------------------ // WAD Reading / Writing //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2019 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #include "main.h" #include "Instance.h" #include #include "Errors.h" #include "lib_adler.h" #include "m_files.h" #include "SafeOutFile.h" #include "w_rawdef.h" #include "w_wad.h" #include // UDMF support is unfinished and hence disabled by default. bool global::udmf_testing = false; #define MAX_LUMPS_IN_A_LEVEL 21 // // Wad namespace string // static const char *WadNamespaceString(WadNamespace ns) noexcept { switch(ns) { case WadNamespace::Flats: return "F"; case WadNamespace::Global: return "(global)"; case WadNamespace::Sprites: return "S"; case WadNamespace::TextureLumps: return "TX"; default: return "(invalid)"; } } //------------------------------------------------------------------------ // LUMP Handling //------------------------------------------------------------------------ Lump_c::Lump_c(const SString &_nam) { // ensure lump name is uppercase name = _nam.asUpper(); if(name.length() > 8) name.erase(8, std::string::npos); } void Lump_c::Rename(const char *new_name) { name = SString(new_name).asUpper(); if(name.length() > 8) name.erase(8, std::string::npos); } bool LumpInputStream::read(void *data, int len) noexcept { bool result = true; if(pos + len > lump.Length()) { result = false; len = lump.Length() - pos; } memcpy(data, lump.getData().data() + pos, len); pos += len; return result; } bool LumpInputStream::readLine(SString &string) noexcept { if(pos >= lump.Length()) return false; // EOF string.clear(); for(; pos < lump.Length(); ++pos) { string.push_back(static_cast(lump.getData()[pos])); if(string.back() == '\n') { ++pos; break; } } return true; // OK } void Lump_c::Write(const void *vdata, int len) { auto data = static_cast(vdata); mData.insert(mData.begin() + mPos, data, data + len); mPos += len; } void Lump_c::Printf(EUR_FORMAT_STRING(const char *msg), ...) { va_list args; va_start(args, msg); SString buffer = SString::vprintf(msg, args); va_end(args); Write(buffer.c_str(), (int)buffer.length()); } // // Writes the data by freading from FILE. Returns the result of the involved // fread call, as number of bytes read. Be sure to check feof and ferror if not // as expected. // size_t Lump_c::writeData(FILE *f, int len) { mData.insert(mData.begin() + mPos, len, 0); size_t actualRead = fread(mData.data() + mPos, 1, len, f); if((int)actualRead < len) { mData.erase(mData.begin() + mPos + actualRead, mData.begin() + mPos + len); } mPos += (int)actualRead; return actualRead; } // // Returns the name coded into 8 bytes // int64_t Lump_c::getName8() const noexcept { union { char cbuf[8]; int64_t cint; } buffer; memcpy(buffer.cbuf, Name().c_str(), std::min(Name().length() + 1, sizeof(buffer))); return buffer.cint; } //------------------------------------------------------------------------ // WAD Reading Interface //------------------------------------------------------------------------ Wad_file::~Wad_file() { gLog.printf("Closing WAD file: %s\n", filename.u8string().c_str()); } std::shared_ptr Wad_file::Open(const fs::path &filename, WadOpenMode mode) { SYS_ASSERT(mode == WadOpenMode::read || mode == WadOpenMode::write || mode == WadOpenMode::append); if (mode == WadOpenMode::write) return Create(filename, mode); gLog.printf("Opening WAD file: %s\n", filename.u8string().c_str()); FILE *fp = NULL; retry: // TODO: #55 unicode fp = fopen(filename.u8string().c_str(), (mode == WadOpenMode::read ? "rb" : "r+b")); if (! fp) { // mimic the fopen() semantics if (mode == WadOpenMode::append && errno == ENOENT) return Create(filename, mode); // if file is read-only, open in 'r' mode instead if (mode == WadOpenMode::append && (errno == EACCES || errno == EROFS)) { gLog.printf("Open r/w failed, trying again in read mode...\n"); mode = WadOpenMode::read; goto retry; } int what = errno; gLog.printf("Open failed: %s\n", GetErrorMessage(what).c_str()); return NULL; } return createAndReadDirectory(filename, mode, fp); } std::shared_ptr Wad_file::loadFromFile(const fs::path &filename) { gLog.printf("Opening WAD file: %s\n", filename.u8string().c_str()); // TODO: #55 unicode FILE *fp = fopen(filename.u8string().c_str(), "rb"); if(!fp) { gLog.printf("Open failed: %s\n", GetErrorMessage(errno).c_str()); return nullptr; } return createAndReadDirectory(filename, WadOpenMode::append, fp); } std::shared_ptr Wad_file::readFromDir(const fs::path &path) { gLog.printf("Opening WAD folder: %s\n", path.u8string().c_str()); // Reading from folder follows this rule (which should be a cross-port standard): // https://eternity.youfailit.net/wiki/ZIP // Currently no editing is allowed in folder paths, which are only for resources anyway auto wraw = new Wad_file(path, WadOpenMode::read); auto w = std::shared_ptr(wraw); fs::directory_iterator iterator; try { iterator = fs::directory_iterator(path); } catch(const fs::filesystem_error &e) { gLog.printf("Open failed: %s\n", e.what()); return nullptr; } auto tryAddNewLump = [](std::shared_ptr &w, const fs::path &path, WadNamespace nameSpace) { SString lumpname = SString(path.filename().replace_extension().u8string()).asUpper().substr(0, 8); for(char &c : lumpname) if(c == '^') c = '\\'; // de-escape backslashes, due to vile precedent Lump_c *lump = new Lump_c(lumpname); std::vector data; if(!FileLoad(path, data)) { gLog.printf("Failed reading %s\n", path.u8string().c_str()); delete lump; return; } lump->setData(std::move(data)); LumpRef ref = {}; ref.lump.reset(lump); ref.ns = nameSpace; w->directory.push_back(std::move(ref)); }; for(const auto &entry : iterator) { if(fs::is_regular_file(entry.path())) { // Promptly add the lump now tryAddNewLump(w, entry.path(), WadNamespace::Global); } else if(fs::is_directory(entry.path())) { fs::directory_iterator subiterator; try { subiterator = fs::directory_iterator(entry.path()); } catch(const fs::filesystem_error &e) { gLog.printf("Error opening subfolder %s: %s\n", entry.path().u8string().c_str(), e.what()); } for(const auto &subentry : subiterator) { if(!fs::is_regular_file(subentry.path())) continue; // only allow one sub level // Check namespaces by the way SString folderName = entry.path().filename().u8string(); WadNamespace nameSpace; if(folderName.noCaseEqual("flats")) nameSpace = WadNamespace::Flats; else if(folderName.noCaseEqual("sprites")) nameSpace = WadNamespace::Sprites; else if(folderName.noCaseEqual("textures")) nameSpace = WadNamespace::TextureLumps; else nameSpace = WadNamespace::Global; tryAddNewLump(w, subentry.path(), nameSpace); } } else { gLog.printf("Ignoring irregular file path %s\n", entry.path().u8string().c_str()); } } // No DetectLevels allowed either. return w; } std::shared_ptr Wad_file::Create(const fs::path &filename, WadOpenMode mode) { gLog.printf("Creating new WAD file: %s\n", filename.u8string().c_str()); return std::shared_ptr(new Wad_file(filename, mode)); } std::shared_ptr Wad_file::createAndReadDirectory(const fs::path &filename, WadOpenMode mode, FILE *fp) { auto wraw = new Wad_file(filename, mode); auto w = std::shared_ptr(wraw); // determine total size (seek to end) if (fseek(fp, 0, SEEK_END) != 0) { fclose(fp); ThrowException("Error determining WAD size.\n"); } int total_size = (int)ftell(fp); gLog.debugPrintf("total_size = %d\n", total_size); if (total_size < 0) { fclose(fp); ThrowException("Error determining WAD size.\n"); } if (! w->ReadDirectory(fp, total_size)) { gLog.printf("Open wad failed (reading directory)\n"); fclose(fp); return NULL; } w->DetectLevels(); w->ProcessNamespaces(); fclose(fp); return w; } bool Wad_file::Validate(const fs::path &filename) { std::ifstream stream(filename, std::ios::binary); if (! stream.is_open()) return false; raw_wad_header_t header; if(!stream.read(reinterpret_cast(&header), sizeof(header)) || stream.gcount() != sizeof(header)) { return false; } stream.close(); if (! ( header.ident[1] == 'W' && header.ident[2] == 'A' && header.ident[3] == 'D')) { return false; } return true; // OK } static int WhatLevelPart(const SString &name) noexcept { if (name.noCaseEqual("THINGS")) return 1; if (name.noCaseEqual("LINEDEFS")) return 2; if (name.noCaseEqual("SIDEDEFS")) return 3; if (name.noCaseEqual("VERTEXES")) return 4; if (name.noCaseEqual("SECTORS")) return 5; return 0; } static bool IsLevelLump(const SString &name) noexcept { if (name.noCaseEqual("SEGS")) return true; if (name.noCaseEqual("SSECTORS")) return true; if (name.noCaseEqual("NODES")) return true; if (name.noCaseEqual("REJECT")) return true; if (name.noCaseEqual("BLOCKMAP")) return true; if (name.noCaseEqual("BEHAVIOR")) return true; if (name.noCaseEqual("SCRIPTS")) return true; return WhatLevelPart(name) != 0; } inline static bool IsGLNodeLump(const SString &name) noexcept { return name.noCaseStartsWith("GL_"); } // // Wad total size // int Wad_file::TotalSize() const noexcept { int size = 12; for(const LumpRef &ref : directory) { assert(ref.lump.get() != nullptr); size += ref.lump->Length(); } size += (int)directory.size() * 16; return size; } Lump_c * Wad_file::GetLump(int index) const noexcept { SYS_ASSERT(0 <= index && index < NumLumps()); SYS_ASSERT(directory[index].lump); return directory[index].lump.get(); } Lump_c * Wad_file::FindLump(const SString &name) const noexcept { for (auto it = directory.rbegin(); it != directory.rend(); ++it) if (it->lump->name.noCaseEqual(name)) return it->lump.get(); return nullptr; // not found } int Wad_file::FindLumpNum(const SString &name) const noexcept { for (int k = NumLumps() - 1 ; k >= 0 ; k--) if (directory[k].lump->name.noCaseEqual(name)) return k; return -1; // not found } int Wad_file::LevelLookupLump(int lev_num, const char *name) const noexcept { int start = LevelHeader(lev_num); // determine how far past the level marker (MAP01 etc) to search int finish = LevelLastLump(lev_num); for (int k = start+1 ; k <= finish ; k++) { SYS_ASSERT(0 <= k && k < NumLumps()); if (directory[k].lump->name.noCaseEqual(name)) return k; } return -1; // not found } int Wad_file::LevelFind(const SString &name) const noexcept { for (int k = 0 ; k < (int)levels.size() ; k++) { int index = levels[k]; SYS_ASSERT(0 <= index && index < NumLumps()); SYS_ASSERT(directory[index].lump); if (directory[index].lump->name.noCaseEqual(name)) return k; } return -1; // not found } int Wad_file::LevelLastLump(int lev_num) const noexcept { int start = LevelHeader(lev_num); int count = 1; // UDMF level? if (directory[start + 1].lump->name.noCaseEqual("TEXTMAP")) { while (count < MAX_LUMPS_IN_A_LEVEL && start+count < NumLumps()) { if (directory[start+count].lump->name.noCaseEqual("ENDMAP")) { count++; break; } count++; } return start + count - 1; } // standard DOOM or HEXEN format while (count < MAX_LUMPS_IN_A_LEVEL && start+count < NumLumps() && (IsLevelLump(directory[start+count].lump->name) || IsGLNodeLump(directory[start+count].lump->name)) ) { count++; } return start + count - 1; } int Wad_file::LevelFindByNumber(int number) const noexcept { // sanity check if (number <= 0 || number > 99) return -1; char buffer[16]; int index; // try MAP## first snprintf(buffer, sizeof(buffer), "MAP%02d", number); index = LevelFind(buffer); if (index >= 0) return index; // otherwise try E#M# snprintf(buffer, sizeof(buffer), "E%dM%d", std::max(1, number / 10), number % 10); index = LevelFind(buffer); if (index >= 0) return index; return -1; // not found } int Wad_file::LevelFindFirst() const noexcept { if (levels.size() > 0) return 0; else return -1; // none } int Wad_file::LevelHeader(int lev_num) const noexcept { SYS_ASSERT(0 <= lev_num && lev_num < LevelCount()); return levels[lev_num]; } MapFormat Wad_file::LevelFormat(int lev_num) const noexcept { int start = LevelHeader(lev_num); if (directory[start+1].lump->name.noCaseEqual("TEXTMAP")) return MapFormat::udmf; if (start + LL_BEHAVIOR < NumLumps()) { const SString &name = GetLump(start + LL_BEHAVIOR)->Name(); if (name.noCaseEqual("BEHAVIOR")) return MapFormat::hexen; } return MapFormat::doom; } const Lump_c * Wad_file::FindLumpInNamespace(const SString &name, WadNamespace group) const noexcept { for(const LumpRef &lumpRef : directory) { if(lumpRef.ns != group || !lumpRef.lump->name.noCaseEqual(name)) continue; return lumpRef.lump.get(); } return nullptr; // not found! } // // Searches for the // std::vector Wad_file::findFirstSpriteLump(const SString &stem) const { auto isSprite = [](const LumpRef &ref) { if(ref.ns != WadNamespace::Sprites) return false; const SString &name = ref.lump->name; if(name.length() != 6 && name.length() != 8) return false; if(name[5] < '0' || name[5] > '8') return false; if(name.length() == 8 && (name[7] < '0' || name[7] > '8')) return false; return true; }; std::vector result; SString substem = stem.length() > 4 ? stem.substr(0, 4) : stem; std::vector candidates; SString foundName; const Lump_c *foundLump = nullptr; // 1. Find the first ordered stem // 2. Find the first ordered frame for(const LumpRef &ref : directory) { if(!isSprite(ref)) continue; const SString &name = ref.lump->name; if(name.startsWith(substem.c_str())) { candidates.push_back(ref.lump.get()); } if(!name.startsWith(stem.c_str())) continue; if(foundName.empty() || foundName.get() > name.get()) { foundName = name; foundLump = ref.lump.get(); } } if(foundName.empty()) return {}; char letter = 0; char rot = 0; // 3. Find all the other rotations with that frame letter = foundName[4]; rot = foundName[5]; if(rot == '0') return {{foundLump, false}}; // got one see-all-around sprite already // we got some rotation result.resize(8); // Now look for all rotations for(const Lump_c *lump : candidates) { const SString &name = lump->Name(); if(stem.length() < 4 && name.substr(0, 4) != foundName.substr(0, 4)) continue; if(name[4] == letter) result[name[5] - '1'] = {lump, false}; if(name.length() == 8 && name[6] == letter) { if(name[7] == '0') return {{lump, true}}; result[name[7] - '1'] = {lump, true}; } } return result; } bool Wad_file::ReadDirectory(FILE *fp, int total_size) { rewind(fp); raw_wad_header_t header; if (fread(&header, sizeof(header), 1, fp) != 1) { gLog.printf("Error reading WAD header.\n"); return false; } kind = header.ident[0] == 'I' ? WadKind::IWAD : WadKind::PWAD; int dir_start = LE_S32(header.dir_start); int dir_count = LE_S32(header.num_entries); if (dir_count < 0) { gLog.printf("Bad WAD header, invalid number of entries (%d)\n", dir_count); return false; } if (fseek(fp, dir_start, SEEK_SET) != 0) { gLog.printf("Error seeking to WAD directory.\n"); return false; } directory.reserve(dir_count); for (int _ = 0 ; _ < dir_count ; _++) { raw_wad_entry_t entry; if (fread(&entry, sizeof(entry), 1, fp) != 1) { gLog.printf("Error reading entry in WAD directory.\n"); return false; } Lump_c *lump = new Lump_c(SString(entry.name, 8)); int l_length = LE_U32(entry.size); int l_start = LE_U32(entry.pos); if(l_length == 0) l_start = 0; // check if entry is valid // [ the total_size value was computed in parent function ] if (l_length != 0) { const int max_size = 99999999; if (l_length < 0 || l_start < 0 || l_length >= max_size || l_start > total_size || l_start + l_length > total_size) { gLog.printf("WARNING: clearing lump '%s' with invalid position (%d+%d > %d)\n", lump->name.c_str(), l_start, l_length, total_size); l_start = 0; l_length = 0; } if(l_length > 0) { long curpos = ftell(fp); if(curpos < 0) { gLog.printf("%s: ftell failed with error %d\n", __func__, errno); return false; } if(fseek(fp, l_start, SEEK_SET) < 0) { gLog.printf("%s: fseek failed with error %d\n", __func__, errno); return false; } if((int)lump->writeData(fp, l_length) < l_length) { gLog.printf("%s: failed reading %d bytes for lump '%s'\n", __func__, l_length, lump->name.c_str()); return false; } if(fseek(fp, curpos, SEEK_SET) < 0) { gLog.printf("%s: fseek back failed with error %d\n", __func__, errno); return false; } } } LumpRef lumpRef = {}; // Currently not set, will set in ResolveNamespace lumpRef.lump.reset(lump); directory.push_back(std::move(lumpRef)); } return true; } void Wad_file::DetectLevels() { // Determine what lumps in the wad are level markers, based on // the lumps which follow it. Store the result in the 'levels' // vector. The test here is rather lax, as I'm told certain // wads exist with a non-standard ordering of level lumps. for (int k = 0 ; k+1 < NumLumps() ; k++) { int part_mask = 0; int part_count = 0; // check for UDMF levels if (global::udmf_testing && directory[k+1].lump->name.noCaseEqual("TEXTMAP")) { levels.push_back(k); gLog.debugPrintf("Detected level : %s (UDMF)\n", directory[k].lump->name.c_str()); continue; } // check whether the next four lumps are level lumps for (int i = 1 ; i <= 4 ; i++) { if (k + i >= NumLumps()) break; int part = WhatLevelPart(directory[k+i].lump->name); if (part == 0) break; // do not allow duplicates if (part_mask & (1 << part)) break; part_mask |= (1 << part); part_count++; } if (part_count == 4) { levels.push_back(k); gLog.debugPrintf("Detected level : %s\n", directory[k].lump->name.c_str()); } } // sort levels into alphabetical order // (mainly for the 'N' next map and 'P' prev map commands) SortLevels(); } void Wad_file::SortLevels() noexcept { std::sort(levels.begin(), levels.end(), level_name_CMP_pred(this)); } static bool IsDummyMarker(const SString &name) noexcept { // matches P1_START, F3_END etc... if (name.length() < 3) return false; if (! strchr("SF", toupper(name[0]))) return false; if (! isdigit(name[1])) return false; if (y_stricmp(name.c_str()+2, "_START") == 0 || y_stricmp(name.c_str()+2, "_END") == 0) return true; return false; } void Wad_file::ProcessNamespaces() { WadNamespace active = WadNamespace::Global; for (LumpRef &lumpRef : directory) { const SString &name = lumpRef.lump->name; lumpRef.ns = WadNamespace::Global; // default it to global // skip the sub-namespace markers if (IsDummyMarker(name)) continue; if (name.noCaseEqual("S_START") || name.noCaseEqual("SS_START")) { if (active != WadNamespace::Global && active != WadNamespace::Sprites) gLog.printf("WARNING: missing %s_END marker.\n", WadNamespaceString(active)); active = WadNamespace::Sprites; continue; } if (name.noCaseEqual("S_END") || name.noCaseEqual("SS_END")) { if (active != WadNamespace::Sprites) gLog.printf("WARNING: stray S_END marker found.\n"); active = WadNamespace::Global; continue; } if (name.noCaseEqual("F_START") || name.noCaseEqual("FF_START")) { if (active != WadNamespace::Global && active != WadNamespace::Flats) gLog.printf("WARNING: missing %s_END marker.\n", WadNamespaceString(active)); active = WadNamespace::Flats; continue; } if (name.noCaseEqual("F_END") || name.noCaseEqual("FF_END")) { if (active != WadNamespace::Flats) gLog.printf("WARNING: stray F_END marker found.\n"); active = WadNamespace::Global; continue; } if (name.noCaseEqual("TX_START")) { if (active != WadNamespace::Global && active != WadNamespace::TextureLumps) gLog.printf("WARNING: missing %s_END marker.\n", WadNamespaceString(active)); active = WadNamespace::TextureLumps; continue; } if (name.noCaseEqual("TX_END")) { if (active != WadNamespace::TextureLumps) gLog.printf("WARNING: stray TX_END marker found.\n"); active = WadNamespace::Global; continue; } if (active != WadNamespace::Global) { if (lumpRef.lump->Length() == 0) { gLog.printf("WARNING: skipping empty lump %s in %s_START\n", name.c_str(), WadNamespaceString(active)); continue; } lumpRef.ns = active; } } if (active != WadNamespace::Global) gLog.printf("WARNING: Missing %s_END marker (at EOF)\n", WadNamespaceString(active)); } //------------------------------------------------------------------------ // WAD Writing Interface //------------------------------------------------------------------------ // // Writes the content to disk now // void Wad_file::writeToDisk() noexcept(false) { if(IsReadOnly()) { ThrowException("Cannot overwrite a read-only file (%s)!", filename.u8string().c_str()); } // Write to our path now writeToPath(filename); // reset the insertion point insert_point = -1; } void Wad_file::RenameLump(int index, const char *new_name) { SYS_ASSERT(0 <= index && index < NumLumps()); Lump_c *lump = directory[index].lump.get(); SYS_ASSERT(lump); lump->Rename(new_name); } void Wad_file::RemoveLumps(int index, int count) { SYS_ASSERT(0 <= index && index < NumLumps()); SYS_ASSERT(directory[index].lump); directory.erase(directory.begin() + index, directory.begin() + index + count); FixLevelGroup(index, 0, count); // reset the insertion point insert_point = -1; ProcessNamespaces(); } std::vector Wad_file::RemoveLevel(int lev_num) { SYS_ASSERT(0 <= lev_num && lev_num < LevelCount()); int start = LevelHeader(lev_num); int finish = LevelLastLump(lev_num); // NOTE: FixGroup() will remove the entry in levels[] std::vector result; for (int i = start; i <= finish; ++i) result.push_back(std::move(*directory[i].lump)); RemoveLumps(start, finish - start + 1); return result; } void Wad_file::RemoveGLNodes(int lev_num) { SYS_ASSERT(0 <= lev_num && lev_num < LevelCount()); int start = LevelHeader(lev_num); int finish = LevelLastLump(lev_num); start++; while (start <= finish && IsLevelLump(directory[start].lump->name)) { start++; } int count = 0; while (start+count <= finish && IsGLNodeLump(directory[start+count].lump->name)) { count++; } if (count > 0) RemoveLumps(start, count); } void Wad_file::RemoveZNodes(int lev_num) { SYS_ASSERT(0 <= lev_num && lev_num < LevelCount()); int start = LevelHeader(lev_num); int finish = LevelLastLump(lev_num); for ( ; start <= finish ; start++) { if (directory[start].lump->name.noCaseEqual("ZNODES")) { RemoveLumps(start, 1); break; } } } void Wad_file::FixLevelGroup(int index, int num_added, int num_removed) { bool did_remove = false; for (int k = 0 ; k < (int)levels.size() ; k++) { if (levels[k] < index) continue; if (levels[k] < index + num_removed) { levels[k] = -1; did_remove = true; continue; } levels[k] += num_added; levels[k] -= num_removed; } if (did_remove) { std::vector::iterator ENDP; ENDP = std::remove(levels.begin(), levels.end(), -1); levels.erase(ENDP, levels.end()); } } // // Writes to the given path // void Wad_file::writeToPath(const fs::path &path) const noexcept(false) { BufferedOutFile sof(path); // Write the header if(kind == WadKind::PWAD) sof.write("PWAD", 4); else sof.write("IWAD", 4); int32_t numlumps = (int32_t)directory.size(); sof.write(&numlumps, 4); int32_t infotableofs = 12; for(const LumpRef &ref : directory) infotableofs += (int32_t)ref.lump->Length(); sof.write(&infotableofs, 4); for(const LumpRef &ref : directory) { assert(ref.lump.get() != nullptr); const Lump_c &lump = *ref.lump; sof.write(lump.getData().data(), lump.Length()); } infotableofs = 12; for(const LumpRef &ref : directory) { sof.write(&infotableofs, 4); const Lump_c &lump = *ref.lump; numlumps = lump.Length(); sof.write(&numlumps, 4); infotableofs += numlumps; int64_t nm = lump.getName8(); sof.write(&nm, 8); } sof.commit(); } Lump_c & Wad_file::AddLump(const SString &name) { Lump_c *lump = new Lump_c(name); // check if the insert_point is still valid if (insert_point >= NumLumps()) insert_point = -1; if (insert_point >= 0) { FixLevelGroup(insert_point, 1, 0); LumpRef lumpRef = {}; lumpRef.lump.reset(lump); directory.insert(directory.begin() + insert_point, std::move(lumpRef)); insert_point++; } else // add to end { LumpRef lumpRef = {}; lumpRef.lump.reset(lump); directory.push_back(std::move(lumpRef)); } ProcessNamespaces(); return *lump; } Lump_c * Wad_file::AddLevel(const SString &name, int *lev_num) { int actual_point = insert_point; if (actual_point < 0 || actual_point > NumLumps()) actual_point = NumLumps(); Lump_c & lump = AddLump(name); if (lev_num) { *lev_num = (int)levels.size(); } levels.push_back(actual_point); return &lump; } void Wad_file::InsertPoint(int index) noexcept { // this is validated on usage insert_point = index; } // // This one merely saves it as a new filename // bool Wad_file::Backup(const fs::path &new_filename) const { try { writeToPath(new_filename); } catch(const std::exception &e) { gLog.printf("Failed backing up %s to %s: %s\n", PathName().u8string().c_str(), new_filename.u8string().c_str(), e.what()); return false; } return true; } //------------------------------------------------------------------------ // GLOBAL API //------------------------------------------------------------------------ // // find a lump in any loaded wad (later ones tried first), // returning NULL if not found. // const Lump_c *MasterDir::findGlobalLump(const SString &name) const { std::vector> wads = getAll(); for (auto it = wads.rbegin(); it != wads.rend(); ++it) { const Lump_c *L = (*it)->FindLumpInNamespace(name, WadNamespace::Global); if (L) return L; } return NULL; // not found } //------------------------------------------------------------------------ void MasterDir::MasterDir_CloseAll() { resource_wads.clear(); edit_wad.reset(); game_wad.reset(); } static bool W_FilenameAbsEqual(const SString &A, const SString &B) { const SString &A_path = GetAbsolutePath(A.get()).u8string(); const SString &B_path = GetAbsolutePath(B.get()).u8string(); return A_path.noCaseEqual(B_path); } void W_StoreString(char *buf, const SString &str, size_t buflen) { memset(buf, 0, buflen); for (size_t i = 0 ; i < buflen && str[i] ; i++) buf[i] = str[i]; } bool MasterDir::MasterDir_HaveFilename(const SString &chk_path) const { std::vector> wads = getAll(); for (const std::shared_ptr &wad : wads) { SString wad_path = wad->PathName().u8string(); if (W_FilenameAbsEqual(wad_path, chk_path)) return true; } return false; } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/src/w_wad.h000066400000000000000000000215631464327712600176110ustar00rootroot00000000000000//------------------------------------------------------------------------ // WAD Reading / Writing //------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2001-2016 Andrew Apted // Copyright (C) 1997-2003 André Majorel et al // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ // // Based on Yadex which incorporated code from DEU 5.21 that was put // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber. // //------------------------------------------------------------------------ #ifndef __EUREKA_W_WAD_H__ #define __EUREKA_W_WAD_H__ #include "Errors.h" #include "main.h" #include #include "filesystem.hpp" namespace fs = ghc::filesystem; class Wad_file; // // Wad namespace // enum class WadNamespace { Global, Flats, Sprites, TextureLumps }; enum class WadOpenMode { read, write, append }; enum class WadKind { PWAD, IWAD }; // // Wad writing exception // class WadWriteException : public std::runtime_error { public: WadWriteException(const SString &msg) : std::runtime_error(msg.c_str()) { } }; class Lump_c { friend class Wad_file; private: SString name; std::vector mData; int mPos = 0; // insertion point for reading or writing public: Lump_c() = default; explicit Lump_c(const SString& _nam); Lump_c(Lump_c&& other) = default; Lump_c& operator = (Lump_c&& other) = default; const SString &Name() const noexcept { return name; } int Length() const { return (int)mData.size(); } // do not call this directly, use Wad_file::RenameLump() void Rename(const char *new_name); // write some data to the lump. Only the lump which had just // been created with Wad_file::AddLump() or RecreateLump() can be // written to. void Write(const void *data, int len); // write some text to the lump void Printf(EUR_FORMAT_STRING(const char *msg), ...) EUR_PRINTF(2, 3); // Memory buffer actions size_t writeData(FILE *f, int len); void setData(std::vector &&data) { mData = std::move(data); } // // Clear the lump data // void clearData() noexcept { mData.clear(); mPos = 0; } // // Gets the data from lump without moving the insertion point. // const std::vector &getData() const noexcept { return mData; } int64_t getName8() const noexcept; private: // deliberately don't implement these Lump_c(const Lump_c& other); Lump_c& operator= (const Lump_c& other); }; class LumpInputStream { public: explicit LumpInputStream(const Lump_c &lump) : lump(lump) { } bool read(void *data, int len) noexcept; bool readLine(SString &string) noexcept; private: const Lump_c &lump; int pos = 0; }; //------------------------------------------------------------------------ struct LumpRef { std::unique_ptr lump; WadNamespace ns; }; struct SpriteLumpRef { const Lump_c *lump; bool flipped; }; class Wad_file { private: const fs::path filename; WadOpenMode mode; // mode value passed to ::Open() WadKind kind = WadKind::PWAD; // 'P' for PWAD, 'I' for IWAD std::vector directory; // these are lump indices (into 'directory' vector) std::vector levels; // when >= 0, the next added lump is placed _before_ this int insert_point = -1; // constructor is private Wad_file(const fs::path &_name, WadOpenMode _mode) : filename(_name), mode(_mode) { } public: ~Wad_file(); // open a wad file. // // mode is similar to the fopen() function: // 'r' opens the wad for reading ONLY // 'a' opens the wad for appending (read and write) // 'w' opens the wad for writing (i.e. create it) // // Note: if 'a' is used and the file is read-only, it will be // silently opened in 'r' mode instead. // static std::shared_ptr Open(const fs::path &filename, WadOpenMode mode = WadOpenMode::append); static std::shared_ptr loadFromFile(const fs::path &filename); static std::shared_ptr readFromDir(const fs::path &path); // check the given wad file exists and is a WAD file static bool Validate(const fs::path &filename); const fs::path &PathName() const noexcept { return filename; } bool IsReadOnly() const noexcept { return mode == WadOpenMode::read; } bool IsIWAD() const noexcept { return kind == WadKind::IWAD; } int TotalSize() const noexcept; int NumLumps() const noexcept { return static_cast(directory.size()); } Lump_c * GetLump(int index) const noexcept; Lump_c * FindLump(const SString &name) const noexcept; int FindLumpNum(const SString &name) const noexcept; const Lump_c * FindLumpInNamespace(const SString &name, WadNamespace group) const noexcept; std::vector findFirstSpriteLump(const SString &stem) const; int LevelCount() const noexcept { return (int)levels.size(); } int LevelHeader(int lev_num) const noexcept; int LevelLastLump(int lev_num) const noexcept; // these return a level number (0 .. count-1) int LevelFind(const SString &name) const noexcept; int LevelFindByNumber(int number) const noexcept; int LevelFindFirst() const noexcept; // returns a lump index, -1 if not found int LevelLookupLump(int lev_num, const char *name) const noexcept; MapFormat LevelFormat(int lev_num) const noexcept; void SortLevels() noexcept; // backup the current wad into the given filename. // returns true if successful, false on error. bool Backup(const fs::path &new_filename) const; void writeToDisk() noexcept(false); // change name of a lump (can be a level marker too) void RenameLump(int index, const char *new_name); // remove the given lump(s) // this will change index numbers on existing lumps // (previous results of FindLumpNum or LevelHeader are invalidated). void RemoveLumps(int index, int count = 1); // this removes the level marker PLUS all associated level lumps // which follow it. std::vector RemoveLevel(int lev_num); // removes any GL-Nodes lumps that are associated with the given // level. void RemoveGLNodes(int lev_num); // removes any ZNODES lump from a UDMF level. void RemoveZNodes(int lev_num); // insert a new lump. // The second form is for a level marker. // The 'max_size' parameter (if >= 0) specifies the most data // you will write into the lump -- writing more will corrupt // something else in the WAD. Lump_c & AddLump (const SString &name); Lump_c * AddLevel(const SString &name, int *lev_num = nullptr); // set the insertion point -- the next lump will be added _before_ // this index, and it will be incremented so that a sequence of // AddLump() calls produces lumps in the same order. // // passing a negative value or invalid index will reset the // insertion point -- future lumps get added at the END. // RemoveLumps(), RemoveLevel() and EndWrite() also reset it. void InsertPoint(int index = -1) noexcept; const std::vector &getDir() const { return directory; } private: static std::shared_ptr Create(const fs::path &filename, WadOpenMode mode); static std::shared_ptr createAndReadDirectory(const fs::path &filename, WadOpenMode mode, FILE *fp); // read the existing directory. bool ReadDirectory(FILE *fp, int totalSize); void DetectLevels(); void ProcessNamespaces(); void FixLevelGroup(int index, int num_added, int num_removed); void writeToPath(const fs::path &path) const noexcept(false); // deliberately don't implement these Wad_file(const Wad_file& other); Wad_file& operator= (const Wad_file& other); // predicate for sorting the levels[] vector struct level_name_CMP_pred { private: const Wad_file *wad; public: level_name_CMP_pred(const Wad_file * _w) : wad(_w) { } inline bool operator() (const int A, const int B) const noexcept { const Lump_c *L1 = wad->directory[A].lump.get(); const Lump_c *L2 = wad->directory[B].lump.get(); return L1->Name() < L2->Name(); } }; }; void W_StoreString(char *buf, const SString &str, size_t buflen); namespace global { extern bool udmf_testing; } //============================================================================= // // Wad and lump fully loaded in memory // // // Holds info of failed resource to read // struct FailedWadReadEntry { int dirIndex; // index in the directory // content of directory char name[9]; int position; int length; }; #endif /* __EUREKA_W_WAD_H__ */ //--- editor settings --- // vi:ts=4:sw=4:noexpandtab eureka-editor-eureka-2.0.2/test/000077500000000000000000000000001464327712600165205ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/test/CMakeLists.txt000066400000000000000000000074611464327712600212700ustar00rootroot00000000000000message(STATUS "Enable testing: ${ENABLE_UNIT_TESTS}") # Following https://github.com/google/googletest/blob/main/googletest/README.md include(FetchContent) FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG v1.14.0 ) # For Windows: Prevent overriding the parent project's compiler/linker settings set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) FetchContent_MakeAvailable(googletest) set(src ${CMAKE_SOURCE_DIR}/src) get_target_property(src_includes eurekasrc INCLUDE_DIRECTORIES) get_target_property(fltk_libs eurekasrc LINK_LIBRARIES) get_target_property(eureka_compile_options eurekasrc COMPILE_OPTIONS) list(FILTER fltk_libs INCLUDE REGEX fltk) # This is the common testing library. Contains whatever's in testUtils and some very common # eurekasrc files add_library( testutils STATIC testUtils/FatalHandler.cpp testUtils/FatalHandler.hpp testUtils/TempDirContext.cpp testUtils/TempDirContext.hpp testUtils/Palette.cpp testUtils/Palette.hpp ) target_link_libraries(testutils PUBLIC gtest_main eurekacore) if(WIN32) target_link_libraries(testutils PUBLIC Rpcrt4.lib) endif() target_include_directories(testutils PUBLIC ${src} ${src_includes}) target_compile_options(testutils PUBLIC ${eureka_compile_options}) # Need to link to them separately if FLTK is linked manually if(APPLE) find_library(CARBON_FRAMEWORK Carbon) target_link_libraries(testutils PUBLIC ${CARBON_FRAMEWORK}) find_library(COCOA_FRAMEWORK Cocoa) target_link_libraries(testutils PUBLIC ${COCOA_FRAMEWORK}) find_library(APPSERVICES_FRAMEWORK ApplicationServices) target_link_libraries(testutils PUBLIC ${APPSERVICES_FRAMEWORK}) endif() add_executable( test_general DocumentTest.cpp e_checks_test.cpp e_commands_test.cpp e_cutpaste_test.cpp e_linedef_test.cpp e_objects_test.cpp FixedPointTest.cpp im_color_test.cpp im_img_test.cpp lib_file_test.cpp lib_tga_test.cpp lib_util_test.cpp m_bitvec_test.cpp m_files_test.cpp m_game_test.cpp m_parse_test.cpp m_select_test.cpp m_streams_test.cpp m_testmap_test.cpp main_test.cpp r_grid_test.cpp SafeOutFileTest.cpp SectorTest.cpp SideTest.cpp SStringTest.cpp StringTableTest.cpp sys_debug_test.cpp ThingTest.cpp VertexTest.cpp w_dehacked_test.cpp w_loadpic_test.cpp w_texture_test.cpp w_wad_test.cpp WadDataTest.cpp stub/osxcalls_stub.cpp ) target_link_libraries(test_general PRIVATE testutils eurekasrc) if(APPLE) # Need to get access to the OSXCalls.h stuff target_include_directories(test_general PRIVATE ${CMAKE_SOURCE_DIR}/osx/EurekaApp) target_compile_definitions(test_general PRIVATE GL_SILENCE_DEPRECATION) endif() target_compile_definitions(test_general PUBLIC NO_OPENGL) target_link_libraries(test_general PRIVATE ${fltk_libs}) if(UNIX AND NOT APPLE) find_package(ZLIB REQUIRED) find_package(X11 REQUIRED) target_link_libraries(test_general PRIVATE ${X11_X11_LIB} ${X11_Xpm_LIB} ${ZLIB_LIBRARIES}) endif() add_test(NAME test_general COMMAND $) # IMPORTANT: the eurekasrc files from testutils are already linked! # unit_test(m_config_keys # m_config_test.cpp # m_keys_test.cpp # SRC im_color.cc # im_img.cc # lib_file.cc # m_config.cc # m_keys.cc # m_parse.cc # m_streams.cc # SafeOutFile.cc # w_wad.cc # FLTK # ) find_package(Python3) if(NOT Python3_FOUND) message(WARNING "Python 3 not found, will not run system tests.") else() add_test(NAME system_test_print_quit COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/python/test_print_quit.py --executable $ --version ${PROJECT_VERSION} ) endif() eureka-editor-eureka-2.0.2/test/DocumentTest.cpp000066400000000000000000000073311464327712600216460ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Document.h" #include "Instance.h" #include "lib_adler.h" #include "LineDef.h" #include "Thing.h" #include "Vertex.h" #include "gtest/gtest.h" class DocumentFixture : public ::testing::Test { protected: DocumentFixture() : doc(inst) { } Instance inst; Document doc; }; TEST_F(DocumentFixture, CheckObjects) { // Start with 0 ASSERT_FALSE(doc.numThings()); ASSERT_FALSE(doc.numVertices()); ASSERT_FALSE(doc.numSectors()); ASSERT_FALSE(doc.numSidedefs()); ASSERT_FALSE(doc.numLinedefs()); // Add some objects doc.things.push_back(std::make_shared()); doc.things.push_back(std::make_shared()); doc.things.push_back(std::make_shared()); doc.vertices.push_back(std::make_shared()); doc.vertices.push_back(std::make_shared()); doc.vertices.push_back(std::make_shared()); doc.vertices.push_back(std::make_shared()); // no sectors doc.sidedefs.push_back(std::make_shared()); doc.sidedefs.push_back(std::make_shared()); doc.linedefs.push_back(std::make_shared()); ASSERT_EQ(doc.numThings(), 3); ASSERT_EQ(doc.numVertices(), 4); ASSERT_EQ(doc.numSectors(), 0); ASSERT_EQ(doc.numSidedefs(), 2); ASSERT_EQ(doc.numLinedefs(), 1); ASSERT_EQ(doc.numObjects(ObjType::things), 3); ASSERT_EQ(doc.numObjects(ObjType::vertices), 4); ASSERT_EQ(doc.numObjects(ObjType::sectors), 0); ASSERT_EQ(doc.numObjects(ObjType::sidedefs), 2); ASSERT_EQ(doc.numObjects(ObjType::linedefs), 1); ASSERT_FALSE(doc.isThing(-1)); ASSERT_TRUE(doc.isThing(0)); ASSERT_TRUE(doc.isThing(1)); ASSERT_TRUE(doc.isThing(2)); ASSERT_FALSE(doc.isThing(3)); ASSERT_FALSE(doc.isVertex(-1)); ASSERT_TRUE(doc.isVertex(0)); ASSERT_TRUE(doc.isVertex(1)); ASSERT_TRUE(doc.isVertex(2)); ASSERT_TRUE(doc.isVertex(3)); ASSERT_FALSE(doc.isVertex(4)); ASSERT_FALSE(doc.isSector(-1)); ASSERT_FALSE(doc.isSector(0)); ASSERT_FALSE(doc.isSidedef(-1)); ASSERT_TRUE(doc.isSidedef(0)); ASSERT_TRUE(doc.isSidedef(1)); ASSERT_FALSE(doc.isSidedef(2)); ASSERT_FALSE(doc.isLinedef(-1)); ASSERT_TRUE(doc.isLinedef(0)); ASSERT_FALSE(doc.isLinedef(1)); } TEST_F(DocumentFixture, CRC) { // Add some objects doc.things.push_back(std::make_shared()); doc.things.push_back(std::make_shared()); doc.things.push_back(std::make_shared()); doc.vertices.push_back(std::make_shared()); doc.vertices.push_back(std::make_shared()); doc.vertices.push_back(std::make_shared()); doc.vertices.push_back(std::make_shared()); // no sectors doc.sidedefs.push_back(std::make_shared()); doc.sidedefs.push_back(std::make_shared()); doc.linedefs.push_back(std::make_shared()); crc32_c crc; doc.getLevelChecksum(crc); // Now remove one thing doc.things.pop_back(); crc32_c crc2; doc.getLevelChecksum(crc2); ASSERT_NE(crc.getPath(), crc2.getPath()); // Now add back one thing doc.things.push_back(std::make_shared()); crc32_c crc3; doc.getLevelChecksum(crc3); ASSERT_EQ(crc.getPath(), crc3.getPath()); } eureka-editor-eureka-2.0.2/test/FixedPointTest.cpp000066400000000000000000000036321464327712600221410ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "FixedPoint.h" #include "gtest/gtest.h" TEST(FixedPoint, FracUnitConsistency) { ASSERT_EQ(kFracUnit, static_cast(kFracUnitD)); } TEST(FixedPoint, FracUnitIsPowerOf2) { ASSERT_GT(kFracUnit, 0); ASSERT_FALSE(kFracUnit & (kFracUnit - 1)); } TEST(FixedPoint, FromCoord) { auto number = FFixedPoint(123.25); ASSERT_EQ(static_cast(number), 123.25); // now try negative number = FFixedPoint(-67.75); ASSERT_EQ(static_cast(number), -67.75); } TEST(FixedPoint, ToCoordRaw) { double number = 123.25; ASSERT_EQ(FFixedPoint(number).raw(), static_cast(123.25 * kFracUnit)); number = -67.75; ASSERT_EQ(FFixedPoint(number).raw(), static_cast(-67.75 * kFracUnit)); } TEST(FixedPoint, IntToCoord) { int number = 123; ASSERT_EQ(FFixedPoint(number).raw(), 123 * kFracUnit); number = -67; ASSERT_EQ(FFixedPoint(number).raw(), -67 * kFracUnit); } TEST(FixedPoint, CoordToInt) { auto number = FFixedPoint(123); ASSERT_EQ(static_cast(number), 123); // now try negative number = FFixedPoint(-67); ASSERT_EQ(static_cast(number), -67); } TEST(FixedPoint, ZeroInit) { FFixedPoint point = {}; ASSERT_EQ(point.raw(), 0); ASSERT_EQ(FFixedPoint{}.raw(), 0); } eureka-editor-eureka-2.0.2/test/LumpTest.cpp000066400000000000000000000024651464327712600210100ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2021 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Lump.h" #include "m_strings.h" #include "gtest/gtest.h" TEST(Lump, General) { Lump lump; ASSERT_STREQ(lump.getName(), ""); ASSERT_STREQ(lump.getDataAsString(), ""); lump.setName("abcde"); ASSERT_STREQ(lump.getName(), "ABCDE"); lump.setName("abcdefghhij"); ASSERT_STREQ(lump.getName(), "ABCDEFGH"); lump.setName(""); ASSERT_STREQ(lump.getName(), ""); lump.setData({ '1', '2', '3', '4', '5', '6', '7', '8', '9'}); ASSERT_STREQ(lump.getDataAsString(), "123456789"); lump.setData({ '1', '2', '3', '4', '5', '6', 0, '8', '9'}); ASSERT_STREQ(lump.getDataAsString(), "123456"); } eureka-editor-eureka-2.0.2/test/SStringTest.cpp000066400000000000000000000221711464327712600214600ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2020 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "m_strings.h" #include "testUtils/FatalHandler.hpp" #include "gtest/gtest.h" TEST(MStrings, YStricmp) { ASSERT_EQ(y_stricmp("Jackson", "jackson"), 0); ASSERT_NE(y_stricmp("Jackson", "Jacksonville"), 0); ASSERT_EQ(y_strnicmp("jackson", "JACKSONVILLE", 7), 0); ASSERT_LT(y_stricmp("jackson", "Michael"), 0); ASSERT_LT(y_stricmp("Jackson", "michael"), 0); ASSERT_GT(y_stricmp("mackson", "Jichael"), 0); ASSERT_GT(y_stricmp("Mackson", "jichael"), 0); ASSERT_EQ(y_stricmp("", ""), 0); } TEST(MStringsDeath, StringNew) { ASSERT_DEATH(Fatal([]{ StringNew(-1); }), "Assertion"); } TEST(MStrings, StringDup) { const char original[] = "Michael"; char *copy = StringDup(original); ASSERT_STREQ(copy, original); ASSERT_NE(copy, original); free(copy); copy = StringDup(original, 4); ASSERT_STREQ(copy, "Mich"); free(copy); copy = StringDup(original, 0); ASSERT_STREQ(copy, ""); free(copy); } TEST(MStrings, YStrUprLowr) { char name[] = "Jackson"; y_strupr(name); ASSERT_STREQ(name, "JACKSON"); char name2[] = "Michael"; y_strlowr(name2); ASSERT_STREQ(name2, "michael"); char empty[] = ""; y_strupr(empty); ASSERT_STREQ(empty, ""); y_strlowr(empty); ASSERT_STREQ(empty, ""); } TEST(MStrings, StringCopy) { char buff[5]; StringCopy(buff, 5, "Michael"); ASSERT_STREQ(buff, "Mich"); StringCopy(buff, 5, "ABC"); ASSERT_STREQ(buff, "ABC"); } TEST(SString, Construct) { SString nullString(nullptr); ASSERT_EQ(nullString, ""); ASSERT_TRUE(nullString.empty()); SString aString("str"); ASSERT_EQ(aString, "str"); ASSERT_STREQ(aString.c_str(), "str"); ASSERT_EQ(aString.length(), 3); ASSERT_TRUE(aString.good()); ASSERT_FALSE(aString.empty()); char sizedBuffer[8] = "Flat"; SString trimmedString(sizedBuffer, (int)sizeof(sizedBuffer)); ASSERT_EQ(trimmedString, "Flat"); ASSERT_EQ(trimmedString.length(), 4); char fullBuffer[4] = {'P', 'W', 'A', 'D'}; SString goodString(fullBuffer, 4); ASSERT_EQ(goodString, "PWAD"); ASSERT_EQ(goodString.length(), 4); SString nullStringSized(nullptr, 4); ASSERT_TRUE(nullStringSized.empty()); // C++ string std::string jackson = "Michael Jackson"; SString sjackson(jackson); ASSERT_EQ(sjackson, "Michael Jackson"); } TEST(SString, FindSpace) { ASSERT_EQ(SString("Michael Jackson").findSpace(), 7); ASSERT_EQ(SString("Michael \tJackson").findSpace(), 7); ASSERT_EQ(SString("Michae\n \tJackson").findSpace(), 6); ASSERT_EQ(SString("Micha\t \nJackson").findSpace(), 5); ASSERT_EQ(SString("Mich\r \tJackson").findSpace(), 4); ASSERT_EQ(SString("MichJackson").findSpace(), SString::npos); ASSERT_EQ(SString().findSpace(), SString::npos); ASSERT_EQ(SString("\t").findSpace(), 0); } TEST(SString, FindDigit) { ASSERT_EQ(SString("MAP01").findDigit(), 3); ASSERT_EQ(SString("MAPXY").findDigit(), SString::npos); ASSERT_EQ(SString("MAPF23").findDigit(), 4); ASSERT_EQ(SString().findDigit(), SString::npos); } TEST(SString, TrimLeadingSpaces) { SString string = " \t\t\nMichael "; string.trimLeadingSpaces(); ASSERT_EQ(string, "Michael "); SString emptyString = ""; emptyString.trimLeadingSpaces(); ASSERT_TRUE(emptyString.empty()); SString invariant = "Jackson "; invariant.trimLeadingSpaces(); ASSERT_EQ(invariant, "Jackson "); SString spaceOnly = " \t\n\r "; spaceOnly.trimLeadingSpaces(); ASSERT_TRUE(spaceOnly.empty()); } TEST(SString, TrimTrailingSet) { SString string = "//\\//Maglev//\\\\///"; string.trimTrailingSet("/\\"); ASSERT_EQ(string, "//\\//Maglev"); SString emptyString = ""; emptyString.trimTrailingSet("a"); ASSERT_TRUE(emptyString.empty()); SString fullRemoval = "jackson"; fullRemoval.trimTrailingSet("acjknos"); ASSERT_TRUE(fullRemoval.empty()); } TEST(SString, TrimTrailingSpaces) { SString string = " \t\t\nMichael \t\n\r"; string.trimTrailingSpaces(); ASSERT_EQ(string, " \t\t\nMichael"); SString emptyString = ""; emptyString.trimTrailingSpaces(); ASSERT_TRUE(emptyString.empty()); SString invariant = " Jackson"; invariant.trimTrailingSpaces(); ASSERT_EQ(invariant, " Jackson"); SString spaceOnly = " \t\n\r "; spaceOnly.trimTrailingSpaces(); ASSERT_TRUE(spaceOnly.empty()); } TEST(SString, NoCaseCheck) { ASSERT_TRUE(SString("Michael").noCaseEqual("MiCHaEL")); ASSERT_TRUE(SString("Michael").noCaseEqual(SString("MiCHaEL"))); ASSERT_FALSE(SString("Michael").noCaseEqual("Jackson")); ASSERT_TRUE(SString("").noCaseEqual(nullptr)); ASSERT_LT(SString("jackson").noCaseCompare("Michael"), 0); ASSERT_EQ(SString("jackson").noCaseCompare("JackSON"), 0); ASSERT_GT(SString("Jackson").noCaseCompare("III"), 0); ASSERT_TRUE(SString("MICHAEL JACKSON").noCaseStartsWith("mich")); ASSERT_FALSE(SString("MICHAEL JACKSON").noCaseStartsWith("Jack")); ASSERT_TRUE(SString("JACKSON").noCaseEndsWith("Son")); ASSERT_FALSE(SString("JACKSON").noCaseEndsWith("MJackson")); ASSERT_TRUE(SString("JACKSON").noCaseEndsWith("Jackson")); ASSERT_TRUE(SString("JACKSON").noCaseEndsWith("")); ASSERT_TRUE(SString("JACKSON").noCaseEndsWith(nullptr)); ASSERT_TRUE(SString().noCaseEndsWith(nullptr)); ASSERT_FALSE(SString().noCaseEndsWith("a")); ASSERT_EQ(SString("Michael Jackson").findNoCase("jack"), 8); ASSERT_EQ(SString("Michael Jackson").findNoCase("ACK"), 9); ASSERT_EQ(SString("Michael Jackson").findNoCase("Jax"), std::string::npos); } TEST(SString, StartsWith) { ASSERT_TRUE(SString("Michael Jackson").startsWith("Mich")); ASSERT_FALSE(SString("Michael Jackson").startsWith("mich")); ASSERT_TRUE(SString("Michael Jackson").startsWith(nullptr)); } TEST(SString, Operators) { ASSERT_NE(SString("Daniel"), SString("daniel")); ASSERT_NE(SString("Daniel"), "daniel"); ASSERT_EQ(SString("Daniel"), SString("Daniel")); ASSERT_EQ(SString("Daniel"), "Daniel"); ASSERT_LT(SString("Daniel"), SString("Earn")); ASSERT_FALSE(SString("EDaniel") < SString("Darn")); } TEST(SString, Indexing) { SString name = "Jackson"; ASSERT_EQ(name[0], 'J'); ASSERT_EQ(name[1], 'a'); ASSERT_EQ(name[2], 'c'); ASSERT_EQ(name[-1], 'n'); ASSERT_EQ(name[-2], 'o'); ASSERT_EQ(name[-3], 's'); name[-3] = 't'; name[1] = 'e'; ASSERT_EQ(name, "Jeckton"); } TEST(SString, NulBan) { SString name = "Jackson"; name += '\0'; ASSERT_EQ(name, "Jackson"); ASSERT_EQ(name.length(), 7); name += 't'; ASSERT_EQ(name, "Jacksont"); } TEST(SString, CutWithSpace) { SString name = "Michael Jackson"; SString first, last; name.getCutWithSpace(7, &first, &last); ASSERT_EQ(first, "Michael"); ASSERT_EQ(last, "Jackson"); SString tail; last.cutWithSpace(6, &tail); ASSERT_EQ(last, "Jackso"); ASSERT_TRUE(tail.empty()); SString surname; name.cutWithSpace(7, &surname); ASSERT_EQ(name, "Michael"); ASSERT_EQ(surname, "Jackson"); } TEST(SString, AsCase) { ASSERT_EQ(SString("jackson").asTitle(), "Jackson"); ASSERT_EQ(SString("Jackson").asUpper(), "JACKSON"); ASSERT_EQ(SString("Jackson").asLower(), "jackson"); } TEST(SString, GetTidy) { ASSERT_EQ(SString("\x02\x01\x02TEXT \"Gorilla\"\n\t\x19").getTidy(), "TEXT \"Gorilla\""); ASSERT_EQ(SString("\x02\x01\x02TEXT \"Gorilla\"\n\t\x19").getTidy("\"a"), "TEXT Gorill"); } TEST(SString, GlobalOperatorPlus) { ASSERT_EQ("Michael" + SString(" Jackson"), "Michael Jackson"); ASSERT_EQ(nullptr + SString(" Jackson"), " Jackson"); } TEST(SString, GlobalOperatorStream) { std::stringstream ss; ss << SString("Michael") << ' ' << SString("Jackson"); ASSERT_EQ(ss.str(), "Michael Jackson"); } TEST(SString, ToNumberOverloads) { ASSERT_EQ(atoi(SString("42")), 42); ASSERT_DOUBLE_EQ(atof(SString("42.24")), 42.24); ASSERT_EQ(strtol(SString("42"), nullptr, 0), 42); ASSERT_EQ(strtol(SString("042"), nullptr, 0), 042); ASSERT_EQ(strtol(SString("0x42"), nullptr, 0), 0x42); ASSERT_EQ(strtol(SString("042"), nullptr, 16), 0x42); ASSERT_EQ(strtol(SString("042"), nullptr, 10), 42); char *endptr = nullptr; SString fourtytwo = "42a"; ASSERT_EQ(strtol(fourtytwo, &endptr, 0), 42); ASSERT_EQ(endptr, fourtytwo.c_str() + 2); } TEST(SString, Escape) { ASSERT_EQ(SString("OneWord").spaceEscape(), "OneWord"); ASSERT_EQ(SString("One Word").spaceEscape(), "\"One Word\""); ASSERT_EQ(SString("One\"Word").spaceEscape(), "\"One\"\"Word\""); ASSERT_EQ(SString("One\"Word").spaceEscape(true), "\"One\\\"Word\""); ASSERT_EQ(SString("One \"Ripper\" Word").spaceEscape(), "\"One \"\"Ripper\"\" Word\""); ASSERT_EQ(SString("").spaceEscape(), "\"\""); ASSERT_EQ(SString("LA#SEC").spaceEscape(), "\"LA#SEC\""); } eureka-editor-eureka-2.0.2/test/SafeOutFileTest.cpp000066400000000000000000000045331464327712600222370ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2021 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Errors.h" #include "SafeOutFile.h" #include "testUtils/TempDirContext.hpp" #include "gtest/gtest.h" class SafeOutFileTest : public TempDirContext { }; static void checkFileContent(const fs::path &path, const char *content) { std::ifstream stream(path); ASSERT_TRUE(stream.is_open()); char msg[128] = {}; ASSERT_TRUE(stream.get(msg, sizeof(msg))); ASSERT_TRUE(stream.eof()); ASSERT_FALSE(stream.fail()); stream.close(); ASSERT_STREQ(msg, content); } TEST_F(SafeOutFileTest, Stuff) { fs::path path = getChildPath("somefile.txt"); // Assert no file if merely created (will fail when tearing down) { BufferedOutFile sof(path); } { { BufferedOutFile sof(path); sof.write("Hello, world!", 13); // and this sof.write(" more.", 6); // and this // forget about commiting. // Tearing down should not be blocked by child folder } BufferedOutFile sof(path); // reopen it sof.write("Hello, world!", 13); // and this sof.write(" more.", 6); // and this // Check the destructor too } { // Now it will work BufferedOutFile sof(path); sof.write("Hello, world2!", 14); // and this sof.write(" more.", 6); // and this sof.commit(); } mDeleteList.push(path); // the delete list // Now check it checkFileContent(path, "Hello, world2! more."); { // Check that forgetting to commit won't overwrite the original BufferedOutFile sof(path); sof.write("New stuff!", 10); // no commit } checkFileContent(path, "Hello, world2! more."); { // Check that we can overwrite an old file BufferedOutFile sof(path); sof.write("New stuff!", 10); sof.commit(); } checkFileContent(path, "New stuff!"); } eureka-editor-eureka-2.0.2/test/SectorTest.cpp000066400000000000000000000031621464327712600213250ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "e_basis.h" #include "m_game.h" #include "Sector.h" #include "gtest/gtest.h" TEST(Sector, HeadRoom) { Sector sector; ASSERT_EQ(sector.HeadRoom(), 0); sector.floorh = 100; sector.ceilh = 345; ASSERT_EQ(sector.HeadRoom(), 245); } TEST(Sector, Texture) { Sector sector; sector.floor_tex = BA_InternaliseString("TEXONE"); sector.ceil_tex = BA_InternaliseString("TEXB"); ASSERT_EQ(sector.FloorTex(), "TEXONE"); ASSERT_EQ(sector.CeilTex(), "TEXB"); } TEST(Sector, SetDefaults) { ConfigData config; config.default_floor_tex = "DEFFLOOR"; config.default_ceil_tex = "DEFCEIL"; global::default_floor_h = 123; global::default_ceil_h = 456; global::default_light_level = 122; Sector sector; sector.SetDefaults(config); ASSERT_EQ(sector.floorh, 123); ASSERT_EQ(sector.ceilh, 456); ASSERT_EQ(sector.FloorTex(), "DEFFLOOR"); ASSERT_EQ(sector.CeilTex(), "DEFCEIL"); ASSERT_EQ(sector.light, 122); } eureka-editor-eureka-2.0.2/test/SideTest.cpp000066400000000000000000000031641464327712600207540ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Side.h" #include "gtest/gtest.h" #include TEST(Side, Enumeration) { std::vector sides; for(Side side : kSides) sides.push_back(side); ASSERT_EQ(sides.size(), 2); ASSERT_EQ(sides[0], Side::right); ASSERT_EQ(sides[1], Side::left); } TEST(Side, Negation) { ASSERT_EQ(-Side::right, Side::left); ASSERT_EQ(-Side::left, Side::right); ASSERT_EQ(-Side::neither, Side::neither); } TEST(Side, Multiplication) { ASSERT_EQ(Side::right * Side::right, Side::right); ASSERT_EQ(Side::right * Side::left, Side::left); ASSERT_EQ(Side::right * Side::neither, Side::neither); ASSERT_EQ(Side::left * Side::right, Side::left); ASSERT_EQ(Side::left * Side::left, Side::right); ASSERT_EQ(Side::left * Side::neither, Side::neither); ASSERT_EQ(Side::neither * Side::right, Side::neither); ASSERT_EQ(Side::neither * Side::left, Side::neither); ASSERT_EQ(Side::neither * Side::neither, Side::neither); } eureka-editor-eureka-2.0.2/test/StringTableTest.cpp000066400000000000000000000037411464327712600223070ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2020 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "m_strings.h" #include "gtest/gtest.h" TEST(StringID, Test) { StringID sid; ASSERT_EQ(sid.get(), 0); ASSERT_TRUE(!sid); ASSERT_TRUE(sid.isValid()); ASSERT_FALSE(sid.isInvalid()); ASSERT_FALSE(sid.hasContent()); StringID sid2; ASSERT_EQ(sid, sid2); sid = StringID(100); ASSERT_NE(sid, sid2); ASSERT_EQ(sid.get(), 100); ASSERT_FALSE(!sid); ASSERT_TRUE(sid.isValid()); ASSERT_FALSE(sid.isInvalid()); ASSERT_TRUE(sid.hasContent()); sid2 = sid; ASSERT_EQ(sid, sid2); sid = StringID(30); sid2 = StringID(30); ASSERT_EQ(sid, sid2); sid = StringID(-31); sid2 = StringID(-32); ASSERT_NE(sid, sid2); ASSERT_LT(sid.get(), 0); ASSERT_LT(sid2.get(), 0); ASSERT_FALSE(!sid); ASSERT_FALSE(sid.isValid()); ASSERT_TRUE(sid.isInvalid()); ASSERT_FALSE(sid.hasContent()); } TEST(StringTable, Test) { StringTable table; StringID index = table.add("Jackson"); ASSERT_EQ(table.get(index), "Jackson"); StringID index2 = table.add("Jackson"); ASSERT_EQ(index2, index); StringID index3 = table.add("Michael"); ASSERT_NE(index3, index2); ASSERT_EQ(table.get(index3), "Michael"); StringID index4 = table.add("jackson"); ASSERT_NE(index4, index); ASSERT_EQ(table.get(index), "Jackson"); ASSERT_EQ(table.get(index4), "jackson"); } eureka-editor-eureka-2.0.2/test/ThingTest.cpp000066400000000000000000000050741464327712600211430ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Thing.h" #include "gtest/gtest.h" TEST(Thing, ZeroInit) { Thing thing; ASSERT_FALSE(thing.raw_x); ASSERT_FALSE(thing.raw_y); ASSERT_FALSE(thing.angle); ASSERT_FALSE(thing.type); ASSERT_FALSE(thing.options); ASSERT_FALSE(thing.raw_h); ASSERT_FALSE(thing.tid); ASSERT_FALSE(thing.special); ASSERT_FALSE(thing.arg1); ASSERT_FALSE(thing.arg2); ASSERT_FALSE(thing.arg3); ASSERT_FALSE(thing.arg4); ASSERT_FALSE(thing.arg5); } TEST(Thing, RawToDouble) { Thing thing; thing.raw_x = FFixedPoint(123.75); ASSERT_EQ(thing.x(), 123.75); thing.raw_y = FFixedPoint(-234.875); ASSERT_EQ(thing.y(), -234.875); ASSERT_EQ(thing.xy(), v2double_t(123.75, -234.875)); thing.raw_h = FFixedPoint(-0.5); ASSERT_EQ(thing.h(), -0.5); } TEST(Thing, SetCoordinateClassicFormat) { Thing thing; thing.SetRawX(MapFormat::doom, 12.75); ASSERT_EQ(thing.x(), 13); thing.SetRawY(MapFormat::hexen, -24.23); ASSERT_EQ(thing.y(), -24); thing.SetRawH(MapFormat::hexen, -24.73); ASSERT_EQ(thing.h(), -25); // UDMF keeps decimals though thing.SetRawY(MapFormat::udmf, -24.75); ASSERT_EQ(thing.y(), -24.75); thing.SetRawH(MapFormat::udmf, 12.75); ASSERT_EQ(thing.h(), 12.75); } TEST(Thing, SetRawXY) { Thing thing; thing.SetRawXY(MapFormat::doom, {12.75, -24.73}); ASSERT_EQ(thing.x(), 13); ASSERT_EQ(thing.y(), -25); thing.SetRawXY(MapFormat::udmf, {12.75, -24.75}); ASSERT_EQ(thing.x(), 12.75); ASSERT_EQ(thing.y(), -24.75); } TEST(Thing, Arg) { Thing thing; thing.arg1 = 2; thing.arg2 = 5; thing.arg3 = -4; thing.arg4 = 22; thing.arg5 = 93; // Out of bounds values will just default to 0 ASSERT_EQ(thing.Arg(0), 0); ASSERT_EQ(thing.Arg(1), 2); ASSERT_EQ(thing.Arg(2), 5); ASSERT_EQ(thing.Arg(3), -4); ASSERT_EQ(thing.Arg(4), 22); ASSERT_EQ(thing.Arg(5), 93); ASSERT_EQ(thing.Arg(6), 0); ASSERT_EQ(thing.Arg(7), 0); ASSERT_EQ(thing.Arg(8), 0); } eureka-editor-eureka-2.0.2/test/VertexTest.cpp000066400000000000000000000044431464327712600213460ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Vertex.h" #include "gtest/gtest.h" TEST(Vertex, ZeroInit) { Vertex vertex; ASSERT_FALSE(vertex.raw_x); ASSERT_FALSE(vertex.raw_y); } TEST(Vertex, RawToDouble) { Vertex vertex; vertex.raw_x = FFixedPoint(123.75); ASSERT_EQ(vertex.x(), 123.75); vertex.raw_y = FFixedPoint(-234.875); ASSERT_EQ(vertex.y(), -234.875); ASSERT_EQ(vertex.xy(), v2double_t(123.75, -234.875)); } TEST(Vertex, SetCoordinateClassicFormat) { Vertex vertex; vertex.SetRawX(MapFormat::doom, 12.75); ASSERT_EQ(vertex.x(), 13); vertex.SetRawY(MapFormat::hexen, -24.23); ASSERT_EQ(vertex.y(), -24); vertex.SetRawX(MapFormat::hexen, -24.73); // UDMF keeps decimals though vertex.SetRawY(MapFormat::udmf, -24.75); ASSERT_EQ(vertex.y(), -24.75); vertex.SetRawX(MapFormat::udmf, 12.75); ASSERT_EQ(vertex.x(), 12.75); } TEST(Vertex, SetRawXY) { Vertex vertex; vertex.SetRawXY(MapFormat::doom, {12.75, -24.73}); ASSERT_EQ(vertex.x(), 13); ASSERT_EQ(vertex.y(), -25); vertex.SetRawXY(MapFormat::udmf, {12.75, -24.75}); ASSERT_EQ(vertex.x(), 12.75); ASSERT_EQ(vertex.y(), -24.75); } TEST(Vertex, Equality) { Vertex vertex; vertex.raw_x = FFixedPoint(1.5); vertex.raw_y = FFixedPoint(-2.75); ASSERT_TRUE(vertex.Matches(FFixedPoint(1.5), FFixedPoint(-2.75))); ASSERT_FALSE(vertex.Matches(FFixedPoint(1.5), FFixedPoint(-2.74))); Vertex vertex2; vertex2.raw_x = FFixedPoint(1.5); vertex2.raw_y = FFixedPoint(-2.75); Vertex vertex3; vertex3.raw_x = FFixedPoint(2); vertex3.raw_y = FFixedPoint(-2.75); ASSERT_EQ(vertex, vertex2); ASSERT_NE(vertex, vertex3); ASSERT_NE(vertex2, vertex3); } eureka-editor-eureka-2.0.2/test/WadDataTest.cpp000066400000000000000000000077711464327712600214050ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2021 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "WadData.h" #include "w_wad.h" #include "gtest/gtest.h" // // Add a valid lump with content so it can be part of the namespace // static void addValidLump(const std::shared_ptr &wad, const char *name) { Lump_c &lump = wad->AddLump(name); lump.Printf("a"); } TEST(MasterDir, FindGlobalLump) { MasterDir master; auto wad = Wad_file::Open("dummy.wad", WadOpenMode::write); ASSERT_TRUE(wad); addValidLump(wad, "LUMP1"); // 0 addValidLump(wad, "LUMP2"); addValidLump(wad, "S_START"); addValidLump(wad, "LUMP3"); addValidLump(wad, "LUMP4"); // 4 addValidLump(wad, "S_END"); addValidLump(wad, "LUMP5"); addValidLump(wad, "F_START"); addValidLump(wad, "LUMP6"); // 8 addValidLump(wad, "F_END"); addValidLump(wad, "LUMP7"); master.setGameWad(wad); auto wad2 = Wad_file::Open("dummy.wad", WadOpenMode::write); ASSERT_TRUE(wad2); addValidLump(wad2, "LUMP11"); // 0 addValidLump(wad2, "LUMP2"); addValidLump(wad2, "SS_START"); addValidLump(wad2, "LUMP5"); addValidLump(wad2, "S_END"); // 4 addValidLump(wad2, "LUMP3"); addValidLump(wad2, "FF_START"); addValidLump(wad2, "LUMP6"); addValidLump(wad2, "FF_END"); // 8 addValidLump(wad2, "LUMP7"); master.ReplaceEditWad(wad2); ASSERT_EQ(master.findGlobalLump("LUMP1"), wad->GetLump(0)); ASSERT_EQ(master.findGlobalLump("LUMP2"), wad2->GetLump(1)); ASSERT_EQ(master.findGlobalLump("LUMP3"), wad2->GetLump(5)); ASSERT_EQ(master.findGlobalLump("LUMP4"), nullptr); ASSERT_EQ(master.findGlobalLump("LUMP5"), wad->GetLump(6)); ASSERT_EQ(master.findGlobalLump("LUMP6"), nullptr); ASSERT_EQ(master.findGlobalLump("LUMP7"), wad2->GetLump(9)); ASSERT_EQ(master.findGlobalLump("LUMP11"), wad2->GetLump(0)); ASSERT_EQ(master.findGlobalLump("LUMP12"), nullptr); } TEST(MasterDir, FindFirstSpriteLump) { MasterDir master; auto wad = Wad_file::Open("dummy.wad", WadOpenMode::write); ASSERT_TRUE(wad); wad->AddLump("S_START"); Lump_c &wad1possa1 = wad->AddLump("POSSA1"); wad1possa1.Printf("a"); // need to have content to be considered wad->AddLump("TROOC1").Printf("a"); Lump_c &wad1troob1 = wad->AddLump("TROOB1"); wad1troob1.Printf("a"); Lump_c &wad1trood1 = wad->AddLump("TROOD1"); wad1trood1.Printf("a"); wad->AddLump("S_END"); master.setGameWad(wad); auto wad2 = Wad_file::Open("dummy2.wad", WadOpenMode::write); ASSERT_TRUE(wad2); wad2->AddLump("S_START"); Lump_c &wad2possa1 = wad2->AddLump("POSSA1"); wad2possa1.Printf("a"); Lump_c &wad2trooe1 = wad2->AddLump("TROOE1"); wad2trooe1.Printf("a"); wad2->AddLump("S_END"); master.ReplaceEditWad(wad2); std::vector tested, expected; tested = master.findFirstSpriteLump("POSS"); expected = { {&wad2possa1, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, }; for(int i = 0; i < 8; ++i) { ASSERT_EQ(tested.at(i).lump, expected[i].lump); ASSERT_EQ(tested.at(i).flipped, expected[i].flipped); } tested = master.findFirstSpriteLump("TROO"); expected = { {&wad2trooe1, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, }; for(int i = 0; i < 8; ++i) { ASSERT_EQ(tested.at(i).lump, expected[i].lump); ASSERT_EQ(tested.at(i).flipped, expected[i].flipped); } } eureka-editor-eureka-2.0.2/test/e_checks_test.cpp000066400000000000000000000202761464327712600220360ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2021 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "gtest/gtest.h" #include "e_checks.h" #include "e_basis.h" #include "e_hover.h" #include "Instance.h" #include "LineDef.h" #include "m_select.h" #include "Sector.h" #include "ui_window.h" //============================================================================== // // Tests // //============================================================================== // // Tests the findFreeTag function // TEST(EChecks, FindFreeTag) { Instance inst; // Check with empty level ASSERT_EQ(findFreeTag(inst, false), 0); ASSERT_EQ(findFreeTag(inst, true), 0); // Check with level having nothing tagged std::vector lines; auto assignLines = [&inst, &lines]() { inst.level.linedefs.clear(); for(LineDef &line : lines) { auto addedLine = std::make_shared(); *addedLine = line; inst.level.linedefs.push_back(std::move(addedLine)); } }; std::vector sectors; auto assignSectors = [&inst, §ors]() { inst.level.sectors.clear(); for(Sector §or : sectors) { auto newSector = std::make_shared(); *newSector = sector; inst.level.sectors.push_back(std::move(newSector)); } }; // Check a level just with lines lines.push_back(LineDef()); lines.push_back(LineDef()); assignLines(); ASSERT_EQ(findFreeTag(inst, false), 1); ASSERT_EQ(findFreeTag(inst, true), 1); // Also add the sectors sectors.push_back(Sector()); sectors.push_back(Sector()); assignSectors(); ASSERT_EQ(findFreeTag(inst, false), 1); ASSERT_EQ(findFreeTag(inst, true), 1); // Remove all lines lines.clear(); assignLines(); ASSERT_EQ(findFreeTag(inst, false), 1); ASSERT_EQ(findFreeTag(inst, true), 1); // Remove all sectors.clear(); assignSectors(); ASSERT_EQ(findFreeTag(inst, false), 0); ASSERT_EQ(findFreeTag(inst, true), 0); // Add them back and tag one line 1 lines.push_back(LineDef()); lines.push_back(LineDef()); lines.push_back(LineDef()); sectors.push_back(Sector()); sectors.push_back(Sector()); sectors.push_back(Sector()); assignLines(); assignSectors(); inst.level.linedefs[1]->tag = 1; ASSERT_EQ(findFreeTag(inst, false), 2); ASSERT_EQ(findFreeTag(inst, true), 2); // Also tag one sector 1 inst.level.sectors[2]->tag = 1; ASSERT_EQ(findFreeTag(inst, false), 2); ASSERT_EQ(findFreeTag(inst, true), 2); // Tag all of them 1: result should be 0 by now inst.level.linedefs[0]->tag = inst.level.linedefs[2]->tag = 1; inst.level.sectors[0]->tag = inst.level.sectors[1]->tag = 1; ASSERT_EQ(findFreeTag(inst, false), 0); ASSERT_EQ(findFreeTag(inst, true), 0); // Restore their tags but tag one by a bigger amount inst.level.linedefs[0]->tag = inst.level.linedefs[2]->tag = 0; inst.level.linedefs[2]->tag = 4; inst.level.sectors[0]->tag = inst.level.sectors[1]->tag = 0; ASSERT_EQ(findFreeTag(inst, false), 2); ASSERT_EQ(findFreeTag(inst, true), 2); // Tag one sector by the remaining gap inst.level.sectors[1]->tag = 2; ASSERT_EQ(findFreeTag(inst, false), 3); ASSERT_EQ(findFreeTag(inst, true), 3); // Finally no more space inst.level.linedefs[0]->tag = 3; ASSERT_EQ(findFreeTag(inst, false), 5); ASSERT_EQ(findFreeTag(inst, true), 5); // Test some other combos sectors.clear(); lines.resize(5); assignSectors(); assignLines(); lines[0].tag = 0; lines[1].tag = 2; lines[2].tag = 3; lines[3].tag = 4; lines[4].tag = 5; ASSERT_EQ(findFreeTag(inst, false), 1); ASSERT_EQ(findFreeTag(inst, true), 1); // Test the beastmark lines.resize(669); sectors.resize(669); assignLines(); assignSectors(); for(int i = 0; i < 666; ++i) { lines[i].tag = i; inst.level.sectors[i]->tag = i; } inst.conf.features.tag_666 = Tag666Rules::doom; // enable it ASSERT_EQ(findFreeTag(inst, false), 666); ASSERT_EQ(findFreeTag(inst, true), 668); inst.conf.features.tag_666 = Tag666Rules::heretic; // essentially the same ASSERT_EQ(findFreeTag(inst, false), 666); ASSERT_EQ(findFreeTag(inst, true), 668); inst.conf.features.tag_666 = Tag666Rules::disabled; // essentially the same ASSERT_EQ(findFreeTag(inst, false), 666); ASSERT_EQ(findFreeTag(inst, true), 666); // Add one more and re-test inst.level.linedefs[666]->tag = 666; inst.conf.features.tag_666 = Tag666Rules::doom; // enable it ASSERT_EQ(findFreeTag(inst, false), 667); ASSERT_EQ(findFreeTag(inst, true), 668); inst.conf.features.tag_666 = Tag666Rules::heretic; // essentially the same ASSERT_EQ(findFreeTag(inst, false), 667); ASSERT_EQ(findFreeTag(inst, true), 668); inst.conf.features.tag_666 = Tag666Rules::disabled; // essentially the same ASSERT_EQ(findFreeTag(inst, false), 667); ASSERT_EQ(findFreeTag(inst, true), 667); inst.level.sectors[667]->tag = 667; inst.conf.features.tag_666 = Tag666Rules::doom; // enable it ASSERT_EQ(findFreeTag(inst, false), 668); ASSERT_EQ(findFreeTag(inst, true), 668); inst.conf.features.tag_666 = Tag666Rules::heretic; // essentially the same ASSERT_EQ(findFreeTag(inst, false), 668); ASSERT_EQ(findFreeTag(inst, true), 668); inst.conf.features.tag_666 = Tag666Rules::disabled; // essentially the same ASSERT_EQ(findFreeTag(inst, false), 668); ASSERT_EQ(findFreeTag(inst, true), 668); } // // Test tagsApplyNewValue // TEST(EChecks, TagsApplyNewValue) { Instance inst; std::vector lines; std::vector sectors; lines.resize(7); sectors.resize(5); for(LineDef &line : lines) { auto newLine = std::make_shared(); *newLine = line; inst.level.linedefs.push_back(std::move(newLine)); } for(Sector §or : sectors) { auto newSector = std::make_shared(); *newSector = sector; inst.level.sectors.push_back(std::move(newSector)); } // Start with linedefs inst.edit.mode = ObjType::linedefs; inst.edit.Selected.emplace(ObjType::linedefs); // Nothing selected: check that nothing happens inst.level.checks.tagsApplyNewValue(1); for(const auto &line : inst.level.linedefs) ASSERT_EQ(line->tag, 0); for(const auto §or : inst.level.sectors) ASSERT_EQ(sector->tag, 0); ASSERT_EQ(inst.tagInMemory, 0); // didn't change // Select a couple of lines inst.edit.Selected->set(1); inst.edit.Selected->set(2); inst.level.checks.tagsApplyNewValue(1); for(const auto &line : inst.level.linedefs) if(line == inst.level.linedefs[1] || line == inst.level.linedefs[2]) ASSERT_EQ(line->tag, 1); else ASSERT_EQ(line->tag, 0); for(const auto §or : inst.level.sectors) ASSERT_EQ(sector->tag, 0); ASSERT_EQ(inst.tagInMemory, 1); // changed // Now select a couple of sectors inst.edit.mode = ObjType::sectors; inst.edit.Selected.emplace(ObjType::sectors); inst.edit.Selected->set(2); inst.edit.Selected->set(4); inst.level.checks.tagsApplyNewValue(2); for(const auto &line : inst.level.linedefs) if(line == inst.level.linedefs[1] || line == inst.level.linedefs[2]) ASSERT_EQ(line->tag, 1); else ASSERT_EQ(line->tag, 0); for(const auto §or : inst.level.sectors) if(sector.get() == inst.level.sectors[2].get() || sector.get() == inst.level.sectors[4].get()) ASSERT_EQ(sector->tag, 2); else ASSERT_EQ(sector->tag, 0); ASSERT_EQ(inst.tagInMemory, 2); // changed inst.edit.Selected->clear(4); inst.level.checks.tagsApplyNewValue(1); for(const auto &line : inst.level.linedefs) if(line == inst.level.linedefs[1] || line == inst.level.linedefs[2]) ASSERT_EQ(line->tag, 1); else ASSERT_EQ(line->tag, 0); for(const auto §or : inst.level.sectors) if(sector.get() == inst.level.sectors[2].get()) ASSERT_EQ(sector->tag, 1); else if(sector == inst.level.sectors[4]) ASSERT_EQ(sector->tag, 2); else ASSERT_EQ(sector->tag, 0); ASSERT_EQ(inst.tagInMemory, 1); // changed again } eureka-editor-eureka-2.0.2/test/e_commands_test.cpp000066400000000000000000000563761464327712600224110ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2023 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Instance.h" #include "LineDef.h" #include "Vertex.h" #include "w_wad.h" #include "gtest/gtest.h" class SelectNeighbor : public ::testing::Test { protected: SelectNeighbor() { inst.edit.Selected.emplace(inst.edit.mode, true); } ~SelectNeighbor() { inst.edit.Selected.reset(); } void addVertex(int x, int y); void addSector(int floorh, int ceilh); void addSide(const SString &upper, const SString &middle, const SString &lower, int sector, int yoffset = 0); void addLine(int v1, int v2, int s1, int s2); Instance inst; Document &doc = inst.level; }; void SelectNeighbor::addVertex(int x, int y) { Vertex *vertex = new Vertex; vertex->SetRawXY(MapFormat::doom, v2double_t{ (double)x, (double)y }); doc.vertices.emplace_back(vertex); } void SelectNeighbor::addSector(int floorh, int ceilh) { Sector *sector = new Sector; sector->floorh = floorh; sector->ceilh = ceilh; sector->floor_tex = BA_InternaliseString("FLOOR"); sector->ceil_tex = BA_InternaliseString("CEIL"); sector->light = 160; sector->type = sector->tag = 0; doc.sectors.emplace_back(sector); } void SelectNeighbor::addSide(const SString &upper, const SString &middle, const SString &lower, int sector, int yoffset) { SideDef *side = new SideDef{}; side->upper_tex = BA_InternaliseString(upper); side->mid_tex = BA_InternaliseString(middle); side->lower_tex = BA_InternaliseString(lower); side->sector = sector; side->y_offset = yoffset; doc.sidedefs.emplace_back(side); } void SelectNeighbor::addLine(int v1, int v2, int s1, int s2) { LineDef *line = new LineDef{}; line->start = v1; line->end = v2; line->right = s1; line->left = s2; doc.linedefs.emplace_back(line); } class SelectNeighborTexture : public SelectNeighbor { protected: void SetUp() override; }; void SelectNeighborTexture::SetUp() { // Use case: highlight a wall and see selection spread to: // - other walls // - upper and lower textures /* Wall aspect *---*---*---* | | | *---* |L0 L1 |L2 | *---* | | *---*---*---* Highlight L1, expect to select L0 and L2 due to same texture being shown Top view vertices and sectors * / \ *---*---*---* | | | *---* | | |mid| | | *---* | | \._| *-----------* */ addVertex(0, 0); addVertex(64, 0); addVertex(128, 0); addVertex(192, 0); addVertex(0, -192); // bottom vertices addVertex(192, -192); // bottom vertices addVertex(160, 32); // top V // Middle cage addVertex(64, -64); addVertex(128, -64); addVertex(128, -128); addVertex(64, -128); addSector(0, 128); addSector(32, 96); addSide("-", "WALL", "-", 0); addSide("-", "WALL", "-", 0); addSide("WALL", "-", "WALL", 0); // bottom walls addSide("-", "OTHER", "-", 0); addSide("-", "OTHER", "-", 0); addSide("-", "OTHER", "-", 0); // top walls (differently textured) addSide("-", "-", "-", 1); addSide("-", "NICHE", "-", 1); addSide("-", "NICHE", "-", 1); // middle cage: all are same textured, except for one to show which get picked addSide("-", "CAGE", "-", 0); addSide("-", "CAGE2", "-", 0); addSide("-", "CAGE", "-", 0); addSide("-", "CAGE", "-", 0); addSide("-", "CAGE", "-", 0); addSide("-", "CAGE", "-", 0); addSide("-", "CAGE", "-", 0); addSide("-", "CAGE", "-", 0); // Bottom right beam (midtexture though) addSide("-", "OTHER", "-", 0); addSide("-", "-", "-", 0); addLine(0, 1, 0, -1); addLine(1, 2, 1, -1); addLine(2, 3, 2, 6); addLine(3, 5, 3, -1); addLine(5, 4, 4, -1); addLine(4, 0, 5, -1); addLine(2, 6, 7, -1); addLine(6, 3, 8, -1); // Cage (8-11) addLine(7, 8, 9, 10); // ----> (top) addLine(9, 8, 11, 12); // up (right) addLine(9, 10, 13, 14); // <---- (bottom) addLine(7, 10, 15, 16); // down (left) // Bottom right beam (midtexture) addLine(5, 9, 18, 17); } TEST_F(SelectNeighborTexture, SelectFromMidWall) { inst.EXEC_Param[0] = "texture"; inst.edit.mode = ObjType::linedefs; inst.edit.highlight.num = 1; inst.edit.highlight.parts = PART_RT_LOWER; inst.CMD_SelectNeighbors(); ASSERT_EQ(inst.edit.Selected->count_obj(), 3); ASSERT_EQ(inst.edit.Selected->get_ext(0), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(1), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(2), PART_RT_LOWER | PART_RT_UPPER); } TEST_F(SelectNeighborTexture, SelectFromBottomThenAddThenClearAll) { inst.EXEC_Param[0] = "texture"; inst.edit.mode = ObjType::linedefs; inst.edit.highlight.num = 2; inst.edit.highlight.parts = PART_RT_LOWER; inst.CMD_SelectNeighbors(); ASSERT_EQ(inst.edit.Selected->count_obj(), 3); ASSERT_EQ(inst.edit.Selected->get_ext(0), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(1), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(2), PART_RT_LOWER | PART_RT_UPPER); // Now select the two textures from north to show they get added inst.edit.highlight.num = 7; inst.edit.highlight.parts = PART_RT_LOWER; inst.CMD_SelectNeighbors(); ASSERT_EQ(inst.edit.Selected->count_obj(), 5); ASSERT_EQ(inst.edit.Selected->get_ext(0), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(1), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(2), PART_RT_LOWER | PART_RT_UPPER); ASSERT_EQ(inst.edit.Selected->get_ext(6), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(7), PART_RT_LOWER); // Now manually select a bottom one inst.edit.Selected->set_ext(4, PART_RT_LOWER); // And apply the command on it inst.edit.highlight.num = 4; inst.edit.highlight.parts = PART_RT_LOWER; inst.CMD_SelectNeighbors(); ASSERT_TRUE(inst.edit.Selected->empty()); } TEST_F(SelectNeighborTexture, SelectCage) { // Select interior inst.EXEC_Param[0] = "texture"; inst.edit.mode = ObjType::linedefs; inst.edit.highlight.num = 8; inst.edit.highlight.parts = PART_RT_RAIL; inst.CMD_SelectNeighbors(); ASSERT_EQ(inst.edit.Selected->count_obj(), 4); ASSERT_EQ(inst.edit.Selected->get_ext(8), PART_RT_RAIL); ASSERT_EQ(inst.edit.Selected->get_ext(9), PART_LF_RAIL); ASSERT_EQ(inst.edit.Selected->get_ext(10), PART_RT_RAIL); ASSERT_EQ(inst.edit.Selected->get_ext(11), PART_LF_RAIL); // Now select exterior inst.edit.highlight.num = 9; inst.edit.highlight.parts = PART_RT_RAIL; inst.CMD_SelectNeighbors(); ASSERT_EQ(inst.edit.Selected->count_obj(), 4); ASSERT_EQ(inst.edit.Selected->get_ext(8), PART_RT_RAIL); ASSERT_EQ(inst.edit.Selected->get_ext(9), PART_LF_RAIL | PART_RT_RAIL); ASSERT_EQ(inst.edit.Selected->get_ext(10), PART_RT_RAIL | PART_LF_RAIL); ASSERT_EQ(inst.edit.Selected->get_ext(11), PART_LF_RAIL | PART_RT_RAIL); } TEST_F(SelectNeighborTexture, WallsDoNotPropagateToRails) { inst.EXEC_Param[0] = "texture"; inst.edit.mode = ObjType::linedefs; inst.edit.highlight.num = 3; inst.edit.highlight.parts = PART_RT_LOWER; inst.CMD_SelectNeighbors(); ASSERT_EQ(inst.edit.Selected->count_obj(), 3); ASSERT_EQ(inst.edit.Selected->get_ext(3), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(4), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(5), PART_RT_LOWER); } TEST_F(SelectNeighborTexture, RailsDoNotPropagateToWalls) { inst.EXEC_Param[0] = "texture"; inst.edit.mode = ObjType::linedefs; inst.edit.highlight.num = 12; inst.edit.highlight.parts = PART_LF_RAIL; inst.CMD_SelectNeighbors(); ASSERT_EQ(inst.edit.Selected->count_obj(), 1); ASSERT_EQ(inst.edit.Selected->get_ext(12), PART_LF_RAIL); } /* Same height selection Alcoves: open door, shut door, shut lift, shut mid, open all x---x x---x---x x---x x---x |OD | |SD vSL | |SM | |OA | x---x-->x---x<--x-->x---x<--x---x-->x---x | | | x<------x------>x<------x | | ^ step ^ st+he v head v | | x<--x-->x<------x-->x-->x | | v s+^ ^ h+v | | x<--x x-->x | | | x---------------------------------------x */ // What to consider: taller textures will check opening size // shorter textures will check their equality and position // need to combine them class SelectNeighborHeight : public SelectNeighbor { protected: void SetUp() override; }; void SelectNeighborHeight::SetUp() { addVertex(0, 0); // 0 addVertex(640, 0); addVertex(128, 64); // 2 addVertex(192, 64); addVertex(448, 64); addVertex(512, 64); addVertex(128, 128); // 6 addVertex(192, 128); addVertex(256, 128); addVertex(384, 128); addVertex(448, 128); addVertex(512, 128); addVertex(128, 192); // 12 addVertex(256, 192); addVertex(384, 192); addVertex(512, 192); addVertex(0, 256); // 16 addVertex(64, 256); addVertex(128, 256); addVertex(192, 256); addVertex(256, 256); addVertex(320, 256); addVertex(384, 256); addVertex(448, 256); addVertex(512, 256); addVertex(576, 256); addVertex(640, 256); addVertex(64, 320); // 27 addVertex(128, 320); addVertex(192, 320); addVertex(256, 320); addVertex(320, 320); addVertex(384, 320); addVertex(448, 320); addVertex(512, 320); addVertex(576, 320); // 36 addSector(0, 128); // 0 addSector(16, 128); // 1 addSector(0, 112); addSector(8, 128); // 3 addSector(8, 120); addSector(0, 120); addSector(0, 48); // 6 addSector(0, 0); addSector(128, 128); addSector(48, 48); addSector(0, 128); // 11 addSide("-", "wall", "-", 0); // 0 addSide("-", "wall", "-", 0); // 1 addSide("-", "wall", "-", 0); addSide("-", "-", "-", 1); // 3 addSide("-", "-", "step", 0); addSide("top", "-", "-", 0); addSide("-", "-", "-", 2); addSide("-", "-", "step", 0); // 7 addSide("-", "-", "-", 1); addSide("-", "-", "step", 0); addSide("-", "-", "-", 1); addSide("-", "-", "-", 2); addSide("top", "-", "-", 0); addSide("-", "-", "-", 2); addSide("top", "-", "-", 0); addSide("-", "-", "step", 3); // 15 addSide("-", "-", "-", 1); addSide("-", "-", "step", 0); addSide("-", "-", "-", 3); addSide("-", "-", "-", 4); addSide("top", "-", "step", 0); addSide("top", "-", "-", 0); addSide("-", "-", "-", 5); addSide("-", "-", "-", 2); addSide("top", "-", "-", 5); addSide("-", "-", "-", 3); // 25 addSide("-", "-", "step", 0); addSide("-", "-", "-", 4); addSide("top", "-", "-", 3); addSide("-", "-", "-", 4); addSide("-", "-", "step", 5); addSide("-", "-", "-", 5); addSide("top", "-", "-", 0); addSide("-", "-", "step", 0); // 33 addSide("-", "-", "-", 3); addSide("-", "-", "-", 4); addSide("top", "-", "step", 0); addSide("top", "-", "-", 0); addSide("-", "-", "-", 5); addSide("-", "wall", "-", 0); // 39 addSide("door", "-", "-", 0); addSide("-", "-", "-", 6); addSide("-", "wall", "-", 0); addSide("-", "-", "-", 7); addSide("door", "-", "-", 0); addSide("-", "-", "lift", 0); addSide("-", "-", "-", 8); addSide("-", "wall", "-", 0); addSide("-", "-", "-", 9); addSide("door", "-", "lift", 0); addSide("-", "wall", "-", 0); addSide("door", "-", "lift", 0); addSide("-", "-", "-", 10); addSide("-", "wall", "-", 0); addSide("-", "wall", "-", 6); // 54 addSide("-", "wall", "-", 6); addSide("-", "wall", "-", 7); addSide("-", "-", "low", 7); addSide("high", "-", "-", 8); addSide("-", "wall", "-", 8); addSide("-", "wall", "-", 9); addSide("-", "wall", "-", 9); addSide("-", "wall", "-", 10); addSide("-", "wall", "-", 10); addSide("-", "wall", "-", 6); // 64 addSide("-", "wall", "-", 7); addSide("-", "wall", "-", 8); addSide("-", "wall", "-", 9); addSide("-", "wall", "-", 10); // 69 addLine(1, 0, 0, -1); // 0 addLine(0, 16, 1, -1); // 1 addLine(26, 1, 2, -1); addLine(3, 2, 3, 4); // 3 addLine(4, 5, 5, 6); addLine(6, 2, 7, 8); // 5 addLine(3, 7, 9, 10); addLine(4, 10, 11, 12); addLine(11, 5, 13, 14); addLine(7, 6, 15, 16); // 9 addLine(7, 8, 17, 18); addLine(9, 8, 19, 20); addLine(9, 10, 21, 22); addLine(10, 11, 23, 24); addLine(6, 12, 25, 26); // 14 addLine(8, 13, 27, 28); addLine(14, 9, 29, 30); addLine(15, 11, 31, 32); addLine(13, 12, 33, 34), // 18 addLine(13, 14, 35, 36), addLine(15, 14, 37, 38), addLine(16, 17, 39, -1); // 21 addLine(17, 18, 40, 41); addLine(18, 19, 42, -1); addLine(20, 19, 43, 44); addLine(20, 21, 45, 46); addLine(21, 22, 47, -1); addLine(23, 22, 48, 49); addLine(23, 24, 50, -1); addLine(24, 25, 51, 52); addLine(25, 26, 53, -1); addLine(17, 27, 54, -1); // 31 addLine(28, 18, 55, -1); addLine(19, 29, 56, -1); addLine(30, 20, 57, 58); addLine(31, 21, 59, -1); addLine(22, 32, 60, -1); addLine(33, 23, 61, -1); addLine(24, 34, 62, -1); addLine(35, 25, 63, -1); addLine(27, 28, 64, -1); // 40 addLine(29, 30, 65, -1); addLine(30, 31, 66, -1); addLine(32, 33, 67, -1); addLine(34, 35, 68, -1); // 45 } TEST_F(SelectNeighborHeight, WallGetsClosedDoorsButNotMids) { inst.EXEC_Param[0] = "height"; inst.edit.mode = ObjType::linedefs; inst.edit.highlight.num = 23; inst.edit.highlight.parts = PART_RT_LOWER; inst.CMD_SelectNeighbors(); ASSERT_EQ(inst.edit.Selected->count_obj(), 4); ASSERT_EQ(inst.edit.Selected->get_ext(23), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(24), PART_LF_UPPER); ASSERT_EQ(inst.edit.Selected->get_ext(25), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(26), PART_RT_LOWER); } TEST_F(SelectNeighborHeight, WallGoesAcrossSectorsThenAddAnotherThenClear) { inst.EXEC_Param[0] = "height"; inst.edit.mode = ObjType::linedefs; inst.edit.highlight.num = 0; inst.edit.highlight.parts = PART_RT_LOWER; inst.CMD_SelectNeighbors(); ASSERT_EQ(inst.edit.Selected->count_obj(), 9); ASSERT_EQ(inst.edit.Selected->get_ext(0), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(1), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(2), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(21), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(28), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(30), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(38), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(39), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(44), PART_RT_LOWER); // Now select the open sector inst.edit.highlight.num = 31; inst.edit.highlight.parts = PART_RT_LOWER; inst.CMD_SelectNeighbors(); ASSERT_EQ(inst.edit.Selected->count_obj(), 12); ASSERT_EQ(inst.edit.Selected->get_ext(31), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(32), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(40), PART_RT_LOWER); // Now apply the same command on a selected line and see how all gets deselected. inst.edit.highlight.num = 30; inst.edit.highlight.parts = PART_RT_LOWER; inst.CMD_SelectNeighbors(); ASSERT_TRUE(inst.edit.Selected->empty()); } TEST_F(SelectNeighborHeight, SelectSteps) { inst.EXEC_Param[0] = "height"; inst.edit.mode = ObjType::linedefs; inst.edit.highlight.num = 14; inst.edit.highlight.parts = PART_LF_LOWER; // Select smaller steps inst.CMD_SelectNeighbors(); ASSERT_EQ(inst.edit.Selected->count_obj(), 6); ASSERT_EQ(inst.edit.Selected->get_ext(10), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(11), PART_LF_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(14), PART_LF_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(16), PART_LF_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(18), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(19), PART_LF_LOWER); // Now select a top inst.edit.highlight.num = 15; inst.edit.highlight.parts = PART_LF_UPPER; inst.CMD_SelectNeighbors(); ASSERT_EQ(inst.edit.Selected->count_obj(), 10); ASSERT_EQ(inst.edit.Selected->get_ext(10), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(11), PART_LF_LOWER | PART_LF_UPPER); ASSERT_EQ(inst.edit.Selected->get_ext(12), PART_RT_UPPER); ASSERT_EQ(inst.edit.Selected->get_ext(14), PART_LF_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(15), PART_LF_UPPER); ASSERT_EQ(inst.edit.Selected->get_ext(16), PART_LF_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(17), PART_LF_UPPER); ASSERT_EQ(inst.edit.Selected->get_ext(18), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(19), PART_LF_LOWER | PART_LF_UPPER); ASSERT_EQ(inst.edit.Selected->get_ext(20), PART_RT_UPPER); // Select an inner top+ inst.edit.highlight.num = 13; inst.edit.highlight.parts = PART_LF_UPPER; inst.CMD_SelectNeighbors(); ASSERT_EQ(inst.edit.Selected->count_obj(), 11); ASSERT_EQ(inst.edit.Selected->get_ext(13), PART_LF_UPPER); // Nothing else // Select an outer step+ inst.edit.highlight.num = 6; inst.edit.highlight.parts = PART_RT_LOWER; inst.CMD_SelectNeighbors(); ASSERT_EQ(inst.edit.Selected->count_obj(), 14); ASSERT_EQ(inst.edit.Selected->get_ext(3), PART_LF_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(5), PART_RT_LOWER); ASSERT_EQ(inst.edit.Selected->get_ext(6), PART_RT_LOWER); } /* Mid-line same-height selection */ static const byte texHeight4[] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x01, 0x03, 0x00, 0x00, 0x00, 0x75, 0x16, 0xC7, 0x79, 0x00, 0x00, 0x00, 0x03, 0x50, 0x4C, 0x54, 0x45, 0x00, 0x00, 0x00, 0xA7, 0x7A, 0x3D, 0xDA, 0x00, 0x00, 0x00, 0x0A, 0x49, 0x44, 0x41, 0x54, 0x78, 0x01, 0x63, 0x80, 0x02, 0x00, 0x00, 0x08, 0x00, 0x01, 0x30, 0x8A, 0x83, 0xD2, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 }; static const byte texHeight6[] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, 0x38, 0xDE, 0x66, 0x72, 0x00, 0x00, 0x00, 0x03, 0x50, 0x4C, 0x54, 0x45, 0x00, 0x00, 0x00, 0xA7, 0x7A, 0x3D, 0xDA, 0x00, 0x00, 0x00, 0x0A, 0x49, 0x44, 0x41, 0x54, 0x78, 0x01, 0x63, 0x40, 0x02, 0x00, 0x00, 0x0C, 0x00, 0x01, 0xFB, 0x9E, 0xB4, 0x85, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 }; static const byte texHeight8[] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x01, 0x03, 0x00, 0x00, 0x00, 0x02, 0xD4, 0x07, 0x02, 0x00, 0x00, 0x00, 0x03, 0x50, 0x4C, 0x54, 0x45, 0x00, 0x00, 0x00, 0xA7, 0x7A, 0x3D, 0xDA, 0x00, 0x00, 0x00, 0x0A, 0x49, 0x44, 0x41, 0x54, 0x78, 0x01, 0x63, 0x40, 0x03, 0x00, 0x00, 0x10, 0x00, 0x01, 0x25, 0xFE, 0x3D, 0x34, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 }; class SelectNeighborMidLines : public SelectNeighbor { protected: void SetUp() override; private: void initTextures(); }; /* 1. Same sector height, different texture heights */ void SelectNeighborMidLines::SetUp() { initTextures(); // Now we have the texes // corners addVertex(0, 0); addVertex(0, 256); addVertex(256, 256); addVertex(256, 0); addSector(0, 128); // walls addSide("-", "WALL", "-", 0); addSide("-", "WALL", "-", 0); addSide("-", "WALL", "-", 0); addSide("-", "WALL", "-", 0); // walls addLine(0, 1, 0, -1); addLine(1, 2, 1, -1); addLine(2, 3, 2, -1); addLine(3, 0, 3, -1); } void SelectNeighborMidLines::initTextures() { auto wad = Wad_file::Open("dummy.wad", WadOpenMode::write); ASSERT_TRUE(wad); wad->AddLump("TX_START"); Lump_c *lump; lump = &wad->AddLump("PIC4"); lump->Write(texHeight4, sizeof(texHeight4)); lump = &wad->AddLump("PIC6"); lump->Write(texHeight6, sizeof(texHeight6)); lump = &wad->AddLump("PIC8"); lump->Write(texHeight8, sizeof(texHeight8)); wad->AddLump("TX_END"); inst.wad.master.setGameWad(wad); inst.conf.features.tx_start = 1; inst.wad.W_LoadTextures(inst.conf); } TEST_F(SelectNeighborMidLines, CheckDifferentTextureHeights) { addVertex(64, 128); addVertex(80, 128); addVertex(96, 128); addVertex(128, 128); addVertex(144, 128); addVertex(160, 128); addVertex(176, 128); addVertex(192, 128); addVertex(208, 128); addVertex(224, 128); addSide("-", "PIC4", "-", 0); addSide("-", "PIC4", "-", 0); addSide("-", "PIC4", "-", 0); addSide("-", "PIC6", "-", 0); addSide("-", "PIC6", "-", 0); addSide("-", "PIC6", "-", 0); addSide("-", "PIC6", "-", 0); addSide("-", "PIC6", "-", 0); addSide("-", "PIC8", "-", 0); addSide("-", "PIC8", "-", 0); addSide("-", "PIC8", "-", 0); addSide("-", "PIC8", "-", 0); addSide("-", "PIC8", "-", 0); addSide("-", "PIC8", "-", 0); addSide("-", "PIC8", "-", 0, 1); addSide("-", "PIC8", "-", 0); addLine(4, 5, 4, 5); addLine(5, 6, 6, 7); addLine(6, 7, 8, 9); addLine(7, 8, 10, 11); addLine(8, 9, 12, 13); addLine(9, 10, 14, 15); addLine(10, 11, 16, 17); addLine(11, 12, 18, 19); inst.EXEC_Param[0] = "height"; inst.edit.mode = ObjType::linedefs; inst.edit.highlight.num = 5; inst.edit.highlight.parts = PART_RT_RAIL; inst.CMD_SelectNeighbors(); ASSERT_EQ(inst.edit.Selected->count_obj(), 2); ASSERT_EQ(inst.edit.Selected->get_ext(4), PART_RT_RAIL); ASSERT_EQ(inst.edit.Selected->get_ext(5), PART_RT_RAIL); inst.edit.highlight.num = 6; inst.edit.highlight.parts = PART_LF_RAIL; inst.CMD_SelectNeighbors(); ASSERT_EQ(inst.edit.Selected->count_obj(), 4); ASSERT_EQ(inst.edit.Selected->get_ext(4), PART_RT_RAIL); ASSERT_EQ(inst.edit.Selected->get_ext(5), PART_RT_RAIL | PART_LF_RAIL); ASSERT_EQ(inst.edit.Selected->get_ext(6), PART_LF_RAIL); ASSERT_EQ(inst.edit.Selected->get_ext(7), PART_LF_RAIL); inst.edit.highlight.num = 8; inst.edit.highlight.parts = PART_RT_RAIL; inst.CMD_SelectNeighbors(); ASSERT_EQ(inst.edit.Selected->count_obj(), 7); ASSERT_EQ(inst.edit.Selected->get_ext(4), PART_RT_RAIL); ASSERT_EQ(inst.edit.Selected->get_ext(5), PART_RT_RAIL | PART_LF_RAIL); ASSERT_EQ(inst.edit.Selected->get_ext(6), PART_LF_RAIL); ASSERT_EQ(inst.edit.Selected->get_ext(7), PART_LF_RAIL); ASSERT_EQ(inst.edit.Selected->get_ext(8), PART_RT_RAIL); ASSERT_EQ(inst.edit.Selected->get_ext(9), PART_RT_RAIL); ASSERT_EQ(inst.edit.Selected->get_ext(10), PART_RT_RAIL); } eureka-editor-eureka-2.0.2/test/e_cutpaste_test.cpp000066400000000000000000000154621464327712600224270ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2024 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "gtest/gtest.h" #include "Instance.h" class ECutPasteFixture : public ::testing::Test { protected: ~ECutPasteFixture() { inst.level.clear(); } void addArea(); void addSecondArea(); Instance inst; }; void ECutPasteFixture::addArea() { Vertex *vertex; vertex = new Vertex; vertex->raw_x = FFixedPoint(0); vertex->raw_y = FFixedPoint(0); inst.level.vertices.push_back(std::shared_ptr(vertex)); vertex = new Vertex; vertex->raw_x = FFixedPoint(0); vertex->raw_y = FFixedPoint(256); inst.level.vertices.push_back(std::shared_ptr(vertex)); vertex = new Vertex; vertex->raw_x = FFixedPoint(256); vertex->raw_y = FFixedPoint(256); inst.level.vertices.push_back(std::shared_ptr(vertex)); vertex = new Vertex; vertex->raw_x = FFixedPoint(256); vertex->raw_y = FFixedPoint(0); inst.level.vertices.push_back(std::shared_ptr(vertex)); Sector *sector; sector = new Sector; sector->floorh = 0; sector->ceilh = 128; inst.level.sectors.push_back(std::shared_ptr(sector)); inst.level.sidedefs.push_back(std::shared_ptr(new SideDef)); inst.level.sidedefs.push_back(std::shared_ptr(new SideDef)); inst.level.sidedefs.push_back(std::shared_ptr(new SideDef)); inst.level.sidedefs.push_back(std::shared_ptr(new SideDef)); LineDef *line; line = new LineDef; line->start = 0; line->end = 1; line->right = 0; line->left = -1; inst.level.linedefs.push_back(std::shared_ptr(line)); line = new LineDef; line->start = 1; line->end = 2; line->right = 1; line->left = -1; inst.level.linedefs.push_back(std::shared_ptr(line)); line = new LineDef; line->start = 2; line->end = 3; line->right = 2; line->left = -1; inst.level.linedefs.push_back(std::shared_ptr(line)); line = new LineDef; line->start = 3; line->end = 0; line->right = 3; line->left = -1; inst.level.linedefs.push_back(std::shared_ptr(line)); Thing *thing; thing = new Thing; thing->raw_x = FFixedPoint(192); thing->raw_y = FFixedPoint(128); thing->type = 1; thing->angle = 0; inst.level.things.push_back(std::shared_ptr(thing)); thing = new Thing; thing->raw_x = FFixedPoint(128); thing->raw_y = FFixedPoint(192); thing->type = 2; thing->angle = 90; inst.level.things.push_back(std::shared_ptr(thing)); thing = new Thing; thing->raw_x = FFixedPoint(64); thing->raw_y = FFixedPoint(128); thing->type = 3; thing->angle = 180; inst.level.things.push_back(std::shared_ptr(thing)); thing = new Thing; thing->raw_x = FFixedPoint(128); thing->raw_y = FFixedPoint(64); thing->type = 4; thing->angle = 270; inst.level.things.push_back(std::shared_ptr(thing)); } void ECutPasteFixture::addSecondArea() { Vertex *vertex; vertex = new Vertex; vertex->raw_x = FFixedPoint(320); vertex->raw_y = FFixedPoint(192); inst.level.vertices.push_back(std::shared_ptr(vertex)); vertex = new Vertex; vertex->raw_x = FFixedPoint(320); vertex->raw_y = FFixedPoint(256); inst.level.vertices.push_back(std::shared_ptr(vertex)); vertex = new Vertex; vertex->raw_x = FFixedPoint(384); vertex->raw_y = FFixedPoint(256); inst.level.vertices.push_back(std::shared_ptr(vertex)); vertex = new Vertex; vertex->raw_x = FFixedPoint(384); vertex->raw_y = FFixedPoint(192); inst.level.vertices.push_back(std::shared_ptr(vertex)); Sector *sector; sector = new Sector; sector->floorh = 0; sector->ceilh = 128; inst.level.sectors.push_back(std::shared_ptr(sector)); SideDef *side; side = new SideDef; side->sector = 1; inst.level.sidedefs.push_back(std::shared_ptr(side)); side = new SideDef; side->sector = 1; inst.level.sidedefs.push_back(std::shared_ptr(side)); side = new SideDef; side->sector = 1; inst.level.sidedefs.push_back(std::shared_ptr(side)); side = new SideDef; side->sector = 1; inst.level.sidedefs.push_back(std::shared_ptr(side)); LineDef *line; line = new LineDef; line->start = 4; line->end = 5; line->right = 4; line->left = -1; inst.level.linedefs.push_back(std::shared_ptr(line)); line = new LineDef; line->start = 5; line->end = 6; line->right = 5; line->left = -1; inst.level.linedefs.push_back(std::shared_ptr(line)); line = new LineDef; line->start = 6; line->end = 7; line->right = 6; line->left = -1; inst.level.linedefs.push_back(std::shared_ptr(line)); line = new LineDef; line->start = 7; line->end = 4; line->right = 7; line->left = -1; inst.level.linedefs.push_back(std::shared_ptr(line)); } TEST_F(ECutPasteFixture, DeletingAllPlayersWillNotCrash) { addArea(); inst.edit.Selected = selection_c(); // things inst.edit.Selected->set(0); inst.edit.Selected->set(1); inst.edit.Selected->set(2); inst.edit.Selected->set(3); inst.CMD_Delete(); ASSERT_TRUE(inst.level.things.empty()); } TEST_F(ECutPasteFixture, DeletingAllLinesFromAnotherSectorWillNotCrash) { addArea(); addSecondArea(); ASSERT_EQ(inst.level.linedefs.size(), 8); ASSERT_EQ(inst.level.vertices.size(), 8); ASSERT_EQ(inst.level.sidedefs.size(), 8); ASSERT_EQ(inst.level.sectors.size(), 2); ASSERT_EQ(inst.level.things.size(), 4); inst.edit.mode = ObjType::linedefs; inst.edit.Selected = selection_c(ObjType::linedefs); inst.edit.Selected->set(4); inst.edit.Selected->set(5); inst.edit.Selected->set(6); inst.edit.Selected->set(7); inst.CMD_Delete(); ASSERT_EQ(inst.level.linedefs.size(), 4); ASSERT_EQ(inst.level.vertices.size(), 4); ASSERT_EQ(inst.level.sidedefs.size(), 4); ASSERT_EQ(inst.level.sectors.size(), 1); ASSERT_EQ(inst.level.things.size(), 4); } TEST_F(ECutPasteFixture, DeletingAllLinesWillNotCrash) { addArea(); inst.edit.mode = ObjType::linedefs; inst.edit.Selected = selection_c(ObjType::linedefs); inst.edit.Selected->set(0); inst.edit.Selected->set(1); inst.edit.Selected->set(2); inst.edit.Selected->set(3); inst.CMD_Delete(); ASSERT_TRUE(inst.level.linedefs.empty()); ASSERT_TRUE(inst.level.vertices.empty()); ASSERT_TRUE(inst.level.sidedefs.empty()); ASSERT_TRUE(inst.level.sectors.empty()); ASSERT_TRUE(inst.level.things.empty()); } eureka-editor-eureka-2.0.2/test/e_linedef_test.cpp000066400000000000000000000026551464327712600222050ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2024 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "e_linedef.h" #include "Instance.h" #include "gtest/gtest.h" TEST(ELinedef, MoveCoordOntoLinedef) { Instance inst; Vertex* vertex; vertex = new Vertex; vertex->raw_x = FFixedPoint(0); vertex->raw_y = FFixedPoint(0); inst.level.vertices.push_back(std::shared_ptr(vertex)); vertex = new Vertex; vertex->raw_x = FFixedPoint(64); vertex->raw_y = FFixedPoint(64); inst.level.vertices.push_back(std::shared_ptr(vertex)); inst.level.linedefs.push_back(std::make_shared()); auto& L = inst.level.linedefs.back(); L->start = 0; L->end = 1; v2double_t v = { 32, 16 }; linemod::moveCoordOntoLinedef(inst.level, 0, v); ASSERT_DOUBLE_EQ(v.x, 24.0); ASSERT_DOUBLE_EQ(v.y, 24.0); }eureka-editor-eureka-2.0.2/test/e_objects_test.cpp000066400000000000000000000525111464327712600222240ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "e_objects.h" #include "Document.h" #include "Instance.h" #include "LineDef.h" #include "Vertex.h" #include "w_rawdef.h" #include "gtest/gtest.h" class EObjectsFixture : public ::testing::Test { protected: ~EObjectsFixture() { inst.level.clear(); } Instance inst; }; // Helpful vertex comparator so we sort our data static bool vertexCompare(const Vertex *v1, const Vertex *v2) { return v1->raw_x == v2->raw_x ? v1->raw_y < v2->raw_y : v1->raw_x < v2->raw_x; }; /* To test: - that we invalidate the selection if the number of selected objects is changeed - various merge scenarios */ // // ._. // We test a ._| |_. dragging of the top line to go to the level of the mid lines // |_____| // We need: // - 6 vertices // - 1 sector // - 5 sides // - 5 lines // TEST_F(EObjectsFixture, DragWallLineToCancelSurroundingLines) { // Each line shall be 64 units long static const FFixedPoint vertexCoordinates[8][2] = { { FFixedPoint(-64), FFixedPoint(0) }, { FFixedPoint(0), FFixedPoint(0) }, { FFixedPoint(0), FFixedPoint(64) }, { FFixedPoint(64), FFixedPoint(64) }, { FFixedPoint(64), FFixedPoint(0) }, { FFixedPoint(128), FFixedPoint(0) }, { FFixedPoint(128), FFixedPoint(-64) }, { FFixedPoint(-64), FFixedPoint(-64) }, }; Document &doc = inst.level; for(size_t i = 0; i < 8; ++i) { auto vertex = std::make_unique(); vertex->raw_x = vertexCoordinates[i][0]; vertex->raw_y = vertexCoordinates[i][1]; doc.vertices.push_back(std::move(vertex)); } auto sector = std::make_shared(); doc.sectors.push_back(std::move(sector)); for(int i = 0; i < 8; ++i) { auto side = std::make_shared(); side->sector = 0; doc.sidedefs.push_back(std::move(side)); auto line = std::make_shared(); line->start = i; line->end = (i + 1) % 8; line->right = i; doc.linedefs.push_back(std::move(line)); } // _ // Now do the move ._| |_. --> ._._._. // |_____| |_____| selection_c selection(ObjType::linedefs); selection.set(2); v3double_t delta = {0, -64, 0}; doc.objects.move(selection, delta); // Now check we have a clear situation ASSERT_EQ(doc.numVertices(), 6); ASSERT_EQ(doc.numSectors(), 1); // still one ASSERT_EQ(doc.numSidedefs(), 6); ASSERT_EQ(doc.numLinedefs(), 6); // Now we must check the coordinates. We do NOT care about order std::vector vertices; for(const std::shared_ptr &vertex : doc.vertices) vertices.push_back(vertex.get()); std::sort(vertices.begin(), vertices.end(), vertexCompare); ASSERT_EQ(vertices[0]->xy(), v2double_t(-64, -64)); ASSERT_EQ(vertices[1]->xy(), v2double_t(-64, 0)); ASSERT_EQ(vertices[2]->xy(), v2double_t(0, 0)); ASSERT_EQ(vertices[3]->xy(), v2double_t(64, 0)); ASSERT_EQ(vertices[4]->xy(), v2double_t(128, -64)); ASSERT_EQ(vertices[5]->xy(), v2double_t(128, 0)); std::vector lines; for(const std::shared_ptr &line : doc.linedefs) lines.push_back(line.get()); std::sort(lines.begin(), lines.end(), [&doc](const LineDef *L1, const LineDef *L2){ return vertexCompare(doc.vertices[L1->start].get(), doc.vertices[L2->start].get()); }); ASSERT_EQ(doc.getStart(*lines[0]).xy(), v2double_t(-64, -64)); ASSERT_EQ(doc.getEnd(*lines[0]).xy(), v2double_t(-64, 0)); ASSERT_EQ(doc.getStart(*lines[1]).xy(), v2double_t(-64, 0)); ASSERT_EQ(doc.getEnd(*lines[1]).xy(), v2double_t(0, 0)); ASSERT_EQ(doc.getStart(*lines[2]).xy(), v2double_t(0, 0)); ASSERT_EQ(doc.getEnd(*lines[2]).xy(), v2double_t(64, 0)); ASSERT_EQ(doc.getStart(*lines[3]).xy(), v2double_t(64, 0)); ASSERT_EQ(doc.getEnd(*lines[3]).xy(), v2double_t(128, 0)); ASSERT_EQ(doc.getStart(*lines[4]).xy(), v2double_t(128, -64)); ASSERT_EQ(doc.getEnd(*lines[4]).xy(), v2double_t(-64, -64)); ASSERT_EQ(doc.getStart(*lines[5]).xy(), v2double_t(128, 0)); ASSERT_EQ(doc.getEnd(*lines[5]).xy(), v2double_t(128, -64)); std::sort(lines.begin(), lines.end(), [](const LineDef *L1, const LineDef *L2) { return L1->right < L2->right; }); for(int i = 0; i < 6; ++i) ASSERT_EQ(lines[i]->right, i); } // ._. ._. // Performs a dragging of |_|_|_| into ._._._. eliminating sectors. The target lines have opposite // orientations. |_____| |_____| // TEST_F(EObjectsFixture, DragLineToEliminateSector) { static const FFixedPoint vertexCoordinates[10][2] = { { FFixedPoint(-64), FFixedPoint(0) }, { FFixedPoint(-64), FFixedPoint(64) }, { FFixedPoint(0), FFixedPoint(64) }, { FFixedPoint(0), FFixedPoint(0) }, { FFixedPoint(64), FFixedPoint(0) }, { FFixedPoint(64), FFixedPoint(64) }, { FFixedPoint(128), FFixedPoint(64) }, { FFixedPoint(128), FFixedPoint(0) }, { FFixedPoint(128), FFixedPoint(-64) }, { FFixedPoint(-64), FFixedPoint(-64) }, }; Document &doc = inst.level; for(size_t i = 0; i < 10; ++i) { auto vertex = std::make_unique(); vertex->raw_x = vertexCoordinates[i][0]; vertex->raw_y = vertexCoordinates[i][1]; doc.vertices.push_back(std::move(vertex)); } auto topLeftSector = std::make_shared(); topLeftSector->floor_tex = BA_InternaliseString("FTOPLEFT"); auto topRightSector = std::make_shared(); topRightSector->floor_tex = BA_InternaliseString("FTOPRITE"); auto bottomSector = std::make_shared(); bottomSector->floor_tex = BA_InternaliseString("FBOTTOM"); doc.sectors.push_back(std::move(bottomSector)); doc.sectors.push_back(std::move(topLeftSector)); doc.sectors.push_back(std::move(topRightSector)); std::shared_ptr side; // bottom room for(int i = 0; i < 6; ++i) { side = std::make_shared(); side->sector = 0; if(i != 0 && i != 2) // do not texture mid sides side->mid_tex = BA_InternaliseString("BOTTOM"); else side->mid_tex = BA_InternaliseString("-"); doc.sidedefs.push_back(std::move(side)); } // top-left room for(int i = 0; i < 4; ++i) { side = std::make_shared(); side->sector = 1; if(i != 3) // do not texture mid sides side->mid_tex = BA_InternaliseString("TOPLEFT"); else side->mid_tex = BA_InternaliseString("-"); doc.sidedefs.push_back(std::move(side)); } // top-right room for(int i = 0; i < 4; ++i) { side = std::make_shared(); side->sector = 2; if(i != 3) // do not texture mid sides side->mid_tex = BA_InternaliseString("TOPRIGHT"); else side->mid_tex = BA_InternaliseString("-"); doc.sidedefs.push_back(std::move(side)); } // Too many lines to concern about, so just create them here std::vector> &lines = doc.linedefs; for(int i = 0; i < 12; ++i) { lines.push_back(std::make_unique()); } for(int i = 0; i < 10; ++i) { lines[i]->start = i; lines[i]->end = (i + 1) % 10; lines[i]->flags = MLF_Blocking; } // Left bridge pointing right lines[10]->start = 0; lines[10]->end = 3; lines[10]->flags = MLF_TwoSided; // Right bridge pointing left lines[11]->start = 7; lines[11]->end = 4; lines[11]->flags = MLF_TwoSided; // Bottom room lines[10]->right = 0; lines[3]->right = 1; lines[11]->left = 2; lines[7]->right = 3; lines[8]->right = 4; lines[9]->right = 5; // top left room lines[0]->right = 6; lines[1]->right = 7; lines[2]->right = 8; lines[10]->left = 9; // top right room lines[4]->right = 10; lines[5]->right = 11; lines[6]->right = 12; lines[11]->right = 13; // Need to check both kinds of merge now // ._. ._. ._. // Now do the move |_|_|_| --> ._._|_| // |_____| |_____| selection_c selection(ObjType::linedefs); selection.set(1); v3double_t delta = {0, -64, 0}; doc.objects.move(selection, delta); ASSERT_EQ(doc.numVertices(), 8); ASSERT_EQ(doc.numSidedefs(), 10); ASSERT_EQ(doc.numLinedefs(), 9); ASSERT_EQ(doc.numSectors(), 2); std::vector vertices; for(const std::shared_ptr &vertex : doc.vertices) vertices.push_back(vertex.get()); std::sort(vertices.begin(), vertices.end(), vertexCompare); ASSERT_EQ(vertices[0]->xy(), v2double_t(-64, -64)); ASSERT_EQ(vertices[1]->xy(), v2double_t(-64, 0)); ASSERT_EQ(vertices[2]->xy(), v2double_t(0, 0)); ASSERT_EQ(vertices[3]->xy(), v2double_t(64, 0)); ASSERT_EQ(vertices[4]->xy(), v2double_t(64, 64)); ASSERT_EQ(vertices[5]->xy(), v2double_t(128, -64)); ASSERT_EQ(vertices[6]->xy(), v2double_t(128, 0)); ASSERT_EQ(vertices[7]->xy(), v2double_t(128, 64)); std::vector vlines; for(const std::shared_ptr &line : doc.linedefs) vlines.push_back(line.get()); std::sort(vlines.begin(), vlines.end(), [&doc](const LineDef *L1, const LineDef *L2){ return doc.vertices[L1->start]->xy() == doc.vertices[L2->start]->xy() ? vertexCompare(doc.vertices[L1->end].get(), doc.vertices[L2->end].get()) : vertexCompare(doc.vertices[L1->start].get(), doc.vertices[L2->start].get()); }); ASSERT_EQ(doc.getStart(*vlines[0]).xy(), v2double_t(-64, -64)); ASSERT_EQ(doc.getEnd(*vlines[0]).xy(), v2double_t(-64, 0)); ASSERT_EQ(doc.getRight(*vlines[0])->MidTex(), "BOTTOM"); ASSERT_EQ(doc.getSector(*doc.getRight(*vlines[0])).FloorTex(), "FBOTTOM"); ASSERT_FALSE(doc.getLeft(*vlines[0])); ASSERT_EQ(vlines[0]->flags, MLF_Blocking); ASSERT_EQ(doc.getStart(*vlines[1]).xy(), v2double_t(-64, 0)); ASSERT_EQ(doc.getEnd(*vlines[1]).xy(), v2double_t(0, 0)); ASSERT_EQ(doc.getRight(*vlines[1])->MidTex(), "TOPLEFT"); // texture copied ASSERT_EQ(doc.getSector(*doc.getRight(*vlines[1])).FloorTex(), "FBOTTOM"); ASSERT_FALSE(doc.getLeft(*vlines[1])); ASSERT_EQ(vlines[1]->flags, MLF_Blocking); ASSERT_EQ(doc.getStart(*vlines[2]).xy(), v2double_t(0, 0)); ASSERT_EQ(doc.getEnd(*vlines[2]).xy(), v2double_t(64, 0)); ASSERT_EQ(doc.getRight(*vlines[2])->MidTex(), "BOTTOM"); ASSERT_EQ(doc.getSector(*doc.getRight(*vlines[2])).FloorTex(), "FBOTTOM"); ASSERT_FALSE(doc.getLeft(*vlines[2])); ASSERT_EQ(vlines[2]->flags, MLF_Blocking); ASSERT_EQ(doc.getStart(*vlines[3]).xy(), v2double_t(64, 0)); ASSERT_EQ(doc.getEnd(*vlines[3]).xy(), v2double_t(64, 64)); ASSERT_EQ(doc.getRight(*vlines[3])->MidTex(), "TOPRIGHT"); ASSERT_EQ(doc.getSector(*doc.getRight(*vlines[3])).FloorTex(), "FTOPRITE"); ASSERT_FALSE(doc.getLeft(*vlines[3])); ASSERT_EQ(vlines[3]->flags, MLF_Blocking); ASSERT_EQ(doc.getStart(*vlines[4]).xy(), v2double_t(64, 64)); ASSERT_EQ(doc.getEnd(*vlines[4]).xy(), v2double_t(128, 64)); ASSERT_EQ(doc.getRight(*vlines[4])->MidTex(), "TOPRIGHT"); ASSERT_EQ(doc.getSector(*doc.getRight(*vlines[4])).FloorTex(), "FTOPRITE"); ASSERT_FALSE(doc.getLeft(*vlines[4])); ASSERT_EQ(vlines[4]->flags, MLF_Blocking); // TODO ASSERT_EQ(doc.getStart(*vlines[5]).xy(), v2double_t(128, -64)); ASSERT_EQ(doc.getEnd(*vlines[5]).xy(), v2double_t(-64, -64)); ASSERT_EQ(doc.getRight(*vlines[5])->MidTex(), "BOTTOM"); ASSERT_EQ(doc.getSector(*doc.getRight(*vlines[5])).FloorTex(), "FBOTTOM"); ASSERT_FALSE(doc.getLeft(*vlines[5])); ASSERT_EQ(vlines[5]->flags, MLF_Blocking); ASSERT_EQ(doc.getStart(*vlines[6]).xy(), v2double_t(128, 0)); ASSERT_EQ(doc.getEnd(*vlines[6]).xy(), v2double_t(64, 0)); ASSERT_EQ(doc.getRight(*vlines[6])->MidTex(), "-"); ASSERT_EQ(doc.getSector(*doc.getRight(*vlines[6])).FloorTex(), "FTOPRITE"); ASSERT_EQ(doc.getLeft(*vlines[6])->MidTex(), "-"); ASSERT_EQ(doc.getSector(*doc.getLeft(*vlines[6])).FloorTex(), "FBOTTOM"); ASSERT_EQ(vlines[6]->flags, MLF_TwoSided); ASSERT_EQ(doc.getStart(*vlines[7]).xy(), v2double_t(128, 0)); ASSERT_EQ(doc.getEnd(*vlines[7]).xy(), v2double_t(128, -64)); ASSERT_EQ(doc.getRight(*vlines[7])->MidTex(), "BOTTOM"); ASSERT_EQ(doc.getSector(*doc.getRight(*vlines[7])).FloorTex(), "FBOTTOM"); ASSERT_FALSE(doc.getLeft(*vlines[7])); ASSERT_EQ(vlines[7]->flags, MLF_Blocking); ASSERT_EQ(doc.getStart(*vlines[8]).xy(), v2double_t(128, 64)); ASSERT_EQ(doc.getEnd(*vlines[8]).xy(), v2double_t(128, 0)); ASSERT_EQ(doc.getRight(*vlines[8])->MidTex(), "TOPRIGHT"); ASSERT_EQ(doc.getSector(*doc.getRight(*vlines[8])).FloorTex(), "FTOPRITE"); ASSERT_FALSE(doc.getLeft(*vlines[8])); ASSERT_EQ(vlines[8]->flags, MLF_Blocking); // ._. // Now do the move ._._|_| --> ._._._. // |_____| |_____| selection.clear_all(); // Find the line to move int lineIndex = 0; for(; lineIndex < doc.numLinedefs(); ++lineIndex) { if(doc.getStart(*doc.linedefs[lineIndex]).xy() == v2double_t{64, 64}) break; } ASSERT_LT(lineIndex, doc.numLinedefs()); selection.set(lineIndex); // same delta doc.objects.move(selection, delta); ASSERT_EQ(doc.numVertices(), 6); ASSERT_EQ(doc.numSidedefs(), 6); ASSERT_EQ(doc.numLinedefs(), 6); ASSERT_EQ(doc.numSectors(), 1); // Now find the line to check for(lineIndex = 0; lineIndex < doc.numLinedefs(); ++lineIndex) { const std::shared_ptr &line = doc.linedefs[lineIndex]; if(doc.getStart(*line).xy() == v2double_t{64, 0} && doc.getEnd(*line).xy() == v2double_t{128, 0}) { ASSERT_EQ(doc.getRight(*line)->MidTex(), "TOPRIGHT"); ASSERT_EQ(doc.getSector(*doc.getRight(*line)).FloorTex(), "FBOTTOM"); ASSERT_FALSE(doc.getLeft(*line)); ASSERT_EQ(line->flags, MLF_Blocking); break; } } ASSERT_LT(lineIndex, doc.numLinedefs()); // Now undo. doc.basis.undo(); doc.basis.undo(); // Now merge in reverse! The mid linedef towards the top sectors // ._. ._. ._. ._. // Now do the move |_|_|_| --> | \|_| // |_____| |_____| selection.clear_all(); selection.set(10); delta.y = 64; doc.objects.move(selection, delta); ASSERT_EQ(doc.numVertices(), 8); ASSERT_EQ(doc.numLinedefs(), 9); ASSERT_EQ(doc.numSidedefs(), 10); ASSERT_EQ(doc.numSectors(), 2); // Now find the line to check int checks = 0; for(const std::shared_ptr &line : doc.linedefs) { if(doc.getStart(*line).xy() == v2double_t{-64, -64} && doc.getEnd(*line).xy() == v2double_t{-64, 64}) { ++checks; ASSERT_EQ(doc.getRight(*line)->MidTex(), "BOTTOM"); ASSERT_EQ(doc.getSector(*doc.getRight(*line)).FloorTex(), "FBOTTOM"); ASSERT_FALSE(doc.getLeft(*line)); ASSERT_EQ(line->flags, MLF_Blocking); } else if(doc.getStart(*line).xy() == v2double_t{-64, 64} && doc.getEnd(*line).xy() == v2double_t{0, 64}) { ++checks; ASSERT_EQ(doc.getRight(*line)->MidTex(), "TOPLEFT"); ASSERT_EQ(doc.getSector(*doc.getRight(*line)).FloorTex(), "FBOTTOM"); ASSERT_FALSE(doc.getLeft(*line)); ASSERT_EQ(line->flags, MLF_Blocking); } else if(doc.getStart(*line).xy() == v2double_t{0, 64} && doc.getEnd(*line).xy() == v2double_t{64, 0}) { ++checks; ASSERT_EQ(doc.getRight(*line)->MidTex(), "BOTTOM"); ASSERT_EQ(doc.getSector(*doc.getRight(*line)).FloorTex(), "FBOTTOM"); ASSERT_FALSE(doc.getLeft(*line)); ASSERT_EQ(line->flags, MLF_Blocking); } } ASSERT_EQ(checks, 3); // ._. ._. ._._._. // Now do the move | \|_| --> | | // |_____| |_____| // Find the line to move for(lineIndex = 0; lineIndex < doc.numLinedefs(); ++lineIndex) { if(doc.getStart(*doc.linedefs[lineIndex]).xy() == v2double_t{128, 0} && doc.getEnd(*doc.linedefs[lineIndex]).xy() == v2double_t{64, 0}) break; } ASSERT_LT(lineIndex, doc.numLinedefs()); selection.clear_all(); selection.set(lineIndex); doc.objects.move(selection, delta); ASSERT_EQ(doc.numVertices(), 6); ASSERT_EQ(doc.numSidedefs(), 6); ASSERT_EQ(doc.numLinedefs(), 6); ASSERT_EQ(doc.numSectors(), 1); checks = 0; for(const std::shared_ptr &line : doc.linedefs) { if(doc.getStart(*line).xy() == v2double_t{0, 64} && doc.getEnd(*line).xy() == v2double_t{64, 64}) { ++checks; ASSERT_EQ(doc.getRight(*line)->MidTex(), "BOTTOM"); ASSERT_EQ(doc.getSector(*doc.getRight(*line)).FloorTex(), "FBOTTOM"); ASSERT_FALSE(doc.getLeft(*line)); ASSERT_EQ(line->flags, MLF_Blocking); } else if(doc.getStart(*line).xy() == v2double_t{64, 64} && doc.getEnd(*line).xy() == v2double_t{128, 64}) { ++checks; ASSERT_EQ(doc.getRight(*line)->MidTex(), "TOPRIGHT"); ASSERT_EQ(doc.getSector(*doc.getRight(*line)).FloorTex(), "FBOTTOM"); ASSERT_FALSE(doc.getLeft(*line)); ASSERT_EQ(line->flags, MLF_Blocking); } else if(doc.getStart(*line).xy() == v2double_t{128, 64} && doc.getEnd(*line).xy() == v2double_t{128, -64}) { ++checks; ASSERT_EQ(doc.getRight(*line)->MidTex(), "BOTTOM"); ASSERT_EQ(doc.getSector(*doc.getRight(*line)).FloorTex(), "FBOTTOM"); ASSERT_FALSE(doc.getLeft(*line)); ASSERT_EQ(line->flags, MLF_Blocking); } } ASSERT_EQ(checks, 3); } // // _ Drag the line here below, causing a split and eliminating a sector // /_\ . // |/ TEST_F(EObjectsFixture, DragLineToSplitLineAndEliminateSector) { /* 1 2 0 3 4 */ static const FFixedPoint vertexCoordinates[5][2] = { { FFixedPoint(0), FFixedPoint(0) }, { FFixedPoint(32), FFixedPoint(64) }, { FFixedPoint(96), FFixedPoint(64) }, { FFixedPoint(128), FFixedPoint(0) }, { FFixedPoint(0), FFixedPoint(-64) }, }; Document &doc = inst.level; inst.grid.ForceStep(8); for(size_t i = 0; i < 5; ++i) { auto vertex = std::make_shared(); vertex->raw_x = vertexCoordinates[i][0]; vertex->raw_y = vertexCoordinates[i][1]; doc.vertices.push_back(std::move(vertex)); } std::shared_ptr sector; sector = std::make_shared(); sector->floor_tex = BA_InternaliseString("FBOTTOM"); doc.sectors.push_back(std::move(sector)); sector = std::make_shared(); sector->floor_tex = BA_InternaliseString("FTOP"); doc.sectors.push_back(std::move(sector)); std::shared_ptr side; // 0 side = std::make_shared(); side->mid_tex = BA_InternaliseString("BOTTOM"); side->sector = 0; doc.sidedefs.push_back(std::move(side)); side = std::make_shared(); // 1 side->mid_tex = BA_InternaliseString("-"); side->sector = 0; doc.sidedefs.push_back(std::move(side)); side = std::make_shared(); // 2 side->mid_tex = BA_InternaliseString("BOTTOM"); side->sector = 0; doc.sidedefs.push_back(std::move(side)); side = std::make_shared(); // 3 side->mid_tex = BA_InternaliseString("TOP"); side->sector = 1; doc.sidedefs.push_back(std::move(side)); side = std::make_shared(); // 4 side->mid_tex = BA_InternaliseString("TOP"); side->sector = 1; doc.sidedefs.push_back(std::move(side)); side = std::make_shared(); // 5 side->mid_tex = BA_InternaliseString("TOP"); side->sector = 1; doc.sidedefs.push_back(std::move(side)); side = std::make_shared(); // 6 side->mid_tex = BA_InternaliseString("-"); side->sector = 1; doc.sidedefs.push_back(std::move(side)); std::shared_ptr line; line = std::make_shared(); line->start = 0; line->end = 1; line->right = 3; line->flags = MLF_Blocking; doc.linedefs.push_back(std::move(line)); line = std::make_shared(); line->start = 1; line->end = 2; line->right = 4; line->flags = MLF_Blocking; doc.linedefs.push_back(std::move(line)); line = std::make_shared(); line->start = 2; line->end = 3; line->right = 5; line->flags = MLF_Blocking; doc.linedefs.push_back(std::move(line)); line = std::make_shared(); line->start = 3; line->end = 4; line->right = 2; line->flags = MLF_Blocking; doc.linedefs.push_back(std::move(line)); line = std::make_shared(); line->start = 4; line->end = 0; line->right = 0; line->flags = MLF_Blocking; doc.linedefs.push_back(std::move(line)); line = std::make_shared(); line->start = 0; line->end = 3; line->right = 1; line->left = 6; line->flags = MLF_TwoSided; doc.linedefs.push_back(std::move(line)); selection_c selection(ObjType::linedefs); selection.set(1); v3double_t delta = {0, -64, 0}; doc.objects.move(selection, delta); // ___ // |/ ASSERT_EQ(doc.numVertices(), 5); ASSERT_EQ(doc.numSectors(), 1); ASSERT_EQ(doc.numSidedefs(), 5); ASSERT_EQ(doc.numLinedefs(), 5); // int checks = 0; for(const std::shared_ptr &line : doc.linedefs) { if(doc.getStart(*line).xy() == v2double_t{0, 0} && doc.getEnd(*line).xy() == v2double_t{32, 0}) { // ++checks; ASSERT_EQ(doc.getRight(*line)->MidTex(), "TOP"); ASSERT_EQ(doc.getSector(*doc.getRight(*line)).FloorTex(), "FBOTTOM"); ASSERT_FALSE(doc.getLeft(*line)); ASSERT_EQ(line->flags, MLF_Blocking); } else if(doc.getStart(*line).xy() == v2double_t{32, 0} && doc.getEnd(*line).xy() == v2double_t{96, 0}) { // ++checks; ASSERT_EQ(doc.getRight(*line)->MidTex(), "TOP"); ASSERT_EQ(doc.getSector(*doc.getRight(*line)).FloorTex(), "FBOTTOM"); ASSERT_FALSE(doc.getLeft(*line)); ASSERT_EQ(line->flags, MLF_Blocking); } else if(doc.getStart(*line).xy() == v2double_t{96, 0} && doc.getEnd(*line).xy() == v2double_t{128, 0}) { // ++checks; ASSERT_EQ(doc.getRight(*line)->MidTex(), "TOP"); ASSERT_EQ(doc.getSector(*doc.getRight(*line)).FloorTex(), "FBOTTOM"); ASSERT_FALSE(doc.getLeft(*line)); ASSERT_EQ(line->flags, MLF_Blocking); } } } eureka-editor-eureka-2.0.2/test/im_color_test.cpp000066400000000000000000000044051464327712600220710ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "im_color.h" #include "w_wad.h" #include "testUtils/Palette.hpp" #include "gtest/gtest.h" #include #include TEST(Palette, LoadPalette) { Palette palette; // Need a wad auto wad = Wad_file::Open("dummy.wad", WadOpenMode::write); ASSERT_TRUE(wad); Lump_c &lump = wad->AddLump("PALETTE"); // Try on empty lump: should fail ASSERT_FALSE(palette.loadPalette(lump, 2, 2)); // Try insufficient lump: should still fail std::vector data; data.resize(256); lump.Write(data.data(), (int)data.size()); ASSERT_FALSE(palette.loadPalette(lump, 2, 2)); // Repopulate lump, this time valid data = makeGrayscale(); lump.clearData(); lump.Write(data.data(), (int)data.size()); ASSERT_TRUE(palette.loadPalette(lump, 2, 2)); ASSERT_TRUE(palette.loadPalette(lump, 0, 0)); ASSERT_FALSE(palette.loadPalette(lump, -1, 0)); ASSERT_FALSE(palette.loadPalette(lump, 0, -1)); ASSERT_TRUE(palette.loadPalette(lump, 4, 4)); ASSERT_FALSE(palette.loadPalette(lump, 4, 5)); ASSERT_FALSE(palette.loadPalette(lump, 5, 4)); } TEST(Palette, FindPaletteColor) { Palette palette; auto wad = Wad_file::Open("dummy.wad", WadOpenMode::write); ASSERT_TRUE(wad); Lump_c &lump = wad->AddLump("PALETTE"); std::vector data = makeGrayscale(); lump.Write(data.data(), (int)data.size()); ASSERT_TRUE(palette.loadPalette(lump, 2, 2)); // Now look for some ASSERT_EQ(palette.findPaletteColor(100, 100, 98), 99); ASSERT_EQ(palette.findPaletteColor(63, 64, 65), 64); ASSERT_EQ(palette.findPaletteColor(255, 255, 255), 254); // not the trans pixel } eureka-editor-eureka-2.0.2/test/im_img_test.cpp000066400000000000000000000765641464327712600215460ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "im_img.h" #include "m_game.h" #include "w_wad.h" #include "testUtils/Palette.hpp" #include "gtest/gtest.h" #include // // Development helper function to generate the code for the expected image. // Do NOT make static: we don't want "unused function" errors. // void outputPixels(const Img_c &image) { for(int y = 0; y < image.height(); ++y) { for(int x = 0; x < image.width(); ++x) { printf("%u, ", image.buf()[y * image.width() + x]); } puts(""); } } //================================================================================================== TEST(ImageBasic, PixelMakeRGB) { img_pixel_t pixel = pixelMakeRGB(23, 15, 27); ASSERT_EQ(pixel, img_pixel_t(IS_RGB_PIXEL | 23 << 10 | 15 << 5 | 27)); pixel = pixelMakeRGB(0, 0, 0); ASSERT_EQ(pixel, img_pixel_t(IS_RGB_PIXEL)); } TEST(ImageBasic, ConvertRGBImageNoAlpha) { std::vector bits = { 12, 34, 56, 0, 80, 0, 56, 77, 22, 98, 0, 98, 22, 255, 200, 0, 99, 255 }; Fl_RGB_Image flImage(bits.data(), 3, 2, 3); auto image = IM_ConvertRGBImage(flImage); ASSERT_FALSE(image->is_null()); ASSERT_EQ(image->width(), 3); ASSERT_EQ(image->height(), 2); ASSERT_FALSE(image->has_transparent()); const img_pixel_t *buf = image->buf(); ASSERT_EQ(buf[0], pixelMakeRGB(1, 4, 7)); ASSERT_EQ(buf[1], pixelMakeRGB(0, 10, 0)); ASSERT_EQ(buf[2], pixelMakeRGB(7, 9, 2)); ASSERT_EQ(buf[3], pixelMakeRGB(12, 0, 12)); ASSERT_EQ(buf[4], pixelMakeRGB(2, 31, 25)); ASSERT_EQ(buf[5], pixelMakeRGB(0, 12, 31)); } TEST(ImageBasic, ConvertRGBImageWithAlpha) { std::vector bits = { 12, 34, 56, 255, 0, 80, 0, 64, 56, 77, 22, 192, 98, 0, 98, 200, 22, 255, 200, 255, 0, 99, 255, 32 }; Fl_RGB_Image flImage(bits.data(), 3, 2, 4); auto image = IM_ConvertRGBImage(flImage); ASSERT_FALSE(image->is_null()); ASSERT_EQ(image->width(), 3); ASSERT_EQ(image->height(), 2); ASSERT_TRUE(image->has_transparent()); const img_pixel_t *buf = image->buf(); ASSERT_EQ(buf[0], pixelMakeRGB(1, 4, 7)); ASSERT_EQ(buf[1], TRANS_PIXEL); ASSERT_EQ(buf[2], pixelMakeRGB(7, 9, 2)); ASSERT_EQ(buf[3], pixelMakeRGB(12, 0, 12)); ASSERT_EQ(buf[4], pixelMakeRGB(2, 31, 25)); ASSERT_EQ(buf[5], TRANS_PIXEL); } TEST(ImageBasic, ConvertRGBImageInvalidDepth1) { std::vector bits = { 12, 34, 56, 98, 0, 98, }; Fl_RGB_Image flImage(bits.data(), 3, 2, 1); auto image = IM_ConvertRGBImage(flImage); ASSERT_FALSE(image); } TEST(ImageBasic, ConvertRGBImageInvalidDepth2) { std::vector bits = { 12, 255, 34, 255, 56, 255, 98, 255, 0, 0, 98, 255 }; Fl_RGB_Image flImage(bits.data(), 3, 2, 2); auto image = IM_ConvertRGBImage(flImage); ASSERT_FALSE(image); } TEST(ImageBasic, ConvertTGAImage) { static const rgba_color_t rgba[] = { 0xff0080ff, 0x7799aa22, 0x337744ff, 0x12469911, 0xffffffff, 0x00000000, 0x246732ff, 0x12345678, }; auto image = IM_ConvertTGAImage(rgba, 4, 2); ASSERT_FALSE(image.is_null()); ASSERT_TRUE(image.has_transparent()); ASSERT_EQ(image.width(), 4); ASSERT_EQ(image.height(), 2); const auto buf = image.buf(); ASSERT_NE(buf[0], TRANS_PIXEL); ASSERT_EQ(buf[1], TRANS_PIXEL); ASSERT_NE(buf[2], TRANS_PIXEL); ASSERT_EQ(buf[3], TRANS_PIXEL); ASSERT_NE(buf[4], TRANS_PIXEL); ASSERT_EQ(buf[5], TRANS_PIXEL); ASSERT_NE(buf[6], TRANS_PIXEL); ASSERT_EQ(buf[7], TRANS_PIXEL); } static Img_c getCrossImage() { Img_c image(3, 3); img_pixel_t *buf = image.wbuf(); buf[1] = buf[3] = buf[4] = buf[5] = buf[7] = 200; // + EXPECT_TRUE(image.has_transparent()); return image; } TEST(ImageBasic, Spectrify) { ConfigData config = {}; config.miscInfo.invis_colors[0] = 2; config.miscInfo.invis_colors[1] = 10; Img_c image = getCrossImage(); Img_c specter = image.spectrify(config); ASSERT_FALSE(specter.is_null()); ASSERT_TRUE(specter.has_transparent()); ASSERT_EQ(specter.width(), 3); ASSERT_EQ(specter.height(), 3); const img_pixel_t *sbuf = specter.buf(); ASSERT_EQ(sbuf[0], TRANS_PIXEL); ASSERT_GE(sbuf[1], 2); ASSERT_LE(sbuf[1], 10); ASSERT_EQ(sbuf[2], TRANS_PIXEL); ASSERT_GE(sbuf[3], 2); ASSERT_LE(sbuf[3], 10); ASSERT_GE(sbuf[4], 2); ASSERT_LE(sbuf[4], 10); ASSERT_GE(sbuf[5], 2); ASSERT_LE(sbuf[5], 10); ASSERT_EQ(sbuf[6], TRANS_PIXEL); ASSERT_GE(sbuf[7], 2); ASSERT_LE(sbuf[7], 10); ASSERT_EQ(sbuf[8], TRANS_PIXEL); } TEST(ImageBasic, SpectrifySingleColor) { ConfigData config = {}; config.miscInfo.invis_colors[0] = 2; config.miscInfo.invis_colors[1] = 0; Img_c image = getCrossImage(); Img_c specter = image.spectrify(config); ASSERT_FALSE(specter.is_null()); ASSERT_TRUE(specter.has_transparent()); ASSERT_EQ(specter.width(), 3); ASSERT_EQ(specter.height(), 3); const img_pixel_t *sbuf = specter.buf(); ASSERT_EQ(sbuf[0], TRANS_PIXEL); ASSERT_EQ(sbuf[1], 2); ASSERT_EQ(sbuf[2], TRANS_PIXEL); ASSERT_EQ(sbuf[3], 2); ASSERT_EQ(sbuf[4], 2); ASSERT_EQ(sbuf[5], 2); ASSERT_EQ(sbuf[6], TRANS_PIXEL); ASSERT_EQ(sbuf[7], 2); ASSERT_EQ(sbuf[8], TRANS_PIXEL); } //================================================================================================== // // Fixture with a palette // class ImageFixture : public ::testing::Test { protected: void SetUp() override; Palette palette; }; // // Setup the palette // void ImageFixture::SetUp() { makeCommonPalette(palette); } TEST_F(ImageFixture, CreateLightSprite) { Img_c image = Img_c::createLightSprite(palette); ASSERT_EQ(image.width(), 11); ASSERT_EQ(image.height(), 11); static const img_pixel_t expected[11 * 11] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2d, 0x32, 0x32, 0x2d, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2d, 0x5a, 0x88, 0x8d, 0x8d, 0x88, 0x5a, 0x2d, 0xff, 0xff, 0xff, 0x5a, 0x8d, 0xe7, 0xed, 0xed, 0xe7, 0x8d, 0x5a, 0xff, 0xff, 0x2d, 0x88, 0xe7, 0xed, 0xee, 0xee, 0xed, 0xe7, 0x88, 0x2d, 0xff, 0x32, 0x8d, 0xed, 0xee, 0xef, 0xef, 0xee, 0xed, 0x8d, 0x32, 0xff, 0x32, 0x8d, 0xed, 0xee, 0xef, 0xef, 0xee, 0xed, 0x8d, 0x32, 0xff, 0x2d, 0x88, 0xe7, 0xed, 0xee, 0xee, 0xed, 0xe7, 0x88, 0x2d, 0xff, 0xff, 0x5a, 0x8d, 0xe7, 0xed, 0xed, 0xe7, 0x8d, 0x5a, 0xff, 0xff, 0xff, 0x2d, 0x5a, 0x88, 0x8d, 0x8d, 0x88, 0x5a, 0x2d, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2d, 0x32, 0x32, 0x2d, 0xff, 0xff, 0xff, }; ASSERT_EQ(memcmp(image.buf(), expected, sizeof(expected)), 0); } TEST_F(ImageFixture, CreateMapSpotSprite) { struct Case { int r, g, b; const img_pixel_t data[32 * 32]; }; static const Case cases[] = { {255, 0, 0, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0xa0, 0xa0, 0xa0, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xa0, 0xa0, 0xa0, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0xa0, 0xa0, 0xa0, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xa0, 0xa0, 0xa0, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0xa0, 0xa0, 0xa0, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xa0, 0xa0, 0xa0, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0xa0, 0xa0, 0xa0, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xa0, 0xa0, 0xa0, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0xa0, 0xa0, 0xa0, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xa0, 0xa0, 0xa0, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0xa0, 0xa0, 0xa0, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xa0, 0xa0, 0xa0, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0xa0, 0xa0, 0xa0, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xa0, 0xa0, 0xa0, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0xa0, 0xa0, 0xa0, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xa0, 0xa0, 0xa0, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0xa0, 0xa0, 0xa0, 0xc8, 0xc8, 0xc8, 0xa0, 0xa0, 0xa0, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0xa0, 0xa0, 0xa0, 0xc8, 0xc8, 0xc8, 0xa0, 0xa0, 0xa0, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0xa0, 0xa0, 0xa0, 0xc8, 0xa0, 0xa0, 0xa0, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0xa0, 0xa0, 0xa0, 0xc8, 0xa0, 0xa0, 0xa0, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0xa0, 0xa0, 0xa0, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0xa0, 0xa0, 0xa0, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0xa0, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0xa0, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x78, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x78, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x50, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, 0x50, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }}, {0, 255, 0, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x19, 0x19, 0x1e, 0x1e, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x1e, 0x1e, 0x19, 0x19, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x19, 0x19, 0x1e, 0x1e, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x1e, 0x1e, 0x19, 0x19, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x19, 0x19, 0x1e, 0x1e, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x1e, 0x1e, 0x19, 0x19, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x19, 0x19, 0x1e, 0x1e, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x1e, 0x1e, 0x19, 0x19, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x19, 0x19, 0x1e, 0x1e, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x1e, 0x1e, 0x19, 0x19, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x19, 0x19, 0x1e, 0x1e, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x1e, 0x1e, 0x19, 0x19, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x19, 0x19, 0x1e, 0x1e, 0x23, 0x23, 0x23, 0x23, 0x23, 0x1e, 0x1e, 0x19, 0x19, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x19, 0x19, 0x1e, 0x1e, 0x23, 0x23, 0x23, 0x23, 0x23, 0x1e, 0x1e, 0x19, 0x19, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x19, 0x19, 0x1e, 0x1e, 0x23, 0x23, 0x23, 0x1e, 0x1e, 0x19, 0x19, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x19, 0x19, 0x1e, 0x1e, 0x23, 0x23, 0x23, 0x1e, 0x1e, 0x19, 0x19, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x19, 0x19, 0x1e, 0x1e, 0x23, 0x1e, 0x1e, 0x19, 0x19, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x19, 0x19, 0x1e, 0x1e, 0x23, 0x1e, 0x1e, 0x19, 0x19, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x19, 0x19, 0x1e, 0x1e, 0x1e, 0x19, 0x19, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x19, 0x19, 0x1e, 0x1e, 0x1e, 0x19, 0x19, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x19, 0x19, 0x1e, 0x19, 0x19, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x19, 0x19, 0x1e, 0x19, 0x19, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x19, 0x19, 0x19, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x19, 0x19, 0x19, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x19, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x19, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x14, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x14, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0f, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0f, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }}, {0, 0, 255, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }}, }; for(const Case &caze : cases) { Img_c image = Img_c::createMapSpotSprite(palette, caze.r, caze.g, caze.b); ASSERT_EQ(image.width(), 32); ASSERT_EQ(image.height(), 32); ASSERT_EQ(memcmp(image.buf(), caze.data, sizeof(caze.data)), 0); } } TEST_F(ImageFixture, CreateDogSprite) { Img_c image = Img_c::createDogSprite(palette); ASSERT_EQ(image.width(), 44); ASSERT_EQ(image.height(), 26); static const img_pixel_t expected[44 * 26] = { 255, 255, 255, 255, 255, 255, 255, 242, 242, 242, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 131, 131, 131, 131, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 131, 131, 131, 131, 131, 131, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 242, 242, 242, 131, 0, 131, 131, 131, 131, 131, 130, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 45, 45, 130, 131, 131, 131, 45, 131, 131, 131, 131, 130, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 45, 85, 130, 130, 130, 131, 131, 130, 131, 131, 130, 131, 131, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 255, 242, 45, 45, 85, 85, 130, 130, 131, 85, 130, 130, 85, 131, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 242, 242, 255, 255, 255, 255, 255, 255, 255, 255, 242, 131, 242, 255, 242, 45, 45, 85, 85, 85, 130, 45, 85, 85, 45, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 85, 242, 242, 242, 255, 255, 255, 242, 242, 131, 242, 255, 255, 255, 242, 45, 45, 45, 242, 242, 45, 85, 45, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 85, 85, 85, 85, 130, 130, 242, 242, 242, 131, 131, 131, 242, 255, 255, 255, 255, 242, 242, 242, 255, 255, 242, 45, 45, 0, 0, 85, 85, 85, 85, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 85, 85, 130, 130, 130, 130, 131, 131, 131, 131, 131, 242, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 0, 0, 131, 130, 130, 130, 85, 85, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 85, 85, 130, 131, 131, 131, 131, 131, 131, 131, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 242, 131, 131, 130, 131, 130, 130, 85, 45, 45, 45, 45, 45, 45, 45, 45, 45, 85, 85, 130, 130, 131, 242, 242, 242, 242, 242, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 131, 131, 131, 131, 130, 130, 130, 45, 45, 45, 45, 45, 45, 45, 85, 85, 130, 131, 131, 131, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 131, 131, 131, 131, 131, 131, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 131, 131, 131, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 45, 45, 131, 131, 131, 131, 131, 131, 131, 131, 242, 242, 242, 242, 131, 131, 131, 131, 131, 131, 131, 131, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 45, 45, 131, 131, 131, 131, 131, 242, 242, 242, 255, 255, 255, 255, 242, 45, 45, 131, 131, 131, 131, 131, 131, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 45, 45, 131, 131, 131, 131, 242, 242, 255, 255, 255, 255, 255, 255, 255, 242, 45, 45, 45, 45, 131, 131, 131, 131, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 85, 45, 131, 131, 131, 242, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 85, 85, 45, 45, 242, 131, 131, 131, 131, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 85, 45, 45, 131, 131, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 85, 85, 85, 85, 242, 242, 131, 131, 131, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 242, 130, 85, 45, 242, 131, 131, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 130, 130, 130, 242, 255, 242, 131, 131, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 131, 131, 130, 130, 242, 242, 131, 131, 131, 242, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 130, 130, 130, 242, 242, 131, 131, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 131, 131, 131, 131, 242, 255, 255, 242, 131, 131, 131, 131, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 130, 131, 131, 242, 242, 131, 131, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 242, 242, 242, 255, 255, 255, 255, 242, 131, 131, 131, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 131, 131, 131, 242, 255, 255, 242, 131, 131, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 242, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 131, 131, 131, 242, 255, 255, 255, 242, 131, 131, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 131, 131, 131, 242, 255, 255, 255, 242, 131, 131, 131, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 242, 242, 255, 255, 255, 255, 255, 242, 242, 242, 255, 255, 255, 255, 255, 255, 255, }; ASSERT_EQ(memcmp(image.buf(), expected, sizeof(expected)), 0); } eureka-editor-eureka-2.0.2/test/lib_file_test.cpp000066400000000000000000000237231464327712600220370ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2020 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "lib_file.h" #include "m_strings.h" #include "testUtils/TempDirContext.hpp" #include "gtest/gtest.h" #include "FL/filename.H" #include class LibFileTempDir : public TempDirContext { }; TEST(LibFile, HasExtension) { ASSERT_FALSE(HasExtension("man/doc.")); ASSERT_TRUE(HasExtension("man/doom.wad")); ASSERT_FALSE(HasExtension("man.wad/doom")); ASSERT_TRUE(HasExtension("man.wad/doom.wad")); ASSERT_TRUE(HasExtension("man.wad/doom..wad")); ASSERT_FALSE(HasExtension(".okay")); ASSERT_FALSE(HasExtension("man/.okay")); ASSERT_TRUE(HasExtension("man/..okay")); ASSERT_FALSE(HasExtension("man/.okay.")); ASSERT_TRUE(HasExtension("man/.okay.wad")); ASSERT_FALSE(HasExtension("/.")); ASSERT_FALSE(HasExtension(".")); ASSERT_FALSE(HasExtension("..")); ASSERT_FALSE(HasExtension("abc/..")); ASSERT_FALSE(HasExtension("../..")); ASSERT_FALSE(HasExtension("")); } TEST(LibFile, MatchExtension) { ASSERT_TRUE(MatchExtensionNoCase("man/doc.", nullptr)); ASSERT_TRUE(MatchExtensionNoCase("man/doc.", "")); ASSERT_FALSE(MatchExtensionNoCase("man/.doc.", ".doc")); ASSERT_TRUE(MatchExtensionNoCase("man/doc. ", ". ")); ASSERT_TRUE(MatchExtensionNoCase("man.wad/doom", nullptr)); ASSERT_FALSE(MatchExtensionNoCase("man.wad/doom", "doom")); ASSERT_TRUE(MatchExtensionNoCase("man.wad/doom.wad", ".WAD")); ASSERT_TRUE(MatchExtensionNoCase("man.wad/doom..wad", ".WAD")); ASSERT_TRUE(MatchExtensionNoCase(".okay", "")); ASSERT_FALSE(MatchExtensionNoCase(".okay", ".okay")); ASSERT_TRUE(MatchExtensionNoCase("man/.okay", "")); ASSERT_FALSE(MatchExtensionNoCase("man/.okay", ".okay")); ASSERT_TRUE(MatchExtensionNoCase("man/.okay.WAD", ".wad")); ASSERT_TRUE(MatchExtensionNoCase("/.", nullptr)); ASSERT_TRUE(MatchExtensionNoCase(".", nullptr)); ASSERT_TRUE(MatchExtensionNoCase("..", nullptr)); ASSERT_FALSE(MatchExtensionNoCase("..", ".")); ASSERT_TRUE(MatchExtensionNoCase("", nullptr)); } TEST(LibFile, ReplaceExtension) { ASSERT_EQ(ReplaceExtension("man/doc.", "wad"), "man/doc.wad"); ASSERT_EQ(ReplaceExtension("man/doc.", "WAD"), "man/doc.WAD"); ASSERT_EQ(ReplaceExtension("man/doc.", ""), "man/doc"); ASSERT_EQ(ReplaceExtension("man/doc.", nullptr), "man/doc"); ASSERT_EQ(ReplaceExtension("man/.doc", ""), "man/.doc"); ASSERT_EQ(ReplaceExtension("man/.doc", nullptr), "man/.doc"); ASSERT_EQ(ReplaceExtension("man/.doc", "wad"), "man/.doc.wad"); ASSERT_EQ(ReplaceExtension("man.wad/doom", "waD"), "man.wad/doom.waD"); ASSERT_EQ(ReplaceExtension("man.wad/doom.wad", ".txt"), "man.wad/doom.txt"); ASSERT_EQ(ReplaceExtension("man.wad/doom.wad", ""), "man.wad/doom"); ASSERT_EQ(ReplaceExtension("man.wad/doom.wad", nullptr), "man.wad/doom"); ASSERT_EQ(ReplaceExtension("man.wad/doom..wad", nullptr), "man.wad/doom."); ASSERT_EQ(ReplaceExtension("man.wad/doom..wad", ""), "man.wad/doom."); ASSERT_EQ(ReplaceExtension("man.wad/doom..wad", "txt"), "man.wad/doom..txt"); ASSERT_EQ(ReplaceExtension(".okay", "txt"), ".okay.txt"); ASSERT_EQ(ReplaceExtension(".okay", ""), ".okay"); ASSERT_EQ(ReplaceExtension(".okay", nullptr), ".okay"); ASSERT_EQ(ReplaceExtension("/.", nullptr), "/."); ASSERT_EQ(ReplaceExtension("/.", "txt"), "/..txt"); ASSERT_EQ(ReplaceExtension(".", "txt"), "..txt"); ASSERT_EQ(ReplaceExtension("", "txt"), ".txt"); ASSERT_EQ(ReplaceExtension(".", ""), "."); ASSERT_EQ(ReplaceExtension(".", nullptr), "."); ASSERT_EQ(ReplaceExtension("..", ""), ".."); ASSERT_EQ(ReplaceExtension("..", nullptr), ".."); ASSERT_EQ(ReplaceExtension("..", "txt"), "..txt"); ASSERT_EQ(ReplaceExtension("..txt", "wad"), "..wad"); ASSERT_EQ(ReplaceExtension("..txt", ""), "."); ASSERT_EQ(ReplaceExtension("..txt", nullptr), "."); ASSERT_EQ(ReplaceExtension("", ""), ""); ASSERT_EQ(ReplaceExtension("", nullptr), ""); ASSERT_EQ(ReplaceExtension("", "wad"), ".wad"); } TEST(LibFile, FilenameGetPath) { ASSERT_EQ(FilenameGetPath("path/to/file"), "path/to"); ASSERT_EQ(FilenameGetPath("path/to" DIR_SEP_STR DIR_SEP_STR "file"), "path/to"); ASSERT_EQ(FilenameGetPath("file"), "."); ASSERT_EQ(FilenameGetPath(""), "."); ASSERT_EQ(FilenameGetPath(DIR_SEP_STR "file"), DIR_SEP_STR); ASSERT_EQ(FilenameGetPath("/doom/"), "/doom"); ASSERT_TRUE(FilenameGetPath("///doom.wad") == "/" || FilenameGetPath("///doom.wad") == "\\"); #ifdef _WIN32 ASSERT_EQ(FilenameGetPath("C:" DIR_SEP_STR "file"), "C:" DIR_SEP_STR); #endif } TEST(LibFile, GetBaseName) { ASSERT_EQ(GetBaseName("path/to///fileA.wad"), "fileA.wad"); ASSERT_EQ(GetBaseName("path/to/fileB"), "fileB"); ASSERT_EQ(GetBaseName("/fileC.txt"), "fileC.txt"); ASSERT_EQ(GetBaseName("/file"), "file"); ASSERT_EQ(GetBaseName("//dir/file"), "file"); ASSERT_EQ(GetBaseName("/file"), "file"); ASSERT_EQ(GetBaseName("fil"), "fil"); ASSERT_EQ(GetBaseName(""), ""); } TEST(LibFile, FilenameIsBare) { ASSERT_TRUE(FilenameIsBare("")); ASSERT_TRUE(FilenameIsBare("Doom")); ASSERT_TRUE(FilenameIsBare("DOOM")); ASSERT_TRUE(FilenameIsBare("doom")); ASSERT_FALSE(FilenameIsBare("/doom")); ASSERT_FALSE(FilenameIsBare("/doom.wad")); ASSERT_FALSE(FilenameIsBare("doom.wad")); ASSERT_FALSE(FilenameIsBare("C:\\doom")); } TEST(LibFile, GetAbsolutePath) { char path[FL_PATH_MAX]; int result = fl_filename_absolute(path, sizeof(path), "Hello"); ASSERT_NE(result, 0); // absolute path stays absolute SString stringResult = GetAbsolutePath("Hello").generic_u8string(); ASSERT_STREQ(stringResult.c_str(), path); } TEST(LibFile, Escape) { ASSERT_EQ(escape("/path with spaces and a quote\"/ okay"), "\"/path with spaces and a quote\"\"/ okay\""); } TEST_F(LibFileTempDir, FileExists) { fs::path path = getChildPath("hello"); ASSERT_FALSE(FileExists(path)); std::ofstream os(path); ASSERT_TRUE(os.is_open()); os.close(); mDeleteList.push(path); ASSERT_TRUE(FileExists(path)); fs::remove(path); mDeleteList.pop(); // Deleted, now must be back to false ASSERT_FALSE(FileExists(path)); ASSERT_TRUE(FileMakeDir(path)); mDeleteList.push(path); ASSERT_FALSE(FileExists(path)); } TEST_F(LibFileTempDir, FileDelete) { fs::path path = getChildPath("file"); ASSERT_FALSE(FileDelete(path)); // can't delete what is not there std::ofstream os(path); ASSERT_TRUE(os.is_open()); mDeleteList.push(path); os << "Hello"; os.close(); ASSERT_TRUE(FileDelete(path)); mDeleteList.pop(); } // NOTE: FileChangeDir modifies the process state TEST_F(LibFileTempDir, FileMakeDir) { fs::path path = getChildPath("dir"); ASSERT_TRUE(FileMakeDir(path)); mDeleteList.push(path); // Disallow overwriting ASSERT_FALSE(FileMakeDir(path)); // Disallow inexistent intermediary paths ASSERT_FALSE(FileMakeDir(getChildPath(fs::path("dir2") / "dir3"))); } TEST_F(LibFileTempDir, FileLoad) { // Must test a sufficiently large file std::vector randomData; randomData.reserve(40000); for(int i = 0; i < 40000; ++i) randomData.push_back(static_cast(rand() & 0xff)); fs::path path = getChildPath("file"); std::ofstream os(path, std::ios::binary); ASSERT_TRUE(os.is_open()); mDeleteList.push(path); os.write(randomData.data(), randomData.size()); os.close(); std::vector result; ASSERT_TRUE(FileLoad(path, result)); ASSERT_EQ(result.size(), 40000); ASSERT_EQ(memcmp(result.data(), randomData.data(), result.size()), 0); // Mustn't read dirs ASSERT_FALSE(FileLoad(mTempDir, result)); // Mustn't read inexistent files ASSERT_FALSE(FileLoad(getChildPath("file2"), result)); #ifndef _WIN32 // Mustn't read special files ASSERT_FALSE(FileLoad("/dev/null", result)); ASSERT_FALSE(FileLoad("/dev/urandom", result)); #endif } TEST_F(LibFileTempDir, ScanDirectory) { // 1. Add a file, a "hidden" file, a folder and a "hidden" folder fs::path path = getChildPath("file"); std::ofstream os(path); ASSERT_TRUE(os.is_open()); mDeleteList.push(path); os << "hello"; os.close(); fs::path filePath = path; path = getChildPath(".file"); os.open(path); ASSERT_TRUE(os.is_open()); mDeleteList.push(path); os << "shadow"; os.close(); path = getChildPath("dir"); ASSERT_TRUE(FileMakeDir(path)); mDeleteList.push(path); path = getChildPath(".dir"); ASSERT_TRUE(FileMakeDir(path)); mDeleteList.push(path); fs::path dotDirPath = path; // Also nest another file, to check it doesn't get listed path = getChildPath(fs::path("dir") / "file2"); os.open(path); ASSERT_TRUE(os.is_open()); mDeleteList.push(path); os << "shadow2"; os.close(); int result = ScanDirectory(mTempDir, [](const fs::path &name, int flags) { if(name == "file") ASSERT_EQ(flags, 0); else if(name == ".file") ASSERT_TRUE(flags & SCAN_F_Hidden); else if(name == "dir") ASSERT_TRUE(flags & SCAN_F_IsDir); else if(name == ".dir") ASSERT_EQ(flags & (SCAN_F_IsDir | SCAN_F_Hidden), SCAN_F_IsDir | SCAN_F_Hidden); else ASSERT_FALSE(true); // error if getting here }); ASSERT_EQ(result, 4); // scan no more // Now also try on some non-folder files result = ScanDirectory(filePath, [](const fs::path &name, int flags) { ASSERT_FALSE(true); // should not get here }); ASSERT_EQ(result, SCAN_ERR_NotDir); result = ScanDirectory(getChildPath("illegal"), [](const fs::path &name, int flags) { ASSERT_FALSE(true); // should not get here }); ASSERT_EQ(result, SCAN_ERR_NoExist); // Also scan an empty dir result = ScanDirectory(dotDirPath, [](const fs::path &name, int flags) { ASSERT_FALSE(true); // should not get here }); ASSERT_EQ(result, 0); } eureka-editor-eureka-2.0.2/test/lib_tga_test.cpp000066400000000000000000000044111464327712600216640ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2023 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "gtest/gtest.h" #include "lib_tga.h" TEST(TGA, DecodeImage) { static const uint8_t image[] = { 17, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 3, 0, 32, 8, 16, 67, 114, 101, 97, 116, 101, 100, 32, 98, 121, 32, 80, 105, 110, 116, 97, 255, 255, 127, 255, 255, 255, 199, 255, 255, 160, 143, 255, 255, 38, 0, 255, 192, 192, 199, 255, 238, 238, 246, 255, 254, 232, 238, 255, 247, 146, 192, 255, 0, 0, 255, 255, 143, 143, 255, 255, 247, 199, 255, 255, 237, 127, 255, 255, }; int width = 0; int height = 0; rgba_color_t *rgba = TGA_DecodeImage(image, sizeof(image), width, height); ASSERT_TRUE(rgba); ASSERT_EQ(width, 4); ASSERT_EQ(height, 3); TGA_FreeImage(rgba); } TEST(TGA, DecodeImageBroken) { static const uint8_t image[] = { 17, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 32, 8, 16, 67, 114, 101, 97, 116, 101, 100, 32, 98, 121, 32, 80, 105, 110, 116, 97, 255, 255, 127, 255, 255, 255, 199, 255, 255, 160, 143, 255, 255, 38, 0, 255, 192, 192, 199, 255, 238, 238, 246, 255, 254, 232, 238, 255, 247, 146, 192, 255, 0, 0, 255, 255, 143, 143, 255, 255, 247, 199, 255, 255, 237, 127, 255, 255, }; int width = 0; int height = 0; rgba_color_t *rgba = TGA_DecodeImage(image, sizeof(image), width, height); ASSERT_FALSE(rgba); } TEST(TGA, DecodeImageMalformed) { static const uint8_t image[] = { 23, }; int width; int height; rgba_color_t *rgba = TGA_DecodeImage(image, sizeof(image), width, height); ASSERT_FALSE(rgba); }eureka-editor-eureka-2.0.2/test/lib_util_test.cpp000066400000000000000000000015641464327712600220740ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2020 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "lib_util.h" #include "gtest/gtest.h" TEST(LibUtil, CheckTypeSizes) { ASSERT_NO_THROW(CheckTypeSizes()); } // Don't test time. It wastes time. eureka-editor-eureka-2.0.2/test/m_bitvec_test.cpp000066400000000000000000000066011464327712600220560ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2020 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "m_bitvec.h" #include "gtest/gtest.h" TEST(BitVec, Construct) { bitvec_c vec(16); ASSERT_EQ(vec.size(), 16); } TEST(BitVec, Get) { bitvec_c vec; ASSERT_FALSE(vec.get(1)); ASSERT_FALSE(vec.get(2)); ASSERT_FALSE(vec.get(4)); ASSERT_FALSE(vec.get(8)); ASSERT_FALSE(vec.get(16)); ASSERT_FALSE(vec.get(32)); ASSERT_FALSE(vec.get(64)); ASSERT_FALSE(vec.get(128)); ASSERT_FALSE(vec.get(256)); ASSERT_FALSE(vec.get(512)); ASSERT_FALSE(vec.get(1024)); } TEST(BitVec, SetClearToggle) { bitvec_c vec(0); // must be okay vec.set(100); ASSERT_GE(vec.size(), 100); int lastSize = vec.size(); for(int i = 0; i < vec.size(); ++i) ASSERT_EQ(vec.get(i), i == 100); vec.set(50); ASSERT_EQ(vec.size(), lastSize); for(int i = 0; i < vec.size(); ++i) ASSERT_EQ(vec.get(i), i == 100 || i == 50); vec.toggle_all(); ASSERT_EQ(vec.size(), lastSize); for(int i = 0; i < vec.size(); ++i) ASSERT_EQ(vec.get(i), i != 100 && i != 50); vec.toggle_all(); vec.clear(100); ASSERT_EQ(vec.size(), lastSize); for(int i = 0; i < vec.size(); ++i) ASSERT_EQ(vec.get(i), i == 50); vec.clear(150); ASSERT_EQ(vec.size(), lastSize); for(int i = 0; i < vec.size(); ++i) ASSERT_EQ(vec.get(i), i == 50); vec.clear(50); ASSERT_EQ(vec.size(), lastSize); for(int i = 0; i < vec.size(); ++i) ASSERT_FALSE(vec.get(i)); vec.toggle(25); ASSERT_EQ(vec.size(), lastSize); for(int i = 0; i < vec.size(); ++i) ASSERT_EQ(vec.get(i), i == 25); vec.toggle(25); ASSERT_EQ(vec.size(), lastSize); for(int i = 0; i < vec.size(); ++i) ASSERT_FALSE(vec.get(i)); vec.set_all(); ASSERT_EQ(vec.size(), lastSize); for(int i = 0; i < vec.size(); ++i) ASSERT_TRUE(vec.get(i)); vec.clear(150); ASSERT_EQ(vec.size(), lastSize); for(int i = 0; i < vec.size(); ++i) ASSERT_EQ(vec.get(i), i != 150); vec.clear_all(); ASSERT_EQ(vec.size(), lastSize); for(int i = 0; i < vec.size(); ++i) ASSERT_FALSE(vec.get(i)); } TEST(BitVec, Frob) { bitvec_c vec; vec.frob(100, BitOp::add); for(int i = 0; i < vec.size(); ++i) ASSERT_EQ(vec.get(i), i == 100); vec.frob(50, BitOp::add); for(int i = 0; i < vec.size(); ++i) ASSERT_EQ(vec.get(i), i == 100 || i == 50); vec.frob(100, BitOp::remove); for(int i = 0; i < vec.size(); ++i) ASSERT_EQ(vec.get(i), i == 50); vec.frob(150, BitOp::remove); for(int i = 0; i < vec.size(); ++i) ASSERT_EQ(vec.get(i), i == 50); vec.frob(50, BitOp::remove); for(int i = 0; i < vec.size(); ++i) ASSERT_FALSE(vec.get(i)); vec.frob(25, BitOp::toggle); for(int i = 0; i < vec.size(); ++i) ASSERT_EQ(vec.get(i), i == 25); vec.frob(25, BitOp::toggle); for(int i = 0; i < vec.size(); ++i) ASSERT_FALSE(vec.get(i)); } eureka-editor-eureka-2.0.2/test/m_config_test.cpp000066400000000000000000000707771464327712600220660ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2021 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "m_config.h" #include "testUtils/FatalHandler.hpp" #include "testUtils/TempDirContext.hpp" #include "Instance.h" #include "m_strings.h" #include "gtest/gtest.h" #include "filesystem.hpp" namespace fs = ghc::filesystem; // // Option end // static const opt_desc_t kEnd = { nullptr, nullptr, 0, nullptr, nullptr, nullptr }; // // Returns an opt_desc_t using only the fields we need for config file // template static opt_desc_t configOption(const char *long_name, unsigned flags, T *data_ptr) { return {long_name, nullptr, flags, nullptr, nullptr, data_ptr}; } template static opt_desc_t configOption(const char *long_name, const char *shortname, unsigned flags, T *data_ptr) { return {long_name, shortname, flags, nullptr, nullptr, data_ptr}; } // // Fixture // class MConfig : public TempDirContext { protected: // // Demo testing configuration data // struct Configuration { SString home_dir; SString loadedIwadName; bool show_help = false; bool udmf_testing = false; bool bsp_on_save = false; bool bsp_gl_nodes = false; bool grid_snap_indicator = false; bool leave_offsets_alone = false; std::vector Pwad_list; int backup_max_files = 0; rgb_color_t dotty_axis_col; bool auto_load_recent = false; bool begin_maximized = false; SString default_port; SString loadedLevelName; fs::path config_file; bool show_version = false; std::vector loadedResourceList; int usegamma = 0; bool Quiet = false; std::vector paths; fs::path onepath; }; void SetUp() override; // // Const getter // const std::vector &options() const { return mOptions; } Configuration config; private: void add(const opt_desc_t &option); std::vector mOptions = {kEnd}; }; // // Set up // void MConfig::SetUp() { TempDirContext::SetUp(); add(configOption("auto_load_recent", OptFlag_preference, &config.auto_load_recent)); add(configOption("backup_max_files", OptFlag_preference, &config.backup_max_files)); add(configOption("begin_maximized", OptFlag_preference, &config.begin_maximized)); add(configOption("bsp_gl_nodes", OptFlag_preference, &config.bsp_gl_nodes)); add(configOption("bsp_on_save", OptFlag_preference, &config.bsp_on_save)); add(configOption("config", OptFlag_pass1 | OptFlag_helpNewline, &config.config_file)); add(configOption("default_gamma", OptFlag_preference, &config.usegamma)); add(configOption("default_port", OptFlag_preference, &config.default_port)); add(configOption("dotty_axis_col", OptFlag_preference, &config.dotty_axis_col)); add(configOption("file", "f", 0, &config.Pwad_list)); add(configOption("grid_snap_indicator", OptFlag_preference, &config.grid_snap_indicator)); add(configOption("help", OptFlag_pass1, &config.show_help)); add(configOption("home", OptFlag_pass1, &config.home_dir)); add(configOption("iwad", 0, &config.loadedIwadName)); add(configOption("leave_offsets_alone", OptFlag_preference, &config.leave_offsets_alone)); add(configOption("merge", "m", 0, &config.loadedResourceList)); add(configOption("quiet", "q", OptFlag_pass1, &config.Quiet)); add(configOption("udmftest", OptFlag_hide, &config.udmf_testing)); add(configOption("version", "v", OptFlag_pass1, &config.show_version)); add(configOption("warp", OptFlag_warp | OptFlag_helpNewline, &config.loadedLevelName)); // Path type add(configOption("path", OptFlag_preference, &config.paths)); add(configOption("onepath", OptFlag_preference, &config.onepath)); } // // Adds a new option, ensuring null termination // void MConfig::add(const opt_desc_t &option) { mOptions.back() = option; mOptions.push_back(kEnd); } TEST_F(MConfig, MParseConfigFileNotFound) { // Get an error result if we don't have the file itself ASSERT_EQ(M_ParseConfigFile(getChildPath("nothing.cfg"), options().data()), -1); } TEST_F(MConfig, MParseConfigEmptyFile) { fs::path path = getChildPath("something.cfg"); FILE *f = fopen(path.u8string().c_str(), "wb"); ASSERT_TRUE(f); mDeleteList.push(path); fclose(f); ASSERT_EQ(M_ParseConfigFile(path, options().data()), 0); } TEST_F(MConfig, MParseConfigFile) { fs::path path = getChildPath("config.cfg"); std::ofstream os(path, std::ios::trunc); ASSERT_TRUE(os.is_open()); mDeleteList.push(path); os.close(); os.open(path); ASSERT_TRUE(os.is_open()); os << "\n"; os << "#\n"; os << " # Test comment\n"; os << "Single\n"; // Safe to skip os << "Single \n"; // Safe to skip os << "home michael\n"; // Home must NOT be changed os << "help 1\n"; // Also unchanged os << "file file1 \"file 2\" file3\n"; os << "iwad \"doom 3.wad\"\n"; os << "udmftest yes\n"; os << "backup_max_files -999\n"; os << "bsp_on_save off\n"; // test "off" os << "bsp_gl_nodes no\n"; // test "no" os << "grid_snap_indicator false\n"; // test "false" os << "leave_offsets_alone 0\n"; // test 0 os << "dotty_axis_col 7b2d43\n"; // NOTE: # not supported os.close(); // Prepare some prereqs config.home_dir = "jackson"; config.bsp_on_save = true; config.bsp_gl_nodes = true; config.grid_snap_indicator = true; config.leave_offsets_alone = true; ASSERT_EQ(M_ParseConfigFile(path, options().data()), 0); ASSERT_EQ(config.home_dir, "jackson"); // unchanged ASSERT_FALSE(config.show_help); // unchanged ASSERT_EQ(config.Pwad_list.size(), 3); ASSERT_EQ(config.Pwad_list[0], "file1"); ASSERT_EQ(config.Pwad_list[1], "file 2"); ASSERT_EQ(config.Pwad_list[2], "file3"); ASSERT_EQ(config.loadedIwadName, "doom 3.wad"); // spaces get included ASSERT_TRUE(config.udmf_testing); ASSERT_EQ(config.backup_max_files, -999); config::backup_max_files = 30; ASSERT_FALSE(config.bsp_on_save); ASSERT_FALSE(config.bsp_gl_nodes); ASSERT_EQ(config.dotty_axis_col, rgbMake(123, 45, 67)); ASSERT_FALSE(config.grid_snap_indicator); ASSERT_FALSE(config.leave_offsets_alone); } TEST_F(MConfig, ParsePathList) { fs::path path = getChildPath("config.cfg"); std::ofstream os(path, std::ios::trunc); ASSERT_TRUE(os.is_open()); mDeleteList.push(path); os.close(); os.open(path); ASSERT_TRUE(os.is_open()); // Use a wild combo of spaces, non-spaces and quotes os << "path \"/michael/jack \"\"Ripper\"\" son\". .. here/next\"here/../here\"here\n"; os << "onepath \"jacob's \"\"ladder\"\"/norg.txt\""; os.close(); ASSERT_EQ(M_ParseConfigFile(path, options().data()), 0); ASSERT_EQ(config.paths.size(), 6); ASSERT_EQ(config.paths[0], fs::path("/") / "michael" / "jack \"Ripper\" son"); ASSERT_EQ(config.paths[1], fs::path(".")); ASSERT_EQ(config.paths[2], fs::path("..")); ASSERT_EQ(config.paths[3], fs::path("here") / "next"); ASSERT_EQ(config.paths[4].lexically_normal(), fs::path("here")); ASSERT_EQ(config.paths[5], fs::path("here")); ASSERT_EQ(config.onepath, fs::path("jacob's \"ladder\"") / "norg.txt"); } TEST_F(MConfig, ParseEmptyList) { fs::path path = getChildPath("config.cfg"); std::ofstream os(path, std::ios::trunc); ASSERT_TRUE(os.is_open()); mDeleteList.push(path); os.close(); os.open(path); ASSERT_TRUE(os.is_open()); // Use a wild combo of spaces, non-spaces and quotes os << "path {}\n"; os << "file {}\n"; os.close(); ASSERT_EQ(M_ParseConfigFile(path, options().data()), 0); ASSERT_TRUE(config.paths.empty()); ASSERT_TRUE(config.Pwad_list.empty()); } TEST_F(MConfig, MWriteConfig) { config.auto_load_recent = true; config.begin_maximized = true; config.backup_max_files = 777; config.default_port = "Doom \\ # Legacy "; config.dotty_axis_col = rgbMake(99, 90, 80); config.udmf_testing = true; // this one shall not be saved config.loadedLevelName = "NEW LEVEL"; config.Pwad_list = { "file1", "file2 file3" }; config.config_file = getChildPath("configx.cfg"); // pick any name ASSERT_EQ(M_WriteConfigFile(config.config_file, options().data()), 0); mDeleteList.push(config.config_file); // Now unset them config.auto_load_recent = false; config.begin_maximized = false; config.backup_max_files = 30; config.default_port = "vanilla"; config.dotty_axis_col = rgbMake(0, 128, 255); config.udmf_testing = false; config.loadedLevelName.clear(); config.Pwad_list.clear(); // Now read config back ASSERT_EQ(M_ParseConfigFile(config.config_file, options().data()), 0); ASSERT_TRUE(config.auto_load_recent); ASSERT_TRUE(config.begin_maximized); ASSERT_EQ(config.backup_max_files, 777); ASSERT_EQ(config.default_port, "Doom \\ # Legacy "); ASSERT_EQ(config.dotty_axis_col, rgbMake(99, 90, 80)); ASSERT_FALSE(config.udmf_testing); // still false ASSERT_TRUE(config.loadedLevelName.empty()); ASSERT_TRUE(config.Pwad_list.empty()); } TEST_F(MConfig, MWriteConfigPathList) { config.paths = { "", ".", "/michael/jack \"Ripper\" son", ".", "..", "here/n\"ext", "here/../here", "here", "\"\"" }; config.onepath = "bi\"g\"/dog"; config.config_file = getChildPath("configx.cfg"); // pick any name ASSERT_EQ(M_WriteConfigFile(config.config_file, options().data()), 0); mDeleteList.push(config.config_file); config.paths.clear(); // Now read config back ASSERT_EQ(M_ParseConfigFile(config.config_file, options().data()), 0); ASSERT_EQ(config.paths.size(), 9); ASSERT_EQ(config.paths[0], fs::path("")); ASSERT_EQ(config.paths[1], fs::path(".")); ASSERT_EQ(config.paths[2], fs::path("/") / "michael" / "jack \"Ripper\" son"); ASSERT_EQ(config.paths[3], fs::path(".")); ASSERT_EQ(config.paths[4], fs::path("..")); ASSERT_EQ(config.paths[5], fs::path("here") / "n\"ext"); ASSERT_EQ(config.paths[6].lexically_normal(), fs::path("here")); ASSERT_EQ(config.paths[7], fs::path("here")); ASSERT_EQ(config.paths[8], fs::path("\"\"")); ASSERT_EQ(config.onepath, "bi\"g\"/dog"); } TEST_F(MConfig, MParseCommandLine) { // NOTE: check that both - and -- work and short name too // Test loose files std::vector argv; argv = { "file1", "file 2", "" }; std::vector &Pwad_list = config.Pwad_list; // First pass doesn't use it M_ParseCommandLine(3, argv.data(), CommandLinePass::early, Pwad_list, options().data()); ASSERT_TRUE(Pwad_list.empty()); // Second pass uses it M_ParseCommandLine(3, argv.data(), CommandLinePass::normal, Pwad_list, options().data()); ASSERT_EQ(Pwad_list.size(), 3); ASSERT_EQ(Pwad_list[0], "file1"); ASSERT_EQ(Pwad_list[1], "file 2"); ASSERT_EQ(Pwad_list[2], ""); Pwad_list.clear(); // Test illegal argument argv = { "file", "-unknown-abcxyz" }; // Both passes reject invalid settings ASSERT_DEATH(Fatal([&argv, &Pwad_list, this]{ M_ParseCommandLine(2, argv.data(), CommandLinePass::early, Pwad_list, options().data()); }), "unknown option"); ASSERT_DEATH(Fatal([&argv, &Pwad_list, this]{ M_ParseCommandLine(2, argv.data(), CommandLinePass::normal, Pwad_list, options().data()); }), "unknown option"); Pwad_list.clear(); // Test file AND valid arg // Pass 1 argv = { "file3", "-home", "home1" }; M_ParseCommandLine(3, argv.data(), CommandLinePass::early, Pwad_list, options().data()); ASSERT_TRUE(Pwad_list.empty()); ASSERT_EQ(config.home_dir, "home1"); config.home_dir.clear(); // Pass 2: ignore the -home arg but populate loose files M_ParseCommandLine(3, argv.data(), CommandLinePass::normal, Pwad_list, options().data()); ASSERT_EQ(Pwad_list.size(), 1); ASSERT_EQ(Pwad_list[0], "file3"); ASSERT_TRUE(config.home_dir.empty()); Pwad_list.clear(); // Test that missing argument shows error // First pass actively looks for -home argv = { "file4", "-home" }; ASSERT_DEATH(Fatal([&]{ M_ParseCommandLine(2, argv.data(), CommandLinePass::early, Pwad_list, options().data()); }), "missing argument"); Pwad_list.clear(); // Second pass still cares about integrity ASSERT_DEATH(Fatal([&]{ M_ParseCommandLine(2, argv.data(), CommandLinePass::normal, Pwad_list, options().data()); }), "missing argument"); Pwad_list.clear(); // Test boolean assignment argv = { "-v" }; M_ParseCommandLine(1, argv.data(), CommandLinePass::early, Pwad_list, options().data()); ASSERT_TRUE(config.show_version); config.show_version = false; // Reject double-dash short options argv = { "--v" }; ASSERT_DEATH(Fatal([&]{ M_ParseCommandLine(1, argv.data(), CommandLinePass::early, Pwad_list, options().data()); }), "unknown option"); // Test that anything means true argv = { "--version", "yeah" }; M_ParseCommandLine(2, argv.data(), CommandLinePass::early, Pwad_list, options().data()); ASSERT_TRUE(config.show_version); config.show_version = false; // Test that second-pass options get ignored in pass 1. // Also combine with loose stuff argv = { "loose file.wad", "", "--file", "doom.wad", "landing page.wad" }; M_ParseCommandLine(5, argv.data(), CommandLinePass::early, Pwad_list, options().data()); ASSERT_TRUE(Pwad_list.empty()); // On pass 2, they get combined M_ParseCommandLine(5, argv.data(), CommandLinePass::normal, Pwad_list, options().data()); ASSERT_EQ(Pwad_list.size(), 4); ASSERT_EQ(Pwad_list[0], "loose file.wad"); ASSERT_EQ(Pwad_list[1], ""); ASSERT_EQ(Pwad_list[2], "doom.wad"); ASSERT_EQ(Pwad_list[3], "landing page.wad"); Pwad_list.clear(); argv = { "loose file.wad", "", "-f", "doom.wad", "landing page.wad", "--merge", "res1.wad", "res2.wad" }; M_ParseCommandLine(8, argv.data(), CommandLinePass::normal, Pwad_list, options().data()); ASSERT_EQ(Pwad_list.size(), 4); ASSERT_EQ(Pwad_list[0], "loose file.wad"); ASSERT_EQ(Pwad_list[1], ""); ASSERT_EQ(Pwad_list[2], "doom.wad"); ASSERT_EQ(Pwad_list[3], "landing page.wad"); Pwad_list.clear(); ASSERT_EQ(config.loadedResourceList.size(), 2); ASSERT_EQ(config.loadedResourceList[0], "res1.wad"); ASSERT_EQ(config.loadedResourceList[1], "res2.wad"); config.loadedResourceList.clear(); // Test integer stuff argv = { "-backup_max_files", "-23", "--default_gamma", "25" }; M_ParseCommandLine(4, argv.data(), CommandLinePass::normal, Pwad_list, options().data()); ASSERT_EQ(config.backup_max_files, -23); ASSERT_EQ(config.usegamma, 25); config.backup_max_files = 30; config.usegamma = 2; // Test the boolean off options argv = { "-quiet", "off" }; config.Quiet = true; M_ParseCommandLine(2, argv.data(), CommandLinePass::early, Pwad_list, options().data()); ASSERT_FALSE(config.Quiet); argv = { "-q", "no" }; config.Quiet = true; M_ParseCommandLine(2, argv.data(), CommandLinePass::early, Pwad_list, options().data()); ASSERT_FALSE(config.Quiet); argv = { "--quiet", "false" }; config.Quiet = true; M_ParseCommandLine(2, argv.data(), CommandLinePass::early, Pwad_list, options().data()); ASSERT_FALSE(config.Quiet); argv = { "-quiet", "0" }; config.Quiet = true; M_ParseCommandLine(2, argv.data(), CommandLinePass::early, Pwad_list, options().data()); ASSERT_FALSE(config.Quiet); // Test the special warp behaviour argv = { "-warp", "map01" }; M_ParseCommandLine(2, argv.data(), CommandLinePass::normal, Pwad_list, options().data()); ASSERT_EQ(config.loadedLevelName, "map01"); // gets uppercase config.loadedLevelName.clear(); // Check that one argument is valid argv = { "--warp", "09" }; M_ParseCommandLine(2, argv.data(), CommandLinePass::normal, Pwad_list, options().data()); ASSERT_EQ(config.loadedLevelName, "09"); config.loadedLevelName.clear(); // Check that loose files can be located within argv = { "file1", "-warp", "map01", "file2", "--merge", "res1", "res2" }; M_ParseCommandLine(7, argv.data(), CommandLinePass::normal, Pwad_list, options().data()); ASSERT_EQ(Pwad_list.size(), 2); ASSERT_EQ(Pwad_list[0], "file1"); ASSERT_EQ(Pwad_list[1], "file2"); ASSERT_EQ(config.loadedLevelName, "map01"); ASSERT_EQ(config.loadedResourceList.size(), 2); ASSERT_EQ(config.loadedResourceList[0], "res1"); ASSERT_EQ(config.loadedResourceList[1], "res2"); Pwad_list.clear(); config.loadedLevelName.clear(); config.loadedResourceList.clear(); // Check that loose files can be located within and arguments can be redone argv = { "file1", "--warp", "map01", "file2", "-warp", "1", "3", "file3" }; M_ParseCommandLine(8, argv.data(), CommandLinePass::normal, Pwad_list, options().data()); ASSERT_EQ(Pwad_list.size(), 3); ASSERT_EQ(Pwad_list[0], "file1"); ASSERT_EQ(Pwad_list[1], "file2"); ASSERT_EQ(Pwad_list[2], "file3"); ASSERT_EQ(config.loadedLevelName, "13"); Pwad_list.clear(); config.loadedLevelName.clear(); // Check that stringList options can be repeatedly argumented argv = { "file1", "-file", "file2", "-merge", "res1", "--file", "file3", "file4", "-merge", "res2", "res3" }; M_ParseCommandLine(11, argv.data(), CommandLinePass::normal, Pwad_list, options().data()); ASSERT_EQ(Pwad_list.size(), 4); ASSERT_EQ(Pwad_list[0], "file1"); ASSERT_EQ(Pwad_list[1], "file2"); ASSERT_EQ(Pwad_list[2], "file3"); ASSERT_EQ(Pwad_list[3], "file4"); ASSERT_EQ(config.loadedResourceList.size(), 3); ASSERT_EQ(config.loadedResourceList[0], "res1"); ASSERT_EQ(config.loadedResourceList[1], "res2"); ASSERT_EQ(config.loadedResourceList[2], "res3"); Pwad_list.clear(); config.loadedResourceList.clear(); } TEST_F(MConfig, MParsePathListCommandLine) { std::vector argv; argv = { "--path", "", "/michael/jackson", ".", "..", "here/next", "here/../here", "here", "--onepath", "big guy" }; std::vector &Pwad_list = config.Pwad_list; M_ParseCommandLine((int)argv.size(), argv.data(), CommandLinePass::normal, Pwad_list, options().data()); ASSERT_EQ(config.paths.size(), 7); ASSERT_EQ(config.paths[0], fs::path("")); ASSERT_EQ(config.paths[1], fs::path("/") / "michael" / "jackson"); ASSERT_EQ(config.paths[2], fs::path(".")); ASSERT_EQ(config.paths[3], fs::path("..")); ASSERT_EQ(config.paths[4], fs::path("here") / "next"); ASSERT_EQ(config.paths[5].lexically_normal(), fs::path("here")); ASSERT_EQ(config.paths[6], fs::path("here")); ASSERT_EQ(config.onepath, fs::path("big guy")); } // M_PrintCommandLineOptions is tested in system testing static std::unordered_map> sUnitTokens; TEST_F(MConfig, InstanceMLoadUserState) { Instance inst; // crc32_c raw=1 extra=0 // Resulted filenme is cache_dir + "/cache/%08X%08X.dat" // crc.extra, crc.raw global::cache_dir = mTempDir; ASSERT_TRUE(FileMakeDir(getChildPath("cache"))); mDeleteList.push(getChildPath("cache")); // Try with no file: should fail ASSERT_FALSE(inst.M_LoadUserState()); // Prepare cache file std::ofstream os(getChildPath(fs::path("cache") / "0000000000000001.dat"), std::ios::trunc); ASSERT_TRUE(os.is_open()); mDeleteList.push(getChildPath(fs::path("cache") / "0000000000000001.dat")); os << " # Stuff\n"; os << "\n"; os << "editor \"hello world\" again\n"; os << "whatever is this\n"; // unhandled by any of these os << "recused\n"; os << "render3d image\n"; os << "browser preferred\n"; os << "grid high resolution\n"; os << "props properties \"\"\n"; os << "render3d again another rendering\n"; os << "grid low key\n"; os << " # Stuff\n"; os.close(); // We use the mockup handlers below to add to a map, which is global // Now it should work ASSERT_TRUE(inst.M_LoadUserState()); // TODO: check sUnitTokens ASSERT_EQ(sUnitTokens["editor"].size(), 3); ASSERT_EQ(sUnitTokens["editor"][0], "editor_editor"); ASSERT_EQ(sUnitTokens["editor"][1], "editor_hello world"); ASSERT_EQ(sUnitTokens["editor"][2], "editor_again"); ASSERT_EQ(sUnitTokens["recused"].size(), 1); ASSERT_EQ(sUnitTokens["recused"][0], "recused_recused"); ASSERT_EQ(sUnitTokens["render3d"].size(), 6); ASSERT_EQ(sUnitTokens["render3d"][0], "render3d_render3d"); ASSERT_EQ(sUnitTokens["render3d"][1], "render3d_image"); ASSERT_EQ(sUnitTokens["render3d"][2], "render3d_render3d"); ASSERT_EQ(sUnitTokens["render3d"][3], "render3d_again"); ASSERT_EQ(sUnitTokens["render3d"][4], "render3d_another"); ASSERT_EQ(sUnitTokens["render3d"][5], "render3d_rendering"); ASSERT_EQ(sUnitTokens["browser"].size(), 2); ASSERT_EQ(sUnitTokens["browser"][0], "browser_browser"); ASSERT_EQ(sUnitTokens["browser"][1], "browser_preferred"); ASSERT_EQ(sUnitTokens["grid"].size(), 6); ASSERT_EQ(sUnitTokens["grid"][0], "grid_grid"); ASSERT_EQ(sUnitTokens["grid"][1], "grid_high"); ASSERT_EQ(sUnitTokens["grid"][2], "grid_resolution"); ASSERT_EQ(sUnitTokens["grid"][3], "grid_grid"); ASSERT_EQ(sUnitTokens["grid"][4], "grid_low"); ASSERT_EQ(sUnitTokens["grid"][5], "grid_key"); // Keep in mind the last value gets called too ASSERT_EQ(sUnitTokens["props"].size(), 3); ASSERT_EQ(sUnitTokens["props"][0], "props_props"); ASSERT_EQ(sUnitTokens["props"][1], "props_properties"); ASSERT_EQ(sUnitTokens["props"][2], "props_"); ASSERT_EQ(sUnitTokens.size(), 6); // only these got stuff global::cache_dir.clear(); sUnitTokens.clear(); } TEST_F(MConfig, InstanceMSaveUserState) { Instance inst; ASSERT_FALSE(inst.M_SaveUserState()); // can't save if no location sUnitTokens.clear(); global::cache_dir = mTempDir; ASSERT_TRUE(FileMakeDir(getChildPath("cache"))); mDeleteList.push(getChildPath("cache")); ASSERT_TRUE(inst.M_SaveUserState()); mDeleteList.push(getChildPath(fs::path("cache") / "0000000000000001.dat")); global::cache_dir.clear(); ASSERT_EQ(sUnitTokens["WriteUser"].size(), 6); ASSERT_EQ(sUnitTokens["WriteUser"][0], "editor"); ASSERT_EQ(sUnitTokens["WriteUser"][1], "grid"); ASSERT_EQ(sUnitTokens["WriteUser"][2], "render3d"); ASSERT_EQ(sUnitTokens["WriteUser"][3], "browser"); ASSERT_EQ(sUnitTokens["WriteUser"][4], "props"); ASSERT_EQ(sUnitTokens["WriteUser"][5], "recused"); sUnitTokens.clear(); } TEST(MConfigBlank, InstanceMDefaultUserState) { sUnitTokens.clear(); Instance().M_DefaultUserState(); ASSERT_EQ(sUnitTokens["default"].size(), 4); ASSERT_EQ(sUnitTokens["default"][0], "gridInit"); ASSERT_EQ(sUnitTokens["default"][1], "zoomWholeMap"); ASSERT_EQ(sUnitTokens["default"][2], "renderSetup"); ASSERT_EQ(sUnitTokens["default"][3], "editorDefaultState"); sUnitTokens.clear(); } //======================================================================== // // Mockups // //======================================================================== static const int LINFO_Length = 1; int config::grid_style; // 0 = squares, 1 = dotty int config::gui_scheme = 1; // gtk+ bool config::bsp_on_save = true; bool config::bsp_force_v5 = false; bool config::bsp_gl_nodes = true; bool config::bsp_warnings = false; SString config::default_port = "vanilla"; int config::gui_color_set = 1; // bright rgb_color_t config::gui_custom_bg = rgbMake(0xCC, 0xD5, 0xDD); rgb_color_t config::gui_custom_ig = rgbMake(255, 255, 255); rgb_color_t config::gui_custom_fg = rgbMake(0, 0, 0); bool config::swap_sidedefs = false; bool config::bsp_compressed = false; rgb_color_t config::dotty_axis_col = rgbMake(0, 128, 255); int config::grid_ratio_low = 1; // (low must be > 0) bool config::begin_maximized = false; bool config::bsp_force_zdoom = false; rgb_color_t config::dotty_major_col = rgbMake(0, 0, 238); rgb_color_t config::dotty_minor_col = rgbMake(0, 0, 187); rgb_color_t config::dotty_point_col = rgbMake(0, 0, 255); int config::grid_ratio_high = 3; // custom ratio (high must be >= low) bool config::map_scroll_bars = true; int config::new_sector_size = 128; rgb_color_t config::normal_axis_col = rgbMake(0, 128, 255); rgb_color_t config::normal_main_col = rgbMake(0, 0, 238); rgb_color_t config::normal_flat_col = rgbMake(60, 60, 120); int config::render_far_clip = 32768; rgb_color_t config::transparent_col = rgbMake(0, 255, 255); bool config::auto_load_recent = false; int config::backup_max_files = 30; int config::backup_max_space = 60; // MB int config::bsp_split_factor = DEFAULT_FACTOR; int config::floor_bump_medium = 8; int config::floor_bump_large = 64; int config::floor_bump_small = 1; int config::light_bump_small = 4; int config::light_bump_medium = 16; int config::light_bump_large = 64; rgb_color_t config::normal_small_col = rgbMake(60, 60, 120); bool config::browser_small_tex = false; int config::default_edit_mode = 3; // Vertices int config::grid_default_size = 64; bool config::grid_default_snap = false; bool config::grid_default_mode = false; bool config::render_high_detail = false; bool config::browser_combine_tex = false; bool config::grid_snap_indicator = true; int config::highlight_line_info = (int)LINFO_Length; bool config::leave_offsets_alone = true; int config::minimum_drag_pixels = 5; bool config::render_lock_gravity = false; int config::render_pixel_aspect = 83; // 100 * width / height bool config::show_full_one_sided = false; int config::thing_render_default = 1; bool config::render_missing_bright = true; bool config::render_unknown_bright = true; int config::sector_render_default = (int)SREND_Floor; bool config::grid_hide_in_free_mode = false; bool config::sidedef_add_del_buttons = false; bool config::same_mode_clears_selection = false; bool config::bsp_fast = false; fs::path global::config_file; fs::path global::install_dir; bool global::show_version; fs::path global::home_dir; fs::path global::log_file; std::vector global::Pwad_list; fs::path global::cache_dir; bool global::show_help; Instance gInstance; bool Browser_ParseUser(Instance &inst, const std::vector &tokens) { if(tokens.empty() || tokens[0] != "browser") return false; for(const SString &token : tokens) sUnitTokens["browser"].push_back("browser_" + token); return true; } void grid::State::Init() { sUnitTokens["default"].push_back("gridInit"); } bool Props_ParseUser(Instance &inst, const std::vector &tokens) { if(tokens.empty() || tokens[0] != "props") return false; for(const SString &token : tokens) sUnitTokens["props"].push_back("props_" + token); return true; } void UI_DefaultProps::LoadValues() { sUnitTokens["props"].push_back("LoadValues"); } void Instance::ZoomWholeMap() { sUnitTokens["default"].push_back("zoomWholeMap"); } bool grid::State::parseUser(const std::vector &tokens) { if(tokens.empty() || tokens[0] != "grid") return false; for(const SString &token : tokens) sUnitTokens["grid"].push_back("grid_" + token); return true; } void Instance::Render3D_Setup() { sUnitTokens["default"].push_back("renderSetup"); } bool Instance::Editor_ParseUser(const std::vector &tokens) { if(tokens.empty() || tokens[0] != "editor") return false; for(const SString &token : tokens) sUnitTokens["editor"].push_back("editor_" + token); return true; } bool Instance::RecUsed_ParseUser(const std::vector &tokens) { if(tokens.empty() || tokens[0] != "recused") return false; for(const SString &token : tokens) sUnitTokens["recused"].push_back("recused_" + token); return true; } bool Instance::Render3D_ParseUser(const std::vector &tokens) { if(tokens.empty() || tokens[0] != "render3d") return false; for(const SString &token : tokens) sUnitTokens["render3d"].push_back("render3d_" + token); return true; } void Editor_State_t::defaultState() { sUnitTokens["default"].push_back("editorDefaultState"); } void Document::getLevelChecksum(crc32_c &crc) const { } void grid::State::writeUser(std::ostream &os) const { sUnitTokens["WriteUser"].push_back("grid"); } void Instance::Props_WriteUser(std::ostream &os) const { sUnitTokens["WriteUser"].push_back("props"); } void Instance::Editor_WriteUser(std::ostream &os) const { sUnitTokens["WriteUser"].push_back("editor"); } void Instance::Browser_WriteUser(std::ostream &os) const { sUnitTokens["WriteUser"].push_back("browser"); } void Instance::RecUsed_WriteUser(std::ostream &os) const { sUnitTokens["WriteUser"].push_back("recused"); } void Instance::Render3D_WriteUser(std::ostream &os) const { sUnitTokens["WriteUser"].push_back("render3d"); } DocumentModule::DocumentModule(Document &doc) : inst(doc.inst), doc(doc) { } void Basis::EditUnit::destroy() { } // UI_NodeDialog UI_NodeDialog::UI_NodeDialog() : Fl_Double_Window(100, 100) { } int UI_NodeDialog::handle(int event) { return 0; } void UI_Canvas::PointerPos(bool in_event) { } void UI_InfoBar::SetScale(double new_scale) { } void UI_InfoBar::SetGrid(int new_step) { } void UI_InfoBar::UpdateSnap() { } void UI_InfoBar::UpdateRatio() { } void UI_CanvasScroll::AdjustPos() { } void Instance::RedrawMap() { } eureka-editor-eureka-2.0.2/test/m_files_test.cpp000066400000000000000000000600361464327712600217060ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "testUtils/TempDirContext.hpp" #include "m_files.h" #include "m_loadsave.h" #include "m_parse.h" #include "m_streams.h" #include "filesystem.hpp" namespace fs = ghc::filesystem; #include "gtest/gtest.h" #define WAD_NAME "EurekaLump.wad" #define IMMEDIATE_RESOURCE "Michael" #define NESTED_RESOURCE "Jackson/George" // // Writing lump fixture // class EurekaLumpFixture : public TempDirContext { protected: LoadingData loaded; // keep a convenient pointer to the LoadingData }; TEST_F(EurekaLumpFixture, WriteEurekaLump) { static const char wadpathbase[] = "first/wad.wad"; fs::path wadpath(getChildPath(wadpathbase)); // Set up a nested directory WAD so we can test relative paths to resources std::shared_ptr wad = Wad_file::Open(wadpath, WadOpenMode::write); ASSERT_TRUE(wad); loaded.gameName = "Mood"; // just pick two random names loaded.portName = "Voom"; loaded.resourceList.push_back(getChildPath(fs::path("first") / "res.png")); // same path loaded.resourceList.push_back(getChildPath(fs::path("first") / "deep" / "call.txt")); // child path loaded.resourceList.push_back(getChildPath("upper.txt")); // upper path loaded.resourceList.push_back(getChildPath(fs::path("second") / "music.mid")); // sibling path // In case of Windows, also check different drive letter fs::path wadpathobj = fs::path(wadpath.c_str()); char otherdriveletter = '\0'; if(wadpathobj.has_root_name()) { char c = wadpathobj.u8string()[0]; c = toupper(c) < 'Z' ? c + 1 : 'A'; char otherpath[] = "C:\\other\\path"; otherpath[0] = c; otherdriveletter = c; loaded.resourceList.push_back(otherpath); } loaded.writeEurekaLump(*wad.get()); Lump_c *lump = wad->FindLump(EUREKA_LUMP); ASSERT_TRUE(lump); // Now read the data // Expected content is: SString expected = "# Eureka project info\n" "game Mood\n" "testing_command_line \"\"\n" "port Voom\n" "resource res.png\n" "resource deep/call.txt\n" "resource ../upper.txt\n" "resource ../second/music.mid\n" ; if(wadpathobj.has_root_name()) { expected += "resource "; expected += otherdriveletter; expected += ":/other/path\n"; } SString content(reinterpret_cast(lump->getData().data()), lump->Length()); ASSERT_EQ(content, expected); // Now make a change: remove port and resources, see that the lump is updated (not deleted). // Add a couple of lumps before and after before doing it, to see how it gets updated alone. wad->InsertPoint(0); wad->AddLump("BEFORE"); wad->InsertPoint(); wad->AddLump("LAST"); ASSERT_EQ(wad->NumLumps(), 3); loaded.portName.clear(); loaded.resourceList.clear(); loaded.writeEurekaLump(*wad.get()); // Check we still have 3 lumps ASSERT_EQ(wad->NumLumps(), 3); ASSERT_EQ(wad->GetLump(0)->Name(), "BEFORE"); ASSERT_EQ(wad->GetLump(1)->Name(), "LAST"); ASSERT_EQ(wad->GetLump(2)->Name(), EUREKA_LUMP); // moved to the end static const char expected2[] = { "# Eureka project info\n" "game Mood\n" "testing_command_line \"\"\n" }; lump = wad->GetLump(2); content = SString(reinterpret_cast(lump->getData().data()), lump->Length()); ASSERT_EQ(content, expected2); } // // Fixture for parsing. Depends on TempDirContext due to technicalities. // class ParseEurekaLumpFixture : public TempDirContext { protected: void SetUp() override; void TearDown() override; void assertEmptyLoading() const; void prepareHomeDir(); fs::path makeGamesDir(); void makeGame(const fs::path &gamesDir, const char *ughName); std::shared_ptr wad; LoadingData loading; fs::path home_dir, install_dir; RecentKnowledge recent; }; // // Init WAD and other stuff // void ParseEurekaLumpFixture::SetUp() { TempDirContext::SetUp(); wad = Wad_file::Open(getChildPath("wad.wad"), WadOpenMode::write); ASSERT_TRUE(wad); } // // Clear all globals // void ParseEurekaLumpFixture::TearDown() { DLG_Notify_Override = nullptr; DLG_Confirm_Override = nullptr; TempDirContext::TearDown(); } /* parseEurekaLump conditions: - Wad_file with written Eureka lump # test without lump - test with invalid syntax lines # global::home_dir, global::install_dir (must reset them) # test without any or both of them # base/.ugh, base/.ugh # test without that file, simulate dialog box # global::known_iwads (must reset it) # test without it - resource paths - try relative - try absolute - try inexistent resources - check that we don't add duplicate resources (SAME NAME RULE MAY NEED FIXING) */ // // Common check we didn't load anything // void ParseEurekaLumpFixture::assertEmptyLoading() const { ASSERT_TRUE(loading.gameName.empty()); ASSERT_TRUE(loading.portName.empty()); ASSERT_TRUE(loading.iwadName.empty()); ASSERT_TRUE(loading.resourceList.empty()); } // // Prepares the home directory // void ParseEurekaLumpFixture::prepareHomeDir() { home_dir = getChildPath("home"); ASSERT_TRUE(FileMakeDir(home_dir)); mDeleteList.push(home_dir); } // // Make the games directory, which it returns // fs::path ParseEurekaLumpFixture::makeGamesDir() { fs::path gamesDir = home_dir / "games"; EXPECT_TRUE(FileMakeDir(gamesDir)); mDeleteList.push(gamesDir); return gamesDir; } // // Make the game definition in the directory // void ParseEurekaLumpFixture::makeGame(const fs::path &gamesDir, const char *ughName) { fs::path ughPath = gamesDir / ughName; FILE *f = fopen(ughPath.u8string().c_str(), "wb"); ASSERT_TRUE(f); fclose(f); mDeleteList.push(ughPath); } TEST_F(ParseEurekaLumpFixture, TryWithoutLump) { // Safe on empty wad ASSERT_TRUE(loading.parseEurekaLump(home_dir, install_dir, recent, wad.get())); assertEmptyLoading(); // Safe on wad with some lumps Lump_c &lump1 = wad->AddLump("LUMP1"); lump1.Printf("Data 1"); Lump_c &lump2 = wad->AddLump("LUMP2"); lump2.Printf("Data 2"); ASSERT_EQ(wad->NumLumps(), 2); ASSERT_TRUE(loading.parseEurekaLump(home_dir, install_dir, recent, wad.get())); assertEmptyLoading(); } TEST_F(ParseEurekaLumpFixture, TryGameAndPort) { Lump_c &eureka = wad->AddLump(EUREKA_LUMP); eureka.Printf("game emag\n"); // have a game name there eureka.Printf("invalid syntax here\n"); eureka.Printf("port trop\n"); // add something else to check how we go // Situation 1: home, install dir unset // Prerequisite: set the DLG_Confirm override int decision = 0; bool gameWarning = false, iwadWarning = false, portWarning = false; DLG_Confirm_Override = [&decision, &gameWarning, &iwadWarning](const std::vector &, const char *message, va_list) { if(strstr(message, "game")) gameWarning = true; else if(strstr(message, "IWAD")) iwadWarning = true; return decision; }; DLG_Notify_Override = [&portWarning](const char *message, va_list) { if(strstr(message, "port")) portWarning = true; }; // Decide to keep trying, but nothing to get ASSERT_TRUE(loading.parseEurekaLump(home_dir, install_dir, recent, wad.get())); ASSERT_TRUE(loading.iwadName.empty()); ASSERT_TRUE(loading.portName.empty()); ASSERT_TRUE(gameWarning); ASSERT_FALSE(iwadWarning); ASSERT_TRUE(portWarning); // Situation 2: same, but with cancelling decision = 1; ASSERT_FALSE(loading.parseEurekaLump(home_dir, install_dir, recent, wad.get())); // Situation 3: add home dir prepareHomeDir(); fs::path gamesDir = makeGamesDir(); // but no emag.ugh: same problem decision = 0; // no ignore gameWarning = portWarning = false; ASSERT_TRUE(loading.parseEurekaLump(home_dir, install_dir, recent, wad.get())); ASSERT_TRUE(loading.iwadName.empty()); ASSERT_TRUE(loading.portName.empty()); ASSERT_TRUE(gameWarning); ASSERT_FALSE(iwadWarning); ASSERT_TRUE(portWarning); // Situation 4: add emag.ugh. But no known IWAD makeGame(gamesDir, "emag.ugh"); gameWarning = iwadWarning = portWarning = false; ASSERT_TRUE(loading.parseEurekaLump(home_dir, install_dir, recent, wad.get())); ASSERT_TRUE(loading.iwadName.empty()); ASSERT_TRUE(loading.portName.empty()); ASSERT_FALSE(gameWarning); ASSERT_TRUE(iwadWarning); ASSERT_TRUE(portWarning); // Situation 5: now add the IWAD fs::path iwadPath = getChildPath("emag.wad"); recent.addIWAD(iwadPath); // NOTE: no need to add file decision = 0; gameWarning = iwadWarning = portWarning = false; ASSERT_TRUE(loading.parseEurekaLump(home_dir, install_dir, recent, wad.get())); ASSERT_EQ(loading.iwadName, iwadPath); ASSERT_TRUE(loading.portName.empty()); ASSERT_FALSE(gameWarning); ASSERT_FALSE(iwadWarning); ASSERT_TRUE(portWarning); // Situation 6: now remove the home dir to see it won't be found fs::path goodHomeDir = home_dir; home_dir.clear(); decision = 1; gameWarning = iwadWarning = portWarning = false; ASSERT_FALSE(loading.parseEurekaLump(home_dir, install_dir, recent, wad.get())); // Situation 7: set the install dir instead install_dir = goodHomeDir; decision = 0; gameWarning = iwadWarning = portWarning = false; ASSERT_TRUE(loading.parseEurekaLump(home_dir, install_dir, recent, wad.get())); ASSERT_EQ(loading.iwadName, iwadPath); ASSERT_TRUE(loading.portName.empty()); ASSERT_FALSE(gameWarning); ASSERT_FALSE(iwadWarning); ASSERT_TRUE(portWarning); // Situation 8: add port home_dir = install_dir; fs::path portsDir = home_dir / "ports"; ASSERT_TRUE(FileMakeDir(portsDir)); mDeleteList.push(portsDir); fs::path tropPath = portsDir / "trop.ugh"; FILE *f = fopen(tropPath.u8string().c_str(), "wb"); ASSERT_TRUE(f); fclose(f); mDeleteList.push(tropPath); decision = 0; gameWarning = iwadWarning = portWarning = false; ASSERT_TRUE(loading.parseEurekaLump(home_dir, install_dir, recent, wad.get())); ASSERT_EQ(loading.iwadName, iwadPath); ASSERT_EQ(loading.portName, "trop"); ASSERT_FALSE(gameWarning); ASSERT_FALSE(iwadWarning); ASSERT_FALSE(portWarning); } TEST_F(ParseEurekaLumpFixture, TryResources) { Lump_c &eureka = wad->AddLump(EUREKA_LUMP); eureka.Printf("game doom\n"); eureka.Printf("resource samepath.wad\n"); eureka.Printf("resource samepath.wad\n"); // repeat so we check we don't add it again eureka.Printf("resource bogus/subpath.wad\n"); eureka.Printf("resource iwadpath.wad\n"); eureka.Printf("resource nopath.wad\n"); eureka.Printf("resource %s\n", getChildPath(fs::path("abs") / "abspath.wad").u8string().c_str()); eureka.Printf("resource \n"); // add something else to check how we go auto makesubfile = [this](const char *path) { fs::path filepath = getChildPath(path); FILE *f = fopen(filepath.u8string().c_str(), "wb"); ASSERT_TRUE(f); fclose(f); mDeleteList.push(filepath); }; makesubfile("samepath.wad"); makesubfile("subpath.wad"); // Prepare the IWAD fs::path path = getChildPath("iwad"); ASSERT_TRUE(FileMakeDir(path)); mDeleteList.push(path); recent.addIWAD(getChildPath(fs::path("iwad") / "doom.wad")); // Prepare the 'game' for the IWAD prepareHomeDir(); makeGame(makeGamesDir(), "doom.ugh"); // Add the resource at the IWAD path makesubfile("iwad/iwadpath.wad"); // And add the absolute subpath path = getChildPath("abs"); ASSERT_TRUE(FileMakeDir(path)); mDeleteList.push(path); makesubfile("abs/abspath.wad"); // Prepare the error message int errorcount = 0; SString errmsg; DLG_Notify_Override = [&errorcount, &errmsg](const char *message, va_list ap) { ++errorcount; errmsg = SString::vprintf(message, ap); }; loading.parseEurekaLump(home_dir, install_dir, recent, wad.get()); // Check that the sole error message we get is about nopath.wad ASSERT_EQ(errorcount, 1); ASSERT_NE(errmsg.find("nopath.wad"), SString::npos); // Check the resource content ASSERT_EQ(loading.resourceList.size(), 4); const auto &res = loading.resourceList; // Now check we have the resources, with their correct paths ASSERT_NE(std::find(res.begin(), res.end(), getChildPath("samepath.wad")), res.end()); ASSERT_NE(std::find(res.begin(), res.end(), getChildPath("subpath.wad")), res.end()); ASSERT_NE(std::find(res.begin(), res.end(), getChildPath(fs::path("iwad") / "iwadpath.wad")), res.end()); ASSERT_NE(std::find(res.begin(), res.end(), getChildPath(fs::path("abs") / "abspath.wad")), res.end()); } TEST_F(ParseEurekaLumpFixture, ResourcesAreUniqueByFileNameNoCase) { Lump_c &eureka = wad->AddLump(EUREKA_LUMP); eureka.Printf("game doom\n"); eureka.Printf("resource samename.wad\n"); eureka.Printf("resource sub/SameName.Wad\n"); // repeat so we check we don't add it again eureka.Printf("resource othername.wad\n"); // Make the files std::ofstream stream; fs::path path = getChildPath("samename.wad"); stream.open(path); ASSERT_TRUE(stream.is_open()); stream.close(); mDeleteList.push(path); path = getChildPath("sub"); ASSERT_TRUE(FileMakeDir(path)); mDeleteList.push(path); path = getChildPath("sub/SameName.Wad"); stream.open(path); ASSERT_TRUE(stream.is_open()); stream.close(); mDeleteList.push(path); path = getChildPath("othername.wad"); stream.open(path); ASSERT_TRUE(stream.is_open()); stream.close(); mDeleteList.push(path); stream.close(); // Prepare the IWAD path = getChildPath("iwad"); ASSERT_TRUE(FileMakeDir(path)); mDeleteList.push(path); recent.addIWAD(getChildPath("iwad/doom.wad")); // Prepare the 'game' for the IWAD prepareHomeDir(); makeGame(makeGamesDir(), "doom.ugh"); loading.parseEurekaLump(home_dir, install_dir, recent, wad.get()); ASSERT_EQ(loading.resourceList.size(), 2); ASSERT_EQ(loading.resourceList[0], getChildPath("samename.wad")); // not the second one too ASSERT_EQ(loading.resourceList[1], getChildPath("othername.wad")); } TEST_F(ParseEurekaLumpFixture, TryResourcesParentPath) { // Re-create wad to be from a subpath ASSERT_TRUE(FileMakeDir(getChildPath("sub"))); mDeleteList.push(getChildPath("sub")); wad = Wad_file::Open(getChildPath(fs::path("sub") / "wad.wad"), WadOpenMode::write); ASSERT_TRUE(wad); // Create a parent path resource FILE *f = fopen(getChildPath("res.wad").u8string().c_str(), "wb"); ASSERT_TRUE(f); fclose(f); mDeleteList.push(getChildPath("res.wad")); // Prepare the lump Lump_c &eureka = wad->AddLump(EUREKA_LUMP); // Try to use just path: won't be found eureka.Printf("resource res.wad\n"); int errorcount = 0; DLG_Notify_Override = [&errorcount](const char *message, va_list ap) { ++errorcount; }; loading.parseEurekaLump(home_dir, install_dir, recent, wad.get()); ASSERT_EQ(errorcount, 1); ASSERT_TRUE(loading.resourceList.empty()); // Now change content and add a relative path eureka.clearData(); eureka.Printf("resource ../res.wad\n"); loading.parseEurekaLump(home_dir, install_dir, recent, wad.get()); ASSERT_EQ(errorcount, 1); ASSERT_EQ(loading.resourceList.size(), 1); ASSERT_EQ(loading.resourceList[0], getChildPath("res.wad")); } // Recent files TEST(RecentFiles, StartEmpty) { RecentFiles_c files; ASSERT_EQ(files.getSize(), 0); // Clear it: still empty files.clear(); ASSERT_EQ(files.getSize(), 0); } TEST(RecentFiles, InsertAndLookup) { RecentFiles_c files; files.insert("Wad1.wad", "MAP01"); files.insert("Sub/Doo.wad", "E3M6"); files.insert("SomeOther.wad", "E4M4"); files.insert("Jack.wad", "H5M5"); files.insert("Other/Jack.wad", "H5M6"); // will override previous map files.insert("Doo.wad", "MAP03"); // this will override second map // Size must be 3 ASSERT_EQ(files.getSize(), 4); // Five made it RecentMap recentMap; recentMap = files.Lookup(0); ASSERT_EQ(recentMap.file, "Doo.wad"); ASSERT_EQ(recentMap.map, "MAP03"); recentMap = files.Lookup(1); ASSERT_EQ(recentMap.file, "Other/Jack.wad"); ASSERT_EQ(recentMap.map, "H5M6"); recentMap = files.Lookup(2); ASSERT_EQ(recentMap.file, "SomeOther.wad"); ASSERT_EQ(recentMap.map, "E4M4"); recentMap = files.Lookup(3); ASSERT_EQ(recentMap.file, "Wad1.wad"); ASSERT_EQ(recentMap.map, "MAP01"); // See one format SString text = files.Format(1); ASSERT_EQ(text, " &2: Jack.wad"); // Get one data RecentMap vdata = files.Lookup(1); ASSERT_EQ(vdata.file, "Other/Jack.wad"); ASSERT_EQ(vdata.map, "H5M6"); // Test clearing it files.clear(); ASSERT_EQ(files.getSize(), 0); } TEST(RecentFiles, InsertPastCap) { RecentFiles_c files; for(int i = 0; i < MAX_RECENT + 3; ++i) { files.insert(fs::path("sub") / SString::printf("Wad%d.wad", i).get(), SString::printf("MAP%d", i)); } // Still max recent entries ASSERT_EQ(files.getSize(), MAX_RECENT); // Check that the latest recent are there for(int i = 0; i < MAX_RECENT; ++i) { RecentMap recentMap = files.Lookup(i); ASSERT_EQ(SString(recentMap.file.generic_u8string()), SString::printf("sub/Wad%d.wad", MAX_RECENT + 3 - i - 1)); ASSERT_EQ(recentMap.map, SString::printf("MAP%d", MAX_RECENT + 3 - i - 1)); } // Test formatting when larger than 9 SString text; for(int i = 0; i < 9; ++i) { text = files.Format(i); ASSERT_EQ(text, SString::printf(" &%d: Wad%d.wad", i + 1, MAX_RECENT + 3 - i - 1)); } for(int i = 9; i < MAX_RECENT; ++i) { text = files.Format(i); ASSERT_EQ(text, SString::printf("%d: Wad%d.wad", i + 1, MAX_RECENT + 3 - i - 1)); } } class RecentFilesFixture : public TempDirContext { }; TEST_F(RecentFilesFixture, WriteFile) { RecentFiles_c files; files.insert("Wad1.wad", "MAP01"); files.insert("Sub/Doo.wad", "E3M6"); files.insert("SomeOther.wad", "E4 M4"); files.insert("Jack.wad", "H5M5"); files.insert("Oth er/Jack.wad", "H5M6"); // will override previous map files.insert("Doo.wad", "MAP03"); // this will override second map fs::path datapath = getChildPath("data.ini"); std::ofstream os(datapath); ASSERT_TRUE(os.is_open()); mDeleteList.push(datapath); files.Write(os); os.close(); std::ifstream stream(datapath); ASSERT_TRUE(stream.is_open()); std::string keyword, map, file; stream >> keyword >> map >> file; ASSERT_EQ(keyword, "recent"); ASSERT_EQ(map, "MAP01"); ASSERT_EQ(file, "Wad1.wad"); std::string line; std::getline(stream, line); // get past current line std::getline(stream, line); ASSERT_EQ(line, "recent \"E4 M4\" SomeOther.wad"); std::getline(stream, line); ASSERT_EQ(line, "recent H5M6 \"Oth er/Jack.wad\""); stream >> keyword >> map >> file; ASSERT_EQ(keyword, "recent"); ASSERT_EQ(map, "MAP03"); ASSERT_EQ(file, "Doo.wad"); ASSERT_FALSE(stream.eof()); stream >> keyword; ASSERT_TRUE(stream.eof()); stream.close(); } TEST_F(RecentFilesFixture, MLoadRecent) { fs::path home_dir = mTempDir; RecentKnowledge recent; // TODO: write the files // TODO: write the necessary IWADs fs::path path = getChildPath("misc.cfg"); std::ofstream stream(path); ASSERT_TRUE(stream.is_open()); mDeleteList.push(path); stream << "# Misc.cfg file" << std::endl; stream << "# recent E1M1 doom.wad" << std::endl; // ignore comment stream << " " << std::endl; // ignore blank line stream << " # comment after line" << std::endl; // ignore comment after space fs::path hticPath = getChildPath("htic.wad"); fs::path doom3Path = getChildPath("doom3.wad"); fs::path freedoomPath = getChildPath("freedoom.wad"); fs::path deletedPath = getChildPath("deleted.wad"); fs::path badPath = getChildPath("bad.wad"); fs::path hereticPath = getChildPath("here tic.wad"); stream << "recent MAP02 " << escape(doom3Path) << " # recent" << std::endl; stream << "recent H5M6 " << std::endl; // malformed stream << "recent E1M1 " << escape(badPath) << std::endl; // invalid wad stream << "recent E3M5 " << escape(hereticPath) << std::endl; stream << "recent \"E3 M5\" " << escape(hticPath) << std::endl; stream << "recent E7M7 " << escape(deletedPath) << std::endl; // missing wad stream << "recent MAP03 " << escape(doom3Path) << std::endl; // should overwrite the other Doom3 wad recent stream << "known_iwad heretic " << escape(hticPath) << std::endl; stream << "known_iwad mood " << std::endl; // malformed stream << "known_iwad \"doom \"\"3\"\"\" " << escape(doom3Path) << std::endl; stream << "known_iwad FreeDoom " << escape(freedoomPath) << std::endl; // ignore freedoom stream << "known_iwad inexistent " << escape(deletedPath) << std::endl; // file not found stream << "known_iwad malformed " << escape(badPath) << std::endl; // bad file (both cases should be "invalid" stream << "known_iwad heretic " << escape(hereticPath) << std::endl; // overwrite stream << "port_path boom |/home/jillson/boom.wad" << std::endl; stream << "port_path zdoom |/home/jillson/zdoom.wad" << std::endl; stream << "port_path goom /home/jillson/goom.wad" << std::endl; // malformed stream << "port_path zdoom | /home/jackson/zdoom.wad" << std::endl; // overwrite stream.close(); // Prepare the IWAD files for(const fs::path &path : { hticPath, doom3Path, freedoomPath, badPath, hereticPath }) { std::ofstream wadstream(path, std::ios::binary); ASSERT_TRUE(wadstream.is_open()); mDeleteList.push(path); if(path != badPath) wadstream.write("PWAD\0\0\0\0\x0c\0\0\0", 12); ASSERT_FALSE(wadstream.fail()); wadstream.close(); } recent.load(home_dir); // Check the recent files ASSERT_EQ(recent.getFiles().getSize(), 3); RecentMap recentMap; recentMap = recent.getFiles().Lookup(0); ASSERT_EQ(recentMap.file, doom3Path); ASSERT_EQ(recentMap.map, "MAP03"); recentMap = recent.getFiles().Lookup(1); ASSERT_EQ(recentMap.file, hticPath); ASSERT_EQ(recentMap.map, "E3 M5"); recentMap = recent.getFiles().Lookup(2); ASSERT_EQ(recentMap.file, hereticPath); ASSERT_EQ(recentMap.map, "E3M5"); // Check the known IWADs map ASSERT_TRUE(recent.queryIWAD("heretic")); ASSERT_EQ(*recent.queryIWAD("heretic"), hereticPath); ASSERT_TRUE(recent.queryIWAD("doom \"3\"")); ASSERT_EQ(*recent.queryIWAD("doom \"3\""), doom3Path); // Check the port paths ASSERT_TRUE(recent.queryPortPath("zdoom")); ASSERT_EQ(*recent.queryPortPath("zdoom"), "/home/jackson/zdoom.wad"); ASSERT_TRUE(recent.queryPortPath("boom")); ASSERT_EQ(*recent.queryPortPath("boom"), "/home/jillson/boom.wad"); } TEST_F(RecentFilesFixture, MSaveRecent) { RecentKnowledge recent; recent.addRecent("file1", "map1", mTempDir); recent.addRecent("file2", "map 2", mTempDir); recent.addRecent("file1/file 4", "map #", mTempDir); recent.addIWAD("path/doom1.wad"); recent.addIWAD("path/doom #.wad"); recent.setPortPath("foom", "port/foom.exe"); recent.setPortPath("joom generation", "port/joom generation.exe"); recent.save(mTempDir); mDeleteList.push(mTempDir / "misc.cfg"); // Now check std::ifstream is(mTempDir / "misc.cfg"); ASSERT_TRUE(is.is_open()); SString line; RecentFiles_c readRecentFiles; std::map readKnownIwads; std::map readPortPaths; while(M_ReadTextLine(line, is)) { TokenWordParse parse(line, true); SString keyword; if(!parse.getNext(keyword)) continue; SString name; fs::path path; ASSERT_TRUE(parse.getNext(name)); ASSERT_TRUE(parse.getNext(path)); if(keyword == "recent") { readRecentFiles.insert(path, name); continue; } if(keyword == "known_iwad") { readKnownIwads[name] = path; continue; } if(keyword == "port_path") { ASSERT_EQ(path.u8string()[0], '|'); if(path == "|") { ASSERT_TRUE(parse.getNext(path)); readPortPaths[name] = path; } else readPortPaths[name] = fs::u8path(path.u8string().substr(1)); continue; } } // Now check content ASSERT_EQ(readRecentFiles.getSize(), 3); for(int i = 0; i < readRecentFiles.getSize(); ++i) { SString readMap; fs::path readPath; RecentMap myRecentMap = recent.getFiles().Lookup(i); RecentMap readRecentMap = readRecentFiles.Lookup(i); ASSERT_EQ(myRecentMap.map, readRecentMap.map); ASSERT_EQ(myRecentMap.file, readRecentMap.file); } for(const auto &item : readKnownIwads) { ASSERT_TRUE(recent.queryIWAD(item.first)); ASSERT_EQ(*recent.queryIWAD(item.first), item.second); } for(const auto &item : readPortPaths) { ASSERT_TRUE(recent.queryPortPath(item.first)); ASSERT_EQ(*recent.queryPortPath(item.first), item.second); } } eureka-editor-eureka-2.0.2/test/m_game_test.cpp000066400000000000000000000104661464327712600215170ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2021 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "testUtils/TempDirContext.hpp" #include "gtest/gtest.h" #include "Instance.h" #include "m_game.h" class MGameFixture : public TempDirContext { }; //============================================================================= // // TESTS // //============================================================================= // // Convenience operator // static bool operator == (const thingtype_t &type1, const thingtype_t &type2) { return type1.group == type2.group && type1.flags == type2.flags && type1.radius == type2.radius && type1.scale == type2.scale && type1.desc == type2.desc && type1.sprite == type2.sprite && type1.color == type2.color && type1.args[0] == type2.args[0] && type1.args[1] == type2.args[1] && type1.args[2] == type2.args[2] && type1.args[3] == type2.args[3] && type1.args[4] == type2.args[4]; } TEST(MGame, ConfigDataGetThingType) { ConfigData config = {}; thingtype_t type = {}; type.group = 'a'; type.flags = THINGDEF_LIT; type.radius = 16; type.scale = 1.0f; type.desc = "Bright spot"; type.sprite = "BRIG"; type.color = rgbMake(128, 0, 0); config.thing_types[111] = type; thingtype_t type2 = {}; type2.group = 'b'; type2.flags = 0; type2.radius = 16; type2.scale = 1.0f; type2.desc = "Dark spot"; type2.sprite = "DARK"; type2.color = rgbMake(0, 0, 128); config.thing_types[222] = type2; ASSERT_EQ(config.getThingType(111), type); ASSERT_EQ(config.getThingType(222), type2); ASSERT_EQ(config.getThingType(1).desc, "UNKNOWN TYPE"); ASSERT_EQ(config.getThingType(0).desc, "UNKNOWN TYPE"); ASSERT_EQ(config.getThingType(-1).desc, "UNKNOWN TYPE"); } TEST_F(MGameFixture, MCollectKnownDefs) { // // Helper to make dir and put it to stack // auto makeDir = [this](const fs::path &path) { ASSERT_TRUE(FileMakeDir(path)); mDeleteList.push(path); }; // // Helper to create empty file, complete with check // auto makeFile = [this](const fs::path &path) { std::ofstream os(path); ASSERT_TRUE(os.is_open()); mDeleteList.push(path); }; // We need the install and home dirs for this test const fs::path install_dir = getChildPath("install"); makeDir(install_dir); const fs::path home_dir = getChildPath("home"); makeDir(home_dir); // Now add some other folder inside both of them const fs::path folder = "conf"; const fs::path home = home_dir / folder; const fs::path install = install_dir / folder; makeDir(install); makeDir(home); // Now add unrelated folders in each fs::path unrelated[2] = {install_dir / "unrel", home_dir / "ated"}; for(const fs::path &unrel : unrelated) makeDir(unrel); // Now produce all sorts of files makeFile(install / "empty"); makeFile(install / "hasugh.ugh"); makeFile(install / "DOOM.ugh"); makeFile(install / "Config.cfg"); makeFile(install / "MooD.uGH"); makeFile(home / "doom.UGH"); makeFile(home / "Heretic.Ugh"); makeFile(home / "Junk"); makeFile(home / "extra.cfg"); makeFile(home / ".hidden.ugh"); // skip for being hidden makeDir(home / "directory.ugh"); // skip for being dir makeFile(home / "directory.ugh" / "subfile.ugh"); // skip for being under dir makeDir(home / "folder"); makeFile(home / "folder" / "subfile2.ugh"); // make sure to always skip subdir makeFile(home / "Extra.ugh"); makeFile(unrelated[0] / "bandit.ugh"); makeFile(unrelated[0] / "brigand.ugh"); makeFile(unrelated[1] / "jackson.ugh"); makeFile(unrelated[1] / "jordan.cfg"); // Requirement: the last entry takes precedence and it's sorted. // Hidden and dirs are skipped auto expected = std::vector{"doom", "Extra", "hasugh", "Heretic", "MooD"}; ASSERT_EQ(M_CollectKnownDefs({install_dir, home_dir}, folder), expected); } eureka-editor-eureka-2.0.2/test/m_keys_test.cpp000066400000000000000000000155271464327712600215640ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2021 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "m_keys.h" #include "testUtils/TempDirContext.hpp" #include "Instance.h" #ifdef __APPLE__ #define CMD "CMD" #else #define CMD "CTRL" #endif void DLG_Notify(EUR_FORMAT_STRING(const char *msg), ...) { } void DLG_ShowError(bool fatal, EUR_FORMAT_STRING(const char* msg), ...) { } static int sUpdates; namespace menu { void updateBindings(Fl_Sys_Menu_Bar *) { ++sUpdates; } } void Instance::Status_Set(EUR_FORMAT_STRING(const char *fmt), ...) const { } //======================================================================== // // Fixture // class MKeys : public TempDirContext { protected: void SetUp() override { TempDirContext::SetUp(); static bool loaded; if(!loaded) { static editor_command_t commands[] = { { "BR_ClearSearch", "Browser", nullptr }, { "BR_Scroll", "Browser", nullptr }, { "3D_NAV_Left", NULL, nullptr }, { "3D_NAV_Right", NULL, nullptr }, { "LIN_SelectPath", NULL, nullptr }, { "GivenFile", "File", nullptr }, { "Insert", "Edit", nullptr }, { "Delete", "Edit", nullptr }, { "Mirror", "General", nullptr }, { nullptr, nullptr, nullptr }, }; M_RegisterCommandList(commands); loaded = true; } global::home_dir = mTempDir; global::install_dir = getChildPath("install"); ASSERT_TRUE(FileMakeDir(global::install_dir)); mDeleteList.push(global::install_dir); writeBindingsFile(); M_LoadBindings(); --sUpdates; // don't increment it here } void TearDown() override { global::config_file.clear(); global::install_dir.clear(); global::home_dir.clear(); sUpdates = 0; // reset it to 0 TempDirContext::TearDown(); } private: void writeBindingsFile(); }; // // Write the bindings file // void MKeys::writeBindingsFile() { FILE *f = fopen((global::install_dir / "bindings.cfg").u8string().c_str(), "wt"); ASSERT_NE(f, nullptr); mDeleteList.push(global::install_dir / "bindings.cfg"); fprintf(f, "browser CMD-k BR_ClearSearch\n"); fprintf(f, "browser PGUP BR_Scroll -3\n"); fprintf(f, "browser PGDN BR_Scroll +3\n"); fprintf(f, "render ALT-LEFT 3D_NAV_Left 384\n"); fprintf(f, "render ALT-RIGHT 3D_NAV_Right 384\n"); fprintf(f, "line E LIN_SelectPath /sametex\n"); fprintf(f, "general META-n GivenFile next\n"); fprintf(f, "general CMD-SPACE Insert /nofill\n"); int n = fclose(f); ASSERT_EQ(n, 0); f = fopen((global::home_dir / "bindings.cfg").u8string().c_str(), "wt"); ASSERT_NE(f, nullptr); mDeleteList.push(global::home_dir / "bindings.cfg"); fprintf(f, "general SHIFT-DEL Delete /keep\n"); fprintf(f, "general SHIFT-BS Delete /keep\n"); fprintf(f, "general CMD-k Mirror horiz\n"); n = fclose(f); ASSERT_EQ(n, 0); } TEST_F(MKeys, MKeyToString) { ASSERT_EQ(M_KeyToString(EMOD_COMMAND | 'a'), CMD "-a"); ASSERT_EQ(M_KeyToString(EMOD_SHIFT | 'a'), "A"); ASSERT_EQ(M_KeyToString(EMOD_SHIFT | FL_Page_Up), "SHIFT-PGUP"); ASSERT_EQ(M_KeyToString(EMOD_META | FL_Page_Down), "META-PGDN"); } TEST_F(MKeys, MIsKeyBound) { ASSERT_TRUE(M_IsKeyBound(FL_Page_Up, KeyContext::browser)); ASSERT_TRUE(M_IsKeyBound(EMOD_COMMAND | 'k', KeyContext::browser)); ASSERT_TRUE(M_IsKeyBound(EMOD_COMMAND | 'k', KeyContext::general)); ASSERT_TRUE(M_IsKeyBound(EMOD_SHIFT | 'e', KeyContext::line)); ASSERT_FALSE(M_IsKeyBound(EMOD_COMMAND | 'k', KeyContext::render)); } TEST_F(MKeys, MRemoveBindingAndSave) { ASSERT_TRUE(M_IsKeyBound(EMOD_SHIFT | FL_BackSpace, KeyContext::general)); M_RemoveBinding(EMOD_SHIFT | FL_BackSpace, KeyContext::vertex); ASSERT_TRUE(M_IsKeyBound(EMOD_SHIFT | FL_BackSpace, KeyContext::general)); M_RemoveBinding(EMOD_SHIFT | FL_BackSpace, KeyContext::general); ASSERT_FALSE(M_IsKeyBound(EMOD_SHIFT | FL_BackSpace, KeyContext::general)); M_RemoveBinding(EMOD_ALT | FL_Left, KeyContext::render); ASSERT_FALSE(M_IsKeyBound(EMOD_ALT | FL_Left, KeyContext::render)); M_SaveBindings(); M_LoadBindings(); ASSERT_TRUE(M_IsKeyBound(EMOD_COMMAND | 'k', KeyContext::browser)); ASSERT_TRUE(M_IsKeyBound(FL_Page_Up, KeyContext::browser)); ASSERT_TRUE(M_IsKeyBound(FL_Page_Down, KeyContext::browser)); ASSERT_FALSE(M_IsKeyBound(EMOD_ALT | FL_Left, KeyContext::render)); ASSERT_TRUE(M_IsKeyBound(EMOD_ALT | FL_Right, KeyContext::render)); ASSERT_TRUE(M_IsKeyBound(EMOD_SHIFT | 'e', KeyContext::line)); ASSERT_TRUE(M_IsKeyBound(EMOD_META | 'n', KeyContext::general)); ASSERT_TRUE(M_IsKeyBound(EMOD_COMMAND | ' ', KeyContext::general)); ASSERT_TRUE(M_IsKeyBound(EMOD_SHIFT | FL_Delete, KeyContext::general)); ASSERT_FALSE(M_IsKeyBound(EMOD_SHIFT | FL_BackSpace, KeyContext::general)); ASSERT_TRUE(M_IsKeyBound(EMOD_COMMAND | 'k', KeyContext::general)); } TEST_F(MKeys, FindKeyCodeForCommandName) { const char *params[MAX_EXEC_PARAM] = {}; keycode_t code = 0; params[0] = "-3"; ASSERT_TRUE(findKeyCodeForCommandName("BR_Scroll", params, &code)); ASSERT_EQ(code, FL_Page_Up); params[0] = "+3"; ASSERT_TRUE(findKeyCodeForCommandName("BR_Scroll", params, &code)); ASSERT_EQ(code, FL_Page_Down); params[0] = nullptr; ASSERT_FALSE(findKeyCodeForCommandName("Mirror", params, &code)); params[0] = "horiz"; ASSERT_TRUE(findKeyCodeForCommandName("Mirror", params, &code)); ASSERT_EQ(code, EMOD_COMMAND | 'k'); } TEST_F(MKeys, UpdateMenuBindingsCall) { ASSERT_EQ(sUpdates, 0); M_LoadBindings(); ASSERT_EQ(sUpdates, 1); // Restore M_CopyBindings(); ASSERT_EQ(sUpdates, 1); M_ChangeBindingKey(0, 'a'); ASSERT_EQ(sUpdates, 1); M_ApplyBindings(); ASSERT_EQ(sUpdates, 2); const char *params[MAX_EXEC_PARAM] = {}; keycode_t code = 0; ASSERT_TRUE(findKeyCodeForCommandName("BR_ClearSearch", params, &code)); ASSERT_EQ(code, 'a'); ASSERT_EQ(sUpdates, 2); } eureka-editor-eureka-2.0.2/test/m_parse_test.cpp000066400000000000000000000154311464327712600217150ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2021 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "m_parse.h" #include "m_strings.h" #include "gtest/gtest.h" TEST(MParse, MParseLine) { SString line; std::vector tokens; static const ParseOptions allOptions[] = { ParseOptions::noStrings, ParseOptions::haveStrings, ParseOptions::haveStringsKeepQuotes }; // Common option tests for(ParseOptions option : allOptions) { // Test for empty lines ASSERT_EQ(M_ParseLine("", tokens, option), 0); ASSERT_EQ(M_ParseLine(" ", tokens, option), 0); ASSERT_EQ(M_ParseLine(" \t ", tokens, option), 0); // Comments shouldn't count ASSERT_EQ(M_ParseLine("\t\t#Hello comment", tokens, option), 0); ASSERT_EQ(M_ParseLine(" # Hello comment", tokens, option), 0); // Newline should end the parsing ASSERT_EQ(M_ParseLine(" # Hello comment \n Hello next line", tokens, option), 0); ASSERT_EQ(M_ParseLine(" # Hello comment \r\n Hello next line", tokens, option), 0); // Except if it's after an empty line, then we just go ahead ASSERT_EQ(M_ParseLine("\n Hello next line", tokens, option), 3); ASSERT_EQ(tokens[0], "Hello"); ASSERT_EQ(tokens[1], "next"); ASSERT_EQ(tokens[2], "line"); // Now we have something going on. The comment and next line ASSERT_EQ(M_ParseLine(" Fir+st, .line \r\n Hello next line", tokens, option), 2); // Check that operators become part of tokens ASSERT_EQ(tokens[0], "Fir+st,"); ASSERT_EQ(tokens[1], ".line"); // Check that no crash happens if last line is newline AND that comments can only be on // start of line ASSERT_EQ(M_ParseLine(" Trailed line #here\n", tokens, option), 3); ASSERT_EQ(tokens[0], "Trailed"); ASSERT_EQ(tokens[1], "line"); ASSERT_EQ(tokens[2], "#here"); // Same if spaced apart ASSERT_EQ(M_ParseLine(" Trailed line # here\n", tokens, option), 4); ASSERT_EQ(tokens[0], "Trailed"); ASSERT_EQ(tokens[1], "line"); ASSERT_EQ(tokens[2], "#"); ASSERT_EQ(tokens[3], "here"); } // Check haveStrings static const ParseOptions stringOptions[] = { ParseOptions::haveStrings, ParseOptions::haveStringsKeepQuotes }; auto assertQuoted = [](const SString &token, const char *value, ParseOptions option) { if(option == ParseOptions::haveStrings) ASSERT_EQ(token, value); else // haveStringsKeepQuotes ASSERT_EQ(token, SString("\"") + value + "\""); }; // Check unterminated string for(ParseOptions option : stringOptions) { // Check that unterminated quote is illegal ASSERT_EQ(M_ParseLine("Hello unterminated \"quote here", tokens, option), ParseLine_stringError); // Check that simple quote is illegal ASSERT_EQ(M_ParseLine("\"", tokens, option), ParseLine_stringError); // Check that newline in string is illegal ASSERT_EQ(M_ParseLine("Hello newline \"string\n here\"", tokens, option), ParseLine_stringError); // Now check string ASSERT_EQ(M_ParseLine("Hello, \"multi word string\" here!", tokens, option), 3); ASSERT_EQ(tokens[0], "Hello,"); assertQuoted(tokens[1], "multi word string", option); ASSERT_EQ(tokens[2], "here!"); // Check that string starting with # is legal ASSERT_EQ(M_ParseLine("\"#multi word\" here.", tokens, option), 2); assertQuoted(tokens[0], "#multi word", option); ASSERT_EQ(tokens[1], "here."); // Check that empty string is a token in itself ASSERT_EQ(M_ParseLine("Here's \"\" empty string", tokens, option), 4); ASSERT_EQ(tokens[0], "Here's"); assertQuoted(tokens[1], "", option); ASSERT_EQ(tokens[2], "empty"); ASSERT_EQ(tokens[3], "string"); // Check that touching strings is legal ASSERT_EQ(M_ParseLine("\"three\"\"\"\"strings\"", tokens, option), 3); assertQuoted(tokens[0], "three", option); assertQuoted(tokens[1], "", option); assertQuoted(tokens[2], "strings", option); // Check that just three """ is illegal ASSERT_EQ(M_ParseLine("\"\"\"", tokens, option), ParseLine_stringError); } } TEST(MParse, TokenWordParse) { TokenWordParse parse("word1 w2 ...g3+gh-\\ \"\" \"have\"\"double word\" \"\"\"\" \"Veac#caev\"#Jackson", true); std::vector words; SString word; while(parse.getNext(word)) words.push_back(word); ASSERT_EQ(words.size(), 7); ASSERT_EQ(words[0], "word1"); ASSERT_EQ(words[1], "w2"); ASSERT_EQ(words[2], "...g3+gh-\\"); ASSERT_EQ(words[3], ""); ASSERT_EQ(words[4], "have\"double word"); ASSERT_EQ(words[5], "\""); ASSERT_EQ(words[6], "Veac#caev"); } TEST(MParse, TokenWordParsePath) { TokenWordParse parse("word1 w2/w3 word3", true); SString word; fs::path path; ASSERT_TRUE(parse.getNext(word)); ASSERT_EQ(word, "word1"); ASSERT_TRUE(parse.getNext(path)); ASSERT_EQ(path, fs::path("w2") / "w3"); ASSERT_TRUE(parse.getNext(word)); ASSERT_EQ(word, "word3"); } TEST(MParse, TokenWordParseEmpty) { TokenWordParse parse(" \t\t\r\n", true); SString word; ASSERT_FALSE(parse.getNext(word)); TokenWordParse parse2("", true); ASSERT_FALSE(parse2.getNext(word)); } TEST(MParse, TokenWordParseUnendedQuote) { SString word; TokenWordParse parse3("\"", true); ASSERT_TRUE(parse3.getNext(word)); ASSERT_EQ(word, ""); ASSERT_FALSE(parse3.getNext(word)); TokenWordParse parse4("\"jackson", true); ASSERT_TRUE(parse4.getNext(word)); ASSERT_EQ(word, "jackson"); ASSERT_FALSE(parse4.getNext(word)); } TEST(MParse, TokenWordParseImmediateQuotes) { SString word; TokenWordParse parse("Michael\"Rogers\"Jack\"\"son\"NoEnd", true); ASSERT_TRUE(parse.getNext(word)); ASSERT_EQ(word, "Michael"); ASSERT_TRUE(parse.getNext(word)); ASSERT_EQ(word, "Rogers"); ASSERT_TRUE(parse.getNext(word)); ASSERT_EQ(word, "Jack"); ASSERT_TRUE(parse.getNext(word)); ASSERT_EQ(word, ""); ASSERT_TRUE(parse.getNext(word)); ASSERT_EQ(word, "son"); ASSERT_TRUE(parse.getNext(word)); ASSERT_EQ(word, "NoEnd"); } eureka-editor-eureka-2.0.2/test/m_select_test.cpp000066400000000000000000000376101464327712600220650ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "m_select.h" #include "gtest/gtest.h" TEST(MSelect, ChangeType) { selection_c selection(ObjType::things); ASSERT_EQ(selection.what_type(), ObjType::things); selection.change_type(ObjType::sectors); ASSERT_EQ(selection.what_type(), ObjType::sectors); } TEST(MSelect, InitiallyEmpty) { selection_c selection; ASSERT_TRUE(selection.empty()); ASSERT_FALSE(selection.notempty()); ASSERT_EQ(selection.count_obj(), 0); ASSERT_EQ(selection.max_obj(), -1); ASSERT_EQ(selection.find_first(), -1); ASSERT_EQ(selection.find_second(), -1); } TEST(MSelect, CountObj) { selection_c selection(ObjType::things); selection.set(2); selection.set(3); selection.set(5); ASSERT_EQ(selection.count_obj(), 3); ASSERT_FALSE(selection.empty()); ASSERT_TRUE(selection.notempty()); } TEST(MSelect, ChangingTypeClearsContent) { selection_c selection(ObjType::things); selection.set(2); selection.set(3); selection.set(5); selection.change_type(ObjType::vertices); ASSERT_EQ(selection.count_obj(), 0); ASSERT_TRUE(selection.empty()); ASSERT_FALSE(selection.notempty()); } TEST(MSelect, ClearAll) { selection_c selection; selection.set(2); selection.set(3); selection.set(5); selection.clear_all(); ASSERT_EQ(selection.count_obj(), 0); ASSERT_TRUE(selection.empty()); ASSERT_FALSE(selection.notempty()); selection.set(4); ASSERT_EQ(selection.count_obj(), 1); ASSERT_FALSE(selection.empty()); ASSERT_TRUE(selection.notempty()); } TEST(MSelect, MaxObj) { selection_c selection; selection.set(2); selection.set(5); selection.set(3); ASSERT_EQ(selection.max_obj(), 5); } TEST(MSelect, Get) { selection_c selection; selection.set(2); selection.set(3); selection.set(5); ASSERT_FALSE(selection.get(0)); ASSERT_FALSE(selection.get(1)); ASSERT_TRUE(selection.get(2)); ASSERT_TRUE(selection.get(3)); ASSERT_FALSE(selection.get(4)); ASSERT_TRUE(selection.get(5)); ASSERT_FALSE(selection.get(6)); // going right is fine } TEST(MSelect, ClearOne) { selection_c selection; selection.set(2); selection.set(3); selection.set(5); selection.clear(3); selection.clear(4); // clearing unset is fine ASSERT_FALSE(selection.get(0)); ASSERT_FALSE(selection.get(1)); ASSERT_TRUE(selection.get(2)); ASSERT_FALSE(selection.get(3)); ASSERT_FALSE(selection.get(4)); ASSERT_TRUE(selection.get(5)); } TEST(MSelect, MaxObjGetsUpdated) { selection_c selection; selection.set(2); selection.set(5); selection.set(3); selection.clear(5); ASSERT_EQ(selection.max_obj(), 3); selection.set(7); ASSERT_EQ(selection.max_obj(), 7); } TEST(MSelect, Toggle) { selection_c selection; selection.set(2); selection.set(3); selection.set(5); selection.toggle(3); selection.toggle(4); // clearing unset is fine ASSERT_FALSE(selection.get(0)); ASSERT_FALSE(selection.get(1)); ASSERT_TRUE(selection.get(2)); ASSERT_FALSE(selection.get(3)); ASSERT_TRUE(selection.get(4)); ASSERT_TRUE(selection.get(5)); } TEST(MSelect, GetExtOnNormalListReturnsFullMask) { selection_c selection; selection.set(2); selection.set(3); selection.set(5); ASSERT_FALSE(selection.get_ext(0)); ASSERT_FALSE(selection.get_ext(1)); ASSERT_EQ(selection.get_ext(2), 255); ASSERT_EQ(selection.get_ext(3), 255); ASSERT_FALSE(selection.get_ext(4)); ASSERT_EQ(selection.get_ext(5), 255); ASSERT_FALSE(selection.get_ext(6)); // going right is fine } TEST(MSelect, ExtendedList) { selection_c selection(ObjType::things, true); selection.set_ext(2, 12); selection.set_ext(3, 23); selection.set_ext(5, 222); ASSERT_FALSE(selection.get_ext(0)); ASSERT_FALSE(selection.get_ext(1)); ASSERT_EQ(selection.get_ext(2), 12); ASSERT_EQ(selection.get_ext(3), 23); ASSERT_FALSE(selection.get_ext(4)); ASSERT_EQ(selection.get_ext(5), 222); ASSERT_FALSE(selection.get_ext(6)); // going right is fine // Replacing value is fine selection.set_ext(3, 40); ASSERT_EQ(selection.get_ext(3), 40); } TEST(MSelect, SimpleSettingOnExtendedList) { selection_c selection(ObjType::things, true); selection.set(2); selection.set(3); selection.set(5); ASSERT_FALSE(selection.get_ext(0)); ASSERT_FALSE(selection.get_ext(1)); ASSERT_EQ(selection.get_ext(2), 1); ASSERT_EQ(selection.get_ext(3), 1); ASSERT_FALSE(selection.get_ext(4)); ASSERT_EQ(selection.get_ext(5), 1); ASSERT_FALSE(selection.get_ext(6)); // going right is fine } TEST(MSelect, SimpleGettingOnExtendedList) { selection_c selection(ObjType::things, true); selection.set_ext(2, 12); selection.set_ext(3, 23); selection.set_ext(5, 222); ASSERT_FALSE(selection.get(0)); ASSERT_FALSE(selection.get(1)); ASSERT_TRUE(selection.get(2)); ASSERT_TRUE(selection.get(3)); ASSERT_FALSE(selection.get(4)); ASSERT_TRUE(selection.get(5)); ASSERT_FALSE(selection.get(6)); // going right is fine // Replacing value is fine selection.set_ext(3, 40); ASSERT_TRUE(selection.get(3)); // Zeroing out value will clear it selection.set_ext(5, 0); ASSERT_FALSE(selection.get(5)); } TEST(MSelect, CountExtendedList) { selection_c selection(ObjType::things, true); selection.set_ext(2, 12); selection.set_ext(3, 23); selection.set_ext(5, 222); ASSERT_EQ(selection.count_obj(), 3); // Zeroing out value will clear it selection.set_ext(5, 0); ASSERT_EQ(selection.count_obj(), 2); // Also accept clearing selection.clear(2); ASSERT_EQ(selection.count_obj(), 1); } TEST(MSelect, CheckExtendedListEmpty) { selection_c selection(ObjType::things, true); selection.set_ext(2, 12); selection.set_ext(3, 23); selection.set_ext(5, 222); ASSERT_FALSE(selection.empty()); ASSERT_TRUE(selection.notempty()); selection.clear(2); selection.set_ext(3, 0); ASSERT_FALSE(selection.empty()); ASSERT_TRUE(selection.notempty()); selection.clear(5); ASSERT_TRUE(selection.empty()); ASSERT_FALSE(selection.notempty()); } TEST(MSelect, CheckExtendedListEmptyAfterClearingAll) { selection_c selection(ObjType::things, true); selection.set_ext(2, 12); selection.set_ext(3, 23); selection.set_ext(5, 222); ASSERT_EQ(selection.count_obj(), 3); ASSERT_FALSE(selection.empty()); ASSERT_TRUE(selection.notempty()); selection.clear_all(); ASSERT_EQ(selection.count_obj(), 0); ASSERT_TRUE(selection.empty()); ASSERT_FALSE(selection.notempty()); } TEST(MSelect, MaxObjOnExtendedList) { selection_c selection(ObjType::things, true); ASSERT_EQ(selection.max_obj(), -1); selection.set_ext(2, 12); ASSERT_EQ(selection.max_obj(), 2); selection.set_ext(3, 23); ASSERT_EQ(selection.max_obj(), 3); selection.set_ext(5, 222); ASSERT_EQ(selection.max_obj(), 5); selection.clear(3); ASSERT_EQ(selection.max_obj(), 5); selection.clear(5); ASSERT_EQ(selection.max_obj(), 2); selection.set_ext(3, 34); selection.set_ext(4, 222); ASSERT_EQ(selection.max_obj(), 4); selection.clear_all(); ASSERT_EQ(selection.max_obj(), -1); } TEST(MSelect, CheckExtendedListClearedAfterChangingType) { selection_c selection(ObjType::things, true); selection.set_ext(2, 12); selection.set_ext(3, 23); selection.set_ext(5, 222); selection.change_type(ObjType::linedefs); ASSERT_EQ(selection.count_obj(), 0); ASSERT_TRUE(selection.empty()); ASSERT_FALSE(selection.notempty()); } TEST(MSelect, Frob) { selection_c selection; selection.frob(2, BitOp::add); selection.frob(3, BitOp::add); selection.frob(5, BitOp::add); ASSERT_EQ(selection.count_obj(), 3); ASSERT_EQ(selection.max_obj(), 5); ASSERT_TRUE(selection.get(2)); ASSERT_TRUE(selection.get(3)); selection.frob(4, BitOp::remove); ASSERT_EQ(selection.count_obj(), 3); ASSERT_TRUE(selection.get(2)); ASSERT_TRUE(selection.get(3)); ASSERT_FALSE(selection.get(4)); ASSERT_TRUE(selection.get(5)); selection.frob(3, BitOp::remove); ASSERT_EQ(selection.count_obj(), 2); ASSERT_TRUE(selection.get(2)); ASSERT_FALSE(selection.get(3)); ASSERT_TRUE(selection.get(5)); selection.frob(3, BitOp::toggle); selection.frob(4, BitOp::toggle); selection.frob(5, BitOp::toggle); ASSERT_TRUE(selection.get(2)); ASSERT_TRUE(selection.get(3)); ASSERT_TRUE(selection.get(4)); ASSERT_FALSE(selection.get(5)); } TEST(MSelect, FrobRange) { selection_c selection; selection.frob_range(1, 10, BitOp::add); ASSERT_FALSE(selection.get(0)); ASSERT_TRUE(selection.get(1)); ASSERT_TRUE(selection.get(2)); ASSERT_TRUE(selection.get(3)); ASSERT_TRUE(selection.get(4)); ASSERT_TRUE(selection.get(5)); ASSERT_TRUE(selection.get(6)); ASSERT_TRUE(selection.get(7)); ASSERT_TRUE(selection.get(8)); ASSERT_TRUE(selection.get(9)); ASSERT_TRUE(selection.get(10)); selection.frob_range(3, 6, BitOp::remove); ASSERT_FALSE(selection.get(0)); ASSERT_TRUE(selection.get(1)); ASSERT_TRUE(selection.get(2)); ASSERT_FALSE(selection.get(3)); ASSERT_FALSE(selection.get(4)); ASSERT_FALSE(selection.get(5)); ASSERT_FALSE(selection.get(6)); ASSERT_TRUE(selection.get(7)); ASSERT_TRUE(selection.get(8)); ASSERT_TRUE(selection.get(9)); ASSERT_TRUE(selection.get(10)); selection.frob_range(5, 9, BitOp::toggle); ASSERT_FALSE(selection.get(0)); ASSERT_TRUE(selection.get(1)); ASSERT_TRUE(selection.get(2)); ASSERT_FALSE(selection.get(3)); ASSERT_FALSE(selection.get(4)); ASSERT_TRUE(selection.get(5)); ASSERT_TRUE(selection.get(6)); ASSERT_FALSE(selection.get(7)); ASSERT_FALSE(selection.get(8)); ASSERT_FALSE(selection.get(9)); ASSERT_TRUE(selection.get(10)); } TEST(MSelect, Merge) { selection_c selection; selection.set(2); selection.set(3); selection.set(5); selection_c selection2; selection2.set(5); selection2.set(9); selection2.set(1); selection.merge(selection2); ASSERT_EQ(selection.count_obj(), 5); ASSERT_TRUE(selection.get(2)); ASSERT_TRUE(selection.get(3)); ASSERT_TRUE(selection.get(5)); ASSERT_TRUE(selection.get(9)); ASSERT_TRUE(selection.get(1)); } TEST(MSelect, MergeAllowsDifferentTypes) { selection_c selection(ObjType::things); selection.set(2); selection.set(3); selection.set(5); selection_c selection2(ObjType::vertices); selection2.set(5); selection2.set(9); selection2.set(1); selection.merge(selection2); ASSERT_EQ(selection.what_type(), ObjType::things); ASSERT_EQ(selection.count_obj(), 5); ASSERT_TRUE(selection.get(2)); ASSERT_TRUE(selection.get(3)); ASSERT_TRUE(selection.get(5)); ASSERT_TRUE(selection.get(9)); ASSERT_TRUE(selection.get(1)); } TEST(MSelect, MergingExtendedSelections) { selection_c selection(ObjType::things, true); selection.set_ext(2, 12); selection.set_ext(3, 23); selection.set_ext(5, 45); selection_c selection2(ObjType::things, true); selection2.set_ext(5, 67); selection2.set_ext(3, 89); selection2.set_ext(1, 90); selection.merge(selection2); ASSERT_EQ(selection.get_ext(2), 12); ASSERT_EQ(selection.get_ext(3), 95); // OR between the values ASSERT_EQ(selection.get_ext(5), 111); // OR between the values ASSERT_EQ(selection.get_ext(1), 90); } TEST(MSelect, Unmerge) { selection_c selection; selection.set(2); selection.set(3); selection.set(5); selection_c selection2; selection2.set(5); selection2.set(3); selection2.set(1); selection.unmerge(selection2); ASSERT_EQ(selection.count_obj(), 1); ASSERT_TRUE(selection.get(2)); // restore it selection.set(3); selection.set(5); selection2.unmerge(selection); ASSERT_EQ(selection2.count_obj(), 1); ASSERT_TRUE(selection2.get(1)); } TEST(MSelect, Intersect) { selection_c selection; selection.set(2); selection.set(3); selection.set(5); selection_c selection2; selection2.set(5); selection2.set(3); selection2.set(1); selection.intersect(selection2); ASSERT_EQ(selection.count_obj(), 2); ASSERT_TRUE(selection.get(3)); ASSERT_TRUE(selection.get(5)); } TEST(MSelect, DifferentTypesAreNotEqual) { selection_c selection(ObjType::things); selection.set(2); selection.set(3); selection.set(5); selection_c selection2(ObjType::vertices); selection2.set(2); selection2.set(3); selection2.set(5); ASSERT_FALSE(selection.test_equal(selection2)); } TEST(MSelect, Inequality) { selection_c selection; selection.set(2); selection.set(5); selection_c selection2; selection2.set(2); selection2.set(3); selection2.set(5); ASSERT_FALSE(selection.test_equal(selection2)); } TEST(MSelect, Equality) { selection_c selection; selection.set(2); selection.set(3); selection.set(5); selection_c selection2; selection2.set(2); selection2.set(3); selection2.set(5); ASSERT_TRUE(selection.test_equal(selection2)); } TEST(MSelect, FindFirstSecond) { selection_c selection; ASSERT_EQ(selection.find_first(), -1); ASSERT_EQ(selection.find_second(), -1); selection.set(4); ASSERT_EQ(selection.find_first(), 4); ASSERT_EQ(selection.find_second(), -1); selection.set(2); ASSERT_EQ(selection.find_first(), 4); // we must keep the first selected ASSERT_EQ(selection.find_second(), 2); selection.set(5); ASSERT_EQ(selection.find_first(), 4); ASSERT_EQ(selection.find_second(), 2); selection.clear(4); // Once clearing, all bets are off about order ASSERT_NE(selection.find_first(), -1); ASSERT_NE(selection.find_second(), -1); ASSERT_NE(selection.find_second(), selection.find_first()); selection.clear(2); ASSERT_EQ(selection.find_first(), 5); ASSERT_EQ(selection.find_second(), -1); } TEST(MSelect, Iterator) { selection_c selection; selection.set(2); selection.set(5); selection.set(9); selection.set(13); selection.set(7); selection.set(12); selection_c checkSelection; int runs = 0; for(sel_iter_c iter(selection); !iter.done(); iter.next()) { ++runs; checkSelection.set(*iter); ASSERT_EQ(checkSelection.count_obj(), runs); // Check that intersecting does nothing checkSelection.intersect(selection); ASSERT_EQ(checkSelection.count_obj(), runs); } // We ended up filling it ASSERT_TRUE(checkSelection.test_equal(selection)); } TEST(MSelect, IteratorExtended) { selection_c selection(ObjType::things, true); selection.set_ext(2, 12); selection.set_ext(5, 23); selection.set_ext(9, 34); selection.set_ext(13, 45); selection.set_ext(7, 56); selection.set_ext(12, 67); selection_c checkSelection(ObjType::things, true); int runs = 0; for(sel_iter_c iter(selection); !iter.done(); iter.next()) { ++runs; checkSelection.set_ext(*iter, selection.get_ext(*iter)); ASSERT_EQ(checkSelection.count_obj(), runs); // Check that intersecting does nothing checkSelection.intersect(selection); ASSERT_EQ(checkSelection.count_obj(), runs); } // Now check we preserve the content ASSERT_EQ(checkSelection.get_ext(2), 12); ASSERT_EQ(checkSelection.get_ext(5), 23); ASSERT_EQ(checkSelection.get_ext(9), 34); ASSERT_EQ(checkSelection.get_ext(13), 45); ASSERT_EQ(checkSelection.get_ext(7), 56); ASSERT_EQ(checkSelection.get_ext(12), 67); } TEST(MSelect, InternalToBitvec) { selection_c selection; for(int i = 0; i < MAX_STORE_SEL * 2; ++i) selection.set(i * i); // Check everything got in ASSERT_EQ(selection.count_obj(), MAX_STORE_SEL * 2); for(int i = 0; i < MAX_STORE_SEL * 2; ++i) ASSERT_TRUE(selection.get(i * i)); } TEST(MSelect, BitvecRealloc) { selection_c selection; for(int i = 0; i < 2048; ++i) selection.set(i); ASSERT_EQ(selection.count_obj(), 2048); for(int i = 0; i < 2048; ++i) ASSERT_TRUE(selection.get(i)); } TEST(MSelect, ExtendedSizeCanGrow) { selection_c selection(ObjType::things, true); // Must avoid setting ext to 0, so we still have 1024 selected for(int i = 0; i < 1024; ++i) selection.set_ext(i, static_cast((i * i + 1) % 256)); ASSERT_EQ(selection.count_obj(), 1024); for(int i = 0; i < 1024; ++i) ASSERT_EQ(selection.get_ext(i), static_cast((i * i + 1) % 256)); } eureka-editor-eureka-2.0.2/test/m_streams_test.cpp000066400000000000000000000060711464327712600222610ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2021 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "m_streams.h" #include "m_strings.h" #include "gtest/gtest.h" TEST(MStreams, MReadTextLine) { // Check that the BOM gets stripped, that both CRLF and LF are detected // and that no newline at the end of stream is fine std::string content = "\xef\xbb\xbfLine 1 is here\n" "Line 2 is here\r\n" "Line 3 is here\n" "Line 4 is here"; SString line; { std::istringstream ss(content); ASSERT_TRUE(M_ReadTextLine(line, ss)); ASSERT_EQ(line, "Line 1 is here"); ASSERT_TRUE(M_ReadTextLine(line, ss)); ASSERT_EQ(line, "Line 2 is here"); ASSERT_TRUE(M_ReadTextLine(line, ss)); ASSERT_EQ(line, "Line 3 is here"); ASSERT_TRUE(M_ReadTextLine(line, ss)); ASSERT_EQ(line, "Line 4 is here"); ASSERT_FALSE(M_ReadTextLine(line, ss)); } // Check that a trailing newline won't generate an empty line content = "Line 5 is here\n" "Line 6 is here\n"; { std::istringstream ss(content); ASSERT_TRUE(M_ReadTextLine(line, ss)); ASSERT_EQ(line, "Line 5 is here"); ASSERT_TRUE(M_ReadTextLine(line, ss)); ASSERT_EQ(line, "Line 6 is here"); ASSERT_FALSE(M_ReadTextLine(line, ss)); } // Check that a final line with just a space gets treated as an empty line content = "Line 5 is here\n" "Line 6 is here\n" " "; { std::istringstream ss(content); ASSERT_TRUE(M_ReadTextLine(line, ss)); ASSERT_EQ(line, "Line 5 is here"); ASSERT_TRUE(M_ReadTextLine(line, ss)); ASSERT_EQ(line, "Line 6 is here"); ASSERT_TRUE(M_ReadTextLine(line, ss)); ASSERT_TRUE(line.empty()); ASSERT_FALSE(M_ReadTextLine(line, ss)); } // Check that a newline shall show up as one empty line content = "\n"; { std::istringstream ss(content); ASSERT_TRUE(M_ReadTextLine(line, ss)); ASSERT_TRUE(line.empty()); ASSERT_FALSE(M_ReadTextLine(line, ss)); } // Check that a mere space shows up as one empty line content = " "; { std::istringstream ss(content); ASSERT_TRUE(M_ReadTextLine(line, ss)); ASSERT_TRUE(line.empty()); ASSERT_FALSE(M_ReadTextLine(line, ss)); } content = ""; { std::istringstream ss(content); ASSERT_FALSE(M_ReadTextLine(line, ss)); } } eureka-editor-eureka-2.0.2/test/m_testmap_test.cpp000066400000000000000000000214501464327712600222560ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2024 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "testUtils/TempDirContext.hpp" #include "Instance.h" #include "m_files.h" #include "gtest/gtest.h" #ifdef _WIN32 #else #include #include #include #endif #include #include #include class TestMapFixture : public TempDirContext { protected: void SetUp() override; void setPortName(const char* name); void addIWAD(); void addResources(); void addPWAD(); std::vector getResultLines() const; std::vector testMapAndGetLines(); Instance inst; fs::path outputPath; fs::path finishMarkPath; // empty file added by test script to indicate it's done fs::path portPath; fs::path gameWadPath; fs::path res1Path; fs::path res2Path; fs::path editWadPath; #ifdef __APPLE__ fs::path macPath; #endif private: #ifndef _WIN32 void writeShellScript(const fs::path &path); #endif }; #ifndef _WIN32 void TestMapFixture::writeShellScript(const fs::path &path) { std::ofstream stream(path); ASSERT_TRUE(stream.is_open()); mDeleteList.push(path); stream << "#!/bin/bash" << std::endl; stream << "echo running script" << std::endl; stream << "echo \"$0\" > " << SString(outputPath.u8string()).spaceEscape(true) << std::endl; stream << "for var in \"$@\"" << std::endl; stream << "do" << std::endl; stream << "echo \"$var\" >> " << SString(outputPath.u8string()).spaceEscape(true) << std::endl; stream << "done" << std::endl; stream << "echo done > " << SString(finishMarkPath.u8string()).spaceEscape(true) << std::endl; stream.close(); int r = chmod(path.u8string().c_str(), S_IRWXU); ASSERT_FALSE(r); } #endif void TestMapFixture::SetUp() { TempDirContext::SetUp(); outputPath = getChildPath("output.list"); finishMarkPath = getChildPath("finish.mark"); // Setup the program #ifdef _WIN32 portPath = getChildPath("port.bat"); std::ofstream stream(portPath); ASSERT_TRUE(stream.is_open()); mDeleteList.push(portPath); stream << "@echo off" << std::endl; stream << "echo running script" << std::endl; stream << "echo %0 > " << SString(outputPath.u8string()).spaceEscape(false) << std::endl; stream << "for %%x in (%*) do (" << std::endl; stream << "echo %%x >> " << SString(outputPath.u8string()).spaceEscape(false) << std::endl; stream << ")" << std::endl; stream << "echo done > " << SString(finishMarkPath.u8string()).spaceEscape(false) << std::endl; stream.close(); #else portPath = getChildPath("port.sh"); writeShellScript(portPath); #endif #ifdef __APPLE__ macPath = getChildPath("port.app"); bool result; result = FileMakeDir(macPath); ASSERT_TRUE(result); mDeleteList.push(macPath); fs::path contdir = macPath / "Contents"; result = FileMakeDir(contdir); ASSERT_TRUE(result); mDeleteList.push(contdir); fs::path macosdir = contdir / "MacOS"; result = FileMakeDir(macosdir); ASSERT_TRUE(result); mDeleteList.push(macosdir); fs::path execpath = macosdir / "portentry"; writeShellScript(execpath); // Now the info plist file fs::path infopath = contdir / "Info.plist"; std::ofstream infostream(infopath); ASSERT_TRUE(infostream.is_open()); mDeleteList.push(infopath); infostream << "" << std::endl; infostream << "" << std::endl; infostream << "" << std::endl; infostream << "" << std::endl; infostream << "CFBundleExecutable" << std::endl; infostream << "" << execpath.filename().u8string() << "" << std::endl; infostream << "CFBundleIdentifier" << std::endl; infostream << "com.eureka.testmaptest" << std::endl; infostream << "" << std::endl; infostream << "" << std::endl; infostream.close(); #endif } void TestMapFixture::setPortName(const char* name) { // Prepare the conditions global::recent.setPortPath(!strcmp(name, "vanilla") ? "vanilla_doom2" : name, portPath); // Populate for GrabWadNamesArgs inst.loaded.portName = name; } void TestMapFixture::addIWAD() { gameWadPath = getChildPath("ga me.wad"); std::shared_ptr gameWad = Wad_file::Open(gameWadPath, WadOpenMode::write); inst.wad.master.setGameWad(gameWad); } void TestMapFixture::addResources() { std::vector> resources; res1Path = getChildPath("re s1.wad"); res2Path = getChildPath("re s2.wad"); resources.push_back(Wad_file::Open(res1Path, WadOpenMode::write)); resources.push_back(Wad_file::Open(res2Path, WadOpenMode::write)); inst.wad.master.setResources(resources); } void TestMapFixture::addPWAD() { editWadPath = getChildPath("ed it.wad"); std::shared_ptr editWad = Wad_file::Open(editWadPath, WadOpenMode::write); inst.wad.master.ReplaceEditWad(editWad); } std::vector TestMapFixture::getResultLines() const { // Try until it's open for (int i = 0; i < 20; ++i) { if (fs::exists(finishMarkPath)) break; std::this_thread::sleep_for(std::chrono::milliseconds(100)); } std::ifstream input; input.open(outputPath); EXPECT_TRUE(input.is_open()); std::vector result; while (input && !input.eof()) { std::string line; std::getline(input, line); if (line.empty() && input.eof()) return result; // Windows may add quotes on arguments with spaces #ifdef _WIN32 SString changedLine = SString(line); changedLine.trimTrailingSpaces(); line = changedLine.get(); if (line.length() >= 2 && line[0] == '"' && line.back() == '"') line = line.substr(1, line.length() - 2); #endif result.push_back(line); } return result; } std::vector TestMapFixture::testMapAndGetLines() { // Now run inst.CMD_TestMap(); mDeleteList.push(outputPath); mDeleteList.push(finishMarkPath); return getResultLines(); } TEST_F(TestMapFixture, TestMapVanillaWithResources) { setPortName("vanilla"); addIWAD(); addResources(); addPWAD(); inst.loaded.levelName = "MAP14"; // Now run std::vector lines = testMapAndGetLines(); std::vector expected = {portPath.u8string(), "-iwad", gameWadPath.u8string(), "-merge", res1Path.u8string(), res2Path.u8string(), "-file", editWadPath.u8string(), "-warp", "14"}; ASSERT_EQ(lines, expected); } TEST_F(TestMapFixture, TestMapPortWithResources) { setPortName("boom"); addIWAD(); addResources(); addPWAD(); inst.loaded.levelName = "MAP14"; std::vector lines = testMapAndGetLines(); std::vector expected = {portPath.u8string(), "-iwad", gameWadPath.u8string(), "-file", res1Path.u8string(), res2Path.u8string(), editWadPath.u8string(), "-warp", "14"}; ASSERT_EQ(lines, expected); } TEST_F(TestMapFixture, TestMapPortWithoutResources) { setPortName("boom"); addIWAD(); addPWAD(); inst.loaded.levelName = "MAP14"; std::vector lines = testMapAndGetLines(); std::vector expected = {portPath.u8string(), "-iwad", gameWadPath.u8string(), "-file", editWadPath.u8string(), "-warp", "14"}; ASSERT_EQ(lines, expected); } TEST_F(TestMapFixture, TestMapPortWithoutResourcesDoom1Map) { setPortName("boom"); addIWAD(); addPWAD(); inst.loaded.levelName = "E6M9"; std::vector lines = testMapAndGetLines(); std::vector expected = {portPath.u8string(), "-iwad", gameWadPath.u8string(), "-file", editWadPath.u8string(), "-warp", "6", "9"}; ASSERT_EQ(lines, expected); } TEST_F(TestMapFixture, TestMapPortWithoutResourcesNonstandardMap) { setPortName("boom"); addIWAD(); addPWAD(); inst.loaded.levelName = "ZOMFG65"; std::vector lines = testMapAndGetLines(); std::vector expected = {portPath.u8string(), "-iwad", gameWadPath.u8string(), "-file", editWadPath.u8string(), "-warp", "65"}; ASSERT_EQ(lines, expected); } TEST_F(TestMapFixture, TestMapPortWithoutResourcesBadMap) { setPortName("boom"); addIWAD(); addPWAD(); inst.loaded.levelName = "NOTHING"; std::vector lines = testMapAndGetLines(); std::vector expected = {portPath.u8string(), "-iwad", gameWadPath.u8string(), "-file", editWadPath.u8string()}; ASSERT_EQ(lines, expected); } // TODO: add mac app bundle test eureka-editor-eureka-2.0.2/test/main_test.cpp000066400000000000000000000021711464327712600212100ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "main.h" #include "gtest/gtest.h" TEST(Main, GameNameFromIWAD) { ASSERT_EQ(GameNameFromIWAD("/michael/jackson/JACKson.wad"), "jackson"); ASSERT_EQ(GameNameFromIWAD(""), ""); ASSERT_EQ(GameNameFromIWAD("Games/Doom.wad/"), ""); ASSERT_EQ(GameNameFromIWAD("Games/Doom.wad/ "), " "); ASSERT_EQ(GameNameFromIWAD("Games/ Do om.wad "), " do om"); ASSERT_EQ(GameNameFromIWAD("Games/Doom .wad "), "doom "); } eureka-editor-eureka-2.0.2/test/python/000077500000000000000000000000001464327712600200415ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/test/python/test_print_quit.py000066400000000000000000000035321464327712600236530ustar00rootroot00000000000000import argparse import re import subprocess # test script expects the executable as argument parser = argparse.ArgumentParser() parser.add_argument('--executable', help='full path to executable') parser.add_argument('--version', help='Eureka version string') args = parser.parse_args() IMMEDIATE_RUN_TIMEOUT = 3 def test_help_command(): result = subprocess.check_output([args.executable, '--help'], timeout=IMMEDIATE_RUN_TIMEOUT).decode('utf-8') assert 'Eureka is free software, under the terms of the GNU General' in result assert 'USAGE: ' in result assert '--version' in result lines = result.split('\n') parms = set() # Check that all the columns are aligned saved_pos = None for line in lines: pos = line.find('<') match = re.search('--[a-z_]+', line) if match: parm = match.group() parms.add(parm) if pos != -1: if saved_pos is not None: assert pos == saved_pos else: saved_pos = pos assert parms == {'--home', '--install', '--log', '--config', '--help', '--version', '--debug', '--quiet', '--file', '--merge', '--iwad', '--port', '--warp', } # Check that '<' marked arguments (like -warp) have an extra newline after in_warp = False for line in lines: if '-warp' in line: in_warp = True continue if in_warp: assert not line.strip() # check that we have an empty line here in_warp = False def test_version_command(): result = str(subprocess.check_output([args.executable, '--version'], timeout=IMMEDIATE_RUN_TIMEOUT)) assert args.version in result test_help_command() test_version_command() eureka-editor-eureka-2.0.2/test/r_grid_test.cpp000066400000000000000000000311211464327712600215270ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2024 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "r_grid.h" #include "m_config.h" #include "gtest/gtest.h" class GridStateFixture : public ::testing::Test, public grid::Listener { public: virtual void gridRedrawMap() override { ++redrawMapCounts; } virtual void gridSetGrid(int grid) override { gridSettings.push_back(grid); } virtual void gridUpdateSnap() override { ++snapUpdates; } virtual void gridAdjustPos() override { ++positionUpdates; } virtual void gridPointerPos() override { ++pointerPositionUpdates; } virtual void gridSetScale(double scale) override { scaleSettings.push_back(scale); } virtual void gridBeep(const char* message) override { beeps.push_back(message); } virtual void gridUpdateRatio() override { ++ratioUpdates; } protected: void TearDown() override { config::grid_default_size = initialGridDefaultSize; config::grid_default_mode = initialGridDefaultMode; config::grid_default_snap = initialGridDefaultSnap; config::grid_hide_in_free_mode = initialGridHideInFreeMode; } int redrawMapCounts = 0; std::vector gridSettings; int snapUpdates = 0; int positionUpdates = 0; int pointerPositionUpdates = 0; std::vector scaleSettings; std::vector beeps; int ratioUpdates = 0; private: int initialGridDefaultSize = config::grid_default_size; bool initialGridDefaultMode = config::grid_default_mode; bool initialGridDefaultSnap = config::grid_default_snap; bool initialGridHideInFreeMode = config::grid_hide_in_free_mode; }; TEST_F(GridStateFixture, InitNormalGrid) { grid::State grid(*this); config::grid_default_size = 16; config::grid_default_mode = true; grid.Init(); ASSERT_TRUE(grid.isShown()); ASSERT_EQ(grid.getStep(), 16); ASSERT_GE(gridSettings.size(), 1); ASSERT_EQ(gridSettings.back(), 16); ASSERT_GE(redrawMapCounts, 1); } TEST_F(GridStateFixture, InitNonPowerOf2Grid) { grid::State grid(*this); config::grid_default_size = 12; config::grid_default_mode = true; grid.Init(); ASSERT_TRUE(grid.isShown()); ASSERT_EQ(grid.getStep(), 16); ASSERT_GE(gridSettings.size(), 1); ASSERT_EQ(gridSettings.back(), 16); ASSERT_GE(redrawMapCounts, 1); } TEST_F(GridStateFixture, InitUnderflowGridCapsAt2) { { grid::State grid(*this); config::grid_default_size = 1; config::grid_default_mode = true; grid.Init(); ASSERT_TRUE(grid.isShown()); ASSERT_EQ(grid.getStep(), 2); ASSERT_GE(gridSettings.size(), 1); ASSERT_EQ(gridSettings.back(), 2); ASSERT_GE(redrawMapCounts, 1); } { grid::State grid(*this); config::grid_default_size = -8; config::grid_default_mode = true; grid.Init(); ASSERT_TRUE(grid.isShown()); ASSERT_EQ(grid.getStep(), 2); ASSERT_GE(gridSettings.size(), 1); ASSERT_EQ(gridSettings.back(), 2); ASSERT_GE(redrawMapCounts, 2); } } TEST_F(GridStateFixture, InitOverflowGridCapsAt1024) { { grid::State grid(*this); config::grid_default_size = 1025; config::grid_default_mode = true; grid.Init(); ASSERT_TRUE(grid.isShown()); ASSERT_EQ(grid.getStep(), 1024); ASSERT_GE(gridSettings.size(), 1); ASSERT_EQ(gridSettings.back(), 1024); ASSERT_GE(redrawMapCounts, 1); } { grid::State grid(*this); config::grid_default_size = 2048; config::grid_default_mode = true; grid.Init(); ASSERT_TRUE(grid.isShown()); ASSERT_EQ(grid.getStep(), 1024); ASSERT_GE(gridSettings.size(), 1); ASSERT_EQ(gridSettings.back(), 1024); ASSERT_GE(redrawMapCounts, 2); } } TEST_F(GridStateFixture, SnapCalled) { grid::State grid(*this); grid.Init(); ASSERT_EQ(snapUpdates, 1); ASSERT_GE(redrawMapCounts, 1); } TEST_F(GridStateFixture, GridDisabledWhenNotConfigured) { grid::State grid(*this); config::grid_default_mode = false; grid.Init(); ASSERT_FALSE(grid.isShown()); ASSERT_GE(gridSettings.size(), 1); ASSERT_EQ(gridSettings.back(), -1); ASSERT_GE(redrawMapCounts, 1); } TEST_F(GridStateFixture, InitWithoutSnappingButVisible) { grid::State grid(*this); config::grid_default_mode = true; config::grid_default_snap = false; config::grid_default_size = 16; grid.Init(); ASSERT_EQ(snapUpdates, 1); ASSERT_FALSE(grid.snaps()); ASSERT_EQ(grid.getStep(), 16); ASSERT_TRUE(grid.isShown()); ASSERT_GE(gridSettings.size(), 1); ASSERT_EQ(gridSettings.back(), 16); ASSERT_GE(redrawMapCounts, 1); } TEST_F(GridStateFixture, InitWithoutSnappingAndInvisible) { grid::State grid(*this); config::grid_default_mode = false; config::grid_default_snap = false; config::grid_default_size = 16; grid.Init(); ASSERT_EQ(snapUpdates, 1); ASSERT_FALSE(grid.snaps()); ASSERT_EQ(grid.getStep(), 16); ASSERT_FALSE(grid.isShown()); ASSERT_GE(gridSettings.size(), 1); ASSERT_EQ(gridSettings.back(), -1); ASSERT_GE(redrawMapCounts, 1); } TEST_F(GridStateFixture, ChangeShownStatus) { grid::State grid(*this); config::grid_default_mode = true; config::grid_default_size = 16; config::grid_default_snap = true; grid.Init(); ASSERT_TRUE(grid.isShown()); grid.SetShown(false); ASSERT_FALSE(grid.isShown()); ASSERT_FALSE(gridSettings.empty()); ASSERT_EQ(gridSettings.back(), -1); grid.SetShown(true); ASSERT_TRUE(grid.isShown()); ASSERT_FALSE(gridSettings.empty()); ASSERT_EQ(gridSettings.back(), 16); // Now also with snapping config::grid_hide_in_free_mode = true; int befsnaps = snapUpdates; grid.SetShown(false); ASSERT_FALSE(grid.isShown()); ASSERT_FALSE(gridSettings.empty()); ASSERT_EQ(gridSettings.back(), -1); ASSERT_FALSE(grid.snaps()); ASSERT_EQ(snapUpdates, befsnaps + 1); befsnaps = snapUpdates; grid.SetShown(true); ASSERT_TRUE(grid.isShown()); ASSERT_FALSE(gridSettings.empty()); ASSERT_EQ(gridSettings.back(), 16); ASSERT_TRUE(grid.snaps()); ASSERT_EQ(snapUpdates, befsnaps + 1); } TEST_F(GridStateFixture, SetSnapSameValueChangesNothing) { { grid::State grid(*this); config::grid_default_snap = false; grid.Init(); int snapUpdatesBefore = snapUpdates; int mapRedrawsBefore = redrawMapCounts; grid.SetSnap(false); ASSERT_EQ(snapUpdates, snapUpdatesBefore); ASSERT_EQ(redrawMapCounts, mapRedrawsBefore); } { grid::State grid(*this); config::grid_default_snap = true; grid.Init(); int snapUpdatesBefore = snapUpdates; int mapRedrawsBefore = redrawMapCounts; grid.SetSnap(true); ASSERT_EQ(snapUpdates, snapUpdatesBefore); ASSERT_EQ(redrawMapCounts, mapRedrawsBefore); } } TEST_F(GridStateFixture, ToggleSnappingWithoutHidingInFreeMode) { grid::State grid(*this); config::grid_default_snap = false; config::grid_default_mode = false; grid.Init(); ASSERT_FALSE(grid.snaps()); ASSERT_FALSE(grid.isShown()); int snapUpdatesBefore = snapUpdates; int mapRedrawsBefore = redrawMapCounts; grid.SetSnap(true); ASSERT_TRUE(grid.snaps()); ASSERT_FALSE(grid.isShown()); ASSERT_EQ(snapUpdates, snapUpdatesBefore + 1); ASSERT_EQ(redrawMapCounts, mapRedrawsBefore + 1); grid.SetSnap(false); ASSERT_FALSE(grid.snaps()); ASSERT_FALSE(grid.isShown()); ASSERT_EQ(snapUpdates, snapUpdatesBefore + 2); ASSERT_EQ(redrawMapCounts, mapRedrawsBefore + 2); } TEST_F(GridStateFixture, ToggleSnappingWithHidingInFreeMode) { grid::State grid(*this); config::grid_default_snap = false; config::grid_default_mode = false; config::grid_hide_in_free_mode = true; grid.Init(); ASSERT_FALSE(grid.snaps()); ASSERT_FALSE(grid.isShown()); int snapUpdatesBefore = snapUpdates; int mapRedrawsBefore = redrawMapCounts; grid.SetSnap(true); ASSERT_TRUE(grid.snaps()); ASSERT_TRUE(grid.isShown()); ASSERT_EQ(snapUpdates, snapUpdatesBefore + 1); ASSERT_GE(redrawMapCounts, mapRedrawsBefore + 1); ASSERT_FALSE(gridSettings.empty()); ASSERT_GE(gridSettings.back(), 2); mapRedrawsBefore = redrawMapCounts; // refresh it because the increment is unknown, it's just >= 1 grid.SetSnap(false); ASSERT_FALSE(grid.snaps()); ASSERT_FALSE(grid.isShown()); ASSERT_EQ(snapUpdates, snapUpdatesBefore + 2); ASSERT_GE(redrawMapCounts, mapRedrawsBefore + 1); ASSERT_FALSE(gridSettings.empty()); ASSERT_GE(gridSettings.back(), -1); } TEST_F(GridStateFixture, ToggleControlsWithoutLinking) { grid::State grid(*this); config::grid_default_snap = false; config::grid_default_mode = false; config::grid_hide_in_free_mode = false; grid.Init(); ASSERT_FALSE(grid.snaps()); ASSERT_FALSE(grid.isShown()); grid.ToggleShown(); ASSERT_FALSE(grid.snaps()); ASSERT_TRUE(grid.isShown()); grid.ToggleShown(); ASSERT_FALSE(grid.snaps()); ASSERT_FALSE(grid.isShown()); grid.ToggleSnap(); ASSERT_TRUE(grid.snaps()); ASSERT_FALSE(grid.isShown()); grid.ToggleSnap(); ASSERT_FALSE(grid.snaps()); ASSERT_FALSE(grid.isShown()); } TEST_F(GridStateFixture, ToggleControlsWithLinking) { grid::State grid(*this); config::grid_default_snap = false; config::grid_default_mode = false; config::grid_hide_in_free_mode = true; grid.Init(); ASSERT_FALSE(grid.snaps()); ASSERT_FALSE(grid.isShown()); grid.ToggleShown(); ASSERT_TRUE(grid.isShown()); ASSERT_TRUE(grid.snaps()); grid.ToggleShown(); ASSERT_FALSE(grid.isShown()); ASSERT_FALSE(grid.snaps()); grid.ToggleSnap(); ASSERT_TRUE(grid.isShown()); ASSERT_TRUE(grid.snaps()); grid.ToggleSnap(); ASSERT_FALSE(grid.isShown()); ASSERT_FALSE(grid.snaps()); } TEST_F(GridStateFixture, MoveToAndScroll) { grid::State grid(*this); grid.Init(); redrawMapCounts = 0; // reset grid.MoveTo({ 100, 200 }); ASSERT_EQ(grid.getOrig().x, 100); ASSERT_EQ(grid.getOrig().y, 200); ASSERT_EQ(positionUpdates, 1); ASSERT_EQ(pointerPositionUpdates, 1); ASSERT_EQ(redrawMapCounts, 1); // Same position here grid.MoveTo({ 100.001, 200.001 }); ASSERT_EQ(grid.getOrig().x, 100); ASSERT_EQ(grid.getOrig().y, 200); ASSERT_EQ(positionUpdates, 1); ASSERT_EQ(pointerPositionUpdates, 1); ASSERT_EQ(redrawMapCounts, 1); // Move more grid.MoveTo({ 100, 202 }); ASSERT_EQ(grid.getOrig().x, 100); ASSERT_EQ(grid.getOrig().y, 202); ASSERT_EQ(positionUpdates, 2); ASSERT_EQ(pointerPositionUpdates, 2); ASSERT_EQ(redrawMapCounts, 2); // Zero scroll grid.Scroll({ 0, 0 }); ASSERT_EQ(grid.getOrig().x, 100); ASSERT_EQ(grid.getOrig().y, 202); ASSERT_EQ(positionUpdates, 2); ASSERT_EQ(pointerPositionUpdates, 2); ASSERT_EQ(redrawMapCounts, 2); // Existing scroll grid.Scroll({ +1, -1 }); ASSERT_EQ(grid.getOrig().x, 101); ASSERT_EQ(grid.getOrig().y, 201); ASSERT_EQ(positionUpdates, 3); ASSERT_EQ(pointerPositionUpdates, 3); ASSERT_EQ(redrawMapCounts, 3); } TEST_F(GridStateFixture, RefocusZoom) { grid::State grid(*this); grid.Init(); ASSERT_EQ(grid.getScale(), 1.0); grid.MoveTo({ 100, 100 }); int redrawMapCountsBefore = redrawMapCounts; int pointerPositionUpdatesBefore = pointerPositionUpdates; grid.RefocusZoom({ 200, 300 }, 0.75); ASSERT_EQ(grid.getOrig().x, 125); ASSERT_EQ(grid.getOrig().y, 150); ASSERT_EQ(redrawMapCounts, redrawMapCountsBefore + 1); ASSERT_EQ(pointerPositionUpdates, pointerPositionUpdatesBefore + 1); } TEST_F(GridStateFixture, NearestScaleValid) { grid::State grid(*this); grid.Init(); int posAdjustBefore = positionUpdates; int pointerPosBefore = pointerPositionUpdates; int redrawMapBefore = redrawMapCounts; size_t scaleSettingsBefore = scaleSettings.size(); grid.NearestScale(12); ASSERT_EQ(grid.getScale(), 8); ASSERT_EQ(positionUpdates, posAdjustBefore + 1); ASSERT_EQ(pointerPositionUpdates, pointerPosBefore + 1); ASSERT_EQ(redrawMapCounts, redrawMapBefore + 1); ASSERT_EQ(scaleSettings.size(), scaleSettingsBefore + 1); ASSERT_EQ(scaleSettings.back(), 8); } TEST_F(GridStateFixture, NearestScaleTiny) // check we don't overflow { grid::State grid(*this); grid.Init(); int posAdjustBefore = positionUpdates; int pointerPosBefore = pointerPositionUpdates; int redrawMapBefore = redrawMapCounts; size_t scaleSettingsBefore = scaleSettings.size(); grid.NearestScale(0.0001); ASSERT_EQ(grid.getScale(), 1.0 / 64.0); ASSERT_EQ(positionUpdates, posAdjustBefore + 1); ASSERT_EQ(pointerPositionUpdates, pointerPosBefore + 1); ASSERT_EQ(redrawMapCounts, redrawMapBefore + 1); ASSERT_EQ(scaleSettings.size(), scaleSettingsBefore + 1); ASSERT_EQ(scaleSettings.back(), 1.0 / 64.0); } TEST_F(GridStateFixture, ForceStep) { } eureka-editor-eureka-2.0.2/test/stub/000077500000000000000000000000001464327712600174755ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/test/stub/e_cutpaste_stub.cpp000066400000000000000000000024121464327712600233710ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "objid.h" class EditOperation; class selection_c; struct Document; void Clipboard_ClearLocals() { } void Clipboard_NotifyBegin() { } void Clipboard_NotifyChange(ObjType type, int objnum, int field) { } void Clipboard_NotifyDelete(ObjType type, int objnum) { } void Clipboard_NotifyEnd() { } void Clipboard_NotifyInsert(const Document &doc, ObjType type, int objnum) { } void DeleteObjects_WithUnused(EditOperation &op, const Document &doc, const selection_c &list, bool keep_things, bool keep_verts, bool keep_lines) { } eureka-editor-eureka-2.0.2/test/stub/e_hover_stub.cpp000066400000000000000000000022411464327712600226640ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "e_hover.h" void Hover::fastOpposite_begin() { } void Hover::fastOpposite_finish() { } Objid hover::getNearbyObject(ObjType type, const Document &doc, const ConfigData &config, const Grid_State_c &grid, const v2double_t &pos) { return Objid(); } Objid hover::getNearestSector(const Document &doc, const v2double_t &pos) { return Objid(); } int Hover::getOppositeSector(int ld, Side ld_side) const { return 0; } eureka-editor-eureka-2.0.2/test/stub/e_main_stub.cpp000066400000000000000000000041021464327712600224630ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "e_main.h" #include "Instance.h" #include "objid.h" void ConvertSelection(const Document &doc, const selection_c & src, selection_c & dest) { } SelectHighlight Editor_State_t::SelectionOrHighlight() { return SelectHighlight::ok; } void Instance::Editor_ChangeMode(char mode_char) { } void Instance::MapStuff_NotifyBegin() { } void Instance::MapStuff_NotifyChange(ObjType type, int objnum, int field) { } void Instance::MapStuff_NotifyDelete(ObjType type, int objnum) { } void Instance::MapStuff_NotifyEnd() { } void Instance::MapStuff_NotifyInsert(ObjType type, int objnum) { } void Instance::ObjectBox_NotifyBegin() { } void Instance::ObjectBox_NotifyChange(ObjType type, int objnum, int field) { } void Instance::ObjectBox_NotifyDelete(ObjType type, int objnum) { } void Instance::ObjectBox_NotifyEnd() const { } void Instance::ObjectBox_NotifyInsert(ObjType type, int objnum) { } void Instance::RedrawMap() { } void Instance::Selection_Clear(bool no_save) { } void Instance::Selection_NotifyBegin() { } void Instance::Selection_NotifyDelete(ObjType type, int objnum) { } void Instance::Selection_NotifyEnd() { } void Instance::Selection_NotifyInsert(ObjType type, int objnum) { } void Recently_used::insert(const SString &name) { } void Recently_used::insert_number(int val) { } void Selection_NotifyChange(ObjType type, int objnum, int field) { } eureka-editor-eureka-2.0.2/test/stub/e_path_stub.cpp000066400000000000000000000014211464327712600224740ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Instance.h" void Instance::GoToErrors() { } eureka-editor-eureka-2.0.2/test/stub/im_img_stub.cpp000066400000000000000000000014471464327712600225050ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "im_img.h" bool Img_c::has_transparent() const { return false; } eureka-editor-eureka-2.0.2/test/stub/m_game_stub.cpp000066400000000000000000000023641464327712600224700ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Instance.h" #include "m_game.h" bool Instance::is_sky(const SString &flat) const { return false; } bool is_null_tex(const SString &tex) { return false; } const linetype_t &Instance::M_GetLineType(int type) const { static linetype_t linetype; return linetype; } const sectortype_t &Instance::M_GetSectorType(int type) const { static sectortype_t sectortype; return sectortype; } const thingtype_t &M_GetThingType(const ConfigData &config, int type) { static thingtype_t thingtype; return thingtype; } eureka-editor-eureka-2.0.2/test/stub/m_keys_stub.cpp000066400000000000000000000014361464327712600225310ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Instance.h" void Instance::Beep(const char *fmt, ...) { } eureka-editor-eureka-2.0.2/test/stub/osxcalls_stub.cpp000066400000000000000000000017331464327712600230720ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "m_strings.h" #include "filesystem.hpp" namespace fs = ghc::filesystem; enum class macOSDirType { library, libraryAppSupport, libraryCache }; fs::path OSX_UserDomainDirectory(macOSDirType dirtype, const char *subdir) { return fs::path(); } eureka-editor-eureka-2.0.2/test/stub/r_render_stub.cpp000066400000000000000000000020521464327712600230350ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "objid.h" class Instance; struct Document; void Render3D_NotifyBegin() { } void Render3D_NotifyChange(ObjType type, int objnum, int field) { } void Render3D_NotifyDelete(const Document &doc, ObjType type, int objnum) { } void Render3D_NotifyEnd(Instance &inst) { } void Render3D_NotifyInsert(ObjType type, int objnum) { } eureka-editor-eureka-2.0.2/test/stub/ui_dialog_stub.cpp000066400000000000000000000016131464327712600231730ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "m_strings.h" int DLG_Confirm(const std::vector &buttons, EUR_FORMAT_STRING(const char *msg), ...) { return 0; } void DLG_Notify(const char *msg, ...) { } eureka-editor-eureka-2.0.2/test/stub/ui_infobar_stub.cpp000066400000000000000000000014761464327712600233630ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Instance.h" void Instance::Status_Set(EUR_FORMAT_STRING(const char *fmt), ...) const { } eureka-editor-eureka-2.0.2/test/sys_debug_test.cpp000066400000000000000000000151541464327712600222550ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2021 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "sys_debug.h" #include "m_streams.h" #include "m_strings.h" #include "testUtils/TempDirContext.hpp" #include "gtest/gtest.h" // // Temporary directory // class SysDebugTempDir : public TempDirContext { }; TEST_F(SysDebugTempDir, LifeCycle) { std::vector localWindowMessages; global::Debugging = false; global::in_fatal_error = false; Log log; fs::path path = getChildPath("log.txt"); log.printf("Test message\n"); log.printf("Here it goes\n"); log.debugPrintf("No text\n"); ASSERT_TRUE(log.openFile(path)); mDeleteList.push(path); log.printf("One more message\n"); fs::path savedPath = getChildPath("log2.txt"); std::ofstream os(savedPath, std::ios::trunc); ASSERT_TRUE(os.is_open()); mDeleteList.push(savedPath); log.saveTo(os); os.close(); log.openWindow([](const SString &text, void *userData) { auto localWindowMessages = static_cast *>(userData); localWindowMessages->push_back(text); }, &localWindowMessages); log.printf("Now we're on window\n"); log.printf("And again\n"); log.close(); auto checkFileLines = [](LineFile &file) { SString line; ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "======= START OF LOGS ======="); ASSERT_TRUE(file.readLine(line)); ASSERT_TRUE(line.empty()); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "Test message"); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "Here it goes"); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "One more message"); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "Now we're on window"); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "And again"); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, ""); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, ""); }; { LineFile file(path); checkFileLines(file); SString line; ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "======== END OF LOGS ========"); ASSERT_FALSE(file.readLine(line)); } // Now check { SString line; LineFile file(savedPath); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "======= START OF LOGS ======="); ASSERT_TRUE(file.readLine(line)); ASSERT_TRUE(line.empty()); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "Test message"); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "Here it goes"); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "One more message"); ASSERT_FALSE(file.readLine(line)); // stopped here } ASSERT_EQ(localWindowMessages.size(), 5); ASSERT_EQ(localWindowMessages[0], "Test message\n"); ASSERT_EQ(localWindowMessages[1], "Here it goes\n"); ASSERT_EQ(localWindowMessages[2], "One more message\n"); ASSERT_EQ(localWindowMessages[3], "Now we're on window\n"); ASSERT_EQ(localWindowMessages[4], "And again\n"); localWindowMessages.clear(); // Now write more stuff log.printf("Extra stuff one\n"); log.openWindow(); log.printf("Extra stuff two\n"); global::Debugging = true; log.debugPrintf("No print here\n"); // Mark fatal error to see it doesn't get added log.markFatalError(); log.printf("Extra stuff three\n"); ASSERT_EQ(localWindowMessages.size(), 2); // it didn't get added to missing window // Now check saving current status works os.open(savedPath, std::ios::trunc); ASSERT_TRUE(os.is_open()); log.saveTo(os); os.close(); log.openFile(path); log.debugPrintf("Debug writeout\n"); log.printf("Extra stuff four\n"); log.debugPrintf("Debug\nwriteout2\n"); log.debugPrintf("%s", ""); // this shall not be printed! global::Debugging = false; log.debugPrintf("Debug writeout3\n"); log.debugPrintf("Debug writeout4\n"); log.printf("Extra stuff five\n"); log.close(); { LineFile file(path); SString line; ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "======= START OF LOGS ======="); ASSERT_TRUE(file.readLine(line)); ASSERT_TRUE(line.empty()); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "Extra stuff one"); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "Extra stuff two"); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "Extra stuff three"); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "# Debug writeout"); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "Extra stuff four"); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "# Debug"); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "# writeout2"); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "Extra stuff five"); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, ""); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, ""); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "======== END OF LOGS ========"); ASSERT_FALSE(file.readLine(line)); } { LineFile file(savedPath); SString line; ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "======= START OF LOGS ======="); ASSERT_TRUE(file.readLine(line)); ASSERT_TRUE(line.empty()); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "Extra stuff one"); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "Extra stuff two"); ASSERT_TRUE(file.readLine(line)); ASSERT_EQ(line, "Extra stuff three"); ASSERT_FALSE(file.readLine(line)); } ASSERT_EQ(localWindowMessages.size(), 2); ASSERT_EQ(localWindowMessages[0], "Extra stuff one\n"); ASSERT_EQ(localWindowMessages[1], "Extra stuff two\n"); } eureka-editor-eureka-2.0.2/test/testUtils/000077500000000000000000000000001464327712600205205ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/test/testUtils/FatalHandler.cpp000066400000000000000000000013651464327712600235560ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2020 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "FatalHandler.hpp" eureka-editor-eureka-2.0.2/test/testUtils/FatalHandler.hpp000066400000000000000000000021261464327712600235570ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2020 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef FatalHandler_hpp #define FatalHandler_hpp #include #include // // Handles a runtime_error exception fatally. Needed for death tests. // template void Fatal(const Callable &callable) { try { callable(); } catch(const std::exception &e) { std::cerr << e.what() << std::endl; abort(); } } #endif /* FatalHandler_hpp */ eureka-editor-eureka-2.0.2/test/testUtils/Palette.cpp000066400000000000000000000041431464327712600226240ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "Palette.hpp" #include "im_color.h" #include "w_wad.h" #include "gtest/gtest.h" #include // // Uses a common palette generated from 3:3:2 RGB (thus no grays) // void makeCommonPalette(Palette &palette) { auto wad = Wad_file::Open("dummy.wad", WadOpenMode::write); EXPECT_TRUE(wad); Lump_c &lump = wad->AddLump("PALETTE"); // Use 6:8:5 RGB + gray levels static const uint8_t redLevels[6] = {0, 51, 102, 153, 204, 255}; static const uint8_t greenLevels[8] = {0, 37, 73, 109, 146, 182, 219, 255}; static const uint8_t blueLevels[5] = {0, 64, 128, 192, 255}; for(uint8_t red : redLevels) for(uint8_t green : greenLevels) for(uint8_t blue : blueLevels) { uint8_t data[3] = {red, green, blue}; lump.Write(data, 3); } constexpr int numGrays = 256 - lengthof(redLevels) * lengthof(greenLevels) * lengthof(blueLevels); for(int i = 0; i < numGrays; ++i) { uint8_t data = (uint8_t)(256 / numGrays * i + 256 / numGrays / 2); lump.Write(&data, 1); lump.Write(&data, 1); lump.Write(&data, 1); } EXPECT_TRUE(palette.loadPalette(lump, 2, 2)); } // // Produces a vector for a grayscale palette // std::vector makeGrayscale() { std::vector data; data.reserve(768); for(int i = 0; i < 256; ++i) { // Make a simple f(x) = [x, x, x] data data.push_back((uint8_t)i); data.push_back((uint8_t)i); data.push_back((uint8_t)i); } return data; } eureka-editor-eureka-2.0.2/test/testUtils/Palette.hpp000066400000000000000000000016231464327712600226310ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef PALETTE_HPP_ #define PALETTE_HPP_ #include #include class Palette; void makeCommonPalette(Palette &palette); std::vector makeGrayscale(); #endif eureka-editor-eureka-2.0.2/test/testUtils/TempDirContext.cpp000066400000000000000000000037701464327712600241440ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2020 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "TempDirContext.hpp" #include "m_strings.h" #ifdef _WIN32 #include #include #else #include #endif // Linux: mkdtemp // Windows: GetTempPath void TempDirContext::SetUp() { #ifdef _WIN32 fs::path tempPath = fs::temp_directory_path(); UUID uuid = {}; RPC_STATUS status = UuidCreate(&uuid); ASSERT_EQ(status, RPC_S_OK); ASSERT_NE(uuid.Data1, 0); mTempDir = tempPath / SString::printf("EurekaTest%08x%04x%04x%02x%02x%02x%02x%02x%02x%02x%02x", uuid.Data1, uuid.Data2, uuid.Data3, uuid.Data4[0], uuid.Data4[1], uuid.Data4[2], uuid.Data4[3], uuid.Data4[4], uuid.Data4[5], uuid.Data4[6], uuid.Data4[7]).get(); fs::create_directory(mTempDir); #else char pattern[] = "/tmp/tempdirXXXXXX"; char *result = mkdtemp(pattern); ASSERT_NE(result, nullptr); mTempDir = result; ASSERT_FALSE(mTempDir.empty()); #endif } void TempDirContext::TearDown() { if(!mTempDir.empty()) { while(!mDeleteList.empty()) { // Don't assert fatally, so we get the change to delete what we can. fs::remove(mDeleteList.top()); mDeleteList.pop(); } fs::remove(mTempDir); } } // // Gets a child path // fs::path TempDirContext::getChildPath(const fs::path &path) const { return mTempDir / path; } TEST_F(TempDirContext, Test) { ASSERT_FALSE(mTempDir.empty()); } eureka-editor-eureka-2.0.2/test/testUtils/TempDirContext.hpp000066400000000000000000000021651464327712600241460ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2020 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #ifndef TempDirContext_hpp #define TempDirContext_hpp #include "gtest/gtest.h" #include #include "filesystem.hpp" namespace fs = ghc::filesystem; class TempDirContext : public ::testing::Test { protected: void SetUp() override; void TearDown() override; fs::path getChildPath(const fs::path &path) const; fs::path mTempDir; std::stack mDeleteList; }; #endif /* TempDirContext_hpp */ eureka-editor-eureka-2.0.2/test/w_dehacked_test.cpp000066400000000000000000000077401464327712600223510ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2024 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "w_dehacked.h" #include "m_game.h" #include "w_wad.h" #include "WadData.h" #include "testUtils/TempDirContext.hpp" #include "gtest/gtest.h" static const char *headerBoilerplate[] = { "Patch file for Dehacked v3.1", "# Here is the file", "" }; static const char *part1[] = { "Thing 2 (Imp Sarge Trooper Vanilla Shadow Ceiling Weapon)", "Initial frame = 442", "Width = 655360", "ID # = 2222", "Bits = 262400", "#$Editor category = Weapons", "", "Frame 442", "Sprite number = 31", "Sprite subnumber = 32769", "", "Text 4 4", "VILEABCD", "" }; static const char *part2[] = { "[SPRITES]", "30 = NEWB", "", "Thing 3 (Newbie)", "Bits = SPAWNCEILING+SHADOW" }; class DehackedTest : public TempDirContext { protected: void makeFile(); }; void DehackedTest::makeFile() { std::ofstream stream(getChildPath("tested.deh")); ASSERT_TRUE(stream.is_open()); mDeleteList.push(getChildPath("tested.deh")); // Add some bogus headers for(const char *line : headerBoilerplate) stream << line << std::endl; for(const char *line : part1) stream << line << std::endl; for(const char *line : part2) stream << line << std::endl; } TEST_F(DehackedTest, LoadNoFile) { ConfigData config; ASSERT_FALSE(dehacked::loadFile("bogus.deh", config)); } static ConfigData baseConfig() { ConfigData config; thingtype_t *type = &config.thing_types[3004]; type->group = 'm'; type->flags = 0; type->radius = 20; type->desc = "Trooper"; type->sprite = "POSS"; type = &config.thing_types[9]; type->group = 'm'; type->flags = 0; type->radius = 20; type->desc = "Sergeant"; type->sprite = "SPOS"; return config; } static void assertChangedConfig(const ConfigData &config) { ASSERT_EQ(config.thing_types.find(3004), config.thing_types.end()); auto it = config.thing_types.find(2222); ASSERT_NE(it, config.thing_types.end()); const thingtype_t *newtype = &it->second; ASSERT_EQ(newtype->group, 'w'); ASSERT_EQ(newtype->flags, THINGDEF_PASS | THINGDEF_CEIL | THINGDEF_INVIS | THINGDEF_LIT); ASSERT_EQ(newtype->radius, 10.0f); ASSERT_EQ(newtype->desc, "Imp Sarge Trooper Vanilla Shadow Ceiling Weapon"); ASSERT_EQ(newtype->sprite, "ABCDB"); it = config.thing_types.find(9); ASSERT_NE(it, config.thing_types.end()); newtype = &it->second; ASSERT_EQ(newtype->group, 'm'); ASSERT_EQ(newtype->flags, THINGDEF_CEIL | THINGDEF_INVIS); ASSERT_EQ(newtype->radius, 20.0f); ASSERT_EQ(newtype->desc, "Newbie"); ASSERT_EQ(newtype->sprite, "NEWB"); } TEST_F(DehackedTest, LoadFile) { makeFile(); ConfigData config = baseConfig(); bool result = dehacked::loadFile(getChildPath("tested.deh"), config); ASSERT_TRUE(result); assertChangedConfig(config); } TEST_F(DehackedTest, LoadLumps) { auto wad = Wad_file::Open("test.wad", WadOpenMode::write); ASSERT_TRUE(wad); Lump_c &dhe1 = wad->AddLump("DEHACKED"); for(const char *line : part1) dhe1.Printf("%s\n", line); std::vector> resources; resources.push_back(wad); wad = Wad_file::Open("test2.wad", WadOpenMode::write); resources.push_back(wad); Lump_c &dhe2 = wad->AddLump("DEHACKED"); for(const char *line : part2) dhe2.Printf("%s\n", line); MasterDir dir; dir.setResources(resources); ConfigData config = baseConfig(); dehacked::loadLumps(dir, config); assertChangedConfig(config); } eureka-editor-eureka-2.0.2/test/w_loadpic_test.cpp000066400000000000000000000220661464327712600222320ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2022 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "w_loadpic.h" #include "w_wad.h" #include "gtest/gtest.h" // // Helper fixture for DetectImageFormat // class DetectImageFormat : public ::testing::Test { protected: void SetUp() override; Lump_c *lump; byte header[20] = {}; private: std::shared_ptr wad; }; // // Sets up the lump // void DetectImageFormat::SetUp() { wad = Wad_file::Open("dummy.wad", WadOpenMode::write); ASSERT_TRUE(wad); lump = &wad->AddLump("PIC"); } TEST_F(DetectImageFormat, ShortFile) { // Empty lump give error ASSERT_EQ(W_DetectImageFormat(*lump), ImageFormat::unrecognized); // Write too little data error lump->Write(header, (int)(sizeof(header) - 1)); ASSERT_EQ(W_DetectImageFormat(*lump), ImageFormat::unrecognized); // Blank data error lump->clearData(); lump->Write(header, (int)sizeof(header)); ASSERT_EQ(W_DetectImageFormat(*lump), ImageFormat::unrecognized); } TEST_F(DetectImageFormat, PNG) { header[0] = 0x89; memcpy(header + 1, "PNG\r\n", 5); lump->Write(header, (int)sizeof(header)); ASSERT_EQ(W_DetectImageFormat(*lump), ImageFormat::png); } TEST_F(DetectImageFormat, JPEG) { const char *tags[] = { "JF", "Ex" }; for(int value = 0xe0; value < 0x100; ++value) { header[0] = 0xff; header[1] = 0xd8; header[2] = 0xff; header[3] = (byte)value; for(const char *tag : tags) { memcpy(header + 6, tag, 2); lump->clearData(); lump->Write(header, (int)sizeof(header)); ASSERT_EQ(W_DetectImageFormat(*lump), ImageFormat::jpeg); } } } TEST_F(DetectImageFormat, GIF) { const char *tags[] = { "GIF87a", "GIF88a", "GIF89a" }; for(const char *tag : tags) { memcpy(header, tag, 6); lump->clearData(); lump->Write(header, (int)sizeof(header)); ASSERT_EQ(W_DetectImageFormat(*lump), ImageFormat::gif); } } TEST_F(DetectImageFormat, DDS) { static const char tag[] = "DDS |"; memcpy(header, tag, 5); lump->Write(header, (int)sizeof(header)); ASSERT_EQ(W_DetectImageFormat(*lump), ImageFormat::dds); } TEST_F(DetectImageFormat, TGA) { int width = 512; int height = 1024; header[12] = (byte)(width & 0xff); header[13] = (byte)((width >> 8) & 0xff); header[14] = (byte)(height & 0xff); header[15] = (byte)((height >> 8) & 0xff); int cmap_type = 1; header[1] = (byte)cmap_type; int img_type = 10; header[2] = (byte)img_type; int depth = 24; header[16] = (byte)depth; lump->Write(header, (int)sizeof(header)); ASSERT_EQ(W_DetectImageFormat(*lump), ImageFormat::tga); } TEST_F(DetectImageFormat, doom) { int width = 64; int height = 128; header[0] = (byte)(width & 0xff); header[1] = (byte)((width >> 8) & 0xff); header[2] = (byte)(height & 0xff); header[3] = (byte)((height >> 8) & 0xff); int ofs_x = 32; int ofs_y = -32; header[4] = (byte)ofs_x; header[5] = 0; header[6] = (byte)ofs_y; lump->Write(header, (int)sizeof(header)); std::vector padding; padding.resize(4 * width); lump->Write(padding.data(), (int)padding.size()); ASSERT_EQ(W_DetectImageFormat(*lump), ImageFormat::doom); } //================================================================================================== static auto prepareData(const std::vector &data) { auto wad = Wad_file::Open("dummy.wad", WadOpenMode::write); EXPECT_TRUE(wad); auto &lump = wad->AddLump("LUMP"); lump.Write(data.data(), (int)data.size()); // IMPORTANT: must return pair because we must preserve the wad lifetime for the lump! return std::make_pair(wad, &lump); } static void assertImageValid(const tl::optional &image) { ASSERT_TRUE(image); ASSERT_FALSE(image->is_null()); ASSERT_EQ(image->width(), 4); // as per content of PNG data ASSERT_EQ(image->height(), 3); ASSERT_FALSE(image->has_transparent()); } static const std::vector pngData = { 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 4, 0, 0, 0, 3, 8, 6, 0, 0, 0, 180, 244, 174, 198, 0, 0, 0, 4, 115, 66, 73, 84, 8, 8, 8, 8, 124, 8, 100, 136, 0, 0, 0, 59, 73, 68, 65, 84, 8, 153, 5, 193, 49, 17, 192, 32, 16, 0, 193, 43, 50, 19, 1, 120, 72, 9, 18, 145, 240, 22, 144, 66, 71, 234, 248, 160, 134, 161, 185, 236, 34, 104, 132, 142, 165, 117, 122, 189, 189, 83, 114, 102, 159, 155, 47, 1, 85, 29, 106, 52, 229, 209, 31, 10, 229, 30, 135, 131, 75, 13, 237, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130, }; TEST(LoadImage, PNG) { // Prepare data auto data = prepareData(pngData); auto image = LoadImage_PNG(*data.second, "our image"); assertImageValid(image); } TEST(LoadImage, PNGBroken) { // 1 bit off auto brokenPNG = pngData; brokenPNG[brokenPNG.size() / 2] ^= 1; // Prepare data auto data = prepareData(brokenPNG); auto image = LoadImage_PNG(*data.second, "our image"); ASSERT_FALSE(image); } static const std::vector jpgData = { 255, 216, 255, 224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 255, 219, 0, 67, 0, 5, 3, 4, 4, 4, 3, 5, 4, 4, 4, 5, 5, 5, 6, 7, 12, 8, 7, 7, 7, 7, 15, 11, 11, 9, 12, 17, 15, 18, 18, 17, 15, 17, 17, 19, 22, 28, 23, 19, 20, 26, 21, 17, 17, 24, 33, 24, 26, 29, 29, 31, 31, 31, 19, 23, 34, 36, 34, 30, 36, 28, 30, 31, 30, 255, 219, 0, 67, 1, 5, 5, 5, 7, 6, 7, 14, 8, 8, 14, 30, 20, 17, 20, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 255, 192, 0, 17, 8, 0, 3, 0, 4, 3, 1, 34, 0, 2, 17, 1, 3, 17, 1, 255, 196, 0, 31, 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 255, 196, 0, 181, 16, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 125, 1, 2, 3, 0, 4, 17, 5, 18, 33, 49, 65, 6, 19, 81, 97, 7, 34, 113, 20, 50, 129, 145, 161, 8, 35, 66, 177, 193, 21, 82, 209, 240, 36, 51, 98, 114, 130, 9, 10, 22, 23, 24, 25, 26, 37, 38, 39, 40, 41, 42, 52, 53, 54, 55, 56, 57, 58, 67, 68, 69, 70, 71, 72, 73, 74, 83, 84, 85, 86, 87, 88, 89, 90, 99, 100, 101, 102, 103, 104, 105, 106, 115, 116, 117, 118, 119, 120, 121, 122, 131, 132, 133, 134, 135, 136, 137, 138, 146, 147, 148, 149, 150, 151, 152, 153, 154, 162, 163, 164, 165, 166, 167, 168, 169, 170, 178, 179, 180, 181, 182, 183, 184, 185, 186, 194, 195, 196, 197, 198, 199, 200, 201, 202, 210, 211, 212, 213, 214, 215, 216, 217, 218, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 255, 196, 0, 31, 1, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 255, 196, 0, 181, 17, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 119, 0, 1, 2, 3, 17, 4, 5, 33, 49, 6, 18, 65, 81, 7, 97, 113, 19, 34, 50, 129, 8, 20, 66, 145, 161, 177, 193, 9, 35, 51, 82, 240, 21, 98, 114, 209, 10, 22, 36, 52, 225, 37, 241, 23, 24, 25, 26, 38, 39, 40, 41, 42, 53, 54, 55, 56, 57, 58, 67, 68, 69, 70, 71, 72, 73, 74, 83, 84, 85, 86, 87, 88, 89, 90, 99, 100, 101, 102, 103, 104, 105, 106, 115, 116, 117, 118, 119, 120, 121, 122, 130, 131, 132, 133, 134, 135, 136, 137, 138, 146, 147, 148, 149, 150, 151, 152, 153, 154, 162, 163, 164, 165, 166, 167, 168, 169, 170, 178, 179, 180, 181, 182, 183, 184, 185, 186, 194, 195, 196, 197, 198, 199, 200, 201, 202, 210, 211, 212, 213, 214, 215, 216, 217, 218, 226, 227, 228, 229, 230, 231, 232, 233, 234, 242, 243, 244, 245, 246, 247, 248, 249, 250, 255, 218, 0, 12, 3, 1, 0, 2, 17, 3, 17, 0, 63, 0, 79, 218, 39, 197, 186, 255, 0, 133, 124, 119, 109, 162, 248, 122, 242, 61, 59, 78, 135, 76, 131, 203, 183, 138, 218, 45, 171, 157, 221, 50, 166, 138, 40, 175, 233, 14, 30, 203, 48, 82, 202, 232, 74, 84, 98, 223, 42, 251, 43, 252, 143, 147, 254, 212, 198, 217, 126, 250, 93, 62, 211, 255, 0, 51, 255, 217 }; TEST(LoadImage, JPEG) { auto data = prepareData(jpgData); auto image = LoadImage_JPEG(*data.second, "our jpg"); assertImageValid(image); } TEST(LoadImage, JPEGBroken) { auto brokenJPG = jpgData; brokenJPG[brokenJPG.size() - 1] ^= 1; auto data = prepareData(brokenJPG); auto image = LoadImage_JPEG(*data.second, "our jpg"); ASSERT_FALSE(image); } TEST(LoadImage, TGA) { std::vector tgaData = { 17, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 3, 0, 32, 8, 16, 67, 114, 101, 97, 116, 101, 100, 32, 98, 121, 32, 80, 105, 110, 116, 97, 255, 255, 127, 255, 255, 255, 199, 255, 255, 160, 143, 255, 255, 38, 0, 255, 192, 192, 199, 255, 238, 238, 246, 255, 254, 232, 238, 255, 247, 146, 192, 255, 0, 0, 255, 255, 143, 143, 255, 255, 247, 199, 255, 255, 237, 127, 255, 255, }; auto data = prepareData(tgaData); auto image = LoadImage_TGA(*data.second, "our tga"); assertImageValid(image); } eureka-editor-eureka-2.0.2/test/w_texture_test.cpp000066400000000000000000000046131464327712600223150ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2023 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "WadData.h" #include "m_game.h" #include "m_loadsave.h" #include "w_wad.h" #include "gtest/gtest.h" TEST(Texture, WadDataGetSpriteDetectsNonstandardRotations) { ConfigData config; thingtype_t type = {}; type.group = 'C'; type.flags = 0; type.radius = 20; type.scale = 1.0; type.desc = "Description"; type.sprite = "POSS"; type.color = 0xff000000; config.thing_types[3004] = type; auto wad = Wad_file::Open("dummy.wad", WadOpenMode::write); ASSERT_TRUE(wad); wad->AddLump("S_START"); auto &spritelump = wad->AddLump("POSSA3D7"); static const uint8_t tga[] = { 17, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 3, 0, 32, 8, 16, 67, 114, 101, 97, 116, 101, 100, 32, 98, 121, 32, 80, 105, 110, 116, 97, 255, 255, 127, 255, 255, 255, 199, 255, 255, 160, 143, 255, 255, 38, 0, 255, 192, 192, 199, 255, 238, 238, 246, 255, 254, 232, 238, 255, 247, 146, 192, 255, 0, 0, 255, 255, 143, 143, 255, 255, 247, 199, 255, 255, 237, 127, 255, 255, }; spritelump.Write(tga, sizeof(tga)); wad->AddLump("S_END"); WadData wadData; wadData.master.setGameWad(wad); LoadingData loading; auto image = wadData.getSprite(config, 3004, loading, 3); ASSERT_TRUE(image); } TEST(Texture, WadDataGetNullSprite) { ConfigData config; thingtype_t type = {}; type.desc = "UNKNOWN"; config.thing_types[1234] = type; LoadingData loading; WadData wadData; auto image = wadData.getSprite(config, 1234, loading, 1); ASSERT_FALSE(image); // Try twice to make sure we don't crash (happened before) image = wadData.getSprite(config, 1234, loading, 1); ASSERT_FALSE(image); } eureka-editor-eureka-2.0.2/test/w_wad_test.cpp000066400000000000000000000516121464327712600213710ustar00rootroot00000000000000//------------------------------------------------------------------------ // // Eureka DOOM Editor // // Copyright (C) 2021 Ioan Chera // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //------------------------------------------------------------------------ #include "w_wad.h" #include "WadData.h" #include "testUtils/TempDirContext.hpp" #ifdef None // fix pollution #undef None #endif #include "gtest/gtest.h" class WadFileTest : public TempDirContext { }; // // Reads data from path. // // NOTE: Google Test doesn't allow its assertion macros to be called in non-void // functions. // static void readFromPath(const fs::path &path, std::vector &data) { FILE *f = fopen(path.u8string().c_str(), "rb"); ASSERT_NE(f, nullptr); uint8_t buffer[4096]; data.clear(); while(!feof(f)) { size_t n = fread(buffer, 1, 4096, f); ASSERT_FALSE(ferror(f)); if(n > 0) data.insert(data.end(), buffer, buffer + n); } ASSERT_EQ(fclose(f), 0); } // // Convenience test of vector vs string // static void assertVecString(const std::vector &data, const char *text) { // WARNING: cannot assert the strlen, because the string can also have nul ASSERT_FALSE(memcmp(data.data(), text, data.size())); } TEST_F(WadFileTest, Open) { std::shared_ptr wad; // Opening a missing file for reading should fail wad = Wad_file::Open(getChildPath("inexistent.wad"), WadOpenMode::read); ASSERT_FALSE(wad); // Opening for writing or appending should be fine. wad = Wad_file::Open(getChildPath("newwad.wad"), WadOpenMode::write); ASSERT_TRUE(wad); // File won't get created per se, so don't add it to the delete list. // Zero lumps for the new file. ASSERT_EQ(wad->NumLumps(), 0); wad = Wad_file::Open(getChildPath("appendwad.wad"), WadOpenMode::append); ASSERT_TRUE(wad); // Same as with writing, no file created unless "writeToDisk". In addition, // check that it's empty, just like the writing mode. ASSERT_EQ(wad->NumLumps(), 0); } // // Tests that whatever we write is formatted correctly, and that reading it will // bring back the correct data. // TEST_F(WadFileTest, WriteRead) { std::shared_ptr wad; std::shared_ptr read; // Prepare the test path fs::path path = getChildPath("newwad.wad"); wad = Wad_file::Open(path, WadOpenMode::write); ASSERT_EQ(wad->PathName(), path); ASSERT_FALSE(wad->IsReadOnly()); ASSERT_FALSE(wad->IsIWAD()); ASSERT_TRUE(wad); // Write it lumpless wad->writeToDisk(); mDeleteList.push(path); // Right now add some data to it. Since writeToDisk won't be called yet, // the lump should only be there in memory. Lump_c *lump = &wad->AddLump("HelloWorld"); ASSERT_NE(lump, nullptr); // Check that the name gets upper-cased and truncated. ASSERT_EQ(lump->Name(), "HELLOWOR"); // Check that what we wrote was _before_ adding the lump. // Check the lump-less wad content std::vector data; std::vector wadReadData; // this is when loading a Wad_file readFromPath(path, data); ASSERT_EQ(data.size(), 12); assertVecString(data, "PWAD\0\0\0\0\x0c\0\0\0"); // The read wad read = Wad_file::Open(path, WadOpenMode::read); ASSERT_TRUE(read); ASSERT_EQ(read->NumLumps(), 0); // Now write it with the new lump. wad->writeToDisk(); readFromPath(path, data); ASSERT_EQ(data.size(), 12 + 16); // header and one dir entry assertVecString(data, "PWAD\x01\0\0\0\x0c\0\0\0" "\x0c\0\0\0\0\0\0\0HELLOWOR"); // And the wad read = Wad_file::Open(path, WadOpenMode::read); ASSERT_TRUE(read); ASSERT_EQ(read->NumLumps(), 1); ASSERT_EQ(read->GetLump(0)->Name(), "HELLOWOR"); ASSERT_EQ(read->GetLump(0)->Length(), 0); // Now add some data to that lump lump->Printf("Hello, world!"); wad->writeToDisk(); // and update the disk entry // Check again readFromPath(path, data); ASSERT_EQ(data.size(), 12 + 16 + 13); // header, dir entry and content // Info table ofs: 12 + 13 = 25 (0x19) assertVecString(data, "PWAD\x01\0\0\0\x19\0\0\0" "Hello, world!" "\x0c\0\0\0\x0d\0\0\0HELLOWOR"); // And the wad read = Wad_file::Open(path, WadOpenMode::read); ASSERT_TRUE(read); ASSERT_EQ(read->NumLumps(), 1); ASSERT_EQ(read->GetLump(0)->Name(), "HELLOWOR"); ASSERT_EQ(read->GetLump(0)->Length(), 13); wadReadData = read->GetLump(0)->getData(); assertVecString(wadReadData, "Hello, world!"); // Now add yet another lump at the end lump = &wad->AddLump("LUMPLUMP"); ASSERT_NE(lump, nullptr); lump->Printf("Ah"); // Also add a lump in the middle. Test the insertion point feature wad->InsertPoint(1); lump = &wad->AddLump("MIDLump"); ASSERT_NE(lump, nullptr); lump->Printf("Doom"); ASSERT_EQ(wad->TotalSize(), 12 + 13 + 4 + 2 + 48); wad->writeToDisk(); // Check readFromPath(path, data); ASSERT_EQ(data.size(), 12 + 13 + 4 + 2 + 48); // Info table ofs: 12 + 13 + 4 + 2 = 25 + 6 = 31 = 0x1f assertVecString(data, "PWAD\x03\0\0\0\x1f\0\0\0" "Hello, world!" "Doom" "Ah" "\x0c\0\0\0\x0d\0\0\0HELLOWOR" "\x19\0\0\0\x04\0\0\0MIDLUMP\0" "\x1d\0\0\0\x02\0\0\0LUMPLUMP"); // And check the wad read = Wad_file::Open(path, WadOpenMode::read); ASSERT_TRUE(read); ASSERT_EQ(read->NumLumps(), 3); ASSERT_EQ(read->GetLump(0)->Name(), "HELLOWOR"); ASSERT_EQ(read->GetLump(0)->Length(), 13); wadReadData = read->GetLump(0)->getData(); assertVecString(wadReadData, "Hello, world!"); ASSERT_EQ(read->GetLump(1)->Name(), "MIDLUMP"); ASSERT_EQ(read->GetLump(1)->Length(), 4); wadReadData = read->GetLump(1)->getData(); assertVecString(wadReadData, "Doom"); ASSERT_EQ(read->GetLump(2)->Name(), "LUMPLUMP"); ASSERT_EQ(read->GetLump(2)->Length(), 2); wadReadData = read->GetLump(2)->getData(); ASSERT_EQ(read->TotalSize(), 12 + 13 + 4 + 2 + 48); assertVecString(wadReadData, "Ah"); // Lump lookup tests ASSERT_EQ(read->FindLump("MIDLuMP"), read->GetLump(1)); ASSERT_EQ(read->FindLump("MIXLUMP"), nullptr); ASSERT_EQ(read->FindLumpNum("LUMPLump"), 2); ASSERT_EQ(read->FindLumpNum("LUMPLuma"), -1); ASSERT_EQ(read->FindLumpInNamespace("HelloWor", WadNamespace::Global), read->GetLump(0)); ASSERT_EQ(read->FindLumpInNamespace("HelloWor", WadNamespace::Flats), nullptr); ASSERT_EQ(read->LevelCount(), 0); ASSERT_EQ(read->LevelFindFirst(), -1); // Test renaming read->RenameLump(read->FindLumpNum("LumpLump"), "BaronOfHell"); ASSERT_EQ(read->GetLump(2)->Name(), "BARONOFH"); // Test name8 int64_t nm8 = read->GetLump(2)->getName8(); char buf[9] = {}; memcpy(buf, &nm8, 8); ASSERT_STREQ(buf, "BARONOFH"); } TEST_F(WadFileTest, Validate) { // Inexistent path should fail validation ASSERT_FALSE(Wad_file::Validate(getChildPath("None.wad"))); fs::path path = getChildPath("wad.wad"); FILE *f = fopen(path.u8string().c_str(), "wb"); ASSERT_NE(f, nullptr); mDeleteList.push(path); fprintf(f, "abcdefghijklmnopq"); ASSERT_EQ(fclose(f), 0); // Will not work: no WAD signature ASSERT_FALSE(Wad_file::Validate(path)); f = fopen(path.u8string().c_str(), "r+b"); ASSERT_NE(f, nullptr); ASSERT_EQ(fseek(f, 1, SEEK_SET), 0); fprintf(f, "WAD"); // put WAD on the second char ASSERT_EQ(fclose(f), 0); // Will be validated due to the WAD signature ASSERT_TRUE(Wad_file::Validate(path)); // Now have it f = fopen(path.u8string().c_str(), "wb"); ASSERT_NE(f, nullptr); fprintf(f, "%s", "PWAD\0\0\01"); ASSERT_EQ(fclose(f), 0); // Will not be validated due to length ASSERT_FALSE(Wad_file::Validate(path)); } // // Test FindLumpInNamespace // TEST_F(WadFileTest, FindLumpInNamespace) { auto wad = Wad_file::Open("dummy.wad", WadOpenMode::write); ASSERT_TRUE(wad); // Print data for each new lump so it gets namespaced correctly wad->AddLump("F_START"); // 0 wad->AddLump("LUMP"); wad->GetLump(wad->NumLumps() - 1)->Printf("data"); wad->AddLump("F_END"); wad->AddLump("FF_START"); wad->AddLump("LUMP2"); // 4 wad->GetLump(wad->NumLumps() - 1)->Printf("data"); wad->AddLump("F_END"); wad->AddLump("FF_START"); wad->AddLump("LUMP3"); wad->GetLump(wad->NumLumps() - 1)->Printf("data"); wad->AddLump("FF_END"); // 8 wad->AddLump("S_START"); wad->AddLump("LUMP"); wad->GetLump(wad->NumLumps() - 1)->Printf("data"); wad->AddLump("S_END"); wad->AddLump("SS_START"); // 12 wad->AddLump("LUMP2"); wad->GetLump(wad->NumLumps() - 1)->Printf("data"); wad->AddLump("S_END"); wad->AddLump("SS_START"); wad->AddLump("LUMP3"); // 16 wad->GetLump(wad->NumLumps() - 1)->Printf("data"); wad->AddLump("SS_END"); wad->AddLump("TX_START"); wad->AddLump("LUMP"); wad->GetLump(wad->NumLumps() - 1)->Printf("data"); wad->AddLump("TX_END"); // 20 wad->AddLump("LUMP"); wad->GetLump(wad->NumLumps() - 1)->Printf("data"); ASSERT_EQ(wad->FindLumpInNamespace("LUMP", WadNamespace::Global), wad->GetLump(21)); ASSERT_EQ(wad->FindLumpInNamespace("LUMP", WadNamespace::Flats), wad->GetLump(1)); ASSERT_EQ(wad->FindLumpInNamespace("LUMP2", WadNamespace::Flats), wad->GetLump(4)); ASSERT_EQ(wad->FindLumpInNamespace("LUMP3", WadNamespace::Flats), wad->GetLump(7)); ASSERT_EQ(wad->FindLumpInNamespace("LUMP", WadNamespace::Sprites), wad->GetLump(10)); ASSERT_EQ(wad->FindLumpInNamespace("LUMP2", WadNamespace::Sprites), wad->GetLump(13)); ASSERT_EQ(wad->FindLumpInNamespace("LUMP3", WadNamespace::Sprites), wad->GetLump(16)); ASSERT_EQ(wad->FindLumpInNamespace("LUMP", WadNamespace::TextureLumps), wad->GetLump(19)); } // // Query levels // TEST_F(WadFileTest, LevelQuery) { fs::path path = getChildPath("wad.wad"); auto wad = Wad_file::Open(path, WadOpenMode::write); ASSERT_TRUE(wad); // Classic Doom map. Give it a nonstandard name // NOTE: when adding, we must explicitly state if the lump is a level wad->AddLevel("MAP45"); // 0 (deliberately after UDMF) wad->AddLump("THINGS"); wad->AddLump("LINEDEFS"); wad->AddLump("SIDEDEFS"); wad->AddLump("VERTEXES"); // 4 wad->AddLump("SEGS"); wad->AddLump("SSECTORS"); wad->AddLump("NODES"); wad->AddLump("SECTORS"); // 8 wad->AddLump("REJECT"); wad->AddLump("BLOCKMAP"); wad->AddLump("BEHAVIOR"); wad->AddLump("GL_JACK"); // 12, random name // UDMF map ASSERT_TRUE(wad->AddLevel("E2M4")); wad->AddLump("TEXTMAP"); wad->AddLump("ZNODES"); wad->AddLump("BLOCKMAP"); // 16, give these rarely-used lumps wad->AddLump("REJECT"); wad->AddLump("ENDMAP"); // Test the sorting... ASSERT_EQ(wad->LevelHeader(0), 0); ASSERT_EQ(wad->LevelHeader(1), 13); wad->SortLevels(); ASSERT_EQ(wad->LevelHeader(0), 13); ASSERT_EQ(wad->LevelHeader(1), 0); wad->writeToDisk(); mDeleteList.push(path); // For this test, let's assume UDMF is active global::udmf_testing = true; // Also check how a wad read from file behaves auto read = Wad_file::Open(path, WadOpenMode::read); ASSERT_TRUE(read); // Test both wads. The second one shall autodetect for(const std::shared_ptr &w : { wad, read }) { if(w.get() == wad.get()) puts("Testing WRITTEN file"); else puts("Testing READ file"); // Check the simple queries ASSERT_EQ(w->LevelCount(), 2); // NOTE: check that they get sorted ASSERT_EQ(w->LevelHeader(0), 13); ASSERT_EQ(w->LevelLastLump(0), 18); ASSERT_EQ(w->LevelHeader(1), 0); ASSERT_EQ(w->LevelLastLump(1), 12); ASSERT_EQ(w->LevelFind("E2M4"), 0); ASSERT_EQ(w->LevelFind("MAP45"), 1); ASSERT_EQ(w->LevelFind("OTHER"), -1); ASSERT_EQ(w->LevelFindByNumber(24), 0); ASSERT_EQ(w->LevelFindByNumber(45), 1); ASSERT_EQ(w->LevelFindByNumber(23), -1); // the other kind is for no-level wads ASSERT_EQ(w->LevelFindFirst(), 0); ASSERT_EQ(w->LevelLookupLump(0, "BLOCKMAP"), 16); ASSERT_EQ(w->LevelLookupLump(0, "ENDMAP"), 18); ASSERT_EQ(w->LevelLookupLump(0, "ZNODES"), 15); ASSERT_EQ(w->LevelLookupLump(1, "BLOCKMAP"), 10); ASSERT_EQ(w->LevelLookupLump(1, "ZNODES"), -1); ASSERT_EQ(w->LevelFormat(0), MapFormat::udmf); ASSERT_EQ(w->LevelFormat(1), MapFormat::hexen); } // Now remove behaviour and check the new format and level indices wad->RemoveLumps(11, 2); // Behavior and GL_jack ASSERT_EQ(wad->LevelFormat(0), MapFormat::udmf); ASSERT_EQ(wad->LevelFormat(1), MapFormat::doom); // no behavior: doom ASSERT_EQ(wad->LevelHeader(0), 11); ASSERT_EQ(wad->LevelLastLump(0), 16); ASSERT_EQ(wad->LevelHeader(1), 0); ASSERT_EQ(wad->LevelLastLump(1), 10); // Now remove the second level (first from directory) wad->RemoveLevel(1); ASSERT_EQ(wad->LevelCount(), 1); ASSERT_EQ(wad->LevelFormat(0), MapFormat::udmf); ASSERT_EQ(wad->LevelHeader(0), 0); ASSERT_EQ(wad->LevelLastLump(0), 5); // Since we already removed stuff from the wad, we should now test the read read->RemoveGLNodes(0); // also test levels lacking it read->RemoveGLNodes(1); ASSERT_EQ(read->LevelHeader(0), 12); ASSERT_EQ(read->LevelLastLump(0), 17); ASSERT_EQ(read->LevelHeader(1), 0); ASSERT_EQ(read->LevelLastLump(1), 11); read->RemoveZNodes(0); read->RemoveZNodes(1); ASSERT_EQ(read->LevelHeader(0), 12); ASSERT_EQ(read->LevelLastLump(0), 16); ASSERT_EQ(read->LevelHeader(1), 0); ASSERT_EQ(read->LevelLastLump(1), 11); } // // Tests that the backup will write exactly like writeToDisk. // TEST_F(WadFileTest, Backup) { fs::path path = getChildPath("wad.wad"); fs::path path2 = getChildPath("wad2.wad"); auto wad = Wad_file::Open(path, WadOpenMode::write); ASSERT_TRUE(wad); wad->AddLump("LUMP1"); wad->GetLump(wad->NumLumps() - 1)->Printf("Hello, world!"); wad->AddLump("LUMP2"); wad->GetLump(wad->NumLumps() - 1)->Printf("Goodbye!"); ASSERT_TRUE(wad->Backup(path2)); mDeleteList.push(path2); wad->writeToDisk(); mDeleteList.push(path); // Test it now std::vector data, data2; readFromPath(path, data); readFromPath(path2, data2); ASSERT_FALSE(data.empty()); ASSERT_EQ(data, data2); } TEST_F(WadFileTest, LumpIO) { auto wad = Wad_file::Open("dummy.wad", WadOpenMode::write); Lump_c &lump = wad->AddLump("LUMP"); lump.Printf("Hello, world!"); LumpInputStream stream(lump); char data[20] = {}; ASSERT_TRUE(stream.read(data, 12)); ASSERT_STREQ(data, "Hello, world"); // Won't accept post-EOF ASSERT_FALSE(stream.read(data, 2)); // If we got false, we're now at EOF and must rewind ASSERT_FALSE(stream.read(data, 1)); LumpInputStream stream2(lump); memset(data, 0, sizeof(data)); ASSERT_TRUE(stream2.read(data, 5)); ASSERT_TRUE(stream2.read(data + 5, 7)); ASSERT_STREQ(data, "Hello, world"); // Now test GetLine Lump_c &lump2 = wad->AddLump("LUMP2"); lump2.Printf("Hello\nworld\nand you!"); LumpInputStream stream3(lump2); SString line; ASSERT_TRUE(stream3.readLine(line)); ASSERT_EQ(line, "Hello\n"); ASSERT_TRUE(stream3.readLine(line)); ASSERT_EQ(line, "world\n"); ASSERT_TRUE(stream3.readLine(line)); ASSERT_EQ(line, "and you!"); ASSERT_FALSE(stream3.readLine(line)); } TEST_F(WadFileTest, LumpFromFile) { fs::path path = getChildPath("wad.wad"); auto wad = Wad_file::Open(path, WadOpenMode::write); ASSERT_TRUE(wad); wad->writeToDisk(); mDeleteList.push(path); Lump_c &lump = wad->AddLump("Test"); FILE *f = fopen(path.u8string().c_str(), "rb"); ASSERT_TRUE(f); ASSERT_EQ(lump.writeData(f, 32), 12); ASSERT_EQ(fclose(f), 0); ASSERT_EQ(lump.Length(), 12); // Test getData ASSERT_FALSE(memcmp(lump.getData().data(), "PWAD\0\0\0\0\x0c\0\0\0", 12)); } TEST_F(WadFileTest, FindFirstSpriteLump) { auto wad = Wad_file::Open("dummy.wad", WadOpenMode::write); ASSERT_TRUE(wad); wad->AddLump("POSSA1"); wad->AddLump("S_START"); Lump_c &possa1 = wad->AddLump("POSSA1"); possa1.Printf("a"); // need to have content to be considered Lump_c &possa2d3 = wad->AddLump("POSSA2D3"); possa2d3.Printf("a"); Lump_c &trooc1 = wad->AddLump("TROOC1"); trooc1.Printf("a"); Lump_c &possa3d2 = wad->AddLump("POSSA3D2"); possa3d2.Printf("a"); Lump_c &troob1 = wad->AddLump("TROOB1"); troob1.Printf("a"); Lump_c &trood1 = wad->AddLump("TROOD1"); trood1.Printf("a"); wad->AddLump("S_END"); std::vector expected = { {&possa1, false}, {&possa2d3, false}, {&possa3d2, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, }; std::vector tested = wad->findFirstSpriteLump("POSS"); for(int i = 0; i < 8; ++i) { ASSERT_EQ(tested.at(i).lump, expected[i].lump); ASSERT_EQ(tested.at(i).flipped, expected[i].flipped); } tested = wad->findFirstSpriteLump("POSSA"); for(int i = 0; i < 8; ++i) { ASSERT_EQ(tested.at(i).lump, expected[i].lump); ASSERT_EQ(tested.at(i).flipped, expected[i].flipped); } expected = { {&trooc1, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, }; tested = wad->findFirstSpriteLump("TROOC"); for(int i = 0; i < 8; ++i) { ASSERT_EQ(tested.at(i).lump, expected[i].lump); ASSERT_EQ(tested.at(i).flipped, expected[i].flipped); } tested = wad->findFirstSpriteLump("POSSD"); ASSERT_TRUE(tested.empty()); tested = wad->findFirstSpriteLump("POSSD2"); ASSERT_TRUE(tested.empty()); expected = { {&possa1, false}, {&possa2d3, false}, {&possa3d2, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, }; tested = wad->findFirstSpriteLump("POSSA3"); for(int i = 0; i < 8; ++i) { ASSERT_EQ(tested.at(i).lump, expected[i].lump); ASSERT_EQ(tested.at(i).flipped, expected[i].flipped); } expected = { {&troob1, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, {nullptr, false}, }; tested = wad->findFirstSpriteLump("TROO"); for(int i = 0; i < 8; ++i) { ASSERT_EQ(tested.at(i).lump, expected[i].lump); ASSERT_EQ(tested.at(i).flipped, expected[i].flipped); } tested = wad->findFirstSpriteLump("POSSD4"); ASSERT_TRUE(tested.empty()); } TEST_F(WadFileTest, ReadFromInvalidDir) { auto wad = Wad_file::readFromDir(getChildPath("jackson")); ASSERT_FALSE(wad); fs::path normalFile = getChildPath("file.txt"); std::ofstream ofs(normalFile); ASSERT_TRUE(ofs); mDeleteList.push(normalFile); ofs.close(); wad = Wad_file::readFromDir(normalFile); ASSERT_FALSE(wad); } TEST_F(WadFileTest, ReadDirectory) { fs::path dir = getChildPath("dir"); fs::create_directory(dir); mDeleteList.push(dir); auto addFile = [this](const fs::path &dir, const fs::path &name, const char *content) { fs::path path = dir / name; std::ofstream stream(path); ASSERT_TRUE(stream); mDeleteList.push(path); stream << content; // also write something }; addFile(dir, "file1", "File one"); addFile(dir, "File2.txt", "File two"); addFile(dir, ".file3", "File three"); addFile(dir, ".File4.txt", "File four"); addFile(dir, "FileMoreLength.txt", "File five"); fs::path subdir = dir / "flats"; fs::create_directory(subdir); mDeleteList.push(subdir); addFile(subdir, "flat1.lmp", "Flat one"); addFile(subdir, "longtexname", "Flat two"); subdir = dir / "sprites"; fs::create_directory(subdir); mDeleteList.push(subdir); addFile(subdir, "POSSA1.png", "sprite one"); addFile(subdir, "POSSA1^1.png", "sprite two"); subdir = dir / "textures"; fs::create_directory(subdir); mDeleteList.push(subdir); addFile(subdir, "TEX1.png", "texture one"); subdir = dir / "sounds"; // no namespace here fs::create_directory(subdir); mDeleteList.push(subdir); addFile(subdir, "sound1.wav", "sound one"); fs::path subsubdir = dir / "sounds" / "extra"; fs::create_directory(subsubdir); mDeleteList.push(subsubdir); addFile(subsubdir, "SUBLUMP.txt", "Sub"); // this will NOT be loaded auto wad = Wad_file::readFromDir(dir); ASSERT_TRUE(wad); // Now inspect the wad // Order can be random, so make a map std::unordered_map> expected = { {"FILE1", {"File one", WadNamespace::Global}}, {"FILE2", {"File two", WadNamespace::Global}}, {".FILE3", {"File three", WadNamespace::Global}}, {".FILE4", {"File four", WadNamespace::Global}}, {"FILEMORE", {"File five", WadNamespace::Global}}, {"FLAT1", {"Flat one", WadNamespace::Flats}}, {"LONGTEXN", {"Flat two", WadNamespace::Flats}}, {"POSSA1", {"sprite one", WadNamespace::Sprites}}, {"POSSA1\\1", {"sprite two", WadNamespace::Sprites}}, {"TEX1", {"texture one", WadNamespace::TextureLumps}}, {"SOUND1", {"sound one", WadNamespace::Global}}, }; int numlumps = wad->NumLumps(); for(int i = 0; i < numlumps; ++i) { const Lump_c *lump = wad->GetLump(i); ASSERT_TRUE(lump); auto it = expected.find(lump->Name()); ASSERT_NE(it, expected.end()); ASSERT_EQ(lump->Length(), (int)it->second.first.length()); ASSERT_FALSE(memcmp(lump->getData().data(), it->second.first.c_str(), it->second.first.length())); ASSERT_EQ(wad->FindLumpInNamespace(lump->Name(), it->second.second), lump); expected.erase(it); // erase it so we don't find stuff twice } ASSERT_TRUE(expected.empty()); // consumed } eureka-editor-eureka-2.0.2/win/000077500000000000000000000000001464327712600163365ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/win/CMakeLists.txt000066400000000000000000000003151464327712600210750ustar00rootroot00000000000000add_library(eurekawin STATIC include/GL/glext.h include/KHR/khrplatform.h dummywin.cpp) target_include_directories(eurekawin PUBLIC include) set_target_properties(eurekawin PROPERTIES LINKER_LANGUAGE CXX) eureka-editor-eureka-2.0.2/win/dummywin.cpp000066400000000000000000000000271464327712600207120ustar00rootroot00000000000000// Intentionally blank eureka-editor-eureka-2.0.2/win/include/000077500000000000000000000000001464327712600177615ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/win/include/GL/000077500000000000000000000000001464327712600202635ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/win/include/GL/glext.h000066400000000000000000031756341464327712600216020ustar00rootroot00000000000000#ifndef __gl_glext_h_ #define __gl_glext_h_ 1 #ifdef __cplusplus extern "C" { #endif /* ** Copyright 2013-2020 The Khronos Group Inc. ** SPDX-License-Identifier: MIT ** ** This header is generated from the Khronos OpenGL / OpenGL ES XML ** API Registry. The current version of the Registry, generator scripts ** used to make the header, and the header can be found at ** https://github.com/KhronosGroup/OpenGL-Registry */ #if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN 1 #endif #include #endif #ifndef APIENTRY #define APIENTRY #endif #ifndef APIENTRYP #define APIENTRYP APIENTRY * #endif #ifndef GLAPI #define GLAPI extern #endif #define GL_GLEXT_VERSION 20210107 #include /* Generated C header for: * API: gl * Profile: compatibility * Versions considered: .* * Versions emitted: 1\.[2-9]|[234]\.[0-9] * Default extensions included: gl * Additional extensions included: _nomatch_^ * Extensions removed: _nomatch_^ */ #ifndef GL_VERSION_1_2 #define GL_VERSION_1_2 1 #define GL_UNSIGNED_BYTE_3_3_2 0x8032 #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 #define GL_UNSIGNED_INT_8_8_8_8 0x8035 #define GL_UNSIGNED_INT_10_10_10_2 0x8036 #define GL_TEXTURE_BINDING_3D 0x806A #define GL_PACK_SKIP_IMAGES 0x806B #define GL_PACK_IMAGE_HEIGHT 0x806C #define GL_UNPACK_SKIP_IMAGES 0x806D #define GL_UNPACK_IMAGE_HEIGHT 0x806E #define GL_TEXTURE_3D 0x806F #define GL_PROXY_TEXTURE_3D 0x8070 #define GL_TEXTURE_DEPTH 0x8071 #define GL_TEXTURE_WRAP_R 0x8072 #define GL_MAX_3D_TEXTURE_SIZE 0x8073 #define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 #define GL_UNSIGNED_SHORT_5_6_5 0x8363 #define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 #define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 #define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 #define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 #define GL_BGR 0x80E0 #define GL_BGRA 0x80E1 #define GL_MAX_ELEMENTS_VERTICES 0x80E8 #define GL_MAX_ELEMENTS_INDICES 0x80E9 #define GL_CLAMP_TO_EDGE 0x812F #define GL_TEXTURE_MIN_LOD 0x813A #define GL_TEXTURE_MAX_LOD 0x813B #define GL_TEXTURE_BASE_LEVEL 0x813C #define GL_TEXTURE_MAX_LEVEL 0x813D #define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 #define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 #define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 #define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 #define GL_ALIASED_LINE_WIDTH_RANGE 0x846E #define GL_RESCALE_NORMAL 0x803A #define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 #define GL_SINGLE_COLOR 0x81F9 #define GL_SEPARATE_SPECULAR_COLOR 0x81FA #define GL_ALIASED_POINT_SIZE_RANGE 0x846D typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); GLAPI void APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); #endif #endif /* GL_VERSION_1_2 */ #ifndef GL_VERSION_1_3 #define GL_VERSION_1_3 1 #define GL_TEXTURE0 0x84C0 #define GL_TEXTURE1 0x84C1 #define GL_TEXTURE2 0x84C2 #define GL_TEXTURE3 0x84C3 #define GL_TEXTURE4 0x84C4 #define GL_TEXTURE5 0x84C5 #define GL_TEXTURE6 0x84C6 #define GL_TEXTURE7 0x84C7 #define GL_TEXTURE8 0x84C8 #define GL_TEXTURE9 0x84C9 #define GL_TEXTURE10 0x84CA #define GL_TEXTURE11 0x84CB #define GL_TEXTURE12 0x84CC #define GL_TEXTURE13 0x84CD #define GL_TEXTURE14 0x84CE #define GL_TEXTURE15 0x84CF #define GL_TEXTURE16 0x84D0 #define GL_TEXTURE17 0x84D1 #define GL_TEXTURE18 0x84D2 #define GL_TEXTURE19 0x84D3 #define GL_TEXTURE20 0x84D4 #define GL_TEXTURE21 0x84D5 #define GL_TEXTURE22 0x84D6 #define GL_TEXTURE23 0x84D7 #define GL_TEXTURE24 0x84D8 #define GL_TEXTURE25 0x84D9 #define GL_TEXTURE26 0x84DA #define GL_TEXTURE27 0x84DB #define GL_TEXTURE28 0x84DC #define GL_TEXTURE29 0x84DD #define GL_TEXTURE30 0x84DE #define GL_TEXTURE31 0x84DF #define GL_ACTIVE_TEXTURE 0x84E0 #define GL_MULTISAMPLE 0x809D #define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E #define GL_SAMPLE_ALPHA_TO_ONE 0x809F #define GL_SAMPLE_COVERAGE 0x80A0 #define GL_SAMPLE_BUFFERS 0x80A8 #define GL_SAMPLES 0x80A9 #define GL_SAMPLE_COVERAGE_VALUE 0x80AA #define GL_SAMPLE_COVERAGE_INVERT 0x80AB #define GL_TEXTURE_CUBE_MAP 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A #define GL_PROXY_TEXTURE_CUBE_MAP 0x851B #define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C #define GL_COMPRESSED_RGB 0x84ED #define GL_COMPRESSED_RGBA 0x84EE #define GL_TEXTURE_COMPRESSION_HINT 0x84EF #define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 #define GL_TEXTURE_COMPRESSED 0x86A1 #define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 #define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 #define GL_CLAMP_TO_BORDER 0x812D #define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 #define GL_MAX_TEXTURE_UNITS 0x84E2 #define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 #define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 #define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 #define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 #define GL_MULTISAMPLE_BIT 0x20000000 #define GL_NORMAL_MAP 0x8511 #define GL_REFLECTION_MAP 0x8512 #define GL_COMPRESSED_ALPHA 0x84E9 #define GL_COMPRESSED_LUMINANCE 0x84EA #define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB #define GL_COMPRESSED_INTENSITY 0x84EC #define GL_COMBINE 0x8570 #define GL_COMBINE_RGB 0x8571 #define GL_COMBINE_ALPHA 0x8572 #define GL_SOURCE0_RGB 0x8580 #define GL_SOURCE1_RGB 0x8581 #define GL_SOURCE2_RGB 0x8582 #define GL_SOURCE0_ALPHA 0x8588 #define GL_SOURCE1_ALPHA 0x8589 #define GL_SOURCE2_ALPHA 0x858A #define GL_OPERAND0_RGB 0x8590 #define GL_OPERAND1_RGB 0x8591 #define GL_OPERAND2_RGB 0x8592 #define GL_OPERAND0_ALPHA 0x8598 #define GL_OPERAND1_ALPHA 0x8599 #define GL_OPERAND2_ALPHA 0x859A #define GL_RGB_SCALE 0x8573 #define GL_ADD_SIGNED 0x8574 #define GL_INTERPOLATE 0x8575 #define GL_SUBTRACT 0x84E7 #define GL_CONSTANT 0x8576 #define GL_PRIMARY_COLOR 0x8577 #define GL_PREVIOUS 0x8578 #define GL_DOT3_RGB 0x86AE #define GL_DOT3_RGBA 0x86AF typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLfloat value, GLboolean invert); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, void *img); typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture); typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC) (GLenum target, GLint s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m); typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m); typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m); typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glActiveTexture (GLenum texture); GLAPI void APIENTRY glSampleCoverage (GLfloat value, GLboolean invert); GLAPI void APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); GLAPI void APIENTRY glCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); GLAPI void APIENTRY glGetCompressedTexImage (GLenum target, GLint level, void *img); GLAPI void APIENTRY glClientActiveTexture (GLenum texture); GLAPI void APIENTRY glMultiTexCoord1d (GLenum target, GLdouble s); GLAPI void APIENTRY glMultiTexCoord1dv (GLenum target, const GLdouble *v); GLAPI void APIENTRY glMultiTexCoord1f (GLenum target, GLfloat s); GLAPI void APIENTRY glMultiTexCoord1fv (GLenum target, const GLfloat *v); GLAPI void APIENTRY glMultiTexCoord1i (GLenum target, GLint s); GLAPI void APIENTRY glMultiTexCoord1iv (GLenum target, const GLint *v); GLAPI void APIENTRY glMultiTexCoord1s (GLenum target, GLshort s); GLAPI void APIENTRY glMultiTexCoord1sv (GLenum target, const GLshort *v); GLAPI void APIENTRY glMultiTexCoord2d (GLenum target, GLdouble s, GLdouble t); GLAPI void APIENTRY glMultiTexCoord2dv (GLenum target, const GLdouble *v); GLAPI void APIENTRY glMultiTexCoord2f (GLenum target, GLfloat s, GLfloat t); GLAPI void APIENTRY glMultiTexCoord2fv (GLenum target, const GLfloat *v); GLAPI void APIENTRY glMultiTexCoord2i (GLenum target, GLint s, GLint t); GLAPI void APIENTRY glMultiTexCoord2iv (GLenum target, const GLint *v); GLAPI void APIENTRY glMultiTexCoord2s (GLenum target, GLshort s, GLshort t); GLAPI void APIENTRY glMultiTexCoord2sv (GLenum target, const GLshort *v); GLAPI void APIENTRY glMultiTexCoord3d (GLenum target, GLdouble s, GLdouble t, GLdouble r); GLAPI void APIENTRY glMultiTexCoord3dv (GLenum target, const GLdouble *v); GLAPI void APIENTRY glMultiTexCoord3f (GLenum target, GLfloat s, GLfloat t, GLfloat r); GLAPI void APIENTRY glMultiTexCoord3fv (GLenum target, const GLfloat *v); GLAPI void APIENTRY glMultiTexCoord3i (GLenum target, GLint s, GLint t, GLint r); GLAPI void APIENTRY glMultiTexCoord3iv (GLenum target, const GLint *v); GLAPI void APIENTRY glMultiTexCoord3s (GLenum target, GLshort s, GLshort t, GLshort r); GLAPI void APIENTRY glMultiTexCoord3sv (GLenum target, const GLshort *v); GLAPI void APIENTRY glMultiTexCoord4d (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); GLAPI void APIENTRY glMultiTexCoord4dv (GLenum target, const GLdouble *v); GLAPI void APIENTRY glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); GLAPI void APIENTRY glMultiTexCoord4fv (GLenum target, const GLfloat *v); GLAPI void APIENTRY glMultiTexCoord4i (GLenum target, GLint s, GLint t, GLint r, GLint q); GLAPI void APIENTRY glMultiTexCoord4iv (GLenum target, const GLint *v); GLAPI void APIENTRY glMultiTexCoord4s (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); GLAPI void APIENTRY glMultiTexCoord4sv (GLenum target, const GLshort *v); GLAPI void APIENTRY glLoadTransposeMatrixf (const GLfloat *m); GLAPI void APIENTRY glLoadTransposeMatrixd (const GLdouble *m); GLAPI void APIENTRY glMultTransposeMatrixf (const GLfloat *m); GLAPI void APIENTRY glMultTransposeMatrixd (const GLdouble *m); #endif #endif /* GL_VERSION_1_3 */ #ifndef GL_VERSION_1_4 #define GL_VERSION_1_4 1 #define GL_BLEND_DST_RGB 0x80C8 #define GL_BLEND_SRC_RGB 0x80C9 #define GL_BLEND_DST_ALPHA 0x80CA #define GL_BLEND_SRC_ALPHA 0x80CB #define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 #define GL_DEPTH_COMPONENT16 0x81A5 #define GL_DEPTH_COMPONENT24 0x81A6 #define GL_DEPTH_COMPONENT32 0x81A7 #define GL_MIRRORED_REPEAT 0x8370 #define GL_MAX_TEXTURE_LOD_BIAS 0x84FD #define GL_TEXTURE_LOD_BIAS 0x8501 #define GL_INCR_WRAP 0x8507 #define GL_DECR_WRAP 0x8508 #define GL_TEXTURE_DEPTH_SIZE 0x884A #define GL_TEXTURE_COMPARE_MODE 0x884C #define GL_TEXTURE_COMPARE_FUNC 0x884D #define GL_POINT_SIZE_MIN 0x8126 #define GL_POINT_SIZE_MAX 0x8127 #define GL_POINT_DISTANCE_ATTENUATION 0x8129 #define GL_GENERATE_MIPMAP 0x8191 #define GL_GENERATE_MIPMAP_HINT 0x8192 #define GL_FOG_COORDINATE_SOURCE 0x8450 #define GL_FOG_COORDINATE 0x8451 #define GL_FRAGMENT_DEPTH 0x8452 #define GL_CURRENT_FOG_COORDINATE 0x8453 #define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 #define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 #define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 #define GL_FOG_COORDINATE_ARRAY 0x8457 #define GL_COLOR_SUM 0x8458 #define GL_CURRENT_SECONDARY_COLOR 0x8459 #define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A #define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B #define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C #define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D #define GL_SECONDARY_COLOR_ARRAY 0x845E #define GL_TEXTURE_FILTER_CONTROL 0x8500 #define GL_DEPTH_TEXTURE_MODE 0x884B #define GL_COMPARE_R_TO_TEXTURE 0x884E #define GL_BLEND_COLOR 0x8005 #define GL_BLEND_EQUATION 0x8009 #define GL_CONSTANT_COLOR 0x8001 #define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 #define GL_CONSTANT_ALPHA 0x8003 #define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 #define GL_FUNC_ADD 0x8006 #define GL_FUNC_REVERSE_SUBTRACT 0x800B #define GL_FUNC_SUBTRACT 0x800A #define GL_MIN 0x8007 #define GL_MAX 0x8008 typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLFOGCOORDFPROC) (GLfloat coord); typedef void (APIENTRYP PFNGLFOGCOORDFVPROC) (const GLfloat *coord); typedef void (APIENTRYP PFNGLFOGCOORDDPROC) (GLdouble coord); typedef void (APIENTRYP PFNGLFOGCOORDDVPROC) (const GLdouble *coord); typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const void *pointer); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC) (const GLbyte *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC) (const GLint *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC) (const GLuint *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC) (const GLushort *v); typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC) (GLint x, GLint y); typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC) (GLshort x, GLshort y); typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); GLAPI void APIENTRY glMultiDrawArrays (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); GLAPI void APIENTRY glMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); GLAPI void APIENTRY glPointParameterf (GLenum pname, GLfloat param); GLAPI void APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params); GLAPI void APIENTRY glPointParameteri (GLenum pname, GLint param); GLAPI void APIENTRY glPointParameteriv (GLenum pname, const GLint *params); GLAPI void APIENTRY glFogCoordf (GLfloat coord); GLAPI void APIENTRY glFogCoordfv (const GLfloat *coord); GLAPI void APIENTRY glFogCoordd (GLdouble coord); GLAPI void APIENTRY glFogCoorddv (const GLdouble *coord); GLAPI void APIENTRY glFogCoordPointer (GLenum type, GLsizei stride, const void *pointer); GLAPI void APIENTRY glSecondaryColor3b (GLbyte red, GLbyte green, GLbyte blue); GLAPI void APIENTRY glSecondaryColor3bv (const GLbyte *v); GLAPI void APIENTRY glSecondaryColor3d (GLdouble red, GLdouble green, GLdouble blue); GLAPI void APIENTRY glSecondaryColor3dv (const GLdouble *v); GLAPI void APIENTRY glSecondaryColor3f (GLfloat red, GLfloat green, GLfloat blue); GLAPI void APIENTRY glSecondaryColor3fv (const GLfloat *v); GLAPI void APIENTRY glSecondaryColor3i (GLint red, GLint green, GLint blue); GLAPI void APIENTRY glSecondaryColor3iv (const GLint *v); GLAPI void APIENTRY glSecondaryColor3s (GLshort red, GLshort green, GLshort blue); GLAPI void APIENTRY glSecondaryColor3sv (const GLshort *v); GLAPI void APIENTRY glSecondaryColor3ub (GLubyte red, GLubyte green, GLubyte blue); GLAPI void APIENTRY glSecondaryColor3ubv (const GLubyte *v); GLAPI void APIENTRY glSecondaryColor3ui (GLuint red, GLuint green, GLuint blue); GLAPI void APIENTRY glSecondaryColor3uiv (const GLuint *v); GLAPI void APIENTRY glSecondaryColor3us (GLushort red, GLushort green, GLushort blue); GLAPI void APIENTRY glSecondaryColor3usv (const GLushort *v); GLAPI void APIENTRY glSecondaryColorPointer (GLint size, GLenum type, GLsizei stride, const void *pointer); GLAPI void APIENTRY glWindowPos2d (GLdouble x, GLdouble y); GLAPI void APIENTRY glWindowPos2dv (const GLdouble *v); GLAPI void APIENTRY glWindowPos2f (GLfloat x, GLfloat y); GLAPI void APIENTRY glWindowPos2fv (const GLfloat *v); GLAPI void APIENTRY glWindowPos2i (GLint x, GLint y); GLAPI void APIENTRY glWindowPos2iv (const GLint *v); GLAPI void APIENTRY glWindowPos2s (GLshort x, GLshort y); GLAPI void APIENTRY glWindowPos2sv (const GLshort *v); GLAPI void APIENTRY glWindowPos3d (GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glWindowPos3dv (const GLdouble *v); GLAPI void APIENTRY glWindowPos3f (GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glWindowPos3fv (const GLfloat *v); GLAPI void APIENTRY glWindowPos3i (GLint x, GLint y, GLint z); GLAPI void APIENTRY glWindowPos3iv (const GLint *v); GLAPI void APIENTRY glWindowPos3s (GLshort x, GLshort y, GLshort z); GLAPI void APIENTRY glWindowPos3sv (const GLshort *v); GLAPI void APIENTRY glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); GLAPI void APIENTRY glBlendEquation (GLenum mode); #endif #endif /* GL_VERSION_1_4 */ #ifndef GL_VERSION_1_5 #define GL_VERSION_1_5 1 typedef khronos_ssize_t GLsizeiptr; typedef khronos_intptr_t GLintptr; #define GL_BUFFER_SIZE 0x8764 #define GL_BUFFER_USAGE 0x8765 #define GL_QUERY_COUNTER_BITS 0x8864 #define GL_CURRENT_QUERY 0x8865 #define GL_QUERY_RESULT 0x8866 #define GL_QUERY_RESULT_AVAILABLE 0x8867 #define GL_ARRAY_BUFFER 0x8892 #define GL_ELEMENT_ARRAY_BUFFER 0x8893 #define GL_ARRAY_BUFFER_BINDING 0x8894 #define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 #define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F #define GL_READ_ONLY 0x88B8 #define GL_WRITE_ONLY 0x88B9 #define GL_READ_WRITE 0x88BA #define GL_BUFFER_ACCESS 0x88BB #define GL_BUFFER_MAPPED 0x88BC #define GL_BUFFER_MAP_POINTER 0x88BD #define GL_STREAM_DRAW 0x88E0 #define GL_STREAM_READ 0x88E1 #define GL_STREAM_COPY 0x88E2 #define GL_STATIC_DRAW 0x88E4 #define GL_STATIC_READ 0x88E5 #define GL_STATIC_COPY 0x88E6 #define GL_DYNAMIC_DRAW 0x88E8 #define GL_DYNAMIC_READ 0x88E9 #define GL_DYNAMIC_COPY 0x88EA #define GL_SAMPLES_PASSED 0x8914 #define GL_SRC1_ALPHA 0x8589 #define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 #define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 #define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 #define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 #define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A #define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B #define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C #define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D #define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E #define GL_FOG_COORD_SRC 0x8450 #define GL_FOG_COORD 0x8451 #define GL_CURRENT_FOG_COORD 0x8453 #define GL_FOG_COORD_ARRAY_TYPE 0x8454 #define GL_FOG_COORD_ARRAY_STRIDE 0x8455 #define GL_FOG_COORD_ARRAY_POINTER 0x8456 #define GL_FOG_COORD_ARRAY 0x8457 #define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D #define GL_SRC0_RGB 0x8580 #define GL_SRC1_RGB 0x8581 #define GL_SRC2_RGB 0x8582 #define GL_SRC0_ALPHA 0x8588 #define GL_SRC2_ALPHA 0x858A typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids); typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids); typedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id); typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id); typedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target); typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage); typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, void *data); typedef void *(APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access); typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target); typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, void **params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenQueries (GLsizei n, GLuint *ids); GLAPI void APIENTRY glDeleteQueries (GLsizei n, const GLuint *ids); GLAPI GLboolean APIENTRY glIsQuery (GLuint id); GLAPI void APIENTRY glBeginQuery (GLenum target, GLuint id); GLAPI void APIENTRY glEndQuery (GLenum target); GLAPI void APIENTRY glGetQueryiv (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetQueryObjectiv (GLuint id, GLenum pname, GLint *params); GLAPI void APIENTRY glGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params); GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer); GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); GLAPI GLboolean APIENTRY glIsBuffer (GLuint buffer); GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage); GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); GLAPI void APIENTRY glGetBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, void *data); GLAPI void *APIENTRY glMapBuffer (GLenum target, GLenum access); GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum target); GLAPI void APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, void **params); #endif #endif /* GL_VERSION_1_5 */ #ifndef GL_VERSION_2_0 #define GL_VERSION_2_0 1 typedef char GLchar; #define GL_BLEND_EQUATION_RGB 0x8009 #define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 #define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 #define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 #define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 #define GL_CURRENT_VERTEX_ATTRIB 0x8626 #define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 #define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 #define GL_STENCIL_BACK_FUNC 0x8800 #define GL_STENCIL_BACK_FAIL 0x8801 #define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 #define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 #define GL_MAX_DRAW_BUFFERS 0x8824 #define GL_DRAW_BUFFER0 0x8825 #define GL_DRAW_BUFFER1 0x8826 #define GL_DRAW_BUFFER2 0x8827 #define GL_DRAW_BUFFER3 0x8828 #define GL_DRAW_BUFFER4 0x8829 #define GL_DRAW_BUFFER5 0x882A #define GL_DRAW_BUFFER6 0x882B #define GL_DRAW_BUFFER7 0x882C #define GL_DRAW_BUFFER8 0x882D #define GL_DRAW_BUFFER9 0x882E #define GL_DRAW_BUFFER10 0x882F #define GL_DRAW_BUFFER11 0x8830 #define GL_DRAW_BUFFER12 0x8831 #define GL_DRAW_BUFFER13 0x8832 #define GL_DRAW_BUFFER14 0x8833 #define GL_DRAW_BUFFER15 0x8834 #define GL_BLEND_EQUATION_ALPHA 0x883D #define GL_MAX_VERTEX_ATTRIBS 0x8869 #define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A #define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 #define GL_FRAGMENT_SHADER 0x8B30 #define GL_VERTEX_SHADER 0x8B31 #define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 #define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A #define GL_MAX_VARYING_FLOATS 0x8B4B #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D #define GL_SHADER_TYPE 0x8B4F #define GL_FLOAT_VEC2 0x8B50 #define GL_FLOAT_VEC3 0x8B51 #define GL_FLOAT_VEC4 0x8B52 #define GL_INT_VEC2 0x8B53 #define GL_INT_VEC3 0x8B54 #define GL_INT_VEC4 0x8B55 #define GL_BOOL 0x8B56 #define GL_BOOL_VEC2 0x8B57 #define GL_BOOL_VEC3 0x8B58 #define GL_BOOL_VEC4 0x8B59 #define GL_FLOAT_MAT2 0x8B5A #define GL_FLOAT_MAT3 0x8B5B #define GL_FLOAT_MAT4 0x8B5C #define GL_SAMPLER_1D 0x8B5D #define GL_SAMPLER_2D 0x8B5E #define GL_SAMPLER_3D 0x8B5F #define GL_SAMPLER_CUBE 0x8B60 #define GL_SAMPLER_1D_SHADOW 0x8B61 #define GL_SAMPLER_2D_SHADOW 0x8B62 #define GL_DELETE_STATUS 0x8B80 #define GL_COMPILE_STATUS 0x8B81 #define GL_LINK_STATUS 0x8B82 #define GL_VALIDATE_STATUS 0x8B83 #define GL_INFO_LOG_LENGTH 0x8B84 #define GL_ATTACHED_SHADERS 0x8B85 #define GL_ACTIVE_UNIFORMS 0x8B86 #define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 #define GL_SHADER_SOURCE_LENGTH 0x8B88 #define GL_ACTIVE_ATTRIBUTES 0x8B89 #define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A #define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B #define GL_SHADING_LANGUAGE_VERSION 0x8B8C #define GL_CURRENT_PROGRAM 0x8B8D #define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 #define GL_LOWER_LEFT 0x8CA1 #define GL_UPPER_LEFT 0x8CA2 #define GL_STENCIL_BACK_REF 0x8CA3 #define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 #define GL_STENCIL_BACK_WRITEMASK 0x8CA5 #define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 #define GL_POINT_SPRITE 0x8861 #define GL_COORD_REPLACE 0x8862 #define GL_MAX_TEXTURE_COORDS 0x8871 typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha); typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs); typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask); typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask); typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name); typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void); typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program); typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader); typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index); typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params); typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer); typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program); typedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader); typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program); typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); typedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0); typedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1); typedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2); typedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha); GLAPI void APIENTRY glDrawBuffers (GLsizei n, const GLenum *bufs); GLAPI void APIENTRY glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); GLAPI void APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask); GLAPI void APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask); GLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader); GLAPI void APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name); GLAPI void APIENTRY glCompileShader (GLuint shader); GLAPI GLuint APIENTRY glCreateProgram (void); GLAPI GLuint APIENTRY glCreateShader (GLenum type); GLAPI void APIENTRY glDeleteProgram (GLuint program); GLAPI void APIENTRY glDeleteShader (GLuint shader); GLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader); GLAPI void APIENTRY glDisableVertexAttribArray (GLuint index); GLAPI void APIENTRY glEnableVertexAttribArray (GLuint index); GLAPI void APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); GLAPI void APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); GLAPI void APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); GLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name); GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params); GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); GLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params); GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); GLAPI void APIENTRY glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name); GLAPI void APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat *params); GLAPI void APIENTRY glGetUniformiv (GLuint program, GLint location, GLint *params); GLAPI void APIENTRY glGetVertexAttribdv (GLuint index, GLenum pname, GLdouble *params); GLAPI void APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params); GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer); GLAPI GLboolean APIENTRY glIsProgram (GLuint program); GLAPI GLboolean APIENTRY glIsShader (GLuint shader); GLAPI void APIENTRY glLinkProgram (GLuint program); GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); GLAPI void APIENTRY glUseProgram (GLuint program); GLAPI void APIENTRY glUniform1f (GLint location, GLfloat v0); GLAPI void APIENTRY glUniform2f (GLint location, GLfloat v0, GLfloat v1); GLAPI void APIENTRY glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); GLAPI void APIENTRY glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); GLAPI void APIENTRY glUniform1i (GLint location, GLint v0); GLAPI void APIENTRY glUniform2i (GLint location, GLint v0, GLint v1); GLAPI void APIENTRY glUniform3i (GLint location, GLint v0, GLint v1, GLint v2); GLAPI void APIENTRY glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); GLAPI void APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glValidateProgram (GLuint program); GLAPI void APIENTRY glVertexAttrib1d (GLuint index, GLdouble x); GLAPI void APIENTRY glVertexAttrib1dv (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib1f (GLuint index, GLfloat x); GLAPI void APIENTRY glVertexAttrib1fv (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib1s (GLuint index, GLshort x); GLAPI void APIENTRY glVertexAttrib1sv (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib2d (GLuint index, GLdouble x, GLdouble y); GLAPI void APIENTRY glVertexAttrib2dv (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y); GLAPI void APIENTRY glVertexAttrib2fv (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib2s (GLuint index, GLshort x, GLshort y); GLAPI void APIENTRY glVertexAttrib2sv (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glVertexAttrib3dv (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glVertexAttrib3fv (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib3s (GLuint index, GLshort x, GLshort y, GLshort z); GLAPI void APIENTRY glVertexAttrib3sv (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib4Nbv (GLuint index, const GLbyte *v); GLAPI void APIENTRY glVertexAttrib4Niv (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttrib4Nsv (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib4Nub (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); GLAPI void APIENTRY glVertexAttrib4Nubv (GLuint index, const GLubyte *v); GLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttrib4Nusv (GLuint index, const GLushort *v); GLAPI void APIENTRY glVertexAttrib4bv (GLuint index, const GLbyte *v); GLAPI void APIENTRY glVertexAttrib4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glVertexAttrib4dv (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glVertexAttrib4fv (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib4iv (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttrib4s (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); GLAPI void APIENTRY glVertexAttrib4sv (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib4ubv (GLuint index, const GLubyte *v); GLAPI void APIENTRY glVertexAttrib4uiv (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttrib4usv (GLuint index, const GLushort *v); GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); #endif #endif /* GL_VERSION_2_0 */ #ifndef GL_VERSION_2_1 #define GL_VERSION_2_1 1 #define GL_PIXEL_PACK_BUFFER 0x88EB #define GL_PIXEL_UNPACK_BUFFER 0x88EC #define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED #define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF #define GL_FLOAT_MAT2x3 0x8B65 #define GL_FLOAT_MAT2x4 0x8B66 #define GL_FLOAT_MAT3x2 0x8B67 #define GL_FLOAT_MAT3x4 0x8B68 #define GL_FLOAT_MAT4x2 0x8B69 #define GL_FLOAT_MAT4x3 0x8B6A #define GL_SRGB 0x8C40 #define GL_SRGB8 0x8C41 #define GL_SRGB_ALPHA 0x8C42 #define GL_SRGB8_ALPHA8 0x8C43 #define GL_COMPRESSED_SRGB 0x8C48 #define GL_COMPRESSED_SRGB_ALPHA 0x8C49 #define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F #define GL_SLUMINANCE_ALPHA 0x8C44 #define GL_SLUMINANCE8_ALPHA8 0x8C45 #define GL_SLUMINANCE 0x8C46 #define GL_SLUMINANCE8 0x8C47 #define GL_COMPRESSED_SLUMINANCE 0x8C4A #define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glUniformMatrix2x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glUniformMatrix3x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glUniformMatrix2x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glUniformMatrix4x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glUniformMatrix3x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glUniformMatrix4x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); #endif #endif /* GL_VERSION_2_1 */ #ifndef GL_VERSION_3_0 #define GL_VERSION_3_0 1 typedef khronos_uint16_t GLhalf; #define GL_COMPARE_REF_TO_TEXTURE 0x884E #define GL_CLIP_DISTANCE0 0x3000 #define GL_CLIP_DISTANCE1 0x3001 #define GL_CLIP_DISTANCE2 0x3002 #define GL_CLIP_DISTANCE3 0x3003 #define GL_CLIP_DISTANCE4 0x3004 #define GL_CLIP_DISTANCE5 0x3005 #define GL_CLIP_DISTANCE6 0x3006 #define GL_CLIP_DISTANCE7 0x3007 #define GL_MAX_CLIP_DISTANCES 0x0D32 #define GL_MAJOR_VERSION 0x821B #define GL_MINOR_VERSION 0x821C #define GL_NUM_EXTENSIONS 0x821D #define GL_CONTEXT_FLAGS 0x821E #define GL_COMPRESSED_RED 0x8225 #define GL_COMPRESSED_RG 0x8226 #define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 #define GL_RGBA32F 0x8814 #define GL_RGB32F 0x8815 #define GL_RGBA16F 0x881A #define GL_RGB16F 0x881B #define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD #define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF #define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 #define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 #define GL_CLAMP_READ_COLOR 0x891C #define GL_FIXED_ONLY 0x891D #define GL_MAX_VARYING_COMPONENTS 0x8B4B #define GL_TEXTURE_1D_ARRAY 0x8C18 #define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 #define GL_TEXTURE_2D_ARRAY 0x8C1A #define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B #define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C #define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D #define GL_R11F_G11F_B10F 0x8C3A #define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B #define GL_RGB9_E5 0x8C3D #define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E #define GL_TEXTURE_SHARED_SIZE 0x8C3F #define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 #define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 #define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 #define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 #define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 #define GL_PRIMITIVES_GENERATED 0x8C87 #define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 #define GL_RASTERIZER_DISCARD 0x8C89 #define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B #define GL_INTERLEAVED_ATTRIBS 0x8C8C #define GL_SEPARATE_ATTRIBS 0x8C8D #define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E #define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F #define GL_RGBA32UI 0x8D70 #define GL_RGB32UI 0x8D71 #define GL_RGBA16UI 0x8D76 #define GL_RGB16UI 0x8D77 #define GL_RGBA8UI 0x8D7C #define GL_RGB8UI 0x8D7D #define GL_RGBA32I 0x8D82 #define GL_RGB32I 0x8D83 #define GL_RGBA16I 0x8D88 #define GL_RGB16I 0x8D89 #define GL_RGBA8I 0x8D8E #define GL_RGB8I 0x8D8F #define GL_RED_INTEGER 0x8D94 #define GL_GREEN_INTEGER 0x8D95 #define GL_BLUE_INTEGER 0x8D96 #define GL_RGB_INTEGER 0x8D98 #define GL_RGBA_INTEGER 0x8D99 #define GL_BGR_INTEGER 0x8D9A #define GL_BGRA_INTEGER 0x8D9B #define GL_SAMPLER_1D_ARRAY 0x8DC0 #define GL_SAMPLER_2D_ARRAY 0x8DC1 #define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 #define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 #define GL_SAMPLER_CUBE_SHADOW 0x8DC5 #define GL_UNSIGNED_INT_VEC2 0x8DC6 #define GL_UNSIGNED_INT_VEC3 0x8DC7 #define GL_UNSIGNED_INT_VEC4 0x8DC8 #define GL_INT_SAMPLER_1D 0x8DC9 #define GL_INT_SAMPLER_2D 0x8DCA #define GL_INT_SAMPLER_3D 0x8DCB #define GL_INT_SAMPLER_CUBE 0x8DCC #define GL_INT_SAMPLER_1D_ARRAY 0x8DCE #define GL_INT_SAMPLER_2D_ARRAY 0x8DCF #define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 #define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 #define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 #define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 #define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 #define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 #define GL_QUERY_WAIT 0x8E13 #define GL_QUERY_NO_WAIT 0x8E14 #define GL_QUERY_BY_REGION_WAIT 0x8E15 #define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 #define GL_BUFFER_ACCESS_FLAGS 0x911F #define GL_BUFFER_MAP_LENGTH 0x9120 #define GL_BUFFER_MAP_OFFSET 0x9121 #define GL_DEPTH_COMPONENT32F 0x8CAC #define GL_DEPTH32F_STENCIL8 0x8CAD #define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD #define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 #define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 #define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 #define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 #define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 #define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 #define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 #define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 #define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 #define GL_FRAMEBUFFER_DEFAULT 0x8218 #define GL_FRAMEBUFFER_UNDEFINED 0x8219 #define GL_DEPTH_STENCIL_ATTACHMENT 0x821A #define GL_MAX_RENDERBUFFER_SIZE 0x84E8 #define GL_DEPTH_STENCIL 0x84F9 #define GL_UNSIGNED_INT_24_8 0x84FA #define GL_DEPTH24_STENCIL8 0x88F0 #define GL_TEXTURE_STENCIL_SIZE 0x88F1 #define GL_TEXTURE_RED_TYPE 0x8C10 #define GL_TEXTURE_GREEN_TYPE 0x8C11 #define GL_TEXTURE_BLUE_TYPE 0x8C12 #define GL_TEXTURE_ALPHA_TYPE 0x8C13 #define GL_TEXTURE_DEPTH_TYPE 0x8C16 #define GL_UNSIGNED_NORMALIZED 0x8C17 #define GL_FRAMEBUFFER_BINDING 0x8CA6 #define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 #define GL_RENDERBUFFER_BINDING 0x8CA7 #define GL_READ_FRAMEBUFFER 0x8CA8 #define GL_DRAW_FRAMEBUFFER 0x8CA9 #define GL_READ_FRAMEBUFFER_BINDING 0x8CAA #define GL_RENDERBUFFER_SAMPLES 0x8CAB #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 #define GL_FRAMEBUFFER_COMPLETE 0x8CD5 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB #define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC #define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD #define GL_MAX_COLOR_ATTACHMENTS 0x8CDF #define GL_COLOR_ATTACHMENT0 0x8CE0 #define GL_COLOR_ATTACHMENT1 0x8CE1 #define GL_COLOR_ATTACHMENT2 0x8CE2 #define GL_COLOR_ATTACHMENT3 0x8CE3 #define GL_COLOR_ATTACHMENT4 0x8CE4 #define GL_COLOR_ATTACHMENT5 0x8CE5 #define GL_COLOR_ATTACHMENT6 0x8CE6 #define GL_COLOR_ATTACHMENT7 0x8CE7 #define GL_COLOR_ATTACHMENT8 0x8CE8 #define GL_COLOR_ATTACHMENT9 0x8CE9 #define GL_COLOR_ATTACHMENT10 0x8CEA #define GL_COLOR_ATTACHMENT11 0x8CEB #define GL_COLOR_ATTACHMENT12 0x8CEC #define GL_COLOR_ATTACHMENT13 0x8CED #define GL_COLOR_ATTACHMENT14 0x8CEE #define GL_COLOR_ATTACHMENT15 0x8CEF #define GL_COLOR_ATTACHMENT16 0x8CF0 #define GL_COLOR_ATTACHMENT17 0x8CF1 #define GL_COLOR_ATTACHMENT18 0x8CF2 #define GL_COLOR_ATTACHMENT19 0x8CF3 #define GL_COLOR_ATTACHMENT20 0x8CF4 #define GL_COLOR_ATTACHMENT21 0x8CF5 #define GL_COLOR_ATTACHMENT22 0x8CF6 #define GL_COLOR_ATTACHMENT23 0x8CF7 #define GL_COLOR_ATTACHMENT24 0x8CF8 #define GL_COLOR_ATTACHMENT25 0x8CF9 #define GL_COLOR_ATTACHMENT26 0x8CFA #define GL_COLOR_ATTACHMENT27 0x8CFB #define GL_COLOR_ATTACHMENT28 0x8CFC #define GL_COLOR_ATTACHMENT29 0x8CFD #define GL_COLOR_ATTACHMENT30 0x8CFE #define GL_COLOR_ATTACHMENT31 0x8CFF #define GL_DEPTH_ATTACHMENT 0x8D00 #define GL_STENCIL_ATTACHMENT 0x8D20 #define GL_FRAMEBUFFER 0x8D40 #define GL_RENDERBUFFER 0x8D41 #define GL_RENDERBUFFER_WIDTH 0x8D42 #define GL_RENDERBUFFER_HEIGHT 0x8D43 #define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 #define GL_STENCIL_INDEX1 0x8D46 #define GL_STENCIL_INDEX4 0x8D47 #define GL_STENCIL_INDEX8 0x8D48 #define GL_STENCIL_INDEX16 0x8D49 #define GL_RENDERBUFFER_RED_SIZE 0x8D50 #define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 #define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 #define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 #define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 #define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 #define GL_MAX_SAMPLES 0x8D57 #define GL_INDEX 0x8222 #define GL_TEXTURE_LUMINANCE_TYPE 0x8C14 #define GL_TEXTURE_INTENSITY_TYPE 0x8C15 #define GL_FRAMEBUFFER_SRGB 0x8DB9 #define GL_HALF_FLOAT 0x140B #define GL_MAP_READ_BIT 0x0001 #define GL_MAP_WRITE_BIT 0x0002 #define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 #define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 #define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 #define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 #define GL_COMPRESSED_RED_RGTC1 0x8DBB #define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC #define GL_COMPRESSED_RG_RGTC2 0x8DBD #define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE #define GL_RG 0x8227 #define GL_RG_INTEGER 0x8228 #define GL_R8 0x8229 #define GL_R16 0x822A #define GL_RG8 0x822B #define GL_RG16 0x822C #define GL_R16F 0x822D #define GL_R32F 0x822E #define GL_RG16F 0x822F #define GL_RG32F 0x8230 #define GL_R8I 0x8231 #define GL_R8UI 0x8232 #define GL_R16I 0x8233 #define GL_R16UI 0x8234 #define GL_R32I 0x8235 #define GL_R32UI 0x8236 #define GL_RG8I 0x8237 #define GL_RG8UI 0x8238 #define GL_RG16I 0x8239 #define GL_RG16UI 0x823A #define GL_RG32I 0x823B #define GL_RG32UI 0x823C #define GL_VERTEX_ARRAY_BINDING 0x85B5 #define GL_CLAMP_VERTEX_COLOR 0x891A #define GL_CLAMP_FRAGMENT_COLOR 0x891B #define GL_ALPHA_INTEGER 0x8D97 typedef void (APIENTRYP PFNGLCOLORMASKIPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data); typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data); typedef void (APIENTRYP PFNGLENABLEIPROC) (GLenum target, GLuint index); typedef void (APIENTRYP PFNGLDISABLEIPROC) (GLenum target, GLuint index); typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC) (GLenum target, GLuint index); typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode); typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC) (void); typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer); typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); typedef void (APIENTRYP PFNGLCLAMPCOLORPROC) (GLenum target, GLenum clamp); typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode); typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC) (void); typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC) (GLuint index, GLint x); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC) (GLuint index, GLint x, GLint y); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC) (GLuint index, GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC) (GLuint index, GLuint x); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC) (GLuint index, GLuint x, GLuint y); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params); typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC) (GLuint program, GLuint color, const GLchar *name); typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name); typedef void (APIENTRYP PFNGLUNIFORM1UIPROC) (GLint location, GLuint v0); typedef void (APIENTRYP PFNGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1); typedef void (APIENTRYP PFNGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); typedef void (APIENTRYP PFNGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint *params); typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value); typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value); typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value); typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index); typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC) (GLuint renderbuffer); typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer); typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers); typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC) (GLuint framebuffer); typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers); typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC) (GLenum target); typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); typedef void *(APIENTRYP PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length); typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array); typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays); typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC) (GLuint array); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorMaski (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); GLAPI void APIENTRY glGetBooleani_v (GLenum target, GLuint index, GLboolean *data); GLAPI void APIENTRY glGetIntegeri_v (GLenum target, GLuint index, GLint *data); GLAPI void APIENTRY glEnablei (GLenum target, GLuint index); GLAPI void APIENTRY glDisablei (GLenum target, GLuint index); GLAPI GLboolean APIENTRY glIsEnabledi (GLenum target, GLuint index); GLAPI void APIENTRY glBeginTransformFeedback (GLenum primitiveMode); GLAPI void APIENTRY glEndTransformFeedback (void); GLAPI void APIENTRY glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); GLAPI void APIENTRY glBindBufferBase (GLenum target, GLuint index, GLuint buffer); GLAPI void APIENTRY glTransformFeedbackVaryings (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); GLAPI void APIENTRY glGetTransformFeedbackVarying (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); GLAPI void APIENTRY glClampColor (GLenum target, GLenum clamp); GLAPI void APIENTRY glBeginConditionalRender (GLuint id, GLenum mode); GLAPI void APIENTRY glEndConditionalRender (void); GLAPI void APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); GLAPI void APIENTRY glGetVertexAttribIiv (GLuint index, GLenum pname, GLint *params); GLAPI void APIENTRY glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint *params); GLAPI void APIENTRY glVertexAttribI1i (GLuint index, GLint x); GLAPI void APIENTRY glVertexAttribI2i (GLuint index, GLint x, GLint y); GLAPI void APIENTRY glVertexAttribI3i (GLuint index, GLint x, GLint y, GLint z); GLAPI void APIENTRY glVertexAttribI4i (GLuint index, GLint x, GLint y, GLint z, GLint w); GLAPI void APIENTRY glVertexAttribI1ui (GLuint index, GLuint x); GLAPI void APIENTRY glVertexAttribI2ui (GLuint index, GLuint x, GLuint y); GLAPI void APIENTRY glVertexAttribI3ui (GLuint index, GLuint x, GLuint y, GLuint z); GLAPI void APIENTRY glVertexAttribI4ui (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); GLAPI void APIENTRY glVertexAttribI1iv (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttribI2iv (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttribI3iv (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttribI4iv (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttribI1uiv (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttribI2uiv (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttribI3uiv (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttribI4uiv (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttribI4bv (GLuint index, const GLbyte *v); GLAPI void APIENTRY glVertexAttribI4sv (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttribI4ubv (GLuint index, const GLubyte *v); GLAPI void APIENTRY glVertexAttribI4usv (GLuint index, const GLushort *v); GLAPI void APIENTRY glGetUniformuiv (GLuint program, GLint location, GLuint *params); GLAPI void APIENTRY glBindFragDataLocation (GLuint program, GLuint color, const GLchar *name); GLAPI GLint APIENTRY glGetFragDataLocation (GLuint program, const GLchar *name); GLAPI void APIENTRY glUniform1ui (GLint location, GLuint v0); GLAPI void APIENTRY glUniform2ui (GLint location, GLuint v0, GLuint v1); GLAPI void APIENTRY glUniform3ui (GLint location, GLuint v0, GLuint v1, GLuint v2); GLAPI void APIENTRY glUniform4ui (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); GLAPI void APIENTRY glUniform1uiv (GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glUniform2uiv (GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glUniform3uiv (GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glTexParameterIiv (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glTexParameterIuiv (GLenum target, GLenum pname, const GLuint *params); GLAPI void APIENTRY glGetTexParameterIiv (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetTexParameterIuiv (GLenum target, GLenum pname, GLuint *params); GLAPI void APIENTRY glClearBufferiv (GLenum buffer, GLint drawbuffer, const GLint *value); GLAPI void APIENTRY glClearBufferuiv (GLenum buffer, GLint drawbuffer, const GLuint *value); GLAPI void APIENTRY glClearBufferfv (GLenum buffer, GLint drawbuffer, const GLfloat *value); GLAPI void APIENTRY glClearBufferfi (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); GLAPI const GLubyte *APIENTRY glGetStringi (GLenum name, GLuint index); GLAPI GLboolean APIENTRY glIsRenderbuffer (GLuint renderbuffer); GLAPI void APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer); GLAPI void APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers); GLAPI void APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers); GLAPI void APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); GLAPI void APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint *params); GLAPI GLboolean APIENTRY glIsFramebuffer (GLuint framebuffer); GLAPI void APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer); GLAPI void APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers); GLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers); GLAPI GLenum APIENTRY glCheckFramebufferStatus (GLenum target); GLAPI void APIENTRY glFramebufferTexture1D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); GLAPI void APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); GLAPI void APIENTRY glFramebufferTexture3D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); GLAPI void APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); GLAPI void APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint *params); GLAPI void APIENTRY glGenerateMipmap (GLenum target); GLAPI void APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); GLAPI void APIENTRY glRenderbufferStorageMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); GLAPI void APIENTRY glFramebufferTextureLayer (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); GLAPI void *APIENTRY glMapBufferRange (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); GLAPI void APIENTRY glFlushMappedBufferRange (GLenum target, GLintptr offset, GLsizeiptr length); GLAPI void APIENTRY glBindVertexArray (GLuint array); GLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays); GLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays); GLAPI GLboolean APIENTRY glIsVertexArray (GLuint array); #endif #endif /* GL_VERSION_3_0 */ #ifndef GL_VERSION_3_1 #define GL_VERSION_3_1 1 #define GL_SAMPLER_2D_RECT 0x8B63 #define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 #define GL_SAMPLER_BUFFER 0x8DC2 #define GL_INT_SAMPLER_2D_RECT 0x8DCD #define GL_INT_SAMPLER_BUFFER 0x8DD0 #define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 #define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 #define GL_TEXTURE_BUFFER 0x8C2A #define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B #define GL_TEXTURE_BINDING_BUFFER 0x8C2C #define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D #define GL_TEXTURE_RECTANGLE 0x84F5 #define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 #define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 #define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 #define GL_R8_SNORM 0x8F94 #define GL_RG8_SNORM 0x8F95 #define GL_RGB8_SNORM 0x8F96 #define GL_RGBA8_SNORM 0x8F97 #define GL_R16_SNORM 0x8F98 #define GL_RG16_SNORM 0x8F99 #define GL_RGB16_SNORM 0x8F9A #define GL_RGBA16_SNORM 0x8F9B #define GL_SIGNED_NORMALIZED 0x8F9C #define GL_PRIMITIVE_RESTART 0x8F9D #define GL_PRIMITIVE_RESTART_INDEX 0x8F9E #define GL_COPY_READ_BUFFER 0x8F36 #define GL_COPY_WRITE_BUFFER 0x8F37 #define GL_UNIFORM_BUFFER 0x8A11 #define GL_UNIFORM_BUFFER_BINDING 0x8A28 #define GL_UNIFORM_BUFFER_START 0x8A29 #define GL_UNIFORM_BUFFER_SIZE 0x8A2A #define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B #define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C #define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D #define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E #define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F #define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 #define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 #define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 #define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 #define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 #define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 #define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 #define GL_UNIFORM_TYPE 0x8A37 #define GL_UNIFORM_SIZE 0x8A38 #define GL_UNIFORM_NAME_LENGTH 0x8A39 #define GL_UNIFORM_BLOCK_INDEX 0x8A3A #define GL_UNIFORM_OFFSET 0x8A3B #define GL_UNIFORM_ARRAY_STRIDE 0x8A3C #define GL_UNIFORM_MATRIX_STRIDE 0x8A3D #define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E #define GL_UNIFORM_BLOCK_BINDING 0x8A3F #define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 #define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 #define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 #define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 #define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 #define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 #define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 #define GL_INVALID_INDEX 0xFFFFFFFFu typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); typedef void (APIENTRYP PFNGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer); typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC) (GLuint index); typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName); typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); GLAPI void APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); GLAPI void APIENTRY glTexBuffer (GLenum target, GLenum internalformat, GLuint buffer); GLAPI void APIENTRY glPrimitiveRestartIndex (GLuint index); GLAPI void APIENTRY glCopyBufferSubData (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); GLAPI void APIENTRY glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); GLAPI void APIENTRY glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); GLAPI void APIENTRY glGetActiveUniformName (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); GLAPI GLuint APIENTRY glGetUniformBlockIndex (GLuint program, const GLchar *uniformBlockName); GLAPI void APIENTRY glGetActiveUniformBlockiv (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); GLAPI void APIENTRY glGetActiveUniformBlockName (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); GLAPI void APIENTRY glUniformBlockBinding (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); #endif #endif /* GL_VERSION_3_1 */ #ifndef GL_VERSION_3_2 #define GL_VERSION_3_2 1 typedef struct __GLsync *GLsync; typedef khronos_uint64_t GLuint64; typedef khronos_int64_t GLint64; #define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 #define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 #define GL_LINES_ADJACENCY 0x000A #define GL_LINE_STRIP_ADJACENCY 0x000B #define GL_TRIANGLES_ADJACENCY 0x000C #define GL_TRIANGLE_STRIP_ADJACENCY 0x000D #define GL_PROGRAM_POINT_SIZE 0x8642 #define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 #define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 #define GL_GEOMETRY_SHADER 0x8DD9 #define GL_GEOMETRY_VERTICES_OUT 0x8916 #define GL_GEOMETRY_INPUT_TYPE 0x8917 #define GL_GEOMETRY_OUTPUT_TYPE 0x8918 #define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF #define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 #define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 #define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 #define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 #define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 #define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 #define GL_CONTEXT_PROFILE_MASK 0x9126 #define GL_DEPTH_CLAMP 0x864F #define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C #define GL_FIRST_VERTEX_CONVENTION 0x8E4D #define GL_LAST_VERTEX_CONVENTION 0x8E4E #define GL_PROVOKING_VERTEX 0x8E4F #define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F #define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 #define GL_OBJECT_TYPE 0x9112 #define GL_SYNC_CONDITION 0x9113 #define GL_SYNC_STATUS 0x9114 #define GL_SYNC_FLAGS 0x9115 #define GL_SYNC_FENCE 0x9116 #define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 #define GL_UNSIGNALED 0x9118 #define GL_SIGNALED 0x9119 #define GL_ALREADY_SIGNALED 0x911A #define GL_TIMEOUT_EXPIRED 0x911B #define GL_CONDITION_SATISFIED 0x911C #define GL_WAIT_FAILED 0x911D #define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull #define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 #define GL_SAMPLE_POSITION 0x8E50 #define GL_SAMPLE_MASK 0x8E51 #define GL_SAMPLE_MASK_VALUE 0x8E52 #define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 #define GL_TEXTURE_2D_MULTISAMPLE 0x9100 #define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 #define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 #define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 #define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 #define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 #define GL_TEXTURE_SAMPLES 0x9106 #define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 #define GL_SAMPLER_2D_MULTISAMPLE 0x9108 #define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 #define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A #define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B #define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C #define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D #define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E #define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F #define GL_MAX_INTEGER_SAMPLES 0x9110 typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC) (GLenum mode); typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC) (GLenum condition, GLbitfield flags); typedef GLboolean (APIENTRYP PFNGLISSYNCPROC) (GLsync sync); typedef void (APIENTRYP PFNGLDELETESYNCPROC) (GLsync sync); typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); typedef void (APIENTRYP PFNGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); typedef void (APIENTRYP PFNGLGETINTEGER64VPROC) (GLenum pname, GLint64 *data); typedef void (APIENTRYP PFNGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei count, GLsizei *length, GLint *values); typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data); typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val); typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC) (GLuint maskNumber, GLbitfield mask); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); GLAPI void APIENTRY glDrawRangeElementsBaseVertex (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); GLAPI void APIENTRY glDrawElementsInstancedBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); GLAPI void APIENTRY glMultiDrawElementsBaseVertex (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); GLAPI void APIENTRY glProvokingVertex (GLenum mode); GLAPI GLsync APIENTRY glFenceSync (GLenum condition, GLbitfield flags); GLAPI GLboolean APIENTRY glIsSync (GLsync sync); GLAPI void APIENTRY glDeleteSync (GLsync sync); GLAPI GLenum APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); GLAPI void APIENTRY glWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); GLAPI void APIENTRY glGetInteger64v (GLenum pname, GLint64 *data); GLAPI void APIENTRY glGetSynciv (GLsync sync, GLenum pname, GLsizei count, GLsizei *length, GLint *values); GLAPI void APIENTRY glGetInteger64i_v (GLenum target, GLuint index, GLint64 *data); GLAPI void APIENTRY glGetBufferParameteri64v (GLenum target, GLenum pname, GLint64 *params); GLAPI void APIENTRY glFramebufferTexture (GLenum target, GLenum attachment, GLuint texture, GLint level); GLAPI void APIENTRY glTexImage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); GLAPI void APIENTRY glTexImage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); GLAPI void APIENTRY glGetMultisamplefv (GLenum pname, GLuint index, GLfloat *val); GLAPI void APIENTRY glSampleMaski (GLuint maskNumber, GLbitfield mask); #endif #endif /* GL_VERSION_3_2 */ #ifndef GL_VERSION_3_3 #define GL_VERSION_3_3 1 #define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE #define GL_SRC1_COLOR 0x88F9 #define GL_ONE_MINUS_SRC1_COLOR 0x88FA #define GL_ONE_MINUS_SRC1_ALPHA 0x88FB #define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC #define GL_ANY_SAMPLES_PASSED 0x8C2F #define GL_SAMPLER_BINDING 0x8919 #define GL_RGB10_A2UI 0x906F #define GL_TEXTURE_SWIZZLE_R 0x8E42 #define GL_TEXTURE_SWIZZLE_G 0x8E43 #define GL_TEXTURE_SWIZZLE_B 0x8E44 #define GL_TEXTURE_SWIZZLE_A 0x8E45 #define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 #define GL_TIME_ELAPSED 0x88BF #define GL_TIMESTAMP 0x8E28 #define GL_INT_2_10_10_10_REV 0x8D9F typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC) (GLuint program, const GLchar *name); typedef void (APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers); typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers); typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC) (GLuint sampler); typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler); typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param); typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param); typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, const GLint *param); typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, const GLuint *param); typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC) (GLuint id, GLenum target); typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC) (GLuint id, GLenum pname, GLint64 *params); typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC) (GLuint id, GLenum pname, GLuint64 *params); typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor); typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); typedef void (APIENTRYP PFNGLVERTEXP2UIPROC) (GLenum type, GLuint value); typedef void (APIENTRYP PFNGLVERTEXP2UIVPROC) (GLenum type, const GLuint *value); typedef void (APIENTRYP PFNGLVERTEXP3UIPROC) (GLenum type, GLuint value); typedef void (APIENTRYP PFNGLVERTEXP3UIVPROC) (GLenum type, const GLuint *value); typedef void (APIENTRYP PFNGLVERTEXP4UIPROC) (GLenum type, GLuint value); typedef void (APIENTRYP PFNGLVERTEXP4UIVPROC) (GLenum type, const GLuint *value); typedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC) (GLenum type, GLuint coords); typedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC) (GLenum type, const GLuint *coords); typedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC) (GLenum type, GLuint coords); typedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC) (GLenum type, const GLuint *coords); typedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC) (GLenum type, GLuint coords); typedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC) (GLenum type, const GLuint *coords); typedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC) (GLenum type, GLuint coords); typedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC) (GLenum type, const GLuint *coords); typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC) (GLenum texture, GLenum type, GLuint coords); typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC) (GLenum texture, GLenum type, GLuint coords); typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC) (GLenum texture, GLenum type, GLuint coords); typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC) (GLenum texture, GLenum type, GLuint coords); typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); typedef void (APIENTRYP PFNGLNORMALP3UIPROC) (GLenum type, GLuint coords); typedef void (APIENTRYP PFNGLNORMALP3UIVPROC) (GLenum type, const GLuint *coords); typedef void (APIENTRYP PFNGLCOLORP3UIPROC) (GLenum type, GLuint color); typedef void (APIENTRYP PFNGLCOLORP3UIVPROC) (GLenum type, const GLuint *color); typedef void (APIENTRYP PFNGLCOLORP4UIPROC) (GLenum type, GLuint color); typedef void (APIENTRYP PFNGLCOLORP4UIVPROC) (GLenum type, const GLuint *color); typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC) (GLenum type, GLuint color); typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC) (GLenum type, const GLuint *color); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindFragDataLocationIndexed (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); GLAPI GLint APIENTRY glGetFragDataIndex (GLuint program, const GLchar *name); GLAPI void APIENTRY glGenSamplers (GLsizei count, GLuint *samplers); GLAPI void APIENTRY glDeleteSamplers (GLsizei count, const GLuint *samplers); GLAPI GLboolean APIENTRY glIsSampler (GLuint sampler); GLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler); GLAPI void APIENTRY glSamplerParameteri (GLuint sampler, GLenum pname, GLint param); GLAPI void APIENTRY glSamplerParameteriv (GLuint sampler, GLenum pname, const GLint *param); GLAPI void APIENTRY glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param); GLAPI void APIENTRY glSamplerParameterfv (GLuint sampler, GLenum pname, const GLfloat *param); GLAPI void APIENTRY glSamplerParameterIiv (GLuint sampler, GLenum pname, const GLint *param); GLAPI void APIENTRY glSamplerParameterIuiv (GLuint sampler, GLenum pname, const GLuint *param); GLAPI void APIENTRY glGetSamplerParameteriv (GLuint sampler, GLenum pname, GLint *params); GLAPI void APIENTRY glGetSamplerParameterIiv (GLuint sampler, GLenum pname, GLint *params); GLAPI void APIENTRY glGetSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetSamplerParameterIuiv (GLuint sampler, GLenum pname, GLuint *params); GLAPI void APIENTRY glQueryCounter (GLuint id, GLenum target); GLAPI void APIENTRY glGetQueryObjecti64v (GLuint id, GLenum pname, GLint64 *params); GLAPI void APIENTRY glGetQueryObjectui64v (GLuint id, GLenum pname, GLuint64 *params); GLAPI void APIENTRY glVertexAttribDivisor (GLuint index, GLuint divisor); GLAPI void APIENTRY glVertexAttribP1ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); GLAPI void APIENTRY glVertexAttribP1uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); GLAPI void APIENTRY glVertexAttribP2ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); GLAPI void APIENTRY glVertexAttribP2uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); GLAPI void APIENTRY glVertexAttribP3ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); GLAPI void APIENTRY glVertexAttribP3uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); GLAPI void APIENTRY glVertexAttribP4ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); GLAPI void APIENTRY glVertexAttribP4uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); GLAPI void APIENTRY glVertexP2ui (GLenum type, GLuint value); GLAPI void APIENTRY glVertexP2uiv (GLenum type, const GLuint *value); GLAPI void APIENTRY glVertexP3ui (GLenum type, GLuint value); GLAPI void APIENTRY glVertexP3uiv (GLenum type, const GLuint *value); GLAPI void APIENTRY glVertexP4ui (GLenum type, GLuint value); GLAPI void APIENTRY glVertexP4uiv (GLenum type, const GLuint *value); GLAPI void APIENTRY glTexCoordP1ui (GLenum type, GLuint coords); GLAPI void APIENTRY glTexCoordP1uiv (GLenum type, const GLuint *coords); GLAPI void APIENTRY glTexCoordP2ui (GLenum type, GLuint coords); GLAPI void APIENTRY glTexCoordP2uiv (GLenum type, const GLuint *coords); GLAPI void APIENTRY glTexCoordP3ui (GLenum type, GLuint coords); GLAPI void APIENTRY glTexCoordP3uiv (GLenum type, const GLuint *coords); GLAPI void APIENTRY glTexCoordP4ui (GLenum type, GLuint coords); GLAPI void APIENTRY glTexCoordP4uiv (GLenum type, const GLuint *coords); GLAPI void APIENTRY glMultiTexCoordP1ui (GLenum texture, GLenum type, GLuint coords); GLAPI void APIENTRY glMultiTexCoordP1uiv (GLenum texture, GLenum type, const GLuint *coords); GLAPI void APIENTRY glMultiTexCoordP2ui (GLenum texture, GLenum type, GLuint coords); GLAPI void APIENTRY glMultiTexCoordP2uiv (GLenum texture, GLenum type, const GLuint *coords); GLAPI void APIENTRY glMultiTexCoordP3ui (GLenum texture, GLenum type, GLuint coords); GLAPI void APIENTRY glMultiTexCoordP3uiv (GLenum texture, GLenum type, const GLuint *coords); GLAPI void APIENTRY glMultiTexCoordP4ui (GLenum texture, GLenum type, GLuint coords); GLAPI void APIENTRY glMultiTexCoordP4uiv (GLenum texture, GLenum type, const GLuint *coords); GLAPI void APIENTRY glNormalP3ui (GLenum type, GLuint coords); GLAPI void APIENTRY glNormalP3uiv (GLenum type, const GLuint *coords); GLAPI void APIENTRY glColorP3ui (GLenum type, GLuint color); GLAPI void APIENTRY glColorP3uiv (GLenum type, const GLuint *color); GLAPI void APIENTRY glColorP4ui (GLenum type, GLuint color); GLAPI void APIENTRY glColorP4uiv (GLenum type, const GLuint *color); GLAPI void APIENTRY glSecondaryColorP3ui (GLenum type, GLuint color); GLAPI void APIENTRY glSecondaryColorP3uiv (GLenum type, const GLuint *color); #endif #endif /* GL_VERSION_3_3 */ #ifndef GL_VERSION_4_0 #define GL_VERSION_4_0 1 #define GL_SAMPLE_SHADING 0x8C36 #define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37 #define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E #define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F #define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009 #define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A #define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B #define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C #define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D #define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E #define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F #define GL_DRAW_INDIRECT_BUFFER 0x8F3F #define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 #define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F #define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A #define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B #define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C #define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D #define GL_MAX_VERTEX_STREAMS 0x8E71 #define GL_DOUBLE_VEC2 0x8FFC #define GL_DOUBLE_VEC3 0x8FFD #define GL_DOUBLE_VEC4 0x8FFE #define GL_DOUBLE_MAT2 0x8F46 #define GL_DOUBLE_MAT3 0x8F47 #define GL_DOUBLE_MAT4 0x8F48 #define GL_DOUBLE_MAT2x3 0x8F49 #define GL_DOUBLE_MAT2x4 0x8F4A #define GL_DOUBLE_MAT3x2 0x8F4B #define GL_DOUBLE_MAT3x4 0x8F4C #define GL_DOUBLE_MAT4x2 0x8F4D #define GL_DOUBLE_MAT4x3 0x8F4E #define GL_ACTIVE_SUBROUTINES 0x8DE5 #define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6 #define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47 #define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48 #define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49 #define GL_MAX_SUBROUTINES 0x8DE7 #define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8 #define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A #define GL_COMPATIBLE_SUBROUTINES 0x8E4B #define GL_PATCHES 0x000E #define GL_PATCH_VERTICES 0x8E72 #define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 #define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 #define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75 #define GL_TESS_GEN_MODE 0x8E76 #define GL_TESS_GEN_SPACING 0x8E77 #define GL_TESS_GEN_VERTEX_ORDER 0x8E78 #define GL_TESS_GEN_POINT_MODE 0x8E79 #define GL_ISOLINES 0x8E7A #define GL_FRACTIONAL_ODD 0x8E7B #define GL_FRACTIONAL_EVEN 0x8E7C #define GL_MAX_PATCH_VERTICES 0x8E7D #define GL_MAX_TESS_GEN_LEVEL 0x8E7E #define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F #define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80 #define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81 #define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82 #define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83 #define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84 #define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85 #define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86 #define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89 #define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A #define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C #define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D #define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E #define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F #define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0 #define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1 #define GL_TESS_EVALUATION_SHADER 0x8E87 #define GL_TESS_CONTROL_SHADER 0x8E88 #define GL_TRANSFORM_FEEDBACK 0x8E22 #define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23 #define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24 #define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 #define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70 typedef void (APIENTRYP PFNGLMINSAMPLESHADINGPROC) (GLfloat value); typedef void (APIENTRYP PFNGLBLENDEQUATIONIPROC) (GLuint buf, GLenum mode); typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); typedef void (APIENTRYP PFNGLBLENDFUNCIPROC) (GLuint buf, GLenum src, GLenum dst); typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); typedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect); typedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect); typedef void (APIENTRYP PFNGLUNIFORM1DPROC) (GLint location, GLdouble x); typedef void (APIENTRYP PFNGLUNIFORM2DPROC) (GLint location, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLUNIFORM3DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLUNIFORM4DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLUNIFORM1DVPROC) (GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORM2DVPROC) (GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORM3DVPROC) (GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORM4DVPROC) (GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLGETUNIFORMDVPROC) (GLuint program, GLint location, GLdouble *params); typedef GLint (APIENTRYP PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC) (GLuint program, GLenum shadertype, const GLchar *name); typedef GLuint (APIENTRYP PFNGLGETSUBROUTINEINDEXPROC) (GLuint program, GLenum shadertype, const GLchar *name); typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC) (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINENAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); typedef void (APIENTRYP PFNGLUNIFORMSUBROUTINESUIVPROC) (GLenum shadertype, GLsizei count, const GLuint *indices); typedef void (APIENTRYP PFNGLGETUNIFORMSUBROUTINEUIVPROC) (GLenum shadertype, GLint location, GLuint *params); typedef void (APIENTRYP PFNGLGETPROGRAMSTAGEIVPROC) (GLuint program, GLenum shadertype, GLenum pname, GLint *values); typedef void (APIENTRYP PFNGLPATCHPARAMETERIPROC) (GLenum pname, GLint value); typedef void (APIENTRYP PFNGLPATCHPARAMETERFVPROC) (GLenum pname, const GLfloat *values); typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id); typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids); typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids); typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC) (GLuint id); typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC) (void); typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC) (void); typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC) (GLenum mode, GLuint id); typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC) (GLenum mode, GLuint id, GLuint stream); typedef void (APIENTRYP PFNGLBEGINQUERYINDEXEDPROC) (GLenum target, GLuint index, GLuint id); typedef void (APIENTRYP PFNGLENDQUERYINDEXEDPROC) (GLenum target, GLuint index); typedef void (APIENTRYP PFNGLGETQUERYINDEXEDIVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMinSampleShading (GLfloat value); GLAPI void APIENTRY glBlendEquationi (GLuint buf, GLenum mode); GLAPI void APIENTRY glBlendEquationSeparatei (GLuint buf, GLenum modeRGB, GLenum modeAlpha); GLAPI void APIENTRY glBlendFunci (GLuint buf, GLenum src, GLenum dst); GLAPI void APIENTRY glBlendFuncSeparatei (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); GLAPI void APIENTRY glDrawArraysIndirect (GLenum mode, const void *indirect); GLAPI void APIENTRY glDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect); GLAPI void APIENTRY glUniform1d (GLint location, GLdouble x); GLAPI void APIENTRY glUniform2d (GLint location, GLdouble x, GLdouble y); GLAPI void APIENTRY glUniform3d (GLint location, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glUniform4d (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glUniform1dv (GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glUniform2dv (GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glUniform3dv (GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glUniform4dv (GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glUniformMatrix2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glUniformMatrix3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glUniformMatrix4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glUniformMatrix2x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glUniformMatrix2x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glUniformMatrix3x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glUniformMatrix3x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glUniformMatrix4x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glUniformMatrix4x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glGetUniformdv (GLuint program, GLint location, GLdouble *params); GLAPI GLint APIENTRY glGetSubroutineUniformLocation (GLuint program, GLenum shadertype, const GLchar *name); GLAPI GLuint APIENTRY glGetSubroutineIndex (GLuint program, GLenum shadertype, const GLchar *name); GLAPI void APIENTRY glGetActiveSubroutineUniformiv (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); GLAPI void APIENTRY glGetActiveSubroutineUniformName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); GLAPI void APIENTRY glGetActiveSubroutineName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); GLAPI void APIENTRY glUniformSubroutinesuiv (GLenum shadertype, GLsizei count, const GLuint *indices); GLAPI void APIENTRY glGetUniformSubroutineuiv (GLenum shadertype, GLint location, GLuint *params); GLAPI void APIENTRY glGetProgramStageiv (GLuint program, GLenum shadertype, GLenum pname, GLint *values); GLAPI void APIENTRY glPatchParameteri (GLenum pname, GLint value); GLAPI void APIENTRY glPatchParameterfv (GLenum pname, const GLfloat *values); GLAPI void APIENTRY glBindTransformFeedback (GLenum target, GLuint id); GLAPI void APIENTRY glDeleteTransformFeedbacks (GLsizei n, const GLuint *ids); GLAPI void APIENTRY glGenTransformFeedbacks (GLsizei n, GLuint *ids); GLAPI GLboolean APIENTRY glIsTransformFeedback (GLuint id); GLAPI void APIENTRY glPauseTransformFeedback (void); GLAPI void APIENTRY glResumeTransformFeedback (void); GLAPI void APIENTRY glDrawTransformFeedback (GLenum mode, GLuint id); GLAPI void APIENTRY glDrawTransformFeedbackStream (GLenum mode, GLuint id, GLuint stream); GLAPI void APIENTRY glBeginQueryIndexed (GLenum target, GLuint index, GLuint id); GLAPI void APIENTRY glEndQueryIndexed (GLenum target, GLuint index); GLAPI void APIENTRY glGetQueryIndexediv (GLenum target, GLuint index, GLenum pname, GLint *params); #endif #endif /* GL_VERSION_4_0 */ #ifndef GL_VERSION_4_1 #define GL_VERSION_4_1 1 #define GL_FIXED 0x140C #define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A #define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B #define GL_LOW_FLOAT 0x8DF0 #define GL_MEDIUM_FLOAT 0x8DF1 #define GL_HIGH_FLOAT 0x8DF2 #define GL_LOW_INT 0x8DF3 #define GL_MEDIUM_INT 0x8DF4 #define GL_HIGH_INT 0x8DF5 #define GL_SHADER_COMPILER 0x8DFA #define GL_SHADER_BINARY_FORMATS 0x8DF8 #define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 #define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB #define GL_MAX_VARYING_VECTORS 0x8DFC #define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD #define GL_RGB565 0x8D62 #define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 #define GL_PROGRAM_BINARY_LENGTH 0x8741 #define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE #define GL_PROGRAM_BINARY_FORMATS 0x87FF #define GL_VERTEX_SHADER_BIT 0x00000001 #define GL_FRAGMENT_SHADER_BIT 0x00000002 #define GL_GEOMETRY_SHADER_BIT 0x00000004 #define GL_TESS_CONTROL_SHADER_BIT 0x00000008 #define GL_TESS_EVALUATION_SHADER_BIT 0x00000010 #define GL_ALL_SHADER_BITS 0xFFFFFFFF #define GL_PROGRAM_SEPARABLE 0x8258 #define GL_ACTIVE_PROGRAM 0x8259 #define GL_PROGRAM_PIPELINE_BINDING 0x825A #define GL_MAX_VIEWPORTS 0x825B #define GL_VIEWPORT_SUBPIXEL_BITS 0x825C #define GL_VIEWPORT_BOUNDS_RANGE 0x825D #define GL_LAYER_PROVOKING_VERTEX 0x825E #define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F #define GL_UNDEFINED_VERTEX 0x8260 typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC) (void); typedef void (APIENTRYP PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryFormat, const void *binary, GLsizei length); typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f); typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC) (GLfloat d); typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); typedef void (APIENTRYP PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value); typedef void (APIENTRYP PFNGLUSEPROGRAMSTAGESPROC) (GLuint pipeline, GLbitfield stages, GLuint program); typedef void (APIENTRYP PFNGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program); typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar *const*strings); typedef void (APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC) (GLuint pipeline); typedef void (APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC) (GLsizei n, const GLuint *pipelines); typedef void (APIENTRYP PFNGLGENPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines); typedef GLboolean (APIENTRYP PFNGLISPROGRAMPIPELINEPROC) (GLuint pipeline); typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC) (GLuint pipeline, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IPROC) (GLuint program, GLint location, GLint v0); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FPROC) (GLuint program, GLint location, GLfloat v0); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DPROC) (GLuint program, GLint location, GLdouble v0); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC) (GLuint program, GLint location, GLuint v0); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IPROC) (GLuint program, GLint location, GLint v0, GLint v1); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC) (GLuint pipeline); typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DPROC) (GLuint index, GLdouble x); typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DPROC) (GLuint index, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC) (GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLVIEWPORTARRAYVPROC) (GLuint first, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLSCISSORARRAYVPROC) (GLuint first, GLsizei count, const GLint *v); typedef void (APIENTRYP PFNGLSCISSORINDEXEDPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLSCISSORINDEXEDVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLDEPTHRANGEARRAYVPROC) (GLuint first, GLsizei count, const GLdouble *v); typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC) (GLuint index, GLdouble n, GLdouble f); typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data); typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glReleaseShaderCompiler (void); GLAPI void APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryFormat, const void *binary, GLsizei length); GLAPI void APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); GLAPI void APIENTRY glDepthRangef (GLfloat n, GLfloat f); GLAPI void APIENTRY glClearDepthf (GLfloat d); GLAPI void APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); GLAPI void APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); GLAPI void APIENTRY glProgramParameteri (GLuint program, GLenum pname, GLint value); GLAPI void APIENTRY glUseProgramStages (GLuint pipeline, GLbitfield stages, GLuint program); GLAPI void APIENTRY glActiveShaderProgram (GLuint pipeline, GLuint program); GLAPI GLuint APIENTRY glCreateShaderProgramv (GLenum type, GLsizei count, const GLchar *const*strings); GLAPI void APIENTRY glBindProgramPipeline (GLuint pipeline); GLAPI void APIENTRY glDeleteProgramPipelines (GLsizei n, const GLuint *pipelines); GLAPI void APIENTRY glGenProgramPipelines (GLsizei n, GLuint *pipelines); GLAPI GLboolean APIENTRY glIsProgramPipeline (GLuint pipeline); GLAPI void APIENTRY glGetProgramPipelineiv (GLuint pipeline, GLenum pname, GLint *params); GLAPI void APIENTRY glProgramUniform1i (GLuint program, GLint location, GLint v0); GLAPI void APIENTRY glProgramUniform1iv (GLuint program, GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glProgramUniform1f (GLuint program, GLint location, GLfloat v0); GLAPI void APIENTRY glProgramUniform1fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glProgramUniform1d (GLuint program, GLint location, GLdouble v0); GLAPI void APIENTRY glProgramUniform1dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glProgramUniform1ui (GLuint program, GLint location, GLuint v0); GLAPI void APIENTRY glProgramUniform1uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glProgramUniform2i (GLuint program, GLint location, GLint v0, GLint v1); GLAPI void APIENTRY glProgramUniform2iv (GLuint program, GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glProgramUniform2f (GLuint program, GLint location, GLfloat v0, GLfloat v1); GLAPI void APIENTRY glProgramUniform2fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glProgramUniform2d (GLuint program, GLint location, GLdouble v0, GLdouble v1); GLAPI void APIENTRY glProgramUniform2dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glProgramUniform2ui (GLuint program, GLint location, GLuint v0, GLuint v1); GLAPI void APIENTRY glProgramUniform2uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glProgramUniform3i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); GLAPI void APIENTRY glProgramUniform3iv (GLuint program, GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glProgramUniform3f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); GLAPI void APIENTRY glProgramUniform3fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glProgramUniform3d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); GLAPI void APIENTRY glProgramUniform3dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glProgramUniform3ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); GLAPI void APIENTRY glProgramUniform3uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glProgramUniform4i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); GLAPI void APIENTRY glProgramUniform4iv (GLuint program, GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glProgramUniform4f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); GLAPI void APIENTRY glProgramUniform4fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glProgramUniform4d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); GLAPI void APIENTRY glProgramUniform4dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glProgramUniform4ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); GLAPI void APIENTRY glProgramUniform4uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glProgramUniformMatrix2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix2x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix3x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix2x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix4x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix3x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix4x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix2x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix3x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix2x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix4x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix3x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix4x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glValidateProgramPipeline (GLuint pipeline); GLAPI void APIENTRY glGetProgramPipelineInfoLog (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); GLAPI void APIENTRY glVertexAttribL1d (GLuint index, GLdouble x); GLAPI void APIENTRY glVertexAttribL2d (GLuint index, GLdouble x, GLdouble y); GLAPI void APIENTRY glVertexAttribL3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glVertexAttribL4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glVertexAttribL1dv (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribL2dv (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribL3dv (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribL4dv (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribLPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); GLAPI void APIENTRY glGetVertexAttribLdv (GLuint index, GLenum pname, GLdouble *params); GLAPI void APIENTRY glViewportArrayv (GLuint first, GLsizei count, const GLfloat *v); GLAPI void APIENTRY glViewportIndexedf (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); GLAPI void APIENTRY glViewportIndexedfv (GLuint index, const GLfloat *v); GLAPI void APIENTRY glScissorArrayv (GLuint first, GLsizei count, const GLint *v); GLAPI void APIENTRY glScissorIndexed (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); GLAPI void APIENTRY glScissorIndexedv (GLuint index, const GLint *v); GLAPI void APIENTRY glDepthRangeArrayv (GLuint first, GLsizei count, const GLdouble *v); GLAPI void APIENTRY glDepthRangeIndexed (GLuint index, GLdouble n, GLdouble f); GLAPI void APIENTRY glGetFloati_v (GLenum target, GLuint index, GLfloat *data); GLAPI void APIENTRY glGetDoublei_v (GLenum target, GLuint index, GLdouble *data); #endif #endif /* GL_VERSION_4_1 */ #ifndef GL_VERSION_4_2 #define GL_VERSION_4_2 1 #define GL_COPY_READ_BUFFER_BINDING 0x8F36 #define GL_COPY_WRITE_BUFFER_BINDING 0x8F37 #define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24 #define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23 #define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127 #define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128 #define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129 #define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A #define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B #define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C #define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D #define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E #define GL_NUM_SAMPLE_COUNTS 0x9380 #define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC #define GL_ATOMIC_COUNTER_BUFFER 0x92C0 #define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1 #define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2 #define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3 #define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4 #define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5 #define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6 #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7 #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8 #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9 #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB #define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC #define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD #define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE #define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF #define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0 #define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1 #define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2 #define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3 #define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4 #define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5 #define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6 #define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7 #define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8 #define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC #define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9 #define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA #define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB #define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 #define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 #define GL_UNIFORM_BARRIER_BIT 0x00000004 #define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 #define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 #define GL_COMMAND_BARRIER_BIT 0x00000040 #define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 #define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 #define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 #define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 #define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800 #define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 #define GL_ALL_BARRIER_BITS 0xFFFFFFFF #define GL_MAX_IMAGE_UNITS 0x8F38 #define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39 #define GL_IMAGE_BINDING_NAME 0x8F3A #define GL_IMAGE_BINDING_LEVEL 0x8F3B #define GL_IMAGE_BINDING_LAYERED 0x8F3C #define GL_IMAGE_BINDING_LAYER 0x8F3D #define GL_IMAGE_BINDING_ACCESS 0x8F3E #define GL_IMAGE_1D 0x904C #define GL_IMAGE_2D 0x904D #define GL_IMAGE_3D 0x904E #define GL_IMAGE_2D_RECT 0x904F #define GL_IMAGE_CUBE 0x9050 #define GL_IMAGE_BUFFER 0x9051 #define GL_IMAGE_1D_ARRAY 0x9052 #define GL_IMAGE_2D_ARRAY 0x9053 #define GL_IMAGE_CUBE_MAP_ARRAY 0x9054 #define GL_IMAGE_2D_MULTISAMPLE 0x9055 #define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056 #define GL_INT_IMAGE_1D 0x9057 #define GL_INT_IMAGE_2D 0x9058 #define GL_INT_IMAGE_3D 0x9059 #define GL_INT_IMAGE_2D_RECT 0x905A #define GL_INT_IMAGE_CUBE 0x905B #define GL_INT_IMAGE_BUFFER 0x905C #define GL_INT_IMAGE_1D_ARRAY 0x905D #define GL_INT_IMAGE_2D_ARRAY 0x905E #define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F #define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060 #define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061 #define GL_UNSIGNED_INT_IMAGE_1D 0x9062 #define GL_UNSIGNED_INT_IMAGE_2D 0x9063 #define GL_UNSIGNED_INT_IMAGE_3D 0x9064 #define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065 #define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 #define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 #define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068 #define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 #define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A #define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B #define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C #define GL_MAX_IMAGE_SAMPLES 0x906D #define GL_IMAGE_BINDING_FORMAT 0x906E #define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7 #define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8 #define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9 #define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA #define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB #define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC #define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD #define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE #define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF #define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C #define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D #define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E #define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F #define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint *params); typedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers); typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) (GLenum mode, GLuint id, GLsizei instancecount); typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawArraysInstancedBaseInstance (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); GLAPI void APIENTRY glDrawElementsInstancedBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); GLAPI void APIENTRY glDrawElementsInstancedBaseVertexBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); GLAPI void APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint *params); GLAPI void APIENTRY glGetActiveAtomicCounterBufferiv (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); GLAPI void APIENTRY glBindImageTexture (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); GLAPI void APIENTRY glMemoryBarrier (GLbitfield barriers); GLAPI void APIENTRY glTexStorage1D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); GLAPI void APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); GLAPI void APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); GLAPI void APIENTRY glDrawTransformFeedbackInstanced (GLenum mode, GLuint id, GLsizei instancecount); GLAPI void APIENTRY glDrawTransformFeedbackStreamInstanced (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); #endif #endif /* GL_VERSION_4_2 */ #ifndef GL_VERSION_4_3 #define GL_VERSION_4_3 1 typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); #define GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9 #define GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E #define GL_COMPRESSED_RGB8_ETC2 0x9274 #define GL_COMPRESSED_SRGB8_ETC2 0x9275 #define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 #define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 #define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 #define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 #define GL_COMPRESSED_R11_EAC 0x9270 #define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 #define GL_COMPRESSED_RG11_EAC 0x9272 #define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 #define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 #define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A #define GL_MAX_ELEMENT_INDEX 0x8D6B #define GL_COMPUTE_SHADER 0x91B9 #define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB #define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC #define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD #define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262 #define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263 #define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264 #define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265 #define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266 #define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB #define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE #define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF #define GL_COMPUTE_WORK_GROUP_SIZE 0x8267 #define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED #define GL_DISPATCH_INDIRECT_BUFFER 0x90EE #define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF #define GL_COMPUTE_SHADER_BIT 0x00000020 #define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 #define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 #define GL_DEBUG_CALLBACK_FUNCTION 0x8244 #define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 #define GL_DEBUG_SOURCE_API 0x8246 #define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 #define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 #define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 #define GL_DEBUG_SOURCE_APPLICATION 0x824A #define GL_DEBUG_SOURCE_OTHER 0x824B #define GL_DEBUG_TYPE_ERROR 0x824C #define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D #define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E #define GL_DEBUG_TYPE_PORTABILITY 0x824F #define GL_DEBUG_TYPE_PERFORMANCE 0x8250 #define GL_DEBUG_TYPE_OTHER 0x8251 #define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 #define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 #define GL_DEBUG_LOGGED_MESSAGES 0x9145 #define GL_DEBUG_SEVERITY_HIGH 0x9146 #define GL_DEBUG_SEVERITY_MEDIUM 0x9147 #define GL_DEBUG_SEVERITY_LOW 0x9148 #define GL_DEBUG_TYPE_MARKER 0x8268 #define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 #define GL_DEBUG_TYPE_POP_GROUP 0x826A #define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B #define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C #define GL_DEBUG_GROUP_STACK_DEPTH 0x826D #define GL_BUFFER 0x82E0 #define GL_SHADER 0x82E1 #define GL_PROGRAM 0x82E2 #define GL_QUERY 0x82E3 #define GL_PROGRAM_PIPELINE 0x82E4 #define GL_SAMPLER 0x82E6 #define GL_MAX_LABEL_LENGTH 0x82E8 #define GL_DEBUG_OUTPUT 0x92E0 #define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 #define GL_MAX_UNIFORM_LOCATIONS 0x826E #define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310 #define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311 #define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312 #define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313 #define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314 #define GL_MAX_FRAMEBUFFER_WIDTH 0x9315 #define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316 #define GL_MAX_FRAMEBUFFER_LAYERS 0x9317 #define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318 #define GL_INTERNALFORMAT_SUPPORTED 0x826F #define GL_INTERNALFORMAT_PREFERRED 0x8270 #define GL_INTERNALFORMAT_RED_SIZE 0x8271 #define GL_INTERNALFORMAT_GREEN_SIZE 0x8272 #define GL_INTERNALFORMAT_BLUE_SIZE 0x8273 #define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274 #define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275 #define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276 #define GL_INTERNALFORMAT_SHARED_SIZE 0x8277 #define GL_INTERNALFORMAT_RED_TYPE 0x8278 #define GL_INTERNALFORMAT_GREEN_TYPE 0x8279 #define GL_INTERNALFORMAT_BLUE_TYPE 0x827A #define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B #define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C #define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D #define GL_MAX_WIDTH 0x827E #define GL_MAX_HEIGHT 0x827F #define GL_MAX_DEPTH 0x8280 #define GL_MAX_LAYERS 0x8281 #define GL_MAX_COMBINED_DIMENSIONS 0x8282 #define GL_COLOR_COMPONENTS 0x8283 #define GL_DEPTH_COMPONENTS 0x8284 #define GL_STENCIL_COMPONENTS 0x8285 #define GL_COLOR_RENDERABLE 0x8286 #define GL_DEPTH_RENDERABLE 0x8287 #define GL_STENCIL_RENDERABLE 0x8288 #define GL_FRAMEBUFFER_RENDERABLE 0x8289 #define GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A #define GL_FRAMEBUFFER_BLEND 0x828B #define GL_READ_PIXELS 0x828C #define GL_READ_PIXELS_FORMAT 0x828D #define GL_READ_PIXELS_TYPE 0x828E #define GL_TEXTURE_IMAGE_FORMAT 0x828F #define GL_TEXTURE_IMAGE_TYPE 0x8290 #define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291 #define GL_GET_TEXTURE_IMAGE_TYPE 0x8292 #define GL_MIPMAP 0x8293 #define GL_MANUAL_GENERATE_MIPMAP 0x8294 #define GL_AUTO_GENERATE_MIPMAP 0x8295 #define GL_COLOR_ENCODING 0x8296 #define GL_SRGB_READ 0x8297 #define GL_SRGB_WRITE 0x8298 #define GL_FILTER 0x829A #define GL_VERTEX_TEXTURE 0x829B #define GL_TESS_CONTROL_TEXTURE 0x829C #define GL_TESS_EVALUATION_TEXTURE 0x829D #define GL_GEOMETRY_TEXTURE 0x829E #define GL_FRAGMENT_TEXTURE 0x829F #define GL_COMPUTE_TEXTURE 0x82A0 #define GL_TEXTURE_SHADOW 0x82A1 #define GL_TEXTURE_GATHER 0x82A2 #define GL_TEXTURE_GATHER_SHADOW 0x82A3 #define GL_SHADER_IMAGE_LOAD 0x82A4 #define GL_SHADER_IMAGE_STORE 0x82A5 #define GL_SHADER_IMAGE_ATOMIC 0x82A6 #define GL_IMAGE_TEXEL_SIZE 0x82A7 #define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8 #define GL_IMAGE_PIXEL_FORMAT 0x82A9 #define GL_IMAGE_PIXEL_TYPE 0x82AA #define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC #define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD #define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE #define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF #define GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1 #define GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2 #define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3 #define GL_CLEAR_BUFFER 0x82B4 #define GL_TEXTURE_VIEW 0x82B5 #define GL_VIEW_COMPATIBILITY_CLASS 0x82B6 #define GL_FULL_SUPPORT 0x82B7 #define GL_CAVEAT_SUPPORT 0x82B8 #define GL_IMAGE_CLASS_4_X_32 0x82B9 #define GL_IMAGE_CLASS_2_X_32 0x82BA #define GL_IMAGE_CLASS_1_X_32 0x82BB #define GL_IMAGE_CLASS_4_X_16 0x82BC #define GL_IMAGE_CLASS_2_X_16 0x82BD #define GL_IMAGE_CLASS_1_X_16 0x82BE #define GL_IMAGE_CLASS_4_X_8 0x82BF #define GL_IMAGE_CLASS_2_X_8 0x82C0 #define GL_IMAGE_CLASS_1_X_8 0x82C1 #define GL_IMAGE_CLASS_11_11_10 0x82C2 #define GL_IMAGE_CLASS_10_10_10_2 0x82C3 #define GL_VIEW_CLASS_128_BITS 0x82C4 #define GL_VIEW_CLASS_96_BITS 0x82C5 #define GL_VIEW_CLASS_64_BITS 0x82C6 #define GL_VIEW_CLASS_48_BITS 0x82C7 #define GL_VIEW_CLASS_32_BITS 0x82C8 #define GL_VIEW_CLASS_24_BITS 0x82C9 #define GL_VIEW_CLASS_16_BITS 0x82CA #define GL_VIEW_CLASS_8_BITS 0x82CB #define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC #define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD #define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE #define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF #define GL_VIEW_CLASS_RGTC1_RED 0x82D0 #define GL_VIEW_CLASS_RGTC2_RG 0x82D1 #define GL_VIEW_CLASS_BPTC_UNORM 0x82D2 #define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3 #define GL_UNIFORM 0x92E1 #define GL_UNIFORM_BLOCK 0x92E2 #define GL_PROGRAM_INPUT 0x92E3 #define GL_PROGRAM_OUTPUT 0x92E4 #define GL_BUFFER_VARIABLE 0x92E5 #define GL_SHADER_STORAGE_BLOCK 0x92E6 #define GL_VERTEX_SUBROUTINE 0x92E8 #define GL_TESS_CONTROL_SUBROUTINE 0x92E9 #define GL_TESS_EVALUATION_SUBROUTINE 0x92EA #define GL_GEOMETRY_SUBROUTINE 0x92EB #define GL_FRAGMENT_SUBROUTINE 0x92EC #define GL_COMPUTE_SUBROUTINE 0x92ED #define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE #define GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF #define GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0 #define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1 #define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2 #define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3 #define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4 #define GL_ACTIVE_RESOURCES 0x92F5 #define GL_MAX_NAME_LENGTH 0x92F6 #define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7 #define GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8 #define GL_NAME_LENGTH 0x92F9 #define GL_TYPE 0x92FA #define GL_ARRAY_SIZE 0x92FB #define GL_OFFSET 0x92FC #define GL_BLOCK_INDEX 0x92FD #define GL_ARRAY_STRIDE 0x92FE #define GL_MATRIX_STRIDE 0x92FF #define GL_IS_ROW_MAJOR 0x9300 #define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301 #define GL_BUFFER_BINDING 0x9302 #define GL_BUFFER_DATA_SIZE 0x9303 #define GL_NUM_ACTIVE_VARIABLES 0x9304 #define GL_ACTIVE_VARIABLES 0x9305 #define GL_REFERENCED_BY_VERTEX_SHADER 0x9306 #define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307 #define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308 #define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309 #define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A #define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B #define GL_TOP_LEVEL_ARRAY_SIZE 0x930C #define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D #define GL_LOCATION 0x930E #define GL_LOCATION_INDEX 0x930F #define GL_IS_PER_PATCH 0x92E7 #define GL_SHADER_STORAGE_BUFFER 0x90D2 #define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3 #define GL_SHADER_STORAGE_BUFFER_START 0x90D4 #define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5 #define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6 #define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7 #define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8 #define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9 #define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA #define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB #define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC #define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD #define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE #define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF #define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000 #define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39 #define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA #define GL_TEXTURE_BUFFER_OFFSET 0x919D #define GL_TEXTURE_BUFFER_SIZE 0x919E #define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F #define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB #define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC #define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD #define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE #define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF #define GL_VERTEX_ATTRIB_BINDING 0x82D4 #define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5 #define GL_VERTEX_BINDING_DIVISOR 0x82D6 #define GL_VERTEX_BINDING_OFFSET 0x82D7 #define GL_VERTEX_BINDING_STRIDE 0x82D8 #define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9 #define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA #define GL_VERTEX_BINDING_BUFFER 0x8F4F #define GL_DISPLAY_LIST 0x82E7 typedef void (APIENTRYP PFNGLCLEARBUFFERDATAPROC) (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data); typedef void (APIENTRYP PFNGLCLEARBUFFERSUBDATAPROC) (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEINDIRECTPROC) (GLintptr indirect); typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATAPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); typedef void (APIENTRYP PFNGLFRAMEBUFFERPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETINTERNALFORMATI64VPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint64 *params); typedef void (APIENTRYP PFNGLINVALIDATETEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); typedef void (APIENTRYP PFNGLINVALIDATETEXIMAGEPROC) (GLuint texture, GLint level); typedef void (APIENTRYP PFNGLINVALIDATEBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); typedef void (APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); typedef void (APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); typedef void (APIENTRYP PFNGLGETPROGRAMINTERFACEIVPROC) (GLuint program, GLenum programInterface, GLenum pname, GLint *params); typedef GLuint (APIENTRYP PFNGLGETPROGRAMRESOURCEINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCENAMEPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEIVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei count, GLsizei *length, GLint *params); typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONPROC) (GLuint program, GLenum programInterface, const GLchar *name); typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); typedef void (APIENTRYP PFNGLSHADERSTORAGEBLOCKBINDINGPROC) (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); typedef void (APIENTRYP PFNGLTEXBUFFERRANGEPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (APIENTRYP PFNGLTEXSTORAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); typedef void (APIENTRYP PFNGLTEXSTORAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); typedef void (APIENTRYP PFNGLTEXTUREVIEWPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERPROC) (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); typedef void (APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex); typedef void (APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor); typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam); typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message); typedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC) (void); typedef void (APIENTRYP PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); typedef void (APIENTRYP PFNGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); typedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label); typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glClearBufferData (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data); GLAPI void APIENTRY glClearBufferSubData (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); GLAPI void APIENTRY glDispatchCompute (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); GLAPI void APIENTRY glDispatchComputeIndirect (GLintptr indirect); GLAPI void APIENTRY glCopyImageSubData (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); GLAPI void APIENTRY glFramebufferParameteri (GLenum target, GLenum pname, GLint param); GLAPI void APIENTRY glGetFramebufferParameteriv (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetInternalformati64v (GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint64 *params); GLAPI void APIENTRY glInvalidateTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); GLAPI void APIENTRY glInvalidateTexImage (GLuint texture, GLint level); GLAPI void APIENTRY glInvalidateBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr length); GLAPI void APIENTRY glInvalidateBufferData (GLuint buffer); GLAPI void APIENTRY glInvalidateFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments); GLAPI void APIENTRY glInvalidateSubFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glMultiDrawArraysIndirect (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); GLAPI void APIENTRY glMultiDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); GLAPI void APIENTRY glGetProgramInterfaceiv (GLuint program, GLenum programInterface, GLenum pname, GLint *params); GLAPI GLuint APIENTRY glGetProgramResourceIndex (GLuint program, GLenum programInterface, const GLchar *name); GLAPI void APIENTRY glGetProgramResourceName (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); GLAPI void APIENTRY glGetProgramResourceiv (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei count, GLsizei *length, GLint *params); GLAPI GLint APIENTRY glGetProgramResourceLocation (GLuint program, GLenum programInterface, const GLchar *name); GLAPI GLint APIENTRY glGetProgramResourceLocationIndex (GLuint program, GLenum programInterface, const GLchar *name); GLAPI void APIENTRY glShaderStorageBlockBinding (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); GLAPI void APIENTRY glTexBufferRange (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); GLAPI void APIENTRY glTexStorage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); GLAPI void APIENTRY glTexStorage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); GLAPI void APIENTRY glTextureView (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); GLAPI void APIENTRY glBindVertexBuffer (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); GLAPI void APIENTRY glVertexAttribFormat (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); GLAPI void APIENTRY glVertexAttribIFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); GLAPI void APIENTRY glVertexAttribLFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); GLAPI void APIENTRY glVertexAttribBinding (GLuint attribindex, GLuint bindingindex); GLAPI void APIENTRY glVertexBindingDivisor (GLuint bindingindex, GLuint divisor); GLAPI void APIENTRY glDebugMessageControl (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); GLAPI void APIENTRY glDebugMessageInsert (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); GLAPI void APIENTRY glDebugMessageCallback (GLDEBUGPROC callback, const void *userParam); GLAPI GLuint APIENTRY glGetDebugMessageLog (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); GLAPI void APIENTRY glPushDebugGroup (GLenum source, GLuint id, GLsizei length, const GLchar *message); GLAPI void APIENTRY glPopDebugGroup (void); GLAPI void APIENTRY glObjectLabel (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); GLAPI void APIENTRY glGetObjectLabel (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); GLAPI void APIENTRY glObjectPtrLabel (const void *ptr, GLsizei length, const GLchar *label); GLAPI void APIENTRY glGetObjectPtrLabel (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); #endif #endif /* GL_VERSION_4_3 */ #ifndef GL_VERSION_4_4 #define GL_VERSION_4_4 1 #define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5 #define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221 #define GL_TEXTURE_BUFFER_BINDING 0x8C2A #define GL_MAP_PERSISTENT_BIT 0x0040 #define GL_MAP_COHERENT_BIT 0x0080 #define GL_DYNAMIC_STORAGE_BIT 0x0100 #define GL_CLIENT_STORAGE_BIT 0x0200 #define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000 #define GL_BUFFER_IMMUTABLE_STORAGE 0x821F #define GL_BUFFER_STORAGE_FLAGS 0x8220 #define GL_CLEAR_TEXTURE 0x9365 #define GL_LOCATION_COMPONENT 0x934A #define GL_TRANSFORM_FEEDBACK_BUFFER_INDEX 0x934B #define GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE 0x934C #define GL_QUERY_BUFFER 0x9192 #define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000 #define GL_QUERY_BUFFER_BINDING 0x9193 #define GL_QUERY_RESULT_NO_WAIT 0x9194 #define GL_MIRROR_CLAMP_TO_EDGE 0x8743 typedef void (APIENTRYP PFNGLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); typedef void (APIENTRYP PFNGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data); typedef void (APIENTRYP PFNGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data); typedef void (APIENTRYP PFNGLBINDBUFFERSBASEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers); typedef void (APIENTRYP PFNGLBINDBUFFERSRANGEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes); typedef void (APIENTRYP PFNGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures); typedef void (APIENTRYP PFNGLBINDSAMPLERSPROC) (GLuint first, GLsizei count, const GLuint *samplers); typedef void (APIENTRYP PFNGLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures); typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERSPROC) (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBufferStorage (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); GLAPI void APIENTRY glClearTexImage (GLuint texture, GLint level, GLenum format, GLenum type, const void *data); GLAPI void APIENTRY glClearTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data); GLAPI void APIENTRY glBindBuffersBase (GLenum target, GLuint first, GLsizei count, const GLuint *buffers); GLAPI void APIENTRY glBindBuffersRange (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes); GLAPI void APIENTRY glBindTextures (GLuint first, GLsizei count, const GLuint *textures); GLAPI void APIENTRY glBindSamplers (GLuint first, GLsizei count, const GLuint *samplers); GLAPI void APIENTRY glBindImageTextures (GLuint first, GLsizei count, const GLuint *textures); GLAPI void APIENTRY glBindVertexBuffers (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); #endif #endif /* GL_VERSION_4_4 */ #ifndef GL_VERSION_4_5 #define GL_VERSION_4_5 1 #define GL_CONTEXT_LOST 0x0507 #define GL_NEGATIVE_ONE_TO_ONE 0x935E #define GL_ZERO_TO_ONE 0x935F #define GL_CLIP_ORIGIN 0x935C #define GL_CLIP_DEPTH_MODE 0x935D #define GL_QUERY_WAIT_INVERTED 0x8E17 #define GL_QUERY_NO_WAIT_INVERTED 0x8E18 #define GL_QUERY_BY_REGION_WAIT_INVERTED 0x8E19 #define GL_QUERY_BY_REGION_NO_WAIT_INVERTED 0x8E1A #define GL_MAX_CULL_DISTANCES 0x82F9 #define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES 0x82FA #define GL_TEXTURE_TARGET 0x1006 #define GL_QUERY_TARGET 0x82EA #define GL_GUILTY_CONTEXT_RESET 0x8253 #define GL_INNOCENT_CONTEXT_RESET 0x8254 #define GL_UNKNOWN_CONTEXT_RESET 0x8255 #define GL_RESET_NOTIFICATION_STRATEGY 0x8256 #define GL_LOSE_CONTEXT_ON_RESET 0x8252 #define GL_NO_RESET_NOTIFICATION 0x8261 #define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT 0x00000004 #define GL_COLOR_TABLE 0x80D0 #define GL_POST_CONVOLUTION_COLOR_TABLE 0x80D1 #define GL_POST_COLOR_MATRIX_COLOR_TABLE 0x80D2 #define GL_PROXY_COLOR_TABLE 0x80D3 #define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4 #define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5 #define GL_CONVOLUTION_1D 0x8010 #define GL_CONVOLUTION_2D 0x8011 #define GL_SEPARABLE_2D 0x8012 #define GL_HISTOGRAM 0x8024 #define GL_PROXY_HISTOGRAM 0x8025 #define GL_MINMAX 0x802E #define GL_CONTEXT_RELEASE_BEHAVIOR 0x82FB #define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82FC typedef void (APIENTRYP PFNGLCLIPCONTROLPROC) (GLenum origin, GLenum depth); typedef void (APIENTRYP PFNGLCREATETRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids); typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC) (GLuint xfb, GLuint index, GLuint buffer); typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC) (GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKIVPROC) (GLuint xfb, GLenum pname, GLint *param); typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint *param); typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI64_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint64 *param); typedef void (APIENTRYP PFNGLCREATEBUFFERSPROC) (GLsizei n, GLuint *buffers); typedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags); typedef void (APIENTRYP PFNGLNAMEDBUFFERDATAPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage); typedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); typedef void (APIENTRYP PFNGLCOPYNAMEDBUFFERSUBDATAPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERDATAPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERPROC) (GLuint buffer, GLenum access); typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERRANGEPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); typedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFERPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVPROC) (GLuint buffer, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERI64VPROC) (GLuint buffer, GLenum pname, GLint64 *params); typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVPROC) (GLuint buffer, GLenum pname, void **params); typedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data); typedef void (APIENTRYP PFNGLCREATEFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC) (GLuint framebuffer, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC) (GLuint framebuffer, GLenum buf); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC) (GLuint framebuffer, GLsizei n, const GLenum *bufs); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC) (GLuint framebuffer, GLenum src); typedef void (APIENTRYP PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC) (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments); typedef void (APIENTRYP PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC) (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERIVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint *value); typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint *value); typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat *value); typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFIPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); typedef void (APIENTRYP PFNGLBLITNAMEDFRAMEBUFFERPROC) (GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); typedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC) (GLuint framebuffer, GLenum target); typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC) (GLuint framebuffer, GLenum pname, GLint *param); typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLCREATERENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC) (GLuint renderbuffer, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLCREATETEXTURESPROC) (GLenum target, GLsizei n, GLuint *textures); typedef void (APIENTRYP PFNGLTEXTUREBUFFERPROC) (GLuint texture, GLenum internalformat, GLuint buffer); typedef void (APIENTRYP PFNGLTEXTUREBUFFERRANGEPROC) (GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (APIENTRYP PFNGLTEXTURESTORAGE1DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width); typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC) (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC) (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFPROC) (GLuint texture, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVPROC) (GLuint texture, GLenum pname, const GLfloat *param); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIPROC) (GLuint texture, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVPROC) (GLuint texture, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVPROC) (GLuint texture, GLenum pname, const GLuint *params); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVPROC) (GLuint texture, GLenum pname, const GLint *param); typedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPPROC) (GLuint texture); typedef void (APIENTRYP PFNGLBINDTEXTUREUNITPROC) (GLuint unit, GLuint texture); typedef void (APIENTRYP PFNGLGETTEXTUREIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels); typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC) (GLuint texture, GLint level, GLsizei bufSize, void *pixels); typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVPROC) (GLuint texture, GLint level, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVPROC) (GLuint texture, GLint level, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVPROC) (GLuint texture, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIIVPROC) (GLuint texture, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVPROC) (GLuint texture, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVPROC) (GLuint texture, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLCREATEVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYATTRIBPROC) (GLuint vaobj, GLuint index); typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYATTRIBPROC) (GLuint vaobj, GLuint index); typedef void (APIENTRYP PFNGLVERTEXARRAYELEMENTBUFFERPROC) (GLuint vaobj, GLuint buffer); typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBUFFERPROC) (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBUFFERSPROC) (GLuint vaobj, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBBINDINGPROC) (GLuint vaobj, GLuint attribindex, GLuint bindingindex); typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBIFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBLFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); typedef void (APIENTRYP PFNGLVERTEXARRAYBINDINGDIVISORPROC) (GLuint vaobj, GLuint bindingindex, GLuint divisor); typedef void (APIENTRYP PFNGLGETVERTEXARRAYIVPROC) (GLuint vaobj, GLenum pname, GLint *param); typedef void (APIENTRYP PFNGLGETVERTEXARRAYINDEXEDIVPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param); typedef void (APIENTRYP PFNGLGETVERTEXARRAYINDEXED64IVPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint64 *param); typedef void (APIENTRYP PFNGLCREATESAMPLERSPROC) (GLsizei n, GLuint *samplers); typedef void (APIENTRYP PFNGLCREATEPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines); typedef void (APIENTRYP PFNGLCREATEQUERIESPROC) (GLenum target, GLsizei n, GLuint *ids); typedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTI64VPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); typedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTIVPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); typedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTUI64VPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); typedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTUIVPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); typedef void (APIENTRYP PFNGLMEMORYBARRIERBYREGIONPROC) (GLbitfield barriers); typedef void (APIENTRYP PFNGLGETTEXTURESUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void *pixels); typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void *pixels); typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSPROC) (void); typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint lod, GLsizei bufSize, void *pixels); typedef void (APIENTRYP PFNGLGETNTEXIMAGEPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels); typedef void (APIENTRYP PFNGLGETNUNIFORMDVPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); typedef void (APIENTRYP PFNGLGETNUNIFORMFVPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); typedef void (APIENTRYP PFNGLGETNUNIFORMIVPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); typedef void (APIENTRYP PFNGLGETNUNIFORMUIVPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params); typedef void (APIENTRYP PFNGLREADNPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); typedef void (APIENTRYP PFNGLGETNMAPDVPROC) (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); typedef void (APIENTRYP PFNGLGETNMAPFVPROC) (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); typedef void (APIENTRYP PFNGLGETNMAPIVPROC) (GLenum target, GLenum query, GLsizei bufSize, GLint *v); typedef void (APIENTRYP PFNGLGETNPIXELMAPFVPROC) (GLenum map, GLsizei bufSize, GLfloat *values); typedef void (APIENTRYP PFNGLGETNPIXELMAPUIVPROC) (GLenum map, GLsizei bufSize, GLuint *values); typedef void (APIENTRYP PFNGLGETNPIXELMAPUSVPROC) (GLenum map, GLsizei bufSize, GLushort *values); typedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEPROC) (GLsizei bufSize, GLubyte *pattern); typedef void (APIENTRYP PFNGLGETNCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table); typedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image); typedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span); typedef void (APIENTRYP PFNGLGETNHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); typedef void (APIENTRYP PFNGLGETNMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); typedef void (APIENTRYP PFNGLTEXTUREBARRIERPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glClipControl (GLenum origin, GLenum depth); GLAPI void APIENTRY glCreateTransformFeedbacks (GLsizei n, GLuint *ids); GLAPI void APIENTRY glTransformFeedbackBufferBase (GLuint xfb, GLuint index, GLuint buffer); GLAPI void APIENTRY glTransformFeedbackBufferRange (GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); GLAPI void APIENTRY glGetTransformFeedbackiv (GLuint xfb, GLenum pname, GLint *param); GLAPI void APIENTRY glGetTransformFeedbacki_v (GLuint xfb, GLenum pname, GLuint index, GLint *param); GLAPI void APIENTRY glGetTransformFeedbacki64_v (GLuint xfb, GLenum pname, GLuint index, GLint64 *param); GLAPI void APIENTRY glCreateBuffers (GLsizei n, GLuint *buffers); GLAPI void APIENTRY glNamedBufferStorage (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags); GLAPI void APIENTRY glNamedBufferData (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage); GLAPI void APIENTRY glNamedBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); GLAPI void APIENTRY glCopyNamedBufferSubData (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); GLAPI void APIENTRY glClearNamedBufferData (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); GLAPI void APIENTRY glClearNamedBufferSubData (GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); GLAPI void *APIENTRY glMapNamedBuffer (GLuint buffer, GLenum access); GLAPI void *APIENTRY glMapNamedBufferRange (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); GLAPI GLboolean APIENTRY glUnmapNamedBuffer (GLuint buffer); GLAPI void APIENTRY glFlushMappedNamedBufferRange (GLuint buffer, GLintptr offset, GLsizeiptr length); GLAPI void APIENTRY glGetNamedBufferParameteriv (GLuint buffer, GLenum pname, GLint *params); GLAPI void APIENTRY glGetNamedBufferParameteri64v (GLuint buffer, GLenum pname, GLint64 *params); GLAPI void APIENTRY glGetNamedBufferPointerv (GLuint buffer, GLenum pname, void **params); GLAPI void APIENTRY glGetNamedBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data); GLAPI void APIENTRY glCreateFramebuffers (GLsizei n, GLuint *framebuffers); GLAPI void APIENTRY glNamedFramebufferRenderbuffer (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); GLAPI void APIENTRY glNamedFramebufferParameteri (GLuint framebuffer, GLenum pname, GLint param); GLAPI void APIENTRY glNamedFramebufferTexture (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); GLAPI void APIENTRY glNamedFramebufferTextureLayer (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); GLAPI void APIENTRY glNamedFramebufferDrawBuffer (GLuint framebuffer, GLenum buf); GLAPI void APIENTRY glNamedFramebufferDrawBuffers (GLuint framebuffer, GLsizei n, const GLenum *bufs); GLAPI void APIENTRY glNamedFramebufferReadBuffer (GLuint framebuffer, GLenum src); GLAPI void APIENTRY glInvalidateNamedFramebufferData (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments); GLAPI void APIENTRY glInvalidateNamedFramebufferSubData (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glClearNamedFramebufferiv (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint *value); GLAPI void APIENTRY glClearNamedFramebufferuiv (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint *value); GLAPI void APIENTRY glClearNamedFramebufferfv (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat *value); GLAPI void APIENTRY glClearNamedFramebufferfi (GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); GLAPI void APIENTRY glBlitNamedFramebuffer (GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); GLAPI GLenum APIENTRY glCheckNamedFramebufferStatus (GLuint framebuffer, GLenum target); GLAPI void APIENTRY glGetNamedFramebufferParameteriv (GLuint framebuffer, GLenum pname, GLint *param); GLAPI void APIENTRY glGetNamedFramebufferAttachmentParameteriv (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); GLAPI void APIENTRY glCreateRenderbuffers (GLsizei n, GLuint *renderbuffers); GLAPI void APIENTRY glNamedRenderbufferStorage (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); GLAPI void APIENTRY glNamedRenderbufferStorageMultisample (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); GLAPI void APIENTRY glGetNamedRenderbufferParameteriv (GLuint renderbuffer, GLenum pname, GLint *params); GLAPI void APIENTRY glCreateTextures (GLenum target, GLsizei n, GLuint *textures); GLAPI void APIENTRY glTextureBuffer (GLuint texture, GLenum internalformat, GLuint buffer); GLAPI void APIENTRY glTextureBufferRange (GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); GLAPI void APIENTRY glTextureStorage1D (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width); GLAPI void APIENTRY glTextureStorage2D (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); GLAPI void APIENTRY glTextureStorage3D (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); GLAPI void APIENTRY glTextureStorage2DMultisample (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); GLAPI void APIENTRY glTextureStorage3DMultisample (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); GLAPI void APIENTRY glTextureSubImage1D (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glTextureSubImage2D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glTextureSubImage3D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glCompressedTextureSubImage1D (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); GLAPI void APIENTRY glCompressedTextureSubImage2D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); GLAPI void APIENTRY glCompressedTextureSubImage3D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); GLAPI void APIENTRY glCopyTextureSubImage1D (GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); GLAPI void APIENTRY glCopyTextureSubImage2D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glCopyTextureSubImage3D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glTextureParameterf (GLuint texture, GLenum pname, GLfloat param); GLAPI void APIENTRY glTextureParameterfv (GLuint texture, GLenum pname, const GLfloat *param); GLAPI void APIENTRY glTextureParameteri (GLuint texture, GLenum pname, GLint param); GLAPI void APIENTRY glTextureParameterIiv (GLuint texture, GLenum pname, const GLint *params); GLAPI void APIENTRY glTextureParameterIuiv (GLuint texture, GLenum pname, const GLuint *params); GLAPI void APIENTRY glTextureParameteriv (GLuint texture, GLenum pname, const GLint *param); GLAPI void APIENTRY glGenerateTextureMipmap (GLuint texture); GLAPI void APIENTRY glBindTextureUnit (GLuint unit, GLuint texture); GLAPI void APIENTRY glGetTextureImage (GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels); GLAPI void APIENTRY glGetCompressedTextureImage (GLuint texture, GLint level, GLsizei bufSize, void *pixels); GLAPI void APIENTRY glGetTextureLevelParameterfv (GLuint texture, GLint level, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetTextureLevelParameteriv (GLuint texture, GLint level, GLenum pname, GLint *params); GLAPI void APIENTRY glGetTextureParameterfv (GLuint texture, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetTextureParameterIiv (GLuint texture, GLenum pname, GLint *params); GLAPI void APIENTRY glGetTextureParameterIuiv (GLuint texture, GLenum pname, GLuint *params); GLAPI void APIENTRY glGetTextureParameteriv (GLuint texture, GLenum pname, GLint *params); GLAPI void APIENTRY glCreateVertexArrays (GLsizei n, GLuint *arrays); GLAPI void APIENTRY glDisableVertexArrayAttrib (GLuint vaobj, GLuint index); GLAPI void APIENTRY glEnableVertexArrayAttrib (GLuint vaobj, GLuint index); GLAPI void APIENTRY glVertexArrayElementBuffer (GLuint vaobj, GLuint buffer); GLAPI void APIENTRY glVertexArrayVertexBuffer (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); GLAPI void APIENTRY glVertexArrayVertexBuffers (GLuint vaobj, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); GLAPI void APIENTRY glVertexArrayAttribBinding (GLuint vaobj, GLuint attribindex, GLuint bindingindex); GLAPI void APIENTRY glVertexArrayAttribFormat (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); GLAPI void APIENTRY glVertexArrayAttribIFormat (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); GLAPI void APIENTRY glVertexArrayAttribLFormat (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); GLAPI void APIENTRY glVertexArrayBindingDivisor (GLuint vaobj, GLuint bindingindex, GLuint divisor); GLAPI void APIENTRY glGetVertexArrayiv (GLuint vaobj, GLenum pname, GLint *param); GLAPI void APIENTRY glGetVertexArrayIndexediv (GLuint vaobj, GLuint index, GLenum pname, GLint *param); GLAPI void APIENTRY glGetVertexArrayIndexed64iv (GLuint vaobj, GLuint index, GLenum pname, GLint64 *param); GLAPI void APIENTRY glCreateSamplers (GLsizei n, GLuint *samplers); GLAPI void APIENTRY glCreateProgramPipelines (GLsizei n, GLuint *pipelines); GLAPI void APIENTRY glCreateQueries (GLenum target, GLsizei n, GLuint *ids); GLAPI void APIENTRY glGetQueryBufferObjecti64v (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); GLAPI void APIENTRY glGetQueryBufferObjectiv (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); GLAPI void APIENTRY glGetQueryBufferObjectui64v (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); GLAPI void APIENTRY glGetQueryBufferObjectuiv (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); GLAPI void APIENTRY glMemoryBarrierByRegion (GLbitfield barriers); GLAPI void APIENTRY glGetTextureSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void *pixels); GLAPI void APIENTRY glGetCompressedTextureSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void *pixels); GLAPI GLenum APIENTRY glGetGraphicsResetStatus (void); GLAPI void APIENTRY glGetnCompressedTexImage (GLenum target, GLint lod, GLsizei bufSize, void *pixels); GLAPI void APIENTRY glGetnTexImage (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels); GLAPI void APIENTRY glGetnUniformdv (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); GLAPI void APIENTRY glGetnUniformfv (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); GLAPI void APIENTRY glGetnUniformiv (GLuint program, GLint location, GLsizei bufSize, GLint *params); GLAPI void APIENTRY glGetnUniformuiv (GLuint program, GLint location, GLsizei bufSize, GLuint *params); GLAPI void APIENTRY glReadnPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); GLAPI void APIENTRY glGetnMapdv (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); GLAPI void APIENTRY glGetnMapfv (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); GLAPI void APIENTRY glGetnMapiv (GLenum target, GLenum query, GLsizei bufSize, GLint *v); GLAPI void APIENTRY glGetnPixelMapfv (GLenum map, GLsizei bufSize, GLfloat *values); GLAPI void APIENTRY glGetnPixelMapuiv (GLenum map, GLsizei bufSize, GLuint *values); GLAPI void APIENTRY glGetnPixelMapusv (GLenum map, GLsizei bufSize, GLushort *values); GLAPI void APIENTRY glGetnPolygonStipple (GLsizei bufSize, GLubyte *pattern); GLAPI void APIENTRY glGetnColorTable (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table); GLAPI void APIENTRY glGetnConvolutionFilter (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image); GLAPI void APIENTRY glGetnSeparableFilter (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span); GLAPI void APIENTRY glGetnHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); GLAPI void APIENTRY glGetnMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); GLAPI void APIENTRY glTextureBarrier (void); #endif #endif /* GL_VERSION_4_5 */ #ifndef GL_VERSION_4_6 #define GL_VERSION_4_6 1 #define GL_SHADER_BINARY_FORMAT_SPIR_V 0x9551 #define GL_SPIR_V_BINARY 0x9552 #define GL_PARAMETER_BUFFER 0x80EE #define GL_PARAMETER_BUFFER_BINDING 0x80EF #define GL_CONTEXT_FLAG_NO_ERROR_BIT 0x00000008 #define GL_VERTICES_SUBMITTED 0x82EE #define GL_PRIMITIVES_SUBMITTED 0x82EF #define GL_VERTEX_SHADER_INVOCATIONS 0x82F0 #define GL_TESS_CONTROL_SHADER_PATCHES 0x82F1 #define GL_TESS_EVALUATION_SHADER_INVOCATIONS 0x82F2 #define GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED 0x82F3 #define GL_FRAGMENT_SHADER_INVOCATIONS 0x82F4 #define GL_COMPUTE_SHADER_INVOCATIONS 0x82F5 #define GL_CLIPPING_INPUT_PRIMITIVES 0x82F6 #define GL_CLIPPING_OUTPUT_PRIMITIVES 0x82F7 #define GL_POLYGON_OFFSET_CLAMP 0x8E1B #define GL_SPIR_V_EXTENSIONS 0x9553 #define GL_NUM_SPIR_V_EXTENSIONS 0x9554 #define GL_TEXTURE_MAX_ANISOTROPY 0x84FE #define GL_MAX_TEXTURE_MAX_ANISOTROPY 0x84FF #define GL_TRANSFORM_FEEDBACK_OVERFLOW 0x82EC #define GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW 0x82ED typedef void (APIENTRYP PFNGLSPECIALIZESHADERPROC) (GLuint shader, const GLchar *pEntryPoint, GLuint numSpecializationConstants, const GLuint *pConstantIndex, const GLuint *pConstantValue); typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC) (GLenum mode, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC) (GLenum mode, GLenum type, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); typedef void (APIENTRYP PFNGLPOLYGONOFFSETCLAMPPROC) (GLfloat factor, GLfloat units, GLfloat clamp); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSpecializeShader (GLuint shader, const GLchar *pEntryPoint, GLuint numSpecializationConstants, const GLuint *pConstantIndex, const GLuint *pConstantValue); GLAPI void APIENTRY glMultiDrawArraysIndirectCount (GLenum mode, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); GLAPI void APIENTRY glMultiDrawElementsIndirectCount (GLenum mode, GLenum type, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); GLAPI void APIENTRY glPolygonOffsetClamp (GLfloat factor, GLfloat units, GLfloat clamp); #endif #endif /* GL_VERSION_4_6 */ #ifndef GL_ARB_ES2_compatibility #define GL_ARB_ES2_compatibility 1 #endif /* GL_ARB_ES2_compatibility */ #ifndef GL_ARB_ES3_1_compatibility #define GL_ARB_ES3_1_compatibility 1 #endif /* GL_ARB_ES3_1_compatibility */ #ifndef GL_ARB_ES3_2_compatibility #define GL_ARB_ES3_2_compatibility 1 #define GL_PRIMITIVE_BOUNDING_BOX_ARB 0x92BE #define GL_MULTISAMPLE_LINE_WIDTH_RANGE_ARB 0x9381 #define GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY_ARB 0x9382 typedef void (APIENTRYP PFNGLPRIMITIVEBOUNDINGBOXARBPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPrimitiveBoundingBoxARB (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW); #endif #endif /* GL_ARB_ES3_2_compatibility */ #ifndef GL_ARB_ES3_compatibility #define GL_ARB_ES3_compatibility 1 #endif /* GL_ARB_ES3_compatibility */ #ifndef GL_ARB_arrays_of_arrays #define GL_ARB_arrays_of_arrays 1 #endif /* GL_ARB_arrays_of_arrays */ #ifndef GL_ARB_base_instance #define GL_ARB_base_instance 1 #endif /* GL_ARB_base_instance */ #ifndef GL_ARB_bindless_texture #define GL_ARB_bindless_texture 1 typedef khronos_uint64_t GLuint64EXT; #define GL_UNSIGNED_INT64_ARB 0x140F typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLEARBPROC) (GLuint texture); typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLEARBPROC) (GLuint texture, GLuint sampler); typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle); typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC) (GLuint64 handle); typedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLEARBPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle, GLenum access); typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC) (GLuint64 handle); typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64ARBPROC) (GLint location, GLuint64 value); typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC) (GLuint program, GLint location, GLuint64 value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values); typedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle); typedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle); typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64ARBPROC) (GLuint index, GLuint64EXT x); typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VARBPROC) (GLuint index, const GLuint64EXT *v); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VARBPROC) (GLuint index, GLenum pname, GLuint64EXT *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI GLuint64 APIENTRY glGetTextureHandleARB (GLuint texture); GLAPI GLuint64 APIENTRY glGetTextureSamplerHandleARB (GLuint texture, GLuint sampler); GLAPI void APIENTRY glMakeTextureHandleResidentARB (GLuint64 handle); GLAPI void APIENTRY glMakeTextureHandleNonResidentARB (GLuint64 handle); GLAPI GLuint64 APIENTRY glGetImageHandleARB (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); GLAPI void APIENTRY glMakeImageHandleResidentARB (GLuint64 handle, GLenum access); GLAPI void APIENTRY glMakeImageHandleNonResidentARB (GLuint64 handle); GLAPI void APIENTRY glUniformHandleui64ARB (GLint location, GLuint64 value); GLAPI void APIENTRY glUniformHandleui64vARB (GLint location, GLsizei count, const GLuint64 *value); GLAPI void APIENTRY glProgramUniformHandleui64ARB (GLuint program, GLint location, GLuint64 value); GLAPI void APIENTRY glProgramUniformHandleui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *values); GLAPI GLboolean APIENTRY glIsTextureHandleResidentARB (GLuint64 handle); GLAPI GLboolean APIENTRY glIsImageHandleResidentARB (GLuint64 handle); GLAPI void APIENTRY glVertexAttribL1ui64ARB (GLuint index, GLuint64EXT x); GLAPI void APIENTRY glVertexAttribL1ui64vARB (GLuint index, const GLuint64EXT *v); GLAPI void APIENTRY glGetVertexAttribLui64vARB (GLuint index, GLenum pname, GLuint64EXT *params); #endif #endif /* GL_ARB_bindless_texture */ #ifndef GL_ARB_blend_func_extended #define GL_ARB_blend_func_extended 1 #endif /* GL_ARB_blend_func_extended */ #ifndef GL_ARB_buffer_storage #define GL_ARB_buffer_storage 1 #endif /* GL_ARB_buffer_storage */ #ifndef GL_ARB_cl_event #define GL_ARB_cl_event 1 struct _cl_context; struct _cl_event; #define GL_SYNC_CL_EVENT_ARB 0x8240 #define GL_SYNC_CL_EVENT_COMPLETE_ARB 0x8241 typedef GLsync (APIENTRYP PFNGLCREATESYNCFROMCLEVENTARBPROC) (struct _cl_context *context, struct _cl_event *event, GLbitfield flags); #ifdef GL_GLEXT_PROTOTYPES GLAPI GLsync APIENTRY glCreateSyncFromCLeventARB (struct _cl_context *context, struct _cl_event *event, GLbitfield flags); #endif #endif /* GL_ARB_cl_event */ #ifndef GL_ARB_clear_buffer_object #define GL_ARB_clear_buffer_object 1 #endif /* GL_ARB_clear_buffer_object */ #ifndef GL_ARB_clear_texture #define GL_ARB_clear_texture 1 #endif /* GL_ARB_clear_texture */ #ifndef GL_ARB_clip_control #define GL_ARB_clip_control 1 #endif /* GL_ARB_clip_control */ #ifndef GL_ARB_color_buffer_float #define GL_ARB_color_buffer_float 1 #define GL_RGBA_FLOAT_MODE_ARB 0x8820 #define GL_CLAMP_VERTEX_COLOR_ARB 0x891A #define GL_CLAMP_FRAGMENT_COLOR_ARB 0x891B #define GL_CLAMP_READ_COLOR_ARB 0x891C #define GL_FIXED_ONLY_ARB 0x891D typedef void (APIENTRYP PFNGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glClampColorARB (GLenum target, GLenum clamp); #endif #endif /* GL_ARB_color_buffer_float */ #ifndef GL_ARB_compatibility #define GL_ARB_compatibility 1 #endif /* GL_ARB_compatibility */ #ifndef GL_ARB_compressed_texture_pixel_storage #define GL_ARB_compressed_texture_pixel_storage 1 #endif /* GL_ARB_compressed_texture_pixel_storage */ #ifndef GL_ARB_compute_shader #define GL_ARB_compute_shader 1 #endif /* GL_ARB_compute_shader */ #ifndef GL_ARB_compute_variable_group_size #define GL_ARB_compute_variable_group_size 1 #define GL_MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB 0x9344 #define GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS_ARB 0x90EB #define GL_MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB 0x9345 #define GL_MAX_COMPUTE_FIXED_GROUP_SIZE_ARB 0x91BF typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDispatchComputeGroupSizeARB (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z); #endif #endif /* GL_ARB_compute_variable_group_size */ #ifndef GL_ARB_conditional_render_inverted #define GL_ARB_conditional_render_inverted 1 #endif /* GL_ARB_conditional_render_inverted */ #ifndef GL_ARB_conservative_depth #define GL_ARB_conservative_depth 1 #endif /* GL_ARB_conservative_depth */ #ifndef GL_ARB_copy_buffer #define GL_ARB_copy_buffer 1 #endif /* GL_ARB_copy_buffer */ #ifndef GL_ARB_copy_image #define GL_ARB_copy_image 1 #endif /* GL_ARB_copy_image */ #ifndef GL_ARB_cull_distance #define GL_ARB_cull_distance 1 #endif /* GL_ARB_cull_distance */ #ifndef GL_ARB_debug_output #define GL_ARB_debug_output 1 typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); #define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 #define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 #define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 #define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 #define GL_DEBUG_SOURCE_API_ARB 0x8246 #define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247 #define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248 #define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 #define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A #define GL_DEBUG_SOURCE_OTHER_ARB 0x824B #define GL_DEBUG_TYPE_ERROR_ARB 0x824C #define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D #define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E #define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F #define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 #define GL_DEBUG_TYPE_OTHER_ARB 0x8251 #define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 #define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 #define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145 #define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146 #define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 #define GL_DEBUG_SEVERITY_LOW_ARB 0x9148 typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC) (GLDEBUGPROCARB callback, const void *userParam); typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDebugMessageControlARB (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); GLAPI void APIENTRY glDebugMessageInsertARB (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); GLAPI void APIENTRY glDebugMessageCallbackARB (GLDEBUGPROCARB callback, const void *userParam); GLAPI GLuint APIENTRY glGetDebugMessageLogARB (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); #endif #endif /* GL_ARB_debug_output */ #ifndef GL_ARB_depth_buffer_float #define GL_ARB_depth_buffer_float 1 #endif /* GL_ARB_depth_buffer_float */ #ifndef GL_ARB_depth_clamp #define GL_ARB_depth_clamp 1 #endif /* GL_ARB_depth_clamp */ #ifndef GL_ARB_depth_texture #define GL_ARB_depth_texture 1 #define GL_DEPTH_COMPONENT16_ARB 0x81A5 #define GL_DEPTH_COMPONENT24_ARB 0x81A6 #define GL_DEPTH_COMPONENT32_ARB 0x81A7 #define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A #define GL_DEPTH_TEXTURE_MODE_ARB 0x884B #endif /* GL_ARB_depth_texture */ #ifndef GL_ARB_derivative_control #define GL_ARB_derivative_control 1 #endif /* GL_ARB_derivative_control */ #ifndef GL_ARB_direct_state_access #define GL_ARB_direct_state_access 1 #endif /* GL_ARB_direct_state_access */ #ifndef GL_ARB_draw_buffers #define GL_ARB_draw_buffers 1 #define GL_MAX_DRAW_BUFFERS_ARB 0x8824 #define GL_DRAW_BUFFER0_ARB 0x8825 #define GL_DRAW_BUFFER1_ARB 0x8826 #define GL_DRAW_BUFFER2_ARB 0x8827 #define GL_DRAW_BUFFER3_ARB 0x8828 #define GL_DRAW_BUFFER4_ARB 0x8829 #define GL_DRAW_BUFFER5_ARB 0x882A #define GL_DRAW_BUFFER6_ARB 0x882B #define GL_DRAW_BUFFER7_ARB 0x882C #define GL_DRAW_BUFFER8_ARB 0x882D #define GL_DRAW_BUFFER9_ARB 0x882E #define GL_DRAW_BUFFER10_ARB 0x882F #define GL_DRAW_BUFFER11_ARB 0x8830 #define GL_DRAW_BUFFER12_ARB 0x8831 #define GL_DRAW_BUFFER13_ARB 0x8832 #define GL_DRAW_BUFFER14_ARB 0x8833 #define GL_DRAW_BUFFER15_ARB 0x8834 typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawBuffersARB (GLsizei n, const GLenum *bufs); #endif #endif /* GL_ARB_draw_buffers */ #ifndef GL_ARB_draw_buffers_blend #define GL_ARB_draw_buffers_blend 1 typedef void (APIENTRYP PFNGLBLENDEQUATIONIARBPROC) (GLuint buf, GLenum mode); typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIARBPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); typedef void (APIENTRYP PFNGLBLENDFUNCIARBPROC) (GLuint buf, GLenum src, GLenum dst); typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIARBPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendEquationiARB (GLuint buf, GLenum mode); GLAPI void APIENTRY glBlendEquationSeparateiARB (GLuint buf, GLenum modeRGB, GLenum modeAlpha); GLAPI void APIENTRY glBlendFunciARB (GLuint buf, GLenum src, GLenum dst); GLAPI void APIENTRY glBlendFuncSeparateiARB (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); #endif #endif /* GL_ARB_draw_buffers_blend */ #ifndef GL_ARB_draw_elements_base_vertex #define GL_ARB_draw_elements_base_vertex 1 #endif /* GL_ARB_draw_elements_base_vertex */ #ifndef GL_ARB_draw_indirect #define GL_ARB_draw_indirect 1 #endif /* GL_ARB_draw_indirect */ #ifndef GL_ARB_draw_instanced #define GL_ARB_draw_instanced 1 typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDARBPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount); typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDARBPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawArraysInstancedARB (GLenum mode, GLint first, GLsizei count, GLsizei primcount); GLAPI void APIENTRY glDrawElementsInstancedARB (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); #endif #endif /* GL_ARB_draw_instanced */ #ifndef GL_ARB_enhanced_layouts #define GL_ARB_enhanced_layouts 1 #endif /* GL_ARB_enhanced_layouts */ #ifndef GL_ARB_explicit_attrib_location #define GL_ARB_explicit_attrib_location 1 #endif /* GL_ARB_explicit_attrib_location */ #ifndef GL_ARB_explicit_uniform_location #define GL_ARB_explicit_uniform_location 1 #endif /* GL_ARB_explicit_uniform_location */ #ifndef GL_ARB_fragment_coord_conventions #define GL_ARB_fragment_coord_conventions 1 #endif /* GL_ARB_fragment_coord_conventions */ #ifndef GL_ARB_fragment_layer_viewport #define GL_ARB_fragment_layer_viewport 1 #endif /* GL_ARB_fragment_layer_viewport */ #ifndef GL_ARB_fragment_program #define GL_ARB_fragment_program 1 #define GL_FRAGMENT_PROGRAM_ARB 0x8804 #define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 #define GL_PROGRAM_LENGTH_ARB 0x8627 #define GL_PROGRAM_FORMAT_ARB 0x8876 #define GL_PROGRAM_BINDING_ARB 0x8677 #define GL_PROGRAM_INSTRUCTIONS_ARB 0x88A0 #define GL_MAX_PROGRAM_INSTRUCTIONS_ARB 0x88A1 #define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2 #define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3 #define GL_PROGRAM_TEMPORARIES_ARB 0x88A4 #define GL_MAX_PROGRAM_TEMPORARIES_ARB 0x88A5 #define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6 #define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7 #define GL_PROGRAM_PARAMETERS_ARB 0x88A8 #define GL_MAX_PROGRAM_PARAMETERS_ARB 0x88A9 #define GL_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AA #define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB #define GL_PROGRAM_ATTRIBS_ARB 0x88AC #define GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD #define GL_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AE #define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF #define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4 #define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5 #define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6 #define GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805 #define GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806 #define GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807 #define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808 #define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809 #define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A #define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B #define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C #define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D #define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E #define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F #define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810 #define GL_PROGRAM_STRING_ARB 0x8628 #define GL_PROGRAM_ERROR_POSITION_ARB 0x864B #define GL_CURRENT_MATRIX_ARB 0x8641 #define GL_TRANSPOSE_CURRENT_MATRIX_ARB 0x88B7 #define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640 #define GL_MAX_PROGRAM_MATRICES_ARB 0x862F #define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E #define GL_MAX_TEXTURE_COORDS_ARB 0x8871 #define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872 #define GL_PROGRAM_ERROR_STRING_ARB 0x8874 #define GL_MATRIX0_ARB 0x88C0 #define GL_MATRIX1_ARB 0x88C1 #define GL_MATRIX2_ARB 0x88C2 #define GL_MATRIX3_ARB 0x88C3 #define GL_MATRIX4_ARB 0x88C4 #define GL_MATRIX5_ARB 0x88C5 #define GL_MATRIX6_ARB 0x88C6 #define GL_MATRIX7_ARB 0x88C7 #define GL_MATRIX8_ARB 0x88C8 #define GL_MATRIX9_ARB 0x88C9 #define GL_MATRIX10_ARB 0x88CA #define GL_MATRIX11_ARB 0x88CB #define GL_MATRIX12_ARB 0x88CC #define GL_MATRIX13_ARB 0x88CD #define GL_MATRIX14_ARB 0x88CE #define GL_MATRIX15_ARB 0x88CF #define GL_MATRIX16_ARB 0x88D0 #define GL_MATRIX17_ARB 0x88D1 #define GL_MATRIX18_ARB 0x88D2 #define GL_MATRIX19_ARB 0x88D3 #define GL_MATRIX20_ARB 0x88D4 #define GL_MATRIX21_ARB 0x88D5 #define GL_MATRIX22_ARB 0x88D6 #define GL_MATRIX23_ARB 0x88D7 #define GL_MATRIX24_ARB 0x88D8 #define GL_MATRIX25_ARB 0x88D9 #define GL_MATRIX26_ARB 0x88DA #define GL_MATRIX27_ARB 0x88DB #define GL_MATRIX28_ARB 0x88DC #define GL_MATRIX29_ARB 0x88DD #define GL_MATRIX30_ARB 0x88DE #define GL_MATRIX31_ARB 0x88DF typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const void *string); typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program); typedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs); typedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, void *string); typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramStringARB (GLenum target, GLenum format, GLsizei len, const void *string); GLAPI void APIENTRY glBindProgramARB (GLenum target, GLuint program); GLAPI void APIENTRY glDeleteProgramsARB (GLsizei n, const GLuint *programs); GLAPI void APIENTRY glGenProgramsARB (GLsizei n, GLuint *programs); GLAPI void APIENTRY glProgramEnvParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glProgramEnvParameter4dvARB (GLenum target, GLuint index, const GLdouble *params); GLAPI void APIENTRY glProgramEnvParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glProgramEnvParameter4fvARB (GLenum target, GLuint index, const GLfloat *params); GLAPI void APIENTRY glProgramLocalParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glProgramLocalParameter4dvARB (GLenum target, GLuint index, const GLdouble *params); GLAPI void APIENTRY glProgramLocalParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glProgramLocalParameter4fvARB (GLenum target, GLuint index, const GLfloat *params); GLAPI void APIENTRY glGetProgramEnvParameterdvARB (GLenum target, GLuint index, GLdouble *params); GLAPI void APIENTRY glGetProgramEnvParameterfvARB (GLenum target, GLuint index, GLfloat *params); GLAPI void APIENTRY glGetProgramLocalParameterdvARB (GLenum target, GLuint index, GLdouble *params); GLAPI void APIENTRY glGetProgramLocalParameterfvARB (GLenum target, GLuint index, GLfloat *params); GLAPI void APIENTRY glGetProgramivARB (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetProgramStringARB (GLenum target, GLenum pname, void *string); GLAPI GLboolean APIENTRY glIsProgramARB (GLuint program); #endif #endif /* GL_ARB_fragment_program */ #ifndef GL_ARB_fragment_program_shadow #define GL_ARB_fragment_program_shadow 1 #endif /* GL_ARB_fragment_program_shadow */ #ifndef GL_ARB_fragment_shader #define GL_ARB_fragment_shader 1 #define GL_FRAGMENT_SHADER_ARB 0x8B30 #define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49 #define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B #endif /* GL_ARB_fragment_shader */ #ifndef GL_ARB_fragment_shader_interlock #define GL_ARB_fragment_shader_interlock 1 #endif /* GL_ARB_fragment_shader_interlock */ #ifndef GL_ARB_framebuffer_no_attachments #define GL_ARB_framebuffer_no_attachments 1 #endif /* GL_ARB_framebuffer_no_attachments */ #ifndef GL_ARB_framebuffer_object #define GL_ARB_framebuffer_object 1 #endif /* GL_ARB_framebuffer_object */ #ifndef GL_ARB_framebuffer_sRGB #define GL_ARB_framebuffer_sRGB 1 #endif /* GL_ARB_framebuffer_sRGB */ #ifndef GL_ARB_geometry_shader4 #define GL_ARB_geometry_shader4 1 #define GL_LINES_ADJACENCY_ARB 0x000A #define GL_LINE_STRIP_ADJACENCY_ARB 0x000B #define GL_TRIANGLES_ADJACENCY_ARB 0x000C #define GL_TRIANGLE_STRIP_ADJACENCY_ARB 0x000D #define GL_PROGRAM_POINT_SIZE_ARB 0x8642 #define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB 0x8C29 #define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB 0x8DA8 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9 #define GL_GEOMETRY_SHADER_ARB 0x8DD9 #define GL_GEOMETRY_VERTICES_OUT_ARB 0x8DDA #define GL_GEOMETRY_INPUT_TYPE_ARB 0x8DDB #define GL_GEOMETRY_OUTPUT_TYPE_ARB 0x8DDC #define GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB 0x8DDD #define GL_MAX_VERTEX_VARYING_COMPONENTS_ARB 0x8DDE #define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF #define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0 #define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1 typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIARBPROC) (GLuint program, GLenum pname, GLint value); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramParameteriARB (GLuint program, GLenum pname, GLint value); GLAPI void APIENTRY glFramebufferTextureARB (GLenum target, GLenum attachment, GLuint texture, GLint level); GLAPI void APIENTRY glFramebufferTextureLayerARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); GLAPI void APIENTRY glFramebufferTextureFaceARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); #endif #endif /* GL_ARB_geometry_shader4 */ #ifndef GL_ARB_get_program_binary #define GL_ARB_get_program_binary 1 #endif /* GL_ARB_get_program_binary */ #ifndef GL_ARB_get_texture_sub_image #define GL_ARB_get_texture_sub_image 1 #endif /* GL_ARB_get_texture_sub_image */ #ifndef GL_ARB_gl_spirv #define GL_ARB_gl_spirv 1 #define GL_SHADER_BINARY_FORMAT_SPIR_V_ARB 0x9551 #define GL_SPIR_V_BINARY_ARB 0x9552 typedef void (APIENTRYP PFNGLSPECIALIZESHADERARBPROC) (GLuint shader, const GLchar *pEntryPoint, GLuint numSpecializationConstants, const GLuint *pConstantIndex, const GLuint *pConstantValue); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSpecializeShaderARB (GLuint shader, const GLchar *pEntryPoint, GLuint numSpecializationConstants, const GLuint *pConstantIndex, const GLuint *pConstantValue); #endif #endif /* GL_ARB_gl_spirv */ #ifndef GL_ARB_gpu_shader5 #define GL_ARB_gpu_shader5 1 #endif /* GL_ARB_gpu_shader5 */ #ifndef GL_ARB_gpu_shader_fp64 #define GL_ARB_gpu_shader_fp64 1 #endif /* GL_ARB_gpu_shader_fp64 */ #ifndef GL_ARB_gpu_shader_int64 #define GL_ARB_gpu_shader_int64 1 #define GL_INT64_ARB 0x140E #define GL_INT64_VEC2_ARB 0x8FE9 #define GL_INT64_VEC3_ARB 0x8FEA #define GL_INT64_VEC4_ARB 0x8FEB #define GL_UNSIGNED_INT64_VEC2_ARB 0x8FF5 #define GL_UNSIGNED_INT64_VEC3_ARB 0x8FF6 #define GL_UNSIGNED_INT64_VEC4_ARB 0x8FF7 typedef void (APIENTRYP PFNGLUNIFORM1I64ARBPROC) (GLint location, GLint64 x); typedef void (APIENTRYP PFNGLUNIFORM2I64ARBPROC) (GLint location, GLint64 x, GLint64 y); typedef void (APIENTRYP PFNGLUNIFORM3I64ARBPROC) (GLint location, GLint64 x, GLint64 y, GLint64 z); typedef void (APIENTRYP PFNGLUNIFORM4I64ARBPROC) (GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w); typedef void (APIENTRYP PFNGLUNIFORM1I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value); typedef void (APIENTRYP PFNGLUNIFORM2I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value); typedef void (APIENTRYP PFNGLUNIFORM3I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value); typedef void (APIENTRYP PFNGLUNIFORM4I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value); typedef void (APIENTRYP PFNGLUNIFORM1UI64ARBPROC) (GLint location, GLuint64 x); typedef void (APIENTRYP PFNGLUNIFORM2UI64ARBPROC) (GLint location, GLuint64 x, GLuint64 y); typedef void (APIENTRYP PFNGLUNIFORM3UI64ARBPROC) (GLint location, GLuint64 x, GLuint64 y, GLuint64 z); typedef void (APIENTRYP PFNGLUNIFORM4UI64ARBPROC) (GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w); typedef void (APIENTRYP PFNGLUNIFORM1UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value); typedef void (APIENTRYP PFNGLUNIFORM2UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value); typedef void (APIENTRYP PFNGLUNIFORM3UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value); typedef void (APIENTRYP PFNGLUNIFORM4UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value); typedef void (APIENTRYP PFNGLGETUNIFORMI64VARBPROC) (GLuint program, GLint location, GLint64 *params); typedef void (APIENTRYP PFNGLGETUNIFORMUI64VARBPROC) (GLuint program, GLint location, GLuint64 *params); typedef void (APIENTRYP PFNGLGETNUNIFORMI64VARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint64 *params); typedef void (APIENTRYP PFNGLGETNUNIFORMUI64VARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint64 *params); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64ARBPROC) (GLuint program, GLint location, GLint64 x); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64ARBPROC) (GLuint program, GLint location, GLint64 x, GLint64 y); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64ARBPROC) (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64ARBPROC) (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64ARBPROC) (GLuint program, GLint location, GLuint64 x); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64ARBPROC) (GLuint program, GLint location, GLuint64 x, GLuint64 y); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64ARBPROC) (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64ARBPROC) (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glUniform1i64ARB (GLint location, GLint64 x); GLAPI void APIENTRY glUniform2i64ARB (GLint location, GLint64 x, GLint64 y); GLAPI void APIENTRY glUniform3i64ARB (GLint location, GLint64 x, GLint64 y, GLint64 z); GLAPI void APIENTRY glUniform4i64ARB (GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w); GLAPI void APIENTRY glUniform1i64vARB (GLint location, GLsizei count, const GLint64 *value); GLAPI void APIENTRY glUniform2i64vARB (GLint location, GLsizei count, const GLint64 *value); GLAPI void APIENTRY glUniform3i64vARB (GLint location, GLsizei count, const GLint64 *value); GLAPI void APIENTRY glUniform4i64vARB (GLint location, GLsizei count, const GLint64 *value); GLAPI void APIENTRY glUniform1ui64ARB (GLint location, GLuint64 x); GLAPI void APIENTRY glUniform2ui64ARB (GLint location, GLuint64 x, GLuint64 y); GLAPI void APIENTRY glUniform3ui64ARB (GLint location, GLuint64 x, GLuint64 y, GLuint64 z); GLAPI void APIENTRY glUniform4ui64ARB (GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w); GLAPI void APIENTRY glUniform1ui64vARB (GLint location, GLsizei count, const GLuint64 *value); GLAPI void APIENTRY glUniform2ui64vARB (GLint location, GLsizei count, const GLuint64 *value); GLAPI void APIENTRY glUniform3ui64vARB (GLint location, GLsizei count, const GLuint64 *value); GLAPI void APIENTRY glUniform4ui64vARB (GLint location, GLsizei count, const GLuint64 *value); GLAPI void APIENTRY glGetUniformi64vARB (GLuint program, GLint location, GLint64 *params); GLAPI void APIENTRY glGetUniformui64vARB (GLuint program, GLint location, GLuint64 *params); GLAPI void APIENTRY glGetnUniformi64vARB (GLuint program, GLint location, GLsizei bufSize, GLint64 *params); GLAPI void APIENTRY glGetnUniformui64vARB (GLuint program, GLint location, GLsizei bufSize, GLuint64 *params); GLAPI void APIENTRY glProgramUniform1i64ARB (GLuint program, GLint location, GLint64 x); GLAPI void APIENTRY glProgramUniform2i64ARB (GLuint program, GLint location, GLint64 x, GLint64 y); GLAPI void APIENTRY glProgramUniform3i64ARB (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z); GLAPI void APIENTRY glProgramUniform4i64ARB (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w); GLAPI void APIENTRY glProgramUniform1i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value); GLAPI void APIENTRY glProgramUniform2i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value); GLAPI void APIENTRY glProgramUniform3i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value); GLAPI void APIENTRY glProgramUniform4i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value); GLAPI void APIENTRY glProgramUniform1ui64ARB (GLuint program, GLint location, GLuint64 x); GLAPI void APIENTRY glProgramUniform2ui64ARB (GLuint program, GLint location, GLuint64 x, GLuint64 y); GLAPI void APIENTRY glProgramUniform3ui64ARB (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z); GLAPI void APIENTRY glProgramUniform4ui64ARB (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w); GLAPI void APIENTRY glProgramUniform1ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value); GLAPI void APIENTRY glProgramUniform2ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value); GLAPI void APIENTRY glProgramUniform3ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value); GLAPI void APIENTRY glProgramUniform4ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value); #endif #endif /* GL_ARB_gpu_shader_int64 */ #ifndef GL_ARB_half_float_pixel #define GL_ARB_half_float_pixel 1 typedef khronos_uint16_t GLhalfARB; #define GL_HALF_FLOAT_ARB 0x140B #endif /* GL_ARB_half_float_pixel */ #ifndef GL_ARB_half_float_vertex #define GL_ARB_half_float_vertex 1 #endif /* GL_ARB_half_float_vertex */ #ifndef GL_ARB_imaging #define GL_ARB_imaging 1 #define GL_CONVOLUTION_BORDER_MODE 0x8013 #define GL_CONVOLUTION_FILTER_SCALE 0x8014 #define GL_CONVOLUTION_FILTER_BIAS 0x8015 #define GL_REDUCE 0x8016 #define GL_CONVOLUTION_FORMAT 0x8017 #define GL_CONVOLUTION_WIDTH 0x8018 #define GL_CONVOLUTION_HEIGHT 0x8019 #define GL_MAX_CONVOLUTION_WIDTH 0x801A #define GL_MAX_CONVOLUTION_HEIGHT 0x801B #define GL_POST_CONVOLUTION_RED_SCALE 0x801C #define GL_POST_CONVOLUTION_GREEN_SCALE 0x801D #define GL_POST_CONVOLUTION_BLUE_SCALE 0x801E #define GL_POST_CONVOLUTION_ALPHA_SCALE 0x801F #define GL_POST_CONVOLUTION_RED_BIAS 0x8020 #define GL_POST_CONVOLUTION_GREEN_BIAS 0x8021 #define GL_POST_CONVOLUTION_BLUE_BIAS 0x8022 #define GL_POST_CONVOLUTION_ALPHA_BIAS 0x8023 #define GL_HISTOGRAM_WIDTH 0x8026 #define GL_HISTOGRAM_FORMAT 0x8027 #define GL_HISTOGRAM_RED_SIZE 0x8028 #define GL_HISTOGRAM_GREEN_SIZE 0x8029 #define GL_HISTOGRAM_BLUE_SIZE 0x802A #define GL_HISTOGRAM_ALPHA_SIZE 0x802B #define GL_HISTOGRAM_LUMINANCE_SIZE 0x802C #define GL_HISTOGRAM_SINK 0x802D #define GL_MINMAX_FORMAT 0x802F #define GL_MINMAX_SINK 0x8030 #define GL_TABLE_TOO_LARGE 0x8031 #define GL_COLOR_MATRIX 0x80B1 #define GL_COLOR_MATRIX_STACK_DEPTH 0x80B2 #define GL_MAX_COLOR_MATRIX_STACK_DEPTH 0x80B3 #define GL_POST_COLOR_MATRIX_RED_SCALE 0x80B4 #define GL_POST_COLOR_MATRIX_GREEN_SCALE 0x80B5 #define GL_POST_COLOR_MATRIX_BLUE_SCALE 0x80B6 #define GL_POST_COLOR_MATRIX_ALPHA_SCALE 0x80B7 #define GL_POST_COLOR_MATRIX_RED_BIAS 0x80B8 #define GL_POST_COLOR_MATRIX_GREEN_BIAS 0x80B9 #define GL_POST_COLOR_MATRIX_BLUE_BIAS 0x80BA #define GL_POST_COLOR_MATRIX_ALPHA_BIAS 0x80BB #define GL_COLOR_TABLE_SCALE 0x80D6 #define GL_COLOR_TABLE_BIAS 0x80D7 #define GL_COLOR_TABLE_FORMAT 0x80D8 #define GL_COLOR_TABLE_WIDTH 0x80D9 #define GL_COLOR_TABLE_RED_SIZE 0x80DA #define GL_COLOR_TABLE_GREEN_SIZE 0x80DB #define GL_COLOR_TABLE_BLUE_SIZE 0x80DC #define GL_COLOR_TABLE_ALPHA_SIZE 0x80DD #define GL_COLOR_TABLE_LUMINANCE_SIZE 0x80DE #define GL_COLOR_TABLE_INTENSITY_SIZE 0x80DF #define GL_CONSTANT_BORDER 0x8151 #define GL_REPLICATE_BORDER 0x8153 #define GL_CONVOLUTION_BORDER_COLOR 0x8154 typedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table); typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, void *table); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data); typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image); typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, void *image); typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span); typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column); typedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); typedef void (APIENTRYP PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink); typedef void (APIENTRYP PFNGLRESETHISTOGRAMPROC) (GLenum target); typedef void (APIENTRYP PFNGLRESETMINMAXPROC) (GLenum target); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorTable (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table); GLAPI void APIENTRY glColorTableParameterfv (GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glColorTableParameteriv (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glCopyColorTable (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); GLAPI void APIENTRY glGetColorTable (GLenum target, GLenum format, GLenum type, void *table); GLAPI void APIENTRY glGetColorTableParameterfv (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetColorTableParameteriv (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glColorSubTable (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data); GLAPI void APIENTRY glCopyColorSubTable (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); GLAPI void APIENTRY glConvolutionFilter1D (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image); GLAPI void APIENTRY glConvolutionFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image); GLAPI void APIENTRY glConvolutionParameterf (GLenum target, GLenum pname, GLfloat params); GLAPI void APIENTRY glConvolutionParameterfv (GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glConvolutionParameteri (GLenum target, GLenum pname, GLint params); GLAPI void APIENTRY glConvolutionParameteriv (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glCopyConvolutionFilter1D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); GLAPI void APIENTRY glCopyConvolutionFilter2D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glGetConvolutionFilter (GLenum target, GLenum format, GLenum type, void *image); GLAPI void APIENTRY glGetConvolutionParameterfv (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetConvolutionParameteriv (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetSeparableFilter (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span); GLAPI void APIENTRY glSeparableFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column); GLAPI void APIENTRY glGetHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); GLAPI void APIENTRY glGetHistogramParameterfv (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetHistogramParameteriv (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); GLAPI void APIENTRY glGetMinmaxParameterfv (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetMinmaxParameteriv (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glHistogram (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); GLAPI void APIENTRY glMinmax (GLenum target, GLenum internalformat, GLboolean sink); GLAPI void APIENTRY glResetHistogram (GLenum target); GLAPI void APIENTRY glResetMinmax (GLenum target); #endif #endif /* GL_ARB_imaging */ #ifndef GL_ARB_indirect_parameters #define GL_ARB_indirect_parameters 1 #define GL_PARAMETER_BUFFER_ARB 0x80EE #define GL_PARAMETER_BUFFER_BINDING_ARB 0x80EF typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC) (GLenum mode, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC) (GLenum mode, GLenum type, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMultiDrawArraysIndirectCountARB (GLenum mode, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); GLAPI void APIENTRY glMultiDrawElementsIndirectCountARB (GLenum mode, GLenum type, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); #endif #endif /* GL_ARB_indirect_parameters */ #ifndef GL_ARB_instanced_arrays #define GL_ARB_instanced_arrays 1 #define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB 0x88FE typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORARBPROC) (GLuint index, GLuint divisor); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttribDivisorARB (GLuint index, GLuint divisor); #endif #endif /* GL_ARB_instanced_arrays */ #ifndef GL_ARB_internalformat_query #define GL_ARB_internalformat_query 1 #endif /* GL_ARB_internalformat_query */ #ifndef GL_ARB_internalformat_query2 #define GL_ARB_internalformat_query2 1 #define GL_SRGB_DECODE_ARB 0x8299 #define GL_VIEW_CLASS_EAC_R11 0x9383 #define GL_VIEW_CLASS_EAC_RG11 0x9384 #define GL_VIEW_CLASS_ETC2_RGB 0x9385 #define GL_VIEW_CLASS_ETC2_RGBA 0x9386 #define GL_VIEW_CLASS_ETC2_EAC_RGBA 0x9387 #define GL_VIEW_CLASS_ASTC_4x4_RGBA 0x9388 #define GL_VIEW_CLASS_ASTC_5x4_RGBA 0x9389 #define GL_VIEW_CLASS_ASTC_5x5_RGBA 0x938A #define GL_VIEW_CLASS_ASTC_6x5_RGBA 0x938B #define GL_VIEW_CLASS_ASTC_6x6_RGBA 0x938C #define GL_VIEW_CLASS_ASTC_8x5_RGBA 0x938D #define GL_VIEW_CLASS_ASTC_8x6_RGBA 0x938E #define GL_VIEW_CLASS_ASTC_8x8_RGBA 0x938F #define GL_VIEW_CLASS_ASTC_10x5_RGBA 0x9390 #define GL_VIEW_CLASS_ASTC_10x6_RGBA 0x9391 #define GL_VIEW_CLASS_ASTC_10x8_RGBA 0x9392 #define GL_VIEW_CLASS_ASTC_10x10_RGBA 0x9393 #define GL_VIEW_CLASS_ASTC_12x10_RGBA 0x9394 #define GL_VIEW_CLASS_ASTC_12x12_RGBA 0x9395 #endif /* GL_ARB_internalformat_query2 */ #ifndef GL_ARB_invalidate_subdata #define GL_ARB_invalidate_subdata 1 #endif /* GL_ARB_invalidate_subdata */ #ifndef GL_ARB_map_buffer_alignment #define GL_ARB_map_buffer_alignment 1 #endif /* GL_ARB_map_buffer_alignment */ #ifndef GL_ARB_map_buffer_range #define GL_ARB_map_buffer_range 1 #endif /* GL_ARB_map_buffer_range */ #ifndef GL_ARB_matrix_palette #define GL_ARB_matrix_palette 1 #define GL_MATRIX_PALETTE_ARB 0x8840 #define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841 #define GL_MAX_PALETTE_MATRICES_ARB 0x8842 #define GL_CURRENT_PALETTE_MATRIX_ARB 0x8843 #define GL_MATRIX_INDEX_ARRAY_ARB 0x8844 #define GL_CURRENT_MATRIX_INDEX_ARB 0x8845 #define GL_MATRIX_INDEX_ARRAY_SIZE_ARB 0x8846 #define GL_MATRIX_INDEX_ARRAY_TYPE_ARB 0x8847 #define GL_MATRIX_INDEX_ARRAY_STRIDE_ARB 0x8848 #define GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849 typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index); typedef void (APIENTRYP PFNGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices); typedef void (APIENTRYP PFNGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices); typedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices); typedef void (APIENTRYP PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCurrentPaletteMatrixARB (GLint index); GLAPI void APIENTRY glMatrixIndexubvARB (GLint size, const GLubyte *indices); GLAPI void APIENTRY glMatrixIndexusvARB (GLint size, const GLushort *indices); GLAPI void APIENTRY glMatrixIndexuivARB (GLint size, const GLuint *indices); GLAPI void APIENTRY glMatrixIndexPointerARB (GLint size, GLenum type, GLsizei stride, const void *pointer); #endif #endif /* GL_ARB_matrix_palette */ #ifndef GL_ARB_multi_bind #define GL_ARB_multi_bind 1 #endif /* GL_ARB_multi_bind */ #ifndef GL_ARB_multi_draw_indirect #define GL_ARB_multi_draw_indirect 1 #endif /* GL_ARB_multi_draw_indirect */ #ifndef GL_ARB_multisample #define GL_ARB_multisample 1 #define GL_MULTISAMPLE_ARB 0x809D #define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E #define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F #define GL_SAMPLE_COVERAGE_ARB 0x80A0 #define GL_SAMPLE_BUFFERS_ARB 0x80A8 #define GL_SAMPLES_ARB 0x80A9 #define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA #define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB #define GL_MULTISAMPLE_BIT_ARB 0x20000000 typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC) (GLfloat value, GLboolean invert); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSampleCoverageARB (GLfloat value, GLboolean invert); #endif #endif /* GL_ARB_multisample */ #ifndef GL_ARB_multitexture #define GL_ARB_multitexture 1 #define GL_TEXTURE0_ARB 0x84C0 #define GL_TEXTURE1_ARB 0x84C1 #define GL_TEXTURE2_ARB 0x84C2 #define GL_TEXTURE3_ARB 0x84C3 #define GL_TEXTURE4_ARB 0x84C4 #define GL_TEXTURE5_ARB 0x84C5 #define GL_TEXTURE6_ARB 0x84C6 #define GL_TEXTURE7_ARB 0x84C7 #define GL_TEXTURE8_ARB 0x84C8 #define GL_TEXTURE9_ARB 0x84C9 #define GL_TEXTURE10_ARB 0x84CA #define GL_TEXTURE11_ARB 0x84CB #define GL_TEXTURE12_ARB 0x84CC #define GL_TEXTURE13_ARB 0x84CD #define GL_TEXTURE14_ARB 0x84CE #define GL_TEXTURE15_ARB 0x84CF #define GL_TEXTURE16_ARB 0x84D0 #define GL_TEXTURE17_ARB 0x84D1 #define GL_TEXTURE18_ARB 0x84D2 #define GL_TEXTURE19_ARB 0x84D3 #define GL_TEXTURE20_ARB 0x84D4 #define GL_TEXTURE21_ARB 0x84D5 #define GL_TEXTURE22_ARB 0x84D6 #define GL_TEXTURE23_ARB 0x84D7 #define GL_TEXTURE24_ARB 0x84D8 #define GL_TEXTURE25_ARB 0x84D9 #define GL_TEXTURE26_ARB 0x84DA #define GL_TEXTURE27_ARB 0x84DB #define GL_TEXTURE28_ARB 0x84DC #define GL_TEXTURE29_ARB 0x84DD #define GL_TEXTURE30_ARB 0x84DE #define GL_TEXTURE31_ARB 0x84DF #define GL_ACTIVE_TEXTURE_ARB 0x84E0 #define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1 #define GL_MAX_TEXTURE_UNITS_ARB 0x84E2 typedef void (APIENTRYP PFNGLACTIVETEXTUREARBPROC) (GLenum texture); typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture); typedef void (APIENTRYP PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glActiveTextureARB (GLenum texture); GLAPI void APIENTRY glClientActiveTextureARB (GLenum texture); GLAPI void APIENTRY glMultiTexCoord1dARB (GLenum target, GLdouble s); GLAPI void APIENTRY glMultiTexCoord1dvARB (GLenum target, const GLdouble *v); GLAPI void APIENTRY glMultiTexCoord1fARB (GLenum target, GLfloat s); GLAPI void APIENTRY glMultiTexCoord1fvARB (GLenum target, const GLfloat *v); GLAPI void APIENTRY glMultiTexCoord1iARB (GLenum target, GLint s); GLAPI void APIENTRY glMultiTexCoord1ivARB (GLenum target, const GLint *v); GLAPI void APIENTRY glMultiTexCoord1sARB (GLenum target, GLshort s); GLAPI void APIENTRY glMultiTexCoord1svARB (GLenum target, const GLshort *v); GLAPI void APIENTRY glMultiTexCoord2dARB (GLenum target, GLdouble s, GLdouble t); GLAPI void APIENTRY glMultiTexCoord2dvARB (GLenum target, const GLdouble *v); GLAPI void APIENTRY glMultiTexCoord2fARB (GLenum target, GLfloat s, GLfloat t); GLAPI void APIENTRY glMultiTexCoord2fvARB (GLenum target, const GLfloat *v); GLAPI void APIENTRY glMultiTexCoord2iARB (GLenum target, GLint s, GLint t); GLAPI void APIENTRY glMultiTexCoord2ivARB (GLenum target, const GLint *v); GLAPI void APIENTRY glMultiTexCoord2sARB (GLenum target, GLshort s, GLshort t); GLAPI void APIENTRY glMultiTexCoord2svARB (GLenum target, const GLshort *v); GLAPI void APIENTRY glMultiTexCoord3dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r); GLAPI void APIENTRY glMultiTexCoord3dvARB (GLenum target, const GLdouble *v); GLAPI void APIENTRY glMultiTexCoord3fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r); GLAPI void APIENTRY glMultiTexCoord3fvARB (GLenum target, const GLfloat *v); GLAPI void APIENTRY glMultiTexCoord3iARB (GLenum target, GLint s, GLint t, GLint r); GLAPI void APIENTRY glMultiTexCoord3ivARB (GLenum target, const GLint *v); GLAPI void APIENTRY glMultiTexCoord3sARB (GLenum target, GLshort s, GLshort t, GLshort r); GLAPI void APIENTRY glMultiTexCoord3svARB (GLenum target, const GLshort *v); GLAPI void APIENTRY glMultiTexCoord4dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); GLAPI void APIENTRY glMultiTexCoord4dvARB (GLenum target, const GLdouble *v); GLAPI void APIENTRY glMultiTexCoord4fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); GLAPI void APIENTRY glMultiTexCoord4fvARB (GLenum target, const GLfloat *v); GLAPI void APIENTRY glMultiTexCoord4iARB (GLenum target, GLint s, GLint t, GLint r, GLint q); GLAPI void APIENTRY glMultiTexCoord4ivARB (GLenum target, const GLint *v); GLAPI void APIENTRY glMultiTexCoord4sARB (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); GLAPI void APIENTRY glMultiTexCoord4svARB (GLenum target, const GLshort *v); #endif #endif /* GL_ARB_multitexture */ #ifndef GL_ARB_occlusion_query #define GL_ARB_occlusion_query 1 #define GL_QUERY_COUNTER_BITS_ARB 0x8864 #define GL_CURRENT_QUERY_ARB 0x8865 #define GL_QUERY_RESULT_ARB 0x8866 #define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867 #define GL_SAMPLES_PASSED_ARB 0x8914 typedef void (APIENTRYP PFNGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids); typedef void (APIENTRYP PFNGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids); typedef GLboolean (APIENTRYP PFNGLISQUERYARBPROC) (GLuint id); typedef void (APIENTRYP PFNGLBEGINQUERYARBPROC) (GLenum target, GLuint id); typedef void (APIENTRYP PFNGLENDQUERYARBPROC) (GLenum target); typedef void (APIENTRYP PFNGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenQueriesARB (GLsizei n, GLuint *ids); GLAPI void APIENTRY glDeleteQueriesARB (GLsizei n, const GLuint *ids); GLAPI GLboolean APIENTRY glIsQueryARB (GLuint id); GLAPI void APIENTRY glBeginQueryARB (GLenum target, GLuint id); GLAPI void APIENTRY glEndQueryARB (GLenum target); GLAPI void APIENTRY glGetQueryivARB (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetQueryObjectivARB (GLuint id, GLenum pname, GLint *params); GLAPI void APIENTRY glGetQueryObjectuivARB (GLuint id, GLenum pname, GLuint *params); #endif #endif /* GL_ARB_occlusion_query */ #ifndef GL_ARB_occlusion_query2 #define GL_ARB_occlusion_query2 1 #endif /* GL_ARB_occlusion_query2 */ #ifndef GL_ARB_parallel_shader_compile #define GL_ARB_parallel_shader_compile 1 #define GL_MAX_SHADER_COMPILER_THREADS_ARB 0x91B0 #define GL_COMPLETION_STATUS_ARB 0x91B1 typedef void (APIENTRYP PFNGLMAXSHADERCOMPILERTHREADSARBPROC) (GLuint count); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMaxShaderCompilerThreadsARB (GLuint count); #endif #endif /* GL_ARB_parallel_shader_compile */ #ifndef GL_ARB_pipeline_statistics_query #define GL_ARB_pipeline_statistics_query 1 #define GL_VERTICES_SUBMITTED_ARB 0x82EE #define GL_PRIMITIVES_SUBMITTED_ARB 0x82EF #define GL_VERTEX_SHADER_INVOCATIONS_ARB 0x82F0 #define GL_TESS_CONTROL_SHADER_PATCHES_ARB 0x82F1 #define GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB 0x82F2 #define GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB 0x82F3 #define GL_FRAGMENT_SHADER_INVOCATIONS_ARB 0x82F4 #define GL_COMPUTE_SHADER_INVOCATIONS_ARB 0x82F5 #define GL_CLIPPING_INPUT_PRIMITIVES_ARB 0x82F6 #define GL_CLIPPING_OUTPUT_PRIMITIVES_ARB 0x82F7 #endif /* GL_ARB_pipeline_statistics_query */ #ifndef GL_ARB_pixel_buffer_object #define GL_ARB_pixel_buffer_object 1 #define GL_PIXEL_PACK_BUFFER_ARB 0x88EB #define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC #define GL_PIXEL_PACK_BUFFER_BINDING_ARB 0x88ED #define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF #endif /* GL_ARB_pixel_buffer_object */ #ifndef GL_ARB_point_parameters #define GL_ARB_point_parameters 1 #define GL_POINT_SIZE_MIN_ARB 0x8126 #define GL_POINT_SIZE_MAX_ARB 0x8127 #define GL_POINT_FADE_THRESHOLD_SIZE_ARB 0x8128 #define GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129 typedef void (APIENTRYP PFNGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPointParameterfARB (GLenum pname, GLfloat param); GLAPI void APIENTRY glPointParameterfvARB (GLenum pname, const GLfloat *params); #endif #endif /* GL_ARB_point_parameters */ #ifndef GL_ARB_point_sprite #define GL_ARB_point_sprite 1 #define GL_POINT_SPRITE_ARB 0x8861 #define GL_COORD_REPLACE_ARB 0x8862 #endif /* GL_ARB_point_sprite */ #ifndef GL_ARB_polygon_offset_clamp #define GL_ARB_polygon_offset_clamp 1 #endif /* GL_ARB_polygon_offset_clamp */ #ifndef GL_ARB_post_depth_coverage #define GL_ARB_post_depth_coverage 1 #endif /* GL_ARB_post_depth_coverage */ #ifndef GL_ARB_program_interface_query #define GL_ARB_program_interface_query 1 #endif /* GL_ARB_program_interface_query */ #ifndef GL_ARB_provoking_vertex #define GL_ARB_provoking_vertex 1 #endif /* GL_ARB_provoking_vertex */ #ifndef GL_ARB_query_buffer_object #define GL_ARB_query_buffer_object 1 #endif /* GL_ARB_query_buffer_object */ #ifndef GL_ARB_robust_buffer_access_behavior #define GL_ARB_robust_buffer_access_behavior 1 #endif /* GL_ARB_robust_buffer_access_behavior */ #ifndef GL_ARB_robustness #define GL_ARB_robustness 1 #define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004 #define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 #define GL_GUILTY_CONTEXT_RESET_ARB 0x8253 #define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 #define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 #define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 #define GL_NO_RESET_NOTIFICATION_ARB 0x8261 typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSARBPROC) (void); typedef void (APIENTRYP PFNGLGETNTEXIMAGEARBPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img); typedef void (APIENTRYP PFNGLREADNPIXELSARBPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLsizei bufSize, void *img); typedef void (APIENTRYP PFNGLGETNUNIFORMFVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); typedef void (APIENTRYP PFNGLGETNUNIFORMIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); typedef void (APIENTRYP PFNGLGETNUNIFORMUIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params); typedef void (APIENTRYP PFNGLGETNUNIFORMDVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); typedef void (APIENTRYP PFNGLGETNMAPDVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); typedef void (APIENTRYP PFNGLGETNMAPFVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); typedef void (APIENTRYP PFNGLGETNMAPIVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLint *v); typedef void (APIENTRYP PFNGLGETNPIXELMAPFVARBPROC) (GLenum map, GLsizei bufSize, GLfloat *values); typedef void (APIENTRYP PFNGLGETNPIXELMAPUIVARBPROC) (GLenum map, GLsizei bufSize, GLuint *values); typedef void (APIENTRYP PFNGLGETNPIXELMAPUSVARBPROC) (GLenum map, GLsizei bufSize, GLushort *values); typedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEARBPROC) (GLsizei bufSize, GLubyte *pattern); typedef void (APIENTRYP PFNGLGETNCOLORTABLEARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table); typedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image); typedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span); typedef void (APIENTRYP PFNGLGETNHISTOGRAMARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); typedef void (APIENTRYP PFNGLGETNMINMAXARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); #ifdef GL_GLEXT_PROTOTYPES GLAPI GLenum APIENTRY glGetGraphicsResetStatusARB (void); GLAPI void APIENTRY glGetnTexImageARB (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img); GLAPI void APIENTRY glReadnPixelsARB (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); GLAPI void APIENTRY glGetnCompressedTexImageARB (GLenum target, GLint lod, GLsizei bufSize, void *img); GLAPI void APIENTRY glGetnUniformfvARB (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); GLAPI void APIENTRY glGetnUniformivARB (GLuint program, GLint location, GLsizei bufSize, GLint *params); GLAPI void APIENTRY glGetnUniformuivARB (GLuint program, GLint location, GLsizei bufSize, GLuint *params); GLAPI void APIENTRY glGetnUniformdvARB (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); GLAPI void APIENTRY glGetnMapdvARB (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); GLAPI void APIENTRY glGetnMapfvARB (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); GLAPI void APIENTRY glGetnMapivARB (GLenum target, GLenum query, GLsizei bufSize, GLint *v); GLAPI void APIENTRY glGetnPixelMapfvARB (GLenum map, GLsizei bufSize, GLfloat *values); GLAPI void APIENTRY glGetnPixelMapuivARB (GLenum map, GLsizei bufSize, GLuint *values); GLAPI void APIENTRY glGetnPixelMapusvARB (GLenum map, GLsizei bufSize, GLushort *values); GLAPI void APIENTRY glGetnPolygonStippleARB (GLsizei bufSize, GLubyte *pattern); GLAPI void APIENTRY glGetnColorTableARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table); GLAPI void APIENTRY glGetnConvolutionFilterARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image); GLAPI void APIENTRY glGetnSeparableFilterARB (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span); GLAPI void APIENTRY glGetnHistogramARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); GLAPI void APIENTRY glGetnMinmaxARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); #endif #endif /* GL_ARB_robustness */ #ifndef GL_ARB_robustness_isolation #define GL_ARB_robustness_isolation 1 #endif /* GL_ARB_robustness_isolation */ #ifndef GL_ARB_sample_locations #define GL_ARB_sample_locations 1 #define GL_SAMPLE_LOCATION_SUBPIXEL_BITS_ARB 0x933D #define GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_ARB 0x933E #define GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_ARB 0x933F #define GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_ARB 0x9340 #define GL_SAMPLE_LOCATION_ARB 0x8E50 #define GL_PROGRAMMABLE_SAMPLE_LOCATION_ARB 0x9341 #define GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB 0x9342 #define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB 0x9343 typedef void (APIENTRYP PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC) (GLenum target, GLuint start, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC) (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLEVALUATEDEPTHVALUESARBPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFramebufferSampleLocationsfvARB (GLenum target, GLuint start, GLsizei count, const GLfloat *v); GLAPI void APIENTRY glNamedFramebufferSampleLocationsfvARB (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v); GLAPI void APIENTRY glEvaluateDepthValuesARB (void); #endif #endif /* GL_ARB_sample_locations */ #ifndef GL_ARB_sample_shading #define GL_ARB_sample_shading 1 #define GL_SAMPLE_SHADING_ARB 0x8C36 #define GL_MIN_SAMPLE_SHADING_VALUE_ARB 0x8C37 typedef void (APIENTRYP PFNGLMINSAMPLESHADINGARBPROC) (GLfloat value); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMinSampleShadingARB (GLfloat value); #endif #endif /* GL_ARB_sample_shading */ #ifndef GL_ARB_sampler_objects #define GL_ARB_sampler_objects 1 #endif /* GL_ARB_sampler_objects */ #ifndef GL_ARB_seamless_cube_map #define GL_ARB_seamless_cube_map 1 #endif /* GL_ARB_seamless_cube_map */ #ifndef GL_ARB_seamless_cubemap_per_texture #define GL_ARB_seamless_cubemap_per_texture 1 #endif /* GL_ARB_seamless_cubemap_per_texture */ #ifndef GL_ARB_separate_shader_objects #define GL_ARB_separate_shader_objects 1 #endif /* GL_ARB_separate_shader_objects */ #ifndef GL_ARB_shader_atomic_counter_ops #define GL_ARB_shader_atomic_counter_ops 1 #endif /* GL_ARB_shader_atomic_counter_ops */ #ifndef GL_ARB_shader_atomic_counters #define GL_ARB_shader_atomic_counters 1 #endif /* GL_ARB_shader_atomic_counters */ #ifndef GL_ARB_shader_ballot #define GL_ARB_shader_ballot 1 #endif /* GL_ARB_shader_ballot */ #ifndef GL_ARB_shader_bit_encoding #define GL_ARB_shader_bit_encoding 1 #endif /* GL_ARB_shader_bit_encoding */ #ifndef GL_ARB_shader_clock #define GL_ARB_shader_clock 1 #endif /* GL_ARB_shader_clock */ #ifndef GL_ARB_shader_draw_parameters #define GL_ARB_shader_draw_parameters 1 #endif /* GL_ARB_shader_draw_parameters */ #ifndef GL_ARB_shader_group_vote #define GL_ARB_shader_group_vote 1 #endif /* GL_ARB_shader_group_vote */ #ifndef GL_ARB_shader_image_load_store #define GL_ARB_shader_image_load_store 1 #endif /* GL_ARB_shader_image_load_store */ #ifndef GL_ARB_shader_image_size #define GL_ARB_shader_image_size 1 #endif /* GL_ARB_shader_image_size */ #ifndef GL_ARB_shader_objects #define GL_ARB_shader_objects 1 #ifdef __APPLE__ typedef void *GLhandleARB; #else typedef unsigned int GLhandleARB; #endif typedef char GLcharARB; #define GL_PROGRAM_OBJECT_ARB 0x8B40 #define GL_SHADER_OBJECT_ARB 0x8B48 #define GL_OBJECT_TYPE_ARB 0x8B4E #define GL_OBJECT_SUBTYPE_ARB 0x8B4F #define GL_FLOAT_VEC2_ARB 0x8B50 #define GL_FLOAT_VEC3_ARB 0x8B51 #define GL_FLOAT_VEC4_ARB 0x8B52 #define GL_INT_VEC2_ARB 0x8B53 #define GL_INT_VEC3_ARB 0x8B54 #define GL_INT_VEC4_ARB 0x8B55 #define GL_BOOL_ARB 0x8B56 #define GL_BOOL_VEC2_ARB 0x8B57 #define GL_BOOL_VEC3_ARB 0x8B58 #define GL_BOOL_VEC4_ARB 0x8B59 #define GL_FLOAT_MAT2_ARB 0x8B5A #define GL_FLOAT_MAT3_ARB 0x8B5B #define GL_FLOAT_MAT4_ARB 0x8B5C #define GL_SAMPLER_1D_ARB 0x8B5D #define GL_SAMPLER_2D_ARB 0x8B5E #define GL_SAMPLER_3D_ARB 0x8B5F #define GL_SAMPLER_CUBE_ARB 0x8B60 #define GL_SAMPLER_1D_SHADOW_ARB 0x8B61 #define GL_SAMPLER_2D_SHADOW_ARB 0x8B62 #define GL_SAMPLER_2D_RECT_ARB 0x8B63 #define GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64 #define GL_OBJECT_DELETE_STATUS_ARB 0x8B80 #define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81 #define GL_OBJECT_LINK_STATUS_ARB 0x8B82 #define GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83 #define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84 #define GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85 #define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86 #define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87 #define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88 typedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj); typedef GLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC) (GLenum pname); typedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj); typedef GLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType); typedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length); typedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj); typedef GLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC) (void); typedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj); typedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC) (GLhandleARB programObj); typedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj); typedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj); typedef void (APIENTRYP PFNGLUNIFORM1FARBPROC) (GLint location, GLfloat v0); typedef void (APIENTRYP PFNGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1); typedef void (APIENTRYP PFNGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (APIENTRYP PFNGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (APIENTRYP PFNGLUNIFORM1IARBPROC) (GLint location, GLint v0); typedef void (APIENTRYP PFNGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1); typedef void (APIENTRYP PFNGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2); typedef void (APIENTRYP PFNGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (APIENTRYP PFNGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); typedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); typedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params); typedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params); typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDeleteObjectARB (GLhandleARB obj); GLAPI GLhandleARB APIENTRY glGetHandleARB (GLenum pname); GLAPI void APIENTRY glDetachObjectARB (GLhandleARB containerObj, GLhandleARB attachedObj); GLAPI GLhandleARB APIENTRY glCreateShaderObjectARB (GLenum shaderType); GLAPI void APIENTRY glShaderSourceARB (GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length); GLAPI void APIENTRY glCompileShaderARB (GLhandleARB shaderObj); GLAPI GLhandleARB APIENTRY glCreateProgramObjectARB (void); GLAPI void APIENTRY glAttachObjectARB (GLhandleARB containerObj, GLhandleARB obj); GLAPI void APIENTRY glLinkProgramARB (GLhandleARB programObj); GLAPI void APIENTRY glUseProgramObjectARB (GLhandleARB programObj); GLAPI void APIENTRY glValidateProgramARB (GLhandleARB programObj); GLAPI void APIENTRY glUniform1fARB (GLint location, GLfloat v0); GLAPI void APIENTRY glUniform2fARB (GLint location, GLfloat v0, GLfloat v1); GLAPI void APIENTRY glUniform3fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); GLAPI void APIENTRY glUniform4fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); GLAPI void APIENTRY glUniform1iARB (GLint location, GLint v0); GLAPI void APIENTRY glUniform2iARB (GLint location, GLint v0, GLint v1); GLAPI void APIENTRY glUniform3iARB (GLint location, GLint v0, GLint v1, GLint v2); GLAPI void APIENTRY glUniform4iARB (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); GLAPI void APIENTRY glUniform1fvARB (GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glUniform2fvARB (GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glUniform3fvARB (GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glUniform4fvARB (GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glUniform1ivARB (GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glUniform2ivARB (GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glUniform3ivARB (GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glUniform4ivARB (GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glUniformMatrix2fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glUniformMatrix3fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glUniformMatrix4fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glGetObjectParameterfvARB (GLhandleARB obj, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetObjectParameterivARB (GLhandleARB obj, GLenum pname, GLint *params); GLAPI void APIENTRY glGetInfoLogARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); GLAPI void APIENTRY glGetAttachedObjectsARB (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); GLAPI GLint APIENTRY glGetUniformLocationARB (GLhandleARB programObj, const GLcharARB *name); GLAPI void APIENTRY glGetActiveUniformARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); GLAPI void APIENTRY glGetUniformfvARB (GLhandleARB programObj, GLint location, GLfloat *params); GLAPI void APIENTRY glGetUniformivARB (GLhandleARB programObj, GLint location, GLint *params); GLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); #endif #endif /* GL_ARB_shader_objects */ #ifndef GL_ARB_shader_precision #define GL_ARB_shader_precision 1 #endif /* GL_ARB_shader_precision */ #ifndef GL_ARB_shader_stencil_export #define GL_ARB_shader_stencil_export 1 #endif /* GL_ARB_shader_stencil_export */ #ifndef GL_ARB_shader_storage_buffer_object #define GL_ARB_shader_storage_buffer_object 1 #endif /* GL_ARB_shader_storage_buffer_object */ #ifndef GL_ARB_shader_subroutine #define GL_ARB_shader_subroutine 1 #endif /* GL_ARB_shader_subroutine */ #ifndef GL_ARB_shader_texture_image_samples #define GL_ARB_shader_texture_image_samples 1 #endif /* GL_ARB_shader_texture_image_samples */ #ifndef GL_ARB_shader_texture_lod #define GL_ARB_shader_texture_lod 1 #endif /* GL_ARB_shader_texture_lod */ #ifndef GL_ARB_shader_viewport_layer_array #define GL_ARB_shader_viewport_layer_array 1 #endif /* GL_ARB_shader_viewport_layer_array */ #ifndef GL_ARB_shading_language_100 #define GL_ARB_shading_language_100 1 #define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C #endif /* GL_ARB_shading_language_100 */ #ifndef GL_ARB_shading_language_420pack #define GL_ARB_shading_language_420pack 1 #endif /* GL_ARB_shading_language_420pack */ #ifndef GL_ARB_shading_language_include #define GL_ARB_shading_language_include 1 #define GL_SHADER_INCLUDE_ARB 0x8DAE #define GL_NAMED_STRING_LENGTH_ARB 0x8DE9 #define GL_NAMED_STRING_TYPE_ARB 0x8DEA typedef void (APIENTRYP PFNGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); typedef void (APIENTRYP PFNGLDELETENAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); typedef void (APIENTRYP PFNGLCOMPILESHADERINCLUDEARBPROC) (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length); typedef GLboolean (APIENTRYP PFNGLISNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); typedef void (APIENTRYP PFNGLGETNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); typedef void (APIENTRYP PFNGLGETNAMEDSTRINGIVARBPROC) (GLint namelen, const GLchar *name, GLenum pname, GLint *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glNamedStringARB (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); GLAPI void APIENTRY glDeleteNamedStringARB (GLint namelen, const GLchar *name); GLAPI void APIENTRY glCompileShaderIncludeARB (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length); GLAPI GLboolean APIENTRY glIsNamedStringARB (GLint namelen, const GLchar *name); GLAPI void APIENTRY glGetNamedStringARB (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); GLAPI void APIENTRY glGetNamedStringivARB (GLint namelen, const GLchar *name, GLenum pname, GLint *params); #endif #endif /* GL_ARB_shading_language_include */ #ifndef GL_ARB_shading_language_packing #define GL_ARB_shading_language_packing 1 #endif /* GL_ARB_shading_language_packing */ #ifndef GL_ARB_shadow #define GL_ARB_shadow 1 #define GL_TEXTURE_COMPARE_MODE_ARB 0x884C #define GL_TEXTURE_COMPARE_FUNC_ARB 0x884D #define GL_COMPARE_R_TO_TEXTURE_ARB 0x884E #endif /* GL_ARB_shadow */ #ifndef GL_ARB_shadow_ambient #define GL_ARB_shadow_ambient 1 #define GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF #endif /* GL_ARB_shadow_ambient */ #ifndef GL_ARB_sparse_buffer #define GL_ARB_sparse_buffer 1 #define GL_SPARSE_STORAGE_BIT_ARB 0x0400 #define GL_SPARSE_BUFFER_PAGE_SIZE_ARB 0x82F8 typedef void (APIENTRYP PFNGLBUFFERPAGECOMMITMENTARBPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLboolean commit); typedef void (APIENTRYP PFNGLNAMEDBUFFERPAGECOMMITMENTEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit); typedef void (APIENTRYP PFNGLNAMEDBUFFERPAGECOMMITMENTARBPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBufferPageCommitmentARB (GLenum target, GLintptr offset, GLsizeiptr size, GLboolean commit); GLAPI void APIENTRY glNamedBufferPageCommitmentEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit); GLAPI void APIENTRY glNamedBufferPageCommitmentARB (GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit); #endif #endif /* GL_ARB_sparse_buffer */ #ifndef GL_ARB_sparse_texture #define GL_ARB_sparse_texture 1 #define GL_TEXTURE_SPARSE_ARB 0x91A6 #define GL_VIRTUAL_PAGE_SIZE_INDEX_ARB 0x91A7 #define GL_NUM_SPARSE_LEVELS_ARB 0x91AA #define GL_NUM_VIRTUAL_PAGE_SIZES_ARB 0x91A8 #define GL_VIRTUAL_PAGE_SIZE_X_ARB 0x9195 #define GL_VIRTUAL_PAGE_SIZE_Y_ARB 0x9196 #define GL_VIRTUAL_PAGE_SIZE_Z_ARB 0x9197 #define GL_MAX_SPARSE_TEXTURE_SIZE_ARB 0x9198 #define GL_MAX_SPARSE_3D_TEXTURE_SIZE_ARB 0x9199 #define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_ARB 0x919A #define GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_ARB 0x91A9 typedef void (APIENTRYP PFNGLTEXPAGECOMMITMENTARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexPageCommitmentARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); #endif #endif /* GL_ARB_sparse_texture */ #ifndef GL_ARB_sparse_texture2 #define GL_ARB_sparse_texture2 1 #endif /* GL_ARB_sparse_texture2 */ #ifndef GL_ARB_sparse_texture_clamp #define GL_ARB_sparse_texture_clamp 1 #endif /* GL_ARB_sparse_texture_clamp */ #ifndef GL_ARB_spirv_extensions #define GL_ARB_spirv_extensions 1 #endif /* GL_ARB_spirv_extensions */ #ifndef GL_ARB_stencil_texturing #define GL_ARB_stencil_texturing 1 #endif /* GL_ARB_stencil_texturing */ #ifndef GL_ARB_sync #define GL_ARB_sync 1 #endif /* GL_ARB_sync */ #ifndef GL_ARB_tessellation_shader #define GL_ARB_tessellation_shader 1 #endif /* GL_ARB_tessellation_shader */ #ifndef GL_ARB_texture_barrier #define GL_ARB_texture_barrier 1 #endif /* GL_ARB_texture_barrier */ #ifndef GL_ARB_texture_border_clamp #define GL_ARB_texture_border_clamp 1 #define GL_CLAMP_TO_BORDER_ARB 0x812D #endif /* GL_ARB_texture_border_clamp */ #ifndef GL_ARB_texture_buffer_object #define GL_ARB_texture_buffer_object 1 #define GL_TEXTURE_BUFFER_ARB 0x8C2A #define GL_MAX_TEXTURE_BUFFER_SIZE_ARB 0x8C2B #define GL_TEXTURE_BINDING_BUFFER_ARB 0x8C2C #define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB 0x8C2D #define GL_TEXTURE_BUFFER_FORMAT_ARB 0x8C2E typedef void (APIENTRYP PFNGLTEXBUFFERARBPROC) (GLenum target, GLenum internalformat, GLuint buffer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexBufferARB (GLenum target, GLenum internalformat, GLuint buffer); #endif #endif /* GL_ARB_texture_buffer_object */ #ifndef GL_ARB_texture_buffer_object_rgb32 #define GL_ARB_texture_buffer_object_rgb32 1 #endif /* GL_ARB_texture_buffer_object_rgb32 */ #ifndef GL_ARB_texture_buffer_range #define GL_ARB_texture_buffer_range 1 #endif /* GL_ARB_texture_buffer_range */ #ifndef GL_ARB_texture_compression #define GL_ARB_texture_compression 1 #define GL_COMPRESSED_ALPHA_ARB 0x84E9 #define GL_COMPRESSED_LUMINANCE_ARB 0x84EA #define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB #define GL_COMPRESSED_INTENSITY_ARB 0x84EC #define GL_COMPRESSED_RGB_ARB 0x84ED #define GL_COMPRESSED_RGBA_ARB 0x84EE #define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF #define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0 #define GL_TEXTURE_COMPRESSED_ARB 0x86A1 #define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2 #define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, void *img); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCompressedTexImage3DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); GLAPI void APIENTRY glCompressedTexImage2DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); GLAPI void APIENTRY glCompressedTexImage1DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); GLAPI void APIENTRY glCompressedTexSubImage3DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); GLAPI void APIENTRY glCompressedTexSubImage2DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); GLAPI void APIENTRY glCompressedTexSubImage1DARB (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); GLAPI void APIENTRY glGetCompressedTexImageARB (GLenum target, GLint level, void *img); #endif #endif /* GL_ARB_texture_compression */ #ifndef GL_ARB_texture_compression_bptc #define GL_ARB_texture_compression_bptc 1 #define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C #define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D #define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E #define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F #endif /* GL_ARB_texture_compression_bptc */ #ifndef GL_ARB_texture_compression_rgtc #define GL_ARB_texture_compression_rgtc 1 #endif /* GL_ARB_texture_compression_rgtc */ #ifndef GL_ARB_texture_cube_map #define GL_ARB_texture_cube_map 1 #define GL_NORMAL_MAP_ARB 0x8511 #define GL_REFLECTION_MAP_ARB 0x8512 #define GL_TEXTURE_CUBE_MAP_ARB 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A #define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B #define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C #endif /* GL_ARB_texture_cube_map */ #ifndef GL_ARB_texture_cube_map_array #define GL_ARB_texture_cube_map_array 1 #define GL_TEXTURE_CUBE_MAP_ARRAY_ARB 0x9009 #define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB 0x900A #define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB 0x900B #define GL_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900C #define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB 0x900D #define GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900E #define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900F #endif /* GL_ARB_texture_cube_map_array */ #ifndef GL_ARB_texture_env_add #define GL_ARB_texture_env_add 1 #endif /* GL_ARB_texture_env_add */ #ifndef GL_ARB_texture_env_combine #define GL_ARB_texture_env_combine 1 #define GL_COMBINE_ARB 0x8570 #define GL_COMBINE_RGB_ARB 0x8571 #define GL_COMBINE_ALPHA_ARB 0x8572 #define GL_SOURCE0_RGB_ARB 0x8580 #define GL_SOURCE1_RGB_ARB 0x8581 #define GL_SOURCE2_RGB_ARB 0x8582 #define GL_SOURCE0_ALPHA_ARB 0x8588 #define GL_SOURCE1_ALPHA_ARB 0x8589 #define GL_SOURCE2_ALPHA_ARB 0x858A #define GL_OPERAND0_RGB_ARB 0x8590 #define GL_OPERAND1_RGB_ARB 0x8591 #define GL_OPERAND2_RGB_ARB 0x8592 #define GL_OPERAND0_ALPHA_ARB 0x8598 #define GL_OPERAND1_ALPHA_ARB 0x8599 #define GL_OPERAND2_ALPHA_ARB 0x859A #define GL_RGB_SCALE_ARB 0x8573 #define GL_ADD_SIGNED_ARB 0x8574 #define GL_INTERPOLATE_ARB 0x8575 #define GL_SUBTRACT_ARB 0x84E7 #define GL_CONSTANT_ARB 0x8576 #define GL_PRIMARY_COLOR_ARB 0x8577 #define GL_PREVIOUS_ARB 0x8578 #endif /* GL_ARB_texture_env_combine */ #ifndef GL_ARB_texture_env_crossbar #define GL_ARB_texture_env_crossbar 1 #endif /* GL_ARB_texture_env_crossbar */ #ifndef GL_ARB_texture_env_dot3 #define GL_ARB_texture_env_dot3 1 #define GL_DOT3_RGB_ARB 0x86AE #define GL_DOT3_RGBA_ARB 0x86AF #endif /* GL_ARB_texture_env_dot3 */ #ifndef GL_ARB_texture_filter_anisotropic #define GL_ARB_texture_filter_anisotropic 1 #endif /* GL_ARB_texture_filter_anisotropic */ #ifndef GL_ARB_texture_filter_minmax #define GL_ARB_texture_filter_minmax 1 #define GL_TEXTURE_REDUCTION_MODE_ARB 0x9366 #define GL_WEIGHTED_AVERAGE_ARB 0x9367 #endif /* GL_ARB_texture_filter_minmax */ #ifndef GL_ARB_texture_float #define GL_ARB_texture_float 1 #define GL_TEXTURE_RED_TYPE_ARB 0x8C10 #define GL_TEXTURE_GREEN_TYPE_ARB 0x8C11 #define GL_TEXTURE_BLUE_TYPE_ARB 0x8C12 #define GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13 #define GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14 #define GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15 #define GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16 #define GL_UNSIGNED_NORMALIZED_ARB 0x8C17 #define GL_RGBA32F_ARB 0x8814 #define GL_RGB32F_ARB 0x8815 #define GL_ALPHA32F_ARB 0x8816 #define GL_INTENSITY32F_ARB 0x8817 #define GL_LUMINANCE32F_ARB 0x8818 #define GL_LUMINANCE_ALPHA32F_ARB 0x8819 #define GL_RGBA16F_ARB 0x881A #define GL_RGB16F_ARB 0x881B #define GL_ALPHA16F_ARB 0x881C #define GL_INTENSITY16F_ARB 0x881D #define GL_LUMINANCE16F_ARB 0x881E #define GL_LUMINANCE_ALPHA16F_ARB 0x881F #endif /* GL_ARB_texture_float */ #ifndef GL_ARB_texture_gather #define GL_ARB_texture_gather 1 #define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5E #define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5F #define GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB 0x8F9F #endif /* GL_ARB_texture_gather */ #ifndef GL_ARB_texture_mirror_clamp_to_edge #define GL_ARB_texture_mirror_clamp_to_edge 1 #endif /* GL_ARB_texture_mirror_clamp_to_edge */ #ifndef GL_ARB_texture_mirrored_repeat #define GL_ARB_texture_mirrored_repeat 1 #define GL_MIRRORED_REPEAT_ARB 0x8370 #endif /* GL_ARB_texture_mirrored_repeat */ #ifndef GL_ARB_texture_multisample #define GL_ARB_texture_multisample 1 #endif /* GL_ARB_texture_multisample */ #ifndef GL_ARB_texture_non_power_of_two #define GL_ARB_texture_non_power_of_two 1 #endif /* GL_ARB_texture_non_power_of_two */ #ifndef GL_ARB_texture_query_levels #define GL_ARB_texture_query_levels 1 #endif /* GL_ARB_texture_query_levels */ #ifndef GL_ARB_texture_query_lod #define GL_ARB_texture_query_lod 1 #endif /* GL_ARB_texture_query_lod */ #ifndef GL_ARB_texture_rectangle #define GL_ARB_texture_rectangle 1 #define GL_TEXTURE_RECTANGLE_ARB 0x84F5 #define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6 #define GL_PROXY_TEXTURE_RECTANGLE_ARB 0x84F7 #define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 #endif /* GL_ARB_texture_rectangle */ #ifndef GL_ARB_texture_rg #define GL_ARB_texture_rg 1 #endif /* GL_ARB_texture_rg */ #ifndef GL_ARB_texture_rgb10_a2ui #define GL_ARB_texture_rgb10_a2ui 1 #endif /* GL_ARB_texture_rgb10_a2ui */ #ifndef GL_ARB_texture_stencil8 #define GL_ARB_texture_stencil8 1 #endif /* GL_ARB_texture_stencil8 */ #ifndef GL_ARB_texture_storage #define GL_ARB_texture_storage 1 #endif /* GL_ARB_texture_storage */ #ifndef GL_ARB_texture_storage_multisample #define GL_ARB_texture_storage_multisample 1 #endif /* GL_ARB_texture_storage_multisample */ #ifndef GL_ARB_texture_swizzle #define GL_ARB_texture_swizzle 1 #endif /* GL_ARB_texture_swizzle */ #ifndef GL_ARB_texture_view #define GL_ARB_texture_view 1 #endif /* GL_ARB_texture_view */ #ifndef GL_ARB_timer_query #define GL_ARB_timer_query 1 #endif /* GL_ARB_timer_query */ #ifndef GL_ARB_transform_feedback2 #define GL_ARB_transform_feedback2 1 #endif /* GL_ARB_transform_feedback2 */ #ifndef GL_ARB_transform_feedback3 #define GL_ARB_transform_feedback3 1 #endif /* GL_ARB_transform_feedback3 */ #ifndef GL_ARB_transform_feedback_instanced #define GL_ARB_transform_feedback_instanced 1 #endif /* GL_ARB_transform_feedback_instanced */ #ifndef GL_ARB_transform_feedback_overflow_query #define GL_ARB_transform_feedback_overflow_query 1 #define GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB 0x82EC #define GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB 0x82ED #endif /* GL_ARB_transform_feedback_overflow_query */ #ifndef GL_ARB_transpose_matrix #define GL_ARB_transpose_matrix 1 #define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3 #define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4 #define GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5 #define GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6 typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glLoadTransposeMatrixfARB (const GLfloat *m); GLAPI void APIENTRY glLoadTransposeMatrixdARB (const GLdouble *m); GLAPI void APIENTRY glMultTransposeMatrixfARB (const GLfloat *m); GLAPI void APIENTRY glMultTransposeMatrixdARB (const GLdouble *m); #endif #endif /* GL_ARB_transpose_matrix */ #ifndef GL_ARB_uniform_buffer_object #define GL_ARB_uniform_buffer_object 1 #endif /* GL_ARB_uniform_buffer_object */ #ifndef GL_ARB_vertex_array_bgra #define GL_ARB_vertex_array_bgra 1 #endif /* GL_ARB_vertex_array_bgra */ #ifndef GL_ARB_vertex_array_object #define GL_ARB_vertex_array_object 1 #endif /* GL_ARB_vertex_array_object */ #ifndef GL_ARB_vertex_attrib_64bit #define GL_ARB_vertex_attrib_64bit 1 #endif /* GL_ARB_vertex_attrib_64bit */ #ifndef GL_ARB_vertex_attrib_binding #define GL_ARB_vertex_attrib_binding 1 #endif /* GL_ARB_vertex_attrib_binding */ #ifndef GL_ARB_vertex_blend #define GL_ARB_vertex_blend 1 #define GL_MAX_VERTEX_UNITS_ARB 0x86A4 #define GL_ACTIVE_VERTEX_UNITS_ARB 0x86A5 #define GL_WEIGHT_SUM_UNITY_ARB 0x86A6 #define GL_VERTEX_BLEND_ARB 0x86A7 #define GL_CURRENT_WEIGHT_ARB 0x86A8 #define GL_WEIGHT_ARRAY_TYPE_ARB 0x86A9 #define GL_WEIGHT_ARRAY_STRIDE_ARB 0x86AA #define GL_WEIGHT_ARRAY_SIZE_ARB 0x86AB #define GL_WEIGHT_ARRAY_POINTER_ARB 0x86AC #define GL_WEIGHT_ARRAY_ARB 0x86AD #define GL_MODELVIEW0_ARB 0x1700 #define GL_MODELVIEW1_ARB 0x850A #define GL_MODELVIEW2_ARB 0x8722 #define GL_MODELVIEW3_ARB 0x8723 #define GL_MODELVIEW4_ARB 0x8724 #define GL_MODELVIEW5_ARB 0x8725 #define GL_MODELVIEW6_ARB 0x8726 #define GL_MODELVIEW7_ARB 0x8727 #define GL_MODELVIEW8_ARB 0x8728 #define GL_MODELVIEW9_ARB 0x8729 #define GL_MODELVIEW10_ARB 0x872A #define GL_MODELVIEW11_ARB 0x872B #define GL_MODELVIEW12_ARB 0x872C #define GL_MODELVIEW13_ARB 0x872D #define GL_MODELVIEW14_ARB 0x872E #define GL_MODELVIEW15_ARB 0x872F #define GL_MODELVIEW16_ARB 0x8730 #define GL_MODELVIEW17_ARB 0x8731 #define GL_MODELVIEW18_ARB 0x8732 #define GL_MODELVIEW19_ARB 0x8733 #define GL_MODELVIEW20_ARB 0x8734 #define GL_MODELVIEW21_ARB 0x8735 #define GL_MODELVIEW22_ARB 0x8736 #define GL_MODELVIEW23_ARB 0x8737 #define GL_MODELVIEW24_ARB 0x8738 #define GL_MODELVIEW25_ARB 0x8739 #define GL_MODELVIEW26_ARB 0x873A #define GL_MODELVIEW27_ARB 0x873B #define GL_MODELVIEW28_ARB 0x873C #define GL_MODELVIEW29_ARB 0x873D #define GL_MODELVIEW30_ARB 0x873E #define GL_MODELVIEW31_ARB 0x873F typedef void (APIENTRYP PFNGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights); typedef void (APIENTRYP PFNGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights); typedef void (APIENTRYP PFNGLWEIGHTIVARBPROC) (GLint size, const GLint *weights); typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights); typedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights); typedef void (APIENTRYP PFNGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights); typedef void (APIENTRYP PFNGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights); typedef void (APIENTRYP PFNGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights); typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glWeightbvARB (GLint size, const GLbyte *weights); GLAPI void APIENTRY glWeightsvARB (GLint size, const GLshort *weights); GLAPI void APIENTRY glWeightivARB (GLint size, const GLint *weights); GLAPI void APIENTRY glWeightfvARB (GLint size, const GLfloat *weights); GLAPI void APIENTRY glWeightdvARB (GLint size, const GLdouble *weights); GLAPI void APIENTRY glWeightubvARB (GLint size, const GLubyte *weights); GLAPI void APIENTRY glWeightusvARB (GLint size, const GLushort *weights); GLAPI void APIENTRY glWeightuivARB (GLint size, const GLuint *weights); GLAPI void APIENTRY glWeightPointerARB (GLint size, GLenum type, GLsizei stride, const void *pointer); GLAPI void APIENTRY glVertexBlendARB (GLint count); #endif #endif /* GL_ARB_vertex_blend */ #ifndef GL_ARB_vertex_buffer_object #define GL_ARB_vertex_buffer_object 1 typedef khronos_ssize_t GLsizeiptrARB; typedef khronos_intptr_t GLintptrARB; #define GL_BUFFER_SIZE_ARB 0x8764 #define GL_BUFFER_USAGE_ARB 0x8765 #define GL_ARRAY_BUFFER_ARB 0x8892 #define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893 #define GL_ARRAY_BUFFER_BINDING_ARB 0x8894 #define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895 #define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896 #define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897 #define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898 #define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899 #define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A #define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B #define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C #define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D #define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E #define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F #define GL_READ_ONLY_ARB 0x88B8 #define GL_WRITE_ONLY_ARB 0x88B9 #define GL_READ_WRITE_ARB 0x88BA #define GL_BUFFER_ACCESS_ARB 0x88BB #define GL_BUFFER_MAPPED_ARB 0x88BC #define GL_BUFFER_MAP_POINTER_ARB 0x88BD #define GL_STREAM_DRAW_ARB 0x88E0 #define GL_STREAM_READ_ARB 0x88E1 #define GL_STREAM_COPY_ARB 0x88E2 #define GL_STATIC_DRAW_ARB 0x88E4 #define GL_STATIC_READ_ARB 0x88E5 #define GL_STATIC_COPY_ARB 0x88E6 #define GL_DYNAMIC_DRAW_ARB 0x88E8 #define GL_DYNAMIC_READ_ARB 0x88E9 #define GL_DYNAMIC_COPY_ARB 0x88EA typedef void (APIENTRYP PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer); typedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers); typedef void (APIENTRYP PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers); typedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const void *data, GLenum usage); typedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void *data); typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, void *data); typedef void *(APIENTRYP PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access); typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC) (GLenum target); typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, void **params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindBufferARB (GLenum target, GLuint buffer); GLAPI void APIENTRY glDeleteBuffersARB (GLsizei n, const GLuint *buffers); GLAPI void APIENTRY glGenBuffersARB (GLsizei n, GLuint *buffers); GLAPI GLboolean APIENTRY glIsBufferARB (GLuint buffer); GLAPI void APIENTRY glBufferDataARB (GLenum target, GLsizeiptrARB size, const void *data, GLenum usage); GLAPI void APIENTRY glBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void *data); GLAPI void APIENTRY glGetBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, void *data); GLAPI void *APIENTRY glMapBufferARB (GLenum target, GLenum access); GLAPI GLboolean APIENTRY glUnmapBufferARB (GLenum target); GLAPI void APIENTRY glGetBufferParameterivARB (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetBufferPointervARB (GLenum target, GLenum pname, void **params); #endif #endif /* GL_ARB_vertex_buffer_object */ #ifndef GL_ARB_vertex_program #define GL_ARB_vertex_program 1 #define GL_COLOR_SUM_ARB 0x8458 #define GL_VERTEX_PROGRAM_ARB 0x8620 #define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622 #define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623 #define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624 #define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625 #define GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626 #define GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642 #define GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643 #define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645 #define GL_MAX_VERTEX_ATTRIBS_ARB 0x8869 #define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A #define GL_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B0 #define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1 #define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2 #define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3 typedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, void **pointer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttrib1dARB (GLuint index, GLdouble x); GLAPI void APIENTRY glVertexAttrib1dvARB (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib1fARB (GLuint index, GLfloat x); GLAPI void APIENTRY glVertexAttrib1fvARB (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib1sARB (GLuint index, GLshort x); GLAPI void APIENTRY glVertexAttrib1svARB (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib2dARB (GLuint index, GLdouble x, GLdouble y); GLAPI void APIENTRY glVertexAttrib2dvARB (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib2fARB (GLuint index, GLfloat x, GLfloat y); GLAPI void APIENTRY glVertexAttrib2fvARB (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib2sARB (GLuint index, GLshort x, GLshort y); GLAPI void APIENTRY glVertexAttrib2svARB (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib3dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glVertexAttrib3dvARB (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib3fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glVertexAttrib3fvARB (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib3sARB (GLuint index, GLshort x, GLshort y, GLshort z); GLAPI void APIENTRY glVertexAttrib3svARB (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib4NbvARB (GLuint index, const GLbyte *v); GLAPI void APIENTRY glVertexAttrib4NivARB (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttrib4NsvARB (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib4NubARB (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); GLAPI void APIENTRY glVertexAttrib4NubvARB (GLuint index, const GLubyte *v); GLAPI void APIENTRY glVertexAttrib4NuivARB (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttrib4NusvARB (GLuint index, const GLushort *v); GLAPI void APIENTRY glVertexAttrib4bvARB (GLuint index, const GLbyte *v); GLAPI void APIENTRY glVertexAttrib4dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glVertexAttrib4dvARB (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib4fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glVertexAttrib4fvARB (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib4ivARB (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttrib4sARB (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); GLAPI void APIENTRY glVertexAttrib4svARB (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib4ubvARB (GLuint index, const GLubyte *v); GLAPI void APIENTRY glVertexAttrib4uivARB (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttrib4usvARB (GLuint index, const GLushort *v); GLAPI void APIENTRY glVertexAttribPointerARB (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); GLAPI void APIENTRY glEnableVertexAttribArrayARB (GLuint index); GLAPI void APIENTRY glDisableVertexAttribArrayARB (GLuint index); GLAPI void APIENTRY glGetVertexAttribdvARB (GLuint index, GLenum pname, GLdouble *params); GLAPI void APIENTRY glGetVertexAttribfvARB (GLuint index, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetVertexAttribivARB (GLuint index, GLenum pname, GLint *params); GLAPI void APIENTRY glGetVertexAttribPointervARB (GLuint index, GLenum pname, void **pointer); #endif #endif /* GL_ARB_vertex_program */ #ifndef GL_ARB_vertex_shader #define GL_ARB_vertex_shader 1 #define GL_VERTEX_SHADER_ARB 0x8B31 #define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A #define GL_MAX_VARYING_FLOATS_ARB 0x8B4B #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D #define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89 #define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name); typedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindAttribLocationARB (GLhandleARB programObj, GLuint index, const GLcharARB *name); GLAPI void APIENTRY glGetActiveAttribARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); GLAPI GLint APIENTRY glGetAttribLocationARB (GLhandleARB programObj, const GLcharARB *name); #endif #endif /* GL_ARB_vertex_shader */ #ifndef GL_ARB_vertex_type_10f_11f_11f_rev #define GL_ARB_vertex_type_10f_11f_11f_rev 1 #endif /* GL_ARB_vertex_type_10f_11f_11f_rev */ #ifndef GL_ARB_vertex_type_2_10_10_10_rev #define GL_ARB_vertex_type_2_10_10_10_rev 1 #endif /* GL_ARB_vertex_type_2_10_10_10_rev */ #ifndef GL_ARB_viewport_array #define GL_ARB_viewport_array 1 typedef void (APIENTRYP PFNGLDEPTHRANGEARRAYDVNVPROC) (GLuint first, GLsizei count, const GLdouble *v); typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDDNVPROC) (GLuint index, GLdouble n, GLdouble f); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDepthRangeArraydvNV (GLuint first, GLsizei count, const GLdouble *v); GLAPI void APIENTRY glDepthRangeIndexeddNV (GLuint index, GLdouble n, GLdouble f); #endif #endif /* GL_ARB_viewport_array */ #ifndef GL_ARB_window_pos #define GL_ARB_window_pos 1 typedef void (APIENTRYP PFNGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLWINDOWPOS2DVARBPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLWINDOWPOS2FVARBPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS2IARBPROC) (GLint x, GLint y); typedef void (APIENTRYP PFNGLWINDOWPOS2IVARBPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y); typedef void (APIENTRYP PFNGLWINDOWPOS2SVARBPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLWINDOWPOS3DVARBPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLWINDOWPOS3FVARBPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLWINDOWPOS3IVARBPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLWINDOWPOS3SVARBPROC) (const GLshort *v); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glWindowPos2dARB (GLdouble x, GLdouble y); GLAPI void APIENTRY glWindowPos2dvARB (const GLdouble *v); GLAPI void APIENTRY glWindowPos2fARB (GLfloat x, GLfloat y); GLAPI void APIENTRY glWindowPos2fvARB (const GLfloat *v); GLAPI void APIENTRY glWindowPos2iARB (GLint x, GLint y); GLAPI void APIENTRY glWindowPos2ivARB (const GLint *v); GLAPI void APIENTRY glWindowPos2sARB (GLshort x, GLshort y); GLAPI void APIENTRY glWindowPos2svARB (const GLshort *v); GLAPI void APIENTRY glWindowPos3dARB (GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glWindowPos3dvARB (const GLdouble *v); GLAPI void APIENTRY glWindowPos3fARB (GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glWindowPos3fvARB (const GLfloat *v); GLAPI void APIENTRY glWindowPos3iARB (GLint x, GLint y, GLint z); GLAPI void APIENTRY glWindowPos3ivARB (const GLint *v); GLAPI void APIENTRY glWindowPos3sARB (GLshort x, GLshort y, GLshort z); GLAPI void APIENTRY glWindowPos3svARB (const GLshort *v); #endif #endif /* GL_ARB_window_pos */ #ifndef GL_KHR_blend_equation_advanced #define GL_KHR_blend_equation_advanced 1 #define GL_MULTIPLY_KHR 0x9294 #define GL_SCREEN_KHR 0x9295 #define GL_OVERLAY_KHR 0x9296 #define GL_DARKEN_KHR 0x9297 #define GL_LIGHTEN_KHR 0x9298 #define GL_COLORDODGE_KHR 0x9299 #define GL_COLORBURN_KHR 0x929A #define GL_HARDLIGHT_KHR 0x929B #define GL_SOFTLIGHT_KHR 0x929C #define GL_DIFFERENCE_KHR 0x929E #define GL_EXCLUSION_KHR 0x92A0 #define GL_HSL_HUE_KHR 0x92AD #define GL_HSL_SATURATION_KHR 0x92AE #define GL_HSL_COLOR_KHR 0x92AF #define GL_HSL_LUMINOSITY_KHR 0x92B0 typedef void (APIENTRYP PFNGLBLENDBARRIERKHRPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendBarrierKHR (void); #endif #endif /* GL_KHR_blend_equation_advanced */ #ifndef GL_KHR_blend_equation_advanced_coherent #define GL_KHR_blend_equation_advanced_coherent 1 #define GL_BLEND_ADVANCED_COHERENT_KHR 0x9285 #endif /* GL_KHR_blend_equation_advanced_coherent */ #ifndef GL_KHR_context_flush_control #define GL_KHR_context_flush_control 1 #endif /* GL_KHR_context_flush_control */ #ifndef GL_KHR_debug #define GL_KHR_debug 1 #endif /* GL_KHR_debug */ #ifndef GL_KHR_no_error #define GL_KHR_no_error 1 #define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008 #endif /* GL_KHR_no_error */ #ifndef GL_KHR_parallel_shader_compile #define GL_KHR_parallel_shader_compile 1 #define GL_MAX_SHADER_COMPILER_THREADS_KHR 0x91B0 #define GL_COMPLETION_STATUS_KHR 0x91B1 typedef void (APIENTRYP PFNGLMAXSHADERCOMPILERTHREADSKHRPROC) (GLuint count); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMaxShaderCompilerThreadsKHR (GLuint count); #endif #endif /* GL_KHR_parallel_shader_compile */ #ifndef GL_KHR_robust_buffer_access_behavior #define GL_KHR_robust_buffer_access_behavior 1 #endif /* GL_KHR_robust_buffer_access_behavior */ #ifndef GL_KHR_robustness #define GL_KHR_robustness 1 #define GL_CONTEXT_ROBUST_ACCESS 0x90F3 #endif /* GL_KHR_robustness */ #ifndef GL_KHR_shader_subgroup #define GL_KHR_shader_subgroup 1 #define GL_SUBGROUP_SIZE_KHR 0x9532 #define GL_SUBGROUP_SUPPORTED_STAGES_KHR 0x9533 #define GL_SUBGROUP_SUPPORTED_FEATURES_KHR 0x9534 #define GL_SUBGROUP_QUAD_ALL_STAGES_KHR 0x9535 #define GL_SUBGROUP_FEATURE_BASIC_BIT_KHR 0x00000001 #define GL_SUBGROUP_FEATURE_VOTE_BIT_KHR 0x00000002 #define GL_SUBGROUP_FEATURE_ARITHMETIC_BIT_KHR 0x00000004 #define GL_SUBGROUP_FEATURE_BALLOT_BIT_KHR 0x00000008 #define GL_SUBGROUP_FEATURE_SHUFFLE_BIT_KHR 0x00000010 #define GL_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT_KHR 0x00000020 #define GL_SUBGROUP_FEATURE_CLUSTERED_BIT_KHR 0x00000040 #define GL_SUBGROUP_FEATURE_QUAD_BIT_KHR 0x00000080 #endif /* GL_KHR_shader_subgroup */ #ifndef GL_KHR_texture_compression_astc_hdr #define GL_KHR_texture_compression_astc_hdr 1 #define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 #define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1 #define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2 #define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3 #define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4 #define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5 #define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6 #define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7 #define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8 #define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9 #define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA #define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB #define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC #define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD #endif /* GL_KHR_texture_compression_astc_hdr */ #ifndef GL_KHR_texture_compression_astc_ldr #define GL_KHR_texture_compression_astc_ldr 1 #endif /* GL_KHR_texture_compression_astc_ldr */ #ifndef GL_KHR_texture_compression_astc_sliced_3d #define GL_KHR_texture_compression_astc_sliced_3d 1 #endif /* GL_KHR_texture_compression_astc_sliced_3d */ #ifndef GL_OES_byte_coordinates #define GL_OES_byte_coordinates 1 typedef void (APIENTRYP PFNGLMULTITEXCOORD1BOESPROC) (GLenum texture, GLbyte s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1BVOESPROC) (GLenum texture, const GLbyte *coords); typedef void (APIENTRYP PFNGLMULTITEXCOORD2BOESPROC) (GLenum texture, GLbyte s, GLbyte t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2BVOESPROC) (GLenum texture, const GLbyte *coords); typedef void (APIENTRYP PFNGLMULTITEXCOORD3BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3BVOESPROC) (GLenum texture, const GLbyte *coords); typedef void (APIENTRYP PFNGLMULTITEXCOORD4BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r, GLbyte q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4BVOESPROC) (GLenum texture, const GLbyte *coords); typedef void (APIENTRYP PFNGLTEXCOORD1BOESPROC) (GLbyte s); typedef void (APIENTRYP PFNGLTEXCOORD1BVOESPROC) (const GLbyte *coords); typedef void (APIENTRYP PFNGLTEXCOORD2BOESPROC) (GLbyte s, GLbyte t); typedef void (APIENTRYP PFNGLTEXCOORD2BVOESPROC) (const GLbyte *coords); typedef void (APIENTRYP PFNGLTEXCOORD3BOESPROC) (GLbyte s, GLbyte t, GLbyte r); typedef void (APIENTRYP PFNGLTEXCOORD3BVOESPROC) (const GLbyte *coords); typedef void (APIENTRYP PFNGLTEXCOORD4BOESPROC) (GLbyte s, GLbyte t, GLbyte r, GLbyte q); typedef void (APIENTRYP PFNGLTEXCOORD4BVOESPROC) (const GLbyte *coords); typedef void (APIENTRYP PFNGLVERTEX2BOESPROC) (GLbyte x, GLbyte y); typedef void (APIENTRYP PFNGLVERTEX2BVOESPROC) (const GLbyte *coords); typedef void (APIENTRYP PFNGLVERTEX3BOESPROC) (GLbyte x, GLbyte y, GLbyte z); typedef void (APIENTRYP PFNGLVERTEX3BVOESPROC) (const GLbyte *coords); typedef void (APIENTRYP PFNGLVERTEX4BOESPROC) (GLbyte x, GLbyte y, GLbyte z, GLbyte w); typedef void (APIENTRYP PFNGLVERTEX4BVOESPROC) (const GLbyte *coords); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMultiTexCoord1bOES (GLenum texture, GLbyte s); GLAPI void APIENTRY glMultiTexCoord1bvOES (GLenum texture, const GLbyte *coords); GLAPI void APIENTRY glMultiTexCoord2bOES (GLenum texture, GLbyte s, GLbyte t); GLAPI void APIENTRY glMultiTexCoord2bvOES (GLenum texture, const GLbyte *coords); GLAPI void APIENTRY glMultiTexCoord3bOES (GLenum texture, GLbyte s, GLbyte t, GLbyte r); GLAPI void APIENTRY glMultiTexCoord3bvOES (GLenum texture, const GLbyte *coords); GLAPI void APIENTRY glMultiTexCoord4bOES (GLenum texture, GLbyte s, GLbyte t, GLbyte r, GLbyte q); GLAPI void APIENTRY glMultiTexCoord4bvOES (GLenum texture, const GLbyte *coords); GLAPI void APIENTRY glTexCoord1bOES (GLbyte s); GLAPI void APIENTRY glTexCoord1bvOES (const GLbyte *coords); GLAPI void APIENTRY glTexCoord2bOES (GLbyte s, GLbyte t); GLAPI void APIENTRY glTexCoord2bvOES (const GLbyte *coords); GLAPI void APIENTRY glTexCoord3bOES (GLbyte s, GLbyte t, GLbyte r); GLAPI void APIENTRY glTexCoord3bvOES (const GLbyte *coords); GLAPI void APIENTRY glTexCoord4bOES (GLbyte s, GLbyte t, GLbyte r, GLbyte q); GLAPI void APIENTRY glTexCoord4bvOES (const GLbyte *coords); GLAPI void APIENTRY glVertex2bOES (GLbyte x, GLbyte y); GLAPI void APIENTRY glVertex2bvOES (const GLbyte *coords); GLAPI void APIENTRY glVertex3bOES (GLbyte x, GLbyte y, GLbyte z); GLAPI void APIENTRY glVertex3bvOES (const GLbyte *coords); GLAPI void APIENTRY glVertex4bOES (GLbyte x, GLbyte y, GLbyte z, GLbyte w); GLAPI void APIENTRY glVertex4bvOES (const GLbyte *coords); #endif #endif /* GL_OES_byte_coordinates */ #ifndef GL_OES_compressed_paletted_texture #define GL_OES_compressed_paletted_texture 1 #define GL_PALETTE4_RGB8_OES 0x8B90 #define GL_PALETTE4_RGBA8_OES 0x8B91 #define GL_PALETTE4_R5_G6_B5_OES 0x8B92 #define GL_PALETTE4_RGBA4_OES 0x8B93 #define GL_PALETTE4_RGB5_A1_OES 0x8B94 #define GL_PALETTE8_RGB8_OES 0x8B95 #define GL_PALETTE8_RGBA8_OES 0x8B96 #define GL_PALETTE8_R5_G6_B5_OES 0x8B97 #define GL_PALETTE8_RGBA4_OES 0x8B98 #define GL_PALETTE8_RGB5_A1_OES 0x8B99 #endif /* GL_OES_compressed_paletted_texture */ #ifndef GL_OES_fixed_point #define GL_OES_fixed_point 1 typedef khronos_int32_t GLfixed; #define GL_FIXED_OES 0x140C typedef void (APIENTRYP PFNGLALPHAFUNCXOESPROC) (GLenum func, GLfixed ref); typedef void (APIENTRYP PFNGLCLEARCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); typedef void (APIENTRYP PFNGLCLEARDEPTHXOESPROC) (GLfixed depth); typedef void (APIENTRYP PFNGLCLIPPLANEXOESPROC) (GLenum plane, const GLfixed *equation); typedef void (APIENTRYP PFNGLCOLOR4XOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); typedef void (APIENTRYP PFNGLDEPTHRANGEXOESPROC) (GLfixed n, GLfixed f); typedef void (APIENTRYP PFNGLFOGXOESPROC) (GLenum pname, GLfixed param); typedef void (APIENTRYP PFNGLFOGXVOESPROC) (GLenum pname, const GLfixed *param); typedef void (APIENTRYP PFNGLFRUSTUMXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); typedef void (APIENTRYP PFNGLGETCLIPPLANEXOESPROC) (GLenum plane, GLfixed *equation); typedef void (APIENTRYP PFNGLGETFIXEDVOESPROC) (GLenum pname, GLfixed *params); typedef void (APIENTRYP PFNGLGETTEXENVXVOESPROC) (GLenum target, GLenum pname, GLfixed *params); typedef void (APIENTRYP PFNGLGETTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params); typedef void (APIENTRYP PFNGLLIGHTMODELXOESPROC) (GLenum pname, GLfixed param); typedef void (APIENTRYP PFNGLLIGHTMODELXVOESPROC) (GLenum pname, const GLfixed *param); typedef void (APIENTRYP PFNGLLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed param); typedef void (APIENTRYP PFNGLLIGHTXVOESPROC) (GLenum light, GLenum pname, const GLfixed *params); typedef void (APIENTRYP PFNGLLINEWIDTHXOESPROC) (GLfixed width); typedef void (APIENTRYP PFNGLLOADMATRIXXOESPROC) (const GLfixed *m); typedef void (APIENTRYP PFNGLMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param); typedef void (APIENTRYP PFNGLMATERIALXVOESPROC) (GLenum face, GLenum pname, const GLfixed *param); typedef void (APIENTRYP PFNGLMULTMATRIXXOESPROC) (const GLfixed *m); typedef void (APIENTRYP PFNGLMULTITEXCOORD4XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q); typedef void (APIENTRYP PFNGLNORMAL3XOESPROC) (GLfixed nx, GLfixed ny, GLfixed nz); typedef void (APIENTRYP PFNGLORTHOXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); typedef void (APIENTRYP PFNGLPOINTPARAMETERXVOESPROC) (GLenum pname, const GLfixed *params); typedef void (APIENTRYP PFNGLPOINTSIZEXOESPROC) (GLfixed size); typedef void (APIENTRYP PFNGLPOLYGONOFFSETXOESPROC) (GLfixed factor, GLfixed units); typedef void (APIENTRYP PFNGLROTATEXOESPROC) (GLfixed angle, GLfixed x, GLfixed y, GLfixed z); typedef void (APIENTRYP PFNGLSCALEXOESPROC) (GLfixed x, GLfixed y, GLfixed z); typedef void (APIENTRYP PFNGLTEXENVXOESPROC) (GLenum target, GLenum pname, GLfixed param); typedef void (APIENTRYP PFNGLTEXENVXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params); typedef void (APIENTRYP PFNGLTEXPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param); typedef void (APIENTRYP PFNGLTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params); typedef void (APIENTRYP PFNGLTRANSLATEXOESPROC) (GLfixed x, GLfixed y, GLfixed z); typedef void (APIENTRYP PFNGLACCUMXOESPROC) (GLenum op, GLfixed value); typedef void (APIENTRYP PFNGLBITMAPXOESPROC) (GLsizei width, GLsizei height, GLfixed xorig, GLfixed yorig, GLfixed xmove, GLfixed ymove, const GLubyte *bitmap); typedef void (APIENTRYP PFNGLBLENDCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); typedef void (APIENTRYP PFNGLCLEARACCUMXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); typedef void (APIENTRYP PFNGLCOLOR3XOESPROC) (GLfixed red, GLfixed green, GLfixed blue); typedef void (APIENTRYP PFNGLCOLOR3XVOESPROC) (const GLfixed *components); typedef void (APIENTRYP PFNGLCOLOR4XVOESPROC) (const GLfixed *components); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params); typedef void (APIENTRYP PFNGLEVALCOORD1XOESPROC) (GLfixed u); typedef void (APIENTRYP PFNGLEVALCOORD1XVOESPROC) (const GLfixed *coords); typedef void (APIENTRYP PFNGLEVALCOORD2XOESPROC) (GLfixed u, GLfixed v); typedef void (APIENTRYP PFNGLEVALCOORD2XVOESPROC) (const GLfixed *coords); typedef void (APIENTRYP PFNGLFEEDBACKBUFFERXOESPROC) (GLsizei n, GLenum type, const GLfixed *buffer); typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params); typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params); typedef void (APIENTRYP PFNGLGETLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed *params); typedef void (APIENTRYP PFNGLGETMAPXVOESPROC) (GLenum target, GLenum query, GLfixed *v); typedef void (APIENTRYP PFNGLGETMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param); typedef void (APIENTRYP PFNGLGETPIXELMAPXVPROC) (GLenum map, GLint size, GLfixed *values); typedef void (APIENTRYP PFNGLGETTEXGENXVOESPROC) (GLenum coord, GLenum pname, GLfixed *params); typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERXVOESPROC) (GLenum target, GLint level, GLenum pname, GLfixed *params); typedef void (APIENTRYP PFNGLINDEXXOESPROC) (GLfixed component); typedef void (APIENTRYP PFNGLINDEXXVOESPROC) (const GLfixed *component); typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXXOESPROC) (const GLfixed *m); typedef void (APIENTRYP PFNGLMAP1XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint stride, GLint order, GLfixed points); typedef void (APIENTRYP PFNGLMAP2XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint ustride, GLint uorder, GLfixed v1, GLfixed v2, GLint vstride, GLint vorder, GLfixed points); typedef void (APIENTRYP PFNGLMAPGRID1XOESPROC) (GLint n, GLfixed u1, GLfixed u2); typedef void (APIENTRYP PFNGLMAPGRID2XOESPROC) (GLint n, GLfixed u1, GLfixed u2, GLfixed v1, GLfixed v2); typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXXOESPROC) (const GLfixed *m); typedef void (APIENTRYP PFNGLMULTITEXCOORD1XOESPROC) (GLenum texture, GLfixed s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1XVOESPROC) (GLenum texture, const GLfixed *coords); typedef void (APIENTRYP PFNGLMULTITEXCOORD2XOESPROC) (GLenum texture, GLfixed s, GLfixed t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2XVOESPROC) (GLenum texture, const GLfixed *coords); typedef void (APIENTRYP PFNGLMULTITEXCOORD3XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3XVOESPROC) (GLenum texture, const GLfixed *coords); typedef void (APIENTRYP PFNGLMULTITEXCOORD4XVOESPROC) (GLenum texture, const GLfixed *coords); typedef void (APIENTRYP PFNGLNORMAL3XVOESPROC) (const GLfixed *coords); typedef void (APIENTRYP PFNGLPASSTHROUGHXOESPROC) (GLfixed token); typedef void (APIENTRYP PFNGLPIXELMAPXPROC) (GLenum map, GLint size, const GLfixed *values); typedef void (APIENTRYP PFNGLPIXELSTOREXPROC) (GLenum pname, GLfixed param); typedef void (APIENTRYP PFNGLPIXELTRANSFERXOESPROC) (GLenum pname, GLfixed param); typedef void (APIENTRYP PFNGLPIXELZOOMXOESPROC) (GLfixed xfactor, GLfixed yfactor); typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESXOESPROC) (GLsizei n, const GLuint *textures, const GLfixed *priorities); typedef void (APIENTRYP PFNGLRASTERPOS2XOESPROC) (GLfixed x, GLfixed y); typedef void (APIENTRYP PFNGLRASTERPOS2XVOESPROC) (const GLfixed *coords); typedef void (APIENTRYP PFNGLRASTERPOS3XOESPROC) (GLfixed x, GLfixed y, GLfixed z); typedef void (APIENTRYP PFNGLRASTERPOS3XVOESPROC) (const GLfixed *coords); typedef void (APIENTRYP PFNGLRASTERPOS4XOESPROC) (GLfixed x, GLfixed y, GLfixed z, GLfixed w); typedef void (APIENTRYP PFNGLRASTERPOS4XVOESPROC) (const GLfixed *coords); typedef void (APIENTRYP PFNGLRECTXOESPROC) (GLfixed x1, GLfixed y1, GLfixed x2, GLfixed y2); typedef void (APIENTRYP PFNGLRECTXVOESPROC) (const GLfixed *v1, const GLfixed *v2); typedef void (APIENTRYP PFNGLTEXCOORD1XOESPROC) (GLfixed s); typedef void (APIENTRYP PFNGLTEXCOORD1XVOESPROC) (const GLfixed *coords); typedef void (APIENTRYP PFNGLTEXCOORD2XOESPROC) (GLfixed s, GLfixed t); typedef void (APIENTRYP PFNGLTEXCOORD2XVOESPROC) (const GLfixed *coords); typedef void (APIENTRYP PFNGLTEXCOORD3XOESPROC) (GLfixed s, GLfixed t, GLfixed r); typedef void (APIENTRYP PFNGLTEXCOORD3XVOESPROC) (const GLfixed *coords); typedef void (APIENTRYP PFNGLTEXCOORD4XOESPROC) (GLfixed s, GLfixed t, GLfixed r, GLfixed q); typedef void (APIENTRYP PFNGLTEXCOORD4XVOESPROC) (const GLfixed *coords); typedef void (APIENTRYP PFNGLTEXGENXOESPROC) (GLenum coord, GLenum pname, GLfixed param); typedef void (APIENTRYP PFNGLTEXGENXVOESPROC) (GLenum coord, GLenum pname, const GLfixed *params); typedef void (APIENTRYP PFNGLVERTEX2XOESPROC) (GLfixed x); typedef void (APIENTRYP PFNGLVERTEX2XVOESPROC) (const GLfixed *coords); typedef void (APIENTRYP PFNGLVERTEX3XOESPROC) (GLfixed x, GLfixed y); typedef void (APIENTRYP PFNGLVERTEX3XVOESPROC) (const GLfixed *coords); typedef void (APIENTRYP PFNGLVERTEX4XOESPROC) (GLfixed x, GLfixed y, GLfixed z); typedef void (APIENTRYP PFNGLVERTEX4XVOESPROC) (const GLfixed *coords); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glAlphaFuncxOES (GLenum func, GLfixed ref); GLAPI void APIENTRY glClearColorxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); GLAPI void APIENTRY glClearDepthxOES (GLfixed depth); GLAPI void APIENTRY glClipPlanexOES (GLenum plane, const GLfixed *equation); GLAPI void APIENTRY glColor4xOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); GLAPI void APIENTRY glDepthRangexOES (GLfixed n, GLfixed f); GLAPI void APIENTRY glFogxOES (GLenum pname, GLfixed param); GLAPI void APIENTRY glFogxvOES (GLenum pname, const GLfixed *param); GLAPI void APIENTRY glFrustumxOES (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); GLAPI void APIENTRY glGetClipPlanexOES (GLenum plane, GLfixed *equation); GLAPI void APIENTRY glGetFixedvOES (GLenum pname, GLfixed *params); GLAPI void APIENTRY glGetTexEnvxvOES (GLenum target, GLenum pname, GLfixed *params); GLAPI void APIENTRY glGetTexParameterxvOES (GLenum target, GLenum pname, GLfixed *params); GLAPI void APIENTRY glLightModelxOES (GLenum pname, GLfixed param); GLAPI void APIENTRY glLightModelxvOES (GLenum pname, const GLfixed *param); GLAPI void APIENTRY glLightxOES (GLenum light, GLenum pname, GLfixed param); GLAPI void APIENTRY glLightxvOES (GLenum light, GLenum pname, const GLfixed *params); GLAPI void APIENTRY glLineWidthxOES (GLfixed width); GLAPI void APIENTRY glLoadMatrixxOES (const GLfixed *m); GLAPI void APIENTRY glMaterialxOES (GLenum face, GLenum pname, GLfixed param); GLAPI void APIENTRY glMaterialxvOES (GLenum face, GLenum pname, const GLfixed *param); GLAPI void APIENTRY glMultMatrixxOES (const GLfixed *m); GLAPI void APIENTRY glMultiTexCoord4xOES (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q); GLAPI void APIENTRY glNormal3xOES (GLfixed nx, GLfixed ny, GLfixed nz); GLAPI void APIENTRY glOrthoxOES (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); GLAPI void APIENTRY glPointParameterxvOES (GLenum pname, const GLfixed *params); GLAPI void APIENTRY glPointSizexOES (GLfixed size); GLAPI void APIENTRY glPolygonOffsetxOES (GLfixed factor, GLfixed units); GLAPI void APIENTRY glRotatexOES (GLfixed angle, GLfixed x, GLfixed y, GLfixed z); GLAPI void APIENTRY glScalexOES (GLfixed x, GLfixed y, GLfixed z); GLAPI void APIENTRY glTexEnvxOES (GLenum target, GLenum pname, GLfixed param); GLAPI void APIENTRY glTexEnvxvOES (GLenum target, GLenum pname, const GLfixed *params); GLAPI void APIENTRY glTexParameterxOES (GLenum target, GLenum pname, GLfixed param); GLAPI void APIENTRY glTexParameterxvOES (GLenum target, GLenum pname, const GLfixed *params); GLAPI void APIENTRY glTranslatexOES (GLfixed x, GLfixed y, GLfixed z); GLAPI void APIENTRY glAccumxOES (GLenum op, GLfixed value); GLAPI void APIENTRY glBitmapxOES (GLsizei width, GLsizei height, GLfixed xorig, GLfixed yorig, GLfixed xmove, GLfixed ymove, const GLubyte *bitmap); GLAPI void APIENTRY glBlendColorxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); GLAPI void APIENTRY glClearAccumxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); GLAPI void APIENTRY glColor3xOES (GLfixed red, GLfixed green, GLfixed blue); GLAPI void APIENTRY glColor3xvOES (const GLfixed *components); GLAPI void APIENTRY glColor4xvOES (const GLfixed *components); GLAPI void APIENTRY glConvolutionParameterxOES (GLenum target, GLenum pname, GLfixed param); GLAPI void APIENTRY glConvolutionParameterxvOES (GLenum target, GLenum pname, const GLfixed *params); GLAPI void APIENTRY glEvalCoord1xOES (GLfixed u); GLAPI void APIENTRY glEvalCoord1xvOES (const GLfixed *coords); GLAPI void APIENTRY glEvalCoord2xOES (GLfixed u, GLfixed v); GLAPI void APIENTRY glEvalCoord2xvOES (const GLfixed *coords); GLAPI void APIENTRY glFeedbackBufferxOES (GLsizei n, GLenum type, const GLfixed *buffer); GLAPI void APIENTRY glGetConvolutionParameterxvOES (GLenum target, GLenum pname, GLfixed *params); GLAPI void APIENTRY glGetHistogramParameterxvOES (GLenum target, GLenum pname, GLfixed *params); GLAPI void APIENTRY glGetLightxOES (GLenum light, GLenum pname, GLfixed *params); GLAPI void APIENTRY glGetMapxvOES (GLenum target, GLenum query, GLfixed *v); GLAPI void APIENTRY glGetMaterialxOES (GLenum face, GLenum pname, GLfixed param); GLAPI void APIENTRY glGetPixelMapxv (GLenum map, GLint size, GLfixed *values); GLAPI void APIENTRY glGetTexGenxvOES (GLenum coord, GLenum pname, GLfixed *params); GLAPI void APIENTRY glGetTexLevelParameterxvOES (GLenum target, GLint level, GLenum pname, GLfixed *params); GLAPI void APIENTRY glIndexxOES (GLfixed component); GLAPI void APIENTRY glIndexxvOES (const GLfixed *component); GLAPI void APIENTRY glLoadTransposeMatrixxOES (const GLfixed *m); GLAPI void APIENTRY glMap1xOES (GLenum target, GLfixed u1, GLfixed u2, GLint stride, GLint order, GLfixed points); GLAPI void APIENTRY glMap2xOES (GLenum target, GLfixed u1, GLfixed u2, GLint ustride, GLint uorder, GLfixed v1, GLfixed v2, GLint vstride, GLint vorder, GLfixed points); GLAPI void APIENTRY glMapGrid1xOES (GLint n, GLfixed u1, GLfixed u2); GLAPI void APIENTRY glMapGrid2xOES (GLint n, GLfixed u1, GLfixed u2, GLfixed v1, GLfixed v2); GLAPI void APIENTRY glMultTransposeMatrixxOES (const GLfixed *m); GLAPI void APIENTRY glMultiTexCoord1xOES (GLenum texture, GLfixed s); GLAPI void APIENTRY glMultiTexCoord1xvOES (GLenum texture, const GLfixed *coords); GLAPI void APIENTRY glMultiTexCoord2xOES (GLenum texture, GLfixed s, GLfixed t); GLAPI void APIENTRY glMultiTexCoord2xvOES (GLenum texture, const GLfixed *coords); GLAPI void APIENTRY glMultiTexCoord3xOES (GLenum texture, GLfixed s, GLfixed t, GLfixed r); GLAPI void APIENTRY glMultiTexCoord3xvOES (GLenum texture, const GLfixed *coords); GLAPI void APIENTRY glMultiTexCoord4xvOES (GLenum texture, const GLfixed *coords); GLAPI void APIENTRY glNormal3xvOES (const GLfixed *coords); GLAPI void APIENTRY glPassThroughxOES (GLfixed token); GLAPI void APIENTRY glPixelMapx (GLenum map, GLint size, const GLfixed *values); GLAPI void APIENTRY glPixelStorex (GLenum pname, GLfixed param); GLAPI void APIENTRY glPixelTransferxOES (GLenum pname, GLfixed param); GLAPI void APIENTRY glPixelZoomxOES (GLfixed xfactor, GLfixed yfactor); GLAPI void APIENTRY glPrioritizeTexturesxOES (GLsizei n, const GLuint *textures, const GLfixed *priorities); GLAPI void APIENTRY glRasterPos2xOES (GLfixed x, GLfixed y); GLAPI void APIENTRY glRasterPos2xvOES (const GLfixed *coords); GLAPI void APIENTRY glRasterPos3xOES (GLfixed x, GLfixed y, GLfixed z); GLAPI void APIENTRY glRasterPos3xvOES (const GLfixed *coords); GLAPI void APIENTRY glRasterPos4xOES (GLfixed x, GLfixed y, GLfixed z, GLfixed w); GLAPI void APIENTRY glRasterPos4xvOES (const GLfixed *coords); GLAPI void APIENTRY glRectxOES (GLfixed x1, GLfixed y1, GLfixed x2, GLfixed y2); GLAPI void APIENTRY glRectxvOES (const GLfixed *v1, const GLfixed *v2); GLAPI void APIENTRY glTexCoord1xOES (GLfixed s); GLAPI void APIENTRY glTexCoord1xvOES (const GLfixed *coords); GLAPI void APIENTRY glTexCoord2xOES (GLfixed s, GLfixed t); GLAPI void APIENTRY glTexCoord2xvOES (const GLfixed *coords); GLAPI void APIENTRY glTexCoord3xOES (GLfixed s, GLfixed t, GLfixed r); GLAPI void APIENTRY glTexCoord3xvOES (const GLfixed *coords); GLAPI void APIENTRY glTexCoord4xOES (GLfixed s, GLfixed t, GLfixed r, GLfixed q); GLAPI void APIENTRY glTexCoord4xvOES (const GLfixed *coords); GLAPI void APIENTRY glTexGenxOES (GLenum coord, GLenum pname, GLfixed param); GLAPI void APIENTRY glTexGenxvOES (GLenum coord, GLenum pname, const GLfixed *params); GLAPI void APIENTRY glVertex2xOES (GLfixed x); GLAPI void APIENTRY glVertex2xvOES (const GLfixed *coords); GLAPI void APIENTRY glVertex3xOES (GLfixed x, GLfixed y); GLAPI void APIENTRY glVertex3xvOES (const GLfixed *coords); GLAPI void APIENTRY glVertex4xOES (GLfixed x, GLfixed y, GLfixed z); GLAPI void APIENTRY glVertex4xvOES (const GLfixed *coords); #endif #endif /* GL_OES_fixed_point */ #ifndef GL_OES_query_matrix #define GL_OES_query_matrix 1 typedef GLbitfield (APIENTRYP PFNGLQUERYMATRIXXOESPROC) (GLfixed *mantissa, GLint *exponent); #ifdef GL_GLEXT_PROTOTYPES GLAPI GLbitfield APIENTRY glQueryMatrixxOES (GLfixed *mantissa, GLint *exponent); #endif #endif /* GL_OES_query_matrix */ #ifndef GL_OES_read_format #define GL_OES_read_format 1 #define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A #define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B #endif /* GL_OES_read_format */ #ifndef GL_OES_single_precision #define GL_OES_single_precision 1 typedef void (APIENTRYP PFNGLCLEARDEPTHFOESPROC) (GLclampf depth); typedef void (APIENTRYP PFNGLCLIPPLANEFOESPROC) (GLenum plane, const GLfloat *equation); typedef void (APIENTRYP PFNGLDEPTHRANGEFOESPROC) (GLclampf n, GLclampf f); typedef void (APIENTRYP PFNGLFRUSTUMFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f); typedef void (APIENTRYP PFNGLGETCLIPPLANEFOESPROC) (GLenum plane, GLfloat *equation); typedef void (APIENTRYP PFNGLORTHOFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glClearDepthfOES (GLclampf depth); GLAPI void APIENTRY glClipPlanefOES (GLenum plane, const GLfloat *equation); GLAPI void APIENTRY glDepthRangefOES (GLclampf n, GLclampf f); GLAPI void APIENTRY glFrustumfOES (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f); GLAPI void APIENTRY glGetClipPlanefOES (GLenum plane, GLfloat *equation); GLAPI void APIENTRY glOrthofOES (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f); #endif #endif /* GL_OES_single_precision */ #ifndef GL_3DFX_multisample #define GL_3DFX_multisample 1 #define GL_MULTISAMPLE_3DFX 0x86B2 #define GL_SAMPLE_BUFFERS_3DFX 0x86B3 #define GL_SAMPLES_3DFX 0x86B4 #define GL_MULTISAMPLE_BIT_3DFX 0x20000000 #endif /* GL_3DFX_multisample */ #ifndef GL_3DFX_tbuffer #define GL_3DFX_tbuffer 1 typedef void (APIENTRYP PFNGLTBUFFERMASK3DFXPROC) (GLuint mask); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTbufferMask3DFX (GLuint mask); #endif #endif /* GL_3DFX_tbuffer */ #ifndef GL_3DFX_texture_compression_FXT1 #define GL_3DFX_texture_compression_FXT1 1 #define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0 #define GL_COMPRESSED_RGBA_FXT1_3DFX 0x86B1 #endif /* GL_3DFX_texture_compression_FXT1 */ #ifndef GL_AMD_blend_minmax_factor #define GL_AMD_blend_minmax_factor 1 #define GL_FACTOR_MIN_AMD 0x901C #define GL_FACTOR_MAX_AMD 0x901D #endif /* GL_AMD_blend_minmax_factor */ #ifndef GL_AMD_conservative_depth #define GL_AMD_conservative_depth 1 #endif /* GL_AMD_conservative_depth */ #ifndef GL_AMD_debug_output #define GL_AMD_debug_output 1 typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); #define GL_MAX_DEBUG_MESSAGE_LENGTH_AMD 0x9143 #define GL_MAX_DEBUG_LOGGED_MESSAGES_AMD 0x9144 #define GL_DEBUG_LOGGED_MESSAGES_AMD 0x9145 #define GL_DEBUG_SEVERITY_HIGH_AMD 0x9146 #define GL_DEBUG_SEVERITY_MEDIUM_AMD 0x9147 #define GL_DEBUG_SEVERITY_LOW_AMD 0x9148 #define GL_DEBUG_CATEGORY_API_ERROR_AMD 0x9149 #define GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD 0x914A #define GL_DEBUG_CATEGORY_DEPRECATION_AMD 0x914B #define GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD 0x914C #define GL_DEBUG_CATEGORY_PERFORMANCE_AMD 0x914D #define GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD 0x914E #define GL_DEBUG_CATEGORY_APPLICATION_AMD 0x914F #define GL_DEBUG_CATEGORY_OTHER_AMD 0x9150 typedef void (APIENTRYP PFNGLDEBUGMESSAGEENABLEAMDPROC) (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTAMDPROC) (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf); typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKAMDPROC) (GLDEBUGPROCAMD callback, void *userParam); typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGAMDPROC) (GLuint count, GLsizei bufSize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDebugMessageEnableAMD (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); GLAPI void APIENTRY glDebugMessageInsertAMD (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf); GLAPI void APIENTRY glDebugMessageCallbackAMD (GLDEBUGPROCAMD callback, void *userParam); GLAPI GLuint APIENTRY glGetDebugMessageLogAMD (GLuint count, GLsizei bufSize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message); #endif #endif /* GL_AMD_debug_output */ #ifndef GL_AMD_depth_clamp_separate #define GL_AMD_depth_clamp_separate 1 #define GL_DEPTH_CLAMP_NEAR_AMD 0x901E #define GL_DEPTH_CLAMP_FAR_AMD 0x901F #endif /* GL_AMD_depth_clamp_separate */ #ifndef GL_AMD_draw_buffers_blend #define GL_AMD_draw_buffers_blend 1 typedef void (APIENTRYP PFNGLBLENDFUNCINDEXEDAMDPROC) (GLuint buf, GLenum src, GLenum dst); typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); typedef void (APIENTRYP PFNGLBLENDEQUATIONINDEXEDAMDPROC) (GLuint buf, GLenum mode); typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendFuncIndexedAMD (GLuint buf, GLenum src, GLenum dst); GLAPI void APIENTRY glBlendFuncSeparateIndexedAMD (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); GLAPI void APIENTRY glBlendEquationIndexedAMD (GLuint buf, GLenum mode); GLAPI void APIENTRY glBlendEquationSeparateIndexedAMD (GLuint buf, GLenum modeRGB, GLenum modeAlpha); #endif #endif /* GL_AMD_draw_buffers_blend */ #ifndef GL_AMD_framebuffer_multisample_advanced #define GL_AMD_framebuffer_multisample_advanced 1 #define GL_RENDERBUFFER_STORAGE_SAMPLES_AMD 0x91B2 #define GL_MAX_COLOR_FRAMEBUFFER_SAMPLES_AMD 0x91B3 #define GL_MAX_COLOR_FRAMEBUFFER_STORAGE_SAMPLES_AMD 0x91B4 #define GL_MAX_DEPTH_STENCIL_FRAMEBUFFER_SAMPLES_AMD 0x91B5 #define GL_NUM_SUPPORTED_MULTISAMPLE_MODES_AMD 0x91B6 #define GL_SUPPORTED_MULTISAMPLE_MODES_AMD 0x91B7 typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEADVANCEDAMDPROC) (GLenum target, GLsizei samples, GLsizei storageSamples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEADVANCEDAMDPROC) (GLuint renderbuffer, GLsizei samples, GLsizei storageSamples, GLenum internalformat, GLsizei width, GLsizei height); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glRenderbufferStorageMultisampleAdvancedAMD (GLenum target, GLsizei samples, GLsizei storageSamples, GLenum internalformat, GLsizei width, GLsizei height); GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleAdvancedAMD (GLuint renderbuffer, GLsizei samples, GLsizei storageSamples, GLenum internalformat, GLsizei width, GLsizei height); #endif #endif /* GL_AMD_framebuffer_multisample_advanced */ #ifndef GL_AMD_framebuffer_sample_positions #define GL_AMD_framebuffer_sample_positions 1 #define GL_SUBSAMPLE_DISTANCE_AMD 0x883F #define GL_PIXELS_PER_SAMPLE_PATTERN_X_AMD 0x91AE #define GL_PIXELS_PER_SAMPLE_PATTERN_Y_AMD 0x91AF #define GL_ALL_PIXELS_AMD 0xFFFFFFFF typedef void (APIENTRYP PFNGLFRAMEBUFFERSAMPLEPOSITIONSFVAMDPROC) (GLenum target, GLuint numsamples, GLuint pixelindex, const GLfloat *values); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERSAMPLEPOSITIONSFVAMDPROC) (GLuint framebuffer, GLuint numsamples, GLuint pixelindex, const GLfloat *values); typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERFVAMDPROC) (GLenum target, GLenum pname, GLuint numsamples, GLuint pixelindex, GLsizei size, GLfloat *values); typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERFVAMDPROC) (GLuint framebuffer, GLenum pname, GLuint numsamples, GLuint pixelindex, GLsizei size, GLfloat *values); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFramebufferSamplePositionsfvAMD (GLenum target, GLuint numsamples, GLuint pixelindex, const GLfloat *values); GLAPI void APIENTRY glNamedFramebufferSamplePositionsfvAMD (GLuint framebuffer, GLuint numsamples, GLuint pixelindex, const GLfloat *values); GLAPI void APIENTRY glGetFramebufferParameterfvAMD (GLenum target, GLenum pname, GLuint numsamples, GLuint pixelindex, GLsizei size, GLfloat *values); GLAPI void APIENTRY glGetNamedFramebufferParameterfvAMD (GLuint framebuffer, GLenum pname, GLuint numsamples, GLuint pixelindex, GLsizei size, GLfloat *values); #endif #endif /* GL_AMD_framebuffer_sample_positions */ #ifndef GL_AMD_gcn_shader #define GL_AMD_gcn_shader 1 #endif /* GL_AMD_gcn_shader */ #ifndef GL_AMD_gpu_shader_half_float #define GL_AMD_gpu_shader_half_float 1 #define GL_FLOAT16_NV 0x8FF8 #define GL_FLOAT16_VEC2_NV 0x8FF9 #define GL_FLOAT16_VEC3_NV 0x8FFA #define GL_FLOAT16_VEC4_NV 0x8FFB #define GL_FLOAT16_MAT2_AMD 0x91C5 #define GL_FLOAT16_MAT3_AMD 0x91C6 #define GL_FLOAT16_MAT4_AMD 0x91C7 #define GL_FLOAT16_MAT2x3_AMD 0x91C8 #define GL_FLOAT16_MAT2x4_AMD 0x91C9 #define GL_FLOAT16_MAT3x2_AMD 0x91CA #define GL_FLOAT16_MAT3x4_AMD 0x91CB #define GL_FLOAT16_MAT4x2_AMD 0x91CC #define GL_FLOAT16_MAT4x3_AMD 0x91CD #endif /* GL_AMD_gpu_shader_half_float */ #ifndef GL_AMD_gpu_shader_int16 #define GL_AMD_gpu_shader_int16 1 #endif /* GL_AMD_gpu_shader_int16 */ #ifndef GL_AMD_gpu_shader_int64 #define GL_AMD_gpu_shader_int64 1 typedef khronos_int64_t GLint64EXT; #define GL_INT64_NV 0x140E #define GL_UNSIGNED_INT64_NV 0x140F #define GL_INT8_NV 0x8FE0 #define GL_INT8_VEC2_NV 0x8FE1 #define GL_INT8_VEC3_NV 0x8FE2 #define GL_INT8_VEC4_NV 0x8FE3 #define GL_INT16_NV 0x8FE4 #define GL_INT16_VEC2_NV 0x8FE5 #define GL_INT16_VEC3_NV 0x8FE6 #define GL_INT16_VEC4_NV 0x8FE7 #define GL_INT64_VEC2_NV 0x8FE9 #define GL_INT64_VEC3_NV 0x8FEA #define GL_INT64_VEC4_NV 0x8FEB #define GL_UNSIGNED_INT8_NV 0x8FEC #define GL_UNSIGNED_INT8_VEC2_NV 0x8FED #define GL_UNSIGNED_INT8_VEC3_NV 0x8FEE #define GL_UNSIGNED_INT8_VEC4_NV 0x8FEF #define GL_UNSIGNED_INT16_NV 0x8FF0 #define GL_UNSIGNED_INT16_VEC2_NV 0x8FF1 #define GL_UNSIGNED_INT16_VEC3_NV 0x8FF2 #define GL_UNSIGNED_INT16_VEC4_NV 0x8FF3 #define GL_UNSIGNED_INT64_VEC2_NV 0x8FF5 #define GL_UNSIGNED_INT64_VEC3_NV 0x8FF6 #define GL_UNSIGNED_INT64_VEC4_NV 0x8FF7 typedef void (APIENTRYP PFNGLUNIFORM1I64NVPROC) (GLint location, GLint64EXT x); typedef void (APIENTRYP PFNGLUNIFORM2I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y); typedef void (APIENTRYP PFNGLUNIFORM3I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); typedef void (APIENTRYP PFNGLUNIFORM4I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); typedef void (APIENTRYP PFNGLUNIFORM1I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); typedef void (APIENTRYP PFNGLUNIFORM2I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); typedef void (APIENTRYP PFNGLUNIFORM3I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); typedef void (APIENTRYP PFNGLUNIFORM4I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); typedef void (APIENTRYP PFNGLUNIFORM1UI64NVPROC) (GLint location, GLuint64EXT x); typedef void (APIENTRYP PFNGLUNIFORM2UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y); typedef void (APIENTRYP PFNGLUNIFORM3UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); typedef void (APIENTRYP PFNGLUNIFORM4UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); typedef void (APIENTRYP PFNGLUNIFORM1UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); typedef void (APIENTRYP PFNGLUNIFORM2UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); typedef void (APIENTRYP PFNGLUNIFORM3UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); typedef void (APIENTRYP PFNGLUNIFORM4UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); typedef void (APIENTRYP PFNGLGETUNIFORMI64VNVPROC) (GLuint program, GLint location, GLint64EXT *params); typedef void (APIENTRYP PFNGLGETUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLuint64EXT *params); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64NVPROC) (GLuint program, GLint location, GLint64EXT x); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glUniform1i64NV (GLint location, GLint64EXT x); GLAPI void APIENTRY glUniform2i64NV (GLint location, GLint64EXT x, GLint64EXT y); GLAPI void APIENTRY glUniform3i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); GLAPI void APIENTRY glUniform4i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); GLAPI void APIENTRY glUniform1i64vNV (GLint location, GLsizei count, const GLint64EXT *value); GLAPI void APIENTRY glUniform2i64vNV (GLint location, GLsizei count, const GLint64EXT *value); GLAPI void APIENTRY glUniform3i64vNV (GLint location, GLsizei count, const GLint64EXT *value); GLAPI void APIENTRY glUniform4i64vNV (GLint location, GLsizei count, const GLint64EXT *value); GLAPI void APIENTRY glUniform1ui64NV (GLint location, GLuint64EXT x); GLAPI void APIENTRY glUniform2ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y); GLAPI void APIENTRY glUniform3ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); GLAPI void APIENTRY glUniform4ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); GLAPI void APIENTRY glUniform1ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); GLAPI void APIENTRY glUniform2ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); GLAPI void APIENTRY glUniform3ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); GLAPI void APIENTRY glUniform4ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); GLAPI void APIENTRY glGetUniformi64vNV (GLuint program, GLint location, GLint64EXT *params); GLAPI void APIENTRY glGetUniformui64vNV (GLuint program, GLint location, GLuint64EXT *params); GLAPI void APIENTRY glProgramUniform1i64NV (GLuint program, GLint location, GLint64EXT x); GLAPI void APIENTRY glProgramUniform2i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); GLAPI void APIENTRY glProgramUniform3i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); GLAPI void APIENTRY glProgramUniform4i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); GLAPI void APIENTRY glProgramUniform1i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); GLAPI void APIENTRY glProgramUniform2i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); GLAPI void APIENTRY glProgramUniform3i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); GLAPI void APIENTRY glProgramUniform4i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); GLAPI void APIENTRY glProgramUniform1ui64NV (GLuint program, GLint location, GLuint64EXT x); GLAPI void APIENTRY glProgramUniform2ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); GLAPI void APIENTRY glProgramUniform3ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); GLAPI void APIENTRY glProgramUniform4ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); GLAPI void APIENTRY glProgramUniform1ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); GLAPI void APIENTRY glProgramUniform2ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); GLAPI void APIENTRY glProgramUniform3ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); GLAPI void APIENTRY glProgramUniform4ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); #endif #endif /* GL_AMD_gpu_shader_int64 */ #ifndef GL_AMD_interleaved_elements #define GL_AMD_interleaved_elements 1 #define GL_VERTEX_ELEMENT_SWIZZLE_AMD 0x91A4 #define GL_VERTEX_ID_SWIZZLE_AMD 0x91A5 typedef void (APIENTRYP PFNGLVERTEXATTRIBPARAMETERIAMDPROC) (GLuint index, GLenum pname, GLint param); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttribParameteriAMD (GLuint index, GLenum pname, GLint param); #endif #endif /* GL_AMD_interleaved_elements */ #ifndef GL_AMD_multi_draw_indirect #define GL_AMD_multi_draw_indirect 1 typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC) (GLenum mode, const void *indirect, GLsizei primcount, GLsizei stride); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei primcount, GLsizei stride); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMultiDrawArraysIndirectAMD (GLenum mode, const void *indirect, GLsizei primcount, GLsizei stride); GLAPI void APIENTRY glMultiDrawElementsIndirectAMD (GLenum mode, GLenum type, const void *indirect, GLsizei primcount, GLsizei stride); #endif #endif /* GL_AMD_multi_draw_indirect */ #ifndef GL_AMD_name_gen_delete #define GL_AMD_name_gen_delete 1 #define GL_DATA_BUFFER_AMD 0x9151 #define GL_PERFORMANCE_MONITOR_AMD 0x9152 #define GL_QUERY_OBJECT_AMD 0x9153 #define GL_VERTEX_ARRAY_OBJECT_AMD 0x9154 #define GL_SAMPLER_OBJECT_AMD 0x9155 typedef void (APIENTRYP PFNGLGENNAMESAMDPROC) (GLenum identifier, GLuint num, GLuint *names); typedef void (APIENTRYP PFNGLDELETENAMESAMDPROC) (GLenum identifier, GLuint num, const GLuint *names); typedef GLboolean (APIENTRYP PFNGLISNAMEAMDPROC) (GLenum identifier, GLuint name); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenNamesAMD (GLenum identifier, GLuint num, GLuint *names); GLAPI void APIENTRY glDeleteNamesAMD (GLenum identifier, GLuint num, const GLuint *names); GLAPI GLboolean APIENTRY glIsNameAMD (GLenum identifier, GLuint name); #endif #endif /* GL_AMD_name_gen_delete */ #ifndef GL_AMD_occlusion_query_event #define GL_AMD_occlusion_query_event 1 #define GL_OCCLUSION_QUERY_EVENT_MASK_AMD 0x874F #define GL_QUERY_DEPTH_PASS_EVENT_BIT_AMD 0x00000001 #define GL_QUERY_DEPTH_FAIL_EVENT_BIT_AMD 0x00000002 #define GL_QUERY_STENCIL_FAIL_EVENT_BIT_AMD 0x00000004 #define GL_QUERY_DEPTH_BOUNDS_FAIL_EVENT_BIT_AMD 0x00000008 #define GL_QUERY_ALL_EVENT_BITS_AMD 0xFFFFFFFF typedef void (APIENTRYP PFNGLQUERYOBJECTPARAMETERUIAMDPROC) (GLenum target, GLuint id, GLenum pname, GLuint param); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glQueryObjectParameteruiAMD (GLenum target, GLuint id, GLenum pname, GLuint param); #endif #endif /* GL_AMD_occlusion_query_event */ #ifndef GL_AMD_performance_monitor #define GL_AMD_performance_monitor 1 #define GL_COUNTER_TYPE_AMD 0x8BC0 #define GL_COUNTER_RANGE_AMD 0x8BC1 #define GL_UNSIGNED_INT64_AMD 0x8BC2 #define GL_PERCENTAGE_AMD 0x8BC3 #define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4 #define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5 #define GL_PERFMON_RESULT_AMD 0x8BC6 typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups); typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, void *data); typedef void (APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); typedef void (APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); typedef void (APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); typedef void (APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor); typedef void (APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor); typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups); GLAPI void APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); GLAPI void APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); GLAPI void APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); GLAPI void APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, void *data); GLAPI void APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors); GLAPI void APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors); GLAPI void APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); GLAPI void APIENTRY glBeginPerfMonitorAMD (GLuint monitor); GLAPI void APIENTRY glEndPerfMonitorAMD (GLuint monitor); GLAPI void APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); #endif #endif /* GL_AMD_performance_monitor */ #ifndef GL_AMD_pinned_memory #define GL_AMD_pinned_memory 1 #define GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD 0x9160 #endif /* GL_AMD_pinned_memory */ #ifndef GL_AMD_query_buffer_object #define GL_AMD_query_buffer_object 1 #define GL_QUERY_BUFFER_AMD 0x9192 #define GL_QUERY_BUFFER_BINDING_AMD 0x9193 #define GL_QUERY_RESULT_NO_WAIT_AMD 0x9194 #endif /* GL_AMD_query_buffer_object */ #ifndef GL_AMD_sample_positions #define GL_AMD_sample_positions 1 typedef void (APIENTRYP PFNGLSETMULTISAMPLEFVAMDPROC) (GLenum pname, GLuint index, const GLfloat *val); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSetMultisamplefvAMD (GLenum pname, GLuint index, const GLfloat *val); #endif #endif /* GL_AMD_sample_positions */ #ifndef GL_AMD_seamless_cubemap_per_texture #define GL_AMD_seamless_cubemap_per_texture 1 #endif /* GL_AMD_seamless_cubemap_per_texture */ #ifndef GL_AMD_shader_atomic_counter_ops #define GL_AMD_shader_atomic_counter_ops 1 #endif /* GL_AMD_shader_atomic_counter_ops */ #ifndef GL_AMD_shader_ballot #define GL_AMD_shader_ballot 1 #endif /* GL_AMD_shader_ballot */ #ifndef GL_AMD_shader_explicit_vertex_parameter #define GL_AMD_shader_explicit_vertex_parameter 1 #endif /* GL_AMD_shader_explicit_vertex_parameter */ #ifndef GL_AMD_shader_gpu_shader_half_float_fetch #define GL_AMD_shader_gpu_shader_half_float_fetch 1 #endif /* GL_AMD_shader_gpu_shader_half_float_fetch */ #ifndef GL_AMD_shader_image_load_store_lod #define GL_AMD_shader_image_load_store_lod 1 #endif /* GL_AMD_shader_image_load_store_lod */ #ifndef GL_AMD_shader_stencil_export #define GL_AMD_shader_stencil_export 1 #endif /* GL_AMD_shader_stencil_export */ #ifndef GL_AMD_shader_trinary_minmax #define GL_AMD_shader_trinary_minmax 1 #endif /* GL_AMD_shader_trinary_minmax */ #ifndef GL_AMD_sparse_texture #define GL_AMD_sparse_texture 1 #define GL_VIRTUAL_PAGE_SIZE_X_AMD 0x9195 #define GL_VIRTUAL_PAGE_SIZE_Y_AMD 0x9196 #define GL_VIRTUAL_PAGE_SIZE_Z_AMD 0x9197 #define GL_MAX_SPARSE_TEXTURE_SIZE_AMD 0x9198 #define GL_MAX_SPARSE_3D_TEXTURE_SIZE_AMD 0x9199 #define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS 0x919A #define GL_MIN_SPARSE_LEVEL_AMD 0x919B #define GL_MIN_LOD_WARNING_AMD 0x919C #define GL_TEXTURE_STORAGE_SPARSE_BIT_AMD 0x00000001 typedef void (APIENTRYP PFNGLTEXSTORAGESPARSEAMDPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); typedef void (APIENTRYP PFNGLTEXTURESTORAGESPARSEAMDPROC) (GLuint texture, GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexStorageSparseAMD (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); GLAPI void APIENTRY glTextureStorageSparseAMD (GLuint texture, GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); #endif #endif /* GL_AMD_sparse_texture */ #ifndef GL_AMD_stencil_operation_extended #define GL_AMD_stencil_operation_extended 1 #define GL_SET_AMD 0x874A #define GL_REPLACE_VALUE_AMD 0x874B #define GL_STENCIL_OP_VALUE_AMD 0x874C #define GL_STENCIL_BACK_OP_VALUE_AMD 0x874D typedef void (APIENTRYP PFNGLSTENCILOPVALUEAMDPROC) (GLenum face, GLuint value); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glStencilOpValueAMD (GLenum face, GLuint value); #endif #endif /* GL_AMD_stencil_operation_extended */ #ifndef GL_AMD_texture_gather_bias_lod #define GL_AMD_texture_gather_bias_lod 1 #endif /* GL_AMD_texture_gather_bias_lod */ #ifndef GL_AMD_texture_texture4 #define GL_AMD_texture_texture4 1 #endif /* GL_AMD_texture_texture4 */ #ifndef GL_AMD_transform_feedback3_lines_triangles #define GL_AMD_transform_feedback3_lines_triangles 1 #endif /* GL_AMD_transform_feedback3_lines_triangles */ #ifndef GL_AMD_transform_feedback4 #define GL_AMD_transform_feedback4 1 #define GL_STREAM_RASTERIZATION_AMD 0x91A0 #endif /* GL_AMD_transform_feedback4 */ #ifndef GL_AMD_vertex_shader_layer #define GL_AMD_vertex_shader_layer 1 #endif /* GL_AMD_vertex_shader_layer */ #ifndef GL_AMD_vertex_shader_tessellator #define GL_AMD_vertex_shader_tessellator 1 #define GL_SAMPLER_BUFFER_AMD 0x9001 #define GL_INT_SAMPLER_BUFFER_AMD 0x9002 #define GL_UNSIGNED_INT_SAMPLER_BUFFER_AMD 0x9003 #define GL_TESSELLATION_MODE_AMD 0x9004 #define GL_TESSELLATION_FACTOR_AMD 0x9005 #define GL_DISCRETE_AMD 0x9006 #define GL_CONTINUOUS_AMD 0x9007 typedef void (APIENTRYP PFNGLTESSELLATIONFACTORAMDPROC) (GLfloat factor); typedef void (APIENTRYP PFNGLTESSELLATIONMODEAMDPROC) (GLenum mode); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTessellationFactorAMD (GLfloat factor); GLAPI void APIENTRY glTessellationModeAMD (GLenum mode); #endif #endif /* GL_AMD_vertex_shader_tessellator */ #ifndef GL_AMD_vertex_shader_viewport_index #define GL_AMD_vertex_shader_viewport_index 1 #endif /* GL_AMD_vertex_shader_viewport_index */ #ifndef GL_APPLE_aux_depth_stencil #define GL_APPLE_aux_depth_stencil 1 #define GL_AUX_DEPTH_STENCIL_APPLE 0x8A14 #endif /* GL_APPLE_aux_depth_stencil */ #ifndef GL_APPLE_client_storage #define GL_APPLE_client_storage 1 #define GL_UNPACK_CLIENT_STORAGE_APPLE 0x85B2 #endif /* GL_APPLE_client_storage */ #ifndef GL_APPLE_element_array #define GL_APPLE_element_array 1 #define GL_ELEMENT_ARRAY_APPLE 0x8A0C #define GL_ELEMENT_ARRAY_TYPE_APPLE 0x8A0D #define GL_ELEMENT_ARRAY_POINTER_APPLE 0x8A0E typedef void (APIENTRYP PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const void *pointer); typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count); typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); typedef void (APIENTRYP PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glElementPointerAPPLE (GLenum type, const void *pointer); GLAPI void APIENTRY glDrawElementArrayAPPLE (GLenum mode, GLint first, GLsizei count); GLAPI void APIENTRY glDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); GLAPI void APIENTRY glMultiDrawElementArrayAPPLE (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); GLAPI void APIENTRY glMultiDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); #endif #endif /* GL_APPLE_element_array */ #ifndef GL_APPLE_fence #define GL_APPLE_fence 1 #define GL_DRAW_PIXELS_APPLE 0x8A0A #define GL_FENCE_APPLE 0x8A0B typedef void (APIENTRYP PFNGLGENFENCESAPPLEPROC) (GLsizei n, GLuint *fences); typedef void (APIENTRYP PFNGLDELETEFENCESAPPLEPROC) (GLsizei n, const GLuint *fences); typedef void (APIENTRYP PFNGLSETFENCEAPPLEPROC) (GLuint fence); typedef GLboolean (APIENTRYP PFNGLISFENCEAPPLEPROC) (GLuint fence); typedef GLboolean (APIENTRYP PFNGLTESTFENCEAPPLEPROC) (GLuint fence); typedef void (APIENTRYP PFNGLFINISHFENCEAPPLEPROC) (GLuint fence); typedef GLboolean (APIENTRYP PFNGLTESTOBJECTAPPLEPROC) (GLenum object, GLuint name); typedef void (APIENTRYP PFNGLFINISHOBJECTAPPLEPROC) (GLenum object, GLint name); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenFencesAPPLE (GLsizei n, GLuint *fences); GLAPI void APIENTRY glDeleteFencesAPPLE (GLsizei n, const GLuint *fences); GLAPI void APIENTRY glSetFenceAPPLE (GLuint fence); GLAPI GLboolean APIENTRY glIsFenceAPPLE (GLuint fence); GLAPI GLboolean APIENTRY glTestFenceAPPLE (GLuint fence); GLAPI void APIENTRY glFinishFenceAPPLE (GLuint fence); GLAPI GLboolean APIENTRY glTestObjectAPPLE (GLenum object, GLuint name); GLAPI void APIENTRY glFinishObjectAPPLE (GLenum object, GLint name); #endif #endif /* GL_APPLE_fence */ #ifndef GL_APPLE_float_pixels #define GL_APPLE_float_pixels 1 #define GL_HALF_APPLE 0x140B #define GL_RGBA_FLOAT32_APPLE 0x8814 #define GL_RGB_FLOAT32_APPLE 0x8815 #define GL_ALPHA_FLOAT32_APPLE 0x8816 #define GL_INTENSITY_FLOAT32_APPLE 0x8817 #define GL_LUMINANCE_FLOAT32_APPLE 0x8818 #define GL_LUMINANCE_ALPHA_FLOAT32_APPLE 0x8819 #define GL_RGBA_FLOAT16_APPLE 0x881A #define GL_RGB_FLOAT16_APPLE 0x881B #define GL_ALPHA_FLOAT16_APPLE 0x881C #define GL_INTENSITY_FLOAT16_APPLE 0x881D #define GL_LUMINANCE_FLOAT16_APPLE 0x881E #define GL_LUMINANCE_ALPHA_FLOAT16_APPLE 0x881F #define GL_COLOR_FLOAT_APPLE 0x8A0F #endif /* GL_APPLE_float_pixels */ #ifndef GL_APPLE_flush_buffer_range #define GL_APPLE_flush_buffer_range 1 #define GL_BUFFER_SERIALIZED_MODIFY_APPLE 0x8A12 #define GL_BUFFER_FLUSHING_UNMAP_APPLE 0x8A13 typedef void (APIENTRYP PFNGLBUFFERPARAMETERIAPPLEPROC) (GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC) (GLenum target, GLintptr offset, GLsizeiptr size); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBufferParameteriAPPLE (GLenum target, GLenum pname, GLint param); GLAPI void APIENTRY glFlushMappedBufferRangeAPPLE (GLenum target, GLintptr offset, GLsizeiptr size); #endif #endif /* GL_APPLE_flush_buffer_range */ #ifndef GL_APPLE_object_purgeable #define GL_APPLE_object_purgeable 1 #define GL_BUFFER_OBJECT_APPLE 0x85B3 #define GL_RELEASED_APPLE 0x8A19 #define GL_VOLATILE_APPLE 0x8A1A #define GL_RETAINED_APPLE 0x8A1B #define GL_UNDEFINED_APPLE 0x8A1C #define GL_PURGEABLE_APPLE 0x8A1D typedef GLenum (APIENTRYP PFNGLOBJECTPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option); typedef GLenum (APIENTRYP PFNGLOBJECTUNPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option); typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVAPPLEPROC) (GLenum objectType, GLuint name, GLenum pname, GLint *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI GLenum APIENTRY glObjectPurgeableAPPLE (GLenum objectType, GLuint name, GLenum option); GLAPI GLenum APIENTRY glObjectUnpurgeableAPPLE (GLenum objectType, GLuint name, GLenum option); GLAPI void APIENTRY glGetObjectParameterivAPPLE (GLenum objectType, GLuint name, GLenum pname, GLint *params); #endif #endif /* GL_APPLE_object_purgeable */ #ifndef GL_APPLE_rgb_422 #define GL_APPLE_rgb_422 1 #define GL_RGB_422_APPLE 0x8A1F #define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA #define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB #define GL_RGB_RAW_422_APPLE 0x8A51 #endif /* GL_APPLE_rgb_422 */ #ifndef GL_APPLE_row_bytes #define GL_APPLE_row_bytes 1 #define GL_PACK_ROW_BYTES_APPLE 0x8A15 #define GL_UNPACK_ROW_BYTES_APPLE 0x8A16 #endif /* GL_APPLE_row_bytes */ #ifndef GL_APPLE_specular_vector #define GL_APPLE_specular_vector 1 #define GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0 #endif /* GL_APPLE_specular_vector */ #ifndef GL_APPLE_texture_range #define GL_APPLE_texture_range 1 #define GL_TEXTURE_RANGE_LENGTH_APPLE 0x85B7 #define GL_TEXTURE_RANGE_POINTER_APPLE 0x85B8 #define GL_TEXTURE_STORAGE_HINT_APPLE 0x85BC #define GL_STORAGE_PRIVATE_APPLE 0x85BD #define GL_STORAGE_CACHED_APPLE 0x85BE #define GL_STORAGE_SHARED_APPLE 0x85BF typedef void (APIENTRYP PFNGLTEXTURERANGEAPPLEPROC) (GLenum target, GLsizei length, const void *pointer); typedef void (APIENTRYP PFNGLGETTEXPARAMETERPOINTERVAPPLEPROC) (GLenum target, GLenum pname, void **params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTextureRangeAPPLE (GLenum target, GLsizei length, const void *pointer); GLAPI void APIENTRY glGetTexParameterPointervAPPLE (GLenum target, GLenum pname, void **params); #endif #endif /* GL_APPLE_texture_range */ #ifndef GL_APPLE_transform_hint #define GL_APPLE_transform_hint 1 #define GL_TRANSFORM_HINT_APPLE 0x85B1 #endif /* GL_APPLE_transform_hint */ #ifndef GL_APPLE_vertex_array_object #define GL_APPLE_vertex_array_object 1 #define GL_VERTEX_ARRAY_BINDING_APPLE 0x85B5 typedef void (APIENTRYP PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array); typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays); typedef void (APIENTRYP PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, GLuint *arrays); typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindVertexArrayAPPLE (GLuint array); GLAPI void APIENTRY glDeleteVertexArraysAPPLE (GLsizei n, const GLuint *arrays); GLAPI void APIENTRY glGenVertexArraysAPPLE (GLsizei n, GLuint *arrays); GLAPI GLboolean APIENTRY glIsVertexArrayAPPLE (GLuint array); #endif #endif /* GL_APPLE_vertex_array_object */ #ifndef GL_APPLE_vertex_array_range #define GL_APPLE_vertex_array_range 1 #define GL_VERTEX_ARRAY_RANGE_APPLE 0x851D #define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E #define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F #define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521 #define GL_STORAGE_CLIENT_APPLE 0x85B4 typedef void (APIENTRYP PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, void *pointer); typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, void *pointer); typedef void (APIENTRYP PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexArrayRangeAPPLE (GLsizei length, void *pointer); GLAPI void APIENTRY glFlushVertexArrayRangeAPPLE (GLsizei length, void *pointer); GLAPI void APIENTRY glVertexArrayParameteriAPPLE (GLenum pname, GLint param); #endif #endif /* GL_APPLE_vertex_array_range */ #ifndef GL_APPLE_vertex_program_evaluators #define GL_APPLE_vertex_program_evaluators 1 #define GL_VERTEX_ATTRIB_MAP1_APPLE 0x8A00 #define GL_VERTEX_ATTRIB_MAP2_APPLE 0x8A01 #define GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE 0x8A02 #define GL_VERTEX_ATTRIB_MAP1_COEFF_APPLE 0x8A03 #define GL_VERTEX_ATTRIB_MAP1_ORDER_APPLE 0x8A04 #define GL_VERTEX_ATTRIB_MAP1_DOMAIN_APPLE 0x8A05 #define GL_VERTEX_ATTRIB_MAP2_SIZE_APPLE 0x8A06 #define GL_VERTEX_ATTRIB_MAP2_COEFF_APPLE 0x8A07 #define GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE 0x8A08 #define GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE 0x8A09 typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname); typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname); typedef GLboolean (APIENTRYP PFNGLISVERTEXATTRIBENABLEDAPPLEPROC) (GLuint index, GLenum pname); typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glEnableVertexAttribAPPLE (GLuint index, GLenum pname); GLAPI void APIENTRY glDisableVertexAttribAPPLE (GLuint index, GLenum pname); GLAPI GLboolean APIENTRY glIsVertexAttribEnabledAPPLE (GLuint index, GLenum pname); GLAPI void APIENTRY glMapVertexAttrib1dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); GLAPI void APIENTRY glMapVertexAttrib1fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); GLAPI void APIENTRY glMapVertexAttrib2dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); GLAPI void APIENTRY glMapVertexAttrib2fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); #endif #endif /* GL_APPLE_vertex_program_evaluators */ #ifndef GL_APPLE_ycbcr_422 #define GL_APPLE_ycbcr_422 1 #define GL_YCBCR_422_APPLE 0x85B9 #endif /* GL_APPLE_ycbcr_422 */ #ifndef GL_ATI_draw_buffers #define GL_ATI_draw_buffers 1 #define GL_MAX_DRAW_BUFFERS_ATI 0x8824 #define GL_DRAW_BUFFER0_ATI 0x8825 #define GL_DRAW_BUFFER1_ATI 0x8826 #define GL_DRAW_BUFFER2_ATI 0x8827 #define GL_DRAW_BUFFER3_ATI 0x8828 #define GL_DRAW_BUFFER4_ATI 0x8829 #define GL_DRAW_BUFFER5_ATI 0x882A #define GL_DRAW_BUFFER6_ATI 0x882B #define GL_DRAW_BUFFER7_ATI 0x882C #define GL_DRAW_BUFFER8_ATI 0x882D #define GL_DRAW_BUFFER9_ATI 0x882E #define GL_DRAW_BUFFER10_ATI 0x882F #define GL_DRAW_BUFFER11_ATI 0x8830 #define GL_DRAW_BUFFER12_ATI 0x8831 #define GL_DRAW_BUFFER13_ATI 0x8832 #define GL_DRAW_BUFFER14_ATI 0x8833 #define GL_DRAW_BUFFER15_ATI 0x8834 typedef void (APIENTRYP PFNGLDRAWBUFFERSATIPROC) (GLsizei n, const GLenum *bufs); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawBuffersATI (GLsizei n, const GLenum *bufs); #endif #endif /* GL_ATI_draw_buffers */ #ifndef GL_ATI_element_array #define GL_ATI_element_array 1 #define GL_ELEMENT_ARRAY_ATI 0x8768 #define GL_ELEMENT_ARRAY_TYPE_ATI 0x8769 #define GL_ELEMENT_ARRAY_POINTER_ATI 0x876A typedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC) (GLenum type, const void *pointer); typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count); typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glElementPointerATI (GLenum type, const void *pointer); GLAPI void APIENTRY glDrawElementArrayATI (GLenum mode, GLsizei count); GLAPI void APIENTRY glDrawRangeElementArrayATI (GLenum mode, GLuint start, GLuint end, GLsizei count); #endif #endif /* GL_ATI_element_array */ #ifndef GL_ATI_envmap_bumpmap #define GL_ATI_envmap_bumpmap 1 #define GL_BUMP_ROT_MATRIX_ATI 0x8775 #define GL_BUMP_ROT_MATRIX_SIZE_ATI 0x8776 #define GL_BUMP_NUM_TEX_UNITS_ATI 0x8777 #define GL_BUMP_TEX_UNITS_ATI 0x8778 #define GL_DUDV_ATI 0x8779 #define GL_DU8DV8_ATI 0x877A #define GL_BUMP_ENVMAP_ATI 0x877B #define GL_BUMP_TARGET_ATI 0x877C typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERIVATIPROC) (GLenum pname, const GLint *param); typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERFVATIPROC) (GLenum pname, const GLfloat *param); typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERIVATIPROC) (GLenum pname, GLint *param); typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERFVATIPROC) (GLenum pname, GLfloat *param); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexBumpParameterivATI (GLenum pname, const GLint *param); GLAPI void APIENTRY glTexBumpParameterfvATI (GLenum pname, const GLfloat *param); GLAPI void APIENTRY glGetTexBumpParameterivATI (GLenum pname, GLint *param); GLAPI void APIENTRY glGetTexBumpParameterfvATI (GLenum pname, GLfloat *param); #endif #endif /* GL_ATI_envmap_bumpmap */ #ifndef GL_ATI_fragment_shader #define GL_ATI_fragment_shader 1 #define GL_FRAGMENT_SHADER_ATI 0x8920 #define GL_REG_0_ATI 0x8921 #define GL_REG_1_ATI 0x8922 #define GL_REG_2_ATI 0x8923 #define GL_REG_3_ATI 0x8924 #define GL_REG_4_ATI 0x8925 #define GL_REG_5_ATI 0x8926 #define GL_REG_6_ATI 0x8927 #define GL_REG_7_ATI 0x8928 #define GL_REG_8_ATI 0x8929 #define GL_REG_9_ATI 0x892A #define GL_REG_10_ATI 0x892B #define GL_REG_11_ATI 0x892C #define GL_REG_12_ATI 0x892D #define GL_REG_13_ATI 0x892E #define GL_REG_14_ATI 0x892F #define GL_REG_15_ATI 0x8930 #define GL_REG_16_ATI 0x8931 #define GL_REG_17_ATI 0x8932 #define GL_REG_18_ATI 0x8933 #define GL_REG_19_ATI 0x8934 #define GL_REG_20_ATI 0x8935 #define GL_REG_21_ATI 0x8936 #define GL_REG_22_ATI 0x8937 #define GL_REG_23_ATI 0x8938 #define GL_REG_24_ATI 0x8939 #define GL_REG_25_ATI 0x893A #define GL_REG_26_ATI 0x893B #define GL_REG_27_ATI 0x893C #define GL_REG_28_ATI 0x893D #define GL_REG_29_ATI 0x893E #define GL_REG_30_ATI 0x893F #define GL_REG_31_ATI 0x8940 #define GL_CON_0_ATI 0x8941 #define GL_CON_1_ATI 0x8942 #define GL_CON_2_ATI 0x8943 #define GL_CON_3_ATI 0x8944 #define GL_CON_4_ATI 0x8945 #define GL_CON_5_ATI 0x8946 #define GL_CON_6_ATI 0x8947 #define GL_CON_7_ATI 0x8948 #define GL_CON_8_ATI 0x8949 #define GL_CON_9_ATI 0x894A #define GL_CON_10_ATI 0x894B #define GL_CON_11_ATI 0x894C #define GL_CON_12_ATI 0x894D #define GL_CON_13_ATI 0x894E #define GL_CON_14_ATI 0x894F #define GL_CON_15_ATI 0x8950 #define GL_CON_16_ATI 0x8951 #define GL_CON_17_ATI 0x8952 #define GL_CON_18_ATI 0x8953 #define GL_CON_19_ATI 0x8954 #define GL_CON_20_ATI 0x8955 #define GL_CON_21_ATI 0x8956 #define GL_CON_22_ATI 0x8957 #define GL_CON_23_ATI 0x8958 #define GL_CON_24_ATI 0x8959 #define GL_CON_25_ATI 0x895A #define GL_CON_26_ATI 0x895B #define GL_CON_27_ATI 0x895C #define GL_CON_28_ATI 0x895D #define GL_CON_29_ATI 0x895E #define GL_CON_30_ATI 0x895F #define GL_CON_31_ATI 0x8960 #define GL_MOV_ATI 0x8961 #define GL_ADD_ATI 0x8963 #define GL_MUL_ATI 0x8964 #define GL_SUB_ATI 0x8965 #define GL_DOT3_ATI 0x8966 #define GL_DOT4_ATI 0x8967 #define GL_MAD_ATI 0x8968 #define GL_LERP_ATI 0x8969 #define GL_CND_ATI 0x896A #define GL_CND0_ATI 0x896B #define GL_DOT2_ADD_ATI 0x896C #define GL_SECONDARY_INTERPOLATOR_ATI 0x896D #define GL_NUM_FRAGMENT_REGISTERS_ATI 0x896E #define GL_NUM_FRAGMENT_CONSTANTS_ATI 0x896F #define GL_NUM_PASSES_ATI 0x8970 #define GL_NUM_INSTRUCTIONS_PER_PASS_ATI 0x8971 #define GL_NUM_INSTRUCTIONS_TOTAL_ATI 0x8972 #define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973 #define GL_NUM_LOOPBACK_COMPONENTS_ATI 0x8974 #define GL_COLOR_ALPHA_PAIRING_ATI 0x8975 #define GL_SWIZZLE_STR_ATI 0x8976 #define GL_SWIZZLE_STQ_ATI 0x8977 #define GL_SWIZZLE_STR_DR_ATI 0x8978 #define GL_SWIZZLE_STQ_DQ_ATI 0x8979 #define GL_SWIZZLE_STRQ_ATI 0x897A #define GL_SWIZZLE_STRQ_DQ_ATI 0x897B #define GL_RED_BIT_ATI 0x00000001 #define GL_GREEN_BIT_ATI 0x00000002 #define GL_BLUE_BIT_ATI 0x00000004 #define GL_2X_BIT_ATI 0x00000001 #define GL_4X_BIT_ATI 0x00000002 #define GL_8X_BIT_ATI 0x00000004 #define GL_HALF_BIT_ATI 0x00000008 #define GL_QUARTER_BIT_ATI 0x00000010 #define GL_EIGHTH_BIT_ATI 0x00000020 #define GL_SATURATE_BIT_ATI 0x00000040 #define GL_COMP_BIT_ATI 0x00000002 #define GL_NEGATE_BIT_ATI 0x00000004 #define GL_BIAS_BIT_ATI 0x00000008 typedef GLuint (APIENTRYP PFNGLGENFRAGMENTSHADERSATIPROC) (GLuint range); typedef void (APIENTRYP PFNGLBINDFRAGMENTSHADERATIPROC) (GLuint id); typedef void (APIENTRYP PFNGLDELETEFRAGMENTSHADERATIPROC) (GLuint id); typedef void (APIENTRYP PFNGLBEGINFRAGMENTSHADERATIPROC) (void); typedef void (APIENTRYP PFNGLENDFRAGMENTSHADERATIPROC) (void); typedef void (APIENTRYP PFNGLPASSTEXCOORDATIPROC) (GLuint dst, GLuint coord, GLenum swizzle); typedef void (APIENTRYP PFNGLSAMPLEMAPATIPROC) (GLuint dst, GLuint interp, GLenum swizzle); typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); typedef void (APIENTRYP PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) (GLuint dst, const GLfloat *value); #ifdef GL_GLEXT_PROTOTYPES GLAPI GLuint APIENTRY glGenFragmentShadersATI (GLuint range); GLAPI void APIENTRY glBindFragmentShaderATI (GLuint id); GLAPI void APIENTRY glDeleteFragmentShaderATI (GLuint id); GLAPI void APIENTRY glBeginFragmentShaderATI (void); GLAPI void APIENTRY glEndFragmentShaderATI (void); GLAPI void APIENTRY glPassTexCoordATI (GLuint dst, GLuint coord, GLenum swizzle); GLAPI void APIENTRY glSampleMapATI (GLuint dst, GLuint interp, GLenum swizzle); GLAPI void APIENTRY glColorFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); GLAPI void APIENTRY glColorFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); GLAPI void APIENTRY glColorFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); GLAPI void APIENTRY glAlphaFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); GLAPI void APIENTRY glAlphaFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); GLAPI void APIENTRY glAlphaFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); GLAPI void APIENTRY glSetFragmentShaderConstantATI (GLuint dst, const GLfloat *value); #endif #endif /* GL_ATI_fragment_shader */ #ifndef GL_ATI_map_object_buffer #define GL_ATI_map_object_buffer 1 typedef void *(APIENTRYP PFNGLMAPOBJECTBUFFERATIPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLUNMAPOBJECTBUFFERATIPROC) (GLuint buffer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void *APIENTRY glMapObjectBufferATI (GLuint buffer); GLAPI void APIENTRY glUnmapObjectBufferATI (GLuint buffer); #endif #endif /* GL_ATI_map_object_buffer */ #ifndef GL_ATI_meminfo #define GL_ATI_meminfo 1 #define GL_VBO_FREE_MEMORY_ATI 0x87FB #define GL_TEXTURE_FREE_MEMORY_ATI 0x87FC #define GL_RENDERBUFFER_FREE_MEMORY_ATI 0x87FD #endif /* GL_ATI_meminfo */ #ifndef GL_ATI_pixel_format_float #define GL_ATI_pixel_format_float 1 #define GL_RGBA_FLOAT_MODE_ATI 0x8820 #define GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI 0x8835 #endif /* GL_ATI_pixel_format_float */ #ifndef GL_ATI_pn_triangles #define GL_ATI_pn_triangles 1 #define GL_PN_TRIANGLES_ATI 0x87F0 #define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1 #define GL_PN_TRIANGLES_POINT_MODE_ATI 0x87F2 #define GL_PN_TRIANGLES_NORMAL_MODE_ATI 0x87F3 #define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4 #define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5 #define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6 #define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7 #define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8 typedef void (APIENTRYP PFNGLPNTRIANGLESIATIPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLPNTRIANGLESFATIPROC) (GLenum pname, GLfloat param); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPNTrianglesiATI (GLenum pname, GLint param); GLAPI void APIENTRY glPNTrianglesfATI (GLenum pname, GLfloat param); #endif #endif /* GL_ATI_pn_triangles */ #ifndef GL_ATI_separate_stencil #define GL_ATI_separate_stencil 1 #define GL_STENCIL_BACK_FUNC_ATI 0x8800 #define GL_STENCIL_BACK_FAIL_ATI 0x8801 #define GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802 #define GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803 typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEATIPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEATIPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glStencilOpSeparateATI (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); GLAPI void APIENTRY glStencilFuncSeparateATI (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); #endif #endif /* GL_ATI_separate_stencil */ #ifndef GL_ATI_text_fragment_shader #define GL_ATI_text_fragment_shader 1 #define GL_TEXT_FRAGMENT_SHADER_ATI 0x8200 #endif /* GL_ATI_text_fragment_shader */ #ifndef GL_ATI_texture_env_combine3 #define GL_ATI_texture_env_combine3 1 #define GL_MODULATE_ADD_ATI 0x8744 #define GL_MODULATE_SIGNED_ADD_ATI 0x8745 #define GL_MODULATE_SUBTRACT_ATI 0x8746 #endif /* GL_ATI_texture_env_combine3 */ #ifndef GL_ATI_texture_float #define GL_ATI_texture_float 1 #define GL_RGBA_FLOAT32_ATI 0x8814 #define GL_RGB_FLOAT32_ATI 0x8815 #define GL_ALPHA_FLOAT32_ATI 0x8816 #define GL_INTENSITY_FLOAT32_ATI 0x8817 #define GL_LUMINANCE_FLOAT32_ATI 0x8818 #define GL_LUMINANCE_ALPHA_FLOAT32_ATI 0x8819 #define GL_RGBA_FLOAT16_ATI 0x881A #define GL_RGB_FLOAT16_ATI 0x881B #define GL_ALPHA_FLOAT16_ATI 0x881C #define GL_INTENSITY_FLOAT16_ATI 0x881D #define GL_LUMINANCE_FLOAT16_ATI 0x881E #define GL_LUMINANCE_ALPHA_FLOAT16_ATI 0x881F #endif /* GL_ATI_texture_float */ #ifndef GL_ATI_texture_mirror_once #define GL_ATI_texture_mirror_once 1 #define GL_MIRROR_CLAMP_ATI 0x8742 #define GL_MIRROR_CLAMP_TO_EDGE_ATI 0x8743 #endif /* GL_ATI_texture_mirror_once */ #ifndef GL_ATI_vertex_array_object #define GL_ATI_vertex_array_object 1 #define GL_STATIC_ATI 0x8760 #define GL_DYNAMIC_ATI 0x8761 #define GL_PRESERVE_ATI 0x8762 #define GL_DISCARD_ATI 0x8763 #define GL_OBJECT_BUFFER_SIZE_ATI 0x8764 #define GL_OBJECT_BUFFER_USAGE_ATI 0x8765 #define GL_ARRAY_OBJECT_BUFFER_ATI 0x8766 #define GL_ARRAY_OBJECT_OFFSET_ATI 0x8767 typedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const void *pointer, GLenum usage); typedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const void *pointer, GLenum preserve); typedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC) (GLuint buffer, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLARRAYOBJECTATIPROC) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); typedef void (APIENTRYP PFNGLGETARRAYOBJECTFVATIPROC) (GLenum array, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETARRAYOBJECTIVATIPROC) (GLenum array, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI GLuint APIENTRY glNewObjectBufferATI (GLsizei size, const void *pointer, GLenum usage); GLAPI GLboolean APIENTRY glIsObjectBufferATI (GLuint buffer); GLAPI void APIENTRY glUpdateObjectBufferATI (GLuint buffer, GLuint offset, GLsizei size, const void *pointer, GLenum preserve); GLAPI void APIENTRY glGetObjectBufferfvATI (GLuint buffer, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetObjectBufferivATI (GLuint buffer, GLenum pname, GLint *params); GLAPI void APIENTRY glFreeObjectBufferATI (GLuint buffer); GLAPI void APIENTRY glArrayObjectATI (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); GLAPI void APIENTRY glGetArrayObjectfvATI (GLenum array, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetArrayObjectivATI (GLenum array, GLenum pname, GLint *params); GLAPI void APIENTRY glVariantArrayObjectATI (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); GLAPI void APIENTRY glGetVariantArrayObjectfvATI (GLuint id, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetVariantArrayObjectivATI (GLuint id, GLenum pname, GLint *params); #endif #endif /* GL_ATI_vertex_array_object */ #ifndef GL_ATI_vertex_attrib_array_object #define GL_ATI_vertex_attrib_array_object 1 typedef void (APIENTRYP PFNGLVERTEXATTRIBARRAYOBJECTATIPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC) (GLuint index, GLenum pname, GLint *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttribArrayObjectATI (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); GLAPI void APIENTRY glGetVertexAttribArrayObjectfvATI (GLuint index, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetVertexAttribArrayObjectivATI (GLuint index, GLenum pname, GLint *params); #endif #endif /* GL_ATI_vertex_attrib_array_object */ #ifndef GL_ATI_vertex_streams #define GL_ATI_vertex_streams 1 #define GL_MAX_VERTEX_STREAMS_ATI 0x876B #define GL_VERTEX_STREAM0_ATI 0x876C #define GL_VERTEX_STREAM1_ATI 0x876D #define GL_VERTEX_STREAM2_ATI 0x876E #define GL_VERTEX_STREAM3_ATI 0x876F #define GL_VERTEX_STREAM4_ATI 0x8770 #define GL_VERTEX_STREAM5_ATI 0x8771 #define GL_VERTEX_STREAM6_ATI 0x8772 #define GL_VERTEX_STREAM7_ATI 0x8773 #define GL_VERTEX_SOURCE_ATI 0x8774 typedef void (APIENTRYP PFNGLVERTEXSTREAM1SATIPROC) (GLenum stream, GLshort x); typedef void (APIENTRYP PFNGLVERTEXSTREAM1SVATIPROC) (GLenum stream, const GLshort *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM1IATIPROC) (GLenum stream, GLint x); typedef void (APIENTRYP PFNGLVERTEXSTREAM1IVATIPROC) (GLenum stream, const GLint *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM1FATIPROC) (GLenum stream, GLfloat x); typedef void (APIENTRYP PFNGLVERTEXSTREAM1FVATIPROC) (GLenum stream, const GLfloat *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM1DATIPROC) (GLenum stream, GLdouble x); typedef void (APIENTRYP PFNGLVERTEXSTREAM1DVATIPROC) (GLenum stream, const GLdouble *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM2SATIPROC) (GLenum stream, GLshort x, GLshort y); typedef void (APIENTRYP PFNGLVERTEXSTREAM2SVATIPROC) (GLenum stream, const GLshort *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM2IATIPROC) (GLenum stream, GLint x, GLint y); typedef void (APIENTRYP PFNGLVERTEXSTREAM2IVATIPROC) (GLenum stream, const GLint *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM2FATIPROC) (GLenum stream, GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLVERTEXSTREAM2FVATIPROC) (GLenum stream, const GLfloat *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM2DATIPROC) (GLenum stream, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLVERTEXSTREAM2DVATIPROC) (GLenum stream, const GLdouble *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM3SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLVERTEXSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM3IATIPROC) (GLenum stream, GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLVERTEXSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM3FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLVERTEXSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM3DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLVERTEXSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM4SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); typedef void (APIENTRYP PFNGLVERTEXSTREAM4SVATIPROC) (GLenum stream, const GLshort *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM4IATIPROC) (GLenum stream, GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLVERTEXSTREAM4IVATIPROC) (GLenum stream, const GLint *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM4FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLVERTEXSTREAM4FVATIPROC) (GLenum stream, const GLfloat *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM4DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLVERTEXSTREAM4DVATIPROC) (GLenum stream, const GLdouble *coords); typedef void (APIENTRYP PFNGLNORMALSTREAM3BATIPROC) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); typedef void (APIENTRYP PFNGLNORMALSTREAM3BVATIPROC) (GLenum stream, const GLbyte *coords); typedef void (APIENTRYP PFNGLNORMALSTREAM3SATIPROC) (GLenum stream, GLshort nx, GLshort ny, GLshort nz); typedef void (APIENTRYP PFNGLNORMALSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); typedef void (APIENTRYP PFNGLNORMALSTREAM3IATIPROC) (GLenum stream, GLint nx, GLint ny, GLint nz); typedef void (APIENTRYP PFNGLNORMALSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); typedef void (APIENTRYP PFNGLNORMALSTREAM3FATIPROC) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); typedef void (APIENTRYP PFNGLNORMALSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); typedef void (APIENTRYP PFNGLNORMALSTREAM3DATIPROC) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); typedef void (APIENTRYP PFNGLNORMALSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); typedef void (APIENTRYP PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC) (GLenum stream); typedef void (APIENTRYP PFNGLVERTEXBLENDENVIATIPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLVERTEXBLENDENVFATIPROC) (GLenum pname, GLfloat param); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexStream1sATI (GLenum stream, GLshort x); GLAPI void APIENTRY glVertexStream1svATI (GLenum stream, const GLshort *coords); GLAPI void APIENTRY glVertexStream1iATI (GLenum stream, GLint x); GLAPI void APIENTRY glVertexStream1ivATI (GLenum stream, const GLint *coords); GLAPI void APIENTRY glVertexStream1fATI (GLenum stream, GLfloat x); GLAPI void APIENTRY glVertexStream1fvATI (GLenum stream, const GLfloat *coords); GLAPI void APIENTRY glVertexStream1dATI (GLenum stream, GLdouble x); GLAPI void APIENTRY glVertexStream1dvATI (GLenum stream, const GLdouble *coords); GLAPI void APIENTRY glVertexStream2sATI (GLenum stream, GLshort x, GLshort y); GLAPI void APIENTRY glVertexStream2svATI (GLenum stream, const GLshort *coords); GLAPI void APIENTRY glVertexStream2iATI (GLenum stream, GLint x, GLint y); GLAPI void APIENTRY glVertexStream2ivATI (GLenum stream, const GLint *coords); GLAPI void APIENTRY glVertexStream2fATI (GLenum stream, GLfloat x, GLfloat y); GLAPI void APIENTRY glVertexStream2fvATI (GLenum stream, const GLfloat *coords); GLAPI void APIENTRY glVertexStream2dATI (GLenum stream, GLdouble x, GLdouble y); GLAPI void APIENTRY glVertexStream2dvATI (GLenum stream, const GLdouble *coords); GLAPI void APIENTRY glVertexStream3sATI (GLenum stream, GLshort x, GLshort y, GLshort z); GLAPI void APIENTRY glVertexStream3svATI (GLenum stream, const GLshort *coords); GLAPI void APIENTRY glVertexStream3iATI (GLenum stream, GLint x, GLint y, GLint z); GLAPI void APIENTRY glVertexStream3ivATI (GLenum stream, const GLint *coords); GLAPI void APIENTRY glVertexStream3fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glVertexStream3fvATI (GLenum stream, const GLfloat *coords); GLAPI void APIENTRY glVertexStream3dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glVertexStream3dvATI (GLenum stream, const GLdouble *coords); GLAPI void APIENTRY glVertexStream4sATI (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); GLAPI void APIENTRY glVertexStream4svATI (GLenum stream, const GLshort *coords); GLAPI void APIENTRY glVertexStream4iATI (GLenum stream, GLint x, GLint y, GLint z, GLint w); GLAPI void APIENTRY glVertexStream4ivATI (GLenum stream, const GLint *coords); GLAPI void APIENTRY glVertexStream4fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glVertexStream4fvATI (GLenum stream, const GLfloat *coords); GLAPI void APIENTRY glVertexStream4dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glVertexStream4dvATI (GLenum stream, const GLdouble *coords); GLAPI void APIENTRY glNormalStream3bATI (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); GLAPI void APIENTRY glNormalStream3bvATI (GLenum stream, const GLbyte *coords); GLAPI void APIENTRY glNormalStream3sATI (GLenum stream, GLshort nx, GLshort ny, GLshort nz); GLAPI void APIENTRY glNormalStream3svATI (GLenum stream, const GLshort *coords); GLAPI void APIENTRY glNormalStream3iATI (GLenum stream, GLint nx, GLint ny, GLint nz); GLAPI void APIENTRY glNormalStream3ivATI (GLenum stream, const GLint *coords); GLAPI void APIENTRY glNormalStream3fATI (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); GLAPI void APIENTRY glNormalStream3fvATI (GLenum stream, const GLfloat *coords); GLAPI void APIENTRY glNormalStream3dATI (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); GLAPI void APIENTRY glNormalStream3dvATI (GLenum stream, const GLdouble *coords); GLAPI void APIENTRY glClientActiveVertexStreamATI (GLenum stream); GLAPI void APIENTRY glVertexBlendEnviATI (GLenum pname, GLint param); GLAPI void APIENTRY glVertexBlendEnvfATI (GLenum pname, GLfloat param); #endif #endif /* GL_ATI_vertex_streams */ #ifndef GL_EXT_422_pixels #define GL_EXT_422_pixels 1 #define GL_422_EXT 0x80CC #define GL_422_REV_EXT 0x80CD #define GL_422_AVERAGE_EXT 0x80CE #define GL_422_REV_AVERAGE_EXT 0x80CF #endif /* GL_EXT_422_pixels */ #ifndef GL_EXT_EGL_image_storage #define GL_EXT_EGL_image_storage 1 typedef void *GLeglImageOES; typedef void (APIENTRYP PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC) (GLenum target, GLeglImageOES image, const GLint* attrib_list); typedef void (APIENTRYP PFNGLEGLIMAGETARGETTEXTURESTORAGEEXTPROC) (GLuint texture, GLeglImageOES image, const GLint* attrib_list); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glEGLImageTargetTexStorageEXT (GLenum target, GLeglImageOES image, const GLint* attrib_list); GLAPI void APIENTRY glEGLImageTargetTextureStorageEXT (GLuint texture, GLeglImageOES image, const GLint* attrib_list); #endif #endif /* GL_EXT_EGL_image_storage */ #ifndef GL_EXT_EGL_sync #define GL_EXT_EGL_sync 1 #endif /* GL_EXT_EGL_sync */ #ifndef GL_EXT_abgr #define GL_EXT_abgr 1 #define GL_ABGR_EXT 0x8000 #endif /* GL_EXT_abgr */ #ifndef GL_EXT_bgra #define GL_EXT_bgra 1 #define GL_BGR_EXT 0x80E0 #define GL_BGRA_EXT 0x80E1 #endif /* GL_EXT_bgra */ #ifndef GL_EXT_bindable_uniform #define GL_EXT_bindable_uniform 1 #define GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT 0x8DE2 #define GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT 0x8DE3 #define GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT 0x8DE4 #define GL_MAX_BINDABLE_UNIFORM_SIZE_EXT 0x8DED #define GL_UNIFORM_BUFFER_EXT 0x8DEE #define GL_UNIFORM_BUFFER_BINDING_EXT 0x8DEF typedef void (APIENTRYP PFNGLUNIFORMBUFFEREXTPROC) (GLuint program, GLint location, GLuint buffer); typedef GLint (APIENTRYP PFNGLGETUNIFORMBUFFERSIZEEXTPROC) (GLuint program, GLint location); typedef GLintptr (APIENTRYP PFNGLGETUNIFORMOFFSETEXTPROC) (GLuint program, GLint location); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glUniformBufferEXT (GLuint program, GLint location, GLuint buffer); GLAPI GLint APIENTRY glGetUniformBufferSizeEXT (GLuint program, GLint location); GLAPI GLintptr APIENTRY glGetUniformOffsetEXT (GLuint program, GLint location); #endif #endif /* GL_EXT_bindable_uniform */ #ifndef GL_EXT_blend_color #define GL_EXT_blend_color 1 #define GL_CONSTANT_COLOR_EXT 0x8001 #define GL_ONE_MINUS_CONSTANT_COLOR_EXT 0x8002 #define GL_CONSTANT_ALPHA_EXT 0x8003 #define GL_ONE_MINUS_CONSTANT_ALPHA_EXT 0x8004 #define GL_BLEND_COLOR_EXT 0x8005 typedef void (APIENTRYP PFNGLBLENDCOLOREXTPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendColorEXT (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); #endif #endif /* GL_EXT_blend_color */ #ifndef GL_EXT_blend_equation_separate #define GL_EXT_blend_equation_separate 1 #define GL_BLEND_EQUATION_RGB_EXT 0x8009 #define GL_BLEND_EQUATION_ALPHA_EXT 0x883D typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEEXTPROC) (GLenum modeRGB, GLenum modeAlpha); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendEquationSeparateEXT (GLenum modeRGB, GLenum modeAlpha); #endif #endif /* GL_EXT_blend_equation_separate */ #ifndef GL_EXT_blend_func_separate #define GL_EXT_blend_func_separate 1 #define GL_BLEND_DST_RGB_EXT 0x80C8 #define GL_BLEND_SRC_RGB_EXT 0x80C9 #define GL_BLEND_DST_ALPHA_EXT 0x80CA #define GL_BLEND_SRC_ALPHA_EXT 0x80CB typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendFuncSeparateEXT (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); #endif #endif /* GL_EXT_blend_func_separate */ #ifndef GL_EXT_blend_logic_op #define GL_EXT_blend_logic_op 1 #endif /* GL_EXT_blend_logic_op */ #ifndef GL_EXT_blend_minmax #define GL_EXT_blend_minmax 1 #define GL_MIN_EXT 0x8007 #define GL_MAX_EXT 0x8008 #define GL_FUNC_ADD_EXT 0x8006 #define GL_BLEND_EQUATION_EXT 0x8009 typedef void (APIENTRYP PFNGLBLENDEQUATIONEXTPROC) (GLenum mode); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendEquationEXT (GLenum mode); #endif #endif /* GL_EXT_blend_minmax */ #ifndef GL_EXT_blend_subtract #define GL_EXT_blend_subtract 1 #define GL_FUNC_SUBTRACT_EXT 0x800A #define GL_FUNC_REVERSE_SUBTRACT_EXT 0x800B #endif /* GL_EXT_blend_subtract */ #ifndef GL_EXT_clip_volume_hint #define GL_EXT_clip_volume_hint 1 #define GL_CLIP_VOLUME_CLIPPING_HINT_EXT 0x80F0 #endif /* GL_EXT_clip_volume_hint */ #ifndef GL_EXT_cmyka #define GL_EXT_cmyka 1 #define GL_CMYK_EXT 0x800C #define GL_CMYKA_EXT 0x800D #define GL_PACK_CMYK_HINT_EXT 0x800E #define GL_UNPACK_CMYK_HINT_EXT 0x800F #endif /* GL_EXT_cmyka */ #ifndef GL_EXT_color_subtable #define GL_EXT_color_subtable 1 typedef void (APIENTRYP PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data); typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorSubTableEXT (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data); GLAPI void APIENTRY glCopyColorSubTableEXT (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); #endif #endif /* GL_EXT_color_subtable */ #ifndef GL_EXT_compiled_vertex_array #define GL_EXT_compiled_vertex_array 1 #define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT 0x81A8 #define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT 0x81A9 typedef void (APIENTRYP PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count); typedef void (APIENTRYP PFNGLUNLOCKARRAYSEXTPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glLockArraysEXT (GLint first, GLsizei count); GLAPI void APIENTRY glUnlockArraysEXT (void); #endif #endif /* GL_EXT_compiled_vertex_array */ #ifndef GL_EXT_convolution #define GL_EXT_convolution 1 #define GL_CONVOLUTION_1D_EXT 0x8010 #define GL_CONVOLUTION_2D_EXT 0x8011 #define GL_SEPARABLE_2D_EXT 0x8012 #define GL_CONVOLUTION_BORDER_MODE_EXT 0x8013 #define GL_CONVOLUTION_FILTER_SCALE_EXT 0x8014 #define GL_CONVOLUTION_FILTER_BIAS_EXT 0x8015 #define GL_REDUCE_EXT 0x8016 #define GL_CONVOLUTION_FORMAT_EXT 0x8017 #define GL_CONVOLUTION_WIDTH_EXT 0x8018 #define GL_CONVOLUTION_HEIGHT_EXT 0x8019 #define GL_MAX_CONVOLUTION_WIDTH_EXT 0x801A #define GL_MAX_CONVOLUTION_HEIGHT_EXT 0x801B #define GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C #define GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D #define GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E #define GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F #define GL_POST_CONVOLUTION_RED_BIAS_EXT 0x8020 #define GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021 #define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022 #define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023 typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image); typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, void *image); typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span); typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image); GLAPI void APIENTRY glConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image); GLAPI void APIENTRY glConvolutionParameterfEXT (GLenum target, GLenum pname, GLfloat params); GLAPI void APIENTRY glConvolutionParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glConvolutionParameteriEXT (GLenum target, GLenum pname, GLint params); GLAPI void APIENTRY glConvolutionParameterivEXT (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glCopyConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); GLAPI void APIENTRY glCopyConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glGetConvolutionFilterEXT (GLenum target, GLenum format, GLenum type, void *image); GLAPI void APIENTRY glGetConvolutionParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetConvolutionParameterivEXT (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetSeparableFilterEXT (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span); GLAPI void APIENTRY glSeparableFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column); #endif #endif /* GL_EXT_convolution */ #ifndef GL_EXT_coordinate_frame #define GL_EXT_coordinate_frame 1 #define GL_TANGENT_ARRAY_EXT 0x8439 #define GL_BINORMAL_ARRAY_EXT 0x843A #define GL_CURRENT_TANGENT_EXT 0x843B #define GL_CURRENT_BINORMAL_EXT 0x843C #define GL_TANGENT_ARRAY_TYPE_EXT 0x843E #define GL_TANGENT_ARRAY_STRIDE_EXT 0x843F #define GL_BINORMAL_ARRAY_TYPE_EXT 0x8440 #define GL_BINORMAL_ARRAY_STRIDE_EXT 0x8441 #define GL_TANGENT_ARRAY_POINTER_EXT 0x8442 #define GL_BINORMAL_ARRAY_POINTER_EXT 0x8443 #define GL_MAP1_TANGENT_EXT 0x8444 #define GL_MAP2_TANGENT_EXT 0x8445 #define GL_MAP1_BINORMAL_EXT 0x8446 #define GL_MAP2_BINORMAL_EXT 0x8447 typedef void (APIENTRYP PFNGLTANGENT3BEXTPROC) (GLbyte tx, GLbyte ty, GLbyte tz); typedef void (APIENTRYP PFNGLTANGENT3BVEXTPROC) (const GLbyte *v); typedef void (APIENTRYP PFNGLTANGENT3DEXTPROC) (GLdouble tx, GLdouble ty, GLdouble tz); typedef void (APIENTRYP PFNGLTANGENT3DVEXTPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLTANGENT3FEXTPROC) (GLfloat tx, GLfloat ty, GLfloat tz); typedef void (APIENTRYP PFNGLTANGENT3FVEXTPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLTANGENT3IEXTPROC) (GLint tx, GLint ty, GLint tz); typedef void (APIENTRYP PFNGLTANGENT3IVEXTPROC) (const GLint *v); typedef void (APIENTRYP PFNGLTANGENT3SEXTPROC) (GLshort tx, GLshort ty, GLshort tz); typedef void (APIENTRYP PFNGLTANGENT3SVEXTPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLBINORMAL3BEXTPROC) (GLbyte bx, GLbyte by, GLbyte bz); typedef void (APIENTRYP PFNGLBINORMAL3BVEXTPROC) (const GLbyte *v); typedef void (APIENTRYP PFNGLBINORMAL3DEXTPROC) (GLdouble bx, GLdouble by, GLdouble bz); typedef void (APIENTRYP PFNGLBINORMAL3DVEXTPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLBINORMAL3FEXTPROC) (GLfloat bx, GLfloat by, GLfloat bz); typedef void (APIENTRYP PFNGLBINORMAL3FVEXTPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLBINORMAL3IEXTPROC) (GLint bx, GLint by, GLint bz); typedef void (APIENTRYP PFNGLBINORMAL3IVEXTPROC) (const GLint *v); typedef void (APIENTRYP PFNGLBINORMAL3SEXTPROC) (GLshort bx, GLshort by, GLshort bz); typedef void (APIENTRYP PFNGLBINORMAL3SVEXTPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer); typedef void (APIENTRYP PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTangent3bEXT (GLbyte tx, GLbyte ty, GLbyte tz); GLAPI void APIENTRY glTangent3bvEXT (const GLbyte *v); GLAPI void APIENTRY glTangent3dEXT (GLdouble tx, GLdouble ty, GLdouble tz); GLAPI void APIENTRY glTangent3dvEXT (const GLdouble *v); GLAPI void APIENTRY glTangent3fEXT (GLfloat tx, GLfloat ty, GLfloat tz); GLAPI void APIENTRY glTangent3fvEXT (const GLfloat *v); GLAPI void APIENTRY glTangent3iEXT (GLint tx, GLint ty, GLint tz); GLAPI void APIENTRY glTangent3ivEXT (const GLint *v); GLAPI void APIENTRY glTangent3sEXT (GLshort tx, GLshort ty, GLshort tz); GLAPI void APIENTRY glTangent3svEXT (const GLshort *v); GLAPI void APIENTRY glBinormal3bEXT (GLbyte bx, GLbyte by, GLbyte bz); GLAPI void APIENTRY glBinormal3bvEXT (const GLbyte *v); GLAPI void APIENTRY glBinormal3dEXT (GLdouble bx, GLdouble by, GLdouble bz); GLAPI void APIENTRY glBinormal3dvEXT (const GLdouble *v); GLAPI void APIENTRY glBinormal3fEXT (GLfloat bx, GLfloat by, GLfloat bz); GLAPI void APIENTRY glBinormal3fvEXT (const GLfloat *v); GLAPI void APIENTRY glBinormal3iEXT (GLint bx, GLint by, GLint bz); GLAPI void APIENTRY glBinormal3ivEXT (const GLint *v); GLAPI void APIENTRY glBinormal3sEXT (GLshort bx, GLshort by, GLshort bz); GLAPI void APIENTRY glBinormal3svEXT (const GLshort *v); GLAPI void APIENTRY glTangentPointerEXT (GLenum type, GLsizei stride, const void *pointer); GLAPI void APIENTRY glBinormalPointerEXT (GLenum type, GLsizei stride, const void *pointer); #endif #endif /* GL_EXT_coordinate_frame */ #ifndef GL_EXT_copy_texture #define GL_EXT_copy_texture 1 typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCopyTexImage1DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); GLAPI void APIENTRY glCopyTexImage2DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); GLAPI void APIENTRY glCopyTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); GLAPI void APIENTRY glCopyTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glCopyTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); #endif #endif /* GL_EXT_copy_texture */ #ifndef GL_EXT_cull_vertex #define GL_EXT_cull_vertex 1 #define GL_CULL_VERTEX_EXT 0x81AA #define GL_CULL_VERTEX_EYE_POSITION_EXT 0x81AB #define GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC typedef void (APIENTRYP PFNGLCULLPARAMETERDVEXTPROC) (GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCullParameterdvEXT (GLenum pname, GLdouble *params); GLAPI void APIENTRY glCullParameterfvEXT (GLenum pname, GLfloat *params); #endif #endif /* GL_EXT_cull_vertex */ #ifndef GL_EXT_debug_label #define GL_EXT_debug_label 1 #define GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F #define GL_PROGRAM_OBJECT_EXT 0x8B40 #define GL_SHADER_OBJECT_EXT 0x8B48 #define GL_BUFFER_OBJECT_EXT 0x9151 #define GL_QUERY_OBJECT_EXT 0x9153 #define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154 typedef void (APIENTRYP PFNGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label); typedef void (APIENTRYP PFNGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glLabelObjectEXT (GLenum type, GLuint object, GLsizei length, const GLchar *label); GLAPI void APIENTRY glGetObjectLabelEXT (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label); #endif #endif /* GL_EXT_debug_label */ #ifndef GL_EXT_debug_marker #define GL_EXT_debug_marker 1 typedef void (APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker); typedef void (APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker); typedef void (APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar *marker); GLAPI void APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar *marker); GLAPI void APIENTRY glPopGroupMarkerEXT (void); #endif #endif /* GL_EXT_debug_marker */ #ifndef GL_EXT_depth_bounds_test #define GL_EXT_depth_bounds_test 1 #define GL_DEPTH_BOUNDS_TEST_EXT 0x8890 #define GL_DEPTH_BOUNDS_EXT 0x8891 typedef void (APIENTRYP PFNGLDEPTHBOUNDSEXTPROC) (GLclampd zmin, GLclampd zmax); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDepthBoundsEXT (GLclampd zmin, GLclampd zmax); #endif #endif /* GL_EXT_depth_bounds_test */ #ifndef GL_EXT_direct_state_access #define GL_EXT_direct_state_access 1 #define GL_PROGRAM_MATRIX_EXT 0x8E2D #define GL_TRANSPOSE_PROGRAM_MATRIX_EXT 0x8E2E #define GL_PROGRAM_MATRIX_STACK_DEPTH_EXT 0x8E2F typedef void (APIENTRYP PFNGLMATRIXLOADFEXTPROC) (GLenum mode, const GLfloat *m); typedef void (APIENTRYP PFNGLMATRIXLOADDEXTPROC) (GLenum mode, const GLdouble *m); typedef void (APIENTRYP PFNGLMATRIXMULTFEXTPROC) (GLenum mode, const GLfloat *m); typedef void (APIENTRYP PFNGLMATRIXMULTDEXTPROC) (GLenum mode, const GLdouble *m); typedef void (APIENTRYP PFNGLMATRIXLOADIDENTITYEXTPROC) (GLenum mode); typedef void (APIENTRYP PFNGLMATRIXROTATEFEXTPROC) (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLMATRIXROTATEDEXTPROC) (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLMATRIXSCALEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLMATRIXSCALEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLMATRIXTRANSLATEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLMATRIXTRANSLATEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLMATRIXFRUSTUMEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); typedef void (APIENTRYP PFNGLMATRIXORTHOEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); typedef void (APIENTRYP PFNGLMATRIXPOPEXTPROC) (GLenum mode); typedef void (APIENTRYP PFNGLMATRIXPUSHEXTPROC) (GLenum mode); typedef void (APIENTRYP PFNGLCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); typedef void (APIENTRYP PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLBINDMULTITEXTUREEXTPROC) (GLenum texunit, GLenum target, GLuint texture); typedef void (APIENTRYP PFNGLMULTITEXCOORDPOINTEREXTPROC) (GLenum texunit, GLint size, GLenum type, GLsizei stride, const void *pointer); typedef void (APIENTRYP PFNGLMULTITEXENVFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLMULTITEXENVIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLMULTITEXGENDEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble param); typedef void (APIENTRYP PFNGLMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params); typedef void (APIENTRYP PFNGLMULTITEXGENFEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLMULTITEXGENIEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLGETMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLENABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); typedef void (APIENTRYP PFNGLGETFLOATINDEXEDVEXTPROC) (GLenum target, GLuint index, GLfloat *data); typedef void (APIENTRYP PFNGLGETDOUBLEINDEXEDVEXTPROC) (GLenum target, GLuint index, GLdouble *data); typedef void (APIENTRYP PFNGLGETPOINTERINDEXEDVEXTPROC) (GLenum target, GLuint index, void **data); typedef void (APIENTRYP PFNGLENABLEINDEXEDEXTPROC) (GLenum target, GLuint index); typedef void (APIENTRYP PFNGLDISABLEINDEXEDEXTPROC) (GLenum target, GLuint index); typedef GLboolean (APIENTRYP PFNGLISENABLEDINDEXEDEXTPROC) (GLenum target, GLuint index); typedef void (APIENTRYP PFNGLGETINTEGERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLint *data); typedef void (APIENTRYP PFNGLGETBOOLEANINDEXEDVEXTPROC) (GLenum target, GLuint index, GLboolean *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint lod, void *img); typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); typedef void (APIENTRYP PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint lod, void *img); typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); typedef void (APIENTRYP PFNGLNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage); typedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFEREXTPROC) (GLuint buffer, GLenum access); typedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFEREXTPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVEXTPROC) (GLuint buffer, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVEXTPROC) (GLuint buffer, GLenum pname, void **params); typedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLTEXTUREBUFFEREXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); typedef void (APIENTRYP PFNGLMULTITEXBUFFEREXTPROC) (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLuint *params); typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLuint *params); typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IEXTPROC) (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLint *params); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLuint *params); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params); typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLint *params); typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIUIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint *params); typedef void (APIENTRYP PFNGLENABLECLIENTSTATEIEXTPROC) (GLenum array, GLuint index); typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEIEXTPROC) (GLenum array, GLuint index); typedef void (APIENTRYP PFNGLGETFLOATI_VEXTPROC) (GLenum pname, GLuint index, GLfloat *params); typedef void (APIENTRYP PFNGLGETDOUBLEI_VEXTPROC) (GLenum pname, GLuint index, GLdouble *params); typedef void (APIENTRYP PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, void **params); typedef void (APIENTRYP PFNGLNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum format, GLsizei len, const void *string); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLdouble *params); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLfloat *params); typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERDVEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble *params); typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERFVEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat *params); typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMIVEXTPROC) (GLuint program, GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum pname, void *string); typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVEXTPROC) (GLuint renderbuffer, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC) (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); typedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSEXTPROC) (GLuint framebuffer, GLenum target); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE1DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE2DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE3DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFEREXTPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPEXTPROC) (GLuint texture, GLenum target); typedef void (APIENTRYP PFNGLGENERATEMULTITEXMIPMAPEXTPROC) (GLenum texunit, GLenum target); typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFEREXTPROC) (GLuint framebuffer, GLenum mode); typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFERSEXTPROC) (GLuint framebuffer, GLsizei n, const GLenum *bufs); typedef void (APIENTRYP PFNGLFRAMEBUFFERREADBUFFEREXTPROC) (GLuint framebuffer, GLenum mode); typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLNAMEDCOPYBUFFERSUBDATAEXTPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYEREXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREFACEEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); typedef void (APIENTRYP PFNGLTEXTURERENDERBUFFEREXTPROC) (GLuint texture, GLenum target, GLuint renderbuffer); typedef void (APIENTRYP PFNGLMULTITEXRENDERBUFFEREXTPROC) (GLenum texunit, GLenum target, GLuint renderbuffer); typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); typedef void (APIENTRYP PFNGLVERTEXARRAYCOLOROFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); typedef void (APIENTRYP PFNGLVERTEXARRAYEDGEFLAGOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset); typedef void (APIENTRYP PFNGLVERTEXARRAYINDEXOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); typedef void (APIENTRYP PFNGLVERTEXARRAYNORMALOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); typedef void (APIENTRYP PFNGLVERTEXARRAYTEXCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); typedef void (APIENTRYP PFNGLVERTEXARRAYMULTITEXCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, GLsizei stride, GLintptr offset); typedef void (APIENTRYP PFNGLVERTEXARRAYFOGCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); typedef void (APIENTRYP PFNGLVERTEXARRAYSECONDARYCOLOROFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset); typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBIOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYEXTPROC) (GLuint vaobj, GLenum array); typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYEXTPROC) (GLuint vaobj, GLenum array); typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYATTRIBEXTPROC) (GLuint vaobj, GLuint index); typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYATTRIBEXTPROC) (GLuint vaobj, GLuint index); typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERVEXTPROC) (GLuint vaobj, GLenum pname, GLint *param); typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERVEXTPROC) (GLuint vaobj, GLenum pname, void **param); typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param); typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, void **param); typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); typedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); typedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEEXTPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags); typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIEXTPROC) (GLuint framebuffer, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DEXTPROC) (GLuint program, GLint location, GLdouble x); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLTEXTUREBUFFERRANGEEXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DMULTISAMPLEEXTPROC) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); typedef void (APIENTRYP PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC) (GLuint vaobj, GLuint attribindex, GLuint bindingindex); typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint divisor); typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); typedef void (APIENTRYP PFNGLTEXTUREPAGECOMMITMENTEXTPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBDIVISOREXTPROC) (GLuint vaobj, GLuint index, GLuint divisor); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMatrixLoadfEXT (GLenum mode, const GLfloat *m); GLAPI void APIENTRY glMatrixLoaddEXT (GLenum mode, const GLdouble *m); GLAPI void APIENTRY glMatrixMultfEXT (GLenum mode, const GLfloat *m); GLAPI void APIENTRY glMatrixMultdEXT (GLenum mode, const GLdouble *m); GLAPI void APIENTRY glMatrixLoadIdentityEXT (GLenum mode); GLAPI void APIENTRY glMatrixRotatefEXT (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glMatrixRotatedEXT (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glMatrixScalefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glMatrixScaledEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glMatrixTranslatefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glMatrixTranslatedEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glMatrixFrustumEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); GLAPI void APIENTRY glMatrixOrthoEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); GLAPI void APIENTRY glMatrixPopEXT (GLenum mode); GLAPI void APIENTRY glMatrixPushEXT (GLenum mode); GLAPI void APIENTRY glClientAttribDefaultEXT (GLbitfield mask); GLAPI void APIENTRY glPushClientAttribDefaultEXT (GLbitfield mask); GLAPI void APIENTRY glTextureParameterfEXT (GLuint texture, GLenum target, GLenum pname, GLfloat param); GLAPI void APIENTRY glTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glTextureParameteriEXT (GLuint texture, GLenum target, GLenum pname, GLint param); GLAPI void APIENTRY glTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glCopyTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); GLAPI void APIENTRY glCopyTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); GLAPI void APIENTRY glCopyTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); GLAPI void APIENTRY glCopyTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glGetTextureImageEXT (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); GLAPI void APIENTRY glGetTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetTextureLevelParameterfvEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetTextureLevelParameterivEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); GLAPI void APIENTRY glTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glCopyTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glBindMultiTextureEXT (GLenum texunit, GLenum target, GLuint texture); GLAPI void APIENTRY glMultiTexCoordPointerEXT (GLenum texunit, GLint size, GLenum type, GLsizei stride, const void *pointer); GLAPI void APIENTRY glMultiTexEnvfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param); GLAPI void APIENTRY glMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glMultiTexEnviEXT (GLenum texunit, GLenum target, GLenum pname, GLint param); GLAPI void APIENTRY glMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glMultiTexGendEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble param); GLAPI void APIENTRY glMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params); GLAPI void APIENTRY glMultiTexGenfEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat param); GLAPI void APIENTRY glMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glMultiTexGeniEXT (GLenum texunit, GLenum coord, GLenum pname, GLint param); GLAPI void APIENTRY glMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, const GLint *params); GLAPI void APIENTRY glGetMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params); GLAPI void APIENTRY glGetMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, GLint *params); GLAPI void APIENTRY glMultiTexParameteriEXT (GLenum texunit, GLenum target, GLenum pname, GLint param); GLAPI void APIENTRY glMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glMultiTexParameterfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param); GLAPI void APIENTRY glMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glCopyMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); GLAPI void APIENTRY glCopyMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); GLAPI void APIENTRY glCopyMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); GLAPI void APIENTRY glCopyMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glGetMultiTexImageEXT (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); GLAPI void APIENTRY glGetMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetMultiTexLevelParameterfvEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetMultiTexLevelParameterivEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); GLAPI void APIENTRY glMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glCopyMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glEnableClientStateIndexedEXT (GLenum array, GLuint index); GLAPI void APIENTRY glDisableClientStateIndexedEXT (GLenum array, GLuint index); GLAPI void APIENTRY glGetFloatIndexedvEXT (GLenum target, GLuint index, GLfloat *data); GLAPI void APIENTRY glGetDoubleIndexedvEXT (GLenum target, GLuint index, GLdouble *data); GLAPI void APIENTRY glGetPointerIndexedvEXT (GLenum target, GLuint index, void **data); GLAPI void APIENTRY glEnableIndexedEXT (GLenum target, GLuint index); GLAPI void APIENTRY glDisableIndexedEXT (GLenum target, GLuint index); GLAPI GLboolean APIENTRY glIsEnabledIndexedEXT (GLenum target, GLuint index); GLAPI void APIENTRY glGetIntegerIndexedvEXT (GLenum target, GLuint index, GLint *data); GLAPI void APIENTRY glGetBooleanIndexedvEXT (GLenum target, GLuint index, GLboolean *data); GLAPI void APIENTRY glCompressedTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); GLAPI void APIENTRY glCompressedTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); GLAPI void APIENTRY glCompressedTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); GLAPI void APIENTRY glCompressedTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); GLAPI void APIENTRY glCompressedTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); GLAPI void APIENTRY glCompressedTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); GLAPI void APIENTRY glGetCompressedTextureImageEXT (GLuint texture, GLenum target, GLint lod, void *img); GLAPI void APIENTRY glCompressedMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); GLAPI void APIENTRY glCompressedMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); GLAPI void APIENTRY glCompressedMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); GLAPI void APIENTRY glCompressedMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); GLAPI void APIENTRY glCompressedMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); GLAPI void APIENTRY glCompressedMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); GLAPI void APIENTRY glGetCompressedMultiTexImageEXT (GLenum texunit, GLenum target, GLint lod, void *img); GLAPI void APIENTRY glMatrixLoadTransposefEXT (GLenum mode, const GLfloat *m); GLAPI void APIENTRY glMatrixLoadTransposedEXT (GLenum mode, const GLdouble *m); GLAPI void APIENTRY glMatrixMultTransposefEXT (GLenum mode, const GLfloat *m); GLAPI void APIENTRY glMatrixMultTransposedEXT (GLenum mode, const GLdouble *m); GLAPI void APIENTRY glNamedBufferDataEXT (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage); GLAPI void APIENTRY glNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); GLAPI void *APIENTRY glMapNamedBufferEXT (GLuint buffer, GLenum access); GLAPI GLboolean APIENTRY glUnmapNamedBufferEXT (GLuint buffer); GLAPI void APIENTRY glGetNamedBufferParameterivEXT (GLuint buffer, GLenum pname, GLint *params); GLAPI void APIENTRY glGetNamedBufferPointervEXT (GLuint buffer, GLenum pname, void **params); GLAPI void APIENTRY glGetNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data); GLAPI void APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat v0); GLAPI void APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1); GLAPI void APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); GLAPI void APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); GLAPI void APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint v0); GLAPI void APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint v0, GLint v1); GLAPI void APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); GLAPI void APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); GLAPI void APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix2x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix3x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix2x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix4x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix3x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix4x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glTextureBufferEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); GLAPI void APIENTRY glMultiTexBufferEXT (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); GLAPI void APIENTRY glTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, const GLuint *params); GLAPI void APIENTRY glGetTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, GLuint *params); GLAPI void APIENTRY glMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, const GLuint *params); GLAPI void APIENTRY glGetMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, GLuint *params); GLAPI void APIENTRY glProgramUniform1uiEXT (GLuint program, GLint location, GLuint v0); GLAPI void APIENTRY glProgramUniform2uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1); GLAPI void APIENTRY glProgramUniform3uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); GLAPI void APIENTRY glProgramUniform4uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); GLAPI void APIENTRY glProgramUniform1uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glProgramUniform2uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glProgramUniform3uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glProgramUniform4uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glNamedProgramLocalParameters4fvEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params); GLAPI void APIENTRY glNamedProgramLocalParameterI4iEXT (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); GLAPI void APIENTRY glNamedProgramLocalParameterI4ivEXT (GLuint program, GLenum target, GLuint index, const GLint *params); GLAPI void APIENTRY glNamedProgramLocalParametersI4ivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params); GLAPI void APIENTRY glNamedProgramLocalParameterI4uiEXT (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); GLAPI void APIENTRY glNamedProgramLocalParameterI4uivEXT (GLuint program, GLenum target, GLuint index, const GLuint *params); GLAPI void APIENTRY glNamedProgramLocalParametersI4uivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params); GLAPI void APIENTRY glGetNamedProgramLocalParameterIivEXT (GLuint program, GLenum target, GLuint index, GLint *params); GLAPI void APIENTRY glGetNamedProgramLocalParameterIuivEXT (GLuint program, GLenum target, GLuint index, GLuint *params); GLAPI void APIENTRY glEnableClientStateiEXT (GLenum array, GLuint index); GLAPI void APIENTRY glDisableClientStateiEXT (GLenum array, GLuint index); GLAPI void APIENTRY glGetFloati_vEXT (GLenum pname, GLuint index, GLfloat *params); GLAPI void APIENTRY glGetDoublei_vEXT (GLenum pname, GLuint index, GLdouble *params); GLAPI void APIENTRY glGetPointeri_vEXT (GLenum pname, GLuint index, void **params); GLAPI void APIENTRY glNamedProgramStringEXT (GLuint program, GLenum target, GLenum format, GLsizei len, const void *string); GLAPI void APIENTRY glNamedProgramLocalParameter4dEXT (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glNamedProgramLocalParameter4dvEXT (GLuint program, GLenum target, GLuint index, const GLdouble *params); GLAPI void APIENTRY glNamedProgramLocalParameter4fEXT (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glNamedProgramLocalParameter4fvEXT (GLuint program, GLenum target, GLuint index, const GLfloat *params); GLAPI void APIENTRY glGetNamedProgramLocalParameterdvEXT (GLuint program, GLenum target, GLuint index, GLdouble *params); GLAPI void APIENTRY glGetNamedProgramLocalParameterfvEXT (GLuint program, GLenum target, GLuint index, GLfloat *params); GLAPI void APIENTRY glGetNamedProgramivEXT (GLuint program, GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetNamedProgramStringEXT (GLuint program, GLenum target, GLenum pname, void *string); GLAPI void APIENTRY glNamedRenderbufferStorageEXT (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); GLAPI void APIENTRY glGetNamedRenderbufferParameterivEXT (GLuint renderbuffer, GLenum pname, GLint *params); GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleEXT (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleCoverageEXT (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); GLAPI GLenum APIENTRY glCheckNamedFramebufferStatusEXT (GLuint framebuffer, GLenum target); GLAPI void APIENTRY glNamedFramebufferTexture1DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); GLAPI void APIENTRY glNamedFramebufferTexture2DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); GLAPI void APIENTRY glNamedFramebufferTexture3DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); GLAPI void APIENTRY glNamedFramebufferRenderbufferEXT (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); GLAPI void APIENTRY glGetNamedFramebufferAttachmentParameterivEXT (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); GLAPI void APIENTRY glGenerateTextureMipmapEXT (GLuint texture, GLenum target); GLAPI void APIENTRY glGenerateMultiTexMipmapEXT (GLenum texunit, GLenum target); GLAPI void APIENTRY glFramebufferDrawBufferEXT (GLuint framebuffer, GLenum mode); GLAPI void APIENTRY glFramebufferDrawBuffersEXT (GLuint framebuffer, GLsizei n, const GLenum *bufs); GLAPI void APIENTRY glFramebufferReadBufferEXT (GLuint framebuffer, GLenum mode); GLAPI void APIENTRY glGetFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params); GLAPI void APIENTRY glNamedCopyBufferSubDataEXT (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); GLAPI void APIENTRY glNamedFramebufferTextureEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); GLAPI void APIENTRY glNamedFramebufferTextureLayerEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); GLAPI void APIENTRY glNamedFramebufferTextureFaceEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); GLAPI void APIENTRY glTextureRenderbufferEXT (GLuint texture, GLenum target, GLuint renderbuffer); GLAPI void APIENTRY glMultiTexRenderbufferEXT (GLenum texunit, GLenum target, GLuint renderbuffer); GLAPI void APIENTRY glVertexArrayVertexOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); GLAPI void APIENTRY glVertexArrayColorOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); GLAPI void APIENTRY glVertexArrayEdgeFlagOffsetEXT (GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset); GLAPI void APIENTRY glVertexArrayIndexOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); GLAPI void APIENTRY glVertexArrayNormalOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); GLAPI void APIENTRY glVertexArrayTexCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); GLAPI void APIENTRY glVertexArrayMultiTexCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, GLsizei stride, GLintptr offset); GLAPI void APIENTRY glVertexArrayFogCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); GLAPI void APIENTRY glVertexArraySecondaryColorOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); GLAPI void APIENTRY glVertexArrayVertexAttribOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset); GLAPI void APIENTRY glVertexArrayVertexAttribIOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); GLAPI void APIENTRY glEnableVertexArrayEXT (GLuint vaobj, GLenum array); GLAPI void APIENTRY glDisableVertexArrayEXT (GLuint vaobj, GLenum array); GLAPI void APIENTRY glEnableVertexArrayAttribEXT (GLuint vaobj, GLuint index); GLAPI void APIENTRY glDisableVertexArrayAttribEXT (GLuint vaobj, GLuint index); GLAPI void APIENTRY glGetVertexArrayIntegervEXT (GLuint vaobj, GLenum pname, GLint *param); GLAPI void APIENTRY glGetVertexArrayPointervEXT (GLuint vaobj, GLenum pname, void **param); GLAPI void APIENTRY glGetVertexArrayIntegeri_vEXT (GLuint vaobj, GLuint index, GLenum pname, GLint *param); GLAPI void APIENTRY glGetVertexArrayPointeri_vEXT (GLuint vaobj, GLuint index, GLenum pname, void **param); GLAPI void *APIENTRY glMapNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); GLAPI void APIENTRY glFlushMappedNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length); GLAPI void APIENTRY glNamedBufferStorageEXT (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags); GLAPI void APIENTRY glClearNamedBufferDataEXT (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); GLAPI void APIENTRY glClearNamedBufferSubDataEXT (GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); GLAPI void APIENTRY glNamedFramebufferParameteriEXT (GLuint framebuffer, GLenum pname, GLint param); GLAPI void APIENTRY glGetNamedFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params); GLAPI void APIENTRY glProgramUniform1dEXT (GLuint program, GLint location, GLdouble x); GLAPI void APIENTRY glProgramUniform2dEXT (GLuint program, GLint location, GLdouble x, GLdouble y); GLAPI void APIENTRY glProgramUniform3dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glProgramUniform4dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glProgramUniform1dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glProgramUniform2dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glProgramUniform3dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glProgramUniform4dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix2x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix2x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix3x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix3x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix4x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix4x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glTextureBufferRangeEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); GLAPI void APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); GLAPI void APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); GLAPI void APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); GLAPI void APIENTRY glTextureStorage2DMultisampleEXT (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); GLAPI void APIENTRY glTextureStorage3DMultisampleEXT (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); GLAPI void APIENTRY glVertexArrayBindVertexBufferEXT (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); GLAPI void APIENTRY glVertexArrayVertexAttribFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); GLAPI void APIENTRY glVertexArrayVertexAttribIFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); GLAPI void APIENTRY glVertexArrayVertexAttribLFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); GLAPI void APIENTRY glVertexArrayVertexAttribBindingEXT (GLuint vaobj, GLuint attribindex, GLuint bindingindex); GLAPI void APIENTRY glVertexArrayVertexBindingDivisorEXT (GLuint vaobj, GLuint bindingindex, GLuint divisor); GLAPI void APIENTRY glVertexArrayVertexAttribLOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); GLAPI void APIENTRY glTexturePageCommitmentEXT (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); GLAPI void APIENTRY glVertexArrayVertexAttribDivisorEXT (GLuint vaobj, GLuint index, GLuint divisor); #endif #endif /* GL_EXT_direct_state_access */ #ifndef GL_EXT_draw_buffers2 #define GL_EXT_draw_buffers2 1 typedef void (APIENTRYP PFNGLCOLORMASKINDEXEDEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorMaskIndexedEXT (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); #endif #endif /* GL_EXT_draw_buffers2 */ #ifndef GL_EXT_draw_instanced #define GL_EXT_draw_instanced 1 typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount); typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawArraysInstancedEXT (GLenum mode, GLint start, GLsizei count, GLsizei primcount); GLAPI void APIENTRY glDrawElementsInstancedEXT (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); #endif #endif /* GL_EXT_draw_instanced */ #ifndef GL_EXT_draw_range_elements #define GL_EXT_draw_range_elements 1 #define GL_MAX_ELEMENTS_VERTICES_EXT 0x80E8 #define GL_MAX_ELEMENTS_INDICES_EXT 0x80E9 typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawRangeElementsEXT (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); #endif #endif /* GL_EXT_draw_range_elements */ #ifndef GL_EXT_external_buffer #define GL_EXT_external_buffer 1 typedef void *GLeglClientBufferEXT; typedef void (APIENTRYP PFNGLBUFFERSTORAGEEXTERNALEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags); typedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEEXTERNALEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBufferStorageExternalEXT (GLenum target, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags); GLAPI void APIENTRY glNamedBufferStorageExternalEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags); #endif #endif /* GL_EXT_external_buffer */ #ifndef GL_EXT_fog_coord #define GL_EXT_fog_coord 1 #define GL_FOG_COORDINATE_SOURCE_EXT 0x8450 #define GL_FOG_COORDINATE_EXT 0x8451 #define GL_FRAGMENT_DEPTH_EXT 0x8452 #define GL_CURRENT_FOG_COORDINATE_EXT 0x8453 #define GL_FOG_COORDINATE_ARRAY_TYPE_EXT 0x8454 #define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455 #define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456 #define GL_FOG_COORDINATE_ARRAY_EXT 0x8457 typedef void (APIENTRYP PFNGLFOGCOORDFEXTPROC) (GLfloat coord); typedef void (APIENTRYP PFNGLFOGCOORDFVEXTPROC) (const GLfloat *coord); typedef void (APIENTRYP PFNGLFOGCOORDDEXTPROC) (GLdouble coord); typedef void (APIENTRYP PFNGLFOGCOORDDVEXTPROC) (const GLdouble *coord); typedef void (APIENTRYP PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFogCoordfEXT (GLfloat coord); GLAPI void APIENTRY glFogCoordfvEXT (const GLfloat *coord); GLAPI void APIENTRY glFogCoorddEXT (GLdouble coord); GLAPI void APIENTRY glFogCoorddvEXT (const GLdouble *coord); GLAPI void APIENTRY glFogCoordPointerEXT (GLenum type, GLsizei stride, const void *pointer); #endif #endif /* GL_EXT_fog_coord */ #ifndef GL_EXT_framebuffer_blit #define GL_EXT_framebuffer_blit 1 #define GL_READ_FRAMEBUFFER_EXT 0x8CA8 #define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 #define GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CA6 #define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA typedef void (APIENTRYP PFNGLBLITFRAMEBUFFEREXTPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlitFramebufferEXT (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); #endif #endif /* GL_EXT_framebuffer_blit */ #ifndef GL_EXT_framebuffer_multisample #define GL_EXT_framebuffer_multisample 1 #define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 #define GL_MAX_SAMPLES_EXT 0x8D57 typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glRenderbufferStorageMultisampleEXT (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); #endif #endif /* GL_EXT_framebuffer_multisample */ #ifndef GL_EXT_framebuffer_multisample_blit_scaled #define GL_EXT_framebuffer_multisample_blit_scaled 1 #define GL_SCALED_RESOLVE_FASTEST_EXT 0x90BA #define GL_SCALED_RESOLVE_NICEST_EXT 0x90BB #endif /* GL_EXT_framebuffer_multisample_blit_scaled */ #ifndef GL_EXT_framebuffer_object #define GL_EXT_framebuffer_object 1 #define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506 #define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8 #define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6 #define GL_RENDERBUFFER_BINDING_EXT 0x8CA7 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4 #define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9 #define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA #define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB #define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC #define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD #define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF #define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 #define GL_COLOR_ATTACHMENT1_EXT 0x8CE1 #define GL_COLOR_ATTACHMENT2_EXT 0x8CE2 #define GL_COLOR_ATTACHMENT3_EXT 0x8CE3 #define GL_COLOR_ATTACHMENT4_EXT 0x8CE4 #define GL_COLOR_ATTACHMENT5_EXT 0x8CE5 #define GL_COLOR_ATTACHMENT6_EXT 0x8CE6 #define GL_COLOR_ATTACHMENT7_EXT 0x8CE7 #define GL_COLOR_ATTACHMENT8_EXT 0x8CE8 #define GL_COLOR_ATTACHMENT9_EXT 0x8CE9 #define GL_COLOR_ATTACHMENT10_EXT 0x8CEA #define GL_COLOR_ATTACHMENT11_EXT 0x8CEB #define GL_COLOR_ATTACHMENT12_EXT 0x8CEC #define GL_COLOR_ATTACHMENT13_EXT 0x8CED #define GL_COLOR_ATTACHMENT14_EXT 0x8CEE #define GL_COLOR_ATTACHMENT15_EXT 0x8CEF #define GL_DEPTH_ATTACHMENT_EXT 0x8D00 #define GL_STENCIL_ATTACHMENT_EXT 0x8D20 #define GL_FRAMEBUFFER_EXT 0x8D40 #define GL_RENDERBUFFER_EXT 0x8D41 #define GL_RENDERBUFFER_WIDTH_EXT 0x8D42 #define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43 #define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44 #define GL_STENCIL_INDEX1_EXT 0x8D46 #define GL_STENCIL_INDEX4_EXT 0x8D47 #define GL_STENCIL_INDEX8_EXT 0x8D48 #define GL_STENCIL_INDEX16_EXT 0x8D49 #define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50 #define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51 #define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52 #define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53 #define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54 #define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55 typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer); typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer); typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers); typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers); typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer); typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer); typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers); typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers); typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target); #ifdef GL_GLEXT_PROTOTYPES GLAPI GLboolean APIENTRY glIsRenderbufferEXT (GLuint renderbuffer); GLAPI void APIENTRY glBindRenderbufferEXT (GLenum target, GLuint renderbuffer); GLAPI void APIENTRY glDeleteRenderbuffersEXT (GLsizei n, const GLuint *renderbuffers); GLAPI void APIENTRY glGenRenderbuffersEXT (GLsizei n, GLuint *renderbuffers); GLAPI void APIENTRY glRenderbufferStorageEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); GLAPI void APIENTRY glGetRenderbufferParameterivEXT (GLenum target, GLenum pname, GLint *params); GLAPI GLboolean APIENTRY glIsFramebufferEXT (GLuint framebuffer); GLAPI void APIENTRY glBindFramebufferEXT (GLenum target, GLuint framebuffer); GLAPI void APIENTRY glDeleteFramebuffersEXT (GLsizei n, const GLuint *framebuffers); GLAPI void APIENTRY glGenFramebuffersEXT (GLsizei n, GLuint *framebuffers); GLAPI GLenum APIENTRY glCheckFramebufferStatusEXT (GLenum target); GLAPI void APIENTRY glFramebufferTexture1DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); GLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); GLAPI void APIENTRY glFramebufferTexture3DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); GLAPI void APIENTRY glFramebufferRenderbufferEXT (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); GLAPI void APIENTRY glGetFramebufferAttachmentParameterivEXT (GLenum target, GLenum attachment, GLenum pname, GLint *params); GLAPI void APIENTRY glGenerateMipmapEXT (GLenum target); #endif #endif /* GL_EXT_framebuffer_object */ #ifndef GL_EXT_framebuffer_sRGB #define GL_EXT_framebuffer_sRGB 1 #define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 #define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA #endif /* GL_EXT_framebuffer_sRGB */ #ifndef GL_EXT_geometry_shader4 #define GL_EXT_geometry_shader4 1 #define GL_GEOMETRY_SHADER_EXT 0x8DD9 #define GL_GEOMETRY_VERTICES_OUT_EXT 0x8DDA #define GL_GEOMETRY_INPUT_TYPE_EXT 0x8DDB #define GL_GEOMETRY_OUTPUT_TYPE_EXT 0x8DDC #define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29 #define GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT 0x8DDD #define GL_MAX_VERTEX_VARYING_COMPONENTS_EXT 0x8DDE #define GL_MAX_VARYING_COMPONENTS_EXT 0x8B4B #define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8DDF #define GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0 #define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT 0x8DE1 #define GL_LINES_ADJACENCY_EXT 0x000A #define GL_LINE_STRIP_ADJACENCY_EXT 0x000B #define GL_TRIANGLES_ADJACENCY_EXT 0x000C #define GL_TRIANGLE_STRIP_ADJACENCY_EXT 0x000D #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT 0x8DA9 #define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT 0x8CD4 #define GL_PROGRAM_POINT_SIZE_EXT 0x8642 typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramParameteriEXT (GLuint program, GLenum pname, GLint value); #endif #endif /* GL_EXT_geometry_shader4 */ #ifndef GL_EXT_gpu_program_parameters #define GL_EXT_gpu_program_parameters 1 typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramEnvParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params); GLAPI void APIENTRY glProgramLocalParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params); #endif #endif /* GL_EXT_gpu_program_parameters */ #ifndef GL_EXT_gpu_shader4 #define GL_EXT_gpu_shader4 1 #define GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT 0x88FD #define GL_SAMPLER_1D_ARRAY_EXT 0x8DC0 #define GL_SAMPLER_2D_ARRAY_EXT 0x8DC1 #define GL_SAMPLER_BUFFER_EXT 0x8DC2 #define GL_SAMPLER_1D_ARRAY_SHADOW_EXT 0x8DC3 #define GL_SAMPLER_2D_ARRAY_SHADOW_EXT 0x8DC4 #define GL_SAMPLER_CUBE_SHADOW_EXT 0x8DC5 #define GL_UNSIGNED_INT_VEC2_EXT 0x8DC6 #define GL_UNSIGNED_INT_VEC3_EXT 0x8DC7 #define GL_UNSIGNED_INT_VEC4_EXT 0x8DC8 #define GL_INT_SAMPLER_1D_EXT 0x8DC9 #define GL_INT_SAMPLER_2D_EXT 0x8DCA #define GL_INT_SAMPLER_3D_EXT 0x8DCB #define GL_INT_SAMPLER_CUBE_EXT 0x8DCC #define GL_INT_SAMPLER_2D_RECT_EXT 0x8DCD #define GL_INT_SAMPLER_1D_ARRAY_EXT 0x8DCE #define GL_INT_SAMPLER_2D_ARRAY_EXT 0x8DCF #define GL_INT_SAMPLER_BUFFER_EXT 0x8DD0 #define GL_UNSIGNED_INT_SAMPLER_1D_EXT 0x8DD1 #define GL_UNSIGNED_INT_SAMPLER_2D_EXT 0x8DD2 #define GL_UNSIGNED_INT_SAMPLER_3D_EXT 0x8DD3 #define GL_UNSIGNED_INT_SAMPLER_CUBE_EXT 0x8DD4 #define GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT 0x8DD5 #define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT 0x8DD6 #define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT 0x8DD7 #define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8 #define GL_MIN_PROGRAM_TEXEL_OFFSET_EXT 0x8904 #define GL_MAX_PROGRAM_TEXEL_OFFSET_EXT 0x8905 typedef void (APIENTRYP PFNGLGETUNIFORMUIVEXTPROC) (GLuint program, GLint location, GLuint *params); typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name); typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONEXTPROC) (GLuint program, const GLchar *name); typedef void (APIENTRYP PFNGLUNIFORM1UIEXTPROC) (GLint location, GLuint v0); typedef void (APIENTRYP PFNGLUNIFORM2UIEXTPROC) (GLint location, GLuint v0, GLuint v1); typedef void (APIENTRYP PFNGLUNIFORM3UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); typedef void (APIENTRYP PFNGLUNIFORM4UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); typedef void (APIENTRYP PFNGLUNIFORM1UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLUNIFORM2UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLUNIFORM3UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLUNIFORM4UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetUniformuivEXT (GLuint program, GLint location, GLuint *params); GLAPI void APIENTRY glBindFragDataLocationEXT (GLuint program, GLuint color, const GLchar *name); GLAPI GLint APIENTRY glGetFragDataLocationEXT (GLuint program, const GLchar *name); GLAPI void APIENTRY glUniform1uiEXT (GLint location, GLuint v0); GLAPI void APIENTRY glUniform2uiEXT (GLint location, GLuint v0, GLuint v1); GLAPI void APIENTRY glUniform3uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2); GLAPI void APIENTRY glUniform4uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); GLAPI void APIENTRY glUniform1uivEXT (GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glUniform2uivEXT (GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glUniform3uivEXT (GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glUniform4uivEXT (GLint location, GLsizei count, const GLuint *value); #endif #endif /* GL_EXT_gpu_shader4 */ #ifndef GL_EXT_histogram #define GL_EXT_histogram 1 #define GL_HISTOGRAM_EXT 0x8024 #define GL_PROXY_HISTOGRAM_EXT 0x8025 #define GL_HISTOGRAM_WIDTH_EXT 0x8026 #define GL_HISTOGRAM_FORMAT_EXT 0x8027 #define GL_HISTOGRAM_RED_SIZE_EXT 0x8028 #define GL_HISTOGRAM_GREEN_SIZE_EXT 0x8029 #define GL_HISTOGRAM_BLUE_SIZE_EXT 0x802A #define GL_HISTOGRAM_ALPHA_SIZE_EXT 0x802B #define GL_HISTOGRAM_LUMINANCE_SIZE_EXT 0x802C #define GL_HISTOGRAM_SINK_EXT 0x802D #define GL_MINMAX_EXT 0x802E #define GL_MINMAX_FORMAT_EXT 0x802F #define GL_MINMAX_SINK_EXT 0x8030 #define GL_TABLE_TOO_LARGE_EXT 0x8031 typedef void (APIENTRYP PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); typedef void (APIENTRYP PFNGLMINMAXEXTPROC) (GLenum target, GLenum internalformat, GLboolean sink); typedef void (APIENTRYP PFNGLRESETHISTOGRAMEXTPROC) (GLenum target); typedef void (APIENTRYP PFNGLRESETMINMAXEXTPROC) (GLenum target); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetHistogramEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); GLAPI void APIENTRY glGetHistogramParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetHistogramParameterivEXT (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetMinmaxEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); GLAPI void APIENTRY glGetMinmaxParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetMinmaxParameterivEXT (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glHistogramEXT (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); GLAPI void APIENTRY glMinmaxEXT (GLenum target, GLenum internalformat, GLboolean sink); GLAPI void APIENTRY glResetHistogramEXT (GLenum target); GLAPI void APIENTRY glResetMinmaxEXT (GLenum target); #endif #endif /* GL_EXT_histogram */ #ifndef GL_EXT_index_array_formats #define GL_EXT_index_array_formats 1 #define GL_IUI_V2F_EXT 0x81AD #define GL_IUI_V3F_EXT 0x81AE #define GL_IUI_N3F_V2F_EXT 0x81AF #define GL_IUI_N3F_V3F_EXT 0x81B0 #define GL_T2F_IUI_V2F_EXT 0x81B1 #define GL_T2F_IUI_V3F_EXT 0x81B2 #define GL_T2F_IUI_N3F_V2F_EXT 0x81B3 #define GL_T2F_IUI_N3F_V3F_EXT 0x81B4 #endif /* GL_EXT_index_array_formats */ #ifndef GL_EXT_index_func #define GL_EXT_index_func 1 #define GL_INDEX_TEST_EXT 0x81B5 #define GL_INDEX_TEST_FUNC_EXT 0x81B6 #define GL_INDEX_TEST_REF_EXT 0x81B7 typedef void (APIENTRYP PFNGLINDEXFUNCEXTPROC) (GLenum func, GLclampf ref); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glIndexFuncEXT (GLenum func, GLclampf ref); #endif #endif /* GL_EXT_index_func */ #ifndef GL_EXT_index_material #define GL_EXT_index_material 1 #define GL_INDEX_MATERIAL_EXT 0x81B8 #define GL_INDEX_MATERIAL_PARAMETER_EXT 0x81B9 #define GL_INDEX_MATERIAL_FACE_EXT 0x81BA typedef void (APIENTRYP PFNGLINDEXMATERIALEXTPROC) (GLenum face, GLenum mode); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glIndexMaterialEXT (GLenum face, GLenum mode); #endif #endif /* GL_EXT_index_material */ #ifndef GL_EXT_index_texture #define GL_EXT_index_texture 1 #endif /* GL_EXT_index_texture */ #ifndef GL_EXT_light_texture #define GL_EXT_light_texture 1 #define GL_FRAGMENT_MATERIAL_EXT 0x8349 #define GL_FRAGMENT_NORMAL_EXT 0x834A #define GL_FRAGMENT_COLOR_EXT 0x834C #define GL_ATTENUATION_EXT 0x834D #define GL_SHADOW_ATTENUATION_EXT 0x834E #define GL_TEXTURE_APPLICATION_MODE_EXT 0x834F #define GL_TEXTURE_LIGHT_EXT 0x8350 #define GL_TEXTURE_MATERIAL_FACE_EXT 0x8351 #define GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352 typedef void (APIENTRYP PFNGLAPPLYTEXTUREEXTPROC) (GLenum mode); typedef void (APIENTRYP PFNGLTEXTURELIGHTEXTPROC) (GLenum pname); typedef void (APIENTRYP PFNGLTEXTUREMATERIALEXTPROC) (GLenum face, GLenum mode); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glApplyTextureEXT (GLenum mode); GLAPI void APIENTRY glTextureLightEXT (GLenum pname); GLAPI void APIENTRY glTextureMaterialEXT (GLenum face, GLenum mode); #endif #endif /* GL_EXT_light_texture */ #ifndef GL_EXT_memory_object #define GL_EXT_memory_object 1 #define GL_TEXTURE_TILING_EXT 0x9580 #define GL_DEDICATED_MEMORY_OBJECT_EXT 0x9581 #define GL_PROTECTED_MEMORY_OBJECT_EXT 0x959B #define GL_NUM_TILING_TYPES_EXT 0x9582 #define GL_TILING_TYPES_EXT 0x9583 #define GL_OPTIMAL_TILING_EXT 0x9584 #define GL_LINEAR_TILING_EXT 0x9585 #define GL_NUM_DEVICE_UUIDS_EXT 0x9596 #define GL_DEVICE_UUID_EXT 0x9597 #define GL_DRIVER_UUID_EXT 0x9598 #define GL_UUID_SIZE_EXT 16 typedef void (APIENTRYP PFNGLGETUNSIGNEDBYTEVEXTPROC) (GLenum pname, GLubyte *data); typedef void (APIENTRYP PFNGLGETUNSIGNEDBYTEI_VEXTPROC) (GLenum target, GLuint index, GLubyte *data); typedef void (APIENTRYP PFNGLDELETEMEMORYOBJECTSEXTPROC) (GLsizei n, const GLuint *memoryObjects); typedef GLboolean (APIENTRYP PFNGLISMEMORYOBJECTEXTPROC) (GLuint memoryObject); typedef void (APIENTRYP PFNGLCREATEMEMORYOBJECTSEXTPROC) (GLsizei n, GLuint *memoryObjects); typedef void (APIENTRYP PFNGLMEMORYOBJECTPARAMETERIVEXTPROC) (GLuint memoryObject, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC) (GLuint memoryObject, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLTEXSTORAGEMEM2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset); typedef void (APIENTRYP PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); typedef void (APIENTRYP PFNGLTEXSTORAGEMEM3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset); typedef void (APIENTRYP PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); typedef void (APIENTRYP PFNGLBUFFERSTORAGEMEMEXTPROC) (GLenum target, GLsizeiptr size, GLuint memory, GLuint64 offset); typedef void (APIENTRYP PFNGLTEXTURESTORAGEMEM2DEXTPROC) (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset); typedef void (APIENTRYP PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC) (GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); typedef void (APIENTRYP PFNGLTEXTURESTORAGEMEM3DEXTPROC) (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset); typedef void (APIENTRYP PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC) (GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); typedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC) (GLuint buffer, GLsizeiptr size, GLuint memory, GLuint64 offset); typedef void (APIENTRYP PFNGLTEXSTORAGEMEM1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLuint memory, GLuint64 offset); typedef void (APIENTRYP PFNGLTEXTURESTORAGEMEM1DEXTPROC) (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLuint memory, GLuint64 offset); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetUnsignedBytevEXT (GLenum pname, GLubyte *data); GLAPI void APIENTRY glGetUnsignedBytei_vEXT (GLenum target, GLuint index, GLubyte *data); GLAPI void APIENTRY glDeleteMemoryObjectsEXT (GLsizei n, const GLuint *memoryObjects); GLAPI GLboolean APIENTRY glIsMemoryObjectEXT (GLuint memoryObject); GLAPI void APIENTRY glCreateMemoryObjectsEXT (GLsizei n, GLuint *memoryObjects); GLAPI void APIENTRY glMemoryObjectParameterivEXT (GLuint memoryObject, GLenum pname, const GLint *params); GLAPI void APIENTRY glGetMemoryObjectParameterivEXT (GLuint memoryObject, GLenum pname, GLint *params); GLAPI void APIENTRY glTexStorageMem2DEXT (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset); GLAPI void APIENTRY glTexStorageMem2DMultisampleEXT (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); GLAPI void APIENTRY glTexStorageMem3DEXT (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset); GLAPI void APIENTRY glTexStorageMem3DMultisampleEXT (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); GLAPI void APIENTRY glBufferStorageMemEXT (GLenum target, GLsizeiptr size, GLuint memory, GLuint64 offset); GLAPI void APIENTRY glTextureStorageMem2DEXT (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset); GLAPI void APIENTRY glTextureStorageMem2DMultisampleEXT (GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); GLAPI void APIENTRY glTextureStorageMem3DEXT (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset); GLAPI void APIENTRY glTextureStorageMem3DMultisampleEXT (GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset); GLAPI void APIENTRY glNamedBufferStorageMemEXT (GLuint buffer, GLsizeiptr size, GLuint memory, GLuint64 offset); GLAPI void APIENTRY glTexStorageMem1DEXT (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLuint memory, GLuint64 offset); GLAPI void APIENTRY glTextureStorageMem1DEXT (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLuint memory, GLuint64 offset); #endif #endif /* GL_EXT_memory_object */ #ifndef GL_EXT_memory_object_fd #define GL_EXT_memory_object_fd 1 #define GL_HANDLE_TYPE_OPAQUE_FD_EXT 0x9586 typedef void (APIENTRYP PFNGLIMPORTMEMORYFDEXTPROC) (GLuint memory, GLuint64 size, GLenum handleType, GLint fd); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glImportMemoryFdEXT (GLuint memory, GLuint64 size, GLenum handleType, GLint fd); #endif #endif /* GL_EXT_memory_object_fd */ #ifndef GL_EXT_memory_object_win32 #define GL_EXT_memory_object_win32 1 #define GL_HANDLE_TYPE_OPAQUE_WIN32_EXT 0x9587 #define GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT 0x9588 #define GL_DEVICE_LUID_EXT 0x9599 #define GL_DEVICE_NODE_MASK_EXT 0x959A #define GL_LUID_SIZE_EXT 8 #define GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT 0x9589 #define GL_HANDLE_TYPE_D3D12_RESOURCE_EXT 0x958A #define GL_HANDLE_TYPE_D3D11_IMAGE_EXT 0x958B #define GL_HANDLE_TYPE_D3D11_IMAGE_KMT_EXT 0x958C typedef void (APIENTRYP PFNGLIMPORTMEMORYWIN32HANDLEEXTPROC) (GLuint memory, GLuint64 size, GLenum handleType, void *handle); typedef void (APIENTRYP PFNGLIMPORTMEMORYWIN32NAMEEXTPROC) (GLuint memory, GLuint64 size, GLenum handleType, const void *name); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glImportMemoryWin32HandleEXT (GLuint memory, GLuint64 size, GLenum handleType, void *handle); GLAPI void APIENTRY glImportMemoryWin32NameEXT (GLuint memory, GLuint64 size, GLenum handleType, const void *name); #endif #endif /* GL_EXT_memory_object_win32 */ #ifndef GL_EXT_misc_attribute #define GL_EXT_misc_attribute 1 #endif /* GL_EXT_misc_attribute */ #ifndef GL_EXT_multi_draw_arrays #define GL_EXT_multi_draw_arrays 1 typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMultiDrawArraysEXT (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); GLAPI void APIENTRY glMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount); #endif #endif /* GL_EXT_multi_draw_arrays */ #ifndef GL_EXT_multisample #define GL_EXT_multisample 1 #define GL_MULTISAMPLE_EXT 0x809D #define GL_SAMPLE_ALPHA_TO_MASK_EXT 0x809E #define GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F #define GL_SAMPLE_MASK_EXT 0x80A0 #define GL_1PASS_EXT 0x80A1 #define GL_2PASS_0_EXT 0x80A2 #define GL_2PASS_1_EXT 0x80A3 #define GL_4PASS_0_EXT 0x80A4 #define GL_4PASS_1_EXT 0x80A5 #define GL_4PASS_2_EXT 0x80A6 #define GL_4PASS_3_EXT 0x80A7 #define GL_SAMPLE_BUFFERS_EXT 0x80A8 #define GL_SAMPLES_EXT 0x80A9 #define GL_SAMPLE_MASK_VALUE_EXT 0x80AA #define GL_SAMPLE_MASK_INVERT_EXT 0x80AB #define GL_SAMPLE_PATTERN_EXT 0x80AC #define GL_MULTISAMPLE_BIT_EXT 0x20000000 typedef void (APIENTRYP PFNGLSAMPLEMASKEXTPROC) (GLclampf value, GLboolean invert); typedef void (APIENTRYP PFNGLSAMPLEPATTERNEXTPROC) (GLenum pattern); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSampleMaskEXT (GLclampf value, GLboolean invert); GLAPI void APIENTRY glSamplePatternEXT (GLenum pattern); #endif #endif /* GL_EXT_multisample */ #ifndef GL_EXT_multiview_tessellation_geometry_shader #define GL_EXT_multiview_tessellation_geometry_shader 1 #endif /* GL_EXT_multiview_tessellation_geometry_shader */ #ifndef GL_EXT_multiview_texture_multisample #define GL_EXT_multiview_texture_multisample 1 #endif /* GL_EXT_multiview_texture_multisample */ #ifndef GL_EXT_multiview_timer_query #define GL_EXT_multiview_timer_query 1 #endif /* GL_EXT_multiview_timer_query */ #ifndef GL_EXT_packed_depth_stencil #define GL_EXT_packed_depth_stencil 1 #define GL_DEPTH_STENCIL_EXT 0x84F9 #define GL_UNSIGNED_INT_24_8_EXT 0x84FA #define GL_DEPTH24_STENCIL8_EXT 0x88F0 #define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 #endif /* GL_EXT_packed_depth_stencil */ #ifndef GL_EXT_packed_float #define GL_EXT_packed_float 1 #define GL_R11F_G11F_B10F_EXT 0x8C3A #define GL_UNSIGNED_INT_10F_11F_11F_REV_EXT 0x8C3B #define GL_RGBA_SIGNED_COMPONENTS_EXT 0x8C3C #endif /* GL_EXT_packed_float */ #ifndef GL_EXT_packed_pixels #define GL_EXT_packed_pixels 1 #define GL_UNSIGNED_BYTE_3_3_2_EXT 0x8032 #define GL_UNSIGNED_SHORT_4_4_4_4_EXT 0x8033 #define GL_UNSIGNED_SHORT_5_5_5_1_EXT 0x8034 #define GL_UNSIGNED_INT_8_8_8_8_EXT 0x8035 #define GL_UNSIGNED_INT_10_10_10_2_EXT 0x8036 #endif /* GL_EXT_packed_pixels */ #ifndef GL_EXT_paletted_texture #define GL_EXT_paletted_texture 1 #define GL_COLOR_INDEX1_EXT 0x80E2 #define GL_COLOR_INDEX2_EXT 0x80E3 #define GL_COLOR_INDEX4_EXT 0x80E4 #define GL_COLOR_INDEX8_EXT 0x80E5 #define GL_COLOR_INDEX12_EXT 0x80E6 #define GL_COLOR_INDEX16_EXT 0x80E7 #define GL_TEXTURE_INDEX_SIZE_EXT 0x80ED typedef void (APIENTRYP PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const void *table); typedef void (APIENTRYP PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, void *data); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorTableEXT (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const void *table); GLAPI void APIENTRY glGetColorTableEXT (GLenum target, GLenum format, GLenum type, void *data); GLAPI void APIENTRY glGetColorTableParameterivEXT (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetColorTableParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); #endif #endif /* GL_EXT_paletted_texture */ #ifndef GL_EXT_pixel_buffer_object #define GL_EXT_pixel_buffer_object 1 #define GL_PIXEL_PACK_BUFFER_EXT 0x88EB #define GL_PIXEL_UNPACK_BUFFER_EXT 0x88EC #define GL_PIXEL_PACK_BUFFER_BINDING_EXT 0x88ED #define GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF #endif /* GL_EXT_pixel_buffer_object */ #ifndef GL_EXT_pixel_transform #define GL_EXT_pixel_transform 1 #define GL_PIXEL_TRANSFORM_2D_EXT 0x8330 #define GL_PIXEL_MAG_FILTER_EXT 0x8331 #define GL_PIXEL_MIN_FILTER_EXT 0x8332 #define GL_PIXEL_CUBIC_WEIGHT_EXT 0x8333 #define GL_CUBIC_EXT 0x8334 #define GL_AVERAGE_EXT 0x8335 #define GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336 #define GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337 #define GL_PIXEL_TRANSFORM_2D_MATRIX_EXT 0x8338 typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLGETPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPixelTransformParameteriEXT (GLenum target, GLenum pname, GLint param); GLAPI void APIENTRY glPixelTransformParameterfEXT (GLenum target, GLenum pname, GLfloat param); GLAPI void APIENTRY glPixelTransformParameterivEXT (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glPixelTransformParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glGetPixelTransformParameterivEXT (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetPixelTransformParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); #endif #endif /* GL_EXT_pixel_transform */ #ifndef GL_EXT_pixel_transform_color_table #define GL_EXT_pixel_transform_color_table 1 #endif /* GL_EXT_pixel_transform_color_table */ #ifndef GL_EXT_point_parameters #define GL_EXT_point_parameters 1 #define GL_POINT_SIZE_MIN_EXT 0x8126 #define GL_POINT_SIZE_MAX_EXT 0x8127 #define GL_POINT_FADE_THRESHOLD_SIZE_EXT 0x8128 #define GL_DISTANCE_ATTENUATION_EXT 0x8129 typedef void (APIENTRYP PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPointParameterfEXT (GLenum pname, GLfloat param); GLAPI void APIENTRY glPointParameterfvEXT (GLenum pname, const GLfloat *params); #endif #endif /* GL_EXT_point_parameters */ #ifndef GL_EXT_polygon_offset #define GL_EXT_polygon_offset 1 #define GL_POLYGON_OFFSET_EXT 0x8037 #define GL_POLYGON_OFFSET_FACTOR_EXT 0x8038 #define GL_POLYGON_OFFSET_BIAS_EXT 0x8039 typedef void (APIENTRYP PFNGLPOLYGONOFFSETEXTPROC) (GLfloat factor, GLfloat bias); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPolygonOffsetEXT (GLfloat factor, GLfloat bias); #endif #endif /* GL_EXT_polygon_offset */ #ifndef GL_EXT_polygon_offset_clamp #define GL_EXT_polygon_offset_clamp 1 #define GL_POLYGON_OFFSET_CLAMP_EXT 0x8E1B typedef void (APIENTRYP PFNGLPOLYGONOFFSETCLAMPEXTPROC) (GLfloat factor, GLfloat units, GLfloat clamp); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPolygonOffsetClampEXT (GLfloat factor, GLfloat units, GLfloat clamp); #endif #endif /* GL_EXT_polygon_offset_clamp */ #ifndef GL_EXT_post_depth_coverage #define GL_EXT_post_depth_coverage 1 #endif /* GL_EXT_post_depth_coverage */ #ifndef GL_EXT_provoking_vertex #define GL_EXT_provoking_vertex 1 #define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT 0x8E4C #define GL_FIRST_VERTEX_CONVENTION_EXT 0x8E4D #define GL_LAST_VERTEX_CONVENTION_EXT 0x8E4E #define GL_PROVOKING_VERTEX_EXT 0x8E4F typedef void (APIENTRYP PFNGLPROVOKINGVERTEXEXTPROC) (GLenum mode); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProvokingVertexEXT (GLenum mode); #endif #endif /* GL_EXT_provoking_vertex */ #ifndef GL_EXT_raster_multisample #define GL_EXT_raster_multisample 1 #define GL_RASTER_MULTISAMPLE_EXT 0x9327 #define GL_RASTER_SAMPLES_EXT 0x9328 #define GL_MAX_RASTER_SAMPLES_EXT 0x9329 #define GL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT 0x932A #define GL_MULTISAMPLE_RASTERIZATION_ALLOWED_EXT 0x932B #define GL_EFFECTIVE_RASTER_SAMPLES_EXT 0x932C typedef void (APIENTRYP PFNGLRASTERSAMPLESEXTPROC) (GLuint samples, GLboolean fixedsamplelocations); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glRasterSamplesEXT (GLuint samples, GLboolean fixedsamplelocations); #endif #endif /* GL_EXT_raster_multisample */ #ifndef GL_EXT_rescale_normal #define GL_EXT_rescale_normal 1 #define GL_RESCALE_NORMAL_EXT 0x803A #endif /* GL_EXT_rescale_normal */ #ifndef GL_EXT_secondary_color #define GL_EXT_secondary_color 1 #define GL_COLOR_SUM_EXT 0x8458 #define GL_CURRENT_SECONDARY_COLOR_EXT 0x8459 #define GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A #define GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B #define GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C #define GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D #define GL_SECONDARY_COLOR_ARRAY_EXT 0x845E typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BEXTPROC) (GLbyte red, GLbyte green, GLbyte blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVEXTPROC) (const GLbyte *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DEXTPROC) (GLdouble red, GLdouble green, GLdouble blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVEXTPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FEXTPROC) (GLfloat red, GLfloat green, GLfloat blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVEXTPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IEXTPROC) (GLint red, GLint green, GLint blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVEXTPROC) (const GLint *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SEXTPROC) (GLshort red, GLshort green, GLshort blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVEXTPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBEXTPROC) (GLubyte red, GLubyte green, GLubyte blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVEXTPROC) (const GLubyte *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIEXTPROC) (GLuint red, GLuint green, GLuint blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVEXTPROC) (const GLuint *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USEXTPROC) (GLushort red, GLushort green, GLushort blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVEXTPROC) (const GLushort *v); typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSecondaryColor3bEXT (GLbyte red, GLbyte green, GLbyte blue); GLAPI void APIENTRY glSecondaryColor3bvEXT (const GLbyte *v); GLAPI void APIENTRY glSecondaryColor3dEXT (GLdouble red, GLdouble green, GLdouble blue); GLAPI void APIENTRY glSecondaryColor3dvEXT (const GLdouble *v); GLAPI void APIENTRY glSecondaryColor3fEXT (GLfloat red, GLfloat green, GLfloat blue); GLAPI void APIENTRY glSecondaryColor3fvEXT (const GLfloat *v); GLAPI void APIENTRY glSecondaryColor3iEXT (GLint red, GLint green, GLint blue); GLAPI void APIENTRY glSecondaryColor3ivEXT (const GLint *v); GLAPI void APIENTRY glSecondaryColor3sEXT (GLshort red, GLshort green, GLshort blue); GLAPI void APIENTRY glSecondaryColor3svEXT (const GLshort *v); GLAPI void APIENTRY glSecondaryColor3ubEXT (GLubyte red, GLubyte green, GLubyte blue); GLAPI void APIENTRY glSecondaryColor3ubvEXT (const GLubyte *v); GLAPI void APIENTRY glSecondaryColor3uiEXT (GLuint red, GLuint green, GLuint blue); GLAPI void APIENTRY glSecondaryColor3uivEXT (const GLuint *v); GLAPI void APIENTRY glSecondaryColor3usEXT (GLushort red, GLushort green, GLushort blue); GLAPI void APIENTRY glSecondaryColor3usvEXT (const GLushort *v); GLAPI void APIENTRY glSecondaryColorPointerEXT (GLint size, GLenum type, GLsizei stride, const void *pointer); #endif #endif /* GL_EXT_secondary_color */ #ifndef GL_EXT_semaphore #define GL_EXT_semaphore 1 #define GL_LAYOUT_GENERAL_EXT 0x958D #define GL_LAYOUT_COLOR_ATTACHMENT_EXT 0x958E #define GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT 0x958F #define GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT 0x9590 #define GL_LAYOUT_SHADER_READ_ONLY_EXT 0x9591 #define GL_LAYOUT_TRANSFER_SRC_EXT 0x9592 #define GL_LAYOUT_TRANSFER_DST_EXT 0x9593 #define GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT 0x9530 #define GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT 0x9531 typedef void (APIENTRYP PFNGLGENSEMAPHORESEXTPROC) (GLsizei n, GLuint *semaphores); typedef void (APIENTRYP PFNGLDELETESEMAPHORESEXTPROC) (GLsizei n, const GLuint *semaphores); typedef GLboolean (APIENTRYP PFNGLISSEMAPHOREEXTPROC) (GLuint semaphore); typedef void (APIENTRYP PFNGLSEMAPHOREPARAMETERUI64VEXTPROC) (GLuint semaphore, GLenum pname, const GLuint64 *params); typedef void (APIENTRYP PFNGLGETSEMAPHOREPARAMETERUI64VEXTPROC) (GLuint semaphore, GLenum pname, GLuint64 *params); typedef void (APIENTRYP PFNGLWAITSEMAPHOREEXTPROC) (GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *srcLayouts); typedef void (APIENTRYP PFNGLSIGNALSEMAPHOREEXTPROC) (GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *dstLayouts); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenSemaphoresEXT (GLsizei n, GLuint *semaphores); GLAPI void APIENTRY glDeleteSemaphoresEXT (GLsizei n, const GLuint *semaphores); GLAPI GLboolean APIENTRY glIsSemaphoreEXT (GLuint semaphore); GLAPI void APIENTRY glSemaphoreParameterui64vEXT (GLuint semaphore, GLenum pname, const GLuint64 *params); GLAPI void APIENTRY glGetSemaphoreParameterui64vEXT (GLuint semaphore, GLenum pname, GLuint64 *params); GLAPI void APIENTRY glWaitSemaphoreEXT (GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *srcLayouts); GLAPI void APIENTRY glSignalSemaphoreEXT (GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *dstLayouts); #endif #endif /* GL_EXT_semaphore */ #ifndef GL_EXT_semaphore_fd #define GL_EXT_semaphore_fd 1 typedef void (APIENTRYP PFNGLIMPORTSEMAPHOREFDEXTPROC) (GLuint semaphore, GLenum handleType, GLint fd); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glImportSemaphoreFdEXT (GLuint semaphore, GLenum handleType, GLint fd); #endif #endif /* GL_EXT_semaphore_fd */ #ifndef GL_EXT_semaphore_win32 #define GL_EXT_semaphore_win32 1 #define GL_HANDLE_TYPE_D3D12_FENCE_EXT 0x9594 #define GL_D3D12_FENCE_VALUE_EXT 0x9595 typedef void (APIENTRYP PFNGLIMPORTSEMAPHOREWIN32HANDLEEXTPROC) (GLuint semaphore, GLenum handleType, void *handle); typedef void (APIENTRYP PFNGLIMPORTSEMAPHOREWIN32NAMEEXTPROC) (GLuint semaphore, GLenum handleType, const void *name); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glImportSemaphoreWin32HandleEXT (GLuint semaphore, GLenum handleType, void *handle); GLAPI void APIENTRY glImportSemaphoreWin32NameEXT (GLuint semaphore, GLenum handleType, const void *name); #endif #endif /* GL_EXT_semaphore_win32 */ #ifndef GL_EXT_separate_shader_objects #define GL_EXT_separate_shader_objects 1 #define GL_ACTIVE_PROGRAM_EXT 0x8B8D typedef void (APIENTRYP PFNGLUSESHADERPROGRAMEXTPROC) (GLenum type, GLuint program); typedef void (APIENTRYP PFNGLACTIVEPROGRAMEXTPROC) (GLuint program); typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMEXTPROC) (GLenum type, const GLchar *string); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glUseShaderProgramEXT (GLenum type, GLuint program); GLAPI void APIENTRY glActiveProgramEXT (GLuint program); GLAPI GLuint APIENTRY glCreateShaderProgramEXT (GLenum type, const GLchar *string); #endif #endif /* GL_EXT_separate_shader_objects */ #ifndef GL_EXT_separate_specular_color #define GL_EXT_separate_specular_color 1 #define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 #define GL_SINGLE_COLOR_EXT 0x81F9 #define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA #endif /* GL_EXT_separate_specular_color */ #ifndef GL_EXT_shader_framebuffer_fetch #define GL_EXT_shader_framebuffer_fetch 1 #define GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT 0x8A52 #endif /* GL_EXT_shader_framebuffer_fetch */ #ifndef GL_EXT_shader_framebuffer_fetch_non_coherent #define GL_EXT_shader_framebuffer_fetch_non_coherent 1 typedef void (APIENTRYP PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFramebufferFetchBarrierEXT (void); #endif #endif /* GL_EXT_shader_framebuffer_fetch_non_coherent */ #ifndef GL_EXT_shader_image_load_formatted #define GL_EXT_shader_image_load_formatted 1 #endif /* GL_EXT_shader_image_load_formatted */ #ifndef GL_EXT_shader_image_load_store #define GL_EXT_shader_image_load_store 1 #define GL_MAX_IMAGE_UNITS_EXT 0x8F38 #define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS_EXT 0x8F39 #define GL_IMAGE_BINDING_NAME_EXT 0x8F3A #define GL_IMAGE_BINDING_LEVEL_EXT 0x8F3B #define GL_IMAGE_BINDING_LAYERED_EXT 0x8F3C #define GL_IMAGE_BINDING_LAYER_EXT 0x8F3D #define GL_IMAGE_BINDING_ACCESS_EXT 0x8F3E #define GL_IMAGE_1D_EXT 0x904C #define GL_IMAGE_2D_EXT 0x904D #define GL_IMAGE_3D_EXT 0x904E #define GL_IMAGE_2D_RECT_EXT 0x904F #define GL_IMAGE_CUBE_EXT 0x9050 #define GL_IMAGE_BUFFER_EXT 0x9051 #define GL_IMAGE_1D_ARRAY_EXT 0x9052 #define GL_IMAGE_2D_ARRAY_EXT 0x9053 #define GL_IMAGE_CUBE_MAP_ARRAY_EXT 0x9054 #define GL_IMAGE_2D_MULTISAMPLE_EXT 0x9055 #define GL_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9056 #define GL_INT_IMAGE_1D_EXT 0x9057 #define GL_INT_IMAGE_2D_EXT 0x9058 #define GL_INT_IMAGE_3D_EXT 0x9059 #define GL_INT_IMAGE_2D_RECT_EXT 0x905A #define GL_INT_IMAGE_CUBE_EXT 0x905B #define GL_INT_IMAGE_BUFFER_EXT 0x905C #define GL_INT_IMAGE_1D_ARRAY_EXT 0x905D #define GL_INT_IMAGE_2D_ARRAY_EXT 0x905E #define GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x905F #define GL_INT_IMAGE_2D_MULTISAMPLE_EXT 0x9060 #define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9061 #define GL_UNSIGNED_INT_IMAGE_1D_EXT 0x9062 #define GL_UNSIGNED_INT_IMAGE_2D_EXT 0x9063 #define GL_UNSIGNED_INT_IMAGE_3D_EXT 0x9064 #define GL_UNSIGNED_INT_IMAGE_2D_RECT_EXT 0x9065 #define GL_UNSIGNED_INT_IMAGE_CUBE_EXT 0x9066 #define GL_UNSIGNED_INT_IMAGE_BUFFER_EXT 0x9067 #define GL_UNSIGNED_INT_IMAGE_1D_ARRAY_EXT 0x9068 #define GL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT 0x9069 #define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x906A #define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_EXT 0x906B #define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x906C #define GL_MAX_IMAGE_SAMPLES_EXT 0x906D #define GL_IMAGE_BINDING_FORMAT_EXT 0x906E #define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT_EXT 0x00000001 #define GL_ELEMENT_ARRAY_BARRIER_BIT_EXT 0x00000002 #define GL_UNIFORM_BARRIER_BIT_EXT 0x00000004 #define GL_TEXTURE_FETCH_BARRIER_BIT_EXT 0x00000008 #define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT_EXT 0x00000020 #define GL_COMMAND_BARRIER_BIT_EXT 0x00000040 #define GL_PIXEL_BUFFER_BARRIER_BIT_EXT 0x00000080 #define GL_TEXTURE_UPDATE_BARRIER_BIT_EXT 0x00000100 #define GL_BUFFER_UPDATE_BARRIER_BIT_EXT 0x00000200 #define GL_FRAMEBUFFER_BARRIER_BIT_EXT 0x00000400 #define GL_TRANSFORM_FEEDBACK_BARRIER_BIT_EXT 0x00000800 #define GL_ATOMIC_COUNTER_BARRIER_BIT_EXT 0x00001000 #define GL_ALL_BARRIER_BITS_EXT 0xFFFFFFFF typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREEXTPROC) (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format); typedef void (APIENTRYP PFNGLMEMORYBARRIEREXTPROC) (GLbitfield barriers); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindImageTextureEXT (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format); GLAPI void APIENTRY glMemoryBarrierEXT (GLbitfield barriers); #endif #endif /* GL_EXT_shader_image_load_store */ #ifndef GL_EXT_shader_integer_mix #define GL_EXT_shader_integer_mix 1 #endif /* GL_EXT_shader_integer_mix */ #ifndef GL_EXT_shadow_funcs #define GL_EXT_shadow_funcs 1 #endif /* GL_EXT_shadow_funcs */ #ifndef GL_EXT_shared_texture_palette #define GL_EXT_shared_texture_palette 1 #define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB #endif /* GL_EXT_shared_texture_palette */ #ifndef GL_EXT_sparse_texture2 #define GL_EXT_sparse_texture2 1 #endif /* GL_EXT_sparse_texture2 */ #ifndef GL_EXT_stencil_clear_tag #define GL_EXT_stencil_clear_tag 1 #define GL_STENCIL_TAG_BITS_EXT 0x88F2 #define GL_STENCIL_CLEAR_TAG_VALUE_EXT 0x88F3 typedef void (APIENTRYP PFNGLSTENCILCLEARTAGEXTPROC) (GLsizei stencilTagBits, GLuint stencilClearTag); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glStencilClearTagEXT (GLsizei stencilTagBits, GLuint stencilClearTag); #endif #endif /* GL_EXT_stencil_clear_tag */ #ifndef GL_EXT_stencil_two_side #define GL_EXT_stencil_two_side 1 #define GL_STENCIL_TEST_TWO_SIDE_EXT 0x8910 #define GL_ACTIVE_STENCIL_FACE_EXT 0x8911 typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glActiveStencilFaceEXT (GLenum face); #endif #endif /* GL_EXT_stencil_two_side */ #ifndef GL_EXT_stencil_wrap #define GL_EXT_stencil_wrap 1 #define GL_INCR_WRAP_EXT 0x8507 #define GL_DECR_WRAP_EXT 0x8508 #endif /* GL_EXT_stencil_wrap */ #ifndef GL_EXT_subtexture #define GL_EXT_subtexture 1 typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); #endif #endif /* GL_EXT_subtexture */ #ifndef GL_EXT_texture #define GL_EXT_texture 1 #define GL_ALPHA4_EXT 0x803B #define GL_ALPHA8_EXT 0x803C #define GL_ALPHA12_EXT 0x803D #define GL_ALPHA16_EXT 0x803E #define GL_LUMINANCE4_EXT 0x803F #define GL_LUMINANCE8_EXT 0x8040 #define GL_LUMINANCE12_EXT 0x8041 #define GL_LUMINANCE16_EXT 0x8042 #define GL_LUMINANCE4_ALPHA4_EXT 0x8043 #define GL_LUMINANCE6_ALPHA2_EXT 0x8044 #define GL_LUMINANCE8_ALPHA8_EXT 0x8045 #define GL_LUMINANCE12_ALPHA4_EXT 0x8046 #define GL_LUMINANCE12_ALPHA12_EXT 0x8047 #define GL_LUMINANCE16_ALPHA16_EXT 0x8048 #define GL_INTENSITY_EXT 0x8049 #define GL_INTENSITY4_EXT 0x804A #define GL_INTENSITY8_EXT 0x804B #define GL_INTENSITY12_EXT 0x804C #define GL_INTENSITY16_EXT 0x804D #define GL_RGB2_EXT 0x804E #define GL_RGB4_EXT 0x804F #define GL_RGB5_EXT 0x8050 #define GL_RGB8_EXT 0x8051 #define GL_RGB10_EXT 0x8052 #define GL_RGB12_EXT 0x8053 #define GL_RGB16_EXT 0x8054 #define GL_RGBA2_EXT 0x8055 #define GL_RGBA4_EXT 0x8056 #define GL_RGB5_A1_EXT 0x8057 #define GL_RGBA8_EXT 0x8058 #define GL_RGB10_A2_EXT 0x8059 #define GL_RGBA12_EXT 0x805A #define GL_RGBA16_EXT 0x805B #define GL_TEXTURE_RED_SIZE_EXT 0x805C #define GL_TEXTURE_GREEN_SIZE_EXT 0x805D #define GL_TEXTURE_BLUE_SIZE_EXT 0x805E #define GL_TEXTURE_ALPHA_SIZE_EXT 0x805F #define GL_TEXTURE_LUMINANCE_SIZE_EXT 0x8060 #define GL_TEXTURE_INTENSITY_SIZE_EXT 0x8061 #define GL_REPLACE_EXT 0x8062 #define GL_PROXY_TEXTURE_1D_EXT 0x8063 #define GL_PROXY_TEXTURE_2D_EXT 0x8064 #define GL_TEXTURE_TOO_LARGE_EXT 0x8065 #endif /* GL_EXT_texture */ #ifndef GL_EXT_texture3D #define GL_EXT_texture3D 1 #define GL_PACK_SKIP_IMAGES_EXT 0x806B #define GL_PACK_IMAGE_HEIGHT_EXT 0x806C #define GL_UNPACK_SKIP_IMAGES_EXT 0x806D #define GL_UNPACK_IMAGE_HEIGHT_EXT 0x806E #define GL_TEXTURE_3D_EXT 0x806F #define GL_PROXY_TEXTURE_3D_EXT 0x8070 #define GL_TEXTURE_DEPTH_EXT 0x8071 #define GL_TEXTURE_WRAP_R_EXT 0x8072 #define GL_MAX_3D_TEXTURE_SIZE_EXT 0x8073 typedef void (APIENTRYP PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexImage3DEXT (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); #endif #endif /* GL_EXT_texture3D */ #ifndef GL_EXT_texture_array #define GL_EXT_texture_array 1 #define GL_TEXTURE_1D_ARRAY_EXT 0x8C18 #define GL_PROXY_TEXTURE_1D_ARRAY_EXT 0x8C19 #define GL_TEXTURE_2D_ARRAY_EXT 0x8C1A #define GL_PROXY_TEXTURE_2D_ARRAY_EXT 0x8C1B #define GL_TEXTURE_BINDING_1D_ARRAY_EXT 0x8C1C #define GL_TEXTURE_BINDING_2D_ARRAY_EXT 0x8C1D #define GL_MAX_ARRAY_TEXTURE_LAYERS_EXT 0x88FF #define GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT 0x884E typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFramebufferTextureLayerEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); #endif #endif /* GL_EXT_texture_array */ #ifndef GL_EXT_texture_buffer_object #define GL_EXT_texture_buffer_object 1 #define GL_TEXTURE_BUFFER_EXT 0x8C2A #define GL_MAX_TEXTURE_BUFFER_SIZE_EXT 0x8C2B #define GL_TEXTURE_BINDING_BUFFER_EXT 0x8C2C #define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT 0x8C2D #define GL_TEXTURE_BUFFER_FORMAT_EXT 0x8C2E typedef void (APIENTRYP PFNGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexBufferEXT (GLenum target, GLenum internalformat, GLuint buffer); #endif #endif /* GL_EXT_texture_buffer_object */ #ifndef GL_EXT_texture_compression_latc #define GL_EXT_texture_compression_latc 1 #define GL_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70 #define GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71 #define GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72 #define GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73 #endif /* GL_EXT_texture_compression_latc */ #ifndef GL_EXT_texture_compression_rgtc #define GL_EXT_texture_compression_rgtc 1 #define GL_COMPRESSED_RED_RGTC1_EXT 0x8DBB #define GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC #define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD #define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE #endif /* GL_EXT_texture_compression_rgtc */ #ifndef GL_EXT_texture_compression_s3tc #define GL_EXT_texture_compression_s3tc 1 #define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 #endif /* GL_EXT_texture_compression_s3tc */ #ifndef GL_EXT_texture_cube_map #define GL_EXT_texture_cube_map 1 #define GL_NORMAL_MAP_EXT 0x8511 #define GL_REFLECTION_MAP_EXT 0x8512 #define GL_TEXTURE_CUBE_MAP_EXT 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP_EXT 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A #define GL_PROXY_TEXTURE_CUBE_MAP_EXT 0x851B #define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT 0x851C #endif /* GL_EXT_texture_cube_map */ #ifndef GL_EXT_texture_env_add #define GL_EXT_texture_env_add 1 #endif /* GL_EXT_texture_env_add */ #ifndef GL_EXT_texture_env_combine #define GL_EXT_texture_env_combine 1 #define GL_COMBINE_EXT 0x8570 #define GL_COMBINE_RGB_EXT 0x8571 #define GL_COMBINE_ALPHA_EXT 0x8572 #define GL_RGB_SCALE_EXT 0x8573 #define GL_ADD_SIGNED_EXT 0x8574 #define GL_INTERPOLATE_EXT 0x8575 #define GL_CONSTANT_EXT 0x8576 #define GL_PRIMARY_COLOR_EXT 0x8577 #define GL_PREVIOUS_EXT 0x8578 #define GL_SOURCE0_RGB_EXT 0x8580 #define GL_SOURCE1_RGB_EXT 0x8581 #define GL_SOURCE2_RGB_EXT 0x8582 #define GL_SOURCE0_ALPHA_EXT 0x8588 #define GL_SOURCE1_ALPHA_EXT 0x8589 #define GL_SOURCE2_ALPHA_EXT 0x858A #define GL_OPERAND0_RGB_EXT 0x8590 #define GL_OPERAND1_RGB_EXT 0x8591 #define GL_OPERAND2_RGB_EXT 0x8592 #define GL_OPERAND0_ALPHA_EXT 0x8598 #define GL_OPERAND1_ALPHA_EXT 0x8599 #define GL_OPERAND2_ALPHA_EXT 0x859A #endif /* GL_EXT_texture_env_combine */ #ifndef GL_EXT_texture_env_dot3 #define GL_EXT_texture_env_dot3 1 #define GL_DOT3_RGB_EXT 0x8740 #define GL_DOT3_RGBA_EXT 0x8741 #endif /* GL_EXT_texture_env_dot3 */ #ifndef GL_EXT_texture_filter_anisotropic #define GL_EXT_texture_filter_anisotropic 1 #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF #endif /* GL_EXT_texture_filter_anisotropic */ #ifndef GL_EXT_texture_filter_minmax #define GL_EXT_texture_filter_minmax 1 #define GL_TEXTURE_REDUCTION_MODE_EXT 0x9366 #define GL_WEIGHTED_AVERAGE_EXT 0x9367 #endif /* GL_EXT_texture_filter_minmax */ #ifndef GL_EXT_texture_integer #define GL_EXT_texture_integer 1 #define GL_RGBA32UI_EXT 0x8D70 #define GL_RGB32UI_EXT 0x8D71 #define GL_ALPHA32UI_EXT 0x8D72 #define GL_INTENSITY32UI_EXT 0x8D73 #define GL_LUMINANCE32UI_EXT 0x8D74 #define GL_LUMINANCE_ALPHA32UI_EXT 0x8D75 #define GL_RGBA16UI_EXT 0x8D76 #define GL_RGB16UI_EXT 0x8D77 #define GL_ALPHA16UI_EXT 0x8D78 #define GL_INTENSITY16UI_EXT 0x8D79 #define GL_LUMINANCE16UI_EXT 0x8D7A #define GL_LUMINANCE_ALPHA16UI_EXT 0x8D7B #define GL_RGBA8UI_EXT 0x8D7C #define GL_RGB8UI_EXT 0x8D7D #define GL_ALPHA8UI_EXT 0x8D7E #define GL_INTENSITY8UI_EXT 0x8D7F #define GL_LUMINANCE8UI_EXT 0x8D80 #define GL_LUMINANCE_ALPHA8UI_EXT 0x8D81 #define GL_RGBA32I_EXT 0x8D82 #define GL_RGB32I_EXT 0x8D83 #define GL_ALPHA32I_EXT 0x8D84 #define GL_INTENSITY32I_EXT 0x8D85 #define GL_LUMINANCE32I_EXT 0x8D86 #define GL_LUMINANCE_ALPHA32I_EXT 0x8D87 #define GL_RGBA16I_EXT 0x8D88 #define GL_RGB16I_EXT 0x8D89 #define GL_ALPHA16I_EXT 0x8D8A #define GL_INTENSITY16I_EXT 0x8D8B #define GL_LUMINANCE16I_EXT 0x8D8C #define GL_LUMINANCE_ALPHA16I_EXT 0x8D8D #define GL_RGBA8I_EXT 0x8D8E #define GL_RGB8I_EXT 0x8D8F #define GL_ALPHA8I_EXT 0x8D90 #define GL_INTENSITY8I_EXT 0x8D91 #define GL_LUMINANCE8I_EXT 0x8D92 #define GL_LUMINANCE_ALPHA8I_EXT 0x8D93 #define GL_RED_INTEGER_EXT 0x8D94 #define GL_GREEN_INTEGER_EXT 0x8D95 #define GL_BLUE_INTEGER_EXT 0x8D96 #define GL_ALPHA_INTEGER_EXT 0x8D97 #define GL_RGB_INTEGER_EXT 0x8D98 #define GL_RGBA_INTEGER_EXT 0x8D99 #define GL_BGR_INTEGER_EXT 0x8D9A #define GL_BGRA_INTEGER_EXT 0x8D9B #define GL_LUMINANCE_INTEGER_EXT 0x8D9C #define GL_LUMINANCE_ALPHA_INTEGER_EXT 0x8D9D #define GL_RGBA_INTEGER_MODE_EXT 0x8D9E typedef void (APIENTRYP PFNGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params); typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLCLEARCOLORIIEXTPROC) (GLint red, GLint green, GLint blue, GLint alpha); typedef void (APIENTRYP PFNGLCLEARCOLORIUIEXTPROC) (GLuint red, GLuint green, GLuint blue, GLuint alpha); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexParameterIivEXT (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glTexParameterIuivEXT (GLenum target, GLenum pname, const GLuint *params); GLAPI void APIENTRY glGetTexParameterIivEXT (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetTexParameterIuivEXT (GLenum target, GLenum pname, GLuint *params); GLAPI void APIENTRY glClearColorIiEXT (GLint red, GLint green, GLint blue, GLint alpha); GLAPI void APIENTRY glClearColorIuiEXT (GLuint red, GLuint green, GLuint blue, GLuint alpha); #endif #endif /* GL_EXT_texture_integer */ #ifndef GL_EXT_texture_lod_bias #define GL_EXT_texture_lod_bias 1 #define GL_MAX_TEXTURE_LOD_BIAS_EXT 0x84FD #define GL_TEXTURE_FILTER_CONTROL_EXT 0x8500 #define GL_TEXTURE_LOD_BIAS_EXT 0x8501 #endif /* GL_EXT_texture_lod_bias */ #ifndef GL_EXT_texture_mirror_clamp #define GL_EXT_texture_mirror_clamp 1 #define GL_MIRROR_CLAMP_EXT 0x8742 #define GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743 #define GL_MIRROR_CLAMP_TO_BORDER_EXT 0x8912 #endif /* GL_EXT_texture_mirror_clamp */ #ifndef GL_EXT_texture_object #define GL_EXT_texture_object 1 #define GL_TEXTURE_PRIORITY_EXT 0x8066 #define GL_TEXTURE_RESIDENT_EXT 0x8067 #define GL_TEXTURE_1D_BINDING_EXT 0x8068 #define GL_TEXTURE_2D_BINDING_EXT 0x8069 #define GL_TEXTURE_3D_BINDING_EXT 0x806A typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTEXTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences); typedef void (APIENTRYP PFNGLBINDTEXTUREEXTPROC) (GLenum target, GLuint texture); typedef void (APIENTRYP PFNGLDELETETEXTURESEXTPROC) (GLsizei n, const GLuint *textures); typedef void (APIENTRYP PFNGLGENTEXTURESEXTPROC) (GLsizei n, GLuint *textures); typedef GLboolean (APIENTRYP PFNGLISTEXTUREEXTPROC) (GLuint texture); typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESEXTPROC) (GLsizei n, const GLuint *textures, const GLclampf *priorities); #ifdef GL_GLEXT_PROTOTYPES GLAPI GLboolean APIENTRY glAreTexturesResidentEXT (GLsizei n, const GLuint *textures, GLboolean *residences); GLAPI void APIENTRY glBindTextureEXT (GLenum target, GLuint texture); GLAPI void APIENTRY glDeleteTexturesEXT (GLsizei n, const GLuint *textures); GLAPI void APIENTRY glGenTexturesEXT (GLsizei n, GLuint *textures); GLAPI GLboolean APIENTRY glIsTextureEXT (GLuint texture); GLAPI void APIENTRY glPrioritizeTexturesEXT (GLsizei n, const GLuint *textures, const GLclampf *priorities); #endif #endif /* GL_EXT_texture_object */ #ifndef GL_EXT_texture_perturb_normal #define GL_EXT_texture_perturb_normal 1 #define GL_PERTURB_EXT 0x85AE #define GL_TEXTURE_NORMAL_EXT 0x85AF typedef void (APIENTRYP PFNGLTEXTURENORMALEXTPROC) (GLenum mode); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTextureNormalEXT (GLenum mode); #endif #endif /* GL_EXT_texture_perturb_normal */ #ifndef GL_EXT_texture_sRGB #define GL_EXT_texture_sRGB 1 #define GL_SRGB_EXT 0x8C40 #define GL_SRGB8_EXT 0x8C41 #define GL_SRGB_ALPHA_EXT 0x8C42 #define GL_SRGB8_ALPHA8_EXT 0x8C43 #define GL_SLUMINANCE_ALPHA_EXT 0x8C44 #define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45 #define GL_SLUMINANCE_EXT 0x8C46 #define GL_SLUMINANCE8_EXT 0x8C47 #define GL_COMPRESSED_SRGB_EXT 0x8C48 #define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49 #define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A #define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B #define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F #endif /* GL_EXT_texture_sRGB */ #ifndef GL_EXT_texture_sRGB_R8 #define GL_EXT_texture_sRGB_R8 1 #define GL_SR8_EXT 0x8FBD #endif /* GL_EXT_texture_sRGB_R8 */ #ifndef GL_EXT_texture_sRGB_RG8 #define GL_EXT_texture_sRGB_RG8 1 #define GL_SRG8_EXT 0x8FBE #endif /* GL_EXT_texture_sRGB_RG8 */ #ifndef GL_EXT_texture_sRGB_decode #define GL_EXT_texture_sRGB_decode 1 #define GL_TEXTURE_SRGB_DECODE_EXT 0x8A48 #define GL_DECODE_EXT 0x8A49 #define GL_SKIP_DECODE_EXT 0x8A4A #endif /* GL_EXT_texture_sRGB_decode */ #ifndef GL_EXT_texture_shadow_lod #define GL_EXT_texture_shadow_lod 1 #endif /* GL_EXT_texture_shadow_lod */ #ifndef GL_EXT_texture_shared_exponent #define GL_EXT_texture_shared_exponent 1 #define GL_RGB9_E5_EXT 0x8C3D #define GL_UNSIGNED_INT_5_9_9_9_REV_EXT 0x8C3E #define GL_TEXTURE_SHARED_SIZE_EXT 0x8C3F #endif /* GL_EXT_texture_shared_exponent */ #ifndef GL_EXT_texture_snorm #define GL_EXT_texture_snorm 1 #define GL_ALPHA_SNORM 0x9010 #define GL_LUMINANCE_SNORM 0x9011 #define GL_LUMINANCE_ALPHA_SNORM 0x9012 #define GL_INTENSITY_SNORM 0x9013 #define GL_ALPHA8_SNORM 0x9014 #define GL_LUMINANCE8_SNORM 0x9015 #define GL_LUMINANCE8_ALPHA8_SNORM 0x9016 #define GL_INTENSITY8_SNORM 0x9017 #define GL_ALPHA16_SNORM 0x9018 #define GL_LUMINANCE16_SNORM 0x9019 #define GL_LUMINANCE16_ALPHA16_SNORM 0x901A #define GL_INTENSITY16_SNORM 0x901B #define GL_RED_SNORM 0x8F90 #define GL_RG_SNORM 0x8F91 #define GL_RGB_SNORM 0x8F92 #define GL_RGBA_SNORM 0x8F93 #endif /* GL_EXT_texture_snorm */ #ifndef GL_EXT_texture_swizzle #define GL_EXT_texture_swizzle 1 #define GL_TEXTURE_SWIZZLE_R_EXT 0x8E42 #define GL_TEXTURE_SWIZZLE_G_EXT 0x8E43 #define GL_TEXTURE_SWIZZLE_B_EXT 0x8E44 #define GL_TEXTURE_SWIZZLE_A_EXT 0x8E45 #define GL_TEXTURE_SWIZZLE_RGBA_EXT 0x8E46 #endif /* GL_EXT_texture_swizzle */ #ifndef GL_EXT_timer_query #define GL_EXT_timer_query 1 #define GL_TIME_ELAPSED_EXT 0x88BF typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VEXTPROC) (GLuint id, GLenum pname, GLint64 *params); typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64 *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetQueryObjecti64vEXT (GLuint id, GLenum pname, GLint64 *params); GLAPI void APIENTRY glGetQueryObjectui64vEXT (GLuint id, GLenum pname, GLuint64 *params); #endif #endif /* GL_EXT_timer_query */ #ifndef GL_EXT_transform_feedback #define GL_EXT_transform_feedback 1 #define GL_TRANSFORM_FEEDBACK_BUFFER_EXT 0x8C8E #define GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT 0x8C84 #define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT 0x8C85 #define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT 0x8C8F #define GL_INTERLEAVED_ATTRIBS_EXT 0x8C8C #define GL_SEPARATE_ATTRIBS_EXT 0x8C8D #define GL_PRIMITIVES_GENERATED_EXT 0x8C87 #define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT 0x8C88 #define GL_RASTERIZER_DISCARD_EXT 0x8C89 #define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT 0x8C8A #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT 0x8C8B #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT 0x8C80 #define GL_TRANSFORM_FEEDBACK_VARYINGS_EXT 0x8C83 #define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT 0x8C7F #define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT 0x8C76 typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKEXTPROC) (GLenum primitiveMode); typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKEXTPROC) (void); typedef void (APIENTRYP PFNGLBINDBUFFERRANGEEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset); typedef void (APIENTRYP PFNGLBINDBUFFERBASEEXTPROC) (GLenum target, GLuint index, GLuint buffer); typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGEXTPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBeginTransformFeedbackEXT (GLenum primitiveMode); GLAPI void APIENTRY glEndTransformFeedbackEXT (void); GLAPI void APIENTRY glBindBufferRangeEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); GLAPI void APIENTRY glBindBufferOffsetEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset); GLAPI void APIENTRY glBindBufferBaseEXT (GLenum target, GLuint index, GLuint buffer); GLAPI void APIENTRY glTransformFeedbackVaryingsEXT (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); GLAPI void APIENTRY glGetTransformFeedbackVaryingEXT (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); #endif #endif /* GL_EXT_transform_feedback */ #ifndef GL_EXT_vertex_array #define GL_EXT_vertex_array 1 #define GL_VERTEX_ARRAY_EXT 0x8074 #define GL_NORMAL_ARRAY_EXT 0x8075 #define GL_COLOR_ARRAY_EXT 0x8076 #define GL_INDEX_ARRAY_EXT 0x8077 #define GL_TEXTURE_COORD_ARRAY_EXT 0x8078 #define GL_EDGE_FLAG_ARRAY_EXT 0x8079 #define GL_VERTEX_ARRAY_SIZE_EXT 0x807A #define GL_VERTEX_ARRAY_TYPE_EXT 0x807B #define GL_VERTEX_ARRAY_STRIDE_EXT 0x807C #define GL_VERTEX_ARRAY_COUNT_EXT 0x807D #define GL_NORMAL_ARRAY_TYPE_EXT 0x807E #define GL_NORMAL_ARRAY_STRIDE_EXT 0x807F #define GL_NORMAL_ARRAY_COUNT_EXT 0x8080 #define GL_COLOR_ARRAY_SIZE_EXT 0x8081 #define GL_COLOR_ARRAY_TYPE_EXT 0x8082 #define GL_COLOR_ARRAY_STRIDE_EXT 0x8083 #define GL_COLOR_ARRAY_COUNT_EXT 0x8084 #define GL_INDEX_ARRAY_TYPE_EXT 0x8085 #define GL_INDEX_ARRAY_STRIDE_EXT 0x8086 #define GL_INDEX_ARRAY_COUNT_EXT 0x8087 #define GL_TEXTURE_COORD_ARRAY_SIZE_EXT 0x8088 #define GL_TEXTURE_COORD_ARRAY_TYPE_EXT 0x8089 #define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A #define GL_TEXTURE_COORD_ARRAY_COUNT_EXT 0x808B #define GL_EDGE_FLAG_ARRAY_STRIDE_EXT 0x808C #define GL_EDGE_FLAG_ARRAY_COUNT_EXT 0x808D #define GL_VERTEX_ARRAY_POINTER_EXT 0x808E #define GL_NORMAL_ARRAY_POINTER_EXT 0x808F #define GL_COLOR_ARRAY_POINTER_EXT 0x8090 #define GL_INDEX_ARRAY_POINTER_EXT 0x8091 #define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092 #define GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093 typedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC) (GLint i); typedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); typedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count); typedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer); typedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC) (GLenum pname, void **params); typedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const void *pointer); typedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const void *pointer); typedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); typedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glArrayElementEXT (GLint i); GLAPI void APIENTRY glColorPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); GLAPI void APIENTRY glDrawArraysEXT (GLenum mode, GLint first, GLsizei count); GLAPI void APIENTRY glEdgeFlagPointerEXT (GLsizei stride, GLsizei count, const GLboolean *pointer); GLAPI void APIENTRY glGetPointervEXT (GLenum pname, void **params); GLAPI void APIENTRY glIndexPointerEXT (GLenum type, GLsizei stride, GLsizei count, const void *pointer); GLAPI void APIENTRY glNormalPointerEXT (GLenum type, GLsizei stride, GLsizei count, const void *pointer); GLAPI void APIENTRY glTexCoordPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); GLAPI void APIENTRY glVertexPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); #endif #endif /* GL_EXT_vertex_array */ #ifndef GL_EXT_vertex_array_bgra #define GL_EXT_vertex_array_bgra 1 #endif /* GL_EXT_vertex_array_bgra */ #ifndef GL_EXT_vertex_attrib_64bit #define GL_EXT_vertex_attrib_64bit 1 #define GL_DOUBLE_VEC2_EXT 0x8FFC #define GL_DOUBLE_VEC3_EXT 0x8FFD #define GL_DOUBLE_VEC4_EXT 0x8FFE #define GL_DOUBLE_MAT2_EXT 0x8F46 #define GL_DOUBLE_MAT3_EXT 0x8F47 #define GL_DOUBLE_MAT4_EXT 0x8F48 #define GL_DOUBLE_MAT2x3_EXT 0x8F49 #define GL_DOUBLE_MAT2x4_EXT 0x8F4A #define GL_DOUBLE_MAT3x2_EXT 0x8F4B #define GL_DOUBLE_MAT3x4_EXT 0x8F4C #define GL_DOUBLE_MAT4x2_EXT 0x8F4D #define GL_DOUBLE_MAT4x3_EXT 0x8F4E typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DEXTPROC) (GLuint index, GLdouble x); typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DEXTPROC) (GLuint index, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVEXTPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVEXTPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVEXTPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVEXTPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVEXTPROC) (GLuint index, GLenum pname, GLdouble *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttribL1dEXT (GLuint index, GLdouble x); GLAPI void APIENTRY glVertexAttribL2dEXT (GLuint index, GLdouble x, GLdouble y); GLAPI void APIENTRY glVertexAttribL3dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glVertexAttribL4dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glVertexAttribL1dvEXT (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribL2dvEXT (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribL3dvEXT (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribL4dvEXT (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribLPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); GLAPI void APIENTRY glGetVertexAttribLdvEXT (GLuint index, GLenum pname, GLdouble *params); #endif #endif /* GL_EXT_vertex_attrib_64bit */ #ifndef GL_EXT_vertex_shader #define GL_EXT_vertex_shader 1 #define GL_VERTEX_SHADER_EXT 0x8780 #define GL_VERTEX_SHADER_BINDING_EXT 0x8781 #define GL_OP_INDEX_EXT 0x8782 #define GL_OP_NEGATE_EXT 0x8783 #define GL_OP_DOT3_EXT 0x8784 #define GL_OP_DOT4_EXT 0x8785 #define GL_OP_MUL_EXT 0x8786 #define GL_OP_ADD_EXT 0x8787 #define GL_OP_MADD_EXT 0x8788 #define GL_OP_FRAC_EXT 0x8789 #define GL_OP_MAX_EXT 0x878A #define GL_OP_MIN_EXT 0x878B #define GL_OP_SET_GE_EXT 0x878C #define GL_OP_SET_LT_EXT 0x878D #define GL_OP_CLAMP_EXT 0x878E #define GL_OP_FLOOR_EXT 0x878F #define GL_OP_ROUND_EXT 0x8790 #define GL_OP_EXP_BASE_2_EXT 0x8791 #define GL_OP_LOG_BASE_2_EXT 0x8792 #define GL_OP_POWER_EXT 0x8793 #define GL_OP_RECIP_EXT 0x8794 #define GL_OP_RECIP_SQRT_EXT 0x8795 #define GL_OP_SUB_EXT 0x8796 #define GL_OP_CROSS_PRODUCT_EXT 0x8797 #define GL_OP_MULTIPLY_MATRIX_EXT 0x8798 #define GL_OP_MOV_EXT 0x8799 #define GL_OUTPUT_VERTEX_EXT 0x879A #define GL_OUTPUT_COLOR0_EXT 0x879B #define GL_OUTPUT_COLOR1_EXT 0x879C #define GL_OUTPUT_TEXTURE_COORD0_EXT 0x879D #define GL_OUTPUT_TEXTURE_COORD1_EXT 0x879E #define GL_OUTPUT_TEXTURE_COORD2_EXT 0x879F #define GL_OUTPUT_TEXTURE_COORD3_EXT 0x87A0 #define GL_OUTPUT_TEXTURE_COORD4_EXT 0x87A1 #define GL_OUTPUT_TEXTURE_COORD5_EXT 0x87A2 #define GL_OUTPUT_TEXTURE_COORD6_EXT 0x87A3 #define GL_OUTPUT_TEXTURE_COORD7_EXT 0x87A4 #define GL_OUTPUT_TEXTURE_COORD8_EXT 0x87A5 #define GL_OUTPUT_TEXTURE_COORD9_EXT 0x87A6 #define GL_OUTPUT_TEXTURE_COORD10_EXT 0x87A7 #define GL_OUTPUT_TEXTURE_COORD11_EXT 0x87A8 #define GL_OUTPUT_TEXTURE_COORD12_EXT 0x87A9 #define GL_OUTPUT_TEXTURE_COORD13_EXT 0x87AA #define GL_OUTPUT_TEXTURE_COORD14_EXT 0x87AB #define GL_OUTPUT_TEXTURE_COORD15_EXT 0x87AC #define GL_OUTPUT_TEXTURE_COORD16_EXT 0x87AD #define GL_OUTPUT_TEXTURE_COORD17_EXT 0x87AE #define GL_OUTPUT_TEXTURE_COORD18_EXT 0x87AF #define GL_OUTPUT_TEXTURE_COORD19_EXT 0x87B0 #define GL_OUTPUT_TEXTURE_COORD20_EXT 0x87B1 #define GL_OUTPUT_TEXTURE_COORD21_EXT 0x87B2 #define GL_OUTPUT_TEXTURE_COORD22_EXT 0x87B3 #define GL_OUTPUT_TEXTURE_COORD23_EXT 0x87B4 #define GL_OUTPUT_TEXTURE_COORD24_EXT 0x87B5 #define GL_OUTPUT_TEXTURE_COORD25_EXT 0x87B6 #define GL_OUTPUT_TEXTURE_COORD26_EXT 0x87B7 #define GL_OUTPUT_TEXTURE_COORD27_EXT 0x87B8 #define GL_OUTPUT_TEXTURE_COORD28_EXT 0x87B9 #define GL_OUTPUT_TEXTURE_COORD29_EXT 0x87BA #define GL_OUTPUT_TEXTURE_COORD30_EXT 0x87BB #define GL_OUTPUT_TEXTURE_COORD31_EXT 0x87BC #define GL_OUTPUT_FOG_EXT 0x87BD #define GL_SCALAR_EXT 0x87BE #define GL_VECTOR_EXT 0x87BF #define GL_MATRIX_EXT 0x87C0 #define GL_VARIANT_EXT 0x87C1 #define GL_INVARIANT_EXT 0x87C2 #define GL_LOCAL_CONSTANT_EXT 0x87C3 #define GL_LOCAL_EXT 0x87C4 #define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5 #define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6 #define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7 #define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8 #define GL_MAX_VERTEX_SHADER_LOCALS_EXT 0x87C9 #define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA #define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB #define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC #define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD #define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE #define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF #define GL_VERTEX_SHADER_VARIANTS_EXT 0x87D0 #define GL_VERTEX_SHADER_INVARIANTS_EXT 0x87D1 #define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2 #define GL_VERTEX_SHADER_LOCALS_EXT 0x87D3 #define GL_VERTEX_SHADER_OPTIMIZED_EXT 0x87D4 #define GL_X_EXT 0x87D5 #define GL_Y_EXT 0x87D6 #define GL_Z_EXT 0x87D7 #define GL_W_EXT 0x87D8 #define GL_NEGATIVE_X_EXT 0x87D9 #define GL_NEGATIVE_Y_EXT 0x87DA #define GL_NEGATIVE_Z_EXT 0x87DB #define GL_NEGATIVE_W_EXT 0x87DC #define GL_ZERO_EXT 0x87DD #define GL_ONE_EXT 0x87DE #define GL_NEGATIVE_ONE_EXT 0x87DF #define GL_NORMALIZED_RANGE_EXT 0x87E0 #define GL_FULL_RANGE_EXT 0x87E1 #define GL_CURRENT_VERTEX_EXT 0x87E2 #define GL_MVP_MATRIX_EXT 0x87E3 #define GL_VARIANT_VALUE_EXT 0x87E4 #define GL_VARIANT_DATATYPE_EXT 0x87E5 #define GL_VARIANT_ARRAY_STRIDE_EXT 0x87E6 #define GL_VARIANT_ARRAY_TYPE_EXT 0x87E7 #define GL_VARIANT_ARRAY_EXT 0x87E8 #define GL_VARIANT_ARRAY_POINTER_EXT 0x87E9 #define GL_INVARIANT_VALUE_EXT 0x87EA #define GL_INVARIANT_DATATYPE_EXT 0x87EB #define GL_LOCAL_CONSTANT_VALUE_EXT 0x87EC #define GL_LOCAL_CONSTANT_DATATYPE_EXT 0x87ED typedef void (APIENTRYP PFNGLBEGINVERTEXSHADEREXTPROC) (void); typedef void (APIENTRYP PFNGLENDVERTEXSHADEREXTPROC) (void); typedef void (APIENTRYP PFNGLBINDVERTEXSHADEREXTPROC) (GLuint id); typedef GLuint (APIENTRYP PFNGLGENVERTEXSHADERSEXTPROC) (GLuint range); typedef void (APIENTRYP PFNGLDELETEVERTEXSHADEREXTPROC) (GLuint id); typedef void (APIENTRYP PFNGLSHADEROP1EXTPROC) (GLenum op, GLuint res, GLuint arg1); typedef void (APIENTRYP PFNGLSHADEROP2EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2); typedef void (APIENTRYP PFNGLSHADEROP3EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); typedef void (APIENTRYP PFNGLSWIZZLEEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); typedef void (APIENTRYP PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); typedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); typedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); typedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); typedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, const void *addr); typedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, const void *addr); typedef void (APIENTRYP PFNGLVARIANTBVEXTPROC) (GLuint id, const GLbyte *addr); typedef void (APIENTRYP PFNGLVARIANTSVEXTPROC) (GLuint id, const GLshort *addr); typedef void (APIENTRYP PFNGLVARIANTIVEXTPROC) (GLuint id, const GLint *addr); typedef void (APIENTRYP PFNGLVARIANTFVEXTPROC) (GLuint id, const GLfloat *addr); typedef void (APIENTRYP PFNGLVARIANTDVEXTPROC) (GLuint id, const GLdouble *addr); typedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC) (GLuint id, const GLubyte *addr); typedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC) (GLuint id, const GLushort *addr); typedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC) (GLuint id, const GLuint *addr); typedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, const void *addr); typedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); typedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); typedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC) (GLenum light, GLenum value); typedef GLuint (APIENTRYP PFNGLBINDMATERIALPARAMETEREXTPROC) (GLenum face, GLenum value); typedef GLuint (APIENTRYP PFNGLBINDTEXGENPARAMETEREXTPROC) (GLenum unit, GLenum coord, GLenum value); typedef GLuint (APIENTRYP PFNGLBINDTEXTUREUNITPARAMETEREXTPROC) (GLenum unit, GLenum value); typedef GLuint (APIENTRYP PFNGLBINDPARAMETEREXTPROC) (GLenum value); typedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC) (GLuint id, GLenum cap); typedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); typedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); typedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); typedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, void **data); typedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); typedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); typedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); typedef void (APIENTRYP PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); typedef void (APIENTRYP PFNGLGETLOCALCONSTANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); typedef void (APIENTRYP PFNGLGETLOCALCONSTANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBeginVertexShaderEXT (void); GLAPI void APIENTRY glEndVertexShaderEXT (void); GLAPI void APIENTRY glBindVertexShaderEXT (GLuint id); GLAPI GLuint APIENTRY glGenVertexShadersEXT (GLuint range); GLAPI void APIENTRY glDeleteVertexShaderEXT (GLuint id); GLAPI void APIENTRY glShaderOp1EXT (GLenum op, GLuint res, GLuint arg1); GLAPI void APIENTRY glShaderOp2EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2); GLAPI void APIENTRY glShaderOp3EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); GLAPI void APIENTRY glSwizzleEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); GLAPI void APIENTRY glWriteMaskEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); GLAPI void APIENTRY glInsertComponentEXT (GLuint res, GLuint src, GLuint num); GLAPI void APIENTRY glExtractComponentEXT (GLuint res, GLuint src, GLuint num); GLAPI GLuint APIENTRY glGenSymbolsEXT (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); GLAPI void APIENTRY glSetInvariantEXT (GLuint id, GLenum type, const void *addr); GLAPI void APIENTRY glSetLocalConstantEXT (GLuint id, GLenum type, const void *addr); GLAPI void APIENTRY glVariantbvEXT (GLuint id, const GLbyte *addr); GLAPI void APIENTRY glVariantsvEXT (GLuint id, const GLshort *addr); GLAPI void APIENTRY glVariantivEXT (GLuint id, const GLint *addr); GLAPI void APIENTRY glVariantfvEXT (GLuint id, const GLfloat *addr); GLAPI void APIENTRY glVariantdvEXT (GLuint id, const GLdouble *addr); GLAPI void APIENTRY glVariantubvEXT (GLuint id, const GLubyte *addr); GLAPI void APIENTRY glVariantusvEXT (GLuint id, const GLushort *addr); GLAPI void APIENTRY glVariantuivEXT (GLuint id, const GLuint *addr); GLAPI void APIENTRY glVariantPointerEXT (GLuint id, GLenum type, GLuint stride, const void *addr); GLAPI void APIENTRY glEnableVariantClientStateEXT (GLuint id); GLAPI void APIENTRY glDisableVariantClientStateEXT (GLuint id); GLAPI GLuint APIENTRY glBindLightParameterEXT (GLenum light, GLenum value); GLAPI GLuint APIENTRY glBindMaterialParameterEXT (GLenum face, GLenum value); GLAPI GLuint APIENTRY glBindTexGenParameterEXT (GLenum unit, GLenum coord, GLenum value); GLAPI GLuint APIENTRY glBindTextureUnitParameterEXT (GLenum unit, GLenum value); GLAPI GLuint APIENTRY glBindParameterEXT (GLenum value); GLAPI GLboolean APIENTRY glIsVariantEnabledEXT (GLuint id, GLenum cap); GLAPI void APIENTRY glGetVariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); GLAPI void APIENTRY glGetVariantIntegervEXT (GLuint id, GLenum value, GLint *data); GLAPI void APIENTRY glGetVariantFloatvEXT (GLuint id, GLenum value, GLfloat *data); GLAPI void APIENTRY glGetVariantPointervEXT (GLuint id, GLenum value, void **data); GLAPI void APIENTRY glGetInvariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); GLAPI void APIENTRY glGetInvariantIntegervEXT (GLuint id, GLenum value, GLint *data); GLAPI void APIENTRY glGetInvariantFloatvEXT (GLuint id, GLenum value, GLfloat *data); GLAPI void APIENTRY glGetLocalConstantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); GLAPI void APIENTRY glGetLocalConstantIntegervEXT (GLuint id, GLenum value, GLint *data); GLAPI void APIENTRY glGetLocalConstantFloatvEXT (GLuint id, GLenum value, GLfloat *data); #endif #endif /* GL_EXT_vertex_shader */ #ifndef GL_EXT_vertex_weighting #define GL_EXT_vertex_weighting 1 #define GL_MODELVIEW0_STACK_DEPTH_EXT 0x0BA3 #define GL_MODELVIEW1_STACK_DEPTH_EXT 0x8502 #define GL_MODELVIEW0_MATRIX_EXT 0x0BA6 #define GL_MODELVIEW1_MATRIX_EXT 0x8506 #define GL_VERTEX_WEIGHTING_EXT 0x8509 #define GL_MODELVIEW0_EXT 0x1700 #define GL_MODELVIEW1_EXT 0x850A #define GL_CURRENT_VERTEX_WEIGHT_EXT 0x850B #define GL_VERTEX_WEIGHT_ARRAY_EXT 0x850C #define GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT 0x850D #define GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT 0x850E #define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F #define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510 typedef void (APIENTRYP PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight); typedef void (APIENTRYP PFNGLVERTEXWEIGHTFVEXTPROC) (const GLfloat *weight); typedef void (APIENTRYP PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexWeightfEXT (GLfloat weight); GLAPI void APIENTRY glVertexWeightfvEXT (const GLfloat *weight); GLAPI void APIENTRY glVertexWeightPointerEXT (GLint size, GLenum type, GLsizei stride, const void *pointer); #endif #endif /* GL_EXT_vertex_weighting */ #ifndef GL_EXT_win32_keyed_mutex #define GL_EXT_win32_keyed_mutex 1 typedef GLboolean (APIENTRYP PFNGLACQUIREKEYEDMUTEXWIN32EXTPROC) (GLuint memory, GLuint64 key, GLuint timeout); typedef GLboolean (APIENTRYP PFNGLRELEASEKEYEDMUTEXWIN32EXTPROC) (GLuint memory, GLuint64 key); #ifdef GL_GLEXT_PROTOTYPES GLAPI GLboolean APIENTRY glAcquireKeyedMutexWin32EXT (GLuint memory, GLuint64 key, GLuint timeout); GLAPI GLboolean APIENTRY glReleaseKeyedMutexWin32EXT (GLuint memory, GLuint64 key); #endif #endif /* GL_EXT_win32_keyed_mutex */ #ifndef GL_EXT_window_rectangles #define GL_EXT_window_rectangles 1 #define GL_INCLUSIVE_EXT 0x8F10 #define GL_EXCLUSIVE_EXT 0x8F11 #define GL_WINDOW_RECTANGLE_EXT 0x8F12 #define GL_WINDOW_RECTANGLE_MODE_EXT 0x8F13 #define GL_MAX_WINDOW_RECTANGLES_EXT 0x8F14 #define GL_NUM_WINDOW_RECTANGLES_EXT 0x8F15 typedef void (APIENTRYP PFNGLWINDOWRECTANGLESEXTPROC) (GLenum mode, GLsizei count, const GLint *box); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glWindowRectanglesEXT (GLenum mode, GLsizei count, const GLint *box); #endif #endif /* GL_EXT_window_rectangles */ #ifndef GL_EXT_x11_sync_object #define GL_EXT_x11_sync_object 1 #define GL_SYNC_X11_FENCE_EXT 0x90E1 typedef GLsync (APIENTRYP PFNGLIMPORTSYNCEXTPROC) (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags); #ifdef GL_GLEXT_PROTOTYPES GLAPI GLsync APIENTRY glImportSyncEXT (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags); #endif #endif /* GL_EXT_x11_sync_object */ #ifndef GL_GREMEDY_frame_terminator #define GL_GREMEDY_frame_terminator 1 typedef void (APIENTRYP PFNGLFRAMETERMINATORGREMEDYPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFrameTerminatorGREMEDY (void); #endif #endif /* GL_GREMEDY_frame_terminator */ #ifndef GL_GREMEDY_string_marker #define GL_GREMEDY_string_marker 1 typedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const void *string); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glStringMarkerGREMEDY (GLsizei len, const void *string); #endif #endif /* GL_GREMEDY_string_marker */ #ifndef GL_HP_convolution_border_modes #define GL_HP_convolution_border_modes 1 #define GL_IGNORE_BORDER_HP 0x8150 #define GL_CONSTANT_BORDER_HP 0x8151 #define GL_REPLICATE_BORDER_HP 0x8153 #define GL_CONVOLUTION_BORDER_COLOR_HP 0x8154 #endif /* GL_HP_convolution_border_modes */ #ifndef GL_HP_image_transform #define GL_HP_image_transform 1 #define GL_IMAGE_SCALE_X_HP 0x8155 #define GL_IMAGE_SCALE_Y_HP 0x8156 #define GL_IMAGE_TRANSLATE_X_HP 0x8157 #define GL_IMAGE_TRANSLATE_Y_HP 0x8158 #define GL_IMAGE_ROTATE_ANGLE_HP 0x8159 #define GL_IMAGE_ROTATE_ORIGIN_X_HP 0x815A #define GL_IMAGE_ROTATE_ORIGIN_Y_HP 0x815B #define GL_IMAGE_MAG_FILTER_HP 0x815C #define GL_IMAGE_MIN_FILTER_HP 0x815D #define GL_IMAGE_CUBIC_WEIGHT_HP 0x815E #define GL_CUBIC_HP 0x815F #define GL_AVERAGE_HP 0x8160 #define GL_IMAGE_TRANSFORM_2D_HP 0x8161 #define GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8162 #define GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8163 typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glImageTransformParameteriHP (GLenum target, GLenum pname, GLint param); GLAPI void APIENTRY glImageTransformParameterfHP (GLenum target, GLenum pname, GLfloat param); GLAPI void APIENTRY glImageTransformParameterivHP (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glImageTransformParameterfvHP (GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glGetImageTransformParameterivHP (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetImageTransformParameterfvHP (GLenum target, GLenum pname, GLfloat *params); #endif #endif /* GL_HP_image_transform */ #ifndef GL_HP_occlusion_test #define GL_HP_occlusion_test 1 #define GL_OCCLUSION_TEST_HP 0x8165 #define GL_OCCLUSION_TEST_RESULT_HP 0x8166 #endif /* GL_HP_occlusion_test */ #ifndef GL_HP_texture_lighting #define GL_HP_texture_lighting 1 #define GL_TEXTURE_LIGHTING_MODE_HP 0x8167 #define GL_TEXTURE_POST_SPECULAR_HP 0x8168 #define GL_TEXTURE_PRE_SPECULAR_HP 0x8169 #endif /* GL_HP_texture_lighting */ #ifndef GL_IBM_cull_vertex #define GL_IBM_cull_vertex 1 #define GL_CULL_VERTEX_IBM 103050 #endif /* GL_IBM_cull_vertex */ #ifndef GL_IBM_multimode_draw_arrays #define GL_IBM_multimode_draw_arrays 1 typedef void (APIENTRYP PFNGLMULTIMODEDRAWARRAYSIBMPROC) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); typedef void (APIENTRYP PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum *mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, GLint modestride); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMultiModeDrawArraysIBM (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); GLAPI void APIENTRY glMultiModeDrawElementsIBM (const GLenum *mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, GLint modestride); #endif #endif /* GL_IBM_multimode_draw_arrays */ #ifndef GL_IBM_rasterpos_clip #define GL_IBM_rasterpos_clip 1 #define GL_RASTER_POSITION_UNCLIPPED_IBM 0x19262 #endif /* GL_IBM_rasterpos_clip */ #ifndef GL_IBM_static_data #define GL_IBM_static_data 1 #define GL_ALL_STATIC_DATA_IBM 103060 #define GL_STATIC_VERTEX_ARRAY_IBM 103061 typedef void (APIENTRYP PFNGLFLUSHSTATICDATAIBMPROC) (GLenum target); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFlushStaticDataIBM (GLenum target); #endif #endif /* GL_IBM_static_data */ #ifndef GL_IBM_texture_mirrored_repeat #define GL_IBM_texture_mirrored_repeat 1 #define GL_MIRRORED_REPEAT_IBM 0x8370 #endif /* GL_IBM_texture_mirrored_repeat */ #ifndef GL_IBM_vertex_array_lists #define GL_IBM_vertex_array_lists 1 #define GL_VERTEX_ARRAY_LIST_IBM 103070 #define GL_NORMAL_ARRAY_LIST_IBM 103071 #define GL_COLOR_ARRAY_LIST_IBM 103072 #define GL_INDEX_ARRAY_LIST_IBM 103073 #define GL_TEXTURE_COORD_ARRAY_LIST_IBM 103074 #define GL_EDGE_FLAG_ARRAY_LIST_IBM 103075 #define GL_FOG_COORDINATE_ARRAY_LIST_IBM 103076 #define GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077 #define GL_VERTEX_ARRAY_LIST_STRIDE_IBM 103080 #define GL_NORMAL_ARRAY_LIST_STRIDE_IBM 103081 #define GL_COLOR_ARRAY_LIST_STRIDE_IBM 103082 #define GL_INDEX_ARRAY_LIST_STRIDE_IBM 103083 #define GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084 #define GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085 #define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086 #define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087 typedef void (APIENTRYP PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERLISTIBMPROC) (GLint stride, const GLboolean **pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); GLAPI void APIENTRY glSecondaryColorPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); GLAPI void APIENTRY glEdgeFlagPointerListIBM (GLint stride, const GLboolean **pointer, GLint ptrstride); GLAPI void APIENTRY glFogCoordPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride); GLAPI void APIENTRY glIndexPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride); GLAPI void APIENTRY glNormalPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride); GLAPI void APIENTRY glTexCoordPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); GLAPI void APIENTRY glVertexPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); #endif #endif /* GL_IBM_vertex_array_lists */ #ifndef GL_INGR_blend_func_separate #define GL_INGR_blend_func_separate 1 typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINGRPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); #endif #endif /* GL_INGR_blend_func_separate */ #ifndef GL_INGR_color_clamp #define GL_INGR_color_clamp 1 #define GL_RED_MIN_CLAMP_INGR 0x8560 #define GL_GREEN_MIN_CLAMP_INGR 0x8561 #define GL_BLUE_MIN_CLAMP_INGR 0x8562 #define GL_ALPHA_MIN_CLAMP_INGR 0x8563 #define GL_RED_MAX_CLAMP_INGR 0x8564 #define GL_GREEN_MAX_CLAMP_INGR 0x8565 #define GL_BLUE_MAX_CLAMP_INGR 0x8566 #define GL_ALPHA_MAX_CLAMP_INGR 0x8567 #endif /* GL_INGR_color_clamp */ #ifndef GL_INGR_interlace_read #define GL_INGR_interlace_read 1 #define GL_INTERLACE_READ_INGR 0x8568 #endif /* GL_INGR_interlace_read */ #ifndef GL_INTEL_blackhole_render #define GL_INTEL_blackhole_render 1 #define GL_BLACKHOLE_RENDER_INTEL 0x83FC #endif /* GL_INTEL_blackhole_render */ #ifndef GL_INTEL_conservative_rasterization #define GL_INTEL_conservative_rasterization 1 #define GL_CONSERVATIVE_RASTERIZATION_INTEL 0x83FE #endif /* GL_INTEL_conservative_rasterization */ #ifndef GL_INTEL_fragment_shader_ordering #define GL_INTEL_fragment_shader_ordering 1 #endif /* GL_INTEL_fragment_shader_ordering */ #ifndef GL_INTEL_framebuffer_CMAA #define GL_INTEL_framebuffer_CMAA 1 typedef void (APIENTRYP PFNGLAPPLYFRAMEBUFFERATTACHMENTCMAAINTELPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glApplyFramebufferAttachmentCMAAINTEL (void); #endif #endif /* GL_INTEL_framebuffer_CMAA */ #ifndef GL_INTEL_map_texture #define GL_INTEL_map_texture 1 #define GL_TEXTURE_MEMORY_LAYOUT_INTEL 0x83FF #define GL_LAYOUT_DEFAULT_INTEL 0 #define GL_LAYOUT_LINEAR_INTEL 1 #define GL_LAYOUT_LINEAR_CPU_CACHED_INTEL 2 typedef void (APIENTRYP PFNGLSYNCTEXTUREINTELPROC) (GLuint texture); typedef void (APIENTRYP PFNGLUNMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level); typedef void *(APIENTRYP PFNGLMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level, GLbitfield access, GLint *stride, GLenum *layout); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSyncTextureINTEL (GLuint texture); GLAPI void APIENTRY glUnmapTexture2DINTEL (GLuint texture, GLint level); GLAPI void *APIENTRY glMapTexture2DINTEL (GLuint texture, GLint level, GLbitfield access, GLint *stride, GLenum *layout); #endif #endif /* GL_INTEL_map_texture */ #ifndef GL_INTEL_parallel_arrays #define GL_INTEL_parallel_arrays 1 #define GL_PARALLEL_ARRAYS_INTEL 0x83F4 #define GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5 #define GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6 #define GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7 #define GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8 typedef void (APIENTRYP PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer); typedef void (APIENTRYP PFNGLNORMALPOINTERVINTELPROC) (GLenum type, const void **pointer); typedef void (APIENTRYP PFNGLCOLORPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer); typedef void (APIENTRYP PFNGLTEXCOORDPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexPointervINTEL (GLint size, GLenum type, const void **pointer); GLAPI void APIENTRY glNormalPointervINTEL (GLenum type, const void **pointer); GLAPI void APIENTRY glColorPointervINTEL (GLint size, GLenum type, const void **pointer); GLAPI void APIENTRY glTexCoordPointervINTEL (GLint size, GLenum type, const void **pointer); #endif #endif /* GL_INTEL_parallel_arrays */ #ifndef GL_INTEL_performance_query #define GL_INTEL_performance_query 1 #define GL_PERFQUERY_SINGLE_CONTEXT_INTEL 0x00000000 #define GL_PERFQUERY_GLOBAL_CONTEXT_INTEL 0x00000001 #define GL_PERFQUERY_WAIT_INTEL 0x83FB #define GL_PERFQUERY_FLUSH_INTEL 0x83FA #define GL_PERFQUERY_DONOT_FLUSH_INTEL 0x83F9 #define GL_PERFQUERY_COUNTER_EVENT_INTEL 0x94F0 #define GL_PERFQUERY_COUNTER_DURATION_NORM_INTEL 0x94F1 #define GL_PERFQUERY_COUNTER_DURATION_RAW_INTEL 0x94F2 #define GL_PERFQUERY_COUNTER_THROUGHPUT_INTEL 0x94F3 #define GL_PERFQUERY_COUNTER_RAW_INTEL 0x94F4 #define GL_PERFQUERY_COUNTER_TIMESTAMP_INTEL 0x94F5 #define GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL 0x94F8 #define GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL 0x94F9 #define GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL 0x94FA #define GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL 0x94FB #define GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL 0x94FC #define GL_PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL 0x94FD #define GL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL 0x94FE #define GL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL 0x94FF #define GL_PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL 0x9500 typedef void (APIENTRYP PFNGLBEGINPERFQUERYINTELPROC) (GLuint queryHandle); typedef void (APIENTRYP PFNGLCREATEPERFQUERYINTELPROC) (GLuint queryId, GLuint *queryHandle); typedef void (APIENTRYP PFNGLDELETEPERFQUERYINTELPROC) (GLuint queryHandle); typedef void (APIENTRYP PFNGLENDPERFQUERYINTELPROC) (GLuint queryHandle); typedef void (APIENTRYP PFNGLGETFIRSTPERFQUERYIDINTELPROC) (GLuint *queryId); typedef void (APIENTRYP PFNGLGETNEXTPERFQUERYIDINTELPROC) (GLuint queryId, GLuint *nextQueryId); typedef void (APIENTRYP PFNGLGETPERFCOUNTERINFOINTELPROC) (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue); typedef void (APIENTRYP PFNGLGETPERFQUERYDATAINTELPROC) (GLuint queryHandle, GLuint flags, GLsizei dataSize, void *data, GLuint *bytesWritten); typedef void (APIENTRYP PFNGLGETPERFQUERYIDBYNAMEINTELPROC) (GLchar *queryName, GLuint *queryId); typedef void (APIENTRYP PFNGLGETPERFQUERYINFOINTELPROC) (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBeginPerfQueryINTEL (GLuint queryHandle); GLAPI void APIENTRY glCreatePerfQueryINTEL (GLuint queryId, GLuint *queryHandle); GLAPI void APIENTRY glDeletePerfQueryINTEL (GLuint queryHandle); GLAPI void APIENTRY glEndPerfQueryINTEL (GLuint queryHandle); GLAPI void APIENTRY glGetFirstPerfQueryIdINTEL (GLuint *queryId); GLAPI void APIENTRY glGetNextPerfQueryIdINTEL (GLuint queryId, GLuint *nextQueryId); GLAPI void APIENTRY glGetPerfCounterInfoINTEL (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue); GLAPI void APIENTRY glGetPerfQueryDataINTEL (GLuint queryHandle, GLuint flags, GLsizei dataSize, void *data, GLuint *bytesWritten); GLAPI void APIENTRY glGetPerfQueryIdByNameINTEL (GLchar *queryName, GLuint *queryId); GLAPI void APIENTRY glGetPerfQueryInfoINTEL (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask); #endif #endif /* GL_INTEL_performance_query */ #ifndef GL_MESAX_texture_stack #define GL_MESAX_texture_stack 1 #define GL_TEXTURE_1D_STACK_MESAX 0x8759 #define GL_TEXTURE_2D_STACK_MESAX 0x875A #define GL_PROXY_TEXTURE_1D_STACK_MESAX 0x875B #define GL_PROXY_TEXTURE_2D_STACK_MESAX 0x875C #define GL_TEXTURE_1D_STACK_BINDING_MESAX 0x875D #define GL_TEXTURE_2D_STACK_BINDING_MESAX 0x875E #endif /* GL_MESAX_texture_stack */ #ifndef GL_MESA_framebuffer_flip_x #define GL_MESA_framebuffer_flip_x 1 #define GL_FRAMEBUFFER_FLIP_X_MESA 0x8BBC #endif /* GL_MESA_framebuffer_flip_x */ #ifndef GL_MESA_framebuffer_flip_y #define GL_MESA_framebuffer_flip_y 1 #define GL_FRAMEBUFFER_FLIP_Y_MESA 0x8BBB typedef void (APIENTRYP PFNGLFRAMEBUFFERPARAMETERIMESAPROC) (GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVMESAPROC) (GLenum target, GLenum pname, GLint *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFramebufferParameteriMESA (GLenum target, GLenum pname, GLint param); GLAPI void APIENTRY glGetFramebufferParameterivMESA (GLenum target, GLenum pname, GLint *params); #endif #endif /* GL_MESA_framebuffer_flip_y */ #ifndef GL_MESA_framebuffer_swap_xy #define GL_MESA_framebuffer_swap_xy 1 #define GL_FRAMEBUFFER_SWAP_XY_MESA 0x8BBD #endif /* GL_MESA_framebuffer_swap_xy */ #ifndef GL_MESA_pack_invert #define GL_MESA_pack_invert 1 #define GL_PACK_INVERT_MESA 0x8758 #endif /* GL_MESA_pack_invert */ #ifndef GL_MESA_program_binary_formats #define GL_MESA_program_binary_formats 1 #define GL_PROGRAM_BINARY_FORMAT_MESA 0x875F #endif /* GL_MESA_program_binary_formats */ #ifndef GL_MESA_resize_buffers #define GL_MESA_resize_buffers 1 typedef void (APIENTRYP PFNGLRESIZEBUFFERSMESAPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glResizeBuffersMESA (void); #endif #endif /* GL_MESA_resize_buffers */ #ifndef GL_MESA_shader_integer_functions #define GL_MESA_shader_integer_functions 1 #endif /* GL_MESA_shader_integer_functions */ #ifndef GL_MESA_tile_raster_order #define GL_MESA_tile_raster_order 1 #define GL_TILE_RASTER_ORDER_FIXED_MESA 0x8BB8 #define GL_TILE_RASTER_ORDER_INCREASING_X_MESA 0x8BB9 #define GL_TILE_RASTER_ORDER_INCREASING_Y_MESA 0x8BBA #endif /* GL_MESA_tile_raster_order */ #ifndef GL_MESA_window_pos #define GL_MESA_window_pos 1 typedef void (APIENTRYP PFNGLWINDOWPOS2DMESAPROC) (GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLWINDOWPOS2DVMESAPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS2FMESAPROC) (GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLWINDOWPOS2FVMESAPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS2IMESAPROC) (GLint x, GLint y); typedef void (APIENTRYP PFNGLWINDOWPOS2IVMESAPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS2SMESAPROC) (GLshort x, GLshort y); typedef void (APIENTRYP PFNGLWINDOWPOS2SVMESAPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLWINDOWPOS3DMESAPROC) (GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLWINDOWPOS3DVMESAPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS3FMESAPROC) (GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLWINDOWPOS3FVMESAPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS3IMESAPROC) (GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLWINDOWPOS3IVMESAPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS3SMESAPROC) (GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLWINDOWPOS3SVMESAPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLWINDOWPOS4DMESAPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLWINDOWPOS4DVMESAPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS4FMESAPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLWINDOWPOS4FVMESAPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS4IMESAPROC) (GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLWINDOWPOS4IVMESAPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS4SMESAPROC) (GLshort x, GLshort y, GLshort z, GLshort w); typedef void (APIENTRYP PFNGLWINDOWPOS4SVMESAPROC) (const GLshort *v); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glWindowPos2dMESA (GLdouble x, GLdouble y); GLAPI void APIENTRY glWindowPos2dvMESA (const GLdouble *v); GLAPI void APIENTRY glWindowPos2fMESA (GLfloat x, GLfloat y); GLAPI void APIENTRY glWindowPos2fvMESA (const GLfloat *v); GLAPI void APIENTRY glWindowPos2iMESA (GLint x, GLint y); GLAPI void APIENTRY glWindowPos2ivMESA (const GLint *v); GLAPI void APIENTRY glWindowPos2sMESA (GLshort x, GLshort y); GLAPI void APIENTRY glWindowPos2svMESA (const GLshort *v); GLAPI void APIENTRY glWindowPos3dMESA (GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glWindowPos3dvMESA (const GLdouble *v); GLAPI void APIENTRY glWindowPos3fMESA (GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glWindowPos3fvMESA (const GLfloat *v); GLAPI void APIENTRY glWindowPos3iMESA (GLint x, GLint y, GLint z); GLAPI void APIENTRY glWindowPos3ivMESA (const GLint *v); GLAPI void APIENTRY glWindowPos3sMESA (GLshort x, GLshort y, GLshort z); GLAPI void APIENTRY glWindowPos3svMESA (const GLshort *v); GLAPI void APIENTRY glWindowPos4dMESA (GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glWindowPos4dvMESA (const GLdouble *v); GLAPI void APIENTRY glWindowPos4fMESA (GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glWindowPos4fvMESA (const GLfloat *v); GLAPI void APIENTRY glWindowPos4iMESA (GLint x, GLint y, GLint z, GLint w); GLAPI void APIENTRY glWindowPos4ivMESA (const GLint *v); GLAPI void APIENTRY glWindowPos4sMESA (GLshort x, GLshort y, GLshort z, GLshort w); GLAPI void APIENTRY glWindowPos4svMESA (const GLshort *v); #endif #endif /* GL_MESA_window_pos */ #ifndef GL_MESA_ycbcr_texture #define GL_MESA_ycbcr_texture 1 #define GL_UNSIGNED_SHORT_8_8_MESA 0x85BA #define GL_UNSIGNED_SHORT_8_8_REV_MESA 0x85BB #define GL_YCBCR_MESA 0x8757 #endif /* GL_MESA_ycbcr_texture */ #ifndef GL_NVX_blend_equation_advanced_multi_draw_buffers #define GL_NVX_blend_equation_advanced_multi_draw_buffers 1 #endif /* GL_NVX_blend_equation_advanced_multi_draw_buffers */ #ifndef GL_NVX_conditional_render #define GL_NVX_conditional_render 1 typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERNVXPROC) (GLuint id); typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERNVXPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBeginConditionalRenderNVX (GLuint id); GLAPI void APIENTRY glEndConditionalRenderNVX (void); #endif #endif /* GL_NVX_conditional_render */ #ifndef GL_NVX_gpu_memory_info #define GL_NVX_gpu_memory_info 1 #define GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX 0x9047 #define GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX 0x9048 #define GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049 #define GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX 0x904A #define GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX 0x904B #endif /* GL_NVX_gpu_memory_info */ #ifndef GL_NVX_gpu_multicast2 #define GL_NVX_gpu_multicast2 1 #define GL_UPLOAD_GPU_MASK_NVX 0x954A typedef void (APIENTRYP PFNGLUPLOADGPUMASKNVXPROC) (GLbitfield mask); typedef void (APIENTRYP PFNGLMULTICASTVIEWPORTARRAYVNVXPROC) (GLuint gpu, GLuint first, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTICASTVIEWPORTPOSITIONWSCALENVXPROC) (GLuint gpu, GLuint index, GLfloat xcoeff, GLfloat ycoeff); typedef void (APIENTRYP PFNGLMULTICASTSCISSORARRAYVNVXPROC) (GLuint gpu, GLuint first, GLsizei count, const GLint *v); typedef GLuint (APIENTRYP PFNGLASYNCCOPYBUFFERSUBDATANVXPROC) (GLsizei waitSemaphoreCount, const GLuint *waitSemaphoreArray, const GLuint64 *fenceValueArray, GLuint readGpu, GLbitfield writeGpuMask, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size, GLsizei signalSemaphoreCount, const GLuint *signalSemaphoreArray, const GLuint64 *signalValueArray); typedef GLuint (APIENTRYP PFNGLASYNCCOPYIMAGESUBDATANVXPROC) (GLsizei waitSemaphoreCount, const GLuint *waitSemaphoreArray, const GLuint64 *waitValueArray, GLuint srcGpu, GLbitfield dstGpuMask, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth, GLsizei signalSemaphoreCount, const GLuint *signalSemaphoreArray, const GLuint64 *signalValueArray); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glUploadGpuMaskNVX (GLbitfield mask); GLAPI void APIENTRY glMulticastViewportArrayvNVX (GLuint gpu, GLuint first, GLsizei count, const GLfloat *v); GLAPI void APIENTRY glMulticastViewportPositionWScaleNVX (GLuint gpu, GLuint index, GLfloat xcoeff, GLfloat ycoeff); GLAPI void APIENTRY glMulticastScissorArrayvNVX (GLuint gpu, GLuint first, GLsizei count, const GLint *v); GLAPI GLuint APIENTRY glAsyncCopyBufferSubDataNVX (GLsizei waitSemaphoreCount, const GLuint *waitSemaphoreArray, const GLuint64 *fenceValueArray, GLuint readGpu, GLbitfield writeGpuMask, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size, GLsizei signalSemaphoreCount, const GLuint *signalSemaphoreArray, const GLuint64 *signalValueArray); GLAPI GLuint APIENTRY glAsyncCopyImageSubDataNVX (GLsizei waitSemaphoreCount, const GLuint *waitSemaphoreArray, const GLuint64 *waitValueArray, GLuint srcGpu, GLbitfield dstGpuMask, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth, GLsizei signalSemaphoreCount, const GLuint *signalSemaphoreArray, const GLuint64 *signalValueArray); #endif #endif /* GL_NVX_gpu_multicast2 */ #ifndef GL_NVX_linked_gpu_multicast #define GL_NVX_linked_gpu_multicast 1 #define GL_LGPU_SEPARATE_STORAGE_BIT_NVX 0x0800 #define GL_MAX_LGPU_GPUS_NVX 0x92BA typedef void (APIENTRYP PFNGLLGPUNAMEDBUFFERSUBDATANVXPROC) (GLbitfield gpuMask, GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); typedef void (APIENTRYP PFNGLLGPUCOPYIMAGESUBDATANVXPROC) (GLuint sourceGpu, GLbitfield destinationGpuMask, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srxY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); typedef void (APIENTRYP PFNGLLGPUINTERLOCKNVXPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glLGPUNamedBufferSubDataNVX (GLbitfield gpuMask, GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); GLAPI void APIENTRY glLGPUCopyImageSubDataNVX (GLuint sourceGpu, GLbitfield destinationGpuMask, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srxY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); GLAPI void APIENTRY glLGPUInterlockNVX (void); #endif #endif /* GL_NVX_linked_gpu_multicast */ #ifndef GL_NVX_progress_fence #define GL_NVX_progress_fence 1 typedef GLuint (APIENTRYP PFNGLCREATEPROGRESSFENCENVXPROC) (void); typedef void (APIENTRYP PFNGLSIGNALSEMAPHOREUI64NVXPROC) (GLuint signalGpu, GLsizei fenceObjectCount, const GLuint *semaphoreArray, const GLuint64 *fenceValueArray); typedef void (APIENTRYP PFNGLWAITSEMAPHOREUI64NVXPROC) (GLuint waitGpu, GLsizei fenceObjectCount, const GLuint *semaphoreArray, const GLuint64 *fenceValueArray); typedef void (APIENTRYP PFNGLCLIENTWAITSEMAPHOREUI64NVXPROC) (GLsizei fenceObjectCount, const GLuint *semaphoreArray, const GLuint64 *fenceValueArray); #ifdef GL_GLEXT_PROTOTYPES GLAPI GLuint APIENTRY glCreateProgressFenceNVX (void); GLAPI void APIENTRY glSignalSemaphoreui64NVX (GLuint signalGpu, GLsizei fenceObjectCount, const GLuint *semaphoreArray, const GLuint64 *fenceValueArray); GLAPI void APIENTRY glWaitSemaphoreui64NVX (GLuint waitGpu, GLsizei fenceObjectCount, const GLuint *semaphoreArray, const GLuint64 *fenceValueArray); GLAPI void APIENTRY glClientWaitSemaphoreui64NVX (GLsizei fenceObjectCount, const GLuint *semaphoreArray, const GLuint64 *fenceValueArray); #endif #endif /* GL_NVX_progress_fence */ #ifndef GL_NV_alpha_to_coverage_dither_control #define GL_NV_alpha_to_coverage_dither_control 1 #define GL_ALPHA_TO_COVERAGE_DITHER_DEFAULT_NV 0x934D #define GL_ALPHA_TO_COVERAGE_DITHER_ENABLE_NV 0x934E #define GL_ALPHA_TO_COVERAGE_DITHER_DISABLE_NV 0x934F #define GL_ALPHA_TO_COVERAGE_DITHER_MODE_NV 0x92BF typedef void (APIENTRYP PFNGLALPHATOCOVERAGEDITHERCONTROLNVPROC) (GLenum mode); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glAlphaToCoverageDitherControlNV (GLenum mode); #endif #endif /* GL_NV_alpha_to_coverage_dither_control */ #ifndef GL_NV_bindless_multi_draw_indirect #define GL_NV_bindless_multi_draw_indirect 1 typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC) (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMultiDrawArraysIndirectBindlessNV (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); GLAPI void APIENTRY glMultiDrawElementsIndirectBindlessNV (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); #endif #endif /* GL_NV_bindless_multi_draw_indirect */ #ifndef GL_NV_bindless_multi_draw_indirect_count #define GL_NV_bindless_multi_draw_indirect_count 1 typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSCOUNTNVPROC) (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSCOUNTNVPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMultiDrawArraysIndirectBindlessCountNV (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount); GLAPI void APIENTRY glMultiDrawElementsIndirectBindlessCountNV (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount); #endif #endif /* GL_NV_bindless_multi_draw_indirect_count */ #ifndef GL_NV_bindless_texture #define GL_NV_bindless_texture 1 typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLENVPROC) (GLuint texture); typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLENVPROC) (GLuint texture, GLuint sampler); typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTNVPROC) (GLuint64 handle); typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTNVPROC) (GLuint64 handle); typedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLENVPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTNVPROC) (GLuint64 handle, GLenum access); typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTNVPROC) (GLuint64 handle); typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64NVPROC) (GLint location, GLuint64 value); typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VNVPROC) (GLint location, GLsizei count, const GLuint64 *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64NVPROC) (GLuint program, GLint location, GLuint64 value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values); typedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTNVPROC) (GLuint64 handle); typedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTNVPROC) (GLuint64 handle); #ifdef GL_GLEXT_PROTOTYPES GLAPI GLuint64 APIENTRY glGetTextureHandleNV (GLuint texture); GLAPI GLuint64 APIENTRY glGetTextureSamplerHandleNV (GLuint texture, GLuint sampler); GLAPI void APIENTRY glMakeTextureHandleResidentNV (GLuint64 handle); GLAPI void APIENTRY glMakeTextureHandleNonResidentNV (GLuint64 handle); GLAPI GLuint64 APIENTRY glGetImageHandleNV (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); GLAPI void APIENTRY glMakeImageHandleResidentNV (GLuint64 handle, GLenum access); GLAPI void APIENTRY glMakeImageHandleNonResidentNV (GLuint64 handle); GLAPI void APIENTRY glUniformHandleui64NV (GLint location, GLuint64 value); GLAPI void APIENTRY glUniformHandleui64vNV (GLint location, GLsizei count, const GLuint64 *value); GLAPI void APIENTRY glProgramUniformHandleui64NV (GLuint program, GLint location, GLuint64 value); GLAPI void APIENTRY glProgramUniformHandleui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64 *values); GLAPI GLboolean APIENTRY glIsTextureHandleResidentNV (GLuint64 handle); GLAPI GLboolean APIENTRY glIsImageHandleResidentNV (GLuint64 handle); #endif #endif /* GL_NV_bindless_texture */ #ifndef GL_NV_blend_equation_advanced #define GL_NV_blend_equation_advanced 1 #define GL_BLEND_OVERLAP_NV 0x9281 #define GL_BLEND_PREMULTIPLIED_SRC_NV 0x9280 #define GL_BLUE_NV 0x1905 #define GL_COLORBURN_NV 0x929A #define GL_COLORDODGE_NV 0x9299 #define GL_CONJOINT_NV 0x9284 #define GL_CONTRAST_NV 0x92A1 #define GL_DARKEN_NV 0x9297 #define GL_DIFFERENCE_NV 0x929E #define GL_DISJOINT_NV 0x9283 #define GL_DST_ATOP_NV 0x928F #define GL_DST_IN_NV 0x928B #define GL_DST_NV 0x9287 #define GL_DST_OUT_NV 0x928D #define GL_DST_OVER_NV 0x9289 #define GL_EXCLUSION_NV 0x92A0 #define GL_GREEN_NV 0x1904 #define GL_HARDLIGHT_NV 0x929B #define GL_HARDMIX_NV 0x92A9 #define GL_HSL_COLOR_NV 0x92AF #define GL_HSL_HUE_NV 0x92AD #define GL_HSL_LUMINOSITY_NV 0x92B0 #define GL_HSL_SATURATION_NV 0x92AE #define GL_INVERT_OVG_NV 0x92B4 #define GL_INVERT_RGB_NV 0x92A3 #define GL_LIGHTEN_NV 0x9298 #define GL_LINEARBURN_NV 0x92A5 #define GL_LINEARDODGE_NV 0x92A4 #define GL_LINEARLIGHT_NV 0x92A7 #define GL_MINUS_CLAMPED_NV 0x92B3 #define GL_MINUS_NV 0x929F #define GL_MULTIPLY_NV 0x9294 #define GL_OVERLAY_NV 0x9296 #define GL_PINLIGHT_NV 0x92A8 #define GL_PLUS_CLAMPED_ALPHA_NV 0x92B2 #define GL_PLUS_CLAMPED_NV 0x92B1 #define GL_PLUS_DARKER_NV 0x9292 #define GL_PLUS_NV 0x9291 #define GL_RED_NV 0x1903 #define GL_SCREEN_NV 0x9295 #define GL_SOFTLIGHT_NV 0x929C #define GL_SRC_ATOP_NV 0x928E #define GL_SRC_IN_NV 0x928A #define GL_SRC_NV 0x9286 #define GL_SRC_OUT_NV 0x928C #define GL_SRC_OVER_NV 0x9288 #define GL_UNCORRELATED_NV 0x9282 #define GL_VIVIDLIGHT_NV 0x92A6 #define GL_XOR_NV 0x1506 typedef void (APIENTRYP PFNGLBLENDPARAMETERINVPROC) (GLenum pname, GLint value); typedef void (APIENTRYP PFNGLBLENDBARRIERNVPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendParameteriNV (GLenum pname, GLint value); GLAPI void APIENTRY glBlendBarrierNV (void); #endif #endif /* GL_NV_blend_equation_advanced */ #ifndef GL_NV_blend_equation_advanced_coherent #define GL_NV_blend_equation_advanced_coherent 1 #define GL_BLEND_ADVANCED_COHERENT_NV 0x9285 #endif /* GL_NV_blend_equation_advanced_coherent */ #ifndef GL_NV_blend_minmax_factor #define GL_NV_blend_minmax_factor 1 #endif /* GL_NV_blend_minmax_factor */ #ifndef GL_NV_blend_square #define GL_NV_blend_square 1 #endif /* GL_NV_blend_square */ #ifndef GL_NV_clip_space_w_scaling #define GL_NV_clip_space_w_scaling 1 #define GL_VIEWPORT_POSITION_W_SCALE_NV 0x937C #define GL_VIEWPORT_POSITION_W_SCALE_X_COEFF_NV 0x937D #define GL_VIEWPORT_POSITION_W_SCALE_Y_COEFF_NV 0x937E typedef void (APIENTRYP PFNGLVIEWPORTPOSITIONWSCALENVPROC) (GLuint index, GLfloat xcoeff, GLfloat ycoeff); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glViewportPositionWScaleNV (GLuint index, GLfloat xcoeff, GLfloat ycoeff); #endif #endif /* GL_NV_clip_space_w_scaling */ #ifndef GL_NV_command_list #define GL_NV_command_list 1 #define GL_TERMINATE_SEQUENCE_COMMAND_NV 0x0000 #define GL_NOP_COMMAND_NV 0x0001 #define GL_DRAW_ELEMENTS_COMMAND_NV 0x0002 #define GL_DRAW_ARRAYS_COMMAND_NV 0x0003 #define GL_DRAW_ELEMENTS_STRIP_COMMAND_NV 0x0004 #define GL_DRAW_ARRAYS_STRIP_COMMAND_NV 0x0005 #define GL_DRAW_ELEMENTS_INSTANCED_COMMAND_NV 0x0006 #define GL_DRAW_ARRAYS_INSTANCED_COMMAND_NV 0x0007 #define GL_ELEMENT_ADDRESS_COMMAND_NV 0x0008 #define GL_ATTRIBUTE_ADDRESS_COMMAND_NV 0x0009 #define GL_UNIFORM_ADDRESS_COMMAND_NV 0x000A #define GL_BLEND_COLOR_COMMAND_NV 0x000B #define GL_STENCIL_REF_COMMAND_NV 0x000C #define GL_LINE_WIDTH_COMMAND_NV 0x000D #define GL_POLYGON_OFFSET_COMMAND_NV 0x000E #define GL_ALPHA_REF_COMMAND_NV 0x000F #define GL_VIEWPORT_COMMAND_NV 0x0010 #define GL_SCISSOR_COMMAND_NV 0x0011 #define GL_FRONT_FACE_COMMAND_NV 0x0012 typedef void (APIENTRYP PFNGLCREATESTATESNVPROC) (GLsizei n, GLuint *states); typedef void (APIENTRYP PFNGLDELETESTATESNVPROC) (GLsizei n, const GLuint *states); typedef GLboolean (APIENTRYP PFNGLISSTATENVPROC) (GLuint state); typedef void (APIENTRYP PFNGLSTATECAPTURENVPROC) (GLuint state, GLenum mode); typedef GLuint (APIENTRYP PFNGLGETCOMMANDHEADERNVPROC) (GLenum tokenID, GLuint size); typedef GLushort (APIENTRYP PFNGLGETSTAGEINDEXNVPROC) (GLenum shadertype); typedef void (APIENTRYP PFNGLDRAWCOMMANDSNVPROC) (GLenum primitiveMode, GLuint buffer, const GLintptr *indirects, const GLsizei *sizes, GLuint count); typedef void (APIENTRYP PFNGLDRAWCOMMANDSADDRESSNVPROC) (GLenum primitiveMode, const GLuint64 *indirects, const GLsizei *sizes, GLuint count); typedef void (APIENTRYP PFNGLDRAWCOMMANDSSTATESNVPROC) (GLuint buffer, const GLintptr *indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count); typedef void (APIENTRYP PFNGLDRAWCOMMANDSSTATESADDRESSNVPROC) (const GLuint64 *indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count); typedef void (APIENTRYP PFNGLCREATECOMMANDLISTSNVPROC) (GLsizei n, GLuint *lists); typedef void (APIENTRYP PFNGLDELETECOMMANDLISTSNVPROC) (GLsizei n, const GLuint *lists); typedef GLboolean (APIENTRYP PFNGLISCOMMANDLISTNVPROC) (GLuint list); typedef void (APIENTRYP PFNGLLISTDRAWCOMMANDSSTATESCLIENTNVPROC) (GLuint list, GLuint segment, const void **indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count); typedef void (APIENTRYP PFNGLCOMMANDLISTSEGMENTSNVPROC) (GLuint list, GLuint segments); typedef void (APIENTRYP PFNGLCOMPILECOMMANDLISTNVPROC) (GLuint list); typedef void (APIENTRYP PFNGLCALLCOMMANDLISTNVPROC) (GLuint list); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCreateStatesNV (GLsizei n, GLuint *states); GLAPI void APIENTRY glDeleteStatesNV (GLsizei n, const GLuint *states); GLAPI GLboolean APIENTRY glIsStateNV (GLuint state); GLAPI void APIENTRY glStateCaptureNV (GLuint state, GLenum mode); GLAPI GLuint APIENTRY glGetCommandHeaderNV (GLenum tokenID, GLuint size); GLAPI GLushort APIENTRY glGetStageIndexNV (GLenum shadertype); GLAPI void APIENTRY glDrawCommandsNV (GLenum primitiveMode, GLuint buffer, const GLintptr *indirects, const GLsizei *sizes, GLuint count); GLAPI void APIENTRY glDrawCommandsAddressNV (GLenum primitiveMode, const GLuint64 *indirects, const GLsizei *sizes, GLuint count); GLAPI void APIENTRY glDrawCommandsStatesNV (GLuint buffer, const GLintptr *indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count); GLAPI void APIENTRY glDrawCommandsStatesAddressNV (const GLuint64 *indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count); GLAPI void APIENTRY glCreateCommandListsNV (GLsizei n, GLuint *lists); GLAPI void APIENTRY glDeleteCommandListsNV (GLsizei n, const GLuint *lists); GLAPI GLboolean APIENTRY glIsCommandListNV (GLuint list); GLAPI void APIENTRY glListDrawCommandsStatesClientNV (GLuint list, GLuint segment, const void **indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count); GLAPI void APIENTRY glCommandListSegmentsNV (GLuint list, GLuint segments); GLAPI void APIENTRY glCompileCommandListNV (GLuint list); GLAPI void APIENTRY glCallCommandListNV (GLuint list); #endif #endif /* GL_NV_command_list */ #ifndef GL_NV_compute_program5 #define GL_NV_compute_program5 1 #define GL_COMPUTE_PROGRAM_NV 0x90FB #define GL_COMPUTE_PROGRAM_PARAMETER_BUFFER_NV 0x90FC #endif /* GL_NV_compute_program5 */ #ifndef GL_NV_compute_shader_derivatives #define GL_NV_compute_shader_derivatives 1 #endif /* GL_NV_compute_shader_derivatives */ #ifndef GL_NV_conditional_render #define GL_NV_conditional_render 1 #define GL_QUERY_WAIT_NV 0x8E13 #define GL_QUERY_NO_WAIT_NV 0x8E14 #define GL_QUERY_BY_REGION_WAIT_NV 0x8E15 #define GL_QUERY_BY_REGION_NO_WAIT_NV 0x8E16 typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERNVPROC) (GLuint id, GLenum mode); typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERNVPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBeginConditionalRenderNV (GLuint id, GLenum mode); GLAPI void APIENTRY glEndConditionalRenderNV (void); #endif #endif /* GL_NV_conditional_render */ #ifndef GL_NV_conservative_raster #define GL_NV_conservative_raster 1 #define GL_CONSERVATIVE_RASTERIZATION_NV 0x9346 #define GL_SUBPIXEL_PRECISION_BIAS_X_BITS_NV 0x9347 #define GL_SUBPIXEL_PRECISION_BIAS_Y_BITS_NV 0x9348 #define GL_MAX_SUBPIXEL_PRECISION_BIAS_BITS_NV 0x9349 typedef void (APIENTRYP PFNGLSUBPIXELPRECISIONBIASNVPROC) (GLuint xbits, GLuint ybits); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSubpixelPrecisionBiasNV (GLuint xbits, GLuint ybits); #endif #endif /* GL_NV_conservative_raster */ #ifndef GL_NV_conservative_raster_dilate #define GL_NV_conservative_raster_dilate 1 #define GL_CONSERVATIVE_RASTER_DILATE_NV 0x9379 #define GL_CONSERVATIVE_RASTER_DILATE_RANGE_NV 0x937A #define GL_CONSERVATIVE_RASTER_DILATE_GRANULARITY_NV 0x937B typedef void (APIENTRYP PFNGLCONSERVATIVERASTERPARAMETERFNVPROC) (GLenum pname, GLfloat value); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glConservativeRasterParameterfNV (GLenum pname, GLfloat value); #endif #endif /* GL_NV_conservative_raster_dilate */ #ifndef GL_NV_conservative_raster_pre_snap #define GL_NV_conservative_raster_pre_snap 1 #define GL_CONSERVATIVE_RASTER_MODE_PRE_SNAP_NV 0x9550 #endif /* GL_NV_conservative_raster_pre_snap */ #ifndef GL_NV_conservative_raster_pre_snap_triangles #define GL_NV_conservative_raster_pre_snap_triangles 1 #define GL_CONSERVATIVE_RASTER_MODE_NV 0x954D #define GL_CONSERVATIVE_RASTER_MODE_POST_SNAP_NV 0x954E #define GL_CONSERVATIVE_RASTER_MODE_PRE_SNAP_TRIANGLES_NV 0x954F typedef void (APIENTRYP PFNGLCONSERVATIVERASTERPARAMETERINVPROC) (GLenum pname, GLint param); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glConservativeRasterParameteriNV (GLenum pname, GLint param); #endif #endif /* GL_NV_conservative_raster_pre_snap_triangles */ #ifndef GL_NV_conservative_raster_underestimation #define GL_NV_conservative_raster_underestimation 1 #endif /* GL_NV_conservative_raster_underestimation */ #ifndef GL_NV_copy_depth_to_color #define GL_NV_copy_depth_to_color 1 #define GL_DEPTH_STENCIL_TO_RGBA_NV 0x886E #define GL_DEPTH_STENCIL_TO_BGRA_NV 0x886F #endif /* GL_NV_copy_depth_to_color */ #ifndef GL_NV_copy_image #define GL_NV_copy_image 1 typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATANVPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCopyImageSubDataNV (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); #endif #endif /* GL_NV_copy_image */ #ifndef GL_NV_deep_texture3D #define GL_NV_deep_texture3D 1 #define GL_MAX_DEEP_3D_TEXTURE_WIDTH_HEIGHT_NV 0x90D0 #define GL_MAX_DEEP_3D_TEXTURE_DEPTH_NV 0x90D1 #endif /* GL_NV_deep_texture3D */ #ifndef GL_NV_depth_buffer_float #define GL_NV_depth_buffer_float 1 #define GL_DEPTH_COMPONENT32F_NV 0x8DAB #define GL_DEPTH32F_STENCIL8_NV 0x8DAC #define GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV 0x8DAD #define GL_DEPTH_BUFFER_FLOAT_MODE_NV 0x8DAF typedef void (APIENTRYP PFNGLDEPTHRANGEDNVPROC) (GLdouble zNear, GLdouble zFar); typedef void (APIENTRYP PFNGLCLEARDEPTHDNVPROC) (GLdouble depth); typedef void (APIENTRYP PFNGLDEPTHBOUNDSDNVPROC) (GLdouble zmin, GLdouble zmax); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDepthRangedNV (GLdouble zNear, GLdouble zFar); GLAPI void APIENTRY glClearDepthdNV (GLdouble depth); GLAPI void APIENTRY glDepthBoundsdNV (GLdouble zmin, GLdouble zmax); #endif #endif /* GL_NV_depth_buffer_float */ #ifndef GL_NV_depth_clamp #define GL_NV_depth_clamp 1 #define GL_DEPTH_CLAMP_NV 0x864F #endif /* GL_NV_depth_clamp */ #ifndef GL_NV_draw_texture #define GL_NV_draw_texture 1 typedef void (APIENTRYP PFNGLDRAWTEXTURENVPROC) (GLuint texture, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawTextureNV (GLuint texture, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1); #endif #endif /* GL_NV_draw_texture */ #ifndef GL_NV_draw_vulkan_image #define GL_NV_draw_vulkan_image 1 typedef void (APIENTRY *GLVULKANPROCNV)(void); typedef void (APIENTRYP PFNGLDRAWVKIMAGENVPROC) (GLuint64 vkImage, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1); typedef GLVULKANPROCNV (APIENTRYP PFNGLGETVKPROCADDRNVPROC) (const GLchar *name); typedef void (APIENTRYP PFNGLWAITVKSEMAPHORENVPROC) (GLuint64 vkSemaphore); typedef void (APIENTRYP PFNGLSIGNALVKSEMAPHORENVPROC) (GLuint64 vkSemaphore); typedef void (APIENTRYP PFNGLSIGNALVKFENCENVPROC) (GLuint64 vkFence); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawVkImageNV (GLuint64 vkImage, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1); GLAPI GLVULKANPROCNV APIENTRY glGetVkProcAddrNV (const GLchar *name); GLAPI void APIENTRY glWaitVkSemaphoreNV (GLuint64 vkSemaphore); GLAPI void APIENTRY glSignalVkSemaphoreNV (GLuint64 vkSemaphore); GLAPI void APIENTRY glSignalVkFenceNV (GLuint64 vkFence); #endif #endif /* GL_NV_draw_vulkan_image */ #ifndef GL_NV_evaluators #define GL_NV_evaluators 1 #define GL_EVAL_2D_NV 0x86C0 #define GL_EVAL_TRIANGULAR_2D_NV 0x86C1 #define GL_MAP_TESSELLATION_NV 0x86C2 #define GL_MAP_ATTRIB_U_ORDER_NV 0x86C3 #define GL_MAP_ATTRIB_V_ORDER_NV 0x86C4 #define GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5 #define GL_EVAL_VERTEX_ATTRIB0_NV 0x86C6 #define GL_EVAL_VERTEX_ATTRIB1_NV 0x86C7 #define GL_EVAL_VERTEX_ATTRIB2_NV 0x86C8 #define GL_EVAL_VERTEX_ATTRIB3_NV 0x86C9 #define GL_EVAL_VERTEX_ATTRIB4_NV 0x86CA #define GL_EVAL_VERTEX_ATTRIB5_NV 0x86CB #define GL_EVAL_VERTEX_ATTRIB6_NV 0x86CC #define GL_EVAL_VERTEX_ATTRIB7_NV 0x86CD #define GL_EVAL_VERTEX_ATTRIB8_NV 0x86CE #define GL_EVAL_VERTEX_ATTRIB9_NV 0x86CF #define GL_EVAL_VERTEX_ATTRIB10_NV 0x86D0 #define GL_EVAL_VERTEX_ATTRIB11_NV 0x86D1 #define GL_EVAL_VERTEX_ATTRIB12_NV 0x86D2 #define GL_EVAL_VERTEX_ATTRIB13_NV 0x86D3 #define GL_EVAL_VERTEX_ATTRIB14_NV 0x86D4 #define GL_EVAL_VERTEX_ATTRIB15_NV 0x86D5 #define GL_MAX_MAP_TESSELLATION_NV 0x86D6 #define GL_MAX_RATIONAL_EVAL_ORDER_NV 0x86D7 typedef void (APIENTRYP PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const void *points); typedef void (APIENTRYP PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, void *points); typedef void (APIENTRYP PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const void *points); GLAPI void APIENTRY glMapParameterivNV (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glMapParameterfvNV (GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glGetMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, void *points); GLAPI void APIENTRY glGetMapParameterivNV (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetMapParameterfvNV (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetMapAttribParameterivNV (GLenum target, GLuint index, GLenum pname, GLint *params); GLAPI void APIENTRY glGetMapAttribParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params); GLAPI void APIENTRY glEvalMapsNV (GLenum target, GLenum mode); #endif #endif /* GL_NV_evaluators */ #ifndef GL_NV_explicit_multisample #define GL_NV_explicit_multisample 1 #define GL_SAMPLE_POSITION_NV 0x8E50 #define GL_SAMPLE_MASK_NV 0x8E51 #define GL_SAMPLE_MASK_VALUE_NV 0x8E52 #define GL_TEXTURE_BINDING_RENDERBUFFER_NV 0x8E53 #define GL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV 0x8E54 #define GL_TEXTURE_RENDERBUFFER_NV 0x8E55 #define GL_SAMPLER_RENDERBUFFER_NV 0x8E56 #define GL_INT_SAMPLER_RENDERBUFFER_NV 0x8E57 #define GL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV 0x8E58 #define GL_MAX_SAMPLE_MASK_WORDS_NV 0x8E59 typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVNVPROC) (GLenum pname, GLuint index, GLfloat *val); typedef void (APIENTRYP PFNGLSAMPLEMASKINDEXEDNVPROC) (GLuint index, GLbitfield mask); typedef void (APIENTRYP PFNGLTEXRENDERBUFFERNVPROC) (GLenum target, GLuint renderbuffer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetMultisamplefvNV (GLenum pname, GLuint index, GLfloat *val); GLAPI void APIENTRY glSampleMaskIndexedNV (GLuint index, GLbitfield mask); GLAPI void APIENTRY glTexRenderbufferNV (GLenum target, GLuint renderbuffer); #endif #endif /* GL_NV_explicit_multisample */ #ifndef GL_NV_fence #define GL_NV_fence 1 #define GL_ALL_COMPLETED_NV 0x84F2 #define GL_FENCE_STATUS_NV 0x84F3 #define GL_FENCE_CONDITION_NV 0x84F4 typedef void (APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences); typedef void (APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences); typedef GLboolean (APIENTRYP PFNGLISFENCENVPROC) (GLuint fence); typedef GLboolean (APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence); typedef void (APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence); typedef void (APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDeleteFencesNV (GLsizei n, const GLuint *fences); GLAPI void APIENTRY glGenFencesNV (GLsizei n, GLuint *fences); GLAPI GLboolean APIENTRY glIsFenceNV (GLuint fence); GLAPI GLboolean APIENTRY glTestFenceNV (GLuint fence); GLAPI void APIENTRY glGetFenceivNV (GLuint fence, GLenum pname, GLint *params); GLAPI void APIENTRY glFinishFenceNV (GLuint fence); GLAPI void APIENTRY glSetFenceNV (GLuint fence, GLenum condition); #endif #endif /* GL_NV_fence */ #ifndef GL_NV_fill_rectangle #define GL_NV_fill_rectangle 1 #define GL_FILL_RECTANGLE_NV 0x933C #endif /* GL_NV_fill_rectangle */ #ifndef GL_NV_float_buffer #define GL_NV_float_buffer 1 #define GL_FLOAT_R_NV 0x8880 #define GL_FLOAT_RG_NV 0x8881 #define GL_FLOAT_RGB_NV 0x8882 #define GL_FLOAT_RGBA_NV 0x8883 #define GL_FLOAT_R16_NV 0x8884 #define GL_FLOAT_R32_NV 0x8885 #define GL_FLOAT_RG16_NV 0x8886 #define GL_FLOAT_RG32_NV 0x8887 #define GL_FLOAT_RGB16_NV 0x8888 #define GL_FLOAT_RGB32_NV 0x8889 #define GL_FLOAT_RGBA16_NV 0x888A #define GL_FLOAT_RGBA32_NV 0x888B #define GL_TEXTURE_FLOAT_COMPONENTS_NV 0x888C #define GL_FLOAT_CLEAR_COLOR_VALUE_NV 0x888D #define GL_FLOAT_RGBA_MODE_NV 0x888E #endif /* GL_NV_float_buffer */ #ifndef GL_NV_fog_distance #define GL_NV_fog_distance 1 #define GL_FOG_DISTANCE_MODE_NV 0x855A #define GL_EYE_RADIAL_NV 0x855B #define GL_EYE_PLANE_ABSOLUTE_NV 0x855C #endif /* GL_NV_fog_distance */ #ifndef GL_NV_fragment_coverage_to_color #define GL_NV_fragment_coverage_to_color 1 #define GL_FRAGMENT_COVERAGE_TO_COLOR_NV 0x92DD #define GL_FRAGMENT_COVERAGE_COLOR_NV 0x92DE typedef void (APIENTRYP PFNGLFRAGMENTCOVERAGECOLORNVPROC) (GLuint color); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFragmentCoverageColorNV (GLuint color); #endif #endif /* GL_NV_fragment_coverage_to_color */ #ifndef GL_NV_fragment_program #define GL_NV_fragment_program 1 #define GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868 #define GL_FRAGMENT_PROGRAM_NV 0x8870 #define GL_MAX_TEXTURE_COORDS_NV 0x8871 #define GL_MAX_TEXTURE_IMAGE_UNITS_NV 0x8872 #define GL_FRAGMENT_PROGRAM_BINDING_NV 0x8873 #define GL_PROGRAM_ERROR_STRING_NV 0x8874 typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramNamedParameter4fNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glProgramNamedParameter4fvNV (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); GLAPI void APIENTRY glProgramNamedParameter4dNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glProgramNamedParameter4dvNV (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); GLAPI void APIENTRY glGetProgramNamedParameterfvNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); GLAPI void APIENTRY glGetProgramNamedParameterdvNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); #endif #endif /* GL_NV_fragment_program */ #ifndef GL_NV_fragment_program2 #define GL_NV_fragment_program2 1 #define GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4 #define GL_MAX_PROGRAM_CALL_DEPTH_NV 0x88F5 #define GL_MAX_PROGRAM_IF_DEPTH_NV 0x88F6 #define GL_MAX_PROGRAM_LOOP_DEPTH_NV 0x88F7 #define GL_MAX_PROGRAM_LOOP_COUNT_NV 0x88F8 #endif /* GL_NV_fragment_program2 */ #ifndef GL_NV_fragment_program4 #define GL_NV_fragment_program4 1 #endif /* GL_NV_fragment_program4 */ #ifndef GL_NV_fragment_program_option #define GL_NV_fragment_program_option 1 #endif /* GL_NV_fragment_program_option */ #ifndef GL_NV_fragment_shader_barycentric #define GL_NV_fragment_shader_barycentric 1 #endif /* GL_NV_fragment_shader_barycentric */ #ifndef GL_NV_fragment_shader_interlock #define GL_NV_fragment_shader_interlock 1 #endif /* GL_NV_fragment_shader_interlock */ #ifndef GL_NV_framebuffer_mixed_samples #define GL_NV_framebuffer_mixed_samples 1 #define GL_COVERAGE_MODULATION_TABLE_NV 0x9331 #define GL_COLOR_SAMPLES_NV 0x8E20 #define GL_DEPTH_SAMPLES_NV 0x932D #define GL_STENCIL_SAMPLES_NV 0x932E #define GL_MIXED_DEPTH_SAMPLES_SUPPORTED_NV 0x932F #define GL_MIXED_STENCIL_SAMPLES_SUPPORTED_NV 0x9330 #define GL_COVERAGE_MODULATION_NV 0x9332 #define GL_COVERAGE_MODULATION_TABLE_SIZE_NV 0x9333 typedef void (APIENTRYP PFNGLCOVERAGEMODULATIONTABLENVPROC) (GLsizei n, const GLfloat *v); typedef void (APIENTRYP PFNGLGETCOVERAGEMODULATIONTABLENVPROC) (GLsizei bufSize, GLfloat *v); typedef void (APIENTRYP PFNGLCOVERAGEMODULATIONNVPROC) (GLenum components); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCoverageModulationTableNV (GLsizei n, const GLfloat *v); GLAPI void APIENTRY glGetCoverageModulationTableNV (GLsizei bufSize, GLfloat *v); GLAPI void APIENTRY glCoverageModulationNV (GLenum components); #endif #endif /* GL_NV_framebuffer_mixed_samples */ #ifndef GL_NV_framebuffer_multisample_coverage #define GL_NV_framebuffer_multisample_coverage 1 #define GL_RENDERBUFFER_COVERAGE_SAMPLES_NV 0x8CAB #define GL_RENDERBUFFER_COLOR_SAMPLES_NV 0x8E10 #define GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV 0x8E11 #define GL_MULTISAMPLE_COVERAGE_MODES_NV 0x8E12 typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glRenderbufferStorageMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); #endif #endif /* GL_NV_framebuffer_multisample_coverage */ #ifndef GL_NV_geometry_program4 #define GL_NV_geometry_program4 1 #define GL_GEOMETRY_PROGRAM_NV 0x8C26 #define GL_MAX_PROGRAM_OUTPUT_VERTICES_NV 0x8C27 #define GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV 0x8C28 typedef void (APIENTRYP PFNGLPROGRAMVERTEXLIMITNVPROC) (GLenum target, GLint limit); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramVertexLimitNV (GLenum target, GLint limit); GLAPI void APIENTRY glFramebufferTextureEXT (GLenum target, GLenum attachment, GLuint texture, GLint level); GLAPI void APIENTRY glFramebufferTextureFaceEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); #endif #endif /* GL_NV_geometry_program4 */ #ifndef GL_NV_geometry_shader4 #define GL_NV_geometry_shader4 1 #endif /* GL_NV_geometry_shader4 */ #ifndef GL_NV_geometry_shader_passthrough #define GL_NV_geometry_shader_passthrough 1 #endif /* GL_NV_geometry_shader_passthrough */ #ifndef GL_NV_gpu_multicast #define GL_NV_gpu_multicast 1 #define GL_PER_GPU_STORAGE_BIT_NV 0x0800 #define GL_MULTICAST_GPUS_NV 0x92BA #define GL_RENDER_GPU_MASK_NV 0x9558 #define GL_PER_GPU_STORAGE_NV 0x9548 #define GL_MULTICAST_PROGRAMMABLE_SAMPLE_LOCATION_NV 0x9549 typedef void (APIENTRYP PFNGLRENDERGPUMASKNVPROC) (GLbitfield mask); typedef void (APIENTRYP PFNGLMULTICASTBUFFERSUBDATANVPROC) (GLbitfield gpuMask, GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); typedef void (APIENTRYP PFNGLMULTICASTCOPYBUFFERSUBDATANVPROC) (GLuint readGpu, GLbitfield writeGpuMask, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); typedef void (APIENTRYP PFNGLMULTICASTCOPYIMAGESUBDATANVPROC) (GLuint srcGpu, GLbitfield dstGpuMask, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); typedef void (APIENTRYP PFNGLMULTICASTBLITFRAMEBUFFERNVPROC) (GLuint srcGpu, GLuint dstGpu, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); typedef void (APIENTRYP PFNGLMULTICASTFRAMEBUFFERSAMPLELOCATIONSFVNVPROC) (GLuint gpu, GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTICASTBARRIERNVPROC) (void); typedef void (APIENTRYP PFNGLMULTICASTWAITSYNCNVPROC) (GLuint signalGpu, GLbitfield waitGpuMask); typedef void (APIENTRYP PFNGLMULTICASTGETQUERYOBJECTIVNVPROC) (GLuint gpu, GLuint id, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLMULTICASTGETQUERYOBJECTUIVNVPROC) (GLuint gpu, GLuint id, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLMULTICASTGETQUERYOBJECTI64VNVPROC) (GLuint gpu, GLuint id, GLenum pname, GLint64 *params); typedef void (APIENTRYP PFNGLMULTICASTGETQUERYOBJECTUI64VNVPROC) (GLuint gpu, GLuint id, GLenum pname, GLuint64 *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glRenderGpuMaskNV (GLbitfield mask); GLAPI void APIENTRY glMulticastBufferSubDataNV (GLbitfield gpuMask, GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); GLAPI void APIENTRY glMulticastCopyBufferSubDataNV (GLuint readGpu, GLbitfield writeGpuMask, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); GLAPI void APIENTRY glMulticastCopyImageSubDataNV (GLuint srcGpu, GLbitfield dstGpuMask, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); GLAPI void APIENTRY glMulticastBlitFramebufferNV (GLuint srcGpu, GLuint dstGpu, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); GLAPI void APIENTRY glMulticastFramebufferSampleLocationsfvNV (GLuint gpu, GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v); GLAPI void APIENTRY glMulticastBarrierNV (void); GLAPI void APIENTRY glMulticastWaitSyncNV (GLuint signalGpu, GLbitfield waitGpuMask); GLAPI void APIENTRY glMulticastGetQueryObjectivNV (GLuint gpu, GLuint id, GLenum pname, GLint *params); GLAPI void APIENTRY glMulticastGetQueryObjectuivNV (GLuint gpu, GLuint id, GLenum pname, GLuint *params); GLAPI void APIENTRY glMulticastGetQueryObjecti64vNV (GLuint gpu, GLuint id, GLenum pname, GLint64 *params); GLAPI void APIENTRY glMulticastGetQueryObjectui64vNV (GLuint gpu, GLuint id, GLenum pname, GLuint64 *params); #endif #endif /* GL_NV_gpu_multicast */ #ifndef GL_NV_gpu_program4 #define GL_NV_gpu_program4 1 #define GL_MIN_PROGRAM_TEXEL_OFFSET_NV 0x8904 #define GL_MAX_PROGRAM_TEXEL_OFFSET_NV 0x8905 #define GL_PROGRAM_ATTRIB_COMPONENTS_NV 0x8906 #define GL_PROGRAM_RESULT_COMPONENTS_NV 0x8907 #define GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV 0x8908 #define GL_MAX_PROGRAM_RESULT_COMPONENTS_NV 0x8909 #define GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV 0x8DA5 #define GL_MAX_PROGRAM_GENERIC_RESULTS_NV 0x8DA6 typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params); typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params); typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params); typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params); typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramLocalParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); GLAPI void APIENTRY glProgramLocalParameterI4ivNV (GLenum target, GLuint index, const GLint *params); GLAPI void APIENTRY glProgramLocalParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params); GLAPI void APIENTRY glProgramLocalParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); GLAPI void APIENTRY glProgramLocalParameterI4uivNV (GLenum target, GLuint index, const GLuint *params); GLAPI void APIENTRY glProgramLocalParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params); GLAPI void APIENTRY glProgramEnvParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); GLAPI void APIENTRY glProgramEnvParameterI4ivNV (GLenum target, GLuint index, const GLint *params); GLAPI void APIENTRY glProgramEnvParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params); GLAPI void APIENTRY glProgramEnvParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); GLAPI void APIENTRY glProgramEnvParameterI4uivNV (GLenum target, GLuint index, const GLuint *params); GLAPI void APIENTRY glProgramEnvParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params); GLAPI void APIENTRY glGetProgramLocalParameterIivNV (GLenum target, GLuint index, GLint *params); GLAPI void APIENTRY glGetProgramLocalParameterIuivNV (GLenum target, GLuint index, GLuint *params); GLAPI void APIENTRY glGetProgramEnvParameterIivNV (GLenum target, GLuint index, GLint *params); GLAPI void APIENTRY glGetProgramEnvParameterIuivNV (GLenum target, GLuint index, GLuint *params); #endif #endif /* GL_NV_gpu_program4 */ #ifndef GL_NV_gpu_program5 #define GL_NV_gpu_program5 1 #define GL_MAX_GEOMETRY_PROGRAM_INVOCATIONS_NV 0x8E5A #define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5B #define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5C #define GL_FRAGMENT_PROGRAM_INTERPOLATION_OFFSET_BITS_NV 0x8E5D #define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5E #define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5F #define GL_MAX_PROGRAM_SUBROUTINE_PARAMETERS_NV 0x8F44 #define GL_MAX_PROGRAM_SUBROUTINE_NUM_NV 0x8F45 typedef void (APIENTRYP PFNGLPROGRAMSUBROUTINEPARAMETERSUIVNVPROC) (GLenum target, GLsizei count, const GLuint *params); typedef void (APIENTRYP PFNGLGETPROGRAMSUBROUTINEPARAMETERUIVNVPROC) (GLenum target, GLuint index, GLuint *param); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramSubroutineParametersuivNV (GLenum target, GLsizei count, const GLuint *params); GLAPI void APIENTRY glGetProgramSubroutineParameteruivNV (GLenum target, GLuint index, GLuint *param); #endif #endif /* GL_NV_gpu_program5 */ #ifndef GL_NV_gpu_program5_mem_extended #define GL_NV_gpu_program5_mem_extended 1 #endif /* GL_NV_gpu_program5_mem_extended */ #ifndef GL_NV_gpu_shader5 #define GL_NV_gpu_shader5 1 #endif /* GL_NV_gpu_shader5 */ #ifndef GL_NV_half_float #define GL_NV_half_float 1 typedef unsigned short GLhalfNV; #define GL_HALF_FLOAT_NV 0x140B typedef void (APIENTRYP PFNGLVERTEX2HNVPROC) (GLhalfNV x, GLhalfNV y); typedef void (APIENTRYP PFNGLVERTEX2HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEX3HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z); typedef void (APIENTRYP PFNGLVERTEX3HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEX4HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); typedef void (APIENTRYP PFNGLVERTEX4HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLNORMAL3HNVPROC) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); typedef void (APIENTRYP PFNGLNORMAL3HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); typedef void (APIENTRYP PFNGLCOLOR3HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLCOLOR4HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); typedef void (APIENTRYP PFNGLCOLOR4HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLTEXCOORD1HNVPROC) (GLhalfNV s); typedef void (APIENTRYP PFNGLTEXCOORD1HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLTEXCOORD2HNVPROC) (GLhalfNV s, GLhalfNV t); typedef void (APIENTRYP PFNGLTEXCOORD2HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLTEXCOORD3HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r); typedef void (APIENTRYP PFNGLTEXCOORD3HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLTEXCOORD4HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); typedef void (APIENTRYP PFNGLTEXCOORD4HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1HNVPROC) (GLenum target, GLhalfNV s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1HVNVPROC) (GLenum target, const GLhalfNV *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2HVNVPROC) (GLenum target, const GLhalfNV *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3HVNVPROC) (GLenum target, const GLhalfNV *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4HVNVPROC) (GLenum target, const GLhalfNV *v); typedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog); typedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight); typedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight); typedef void (APIENTRYP PFNGLVERTEXATTRIB1HNVPROC) (GLuint index, GLhalfNV x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1HVNVPROC) (GLuint index, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2HVNVPROC) (GLuint index, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3HVNVPROC) (GLuint index, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4HVNVPROC) (GLuint index, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS1HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS2HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS3HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS4HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertex2hNV (GLhalfNV x, GLhalfNV y); GLAPI void APIENTRY glVertex2hvNV (const GLhalfNV *v); GLAPI void APIENTRY glVertex3hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z); GLAPI void APIENTRY glVertex3hvNV (const GLhalfNV *v); GLAPI void APIENTRY glVertex4hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); GLAPI void APIENTRY glVertex4hvNV (const GLhalfNV *v); GLAPI void APIENTRY glNormal3hNV (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); GLAPI void APIENTRY glNormal3hvNV (const GLhalfNV *v); GLAPI void APIENTRY glColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue); GLAPI void APIENTRY glColor3hvNV (const GLhalfNV *v); GLAPI void APIENTRY glColor4hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); GLAPI void APIENTRY glColor4hvNV (const GLhalfNV *v); GLAPI void APIENTRY glTexCoord1hNV (GLhalfNV s); GLAPI void APIENTRY glTexCoord1hvNV (const GLhalfNV *v); GLAPI void APIENTRY glTexCoord2hNV (GLhalfNV s, GLhalfNV t); GLAPI void APIENTRY glTexCoord2hvNV (const GLhalfNV *v); GLAPI void APIENTRY glTexCoord3hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r); GLAPI void APIENTRY glTexCoord3hvNV (const GLhalfNV *v); GLAPI void APIENTRY glTexCoord4hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); GLAPI void APIENTRY glTexCoord4hvNV (const GLhalfNV *v); GLAPI void APIENTRY glMultiTexCoord1hNV (GLenum target, GLhalfNV s); GLAPI void APIENTRY glMultiTexCoord1hvNV (GLenum target, const GLhalfNV *v); GLAPI void APIENTRY glMultiTexCoord2hNV (GLenum target, GLhalfNV s, GLhalfNV t); GLAPI void APIENTRY glMultiTexCoord2hvNV (GLenum target, const GLhalfNV *v); GLAPI void APIENTRY glMultiTexCoord3hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); GLAPI void APIENTRY glMultiTexCoord3hvNV (GLenum target, const GLhalfNV *v); GLAPI void APIENTRY glMultiTexCoord4hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); GLAPI void APIENTRY glMultiTexCoord4hvNV (GLenum target, const GLhalfNV *v); GLAPI void APIENTRY glFogCoordhNV (GLhalfNV fog); GLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *fog); GLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue); GLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *v); GLAPI void APIENTRY glVertexWeighthNV (GLhalfNV weight); GLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *weight); GLAPI void APIENTRY glVertexAttrib1hNV (GLuint index, GLhalfNV x); GLAPI void APIENTRY glVertexAttrib1hvNV (GLuint index, const GLhalfNV *v); GLAPI void APIENTRY glVertexAttrib2hNV (GLuint index, GLhalfNV x, GLhalfNV y); GLAPI void APIENTRY glVertexAttrib2hvNV (GLuint index, const GLhalfNV *v); GLAPI void APIENTRY glVertexAttrib3hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); GLAPI void APIENTRY glVertexAttrib3hvNV (GLuint index, const GLhalfNV *v); GLAPI void APIENTRY glVertexAttrib4hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); GLAPI void APIENTRY glVertexAttrib4hvNV (GLuint index, const GLhalfNV *v); GLAPI void APIENTRY glVertexAttribs1hvNV (GLuint index, GLsizei n, const GLhalfNV *v); GLAPI void APIENTRY glVertexAttribs2hvNV (GLuint index, GLsizei n, const GLhalfNV *v); GLAPI void APIENTRY glVertexAttribs3hvNV (GLuint index, GLsizei n, const GLhalfNV *v); GLAPI void APIENTRY glVertexAttribs4hvNV (GLuint index, GLsizei n, const GLhalfNV *v); #endif #endif /* GL_NV_half_float */ #ifndef GL_NV_internalformat_sample_query #define GL_NV_internalformat_sample_query 1 #define GL_MULTISAMPLES_NV 0x9371 #define GL_SUPERSAMPLE_SCALE_X_NV 0x9372 #define GL_SUPERSAMPLE_SCALE_Y_NV 0x9373 #define GL_CONFORMANT_NV 0x9374 typedef void (APIENTRYP PFNGLGETINTERNALFORMATSAMPLEIVNVPROC) (GLenum target, GLenum internalformat, GLsizei samples, GLenum pname, GLsizei count, GLint *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetInternalformatSampleivNV (GLenum target, GLenum internalformat, GLsizei samples, GLenum pname, GLsizei count, GLint *params); #endif #endif /* GL_NV_internalformat_sample_query */ #ifndef GL_NV_light_max_exponent #define GL_NV_light_max_exponent 1 #define GL_MAX_SHININESS_NV 0x8504 #define GL_MAX_SPOT_EXPONENT_NV 0x8505 #endif /* GL_NV_light_max_exponent */ #ifndef GL_NV_memory_attachment #define GL_NV_memory_attachment 1 #define GL_ATTACHED_MEMORY_OBJECT_NV 0x95A4 #define GL_ATTACHED_MEMORY_OFFSET_NV 0x95A5 #define GL_MEMORY_ATTACHABLE_ALIGNMENT_NV 0x95A6 #define GL_MEMORY_ATTACHABLE_SIZE_NV 0x95A7 #define GL_MEMORY_ATTACHABLE_NV 0x95A8 #define GL_DETACHED_MEMORY_INCARNATION_NV 0x95A9 #define GL_DETACHED_TEXTURES_NV 0x95AA #define GL_DETACHED_BUFFERS_NV 0x95AB #define GL_MAX_DETACHED_TEXTURES_NV 0x95AC #define GL_MAX_DETACHED_BUFFERS_NV 0x95AD typedef void (APIENTRYP PFNGLGETMEMORYOBJECTDETACHEDRESOURCESUIVNVPROC) (GLuint memory, GLenum pname, GLint first, GLsizei count, GLuint *params); typedef void (APIENTRYP PFNGLRESETMEMORYOBJECTPARAMETERNVPROC) (GLuint memory, GLenum pname); typedef void (APIENTRYP PFNGLTEXATTACHMEMORYNVPROC) (GLenum target, GLuint memory, GLuint64 offset); typedef void (APIENTRYP PFNGLBUFFERATTACHMEMORYNVPROC) (GLenum target, GLuint memory, GLuint64 offset); typedef void (APIENTRYP PFNGLTEXTUREATTACHMEMORYNVPROC) (GLuint texture, GLuint memory, GLuint64 offset); typedef void (APIENTRYP PFNGLNAMEDBUFFERATTACHMEMORYNVPROC) (GLuint buffer, GLuint memory, GLuint64 offset); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetMemoryObjectDetachedResourcesuivNV (GLuint memory, GLenum pname, GLint first, GLsizei count, GLuint *params); GLAPI void APIENTRY glResetMemoryObjectParameterNV (GLuint memory, GLenum pname); GLAPI void APIENTRY glTexAttachMemoryNV (GLenum target, GLuint memory, GLuint64 offset); GLAPI void APIENTRY glBufferAttachMemoryNV (GLenum target, GLuint memory, GLuint64 offset); GLAPI void APIENTRY glTextureAttachMemoryNV (GLuint texture, GLuint memory, GLuint64 offset); GLAPI void APIENTRY glNamedBufferAttachMemoryNV (GLuint buffer, GLuint memory, GLuint64 offset); #endif #endif /* GL_NV_memory_attachment */ #ifndef GL_NV_memory_object_sparse #define GL_NV_memory_object_sparse 1 typedef void (APIENTRYP PFNGLBUFFERPAGECOMMITMENTMEMNVPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLuint memory, GLuint64 memOffset, GLboolean commit); typedef void (APIENTRYP PFNGLTEXPAGECOMMITMENTMEMNVPROC) (GLenum target, GLint layer, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset, GLboolean commit); typedef void (APIENTRYP PFNGLNAMEDBUFFERPAGECOMMITMENTMEMNVPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLuint memory, GLuint64 memOffset, GLboolean commit); typedef void (APIENTRYP PFNGLTEXTUREPAGECOMMITMENTMEMNVPROC) (GLuint texture, GLint layer, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset, GLboolean commit); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBufferPageCommitmentMemNV (GLenum target, GLintptr offset, GLsizeiptr size, GLuint memory, GLuint64 memOffset, GLboolean commit); GLAPI void APIENTRY glTexPageCommitmentMemNV (GLenum target, GLint layer, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset, GLboolean commit); GLAPI void APIENTRY glNamedBufferPageCommitmentMemNV (GLuint buffer, GLintptr offset, GLsizeiptr size, GLuint memory, GLuint64 memOffset, GLboolean commit); GLAPI void APIENTRY glTexturePageCommitmentMemNV (GLuint texture, GLint layer, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset, GLboolean commit); #endif #endif /* GL_NV_memory_object_sparse */ #ifndef GL_NV_mesh_shader #define GL_NV_mesh_shader 1 #define GL_MESH_SHADER_NV 0x9559 #define GL_TASK_SHADER_NV 0x955A #define GL_MAX_MESH_UNIFORM_BLOCKS_NV 0x8E60 #define GL_MAX_MESH_TEXTURE_IMAGE_UNITS_NV 0x8E61 #define GL_MAX_MESH_IMAGE_UNIFORMS_NV 0x8E62 #define GL_MAX_MESH_UNIFORM_COMPONENTS_NV 0x8E63 #define GL_MAX_MESH_ATOMIC_COUNTER_BUFFERS_NV 0x8E64 #define GL_MAX_MESH_ATOMIC_COUNTERS_NV 0x8E65 #define GL_MAX_MESH_SHADER_STORAGE_BLOCKS_NV 0x8E66 #define GL_MAX_COMBINED_MESH_UNIFORM_COMPONENTS_NV 0x8E67 #define GL_MAX_TASK_UNIFORM_BLOCKS_NV 0x8E68 #define GL_MAX_TASK_TEXTURE_IMAGE_UNITS_NV 0x8E69 #define GL_MAX_TASK_IMAGE_UNIFORMS_NV 0x8E6A #define GL_MAX_TASK_UNIFORM_COMPONENTS_NV 0x8E6B #define GL_MAX_TASK_ATOMIC_COUNTER_BUFFERS_NV 0x8E6C #define GL_MAX_TASK_ATOMIC_COUNTERS_NV 0x8E6D #define GL_MAX_TASK_SHADER_STORAGE_BLOCKS_NV 0x8E6E #define GL_MAX_COMBINED_TASK_UNIFORM_COMPONENTS_NV 0x8E6F #define GL_MAX_MESH_WORK_GROUP_INVOCATIONS_NV 0x95A2 #define GL_MAX_TASK_WORK_GROUP_INVOCATIONS_NV 0x95A3 #define GL_MAX_MESH_TOTAL_MEMORY_SIZE_NV 0x9536 #define GL_MAX_TASK_TOTAL_MEMORY_SIZE_NV 0x9537 #define GL_MAX_MESH_OUTPUT_VERTICES_NV 0x9538 #define GL_MAX_MESH_OUTPUT_PRIMITIVES_NV 0x9539 #define GL_MAX_TASK_OUTPUT_COUNT_NV 0x953A #define GL_MAX_DRAW_MESH_TASKS_COUNT_NV 0x953D #define GL_MAX_MESH_VIEWS_NV 0x9557 #define GL_MESH_OUTPUT_PER_VERTEX_GRANULARITY_NV 0x92DF #define GL_MESH_OUTPUT_PER_PRIMITIVE_GRANULARITY_NV 0x9543 #define GL_MAX_MESH_WORK_GROUP_SIZE_NV 0x953B #define GL_MAX_TASK_WORK_GROUP_SIZE_NV 0x953C #define GL_MESH_WORK_GROUP_SIZE_NV 0x953E #define GL_TASK_WORK_GROUP_SIZE_NV 0x953F #define GL_MESH_VERTICES_OUT_NV 0x9579 #define GL_MESH_PRIMITIVES_OUT_NV 0x957A #define GL_MESH_OUTPUT_TYPE_NV 0x957B #define GL_UNIFORM_BLOCK_REFERENCED_BY_MESH_SHADER_NV 0x959C #define GL_UNIFORM_BLOCK_REFERENCED_BY_TASK_SHADER_NV 0x959D #define GL_REFERENCED_BY_MESH_SHADER_NV 0x95A0 #define GL_REFERENCED_BY_TASK_SHADER_NV 0x95A1 #define GL_MESH_SHADER_BIT_NV 0x00000040 #define GL_TASK_SHADER_BIT_NV 0x00000080 #define GL_MESH_SUBROUTINE_NV 0x957C #define GL_TASK_SUBROUTINE_NV 0x957D #define GL_MESH_SUBROUTINE_UNIFORM_NV 0x957E #define GL_TASK_SUBROUTINE_UNIFORM_NV 0x957F #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_MESH_SHADER_NV 0x959E #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TASK_SHADER_NV 0x959F typedef void (APIENTRYP PFNGLDRAWMESHTASKSNVPROC) (GLuint first, GLuint count); typedef void (APIENTRYP PFNGLDRAWMESHTASKSINDIRECTNVPROC) (GLintptr indirect); typedef void (APIENTRYP PFNGLMULTIDRAWMESHTASKSINDIRECTNVPROC) (GLintptr indirect, GLsizei drawcount, GLsizei stride); typedef void (APIENTRYP PFNGLMULTIDRAWMESHTASKSINDIRECTCOUNTNVPROC) (GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawMeshTasksNV (GLuint first, GLuint count); GLAPI void APIENTRY glDrawMeshTasksIndirectNV (GLintptr indirect); GLAPI void APIENTRY glMultiDrawMeshTasksIndirectNV (GLintptr indirect, GLsizei drawcount, GLsizei stride); GLAPI void APIENTRY glMultiDrawMeshTasksIndirectCountNV (GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); #endif #endif /* GL_NV_mesh_shader */ #ifndef GL_NV_multisample_coverage #define GL_NV_multisample_coverage 1 #endif /* GL_NV_multisample_coverage */ #ifndef GL_NV_multisample_filter_hint #define GL_NV_multisample_filter_hint 1 #define GL_MULTISAMPLE_FILTER_HINT_NV 0x8534 #endif /* GL_NV_multisample_filter_hint */ #ifndef GL_NV_occlusion_query #define GL_NV_occlusion_query 1 #define GL_PIXEL_COUNTER_BITS_NV 0x8864 #define GL_CURRENT_OCCLUSION_QUERY_ID_NV 0x8865 #define GL_PIXEL_COUNT_NV 0x8866 #define GL_PIXEL_COUNT_AVAILABLE_NV 0x8867 typedef void (APIENTRYP PFNGLGENOCCLUSIONQUERIESNVPROC) (GLsizei n, GLuint *ids); typedef void (APIENTRYP PFNGLDELETEOCCLUSIONQUERIESNVPROC) (GLsizei n, const GLuint *ids); typedef GLboolean (APIENTRYP PFNGLISOCCLUSIONQUERYNVPROC) (GLuint id); typedef void (APIENTRYP PFNGLBEGINOCCLUSIONQUERYNVPROC) (GLuint id); typedef void (APIENTRYP PFNGLENDOCCLUSIONQUERYNVPROC) (void); typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYIVNVPROC) (GLuint id, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYUIVNVPROC) (GLuint id, GLenum pname, GLuint *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenOcclusionQueriesNV (GLsizei n, GLuint *ids); GLAPI void APIENTRY glDeleteOcclusionQueriesNV (GLsizei n, const GLuint *ids); GLAPI GLboolean APIENTRY glIsOcclusionQueryNV (GLuint id); GLAPI void APIENTRY glBeginOcclusionQueryNV (GLuint id); GLAPI void APIENTRY glEndOcclusionQueryNV (void); GLAPI void APIENTRY glGetOcclusionQueryivNV (GLuint id, GLenum pname, GLint *params); GLAPI void APIENTRY glGetOcclusionQueryuivNV (GLuint id, GLenum pname, GLuint *params); #endif #endif /* GL_NV_occlusion_query */ #ifndef GL_NV_packed_depth_stencil #define GL_NV_packed_depth_stencil 1 #define GL_DEPTH_STENCIL_NV 0x84F9 #define GL_UNSIGNED_INT_24_8_NV 0x84FA #endif /* GL_NV_packed_depth_stencil */ #ifndef GL_NV_parameter_buffer_object #define GL_NV_parameter_buffer_object 1 #define GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV 0x8DA0 #define GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV 0x8DA1 #define GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV 0x8DA2 #define GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV 0x8DA3 #define GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV 0x8DA4 typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLfloat *params); typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIIVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLint *params); typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIUIVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLuint *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramBufferParametersfvNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLfloat *params); GLAPI void APIENTRY glProgramBufferParametersIivNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLint *params); GLAPI void APIENTRY glProgramBufferParametersIuivNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLuint *params); #endif #endif /* GL_NV_parameter_buffer_object */ #ifndef GL_NV_parameter_buffer_object2 #define GL_NV_parameter_buffer_object2 1 #endif /* GL_NV_parameter_buffer_object2 */ #ifndef GL_NV_path_rendering #define GL_NV_path_rendering 1 #define GL_PATH_FORMAT_SVG_NV 0x9070 #define GL_PATH_FORMAT_PS_NV 0x9071 #define GL_STANDARD_FONT_NAME_NV 0x9072 #define GL_SYSTEM_FONT_NAME_NV 0x9073 #define GL_FILE_NAME_NV 0x9074 #define GL_PATH_STROKE_WIDTH_NV 0x9075 #define GL_PATH_END_CAPS_NV 0x9076 #define GL_PATH_INITIAL_END_CAP_NV 0x9077 #define GL_PATH_TERMINAL_END_CAP_NV 0x9078 #define GL_PATH_JOIN_STYLE_NV 0x9079 #define GL_PATH_MITER_LIMIT_NV 0x907A #define GL_PATH_DASH_CAPS_NV 0x907B #define GL_PATH_INITIAL_DASH_CAP_NV 0x907C #define GL_PATH_TERMINAL_DASH_CAP_NV 0x907D #define GL_PATH_DASH_OFFSET_NV 0x907E #define GL_PATH_CLIENT_LENGTH_NV 0x907F #define GL_PATH_FILL_MODE_NV 0x9080 #define GL_PATH_FILL_MASK_NV 0x9081 #define GL_PATH_FILL_COVER_MODE_NV 0x9082 #define GL_PATH_STROKE_COVER_MODE_NV 0x9083 #define GL_PATH_STROKE_MASK_NV 0x9084 #define GL_COUNT_UP_NV 0x9088 #define GL_COUNT_DOWN_NV 0x9089 #define GL_PATH_OBJECT_BOUNDING_BOX_NV 0x908A #define GL_CONVEX_HULL_NV 0x908B #define GL_BOUNDING_BOX_NV 0x908D #define GL_TRANSLATE_X_NV 0x908E #define GL_TRANSLATE_Y_NV 0x908F #define GL_TRANSLATE_2D_NV 0x9090 #define GL_TRANSLATE_3D_NV 0x9091 #define GL_AFFINE_2D_NV 0x9092 #define GL_AFFINE_3D_NV 0x9094 #define GL_TRANSPOSE_AFFINE_2D_NV 0x9096 #define GL_TRANSPOSE_AFFINE_3D_NV 0x9098 #define GL_UTF8_NV 0x909A #define GL_UTF16_NV 0x909B #define GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV 0x909C #define GL_PATH_COMMAND_COUNT_NV 0x909D #define GL_PATH_COORD_COUNT_NV 0x909E #define GL_PATH_DASH_ARRAY_COUNT_NV 0x909F #define GL_PATH_COMPUTED_LENGTH_NV 0x90A0 #define GL_PATH_FILL_BOUNDING_BOX_NV 0x90A1 #define GL_PATH_STROKE_BOUNDING_BOX_NV 0x90A2 #define GL_SQUARE_NV 0x90A3 #define GL_ROUND_NV 0x90A4 #define GL_TRIANGULAR_NV 0x90A5 #define GL_BEVEL_NV 0x90A6 #define GL_MITER_REVERT_NV 0x90A7 #define GL_MITER_TRUNCATE_NV 0x90A8 #define GL_SKIP_MISSING_GLYPH_NV 0x90A9 #define GL_USE_MISSING_GLYPH_NV 0x90AA #define GL_PATH_ERROR_POSITION_NV 0x90AB #define GL_ACCUM_ADJACENT_PAIRS_NV 0x90AD #define GL_ADJACENT_PAIRS_NV 0x90AE #define GL_FIRST_TO_REST_NV 0x90AF #define GL_PATH_GEN_MODE_NV 0x90B0 #define GL_PATH_GEN_COEFF_NV 0x90B1 #define GL_PATH_GEN_COMPONENTS_NV 0x90B3 #define GL_PATH_STENCIL_FUNC_NV 0x90B7 #define GL_PATH_STENCIL_REF_NV 0x90B8 #define GL_PATH_STENCIL_VALUE_MASK_NV 0x90B9 #define GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV 0x90BD #define GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV 0x90BE #define GL_PATH_COVER_DEPTH_FUNC_NV 0x90BF #define GL_PATH_DASH_OFFSET_RESET_NV 0x90B4 #define GL_MOVE_TO_RESETS_NV 0x90B5 #define GL_MOVE_TO_CONTINUES_NV 0x90B6 #define GL_CLOSE_PATH_NV 0x00 #define GL_MOVE_TO_NV 0x02 #define GL_RELATIVE_MOVE_TO_NV 0x03 #define GL_LINE_TO_NV 0x04 #define GL_RELATIVE_LINE_TO_NV 0x05 #define GL_HORIZONTAL_LINE_TO_NV 0x06 #define GL_RELATIVE_HORIZONTAL_LINE_TO_NV 0x07 #define GL_VERTICAL_LINE_TO_NV 0x08 #define GL_RELATIVE_VERTICAL_LINE_TO_NV 0x09 #define GL_QUADRATIC_CURVE_TO_NV 0x0A #define GL_RELATIVE_QUADRATIC_CURVE_TO_NV 0x0B #define GL_CUBIC_CURVE_TO_NV 0x0C #define GL_RELATIVE_CUBIC_CURVE_TO_NV 0x0D #define GL_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0E #define GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0F #define GL_SMOOTH_CUBIC_CURVE_TO_NV 0x10 #define GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV 0x11 #define GL_SMALL_CCW_ARC_TO_NV 0x12 #define GL_RELATIVE_SMALL_CCW_ARC_TO_NV 0x13 #define GL_SMALL_CW_ARC_TO_NV 0x14 #define GL_RELATIVE_SMALL_CW_ARC_TO_NV 0x15 #define GL_LARGE_CCW_ARC_TO_NV 0x16 #define GL_RELATIVE_LARGE_CCW_ARC_TO_NV 0x17 #define GL_LARGE_CW_ARC_TO_NV 0x18 #define GL_RELATIVE_LARGE_CW_ARC_TO_NV 0x19 #define GL_RESTART_PATH_NV 0xF0 #define GL_DUP_FIRST_CUBIC_CURVE_TO_NV 0xF2 #define GL_DUP_LAST_CUBIC_CURVE_TO_NV 0xF4 #define GL_RECT_NV 0xF6 #define GL_CIRCULAR_CCW_ARC_TO_NV 0xF8 #define GL_CIRCULAR_CW_ARC_TO_NV 0xFA #define GL_CIRCULAR_TANGENT_ARC_TO_NV 0xFC #define GL_ARC_TO_NV 0xFE #define GL_RELATIVE_ARC_TO_NV 0xFF #define GL_BOLD_BIT_NV 0x01 #define GL_ITALIC_BIT_NV 0x02 #define GL_GLYPH_WIDTH_BIT_NV 0x01 #define GL_GLYPH_HEIGHT_BIT_NV 0x02 #define GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV 0x04 #define GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV 0x08 #define GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV 0x10 #define GL_GLYPH_VERTICAL_BEARING_X_BIT_NV 0x20 #define GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV 0x40 #define GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV 0x80 #define GL_GLYPH_HAS_KERNING_BIT_NV 0x100 #define GL_FONT_X_MIN_BOUNDS_BIT_NV 0x00010000 #define GL_FONT_Y_MIN_BOUNDS_BIT_NV 0x00020000 #define GL_FONT_X_MAX_BOUNDS_BIT_NV 0x00040000 #define GL_FONT_Y_MAX_BOUNDS_BIT_NV 0x00080000 #define GL_FONT_UNITS_PER_EM_BIT_NV 0x00100000 #define GL_FONT_ASCENDER_BIT_NV 0x00200000 #define GL_FONT_DESCENDER_BIT_NV 0x00400000 #define GL_FONT_HEIGHT_BIT_NV 0x00800000 #define GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV 0x01000000 #define GL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV 0x02000000 #define GL_FONT_UNDERLINE_POSITION_BIT_NV 0x04000000 #define GL_FONT_UNDERLINE_THICKNESS_BIT_NV 0x08000000 #define GL_FONT_HAS_KERNING_BIT_NV 0x10000000 #define GL_ROUNDED_RECT_NV 0xE8 #define GL_RELATIVE_ROUNDED_RECT_NV 0xE9 #define GL_ROUNDED_RECT2_NV 0xEA #define GL_RELATIVE_ROUNDED_RECT2_NV 0xEB #define GL_ROUNDED_RECT4_NV 0xEC #define GL_RELATIVE_ROUNDED_RECT4_NV 0xED #define GL_ROUNDED_RECT8_NV 0xEE #define GL_RELATIVE_ROUNDED_RECT8_NV 0xEF #define GL_RELATIVE_RECT_NV 0xF7 #define GL_FONT_GLYPHS_AVAILABLE_NV 0x9368 #define GL_FONT_TARGET_UNAVAILABLE_NV 0x9369 #define GL_FONT_UNAVAILABLE_NV 0x936A #define GL_FONT_UNINTELLIGIBLE_NV 0x936B #define GL_CONIC_CURVE_TO_NV 0x1A #define GL_RELATIVE_CONIC_CURVE_TO_NV 0x1B #define GL_FONT_NUM_GLYPH_INDICES_BIT_NV 0x20000000 #define GL_STANDARD_FONT_FORMAT_NV 0x936C #define GL_2_BYTES_NV 0x1407 #define GL_3_BYTES_NV 0x1408 #define GL_4_BYTES_NV 0x1409 #define GL_EYE_LINEAR_NV 0x2400 #define GL_OBJECT_LINEAR_NV 0x2401 #define GL_CONSTANT_NV 0x8576 #define GL_PATH_FOG_GEN_MODE_NV 0x90AC #define GL_PRIMARY_COLOR_NV 0x852C #define GL_SECONDARY_COLOR_NV 0x852D #define GL_PATH_GEN_COLOR_FORMAT_NV 0x90B2 #define GL_PATH_PROJECTION_NV 0x1701 #define GL_PATH_MODELVIEW_NV 0x1700 #define GL_PATH_MODELVIEW_STACK_DEPTH_NV 0x0BA3 #define GL_PATH_MODELVIEW_MATRIX_NV 0x0BA6 #define GL_PATH_MAX_MODELVIEW_STACK_DEPTH_NV 0x0D36 #define GL_PATH_TRANSPOSE_MODELVIEW_MATRIX_NV 0x84E3 #define GL_PATH_PROJECTION_STACK_DEPTH_NV 0x0BA4 #define GL_PATH_PROJECTION_MATRIX_NV 0x0BA7 #define GL_PATH_MAX_PROJECTION_STACK_DEPTH_NV 0x0D38 #define GL_PATH_TRANSPOSE_PROJECTION_MATRIX_NV 0x84E4 #define GL_FRAGMENT_INPUT_NV 0x936D typedef GLuint (APIENTRYP PFNGLGENPATHSNVPROC) (GLsizei range); typedef void (APIENTRYP PFNGLDELETEPATHSNVPROC) (GLuint path, GLsizei range); typedef GLboolean (APIENTRYP PFNGLISPATHNVPROC) (GLuint path); typedef void (APIENTRYP PFNGLPATHCOMMANDSNVPROC) (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); typedef void (APIENTRYP PFNGLPATHCOORDSNVPROC) (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords); typedef void (APIENTRYP PFNGLPATHSUBCOMMANDSNVPROC) (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); typedef void (APIENTRYP PFNGLPATHSUBCOORDSNVPROC) (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords); typedef void (APIENTRYP PFNGLPATHSTRINGNVPROC) (GLuint path, GLenum format, GLsizei length, const void *pathString); typedef void (APIENTRYP PFNGLPATHGLYPHSNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); typedef void (APIENTRYP PFNGLPATHGLYPHRANGENVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); typedef void (APIENTRYP PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); typedef void (APIENTRYP PFNGLCOPYPATHNVPROC) (GLuint resultPath, GLuint srcPath); typedef void (APIENTRYP PFNGLINTERPOLATEPATHSNVPROC) (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); typedef void (APIENTRYP PFNGLTRANSFORMPATHNVPROC) (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues); typedef void (APIENTRYP PFNGLPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, const GLint *value); typedef void (APIENTRYP PFNGLPATHPARAMETERINVPROC) (GLuint path, GLenum pname, GLint value); typedef void (APIENTRYP PFNGLPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, const GLfloat *value); typedef void (APIENTRYP PFNGLPATHPARAMETERFNVPROC) (GLuint path, GLenum pname, GLfloat value); typedef void (APIENTRYP PFNGLPATHDASHARRAYNVPROC) (GLuint path, GLsizei dashCount, const GLfloat *dashArray); typedef void (APIENTRYP PFNGLPATHSTENCILFUNCNVPROC) (GLenum func, GLint ref, GLuint mask); typedef void (APIENTRYP PFNGLPATHSTENCILDEPTHOFFSETNVPROC) (GLfloat factor, GLfloat units); typedef void (APIENTRYP PFNGLSTENCILFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask); typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask); typedef void (APIENTRYP PFNGLSTENCILFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); typedef void (APIENTRYP PFNGLPATHCOVERDEPTHFUNCNVPROC) (GLenum func); typedef void (APIENTRYP PFNGLCOVERFILLPATHNVPROC) (GLuint path, GLenum coverMode); typedef void (APIENTRYP PFNGLCOVERSTROKEPATHNVPROC) (GLuint path, GLenum coverMode); typedef void (APIENTRYP PFNGLCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); typedef void (APIENTRYP PFNGLCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); typedef void (APIENTRYP PFNGLGETPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, GLint *value); typedef void (APIENTRYP PFNGLGETPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, GLfloat *value); typedef void (APIENTRYP PFNGLGETPATHCOMMANDSNVPROC) (GLuint path, GLubyte *commands); typedef void (APIENTRYP PFNGLGETPATHCOORDSNVPROC) (GLuint path, GLfloat *coords); typedef void (APIENTRYP PFNGLGETPATHDASHARRAYNVPROC) (GLuint path, GLfloat *dashArray); typedef void (APIENTRYP PFNGLGETPATHMETRICSNVPROC) (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); typedef void (APIENTRYP PFNGLGETPATHMETRICRANGENVPROC) (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); typedef void (APIENTRYP PFNGLGETPATHSPACINGNVPROC) (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); typedef GLboolean (APIENTRYP PFNGLISPOINTINFILLPATHNVPROC) (GLuint path, GLuint mask, GLfloat x, GLfloat y); typedef GLboolean (APIENTRYP PFNGLISPOINTINSTROKEPATHNVPROC) (GLuint path, GLfloat x, GLfloat y); typedef GLfloat (APIENTRYP PFNGLGETPATHLENGTHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments); typedef GLboolean (APIENTRYP PFNGLPOINTALONGPATHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); typedef void (APIENTRYP PFNGLMATRIXLOAD3X2FNVPROC) (GLenum matrixMode, const GLfloat *m); typedef void (APIENTRYP PFNGLMATRIXLOAD3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); typedef void (APIENTRYP PFNGLMATRIXMULT3X2FNVPROC) (GLenum matrixMode, const GLfloat *m); typedef void (APIENTRYP PFNGLMATRIXMULT3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); typedef void (APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode); typedef void (APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask, GLenum coverMode); typedef void (APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); typedef void (APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); typedef GLenum (APIENTRYP PFNGLPATHGLYPHINDEXRANGENVPROC) (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint baseAndCount[2]); typedef GLenum (APIENTRYP PFNGLPATHGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); typedef GLenum (APIENTRYP PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); typedef void (APIENTRYP PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC) (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs); typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEFVNVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei count, GLsizei *length, GLfloat *params); typedef void (APIENTRYP PFNGLPATHCOLORGENNVPROC) (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs); typedef void (APIENTRYP PFNGLPATHTEXGENNVPROC) (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs); typedef void (APIENTRYP PFNGLPATHFOGGENNVPROC) (GLenum genMode); typedef void (APIENTRYP PFNGLGETPATHCOLORGENIVNVPROC) (GLenum color, GLenum pname, GLint *value); typedef void (APIENTRYP PFNGLGETPATHCOLORGENFVNVPROC) (GLenum color, GLenum pname, GLfloat *value); typedef void (APIENTRYP PFNGLGETPATHTEXGENIVNVPROC) (GLenum texCoordSet, GLenum pname, GLint *value); typedef void (APIENTRYP PFNGLGETPATHTEXGENFVNVPROC) (GLenum texCoordSet, GLenum pname, GLfloat *value); #ifdef GL_GLEXT_PROTOTYPES GLAPI GLuint APIENTRY glGenPathsNV (GLsizei range); GLAPI void APIENTRY glDeletePathsNV (GLuint path, GLsizei range); GLAPI GLboolean APIENTRY glIsPathNV (GLuint path); GLAPI void APIENTRY glPathCommandsNV (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); GLAPI void APIENTRY glPathCoordsNV (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords); GLAPI void APIENTRY glPathSubCommandsNV (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); GLAPI void APIENTRY glPathSubCoordsNV (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords); GLAPI void APIENTRY glPathStringNV (GLuint path, GLenum format, GLsizei length, const void *pathString); GLAPI void APIENTRY glPathGlyphsNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); GLAPI void APIENTRY glPathGlyphRangeNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); GLAPI void APIENTRY glWeightPathsNV (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); GLAPI void APIENTRY glCopyPathNV (GLuint resultPath, GLuint srcPath); GLAPI void APIENTRY glInterpolatePathsNV (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); GLAPI void APIENTRY glTransformPathNV (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues); GLAPI void APIENTRY glPathParameterivNV (GLuint path, GLenum pname, const GLint *value); GLAPI void APIENTRY glPathParameteriNV (GLuint path, GLenum pname, GLint value); GLAPI void APIENTRY glPathParameterfvNV (GLuint path, GLenum pname, const GLfloat *value); GLAPI void APIENTRY glPathParameterfNV (GLuint path, GLenum pname, GLfloat value); GLAPI void APIENTRY glPathDashArrayNV (GLuint path, GLsizei dashCount, const GLfloat *dashArray); GLAPI void APIENTRY glPathStencilFuncNV (GLenum func, GLint ref, GLuint mask); GLAPI void APIENTRY glPathStencilDepthOffsetNV (GLfloat factor, GLfloat units); GLAPI void APIENTRY glStencilFillPathNV (GLuint path, GLenum fillMode, GLuint mask); GLAPI void APIENTRY glStencilStrokePathNV (GLuint path, GLint reference, GLuint mask); GLAPI void APIENTRY glStencilFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); GLAPI void APIENTRY glStencilStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); GLAPI void APIENTRY glPathCoverDepthFuncNV (GLenum func); GLAPI void APIENTRY glCoverFillPathNV (GLuint path, GLenum coverMode); GLAPI void APIENTRY glCoverStrokePathNV (GLuint path, GLenum coverMode); GLAPI void APIENTRY glCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); GLAPI void APIENTRY glCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); GLAPI void APIENTRY glGetPathParameterivNV (GLuint path, GLenum pname, GLint *value); GLAPI void APIENTRY glGetPathParameterfvNV (GLuint path, GLenum pname, GLfloat *value); GLAPI void APIENTRY glGetPathCommandsNV (GLuint path, GLubyte *commands); GLAPI void APIENTRY glGetPathCoordsNV (GLuint path, GLfloat *coords); GLAPI void APIENTRY glGetPathDashArrayNV (GLuint path, GLfloat *dashArray); GLAPI void APIENTRY glGetPathMetricsNV (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); GLAPI void APIENTRY glGetPathMetricRangeNV (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); GLAPI void APIENTRY glGetPathSpacingNV (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); GLAPI GLboolean APIENTRY glIsPointInFillPathNV (GLuint path, GLuint mask, GLfloat x, GLfloat y); GLAPI GLboolean APIENTRY glIsPointInStrokePathNV (GLuint path, GLfloat x, GLfloat y); GLAPI GLfloat APIENTRY glGetPathLengthNV (GLuint path, GLsizei startSegment, GLsizei numSegments); GLAPI GLboolean APIENTRY glPointAlongPathNV (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); GLAPI void APIENTRY glMatrixLoad3x2fNV (GLenum matrixMode, const GLfloat *m); GLAPI void APIENTRY glMatrixLoad3x3fNV (GLenum matrixMode, const GLfloat *m); GLAPI void APIENTRY glMatrixLoadTranspose3x3fNV (GLenum matrixMode, const GLfloat *m); GLAPI void APIENTRY glMatrixMult3x2fNV (GLenum matrixMode, const GLfloat *m); GLAPI void APIENTRY glMatrixMult3x3fNV (GLenum matrixMode, const GLfloat *m); GLAPI void APIENTRY glMatrixMultTranspose3x3fNV (GLenum matrixMode, const GLfloat *m); GLAPI void APIENTRY glStencilThenCoverFillPathNV (GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode); GLAPI void APIENTRY glStencilThenCoverStrokePathNV (GLuint path, GLint reference, GLuint mask, GLenum coverMode); GLAPI void APIENTRY glStencilThenCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); GLAPI void APIENTRY glStencilThenCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); GLAPI GLenum APIENTRY glPathGlyphIndexRangeNV (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint baseAndCount[2]); GLAPI GLenum APIENTRY glPathGlyphIndexArrayNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); GLAPI GLenum APIENTRY glPathMemoryGlyphIndexArrayNV (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); GLAPI void APIENTRY glProgramPathFragmentInputGenNV (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs); GLAPI void APIENTRY glGetProgramResourcefvNV (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei count, GLsizei *length, GLfloat *params); GLAPI void APIENTRY glPathColorGenNV (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs); GLAPI void APIENTRY glPathTexGenNV (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs); GLAPI void APIENTRY glPathFogGenNV (GLenum genMode); GLAPI void APIENTRY glGetPathColorGenivNV (GLenum color, GLenum pname, GLint *value); GLAPI void APIENTRY glGetPathColorGenfvNV (GLenum color, GLenum pname, GLfloat *value); GLAPI void APIENTRY glGetPathTexGenivNV (GLenum texCoordSet, GLenum pname, GLint *value); GLAPI void APIENTRY glGetPathTexGenfvNV (GLenum texCoordSet, GLenum pname, GLfloat *value); #endif #endif /* GL_NV_path_rendering */ #ifndef GL_NV_path_rendering_shared_edge #define GL_NV_path_rendering_shared_edge 1 #define GL_SHARED_EDGE_NV 0xC0 #endif /* GL_NV_path_rendering_shared_edge */ #ifndef GL_NV_pixel_data_range #define GL_NV_pixel_data_range 1 #define GL_WRITE_PIXEL_DATA_RANGE_NV 0x8878 #define GL_READ_PIXEL_DATA_RANGE_NV 0x8879 #define GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A #define GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B #define GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C #define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D typedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, const void *pointer); typedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPixelDataRangeNV (GLenum target, GLsizei length, const void *pointer); GLAPI void APIENTRY glFlushPixelDataRangeNV (GLenum target); #endif #endif /* GL_NV_pixel_data_range */ #ifndef GL_NV_point_sprite #define GL_NV_point_sprite 1 #define GL_POINT_SPRITE_NV 0x8861 #define GL_COORD_REPLACE_NV 0x8862 #define GL_POINT_SPRITE_R_MODE_NV 0x8863 typedef void (APIENTRYP PFNGLPOINTPARAMETERINVPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLPOINTPARAMETERIVNVPROC) (GLenum pname, const GLint *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPointParameteriNV (GLenum pname, GLint param); GLAPI void APIENTRY glPointParameterivNV (GLenum pname, const GLint *params); #endif #endif /* GL_NV_point_sprite */ #ifndef GL_NV_present_video #define GL_NV_present_video 1 #define GL_FRAME_NV 0x8E26 #define GL_FIELDS_NV 0x8E27 #define GL_CURRENT_TIME_NV 0x8E28 #define GL_NUM_FILL_STREAMS_NV 0x8E29 #define GL_PRESENT_TIME_NV 0x8E2A #define GL_PRESENT_DURATION_NV 0x8E2B typedef void (APIENTRYP PFNGLPRESENTFRAMEKEYEDNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1); typedef void (APIENTRYP PFNGLPRESENTFRAMEDUALFILLNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3); typedef void (APIENTRYP PFNGLGETVIDEOIVNVPROC) (GLuint video_slot, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVIDEOUIVNVPROC) (GLuint video_slot, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLGETVIDEOI64VNVPROC) (GLuint video_slot, GLenum pname, GLint64EXT *params); typedef void (APIENTRYP PFNGLGETVIDEOUI64VNVPROC) (GLuint video_slot, GLenum pname, GLuint64EXT *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPresentFrameKeyedNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1); GLAPI void APIENTRY glPresentFrameDualFillNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3); GLAPI void APIENTRY glGetVideoivNV (GLuint video_slot, GLenum pname, GLint *params); GLAPI void APIENTRY glGetVideouivNV (GLuint video_slot, GLenum pname, GLuint *params); GLAPI void APIENTRY glGetVideoi64vNV (GLuint video_slot, GLenum pname, GLint64EXT *params); GLAPI void APIENTRY glGetVideoui64vNV (GLuint video_slot, GLenum pname, GLuint64EXT *params); #endif #endif /* GL_NV_present_video */ #ifndef GL_NV_primitive_restart #define GL_NV_primitive_restart 1 #define GL_PRIMITIVE_RESTART_NV 0x8558 #define GL_PRIMITIVE_RESTART_INDEX_NV 0x8559 typedef void (APIENTRYP PFNGLPRIMITIVERESTARTNVPROC) (void); typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXNVPROC) (GLuint index); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPrimitiveRestartNV (void); GLAPI void APIENTRY glPrimitiveRestartIndexNV (GLuint index); #endif #endif /* GL_NV_primitive_restart */ #ifndef GL_NV_primitive_shading_rate #define GL_NV_primitive_shading_rate 1 #define GL_SHADING_RATE_IMAGE_PER_PRIMITIVE_NV 0x95B1 #define GL_SHADING_RATE_IMAGE_PALETTE_COUNT_NV 0x95B2 #endif /* GL_NV_primitive_shading_rate */ #ifndef GL_NV_query_resource #define GL_NV_query_resource 1 #define GL_QUERY_RESOURCE_TYPE_VIDMEM_ALLOC_NV 0x9540 #define GL_QUERY_RESOURCE_MEMTYPE_VIDMEM_NV 0x9542 #define GL_QUERY_RESOURCE_SYS_RESERVED_NV 0x9544 #define GL_QUERY_RESOURCE_TEXTURE_NV 0x9545 #define GL_QUERY_RESOURCE_RENDERBUFFER_NV 0x9546 #define GL_QUERY_RESOURCE_BUFFEROBJECT_NV 0x9547 typedef GLint (APIENTRYP PFNGLQUERYRESOURCENVPROC) (GLenum queryType, GLint tagId, GLuint count, GLint *buffer); #ifdef GL_GLEXT_PROTOTYPES GLAPI GLint APIENTRY glQueryResourceNV (GLenum queryType, GLint tagId, GLuint count, GLint *buffer); #endif #endif /* GL_NV_query_resource */ #ifndef GL_NV_query_resource_tag #define GL_NV_query_resource_tag 1 typedef void (APIENTRYP PFNGLGENQUERYRESOURCETAGNVPROC) (GLsizei n, GLint *tagIds); typedef void (APIENTRYP PFNGLDELETEQUERYRESOURCETAGNVPROC) (GLsizei n, const GLint *tagIds); typedef void (APIENTRYP PFNGLQUERYRESOURCETAGNVPROC) (GLint tagId, const GLchar *tagString); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenQueryResourceTagNV (GLsizei n, GLint *tagIds); GLAPI void APIENTRY glDeleteQueryResourceTagNV (GLsizei n, const GLint *tagIds); GLAPI void APIENTRY glQueryResourceTagNV (GLint tagId, const GLchar *tagString); #endif #endif /* GL_NV_query_resource_tag */ #ifndef GL_NV_register_combiners #define GL_NV_register_combiners 1 #define GL_REGISTER_COMBINERS_NV 0x8522 #define GL_VARIABLE_A_NV 0x8523 #define GL_VARIABLE_B_NV 0x8524 #define GL_VARIABLE_C_NV 0x8525 #define GL_VARIABLE_D_NV 0x8526 #define GL_VARIABLE_E_NV 0x8527 #define GL_VARIABLE_F_NV 0x8528 #define GL_VARIABLE_G_NV 0x8529 #define GL_CONSTANT_COLOR0_NV 0x852A #define GL_CONSTANT_COLOR1_NV 0x852B #define GL_SPARE0_NV 0x852E #define GL_SPARE1_NV 0x852F #define GL_DISCARD_NV 0x8530 #define GL_E_TIMES_F_NV 0x8531 #define GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532 #define GL_UNSIGNED_IDENTITY_NV 0x8536 #define GL_UNSIGNED_INVERT_NV 0x8537 #define GL_EXPAND_NORMAL_NV 0x8538 #define GL_EXPAND_NEGATE_NV 0x8539 #define GL_HALF_BIAS_NORMAL_NV 0x853A #define GL_HALF_BIAS_NEGATE_NV 0x853B #define GL_SIGNED_IDENTITY_NV 0x853C #define GL_SIGNED_NEGATE_NV 0x853D #define GL_SCALE_BY_TWO_NV 0x853E #define GL_SCALE_BY_FOUR_NV 0x853F #define GL_SCALE_BY_ONE_HALF_NV 0x8540 #define GL_BIAS_BY_NEGATIVE_ONE_HALF_NV 0x8541 #define GL_COMBINER_INPUT_NV 0x8542 #define GL_COMBINER_MAPPING_NV 0x8543 #define GL_COMBINER_COMPONENT_USAGE_NV 0x8544 #define GL_COMBINER_AB_DOT_PRODUCT_NV 0x8545 #define GL_COMBINER_CD_DOT_PRODUCT_NV 0x8546 #define GL_COMBINER_MUX_SUM_NV 0x8547 #define GL_COMBINER_SCALE_NV 0x8548 #define GL_COMBINER_BIAS_NV 0x8549 #define GL_COMBINER_AB_OUTPUT_NV 0x854A #define GL_COMBINER_CD_OUTPUT_NV 0x854B #define GL_COMBINER_SUM_OUTPUT_NV 0x854C #define GL_MAX_GENERAL_COMBINERS_NV 0x854D #define GL_NUM_GENERAL_COMBINERS_NV 0x854E #define GL_COLOR_SUM_CLAMP_NV 0x854F #define GL_COMBINER0_NV 0x8550 #define GL_COMBINER1_NV 0x8551 #define GL_COMBINER2_NV 0x8552 #define GL_COMBINER3_NV 0x8553 #define GL_COMBINER4_NV 0x8554 #define GL_COMBINER5_NV 0x8555 #define GL_COMBINER6_NV 0x8556 #define GL_COMBINER7_NV 0x8557 typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFNVPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLCOMBINERPARAMETERIVNVPROC) (GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); typedef void (APIENTRYP PFNGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); typedef void (APIENTRYP PFNGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) (GLenum variable, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) (GLenum variable, GLenum pname, GLint *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCombinerParameterfvNV (GLenum pname, const GLfloat *params); GLAPI void APIENTRY glCombinerParameterfNV (GLenum pname, GLfloat param); GLAPI void APIENTRY glCombinerParameterivNV (GLenum pname, const GLint *params); GLAPI void APIENTRY glCombinerParameteriNV (GLenum pname, GLint param); GLAPI void APIENTRY glCombinerInputNV (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); GLAPI void APIENTRY glCombinerOutputNV (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); GLAPI void APIENTRY glFinalCombinerInputNV (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); GLAPI void APIENTRY glGetCombinerInputParameterfvNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetCombinerInputParameterivNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); GLAPI void APIENTRY glGetCombinerOutputParameterfvNV (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetCombinerOutputParameterivNV (GLenum stage, GLenum portion, GLenum pname, GLint *params); GLAPI void APIENTRY glGetFinalCombinerInputParameterfvNV (GLenum variable, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetFinalCombinerInputParameterivNV (GLenum variable, GLenum pname, GLint *params); #endif #endif /* GL_NV_register_combiners */ #ifndef GL_NV_register_combiners2 #define GL_NV_register_combiners2 1 #define GL_PER_STAGE_CONSTANTS_NV 0x8535 typedef void (APIENTRYP PFNGLCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, GLfloat *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCombinerStageParameterfvNV (GLenum stage, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glGetCombinerStageParameterfvNV (GLenum stage, GLenum pname, GLfloat *params); #endif #endif /* GL_NV_register_combiners2 */ #ifndef GL_NV_representative_fragment_test #define GL_NV_representative_fragment_test 1 #define GL_REPRESENTATIVE_FRAGMENT_TEST_NV 0x937F #endif /* GL_NV_representative_fragment_test */ #ifndef GL_NV_robustness_video_memory_purge #define GL_NV_robustness_video_memory_purge 1 #define GL_PURGED_CONTEXT_RESET_NV 0x92BB #endif /* GL_NV_robustness_video_memory_purge */ #ifndef GL_NV_sample_locations #define GL_NV_sample_locations 1 #define GL_SAMPLE_LOCATION_SUBPIXEL_BITS_NV 0x933D #define GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_NV 0x933E #define GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_NV 0x933F #define GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_NV 0x9340 #define GL_SAMPLE_LOCATION_NV 0x8E50 #define GL_PROGRAMMABLE_SAMPLE_LOCATION_NV 0x9341 #define GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_NV 0x9342 #define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_NV 0x9343 typedef void (APIENTRYP PFNGLFRAMEBUFFERSAMPLELOCATIONSFVNVPROC) (GLenum target, GLuint start, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVNVPROC) (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLRESOLVEDEPTHVALUESNVPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFramebufferSampleLocationsfvNV (GLenum target, GLuint start, GLsizei count, const GLfloat *v); GLAPI void APIENTRY glNamedFramebufferSampleLocationsfvNV (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v); GLAPI void APIENTRY glResolveDepthValuesNV (void); #endif #endif /* GL_NV_sample_locations */ #ifndef GL_NV_sample_mask_override_coverage #define GL_NV_sample_mask_override_coverage 1 #endif /* GL_NV_sample_mask_override_coverage */ #ifndef GL_NV_scissor_exclusive #define GL_NV_scissor_exclusive 1 #define GL_SCISSOR_TEST_EXCLUSIVE_NV 0x9555 #define GL_SCISSOR_BOX_EXCLUSIVE_NV 0x9556 typedef void (APIENTRYP PFNGLSCISSOREXCLUSIVENVPROC) (GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLSCISSOREXCLUSIVEARRAYVNVPROC) (GLuint first, GLsizei count, const GLint *v); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glScissorExclusiveNV (GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glScissorExclusiveArrayvNV (GLuint first, GLsizei count, const GLint *v); #endif #endif /* GL_NV_scissor_exclusive */ #ifndef GL_NV_shader_atomic_counters #define GL_NV_shader_atomic_counters 1 #endif /* GL_NV_shader_atomic_counters */ #ifndef GL_NV_shader_atomic_float #define GL_NV_shader_atomic_float 1 #endif /* GL_NV_shader_atomic_float */ #ifndef GL_NV_shader_atomic_float64 #define GL_NV_shader_atomic_float64 1 #endif /* GL_NV_shader_atomic_float64 */ #ifndef GL_NV_shader_atomic_fp16_vector #define GL_NV_shader_atomic_fp16_vector 1 #endif /* GL_NV_shader_atomic_fp16_vector */ #ifndef GL_NV_shader_atomic_int64 #define GL_NV_shader_atomic_int64 1 #endif /* GL_NV_shader_atomic_int64 */ #ifndef GL_NV_shader_buffer_load #define GL_NV_shader_buffer_load 1 #define GL_BUFFER_GPU_ADDRESS_NV 0x8F1D #define GL_GPU_ADDRESS_NV 0x8F34 #define GL_MAX_SHADER_BUFFER_ADDRESS_NV 0x8F35 typedef void (APIENTRYP PFNGLMAKEBUFFERRESIDENTNVPROC) (GLenum target, GLenum access); typedef void (APIENTRYP PFNGLMAKEBUFFERNONRESIDENTNVPROC) (GLenum target); typedef GLboolean (APIENTRYP PFNGLISBUFFERRESIDENTNVPROC) (GLenum target); typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERRESIDENTNVPROC) (GLuint buffer, GLenum access); typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERNONRESIDENTNVPROC) (GLuint buffer); typedef GLboolean (APIENTRYP PFNGLISNAMEDBUFFERRESIDENTNVPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERUI64VNVPROC) (GLenum target, GLenum pname, GLuint64EXT *params); typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERUI64VNVPROC) (GLuint buffer, GLenum pname, GLuint64EXT *params); typedef void (APIENTRYP PFNGLGETINTEGERUI64VNVPROC) (GLenum value, GLuint64EXT *result); typedef void (APIENTRYP PFNGLUNIFORMUI64NVPROC) (GLint location, GLuint64EXT value); typedef void (APIENTRYP PFNGLUNIFORMUI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64NVPROC) (GLuint program, GLint location, GLuint64EXT value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMakeBufferResidentNV (GLenum target, GLenum access); GLAPI void APIENTRY glMakeBufferNonResidentNV (GLenum target); GLAPI GLboolean APIENTRY glIsBufferResidentNV (GLenum target); GLAPI void APIENTRY glMakeNamedBufferResidentNV (GLuint buffer, GLenum access); GLAPI void APIENTRY glMakeNamedBufferNonResidentNV (GLuint buffer); GLAPI GLboolean APIENTRY glIsNamedBufferResidentNV (GLuint buffer); GLAPI void APIENTRY glGetBufferParameterui64vNV (GLenum target, GLenum pname, GLuint64EXT *params); GLAPI void APIENTRY glGetNamedBufferParameterui64vNV (GLuint buffer, GLenum pname, GLuint64EXT *params); GLAPI void APIENTRY glGetIntegerui64vNV (GLenum value, GLuint64EXT *result); GLAPI void APIENTRY glUniformui64NV (GLint location, GLuint64EXT value); GLAPI void APIENTRY glUniformui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); GLAPI void APIENTRY glProgramUniformui64NV (GLuint program, GLint location, GLuint64EXT value); GLAPI void APIENTRY glProgramUniformui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); #endif #endif /* GL_NV_shader_buffer_load */ #ifndef GL_NV_shader_buffer_store #define GL_NV_shader_buffer_store 1 #define GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV 0x00000010 #endif /* GL_NV_shader_buffer_store */ #ifndef GL_NV_shader_storage_buffer_object #define GL_NV_shader_storage_buffer_object 1 #endif /* GL_NV_shader_storage_buffer_object */ #ifndef GL_NV_shader_subgroup_partitioned #define GL_NV_shader_subgroup_partitioned 1 #define GL_SUBGROUP_FEATURE_PARTITIONED_BIT_NV 0x00000100 #endif /* GL_NV_shader_subgroup_partitioned */ #ifndef GL_NV_shader_texture_footprint #define GL_NV_shader_texture_footprint 1 #endif /* GL_NV_shader_texture_footprint */ #ifndef GL_NV_shader_thread_group #define GL_NV_shader_thread_group 1 #define GL_WARP_SIZE_NV 0x9339 #define GL_WARPS_PER_SM_NV 0x933A #define GL_SM_COUNT_NV 0x933B #endif /* GL_NV_shader_thread_group */ #ifndef GL_NV_shader_thread_shuffle #define GL_NV_shader_thread_shuffle 1 #endif /* GL_NV_shader_thread_shuffle */ #ifndef GL_NV_shading_rate_image #define GL_NV_shading_rate_image 1 #define GL_SHADING_RATE_IMAGE_NV 0x9563 #define GL_SHADING_RATE_NO_INVOCATIONS_NV 0x9564 #define GL_SHADING_RATE_1_INVOCATION_PER_PIXEL_NV 0x9565 #define GL_SHADING_RATE_1_INVOCATION_PER_1X2_PIXELS_NV 0x9566 #define GL_SHADING_RATE_1_INVOCATION_PER_2X1_PIXELS_NV 0x9567 #define GL_SHADING_RATE_1_INVOCATION_PER_2X2_PIXELS_NV 0x9568 #define GL_SHADING_RATE_1_INVOCATION_PER_2X4_PIXELS_NV 0x9569 #define GL_SHADING_RATE_1_INVOCATION_PER_4X2_PIXELS_NV 0x956A #define GL_SHADING_RATE_1_INVOCATION_PER_4X4_PIXELS_NV 0x956B #define GL_SHADING_RATE_2_INVOCATIONS_PER_PIXEL_NV 0x956C #define GL_SHADING_RATE_4_INVOCATIONS_PER_PIXEL_NV 0x956D #define GL_SHADING_RATE_8_INVOCATIONS_PER_PIXEL_NV 0x956E #define GL_SHADING_RATE_16_INVOCATIONS_PER_PIXEL_NV 0x956F #define GL_SHADING_RATE_IMAGE_BINDING_NV 0x955B #define GL_SHADING_RATE_IMAGE_TEXEL_WIDTH_NV 0x955C #define GL_SHADING_RATE_IMAGE_TEXEL_HEIGHT_NV 0x955D #define GL_SHADING_RATE_IMAGE_PALETTE_SIZE_NV 0x955E #define GL_MAX_COARSE_FRAGMENT_SAMPLES_NV 0x955F #define GL_SHADING_RATE_SAMPLE_ORDER_DEFAULT_NV 0x95AE #define GL_SHADING_RATE_SAMPLE_ORDER_PIXEL_MAJOR_NV 0x95AF #define GL_SHADING_RATE_SAMPLE_ORDER_SAMPLE_MAJOR_NV 0x95B0 typedef void (APIENTRYP PFNGLBINDSHADINGRATEIMAGENVPROC) (GLuint texture); typedef void (APIENTRYP PFNGLGETSHADINGRATEIMAGEPALETTENVPROC) (GLuint viewport, GLuint entry, GLenum *rate); typedef void (APIENTRYP PFNGLGETSHADINGRATESAMPLELOCATIONIVNVPROC) (GLenum rate, GLuint samples, GLuint index, GLint *location); typedef void (APIENTRYP PFNGLSHADINGRATEIMAGEBARRIERNVPROC) (GLboolean synchronize); typedef void (APIENTRYP PFNGLSHADINGRATEIMAGEPALETTENVPROC) (GLuint viewport, GLuint first, GLsizei count, const GLenum *rates); typedef void (APIENTRYP PFNGLSHADINGRATESAMPLEORDERNVPROC) (GLenum order); typedef void (APIENTRYP PFNGLSHADINGRATESAMPLEORDERCUSTOMNVPROC) (GLenum rate, GLuint samples, const GLint *locations); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindShadingRateImageNV (GLuint texture); GLAPI void APIENTRY glGetShadingRateImagePaletteNV (GLuint viewport, GLuint entry, GLenum *rate); GLAPI void APIENTRY glGetShadingRateSampleLocationivNV (GLenum rate, GLuint samples, GLuint index, GLint *location); GLAPI void APIENTRY glShadingRateImageBarrierNV (GLboolean synchronize); GLAPI void APIENTRY glShadingRateImagePaletteNV (GLuint viewport, GLuint first, GLsizei count, const GLenum *rates); GLAPI void APIENTRY glShadingRateSampleOrderNV (GLenum order); GLAPI void APIENTRY glShadingRateSampleOrderCustomNV (GLenum rate, GLuint samples, const GLint *locations); #endif #endif /* GL_NV_shading_rate_image */ #ifndef GL_NV_stereo_view_rendering #define GL_NV_stereo_view_rendering 1 #endif /* GL_NV_stereo_view_rendering */ #ifndef GL_NV_tessellation_program5 #define GL_NV_tessellation_program5 1 #define GL_MAX_PROGRAM_PATCH_ATTRIBS_NV 0x86D8 #define GL_TESS_CONTROL_PROGRAM_NV 0x891E #define GL_TESS_EVALUATION_PROGRAM_NV 0x891F #define GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV 0x8C74 #define GL_TESS_EVALUATION_PROGRAM_PARAMETER_BUFFER_NV 0x8C75 #endif /* GL_NV_tessellation_program5 */ #ifndef GL_NV_texgen_emboss #define GL_NV_texgen_emboss 1 #define GL_EMBOSS_LIGHT_NV 0x855D #define GL_EMBOSS_CONSTANT_NV 0x855E #define GL_EMBOSS_MAP_NV 0x855F #endif /* GL_NV_texgen_emboss */ #ifndef GL_NV_texgen_reflection #define GL_NV_texgen_reflection 1 #define GL_NORMAL_MAP_NV 0x8511 #define GL_REFLECTION_MAP_NV 0x8512 #endif /* GL_NV_texgen_reflection */ #ifndef GL_NV_texture_barrier #define GL_NV_texture_barrier 1 typedef void (APIENTRYP PFNGLTEXTUREBARRIERNVPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTextureBarrierNV (void); #endif #endif /* GL_NV_texture_barrier */ #ifndef GL_NV_texture_compression_vtc #define GL_NV_texture_compression_vtc 1 #endif /* GL_NV_texture_compression_vtc */ #ifndef GL_NV_texture_env_combine4 #define GL_NV_texture_env_combine4 1 #define GL_COMBINE4_NV 0x8503 #define GL_SOURCE3_RGB_NV 0x8583 #define GL_SOURCE3_ALPHA_NV 0x858B #define GL_OPERAND3_RGB_NV 0x8593 #define GL_OPERAND3_ALPHA_NV 0x859B #endif /* GL_NV_texture_env_combine4 */ #ifndef GL_NV_texture_expand_normal #define GL_NV_texture_expand_normal 1 #define GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F #endif /* GL_NV_texture_expand_normal */ #ifndef GL_NV_texture_multisample #define GL_NV_texture_multisample 1 #define GL_TEXTURE_COVERAGE_SAMPLES_NV 0x9045 #define GL_TEXTURE_COLOR_SAMPLES_NV 0x9046 typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexImage2DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); GLAPI void APIENTRY glTexImage3DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); GLAPI void APIENTRY glTextureImage2DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); GLAPI void APIENTRY glTextureImage3DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); GLAPI void APIENTRY glTextureImage2DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); GLAPI void APIENTRY glTextureImage3DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); #endif #endif /* GL_NV_texture_multisample */ #ifndef GL_NV_texture_rectangle #define GL_NV_texture_rectangle 1 #define GL_TEXTURE_RECTANGLE_NV 0x84F5 #define GL_TEXTURE_BINDING_RECTANGLE_NV 0x84F6 #define GL_PROXY_TEXTURE_RECTANGLE_NV 0x84F7 #define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV 0x84F8 #endif /* GL_NV_texture_rectangle */ #ifndef GL_NV_texture_rectangle_compressed #define GL_NV_texture_rectangle_compressed 1 #endif /* GL_NV_texture_rectangle_compressed */ #ifndef GL_NV_texture_shader #define GL_NV_texture_shader 1 #define GL_OFFSET_TEXTURE_RECTANGLE_NV 0x864C #define GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D #define GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E #define GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9 #define GL_UNSIGNED_INT_S8_S8_8_8_NV 0x86DA #define GL_UNSIGNED_INT_8_8_S8_S8_REV_NV 0x86DB #define GL_DSDT_MAG_INTENSITY_NV 0x86DC #define GL_SHADER_CONSISTENT_NV 0x86DD #define GL_TEXTURE_SHADER_NV 0x86DE #define GL_SHADER_OPERATION_NV 0x86DF #define GL_CULL_MODES_NV 0x86E0 #define GL_OFFSET_TEXTURE_MATRIX_NV 0x86E1 #define GL_OFFSET_TEXTURE_SCALE_NV 0x86E2 #define GL_OFFSET_TEXTURE_BIAS_NV 0x86E3 #define GL_OFFSET_TEXTURE_2D_MATRIX_NV 0x86E1 #define GL_OFFSET_TEXTURE_2D_SCALE_NV 0x86E2 #define GL_OFFSET_TEXTURE_2D_BIAS_NV 0x86E3 #define GL_PREVIOUS_TEXTURE_INPUT_NV 0x86E4 #define GL_CONST_EYE_NV 0x86E5 #define GL_PASS_THROUGH_NV 0x86E6 #define GL_CULL_FRAGMENT_NV 0x86E7 #define GL_OFFSET_TEXTURE_2D_NV 0x86E8 #define GL_DEPENDENT_AR_TEXTURE_2D_NV 0x86E9 #define GL_DEPENDENT_GB_TEXTURE_2D_NV 0x86EA #define GL_DOT_PRODUCT_NV 0x86EC #define GL_DOT_PRODUCT_DEPTH_REPLACE_NV 0x86ED #define GL_DOT_PRODUCT_TEXTURE_2D_NV 0x86EE #define GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0 #define GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1 #define GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2 #define GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3 #define GL_HILO_NV 0x86F4 #define GL_DSDT_NV 0x86F5 #define GL_DSDT_MAG_NV 0x86F6 #define GL_DSDT_MAG_VIB_NV 0x86F7 #define GL_HILO16_NV 0x86F8 #define GL_SIGNED_HILO_NV 0x86F9 #define GL_SIGNED_HILO16_NV 0x86FA #define GL_SIGNED_RGBA_NV 0x86FB #define GL_SIGNED_RGBA8_NV 0x86FC #define GL_SIGNED_RGB_NV 0x86FE #define GL_SIGNED_RGB8_NV 0x86FF #define GL_SIGNED_LUMINANCE_NV 0x8701 #define GL_SIGNED_LUMINANCE8_NV 0x8702 #define GL_SIGNED_LUMINANCE_ALPHA_NV 0x8703 #define GL_SIGNED_LUMINANCE8_ALPHA8_NV 0x8704 #define GL_SIGNED_ALPHA_NV 0x8705 #define GL_SIGNED_ALPHA8_NV 0x8706 #define GL_SIGNED_INTENSITY_NV 0x8707 #define GL_SIGNED_INTENSITY8_NV 0x8708 #define GL_DSDT8_NV 0x8709 #define GL_DSDT8_MAG8_NV 0x870A #define GL_DSDT8_MAG8_INTENSITY8_NV 0x870B #define GL_SIGNED_RGB_UNSIGNED_ALPHA_NV 0x870C #define GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D #define GL_HI_SCALE_NV 0x870E #define GL_LO_SCALE_NV 0x870F #define GL_DS_SCALE_NV 0x8710 #define GL_DT_SCALE_NV 0x8711 #define GL_MAGNITUDE_SCALE_NV 0x8712 #define GL_VIBRANCE_SCALE_NV 0x8713 #define GL_HI_BIAS_NV 0x8714 #define GL_LO_BIAS_NV 0x8715 #define GL_DS_BIAS_NV 0x8716 #define GL_DT_BIAS_NV 0x8717 #define GL_MAGNITUDE_BIAS_NV 0x8718 #define GL_VIBRANCE_BIAS_NV 0x8719 #define GL_TEXTURE_BORDER_VALUES_NV 0x871A #define GL_TEXTURE_HI_SIZE_NV 0x871B #define GL_TEXTURE_LO_SIZE_NV 0x871C #define GL_TEXTURE_DS_SIZE_NV 0x871D #define GL_TEXTURE_DT_SIZE_NV 0x871E #define GL_TEXTURE_MAG_SIZE_NV 0x871F #endif /* GL_NV_texture_shader */ #ifndef GL_NV_texture_shader2 #define GL_NV_texture_shader2 1 #define GL_DOT_PRODUCT_TEXTURE_3D_NV 0x86EF #endif /* GL_NV_texture_shader2 */ #ifndef GL_NV_texture_shader3 #define GL_NV_texture_shader3 1 #define GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850 #define GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851 #define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852 #define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853 #define GL_OFFSET_HILO_TEXTURE_2D_NV 0x8854 #define GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855 #define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856 #define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857 #define GL_DEPENDENT_HILO_TEXTURE_2D_NV 0x8858 #define GL_DEPENDENT_RGB_TEXTURE_3D_NV 0x8859 #define GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A #define GL_DOT_PRODUCT_PASS_THROUGH_NV 0x885B #define GL_DOT_PRODUCT_TEXTURE_1D_NV 0x885C #define GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D #define GL_HILO8_NV 0x885E #define GL_SIGNED_HILO8_NV 0x885F #define GL_FORCE_BLUE_TO_ONE_NV 0x8860 #endif /* GL_NV_texture_shader3 */ #ifndef GL_NV_timeline_semaphore #define GL_NV_timeline_semaphore 1 #define GL_TIMELINE_SEMAPHORE_VALUE_NV 0x9595 #define GL_SEMAPHORE_TYPE_NV 0x95B3 #define GL_SEMAPHORE_TYPE_BINARY_NV 0x95B4 #define GL_SEMAPHORE_TYPE_TIMELINE_NV 0x95B5 #define GL_MAX_TIMELINE_SEMAPHORE_VALUE_DIFFERENCE_NV 0x95B6 typedef void (APIENTRYP PFNGLCREATESEMAPHORESNVPROC) (GLsizei n, GLuint *semaphores); typedef void (APIENTRYP PFNGLSEMAPHOREPARAMETERIVNVPROC) (GLuint semaphore, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLGETSEMAPHOREPARAMETERIVNVPROC) (GLuint semaphore, GLenum pname, GLint *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCreateSemaphoresNV (GLsizei n, GLuint *semaphores); GLAPI void APIENTRY glSemaphoreParameterivNV (GLuint semaphore, GLenum pname, const GLint *params); GLAPI void APIENTRY glGetSemaphoreParameterivNV (GLuint semaphore, GLenum pname, GLint *params); #endif #endif /* GL_NV_timeline_semaphore */ #ifndef GL_NV_transform_feedback #define GL_NV_transform_feedback 1 #define GL_BACK_PRIMARY_COLOR_NV 0x8C77 #define GL_BACK_SECONDARY_COLOR_NV 0x8C78 #define GL_TEXTURE_COORD_NV 0x8C79 #define GL_CLIP_DISTANCE_NV 0x8C7A #define GL_VERTEX_ID_NV 0x8C7B #define GL_PRIMITIVE_ID_NV 0x8C7C #define GL_GENERIC_ATTRIB_NV 0x8C7D #define GL_TRANSFORM_FEEDBACK_ATTRIBS_NV 0x8C7E #define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV 0x8C7F #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV 0x8C80 #define GL_ACTIVE_VARYINGS_NV 0x8C81 #define GL_ACTIVE_VARYING_MAX_LENGTH_NV 0x8C82 #define GL_TRANSFORM_FEEDBACK_VARYINGS_NV 0x8C83 #define GL_TRANSFORM_FEEDBACK_BUFFER_START_NV 0x8C84 #define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV 0x8C85 #define GL_TRANSFORM_FEEDBACK_RECORD_NV 0x8C86 #define GL_PRIMITIVES_GENERATED_NV 0x8C87 #define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV 0x8C88 #define GL_RASTERIZER_DISCARD_NV 0x8C89 #define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_NV 0x8C8A #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV 0x8C8B #define GL_INTERLEAVED_ATTRIBS_NV 0x8C8C #define GL_SEPARATE_ATTRIBS_NV 0x8C8D #define GL_TRANSFORM_FEEDBACK_BUFFER_NV 0x8C8E #define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV 0x8C8F #define GL_LAYER_NV 0x8DAA #define GL_NEXT_BUFFER_NV -2 #define GL_SKIP_COMPONENTS4_NV -3 #define GL_SKIP_COMPONENTS3_NV -4 #define GL_SKIP_COMPONENTS2_NV -5 #define GL_SKIP_COMPONENTS1_NV -6 typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKNVPROC) (GLenum primitiveMode); typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKNVPROC) (void); typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKATTRIBSNVPROC) (GLsizei count, const GLint *attribs, GLenum bufferMode); typedef void (APIENTRYP PFNGLBINDBUFFERRANGENVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETNVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset); typedef void (APIENTRYP PFNGLBINDBUFFERBASENVPROC) (GLenum target, GLuint index, GLuint buffer); typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSNVPROC) (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode); typedef void (APIENTRYP PFNGLACTIVEVARYINGNVPROC) (GLuint program, const GLchar *name); typedef GLint (APIENTRYP PFNGLGETVARYINGLOCATIONNVPROC) (GLuint program, const GLchar *name); typedef void (APIENTRYP PFNGLGETACTIVEVARYINGNVPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGNVPROC) (GLuint program, GLuint index, GLint *location); typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKSTREAMATTRIBSNVPROC) (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBeginTransformFeedbackNV (GLenum primitiveMode); GLAPI void APIENTRY glEndTransformFeedbackNV (void); GLAPI void APIENTRY glTransformFeedbackAttribsNV (GLsizei count, const GLint *attribs, GLenum bufferMode); GLAPI void APIENTRY glBindBufferRangeNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); GLAPI void APIENTRY glBindBufferOffsetNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset); GLAPI void APIENTRY glBindBufferBaseNV (GLenum target, GLuint index, GLuint buffer); GLAPI void APIENTRY glTransformFeedbackVaryingsNV (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode); GLAPI void APIENTRY glActiveVaryingNV (GLuint program, const GLchar *name); GLAPI GLint APIENTRY glGetVaryingLocationNV (GLuint program, const GLchar *name); GLAPI void APIENTRY glGetActiveVaryingNV (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); GLAPI void APIENTRY glGetTransformFeedbackVaryingNV (GLuint program, GLuint index, GLint *location); GLAPI void APIENTRY glTransformFeedbackStreamAttribsNV (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode); #endif #endif /* GL_NV_transform_feedback */ #ifndef GL_NV_transform_feedback2 #define GL_NV_transform_feedback2 1 #define GL_TRANSFORM_FEEDBACK_NV 0x8E22 #define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED_NV 0x8E23 #define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE_NV 0x8E24 #define GL_TRANSFORM_FEEDBACK_BINDING_NV 0x8E25 typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKNVPROC) (GLenum target, GLuint id); typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSNVPROC) (GLsizei n, const GLuint *ids); typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSNVPROC) (GLsizei n, GLuint *ids); typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKNVPROC) (GLuint id); typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKNVPROC) (void); typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKNVPROC) (void); typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKNVPROC) (GLenum mode, GLuint id); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindTransformFeedbackNV (GLenum target, GLuint id); GLAPI void APIENTRY glDeleteTransformFeedbacksNV (GLsizei n, const GLuint *ids); GLAPI void APIENTRY glGenTransformFeedbacksNV (GLsizei n, GLuint *ids); GLAPI GLboolean APIENTRY glIsTransformFeedbackNV (GLuint id); GLAPI void APIENTRY glPauseTransformFeedbackNV (void); GLAPI void APIENTRY glResumeTransformFeedbackNV (void); GLAPI void APIENTRY glDrawTransformFeedbackNV (GLenum mode, GLuint id); #endif #endif /* GL_NV_transform_feedback2 */ #ifndef GL_NV_uniform_buffer_unified_memory #define GL_NV_uniform_buffer_unified_memory 1 #define GL_UNIFORM_BUFFER_UNIFIED_NV 0x936E #define GL_UNIFORM_BUFFER_ADDRESS_NV 0x936F #define GL_UNIFORM_BUFFER_LENGTH_NV 0x9370 #endif /* GL_NV_uniform_buffer_unified_memory */ #ifndef GL_NV_vdpau_interop #define GL_NV_vdpau_interop 1 typedef GLintptr GLvdpauSurfaceNV; #define GL_SURFACE_STATE_NV 0x86EB #define GL_SURFACE_REGISTERED_NV 0x86FD #define GL_SURFACE_MAPPED_NV 0x8700 #define GL_WRITE_DISCARD_NV 0x88BE typedef void (APIENTRYP PFNGLVDPAUINITNVPROC) (const void *vdpDevice, const void *getProcAddress); typedef void (APIENTRYP PFNGLVDPAUFININVPROC) (void); typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTERVIDEOSURFACENVPROC) (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC) (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); typedef GLboolean (APIENTRYP PFNGLVDPAUISSURFACENVPROC) (GLvdpauSurfaceNV surface); typedef void (APIENTRYP PFNGLVDPAUUNREGISTERSURFACENVPROC) (GLvdpauSurfaceNV surface); typedef void (APIENTRYP PFNGLVDPAUGETSURFACEIVNVPROC) (GLvdpauSurfaceNV surface, GLenum pname, GLsizei count, GLsizei *length, GLint *values); typedef void (APIENTRYP PFNGLVDPAUSURFACEACCESSNVPROC) (GLvdpauSurfaceNV surface, GLenum access); typedef void (APIENTRYP PFNGLVDPAUMAPSURFACESNVPROC) (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces); typedef void (APIENTRYP PFNGLVDPAUUNMAPSURFACESNVPROC) (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVDPAUInitNV (const void *vdpDevice, const void *getProcAddress); GLAPI void APIENTRY glVDPAUFiniNV (void); GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterVideoSurfaceNV (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterOutputSurfaceNV (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); GLAPI GLboolean APIENTRY glVDPAUIsSurfaceNV (GLvdpauSurfaceNV surface); GLAPI void APIENTRY glVDPAUUnregisterSurfaceNV (GLvdpauSurfaceNV surface); GLAPI void APIENTRY glVDPAUGetSurfaceivNV (GLvdpauSurfaceNV surface, GLenum pname, GLsizei count, GLsizei *length, GLint *values); GLAPI void APIENTRY glVDPAUSurfaceAccessNV (GLvdpauSurfaceNV surface, GLenum access); GLAPI void APIENTRY glVDPAUMapSurfacesNV (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces); GLAPI void APIENTRY glVDPAUUnmapSurfacesNV (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces); #endif #endif /* GL_NV_vdpau_interop */ #ifndef GL_NV_vdpau_interop2 #define GL_NV_vdpau_interop2 1 typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTERVIDEOSURFACEWITHPICTURESTRUCTURENVPROC) (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames, GLboolean isFrameStructure); #ifdef GL_GLEXT_PROTOTYPES GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterVideoSurfaceWithPictureStructureNV (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames, GLboolean isFrameStructure); #endif #endif /* GL_NV_vdpau_interop2 */ #ifndef GL_NV_vertex_array_range #define GL_NV_vertex_array_range 1 #define GL_VERTEX_ARRAY_RANGE_NV 0x851D #define GL_VERTEX_ARRAY_RANGE_LENGTH_NV 0x851E #define GL_VERTEX_ARRAY_RANGE_VALID_NV 0x851F #define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520 #define GL_VERTEX_ARRAY_RANGE_POINTER_NV 0x8521 typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void); typedef void (APIENTRYP PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, const void *pointer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFlushVertexArrayRangeNV (void); GLAPI void APIENTRY glVertexArrayRangeNV (GLsizei length, const void *pointer); #endif #endif /* GL_NV_vertex_array_range */ #ifndef GL_NV_vertex_array_range2 #define GL_NV_vertex_array_range2 1 #define GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533 #endif /* GL_NV_vertex_array_range2 */ #ifndef GL_NV_vertex_attrib_integer_64bit #define GL_NV_vertex_attrib_integer_64bit 1 typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64NVPROC) (GLuint index, GLint64EXT x); typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y); typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z); typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64VNVPROC) (GLuint index, const GLint64EXT *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64VNVPROC) (GLuint index, const GLint64EXT *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64VNVPROC) (GLuint index, const GLint64EXT *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64VNVPROC) (GLuint index, const GLint64EXT *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64NVPROC) (GLuint index, GLuint64EXT x); typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y); typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VNVPROC) (GLuint index, const GLuint64EXT *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64VNVPROC) (GLuint index, const GLuint64EXT *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64VNVPROC) (GLuint index, const GLuint64EXT *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64VNVPROC) (GLuint index, const GLuint64EXT *v); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLI64VNVPROC) (GLuint index, GLenum pname, GLint64EXT *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VNVPROC) (GLuint index, GLenum pname, GLuint64EXT *params); typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttribL1i64NV (GLuint index, GLint64EXT x); GLAPI void APIENTRY glVertexAttribL2i64NV (GLuint index, GLint64EXT x, GLint64EXT y); GLAPI void APIENTRY glVertexAttribL3i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z); GLAPI void APIENTRY glVertexAttribL4i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); GLAPI void APIENTRY glVertexAttribL1i64vNV (GLuint index, const GLint64EXT *v); GLAPI void APIENTRY glVertexAttribL2i64vNV (GLuint index, const GLint64EXT *v); GLAPI void APIENTRY glVertexAttribL3i64vNV (GLuint index, const GLint64EXT *v); GLAPI void APIENTRY glVertexAttribL4i64vNV (GLuint index, const GLint64EXT *v); GLAPI void APIENTRY glVertexAttribL1ui64NV (GLuint index, GLuint64EXT x); GLAPI void APIENTRY glVertexAttribL2ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y); GLAPI void APIENTRY glVertexAttribL3ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); GLAPI void APIENTRY glVertexAttribL4ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); GLAPI void APIENTRY glVertexAttribL1ui64vNV (GLuint index, const GLuint64EXT *v); GLAPI void APIENTRY glVertexAttribL2ui64vNV (GLuint index, const GLuint64EXT *v); GLAPI void APIENTRY glVertexAttribL3ui64vNV (GLuint index, const GLuint64EXT *v); GLAPI void APIENTRY glVertexAttribL4ui64vNV (GLuint index, const GLuint64EXT *v); GLAPI void APIENTRY glGetVertexAttribLi64vNV (GLuint index, GLenum pname, GLint64EXT *params); GLAPI void APIENTRY glGetVertexAttribLui64vNV (GLuint index, GLenum pname, GLuint64EXT *params); GLAPI void APIENTRY glVertexAttribLFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride); #endif #endif /* GL_NV_vertex_attrib_integer_64bit */ #ifndef GL_NV_vertex_buffer_unified_memory #define GL_NV_vertex_buffer_unified_memory 1 #define GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV 0x8F1E #define GL_ELEMENT_ARRAY_UNIFIED_NV 0x8F1F #define GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV 0x8F20 #define GL_VERTEX_ARRAY_ADDRESS_NV 0x8F21 #define GL_NORMAL_ARRAY_ADDRESS_NV 0x8F22 #define GL_COLOR_ARRAY_ADDRESS_NV 0x8F23 #define GL_INDEX_ARRAY_ADDRESS_NV 0x8F24 #define GL_TEXTURE_COORD_ARRAY_ADDRESS_NV 0x8F25 #define GL_EDGE_FLAG_ARRAY_ADDRESS_NV 0x8F26 #define GL_SECONDARY_COLOR_ARRAY_ADDRESS_NV 0x8F27 #define GL_FOG_COORD_ARRAY_ADDRESS_NV 0x8F28 #define GL_ELEMENT_ARRAY_ADDRESS_NV 0x8F29 #define GL_VERTEX_ATTRIB_ARRAY_LENGTH_NV 0x8F2A #define GL_VERTEX_ARRAY_LENGTH_NV 0x8F2B #define GL_NORMAL_ARRAY_LENGTH_NV 0x8F2C #define GL_COLOR_ARRAY_LENGTH_NV 0x8F2D #define GL_INDEX_ARRAY_LENGTH_NV 0x8F2E #define GL_TEXTURE_COORD_ARRAY_LENGTH_NV 0x8F2F #define GL_EDGE_FLAG_ARRAY_LENGTH_NV 0x8F30 #define GL_SECONDARY_COLOR_ARRAY_LENGTH_NV 0x8F31 #define GL_FOG_COORD_ARRAY_LENGTH_NV 0x8F32 #define GL_ELEMENT_ARRAY_LENGTH_NV 0x8F33 #define GL_DRAW_INDIRECT_UNIFIED_NV 0x8F40 #define GL_DRAW_INDIRECT_ADDRESS_NV 0x8F41 #define GL_DRAW_INDIRECT_LENGTH_NV 0x8F42 typedef void (APIENTRYP PFNGLBUFFERADDRESSRANGENVPROC) (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length); typedef void (APIENTRYP PFNGLVERTEXFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); typedef void (APIENTRYP PFNGLNORMALFORMATNVPROC) (GLenum type, GLsizei stride); typedef void (APIENTRYP PFNGLCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); typedef void (APIENTRYP PFNGLINDEXFORMATNVPROC) (GLenum type, GLsizei stride); typedef void (APIENTRYP PFNGLTEXCOORDFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); typedef void (APIENTRYP PFNGLEDGEFLAGFORMATNVPROC) (GLsizei stride); typedef void (APIENTRYP PFNGLSECONDARYCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); typedef void (APIENTRYP PFNGLFOGCOORDFORMATNVPROC) (GLenum type, GLsizei stride); typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride); typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride); typedef void (APIENTRYP PFNGLGETINTEGERUI64I_VNVPROC) (GLenum value, GLuint index, GLuint64EXT *result); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBufferAddressRangeNV (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length); GLAPI void APIENTRY glVertexFormatNV (GLint size, GLenum type, GLsizei stride); GLAPI void APIENTRY glNormalFormatNV (GLenum type, GLsizei stride); GLAPI void APIENTRY glColorFormatNV (GLint size, GLenum type, GLsizei stride); GLAPI void APIENTRY glIndexFormatNV (GLenum type, GLsizei stride); GLAPI void APIENTRY glTexCoordFormatNV (GLint size, GLenum type, GLsizei stride); GLAPI void APIENTRY glEdgeFlagFormatNV (GLsizei stride); GLAPI void APIENTRY glSecondaryColorFormatNV (GLint size, GLenum type, GLsizei stride); GLAPI void APIENTRY glFogCoordFormatNV (GLenum type, GLsizei stride); GLAPI void APIENTRY glVertexAttribFormatNV (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride); GLAPI void APIENTRY glVertexAttribIFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride); GLAPI void APIENTRY glGetIntegerui64i_vNV (GLenum value, GLuint index, GLuint64EXT *result); #endif #endif /* GL_NV_vertex_buffer_unified_memory */ #ifndef GL_NV_vertex_program #define GL_NV_vertex_program 1 #define GL_VERTEX_PROGRAM_NV 0x8620 #define GL_VERTEX_STATE_PROGRAM_NV 0x8621 #define GL_ATTRIB_ARRAY_SIZE_NV 0x8623 #define GL_ATTRIB_ARRAY_STRIDE_NV 0x8624 #define GL_ATTRIB_ARRAY_TYPE_NV 0x8625 #define GL_CURRENT_ATTRIB_NV 0x8626 #define GL_PROGRAM_LENGTH_NV 0x8627 #define GL_PROGRAM_STRING_NV 0x8628 #define GL_MODELVIEW_PROJECTION_NV 0x8629 #define GL_IDENTITY_NV 0x862A #define GL_INVERSE_NV 0x862B #define GL_TRANSPOSE_NV 0x862C #define GL_INVERSE_TRANSPOSE_NV 0x862D #define GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E #define GL_MAX_TRACK_MATRICES_NV 0x862F #define GL_MATRIX0_NV 0x8630 #define GL_MATRIX1_NV 0x8631 #define GL_MATRIX2_NV 0x8632 #define GL_MATRIX3_NV 0x8633 #define GL_MATRIX4_NV 0x8634 #define GL_MATRIX5_NV 0x8635 #define GL_MATRIX6_NV 0x8636 #define GL_MATRIX7_NV 0x8637 #define GL_CURRENT_MATRIX_STACK_DEPTH_NV 0x8640 #define GL_CURRENT_MATRIX_NV 0x8641 #define GL_VERTEX_PROGRAM_POINT_SIZE_NV 0x8642 #define GL_VERTEX_PROGRAM_TWO_SIDE_NV 0x8643 #define GL_PROGRAM_PARAMETER_NV 0x8644 #define GL_ATTRIB_ARRAY_POINTER_NV 0x8645 #define GL_PROGRAM_TARGET_NV 0x8646 #define GL_PROGRAM_RESIDENT_NV 0x8647 #define GL_TRACK_MATRIX_NV 0x8648 #define GL_TRACK_MATRIX_TRANSFORM_NV 0x8649 #define GL_VERTEX_PROGRAM_BINDING_NV 0x864A #define GL_PROGRAM_ERROR_POSITION_NV 0x864B #define GL_VERTEX_ATTRIB_ARRAY0_NV 0x8650 #define GL_VERTEX_ATTRIB_ARRAY1_NV 0x8651 #define GL_VERTEX_ATTRIB_ARRAY2_NV 0x8652 #define GL_VERTEX_ATTRIB_ARRAY3_NV 0x8653 #define GL_VERTEX_ATTRIB_ARRAY4_NV 0x8654 #define GL_VERTEX_ATTRIB_ARRAY5_NV 0x8655 #define GL_VERTEX_ATTRIB_ARRAY6_NV 0x8656 #define GL_VERTEX_ATTRIB_ARRAY7_NV 0x8657 #define GL_VERTEX_ATTRIB_ARRAY8_NV 0x8658 #define GL_VERTEX_ATTRIB_ARRAY9_NV 0x8659 #define GL_VERTEX_ATTRIB_ARRAY10_NV 0x865A #define GL_VERTEX_ATTRIB_ARRAY11_NV 0x865B #define GL_VERTEX_ATTRIB_ARRAY12_NV 0x865C #define GL_VERTEX_ATTRIB_ARRAY13_NV 0x865D #define GL_VERTEX_ATTRIB_ARRAY14_NV 0x865E #define GL_VERTEX_ATTRIB_ARRAY15_NV 0x865F #define GL_MAP1_VERTEX_ATTRIB0_4_NV 0x8660 #define GL_MAP1_VERTEX_ATTRIB1_4_NV 0x8661 #define GL_MAP1_VERTEX_ATTRIB2_4_NV 0x8662 #define GL_MAP1_VERTEX_ATTRIB3_4_NV 0x8663 #define GL_MAP1_VERTEX_ATTRIB4_4_NV 0x8664 #define GL_MAP1_VERTEX_ATTRIB5_4_NV 0x8665 #define GL_MAP1_VERTEX_ATTRIB6_4_NV 0x8666 #define GL_MAP1_VERTEX_ATTRIB7_4_NV 0x8667 #define GL_MAP1_VERTEX_ATTRIB8_4_NV 0x8668 #define GL_MAP1_VERTEX_ATTRIB9_4_NV 0x8669 #define GL_MAP1_VERTEX_ATTRIB10_4_NV 0x866A #define GL_MAP1_VERTEX_ATTRIB11_4_NV 0x866B #define GL_MAP1_VERTEX_ATTRIB12_4_NV 0x866C #define GL_MAP1_VERTEX_ATTRIB13_4_NV 0x866D #define GL_MAP1_VERTEX_ATTRIB14_4_NV 0x866E #define GL_MAP1_VERTEX_ATTRIB15_4_NV 0x866F #define GL_MAP2_VERTEX_ATTRIB0_4_NV 0x8670 #define GL_MAP2_VERTEX_ATTRIB1_4_NV 0x8671 #define GL_MAP2_VERTEX_ATTRIB2_4_NV 0x8672 #define GL_MAP2_VERTEX_ATTRIB3_4_NV 0x8673 #define GL_MAP2_VERTEX_ATTRIB4_4_NV 0x8674 #define GL_MAP2_VERTEX_ATTRIB5_4_NV 0x8675 #define GL_MAP2_VERTEX_ATTRIB6_4_NV 0x8676 #define GL_MAP2_VERTEX_ATTRIB7_4_NV 0x8677 #define GL_MAP2_VERTEX_ATTRIB8_4_NV 0x8678 #define GL_MAP2_VERTEX_ATTRIB9_4_NV 0x8679 #define GL_MAP2_VERTEX_ATTRIB10_4_NV 0x867A #define GL_MAP2_VERTEX_ATTRIB11_4_NV 0x867B #define GL_MAP2_VERTEX_ATTRIB12_4_NV 0x867C #define GL_MAP2_VERTEX_ATTRIB13_4_NV 0x867D #define GL_MAP2_VERTEX_ATTRIB14_4_NV 0x867E #define GL_MAP2_VERTEX_ATTRIB15_4_NV 0x867F typedef GLboolean (APIENTRYP PFNGLAREPROGRAMSRESIDENTNVPROC) (GLsizei n, const GLuint *programs, GLboolean *residences); typedef void (APIENTRYP PFNGLBINDPROGRAMNVPROC) (GLenum target, GLuint id); typedef void (APIENTRYP PFNGLDELETEPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); typedef void (APIENTRYP PFNGLEXECUTEPROGRAMNVPROC) (GLenum target, GLuint id, const GLfloat *params); typedef void (APIENTRYP PFNGLGENPROGRAMSNVPROC) (GLsizei n, GLuint *programs); typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERDVNVPROC) (GLenum target, GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETPROGRAMIVNVPROC) (GLuint id, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGNVPROC) (GLuint id, GLenum pname, GLubyte *program); typedef void (APIENTRYP PFNGLGETTRACKMATRIXIVNVPROC) (GLenum target, GLuint address, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVNVPROC) (GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVNVPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVNVPROC) (GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, void **pointer); typedef GLboolean (APIENTRYP PFNGLISPROGRAMNVPROC) (GLuint id); typedef void (APIENTRYP PFNGLLOADPROGRAMNVPROC) (GLenum target, GLuint id, GLsizei len, const GLubyte *program); typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DNVPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DVNVPROC) (GLenum target, GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FNVPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FVNVPROC) (GLenum target, GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4DVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLdouble *v); typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4FVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLREQUESTRESIDENTPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); typedef void (APIENTRYP PFNGLTRACKMATRIXNVPROC) (GLenum target, GLuint address, GLenum matrix, GLenum transform); typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const void *pointer); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DNVPROC) (GLuint index, GLdouble x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVNVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FNVPROC) (GLuint index, GLfloat x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVNVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SNVPROC) (GLuint index, GLshort x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVNVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DNVPROC) (GLuint index, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVNVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FNVPROC) (GLuint index, GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVNVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SNVPROC) (GLuint index, GLshort x, GLshort y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVNVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVNVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVNVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVNVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVNVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVNVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVNVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBNVPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVNVPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS1DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS1FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS1SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS2DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS2FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS2SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS3DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS3FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS3SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS4DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS4FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS4SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS4UBVNVPROC) (GLuint index, GLsizei count, const GLubyte *v); #ifdef GL_GLEXT_PROTOTYPES GLAPI GLboolean APIENTRY glAreProgramsResidentNV (GLsizei n, const GLuint *programs, GLboolean *residences); GLAPI void APIENTRY glBindProgramNV (GLenum target, GLuint id); GLAPI void APIENTRY glDeleteProgramsNV (GLsizei n, const GLuint *programs); GLAPI void APIENTRY glExecuteProgramNV (GLenum target, GLuint id, const GLfloat *params); GLAPI void APIENTRY glGenProgramsNV (GLsizei n, GLuint *programs); GLAPI void APIENTRY glGetProgramParameterdvNV (GLenum target, GLuint index, GLenum pname, GLdouble *params); GLAPI void APIENTRY glGetProgramParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetProgramivNV (GLuint id, GLenum pname, GLint *params); GLAPI void APIENTRY glGetProgramStringNV (GLuint id, GLenum pname, GLubyte *program); GLAPI void APIENTRY glGetTrackMatrixivNV (GLenum target, GLuint address, GLenum pname, GLint *params); GLAPI void APIENTRY glGetVertexAttribdvNV (GLuint index, GLenum pname, GLdouble *params); GLAPI void APIENTRY glGetVertexAttribfvNV (GLuint index, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetVertexAttribivNV (GLuint index, GLenum pname, GLint *params); GLAPI void APIENTRY glGetVertexAttribPointervNV (GLuint index, GLenum pname, void **pointer); GLAPI GLboolean APIENTRY glIsProgramNV (GLuint id); GLAPI void APIENTRY glLoadProgramNV (GLenum target, GLuint id, GLsizei len, const GLubyte *program); GLAPI void APIENTRY glProgramParameter4dNV (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glProgramParameter4dvNV (GLenum target, GLuint index, const GLdouble *v); GLAPI void APIENTRY glProgramParameter4fNV (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glProgramParameter4fvNV (GLenum target, GLuint index, const GLfloat *v); GLAPI void APIENTRY glProgramParameters4dvNV (GLenum target, GLuint index, GLsizei count, const GLdouble *v); GLAPI void APIENTRY glProgramParameters4fvNV (GLenum target, GLuint index, GLsizei count, const GLfloat *v); GLAPI void APIENTRY glRequestResidentProgramsNV (GLsizei n, const GLuint *programs); GLAPI void APIENTRY glTrackMatrixNV (GLenum target, GLuint address, GLenum matrix, GLenum transform); GLAPI void APIENTRY glVertexAttribPointerNV (GLuint index, GLint fsize, GLenum type, GLsizei stride, const void *pointer); GLAPI void APIENTRY glVertexAttrib1dNV (GLuint index, GLdouble x); GLAPI void APIENTRY glVertexAttrib1dvNV (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib1fNV (GLuint index, GLfloat x); GLAPI void APIENTRY glVertexAttrib1fvNV (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib1sNV (GLuint index, GLshort x); GLAPI void APIENTRY glVertexAttrib1svNV (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib2dNV (GLuint index, GLdouble x, GLdouble y); GLAPI void APIENTRY glVertexAttrib2dvNV (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib2fNV (GLuint index, GLfloat x, GLfloat y); GLAPI void APIENTRY glVertexAttrib2fvNV (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib2sNV (GLuint index, GLshort x, GLshort y); GLAPI void APIENTRY glVertexAttrib2svNV (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib3dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glVertexAttrib3dvNV (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib3fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glVertexAttrib3fvNV (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib3sNV (GLuint index, GLshort x, GLshort y, GLshort z); GLAPI void APIENTRY glVertexAttrib3svNV (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib4dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glVertexAttrib4dvNV (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib4fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glVertexAttrib4fvNV (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib4sNV (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); GLAPI void APIENTRY glVertexAttrib4svNV (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib4ubNV (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); GLAPI void APIENTRY glVertexAttrib4ubvNV (GLuint index, const GLubyte *v); GLAPI void APIENTRY glVertexAttribs1dvNV (GLuint index, GLsizei count, const GLdouble *v); GLAPI void APIENTRY glVertexAttribs1fvNV (GLuint index, GLsizei count, const GLfloat *v); GLAPI void APIENTRY glVertexAttribs1svNV (GLuint index, GLsizei count, const GLshort *v); GLAPI void APIENTRY glVertexAttribs2dvNV (GLuint index, GLsizei count, const GLdouble *v); GLAPI void APIENTRY glVertexAttribs2fvNV (GLuint index, GLsizei count, const GLfloat *v); GLAPI void APIENTRY glVertexAttribs2svNV (GLuint index, GLsizei count, const GLshort *v); GLAPI void APIENTRY glVertexAttribs3dvNV (GLuint index, GLsizei count, const GLdouble *v); GLAPI void APIENTRY glVertexAttribs3fvNV (GLuint index, GLsizei count, const GLfloat *v); GLAPI void APIENTRY glVertexAttribs3svNV (GLuint index, GLsizei count, const GLshort *v); GLAPI void APIENTRY glVertexAttribs4dvNV (GLuint index, GLsizei count, const GLdouble *v); GLAPI void APIENTRY glVertexAttribs4fvNV (GLuint index, GLsizei count, const GLfloat *v); GLAPI void APIENTRY glVertexAttribs4svNV (GLuint index, GLsizei count, const GLshort *v); GLAPI void APIENTRY glVertexAttribs4ubvNV (GLuint index, GLsizei count, const GLubyte *v); #endif #endif /* GL_NV_vertex_program */ #ifndef GL_NV_vertex_program1_1 #define GL_NV_vertex_program1_1 1 #endif /* GL_NV_vertex_program1_1 */ #ifndef GL_NV_vertex_program2 #define GL_NV_vertex_program2 1 #endif /* GL_NV_vertex_program2 */ #ifndef GL_NV_vertex_program2_option #define GL_NV_vertex_program2_option 1 #endif /* GL_NV_vertex_program2_option */ #ifndef GL_NV_vertex_program3 #define GL_NV_vertex_program3 1 #endif /* GL_NV_vertex_program3 */ #ifndef GL_NV_vertex_program4 #define GL_NV_vertex_program4 1 #define GL_VERTEX_ATTRIB_ARRAY_INTEGER_NV 0x88FD typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IEXTPROC) (GLuint index, GLint x); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IEXTPROC) (GLuint index, GLint x, GLint y); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IEXTPROC) (GLuint index, GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IEXTPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIEXTPROC) (GLuint index, GLuint x); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIEXTPROC) (GLuint index, GLuint x, GLuint y); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVEXTPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVEXTPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVEXTPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVEXTPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVEXTPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVEXTPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVEXTPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVEXTPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVEXTPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVEXTPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVEXTPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVEXTPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVEXTPROC) (GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVEXTPROC) (GLuint index, GLenum pname, GLuint *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttribI1iEXT (GLuint index, GLint x); GLAPI void APIENTRY glVertexAttribI2iEXT (GLuint index, GLint x, GLint y); GLAPI void APIENTRY glVertexAttribI3iEXT (GLuint index, GLint x, GLint y, GLint z); GLAPI void APIENTRY glVertexAttribI4iEXT (GLuint index, GLint x, GLint y, GLint z, GLint w); GLAPI void APIENTRY glVertexAttribI1uiEXT (GLuint index, GLuint x); GLAPI void APIENTRY glVertexAttribI2uiEXT (GLuint index, GLuint x, GLuint y); GLAPI void APIENTRY glVertexAttribI3uiEXT (GLuint index, GLuint x, GLuint y, GLuint z); GLAPI void APIENTRY glVertexAttribI4uiEXT (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); GLAPI void APIENTRY glVertexAttribI1ivEXT (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttribI2ivEXT (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttribI3ivEXT (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttribI4ivEXT (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttribI1uivEXT (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttribI2uivEXT (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttribI3uivEXT (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttribI4uivEXT (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttribI4bvEXT (GLuint index, const GLbyte *v); GLAPI void APIENTRY glVertexAttribI4svEXT (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttribI4ubvEXT (GLuint index, const GLubyte *v); GLAPI void APIENTRY glVertexAttribI4usvEXT (GLuint index, const GLushort *v); GLAPI void APIENTRY glVertexAttribIPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); GLAPI void APIENTRY glGetVertexAttribIivEXT (GLuint index, GLenum pname, GLint *params); GLAPI void APIENTRY glGetVertexAttribIuivEXT (GLuint index, GLenum pname, GLuint *params); #endif #endif /* GL_NV_vertex_program4 */ #ifndef GL_NV_video_capture #define GL_NV_video_capture 1 #define GL_VIDEO_BUFFER_NV 0x9020 #define GL_VIDEO_BUFFER_BINDING_NV 0x9021 #define GL_FIELD_UPPER_NV 0x9022 #define GL_FIELD_LOWER_NV 0x9023 #define GL_NUM_VIDEO_CAPTURE_STREAMS_NV 0x9024 #define GL_NEXT_VIDEO_CAPTURE_BUFFER_STATUS_NV 0x9025 #define GL_VIDEO_CAPTURE_TO_422_SUPPORTED_NV 0x9026 #define GL_LAST_VIDEO_CAPTURE_STATUS_NV 0x9027 #define GL_VIDEO_BUFFER_PITCH_NV 0x9028 #define GL_VIDEO_COLOR_CONVERSION_MATRIX_NV 0x9029 #define GL_VIDEO_COLOR_CONVERSION_MAX_NV 0x902A #define GL_VIDEO_COLOR_CONVERSION_MIN_NV 0x902B #define GL_VIDEO_COLOR_CONVERSION_OFFSET_NV 0x902C #define GL_VIDEO_BUFFER_INTERNAL_FORMAT_NV 0x902D #define GL_PARTIAL_SUCCESS_NV 0x902E #define GL_SUCCESS_NV 0x902F #define GL_FAILURE_NV 0x9030 #define GL_YCBYCR8_422_NV 0x9031 #define GL_YCBAYCR8A_4224_NV 0x9032 #define GL_Z6Y10Z6CB10Z6Y10Z6CR10_422_NV 0x9033 #define GL_Z6Y10Z6CB10Z6A10Z6Y10Z6CR10Z6A10_4224_NV 0x9034 #define GL_Z4Y12Z4CB12Z4Y12Z4CR12_422_NV 0x9035 #define GL_Z4Y12Z4CB12Z4A12Z4Y12Z4CR12Z4A12_4224_NV 0x9036 #define GL_Z4Y12Z4CB12Z4CR12_444_NV 0x9037 #define GL_VIDEO_CAPTURE_FRAME_WIDTH_NV 0x9038 #define GL_VIDEO_CAPTURE_FRAME_HEIGHT_NV 0x9039 #define GL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV 0x903A #define GL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV 0x903B #define GL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV 0x903C typedef void (APIENTRYP PFNGLBEGINVIDEOCAPTURENVPROC) (GLuint video_capture_slot); typedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMBUFFERNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset); typedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMTEXTURENVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture); typedef void (APIENTRYP PFNGLENDVIDEOCAPTURENVPROC) (GLuint video_capture_slot); typedef void (APIENTRYP PFNGLGETVIDEOCAPTUREIVNVPROC) (GLuint video_capture_slot, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params); typedef GLenum (APIENTRYP PFNGLVIDEOCAPTURENVPROC) (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time); typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBeginVideoCaptureNV (GLuint video_capture_slot); GLAPI void APIENTRY glBindVideoCaptureStreamBufferNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset); GLAPI void APIENTRY glBindVideoCaptureStreamTextureNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture); GLAPI void APIENTRY glEndVideoCaptureNV (GLuint video_capture_slot); GLAPI void APIENTRY glGetVideoCaptureivNV (GLuint video_capture_slot, GLenum pname, GLint *params); GLAPI void APIENTRY glGetVideoCaptureStreamivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params); GLAPI void APIENTRY glGetVideoCaptureStreamfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetVideoCaptureStreamdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params); GLAPI GLenum APIENTRY glVideoCaptureNV (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time); GLAPI void APIENTRY glVideoCaptureStreamParameterivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params); GLAPI void APIENTRY glVideoCaptureStreamParameterfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glVideoCaptureStreamParameterdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params); #endif #endif /* GL_NV_video_capture */ #ifndef GL_NV_viewport_array2 #define GL_NV_viewport_array2 1 #endif /* GL_NV_viewport_array2 */ #ifndef GL_NV_viewport_swizzle #define GL_NV_viewport_swizzle 1 #define GL_VIEWPORT_SWIZZLE_POSITIVE_X_NV 0x9350 #define GL_VIEWPORT_SWIZZLE_NEGATIVE_X_NV 0x9351 #define GL_VIEWPORT_SWIZZLE_POSITIVE_Y_NV 0x9352 #define GL_VIEWPORT_SWIZZLE_NEGATIVE_Y_NV 0x9353 #define GL_VIEWPORT_SWIZZLE_POSITIVE_Z_NV 0x9354 #define GL_VIEWPORT_SWIZZLE_NEGATIVE_Z_NV 0x9355 #define GL_VIEWPORT_SWIZZLE_POSITIVE_W_NV 0x9356 #define GL_VIEWPORT_SWIZZLE_NEGATIVE_W_NV 0x9357 #define GL_VIEWPORT_SWIZZLE_X_NV 0x9358 #define GL_VIEWPORT_SWIZZLE_Y_NV 0x9359 #define GL_VIEWPORT_SWIZZLE_Z_NV 0x935A #define GL_VIEWPORT_SWIZZLE_W_NV 0x935B typedef void (APIENTRYP PFNGLVIEWPORTSWIZZLENVPROC) (GLuint index, GLenum swizzlex, GLenum swizzley, GLenum swizzlez, GLenum swizzlew); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glViewportSwizzleNV (GLuint index, GLenum swizzlex, GLenum swizzley, GLenum swizzlez, GLenum swizzlew); #endif #endif /* GL_NV_viewport_swizzle */ #ifndef GL_OML_interlace #define GL_OML_interlace 1 #define GL_INTERLACE_OML 0x8980 #define GL_INTERLACE_READ_OML 0x8981 #endif /* GL_OML_interlace */ #ifndef GL_OML_resample #define GL_OML_resample 1 #define GL_PACK_RESAMPLE_OML 0x8984 #define GL_UNPACK_RESAMPLE_OML 0x8985 #define GL_RESAMPLE_REPLICATE_OML 0x8986 #define GL_RESAMPLE_ZERO_FILL_OML 0x8987 #define GL_RESAMPLE_AVERAGE_OML 0x8988 #define GL_RESAMPLE_DECIMATE_OML 0x8989 #endif /* GL_OML_resample */ #ifndef GL_OML_subsample #define GL_OML_subsample 1 #define GL_FORMAT_SUBSAMPLE_24_24_OML 0x8982 #define GL_FORMAT_SUBSAMPLE_244_244_OML 0x8983 #endif /* GL_OML_subsample */ #ifndef GL_OVR_multiview #define GL_OVR_multiview 1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR 0x9630 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR 0x9632 #define GL_MAX_VIEWS_OVR 0x9631 #define GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR 0x9633 typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFramebufferTextureMultiviewOVR (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews); #endif #endif /* GL_OVR_multiview */ #ifndef GL_OVR_multiview2 #define GL_OVR_multiview2 1 #endif /* GL_OVR_multiview2 */ #ifndef GL_PGI_misc_hints #define GL_PGI_misc_hints 1 #define GL_PREFER_DOUBLEBUFFER_HINT_PGI 0x1A1F8 #define GL_CONSERVE_MEMORY_HINT_PGI 0x1A1FD #define GL_RECLAIM_MEMORY_HINT_PGI 0x1A1FE #define GL_NATIVE_GRAPHICS_HANDLE_PGI 0x1A202 #define GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 0x1A203 #define GL_NATIVE_GRAPHICS_END_HINT_PGI 0x1A204 #define GL_ALWAYS_FAST_HINT_PGI 0x1A20C #define GL_ALWAYS_SOFT_HINT_PGI 0x1A20D #define GL_ALLOW_DRAW_OBJ_HINT_PGI 0x1A20E #define GL_ALLOW_DRAW_WIN_HINT_PGI 0x1A20F #define GL_ALLOW_DRAW_FRG_HINT_PGI 0x1A210 #define GL_ALLOW_DRAW_MEM_HINT_PGI 0x1A211 #define GL_STRICT_DEPTHFUNC_HINT_PGI 0x1A216 #define GL_STRICT_LIGHTING_HINT_PGI 0x1A217 #define GL_STRICT_SCISSOR_HINT_PGI 0x1A218 #define GL_FULL_STIPPLE_HINT_PGI 0x1A219 #define GL_CLIP_NEAR_HINT_PGI 0x1A220 #define GL_CLIP_FAR_HINT_PGI 0x1A221 #define GL_WIDE_LINE_HINT_PGI 0x1A222 #define GL_BACK_NORMALS_HINT_PGI 0x1A223 typedef void (APIENTRYP PFNGLHINTPGIPROC) (GLenum target, GLint mode); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glHintPGI (GLenum target, GLint mode); #endif #endif /* GL_PGI_misc_hints */ #ifndef GL_PGI_vertex_hints #define GL_PGI_vertex_hints 1 #define GL_VERTEX_DATA_HINT_PGI 0x1A22A #define GL_VERTEX_CONSISTENT_HINT_PGI 0x1A22B #define GL_MATERIAL_SIDE_HINT_PGI 0x1A22C #define GL_MAX_VERTEX_HINT_PGI 0x1A22D #define GL_COLOR3_BIT_PGI 0x00010000 #define GL_COLOR4_BIT_PGI 0x00020000 #define GL_EDGEFLAG_BIT_PGI 0x00040000 #define GL_INDEX_BIT_PGI 0x00080000 #define GL_MAT_AMBIENT_BIT_PGI 0x00100000 #define GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000 #define GL_MAT_DIFFUSE_BIT_PGI 0x00400000 #define GL_MAT_EMISSION_BIT_PGI 0x00800000 #define GL_MAT_COLOR_INDEXES_BIT_PGI 0x01000000 #define GL_MAT_SHININESS_BIT_PGI 0x02000000 #define GL_MAT_SPECULAR_BIT_PGI 0x04000000 #define GL_NORMAL_BIT_PGI 0x08000000 #define GL_TEXCOORD1_BIT_PGI 0x10000000 #define GL_TEXCOORD2_BIT_PGI 0x20000000 #define GL_TEXCOORD3_BIT_PGI 0x40000000 #define GL_TEXCOORD4_BIT_PGI 0x80000000 #define GL_VERTEX23_BIT_PGI 0x00000004 #define GL_VERTEX4_BIT_PGI 0x00000008 #endif /* GL_PGI_vertex_hints */ #ifndef GL_REND_screen_coordinates #define GL_REND_screen_coordinates 1 #define GL_SCREEN_COORDINATES_REND 0x8490 #define GL_INVERTED_SCREEN_W_REND 0x8491 #endif /* GL_REND_screen_coordinates */ #ifndef GL_S3_s3tc #define GL_S3_s3tc 1 #define GL_RGB_S3TC 0x83A0 #define GL_RGB4_S3TC 0x83A1 #define GL_RGBA_S3TC 0x83A2 #define GL_RGBA4_S3TC 0x83A3 #define GL_RGBA_DXT5_S3TC 0x83A4 #define GL_RGBA4_DXT5_S3TC 0x83A5 #endif /* GL_S3_s3tc */ #ifndef GL_SGIS_detail_texture #define GL_SGIS_detail_texture 1 #define GL_DETAIL_TEXTURE_2D_SGIS 0x8095 #define GL_DETAIL_TEXTURE_2D_BINDING_SGIS 0x8096 #define GL_LINEAR_DETAIL_SGIS 0x8097 #define GL_LINEAR_DETAIL_ALPHA_SGIS 0x8098 #define GL_LINEAR_DETAIL_COLOR_SGIS 0x8099 #define GL_DETAIL_TEXTURE_LEVEL_SGIS 0x809A #define GL_DETAIL_TEXTURE_MODE_SGIS 0x809B #define GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS 0x809C typedef void (APIENTRYP PFNGLDETAILTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); typedef void (APIENTRYP PFNGLGETDETAILTEXFUNCSGISPROC) (GLenum target, GLfloat *points); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDetailTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points); GLAPI void APIENTRY glGetDetailTexFuncSGIS (GLenum target, GLfloat *points); #endif #endif /* GL_SGIS_detail_texture */ #ifndef GL_SGIS_fog_function #define GL_SGIS_fog_function 1 #define GL_FOG_FUNC_SGIS 0x812A #define GL_FOG_FUNC_POINTS_SGIS 0x812B #define GL_MAX_FOG_FUNC_POINTS_SGIS 0x812C typedef void (APIENTRYP PFNGLFOGFUNCSGISPROC) (GLsizei n, const GLfloat *points); typedef void (APIENTRYP PFNGLGETFOGFUNCSGISPROC) (GLfloat *points); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFogFuncSGIS (GLsizei n, const GLfloat *points); GLAPI void APIENTRY glGetFogFuncSGIS (GLfloat *points); #endif #endif /* GL_SGIS_fog_function */ #ifndef GL_SGIS_generate_mipmap #define GL_SGIS_generate_mipmap 1 #define GL_GENERATE_MIPMAP_SGIS 0x8191 #define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192 #endif /* GL_SGIS_generate_mipmap */ #ifndef GL_SGIS_multisample #define GL_SGIS_multisample 1 #define GL_MULTISAMPLE_SGIS 0x809D #define GL_SAMPLE_ALPHA_TO_MASK_SGIS 0x809E #define GL_SAMPLE_ALPHA_TO_ONE_SGIS 0x809F #define GL_SAMPLE_MASK_SGIS 0x80A0 #define GL_1PASS_SGIS 0x80A1 #define GL_2PASS_0_SGIS 0x80A2 #define GL_2PASS_1_SGIS 0x80A3 #define GL_4PASS_0_SGIS 0x80A4 #define GL_4PASS_1_SGIS 0x80A5 #define GL_4PASS_2_SGIS 0x80A6 #define GL_4PASS_3_SGIS 0x80A7 #define GL_SAMPLE_BUFFERS_SGIS 0x80A8 #define GL_SAMPLES_SGIS 0x80A9 #define GL_SAMPLE_MASK_VALUE_SGIS 0x80AA #define GL_SAMPLE_MASK_INVERT_SGIS 0x80AB #define GL_SAMPLE_PATTERN_SGIS 0x80AC typedef void (APIENTRYP PFNGLSAMPLEMASKSGISPROC) (GLclampf value, GLboolean invert); typedef void (APIENTRYP PFNGLSAMPLEPATTERNSGISPROC) (GLenum pattern); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSampleMaskSGIS (GLclampf value, GLboolean invert); GLAPI void APIENTRY glSamplePatternSGIS (GLenum pattern); #endif #endif /* GL_SGIS_multisample */ #ifndef GL_SGIS_pixel_texture #define GL_SGIS_pixel_texture 1 #define GL_PIXEL_TEXTURE_SGIS 0x8353 #define GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS 0x8354 #define GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS 0x8355 #define GL_PIXEL_GROUP_COLOR_SGIS 0x8356 typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERISGISPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFSGISPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, GLfloat *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPixelTexGenParameteriSGIS (GLenum pname, GLint param); GLAPI void APIENTRY glPixelTexGenParameterivSGIS (GLenum pname, const GLint *params); GLAPI void APIENTRY glPixelTexGenParameterfSGIS (GLenum pname, GLfloat param); GLAPI void APIENTRY glPixelTexGenParameterfvSGIS (GLenum pname, const GLfloat *params); GLAPI void APIENTRY glGetPixelTexGenParameterivSGIS (GLenum pname, GLint *params); GLAPI void APIENTRY glGetPixelTexGenParameterfvSGIS (GLenum pname, GLfloat *params); #endif #endif /* GL_SGIS_pixel_texture */ #ifndef GL_SGIS_point_line_texgen #define GL_SGIS_point_line_texgen 1 #define GL_EYE_DISTANCE_TO_POINT_SGIS 0x81F0 #define GL_OBJECT_DISTANCE_TO_POINT_SGIS 0x81F1 #define GL_EYE_DISTANCE_TO_LINE_SGIS 0x81F2 #define GL_OBJECT_DISTANCE_TO_LINE_SGIS 0x81F3 #define GL_EYE_POINT_SGIS 0x81F4 #define GL_OBJECT_POINT_SGIS 0x81F5 #define GL_EYE_LINE_SGIS 0x81F6 #define GL_OBJECT_LINE_SGIS 0x81F7 #endif /* GL_SGIS_point_line_texgen */ #ifndef GL_SGIS_point_parameters #define GL_SGIS_point_parameters 1 #define GL_POINT_SIZE_MIN_SGIS 0x8126 #define GL_POINT_SIZE_MAX_SGIS 0x8127 #define GL_POINT_FADE_THRESHOLD_SIZE_SGIS 0x8128 #define GL_DISTANCE_ATTENUATION_SGIS 0x8129 typedef void (APIENTRYP PFNGLPOINTPARAMETERFSGISPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPOINTPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPointParameterfSGIS (GLenum pname, GLfloat param); GLAPI void APIENTRY glPointParameterfvSGIS (GLenum pname, const GLfloat *params); #endif #endif /* GL_SGIS_point_parameters */ #ifndef GL_SGIS_sharpen_texture #define GL_SGIS_sharpen_texture 1 #define GL_LINEAR_SHARPEN_SGIS 0x80AD #define GL_LINEAR_SHARPEN_ALPHA_SGIS 0x80AE #define GL_LINEAR_SHARPEN_COLOR_SGIS 0x80AF #define GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS 0x80B0 typedef void (APIENTRYP PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); typedef void (APIENTRYP PFNGLGETSHARPENTEXFUNCSGISPROC) (GLenum target, GLfloat *points); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSharpenTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points); GLAPI void APIENTRY glGetSharpenTexFuncSGIS (GLenum target, GLfloat *points); #endif #endif /* GL_SGIS_sharpen_texture */ #ifndef GL_SGIS_texture4D #define GL_SGIS_texture4D 1 #define GL_PACK_SKIP_VOLUMES_SGIS 0x8130 #define GL_PACK_IMAGE_DEPTH_SGIS 0x8131 #define GL_UNPACK_SKIP_VOLUMES_SGIS 0x8132 #define GL_UNPACK_IMAGE_DEPTH_SGIS 0x8133 #define GL_TEXTURE_4D_SGIS 0x8134 #define GL_PROXY_TEXTURE_4D_SGIS 0x8135 #define GL_TEXTURE_4DSIZE_SGIS 0x8136 #define GL_TEXTURE_WRAP_Q_SGIS 0x8137 #define GL_MAX_4D_TEXTURE_SIZE_SGIS 0x8138 #define GL_TEXTURE_4D_BINDING_SGIS 0x814F typedef void (APIENTRYP PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const void *pixels); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexImage4DSGIS (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glTexSubImage4DSGIS (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const void *pixels); #endif #endif /* GL_SGIS_texture4D */ #ifndef GL_SGIS_texture_border_clamp #define GL_SGIS_texture_border_clamp 1 #define GL_CLAMP_TO_BORDER_SGIS 0x812D #endif /* GL_SGIS_texture_border_clamp */ #ifndef GL_SGIS_texture_color_mask #define GL_SGIS_texture_color_mask 1 #define GL_TEXTURE_COLOR_WRITEMASK_SGIS 0x81EF typedef void (APIENTRYP PFNGLTEXTURECOLORMASKSGISPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTextureColorMaskSGIS (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); #endif #endif /* GL_SGIS_texture_color_mask */ #ifndef GL_SGIS_texture_edge_clamp #define GL_SGIS_texture_edge_clamp 1 #define GL_CLAMP_TO_EDGE_SGIS 0x812F #endif /* GL_SGIS_texture_edge_clamp */ #ifndef GL_SGIS_texture_filter4 #define GL_SGIS_texture_filter4 1 #define GL_FILTER4_SGIS 0x8146 #define GL_TEXTURE_FILTER4_SIZE_SGIS 0x8147 typedef void (APIENTRYP PFNGLGETTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLfloat *weights); typedef void (APIENTRYP PFNGLTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetTexFilterFuncSGIS (GLenum target, GLenum filter, GLfloat *weights); GLAPI void APIENTRY glTexFilterFuncSGIS (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); #endif #endif /* GL_SGIS_texture_filter4 */ #ifndef GL_SGIS_texture_lod #define GL_SGIS_texture_lod 1 #define GL_TEXTURE_MIN_LOD_SGIS 0x813A #define GL_TEXTURE_MAX_LOD_SGIS 0x813B #define GL_TEXTURE_BASE_LEVEL_SGIS 0x813C #define GL_TEXTURE_MAX_LEVEL_SGIS 0x813D #endif /* GL_SGIS_texture_lod */ #ifndef GL_SGIS_texture_select #define GL_SGIS_texture_select 1 #define GL_DUAL_ALPHA4_SGIS 0x8110 #define GL_DUAL_ALPHA8_SGIS 0x8111 #define GL_DUAL_ALPHA12_SGIS 0x8112 #define GL_DUAL_ALPHA16_SGIS 0x8113 #define GL_DUAL_LUMINANCE4_SGIS 0x8114 #define GL_DUAL_LUMINANCE8_SGIS 0x8115 #define GL_DUAL_LUMINANCE12_SGIS 0x8116 #define GL_DUAL_LUMINANCE16_SGIS 0x8117 #define GL_DUAL_INTENSITY4_SGIS 0x8118 #define GL_DUAL_INTENSITY8_SGIS 0x8119 #define GL_DUAL_INTENSITY12_SGIS 0x811A #define GL_DUAL_INTENSITY16_SGIS 0x811B #define GL_DUAL_LUMINANCE_ALPHA4_SGIS 0x811C #define GL_DUAL_LUMINANCE_ALPHA8_SGIS 0x811D #define GL_QUAD_ALPHA4_SGIS 0x811E #define GL_QUAD_ALPHA8_SGIS 0x811F #define GL_QUAD_LUMINANCE4_SGIS 0x8120 #define GL_QUAD_LUMINANCE8_SGIS 0x8121 #define GL_QUAD_INTENSITY4_SGIS 0x8122 #define GL_QUAD_INTENSITY8_SGIS 0x8123 #define GL_DUAL_TEXTURE_SELECT_SGIS 0x8124 #define GL_QUAD_TEXTURE_SELECT_SGIS 0x8125 #endif /* GL_SGIS_texture_select */ #ifndef GL_SGIX_async #define GL_SGIX_async 1 #define GL_ASYNC_MARKER_SGIX 0x8329 typedef void (APIENTRYP PFNGLASYNCMARKERSGIXPROC) (GLuint marker); typedef GLint (APIENTRYP PFNGLFINISHASYNCSGIXPROC) (GLuint *markerp); typedef GLint (APIENTRYP PFNGLPOLLASYNCSGIXPROC) (GLuint *markerp); typedef GLuint (APIENTRYP PFNGLGENASYNCMARKERSSGIXPROC) (GLsizei range); typedef void (APIENTRYP PFNGLDELETEASYNCMARKERSSGIXPROC) (GLuint marker, GLsizei range); typedef GLboolean (APIENTRYP PFNGLISASYNCMARKERSGIXPROC) (GLuint marker); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glAsyncMarkerSGIX (GLuint marker); GLAPI GLint APIENTRY glFinishAsyncSGIX (GLuint *markerp); GLAPI GLint APIENTRY glPollAsyncSGIX (GLuint *markerp); GLAPI GLuint APIENTRY glGenAsyncMarkersSGIX (GLsizei range); GLAPI void APIENTRY glDeleteAsyncMarkersSGIX (GLuint marker, GLsizei range); GLAPI GLboolean APIENTRY glIsAsyncMarkerSGIX (GLuint marker); #endif #endif /* GL_SGIX_async */ #ifndef GL_SGIX_async_histogram #define GL_SGIX_async_histogram 1 #define GL_ASYNC_HISTOGRAM_SGIX 0x832C #define GL_MAX_ASYNC_HISTOGRAM_SGIX 0x832D #endif /* GL_SGIX_async_histogram */ #ifndef GL_SGIX_async_pixel #define GL_SGIX_async_pixel 1 #define GL_ASYNC_TEX_IMAGE_SGIX 0x835C #define GL_ASYNC_DRAW_PIXELS_SGIX 0x835D #define GL_ASYNC_READ_PIXELS_SGIX 0x835E #define GL_MAX_ASYNC_TEX_IMAGE_SGIX 0x835F #define GL_MAX_ASYNC_DRAW_PIXELS_SGIX 0x8360 #define GL_MAX_ASYNC_READ_PIXELS_SGIX 0x8361 #endif /* GL_SGIX_async_pixel */ #ifndef GL_SGIX_blend_alpha_minmax #define GL_SGIX_blend_alpha_minmax 1 #define GL_ALPHA_MIN_SGIX 0x8320 #define GL_ALPHA_MAX_SGIX 0x8321 #endif /* GL_SGIX_blend_alpha_minmax */ #ifndef GL_SGIX_calligraphic_fragment #define GL_SGIX_calligraphic_fragment 1 #define GL_CALLIGRAPHIC_FRAGMENT_SGIX 0x8183 #endif /* GL_SGIX_calligraphic_fragment */ #ifndef GL_SGIX_clipmap #define GL_SGIX_clipmap 1 #define GL_LINEAR_CLIPMAP_LINEAR_SGIX 0x8170 #define GL_TEXTURE_CLIPMAP_CENTER_SGIX 0x8171 #define GL_TEXTURE_CLIPMAP_FRAME_SGIX 0x8172 #define GL_TEXTURE_CLIPMAP_OFFSET_SGIX 0x8173 #define GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8174 #define GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX 0x8175 #define GL_TEXTURE_CLIPMAP_DEPTH_SGIX 0x8176 #define GL_MAX_CLIPMAP_DEPTH_SGIX 0x8177 #define GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8178 #define GL_NEAREST_CLIPMAP_NEAREST_SGIX 0x844D #define GL_NEAREST_CLIPMAP_LINEAR_SGIX 0x844E #define GL_LINEAR_CLIPMAP_NEAREST_SGIX 0x844F #endif /* GL_SGIX_clipmap */ #ifndef GL_SGIX_convolution_accuracy #define GL_SGIX_convolution_accuracy 1 #define GL_CONVOLUTION_HINT_SGIX 0x8316 #endif /* GL_SGIX_convolution_accuracy */ #ifndef GL_SGIX_depth_pass_instrument #define GL_SGIX_depth_pass_instrument 1 #endif /* GL_SGIX_depth_pass_instrument */ #ifndef GL_SGIX_depth_texture #define GL_SGIX_depth_texture 1 #define GL_DEPTH_COMPONENT16_SGIX 0x81A5 #define GL_DEPTH_COMPONENT24_SGIX 0x81A6 #define GL_DEPTH_COMPONENT32_SGIX 0x81A7 #endif /* GL_SGIX_depth_texture */ #ifndef GL_SGIX_flush_raster #define GL_SGIX_flush_raster 1 typedef void (APIENTRYP PFNGLFLUSHRASTERSGIXPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFlushRasterSGIX (void); #endif #endif /* GL_SGIX_flush_raster */ #ifndef GL_SGIX_fog_offset #define GL_SGIX_fog_offset 1 #define GL_FOG_OFFSET_SGIX 0x8198 #define GL_FOG_OFFSET_VALUE_SGIX 0x8199 #endif /* GL_SGIX_fog_offset */ #ifndef GL_SGIX_fragment_lighting #define GL_SGIX_fragment_lighting 1 #define GL_FRAGMENT_LIGHTING_SGIX 0x8400 #define GL_FRAGMENT_COLOR_MATERIAL_SGIX 0x8401 #define GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX 0x8402 #define GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX 0x8403 #define GL_MAX_FRAGMENT_LIGHTS_SGIX 0x8404 #define GL_MAX_ACTIVE_LIGHTS_SGIX 0x8405 #define GL_CURRENT_RASTER_NORMAL_SGIX 0x8406 #define GL_LIGHT_ENV_MODE_SGIX 0x8407 #define GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX 0x8408 #define GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX 0x8409 #define GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX 0x840A #define GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX 0x840B #define GL_FRAGMENT_LIGHT0_SGIX 0x840C #define GL_FRAGMENT_LIGHT1_SGIX 0x840D #define GL_FRAGMENT_LIGHT2_SGIX 0x840E #define GL_FRAGMENT_LIGHT3_SGIX 0x840F #define GL_FRAGMENT_LIGHT4_SGIX 0x8410 #define GL_FRAGMENT_LIGHT5_SGIX 0x8411 #define GL_FRAGMENT_LIGHT6_SGIX 0x8412 #define GL_FRAGMENT_LIGHT7_SGIX 0x8413 typedef void (APIENTRYP PFNGLFRAGMENTCOLORMATERIALSGIXPROC) (GLenum face, GLenum mode); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFSGIXPROC) (GLenum light, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTISGIXPROC) (GLenum light, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFSGIXPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFVSGIXPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELISGIXPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELIVSGIXPROC) (GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFSGIXPROC) (GLenum face, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLFRAGMENTMATERIALISGIXPROC) (GLenum face, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLLIGHTENVISGIXPROC) (GLenum pname, GLint param); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFragmentColorMaterialSGIX (GLenum face, GLenum mode); GLAPI void APIENTRY glFragmentLightfSGIX (GLenum light, GLenum pname, GLfloat param); GLAPI void APIENTRY glFragmentLightfvSGIX (GLenum light, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glFragmentLightiSGIX (GLenum light, GLenum pname, GLint param); GLAPI void APIENTRY glFragmentLightivSGIX (GLenum light, GLenum pname, const GLint *params); GLAPI void APIENTRY glFragmentLightModelfSGIX (GLenum pname, GLfloat param); GLAPI void APIENTRY glFragmentLightModelfvSGIX (GLenum pname, const GLfloat *params); GLAPI void APIENTRY glFragmentLightModeliSGIX (GLenum pname, GLint param); GLAPI void APIENTRY glFragmentLightModelivSGIX (GLenum pname, const GLint *params); GLAPI void APIENTRY glFragmentMaterialfSGIX (GLenum face, GLenum pname, GLfloat param); GLAPI void APIENTRY glFragmentMaterialfvSGIX (GLenum face, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glFragmentMaterialiSGIX (GLenum face, GLenum pname, GLint param); GLAPI void APIENTRY glFragmentMaterialivSGIX (GLenum face, GLenum pname, const GLint *params); GLAPI void APIENTRY glGetFragmentLightfvSGIX (GLenum light, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetFragmentLightivSGIX (GLenum light, GLenum pname, GLint *params); GLAPI void APIENTRY glGetFragmentMaterialfvSGIX (GLenum face, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetFragmentMaterialivSGIX (GLenum face, GLenum pname, GLint *params); GLAPI void APIENTRY glLightEnviSGIX (GLenum pname, GLint param); #endif #endif /* GL_SGIX_fragment_lighting */ #ifndef GL_SGIX_framezoom #define GL_SGIX_framezoom 1 #define GL_FRAMEZOOM_SGIX 0x818B #define GL_FRAMEZOOM_FACTOR_SGIX 0x818C #define GL_MAX_FRAMEZOOM_FACTOR_SGIX 0x818D typedef void (APIENTRYP PFNGLFRAMEZOOMSGIXPROC) (GLint factor); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFrameZoomSGIX (GLint factor); #endif #endif /* GL_SGIX_framezoom */ #ifndef GL_SGIX_igloo_interface #define GL_SGIX_igloo_interface 1 typedef void (APIENTRYP PFNGLIGLOOINTERFACESGIXPROC) (GLenum pname, const void *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glIglooInterfaceSGIX (GLenum pname, const void *params); #endif #endif /* GL_SGIX_igloo_interface */ #ifndef GL_SGIX_instruments #define GL_SGIX_instruments 1 #define GL_INSTRUMENT_BUFFER_POINTER_SGIX 0x8180 #define GL_INSTRUMENT_MEASUREMENTS_SGIX 0x8181 typedef GLint (APIENTRYP PFNGLGETINSTRUMENTSSGIXPROC) (void); typedef void (APIENTRYP PFNGLINSTRUMENTSBUFFERSGIXPROC) (GLsizei size, GLint *buffer); typedef GLint (APIENTRYP PFNGLPOLLINSTRUMENTSSGIXPROC) (GLint *marker_p); typedef void (APIENTRYP PFNGLREADINSTRUMENTSSGIXPROC) (GLint marker); typedef void (APIENTRYP PFNGLSTARTINSTRUMENTSSGIXPROC) (void); typedef void (APIENTRYP PFNGLSTOPINSTRUMENTSSGIXPROC) (GLint marker); #ifdef GL_GLEXT_PROTOTYPES GLAPI GLint APIENTRY glGetInstrumentsSGIX (void); GLAPI void APIENTRY glInstrumentsBufferSGIX (GLsizei size, GLint *buffer); GLAPI GLint APIENTRY glPollInstrumentsSGIX (GLint *marker_p); GLAPI void APIENTRY glReadInstrumentsSGIX (GLint marker); GLAPI void APIENTRY glStartInstrumentsSGIX (void); GLAPI void APIENTRY glStopInstrumentsSGIX (GLint marker); #endif #endif /* GL_SGIX_instruments */ #ifndef GL_SGIX_interlace #define GL_SGIX_interlace 1 #define GL_INTERLACE_SGIX 0x8094 #endif /* GL_SGIX_interlace */ #ifndef GL_SGIX_ir_instrument1 #define GL_SGIX_ir_instrument1 1 #define GL_IR_INSTRUMENT1_SGIX 0x817F #endif /* GL_SGIX_ir_instrument1 */ #ifndef GL_SGIX_list_priority #define GL_SGIX_list_priority 1 #define GL_LIST_PRIORITY_SGIX 0x8182 typedef void (APIENTRYP PFNGLGETLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLLISTPARAMETERFSGIXPROC) (GLuint list, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLLISTPARAMETERISGIXPROC) (GLuint list, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, const GLint *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetListParameterfvSGIX (GLuint list, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetListParameterivSGIX (GLuint list, GLenum pname, GLint *params); GLAPI void APIENTRY glListParameterfSGIX (GLuint list, GLenum pname, GLfloat param); GLAPI void APIENTRY glListParameterfvSGIX (GLuint list, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glListParameteriSGIX (GLuint list, GLenum pname, GLint param); GLAPI void APIENTRY glListParameterivSGIX (GLuint list, GLenum pname, const GLint *params); #endif #endif /* GL_SGIX_list_priority */ #ifndef GL_SGIX_pixel_texture #define GL_SGIX_pixel_texture 1 #define GL_PIXEL_TEX_GEN_SGIX 0x8139 #define GL_PIXEL_TEX_GEN_MODE_SGIX 0x832B typedef void (APIENTRYP PFNGLPIXELTEXGENSGIXPROC) (GLenum mode); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPixelTexGenSGIX (GLenum mode); #endif #endif /* GL_SGIX_pixel_texture */ #ifndef GL_SGIX_pixel_tiles #define GL_SGIX_pixel_tiles 1 #define GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX 0x813E #define GL_PIXEL_TILE_CACHE_INCREMENT_SGIX 0x813F #define GL_PIXEL_TILE_WIDTH_SGIX 0x8140 #define GL_PIXEL_TILE_HEIGHT_SGIX 0x8141 #define GL_PIXEL_TILE_GRID_WIDTH_SGIX 0x8142 #define GL_PIXEL_TILE_GRID_HEIGHT_SGIX 0x8143 #define GL_PIXEL_TILE_GRID_DEPTH_SGIX 0x8144 #define GL_PIXEL_TILE_CACHE_SIZE_SGIX 0x8145 #endif /* GL_SGIX_pixel_tiles */ #ifndef GL_SGIX_polynomial_ffd #define GL_SGIX_polynomial_ffd 1 #define GL_TEXTURE_DEFORMATION_BIT_SGIX 0x00000001 #define GL_GEOMETRY_DEFORMATION_BIT_SGIX 0x00000002 #define GL_GEOMETRY_DEFORMATION_SGIX 0x8194 #define GL_TEXTURE_DEFORMATION_SGIX 0x8195 #define GL_DEFORMATIONS_MASK_SGIX 0x8196 #define GL_MAX_DEFORMATION_ORDER_SGIX 0x8197 typedef void (APIENTRYP PFNGLDEFORMATIONMAP3DSGIXPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); typedef void (APIENTRYP PFNGLDEFORMATIONMAP3FSGIXPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); typedef void (APIENTRYP PFNGLDEFORMSGIXPROC) (GLbitfield mask); typedef void (APIENTRYP PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC) (GLbitfield mask); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDeformationMap3dSGIX (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); GLAPI void APIENTRY glDeformationMap3fSGIX (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); GLAPI void APIENTRY glDeformSGIX (GLbitfield mask); GLAPI void APIENTRY glLoadIdentityDeformationMapSGIX (GLbitfield mask); #endif #endif /* GL_SGIX_polynomial_ffd */ #ifndef GL_SGIX_reference_plane #define GL_SGIX_reference_plane 1 #define GL_REFERENCE_PLANE_SGIX 0x817D #define GL_REFERENCE_PLANE_EQUATION_SGIX 0x817E typedef void (APIENTRYP PFNGLREFERENCEPLANESGIXPROC) (const GLdouble *equation); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glReferencePlaneSGIX (const GLdouble *equation); #endif #endif /* GL_SGIX_reference_plane */ #ifndef GL_SGIX_resample #define GL_SGIX_resample 1 #define GL_PACK_RESAMPLE_SGIX 0x842E #define GL_UNPACK_RESAMPLE_SGIX 0x842F #define GL_RESAMPLE_REPLICATE_SGIX 0x8433 #define GL_RESAMPLE_ZERO_FILL_SGIX 0x8434 #define GL_RESAMPLE_DECIMATE_SGIX 0x8430 #endif /* GL_SGIX_resample */ #ifndef GL_SGIX_scalebias_hint #define GL_SGIX_scalebias_hint 1 #define GL_SCALEBIAS_HINT_SGIX 0x8322 #endif /* GL_SGIX_scalebias_hint */ #ifndef GL_SGIX_shadow #define GL_SGIX_shadow 1 #define GL_TEXTURE_COMPARE_SGIX 0x819A #define GL_TEXTURE_COMPARE_OPERATOR_SGIX 0x819B #define GL_TEXTURE_LEQUAL_R_SGIX 0x819C #define GL_TEXTURE_GEQUAL_R_SGIX 0x819D #endif /* GL_SGIX_shadow */ #ifndef GL_SGIX_shadow_ambient #define GL_SGIX_shadow_ambient 1 #define GL_SHADOW_AMBIENT_SGIX 0x80BF #endif /* GL_SGIX_shadow_ambient */ #ifndef GL_SGIX_sprite #define GL_SGIX_sprite 1 #define GL_SPRITE_SGIX 0x8148 #define GL_SPRITE_MODE_SGIX 0x8149 #define GL_SPRITE_AXIS_SGIX 0x814A #define GL_SPRITE_TRANSLATION_SGIX 0x814B #define GL_SPRITE_AXIAL_SGIX 0x814C #define GL_SPRITE_OBJECT_ALIGNED_SGIX 0x814D #define GL_SPRITE_EYE_ALIGNED_SGIX 0x814E typedef void (APIENTRYP PFNGLSPRITEPARAMETERFSGIXPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLSPRITEPARAMETERFVSGIXPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLSPRITEPARAMETERISGIXPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLSPRITEPARAMETERIVSGIXPROC) (GLenum pname, const GLint *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSpriteParameterfSGIX (GLenum pname, GLfloat param); GLAPI void APIENTRY glSpriteParameterfvSGIX (GLenum pname, const GLfloat *params); GLAPI void APIENTRY glSpriteParameteriSGIX (GLenum pname, GLint param); GLAPI void APIENTRY glSpriteParameterivSGIX (GLenum pname, const GLint *params); #endif #endif /* GL_SGIX_sprite */ #ifndef GL_SGIX_subsample #define GL_SGIX_subsample 1 #define GL_PACK_SUBSAMPLE_RATE_SGIX 0x85A0 #define GL_UNPACK_SUBSAMPLE_RATE_SGIX 0x85A1 #define GL_PIXEL_SUBSAMPLE_4444_SGIX 0x85A2 #define GL_PIXEL_SUBSAMPLE_2424_SGIX 0x85A3 #define GL_PIXEL_SUBSAMPLE_4242_SGIX 0x85A4 #endif /* GL_SGIX_subsample */ #ifndef GL_SGIX_tag_sample_buffer #define GL_SGIX_tag_sample_buffer 1 typedef void (APIENTRYP PFNGLTAGSAMPLEBUFFERSGIXPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTagSampleBufferSGIX (void); #endif #endif /* GL_SGIX_tag_sample_buffer */ #ifndef GL_SGIX_texture_add_env #define GL_SGIX_texture_add_env 1 #define GL_TEXTURE_ENV_BIAS_SGIX 0x80BE #endif /* GL_SGIX_texture_add_env */ #ifndef GL_SGIX_texture_coordinate_clamp #define GL_SGIX_texture_coordinate_clamp 1 #define GL_TEXTURE_MAX_CLAMP_S_SGIX 0x8369 #define GL_TEXTURE_MAX_CLAMP_T_SGIX 0x836A #define GL_TEXTURE_MAX_CLAMP_R_SGIX 0x836B #endif /* GL_SGIX_texture_coordinate_clamp */ #ifndef GL_SGIX_texture_lod_bias #define GL_SGIX_texture_lod_bias 1 #define GL_TEXTURE_LOD_BIAS_S_SGIX 0x818E #define GL_TEXTURE_LOD_BIAS_T_SGIX 0x818F #define GL_TEXTURE_LOD_BIAS_R_SGIX 0x8190 #endif /* GL_SGIX_texture_lod_bias */ #ifndef GL_SGIX_texture_multi_buffer #define GL_SGIX_texture_multi_buffer 1 #define GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E #endif /* GL_SGIX_texture_multi_buffer */ #ifndef GL_SGIX_texture_scale_bias #define GL_SGIX_texture_scale_bias 1 #define GL_POST_TEXTURE_FILTER_BIAS_SGIX 0x8179 #define GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A #define GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B #define GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C #endif /* GL_SGIX_texture_scale_bias */ #ifndef GL_SGIX_vertex_preclip #define GL_SGIX_vertex_preclip 1 #define GL_VERTEX_PRECLIP_SGIX 0x83EE #define GL_VERTEX_PRECLIP_HINT_SGIX 0x83EF #endif /* GL_SGIX_vertex_preclip */ #ifndef GL_SGIX_ycrcb #define GL_SGIX_ycrcb 1 #define GL_YCRCB_422_SGIX 0x81BB #define GL_YCRCB_444_SGIX 0x81BC #endif /* GL_SGIX_ycrcb */ #ifndef GL_SGIX_ycrcb_subsample #define GL_SGIX_ycrcb_subsample 1 #endif /* GL_SGIX_ycrcb_subsample */ #ifndef GL_SGIX_ycrcba #define GL_SGIX_ycrcba 1 #define GL_YCRCB_SGIX 0x8318 #define GL_YCRCBA_SGIX 0x8319 #endif /* GL_SGIX_ycrcba */ #ifndef GL_SGI_color_matrix #define GL_SGI_color_matrix 1 #define GL_COLOR_MATRIX_SGI 0x80B1 #define GL_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B2 #define GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3 #define GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4 #define GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5 #define GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6 #define GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7 #define GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8 #define GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9 #define GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA #define GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB #endif /* GL_SGI_color_matrix */ #ifndef GL_SGI_color_table #define GL_SGI_color_table 1 #define GL_COLOR_TABLE_SGI 0x80D0 #define GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1 #define GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2 #define GL_PROXY_COLOR_TABLE_SGI 0x80D3 #define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4 #define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5 #define GL_COLOR_TABLE_SCALE_SGI 0x80D6 #define GL_COLOR_TABLE_BIAS_SGI 0x80D7 #define GL_COLOR_TABLE_FORMAT_SGI 0x80D8 #define GL_COLOR_TABLE_WIDTH_SGI 0x80D9 #define GL_COLOR_TABLE_RED_SIZE_SGI 0x80DA #define GL_COLOR_TABLE_GREEN_SIZE_SGI 0x80DB #define GL_COLOR_TABLE_BLUE_SIZE_SGI 0x80DC #define GL_COLOR_TABLE_ALPHA_SIZE_SGI 0x80DD #define GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE #define GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF typedef void (APIENTRYP PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table); typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, void *table); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorTableSGI (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table); GLAPI void APIENTRY glColorTableParameterfvSGI (GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glColorTableParameterivSGI (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glCopyColorTableSGI (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); GLAPI void APIENTRY glGetColorTableSGI (GLenum target, GLenum format, GLenum type, void *table); GLAPI void APIENTRY glGetColorTableParameterfvSGI (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetColorTableParameterivSGI (GLenum target, GLenum pname, GLint *params); #endif #endif /* GL_SGI_color_table */ #ifndef GL_SGI_texture_color_table #define GL_SGI_texture_color_table 1 #define GL_TEXTURE_COLOR_TABLE_SGI 0x80BC #define GL_PROXY_TEXTURE_COLOR_TABLE_SGI 0x80BD #endif /* GL_SGI_texture_color_table */ #ifndef GL_SUNX_constant_data #define GL_SUNX_constant_data 1 #define GL_UNPACK_CONSTANT_DATA_SUNX 0x81D5 #define GL_TEXTURE_CONSTANT_DATA_SUNX 0x81D6 typedef void (APIENTRYP PFNGLFINISHTEXTURESUNXPROC) (void); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFinishTextureSUNX (void); #endif #endif /* GL_SUNX_constant_data */ #ifndef GL_SUN_convolution_border_modes #define GL_SUN_convolution_border_modes 1 #define GL_WRAP_BORDER_SUN 0x81D4 #endif /* GL_SUN_convolution_border_modes */ #ifndef GL_SUN_global_alpha #define GL_SUN_global_alpha 1 #define GL_GLOBAL_ALPHA_SUN 0x81D9 #define GL_GLOBAL_ALPHA_FACTOR_SUN 0x81DA typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORBSUNPROC) (GLbyte factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORSSUNPROC) (GLshort factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORISUNPROC) (GLint factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORFSUNPROC) (GLfloat factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORDSUNPROC) (GLdouble factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUBSUNPROC) (GLubyte factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUSSUNPROC) (GLushort factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUISUNPROC) (GLuint factor); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGlobalAlphaFactorbSUN (GLbyte factor); GLAPI void APIENTRY glGlobalAlphaFactorsSUN (GLshort factor); GLAPI void APIENTRY glGlobalAlphaFactoriSUN (GLint factor); GLAPI void APIENTRY glGlobalAlphaFactorfSUN (GLfloat factor); GLAPI void APIENTRY glGlobalAlphaFactordSUN (GLdouble factor); GLAPI void APIENTRY glGlobalAlphaFactorubSUN (GLubyte factor); GLAPI void APIENTRY glGlobalAlphaFactorusSUN (GLushort factor); GLAPI void APIENTRY glGlobalAlphaFactoruiSUN (GLuint factor); #endif #endif /* GL_SUN_global_alpha */ #ifndef GL_SUN_mesh_array #define GL_SUN_mesh_array 1 #define GL_QUAD_MESH_SUN 0x8614 #define GL_TRIANGLE_MESH_SUN 0x8615 typedef void (APIENTRYP PFNGLDRAWMESHARRAYSSUNPROC) (GLenum mode, GLint first, GLsizei count, GLsizei width); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawMeshArraysSUN (GLenum mode, GLint first, GLsizei count, GLsizei width); #endif #endif /* GL_SUN_mesh_array */ #ifndef GL_SUN_slice_accum #define GL_SUN_slice_accum 1 #define GL_SLICE_ACCUM_SUN 0x85CC #endif /* GL_SUN_slice_accum */ #ifndef GL_SUN_triangle_list #define GL_SUN_triangle_list 1 #define GL_RESTART_SUN 0x0001 #define GL_REPLACE_MIDDLE_SUN 0x0002 #define GL_REPLACE_OLDEST_SUN 0x0003 #define GL_TRIANGLE_LIST_SUN 0x81D7 #define GL_REPLACEMENT_CODE_SUN 0x81D8 #define GL_REPLACEMENT_CODE_ARRAY_SUN 0x85C0 #define GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1 #define GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2 #define GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3 #define GL_R1UI_V3F_SUN 0x85C4 #define GL_R1UI_C4UB_V3F_SUN 0x85C5 #define GL_R1UI_C3F_V3F_SUN 0x85C6 #define GL_R1UI_N3F_V3F_SUN 0x85C7 #define GL_R1UI_C4F_N3F_V3F_SUN 0x85C8 #define GL_R1UI_T2F_V3F_SUN 0x85C9 #define GL_R1UI_T2F_N3F_V3F_SUN 0x85CA #define GL_R1UI_T2F_C4F_N3F_V3F_SUN 0x85CB typedef void (APIENTRYP PFNGLREPLACEMENTCODEUISUNPROC) (GLuint code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSSUNPROC) (GLushort code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVSUNPROC) (const GLuint *code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSVSUNPROC) (const GLushort *code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte *code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const void **pointer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glReplacementCodeuiSUN (GLuint code); GLAPI void APIENTRY glReplacementCodeusSUN (GLushort code); GLAPI void APIENTRY glReplacementCodeubSUN (GLubyte code); GLAPI void APIENTRY glReplacementCodeuivSUN (const GLuint *code); GLAPI void APIENTRY glReplacementCodeusvSUN (const GLushort *code); GLAPI void APIENTRY glReplacementCodeubvSUN (const GLubyte *code); GLAPI void APIENTRY glReplacementCodePointerSUN (GLenum type, GLsizei stride, const void **pointer); #endif #endif /* GL_SUN_triangle_list */ #ifndef GL_SUN_vertex #define GL_SUN_vertex 1 typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FVSUNPROC) (const GLubyte *c, const GLfloat *v); typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FVSUNPROC) (const GLubyte *c, const GLfloat *v); typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *v); typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FSUNPROC) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC) (const GLfloat *tc, const GLubyte *c, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC) (GLuint rc, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC) (const GLuint *rc, const GLubyte *c, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColor4ubVertex2fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); GLAPI void APIENTRY glColor4ubVertex2fvSUN (const GLubyte *c, const GLfloat *v); GLAPI void APIENTRY glColor4ubVertex3fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glColor4ubVertex3fvSUN (const GLubyte *c, const GLfloat *v); GLAPI void APIENTRY glColor3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glColor3fVertex3fvSUN (const GLfloat *c, const GLfloat *v); GLAPI void APIENTRY glNormal3fVertex3fSUN (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glNormal3fVertex3fvSUN (const GLfloat *n, const GLfloat *v); GLAPI void APIENTRY glColor4fNormal3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glColor4fNormal3fVertex3fvSUN (const GLfloat *c, const GLfloat *n, const GLfloat *v); GLAPI void APIENTRY glTexCoord2fVertex3fSUN (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glTexCoord2fVertex3fvSUN (const GLfloat *tc, const GLfloat *v); GLAPI void APIENTRY glTexCoord4fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glTexCoord4fVertex4fvSUN (const GLfloat *tc, const GLfloat *v); GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fSUN (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fvSUN (const GLfloat *tc, const GLubyte *c, const GLfloat *v); GLAPI void APIENTRY glTexCoord2fColor3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glTexCoord2fColor3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *v); GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *n, const GLfloat *v); GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); GLAPI void APIENTRY glReplacementCodeuiVertex3fSUN (GLuint rc, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glReplacementCodeuiVertex3fvSUN (const GLuint *rc, const GLfloat *v); GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fSUN (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *rc, const GLubyte *c, const GLfloat *v); GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *v); GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fSUN (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *n, const GLfloat *v); GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *v); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); #endif #endif /* GL_SUN_vertex */ #ifndef GL_WIN_phong_shading #define GL_WIN_phong_shading 1 #define GL_PHONG_WIN 0x80EA #define GL_PHONG_HINT_WIN 0x80EB #endif /* GL_WIN_phong_shading */ #ifndef GL_WIN_specular_fog #define GL_WIN_specular_fog 1 #define GL_FOG_SPECULAR_TEXTURE_WIN 0x80EC #endif /* GL_WIN_specular_fog */ #ifdef __cplusplus } #endif #endif eureka-editor-eureka-2.0.2/win/include/KHR/000077500000000000000000000000001464327712600204055ustar00rootroot00000000000000eureka-editor-eureka-2.0.2/win/include/KHR/khrplatform.h000066400000000000000000000240471464327712600231160ustar00rootroot00000000000000#ifndef __khrplatform_h_ #define __khrplatform_h_ /* ** Copyright (c) 2008-2018 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the ** "Materials"), to deal in the Materials without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Materials, and to ** permit persons to whom the Materials are 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 Materials. ** ** THE MATERIALS ARE 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. */ /* Khronos platform-specific types and definitions. * * The master copy of khrplatform.h is maintained in the Khronos EGL * Registry repository at https://github.com/KhronosGroup/EGL-Registry * The last semantic modification to khrplatform.h was at commit ID: * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 * * Adopters may modify this file to suit their platform. Adopters are * encouraged to submit platform specific modifications to the Khronos * group so that they can be included in future versions of this file. * Please submit changes by filing pull requests or issues on * the EGL Registry repository linked above. * * * See the Implementer's Guidelines for information about where this file * should be located on your system and for more details of its use: * http://www.khronos.org/registry/implementers_guide.pdf * * This file should be included as * #include * by Khronos client API header files that use its types and defines. * * The types in khrplatform.h should only be used to define API-specific types. * * Types defined in khrplatform.h: * khronos_int8_t signed 8 bit * khronos_uint8_t unsigned 8 bit * khronos_int16_t signed 16 bit * khronos_uint16_t unsigned 16 bit * khronos_int32_t signed 32 bit * khronos_uint32_t unsigned 32 bit * khronos_int64_t signed 64 bit * khronos_uint64_t unsigned 64 bit * khronos_intptr_t signed same number of bits as a pointer * khronos_uintptr_t unsigned same number of bits as a pointer * khronos_ssize_t signed size * khronos_usize_t unsigned size * khronos_float_t signed 32 bit floating point * khronos_time_ns_t unsigned 64 bit time in nanoseconds * khronos_utime_nanoseconds_t unsigned time interval or absolute time in * nanoseconds * khronos_stime_nanoseconds_t signed time interval in nanoseconds * khronos_boolean_enum_t enumerated boolean type. This should * only be used as a base type when a client API's boolean type is * an enum. Client APIs which use an integer or other type for * booleans cannot use this as the base type for their boolean. * * Tokens defined in khrplatform.h: * * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. * * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. * * Calling convention macros defined in this file: * KHRONOS_APICALL * KHRONOS_APIENTRY * KHRONOS_APIATTRIBUTES * * These may be used in function prototypes as: * * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( * int arg1, * int arg2) KHRONOS_APIATTRIBUTES; */ #if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC) # define KHRONOS_STATIC 1 #endif /*------------------------------------------------------------------------- * Definition of KHRONOS_APICALL *------------------------------------------------------------------------- * This precedes the return type of the function in the function prototype. */ #if defined(KHRONOS_STATIC) /* If the preprocessor constant KHRONOS_STATIC is defined, make the * header compatible with static linking. */ # define KHRONOS_APICALL #elif defined(_WIN32) # define KHRONOS_APICALL __declspec(dllimport) #elif defined (__SYMBIAN32__) # define KHRONOS_APICALL IMPORT_C #elif defined(__ANDROID__) # define KHRONOS_APICALL __attribute__((visibility("default"))) #else # define KHRONOS_APICALL #endif /*------------------------------------------------------------------------- * Definition of KHRONOS_APIENTRY *------------------------------------------------------------------------- * This follows the return type of the function and precedes the function * name in the function prototype. */ #if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) /* Win32 but not WinCE */ # define KHRONOS_APIENTRY __stdcall #else # define KHRONOS_APIENTRY #endif /*------------------------------------------------------------------------- * Definition of KHRONOS_APIATTRIBUTES *------------------------------------------------------------------------- * This follows the closing parenthesis of the function prototype arguments. */ #if defined (__ARMCC_2__) #define KHRONOS_APIATTRIBUTES __softfp #else #define KHRONOS_APIATTRIBUTES #endif /*------------------------------------------------------------------------- * basic type definitions *-----------------------------------------------------------------------*/ #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) /* * Using */ #include typedef int32_t khronos_int32_t; typedef uint32_t khronos_uint32_t; typedef int64_t khronos_int64_t; typedef uint64_t khronos_uint64_t; #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #elif defined(__VMS ) || defined(__sgi) /* * Using */ #include typedef int32_t khronos_int32_t; typedef uint32_t khronos_uint32_t; typedef int64_t khronos_int64_t; typedef uint64_t khronos_uint64_t; #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #elif defined(_WIN32) && !defined(__SCITECH_SNAP__) /* * Win32 */ typedef __int32 khronos_int32_t; typedef unsigned __int32 khronos_uint32_t; typedef __int64 khronos_int64_t; typedef unsigned __int64 khronos_uint64_t; #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #elif defined(__sun__) || defined(__digital__) /* * Sun or Digital */ typedef int khronos_int32_t; typedef unsigned int khronos_uint32_t; #if defined(__arch64__) || defined(_LP64) typedef long int khronos_int64_t; typedef unsigned long int khronos_uint64_t; #else typedef long long int khronos_int64_t; typedef unsigned long long int khronos_uint64_t; #endif /* __arch64__ */ #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #elif 0 /* * Hypothetical platform with no float or int64 support */ typedef int khronos_int32_t; typedef unsigned int khronos_uint32_t; #define KHRONOS_SUPPORT_INT64 0 #define KHRONOS_SUPPORT_FLOAT 0 #else /* * Generic fallback */ #include typedef int32_t khronos_int32_t; typedef uint32_t khronos_uint32_t; typedef int64_t khronos_int64_t; typedef uint64_t khronos_uint64_t; #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #endif /* * Types that are (so far) the same on all platforms */ typedef signed char khronos_int8_t; typedef unsigned char khronos_uint8_t; typedef signed short int khronos_int16_t; typedef unsigned short int khronos_uint16_t; /* * Types that differ between LLP64 and LP64 architectures - in LLP64, * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears * to be the only LLP64 architecture in current use. */ #ifdef _WIN64 typedef signed long long int khronos_intptr_t; typedef unsigned long long int khronos_uintptr_t; typedef signed long long int khronos_ssize_t; typedef unsigned long long int khronos_usize_t; #else typedef signed long int khronos_intptr_t; typedef unsigned long int khronos_uintptr_t; typedef signed long int khronos_ssize_t; typedef unsigned long int khronos_usize_t; #endif #if KHRONOS_SUPPORT_FLOAT /* * Float type */ typedef float khronos_float_t; #endif #if KHRONOS_SUPPORT_INT64 /* Time types * * These types can be used to represent a time interval in nanoseconds or * an absolute Unadjusted System Time. Unadjusted System Time is the number * of nanoseconds since some arbitrary system event (e.g. since the last * time the system booted). The Unadjusted System Time is an unsigned * 64 bit value that wraps back to 0 every 584 years. Time intervals * may be either signed or unsigned. */ typedef khronos_uint64_t khronos_utime_nanoseconds_t; typedef khronos_int64_t khronos_stime_nanoseconds_t; #endif /* * Dummy value used to pad enum types to 32 bits. */ #ifndef KHRONOS_MAX_ENUM #define KHRONOS_MAX_ENUM 0x7FFFFFFF #endif /* * Enumerated boolean type * * Values other than zero should be considered to be true. Therefore * comparisons should not be made against KHRONOS_TRUE. */ typedef enum { KHRONOS_FALSE = 0, KHRONOS_TRUE = 1, KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM } khronos_boolean_enum_t; #endif /* __khrplatform_h_ */