@ -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 | |||
* 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, | |||
* 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/>. | |||
* 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 | |||
* 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, | |||
* 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/>. | |||
* 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); | |||
} | |||