@ -1,5 +0,0 @@ | |||||
CMakeFiles | |||||
cmake_install.cmake | |||||
CMakeCache.txt | |||||
Makefile | |||||
tags |
@ -1,97 +1,122 @@ | |||||
# Prevent in-source builds | |||||
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) | |||||
message(FATAL_ERROR "In-source builds prohibited. Call cmake from the build directory.") | |||||
endif() | |||||
cmake_minimum_required(VERSION 3.7) | |||||
# Set compiler flags | |||||
if(CMAKE_COMPILER_IS_GNUCC) | |||||
set(CMAKE_CXX_FLAGS "-Wall -Wextra") | |||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -g") | |||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -O3") | |||||
elseif(MSVC) | |||||
set(CMAKE_CXX_FLAGS "/W3 /MP /MD") | |||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS}") | |||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} /Ox") | |||||
endif() | |||||
# Include project macro | |||||
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/project.cmake) | |||||
# Find dependency packages | |||||
find_package(emergent REQUIRED CONFIG) | |||||
find_package(OpenAL REQUIRED CONFIG) | |||||
# Determine dependencies | |||||
set(STATIC_LIBS | |||||
emergent) | |||||
set(SHARED_LIBS | |||||
OpenAL::OpenAL) | |||||
# Generate configuration header file | |||||
configure_file(${PROJECT_SOURCE_DIR}/src/configuration.hpp.in | |||||
${PROJECT_BINARY_DIR}/src/configuration.hpp) | |||||
# Collect source files | |||||
file(GLOB_RECURSE SOURCE_FILES | |||||
${PROJECT_SOURCE_DIR}/src/*.cpp) | |||||
# Make DPI-aware on Windows | |||||
if(MSVC) | |||||
list(APPEND SOURCE_FILES "${PROJECT_SOURCE_DIR}/src/dpi-aware.manifest") | |||||
endif() | |||||
# Add executable target | |||||
set(EXECUTABLE_TARGET ${PROJECT_NAME}-executable) | |||||
add_executable(${EXECUTABLE_TARGET} ${SOURCE_FILES}) | |||||
set_target_properties(${EXECUTABLE_TARGET} PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) | |||||
# Add compile definitions | |||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug") | |||||
target_compile_definitions(${EXECUTABLE_TARGET} PRIVATE DEBUG) | |||||
else() | |||||
target_compile_definitions(${EXECUTABLE_TARGET} PRIVATE NDEBUG) | |||||
endif() | |||||
# Set C++17 standard | |||||
set_target_properties(${EXECUTABLE_TARGET} PROPERTIES | |||||
CXX_STANDARD 17 | |||||
CXX_EXTENSIONS OFF) | |||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") | |||||
set_target_properties(${EXECUTABLE_TARGET} PROPERTIES COMPILE_FLAGS "-std=c++17") | |||||
elseif(MSVC) | |||||
set_target_properties(${EXECUTABLE_TARGET} PROPERTIES COMPILE_FLAGS "/std:c++17") | |||||
endif() | |||||
# Set link flags to show console window on debug builds and hide it on release builds | |||||
if(MSVC) | |||||
set_target_properties(${EXECUTABLE_TARGET} PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE") | |||||
set_target_properties(${EXECUTABLE_TARGET} PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS /ENTRY:\"mainCRTStartup\"") | |||||
endif(MSVC) | |||||
# Set include directories | |||||
target_include_directories(${EXECUTABLE_TARGET} | |||||
PUBLIC | |||||
${PROJECT_SOURCE_DIR}/src | |||||
${PROJECT_BINARY_DIR}/src) | |||||
# Link to dependencies | |||||
target_link_libraries(${EXECUTABLE_TARGET} ${STATIC_LIBS} ${SHARED_LIBS}) | |||||
# Install executable | |||||
if(PACKAGE_PLATFORM MATCHES "linux") | |||||
install(TARGETS ${EXECUTABLE_TARGET} DESTINATION bin) | |||||
elseif(PACKAGE_PLATFORM MATCHES "win") | |||||
# Install executable | |||||
install(TARGETS ${EXECUTABLE_TARGET} DESTINATION .) | |||||
# Install OpenAL DLL | |||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug") | |||||
get_target_property(OPENAL_DLL OpenAL::OpenAL IMPORTED_LOCATION_DEBUG) | |||||
else() | |||||
get_target_property(OPENAL_DLL OpenAL::OpenAL IMPORTED_LOCATION_RELEASE) | |||||
endif() | |||||
install(FILES ${OPENAL_DLL} DESTINATION .) | |||||
endif() | |||||
# Prevent in-source builds | |||||
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) | |||||
message(FATAL_ERROR "In-source builds prohibited. Call cmake from the build directory.") | |||||
endif() | |||||
cmake_minimum_required(VERSION 3.7) | |||||
# Include project macro | |||||
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/project.cmake) | |||||
# Set compiler flags | |||||
if(CMAKE_COMPILER_IS_GNUCC) | |||||
set(CMAKE_CXX_FLAGS "-Wall -Wextra") | |||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -g") | |||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -O3") | |||||
elseif(MSVC) | |||||
set(CMAKE_CXX_FLAGS "/W3 /MP /MD") | |||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS}") | |||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} /Ox") | |||||
endif() | |||||
# Find dependency packages | |||||
find_package(vmq REQUIRED CONFIG) | |||||
find_package(EnTT REQUIRED CONFIG) | |||||
find_package(OpenGL REQUIRED) | |||||
find_package(SDL2 REQUIRED COMPONENTS SDL2::SDL2-static SDL2::SDL2main CONFIG) | |||||
find_package(OpenAL REQUIRED CONFIG) | |||||
# Determine dependencies | |||||
set(STATIC_LIBS | |||||
vmq | |||||
EnTT | |||||
SDL2::SDL2main) | |||||
set(SHARED_LIBS | |||||
${OPENGL_gl_LIBRARY} | |||||
SDL2::SDL2 | |||||
OpenAL::OpenAL) | |||||
# Generate configuration header file | |||||
configure_file(${PROJECT_SOURCE_DIR}/src/antkeeper/configuration.hpp.in | |||||
${PROJECT_BINARY_DIR}/src/antkeeper/configuration.hpp) | |||||
# Collect source files | |||||
file(GLOB_RECURSE SOURCE_FILES | |||||
${PROJECT_SOURCE_DIR}/src/*.cpp | |||||
${PROJECT_SOURCE_DIR}/src/*.c) | |||||
if(MSVC) | |||||
# Generate Windows icon resource file | |||||
set(ICON_FILE "${PROJECT_SOURCE_DIR}/../antkeeper-data/src/icons/antkeeper.ico") | |||||
configure_file(${PROJECT_SOURCE_DIR}/src/antkeeper/platform/windows/icon.rc.in | |||||
${PROJECT_BINARY_DIR}/src/antkeeper/platform/windows/icon.rc) | |||||
# Add executable icon | |||||
list(APPEND SOURCE_FILES "${PROJECT_BINARY_DIR}/src/antkeeper/platform/windows/icon.rc") | |||||
# Make DPI-aware on Windows | |||||
list(APPEND SOURCE_FILES "${PROJECT_SOURCE_DIR}/src/antkeeper/platform/windows/dpi-aware.manifest") | |||||
endif() | |||||
# Add executable target | |||||
set(EXECUTABLE_TARGET ${PROJECT_NAME}-executable) | |||||
add_executable(${EXECUTABLE_TARGET} ${SOURCE_FILES}) | |||||
set_target_properties(${EXECUTABLE_TARGET} PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) | |||||
# Add compile definitions | |||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug") | |||||
target_compile_definitions(${EXECUTABLE_TARGET} PRIVATE DEBUG) | |||||
else() | |||||
target_compile_definitions(${EXECUTABLE_TARGET} PRIVATE NDEBUG) | |||||
endif() | |||||
# Set C++17 standard | |||||
set_target_properties(${EXECUTABLE_TARGET} PROPERTIES | |||||
CXX_STANDARD 17 | |||||
CXX_EXTENSIONS OFF) | |||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") | |||||
set_target_properties(${EXECUTABLE_TARGET} PROPERTIES COMPILE_FLAGS "-std=c++17") | |||||
elseif(MSVC) | |||||
set_target_properties(${EXECUTABLE_TARGET} PROPERTIES COMPILE_FLAGS "/std:c++17") | |||||
endif() | |||||
# Set link flags to show console window on debug builds and hide it on release builds | |||||
if(MSVC) | |||||
set_target_properties(${EXECUTABLE_TARGET} PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE") | |||||
set_target_properties(${EXECUTABLE_TARGET} PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS /ENTRY:\"mainCRTStartup\"") | |||||
endif(MSVC) | |||||
# Set include directories | |||||
target_include_directories(${EXECUTABLE_TARGET} | |||||
PUBLIC | |||||
${PROJECT_SOURCE_DIR}/src | |||||
${PROJECT_SOURCE_DIR}/src/antkeeper | |||||
${PROJECT_BINARY_DIR}/src/antkeeper) | |||||
# Link to dependencies | |||||
target_link_libraries(${EXECUTABLE_TARGET} ${STATIC_LIBS} ${SHARED_LIBS}) | |||||
# Install executable | |||||
if(PACKAGE_PLATFORM MATCHES "linux") | |||||
install(TARGETS ${EXECUTABLE_TARGET} DESTINATION bin) | |||||
elseif(PACKAGE_PLATFORM MATCHES "win") | |||||
# Install executable | |||||
install(TARGETS ${EXECUTABLE_TARGET} DESTINATION .) | |||||
# Install SDL2 DLLs | |||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug") | |||||
get_target_property(SDL2_DLL SDL2::SDL2 IMPORTED_LOCATION_DEBUG) | |||||
else() | |||||
get_target_property(SDL2_DLL SDL2::SDL2 IMPORTED_LOCATION_RELEASE) | |||||
endif() | |||||
install(FILES ${SDL2_DLL} DESTINATION .) | |||||
# Install OpenAL DLL | |||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug") | |||||
get_target_property(OPENAL_DLL OpenAL::OpenAL IMPORTED_LOCATION_DEBUG) | |||||
else() | |||||
get_target_property(OPENAL_DLL OpenAL::OpenAL IMPORTED_LOCATION_RELEASE) | |||||
endif() | |||||
install(FILES ${OPENAL_DLL} DESTINATION .) | |||||
endif() |
@ -1,674 +0,0 @@ | |||||
GNU GENERAL PUBLIC LICENSE | |||||
Version 3, 29 June 2007 | |||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> | |||||
Everyone is permitted to copy and distribute verbatim copies | |||||
of this license document, but changing it is not allowed. | |||||
Preamble | |||||
The GNU General Public License is a free, copyleft license for | |||||
software and other kinds of works. | |||||
The licenses for most software and other practical works are designed | |||||
to take away your freedom to share and change the works. By contrast, | |||||
the GNU General Public License is intended to guarantee your freedom to | |||||
share and change all versions of a program--to make sure it remains free | |||||
software for all its users. We, the Free Software Foundation, use the | |||||
GNU General Public License for most of our software; it applies also to | |||||
any other work released this way by its authors. You can apply it to | |||||
your programs, too. | |||||
When we speak of free software, we are referring to freedom, not | |||||
price. Our General Public Licenses are designed to make sure that you | |||||
have the freedom to distribute copies of free software (and charge for | |||||
them if you wish), that you receive source code or can get it if you | |||||
want it, that you can change the software or use pieces of it in new | |||||
free programs, and that you know you can do these things. | |||||
To protect your rights, we need to prevent others from denying you | |||||
these rights or asking you to surrender the rights. Therefore, you have | |||||
certain responsibilities if you distribute copies of the software, or if | |||||
you modify it: responsibilities to respect the freedom of others. | |||||
For example, if you distribute copies of such a program, whether | |||||
gratis or for a fee, you must pass on to the recipients the same | |||||
freedoms that you received. You must make sure that they, too, receive | |||||
or can get the source code. And you must show them these terms so they | |||||
know their rights. | |||||
Developers that use the GNU GPL protect your rights with two steps: | |||||
(1) assert copyright on the software, and (2) offer you this License | |||||
giving you legal permission to copy, distribute and/or modify it. | |||||
For the developers' and authors' protection, the GPL clearly explains | |||||
that there is no warranty for this free software. For both users' and | |||||
authors' sake, the GPL requires that modified versions be marked as | |||||
changed, so that their problems will not be attributed erroneously to | |||||
authors of previous versions. | |||||
Some devices are designed to deny users access to install or run | |||||
modified versions of the software inside them, although the manufacturer | |||||
can do so. This is fundamentally incompatible with the aim of | |||||
protecting users' freedom to change the software. The systematic | |||||
pattern of such abuse occurs in the area of products for individuals to | |||||
use, which is precisely where it is most unacceptable. Therefore, we | |||||
have designed this version of the GPL to prohibit the practice for those | |||||
products. If such problems arise substantially in other domains, we | |||||
stand ready to extend this provision to those domains in future versions | |||||
of the GPL, as needed to protect the freedom of users. | |||||
Finally, every program is threatened constantly by software patents. | |||||
States should not allow patents to restrict development and use of | |||||
software on general-purpose computers, but in those that do, we wish to | |||||
avoid the special danger that patents applied to a free program could | |||||
make it effectively proprietary. To prevent this, the GPL assures that | |||||
patents cannot be used to render the program non-free. | |||||
The precise terms and conditions for copying, distribution and | |||||
modification follow. | |||||
TERMS AND CONDITIONS | |||||
0. Definitions. | |||||
"This License" refers to version 3 of the GNU General Public License. | |||||
"Copyright" also means copyright-like laws that apply to other kinds of | |||||
works, such as semiconductor masks. | |||||
"The Program" refers to any copyrightable work licensed under this | |||||
License. Each licensee is addressed as "you". "Licensees" and | |||||
"recipients" may be individuals or organizations. | |||||
To "modify" a work means to copy from or adapt all or part of the work | |||||
in a fashion requiring copyright permission, other than the making of an | |||||
exact copy. The resulting work is called a "modified version" of the | |||||
earlier work or a work "based on" the earlier work. | |||||
A "covered work" means either the unmodified Program or a work based | |||||
on the Program. | |||||
To "propagate" a work means to do anything with it that, without | |||||
permission, would make you directly or secondarily liable for | |||||
infringement under applicable copyright law, except executing it on a | |||||
computer or modifying a private copy. Propagation includes copying, | |||||
distribution (with or without modification), making available to the | |||||
public, and in some countries other activities as well. | |||||
To "convey" a work means any kind of propagation that enables other | |||||
parties to make or receive copies. Mere interaction with a user through | |||||
a computer network, with no transfer of a copy, is not conveying. | |||||
An interactive user interface displays "Appropriate Legal Notices" | |||||
to the extent that it includes a convenient and prominently visible | |||||
feature that (1) displays an appropriate copyright notice, and (2) | |||||
tells the user that there is no warranty for the work (except to the | |||||
extent that warranties are provided), that licensees may convey the | |||||
work under this License, and how to view a copy of this License. If | |||||
the interface presents a list of user commands or options, such as a | |||||
menu, a prominent item in the list meets this criterion. | |||||
1. Source Code. | |||||
The "source code" for a work means the preferred form of the work | |||||
for making modifications to it. "Object code" means any non-source | |||||
form of a work. | |||||
A "Standard Interface" means an interface that either is an official | |||||
standard defined by a recognized standards body, or, in the case of | |||||
interfaces specified for a particular programming language, one that | |||||
is widely used among developers working in that language. | |||||
The "System Libraries" of an executable work include anything, other | |||||
than the work as a whole, that (a) is included in the normal form of | |||||
packaging a Major Component, but which is not part of that Major | |||||
Component, and (b) serves only to enable use of the work with that | |||||
Major Component, or to implement a Standard Interface for which an | |||||
implementation is available to the public in source code form. A | |||||
"Major Component", in this context, means a major essential component | |||||
(kernel, window system, and so on) of the specific operating system | |||||
(if any) on which the executable work runs, or a compiler used to | |||||
produce the work, or an object code interpreter used to run it. | |||||
The "Corresponding Source" for a work in object code form means all | |||||
the source code needed to generate, install, and (for an executable | |||||
work) run the object code and to modify the work, including scripts to | |||||
control those activities. However, it does not include the work's | |||||
System Libraries, or general-purpose tools or generally available free | |||||
programs which are used unmodified in performing those activities but | |||||
which are not part of the work. For example, Corresponding Source | |||||
includes interface definition files associated with source files for | |||||
the work, and the source code for shared libraries and dynamically | |||||
linked subprograms that the work is specifically designed to require, | |||||
such as by intimate data communication or control flow between those | |||||
subprograms and other parts of the work. | |||||
The Corresponding Source need not include anything that users | |||||
can regenerate automatically from other parts of the Corresponding | |||||
Source. | |||||
The Corresponding Source for a work in source code form is that | |||||
same work. | |||||
2. Basic Permissions. | |||||
All rights granted under this License are granted for the term of | |||||
copyright on the Program, and are irrevocable provided the stated | |||||
conditions are met. This License explicitly affirms your unlimited | |||||
permission to run the unmodified Program. The output from running a | |||||
covered work is covered by this License only if the output, given its | |||||
content, constitutes a covered work. This License acknowledges your | |||||
rights of fair use or other equivalent, as provided by copyright law. | |||||
You may make, run and propagate covered works that you do not | |||||
convey, without conditions so long as your license otherwise remains | |||||
in force. You may convey covered works to others for the sole purpose | |||||
of having them make modifications exclusively for you, or provide you | |||||
with facilities for running those works, provided that you comply with | |||||
the terms of this License in conveying all material for which you do | |||||
not control copyright. Those thus making or running the covered works | |||||
for you must do so exclusively on your behalf, under your direction | |||||
and control, on terms that prohibit them from making any copies of | |||||
your copyrighted material outside their relationship with you. | |||||
Conveying under any other circumstances is permitted solely under | |||||
the conditions stated below. Sublicensing is not allowed; section 10 | |||||
makes it unnecessary. | |||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law. | |||||
No covered work shall be deemed part of an effective technological | |||||
measure under any applicable law fulfilling obligations under article | |||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or | |||||
similar laws prohibiting or restricting circumvention of such | |||||
measures. | |||||
When you convey a covered work, you waive any legal power to forbid | |||||
circumvention of technological measures to the extent such circumvention | |||||
is effected by exercising rights under this License with respect to | |||||
the covered work, and you disclaim any intention to limit operation or | |||||
modification of the work as a means of enforcing, against the work's | |||||
users, your or third parties' legal rights to forbid circumvention of | |||||
technological measures. | |||||
4. Conveying Verbatim Copies. | |||||
You may convey verbatim copies of the Program's source code as you | |||||
receive it, in any medium, provided that you conspicuously and | |||||
appropriately publish on each copy an appropriate copyright notice; | |||||
keep intact all notices stating that this License and any | |||||
non-permissive terms added in accord with section 7 apply to the code; | |||||
keep intact all notices of the absence of any warranty; and give all | |||||
recipients a copy of this License along with the Program. | |||||
You may charge any price or no price for each copy that you convey, | |||||
and you may offer support or warranty protection for a fee. | |||||
5. Conveying Modified Source Versions. | |||||
You may convey a work based on the Program, or the modifications to | |||||
produce it from the Program, in the form of source code under the | |||||
terms of section 4, provided that you also meet all of these conditions: | |||||
a) The work must carry prominent notices stating that you modified | |||||
it, and giving a relevant date. | |||||
b) The work must carry prominent notices stating that it is | |||||
released under this License and any conditions added under section | |||||
7. This requirement modifies the requirement in section 4 to | |||||
"keep intact all notices". | |||||
c) You must license the entire work, as a whole, under this | |||||
License to anyone who comes into possession of a copy. This | |||||
License will therefore apply, along with any applicable section 7 | |||||
additional terms, to the whole of the work, and all its parts, | |||||
regardless of how they are packaged. This License gives no | |||||
permission to license the work in any other way, but it does not | |||||
invalidate such permission if you have separately received it. | |||||
d) If the work has interactive user interfaces, each must display | |||||
Appropriate Legal Notices; however, if the Program has interactive | |||||
interfaces that do not display Appropriate Legal Notices, your | |||||
work need not make them do so. | |||||
A compilation of a covered work with other separate and independent | |||||
works, which are not by their nature extensions of the covered work, | |||||
and which are not combined with it such as to form a larger program, | |||||
in or on a volume of a storage or distribution medium, is called an | |||||
"aggregate" if the compilation and its resulting copyright are not | |||||
used to limit the access or legal rights of the compilation's users | |||||
beyond what the individual works permit. Inclusion of a covered work | |||||
in an aggregate does not cause this License to apply to the other | |||||
parts of the aggregate. | |||||
6. Conveying Non-Source Forms. | |||||
You may convey a covered work in object code form under the terms | |||||
of sections 4 and 5, provided that you also convey the | |||||
machine-readable Corresponding Source under the terms of this License, | |||||
in one of these ways: | |||||
a) Convey the object code in, or embodied in, a physical product | |||||
(including a physical distribution medium), accompanied by the | |||||
Corresponding Source fixed on a durable physical medium | |||||
customarily used for software interchange. | |||||
b) Convey the object code in, or embodied in, a physical product | |||||
(including a physical distribution medium), accompanied by a | |||||
written offer, valid for at least three years and valid for as | |||||
long as you offer spare parts or customer support for that product | |||||
model, to give anyone who possesses the object code either (1) a | |||||
copy of the Corresponding Source for all the software in the | |||||
product that is covered by this License, on a durable physical | |||||
medium customarily used for software interchange, for a price no | |||||
more than your reasonable cost of physically performing this | |||||
conveying of source, or (2) access to copy the | |||||
Corresponding Source from a network server at no charge. | |||||
c) Convey individual copies of the object code with a copy of the | |||||
written offer to provide the Corresponding Source. This | |||||
alternative is allowed only occasionally and noncommercially, and | |||||
only if you received the object code with such an offer, in accord | |||||
with subsection 6b. | |||||
d) Convey the object code by offering access from a designated | |||||
place (gratis or for a charge), and offer equivalent access to the | |||||
Corresponding Source in the same way through the same place at no | |||||
further charge. You need not require recipients to copy the | |||||
Corresponding Source along with the object code. If the place to | |||||
copy the object code is a network server, the Corresponding Source | |||||
may be on a different server (operated by you or a third party) | |||||
that supports equivalent copying facilities, provided you maintain | |||||
clear directions next to the object code saying where to find the | |||||
Corresponding Source. Regardless of what server hosts the | |||||
Corresponding Source, you remain obligated to ensure that it is | |||||
available for as long as needed to satisfy these requirements. | |||||
e) Convey the object code using peer-to-peer transmission, provided | |||||
you inform other peers where the object code and Corresponding | |||||
Source of the work are being offered to the general public at no | |||||
charge under subsection 6d. | |||||
A separable portion of the object code, whose source code is excluded | |||||
from the Corresponding Source as a System Library, need not be | |||||
included in conveying the object code work. | |||||
A "User Product" is either (1) a "consumer product", which means any | |||||
tangible personal property which is normally used for personal, family, | |||||
or household purposes, or (2) anything designed or sold for incorporation | |||||
into a dwelling. In determining whether a product is a consumer product, | |||||
doubtful cases shall be resolved in favor of coverage. For a particular | |||||
product received by a particular user, "normally used" refers to a | |||||
typical or common use of that class of product, regardless of the status | |||||
of the particular user or of the way in which the particular user | |||||
actually uses, or expects or is expected to use, the product. A product | |||||
is a consumer product regardless of whether the product has substantial | |||||
commercial, industrial or non-consumer uses, unless such uses represent | |||||
the only significant mode of use of the product. | |||||
"Installation Information" for a User Product means any methods, | |||||
procedures, authorization keys, or other information required to install | |||||
and execute modified versions of a covered work in that User Product from | |||||
a modified version of its Corresponding Source. The information must | |||||
suffice to ensure that the continued functioning of the modified object | |||||
code is in no case prevented or interfered with solely because | |||||
modification has been made. | |||||
If you convey an object code work under this section in, or with, or | |||||
specifically for use in, a User Product, and the conveying occurs as | |||||
part of a transaction in which the right of possession and use of the | |||||
User Product is transferred to the recipient in perpetuity or for a | |||||
fixed term (regardless of how the transaction is characterized), the | |||||
Corresponding Source conveyed under this section must be accompanied | |||||
by the Installation Information. But this requirement does not apply | |||||
if neither you nor any third party retains the ability to install | |||||
modified object code on the User Product (for example, the work has | |||||
been installed in ROM). | |||||
The requirement to provide Installation Information does not include a | |||||
requirement to continue to provide support service, warranty, or updates | |||||
for a work that has been modified or installed by the recipient, or for | |||||
the User Product in which it has been modified or installed. Access to a | |||||
network may be denied when the modification itself materially and | |||||
adversely affects the operation of the network or violates the rules and | |||||
protocols for communication across the network. | |||||
Corresponding Source conveyed, and Installation Information provided, | |||||
in accord with this section must be in a format that is publicly | |||||
documented (and with an implementation available to the public in | |||||
source code form), and must require no special password or key for | |||||
unpacking, reading or copying. | |||||
7. Additional Terms. | |||||
"Additional permissions" are terms that supplement the terms of this | |||||
License by making exceptions from one or more of its conditions. | |||||
Additional permissions that are applicable to the entire Program shall | |||||
be treated as though they were included in this License, to the extent | |||||
that they are valid under applicable law. If additional permissions | |||||
apply only to part of the Program, that part may be used separately | |||||
under those permissions, but the entire Program remains governed by | |||||
this License without regard to the additional permissions. | |||||
When you convey a copy of a covered work, you may at your option | |||||
remove any additional permissions from that copy, or from any part of | |||||
it. (Additional permissions may be written to require their own | |||||
removal in certain cases when you modify the work.) You may place | |||||
additional permissions on material, added by you to a covered work, | |||||
for which you have or can give appropriate copyright permission. | |||||
Notwithstanding any other provision of this License, for material you | |||||
add to a covered work, you may (if authorized by the copyright holders of | |||||
that material) supplement the terms of this License with terms: | |||||
a) Disclaiming warranty or limiting liability differently from the | |||||
terms of sections 15 and 16 of this License; or | |||||
b) Requiring preservation of specified reasonable legal notices or | |||||
author attributions in that material or in the Appropriate Legal | |||||
Notices displayed by works containing it; or | |||||
c) Prohibiting misrepresentation of the origin of that material, or | |||||
requiring that modified versions of such material be marked in | |||||
reasonable ways as different from the original version; or | |||||
d) Limiting the use for publicity purposes of names of licensors or | |||||
authors of the material; or | |||||
e) Declining to grant rights under trademark law for use of some | |||||
trade names, trademarks, or service marks; or | |||||
f) Requiring indemnification of licensors and authors of that | |||||
material by anyone who conveys the material (or modified versions of | |||||
it) with contractual assumptions of liability to the recipient, for | |||||
any liability that these contractual assumptions directly impose on | |||||
those licensors and authors. | |||||
All other non-permissive additional terms are considered "further | |||||
restrictions" within the meaning of section 10. If the Program as you | |||||
received it, or any part of it, contains a notice stating that it is | |||||
governed by this License along with a term that is a further | |||||
restriction, you may remove that term. If a license document contains | |||||
a further restriction but permits relicensing or conveying under this | |||||
License, you may add to a covered work material governed by the terms | |||||
of that license document, provided that the further restriction does | |||||
not survive such relicensing or conveying. | |||||
If you add terms to a covered work in accord with this section, you | |||||
must place, in the relevant source files, a statement of the | |||||
additional terms that apply to those files, or a notice indicating | |||||
where to find the applicable terms. | |||||
Additional terms, permissive or non-permissive, may be stated in the | |||||
form of a separately written license, or stated as exceptions; | |||||
the above requirements apply either way. | |||||
8. Termination. | |||||
You may not propagate or modify a covered work except as expressly | |||||
provided under this License. Any attempt otherwise to propagate or | |||||
modify it is void, and will automatically terminate your rights under | |||||
this License (including any patent licenses granted under the third | |||||
paragraph of section 11). | |||||
However, if you cease all violation of this License, then your | |||||
license from a particular copyright holder is reinstated (a) | |||||
provisionally, unless and until the copyright holder explicitly and | |||||
finally terminates your license, and (b) permanently, if the copyright | |||||
holder fails to notify you of the violation by some reasonable means | |||||
prior to 60 days after the cessation. | |||||
Moreover, your license from a particular copyright holder is | |||||
reinstated permanently if the copyright holder notifies you of the | |||||
violation by some reasonable means, this is the first time you have | |||||
received notice of violation of this License (for any work) from that | |||||
copyright holder, and you cure the violation prior to 30 days after | |||||
your receipt of the notice. | |||||
Termination of your rights under this section does not terminate the | |||||
licenses of parties who have received copies or rights from you under | |||||
this License. If your rights have been terminated and not permanently | |||||
reinstated, you do not qualify to receive new licenses for the same | |||||
material under section 10. | |||||
9. Acceptance Not Required for Having Copies. | |||||
You are not required to accept this License in order to receive or | |||||
run a copy of the Program. Ancillary propagation of a covered work | |||||
occurring solely as a consequence of using peer-to-peer transmission | |||||
to receive a copy likewise does not require acceptance. However, | |||||
nothing other than this License grants you permission to propagate or | |||||
modify any covered work. These actions infringe copyright if you do | |||||
not accept this License. Therefore, by modifying or propagating a | |||||
covered work, you indicate your acceptance of this License to do so. | |||||
10. Automatic Licensing of Downstream Recipients. | |||||
Each time you convey a covered work, the recipient automatically | |||||
receives a license from the original licensors, to run, modify and | |||||
propagate that work, subject to this License. You are not responsible | |||||
for enforcing compliance by third parties with this License. | |||||
An "entity transaction" is a transaction transferring control of an | |||||
organization, or substantially all assets of one, or subdividing an | |||||
organization, or merging organizations. If propagation of a covered | |||||
work results from an entity transaction, each party to that | |||||
transaction who receives a copy of the work also receives whatever | |||||
licenses to the work the party's predecessor in interest had or could | |||||
give under the previous paragraph, plus a right to possession of the | |||||
Corresponding Source of the work from the predecessor in interest, if | |||||
the predecessor has it or can get it with reasonable efforts. | |||||
You may not impose any further restrictions on the exercise of the | |||||
rights granted or affirmed under this License. For example, you may | |||||
not impose a license fee, royalty, or other charge for exercise of | |||||
rights granted under this License, and you may not initiate litigation | |||||
(including a cross-claim or counterclaim in a lawsuit) alleging that | |||||
any patent claim is infringed by making, using, selling, offering for | |||||
sale, or importing the Program or any portion of it. | |||||
11. Patents. | |||||
A "contributor" is a copyright holder who authorizes use under this | |||||
License of the Program or a work on which the Program is based. The | |||||
work thus licensed is called the contributor's "contributor version". | |||||
A contributor's "essential patent claims" are all patent claims | |||||
owned or controlled by the contributor, whether already acquired or | |||||
hereafter acquired, that would be infringed by some manner, permitted | |||||
by this License, of making, using, or selling its contributor version, | |||||
but do not include claims that would be infringed only as a | |||||
consequence of further modification of the contributor version. For | |||||
purposes of this definition, "control" includes the right to grant | |||||
patent sublicenses in a manner consistent with the requirements of | |||||
this License. | |||||
Each contributor grants you a non-exclusive, worldwide, royalty-free | |||||
patent license under the contributor's essential patent claims, to | |||||
make, use, sell, offer for sale, import and otherwise run, modify and | |||||
propagate the contents of its contributor version. | |||||
In the following three paragraphs, a "patent license" is any express | |||||
agreement or commitment, however denominated, not to enforce a patent | |||||
(such as an express permission to practice a patent or covenant not to | |||||
sue for patent infringement). To "grant" such a patent license to a | |||||
party means to make such an agreement or commitment not to enforce a | |||||
patent against the party. | |||||
If you convey a covered work, knowingly relying on a patent license, | |||||
and the Corresponding Source of the work is not available for anyone | |||||
to copy, free of charge and under the terms of this License, through a | |||||
publicly available network server or other readily accessible means, | |||||
then you must either (1) cause the Corresponding Source to be so | |||||
available, or (2) arrange to deprive yourself of the benefit of the | |||||
patent license for this particular work, or (3) arrange, in a manner | |||||
consistent with the requirements of this License, to extend the patent | |||||
license to downstream recipients. "Knowingly relying" means you have | |||||
actual knowledge that, but for the patent license, your conveying the | |||||
covered work in a country, or your recipient's use of the covered work | |||||
in a country, would infringe one or more identifiable patents in that | |||||
country that you have reason to believe are valid. | |||||
If, pursuant to or in connection with a single transaction or | |||||
arrangement, you convey, or propagate by procuring conveyance of, a | |||||
covered work, and grant a patent license to some of the parties | |||||
receiving the covered work authorizing them to use, propagate, modify | |||||
or convey a specific copy of the covered work, then the patent license | |||||
you grant is automatically extended to all recipients of the covered | |||||
work and works based on it. | |||||
A patent license is "discriminatory" if it does not include within | |||||
the scope of its coverage, prohibits the exercise of, or is | |||||
conditioned on the non-exercise of one or more of the rights that are | |||||
specifically granted under this License. You may not convey a covered | |||||
work if you are a party to an arrangement with a third party that is | |||||
in the business of distributing software, under which you make payment | |||||
to the third party based on the extent of your activity of conveying | |||||
the work, and under which the third party grants, to any of the | |||||
parties who would receive the covered work from you, a discriminatory | |||||
patent license (a) in connection with copies of the covered work | |||||
conveyed by you (or copies made from those copies), or (b) primarily | |||||
for and in connection with specific products or compilations that | |||||
contain the covered work, unless you entered into that arrangement, | |||||
or that patent license was granted, prior to 28 March 2007. | |||||
Nothing in this License shall be construed as excluding or limiting | |||||
any implied license or other defenses to infringement that may | |||||
otherwise be available to you under applicable patent law. | |||||
12. No Surrender of Others' Freedom. | |||||
If 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 convey a | |||||
covered work so as to satisfy simultaneously your obligations under this | |||||
License and any other pertinent obligations, then as a consequence you may | |||||
not convey it at all. For example, if you agree to terms that obligate you | |||||
to collect a royalty for further conveying from those to whom you convey | |||||
the Program, the only way you could satisfy both those terms and this | |||||
License would be to refrain entirely from conveying the Program. | |||||
13. Use with the GNU Affero General Public License. | |||||
Notwithstanding any other provision of this License, you have | |||||
permission to link or combine any covered work with a work licensed | |||||
under version 3 of the GNU Affero General Public License into a single | |||||
combined work, and to convey the resulting work. The terms of this | |||||
License will continue to apply to the part which is the covered work, | |||||
but the special requirements of the GNU Affero General Public License, | |||||
section 13, concerning interaction through a network will apply to the | |||||
combination as such. | |||||
14. Revised Versions of this License. | |||||
The Free Software Foundation may publish revised and/or new versions of | |||||
the GNU General Public License from time to time. Such new versions will | |||||
be similar in spirit to the present version, but may differ in detail to | |||||
address new problems or concerns. | |||||
Each version is given a distinguishing version number. If the | |||||
Program specifies that a certain numbered version of the GNU General | |||||
Public License "or any later version" applies to it, you have the | |||||
option of following the terms and conditions either of that numbered | |||||
version or of any later version published by the Free Software | |||||
Foundation. If the Program does not specify a version number of the | |||||
GNU General Public License, you may choose any version ever published | |||||
by the Free Software Foundation. | |||||
If the Program specifies that a proxy can decide which future | |||||
versions of the GNU General Public License can be used, that proxy's | |||||
public statement of acceptance of a version permanently authorizes you | |||||
to choose that version for the Program. | |||||
Later license versions may give you additional or different | |||||
permissions. However, no additional obligations are imposed on any | |||||
author or copyright holder as a result of your choosing to follow a | |||||
later version. | |||||
15. Disclaimer of Warranty. | |||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY | |||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT | |||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY | |||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, | |||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM | |||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF | |||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | |||||
16. Limitation of Liability. | |||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | |||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS | |||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY | |||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE | |||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF | |||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD | |||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), | |||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF | |||||
SUCH DAMAGES. | |||||
17. Interpretation of Sections 15 and 16. | |||||
If the disclaimer of warranty and limitation of liability provided | |||||
above cannot be given local legal effect according to their terms, | |||||
reviewing courts shall apply local law that most closely approximates | |||||
an absolute waiver of all civil liability in connection with the | |||||
Program, unless a warranty or assumption of liability accompanies a | |||||
copy of the Program in return for a fee. | |||||
END OF TERMS AND CONDITIONS | |||||
How to Apply These Terms to Your New Programs | |||||
If you develop a new program, and you want it to be of the greatest | |||||
possible use to the public, the best way to achieve this is to make it | |||||
free software which everyone can redistribute and change under these terms. | |||||
To do so, attach the following notices to the program. It is safest | |||||
to attach them to the start of each source file to most effectively | |||||
state the exclusion of warranty; and each file should have at least | |||||
the "copyright" line and a pointer to where the full notice is found. | |||||
<one line to give the program's name and a brief idea of what it does.> | |||||
Copyright (C) <year> <name of author> | |||||
This program is free software: you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation, either version 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 <http://www.gnu.org/licenses/>. | |||||
Also add information on how to contact you by electronic and paper mail. | |||||
If the program does terminal interaction, make it output a short | |||||
notice like this when it starts in an interactive mode: | |||||
<program> Copyright (C) <year> <name of author> | |||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | |||||
This is free software, and you are welcome to redistribute it | |||||
under certain conditions; type `show c' for details. | |||||
The hypothetical commands `show w' and `show c' should show the appropriate | |||||
parts of the General Public License. Of course, your program's commands | |||||
might be different; for a GUI interface, you would use an "about box". | |||||
You should also get your employer (if you work as a programmer) or school, | |||||
if any, to sign a "copyright disclaimer" for the program, if necessary. | |||||
For more information on this, and how to apply and follow the GNU GPL, see | |||||
<http://www.gnu.org/licenses/>. | |||||
The GNU General Public License does not permit incorporating your program | |||||
into proprietary programs. If your program is a subroutine library, you | |||||
may consider it more useful to permit linking proprietary applications with | |||||
the library. If this is what you want to do, use the GNU Lesser General | |||||
Public License instead of this License. But first, please read | |||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>. |
@ -0,0 +1,675 @@ | |||||
### GNU GENERAL PUBLIC LICENSE | |||||
Version 3, 29 June 2007 | |||||
Copyright (C) 2007 Free Software Foundation, Inc. | |||||
<https://fsf.org/> | |||||
Everyone is permitted to copy and distribute verbatim copies of this | |||||
license document, but changing it is not allowed. | |||||
### Preamble | |||||
The GNU General Public License is a free, copyleft license for | |||||
software and other kinds of works. | |||||
The licenses for most software and other practical works are designed | |||||
to take away your freedom to share and change the works. By contrast, | |||||
the GNU General Public License is intended to guarantee your freedom | |||||
to share and change all versions of a program--to make sure it remains | |||||
free software for all its users. We, the Free Software Foundation, use | |||||
the GNU General Public License for most of our software; it applies | |||||
also to any other work released this way by its authors. You can apply | |||||
it to your programs, too. | |||||
When we speak of free software, we are referring to freedom, not | |||||
price. Our General Public Licenses are designed to make sure that you | |||||
have the freedom to distribute copies of free software (and charge for | |||||
them if you wish), that you receive source code or can get it if you | |||||
want it, that you can change the software or use pieces of it in new | |||||
free programs, and that you know you can do these things. | |||||
To protect your rights, we need to prevent others from denying you | |||||
these rights or asking you to surrender the rights. Therefore, you | |||||
have certain responsibilities if you distribute copies of the | |||||
software, or if you modify it: responsibilities to respect the freedom | |||||
of others. | |||||
For example, if you distribute copies of such a program, whether | |||||
gratis or for a fee, you must pass on to the recipients the same | |||||
freedoms that you received. You must make sure that they, too, receive | |||||
or can get the source code. And you must show them these terms so they | |||||
know their rights. | |||||
Developers that use the GNU GPL protect your rights with two steps: | |||||
(1) assert copyright on the software, and (2) offer you this License | |||||
giving you legal permission to copy, distribute and/or modify it. | |||||
For the developers' and authors' protection, the GPL clearly explains | |||||
that there is no warranty for this free software. For both users' and | |||||
authors' sake, the GPL requires that modified versions be marked as | |||||
changed, so that their problems will not be attributed erroneously to | |||||
authors of previous versions. | |||||
Some devices are designed to deny users access to install or run | |||||
modified versions of the software inside them, although the | |||||
manufacturer can do so. This is fundamentally incompatible with the | |||||
aim of protecting users' freedom to change the software. The | |||||
systematic pattern of such abuse occurs in the area of products for | |||||
individuals to use, which is precisely where it is most unacceptable. | |||||
Therefore, we have designed this version of the GPL to prohibit the | |||||
practice for those products. If such problems arise substantially in | |||||
other domains, we stand ready to extend this provision to those | |||||
domains in future versions of the GPL, as needed to protect the | |||||
freedom of users. | |||||
Finally, every program is threatened constantly by software patents. | |||||
States should not allow patents to restrict development and use of | |||||
software on general-purpose computers, but in those that do, we wish | |||||
to avoid the special danger that patents applied to a free program | |||||
could make it effectively proprietary. To prevent this, the GPL | |||||
assures that patents cannot be used to render the program non-free. | |||||
The precise terms and conditions for copying, distribution and | |||||
modification follow. | |||||
### TERMS AND CONDITIONS | |||||
#### 0. Definitions. | |||||
"This License" refers to version 3 of the GNU General Public License. | |||||
"Copyright" also means copyright-like laws that apply to other kinds | |||||
of works, such as semiconductor masks. | |||||
"The Program" refers to any copyrightable work licensed under this | |||||
License. Each licensee is addressed as "you". "Licensees" and | |||||
"recipients" may be individuals or organizations. | |||||
To "modify" a work means to copy from or adapt all or part of the work | |||||
in a fashion requiring copyright permission, other than the making of | |||||
an exact copy. The resulting work is called a "modified version" of | |||||
the earlier work or a work "based on" the earlier work. | |||||
A "covered work" means either the unmodified Program or a work based | |||||
on the Program. | |||||
To "propagate" a work means to do anything with it that, without | |||||
permission, would make you directly or secondarily liable for | |||||
infringement under applicable copyright law, except executing it on a | |||||
computer or modifying a private copy. Propagation includes copying, | |||||
distribution (with or without modification), making available to the | |||||
public, and in some countries other activities as well. | |||||
To "convey" a work means any kind of propagation that enables other | |||||
parties to make or receive copies. Mere interaction with a user | |||||
through a computer network, with no transfer of a copy, is not | |||||
conveying. | |||||
An interactive user interface displays "Appropriate Legal Notices" to | |||||
the extent that it includes a convenient and prominently visible | |||||
feature that (1) displays an appropriate copyright notice, and (2) | |||||
tells the user that there is no warranty for the work (except to the | |||||
extent that warranties are provided), that licensees may convey the | |||||
work under this License, and how to view a copy of this License. If | |||||
the interface presents a list of user commands or options, such as a | |||||
menu, a prominent item in the list meets this criterion. | |||||
#### 1. Source Code. | |||||
The "source code" for a work means the preferred form of the work for | |||||
making modifications to it. "Object code" means any non-source form of | |||||
a work. | |||||
A "Standard Interface" means an interface that either is an official | |||||
standard defined by a recognized standards body, or, in the case of | |||||
interfaces specified for a particular programming language, one that | |||||
is widely used among developers working in that language. | |||||
The "System Libraries" of an executable work include anything, other | |||||
than the work as a whole, that (a) is included in the normal form of | |||||
packaging a Major Component, but which is not part of that Major | |||||
Component, and (b) serves only to enable use of the work with that | |||||
Major Component, or to implement a Standard Interface for which an | |||||
implementation is available to the public in source code form. A | |||||
"Major Component", in this context, means a major essential component | |||||
(kernel, window system, and so on) of the specific operating system | |||||
(if any) on which the executable work runs, or a compiler used to | |||||
produce the work, or an object code interpreter used to run it. | |||||
The "Corresponding Source" for a work in object code form means all | |||||
the source code needed to generate, install, and (for an executable | |||||
work) run the object code and to modify the work, including scripts to | |||||
control those activities. However, it does not include the work's | |||||
System Libraries, or general-purpose tools or generally available free | |||||
programs which are used unmodified in performing those activities but | |||||
which are not part of the work. For example, Corresponding Source | |||||
includes interface definition files associated with source files for | |||||
the work, and the source code for shared libraries and dynamically | |||||
linked subprograms that the work is specifically designed to require, | |||||
such as by intimate data communication or control flow between those | |||||
subprograms and other parts of the work. | |||||
The Corresponding Source need not include anything that users can | |||||
regenerate automatically from other parts of the Corresponding Source. | |||||
The Corresponding Source for a work in source code form is that same | |||||
work. | |||||
#### 2. Basic Permissions. | |||||
All rights granted under this License are granted for the term of | |||||
copyright on the Program, and are irrevocable provided the stated | |||||
conditions are met. This License explicitly affirms your unlimited | |||||
permission to run the unmodified Program. The output from running a | |||||
covered work is covered by this License only if the output, given its | |||||
content, constitutes a covered work. This License acknowledges your | |||||
rights of fair use or other equivalent, as provided by copyright law. | |||||
You may make, run and propagate covered works that you do not convey, | |||||
without conditions so long as your license otherwise remains in force. | |||||
You may convey covered works to others for the sole purpose of having | |||||
them make modifications exclusively for you, or provide you with | |||||
facilities for running those works, provided that you comply with the | |||||
terms of this License in conveying all material for which you do not | |||||
control copyright. Those thus making or running the covered works for | |||||
you must do so exclusively on your behalf, under your direction and | |||||
control, on terms that prohibit them from making any copies of your | |||||
copyrighted material outside their relationship with you. | |||||
Conveying under any other circumstances is permitted solely under the | |||||
conditions stated below. Sublicensing is not allowed; section 10 makes | |||||
it unnecessary. | |||||
#### 3. Protecting Users' Legal Rights From Anti-Circumvention Law. | |||||
No covered work shall be deemed part of an effective technological | |||||
measure under any applicable law fulfilling obligations under article | |||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or | |||||
similar laws prohibiting or restricting circumvention of such | |||||
measures. | |||||
When you convey a covered work, you waive any legal power to forbid | |||||
circumvention of technological measures to the extent such | |||||
circumvention is effected by exercising rights under this License with | |||||
respect to the covered work, and you disclaim any intention to limit | |||||
operation or modification of the work as a means of enforcing, against | |||||
the work's users, your or third parties' legal rights to forbid | |||||
circumvention of technological measures. | |||||
#### 4. Conveying Verbatim Copies. | |||||
You may convey verbatim copies of the Program's source code as you | |||||
receive it, in any medium, provided that you conspicuously and | |||||
appropriately publish on each copy an appropriate copyright notice; | |||||
keep intact all notices stating that this License and any | |||||
non-permissive terms added in accord with section 7 apply to the code; | |||||
keep intact all notices of the absence of any warranty; and give all | |||||
recipients a copy of this License along with the Program. | |||||
You may charge any price or no price for each copy that you convey, | |||||
and you may offer support or warranty protection for a fee. | |||||
#### 5. Conveying Modified Source Versions. | |||||
You may convey a work based on the Program, or the modifications to | |||||
produce it from the Program, in the form of source code under the | |||||
terms of section 4, provided that you also meet all of these | |||||
conditions: | |||||
- a) The work must carry prominent notices stating that you modified | |||||
it, and giving a relevant date. | |||||
- b) The work must carry prominent notices stating that it is | |||||
released under this License and any conditions added under | |||||
section 7. This requirement modifies the requirement in section 4 | |||||
to "keep intact all notices". | |||||
- c) You must license the entire work, as a whole, under this | |||||
License to anyone who comes into possession of a copy. This | |||||
License will therefore apply, along with any applicable section 7 | |||||
additional terms, to the whole of the work, and all its parts, | |||||
regardless of how they are packaged. This License gives no | |||||
permission to license the work in any other way, but it does not | |||||
invalidate such permission if you have separately received it. | |||||
- d) If the work has interactive user interfaces, each must display | |||||
Appropriate Legal Notices; however, if the Program has interactive | |||||
interfaces that do not display Appropriate Legal Notices, your | |||||
work need not make them do so. | |||||
A compilation of a covered work with other separate and independent | |||||
works, which are not by their nature extensions of the covered work, | |||||
and which are not combined with it such as to form a larger program, | |||||
in or on a volume of a storage or distribution medium, is called an | |||||
"aggregate" if the compilation and its resulting copyright are not | |||||
used to limit the access or legal rights of the compilation's users | |||||
beyond what the individual works permit. Inclusion of a covered work | |||||
in an aggregate does not cause this License to apply to the other | |||||
parts of the aggregate. | |||||
#### 6. Conveying Non-Source Forms. | |||||
You may convey a covered work in object code form under the terms of | |||||
sections 4 and 5, provided that you also convey the machine-readable | |||||
Corresponding Source under the terms of this License, in one of these | |||||
ways: | |||||
- a) Convey the object code in, or embodied in, a physical product | |||||
(including a physical distribution medium), accompanied by the | |||||
Corresponding Source fixed on a durable physical medium | |||||
customarily used for software interchange. | |||||
- b) Convey the object code in, or embodied in, a physical product | |||||
(including a physical distribution medium), accompanied by a | |||||
written offer, valid for at least three years and valid for as | |||||
long as you offer spare parts or customer support for that product | |||||
model, to give anyone who possesses the object code either (1) a | |||||
copy of the Corresponding Source for all the software in the | |||||
product that is covered by this License, on a durable physical | |||||
medium customarily used for software interchange, for a price no | |||||
more than your reasonable cost of physically performing this | |||||
conveying of source, or (2) access to copy the Corresponding | |||||
Source from a network server at no charge. | |||||
- c) Convey individual copies of the object code with a copy of the | |||||
written offer to provide the Corresponding Source. This | |||||
alternative is allowed only occasionally and noncommercially, and | |||||
only if you received the object code with such an offer, in accord | |||||
with subsection 6b. | |||||
- d) Convey the object code by offering access from a designated | |||||
place (gratis or for a charge), and offer equivalent access to the | |||||
Corresponding Source in the same way through the same place at no | |||||
further charge. You need not require recipients to copy the | |||||
Corresponding Source along with the object code. If the place to | |||||
copy the object code is a network server, the Corresponding Source | |||||
may be on a different server (operated by you or a third party) | |||||
that supports equivalent copying facilities, provided you maintain | |||||
clear directions next to the object code saying where to find the | |||||
Corresponding Source. Regardless of what server hosts the | |||||
Corresponding Source, you remain obligated to ensure that it is | |||||
available for as long as needed to satisfy these requirements. | |||||
- e) Convey the object code using peer-to-peer transmission, | |||||
provided you inform other peers where the object code and | |||||
Corresponding Source of the work are being offered to the general | |||||
public at no charge under subsection 6d. | |||||
A separable portion of the object code, whose source code is excluded | |||||
from the Corresponding Source as a System Library, need not be | |||||
included in conveying the object code work. | |||||
A "User Product" is either (1) a "consumer product", which means any | |||||
tangible personal property which is normally used for personal, | |||||
family, or household purposes, or (2) anything designed or sold for | |||||
incorporation into a dwelling. In determining whether a product is a | |||||
consumer product, doubtful cases shall be resolved in favor of | |||||
coverage. For a particular product received by a particular user, | |||||
"normally used" refers to a typical or common use of that class of | |||||
product, regardless of the status of the particular user or of the way | |||||
in which the particular user actually uses, or expects or is expected | |||||
to use, the product. A product is a consumer product regardless of | |||||
whether the product has substantial commercial, industrial or | |||||
non-consumer uses, unless such uses represent the only significant | |||||
mode of use of the product. | |||||
"Installation Information" for a User Product means any methods, | |||||
procedures, authorization keys, or other information required to | |||||
install and execute modified versions of a covered work in that User | |||||
Product from a modified version of its Corresponding Source. The | |||||
information must suffice to ensure that the continued functioning of | |||||
the modified object code is in no case prevented or interfered with | |||||
solely because modification has been made. | |||||
If you convey an object code work under this section in, or with, or | |||||
specifically for use in, a User Product, and the conveying occurs as | |||||
part of a transaction in which the right of possession and use of the | |||||
User Product is transferred to the recipient in perpetuity or for a | |||||
fixed term (regardless of how the transaction is characterized), the | |||||
Corresponding Source conveyed under this section must be accompanied | |||||
by the Installation Information. But this requirement does not apply | |||||
if neither you nor any third party retains the ability to install | |||||
modified object code on the User Product (for example, the work has | |||||
been installed in ROM). | |||||
The requirement to provide Installation Information does not include a | |||||
requirement to continue to provide support service, warranty, or | |||||
updates for a work that has been modified or installed by the | |||||
recipient, or for the User Product in which it has been modified or | |||||
installed. Access to a network may be denied when the modification | |||||
itself materially and adversely affects the operation of the network | |||||
or violates the rules and protocols for communication across the | |||||
network. | |||||
Corresponding Source conveyed, and Installation Information provided, | |||||
in accord with this section must be in a format that is publicly | |||||
documented (and with an implementation available to the public in | |||||
source code form), and must require no special password or key for | |||||
unpacking, reading or copying. | |||||
#### 7. Additional Terms. | |||||
"Additional permissions" are terms that supplement the terms of this | |||||
License by making exceptions from one or more of its conditions. | |||||
Additional permissions that are applicable to the entire Program shall | |||||
be treated as though they were included in this License, to the extent | |||||
that they are valid under applicable law. If additional permissions | |||||
apply only to part of the Program, that part may be used separately | |||||
under those permissions, but the entire Program remains governed by | |||||
this License without regard to the additional permissions. | |||||
When you convey a copy of a covered work, you may at your option | |||||
remove any additional permissions from that copy, or from any part of | |||||
it. (Additional permissions may be written to require their own | |||||
removal in certain cases when you modify the work.) You may place | |||||
additional permissions on material, added by you to a covered work, | |||||
for which you have or can give appropriate copyright permission. | |||||
Notwithstanding any other provision of this License, for material you | |||||
add to a covered work, you may (if authorized by the copyright holders | |||||
of that material) supplement the terms of this License with terms: | |||||
- a) Disclaiming warranty or limiting liability differently from the | |||||
terms of sections 15 and 16 of this License; or | |||||
- b) Requiring preservation of specified reasonable legal notices or | |||||
author attributions in that material or in the Appropriate Legal | |||||
Notices displayed by works containing it; or | |||||
- c) Prohibiting misrepresentation of the origin of that material, | |||||
or requiring that modified versions of such material be marked in | |||||
reasonable ways as different from the original version; or | |||||
- d) Limiting the use for publicity purposes of names of licensors | |||||
or authors of the material; or | |||||
- e) Declining to grant rights under trademark law for use of some | |||||
trade names, trademarks, or service marks; or | |||||
- f) Requiring indemnification of licensors and authors of that | |||||
material by anyone who conveys the material (or modified versions | |||||
of it) with contractual assumptions of liability to the recipient, | |||||
for any liability that these contractual assumptions directly | |||||
impose on those licensors and authors. | |||||
All other non-permissive additional terms are considered "further | |||||
restrictions" within the meaning of section 10. If the Program as you | |||||
received it, or any part of it, contains a notice stating that it is | |||||
governed by this License along with a term that is a further | |||||
restriction, you may remove that term. If a license document contains | |||||
a further restriction but permits relicensing or conveying under this | |||||
License, you may add to a covered work material governed by the terms | |||||
of that license document, provided that the further restriction does | |||||
not survive such relicensing or conveying. | |||||
If you add terms to a covered work in accord with this section, you | |||||
must place, in the relevant source files, a statement of the | |||||
additional terms that apply to those files, or a notice indicating | |||||
where to find the applicable terms. | |||||
Additional terms, permissive or non-permissive, may be stated in the | |||||
form of a separately written license, or stated as exceptions; the | |||||
above requirements apply either way. | |||||
#### 8. Termination. | |||||
You may not propagate or modify a covered work except as expressly | |||||
provided under this License. Any attempt otherwise to propagate or | |||||
modify it is void, and will automatically terminate your rights under | |||||
this License (including any patent licenses granted under the third | |||||
paragraph of section 11). | |||||
However, if you cease all violation of this License, then your license | |||||
from a particular copyright holder is reinstated (a) provisionally, | |||||
unless and until the copyright holder explicitly and finally | |||||
terminates your license, and (b) permanently, if the copyright holder | |||||
fails to notify you of the violation by some reasonable means prior to | |||||
60 days after the cessation. | |||||
Moreover, your license from a particular copyright holder is | |||||
reinstated permanently if the copyright holder notifies you of the | |||||
violation by some reasonable means, this is the first time you have | |||||
received notice of violation of this License (for any work) from that | |||||
copyright holder, and you cure the violation prior to 30 days after | |||||
your receipt of the notice. | |||||
Termination of your rights under this section does not terminate the | |||||
licenses of parties who have received copies or rights from you under | |||||
this License. If your rights have been terminated and not permanently | |||||
reinstated, you do not qualify to receive new licenses for the same | |||||
material under section 10. | |||||
#### 9. Acceptance Not Required for Having Copies. | |||||
You are not required to accept this License in order to receive or run | |||||
a copy of the Program. Ancillary propagation of a covered work | |||||
occurring solely as a consequence of using peer-to-peer transmission | |||||
to receive a copy likewise does not require acceptance. However, | |||||
nothing other than this License grants you permission to propagate or | |||||
modify any covered work. These actions infringe copyright if you do | |||||
not accept this License. Therefore, by modifying or propagating a | |||||
covered work, you indicate your acceptance of this License to do so. | |||||
#### 10. Automatic Licensing of Downstream Recipients. | |||||
Each time you convey a covered work, the recipient automatically | |||||
receives a license from the original licensors, to run, modify and | |||||
propagate that work, subject to this License. You are not responsible | |||||
for enforcing compliance by third parties with this License. | |||||
An "entity transaction" is a transaction transferring control of an | |||||
organization, or substantially all assets of one, or subdividing an | |||||
organization, or merging organizations. If propagation of a covered | |||||
work results from an entity transaction, each party to that | |||||
transaction who receives a copy of the work also receives whatever | |||||
licenses to the work the party's predecessor in interest had or could | |||||
give under the previous paragraph, plus a right to possession of the | |||||
Corresponding Source of the work from the predecessor in interest, if | |||||
the predecessor has it or can get it with reasonable efforts. | |||||
You may not impose any further restrictions on the exercise of the | |||||
rights granted or affirmed under this License. For example, you may | |||||
not impose a license fee, royalty, or other charge for exercise of | |||||
rights granted under this License, and you may not initiate litigation | |||||
(including a cross-claim or counterclaim in a lawsuit) alleging that | |||||
any patent claim is infringed by making, using, selling, offering for | |||||
sale, or importing the Program or any portion of it. | |||||
#### 11. Patents. | |||||
A "contributor" is a copyright holder who authorizes use under this | |||||
License of the Program or a work on which the Program is based. The | |||||
work thus licensed is called the contributor's "contributor version". | |||||
A contributor's "essential patent claims" are all patent claims owned | |||||
or controlled by the contributor, whether already acquired or | |||||
hereafter acquired, that would be infringed by some manner, permitted | |||||
by this License, of making, using, or selling its contributor version, | |||||
but do not include claims that would be infringed only as a | |||||
consequence of further modification of the contributor version. For | |||||
purposes of this definition, "control" includes the right to grant | |||||
patent sublicenses in a manner consistent with the requirements of | |||||
this License. | |||||
Each contributor grants you a non-exclusive, worldwide, royalty-free | |||||
patent license under the contributor's essential patent claims, to | |||||
make, use, sell, offer for sale, import and otherwise run, modify and | |||||
propagate the contents of its contributor version. | |||||
In the following three paragraphs, a "patent license" is any express | |||||
agreement or commitment, however denominated, not to enforce a patent | |||||
(such as an express permission to practice a patent or covenant not to | |||||
sue for patent infringement). To "grant" such a patent license to a | |||||
party means to make such an agreement or commitment not to enforce a | |||||
patent against the party. | |||||
If you convey a covered work, knowingly relying on a patent license, | |||||
and the Corresponding Source of the work is not available for anyone | |||||
to copy, free of charge and under the terms of this License, through a | |||||
publicly available network server or other readily accessible means, | |||||
then you must either (1) cause the Corresponding Source to be so | |||||
available, or (2) arrange to deprive yourself of the benefit of the | |||||
patent license for this particular work, or (3) arrange, in a manner | |||||
consistent with the requirements of this License, to extend the patent | |||||
license to downstream recipients. "Knowingly relying" means you have | |||||
actual knowledge that, but for the patent license, your conveying the | |||||
covered work in a country, or your recipient's use of the covered work | |||||
in a country, would infringe one or more identifiable patents in that | |||||
country that you have reason to believe are valid. | |||||
If, pursuant to or in connection with a single transaction or | |||||
arrangement, you convey, or propagate by procuring conveyance of, a | |||||
covered work, and grant a patent license to some of the parties | |||||
receiving the covered work authorizing them to use, propagate, modify | |||||
or convey a specific copy of the covered work, then the patent license | |||||
you grant is automatically extended to all recipients of the covered | |||||
work and works based on it. | |||||
A patent license is "discriminatory" if it does not include within the | |||||
scope of its coverage, prohibits the exercise of, or is conditioned on | |||||
the non-exercise of one or more of the rights that are specifically | |||||
granted under this License. You may not convey a covered work if you | |||||
are a party to an arrangement with a third party that is in the | |||||
business of distributing software, under which you make payment to the | |||||
third party based on the extent of your activity of conveying the | |||||
work, and under which the third party grants, to any of the parties | |||||
who would receive the covered work from you, a discriminatory patent | |||||
license (a) in connection with copies of the covered work conveyed by | |||||
you (or copies made from those copies), or (b) primarily for and in | |||||
connection with specific products or compilations that contain the | |||||
covered work, unless you entered into that arrangement, or that patent | |||||
license was granted, prior to 28 March 2007. | |||||
Nothing in this License shall be construed as excluding or limiting | |||||
any implied license or other defenses to infringement that may | |||||
otherwise be available to you under applicable patent law. | |||||
#### 12. No Surrender of Others' Freedom. | |||||
If 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 convey a | |||||
covered work so as to satisfy simultaneously your obligations under | |||||
this License and any other pertinent obligations, then as a | |||||
consequence you may not convey it at all. For example, if you agree to | |||||
terms that obligate you to collect a royalty for further conveying | |||||
from those to whom you convey the Program, the only way you could | |||||
satisfy both those terms and this License would be to refrain entirely | |||||
from conveying the Program. | |||||
#### 13. Use with the GNU Affero General Public License. | |||||
Notwithstanding any other provision of this License, you have | |||||
permission to link or combine any covered work with a work licensed | |||||
under version 3 of the GNU Affero General Public License into a single | |||||
combined work, and to convey the resulting work. The terms of this | |||||
License will continue to apply to the part which is the covered work, | |||||
but the special requirements of the GNU Affero General Public License, | |||||
section 13, concerning interaction through a network will apply to the | |||||
combination as such. | |||||
#### 14. Revised Versions of this License. | |||||
The Free Software Foundation may publish revised and/or new versions | |||||
of the GNU General Public License from time to time. Such new versions | |||||
will be similar in spirit to the present version, but may differ in | |||||
detail to address new problems or concerns. | |||||
Each version is given a distinguishing version number. If the Program | |||||
specifies that a certain numbered version of the GNU General Public | |||||
License "or any later version" applies to it, you have the option of | |||||
following the terms and conditions either of that numbered version or | |||||
of any later version published by the Free Software Foundation. If the | |||||
Program does not specify a version number of the GNU General Public | |||||
License, you may choose any version ever published by the Free | |||||
Software Foundation. | |||||
If the Program specifies that a proxy can decide which future versions | |||||
of the GNU General Public License can be used, that proxy's public | |||||
statement of acceptance of a version permanently authorizes you to | |||||
choose that version for the Program. | |||||
Later license versions may give you additional or different | |||||
permissions. However, no additional obligations are imposed on any | |||||
author or copyright holder as a result of your choosing to follow a | |||||
later version. | |||||
#### 15. Disclaimer of Warranty. | |||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY | |||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT | |||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT | |||||
WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT | |||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |||||
A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND | |||||
PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE | |||||
DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR | |||||
CORRECTION. | |||||
#### 16. Limitation of Liability. | |||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | |||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR | |||||
CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | |||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES | |||||
ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT | |||||
NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR | |||||
LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM | |||||
TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER | |||||
PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | |||||
#### 17. Interpretation of Sections 15 and 16. | |||||
If the disclaimer of warranty and limitation of liability provided | |||||
above cannot be given local legal effect according to their terms, | |||||
reviewing courts shall apply local law that most closely approximates | |||||
an absolute waiver of all civil liability in connection with the | |||||
Program, unless a warranty or assumption of liability accompanies a | |||||
copy of the Program in return for a fee. | |||||
END OF TERMS AND CONDITIONS | |||||
### How to Apply These Terms to Your New Programs | |||||
If you develop a new program, and you want it to be of the greatest | |||||
possible use to the public, the best way to achieve this is to make it | |||||
free software which everyone can redistribute and change under these | |||||
terms. | |||||
To do so, attach the following notices to the program. It is safest to | |||||
attach them to the start of each source file to most effectively state | |||||
the exclusion of warranty; and each file should have at least the | |||||
"copyright" line and a pointer to where the full notice is found. | |||||
<one line to give the program's name and a brief idea of what it does.> | |||||
Copyright (C) <year> <name of author> | |||||
This program is free software: you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation, either version 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 <https://www.gnu.org/licenses/>. | |||||
Also add information on how to contact you by electronic and paper | |||||
mail. | |||||
If the program does terminal interaction, make it output a short | |||||
notice like this when it starts in an interactive mode: | |||||
<program> Copyright (C) <year> <name of author> | |||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | |||||
This is free software, and you are welcome to redistribute it | |||||
under certain conditions; type `show c' for details. | |||||
The hypothetical commands \`show w' and \`show c' should show the | |||||
appropriate parts of the General Public License. Of course, your | |||||
program's commands might be different; for a GUI interface, you would | |||||
use an "about box". | |||||
You should also get your employer (if you work as a programmer) or | |||||
school, if any, to sign a "copyright disclaimer" for the program, if | |||||
necessary. For more information on this, and how to apply and follow | |||||
the GNU GPL, see <https://www.gnu.org/licenses/>. | |||||
The GNU General Public License does not permit incorporating your | |||||
program into proprietary programs. If your program is a subroutine | |||||
library, you may consider it more useful to permit linking proprietary | |||||
applications with the library. If this is what you want to do, use the | |||||
GNU Lesser General Public License instead of this License. But first, | |||||
please read <https://www.gnu.org/licenses/why-not-lgpl.html>. |
@ -1,17 +1,54 @@ | |||||
# Antkeeper Source · [![GitHub license](https://img.shields.io/github/license/cjhoward/antkeeper.svg)](https://github.com/cjhoward/antkeeper/blob/master/COPYING) [![GitHub release](https://img.shields.io/github/release/cjhoward/antkeeper.svg)](https://github.com/cjhoward/antkeeper/releases/) | |||||
Antkeeper is an ant colony simulation game for Windows, Mac OS X, and GNU/Linux. This repository contains all of the source code to Antkeeper. The game data, however, is proprietary. You can access the game data by purchasing a copy of Antkeeper at [antkeeper.com](https://antkeeper.com/). | |||||
## License | |||||
The source code for Antkeeper is licensed under the GNU General Public License, version 3. See [`COPYING`](./COPYING) for details. | |||||
### 3rd-Party Software | |||||
| Name | Author(s) | License | Files | | |||||
| :--------------- | :----------- | :-------------------------- | :---- | | |||||
| dr_wav | David Reid | Public Domain | [`dr_wav.h`](./src/dr_libs/dr_wav.h) | | |||||
| Emergent | C. J. Howard | GNU GPL v3.0 | | | |||||
| OpenAL soft | | GNU GPL v2.0 | | | |||||
| stb_image | Sean Barrett | Public Domain / MIT License | [`stb_image.h`](./src/stb/stb_image.h) | | |||||
| stb_image_writer | Sean Barrett | Public Domain / MIT License | [`stb_image_writer.h`](./src/stb/stb_image_writer.h) | | |||||
# Antkeeper Source | |||||
Antkeeper is an ant colony simulation game currently in development for Windows, Mac OS X, and GNU/Linux. This repository contains all of the source code to Antkeeper. | |||||
Head over to [antkeeper.com](https://antkeeper.com/) if you're interested in following the development of the game or purchasing a copy when it's released. Antkeeper is an indie game with a single developer, so feel free to reach out to me personally with any questions, comments, or feedback you may have. | |||||
## Configuration & Building | |||||
CMake is required to configure and build the application. Depending on the target build platform, CMake should be invoked from one of the following directories: | |||||
build/linux32 // 32-bit GNU/Linux application | |||||
build/linux64 // 64-bit GNU/Linux application | |||||
build/win32 // 32-bit Windows application | |||||
build/win64 // 64-bit Windows application | |||||
The following arguments may be passed to CMake during configuration: | |||||
-DCMAKE_BUILD_TYPE // [Debug, Release] | |||||
### GNU/Linux | |||||
Building on GNU/Linux requires CMake, GCC, G++, and GNU Make. Open a terminal in the project root directory and run the following commands: | |||||
cd build/linux64 | |||||
cmake ../.. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=... | |||||
cmake --build . | |||||
### Windows | |||||
Building on Windows requires CMake and Visual Studio. Additionally, [NSIS](http://nsis.sourceforge.net/) is required if you want to build a distributable installer program. In order to correctly build for your target architecture, you must use the `x86 Native Tools Command Prompt` or the `x64 Native Tools Command Prompt` for 32-bit and 64-bit applications, respectively. Then navigate to the project root directory and run the following commands: | |||||
cd build\win64 | |||||
cmake ..\.. -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=... | |||||
cmake --build . | |||||
## License | |||||
Antkeeper source code is licensed under the GNU General Public License, version 3. For more information, see [LICENSE.md](./LICENSE.md). | |||||
### 3rd-Party Software | |||||
| Name | Author(s) | License | File(s) | | |||||
| :------------------------------ | :--------------------- | :-------------------------- | :------------------------------------------------------- | | |||||
| dr_wav | David Reid | Public Domain (Unlicense) | [dr_wav.h](./src/dr_libs/dr_wav.h) | | |||||
| Easing Functions (Equations) | Robert Penner | MIT License | [easings.hpp](./src/antkeeper/animation/easings.hpp) | | |||||
| EnTT | Michele Caini | MIT License | *Not included in repository* | | |||||
| khrplatform.h | The Khronos Group Inc. | MIT License | [khrplatform.h](./src/glad/khrplatform.h) | | |||||
| OpenGL loader generated by glad | David Herberth | Public Domain / WTFPL / CC0 | [glad.h](./src/glad/glad.h), [glad.c](./src/glad/glad.c) | | |||||
| JSON for Modern C++ | Niels Lohmann | MIT License | [json.hpp](./src/nlohmann/json.hpp) | | |||||
| OpenAL Soft | | GNU GPL v2.0 | *Not included in repository* | | |||||
| Simple DirectMedia Layer | Sam Lantinga | zlib License | *Not included in repository* | | |||||
| stb_image | Sean Barrett | Public Domain / MIT License | [stb_image.h](./src/stb/stb_image.h) | | |||||
| stb_image_write | Sean Barrett | Public Domain / MIT License | [stb_image_write.h](./src/stb/stb_image_writer.h) | | |||||
@ -1,2 +1,2 @@ | |||||
* | * | ||||
!.gitignore | |||||
!.gitignore |
@ -1,27 +1,29 @@ | |||||
/* | /* | ||||
* Copyright (C) 2017-2019 Christopher J. Howard | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | * | ||||
* This file is part of Antkeeper Source Code. | |||||
* This file is part of Antkeeper source code. | |||||
* | * | ||||
* Antkeeper Source Code is free software: you can redistribute it and/or modify | |||||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by | ||||
* the Free Software Foundation, either version 3 of the License, or | * the Free Software Foundation, either version 3 of the License, or | ||||
* (at your option) any later version. | * (at your option) any later version. | ||||
* | * | ||||
* Antkeeper Source Code is distributed in the hope that it will be useful, | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
* GNU General Public License for more details. | * GNU General Public License for more details. | ||||
* | * | ||||
* You should have received a copy of the GNU General Public License | * You should have received a copy of the GNU General Public License | ||||
* along with Antkeeper Source Code. If not, see <http://www.gnu.org/licenses/>. | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | */ | ||||
#include "game-state.hpp" | |||||
#include "animation.hpp" | |||||
GameState::GameState(Game* game): | |||||
game(game) | |||||
void animation_base::animate(float dt) | |||||
{} | {} | ||||
GameState::~GameState() | |||||
{} | |||||
void animator::animate(float dt) | |||||
{ | |||||
} | |||||
@ -0,0 +1,64 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_ANIMATION_HPP | |||||
#define ANTKEEPER_ANIMATION_HPP | |||||
#include <functional> | |||||
class animation_base | |||||
{ | |||||
public: | |||||
void animate(float dt); | |||||
}; | |||||
template <typename T> | |||||
class animation: public animation_base | |||||
{ | |||||
public: | |||||
void set_start_callback(std::function<void()> callback); | |||||
void set_end_callback(std::function<void()> callback); | |||||
void set_loop_callback(std::function<void()> callback); | |||||
void set_frame_callback(std::function<void(std::size_t, const T&)> callback); | |||||
private: | |||||
std::function<void()> start_callback; | |||||
std::function<void()> end_callback; | |||||
std::function<void()> loop_callback; | |||||
std::function<void(std::size_t, const T&)> motion_callback; | |||||
}; | |||||
class skeletal_animation: public animation<int> | |||||
{ | |||||
}; | |||||
class animator | |||||
{ | |||||
public: | |||||
/** | |||||
* Progresses all active animations by @p dt. | |||||
* | |||||
* @param dt Delta time by which the animations will be progressed. | |||||
*/ | |||||
void animate(float dt); | |||||
}; | |||||
#endif // ANTKEEPER_ANIMATION_HPP | |||||
@ -0,0 +1,284 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
/* | |||||
* Easing Functions (Equations) | |||||
* | |||||
* Copyright (C) 2001 Robert Penner | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions are met: | |||||
* | |||||
* * Redistributions of source code must retain the above copyright notice, this | |||||
* list of conditions and the following disclaimer. | |||||
* | |||||
* * 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. | |||||
* | |||||
* * Neither the name of the author nor the names of contributors may be used to | |||||
* endorse or promote products derived from this software without specific | |||||
* prior written permission. | |||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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. | |||||
*/ | |||||
#ifndef ANTKEEPER_EASINGS_HPP | |||||
#define ANTKEEPER_EASINGS_HPP | |||||
#include <vmq/vmq.hpp> | |||||
#include <cmath> | |||||
template <typename T> | |||||
inline T ease_linear(const T& x, const T& y, float a) | |||||
{ | |||||
return (y - x) * a + x; | |||||
} | |||||
template <typename T> | |||||
T ease_in_sine(const T& x, const T& y, float a) | |||||
{ | |||||
return -(y - x) * std::cos(a * vmq::half_pi<float>) + (y - x) + x; | |||||
} | |||||
template <typename T> | |||||
T ease_out_sine(const T& x, const T& y, float a) | |||||
{ | |||||
return (y - x) * std::sin(a * vmq::half_pi<float>) + x; | |||||
} | |||||
template <typename T> | |||||
T ease_in_out_sine(const T& x, const T& y, float a) | |||||
{ | |||||
return -(y - x) * 0.5f * (std::cos(vmq::pi<float> * a) - 1.0f) + x; | |||||
} | |||||
template <typename T> | |||||
T ease_in_quad(const T& x, const T& y, float a) | |||||
{ | |||||
return (y - x) * a * a + x; | |||||
} | |||||
template <typename T> | |||||
T ease_out_quad(const T& x, const T& y, float a) | |||||
{ | |||||
return -(y - x) * a * (a - 2.0f) + x; | |||||
} | |||||
template <typename T> | |||||
T ease_in_out_quad(const T& x, const T& y, float a) | |||||
{ | |||||
a *= 2.0f; | |||||
if (a < 1.0f) | |||||
{ | |||||
return (y - x) * 0.5f * a * a + x; | |||||
} | |||||
a -= 1.0f; | |||||
return -(y - x) * 0.5f * (a * (a - 2.0f) - 1.0f) + x; | |||||
} | |||||
template <typename T> | |||||
T ease_in_cubic(const T& x, const T& y, float a) | |||||
{ | |||||
return (y - x) * a * a * a + x; | |||||
} | |||||
template <typename T> | |||||
T ease_out_cubic(const T& x, const T& y, float a) | |||||
{ | |||||
a -= 1.0f; | |||||
return (y - x) * (a * a * a + 1.0f) + x; | |||||
} | |||||
template <typename T> | |||||
T ease_in_out_cubic(const T& x, const T& y, float a) | |||||
{ | |||||
a *= 2.0f; | |||||
if (a < 1.0f) | |||||
{ | |||||
return (y - x) * 0.5f * a * a * a + x; | |||||
} | |||||
a -= 2.0f; | |||||
return (y - x) * 0.5f * (a * a * a + 2.0f) + x; | |||||
} | |||||
template <typename T> | |||||
T ease_in_quart(const T& x, const T& y, float a) | |||||
{ | |||||
return (y - x) * a * a * a * a + x; | |||||
} | |||||
template <typename T> | |||||
T ease_out_quart(const T& x, const T& y, float a) | |||||
{ | |||||
a -= 1.0f; | |||||
return -(y - x) * (a * a * a * a - 1.0f) + x; | |||||
} | |||||
template <typename T> | |||||
T ease_in_out_quart(const T& x, const T& y, float a) | |||||
{ | |||||
a *= 2.0f; | |||||
if (a < 1.0f) | |||||
{ | |||||
return (y - x) * 0.5f * a * a * a * a + x; | |||||
} | |||||
a -= 2.0f; | |||||
return -(y - x) * 0.5f * (a * a * a * a - 2.0f) + x; | |||||
} | |||||
template <typename T> | |||||
T ease_in_quint(const T& x, const T& y, float a) | |||||
{ | |||||
return (y - x) * a * a * a * a * a + x; | |||||
} | |||||
template <typename T> | |||||
T ease_out_quint(const T& x, const T& y, float a) | |||||
{ | |||||
a -= 1.0f; | |||||
return (y - x) * (a * a * a * a * a + 1.0f) + x; | |||||
} | |||||
template <typename T> | |||||
T ease_in_out_quint(const T& x, const T& y, float a) | |||||
{ | |||||
a *= 2.0f; | |||||
if (a < 1.0f) | |||||
{ | |||||
return (y - x) * 0.5f * a * a * a * a * a + x; | |||||
} | |||||
a -= 2.0f; | |||||
return (y - x) * 0.5f * (a * a * a * a * a + 2.0f) + x; | |||||
} | |||||
template <typename T> | |||||
T ease_in_expo(const T& x, const T& y, float a) | |||||
{ | |||||
if (a == 0.0f) | |||||
{ | |||||
return x; | |||||
} | |||||
return (y - x) * std::pow(2.0f, 10.0f * (a - 1.0f)) + x; | |||||
} | |||||
template <typename T> | |||||
T ease_out_expo(const T& x, const T& y, float a) | |||||
{ | |||||
if (a == 1.0f) | |||||
{ | |||||
return y; | |||||
} | |||||
return (y - x) * (-std::pow(2.0f, -10.0f * a) + 1.0f) + x; | |||||
} | |||||
template <typename T> | |||||
T ease_in_out_expo(const T& x, const T& y, float a) | |||||
{ | |||||
if (a == 0.0f) | |||||
{ | |||||
return x; | |||||
} | |||||
else if (a == 1.0f) | |||||
{ | |||||
return y; | |||||
} | |||||
a *= 2.0f; | |||||
if (a < 1.0f) | |||||
{ | |||||
return (y - x) * 0.5f * std::pow(2.0f, 10.0f * (a - 1.0f)) + x; | |||||
} | |||||
a -= 1.0f; | |||||
return (y - x) * 0.5f * (-std::pow(2.0f, -10.0f * a) + 2.0f) + x; | |||||
} | |||||
template <typename T> | |||||
T ease_in_circ(const T& x, const T& y, float a) | |||||
{ | |||||
return -(y - x) * (std::sqrt(1.0f - a * a) - 1.0f) + x; | |||||
} | |||||
template <typename T> | |||||
T ease_out_circ(const T& x, const T& y, float a) | |||||
{ | |||||
a -= 1.0f; | |||||
return (y - x) * std::sqrt(1.0f - a * a) + x; | |||||
} | |||||
template <typename T> | |||||
T ease_in_out_circ(const T& x, const T& y, float a) | |||||
{ | |||||
a *= 2.0f; | |||||
if (a < 1.0f) | |||||
{ | |||||
return -(y - x) * 0.5f * (std::sqrt(1.0f - a * a) - 1.0f) + x; | |||||
} | |||||
a -= 2.0f; | |||||
return (y - x) * 0.5f * (std::sqrt(1.0f - a * a) + 1.0f) + x; | |||||
} | |||||
template <typename T> | |||||
T ease_in_back(const T& x, const T& y, float a) | |||||
{ | |||||
const float s = 1.70158f; | |||||
return (y - x) * a * a * ((s + 1.0f) * a - s) + x; | |||||
} | |||||
template <typename T> | |||||
T ease_out_back(const T& x, const T& y, float a) | |||||
{ | |||||
const float s = 1.70158f; | |||||
a -= 1.0f; | |||||
return (y - x) * (a * a * ((s + 1.0f) * a + s) + 1.0f) + x; | |||||
} | |||||
template <typename T> | |||||
T ease_in_out_back(const T& x, const T& y, float a) | |||||
{ | |||||
const float s = 1.70158f * 1.525f; | |||||
a *= 2.0f; | |||||
if (a < 1.0f) | |||||
{ | |||||
return (y - x) * 0.5f * (a * a * ((s + 1.0f) * a - s)) + x; | |||||
} | |||||
a -= 2.0f; | |||||
return (y - x) * 0.5f * (a * a * ((s + 1.0f) * a + s) + 2.0f) + x; | |||||
} | |||||
#endif // ANTKEEPER_EASINGS_HPP |
@ -0,0 +1,112 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "timeline.hpp" | |||||
auto cue_compare = [](const cue& a, const cue& b) | |||||
{ | |||||
return std::get<0>(a) < std::get<0>(b); | |||||
}; | |||||
timeline::timeline(): | |||||
cues(cue_compare), | |||||
position(0.0f), | |||||
autoremove(false) | |||||
{} | |||||
void timeline::advance(float dt) | |||||
{ | |||||
auto lower_bound = cues.lower_bound({position, nullptr}); | |||||
auto upper_bound = cues.upper_bound({position + dt, nullptr}); | |||||
for (auto iterator = lower_bound; iterator != upper_bound; ++iterator) | |||||
{ | |||||
std::get<1>(*iterator)(); | |||||
} | |||||
if (autoremove && lower_bound != upper_bound) | |||||
{ | |||||
cues.erase(lower_bound, upper_bound); | |||||
} | |||||
position += dt; | |||||
} | |||||
void timeline::seek(float t) | |||||
{ | |||||
position = t; | |||||
} | |||||
void timeline::add_cue(const cue& c) | |||||
{ | |||||
cues.emplace(c); | |||||
} | |||||
void timeline::remove_cue(const cue& c) | |||||
{ | |||||
cues.erase(c); | |||||
} | |||||
void timeline::remove_cues(float start, float end) | |||||
{ | |||||
auto lower_bound = cues.lower_bound({start, nullptr}); | |||||
auto upper_bound = cues.upper_bound({end, nullptr}); | |||||
cues.erase(lower_bound, upper_bound); | |||||
} | |||||
void timeline::add_sequence(const sequence& s) | |||||
{ | |||||
for (const cue& c: s) | |||||
{ | |||||
add_cue(c); | |||||
} | |||||
} | |||||
void timeline::remove_sequence(const sequence& s) | |||||
{ | |||||
for (const cue& c: s) | |||||
{ | |||||
remove_cue(c); | |||||
} | |||||
} | |||||
void timeline::clear() | |||||
{ | |||||
cues.clear(); | |||||
} | |||||
void timeline::set_autoremove(bool enabled) | |||||
{ | |||||
autoremove = enabled; | |||||
} | |||||
sequence timeline::get_cues(float start, float end) | |||||
{ | |||||
sequence s; | |||||
auto lower_bound = cues.lower_bound({start, nullptr}); | |||||
auto upper_bound = cues.upper_bound({end, nullptr}); | |||||
for (auto iterator = lower_bound; iterator != upper_bound; ++iterator) | |||||
{ | |||||
s.push_back(*iterator); | |||||
} | |||||
return s; | |||||
} | |||||
@ -0,0 +1,136 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_TIMELINE_HPP | |||||
#define ANTKEEPER_TIMELINE_HPP | |||||
#include <functional> | |||||
#include <set> | |||||
#include <tuple> | |||||
/** | |||||
* Scheduled function consisting of a time and function object. | |||||
*/ | |||||
typedef std::tuple<float, std::function<void()>> cue; | |||||
/** | |||||
* List of cues. | |||||
*/ | |||||
typedef std::list<cue> sequence; | |||||
/** | |||||
* Timeline which executes cues (scheduled functions) when advanced over their respective positions in time. | |||||
*/ | |||||
class timeline | |||||
{ | |||||
public: | |||||
/** | |||||
* Creates a timeline. | |||||
*/ | |||||
timeline(); | |||||
/** | |||||
* Advances the timeline position (t) by @p dt, triggering any cues scheduled between `t` and `dt`. If autoremove is enabled, triggered cues will be removed. | |||||
* | |||||
* @param dt Delta time by which the timeline position will be advanced. | |||||
*/ | |||||
void advance(float dt); | |||||
/** | |||||
* Sets the timeline position to @p t. | |||||
* | |||||
* @param t Position in time to which the timeline position will be set. | |||||
*/ | |||||
void seek(float t); | |||||
/** | |||||
* Adds a cue to the timeline. | |||||
* | |||||
* @param c Cue to add. | |||||
*/ | |||||
void add_cue(const cue& c); | |||||
/** | |||||
* Removes a cue from the timeline. If there are multiple identical cues (same time and function), they will all be removed. | |||||
* | |||||
* @param c Cue to remove. | |||||
*/ | |||||
void remove_cue(const cue& c); | |||||
/** | |||||
* Removes all cues on `[start, end)`. | |||||
* | |||||
* @param start Starting position in time (inclusive). | |||||
* @param end Ending position in time (non-inclusive). | |||||
*/ | |||||
void remove_cues(float start, float end); | |||||
/** | |||||
* Adds a sequence of cues to the timeline. | |||||
* | |||||
* @param s Sequence of cues to add. | |||||
*/ | |||||
void add_sequence(const sequence& s); | |||||
/** | |||||
* Removes a sequence of cues from the timeline. | |||||
* | |||||
* @param s Sequence of cues to remove. | |||||
*/ | |||||
void remove_sequence(const sequence& s); | |||||
/** | |||||
* Removes all cues from the timeline. | |||||
*/ | |||||
void clear(); | |||||
/** | |||||
* If enabled, cues will be automatically removed from the timeline when they are triggered. | |||||
* | |||||
* @param enabled Whether to enable autoremove. | |||||
*/ | |||||
void set_autoremove(bool enabled); | |||||
/** | |||||
* Returns the current position in time on the timeline. | |||||
*/ | |||||
float get_position() const; | |||||
/** | |||||
* Returns all the cues on `[start, end)`. | |||||
* | |||||
* @param start Starting position in time (inclusive). | |||||
* @param end Ending position in time (non-inclusive). | |||||
* @return All cues on `[start, end)`. | |||||
*/ | |||||
sequence get_cues(float start, float end); | |||||
private: | |||||
std::multiset<cue, std::function<bool(const cue&, const cue&)>> cues; | |||||
float position; | |||||
bool autoremove; | |||||
}; | |||||
inline float timeline::get_position() const | |||||
{ | |||||
return position; | |||||
} | |||||
#endif // ANTKEEPER_TIMELINE_HPP | |||||
@ -0,0 +1,177 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_TWEEN_HPP | |||||
#define ANTKEEPER_TWEEN_HPP | |||||
#include <algorithm> | |||||
#include <functional> | |||||
#include <type_traits> | |||||
/** | |||||
* Linearly interpolates between two values. | |||||
* | |||||
* @param x Start of the range in which to interpolate. | |||||
* @param y End of the range in which to interpolate. | |||||
* @param a Value used to interpolate between @p x and @p y. | |||||
* @return Interpolated value. | |||||
*/ | |||||
template <class T> | |||||
T tween_default_lerp(const T& x, const T& y, float a); | |||||
/** | |||||
* Container which stores two states along with an interpolator, for quick and easy tweening. | |||||
* | |||||
* @tparam T Value type. | |||||
* @tparam Interpolator Interpolator function or function object type. | |||||
*/ | |||||
template <class T, class Interpolator = typename std::function<std::remove_pointer<T>::type(const T&, const T&, float)>> | |||||
class tween | |||||
{ | |||||
public: | |||||
typedef typename std::remove_pointer<T>::type value_type; | |||||
typedef typename std::decay<Interpolator>::type interpolator_type; | |||||
/** | |||||
* Creates a tween. | |||||
* | |||||
* @param state0 Initial value of state 0. | |||||
* @param state1 Initial value of state 1. | |||||
* @param interpolator Function or function object that will be used to interpolate between states 0 and 1. | |||||
*/ | |||||
explicit tween(const T& state0, const T& state1, const interpolator_type& interpolator = tween_default_lerp<T>); | |||||
/** | |||||
* Creates a tween. | |||||
* | |||||
* @param value Initial value of states 0 and 1. | |||||
* @param interpolator Function or function object that will be used to interpolate between states 0 and 1. | |||||
*/ | |||||
explicit tween(const T& value, const interpolator_type& interpolator = tween_default_lerp<T>); | |||||
/** | |||||
* Creates a tween. | |||||
* | |||||
* @param interpolator Function or function object that will be used to interpolate between states 0 and 1. | |||||
*/ | |||||
explicit tween(const interpolator_type& interpolator = tween_default_lerp<T>); | |||||
/** | |||||
* Returns a reference to the specified tween state. | |||||
* | |||||
* @param state Index of a tween state. Should be either `0` or `1`. | |||||
* @return Reference to the specified tween state. | |||||
*/ | |||||
const T& operator[](int state) const; | |||||
/// @copydoc tween::operator[](int) const | |||||
T& operator[](int state); | |||||
/** | |||||
* Returns an interpolated state between state 0 and state 1. | |||||
* | |||||
* @param a Interpolation factor. Should be on `[0.0, 1.0]`. | |||||
* @return Interpolated state. | |||||
*/ | |||||
value_type interpolate(float a) const; | |||||
/** | |||||
* Returns the function or function object that is used to interpolate between states 0 and 1. | |||||
*/ | |||||
const interpolator_type& get_interpolator() const; | |||||
/** | |||||
* Sets state 0 = state 1. | |||||
*/ | |||||
void update(); | |||||
/** | |||||
* Swaps state 0 and state 1. | |||||
*/ | |||||
void swap(); | |||||
private: | |||||
interpolator_type interpolator; | |||||
T state0; | |||||
T state1; | |||||
}; | |||||
template <class T> | |||||
inline T tween_default_lerp(const T& x, const T& y, float a) | |||||
{ | |||||
return x * (1.0f - a) + y * a; | |||||
} | |||||
template <class T, class Interpolator> | |||||
tween<T, Interpolator>::tween(const T& value, const interpolator_type& interpolator): | |||||
interpolator(interpolator), | |||||
state0(value), | |||||
state1(value) | |||||
{} | |||||
template <class T, class Interpolator> | |||||
tween<T, Interpolator>::tween(const T& state0, const T& state1, const interpolator_type& interpolator): | |||||
interpolator(interpolator), | |||||
state0(state0), | |||||
state1(state1) | |||||
{} | |||||
template <class T, class Interpolator> | |||||
tween<T, Interpolator>::tween(const interpolator_type& interpolator): | |||||
interpolator(interpolator) | |||||
{} | |||||
template <class T, class Interpolator> | |||||
inline const T& tween<T, Interpolator>::operator[](int state) const | |||||
{ | |||||
return (state <= 0) ? state0 : state1; | |||||
} | |||||
template <class T, class Interpolator> | |||||
inline T& tween<T, Interpolator>::operator[](int state) | |||||
{ | |||||
return (state <= 0) ? state0 : state1; | |||||
} | |||||
template <class T, class Interpolator> | |||||
inline typename tween<T, Interpolator>::value_type tween<T, Interpolator>::interpolate(float a) const | |||||
{ | |||||
return interpolator(state0, state1, a); | |||||
} | |||||
template <class T, class Interpolator> | |||||
inline const typename tween<T, Interpolator>::interpolator_type& tween<T, Interpolator>::get_interpolator() const | |||||
{ | |||||
return interpolator; | |||||
} | |||||
template <class T, class Interpolator> | |||||
inline void tween<T, Interpolator>::update() | |||||
{ | |||||
state0 = state1; | |||||
} | |||||
template <class T, class Interpolator> | |||||
inline void tween<T, Interpolator>::swap() | |||||
{ | |||||
std::swap(state0, state1); | |||||
} | |||||
#endif // ANTKEEPER_TWEEN_HPP | |||||
@ -0,0 +1,386 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_APPLICATION_HPP | |||||
#define ANTKEEPER_APPLICATION_HPP | |||||
// STL | |||||
#include <fstream> | |||||
#include <functional> | |||||
#include <list> | |||||
#include <map> | |||||
#include <string> | |||||
// External | |||||
#include <entt/entt.hpp> | |||||
// Debug | |||||
#include "debug/logger.hpp" | |||||
#include "debug/performance-sampler.hpp" | |||||
// Input | |||||
#include "input/control.hpp" | |||||
#include "input/control-set.hpp" | |||||
#include "input/keyboard.hpp" | |||||
#include "input/mouse.hpp" | |||||
#include "input/game-controller.hpp" | |||||
#include "input/input-event-router.hpp" | |||||
#include "input/input-mapper.hpp" | |||||
// Event | |||||
#include "event/event-dispatcher.hpp" | |||||
// Renderer | |||||
#include "renderer/compositor.hpp" | |||||
#include "renderer/renderer.hpp" | |||||
// Scene | |||||
#include "scene/scene.hpp" | |||||
#include "scene/camera.hpp" | |||||
#include "scene/ambient-light.hpp" | |||||
#include "scene/directional-light.hpp" | |||||
#include "scene/point-light.hpp" | |||||
#include "scene/spotlight.hpp" | |||||
#include "scene/model-instance.hpp" | |||||
// Animation | |||||
#include "animation/timeline.hpp" | |||||
#include "animation/animation.hpp" | |||||
#include "animation/tween.hpp" | |||||
// Misc | |||||
#include "state/fsm.hpp" | |||||
#include "frame-scheduler.hpp" | |||||
#include "pheromone-matrix.hpp" | |||||
#include "orbit-cam.hpp" | |||||
// Forward declarations | |||||
//{ | |||||
// SDL | |||||
typedef struct SDL_Window SDL_Window; | |||||
typedef void* SDL_GLContext; | |||||
// Resources | |||||
class resource_manager; | |||||
// Rasterizer | |||||
class rasterizer; | |||||
class framebuffer; | |||||
class vertex_buffer; | |||||
class vertex_array; | |||||
class texture_2d; | |||||
// Renderer | |||||
class clear_pass; | |||||
class shadow_map_pass; | |||||
class material_pass; | |||||
class sky_pass; | |||||
class bloom_pass; | |||||
class final_pass; | |||||
// Systems | |||||
class behavior_system; | |||||
class camera_system; | |||||
class collision_system; | |||||
class locomotion_system; | |||||
class model_system; | |||||
class nest_system; | |||||
class placement_system; | |||||
class samara_system; | |||||
class subterrain_system; | |||||
class terrain_system; | |||||
class vegetation_system; | |||||
class tool_system; | |||||
class control_system; | |||||
class ui_system; | |||||
//} | |||||
class application | |||||
{ | |||||
public: | |||||
/** | |||||
* Creates and initializes an application. | |||||
*/ | |||||
application(int argc, char** argv); | |||||
/** | |||||
* Destroys an application. | |||||
*/ | |||||
~application(); | |||||
/** | |||||
* Executes the application, causing it to enter the execution loop until closed. | |||||
* | |||||
* @return Exit status code. | |||||
*/ | |||||
int execute(); | |||||
/** | |||||
* Requests the application's execution loop to cleanly terminate, and specifies its exit status code. | |||||
* | |||||
* @param status Status to be returned by application::execute() upon execution loop termination. | |||||
*/ | |||||
void close(int status); | |||||
logger* get_logger(); | |||||
resource_manager* get_resource_manager(); | |||||
fsm::machine* get_state_machine(); | |||||
const fsm::state& get_loading_state() const; | |||||
const fsm::state& get_language_select_state() const; | |||||
const fsm::state& get_splash_state() const; | |||||
const fsm::state& get_title_state() const; | |||||
const fsm::state& get_play_state() const; | |||||
const fsm::state& get_pause_state() const; | |||||
timeline* get_timeline(); | |||||
animator* get_animator(); | |||||
camera* get_camera(); | |||||
orbit_cam* get_orbit_cam(); | |||||
control_system* get_control_system(); | |||||
entt::registry& get_ecs_registry(); | |||||
scene& get_scene(); | |||||
void take_screenshot() const; | |||||
private: | |||||
void update(double t, double dt); | |||||
void render(double alpha); | |||||
void translate_sdl_events(); | |||||
void set_relative_mouse_mode(bool enabled); | |||||
void toggle_fullscreen(); | |||||
void window_resized(); | |||||
static void save_image(const std::string& filename, int w, int h, const unsigned char* pixels); | |||||
bool fullscreen; | |||||
std::tuple<int, int> saved_mouse_position; | |||||
std::tuple<int, int> window_dimensions; | |||||
std::tuple<int, int> window_position; | |||||
std::tuple<int, int> display_dimensions; | |||||
float4 viewport; | |||||
// Debugging | |||||
std::ofstream log_filestream; | |||||
logger logger; | |||||
// Paths | |||||
std::string data_path; | |||||
std::string config_path; | |||||
std::string screenshots_path; | |||||
// Resources | |||||
resource_manager* resource_manager; | |||||
SDL_Window* window; | |||||
SDL_GLContext context; | |||||
bool closed; | |||||
int exit_status; | |||||
// Updatable systems | |||||
timeline timeline; | |||||
animator animator; | |||||
std::list<std::function<void(double, double)>> systems; | |||||
int shadow_map_resolution; | |||||
framebuffer* shadow_map_framebuffer; | |||||
texture_2d* shadow_map_depth_texture; | |||||
framebuffer* framebuffer_hdr; | |||||
texture_2d* framebuffer_hdr_color; | |||||
texture_2d* framebuffer_hdr_depth; | |||||
framebuffer* framebuffer_bloom; // General purpose framebuffer A | |||||
texture_2d* bloom_texture; | |||||
// Rendering | |||||
rasterizer* rasterizer; | |||||
material* fallback_material; | |||||
::clear_pass* clear_pass; | |||||
::sky_pass* sky_pass; | |||||
::material_pass* material_pass; | |||||
compositor default_compositor; | |||||
::clear_pass* shadow_map_clear_pass; | |||||
::shadow_map_pass* shadow_map_pass; | |||||
::bloom_pass* bloom_pass; | |||||
::final_pass* final_pass; | |||||
camera default_camera; | |||||
ambient_light sun_indirect; | |||||
directional_light sun_direct; | |||||
point_light subterrain_light; | |||||
ambient_light underworld_ambient_light; | |||||
model_instance darkness_volume; | |||||
model_instance lantern; | |||||
model_instance cloud; | |||||
model_instance* grass_patches; | |||||
::spotlight spotlight; | |||||
vertex_buffer* billboard_vbo; | |||||
vertex_array* billboard_vao; | |||||
::renderer renderer; | |||||
scene overworld_scene; | |||||
scene underworld_scene; | |||||
scene* active_scene; | |||||
// FSM | |||||
fsm::machine state_machine; | |||||
fsm::state loading_state; | |||||
fsm::state language_select_state; | |||||
fsm::state splash_state; | |||||
fsm::state title_state; | |||||
fsm::state play_state; | |||||
fsm::state pause_state; | |||||
// Frame timing | |||||
frame_scheduler frame_scheduler; | |||||
performance_sampler performance_sampler; | |||||
tween<double> time; | |||||
// Events | |||||
event_dispatcher event_dispatcher; | |||||
input_event_router input_event_router; | |||||
input_mapper input_mapper; | |||||
// Input devices | |||||
keyboard keyboard; | |||||
mouse mouse; | |||||
game_controller game_controller; | |||||
// Controls | |||||
control_set menu_controls; | |||||
control menu_back_control; | |||||
control menu_select_control; | |||||
control_set* camera_controls; | |||||
// System controls | |||||
control_set application_controls; | |||||
control toggle_fullscreen_control; | |||||
control screenshot_control; | |||||
control dig_control; | |||||
// Game | |||||
orbit_cam orbit_cam; | |||||
pheromone_matrix pheromones; | |||||
control_system* control_system; | |||||
// ECS | |||||
entt::registry ecs_registry; | |||||
behavior_system* behavior_system; | |||||
camera_system* camera_system; | |||||
collision_system* collision_system; | |||||
locomotion_system* locomotion_system; | |||||
model_system* model_system; | |||||
nest_system* nest_system; | |||||
placement_system* placement_system; | |||||
samara_system* samara_system; | |||||
subterrain_system* subterrain_system; | |||||
terrain_system* terrain_system; | |||||
vegetation_system* vegetation_system; | |||||
tool_system* tool_system; | |||||
// UI | |||||
ui_system* ui_system; | |||||
compositor ui_compositor; | |||||
::clear_pass* ui_clear_pass; | |||||
::material_pass* ui_material_pass; | |||||
// Animation | |||||
tween<float3> focal_point_tween; | |||||
}; | |||||
inline logger* application::get_logger() | |||||
{ | |||||
return &logger; | |||||
} | |||||
inline resource_manager* application::get_resource_manager() | |||||
{ | |||||
return resource_manager; | |||||
} | |||||
inline fsm::machine* application::get_state_machine() | |||||
{ | |||||
return &state_machine; | |||||
} | |||||
inline const fsm::state& application::get_loading_state() const | |||||
{ | |||||
return loading_state; | |||||
} | |||||
inline const fsm::state& application::get_language_select_state() const | |||||
{ | |||||
return language_select_state; | |||||
} | |||||
inline const fsm::state& application::get_splash_state() const | |||||
{ | |||||
return splash_state; | |||||
} | |||||
inline const fsm::state& application::get_title_state() const | |||||
{ | |||||
return title_state; | |||||
} | |||||
inline const fsm::state& application::get_play_state() const | |||||
{ | |||||
return play_state; | |||||
} | |||||
inline const fsm::state& application::get_pause_state() const | |||||
{ | |||||
return pause_state; | |||||
} | |||||
inline timeline* application::get_timeline() | |||||
{ | |||||
return &timeline; | |||||
} | |||||
inline animator* application::get_animator() | |||||
{ | |||||
return &animator; | |||||
} | |||||
inline camera* application::get_camera() | |||||
{ | |||||
return &default_camera; | |||||
} | |||||
inline orbit_cam* application::get_orbit_cam() | |||||
{ | |||||
return &orbit_cam; | |||||
} | |||||
inline control_system* application::get_control_system() | |||||
{ | |||||
return control_system; | |||||
} | |||||
inline entt::registry& application::get_ecs_registry() | |||||
{ | |||||
return ecs_registry; | |||||
} | |||||
inline scene& application::get_scene() | |||||
{ | |||||
return overworld_scene; | |||||
} | |||||
#endif // ANTKEEPER_APPLICATION_HPP | |||||
@ -0,0 +1,193 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_BEHAVIOR_TREE_HPP | |||||
#define ANTKEEPER_BEHAVIOR_TREE_HPP | |||||
#include <functional> | |||||
#include <list> | |||||
namespace behavior_tree { | |||||
/// Behavior tree node return status enumerations. | |||||
enum class status | |||||
{ | |||||
failure, ///< Indicates a node's execution failed. | |||||
success, ///< Indicates a node's execution succeed. | |||||
running ///< Indicates a node's execution has not finished. | |||||
}; | |||||
/** | |||||
* Abstract base class for behavior tree nodes. | |||||
* | |||||
* @tparam T Data type on which nodes operate. | |||||
*/ | |||||
template <class T> | |||||
struct node | |||||
{ | |||||
/// Data type on which nodes operate. | |||||
typedef T context_type; | |||||
/** | |||||
* Executes a node's functionality and returns its status. | |||||
* | |||||
* @param context Context data on which the node will operate. | |||||
*/ | |||||
virtual status execute(context_type& context) const = 0; | |||||
}; | |||||
/// A node with no children. | |||||
template <class T> | |||||
using leaf_node = node<T>; | |||||
/// A node with exactly one child. | |||||
template <class T> | |||||
struct decorator_node: node<T> | |||||
{ | |||||
node* child; | |||||
}; | |||||
/// A node that can have one or more children. | |||||
template <class T> | |||||
struct composite_node: node<T> | |||||
{ | |||||
std::list<node*> children; | |||||
}; | |||||
/// Executes a function on a context and returns the status. | |||||
template <class T> | |||||
struct action: leaf_node<T> | |||||
{ | |||||
virtual status execute(context_type& context) const final; | |||||
typedef std::function<status(context_type&)> function_type; | |||||
function_type function; | |||||
}; | |||||
/// Evaluates a boolean condition (predicate) and returns either `status::success` or `status::failure`. | |||||
template <class T> | |||||
struct condition: leaf_node<T> | |||||
{ | |||||
virtual status execute(context_type& context) const final; | |||||
typedef std::function<status(const context_type&)> predicate_type; | |||||
predicate_type predicate; | |||||
}; | |||||
/// Executes a child node and returns its inverted status. If the child returns `status::success`, then `status::failure` will be returned. Otherwise if the child returns `status::failure`, then `status::success` will be returned. | |||||
template <class T> | |||||
struct inverter: decorator_node<T> | |||||
{ | |||||
virtual status execute(context_type& context) const final; | |||||
}; | |||||
/// Attempts to execute a child node `n` times or until the child fails. | |||||
template <class T> | |||||
struct repeater: decorator_node<T> | |||||
{ | |||||
virtual status execute(context_type& context) const final; | |||||
int n; | |||||
}; | |||||
/// Executes a child node and returns `status::success` regardless of the child node status. | |||||
template <class T> | |||||
struct succeeder: decorator_node<T> | |||||
{ | |||||
virtual status execute(context_type& context) const final; | |||||
}; | |||||
/// Attempts to execute each child node sequentially until one fails. If all children are executed successfully, `status::success` will be returned. Otherwise if any children fail, `status::failure` will be returned. | |||||
template <class T> | |||||
struct sequence: composite_node<T> | |||||
{ | |||||
virtual status execute(context_type& context) const final; | |||||
}; | |||||
/// Attempts to execute each child node sequentially until one succeeds. If a child succeeds, `status::success` will be returned. Otherwise if all children fail, `status::failure` will be returned. | |||||
template <class T> | |||||
struct selector: composite_node<T> | |||||
{ | |||||
virtual status execute(context_type& context) const final; | |||||
}; | |||||
template <class T> | |||||
status action<T>::execute(context_type& context) const | |||||
{ | |||||
return function(context); | |||||
} | |||||
template <class T> | |||||
status condition<T>::execute(context_type& context) const | |||||
{ | |||||
return (predicate(context)) ? status::success : status::failure; | |||||
} | |||||
template <class T> | |||||
status inverter<T>::execute(context_type& context) const | |||||
{ | |||||
status child_status = child->execute(context); | |||||
return (child_status == status::success) ? status::failure : (child_status == status::failure) ? status::success : child_status; | |||||
} | |||||
template <class T> | |||||
status repeater<T>::execute(context_type& context) const | |||||
{ | |||||
status child_status; | |||||
for (int i = 0; i < n; ++i) | |||||
{ | |||||
child_status = child->execute(context); | |||||
if (child_status == status::failure) | |||||
break; | |||||
} | |||||
return child_status; | |||||
} | |||||
template <class T> | |||||
status succeeder<T>::execute(context_type& context) const | |||||
{ | |||||
child->execute(context); | |||||
return status::success; | |||||
} | |||||
template <class T> | |||||
status sequence<T>::execute(context_type& context) const | |||||
{ | |||||
for (const node* child: children) | |||||
{ | |||||
status child_status = child->execute(context); | |||||
if (child_status != status::success) | |||||
return child_status; | |||||
} | |||||
return status::success; | |||||
} | |||||
template <class T> | |||||
status selector<T>::execute(context_type& context) const | |||||
{ | |||||
for (const node* child: children) | |||||
{ | |||||
status child_status = child->execute(context); | |||||
if (child_status != status::failure) | |||||
return child_status; | |||||
} | |||||
return status::failure; | |||||
} | |||||
} // namespace behavior_tree | |||||
#endif // ANTKEEPER_BEHAVIOR_TREE_HPP | |||||
@ -0,0 +1,54 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "behavior/ebt.hpp" | |||||
#include "entity/components/transform-component.hpp" | |||||
#include <iostream> | |||||
using namespace ecs; | |||||
namespace ebt { | |||||
status print(context& context, const std::string& text) | |||||
{ | |||||
std::cout << text; | |||||
return status::success; | |||||
} | |||||
status print_eid(context& context) | |||||
{ | |||||
std::cout << context.entity << std::endl; | |||||
return status::success; | |||||
} | |||||
status warp_to(context& context, float x, float y, float z) | |||||
{ | |||||
auto& transform = context.registry->get<transform_component>(context.entity); | |||||
transform.transform.translation = {x, y, z}; | |||||
transform.warp = true; | |||||
return status::success; | |||||
} | |||||
bool is_carrying_food(const context& context) | |||||
{ | |||||
return false; | |||||
} | |||||
} // namespace ebt | |||||
@ -0,0 +1,66 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_EBT_HPP | |||||
#define ANTKEEPER_EBT_HPP | |||||
#include "behavior/behavior-tree.hpp" | |||||
#include <entt/entt.hpp> | |||||
/// Entity Behavior Tree | |||||
/** | |||||
* The `ebt` namespace defines Entity Behavior Tree (EBT) nodes and an EBT context, on which EBT nodes operate. | |||||
*/ | |||||
namespace ebt { | |||||
/** | |||||
* EBT context which references an entity and its registry. | |||||
*/ | |||||
struct context | |||||
{ | |||||
entt::registry* registry; | |||||
entt::entity entity; | |||||
}; | |||||
typedef behavior_tree::status status; | |||||
typedef behavior_tree::node<context> node; | |||||
typedef behavior_tree::leaf_node<context> leaf_node; | |||||
typedef behavior_tree::decorator_node<context> decorator_node; | |||||
typedef behavior_tree::composite_node<context> composite_node; | |||||
typedef behavior_tree::action<context> action; | |||||
typedef behavior_tree::condition<context> condition; | |||||
typedef behavior_tree::inverter<context> inverter; | |||||
typedef behavior_tree::repeater<context> repeater; | |||||
typedef behavior_tree::succeeder<context> succeeder; | |||||
typedef behavior_tree::sequence<context> sequence; | |||||
typedef behavior_tree::selector<context> selector; | |||||
// Actions | |||||
status print(context& context, const std::string& text); | |||||
status print_eid(context& context); | |||||
status warp_to(context& context, float x, float y, float z); | |||||
// Conditions | |||||
bool is_carrying_food(const context& context); | |||||
} // namespace ebt | |||||
#endif // ANTKEEPER_EBT_HPP | |||||
@ -0,0 +1,65 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "orbit-cam.hpp" | |||||
#include "scene/camera.hpp" | |||||
#include "configuration.hpp" | |||||
#include <algorithm> | |||||
#include <cmath> | |||||
using namespace vmq::operators; | |||||
camera_rig::camera_rig(): | |||||
camera(nullptr), | |||||
translation{0.0f, 0.0f, 0.0f}, | |||||
rotation(vmq::identity_quaternion<float>), | |||||
forward(global_forward), | |||||
right(global_right), | |||||
up(global_up) | |||||
{} | |||||
void camera_rig::attach(::camera* camera) | |||||
{ | |||||
this->camera = camera; | |||||
if (camera != nullptr) | |||||
{ | |||||
camera->look_at(translation, translation + forward, up); | |||||
} | |||||
} | |||||
void camera_rig::detach() | |||||
{ | |||||
camera = nullptr; | |||||
} | |||||
void camera_rig::set_translation(const float3& translation) | |||||
{ | |||||
this->translation = translation; | |||||
} | |||||
void camera_rig::set_rotation(const vmq::quaternion<float>& rotation) | |||||
{ | |||||
this->rotation = rotation; | |||||
// Calculate orthonormal basis | |||||
forward = rotation * global_forward; | |||||
up = rotation * global_up; | |||||
right = rotation * global_right; | |||||
} | |||||
@ -0,0 +1,125 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_CAMERA_RIG_HPP | |||||
#define ANTKEEPER_CAMERA_RIG_HPP | |||||
#include <vmq/vmq.hpp> | |||||
using namespace vmq::types; | |||||
class camera; | |||||
/** | |||||
* Abstract base class for camera rigs which control the movement of cameras. | |||||
*/ | |||||
class camera_rig | |||||
{ | |||||
public: | |||||
camera_rig(); | |||||
/** | |||||
* Updates the rig. | |||||
* | |||||
* @param dt Delta time. | |||||
*/ | |||||
virtual void update(float dt) = 0; | |||||
/** | |||||
* Attaches a camera to the rig. | |||||
* | |||||
* @param camera Camera to attach. | |||||
*/ | |||||
void attach(::camera* camera); | |||||
/** | |||||
* Detaches a camera from the rig. | |||||
*/ | |||||
void detach(); | |||||
/** | |||||
* Sets the translation of the camera rig. | |||||
*/ | |||||
void set_translation(const float3& translation); | |||||
/** | |||||
* Sets the rotation of the camera rig. | |||||
*/ | |||||
void set_rotation(const vmq::quaternion<float>& rotation); | |||||
/** | |||||
* Returns the attached camera. | |||||
*/ | |||||
const ::camera* get_camera() const; | |||||
/// @copydoc camera_rig::get_camera() const | |||||
::camera* get_camera(); | |||||
const float3& get_translation() const; | |||||
const vmq::quaternion<float>& get_rotation() const; | |||||
const float3& get_forward() const; | |||||
const float3& get_right() const; | |||||
const float3& get_up() const; | |||||
private: | |||||
camera* camera; | |||||
float3 translation; | |||||
vmq::quaternion<float> rotation; | |||||
float3 forward; | |||||
float3 right; | |||||
float3 up; | |||||
}; | |||||
inline const camera* camera_rig::get_camera() const | |||||
{ | |||||
return camera; | |||||
} | |||||
inline camera* camera_rig::get_camera() | |||||
{ | |||||
return camera; | |||||
} | |||||
inline const float3& camera_rig::get_translation() const | |||||
{ | |||||
return translation; | |||||
} | |||||
inline const vmq::quaternion<float>& camera_rig::get_rotation() const | |||||
{ | |||||
return rotation; | |||||
} | |||||
inline const float3& camera_rig::get_forward() const | |||||
{ | |||||
return forward; | |||||
} | |||||
inline const float3& camera_rig::get_right() const | |||||
{ | |||||
return right; | |||||
} | |||||
inline const float3& camera_rig::get_up() const | |||||
{ | |||||
return up; | |||||
} | |||||
#endif // ANTKEEPER_CAMERA_RIG_HPP | |||||
@ -0,0 +1,44 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_CONFIGURATION_HPP | |||||
#define ANTKEEPER_CONFIGURATION_HPP | |||||
#include <vmq/vmq.hpp> | |||||
using namespace vmq::types; | |||||
#define ANTKEEPER_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ | |||||
#define ANTKEEPER_VERSION_MINOR @PROJECT_VERSION_MINOR@ | |||||
#define ANTKEEPER_VERSION_PATCH @PROJECT_VERSION_PATCH@ | |||||
#define ANTKEEPER_VERSION_STRING "@PROJECT_VERSION@" | |||||
constexpr float3 global_forward = {0.0f, 0.0f, -1.0f}; | |||||
constexpr float3 global_up = {0.0f, 1.0f, 0.0f}; | |||||
constexpr float3 global_right = {1.0f, 0.0f, 0.0f}; | |||||
#define MATERIAL_PASS_MAX_AMBIENT_LIGHT_COUNT 1 | |||||
#define MATERIAL_PASS_MAX_POINT_LIGHT_COUNT 1 | |||||
#define MATERIAL_PASS_MAX_DIRECTIONAL_LIGHT_COUNT 1 | |||||
#define MATERIAL_PASS_MAX_SPOTLIGHT_COUNT 1 | |||||
#define TERRAIN_PATCH_SIZE 200.0f | |||||
#define TERRAIN_PATCH_RESOLUTION 4 | |||||
#define VEGETATION_PATCH_RESOLUTION 1 | |||||
#endif // ANTKEEPER_CONFIGURATION_HPP |
@ -0,0 +1,70 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_ANSI_CODES_HPP | |||||
#define ANTKEEPER_ANSI_CODES_HPP | |||||
namespace ansi { | |||||
constexpr char* reset = "\u004b[0m"; | |||||
constexpr char* black = "\u003b[30m"; | |||||
constexpr char* red = "\u003b[31m"; | |||||
constexpr char* green = "\u003b[32m"; | |||||
constexpr char* yellow = "\u003b[33m"; | |||||
constexpr char* blue = "\u003b[34m"; | |||||
constexpr char* magenta = "\u003b[35m"; | |||||
constexpr char* cyan = "\u003b[36m"; | |||||
constexpr char* white = "\u003b[37m"; | |||||
constexpr char* bright_black = "\u003b[30;1m"; | |||||
constexpr char* bright_red = "\u003b[31;1m"; | |||||
constexpr char* bright_green = "\u003b[32;1m"; | |||||
constexpr char* bright_yellow = "\u003b[33;1m"; | |||||
constexpr char* bright_blue = "\u003b[34;1m"; | |||||
constexpr char* bright_magenta = "\u003b[35;1m"; | |||||
constexpr char* bright_cyan = "\u003b[36;1m"; | |||||
constexpr char* bright_white = "\u003b[37;1m"; | |||||
constexpr char* background_black = "\u003b[40m"; | |||||
constexpr char* background_red = "\u003b[41m"; | |||||
constexpr char* background_green = "\u003b[42m"; | |||||
constexpr char* background_yellow = "\u003b[43m"; | |||||
constexpr char* background_blue = "\u003b[44m"; | |||||
constexpr char* background_magenta = "\u003b[45m"; | |||||
constexpr char* background_cyan = "\u003b[46m"; | |||||
constexpr char* background_white = "\u003b[47m"; | |||||
constexpr char* background_bright_black = "\u003b[40;1m"; | |||||
constexpr char* background_bright_red = "\u003b[41;1m"; | |||||
constexpr char* background_bright_green = "\u003b[42;1m"; | |||||
constexpr char* background_bright_yellow = "\u003b[43;1m"; | |||||
constexpr char* background_bright_blue = "\u003b[44;1m"; | |||||
constexpr char* background_bright_magenta = "\u003b[45;1m"; | |||||
constexpr char* background_bright_cyan = "\u003b[46;1m"; | |||||
constexpr char* background_bright_white = "\u003b[47;1m"; | |||||
constexpr char* bold = "\u003b[1m"; | |||||
constexpr char* underline = "\u003b[4m"; | |||||
constexpr char* reversed = "\u001b[7m"; | |||||
} // namespace ansi | |||||
#endif // ANTKEEPER_ANSI_CODES_HPP | |||||
@ -0,0 +1,153 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_CLI_HPP | |||||
#define ANTKEEPER_CLI_HPP | |||||
#include <functional> | |||||
#include <map> | |||||
#include <sstream> | |||||
#include <string> | |||||
#include <tuple> | |||||
/** | |||||
* Minimal command-line interpreter. | |||||
*/ | |||||
class cli | |||||
{ | |||||
public: | |||||
/// String-wrapped function object | |||||
typedef std::function<std::string(const std::string&)> command_type; | |||||
/** | |||||
* Interprets a command line as a function invocation. | |||||
* | |||||
* @param line Command line. | |||||
* @return Stringified return value of the command function. | |||||
*/ | |||||
std::string interpret(const std::string& line) const; | |||||
/** | |||||
* Registers a command with the CLI. | |||||
* | |||||
* @tparam T Command function return type. | |||||
* @tparam Args Command function argument types. | |||||
* @param name Command name. | |||||
* @param function Command function. | |||||
*/ | |||||
template <class T, class... Args> | |||||
void register_command(const std::string& name, const std::function<T(Args...)>& function); | |||||
/// @copydoc register_command(const std::string, const std::function<T(Args...)>&) | |||||
template <class T, class... Args> | |||||
void register_command(const std::string& name, T (*function)(Args...)); | |||||
/** | |||||
* Unregisters a command from the CLI. | |||||
* | |||||
* @param name Command name. | |||||
*/ | |||||
void unregister_command(const std::string& name); | |||||
private: | |||||
/** | |||||
* Parses a single argument from a string stream. | |||||
* | |||||
* @param stream String stream from which an argument should be parsed. | |||||
*/ | |||||
template <class T> | |||||
static T parse(std::istringstream& stream); | |||||
/** | |||||
* Wraps a function in an interpreter function that parses strings as arguments then executes the wrapped function with the parsed arguments. | |||||
* | |||||
* @param function Function to wrap. | |||||
* @return Wrapped function. | |||||
*/ | |||||
template <class T, class... Args> | |||||
static command_type wrap(const std::function<T(Args...)>& function); | |||||
std::map<std::string, command_type> commands; | |||||
}; | |||||
std::string cli::interpret(const std::string& line) const | |||||
{ | |||||
std::istringstream stream(line); | |||||
std::string command_name; | |||||
stream >> command_name; | |||||
if (auto it = commands.find(command_name); it != commands.end()) | |||||
{ | |||||
return it->second(line.substr(command_name.length() + 1)); | |||||
} | |||||
return std::string(); | |||||
} | |||||
template <class T, class... Args> | |||||
void cli::register_command(const std::string& name, const std::function<T(Args...)>& function) | |||||
{ | |||||
commands[name] = wrap(function); | |||||
} | |||||
template <class T, class... Args> | |||||
void cli::register_command(const std::string& name, T (*function)(Args...)) | |||||
{ | |||||
commands[name] = wrap(std::function(function)); | |||||
} | |||||
void cli::unregister_command(const std::string& name) | |||||
{ | |||||
if (auto it = commands.find(name); it != commands.end()) | |||||
commands.erase(it); | |||||
} | |||||
template <class T> | |||||
T cli::parse(std::istringstream& stream) | |||||
{ | |||||
T value; | |||||
stream >> value; | |||||
return value; | |||||
} | |||||
template <class T, class... Args> | |||||
typename cli::command_type cli::wrap(const std::function<T(Args...)>& function) | |||||
{ | |||||
return std::bind( | |||||
[function](const std::string& line) -> std::string | |||||
{ | |||||
//std::size_t argument_count = sizeof...(Args); | |||||
// Parse string into tuple of arguments | |||||
std::istringstream istream(line); | |||||
std::tuple<Args...> arguments{parse<Args>(istream)...}; | |||||
// Invoke function with arguments and save the result | |||||
T result = std::apply(function, arguments); | |||||
// Return function result as string | |||||
std::ostringstream ostream; | |||||
ostream << result; | |||||
return ostream.str(); | |||||
}, | |||||
std::placeholders::_1); | |||||
} | |||||
#endif // ANTKEEPER_CLI_HPP | |||||
@ -0,0 +1,122 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "logger.hpp" | |||||
#include <iostream> | |||||
logger::logger(): | |||||
os(&std::cout), | |||||
log_prefix(std::string()), | |||||
log_postfix(std::string()), | |||||
warning_prefix(std::string("Warning: ")), | |||||
warning_postfix(std::string()), | |||||
error_prefix(std::string("Error: ")), | |||||
error_postfix(std::string()), | |||||
success_prefix(std::string("Success: ")), | |||||
success_postfix(std::string()) | |||||
{} | |||||
logger::~logger() | |||||
{} | |||||
void logger::redirect(std::ostream* stream) | |||||
{ | |||||
os = stream; | |||||
} | |||||
void logger::log(const std::string& text) | |||||
{ | |||||
if (os) | |||||
{ | |||||
for (const std::string& prefix: prefix_stack) | |||||
{ | |||||
(*os) << prefix; | |||||
} | |||||
(*os) << (log_prefix + text + log_postfix); | |||||
os->flush(); | |||||
} | |||||
} | |||||
void logger::warning(const std::string& text) | |||||
{ | |||||
log(warning_prefix + text + warning_postfix); | |||||
} | |||||
void logger::error(const std::string& text) | |||||
{ | |||||
log(error_prefix + text + error_postfix); | |||||
} | |||||
void logger::success(const std::string& text) | |||||
{ | |||||
log(success_prefix + text + success_postfix); | |||||
} | |||||
void logger::set_log_prefix(const std::string& prefix) | |||||
{ | |||||
log_prefix = prefix; | |||||
} | |||||
void logger::set_log_postfix(const std::string& postfix) | |||||
{ | |||||
log_postfix = postfix; | |||||
} | |||||
void logger::set_warning_prefix(const std::string& prefix) | |||||
{ | |||||
warning_prefix = prefix; | |||||
} | |||||
void logger::set_warning_postfix(const std::string& postfix) | |||||
{ | |||||
warning_postfix = postfix; | |||||
} | |||||
void logger::set_error_prefix(const std::string& prefix) | |||||
{ | |||||
error_prefix = prefix; | |||||
} | |||||
void logger::set_error_postfix(const std::string& postfix) | |||||
{ | |||||
error_postfix = postfix; | |||||
} | |||||
void logger::set_success_prefix(const std::string& prefix) | |||||
{ | |||||
success_prefix = prefix; | |||||
} | |||||
void logger::set_success_postfix(const std::string& postfix) | |||||
{ | |||||
success_postfix = postfix; | |||||
} | |||||
void logger::push_prefix(const std::string& prefix) | |||||
{ | |||||
prefix_stack.push_back(prefix); | |||||
} | |||||
void logger::pop_prefix() | |||||
{ | |||||
prefix_stack.pop_back(); | |||||
} | |||||
@ -0,0 +1,74 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_LOGGER_HPP | |||||
#define ANTKEEPER_LOGGER_HPP | |||||
#include <list> | |||||
#include <ostream> | |||||
#include <string> | |||||
class logger | |||||
{ | |||||
public: | |||||
logger(); | |||||
~logger(); | |||||
/** | |||||
* Redirects log output to the specified output stream. | |||||
* | |||||
* @param stream Output stream to which log text will be written. | |||||
*/ | |||||
void redirect(std::ostream* stream); | |||||
/** | |||||
* Outputs text to the log. | |||||
*/ | |||||
void log(const std::string& text); | |||||
void warning(const std::string& text); | |||||
void error(const std::string& text); | |||||
void success(const std::string& text); | |||||
void set_log_prefix(const std::string& prefix); | |||||
void set_log_postfix(const std::string& postfix); | |||||
void set_warning_prefix(const std::string& prefix); | |||||
void set_warning_postfix(const std::string& postfix); | |||||
void set_error_prefix(const std::string& prefix); | |||||
void set_error_postfix(const std::string& postfix); | |||||
void set_success_prefix(const std::string& prefix); | |||||
void set_success_postfix(const std::string& postfix); | |||||
void push_prefix(const std::string& prefix); | |||||
void pop_prefix(); | |||||
private: | |||||
std::ostream* os; | |||||
std::string log_prefix; | |||||
std::string log_postfix; | |||||
std::string warning_prefix; | |||||
std::string warning_postfix; | |||||
std::string error_prefix; | |||||
std::string error_postfix; | |||||
std::string success_prefix; | |||||
std::string success_postfix; | |||||
std::list<std::string> prefix_stack; | |||||
}; | |||||
#endif // ANTKEEPER_LOGGER_HPP | |||||
@ -0,0 +1,62 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "performance-sampler.hpp" | |||||
#include <algorithm> | |||||
#include <numeric> | |||||
performance_sampler::performance_sampler(): | |||||
sample_size(1), | |||||
sample_index(0) | |||||
{} | |||||
void performance_sampler::sample(double duration) | |||||
{ | |||||
if (samples.size() < sample_size) | |||||
{ | |||||
samples.push_back(duration); | |||||
} | |||||
else | |||||
{ | |||||
samples[sample_index] = duration; | |||||
sample_index = (sample_index + 1) % samples.size(); | |||||
} | |||||
} | |||||
void performance_sampler::reset() | |||||
{ | |||||
samples.clear(); | |||||
sample_index = 0; | |||||
} | |||||
void performance_sampler::set_sample_size(std::size_t size) | |||||
{ | |||||
sample_size = size; | |||||
if (samples.size() > size) | |||||
{ | |||||
samples.resize(size); | |||||
sample_index = 0; | |||||
} | |||||
} | |||||
double performance_sampler::mean_frame_duration() const | |||||
{ | |||||
return std::accumulate(samples.begin(), samples.end(), 0.0) / static_cast<double>(samples.size()); | |||||
} | |||||
@ -0,0 +1,66 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_PERFORMANCE_SAMPLER_HPP | |||||
#define ANTKEEPER_PERFORMANCE_SAMPLER_HPP | |||||
#include <cstdlib> | |||||
#include <vector> | |||||
/** | |||||
* Measures a rolling mean frame duration. | |||||
*/ | |||||
class performance_sampler | |||||
{ | |||||
public: | |||||
/// Creates a performance sampler. | |||||
performance_sampler(); | |||||
/** | |||||
* Adds a frame duration to the sample. | |||||
* | |||||
* @param duration Duration of the frame. | |||||
*/ | |||||
void sample(double duration); | |||||
/** | |||||
* Resets the sampling process. | |||||
*/ | |||||
void reset(); | |||||
/** | |||||
* Sets the number of frames in a sample. | |||||
* | |||||
* @param size Number of frames in a sample. | |||||
*/ | |||||
void set_sample_size(std::size_t size); | |||||
/** | |||||
* Returns the mean frame duration. | |||||
*/ | |||||
double mean_frame_duration() const; | |||||
private: | |||||
std::vector<double> samples; | |||||
std::size_t sample_size; | |||||
std::size_t sample_index; | |||||
}; | |||||
#endif // ANTKEEPER_PERFORMANCE_SAMPLER_HPP | |||||
@ -1,28 +1,32 @@ | |||||
/* | /* | ||||
* Copyright (C) 2017-2019 Christopher J. Howard | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | * | ||||
* This file is part of Antkeeper Source Code. | |||||
* This file is part of Antkeeper source code. | |||||
* | * | ||||
* Antkeeper Source Code is free software: you can redistribute it and/or modify | |||||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by | ||||
* the Free Software Foundation, either version 3 of the License, or | * the Free Software Foundation, either version 3 of the License, or | ||||
* (at your option) any later version. | * (at your option) any later version. | ||||
* | * | ||||
* Antkeeper Source Code is distributed in the hope that it will be useful, | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
* GNU General Public License for more details. | * GNU General Public License for more details. | ||||
* | * | ||||
* You should have received a copy of the GNU General Public License | * You should have received a copy of the GNU General Public License | ||||
* along with Antkeeper Source Code. If not, see <http://www.gnu.org/licenses/>. | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | */ | ||||
#ifndef CURL_NOISE_HPP | |||||
#define CURL_NOISE_HPP | |||||
#ifndef ANTKEEPER_ECS_ARCHETYPE_HPP | |||||
#define ANTKEEPER_ECS_ARCHETYPE_HPP | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
#include <entt/entt.hpp> | |||||
Vector3 curl(const Vector3& p, const Vector3& offset, float frequency); | |||||
namespace ecs { | |||||
typedef entt::prototype archetype; | |||||
} // namespace ecs | |||||
#endif // ANTKEEPER_ECS_ARCHETYPE_HPP | |||||
#endif // CURL_NOISE_HPP |
@ -0,0 +1,35 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_ECS_BEHAVIOR_COMPONENT_HPP | |||||
#define ANTKEEPER_ECS_BEHAVIOR_COMPONENT_HPP | |||||
#include "behavior/ebt.hpp" | |||||
namespace ecs { | |||||
struct behavior_component | |||||
{ | |||||
const ebt::node* behavior_tree; | |||||
}; | |||||
} // namespace ecs | |||||
#endif // ANTKEEPER_ECS_BEHAVIOR_COMPONENT_HPP | |||||
@ -0,0 +1,37 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_ECS_CAVITY_COMPONENT_HPP | |||||
#define ANTKEEPER_ECS_CAVITY_COMPONENT_HPP | |||||
#include <vmq/vmq.hpp> | |||||
using namespace vmq::types; | |||||
namespace ecs { | |||||
struct cavity_component | |||||
{ | |||||
float3 position; | |||||
float radius; | |||||
}; | |||||
} // namespace ecs | |||||
#endif // ANTKEEPER_ECS_CAVITY_COMPONENT_HPP | |||||
@ -0,0 +1,40 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_ECS_COLLISION_COMPONENT_HPP | |||||
#define ANTKEEPER_ECS_COLLISION_COMPONENT_HPP | |||||
#include "geometry/aabb.hpp" | |||||
#include "geometry/mesh-accelerator.hpp" | |||||
class mesh; | |||||
namespace ecs { | |||||
struct collision_component | |||||
{ | |||||
mesh* mesh; | |||||
aabb<float> bounds; | |||||
mesh_accelerator mesh_accelerator; | |||||
}; | |||||
} // namespace ecs | |||||
#endif // ANTKEEPER_ECS_COLLISION_COMPONENT_HPP | |||||
@ -0,0 +1,38 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_ECS_PLACEMENT_COMPONENT_HPP | |||||
#define ANTKEEPER_ECS_PLACEMENT_COMPONENT_HPP | |||||
#include "geometry/mesh.hpp" | |||||
#include <vmq/vmq.hpp> | |||||
using namespace vmq::types; | |||||
namespace ecs { | |||||
struct locomotion_component | |||||
{ | |||||
const mesh::face* triangle; | |||||
float3 barycentric_position; | |||||
}; | |||||
} // namespace ecs | |||||
#endif // ANTKEEPER_ECS_PLACEMENT_COMPONENT_HPP | |||||
@ -0,0 +1,38 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_ECS_MODEL_COMPONENT_HPP | |||||
#define ANTKEEPER_ECS_MODEL_COMPONENT_HPP | |||||
#include "renderer/model.hpp" | |||||
#include <unordered_map> | |||||
namespace ecs { | |||||
struct model_component | |||||
{ | |||||
model* model; | |||||
std::unordered_map<int, material*> materials; | |||||
int instance_count; | |||||
}; | |||||
} // namespace ecs | |||||
#endif // ANTKEEPER_ECS_MODEL_COMPONENT_HPP | |||||
@ -0,0 +1,33 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_ECS_NEST_COMPONENT_HPP | |||||
#define ANTKEEPER_ECS_NEST_COMPONENT_HPP | |||||
namespace ecs { | |||||
struct nest_component | |||||
{ | |||||
int bla; | |||||
}; | |||||
} // namespace ecs | |||||
#endif // ANTKEEPER_ECS_NEST_COMPONENT_HPP | |||||
@ -0,0 +1,35 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_ECS_PLACEMENT_COMPONENT_HPP | |||||
#define ANTKEEPER_ECS_PLACEMENT_COMPONENT_HPP | |||||
#include "geometry/ray.hpp" | |||||
namespace ecs { | |||||
struct placement_component | |||||
{ | |||||
::ray<float> ray; | |||||
}; | |||||
} // namespace ecs | |||||
#endif // ANTKEEPER_ECS_PLACEMENT_COMPONENT_HPP | |||||
@ -0,0 +1,38 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_ECS_SAMARA_COMPONENT_HPP | |||||
#define ANTKEEPER_ECS_SAMARA_COMPONENT_HPP | |||||
#include <vmq/vmq.hpp> | |||||
using namespace vmq::types; | |||||
namespace ecs { | |||||
struct samara_component | |||||
{ | |||||
float3 direction; | |||||
float angle; | |||||
float chirality; | |||||
}; | |||||
} // namespace ecs | |||||
#endif // ANTKEEPER_ECS_SAMARA_COMPONENT_HPP | |||||
@ -0,0 +1,35 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_ECS_TERRAIN_COMPONENT_HPP | |||||
#define ANTKEEPER_ECS_TERRAIN_COMPONENT_HPP | |||||
namespace ecs { | |||||
struct terrain_component | |||||
{ | |||||
int subdivisions; | |||||
int x; | |||||
int z; | |||||
}; | |||||
} // namespace ecs | |||||
#endif // ANTKEEPER_ECS_TERRAIN_COMPONENT_HPP | |||||
@ -0,0 +1,33 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_ECS_TOOL_COMPONENT_HPP | |||||
#define ANTKEEPER_ECS_TOOL_COMPONENT_HPP | |||||
namespace ecs { | |||||
struct tool_component | |||||
{ | |||||
bool active; | |||||
}; | |||||
} // namespace ecs | |||||
#endif // ANTKEEPER_ECS_TOOL_COMPONENT_HPP | |||||
@ -0,0 +1,36 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_ECS_TRANSFORM_COMPONENT_HPP | |||||
#define ANTKEEPER_ECS_TRANSFORM_COMPONENT_HPP | |||||
#include <vmq/vmq.hpp> | |||||
namespace ecs { | |||||
struct transform_component | |||||
{ | |||||
vmq::transform<float> transform; | |||||
bool warp; | |||||
}; | |||||
} // namespace ecs | |||||
#endif // ANTKEEPER_ECS_TRANSFORM_COMPONENT_HPP | |||||
@ -0,0 +1,107 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "event-dispatcher.hpp" | |||||
event_dispatcher::event_dispatcher() | |||||
{} | |||||
event_dispatcher::~event_dispatcher() | |||||
{ | |||||
clear(); | |||||
} | |||||
void event_dispatcher::update(double time) | |||||
{ | |||||
// Process pending subscriptions | |||||
for (auto it = to_subscribe.begin(); it != to_subscribe.end(); ++it) | |||||
{ | |||||
handler_map[std::get<0>(*it)].push_back(std::get<1>(*it)); | |||||
} | |||||
to_subscribe.clear(); | |||||
// Process pending unsubscriptions | |||||
for (auto it = to_unsubscribe.begin(); it != to_unsubscribe.end(); ++it) | |||||
{ | |||||
handler_map[std::get<0>(*it)].remove(std::get<1>(*it)); | |||||
} | |||||
to_unsubscribe.clear(); | |||||
// Dispatch queued events | |||||
flush(); | |||||
// For each scheduled event | |||||
for (auto event = scheduled_events.begin(); event != scheduled_events.end();) | |||||
{ | |||||
// If the event is due | |||||
if (time >= event->first) | |||||
{ | |||||
// Dispatch event | |||||
dispatch(*(event->second)); | |||||
// Delete event | |||||
delete event->second; | |||||
event = scheduled_events.erase(event); | |||||
} | |||||
else | |||||
{ | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
void event_dispatcher::flush() | |||||
{ | |||||
// For each event in the queue | |||||
for (auto event = queued_events.begin(); event != queued_events.end(); ++event) | |||||
{ | |||||
// Dispatch event | |||||
dispatch(**event); | |||||
// Delete event | |||||
delete (*event); | |||||
} | |||||
// Clear event queue | |||||
queued_events.clear(); | |||||
} | |||||
void event_dispatcher::clear() | |||||
{ | |||||
// For each event in the queue | |||||
for (auto event = queued_events.begin(); event != queued_events.end(); ++event) | |||||
{ | |||||
// Delete event | |||||
delete (*event); | |||||
} | |||||
// Clear event queue | |||||
queued_events.clear(); | |||||
// For each scheduled event | |||||
for (auto event = scheduled_events.begin(); event != scheduled_events.end(); ++event) | |||||
{ | |||||
// Delete event | |||||
delete event->second; | |||||
} | |||||
// Clear scheduled events | |||||
scheduled_events.clear(); | |||||
} | |||||
@ -0,0 +1,138 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_EVENT_DISPATCHER_HPP | |||||
#define ANTKEEPER_EVENT_DISPATCHER_HPP | |||||
#include "event.hpp" | |||||
#include "event-handler.hpp" | |||||
#include <cstdlib> | |||||
#include <list> | |||||
#include <map> | |||||
/** | |||||
* Queues events and dispatches them to event handlers. | |||||
*/ | |||||
class event_dispatcher | |||||
{ | |||||
public: | |||||
/// Creates an event dispatcher | |||||
event_dispatcher(); | |||||
/// Destroys an event dispatcher | |||||
~event_dispatcher(); | |||||
/** | |||||
* Processes all pending subscriptions and unsubscriptions, dispatches queued events, then dispatches due scheduled events. | |||||
* | |||||
* @param time The current time. | |||||
*/ | |||||
void update(double time); | |||||
/** | |||||
* Subscribes an event handler to event dispatches. | |||||
* | |||||
* @param handler Handler to subscribe. | |||||
*/ | |||||
template <typename T> | |||||
void subscribe(event_handler<T>* handler); | |||||
/** | |||||
* Unsubscribes an event handler from event dispatches. | |||||
* | |||||
* @param handler Handler to unsubscribe. | |||||
*/ | |||||
template <typename T> | |||||
void unsubscribe(event_handler<T>* handler); | |||||
/** | |||||
* Adds an event to the queue. | |||||
* | |||||
* @param event Event to queue. | |||||
*/ | |||||
void queue(const event_base& event); | |||||
/** | |||||
* Schedules an event to be dispatched at a specific time. | |||||
* | |||||
* @param event Event to schedule. | |||||
* @param time Time that the event should be dispatched. | |||||
*/ | |||||
void schedule(const event_base& event, double time); | |||||
/** | |||||
* Dispatches a single event. | |||||
* | |||||
* @param event Event to dispatch. | |||||
*/ | |||||
void dispatch(const event_base& event); | |||||
/** | |||||
* Dispatches all events in the queue. | |||||
*/ | |||||
void flush(); | |||||
/// Removes all queued and scheduled events from the queue without notifying handlers. | |||||
void clear(); | |||||
private: | |||||
std::list<std::tuple<std::size_t, event_handler_base*>> to_subscribe; | |||||
std::list<std::tuple<std::size_t, event_handler_base*>> to_unsubscribe; | |||||
std::map<std::size_t, std::list<event_handler_base*>> handler_map; | |||||
std::list<event_base*> queued_events; | |||||
std::multimap<double, event_base*> scheduled_events; | |||||
}; | |||||
template <typename T> | |||||
void event_dispatcher::subscribe(event_handler<T>* handler) | |||||
{ | |||||
to_subscribe.push_back(std::make_tuple(handler->get_handled_event_type_id(), handler)); | |||||
} | |||||
template <typename T> | |||||
void event_dispatcher::unsubscribe(event_handler<T>* handler) | |||||
{ | |||||
to_unsubscribe.push_back(std::make_tuple(handler->get_handled_event_type_id(), handler)); | |||||
} | |||||
inline void event_dispatcher::queue(const event_base& event) | |||||
{ | |||||
queued_events.push_back(event.clone()); | |||||
} | |||||
inline void event_dispatcher::schedule(const event_base& event, double time) | |||||
{ | |||||
scheduled_events.insert(std::pair<double, event_base*>(time, event.clone())); | |||||
} | |||||
inline void event_dispatcher::dispatch(const event_base& event) | |||||
{ | |||||
// Get list of handlers for this type of event | |||||
const std::list<event_handler_base*>& handlers = handler_map[event.get_event_type_id()]; | |||||
// For each handler | |||||
for (auto handler = handlers.begin(); handler != handlers.end(); ++handler) | |||||
{ | |||||
// Pass event to the handler | |||||
(*handler)->route_event(event); | |||||
} | |||||
} | |||||
#endif // ANTKEEPER_EVENT_DISPATCHER_HPP | |||||
@ -0,0 +1,83 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_EVENT_HANDLER_HPP | |||||
#define ANTKEEPER_EVENT_HANDLER_HPP | |||||
#include "event.hpp" | |||||
#include <type_traits> | |||||
class event_dispatcher; | |||||
/** | |||||
* Abstract base class for event handlers. | |||||
*/ | |||||
class event_handler_base | |||||
{ | |||||
private: | |||||
friend class event_dispatcher; | |||||
/** | |||||
* Receives an event, casts it to its derived event type, then handles it. | |||||
* | |||||
* @param event Received event. | |||||
*/ | |||||
virtual void route_event(const event_base& event) = 0; | |||||
}; | |||||
/** | |||||
* Templates abstract base class for event handlers. | |||||
* | |||||
* @tparam Event type. | |||||
*/ | |||||
template <typename T> | |||||
class event_handler: public event_handler_base | |||||
{ | |||||
public: | |||||
static_assert(std::is_base_of<event_base, T>::value, "T must be a descendant of event_base."); | |||||
/// Returns the unique event type identifier for the event type handled by this event handler. | |||||
const std::size_t get_handled_event_type_id() const; | |||||
/** | |||||
* Handles an event of type T. | |||||
* | |||||
* @param event Event to handle. | |||||
*/ | |||||
virtual void handle_event(const T& event) = 0; | |||||
private: | |||||
/// @copydoc event_handler_base::route_event() | |||||
virtual void route_event(const event_base& event) final; | |||||
}; | |||||
template <typename T> | |||||
inline const std::size_t event_handler<T>::get_handled_event_type_id() const | |||||
{ | |||||
return T::event_type_id; | |||||
} | |||||
template <typename T> | |||||
void event_handler<T>::route_event(const event_base& event) | |||||
{ | |||||
handle_event(static_cast<const T&>(event)); | |||||
} | |||||
#endif // ANTKEEPER_EVENT_HANDLER_HPP | |||||
@ -0,0 +1,85 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_EVENT_HPP | |||||
#define ANTKEEPER_EVENT_HPP | |||||
#include <atomic> | |||||
#include <cstdlib> | |||||
/** | |||||
* Abstract base class for events. | |||||
*/ | |||||
class event_base | |||||
{ | |||||
public: | |||||
/// Destroys an event base. | |||||
virtual ~event_base() = default; | |||||
/// Returns the unique event type identifier for this event type. | |||||
virtual const std::size_t get_event_type_id() const = 0; | |||||
/** | |||||
* Allocates a copy of this event. | |||||
* | |||||
* @return Newly allocated copy of this event. | |||||
*/ | |||||
virtual event_base* clone() const = 0; | |||||
protected: | |||||
/// Returns then increments the next available event type ID. | |||||
static std::size_t next_event_type_id(); | |||||
}; | |||||
inline std::size_t event_base::next_event_type_id() | |||||
{ | |||||
static std::atomic<std::size_t> next_event_type_id{0}; | |||||
return next_event_type_id++; | |||||
} | |||||
/** | |||||
* Templated abstract base class for events. | |||||
* | |||||
* @tparam T The derived class. | |||||
*/ | |||||
template <typename T> | |||||
class event: public event_base | |||||
{ | |||||
public: | |||||
/// The unique event type identifier for this event type. | |||||
static const std::atomic<std::size_t> event_type_id; | |||||
/// Destroys an event | |||||
virtual ~event() = default; | |||||
virtual const std::size_t get_event_type_id() const final; | |||||
virtual event_base* clone() const = 0; | |||||
}; | |||||
template <typename T> | |||||
const std::atomic<std::size_t> event<T>::event_type_id{event_base::next_event_type_id()}; | |||||
template <typename T> | |||||
inline const std::size_t event<T>::get_event_type_id() const | |||||
{ | |||||
return event_type_id; | |||||
} | |||||
#endif // ANTKEEPER_EVENT_HPP | |||||
@ -0,0 +1,85 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "frame-scheduler.hpp" | |||||
#include <algorithm> | |||||
frame_scheduler::frame_scheduler(): | |||||
update_callback(nullptr), | |||||
render_callback(nullptr), | |||||
update_rate(60.0), | |||||
update_timestep(1.0 / update_rate), | |||||
max_frame_duration(update_timestep) | |||||
{ | |||||
reset(); | |||||
} | |||||
void frame_scheduler::set_update_callback(std::function<void(double, double)> callback) | |||||
{ | |||||
update_callback = callback; | |||||
} | |||||
void frame_scheduler::set_render_callback(std::function<void(double)> callback) | |||||
{ | |||||
render_callback = callback; | |||||
} | |||||
void frame_scheduler::set_update_rate(double frequency) | |||||
{ | |||||
update_rate = frequency; | |||||
update_timestep = 1.0 / frequency; | |||||
} | |||||
void frame_scheduler::set_max_frame_duration(double duration) | |||||
{ | |||||
max_frame_duration = duration; | |||||
} | |||||
double frame_scheduler::get_frame_duration() const | |||||
{ | |||||
return frame_duration; | |||||
} | |||||
void frame_scheduler::reset() | |||||
{ | |||||
elapsed_time = 0.0; | |||||
accumulator = 0.0; | |||||
frame_start = std::chrono::high_resolution_clock::now(); | |||||
frame_end = frame_start; | |||||
frame_duration = 0.0; | |||||
} | |||||
void frame_scheduler::tick() | |||||
{ | |||||
accumulator += std::min<double>(max_frame_duration, frame_duration); | |||||
while (accumulator >= update_timestep) | |||||
{ | |||||
update_callback(elapsed_time, update_timestep); | |||||
elapsed_time += update_timestep; | |||||
accumulator -= update_timestep; | |||||
} | |||||
render_callback(accumulator * update_rate); | |||||
frame_end = std::chrono::high_resolution_clock::now(); | |||||
frame_duration = static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>(frame_end - frame_start).count()) / 1000000.0; | |||||
frame_start = frame_end; | |||||
} | |||||
@ -0,0 +1,91 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_FRAME_SCHEDULER_HPP | |||||
#define ANTKEEPER_FRAME_SCHEDULER_HPP | |||||
#include <chrono> | |||||
#include <functional> | |||||
/** | |||||
* Schedules fixed-timestep update calls and variable timestep render calls. | |||||
*/ | |||||
class frame_scheduler | |||||
{ | |||||
public: | |||||
frame_scheduler(); | |||||
/** | |||||
* Sets the update callback. | |||||
* | |||||
* @param callback Function which takes two parameters: `t`, the total elapsed time, and `dt`, delta time (timestep) which is calculated as `1.0 / update_rate`. This function will be called at the frequency specified by `frame_scheduler::set_update_rate()`. | |||||
*/ | |||||
void set_update_callback(std::function<void(double, double)> callback); | |||||
/** | |||||
* Sets the render callback. | |||||
* | |||||
* @param callback Function which takes one parameter: `alpha`, which is a factor that can be used to interpolate between the previous and current update states. | |||||
*/ | |||||
void set_render_callback(std::function<void(double)> callback); | |||||
/** | |||||
* Sets the update rate. | |||||
* | |||||
* @param frequency Frequency, in hertz, at which the update callback should be called. | |||||
*/ | |||||
void set_update_rate(double frequency); | |||||
/** | |||||
* Sets the maximum duration of a frame. This limits the number of times the update callback is called per frame, thereby preventing a "spiral of death", in which the update callback is called too many times per frame while trying to catch up to the target update rate. | |||||
* | |||||
* @param duration Maximum frame duration, in seconds.. | |||||
*/ | |||||
void set_max_frame_duration(double duration); | |||||
/** | |||||
* Returns the duration of the last frame, in seconds. | |||||
*/ | |||||
double get_frame_duration() const; | |||||
/** | |||||
* Resets the total elapsed time, frame duration, and internal timers. | |||||
*/ | |||||
void reset(); | |||||
/** | |||||
* Updates the internal timers and performs the scheduled update and render callbacks. | |||||
*/ | |||||
void tick(); | |||||
private: | |||||
std::function<void(double, double)> update_callback; | |||||
std::function<void(double)> render_callback; | |||||
double update_rate; | |||||
double update_timestep; | |||||
double max_frame_duration; | |||||
double elapsed_time; | |||||
double accumulator; | |||||
std::chrono::high_resolution_clock::time_point frame_start; | |||||
std::chrono::high_resolution_clock::time_point frame_end; | |||||
double frame_duration; | |||||
}; | |||||
#endif // ANTKEEPER_FRAME_SCHEDULER_HPP | |||||
@ -0,0 +1,201 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_AABB_HPP | |||||
#define ANTKEEPER_AABB_HPP | |||||
#include "bounding-volume.hpp" | |||||
#include "sphere.hpp" | |||||
#include <vmq/vmq.hpp> | |||||
#include <array> | |||||
#include <limits> | |||||
using vmq::vector; | |||||
using vmq::matrix; | |||||
using vmq::transform; | |||||
using namespace vmq::operators; | |||||
template <class T> | |||||
struct aabb: public bounding_volume<T> | |||||
{ | |||||
vector<T, 3> min_point; | |||||
vector<T, 3> max_point; | |||||
/** | |||||
* Transforms an AABB. | |||||
* | |||||
* @param a AABB to be transformed. | |||||
* @param t Transform by which the AABB should be transformed. | |||||
* @return Transformed AABB. | |||||
*/ | |||||
static aabb transform(const aabb& a, const ::transform<T>& t); | |||||
/** | |||||
* Transforms an AABB. | |||||
* | |||||
* @param a AABB to be transformed. | |||||
* @param m Matrix by which the AABB should be transformed. | |||||
* @return Transformed AABB. | |||||
*/ | |||||
static aabb transform(const aabb& a, const matrix<T, 4, 4>& m); | |||||
aabb(const vector<T, 3>& min_point, const vector<T, 3>& max_point); | |||||
aabb(); | |||||
virtual bounding_volume_type get_bounding_volume_type() const; | |||||
virtual bool intersects(const sphere<T>& sphere) const; | |||||
virtual bool intersects(const aabb<T>& aabb) const; | |||||
virtual bool contains(const sphere<T>& sphere) const; | |||||
virtual bool contains(const aabb<T>& aabb) const; | |||||
virtual bool contains(const vector<T, 3>& point) const; | |||||
/** | |||||
* Returns the position of the specified corner. | |||||
* | |||||
* @param index Index of a corner. | |||||
* @return Position of the specified corner. | |||||
*/ | |||||
vector<T, 3> corner(int index) const noexcept; | |||||
}; | |||||
template <class T> | |||||
aabb<T> aabb<T>::transform(const aabb& a, const ::transform<T>& t) | |||||
{ | |||||
vector<T, 3> min_point = {std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity()}; | |||||
vector<T, 3> max_point = {-std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity()}; | |||||
for (std::size_t i = 0; i < 8; ++i) | |||||
{ | |||||
vector<T, 3> transformed_corner = vmq::mul(t, a.corner(i)); | |||||
for (std::size_t j = 0; j < 3; ++j) | |||||
{ | |||||
min_point[j] = std::min<T>(min_point[j], transformed_corner[j]); | |||||
max_point[j] = std::max<T>(max_point[j], transformed_corner[j]); | |||||
} | |||||
} | |||||
return {min_point, max_point}; | |||||
} | |||||
template <class T> | |||||
aabb<T> aabb<T>::transform(const aabb& a, const matrix<T, 4, 4>& m) | |||||
{ | |||||
vector<T, 3> min_point = {std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity()}; | |||||
vector<T, 3> max_point = {-std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity()}; | |||||
for (std::size_t i = 0; i < 8; ++i) | |||||
{ | |||||
vector<T, 3> corner = a.corner(i); | |||||
vector<T, 4> transformed_corner = vmq::mul(m, vector<T, 4>{corner.x, corner.y, corner.z, T(1)}); | |||||
for (std::size_t j = 0; j < 3; ++j) | |||||
{ | |||||
min_point[j] = std::min<T>(min_point[j], transformed_corner[j]); | |||||
max_point[j] = std::max<T>(max_point[j], transformed_corner[j]); | |||||
} | |||||
} | |||||
return {min_point, max_point}; | |||||
} | |||||
template <class T> | |||||
aabb<T>::aabb(const vector<T, 3>& min_point, const vector<T, 3>& max_point): | |||||
min_point(min_point), | |||||
max_point(max_point) | |||||
{} | |||||
template <class T> | |||||
aabb<T>::aabb() | |||||
{} | |||||
template <class T> | |||||
inline bounding_volume_type aabb<T>::get_bounding_volume_type() const | |||||
{ | |||||
return bounding_volume_type::aabb; | |||||
} | |||||
template <class T> | |||||
bool aabb<T>::intersects(const sphere<T>& sphere) const | |||||
{ | |||||
const vector<T, 3> radius_vector = {sphere.radius, sphere.radius, sphere.radius}; | |||||
return aabb<T>(min_point - radius_vector, max_point + radius_vector).contains(sphere.center); | |||||
} | |||||
template <class T> | |||||
bool aabb<T>::intersects(const aabb<T>& aabb) const | |||||
{ | |||||
if (max_point.x < aabb.min_point.x || min_point.x > aabb.max_point.x) | |||||
return false; | |||||
if (max_point.y < aabb.min_point.y || min_point.y > aabb.max_point.y) | |||||
return false; | |||||
if (max_point.z < aabb.min_point.z || min_point.z > aabb.max_point.z) | |||||
return false; | |||||
return true; | |||||
} | |||||
template <class T> | |||||
bool aabb<T>::contains(const sphere<T>& sphere) const | |||||
{ | |||||
if (sphere.center.x - sphere.radius < min_point.x || sphere.center.x + sphere.radius > max_point.x) | |||||
return false; | |||||
if (sphere.center.y - sphere.radius < min_point.y || sphere.center.y + sphere.radius > max_point.y) | |||||
return false; | |||||
if (sphere.center.z - sphere.radius < min_point.z || sphere.center.z + sphere.radius > max_point.z) | |||||
return false; | |||||
return true; | |||||
} | |||||
template <class T> | |||||
bool aabb<T>::contains(const aabb<T>& aabb) const | |||||
{ | |||||
if (aabb.min_point.x < min_point.x || aabb.max_point.x > max_point.x) | |||||
return false; | |||||
if (aabb.min_point.y < min_point.y || aabb.max_point.y > max_point.y) | |||||
return false; | |||||
if (aabb.min_point.z < min_point.z || aabb.max_point.z > max_point.z) | |||||
return false; | |||||
return true; | |||||
} | |||||
template <class T> | |||||
bool aabb<T>::contains(const vector<T, 3>& point) const | |||||
{ | |||||
if (point.x < min_point.x || point.x > max_point.x) | |||||
return false; | |||||
if (point.y < min_point.y || point.y > max_point.y) | |||||
return false; | |||||
if (point.z < min_point.z || point.z > max_point.z) | |||||
return false; | |||||
return true; | |||||
} | |||||
template <class T> | |||||
vector<T, 3> aabb<T>::corner(int index) const noexcept | |||||
{ | |||||
return | |||||
{ | |||||
((index >> 2) & 1) ? max_point[0] : min_point[0], | |||||
((index >> 1) & 1) ? max_point[1] : min_point[1], | |||||
((index >> 0) & 1) ? max_point[2] : min_point[2] | |||||
}; | |||||
} | |||||
#endif // ANTKEEPER_AABB_HPP | |||||
@ -0,0 +1,94 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_BOUNDING_VOLUME_HPP | |||||
#define ANTKEEPER_BOUNDING_VOLUME_HPP | |||||
#include <stdexcept> | |||||
#include <vmq/vmq.hpp> | |||||
using vmq::vector; | |||||
template <class T> | |||||
struct sphere; | |||||
template <class T> | |||||
struct aabb; | |||||
/// Enumerates bounding volume types. | |||||
enum class bounding_volume_type | |||||
{ | |||||
aabb, ///< Indicates the bounding volume is an axis-aligned bounding box. | |||||
sphere, ///< Indicates the bounding volume is a sphere. | |||||
convex_hull ///< Indicates the bounding volume is a convex hull. | |||||
}; | |||||
/** | |||||
* Abstract base class for bounding volumes. | |||||
* | |||||
* @tparam T Scalar type. | |||||
*/ | |||||
template <class T> | |||||
class bounding_volume | |||||
{ | |||||
public: | |||||
/// Returns the enumerated type of this bounding volume. | |||||
virtual bounding_volume_type get_bounding_volume_type() const = 0; | |||||
/// Tests for intersection between this bounding volume and a bounding sphere. | |||||
virtual bool intersects(const sphere<T>& sphere) const = 0; | |||||
/// Tests for intersection between this bounding volume and an axis-aligned bounding box. | |||||
virtual bool intersects(const aabb<T>& aabb) const = 0; | |||||
/// Tests whether this bounding volume contains a sphere. | |||||
virtual bool contains(const sphere<T>& sphere) const = 0; | |||||
/// Tests whether this bounding volume contains an axis-aligned bounding box. | |||||
virtual bool contains(const aabb<T>& aabb) const = 0; | |||||
/// Tests whether this bounding volume contains a point. | |||||
virtual bool contains(const vector<T, 3>& point) const = 0; | |||||
/// Tests for intersection between this bounding volume and another bounding volume. | |||||
bool intersects(const bounding_volume& volume) const; | |||||
}; | |||||
/// Tests for intersection between this bounding volume and another bounding volume. | |||||
template <class T> | |||||
bool bounding_volume<T>::intersects(const bounding_volume& volume) const | |||||
{ | |||||
const bounding_volume_type type = volume.get_bounding_volume_type(); | |||||
switch (type) | |||||
{ | |||||
case bounding_volume_type::sphere: | |||||
return intersects(static_cast<const sphere<T>&>(volume)); | |||||
break; | |||||
case bounding_volume_type::aabb: | |||||
return intersects(static_cast<const aabb<T>&>(volume)); | |||||
break; | |||||
default: | |||||
throw std::runtime_error("unimplemented"); | |||||
break; | |||||
} | |||||
} | |||||
#endif // ANTKEEPER_BOUNDING_VOLUME_HPP | |||||
@ -0,0 +1,139 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_CONVEX_HULL_HPP | |||||
#define ANTKEEPER_CONVEX_HULL_HPP | |||||
#include <cstdlib> | |||||
#include <vector> | |||||
#include "bounding-volume.hpp" | |||||
#include "plane.hpp" | |||||
#include "sphere.hpp" | |||||
#include "aabb.hpp" | |||||
/** | |||||
* A plane-bounded convex hull. | |||||
*/ | |||||
template <class T> | |||||
struct convex_hull: public bounding_volume<T> | |||||
{ | |||||
/// Vector of planes with descibe the bounds of the convex hull. | |||||
std::vector<plane<T>> planes; | |||||
/** | |||||
* Creates a convex hull. | |||||
* | |||||
* @param size Number of planes the convex hull should accommodate. | |||||
*/ | |||||
convex_hull(std::size_t size); | |||||
/// Creates a convex hull. | |||||
convex_hull(); | |||||
virtual bounding_volume_type get_bounding_volume_type() const; | |||||
virtual bool intersects(const sphere<T>& sphere) const; | |||||
virtual bool intersects(const aabb<T>& aabb) const; | |||||
virtual bool contains(const sphere<T>& sphere) const; | |||||
virtual bool contains(const aabb<T>& aabb) const; | |||||
virtual bool contains(const vector<T, 3>& point) const; | |||||
}; | |||||
template <class T> | |||||
convex_hull<T>::convex_hull(std::size_t size): | |||||
planes(size, plane<T>()) | |||||
{} | |||||
template <class T> | |||||
convex_hull<T>::convex_hull() | |||||
{} | |||||
template <class T> | |||||
inline bounding_volume_type convex_hull<T>::get_bounding_volume_type() const | |||||
{ | |||||
return bounding_volume_type::convex_hull; | |||||
} | |||||
template <class T> | |||||
bool convex_hull<T>::intersects(const sphere<T>& sphere) const | |||||
{ | |||||
for (const plane<T>& plane: planes) | |||||
if (signed_distance(plane, sphere.center) < -sphere.radius) | |||||
return false; | |||||
return true; | |||||
} | |||||
template <class T> | |||||
bool convex_hull<T>::intersects(const aabb<T>& aabb) const | |||||
{ | |||||
vector<T, 3> pv; | |||||
for (const plane<T>& plane: planes) | |||||
{ | |||||
pv.x = (plane.normal.x > T(0)) ? aabb.max_point.x : aabb.min_point.x; | |||||
pv.y = (plane.normal.y > T(0)) ? aabb.max_point.y : aabb.min_point.y; | |||||
pv.z = (plane.normal.z > T(0)) ? aabb.max_point.z : aabb.min_point.z; | |||||
if (signed_distance(plane, pv) < T(0)) | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
template <class T> | |||||
bool convex_hull<T>::contains(const sphere<T>& sphere) const | |||||
{ | |||||
for (const plane<T>& plane: planes) | |||||
if (signed_distance(plane, sphere.center) < sphere.radius) | |||||
return false; | |||||
return true; | |||||
} | |||||
template <class T> | |||||
bool convex_hull<T>::contains(const aabb<T>& aabb) const | |||||
{ | |||||
vector<T, 3> pv; | |||||
vector<T, 3> nv; | |||||
for (const plane<T>& plane: planes) | |||||
{ | |||||
pv.x = (plane.normal.x > T(0)) ? aabb.max_point.x : aabb.min_point.x; | |||||
pv.y = (plane.normal.y > T(0)) ? aabb.max_point.y : aabb.min_point.y; | |||||
pv.z = (plane.normal.z > T(0)) ? aabb.max_point.z : aabb.min_point.z; | |||||
nv.x = (plane.normal.x < T(0)) ? aabb.max_point.x : aabb.min_point.x; | |||||
nv.y = (plane.normal.y < T(0)) ? aabb.max_point.y : aabb.min_point.y; | |||||
nv.z = (plane.normal.z < T(0)) ? aabb.max_point.z : aabb.min_point.z; | |||||
if (signed_distance(plane, pv) < T(0) || signed_distance(plane, nv) < T(0)) | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
template <class T> | |||||
bool convex_hull<T>::contains(const vector<T, 3>& point) const | |||||
{ | |||||
for (const plane<T>& plane: planes) | |||||
if (signed_distance(plane, point) < T(0)) | |||||
return false; | |||||
return true; | |||||
} | |||||
#endif // ANTKEEPER_CONVEX_HULL_HPP | |||||
@ -0,0 +1,115 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "csg.hpp" | |||||
#include <tuple> | |||||
namespace csg { | |||||
enum class polygon_classification | |||||
{ | |||||
coplanar, | |||||
front, | |||||
back, | |||||
spanning | |||||
}; | |||||
/** | |||||
* Classifies a polygon relative to a partitioning plane. | |||||
* | |||||
* @param partition Partitioning plane relative to which the polygon should be classified. | |||||
* @param poly Polygon to be classified. | |||||
* @return Classification of the polygon, relative to the plane. | |||||
*/ | |||||
static polygon_classification classify_polygon(const plane& partition, const polygon& poly) | |||||
{ | |||||
for (const float3& vertex: poly.vertices) | |||||
{ | |||||
} | |||||
return polygon_classification::coplanar; | |||||
} | |||||
/** | |||||
* Splits a polygon along a partitioning plane. | |||||
* | |||||
* @param poly Polygon to split. | |||||
* @param partition Partitioning plane along which the polygon should be split. | |||||
* @return List of polygons which were formed by splitting the specified polygon along the partitioning plane, along with their respective classifications relative to the partition. | |||||
*/ | |||||
std::list<std::tuple<polygon, polygon_classification>> split_polygon(const polygon& poly, const plane& partition) | |||||
{ | |||||
return {}; | |||||
} | |||||
bsp_tree::bsp_tree(const std::list<polygon>& polygons): | |||||
front(nullptr), | |||||
back(nullptr) | |||||
{ | |||||
//partition = polygons.front(); | |||||
std::list<polygon> front_polygons; | |||||
std::list<polygon> back_polygons; | |||||
// Classify all polygons relative to this node's partitioning plane | |||||
for (const polygon& p: polygons) | |||||
{ | |||||
polygon_classification classification = classify_polygon(partition, p); | |||||
switch (classification) | |||||
{ | |||||
case polygon_classification::coplanar: | |||||
coplanar_polygons.push_back(p); | |||||
break; | |||||
case polygon_classification::front: | |||||
front_polygons.push_back(p); | |||||
break; | |||||
case polygon_classification::back: | |||||
back_polygons.push_back(p); | |||||
break; | |||||
case polygon_classification::spanning: | |||||
break; | |||||
} | |||||
} | |||||
if (!front_polygons.empty()) | |||||
{ | |||||
// Make subtree containing all polygons in front of this node's plane | |||||
front = new bsp_tree(front_polygons); | |||||
} | |||||
if (!back_polygons.empty()) | |||||
{ | |||||
// Make subtree containing all polygons behind this node's plane | |||||
back = new bsp_tree(back_polygons); | |||||
} | |||||
} | |||||
bsp_tree::~bsp_tree() | |||||
{ | |||||
delete front; | |||||
delete back; | |||||
} | |||||
} // namespace csg | |||||
@ -0,0 +1,88 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_CSG_HPP | |||||
#define ANTKEEPER_CSG_HPP | |||||
#include <list> | |||||
#include <vmq/vmq.hpp> | |||||
namespace csg { | |||||
using vmq::float3; | |||||
using vmq::float4; | |||||
struct plane | |||||
{ | |||||
float3 normal; | |||||
float distance; | |||||
}; | |||||
struct polygon | |||||
{ | |||||
std::list<float3> vertices; | |||||
void* shared; | |||||
}; | |||||
/** | |||||
* 3D solid represented by a collection of polygons. | |||||
*/ | |||||
typedef std::list<polygon> solid; | |||||
/** | |||||
* BSP tree node. | |||||
*/ | |||||
class bsp_tree | |||||
{ | |||||
public: | |||||
/** | |||||
* Recursively constructs a BSP tree from a collection of polygons. | |||||
* | |||||
* @param polygons Collection of polygons from which to create the BSP tree. | |||||
*/ | |||||
explicit bsp_tree(const std::list<polygon>& polygons); | |||||
/** | |||||
* Destroys a BSP tree. | |||||
*/ | |||||
~bsp_tree(); | |||||
private: | |||||
/// Partition which separates the front and back polygons. | |||||
plane partition; | |||||
/// Set of polygons which are coplanar with the partition. | |||||
std::list<polygon> coplanar_polygons; | |||||
/// Subtree containing all polygons in front of the partition. | |||||
bsp_tree* front; | |||||
/// Subtree containing all polygons behind the partition. | |||||
bsp_tree* back; | |||||
}; | |||||
solid op_union(const solid& a, const solid& b); | |||||
solid op_difference(const solid& a, const solid& b); | |||||
solid op_intersect(const solid& a, const solid& b); | |||||
} // namespace csg | |||||
#endif // ANTKEEPER_CSG_HPP | |||||
@ -0,0 +1,184 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "intersection.hpp" | |||||
#include <limits> | |||||
std::tuple<bool, float> ray_plane_intersection(const ray<float>& ray, const plane<float>& plane) | |||||
{ | |||||
float denom = vmq::dot(ray.direction, plane.normal); | |||||
if (denom != 0.0f) | |||||
{ | |||||
float t = -(vmq::dot(ray.origin, plane.normal) + plane.distance) / denom; | |||||
if (t >= 0.0f) | |||||
{ | |||||
return std::make_tuple(true, t); | |||||
} | |||||
} | |||||
return std::make_tuple(false, std::numeric_limits<float>::infinity()); | |||||
} | |||||
std::tuple<bool, float, float, float> ray_triangle_intersection(const ray<float>& ray, const float3& a, const float3& b, const float3& c) | |||||
{ | |||||
// Find edges | |||||
float3 edge10 = b - a; | |||||
float3 edge20 = c - a; | |||||
// Calculate determinant | |||||
float3 pv = vmq::cross(ray.direction, edge20); | |||||
float det = vmq::dot(edge10, pv); | |||||
if (!det) | |||||
{ | |||||
return std::make_tuple(false, std::numeric_limits<float>::infinity(), 0.0f, 0.0f); | |||||
} | |||||
float inverse_det = 1.0f / det; | |||||
// Calculate u | |||||
float3 tv = ray.origin - a; | |||||
float u = vmq::dot(tv, pv) * inverse_det; | |||||
if (u < 0.0f || u > 1.0f) | |||||
{ | |||||
return std::make_tuple(false, std::numeric_limits<float>::infinity(), 0.0f, 0.0f); | |||||
} | |||||
// Calculate v | |||||
float3 qv = vmq::cross(tv, edge10); | |||||
float v = vmq::dot(ray.direction, qv) * inverse_det; | |||||
if (v < 0.0f || u + v > 1.0f) | |||||
{ | |||||
return std::make_tuple(false, std::numeric_limits<float>::infinity(), 0.0f, 0.0f); | |||||
} | |||||
// Calculate t | |||||
float t = vmq::dot(edge20, qv) * inverse_det; | |||||
if (t > 0.0f) | |||||
{ | |||||
return std::make_tuple(true, t, u, v); | |||||
} | |||||
return std::make_tuple(false, std::numeric_limits<float>::infinity(), 0.0f, 0.0f); | |||||
} | |||||
std::tuple<bool, float, float> ray_aabb_intersection(const ray<float>& ray, const aabb<float>& aabb) | |||||
{ | |||||
float t0 = -std::numeric_limits<float>::infinity(); | |||||
float t1 = std::numeric_limits<float>::infinity(); | |||||
for (std::size_t i = 0; i < 3; ++i) | |||||
{ | |||||
if (ray.direction[i] == 0.0f) | |||||
{ | |||||
if (ray.origin[i] < aabb.min_point[i] || ray.origin[i] > aabb.max_point[i]) | |||||
{ | |||||
return std::make_tuple(false, std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity()); | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
float tmin = (aabb.min_point[i] - ray.origin[i]) / ray.direction[i]; | |||||
float tmax = (aabb.max_point[i] - ray.origin[i]) / ray.direction[i]; | |||||
t0 = std::max(t0, std::min(tmin, tmax)); | |||||
t1 = std::min(t1, std::max(tmin, tmax)); | |||||
} | |||||
} | |||||
if (t0 > t1 || t1 < 0.0f) | |||||
{ | |||||
return std::make_tuple(false, std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity()); | |||||
} | |||||
return std::make_tuple(true, t0, t1); | |||||
} | |||||
std::tuple<bool, float, float, std::size_t, std::size_t> ray_mesh_intersection(const ray<float>& ray, const mesh& mesh) | |||||
{ | |||||
const std::vector<mesh::face*>& triangles = mesh.get_faces(); | |||||
bool intersection = false; | |||||
float t0 = std::numeric_limits<float>::infinity(); | |||||
float t1 = -std::numeric_limits<float>::infinity(); | |||||
std::size_t index0 = triangles.size(); | |||||
std::size_t index1 = triangles.size(); | |||||
for (std::size_t i = 0; i < triangles.size(); ++i) | |||||
{ | |||||
const mesh::face* triangle = triangles[i]; | |||||
const float3& a = reinterpret_cast<const float3&>(triangle->edge->vertex->position); | |||||
const float3& b = reinterpret_cast<const float3&>(triangle->edge->next->vertex->position); | |||||
const float3& c = reinterpret_cast<const float3&>(triangle->edge->previous->vertex->position); | |||||
auto result = ray_triangle_intersection(ray, a, b, c); | |||||
if (std::get<0>(result)) | |||||
{ | |||||
intersection = true; | |||||
float t = std::get<1>(result); | |||||
if (t < t0) | |||||
{ | |||||
t0 = t; | |||||
index0 = i; | |||||
} | |||||
if (t > t1) | |||||
{ | |||||
t1 = t; | |||||
index1 = i; | |||||
} | |||||
} | |||||
} | |||||
return std::make_tuple(intersection, t0, t1, index0, index1); | |||||
} | |||||
bool aabb_aabb_intersection(const aabb<float>& a, const aabb<float>& b) | |||||
{ | |||||
if (a.max_point.x < b.min_point.x || a.min_point.x > b.max_point.x) | |||||
return false; | |||||
if (a.max_point.y < b.min_point.y || a.min_point.y > b.max_point.y) | |||||
return false; | |||||
if (a.max_point.z < b.min_point.z || a.min_point.z > b.max_point.z) | |||||
return false; | |||||
return true; | |||||
} | |||||
bool aabb_sphere_intersection(const aabb<float>& aabb, const float3& center, float radius) | |||||
{ | |||||
float distance_squared = 0.0f; | |||||
for (int i = 0; i < 3; ++i) | |||||
{ | |||||
float v = center[i]; | |||||
if (v < aabb.min_point[i]) | |||||
distance_squared += (aabb.min_point[i] - v) * (aabb.min_point[i] - v); | |||||
if (v > aabb.max_point[i]) | |||||
distance_squared += (v - aabb.max_point[i]) * (v - aabb.max_point[i]); | |||||
} | |||||
return (distance_squared <= (radius * radius)); | |||||
} | |||||
@ -0,0 +1,54 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_INTERSECTION_HPP | |||||
#define ANTKEEPER_INTERSECTION_HPP | |||||
#include <tuple> | |||||
#include <vmq/vmq.hpp> | |||||
#include "aabb.hpp" | |||||
#include "mesh.hpp" | |||||
#include "plane.hpp" | |||||
#include "ray.hpp" | |||||
using namespace vmq::types; | |||||
using namespace vmq::operators; | |||||
/** | |||||
* Tests for intersection between a ray and a plane. | |||||
* | |||||
* @param ray Ray to test for intersection. | |||||
* @param plane Plane to test for intersection. | |||||
* @return Tuple containing a boolean indicating whether intersection occurred, and a float indicating the signed distance along the ray to the point of intersection. | |||||
*/ | |||||
std::tuple<bool, float> ray_plane_intersection(const ray<float>& ray, const plane<float>& plane); | |||||
std::tuple<bool, float, float, float> ray_triangle_intersection(const ray<float>& ray, const float3& a, const float3& b, const float3& c); | |||||
std::tuple<bool, float, float> ray_aabb_intersection(const ray<float>& ray, const aabb<float>& aabb); | |||||
std::tuple<bool, float, float, std::size_t, std::size_t> ray_mesh_intersection(const ray<float>& ray, const mesh& mesh); | |||||
bool aabb_sphere_intersection(const aabb<float>& aabb, const float3& center, float radius); | |||||
bool aabb_aabb_intersection(const aabb<float>& a, const aabb<float>& b); | |||||
#endif // ANTKEEPER_INTERSECTION_HPP | |||||
@ -0,0 +1,179 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "mesh-accelerator.hpp" | |||||
#include "mesh-functions.hpp" | |||||
#include "morton.hpp" | |||||
#include <iostream> | |||||
#include <bitset> | |||||
mesh_accelerator::mesh_accelerator() | |||||
{} | |||||
void mesh_accelerator::build(const mesh& mesh) | |||||
{ | |||||
// Clear octree and face map | |||||
octree.clear(); | |||||
face_map.clear(); | |||||
// Calculate mesh dimensions | |||||
aabb<float> bounds = calculate_bounds(mesh); | |||||
float3 mesh_dimensions = bounds.max_point - bounds.min_point; | |||||
center_offset = mesh_dimensions * 0.5f - (bounds.min_point + bounds.max_point) * 0.5f; | |||||
// Calculate node dimensions at each octree depth | |||||
for (auto i = 0; i <= octree32::max_depth; ++i) | |||||
{ | |||||
node_dimensions[i] = mesh_dimensions * static_cast<float>((1.0f / std::pow(2, i))); | |||||
} | |||||
// Add faces to octree | |||||
for (mesh::face* face: mesh.get_faces()) | |||||
{ | |||||
// Calculate face bounds | |||||
float3 min_point = reinterpret_cast<const float3&>(face->edge->vertex->position); | |||||
float3 max_point = min_point; | |||||
mesh::edge* edge = face->edge; | |||||
do | |||||
{ | |||||
const auto& position = edge->vertex->position; | |||||
for (int i = 0; i < 3; ++i) | |||||
{ | |||||
min_point[i] = std::min<float>(min_point[i], position[i]); | |||||
max_point[i] = std::max<float>(max_point[i], position[i]); | |||||
} | |||||
edge = edge->next; | |||||
} | |||||
while (edge != face->edge); | |||||
// 1. Find max depth node of aabb min | |||||
// 2. Find max depth node of aabb max | |||||
// 3. Find common ancestor of the two nodes--that's the containing node. | |||||
octree32::node_type min_node = find_node(min_point); | |||||
octree32::node_type max_node = find_node(max_point); | |||||
octree32::node_type containing_node = octree32::common_ancestor(min_node, max_node); | |||||
// Insert containing node into octree | |||||
octree.insert(containing_node); | |||||
// Add face to face map | |||||
face_map[containing_node].push_back(face); | |||||
} | |||||
} | |||||
std::optional<mesh_accelerator::ray_query_result> mesh_accelerator::query_nearest(const ray<float>& ray) const | |||||
{ | |||||
ray_query_result result; | |||||
result.t = std::numeric_limits<float>::infinity(); | |||||
result.face = nullptr; | |||||
query_nearest_recursive(result.t, result.face, octree.root, ray); | |||||
if (result.face) | |||||
return std::optional{result}; | |||||
return std::nullopt; | |||||
} | |||||
void mesh_accelerator::query_nearest_recursive(float& nearest_t, ::mesh::face*& nearest_face, octree32::node_type node, const ray<float>& ray) const | |||||
{ | |||||
// Get node bounds | |||||
const aabb<float> node_bounds = get_node_bounds(node); | |||||
// Test for intersection with node bounds | |||||
auto aabb_intersection = ray_aabb_intersection(ray, node_bounds); | |||||
// If ray passed through this node | |||||
if (std::get<0>(aabb_intersection)) | |||||
{ | |||||
// Test all triangles in the node | |||||
if (auto it = face_map.find(node); it != face_map.end()) | |||||
{ | |||||
const std::list<mesh::face*>& faces = it->second; | |||||
//std::cout << std::bitset<32>(node) << " has " << faces.size() << " faces\n"; | |||||
for (mesh::face* face: faces) | |||||
{ | |||||
// Get triangle coordinates | |||||
const float3& a = reinterpret_cast<const float3&>(face->edge->vertex->position); | |||||
const float3& b = reinterpret_cast<const float3&>(face->edge->next->vertex->position); | |||||
const float3& c = reinterpret_cast<const float3&>(face->edge->previous->vertex->position); | |||||
// Test for intersection with triangle | |||||
auto triangle_intersection = ray_triangle_intersection(ray, a, b, c); | |||||
if (std::get<0>(triangle_intersection)) | |||||
{ | |||||
float t = std::get<1>(triangle_intersection); | |||||
if (t < nearest_t) | |||||
{ | |||||
nearest_t = t; | |||||
nearest_face = face; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
// Test all child nodes | |||||
if (!octree.is_leaf(node)) | |||||
{ | |||||
for (int i = 0; i < 8; ++i) | |||||
query_nearest_recursive(nearest_t, nearest_face, octree.child(node, i), ray); | |||||
} | |||||
} | |||||
} | |||||
aabb<float> mesh_accelerator::get_node_bounds(octree32::node_type node) const | |||||
{ | |||||
// Decode Morton location of node | |||||
auto [x, y, z] = morton::decode_3d(octree32::location(node)); | |||||
float3 node_location = float3{static_cast<float>(x), static_cast<float>(y), static_cast<float>(z)}; | |||||
// Get node dimensions at node depth | |||||
const float3& dimensions = node_dimensions[octree32::depth(node)]; | |||||
// Calculate AABB | |||||
float3 min_point = (node_location * dimensions) - center_offset; | |||||
return aabb<float>{min_point, min_point + dimensions}; | |||||
} | |||||
octree32::node_type mesh_accelerator::find_node(const float3& point) const | |||||
{ | |||||
// Transform point to octree space | |||||
float3 transformed_point = (point + center_offset); | |||||
// Account for floating-point tolerance | |||||
const float epsilon = 0.00001f; | |||||
transformed_point.x = std::max<float>(0.0f, std::min<float>(node_dimensions[0].x - epsilon, transformed_point.x)); | |||||
transformed_point.y = std::max<float>(0.0f, std::min<float>(node_dimensions[0].y - epsilon, transformed_point.y)); | |||||
transformed_point.z = std::max<float>(0.0f, std::min<float>(node_dimensions[0].z - epsilon, transformed_point.z)); | |||||
// Transform point to max-depth node space | |||||
transformed_point = transformed_point / node_dimensions[octree32::max_depth]; | |||||
// Encode transformed point as a Morton location code | |||||
std::uint32_t location = morton::encode_3d( | |||||
static_cast<std::uint32_t>(transformed_point.x), | |||||
static_cast<std::uint32_t>(transformed_point.y), | |||||
static_cast<std::uint32_t>(transformed_point.z)); | |||||
/// Return max depth node at the determined location | |||||
return octree32::node(octree32::max_depth, location); | |||||
} | |||||
@ -0,0 +1,76 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_MESH_ACCELERATOR_HPP | |||||
#define ANTKEEPER_MESH_ACCELERATOR_HPP | |||||
#include "mesh.hpp" | |||||
#include "octree.hpp" | |||||
#include "geometry/aabb.hpp" | |||||
#include "intersection.hpp" | |||||
#include <list> | |||||
#include <unordered_map> | |||||
#include <optional> | |||||
#include <vmq/vmq.hpp> | |||||
using namespace vmq::types; | |||||
using namespace vmq::operators; | |||||
/** | |||||
* Acceleration structure for querying mesh geometry. | |||||
*/ | |||||
class mesh_accelerator | |||||
{ | |||||
public: | |||||
struct ray_query_result | |||||
{ | |||||
float t; | |||||
::mesh::face* face; | |||||
}; | |||||
mesh_accelerator(); | |||||
/** | |||||
* Builds the acceleration structure. | |||||
*/ | |||||
void build(const mesh& mesh); | |||||
/** | |||||
* Finds the first intersection between a ray and a triangle in the mesh. | |||||
* | |||||
* @param ray Ray to test for intersection. | |||||
* @return Ray query result on intersection, and `std::nullopt` if no intersection occurreda. | |||||
*/ | |||||
std::optional<ray_query_result> query_nearest(const ray<float>& ray) const; | |||||
private: | |||||
aabb<float> get_node_bounds(octree32::node_type node) const; | |||||
void query_nearest_recursive(float& nearest_t, ::mesh::face*& nearest_face, octree32::node_type node, const ray<float>& ray) const; | |||||
/// Returns the max-depth node in which the point is located | |||||
octree32::node_type find_node(const float3& point) const; | |||||
octree32 octree; | |||||
float3 node_dimensions[octree32::max_depth + 1]; | |||||
float3 center_offset; | |||||
std::unordered_map<octree32::node_type, std::list<mesh::face*>> face_map; | |||||
}; | |||||
#endif // ANTKEEPER_MESH_ACCELERATOR_HPP | |||||
@ -0,0 +1,122 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "mesh-functions.hpp" | |||||
#include <vmq/vmq.hpp> | |||||
#include <stdexcept> | |||||
#include <unordered_map> | |||||
#include <map> | |||||
#include <iostream> | |||||
using namespace vmq::operators; | |||||
struct edge_hasher | |||||
{ | |||||
std::size_t operator()(const std::array<std::size_t, 2>& v) const noexcept | |||||
{ | |||||
std::size_t hash = std::hash<std::size_t>()(v[0]); | |||||
return hash ^ (std::hash<std::size_t>()(v[1]) + 0x9e3779b9 + (hash << 6) + (hash >> 2)); | |||||
} | |||||
}; | |||||
void create_triangle_mesh(mesh& mesh, const std::vector<float3>& vertices, const std::vector<std::array<std::uint_fast32_t, 3>>& triangles) | |||||
{ | |||||
for (const auto& vertex: vertices) | |||||
mesh.add_vertex(vertex); | |||||
std::unordered_map<std::array<std::size_t, 2>, ::mesh::edge*, edge_hasher> edge_map; | |||||
const std::vector<mesh::vertex*>& mesh_vertices = mesh.get_vertices(); | |||||
std::vector<::mesh::edge*> loop(3); | |||||
for (const auto& triangle: triangles) | |||||
{ | |||||
::mesh::vertex* triangle_vertices[3] = | |||||
{ | |||||
mesh_vertices[triangle[0]], | |||||
mesh_vertices[triangle[1]], | |||||
mesh_vertices[triangle[2]] | |||||
}; | |||||
for (int j = 0; j < 3; ++j) | |||||
{ | |||||
::mesh::vertex* start = triangle_vertices[j]; | |||||
::mesh::vertex* end = triangle_vertices[(j + 1) % 3]; | |||||
if (auto it = edge_map.find({start->index, end->index}); it != edge_map.end()) | |||||
{ | |||||
/* | |||||
if (it->second->face) | |||||
std::cout << "THIS EDGE ALREADY HAS A FACE!\n" << std::endl; | |||||
*/ | |||||
loop[j] = it->second; | |||||
} | |||||
else | |||||
{ | |||||
loop[j] = mesh.add_edge(start, end); | |||||
edge_map[{start->index, end->index}] = loop[j]; | |||||
edge_map[{end->index, start->index}] = loop[j]->symmetric; | |||||
} | |||||
} | |||||
mesh.add_face(loop); | |||||
} | |||||
} | |||||
void calculate_face_normals(float* normals, const mesh& mesh) | |||||
{ | |||||
const std::vector<mesh::face*>& faces = mesh.get_faces(); | |||||
for (std::size_t i = 0; i < faces.size(); ++i) | |||||
{ | |||||
const mesh::face& face = *(faces[i]); | |||||
float3& normal = reinterpret_cast<float3&>(normals[i * 3]); | |||||
const float3& a = reinterpret_cast<const float3&>(face.edge->vertex->position); | |||||
const float3& b = reinterpret_cast<const float3&>(face.edge->next->vertex->position); | |||||
const float3& c = reinterpret_cast<const float3&>(face.edge->previous->vertex->position); | |||||
normal = vmq::normalize(vmq::cross(b - a, c - a)); | |||||
} | |||||
} | |||||
aabb<float> calculate_bounds(const mesh& mesh) | |||||
{ | |||||
float3 bounds_min; | |||||
float3 bounds_max; | |||||
for (int i = 0; i < 3; ++i) | |||||
{ | |||||
bounds_min[i] = std::numeric_limits<float>::infinity(); | |||||
bounds_max[i] = -std::numeric_limits<float>::infinity(); | |||||
} | |||||
for (const mesh::vertex* vertex: mesh.get_vertices()) | |||||
{ | |||||
const auto& position = vertex->position; | |||||
for (int i = 0; i < 3; ++i) | |||||
{ | |||||
bounds_min[i] = std::min<float>(bounds_min[i], position[i]); | |||||
bounds_max[i] = std::max<float>(bounds_max[i], position[i]); | |||||
} | |||||
} | |||||
return aabb<float>{bounds_min, bounds_max}; | |||||
} | |||||
@ -0,0 +1,58 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_MESH_FUNCTIONS_HPP | |||||
#define ANTKEEPER_MESH_FUNCTIONS_HPP | |||||
#include "mesh.hpp" | |||||
#include <vmq/vmq.hpp> | |||||
#include <array> | |||||
#include <vector> | |||||
#include "geometry/aabb.hpp" | |||||
using namespace vmq::types; | |||||
/** | |||||
* Creates a triangle mesh from a list of vertices and indices. | |||||
* | |||||
* @param[out] mesh Mesh to which vertices, edges, and faces will be added. | |||||
* @param vertices Vertex positions | |||||
* @param triangles Triangle indices | |||||
* @return Newly created triangle mesh. | |||||
*/ | |||||
void create_triangle_mesh(mesh& mesh, const std::vector<float3>& vertices, const std::vector<std::array<std::uint_fast32_t, 3>>& triangles); | |||||
/** | |||||
* Calculates normals for each face. | |||||
* | |||||
* @param[out] Array in which normals will be stored. Must be able to hold `3 * face count` floats. | |||||
* @param layer Face layer in which the normals will be stored. Must have three components. | |||||
*/ | |||||
void calculate_face_normals(float* normals, const mesh& mesh); | |||||
void calculate_vertex_normals(float* normals, const mesh& mesh); | |||||
/** | |||||
* Calculates the AABB bounds of a mesh. | |||||
*/ | |||||
aabb<float> calculate_bounds(const mesh& mesh); | |||||
#endif // ANTKEEPER_MESH_FUNCTIONS_HPP | |||||
@ -0,0 +1,332 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "mesh.hpp" | |||||
#include <stdexcept> | |||||
mesh::~mesh() | |||||
{ | |||||
// Deallocate vertices | |||||
for (mesh::vertex* vertex: vertices) | |||||
{ | |||||
delete vertex; | |||||
} | |||||
// Deallocate edges | |||||
for (mesh::edge* edge: edges) | |||||
{ | |||||
delete edge->symmetric; | |||||
delete edge; | |||||
} | |||||
// Deallocate faces | |||||
for (mesh::face* face: faces) | |||||
{ | |||||
delete face; | |||||
} | |||||
} | |||||
mesh::vertex* mesh::add_vertex(const std::array<float, 3>& position) | |||||
{ | |||||
mesh::vertex* vertex = new mesh::vertex(); | |||||
vertex->edge = nullptr; | |||||
vertex->position = position; | |||||
vertex->index = vertices.size(); | |||||
vertices.push_back(vertex); | |||||
return vertex; | |||||
} | |||||
mesh::edge* mesh::add_edge(mesh::vertex* a, mesh::vertex* b) | |||||
{ | |||||
mesh::edge* ab = new mesh::edge(); | |||||
mesh::edge* ba = new mesh::edge(); | |||||
ab->vertex = a; | |||||
ab->face = nullptr; | |||||
ab->previous = ba; | |||||
ab->next = ba; | |||||
ab->symmetric = ba; | |||||
ab->index = edges.size(); | |||||
ba->vertex = b; | |||||
ba->face = nullptr; | |||||
ba->previous = ab; | |||||
ba->next = ab; | |||||
ba->symmetric = ab; | |||||
ba->index = edges.size(); | |||||
if (!a->edge) | |||||
{ | |||||
a->edge = ab; | |||||
} | |||||
else | |||||
{ | |||||
mesh::edge* a_in = find_free_incident(a); | |||||
mesh::edge* a_out = a_in->next; | |||||
a_in->next = ab; | |||||
ab->previous = a_in; | |||||
ba->next = a_out; | |||||
a_out->previous = ba; | |||||
} | |||||
if (!b->edge) | |||||
{ | |||||
b->edge = ba; | |||||
} | |||||
else | |||||
{ | |||||
mesh::edge* b_in = find_free_incident(b); | |||||
mesh::edge* b_out = b_in->next; | |||||
b_in->next = ba; | |||||
ba->previous = b_in; | |||||
ab->next = b_out; | |||||
b_out->previous = ab; | |||||
} | |||||
// Add edge | |||||
edges.push_back(ab); | |||||
return ab; | |||||
} | |||||
mesh::face* mesh::add_face(const loop& loop) | |||||
{ | |||||
if (loop.empty()) | |||||
{ | |||||
throw std::runtime_error("Empty edge loop"); | |||||
} | |||||
// Validate edge loop | |||||
for (std::size_t i = 0; i < loop.size(); ++i) | |||||
{ | |||||
mesh::edge* current = loop[i]; | |||||
mesh::edge* next = loop[(i + 1) % loop.size()]; | |||||
if (current->symmetric->vertex != next->vertex) | |||||
{ | |||||
// Disconnected edge loop | |||||
throw std::runtime_error("Disconnected edge loop"); | |||||
} | |||||
if (current->face) | |||||
{ | |||||
// This edge already has a face | |||||
throw std::runtime_error("Non-manifold mesh 1"); | |||||
} | |||||
} | |||||
// Make edges adjacent | |||||
for (std::size_t i = 0; i < loop.size(); ++i) | |||||
{ | |||||
if (!make_adjacent(loop[i], loop[(i + 1) % loop.size()])) | |||||
{ | |||||
throw std::runtime_error("Non-manifold mesh 2"); | |||||
} | |||||
} | |||||
// Create face | |||||
mesh::face* face = new mesh::face(); | |||||
face->edge = loop[0]; | |||||
face->index = faces.size(); | |||||
// Add face | |||||
faces.push_back(face); | |||||
// Connect edges to the face | |||||
for (mesh::edge* edge: loop) | |||||
{ | |||||
edge->face = face; | |||||
} | |||||
return face; | |||||
} | |||||
void mesh::remove_face(mesh::face* face) | |||||
{ | |||||
// Nullify pointers to this face | |||||
mesh::edge* edge = face->edge; | |||||
do | |||||
{ | |||||
edge->face = nullptr; | |||||
edge = edge->next; | |||||
} | |||||
while (edge != face->edge); | |||||
// Adjust indices of faces after this face | |||||
for (std::size_t i = face->index + 1; i < faces.size(); ++i) | |||||
{ | |||||
--faces[i]->index; | |||||
} | |||||
// Remove face from the faces vector | |||||
faces.erase(faces.begin() + face->index); | |||||
// Deallocate face | |||||
delete face; | |||||
} | |||||
void mesh::remove_edge(mesh::edge* edge) | |||||
{ | |||||
mesh::edge* ab = edge; | |||||
mesh::edge* ba = edge->symmetric; | |||||
mesh::vertex* a = ab->vertex; | |||||
mesh::edge* a_in = ab->previous; | |||||
mesh::edge* a_out = ba->next; | |||||
mesh::vertex* b = ba->vertex; | |||||
mesh::edge* b_in = ba->previous; | |||||
mesh::edge* b_out = ab->next; | |||||
// Remove dependent faces | |||||
if (ab->face) | |||||
remove_face(ab->face); | |||||
if (ba->face) | |||||
remove_face(ba->face); | |||||
// Re-link edges | |||||
if (a->edge == ab) | |||||
a->edge = (a_out == ab) ? nullptr : a_out; | |||||
if (b->edge == ba) | |||||
b->edge = (b_out == ba) ? nullptr : b_out; | |||||
a_in->next = a_out; | |||||
a_out->previous = a_in; | |||||
b_in->next = b_out; | |||||
b_out->previous = b_in; | |||||
// Adjust indices of edges after this edge | |||||
for (std::size_t i = edge->index + 1; i < edges.size(); ++i) | |||||
{ | |||||
--edges[i]->index; | |||||
--edges[i]->symmetric->index; | |||||
} | |||||
// Remove edge from the edges vector | |||||
edges.erase(edges.begin() + edge->index); | |||||
// Deallocate edge | |||||
delete edge->symmetric; | |||||
delete edge; | |||||
} | |||||
void mesh::remove_vertex(mesh::vertex* vertex) | |||||
{ | |||||
// Remove connected edges | |||||
if (vertex->edge) | |||||
{ | |||||
mesh::edge* current = nullptr; | |||||
mesh::edge* next = vertex->edge; | |||||
do | |||||
{ | |||||
current = next; | |||||
next = next->symmetric->next; | |||||
if (next == current) | |||||
{ | |||||
next = next->symmetric->next; | |||||
} | |||||
remove_edge(current); | |||||
} | |||||
while (current != next); | |||||
} | |||||
// Adjust indices of vertices after this vertex | |||||
for (std::size_t i = vertex->index + 1; i < vertices.size(); ++i) | |||||
{ | |||||
--vertices[i]->index; | |||||
} | |||||
// Remove vertex from the vertices vector | |||||
vertices.erase(vertices.begin() + vertex->index); | |||||
// Deallocate vertex | |||||
delete vertex; | |||||
} | |||||
mesh::edge* mesh::find_free_incident(mesh::vertex* vertex) const | |||||
{ | |||||
mesh::edge* begin = vertex->edge->symmetric; | |||||
mesh::edge* current = begin; | |||||
do | |||||
{ | |||||
if (!current->face) | |||||
{ | |||||
return current; | |||||
} | |||||
current = current->next->symmetric; | |||||
} | |||||
while (current != begin); | |||||
return nullptr; | |||||
} | |||||
mesh::edge* mesh::find_free_incident(mesh::edge* start_edge, mesh::edge* end_edge) const | |||||
{ | |||||
if (start_edge == end_edge) | |||||
{ | |||||
return nullptr; | |||||
} | |||||
mesh::edge* current = start_edge; | |||||
do | |||||
{ | |||||
if (!current->face) | |||||
{ | |||||
return current; | |||||
} | |||||
current = current->next->symmetric; | |||||
} | |||||
while (current != end_edge); | |||||
return nullptr; | |||||
} | |||||
bool mesh::make_adjacent(mesh::edge* in, mesh::edge* out) | |||||
{ | |||||
if (in->next == out) | |||||
{ | |||||
return true; | |||||
} | |||||
mesh::edge* b = in->next; | |||||
mesh::edge* d = out->previous; | |||||
mesh::edge* g = find_free_incident(out->symmetric, in); | |||||
if (!g) | |||||
{ | |||||
return false; | |||||
} | |||||
mesh::edge* h = g->next; | |||||
in->next = out; | |||||
out->previous = in; | |||||
g->next = b; | |||||
b->previous = g; | |||||
d->next = h; | |||||
h->previous = d; | |||||
return true; | |||||
} | |||||
@ -0,0 +1,181 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_MESH_HPP | |||||
#define ANTKEEPER_MESH_HPP | |||||
#include <array> | |||||
#include <vector> | |||||
/** | |||||
* Half-edge mesh. | |||||
* | |||||
* @see http://kaba.hilvi.org/homepage/blog/halfedge/halfedge.htm | |||||
*/ | |||||
class mesh | |||||
{ | |||||
public: | |||||
struct vertex; | |||||
struct edge; | |||||
struct face; | |||||
typedef std::vector<edge*> loop; | |||||
/** | |||||
* Creates a mesh. | |||||
*/ | |||||
mesh() = default; | |||||
/** | |||||
* Destroys a mesh. | |||||
*/ | |||||
~mesh(); | |||||
/** | |||||
* Adds a vertex to the mesh. This vertex initially has a null edge. | |||||
* | |||||
* @param position Position of the vertex. | |||||
* @return Pointer to the added vertex. | |||||
*/ | |||||
mesh::vertex* add_vertex(const std::array<float, 3>& position); | |||||
/** | |||||
* Adds an edge to the mesh. | |||||
* | |||||
* @param a The vertex from which the edge originates. | |||||
* @param b The vertex at which the edge ends. | |||||
* @return Pointer to the added edge. | |||||
*/ | |||||
mesh::edge* add_edge(mesh::vertex* a, mesh::vertex* b); | |||||
/** | |||||
* Adds a face to the mesh. | |||||
* | |||||
* @param loop List of edges which form the face. | |||||
* @return Pointer to the added face. | |||||
*/ | |||||
mesh::face* add_face(const loop& loop); | |||||
/** | |||||
* Removes a face from the mesh. | |||||
* | |||||
* @param face Face to be removed. This face will be deallocated after removal. | |||||
*/ | |||||
void remove_face(mesh::face* face); | |||||
/** | |||||
* Removes an edge and all dependent faces from the mesh. | |||||
* | |||||
* @param edge Edge to be removed. This edge will be deallocated after removal. | |||||
*/ | |||||
void remove_edge(mesh::edge* edge); | |||||
/** | |||||
* Removes a vertex, all dependent edges, and all dependent faces from the mesh. | |||||
* | |||||
* @param vertex Vertex to be removed. This vertex will be deallocated after removal. | |||||
*/ | |||||
void remove_vertex(mesh::vertex* vertex); | |||||
/// Returns the mesh vertices | |||||
const std::vector<mesh::vertex*>& get_vertices() const; | |||||
/// Returns the mesh edges | |||||
const std::vector<mesh::edge*>& get_edges() const; | |||||
/// Returns the mesh faces | |||||
const std::vector<mesh::face*>& get_faces() const; | |||||
/** | |||||
* Half-edge vertex which contains a pointer to its parent edge, a position vector, and an index. | |||||
*/ | |||||
struct vertex | |||||
{ | |||||
/// Pointer to the edge to which this vertex belongs | |||||
mesh::edge* edge; | |||||
/// Vertex position | |||||
std::array<float, 3> position; | |||||
/// Index of this vertex | |||||
std::size_t index; | |||||
}; | |||||
/** | |||||
* Half-edge edge which contains pointers to its starting vertex, parent face, and related edges. | |||||
*/ | |||||
struct edge | |||||
{ | |||||
/// Pointer to the vertex at which the edge starts | |||||
mesh::vertex* vertex; | |||||
/// Pointer to the face on the left of this edge | |||||
mesh::face* face; | |||||
/// Pointer to the previous edge in the parent face | |||||
mesh::edge* previous; | |||||
/// Pointer to the next edge in the parent face | |||||
mesh::edge* next; | |||||
/// Pointer to the symmetric edge | |||||
mesh::edge* symmetric; | |||||
/// Index of this edge | |||||
std::size_t index; | |||||
}; | |||||
/** | |||||
* Half-edge face which contains a pointer to its first edge and its normal vector. | |||||
*/ | |||||
struct face | |||||
{ | |||||
/// Pointer to the first edge in this face | |||||
mesh::edge* edge; | |||||
/// Index of this face | |||||
std::size_t index; | |||||
}; | |||||
private: | |||||
mesh::edge* find_free_incident(mesh::vertex* vertex) const; | |||||
mesh::edge* find_free_incident(mesh::edge* start_edge, mesh::edge* end_edge) const; | |||||
bool make_adjacent(mesh::edge* in_edge, mesh::edge* out_edge); | |||||
std::vector<mesh::vertex*> vertices; | |||||
std::vector<mesh::edge*> edges; | |||||
std::vector<mesh::face*> faces; | |||||
}; | |||||
inline const std::vector<mesh::vertex*>& mesh::get_vertices() const | |||||
{ | |||||
return vertices; | |||||
} | |||||
inline const std::vector<mesh::edge*>& mesh::get_edges() const | |||||
{ | |||||
return edges; | |||||
} | |||||
inline const std::vector<mesh::face*>& mesh::get_faces() const | |||||
{ | |||||
return faces; | |||||
} | |||||
#endif // ANTKEEPER_MESH_HPP | |||||
@ -0,0 +1,112 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_PLANE_HPP | |||||
#define ANTKEEPER_PLANE_HPP | |||||
#include <vmq/vmq.hpp> | |||||
using vmq::vector; | |||||
using namespace vmq::operators; | |||||
template <class T> | |||||
struct plane | |||||
{ | |||||
vector<T, 3> normal; | |||||
T distance; | |||||
/** | |||||
* Creates a plane given a normal vector and distance. | |||||
*/ | |||||
plane(const vector<T, 3>& normal, T distance); | |||||
/** | |||||
* Creates a plane given a normal vector and offset vector. | |||||
*/ | |||||
plane(const vector<T, 3>& normal, const vector<T, 3>& offset); | |||||
/** | |||||
* Creates a plane given three points. | |||||
*/ | |||||
plane(const vector<T, 3>& a, const vector<T, 3>& b, const vector<T, 3>& c); | |||||
/** | |||||
* Creates a plane given its coefficients. | |||||
* | |||||
* @param coefficients Vector containing the plane coefficients, A, B, C and D, as x, y, z, and w, respectively. | |||||
*/ | |||||
plane(const vector<T, 4>& coefficients); | |||||
/// Creates an uninitialized plane. | |||||
plane() = default; | |||||
}; | |||||
template <class T> | |||||
inline plane<T>::plane(const vector<T, 3>& normal, T distance): | |||||
normal(normal), | |||||
distance(distance) | |||||
{} | |||||
template <class T> | |||||
plane<T>::plane(const vector<T, 3>& normal, const vector<T, 3>& offset): | |||||
normal(normal), | |||||
distance(-vmq::dot(normal, offset)) | |||||
{} | |||||
template <class T> | |||||
plane<T>::plane(const vector<T, 3>& a, const vector<T, 3>& b, const vector<T, 3>& c) | |||||
{ | |||||
normal = vmq::normalize(vmq::cross(c - b, a - b)); | |||||
distance = -(vmq::dot(normal, b)); | |||||
} | |||||
template <class T> | |||||
plane<T>::plane(const vector<T, 4>& coefficients) | |||||
{ | |||||
const vector<T, 3> abc = vmq::resize<3>(coefficients); | |||||
const float inverse_length = T(1) / vmq::length(abc); | |||||
normal = abc * inverse_length; | |||||
distance = coefficients[3] * inverse_length; | |||||
} | |||||
/** | |||||
* Calculates the signed distance between a plane and a vector. | |||||
* | |||||
* @param p Plane. | |||||
* @param v Vector. | |||||
* @return Signed distance between the plane and a vector. | |||||
*/ | |||||
template <class T> | |||||
inline T signed_distance(const plane<T>& p, const vector<T, 3>& v) | |||||
{ | |||||
return p.distance + vmq::dot(p.normal, v); | |||||
} | |||||
/** | |||||
* Calculates the point of intersection between three planes. | |||||
*/ | |||||
template <class T> | |||||
vector<T, 3> intersection(const plane<T>& p0, const plane<T>& p1, const plane<T>& p2) | |||||
{ | |||||
return -(p0.distance * vmq::cross(p1.normal, p2.normal) + p1.distance * vmq::cross(p2.normal, p0.normal) + p2.distance * vmq::cross(p0.normal, p1.normal)) / vmq::dot(p0.normal, vmq::cross(p1.normal, p2.normal)); | |||||
} | |||||
#endif // ANTKEEPER_PLANE_HPP | |||||
@ -0,0 +1,44 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_RAY_HPP | |||||
#define ANTKEEPER_RAY_HPP | |||||
#include <vmq/vmq.hpp> | |||||
using vmq::vector; | |||||
using namespace vmq::operators; | |||||
template <class T> | |||||
struct ray | |||||
{ | |||||
vector<T, 3> origin; | |||||
vector<T, 3> direction; | |||||
vector<T, 3> extrapolate(T distance) const; | |||||
}; | |||||
template <class T> | |||||
inline vector<T, 3> ray<T>::extrapolate(T distance) const | |||||
{ | |||||
return origin + direction * distance; | |||||
} | |||||
#endif // ANTKEEPER_RAY_HPP | |||||
@ -0,0 +1,112 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_SPHERE_HPP | |||||
#define ANTKEEPER_SPHERE_HPP | |||||
#include "bounding-volume.hpp" | |||||
#include "aabb.hpp" | |||||
#include <vmq/vmq.hpp> | |||||
#include <algorithm> | |||||
using vmq::vector; | |||||
using namespace vmq::operators; | |||||
template <class T> | |||||
struct sphere: public bounding_volume<T> | |||||
{ | |||||
vector<T, 3> center; | |||||
T radius; | |||||
sphere(const vector<T, 3>& center, T radius); | |||||
sphere(); | |||||
virtual bounding_volume_type get_bounding_volume_type() const; | |||||
virtual bool intersects(const sphere<T>& sphere) const; | |||||
virtual bool intersects(const aabb<T>& aabb) const; | |||||
virtual bool contains(const sphere<T>& sphere) const; | |||||
virtual bool contains(const aabb<T>& aabb) const; | |||||
virtual bool contains(const vector<T, 3>& point) const; | |||||
}; | |||||
template <class T> | |||||
sphere<T>::sphere(const vector<T, 3>& center, T radius): | |||||
center(center), | |||||
radius(radius) | |||||
{} | |||||
template <class T> | |||||
sphere<T>::sphere() | |||||
{} | |||||
template <class T> | |||||
inline bounding_volume_type sphere<T>::get_bounding_volume_type() const | |||||
{ | |||||
return bounding_volume_type::sphere; | |||||
} | |||||
template <class T> | |||||
bool sphere<T>::intersects(const sphere<T>& sphere) const | |||||
{ | |||||
vector<T, 3> d = center - sphere.center; | |||||
float r = radius + sphere.radius; | |||||
return (vmq::dot(d, d) <= r * r); | |||||
} | |||||
template <class T> | |||||
bool sphere<T>::intersects(const aabb<T>& aabb) const | |||||
{ | |||||
return aabb.intersects(*this); | |||||
} | |||||
template <class T> | |||||
bool sphere<T>::contains(const sphere<T>& sphere) const | |||||
{ | |||||
float containment_radius = radius - sphere.radius; | |||||
if (containment_radius < T(0)) | |||||
return false; | |||||
vector<T, 3> d = center - sphere.center; | |||||
return (vmq::dot(d, d) <= containment_radius * containment_radius); | |||||
} | |||||
template <class T> | |||||
bool sphere<T>::contains(const aabb<T>& aabb) const | |||||
{ | |||||
T distance = T(0); | |||||
vector<T, 3> a = center - aabb.min_point; | |||||
vector<T, 3> b = center - aabb.max_point; | |||||
distance += std::max(a.x * a.x, b.x * b.x); | |||||
distance += std::max(a.y * a.y, b.y * b.y); | |||||
distance += std::max(a.z * a.z, b.z * b.z); | |||||
return (distance <= radius * radius); | |||||
} | |||||
template <class T> | |||||
bool sphere<T>::contains(const vector<T, 3>& point) const | |||||
{ | |||||
vector<T, 3> d = center - point; | |||||
return (vmq::dot(d, d) <= radius * radius); | |||||
} | |||||
#endif // ANTKEEPER_SPHERE_HPP | |||||
@ -0,0 +1,181 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_VIEW_FRUSTUM_HPP | |||||
#define ANTKEEPER_VIEW_FRUSTUM_HPP | |||||
#include "convex-hull.hpp" | |||||
#include <array> | |||||
#include <vmq/vmq.hpp> | |||||
using vmq::vector; | |||||
using vmq::matrix; | |||||
using namespace vmq::operators; | |||||
template <class T> | |||||
class view_frustum | |||||
{ | |||||
public: | |||||
/** | |||||
* Creates a view frustum from a view-projection matrix. | |||||
* | |||||
* @param view_projection View-projection matrix. | |||||
*/ | |||||
view_frustum(const matrix<T, 4, 4>& view_projection); | |||||
/// Creates an uninitialized view frustum. | |||||
view_frustum(); | |||||
/** | |||||
* Recalculates the view frustum from a view-projection matrix. | |||||
* | |||||
* @param view_projection View-projection matrix. | |||||
*/ | |||||
void set_matrix(const matrix<T, 4, 4>& view_projection); | |||||
/// Returns a convex hull which describes the bounds of the view frustum. | |||||
const convex_hull<T>& get_bounds() const; | |||||
/// Returns the left clipping plane. | |||||
const plane<T>& get_left() const; | |||||
/// Returns the right clipping plane. | |||||
const plane<T>& get_right() const; | |||||
/// Returns the bottom clipping plane. | |||||
const plane<T>& get_bottom() const; | |||||
/// Returns the top clipping plane. | |||||
const plane<T>& get_top() const; | |||||
/// Returns the near clipping plane. | |||||
const plane<T>& get_near() const; | |||||
/// Returns the far clipping plane. | |||||
const plane<T>& get_far() const; | |||||
/** | |||||
* Returns an array containing the corners of the view frustum bounds. | |||||
* | |||||
* @return Array containing the corners of the view frustum bounds. Corners are stored in the following order: NTL, NTR, NBL, NBR, FTL, FTR, FBL, FBR; where N is near, F is far, T is top, B is bottom, L is left, and R is right, therefore NTL refers to the corner shared between the near, top, and left clipping planes. | |||||
*/ | |||||
const std::array<vector<T, 3>, 8>& get_corners() const; | |||||
private: | |||||
void recalculate_planes(const matrix<T, 4, 4>& view_projection); | |||||
void recalculate_corners(); | |||||
convex_hull<T> bounds; | |||||
std::array<vector<T, 3>, 8> corners; | |||||
}; | |||||
template <class T> | |||||
view_frustum<T>::view_frustum(const matrix<T, 4, 4>& view_projection): | |||||
bounds(6) | |||||
{ | |||||
set_matrix(view_projection); | |||||
} | |||||
template <class T> | |||||
view_frustum<T>::view_frustum(): | |||||
view_frustum(vmq::identity4x4<T>) | |||||
{} | |||||
template <class T> | |||||
void view_frustum<T>::set_matrix(const matrix<T, 4, 4>& view_projection) | |||||
{ | |||||
recalculate_planes(view_projection); | |||||
recalculate_corners(); | |||||
} | |||||
template <class T> | |||||
inline const convex_hull<T>& view_frustum<T>::get_bounds() const | |||||
{ | |||||
return bounds; | |||||
} | |||||
template <class T> | |||||
inline const plane<T>& view_frustum<T>::get_left() const | |||||
{ | |||||
return bounds.planes[0]; | |||||
} | |||||
template <class T> | |||||
inline const plane<T>& view_frustum<T>::get_right() const | |||||
{ | |||||
return bounds.planes[1]; | |||||
} | |||||
template <class T> | |||||
inline const plane<T>& view_frustum<T>::get_bottom() const | |||||
{ | |||||
return bounds.planes[2]; | |||||
} | |||||
template <class T> | |||||
inline const plane<T>& view_frustum<T>::get_top() const | |||||
{ | |||||
return bounds.planes[3]; | |||||
} | |||||
template <class T> | |||||
inline const plane<T>& view_frustum<T>::get_near() const | |||||
{ | |||||
return bounds.planes[4]; | |||||
} | |||||
template <class T> | |||||
inline const plane<T>& view_frustum<T>::get_far() const | |||||
{ | |||||
return bounds.planes[5]; | |||||
} | |||||
template <class T> | |||||
inline const std::array<vector<T, 3>, 8>& view_frustum<T>::get_corners() const | |||||
{ | |||||
return corners; | |||||
} | |||||
template <class T> | |||||
void view_frustum<T>::recalculate_planes(const matrix<T, 4, 4>& view_projection) | |||||
{ | |||||
matrix<T, 4, 4> transpose = vmq::transpose(view_projection); | |||||
bounds.planes[0] = plane<T>(transpose[3] + transpose[0]); | |||||
bounds.planes[1] = plane<T>(transpose[3] - transpose[0]); | |||||
bounds.planes[2] = plane<T>(transpose[3] + transpose[1]); | |||||
bounds.planes[3] = plane<T>(transpose[3] - transpose[1]); | |||||
bounds.planes[4] = plane<T>(transpose[3] + transpose[2]); | |||||
bounds.planes[5] = plane<T>(transpose[3] - transpose[2]); | |||||
} | |||||
template <class T> | |||||
void view_frustum<T>::recalculate_corners() | |||||
{ | |||||
corners[0] = intersection(get_near(), get_top(), get_left()); | |||||
corners[1] = intersection(get_near(), get_top(), get_right()); | |||||
corners[2] = intersection(get_near(), get_bottom(), get_left()); | |||||
corners[3] = intersection(get_near(), get_bottom(), get_right()); | |||||
corners[4] = intersection(get_far(), get_top(), get_left()); | |||||
corners[5] = intersection(get_far(), get_top(), get_right()); | |||||
corners[6] = intersection(get_far(), get_bottom(), get_left()); | |||||
corners[7] = intersection(get_far(), get_bottom(), get_right()); | |||||
} | |||||
#endif // ANTKEEPER_VIEW_FRUSTUM_HPP | |||||
@ -0,0 +1,53 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "control-set.hpp" | |||||
#include "control.hpp" | |||||
void control_set::add_control(control* control) | |||||
{ | |||||
controls.push_back(control); | |||||
} | |||||
void control_set::remove_control(control* control) | |||||
{ | |||||
controls.remove(control); | |||||
} | |||||
void control_set::remove_controls() | |||||
{ | |||||
controls.clear(); | |||||
} | |||||
void control_set::update() | |||||
{ | |||||
for (control* control: controls) | |||||
{ | |||||
control->update(); | |||||
} | |||||
} | |||||
void control_set::set_callbacks_enabled(bool enabled) | |||||
{ | |||||
for (control* control: controls) | |||||
{ | |||||
control->set_callbacks_enabled(enabled); | |||||
} | |||||
} | |||||
@ -0,0 +1,81 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_CONTROL_SET_HPP | |||||
#define ANTKEEPER_CONTROL_SET_HPP | |||||
#include <list> | |||||
class control; | |||||
/** | |||||
* A set of controls which can be managed simultaneously. | |||||
* | |||||
* @ingroup input | |||||
*/ | |||||
class control_set | |||||
{ | |||||
public: | |||||
/** | |||||
* Adds a control to the control set. | |||||
* | |||||
* @param control Pointer to the control to add. | |||||
*/ | |||||
void add_control(control* control); | |||||
/** | |||||
* Removes a control from the control set. | |||||
* | |||||
* @param control Pointer to the control to remove. | |||||
*/ | |||||
void remove_control(control* control); | |||||
/** | |||||
* Removes all controls from the control set. | |||||
*/ | |||||
void remove_controls(); | |||||
/** | |||||
* Calls control::update() on each control in this control set. | |||||
*/ | |||||
void update(); | |||||
/** | |||||
* Enables or disables callbacks for all controls in the control set. | |||||
* | |||||
* @param enabled Whether to enable or disable callbacks for all controls in the control set. | |||||
*/ | |||||
void set_callbacks_enabled(bool enabled); | |||||
/** | |||||
* Returns the list of controls in the control set. | |||||
*/ | |||||
const std::list<control*>* get_controls() const; | |||||
private: | |||||
std::list<control*> controls; | |||||
}; | |||||
inline const std::list<control*>* control_set::get_controls() const | |||||
{ | |||||
return &controls; | |||||
} | |||||
#endif // ANTKEEPER_CONTROL_SET_HPP | |||||
@ -0,0 +1,111 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "control.hpp" | |||||
control::control(): | |||||
deadzone(0.0f), | |||||
current_value(0.0f), | |||||
previous_value(0.0f), | |||||
reset(false), | |||||
activated_callback(nullptr), | |||||
deactivated_callback(nullptr), | |||||
value_changed_callback(nullptr), | |||||
callbacks_enabled(true) | |||||
{} | |||||
control::~control() | |||||
{} | |||||
void control::update() | |||||
{ | |||||
// Perform callbacks, if enabled | |||||
if (callbacks_enabled) | |||||
{ | |||||
if (activated_callback) | |||||
{ | |||||
if (is_active() && !was_active()) | |||||
{ | |||||
activated_callback(); | |||||
} | |||||
} | |||||
if (deactivated_callback) | |||||
{ | |||||
if (!is_active() && was_active()) | |||||
{ | |||||
deactivated_callback(); | |||||
} | |||||
} | |||||
if (value_changed_callback) | |||||
{ | |||||
if (current_value != previous_value) | |||||
{ | |||||
if (is_active() || was_active()) | |||||
{ | |||||
value_changed_callback(current_value); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
// Update previous value | |||||
previous_value = current_value; | |||||
// Reset temporary values | |||||
if (reset) | |||||
{ | |||||
current_value = 0.0f; | |||||
reset = false; | |||||
} | |||||
} | |||||
void control::set_current_value(float value) | |||||
{ | |||||
current_value = value; | |||||
reset = false; | |||||
} | |||||
void control::set_temporary_value(float value) | |||||
{ | |||||
current_value = value; | |||||
reset = true; | |||||
} | |||||
void control::set_deadzone(float value) | |||||
{ | |||||
deadzone = value; | |||||
} | |||||
void control::set_activated_callback(std::function<void()> callback) | |||||
{ | |||||
this->activated_callback = callback; | |||||
} | |||||
void control::set_deactivated_callback(std::function<void()> callback) | |||||
{ | |||||
this->deactivated_callback = callback; | |||||
} | |||||
void control::set_value_changed_callback(std::function<void(float)> callback) | |||||
{ | |||||
this->value_changed_callback = callback; | |||||
} | |||||
@ -0,0 +1,136 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_CONTROL_HPP | |||||
#define ANTKEEPER_CONTROL_HPP | |||||
#include <functional> | |||||
/** | |||||
* A control can be bound to multiple types of input events. | |||||
* | |||||
* @ingroup input | |||||
*/ | |||||
class control | |||||
{ | |||||
public: | |||||
/// Creates a control. | |||||
control(); | |||||
/// Destroys a control. | |||||
virtual ~control(); | |||||
/** | |||||
* Performs callbacks then sets the previous value equal to the current value. | |||||
*/ | |||||
void update(); | |||||
/** | |||||
* Sets the current value of the control. | |||||
* | |||||
* @param value control value. | |||||
*/ | |||||
void set_current_value(float value); | |||||
/** | |||||
* This works the same as setting the current value, but causes the value to be reset on the next call to update. | |||||
*/ | |||||
void set_temporary_value(float value); | |||||
/** | |||||
* Sets the deadzone value. If the current value of the control is not greater than the deadzone value, the control will not be considered active. | |||||
* | |||||
* @param value Deadzone value. | |||||
*/ | |||||
void set_deadzone(float value); | |||||
/// Sets the callback for when the control is activated. | |||||
void set_activated_callback(std::function<void()> callback); | |||||
/// Sets the callback for when the control is deactivated. | |||||
void set_deactivated_callback(std::function<void()> callback); | |||||
/// Sets the callback for when the control value is changed. | |||||
void set_value_changed_callback(std::function<void(float)> callback); | |||||
/** | |||||
* Enables or disables callbacks. | |||||
* | |||||
* @param enabled Whether to enable or disable callbacks. | |||||
*/ | |||||
void set_callbacks_enabled(bool enabled); | |||||
/// Returns the deadzone value. The default value is 0.0. | |||||
float get_deadzone() const; | |||||
/// Returns the current value of the control. | |||||
float get_current_value() const; | |||||
/// Returns the previous value of the control. | |||||
float get_previous_value() const; | |||||
/// Returns true if the control is currently active. | |||||
bool is_active() const; | |||||
/// Returns true if the control was previously active when update() was last called. | |||||
bool was_active() const; | |||||
private: | |||||
float deadzone; | |||||
float current_value; | |||||
float previous_value; | |||||
bool reset; | |||||
std::function<void()> activated_callback; | |||||
std::function<void()> deactivated_callback; | |||||
std::function<void(float)> value_changed_callback; | |||||
bool callbacks_enabled; | |||||
}; | |||||
inline void control::set_callbacks_enabled(bool enabled) | |||||
{ | |||||
this->callbacks_enabled = enabled; | |||||
} | |||||
inline float control::get_deadzone() const | |||||
{ | |||||
return deadzone; | |||||
} | |||||
inline float control::get_current_value() const | |||||
{ | |||||
return current_value; | |||||
} | |||||
inline float control::get_previous_value() const | |||||
{ | |||||
return previous_value; | |||||
} | |||||
inline bool control::is_active() const | |||||
{ | |||||
return current_value > deadzone; | |||||
} | |||||
inline bool control::was_active() const | |||||
{ | |||||
return previous_value > deadzone; | |||||
} | |||||
#endif // ANTKEEPER_CONTROL_HPP | |||||
@ -0,0 +1,70 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "game-controller.hpp" | |||||
#include "input-events.hpp" | |||||
#include "event/event-dispatcher.hpp" | |||||
#include <cmath> | |||||
game_controller::game_controller() | |||||
{} | |||||
void game_controller::press(game_controller_button button) | |||||
{ | |||||
if (!input_device::event_dispatcher) | |||||
{ | |||||
return; | |||||
} | |||||
game_controller_button_pressed_event event; | |||||
event.game_controller = this; | |||||
event.button = button; | |||||
input_device::event_dispatcher->queue(event); | |||||
} | |||||
void game_controller::release(game_controller_button button) | |||||
{ | |||||
if (!input_device::event_dispatcher) | |||||
{ | |||||
return; | |||||
} | |||||
game_controller_button_released_event event; | |||||
event.game_controller = this; | |||||
event.button = button; | |||||
input_device::event_dispatcher->queue(event); | |||||
} | |||||
void game_controller::move(game_controller_axis axis, float value) | |||||
{ | |||||
if (!input_device::event_dispatcher) | |||||
{ | |||||
return; | |||||
} | |||||
game_controller_axis_moved_event event; | |||||
event.game_controller = this; | |||||
event.axis = axis; | |||||
event.value = value; | |||||
input_device::event_dispatcher->queue(event); | |||||
} | |||||
@ -0,0 +1,95 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_GAME_CONTROLLER_HPP | |||||
#define ANTKEEPER_GAME_CONTROLLER_HPP | |||||
#include "input-device.hpp" | |||||
enum class game_controller_button | |||||
{ | |||||
a, | |||||
b, | |||||
x, | |||||
y, | |||||
back, | |||||
guide, | |||||
start, | |||||
left_stick, | |||||
right_stick, | |||||
left_shoulder, | |||||
right_shoulder, | |||||
dpad_up, | |||||
dpad_down, | |||||
dpad_left, | |||||
dpad_right | |||||
}; | |||||
enum class game_controller_axis | |||||
{ | |||||
left_x, | |||||
left_y, | |||||
right_x, | |||||
right_y, | |||||
trigger_left, | |||||
trigger_right, | |||||
}; | |||||
/** | |||||
* A virtual game controller which can generate game controller-related input events and pass them to an event dispatcher. | |||||
* | |||||
* @ingroup input | |||||
*/ | |||||
class game_controller: public input_device | |||||
{ | |||||
public: | |||||
/** | |||||
* Creates a game controller input device. | |||||
*/ | |||||
game_controller(); | |||||
/// Destroys a game controller input device. | |||||
virtual ~game_controller() = default; | |||||
/** | |||||
* Simulates a game controller button press. | |||||
* | |||||
* @param button Index of the pressed button. | |||||
*/ | |||||
void press(game_controller_button button); | |||||
/** | |||||
* Simulates a game controller button release. | |||||
* | |||||
* @param button Index of the released button. | |||||
*/ | |||||
void release(game_controller_button button); | |||||
/** | |||||
* Simulates a game controller axis movement. | |||||
* | |||||
* @param axis Index of the moved axis. | |||||
* @param negative Whether the movement was negative or positive. | |||||
* @param value Normalized degree of movement. | |||||
*/ | |||||
void move(game_controller_axis axis, float value); | |||||
}; | |||||
#endif // ANTKEEPER_GAME_CONTROLLER_HPP | |||||
@ -0,0 +1,30 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "input-device.hpp" | |||||
#include "event/event-dispatcher.hpp" | |||||
input_device::input_device(): | |||||
event_dispatcher(nullptr) | |||||
{} | |||||
void input_device::set_event_dispatcher(::event_dispatcher* event_dispatcher) | |||||
{ | |||||
this->event_dispatcher = event_dispatcher; | |||||
} |
@ -0,0 +1,55 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_INPUT_DEVICE_HPP | |||||
#define ANTKEEPER_INPUT_DEVICE_HPP | |||||
#include "input-device.hpp" | |||||
class event_dispatcher; | |||||
/** | |||||
* Base class for virtual devices which generate input events. | |||||
*/ | |||||
class input_device | |||||
{ | |||||
public: | |||||
input_device(); | |||||
virtual ~input_device() = default; | |||||
void set_event_dispatcher(event_dispatcher* event_dispatcher); | |||||
const event_dispatcher* get_event_dispatcher() const; | |||||
event_dispatcher* get_event_dispatcher(); | |||||
protected: | |||||
event_dispatcher* event_dispatcher; | |||||
}; | |||||
inline const event_dispatcher* input_device::get_event_dispatcher() const | |||||
{ | |||||
return event_dispatcher; | |||||
} | |||||
inline event_dispatcher* input_device::get_event_dispatcher() | |||||
{ | |||||
return event_dispatcher; | |||||
} | |||||
#endif // ANTKEEPER_INPUT_DEVICE_HPP | |||||
@ -0,0 +1,341 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "input-event-router.hpp" | |||||
#include "control.hpp" | |||||
#include "input-mapping.hpp" | |||||
#include "mouse.hpp" | |||||
#include "event/event-dispatcher.hpp" | |||||
input_event_router::input_event_router(): | |||||
event_dispatcher(nullptr) | |||||
{} | |||||
input_event_router::~input_event_router() | |||||
{ | |||||
remove_mappings(); | |||||
set_event_dispatcher(nullptr); | |||||
} | |||||
void input_event_router::add_mapping(const input_mapping& mapping) | |||||
{ | |||||
control* control = mapping.control; | |||||
switch (mapping.get_type()) | |||||
{ | |||||
case input_mapping_type::key: | |||||
{ | |||||
::key_mapping* key_mapping = new ::key_mapping(static_cast<const ::key_mapping&>(mapping)); | |||||
key_mappings.push_back(key_mapping); | |||||
controls[control].push_back(key_mapping); | |||||
break; | |||||
} | |||||
case input_mapping_type::mouse_motion: | |||||
{ | |||||
::mouse_motion_mapping* mouse_motion_mapping = new ::mouse_motion_mapping(static_cast<const ::mouse_motion_mapping&>(mapping)); | |||||
mouse_motion_mappings.push_back(mouse_motion_mapping); | |||||
controls[control].push_back(mouse_motion_mapping); | |||||
break; | |||||
} | |||||
case input_mapping_type::mouse_wheel: | |||||
{ | |||||
::mouse_wheel_mapping* mouse_wheel_mapping = new ::mouse_wheel_mapping(static_cast<const ::mouse_wheel_mapping&>(mapping)); | |||||
mouse_wheel_mappings.push_back(mouse_wheel_mapping); | |||||
controls[control].push_back(mouse_wheel_mapping); | |||||
break; | |||||
} | |||||
case input_mapping_type::mouse_button: | |||||
{ | |||||
::mouse_button_mapping* mouse_button_mapping = new ::mouse_button_mapping(static_cast<const ::mouse_button_mapping&>(mapping)); | |||||
mouse_button_mappings.push_back(mouse_button_mapping); | |||||
controls[control].push_back(mouse_button_mapping); | |||||
break; | |||||
} | |||||
case input_mapping_type::game_controller_axis: | |||||
{ | |||||
::game_controller_axis_mapping* game_controller_axis_mapping = new ::game_controller_axis_mapping(static_cast<const ::game_controller_axis_mapping&>(mapping)); | |||||
game_controller_axis_mappings.push_back(game_controller_axis_mapping); | |||||
controls[control].push_back(game_controller_axis_mapping); | |||||
break; | |||||
} | |||||
case input_mapping_type::game_controller_button: | |||||
{ | |||||
::game_controller_button_mapping* game_controller_button_mapping = new ::game_controller_button_mapping(static_cast<const ::game_controller_button_mapping&>(mapping)); | |||||
game_controller_button_mappings.push_back(game_controller_button_mapping); | |||||
controls[control].push_back(game_controller_button_mapping); | |||||
break; | |||||
} | |||||
default: | |||||
break; | |||||
} | |||||
} | |||||
void input_event_router::remove_mappings(control* control) | |||||
{ | |||||
auto it = controls.find(control); | |||||
if (it != controls.end()) | |||||
{ | |||||
for (input_mapping* mapping: it->second) | |||||
{ | |||||
switch (mapping->get_type()) | |||||
{ | |||||
case input_mapping_type::key: | |||||
key_mappings.remove(static_cast<key_mapping*>(mapping)); | |||||
break; | |||||
case input_mapping_type::mouse_motion: | |||||
mouse_motion_mappings.remove(static_cast<mouse_motion_mapping*>(mapping)); | |||||
break; | |||||
case input_mapping_type::mouse_wheel: | |||||
mouse_wheel_mappings.remove(static_cast<mouse_wheel_mapping*>(mapping)); | |||||
break; | |||||
case input_mapping_type::mouse_button: | |||||
mouse_button_mappings.remove(static_cast<mouse_button_mapping*>(mapping)); | |||||
break; | |||||
case input_mapping_type::game_controller_axis: | |||||
game_controller_axis_mappings.remove(static_cast<game_controller_axis_mapping*>(mapping)); | |||||
break; | |||||
case input_mapping_type::game_controller_button: | |||||
game_controller_button_mappings.remove(static_cast<game_controller_button_mapping*>(mapping)); | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
delete mapping; | |||||
} | |||||
controls.erase(it); | |||||
} | |||||
} | |||||
void input_event_router::set_event_dispatcher(::event_dispatcher* event_dispatcher) | |||||
{ | |||||
if (this->event_dispatcher) | |||||
{ | |||||
this->event_dispatcher->unsubscribe<key_pressed_event>(this); | |||||
this->event_dispatcher->unsubscribe<key_released_event>(this); | |||||
this->event_dispatcher->unsubscribe<mouse_moved_event>(this); | |||||
this->event_dispatcher->unsubscribe<mouse_wheel_scrolled_event>(this); | |||||
this->event_dispatcher->unsubscribe<mouse_button_pressed_event>(this); | |||||
this->event_dispatcher->unsubscribe<mouse_button_released_event>(this); | |||||
this->event_dispatcher->unsubscribe<game_controller_axis_moved_event>(this); | |||||
this->event_dispatcher->unsubscribe<game_controller_button_pressed_event>(this); | |||||
this->event_dispatcher->unsubscribe<game_controller_button_released_event>(this); | |||||
} | |||||
this->event_dispatcher = event_dispatcher; | |||||
if (event_dispatcher) | |||||
{ | |||||
event_dispatcher->subscribe<key_pressed_event>(this); | |||||
event_dispatcher->subscribe<key_released_event>(this); | |||||
event_dispatcher->subscribe<mouse_moved_event>(this); | |||||
event_dispatcher->subscribe<mouse_wheel_scrolled_event>(this); | |||||
event_dispatcher->subscribe<mouse_button_pressed_event>(this); | |||||
event_dispatcher->subscribe<mouse_button_released_event>(this); | |||||
event_dispatcher->subscribe<game_controller_axis_moved_event>(this); | |||||
event_dispatcher->subscribe<game_controller_button_pressed_event>(this); | |||||
event_dispatcher->subscribe<game_controller_button_released_event>(this); | |||||
} | |||||
} | |||||
void input_event_router::remove_mappings() | |||||
{ | |||||
for (auto it = controls.begin(); it != controls.end(); ++it) | |||||
{ | |||||
for (input_mapping* mapping: it->second) | |||||
{ | |||||
delete mapping; | |||||
} | |||||
} | |||||
controls.clear(); | |||||
key_mappings.clear(); | |||||
mouse_motion_mappings.clear(); | |||||
mouse_wheel_mappings.clear(); | |||||
mouse_button_mappings.clear(); | |||||
game_controller_axis_mappings.clear(); | |||||
game_controller_button_mappings.clear(); | |||||
} | |||||
const std::list<input_mapping*>* input_event_router::get_mappings(control* control) const | |||||
{ | |||||
auto it = controls.find(control); | |||||
if (it == controls.end()) | |||||
{ | |||||
return nullptr; | |||||
} | |||||
return &it->second; | |||||
} | |||||
void input_event_router::handle_event(const key_pressed_event& event) | |||||
{ | |||||
for (const key_mapping* mapping: key_mappings) | |||||
{ | |||||
if ((!mapping->keyboard || mapping->keyboard == event.keyboard) && mapping->scancode == event.scancode) | |||||
{ | |||||
mapping->control->set_current_value(1.0f); | |||||
} | |||||
} | |||||
} | |||||
void input_event_router::handle_event(const key_released_event& event) | |||||
{ | |||||
for (const key_mapping* mapping: key_mappings) | |||||
{ | |||||
if ((!mapping->keyboard || mapping->keyboard == event.keyboard) && mapping->scancode == event.scancode) | |||||
{ | |||||
mapping->control->set_current_value(0.0f); | |||||
} | |||||
} | |||||
} | |||||
void input_event_router::handle_event(const mouse_moved_event& event) | |||||
{ | |||||
for (const mouse_motion_mapping* mapping: mouse_motion_mappings) | |||||
{ | |||||
if (!mapping->mouse || mapping->mouse == event.mouse) | |||||
{ | |||||
if (mapping->axis == mouse_motion_axis::negative_x && event.dx < 0) | |||||
{ | |||||
mapping->control->set_temporary_value(-event.dx); | |||||
} | |||||
else if (mapping->axis == mouse_motion_axis::positive_x && event.dx > 0) | |||||
{ | |||||
mapping->control->set_temporary_value(event.dx); | |||||
} | |||||
else if (mapping->axis == mouse_motion_axis::negative_y && event.dy < 0) | |||||
{ | |||||
mapping->control->set_temporary_value(-event.dy); | |||||
} | |||||
else if (mapping->axis == mouse_motion_axis::positive_y && event.dy > 0) | |||||
{ | |||||
mapping->control->set_temporary_value(event.dy); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
void input_event_router::handle_event(const mouse_wheel_scrolled_event& event) | |||||
{ | |||||
for (const mouse_wheel_mapping* mapping: mouse_wheel_mappings) | |||||
{ | |||||
if (!mapping->mouse || mapping->mouse == event.mouse) | |||||
{ | |||||
if (mapping->axis == mouse_wheel_axis::negative_x && event.x < 0) | |||||
{ | |||||
mapping->control->set_temporary_value(-event.x); | |||||
} | |||||
else if (mapping->axis == mouse_wheel_axis::positive_x && event.x > 0) | |||||
{ | |||||
mapping->control->set_temporary_value(event.x); | |||||
} | |||||
else if (mapping->axis == mouse_wheel_axis::negative_y && event.y < 0) | |||||
{ | |||||
mapping->control->set_temporary_value(-event.y); | |||||
} | |||||
else if (mapping->axis == mouse_wheel_axis::positive_y && event.y > 0) | |||||
{ | |||||
mapping->control->set_temporary_value(event.y); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
void input_event_router::handle_event(const mouse_button_pressed_event& event) | |||||
{ | |||||
for (const mouse_button_mapping* mapping: mouse_button_mappings) | |||||
{ | |||||
if ((!mapping->mouse || mapping->mouse == event.mouse) && mapping->button == event.button) | |||||
{ | |||||
mapping->control->set_current_value(1.0f); | |||||
} | |||||
} | |||||
} | |||||
void input_event_router::handle_event(const mouse_button_released_event& event) | |||||
{ | |||||
for (const mouse_button_mapping* mapping: mouse_button_mappings) | |||||
{ | |||||
if ((!mapping->mouse || mapping->mouse == event.mouse) && mapping->button == event.button) | |||||
{ | |||||
mapping->control->set_current_value(0.0f); | |||||
} | |||||
} | |||||
} | |||||
void input_event_router::handle_event(const game_controller_axis_moved_event& event) | |||||
{ | |||||
for (const game_controller_axis_mapping* mapping: game_controller_axis_mappings) | |||||
{ | |||||
if ((!mapping->game_controller || mapping->game_controller == event.game_controller) && mapping->axis == event.axis) | |||||
{ | |||||
if (mapping->negative && event.value >= 0.0f || !mapping->negative && event.value <= 0.0f) | |||||
{ | |||||
mapping->control->set_current_value(0.0f); | |||||
} | |||||
else | |||||
{ | |||||
mapping->control->set_current_value(std::abs(event.value)); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
void input_event_router::handle_event(const game_controller_button_pressed_event& event) | |||||
{ | |||||
for (const game_controller_button_mapping* mapping: game_controller_button_mappings) | |||||
{ | |||||
if ((!mapping->game_controller || mapping->game_controller == event.game_controller) && mapping->button == event.button) | |||||
{ | |||||
mapping->control->set_current_value(1.0f); | |||||
} | |||||
} | |||||
} | |||||
void input_event_router::handle_event(const game_controller_button_released_event& event) | |||||
{ | |||||
for (const game_controller_button_mapping* mapping: game_controller_button_mappings) | |||||
{ | |||||
if ((!mapping->game_controller || mapping->game_controller == event.game_controller) && mapping->button == event.button) | |||||
{ | |||||
mapping->control->set_current_value(0.0f); | |||||
} | |||||
} | |||||
} | |||||
@ -0,0 +1,115 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEER_INPUT_EVENT_ROUTER_HPP | |||||
#define ANTKEEER_INPUT_EVENT_ROUTER_HPP | |||||
#include "input-events.hpp" | |||||
#include "event/event-handler.hpp" | |||||
#include <list> | |||||
#include <map> | |||||
class control; | |||||
class event_dispatcher; | |||||
class input_mapping; | |||||
class key_mapping; | |||||
class mouse_motion_mapping; | |||||
class mouse_wheel_mapping; | |||||
class mouse_button_mapping; | |||||
class game_controller_axis_mapping; | |||||
class game_controller_button_mapping; | |||||
enum class mouse_motion_axis; | |||||
enum class mouse_wheel_axis; | |||||
/** | |||||
* Uses input mappings to route input events to controls. | |||||
*/ | |||||
class input_event_router: | |||||
public event_handler<key_pressed_event>, | |||||
public event_handler<key_released_event>, | |||||
public event_handler<mouse_moved_event>, | |||||
public event_handler<mouse_wheel_scrolled_event>, | |||||
public event_handler<mouse_button_pressed_event>, | |||||
public event_handler<mouse_button_released_event>, | |||||
public event_handler<game_controller_axis_moved_event>, | |||||
public event_handler<game_controller_button_pressed_event>, | |||||
public event_handler<game_controller_button_released_event> | |||||
{ | |||||
public: | |||||
/** | |||||
* Creates an input router and subscribes it to the input events of the specified event dispatcher. | |||||
*/ | |||||
input_event_router(); | |||||
/** | |||||
* Destroys an input router and unsubscribes it from input events. | |||||
*/ | |||||
~input_event_router(); | |||||
/** | |||||
* Adds an input mapping to the router. | |||||
* | |||||
* @param mapping Input mapping to add. | |||||
*/ | |||||
void add_mapping(const input_mapping& mapping); | |||||
/** | |||||
* Removes all input mappings from the router that are associated with the specified control. | |||||
* | |||||
* @param control control with which associated input mappings should be removed. | |||||
*/ | |||||
void remove_mappings(control* control); | |||||
/** | |||||
* Sets the event dispatcher to which this input event router will subscribe itself. | |||||
*/ | |||||
void set_event_dispatcher(event_dispatcher* event_dispatcher); | |||||
/** | |||||
* Removes all input mappings from the router. | |||||
*/ | |||||
void remove_mappings(); | |||||
/// Returns a list of mappings for the specified control, or nullptr if the control is unmapped. | |||||
const std::list<input_mapping*>* get_mappings(control* control) const; | |||||
private: | |||||
virtual void handle_event(const key_pressed_event& event); | |||||
virtual void handle_event(const key_released_event& event); | |||||
virtual void handle_event(const mouse_moved_event& event); | |||||
virtual void handle_event(const mouse_wheel_scrolled_event& event); | |||||
virtual void handle_event(const mouse_button_pressed_event& event); | |||||
virtual void handle_event(const mouse_button_released_event& event); | |||||
virtual void handle_event(const game_controller_axis_moved_event& event); | |||||
virtual void handle_event(const game_controller_button_pressed_event& event); | |||||
virtual void handle_event(const game_controller_button_released_event& event); | |||||
event_dispatcher* event_dispatcher; | |||||
std::map<control*, std::list<input_mapping*>> controls; | |||||
std::list<key_mapping*> key_mappings; | |||||
std::list<mouse_motion_mapping*> mouse_motion_mappings; | |||||
std::list<mouse_wheel_mapping*> mouse_wheel_mappings; | |||||
std::list<mouse_button_mapping*> mouse_button_mappings; | |||||
std::list<game_controller_axis_mapping*> game_controller_axis_mappings; | |||||
std::list<game_controller_button_mapping*> game_controller_button_mappings; | |||||
}; | |||||
#endif // ANTKEEER_INPUT_EVENT_ROUTER_HPP | |||||
@ -0,0 +1,117 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "input-events.hpp" | |||||
event_base* key_pressed_event::clone() const | |||||
{ | |||||
key_pressed_event* event = new key_pressed_event(); | |||||
event->keyboard = keyboard; | |||||
event->scancode = scancode; | |||||
return event; | |||||
} | |||||
event_base* key_released_event::clone() const | |||||
{ | |||||
key_released_event* event = new key_released_event(); | |||||
event->keyboard = keyboard; | |||||
event->scancode = scancode; | |||||
return event; | |||||
} | |||||
event_base* mouse_moved_event::clone() const | |||||
{ | |||||
mouse_moved_event* event = new mouse_moved_event(); | |||||
event->mouse = mouse; | |||||
event->x = x; | |||||
event->y = y; | |||||
event->dx = dx; | |||||
event->dy = dy; | |||||
return event; | |||||
} | |||||
event_base* mouse_button_pressed_event::clone() const | |||||
{ | |||||
mouse_button_pressed_event* event = new mouse_button_pressed_event(); | |||||
event->mouse = mouse; | |||||
event->button = button; | |||||
event->x = x; | |||||
event->y = y; | |||||
return event; | |||||
} | |||||
event_base* mouse_button_released_event::clone() const | |||||
{ | |||||
mouse_button_released_event* event = new mouse_button_released_event(); | |||||
event->mouse = mouse; | |||||
event->button = button; | |||||
event->x = x; | |||||
event->y = y; | |||||
return event; | |||||
} | |||||
event_base* mouse_wheel_scrolled_event::clone() const | |||||
{ | |||||
mouse_wheel_scrolled_event* event = new mouse_wheel_scrolled_event(); | |||||
event->mouse = mouse; | |||||
event->x = x; | |||||
event->y = y; | |||||
return event; | |||||
} | |||||
event_base* game_controller_connected_event::clone() const | |||||
{ | |||||
game_controller_connected_event* event = new game_controller_connected_event(); | |||||
event->game_controller = game_controller; | |||||
event->reconnected = reconnected; | |||||
return event; | |||||
} | |||||
event_base* game_controller_disconnected_event::clone() const | |||||
{ | |||||
game_controller_disconnected_event* event = new game_controller_disconnected_event(); | |||||
event->game_controller = game_controller; | |||||
return event; | |||||
} | |||||
event_base* game_controller_button_pressed_event::clone() const | |||||
{ | |||||
game_controller_button_pressed_event* event = new game_controller_button_pressed_event(); | |||||
event->game_controller = game_controller; | |||||
event->button = button; | |||||
return event; | |||||
} | |||||
event_base* game_controller_button_released_event::clone() const | |||||
{ | |||||
game_controller_button_released_event* event = new game_controller_button_released_event(); | |||||
event->game_controller = game_controller; | |||||
event->button = button; | |||||
return event; | |||||
} | |||||
event_base* game_controller_axis_moved_event::clone() const | |||||
{ | |||||
game_controller_axis_moved_event* event = new game_controller_axis_moved_event(); | |||||
event->game_controller = game_controller; | |||||
event->axis = axis; | |||||
event->value = value; | |||||
return event; | |||||
} | |||||
@ -0,0 +1,173 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_INPUT_EVENT_HPP | |||||
#define ANTKEEPER_INPUT_EVENT_HPP | |||||
#include "event/event.hpp" | |||||
enum class scancode; | |||||
enum class game_controller_axis; | |||||
enum class game_controller_button; | |||||
class keyboard; | |||||
class mouse; | |||||
class game_controller; | |||||
/** | |||||
* Input event which indicates a keyboard key has been pressed. | |||||
*/ | |||||
class key_pressed_event: public event<key_pressed_event> | |||||
{ | |||||
public: | |||||
virtual event_base* clone() const; | |||||
keyboard* keyboard; | |||||
scancode scancode; | |||||
}; | |||||
/** | |||||
* Input event which indicates a keyboard key has been released. | |||||
*/ | |||||
class key_released_event: public event<key_released_event> | |||||
{ | |||||
public: | |||||
virtual event_base* clone() const; | |||||
keyboard* keyboard; | |||||
scancode scancode; | |||||
}; | |||||
/** | |||||
* Input event which indicates a mouse has been moved. | |||||
*/ | |||||
class mouse_moved_event: public event<mouse_moved_event> | |||||
{ | |||||
public: | |||||
virtual event_base* clone() const; | |||||
mouse* mouse; | |||||
int x; | |||||
int y; | |||||
int dx; | |||||
int dy; | |||||
}; | |||||
/** | |||||
* Input event which indicates a mouse button has been pressed. | |||||
*/ | |||||
class mouse_button_pressed_event: public event<mouse_button_pressed_event> | |||||
{ | |||||
public: | |||||
virtual event_base* clone() const; | |||||
mouse* mouse; | |||||
int button; | |||||
int x; | |||||
int y; | |||||
}; | |||||
/** | |||||
* Input event which indicates a mouse button has been released. | |||||
*/ | |||||
class mouse_button_released_event: public event<mouse_button_released_event> | |||||
{ | |||||
public: | |||||
virtual event_base* clone() const; | |||||
mouse* mouse; | |||||
int button; | |||||
int x; | |||||
int y; | |||||
}; | |||||
/** | |||||
* Input event which indicates a mouse wheel has been scrolled. | |||||
*/ | |||||
class mouse_wheel_scrolled_event: public event<mouse_wheel_scrolled_event> | |||||
{ | |||||
public: | |||||
virtual event_base* clone() const; | |||||
mouse* mouse; | |||||
int x; | |||||
int y; | |||||
}; | |||||
/** | |||||
* Input event which indicates a controller has been connected. | |||||
*/ | |||||
class game_controller_connected_event: public event<game_controller_connected_event> | |||||
{ | |||||
public: | |||||
virtual event_base* clone() const; | |||||
game_controller* game_controller; | |||||
bool reconnected; | |||||
}; | |||||
/** | |||||
* Input event which indicates a controller has been disconnected. | |||||
*/ | |||||
class game_controller_disconnected_event: public event<game_controller_disconnected_event> | |||||
{ | |||||
public: | |||||
virtual event_base* clone() const; | |||||
game_controller* game_controller; | |||||
}; | |||||
/** | |||||
* Input event which indicates a controller button has been pressed. | |||||
*/ | |||||
class game_controller_button_pressed_event: public event<game_controller_button_pressed_event> | |||||
{ | |||||
public: | |||||
virtual event_base* clone() const; | |||||
game_controller* game_controller; | |||||
game_controller_button button; | |||||
}; | |||||
/** | |||||
* Input event which indicates a controller button has been released. | |||||
*/ | |||||
class game_controller_button_released_event: public event<game_controller_button_released_event> | |||||
{ | |||||
public: | |||||
virtual event_base* clone() const; | |||||
game_controller* game_controller; | |||||
game_controller_button button; | |||||
}; | |||||
/** | |||||
* Input event which indicates a controller axis has been moved. | |||||
*/ | |||||
class game_controller_axis_moved_event: public event<game_controller_axis_moved_event> | |||||
{ | |||||
public: | |||||
virtual event_base* clone() const; | |||||
game_controller* game_controller; | |||||
game_controller_axis axis; | |||||
float value; | |||||
}; | |||||
#endif // ANTKEEPER_INPUT_EVENT_HPP | |||||
@ -0,0 +1,155 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "input-mapper.hpp" | |||||
#include "mouse.hpp" | |||||
#include "event/event-dispatcher.hpp" | |||||
input_mapper::input_mapper(): | |||||
event_dispatcher(nullptr), | |||||
control(nullptr), | |||||
callback(nullptr), | |||||
enabled(false) | |||||
{} | |||||
input_mapper::~input_mapper() | |||||
{ | |||||
set_event_dispatcher(nullptr); | |||||
} | |||||
void input_mapper::set_event_dispatcher(::event_dispatcher* event_dispatcher) | |||||
{ | |||||
if (this->event_dispatcher) | |||||
{ | |||||
this->event_dispatcher->unsubscribe<key_pressed_event>(this); | |||||
this->event_dispatcher->unsubscribe<mouse_moved_event>(this); | |||||
this->event_dispatcher->unsubscribe<mouse_wheel_scrolled_event>(this); | |||||
this->event_dispatcher->unsubscribe<mouse_button_pressed_event>(this); | |||||
this->event_dispatcher->unsubscribe<game_controller_axis_moved_event>(this); | |||||
this->event_dispatcher->unsubscribe<game_controller_button_pressed_event>(this); | |||||
} | |||||
this->event_dispatcher = event_dispatcher; | |||||
if (event_dispatcher) | |||||
{ | |||||
event_dispatcher->subscribe<key_pressed_event>(this); | |||||
event_dispatcher->subscribe<mouse_moved_event>(this); | |||||
event_dispatcher->subscribe<mouse_wheel_scrolled_event>(this); | |||||
event_dispatcher->subscribe<mouse_button_pressed_event>(this); | |||||
event_dispatcher->subscribe<game_controller_axis_moved_event>(this); | |||||
event_dispatcher->subscribe<game_controller_button_pressed_event>(this); | |||||
} | |||||
} | |||||
void input_mapper::set_control(::control* control) | |||||
{ | |||||
this->control = control; | |||||
} | |||||
void input_mapper::set_callback(std::function<void(const input_mapping&)> callback) | |||||
{ | |||||
this->callback = callback; | |||||
} | |||||
void input_mapper::set_enabled(bool enabled) | |||||
{ | |||||
this->enabled = enabled; | |||||
} | |||||
void input_mapper::handle_event(const key_pressed_event& event) | |||||
{ | |||||
if (!is_enabled() || !callback) | |||||
{ | |||||
return; | |||||
} | |||||
callback(key_mapping(control, event.keyboard, event.scancode)); | |||||
} | |||||
void input_mapper::handle_event(const mouse_moved_event& event) | |||||
{ | |||||
if (!is_enabled() || !callback) | |||||
{ | |||||
return; | |||||
} | |||||
if (event.dx != 0) | |||||
{ | |||||
mouse_motion_axis axis = (event.dx < 0) ? mouse_motion_axis::negative_x : mouse_motion_axis::positive_x; | |||||
callback(mouse_motion_mapping(control, event.mouse, axis)); | |||||
} | |||||
if (event.dy != 0) | |||||
{ | |||||
mouse_motion_axis axis = (event.dy < 0) ? mouse_motion_axis::negative_y : mouse_motion_axis::positive_y; | |||||
callback(mouse_motion_mapping(control, event.mouse, axis)); | |||||
} | |||||
} | |||||
void input_mapper::handle_event(const mouse_button_pressed_event& event) | |||||
{ | |||||
if (!is_enabled() || !callback) | |||||
{ | |||||
return; | |||||
} | |||||
callback(mouse_button_mapping(control, event.mouse, event.button)); | |||||
} | |||||
void input_mapper::handle_event(const mouse_wheel_scrolled_event& event) | |||||
{ | |||||
if (!is_enabled() || !callback) | |||||
{ | |||||
return; | |||||
} | |||||
if (event.x != 0) | |||||
{ | |||||
mouse_wheel_axis axis = (event.x < 0) ? mouse_wheel_axis::negative_x : mouse_wheel_axis::positive_x; | |||||
callback(mouse_wheel_mapping(control, event.mouse, axis)); | |||||
} | |||||
if (event.y != 0) | |||||
{ | |||||
mouse_wheel_axis axis = (event.y < 0) ? mouse_wheel_axis::negative_y : mouse_wheel_axis::positive_y; | |||||
callback(mouse_wheel_mapping(control, event.mouse, axis)); | |||||
} | |||||
} | |||||
void input_mapper::handle_event(const game_controller_button_pressed_event& event) | |||||
{ | |||||
if (!is_enabled() || !callback) | |||||
{ | |||||
return; | |||||
} | |||||
callback(game_controller_button_mapping(control, event.game_controller, event.button)); | |||||
} | |||||
void input_mapper::handle_event(const game_controller_axis_moved_event& event) | |||||
{ | |||||
if (!is_enabled() || !callback) | |||||
{ | |||||
return; | |||||
} | |||||
callback(game_controller_axis_mapping(control, event.game_controller, event.axis, (event.value < 0.0f))); | |||||
} | |||||
@ -0,0 +1,103 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_INPUT_MAPPER_HPP | |||||
#define ANTKEEPER_INPUT_MAPPER_HPP | |||||
#include "input-events.hpp" | |||||
#include "input-mapping.hpp" | |||||
#include "event/event-handler.hpp" | |||||
#include <functional> | |||||
class event_dispatcher; | |||||
/** | |||||
* An input mapper takes a control and listens to input events then generates corresponding input mappings which can be added to an input router. | |||||
*/ | |||||
class input_mapper: | |||||
public event_handler<key_pressed_event>, | |||||
public event_handler<mouse_moved_event>, | |||||
public event_handler<mouse_wheel_scrolled_event>, | |||||
public event_handler<mouse_button_pressed_event>, | |||||
public event_handler<game_controller_axis_moved_event>, | |||||
public event_handler<game_controller_button_pressed_event> | |||||
{ | |||||
public: | |||||
/** | |||||
* Creates an input mapper. | |||||
*/ | |||||
input_mapper(); | |||||
/** | |||||
* Destroys an input mapper. | |||||
*/ | |||||
virtual ~input_mapper(); | |||||
/** | |||||
* Sets the event dispatcher to which this input event router will subscribe itself. | |||||
*/ | |||||
void set_event_dispatcher(event_dispatcher* event_dispatcher); | |||||
/** | |||||
* Sets the control for which input mappings will be generated. | |||||
* | |||||
* @param control ::control for which input mappings will be generated. | |||||
*/ | |||||
void set_control(::control* control); | |||||
/** | |||||
* Sets the callback function to the input mappings generated by this input mapper. | |||||
* | |||||
* @param callback Callback function operates on an input mapping. | |||||
*/ | |||||
void set_callback(std::function<void(const input_mapping&)> callback); | |||||
/** | |||||
* Enables or disables the input mapping generation. | |||||
* | |||||
* @param enabled Whether to enable input mapping generation or not. | |||||
*/ | |||||
void set_enabled(bool enabled); | |||||
/** | |||||
* Returns true if input mapping generation is enabled. | |||||
*/ | |||||
bool is_enabled() const; | |||||
private: | |||||
void handle_event(const key_pressed_event& event); | |||||
void handle_event(const mouse_moved_event& event); | |||||
void handle_event(const mouse_wheel_scrolled_event& event); | |||||
void handle_event(const mouse_button_pressed_event& event); | |||||
void handle_event(const game_controller_axis_moved_event& event); | |||||
void handle_event(const game_controller_button_pressed_event& event); | |||||
event_dispatcher* event_dispatcher; | |||||
::control* control; | |||||
std::function<void(const input_mapping&)> callback; | |||||
bool enabled; | |||||
}; | |||||
inline bool input_mapper::is_enabled() const | |||||
{ | |||||
return enabled; | |||||
} | |||||
#endif // ANTKEEPER_INPUT_MAPPER_HPP | |||||
@ -0,0 +1,141 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "input-mapping.hpp" | |||||
input_mapping::input_mapping(::control* control): | |||||
control(control) | |||||
{} | |||||
key_mapping::key_mapping(const key_mapping& mapping) | |||||
{ | |||||
*this = mapping; | |||||
} | |||||
key_mapping::key_mapping(::control* control, ::keyboard* keyboard, ::scancode scancode): | |||||
input_mapping(control), | |||||
keyboard(keyboard), | |||||
scancode(scancode) | |||||
{} | |||||
key_mapping& key_mapping::operator=(const key_mapping& mapping) | |||||
{ | |||||
control = mapping.control; | |||||
keyboard = mapping.keyboard; | |||||
scancode = mapping.scancode; | |||||
return *this; | |||||
} | |||||
mouse_motion_mapping::mouse_motion_mapping(const mouse_motion_mapping& mapping) | |||||
{ | |||||
*this = mapping; | |||||
} | |||||
mouse_motion_mapping::mouse_motion_mapping(::control* control, ::mouse* mouse, mouse_motion_axis axis): | |||||
input_mapping(control), | |||||
mouse(mouse), | |||||
axis(axis) | |||||
{} | |||||
mouse_motion_mapping& mouse_motion_mapping::operator=(const mouse_motion_mapping& mapping) | |||||
{ | |||||
control = mapping.control; | |||||
mouse = mapping.mouse; | |||||
axis = mapping.axis; | |||||
return *this; | |||||
} | |||||
mouse_wheel_mapping::mouse_wheel_mapping(const mouse_wheel_mapping& mapping) | |||||
{ | |||||
*this = mapping; | |||||
} | |||||
mouse_wheel_mapping::mouse_wheel_mapping(::control* control, ::mouse* mouse, ::mouse_wheel_axis axis): | |||||
input_mapping(control), | |||||
mouse(mouse), | |||||
axis(axis) | |||||
{} | |||||
mouse_wheel_mapping& mouse_wheel_mapping::operator=(const mouse_wheel_mapping& mapping) | |||||
{ | |||||
control = mapping.control; | |||||
mouse = mapping.mouse; | |||||
axis = mapping.axis; | |||||
return *this; | |||||
} | |||||
mouse_button_mapping::mouse_button_mapping(const mouse_button_mapping& mapping) | |||||
{ | |||||
*this = mapping; | |||||
} | |||||
mouse_button_mapping::mouse_button_mapping(::control* control, ::mouse* mouse, int button): | |||||
input_mapping(control), | |||||
mouse(mouse), | |||||
button(button) | |||||
{} | |||||
mouse_button_mapping& mouse_button_mapping::operator=(const mouse_button_mapping& mapping) | |||||
{ | |||||
control = mapping.control; | |||||
mouse = mapping.mouse; | |||||
button = mapping.button; | |||||
return *this; | |||||
} | |||||
game_controller_axis_mapping::game_controller_axis_mapping(const game_controller_axis_mapping& mapping) | |||||
{ | |||||
*this = mapping; | |||||
} | |||||
game_controller_axis_mapping::game_controller_axis_mapping(::control* control, ::game_controller* game_controller, game_controller_axis axis, bool negative): | |||||
input_mapping(control), | |||||
game_controller(game_controller), | |||||
axis(axis), | |||||
negative(negative) | |||||
{} | |||||
game_controller_axis_mapping& game_controller_axis_mapping::operator=(const game_controller_axis_mapping& mapping) | |||||
{ | |||||
control = mapping.control; | |||||
game_controller = mapping.game_controller; | |||||
axis = mapping.axis; | |||||
negative = mapping.negative; | |||||
return *this; | |||||
} | |||||
game_controller_button_mapping::game_controller_button_mapping(const game_controller_button_mapping& mapping) | |||||
{ | |||||
*this = mapping; | |||||
} | |||||
game_controller_button_mapping::game_controller_button_mapping(::control* control, ::game_controller* game_controller, game_controller_button button): | |||||
input_mapping(control), | |||||
game_controller(game_controller), | |||||
button(button) | |||||
{} | |||||
game_controller_button_mapping& game_controller_button_mapping::operator=(const game_controller_button_mapping& mapping) | |||||
{ | |||||
control = mapping.control; | |||||
game_controller = mapping.game_controller; | |||||
button = mapping.button; | |||||
return *this; | |||||
} | |||||
@ -0,0 +1,198 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_INPUT_MAPPING_HPP | |||||
#define ANTKEEPER_INPUT_MAPPING_HPP | |||||
enum class mouse_motion_axis; | |||||
enum class mouse_wheel_axis; | |||||
enum class scancode; | |||||
enum class game_controller_axis; | |||||
enum class game_controller_button; | |||||
class control; | |||||
class keyboard; | |||||
class mouse; | |||||
class game_controller; | |||||
/** | |||||
* Enumerates the supported types of control mappings. | |||||
*/ | |||||
enum class input_mapping_type | |||||
{ | |||||
key, | |||||
mouse_motion, | |||||
mouse_wheel, | |||||
mouse_button, | |||||
game_controller_axis, | |||||
game_controller_button | |||||
}; | |||||
/** | |||||
* Abstract base class for input mappings. | |||||
*/ | |||||
class input_mapping | |||||
{ | |||||
public: | |||||
input_mapping() = default; | |||||
input_mapping(::control* control); | |||||
virtual ~input_mapping() = default; | |||||
/// Returns this control mapping's type. | |||||
virtual input_mapping_type get_type() const = 0; | |||||
control* control; | |||||
}; | |||||
/** | |||||
* A mapping between a control and a keyboard key. | |||||
*/ | |||||
class key_mapping: public input_mapping | |||||
{ | |||||
public: | |||||
key_mapping() = default; | |||||
key_mapping(const key_mapping& mapping); | |||||
key_mapping(::control* control, keyboard* keyboard, scancode scancode); | |||||
virtual ~key_mapping() = default; | |||||
key_mapping& operator=(const key_mapping& mapping); | |||||
virtual input_mapping_type get_type() const; | |||||
keyboard* keyboard; | |||||
scancode scancode; | |||||
}; | |||||
inline input_mapping_type key_mapping::get_type() const | |||||
{ | |||||
return input_mapping_type::key; | |||||
} | |||||
/** | |||||
* A mapping between a control and a mouse motion axis. | |||||
*/ | |||||
class mouse_motion_mapping: public input_mapping | |||||
{ | |||||
public: | |||||
mouse_motion_mapping() = default; | |||||
mouse_motion_mapping(const mouse_motion_mapping& mapping); | |||||
mouse_motion_mapping(::control* control, ::mouse* mouse, mouse_motion_axis axis); | |||||
virtual ~mouse_motion_mapping() = default; | |||||
mouse_motion_mapping& operator=(const mouse_motion_mapping& mapping); | |||||
virtual input_mapping_type get_type() const; | |||||
mouse* mouse; | |||||
mouse_motion_axis axis; | |||||
}; | |||||
inline input_mapping_type mouse_motion_mapping::get_type() const | |||||
{ | |||||
return input_mapping_type::mouse_motion; | |||||
} | |||||
/** | |||||
* A mapping between a control and a mouse wheel axis. | |||||
*/ | |||||
class mouse_wheel_mapping: public input_mapping | |||||
{ | |||||
public: | |||||
mouse_wheel_mapping() = default; | |||||
mouse_wheel_mapping(const mouse_wheel_mapping& mapping); | |||||
mouse_wheel_mapping(::control* control, mouse* mouse, mouse_wheel_axis axis); | |||||
virtual ~mouse_wheel_mapping() = default; | |||||
mouse_wheel_mapping& operator=(const mouse_wheel_mapping& mapping); | |||||
virtual input_mapping_type get_type() const; | |||||
mouse* mouse; | |||||
mouse_wheel_axis axis; | |||||
}; | |||||
inline input_mapping_type mouse_wheel_mapping::get_type() const | |||||
{ | |||||
return input_mapping_type::mouse_wheel; | |||||
} | |||||
/** | |||||
* A mapping between a control and a mouse button. | |||||
*/ | |||||
class mouse_button_mapping: public input_mapping | |||||
{ | |||||
public: | |||||
mouse_button_mapping() = default; | |||||
mouse_button_mapping(const mouse_button_mapping& mapping); | |||||
mouse_button_mapping(::control* control, mouse* mouse, int button); | |||||
virtual ~mouse_button_mapping() = default; | |||||
mouse_button_mapping& operator=(const mouse_button_mapping& mapping); | |||||
virtual input_mapping_type get_type() const; | |||||
mouse* mouse; | |||||
int button; | |||||
}; | |||||
inline input_mapping_type mouse_button_mapping::get_type() const | |||||
{ | |||||
return input_mapping_type::mouse_button; | |||||
} | |||||
/** | |||||
* A mapping between a control and a game controller axis. | |||||
*/ | |||||
class game_controller_axis_mapping: public input_mapping | |||||
{ | |||||
public: | |||||
game_controller_axis_mapping() = default; | |||||
game_controller_axis_mapping(const game_controller_axis_mapping& mapping); | |||||
game_controller_axis_mapping(::control* control, game_controller* game_controller, game_controller_axis axis, bool negative); | |||||
virtual ~game_controller_axis_mapping() = default; | |||||
game_controller_axis_mapping& operator=(const game_controller_axis_mapping& mapping); | |||||
virtual input_mapping_type get_type() const; | |||||
game_controller* game_controller; | |||||
game_controller_axis axis; | |||||
bool negative; | |||||
}; | |||||
inline input_mapping_type game_controller_axis_mapping::get_type() const | |||||
{ | |||||
return input_mapping_type::game_controller_axis; | |||||
} | |||||
/** | |||||
* A mapping between a control and a game controller button. | |||||
* | |||||
* @ingroup input. | |||||
*/ | |||||
class game_controller_button_mapping: public input_mapping | |||||
{ | |||||
public: | |||||
game_controller_button_mapping() = default; | |||||
game_controller_button_mapping(const game_controller_button_mapping& mapping); | |||||
game_controller_button_mapping(::control* control, game_controller* game_controller, game_controller_button button); | |||||
virtual ~game_controller_button_mapping() = default; | |||||
game_controller_button_mapping& operator=(const game_controller_button_mapping& mapping); | |||||
virtual input_mapping_type get_type() const; | |||||
game_controller* game_controller; | |||||
game_controller_button button; | |||||
}; | |||||
inline input_mapping_type game_controller_button_mapping::get_type() const | |||||
{ | |||||
return input_mapping_type::game_controller_button; | |||||
} | |||||
#endif // ANTKEEPER_INPUT_MAPPING_HPP | |||||
@ -0,0 +1,341 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "keyboard.hpp" | |||||
#include "scancode.hpp" | |||||
#include "event/event-dispatcher.hpp" | |||||
#include "input-events.hpp" | |||||
const char* keyboard::get_scancode_name(scancode scancode) | |||||
{ | |||||
return scancode_names[static_cast<std::size_t>(scancode)]; | |||||
}; | |||||
scancode keyboard::get_scancode_from_name(const char* name) | |||||
{ | |||||
auto it = scancode_map.find(std::string(name)); | |||||
if (it == scancode_map.end()) | |||||
{ | |||||
return scancode::unknown; | |||||
} | |||||
return it->second; | |||||
} | |||||
keyboard::keyboard() | |||||
{} | |||||
keyboard::~keyboard() | |||||
{} | |||||
void keyboard::press(scancode scancode) | |||||
{ | |||||
if (!input_device::event_dispatcher) | |||||
{ | |||||
return; | |||||
} | |||||
key_pressed_event event; | |||||
event.keyboard = this; | |||||
event.scancode = scancode; | |||||
input_device::event_dispatcher->queue(event); | |||||
} | |||||
void keyboard::release(scancode scancode) | |||||
{ | |||||
if (!input_device::event_dispatcher) | |||||
{ | |||||
return; | |||||
} | |||||
key_released_event event; | |||||
event.keyboard = this; | |||||
event.scancode = scancode; | |||||
input_device::event_dispatcher->queue(event); | |||||
} | |||||
std::map<std::string, scancode> keyboard::build_scancode_map() | |||||
{ | |||||
std::map<std::string, scancode> scancode_map; | |||||
for (std::size_t i = 0; i <= static_cast<std::size_t>(scancode::audio_fast_forward); ++i) | |||||
{ | |||||
if (scancode_names[i] != nullptr) | |||||
{ | |||||
std::string scancode_name = scancode_names[i]; | |||||
scancode_map[scancode_name] = static_cast<scancode>(i); | |||||
} | |||||
} | |||||
return scancode_map; | |||||
} | |||||
const char* keyboard::scancode_names[] = | |||||
{ | |||||
nullptr, // UNKNOWN | |||||
"A", // A | |||||
"B", // B | |||||
"C", // C | |||||
"D", // D | |||||
"E", // E | |||||
"F", // F | |||||
"G", // G | |||||
"H", // H | |||||
"I", // I | |||||
"J", // J | |||||
"K", // K | |||||
"L", // L | |||||
"M", // M | |||||
"N", // N | |||||
"O", // O | |||||
"P", // P | |||||
"Q", // Q | |||||
"R", // R | |||||
"S", // S | |||||
"T", // T | |||||
"U", // U | |||||
"V", // V | |||||
"W", // W | |||||
"X", // X | |||||
"Y", // Y | |||||
"Z", // Z | |||||
"1", // ONE | |||||
"2", // TWO | |||||
"3", // THREE | |||||
"4", // FOUR | |||||
"5", // FIVE | |||||
"6", // SIX | |||||
"7", // SEVEN | |||||
"8", // EIGHT | |||||
"9", // NINE | |||||
"0", // ZERO | |||||
"Enter", // ENTER | |||||
"Escape", // ESCAPE | |||||
"Backspace", // BACKSPACE | |||||
"Tab", // TAB | |||||
"Space", // SPACE | |||||
"-", // MINUS | |||||
"=", // EQUALS | |||||
"[", // LEFTBRACKET | |||||
"]", // RIGHTBRACKET | |||||
"\\", // BACKSLASH | |||||
"#", // NONUSHASH | |||||
";", // SEMICOLON | |||||
"'", // APOSTROPHE | |||||
"`", // GRAVE | |||||
",", // COMMA | |||||
".", // PERIOD | |||||
"/", // SLASH | |||||
"Caps Lock", // CAPSLOCK | |||||
"F1", // F1 | |||||
"F2", // F2 | |||||
"F3", // F3 | |||||
"F4", // F4 | |||||
"F5", // F5 | |||||
"F6", // F6 | |||||
"F7", // F7 | |||||
"F8", // F8 | |||||
"F9", // F9 | |||||
"F10", // F10 | |||||
"F11", // F11 | |||||
"F12", // F12 | |||||
"Print Screen", // PRINTSCREEN | |||||
"Scroll Lock", // SCROLLLOCK | |||||
"Pause", // PAUSE | |||||
"Insert", // INSERT | |||||
"Home", // HOME | |||||
"Page Up", // PAGEUP | |||||
"Delete", // DELETE | |||||
"End", // END | |||||
"Page Down", // PAGEDOWN | |||||
"Right", // RIGHT | |||||
"Left", // LEFT | |||||
"Down", // DOWN | |||||
"Up", // UP | |||||
"Num Lock", // NUMLOCKCLEAR | |||||
"Keypad /", // KP_DIVIDE | |||||
"Keypad *", // KP_MULTIPLY | |||||
"Keypad -", // KP_MINUS | |||||
"Keypad +", // KP_PLUS | |||||
"Keypad Enter", // KP_ENTER | |||||
"Keypad 1", // KP_1 | |||||
"Keypad 2", // KP_2 | |||||
"Keypad 3", // KP_3 | |||||
"Keypad 4", // KP_4 | |||||
"Keypad 5", // KP_5 | |||||
"Keypad 6", // KP_6 | |||||
"Keypad 7", // KP_7 | |||||
"Keypad 8", // KP_8 | |||||
"Keypad 9", // KP_9 | |||||
"Keypad 0", // KP_0 | |||||
"Keypad .", // KP_PERIOD | |||||
nullptr, // NONUSBACKSLASH | |||||
"Application", // APPLICATION | |||||
"Power", // POWER | |||||
"Keypad =", // KP_EQUALS | |||||
"F13", // F13 | |||||
"F14", // F14 | |||||
"F15", // F15 | |||||
"F16", // F16 | |||||
"F17", // F17 | |||||
"F18", // F18 | |||||
"F19", // F19 | |||||
"F20", // F20 | |||||
"F21", // F21 | |||||
"F22", // F22 | |||||
"F23", // F23 | |||||
"F24", // F24 | |||||
"Execute", // EXECUTE | |||||
"Help", // HELP | |||||
"Menu", // MENU | |||||
"Select", // SELECT | |||||
"Stop", // STOP | |||||
"Again", // AGAIN | |||||
"Undo", // UNDO | |||||
"Cut", // CUT | |||||
"Copy", // COPY | |||||
"Paste", // PASTE | |||||
"Find", // FIND | |||||
"Mute", // MUTE | |||||
"Volume Up", // VOLUMEUP | |||||
"Volume Down", // VOLUMEDOWN | |||||
nullptr, // LOCKINGCAPSLOCK | |||||
nullptr, // LOCKINGNUMLOCK | |||||
nullptr, // LOCKINGSCROLLLOCK | |||||
"Keypad ,", // KP_COMMA | |||||
"Keypad = (AS400)", // KP_EQUALSAS400 | |||||
nullptr, // INTERNATIONAL1 | |||||
nullptr, // INTERNATIONAL2 | |||||
nullptr, // INTERNATIONAL3 | |||||
nullptr, // INTERNATIONAL4 | |||||
nullptr, // INTERNATIONAL5 | |||||
nullptr, // INTERNATIONAL6 | |||||
nullptr, // INTERNATIONAL7 | |||||
nullptr, // INTERNATIONAL8 | |||||
nullptr, // INTERNATIONAL9 | |||||
nullptr, // LANG1 | |||||
nullptr, // LANG2 | |||||
nullptr, // LANG3 | |||||
nullptr, // LANG4 | |||||
nullptr, // LANG5 | |||||
nullptr, // LANG6 | |||||
nullptr, // LANG7 | |||||
nullptr, // LANG8 | |||||
nullptr, // LANG9 | |||||
"Alt Erase", // ALTERASE | |||||
"Sys Req", // SYSREQ | |||||
"Cancel", // CANCEL | |||||
"Clear", // CLEAR | |||||
"Prior", // PRIOR | |||||
"Return", // RETURN2 | |||||
"Separator", // SEPARATOR | |||||
"Out", // OUT | |||||
"Oper", // OPER | |||||
"Clear/Again", // CLEARAGAIN | |||||
"CrSel", // CRSEL | |||||
"ExSel", // EXSEL | |||||
"Keypad 00", // KP_00 | |||||
"Keypad 000", // KP_000 | |||||
"Thousands Separator", // THOUSANDSSEPARATOR | |||||
"Decimal Separator", // DECIMALSEPARATOR | |||||
"Currency Unit", // CURRENCYUNIT | |||||
"Currency Sub-Unit", // CURRENCYSUBUNIT | |||||
"Keypad (", // KP_LEFTPAREN | |||||
"Keypad )", // KP_RIGHTPAREN | |||||
"Keypad {", // KP_LEFTBRACE | |||||
"Keypad }", // KP_RIGHTBRACE | |||||
"Keypad Tab", // KP_TAB | |||||
"Keypad Backspace", // KP_BACKSPACE | |||||
"Keypad A", // KP_A | |||||
"Keypad B", // KP_B | |||||
"Keypad C", // KP_C | |||||
"Keypad D", // KP_D | |||||
"Keypad E", // KP_E | |||||
"Keypad F", // KP_F | |||||
"Keypad XOR", // KP_XOR | |||||
"Keypad ^", // KP_POWER | |||||
"Keypad %", // KP_PERCENT | |||||
"Keypad <", // KP_LESS | |||||
"Keypad >", // KP_GREATER | |||||
"Keypad &", // KP_AMPERSAND | |||||
"Keypad &&", // KP_DBLAMPERSAND | |||||
"Keypad |", // KP_VERTICALBAR | |||||
"Keypad ||", // KP_DBLVERTICALBAR | |||||
"Keypad :", // KP_COLON | |||||
"Keypad #", // KP_HASH | |||||
"Keypad Space", // KP_SPACE | |||||
"Keypad @", // KP_AT | |||||
"Keypad !", // KP_EXCLAM | |||||
"Keypad Mem Store", // KP_MEMSTORE | |||||
"Keypad Mem Recall", // KP_MEMRECALL | |||||
"Keypad Mem Clear", // KP_MEMCLEAR | |||||
"Keypad Mem Add", // KP_MEMADD | |||||
"Keypad Mem Subtract", // KP_MEMSUBTRACT | |||||
"Keypad Mem Multiply", // KP_MEMMULTIPLY | |||||
"Keypad Mem Divide", // KP_MEMDIVIDE | |||||
"Keypad +/-", // KP_PLUSMINUS | |||||
"Keypad Clear", // KP_CLEAR | |||||
"Keypad Clear Entry", // KP_CLEARENTRY | |||||
"Keypad Binary", // KP_BINARY | |||||
"Keypad Octal", // KP_OCTAL | |||||
"Keypad Decimal", // KP_DECIMAL | |||||
"Keypad Hexadecimal", // KP_HEXADECIMAL | |||||
"Left Ctrl", // LCTRL | |||||
"Left Shift", // LSHIFT | |||||
"Left Alt", // LALT | |||||
"Left GUI", // LGUI | |||||
"Right Ctrl", // RCTRL | |||||
"Right Shift", // RSHIFT | |||||
"Right Alt", // RALT | |||||
"Right GUI", // RGUI | |||||
"Mode Switch", // MODE | |||||
"Audio Next", // AUDIONEXT | |||||
"Audio Prev", // AUDIOPREV | |||||
"Audio Stop", // AUDIOSTOP | |||||
"Audio Play", // AUDIOPLAY | |||||
"Audio Mute", // AUDIOMUTE | |||||
"Media Select", // MEDIASELECT | |||||
"WWW", // WWW | |||||
"Mail", // MAIL | |||||
"Calculator", // CALCULATOR | |||||
"Computer", // COMPUTER | |||||
"AC Search", // AC_SEARCH | |||||
"AC Home", // AC_HOME | |||||
"AC Back", // AC_BACK | |||||
"AC Forward", // AC_FORWARD | |||||
"AC Stop", // AC_STOP | |||||
"AC Refresh", // AC_REFRESH | |||||
"AC Bookmarks", // AC_BOOKMARKS | |||||
"Brightness Down", // BRIGHTNESSDOWN | |||||
"Brightness Up", // BRIGHTNESSUP | |||||
"Display Switch", // DISPLAYSWITCH | |||||
"KBD Illum Toggle", // KBDILLUMTOGGLE | |||||
"KBD Illum Down", // KBDILLUMDOWN | |||||
"KBD Illum Up", // KBDILLUMUP | |||||
"Eject", // EJECT | |||||
"Sleep", // SLEEP | |||||
"App 1", // APP1 | |||||
"App 2", // APP2 | |||||
"Audio Rewind", // AUDIOREWIND | |||||
"Audio Fast-Forward", // AUDIOFASTFORWARD | |||||
}; | |||||
std::map<std::string, scancode> keyboard::scancode_map = keyboard::build_scancode_map(); | |||||
@ -0,0 +1,77 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_KEYBOARD_HPP | |||||
#define ANTKEEPER_KEYBOARD_HPP | |||||
#include "input-device.hpp" | |||||
#include <map> | |||||
#include <string> | |||||
enum class scancode; | |||||
/** | |||||
* A virtual keyboard which can generate keyboard-related input events and pass them to an event dispatcher. | |||||
*/ | |||||
class keyboard: public input_device | |||||
{ | |||||
public: | |||||
/** | |||||
* Returns the UTF-8 encoded name of a scancode. | |||||
*/ | |||||
static const char* get_scancode_name(scancode scancode); | |||||
/** | |||||
* Returns the scancode corresponding to a scancode name. | |||||
* | |||||
* @param name Name of a scancode. | |||||
* @return Corresponding scancode, or nullptr if a matching scancode was not found. | |||||
*/ | |||||
static scancode get_scancode_from_name(const char* name); | |||||
/** | |||||
* Creates a keyboard input device. | |||||
*/ | |||||
keyboard(); | |||||
/// Destroys a keyboard input device. | |||||
virtual ~keyboard(); | |||||
/** | |||||
* Simulates a key press. | |||||
* | |||||
* @param scancode scancode of the simulated key press. | |||||
*/ | |||||
void press(scancode scancode); | |||||
/** | |||||
* Simulates a key release. | |||||
* | |||||
* @param scancode scancode of the simulated key release. | |||||
*/ | |||||
void release(scancode scancode); | |||||
private: | |||||
static std::map<std::string, scancode> build_scancode_map(); | |||||
static const char* scancode_names[]; | |||||
static std::map<std::string, scancode> scancode_map; | |||||
}; | |||||
#endif // ANTKEEPER_KEYBOARD_HPP | |||||
@ -0,0 +1,93 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "mouse.hpp" | |||||
#include "input-events.hpp" | |||||
#include "event/event-dispatcher.hpp" | |||||
mouse::mouse() | |||||
{} | |||||
void mouse::press(int button, int x, int y) | |||||
{ | |||||
if (!input_device::event_dispatcher) | |||||
{ | |||||
return; | |||||
} | |||||
mouse_button_pressed_event event; | |||||
event.mouse = this; | |||||
event.button = button; | |||||
event.x = x; | |||||
event.y = y; | |||||
input_device::event_dispatcher->queue(event); | |||||
} | |||||
void mouse::release(int button, int x, int y) | |||||
{ | |||||
if (!input_device::event_dispatcher) | |||||
{ | |||||
return; | |||||
} | |||||
mouse_button_released_event event; | |||||
event.mouse = this; | |||||
event.button = button; | |||||
event.x = x; | |||||
event.y = y; | |||||
input_device::event_dispatcher->queue(event); | |||||
} | |||||
void mouse::move(int x, int y, int dx, int dy) | |||||
{ | |||||
previous_position = current_position; | |||||
current_position = {x, y}; | |||||
if (!input_device::event_dispatcher) | |||||
{ | |||||
return; | |||||
} | |||||
mouse_moved_event event; | |||||
event.mouse = this; | |||||
event.x = x; | |||||
event.y = y; | |||||
event.dx = dx; | |||||
event.dy = dy; | |||||
input_device::event_dispatcher->queue(event); | |||||
} | |||||
void mouse::scroll(int x, int y) | |||||
{ | |||||
if (!input_device::event_dispatcher) | |||||
{ | |||||
return; | |||||
} | |||||
mouse_wheel_scrolled_event event; | |||||
event.mouse = this; | |||||
event.x = x; | |||||
event.y = y; | |||||
input_device::event_dispatcher->queue(event); | |||||
} | |||||
@ -0,0 +1,131 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_MOUSE_HPP | |||||
#define ANTKEEPER_MOUSE_HPP | |||||
#include "input-device.hpp" | |||||
#include <tuple> | |||||
/** | |||||
* Enumerates the mouse motion axes. | |||||
*/ | |||||
enum class mouse_motion_axis | |||||
{ | |||||
/// Indicates the positive X-axis. | |||||
positive_x, | |||||
/// Indicates the negative X-axis. | |||||
negative_x, | |||||
/// Indicates the positive Y-axis. | |||||
positive_y, | |||||
/// Indicates the negative Y-axis. | |||||
negative_y | |||||
}; | |||||
/** | |||||
* Enumerates the mouse wheel axes. | |||||
*/ | |||||
enum class mouse_wheel_axis | |||||
{ | |||||
/// Indicates the positive X-axis. | |||||
positive_x, | |||||
/// Indicates the negative X-axis. | |||||
negative_x, | |||||
/// Indicates the positive Y-axis. | |||||
positive_y, | |||||
/// Indicates the negative Y-axis. | |||||
negative_y | |||||
}; | |||||
/** | |||||
* A virtual mouse which can generate mouse-related input events and pass them to an event dispatcher. | |||||
*/ | |||||
class mouse: public input_device | |||||
{ | |||||
public: | |||||
/** | |||||
* Creates a mouse input device. | |||||
*/ | |||||
mouse(); | |||||
/// Destroys a mouse input device. | |||||
virtual ~mouse() = default; | |||||
/** | |||||
* Simulates a mouse button press. | |||||
* | |||||
* @param button Index of the pressed button. | |||||
* @param x X-coordinate of the mouse position. | |||||
* @param y Y-coordinate of the mouse position. | |||||
*/ | |||||
void press(int button, int x, int y); | |||||
/** | |||||
* Simulates a mouse button release. | |||||
* | |||||
* @param button Index of the released button. | |||||
* @param x X-coordinate of the mouse position. | |||||
* @param y Y-coordinate of the mouse position. | |||||
*/ | |||||
void release(int button, int x, int y); | |||||
/** | |||||
* Simulates mouse movement. | |||||
* | |||||
* @param x X-coordinate of the mouse position. | |||||
* @param y Y-coordinate of the mouse position. | |||||
* @param dx Relative movement on the X-axis. | |||||
* @param dy Relative movement on the Y-axis. | |||||
*/ | |||||
void move(int x, int y, int dx, int dy); | |||||
/** | |||||
* Simulates mouse wheel scrolling. | |||||
*/ | |||||
void scroll(int x, int y); | |||||
/// Returns the current mouse position. | |||||
const std::tuple<int, int>& get_current_position() const; | |||||
/// Returns the previous mouse position. | |||||
const std::tuple<int, int>& get_previous_position() const; | |||||
private: | |||||
std::tuple<int, int> current_position; | |||||
std::tuple<int, int> previous_position; | |||||
}; | |||||
inline const std::tuple<int, int>& mouse::get_current_position() const | |||||
{ | |||||
return current_position; | |||||
} | |||||
inline const std::tuple<int, int>& mouse::get_previous_position() const | |||||
{ | |||||
return previous_position; | |||||
} | |||||
#endif // ANTKEEPER_MOUSE_HPP | |||||
@ -0,0 +1,277 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_SCANCODE_HPP | |||||
#define ANTKEEPER_SCANCODE_HPP | |||||
/** | |||||
* Enumerates keyboard scancodes. | |||||
*/ | |||||
enum class scancode | |||||
{ | |||||
unknown, | |||||
a, | |||||
b, | |||||
c, | |||||
d, | |||||
e, | |||||
f, | |||||
g, | |||||
h, | |||||
i, | |||||
j, | |||||
k, | |||||
l, | |||||
m, | |||||
n, | |||||
o, | |||||
p, | |||||
q, | |||||
r, | |||||
s, | |||||
t, | |||||
u, | |||||
v, | |||||
w, | |||||
x, | |||||
y, | |||||
z, | |||||
one, | |||||
two, | |||||
three, | |||||
four, | |||||
five, | |||||
six, | |||||
seven, | |||||
eight, | |||||
nine, | |||||
zero, | |||||
enter, | |||||
escape, | |||||
backspace, | |||||
tab, | |||||
space, | |||||
minus, | |||||
equal, | |||||
left_brace, | |||||
right_brace, | |||||
backslash, | |||||
non_us_hash, | |||||
semicolon, | |||||
apostrophe, | |||||
grave, | |||||
comma, | |||||
dot, | |||||
slash, | |||||
caps_lock, | |||||
f1, | |||||
f2, | |||||
f3, | |||||
f4, | |||||
f5, | |||||
f6, | |||||
f7, | |||||
f8, | |||||
f9, | |||||
f10, | |||||
f11, | |||||
f12, | |||||
print_screen, | |||||
scroll_lock, | |||||
pause, | |||||
insert, | |||||
home, | |||||
page_up, | |||||
del, | |||||
end, | |||||
page_down, | |||||
right, | |||||
left, | |||||
down, | |||||
up, | |||||
num_lock, | |||||
kp_slash, | |||||
kp_asterisk, | |||||
kp_minus, | |||||
kp_plus, | |||||
kp_enter, | |||||
kp_1, | |||||
kp_2, | |||||
kp_3, | |||||
kp_4, | |||||
kp_5, | |||||
kp_6, | |||||
kp_7, | |||||
kp_8, | |||||
kp_9, | |||||
kp_0, | |||||
kp_dot, | |||||
non_us_backslash, | |||||
application, | |||||
power, | |||||
kp_equal, | |||||
f13, | |||||
f14, | |||||
f15, | |||||
f16, | |||||
f17, | |||||
f18, | |||||
f19, | |||||
f20, | |||||
f21, | |||||
f22, | |||||
f23, | |||||
f24, | |||||
execute, | |||||
help, | |||||
menu, | |||||
select, | |||||
stop, | |||||
again, | |||||
undo, | |||||
cut, | |||||
copy, | |||||
paste, | |||||
find, | |||||
mute, | |||||
volume_up, | |||||
volume_down, | |||||
locking_caps_lock, | |||||
locking_num_lock, | |||||
locking_scroll_lock, | |||||
kp_comma, | |||||
kp_equal_as400, | |||||
international_1, | |||||
international_2, | |||||
international_3, | |||||
international_4, | |||||
international_5, | |||||
international_6, | |||||
international_7, | |||||
international_8, | |||||
international_9, | |||||
lang_1, | |||||
lang_2, | |||||
lang_3, | |||||
lang_4, | |||||
lang_5, | |||||
lang_6, | |||||
lang_7, | |||||
lang_8, | |||||
lang_9, | |||||
alt_erase, | |||||
sys_req, | |||||
cancel, | |||||
clear, | |||||
prior, | |||||
return_2, | |||||
separator, | |||||
_out, | |||||
oper, | |||||
clear_again, | |||||
cr_sel, | |||||
ex_sel, | |||||
kp_00, | |||||
kp_000, | |||||
thousands_separator, | |||||
decimal_separator, | |||||
currency_unit, | |||||
currency_sub_unit, | |||||
kp_left_paren, | |||||
kp_right_paren, | |||||
kp_left_brace, | |||||
kp_right_brace, | |||||
kp_tab, | |||||
kp_backspace, | |||||
kp_a, | |||||
kp_b, | |||||
kp_c, | |||||
kp_d, | |||||
kp_e, | |||||
kp_f, | |||||
kp_xor, | |||||
kp_power, | |||||
kp_percent, | |||||
kp_less, | |||||
kp_greater, | |||||
kp_ampersand, | |||||
kp_double_ampersand, | |||||
kp_vertical_bar, | |||||
kp_double_vertical_bar, | |||||
kp_colon, | |||||
kp_hash, | |||||
kp_space, | |||||
kp_at, | |||||
kp_exclam, | |||||
kp_mem_store, | |||||
kp_mem_recall, | |||||
kp_mem_clear, | |||||
kp_mem_add, | |||||
kp_mem_subtract, | |||||
kp_mem_multiply, | |||||
kp_mem_divide, | |||||
kp_plus_minus, | |||||
kp_clear, | |||||
kp_clear_entry, | |||||
kp_binary, | |||||
kp_octal, | |||||
kp_decimal, | |||||
kp_hexadecimal, | |||||
left_ctrl, | |||||
left_shift, | |||||
left_alt, | |||||
left_gui, | |||||
right_ctrl, | |||||
right_shift, | |||||
right_alt, | |||||
right_gui, | |||||
mode, | |||||
audio_next, | |||||
audio_prev, | |||||
audio_stop, | |||||
audio_play, | |||||
audio_mute, | |||||
media_select, | |||||
www, | |||||
mail, | |||||
calculator, | |||||
computer, | |||||
ac_search, | |||||
ac_home, | |||||
ac_back, | |||||
ac_forward, | |||||
ac_stop, | |||||
ac_refresh, | |||||
ac_bookmarks, | |||||
brightness_down, | |||||
brightness_up, | |||||
display_switch, | |||||
kbd_illum_toggle, | |||||
kbd_illum_down, | |||||
kbd_illum_up, | |||||
eject, | |||||
sleep, | |||||
app_1, | |||||
app_2, | |||||
audio_rewind, | |||||
audio_fast_forward | |||||
}; | |||||
#endif // ANTKEEPER_SCANCODE_HPP | |||||
@ -0,0 +1,51 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "sdl-game-controller-tables.hpp" | |||||
#include "game-controller.hpp" | |||||
const game_controller_button sdl_button_table[15] = | |||||
{ | |||||
game_controller_button::a, // SDL_CONTROLLER_BUTTON_A, | |||||
game_controller_button::b, // SDL_CONTROLLER_BUTTON_B, | |||||
game_controller_button::x, // SDL_CONTROLLER_BUTTON_X, | |||||
game_controller_button::y, // SDL_CONTROLLER_BUTTON_Y, | |||||
game_controller_button::back, // SDL_CONTROLLER_BUTTON_BACK, | |||||
game_controller_button::guide, // SDL_CONTROLLER_BUTTON_GUIDE, | |||||
game_controller_button::start, // SDL_CONTROLLER_BUTTON_START, | |||||
game_controller_button::left_stick, // SDL_CONTROLLER_BUTTON_LEFTSTICK, | |||||
game_controller_button::right_stick, // SDL_CONTROLLER_BUTTON_RIGHTSTICK, | |||||
game_controller_button::left_shoulder, // SDL_CONTROLLER_BUTTON_LEFTSHOULDER, | |||||
game_controller_button::right_shoulder, // SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, | |||||
game_controller_button::dpad_up, // SDL_CONTROLLER_BUTTON_DPAD_UP, | |||||
game_controller_button::dpad_down, // SDL_CONTROLLER_BUTTON_DPAD_DOWN, | |||||
game_controller_button::dpad_left, // SDL_CONTROLLER_BUTTON_DPAD_LEFT, | |||||
game_controller_button::dpad_right, // SDL_CONTROLLER_BUTTON_DPAD_RIGHT, | |||||
}; | |||||
const game_controller_axis sdl_axis_table[6] = | |||||
{ | |||||
game_controller_axis::left_x, // SDL_CONTROLLER_AXIS_LEFTX, | |||||
game_controller_axis::left_y, // SDL_CONTROLLER_AXIS_LEFTY, | |||||
game_controller_axis::right_x, // SDL_CONTROLLER_AXIS_RIGHTX, | |||||
game_controller_axis::right_y, // SDL_CONTROLLER_AXIS_RIGHTY, | |||||
game_controller_axis::trigger_left, // SDL_CONTROLLER_AXIS_TRIGGERLEFT, | |||||
game_controller_axis::trigger_right, // SDL_CONTROLLER_AXIS_TRIGGERRIGHT, | |||||
}; | |||||
@ -0,0 +1,30 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_SDL_GAME_CONTROLLER_TABLES_HPP | |||||
#define ANTKEEPER_SDL_GAME_CONTROLLER_TABLES_HPP | |||||
enum class game_controller_button; | |||||
enum class game_controller_axis; | |||||
extern const game_controller_button sdl_button_table[15]; | |||||
extern const game_controller_axis sdl_axis_table[6]; | |||||
#endif // ANTKEEPER_SDL_GAME_CONTROLLER_TABLES_HPP | |||||
@ -0,0 +1,313 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "sdl-scancode-table.hpp" | |||||
#include "scancode.hpp" | |||||
const scancode sdl_scancode_table[287] = | |||||
{ | |||||
scancode::unknown, // SDL_SCANCODE_UNKNOWN = 0, | |||||
scancode::unknown, // Unassigned = 1 | |||||
scancode::unknown, // Unassigned = 2 | |||||
scancode::unknown, // Unassigned = 3 | |||||
scancode::a, // SDL_SCANCODE_A = 4, | |||||
scancode::b, // SDL_SCANCODE_B = 5, | |||||
scancode::c, // SDL_SCANCODE_C = 6, | |||||
scancode::d, // SDL_SCANCODE_D = 7, | |||||
scancode::e, // SDL_SCANCODE_E = 8, | |||||
scancode::f, // SDL_SCANCODE_F = 9, | |||||
scancode::g, // SDL_SCANCODE_G = 10, | |||||
scancode::h, // SDL_SCANCODE_H = 11, | |||||
scancode::i, // SDL_SCANCODE_I = 12, | |||||
scancode::j, // SDL_SCANCODE_J = 13, | |||||
scancode::k, // SDL_SCANCODE_K = 14, | |||||
scancode::l, // SDL_SCANCODE_L = 15, | |||||
scancode::m, // SDL_SCANCODE_M = 16, | |||||
scancode::n, // SDL_SCANCODE_N = 17, | |||||
scancode::o, // SDL_SCANCODE_O = 18, | |||||
scancode::p, // SDL_SCANCODE_P = 19, | |||||
scancode::q, // SDL_SCANCODE_Q = 20, | |||||
scancode::r, // SDL_SCANCODE_R = 21, | |||||
scancode::s, // SDL_SCANCODE_S = 22, | |||||
scancode::t, // SDL_SCANCODE_T = 23, | |||||
scancode::u, // SDL_SCANCODE_U = 24, | |||||
scancode::v, // SDL_SCANCODE_V = 25, | |||||
scancode::w, // SDL_SCANCODE_W = 26, | |||||
scancode::x, // SDL_SCANCODE_X = 27, | |||||
scancode::y, // SDL_SCANCODE_Y = 28, | |||||
scancode::z, // SDL_SCANCODE_Z = 29, | |||||
scancode::one, // SDL_SCANCODE_1 = 30, | |||||
scancode::two, // SDL_SCANCODE_2 = 31, | |||||
scancode::three, // SDL_SCANCODE_3 = 32, | |||||
scancode::four, // SDL_SCANCODE_4 = 33, | |||||
scancode::five, // SDL_SCANCODE_5 = 34, | |||||
scancode::six, // SDL_SCANCODE_6 = 35, | |||||
scancode::seven, // SDL_SCANCODE_7 = 36, | |||||
scancode::eight, // SDL_SCANCODE_8 = 37, | |||||
scancode::nine, // SDL_SCANCODE_9 = 38, | |||||
scancode::zero, // SDL_SCANCODE_0 = 39, | |||||
scancode::enter, // SDL_SCANCODE_RETURN = 40, | |||||
scancode::escape, // SDL_SCANCODE_ESCAPE = 41, | |||||
scancode::backspace, // SDL_SCANCODE_BACKSPACE = 42, | |||||
scancode::tab, // SDL_SCANCODE_TAB = 43, | |||||
scancode::space, // SDL_SCANCODE_SPACE = 44, | |||||
scancode::minus, // SDL_SCANCODE_MINUS = 45, | |||||
scancode::equal, // SDL_SCANCODE_EQUALS = 46, | |||||
scancode::left_brace, // SDL_SCANCODE_LEFTBRACKET = 47, | |||||
scancode::right_brace, // SDL_SCANCODE_RIGHTBRACKET = 48, | |||||
scancode::backslash, // SDL_SCANCODE_BACKSLASH = 49, | |||||
scancode::non_us_hash, // SDL_SCANCODE_NONUSHASH = 50, | |||||
scancode::semicolon, // SDL_SCANCODE_SEMICOLON = 51, | |||||
scancode::apostrophe, // SDL_SCANCODE_APOSTROPHE = 52, | |||||
scancode::grave, // SDL_SCANCODE_GRAVE = 53, | |||||
scancode::comma, // SDL_SCANCODE_COMMA = 54, | |||||
scancode::dot, // SDL_SCANCODE_PERIOD = 55, | |||||
scancode::slash, // SDL_SCANCODE_SLASH = 56, | |||||
scancode::caps_lock, // SDL_SCANCODE_CAPSLOCK = 57, | |||||
scancode::f1, // SDL_SCANCODE_F1 = 58, | |||||
scancode::f2, // SDL_SCANCODE_F2 = 59, | |||||
scancode::f3, // SDL_SCANCODE_F3 = 60, | |||||
scancode::f4, // SDL_SCANCODE_F4 = 61, | |||||
scancode::f5, // SDL_SCANCODE_F5 = 62, | |||||
scancode::f6, // SDL_SCANCODE_F6 = 63, | |||||
scancode::f7, // SDL_SCANCODE_F7 = 64, | |||||
scancode::f8, // SDL_SCANCODE_F8 = 65, | |||||
scancode::f9, // SDL_SCANCODE_F9 = 66, | |||||
scancode::f10, // SDL_SCANCODE_F10 = 67, | |||||
scancode::f11, // SDL_SCANCODE_F11 = 68, | |||||
scancode::f12, // SDL_SCANCODE_F12 = 69, | |||||
scancode::print_screen, // SDL_SCANCODE_PRINTSCREEN = 70, | |||||
scancode::scroll_lock, // SDL_SCANCODE_SCROLLLOCK = 71, | |||||
scancode::pause, // SDL_SCANCODE_PAUSE = 72, | |||||
scancode::insert, // SDL_SCANCODE_INSERT = 73, | |||||
scancode::home, // SDL_SCANCODE_HOME = 74, | |||||
scancode::page_up, // SDL_SCANCODE_PAGEUP = 75, | |||||
scancode::del, // SDL_SCANCODE_DELETE = 76, | |||||
scancode::end, // SDL_SCANCODE_END = 77, | |||||
scancode::page_down, // SDL_SCANCODE_PAGEDOWN = 78, | |||||
scancode::right, // SDL_SCANCODE_RIGHT = 79, | |||||
scancode::left, // SDL_SCANCODE_LEFT = 80, | |||||
scancode::down, // SDL_SCANCODE_DOWN = 81, | |||||
scancode::up, // SDL_SCANCODE_UP = 82, | |||||
scancode::num_lock, // SDL_SCANCODE_NUMLOCKCLEAR = 83, | |||||
scancode::kp_slash, // SDL_SCANCODE_KP_DIVIDE = 84, | |||||
scancode::kp_asterisk, // SDL_SCANCODE_KP_MULTIPLY = 85, | |||||
scancode::kp_minus, // SDL_SCANCODE_KP_MINUS = 86, | |||||
scancode::kp_plus, // SDL_SCANCODE_KP_PLUS = 87, | |||||
scancode::kp_enter, // SDL_SCANCODE_KP_ENTER = 88, | |||||
scancode::kp_1, // SDL_SCANCODE_KP_1 = 89, | |||||
scancode::kp_2, // SDL_SCANCODE_KP_2 = 90, | |||||
scancode::kp_3, // SDL_SCANCODE_KP_3 = 91, | |||||
scancode::kp_4, // SDL_SCANCODE_KP_4 = 92, | |||||
scancode::kp_5, // SDL_SCANCODE_KP_5 = 93, | |||||
scancode::kp_6, // SDL_SCANCODE_KP_6 = 94, | |||||
scancode::kp_7, // SDL_SCANCODE_KP_7 = 95, | |||||
scancode::kp_8, // SDL_SCANCODE_KP_8 = 96, | |||||
scancode::kp_9, // SDL_SCANCODE_KP_9 = 97, | |||||
scancode::kp_0, // SDL_SCANCODE_KP_0 = 98, | |||||
scancode::kp_dot, // SDL_SCANCODE_KP_PERIOD = 99, | |||||
scancode::non_us_backslash, // SDL_SCANCODE_NONUSBACKSLASH = 100, | |||||
scancode::application, // SDL_SCANCODE_APPLICATION = 101, | |||||
scancode::power, // SDL_SCANCODE_POWER = 102, | |||||
scancode::kp_equal, // SDL_SCANCODE_KP_EQUALS = 103, | |||||
scancode::f13, // SDL_SCANCODE_F13 = 104, | |||||
scancode::f14, // SDL_SCANCODE_F14 = 105, | |||||
scancode::f15, // SDL_SCANCODE_F15 = 106, | |||||
scancode::f16, // SDL_SCANCODE_F16 = 107, | |||||
scancode::f17, // SDL_SCANCODE_F17 = 108, | |||||
scancode::f18, // SDL_SCANCODE_F18 = 109, | |||||
scancode::f19, // SDL_SCANCODE_F19 = 110, | |||||
scancode::f20, // SDL_SCANCODE_F20 = 111, | |||||
scancode::f21, // SDL_SCANCODE_F21 = 112, | |||||
scancode::f22, // SDL_SCANCODE_F22 = 113, | |||||
scancode::f23, // SDL_SCANCODE_F23 = 114, | |||||
scancode::f24, // SDL_SCANCODE_F24 = 115, | |||||
scancode::execute, // SDL_SCANCODE_EXECUTE = 116, | |||||
scancode::help, // SDL_SCANCODE_HELP = 117, | |||||
scancode::menu, // SDL_SCANCODE_MENU = 118, | |||||
scancode::select, // SDL_SCANCODE_SELECT = 119, | |||||
scancode::stop, // SDL_SCANCODE_STOP = 120, | |||||
scancode::again, // SDL_SCANCODE_AGAIN = 121, | |||||
scancode::undo, // SDL_SCANCODE_UNDO = 122, | |||||
scancode::cut, // SDL_SCANCODE_CUT = 123, | |||||
scancode::copy, // SDL_SCANCODE_COPY = 124, | |||||
scancode::paste, // SDL_SCANCODE_PASTE = 125, | |||||
scancode::find, // SDL_SCANCODE_FIND = 126, | |||||
scancode::mute, // SDL_SCANCODE_MUTE = 127, | |||||
scancode::volume_up, // SDL_SCANCODE_VOLUMEUP = 128, | |||||
scancode::volume_down, // SDL_SCANCODE_VOLUMEDOWN = 129, | |||||
scancode::locking_caps_lock, // Unassigned = 130 | |||||
scancode::locking_num_lock, // Unassigned = 131 | |||||
scancode::locking_scroll_lock, // Unassigned = 132 | |||||
scancode::kp_comma, // SDL_SCANCODE_KP_COMMA = 133, | |||||
scancode::kp_equal_as400, // SDL_SCANCODE_KP_EQUALSAS400 = 134, | |||||
scancode::international_1, // SDL_SCANCODE_INTERNATIONAL1 = 135, | |||||
scancode::international_2, // SDL_SCANCODE_INTERNATIONAL2 = 136, | |||||
scancode::international_3, // SDL_SCANCODE_INTERNATIONAL3 = 137, | |||||
scancode::international_4, // SDL_SCANCODE_INTERNATIONAL4 = 138, | |||||
scancode::international_5, // SDL_SCANCODE_INTERNATIONAL5 = 139, | |||||
scancode::international_6, // SDL_SCANCODE_INTERNATIONAL6 = 140, | |||||
scancode::international_7, // SDL_SCANCODE_INTERNATIONAL7 = 141, | |||||
scancode::international_8, // SDL_SCANCODE_INTERNATIONAL8 = 142, | |||||
scancode::international_9, // SDL_SCANCODE_INTERNATIONAL9 = 143, | |||||
scancode::lang_1, // SDL_SCANCODE_LANG1 = 144, | |||||
scancode::lang_2, // SDL_SCANCODE_LANG2 = 145, | |||||
scancode::lang_3, // SDL_SCANCODE_LANG3 = 146, | |||||
scancode::lang_4, // SDL_SCANCODE_LANG4 = 147, | |||||
scancode::lang_5, // SDL_SCANCODE_LANG5 = 148, | |||||
scancode::lang_6, // SDL_SCANCODE_LANG6 = 149, | |||||
scancode::lang_7, // SDL_SCANCODE_LANG7 = 150, | |||||
scancode::lang_8, // SDL_SCANCODE_LANG8 = 151, | |||||
scancode::lang_9, // SDL_SCANCODE_LANG9 = 152, | |||||
scancode::alt_erase, // SDL_SCANCODE_ALTERASE = 153, | |||||
scancode::sys_req, // SDL_SCANCODE_SYSREQ = 154, | |||||
scancode::cancel, // SDL_SCANCODE_CANCEL = 155, | |||||
scancode::clear, // SDL_SCANCODE_CLEAR = 156, | |||||
scancode::prior, // SDL_SCANCODE_PRIOR = 157, | |||||
scancode::return_2, // SDL_SCANCODE_RETURN2 = 158, | |||||
scancode::separator, // SDL_SCANCODE_SEPARATOR = 159, | |||||
scancode::_out, // SDL_SCANCODE_OUT = 160, | |||||
scancode::oper, // SDL_SCANCODE_OPER = 161, | |||||
scancode::clear_again, // SDL_SCANCODE_CLEARAGAIN = 162, | |||||
scancode::cr_sel, // SDL_SCANCODE_CRSEL = 163, | |||||
scancode::ex_sel, // SDL_SCANCODE_EXSEL = 164, | |||||
scancode::unknown, // Unassigned = 165 | |||||
scancode::unknown, // Unassigned = 166 | |||||
scancode::unknown, // Unassigned = 167 | |||||
scancode::unknown, // Unassigned = 168 | |||||
scancode::unknown, // Unassigned = 169 | |||||
scancode::unknown, // Unassigned = 170 | |||||
scancode::unknown, // Unassigned = 171 | |||||
scancode::unknown, // Unassigned = 172 | |||||
scancode::unknown, // Unassigned = 173 | |||||
scancode::unknown, // Unassigned = 174 | |||||
scancode::unknown, // Unassigned = 175 | |||||
scancode::kp_00, // SDL_SCANCODE_KP_00 = 176, | |||||
scancode::kp_000, // SDL_SCANCODE_KP_000 = 177, | |||||
scancode::thousands_separator, // SDL_SCANCODE_THOUSANDSSEPARATOR = 178, | |||||
scancode::decimal_separator, // SDL_SCANCODE_DECIMALSEPARATOR = 179, | |||||
scancode::currency_unit, // SDL_SCANCODE_CURRENCYUNIT = 180, | |||||
scancode::currency_sub_unit, // SDL_SCANCODE_CURRENCYSUBUNIT = 181, | |||||
scancode::kp_left_paren, // SDL_SCANCODE_KP_LEFTPAREN = 182, | |||||
scancode::kp_right_paren, // SDL_SCANCODE_KP_RIGHTPAREN = 183, | |||||
scancode::kp_left_brace, // SDL_SCANCODE_KP_LEFTBRACE = 184, | |||||
scancode::kp_right_brace, // SDL_SCANCODE_KP_RIGHTBRACE = 185, | |||||
scancode::kp_tab, // SDL_SCANCODE_KP_TAB = 186, | |||||
scancode::kp_backspace, // SDL_SCANCODE_KP_BACKSPACE = 187, | |||||
scancode::kp_a, // SDL_SCANCODE_KP_A = 188, | |||||
scancode::kp_b, // SDL_SCANCODE_KP_B = 189, | |||||
scancode::kp_c, // SDL_SCANCODE_KP_C = 190, | |||||
scancode::kp_d, // SDL_SCANCODE_KP_D = 191, | |||||
scancode::kp_e, // SDL_SCANCODE_KP_E = 192, | |||||
scancode::kp_f, // SDL_SCANCODE_KP_F = 193, | |||||
scancode::kp_xor, // SDL_SCANCODE_KP_XOR = 194, | |||||
scancode::kp_power, // SDL_SCANCODE_KP_POWER = 195, | |||||
scancode::kp_percent, // SDL_SCANCODE_KP_PERCENT = 196, | |||||
scancode::kp_less, // SDL_SCANCODE_KP_LESS = 197, | |||||
scancode::kp_greater, // SDL_SCANCODE_KP_GREATER = 198, | |||||
scancode::kp_ampersand, // SDL_SCANCODE_KP_AMPERSAND = 199, | |||||
scancode::kp_double_ampersand, // SDL_SCANCODE_KP_DBLAMPERSAND = 200, | |||||
scancode::kp_vertical_bar, // SDL_SCANCODE_KP_VERTICALBAR = 201, | |||||
scancode::kp_double_vertical_bar, // SDL_SCANCODE_KP_DBLVERTICALBAR = 202, | |||||
scancode::kp_colon, // SDL_SCANCODE_KP_COLON = 203, | |||||
scancode::kp_hash, // SDL_SCANCODE_KP_HASH = 204, | |||||
scancode::kp_space, // SDL_SCANCODE_KP_SPACE = 205, | |||||
scancode::kp_at, // SDL_SCANCODE_KP_AT = 206, | |||||
scancode::kp_exclam, // SDL_SCANCODE_KP_EXCLAM = 207, | |||||
scancode::kp_mem_store, // SDL_SCANCODE_KP_MEMSTORE = 208, | |||||
scancode::kp_mem_recall, // SDL_SCANCODE_KP_MEMRECALL = 209, | |||||
scancode::kp_mem_clear, // SDL_SCANCODE_KP_MEMCLEAR = 210, | |||||
scancode::kp_mem_add, // SDL_SCANCODE_KP_MEMADD = 211, | |||||
scancode::kp_mem_subtract, // SDL_SCANCODE_KP_MEMSUBTRACT = 212, | |||||
scancode::kp_mem_multiply, // SDL_SCANCODE_KP_MEMMULTIPLY = 213, | |||||
scancode::kp_mem_divide, // SDL_SCANCODE_KP_MEMDIVIDE = 214, | |||||
scancode::kp_plus_minus, // SDL_SCANCODE_KP_PLUSMINUS = 215, | |||||
scancode::kp_clear, // SDL_SCANCODE_KP_CLEAR = 216, | |||||
scancode::kp_clear_entry, // SDL_SCANCODE_KP_CLEARENTRY = 217, | |||||
scancode::kp_binary, // SDL_SCANCODE_KP_BINARY = 218, | |||||
scancode::kp_octal, // SDL_SCANCODE_KP_OCTAL = 219, | |||||
scancode::kp_decimal, // SDL_SCANCODE_KP_DECIMAL = 220, | |||||
scancode::kp_hexadecimal, // SDL_SCANCODE_KP_HEXADECIMAL = 221, | |||||
scancode::unknown, // Unassigned = 222 | |||||
scancode::unknown, // Unassigned = 223 | |||||
scancode::left_ctrl, // SDL_SCANCODE_LCTRL = 224, | |||||
scancode::left_shift, // SDL_SCANCODE_LSHIFT = 225, | |||||
scancode::left_alt, // SDL_SCANCODE_LALT = 226, | |||||
scancode::left_gui, // SDL_SCANCODE_LGUI = 227, | |||||
scancode::right_ctrl, // SDL_SCANCODE_RCTRL = 228, | |||||
scancode::right_shift, // SDL_SCANCODE_RSHIFT = 229, | |||||
scancode::right_alt, // SDL_SCANCODE_RALT = 230, | |||||
scancode::right_gui, // SDL_SCANCODE_RGUI = 231, | |||||
scancode::unknown, // Unassigned = 232 | |||||
scancode::unknown, // Unassigned = 233 | |||||
scancode::unknown, // Unassigned = 234 | |||||
scancode::unknown, // Unassigned = 235 | |||||
scancode::unknown, // Unassigned = 236 | |||||
scancode::unknown, // Unassigned = 237 | |||||
scancode::unknown, // Unassigned = 238 | |||||
scancode::unknown, // Unassigned = 239 | |||||
scancode::unknown, // Unassigned = 240 | |||||
scancode::unknown, // Unassigned = 241 | |||||
scancode::unknown, // Unassigned = 242 | |||||
scancode::unknown, // Unassigned = 243 | |||||
scancode::unknown, // Unassigned = 244 | |||||
scancode::unknown, // Unassigned = 245 | |||||
scancode::unknown, // Unassigned = 246 | |||||
scancode::unknown, // Unassigned = 247 | |||||
scancode::unknown, // Unassigned = 248 | |||||
scancode::unknown, // Unassigned = 249 | |||||
scancode::unknown, // Unassigned = 250 | |||||
scancode::unknown, // Unassigned = 251 | |||||
scancode::unknown, // Unassigned = 252 | |||||
scancode::unknown, // Unassigned = 253 | |||||
scancode::unknown, // Unassigned = 254 | |||||
scancode::unknown, // Unassigned = 255 | |||||
scancode::unknown, // Unassigned = 256 | |||||
scancode::mode, // SDL_SCANCODE_MODE = 257, | |||||
scancode::audio_next, // SDL_SCANCODE_AUDIONEXT = 258, | |||||
scancode::audio_prev, // SDL_SCANCODE_AUDIOPREV = 259, | |||||
scancode::audio_stop, // SDL_SCANCODE_AUDIOSTOP = 260, | |||||
scancode::audio_play, // SDL_SCANCODE_AUDIOPLAY = 261, | |||||
scancode::audio_mute, // SDL_SCANCODE_AUDIOMUTE = 262, | |||||
scancode::media_select, // SDL_SCANCODE_MEDIASELECT = 263, | |||||
scancode::www, // SDL_SCANCODE_WWW = 264, | |||||
scancode::mail, // SDL_SCANCODE_MAIL = 265, | |||||
scancode::calculator, // SDL_SCANCODE_CALCULATOR = 266, | |||||
scancode::computer, // SDL_SCANCODE_COMPUTER = 267, | |||||
scancode::ac_search, // SDL_SCANCODE_AC_SEARCH = 268, | |||||
scancode::ac_home, // SDL_SCANCODE_AC_HOME = 269, | |||||
scancode::ac_back, // SDL_SCANCODE_AC_BACK = 270, | |||||
scancode::ac_forward, // SDL_SCANCODE_AC_FORWARD = 271, | |||||
scancode::ac_stop, // SDL_SCANCODE_AC_STOP = 272, | |||||
scancode::ac_refresh, // SDL_SCANCODE_AC_REFRESH = 273, | |||||
scancode::ac_bookmarks, // SDL_SCANCODE_AC_BOOKMARKS = 274, | |||||
scancode::brightness_down, // SDL_SCANCODE_BRIGHTNESSDOWN = 275, | |||||
scancode::brightness_up, // SDL_SCANCODE_BRIGHTNESSUP = 276, | |||||
scancode::display_switch, // SDL_SCANCODE_DISPLAYSWITCH = 277, | |||||
scancode::kbd_illum_toggle, // SDL_SCANCODE_KBDILLUMTOGGLE = 278, | |||||
scancode::kbd_illum_down, // SDL_SCANCODE_KBDILLUMDOWN = 279, | |||||
scancode::kbd_illum_up, // SDL_SCANCODE_KBDILLUMUP = 280, | |||||
scancode::eject, // SDL_SCANCODE_EJECT = 281, | |||||
scancode::sleep, // SDL_SCANCODE_SLEEP = 282, | |||||
scancode::app_1, // SDL_SCANCODE_APP1 = 283, | |||||
scancode::app_2, // SDL_SCANCODE_APP2 = 284, | |||||
scancode::audio_rewind, // SDL_SCANCODE_AUDIOREWIND = 285, | |||||
scancode::audio_fast_forward, // SDL_SCANCODE_AUDIOFASTFORWARD = 286, | |||||
}; | |||||
@ -0,0 +1,28 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_SDL_SCANCODE_TABLE_HPP | |||||
#define ANTKEEPER_SDL_SCANCODE_TABLE_HPP | |||||
enum class scancode; | |||||
extern const scancode sdl_scancode_table[287]; | |||||
#endif // ANTKEEPER_SDL_SCANCODE_TABLE_HPP | |||||
@ -1,35 +1,37 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper Source Code. | |||||
* | |||||
* Antkeeper Source Code is free software: you can 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. | |||||
* | |||||
* Antkeeper Source Code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper Source Code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "game.hpp" | |||||
int main(int argc, char* argv[]) | |||||
{ | |||||
try | |||||
{ | |||||
return Game(argc, argv).execute(); | |||||
} | |||||
catch (const std::exception& e) | |||||
{ | |||||
std::cerr << "Exception caught: \"" << e.what() << "\"" << std::endl; | |||||
} | |||||
return EXIT_FAILURE; | |||||
} | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "application.hpp" | |||||
#include <iostream> | |||||
#include <stdexcept> | |||||
int main(int argc, char* argv[]) | |||||
{ | |||||
try | |||||
{ | |||||
return application(argc, argv).execute(); | |||||
} | |||||
catch (const std::exception& e) | |||||
{ | |||||
std::cerr << "Exception caught: \"" << e.what() << "\"" << std::endl; | |||||
} | |||||
return EXIT_FAILURE; | |||||
} | |||||
@ -0,0 +1,417 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "marching-cubes.hpp" | |||||
#include <cmath> | |||||
namespace mc { | |||||
static constexpr std::uint_fast8_t vertex_table[12][2] = | |||||
{ | |||||
{0, 1}, | |||||
{1, 2}, | |||||
{2, 3}, | |||||
{3, 0}, | |||||
{4, 5}, | |||||
{5, 6}, | |||||
{6, 7}, | |||||
{7, 4}, | |||||
{0, 4}, | |||||
{1, 5}, | |||||
{2, 6}, | |||||
{3, 7} | |||||
}; | |||||
static constexpr std::uint_fast16_t edge_table[256] = | |||||
{ | |||||
0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, | |||||
0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, | |||||
0x190, 0x099, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, | |||||
0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, | |||||
0x230, 0x339, 0x033, 0x13a, 0x636, 0x73f, 0x435, 0x53c, | |||||
0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, | |||||
0x3a0, 0x2a9, 0x1a3, 0x0aa, 0x7a6, 0x6af, 0x5a5, 0x4ac, | |||||
0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, | |||||
0x460, 0x569, 0x663, 0x76a, 0x066, 0x16f, 0x265, 0x36c, | |||||
0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, | |||||
0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0x0ff, 0x3f5, 0x2fc, | |||||
0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, | |||||
0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x055, 0x15c, | |||||
0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, | |||||
0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0x0cc, | |||||
0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, | |||||
0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, | |||||
0x0cc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, | |||||
0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, | |||||
0x15c, 0x055, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, | |||||
0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, | |||||
0x2fc, 0x3f5, 0x0ff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, | |||||
0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, | |||||
0x36c, 0x265, 0x16f, 0x066, 0x76a, 0x663, 0x569, 0x460, | |||||
0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, | |||||
0x4ac, 0x5a5, 0x6af, 0x7a6, 0x0aa, 0x1a3, 0x2a9, 0x3a0, | |||||
0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, | |||||
0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x033, 0x339, 0x230, | |||||
0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, | |||||
0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x099, 0x190, | |||||
0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, | |||||
0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000 | |||||
}; | |||||
static constexpr std::int_fast8_t triangle_table[256][16] = | |||||
{ | |||||
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1}, | |||||
{3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1}, | |||||
{3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1}, | |||||
{3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1}, | |||||
{9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1}, | |||||
{9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}, | |||||
{2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1}, | |||||
{8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1}, | |||||
{9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}, | |||||
{4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1}, | |||||
{3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1}, | |||||
{4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1}, | |||||
{4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1}, | |||||
{9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}, | |||||
{5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1}, | |||||
{2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1}, | |||||
{9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}, | |||||
{2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1}, | |||||
{10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1}, | |||||
{4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1}, | |||||
{5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1}, | |||||
{5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1}, | |||||
{9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1}, | |||||
{10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1}, | |||||
{8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1}, | |||||
{2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1}, | |||||
{7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1}, | |||||
{9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1}, | |||||
{2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1}, | |||||
{11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1}, | |||||
{9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1}, | |||||
{5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1}, | |||||
{11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1}, | |||||
{11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1}, | |||||
{9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1}, | |||||
{5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1}, | |||||
{2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1}, | |||||
{5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1}, | |||||
{6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1}, | |||||
{3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1}, | |||||
{6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1}, | |||||
{5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}, | |||||
{10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1}, | |||||
{6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1}, | |||||
{8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1}, | |||||
{7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1}, | |||||
{3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}, | |||||
{5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1}, | |||||
{0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1}, | |||||
{9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1}, | |||||
{8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1}, | |||||
{5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1}, | |||||
{0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1}, | |||||
{6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1}, | |||||
{10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1}, | |||||
{10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1}, | |||||
{8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1}, | |||||
{1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1}, | |||||
{3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1}, | |||||
{0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1}, | |||||
{10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1}, | |||||
{3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1}, | |||||
{6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1}, | |||||
{9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1}, | |||||
{8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1}, | |||||
{3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1}, | |||||
{6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1}, | |||||
{10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1}, | |||||
{10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1}, | |||||
{2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1}, | |||||
{7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1}, | |||||
{7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1}, | |||||
{2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1}, | |||||
{1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1}, | |||||
{11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1}, | |||||
{8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1}, | |||||
{0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1}, | |||||
{7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1}, | |||||
{10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}, | |||||
{2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}, | |||||
{6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1}, | |||||
{7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1}, | |||||
{2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1}, | |||||
{10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1}, | |||||
{10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1}, | |||||
{0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1}, | |||||
{7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1}, | |||||
{6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1}, | |||||
{8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1}, | |||||
{6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1}, | |||||
{4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1}, | |||||
{10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1}, | |||||
{8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1}, | |||||
{1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1}, | |||||
{8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1}, | |||||
{10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1}, | |||||
{4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1}, | |||||
{10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1}, | |||||
{5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}, | |||||
{11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1}, | |||||
{9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}, | |||||
{6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1}, | |||||
{7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1}, | |||||
{3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1}, | |||||
{7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1}, | |||||
{9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1}, | |||||
{3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1}, | |||||
{6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1}, | |||||
{9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1}, | |||||
{1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1}, | |||||
{4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1}, | |||||
{7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1}, | |||||
{6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1}, | |||||
{3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1}, | |||||
{0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1}, | |||||
{6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1}, | |||||
{0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1}, | |||||
{11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1}, | |||||
{6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1}, | |||||
{5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1}, | |||||
{9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1}, | |||||
{1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1}, | |||||
{10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1}, | |||||
{0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1}, | |||||
{5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1}, | |||||
{10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1}, | |||||
{11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1}, | |||||
{9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1}, | |||||
{7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1}, | |||||
{2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1}, | |||||
{8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1}, | |||||
{9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1}, | |||||
{9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1}, | |||||
{1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1}, | |||||
{9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1}, | |||||
{9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1}, | |||||
{5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1}, | |||||
{0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1}, | |||||
{10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1}, | |||||
{2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1}, | |||||
{0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1}, | |||||
{0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1}, | |||||
{9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1}, | |||||
{5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1}, | |||||
{3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1}, | |||||
{5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1}, | |||||
{8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1}, | |||||
{9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1}, | |||||
{1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1}, | |||||
{3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1}, | |||||
{4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1}, | |||||
{9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1}, | |||||
{11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1}, | |||||
{11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1}, | |||||
{2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1}, | |||||
{9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1}, | |||||
{3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1}, | |||||
{1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1}, | |||||
{4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1}, | |||||
{4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1}, | |||||
{3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1}, | |||||
{3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1}, | |||||
{0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1}, | |||||
{9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1}, | |||||
{1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, | |||||
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1} | |||||
}; | |||||
void polygonize(float* vertices, std::uint_fast8_t* vertex_count, std::int_fast8_t* triangles, std::uint_fast8_t* triangle_count, const float* corners, const float* distances) | |||||
{ | |||||
*vertex_count = 0; | |||||
*triangle_count = 0; | |||||
// Calculate signed distances for each cube corner and form an edge table index. | |||||
std::uint_fast8_t edge_index = 0; | |||||
for (std::uint_fast8_t i = 0; i < 8; ++i) | |||||
edge_index |= (distances[i] < 0.0f) ? (1 << i) : 0; | |||||
// Get edge flags from edge table | |||||
const std::uint_fast16_t edge_flags = edge_table[edge_index]; | |||||
if (!edge_flags) | |||||
return; | |||||
// Get vertex indices of the case | |||||
const std::int_fast8_t* indices = triangle_table[edge_index]; | |||||
// Calculate vertices and store in vertex buffer | |||||
float vertex_buffer[12 * 3]; | |||||
for (std::uint_fast16_t i = 0; i < 12; ++i) | |||||
{ | |||||
// If this edge is intersected | |||||
if (edge_flags & (1 << i)) | |||||
{ | |||||
// Find the two vertices which make up edge ab | |||||
std::uint_fast8_t a = vertex_table[i][0]; | |||||
std::uint_fast8_t b = vertex_table[i][1]; | |||||
const float* v_a = corners + a * 3; | |||||
const float* v_b = corners + b * 3; | |||||
float f_a = distances[a]; | |||||
float f_b = distances[b]; | |||||
// Determine interpolation ratio | |||||
static const float epsilon = 0.00001f; | |||||
float t; | |||||
if (std::fabs(f_a) < epsilon) | |||||
t = 1.0f; | |||||
else if (std::fabs(f_b) < epsilon) | |||||
t = 0.0f; | |||||
else if (std::fabs(f_b - f_a) < epsilon) | |||||
t = 0.5f; // Paul Bourke suggested this be 1.0f? Why? | |||||
else | |||||
t = (-f_a) / (f_b - f_a); | |||||
// Interpolate between vertices | |||||
float* v = vertex_buffer + i * 3; | |||||
v[0] = v_a[0] + t * (v_b[0] - v_a[0]); | |||||
v[1] = v_a[1] + t * (v_b[1] - v_a[1]); | |||||
v[2] = v_a[2] + t * (v_b[2] - v_a[2]); | |||||
} | |||||
} | |||||
// Remap vertex buffer to be stored contiguously | |||||
std::int_fast8_t vertex_remap[12]; | |||||
for (std::uint_fast8_t i = 0; i < 12; ++i) | |||||
vertex_remap[i] = -1; | |||||
for (std::uint_fast8_t i = 0; indices[i] != -1; ++i) | |||||
{ | |||||
if (vertex_remap[indices[i]] == -1) | |||||
{ | |||||
std::int_fast8_t index = indices[i] * 3; | |||||
*(vertices++) = vertex_buffer[ index]; | |||||
*(vertices++) = vertex_buffer[++index]; | |||||
*(vertices++) = vertex_buffer[++index]; | |||||
vertex_remap[indices[i]] = (*vertex_count)++; | |||||
} | |||||
} | |||||
// Form triangles | |||||
for (std::uint_fast8_t i = 0; indices[i] != -1;) | |||||
{ | |||||
*(triangles++) = vertex_remap[indices[i++]]; | |||||
*(triangles++) = vertex_remap[indices[i++]]; | |||||
*(triangles++) = vertex_remap[indices[i++]]; | |||||
++(*triangle_count); | |||||
} | |||||
} | |||||
} // namespace mc | |||||
@ -0,0 +1,58 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_MARCHING_CUBES_HPP | |||||
#define ANTKEEPER_MARCHING_CUBES_HPP | |||||
#include <cstdint> | |||||
/** | |||||
* Contains functions and constants related to the Marching Cubes (MC) algorithm. | |||||
*/ | |||||
namespace mc { | |||||
/** | |||||
* Uses the marching cubes algorithm to polygonize a single cell. | |||||
* | |||||
* @param[out] vertices Array which can hold at least 12 vertices (36 floats). | |||||
* @param[out] vertex_count Number of generated vertices. | |||||
* @param[out] triangles Array which can hold 5 at least triangles (15 ints). | |||||
* @param[out] triangle_count Number of generated triangles. The maximum number triangles generated for a single cell is 5. | |||||
*/ | |||||
void polygonize(float* vertices, std::uint_fast8_t* vertex_count, std::int_fast8_t* triangles, std::uint_fast8_t* triangle_count, const float* corners, const float* distances); | |||||
/** | |||||
* Vertices of a unit cube. | |||||
*/ | |||||
constexpr float unit_cube[8][3] = | |||||
{ | |||||
{0, 0, 0}, | |||||
{1, 0, 0}, | |||||
{1, 1, 0}, | |||||
{0, 1, 0}, | |||||
{0, 0, 1}, | |||||
{1, 0, 1}, | |||||
{1, 1, 1}, | |||||
{0, 1, 1} | |||||
}; | |||||
} // namespace mc | |||||
#endif // ANTKEEPER_MARCHING_CUBES_HPP | |||||
@ -0,0 +1,75 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_MATH_HPP | |||||
#define ANTKEEPER_MATH_HPP | |||||
#include <cstdlib> | |||||
#include <type_traits> | |||||
#include <vmq/vmq.hpp> | |||||
using namespace vmq::operators; | |||||
inline float frand(float start, float end) | |||||
{ | |||||
float f = (float)std::rand() / RAND_MAX; | |||||
return start + f * (end - start); | |||||
} | |||||
namespace math { | |||||
/** | |||||
* Reinterprets data as an `N`-dimensional vector of type `T`. | |||||
* | |||||
* @tparam N Number of vector dimensions. | |||||
* @tparam T Scalar type. | |||||
* @param data Data to reinterpret. | |||||
*/ | |||||
template <std::size_t N, typename T> | |||||
inline vmq::vector<T, N>& as_vector(T& data) | |||||
{ | |||||
static_assert(std::is_pod<vmq::vector<T, N>>::value); | |||||
return reinterpret_cast<vmq::vector<T, N>&>(data); | |||||
} | |||||
/** | |||||
* Reinterprets data as an `NxM` matrix of type `T`. | |||||
* | |||||
* @tparam N Number of columns. | |||||
* @tparam M Number of rows. | |||||
* @tparam T Element type. | |||||
* @param data Data to reinterpret. | |||||
*/ | |||||
template <std::size_t N, std::size_t M, typename T> | |||||
inline vmq::matrix<T, N, M>& as_matrix(T& data) | |||||
{ | |||||
static_assert(std::is_pod<vmq::matrix<T, N, M>>::value); | |||||
return reinterpret_cast<vmq::matrix<T, N, M>&>(data); | |||||
} | |||||
template <class T> | |||||
vmq::vector<T, 3> project_on_plane(const vmq::vector<T, 3>& v, const vmq::vector<T, 3>& p, const vmq::vector<T, 3>& n) | |||||
{ | |||||
return v - n * vmq::dot(v - p, n); | |||||
} | |||||
} // namespace math | |||||
#endif // ANTKEEPER_MATH_HPP | |||||
@ -0,0 +1,85 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "morton.hpp" | |||||
namespace morton { | |||||
std::uint32_t encode_2d(std::uint32_t x, std::uint32_t y) | |||||
{ | |||||
auto interleave = [](std::uint32_t x) -> std::uint32_t | |||||
{ | |||||
x &= 0x0000ffff; | |||||
x = (x ^ (x << 8)) & 0x00ff00ff; | |||||
x = (x ^ (x << 4)) & 0x0f0f0f0f; | |||||
x = (x ^ (x << 2)) & 0x33333333; | |||||
x = (x ^ (x << 1)) & 0x55555555; | |||||
return x; | |||||
}; | |||||
return (interleave(y) << 1) + interleave(x); | |||||
} | |||||
std::uint32_t encode_3d(std::uint32_t x, std::uint32_t y, std::uint32_t z) | |||||
{ | |||||
auto interleave = [](std::uint32_t x) -> std::uint32_t | |||||
{ | |||||
x &= 0x000003ff; | |||||
x = (x ^ (x << 16)) & 0xff0000ff; | |||||
x = (x ^ (x << 8)) & 0x0300f00f; | |||||
x = (x ^ (x << 4)) & 0x030c30c3; | |||||
x = (x ^ (x << 2)) & 0x09249249; | |||||
return x; | |||||
}; | |||||
return interleave(x) | (interleave(y) << 1) | (interleave(z) << 2); | |||||
} | |||||
std::array<uint32_t, 2> decode_2d(std::uint32_t code) | |||||
{ | |||||
auto unravel = [](std::uint32_t x) -> std::uint32_t | |||||
{ | |||||
x &= 0x55555555; | |||||
x = (x ^ (x >> 1)) & 0x33333333; | |||||
x = (x ^ (x >> 2)) & 0x0f0f0f0f; | |||||
x = (x ^ (x >> 4)) & 0x00ff00ff; | |||||
x = (x ^ (x >> 8)) & 0x0000ffff; | |||||
return x; | |||||
}; | |||||
return {unravel(code >> 0), unravel(code >> 1)}; | |||||
} | |||||
std::array<uint32_t, 3> decode_3d(std::uint32_t code) | |||||
{ | |||||
auto unravel = [](std::uint32_t x) -> std::uint32_t | |||||
{ | |||||
x &= 0x09249249; | |||||
x = (x ^ (x >> 2)) & 0x030c30c3; | |||||
x = (x ^ (x >> 4)) & 0x0300f00f; | |||||
x = (x ^ (x >> 8)) & 0xff0000ff; | |||||
x = (x ^ (x >> 16)) & 0x000003ff; | |||||
return x; | |||||
}; | |||||
return {unravel(code >> 0), unravel(code >> 1), unravel(code >> 2)}; | |||||
} | |||||
} // namespace morton | |||||
@ -0,0 +1,46 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_MORTON_HPP | |||||
#define ANTKEEPER_MORTON_HPP | |||||
#include <array> | |||||
#include <cstdint> | |||||
/** | |||||
* Contains functions for encoding and decoding Morton location codes. | |||||
*/ | |||||
namespace morton { | |||||
/// Encodes 2D coordinates as a 32-bit Morton location code. | |||||
std::uint32_t encode_2d(std::uint32_t x, std::uint32_t y); | |||||
/// Encodes 3D coordinates as a 32-bit Morton location code. | |||||
std::uint32_t encode_3d(std::uint32_t x, std::uint32_t y, std::uint32_t z); | |||||
/// Decodes X and Y coordinates from a 32-bit Morton location code. | |||||
std::array<uint32_t, 2> decode_2d(std::uint32_t code); | |||||
/// Decodes X, Y, and Z coordinates from a 32-bit Morton location code. | |||||
std::array<uint32_t, 3> decode_3d(std::uint32_t code); | |||||
} // namespace morton | |||||
#endif // ANTKEEPER_MORTON_HPP | |||||
@ -0,0 +1,99 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "nest.hpp" | |||||
#include "animation/easings.hpp" | |||||
#include "marching-cubes.hpp" | |||||
#include "geometry/mesh-functions.hpp" | |||||
#include "sdf.hpp" | |||||
#include <functional> | |||||
#include <iostream> | |||||
#include <map> | |||||
#include <vector> | |||||
#include "math.hpp" | |||||
#include <functional> | |||||
#include <limits> | |||||
nest::nest() | |||||
{ | |||||
dig_radius = 1.25f; | |||||
} | |||||
float3 nest::extend_shaft(shaft& shaft) | |||||
{ | |||||
float3 dig_position = get_shaft_position(shaft, shaft.current_depth); | |||||
float dr = frand(dig_radius * 0.75f, dig_radius * 1.25f); | |||||
shaft.current_depth += dr * 0.5f; | |||||
return dig_position; | |||||
} | |||||
float3 nest::expand_chamber(chamber& chamber) | |||||
{ | |||||
float dig_angle = frand(0.0f, vmq::two_pi<float>); | |||||
float2 dig_direction = vmq::normalize(float2{std::cos(dig_angle), std::sin(dig_angle)}); | |||||
float3 chamber_center = get_shaft_position(*chamber.shaft, chamber.depth); | |||||
float3 dig_position = chamber_center; | |||||
float dr = frand(dig_radius * 0.75f, dig_radius * 1.25f); | |||||
float t = frand(0.0f, 1.0f); | |||||
dig_position.x += dig_direction.x * (chamber.outer_radius - dr) * t; | |||||
dig_position.z += dig_direction.y * (chamber.outer_radius - dr) * t; | |||||
return dig_position; | |||||
} | |||||
void nest::set_tunnel_radius(float radius) | |||||
{ | |||||
tunnel_radius = radius; | |||||
} | |||||
float nest::get_shaft_angle(const shaft& shaft, float depth) const | |||||
{ | |||||
float shaft_length = shaft.depth[1] - shaft.depth[0]; | |||||
float depth_factor = (depth - shaft.depth[0]) / shaft_length; | |||||
float pitch = ease_linear(shaft.pitch[0], shaft.pitch[1], depth_factor); | |||||
return shaft.rotation + (depth / pitch) * shaft.chirality; | |||||
} | |||||
float3 nest::get_shaft_position(const shaft& shaft, float depth) const | |||||
{ | |||||
float shaft_length = shaft.depth[1] - shaft.depth[0]; | |||||
float depth_factor = (depth - shaft.depth[0]) / shaft_length; | |||||
float pitch = ease_linear(shaft.pitch[0], shaft.pitch[1], depth_factor); | |||||
float radius = ease_out_expo(shaft.radius[0], shaft.radius[1], depth_factor); | |||||
float translation_x = ease_linear(shaft.translation[0][0], shaft.translation[1][0], depth_factor); | |||||
float translation_z = ease_linear(shaft.translation[0][1], shaft.translation[1][1], depth_factor); | |||||
float angle = shaft.rotation + (depth / pitch) * shaft.chirality; | |||||
float3 position; | |||||
position[0] = std::cos(angle) * radius + translation_x; | |||||
position[1] = -std::max<float>(shaft.depth[0], std::min<float>(shaft.depth[1], depth)); | |||||
position[2] = std::sin(angle) * radius + translation_z; | |||||
return position; | |||||
} | |||||
@ -0,0 +1,91 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_NEST_HPP | |||||
#define ANTKEEPER_NEST_HPP | |||||
#include "geometry/mesh.hpp" | |||||
#include <vmq/vmq.hpp> | |||||
#include <array> | |||||
#include <vector> | |||||
using namespace vmq::types; | |||||
using namespace vmq::operators; | |||||
class nest | |||||
{ | |||||
public: | |||||
struct chamber; | |||||
struct shaft | |||||
{ | |||||
std::array<float, 2> depth; ///< start and end shaft depth | |||||
float chirality; ///< 1 = right-handed, -1 = left-handed | |||||
float rotation; ///< starting helix angle, in radians | |||||
std::array<float, 2> radius; ///< start and end helix radius | |||||
std::array<float, 2> pitch; ///< start and end helix pitch | |||||
std::array<float2, 2> translation; ///< start and end helix translation | |||||
std::vector<chamber> chambers; | |||||
float current_depth; | |||||
}; | |||||
struct chamber | |||||
{ | |||||
shaft* shaft; ///< parent shaft | |||||
float depth; ///< chamber depth, relative to parent shaft | |||||
float rotation; ///< chamber rotation, relative to helix angle | |||||
float sector_angle; ///< | |||||
float inner_radius; | |||||
float outer_radius; | |||||
}; | |||||
/** | |||||
* Creates a nest. | |||||
*/ | |||||
nest(); | |||||
float3 extend_shaft(shaft& shaft); | |||||
float3 expand_chamber(chamber& chamber); | |||||
void regenerate(); | |||||
void set_tunnel_radius(float radius); | |||||
shaft* get_central_shaft(); | |||||
/** | |||||
* Calculates the position on a shaft at the specified depth. | |||||
*/ | |||||
float3 get_shaft_position(const shaft& shaft, float depth) const; | |||||
float get_shaft_angle(const shaft& shaft, float depth) const; | |||||
private: | |||||
float tunnel_radius; | |||||
shaft central_shaft; | |||||
float dig_radius; | |||||
}; | |||||
inline nest::shaft* nest::get_central_shaft() | |||||
{ | |||||
return ¢ral_shaft; | |||||
} | |||||
#endif // ANTKEEPER_NEST_HPP | |||||
@ -0,0 +1,455 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_OCTREE_HPP | |||||
#define ANTKEEPER_OCTREE_HPP | |||||
#include <cstdint> | |||||
#include <limits> | |||||
#include <type_traits> | |||||
#include <unordered_set> | |||||
#include <stack> | |||||
/** | |||||
* A general purpose (hashed) linear octree. Nodes are integer identifiers and no other data is stored in the octree. | |||||
* | |||||
* @tparam T Integer node type. Must be 16-bit, 32-bit, or 64-bit. | |||||
* | |||||
* @see http://codervil.blogspot.com/2015/10/octree-node-identifiers.html | |||||
* @see https://geidav.wordpress.com/2014/08/18/advanced-octrees-2-node-representations/ | |||||
*/ | |||||
template <class T> | |||||
class octree | |||||
{ | |||||
private: | |||||
/// Compile-time calculation of the minimum bits required to represent `n` state changes. | |||||
static constexpr T ceil_log2(T n); | |||||
public: | |||||
static_assert(std::is_integral<T>::value, "Node type must be integral."); | |||||
static_assert(sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, "Node type must be 16-bit, 32-bit, or 64-bit."); | |||||
/// Maximum octree depth | |||||
static constexpr T max_depth = (sizeof(T) == 2) ? 3 : (sizeof(T) == 4) ? 8 : 18; | |||||
/// Number of bits in the node type | |||||
static constexpr T node_bits = sizeof(T) * 8; | |||||
/// Number of bits used to encode the depth of a node. | |||||
static constexpr T depth_bits = ceil_log2(max_depth + 1); | |||||
/// Number of bits used to encode the Morton code location a node. | |||||
static constexpr T location_bits = (max_depth + 1) * 3; | |||||
/// Integer node type. | |||||
typedef T node_type; | |||||
/// Root node which is always guaranteed to exist. | |||||
static constexpr node_type root = 0; | |||||
/** | |||||
* Accesses nodes in their internal hashmap order. | |||||
*/ | |||||
struct unordered_iterator | |||||
{ | |||||
inline unordered_iterator(const unordered_iterator& other): set_iterator(other.set_iterator) {}; | |||||
inline unordered_iterator& operator=(const unordered_iterator& other) { this->set_iterator = other.set_iterator; return *this; }; | |||||
inline unordered_iterator& operator++() { ++(this->set_iterator); return *this; }; | |||||
inline unordered_iterator& operator--() { --(this->set_iterator); return *this; }; | |||||
inline bool operator==(const unordered_iterator& other) const { return this->set_iterator == other.set_iterator; }; | |||||
inline bool operator!=(const unordered_iterator& other) const { return this->set_iterator != other.set_iterator; }; | |||||
inline const node_type& operator*() const { return *this->set_iterator; }; | |||||
private: | |||||
friend class octree; | |||||
inline explicit unordered_iterator(const typename std::unordered_set<node_type>::const_iterator& it): set_iterator(it) {}; | |||||
typename std::unordered_set<node_type>::const_iterator set_iterator; | |||||
}; | |||||
/** | |||||
* Accesses nodes in z-order. TODO: I think this can be done without a stack. | |||||
*/ | |||||
struct iterator | |||||
{ | |||||
inline iterator(const iterator& other): octree(other.octree), stack(other.stack) {}; | |||||
inline iterator& operator=(const iterator& other) { this->octree = other.octree; this->stack = other.stack; return *this; }; | |||||
iterator& operator++(); | |||||
inline bool operator==(const iterator& other) const { return **this == *other; }; | |||||
inline bool operator!=(const iterator& other) const { return **this != *other; }; | |||||
inline const node_type& operator*() const { return stack.top(); }; | |||||
private: | |||||
friend class octree; | |||||
inline explicit iterator(const octree* octree, node_type node): octree(octree), stack({node}) {}; | |||||
const octree* octree; | |||||
std::stack<node_type> stack; | |||||
}; | |||||
/** | |||||
* Returns the depth of a node. | |||||
* | |||||
* @param node Node. | |||||
* @return Depth of the node. | |||||
*/ | |||||
static T depth(node_type node); | |||||
/** | |||||
* Returns the Morton code location of a node. | |||||
* | |||||
* @param node Node. | |||||
* @return Morton code location of the node. | |||||
*/ | |||||
static T location(node_type node); | |||||
/** | |||||
* Returns the node at the given depth and location. | |||||
* | |||||
* @param depth Node depth. | |||||
* @param location Node Morton code location. | |||||
*/ | |||||
static node_type node(T depth, T location); | |||||
/** | |||||
* Returns the ancestor of a node at the specified depth. | |||||
* | |||||
* @param node Node whose ancestor will be located. | |||||
* @param depth Absolute depth of the ancestors. | |||||
* @return Ancestral node. | |||||
*/ | |||||
static node_type ancestor(node_type node, T depth); | |||||
/** | |||||
* Returns the parent of a node. | |||||
* | |||||
* @param node Node. | |||||
* @return Parent node. | |||||
*/ | |||||
static node_type parent(node_type node); | |||||
/** | |||||
* Returns the nth sibling of a node. | |||||
* | |||||
* @param node Node. | |||||
* @param n Offset to next sibling. (Automatically wraps to 0..7) | |||||
* @return Next sibling node. | |||||
*/ | |||||
static node_type sibling(node_type node, T n); | |||||
/** | |||||
* Returns the nth child of a node. | |||||
* | |||||
* @param node Parent node. | |||||
* @param n Offset to the nth sibling of the first child node. (Automatically wraps to 0..7) | |||||
* @return nth child node. | |||||
*/ | |||||
static node_type child(node_type node, T n); | |||||
/** | |||||
* Calculates the first common ancestor of two nodes. | |||||
* | |||||
* @param a First node. | |||||
* @param b Second node. | |||||
* @return First common ancestor of the two nodes. | |||||
*/ | |||||
static node_type common_ancestor(node_type a, node_type b); | |||||
/// Creates an octree with a single root node. | |||||
octree(); | |||||
/// Returns a z-order iterator to the root node. | |||||
iterator begin() const; | |||||
/// Returns a z-order iterator indicating the end of a traversal. | |||||
iterator end() const; | |||||
/// Returns an iterator to the specified node. | |||||
iterator find(node_type node) const; | |||||
/// Returns an unordered iterator indicating the beginning of a traversal. | |||||
unordered_iterator unordered_begin() const; | |||||
/// Returns an unordered iterator indicating the end of a traversal. | |||||
unordered_iterator unordered_end() const; | |||||
/** | |||||
* Inserts a node and its siblings into the octree, creating its ancestors as necessary. Note: The root node is persistent and cannot be inserted. | |||||
* | |||||
* @param node Node to insert. | |||||
*/ | |||||
void insert(node_type node); | |||||
/** | |||||
* Erases a node along with its siblings and descendants. Note: The root node is persistent and cannot be erased. | |||||
* | |||||
* @param node Node to erase. | |||||
*/ | |||||
void erase(node_type node); | |||||
/** | |||||
* Erases all nodes except the root. | |||||
*/ | |||||
void clear(); | |||||
/// Returns `true` if the node exists in the octree, and `false` otherwise. | |||||
bool exists(node_type node) const; | |||||
/// Returns `true` if the node has no children, and `false` otherwise. | |||||
bool is_leaf(node_type node) const; | |||||
/// Returns the number of nodes in the octree. | |||||
std::size_t size() const; | |||||
private: | |||||
/// Compile-time pow() | |||||
static constexpr T pow(T x, T exponent); | |||||
/// Count leading zeros | |||||
static T clz(T x); | |||||
std::unordered_set<node_type> nodes; | |||||
}; | |||||
/** | |||||
* Octree with a 16-bit node type and a maximum depth of `3`. | |||||
*/ | |||||
typedef octree<std::uint16_t> octree16; | |||||
/** | |||||
* Octree with a 32-bit node type and a maximum depth of `8`. | |||||
*/ | |||||
typedef octree<std::uint32_t> octree32; | |||||
/** | |||||
* Octree with a 64-bit node type and a maximum depth of `18`. | |||||
*/ | |||||
typedef octree<std::uint64_t> octree64; | |||||
template <typename T> | |||||
typename octree<T>::iterator& octree<T>::iterator::operator++() | |||||
{ | |||||
// Get next node from top of stack | |||||
node_type node = stack.top(); | |||||
stack.pop(); | |||||
// If the node has children | |||||
if (!octree->is_leaf(node)) | |||||
{ | |||||
// Push first child onto the stack | |||||
for (T i = 0; i < 8; ++i) | |||||
stack.push(child(node, 7 - i)); | |||||
} | |||||
if (stack.empty()) | |||||
stack.push(std::numeric_limits<T>::max()); | |||||
return *this; | |||||
} | |||||
template <class T> | |||||
constexpr T octree<T>::ceil_log2(T n) | |||||
{ | |||||
return (n <= 1) ? 0 : ceil_log2((n + 1) / 2) + 1; | |||||
} | |||||
template <class T> | |||||
inline T octree<T>::depth(node_type node) | |||||
{ | |||||
// Extract depth using a bit mask | |||||
constexpr T mask = pow(2, depth_bits) - 1; | |||||
return node & mask; | |||||
} | |||||
template <class T> | |||||
inline T octree<T>::location(node_type node) | |||||
{ | |||||
return node >> ((node_bits - 1) - depth(node) * 3); | |||||
} | |||||
template <class T> | |||||
inline typename octree<T>::node_type octree<T>::node(T depth, T location) | |||||
{ | |||||
return (location << ((node_bits - 1) - depth * 3)) | depth; | |||||
} | |||||
template <class T> | |||||
inline typename octree<T>::node_type octree<T>::ancestor(node_type node, T depth) | |||||
{ | |||||
const T mask = std::numeric_limits<T>::max() << ((node_bits - 1) - depth * 3); | |||||
return (node & mask) | depth; | |||||
} | |||||
template <class T> | |||||
inline typename octree<T>::node_type octree<T>::parent(node_type node) | |||||
{ | |||||
return ancestor(node, depth(node) - 1); | |||||
} | |||||
template <class T> | |||||
inline typename octree<T>::node_type octree<T>::sibling(node_type node, T n) | |||||
{ | |||||
T depth = octree::depth(node); | |||||
T location = node >> ((node_bits - 1) - depth * 3); | |||||
return octree::node(depth, (location & (~0b111)) | ((location + n) & 0b111)); | |||||
} | |||||
template <class T> | |||||
inline typename octree<T>::node_type octree<T>::child(node_type node, T n) | |||||
{ | |||||
return sibling(node + 1, n); | |||||
} | |||||
template <class T> | |||||
inline typename octree<T>::node_type octree<T>::common_ancestor(node_type a, node_type b) | |||||
{ | |||||
T bits = std::min<T>(depth(a), depth(b)) * 3; | |||||
T marker = (T(1) << (node_bits - 1)) >> bits; | |||||
T depth = clz((a ^ b) | marker) / 3; | |||||
return ancestor(a, depth); | |||||
} | |||||
template <class T> | |||||
inline octree<T>::octree(): | |||||
nodes({0}) | |||||
{} | |||||
template <class T> | |||||
void octree<T>::insert(node_type node) | |||||
{ | |||||
if (exists(node)) | |||||
return; | |||||
// Insert node | |||||
nodes.emplace(node); | |||||
// Insert siblings | |||||
for (T i = 1; i < 8; ++i) | |||||
nodes.emplace(sibling(node, i)); | |||||
// Insert parent as necessary | |||||
node_type parent = octree::parent(node); | |||||
if (!exists(parent)) | |||||
insert(parent); | |||||
} | |||||
template <class T> | |||||
void octree<T>::erase(node_type node) | |||||
{ | |||||
// Don't erase the root! | |||||
if (node == root) | |||||
return; | |||||
for (T i = 0; i < 8; ++i) | |||||
{ | |||||
// Erase node | |||||
nodes.erase(node); | |||||
// Erase descendants | |||||
if (!is_leaf(node)) | |||||
{ | |||||
for (T j = 0; j < 8; ++j) | |||||
erase(child(node, j)); | |||||
} | |||||
// Go to next sibling | |||||
if (i < 7) | |||||
node = sibling(node, i); | |||||
} | |||||
} | |||||
template <class T> | |||||
void octree<T>::clear() | |||||
{ | |||||
nodes = {0}; | |||||
} | |||||
template <class T> | |||||
inline bool octree<T>::exists(node_type node) const | |||||
{ | |||||
return (nodes.find(node) != nodes.end()); | |||||
} | |||||
template <class T> | |||||
inline bool octree<T>::is_leaf(node_type node) const | |||||
{ | |||||
return !exists(child(node, 0)); | |||||
} | |||||
template <class T> | |||||
inline std::size_t octree<T>::size() const | |||||
{ | |||||
return nodes.size(); | |||||
} | |||||
template <class T> | |||||
typename octree<T>::iterator octree<T>::begin() const | |||||
{ | |||||
return iterator(this, octree::root); | |||||
} | |||||
template <class T> | |||||
typename octree<T>::iterator octree<T>::end() const | |||||
{ | |||||
return iterator(this, std::numeric_limits<T>::max()); | |||||
} | |||||
template <class T> | |||||
typename octree<T>::iterator octree<T>::find(node_type node) const | |||||
{ | |||||
return exists(node) ? iterator(node) : end(); | |||||
} | |||||
template <class T> | |||||
typename octree<T>::unordered_iterator octree<T>::unordered_begin() const | |||||
{ | |||||
return unordered_iterator(nodes.begin()); | |||||
} | |||||
template <class T> | |||||
typename octree<T>::unordered_iterator octree<T>::unordered_end() const | |||||
{ | |||||
return unordered_iterator(nodes.end()); | |||||
} | |||||
template <class T> | |||||
constexpr T octree<T>::pow(T x, T exponent) | |||||
{ | |||||
return (exponent == 0) ? 1 : x * pow(x, exponent - 1); | |||||
} | |||||
template <class T> | |||||
T octree<T>::clz(T x) | |||||
{ | |||||
if (!x) | |||||
return sizeof(T) * 8; | |||||
#if defined(__GNU__) | |||||
return __builtin_clz(x); | |||||
#else | |||||
T n = 0; | |||||
while ((x & (T(1) << (8 * sizeof(x) - 1))) == 0) | |||||
{ | |||||
x <<= 1; | |||||
++n; | |||||
} | |||||
return n; | |||||
#endif | |||||
} | |||||
#endif // ANTKEEPER_OCTREE_HPP | |||||
@ -0,0 +1,161 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "orbit-cam.hpp" | |||||
#include "scene/camera.hpp" | |||||
#include <algorithm> | |||||
#include <cmath> | |||||
using namespace vmq::operators; | |||||
template <class T> | |||||
static inline T lerp(const T& x, const T& y, float a) | |||||
{ | |||||
return x * (1.0f - a) + y * a; | |||||
} | |||||
orbit_cam::orbit_cam(): | |||||
elevation_rotation(vmq::identity_quaternion<float>), | |||||
azimuth_rotation(vmq::identity_quaternion<float>), | |||||
target_elevation_rotation(vmq::identity_quaternion<float>), | |||||
target_azimuth_rotation(vmq::identity_quaternion<float>), | |||||
target_rotation(vmq::identity_quaternion<float>) | |||||
{} | |||||
orbit_cam::~orbit_cam() | |||||
{} | |||||
void orbit_cam::update(float dt) | |||||
{ | |||||
float interpolation_factor = 1.0f; | |||||
// Calculate rotation and target rotation quaternions | |||||
//rotation = azimuth_rotation * elevation_rotation; | |||||
target_rotation = vmq::normalize(target_azimuth_rotation * target_elevation_rotation); | |||||
// Calculate target translation | |||||
target_translation = target_focal_point + target_rotation * float3{0.0f, 0.0f, target_focal_distance}; | |||||
// Interpolate rotation | |||||
//rotation = glm::mix(rotation, target_rotation, interpolation_factor); | |||||
// Interpolate angles | |||||
set_elevation(lerp(elevation, target_elevation, interpolation_factor)); | |||||
set_azimuth(lerp(azimuth, target_azimuth, interpolation_factor)); | |||||
// Calculate rotation | |||||
set_rotation(vmq::normalize(azimuth_rotation * elevation_rotation)); | |||||
// Interpolate focal point and focal distance | |||||
focal_point = vmq::lerp(focal_point, target_focal_point, interpolation_factor); | |||||
focal_distance = lerp(focal_distance, target_focal_distance, interpolation_factor); | |||||
// Caluclate translation | |||||
set_translation(focal_point + get_rotation() * float3{0.0f, 0.0f, focal_distance}); | |||||
/* | |||||
// Recalculate azimuth | |||||
azimuth_rotation = rotation; | |||||
azimuth_rotation.x = 0.0f; | |||||
azimuth_rotation.z = 0.0f; | |||||
azimuth_rotation = glm::normalize(azimuth_rotation); | |||||
azimuth = 2.0f * std::acos(azimuth_rotation.w); | |||||
// Recalculate elevation | |||||
elevation_rotation = rotation; | |||||
elevation_rotation.y = 0.0f; | |||||
elevation_rotation.z = 0.0f; | |||||
elevation_rotation = glm::normalize(elevation_rotation); | |||||
elevation = 2.0f * std::acos(elevation_rotation.w); | |||||
*/ | |||||
// Update camera | |||||
if (get_camera() != nullptr) | |||||
{ | |||||
transform<float> transform = vmq::identity_transform<float>; | |||||
transform.translation = get_translation(); | |||||
transform.rotation = get_rotation(); | |||||
get_camera()->set_transform(transform); | |||||
//get_camera()->look_at(get_translation(), get_translation() + get_forward(), get_up()); | |||||
} | |||||
} | |||||
void orbit_cam::move(const float2& direction) | |||||
{ | |||||
target_focal_point += azimuth_rotation * float3{direction[0], 0.0f, direction[1]}; | |||||
} | |||||
void orbit_cam::rotate(float angle) | |||||
{ | |||||
set_target_azimuth(target_azimuth + angle); | |||||
} | |||||
void orbit_cam::tilt(float angle) | |||||
{ | |||||
set_target_elevation(target_elevation + angle); | |||||
} | |||||
void orbit_cam::zoom(float distance) | |||||
{ | |||||
set_target_focal_distance(target_focal_distance - distance); | |||||
} | |||||
void orbit_cam::set_focal_point(const float3& point) | |||||
{ | |||||
focal_point = point; | |||||
} | |||||
void orbit_cam::set_focal_distance(float distance) | |||||
{ | |||||
focal_distance = distance; | |||||
} | |||||
void orbit_cam::set_elevation(float angle) | |||||
{ | |||||
elevation = angle; | |||||
elevation_rotation = vmq::angle_axis(elevation, float3{-1.0f, 0.0f, 0.0f}); | |||||
} | |||||
void orbit_cam::set_azimuth(float angle) | |||||
{ | |||||
azimuth = angle; | |||||
azimuth_rotation = vmq::angle_axis(azimuth, float3{0.0f, 1.0f, 0.0f}); | |||||
} | |||||
void orbit_cam::set_target_focal_point(const float3& point) | |||||
{ | |||||
target_focal_point = point; | |||||
} | |||||
void orbit_cam::set_target_focal_distance(float distance) | |||||
{ | |||||
target_focal_distance = distance; | |||||
} | |||||
void orbit_cam::set_target_elevation(float angle) | |||||
{ | |||||
target_elevation = angle; | |||||
target_elevation_rotation = vmq::angle_axis(target_elevation, float3{-1.0f, 0.0f, 0.0f}); | |||||
} | |||||
void orbit_cam::set_target_azimuth(float angle) | |||||
{ | |||||
target_azimuth = angle; | |||||
target_azimuth_rotation = vmq::angle_axis(target_azimuth, float3{0.0f, 1.0f, 0.0f}); | |||||
} | |||||
@ -0,0 +1,130 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_ORBIT_CAM_HPP | |||||
#define ANTKEEPER_ORBIT_CAM_HPP | |||||
#include "camera-rig.hpp" | |||||
/** | |||||
* Rig which orbits around a focal point. | |||||
*/ | |||||
class orbit_cam: public camera_rig | |||||
{ | |||||
public: | |||||
orbit_cam(); | |||||
virtual ~orbit_cam(); | |||||
virtual void update(float dt); | |||||
/// @param direction Specifies the movement direction and speed scale on the XZ plane | |||||
void move(const float2& direction); | |||||
void rotate(float angle); | |||||
void tilt(float angle); | |||||
void zoom(float distance); | |||||
void set_focal_point(const float3& point); | |||||
void set_focal_distance(float distance); | |||||
void set_elevation(float angle); | |||||
void set_azimuth(float angle); | |||||
void set_target_focal_point(const float3& point); | |||||
void set_target_focal_distance(float distance); | |||||
void set_target_elevation(float angle); | |||||
void set_target_azimuth(float angle); | |||||
const float3& get_focal_point() const; | |||||
float get_focal_distance() const; | |||||
float get_elevation() const; | |||||
float get_azimuth() const; | |||||
const float3& get_target_focal_point() const; | |||||
float get_target_focal_distance() const; | |||||
float get_target_elevation() const; | |||||
float get_target_azimuth() const; | |||||
const float3& get_target_translation() const; | |||||
const vmq::quaternion<float>& get_target_rotation() const; | |||||
private: | |||||
float3 focal_point; | |||||
float focal_distance; | |||||
float elevation; | |||||
float azimuth; | |||||
float3 target_focal_point; | |||||
float target_focal_distance; | |||||
float target_elevation; | |||||
float target_azimuth; | |||||
vmq::quaternion<float> elevation_rotation; | |||||
vmq::quaternion<float> azimuth_rotation; | |||||
vmq::quaternion<float> target_elevation_rotation; | |||||
vmq::quaternion<float> target_azimuth_rotation; | |||||
vmq::quaternion<float> target_rotation; | |||||
float3 target_translation; | |||||
}; | |||||
inline const float3& orbit_cam::get_focal_point() const | |||||
{ | |||||
return focal_point; | |||||
} | |||||
inline float orbit_cam::get_focal_distance() const | |||||
{ | |||||
return focal_distance; | |||||
} | |||||
inline float orbit_cam::get_elevation() const | |||||
{ | |||||
return elevation; | |||||
} | |||||
inline float orbit_cam::get_azimuth() const | |||||
{ | |||||
return azimuth; | |||||
} | |||||
inline const float3& orbit_cam::get_target_focal_point() const | |||||
{ | |||||
return target_focal_point; | |||||
} | |||||
inline float orbit_cam::get_target_focal_distance() const | |||||
{ | |||||
return target_focal_distance; | |||||
} | |||||
inline float orbit_cam::get_target_elevation() const | |||||
{ | |||||
return target_elevation; | |||||
} | |||||
inline float orbit_cam::get_target_azimuth() const | |||||
{ | |||||
return target_azimuth; | |||||
} | |||||
inline const float3& orbit_cam::get_target_translation() const | |||||
{ | |||||
return target_translation; | |||||
} | |||||
inline const vmq::quaternion<float>& orbit_cam::get_target_rotation() const | |||||
{ | |||||
return target_rotation; | |||||
} | |||||
#endif // ANTKEEPER_ORBIT_CAM_HPP |
@ -0,0 +1,90 @@ | |||||
/* | |||||
* Copyright (C) 2020 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can 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. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "pheromone-matrix.hpp" | |||||
#include <vmq/vmq.hpp> | |||||
void convolve(pheromone_matrix* matrix, const float* kernel, int kernel_size) | |||||
{ | |||||
float* front = matrix->buffers[matrix->current]; | |||||
float* back = matrix->buffers[(matrix->current + 1) % 2]; | |||||
const int kernel_radius = kernel_size << 1; | |||||
// For each pheromone matrix row | |||||
for (int i = 0; i < matrix->rows; ++i) | |||||
{ | |||||
// For each pheromone in the row | |||||
for (int j = 0; j < matrix->columns; ++j) | |||||
{ | |||||
// Reset accumulator | |||||
float accumulator = 0.0f; | |||||
// For each kernel row | |||||
for (int k = -kernel_radius; k <= kernel_radius; ++k) | |||||
{ | |||||
// For each kernel element | |||||
for (int l = -kernel_radius; l <= kernel_radius; ++l) | |||||
{ | |||||
// Determine row and column of pheromone corresponding to the kernel element. | |||||
int m = i + k; | |||||
int n = j + l; | |||||
// If the row and column indices are within the matrix | |||||
if (m >= 0 && m < matrix->rows && n >= 0 && n < matrix->columns) | |||||
{ | |||||
// Multiply pheromone strength in the front buffer by the kernel value and add it to the accumulator. | |||||
accumulator += front[m * matrix->columns + n] * kernel[(k + kernel_radius) * kernel_size + l + kernel_radius]; | |||||
} | |||||
} | |||||
} | |||||
// Set pheromone strength in the back buffer equal to the accumulator value | |||||
back[i * matrix->columns + j] = accumulator; | |||||
} | |||||
} | |||||
// Swap buffers | |||||
matrix->current = (matrix->current + 1) % 2; | |||||
} | |||||
void evaporate(pheromone_matrix* matrix, float factor) | |||||
{ | |||||
const int size = matrix->columns * matrix->rows; | |||||
for (int i = 0; i < size; ++i) | |||||
{ | |||||
matrix->buffers[matrix->current][i] *= factor; | |||||
} | |||||
} | |||||
void diffuse(pheromone_matrix* matrix) | |||||
{ | |||||
const vmq::matrix<float, 3, 3> diffusion_kernel = | |||||
vmq::mul( | |||||
vmq::matrix<float, 3, 3> | |||||
{{ | |||||
{1, 2, 1}, | |||||
{2, 4, 2}, | |||||
{1, 2, 1} | |||||
}}, | |||||
1.0f / 16.0f); | |||||
convolve(matrix, &diffusion_kernel[0][0], 3); | |||||
} | |||||