From b3fad2151249a019161434bcb1e5451ce8592f1b Mon Sep 17 00:00:00 2001 From: PaladinDev Date: Sun, 28 May 2023 14:52:19 +0300 Subject: [PATCH] Switch to meson & refactoring --- .gitignore | 3 - AUTHORS | 1 - CMakeLists.txt | 112 --- COPYING | 19 - COPYING.LGPL | 510 ----------- README.md | 27 +- ValaGL.Core/Camera.vala | 203 ----- ValaGL.Core/CoreError.vala | 44 - ValaGL.Core/GLProgram.vala | 147 ---- ValaGL.Core/GeometryUtil.vala | 135 --- ValaGL.Core/IBO.vala | 70 -- ValaGL.Core/MatrixMath.vala | 774 ----------------- ValaGL.Core/Util.vala | 72 -- ValaGL.Core/VAO.vala | 73 -- ValaGL.Core/VBO.vala | 84 -- ValaGL.Core/_namespace.vala | 29 - ValaGL/App.vala | 210 ----- ValaGL/AppError.vala | 31 - ValaGL/Canvas.vala | 215 ----- ValaGL/_namespace.vala | 29 - cmake/FindGLEW.cmake | 50 -- cmake/FindGLib.cmake | 33 - cmake/FindVala.cmake | 65 -- cmake/FindValadoc.cmake | 20 - cmake/ParseArguments.cmake | 36 - cmake/ValaPrecompile.cmake | 171 ---- cmake/ValaVersion.cmake | 96 --- cmake/Valadoc.cmake | 38 - cmake/config.h.in | 36 - cmake/intltool-merge.pl | 1500 --------------------------------- data/meson.build | 7 + data/shaders/fragment.glsl | 2 +- data/shaders/vertex.glsl | 4 +- data/valagl.gresource.xml | 7 + install.cmake | 2 - meson.build | 16 + result.png | Bin 0 -> 20079 bytes scripts/seed | 40 - sources.cmake | 27 - src/app-error.vala | 12 + src/app.vala | 184 ++++ src/canvas.vala | 193 +++++ src/core/camera.vala | 189 +++++ src/core/core-error.vala | 20 + src/core/geometry-util.vala | 112 +++ src/core/gl-program.vala | 116 +++ src/core/ibo.vala | 45 + src/core/matrix-math.vala | 734 ++++++++++++++++ src/core/vao.vala | 49 ++ src/core/vbo.vala | 60 ++ src/meson.build | 31 + valagl.doap | 24 + vapi/AppConfig.vapi | 37 - vapi/glu.vapi | 304 ------- 54 files changed, 1819 insertions(+), 5229 deletions(-) delete mode 100644 .gitignore delete mode 100644 AUTHORS delete mode 100644 CMakeLists.txt delete mode 100644 COPYING delete mode 100644 COPYING.LGPL delete mode 100644 ValaGL.Core/Camera.vala delete mode 100644 ValaGL.Core/CoreError.vala delete mode 100644 ValaGL.Core/GLProgram.vala delete mode 100644 ValaGL.Core/GeometryUtil.vala delete mode 100644 ValaGL.Core/IBO.vala delete mode 100644 ValaGL.Core/MatrixMath.vala delete mode 100644 ValaGL.Core/Util.vala delete mode 100644 ValaGL.Core/VAO.vala delete mode 100644 ValaGL.Core/VBO.vala delete mode 100644 ValaGL.Core/_namespace.vala delete mode 100644 ValaGL/App.vala delete mode 100644 ValaGL/AppError.vala delete mode 100644 ValaGL/Canvas.vala delete mode 100644 ValaGL/_namespace.vala delete mode 100644 cmake/FindGLEW.cmake delete mode 100644 cmake/FindGLib.cmake delete mode 100644 cmake/FindVala.cmake delete mode 100644 cmake/FindValadoc.cmake delete mode 100644 cmake/ParseArguments.cmake delete mode 100644 cmake/ValaPrecompile.cmake delete mode 100644 cmake/ValaVersion.cmake delete mode 100644 cmake/Valadoc.cmake delete mode 100644 cmake/config.h.in delete mode 100755 cmake/intltool-merge.pl create mode 100644 data/meson.build create mode 100644 data/valagl.gresource.xml delete mode 100644 install.cmake create mode 100644 meson.build create mode 100644 result.png delete mode 100755 scripts/seed delete mode 100644 sources.cmake create mode 100644 src/app-error.vala create mode 100644 src/app.vala create mode 100644 src/canvas.vala create mode 100644 src/core/camera.vala create mode 100644 src/core/core-error.vala create mode 100644 src/core/geometry-util.vala create mode 100644 src/core/gl-program.vala create mode 100644 src/core/ibo.vala create mode 100644 src/core/matrix-math.vala create mode 100644 src/core/vao.vala create mode 100644 src/core/vbo.vala create mode 100644 src/meson.build create mode 100644 valagl.doap delete mode 100644 vapi/AppConfig.vapi delete mode 100644 vapi/glu.vapi diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 897be08..0000000 --- a/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/bin/ -/build/ -*~ diff --git a/AUTHORS b/AUTHORS deleted file mode 100644 index f4942df..0000000 --- a/AUTHORS +++ /dev/null @@ -1 +0,0 @@ -Maia Everett diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index c0d18bb..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,112 +0,0 @@ -project(valagl C) -cmake_minimum_required(VERSION 3.10) - -# Change version number on release -set(PROJECT_VERSION "0.1.0") -set(COMMON_DATA_DIR ${CMAKE_INSTALL_PREFIX}/share) -set(PROJECT_DATA_DIR ${CMAKE_INSTALL_PREFIX}/share/${CMAKE_PROJECT_NAME}) - -list(APPEND CMAKE_MODULE_PATH - ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/cmake -) - -option(BUILD_VALADOC "Build API documentation if Valadoc is available" ON) - -set(VALA_REQUIRED_VERSION 0.48) -set(GLIB_REQUIRED_VERSION 2.30.0) -set(GTK_REQUIRED_VERSION 3.0.0) - -# Use GLVND, the modern OpenGL ABI -set(OpenGL_GL_PREFERENCE GLVND) - -find_package(PkgConfig REQUIRED) -find_package(Vala REQUIRED) -find_package(GLib REQUIRED) -find_package(SDL2 REQUIRED) -find_package(OpenGL REQUIRED) -pkg_check_modules(EPOXY REQUIRED epoxy) - -set(HAVE_VALADOC OFF) - -if(BUILD_VALADOC) - find_package(Valadoc) - - if(VALADOC_FOUND) - set(HAVE_VALADOC ON) - include(Valadoc) - else() - message("Valadoc not found, will not build documentation") - endif() -endif() - -include(ValaVersion) -include(ValaPrecompile) -include(sources) - -ensure_vala_version(${VALA_REQUIRED_VERSION} MINIMUM) - -file (READ ${CMAKE_SOURCE_DIR}/AUTHORS PROJECT_AUTHORS) -string (REPLACE "\n" "\\n\\\n" PROJECT_AUTHORS ${PROJECT_AUTHORS}) -configure_file(${CMAKE_SOURCE_DIR}/cmake/config.h.in ${CMAKE_BINARY_DIR}/config.h @ONLY) - -set(CUSTOM_VAPIS - # VAPI containing install definitions, mapping from cmake generated config.h - ${CMAKE_SOURCE_DIR}/vapi/AppConfig.vapi - # Order is important! GLEW must come before GL and GLU. - ${CMAKE_SOURCE_DIR}/vapi/gl.vapi - ${CMAKE_SOURCE_DIR}/vapi/glu.vapi - ${CMAKE_SOURCE_DIR}/vapi/sdl2.vapi -) - -set(VALA_PACKAGES - gio-2.0 - glib-2.0 -) - -vala_precompile(VALA_C - ${APP_SOURCES} -CUSTOM_VAPIS - ${CUSTOM_VAPIS} -PACKAGES - ${VALA_PACKAGES} -OPTIONS - -g -) - -include_directories( - ${GLIB_ALL_INCLUDES} - ${SDL2_INCLUDE_DIR} - ${EPOXY_INCLUDE_PATH} - ${OPENGL_INCLUDE_DIR} - ${CMAKE_BINARY_DIR} -) - -add_definitions( - ${GLIB_ALL_CFLAGS} - ${EPOXY_CFLAGS_OTHER} - -DNO_SDL_GLEXT -) - -add_executable(${CMAKE_PROJECT_NAME} ${VALA_C}) - -target_link_libraries(${CMAKE_PROJECT_NAME} - ${GLIB_ALL_LIBS} - ${EPOXY_LIBRARIES} - ${SDL2_LIBRARIES} - ${OPENGL_LIBRARIES} - -lm -) - -if(HAVE_VALADOC) - valadoc(${CMAKE_PROJECT_NAME} - ${CMAKE_BINARY_DIR}/valadoc - ${APP_SOURCES} - CUSTOM_VAPIS - ${CUSTOM_VAPIS} - PACKAGES - ${VALA_PACKAGES} - ) -endif() - -include(install) diff --git a/COPYING b/COPYING deleted file mode 100644 index 8e49eed..0000000 --- a/COPYING +++ /dev/null @@ -1,19 +0,0 @@ -The MIT License - -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. \ No newline at end of file diff --git a/COPYING.LGPL b/COPYING.LGPL deleted file mode 100644 index 2d2d780..0000000 --- a/COPYING.LGPL +++ /dev/null @@ -1,510 +0,0 @@ - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin St, 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. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations -below. - - When we speak of free software, we are referring to freedom of use, -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 and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it -becomes a de-facto standard. To achieve this, non-free programs must -be allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, 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 library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete 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 distribute a copy of this License along with the -Library. - - 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 Library or any portion -of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -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 Library, 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 Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you 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. - - If distribution of 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 satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at least - three years, to give the same user the materials specified in - Subsection 6a, above, for a charge no more than the cost of - performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be 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. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library 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. - - 9. 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 Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -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 with -this License. - - 11. 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 Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library 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 Library. - -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. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library 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. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser 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 Library -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 Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -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 - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "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 -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. 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 LIBRARY 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 -LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms -of the ordinary General Public License). - - To apply these terms, attach the following notices to the library. -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 library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or -your school, if any, to sign a "copyright disclaimer" for the library, -if necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James - Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/README.md b/README.md index 5c1a043..8eeb798 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,22 @@ # ValaGL -A skeletal Vala application using modern OpenGL 3.x. No legacy pipeline. +Fork of [Maia-Everett/valagl](https://github.com/Maia-Everett/valagl) -It sets up a fullscreen SDL window and displays a colored rotating cube. +* Refactored & Rewriten to meson build system +* Fixed warnings +* Loading shaders with [GLib.Resource](https://valadoc.org/gio-2.0/GLib.Resource.html) -## Building and running under Ubuntu +![Screenshot](./result.png) -``` -sudo apt-get install libepoxy-dev libsdl2-dev cmake valac valadoc -mkdir bin -cd bin; cmake ..; cd .. -make -C bin -bin/valagl -``` +## Installation + +#### Dependencies +* libsdl2 +* libepoxy +* glib + +#### Build manualy + + $ meson setup --prefix=/usr build + $ cd build + $ ninja install \ No newline at end of file diff --git a/ValaGL.Core/Camera.vala b/ValaGL.Core/Camera.vala deleted file mode 100644 index d26f18c..0000000 --- a/ValaGL.Core/Camera.vala +++ /dev/null @@ -1,203 +0,0 @@ -/* - Camera.vala - Copyright (C) 2013, 2021 Maia Everett - - 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. -*/ - -using GL; - -namespace ValaGL.Core { - -/** - * Encapsulates a camera object. A camera contains a projection matrix and a view matrix. - * - * The main purpose of this class is to provide equivalents of legacy OpenGL functions - * removed in modern OpenGL. Advanced features like quaternion-based rotations are beyond - * the scope of this project. -*/ -public class Camera : Object { - private Mat4 projection_matrix; - private Mat4 view_matrix; - private Mat4 result_matrix; - private Mat4 total_matrix; - - /** - * Instantiates a camera object. - * - * The projection and view matrices are set to the identity matrix. - */ - public Camera () { - reset (); - } - - private void update () { - result_matrix = projection_matrix; - result_matrix.mul_mat (ref view_matrix); - } - - /** - * Resets both the projection matrix and the view matrix. - */ - public void reset () { - reset_projection (); - reset_view (); - } - - /** - * Resets the projection matrix, setting it to the identity matrix. - */ - public void reset_projection () { - projection_matrix = Mat4.identity (); - update (); - } - - /** - * Resets the view matrix, setting it to the identity matrix. - */ - public void reset_view () { - view_matrix = Mat4.identity (); - update (); - } - - /** - * Applies the camera to the next model object that will be drawn, by - * multiplying the current projection and view matrices by the model matrix - * passed to the function (which specifies the offset and rotation of the model - * relative to the camera), and binds the matrix data to the specified - * shader uniform variable. - * - * @param uniform_id The shader uniform variable to bind to - * @param model_matrix The model matrix - */ - public void apply (GLint uniform_id, ref Mat4 model_matrix) { - total_matrix = result_matrix; - total_matrix.mul_mat (ref model_matrix); - glUniformMatrix4fv (uniform_id, 1, (GLboolean) GL_FALSE, total_matrix.data); - } - - /** - * Sets up a perspective projection. The previous projection matrix is ignored and overwritten. - * - * Replicates the effects of the legacy ``glFrustum`` function within this camera. - * Refer to that function for the complete description of the projection parameters. - * - * @param left The coordinate of the left vertical clipping plane. - * @param right The coordinate of the right vertical clipping plane. - * @param bottom The coordinate of the bottom horizontal clipping plane. - * @param top The coordinate of the top horizontal clipping plane. - * @param near The coordinate of the near vertical clipping plane. Must be positive. - * @param far The coordinate of the far vertical clipping plane. Must be positive. - */ - public void set_frustum_projection (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, - GLfloat near, GLfloat far) { - projection_matrix = Mat4.from_data ( - 2f * near / (right - left), 0, (right + left) / (right - left), 0, - 0, 2f * near / (top - bottom), (top + bottom) / (top - bottom), 0, - 0, 0, -(far + near) / (far - near), -2f * far * near / (far - near), - 0, 0, -1, 0 - ); - - update (); - } - - /** - * Sets up a symmetrical perspective projection. The previous projection matrix is ignored and overwritten. - * - * Replicates the effects of the legacy ``gluPerspective`` function within this camera. - * Refer to that function for the complete description of the projection parameters. - * - * @param fovy_deg The field of view angle, in degrees, in the y direction. - * @param aspect The aspect ratio that determines the field of view in the x direction. - * The aspect ratio is the ratio of x (width) to y (height). - * @param near The coordinate of the near vertical clipping plane. Must be positive. - * @param far The coordinate of the far vertical clipping plane. Must be positive. - */ - public void set_perspective_projection (GLfloat fovy_deg, GLfloat aspect, GLfloat near, GLfloat far) { - var f = 1 / Math.tanf (GeometryUtil.deg_to_rad (fovy_deg / 2)); - - projection_matrix = Mat4.from_data ( - f / aspect, 0, 0, 0, - 0, f, 0, 0, - 0, 0, -(far + near) / (far - near), -2f * far * near / (far - near), - 0, 0, -1, 0 - ); - - update (); - } - - /** - * Sets up an orthogonal projection. The previous projection matrix is ignored and overwritten. - * - * Replicates the effects of the legacy ``glOrtho`` function within this camera. - * Refer to that function for the complete description of the projection parameters. - * - * @param left The coordinate of the left vertical clipping plane. - * @param right The coordinate of the right vertical clipping plane. - * @param bottom The coordinate of the bottom horizontal clipping plane. - * @param top The coordinate of the top horizontal clipping plane. - * @param near The coordinate of the near vertical clipping plane. - * @param far The coordinate of the far vertical clipping plane. - */ - public void set_ortho_projection (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, - GLfloat near, GLfloat far) { - projection_matrix = Mat4.from_data ( - 2f / (right - left), 0, 0, (right + left) / (right - left), - 0, 2f / (top - bottom), 0, (top + bottom) / (top - bottom), - 0, 0, -2f * far * near / (far - near), -(far + near) / (far - near), - 0, 0, 0, 1 - ); - - update (); - } - - /** - * Replicates the effects of the legacy ``gluLookAt`` function within this camera. - * Refer to that function for the complete description of how the camera is positioned. - * - * @param eye The 3D position of the camera - * @param center The 3D position of the point the camera is looking at - * @param up The up-direction - */ - public void look_at (ref Vec3 eye, ref Vec3 center, ref Vec3 up) { - Vec3 l = center; - l.sub (ref eye); - l.normalize (); - - Vec3 uptemp = up; - uptemp.normalize (); - - Vec3 s = l.cross_product (ref uptemp); - Vec3 u = s.cross_product (ref l); - - view_matrix = Mat4.from_data ( - s.x, s.y, s.z, 0, - u.x, u.y, u.z, 0, - -l.x, -l.y, -l.z, 0, - 0, 0, 0, 1 - ); - - Vec3 translation = Vec3 (); - translation.sub (ref eye); - GeometryUtil.translate (ref view_matrix, ref translation); - update (); - } -} - -} diff --git a/ValaGL.Core/CoreError.vala b/ValaGL.Core/CoreError.vala deleted file mode 100644 index 1aeb3f0..0000000 --- a/ValaGL.Core/CoreError.vala +++ /dev/null @@ -1,44 +0,0 @@ -/* - CoreError.vala - Copyright (C) 2013, 2021 Maia Everett - - 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. -*/ - -namespace ValaGL.Core { - -/** - * Error domain for the ValaGL core OpenGL support. - */ -public errordomain CoreError { - /** - * Indicates a vertex or fragment shader initialization error. - */ - SHADER_INIT, - /** - * Indicates a vertex buffer object initialization error. - */ - VBO_INIT, - /** - * Indicates an index buffer object initialization error. - */ - IBO_INIT -} - -} diff --git a/ValaGL.Core/GLProgram.vala b/ValaGL.Core/GLProgram.vala deleted file mode 100644 index 62313ae..0000000 --- a/ValaGL.Core/GLProgram.vala +++ /dev/null @@ -1,147 +0,0 @@ -/* - GLProgram.vala - Copyright (C) 2013, 2021 Maia Everett - - 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. -*/ - -using GL; - -namespace ValaGL.Core { - -/** - * Encapsulation of an OpenGL GPU program, containing one vertex shader and one fragment shader. - */ -public class GLProgram : Object { - private GLuint vertex_shader = 0; - private GLuint fragment_shader = 0; - private GLuint prog_id = 0; - - /** - * Instantiates a new OpenGL program object, reading the vertex and fragment shaders from files. - * - * @param vertex_shader_file The file to read the vertex shader from - * @param fragment_shader_file The file to read the fragment shader from - */ - public GLProgram (string vertex_shader_file, string fragment_shader_file) throws CoreError { - vertex_shader = create_shader_from_file (GL_VERTEX_SHADER, vertex_shader_file); - fragment_shader = create_shader_from_file (GL_FRAGMENT_SHADER, fragment_shader_file); - - prog_id = glCreateProgram (); - - if (prog_id == 0) { - throw new CoreError.SHADER_INIT ("Cannot allocate GL program ID"); - } - - glAttachShader (prog_id, vertex_shader); - glAttachShader (prog_id, fragment_shader); - glLinkProgram (prog_id); - - GLint[] link_ok = { GL_FALSE }; - glGetProgramiv (prog_id, GL_LINK_STATUS, link_ok); - - if (link_ok[0] != GL_TRUE) { - throw new CoreError.SHADER_INIT ("Cannot link GL program"); - } - } - - ~GLProgram () { - if (vertex_shader != 0) { - glDeleteShader (vertex_shader); - } - - if (fragment_shader != 0) { - glDeleteShader (fragment_shader); - } - - if (prog_id != 0) { - glDeleteProgram (prog_id); - } - } - - /** - * Gets the ID for the shader ``attribute`` variable with the specified name. - * - * @return The attribute ID - */ - public GLint get_attrib_location (string name) { - assert (prog_id != 0); - return glGetAttribLocation (prog_id, name); - } - - /** - * Gets the ID for the shader ``uniform`` variable with the specified name. - * - * @return The uniform ID - */ - public GLint get_uniform_location (string name) { - assert (prog_id != 0); - return glGetUniformLocation (prog_id, name); - } - - /** - * Makes this OpenGL program current in the current OpenGL context, applying it to future drawing operations. - */ - public void make_current () { - assert (prog_id != 0); - glUseProgram (prog_id); - } - - private static GLuint create_shader_from_file (GLuint shader_type, string file_path) throws CoreError { - try { - uint8[] file_contents; - File.new_for_path (file_path).load_contents (null, out file_contents, null); - return create_shader_from_string (shader_type, (string) file_contents); - } catch (Error e) { - throw new CoreError.SHADER_INIT (e.message); - } - } - - private static GLuint create_shader_from_string (GLuint shader_type, string source) throws CoreError - { - var shader = glCreateShader (shader_type); - - if (shader == 0) { - throw new CoreError.SHADER_INIT ("Cannot allocate shader ID"); - } - - string[] sourceArray = { source, null }; - glShaderSource (shader, 1, sourceArray, null); - glCompileShader (shader); - - GLint[] compile_ok = { GL_FALSE }; - glGetShaderiv (shader, GL_COMPILE_STATUS, compile_ok); - - if (compile_ok[0] == GL_TRUE) - { - return shader; - } - - // Otherwise, there is an error. - glDeleteShader (shader); - - if (shader_type == GL_VERTEX_SHADER) { - throw new CoreError.SHADER_INIT ("Error compiling vertex shader"); - } else { - throw new CoreError.SHADER_INIT ("Error compiling fragment shader"); - } - } -} - -} diff --git a/ValaGL.Core/GeometryUtil.vala b/ValaGL.Core/GeometryUtil.vala deleted file mode 100644 index fb0e763..0000000 --- a/ValaGL.Core/GeometryUtil.vala +++ /dev/null @@ -1,135 +0,0 @@ -/* - GeometryUtil.vala - Copyright (C) 2013, 2021 Maia Everett - - 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. -*/ - -using GL; - -namespace ValaGL.Core { - -/** - * Static helper class for stock geometry calculations and matrix transformations. - */ -public class GeometryUtil : Object { - private GeometryUtil () { } - - /** - * Converts the given angle from degrees to radians. - * - * @param deg Angle in radians - * @return Angle in degrees - */ - public static GLfloat deg_to_rad (GLfloat deg) { - return (GLfloat) (deg * Math.PI / 180f); - } - - /** - * Converts the given angle from radians to degrees. - * - * @param rad Angle in degrees - * @return Angle in radians - */ - public static GLfloat rad_to_deg (GLfloat rad) { - return (GLfloat) (rad / Math.PI * 180f); - } - - /** - * Multiples the given matrix by a matrix that specifies a translation - * by the given vector. The matrix is modified in-place. - * - * For more information, refer to the ``glTranslatef`` legacy OpenGL function. - * - * @param matrix The matrix to transform - * @param translation The translation vector - */ - public static void translate (ref Mat4 matrix, ref Vec3 translation) { - var tmp = Mat4.from_data ( - 1, 0, 0, translation.x, - 0, 1, 0, translation.y, - 0, 0, 1, translation.z, - 0, 0, 0, 1 - ); - - matrix.mul_mat (ref tmp); - } - - /** - * Multiples the given matrix by a matrix that specifies a scale operation - * by the given factors in the x, y and z directions. - * The matrix is modified in-place. - * - * For more information, refer to the ``glScalef`` legacy OpenGL function. - * - * @param matrix The matrix to transform - * @param scale_factors The scale factor vector - */ - public static void scale (ref Mat4 matrix, ref Vec3 scale_factors) { - var tmp = Mat4.from_data ( - scale_factors.x, 0, 0, 0, - 0, scale_factors.y, 0, 0, - 0, 0, scale_factors.z, 0, - 0, 0, 0, 1 - ); - - matrix.mul_mat (ref tmp); - } - - - /** - * Multiples the given matrix by a matrix that specifies a rotation around - * the given axis by the given angle. The matrix is modified in-place. - * - * Be careful with these rotations. Unlike quaternion-based transformations, - * they may incur gimbal lock. - * - * For more information, refer to the ``glRotatef`` legacy OpenGL function. - * - * @param matrix The matrix to transform - * @param angle_deg The rotation angle in degrees - * @param axis The rotation axis - */ - public static void rotate (ref Mat4 matrix, GLfloat angle_deg, ref Vec3 axis) { - Vec3 axis_normalized = axis; - axis_normalized.normalize (); - - GLfloat angle_rad = deg_to_rad (angle_deg); - - // M = uuT + (cos a) (1 - uuT) + (sin a) S - Mat3 tmp1 = Mat3.from_vec_mul (ref axis_normalized, ref axis_normalized); - Mat3 tmp2 = Mat3.identity (); - tmp2.sub (ref tmp1); - tmp2.mul (Math.cosf (angle_rad)); - tmp1.add (ref tmp2); - - Mat3 s = Mat3.from_data ( - 0, -axis_normalized.z, axis_normalized.y, - axis_normalized.z, 0, -axis_normalized.x, - -axis_normalized.y, axis_normalized.x, 0 - ); - s.mul (Math.sinf (angle_rad)); - tmp1.add (ref s); - - var tmp = Mat4.expand (ref tmp1); - matrix.mul_mat (ref tmp); - } -} - -} diff --git a/ValaGL.Core/IBO.vala b/ValaGL.Core/IBO.vala deleted file mode 100644 index 8851309..0000000 --- a/ValaGL.Core/IBO.vala +++ /dev/null @@ -1,70 +0,0 @@ -/* - IBO.vala - Copyright (C) 2013, 2021 Maia Everett - - 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. -*/ - -using GL; - -namespace ValaGL.Core { - -/** - * Encapsulation of an OpenGL index buffer object. - * - * The underlying OpenGL buffer is destroyed when this object is finally unreferenced. - */ -public class IBO : Object { - private GLuint id; - - /** - * Creates an index buffer object. - * - * @param data Array to bind to the OpenGL buffer - */ - public IBO (GLushort[] data) throws CoreError { - GLuint id_array[1]; - glGenBuffers (1, id_array); - id = id_array[0]; - - if (id == 0) { - throw new CoreError.IBO_INIT ("Cannot allocate index buffer object"); - } - - glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, id); - glBufferData (GL_ELEMENT_ARRAY_BUFFER, data.length * sizeof (GLushort), (GLvoid[]) data, GL_STATIC_DRAW); - glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0); - } - - /** - * Makes this IBO current for future drawing operations in the OpenGL context. - */ - public void make_current () { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id); - } - - ~IBO () { - if (id != 0) { - GLuint[] id_array = { id }; - glDeleteBuffers (1, id_array); - } - } -} - -} diff --git a/ValaGL.Core/MatrixMath.vala b/ValaGL.Core/MatrixMath.vala deleted file mode 100644 index aac91f1..0000000 --- a/ValaGL.Core/MatrixMath.vala +++ /dev/null @@ -1,774 +0,0 @@ -/* - MatrixMath.vala - Copyright (C) 2013, 2021 Maia Everett - - 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. -*/ - -using GL; - -namespace ValaGL.Core { - -/** - * A 3-component vector. - */ -public struct Vec3 { - public GLfloat data[3]; - - /** - * Creates a new vector, zero initialized. - */ - public Vec3() { - - } - - /** - * Creates a vector whose contents are the copy of the given data. - */ - public Vec3.from_data (GLfloat x, GLfloat y, GLfloat z) { - data[0] = x; - data[1] = y; - data[2] = z; - } - - /** - * Creates a vector whose contents are the copy of the given array. - */ - public Vec3.from_array ([CCode (array_length = false)] GLfloat[] data) { - this.data[0] = data[0]; - this.data[1] = data[1]; - this.data[2] = data[2]; - } - - /** - * Adds the given vector, component-wise. - */ - public void add (ref Vec3 other) { - data[0] += other.data[0]; - data[1] += other.data[1]; - data[2] += other.data[2]; - } - - /** - * Subtracts the given vector, component-wise. - */ - public void sub (ref Vec3 other) { - data[0] -= other.data[0]; - data[1] -= other.data[1]; - data[2] -= other.data[2]; - } - - /** - * Multiplies the given vector, component-wise. - */ - public void mul_vec (ref Vec3 other) { - data[0] *= other.data[0]; - data[1] *= other.data[1]; - data[2] *= other.data[2]; - } - - /** - * Divides the given vector, component-wise. - */ - public void div_vec (ref Vec3 other) { - data[0] /= other.data[0]; - data[1] /= other.data[1]; - data[2] /= other.data[2]; - } - - /** - * Computes the dot product of this vector and the other vector. - */ - public GLfloat dot_product (ref Vec3 other) { - return data[0] * other.data[0] + data[1] * other.data[1] + data[2] * other.data[2]; - } - - /** - * Computes the cross product of this vector and the other vector. - */ - public Vec3 cross_product (ref Vec3 other) { - return Vec3.from_data( - data[1] * other.data[2] - data[2] * other.data[1], - data[2] * other.data[0] - data[0] * other.data[2], - data[0] * other.data[1] - data[1] * other.data[0]); - } - - /** - * Multiplies the vector by the given scalar. - */ - public void mul (GLfloat factor) { - data[0] *= factor; - data[1] *= factor; - data[2] *= factor; - } - - /** - * Divides the vector by the given scalar. - */ - public void div (GLfloat factor) { - data[0] /= factor; - data[1] /= factor; - data[2] /= factor; - } - - /** - * Computes the norm of this vector. - */ - public GLfloat norm () { - return Math.sqrtf (dot_product (ref this)); - } - - /** - * Normalizes this vector, dividing it by its norm. - * If the norm is zero, the result is undefined. - */ - public void normalize () { - div (norm ()); - } - - /** - * Convenience accessor for data[0]. - */ - public GLfloat x { - get { return data[0]; } - } - - /** - * Convenience accessor for data[1]. - */ - public GLfloat y { - get { return data[1]; } - } - - /** - * Convenience accessor for data[2]. - */ - public GLfloat z { - get { return data[2]; } - } -} - -/** - * A 4-component vector. - */ -public struct Vec4 { - public GLfloat data[4]; - - /** - * Creates a new vector, zero initialized. - */ - public Vec4() { - - } - - /** - * Creates a vector whose contents are the copy of the given data. - */ - public Vec4.from_data (GLfloat x, GLfloat y, GLfloat z, GLfloat w) { - data[0] = x; - data[1] = y; - data[2] = z; - data[3] = w; - } - - /** - * Creates a vector whose contents are the copy of the given array. - */ - public Vec4.from_array ([CCode (array_length = false)] GLfloat[] data) { - this.data[0] = data[0]; - this.data[1] = data[1]; - this.data[2] = data[2]; - this.data[3] = data[3]; - } - - /** - * Expands a 3x3 vector plus scalar into a 4x4 vector. - */ - public Vec4.expand (ref Vec3 vec3, GLfloat w) { - this.data[0] = vec3.data[0]; - this.data[1] = vec3.data[1]; - this.data[2] = vec3.data[2]; - this.data[3] = w; - } - - /** - * Adds the given vector, component-wise. - */ - public void add (ref Vec4 other) { - data[0] += other.data[0]; - data[1] += other.data[1]; - data[2] += other.data[2]; - data[3] += other.data[3]; - } - - /** - * Subtracts the given vector, component-wise. - */ - public void sub (ref Vec4 other) { - data[0] -= other.data[0]; - data[1] -= other.data[1]; - data[2] -= other.data[2]; - data[3] -= other.data[3]; - } - - /** - * Multiplies the given vector, component-wise. - */ - public void mul_vec (ref Vec4 other) { - data[0] *= other.data[0]; - data[1] *= other.data[1]; - data[2] *= other.data[2]; - data[3] *= other.data[3]; - } - - /** - * Divides the given vector, component-wise. - */ - public void div_vec (ref Vec4 other) { - data[0] /= other.data[0]; - data[1] /= other.data[1]; - data[2] /= other.data[2]; - data[3] /= other.data[3]; - } - - /** - * Computes the dot product of this vector and the other vector. - */ - public GLfloat dot_product (ref Vec4 other) { - return data[0] * other.data[0] + data[1] * other.data[1] - + data[2] * other.data[2] + data[3] * other.data[3]; - } - - - /** - * Multiplies the vector by the given scalar. - */ - public void mul (GLfloat factor) { - data[0] *= factor; - data[1] *= factor; - data[2] *= factor; - data[3] *= factor; - } - - /** - * Divides the vector by the given scalar. - */ - public void div (GLfloat factor) { - data[0] /= factor; - data[1] /= factor; - data[2] /= factor; - data[3] /= factor; - } - - /** - * Computes the norm of this vector. - */ - public GLfloat norm () { - return Math.sqrtf (dot_product(ref this)); - } - - /** - * Normalizes this vector, dividing it by its norm. - * If the norm is zero, the result is undefined. - */ - public void normalize () { - div (norm ()); - } - - /** - * Convenience accessor for data[0]. - */ - public GLfloat x { - get { return data[0]; } - } - - /** - * Convenience accessor for data[1]. - */ - public GLfloat y { - get { return data[1]; } - } - - /** - * Convenience accessor for data[2]. - */ - public GLfloat z { - get { return data[2]; } - } - - /** - * Convenience accessor for data[3]. - */ - public GLfloat w { - get { return data[3]; } - } -} - -/** - * A 3x3 matrix. - */ -public struct Mat3 { - public float data[9]; - - /** - * Creates a new matrix, zero initialized. - */ - public Mat3() { - - } - - /** - * Creates a matrix whose contents are the copy of the given data. - * Warning: the data are specified in column-first-index order, which is different from - * the internal storage format (row-first-index). - */ - public Mat3.from_data (GLfloat a11, GLfloat a12, GLfloat a13, - GLfloat a21, GLfloat a22, GLfloat a23, - GLfloat a31, GLfloat a32, GLfloat a33) { - data[0] = a11; - data[1] = a21; - data[2] = a31; - - data[3] = a12; - data[4] = a22; - data[5] = a32; - - data[6] = a13; - data[7] = a23; - data[8] = a33; - } - - /** - * Given two vectors ``a`` and ``b``, computes a matrix equal to ``a * bT``. - */ - public Mat3.from_vec_mul (ref Vec3 a, ref Vec3 b) { - data[0] = a.data[0] * b.data[0]; - data[1] = a.data[1] * b.data[0]; - data[2] = a.data[2] * b.data[0]; - - data[3] = a.data[0] * b.data[1]; - data[4] = a.data[1] * b.data[1]; - data[5] = a.data[2] * b.data[1]; - - data[6] = a.data[0] * b.data[2]; - data[7] = a.data[1] * b.data[2]; - data[8] = a.data[2] * b.data[2]; - } - - /** - * Creates a matrix whose contents are the copy of the given array, assumed to have at least 9 elements. - */ - public Mat3.from_array ([CCode (array_length = false)] GLfloat[] data) { - this.data = data; - } - - /** - * Creates an identity matrix. - */ - public Mat3.identity () { - data[0 * 3 + 0] = 1; - data[1 * 3 + 1] = 1; - data[2 * 3 + 2] = 1; - } - - /** - * Adds the given matrix, component-wise. - */ - public void add (ref Mat3 other) { - for (int i = 0; i < 9; i++) { - data[i] += other.data[i]; - } - } - - /** - * Subtracts the given matrix, component-wise. - */ - public void sub (ref Mat3 other) { - for (int i = 0; i < 9; i++) { - data[i] -= other.data[i]; - } - } - - /** - * Multiplies the matrix by the given scalar, component-wise. - */ - public void mul (GLfloat factor) { - for (int i = 0; i < 9; i++) { - data[i] *= factor; - } - } - - /** - * Divides the matrix by the given scalar, component-wise. - */ - public void div (GLfloat factor) { - for (int i = 0; i < 9; i++) { - data[i] /= factor; - } - } - - /** - * Multiplies the given matrix using the linear algebra definition of matrix multiplication. - */ - public void mul_mat (ref Mat3 other) { - float res[9]; // Zero initialized - - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - res[j * 3 + i] = 0; - - for (int k = 0; k < 3; k++) { - res[j * 3 + i] += data[k * 3 + i] * other.data[j * 3 + k]; - } - } - } - - data = res; - } - - /** - * Multiplies this matrix by the given vector and returns the result as a new vector. - */ - public Vec3 mul_vec (ref Vec3 vec) { - Vec3 res = Vec3(); // Zero initialized - - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - res.data[i] += data[j * 3 + i] * vec.data[j]; - } - } - - return res; - } - - /** - * Returns a new matrix that is the transposition of this matrix. - */ - public Mat3 transposed () { - Mat3 res = Mat3(); - - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - res.data[i * 3 + j] = data[j * 3 + i]; - } - } - - return res; - } - - /** - * Computes the determinant of this matrix. - */ - public GLfloat det () { - return det_helper3 (data[0:3], data[3:6], data[6:9]); - } - - /** - * Returns a new matrix that is the inversion of this matrix. - * @param success Set to ``false`` if the matrix cannot be inverted (its determinant is zero) - * and ``true`` otherwise. - * @return The inverted matrix if the matrix was not successfully inverted, - * otherwise the return value is undefined. - */ - public Mat3 inverted (out bool success) { - GLfloat det = det (); - - if (Math.fabsf (det) < 0.00001f) { - success = false; - return Mat3 (); - } - - success = true; - - GLfloat inv_det = 1.0f / det; - Mat3 res = Mat3 (); - - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - int i1 = (i + 1) % 3; - int j1 = (j + 1) % 3; - int i2 = (i + 2) % 3; - int j2 = (j + 2) % 3; - // Warning: computing determinants from transposed matrix! i becomes j and the other way round - res.data [j * 3 + i] = inv_det * - (data[i1 * 3 + j1] * data[i2 * 3 + j2] - data[i2 * 3 + j1] * data[i1 * 3 + j2]); - } - } - - return res; - } -} - -/** - * A 4x4 matrix. - */ -public struct Mat4 { - public float data[16]; - - /** - * Creates a new matrix, zero initialized. - */ - public Mat4() { - - } - - /** - * Creates a matrix whose contents are the copy of the given data. - * Warning: the data are specified in column-first-index order, which is different from - * the internal storage format (row-first-index). - */ - public Mat4.from_data (GLfloat a11, GLfloat a12, GLfloat a13, GLfloat a14, - GLfloat a21, GLfloat a22, GLfloat a23, GLfloat a24, - GLfloat a31, GLfloat a32, GLfloat a33, GLfloat a34, - GLfloat a41, GLfloat a42, GLfloat a43, GLfloat a44) { - data[0] = a11; - data[1] = a21; - data[2] = a31; - data[3] = a41; - - data[4] = a12; - data[5] = a22; - data[6] = a32; - data[7] = a42; - - data[8] = a13; - data[9] = a23; - data[10] = a33; - data[11] = a43; - - data[12] = a14; - data[13] = a24; - data[14] = a34; - data[15] = a44; - } - - /** - * Given two vectors ``a`` and ``b``, computes a matrix equal to ``a * bT``. - */ - public Mat4.from_vec_mul (ref Vec4 a, ref Vec4 b) { - data[0] = a.data[0] * b.data[0]; - data[1] = a.data[1] * b.data[0]; - data[2] = a.data[2] * b.data[0]; - data[3] = a.data[3] * b.data[0]; - - data[4] = a.data[0] * b.data[1]; - data[5] = a.data[1] * b.data[1]; - data[6] = a.data[2] * b.data[1]; - data[7] = a.data[3] * b.data[1]; - - data[8] = a.data[0] * b.data[2]; - data[9] = a.data[1] * b.data[2]; - data[10] = a.data[2] * b.data[2]; - data[11] = a.data[3] * b.data[2]; - - data[12] = a.data[0] * b.data[3]; - data[13] = a.data[1] * b.data[3]; - data[14] = a.data[2] * b.data[3]; - data[15] = a.data[3] * b.data[3]; - } - - /** - * Creates a matrix whose contents are the copy of the given array, assumed to have at least 16 elements. - */ - public Mat4.from_array ([CCode (array_length = false)] GLfloat[] data) { - this.data = data; - } - - /** - * Creates an identity matrix. - */ - public Mat4.identity () { - data[0 * 4 + 0] = 1; - data[1 * 4 + 1] = 1; - data[2 * 4 + 2] = 1; - data[3 * 4 + 3] = 1; - } - - /** - * Creates an expansion of the given 3x3 matrix into 4x4: - * - * A 0 - * - * 0 1 - */ - public Mat4.expand (ref Mat3 mat3) { - data[0] = mat3.data[0]; - data[1] = mat3.data[1]; - data[2] = mat3.data[2]; - - data[4] = mat3.data[3]; - data[5] = mat3.data[4]; - data[6] = mat3.data[5]; - - data[8] = mat3.data[6]; - data[9] = mat3.data[7]; - data[10] = mat3.data[8]; - - data[3 * 4 + 3] = 1; - } - - /** - * Adds the given matrix, component-wise. - */ - public void add (ref Mat4 other) { - for (int i = 0; i < 16; i++) { - data[i] += other.data[i]; - } - } - - /** - * Subtracts the given matrix, component-wise. - */ - public void sub (ref Mat4 other) { - for (int i = 0; i < 16; i++) { - data[i] -= other.data[i]; - } - } - - /** - * Multiplies the matrix by the given scalar, component-wise. - */ - public void mul (GLfloat factor) { - for (int i = 0; i < 16; i++) { - data[i] *= factor; - } - } - - /** - * Divides the matrix by the given scalar, component-wise. - */ - public void div (GLfloat factor) { - for (int i = 0; i < 16; i++) { - data[i] /= factor; - } - } - - /** - * Multiplies the given matrix using the linear algebra definition of matrix multiplication. - */ - public void mul_mat (ref Mat4 other) { - float res[16]; // Zero initialized - - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - res[j * 4 + i] = 0; - - for (int k = 0; k < 4; k++) { - res[j * 4 + i] += data[k * 4 + i] * other.data[j * 4 + k]; - } - } - } - - data = res; - } - - /** - * Multiplies this matrix by the given vector and returns the result as a new vector. - */ - public Vec4 mul_vec (ref Vec4 vec) { - Vec4 res = Vec4(); // Zero initialized - - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - res.data[i] += data[j * 4 + i] * vec.data[j]; - } - } - - return res; - } - - /** - * Returns a new matrix that is the transposition of this matrix. - */ - public Mat4 transposed () { - Mat4 res = Mat4(); - - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - res.data[i * 4 + j] = data[j * 4 + i]; - } - } - - return res; - } - - /** - * Computes the determinant of this matrix. - */ - public GLfloat det () { - return data[0] * det_helper3 (data[4:8], data[9:12], data[13:16]) - - data[4] * det_helper3 (data[1:4], data[9:12], data[13:16]) - + data[8] * det_helper3 (data[1:4], data[4:8], data[13:16]) - - data[12] * det_helper3 (data[1:4], data[4:8], data[9:12] ); - } - - /** - * Returns a new matrix that is the inversion of this matrix. - * @param success Set to ``false`` if the matrix cannot be inverted (its determinant is zero) - * and ``true`` otherwise. - * @return The inverted matrix if the matrix was not successfully inverted, - * otherwise the return value is undefined. - */ - public Mat4 inverted (out bool success) { - GLfloat det = det (); - - if (Math.fabsf (det) < 0.00001f) { - success = false; - return Mat4 (); - } - - success = true; - - GLfloat inv_det = 1.0f / det; - Mat3 transposed_submatrix = Mat3 (); - Mat4 res = Mat4 (); - - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - int i1 = (i + 1) % 4; - int j1 = (j + 1) % 4; - int i2 = (i + 2) % 4; - int j2 = (j + 2) % 4; - int i3 = (i + 3) % 4; - int j3 = (j + 3) % 4; - - // Warning: computing determinants from transposed matrix! i becomes j and the other way round - transposed_submatrix.data = { - data[i1 * 4 + j1], data[i1 * 4 + j2], data[i1 * 4 + j3], - data[i2 * 4 + j1], data[i2 * 4 + j2], data[i2 * 4 + j3], - data[i3 * 4 + j1], data[i3 * 4 + j2], data[i3 * 4 + j3] - }; - - res.data [j * 4 + i] = inv_det * transposed_submatrix.det (); - } - } - - return res; - } -} - -private static GLfloat det_helper3 ([CCode (array_length = false)] GLfloat[] col1, - [CCode (array_length = false)] GLfloat[] col2, - [CCode (array_length = false)] GLfloat[] col3) { - return col1[0] * (col2[1] * col3[2] - col2[2] * col3[1]) - + col2[0] * (col3[1] * col1[2] - col3[2] * col1[1]) - + col3[0] * (col1[1] * col2[2] - col1[2] * col2[1]); -} - -} diff --git a/ValaGL.Core/Util.vala b/ValaGL.Core/Util.vala deleted file mode 100644 index f61141f..0000000 --- a/ValaGL.Core/Util.vala +++ /dev/null @@ -1,72 +0,0 @@ -/* - Util.vala - Copyright (C) 2010-2013 Maia Everett - - 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. -*/ - -namespace ValaGL.Core { - -/** - * Static helper class for miscellaneous utilities essential to the application. - */ -public class Util : GLib.Object { - private Util () {} - - private static bool first_run = true; - private static bool local_install; - - /** - * Checks if the application is being run from the root of the build directory. - * - * This implementation is rather hackish. It checks for the existence of - * a specific source file, as GLib provides no way to get the application - * executable directory. - */ - public static bool is_local_install () { - if (first_run) { - local_install = FileUtils.test ("ValaGL/App.vala", FileTest.EXISTS); - first_run = false; - } - - return local_install; - } - - private static string get_data_dir () { - if (is_local_install ()) - return "data"; - - return AppConfig.APP_DATA_DIR; - } - - /** - * Merges the application resources path with the specified relative path. - * - * If ``is_local_install`` is true, the application resources path is simply - * the ``data`` subdirectory of the build directory. Otherwise, it is the data - * installation directory specified at build time. - * - * @param rel_path The relative path of the resource in the resource directory - */ - public static string data_file_path (string rel_path) { - return Path.build_filename (get_data_dir (), rel_path); - } -} - -} diff --git a/ValaGL.Core/VAO.vala b/ValaGL.Core/VAO.vala deleted file mode 100644 index 1b1f16c..0000000 --- a/ValaGL.Core/VAO.vala +++ /dev/null @@ -1,73 +0,0 @@ -/* - VAO.vala - Copyright (C) 2021 Maia Everett - - 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. -*/ - -using GL; - -namespace ValaGL.Core { - -/** - * Encapsulation of an OpenGL vertex array object. - * - * The underlying OpenGL vertex array is destroyed when this object is finally unreferenced. - */ -public class VAO : Object { - private GLuint id; - - /** - * Creates a vertex array object. - */ - public VAO () throws CoreError { - GLuint id_array[1]; - glGenVertexArrays(1, id_array); - id = id_array[0]; - - if (id == 0) { - throw new CoreError.VBO_INIT ("Cannot allocate vertex array object"); - } - } - - /** - * Registers a VBO binding to the given shader attribute in this VAO. - */ - public void register_vbo (VBO vbo, GLint attribute, GLsizei stride) { - make_current (); - vbo.make_current (); - glVertexAttribPointer (attribute, stride, GL_FLOAT, (GLboolean) GL_FALSE, 0, null); - } - - /** - * Makes this VAO current for future drawing operations in the OpenGL context. - */ - public void make_current () { - glBindVertexArray(id); - } - - ~VAO () { - if (id != 0) { - GLuint[] id_array = { id }; - glDeleteVertexArrays (1, id_array); - } - } -} - -} diff --git a/ValaGL.Core/VBO.vala b/ValaGL.Core/VBO.vala deleted file mode 100644 index e385d4c..0000000 --- a/ValaGL.Core/VBO.vala +++ /dev/null @@ -1,84 +0,0 @@ -/* - VBO.vala - Copyright (C) 2013, 2021 Maia Everett - - 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. -*/ - -using GL; - -namespace ValaGL.Core { - -/** - * Encapsulation of an OpenGL vertex buffer object. - * - * The underlying OpenGL buffer is destroyed when this object is finally unreferenced. - */ -public class VBO : Object { - private GLuint id; - - /** - * Creates a vertex buffer object. - * - * @param data Array to bind to the OpenGL buffer - */ - public VBO (GLfloat[] data) throws CoreError { - GLuint id_array[1]; - glGenBuffers (1, id_array); - id = id_array[0]; - - if (id == 0) { - throw new CoreError.VBO_INIT ("Cannot allocate vertex buffer object"); - } - - glBindBuffer (GL_ARRAY_BUFFER, id); - glBufferData (GL_ARRAY_BUFFER, data.length * sizeof (GLfloat), (GLvoid[]) data, GL_STATIC_DRAW); - glBindBuffer (GL_ARRAY_BUFFER, 0); - } - - /** - * Makes this VBO current for future drawing operations in the OpenGL context. - */ - public void make_current () { - glBindBuffer(GL_ARRAY_BUFFER, id); - } - - /** - * Makes this VBO current for future drawing operations in the OpenGL context, - * and sets it up as the source of vertex data for the given shader attribute. - * - * For the meaning of ``attribute`` and ``stride``, see ``glVertexAttribPointer``. - * - * @param attribute The index of the generic vertex attribute to be modified. - * @param stride The byte offset between consecutive generic vertex attributes. - */ - public void apply_as_vertex_array (GLint attribute, GLsizei stride) { - make_current (); - glVertexAttribPointer (attribute, stride, GL_FLOAT, (GLboolean) GL_FALSE, 0, null); - } - - ~VBO () { - if (id != 0) { - GLuint[] id_array = { id }; - glDeleteBuffers (1, id_array); - } - } -} - -} diff --git a/ValaGL.Core/_namespace.vala b/ValaGL.Core/_namespace.vala deleted file mode 100644 index 1b02af1..0000000 --- a/ValaGL.Core/_namespace.vala +++ /dev/null @@ -1,29 +0,0 @@ -/* - _namespace.vala - Copyright (C) 2013, 2021 Maia Everett - - 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. -*/ - -/** - * Helper classes for basic OpenGL and system functionality. - */ -namespace ValaGL.Core { - -} diff --git a/ValaGL/App.vala b/ValaGL/App.vala deleted file mode 100644 index 12ef19d..0000000 --- a/ValaGL/App.vala +++ /dev/null @@ -1,210 +0,0 @@ -/* - App.vala - Copyright (C) 2013, 2021 Maia Everett - - 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. -*/ - -using SDL; -using SDL.Input; -using SDL.Video; - -namespace ValaGL { - -/** - * The singleton application, responsible for managing the fullscreen SDL main window. - */ -public class App : GLib.Object { - private enum EventCode { - TIMER_EVENT - } - - private Window window; - private SDL.Video.GL.Context context; - private bool done; - private Canvas canvas; - private SDL.Timer? timer; - - private uint initial_rotation_angle = 30; - private uint timer_ticks; - - /** - * Creates the application. - */ - public App() { - // Do nothing - } - - /** - * Runs the application. - */ - public void run () throws AppError { - try { - init_video (); - init_timer (); - - while (!done) { - process_events (); - draw (); - } - } finally { - if (timer != null) { - timer.remove (); - timer = null; - } - - // Free the canvas and associated GL resources - canvas = null; - } - } - - private void init_video () throws AppError { - SDL.Video.GL.set_attribute (SDL.Video.GL.Attributes.RED_SIZE, 8); - SDL.Video.GL.set_attribute (SDL.Video.GL.Attributes.GREEN_SIZE, 8); - SDL.Video.GL.set_attribute (SDL.Video.GL.Attributes.BLUE_SIZE, 8); - SDL.Video.GL.set_attribute (SDL.Video.GL.Attributes.ALPHA_SIZE, 8); - SDL.Video.GL.set_attribute (SDL.Video.GL.Attributes.DEPTH_SIZE, 16); - SDL.Video.GL.set_attribute (SDL.Video.GL.Attributes.DOUBLEBUFFER, 1); - - // Request OpenGL 3.3 core profile - SDL.Video.GL.set_attribute (SDL.Video.GL.Attributes.CONTEXT_PROFILE_MASK, SDL.Video.GL.ProfileType.CORE); - SDL.Video.GL.set_attribute (SDL.Video.GL.Attributes.CONTEXT_MAJOR_VERSION, 3); - SDL.Video.GL.set_attribute (SDL.Video.GL.Attributes.CONTEXT_MINOR_VERSION, 3); - - // Ask for multisampling if possible - SDL.Video.GL.set_attribute (SDL.Video.GL.Attributes.MULTISAMPLEBUFFERS, 1); - SDL.Video.GL.set_attribute (SDL.Video.GL.Attributes.MULTISAMPLESAMPLES, 4); - - // Enter fullscreen mode. - window = new Window ("Vala OpenGL Skeletal Application", -1, -1, -1, -1, - WindowFlags.FULLSCREEN_DESKTOP | WindowFlags.OPENGL); - - if (window == null) { - throw new AppError.INIT ("Could not set video mode"); - } - - context = SDL.Video.GL.Context.create (window); - - if (context == null) { - throw new AppError.INIT ("Could not create GL context"); - } - - canvas = new Canvas (); - - // Get the screen width and height and set up the viewport accordingly - int width; - int height; - window.get_size (out width, out height); - canvas.resize_gl (width, height); - canvas.update_scene_data (initial_rotation_angle); - } - - private void init_timer () { - timer = SDL.Timer (10, (interval) => { - // Executed in a separate thread, so we exchange information with the UI thread through events - SDL.Event event = SDL.Event () { - type = EventType.USEREVENT - }; - event.user.code = EventCode.TIMER_EVENT; - Event.push (event); - return interval; - }); - } - - private void draw () { - canvas.paint_gl (); - SDL.Video.GL.swap_window (window); - } - - private void process_events () { - Event event; - - while (Event.poll (out event) == 1) { - switch (event.type) { - case EventType.QUIT: - done = true; - break; - case EventType.WINDOWEVENT: - on_window_event (event.window); - break; - case EventType.KEYDOWN: - on_keyboard_event (event.key); - break; - case EventType.USEREVENT: - on_timer_event (); - break; - } - } - } - - private void on_window_event (WindowEvent event) { - if (event.event == WindowEventType.RESIZED) { - canvas.resize_gl (event.data1, event.data2); - } - } - - private void on_keyboard_event (KeyboardEvent event) { - switch (event.keysym.sym) { - case Keycode.ESCAPE: - // Close on Esc - on_quit(); - break; - default: - // Insert any other keyboard combinations here. - break; - } - } - - private void on_timer_event () { - timer_ticks = (timer_ticks + 1) % 1800; - canvas.update_scene_data (initial_rotation_angle + timer_ticks / 5.0f); - } - - private void on_quit () { - Event e = Event () { - type = EventType.QUIT - }; - Event.push(e); - } - - /** - * Application entry point. - * - * Creates an instance of the ValaGL application and runs the SDL event loop - * until the user exits the application. - * - * @param args Command line arguments. Ignored. - */ - public static int main (string[] args) { - SDL.init (InitFlag.VIDEO | InitFlag.TIMER); - - try { - new App ().run (); - } catch (AppError e) { - stderr.printf("Fatal error: %s\n", e.message); - return 1; - } finally { - SDL.quit (); - } - - return 0; - } -} - -} diff --git a/ValaGL/AppError.vala b/ValaGL/AppError.vala deleted file mode 100644 index 1a167f9..0000000 --- a/ValaGL/AppError.vala +++ /dev/null @@ -1,31 +0,0 @@ -/* - AppError.vala - Copyright (C) 2013, 2021 Maia Everett - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -namespace ValaGL { - -/** - * Error domain for the ValaGL application. - */ -public errordomain AppError { - /** - * Indicates an application initialization error (e.g. inability to initialize SDL or OpenGL). - */ - INIT -} - -} diff --git a/ValaGL/Canvas.vala b/ValaGL/Canvas.vala deleted file mode 100644 index 20a94fe..0000000 --- a/ValaGL/Canvas.vala +++ /dev/null @@ -1,215 +0,0 @@ -/* - Canvas.vala - Copyright (C) 2013 Maia Everett - - 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. -*/ - -using GL; -using ValaGL.Core; - -namespace ValaGL { - -private const GLfloat[] cube_vertices = { - // front - -1, -1, 1, - 1, -1, 1, - 1, 1, 1, - -1, 1, 1, - // back - -1, -1, -1, - 1, -1, -1, - 1, 1, -1, - -1, 1, -1, -}; - -private const GLfloat[] cube_colors = { - // front colors - 1, 0, 0, - 0, 1, 0, - 0, 0, 1, - 1, 1, 1, - // back colors - 1, 0, 0, - 0, 1, 0, - 0, 0, 1, - 1, 1, 1, -}; - -private const GLushort cube_elements[] = { - // front - 0, 1, 2, - 2, 3, 0, - // top - 1, 5, 6, - 6, 2, 1, - // back - 7, 6, 5, - 5, 4, 7, - // bottom - 4, 0, 3, - 3, 7, 4, - // left - 4, 5, 1, - 1, 0, 4, - // right - 3, 2, 6, - 6, 7, 3, -}; - -/** - * The OpenGL canvas associated with the application main window. - * - * This class is responsible for initializing the state of the OpenGL context - * and managing resize and redraw events sent by the underlying SDL window. - */ -public class Canvas : Object { - private GLProgram gl_program; - private VBO coord_vbo; - private VBO color_vbo; - private VAO vao; - private IBO element_ibo; - - private Camera camera; - private Mat4 model_matrix; - - private GLint unif_transform; - private GLint attr_coord3d; - private GLint attr_v_color; - private GLfloat rotation_angle; - - /** - * Instantiates a new canvas object. - * - * Assumes that the desired OpenGL context is already selected. - * - * Initializes GLEW, global OpenGL state, and GPU programs that will be - * used for rendering. - */ - public Canvas () throws AppError { - glEnable (GL_DEBUG_OUTPUT); - glDebugMessageCallback (on_gl_error); - - // GL initialization comes here - glClearColor (71.0f/255, 95.0f/255, 121.0f/255, 1); - glEnable (GL_MULTISAMPLE); - glEnable (GL_DEPTH_TEST); - glEnable (GL_BLEND); - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - try { - gl_program = new GLProgram (Util.data_file_path ("shaders/vertex.glsl"), - Util.data_file_path ("shaders/fragment.glsl")); - - unif_transform = gl_program.get_uniform_location ("transform"); - attr_coord3d = gl_program.get_attrib_location ("coord3d"); - attr_v_color = gl_program.get_attrib_location ("v_color"); - - vao = new VAO(); - - coord_vbo = new VBO (cube_vertices); - vao.register_vbo (coord_vbo, attr_coord3d, 3); - - color_vbo = new VBO (cube_colors); - vao.register_vbo (color_vbo, attr_v_color, 3); - - element_ibo = new IBO (cube_elements); - } catch (CoreError e) { - throw new AppError.INIT (e.message); - } - - camera = new Camera(); - Vec3 eye = Vec3.from_data (0, 2, 0); - Vec3 center = Vec3.from_data (0, 0, -2); - Vec3 up = Vec3.from_data (0, 1, 0); - camera.look_at (ref eye, ref center, ref up); - } - - private void on_gl_error (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, string message) { - stderr.printf("GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n", - ( type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : "" ), - type, severity, message ); - } - - /** - * Handler of the window resize event. - * - * It is called for the first time when the SDL window is created and shown, - * and then every time the display resolution changes. - * - * Responsible for setting up the viewport size and perspective projection. - * - * @param width The new window width - * @param height The new window height - */ - public void resize_gl (uint width, uint height) { - glViewport(0, 0, (GLsizei) width, (GLsizei) height); - camera.set_perspective_projection (70, (GLfloat) width / (GLfloat) height, 0.01f, 100f); - } - - /** - * Handler of the window repaint event. - * - * It is called every time the window is created. - * - * Responsible for drawing the OpenGL scene. - */ - public void paint_gl () { - glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - // Compute current transformation matrix for the cube - model_matrix = Mat4.identity (); - - Vec3 translation = Vec3.from_data (0, 0, -4); - GeometryUtil.translate (ref model_matrix, ref translation); - Vec3 rotation = Vec3.from_data (0, 1, 0); - GeometryUtil.rotate (ref model_matrix, rotation_angle, ref rotation); - - // Activate our vertex and fragment shaders for the next drawing operations - gl_program.make_current (); - - // Apply camera before drawing the model - camera.apply (unif_transform, ref model_matrix); - - glEnableVertexAttribArray (attr_coord3d); - glEnableVertexAttribArray (attr_v_color); - - // Apply buffers - vao.make_current (); - element_ibo.make_current (); - - // Draw the cube - glDrawElements (GL_TRIANGLES, cube_elements.length, GL_UNSIGNED_SHORT, null); - glDisableVertexAttribArray (attr_coord3d); - glDisableVertexAttribArray (attr_v_color); - } - - /** - * Updates the scene data. - * - * In this application, the only variable scene data is the rotation angle. - * - * @param rotation_angle The new rotation angle (in degrees) - */ - public void update_scene_data(GLfloat rotation_angle) { - this.rotation_angle = rotation_angle; - } -} - -} diff --git a/ValaGL/_namespace.vala b/ValaGL/_namespace.vala deleted file mode 100644 index abcdbf2..0000000 --- a/ValaGL/_namespace.vala +++ /dev/null @@ -1,29 +0,0 @@ -/* - _namespace.vala - Copyright (C) 2013, 2021 Maia Everett - - 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. -*/ - -/** - * Main ValaGL namespace, containing application logic. - */ -namespace ValaGL { - -} diff --git a/cmake/FindGLEW.cmake b/cmake/FindGLEW.cmake deleted file mode 100644 index 540911f..0000000 --- a/cmake/FindGLEW.cmake +++ /dev/null @@ -1,50 +0,0 @@ -# -# Try to find GLEW library and include path. -# Once done this will define -# -# GLEW_FOUND -# GLEW_INCLUDE_PATH -# GLEW_LIBRARY -# - -IF (WIN32) - FIND_PATH( GLEW_INCLUDE_PATH GL/glew.h - $ENV{PROGRAMFILES}/GLEW/include - ${GLEW_ROOT_DIR}/include - DOC "The directory where GL/glew.h resides") - - FIND_LIBRARY( GLEW_LIBRARY - NAMES glew GLEW glew32 glew32s - PATHS - $ENV{PROGRAMFILES}/GLEW/lib - ${PROJECT_SOURCE_DIR}/src/nvgl/glew/bin - ${PROJECT_SOURCE_DIR}/src/nvgl/glew/lib - DOC "The GLEW library") -ELSE (WIN32) - FIND_PATH( GLEW_INCLUDE_PATH GL/glew.h - /usr/include - /usr/local/include - /sw/include - /opt/local/include - ${GLEW_ROOT_DIR}/include - DOC "The directory where GL/glew.h resides") - - # Prefer the static library. - FIND_LIBRARY( GLEW_LIBRARY - NAMES libGLEW.a GLEW - PATHS - /usr/lib64 - /usr/lib - /usr/local/lib64 - /usr/local/lib - /sw/lib - /opt/local/lib - ${GLEW_ROOT_DIR}/lib - DOC "The GLEW library") -ENDIF (WIN32) - -SET(GLEW_FOUND "NO") -IF (GLEW_INCLUDE_PATH AND GLEW_LIBRARY) - SET(GLEW_LIBRARIES ${GLEW_LIBRARY}) - SET(GLEW_FOUND "YES") -ENDIF (GLEW_INCLUDE_PATH AND GLEW_LIBRARY) diff --git a/cmake/FindGLib.cmake b/cmake/FindGLib.cmake deleted file mode 100644 index ece390f..0000000 --- a/cmake/FindGLib.cmake +++ /dev/null @@ -1,33 +0,0 @@ -message("-- Checking for Glib >= ${GLIB_REQUIRED_VERSION}...") -pkg_check_modules(GLIB2 glib-2.0>=${GLIB_REQUIRED_VERSION}) -message("-- Checking for GObject...") -pkg_check_modules(GOBJECT gobject-2.0) -message("-- Checking for GIO...") -pkg_check_modules(GIO gio-2.0) -message("-- Checking for GModule...") -pkg_check_modules(GMODULE gmodule-2.0) - -if(GLIB2_FOUND AND GOBJECT_FOUND AND GMODULE_FOUND AND GIO_FOUND) - set(GLIB_FOUND TRUE) - - set(GLIB_ALL_INCLUDES - ${GLIB2_INCLUDE_DIRS} - ${GOBJECT_INCLUDE_DIRS} - ${GIO_INCLUDE_DIRS} - ${GMODULE_INCLUDE_DIRS} - ) - set(GLIB_ALL_CFLAGS - ${GLIB2_CFLAGS_OTHER} - ${GOBJECT_CFLAGS_OTHER} - ${GIO_CFLAGS_OTHER} - ${GMODULE_CFLAGS_OTHER} - ) - set(GLIB_ALL_LIBS - ${GLIB2_LDFLAGS} - ${GOBJECT_LDFLAGS} - ${GIO_LDFLAGS} - ${GMODULE_LDFLAGS} - ) -else() - set(GLIB_FOUND FALSE) -endif() diff --git a/cmake/FindVala.cmake b/cmake/FindVala.cmake deleted file mode 100644 index d4bd922..0000000 --- a/cmake/FindVala.cmake +++ /dev/null @@ -1,65 +0,0 @@ -## -# Copyright 2009-2010 Jakob Westhoff. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY JAKOB WESTHOFF ``AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -# EVENT SHALL JAKOB WESTHOFF OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# The views and conclusions contained in the software and documentation are those -# of the authors and should not be interpreted as representing official policies, -# either expressed or implied, of Jakob Westhoff -## - -## -# Find module for the Vala compiler (valac) -# -# This module determines wheter a Vala compiler is installed on the current -# system and where its executable is. -# -# Call the module using "find_package(Vala) from within your CMakeLists.txt. -# -# The following variables will be set after an invocation: -# -# VALA_FOUND Whether the vala compiler has been found or not -# VALA_EXECUTABLE Full path to the valac executable if it has been found -# VALA_VERSION Version number of the available valac -## - - -# Search for the valac executable in the usual system paths. -find_program(VALA_EXECUTABLE - NAMES "valac-${VALA_REQUIRED_VERSION}" valac) - -# Handle the QUIETLY and REQUIRED arguments, which may be given to the find call. -# Furthermore set VALA_FOUND to TRUE if Vala has been found (aka. -# VALA_EXECUTABLE is set) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Vala DEFAULT_MSG VALA_EXECUTABLE) - -mark_as_advanced(VALA_EXECUTABLE) - -# Determine the valac version -if(VALA_FOUND) - execute_process(COMMAND ${VALA_EXECUTABLE} "--version" - OUTPUT_VARIABLE "VALA_VERSION") - string(REPLACE "Vala" "" "VALA_VERSION" ${VALA_VERSION}) - string(STRIP ${VALA_VERSION} "VALA_VERSION") -endif(VALA_FOUND) diff --git a/cmake/FindValadoc.cmake b/cmake/FindValadoc.cmake deleted file mode 100644 index 2fc0c73..0000000 --- a/cmake/FindValadoc.cmake +++ /dev/null @@ -1,20 +0,0 @@ - -# Search for the valadocc executable in the usual system paths. -find_program(VALADOC_EXECUTABLE NAMES valadoc) - -# Handle the QUIETLY and REQUIRED arguments, which may be given to the find call. -# Furthermore set VALA_FOUND to TRUE if Vala has been found (aka. -# VALA_EXECUTABLE is set) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Valadoc DEFAULT_MSG VALADOC_EXECUTABLE) - -mark_as_advanced(VALADOC_EXECUTABLE) - -# Determine the valac version -if(VALA_FOUND) - execute_process(COMMAND ${VALA_EXECUTABLE} "--version" - OUTPUT_VARIABLE "VALA_VERSION") - string(REPLACE "Vala" "" "VALA_VERSION" ${VALA_VERSION}) - string(STRIP ${VALA_VERSION} "VALA_VERSION") -endif(VALA_FOUND) diff --git a/cmake/ParseArguments.cmake b/cmake/ParseArguments.cmake deleted file mode 100644 index 717c0f5..0000000 --- a/cmake/ParseArguments.cmake +++ /dev/null @@ -1,36 +0,0 @@ -## -# This is a helper Macro to parse optional arguments in Macros/Functions -# It has been taken from the public CMake wiki. -# See http://www.cmake.org/Wiki/CMakeMacroParseArguments for documentation and -# licensing. -## -macro(parse_arguments prefix arg_names option_names) - set(DEFAULT_ARGS) - foreach(arg_name ${arg_names}) - set(${prefix}_${arg_name}) - endforeach(arg_name) - foreach(option ${option_names}) - set(${prefix}_${option} FALSE) - endforeach(option) - - set(current_arg_name DEFAULT_ARGS) - set(current_arg_list) - foreach(arg ${ARGN}) - set(larg_names ${arg_names}) - list(FIND larg_names "${arg}" is_arg_name) - if(is_arg_name GREATER -1) - set(${prefix}_${current_arg_name} ${current_arg_list}) - set(current_arg_name ${arg}) - set(current_arg_list) - else(is_arg_name GREATER -1) - set(loption_names ${option_names}) - list(FIND loption_names "${arg}" is_option) - if(is_option GREATER -1) - set(${prefix}_${arg} TRUE) - else(is_option GREATER -1) - set(current_arg_list ${current_arg_list} ${arg}) - endif(is_option GREATER -1) - endif(is_arg_name GREATER -1) - endforeach(arg) - set(${prefix}_${current_arg_name} ${current_arg_list}) -endmacro(parse_arguments) diff --git a/cmake/ValaPrecompile.cmake b/cmake/ValaPrecompile.cmake deleted file mode 100644 index 333468c..0000000 --- a/cmake/ValaPrecompile.cmake +++ /dev/null @@ -1,171 +0,0 @@ -## -# Copyright 2009-2010 Jakob Westhoff. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY JAKOB WESTHOFF ``AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -# EVENT SHALL JAKOB WESTHOFF OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# The views and conclusions contained in the software and documentation are those -# of the authors and should not be interpreted as representing official policies, -# either expressed or implied, of Jakob Westhoff -## - -include(ParseArguments) -find_package(Vala REQUIRED) - -## -# Compile vala files to their c equivalents for further processing. -# -# The "vala_precompile" macro takes care of calling the valac executable on the -# given source to produce c files which can then be processed further using -# default cmake functions. -# -# The first parameter provided is a variable, which will be filled with a list -# of c files outputted by the vala compiler. This list can than be used in -# conjuction with functions like "add_executable" or others to create the -# neccessary compile rules with CMake. -# -# The initial variable is followed by a list of .vala files to be compiled. -# Please take care to add every vala file belonging to the currently compiled -# project or library as Vala will otherwise not be able to resolve all -# dependencies. -# -# The following sections may be specified afterwards to provide certain options -# to the vala compiler: -# -# PACKAGES -# A list of vala packages/libraries to be used during the compile cycle. The -# package names are exactly the same, as they would be passed to the valac -# "--pkg=" option. -# -# OPTIONS -# A list of optional options to be passed to the valac executable. This can be -# used to pass "--thread" for example to enable multi-threading support. -# -# CUSTOM_VAPIS -# A list of custom vapi files to be included for compilation. This can be -# useful to include freshly created vala libraries without having to install -# them in the system. -# -# GENERATE_VAPI -# Pass all the needed flags to the compiler to create an internal vapi for -# the compiled library. The provided name will be used for this and a -# .vapi file will be created. -# -# GENERATE_HEADER -# Let the compiler generate a header file for the compiled code. There will -# be a header file as well as an internal header file being generated called -# .h and _internal.h -# -# The following call is a simple example to the vala_precompile macro showing -# an example to every of the optional sections: -# -# vala_precompile(VALA_C -# source1.vala -# source2.vala -# source3.vala -# PACKAGES -# gtk+-2.0 -# gio-1.0 -# posix -# DIRECTORY -# gen -# OPTIONS -# --thread -# CUSTOM_VAPIS -# some_vapi.vapi -# GENERATE_VAPI -# myvapi -# GENERATE_HEADER -# myheader -# ) -# -# Most important is the variable VALA_C which will contain all the generated c -# file names after the call. -## - -macro(vala_precompile output) - parse_arguments(ARGS "PACKAGES;OPTIONS;DIRECTORY;GENERATE_HEADER;GENERATE_VAPI;CUSTOM_VAPIS" "" ${ARGN}) - if(ARGS_DIRECTORY) - set(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${ARGS_DIRECTORY}) - else(ARGS_DIRECTORY) - set(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - endif(ARGS_DIRECTORY) - include_directories(${DIRECTORY}) - set(vala_pkg_opts "") - foreach(pkg ${ARGS_PACKAGES}) - list(APPEND vala_pkg_opts "--pkg=${pkg}") - endforeach(pkg ${ARGS_PACKAGES}) - set(in_files "") - set(out_files "") - set(${output} "") - foreach(src ${ARGS_DEFAULT_ARGS}) - list(APPEND in_files "${CMAKE_CURRENT_SOURCE_DIR}/${src}") - string(REPLACE ".vala" ".c" src ${src}) - string(REPLACE ".gs" ".c" src ${src}) - set(out_file "${DIRECTORY}/${src}") - list(APPEND out_files "${DIRECTORY}/${src}") - list(APPEND ${output} ${out_file}) - endforeach(src ${ARGS_DEFAULT_ARGS}) - - set(custom_vapi_arguments "") - if(ARGS_CUSTOM_VAPIS) - foreach(vapi ${ARGS_CUSTOM_VAPIS}) - list(APPEND custom_vapi_arguments ${vapi}) - endforeach(vapi ${ARGS_CUSTOM_VAPIS}) - endif(ARGS_CUSTOM_VAPIS) - - set(vapi_arguments "") - if(ARGS_GENERATE_VAPI) - list(APPEND out_files "${DIRECTORY}/${ARGS_GENERATE_VAPI}.vapi") - set(vapi_arguments "--internal-vapi=${ARGS_GENERATE_VAPI}.vapi") - - # Header and internal header is needed to generate internal vapi - if (NOT ARGS_GENERATE_HEADER) - set(ARGS_GENERATE_HEADER ${ARGS_GENERATE_VAPI}) - endif(NOT ARGS_GENERATE_HEADER) - endif(ARGS_GENERATE_VAPI) - - set(header_arguments "") - if(ARGS_GENERATE_HEADER) - list(APPEND out_files "${DIRECTORY}/${ARGS_GENERATE_HEADER}.h") - list(APPEND out_files "${DIRECTORY}/${ARGS_GENERATE_HEADER}_internal.h") - list(APPEND header_arguments "--header=${DIRECTORY}/${ARGS_GENERATE_HEADER}.h") - list(APPEND header_arguments "--internal-header=${DIRECTORY}/${ARGS_GENERATE_HEADER}_internal.h") - endif(ARGS_GENERATE_HEADER) - - add_custom_command(OUTPUT ${out_files} - COMMAND - ${VALA_EXECUTABLE} - ARGS - "-C" - ${header_arguments} - ${vapi_arguments} - "-b" ${CMAKE_CURRENT_SOURCE_DIR} - "-d" ${DIRECTORY} - ${vala_pkg_opts} - ${ARGS_OPTIONS} - ${in_files} - ${custom_vapi_arguments} - DEPENDS - ${in_files} - ${ARGS_CUSTOM_VAPIS} - ) -endmacro(vala_precompile) diff --git a/cmake/ValaVersion.cmake b/cmake/ValaVersion.cmake deleted file mode 100644 index 3fff193..0000000 --- a/cmake/ValaVersion.cmake +++ /dev/null @@ -1,96 +0,0 @@ -## -# Copyright 2009-2010 Jakob Westhoff. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY JAKOB WESTHOFF ``AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -# EVENT SHALL JAKOB WESTHOFF OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# The views and conclusions contained in the software and documentation are those -# of the authors and should not be interpreted as representing official policies, -# either expressed or implied, of Jakob Westhoff -## - -include(ParseArguments) -find_package(Vala REQUIRED) - -## -# Ensure a certain valac version is available -# -# The initial argument is the version to check for -# -# It may be followed by a optional parameter to specifiy a version range. The -# following options are valid: -# -# EXACT -# Vala needs to be available in the exact version given -# -# MINIMUM -# The provided version is the minimum version. Therefore Vala needs to be -# available in the given version or any higher version -# -# MAXIMUM -# The provided version is the maximum. Therefore Vala needs to be available -# in the given version or any version older than this -# -# If no option is specified the version will be treated as a minimal version. -## -macro(ensure_vala_version version) - parse_arguments(ARGS "" "MINIMUM;MAXIMUM;EXACT" ${ARGN}) - set(compare_message "") - set(error_message "") - if(ARGS_MINIMUM) - set(compare_message "a minimum ") - set(error_message "or greater ") - elseif(ARGS_MAXIMUM) - set(compare_message "a maximum ") - set(error_message "or less ") - endif(ARGS_MINIMUM) - - message(STATUS - "checking for ${compare_message}Vala version of ${version}" - ) - - unset(version_accepted) - - # MINIMUM is the default if no option is specified - if(ARGS_EXACT) - if(${VALA_VERSION} VERSION_EQUAL ${version} ) - set(version_accepted TRUE) - endif(${VALA_VERSION} VERSION_EQUAL ${version}) - elseif(ARGS_MAXIMUM) - if(${VALA_VERSION} VERSION_LESS ${version} OR ${VALA_VERSION} VERSION_EQUAL ${version}) - set(version_accepted TRUE) - endif(${VALA_VERSION} VERSION_LESS ${version} OR ${VALA_VERSION} VERSION_EQUAL ${version}) - else(ARGS_MAXIMUM) - if(${VALA_VERSION} VERSION_GREATER ${version} OR ${VALA_VERSION} VERSION_EQUAL ${version}) - set(version_accepted TRUE) - endif(${VALA_VERSION} VERSION_GREATER ${version} OR ${VALA_VERSION} VERSION_EQUAL ${version}) - endif(ARGS_EXACT) - - if (NOT version_accepted) - message(FATAL_ERROR - "Vala version ${version} ${error_message}is required." - ) - endif(NOT version_accepted) - - message(STATUS - " found Vala, version ${VALA_VERSION}" - ) -endmacro(ensure_vala_version) diff --git a/cmake/Valadoc.cmake b/cmake/Valadoc.cmake deleted file mode 100644 index cc79074..0000000 --- a/cmake/Valadoc.cmake +++ /dev/null @@ -1,38 +0,0 @@ -include(ParseArguments) -find_package(Valadoc REQUIRED) - -macro(valadoc target outdir) - parse_arguments(ARGS "PACKAGES;OPTIONS;CUSTOM_VAPIS" "" ${ARGN}) - set(vala_pkg_opts "") - foreach(pkg ${ARGS_PACKAGES}) - list(APPEND vala_pkg_opts "--pkg=${pkg}") - endforeach(pkg ${ARGS_PACKAGES}) - - set(vapi_dir_opts "") - foreach(src ${ARGS_CUSTOM_VAPIS}) - get_filename_component(pkg ${src} NAME_WE) - list(APPEND vala_pkg_opts "--pkg=${pkg}") - - get_filename_component(path ${src} PATH) - list(APPEND vapi_dir_opts "--vapidir=${path}") - endforeach(src ${ARGS_DEFAULT_ARGS}) - list(REMOVE_DUPLICATES vapi_dir_opts) - - add_custom_command(TARGET ${target} - COMMAND - ${VALADOC_EXECUTABLE} - ARGS - "--force" - "-b" ${CMAKE_CURRENT_SOURCE_DIR} - "-o" ${outdir} - "--package-name=${CMAKE_PROJECT_NAME}" - "--package-version=${PROJECT_VERSION}" - ${vala_pkg_opts} - ${vapi_dir_opts} - ${ARGS_OPTIONS} - ${in_files} - DEPENDS - ${in_files} - ${ARGS_CUSTOM_VAPIS} - ) -endmacro(valadoc) diff --git a/cmake/config.h.in b/cmake/config.h.in deleted file mode 100644 index 7d62bba..0000000 --- a/cmake/config.h.in +++ /dev/null @@ -1,36 +0,0 @@ -/* - config.h.in - Copyright (C) 2010-2012 Maia Everett - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#ifndef CONFIG_H -#define CONFIG_H - -/* - Macro definitions for CMake - - From a Vala program, you will not need to directly reference this file. - Instead, see AppConfig.vapi. Only change both if you know what you're doing. -*/ - -#define CMAKE_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@" -#define CMAKE_INSTALL_BIN_DIR "@CMAKE_INSTALL_PREFIX@/bin" -#define CMAKE_INSTALL_DATA_DIR "@COMMON_DATA_DIR@" -#define CMAKE_INSTALL_APP_DATA_DIR "@PROJECT_DATA_DIR@" -#define CMAKE_APP_VERSION "@PROJECT_VERSION@" -#define CMAKE_APP_AUTHORS "@PROJECT_AUTHORS@" - -#endif diff --git a/cmake/intltool-merge.pl b/cmake/intltool-merge.pl deleted file mode 100755 index e9fc599..0000000 --- a/cmake/intltool-merge.pl +++ /dev/null @@ -1,1500 +0,0 @@ -#!/usr/bin/perl -w -# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 4 -*- - -# -# The Intltool Message Merger -# -# Copyright (C) 2000, 2003 Free Software Foundation. -# Copyright (C) 2000, 2001 Eazel, Inc -# -# Intltool is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# version 2 published by the Free Software Foundation. -# -# Intltool is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. -# -# Authors: Maciej Stachowiak -# Kenneth Christiansen -# Darin Adler -# -# Proper XML UTF-8'ification written by Cyrille Chepelov -# - -## Release information -my $PROGRAM = "intltool-merge"; -my $PACKAGE = "intltool"; -my $VERSION = "0.41.0"; - -## Loaded modules -use strict; -use Getopt::Long; -use Text::Wrap; -use File::Basename; -use Encode; - -my $must_end_tag = -1; -my $last_depth = -1; -my $translation_depth = -1; -my @tag_stack = (); -my @entered_tag = (); -my @translation_strings = (); -my $leading_space = ""; - -## Scalars used by the option stuff -my $HELP_ARG = 0; -my $VERSION_ARG = 0; -my $BA_STYLE_ARG = 0; -my $XML_STYLE_ARG = 0; -my $KEYS_STYLE_ARG = 0; -my $DESKTOP_STYLE_ARG = 0; -my $SCHEMAS_STYLE_ARG = 0; -my $RFC822DEB_STYLE_ARG = 0; -my $QUOTED_STYLE_ARG = 0; -my $QUOTEDXML_STYLE_ARG = 0; -my $QUIET_ARG = 0; -my $PASS_THROUGH_ARG = 0; -my $UTF8_ARG = 0; -my $MULTIPLE_OUTPUT = 0; -my $cache_file; - -## Handle options -GetOptions -( - "help" => \$HELP_ARG, - "version" => \$VERSION_ARG, - "quiet|q" => \$QUIET_ARG, - "oaf-style|o" => \$BA_STYLE_ARG, ## for compatibility - "ba-style|b" => \$BA_STYLE_ARG, - "xml-style|x" => \$XML_STYLE_ARG, - "keys-style|k" => \$KEYS_STYLE_ARG, - "desktop-style|d" => \$DESKTOP_STYLE_ARG, - "schemas-style|s" => \$SCHEMAS_STYLE_ARG, - "rfc822deb-style|r" => \$RFC822DEB_STYLE_ARG, - "quoted-style" => \$QUOTED_STYLE_ARG, - "quotedxml-style" => \$QUOTEDXML_STYLE_ARG, - "pass-through|p" => \$PASS_THROUGH_ARG, - "utf8|u" => \$UTF8_ARG, - "multiple-output|m" => \$MULTIPLE_OUTPUT, - "cache|c=s" => \$cache_file - ) or &error; - -my $PO_DIR; -my $FILE; -my $OUTFILE; - -my %po_files_by_lang = (); -my %translations = (); - -# Use this instead of \w for XML files to handle more possible characters. -my $w = "[-A-Za-z0-9._:]"; - -# XML quoted string contents -my $q = "[^\\\"]*"; - -## Check for options. - -if ($VERSION_ARG) -{ - &print_version; -} -elsif ($HELP_ARG) -{ - &print_help; -} -elsif ($BA_STYLE_ARG && @ARGV > 2) -{ - &utf8_sanity_check; - &preparation; - &print_message; - &ba_merge_translations; - &finalize; -} -elsif ($XML_STYLE_ARG && @ARGV > 2) -{ - &utf8_sanity_check; - &preparation; - &print_message; - &xml_merge_output; - &finalize; -} -elsif ($KEYS_STYLE_ARG && @ARGV > 2) -{ - &utf8_sanity_check; - &preparation; - &print_message; - &keys_merge_translations; - &finalize; -} -elsif ($DESKTOP_STYLE_ARG && @ARGV > 2) -{ - &utf8_sanity_check; - &preparation; - &print_message; - &desktop_merge_translations; - &finalize; -} -elsif ($SCHEMAS_STYLE_ARG && @ARGV > 2) -{ - &utf8_sanity_check; - &preparation; - &print_message; - &schemas_merge_translations; - &finalize; -} -elsif ($RFC822DEB_STYLE_ARG && @ARGV > 2) -{ - &preparation; - &print_message; - &rfc822deb_merge_translations; - &finalize; -} -elsif (($QUOTED_STYLE_ARG || $QUOTEDXML_STYLE_ARG) && @ARGV > 2) -{ - &utf8_sanity_check; - &preparation; - &print_message; - "ed_merge_translations($QUOTEDXML_STYLE_ARG); - &finalize; -} -else -{ - &print_help; -} - -exit; - -## Sub for printing release information -sub print_version -{ - print <<_EOF_; -${PROGRAM} (${PACKAGE}) ${VERSION} -Written by Maciej Stachowiak, Darin Adler and Kenneth Christiansen. - -Copyright (C) 2000-2003 Free Software Foundation, Inc. -Copyright (C) 2000-2001 Eazel, Inc. -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -_EOF_ - exit; -} - -## Sub for printing usage information -sub print_help -{ - print <<_EOF_; -Usage: ${PROGRAM} [OPTION]... PO_DIRECTORY FILENAME OUTPUT_FILE -Generates an output file that includes some localized attributes from an -untranslated source file. - -Mandatory options: (exactly one must be specified) - -b, --ba-style includes translations in the bonobo-activation style - -d, --desktop-style includes translations in the desktop style - -k, --keys-style includes translations in the keys style - -s, --schemas-style includes translations in the schemas style - -r, --rfc822deb-style includes translations in the RFC822 style - --quoted-style includes translations in the quoted string style - --quotedxml-style includes translations in the quoted xml string style - -x, --xml-style includes translations in the standard xml style - -Other options: - -u, --utf8 convert all strings to UTF-8 before merging - (default for everything except RFC822 style) - -p, --pass-through deprecated, does nothing and issues a warning - -m, --multiple-output output one localized file per locale, instead of - a single file containing all localized elements - -c, --cache=FILE specify cache file name - (usually \$top_builddir/po/.intltool-merge-cache) - -q, --quiet suppress most messages - --help display this help and exit - --version output version information and exit - -Report bugs to http://bugs.launchpad.net/intltool -_EOF_ - exit; -} - - -## Sub for printing error messages -sub print_error -{ - print STDERR "Try `${PROGRAM} --help' for more information.\n"; - exit; -} - - -sub print_message -{ - print "Merging translations into $OUTFILE.\n" unless $QUIET_ARG; -} - - -sub preparation -{ - $PO_DIR = $ARGV[0]; - $FILE = $ARGV[1]; - $OUTFILE = $ARGV[2]; - - &gather_po_files; - &get_translation_database; -} - -# General-purpose code for looking up translations in .po files - -sub po_file2lang -{ - my ($tmp) = @_; - $tmp =~ s/^.*\/(.*)\.po$/$1/; - return $tmp; -} - -sub gather_po_files -{ - if (my $linguas = $ENV{"LINGUAS"}) - { - for my $lang (split / /, $linguas) { - my $po_file = $PO_DIR . "/" . $lang . ".po"; - if (-e $po_file) { - $po_files_by_lang{$lang} = $po_file; - } - } - } - else - { - if (open LINGUAS_FILE, "$PO_DIR/LINGUAS") - { - while () - { - next if /^#/; - - for my $lang (split) - { - chomp ($lang); - my $po_file = $PO_DIR . "/" . $lang . ".po"; - if (-e $po_file) { - $po_files_by_lang{$lang} = $po_file; - } - } - } - - close LINGUAS_FILE; - } - else - { - for my $po_file (glob "$PO_DIR/*.po") { - $po_files_by_lang{po_file2lang($po_file)} = $po_file; - } - } - } -} - -sub get_po_encoding -{ - my ($in_po_file) = @_; - my $encoding = ""; - - open IN_PO_FILE, $in_po_file or die; - while () - { - ## example: "Content-Type: text/plain; charset=ISO-8859-1\n" - if (/Content-Type\:.*charset=([-a-zA-Z0-9]+)\\n/) - { - $encoding = $1; - last; - } - } - close IN_PO_FILE; - - if (!$encoding) - { - print STDERR "Warning: no encoding found in $in_po_file. Assuming ISO-8859-1\n" unless $QUIET_ARG; - $encoding = "ISO-8859-1"; - } - - return $encoding -} - -sub utf8_sanity_check -{ - print STDERR "Warning: option --pass-through has been removed.\n" if $PASS_THROUGH_ARG; - $UTF8_ARG = 1; -} - -sub get_translation_database -{ - if ($cache_file) { - &get_cached_translation_database; - } else { - &create_translation_database; - } -} - -sub get_newest_po_age -{ - my $newest_age; - - foreach my $file (values %po_files_by_lang) - { - my $file_age = -M $file; - $newest_age = $file_age if !$newest_age || $file_age < $newest_age; - } - - $newest_age = 0 if !$newest_age; - - return $newest_age; -} - -sub create_cache -{ - print "Generating and caching the translation database\n" unless $QUIET_ARG; - - &create_translation_database; - - open CACHE, ">$cache_file" || die; - print CACHE join "\x01", %translations; - close CACHE; -} - -sub load_cache -{ - print "Found cached translation database\n" unless $QUIET_ARG; - - my $contents; - open CACHE, "<$cache_file" || die; - { - local $/; - $contents = ; - } - close CACHE; - %translations = split "\x01", $contents; -} - -sub get_cached_translation_database -{ - my $cache_file_age = -M $cache_file; - if (defined $cache_file_age) - { - if ($cache_file_age <= &get_newest_po_age) - { - &load_cache; - return; - } - print "Found too-old cached translation database\n" unless $QUIET_ARG; - } - - &create_cache; -} - -sub add_translation -{ - my ($lang, $encoding, $msgctxt, $msgid, $msgstr) = @_; - - return if !($msgid && $msgstr); - - if ($msgctxt) { - $msgid = "$msgctxt\004$msgid"; - } - if (uc $encoding ne "UTF-8") { - Encode::from_to ($msgid, $encoding, "UTF-8"); - Encode::from_to ($msgstr, $encoding, "UTF-8"); - } - $translations{$lang, $msgid} = $msgstr; -} - -sub create_translation_database -{ - for my $lang (keys %po_files_by_lang) - { - my $po_file = $po_files_by_lang{$lang}; - my $encoding = "UTF-8"; - - if ($UTF8_ARG) - { - $encoding = get_po_encoding ($po_file); - if (uc $encoding ne "UTF-8") { - print "NOTICE: $po_file is not in UTF-8 but $encoding, converting...\n" unless $QUIET_ARG;; - } - } - open PO_FILE, "<$po_file"; - - my $nextfuzzy = 0; - my $inmsgctxt = 0; - my $inmsgid = 0; - my $inmsgstr = 0; - my $msgctxt = ""; - my $msgid = ""; - my $msgstr = ""; - - while () - { - $nextfuzzy = 1 if /^#, fuzzy/; - - if (/^msgctxt "((\\.|[^\\]+)*)"/ ) - { - if ($inmsgstr) { - add_translation ($lang, $encoding, - $msgctxt, $msgid, $msgstr); - $msgctxt = ""; - $msgid = ""; - $msgstr = ""; - } - - $msgctxt = unescape_po_string($1); - $inmsgctxt = 1; - $inmsgid = 0; - $inmsgstr = 0; - } - - if (/^msgid "((\\.|[^\\]+)*)"/ ) - { - if ($inmsgstr) { - add_translation ($lang, $encoding, - $msgctxt, $msgid, $msgstr); - $msgctxt = ""; - $msgid = ""; - $msgstr = ""; - } - - if ($nextfuzzy) { - $inmsgid = 0; - $nextfuzzy = 0; - } else { - $msgid = unescape_po_string($1); - $inmsgid = 1; - } - $inmsgctxt = 0; - $inmsgstr = 0; - } - - if (/^msgstr "((\\.|[^\\]+)*)"/) - { - $msgstr = unescape_po_string($1); - $inmsgstr = 1; - $inmsgctxt = 0; - $inmsgid = 0; - } - - if (/^"((\\.|[^\\]+)*)"/) - { - $msgctxt .= unescape_po_string($1) if $inmsgctxt; - $msgid .= unescape_po_string($1) if $inmsgid; - $msgstr .= unescape_po_string($1) if $inmsgstr; - } - } - add_translation ($lang, $encoding, $msgctxt, $msgid, $msgstr) - if ($inmsgstr); - } -} - -sub finalize -{ -} - -sub unescape_one_sequence -{ - my ($sequence) = @_; - - return "\\" if $sequence eq "\\\\"; - return "\"" if $sequence eq "\\\""; - return "\n" if $sequence eq "\\n"; - return "\r" if $sequence eq "\\r"; - return "\t" if $sequence eq "\\t"; - return "\b" if $sequence eq "\\b"; - return "\f" if $sequence eq "\\f"; - return "\a" if $sequence eq "\\a"; - return chr(11) if $sequence eq "\\v"; # vertical tab, see ascii(7) - - return chr(hex($1)) if ($sequence =~ /\\x([0-9a-fA-F]{2})/); - return chr(oct($1)) if ($sequence =~ /\\([0-7]{3})/); - - # FIXME: Is \0 supported as well? Kenneth and Rodney don't want it, see bug #48489 - - return $sequence; -} - -sub unescape_po_string -{ - my ($string) = @_; - - $string =~ s/(\\x[0-9a-fA-F]{2}|\\[0-7]{3}|\\.)/unescape_one_sequence($1)/eg; - - return $string; -} - -sub entity_decode -{ - local ($_) = @_; - - s/'/'/g; # ' - s/"/"/g; # " - s/<//g; - s/&/&/g; - - return $_; -} - -# entity_encode: (string) -# -# Encode the given string to XML format (encode '<' etc). - -sub entity_encode -{ - my ($pre_encoded) = @_; - - my @list_of_chars = unpack ('C*', $pre_encoded); - - # with UTF-8 we only encode minimalistic - return join ('', map (&entity_encode_int_minimalist, @list_of_chars)); -} - -sub entity_encode_int_minimalist -{ - return """ if $_ == 34; - return "&" if $_ == 38; - return "'" if $_ == 39; - return "<" if $_ == 60; - return ">" if $_ == 62; - return chr $_; -} - -sub entity_encoded_translation -{ - my ($lang, $string) = @_; - - my $translation = $translations{$lang, $string}; - return $string if !$translation; - return entity_encode ($translation); -} - -## XML (bonobo-activation specific) merge code - -sub ba_merge_translations -{ - my $source; - - { - local $/; # slurp mode - open INPUT, "<$FILE" or die "can't open $FILE: $!"; - $source = ; - close INPUT; - } - - open OUTPUT, ">$OUTFILE" or die "can't open $OUTFILE: $!"; - # Binmode so that selftest works ok if using a native Win32 Perl... - binmode (OUTPUT) if $^O eq 'MSWin32'; - - while ($source =~ s|^(.*?)([ \t]*<\s*$w+\s+($w+\s*=\s*"$q"\s*)+/?>)([ \t]*\n)?||s) - { - print OUTPUT $1; - - my $node = $2 . "\n"; - - my @strings = (); - $_ = $node; - while (s/(\s)_($w+\s*=\s*"($q)")/$1$2/s) { - push @strings, entity_decode($3); - } - print OUTPUT; - - my %langs; - for my $string (@strings) - { - for my $lang (keys %po_files_by_lang) - { - $langs{$lang} = 1 if $translations{$lang, $string}; - } - } - - for my $lang (sort keys %langs) - { - $_ = $node; - s/(\sname\s*=\s*)"($q)"/$1"$2-$lang"/s; - s/(\s)_($w+\s*=\s*")($q)"/$1 . $2 . entity_encoded_translation($lang, $3) . '"'/seg; - print OUTPUT; - } - } - - print OUTPUT $source; - - close OUTPUT; -} - - -## XML (non-bonobo-activation) merge code - - -# Process tag attributes -# Only parameter is a HASH containing attributes -> values mapping -sub getAttributeString -{ - my $sub = shift; - my $do_translate = shift || 0; - my $language = shift || ""; - my $result = ""; - my $translate = shift; - foreach my $e (reverse(sort(keys %{ $sub }))) { - my $key = $e; - my $string = $sub->{$e}; - my $quote = '"'; - - $string =~ s/^[\s]+//; - $string =~ s/[\s]+$//; - - if ($string =~ /^'.*'$/) - { - $quote = "'"; - } - $string =~ s/^['"]//g; - $string =~ s/['"]$//g; - - if ($do_translate && $key =~ /^_/) { - $key =~ s|^_||g; - if ($language) { - # Handle translation - my $decode_string = entity_decode($string); - my $translation = $translations{$language, $decode_string}; - if ($translation) { - $translation = entity_encode($translation); - $string = $translation; - } - $$translate = 2; - } else { - $$translate = 2 if ($translate && (!$$translate)); # watch not to "overwrite" $translate - } - } - - $result .= " $key=$quote$string$quote"; - } - return $result; -} - -# Returns a translatable string from XML node, it works on contents of every node in XML::Parser tree -sub getXMLstring -{ - my $ref = shift; - my $spacepreserve = shift || 0; - my @list = @{ $ref }; - my $result = ""; - - my $count = scalar(@list); - my $attrs = $list[0]; - my $index = 1; - - $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); - $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); - - while ($index < $count) { - my $type = $list[$index]; - my $content = $list[$index+1]; - if (! $type ) { - # We've got CDATA - if ($content) { - # lets strip the whitespace here, and *ONLY* here - $content =~ s/\s+/ /gs if (!$spacepreserve); - $result .= $content; - } - } elsif ( "$type" ne "1" ) { - # We've got another element - $result .= "<$type"; - $result .= getAttributeString(@{$content}[0], 0); # no nested translatable elements - if ($content) { - my $subresult = getXMLstring($content, $spacepreserve); - if ($subresult) { - $result .= ">".$subresult . ""; - } else { - $result .= "/>"; - } - } else { - $result .= "/>"; - } - } - $index += 2; - } - return $result; -} - -# Translate list of nodes if necessary -sub translate_subnodes -{ - my $fh = shift; - my $content = shift; - my $language = shift || ""; - my $singlelang = shift || 0; - my $spacepreserve = shift || 0; - - my @nodes = @{ $content }; - - my $count = scalar(@nodes); - my $index = 0; - while ($index < $count) { - my $type = $nodes[$index]; - my $rest = $nodes[$index+1]; - if ($singlelang) { - my $oldMO = $MULTIPLE_OUTPUT; - $MULTIPLE_OUTPUT = 1; - traverse($fh, $type, $rest, $language, $spacepreserve); - $MULTIPLE_OUTPUT = $oldMO; - } else { - traverse($fh, $type, $rest, $language, $spacepreserve); - } - $index += 2; - } -} - -sub isWellFormedXmlFragment -{ - my $ret = eval 'require XML::Parser'; - if(!$ret) { - die "You must have XML::Parser installed to run $0\n\n"; - } - - my $fragment = shift; - return 0 if (!$fragment); - - $fragment = "$fragment"; - my $xp = new XML::Parser(Style => 'Tree'); - my $tree = 0; - eval { $tree = $xp->parse($fragment); }; - return $tree; -} - -sub traverse -{ - my $fh = shift; - my $nodename = shift; - my $content = shift; - my $language = shift || ""; - my $spacepreserve = shift || 0; - - if (!$nodename) { - if ($content =~ /^[\s]*$/) { - $leading_space .= $content; - } - print $fh $content; - } else { - # element - my @all = @{ $content }; - my $attrs = shift @all; - my $translate = 0; - my $outattr = getAttributeString($attrs, 1, $language, \$translate); - - if ($nodename =~ /^_/) { - $translate = 1; - $nodename =~ s/^_//; - } - my $lookup = ''; - - $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); - $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); - - print $fh "<$nodename", $outattr; - if ($translate) { - $content = getXMLstring($content, $spacepreserve); - if (!$spacepreserve) { - $content =~ s/^\s+//s; - $content =~ s/\s+$//s; - } - if (exists $attrs->{"msgctxt"}) { - my $context = entity_decode ($attrs->{"msgctxt"}); - $context =~ s/^["'](.*)["']/$1/; - $lookup = "$context\004$content"; - } else { - $lookup = $content; - } - - if ($lookup || $translate == 2) { - my $translation = $translations{$language, $lookup} if isWellFormedXmlFragment($translations{$language, $lookup}); - if ($MULTIPLE_OUTPUT && ($translation || $translate == 2)) { - $translation = $content if (!$translation); - print $fh " xml:lang=\"", $language, "\"" if $language; - print $fh ">"; - if ($translate == 2) { - translate_subnodes($fh, \@all, $language, 1, $spacepreserve); - } else { - print $fh $translation; - } - print $fh ""; - - return; # this means there will be no same translation with xml:lang="$language"... - # if we want them both, just remove this "return" - } else { - print $fh ">"; - if ($translate == 2) { - translate_subnodes($fh, \@all, $language, 1, $spacepreserve); - } else { - print $fh $content; - } - print $fh ""; - } - } else { - print $fh "/>"; - } - - for my $lang (sort keys %po_files_by_lang) { - if ($MULTIPLE_OUTPUT && $lang ne "$language") { - next; - } - if ($lang) { - # Handle translation - # - my $translate = 0; - my $localattrs = getAttributeString($attrs, 1, $lang, \$translate); - my $translation = $translations{$lang, $lookup} if isWellFormedXmlFragment($translations{$lang, $lookup}); - if ($translate && !$translation) { - $translation = $content; - } - - if ($translation || $translate) { - print $fh "\n"; - $leading_space =~ s/.*\n//g; - print $fh $leading_space; - print $fh "<", $nodename, " xml:lang=\"", $lang, "\"", $localattrs, ">"; - if ($translate == 2) { - translate_subnodes($fh, \@all, $lang, 1, $spacepreserve); - } else { - print $fh $translation; - } - print $fh ""; - } - } - } - - } else { - my $count = scalar(@all); - if ($count > 0) { - print $fh ">"; - my $index = 0; - while ($index < $count) { - my $type = $all[$index]; - my $rest = $all[$index+1]; - traverse($fh, $type, $rest, $language, $spacepreserve); - $index += 2; - } - print $fh ""; - } else { - print $fh "/>"; - } - } - } -} - -sub intltool_tree_comment -{ - my $expat = shift; - my $data = shift; - my $clist = $expat->{Curlist}; - my $pos = $#$clist; - - push @$clist, 1 => $data; -} - -sub intltool_tree_cdatastart -{ - my $expat = shift; - my $clist = $expat->{Curlist}; - my $pos = $#$clist; - - push @$clist, 0 => $expat->original_string(); -} - -sub intltool_tree_cdataend -{ - my $expat = shift; - my $clist = $expat->{Curlist}; - my $pos = $#$clist; - - $clist->[$pos] .= $expat->original_string(); -} - -sub intltool_tree_char -{ - my $expat = shift; - my $text = shift; - my $clist = $expat->{Curlist}; - my $pos = $#$clist; - - # Use original_string so that we retain escaped entities - # in CDATA sections. - # - if ($pos > 0 and $clist->[$pos - 1] eq '0') { - $clist->[$pos] .= $expat->original_string(); - } else { - push @$clist, 0 => $expat->original_string(); - } -} - -sub intltool_tree_start -{ - my $expat = shift; - my $tag = shift; - my @origlist = (); - - # Use original_string so that we retain escaped entities - # in attribute values. We must convert the string to an - # @origlist array to conform to the structure of the Tree - # Style. - # - my @original_array = split /\x/, $expat->original_string(); - my $source = $expat->original_string(); - - # Remove leading tag. - # - $source =~ s|^\s*<\s*(\S+)||s; - - # Grab attribute key/value pairs and push onto @origlist array. - # - while ($source) - { - if ($source =~ /^\s*([\w:-]+)\s*[=]\s*["]/) - { - $source =~ s|^\s*([\w:-]+)\s*[=]\s*["]([^"]*)["]||s; - push @origlist, $1; - push @origlist, '"' . $2 . '"'; - } - elsif ($source =~ /^\s*([\w:-]+)\s*[=]\s*[']/) - { - $source =~ s|^\s*([\w:-]+)\s*[=]\s*[']([^']*)[']||s; - push @origlist, $1; - push @origlist, "'" . $2 . "'"; - } - else - { - last; - } - } - - my $ol = [ { @origlist } ]; - - push @{ $expat->{Lists} }, $expat->{Curlist}; - push @{ $expat->{Curlist} }, $tag => $ol; - $expat->{Curlist} = $ol; -} - -sub readXml -{ - my $filename = shift || return; - if(!-f $filename) { - die "ERROR Cannot find filename: $filename\n"; - } - - my $ret = eval 'require XML::Parser'; - if(!$ret) { - die "You must have XML::Parser installed to run $0\n\n"; - } - my $xp = new XML::Parser(Style => 'Tree'); - $xp->setHandlers(Char => \&intltool_tree_char); - $xp->setHandlers(Start => \&intltool_tree_start); - $xp->setHandlers(CdataStart => \&intltool_tree_cdatastart); - $xp->setHandlers(CdataEnd => \&intltool_tree_cdataend); - my $tree = $xp->parsefile($filename); - -# Hello thereHowdydo -# would be: -# [foo, [{}, head, [{id => "a"}, 0, "Hello ", em, [{}, 0, "there"]], bar, [{}, -# 0, "Howdy", ref, [{}]], 0, "do" ] ] - - return $tree; -} - -sub print_header -{ - my $infile = shift; - my $fh = shift; - my $source; - - if(!-f $infile) { - die "ERROR Cannot find filename: $infile\n"; - } - - print $fh qq{\n}; - { - local $/; - open DOCINPUT, "<${FILE}" or die; - $source = ; - close DOCINPUT; - } - if ($source =~ /()/s) - { - print $fh "$1\n"; - } - elsif ($source =~ /(]*>)/s) - { - print $fh "$1\n"; - } -} - -sub parseTree -{ - my $fh = shift; - my $ref = shift; - my $language = shift || ""; - - my $name = shift @{ $ref }; - my $cont = shift @{ $ref }; - - while (!$name || "$name" eq "1") { - $name = shift @{ $ref }; - $cont = shift @{ $ref }; - } - - my $spacepreserve = 0; - my $attrs = @{$cont}[0]; - $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); - - traverse($fh, $name, $cont, $language, $spacepreserve); -} - -sub xml_merge_output -{ - my $source; - - if ($MULTIPLE_OUTPUT) { - for my $lang (sort keys %po_files_by_lang) { - if ( ! -d $lang ) { - mkdir $lang or -d $lang or die "Cannot create subdirectory $lang: $!\n"; - } - open OUTPUT, ">$lang/$OUTFILE" or die "Cannot open $lang/$OUTFILE: $!\n"; - binmode (OUTPUT) if $^O eq 'MSWin32'; - my $tree = readXml($FILE); - print_header($FILE, \*OUTPUT); - parseTree(\*OUTPUT, $tree, $lang); - close OUTPUT; - print "CREATED $lang/$OUTFILE\n" unless $QUIET_ARG; - } - if ( ! -d "C" ) { - mkdir "C" or -d "C" or die "Cannot create subdirectory C: $!\n"; - } - open OUTPUT, ">C/$OUTFILE" or die "Cannot open C/$OUTFILE: $!\n"; - binmode (OUTPUT) if $^O eq 'MSWin32'; - my $tree = readXml($FILE); - print_header($FILE, \*OUTPUT); - parseTree(\*OUTPUT, $tree); - close OUTPUT; - print "CREATED C/$OUTFILE\n" unless $QUIET_ARG; - } else { - open OUTPUT, ">$OUTFILE" or die "Cannot open $OUTFILE: $!\n"; - binmode (OUTPUT) if $^O eq 'MSWin32'; - my $tree = readXml($FILE); - print_header($FILE, \*OUTPUT); - parseTree(\*OUTPUT, $tree); - close OUTPUT; - print "CREATED $OUTFILE\n" unless $QUIET_ARG; - } -} - -sub keys_merge_translation -{ - my ($lang) = @_; - - if ( ! -d $lang && $MULTIPLE_OUTPUT) - { - mkdir $lang or -d $lang or die "Cannot create subdirectory $lang: $!\n"; - } - - open INPUT, "<${FILE}" or die "Cannot open ${FILE}: $!\n"; - open OUTPUT, ">$lang/$OUTFILE" or die "Cannot open $lang/$OUTFILE: $!\n"; - binmode (OUTPUT) if $^O eq 'MSWin32'; - - while () - { - if (s/^(\s*)_(\w+=(.*))/$1$2/) - { - my $string = $3; - - if (!$MULTIPLE_OUTPUT) - { - print OUTPUT; - - my $non_translated_line = $_; - - for my $lang (sort keys %po_files_by_lang) - { - my $translation = $translations{$lang, $string}; - next if !$translation; - - $_ = $non_translated_line; - s/(\w+)=.*/[$lang]$1=$translation/; - print OUTPUT; - } - } - else - { - my $non_translated_line = $_; - my $translation = $translations{$lang, $string}; - $translation = $string if !$translation; - - $_ = $non_translated_line; - s/(\w+)=.*/$1=$translation/; - print OUTPUT; - } - } - else - { - print OUTPUT; - } - } - - close OUTPUT; - close INPUT; - - print "CREATED $lang/$OUTFILE\n" unless $QUIET_ARG; -} - -sub keys_merge_translations -{ - if ($MULTIPLE_OUTPUT) - { - for my $lang (sort keys %po_files_by_lang) - { - keys_merge_translation ($lang); - } - keys_merge_translation ("C"); - } - else - { - keys_merge_translation ("."); - } -} - -sub desktop_merge_translations -{ - open INPUT, "<${FILE}" or die; - open OUTPUT, ">${OUTFILE}" or die; - binmode (OUTPUT) if $^O eq 'MSWin32'; - - while () - { - if (s/^(\s*)_([A-Za-z0-9\-]+=(.*))/$1$2/) - { - my $string = $3; - - print OUTPUT; - - my $non_translated_line = $_; - - for my $lang (sort keys %po_files_by_lang) - { - my $translation = $translations{$lang, $string}; - next if !$translation; - - $_ = $non_translated_line; - s/(\w+)=.*/${1}[$lang]=$translation/; - print OUTPUT; - } - } - else - { - print OUTPUT; - } - } - - close OUTPUT; - close INPUT; -} - -sub schemas_merge_translations -{ - my $source; - - { - local $/; # slurp mode - open INPUT, "<$FILE" or die "can't open $FILE: $!"; - $source = ; - close INPUT; - } - - open OUTPUT, ">$OUTFILE" or die; - binmode (OUTPUT) if $^O eq 'MSWin32'; - - # FIXME: support attribute translations - - # Empty nodes never need translation, so unmark all of them. - # For example, <_foo/> is just replaced by . - $source =~ s|<\s*_($w+)\s*/>|<$1/>|g; - - while ($source =~ s/ - (.*?) - (\s+)((\s*) - (\s*(?:\s*)?(.*?)\s*<\/default>)?(\s*) - (\s*(?:\s*)?(.*?)\s*<\/short>)?(\s*) - (\s*(?:\s*)?(.*?)\s*<\/long>)?(\s*) - <\/locale>) - //sx) - { - print OUTPUT $1; - - my $locale_start_spaces = $2 ? $2 : ''; - my $default_spaces = $4 ? $4 : ''; - my $short_spaces = $7 ? $7 : ''; - my $long_spaces = $10 ? $10 : ''; - my $locale_end_spaces = $13 ? $13 : ''; - my $c_default_block = $3 ? $3 : ''; - my $default_string = $6 ? $6 : ''; - my $short_string = $9 ? $9 : ''; - my $long_string = $12 ? $12 : ''; - - print OUTPUT "$locale_start_spaces$c_default_block"; - - $default_string =~ s/\s+/ /g; - $default_string = entity_decode($default_string); - $short_string =~ s/\s+/ /g; - $short_string = entity_decode($short_string); - $long_string =~ s/\s+/ /g; - $long_string = entity_decode($long_string); - - for my $lang (sort keys %po_files_by_lang) - { - my $default_translation = $translations{$lang, $default_string}; - my $short_translation = $translations{$lang, $short_string}; - my $long_translation = $translations{$lang, $long_string}; - - next if (!$default_translation && !$short_translation && - !$long_translation); - - print OUTPUT "\n$locale_start_spaces"; - - print OUTPUT "$default_spaces"; - - if ($default_translation) - { - $default_translation = entity_encode($default_translation); - print OUTPUT "$default_translation"; - } - - print OUTPUT "$short_spaces"; - - if ($short_translation) - { - $short_translation = entity_encode($short_translation); - print OUTPUT "$short_translation"; - } - - print OUTPUT "$long_spaces"; - - if ($long_translation) - { - $long_translation = entity_encode($long_translation); - print OUTPUT "$long_translation"; - } - - print OUTPUT "$locale_end_spaces"; - } - } - - print OUTPUT $source; - - close OUTPUT; -} - -sub rfc822deb_merge_translations -{ - my %encodings = (); - for my $lang (keys %po_files_by_lang) { - $encodings{$lang} = ($UTF8_ARG ? 'UTF-8' : get_po_encoding($po_files_by_lang{$lang})); - } - - my $source; - - $Text::Wrap::huge = 'overflow'; - $Text::Wrap::break = qr/\n|\s(?=\S)/; - - { - local $/; # slurp mode - open INPUT, "<$FILE" or die "can't open $FILE: $!"; - $source = ; - close INPUT; - } - - open OUTPUT, ">${OUTFILE}" or die; - binmode (OUTPUT) if $^O eq 'MSWin32'; - - while ($source =~ /(^|\n+)(_*)([^:\s]+)(:[ \t]*)(.*?)(?=\n[\S\n]|$)/sg) - { - my $sep = $1; - my $non_translated_line = $3.$4; - my $string = $5; - my $underscore = length($2); - next if $underscore eq 0 && $non_translated_line =~ /^#/; - # Remove [] dummy strings - my $stripped = $string; - $stripped =~ s/\[\s[^\[\]]*\],/,/g if $underscore eq 2; - $stripped =~ s/\[\s[^\[\]]*\]$//; - $non_translated_line .= $stripped; - - print OUTPUT $sep.$non_translated_line; - - if ($underscore) - { - my @str_list = rfc822deb_split($underscore, $string); - - for my $lang (sort keys %po_files_by_lang) - { - my $is_translated = 1; - my $str_translated = ''; - my $first = 1; - - for my $str (@str_list) - { - my $translation = $translations{$lang, $str}; - - if (!$translation) - { - $is_translated = 0; - last; - } - - # $translation may also contain [] dummy - # strings, mostly to indicate an empty string - $translation =~ s/\[\s[^\[\]]*\]$//; - - if ($first) - { - if ($underscore eq 2) - { - $str_translated .= $translation; - } - else - { - $str_translated .= - Text::Tabs::expand($translation) . - "\n"; - } - } - else - { - if ($underscore eq 2) - { - $str_translated .= ', ' . $translation; - } - else - { - $str_translated .= Text::Tabs::expand( - Text::Wrap::wrap(' ', ' ', $translation)) . - "\n .\n"; - } - } - $first = 0; - - # To fix some problems with Text::Wrap::wrap - $str_translated =~ s/(\n )+\n/\n .\n/g; - } - next unless $is_translated; - - $str_translated =~ s/\n \.\n$//; - $str_translated =~ s/\s+$//; - - $_ = $non_translated_line; - s/^(\w+):\s*.*/$sep${1}-$lang.$encodings{$lang}: $str_translated/s; - print OUTPUT; - } - } - } - print OUTPUT "\n"; - - close OUTPUT; - close INPUT; -} - -sub rfc822deb_split -{ - # Debian defines a special way to deal with rfc822-style files: - # when a value contain newlines, it consists of - # 1. a short form (first line) - # 2. a long description, all lines begin with a space, - # and paragraphs are separated by a single dot on a line - # This routine returns an array of all paragraphs, and reformat - # them. - # When first argument is 2, the string is a comma separated list of - # values. - my $type = shift; - my $text = shift; - $text =~ s/^[ \t]//mg; - return (split(/, */, $text, 0)) if $type ne 1; - return ($text) if $text !~ /\n/; - - $text =~ s/([^\n]*)\n//; - my @list = ($1); - my $str = ''; - - for my $line (split (/\n/, $text)) - { - chomp $line; - if ($line =~ /^\.\s*$/) - { - # New paragraph - $str =~ s/\s*$//; - push(@list, $str); - $str = ''; - } - elsif ($line =~ /^\s/) - { - # Line which must not be reformatted - $str .= "\n" if length ($str) && $str !~ /\n$/; - $line =~ s/\s+$//; - $str .= $line."\n"; - } - else - { - # Continuation line, remove newline - $str .= " " if length ($str) && $str !~ /\n$/; - $str .= $line; - } - } - - $str =~ s/\s*$//; - push(@list, $str) if length ($str); - - return @list; -} - -sub quoted_translation -{ - my ($xml_mode, $lang, $string) = @_; - - $string = entity_decode($string) if $xml_mode; - $string =~ s/\\\"/\"/g; - - my $translation = $translations{$lang, $string}; - $translation = $string if !$translation; - $translation = entity_encode($translation) if $xml_mode; - $translation =~ s/\"/\\\"/g; - return $translation -} - -sub quoted_merge_translations -{ - my ($xml_mode) = @_; - - if (!$MULTIPLE_OUTPUT) { - print "Quoted only supports Multiple Output.\n"; - exit(1); - } - - for my $lang (sort keys %po_files_by_lang) { - if ( ! -d $lang ) { - mkdir $lang or -d $lang or die "Cannot create subdirectory $lang: $!\n"; - } - open INPUT, "<${FILE}" or die; - open OUTPUT, ">$lang/$OUTFILE" or die "Cannot open $lang/$OUTFILE: $!\n"; - binmode (OUTPUT) if $^O eq 'MSWin32'; - while () - { - s/\"(([^\"]|\\\")*[^\\\"])\"/"\"" . "ed_translation($xml_mode, $lang, $1) . "\""/ge; - print OUTPUT; - } - close OUTPUT; - close INPUT; - } -} diff --git a/data/meson.build b/data/meson.build new file mode 100644 index 0000000..5874857 --- /dev/null +++ b/data/meson.build @@ -0,0 +1,7 @@ +gnome = import('gnome') + +# Include shaders in executable +valagl_resources = gnome.compile_resources( + 'valagl-resources', + 'valagl.gresource.xml' +) \ No newline at end of file diff --git a/data/shaders/fragment.glsl b/data/shaders/fragment.glsl index 2c0125d..faa56af 100644 --- a/data/shaders/fragment.glsl +++ b/data/shaders/fragment.glsl @@ -1,5 +1,5 @@ varying vec3 f_color; void main(void) { - gl_FragColor = vec4(f_color.x, f_color.y, f_color.z, 1.0); + gl_FragColor = vec4(f_color.x, f_color.y, f_color.z, 1.0); } diff --git a/data/shaders/vertex.glsl b/data/shaders/vertex.glsl index de46923..5ee2cce 100644 --- a/data/shaders/vertex.glsl +++ b/data/shaders/vertex.glsl @@ -4,6 +4,6 @@ attribute vec3 v_color; varying vec3 f_color; void main(void) { - gl_Position = transform * vec4(coord3d, 1.0); - f_color = v_color; + gl_Position = transform * vec4(coord3d, 1.0); + f_color = v_color; } diff --git a/data/valagl.gresource.xml b/data/valagl.gresource.xml new file mode 100644 index 0000000..1161a69 --- /dev/null +++ b/data/valagl.gresource.xml @@ -0,0 +1,7 @@ + + + + shaders/fragment.glsl + shaders/vertex.glsl + + diff --git a/install.cmake b/install.cmake deleted file mode 100644 index 4a98433..0000000 --- a/install.cmake +++ /dev/null @@ -1,2 +0,0 @@ -install(TARGETS ${CMAKE_PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) -install(DIRECTORY ${CMAKE_SOURCE_DIR}/data DESTINATION ${PROJECT_DATA_DIR}) diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..27b4d1a --- /dev/null +++ b/meson.build @@ -0,0 +1,16 @@ +project('valagl', ['c', 'vala'], + default_options: [ 'warning_level=2' ], + version: '1.0', + meson_version: '>= 0.50.0', +) + +pkg = import('pkgconfig') + +# Load custom vapi files +add_project_arguments( + ['--vapidir', meson.current_source_dir() / 'vapi'], + language: 'vala' +) + +subdir('data') +subdir('src') diff --git a/result.png b/result.png new file mode 100644 index 0000000000000000000000000000000000000000..8583e34d170dfb7ca3d850683b5af9f73f50bd3e GIT binary patch literal 20079 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 lA3jwsRDAj7{{eot52yeD literal 0 HcmV?d00001 diff --git a/scripts/seed b/scripts/seed deleted file mode 100755 index 7aa80ca..0000000 --- a/scripts/seed +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python -template = """/* - ${CLASS}.vala - Copyright (C) 2012, 2021 Maia Everett - - 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. -*/ - -namespace ${NS} { - -public class ${CLASS} : Object { - -} - -} -""" - -import string, sys - -template = string.Template(template).substitute(NS = sys.argv[1], CLASS = sys.argv[2]) - -vfile = open('%s/%s.vala' % (sys.argv[1], sys.argv[2]), 'w') -vfile.write(template) -vfile.close() diff --git a/sources.cmake b/sources.cmake deleted file mode 100644 index 0b4b9e8..0000000 --- a/sources.cmake +++ /dev/null @@ -1,27 +0,0 @@ -set(VALAGL_CORE_CLASSES - _namespace - Camera - CoreError - GeometryUtil - GLProgram - IBO - MatrixMath - Util - VAO - VBO -) - -foreach(CLASS ${VALAGL_CORE_CLASSES}) - set(APP_SOURCES ${APP_SOURCES} "ValaGL.Core/${CLASS}.vala") -endforeach() - -set(VALAGL_CLASSES - _namespace - AppError - App - Canvas -) - -foreach(CLASS ${VALAGL_CLASSES}) - set(APP_SOURCES ${APP_SOURCES} "ValaGL/${CLASS}.vala") -endforeach() diff --git a/src/app-error.vala b/src/app-error.vala new file mode 100644 index 0000000..a7cbfff --- /dev/null +++ b/src/app-error.vala @@ -0,0 +1,12 @@ +namespace ValaGL { + + /** + * Error domain for the ValaGL application. + */ + public errordomain AppError { + /** + * Indicates an application initialization error (e.g. inability to initialize SDL or OpenGL). + */ + INIT + } +} diff --git a/src/app.vala b/src/app.vala new file mode 100644 index 0000000..7a65441 --- /dev/null +++ b/src/app.vala @@ -0,0 +1,184 @@ +using SDL; +using SDL.Input; +using SDL.Video; + +namespace ValaGL { + + /** + * The singleton application, responsible for managing the fullscreen SDL main window. + */ + public class App : GLib.Object { + private enum EventCode { + TIMER_EVENT + } + + private Window window; + private SDL.Video.GL.Context context; + private bool done; + private Canvas canvas; + private SDL.Timer? timer; + + private uint initial_rotation_angle = 30; + private uint timer_ticks; + + /** + * Creates the application. + */ + public App() {} + + /** + * Runs the application. + */ + public void run() throws AppError { + try { + init_video(); + init_timer(); + + while (!done) { + process_events(); + draw(); + } + } finally { + if (timer != null) { + timer.remove(); + timer = null; + } + + // Free the canvas and associated GL resources + canvas = null; + } + } + + private void init_video() throws AppError { + SDL.Video.GL.set_attribute(SDL.Video.GL.Attributes.RED_SIZE, 8); + SDL.Video.GL.set_attribute(SDL.Video.GL.Attributes.GREEN_SIZE, 8); + SDL.Video.GL.set_attribute(SDL.Video.GL.Attributes.BLUE_SIZE, 8); + SDL.Video.GL.set_attribute(SDL.Video.GL.Attributes.ALPHA_SIZE, 8); + SDL.Video.GL.set_attribute(SDL.Video.GL.Attributes.DEPTH_SIZE, 16); + SDL.Video.GL.set_attribute(SDL.Video.GL.Attributes.DOUBLEBUFFER, 1); + + // Request OpenGL 3.3 core profile + SDL.Video.GL.set_attribute(SDL.Video.GL.Attributes.CONTEXT_PROFILE_MASK, SDL.Video.GL.ProfileType.CORE); + SDL.Video.GL.set_attribute(SDL.Video.GL.Attributes.CONTEXT_MAJOR_VERSION, 3); + SDL.Video.GL.set_attribute(SDL.Video.GL.Attributes.CONTEXT_MINOR_VERSION, 3); + + // Ask for multisampling if possible + SDL.Video.GL.set_attribute(SDL.Video.GL.Attributes.MULTISAMPLEBUFFERS, 1); + SDL.Video.GL.set_attribute(SDL.Video.GL.Attributes.MULTISAMPLESAMPLES, 4); + + // Create SDL window + window = new Window("Vala OpenGL Skeletal Application", + 50, 50, + 600, 600, + WindowFlags.SHOWN | WindowFlags.RESIZABLE | WindowFlags.OPENGL + ); + + if (window == null) { + throw new AppError.INIT("Could not set video mode"); + } + + context = SDL.Video.GL.Context.create(window); + + if (context == null) { + throw new AppError.INIT("Could not create GL context"); + } + + canvas = new Canvas(); + + // Get the screen width and height and set up the viewport accordingly + int width; + int height; + window.get_size(out width, out height); + canvas.resize_gl(width, height); + canvas.update_scene_data(initial_rotation_angle); + } + + private void init_timer() { + timer = SDL.Timer(10, (interval) => { + // Executed in a separate thread, so we exchange information with the UI thread through events + SDL.Event event = SDL.Event() { + type = EventType.USEREVENT + }; + event.user.code = EventCode.TIMER_EVENT; + Event.push(event); + return interval; + }); + } + + private void draw() { + canvas.paint_gl(); + SDL.Video.GL.swap_window(window); + } + + private void process_events() { + Event event; + + while (Event.poll(out event) == 1) { + if (event.type == EventType.QUIT) + done = true; + + if (event.type == EventType.WINDOWEVENT) + on_window_event(event.window); + + if (event.type == EventType.KEYDOWN) + on_keyboard_event(event.key); + + if (event.type == EventType.USEREVENT) + on_timer_event(); + } + } + + private void on_window_event(WindowEvent event) { + if (event.event == WindowEventType.RESIZED) { + canvas.resize_gl(event.data1, event.data2); + } + } + + private void on_keyboard_event(KeyboardEvent event) { + switch (event.keysym.sym) { + case Keycode.ESCAPE: + // Close on Esc + on_quit(); + break; + default: + // Insert any other keyboard combinations here. + break; + } + } + + private void on_timer_event() { + timer_ticks = (timer_ticks + 1) % 1800; + canvas.update_scene_data(initial_rotation_angle + timer_ticks / 5.0f); + } + + private void on_quit() { + Event e = Event() { + type = EventType.QUIT + }; + Event.push(e); + } + + /** + * Application entry point. + * + * Creates an instance of the ValaGL application and runs the SDL event loop + * until the user exits the application. + * + * @param args Command line arguments. Ignored. + */ + public static int main(string[] args) { + SDL.init(InitFlag.VIDEO | InitFlag.TIMER); + + try { + new App().run(); + } catch (AppError e) { + stderr.printf("Fatal error: %s\n", e.message); + return 1; + } finally { + SDL.quit(); + } + + return 0; + } + } +} diff --git a/src/canvas.vala b/src/canvas.vala new file mode 100644 index 0000000..76c5345 --- /dev/null +++ b/src/canvas.vala @@ -0,0 +1,193 @@ +using GL; +using ValaGL.Core; + +namespace ValaGL { + + private const GLfloat[] cube_vertices = { + // front + -1, -1, 1, + 1, -1, 1, + 1, 1, 1, + -1, 1, 1, + // back + -1, -1, -1, + 1, -1, -1, + 1, 1, -1, + -1, 1, -1, + }; + + private const GLfloat[] cube_colors = { + // front colors + 1, 0, 0, + 0, 1, 0, + 0, 0, 1, + 1, 1, 1, + // back colors + 1, 0, 0, + 0, 1, 0, + 0, 0, 1, + 1, 1, 1, + }; + + private const GLushort cube_elements[] = { + // front + 0, 1, 2, + 2, 3, 0, + // top + 1, 5, 6, + 6, 2, 1, + // back + 7, 6, 5, + 5, 4, 7, + // bottom + 4, 0, 3, + 3, 7, 4, + // left + 4, 5, 1, + 1, 0, 4, + // right + 3, 2, 6, + 6, 7, 3, + }; + + /** + * The OpenGL canvas associated with the application main window. + * + * This class is responsible for initializing the state of the OpenGL context + * and managing resize and redraw events sent by the underlying SDL window. + */ + public class Canvas : Object { + private GLProgram gl_program; + private VBO coord_vbo; + private VBO color_vbo; + private VAO vao; + private IBO element_ibo; + + private Camera camera; + private Mat4 model_matrix; + + private GLint unif_transform; + private GLint attr_coord3d; + private GLint attr_v_color; + private GLfloat rotation_angle; + + /** + * Instantiates a new canvas object. + * + * Assumes that the desired OpenGL context is already selected. + * + * Initializes GLEW, global OpenGL state, and GPU programs that will be + * used for rendering. + */ + public Canvas() throws AppError { + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallback(on_gl_error); + + // GL initialization comes here + glClearColor(71.0f/255, 95.0f/255, 121.0f/255, 1); + glEnable(GL_MULTISAMPLE); + glEnable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + try { + gl_program = new GLProgram( + "resource:///valagl/shaders/vertex.glsl", + "resource:///valagl/shaders/fragment.glsl" + ); + + unif_transform = gl_program.get_uniform_location("transform"); + attr_coord3d = gl_program.get_attrib_location("coord3d"); + attr_v_color = gl_program.get_attrib_location("v_color"); + + vao = new VAO(); + + coord_vbo = new VBO(cube_vertices); + vao.register_vbo(coord_vbo, attr_coord3d, 3); + + color_vbo = new VBO(cube_colors); + vao.register_vbo(color_vbo, attr_v_color, 3); + + element_ibo = new IBO(cube_elements); + } catch (CoreError e) { + throw new AppError.INIT(e.message); + } + + camera = new Camera(); + Vec3 eye = Vec3.from_data(0, 2, 0); + Vec3 center = Vec3.from_data(0, 0, -2); + Vec3 up = Vec3.from_data(0, 1, 0); + camera.look_at(ref eye, ref center, ref up); + } + + private void on_gl_error(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, string message) { + stderr.printf("GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n", + ( type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : "" ), + type, severity, message ); + } + + /** + * Handler of the window resize event. + * + * It is called for the first time when the SDL window is created and shown, + * and then every time the display resolution changes. + * + * Responsible for setting up the viewport size and perspective projection. + * + * @param width The new window width + * @param height The new window height + */ + public void resize_gl(uint width, uint height) { + glViewport(0, 0, (GLsizei) width, (GLsizei) height); + camera.set_perspective_projection(70, (GLfloat) width / (GLfloat) height, 0.01f, 100f); + } + + /** + * Handler of the window repaint event. + * + * It is called every time the window is created. + * + * Responsible for drawing the OpenGL scene. + */ + public void paint_gl() { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // Compute current transformation matrix for the cube + model_matrix = Mat4.identity(); + + Vec3 translation = Vec3.from_data(0, 0, -4); + GeometryUtil.translate(ref model_matrix, ref translation); + Vec3 rotation = Vec3.from_data(0, 1, 0); + GeometryUtil.rotate(ref model_matrix, rotation_angle, ref rotation); + + // Activate our vertex and fragment shaders for the next drawing operations + gl_program.make_current(); + + // Apply camera before drawing the model + camera.apply(unif_transform, ref model_matrix); + + glEnableVertexAttribArray(attr_coord3d); + glEnableVertexAttribArray(attr_v_color); + + // Apply buffers + vao.make_current(); + element_ibo.make_current(); + + // Draw the cube + glDrawElements(GL_TRIANGLES, cube_elements.length, GL_UNSIGNED_SHORT, null); + glDisableVertexAttribArray(attr_coord3d); + glDisableVertexAttribArray(attr_v_color); + } + + /** + * Updates the scene data. + * + * In this application, the only variable scene data is the rotation angle. + * + * @param rotation_angle The new rotation angle (in degrees) + */ + public void update_scene_data(GLfloat rotation_angle) { + this.rotation_angle = rotation_angle; + } + } +} diff --git a/src/core/camera.vala b/src/core/camera.vala new file mode 100644 index 0000000..1b8dc77 --- /dev/null +++ b/src/core/camera.vala @@ -0,0 +1,189 @@ +using GL; + +namespace ValaGL.Core { + + /** + * Encapsulates a camera object. A camera contains a projection matrix and a view matrix. + * + * The main purpose of this class is to provide equivalents of legacy OpenGL functions + * removed in modern OpenGL. Advanced features like quaternion-based rotations are beyond + * the scope of this project. + */ + public class Camera : Object { + private Mat4 projection_matrix; + private Mat4 view_matrix; + private Mat4 result_matrix; + private Mat4 total_matrix; + + /** + * Instantiates a camera object. + * + * The projection and view matrices are set to the identity matrix. + */ + public Camera() { + reset(); + } + + private void update() { + result_matrix = projection_matrix; + result_matrix.mul_mat(ref view_matrix); + } + + /** + * Resets both the projection matrix and the view matrix. + */ + public void reset() { + reset_projection(); + reset_view(); + } + + /** + * Resets the projection matrix, setting it to the identity matrix. + */ + public void reset_projection() { + projection_matrix = Mat4.identity(); + update(); + } + + /** + * Resets the view matrix, setting it to the identity matrix. + */ + public void reset_view() { + view_matrix = Mat4.identity(); + update(); + } + + /** + * Applies the camera to the next model object that will be drawn, by + * multiplying the current projection and view matrices by the model matrix + * passed to the function (which specifies the offset and rotation of the model + * relative to the camera), and binds the matrix data to the specified + * shader uniform variable. + * + * @param uniform_id The shader uniform variable to bind to + * @param model_matrix The model matrix + */ + public void apply(GLint uniform_id, ref Mat4 model_matrix) { + total_matrix = result_matrix; + total_matrix.mul_mat(ref model_matrix); + glUniformMatrix4fv(uniform_id, 1, (GLboolean) GL_FALSE, total_matrix.data); + } + + /** + * Sets up a perspective projection. The previous projection matrix is ignored and overwritten. + * + * Replicates the effects of the legacy ``glFrustum`` function within this camera. + * Refer to that function for the complete description of the projection parameters. + * + * @param left The coordinate of the left vertical clipping plane. + * @param right The coordinate of the right vertical clipping plane. + * @param bottom The coordinate of the bottom horizontal clipping plane. + * @param top The coordinate of the top horizontal clipping plane. + * @param near The coordinate of the near vertical clipping plane. Must be positive. + * @param far The coordinate of the far vertical clipping plane. Must be positive. + */ + public void set_frustum_projection( + GLfloat left, + GLfloat right, + GLfloat bottom, + GLfloat top, + GLfloat near, GLfloat far + ) { + projection_matrix = Mat4.from_data( + 2f * near / (right - left), 0, (right + left) / (right - left), 0, + 0, 2f * near / (top - bottom), (top + bottom) / (top - bottom), 0, + 0, 0, -(far + near) / (far - near), -2f * far * near / (far - near), + 0, 0, -1, 0 + ); + + update(); + } + + /** + * Sets up a symmetrical perspective projection. The previous projection matrix is ignored and overwritten. + * + * Replicates the effects of the legacy ``gluPerspective`` function within this camera. + * Refer to that function for the complete description of the projection parameters. + * + * @param fovy_deg The field of view angle, in degrees, in the y direction. + * @param aspect The aspect ratio that determines the field of view in the x direction. + * The aspect ratio is the ratio of x (width) to y (height). + * @param near The coordinate of the near vertical clipping plane. Must be positive. + * @param far The coordinate of the far vertical clipping plane. Must be positive. + */ + public void set_perspective_projection(GLfloat fovy_deg, GLfloat aspect, GLfloat near, GLfloat far) { + var f = 1 / Math.tanf(GeometryUtil.deg_to_rad(fovy_deg / 2)); + + projection_matrix = Mat4.from_data( + f / aspect, 0, 0, 0, + 0, f, 0, 0, + 0, 0, -(far + near) / (far - near), -2f * far * near / (far - near), + 0, 0, -1, 0 + ); + + update(); + } + + /** + * Sets up an orthogonal projection. The previous projection matrix is ignored and overwritten. + * + * Replicates the effects of the legacy ``glOrtho`` function within this camera. + * Refer to that function for the complete description of the projection parameters. + * + * @param left The coordinate of the left vertical clipping plane. + * @param right The coordinate of the right vertical clipping plane. + * @param bottom The coordinate of the bottom horizontal clipping plane. + * @param top The coordinate of the top horizontal clipping plane. + * @param near The coordinate of the near vertical clipping plane. + * @param far The coordinate of the far vertical clipping plane. + */ + public void set_ortho_projection( + GLfloat left, + GLfloat right, + GLfloat bottom, + GLfloat top, + GLfloat near, GLfloat far + ) { + projection_matrix = Mat4.from_data( + 2f / (right - left), 0, 0, (right + left) / (right - left), + 0, 2f / (top - bottom), 0, (top + bottom) / (top - bottom), + 0, 0, -2f * far * near / (far - near), -(far + near) / (far - near), + 0, 0, 0, 1 + ); + + update(); + } + + /** + * Replicates the effects of the legacy ``gluLookAt`` function within this camera. + * Refer to that function for the complete description of how the camera is positioned. + * + * @param eye The 3D position of the camera + * @param center The 3D position of the point the camera is looking at + * @param up The up-direction + */ + public void look_at(ref Vec3 eye, ref Vec3 center, ref Vec3 up) { + Vec3 l = center; + l.sub(ref eye); + l.normalize(); + + Vec3 uptemp = up; + uptemp.normalize(); + + Vec3 s = l.cross_product(ref uptemp); + Vec3 u = s.cross_product(ref l); + + view_matrix = Mat4.from_data( + s.x, s.y, s.z, 0, + u.x, u.y, u.z, 0, + -l.x, -l.y, -l.z, 0, + 0, 0, 0, 1 + ); + + Vec3 translation = Vec3(); + translation.sub(ref eye); + GeometryUtil.translate(ref view_matrix, ref translation); + update(); + } + } +} diff --git a/src/core/core-error.vala b/src/core/core-error.vala new file mode 100644 index 0000000..f7afb75 --- /dev/null +++ b/src/core/core-error.vala @@ -0,0 +1,20 @@ +namespace ValaGL.Core { + + /** + * Error domain for the ValaGL core OpenGL support. + */ + public errordomain CoreError { + /** + * Indicates a vertex or fragment shader initialization error. + */ + SHADER_INIT, + /** + * Indicates a vertex buffer object initialization error. + */ + VBO_INIT, + /** + * Indicates an index buffer object initialization error. + */ + IBO_INIT + } +} diff --git a/src/core/geometry-util.vala b/src/core/geometry-util.vala new file mode 100644 index 0000000..6a23810 --- /dev/null +++ b/src/core/geometry-util.vala @@ -0,0 +1,112 @@ +using GL; + +namespace ValaGL.Core { + + /** + * Static helper class for stock geometry calculations and matrix transformations. + */ + public class GeometryUtil : Object { + + private GeometryUtil() {} + + /** + * Converts the given angle from degrees to radians. + * + * @param deg Angle in radians + * @return Angle in degrees + */ + public static GLfloat deg_to_rad(GLfloat deg) { + return (GLfloat) (deg * Math.PI / 180f); + } + + /** + * Converts the given angle from radians to degrees. + * + * @param rad Angle in degrees + * @return Angle in radians + */ + public static GLfloat rad_to_deg(GLfloat rad) { + return (GLfloat) (rad / Math.PI * 180f); + } + + /** + * Multiples the given matrix by a matrix that specifies a translation + * by the given vector. The matrix is modified in-place. + * + * For more information, refer to the ``glTranslatef`` legacy OpenGL function. + * + * @param matrix The matrix to transform + * @param translation The translation vector + */ + public static void translate(ref Mat4 matrix, ref Vec3 translation) { + var tmp = Mat4.from_data( + 1, 0, 0, translation.x, + 0, 1, 0, translation.y, + 0, 0, 1, translation.z, + 0, 0, 0, 1 + ); + + matrix.mul_mat(ref tmp); + } + + /** + * Multiples the given matrix by a matrix that specifies a scale operation + * by the given factors in the x, y and z directions. + * The matrix is modified in-place. + * + * For more information, refer to the ``glScalef`` legacy OpenGL function. + * + * @param matrix The matrix to transform + * @param scale_factors The scale factor vector + */ + public static void scale(ref Mat4 matrix, ref Vec3 scale_factors) { + var tmp = Mat4.from_data( + scale_factors.x, 0, 0, 0, + 0, scale_factors.y, 0, 0, + 0, 0, scale_factors.z, 0, + 0, 0, 0, 1 + ); + + matrix.mul_mat(ref tmp); + } + + + /** + * Multiples the given matrix by a matrix that specifies a rotation around + * the given axis by the given angle. The matrix is modified in-place. + * + * Be careful with these rotations. Unlike quaternion-based transformations, + * they may incur gimbal lock. + * + * For more information, refer to the ``glRotatef`` legacy OpenGL function. + * + * @param matrix The matrix to transform + * @param angle_deg The rotation angle in degrees + * @param axis The rotation axis + */ + public static void rotate(ref Mat4 matrix, GLfloat angle_deg, ref Vec3 axis) { + Vec3 axis_normalized = axis; + axis_normalized.normalize(); + + GLfloat angle_rad = deg_to_rad(angle_deg); + + // M = uuT + (cos a) (1 - uuT) + (sin a) S + Mat3 tmp1 = Mat3.from_vec_mul(ref axis_normalized, ref axis_normalized); + Mat3 tmp2 = Mat3.identity(); + tmp2.sub(ref tmp1); + tmp2.mul(Math.cosf(angle_rad)); + tmp1.add(ref tmp2); + + Mat3 s = Mat3.from_data( + 0, -axis_normalized.z, axis_normalized.y, + axis_normalized.z, 0, -axis_normalized.x, + -axis_normalized.y, axis_normalized.x, 0 + ); + s.mul(Math.sinf(angle_rad)); + tmp1.add(ref s); + + var tmp = Mat4.expand(ref tmp1); + matrix.mul_mat(ref tmp); + } + } +} diff --git a/src/core/gl-program.vala b/src/core/gl-program.vala new file mode 100644 index 0000000..d4f7224 --- /dev/null +++ b/src/core/gl-program.vala @@ -0,0 +1,116 @@ +using GL; + +namespace ValaGL.Core { + + /** + * Encapsulation of an OpenGL GPU program, containing one vertex shader and one fragment shader. + */ + public class GLProgram : Object { + private GLuint vertex_shader = 0; + private GLuint fragment_shader = 0; + private GLuint prog_id = 0; + + /** + * Instantiates a new OpenGL program object, reading the vertex and fragment shaders from files. + * + * @param vertex_shader_file The file to read the vertex shader from + * @param fragment_shader_file The file to read the fragment shader from + */ + public GLProgram(string vertex_shader_file, string fragment_shader_file) throws CoreError { + vertex_shader = create_shader_from_file(GL_VERTEX_SHADER, vertex_shader_file); + fragment_shader = create_shader_from_file(GL_FRAGMENT_SHADER, fragment_shader_file); + + prog_id = glCreateProgram(); + + if (prog_id == 0) + throw new CoreError.SHADER_INIT("Cannot allocate GL program ID"); + + glAttachShader(prog_id, vertex_shader); + glAttachShader(prog_id, fragment_shader); + glLinkProgram(prog_id); + + GLint[] link_ok = { GL_FALSE }; + glGetProgramiv(prog_id, GL_LINK_STATUS, link_ok); + + if (link_ok[0] != GL_TRUE) + throw new CoreError.SHADER_INIT("Cannot link GL program"); + } + + ~GLProgram() { + if (vertex_shader != 0) + glDeleteShader(vertex_shader); + + if (fragment_shader != 0) + glDeleteShader(fragment_shader); + + if (prog_id != 0) + glDeleteProgram(prog_id); + } + + /** + * Gets the ID for the shader ``attribute`` variable with the specified name. + * + * @return The attribute ID + */ + public GLint get_attrib_location(string name) { + assert(prog_id != 0); + return glGetAttribLocation(prog_id, name); + } + + /** + * Gets the ID for the shader ``uniform`` variable with the specified name. + * + * @return The uniform ID + */ + public GLint get_uniform_location(string name) { + assert(prog_id != 0); + return glGetUniformLocation(prog_id, name); + } + + /** + * Makes this OpenGL program current in the current OpenGL context, applying it to future drawing operations. + */ + public void make_current() { + assert(prog_id != 0); + glUseProgram(prog_id); + } + + private static GLuint create_shader_from_file(GLuint shader_type, string file_path) throws CoreError { + try { + uint8[] file_contents; + + var file = file_path.has_prefix("resource://") ? File.new_for_uri(file_path) : File.new_for_path(file_path); + + file.load_contents(null, out file_contents, null); + return create_shader_from_string(shader_type, (string) file_contents); + } catch (Error e) { + throw new CoreError.SHADER_INIT(e.message); + } + } + + private static GLuint create_shader_from_string(GLuint shader_type, string source) throws CoreError { + var shader = glCreateShader(shader_type); + + if (shader == 0) + throw new CoreError.SHADER_INIT("Cannot allocate shader ID"); + + string[] sourceArray = { source, null }; + glShaderSource(shader, 1, sourceArray, null); + glCompileShader(shader); + + GLint[] compile_ok = { GL_FALSE }; + glGetShaderiv(shader, GL_COMPILE_STATUS, compile_ok); + + if (compile_ok[0] == GL_TRUE) + return shader; + + // Otherwise, there is an error. + glDeleteShader(shader); + + if (shader_type == GL_VERTEX_SHADER) + throw new CoreError.SHADER_INIT("Error compiling vertex shader"); + else + throw new CoreError.SHADER_INIT("Error compiling fragment shader"); + } + } +} diff --git a/src/core/ibo.vala b/src/core/ibo.vala new file mode 100644 index 0000000..4fa512e --- /dev/null +++ b/src/core/ibo.vala @@ -0,0 +1,45 @@ +using GL; + +namespace ValaGL.Core { + + /** + * Encapsulation of an OpenGL index buffer object. + * + * The underlying OpenGL buffer is destroyed when this object is finally unreferenced. + */ + public class IBO : Object { + private GLuint id; + + /** + * Creates an index buffer object. + * + * @param data Array to bind to the OpenGL buffer + */ + public IBO(GLushort[] data) throws CoreError { + GLuint id_array[1]; + glGenBuffers(1, id_array); + id = id_array[0]; + + if (id == 0) + throw new CoreError.IBO_INIT("Cannot allocate index buffer object"); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.length * sizeof(GLushort), (GLvoid[]) data, GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + + /** + * Makes this IBO current for future drawing operations in the OpenGL context. + */ + public void make_current() { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id); + } + + ~IBO() { + if (id != 0) { + GLuint[] id_array = { id }; + glDeleteBuffers(1, id_array); + } + } + } +} diff --git a/src/core/matrix-math.vala b/src/core/matrix-math.vala new file mode 100644 index 0000000..c7adeba --- /dev/null +++ b/src/core/matrix-math.vala @@ -0,0 +1,734 @@ +using GL; + +namespace ValaGL.Core { + + /** + * A 3-component vector. + */ + public struct Vec3 { + public GLfloat data[3]; + + /** + * Creates a new vector, zero initialized. + */ + public Vec3() {} + + /** + * Creates a vector whose contents are the copy of the given data. + */ + public Vec3.from_data(GLfloat x, GLfloat y, GLfloat z) { + data[0] = x; + data[1] = y; + data[2] = z; + } + + /** + * Creates a vector whose contents are the copy of the given array. + */ + public Vec3.from_array([CCode (array_length = false)] GLfloat[] data) { + this.data[0] = data[0]; + this.data[1] = data[1]; + this.data[2] = data[2]; + } + + /** + * Adds the given vector, component-wise. + */ + public void add(ref Vec3 other) { + data[0] += other.data[0]; + data[1] += other.data[1]; + data[2] += other.data[2]; + } + + /** + * Subtracts the given vector, component-wise. + */ + public void sub(ref Vec3 other) { + data[0] -= other.data[0]; + data[1] -= other.data[1]; + data[2] -= other.data[2]; + } + + /** + * Multiplies the given vector, component-wise. + */ + public void mul_vec(ref Vec3 other) { + data[0] *= other.data[0]; + data[1] *= other.data[1]; + data[2] *= other.data[2]; + } + + /** + * Divides the given vector, component-wise. + */ + public void div_vec(ref Vec3 other) { + data[0] /= other.data[0]; + data[1] /= other.data[1]; + data[2] /= other.data[2]; + } + + /** + * Computes the dot product of this vector and the other vector. + */ + public GLfloat dot_product(ref Vec3 other) { + return data[0] * other.data[0] + data[1] * other.data[1] + data[2] * other.data[2]; + } + + /** + * Computes the cross product of this vector and the other vector. + */ + public Vec3 cross_product(ref Vec3 other) { + return Vec3.from_data( + data[1] * other.data[2] - data[2] * other.data[1], + data[2] * other.data[0] - data[0] * other.data[2], + data[0] * other.data[1] - data[1] * other.data[0] + ); + } + + /** + * Multiplies the vector by the given scalar. + */ + public void mul(GLfloat factor) { + data[0] *= factor; + data[1] *= factor; + data[2] *= factor; + } + + /** + * Divides the vector by the given scalar. + */ + public void div(GLfloat factor) { + data[0] /= factor; + data[1] /= factor; + data[2] /= factor; + } + + /** + * Computes the norm of this vector. + */ + public GLfloat norm() { + return Math.sqrtf(dot_product(ref this)); + } + + /** + * Normalizes this vector, dividing it by its norm. + * If the norm is zero, the result is undefined. + */ + public void normalize() { + div(norm()); + } + + /** + * Convenience accessor for data[0]. + */ + public GLfloat x { + get { return data[0]; } + } + + /** + * Convenience accessor for data[1]. + */ + public GLfloat y { + get { return data[1]; } + } + + /** + * Convenience accessor for data[2]. + */ + public GLfloat z { + get { return data[2]; } + } + } + + /** + * A 4-component vector. + */ + public struct Vec4 { + public GLfloat data[4]; + + /** + * Creates a new vector, zero initialized. + */ + public Vec4() {} + + /** + * Creates a vector whose contents are the copy of the given data. + */ + public Vec4.from_data(GLfloat x, GLfloat y, GLfloat z, GLfloat w) { + data[0] = x; + data[1] = y; + data[2] = z; + data[3] = w; + } + + /** + * Creates a vector whose contents are the copy of the given array. + */ + public Vec4.from_array([CCode (array_length = false)] GLfloat[] data) { + this.data[0] = data[0]; + this.data[1] = data[1]; + this.data[2] = data[2]; + this.data[3] = data[3]; + } + + /** + * Expands a 3x3 vector plus scalar into a 4x4 vector. + */ + public Vec4.expand(ref Vec3 vec3, GLfloat w) { + this.data[0] = vec3.data[0]; + this.data[1] = vec3.data[1]; + this.data[2] = vec3.data[2]; + this.data[3] = w; + } + + /** + * Adds the given vector, component-wise. + */ + public void add(ref Vec4 other) { + data[0] += other.data[0]; + data[1] += other.data[1]; + data[2] += other.data[2]; + data[3] += other.data[3]; + } + + /** + * Subtracts the given vector, component-wise. + */ + public void sub(ref Vec4 other) { + data[0] -= other.data[0]; + data[1] -= other.data[1]; + data[2] -= other.data[2]; + data[3] -= other.data[3]; + } + + /** + * Multiplies the given vector, component-wise. + */ + public void mul_vec(ref Vec4 other) { + data[0] *= other.data[0]; + data[1] *= other.data[1]; + data[2] *= other.data[2]; + data[3] *= other.data[3]; + } + + /** + * Divides the given vector, component-wise. + */ + public void div_vec(ref Vec4 other) { + data[0] /= other.data[0]; + data[1] /= other.data[1]; + data[2] /= other.data[2]; + data[3] /= other.data[3]; + } + + /** + * Computes the dot product of this vector and the other vector. + */ + public GLfloat dot_product(ref Vec4 other) { + return data[0] * other.data[0] + data[1] * other.data[1] + + data[2] * other.data[2] + data[3] * other.data[3]; + } + + /** + * Multiplies the vector by the given scalar. + */ + public void mul(GLfloat factor) { + data[0] *= factor; + data[1] *= factor; + data[2] *= factor; + data[3] *= factor; + } + + /** + * Divides the vector by the given scalar. + */ + public void div(GLfloat factor) { + data[0] /= factor; + data[1] /= factor; + data[2] /= factor; + data[3] /= factor; + } + + /** + * Computes the norm of this vector. + */ + public GLfloat norm() { + return Math.sqrtf(dot_product(ref this)); + } + + /** + * Normalizes this vector, dividing it by its norm. + * If the norm is zero, the result is undefined. + */ + public void normalize() { + div(norm()); + } + + /** + * Convenience accessor for data[0]. + */ + public GLfloat x { + get { return data[0]; } + } + + /** + * Convenience accessor for data[1]. + */ + public GLfloat y { + get { return data[1]; } + } + + /** + * Convenience accessor for data[2]. + */ + public GLfloat z { + get { return data[2]; } + } + + /** + * Convenience accessor for data[3]. + */ + public GLfloat w { + get { return data[3]; } + } + } + + /** + * A 3x3 matrix. + */ + public struct Mat3 { + public float data[9]; + + /** + * Creates a new matrix, zero initialized. + */ + public Mat3() {} + + /** + * Creates a matrix whose contents are the copy of the given data. + * Warning: the data are specified in column-first-index order, which is different from + * the internal storage format (row-first-index). + */ + public Mat3.from_data( + GLfloat a11, GLfloat a12, GLfloat a13, + GLfloat a21, GLfloat a22, GLfloat a23, + GLfloat a31, GLfloat a32, GLfloat a33 + ) { + data[0] = a11; + data[1] = a21; + data[2] = a31; + + data[3] = a12; + data[4] = a22; + data[5] = a32; + + data[6] = a13; + data[7] = a23; + data[8] = a33; + } + + /** + * Given two vectors ``a`` and ``b``, computes a matrix equal to ``a * bT``. + */ + public Mat3.from_vec_mul(ref Vec3 a, ref Vec3 b) { + data[0] = a.data[0] * b.data[0]; + data[1] = a.data[1] * b.data[0]; + data[2] = a.data[2] * b.data[0]; + + data[3] = a.data[0] * b.data[1]; + data[4] = a.data[1] * b.data[1]; + data[5] = a.data[2] * b.data[1]; + + data[6] = a.data[0] * b.data[2]; + data[7] = a.data[1] * b.data[2]; + data[8] = a.data[2] * b.data[2]; + } + + /** + * Creates a matrix whose contents are the copy of the given array, assumed to have at least 9 elements. + */ + public Mat3.from_array([CCode (array_length = false)] GLfloat[] data) { + this.data = data; + } + + /** + * Creates an identity matrix. + */ + public Mat3.identity() { + data[0 * 3 + 0] = 1; + data[1 * 3 + 1] = 1; + data[2 * 3 + 2] = 1; + } + + /** + * Adds the given matrix, component-wise. + */ + public void add(ref Mat3 other) { + for (int i = 0; i < 9; i++) + data[i] += other.data[i]; + } + + /** + * Subtracts the given matrix, component-wise. + */ + public void sub(ref Mat3 other) { + for (int i = 0; i < 9; i++) + data[i] -= other.data[i]; + } + + /** + * Multiplies the matrix by the given scalar, component-wise. + */ + public void mul(GLfloat factor) { + for (int i = 0; i < 9; i++) + data[i] *= factor; + } + + /** + * Divides the matrix by the given scalar, component-wise. + */ + public void div(GLfloat factor) { + for (int i = 0; i < 9; i++) + data[i] /= factor; + } + + /** + * Multiplies the given matrix using the linear algebra definition of matrix multiplication. + */ + public void mul_mat(ref Mat3 other) { + float res[9]; // Zero initialized + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + res[j * 3 + i] = 0; + + for (int k = 0; k < 3; k++) + res[j * 3 + i] += data[k * 3 + i] * other.data[j * 3 + k]; + } + } + + data = res; + } + + /** + * Multiplies this matrix by the given vector and returns the result as a new vector. + */ + public Vec3 mul_vec(ref Vec3 vec) { + Vec3 res = Vec3(); // Zero initialized + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) + res.data[i] += data[j * 3 + i] * vec.data[j]; + } + + return res; + } + + /** + * Returns a new matrix that is the transposition of this matrix. + */ + public Mat3 transposed() { + Mat3 res = Mat3(); + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) + res.data[i * 3 + j] = data[j * 3 + i]; + } + + return res; + } + + /** + * Computes the determinant of this matrix. + */ + public GLfloat det() { + return det_helper3(data[0:3], data[3:6], data[6:9]); + } + + /** + * Returns a new matrix that is the inversion of this matrix. + * @param success Set to ``false`` if the matrix cannot be inverted (its determinant is zero) + * and ``true`` otherwise. + * @return The inverted matrix if the matrix was not successfully inverted, + * otherwise the return value is undefined. + */ + public Mat3 inverted(out bool success) { + GLfloat det = det(); + + if (Math.fabsf(det) < 0.00001f) { + success = false; + return Mat3(); + } + + success = true; + + GLfloat inv_det = 1.0f / det; + Mat3 res = Mat3(); + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + int i1 = (i + 1) % 3; + int j1 = (j + 1) % 3; + int i2 = (i + 2) % 3; + int j2 = (j + 2) % 3; + // Warning: computing determinants from transposed matrix! i becomes j and the other way round + res.data [j * 3 + i] = inv_det * + (data[i1 * 3 + j1] * data[i2 * 3 + j2] - data[i2 * 3 + j1] * data[i1 * 3 + j2]); + } + } + + return res; + } + } + + /** + * A 4x4 matrix. + */ + public struct Mat4 { + public float data[16]; + + /** + * Creates a new matrix, zero initialized. + */ + public Mat4() {} + + /** + * Creates a matrix whose contents are the copy of the given data. + * Warning: the data are specified in column-first-index order, which is different from + * the internal storage format (row-first-index). + */ + public Mat4.from_data( + GLfloat a11, GLfloat a12, GLfloat a13, GLfloat a14, + GLfloat a21, GLfloat a22, GLfloat a23, GLfloat a24, + GLfloat a31, GLfloat a32, GLfloat a33, GLfloat a34, + GLfloat a41, GLfloat a42, GLfloat a43, GLfloat a44 + ) { + data[0] = a11; + data[1] = a21; + data[2] = a31; + data[3] = a41; + + data[4] = a12; + data[5] = a22; + data[6] = a32; + data[7] = a42; + + data[8] = a13; + data[9] = a23; + data[10] = a33; + data[11] = a43; + + data[12] = a14; + data[13] = a24; + data[14] = a34; + data[15] = a44; + } + + /** + * Given two vectors ``a`` and ``b``, computes a matrix equal to ``a * bT``. + */ + public Mat4.from_vec_mul(ref Vec4 a, ref Vec4 b) { + data[0] = a.data[0] * b.data[0]; + data[1] = a.data[1] * b.data[0]; + data[2] = a.data[2] * b.data[0]; + data[3] = a.data[3] * b.data[0]; + + data[4] = a.data[0] * b.data[1]; + data[5] = a.data[1] * b.data[1]; + data[6] = a.data[2] * b.data[1]; + data[7] = a.data[3] * b.data[1]; + + data[8] = a.data[0] * b.data[2]; + data[9] = a.data[1] * b.data[2]; + data[10] = a.data[2] * b.data[2]; + data[11] = a.data[3] * b.data[2]; + + data[12] = a.data[0] * b.data[3]; + data[13] = a.data[1] * b.data[3]; + data[14] = a.data[2] * b.data[3]; + data[15] = a.data[3] * b.data[3]; + } + + /** + * Creates a matrix whose contents are the copy of the given array, assumed to have at least 16 elements. + */ + public Mat4.from_array([CCode (array_length = false)] GLfloat[] data) { + this.data = data; + } + + /** + * Creates an identity matrix. + */ + public Mat4.identity() { + data[0 * 4 + 0] = 1; + data[1 * 4 + 1] = 1; + data[2 * 4 + 2] = 1; + data[3 * 4 + 3] = 1; + } + + /** + * Creates an expansion of the given 3x3 matrix into 4x4: + * + * A 0 + * + * 0 1 + */ + public Mat4.expand(ref Mat3 mat3) { + data[0] = mat3.data[0]; + data[1] = mat3.data[1]; + data[2] = mat3.data[2]; + + data[4] = mat3.data[3]; + data[5] = mat3.data[4]; + data[6] = mat3.data[5]; + + data[8] = mat3.data[6]; + data[9] = mat3.data[7]; + data[10] = mat3.data[8]; + + data[3 * 4 + 3] = 1; + } + + /** + * Adds the given matrix, component-wise. + */ + public void add(ref Mat4 other) { + for (int i = 0; i < 16; i++) + data[i] += other.data[i]; + } + + /** + * Subtracts the given matrix, component-wise. + */ + public void sub(ref Mat4 other) { + for (int i = 0; i < 16; i++) + data[i] -= other.data[i]; + } + + /** + * Multiplies the matrix by the given scalar, component-wise. + */ + public void mul(GLfloat factor) { + for (int i = 0; i < 16; i++) + data[i] *= factor; + } + + /** + * Divides the matrix by the given scalar, component-wise. + */ + public void div(GLfloat factor) { + for (int i = 0; i < 16; i++) + data[i] /= factor; + } + + /** + * Multiplies the given matrix using the linear algebra definition of matrix multiplication. + */ + public void mul_mat(ref Mat4 other) { + float res[16]; // Zero initialized + + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + res[j * 4 + i] = 0; + + for (int k = 0; k < 4; k++) + res[j * 4 + i] += data[k * 4 + i] * other.data[j * 4 + k]; + } + } + + data = res; + } + + /** + * Multiplies this matrix by the given vector and returns the result as a new vector. + */ + public Vec4 mul_vec(ref Vec4 vec) { + Vec4 res = Vec4(); // Zero initialized + + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) + res.data[i] += data[j * 4 + i] * vec.data[j]; + } + + return res; + } + + /** + * Returns a new matrix that is the transposition of this matrix. + */ + public Mat4 transposed() { + Mat4 res = Mat4(); + + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) + res.data[i * 4 + j] = data[j * 4 + i]; + } + + return res; + } + + /** + * Computes the determinant of this matrix. + */ + public GLfloat det() { + return data[0] * det_helper3(data[4:8], data[9:12], data[13:16]) + - data[4] * det_helper3(data[1:4], data[9:12], data[13:16]) + + data[8] * det_helper3(data[1:4], data[4:8], data[13:16]) + - data[12] * det_helper3(data[1:4], data[4:8], data[9:12] ); + } + + /** + * Returns a new matrix that is the inversion of this matrix. + * @param success Set to ``false`` if the matrix cannot be inverted (its determinant is zero) + * and ``true`` otherwise. + * @return The inverted matrix if the matrix was not successfully inverted, + * otherwise the return value is undefined. + */ + public Mat4 inverted(out bool success) { + GLfloat det = det(); + + if (Math.fabsf(det) < 0.00001f) { + success = false; + return Mat4(); + } + + success = true; + + GLfloat inv_det = 1.0f / det; + Mat3 transposed_submatrix = Mat3(); + Mat4 res = Mat4(); + + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + int i1 = (i + 1) % 4; + int j1 = (j + 1) % 4; + int i2 = (i + 2) % 4; + int j2 = (j + 2) % 4; + int i3 = (i + 3) % 4; + int j3 = (j + 3) % 4; + + // Warning: computing determinants from transposed matrix! i becomes j and the other way round + transposed_submatrix.data = { + data[i1 * 4 + j1], data[i1 * 4 + j2], data[i1 * 4 + j3], + data[i2 * 4 + j1], data[i2 * 4 + j2], data[i2 * 4 + j3], + data[i3 * 4 + j1], data[i3 * 4 + j2], data[i3 * 4 + j3] + }; + + res.data [j * 4 + i] = inv_det * transposed_submatrix.det(); + } + } + + return res; + } + } + + private static GLfloat det_helper3( + [CCode (array_length = false)] GLfloat[] col1, + [CCode (array_length = false)] GLfloat[] col2, + [CCode (array_length = false)] GLfloat[] col3 + ) { + return col1[0] * (col2[1] * col3[2] - col2[2] * col3[1]) + + col2[0] * (col3[1] * col1[2] - col3[2] * col1[1]) + + col3[0] * (col1[1] * col2[2] - col1[2] * col2[1]); + } +} diff --git a/src/core/vao.vala b/src/core/vao.vala new file mode 100644 index 0000000..11a9859 --- /dev/null +++ b/src/core/vao.vala @@ -0,0 +1,49 @@ +using GL; + +namespace ValaGL.Core { + + /** + * Encapsulation of an OpenGL vertex array object. + * + * The underlying OpenGL vertex array is destroyed when this object is finally unreferenced. + */ + public class VAO : Object { + private GLuint id; + + /** + * Creates a vertex array object. + */ + public VAO() throws CoreError { + GLuint id_array[1]; + glGenVertexArrays(1, id_array); + id = id_array[0]; + + if (id == 0) { + throw new CoreError.VBO_INIT("Cannot allocate vertex array object"); + } + } + + /** + * Registers a VBO binding to the given shader attribute in this VAO. + */ + public void register_vbo(VBO vbo, GLint attribute, GLsizei stride) { + make_current(); + vbo.make_current(); + glVertexAttribPointer(attribute, stride, GL_FLOAT, (GLboolean) GL_FALSE, 0, null); + } + + /** + * Makes this VAO current for future drawing operations in the OpenGL context. + */ + public void make_current() { + glBindVertexArray(id); + } + + ~VAO() { + if (id != 0) { + GLuint[] id_array = { id }; + glDeleteVertexArrays(1, id_array); + } + } + } +} diff --git a/src/core/vbo.vala b/src/core/vbo.vala new file mode 100644 index 0000000..30daa5b --- /dev/null +++ b/src/core/vbo.vala @@ -0,0 +1,60 @@ +using GL; + +namespace ValaGL.Core { + + /** + * Encapsulation of an OpenGL vertex buffer object. + * + * The underlying OpenGL buffer is destroyed when this object is finally unreferenced. + */ + public class VBO : Object { + private GLuint id; + + /** + * Creates a vertex buffer object. + * + * @param data Array to bind to the OpenGL buffer + */ + public VBO(GLfloat[] data) throws CoreError { + GLuint id_array[1]; + glGenBuffers(1, id_array); + id = id_array[0]; + + if (id == 0) { + throw new CoreError.VBO_INIT("Cannot allocate vertex buffer object"); + } + + glBindBuffer(GL_ARRAY_BUFFER, id); + glBufferData(GL_ARRAY_BUFFER, data.length * sizeof(GLfloat), (GLvoid[]) data, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + + /** + * Makes this VBO current for future drawing operations in the OpenGL context. + */ + public void make_current() { + glBindBuffer(GL_ARRAY_BUFFER, id); + } + + /** + * Makes this VBO current for future drawing operations in the OpenGL context, + * and sets it up as the source of vertex data for the given shader attribute. + * + * For the meaning of ``attribute`` and ``stride``, see ``glVertexAttribPointer``. + * + * @param attribute The index of the generic vertex attribute to be modified. + * @param stride The byte offset between consecutive generic vertex attributes. + */ + public void apply_as_vertex_array(GLint attribute, GLsizei stride) { + make_current(); + glVertexAttribPointer(attribute, stride, GL_FLOAT, (GLboolean) GL_FALSE, 0, null); + } + + ~VBO() { + if (id != 0) { + GLuint[] id_array = { id }; + glDeleteBuffers(1, id_array); + } + } + } +} diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 0000000..eb9888f --- /dev/null +++ b/src/meson.build @@ -0,0 +1,31 @@ +valagl_deps = [ + dependency('glib-2.0'), + dependency('gobject-2.0'), + dependency('gio-2.0'), + dependency('gl'), + dependency('sdl2'), +] + +valagl_sources = [ + 'app.vala', + 'app-error.vala', + 'canvas.vala', + + 'core/camera.vala', + 'core/core-error.vala', + 'core/geometry-util.vala', + 'core/gl-program.vala', + 'core/ibo.vala', + 'core/matrix-math.vala', + 'core/vao.vala', + 'core/vbo.vala', +] + +executable('valagl', + valagl_resources, + valagl_sources, + vala_args: '--target-glib=2.58', + dependencies: valagl_deps, + link_args : ['-lepoxy', '-lm' ], + install: true, +) diff --git a/valagl.doap b/valagl.doap new file mode 100644 index 0000000..8d5e663 --- /dev/null +++ b/valagl.doap @@ -0,0 +1,24 @@ + + + + ValaGL + OpenGL example + OpenGL example using Vala & SDL + + + + + Vala + + + + PaladinDev + + + + diff --git a/vapi/AppConfig.vapi b/vapi/AppConfig.vapi deleted file mode 100644 index 139d304..0000000 --- a/vapi/AppConfig.vapi +++ /dev/null @@ -1,37 +0,0 @@ -/* - AppConfig.vapi - Copyright (C) 2010-2012 Maia Everett - - 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. -*/ - -namespace ValaGL.Core.AppConfig { - [CCode (cheader_filename = "config.h", cname = "CMAKE_INSTALL_PREFIX")] - public const string PREFIX; - [CCode (cheader_filename = "config.h", cname = "CMAKE_INSTALL_BIN_DIR")] - public const string BIN_DIR; - [CCode (cheader_filename = "config.h", cname = "CMAKE_INSTALL_DATA_DIR")] - public const string DATA_DIR; - [CCode (cheader_filename = "config.h", cname = "CMAKE_INSTALL_APP_DATA_DIR")] - public const string APP_DATA_DIR; - [CCode (cheader_filename = "config.h", cname = "CMAKE_APP_VERSION")] - public const string APP_VERSION; - [CCode (cheader_filename = "config.h", cname = "CMAKE_APP_AUTHORS")] - public const string APP_AUTHORS; -} diff --git a/vapi/glu.vapi b/vapi/glu.vapi deleted file mode 100644 index 8177032..0000000 --- a/vapi/glu.vapi +++ /dev/null @@ -1,304 +0,0 @@ -/* glu.vapi - * - * Copyright (C) 2008 Matias De la Puente - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Author: - * Matias De la Puente - * - * Modified by Maia Everett : - * - use epoxy/gl.h instead of glu.h - */ - -[CCode (lower_case_cprefix ="", cheader_filename="epoxy/gl.h")] -namespace GLU -{ - // Extensions - public const GL.GLenum GLU_EXT_object_space_tess; - public const GL.GLenum GLU_EXT_nurbs_tessellator; - - // Version - public const GL.GLenum GLU_VERSION_1_1; - public const GL.GLenum GLU_VERSION_1_2; - public const GL.GLenum GLU_VERSION_1_3; - - // StringName - public const GL.GLenum GLU_VERSION; - public const GL.GLenum GLU_EXTENSIONS; - - // ErrorCode - public const GL.GLenum GLU_INVALID_ENUM; - public const GL.GLenum GLU_INVALID_VALUE; - public const GL.GLenum GLU_OUT_OF_MEMORY; - public const GL.GLenum GLU_INCOMPATIBLE_GL_VERSION; - public const GL.GLenum GLU_INVALID_OPERATION; - - // NurbsDisplay - public const GL.GLenum GLU_OUTLINE_POLYGON; - public const GL.GLenum GLU_OUTLINE_PATCH; - - // NurbsCallback - public const GL.GLenum GLU_NURBS_ERROR; - public const GL.GLenum GLU_ERROR; - public const GL.GLenum GLU_NURBS_BEGIN; - public const GL.GLenum GLU_NURBS_BEGIN_EXT; - public const GL.GLenum GLU_NURBS_VERTEX; - public const GL.GLenum GLU_NURBS_VERTEX_EXT; - public const GL.GLenum GLU_NURBS_NORMAL; - public const GL.GLenum GLU_NURBS_NORMAL_EXT; - public const GL.GLenum GLU_NURBS_COLOR; - public const GL.GLenum GLU_NURBS_COLOR_EXT; - public const GL.GLenum GLU_NURBS_TEXTURE_COORD; - public const GL.GLenum GLU_NURBS_TEX_COORD_EXT; - public const GL.GLenum GLU_NURBS_END; - public const GL.GLenum GLU_NURBS_END_EXT; - public const GL.GLenum GLU_NURBS_BEGIN_DATA; - public const GL.GLenum GLU_NURBS_BEGIN_DATA_EXT; - public const GL.GLenum GLU_NURBS_VERTEX_DATA; - public const GL.GLenum GLU_NURBS_VERTEX_DATA_EXT; - public const GL.GLenum GLU_NURBS_NORMAL_DATA; - public const GL.GLenum GLU_NURBS_NORMAL_DATA_EXT; - public const GL.GLenum GLU_NURBS_COLOR_DATA; - public const GL.GLenum GLU_NURBS_COLOR_DATA_EXT; - public const GL.GLenum GLU_NURBS_TEXTURE_COORD_DATA; - public const GL.GLenum GLU_NURBS_TEX_COORD_DATA_EXT; - public const GL.GLenum GLU_NURBS_END_DATA; - public const GL.GLenum GLU_NURBS_END_DATA_EXT; - - // NurbsError - public const GL.GLenum GLU_NURBS_ERROR1; - public const GL.GLenum GLU_NURBS_ERROR2; - public const GL.GLenum GLU_NURBS_ERROR3; - public const GL.GLenum GLU_NURBS_ERROR4; - public const GL.GLenum GLU_NURBS_ERROR5; - public const GL.GLenum GLU_NURBS_ERROR6; - public const GL.GLenum GLU_NURBS_ERROR7; - public const GL.GLenum GLU_NURBS_ERROR8; - public const GL.GLenum GLU_NURBS_ERROR9; - public const GL.GLenum GLU_NURBS_ERROR10; - public const GL.GLenum GLU_NURBS_ERROR11; - public const GL.GLenum GLU_NURBS_ERROR12; - public const GL.GLenum GLU_NURBS_ERROR13; - public const GL.GLenum GLU_NURBS_ERROR14; - public const GL.GLenum GLU_NURBS_ERROR15; - public const GL.GLenum GLU_NURBS_ERROR16; - public const GL.GLenum GLU_NURBS_ERROR17; - public const GL.GLenum GLU_NURBS_ERROR18; - public const GL.GLenum GLU_NURBS_ERROR19; - public const GL.GLenum GLU_NURBS_ERROR20; - public const GL.GLenum GLU_NURBS_ERROR21; - public const GL.GLenum GLU_NURBS_ERROR22; - public const GL.GLenum GLU_NURBS_ERROR23; - public const GL.GLenum GLU_NURBS_ERROR24; - public const GL.GLenum GLU_NURBS_ERROR25; - public const GL.GLenum GLU_NURBS_ERROR26; - public const GL.GLenum GLU_NURBS_ERROR27; - public const GL.GLenum GLU_NURBS_ERROR28; - public const GL.GLenum GLU_NURBS_ERROR29; - public const GL.GLenum GLU_NURBS_ERROR30; - public const GL.GLenum GLU_NURBS_ERROR31; - public const GL.GLenum GLU_NURBS_ERROR32; - public const GL.GLenum GLU_NURBS_ERROR33; - public const GL.GLenum GLU_NURBS_ERROR34; - public const GL.GLenum GLU_NURBS_ERROR35; - public const GL.GLenum GLU_NURBS_ERROR36; - public const GL.GLenum GLU_NURBS_ERROR37; - - // NurbsProperty - public const GL.GLenum GLU_AUTO_LOAD_MATRIX; - public const GL.GLenum GLU_CULLING; - public const GL.GLenum GLU_SAMPLING_TOLERANCE; - public const GL.GLenum GLU_DISPLAY_MODE; - public const GL.GLenum GLU_PARAMETRIC_TOLERANCE; - public const GL.GLenum GLU_SAMPLING_METHOD; - public const GL.GLenum GLU_U_STEP; - public const GL.GLenum GLU_V_STEP; - public const GL.GLenum GLU_NURBS_MODE; - public const GL.GLenum GLU_NURBS_MODE_EXT; - public const GL.GLenum GLU_NURBS_TESSELLATOR; - public const GL.GLenum GLU_NURBS_TESSELLATOR_EXT; - public const GL.GLenum GLU_NURBS_RENDERER; - public const GL.GLenum GLU_NURBS_RENDERER_EXT; - - // NurbsSampling - public const GL.GLenum GLU_OBJECT_PARAMETRIC_ERROR; - public const GL.GLenum GLU_OBJECT_PARAMETRIC_ERROR_EXT; - public const GL.GLenum GLU_OBJECT_PATH_LENGTH; - public const GL.GLenum GLU_OBJECT_PATH_LENGTH_EXT; - public const GL.GLenum GLU_PATH_LENGTH; - public const GL.GLenum GLU_PARAMETRIC_ERROR; - public const GL.GLenum GLU_DOMAIN_DISTANCE; - - // NurbsTrim - public const GL.GLenum GLU_MAP1_TRIM_2; - public const GL.GLenum GLU_MAP1_TRIM_3; - - // QuadricDrawStyle - public const GL.GLenum GLU_POINT; - public const GL.GLenum GLU_LINE; - public const GL.GLenum GLU_FILL; - public const GL.GLenum GLU_SILHOUETTE; - - // QuadricNormal - public const GL.GLenum GLU_SMOOTH; - public const GL.GLenum GLU_FLAT; - public const GL.GLenum GLU_NONE; - - // QuadricOrientation - public const GL.GLenum GLU_OUTSIDE; - public const GL.GLenum GLU_INSIDE; - - // TessCallback - public const GL.GLenum GLU_TESS_BEGIN; - public const GL.GLenum GLU_BEGIN; - public const GL.GLenum GLU_TESS_VERTEX; - public const GL.GLenum GLU_VERTEX; - public const GL.GLenum GLU_TESS_END; - public const GL.GLenum GLU_END; - public const GL.GLenum GLU_TESS_ERROR; - public const GL.GLenum GLU_TESS_EDGE_FLAG; - public const GL.GLenum GLU_EDGE_FLAG; - public const GL.GLenum GLU_TESS_COMBINE; - public const GL.GLenum GLU_TESS_BEGIN_DATA; - public const GL.GLenum GLU_TESS_VERTEX_DATA; - public const GL.GLenum GLU_TESS_END_DATA; - public const GL.GLenum GLU_TESS_ERROR_DATA; - public const GL.GLenum GLU_TESS_EDGE_FLAG_DATA; - public const GL.GLenum GLU_TESS_COMBINE_DATA; - - // TessContour - public const GL.GLenum GLU_CW; - public const GL.GLenum GLU_CCW; - public const GL.GLenum GLU_INTERIOR; - public const GL.GLenum GLU_EXTERIOR; - public const GL.GLenum GLU_UNKNOWN; - - // TessProperty - public const GL.GLenum GLU_TESS_WINDING_RULE; - public const GL.GLenum GLU_TESS_BOUNDARY_ONLY; - public const GL.GLenum GLU_TESS_TOLERANCE; - - // TessError - public const GL.GLenum GLU_TESS_ERROR1; - public const GL.GLenum GLU_TESS_ERROR2; - public const GL.GLenum GLU_TESS_ERROR3; - public const GL.GLenum GLU_TESS_ERROR4; - public const GL.GLenum GLU_TESS_ERROR5; - public const GL.GLenum GLU_TESS_ERROR6; - public const GL.GLenum GLU_TESS_ERROR7; - public const GL.GLenum GLU_TESS_ERROR8; - public const GL.GLenum GLU_TESS_MISSING_BEGIN_POLYGON; - public const GL.GLenum GLU_TESS_MISSING_BEGIN_CONTOUR; - public const GL.GLenum GLU_TESS_MISSING_END_POLYGON; - public const GL.GLenum GLU_TESS_MISSING_END_CONTOUR; - public const GL.GLenum GLU_TESS_COORD_TOO_LARGE; - public const GL.GLenum GLU_TESS_NEED_COMBINE_CALLBACK; - - // TessWinding - public const GL.GLenum GLU_TESS_WINDING_ODD; - public const GL.GLenum GLU_TESS_WINDING_NONZERO; - public const GL.GLenum GLU_TESS_WINDING_POSITIVE; - public const GL.GLenum GLU_TESS_WINDING_NEGATIVE; - public const GL.GLenum GLU_TESS_WINDING_ABS_GEQ_TWO; - public const GL.GLenum GLU_TESS_MAX_COORD; - - [CCode (cname="_GLUfuncptr", has_target = false)] - public delegate void GLUfuncptr (); - - [Compact] - [CCode (cname="GLUnurbsObj", cprefix="glu", free_function="gluDeleteNurbsRenderer")] - public class Nurbs - { - [CCode (cname="gluNewNurbsRenderer")] - public Nurbs (); - - public void BeginCurve (); - public void BeginSurface (); - public void BeginTrim (); - public void EndCurve (); - public void EndSurface (); - public void EndTrim (); - public void GetNurbsProperty (GL.GLenum property, out GL.GLfloat data); - public void LoadSamplingMatrices ([CCode (array_length = false)] GL.GLfloat[] model, [CCode (array_length = false)] GL.GLfloat[] perspective, [CCode (array_length = false)] GL.GLint[] view); - public void NurbsCallback (GL.GLenum which, GLUfuncptr CallBackFunc); - public void NurbsCallbackData (GL.GLvoid* userData); - public void NurbsCallbackDataEXT (GL.GLvoid* userData); - public void NurbsCurve (GL.GLint knotCount, [CCode (array_length = false)] GL.GLfloat[] knots, [CCode (array_length = false)] GL.GLint stride, [CCode (array_length = false)] GL.GLfloat[] control, GL.GLint order, GL.GLenum type); - public void NurbsProperty (GL.GLenum property, GL.GLfloat @value); - public void NurbsSurface (GL.GLint sKnotCount, [CCode (array_length = false)] GL.GLfloat[] sKnots, GL.GLint tKnotCount, [CCode (array_length = false)] GL.GLfloat[] tKnots, GL.GLint sStride, GL.GLint tStride, [CCode (array_length = false)] GL.GLfloat[] control, GL.GLint sOrder, GL.GLint tOrder, GL.GLenum type); - public void PwlCurve (GL.GLint count, [CCode (array_length = false)] GL.GLfloat[] data, GL.GLint stride, GL.GLenum type); - } - - [Compact] - [CCode (cname="GLUquadricObj", cprefix="glu", free_function="gluDeleteQuadric")] - public class Quadric - { - [CCode (cname="gluNewQuadric")] - public Quadric (); - - public void Cylinder (GL.GLdouble @base, GL.GLdouble top, GL.GLdouble height, GL.GLint slices, GL.GLint stacks); - public void Disk (GL.GLdouble inner, GL.GLdouble outer, GL.GLint slices, GL.GLint loops); - public void PartialDisk (GL.GLdouble inner, GL.GLdouble outer, GL.GLint slices, GL.GLint loops, GL.GLdouble start, GL.GLdouble sweep); - public void Sphere (GL.GLdouble radius, GL.GLint slices, GL.GLint stacks); - public void QuadricCallback (GL.GLenum which, GLUfuncptr CallBackFunc); - public void QuadricDrawStyle (GL.GLenum draw); - public void QuadricNormals (GL.GLenum normal); - public void QuadricOrientation (GL.GLenum orientation); - public void QuadricTexture (GL.GLboolean texture); - } - - [Compact] - [CCode (cname="GLUtesselatorObj", cprefix="glu", free_function="gluDeleteTess")] - public class Tesselator - { - [CCode (cname="gluNewTess")] - public Tesselator (); - - public void BeginPolygon (); - public void EndPolygon (); - public void GetTessProperty (GL.GLenum which, out GL.GLdouble data); - public void NextContour (GL.GLenum type); - public void TessBeginContour (); - public void TessBeginPolygon (GL.GLvoid* data); - public void TessCallback (GL.GLenum which, GLUfuncptr CallBackFunc); - public void TessEndContour (); - public void TessEndPolygon (); - public void TessNormal (GL.GLdouble valueX, GL.GLdouble valueY, GL.GLdouble valueZ); - public void TessProperty (GL.GLenum which, GL.GLdouble data); - public void TessVertex ([CCode (array_length = false)] GL.GLdouble[] location, GL.GLvoid* data); - } - - - public static GL.GLint gluBuild1DMipmapLevels (GL.GLenum target, GL.GLint internalFormat, GL.GLsizei width, GL.GLenum format, GL.GLenum type, GL.GLint level, GL.GLint @base, GL.GLint max, void* data); - public static GL.GLint gluBuild1DMipmaps (GL.GLenum target, GL.GLint internalFormat, GL.GLsizei width, GL.GLenum format, GL.GLenum type, void* data); - public static GL.GLint gluBuild2DMipmapLevels (GL.GLenum target, GL.GLint internalFormat, GL.GLsizei width, GL.GLsizei height, GL.GLenum format, GL.GLenum type, GL.GLint level, GL.GLint @base, GL.GLint max, void* data); - public static GL.GLint gluBuild2DMipmaps (GL.GLenum target, GL.GLint internalFormat, GL.GLsizei width, GL.GLsizei height, GL.GLenum format, GL.GLenum type, void* data); - public static GL.GLint gluBuild3DMipmapLevels (GL.GLenum target, GL.GLint internalFormat, GL.GLsizei width, GL.GLsizei height, GL.GLsizei depth, GL.GLenum format, GL.GLenum type, GL.GLint level, GL.GLint @base, GL.GLint max, void* data); - public static GL.GLint gluBuild3DMipmaps (GL.GLenum target, GL.GLint internalFormat, GL.GLsizei width, GL.GLsizei height, GL.GLsizei depth, GL.GLenum format, GL.GLenum type, void* data); - public static GL.GLboolean gluCheckExtension (string extName, string extString); - public static unowned string gluErrorString (GL.GLenum error); - public static unowned string gluGetString (GL.GLenum name); - public static void gluLookAt (GL.GLdouble eyeX, GL.GLdouble eyeY, GL.GLdouble eyeZ, GL.GLdouble centerX, GL.GLdouble centerY, GL.GLdouble centerZ, GL.GLdouble upX, GL.GLdouble upY, GL.GLdouble upZ); - public static void gluOrtho2D (GL.GLdouble left, GL.GLdouble right, GL.GLdouble bottom, GL.GLdouble top); - public static void gluPerspective (GL.GLdouble fovy, GL.GLdouble aspect, GL.GLdouble zNear, GL.GLdouble zFar); - public static void gluPickMatrix (GL.GLdouble x, GL.GLdouble y, GL.GLdouble delX, GL.GLdouble delY, [CCode (array_length = false)] GL.GLint[] viewport); - public static GL.GLint gluProject (GL.GLdouble objX, GL.GLdouble objY, GL.GLdouble objZ, [CCode (array_length = false)] GL.GLdouble[] model, [CCode (array_length = false)] GL.GLdouble[] proj, [CCode (array_length = false)] GL.GLint[] view, out GL.GLdouble winX, out GL.GLdouble winY, out GL.GLdouble winZ); - public static GL.GLint gluScaleImage (GL.GLenum format, GL.GLsizei wIn, GL.GLsizei hIn, GL.GLenum typeIn, void* dataIn, GL.GLsizei wOut, GL.GLsizei hOut, GL.GLenum typeOut, GL.GLvoid* dataOut); - public static GL.GLint gluUnProject (GL.GLdouble winX, GL.GLdouble winY, GL.GLdouble winZ, [CCode (array_length = false)] GL.GLdouble[] model, [CCode (array_length = false)] GL.GLdouble[] proj, [CCode (array_length = false)] GL.GLint[] view, out GL.GLdouble objX, out GL.GLdouble objY, out GL.GLdouble objZ); - public static GL.GLint gluUnProject4 (GL.GLdouble winX, GL.GLdouble winY, GL.GLdouble winZ, GL.GLdouble clipW, [CCode (array_length = false)] GL.GLdouble[] model, [CCode (array_length = false)] GL.GLdouble[] proj, [CCode (array_length = false)] GL.GLint[] view, GL.GLdouble nearVal, GL.GLdouble farVal, out GL.GLdouble objX, out GL.GLdouble objY, out GL.GLdouble objZ, out GL.GLdouble objW); - -} -