diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..21b4487f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+# Project exclude paths
+/out/
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 00000000..73f69e09
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/.idea/artifacts/kyanite_jar.xml b/.idea/artifacts/kyanite_jar.xml
new file mode 100644
index 00000000..cd4eaca5
--- /dev/null
+++ b/.idea/artifacts/kyanite_jar.xml
@@ -0,0 +1,15 @@
+
+
+ $PROJECT_DIR$/out/artifacts/kyanite_jar
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/description.html b/.idea/description.html
new file mode 100644
index 00000000..db5f1295
--- /dev/null
+++ b/.idea/description.html
@@ -0,0 +1 @@
+Simple Java application that includes a class with main() method
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 00000000..97626ba4
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/jackson.xml b/.idea/libraries/jackson.xml
new file mode 100644
index 00000000..bf39d550
--- /dev/null
+++ b/.idea/libraries/jackson.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/jsfml.xml b/.idea/libraries/jsfml.xml
new file mode 100644
index 00000000..fd2d36c5
--- /dev/null
+++ b/.idea/libraries/jsfml.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 00000000..f07a036c
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 00000000..9c81de2c
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/project-template.xml b/.idea/project-template.xml
new file mode 100644
index 00000000..1f08b887
--- /dev/null
+++ b/.idea/project-template.xml
@@ -0,0 +1,3 @@
+
+ IJ_BASE_PACKAGE
+
\ No newline at end of file
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
new file mode 100644
index 00000000..e96534fb
--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/changelog.txt b/changelog.txt
new file mode 100644
index 00000000..a1d3a2cd
--- /dev/null
+++ b/changelog.txt
@@ -0,0 +1,36 @@
+October 28th, 2021
+[1.5.3]
+- Added a method for extracting an InputStream from assets located in the source root directory
+- Failed attempt to load a native Asset now raises a critical error and exits the program instread of causing it to stop responding
+
+October 26th, 2021
+[1.5.2]
+- Added icon asset type
+- Added native window icon management
+- Assets can now be constructed with an InputStream
+- Fixed binding from a JSON object to the Dictionary class object during DataAsset conversion
+
+October 25th, 2021
+[1.5.1]
+- Fixed the Dictionary class visibility
+
+October 24th, 2021
+[1.5]
+- Added a JSON data asset type
+- Added an animated entity interface
+- Added a method for testing and calculating intersection with another GlobalBounds
+- Added a method for calculating the direction vector between two points
+- Added a method for calculating the moving circle vs fixed rectangle collision direction vector
+- Added native support for window background texture
+- The getDeltaTime method has been moved to the Scene class
+- Enabling vertical synchronization is now done by calling the framerate limit setter with Window.Framerate.VSYNC argument
+- The GlobalBounds class is no longer a record class, which means that its fields are called without parentheses
+
+October 21st, 2021
+[1.4.1]
+- Added support for changing the sound pitch and volume
+- GlobalBounds objects can now be tested for containing a certain point
+
+October 20th, 2021
+[1.4]
+- First public release
\ No newline at end of file
diff --git a/doc/allclasses-index.html b/doc/allclasses-index.html
new file mode 100644
index 00000000..77542473
--- /dev/null
+++ b/doc/allclasses-index.html
@@ -0,0 +1,159 @@
+
+
+
Provides a set of references to the basic objects used by the game. The instance of this class can be accessed via the
+ getInstance() method. Only one GameContext instance can exist in a single game instance.
An external asset. This tagging interface groups assets allowing them to be stored
+ in an AssetsBundle. Kyanite provides several basic types of assets, but the
+ programmer should feel free to implement this interface in their own asset types.
Provides a handy assets storage. Assets are registered and retrieved with String identifiers. An identifier can be
+ any text, however it is good to keep the identifiers organized, compliant with a consistent convention. For example,
+ kyanite:texture.flowers.purple makes up a good identifier, however txt_flower_13 does not.
public class FontFace
+extends Object
+implements Asset
+
A wrapper class for JSFML Font objects, representing a font face asset. The source must be the path
+ to an font file. Supported formats are: TrueType, Type 1, CFF, OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42.
public class Sound
+extends Object
+implements Asset
+
A wrapper class for JSFML Sound objects, representing a sound asset.
+ The source must be the path to an audio file. Supported formats are: WAV, OGG/Vorbis and FLAC.
public class Texture
+extends Object
+implements Asset
+
A wrapper class for JSFML Texture objects, representing a texture asset.
+ The source must be the path to an image file. Supported formats are: BMP, DDS, JPEG, PNG, TGA and PSD.
public class CompoundEntity
+extends Object
+implements org.jsfml.graphics.Transformable, org.jsfml.graphics.Drawable
+
An entity consisting of many components. A CompoundEntity can be drawn to a render target,
+ as well as positioned in the scene, rotated and scaled around an origin. This class can be used,
+ for instance, to create complex structures out of primitive shapes or to compose spannable texts.
Returns a string representation of this record class. The representation contains the name of the class, followed by the name and value of each of the record components.
Indicates whether some other object is "equal to" this one. The objects are equal if the other object is of the same class and if all the record components are equal. All components in this record class are compared with '=='.
Values for the alignment mode. The first word of the name indicates vertical alignment and the second
+ word indicates horizontal alignment. The CENTER value indicates centering on both axes.
Returns the enum constant of this class with the specified name.
+The string must match exactly an identifier used to declare an
+enum constant in this class. (Extraneous whitespace characters are
+not permitted.)
+
+
Parameters:
+
name - the name of the enum constant to be returned.
Indicates that the annotated String is an asset identifier. The programmer can use
+ this annotation to enhance code readability. It does not have any uses other than that.
public final class FirstThreadTool
+extends Object
+
If the application is running on macOS, it must be started with the -XstartOnFirstThread JVM option.
+ Otherwise, the application thread will not be allowed to create a window. This is an SWT limitation.
Returns the smaller of two numeric values. If the arguments have the same value, the result is that same value.
+ If either value is NaN, then the result is also NaN. If exactly one of the arguments is null, the result
+ is the other argument, whereas if both values are null, then the result is also null.
Returns the bigger of two numeric values. If the arguments have the same value, the result is that same value.
+ If either value is NaN, then the result is also NaN. If exactly one of the arguments is null, the result
+ is the other argument, whereas if both values are null, then the result is also null.
Returns a string representation of this record class. The representation contains the name of the class, followed by the name and value of each of the record components.
Indicates whether some other object is "equal to" this one. The objects are equal if the other object is of the same class and if all the record components are equal. All components in this record class are compared with Objects::equals(Object,Object).
public class Window
+extends org.jsfml.graphics.RenderWindow
+
Provides a window that can serve as a target for 2D drawing. The window is already
+ initialized with an empty scene to which Drawable objects can be added.
+
+
+
+
+
+
+
Field Summary
+
+
Fields inherited from interface org.jsfml.window.WindowStyle
Returns a string representation of this record class. The representation contains the name of the class, followed by the name and value of each of the record components.
Indicates whether some other object is "equal to" this one. The objects are equal if the other object is of the same class and if all the record components are equal. All components in this record class are compared with Objects::equals(Object,Object).
+Starting from the Overview page, you can browse the documentation using the links in each page, and in the navigation bar at the top of each page. The Index and Search box allow you to navigate to specific declarations and summary pages, including: All Packages, All Classes and Interfaces
+
+
Search
+
You can search for definitions of modules, packages, types, fields, methods, system properties and other terms defined in the API, using some or all of the name, optionally using "camelCase" abbreviations. For example:
+
+
j.l.obj will match "java.lang.Object"
+
InpStr will match "java.io.InputStream"
+
HM.cK will match "java.util.HashMap.containsKey(Object)"
+The following sections describe the different kinds of pages in this collection.
+
+
Overview
+
The Overview page is the front page of this API document and provides a list of all packages with a summary for each. This page can also contain an overall description of the set of packages.
+
+
+
Package
+
Each package has a page that contains a list of its classes and interfaces, with a summary for each. These pages may contain the following categories:
+
+
Interfaces
+
Classes
+
Enum Classes
+
Exceptions
+
Errors
+
Annotation Interfaces
+
+
+
+
Class or Interface
+
Each class, interface, nested class and nested interface has its own separate page. Each of these pages has three sections consisting of a declaration and description, member summary tables, and detailed member descriptions. Entries in each of these sections are omitted if they are empty or not applicable.
+
+
Class Inheritance Diagram
+
Direct Subclasses
+
All Known Subinterfaces
+
All Known Implementing Classes
+
Class or Interface Declaration
+
Class or Interface Description
+
+
+
+
Nested Class Summary
+
Enum Constant Summary
+
Field Summary
+
Property Summary
+
Constructor Summary
+
Method Summary
+
Required Element Summary
+
Optional Element Summary
+
+
+
+
Enum Constant Details
+
Field Details
+
Property Details
+
Constructor Details
+
Method Details
+
Element Details
+
+
Note: Annotation interfaces have required and optional elements, but not methods. Only enum classes have enum constants. The components of a record class are displayed as part of the declaration of the record class. Properties are a feature of JavaFX.
+
The summary entries are alphabetical, while the detailed descriptions are in the order they appear in the source code. This preserves the logical groupings established by the programmer.
+
+
+
Other Files
+
Packages and modules may contain pages with additional information related to the declarations nearby.
+
+
+
Tree (Class Hierarchy)
+
There is a Class Hierarchy page for all packages, plus a hierarchy for each package. Each hierarchy page contains a list of classes and a list of interfaces. Classes are organized by inheritance structure starting with java.lang.Object. Interfaces do not inherit from java.lang.Object.
+
+
When viewing the Overview page, clicking on TREE displays the hierarchy for all packages.
+
When viewing a particular package, class or interface page, clicking on TREE displays the hierarchy for only that package.
+
+
+
+
Deprecated API
+
The Deprecated API page lists all of the API that have been deprecated. A deprecated API is not recommended for use, generally due to shortcomings, and a replacement API is usually given. Deprecated APIs may be removed in future implementations.
+
+
+
Serialized Form
+
Each serializable or externalizable class has a description of its serialization fields and methods. This information is of interest to those who implement rather than use the API. While there is no link in the navigation bar, you can get to this information by going to any serialized class and clicking "Serialized Form" in the "See Also" section of the class description.
+
+
+
All Packages
+
The All Packages page contains an alphabetic index of all packages contained in the documentation.
+
+
+
All Classes and Interfaces
+
The All Classes and Interfaces page contains an alphabetic index of all classes and interfaces contained in the documentation, including annotation interfaces, enum classes, and record classes.
+
+
+
Index
+
The Index contains an alphabetic index of all classes, interfaces, constructors, methods, and fields in the documentation, as well as summary pages such as All Packages, All Classes and Interfaces.
+
+
+
+This help file applies to API documentation generated by the standard doclet.
+
Contains classes representing window events and event listeners.
+
+
+
+
+
+
+
+
diff --git a/doc/jquery-ui.overrides.css b/doc/jquery-ui.overrides.css
new file mode 100644
index 00000000..f89acb63
--- /dev/null
+++ b/doc/jquery-ui.overrides.css
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+.ui-state-active,
+.ui-widget-content .ui-state-active,
+.ui-widget-header .ui-state-active,
+a.ui-button:active,
+.ui-button:active,
+.ui-button.ui-state-active:hover {
+ /* Overrides the color of selection used in jQuery UI */
+ background: #F8981D;
+}
diff --git a/doc/legal/ADDITIONAL_LICENSE_INFO b/doc/legal/ADDITIONAL_LICENSE_INFO
new file mode 100644
index 00000000..ff700cd0
--- /dev/null
+++ b/doc/legal/ADDITIONAL_LICENSE_INFO
@@ -0,0 +1,37 @@
+ ADDITIONAL INFORMATION ABOUT LICENSING
+
+Certain files distributed by Oracle America, Inc. and/or its affiliates are
+subject to the following clarification and special exception to the GPLv2,
+based on the GNU Project exception for its Classpath libraries, known as the
+GNU Classpath Exception.
+
+Note that Oracle includes multiple, independent programs in this software
+package. Some of those programs are provided under licenses deemed
+incompatible with the GPLv2 by the Free Software Foundation and others.
+For example, the package includes programs licensed under the Apache
+License, Version 2.0 and may include FreeType. Such programs are licensed
+to you under their original licenses.
+
+Oracle facilitates your further distribution of this package by adding the
+Classpath Exception to the necessary parts of its GPLv2 code, which permits
+you to use that code in combination with other independent modules not
+licensed under the GPLv2. However, note that this would not permit you to
+commingle code under an incompatible license with Oracle's GPLv2 licensed
+code by, for example, cutting and pasting such code into a file also
+containing Oracle's GPLv2 licensed code and then distributing the result.
+
+Additionally, if you were to remove the Classpath Exception from any of the
+files to which it applies and distribute the result, you would likely be
+required to license some or all of the other code in that distribution under
+the GPLv2 as well, and since the GPLv2 is incompatible with the license terms
+of some items included in the distribution by Oracle, removing the Classpath
+Exception could therefore effectively compromise your ability to further
+distribute the package.
+
+Failing to distribute notices associated with some files may also create
+unexpected legal consequences.
+
+Proceed with caution and we recommend that you obtain the advice of a lawyer
+skilled in open source matters before removing the Classpath Exception or
+making modifications to this package which may subsequently be redistributed
+and/or involve the use of third party software.
diff --git a/doc/legal/ASSEMBLY_EXCEPTION b/doc/legal/ASSEMBLY_EXCEPTION
new file mode 100644
index 00000000..065b8d90
--- /dev/null
+++ b/doc/legal/ASSEMBLY_EXCEPTION
@@ -0,0 +1,27 @@
+
+OPENJDK ASSEMBLY EXCEPTION
+
+The OpenJDK source code made available by Oracle America, Inc. (Oracle) at
+openjdk.java.net ("OpenJDK Code") is distributed under the terms of the GNU
+General Public License version 2
+only ("GPL2"), with the following clarification and special exception.
+
+ Linking this OpenJDK Code statically or dynamically with other code
+ is making a combined work based on this library. Thus, the terms
+ and conditions of GPL2 cover the whole combination.
+
+ As a special exception, Oracle gives you permission to link this
+ OpenJDK Code with certain code licensed by Oracle as indicated at
+ http://openjdk.java.net/legal/exception-modules-2007-05-08.html
+ ("Designated Exception Modules") to produce an executable,
+ regardless of the license terms of the Designated Exception Modules,
+ and to copy and distribute the resulting executable under GPL2,
+ provided that the Designated Exception Modules continue to be
+ governed by the licenses under which they were offered by Oracle.
+
+As such, it allows licensees and sublicensees of Oracle's GPL2 OpenJDK Code
+to build an executable that includes those portions of necessary code that
+Oracle could not provide under GPL2 (or that Oracle has provided under GPL2
+with the Classpath exception). If you modify or add to the OpenJDK code,
+that new GPL2 code may still be combined with Designated Exception Modules
+if the new code is made subject to this exception by its copyright holder.
diff --git a/doc/legal/LICENSE b/doc/legal/LICENSE
new file mode 100644
index 00000000..8b400c7a
--- /dev/null
+++ b/doc/legal/LICENSE
@@ -0,0 +1,347 @@
+The GNU General Public License (GPL)
+
+Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Everyone is permitted to copy and distribute verbatim copies of this license
+document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to share
+and change it. By contrast, the GNU General Public License is intended to
+guarantee your freedom to share and change free software--to make sure the
+software is free for all its users. This General Public License applies to
+most of the Free Software Foundation's software and to any other program whose
+authors commit to using it. (Some other Free Software Foundation software is
+covered by the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our
+General Public Licenses are designed to make sure that you have the freedom to
+distribute copies of free software (and charge for this service if you wish),
+that you receive source code or can get it if you want it, that you can change
+the software or use pieces of it in new free programs; and that you know you
+can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to deny
+you these rights or to ask you to surrender the rights. These restrictions
+translate to certain responsibilities for you if you distribute copies of the
+software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or for
+a fee, you must give the recipients all the rights that you have. You must
+make sure that they, too, receive or can get the source code. And you must
+show them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and (2)
+offer you this license which gives you legal permission to copy, distribute
+and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain that
+everyone understands that there is no warranty for this free software. If the
+software is modified by someone else and passed on, we want its recipients to
+know that what they have is not the original, so that any problems introduced
+by others will not reflect on the original authors' reputations.
+
+Finally, any free program is threatened constantly by software patents. We
+wish to avoid the danger that redistributors of a free program will
+individually obtain patent licenses, in effect making the program proprietary.
+To prevent this, we have made it clear that any patent must be licensed for
+everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and modification
+follow.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a notice
+placed by the copyright holder saying it may be distributed under the terms of
+this General Public License. The "Program", below, refers to any such program
+or work, and a "work based on the Program" means either the Program or any
+derivative work under copyright law: that is to say, a work containing the
+Program or a portion of it, either verbatim or with modifications and/or
+translated into another language. (Hereinafter, translation is included
+without limitation in the term "modification".) Each licensee is addressed as
+"you".
+
+Activities other than copying, distribution and modification are not covered by
+this License; they are outside its scope. The act of running the Program is
+not restricted, and the output from the Program is covered only if its contents
+constitute a work based on the Program (independent of having been made by
+running the Program). Whether that is true depends on what the Program does.
+
+1. You may copy and distribute verbatim copies of the Program's source code as
+you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this License
+and to the absence of any warranty; and give any other recipients of the
+Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and you may
+at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Program or any portion of it, thus
+forming a work based on the Program, and copy and distribute such modifications
+or work under the terms of Section 1 above, provided that you also meet all of
+these conditions:
+
+ a) You must cause the modified files to carry prominent notices stating
+ that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in whole or
+ in part contains or is derived from the Program or any part thereof, to be
+ licensed as a whole at no charge to all third parties under the terms of
+ this License.
+
+ c) If the modified program normally reads commands interactively when run,
+ you must cause it, when started running for such interactive use in the
+ most ordinary way, to print or display an announcement including an
+ appropriate copyright notice and a notice that there is no warranty (or
+ else, saying that you provide a warranty) and that users may redistribute
+ the program under these conditions, and telling the user how to view a copy
+ of this License. (Exception: if the Program itself is interactive but does
+ not normally print such an announcement, your work based on the Program is
+ not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If identifiable
+sections of that work are not derived from the Program, and can be reasonably
+considered independent and separate works in themselves, then this License, and
+its terms, do not apply to those sections when you distribute them as separate
+works. But when you distribute the same sections as part of a whole which is a
+work based on the Program, the distribution of the whole must be on the terms
+of this License, whose permissions for other licensees extend to the entire
+whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your
+rights to work written entirely by you; rather, the intent is to exercise the
+right to control the distribution of derivative or collective works based on
+the Program.
+
+In addition, mere aggregation of another work not based on the Program with the
+Program (or with a work based on the Program) on a volume of a storage or
+distribution medium does not bring the other work under the scope of this
+License.
+
+3. You may copy and distribute the Program (or a work based on it, under
+Section 2) in object code or executable form under the terms of Sections 1 and
+2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable source
+ code, which must be distributed under the terms of Sections 1 and 2 above
+ on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three years, to
+ give any third party, for a charge no more than your cost of physically
+ performing source distribution, a complete machine-readable copy of the
+ corresponding source code, to be distributed under the terms of Sections 1
+ and 2 above on a medium customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer to
+ distribute corresponding source code. (This alternative is allowed only
+ for noncommercial distribution and only if you received the program in
+ object code or executable form with such an offer, in accord with
+ Subsection b above.)
+
+The source code for a work means the preferred form of the work for making
+modifications to it. For an executable work, complete source code means all
+the source code for all modules it contains, plus any associated interface
+definition files, plus the scripts used to control compilation and installation
+of the executable. However, as a special exception, the source code
+distributed need not include anything that is normally distributed (in either
+source or binary form) with the major components (compiler, kernel, and so on)
+of the operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the source
+code from the same place counts as distribution of the source code, even though
+third parties are not compelled to copy the source along with the object code.
+
+4. You may not copy, modify, sublicense, or distribute the Program except as
+expressly provided under this License. Any attempt otherwise to copy, modify,
+sublicense or distribute the Program is void, and will automatically terminate
+your rights under this License. However, parties who have received copies, or
+rights, from you under this License will not have their licenses terminated so
+long as such parties remain in full compliance.
+
+5. You are not required to accept this License, since you have not signed it.
+However, nothing else grants you permission to modify or distribute the Program
+or its derivative works. These actions are prohibited by law if you do not
+accept this License. Therefore, by modifying or distributing the Program (or
+any work based on the Program), you indicate your acceptance of this License to
+do so, and all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+6. Each time you redistribute the Program (or any work based on the Program),
+the recipient automatically receives a license from the original licensor to
+copy, distribute or modify the Program subject to these terms and conditions.
+You may not impose any further restrictions on the recipients' exercise of the
+rights granted herein. You are not responsible for enforcing compliance by
+third parties to this License.
+
+7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues), conditions
+are imposed on you (whether by court order, agreement or otherwise) that
+contradict the conditions of this License, they do not excuse you from the
+conditions of this License. If you cannot distribute so as to satisfy
+simultaneously your obligations under this License and any other pertinent
+obligations, then as a consequence you may not distribute the Program at all.
+For example, if a patent license would not permit royalty-free redistribution
+of the Program by all those who receive copies directly or indirectly through
+you, then the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply and
+the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or
+other property right claims or to contest validity of any such claims; this
+section has the sole purpose of protecting the integrity of the free software
+distribution system, which is implemented by public license practices. Many
+people have made generous contributions to the wide range of software
+distributed through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing to
+distribute software through any other system and a licensee cannot impose that
+choice.
+
+This section is intended to make thoroughly clear what is believed to be a
+consequence of the rest of this License.
+
+8. If the distribution and/or use of the Program is restricted in certain
+countries either by patents or by copyrighted interfaces, the original
+copyright holder who places the Program under this License may add an explicit
+geographical distribution limitation excluding those countries, so that
+distribution is permitted only in or among countries not thus excluded. In
+such case, this License incorporates the limitation as if written in the body
+of this License.
+
+9. The Free Software Foundation may publish revised and/or new versions of the
+General Public License from time to time. Such new versions will be similar in
+spirit to the present version, but may differ in detail to address new problems
+or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any later
+version", you have the option of following the terms and conditions either of
+that version or of any later version published by the Free Software Foundation.
+If the Program does not specify a version number of this License, you may
+choose any version ever published by the Free Software Foundation.
+
+10. If you wish to incorporate parts of the Program into other free programs
+whose distribution conditions are different, write to the author to ask for
+permission. For software which is copyrighted by the Free Software Foundation,
+write to the Free Software Foundation; we sometimes make exceptions for this.
+Our decision will be guided by the two goals of preserving the free status of
+all derivatives of our free software and of promoting the sharing and reuse of
+software generally.
+
+NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
+THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
+STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE
+PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
+PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE,
+YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL
+ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE
+PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
+INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
+BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER
+OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest possible
+use to the public, the best way to achieve this is to make it free software
+which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest to attach
+them to the start of each source file to most effectively convey the exclusion
+of warranty; and each file should have at least the "copyright" line and a
+pointer to where the full notice is found.
+
+ One line to give the program's name and a brief idea of what it does.
+
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this when it
+starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author Gnomovision comes
+ with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free
+ software, and you are welcome to redistribute it under certain conditions;
+ type 'show c' for details.
+
+The hypothetical commands 'show w' and 'show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may be
+called something other than 'show w' and 'show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your school,
+if any, to sign a "copyright disclaimer" for the program, if necessary. Here
+is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ 'Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ signature of Ty Coon, 1 April 1989
+
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General Public
+License instead of this License.
+
+
+"CLASSPATH" EXCEPTION TO THE GPL
+
+Certain source files distributed by Oracle America and/or its affiliates are
+subject to the following clarification and special exception to the GPL, but
+only where Oracle has expressly included in the particular source file's header
+the words "Oracle designates this particular file as subject to the "Classpath"
+exception as provided by Oracle in the LICENSE file that accompanied this code."
+
+ Linking this library statically or dynamically with other modules is making
+ a combined work based on this library. Thus, the terms and conditions of
+ the GNU General Public License cover the whole combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent modules,
+ and to copy and distribute the resulting executable under terms of your
+ choice, provided that you also meet, for each linked independent module,
+ the terms and conditions of the license of that module. An independent
+ module is a module which is not derived from or based on this library. If
+ you modify this library, you may extend this exception to your version of
+ the library, but you are not obligated to do so. If you do not wish to do
+ so, delete this exception statement from your version.
diff --git a/doc/legal/jquery.md b/doc/legal/jquery.md
new file mode 100644
index 00000000..8054a34c
--- /dev/null
+++ b/doc/legal/jquery.md
@@ -0,0 +1,72 @@
+## jQuery v3.5.1
+
+### jQuery License
+```
+jQuery v 3.5.1
+Copyright JS Foundation and other contributors, https://js.foundation/
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************
+
+The jQuery JavaScript Library v3.5.1 also includes Sizzle.js
+
+Sizzle.js includes the following license:
+
+Copyright JS Foundation and other contributors, https://js.foundation/
+
+This software consists of voluntary contributions made by many
+individuals. For exact contribution history, see the revision history
+available at https://github.com/jquery/sizzle
+
+The following license applies to all parts of this software except as
+documented below:
+
+====
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+====
+
+All files located in the node_modules and external directories are
+externally maintained libraries used by this software which have their
+own licenses; we recommend you read them, as their terms may differ from
+the terms above.
+
+*********************
+
+```
diff --git a/doc/legal/jqueryUI.md b/doc/legal/jqueryUI.md
new file mode 100644
index 00000000..8031bdb5
--- /dev/null
+++ b/doc/legal/jqueryUI.md
@@ -0,0 +1,49 @@
+## jQuery UI v1.12.1
+
+### jQuery UI License
+```
+Copyright jQuery Foundation and other contributors, https://jquery.org/
+
+This software consists of voluntary contributions made by many
+individuals. For exact contribution history, see the revision history
+available at https://github.com/jquery/jquery-ui
+
+The following license applies to all parts of this software except as
+documented below:
+
+====
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+====
+
+Copyright and related rights for sample code are waived via CC0. Sample
+code is defined as all source code contained within the demos directory.
+
+CC0: http://creativecommons.org/publicdomain/zero/1.0/
+
+====
+
+All files located in the node_modules and external directories are
+externally maintained libraries used by this software which have their
+own licenses; we recommend you read them, as their terms may differ from
+the terms above.
+
+```
diff --git a/doc/member-search-index.js b/doc/member-search-index.js
new file mode 100644
index 00000000..072cb31e
--- /dev/null
+++ b/doc/member-search-index.js
@@ -0,0 +1 @@
+memberSearchIndex = [{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"add(Object, Vector2f)","u":"add(java.lang.Object,org.jsfml.system.Vector2f)"},{"p":"com.rubynaxela.kyanite.game.assets","c":"Texture","l":"apply(Shape)","u":"apply(org.jsfml.graphics.Shape)"},{"p":"com.rubynaxela.kyanite.game.assets","c":"Texture","l":"apply(Sprite)","u":"apply(org.jsfml.graphics.Sprite)"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Font","l":"apply(Text)","u":"apply(org.jsfml.graphics.Text)"},{"p":"com.rubynaxela.kyanite.game.assets","c":"FontFace","l":"apply(Text)","u":"apply(org.jsfml.graphics.Text)"},{"p":"com.rubynaxela.kyanite.game.assets","c":"AssetsBundle","l":"AssetsBundle()","u":"%3Cinit%3E()"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Text.Alignment","l":"BOTTOM_CENTER"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Text.Alignment","l":"BOTTOM_LEFT"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Text.Alignment","l":"BOTTOM_RIGHT"},{"p":"com.rubynaxela.kyanite.game.entities","c":"HitBox","l":"bottom()"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Text.Alignment","l":"CENTER"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Text.Alignment","l":"CENTER_LEFT"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Text.Alignment","l":"CENTER_RIGHT"},{"p":"com.rubynaxela.kyanite.system","c":"Clock","l":"Clock()","u":"%3Cinit%3E()"},{"p":"com.rubynaxela.kyanite.system","c":"Clock","l":"Clock(boolean)","u":"%3Cinit%3E(boolean)"},{"p":"com.rubynaxela.kyanite.window.event","c":"CloseListener","l":"closed()"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"CompoundEntity()","u":"%3Cinit%3E()"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"CompoundEntity(Vector2f)","u":"%3Cinit%3E(org.jsfml.system.Vector2f)"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"draw(RenderTarget, RenderStates)","u":"draw(org.jsfml.graphics.RenderTarget,org.jsfml.graphics.RenderStates)"},{"p":"com.rubynaxela.kyanite.game.entities","c":"HitBox","l":"equals(Object)","u":"equals(java.lang.Object)"},{"p":"com.rubynaxela.kyanite.util","c":"Pair","l":"equals(Object)","u":"equals(java.lang.Object)"},{"p":"com.rubynaxela.kyanite.window.event","c":"ResizeEvent","l":"equals(Object)","u":"equals(java.lang.Object)"},{"p":"com.rubynaxela.kyanite.window.event","c":"FocusListener","l":"focusGained()"},{"p":"com.rubynaxela.kyanite.window.event","c":"FocusListener","l":"focusLost()"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Font","l":"Font(FontFace, int)","u":"%3Cinit%3E(com.rubynaxela.kyanite.game.assets.FontFace,int)"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Font","l":"Font(FontFace, int, int)","u":"%3Cinit%3E(com.rubynaxela.kyanite.game.assets.FontFace,int,int)"},{"p":"com.rubynaxela.kyanite.game.assets","c":"FontFace","l":"FontFace(File)","u":"%3Cinit%3E(java.io.File)"},{"p":"com.rubynaxela.kyanite.game.assets","c":"FontFace","l":"FontFace(Path)","u":"%3Cinit%3E(java.nio.file.Path)"},{"p":"com.rubynaxela.kyanite.game.assets","c":"FontFace","l":"FontFace(String)","u":"%3Cinit%3E(java.lang.String)"},{"p":"com.rubynaxela.kyanite.game.entities","c":"HitBox","l":"from(FloatRect)","u":"from(org.jsfml.graphics.FloatRect)"},{"p":"com.rubynaxela.kyanite.game.assets","c":"AssetsBundle","l":"get(String)","u":"get(java.lang.String)"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Text","l":"getAlignment()"},{"p":"com.rubynaxela.kyanite.game","c":"GameContext","l":"getAssetsBundle()"},{"p":"com.rubynaxela.kyanite.game","c":"GameContext","l":"getClock()"},{"p":"com.rubynaxela.kyanite.system","c":"Clock","l":"getDeltaTime()"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Font","l":"getFontFace()"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"getGlobalBounds()"},{"p":"com.rubynaxela.kyanite.game","c":"GameContext","l":"getInstance()"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"getInverseTransform()"},{"p":"org.jsfml.graphics","c":"Text","l":"getInverseTransform()"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"getOrigin()"},{"p":"org.jsfml.graphics","c":"Text","l":"getOrigin()"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"getPosition()"},{"p":"org.jsfml.graphics","c":"Text","l":"getPosition()"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"getRotation()"},{"p":"org.jsfml.graphics","c":"Text","l":"getRotation()"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"getScale()"},{"p":"org.jsfml.graphics","c":"Text","l":"getScale()"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"getScene()"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Font","l":"getSize()"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Font","l":"getStyle()"},{"p":"com.rubynaxela.kyanite.system","c":"Clock","l":"getTime()"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"getTransform()"},{"p":"org.jsfml.graphics","c":"Text","l":"getTransform()"},{"p":"com.rubynaxela.kyanite.game","c":"GameContext","l":"getWindow()"},{"p":"com.rubynaxela.kyanite.game.entities","c":"HitBox","l":"hashCode()"},{"p":"com.rubynaxela.kyanite.util","c":"Pair","l":"hashCode()"},{"p":"com.rubynaxela.kyanite.window.event","c":"ResizeEvent","l":"hashCode()"},{"p":"com.rubynaxela.kyanite.game.entities","c":"HitBox","l":"HitBox(float, float, float, float)","u":"%3Cinit%3E(float,float,float,float)"},{"p":"com.rubynaxela.kyanite.window","c":"Scene","l":"isInitialized()"},{"p":"com.rubynaxela.kyanite.game.assets","c":"Texture","l":"isSmooth()"},{"p":"com.rubynaxela.kyanite.game.assets","c":"Texture","l":"isTileable()"},{"p":"com.rubynaxela.kyanite.window.event","c":"JoystickButtonListener","l":"joystickButtonPressed(JoystickButtonEvent)","u":"joystickButtonPressed(org.jsfml.window.event.JoystickButtonEvent)"},{"p":"com.rubynaxela.kyanite.window.event","c":"JoystickButtonListener","l":"joystickButtonReleased(JoystickButtonEvent)","u":"joystickButtonReleased(org.jsfml.window.event.JoystickButtonEvent)"},{"p":"com.rubynaxela.kyanite.window.event","c":"JoystickConnectionListener","l":"joystickConnected(JoystickEvent)","u":"joystickConnected(org.jsfml.window.event.JoystickEvent)"},{"p":"com.rubynaxela.kyanite.window.event","c":"JoystickConnectionListener","l":"joystickDisconnected(JoystickEvent)","u":"joystickDisconnected(org.jsfml.window.event.JoystickEvent)"},{"p":"com.rubynaxela.kyanite.window.event","c":"JoystickListener","l":"joystickMoved(JoystickMoveEvent)","u":"joystickMoved(org.jsfml.window.event.JoystickMoveEvent)"},{"p":"com.rubynaxela.kyanite.window.event","c":"KeyListener","l":"keyPressed(KeyEvent)","u":"keyPressed(org.jsfml.window.event.KeyEvent)"},{"p":"com.rubynaxela.kyanite.window.event","c":"KeyListener","l":"keyReleased(KeyEvent)","u":"keyReleased(org.jsfml.window.event.KeyEvent)"},{"p":"com.rubynaxela.kyanite.game.entities","c":"HitBox","l":"left()"},{"p":"com.rubynaxela.kyanite.util","c":"MathUtils","l":"max(T, T)","u":"max(T,T)"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"maximize()"},{"p":"com.rubynaxela.kyanite.util","c":"MathUtils","l":"min(T, T)","u":"min(T,T)"},{"p":"com.rubynaxela.kyanite.window.event","c":"MouseButtonListener","l":"mouseButtonPressed(MouseButtonEvent)","u":"mouseButtonPressed(org.jsfml.window.event.MouseButtonEvent)"},{"p":"com.rubynaxela.kyanite.window.event","c":"MouseButtonListener","l":"mouseButtonReleased(MouseButtonEvent)","u":"mouseButtonReleased(org.jsfml.window.event.MouseButtonEvent)"},{"p":"com.rubynaxela.kyanite.window.event","c":"MouseListener","l":"mouseEntered(MouseEvent)","u":"mouseEntered(org.jsfml.window.event.MouseEvent)"},{"p":"com.rubynaxela.kyanite.window.event","c":"MouseListener","l":"mouseLeft(MouseEvent)","u":"mouseLeft(org.jsfml.window.event.MouseEvent)"},{"p":"com.rubynaxela.kyanite.window.event","c":"MouseListener","l":"mouseMoved(MouseEvent)","u":"mouseMoved(org.jsfml.window.event.MouseEvent)"},{"p":"com.rubynaxela.kyanite.window.event","c":"MouseWheelListener","l":"mouseWheelMoved(MouseWheelEvent)","u":"mouseWheelMoved(org.jsfml.window.event.MouseWheelEvent)"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"move(float, float)","u":"move(float,float)"},{"p":"org.jsfml.graphics","c":"Text","l":"move(float, float)","u":"move(float,float)"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"move(Vector2f)","u":"move(org.jsfml.system.Vector2f)"},{"p":"org.jsfml.graphics","c":"Text","l":"move(Vector2f)","u":"move(org.jsfml.system.Vector2f)"},{"p":"com.rubynaxela.kyanite.window.event","c":"ResizeEvent","l":"newSize()"},{"p":"com.rubynaxela.kyanite.util","c":"Pair","l":"Pair(T1, T2)","u":"%3Cinit%3E(T1,T2)"},{"p":"com.rubynaxela.kyanite.game.assets","c":"Sound","l":"pause()"},{"p":"com.rubynaxela.kyanite.game.assets","c":"Sound","l":"play()"},{"p":"com.rubynaxela.kyanite.game.assets","c":"AssetsBundle","l":"register(String, T)","u":"register(java.lang.String,T)"},{"p":"com.rubynaxela.kyanite.window.event","c":"ResizeListener","l":"resized(ResizeEvent)","u":"resized(com.rubynaxela.kyanite.window.event.ResizeEvent)"},{"p":"com.rubynaxela.kyanite.window.event","c":"ResizeEvent","l":"ResizeEvent(Vector2i)","u":"%3Cinit%3E(org.jsfml.system.Vector2i)"},{"p":"com.rubynaxela.kyanite.system","c":"Clock","l":"restart()"},{"p":"com.rubynaxela.kyanite.system","c":"FirstThreadTool","l":"restartIfNecessary(String[])","u":"restartIfNecessary(java.lang.String[])"},{"p":"com.rubynaxela.kyanite.game.entities","c":"HitBox","l":"right()"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"rotate(float)"},{"p":"org.jsfml.graphics","c":"Text","l":"rotate(float)"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"scale(float, float)","u":"scale(float,float)"},{"p":"org.jsfml.graphics","c":"Text","l":"scale(float, float)","u":"scale(float,float)"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"scale(Vector2f)","u":"scale(org.jsfml.system.Vector2f)"},{"p":"org.jsfml.graphics","c":"Text","l":"scale(Vector2f)","u":"scale(org.jsfml.system.Vector2f)"},{"p":"com.rubynaxela.kyanite.window","c":"Scene","l":"Scene()","u":"%3Cinit%3E()"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Text","l":"setAlignment(Text.Alignment)","u":"setAlignment(com.rubynaxela.kyanite.game.gui.Text.Alignment)"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"setBackgroundColor(Color)","u":"setBackgroundColor(org.jsfml.graphics.Color)"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"setCloseListener(CloseListener)","u":"setCloseListener(com.rubynaxela.kyanite.window.event.CloseListener)"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"setFocusListener(FocusListener)","u":"setFocusListener(com.rubynaxela.kyanite.window.event.FocusListener)"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Text","l":"setFont(Font)","u":"setFont(com.rubynaxela.kyanite.game.gui.Font)"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"setJoystickButtonListener(JoystickButtonListener)","u":"setJoystickButtonListener(com.rubynaxela.kyanite.window.event.JoystickButtonListener)"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"setJoystickConnectionListener(JoystickConnectionListener)","u":"setJoystickConnectionListener(com.rubynaxela.kyanite.window.event.JoystickConnectionListener)"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"setJoystickListener(JoystickListener)","u":"setJoystickListener(com.rubynaxela.kyanite.window.event.JoystickListener)"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"setKeyListener(KeyListener)","u":"setKeyListener(com.rubynaxela.kyanite.window.event.KeyListener)"},{"p":"com.rubynaxela.kyanite.window","c":"Scene","l":"setLoop(Runnable)","u":"setLoop(java.lang.Runnable)"},{"p":"com.rubynaxela.kyanite.game.assets","c":"Sound","l":"setLooping(boolean)"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"setMouseButtonListener(MouseButtonListener)","u":"setMouseButtonListener(com.rubynaxela.kyanite.window.event.MouseButtonListener)"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"setMouseListener(MouseListener)","u":"setMouseListener(com.rubynaxela.kyanite.window.event.MouseListener)"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"setMouseWheelListener(MouseWheelListener)","u":"setMouseWheelListener(com.rubynaxela.kyanite.window.event.MouseWheelListener)"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"setOrigin(float, float)","u":"setOrigin(float,float)"},{"p":"org.jsfml.graphics","c":"Text","l":"setOrigin(float, float)","u":"setOrigin(float,float)"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"setOrigin(Vector2f)","u":"setOrigin(org.jsfml.system.Vector2f)"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"setPosition(float, float)","u":"setPosition(float,float)"},{"p":"org.jsfml.graphics","c":"Text","l":"setPosition(float, float)","u":"setPosition(float,float)"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"setPosition(Vector2f)","u":"setPosition(org.jsfml.system.Vector2f)"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"setResizeListener(ResizeListener)","u":"setResizeListener(com.rubynaxela.kyanite.window.event.ResizeListener)"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"setRotation(float)"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"setScale(float, float)","u":"setScale(float,float)"},{"p":"org.jsfml.graphics","c":"Text","l":"setScale(float, float)","u":"setScale(float,float)"},{"p":"com.rubynaxela.kyanite.game.entities","c":"CompoundEntity","l":"setScale(Vector2f)","u":"setScale(org.jsfml.system.Vector2f)"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"setScene(Scene)","u":"setScene(com.rubynaxela.kyanite.window.Scene)"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"setSize(int, int)","u":"setSize(int,int)"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"setSize(Vector2i)","u":"setSize(org.jsfml.system.Vector2i)"},{"p":"com.rubynaxela.kyanite.game.assets","c":"Sound","l":"setSkip(Time)","u":"setSkip(org.jsfml.system.Time)"},{"p":"com.rubynaxela.kyanite.game.assets","c":"Texture","l":"setSmooth(boolean)"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Text","l":"setString(String)","u":"setString(java.lang.String)"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Text","l":"setText(String)","u":"setText(java.lang.String)"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"setTextListener(TextListener)","u":"setTextListener(com.rubynaxela.kyanite.window.event.TextListener)"},{"p":"com.rubynaxela.kyanite.game.assets","c":"Texture","l":"setTileable(boolean)"},{"p":"com.rubynaxela.kyanite.game.assets","c":"Sound","l":"Sound(File)","u":"%3Cinit%3E(java.io.File)"},{"p":"com.rubynaxela.kyanite.game.assets","c":"Sound","l":"Sound(Path)","u":"%3Cinit%3E(java.nio.file.Path)"},{"p":"com.rubynaxela.kyanite.game.assets","c":"Sound","l":"Sound(String)","u":"%3Cinit%3E(java.lang.String)"},{"p":"com.rubynaxela.kyanite.system","c":"Clock","l":"start()"},{"p":"com.rubynaxela.kyanite.game","c":"GameContext","l":"startGame()"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"startLoop(GameContext)","u":"startLoop(com.rubynaxela.kyanite.game.GameContext)"},{"p":"com.rubynaxela.kyanite.game.assets","c":"Sound","l":"stop()"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Text","l":"Text()","u":"%3Cinit%3E()"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Text","l":"Text(Font)","u":"%3Cinit%3E(com.rubynaxela.kyanite.game.gui.Font)"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Text","l":"Text(String)","u":"%3Cinit%3E(java.lang.String)"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Text","l":"Text(String, Font)","u":"%3Cinit%3E(java.lang.String,com.rubynaxela.kyanite.game.gui.Font)"},{"p":"com.rubynaxela.kyanite.window.event","c":"TextListener","l":"textEntered(TextEvent)","u":"textEntered(org.jsfml.window.event.TextEvent)"},{"p":"com.rubynaxela.kyanite.game.assets","c":"Texture","l":"Texture(File)","u":"%3Cinit%3E(java.io.File)"},{"p":"com.rubynaxela.kyanite.game.assets","c":"Texture","l":"Texture(Path)","u":"%3Cinit%3E(java.nio.file.Path)"},{"p":"com.rubynaxela.kyanite.game.assets","c":"Texture","l":"Texture(String)","u":"%3Cinit%3E(java.lang.String)"},{"p":"com.rubynaxela.kyanite.game.entities","c":"HitBox","l":"toFloatRect()"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Text.Alignment","l":"TOP_CENTER"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Text.Alignment","l":"TOP_LEFT"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Text.Alignment","l":"TOP_RIGHT"},{"p":"com.rubynaxela.kyanite.game.entities","c":"HitBox","l":"top()"},{"p":"com.rubynaxela.kyanite.game.entities","c":"HitBox","l":"toString()"},{"p":"com.rubynaxela.kyanite.util","c":"Pair","l":"toString()"},{"p":"com.rubynaxela.kyanite.window.event","c":"ResizeEvent","l":"toString()"},{"p":"com.rubynaxela.kyanite.util","c":"Pair","l":"value1()"},{"p":"com.rubynaxela.kyanite.util","c":"Pair","l":"value2()"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Text.Alignment","l":"valueOf(String)","u":"valueOf(java.lang.String)"},{"p":"com.rubynaxela.kyanite.game.gui","c":"Text.Alignment","l":"values()"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"Window()","u":"%3Cinit%3E()"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"Window(VideoMode, String)","u":"%3Cinit%3E(org.jsfml.window.VideoMode,java.lang.String)"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"Window(VideoMode, String, int)","u":"%3Cinit%3E(org.jsfml.window.VideoMode,java.lang.String,int)"},{"p":"com.rubynaxela.kyanite.window","c":"Window","l":"Window(VideoMode, String, int, ContextSettings)","u":"%3Cinit%3E(org.jsfml.window.VideoMode,java.lang.String,int,org.jsfml.window.ContextSettings)"}];updateSearchResults();
\ No newline at end of file
diff --git a/doc/module-search-index.js b/doc/module-search-index.js
new file mode 100644
index 00000000..0d59754f
--- /dev/null
+++ b/doc/module-search-index.js
@@ -0,0 +1 @@
+moduleSearchIndex = [];updateSearchResults();
\ No newline at end of file
diff --git a/doc/overview-summary.html b/doc/overview-summary.html
new file mode 100644
index 00000000..4a19f460
--- /dev/null
+++ b/doc/overview-summary.html
@@ -0,0 +1,26 @@
+
+
+
+
+Generated Documentation (Untitled)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
").text(i.label)).appendTo(e)},_move:function(t,e){return this.menu.element.is(":visible")?this.menu.isFirstItem()&&/^previous/.test(t)||this.menu.isLastItem()&&/^next/.test(t)?(this.isMultiLine||this._value(this.term),this.menu.blur(),void 0):(this.menu[t](e),void 0):(this.search(null,e),void 0)},widget:function(){return this.menu.element},_value:function(){return this.valueMethod.apply(this.element,arguments)},_keyEvent:function(t,e){(!this.isMultiLine||this.menu.element.is(":visible"))&&(this._move(t,e),e.preventDefault())},_isContentEditable:function(t){if(!t.length)return!1;var e=t.prop("contentEditable");return"inherit"===e?this._isContentEditable(t.parent()):"true"===e}}),t.extend(t.ui.autocomplete,{escapeRegex:function(t){return t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")},filter:function(e,i){var s=RegExp(t.ui.autocomplete.escapeRegex(i),"i");return t.grep(e,function(t){return s.test(t.label||t.value||t)})}}),t.widget("ui.autocomplete",t.ui.autocomplete,{options:{messages:{noResults:"No search results.",results:function(t){return t+(t>1?" results are":" result is")+" available, use up and down arrow keys to navigate."}}},__response:function(e){var i;this._superApply(arguments),this.options.disabled||this.cancelSearch||(i=e&&e.length?this.options.messages.results(e.length):this.options.messages.noResults,this.liveRegion.children().hide(),t("
").text(i).appendTo(this.liveRegion))}}),t.ui.autocomplete});
\ No newline at end of file
diff --git a/doc/script-dir/jquery-ui.structure.min.css b/doc/script-dir/jquery-ui.structure.min.css
new file mode 100644
index 00000000..e8808927
--- /dev/null
+++ b/doc/script-dir/jquery-ui.structure.min.css
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.12.1 - 2018-12-06
+* http://jqueryui.com
+* Copyright jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important;pointer-events:none}.ui-icon{display:inline-block;vertical-align:middle;margin-top:-.25em;position:relative;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-icon-block{left:50%;margin-left:-8px;display:block}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{margin:0;cursor:pointer;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-item-wrapper{position:relative;padding:3px 1em 3px .4em}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item-wrapper{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}
\ No newline at end of file
diff --git a/doc/script.js b/doc/script.js
new file mode 100644
index 00000000..864989cf
--- /dev/null
+++ b/doc/script.js
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+var moduleSearchIndex;
+var packageSearchIndex;
+var typeSearchIndex;
+var memberSearchIndex;
+var tagSearchIndex;
+function loadScripts(doc, tag) {
+ createElem(doc, tag, 'search.js');
+
+ createElem(doc, tag, 'module-search-index.js');
+ createElem(doc, tag, 'package-search-index.js');
+ createElem(doc, tag, 'type-search-index.js');
+ createElem(doc, tag, 'member-search-index.js');
+ createElem(doc, tag, 'tag-search-index.js');
+}
+
+function createElem(doc, tag, path) {
+ var script = doc.createElement(tag);
+ var scriptElement = doc.getElementsByTagName(tag)[0];
+ script.src = pathtoroot + path;
+ scriptElement.parentNode.insertBefore(script, scriptElement);
+}
+
+function show(tableId, selected, columns) {
+ if (tableId !== selected) {
+ document.querySelectorAll('div.' + tableId + ':not(.' + selected + ')')
+ .forEach(function(elem) {
+ elem.style.display = 'none';
+ });
+ }
+ document.querySelectorAll('div.' + selected)
+ .forEach(function(elem, index) {
+ elem.style.display = '';
+ var isEvenRow = index % (columns * 2) < columns;
+ elem.classList.remove(isEvenRow ? oddRowColor : evenRowColor);
+ elem.classList.add(isEvenRow ? evenRowColor : oddRowColor);
+ });
+ updateTabs(tableId, selected);
+}
+
+function updateTabs(tableId, selected) {
+ document.querySelector('div#' + tableId +' .summary-table')
+ .setAttribute('aria-labelledby', selected);
+ document.querySelectorAll('button[id^="' + tableId + '"]')
+ .forEach(function(tab, index) {
+ if (selected === tab.id || (tableId === selected && index === 0)) {
+ tab.className = activeTableTab;
+ tab.setAttribute('aria-selected', true);
+ tab.setAttribute('tabindex',0);
+ } else {
+ tab.className = tableTab;
+ tab.setAttribute('aria-selected', false);
+ tab.setAttribute('tabindex',-1);
+ }
+ });
+}
+
+function switchTab(e) {
+ var selected = document.querySelector('[aria-selected=true]');
+ if (selected) {
+ if ((e.keyCode === 37 || e.keyCode === 38) && selected.previousSibling) {
+ // left or up arrow key pressed: move focus to previous tab
+ selected.previousSibling.click();
+ selected.previousSibling.focus();
+ e.preventDefault();
+ } else if ((e.keyCode === 39 || e.keyCode === 40) && selected.nextSibling) {
+ // right or down arrow key pressed: move focus to next tab
+ selected.nextSibling.click();
+ selected.nextSibling.focus();
+ e.preventDefault();
+ }
+ }
+}
+
+var updateSearchResults = function() {};
+
+function indexFilesLoaded() {
+ return moduleSearchIndex
+ && packageSearchIndex
+ && typeSearchIndex
+ && memberSearchIndex
+ && tagSearchIndex;
+}
+
+// Workaround for scroll position not being included in browser history (8249133)
+document.addEventListener("DOMContentLoaded", function(e) {
+ var contentDiv = document.querySelector("div.flex-content");
+ window.addEventListener("popstate", function(e) {
+ if (e.state !== null) {
+ contentDiv.scrollTop = e.state;
+ }
+ });
+ window.addEventListener("hashchange", function(e) {
+ history.replaceState(contentDiv.scrollTop, document.title);
+ });
+ contentDiv.addEventListener("scroll", function(e) {
+ var timeoutID;
+ if (!timeoutID) {
+ timeoutID = setTimeout(function() {
+ history.replaceState(contentDiv.scrollTop, document.title);
+ timeoutID = null;
+ }, 100);
+ }
+ });
+ if (!location.hash) {
+ history.replaceState(contentDiv.scrollTop, document.title);
+ }
+});
diff --git a/doc/search.js b/doc/search.js
new file mode 100644
index 00000000..db3b2f4a
--- /dev/null
+++ b/doc/search.js
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+var noResult = {l: "No results found"};
+var loading = {l: "Loading search index..."};
+var catModules = "Modules";
+var catPackages = "Packages";
+var catTypes = "Classes and Interfaces";
+var catMembers = "Members";
+var catSearchTags = "Search Tags";
+var highlight = "$&";
+var searchPattern = "";
+var fallbackPattern = "";
+var RANKING_THRESHOLD = 2;
+var NO_MATCH = 0xffff;
+var MIN_RESULTS = 3;
+var MAX_RESULTS = 500;
+var UNNAMED = "";
+function escapeHtml(str) {
+ return str.replace(//g, ">");
+}
+function getHighlightedText(item, matcher, fallbackMatcher) {
+ var escapedItem = escapeHtml(item);
+ var highlighted = escapedItem.replace(matcher, highlight);
+ if (highlighted === escapedItem) {
+ highlighted = escapedItem.replace(fallbackMatcher, highlight)
+ }
+ return highlighted;
+}
+function getURLPrefix(ui) {
+ var urlPrefix="";
+ var slash = "/";
+ if (ui.item.category === catModules) {
+ return ui.item.l + slash;
+ } else if (ui.item.category === catPackages && ui.item.m) {
+ return ui.item.m + slash;
+ } else if (ui.item.category === catTypes || ui.item.category === catMembers) {
+ if (ui.item.m) {
+ urlPrefix = ui.item.m + slash;
+ } else {
+ $.each(packageSearchIndex, function(index, item) {
+ if (item.m && ui.item.p === item.l) {
+ urlPrefix = item.m + slash;
+ }
+ });
+ }
+ }
+ return urlPrefix;
+}
+function createSearchPattern(term) {
+ var pattern = "";
+ var isWordToken = false;
+ term.replace(/,\s*/g, ", ").trim().split(/\s+/).forEach(function(w, index) {
+ if (index > 0) {
+ // whitespace between identifiers is significant
+ pattern += (isWordToken && /^\w/.test(w)) ? "\\s+" : "\\s*";
+ }
+ var tokens = w.split(/(?=[A-Z,.()<>[\/])/);
+ for (var i = 0; i < tokens.length; i++) {
+ var s = tokens[i];
+ if (s === "") {
+ continue;
+ }
+ pattern += $.ui.autocomplete.escapeRegex(s);
+ isWordToken = /\w$/.test(s);
+ if (isWordToken) {
+ pattern += "([a-z0-9_$<>\\[\\]]*?)";
+ }
+ }
+ });
+ return pattern;
+}
+function createMatcher(pattern, flags) {
+ var isCamelCase = /[A-Z]/.test(pattern);
+ return new RegExp(pattern, flags + (isCamelCase ? "" : "i"));
+}
+var watermark = 'Search';
+$(function() {
+ var search = $("#search-input");
+ var reset = $("#reset-button");
+ search.val('');
+ search.prop("disabled", false);
+ reset.prop("disabled", false);
+ search.val(watermark).addClass('watermark');
+ search.blur(function() {
+ if ($(this).val().length === 0) {
+ $(this).val(watermark).addClass('watermark');
+ }
+ });
+ search.on('click keydown paste', function() {
+ if ($(this).val() === watermark) {
+ $(this).val('').removeClass('watermark');
+ }
+ });
+ reset.click(function() {
+ search.val('').focus();
+ });
+ search.focus()[0].setSelectionRange(0, 0);
+});
+$.widget("custom.catcomplete", $.ui.autocomplete, {
+ _create: function() {
+ this._super();
+ this.widget().menu("option", "items", "> :not(.ui-autocomplete-category)");
+ },
+ _renderMenu: function(ul, items) {
+ var rMenu = this;
+ var currentCategory = "";
+ rMenu.menu.bindings = $();
+ $.each(items, function(index, item) {
+ var li;
+ if (item.category && item.category !== currentCategory) {
+ ul.append("
+
+
diff --git a/doc/stylesheet.css b/doc/stylesheet.css
new file mode 100644
index 00000000..836c62da
--- /dev/null
+++ b/doc/stylesheet.css
@@ -0,0 +1,865 @@
+/*
+ * Javadoc style sheet
+ */
+
+@import url('resources/fonts/dejavu.css');
+
+/*
+ * Styles for individual HTML elements.
+ *
+ * These are styles that are specific to individual HTML elements. Changing them affects the style of a particular
+ * HTML element throughout the page.
+ */
+
+body {
+ background-color:#ffffff;
+ color:#353833;
+ font-family:'DejaVu Sans', Arial, Helvetica, sans-serif;
+ font-size:14px;
+ margin:0;
+ padding:0;
+ height:100%;
+ width:100%;
+}
+iframe {
+ margin:0;
+ padding:0;
+ height:100%;
+ width:100%;
+ overflow-y:scroll;
+ border:none;
+}
+a:link, a:visited {
+ text-decoration:none;
+ color:#4A6782;
+}
+a[href]:hover, a[href]:focus {
+ text-decoration:none;
+ color:#bb7a2a;
+}
+a[name] {
+ color:#353833;
+}
+pre {
+ font-family:'DejaVu Sans Mono', monospace;
+ font-size:14px;
+}
+h1 {
+ font-size:20px;
+}
+h2 {
+ font-size:18px;
+}
+h3 {
+ font-size:16px;
+}
+h4 {
+ font-size:15px;
+}
+h5 {
+ font-size:14px;
+}
+h6 {
+ font-size:13px;
+}
+ul {
+ list-style-type:disc;
+}
+code, tt {
+ font-family:'DejaVu Sans Mono', monospace;
+}
+:not(h1, h2, h3, h4, h5, h6) > code,
+:not(h1, h2, h3, h4, h5, h6) > tt {
+ font-size:14px;
+ padding-top:4px;
+ margin-top:8px;
+ line-height:1.4em;
+}
+dt code {
+ font-family:'DejaVu Sans Mono', monospace;
+ font-size:14px;
+ padding-top:4px;
+}
+.summary-table dt code {
+ font-family:'DejaVu Sans Mono', monospace;
+ font-size:14px;
+ vertical-align:top;
+ padding-top:4px;
+}
+sup {
+ font-size:8px;
+}
+button {
+ font-family: 'DejaVu Sans', Arial, Helvetica, sans-serif;
+ font-size: 14px;
+}
+/*
+ * Styles for HTML generated by javadoc.
+ *
+ * These are style classes that are used by the standard doclet to generate HTML documentation.
+ */
+
+/*
+ * Styles for document title and copyright.
+ */
+.clear {
+ clear:both;
+ height:0;
+ overflow:hidden;
+}
+.about-language {
+ float:right;
+ padding:0 21px 8px 8px;
+ font-size:11px;
+ margin-top:-9px;
+ height:2.9em;
+}
+.legal-copy {
+ margin-left:.5em;
+}
+.tab {
+ background-color:#0066FF;
+ color:#ffffff;
+ padding:8px;
+ width:5em;
+ font-weight:bold;
+}
+/*
+ * Styles for navigation bar.
+ */
+@media screen {
+ .flex-box {
+ position:fixed;
+ display:flex;
+ flex-direction:column;
+ height: 100%;
+ width: 100%;
+ }
+ .flex-header {
+ flex: 0 0 auto;
+ }
+ .flex-content {
+ flex: 1 1 auto;
+ overflow-y: auto;
+ }
+}
+.top-nav {
+ background-color:#4D7A97;
+ color:#FFFFFF;
+ float:left;
+ padding:0;
+ width:100%;
+ clear:right;
+ min-height:2.8em;
+ padding-top:10px;
+ overflow:hidden;
+ font-size:12px;
+}
+.sub-nav {
+ background-color:#dee3e9;
+ float:left;
+ width:100%;
+ overflow:hidden;
+ font-size:12px;
+}
+.sub-nav div {
+ clear:left;
+ float:left;
+ padding:0 0 5px 6px;
+ text-transform:uppercase;
+}
+.sub-nav .nav-list {
+ padding-top:5px;
+}
+ul.nav-list {
+ display:block;
+ margin:0 25px 0 0;
+ padding:0;
+}
+ul.sub-nav-list {
+ float:left;
+ margin:0 25px 0 0;
+ padding:0;
+}
+ul.nav-list li {
+ list-style:none;
+ float:left;
+ padding: 5px 6px;
+ text-transform:uppercase;
+}
+.sub-nav .nav-list-search {
+ float:right;
+ margin:0 0 0 0;
+ padding:5px 6px;
+ clear:none;
+}
+.nav-list-search label {
+ position:relative;
+ right:-16px;
+}
+ul.sub-nav-list li {
+ list-style:none;
+ float:left;
+ padding-top:10px;
+}
+.top-nav a:link, .top-nav a:active, .top-nav a:visited {
+ color:#FFFFFF;
+ text-decoration:none;
+ text-transform:uppercase;
+}
+.top-nav a:hover {
+ text-decoration:none;
+ color:#bb7a2a;
+ text-transform:uppercase;
+}
+.nav-bar-cell1-rev {
+ background-color:#F8981D;
+ color:#253441;
+ margin: auto 5px;
+}
+.skip-nav {
+ position:absolute;
+ top:auto;
+ left:-9999px;
+ overflow:hidden;
+}
+/*
+ * Hide navigation links and search box in print layout
+ */
+@media print {
+ ul.nav-list, div.sub-nav {
+ display:none;
+ }
+}
+/*
+ * Styles for page header and footer.
+ */
+.title {
+ color:#2c4557;
+ margin:10px 0;
+}
+.sub-title {
+ margin:5px 0 0 0;
+}
+.header ul {
+ margin:0 0 15px 0;
+ padding:0;
+}
+.header ul li, .footer ul li {
+ list-style:none;
+ font-size:13px;
+}
+/*
+ * Styles for headings.
+ */
+body.class-declaration-page .summary h2,
+body.class-declaration-page .details h2,
+body.class-use-page h2,
+body.module-declaration-page .block-list h2 {
+ font-style: italic;
+ padding:0;
+ margin:15px 0;
+}
+body.class-declaration-page .summary h3,
+body.class-declaration-page .details h3,
+body.class-declaration-page .summary .inherited-list h2 {
+ background-color:#dee3e9;
+ border:1px solid #d0d9e0;
+ margin:0 0 6px -8px;
+ padding:7px 5px;
+}
+/*
+ * Styles for page layout containers.
+ */
+main {
+ clear:both;
+ padding:10px 20px;
+ position:relative;
+}
+dl.notes > dt {
+ font-family: 'DejaVu Sans', Arial, Helvetica, sans-serif;
+ font-size:12px;
+ font-weight:bold;
+ margin:10px 0 0 0;
+ color:#4E4E4E;
+}
+dl.notes > dd {
+ margin:5px 10px 10px 0;
+ font-size:14px;
+ font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif;
+}
+dl.name-value > dt {
+ margin-left:1px;
+ font-size:1.1em;
+ display:inline;
+ font-weight:bold;
+}
+dl.name-value > dd {
+ margin:0 0 0 1px;
+ font-size:1.1em;
+ display:inline;
+}
+/*
+ * Styles for lists.
+ */
+li.circle {
+ list-style:circle;
+}
+ul.horizontal li {
+ display:inline;
+ font-size:0.9em;
+}
+div.inheritance {
+ margin:0;
+ padding:0;
+}
+div.inheritance div.inheritance {
+ margin-left:2em;
+}
+ul.block-list,
+ul.details-list,
+ul.member-list,
+ul.summary-list {
+ margin:10px 0 10px 0;
+ padding:0;
+}
+ul.block-list > li,
+ul.details-list > li,
+ul.member-list > li,
+ul.summary-list > li {
+ list-style:none;
+ margin-bottom:15px;
+ line-height:1.4;
+}
+.summary-table dl, .summary-table dl dt, .summary-table dl dd {
+ margin-top:0;
+ margin-bottom:1px;
+}
+ul.see-list, ul.see-list-long {
+ padding-left: 0;
+ list-style: none;
+}
+ul.see-list li {
+ display: inline;
+}
+ul.see-list li:not(:last-child):after,
+ul.see-list-long li:not(:last-child):after {
+ content: ", ";
+ white-space: pre-wrap;
+}
+/*
+ * Styles for tables.
+ */
+.summary-table, .details-table {
+ width:100%;
+ border-spacing:0;
+ border-left:1px solid #EEE;
+ border-right:1px solid #EEE;
+ border-bottom:1px solid #EEE;
+ padding:0;
+}
+.caption {
+ position:relative;
+ text-align:left;
+ background-repeat:no-repeat;
+ color:#253441;
+ font-weight:bold;
+ clear:none;
+ overflow:hidden;
+ padding:0;
+ padding-top:10px;
+ padding-left:1px;
+ margin:0;
+ white-space:pre;
+}
+.caption a:link, .caption a:visited {
+ color:#1f389c;
+}
+.caption a:hover,
+.caption a:active {
+ color:#FFFFFF;
+}
+.caption span {
+ white-space:nowrap;
+ padding-top:5px;
+ padding-left:12px;
+ padding-right:12px;
+ padding-bottom:7px;
+ display:inline-block;
+ float:left;
+ background-color:#F8981D;
+ border: none;
+ height:16px;
+}
+div.table-tabs {
+ padding:10px 0 0 1px;
+ margin:0;
+}
+div.table-tabs > button {
+ border: none;
+ cursor: pointer;
+ padding: 5px 12px 7px 12px;
+ font-weight: bold;
+ margin-right: 3px;
+}
+div.table-tabs > button.active-table-tab {
+ background: #F8981D;
+ color: #253441;
+}
+div.table-tabs > button.table-tab {
+ background: #4D7A97;
+ color: #FFFFFF;
+}
+.two-column-summary {
+ display: grid;
+ grid-template-columns: minmax(15%, max-content) minmax(15%, auto);
+}
+.three-column-summary {
+ display: grid;
+ grid-template-columns: minmax(10%, max-content) minmax(15%, max-content) minmax(15%, auto);
+}
+.four-column-summary {
+ display: grid;
+ grid-template-columns: minmax(10%, max-content) minmax(10%, max-content) minmax(10%, max-content) minmax(10%, auto);
+}
+@media screen and (max-width: 600px) {
+ .two-column-summary {
+ display: grid;
+ grid-template-columns: 1fr;
+ }
+}
+@media screen and (max-width: 800px) {
+ .three-column-summary {
+ display: grid;
+ grid-template-columns: minmax(10%, max-content) minmax(25%, auto);
+ }
+ .three-column-summary .col-last {
+ grid-column-end: span 2;
+ }
+}
+@media screen and (max-width: 1000px) {
+ .four-column-summary {
+ display: grid;
+ grid-template-columns: minmax(15%, max-content) minmax(15%, auto);
+ }
+}
+.summary-table > div, .details-table > div {
+ text-align:left;
+ padding: 8px 3px 3px 7px;
+}
+.col-first, .col-second, .col-last, .col-constructor-name, .col-summary-item-name {
+ vertical-align:top;
+ padding-right:0;
+ padding-top:8px;
+ padding-bottom:3px;
+}
+.table-header {
+ background:#dee3e9;
+ font-weight: bold;
+}
+.col-first, .col-first {
+ font-size:13px;
+}
+.col-second, .col-second, .col-last, .col-constructor-name, .col-summary-item-name, .col-last {
+ font-size:13px;
+}
+.col-first, .col-second, .col-constructor-name {
+ vertical-align:top;
+ overflow: auto;
+}
+.col-last {
+ white-space:normal;
+}
+.col-first a:link, .col-first a:visited,
+.col-second a:link, .col-second a:visited,
+.col-first a:link, .col-first a:visited,
+.col-second a:link, .col-second a:visited,
+.col-constructor-name a:link, .col-constructor-name a:visited,
+.col-summary-item-name a:link, .col-summary-item-name a:visited,
+.constant-values-container a:link, .constant-values-container a:visited,
+.all-classes-container a:link, .all-classes-container a:visited,
+.all-packages-container a:link, .all-packages-container a:visited {
+ font-weight:bold;
+}
+.table-sub-heading-color {
+ background-color:#EEEEFF;
+}
+.even-row-color, .even-row-color .table-header {
+ background-color:#FFFFFF;
+}
+.odd-row-color, .odd-row-color .table-header {
+ background-color:#EEEEEF;
+}
+/*
+ * Styles for contents.
+ */
+.deprecated-content {
+ margin:0;
+ padding:10px 0;
+}
+div.block {
+ font-size:14px;
+ font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif;
+}
+.col-last div {
+ padding-top:0;
+}
+.col-last a {
+ padding-bottom:3px;
+}
+.module-signature,
+.package-signature,
+.type-signature,
+.member-signature {
+ font-family:'DejaVu Sans Mono', monospace;
+ font-size:14px;
+ margin:14px 0;
+ white-space: pre-wrap;
+}
+.module-signature,
+.package-signature,
+.type-signature {
+ margin-top: 0;
+}
+.member-signature .type-parameters-long,
+.member-signature .parameters,
+.member-signature .exceptions {
+ display: inline-block;
+ vertical-align: top;
+ white-space: pre;
+}
+.member-signature .type-parameters {
+ white-space: normal;
+}
+/*
+ * Styles for formatting effect.
+ */
+.source-line-no {
+ color:green;
+ padding:0 30px 0 0;
+}
+h1.hidden {
+ visibility:hidden;
+ overflow:hidden;
+ font-size:10px;
+}
+.block {
+ display:block;
+ margin:0 10px 5px 0;
+ color:#474747;
+}
+.deprecated-label, .descfrm-type-label, .implementation-label, .member-name-label, .member-name-link,
+.module-label-in-package, .module-label-in-type, .override-specify-label, .package-label-in-type,
+.package-hierarchy-label, .type-name-label, .type-name-link, .search-tag-link, .preview-label {
+ font-weight:bold;
+}
+.deprecation-comment, .help-footnote, .preview-comment {
+ font-style:italic;
+}
+.deprecation-block {
+ font-size:14px;
+ font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif;
+ border-style:solid;
+ border-width:thin;
+ border-radius:10px;
+ padding:10px;
+ margin-bottom:10px;
+ margin-right:10px;
+ display:inline-block;
+}
+.preview-block {
+ font-size:14px;
+ font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif;
+ border-style:solid;
+ border-width:thin;
+ border-radius:10px;
+ padding:10px;
+ margin-bottom:10px;
+ margin-right:10px;
+ display:inline-block;
+}
+div.block div.deprecation-comment {
+ font-style:normal;
+}
+/*
+ * Styles specific to HTML5 elements.
+ */
+main, nav, header, footer, section {
+ display:block;
+}
+/*
+ * Styles for javadoc search.
+ */
+.ui-autocomplete-category {
+ font-weight:bold;
+ font-size:15px;
+ padding:7px 0 7px 3px;
+ background-color:#4D7A97;
+ color:#FFFFFF;
+}
+.result-item {
+ font-size:13px;
+}
+.ui-autocomplete {
+ max-height:85%;
+ max-width:65%;
+ overflow-y:scroll;
+ overflow-x:scroll;
+ white-space:nowrap;
+ box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
+}
+ul.ui-autocomplete {
+ position:fixed;
+ z-index:999999;
+}
+ul.ui-autocomplete li {
+ float:left;
+ clear:both;
+ width:100%;
+}
+.result-highlight {
+ font-weight:bold;
+}
+#search-input {
+ background-image:url('resources/glass.png');
+ background-size:13px;
+ background-repeat:no-repeat;
+ background-position:2px 3px;
+ padding-left:20px;
+ position:relative;
+ right:-18px;
+ width:400px;
+}
+#reset-button {
+ background-color: rgb(255,255,255);
+ background-image:url('resources/x.png');
+ background-position:center;
+ background-repeat:no-repeat;
+ background-size:12px;
+ border:0 none;
+ width:16px;
+ height:16px;
+ position:relative;
+ left:-4px;
+ top:-4px;
+ font-size:0px;
+}
+.watermark {
+ color:#545454;
+}
+.search-tag-desc-result {
+ font-style:italic;
+ font-size:11px;
+}
+.search-tag-holder-result {
+ font-style:italic;
+ font-size:12px;
+}
+.search-tag-result:target {
+ background-color:yellow;
+}
+.module-graph span {
+ display:none;
+ position:absolute;
+}
+.module-graph:hover span {
+ display:block;
+ margin: -100px 0 0 100px;
+ z-index: 1;
+}
+.inherited-list {
+ margin: 10px 0 10px 0;
+}
+section.class-description {
+ line-height: 1.4;
+}
+.summary section[class$="-summary"], .details section[class$="-details"],
+.class-uses .detail, .serialized-class-details {
+ padding: 0px 20px 5px 10px;
+ border: 1px solid #ededed;
+ background-color: #f8f8f8;
+}
+.inherited-list, section[class$="-details"] .detail {
+ padding:0 0 5px 8px;
+ background-color:#ffffff;
+ border:none;
+}
+.vertical-separator {
+ padding: 0 5px;
+}
+ul.help-section-list {
+ margin: 0;
+}
+ul.help-subtoc > li {
+ display: inline-block;
+ padding-right: 5px;
+ font-size: smaller;
+}
+ul.help-subtoc > li::before {
+ content: "\2022" ;
+ padding-right:2px;
+}
+span.help-note {
+ font-style: italic;
+}
+/*
+ * Indicator icon for external links.
+ */
+main a[href*="://"]::after {
+ content:"";
+ display:inline-block;
+ background-image:url('data:image/svg+xml; utf8, \
+ ');
+ background-size:100% 100%;
+ width:7px;
+ height:7px;
+ margin-left:2px;
+ margin-bottom:4px;
+}
+main a[href*="://"]:hover::after,
+main a[href*="://"]:focus::after {
+ background-image:url('data:image/svg+xml; utf8, \
+ ');
+}
+
+/*
+ * Styles for user-provided tables.
+ *
+ * borderless:
+ * No borders, vertical margins, styled caption.
+ * This style is provided for use with existing doc comments.
+ * In general, borderless tables should not be used for layout purposes.
+ *
+ * plain:
+ * Plain borders around table and cells, vertical margins, styled caption.
+ * Best for small tables or for complex tables for tables with cells that span
+ * rows and columns, when the "striped" style does not work well.
+ *
+ * striped:
+ * Borders around the table and vertical borders between cells, striped rows,
+ * vertical margins, styled caption.
+ * Best for tables that have a header row, and a body containing a series of simple rows.
+ */
+
+table.borderless,
+table.plain,
+table.striped {
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+table.borderless > caption,
+table.plain > caption,
+table.striped > caption {
+ font-weight: bold;
+ font-size: smaller;
+}
+table.borderless th, table.borderless td,
+table.plain th, table.plain td,
+table.striped th, table.striped td {
+ padding: 2px 5px;
+}
+table.borderless,
+table.borderless > thead > tr > th, table.borderless > tbody > tr > th, table.borderless > tr > th,
+table.borderless > thead > tr > td, table.borderless > tbody > tr > td, table.borderless > tr > td {
+ border: none;
+}
+table.borderless > thead > tr, table.borderless > tbody > tr, table.borderless > tr {
+ background-color: transparent;
+}
+table.plain {
+ border-collapse: collapse;
+ border: 1px solid black;
+}
+table.plain > thead > tr, table.plain > tbody tr, table.plain > tr {
+ background-color: transparent;
+}
+table.plain > thead > tr > th, table.plain > tbody > tr > th, table.plain > tr > th,
+table.plain > thead > tr > td, table.plain > tbody > tr > td, table.plain > tr > td {
+ border: 1px solid black;
+}
+table.striped {
+ border-collapse: collapse;
+ border: 1px solid black;
+}
+table.striped > thead {
+ background-color: #E3E3E3;
+}
+table.striped > thead > tr > th, table.striped > thead > tr > td {
+ border: 1px solid black;
+}
+table.striped > tbody > tr:nth-child(even) {
+ background-color: #EEE
+}
+table.striped > tbody > tr:nth-child(odd) {
+ background-color: #FFF
+}
+table.striped > tbody > tr > th, table.striped > tbody > tr > td {
+ border-left: 1px solid black;
+ border-right: 1px solid black;
+}
+table.striped > tbody > tr > th {
+ font-weight: normal;
+}
+/**
+ * Tweak font sizes and paddings for small screens.
+ */
+@media screen and (max-width: 1050px) {
+ #search-input {
+ width: 300px;
+ }
+}
+@media screen and (max-width: 800px) {
+ #search-input {
+ width: 200px;
+ }
+ .top-nav,
+ .bottom-nav {
+ font-size: 11px;
+ padding-top: 6px;
+ }
+ .sub-nav {
+ font-size: 11px;
+ }
+ .about-language {
+ padding-right: 16px;
+ }
+ ul.nav-list li,
+ .sub-nav .nav-list-search {
+ padding: 6px;
+ }
+ ul.sub-nav-list li {
+ padding-top: 5px;
+ }
+ main {
+ padding: 10px;
+ }
+ .summary section[class$="-summary"], .details section[class$="-details"],
+ .class-uses .detail, .serialized-class-details {
+ padding: 0 8px 5px 8px;
+ }
+ body {
+ -webkit-text-size-adjust: none;
+ }
+}
+@media screen and (max-width: 500px) {
+ #search-input {
+ width: 150px;
+ }
+ .top-nav,
+ .bottom-nav {
+ font-size: 10px;
+ }
+ .sub-nav {
+ font-size: 10px;
+ }
+ .about-language {
+ font-size: 10px;
+ padding-right: 12px;
+ }
+}
diff --git a/doc/tag-search-index.js b/doc/tag-search-index.js
new file mode 100644
index 00000000..f38b3cb3
--- /dev/null
+++ b/doc/tag-search-index.js
@@ -0,0 +1 @@
+tagSearchIndex = [{"l":"Serialized Form","h":"","u":"serialized-form.html"}];updateSearchResults();
\ No newline at end of file
diff --git a/doc/type-search-index.js b/doc/type-search-index.js
new file mode 100644
index 00000000..2ebf78b1
--- /dev/null
+++ b/doc/type-search-index.js
@@ -0,0 +1 @@
+typeSearchIndex = [{"p":"com.rubynaxela.kyanite.game.gui","l":"Text.Alignment"},{"l":"All Classes and Interfaces","u":"allclasses-index.html"},{"p":"com.rubynaxela.kyanite.game.assets","l":"Asset"},{"p":"com.rubynaxela.kyanite.system","l":"AssetId"},{"p":"com.rubynaxela.kyanite.game.assets","l":"AssetsBundle"},{"p":"com.rubynaxela.kyanite.system","l":"Clock"},{"p":"com.rubynaxela.kyanite.window.event","l":"CloseListener"},{"p":"com.rubynaxela.kyanite.game.entities","l":"CompoundEntity"},{"p":"com.rubynaxela.kyanite.system","l":"FirstThreadTool"},{"p":"com.rubynaxela.kyanite.window.event","l":"FocusListener"},{"p":"com.rubynaxela.kyanite.game.gui","l":"Font"},{"p":"com.rubynaxela.kyanite.game.assets","l":"FontFace"},{"p":"com.rubynaxela.kyanite.game","l":"GameContext"},{"p":"com.rubynaxela.kyanite.game.entities","l":"HitBox"},{"p":"com.rubynaxela.kyanite.window.event","l":"JoystickButtonListener"},{"p":"com.rubynaxela.kyanite.window.event","l":"JoystickConnectionListener"},{"p":"com.rubynaxela.kyanite.window.event","l":"JoystickListener"},{"p":"com.rubynaxela.kyanite.window.event","l":"KeyListener"},{"p":"com.rubynaxela.kyanite.util","l":"MathUtils"},{"p":"com.rubynaxela.kyanite.window.event","l":"MouseButtonListener"},{"p":"com.rubynaxela.kyanite.window.event","l":"MouseListener"},{"p":"com.rubynaxela.kyanite.window.event","l":"MouseWheelListener"},{"p":"com.rubynaxela.kyanite.util","l":"Pair"},{"p":"com.rubynaxela.kyanite.window.event","l":"ResizeEvent"},{"p":"com.rubynaxela.kyanite.window.event","l":"ResizeListener"},{"p":"com.rubynaxela.kyanite.window","l":"Scene"},{"p":"com.rubynaxela.kyanite.game.assets","l":"Sound"},{"p":"com.rubynaxela.kyanite.game.gui","l":"Text"},{"p":"com.rubynaxela.kyanite.window.event","l":"TextListener"},{"p":"com.rubynaxela.kyanite.game.assets","l":"Texture"},{"p":"com.rubynaxela.kyanite.window","l":"Window"}];updateSearchResults();
\ No newline at end of file
diff --git a/kyanite.iml b/kyanite.iml
new file mode 100644
index 00000000..de90c35a
--- /dev/null
+++ b/kyanite.iml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lib/annotations-20.1.0.jar b/lib/annotations-20.1.0.jar
new file mode 100644
index 00000000..8bd96c58
Binary files /dev/null and b/lib/annotations-20.1.0.jar differ
diff --git a/lib/jackson-annotations-2.13.0.jar b/lib/jackson-annotations-2.13.0.jar
new file mode 100644
index 00000000..ad9613d0
Binary files /dev/null and b/lib/jackson-annotations-2.13.0.jar differ
diff --git a/lib/jackson-core-2.13.0.jar b/lib/jackson-core-2.13.0.jar
new file mode 100644
index 00000000..fd8c2ed5
Binary files /dev/null and b/lib/jackson-core-2.13.0.jar differ
diff --git a/lib/jackson-databind-2.13.0.jar b/lib/jackson-databind-2.13.0.jar
new file mode 100644
index 00000000..d72f47ec
Binary files /dev/null and b/lib/jackson-databind-2.13.0.jar differ
diff --git a/lib/jsfml/bin/jsfml.jar b/lib/jsfml/bin/jsfml.jar
new file mode 100644
index 00000000..1ec34110
Binary files /dev/null and b/lib/jsfml/bin/jsfml.jar differ
diff --git a/lib/jsfml/src/java/org/jsfml/audio/ConstSoundBuffer.java b/lib/jsfml/src/java/org/jsfml/audio/ConstSoundBuffer.java
new file mode 100644
index 00000000..eca1e1b7
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/audio/ConstSoundBuffer.java
@@ -0,0 +1,65 @@
+package org.jsfml.audio;
+
+import org.jsfml.internal.Const;
+import org.jsfml.system.Time;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+
+/**
+ * Read-only interface for sound buffers.
+ *
+ * It provides methods to can gain information from a sound buffer (such as the duration)
+ * and save it to a file.
+ *
+ * Note that this interface is expected to be implemented by a {@link SoundBuffer}.
+ * It is not recommended to be implemented outside of the JSFML API.
+ *
+ * @see Const
+ */
+public interface ConstSoundBuffer extends Const {
+ /**
+ * Attempts to save the sound buffer to a file.
+ *
+ * @param path the path to the file to write.
+ * @throws IOException in case saving failed.
+ */
+ public void saveToFile(Path path) throws IOException;
+
+ /**
+ * Retrieves the raw 16-bit audio samples stored in the buffer.
+ *
+ * @return the raw audio 16-bit samples stored in the buffer.
+ */
+ public short[] getSamples();
+
+ /**
+ * Retrieves the amount of samples stored in the buffer.
+ *
+ * @return the amount of samples stored in the buffer.
+ */
+ public int getSampleCount();
+
+ /**
+ * Gets the sound buffer's sample rate in samples per second.
+ *
+ * @return the sound buffer's sample rate in samples per second.
+ */
+ public int getSampleRate();
+
+ /**
+ * Gets the amount of audio channels in the buffer
+ * (e.g. 1 for mono, 2 for stereo etc).
+ *
+ * @return the amount of audio channels in the buffer.
+ */
+ public int getChannelCount();
+
+ /**
+ * Gets the duration of the sound.
+ *
+ * @return the duration of the sound.
+ */
+ public Time getDuration();
+}
diff --git a/lib/jsfml/src/java/org/jsfml/audio/Listener.java b/lib/jsfml/src/java/org/jsfml/audio/Listener.java
new file mode 100644
index 00000000..03585db6
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/audio/Listener.java
@@ -0,0 +1,129 @@
+package org.jsfml.audio;
+
+import org.jsfml.internal.SFMLNative;
+import org.jsfml.system.Vector3f;
+
+/**
+ * Represents the point in the scene from where all the sounds are heard and
+ * provides funcionality to modify it.
+ *
+ * Modifying the position and orientation ("view direction") of the listener
+ * changes the way sounds are heard to accomplish 3D sound.
+ * Sounds will be panned and attenuated according to their position relative to the listener
+ * and the listener's orientation..
+ */
+public final class Listener {
+ static {
+ SFMLNative.loadNativeLibraries();
+ }
+
+ //cache
+ private static float volume = 100;
+ private static Vector3f position = Vector3f.ZERO;
+ private static Vector3f direction = Vector3f.ZERO;
+
+ private static native void nativeSetGlobalVolume(float volume);
+
+ /**
+ * Sets the global sound volume.
+ *
+ * The default global volume is 100 (maximum).
+ *
+ * @param volume the global sound volume, ranging between 0 (silence) and 100 (full volume).
+ */
+ public static void setGlobalVolume(float volume) {
+ nativeSetGlobalVolume(volume);
+ Listener.volume = volume;
+ }
+
+ /**
+ * Gets the global sound volume.
+ *
+ * @return the global sound volume, ranging between 0 (silence) and 100 (full volume).
+ */
+ public static float getGlobalVolume() {
+ return volume;
+ }
+
+ private static native void nativeSetPosition(float x, float y, float z);
+
+ /**
+ * Sets the position of the listener in the scene.
+ *
+ * Initially, the listener is located at the origin (0, 0, 0).
+ *
+ * @param x the X coordinate of the listener's new position.
+ * @param y the Y coordinate of the listener's new position.
+ * @param z the Z coordinate of the listener's new position.
+ * @see SoundSource#setPosition(org.jsfml.system.Vector3f)
+ */
+ public static void setPosition(float x, float y, float z) {
+ setPosition(new Vector3f(x, y, z));
+ }
+
+ /**
+ * Sets the position of the listener in the scene.
+ *
+ * Initially, the listener is located at the origin (0, 0, 0).
+ *
+ * @param v the listener's new position.
+ * @see SoundSource#setPosition(org.jsfml.system.Vector3f)
+ */
+ public static void setPosition(Vector3f v) {
+ nativeSetPosition(v.x, v.y, v.z);
+ Listener.position = v;
+ }
+
+ /**
+ * Gets the listener's current position in the scene.
+ *
+ * @return the listener's current position in the scene.
+ */
+ public static Vector3f getPosition() {
+ return position;
+ }
+
+ private static native void nativeSetDirection(float x, float y, float z);
+
+ /**
+ * Sets the orientation or "view direction" of the listener in the scene.
+ *
+ * The vector passed does not need to be normalized. Initially, the listener's orientation
+ * is along the Z axis, looking "into" the screen (0, 0, -1).
+ *
+ * @param x the X component of the listener's new orientation.
+ * @param y the Y component of the listener's new orientation.
+ * @param z the Z component of the listener's new orientation.
+ * @see SoundSource#setPosition(org.jsfml.system.Vector3f)
+ */
+ public static void setDirection(float x, float y, float z) {
+ setDirection(new Vector3f(x, y, z));
+ }
+
+ /**
+ * Sets the orientation or "view direction" of the listener in the scene.
+ *
+ * The vector passed does not need to be normalized. Initially, the listener's orientation
+ * is along the Z axis, looking "into" the screen (0, 0, -1).
+ *
+ * @param v the listener's new orientation.
+ * @see SoundSource#setPosition(org.jsfml.system.Vector3f)
+ */
+ public static void setDirection(Vector3f v) {
+ nativeSetDirection(v.x, v.y, v.z);
+ Listener.direction = v;
+ }
+
+ /**
+ * Gets the listener's current orientation or "view direction" in the scene.
+ *
+ * @return the listener's current orientation in the scene.
+ */
+ public static Vector3f getDirection() {
+ return direction;
+ }
+
+ //cannot instantiate
+ private Listener() {
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/audio/Music.java b/lib/jsfml/src/java/org/jsfml/audio/Music.java
new file mode 100644
index 00000000..a47bfe49
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/audio/Music.java
@@ -0,0 +1,123 @@
+package org.jsfml.audio;
+
+import org.jsfml.internal.IntercomHelper;
+import org.jsfml.internal.SFMLErrorCapture;
+import org.jsfml.internal.SFMLInputStream;
+import org.jsfml.system.Time;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Objects;
+
+/**
+ * Provides functionality to play music streams from common audio file formats.
+ *
+ * Audio files can be opened using either the {@link #openFromFile(java.nio.file.Path)} or
+ * {@link #openFromStream(java.io.InputStream)} methods.
+ *
+ * The supported audio file formats are:
+ * {@code ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam, w64, mat4,
+ * mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64}
+ */
+public class Music extends SoundStream {
+ private final SFMLInputStream.NativeStreamRef streamRef =
+ new SFMLInputStream.NativeStreamRef();
+
+ private Time duration = Time.ZERO;
+
+ /**
+ * Constructs a music.
+ */
+ public Music() {
+ super();
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native long nativeCreate();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeSetExPtr();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeDelete();
+
+ private native boolean nativeOpenFromStream(SFMLInputStream.NativeStreamRef stream);
+
+ /**
+ * Attempts to open the music from an {@code InputStream}.
+ *
+ * @param in the input stream to stream from.
+ * @throws java.io.IOException in case an I/O error occurs.
+ */
+ public void openFromStream(InputStream in) throws IOException {
+ streamRef.initialize(new SFMLInputStream(Objects.requireNonNull(in)));
+
+ SFMLErrorCapture.start();
+ final boolean success = nativeOpenFromStream(streamRef);
+ final String msg = SFMLErrorCapture.finish();
+
+ if (!success) {
+ throw new IOException(msg);
+ }
+
+ sync();
+ }
+
+ /**
+ * Attempts to open the music from a file.
+ *
+ * @param path the file to stream from.
+ * @throws IOException in case an I/O error occurs.
+ */
+ public void openFromFile(Path path) throws IOException {
+ openFromStream(Files.newInputStream(path));
+ }
+
+ private native void nativeGetData(Buffer buffer);
+
+ private void sync() {
+ final ByteBuffer buffer = IntercomHelper.getBuffer();
+ nativeGetData(buffer);
+
+ this.duration = Time.getMicroseconds(buffer.asLongBuffer().get(0));
+
+ final IntBuffer ints = buffer.asIntBuffer();
+ setData(ints.get(2), ints.get(3));
+ }
+
+ /**
+ * Gets the total duration of the music.
+ *
+ * @return the total duration of the music.
+ */
+ public Time getDuration() {
+ return duration;
+ }
+
+ @Override
+ protected final void initialize(int channelCount, int sampleRate) {
+ //Music is implemented natively, so this is not used.
+ }
+
+ @Override
+ protected final Chunk onGetData() {
+ //Music is implemented natively, so this is not used.
+ return null;
+ }
+
+ @Override
+ protected final void onSeek(Time time) {
+ //Music is implemented natively, so this is not used.
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/audio/Sound.java b/lib/jsfml/src/java/org/jsfml/audio/Sound.java
new file mode 100644
index 00000000..48174c07
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/audio/Sound.java
@@ -0,0 +1,161 @@
+package org.jsfml.audio;
+
+import org.jsfml.internal.IntercomHelper;
+import org.jsfml.internal.UnsafeOperations;
+import org.jsfml.system.Time;
+
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.util.Objects;
+
+/**
+ * Provides functionality to instantiate a {@code SoundBuffer} and play a buffered sound.
+ */
+public class Sound extends SoundSource {
+ //cache
+ private ConstSoundBuffer soundBuffer = null;
+ private boolean loop = false;
+ private Time playingOffset = Time.ZERO;
+
+ /**
+ * Constructs an empty sound.
+ */
+ public Sound() {
+ super();
+ }
+
+ /**
+ * Constructs a sound with the specified {@link SoundBuffer}
+ *
+ * @param soundBuffer the sound buffer to use.
+ */
+ public Sound(ConstSoundBuffer soundBuffer) {
+ this();
+ setBuffer(soundBuffer);
+ }
+
+ /**
+ * Constructs a sound by copying another sound.
+ *
+ * @param other the sound to copy.
+ */
+ @SuppressWarnings("deprecation")
+ public Sound(Sound other) {
+ super(other.nativeCopy());
+ UnsafeOperations.manageSFMLObject(this, true);
+
+ final ByteBuffer buffer = IntercomHelper.getBuffer();
+ nativeGetData(buffer);
+
+ this.loop = (buffer.get(0) == 1);
+ this.playingOffset = Time.getMicroseconds(buffer.asLongBuffer().get(1));
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native long nativeCreate();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeSetExPtr();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeDelete();
+
+ private native long nativeCopy();
+
+ private native void nativeGetData(Buffer buffer);
+
+ /**
+ * Starts playing the sound or resumes it if it is currently paused.
+ */
+ public native void play();
+
+ /**
+ * Pauses the sound if it is currently playing.
+ */
+ public native void pause();
+
+ /**
+ * Stops the sound if it is currently playing or paused.
+ */
+ public native void stop();
+
+ private native void nativeSetBuffer(SoundBuffer soundBuffer);
+
+ /**
+ * Sets the sound buffer used by this sound.
+ *
+ * @param soundBuffer the new sound buffer.
+ */
+ public void setBuffer(ConstSoundBuffer soundBuffer) {
+ this.soundBuffer = Objects.requireNonNull(soundBuffer);
+ nativeSetBuffer((SoundBuffer) soundBuffer);
+ }
+
+ private native void nativeSetLoop(boolean loop);
+
+ /**
+ * Enables or disables repeated looping of the sound.
+ *
+ * If this is set to {@code true} and the sound has finished playing, it will
+ * be restarted from the beginning as if {@code setPlayingOffset(Time.ZERO)} was called.
+ *
+ * @param loop {@code true} to enable looping, {@code false} to disable.
+ */
+ public void setLoop(boolean loop) {
+ nativeSetLoop(loop);
+ this.loop = loop;
+ }
+
+ private native void nativeSetPlayingOffset(long offset);
+
+ /**
+ * Sets the playing offset from where to play the underlying buffer.
+ *
+ * @param offset the playing offset in the underlaying buffer.
+ */
+ public void setPlayingOffset(Time offset) {
+ nativeSetPlayingOffset(offset.asMicroseconds());
+ this.playingOffset = offset;
+ }
+
+ /**
+ * Gets the underlying sound buffer that this sound plays from.
+ *
+ * @return the underlying sound buffer that this sound plays from.
+ */
+ public ConstSoundBuffer getBuffer() {
+ return soundBuffer;
+ }
+
+ /**
+ * Returns whether or not the sound is looping.
+ *
+ * @return {@code true} if this sound is looping, {@code false} if not.
+ */
+ public boolean isLoop() {
+ return loop;
+ }
+
+ /**
+ * Gets the playing offset from where to start playing the underlying buffer.
+ *
+ * @return the playing offset from where to start playing the underlying buffer.
+ */
+ public Time getPlayingOffset() {
+ return playingOffset;
+ }
+
+ @Override
+ native int nativeGetStatus();
+
+ @Override
+ public Status getStatus() {
+ return super.getStatus();
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/audio/SoundBuffer.java b/lib/jsfml/src/java/org/jsfml/audio/SoundBuffer.java
new file mode 100644
index 00000000..5a784aec
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/audio/SoundBuffer.java
@@ -0,0 +1,234 @@
+package org.jsfml.audio;
+
+
+import org.jsfml.internal.*;
+import org.jsfml.system.Time;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.*;
+import java.nio.file.Path;
+
+/**
+ * Buffer of audio samples, providing an audio data source for a {@code Sound}.
+ */
+public class SoundBuffer extends SFMLNativeObject implements ConstSoundBuffer {
+ //cache
+ private int sampleCount = 0;
+ private int sampleRate = 0;
+ private int channelCount = 0;
+ private Time duration = Time.ZERO;
+
+ private boolean needsSync = true;
+ private boolean samplesNeedSync = true;
+ private ShortBuffer samplesBuffer = null;
+
+ /**
+ * Constructs a sound buffer.
+ */
+ public SoundBuffer() {
+ super();
+ }
+
+ @SuppressWarnings("deprecation")
+ SoundBuffer(long wrap) {
+ super(wrap);
+ }
+
+ /**
+ * Constructs a sound buffer by copying another sound buffer.
+ *
+ * @param other the sound buffer to copy.
+ */
+ @SuppressWarnings("deprecation")
+ public SoundBuffer(ConstSoundBuffer other) {
+ super(((SoundBuffer) other).nativeCopy());
+ UnsafeOperations.manageSFMLObject(this, true);
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native long nativeCreate();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected void nativeSetExPtr() {
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeDelete();
+
+ private native long nativeCopy();
+
+ private native boolean nativeLoadFromMemory(byte[] memory);
+
+ /**
+ * Fully loads all available bytes from the specified {@link java.io.InputStream}
+ * and attempts to load the sound buffer from it.
+ *
+ * @param in the input stream to read from.
+ * @throws java.io.IOException in case an I/O error occurs.
+ */
+ public void loadFromStream(InputStream in) throws IOException {
+ SFMLErrorCapture.start();
+ final boolean success = nativeLoadFromMemory(StreamUtil.readStream(in));
+ final String err = SFMLErrorCapture.finish();
+
+ if (!success) {
+ throw new IOException(err);
+ }
+
+ needsSync = true;
+ samplesNeedSync = true;
+ }
+
+ /**
+ * Attempts to load the sound buffer from a file.
+ *
+ * @param path the path to the file to load the sound buffer from.
+ * @throws IOException in case an I/O error occurs.
+ */
+ public void loadFromFile(Path path) throws IOException {
+ SFMLErrorCapture.start();
+ final boolean success = nativeLoadFromMemory(StreamUtil.readFile(path));
+ final String err = SFMLErrorCapture.finish();
+
+ if (!success) {
+ throw new IOException(err);
+ }
+
+ needsSync = true;
+ samplesNeedSync = true;
+ }
+
+ private native boolean nativeLoadFromSamples(Buffer samples, int n, int channelCount, int sampleRate);
+
+ /**
+ * Attempts to load the sound buffer from an array of raw 16-bit audio samples.
+ *
+ * @param samples the samples data.
+ * @param channelCount the amount of audio channels.
+ * @param sampleRate the sample rate in samples per second.
+ * @throws java.io.IOException in case an I/O error occurs.
+ */
+ public void loadFromSamples(short[] samples, int channelCount, int sampleRate)
+ throws IOException {
+
+ final ShortBuffer buffer = ByteBuffer.allocateDirect(2 * samples.length).order(
+ ByteOrder.nativeOrder()).asShortBuffer();
+
+ buffer.put(samples);
+
+ SFMLErrorCapture.start();
+ final boolean success = nativeLoadFromSamples(
+ buffer, samples.length, channelCount, sampleRate);
+
+ final String err = SFMLErrorCapture.finish();
+
+ if (!success) {
+ throw new IOException(err);
+ }
+
+ this.samplesBuffer = buffer;
+ this.sampleCount = samples.length;
+ this.channelCount = channelCount;
+ this.sampleRate = sampleRate;
+
+ needsSync = true;
+ samplesNeedSync = false;
+ }
+
+ private native boolean nativeSaveToFile(String fileName);
+
+ @Override
+ public void saveToFile(Path path) throws IOException {
+ SFMLErrorCapture.start();
+ final boolean success = nativeSaveToFile(path.toAbsolutePath().toString());
+ final String err = SFMLErrorCapture.finish();
+
+ if (!success) {
+ throw new IOException(err);
+ }
+ }
+
+ private native void nativeGetData(Buffer buffer);
+
+ private void sync() {
+ if (needsSync) {
+ final IntBuffer ints = IntercomHelper.getBuffer().asIntBuffer();
+ final LongBuffer longs = IntercomHelper.getBuffer().asLongBuffer();
+
+ nativeGetData(IntercomHelper.getBuffer());
+ sampleCount = ints.get(0);
+ sampleRate = ints.get(1);
+ channelCount = ints.get(2);
+ duration = Time.getMicroseconds(longs.get(2));
+
+ needsSync = false;
+ }
+ }
+
+ private native void nativeGetSamples(int n, Buffer buffer);
+
+ private void syncSamples() {
+ if (samplesNeedSync) {
+ final int samples = getSampleCount();
+ samplesBuffer = ByteBuffer.allocateDirect(2 * getSampleCount()).order(
+ ByteOrder.nativeOrder()).asShortBuffer();
+
+ nativeGetSamples(samples, samplesBuffer);
+ samplesNeedSync = false;
+ }
+ }
+
+ @Override
+ public short[] getSamples() {
+ if (samplesNeedSync) {
+ syncSamples();
+ }
+
+ final short[] copy = new short[sampleCount];
+ samplesBuffer.get(copy);
+ return copy;
+ }
+
+ @Override
+ public int getSampleCount() {
+ if (needsSync) {
+ sync();
+ }
+
+ return sampleCount;
+ }
+
+ @Override
+ public int getSampleRate() {
+ if (needsSync) {
+ sync();
+ }
+
+ return sampleRate;
+ }
+
+ @Override
+ public int getChannelCount() {
+ if (needsSync) {
+ sync();
+ }
+
+ return channelCount;
+ }
+
+ @Override
+ public Time getDuration() {
+ if (needsSync) {
+ sync();
+ }
+
+ return duration;
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/audio/SoundBufferRecorder.java b/lib/jsfml/src/java/org/jsfml/audio/SoundBufferRecorder.java
new file mode 100644
index 00000000..331a80f1
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/audio/SoundBufferRecorder.java
@@ -0,0 +1,62 @@
+package org.jsfml.audio;
+
+/**
+ * A {@code SoundRecorder} which stores captured audio data into a {@code SoundBuffer}.
+ */
+public class SoundBufferRecorder extends SoundRecorder {
+ private SoundBuffer soundBuffer;
+
+ /**
+ * Constructs a sound buffer recorder.
+ */
+ public SoundBufferRecorder() {
+ super();
+ soundBuffer = new SoundBuffer(nativeGetBuffer());
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native long nativeCreate();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeSetExPtr();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeDelete();
+
+ private native long nativeGetBuffer();
+
+ /**
+ * Gets the sound buffer containing the captured audio data.
+ *
+ * The sound buffer will remain empty until any sound has been successfully captured
+ * using the {@link #start(int)} and {@link #stop()} methods.
+ *
+ * @return the sound buffer containing the captured audio data.
+ */
+ public ConstSoundBuffer getBuffer() {
+ return soundBuffer;
+ }
+
+ @Override
+ protected final boolean onStart() {
+ //SoundBufferRecorder is implemented natively, so this is not used.
+ return true;
+ }
+
+ @Override
+ protected final boolean onProcessSamples(short[] samples) {
+ //SoundBufferRecorder is implemented natively, so this is not used.
+ return true;
+ }
+
+ @Override
+ protected final void onStop() {
+ //SoundBufferRecorder is implemented natively, so this is not used.
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/audio/SoundRecorder.java b/lib/jsfml/src/java/org/jsfml/audio/SoundRecorder.java
new file mode 100644
index 00000000..4b622a1d
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/audio/SoundRecorder.java
@@ -0,0 +1,101 @@
+package org.jsfml.audio;
+
+import org.jsfml.internal.SFMLNative;
+import org.jsfml.internal.SFMLNativeObject;
+
+/**
+ * Abstract base class for sound recorders, which provide functionality to capture audio data.
+ */
+public abstract class SoundRecorder extends SFMLNativeObject {
+ static {
+ SFMLNative.loadNativeLibraries();
+ }
+
+ /**
+ * Checks whether audio capturing is available on this system.
+ *
+ * @return {@code true} if audio capturing is available, {@code false} otherwise.
+ */
+ public static native boolean isAvailable();
+
+ /**
+ * Constructs a sound recorder.
+ */
+ protected SoundRecorder() {
+ super();
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native long nativeCreate();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeSetExPtr();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeDelete();
+
+ /**
+ * Starts capturing audio data with the specified sample rate.
+ *
+ * @param sampleRate the sample rate in samples per second.
+ */
+ public final native void start(int sampleRate);
+
+ /**
+ * Starts capturing audio data with a sample rate of 44,100 Hz.
+ */
+ public final void start() {
+ start(44100);
+ }
+
+ /**
+ * Stops capturing audio data.
+ */
+ public final native void stop();
+
+ /**
+ * Gets the sample rate that audio is being captured with.
+ *
+ * @return the audio sample rate in samples per second.
+ */
+ public final native int getSampleRate();
+
+ /**
+ * Called when the sound recorder starts recording.
+ *
+ * This method can be implemented by deriving classes to perform any actions
+ * necessary before audio recording actually starts.
+ *
+ * @return {@code true} to start recording after this method is done, {@code false} to cancel.
+ */
+ protected abstract boolean onStart();
+
+ /**
+ * Called when a new batch of audio samples comes in.
+ *
+ * Implementing classes can then process the captured audio data.
+ *
+ * Note that this method will be called in a separate audio capturing thread.
+ *
+ * Also note that this method is currently hardcoded to be called every 100ms, which might
+ * be changed in the future.
+ *
+ * @param samples the 16-bit mono samples that were captured.
+ * @return {@code true} to continue recording after this method is done, {@code false}
+ * to stop recording.
+ */
+ protected abstract boolean onProcessSamples(short[] samples);
+
+ /**
+ * Called when the audio capture has stopped.
+ *
+ * Note that this method will be called in a separate audio capturing thread.
+ */
+ protected abstract void onStop();
+}
diff --git a/lib/jsfml/src/java/org/jsfml/audio/SoundSource.java b/lib/jsfml/src/java/org/jsfml/audio/SoundSource.java
new file mode 100644
index 00000000..45639dce
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/audio/SoundSource.java
@@ -0,0 +1,276 @@
+package org.jsfml.audio;
+
+import org.jsfml.internal.IntercomHelper;
+import org.jsfml.internal.SFMLNativeObject;
+import org.jsfml.system.Vector3f;
+
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+
+/**
+ * Abstract base class for playable sound sources.
+ */
+public abstract class SoundSource extends SFMLNativeObject {
+ /**
+ * Enumeration of possible sound source states.
+ */
+ public static enum Status {
+ /**
+ * Indicates that the sound is currently stopped or has finished playing.
+ */
+ STOPPED,
+
+ /**
+ * Indicates that the sound is currently paused and can be resumed.
+ */
+ PAUSED,
+
+ /**
+ * Indicates that the sound is currently playing.
+ */
+ PLAYING
+ }
+
+ //cache
+ private float volume = 100;
+ private float pitch = 1;
+ private Vector3f position = Vector3f.ZERO;
+ private boolean relativeToListener = false;
+ private float minDistance = 1;
+ private float attenuation = 1;
+
+ /**
+ * Constructs a sound source.
+ */
+ public SoundSource() {
+ super();
+ }
+
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ SoundSource(long wrap) {
+ super(wrap);
+
+ final ByteBuffer buffer = IntercomHelper.getBuffer();
+ final FloatBuffer floats = IntercomHelper.getBuffer().asFloatBuffer();
+
+ nativeGetData(buffer);
+ this.relativeToListener = (buffer.get(0) == 1);
+ this.volume = floats.get(1);
+ this.pitch = floats.get(2);
+ this.position = new Vector3f(floats.get(3), floats.get(4), floats.get(5));
+ this.minDistance = floats.get(6);
+ this.attenuation = floats.get(7);
+
+ }
+
+ private native void nativeGetData(Buffer buffer);
+
+ private native void nativeSetPitch(float pitch);
+
+ /**
+ * Sets the pitch factor of the sound.
+ *
+ * This factor is used to scale the sound's original pitch. This means that the default
+ * value of 1 will not affect the pitch at all. Values between 0 and 1 will pitch
+ * down the sound, while values greater than 1 will pitch it up.
+ *
+ * @param pitch the new pitch factor of the sound.
+ */
+ public void setPitch(float pitch) {
+ nativeSetPitch(pitch);
+ this.pitch = pitch;
+ }
+
+ private native void nativeSetVolume(float volume);
+
+ /**
+ * Sets the volume of the sound.
+ *
+ * The sound volume is a percentages and ranges between 0 (silence) and 100 (full volume).
+ * The default volume of a sound is 100.
+ *
+ * @param volume the new volume of the sound, ranging between 0 and 100.
+ */
+ public void setVolume(float volume) {
+ nativeSetVolume(volume);
+ this.volume = volume;
+ }
+
+ private native void nativeSetPosition(float x, float y, float z);
+
+ /**
+ * Sets the position of the sound in the scene.
+ *
+ * This allows for sound spatialization, also involving the {@link Listener}.
+ * The sound position is set either absolutely in the scene or relatively to the
+ * {@code Listener}, depending on whether {@link #isRelativeToListener()} is
+ * {@code true} or {@code false}.
+ *
+ * By default, a sound is located at the origin {@code (0, 0, 0)}.
+ *
+ * Note that only mono sounds (ie 1 audio channel) can be spatialized.
+ *
+ * @param x the sound's new X coordinate.
+ * @param y the sound's new Y coordinate.
+ * @param z the sound's new Z coordinate.
+ * @see #setRelativeToListener(boolean)
+ */
+ public final void setPosition(float x, float y, float z) {
+ setPosition(new Vector3f(x, y, z));
+ }
+
+ /**
+ * Sets the position of the sound in the scene.
+ *
+ * This allows for sound spatialization, also involving the {@link Listener}.
+ * The sound position is set either absolutely in the scene or relatively to the
+ * {@code Listener}, depending on whether {@link #isRelativeToListener()} is
+ * {@code true} or {@code false}.
+ *
+ * By default, a sound is located at the origin {@code (0, 0, 0)}.
+ *
+ * Note that only mono sounds (ie 1 audio channel) can be spatialized.
+ *
+ * @param v the sound's new position.
+ * @see #setRelativeToListener(boolean)
+ */
+ public void setPosition(Vector3f v) {
+ nativeSetPosition(v.x, v.y, v.z);
+ this.position = v;
+ }
+
+ private native void nativeSetRelativeToListener(boolean relative);
+
+ /**
+ * Determines whether the sound position is bound to be relative to the {@link Listener}
+ * or whether it is positioned absolutely in the scene.
+ *
+ * By default, the sound's position in the scene is absolute.
+ *
+ * @param relative {@code true} to make the sound position relative to the listener,
+ * {@code false} to make it absolute.
+ * @see SoundSource#setPosition(float, float, float)
+ */
+ public void setRelativeToListener(boolean relative) {
+ nativeSetRelativeToListener(relative);
+ this.relativeToListener = relative;
+ }
+
+ private native void nativeSetMinDistance(float distance);
+
+ /**
+ * Sets the minimum distance of the sound before attenuation kicks in.
+ *
+ * If the distance between the sound and the {@link Listener} is less or equal to this value,
+ * the sound will be heard at its maximum volume. As the distance becomes larger,
+ * the sound is attenuated (ie become more quiet) according to its attenuation factor.
+ *
+ * The default minimum distance is 1.
+ *
+ * @param distance the minimum distance before attenuation in world units.
+ * @see SoundSource#setAttenuation(float)
+ */
+ public void setMinDistance(float distance) {
+ nativeSetMinDistance(distance);
+ this.minDistance = distance;
+ }
+
+ private native void nativeSetAttenuation(float att);
+
+ /**
+ * Sets the sound's attenuation factor.
+ *
+ * As the distance between the sound and the {@link Listener} becomes higher than the
+ * minimum distance, the sound volume will decrease according to this factor.
+ *
+ * The attenuation factor ranges between 0 (no attenuation) and 100 (instant attenuation),
+ * where the default value is 1.
+ *
+ * @param att the new attenuation factor, ranging between 0 (no attenuation)
+ * and 100 (instant attenuation).
+ * @see SoundSource#setMinDistance(float)
+ */
+ public void setAttenuation(float att) {
+ nativeSetAttenuation(att);
+ this.attenuation = att;
+ }
+
+ /**
+ * Gets the sound's current pitch factor.
+ *
+ * A value of 1 means that the sound is not pitched, a value between 0 and 1 means that
+ * the sound is pitched down, a value greater than 1 means that the sound is pitched up.
+ *
+ * @return the sound's current pitch factor.
+ */
+ public float getPitch() {
+ return pitch;
+ }
+
+ /**
+ * Gets the sound's current volume.
+ *
+ * The volume level ranges between 0 (silence) and 100 (full volume).
+ *
+ * @return the sound's current volume, ranging between 0 (silence) and 100 (full volume).
+ */
+ public float getVolume() {
+ return volume;
+ }
+
+ /**
+ * Gets the sound's current position in the scene.
+ *
+ * @return the sound's current position in the scene.
+ */
+ public Vector3f getPosition() {
+ return position;
+ }
+
+ /**
+ * Returns whether the sound's position is relative to the {@link Listener}.
+ *
+ * @return {@code true} if the sound's position is relative to the listener, {@code false} if
+ * it is absolute.
+ * @see SoundSource#setRelativeToListener(boolean)
+ */
+ public boolean isRelativeToListener() {
+ return relativeToListener;
+ }
+
+ /**
+ * Gets the sound's minimum distance from the {@link Listener} before attenuation sets in.
+ *
+ * @return the sound's minimum distance before attenuation sets in.
+ * @see SoundSource#setMinDistance(float)
+ */
+ public float getMinDistance() {
+ return minDistance;
+ }
+
+ /**
+ * Gets the sound's attenuation factor.
+ *
+ * The attenuation factor ranges between 0 (no attenuation) and 100 (instant attenuation),
+ * where the default value is 1.
+ *
+ * @return the sound's attenuation factor.
+ * @see SoundSource#setAttenuation(float)
+ */
+ public float getAttenuation() {
+ return attenuation;
+ }
+
+ abstract int nativeGetStatus();
+
+ /**
+ * Gets the current state of the sound stream.
+ *
+ * @return the current state of the sound stream.
+ */
+ protected Status getStatus() {
+ return Status.values()[nativeGetStatus()];
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/audio/SoundStream.java b/lib/jsfml/src/java/org/jsfml/audio/SoundStream.java
new file mode 100644
index 00000000..626571f3
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/audio/SoundStream.java
@@ -0,0 +1,244 @@
+package org.jsfml.audio;
+
+import org.jsfml.internal.Intercom;
+import org.jsfml.system.Time;
+
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.ShortBuffer;
+import java.util.Objects;
+
+/**
+ * Abstract base class for streamed sound sources.
+ *
+ * Unlike buffered sounds, streamed sounds are not held in memory in their entirety, but only
+ * a certain amount of sound chunks. When the currently buffered chunk is done being played,
+ * the next chunk is requested from the stream's source.
+ *
+ * This approach should be preferred for long sounds
+ * that do not need to be sought around in often, such as music or procedurally generated
+ * sounds.
+ *
+ * @see Chunk
+ */
+@Intercom
+public abstract class SoundStream extends SoundSource {
+ /**
+ * Represents a chunk of audio data provided by a {@code SoundStream} when
+ * new data is requested.
+ */
+ public static class Chunk {
+ private final short[] data;
+ private final boolean last;
+
+ /**
+ * Constructs a new chunk containing the specified data.
+ *
+ * @param data An array of 16-bit samples representing the chunk's audio data.
+ * @param last Determines whether this audio chunk is the last in the stream. If set to
+ * {@code true}, the stream will stop playing once this chunk has finished
+ * playing.
+ */
+ public Chunk(short[] data, boolean last) {
+ this.data = Objects.requireNonNull(data);
+ this.last = last;
+ }
+ }
+
+ //Cache
+ private int channelCount = 0;
+ private int sampleRate = 0;
+ private boolean loop = false;
+ private Time playingOffset = Time.ZERO;
+
+ /**
+ * Constructs a sound stream.
+ */
+ public SoundStream() {
+ super();
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native long nativeCreate();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeSetExPtr();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeDelete();
+
+ /**
+ * Starts playing the stream or resumes it if it is currently paused.
+ */
+ public native void play();
+
+ /**
+ * Pauses playback of the stream if it is currently playing.
+ */
+ public native void pause();
+
+ /**
+ * Stops playing the stream.
+ */
+ public native void stop();
+
+ /**
+ * Gets the amount of audio channels of this stream.
+ *
+ * @return the amount of audio channels of this stream.
+ */
+ public int getChannelCount() {
+ return channelCount;
+ }
+
+ /**
+ * Gets the sample rate of this stream.
+ *
+ * @return the sample rate of this stream in samples per second.
+ */
+ public int getSampleRate() {
+ return sampleRate;
+ }
+
+ private native void nativeSetPlayingOffset(long offset);
+
+ /**
+ * Sets the current playing offset at which to play from the stream.
+ *
+ * @param offset the playing offset at which to play from the stream.
+ */
+ public final void setPlayingOffset(Time offset) {
+ nativeSetPlayingOffset(offset.asMicroseconds());
+ this.playingOffset = offset;
+ }
+
+ /**
+ * Gets the playing offset at which to play from the stream.
+ *
+ * @return the playing offset at which to play from the stream.
+ */
+ public Time getPlayingOffset() {
+ return playingOffset;
+ }
+
+ private native void nativeSetLoop(boolean loop);
+
+ /**
+ * Enables or disables repeated looping of the sound stream playback.
+ *
+ * If a looping sound stream has finished playing its last audio chunk, it will
+ * restart playing from the first chunk as if {@code setPlayingOffset(Time.ZERO)} was invoked.
+ *
+ * @param loop {@code true} to enable looping, {@code false} to disable.
+ */
+ public void setLoop(boolean loop) {
+ nativeSetLoop(loop);
+ this.loop = loop;
+ }
+
+ /**
+ * Returns whether or not the sound stream playback is looping.
+ *
+ * If a looping sound stream has finished playing its last audio chunk, it will
+ * restart playing from the first chunk as if {@code setPlayingOffset(Time.ZERO)} was invoked.
+ *
+ * @return {@code true} if it is looping, {@code false} if not.
+ */
+ public boolean isLoop() {
+ return loop;
+ }
+
+ @Override
+ native int nativeGetStatus();
+
+ @Override
+ public Status getStatus() {
+ return super.getStatus();
+ }
+
+ final void setData(int channelCount, int sampleRate) {
+ this.channelCount = channelCount;
+ this.sampleRate = sampleRate;
+ }
+
+ private native void nativeInitialize(int channelCount, int sampleRate);
+
+ /**
+ * Defines the audio stream parameters.
+ *
+ * Before the stream can be played, the implementing class must call this method.
+ *
+ * @param channelCount the amount of audio channels (e.g. 1 for mono, 2 for stereo).
+ * @param sampleRate the sample rate in samples per second.
+ */
+ protected void initialize(int channelCount, int sampleRate) {
+ nativeInitialize(channelCount, sampleRate);
+ setData(channelCount, sampleRate);
+ }
+
+ @Intercom
+ @SuppressWarnings("unused")
+ private Buffer onGetDataInternal() {
+ final Chunk chunk = onGetData();
+ if (chunk != null && chunk.data.length > 0) {
+ final ByteBuffer buffer = ByteBuffer.allocateDirect(4 + 2 * chunk.data.length).order(
+ ByteOrder.nativeOrder());
+
+ int header = chunk.data.length & 0x7FFFFFFF;
+ if (chunk.last) {
+ header |= 0x80000000;
+ }
+
+ buffer.asIntBuffer().put(header);
+
+ final ShortBuffer samples = buffer.asShortBuffer();
+ samples.position(2);
+ samples.put(chunk.data);
+
+ return buffer;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Requests a new chunk of audio data.
+ *
+ * This method is called when the audio stream has played all buffered samples and needs
+ * new samples to continue playing.
+ *
+ * Note that this method will be called within a separate playback thread.
+ *
+ * @return the next chunk of audio data. If the chunk is marked as the last chunk,
+ * the stream will either stop playing after playing this chunk, or restart
+ * from the beginning if {@link #isLoop()} returns {@code true}.
+ * To stop playback immediately, {@code null} may be returned.
+ * @see Chunk
+ */
+ protected abstract Chunk onGetData();
+
+ @Intercom
+ @SuppressWarnings("unused")
+ private void onSeekInternal(long time) {
+ onSeek(Time.getMicroseconds(time));
+ }
+
+ /**
+ * Re-positions the stream's current playing offset.
+ *
+ * This method is called when the stream is reset or a re-positioning has been requested
+ * via {@link #setPlayingOffset(org.jsfml.system.Time)}.
+ *
+ * Note that this method will be called within a separate playback thread.
+ *
+ * @param time the time offset to jump to.
+ */
+ protected abstract void onSeek(Time time);
+}
diff --git a/lib/jsfml/src/java/org/jsfml/audio/package-info.java b/lib/jsfml/src/java/org/jsfml/audio/package-info.java
new file mode 100644
index 00000000..4d6cd877
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/audio/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains classes related to audio playback and recording.
+ */
+package org.jsfml.audio;
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/BasicTransformable.java b/lib/jsfml/src/java/org/jsfml/graphics/BasicTransformable.java
new file mode 100644
index 00000000..f31ed3f1
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/BasicTransformable.java
@@ -0,0 +1,156 @@
+package org.jsfml.graphics;
+
+import org.jsfml.system.Vector2f;
+
+/**
+ * Implementation of the {@link Transformable} interface.
+ *
+ * Classes can inherit from this in order to provide the {@link Transformable} interface.
+ * The implementation equals that of the original SFML implementation.
+ */
+public class BasicTransformable implements Transformable {
+ private Vector2f origin = Vector2f.ZERO;
+ private Vector2f position = Vector2f.ZERO;
+ private float rotation = 0;
+ private Vector2f scale = new Vector2f(1, 1);
+
+ private Transform transform = Transform.IDENTITY;
+ private boolean transformNeedsUpdate = false;
+ private Transform inverseTransform = Transform.IDENTITY;
+ private boolean inverseTransformNeedsUpdate = false;
+
+ /**
+ * Default constructor, initializes this object with an identity transformation.
+ */
+ public BasicTransformable() {
+ }
+
+ @Override
+ public final void setPosition(float x, float y) {
+ setPosition(new Vector2f(x, y));
+ }
+
+ @Override
+ public void setPosition(Vector2f v) {
+ this.position = v;
+
+ transformNeedsUpdate = true;
+ inverseTransformNeedsUpdate = true;
+ }
+
+ @Override
+ public void setRotation(float angle) {
+ this.rotation = angle % 360.0f;
+ if (this.rotation < 0)
+ this.rotation += 360.0f;
+
+ transformNeedsUpdate = true;
+ inverseTransformNeedsUpdate = true;
+ }
+
+ @Override
+ public final void setScale(float x, float y) {
+ setScale(new Vector2f(x, y));
+ }
+
+ @Override
+ public void setScale(Vector2f factors) {
+ this.scale = factors;
+
+ transformNeedsUpdate = true;
+ inverseTransformNeedsUpdate = true;
+ }
+
+ @Override
+ public final void setOrigin(float x, float y) {
+ setOrigin(new Vector2f(x, y));
+ }
+
+ @Override
+ public void setOrigin(Vector2f v) {
+ this.origin = v;
+
+ transformNeedsUpdate = true;
+ inverseTransformNeedsUpdate = true;
+ }
+
+ @Override
+ public Vector2f getPosition() {
+ return position;
+ }
+
+ @Override
+ public float getRotation() {
+ return rotation;
+ }
+
+ @Override
+ public Vector2f getScale() {
+ return scale;
+ }
+
+ @Override
+ public Vector2f getOrigin() {
+ return origin;
+ }
+
+ @Override
+ public final void move(float x, float y) {
+ move(new Vector2f(x, y));
+ }
+
+ @Override
+ public void move(Vector2f v) {
+ setPosition(Vector2f.add(position, v));
+ }
+
+ @Override
+ public void rotate(float angle) {
+ setRotation(rotation + angle);
+ }
+
+ @Override
+ public final void scale(float x, float y) {
+ scale(new Vector2f(x, y));
+ }
+
+ @Override
+ public void scale(Vector2f factors) {
+ setScale(Vector2f.componentwiseMul(scale, factors));
+ }
+
+ @Override
+ public Transform getTransform() {
+ if (transformNeedsUpdate) {
+ double angle = -Math.toRadians(rotation);
+ float cos = (float) Math.cos(angle);
+ float sin = (float) Math.sin(angle);
+
+ float sxc = scale.x * cos;
+ float syc = scale.y * cos;
+ float sxs = scale.x * sin;
+ float sys = scale.y * sin;
+ float tx = -origin.x * sxc - origin.y * sys + position.x;
+ float ty = origin.x * sxs - origin.y * syc + position.y;
+
+ transform = new Transform(
+ sxc, sys, tx,
+ -sxs, syc, ty,
+ 0, 0, 1);
+
+ transformNeedsUpdate = false;
+ }
+
+ return transform;
+ }
+
+ @Override
+ public Transform getInverseTransform() {
+ if (inverseTransformNeedsUpdate) {
+ inverseTransform = getTransform().getInverse();
+ inverseTransformNeedsUpdate = false;
+ }
+
+ return inverseTransform;
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/BlendMode.java b/lib/jsfml/src/java/org/jsfml/graphics/BlendMode.java
new file mode 100644
index 00000000..ecb64857
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/BlendMode.java
@@ -0,0 +1,34 @@
+package org.jsfml.graphics;
+
+/**
+ * Enumeration of the supported blending modes for drawing.
+ */
+public enum BlendMode {
+ /**
+ * Blends source and destrination colors by using a common alpha blending formula.
+ *
+ * {@code Pixel = Source * Source.a + Dest * (1 - Source.a)}
+ */
+ ALPHA,
+
+ /**
+ * Blends source and destination colors by performing a component-wise addition.
+ *
+ * {@code Pixel = Source + Dest}
+ */
+ ADD,
+
+ /**
+ * Blends source and destination colors by performing a component-wise multiplication.
+ *
+ * {@code Pixel = Source * Dest}
+ */
+ MULTIPLY,
+
+ /**
+ * Does not blend and overrides the destination color with the source color.
+ *
+ * {@code Pixel = Source}
+ */
+ NONE
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/CircleShape.java b/lib/jsfml/src/java/org/jsfml/graphics/CircleShape.java
new file mode 100644
index 00000000..9231400d
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/CircleShape.java
@@ -0,0 +1,89 @@
+package org.jsfml.graphics;
+
+/**
+ * A specialized shape representing a circle.
+ */
+public class CircleShape extends Shape {
+ //cache
+ private float radius = 0;
+
+ /**
+ * Constructs a new circle shape with a zero radius, approximated using 30 points.
+ */
+ public CircleShape() {
+ super();
+ }
+
+ /**
+ * Constructs a new circle shape with the specified radius, approximated using 30 points.
+ *
+ * @param radius the circle's radius.
+ */
+ public CircleShape(float radius) {
+ this();
+ setRadius(radius);
+ }
+
+ /**
+ * Constructs a new circle shape with the specified parameters.
+ *
+ * @param radius the circle's radius.
+ * @param points the amount of points to approximate the circle with.
+ * @see CircleShape#setPointCount(int)
+ */
+ public CircleShape(float radius, int points) {
+ this(radius);
+ setPointCount(points);
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native long nativeCreate();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeSetExPtr();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeDelete();
+
+ private native void nativeSetRadius(float radius);
+
+ /**
+ * Sets the radius of this circle.
+ *
+ * @param radius the new radius of the circle shape.
+ */
+ public void setRadius(float radius) {
+ nativeSetRadius(radius);
+ this.radius = radius;
+ pointsNeedUpdate = true;
+ }
+
+ /**
+ * Gets the radius of this circle.
+ *
+ * @return the radius of this circle shape.
+ */
+ public float getRadius() {
+ return radius;
+ }
+
+ private native void nativeSetPointCount(int count);
+
+ /**
+ * Sets the amount of points the circle should be approximated with.
+ *
+ * A higher amount of points will yield a smoother result at the cost of performance.
+ *
+ * @param count the amount of points used to approximate the circle.
+ */
+ public void setPointCount(int count) {
+ nativeSetPointCount(count);
+ pointsNeedUpdate = true;
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/Color.java b/lib/jsfml/src/java/org/jsfml/graphics/Color.java
new file mode 100644
index 00000000..36e8a3b5
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/Color.java
@@ -0,0 +1,194 @@
+package org.jsfml.graphics;
+
+
+import java.io.Serializable;
+
+/**
+ * Represents RGBA colors.
+ */
+public final class Color implements Serializable {
+ private static final long serialVersionUID = -161207563051572152L;
+
+ /**
+ * Black {@code (0, 0, 0)}
+ */
+ public final static Color BLACK = new Color(0, 0, 0);
+
+ /**
+ * White {@code (255, 255, 255)}
+ */
+ public final static Color WHITE = new Color(255, 255, 255);
+
+ /**
+ * Red {@code (255, 0, 0)}
+ */
+ public final static Color RED = new Color(255, 0, 0);
+
+ /**
+ * Green {@code (0, 255, 0)}
+ */
+ public final static Color GREEN = new Color(0, 255, 0);
+
+ /**
+ * Blue {@code (0, 0, 255)}
+ */
+ public final static Color BLUE = new Color(0, 0, 255);
+
+ /**
+ * Yellow {@code (255, 255, 0)}
+ */
+ public final static Color YELLOW = new Color(255, 255, 0);
+
+ /**
+ * Magenta {@code (255, 255, 0)}
+ */
+ public final static Color MAGENTA = new Color(255, 0, 255);
+
+ /**
+ * Cyan {@code (0, 255, 255)}
+ */
+ public final static Color CYAN = new Color(0, 255, 255);
+
+ /**
+ * Transparent {@code (0, 0, 0, 0)}
+ */
+ public final static Color TRANSPARENT = new Color(0, 0, 0, 0);
+
+ /**
+ * Modulates two colors by performing a component-wise addition.
+ *
+ * @param a the first color.
+ * @param b the second color.
+ * @return the modulated color.
+ */
+ public static Color add(Color a, Color b) {
+ return new Color(
+ a.r + b.r,
+ a.g + b.g,
+ a.b + b.b,
+ a.a + b.a);
+ }
+
+ /**
+ * Modulates two colors by performing a component-wise multiplication.
+ *
+ * @param a the first color.
+ * @param b the second color.
+ * @return the modulated color.
+ */
+ public static Color mul(Color a, Color b) {
+ return new Color(
+ (a.r * b.r) / 255,
+ (a.g * b.g) / 255,
+ (a.b * b.b) / 255,
+ (a.a * b.a) / 255);
+ }
+
+ /**
+ * Modulates a color by multiplying its components with a factor.
+ *
+ * @param color the color.
+ * @param f the factor.
+ * @return the modulated color.
+ */
+ public static Color mul(Color color, float f) {
+ return new Color(
+ (int) (color.r * f),
+ (int) (color.g * f),
+ (int) (color.b * f),
+ (int) (color.a * f));
+ }
+
+ private static int clamp(int x) {
+ return Math.max(0, Math.min(x, 255));
+ }
+
+ /**
+ * The red component of the color.
+ */
+ public final int r;
+
+ /**
+ * The green component of the color.
+ */
+ public final int g;
+
+ /**
+ * The blue component of the color.
+ */
+ public final int b;
+
+ /**
+ * The alpha component of the color, ranging between 0 (transparent) and 255 (fully opaque).
+ */
+ public final int a;
+
+ /**
+ * Constructs a new color with the specified color components and an alpha value of 255
+ * (fully opaque).
+ *
+ * @param r the color's red component.
+ * @param g the color's green component.
+ * @param b the color's blue component.
+ */
+ public Color(int r, int g, int b) {
+ this(r, g, b, 255);
+ }
+
+ /**
+ * Constructs a new color with the specified color and alpha components.
+ *
+ * @param r the color's red component.
+ * @param g the color's green component.
+ * @param b the color's blue component.
+ * @param a the color's alpha component, ranging between 0 (transparent) and 255 (fully opaque).
+ */
+ public Color(int r, int g, int b, int a) {
+ this.r = clamp(r);
+ this.g = clamp(g);
+ this.b = clamp(b);
+ this.a = clamp(a);
+ }
+
+ /**
+ * Constructs a new color by copying another color and resetting the alpha value.
+ *
+ * @param color the color to copy.
+ * @param alpha the alpha value of the new color,
+ * ranging between 0 (transparent) and 255 (fully opaque).
+ */
+ public Color(Color color, int alpha) {
+ this.r = color.r;
+ this.g = color.g;
+ this.b = color.b;
+ this.a = clamp(alpha);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return (o instanceof Color &&
+ ((Color) o).r == r &&
+ ((Color) o).g == g &&
+ ((Color) o).b == b &&
+ ((Color) o).a == a);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = r;
+ result = 31 * result + g;
+ result = 31 * result + b;
+ result = 31 * result + a;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "Color{" +
+ "r=" + r +
+ ", g=" + g +
+ ", b=" + b +
+ ", a=" + a +
+ '}';
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/ConstFont.java b/lib/jsfml/src/java/org/jsfml/graphics/ConstFont.java
new file mode 100644
index 00000000..f5a7cc0b
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/ConstFont.java
@@ -0,0 +1,55 @@
+package org.jsfml.graphics;
+
+import org.jsfml.internal.Const;
+
+/**
+ * Interface for read-only fonts.
+ *
+ * It provides methods to can gain information from a font, but none to modify it
+ * in any way.
+ *
+ * Note that this interface is expected to be implemented by a {@link Font}.
+ * It is not recommended to be implemented outside of the JSFML API.
+ *
+ * @see org.jsfml.internal.Const
+ */
+public interface ConstFont extends Const {
+ /**
+ * Gets a glyph information structure from the font.
+ *
+ * @param unicode the unicode (UTF-32) of the character to retrieve the glyph for.
+ * @param characterSize the character size in question.
+ * @param bold {@code true} if the bold glyph version should be returned,
+ * {@code false} for the regular version.
+ * @return the {@link Glyph} representing the given unicode character.
+ */
+ public Glyph getGlyph(int unicode, int characterSize, boolean bold);
+
+ /**
+ * Gets the kerning offset between two glyphs.
+ *
+ * @param first the unicode (UTF-32) of the first character.
+ * @param second the unicode (UTF-32) of the second character.
+ * @param characterSize the character size in question.
+ * @return the kerning offset between the two glyphs.
+ */
+ public int getKerning(int first, int second, int characterSize);
+
+ /**
+ * Gets the line spacing of the font.
+ *
+ * @param characterSize the character size in question.
+ * @return the line spacing of the font.
+ */
+ public int getLineSpacing(int characterSize);
+
+ /**
+ * Retrieves the texture containing the font's glyphs.
+ *
+ * The texture returned is immutable.
+ *
+ * @param characterSize the character size in question.
+ * @return the texture containing the font's glyphs of the character given size.
+ */
+ public ConstTexture getTexture(int characterSize);
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/ConstShader.java b/lib/jsfml/src/java/org/jsfml/graphics/ConstShader.java
new file mode 100644
index 00000000..d7c0edf6
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/ConstShader.java
@@ -0,0 +1,17 @@
+package org.jsfml.graphics;
+
+import org.jsfml.internal.Const;
+
+/**
+ * Interface for read-only textures.
+ *
+ * It provides methods to can gain information from a shader, but none to modify it
+ * in any way.
+ *
+ * Note that this interface is expected to be implemented by a {@link Shader}.
+ * It is not recommended to be implemented outside of the JSFML API.
+ *
+ * @see org.jsfml.internal.Const
+ */
+public interface ConstShader extends Const {
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/ConstTexture.java b/lib/jsfml/src/java/org/jsfml/graphics/ConstTexture.java
new file mode 100644
index 00000000..803e32f4
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/ConstTexture.java
@@ -0,0 +1,45 @@
+package org.jsfml.graphics;
+
+import org.jsfml.internal.Const;
+import org.jsfml.system.Vector2i;
+
+/**
+ * Interface for read-only textures.
+ *
+ * It provides methods to can gain information from a texture, but none to modify it
+ * in any way.
+ *
+ * Note that this interface is expected to be implemented by a {@link Texture}.
+ * It is not recommended to be implemented outside of the JSFML API.
+ *
+ * @see Const
+ */
+public interface ConstTexture extends Const {
+ /**
+ * Gets the dimensions of the texture.
+ *
+ * @return the dimensions of the texture.
+ */
+ public Vector2i getSize();
+
+ /**
+ * Copies this texture to an editable {@link Image}.
+ *
+ * @return the image that contains a coyp of the texure's contents.
+ */
+ public Image copyToImage();
+
+ /**
+ * Checks whether the smooth filter is enabled.
+ *
+ * @return {@code true} if enabled, {@code false} if disabled.
+ */
+ public boolean isSmooth();
+
+ /**
+ * Checks whether texture repeating is enabled.
+ *
+ * @return {@code true} if enabled, {@code false} if disabled.
+ */
+ public boolean isRepeated();
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/ConstView.java b/lib/jsfml/src/java/org/jsfml/graphics/ConstView.java
new file mode 100644
index 00000000..92c4bc83
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/ConstView.java
@@ -0,0 +1,61 @@
+package org.jsfml.graphics;
+
+import org.jsfml.internal.Const;
+import org.jsfml.system.Vector2f;
+
+/**
+ * Interface for read-only views.
+ *
+ * It provides methods to can gain information from a view, but none to modify it
+ * in any way.
+ *
+ * Note that this interface is expected to be implemented by a {@link View}. It is not
+ * recommended to be implemented outside of the JSFML API.
+ *
+ * @see Const
+ */
+public interface ConstView extends Const {
+ /**
+ * Gets the current center of the view.
+ *
+ * @return the current center of the view.
+ */
+ public Vector2f getCenter();
+
+ /**
+ * Gets the current dimensions of the view in pixels.
+ *
+ * @return the current dimensions of the view in pixels.
+ */
+ public Vector2f getSize();
+
+ /**
+ * Gets the current rotation angle of the view in degrees.
+ *
+ * @return the current rotation angle of the view in degrees.
+ */
+ public float getRotation();
+
+ /**
+ * Gets the current viewport rectangle of this view.
+ *
+ * @return the current viewport rectangle of this view.
+ */
+ public FloatRect getViewport();
+
+ /**
+ * Gets the view's current transformation matrix as determined by its center,
+ * size and rotation angle.
+ *
+ * @return the view's current transformation matrix.
+ */
+ public Transform getTransform();
+
+ /**
+ * Gets the inverse of the view's current transformation matrix as determined
+ * by its center, size and rotation angle.
+ *
+ * @return the inverse of the view's current transformation matrix.
+ */
+ public Transform getInverseTransform();
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/ConvexShape.java b/lib/jsfml/src/java/org/jsfml/graphics/ConvexShape.java
new file mode 100644
index 00000000..41bfe855
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/ConvexShape.java
@@ -0,0 +1,122 @@
+package org.jsfml.graphics;
+
+import org.jsfml.system.Vector2f;
+
+import java.util.Objects;
+
+/**
+ * Specialized shape representing a convex polygon.
+ */
+public class ConvexShape extends Shape {
+ /**
+ * Constructs a new empty polygon.
+ */
+ public ConvexShape() {
+ super();
+ }
+
+ /**
+ * Constructs a new empty polygon and allocates a certain amount of points.
+ *
+ * This is equal to calling {@link ConvexShape#setPointCount(int)} directly after
+ * construction of the polygon.
+ *
+ * @param points the amount of points of the polygon.
+ */
+ public ConvexShape(int points) {
+ this();
+ setPointCount(points);
+ }
+
+ /**
+ * Constructs a new polygon from a given set of points.
+ *
+ * This is equal to calling {@link ConvexShape#setPoints(org.jsfml.system.Vector2f...)}
+ * directly after construction of the polygon.
+ *
+ * @param points the points of the polygon.
+ */
+ public ConvexShape(Vector2f... points) {
+ this();
+ setPoints(points);
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native long nativeCreate();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeSetExPtr();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeDelete();
+
+ private native void nativeSetPointCount(int count);
+
+ private native void nativeSetPoint(int i, float x, float y);
+
+ /**
+ * Sets the amount of points that belong to the polygon.
+ *
+ * @param pointCount the amount of points of the polygon.
+ */
+ public void setPointCount(int pointCount) {
+ nativeSetPointCount(pointCount);
+
+ points = new Vector2f[pointCount];
+ for (int i = 0; i < pointCount; i++) {
+ points[i] = Vector2f.ZERO;
+ }
+ }
+
+ /**
+ * Sets a point of the polygon.
+ *
+ * @param i the index of the point to set. Note that this index must be within the bounds
+ * of the polygon's point count, ie the point count needs to be set properly
+ * using {@link ConvexShape#setPointCount(int)} first.
+ * @param v the point to set at the given index.
+ */
+ public void setPoint(int i, Vector2f v) {
+ if (points == null || i < 0 || i >= points.length)
+ throw new IndexOutOfBoundsException(Integer.toString(i));
+
+ nativeSetPoint(i, v.x, v.y);
+ points[i] = v;
+ }
+
+ /**
+ * Sets the points of the polygon.
+ *
+ * The use of this method equals consecutive calls of {@link ConvexShape#setPointCount(int)}
+ * and {@link ConvexShape#setPoint(int, org.jsfml.system.Vector2f)} for each point
+ * in the given array.
+ *
+ * @param points the points of the polygon.
+ */
+ public void setPoints(Vector2f... points) {
+ this.points = Objects.requireNonNull(points);
+ nativeSetPointCount(points.length);
+
+ for (int i = 0; i < points.length; i++) {
+ if (points[i] == null) {
+ setPointCount(0);
+ this.points = null;
+ throw new NullPointerException("point " + i + " is null.");
+ }
+
+ nativeSetPoint(i, points[i].x, points[i].y);
+ }
+ }
+
+ @Override
+ public Vector2f[] getPoints() {
+ pointsNeedUpdate = false;
+ return super.getPoints();
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/Drawable.java b/lib/jsfml/src/java/org/jsfml/graphics/Drawable.java
new file mode 100644
index 00000000..773a891f
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/Drawable.java
@@ -0,0 +1,17 @@
+package org.jsfml.graphics;
+
+/**
+ * Interface for objects that can be drawn to a render target.
+ *
+ * Implementing classes can be conveniently used for the {@link RenderTarget#draw(Drawable)}
+ * method, but serve no additional purpose otherwise.
+ */
+public interface Drawable {
+ /**
+ * Draws the object to a render target.
+ *
+ * @param target the target to draw this object on.
+ * @param states the current render states.
+ */
+ void draw(RenderTarget target, RenderStates states);
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/FloatRect.java b/lib/jsfml/src/java/org/jsfml/graphics/FloatRect.java
new file mode 100644
index 00000000..21bb60ec
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/FloatRect.java
@@ -0,0 +1,205 @@
+/*
+ This class uses direct C++ to Java translations from SFML source code, hence the following notice:
+
+ ////////////////////////////////////////////////////////////
+ //
+ // SFML - Simple and Fast Multimedia Library
+ // Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
+ //
+ // This software is provided 'as-is', without any express or implied warranty.
+ // In no event will the authors be held liable for any damages arising from the use of this software.
+ //
+ // Permission is granted to anyone to use this software for any purpose,
+ // including commercial applications, and to alter it and redistribute it freely,
+ // subject to the following restrictions:
+ //
+ // 1. The origin of this software must not be misrepresented;
+ // you must not claim that you wrote the original software.
+ // If you use this software in a product, an acknowledgment
+ // in the product documentation would be appreciated but is not required.
+ //
+ // 2. Altered source versions must be plainly marked as such,
+ // and must not be misrepresented as being the original software.
+ //
+ // 3. This notice may not be removed or altered from any source distribution.
+ //
+ ////////////////////////////////////////////////////////////
+*/
+
+package org.jsfml.graphics;
+
+import org.jsfml.system.Vector2f;
+
+import java.io.Serializable;
+
+/**
+ * Represents an axis-aligned rectangle using floating point coordinates.
+ */
+public final strictfp class FloatRect implements Serializable {
+ private static final long serialVersionUID = -8603980852893951558L;
+
+ /**
+ * An empty rectangle with no dimensions.
+ */
+ public static final FloatRect EMPTY = new FloatRect(0, 0, 0, 0);
+
+ /**
+ * The X coordinate of the rectangle's left edge.
+ */
+ public final float left;
+
+ /**
+ * The Y coordinate of the rectangle's top edge.
+ */
+ public final float top;
+
+ /**
+ * The width of the rectangle.
+ */
+ public final float width;
+
+ /**
+ * The height of the rectangle.
+ */
+ public final float height;
+
+ /**
+ * Constructs a new rectangle with the specified parameters.
+ *
+ * @param left the X coordinate of the rectangle's left edge.
+ * @param top the Y coordinate of the rectangle's top edge.
+ * @param width the rectangle's width.
+ * @param height the rectangle's height.
+ */
+ public FloatRect(float left, float top, float width, float height) {
+ this.left = left;
+ this.top = top;
+ this.width = width;
+ this.height = height;
+ }
+
+ /**
+ * Constructs a new rectangle with the specified parameters.
+ *
+ * @param position the position of the rectangle's top left corner.
+ * @param size the rectangle's dimension.
+ */
+ public FloatRect(Vector2f position, Vector2f size) {
+ this.left = position.x;
+ this.top = position.y;
+ this.width = size.x;
+ this.height = size.y;
+ }
+
+ /**
+ * Constructs a new rectangle by converting an intergral rectangle.
+ *
+ * The fractions of the components will be set to zero.
+ *
+ * @param rect the rectangle to convert.
+ */
+ public FloatRect(IntRect rect) {
+ this((float) rect.left, (float) rect.top, (float) rect.width, (float) rect.height);
+ }
+
+ /**
+ * Tests whether a point is inside the rectangle's boundaries, including its edges.
+ *
+ * @param x the X coordinate of the tested point.
+ * @param y the Y coordinate of the tested point.
+ * @return {@code true} if the point lies within the rectangle's boundaries,
+ * {@code false} otherwise.
+ */
+ public boolean contains(float x, float y) {
+ //direct port of SFML code
+ final float minX = Math.min(left, left + width);
+ final float maxX = Math.max(left, left + width);
+ final float minY = Math.min(top, top + height);
+ final float maxY = Math.max(top, top + height);
+
+ return (x >= minX) && (x < maxX) && (y >= minY) && (y < maxY);
+ }
+
+ /**
+ * Tests whether a point is inside the rectangle's boundaries, including its edges.
+ *
+ * @param point the point to be tested.
+ * @return {@code true} if the point lies within the rectangle's boundaries,
+ * {@code false} otherwise.
+ */
+ public boolean contains(Vector2f point) {
+ return contains(point.x, point.y);
+ }
+
+ /**
+ * Tests whether this rectangle intersects with another rectangle and
+ * calculates the rectangle of intersection.
+ *
+ * @param rect the rectangle to test against.
+ * @return the intersection rectangle, or {@code null} if the rectangles do not intersect.
+ */
+ public FloatRect intersection(FloatRect rect) {
+ //direct port of SFML code
+
+ // Compute the min and max of the first rectangle on both axes
+ final float r1MinX = Math.min(left, left + width);
+ final float r1MaxX = Math.max(left, left + width);
+ final float r1MinY = Math.min(top, top + height);
+ final float r1MaxY = Math.max(top, top + height);
+
+ // Compute the min and max of the second rectangle on both axes
+ final float r2MinX = Math.min(rect.left, rect.left + rect.width);
+ final float r2MaxX = Math.max(rect.left, rect.left + rect.width);
+ final float r2MinY = Math.min(rect.top, rect.top + rect.height);
+ final float r2MaxY = Math.max(rect.top, rect.top + rect.height);
+
+ // Compute the intersection boundaries
+ final float interLeft = Math.max(r1MinX, r2MinX);
+ final float interTop = Math.max(r1MinY, r2MinY);
+ final float interRight = Math.min(r1MaxX, r2MaxX);
+ final float interBottom = Math.min(r1MaxY, r2MaxY);
+
+ // If the intersection is valid (positive non zero area), then there is an intersection
+ if ((interLeft < interRight) && (interTop < interBottom)) {
+ return new FloatRect(
+ interLeft,
+ interTop,
+ interRight - interLeft,
+ interBottom - interTop);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof FloatRect) {
+ FloatRect r = (FloatRect) o;
+ return (left == r.left &&
+ top == r.top &&
+ width == r.width &&
+ height == r.height);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (left != +0.0f ? Float.floatToIntBits(left) : 0);
+ result = 31 * result + (top != +0.0f ? Float.floatToIntBits(top) : 0);
+ result = 31 * result + (width != +0.0f ? Float.floatToIntBits(width) : 0);
+ result = 31 * result + (height != +0.0f ? Float.floatToIntBits(height) : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "FloatRect{" +
+ "left=" + left +
+ ", top=" + top +
+ ", width=" + width +
+ ", height=" + height +
+ '}';
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/Font.java b/lib/jsfml/src/java/org/jsfml/graphics/Font.java
new file mode 100644
index 00000000..14c57170
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/Font.java
@@ -0,0 +1,172 @@
+package org.jsfml.graphics;
+
+import org.jsfml.internal.*;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.Buffer;
+import java.nio.IntBuffer;
+import java.nio.file.Path;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Holds a character font for use in text displays.
+ */
+public class Font extends SFMLNativeObject implements ConstFont {
+ private class SizeInfo {
+ final int characterSize, lineSpacing;
+ final ConstTexture texture;
+ final TreeMap kerning = new TreeMap<>();
+ final TreeMap glyphs = new TreeMap<>();
+ final TreeMap boldGlyphs = new TreeMap<>();
+
+ SizeInfo(int characterSize, int lineSpacing, ConstTexture texture) {
+ this.characterSize = characterSize;
+ this.lineSpacing = lineSpacing;
+ this.texture = texture;
+ }
+ }
+
+ private final Map sizeInfos = new TreeMap<>();
+
+ /**
+ * Memory reference and heap pointer that keeps alive the data input stream for freetype.
+ */
+ private final NativeRef memoryRef = new NativeRef() {
+ @Override
+ protected long nativeInitialize(byte[] ref) {
+ return nativeLoadFromMemory(ref);
+ }
+
+ @Override
+ protected void nativeRelease(byte[] ref, long ptr) {
+ nativeReleaseMemory(ref, ptr);
+ }
+ };
+
+ /**
+ * Constructs a new font.
+ */
+ public Font() {
+ super();
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native long nativeCreate();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected void nativeSetExPtr() {
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeDelete();
+
+ private native long nativeLoadFromMemory(byte[] memory);
+
+ private native void nativeReleaseMemory(byte[] memory, long ptr);
+
+ /**
+ * Fully loads all available bytes from an {@link java.io.InputStream}
+ * and attempts to load the texture from it.
+ *
+ * @param in the input stream to read from.
+ * @throws java.io.IOException in case an I/O error occurs.
+ */
+ public void loadFromStream(InputStream in) throws IOException {
+ SFMLErrorCapture.start();
+ memoryRef.initialize(StreamUtil.readStream(in));
+ final String msg = SFMLErrorCapture.finish();
+
+ if (!memoryRef.hasNonZeroPointer()) {
+ throw new IOException(msg);
+ }
+ }
+
+ /**
+ * Attempts to load the texture from a file.
+ *
+ * @param path the path to the file to load the texture from.
+ * @throws IOException in case an I/O error occurs.
+ */
+ public void loadFromFile(Path path) throws IOException {
+ SFMLErrorCapture.start();
+ memoryRef.initialize(StreamUtil.readFile(path));
+ final String msg = SFMLErrorCapture.finish();
+
+ if (!memoryRef.hasNonZeroPointer()) {
+ throw new IOException(msg);
+ }
+ }
+
+ private native long nativeGetTexture(int characterSize);
+
+ private native int nativeGetLineSpacing(int characterSize);
+
+ private native void nativeGetGlyph(int unicode, int characterSize, boolean bold, Buffer buf);
+
+ private native int nativeGetKerning(int first, int second, int characterSize);
+
+ private SizeInfo getSizeInfo(int characterSize) {
+ SizeInfo info = sizeInfos.get(characterSize);
+ if (info == null) {
+ final int lineSpacing = nativeGetLineSpacing(characterSize);
+ final long p = nativeGetTexture(characterSize);
+ final ConstTexture tex = (p != 0) ? new Texture(p) : null;
+
+ info = new SizeInfo(characterSize, lineSpacing, tex);
+ sizeInfos.put(characterSize, info);
+ }
+ return info;
+ }
+
+ @Override
+ public Glyph getGlyph(int unicode, int characterSize, boolean bold) {
+ final SizeInfo info = getSizeInfo(characterSize);
+ final Map glyphMap = bold ? info.boldGlyphs : info.glyphs;
+
+ Glyph glyph = glyphMap.get(unicode);
+ if (glyph == null) {
+ final IntBuffer buf = IntercomHelper.getBuffer().asIntBuffer();
+
+ nativeGetGlyph(unicode, characterSize, bold, buf);
+ glyph = new Glyph(
+ buf.get(0),
+ new IntRect(buf.get(1), buf.get(2), buf.get(3), buf.get(4)),
+ new IntRect(buf.get(5), buf.get(6), buf.get(7), buf.get(8)));
+
+ glyphMap.put(unicode, glyph);
+ }
+
+ return glyph;
+ }
+
+ @Override
+ public int getKerning(int first, int second, int characterSize) {
+ final SizeInfo info = getSizeInfo(characterSize);
+ final long x = ((long) first << 32) | (long) second;
+ Integer kerning = info.kerning.get(x);
+ if (kerning == null) {
+ kerning = nativeGetKerning(first, second, characterSize);
+ info.kerning.put(x, kerning);
+ }
+
+ return kerning;
+ }
+
+ @Override
+ public int getLineSpacing(int characterSize) {
+ return getSizeInfo(characterSize).lineSpacing;
+ }
+
+ @Override
+ public ConstTexture getTexture(int characterSize) {
+ return getSizeInfo(characterSize).texture;
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/Glyph.java b/lib/jsfml/src/java/org/jsfml/graphics/Glyph.java
new file mode 100644
index 00000000..b2c88e9f
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/Glyph.java
@@ -0,0 +1,41 @@
+package org.jsfml.graphics;
+
+/**
+ * Describes a glyph in a {@link Font}.
+ *
+ * @see Font
+ */
+public final class Glyph {
+ /**
+ * The offset to move horizontally to the next character.
+ */
+ public final int advance;
+
+ /**
+ * The bounding rectangle of the glyph, in coordinates relative to the baseline.
+ */
+ public final IntRect bounds;
+
+ /**
+ * The texture coordinates of the glyph on the font's texture.
+ */
+ public final IntRect textureRect;
+
+ /**
+ * Constructs a glyph with the specified parameters.
+ *
+ * Note that this constructor is reserved for internal use and should
+ * never be required to be used directly. Glyphs should be obtained
+ * using the {@link Font#getGlyph(int, int, boolean)} method.
+ *
+ * @param advance the offset to move horizontally to the next character.
+ * @param bounds the boundaries of the glyph.
+ * @param textureRect the texture rectangle used by the glyph.
+ * @see Font#getGlyph(int, int, boolean)
+ */
+ public Glyph(int advance, IntRect bounds, IntRect textureRect) {
+ this.advance = advance;
+ this.bounds = bounds;
+ this.textureRect = textureRect;
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/Image.java b/lib/jsfml/src/java/org/jsfml/graphics/Image.java
new file mode 100644
index 00000000..95f56073
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/Image.java
@@ -0,0 +1,511 @@
+package org.jsfml.graphics;
+
+import org.jsfml.internal.IntercomHelper;
+import org.jsfml.internal.SFMLErrorCapture;
+import org.jsfml.internal.SFMLNativeObject;
+import org.jsfml.internal.StreamUtil;
+import org.jsfml.system.Vector2i;
+
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.IntBuffer;
+import java.nio.file.Path;
+
+/**
+ * Provides methods for loading, manipulating and saving images.
+ */
+public class Image extends SFMLNativeObject {
+ private static int srcBlend(int s, int d) {
+ final int sa = (s >> 24) & 0xFF;
+ final int sb = (s >> 16) & 0xFF;
+ final int sg = (s >> 8) & 0xFF;
+ final int sr = s & 0xFF;
+
+ final int da = (d >> 24) & 0xFF;
+ final int db = (d >> 16) & 0xFF;
+ final int dg = (d >> 8) & 0xFF;
+ final int dr = d & 0xFF;
+
+ final int r = (sr * sa + dr * (255 - sa)) / 255;
+ final int g = (sg * sa + dg * (255 - sa)) / 255;
+ final int b = (sb * sa + db * (255 - sa)) / 255;
+ final int a = (sa + da * (255 - sa)) / 255;
+
+ return (a << 24) | (b << 16) | (g << 8) | r;
+ }
+
+ private static int swapRB(int s) {
+ return (s & 0xFF00FF00) |
+ ((s & 0xFF) << 16) |
+ ((s >> 16) & 0xFF);
+ }
+
+ private Vector2i size = Vector2i.ZERO;
+ private IntBuffer pixels = null;
+ private boolean changed = true;
+
+ /**
+ * Constructs a new empty image.
+ */
+ public Image() {
+ super();
+ }
+
+ @SuppressWarnings("deprecation")
+ Image(long wrap) {
+ super(wrap);
+ sync();
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native long nativeCreate();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected void nativeSetExPtr() {
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeDelete();
+
+ /**
+ * Generates a new image and fills it with a color.
+ *
+ * @param width the image's width.
+ * @param height the image's height.
+ * @param color the fill color of the image.
+ */
+ public void create(int width, int height, Color color) {
+ if (width < 0 || height < 0) {
+ throw new IllegalArgumentException("width: " + width + ", height: " + height);
+ }
+
+ size = new Vector2i(width, height);
+
+ if (width > 0 && height > 0) {
+ pixels = ByteBuffer.allocateDirect(4 * width * height).order(
+ ByteOrder.LITTLE_ENDIAN).asIntBuffer();
+ } else {
+ pixels = null;
+ }
+
+ if (!color.equals(Color.BLACK)) {
+ fill(color);
+ }
+ }
+
+ /**
+ * Generates a new image and fills it with black.
+ *
+ * @param width the image's width.
+ * @param height the image's height.
+ */
+ public final void create(int width, int height) {
+ create(width, height, Color.BLACK);
+ }
+
+ /**
+ * Creates a new image by converting an AWT {@link BufferedImage}.
+ *
+ * @param image the AWT buffered image to convert.
+ */
+ public void create(BufferedImage image) {
+ final int w = image.getWidth();
+ final int h = image.getHeight();
+
+ final int[] data = new int[w * h];
+ create(w, h, image.getRGB(0, 0, w, h, data, 0, w));
+ }
+
+ /**
+ * Creates a new image from the given pixel data.
+ *
+ * The pixel data is expected to be in the {@link BufferedImage#TYPE_INT_ARGB}
+ * color format.
+ *
+ * @param width the image's width.
+ * @param height the image's height.
+ * @param pixels the image's pixel data in 32-bit ARGB format.
+ */
+ public void create(int width, int height, int[] pixels) {
+ if (pixels.length != width * height) {
+ throw new IllegalArgumentException(
+ "pixel buffer size does not fit the specified dimensions");
+ }
+
+ create(width, height);
+
+ if (width > 0 && height > 0) {
+ //Pixels are in ARGB, we need ABGR
+ for (int i = 0; i < pixels.length; i++) {
+ pixels[i] = swapRB(pixels[i]);
+ }
+
+ this.pixels.rewind();
+ this.pixels.put(pixels);
+ }
+ }
+
+ private native boolean nativeLoadFromMemory(byte[] memory);
+
+ /**
+ * Fully loads all available bytes from an {@link java.io.InputStream}
+ * and attempts to load the image from it.
+ *
+ * @param in the input stream to read from.
+ * @throws java.io.IOException in case an I/O error occurs.
+ */
+ public void loadFromStream(InputStream in) throws IOException {
+ SFMLErrorCapture.start();
+ final boolean success = nativeLoadFromMemory(StreamUtil.readStream(in));
+ final String err = SFMLErrorCapture.finish();
+
+ if (!success) {
+ throw new IOException(err);
+ }
+
+ sync();
+ }
+
+ /**
+ * Attempts to load an image from a file.
+ *
+ * @param path the file to load the texture from.
+ * @throws IOException in case an I/O error occurs.
+ */
+ public void loadFromFile(Path path) throws IOException {
+ SFMLErrorCapture.start();
+ final boolean success = nativeLoadFromMemory(StreamUtil.readFile(path));
+ final String err = SFMLErrorCapture.finish();
+
+ if (!success) {
+ throw new IOException(err);
+ }
+
+ sync();
+ }
+
+ private native boolean nativeSaveToFile(String fileName);
+
+ /**
+ * Attempts to save the image to a file.
+ *
+ * @param path the path to the file to write.
+ * @throws IOException in case an I/O error occurs.
+ */
+ public void saveToFile(Path path) throws IOException {
+ commit();
+
+ SFMLErrorCapture.start();
+ final boolean success = nativeSaveToFile(path.toAbsolutePath().toString());
+ final String err = SFMLErrorCapture.finish();
+
+ if (!success) {
+ throw new IOException(err);
+ }
+ }
+
+ private native long nativeGetSize();
+
+ private native void nativeSync(int width, int height, Buffer buffer);
+
+ final void sync() {
+ size = IntercomHelper.decodeVector2i(nativeGetSize());
+ create(size.x, size.y);
+
+ if (size.x > 0 && size.y > 0) {
+ nativeSync(size.x, size.y, pixels);
+ }
+
+ changed = false;
+ }
+
+ private native void nativeCommit(int width, int height, Buffer buffer);
+
+ final void commit() {
+ if (changed) {
+ nativeCommit(size.x, size.y, pixels);
+ changed = false;
+ }
+ }
+
+ private int pixel(int x, int y) {
+ return y * size.x + x;
+ }
+
+ /**
+ * Gets the size of the image.
+ *
+ * @return the size of the image.
+ */
+ public Vector2i getSize() {
+ return size;
+ }
+
+ private void fill(Color color) {
+ final int c = IntercomHelper.encodeColor(color);
+ for (int i = 0; i < size.x * size.y; i++) {
+ pixels.put(i, c);
+ }
+ }
+
+ /**
+ * Creates a transparency mask from the given color.
+ *
+ * @param color the color to be made transparent.
+ * @param alpha the alpha value to assign to pixels matching the color key.
+ */
+ public void createMaskFromColor(Color color, int alpha) {
+ final int c = IntercomHelper.encodeColor(color);
+ final int a = alpha << 24;
+
+ for (int i = 0; i < size.x * size.y; i++) {
+ final int s = pixels.get(i);
+ if (pixels.get(i) == c) {
+ pixels.put(i, a | (s & 0xFFFFFF));
+ }
+ }
+
+ changed = true;
+ }
+
+ /**
+ * Creates a transparency mask from the given color, making matching pixels fully transparent.
+ *
+ * @param color the color to be made transparent.
+ */
+ public final void createMaskFromColor(Color color) {
+ createMaskFromColor(color, 0);
+ }
+
+ /**
+ * Copies a portion of another image onto this image.
+ *
+ * @param source the source image.
+ * @param destX the destination X coordinate.
+ * @param destY the destination X coordinate.
+ * @param sourceRect the source rectangle. An empty rectangle means the full image.
+ * @param applyAlpha {@code true} to copy alpha values as well, {@code false} to leave the destination alpha.
+ */
+ public void copy(Image source, int destX, int destY, IntRect sourceRect, boolean applyAlpha) {
+ //Code partially translated from SFML
+
+ //Make sure both images are valid
+ if (size.x == 0 || size.y == 0 || source.size.x == 0 || source.size.y == 0) {
+ return;
+ }
+
+ //Adjust source rectangle
+ int left, top, width, height;
+
+ if (sourceRect.width == 0 || sourceRect.height == 0) {
+ left = 0;
+ top = 0;
+ width = source.size.x;
+ height = source.size.y;
+ } else {
+ left = Math.max(0, sourceRect.top);
+ top = Math.max(0, sourceRect.top);
+ width = Math.min(sourceRect.width, source.size.x - left);
+ height = Math.min(sourceRect.height, source.size.y - top);
+ }
+
+ //Adjust destination rectangle
+ if (destX + width > size.x) width = size.x - destX;
+ if (destY + height > size.y) height = size.y - destY;
+
+ //Validate
+ if (width <= 0 || height <= 0) {
+ return;
+ }
+
+ //Copy
+ if (applyAlpha) {
+ //Pixel by pixel...
+ for (int y = 0; y < height; y++) {
+ int src = source.pixel(left, top + y);
+ int dst = pixel(destX, destY + y);
+
+ for (int x = 0; x < width; x++) {
+ final int s = source.pixels.get(src);
+ final int d = pixels.get(dst);
+
+ //Blend
+ pixels.put(dst, srcBlend(s, d));
+
+ src++;
+ dst++;
+ }
+ }
+ } else {
+ //"lines"
+ final int[] buffer = new int[width];
+ for (int y = 0; y < height; y++) {
+ source.pixels.position(source.pixel(left, top + y));
+ source.pixels.get(buffer, 0, width);
+
+ pixels.position(pixel(destX, destY + y));
+ pixels.put(buffer, 0, width);
+ }
+ }
+
+ changed = true;
+ }
+
+ /**
+ * Copies a portion of another image onto this image.
+ *
+ * @param source the source image.
+ * @param destX the destination X coordinate.
+ * @param destY the destination X coordinate.
+ * @param sourceRect the source rectangle. An empty rectangle means the full image.
+ */
+ public final void copy(Image source, int destX, int destY, IntRect sourceRect) {
+ copy(source, destX, destY, sourceRect, false);
+ }
+
+ /**
+ * Copies another image onto this image.
+ *
+ * @param source the source image.
+ * @param destX the destination X coordinate.
+ * @param destY the destination X coordinate.
+ */
+ public final void copy(Image source, int destX, int destY) {
+ copy(source, destX, destY, IntRect.EMPTY, false);
+ }
+
+ /**
+ * Sets the color of a certain pixel.
+ *
+ * @param x the pixel's X coordinate.
+ * @param y the pixel's Y coordinate.
+ * @param color the color to apply to the pixel.
+ */
+ public void setPixel(int x, int y, Color color) {
+ if (x < 0 || y < 0 || x >= size.x || y >= size.y) {
+ throw new PixelOutOfBoundsException(x, y);
+ }
+
+ pixels.put(y * size.x + x, IntercomHelper.encodeColor(color));
+ changed = true;
+ }
+
+ /**
+ * Gets the color of a certain pixel.
+ *
+ * @param x the pixel's X coordinate.
+ * @param y the pixel's Y coordinate.
+ * @return the pixel's color.
+ */
+ public Color getPixel(int x, int y) {
+ if (x < 0 || y < 0 || x >= size.x || y >= size.y) {
+ throw new PixelOutOfBoundsException(x, y);
+ }
+
+ return IntercomHelper.decodeColor(pixels.get(y * size.x + x));
+ }
+
+ /**
+ * Retrieves a copy of all the pixels of the image in 32-bit ARGB color format.
+ *
+ * The retrieved image data is compatible to the {@link BufferedImage#TYPE_INT_ARGB}
+ * color format.
+ *
+ * @return a copy of all the pixels of the image in 32-bit ARGB color format.
+ */
+ public int[] getPixels() {
+ final int[] data = new int[pixels.capacity()];
+
+ //Pixels are in ABGR, we promise ARGB
+ for (int i = 0; i < data.length; i++) {
+ data[i] = swapRB(pixels.get(i));
+ }
+
+ return data;
+ }
+
+ /**
+ * Converts this image to an AWT {@link BufferedImage}.
+ *
+ * The resulting buffered image will be of {@link BufferedImage#TYPE_INT_ARGB}
+ * color format.
+ *
+ * @return the resulting buffered image.
+ */
+ public BufferedImage toBufferedImage() {
+ final BufferedImage bufferedImage = new BufferedImage(
+ size.x, size.y, BufferedImage.TYPE_INT_ARGB);
+
+ if (size.x > 0 && size.y > 0) {
+ bufferedImage.setRGB(0, 0, size.x, size.y, getPixels(), 0, size.x);
+ }
+
+ return bufferedImage;
+ }
+
+ /**
+ * Flips the image horizontally.
+ */
+ public void flipHorizontally() {
+ for (int y = 0; y < size.y; y++) {
+ for (int x = 0; x < size.x / 2; x++) {
+ final int i1 = y * size.x + x;
+ final int i2 = y * size.x + size.x - 1 - x;
+
+ if (i1 != i2) {
+ final int t = pixels.get(i1);
+ pixels.put(i1, pixels.get(i2));
+ pixels.put(i2, t);
+ }
+ }
+ }
+ changed = true;
+ }
+
+ /**
+ * Flips the image vertically.
+ */
+ public void flipVertically() {
+ for (int x = 0; x < size.x; x++) {
+ for (int y = 0; y < size.y / 2; y++) {
+ final int i1 = y * size.x + x;
+ final int i2 = (size.y - 1 - y) * size.x + x;
+
+ if (i1 != i2) {
+ final int t = pixels.get(i1);
+ pixels.put(i1, pixels.get(i2));
+ pixels.put(i2, t);
+ }
+ }
+ }
+ changed = true;
+ }
+
+ /**
+ * Thrown if a non-existing pixel is being accessed by either {@link #getPixel(int, int)}
+ * or {@link #setPixel(int, int, Color)}.
+ */
+ public static class PixelOutOfBoundsException extends RuntimeException {
+ private static final long serialVersionUID = -7306446590734505000L;
+
+ /**
+ * Constructs a new exception.
+ *
+ * @param x the X coordinate of the pixel that was being accessed.
+ * @param y the Y coordinate of the pixel that was being accessed.
+ */
+ public PixelOutOfBoundsException(int x, int y) {
+ super("(" + x + ", " + y + ")");
+ }
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/IntRect.java b/lib/jsfml/src/java/org/jsfml/graphics/IntRect.java
new file mode 100644
index 00000000..7156e672
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/IntRect.java
@@ -0,0 +1,205 @@
+/*
+ This class uses direct C++ to Java translations from SFML source code, hence the following notice:
+
+ ////////////////////////////////////////////////////////////
+ //
+ // SFML - Simple and Fast Multimedia Library
+ // Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
+ //
+ // This software is provided 'as-is', without any express or implied warranty.
+ // In no event will the authors be held liable for any damages arising from the use of this software.
+ //
+ // Permission is granted to anyone to use this software for any purpose,
+ // including commercial applications, and to alter it and redistribute it freely,
+ // subject to the following restrictions:
+ //
+ // 1. The origin of this software must not be misrepresented;
+ // you must not claim that you wrote the original software.
+ // If you use this software in a product, an acknowledgment
+ // in the product documentation would be appreciated but is not required.
+ //
+ // 2. Altered source versions must be plainly marked as such,
+ // and must not be misrepresented as being the original software.
+ //
+ // 3. This notice may not be removed or altered from any source distribution.
+ //
+ ////////////////////////////////////////////////////////////
+*/
+
+package org.jsfml.graphics;
+
+import org.jsfml.system.Vector2i;
+
+import java.io.Serializable;
+
+/**
+ * Represents an axis-aligned rectangle using integer coordinates.
+ */
+public final class IntRect implements Serializable {
+ private static final long serialVersionUID = -4430448425788537785L;
+
+ /**
+ * An empty rectangle with no dimensions.
+ */
+ public static final IntRect EMPTY = new IntRect(0, 0, 0, 0);
+
+ /**
+ * The X coordinate of the rectangle's left edge.
+ */
+ public final int left;
+
+ /**
+ * The Y coordinate of the rectangle's top edge.
+ */
+ public final int top;
+
+ /**
+ * The width of the rectangle.
+ */
+ public final int width;
+
+ /**
+ * The height of the rectangle.
+ */
+ public final int height;
+
+ /**
+ * Constructs a new rectangle with the specified parameters.
+ *
+ * @param left the X coordinate of the rectangle's left edge.
+ * @param top the Y coordinate of the rectangle's top edge.
+ * @param width the rectangle's width.
+ * @param height the rectangle's height.
+ */
+ public IntRect(int left, int top, int width, int height) {
+ this.left = left;
+ this.top = top;
+ this.width = width;
+ this.height = height;
+ }
+
+ /**
+ * Constructs a new rectangle with the specified parameters.
+ *
+ * @param position the position of the rectangle's top left corner.
+ * @param size the rectangle's dimension.
+ */
+ public IntRect(Vector2i position, Vector2i size) {
+ this.left = position.x;
+ this.top = position.y;
+ this.width = size.x;
+ this.height = size.y;
+ }
+
+ /**
+ * Constructs a new rectangle by converting a floating point rectangle.
+ *
+ * The fractions of the components will be removed.
+ *
+ * @param rect the rectangle to convert.
+ */
+ public IntRect(FloatRect rect) {
+ this((int) rect.left, (int) rect.top, (int) rect.width, (int) rect.height);
+ }
+
+ /**
+ * Tests whether a point is inside the rectangle's boundaries, including its edges.
+ *
+ * @param x the X coordinate of the tested point.
+ * @param y the Y coordinate of the tested point.
+ * @return {@code true} if the point lies within the rectangle's boundaries,
+ * {@code false} otherwise.
+ */
+ public boolean contains(int x, int y) {
+ //direct port of SFML code
+ final int minX = Math.min(left, left + width);
+ final int maxX = Math.max(left, left + width);
+ final int minY = Math.min(top, top + height);
+ final int maxY = Math.max(top, top + height);
+
+ return (x >= minX) && (x < maxX) && (y >= minY) && (y < maxY);
+ }
+
+ /**
+ * Tests whether a point is inside the rectangle's boundaries, including its edges.
+ *
+ * @param point the point to be tested.
+ * @return {@code true} if the point lies within the rectangle's boundaries,
+ * {@code false} otherwise.
+ */
+ public boolean contains(Vector2i point) {
+ return contains(point.x, point.y);
+ }
+
+ /**
+ * Tests whether this rectangle intersects with another rectangle and
+ * calculates the rectangle of intersection.
+ *
+ * @param rect the rectangle to test against.
+ * @return the intersection rectangle, or {@code null} if the rectangles do not intersect.
+ */
+ public IntRect intersection(IntRect rect) {
+ //direct port of SFML code
+
+ // Compute the min and max of the first rectangle on both axes
+ final int r1MinX = Math.min(left, left + width);
+ final int r1MaxX = Math.max(left, left + width);
+ final int r1MinY = Math.min(top, top + height);
+ final int r1MaxY = Math.max(top, top + height);
+
+ // Compute the min and max of the second rectangle on both axes
+ final int r2MinX = Math.min(rect.left, rect.left + rect.width);
+ final int r2MaxX = Math.max(rect.left, rect.left + rect.width);
+ final int r2MinY = Math.min(rect.top, rect.top + rect.height);
+ final int r2MaxY = Math.max(rect.top, rect.top + rect.height);
+
+ // Compute the intersection boundaries
+ final int interLeft = Math.max(r1MinX, r2MinX);
+ final int interTop = Math.max(r1MinY, r2MinY);
+ final int interRight = Math.min(r1MaxX, r2MaxX);
+ final int interBottom = Math.min(r1MaxY, r2MaxY);
+
+ // If the intersection is valid (positive non zero area), then there is an intersection
+ if ((interLeft < interRight) && (interTop < interBottom)) {
+ return new IntRect(
+ interLeft,
+ interTop,
+ interRight - interLeft,
+ interBottom - interTop);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof IntRect) {
+ IntRect r = (IntRect) o;
+ return (left == r.left &&
+ top == r.top &&
+ width == r.width &&
+ height == r.height);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ int result = left;
+ result = 31 * result + top;
+ result = 31 * result + width;
+ result = 31 * result + height;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "IntRect{" +
+ "left=" + left +
+ ", top=" + top +
+ ", width=" + width +
+ ", height=" + height +
+ '}';
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/PrimitiveType.java b/lib/jsfml/src/java/org/jsfml/graphics/PrimitiveType.java
new file mode 100644
index 00000000..5aea2cc9
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/PrimitiveType.java
@@ -0,0 +1,45 @@
+package org.jsfml.graphics;
+
+/**
+ * Enumeration of supported primitive types.
+ *
+ * @see VertexArray
+ */
+public enum PrimitiveType {
+ /**
+ * A list of individual points.
+ */
+ POINTS,
+
+ /**
+ * A list of individual lines.
+ */
+ LINES,
+
+ /**
+ * A list of connected lines, where each point gets connected to the previous point.
+ */
+ LINE_STRIP,
+
+ /**
+ * A list of individual triangles.
+ */
+ TRIANGLES,
+
+ /**
+ * A list of connected triangles, where ech point uses the two previous points
+ * to form a triangle.
+ */
+ TRIANGLE_STRIP,
+
+ /**
+ * A list of connected triangles, where each point uses the common center and the
+ * previous point to form a triangle.
+ */
+ TRIANGLE_FAN,
+
+ /**
+ * A list of individual quads.
+ */
+ QUADS
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/RectangleShape.java b/lib/jsfml/src/java/org/jsfml/graphics/RectangleShape.java
new file mode 100644
index 00000000..527c6ce6
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/RectangleShape.java
@@ -0,0 +1,65 @@
+package org.jsfml.graphics;
+
+import org.jsfml.system.Vector2f;
+
+/**
+ * A specialized shape representing a rectangle.
+ */
+public class RectangleShape extends Shape {
+ //cache
+ private Vector2f size = Vector2f.ZERO;
+
+ /**
+ * Constructs a new rectangle shape with no dimensions.
+ */
+ public RectangleShape() {
+ super();
+ }
+
+ /**
+ * Constructs a new rectangle shape with the specified dimensions.
+ *
+ * @param size the rectangle's dimensions.
+ */
+ public RectangleShape(Vector2f size) {
+ this();
+ setSize(size);
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native long nativeCreate();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeSetExPtr();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeDelete();
+
+ private native void nativeSetSize(float w, float h);
+
+ /**
+ * Sets the dimensions of the rectangle.
+ *
+ * @param size the new dimensions of the rectangle.
+ */
+ public void setSize(Vector2f size) {
+ nativeSetSize(size.x, size.y);
+ this.size = size;
+ pointsNeedUpdate = true;
+ }
+
+ /**
+ * Gets the dimensions of the rectangle.
+ *
+ * @return the dimensions of the rectangle.
+ */
+ public Vector2f getSize() {
+ return size;
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/RenderStates.java b/lib/jsfml/src/java/org/jsfml/graphics/RenderStates.java
new file mode 100644
index 00000000..5a1b3126
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/RenderStates.java
@@ -0,0 +1,136 @@
+package org.jsfml.graphics;
+
+import java.util.Objects;
+
+/**
+ * Defines drawing properties when drawing objects to a {@link RenderTarget}.
+ */
+public final class RenderStates {
+ /**
+ * Pre-defined instance holding the default render states using
+ * {@link BlendMode#ALPHA} blending, the identity transformation and no texture or shader.
+ */
+ public static final RenderStates DEFAULT =
+ new RenderStates(BlendMode.ALPHA, Transform.IDENTITY, null, null);
+
+ /**
+ * The blending mode used for drawing.
+ */
+ public final BlendMode blendMode;
+
+ /**
+ * The transformation matrix used for drawing.
+ */
+ public final Transform transform;
+
+ /**
+ * The texture used for drawing.
+ */
+ public final ConstTexture texture;
+
+ /**
+ * The shader used for drawing.
+ */
+ public final ConstShader shader;
+
+ /**
+ * Constructs a new set of render states with default settings and
+ * the specified blending mode.
+ *
+ * @param blendMode the blending mode used for drawing.
+ */
+ public RenderStates(BlendMode blendMode) {
+ this(blendMode, Transform.IDENTITY, null, null);
+ }
+
+ /**
+ * Constructs a new set of render states with default settings and
+ * the specified transformation matrix.
+ *
+ * @param transform the transformation matrix used for drawing.
+ */
+ public RenderStates(Transform transform) {
+ this(BlendMode.ALPHA, transform, null, null);
+ }
+
+ /**
+ * Constructs a new set of render states with default settings and
+ * the specified texture.
+ *
+ * @param texture the texture used for drawing,
+ * or {@code null} to indicate that no texture should be used.
+ */
+ public RenderStates(ConstTexture texture) {
+ this(BlendMode.ALPHA, Transform.IDENTITY, texture, null);
+ }
+
+ /**
+ * Constructs a new set of render states with default settings and
+ * the specified shader.
+ *
+ * @param shader the shader applied to whatever is drawn using these states,
+ * or {@code null} to indicate that no shader should be used.
+ */
+ public RenderStates(ConstShader shader) {
+ this(BlendMode.ALPHA, Transform.IDENTITY, null, shader);
+ }
+
+ /**
+ * Constructs a new set of render states by copying other states,
+ * but changing the blend mode.
+ *
+ * @param blendMode the blending mode used for drawing.
+ */
+ public RenderStates(RenderStates states, BlendMode blendMode) {
+ this(blendMode, states.transform, states.texture, states.shader);
+ }
+
+ /**
+ * Constructs a new set of render states by copying other states,
+ * but changing the transformation.
+ *
+ * @param transform the transformation matrix used for drawing.
+ */
+ public RenderStates(RenderStates states, Transform transform) {
+ this(states.blendMode, transform, states.texture, states.shader);
+ }
+
+ /**
+ * Constructs a new set of render states by copying other states,
+ * but changing the texture.
+ *
+ * @param texture the texture used for drawing, or {@code null} to indicate that
+ * no texture should be used.
+ */
+ public RenderStates(RenderStates states, ConstTexture texture) {
+ this(states.blendMode, states.transform, texture, states.shader);
+ }
+
+ /**
+ * Constructs a new set of render states by copying other states,
+ * but changing the shader.
+ *
+ * @param shader the shader applied to whatever is drawn using these states,
+ * or {@code null} to indicate that no shader should be used.
+ */
+ public RenderStates(RenderStates states, ConstShader shader) {
+ this(states.blendMode, states.transform, states.texture, shader);
+ }
+
+ /**
+ * Constructs a new set of render states with the specified parameters.
+ *
+ * @param blendMode the blending mode used for drawing.
+ * @param transform the transformation matrix used for drawing.
+ * @param texture the texture used for drawing,
+ * or {@code null} to indicate that no texture should be used.
+ * @param shader the shader applied to whatever is drawn using these states,
+ * or {@code null} to indicate that no shader should be used.
+ */
+ public RenderStates(BlendMode blendMode, Transform transform, ConstTexture texture, ConstShader shader) {
+ this.blendMode = Objects.requireNonNull(blendMode);
+ this.transform = Objects.requireNonNull(transform);
+ this.texture = texture;
+ this.shader = shader;
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/RenderTarget.java b/lib/jsfml/src/java/org/jsfml/graphics/RenderTarget.java
new file mode 100644
index 00000000..436c63cb
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/RenderTarget.java
@@ -0,0 +1,135 @@
+package org.jsfml.graphics;
+
+import org.jsfml.system.Vector2f;
+import org.jsfml.system.Vector2i;
+
+/**
+ * Interface for render targets.
+ */
+public interface RenderTarget {
+ /**
+ * Clears the render target and fills it with a constant color.
+ *
+ * @param color the color to fill the target with.
+ */
+ public void clear(Color color);
+
+ /**
+ * Sets the target's view.
+ *
+ * @param view the target's new view.
+ */
+ public void setView(ConstView view);
+
+ /**
+ * Gets the target's current view.
+ *
+ * @return the target's current view.
+ */
+ public ConstView getView();
+
+ /**
+ * Gets the target's default view.
+ *
+ * @return the target's default view.
+ */
+ public ConstView getDefaultView();
+
+ /**
+ * Computes the viewport of the given view applied to this render target.
+ *
+ * @param view the view.
+ * @return the viewport of the given view applied to this render target.
+ */
+ public IntRect getViewport(ConstView view);
+
+ /**
+ * Converts a point from target coordinates to world coordinates using the target's
+ * current view.
+ *
+ * @param point the point on the render target.
+ * @return the matching point in the world.
+ */
+ public Vector2f mapPixelToCoords(Vector2i point);
+
+ /**
+ * Converts a point from target coordinates to world coordinates for a certain view.
+ *
+ * @param point the point on the render target.
+ * @param view the view to use for conversion.
+ * @return the matching point in the world.
+ */
+ public Vector2f mapPixelToCoords(Vector2i point, ConstView view);
+
+ /**
+ * Converts a point from world coordinates to target coordinates using the target's
+ * current view.
+ *
+ * @param point the point in the world.
+ * @return the matching point on the render target.
+ */
+ public Vector2i mapCoordsToPixel(Vector2f point);
+
+ /**
+ * Converts a point from world coordinates to target coordinates for a certain view.
+ *
+ * @param point the point in the world.
+ * @param view the view to use for conversion.
+ * @return the matching point on the render target.
+ */
+ public Vector2i mapCoordsToPixel(Vector2f point, ConstView view);
+
+ /**
+ * Draws a drawable object to the render target using the default render states.
+ *
+ * @param drawable the object to draw.
+ */
+ public void draw(Drawable drawable);
+
+ /**
+ * Draws a drawable object to the render target using the given render states.
+ *
+ * @param drawable the object to draw.
+ * @param renderStates the render states to use for drawing.
+ */
+ public void draw(Drawable drawable, RenderStates renderStates);
+
+ /**
+ * Draws a primitive of the given type using the given vertices and the default render states.
+ *
+ * @param vertices the vertices to draw.
+ * @param type the type of OpenGL primitive to draw.
+ */
+ public void draw(Vertex[] vertices, PrimitiveType type);
+
+ /**
+ * Draws a primitive of the given type using the given vertices and the given render states.
+ *
+ * @param vertices the vertices to draw.
+ * @param type the type of OpenGL primitive to draw.
+ * @param states the render states to use for drawing.
+ */
+ public void draw(Vertex[] vertices, PrimitiveType type, RenderStates states);
+
+ /**
+ * Gets the size of the render region.
+ *
+ * @return the size of the render region.
+ */
+ public Vector2i getSize();
+
+ /**
+ * Pushes the current OpenGL states and matrices to the stack.
+ */
+ public void pushGLStates();
+
+ /**
+ * Pops the last OpenGL states and matrices from the top of the stack.
+ */
+ public void popGLStates();
+
+ /**
+ * Resets the internal OpenGL states so that the target is ready for drawing.
+ */
+ public void resetGLStates();
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/RenderTexture.java b/lib/jsfml/src/java/org/jsfml/graphics/RenderTexture.java
new file mode 100644
index 00000000..ca6bad8e
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/RenderTexture.java
@@ -0,0 +1,256 @@
+package org.jsfml.graphics;
+
+import org.jsfml.internal.IntercomHelper;
+import org.jsfml.internal.SFMLErrorCapture;
+import org.jsfml.internal.SFMLNative;
+import org.jsfml.internal.SFMLNativeObject;
+import org.jsfml.system.Vector2f;
+import org.jsfml.system.Vector2i;
+
+import java.util.Objects;
+
+/**
+ * Provides a render target for off-screen 2D rendering into a texture.
+ */
+public class RenderTexture extends SFMLNativeObject implements RenderTarget {
+ private Vector2i size = Vector2i.ZERO;
+
+ private ConstView defaultView;
+ private ConstView view;
+ private final Texture texture;
+
+ /**
+ * Constructs a new render texture.
+ */
+ public RenderTexture() {
+ super();
+ SFMLNative.ensureDisplay();
+
+ texture = new Texture(nativeGetTexture());
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native long nativeCreate();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeSetExPtr();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeDelete();
+
+ private native boolean nativeCreateTexture(int width, int height, boolean depthBuffer);
+
+ /**
+ * Sets up the render texture.
+ *
+ * @param width the texture's width.
+ * @param height the texture's height.
+ * @param depthBuffer {@code true} to generate a depth buffer, {@code false} otherwise.
+ * Use this only in case you wish to do 3D rendering to this texture.
+ * @throws TextureCreationException if the render texture could not be created.
+ */
+ public void create(int width, int height, boolean depthBuffer)
+ throws TextureCreationException {
+
+ size = Vector2i.ZERO;
+
+ SFMLErrorCapture.start();
+ final boolean success = nativeCreateTexture(width, height, depthBuffer);
+ final String msg = SFMLErrorCapture.finish();
+
+ if (!success)
+ throw new TextureCreationException(msg);
+
+ defaultView = new View(nativeGetDefaultView());
+
+ if(view == null) {
+ view = defaultView;
+ }
+
+ size = new Vector2i(width, height);
+ }
+
+ /**
+ * Sets up the render texture without a depth buffer.
+ *
+ * @param width the texture's width.
+ * @param height the texture's height.
+ * @throws TextureCreationException if the render texture could not be created.
+ */
+ public final void create(int width, int height) throws TextureCreationException {
+ create(width, height, false);
+ }
+
+ /**
+ * Enables or disables textures smoothing.
+ *
+ * @param smooth {@code true} to enable, {@code false} to disable.
+ */
+ public void setSmooth(boolean smooth) {
+ texture.setSmooth(smooth);
+ }
+
+ /**
+ * Checks whether texture smoothing is enabled.
+ *
+ * @return {@code true} if enabled, {@code false} if not.
+ */
+ public boolean isSmooth() {
+ return texture.isSmooth();
+ }
+
+ /**
+ * Enables or disables texture repeating for the underlying texture.
+ *
+ * Texture repeating is disabled by default.
+ *
+ * @param repeated {@code true} to enable, {@code false} to disable.
+ */
+ public void setRepeated(boolean repeated) {
+ texture.setRepeated(repeated);
+ }
+
+ /**
+ * Checks whether texture repeating is enabled for the underlying texture.
+ *
+ * @return {@code true} if enabled, {@code false} if disabled.
+ */
+ public boolean isRepeated() {
+ return texture.isRepeated();
+ }
+
+ /**
+ * Activates or deactivates the render texture for rendering.
+ *
+ * @param active {@code true} to activate, {@code false} to deactivate.
+ */
+ public native void setActive(boolean active);
+
+ /**
+ * Updates the contents of the target texture.
+ */
+ public native void display();
+
+ private native long nativeGetTexture();
+
+ /**
+ * Gets the target texture.
+ *
+ * @return the target texture.
+ */
+ public ConstTexture getTexture() {
+ return texture;
+ }
+
+ @Override
+ public Vector2i getSize() {
+ return size;
+ }
+
+ private native void nativeClear(int color);
+
+ @Override
+ public void clear(Color color) {
+ nativeClear(IntercomHelper.encodeColor(color));
+ }
+
+ /**
+ * Clears the target with black.
+ */
+ public void clear() {
+ nativeClear(0xFF000000);
+ }
+
+ private native void nativeSetView(View view);
+
+ @Override
+ public void setView(ConstView view) {
+ this.view = Objects.requireNonNull(view);
+ nativeSetView((View) view);
+ }
+
+ @Override
+ public ConstView getView() {
+ return view;
+ }
+
+ private native long nativeGetDefaultView();
+
+ @Override
+ public ConstView getDefaultView() {
+ return defaultView;
+ }
+
+ @Override
+ public IntRect getViewport(ConstView view) {
+ final FloatRect viewport = view.getViewport();
+ final Vector2i size = getSize();
+
+ return new IntRect(
+ (int) (0.5f + viewport.left * size.x),
+ (int) (0.5f + viewport.top * size.y),
+ (int) (viewport.width * size.x),
+ (int) (viewport.height * size.y));
+ }
+
+ private native long nativeMapPixelToCoords(long point, ConstView view);
+
+ @Override
+ public final Vector2f mapPixelToCoords(Vector2i point) {
+ return mapPixelToCoords(point, view);
+ }
+
+ @Override
+ public Vector2f mapPixelToCoords(Vector2i point, ConstView view) {
+ return IntercomHelper.decodeVector2f(
+ nativeMapPixelToCoords(IntercomHelper.encodeVector2i(point), view));
+ }
+
+ private native long nativeMapCoordsToPixel(long point, ConstView view);
+
+ @Override
+ public final Vector2i mapCoordsToPixel(Vector2f point) {
+ return mapCoordsToPixel(point, view);
+ }
+
+ @Override
+ public Vector2i mapCoordsToPixel(Vector2f point, ConstView view) {
+ return IntercomHelper.decodeVector2i(
+ nativeMapCoordsToPixel(IntercomHelper.encodeVector2f(point), view));
+ }
+
+ @Override
+ public final void draw(Drawable drawable) {
+ draw(drawable, RenderStates.DEFAULT);
+ }
+
+ @Override
+ public void draw(Drawable drawable, RenderStates renderStates) {
+ drawable.draw(this, renderStates);
+ }
+
+ @Override
+ public final void draw(Vertex[] vertices, PrimitiveType type) {
+ draw(vertices, type, RenderStates.DEFAULT);
+ }
+
+ @Override
+ public void draw(Vertex[] vertices, PrimitiveType type, RenderStates states) {
+ SFMLNativeDrawer.drawVertices(vertices, type, this, states);
+ }
+
+ @Override
+ public native void pushGLStates();
+
+ @Override
+ public native void popGLStates();
+
+ @Override
+ public native void resetGLStates();
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/RenderWindow.java b/lib/jsfml/src/java/org/jsfml/graphics/RenderWindow.java
new file mode 100644
index 00000000..3d3a7f69
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/RenderWindow.java
@@ -0,0 +1,219 @@
+package org.jsfml.graphics;
+
+import org.jsfml.internal.IntercomHelper;
+import org.jsfml.internal.UnsafeOperations;
+import org.jsfml.system.Vector2f;
+import org.jsfml.system.Vector2i;
+import org.jsfml.window.ContextSettings;
+import org.jsfml.window.VideoMode;
+import org.jsfml.window.Window;
+
+import java.util.Objects;
+
+/**
+ * Provides a window that can serve as a target for 2D drawing.
+ */
+public class RenderWindow extends Window implements RenderTarget {
+ private ConstView defaultView = null;
+ private ConstView view = null;
+
+ /**
+ * Constructs a new render window without actually creating (opening) it.
+ *
+ * @see RenderWindow#create(org.jsfml.window.VideoMode, String, int, org.jsfml.window.ContextSettings)
+ */
+ public RenderWindow() {
+ super();
+ }
+
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ RenderWindow(long ptr) {
+ super(ptr);
+
+ defaultView = new View(nativeGetDefaultView());
+ view = defaultView;
+ }
+
+ /**
+ * Constructs a new render window and creates it with the specified parameters.
+ *
+ * @param mode the video mode to use for rendering.
+ * @param title the window title.
+ * @param style the window style.
+ * @param settings the settings for the OpenGL context.
+ * @see #create(org.jsfml.window.VideoMode, String, int, org.jsfml.window.ContextSettings)
+ */
+ public RenderWindow(VideoMode mode, String title, int style, ContextSettings settings) {
+ this();
+ create(mode, title, style, settings);
+ }
+
+ /**
+ * Constructs a new render window and creates it with default context settings.
+ *
+ * @param mode the video mode to use for rendering.
+ * @param title the window title.
+ * @param style the window style.
+ * @see #create(org.jsfml.window.VideoMode, String, int)
+ */
+ public RenderWindow(VideoMode mode, String title, int style) {
+ this();
+ create(mode, title, style, new ContextSettings());
+ }
+
+ /**
+ * Constructs a new render window and creates it with default style and context settings.
+ *
+ * @param mode The video mode to use for rendering.
+ * @param title The window title.
+ */
+ public RenderWindow(VideoMode mode, String title) {
+ this();
+ create(mode, title, DEFAULT, new ContextSettings());
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native long nativeCreate();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeSetExPtr();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeDelete();
+
+ @Override
+ public void create(VideoMode mode, String title, int style, ContextSettings settings) {
+ super.create(mode, title, style, settings);
+
+ defaultView = new View(nativeGetDefaultView());
+
+ if (view == null) {
+ view = defaultView;
+ }
+ }
+
+ private native long nativeCapture();
+
+ /**
+ * Copies the current contents of the window to an image.
+ *
+ * This is a slow operation and should be used to take screenshots, not to re-use
+ * resulting image as a texture. For that, use {@link Texture#update(org.jsfml.window.Window)}
+ * or a {@link RenderTexture} instead.
+ *
+ * @return the image with the current contents of the window.
+ */
+ public Image capture() {
+ final Image image = new Image(nativeCapture());
+ UnsafeOperations.manageSFMLObject(image, true);
+ return image;
+ }
+
+ private native void nativeClear(int color);
+
+ @Override
+ public void clear(Color color) {
+ nativeClear(IntercomHelper.encodeColor(color));
+ }
+
+ /**
+ * Clears the target with black.
+ */
+ public void clear() {
+ nativeClear(0xFF000000);
+ }
+
+ private native void nativeSetView(View view);
+
+ @Override
+ public void setView(ConstView view) {
+ this.view = Objects.requireNonNull(view);
+ nativeSetView((View) view);
+ }
+
+ @Override
+ public ConstView getView() {
+ return view;
+ }
+
+ private native long nativeGetDefaultView();
+
+ @Override
+ public ConstView getDefaultView() {
+ return defaultView;
+ }
+
+ @Override
+ public IntRect getViewport(ConstView view) {
+ final FloatRect viewport = view.getViewport();
+ final Vector2i size = getSize();
+
+ return new IntRect(
+ (int) (0.5f + viewport.left * size.x),
+ (int) (0.5f + viewport.top * size.y),
+ (int) (viewport.width * size.x),
+ (int) (viewport.height * size.y));
+ }
+
+ private native long nativeMapPixelToCoords(long point, ConstView view);
+
+ @Override
+ public final Vector2f mapPixelToCoords(Vector2i point) {
+ return mapPixelToCoords(point, view);
+ }
+
+ @Override
+ public Vector2f mapPixelToCoords(Vector2i point, ConstView view) {
+ return IntercomHelper.decodeVector2f(
+ nativeMapPixelToCoords(IntercomHelper.encodeVector2i(point), view));
+ }
+
+ private native long nativeMapCoordsToPixel(long point, ConstView view);
+
+ @Override
+ public final Vector2i mapCoordsToPixel(Vector2f point) {
+ return mapCoordsToPixel(point, view);
+ }
+
+ @Override
+ public Vector2i mapCoordsToPixel(Vector2f point, ConstView view) {
+ return IntercomHelper.decodeVector2i(
+ nativeMapCoordsToPixel(IntercomHelper.encodeVector2f(point), view));
+ }
+
+ @Override
+ public final void draw(Drawable drawable) {
+ draw(drawable, RenderStates.DEFAULT);
+ }
+
+ @Override
+ public void draw(Drawable drawable, RenderStates renderStates) {
+ drawable.draw(this, renderStates);
+ }
+
+ @Override
+ public final void draw(Vertex[] vertices, PrimitiveType type) {
+ draw(vertices, type, RenderStates.DEFAULT);
+ }
+
+ @Override
+ public void draw(Vertex[] vertices, PrimitiveType type, RenderStates states) {
+ SFMLNativeDrawer.drawVertices(vertices, type, this, states);
+ }
+
+ @Override
+ public native void pushGLStates();
+
+ @Override
+ public native void popGLStates();
+
+ @Override
+ public native void resetGLStates();
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/SFMLNativeDrawer.java b/lib/jsfml/src/java/org/jsfml/graphics/SFMLNativeDrawer.java
new file mode 100644
index 00000000..a7a35a17
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/SFMLNativeDrawer.java
@@ -0,0 +1,78 @@
+package org.jsfml.graphics;
+
+import org.jsfml.internal.IntercomHelper;
+
+import java.nio.*;
+
+/**
+ * Provides generic implementations of the {@code draw} methods for
+ * native SFML drawables and vertices.
+ */
+final class SFMLNativeDrawer {
+ private static final int NATIVE_VERTEX_SIZE = 20;
+ private static final int MAX_VERTICES = 1024;
+
+ private static final ThreadLocal vertexBuffer = new ThreadLocal() {
+ @Override
+ protected ByteBuffer initialValue() {
+ return ByteBuffer.allocateDirect(MAX_VERTICES * NATIVE_VERTEX_SIZE).order(ByteOrder.nativeOrder());
+ }
+ };
+
+ private static native void nativeDrawVertices(
+ int num,
+ Buffer vbuf,
+ int type,
+ RenderTarget target,
+ int blendMode,
+ Buffer xform,
+ ConstTexture texture,
+ ConstShader shader);
+
+ static void drawVertices(Vertex[] vertices, PrimitiveType type, RenderTarget target, RenderStates states) {
+ final ByteBuffer vbuf = vertexBuffer.get();
+ final FloatBuffer vfloats = vbuf.asFloatBuffer();
+ final IntBuffer vints = vbuf.asIntBuffer();
+
+ final int sz = NATIVE_VERTEX_SIZE / 4;
+ for (int i = 0; i < vertices.length; i++) {
+ final Vertex v = vertices[i];
+ final int x = i * sz;
+
+ //keep away from children!
+ vfloats.put(x, v.position.x);
+ vfloats.put(x + 1, v.position.y);
+ vints.put(x + 2, IntercomHelper.encodeColor(v.color));
+ vfloats.put(x + 3, v.texCoords.x);
+ vfloats.put(x + 4, v.texCoords.y);
+ }
+
+ nativeDrawVertices(
+ vertices.length,
+ vbuf,
+ type.ordinal(),
+ target,
+ states.blendMode.ordinal(),
+ IntercomHelper.encodeTransform(states.transform),
+ states.texture,
+ states.shader);
+ }
+
+ private static native void nativeDrawDrawable(
+ Drawable drawable,
+ RenderTarget target,
+ int blendMode,
+ Buffer xform,
+ ConstTexture texture,
+ ConstShader shader);
+
+ static void draw(Drawable drawable, RenderTarget target, RenderStates states) {
+ nativeDrawDrawable(
+ drawable,
+ target,
+ states.blendMode.ordinal(),
+ IntercomHelper.encodeTransform(states.transform),
+ states.texture,
+ states.shader);
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/SFMLNativeTransformable.java b/lib/jsfml/src/java/org/jsfml/graphics/SFMLNativeTransformable.java
new file mode 100644
index 00000000..99e62035
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/SFMLNativeTransformable.java
@@ -0,0 +1,152 @@
+package org.jsfml.graphics;
+
+import org.jsfml.internal.IntercomHelper;
+import org.jsfml.internal.SFMLNativeObject;
+import org.jsfml.system.Vector2f;
+
+import java.nio.Buffer;
+import java.util.Objects;
+
+/**
+ * Decomposed transform defined by a position, a rotation and a scale.
+ */
+abstract class SFMLNativeTransformable extends SFMLNativeObject implements Transformable {
+ //cache
+ private Vector2f position = Vector2f.ZERO;
+ private float rotation = 0;
+ private Vector2f scale = new Vector2f(1, 1);
+ private Vector2f origin = Vector2f.ZERO;
+
+ private boolean transformNeedsUpdate = true;
+ private Transform transformCache = null;
+ private Transform inverseTransformCache = null;
+
+ protected SFMLNativeTransformable() {
+ super();
+ }
+
+ private native void nativeSetPosition(float x, float y);
+
+ @Override
+ public final void setPosition(float x, float y) {
+ setPosition(new Vector2f(x, y));
+ }
+
+ @Override
+ public void setPosition(Vector2f v) {
+ position = Objects.requireNonNull(v);
+ nativeSetPosition(v.x, v.y);
+ transformNeedsUpdate = true;
+ }
+
+ private native void nativeSetRotation(float angle);
+
+ @Override
+ public void setRotation(float angle) {
+ rotation = angle;
+ nativeSetRotation(angle);
+ transformNeedsUpdate = true;
+ }
+
+ private native void nativeSetScale(float x, float y);
+
+ @Override
+ public final void setScale(float x, float y) {
+ setScale(new Vector2f(x, y));
+ }
+
+ @Override
+ public void setScale(Vector2f v) {
+ scale = Objects.requireNonNull(v);
+ nativeSetScale(v.x, v.y);
+ transformNeedsUpdate = true;
+ }
+
+ private native void nativeSetOrigin(float x, float y);
+
+ @Override
+ public final void setOrigin(float x, float y) {
+ setOrigin(new Vector2f(x, y));
+ }
+
+ @Override
+ public void setOrigin(Vector2f v) {
+ origin = Objects.requireNonNull(v);
+ nativeSetOrigin(v.x, v.y);
+ transformNeedsUpdate = true;
+ }
+
+ @Override
+ public Vector2f getPosition() {
+ return position;
+ }
+
+ @Override
+ public float getRotation() {
+ return rotation;
+ }
+
+ @Override
+ public Vector2f getScale() {
+ return scale;
+ }
+
+ @Override
+ public Vector2f getOrigin() {
+ return origin;
+ }
+
+ @Override
+ public final void move(float x, float y) {
+ setPosition(new Vector2f(position.x + x, position.y + y));
+ }
+
+ @Override
+ public final void move(Vector2f v) {
+ move(v.x, v.y);
+ }
+
+ @Override
+ public final void rotate(float angle) {
+ setRotation(rotation + angle);
+ }
+
+ @Override
+ public final void scale(float x, float y) {
+ setScale(new Vector2f(scale.x * x, scale.y * y));
+ }
+
+ @Override
+ public final void scale(Vector2f factors) {
+ scale(factors.x, factors.y);
+ }
+
+ private native void nativeGetTransform(Buffer buf);
+
+ private void updateTransform() {
+ if (transformNeedsUpdate) {
+ nativeGetTransform(IntercomHelper.getBuffer());
+ transformCache = IntercomHelper.decodeTransform();
+ inverseTransformCache = transformCache.getInverse();
+ transformNeedsUpdate = false;
+ }
+ }
+
+ @Override
+ public Transform getTransform() {
+ if (transformNeedsUpdate) {
+ updateTransform();
+ }
+
+ return transformCache;
+ }
+
+ @Override
+ public Transform getInverseTransform() {
+ if (transformNeedsUpdate) {
+ updateTransform();
+ }
+
+ return inverseTransformCache;
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/Shader.java b/lib/jsfml/src/java/org/jsfml/graphics/Shader.java
new file mode 100644
index 00000000..4323e9d3
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/Shader.java
@@ -0,0 +1,344 @@
+package org.jsfml.graphics;
+
+import org.jsfml.internal.*;
+import org.jsfml.system.Vector2f;
+import org.jsfml.system.Vector3f;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.Buffer;
+import java.nio.file.Path;
+import java.util.Objects;
+
+/**
+ * Represents a GLSL shader program, consisting of a vertex and a fragment shader.
+ */
+public class Shader extends SFMLNativeObject implements ConstShader {
+ static {
+ SFMLNative.loadNativeLibraries();
+ }
+
+ /**
+ * Special type denoting that the texture of the object being drawn
+ * should be used, which cannot be known before it is actually being drawn.
+ *
+ * @see Shader#setParameter(String, org.jsfml.graphics.Shader.CurrentTextureType)
+ */
+ public static final class CurrentTextureType {
+ private CurrentTextureType() {
+ //cannot instantiate from outside.
+ }
+ }
+
+ /**
+ * Special value denoting that the texture of the object being drawn
+ * should be used, which cannot be known before it is actually being drawn.
+ *
+ * @see Shader#setParameter(String, org.jsfml.graphics.Shader.CurrentTextureType)
+ */
+ public static final CurrentTextureType CURRENT_TEXTURE = new CurrentTextureType();
+
+ /**
+ * Activates a shader for rendering.
+ *
+ * This is required only if you wish to use JSFML shaders in custom OpenGL code.
+ *
+ * @param shader the shader to activate, or {@code null} to indicate that no shader
+ * is to be used.
+ */
+ public static native void bind(ConstShader shader);
+
+ /**
+ * Checks if shaders are available on this system.
+ *
+ * @return {@code true} if shaders are available, {@code false} otherwise.
+ */
+ public static native boolean isAvailable();
+
+ /**
+ * Enumeration of shader types.
+ */
+ public static enum Type {
+ /**
+ * Vertex shaders.
+ */
+ VERTEX,
+
+ /**
+ * Fragment shaders.
+ */
+ FRAGMENT
+ }
+
+ /**
+ * Constructs a new shader.
+ */
+ public Shader() {
+ super();
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native long nativeCreate();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected void nativeSetExPtr() {
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeDelete();
+
+ private native boolean nativeLoadFromSource1(String source, int shaderType);
+
+ private native boolean nativeLoadFromSource2(String vertSource, String fragSource);
+
+ private void throwException(String msg) throws IOException, ShaderSourceException {
+ if (msg.startsWith("Failed to compile") || msg.startsWith("Failed to link")) {
+ throw new ShaderSourceException(msg);
+ } else {
+ throw new IOException(msg);
+ }
+ }
+
+ /**
+ * Attempts to load a shader from GLSL source code.
+ *
+ * @param source the GLSL source code.
+ * @param shaderType the shader type.
+ * @throws IOException in case an I/O error occurs.
+ * @throws ShaderSourceException in case the shader could not be compiled or linked.
+ */
+ public void loadFromSource(String source, Type shaderType)
+ throws IOException, ShaderSourceException {
+
+ SFMLErrorCapture.start();
+ final boolean result = nativeLoadFromSource1(
+ Objects.requireNonNull(source), shaderType.ordinal());
+
+ final String msg = SFMLErrorCapture.finish();
+
+ if (!result) {
+ throwException(msg);
+ }
+ }
+
+ /**
+ * Attempts to load a shader from GLSL source code.
+ *
+ * @param vertexShaderSource the vertex shader's GLSL source code.
+ * @param fragmentShaderSource the fragment shader's GLSL source code.
+ * @throws IOException in case an I/O error occurs.
+ * @throws ShaderSourceException in case the shader could not be compiled or linked.
+ */
+ public void loadFromSource(String vertexShaderSource, String fragmentShaderSource)
+ throws IOException, ShaderSourceException {
+
+ SFMLErrorCapture.start();
+ final boolean result = nativeLoadFromSource2(
+ Objects.requireNonNull(vertexShaderSource),
+ Objects.requireNonNull(fragmentShaderSource));
+
+ final String msg = SFMLErrorCapture.finish();
+
+ if (!result) {
+ throwException(msg);
+ }
+ }
+
+ /**
+ * Fully loads all available bytes from an {@link InputStream}
+ * and attempts to load the shader from it.
+ *
+ * @param in the input stream to read from.
+ * @param shaderType the shader type.
+ * @throws IOException in case an I/O error occurs.
+ * @throws ShaderSourceException in case the shader could not be compiled or linked.
+ */
+ public void loadFromStream(InputStream in, Type shaderType)
+ throws IOException, ShaderSourceException {
+
+ loadFromSource(new String(StreamUtil.readStream(in)), Objects.requireNonNull(shaderType));
+ }
+
+ /**
+ * Fully loads all available bytes from an {@link InputStream}
+ * and attempts to load the shader from it.
+ *
+ * @param vertexShaderIn the input stream to read the vertex shader from.
+ * @param fragmentShaderIn the input stream to read the fragment shader from.
+ * @throws IOException in case an I/O error occurs.
+ * @throws ShaderSourceException in case the shader could not be compiled or linked.
+ */
+ public void loadFromStream(InputStream vertexShaderIn, InputStream fragmentShaderIn)
+ throws IOException, ShaderSourceException {
+
+ loadFromSource(
+ new String(StreamUtil.readStream(vertexShaderIn)),
+ new String(StreamUtil.readStream(fragmentShaderIn)));
+ }
+
+ /**
+ * Attempts to load the shader from a file.
+ *
+ * @param path the path to the file to load.
+ * @param shaderType the shader type.
+ * @throws IOException in case an I/O error occurs.
+ * @throws ShaderSourceException in case the shader could not be compiled or linked.
+ */
+ public void loadFromFile(Path path, Type shaderType)
+ throws IOException, ShaderSourceException {
+
+ loadFromSource(new String(StreamUtil.readFile(path)), Objects.requireNonNull(shaderType));
+ }
+
+ /**
+ * Attempts to load the shader from files.
+ *
+ * @param vertexShaderFile the path to the file to read the vertex shader from.
+ * @param fragmentShaderFile the path to the file to read the fragment shader from.
+ * @throws IOException in case an I/O error occurs.
+ * @throws ShaderSourceException in case the shader could not be compiled or linked.
+ */
+ public void loadFromFile(Path vertexShaderFile, Path fragmentShaderFile)
+ throws IOException, ShaderSourceException {
+
+ loadFromSource(
+ new String(StreamUtil.readFile(vertexShaderFile)),
+ new String(StreamUtil.readFile(fragmentShaderFile)));
+ }
+
+ private native void nativeSetParameterFloat(String name, float x);
+
+ /**
+ * Sets a float parameter ({@code float}) value in the shader.
+ *
+ * @param name the parameter's name.
+ * @param value the parameter's value.
+ */
+ public void setParameter(String name, float value) {
+ nativeSetParameterFloat(Objects.requireNonNull(name), value);
+ }
+
+ private native void nativeSetParameterVec2(String name, float x, float y);
+
+ /**
+ * Sets a 2-component-float ({@code vec2}) parameter value in the shader.
+ *
+ * @param name the parameter's name.
+ * @param x the parameter's value.
+ * @param y the parameter's value.
+ */
+ public void setParameter(String name, float x, float y) {
+ nativeSetParameterVec2(Objects.requireNonNull(name), x, y);
+ }
+
+ /**
+ * Sets a 2-component-float ({@code vec2}) parameter value in the shader.
+ *
+ * @param name the parameter's name.
+ * @param v the parameter's value.
+ */
+ public void setParameter(String name, Vector2f v) {
+ setParameter(name, v.x, v.y);
+ }
+
+ private native void nativeSetParameterVec3(String name, float x, float y, float z);
+
+ /**
+ * Sets a 3-component-float ({@code vec3}) parameter value in the shader.
+ *
+ * @param name the parameter's name.
+ * @param x the parameter's value.
+ * @param y the parameter's value.
+ * @param z the parameter's value.
+ */
+ public void setParameter(String name, float x, float y, float z) {
+ nativeSetParameterVec3(Objects.requireNonNull(name), x, y, z);
+ }
+
+ /**
+ * Sets a 3-component-float ({@code vec3}) parameter value in the shader.
+ *
+ * @param name the parameter's name.
+ * @param v the parameter's value.
+ */
+ public void setParameter(String name, Vector3f v) {
+ setParameter(name, v.x, v.y, v.z);
+ }
+
+ private native void nativeSetParameterVec4(String name, float x, float y, float z, float w);
+
+ /**
+ * Sets a 4-component-float ({@code vec4}) parameter value in the shader.
+ *
+ * @param name the parameter's name.
+ * @param x the parameter's value.
+ * @param y the parameter's value.
+ * @param z the parameter's value.
+ * @param w the parameter's value.
+ */
+ public void setParameter(String name, float x, float y, float z, float w) {
+ nativeSetParameterVec4(Objects.requireNonNull(name), x, y, z, w);
+ }
+
+ /**
+ * Sets a color (vec4) parameter value in the shader.
+ *
+ * @param name the parameter's name.
+ * @param color the parameter's value.
+ */
+ public void setParameter(String name, Color color) {
+ setParameter(name,
+ (float) color.r / 255.0f,
+ (float) color.g / 255.0f,
+ (float) color.b / 255.0f,
+ (float) color.a / 255.0f);
+ }
+
+ private native void nativeSetParameterMat4(String name, Buffer xform);
+
+ /**
+ * Sets a matrix (mat4) parameter value in the shader.
+ *
+ * @param name the parameter's name.
+ * @param xform the parameter's value.
+ */
+ public void setParameter(String name, Transform xform) {
+ nativeSetParameterMat4(
+ Objects.requireNonNull(name),
+ IntercomHelper.encodeTransform(xform));
+ }
+
+ private native void nativeSetParameterSampler2d(String name, Texture texture);
+
+ /**
+ * Sets a texture (sampler2D) parameter value in the shader.
+ *
+ * @param name the parameter's name.
+ * @param texture the parameter's value.
+ */
+ public void setParameter(String name, ConstTexture texture) {
+ nativeSetParameterSampler2d(Objects.requireNonNull(name), (Texture) Objects.requireNonNull(texture));
+ }
+
+ private native void nativeSetParameterCurrentTexture(String name);
+
+ /**
+ * Sets a texture (sampler2D) parameter value in the shader to the texture
+ * of the object being drawn in the moment the shader is applied.
+ *
+ * Since that texture cannot be known before the object is actually being drawn,
+ * this overload can be used to tell the shader to use it when applied.
+ *
+ * @param name the parameter's name.
+ * @param currentTexture should be {@link Shader#CURRENT_TEXTURE}.
+ */
+ public void setParameter(String name, CurrentTextureType currentTexture) {
+ nativeSetParameterCurrentTexture(Objects.requireNonNull(name));
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/ShaderSourceException.java b/lib/jsfml/src/java/org/jsfml/graphics/ShaderSourceException.java
new file mode 100644
index 00000000..82c5ba6a
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/ShaderSourceException.java
@@ -0,0 +1,17 @@
+package org.jsfml.graphics;
+
+/**
+ * Thrown if a vertex or fragment shader source could not be compiled or linked.
+ */
+public class ShaderSourceException extends Exception {
+ private static final long serialVersionUID = -6514888818053624276L;
+
+ /**
+ * Constructs a shader compilation exception with the specified message.
+ *
+ * @param msg the error message.
+ */
+ public ShaderSourceException(String msg) {
+ super(msg);
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/Shape.java b/lib/jsfml/src/java/org/jsfml/graphics/Shape.java
new file mode 100644
index 00000000..0e417720
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/Shape.java
@@ -0,0 +1,302 @@
+package org.jsfml.graphics;
+
+import org.jsfml.internal.IntercomHelper;
+import org.jsfml.system.Vector2f;
+
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.util.Objects;
+
+/**
+ * Abstract base class for (optionally) textured shapes with (optional) outlines.
+ */
+public abstract class Shape extends SFMLNativeTransformable implements Drawable {
+ //cache
+ private Color fillColor = Color.WHITE;
+ private Color outlineColor = Color.WHITE;
+ private float outlineThickness = 0;
+ private IntRect textureRect = IntRect.EMPTY;
+ private ConstTexture texture = null;
+
+ protected boolean pointsNeedUpdate = true;
+ protected Vector2f[] points = null;
+
+ private boolean boundsNeedUpdate = true;
+ private FloatRect localBounds = null;
+ private FloatRect globalBounds = null;
+
+ /**
+ * Default constructor.
+ */
+ public Shape() {
+ super();
+ }
+
+ private native void nativeSetTexture(Texture texture, boolean resetRect);
+
+ /**
+ * Sets the texture of the shape.
+ *
+ * The texture may be {@code null} if no texture is to be used.
+ *
+ * @param texture the texture of the shape, or {@code null} to indicate that no texture
+ * is to be used.
+ * @param resetRect {@code true} to reset the texture rect, {@code false} otherwise.
+ */
+ public void setTexture(ConstTexture texture, boolean resetRect) {
+ this.texture = texture;
+ nativeSetTexture((Texture) texture, resetRect);
+ }
+
+ /**
+ * Sets the texture of the shape without affecting the texture rectangle.
+ *
+ * The texture may be {@code null} if no texture is to be used.
+ *
+ * @param texture the texture of the shape, or {@code null} to indicate that no texture
+ * is to be used.
+ */
+ public final void setTexture(ConstTexture texture) {
+ setTexture(texture, false);
+ }
+
+ private native void nativeSetTextureRect(Buffer buffer);
+
+ /**
+ * Sets the portion of the texture that will be used for drawing.
+ *
+ * An empty rectangle can be passed to indicate that the whole texture shall be used.
+ *
+ * The width and / or height of the rectangle may be negative to indicate that the
+ * respective axis should be flipped. For example, a width of {@code -32} will
+ * result in a sprite that is 32 pixels wide and flipped horizontally.
+ *
+ * @param rect the texture portion.
+ */
+ public void setTextureRect(IntRect rect) {
+ nativeSetTextureRect(IntercomHelper.encodeIntRect(rect));
+ this.textureRect = rect;
+ }
+
+ private native void nativeSetFillColor(int color);
+
+ /**
+ * Sets the fill color of the shape.
+ *
+ * @param color the new fill color of the shape, or {@link Color#TRANSPARENT} to indicate
+ * that the shape should not be filled.
+ */
+ public void setFillColor(Color color) {
+ nativeSetFillColor(IntercomHelper.encodeColor(color));
+ this.fillColor = color;
+ }
+
+ private native void nativeSetOutlineColor(int color);
+
+ /**
+ * Sets the outline color of the shape.
+ *
+ * @param color the new outline color of the shape.
+ */
+ public void setOutlineColor(Color color) {
+ nativeSetOutlineColor(IntercomHelper.encodeColor(color));
+ this.outlineColor = color;
+ }
+
+ private native void nativeSetOutlineThickness(float thickness);
+
+ /**
+ * Sets the thickness of the shape's outline.
+ *
+ * @param thickness the thickness of the shape's outline, or 0 to indicate that no
+ * outline should be drawn.
+ */
+ public void setOutlineThickness(float thickness) {
+ nativeSetOutlineThickness(thickness);
+ this.outlineThickness = thickness;
+ }
+
+ /**
+ * Gets the shape's current texture.
+ *
+ * @return the shape's current texture.
+ */
+ public ConstTexture getTexture() {
+ return texture;
+ }
+
+ /**
+ * Gets the shape's current texture portion.
+ *
+ * @return the shape's current texture portion.
+ */
+ public IntRect getTextureRect() {
+ return textureRect;
+ }
+
+ /**
+ * Gets the shape's current fill color.
+ *
+ * @return the shape's current fill color.
+ */
+ public Color getFillColor() {
+ return fillColor;
+ }
+
+ /**
+ * Gets the shape's current outline color.
+ *
+ * @return the shape's current outline color.
+ */
+ public Color getOutlineColor() {
+ return outlineColor;
+ }
+
+ /**
+ * Gets the shape's current outline thickness.
+ *
+ * @return the shape's current outline thickness.
+ */
+ public float getOutlineThickness() {
+ return outlineThickness;
+ }
+
+ private native int nativeGetPointCount();
+
+ private native void nativeGetPoints(int n, Buffer buffer);
+
+ private void updatePoints() {
+ if (pointsNeedUpdate) {
+ final int n = nativeGetPointCount();
+ final FloatBuffer buffer = ByteBuffer.allocateDirect(2 * n * 4).order(
+ ByteOrder.nativeOrder()).asFloatBuffer();
+
+ nativeGetPoints(n, buffer);
+ points = new Vector2f[n];
+ for (int i = 0; i < n; i++) {
+ points[i] = new Vector2f(buffer.get(2 * i), buffer.get(2 * i + 1));
+ }
+
+ pointsNeedUpdate = false;
+ }
+ }
+
+ /**
+ * Gets the amount of points that defines this shape.
+ *
+ * @return the amount of points that defines this shape.
+ */
+ public int getPointCount() {
+ if (pointsNeedUpdate) {
+ updatePoints();
+ }
+
+ return points.length;
+ }
+
+ /**
+ * Gets a point of the shape.
+ *
+ * @param i the index of the point to retrieve.
+ * @return the point at the given index.
+ */
+ public Vector2f getPoint(int i) {
+ if (pointsNeedUpdate) {
+ updatePoints();
+ }
+
+ return points[i];
+ }
+
+ /**
+ * Gets all the points of the shape.
+ *
+ * @return an array containing the points of the shape.
+ */
+ public Vector2f[] getPoints() {
+ int n = getPointCount();
+ Vector2f[] points = new Vector2f[n];
+
+ System.arraycopy(this.points, 0, points, 0, n);
+ return points;
+ }
+
+ private native void nativeGetLocalBounds(Buffer buf);
+
+ private native void nativeGetGlobalBounds(Buffer buf);
+
+ private void updateBounds() {
+ if(boundsNeedUpdate) {
+ nativeGetLocalBounds(IntercomHelper.getBuffer());
+ localBounds = IntercomHelper.decodeFloatRect();
+
+ nativeGetGlobalBounds(IntercomHelper.getBuffer());
+ globalBounds = IntercomHelper.decodeFloatRect();
+
+ boundsNeedUpdate = false;
+ }
+ }
+
+ /**
+ * Gets the text's local bounding rectangle,
+ * not taking the text's transformation into account.
+ *
+ * @return the text's local bounding rectangle.
+ * @see org.jsfml.graphics.Sprite#getGlobalBounds()
+ */
+ public FloatRect getLocalBounds() {
+ if(boundsNeedUpdate) {
+ updateBounds();
+ }
+
+ return localBounds;
+ }
+
+ /**
+ * Gets the text's global bounding rectangle in the scene,
+ * taking the text's transformation into account.
+ *
+ * @return the text's global bounding rectangle.
+ * @see org.jsfml.graphics.Text#getLocalBounds()
+ */
+ public FloatRect getGlobalBounds() {
+ if(boundsNeedUpdate) {
+ updateBounds();
+ }
+
+ return globalBounds;
+ }
+
+ @Override
+ public void setPosition(Vector2f v) {
+ super.setPosition(v);
+ boundsNeedUpdate = true;
+ }
+
+ @Override
+ public void setRotation(float angle) {
+ super.setRotation(angle);
+ boundsNeedUpdate = true;
+ }
+
+ @Override
+ public void setScale(Vector2f v) {
+ super.setScale(v);
+ boundsNeedUpdate = true;
+ }
+
+ @Override
+ public void setOrigin(Vector2f v) {
+ super.setOrigin(v);
+ boundsNeedUpdate = true;
+ }
+
+ @Override
+ public void draw(RenderTarget target, RenderStates states) {
+ SFMLNativeDrawer.draw(this,
+ Objects.requireNonNull(target),
+ Objects.requireNonNull(states));
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/Sprite.java b/lib/jsfml/src/java/org/jsfml/graphics/Sprite.java
new file mode 100644
index 00000000..ce0a2307
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/Sprite.java
@@ -0,0 +1,227 @@
+package org.jsfml.graphics;
+
+import org.jsfml.internal.IntercomHelper;
+import org.jsfml.system.Vector2f;
+
+import java.nio.Buffer;
+import java.util.Objects;
+
+/**
+ * Represents a drawable instance of a texture or texture portion.
+ */
+public class Sprite extends SFMLNativeTransformable implements Drawable {
+ //cache
+ private Color color = Color.WHITE;
+ private IntRect textureRect = IntRect.EMPTY;
+ private ConstTexture texture = null;
+
+ private boolean boundsNeedUpdate = true;
+ private FloatRect localBounds = null;
+ private FloatRect globalBounds = null;
+
+ /**
+ * Constructs a new sprite without a texture.
+ */
+ public Sprite() {
+ super();
+ }
+
+ /**
+ * Constructs a new sprite with the specified texture.
+ *
+ * @param texture the texture.
+ */
+ public Sprite(ConstTexture texture) {
+ this();
+ setTexture(texture);
+ }
+
+ /**
+ * Constructs a new sprite with the specified texture and texture portion.
+ *
+ * @param texture the texture.
+ * @param rect the portion of the texture to use.
+ */
+ public Sprite(ConstTexture texture, IntRect rect) {
+ this(texture);
+ setTextureRect(rect);
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native long nativeCreate();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeSetExPtr();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeDelete();
+
+ private native void nativeSetTexture(Texture texture, boolean resetRect);
+
+ /**
+ * Sets the texture of this sprite.
+ *
+ * @param texture the new texture.
+ * @param resetRect {@code true} to reset the texture rectangle, {@code false} otherwise.
+ */
+ public void setTexture(ConstTexture texture, boolean resetRect) {
+ nativeSetTexture((Texture) Objects.requireNonNull(texture), resetRect);
+ this.texture = texture;
+
+ if(resetRect) {
+ textureRect = IntRect.EMPTY;
+ }
+
+ boundsNeedUpdate = true;
+ }
+
+ /**
+ * Sets the texture of this sprite without affecting the texture rectangle.
+ *
+ * @param texture the new texture.
+ */
+ public final void setTexture(ConstTexture texture) {
+ setTexture(texture, false);
+ }
+
+ private native void nativeSetTextureRect(Buffer rect);
+
+ /**
+ * Sets the portion of the texture that will be used for drawing.
+ *
+ * An empty rectangle can be passed to indicate that the whole texture shall be used.
+ *
+ * The width and / or height of the rectangle may be negative to indicate that the
+ * respective axis should be flipped. For example, a width of {@code -32} will
+ * result in a sprite that is 32 pixels wide and flipped horizontally.
+ *
+ * @param rect the texture portion.
+ */
+ public void setTextureRect(IntRect rect) {
+ this.textureRect = rect;
+ nativeSetTextureRect(IntercomHelper.encodeIntRect(rect));
+ boundsNeedUpdate = true;
+ }
+
+ private native void nativeSetColor(int color);
+
+ /**
+ * Sets the color mask of the sprite.
+ *
+ * @param color the new color.
+ */
+ public void setColor(Color color) {
+ this.color = color;
+ nativeSetColor(IntercomHelper.encodeColor(color));
+ }
+
+ /**
+ * Gets the sprite's current texture.
+ *
+ * @return the sprite's current texture.
+ */
+ public ConstTexture getTexture() {
+ return texture;
+ }
+
+ /**
+ * Gets the sprite's current texture rectangle.
+ *
+ * @return the sprite's current texture rectangle.
+ */
+ public IntRect getTextureRect() {
+ return textureRect;
+ }
+
+ /**
+ * Gets the sprite's current color mask.
+ *
+ * @return the sprite's current color mask.
+ */
+ public Color getColor() {
+ return color;
+ }
+
+ private native void nativeGetLocalBounds(Buffer buf);
+
+ private native void nativeGetGlobalBounds(Buffer buf);
+
+ private void updateBounds() {
+ if(boundsNeedUpdate) {
+ nativeGetLocalBounds(IntercomHelper.getBuffer());
+ localBounds = IntercomHelper.decodeFloatRect();
+
+ nativeGetGlobalBounds(IntercomHelper.getBuffer());
+ globalBounds = IntercomHelper.decodeFloatRect();
+
+ boundsNeedUpdate = false;
+ }
+ }
+
+ /**
+ * Gets the sprite's local bounding rectangle,
+ * not taking the sprite's transformation into account.
+ *
+ * @return the sprite's local bounding rectangle.
+ * @see org.jsfml.graphics.Sprite#getGlobalBounds()
+ */
+ public FloatRect getLocalBounds() {
+ if(boundsNeedUpdate) {
+ updateBounds();
+ }
+
+ return localBounds;
+ }
+
+ /**
+ * Gets the sprite's global bounding rectangle in the scene,
+ * taking the sprite's transformation into account.
+ *
+ * @return the sprite's global bounding rectangle.
+ * @see org.jsfml.graphics.Sprite#getLocalBounds()
+ */
+ public FloatRect getGlobalBounds() {
+ if(boundsNeedUpdate) {
+ updateBounds();
+ }
+
+ return globalBounds;
+ }
+
+ @Override
+ public void setPosition(Vector2f v) {
+ super.setPosition(v);
+ boundsNeedUpdate = true;
+ }
+
+ @Override
+ public void setRotation(float angle) {
+ super.setRotation(angle);
+ boundsNeedUpdate = true;
+ }
+
+ @Override
+ public void setScale(Vector2f v) {
+ super.setScale(v);
+ boundsNeedUpdate = true;
+ }
+
+ @Override
+ public void setOrigin(Vector2f v) {
+ super.setOrigin(v);
+ boundsNeedUpdate = true;
+ }
+
+ @Override
+ public void draw(RenderTarget target, RenderStates states) {
+ SFMLNativeDrawer.draw(this,
+ Objects.requireNonNull(target),
+ Objects.requireNonNull(states));
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/Text.java b/lib/jsfml/src/java/org/jsfml/graphics/Text.java
new file mode 100644
index 00000000..a5896214
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/Text.java
@@ -0,0 +1,278 @@
+package org.jsfml.graphics;
+
+import org.jsfml.internal.IntercomHelper;
+import org.jsfml.system.Vector2f;
+
+import java.nio.Buffer;
+import java.util.Objects;
+
+/**
+ * Represents a graphical text that can be transformed and drawn to a render target.
+ *
+ * This class implements the {@code TextStyle} interface for quick access to the constants
+ * provided by it.
+ */
+public class Text extends SFMLNativeTransformable implements Drawable, TextStyle {
+ private ConstFont font = null;
+ private String string = "";
+ private Color color = Color.WHITE;
+ private int style = TextStyle.REGULAR;
+ private int characterSize = 30;
+
+ private boolean boundsNeedUpdate = true;
+ private FloatRect localBounds = null;
+ private FloatRect globalBounds = null;
+
+ /**
+ * Creates a new empty text.
+ */
+ public Text() {
+ super();
+ }
+
+ /**
+ * Creates a new text.
+ *
+ * @param string The text string.
+ * @param font The font to use.
+ */
+ public Text(String string, ConstFont font) {
+ this();
+ setFont(font);
+ setString(string);
+ }
+
+ /**
+ * Creates a new text.
+ *
+ * @param string The text string.
+ * @param font The font to use.
+ * @param characterSize The font size.
+ */
+ public Text(String string, ConstFont font, int characterSize) {
+ this();
+ setCharacterSize(characterSize);
+ setFont(font);
+ setString(string);
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native long nativeCreate();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeSetExPtr();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeDelete();
+
+ private native void nativeSetString(String string);
+
+ /**
+ * Sets the string to display.
+ *
+ * @param string The string to display.
+ */
+ public void setString(String string) {
+ this.string = Objects.requireNonNull(string);
+ nativeSetString(string);
+ boundsNeedUpdate = true;
+ }
+
+ private native void nativeSetFont(Font font);
+
+ /**
+ * Sets the text's font.
+ *
+ * @param font The text's font.
+ */
+ public void setFont(ConstFont font) {
+ this.font = Objects.requireNonNull(font);
+ nativeSetFont((Font) font);
+ boundsNeedUpdate = true;
+ }
+
+ private native void nativeSetCharacterSize(int characterSize);
+
+ /**
+ * Sets the font size for this text.
+ *
+ * @param characterSize The font size for this text.
+ */
+ public void setCharacterSize(int characterSize) {
+ nativeSetCharacterSize(characterSize);
+ this.characterSize = characterSize;
+ boundsNeedUpdate = true;
+ }
+
+ private native void nativeSetStyle(int style);
+
+ /**
+ * Sets the font drawing style.
+ *
+ * @param style The font drawing style. This should be an combination ({@code OR})
+ * of the style flags {@link TextStyle#BOLD}, {@link TextStyle#ITALIC} and
+ * {@link TextStyle#UNDERLINED}, or {@link TextStyle#REGULAR} for the
+ * regular style.
+ */
+ public void setStyle(int style) {
+ nativeSetStyle(style);
+ this.style = style;
+ boundsNeedUpdate = true;
+ }
+
+ private native void nativeSetColor(int color);
+
+ /**
+ * Sets the font color for this text.
+ *
+ * @param color The font color for this text.
+ */
+ public void setColor(Color color) {
+ nativeSetColor(IntercomHelper.encodeColor(color));
+ this.color = color;
+ }
+
+ /**
+ * Gets the text's string.
+ *
+ * @return The text strng.
+ */
+ public String getString() {
+ return string;
+ }
+
+ /**
+ * Gets the text's current font.
+ *
+ * @return The text's current font. This may be {@code null} if no font has been set yet.
+ */
+ public ConstFont getFont() {
+ return font;
+ }
+
+ /**
+ * Gets the text's current font size.
+ *
+ * @return The text's current font size.
+ */
+ public int getCharacterSize() {
+ return characterSize;
+ }
+
+ /**
+ * Gets the text's current font style.
+ *
+ * @return The text's current font style.
+ * @see Text#setStyle(int)
+ */
+ public int getStyle() {
+ return style;
+ }
+
+ /**
+ * Gets the text's current font color.
+ *
+ * @return The text's current font color.
+ */
+ public Color getColor() {
+ return color;
+ }
+
+ private native long nativeFindCharacterPos(int i);
+
+ /**
+ * Returns the position of a character inside the string.
+ *
+ * @param i The index of the character to return the position for.
+ * @return The position of the character at the given index.
+ */
+ public Vector2f findCharacterPos(int i) {
+ if (i < 0 || i >= string.length())
+ throw new StringIndexOutOfBoundsException(Integer.toString(i));
+
+ return IntercomHelper.decodeVector2f(nativeFindCharacterPos(i));
+ }
+
+ private native void nativeGetLocalBounds(Buffer buf);
+
+ private native void nativeGetGlobalBounds(Buffer buf);
+
+ private void updateBounds() {
+ if(boundsNeedUpdate) {
+ nativeGetLocalBounds(IntercomHelper.getBuffer());
+ localBounds = IntercomHelper.decodeFloatRect();
+
+ nativeGetGlobalBounds(IntercomHelper.getBuffer());
+ globalBounds = IntercomHelper.decodeFloatRect();
+
+ boundsNeedUpdate = false;
+ }
+ }
+
+ /**
+ * Gets the text's local bounding rectangle,
+ * not taking the text's transformation into account.
+ *
+ * @return the text's local bounding rectangle.
+ * @see org.jsfml.graphics.Sprite#getGlobalBounds()
+ */
+ public FloatRect getLocalBounds() {
+ if(boundsNeedUpdate) {
+ updateBounds();
+ }
+
+ return localBounds;
+ }
+
+ /**
+ * Gets the text's global bounding rectangle in the scene,
+ * taking the text's transformation into account.
+ *
+ * @return the text's global bounding rectangle.
+ * @see org.jsfml.graphics.Text#getLocalBounds()
+ */
+ public FloatRect getGlobalBounds() {
+ if(boundsNeedUpdate) {
+ updateBounds();
+ }
+
+ return globalBounds;
+ }
+
+ @Override
+ public void setPosition(Vector2f v) {
+ super.setPosition(v);
+ boundsNeedUpdate = true;
+ }
+
+ @Override
+ public void setRotation(float angle) {
+ super.setRotation(angle);
+ boundsNeedUpdate = true;
+ }
+
+ @Override
+ public void setScale(Vector2f v) {
+ super.setScale(v);
+ boundsNeedUpdate = true;
+ }
+
+ @Override
+ public void setOrigin(Vector2f v) {
+ super.setOrigin(v);
+ boundsNeedUpdate = true;
+ }
+
+ @Override
+ public void draw(RenderTarget target, RenderStates states) {
+ SFMLNativeDrawer.draw(this,
+ Objects.requireNonNull(target),
+ Objects.requireNonNull(states));
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/TextStyle.java b/lib/jsfml/src/java/org/jsfml/graphics/TextStyle.java
new file mode 100644
index 00000000..8853c607
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/TextStyle.java
@@ -0,0 +1,29 @@
+package org.jsfml.graphics;
+
+/**
+ * Provides text style constants.
+ *
+ * These constants can be combined using an arithmetic {@code OR} operation to define
+ * a text style.
+ */
+public interface TextStyle {
+ /**
+ * Regular drawing style.
+ */
+ public static final int REGULAR = 0;
+
+ /**
+ * Bold drawing style.
+ */
+ public static final int BOLD = 0x01;
+
+ /**
+ * Italic drawing style.
+ */
+ public static final int ITALIC = 0x02;
+
+ /**
+ * Underlined drawing style.
+ */
+ public static final int UNDERLINED = 0x04;
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/Texture.java b/lib/jsfml/src/java/org/jsfml/graphics/Texture.java
new file mode 100644
index 00000000..df65da8e
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/Texture.java
@@ -0,0 +1,358 @@
+package org.jsfml.graphics;
+
+import org.jsfml.internal.*;
+import org.jsfml.system.Vector2i;
+import org.jsfml.window.Context;
+import org.jsfml.window.Window;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.Buffer;
+import java.nio.file.Path;
+import java.util.Objects;
+
+/**
+ * Represents a 2D texture stored on the graphics card for rendering.
+ */
+public class Texture extends SFMLNativeObject implements ConstTexture {
+ private static final int maximumSize;
+
+ static {
+ SFMLNative.loadNativeLibraries();
+ maximumSize = nativeGetMaximumSize();
+ }
+
+ private static native int nativeGetMaximumSize();
+
+ /**
+ * Gets the maximum texture size supported by the current hardware.
+ *
+ * @return the maximum texture size supported by the current hardware.
+ */
+ public static int getMaximumSize() {
+ return maximumSize;
+ }
+
+ /**
+ * Enumeation of texture coordinate types that can be used for rendering.
+ */
+ public static enum CoordinateType {
+ /**
+ * Normalized OpenGL coordinates, ranging from 0 to 1.
+ */
+ NORMALIZED,
+
+ /**
+ * Pixel coordinates, ranging from 0 to the respective dimension (width or height).
+ */
+ PIXELS
+ }
+
+ private static native void nativeBind(Texture texture, int coordinateType);
+
+ /**
+ * Activates a texture for rendering with the specified coordinate type.
+ *
+ * This is required only if you wish to use JSFML textures in custom OpenGL code.
+ *
+ * @param texture the texture to bind, or {@code null} to indicate that
+ * no texture is to be used..
+ * @param coordinateType the coordinate type to use.
+ */
+ public static void bind(ConstTexture texture, CoordinateType coordinateType) {
+ nativeBind((Texture) texture, coordinateType.ordinal());
+ }
+
+ /**
+ * Activates a texture for rendering, using the
+ * {@link Texture.CoordinateType#NORMALIZED} coordinate type.
+ */
+ public static void bind(ConstTexture texture) {
+ bind(texture, CoordinateType.NORMALIZED);
+ }
+
+ //cache
+ private Vector2i size = Vector2i.ZERO;
+ private boolean smooth = false;
+ private boolean repeated = false;
+
+ /**
+ * Constructs a new texture.
+ */
+ public Texture() {
+ super();
+ }
+
+ @SuppressWarnings("deprecation")
+ Texture(long wrap) {
+ super(wrap);
+ updateSize();
+ smooth = nativeIsSmooth();
+ repeated = nativeIsRepeated();
+ }
+
+ /**
+ * Constructs a new texture by copying another texture.
+ *
+ * @param other The texture to copy.
+ */
+ @SuppressWarnings("deprecation")
+ public Texture(ConstTexture other) {
+ super(((Texture) other).nativeCopy());
+ UnsafeOperations.manageSFMLObject(this, true);
+ updateSize();
+ smooth = nativeIsSmooth();
+ repeated = nativeIsRepeated();
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native long nativeCreate();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected void nativeSetExPtr() {
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeDelete();
+
+ private native long nativeCopy();
+
+ private native boolean nativeCreate(int width, int height);
+
+ /**
+ * Generates an empty texture with the specified dimensions.
+ *
+ * @param width the texture's width.
+ * @param height the texture's height.
+ * @throws TextureCreationException if the texture could not be created.
+ */
+ public void create(int width, int height) throws TextureCreationException {
+ if (!nativeCreate(width, height)) {
+ throw new TextureCreationException("Failed to create texture.");
+ }
+
+ updateSize();
+ }
+
+ private native boolean nativeLoadFromStream(
+ SFMLInputStream.NativeStreamRef stm, Buffer area);
+
+ /**
+ * Fully loads all available bytes from an {@link InputStream}
+ * and attempts to load the texture portion from it.
+ *
+ * @param in the input stream to read from.
+ * @param area the area of the image to load into the texture.
+ * @throws IOException in case an I/O error occurs.
+ */
+ public void loadFromStream(InputStream in, IntRect area) throws IOException {
+ Context.getContext();
+
+ final SFMLInputStream.NativeStreamRef streamRef =
+ new SFMLInputStream.NativeStreamRef();
+
+ streamRef.initialize(new SFMLInputStream(Objects.requireNonNull(in)));
+
+ SFMLErrorCapture.start();
+ final boolean success = nativeLoadFromStream(
+ streamRef, IntercomHelper.encodeIntRect(area));
+
+ final String msg = SFMLErrorCapture.finish();
+
+ if (!success) {
+ throw new IOException(msg);
+ }
+
+ updateSize();
+ }
+
+ /**
+ * Fully loads all available bytes from an {@link InputStream}
+ * and attempts to load the texture from it.
+ *
+ * @param in the input stream to read from.
+ * @throws IOException in case an I/O error occurs.
+ */
+ public final void loadFromStream(InputStream in) throws IOException {
+ loadFromStream(in, IntRect.EMPTY);
+ }
+
+ private native boolean nativeLoadFromFile(String path, Buffer area);
+
+ /**
+ * Attempts to load the texture from a file.
+ *
+ * @param path the path to the file to load the texture from.
+ * @param area the area of the image to load into the texture.
+ * @throws IOException in case an I/O error occurs.
+ */
+ public void loadFromFile(Path path, IntRect area) throws IOException {
+ Context.getContext();
+
+ SFMLErrorCapture.start();
+
+ final boolean success = nativeLoadFromFile(
+ path.toAbsolutePath().toString(),
+ IntercomHelper.encodeIntRect(area));
+
+ final String msg = SFMLErrorCapture.finish();
+
+ if (!success) {
+ throw new IOException(msg);
+ }
+
+ updateSize();
+ }
+
+ /**
+ * Attempts to load the texture from a file.
+ *
+ * @param path the path to the file to load the texture from.
+ * @throws IOException in case an I/O error occurs.
+ */
+ public final void loadFromFile(Path path) throws IOException {
+ loadFromFile(path, IntRect.EMPTY);
+ }
+
+ private native boolean nativeLoadFromImage(Image image, Buffer area);
+
+ /**
+ * Attempts to load the texture from a source image portion.
+ *
+ * @param image the source image.
+ * @param area the area of the image to load into the texture.
+ * @throws TextureCreationException if the texture could not be loaded from the image.
+ */
+ public void loadFromImage(Image image, IntRect area)
+ throws TextureCreationException {
+
+ image.commit();
+
+ Context.getContext();
+
+ if (!nativeLoadFromImage(image, IntercomHelper.encodeIntRect(area))) {
+ throw new TextureCreationException("Failed to load texture from image.");
+ }
+
+ updateSize();
+ }
+
+ /**
+ * Attempts to load the texture from a source image.
+ *
+ * @param image the source image.
+ * @throws TextureCreationException if the texture could not be loaded from the image.
+ */
+ public final void loadFromImage(Image image) throws TextureCreationException {
+ loadFromImage(image, IntRect.EMPTY);
+ }
+
+ private native long nativeGetSize();
+
+ private void updateSize() {
+ size = IntercomHelper.decodeVector2i(nativeGetSize());
+ }
+
+ /**
+ * Gets the dimensions of the texture.
+ *
+ * @return the dimensions of the texture.
+ */
+ public Vector2i getSize() {
+ return size;
+ }
+
+ private native long nativeCopyToImage();
+
+ @Override
+ public Image copyToImage() {
+ Image image = new Image(nativeCopyToImage());
+ UnsafeOperations.manageSFMLObject(image, true);
+
+ return image;
+ }
+
+ private native void nativeUpdate(Image image, int x, int y);
+
+ /**
+ * Updates a part of the texture from an image.
+ *
+ * @param image the image to update from.
+ * @param x the X offset inside the texture.
+ * @param y the Y offset inside the texture.
+ */
+ public void update(Image image, int x, int y) {
+ image.commit();
+ nativeUpdate(image, x, y);
+ }
+
+ private native void nativeUpdate(Window window, int x, int y);
+
+ /**
+ * Updates a part of the texture from the contents of a window.
+ *
+ * @param window the window to update from.
+ * @param x the X offset inside the texture.
+ * @param y the Y offset inside the texture.
+ */
+ public void update(Window window, int x, int y) {
+ nativeUpdate(Objects.requireNonNull(window), x, y);
+ }
+
+ /**
+ * Updates the texture from the contents of a window.
+ *
+ * @param window the window to update from.
+ */
+ public final void update(Window window) {
+ update(window, 0, 0);
+ }
+
+ private native void nativeSetSmooth(boolean smooth);
+
+ /**
+ * Enables or disables the smooth filter.
+ *
+ * The smooth filter is disabled by default.
+ *
+ * @param smooth {@code true} to enable, {@code false} to disable.
+ */
+ public void setSmooth(boolean smooth) {
+ nativeSetSmooth(smooth);
+ this.smooth = smooth;
+ }
+
+ private native boolean nativeIsSmooth();
+
+ @Override
+ public boolean isSmooth() {
+ return smooth;
+ }
+
+ private native void nativeSetRepeated(boolean repeated);
+
+ /**
+ * Enables or disables texture repeating.
+ *
+ * Texture repeating is disabled by default.
+ *
+ * @param repeated {@code true} to enable, {@code false} to disable.
+ */
+ public void setRepeated(boolean repeated) {
+ nativeSetRepeated(repeated);
+ this.repeated = repeated;
+ }
+
+ private native boolean nativeIsRepeated();
+
+ @Override
+ public boolean isRepeated() {
+ return repeated;
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/TextureCreationException.java b/lib/jsfml/src/java/org/jsfml/graphics/TextureCreationException.java
new file mode 100644
index 00000000..3dec5e47
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/TextureCreationException.java
@@ -0,0 +1,17 @@
+package org.jsfml.graphics;
+
+/**
+ * Thrown if a texture failed to be created.
+ */
+public class TextureCreationException extends Exception {
+ private static final long serialVersionUID = -3423733954575177518L;
+
+ /**
+ * Constructs a new texture creation exception with the specified message.
+ *
+ * @param message the detail message.
+ */
+ public TextureCreationException(String message) {
+ super(message);
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/Transform.java b/lib/jsfml/src/java/org/jsfml/graphics/Transform.java
new file mode 100644
index 00000000..b5a301ac
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/Transform.java
@@ -0,0 +1,371 @@
+/*
+ This class uses direct C++ to Java translations from SFML source code, hence the following notice:
+
+ ////////////////////////////////////////////////////////////
+ //
+ // SFML - Simple and Fast Multimedia Library
+ // Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
+ //
+ // This software is provided 'as-is', without any express or implied warranty.
+ // In no event will the authors be held liable for any damages arising from the use of this software.
+ //
+ // Permission is granted to anyone to use this software for any purpose,
+ // including commercial applications, and to alter it and redistribute it freely,
+ // subject to the following restrictions:
+ //
+ // 1. The origin of this software must not be misrepresented;
+ // you must not claim that you wrote the original software.
+ // If you use this software in a product, an acknowledgment
+ // in the product documentation would be appreciated but is not required.
+ //
+ // 2. Altered source versions must be plainly marked as such,
+ // and must not be misrepresented as being the original software.
+ //
+ // 3. This notice may not be removed or altered from any source distribution.
+ //
+ ////////////////////////////////////////////////////////////
+*/
+
+package org.jsfml.graphics;
+
+import org.jsfml.system.Vector2f;
+
+import java.io.Serializable;
+import java.util.Arrays;
+
+/**
+ * Defines a 3x3 transformation matrix for 2D transformations.
+ */
+public final strictfp class Transform implements Serializable {
+ private static final long serialVersionUID = 3796964163848107663L;
+
+ /**
+ * The identity transformation, maps any vector to itself and therefore
+ * "does nothing".
+ */
+ public final static Transform IDENTITY = new Transform();
+
+ /**
+ * Combines two transformation matrices by multiplying them.
+ *
+ * @param t1 the first transformation matrix.
+ * @param t2 the second transformation matrix.
+ * @return the product of the two given matrices.
+ */
+ public static Transform combine(Transform t1, Transform t2) {
+ float[] a = t1.data;
+ float[] b = t2.data;
+
+ return new Transform(
+ a[0] * b[0] + a[4] * b[1] + a[12] * b[3],
+ a[0] * b[4] + a[4] * b[5] + a[12] * b[7],
+ a[0] * b[12] + a[4] * b[13] + a[12] * b[15],
+ a[1] * b[0] + a[5] * b[1] + a[13] * b[3],
+ a[1] * b[4] + a[5] * b[5] + a[13] * b[7],
+ a[1] * b[12] + a[5] * b[13] + a[13] * b[15],
+ a[3] * b[0] + a[7] * b[1] + a[15] * b[3],
+ a[3] * b[4] + a[7] * b[5] + a[15] * b[7],
+ a[3] * b[12] + a[7] * b[13] + a[15] * b[15]);
+ }
+
+ /**
+ * Adds a translation by a 2D vector to a transformation.
+ *
+ * @param t the transformation to apply the translation on.
+ * @param x the X coordinate of the translation vector.
+ * @param y the Y coordinate of the translation vector.
+ * @return a new transformation matrix with the translation applied.
+ */
+ public static Transform translate(Transform t, float x, float y) {
+ return combine(t, new Transform(
+ 1, 0, x,
+ 0, 1, y,
+ 0, 0, 1));
+ }
+
+ /**
+ * Adds a translation by a 2D vector to a transformation.
+ *
+ * @param t the transformation to apply the translation to.
+ * @param v the translation vector.
+ * @return a new transformation matrix with the translation applied.
+ */
+ public static Transform translate(Transform t, Vector2f v) {
+ return translate(t, v.x, v.y);
+ }
+
+ /**
+ * Adds a rotation around the origin to a transformation.
+ *
+ * @param t the transformation to apply the rotation on.
+ * @param angle the rotation angle in degrees.
+ * @return a new transformation with the rotation applied
+ */
+ public static Transform rotate(Transform t, float angle) {
+ double rad = Math.toRadians(angle);
+ float cos = (float) Math.cos(rad);
+ float sin = (float) Math.sin(rad);
+
+ return combine(t, new Transform(
+ cos, -sin, 0,
+ sin, cos, 0,
+ 0, 0, 1));
+ }
+
+ /**
+ * Adds a rotation around an arbitrary center to this transformation.
+ *
+ * @param t the transformation to apply the rotation on.
+ * @param angle the rotation angle in degrees.
+ * @param centerX the X coordinate of the rotation center.
+ * @param centerY the Y coordinate of the rotation center.
+ * @return a new transformation with the rotation applied.
+ */
+ public static Transform rotate(Transform t, float angle, float centerX, float centerY) {
+ double rad = Math.toRadians(angle);
+ float cos = (float) Math.cos(rad);
+ float sin = (float) Math.sin(rad);
+
+ return combine(t, new Transform(
+ cos, -sin, centerX * (1 - cos) + centerY * sin,
+ sin, cos, centerY * (1 - cos) - centerX * sin,
+ 0, 0, 1));
+ }
+
+ /**
+ * Adds a rotation around an arbitrary center to this transformation.
+ *
+ * @param t the transformation to apply the rotation on.
+ * @param angle the rotation angle in degrees.
+ * @param center the rotation center.
+ * @return a new transformation with the rotation applied.
+ */
+ public static Transform rotate(Transform t, float angle, Vector2f center) {
+ return rotate(t, angle, center.x, center.y);
+ }
+
+ /**
+ * Adds a scaling operation from the origin to a transformation.
+ *
+ * @param t the transform to apply the scaling on.
+ * @param scaleX the X factor of the scaling operation.
+ * @param scaleY the Y factor of the scaling operation.
+ * @return a new transformation with the scaling applied.
+ */
+ public static Transform scale(Transform t, float scaleX, float scaleY) {
+ return combine(t, new Transform(
+ scaleX, 0, 0,
+ 0, scaleY, 0,
+ 0, 0, 1));
+ }
+
+ /**
+ * Adds a scaling operation from the origin to a transformation.
+ *
+ * @param t the transform to apply the scaling on.
+ * @param factors the factors of the scaling operation.
+ * @return a new transformation with the scaling applied.
+ */
+ public static Transform scale(Transform t, Vector2f factors) {
+ return scale(t, factors.x, factors.y);
+ }
+
+ /**
+ * Adds a scaling operation from an arbitrary center to a transformation.
+ *
+ * @param t the transform to apply the scaling on.
+ * @param scaleX the X factor of the scaling operation.
+ * @param scaleY the Y factor of the scaling operation.
+ * @param centerX the X coordinate of the scaling center.
+ * @param centerY the Y coordinate of the scaling center.
+ * @return a new transformation with the scaling applied.
+ */
+ public static Transform scale(Transform t, float scaleX, float scaleY, float centerX, float centerY) {
+ return combine(t, new Transform(
+ scaleX, 0, centerX * (1 - scaleX),
+ 0, scaleY, centerY * (1 - scaleY),
+ 0, 0, 1));
+ }
+
+ /**
+ * Adds a scaling operation from an arbitrary center to a transformation.
+ *
+ * @param t the transform to apply the scaling on.
+ * @param factors the factors of the scaling operation.
+ * @param center the scaling center.
+ * @return a new transformation with the scaling applied.
+ */
+ public static Transform scale(Transform t, Vector2f factors, Vector2f center) {
+ return scale(t, factors.x, factors.y, center.x, center.y);
+ }
+
+ private final float[] data = new float[16];
+
+ /**
+ * Constructs an identity transformation.
+ */
+ public Transform() {
+ data[0] = 1.0f;
+ data[5] = 1.0f;
+ data[10] = 1.0f;
+ data[15] = 1.0f;
+ }
+
+ /**
+ * Constructs a new transformation from a 3x3 matrix of the following format:
+ *
+ *
+ * @param a00 Matrix component.
+ * @param a01 Matrix component.
+ * @param a02 Matrix component.
+ * @param a10 Matrix component.
+ * @param a11 Matrix component.
+ * @param a12 Matrix component.
+ * @param a20 Matrix component.
+ * @param a21 Matrix component.
+ * @param a22 Matrix component.
+ */
+ public Transform(
+ float a00, float a01, float a02,
+ float a10, float a11, float a12,
+ float a20, float a21, float a22) {
+ data[0] = a00;
+ data[1] = a10;
+ data[3] = a20;
+ data[4] = a01;
+ data[5] = a11;
+ data[7] = a21;
+ data[10] = 1.f;
+ data[12] = a02;
+ data[11] = 0.f;
+ data[13] = a12;
+ data[15] = a22;
+ }
+
+ /**
+ * Constructs a new transformation by copying another transformation.
+ *
+ * @param t the transformation to copy.
+ */
+ public Transform(Transform t) {
+ System.arraycopy(t.data, 0, data, 0, 16);
+ }
+
+ /**
+ * Gets a copy of the underlying 4x4 3D transformation matrix.
+ *
+ * @return a copy of the underlying 4x4 3D transformation matrix.
+ */
+ public float[] getMatrix() {
+ float[] m = new float[16];
+ System.arraycopy(data, 0, m, 0, 16);
+ return m;
+ }
+
+ /**
+ * Returns the inverse transformation.
+ *
+ * @return the inverse transformation,
+ * or the identity transformation if the matrix cannot be inverted.
+ */
+ public Transform getInverse() {
+ float det = data[0] * (data[15] * data[5] - data[7] * data[13]) -
+ data[1] * (data[15] * data[4] - data[7] * data[12]) +
+ data[3] * (data[13] * data[4] - data[5] * data[12]);
+
+ if (det != 0.f) {
+ return new Transform(
+ (data[15] * data[5] - data[7] * data[13]) / det,
+ -(data[15] * data[4] - data[7] * data[12]) / det,
+ (data[13] * data[4] - data[5] * data[12]) / det,
+ -(data[15] * data[1] - data[3] * data[13]) / det,
+ (data[15] * data[0] - data[3] * data[12]) / det,
+ -(data[13] * data[0] - data[1] * data[12]) / det,
+ (data[7] * data[1] - data[3] * data[5]) / det,
+ -(data[7] * data[0] - data[3] * data[4]) / det,
+ (data[5] * data[0] - data[1] * data[4]) / det);
+ } else {
+ return new Transform();
+ }
+ }
+
+ /**
+ * Transforms a 2D point using the transformation matrix.
+ *
+ * @param x the X coordinate of the point.
+ * @param y the Y coordinate of the point.
+ * @return a new 2D vector, representing the transformed point.
+ */
+ public Vector2f transformPoint(float x, float y) {
+ return new Vector2f(
+ data[0] * x + data[4] * y + data[12],
+ data[1] * x + data[5] * y + data[13]);
+ }
+
+ /**
+ * Transforms a 2D point using the transformation matrix.
+ *
+ * @param v the point to transform.
+ * @return a new 2D vector, representing the transformed point.
+ */
+ public final Vector2f transformPoint(Vector2f v) {
+ return transformPoint(v.x, v.y);
+ }
+
+ /**
+ * Transforms a rectangle and returns the axis-aligned bounding rectangle.
+ *
+ * @param rectangle the rectangle to transform.
+ * @return the axis-aligned bounding rectangle of the rotated rectangle.
+ */
+ public FloatRect transformRect(FloatRect rectangle) {
+ // Transform the 4 corners of the rectangle
+ Vector2f points[] = new Vector2f[]{
+ transformPoint(rectangle.left, rectangle.top),
+ transformPoint(rectangle.left, rectangle.top + rectangle.height),
+ transformPoint(rectangle.left + rectangle.width, rectangle.top),
+ transformPoint(rectangle.left + rectangle.width, rectangle.top + rectangle.height)};
+
+ // Compute the bounding rectangle of the transformed points
+ float left = points[0].x;
+ float top = points[0].y;
+ float right = points[0].x;
+ float bottom = points[0].y;
+
+ for (int i = 1; i < 4; ++i) {
+ if (points[i].x < left) left = points[i].x;
+ else if (points[i].x > right) right = points[i].x;
+ if (points[i].y < top) top = points[i].y;
+ else if (points[i].y > bottom) bottom = points[i].y;
+ }
+
+ return new FloatRect(left, top, right - left, bottom - top);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return (o instanceof Transform && Arrays.equals(data, ((Transform) o).data));
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(data);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder str = new StringBuilder();
+ str.append("Transform{data=\n");
+ int i = 0;
+ for (int y = 0; y < 4; y++) {
+ for (int x = 0; x < 4; x++) {
+ str.append(Float.toString(data[i++])).append(" ");
+ }
+ str.append("\n");
+ }
+ str.append("}");
+ return str.toString();
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/Transformable.java b/lib/jsfml/src/java/org/jsfml/graphics/Transformable.java
new file mode 100644
index 00000000..26616106
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/Transformable.java
@@ -0,0 +1,142 @@
+package org.jsfml.graphics;
+
+import org.jsfml.system.Vector2f;
+
+/**
+ * Interface for transformable objects that can be positioned in the scene and
+ * rotated and scaled around an origin.
+ *
+ * An implementation of this interface is provided by the {@link BasicTransformable} class.
+ */
+public interface Transformable {
+ /**
+ * Sets the position of this object in the scene so that its origin will be exactly on it.
+ *
+ * @param x the new X coordinate.
+ * @param y the new Y coordinate.
+ */
+ public void setPosition(float x, float y);
+
+ /**
+ * Sets the position of this object in the scene so that its origin will be exactly on it.
+ *
+ * @param v the new position.
+ */
+ public void setPosition(Vector2f v);
+
+ /**
+ * Sets the rotation of this object around its origin.
+ *
+ * @param angle the new rotation angle in degrees.
+ */
+ public void setRotation(float angle);
+
+ /**
+ * Sets the scaling of this object, using its origin as the scaling center.
+ *
+ * @param x the new X scaling factor.
+ * @param y the new Y scaling factor.
+ */
+ public void setScale(float x, float y);
+
+ /**
+ * Sets the scaling of this object, using its origin as the scaling center.
+ *
+ * @param factors the new scaling factors.
+ */
+ public void setScale(Vector2f factors);
+
+ /**
+ * Sets the rotation, scaling and drawing origin of this object.
+ *
+ * @param x the new X coordinate of the origin.
+ * @param y the new Y coordinate of the origin.
+ */
+ public void setOrigin(float x, float y);
+
+ /**
+ * Sets the rotation, scaling and drawing origin of this object.
+ *
+ * @param v the new origin.
+ */
+ public void setOrigin(Vector2f v);
+
+ /**
+ * Gets the position of this object.
+ *
+ * @return the current position.
+ */
+ public Vector2f getPosition();
+
+ /**
+ * Gets the rotation angle of this object.
+ *
+ * @return the current rotation angle in degrees.
+ */
+ public float getRotation();
+
+ /**
+ * Gets the scaling of this object.
+ *
+ * @return the current scaling factors.
+ */
+ public Vector2f getScale();
+
+ /**
+ * Gets the origin of this object.
+ *
+ * @return the current origin.
+ */
+ public Vector2f getOrigin();
+
+ /**
+ * Moves this object.
+ *
+ * @param x the X offset added to the current position.
+ * @param y the Y offset added to the current position.
+ */
+ public void move(float x, float y);
+
+ /**
+ * Moves the object.
+ *
+ * @param v the offset vector added to the current position.
+ */
+ public void move(Vector2f v);
+
+ /**
+ * Rotates this object around its origin.
+ *
+ * @param angle the rotation angle in degrees.
+ */
+ public void rotate(float angle);
+
+ /**
+ * Scales the object, using its origin as the scaling center.
+ *
+ * @param x the X scaling factor.
+ * @param y the Y scaling factor.
+ */
+ public void scale(float x, float y);
+
+ /**
+ * Scales the object, using its origin as the scaling center.
+ *
+ * @param factors the scaling factors.
+ */
+ public void scale(Vector2f factors);
+
+ /**
+ * Gets the current transformation matrix.
+ *
+ * @return the current transformation.
+ */
+ public Transform getTransform();
+
+ /**
+ * Gets the inverse of the current transformation matrix.
+ *
+ * @return the inverse of the current transform.
+ */
+ public Transform getInverseTransform();
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/Vertex.java b/lib/jsfml/src/java/org/jsfml/graphics/Vertex.java
new file mode 100644
index 00000000..9c453db9
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/Vertex.java
@@ -0,0 +1,73 @@
+package org.jsfml.graphics;
+
+import org.jsfml.system.Vector2f;
+
+import java.io.Serializable;
+
+/**
+ * Defines a shape point with position, color and texture coordinates information.
+ */
+public final class Vertex implements Serializable {
+ private static final long serialVersionUID = -5749297453247575018L;
+
+ /**
+ * The vertex position.
+ */
+ public final Vector2f position;
+
+ /**
+ * The vertex color.
+ */
+ public final Color color;
+
+ /**
+ * The vertex texture coordinates.
+ *
+ * The unit space this information is measured in depends on the way the respective
+ * texture will be bound. By the default, the {@link Texture.CoordinateType#NORMALIZED}
+ * coordinate type is used.
+ */
+ public final Vector2f texCoords;
+
+ /**
+ * Constructs a new vertex at the specified position with white color.
+ *
+ * @param position the vertex' position.
+ */
+ public Vertex(Vector2f position) {
+ this(position, Color.WHITE, Vector2f.ZERO);
+ }
+
+ /**
+ * Constructs a new vertex with the specified position and color.
+ *
+ * @param position the vertex' position.
+ * @param color the vertex' color.
+ */
+ public Vertex(Vector2f position, Color color) {
+ this(position, color, Vector2f.ZERO);
+ }
+
+ /**
+ * Constructs a new vertex with the specified position and texture coordinates, with white color.
+ *
+ * @param position the vertex' position.
+ * @param texCoords the vertex' texture coordinates.
+ */
+ public Vertex(Vector2f position, Vector2f texCoords) {
+ this(position, Color.WHITE, texCoords);
+ }
+
+ /**
+ * Constructs a new vertex with the specified parameters.
+ *
+ * @param position the vertex' position.
+ * @param color the vertex' color.
+ * @param texCoords the vertex' texture coordinates.
+ */
+ public Vertex(Vector2f position, Color color, Vector2f texCoords) {
+ this.position = position;
+ this.color = color;
+ this.texCoords = texCoords;
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/VertexArray.java b/lib/jsfml/src/java/org/jsfml/graphics/VertexArray.java
new file mode 100644
index 00000000..a6bac347
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/VertexArray.java
@@ -0,0 +1,90 @@
+package org.jsfml.graphics;
+
+import org.jsfml.system.Vector2f;
+
+import java.util.ArrayList;
+
+/**
+ * Defines a drawable set of one or multiple 2D primitives.
+ */
+public class VertexArray extends ArrayList implements Drawable {
+ private static final long serialVersionUID = 4656221909265000727L;
+
+ private PrimitiveType primitiveType;
+
+ /**
+ * Constructs a new empty vertex array using the {@link PrimitiveType#POINTS} type.
+ */
+ public VertexArray() {
+ this(PrimitiveType.POINTS);
+ }
+
+ /**
+ * Constructs a new empty vertex array.
+ *
+ * @param primitiveType The type of primitives drawn by this vertex array.
+ */
+ public VertexArray(PrimitiveType primitiveType) {
+ super(4);
+
+ this.primitiveType = primitiveType;
+ }
+
+ /**
+ * Gets the type of primitives drawn by this vertex array.
+ *
+ * @return the type of primitives drawn by this vertex array.
+ */
+ public PrimitiveType getPrimitiveType() {
+ return primitiveType;
+ }
+
+ /**
+ * Sets the type of primitives drawn by this vertex array.
+ *
+ * @param primitiveType the type of primitives drawn by this vertex array.
+ */
+ public void setPrimitiveType(PrimitiveType primitiveType) {
+ this.primitiveType = primitiveType;
+ }
+
+ /**
+ * Computes the axis-aligned bounding box of this vertex array.
+ *
+ * @return the axis-aligned bounding box of this vertex array.
+ */
+ public FloatRect getBounds() {
+ if (!isEmpty()) {
+ Vector2f v = get(0).position;
+ float left = v.x;
+ float top = v.y;
+ float right = v.x;
+ float bottom = v.y;
+
+ for (int i = 1; i < size(); i++) {
+ v = get(i).position;
+
+ if (v.x < left)
+ left = v.x;
+ else if (v.x > right)
+ right = v.x;
+
+ if (v.y < top)
+ top = v.y;
+ else if (v.y > bottom)
+ bottom = v.y;
+ }
+
+ return new FloatRect(left, top, right - left, bottom - top);
+ } else {
+ return FloatRect.EMPTY;
+ }
+ }
+
+ @Override
+ public void draw(RenderTarget target, RenderStates states) {
+ if (!isEmpty()) {
+ target.draw(toArray(new Vertex[size()]), primitiveType, states);
+ }
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/View.java b/lib/jsfml/src/java/org/jsfml/graphics/View.java
new file mode 100644
index 00000000..83b76909
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/View.java
@@ -0,0 +1,264 @@
+package org.jsfml.graphics;
+
+import org.jsfml.internal.IntercomHelper;
+import org.jsfml.internal.SFMLNativeObject;
+import org.jsfml.system.Vector2f;
+
+import java.nio.Buffer;
+
+/**
+ * Represents a 2D camera which defines the region of the scene that is visible.
+ */
+public class View extends SFMLNativeObject implements ConstView {
+ //Cache
+ private Vector2f size = new Vector2f(1000, 1000);
+ private Vector2f center = new Vector2f(500, 500);
+ private float rotation = 0;
+ private FloatRect viewport = new FloatRect(0, 0, 1, 1);
+
+ private boolean transformNeedsUpdate = true;
+ private Transform transformCache = null;
+ private Transform inverseTransformCache = null;
+
+ /**
+ * Constructs a new view for the area of (0, 0, 1000, 1000).
+ */
+ public View() {
+ super();
+ }
+
+ @SuppressWarnings("deprecation")
+ View(long wrap) {
+ super(wrap);
+ sync();
+ }
+
+ /**
+ * Constructs a new view for the specified area.
+ *
+ * @param rect the area visible by this view.
+ */
+ public View(FloatRect rect) {
+ this();
+ reset(rect);
+ }
+
+ /**
+ * Constructs a view for the specified area.
+ *
+ * @param center the center of the view.
+ * @param size the size of the view.
+ */
+ public View(Vector2f center, Vector2f size) {
+ this();
+ setCenter(center);
+ setSize(size);
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected final native long nativeCreate();
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected void nativeSetExPtr() {
+ }
+
+ @Override
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected native void nativeDelete();
+
+ private native void nativeSetCenter(float x, float y);
+
+ /**
+ * Sets the center of the view.
+ *
+ * @param x the new X coordinate of the view's center.
+ * @param y the new Y coordinate of the view's center.
+ */
+ public final void setCenter(float x, float y) {
+ setCenter(new Vector2f(x, y));
+ }
+
+ /**
+ * Sets the center of the view.
+ *
+ * @param v the new center of the view.
+ */
+ public void setCenter(Vector2f v) {
+ nativeSetCenter(v.x, v.y);
+ this.center = v;
+ transformNeedsUpdate = true;
+ }
+
+ private native void nativeSetSize(float width, float height);
+
+ /**
+ * Sets the dimensions of the view.
+ *
+ * @param width the new width of the view in pixels.
+ * @param height the new height of the view in pixels.
+ */
+ public void setSize(float width, float height) {
+ setSize(new Vector2f(width, height));
+ }
+
+ /**
+ * Sets the dimensions of the view.
+ *
+ * @param v the new size of the view in pixels.
+ */
+ public void setSize(Vector2f v) {
+ nativeSetSize(v.x, v.y);
+ this.size = v;
+ transformNeedsUpdate = true;
+ }
+
+ private native void nativeSetRotation(float angle);
+
+ /**
+ * Sets the rotation of the view around its center.
+ *
+ * @param angle the new rotation angle in degrees.
+ */
+ public void setRotation(float angle) {
+ nativeSetRotation(angle);
+ this.rotation = angle;
+ transformNeedsUpdate = true;
+ }
+
+ private native void nativeSetViewport(Buffer buffer);
+
+ /**
+ * Sets the viewport rectangle of this view.
+ *
+ * The viewport defines which portion of the render target is used by this view and is
+ * expressed using factors between 0 and 1 (percentage of the target's width and height).
+ *
+ * The default viewport rectangle is (0, 0, 1, 1).
+ *
+ * @param rect the new viewport rectangle.
+ */
+ public void setViewport(FloatRect rect) {
+ nativeSetViewport(IntercomHelper.encodeFloatRect(rect));
+ this.viewport = rect;
+ }
+
+ private native void nativeReset(Buffer buffer);
+
+ /**
+ * Resets the view to a certain viewport rectangle, resetting the rotation angle in the process.
+ *
+ * @param rect the viewport rectangle.
+ */
+ public void reset(FloatRect rect) {
+ nativeReset(IntercomHelper.encodeFloatRect(rect));
+ sync();
+ }
+
+ private native void nativeGetViewport(Buffer buffer);
+
+ private native long nativeGetSize();
+
+ private native long nativeGetCenter();
+
+ private native float nativeGetRotation();
+
+ private void sync() {
+ nativeGetViewport(IntercomHelper.getBuffer());
+ this.viewport = IntercomHelper.decodeFloatRect();
+ this.size = IntercomHelper.decodeVector2f(nativeGetSize());
+ this.center = IntercomHelper.decodeVector2f(nativeGetCenter());
+ this.rotation = nativeGetRotation();
+ transformNeedsUpdate = true;
+ }
+
+ @Override
+ public Vector2f getCenter() {
+ return center;
+ }
+
+ @Override
+ public Vector2f getSize() {
+ return size;
+ }
+
+ @Override
+ public float getRotation() {
+ return rotation;
+ }
+
+ @Override
+ public FloatRect getViewport() {
+ return viewport;
+ }
+
+ /**
+ * Rotates the view around its center.
+ *
+ * @param angle the angle to rotate by, in degrees.
+ */
+ public final void rotate(float angle) {
+ setRotation(rotation + angle);
+ }
+
+ /**
+ * Moves the center of the view.
+ *
+ * @param x the X offset to move the view's center by.
+ * @param y the Y offset to move the view's center by.
+ */
+ public final void move(float x, float y) {
+ setCenter(new Vector2f(center.x + x, center.y + y));
+ }
+
+ /**
+ * Moves the center of the view.
+ *
+ * @param v the offset vector to move the view's center by.
+ */
+ public final void move(Vector2f v) {
+ move(v.x, v.y);
+ }
+
+ /**
+ * Resizes the view.
+ *
+ * @param factor the zoom factor.
+ */
+ public final void zoom(float factor) {
+ setSize(size.x * factor, size.y * factor);
+ }
+
+ private native void nativeGetTransform(Buffer buf);
+
+ private void updateTransform() {
+ if (transformNeedsUpdate) {
+ nativeGetTransform(IntercomHelper.getBuffer());
+ transformCache = IntercomHelper.decodeTransform();
+ inverseTransformCache = transformCache.getInverse();
+ transformNeedsUpdate = false;
+ }
+ }
+
+ @Override
+ public Transform getTransform() {
+ if (transformNeedsUpdate) {
+ updateTransform();
+ }
+
+ return transformCache;
+ }
+
+ @Override
+ public Transform getInverseTransform() {
+ if (transformNeedsUpdate) {
+ updateTransform();
+ }
+
+ return inverseTransformCache;
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/graphics/package-info.java b/lib/jsfml/src/java/org/jsfml/graphics/package-info.java
new file mode 100644
index 00000000..ff700a22
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/graphics/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Contains classes related to graphics, representing drawable and transformable objects
+ * that can be made visible on a render target.
+ */
+package org.jsfml.graphics;
diff --git a/lib/jsfml/src/java/org/jsfml/internal/Const.java b/lib/jsfml/src/java/org/jsfml/internal/Const.java
new file mode 100644
index 00000000..1de635b3
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/internal/Const.java
@@ -0,0 +1,14 @@
+package org.jsfml.internal;
+
+/**
+ * Interface for read-only objects.
+ *
+ * This interface is JSFML's way to map C++ const references to Java. Subinterfaces will
+ * be specific to a certain JSFML type and provide methods to read from them only.
+ *
+ * The subinterfaces may be used freely outside of the JSFML API itself, however, it is not
+ * recommended to implement them, because in certain cases, they are expected to be implemented
+ * by a certain JSFML class.
+ */
+public interface Const {
+}
diff --git a/lib/jsfml/src/java/org/jsfml/internal/ExPtr.java b/lib/jsfml/src/java/org/jsfml/internal/ExPtr.java
new file mode 100644
index 00000000..d37dfc21
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/internal/ExPtr.java
@@ -0,0 +1,43 @@
+package org.jsfml.internal;
+
+/**
+ * Holds index definitions for the {@link SFMLNativeObject#exPtr} array.
+ */
+@Intercom
+final class ExPtr {
+ //Total amount of exPtr fields.
+ @Intercom
+ static final int NUM = 3;
+
+ //Pointer to sf::Drawable.
+ @Intercom
+ static final int DRAWABLE = 0;
+
+ //Pointer to sf::Transformable.
+ @Intercom
+ static final int TRANSFORMABLE = 1;
+
+ //Pointer to sf::Shape.
+ @Intercom
+ static final int SHAPE = 2;
+
+ //Pointer to sf::RenderTarget.
+ @Intercom
+ static final int RENDER_TARGET = 0;
+
+ //Pointer to sf::Window.
+ @Intercom
+ static final int WINDOW = 1;
+
+ //Pointer to sf::SoundSource.
+ @Intercom
+ static final int SOUND_SOURCE = 0;
+
+ //Pointer to sf::SoundStream.
+ @Intercom
+ static final int SOUND_STREAM = 1;
+
+ //Pointer to sf::SoundRecorder.
+ @Intercom
+ static final int SOUND_RECORDER = 0;
+}
diff --git a/lib/jsfml/src/java/org/jsfml/internal/Intercom.java b/lib/jsfml/src/java/org/jsfml/internal/Intercom.java
new file mode 100644
index 00000000..92e07867
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/internal/Intercom.java
@@ -0,0 +1,15 @@
+package org.jsfml.internal;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for intercom-critical types, fields, methods and constructors.
+ *
+ * This annotation is purely for informational purposes and provides no actual functionality.
+ * Elements annotated by this annotation must not be refactored without altering
+ * the respective native (C++) sources.
+ */
+@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface Intercom {
+}
diff --git a/lib/jsfml/src/java/org/jsfml/internal/IntercomHelper.java b/lib/jsfml/src/java/org/jsfml/internal/IntercomHelper.java
new file mode 100644
index 00000000..b3b9ae88
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/internal/IntercomHelper.java
@@ -0,0 +1,201 @@
+package org.jsfml.internal;
+
+import org.jsfml.graphics.*;
+import org.jsfml.system.Vector2f;
+import org.jsfml.system.Vector2i;
+
+import java.nio.*;
+
+/**
+ * Provides functionality to encode and decode data structures used
+ * for intercom methods.
+ */
+public final class IntercomHelper {
+ private static final ThreadLocal BUFFER =
+ new ThreadLocal() {
+ @Override
+ protected ByteBuffer initialValue() {
+ return ByteBuffer.allocateDirect(256).order(ByteOrder.nativeOrder());
+ }
+ };
+
+ /**
+ * Gets the current thread-local buffer.
+ *
+ * @return the current thread-local buffer.
+ */
+ public static ByteBuffer getBuffer() {
+ return BUFFER.get();
+ }
+
+ /**
+ * Encodes a color into a 32-bit integer.
+ *
+ * @param color the color to encode.
+ * @return the encoded color.
+ */
+ public static int encodeColor(Color color) {
+ return (color.a << 24) | (color.b << 16) | (color.g << 8) | color.r;
+ }
+
+ /**
+ * Decodes a color from a 32-bit integer.
+ *
+ * @param code the encoded color.
+ * @return the decoded color.
+ */
+ public static Color decodeColor(int code) {
+ final int a = (code >> 24) & 0xFF;
+ final int b = (code >> 16) & 0xFF;
+ final int g = (code >> 8) & 0xFF;
+ final int r = code & 0xFF;
+ return new Color(r, g, b, a);
+ }
+
+ /**
+ * Encodes an integer vector into a 64-bit integer.
+ *
+ * @param vec the vector.
+ * @return the encoded vector.
+ */
+ public static long encodeVector2i(Vector2i vec) {
+ long v = ((long) vec.y) << 32;
+ v |= vec.x;
+ return v;
+ }
+
+ /**
+ * Encodes a float vector into a 64-bit integer.
+ *
+ * @param vec the vector.
+ * @return the encoded vector.
+ */
+ public static long encodeVector2f(Vector2f vec) {
+ long v = ((long) Float.floatToIntBits(vec.y)) << 32;
+ v |= Float.floatToIntBits(vec.x);
+ return v;
+ }
+
+ /**
+ * Decodes an integer vector from a 64-bit integer.
+ *
+ * @param vec the encoded vector.
+ * @return the decoded vector.
+ */
+ public static Vector2i decodeVector2i(long vec) {
+ if (vec == 0) {
+ return Vector2i.ZERO;
+ } else {
+ return new Vector2i((int) vec, (int) (vec >> 32));
+ }
+ }
+
+ /**
+ * Decodes a float vector from a 64-bit integer.
+ *
+ * @param vec the encoded vector.
+ * @return the decoded vector.
+ */
+ public static Vector2f decodeVector2f(long vec) {
+ return new Vector2f(
+ Float.intBitsToFloat((int) vec),
+ Float.intBitsToFloat((int) (vec >> 32)));
+ }
+
+ /**
+ * Decodes an integer rectangle from the current float buffer content.
+ *
+ * @return the decoded rectangle.
+ */
+ public static IntRect decodeIntRect() {
+ final IntBuffer buf = BUFFER.get().asIntBuffer();
+ return new IntRect(
+ buf.get(0),
+ buf.get(1),
+ buf.get(2),
+ buf.get(3));
+ }
+
+ /**
+ * Encodes an integer rectangle into the current integer buffer.
+ *
+ * @param r the rectangle to encode.
+ * @return A reference to the integer buffer.
+ */
+ public static Buffer encodeIntRect(IntRect r) {
+ final IntBuffer buf = BUFFER.get().asIntBuffer();
+ buf.put(0, r.left);
+ buf.put(1, r.top);
+ buf.put(2, r.width);
+ buf.put(3, r.height);
+ return buf;
+ }
+
+ /**
+ * Decodes a float rectangle from the current float buffer content.
+ *
+ * @return the decoded rectangle.
+ */
+ public static FloatRect decodeFloatRect() {
+ final FloatBuffer buf = BUFFER.get().asFloatBuffer();
+ return new FloatRect(
+ buf.get(0),
+ buf.get(1),
+ buf.get(2),
+ buf.get(3));
+ }
+
+ /**
+ * Encodes a float rectangle into the current float buffer.
+ *
+ * @param r the float to encode.
+ * @return A reference to the float buffer.
+ */
+ public static Buffer encodeFloatRect(FloatRect r) {
+ final FloatBuffer buf = BUFFER.get().asFloatBuffer();
+ buf.put(0, r.left);
+ buf.put(1, r.top);
+ buf.put(2, r.width);
+ buf.put(3, r.height);
+ return buf;
+ }
+
+ /**
+ * Decodes a transformation matrix from the current float buffer content.
+ *
+ * @return the decoded transformation matrix.
+ */
+ public static Transform decodeTransform() {
+ final FloatBuffer buf = BUFFER.get().asFloatBuffer();
+ return new Transform(
+ buf.get(0), buf.get(1), buf.get(2),
+ buf.get(3), buf.get(4), buf.get(5),
+ buf.get(6), buf.get(7), buf.get(8)
+ );
+ }
+
+ /**
+ * Encodes a transformation matrix into the current float buffer.
+ *
+ * @param xform the transformation matrix to encode.
+ * @return A reference to the float buffer.
+ */
+ public static Buffer encodeTransform(Transform xform) {
+ final FloatBuffer buf = BUFFER.get().asFloatBuffer();
+ final float[] data = xform.getMatrix();
+
+ buf.put(0, data[0]);
+ buf.put(1, data[4]);
+ buf.put(2, data[12]);
+ buf.put(3, data[1]);
+ buf.put(4, data[5]);
+ buf.put(5, data[13]);
+ buf.put(6, data[3]);
+ buf.put(7, data[7]);
+ buf.put(8, data[15]);
+ return buf;
+ }
+
+ private IntercomHelper() {
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/internal/JSFMLError.java b/lib/jsfml/src/java/org/jsfml/internal/JSFMLError.java
new file mode 100644
index 00000000..5fd66bcc
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/internal/JSFMLError.java
@@ -0,0 +1,30 @@
+package org.jsfml.internal;
+
+/**
+ * Error class for severe JSFML faults.
+ *
+ * An error of this type is raised either if JSFML tried to load its native libraries on an unsupported
+ * platform, or if a platform-specific requirement is violated.
+ */
+public class JSFMLError extends Error {
+ private static final long serialVersionUID = -8281004117329430845L;
+
+ /**
+ * Constructs a JSFML error with the specified message.
+ *
+ * @param message the exception's message text.
+ */
+ public JSFMLError(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a JSFML error with the specified message and cause.
+ *
+ * @param message the exception's message text.
+ * @param cause the exception's cause, or {@code null} if no cause is known or available.
+ */
+ public JSFMLError(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/internal/NativeRef.java b/lib/jsfml/src/java/org/jsfml/internal/NativeRef.java
new file mode 100644
index 00000000..f14df173
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/internal/NativeRef.java
@@ -0,0 +1,78 @@
+package org.jsfml.internal;
+
+/**
+ * Helper class for managing Java object references and related native pointers.
+ *
+ * @param The type of the related Java object, if any.
+ */
+@Intercom
+public abstract class NativeRef {
+ private T ref = null;
+
+ @Intercom
+ private long ptr = 0;
+
+ /**
+ * Constructs a native reference.
+ */
+ public NativeRef() {
+ }
+
+ /**
+ * Initializes a native pointer related to the specified Java object.
+ *
+ * @param ref the related Java object, or {@code null} if there is none.
+ * @return a native pointer, or 0 if none was initialized.
+ */
+ protected abstract long nativeInitialize(T ref);
+
+ /**
+ * Releases the Java reference, if any, and the managed native pointer, if any.
+ *
+ * This also is responsible for natively allocated memory being freed.
+ *
+ * @param ref the Java object reference, or {@code null} if there is none.
+ * @param ptr the native pointer, if any.
+ */
+ protected abstract void nativeRelease(T ref, long ptr);
+
+ /**
+ * Initializes a native reference with the specified Java object.
+ *
+ * @param ref the Java object, or {@code null} if none is required.
+ */
+ public void initialize(T ref) {
+ release();
+
+ this.ref = ref;
+ this.ptr = nativeInitialize(ref);
+ }
+
+ /**
+ * Releases the managed Java reference, if any, and frees the managed native pointer,
+ * if any, including freeing any natively allocated memory.
+ */
+ public void release() {
+ if (ptr != 0) {
+ nativeRelease(ref, ptr);
+ ptr = 0;
+ }
+
+ ref = null;
+ }
+
+ /**
+ * Tests whether this reference has a non-zero native pointer.
+ *
+ * @return {@code true} if the pointer is non-zero, {@code false} if it is {@code NULL}.
+ */
+ public boolean hasNonZeroPointer() {
+ return (ptr != 0);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ release();
+ super.finalize();
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/internal/SFMLErrorCapture.java b/lib/jsfml/src/java/org/jsfml/internal/SFMLErrorCapture.java
new file mode 100644
index 00000000..5ae4bd73
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/internal/SFMLErrorCapture.java
@@ -0,0 +1,58 @@
+package org.jsfml.internal;
+
+import java.util.concurrent.Semaphore;
+
+/**
+ * Provides methods to capture output to {@code sf::err()}.
+ */
+public class SFMLErrorCapture {
+ private static boolean capturing = false;
+ private final static Semaphore semaphore = new Semaphore(1);
+
+ private static native void nativeStart();
+
+ /**
+ * Starts capturing all output to {@code sf::err()}.
+ *
+ * This method acquires a semaphore and will block if a capture is currently going,
+ * therefore the capturing is thread-safe.
+ *
+ * A capture must be concluded by calling the {@link #finish()} method.
+ */
+ public static void start() {
+ try {
+ semaphore.acquire();
+ capturing = true;
+
+ nativeStart();
+ } catch (InterruptedException ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ private static native String nativeFinish();
+
+ /**
+ * Finishes capturing all output to {@code sf::err()} and returns what was captured.
+ *
+ * @return the output that was captured, or {@code null} if capturing was never started using
+ * {@link #start()}.
+ */
+ public static String finish() {
+ final String str;
+ if (capturing) {
+ str = nativeFinish().trim();
+
+ capturing = false;
+ semaphore.release();
+ } else {
+ str = null;
+ }
+
+ return str;
+ }
+
+ private SFMLErrorCapture() {
+ //cannot instantiate
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/internal/SFMLInputStream.java b/lib/jsfml/src/java/org/jsfml/internal/SFMLInputStream.java
new file mode 100644
index 00000000..4d7d4f97
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/internal/SFMLInputStream.java
@@ -0,0 +1,106 @@
+package org.jsfml.internal;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Objects;
+
+/**
+ * Pipe for enabling stream from a Java {@link InputStream} into a {@code sf::InputStream}.
+ */
+public class SFMLInputStream {
+ /**
+ * Native pointer manager for an {@code SFMLInputStream} bound
+ * natively to an {@code sf::InputStream}.
+ */
+ public static class NativeStreamRef extends NativeRef {
+ @Override
+ protected native long nativeInitialize(SFMLInputStream ref);
+
+ @Override
+ protected native void nativeRelease(SFMLInputStream ref, long ptr);
+ }
+
+ private final InputStream stream;
+ private long pos;
+
+ public SFMLInputStream(InputStream stream) {
+ Objects.requireNonNull(stream);
+
+ if (stream.markSupported()) {
+ this.stream = stream;
+ } else {
+ this.stream = new BufferedInputStream(stream);
+ }
+
+ //Mark the current position as zero
+ this.stream.mark(Integer.MAX_VALUE);
+ pos = 0;
+ }
+
+ //As defined in sf::InputStream.
+ long read(ByteBuffer buffer, long n) {
+ try {
+ byte[] b = new byte[buffer.capacity()];
+ long num = (long) stream.read(b);
+ if (num == -1) {
+ return 0;
+ } else {
+ buffer.put(b);
+ }
+
+ pos += num;
+ return num;
+ } catch (IOException ex) {
+ pos = -1;
+ return 0;
+ }
+ }
+
+ //As defined in sf::InputStream.
+ long seek(long n) {
+ try {
+ if (n > pos) {
+ long skipped = stream.skip(n - pos);
+ pos += skipped;
+ } else {
+ stream.reset();
+ pos = 0;
+
+ if (n > 0) {
+ pos = stream.skip(n);
+ }
+ }
+
+ return (pos == n) ? pos : -1;
+ } catch (IOException ex) {
+ pos = -1;
+ return -1;
+ }
+ }
+
+ //As defined in sf::InputStream.
+ long tell() {
+ return pos;
+ }
+
+ //As defined in sf::InputStream.
+ long getSize() {
+ try {
+ long n = (long) stream.available();
+ return n;
+ } catch (IOException ex) {
+ return -1;
+ }
+ }
+
+ //Called by the destructor.
+ void close() {
+ try {
+ stream.close();
+ } catch (IOException ex) {
+ //
+ }
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/internal/SFMLNative.java b/lib/jsfml/src/java/org/jsfml/internal/SFMLNative.java
new file mode 100644
index 00000000..51f852e6
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/internal/SFMLNative.java
@@ -0,0 +1,227 @@
+package org.jsfml.internal;
+
+import java.awt.*;
+import java.io.*;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.LinkedList;
+
+/**
+ * Native library loader.
+ *
+ * This class contains the "self-containedness" functionality of JSFML.
+ *
+ * @see #loadNativeLibraries() for more information.
+ */
+public final class SFMLNative {
+ private static final Path JSFML_USER_HOME = Paths.get(System.getProperty("user.home"), ".jsfml");
+
+ private static final String JSFML_BIN_RESOURCE_PATH = "/bin/";
+
+ private static final String MD5_EXT = ".MD5";
+ private static final int MD5_LENGTH = 32;
+
+ /**
+ * The substring of the {@code os.name} system property
+ * to look for to detect Windows systems.
+ */
+ public static final String OS_NAME_WINDOWS = "Windows";
+
+ /**
+ * The substring of the {@code os.name} system property
+ * to look for to detect Linux systems.
+ */
+ public static final String OS_NAME_LINUX = "Linux";
+
+ /**
+ * The substring of the {@code os.name} system property
+ * to look for to detect Mac OS X systems.
+ */
+ public static final String OS_NAME_MACOSX = "Mac OS X";
+
+ private static native void nativeInit();
+
+ private static boolean loaded = false;
+
+ private static String readMD5File(InputStream in) throws IOException {
+ byte[] buffer = new byte[MD5_LENGTH];
+ int n = in.read(buffer);
+
+ if (n != MD5_LENGTH)
+ throw new IOException("Error reading MD5 file.");
+
+ return new String(buffer);
+ }
+
+ private static String readMD5File(Path path) throws IOException {
+ try (final InputStream fis = Files.newInputStream(path)) {
+ return readMD5File(fis);
+ }
+ }
+
+ /**
+ * Loads the native JSFML libraries if it has not been done yet.
+ *
+ * This must be done before any SFML class representations can be used. All affected classes
+ * will call this method when they are loaded, so this does not have to be done manually.
+ *
+ * This method will scan the {@code os.name} and {@code os.arch} system properties and
+ * compile a list of libraries to load if the platform is supported. The libraries will
+ * then be looked for in the classpath, extracted to the user directory and loaded.
+ *
+ * The libraries will be extracted to {@code ~/.jsfml}. If the files already exist, their MD5
+ * hashes (which are provided in separate files) will be tested against the ones in the
+ * classpath. If the MD5 hashes differ, the existing file in the user directory will
+ * be overridden.
+ *
+ * If loading the native libraries fails, a {@link JSFMLError} will be raised with
+ * a brief description of what went wrong.
+ */
+ public static void loadNativeLibraries() {
+ if (!loaded) {
+ loaded = true;
+
+ //Get operating system information
+ final String osName = System.getProperty("os.name");
+ final String osArch = System.getProperty("os.arch");
+
+ String arch = null;
+
+ final LinkedList nativeLibs = new LinkedList<>();
+
+ if (osName.contains(OS_NAME_WINDOWS)) {
+ switch (osArch) {
+ case "x86":
+ arch = "windows_x86";
+ break;
+
+ case "amd64":
+ arch = "windows_x64";
+ break;
+ }
+
+ nativeLibs.add("libsndfile-1.dll");
+ nativeLibs.add("openal32.dll");
+ nativeLibs.add("sfml-system-2.dll");
+ nativeLibs.add("sfml-window-2.dll");
+ nativeLibs.add("sfml-audio-2.dll");
+ nativeLibs.add("sfml-graphics-2.dll");
+ nativeLibs.add("jsfml.dll");
+ } else if (osName.contains(OS_NAME_LINUX)) {
+ switch (osArch) {
+ case "x86":
+ case "i386":
+ arch = "linux_x86";
+ break;
+
+ case "amd64":
+ arch = "linux_x64";
+ break;
+ }
+
+ nativeLibs.add("libsfml-system.so");
+ nativeLibs.add("libsfml-window.so");
+ nativeLibs.add("libsfml-graphics.so");
+ nativeLibs.add("libsfml-audio.so");
+ nativeLibs.add("libjsfml.so");
+ } else if (osName.contains(OS_NAME_MACOSX)) {
+ arch = "macosx_universal";
+
+ nativeLibs.add("libfreetype.dylib");
+ nativeLibs.add("libsndfile.dylib");
+ nativeLibs.add("libsfml-system.dylib");
+ nativeLibs.add("libsfml-window.dylib");
+ nativeLibs.add("libsfml-graphics.dylib");
+ nativeLibs.add("libsfml-audio.dylib");
+ nativeLibs.add("libjsfml.jnilib");
+ }
+
+ //Check if the current platform is supported
+ if (arch == null) {
+ throw new JSFMLError("Unsupported platform: " + osName + " " + osArch);
+ }
+
+ //Extract native libraries
+ final String nativeResourcePath = JSFML_BIN_RESOURCE_PATH + arch + "/";
+ final Path nativeLibPath = JSFML_USER_HOME.resolve(arch);
+
+ try {
+ Files.createDirectories(nativeLibPath);
+ } catch (FileAlreadyExistsException ex) {
+ //nevermind
+ } catch (IOException ex) {
+ throw new JSFMLError("Failed to create native library directory: " +
+ nativeLibPath.toString(), ex);
+ }
+
+ for (String lib : nativeLibs) {
+ final Path libFile = nativeLibPath.resolve(lib);
+
+ //Check MD5 hash, don't extract if not necessary
+ boolean md5Equal = false;
+
+ final String md5FileName = lib + MD5_EXT;
+
+ try (final InputStream md5InputStream =
+ SFMLNative.class.getResourceAsStream(nativeResourcePath + md5FileName)) {
+
+ final String md5Jar = readMD5File(md5InputStream);
+ final Path md5File = nativeLibPath.resolve(md5FileName);
+
+ if (Files.isRegularFile(libFile) && Files.isRegularFile(md5File)) {
+ md5Equal = readMD5File(md5File).equals(md5Jar);
+ }
+
+ if (!md5Equal) {
+ try (final OutputStream out = Files.newOutputStream(md5File)) {
+ out.write(md5Jar.getBytes());
+ } catch (IOException ex) {
+ ex.printStackTrace(); //write to stderr
+ }
+ }
+ } catch (IOException ex) {
+ ex.printStackTrace(); //write to stderr
+ }
+
+ if (!md5Equal) {
+ try (final InputStream in = SFMLNative.class.getResourceAsStream(
+ nativeResourcePath + lib)) {
+
+ if (in != null) {
+ StreamUtil.streamToFile(in, libFile);
+ } else {
+ throw new JSFMLError(
+ "Could not find native library in the classpath: " + nativeResourcePath + lib);
+ }
+ } catch (IOException ex) {
+ throw new JSFMLError(
+ "Failed to extract native library: " + libFile.toString(), ex);
+ }
+ } else {
+ //MD5 hashes are equal, no need to extract
+ }
+ }
+
+ //On Linux, add SFML's default install path as a fallback
+ for (String lib : nativeLibs) {
+ System.load(nativeLibPath.resolve(lib).toAbsolutePath().toString());
+ }
+
+ //Initialize
+ nativeInit();
+ }
+ }
+
+ /**
+ * Ensures that a display is available on this system.
+ *
+ * If that is not the case, a {@link HeadlessException} is thrown to indicate that the desired
+ * JSFML feature is not available.
+ */
+ public static void ensureDisplay() {
+ if (GraphicsEnvironment.isHeadless())
+ throw new HeadlessException("This JSFML feature is not available in a headless environment");
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/internal/SFMLNativeObject.java b/lib/jsfml/src/java/org/jsfml/internal/SFMLNativeObject.java
new file mode 100644
index 00000000..149bb6eb
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/internal/SFMLNativeObject.java
@@ -0,0 +1,129 @@
+package org.jsfml.internal;
+
+import java.nio.ByteBuffer;
+import java.nio.LongBuffer;
+
+/**
+ * Abstract base class for classes bound to SFML C++ objects.
+ *
+ * This class serves as a communication interface between native SFML objects and their Java
+ * representations by linking the Java object to the object's native pointer.
+ *
+ * There should be no reason whatsoever to use this class outside of
+ * JSFML itself.
+ */
+@Intercom
+public abstract class SFMLNativeObject {
+ /**
+ * Pointer to the underlying SFML object.
+ */
+ @Intercom
+ private long ptr = 0;
+
+ /**
+ * "Extra Pointers".
+ *
+ * These are pointers dynamically cast to abstract supertypes of the same SFML object.
+ *
+ * Holding these is necessary, because all the C++ type information gets lost in the
+ * process of storing a pointer in a Java long field. When casting them back
+ * to SFML object pointers, the correct virtual table offset has to be used
+ * for calls to methods of abstract types.
+ */
+ @Intercom
+ private final LongBuffer exPtr =
+ ByteBuffer.allocateDirect(ExPtr.NUM << 3).asLongBuffer();
+
+ /**
+ * If this is {@code true}, the underlying object is merely "wrapped" and not
+ * "managed" by JSFML.
+ *
+ * If an object is managed by JSFML, it will be deleted using the delete
+ * operator when the Java object is finalized. Wrapped objects are expected
+ * to be cleaned up by SFML and will simply be abandoned upon finalization.
+ */
+ private boolean wrapped;
+
+ /**
+ * Constructs a JSFML native object by invoking the {@link #nativeCreate()}
+ * method and retrieving a pointer to the SFML object in the JVM heap.
+ */
+ @SuppressWarnings("deprecation")
+ protected SFMLNativeObject() {
+ SFMLNative.loadNativeLibraries();
+
+ ptr = nativeCreate();
+
+ if (ptr == 0)
+ throw new JSFMLError("nativeCreate() yielded a NULL pointer: " + this);
+
+ nativeSetExPtr();
+
+ wrapped = false;
+ }
+
+ /**
+ * Wraps an JSFML native object around an already existing native SFML object.
+ *
+ * @param wrap the pointer to the native SFML object in the JNI heap.
+ * @deprecated Use of this constructor may cause undefined behaviour and is not supported.
+ */
+ @Deprecated
+ @SuppressWarnings("deprecation")
+ protected SFMLNativeObject(long wrap) {
+ SFMLNative.loadNativeLibraries();
+
+ if (wrap == 0)
+ throw new JSFMLError("Tried to wrap around a NULL pointer: " + this);
+
+ ptr = wrap;
+ nativeSetExPtr();
+
+ wrapped = true;
+ }
+
+ final void setJavaManaged(boolean javaManaged) {
+ wrapped = !javaManaged;
+ }
+
+ /**
+ * Creates a new native SFML object of the represented SFML class in the JVM memory heap.
+ *
+ * @return the pointer to the newly created native SFML object.
+ * @deprecated Use of this method may cause undefined behaviour and is not supported.
+ */
+ @Deprecated
+ protected abstract long nativeCreate();
+
+ /**
+ * This method is expected to fill the extra pointers array, if any.
+ *
+ * It is called after the object has been created or wrapped around an already
+ * existing pointer.
+ *
+ * @deprecated Use of this method may cause undefined behaviour and is not supported.
+ */
+ @Deprecated
+ protected abstract void nativeSetExPtr();
+
+ /**
+ * Deletes the underlying SFML object.
+ *
+ * @deprecated Use of this method may cause undefined behaviour and is not supported.
+ */
+ @Deprecated
+ protected abstract void nativeDelete();
+
+ @Override
+ @SuppressWarnings("deprecation")
+ protected void finalize() throws Throwable {
+ if (!wrapped && ptr != 0)
+ nativeDelete();
+
+ ptr = 0;
+ for (int i = 0; i < ExPtr.NUM; i++)
+ exPtr.put(i, 0);
+
+ super.finalize();
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/internal/StreamUtil.java b/lib/jsfml/src/java/org/jsfml/internal/StreamUtil.java
new file mode 100644
index 00000000..208a0b3d
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/internal/StreamUtil.java
@@ -0,0 +1,65 @@
+package org.jsfml.internal;
+
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+/**
+ * Provides stream utility functions used by JSFML-internal file reading and writing methods.
+ */
+public class StreamUtil {
+ private final static int BUFFER_SIZE = 16384;
+
+ /**
+ * Fully reads an input stream into a byte array.
+ *
+ * This method does not close the stream when done.
+ *
+ * @param inputStream the input stream to read.
+ * @return the bytes read from the stream.
+ * @throws IOException if an error occurs in the process.
+ */
+ public static byte[] readStream(InputStream inputStream) throws IOException {
+ byte[] buffer = new byte[BUFFER_SIZE];
+ ByteArrayOutputStream out = new ByteArrayOutputStream(BUFFER_SIZE);
+
+ for (int n = inputStream.read(buffer); n > 0; n = inputStream.read(buffer))
+ out.write(buffer, 0, n);
+
+ return out.toByteArray();
+ }
+
+ /**
+ * Fully reads a file into a byte array.
+ *
+ * @param path the path to the file to read.
+ * @return the bytes read from the file.
+ * @throws IOException if an error occurs in the process.
+ */
+ public static byte[] readFile(Path path) throws IOException {
+ try (final InputStream in = Files.newInputStream(path)) {
+ return readStream(in);
+ }
+ }
+
+ /**
+ * Fully streams an input stream into a file.
+ *
+ * This method does not close the stream when done.
+ *
+ * @param inputStream the input stream to read.
+ * @param path the file to write to.
+ * @throws IOException if an error occurs in the process.
+ */
+ public static void streamToFile(InputStream inputStream, Path path) throws IOException {
+ if (inputStream == null)
+ throw new IOException("The input stream is null");
+
+ final byte[] buffer = new byte[BUFFER_SIZE];
+ try (final OutputStream out = Files.newOutputStream(path)) {
+ for (int n = inputStream.read(buffer); n > 0; n = inputStream.read(buffer)) {
+ out.write(buffer, 0, n);
+ }
+ }
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/internal/UnsafeOperations.java b/lib/jsfml/src/java/org/jsfml/internal/UnsafeOperations.java
new file mode 100644
index 00000000..6ccd5c26
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/internal/UnsafeOperations.java
@@ -0,0 +1,30 @@
+package org.jsfml.internal;
+
+/**
+ * Provides inherently unsafe operations on native SFML objects.
+ *
+ * These need to be public in order to maintain JSFML's package structure, but should by no means
+ * used outside of JSFML.
+ */
+public final class UnsafeOperations {
+ /**
+ * Flags an SFML object as Java managed or unmanaged. Java managed objects will be destroyed using the
+ * {@link SFMLNativeObject#nativeDelete()} method when this object gets finalized.
+ *
+ * This is used for JSFML to differentiate between explicitly self-constructed SFML objects
+ * (using {@code new}) and SFML objects that are managed by other SFML objects, but require
+ * a Java representation.
+ *
+ * Wrong use of this method will make the application prone to crashes and memory leaks,
+ * so handle with extreme care.
+ *
+ * @param object The SFML object wrapper.
+ * @param managed Whether or not this object is managed by JSFML.
+ */
+ public static void manageSFMLObject(SFMLNativeObject object, boolean managed) {
+ object.setJavaManaged(managed);
+ }
+
+ private UnsafeOperations() {
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/internal/package-info.java b/lib/jsfml/src/java/org/jsfml/internal/package-info.java
new file mode 100644
index 00000000..bfe21980
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/internal/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains classes, interfaces and annotations meant for internal use only.
+ */
+package org.jsfml.internal;
diff --git a/lib/jsfml/src/java/org/jsfml/system/Clock.java b/lib/jsfml/src/java/org/jsfml/system/Clock.java
new file mode 100644
index 00000000..7991db17
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/system/Clock.java
@@ -0,0 +1,36 @@
+package org.jsfml.system;
+
+/**
+ * Provides functionality for time measurement.
+ */
+public class Clock {
+ private long t0;
+
+ /**
+ * Constructs a clock and starts it.
+ */
+ public Clock() {
+ t0 = System.nanoTime();
+ }
+
+ /**
+ * Gets the elapsed time since the clock was created or last restarted.
+ *
+ * @return the elapsed time since the clock was created or last restarted.
+ */
+ public Time getElapsedTime() {
+ long dt = System.nanoTime() - t0;
+ return Time.getMicroseconds(dt / 1000L);
+ }
+
+ /**
+ * Yields the elapsed time and restarts the clock.
+ *
+ * @return the elapsed time since the clock was created or last restarted.
+ */
+ public final Time restart() {
+ Time dt = getElapsedTime();
+ t0 = System.nanoTime();
+ return dt;
+ }
+}
diff --git a/lib/jsfml/src/java/org/jsfml/system/Time.java b/lib/jsfml/src/java/org/jsfml/system/Time.java
new file mode 100644
index 00000000..949eb603
--- /dev/null
+++ b/lib/jsfml/src/java/org/jsfml/system/Time.java
@@ -0,0 +1,156 @@
+package org.jsfml.system;
+
+import java.io.Serializable;
+
+/**
+ * Represents a time period and provides functionality to convert between
+ * various time units, as well as arithmetic operations on time intervals.
+ */
+public final strictfp class Time implements Comparable
setText(java.lang.String)
method instead.