Compare commits
86 Commits
TechDemo
...
falling-sa
Author | SHA1 | Date | |
---|---|---|---|
71250104ea | |||
51752f95f9 | |||
175f092673 | |||
59129f95c9 | |||
efff41a6db | |||
30879a1241 | |||
9fc1a21191
|
|||
4f620b7261
|
|||
6f90bf345b
|
|||
2328f2ae3a
|
|||
15b5d367b4
|
|||
ca2014802a
|
|||
539a61e854
|
|||
a3760d7425
|
|||
d33b48578d
|
|||
a6fd81ba1e
|
|||
82872c7cf3
|
|||
54c66d28d6
|
|||
78a1c25554
|
|||
a03c783fc9
|
|||
0a45613e45
|
|||
5fb4c601ff
|
|||
020802a89c
|
|||
0f909039fe
|
|||
15f741bc04
|
|||
80541eafc3
|
|||
0f60d45ffa
|
|||
fbc803d6e2
|
|||
dccfcc9419 | |||
c2a2cc074a | |||
1ee9a55d19 | |||
a338a00f1d | |||
9a326603cd | |||
d7afe39f00
|
|||
0264e512ab
|
|||
e47fb3c4bd
|
|||
eace6733ce
|
|||
085f602427
|
|||
737b495fc4
|
|||
e58007ea11 | |||
ae2980c9de | |||
3879e5ffac | |||
47eb9fa5af | |||
bf49687ab6 | |||
b3ae829383 | |||
b374e9a736 | |||
531a8c99c3
|
|||
6fb7e7fc04
|
|||
20dccf3d12
|
|||
32851b8fb0
|
|||
a95bdf1efe
|
|||
e0a03cad1d
|
|||
2532e80f6a
|
|||
3c3f3816df
|
|||
2d3d250f92
|
|||
c49fdfa5ff
|
|||
9d7f69892b
|
|||
7ecdfdfb4d
|
|||
4332a78221
|
|||
ef572c43c7
|
|||
f28c765e3f
|
|||
f4311fb27c
|
|||
abd8d9eebb
|
|||
a9a21ce664
|
|||
bd5a1fa04e
|
|||
2d55d4db51
|
|||
d438d2aa14
|
|||
d3c5011063
|
|||
10d271059c
|
|||
acef9d32df
|
|||
848178b343
|
|||
b1666fa4b9
|
|||
73d24d36f4 | |||
bdb3bff570 | |||
6997bb1104 | |||
eac0a34516 | |||
f9717be412
|
|||
127d1c3d87 | |||
26a35f306c
|
|||
52f3f653d8 | |||
553837f207
|
|||
8c5493f78e
|
|||
fc85eb5658
|
|||
260562310a
|
|||
85edc07c75 | |||
fcf225f9c7 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -30,6 +30,8 @@ build_packages/*
|
||||
!build_packages/NSIS
|
||||
build_packages/NSIS/*
|
||||
!build_packages/NSIS/ProgressiaInstaller.nsi
|
||||
!build_packages/NSIS/logo.ico
|
||||
!build_packages/NSIS/left_side.bmp
|
||||
|
||||
# ... and except build_packages/DEB/template
|
||||
!build_packages/DEB
|
||||
|
@ -16,7 +16,7 @@ temperature mechanics and a parallelism-capable server.
|
||||
- GNU/Linux (x64, arm32 or arm64), Windows XP or later (x64 or x86) or MacOS (x64)
|
||||
- Java 8 or later
|
||||
- OpenGL 2.1 or later
|
||||
- Probably at least 4 GiB RAM
|
||||
- Probably about 0.5 GiB RAM
|
||||
- Less than 1 GiB of storage space
|
||||
|
||||
See [Build Guide](docs/building/BuildGuide.md) for compilation requirements.
|
||||
|
@ -128,6 +128,7 @@ buildWindowsInstaller() {
|
||||
{
|
||||
cp -r 'build/libs/lib' 'build_packages/NSIS/lib' &&
|
||||
cp 'build/libs/Progressia.jar' 'build_packages/NSIS/Progressia.jar' &&
|
||||
cp 'LICENSE' 'build_packages/NSIS/LICENSE.txt' &&
|
||||
echo "------ NSIS ------" &&
|
||||
makensis "$configurationFile" &&
|
||||
echo "---- NSIS END ----" &&
|
||||
@ -144,6 +145,9 @@ buildWindowsInstaller() {
|
||||
if [ -e 'build_packages/NSIS/Progressia.jar' ]; then
|
||||
rm 'build_packages/NSIS/Progressia.jar'
|
||||
fi
|
||||
if [ -e 'build_packages/NSIS/LICENSE.txt' ]; then
|
||||
rm 'build_packages/NSIS/LICENSE.txt'
|
||||
fi
|
||||
echo "Cleaned up"
|
||||
} || {
|
||||
echoerr "Could not clean up after building Windows installer"
|
||||
|
@ -10,16 +10,32 @@
|
||||
;--------------------------------
|
||||
;General
|
||||
|
||||
!define PROJECT_NAME "Progressia"
|
||||
|
||||
; MUI Settings / Icons
|
||||
!define MUI_ICON "logo.ico"
|
||||
;!define MUI_UNICON ;Uninstall icon
|
||||
|
||||
; MUI Settings / Header
|
||||
; !define MUI_HEADERIMAGE
|
||||
; !define MUI_HEADERIMAGE_RIGHT
|
||||
; !define MUI_HEADERIMAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Header\orange-r-nsis.bmp"
|
||||
; !define MUI_HEADERIMAGE_UNBITMAP "${NSISDIR}\Contrib\Graphics\Header\orange-uninstall-r-nsis.bmp"
|
||||
|
||||
; MUI Settings / Wizard
|
||||
!define MUI_WELCOMEFINISHPAGE_BITMAP "left_side.bmp"
|
||||
!define MUI_UNWELCOMEFINISHPAGE_BITMAP "left_side.bmp"
|
||||
|
||||
;Name and file
|
||||
Name "Progressia"
|
||||
OutFile "ProgressiaInstaller.exe"
|
||||
Name "${PROJECT_NAME}"
|
||||
OutFile "${PROJECT_NAME}Installer.exe"
|
||||
Unicode True
|
||||
|
||||
;Default installation folder
|
||||
InstallDir "$PROGRAMFILES\Progressia"
|
||||
InstallDir "$PROGRAMFILES\${PROJECT_NAME}"
|
||||
|
||||
;Get installation folder from registry if available
|
||||
InstallDirRegKey HKLM "Software\Progressia" "Install_Dir"
|
||||
InstallDirRegKey HKLM "Software\${PROJECT_NAME}" ""
|
||||
|
||||
;Request application privileges for Windows Vista
|
||||
RequestExecutionLevel admin
|
||||
@ -33,14 +49,18 @@
|
||||
;Pages
|
||||
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
;!insertmacro MUI_PAGE_LICENSE "${NSISDIR}\Docs\Modern UI\License.txt"
|
||||
!insertmacro MUI_PAGE_LICENSE "LICENSE.txt"
|
||||
!insertmacro MUI_PAGE_COMPONENTS
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
!define MUI_FINISHPAGE_RUN
|
||||
!define MUI_FINISHPAGE_RUN_TEXT "Start ${PROJECT_NAME}"
|
||||
!define MUI_FINISHPAGE_RUN_FUNCTION "LaunchLink"
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
!insertmacro MUI_UNPAGE_WELCOME
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_COMPONENTS
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
!insertmacro MUI_UNPAGE_FINISH
|
||||
|
||||
@ -52,12 +72,15 @@
|
||||
;--------------------------------
|
||||
;Installer Sections
|
||||
|
||||
Section "Install Progressia" SecDummy
|
||||
Section "Install ${PROJECT_NAME}" SEC0000
|
||||
|
||||
SectionIn RO ;Make it read-only
|
||||
SetOutPath "$INSTDIR"
|
||||
SetOverwrite on
|
||||
|
||||
;Files
|
||||
File Progressia.jar
|
||||
File logo.ico
|
||||
File /r lib
|
||||
|
||||
;Store installation folder
|
||||
@ -65,22 +88,24 @@ Section "Install Progressia" SecDummy
|
||||
|
||||
;Create uninstaller
|
||||
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Progressia" "DisplayName" "Progressia (remove only)"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Progressia" "UninstallString" "$INSTDIR\Uninstall.exe"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROJECT_NAME}" "DisplayName" "${PROJECT_NAME} (remove only)"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROJECT_NAME}" "UninstallString" "$INSTDIR\Uninstall.exe"
|
||||
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||
|
||||
SectionEnd
|
||||
|
||||
;--------------------------------
|
||||
;Descriptions
|
||||
Section "Create Desktop Shortcut" SEC0001
|
||||
SetOutPath "$APPDATA\${PROJECT_NAME}"
|
||||
CreateShortCut "$DESKTOP\${PROJECT_NAME}.lnk" "$INSTDIR\${PROJECT_NAME}.jar" "" "$INSTDIR\logo.ico"
|
||||
SectionEnd
|
||||
|
||||
;Language strings
|
||||
LangString DESC_SecDummy ${LANG_ENGLISH} "A test section."
|
||||
Section "Start Menu Shortcuts" SEC0002
|
||||
|
||||
;Assign language strings to sections
|
||||
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${SecDummy} $(DESC_SecDummy)
|
||||
!insertmacro MUI_FUNCTION_DESCRIPTION_END
|
||||
CreateDirectory "$SMPROGRAMS\${PROJECT_NAME}"
|
||||
CreateShortcut "$SMPROGRAMS\${PROJECT_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
|
||||
CreateShortcut "$SMPROGRAMS\${PROJECT_NAME}\${PROJECT_NAME}.lnk" "$INSTDIR\${PROJECT_NAME}.jar" "" "$INSTDIR\logo.ico"
|
||||
|
||||
SectionEnd
|
||||
|
||||
;--------------------------------
|
||||
;Uninstaller Section
|
||||
@ -92,9 +117,45 @@ Section "Uninstall"
|
||||
Delete $INSTDIR\Uninstall.exe
|
||||
Delete $INSTDIR\Progressia.jar
|
||||
Delete $INSTDIR\lib\*.*
|
||||
Delete $INSTDIR\logo.ico
|
||||
|
||||
RMDir /r "$INSTDIR"
|
||||
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Progressia"
|
||||
DeleteRegKey HKLM "Software\Progressia"
|
||||
RMDir $INSTDIR\lib
|
||||
|
||||
Delete $DESKTOP\${PROJECT_NAME}.lnk
|
||||
|
||||
Delete $SMPROGRAMS\${PROJECT_NAME}\Uninstall.lnk
|
||||
Delete $SMPROGRAMS\${PROJECT_NAME}\${PROJECT_NAME}.lnk
|
||||
|
||||
RMDir $INSTDIR
|
||||
|
||||
RMDir /r $SMPROGRAMS\${PROJECT_NAME}
|
||||
|
||||
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROJECT_NAME}"
|
||||
DeleteRegKey HKLM "Software\${PROJECT_NAME}"
|
||||
|
||||
SectionEnd
|
||||
|
||||
Section "un.Remove user data"
|
||||
|
||||
RMDir /r "$APPDATA\${PROJECT_NAME}"
|
||||
|
||||
SectionEnd
|
||||
|
||||
;--------------------------------
|
||||
;Functions
|
||||
|
||||
Function LaunchLink
|
||||
SetOutPath "$APPDATA\${PROJECT_NAME}"
|
||||
ExecShell "" "$INSTDIR\${PROJECT_NAME}.jar"
|
||||
FunctionEnd
|
||||
|
||||
;--------------------------------
|
||||
;Descriptions
|
||||
|
||||
;Language strings
|
||||
LangString DESC_SecDummy ${LANG_ENGLISH} "Install ${PROJECT_NAME}."
|
||||
|
||||
;Assign language strings to sections
|
||||
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${SEC0000} $(DESC_SecDummy)
|
||||
!insertmacro MUI_FUNCTION_DESCRIPTION_END
|
BIN
build_packages/NSIS/left_side.bmp
Normal file
BIN
build_packages/NSIS/left_side.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 151 KiB |
BIN
build_packages/NSIS/logo.ico
Normal file
BIN
build_packages/NSIS/logo.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 187 KiB |
69
docs/CONTRIBUTING.md
Normal file
69
docs/CONTRIBUTING.md
Normal file
@ -0,0 +1,69 @@
|
||||
# Contributing Guidelines
|
||||
|
||||
This document lists conventions adopted by Progressia developers.
|
||||
|
||||
## git
|
||||
|
||||
### Branches
|
||||
Progressia repository contains a `master` branch and several "feature" branches.
|
||||
|
||||
`master` is expected to contain a version of the game suitable for demonstration and forking/branching. Do not commit directly to `master` without OLEGSHA's approval.
|
||||
- `master` must always correctly build without compiler warnings (see below).
|
||||
- `master` must always pass all unit tests.
|
||||
- `master` must always be able to launch successfully.
|
||||
- `master` must always only contain working features.
|
||||
- `master` should not contain excessive debug code.
|
||||
- `master` must always have its code and filenames formatted (see below).
|
||||
|
||||
"Feature" branches are branches dedicated to the development of a single feature. When the feature reaches completion the branch is merged into `master` and removed. Intermediate merges into `master` may occur when some fitting milestone is reached. Intermediate merges from `master` may be done as necessary. Merges between "feature" branches should generally be avoided.
|
||||
|
||||
When beginning work on a new feature, create a new branch based on `master` (or on another "feature" branch if absolutely necessary). Use `all-small-with-dashes` to name the branch: `add-trees` or `rebalance-plastics` are good names. Do not fix unrelated bugs or work on unrelated features in a "feature" branch - create a new one, switch to an existing one or commit directly to `master` if the changes are small enough.
|
||||
|
||||
"Feature" branches may not be formatted properly. Formatting is required before merging into `master` or other branches.
|
||||
|
||||
### Commits
|
||||
- Commits must leave the branch in a state that builds without compiler warnings (see below).
|
||||
- Changes should be grouped in commits semantically. Avoid committing many small related changes in sequence; if necessary, wait and accumulate them. Avoid committing unrelated changes together; if necessary, split staged changes into several commits. This should normally result in about 1-2 commits for a day's work.
|
||||
- Commit bulk changes (renaming, formatting, ...) separately. Don't ever commit whitespace changes outside formatting commits.
|
||||
- Message format:
|
||||
|
||||
```
|
||||
Short description of changes
|
||||
<empty line>
|
||||
- Enumeration of changes
|
||||
- Nest when appropriate
|
||||
- Use dashes only
|
||||
- List not needed for small commits
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
Changed packages for relations, renamed Face to ShapePart
|
||||
|
||||
- Added BlockRelation as an abstract superclass to existing relations
|
||||
- Must be given an absolute "up" direction before use
|
||||
- Moved AbsFace, AbsRelation and BlockRelation to .world.rels
|
||||
- Renamed Face to ShapePart to reduce confusion with AbsFace
|
||||
```
|
||||
|
||||
- Only commit changes described in the commit message. Please double-check staged files before committing.
|
||||
- Avoid merge conflicts. Pull before committing.
|
||||
- Better sign commits than not. See: [git](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work), [GitHub](https://docs.github.com/en/github/authenticating-to-github/managing-commit-signature-verification).
|
||||
|
||||
## Code
|
||||
|
||||
### Warnings
|
||||
Make sure that all committed code contains no compiler warnings. This specifically includes unused imports, unused private members, missing `@Override`s and warnings related to generics.
|
||||
|
||||
Warnings about unknown tokens in `@SuppressWarnings` are temporarily ignored. Please disable them in your IDE.
|
||||
|
||||
### Code Style
|
||||
Formatting code is important.
|
||||
|
||||
- The format is specified within the files inside `/templates_and_presets/eclipse_ide`. Import the specifications into Eclipse or IntelliJ IDEA and use the IDEs' format feature. Alternatively format the code manually in accordance with existing files.
|
||||
- Only use tabs for indentation. Never indent with spaces even when wrapping lines. This is to ensure that indentation does not break when tab width is different.
|
||||
- Don't use `I` prefix for interfaces (not `IDoable` but `Doable`).
|
||||
- Prioritize readability over compactness. Do not hesitate to use (very) long identifiers if they aid comprehension.
|
||||
- Document all mathematics unless it is trivial, especially when using math notation for variable names.
|
||||
- Use proper English when writing comments. Avoid boxes in comments. Use `//` for single-line comments.
|
@ -45,7 +45,7 @@ public class OpenSimplex2S {
|
||||
source[i] = i;
|
||||
for (int i = PSIZE - 1; i >= 0; i--) {
|
||||
seed = seed * 6364136223846793005L + 1442695040888963407L;
|
||||
int r = (int)((seed + 31) % (i + 1));
|
||||
int r = (int) ((seed + 31) % (i + 1));
|
||||
if (r < 0)
|
||||
r += (i + 1);
|
||||
perm[i] = source[r];
|
||||
@ -72,9 +72,9 @@ public class OpenSimplex2S {
|
||||
}
|
||||
|
||||
/**
|
||||
* 2D SuperSimplex noise, with Y pointing down the main diagonal.
|
||||
* Might be better for a 2D sandbox style game, where Y is vertical.
|
||||
* Probably slightly less optimal for heightmaps or continent maps.
|
||||
* 2D SuperSimplex noise, with Y pointing down the main diagonal. Might be
|
||||
* better for a 2D sandbox style game, where Y is vertical. Probably
|
||||
* slightly less optimal for heightmaps or continent maps.
|
||||
*/
|
||||
public double noise2_XBeforeY(double x, double y) {
|
||||
|
||||
@ -86,8 +86,8 @@ public class OpenSimplex2S {
|
||||
}
|
||||
|
||||
/**
|
||||
* 2D SuperSimplex noise base.
|
||||
* Lookup table implementation inspired by DigitalShadow.
|
||||
* 2D SuperSimplex noise base. Lookup table implementation inspired by
|
||||
* DigitalShadow.
|
||||
*/
|
||||
private double noise2_Base(double xs, double ys) {
|
||||
double value = 0;
|
||||
@ -97,11 +97,8 @@ public class OpenSimplex2S {
|
||||
double xsi = xs - xsb, ysi = ys - ysb;
|
||||
|
||||
// Index to point list
|
||||
int a = (int)(xsi + ysi);
|
||||
int index =
|
||||
(a << 2) |
|
||||
(int)(xsi - ysi / 2 + 1 - a / 2.0) << 3 |
|
||||
(int)(ysi - xsi / 2 + 1 - a / 2.0) << 4;
|
||||
int a = (int) (xsi + ysi);
|
||||
int index = (a << 2) | (int) (xsi - ysi / 2 + 1 - a / 2.0) << 3 | (int) (ysi - xsi / 2 + 1 - a / 2.0) << 4;
|
||||
|
||||
double ssi = (xsi + ysi) * -0.211324865405187;
|
||||
double xi = xsi + ssi, yi = ysi + ssi;
|
||||
@ -112,7 +109,8 @@ public class OpenSimplex2S {
|
||||
|
||||
double dx = xi + c.dx, dy = yi + c.dy;
|
||||
double attn = 2.0 / 3.0 - dx * dx - dy * dy;
|
||||
if (attn <= 0) continue;
|
||||
if (attn <= 0)
|
||||
continue;
|
||||
|
||||
int pxm = (xsb + c.xsv) & PMASK, pym = (ysb + c.ysv) & PMASK;
|
||||
Grad2 grad = permGrad2[perm[pxm] ^ pym];
|
||||
@ -126,15 +124,16 @@ public class OpenSimplex2S {
|
||||
}
|
||||
|
||||
/**
|
||||
* 3D Re-oriented 8-point BCC noise, classic orientation
|
||||
* Proper substitute for what 3D SuperSimplex would be,
|
||||
* in light of Forbidden Formulae.
|
||||
* Use noise3_XYBeforeZ or noise3_XZBeforeY instead, wherever appropriate.
|
||||
* 3D Re-oriented 8-point BCC noise, classic orientation Proper substitute
|
||||
* for what 3D SuperSimplex would be, in light of Forbidden Formulae. Use
|
||||
* noise3_XYBeforeZ or noise3_XZBeforeY instead, wherever appropriate.
|
||||
*/
|
||||
public double noise3_Classic(double x, double y, double z) {
|
||||
|
||||
// Re-orient the cubic lattices via rotation, to produce the expected look on cardinal planar slices.
|
||||
// If texturing objects that don't tend to have cardinal plane faces, you could even remove this.
|
||||
// Re-orient the cubic lattices via rotation, to produce the expected
|
||||
// look on cardinal planar slices.
|
||||
// If texturing objects that don't tend to have cardinal plane faces,
|
||||
// you could even remove this.
|
||||
// Orthonormal rotation. Not a skew transform.
|
||||
double r = (2.0 / 3.0) * (x + y + z);
|
||||
double xr = r - x, yr = r - y, zr = r - z;
|
||||
@ -145,15 +144,17 @@ public class OpenSimplex2S {
|
||||
|
||||
/**
|
||||
* 3D Re-oriented 8-point BCC noise, with better visual isotropy in (X, Y).
|
||||
* Recommended for 3D terrain and time-varied animations.
|
||||
* The Z coordinate should always be the "different" coordinate in your use case.
|
||||
* If Y is vertical in world coordinates, call noise3_XYBeforeZ(x, z, Y) or use noise3_XZBeforeY.
|
||||
* If Z is vertical in world coordinates, call noise3_XYBeforeZ(x, y, Z).
|
||||
* For a time varied animation, call noise3_XYBeforeZ(x, y, T).
|
||||
* Recommended for 3D terrain and time-varied animations. The Z coordinate
|
||||
* should always be the "different" coordinate in your use case. If Y is
|
||||
* vertical in world coordinates, call noise3_XYBeforeZ(x, z, Y) or use
|
||||
* noise3_XZBeforeY. If Z is vertical in world coordinates, call
|
||||
* noise3_XYBeforeZ(x, y, Z). For a time varied animation, call
|
||||
* noise3_XYBeforeZ(x, y, T).
|
||||
*/
|
||||
public double noise3_XYBeforeZ(double x, double y, double z) {
|
||||
|
||||
// Re-orient the cubic lattices without skewing, to make X and Y triangular like 2D.
|
||||
// Re-orient the cubic lattices without skewing, to make X and Y
|
||||
// triangular like 2D.
|
||||
// Orthonormal rotation. Not a skew transform.
|
||||
double xy = x + y;
|
||||
double s2 = xy * -0.211324865405187;
|
||||
@ -167,20 +168,23 @@ public class OpenSimplex2S {
|
||||
|
||||
/**
|
||||
* 3D Re-oriented 8-point BCC noise, with better visual isotropy in (X, Z).
|
||||
* Recommended for 3D terrain and time-varied animations.
|
||||
* The Y coordinate should always be the "different" coordinate in your use case.
|
||||
* If Y is vertical in world coordinates, call noise3_XZBeforeY(x, Y, z).
|
||||
* If Z is vertical in world coordinates, call noise3_XZBeforeY(x, Z, y) or use noise3_XYBeforeZ.
|
||||
* For a time varied animation, call noise3_XZBeforeY(x, T, y) or use noise3_XYBeforeZ.
|
||||
* Recommended for 3D terrain and time-varied animations. The Y coordinate
|
||||
* should always be the "different" coordinate in your use case. If Y is
|
||||
* vertical in world coordinates, call noise3_XZBeforeY(x, Y, z). If Z is
|
||||
* vertical in world coordinates, call noise3_XZBeforeY(x, Z, y) or use
|
||||
* noise3_XYBeforeZ. For a time varied animation, call noise3_XZBeforeY(x,
|
||||
* T, y) or use noise3_XYBeforeZ.
|
||||
*/
|
||||
public double noise3_XZBeforeY(double x, double y, double z) {
|
||||
|
||||
// Re-orient the cubic lattices without skewing, to make X and Z triangular like 2D.
|
||||
// Re-orient the cubic lattices without skewing, to make X and Z
|
||||
// triangular like 2D.
|
||||
// Orthonormal rotation. Not a skew transform.
|
||||
double xz = x + z;
|
||||
double s2 = xz * -0.211324865405187;
|
||||
double yy = y * 0.577350269189626;
|
||||
double xr = x + s2 - yy; double zr = z + s2 - yy;
|
||||
double xr = x + s2 - yy;
|
||||
double zr = z + s2 - yy;
|
||||
double yr = xz * 0.577350269189626 + yy;
|
||||
|
||||
// Evaluate both lattices to form a BCC lattice.
|
||||
@ -188,10 +192,10 @@ public class OpenSimplex2S {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate overlapping cubic lattices for 3D Re-oriented BCC noise.
|
||||
* Lookup table implementation inspired by DigitalShadow.
|
||||
* It was actually faster to narrow down the points in the loop itself,
|
||||
* than to build up the index with enough info to isolate 8 points.
|
||||
* Generate overlapping cubic lattices for 3D Re-oriented BCC noise. Lookup
|
||||
* table implementation inspired by DigitalShadow. It was actually faster to
|
||||
* narrow down the points in the loop itself, than to build up the index
|
||||
* with enough info to isolate 8 points.
|
||||
*/
|
||||
private double noise3_BCC(double xr, double yr, double zr) {
|
||||
|
||||
@ -199,9 +203,11 @@ public class OpenSimplex2S {
|
||||
int xrb = fastFloor(xr), yrb = fastFloor(yr), zrb = fastFloor(zr);
|
||||
double xri = xr - xrb, yri = yr - yrb, zri = zr - zrb;
|
||||
|
||||
// Identify which octant of the cube we're in. This determines which cell
|
||||
// in the other cubic lattice we're in, and also narrows down one point on each.
|
||||
int xht = (int)(xri + 0.5), yht = (int)(yri + 0.5), zht = (int)(zri + 0.5);
|
||||
// Identify which octant of the cube we're in. This determines which
|
||||
// cell
|
||||
// in the other cubic lattice we're in, and also narrows down one point
|
||||
// on each.
|
||||
int xht = (int) (xri + 0.5), yht = (int) (yri + 0.5), zht = (int) (zri + 0.5);
|
||||
int index = (xht << 0) | (yht << 1) | (zht << 2);
|
||||
|
||||
// Point contributions
|
||||
@ -230,9 +236,9 @@ public class OpenSimplex2S {
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generate the 2D noise over a large area.
|
||||
* Propagates by flood-fill instead of iterating over a range.
|
||||
* Results may occasionally slightly exceed [-1, 1] due to the grid-snapped pre-generated kernel.
|
||||
* Generate the 2D noise over a large area. Propagates by flood-fill instead
|
||||
* of iterating over a range. Results may occasionally slightly exceed [-1,
|
||||
* 1] due to the grid-snapped pre-generated kernel.
|
||||
*/
|
||||
public void generate2(GenerateContext2D context, double[][] buffer, int x0, int y0) {
|
||||
int height = buffer.length;
|
||||
@ -241,11 +247,12 @@ public class OpenSimplex2S {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the 2D noise over a large area.
|
||||
* Propagates by flood-fill instead of iterating over a range.
|
||||
* Results may occasionally slightly exceed [-1, 1] due to the grid-snapped pre-generated kernel.
|
||||
* Generate the 2D noise over a large area. Propagates by flood-fill instead
|
||||
* of iterating over a range. Results may occasionally slightly exceed [-1,
|
||||
* 1] due to the grid-snapped pre-generated kernel.
|
||||
*/
|
||||
public void generate2(GenerateContext2D context, double[][] buffer, int x0, int y0, int width, int height, int skipX, int skipY) {
|
||||
public void generate2(GenerateContext2D context, double[][] buffer, int x0, int y0, int width, int height,
|
||||
int skipX, int skipY) {
|
||||
Queue<AreaGenLatticePoint2D> queue = new LinkedList<AreaGenLatticePoint2D>();
|
||||
Set<AreaGenLatticePoint2D> seen = new HashSet<AreaGenLatticePoint2D>();
|
||||
|
||||
@ -260,16 +267,19 @@ public class OpenSimplex2S {
|
||||
// - Much faster than computing the kernel equation every time.
|
||||
// You can remove these lines if you find it's the opposite for you.
|
||||
// You'll have to double the bounds again in GenerateContext2D
|
||||
kernel = new double[scaledRadiusY * 2][/*scaledRadiusX * 2*/];
|
||||
kernel = new double[scaledRadiusY * 2][/* scaledRadiusX * 2 */];
|
||||
for (int yy = 0; yy < scaledRadiusY; yy++) {
|
||||
kernel[2 * scaledRadiusY - yy - 1] = kernel[yy] = (double[]) context.kernel[yy].clone();
|
||||
}
|
||||
|
||||
// Get started with one point/vertex.
|
||||
// For some lattices, you might need to try a handful of points in the cell,
|
||||
// or flip a couple of coordinates, to guarantee it or a neighbor contributes.
|
||||
// For some lattices, you might need to try a handful of points in the
|
||||
// cell,
|
||||
// or flip a couple of coordinates, to guarantee it or a neighbor
|
||||
// contributes.
|
||||
// For An* lattices, the base coordinate seems fine.
|
||||
double x0f = x0Skipped * context.xFrequency; double y0f = y0Skipped * context.yFrequency;
|
||||
double x0f = x0Skipped * context.xFrequency;
|
||||
double y0f = y0Skipped * context.yFrequency;
|
||||
double x0s = context.orientation.s00 * x0f + context.orientation.s01 * y0f;
|
||||
double y0s = context.orientation.s10 * x0f + context.orientation.s11 * y0f;
|
||||
int x0sb = fastFloor(x0s), y0sb = fastFloor(y0s);
|
||||
@ -287,11 +297,16 @@ public class OpenSimplex2S {
|
||||
Grad2 grad = context.orientation.gradients[perm[perm[pxm] ^ pym]];
|
||||
double gx = grad.dx * context.xFrequency;
|
||||
double gy = grad.dy * context.yFrequency;
|
||||
double gOff = 0.5 * (gx + gy); // to correct for (0.5, 0.5)-offset kernel
|
||||
double gOff = 0.5 * (gx + gy); // to correct for (0.5, 0.5)-offset
|
||||
// kernel
|
||||
|
||||
// Contribution kernel bounds
|
||||
int yy0 = destPointY - scaledRadiusY; if (yy0 < y0Skipped) yy0 = y0Skipped;
|
||||
int yy1 = destPointY + scaledRadiusY; if (yy1 > y0 + height) yy1 = y0 + height;
|
||||
int yy0 = destPointY - scaledRadiusY;
|
||||
if (yy0 < y0Skipped)
|
||||
yy0 = y0Skipped;
|
||||
int yy1 = destPointY + scaledRadiusY;
|
||||
if (yy1 > y0 + height)
|
||||
yy1 = y0 + height;
|
||||
|
||||
// For each row of the contribution circle,
|
||||
for (int yy = yy0; yy < yy1; yy++) {
|
||||
@ -300,16 +315,22 @@ public class OpenSimplex2S {
|
||||
|
||||
// Set up bounds so we only loop over what we need to
|
||||
int thisScaledRadiusX = context.kernelBounds[ky];
|
||||
int xx0 = destPointX - thisScaledRadiusX; if (xx0 < x0Skipped) xx0 = x0Skipped;
|
||||
int xx1 = destPointX + thisScaledRadiusX; if (xx1 > x0 + width) xx1 = x0 + width;
|
||||
int xx0 = destPointX - thisScaledRadiusX;
|
||||
if (xx0 < x0Skipped)
|
||||
xx0 = x0Skipped;
|
||||
int xx1 = destPointX + thisScaledRadiusX;
|
||||
if (xx1 > x0 + width)
|
||||
xx1 = x0 + width;
|
||||
|
||||
// For each point on that row
|
||||
for (int xx = xx0; xx < xx1; xx++) {
|
||||
int dx = xx - destPointX;
|
||||
int kx = dx + scaledRadiusX;
|
||||
|
||||
// gOff accounts for our choice to offset the pre-generated kernel by (0.5, 0.5) to avoid the zero center.
|
||||
// I found almost no difference in performance using gOff vs not (under 1ns diff per value on my system)
|
||||
// gOff accounts for our choice to offset the pre-generated
|
||||
// kernel by (0.5, 0.5) to avoid the zero center.
|
||||
// I found almost no difference in performance using gOff vs
|
||||
// not (under 1ns diff per value on my system)
|
||||
double extrapolation = gx * dx + gy * dy + gOff;
|
||||
buffer[yy - y0][xx - x0] += kernel[ky][kx] * extrapolation;
|
||||
|
||||
@ -318,13 +339,14 @@ public class OpenSimplex2S {
|
||||
|
||||
// For each neighbor of the point
|
||||
for (int i = 0; i < NEIGHBOR_MAP_2D.length; i++) {
|
||||
AreaGenLatticePoint2D neighbor = new AreaGenLatticePoint2D(context,
|
||||
point.xsv + NEIGHBOR_MAP_2D[i][0], point.ysv + NEIGHBOR_MAP_2D[i][1]);
|
||||
AreaGenLatticePoint2D neighbor = new AreaGenLatticePoint2D(context, point.xsv + NEIGHBOR_MAP_2D[i][0],
|
||||
point.ysv + NEIGHBOR_MAP_2D[i][1]);
|
||||
|
||||
// If it's in range of the buffer region and not seen before
|
||||
if (neighbor.destPointX + scaledRadiusX >= x0Skipped && neighbor.destPointX - scaledRadiusX <= x0 + width - 1
|
||||
&& neighbor.destPointY + scaledRadiusY >= y0Skipped && neighbor.destPointY - scaledRadiusY <= y0 + height - 1
|
||||
&& !seen.contains(neighbor)) {
|
||||
if (neighbor.destPointX + scaledRadiusX >= x0Skipped
|
||||
&& neighbor.destPointX - scaledRadiusX <= x0 + width - 1
|
||||
&& neighbor.destPointY + scaledRadiusY >= y0Skipped
|
||||
&& neighbor.destPointY - scaledRadiusY <= y0 + height - 1 && !seen.contains(neighbor)) {
|
||||
|
||||
// Add it to the queue so we can process it at some point
|
||||
queue.add(neighbor);
|
||||
@ -337,9 +359,9 @@ public class OpenSimplex2S {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the 3D noise over a large area/volume.
|
||||
* Propagates by flood-fill instead of iterating over a range.
|
||||
* Results may occasionally slightly exceed [-1, 1] due to the grid-snapped pre-generated kernel.
|
||||
* Generate the 3D noise over a large area/volume. Propagates by flood-fill
|
||||
* instead of iterating over a range. Results may occasionally slightly
|
||||
* exceed [-1, 1] due to the grid-snapped pre-generated kernel.
|
||||
*/
|
||||
public void generate3(GenerateContext3D context, double[][][] buffer, int x0, int y0, int z0) {
|
||||
int depth = buffer.length;
|
||||
@ -349,11 +371,12 @@ public class OpenSimplex2S {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the 3D noise over a large area/volume.
|
||||
* Propagates by flood-fill instead of iterating over a range.
|
||||
* Results may occasionally slightly exceed [-1, 1] due to the grid-snapped pre-generated kernel.
|
||||
* Generate the 3D noise over a large area/volume. Propagates by flood-fill
|
||||
* instead of iterating over a range. Results may occasionally slightly
|
||||
* exceed [-1, 1] due to the grid-snapped pre-generated kernel.
|
||||
*/
|
||||
public void generate3(GenerateContext3D context, double[][][] buffer, int x0, int y0, int z0, int width, int height, int depth, int skipX, int skipY, int skipZ) {
|
||||
public void generate3(GenerateContext3D context, double[][][] buffer, int x0, int y0, int z0, int width, int height,
|
||||
int depth, int skipX, int skipY, int skipZ) {
|
||||
Queue<AreaGenLatticePoint3D> queue = new LinkedList<AreaGenLatticePoint3D>();
|
||||
Set<AreaGenLatticePoint3D> seen = new HashSet<AreaGenLatticePoint3D>();
|
||||
|
||||
@ -365,8 +388,10 @@ public class OpenSimplex2S {
|
||||
|
||||
// Quaternion multiplication for rotation.
|
||||
// https://blog.molecular-matters.com/2013/05/24/a-faster-quaternion-vector-multiplication/
|
||||
double qx = context.orientation.qx, qy = context.orientation.qy, qz = context.orientation.qz, qw = context.orientation.qw;
|
||||
double x0f = x0Skipped * context.xFrequency, y0f = y0Skipped * context.yFrequency, z0f = z0Skipped * context.zFrequency;
|
||||
double qx = context.orientation.qx, qy = context.orientation.qy, qz = context.orientation.qz,
|
||||
qw = context.orientation.qw;
|
||||
double x0f = x0Skipped * context.xFrequency, y0f = y0Skipped * context.yFrequency,
|
||||
z0f = z0Skipped * context.zFrequency;
|
||||
double tx = 2 * (qy * z0f - qz * y0f);
|
||||
double ty = 2 * (qz * x0f - qx * z0f);
|
||||
double tz = 2 * (qx * y0f - qy * x0f);
|
||||
@ -392,11 +417,16 @@ public class OpenSimplex2S {
|
||||
double gx = grad.dx * context.xFrequency;
|
||||
double gy = grad.dy * context.yFrequency;
|
||||
double gz = grad.dz * context.zFrequency;
|
||||
double gOff = 0.5 * (gx + gy + gz); // to correct for (0.5, 0.5, 0.5)-offset kernel
|
||||
double gOff = 0.5 * (gx + gy + gz); // to correct for (0.5, 0.5,
|
||||
// 0.5)-offset kernel
|
||||
|
||||
// Contribution kernel bounds.
|
||||
int zz0 = destPointZ - scaledRadiusZ; if (zz0 < z0Skipped) zz0 = z0Skipped;
|
||||
int zz1 = destPointZ + scaledRadiusZ; if (zz1 > z0 + depth) zz1 = z0 + depth;
|
||||
int zz0 = destPointZ - scaledRadiusZ;
|
||||
if (zz0 < z0Skipped)
|
||||
zz0 = z0Skipped;
|
||||
int zz1 = destPointZ + scaledRadiusZ;
|
||||
if (zz1 > z0 + depth)
|
||||
zz1 = z0 + depth;
|
||||
|
||||
// For each x/y slice of the contribution sphere,
|
||||
for (int zz = zz0; zz < zz1; zz++) {
|
||||
@ -405,8 +435,12 @@ public class OpenSimplex2S {
|
||||
|
||||
// Set up bounds so we only loop over what we need to
|
||||
int thisScaledRadiusY = context.kernelBoundsY[kz];
|
||||
int yy0 = destPointY - thisScaledRadiusY; if (yy0 < y0Skipped) yy0 = y0Skipped;
|
||||
int yy1 = destPointY + thisScaledRadiusY; if (yy1 > y0 + height) yy1 = y0 + height;
|
||||
int yy0 = destPointY - thisScaledRadiusY;
|
||||
if (yy0 < y0Skipped)
|
||||
yy0 = y0Skipped;
|
||||
int yy1 = destPointY + thisScaledRadiusY;
|
||||
if (yy1 > y0 + height)
|
||||
yy1 = y0 + height;
|
||||
|
||||
// For each row of the contribution circle,
|
||||
for (int yy = yy0; yy < yy1; yy++) {
|
||||
@ -415,15 +449,21 @@ public class OpenSimplex2S {
|
||||
|
||||
// Set up bounds so we only loop over what we need to
|
||||
int thisScaledRadiusX = context.kernelBoundsX[kz][ky];
|
||||
int xx0 = destPointX - thisScaledRadiusX; if (xx0 < x0Skipped) xx0 = x0Skipped;
|
||||
int xx1 = destPointX + thisScaledRadiusX; if (xx1 > x0 + width) xx1 = x0 + width;
|
||||
int xx0 = destPointX - thisScaledRadiusX;
|
||||
if (xx0 < x0Skipped)
|
||||
xx0 = x0Skipped;
|
||||
int xx1 = destPointX + thisScaledRadiusX;
|
||||
if (xx1 > x0 + width)
|
||||
xx1 = x0 + width;
|
||||
|
||||
// For each point on that row
|
||||
for (int xx = xx0; xx < xx1; xx++) {
|
||||
int dx = xx - destPointX;
|
||||
int kx = dx + scaledRadiusX;
|
||||
|
||||
// gOff accounts for our choice to offset the pre-generated kernel by (0.5, 0.5, 0.5) to avoid the zero center.
|
||||
// gOff accounts for our choice to offset the
|
||||
// pre-generated kernel by (0.5, 0.5, 0.5) to avoid the
|
||||
// zero center.
|
||||
double extrapolation = gx * dx + gy * dy + gz * dz + gOff;
|
||||
buffer[zz - z0][yy - y0][xx - x0] += kernel[kz][ky][kx] * extrapolation;
|
||||
|
||||
@ -435,13 +475,16 @@ public class OpenSimplex2S {
|
||||
for (int i = 0; i < NEIGHBOR_MAP_3D[0].length; i++) {
|
||||
int l = point.lattice;
|
||||
AreaGenLatticePoint3D neighbor = new AreaGenLatticePoint3D(context,
|
||||
point.xsv + NEIGHBOR_MAP_3D[l][i][0], point.ysv + NEIGHBOR_MAP_3D[l][i][1], point.zsv + NEIGHBOR_MAP_3D[l][i][2], 1 ^ l);
|
||||
point.xsv + NEIGHBOR_MAP_3D[l][i][0], point.ysv + NEIGHBOR_MAP_3D[l][i][1],
|
||||
point.zsv + NEIGHBOR_MAP_3D[l][i][2], 1 ^ l);
|
||||
|
||||
// If it's in range of the buffer region and not seen before
|
||||
if (neighbor.destPointX + scaledRadiusX >= x0Skipped && neighbor.destPointX - scaledRadiusX <= x0 + width - 1
|
||||
&& neighbor.destPointY + scaledRadiusY >= y0Skipped && neighbor.destPointY - scaledRadiusY <= y0 + height - 1
|
||||
&& neighbor.destPointZ + scaledRadiusZ >= z0Skipped && neighbor.destPointZ - scaledRadiusZ <= z0 + depth - 1
|
||||
&& !seen.contains(neighbor)) {
|
||||
if (neighbor.destPointX + scaledRadiusX >= x0Skipped
|
||||
&& neighbor.destPointX - scaledRadiusX <= x0 + width - 1
|
||||
&& neighbor.destPointY + scaledRadiusY >= y0Skipped
|
||||
&& neighbor.destPointY - scaledRadiusY <= y0 + height - 1
|
||||
&& neighbor.destPointZ + scaledRadiusZ >= z0Skipped
|
||||
&& neighbor.destPointZ - scaledRadiusZ <= z0 + depth - 1 && !seen.contains(neighbor)) {
|
||||
|
||||
// Add it to the queue so we can process it at some point
|
||||
queue.add(neighbor);
|
||||
@ -458,7 +501,7 @@ public class OpenSimplex2S {
|
||||
*/
|
||||
|
||||
private static int fastFloor(double x) {
|
||||
int xi = (int)x;
|
||||
int xi = (int) x;
|
||||
return x < xi ? xi - 1 : xi;
|
||||
}
|
||||
|
||||
@ -475,11 +518,35 @@ public class OpenSimplex2S {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int i1, j1, i2, j2;
|
||||
if ((i & 1) == 0) {
|
||||
if ((i & 2) == 0) { i1 = -1; j1 = 0; } else { i1 = 1; j1 = 0; }
|
||||
if ((i & 4) == 0) { i2 = 0; j2 = -1; } else { i2 = 0; j2 = 1; }
|
||||
if ((i & 2) == 0) {
|
||||
i1 = -1;
|
||||
j1 = 0;
|
||||
} else {
|
||||
if ((i & 2) != 0) { i1 = 2; j1 = 1; } else { i1 = 0; j1 = 1; }
|
||||
if ((i & 4) != 0) { i2 = 1; j2 = 2; } else { i2 = 1; j2 = 0; }
|
||||
i1 = 1;
|
||||
j1 = 0;
|
||||
}
|
||||
if ((i & 4) == 0) {
|
||||
i2 = 0;
|
||||
j2 = -1;
|
||||
} else {
|
||||
i2 = 0;
|
||||
j2 = 1;
|
||||
}
|
||||
} else {
|
||||
if ((i & 2) != 0) {
|
||||
i1 = 2;
|
||||
j1 = 1;
|
||||
} else {
|
||||
i1 = 0;
|
||||
j1 = 1;
|
||||
}
|
||||
if ((i & 4) != 0) {
|
||||
i2 = 1;
|
||||
j2 = 2;
|
||||
} else {
|
||||
i2 = 1;
|
||||
j2 = 0;
|
||||
}
|
||||
}
|
||||
LOOKUP_2D[i * 4 + 0] = new LatticePoint2D(0, 0);
|
||||
LOOKUP_2D[i * 4 + 1] = new LatticePoint2D(1, 1);
|
||||
@ -489,10 +556,15 @@ public class OpenSimplex2S {
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int i1, j1, k1, i2, j2, k2;
|
||||
i1 = (i >> 0) & 1; j1 = (i >> 1) & 1; k1 = (i >> 2) & 1;
|
||||
i2 = i1 ^ 1; j2 = j1 ^ 1; k2 = k1 ^ 1;
|
||||
i1 = (i >> 0) & 1;
|
||||
j1 = (i >> 1) & 1;
|
||||
k1 = (i >> 2) & 1;
|
||||
i2 = i1 ^ 1;
|
||||
j2 = j1 ^ 1;
|
||||
k2 = k1 ^ 1;
|
||||
|
||||
// The two points within this octant, one from each of the two cubic half-lattices.
|
||||
// The two points within this octant, one from each of the two cubic
|
||||
// half-lattices.
|
||||
LatticePoint3D c0 = new LatticePoint3D(i1, j1, k1, 0);
|
||||
LatticePoint3D c1 = new LatticePoint3D(i1 + i2, j1 + j2, k1 + k2, 1);
|
||||
|
||||
@ -525,27 +597,36 @@ public class OpenSimplex2S {
|
||||
c1.nextOnFailure = c1.nextOnSuccess = c2;
|
||||
|
||||
// If c2 is in range, then we know c3 and c4 are not.
|
||||
c2.nextOnFailure = c3; c2.nextOnSuccess = c5;
|
||||
c3.nextOnFailure = c4; c3.nextOnSuccess = c4;
|
||||
c2.nextOnFailure = c3;
|
||||
c2.nextOnSuccess = c5;
|
||||
c3.nextOnFailure = c4;
|
||||
c3.nextOnSuccess = c4;
|
||||
|
||||
// If c4 is in range, then we know c5 is not.
|
||||
c4.nextOnFailure = c5; c4.nextOnSuccess = c6;
|
||||
c4.nextOnFailure = c5;
|
||||
c4.nextOnSuccess = c6;
|
||||
c5.nextOnFailure = c5.nextOnSuccess = c6;
|
||||
|
||||
// If c6 is in range, then we know c7 and c8 are not.
|
||||
c6.nextOnFailure = c7; c6.nextOnSuccess = c9;
|
||||
c7.nextOnFailure = c8; c7.nextOnSuccess = c8;
|
||||
c6.nextOnFailure = c7;
|
||||
c6.nextOnSuccess = c9;
|
||||
c7.nextOnFailure = c8;
|
||||
c7.nextOnSuccess = c8;
|
||||
|
||||
// If c8 is in range, then we know c9 is not.
|
||||
c8.nextOnFailure = c9; c8.nextOnSuccess = cA;
|
||||
c8.nextOnFailure = c9;
|
||||
c8.nextOnSuccess = cA;
|
||||
c9.nextOnFailure = c9.nextOnSuccess = cA;
|
||||
|
||||
// If cA is in range, then we know cB and cC are not.
|
||||
cA.nextOnFailure = cB; cA.nextOnSuccess = cD;
|
||||
cB.nextOnFailure = cC; cB.nextOnSuccess = cC;
|
||||
cA.nextOnFailure = cB;
|
||||
cA.nextOnSuccess = cD;
|
||||
cB.nextOnFailure = cC;
|
||||
cB.nextOnSuccess = cC;
|
||||
|
||||
// If cC is in range, then we know cD is not.
|
||||
cC.nextOnFailure = cD; cC.nextOnSuccess = null;
|
||||
cC.nextOnFailure = cD;
|
||||
cC.nextOnSuccess = null;
|
||||
cD.nextOnFailure = cD.nextOnSuccess = null;
|
||||
|
||||
LOOKUP_3D[i] = c0;
|
||||
@ -554,28 +635,24 @@ public class OpenSimplex2S {
|
||||
}
|
||||
|
||||
// Hexagon surrounding each vertex.
|
||||
private static final int[][] NEIGHBOR_MAP_2D = {
|
||||
{ 1, 0 }, { 1, 1 }, { 0, 1 }, { 0, -1 }, { -1, -1 }, { -1, 0 }
|
||||
};
|
||||
private static final int[][] NEIGHBOR_MAP_2D = { { 1, 0 }, { 1, 1 }, { 0, 1 }, { 0, -1 }, { -1, -1 }, { -1, 0 } };
|
||||
|
||||
// Cube surrounding each vertex.
|
||||
// Alternates between half-lattices.
|
||||
private static final int[][][] NEIGHBOR_MAP_3D = {
|
||||
{
|
||||
{ 1024, 1024, 1024 }, { 1025, 1024, 1024 }, { 1024, 1025, 1024 }, { 1025, 1025, 1024 },
|
||||
{ 1024, 1024, 1025 }, { 1025, 1024, 1025 }, { 1024, 1025, 1025 }, { 1025, 1025, 1025 }
|
||||
},
|
||||
{
|
||||
{ -1024, -1024, -1024 }, { -1025, -1024, 1024 }, { -1024, -1025, -1024 }, { -1025, -1025, -1024 },
|
||||
{ -1024, -1024, -1025 }, { -1025, -1024, -1025 }, { -1024, -1025, -1025 }, { -1025, -1025, 1025 }
|
||||
},
|
||||
};
|
||||
{ { 1024, 1024, 1024 }, { 1025, 1024, 1024 }, { 1024, 1025, 1024 }, { 1025, 1025, 1024 },
|
||||
{ 1024, 1024, 1025 }, { 1025, 1024, 1025 }, { 1024, 1025, 1025 }, { 1025, 1025, 1025 } },
|
||||
{ { -1024, -1024, -1024 }, { -1025, -1024, 1024 }, { -1024, -1025, -1024 }, { -1025, -1025, -1024 },
|
||||
{ -1024, -1024, -1025 }, { -1025, -1024, -1025 }, { -1024, -1025, -1025 },
|
||||
{ -1025, -1025, 1025 } }, };
|
||||
|
||||
private static class LatticePoint2D {
|
||||
int xsv, ysv;
|
||||
double dx, dy;
|
||||
|
||||
public LatticePoint2D(int xsv, int ysv) {
|
||||
this.xsv = xsv; this.ysv = ysv;
|
||||
this.xsv = xsv;
|
||||
this.ysv = ysv;
|
||||
double ssv = (xsv + ysv) * -0.211324865405187;
|
||||
this.dx = -xsv - ssv;
|
||||
this.dy = -ysv - ssv;
|
||||
@ -586,29 +663,42 @@ public class OpenSimplex2S {
|
||||
public double dxr, dyr, dzr;
|
||||
public int xrv, yrv, zrv;
|
||||
LatticePoint3D nextOnFailure, nextOnSuccess;
|
||||
|
||||
public LatticePoint3D(int xrv, int yrv, int zrv, int lattice) {
|
||||
this.dxr = -xrv + lattice * 0.5; this.dyr = -yrv + lattice * 0.5; this.dzr = -zrv + lattice * 0.5;
|
||||
this.xrv = xrv + lattice * 1024; this.yrv = yrv + lattice * 1024; this.zrv = zrv + lattice * 1024;
|
||||
this.dxr = -xrv + lattice * 0.5;
|
||||
this.dyr = -yrv + lattice * 0.5;
|
||||
this.dzr = -zrv + lattice * 0.5;
|
||||
this.xrv = xrv + lattice * 1024;
|
||||
this.yrv = yrv + lattice * 1024;
|
||||
this.zrv = zrv + lattice * 1024;
|
||||
}
|
||||
}
|
||||
|
||||
private static class AreaGenLatticePoint2D {
|
||||
int xsv, ysv;
|
||||
int destPointX, destPointY;
|
||||
public AreaGenLatticePoint2D(GenerateContext2D context, int xsv, int ysv) {
|
||||
this.xsv = xsv; this.ysv = ysv;
|
||||
|
||||
//Matrix multiplication for inverse rotation. Simplex skew transforms have always been shorthand for matrices.
|
||||
this.destPointX = (int)Math.ceil((context.orientation.t00 * xsv + context.orientation.t01 * ysv) * context.xFrequencyInverse);
|
||||
this.destPointY = (int)Math.ceil((context.orientation.t10 * xsv + context.orientation.t11 * ysv) * context.yFrequencyInverse);
|
||||
public AreaGenLatticePoint2D(GenerateContext2D context, int xsv, int ysv) {
|
||||
this.xsv = xsv;
|
||||
this.ysv = ysv;
|
||||
|
||||
// Matrix multiplication for inverse rotation. Simplex skew
|
||||
// transforms have always been shorthand for matrices.
|
||||
this.destPointX = (int) Math
|
||||
.ceil((context.orientation.t00 * xsv + context.orientation.t01 * ysv) * context.xFrequencyInverse);
|
||||
this.destPointY = (int) Math
|
||||
.ceil((context.orientation.t10 * xsv + context.orientation.t11 * ysv) * context.yFrequencyInverse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return xsv * 7841 + ysv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof AreaGenLatticePoint2D)) return false;
|
||||
if (!(obj instanceof AreaGenLatticePoint2D))
|
||||
return false;
|
||||
AreaGenLatticePoint2D other = (AreaGenLatticePoint2D) obj;
|
||||
return (other.xsv == this.xsv && other.ysv == this.ysv);
|
||||
}
|
||||
@ -617,15 +707,20 @@ public class OpenSimplex2S {
|
||||
private static class AreaGenLatticePoint3D {
|
||||
int xsv, ysv, zsv, lattice;
|
||||
int destPointX, destPointY, destPointZ;
|
||||
|
||||
public AreaGenLatticePoint3D(GenerateContext3D context, int xsv, int ysv, int zsv, int lattice) {
|
||||
this.xsv = xsv; this.ysv = ysv; this.zsv = zsv; this.lattice = lattice;
|
||||
this.xsv = xsv;
|
||||
this.ysv = ysv;
|
||||
this.zsv = zsv;
|
||||
this.lattice = lattice;
|
||||
double xr = (xsv - lattice * 1024.5);
|
||||
double yr = (ysv - lattice * 1024.5);
|
||||
double zr = (zsv - lattice * 1024.5);
|
||||
|
||||
// Quaternion multiplication for inverse rotation.
|
||||
// https://blog.molecular-matters.com/2013/05/24/a-faster-quaternion-vector-multiplication/
|
||||
double qx = -context.orientation.qx, qy = -context.orientation.qy, qz = -context.orientation.qz, qw = context.orientation.qw;
|
||||
double qx = -context.orientation.qx, qy = -context.orientation.qy, qz = -context.orientation.qz,
|
||||
qw = context.orientation.qw;
|
||||
double tx = 2 * (qy * zr - qz * yr);
|
||||
double ty = 2 * (qz * xr - qx * zr);
|
||||
double tz = 2 * (qx * yr - qy * xr);
|
||||
@ -633,19 +728,23 @@ public class OpenSimplex2S {
|
||||
double yrr = yr + qw * ty + (qz * tx - qx * tz);
|
||||
double zrr = zr + qw * tz + (qx * ty - qy * tx);
|
||||
|
||||
this.destPointX = (int)Math.ceil(xrr * context.xFrequencyInverse);
|
||||
this.destPointY = (int)Math.ceil(yrr * context.yFrequencyInverse);
|
||||
this.destPointZ = (int)Math.ceil(zrr * context.zFrequencyInverse);
|
||||
this.destPointX = (int) Math.ceil(xrr * context.xFrequencyInverse);
|
||||
this.destPointY = (int) Math.ceil(yrr * context.yFrequencyInverse);
|
||||
this.destPointZ = (int) Math.ceil(zrr * context.zFrequencyInverse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return xsv * 2122193 + ysv * 2053 + zsv * 2 + lattice;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof AreaGenLatticePoint3D)) return false;
|
||||
if (!(obj instanceof AreaGenLatticePoint3D))
|
||||
return false;
|
||||
AreaGenLatticePoint3D other = (AreaGenLatticePoint3D) obj;
|
||||
return (other.xsv == this.xsv && other.ysv == this.ysv && other.zsv == this.zsv && other.lattice == this.lattice);
|
||||
return (other.xsv == this.xsv && other.ysv == this.ysv && other.zsv == this.zsv
|
||||
&& other.lattice == this.lattice);
|
||||
}
|
||||
}
|
||||
|
||||
@ -661,7 +760,8 @@ public class OpenSimplex2S {
|
||||
int[] kernelBounds;
|
||||
LatticeOrientation2D orientation;
|
||||
|
||||
public GenerateContext2D(LatticeOrientation2D orientation, double xFrequency, double yFrequency, double amplitude) {
|
||||
public GenerateContext2D(LatticeOrientation2D orientation, double xFrequency, double yFrequency,
|
||||
double amplitude) {
|
||||
|
||||
// These will be used by every call to generate
|
||||
this.orientation = orientation;
|
||||
@ -674,19 +774,18 @@ public class OpenSimplex2S {
|
||||
double preciseScaledRadiusY = Math.sqrt(2.0 / 3.0) * yFrequencyInverse;
|
||||
|
||||
// 0.25 because we offset center by 0.5
|
||||
this.scaledRadiusX = (int)Math.ceil(preciseScaledRadiusX + 0.25);
|
||||
this.scaledRadiusY = (int)Math.ceil(preciseScaledRadiusY + 0.25);
|
||||
this.scaledRadiusX = (int) Math.ceil(preciseScaledRadiusX + 0.25);
|
||||
this.scaledRadiusY = (int) Math.ceil(preciseScaledRadiusY + 0.25);
|
||||
|
||||
// So will these
|
||||
kernel = new double[scaledRadiusY/* * 2*/][];
|
||||
kernel = new double[scaledRadiusY/* * 2 */][];
|
||||
kernelBounds = new int[scaledRadiusY * 2];
|
||||
for (int yy = 0; yy < scaledRadiusY * 2; yy++) {
|
||||
|
||||
// Pre-generate boundary of circle
|
||||
kernelBounds[yy] = (int)Math.ceil(
|
||||
Math.sqrt(1.0
|
||||
- (yy + 0.5 - scaledRadiusY) * (yy + 0.5 - scaledRadiusY) / (scaledRadiusY * scaledRadiusY)
|
||||
) * scaledRadiusX);
|
||||
kernelBounds[yy] = (int) Math.ceil(Math.sqrt(
|
||||
1.0 - (yy + 0.5 - scaledRadiusY) * (yy + 0.5 - scaledRadiusY) / (scaledRadiusY * scaledRadiusY))
|
||||
* scaledRadiusX);
|
||||
|
||||
if (yy < scaledRadiusY) {
|
||||
kernel[yy] = new double[scaledRadiusX * 2];
|
||||
@ -703,7 +802,7 @@ public class OpenSimplex2S {
|
||||
kernel[yy][xx] = 0.0;
|
||||
}
|
||||
}
|
||||
} /* else kernel[yy] = kernel[2 * scaledRadiusY - yy - 1];*/
|
||||
} /* else kernel[yy] = kernel[2 * scaledRadiusY - yy - 1]; */
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -724,7 +823,8 @@ public class OpenSimplex2S {
|
||||
int[][] kernelBoundsX;
|
||||
LatticeOrientation3D orientation;
|
||||
|
||||
public GenerateContext3D(LatticeOrientation3D orientation, double xFrequency, double yFrequency, double zFrequency, double amplitude) {
|
||||
public GenerateContext3D(LatticeOrientation3D orientation, double xFrequency, double yFrequency,
|
||||
double zFrequency, double amplitude) {
|
||||
|
||||
// These will be used by every call to generate
|
||||
this.orientation = orientation;
|
||||
@ -740,9 +840,9 @@ public class OpenSimplex2S {
|
||||
double preciseScaledRadiusZ = Math.sqrt(0.75) * zFrequencyInverse;
|
||||
|
||||
// 0.25 because we offset center by 0.5
|
||||
this.scaledRadiusX = (int)Math.ceil(preciseScaledRadiusX + 0.25);
|
||||
this.scaledRadiusY = (int)Math.ceil(preciseScaledRadiusY + 0.25);
|
||||
this.scaledRadiusZ = (int)Math.ceil(preciseScaledRadiusZ + 0.25);
|
||||
this.scaledRadiusX = (int) Math.ceil(preciseScaledRadiusX + 0.25);
|
||||
this.scaledRadiusY = (int) Math.ceil(preciseScaledRadiusY + 0.25);
|
||||
this.scaledRadiusZ = (int) Math.ceil(preciseScaledRadiusZ + 0.25);
|
||||
|
||||
// So will these
|
||||
kernel = new double[scaledRadiusZ * 2][][];
|
||||
@ -751,9 +851,9 @@ public class OpenSimplex2S {
|
||||
for (int zz = 0; zz < scaledRadiusZ * 2; zz++) {
|
||||
|
||||
// Pre-generate boundary of sphere
|
||||
kernelBoundsY[zz] = (int)Math.ceil(
|
||||
Math.sqrt(1.0 - (zz + 0.5 - scaledRadiusZ) * (zz + 0.5 - scaledRadiusZ)
|
||||
/ (scaledRadiusZ * scaledRadiusZ)) * scaledRadiusY);
|
||||
kernelBoundsY[zz] = (int) Math.ceil(Math.sqrt(
|
||||
1.0 - (zz + 0.5 - scaledRadiusZ) * (zz + 0.5 - scaledRadiusZ) / (scaledRadiusZ * scaledRadiusZ))
|
||||
* scaledRadiusY);
|
||||
|
||||
if (zz < scaledRadiusZ) {
|
||||
kernel[zz] = new double[scaledRadiusY * 2][];
|
||||
@ -767,11 +867,12 @@ public class OpenSimplex2S {
|
||||
for (int yy = 0; yy < scaledRadiusY * 2; yy++) {
|
||||
|
||||
// Pre-generate boundary of sphere
|
||||
kernelBoundsX[zz][yy] = (int)Math.ceil(
|
||||
Math.sqrt(1.0
|
||||
- (yy + 0.5 - scaledRadiusY) * (yy + 0.5 - scaledRadiusY) / (scaledRadiusY * scaledRadiusY)
|
||||
- (zz + 0.5 - scaledRadiusZ) * (zz + 0.5 - scaledRadiusZ) / (scaledRadiusZ * scaledRadiusZ)
|
||||
) * scaledRadiusX);
|
||||
kernelBoundsX[zz][yy] = (int) Math.ceil(Math.sqrt(1.0
|
||||
- (yy + 0.5 - scaledRadiusY) * (yy + 0.5 - scaledRadiusY)
|
||||
/ (scaledRadiusY * scaledRadiusY)
|
||||
- (zz + 0.5 - scaledRadiusZ) * (zz + 0.5 - scaledRadiusZ)
|
||||
/ (scaledRadiusZ * scaledRadiusZ))
|
||||
* scaledRadiusX);
|
||||
|
||||
if (yy < scaledRadiusY) {
|
||||
kernel[zz][yy] = new double[scaledRadiusX * 2];
|
||||
@ -790,7 +891,8 @@ public class OpenSimplex2S {
|
||||
}
|
||||
}
|
||||
|
||||
} else kernel[zz][yy] = kernel[zz][2 * scaledRadiusY - yy - 1];
|
||||
} else
|
||||
kernel[zz][yy] = kernel[zz][2 * scaledRadiusY - yy - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -798,40 +900,50 @@ public class OpenSimplex2S {
|
||||
}
|
||||
|
||||
public enum LatticeOrientation2D {
|
||||
// Simplex skew transforms have always been shorthand for the matrices they represent.
|
||||
// But when we bake the rotation into the skew transform, we need to use the general form.
|
||||
Standard(GRADIENTS_2D,
|
||||
1.366025403784439, 0.366025403784439, 0.366025403784439, 1.366025403784439,
|
||||
0.788675134594813, -0.211324865405187, -0.211324865405187, 0.788675134594813),
|
||||
XBeforeY(GRADIENTS_2D_X_BEFORE_Y,
|
||||
0.7071067811865476, 1.224744871380249, -0.7071067811865476, 1.224744871380249,
|
||||
0.7071067811865476, -0.7071067811865476, 0.40824829046764305, 0.40824829046764305);
|
||||
// Simplex skew transforms have always been shorthand for the matrices
|
||||
// they represent.
|
||||
// But when we bake the rotation into the skew transform, we need to use
|
||||
// the general form.
|
||||
Standard(GRADIENTS_2D, 1.366025403784439, 0.366025403784439, 0.366025403784439, 1.366025403784439,
|
||||
0.788675134594813, -0.211324865405187, -0.211324865405187,
|
||||
0.788675134594813), XBeforeY(GRADIENTS_2D_X_BEFORE_Y, 0.7071067811865476, 1.224744871380249,
|
||||
-0.7071067811865476, 1.224744871380249, 0.7071067811865476, -0.7071067811865476,
|
||||
0.40824829046764305, 0.40824829046764305);
|
||||
|
||||
Grad2[] gradients;
|
||||
double s00, s01, s10, s11;
|
||||
double t00, t01, t10, t11;
|
||||
|
||||
private LatticeOrientation2D(Grad2[] gradients,
|
||||
double s00, double s01, double s10, double s11,
|
||||
double t00, double t01, double t10, double t11) {
|
||||
private LatticeOrientation2D(Grad2[] gradients, double s00, double s01, double s10, double s11, double t00,
|
||||
double t01, double t10, double t11) {
|
||||
this.gradients = gradients;
|
||||
this.s00 = s00; this.s01 = s01; this.s10 = s10; this.s11 = s11;
|
||||
this.t00 = t00; this.t01 = t01; this.t10 = t10; this.t11 = t11;
|
||||
this.s00 = s00;
|
||||
this.s01 = s01;
|
||||
this.s10 = s10;
|
||||
this.s11 = s11;
|
||||
this.t00 = t00;
|
||||
this.t01 = t01;
|
||||
this.t10 = t10;
|
||||
this.t11 = t11;
|
||||
}
|
||||
}
|
||||
|
||||
public enum LatticeOrientation3D {
|
||||
// Quaternions for 3D. Could use matrices, but I already wrote this code before I moved them into here.
|
||||
Classic(GRADIENTS_3D_CLASSIC, 0.577350269189626, 0.577350269189626, 0.577350269189626, 0),
|
||||
XYBeforeZ(GRADIENTS_3D_XY_BEFORE_Z, 0.3250575836718682, -0.3250575836718682, 0, 0.8880738339771154),
|
||||
XZBeforeY(GRADIENTS_3D_XZ_BEFORE_Y, -0.3250575836718682, 0, 0.3250575836718682, 0.8880738339771154);
|
||||
// Quaternions for 3D. Could use matrices, but I already wrote this code
|
||||
// before I moved them into here.
|
||||
Classic(GRADIENTS_3D_CLASSIC, 0.577350269189626, 0.577350269189626, 0.577350269189626, 0), XYBeforeZ(
|
||||
GRADIENTS_3D_XY_BEFORE_Z, 0.3250575836718682, -0.3250575836718682, 0, 0.8880738339771154), XZBeforeY(
|
||||
GRADIENTS_3D_XZ_BEFORE_Y, -0.3250575836718682, 0, 0.3250575836718682, 0.8880738339771154);
|
||||
|
||||
Grad3[] gradients;
|
||||
double qx, qy, qz, qw;
|
||||
|
||||
private LatticeOrientation3D(Grad3[] gradients, double qx, double qy, double qz, double qw) {
|
||||
this.gradients = gradients;
|
||||
this.qx = qx; this.qy = qy; this.qz = qz; this.qw = qw;
|
||||
this.qx = qx;
|
||||
this.qy = qy;
|
||||
this.qz = qz;
|
||||
this.qw = qw;
|
||||
}
|
||||
}
|
||||
|
||||
@ -841,15 +953,20 @@ public class OpenSimplex2S {
|
||||
|
||||
public static class Grad2 {
|
||||
double dx, dy;
|
||||
|
||||
public Grad2(double dx, double dy) {
|
||||
this.dx = dx; this.dy = dy;
|
||||
this.dx = dx;
|
||||
this.dy = dy;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Grad3 {
|
||||
double dx, dy, dz;
|
||||
|
||||
public Grad3(double dx, double dy, double dz) {
|
||||
this.dx = dx; this.dy = dy; this.dz = dz;
|
||||
this.dx = dx;
|
||||
this.dy = dy;
|
||||
this.dz = dz;
|
||||
}
|
||||
}
|
||||
|
||||
@ -861,35 +978,23 @@ public class OpenSimplex2S {
|
||||
|
||||
GRADIENTS_2D = new Grad2[PSIZE];
|
||||
GRADIENTS_2D_X_BEFORE_Y = new Grad2[PSIZE];
|
||||
Grad2[] grad2 = {
|
||||
new Grad2( 0.130526192220052, 0.99144486137381),
|
||||
new Grad2( 0.38268343236509, 0.923879532511287),
|
||||
new Grad2( 0.608761429008721, 0.793353340291235),
|
||||
new Grad2( 0.793353340291235, 0.608761429008721),
|
||||
new Grad2( 0.923879532511287, 0.38268343236509),
|
||||
new Grad2( 0.99144486137381, 0.130526192220051),
|
||||
new Grad2( 0.99144486137381, -0.130526192220051),
|
||||
new Grad2( 0.923879532511287, -0.38268343236509),
|
||||
new Grad2( 0.793353340291235, -0.60876142900872),
|
||||
new Grad2( 0.608761429008721, -0.793353340291235),
|
||||
new Grad2( 0.38268343236509, -0.923879532511287),
|
||||
new Grad2( 0.130526192220052, -0.99144486137381),
|
||||
new Grad2(-0.130526192220052, -0.99144486137381),
|
||||
new Grad2(-0.38268343236509, -0.923879532511287),
|
||||
new Grad2(-0.608761429008721, -0.793353340291235),
|
||||
new Grad2(-0.793353340291235, -0.608761429008721),
|
||||
new Grad2(-0.923879532511287, -0.38268343236509),
|
||||
new Grad2(-0.99144486137381, -0.130526192220052),
|
||||
new Grad2(-0.99144486137381, 0.130526192220051),
|
||||
new Grad2(-0.923879532511287, 0.38268343236509),
|
||||
new Grad2(-0.793353340291235, 0.608761429008721),
|
||||
new Grad2(-0.608761429008721, 0.793353340291235),
|
||||
new Grad2(-0.38268343236509, 0.923879532511287),
|
||||
new Grad2(-0.130526192220052, 0.99144486137381)
|
||||
};
|
||||
Grad2[] grad2 = { new Grad2(0.130526192220052, 0.99144486137381),
|
||||
new Grad2(0.38268343236509, 0.923879532511287), new Grad2(0.608761429008721, 0.793353340291235),
|
||||
new Grad2(0.793353340291235, 0.608761429008721), new Grad2(0.923879532511287, 0.38268343236509),
|
||||
new Grad2(0.99144486137381, 0.130526192220051), new Grad2(0.99144486137381, -0.130526192220051),
|
||||
new Grad2(0.923879532511287, -0.38268343236509), new Grad2(0.793353340291235, -0.60876142900872),
|
||||
new Grad2(0.608761429008721, -0.793353340291235), new Grad2(0.38268343236509, -0.923879532511287),
|
||||
new Grad2(0.130526192220052, -0.99144486137381), new Grad2(-0.130526192220052, -0.99144486137381),
|
||||
new Grad2(-0.38268343236509, -0.923879532511287), new Grad2(-0.608761429008721, -0.793353340291235),
|
||||
new Grad2(-0.793353340291235, -0.608761429008721), new Grad2(-0.923879532511287, -0.38268343236509),
|
||||
new Grad2(-0.99144486137381, -0.130526192220052), new Grad2(-0.99144486137381, 0.130526192220051),
|
||||
new Grad2(-0.923879532511287, 0.38268343236509), new Grad2(-0.793353340291235, 0.608761429008721),
|
||||
new Grad2(-0.608761429008721, 0.793353340291235), new Grad2(-0.38268343236509, 0.923879532511287),
|
||||
new Grad2(-0.130526192220052, 0.99144486137381) };
|
||||
Grad2[] grad2XBeforeY = new Grad2[grad2.length];
|
||||
for (int i = 0; i < grad2.length; i++) {
|
||||
grad2[i].dx /= N2; grad2[i].dy /= N2;
|
||||
grad2[i].dx /= N2;
|
||||
grad2[i].dy /= N2;
|
||||
|
||||
// Unrotated gradients for XBeforeY 2D
|
||||
double xx = grad2[i].dx * 0.7071067811865476;
|
||||
@ -905,77 +1010,59 @@ public class OpenSimplex2S {
|
||||
GRADIENTS_3D_CLASSIC = new Grad3[PSIZE];
|
||||
GRADIENTS_3D_XY_BEFORE_Z = new Grad3[PSIZE];
|
||||
GRADIENTS_3D_XZ_BEFORE_Y = new Grad3[PSIZE];
|
||||
Grad3[] grad3 = {
|
||||
new Grad3(-2.22474487139, -2.22474487139, -1.0),
|
||||
Grad3[] grad3 = { new Grad3(-2.22474487139, -2.22474487139, -1.0),
|
||||
new Grad3(-2.22474487139, -2.22474487139, 1.0),
|
||||
new Grad3(-3.0862664687972017, -1.1721513422464978, 0.0),
|
||||
new Grad3(-1.1721513422464978, -3.0862664687972017, 0.0),
|
||||
new Grad3(-2.22474487139, -1.0, -2.22474487139),
|
||||
new Grad3(-2.22474487139, 1.0, -2.22474487139),
|
||||
new Grad3(-2.22474487139, -1.0, -2.22474487139), new Grad3(-2.22474487139, 1.0, -2.22474487139),
|
||||
new Grad3(-1.1721513422464978, 0.0, -3.0862664687972017),
|
||||
new Grad3(-3.0862664687972017, 0.0, -1.1721513422464978),
|
||||
new Grad3(-2.22474487139, -1.0, 2.22474487139),
|
||||
new Grad3(-2.22474487139, 1.0, 2.22474487139),
|
||||
new Grad3(-2.22474487139, -1.0, 2.22474487139), new Grad3(-2.22474487139, 1.0, 2.22474487139),
|
||||
new Grad3(-3.0862664687972017, 0.0, 1.1721513422464978),
|
||||
new Grad3(-1.1721513422464978, 0.0, 3.0862664687972017),
|
||||
new Grad3(-2.22474487139, 2.22474487139, -1.0),
|
||||
new Grad3(-2.22474487139, 2.22474487139, 1.0),
|
||||
new Grad3(-1.1721513422464978, 3.0862664687972017, 0.0),
|
||||
new Grad3(-1.1721513422464978, 0.0, 3.0862664687972017), new Grad3(-2.22474487139, 2.22474487139, -1.0),
|
||||
new Grad3(-2.22474487139, 2.22474487139, 1.0), new Grad3(-1.1721513422464978, 3.0862664687972017, 0.0),
|
||||
new Grad3(-3.0862664687972017, 1.1721513422464978, 0.0),
|
||||
new Grad3(-1.0, -2.22474487139, -2.22474487139),
|
||||
new Grad3( 1.0, -2.22474487139, -2.22474487139),
|
||||
new Grad3( 0.0, -3.0862664687972017, -1.1721513422464978),
|
||||
new Grad3( 0.0, -1.1721513422464978, -3.0862664687972017),
|
||||
new Grad3(-1.0, -2.22474487139, 2.22474487139),
|
||||
new Grad3( 1.0, -2.22474487139, 2.22474487139),
|
||||
new Grad3( 0.0, -1.1721513422464978, 3.0862664687972017),
|
||||
new Grad3( 0.0, -3.0862664687972017, 1.1721513422464978),
|
||||
new Grad3(-1.0, 2.22474487139, -2.22474487139),
|
||||
new Grad3( 1.0, 2.22474487139, -2.22474487139),
|
||||
new Grad3( 0.0, 1.1721513422464978, -3.0862664687972017),
|
||||
new Grad3( 0.0, 3.0862664687972017, -1.1721513422464978),
|
||||
new Grad3(-1.0, 2.22474487139, 2.22474487139),
|
||||
new Grad3( 1.0, 2.22474487139, 2.22474487139),
|
||||
new Grad3( 0.0, 3.0862664687972017, 1.1721513422464978),
|
||||
new Grad3( 0.0, 1.1721513422464978, 3.0862664687972017),
|
||||
new Grad3( 2.22474487139, -2.22474487139, -1.0),
|
||||
new Grad3( 2.22474487139, -2.22474487139, 1.0),
|
||||
new Grad3( 1.1721513422464978, -3.0862664687972017, 0.0),
|
||||
new Grad3( 3.0862664687972017, -1.1721513422464978, 0.0),
|
||||
new Grad3( 2.22474487139, -1.0, -2.22474487139),
|
||||
new Grad3( 2.22474487139, 1.0, -2.22474487139),
|
||||
new Grad3( 3.0862664687972017, 0.0, -1.1721513422464978),
|
||||
new Grad3( 1.1721513422464978, 0.0, -3.0862664687972017),
|
||||
new Grad3( 2.22474487139, -1.0, 2.22474487139),
|
||||
new Grad3( 2.22474487139, 1.0, 2.22474487139),
|
||||
new Grad3( 1.1721513422464978, 0.0, 3.0862664687972017),
|
||||
new Grad3( 3.0862664687972017, 0.0, 1.1721513422464978),
|
||||
new Grad3( 2.22474487139, 2.22474487139, -1.0),
|
||||
new Grad3( 2.22474487139, 2.22474487139, 1.0),
|
||||
new Grad3( 3.0862664687972017, 1.1721513422464978, 0.0),
|
||||
new Grad3( 1.1721513422464978, 3.0862664687972017, 0.0)
|
||||
};
|
||||
new Grad3(-1.0, -2.22474487139, -2.22474487139), new Grad3(1.0, -2.22474487139, -2.22474487139),
|
||||
new Grad3(0.0, -3.0862664687972017, -1.1721513422464978),
|
||||
new Grad3(0.0, -1.1721513422464978, -3.0862664687972017),
|
||||
new Grad3(-1.0, -2.22474487139, 2.22474487139), new Grad3(1.0, -2.22474487139, 2.22474487139),
|
||||
new Grad3(0.0, -1.1721513422464978, 3.0862664687972017),
|
||||
new Grad3(0.0, -3.0862664687972017, 1.1721513422464978), new Grad3(-1.0, 2.22474487139, -2.22474487139),
|
||||
new Grad3(1.0, 2.22474487139, -2.22474487139), new Grad3(0.0, 1.1721513422464978, -3.0862664687972017),
|
||||
new Grad3(0.0, 3.0862664687972017, -1.1721513422464978), new Grad3(-1.0, 2.22474487139, 2.22474487139),
|
||||
new Grad3(1.0, 2.22474487139, 2.22474487139), new Grad3(0.0, 3.0862664687972017, 1.1721513422464978),
|
||||
new Grad3(0.0, 1.1721513422464978, 3.0862664687972017), new Grad3(2.22474487139, -2.22474487139, -1.0),
|
||||
new Grad3(2.22474487139, -2.22474487139, 1.0), new Grad3(1.1721513422464978, -3.0862664687972017, 0.0),
|
||||
new Grad3(3.0862664687972017, -1.1721513422464978, 0.0), new Grad3(2.22474487139, -1.0, -2.22474487139),
|
||||
new Grad3(2.22474487139, 1.0, -2.22474487139), new Grad3(3.0862664687972017, 0.0, -1.1721513422464978),
|
||||
new Grad3(1.1721513422464978, 0.0, -3.0862664687972017), new Grad3(2.22474487139, -1.0, 2.22474487139),
|
||||
new Grad3(2.22474487139, 1.0, 2.22474487139), new Grad3(1.1721513422464978, 0.0, 3.0862664687972017),
|
||||
new Grad3(3.0862664687972017, 0.0, 1.1721513422464978), new Grad3(2.22474487139, 2.22474487139, -1.0),
|
||||
new Grad3(2.22474487139, 2.22474487139, 1.0), new Grad3(3.0862664687972017, 1.1721513422464978, 0.0),
|
||||
new Grad3(1.1721513422464978, 3.0862664687972017, 0.0) };
|
||||
Grad3[] grad3Classic = new Grad3[grad3.length];
|
||||
Grad3[] grad3XYBeforeZ = new Grad3[grad3.length];
|
||||
Grad3[] grad3XZBeforeY = new Grad3[grad3.length];
|
||||
for (int i = 0; i < grad3.length; i++) {
|
||||
grad3[i].dx /= N3; grad3[i].dy /= N3; grad3[i].dz /= N3;
|
||||
grad3[i].dx /= N3;
|
||||
grad3[i].dy /= N3;
|
||||
grad3[i].dz /= N3;
|
||||
double gxr = grad3[i].dx, gyr = grad3[i].dy, gzr = grad3[i].dz;
|
||||
|
||||
// Unrotated gradients for classic 3D
|
||||
double grr = (2.0 / 3.0) * (gxr + gyr + gzr);
|
||||
// double dx = grr - gxr, dy = grr - gyr, dz = grr - gzr;
|
||||
grad3Classic[i] = new Grad3( grr - gxr, grr - gyr, grr - gzr );
|
||||
// double dx = grr - gxr, dy = grr - gyr, dz = grr - gzr;
|
||||
grad3Classic[i] = new Grad3(grr - gxr, grr - gyr, grr - gzr);
|
||||
|
||||
// Unrotated gradients for XYBeforeZ 3D
|
||||
double s2 = (gxr + gyr) * -0.211324865405187;
|
||||
double zz = gzr * 0.577350269189626;
|
||||
grad3XYBeforeZ[i] = new Grad3( gxr + s2 + zz, gyr + s2 + zz, (gzr - gxr - gyr) * 0.577350269189626 );
|
||||
grad3XYBeforeZ[i] = new Grad3(gxr + s2 + zz, gyr + s2 + zz, (gzr - gxr - gyr) * 0.577350269189626);
|
||||
|
||||
// Unrotated gradients for plane-first 3D
|
||||
s2 = (gxr + gzr) * -0.211324865405187;
|
||||
double yy = gyr * 0.577350269189626;
|
||||
grad3XZBeforeY[i] = new Grad3( gxr + s2 + yy, (gyr - gxr - gzr) * 0.577350269189626, gzr + s2 + yy );
|
||||
grad3XZBeforeY[i] = new Grad3(gxr + s2 + yy, (gyr - gxr - gzr) * 0.577350269189626, gzr + s2 + yy);
|
||||
}
|
||||
for (int i = 0; i < PSIZE; i++) {
|
||||
GRADIENTS_3D[i] = grad3[i % grad3.length];
|
||||
|
@ -611,8 +611,7 @@ public class ArrayUtil {
|
||||
int end = offset + length;
|
||||
if (end > arrayLength || offset < 0)
|
||||
throw new IllegalArgumentException(
|
||||
"Array contains [0; " + arrayLength + "), requested [" + offset + "; " + end + ")"
|
||||
);
|
||||
"Array contains [0; " + arrayLength + "), requested [" + offset + "; " + end + ")");
|
||||
|
||||
return length;
|
||||
}
|
||||
@ -628,8 +627,7 @@ public class ArrayUtil {
|
||||
|
||||
if (end > arrayLength || start < 0)
|
||||
throw new IllegalArgumentException(
|
||||
"Array contains [0; " + arrayLength + "), requested [" + start + "; " + end + ")"
|
||||
);
|
||||
"Array contains [0; " + arrayLength + "), requested [" + start + "; " + end + ")");
|
||||
|
||||
return end;
|
||||
}
|
||||
|
@ -30,18 +30,8 @@ public class PrimitiveUtil {
|
||||
private static final Map<Class<?>, Object> PRIMITIVE_TO_NULL = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (
|
||||
Class<?> boxed : new Class<?>[] {
|
||||
Boolean.class,
|
||||
Byte.class,
|
||||
Short.class,
|
||||
Character.class,
|
||||
Integer.class,
|
||||
Long.class,
|
||||
Float.class,
|
||||
Double.class
|
||||
}
|
||||
) {
|
||||
for (Class<?> boxed : new Class<?>[] { Boolean.class, Byte.class, Short.class, Character.class, Integer.class,
|
||||
Long.class, Float.class, Double.class }) {
|
||||
try {
|
||||
PRIMITIVE_TO_BOXED.put((Class<?>) boxed.getField("TYPE").get(null), boxed);
|
||||
} catch (Exception e) {
|
||||
|
@ -40,8 +40,7 @@ import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Contains static methods to create {@link Stream Streams} that synchronize
|
||||
* their
|
||||
* <a href=
|
||||
* their <a href=
|
||||
* "https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#StreamOps">
|
||||
* terminal operations</a> on a given monitor.
|
||||
*
|
||||
@ -1070,21 +1069,18 @@ public class SyncStreams {
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the given {@link Stream} to make all
|
||||
* <a href=
|
||||
* Wraps the given {@link Stream} to make all <a href=
|
||||
* "https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#StreamOps">
|
||||
* terminal operations</a> acquire the provided monitor's lock before
|
||||
* execution. Intermediate operations
|
||||
* return streams that are also synchronized on the same object. The created
|
||||
* stream will behave identically
|
||||
* to the provided stream in all other aspects. Use this to synchronize
|
||||
* access to stream's source.
|
||||
* execution. Intermediate operations return streams that are also
|
||||
* synchronized on the same object. The created stream will behave
|
||||
* identically to the provided stream in all other aspects. Use this to
|
||||
* synchronize access to stream's source.
|
||||
* <p>
|
||||
* <i>The returned {@code Stream}'s {@link Stream#iterator() iterator()} and
|
||||
* {@link Stream#spliterator()
|
||||
* spliterator()} methods return regular non-synchronized iterators and
|
||||
* spliterators respectively</i>. It
|
||||
* is the user's responsibility to avoid concurrency issues:
|
||||
* {@link Stream#spliterator() spliterator()} methods return regular
|
||||
* non-synchronized iterators and spliterators respectively</i>. It is the
|
||||
* user's responsibility to avoid concurrency issues:
|
||||
*
|
||||
* <pre>
|
||||
* synchronized (stream.getMonitor()) {
|
||||
@ -1103,14 +1099,17 @@ public class SyncStreams {
|
||||
* stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException
|
||||
* </pre>
|
||||
*
|
||||
* @param <T> the class of objects in the Stream
|
||||
* @param stream the stream to wrap.
|
||||
* @param monitor the object that the stream will use for synchronization.
|
||||
* When {@code null}, the stream
|
||||
* will synchronize on itself.
|
||||
* @param <T>
|
||||
* the class of objects in the Stream
|
||||
* @param stream
|
||||
* the stream to wrap.
|
||||
* @param monitor
|
||||
* the object that the stream will use for synchronization. When
|
||||
* {@code null}, the stream will synchronize on itself.
|
||||
* @return a {@link SyncStream SyncStream<T>} synchronized on
|
||||
* {@code monitor} and backed by {@code stream}.
|
||||
* @throws NullPointerException if {@code stream == null}.
|
||||
* @throws NullPointerException
|
||||
* if {@code stream == null}.
|
||||
*/
|
||||
public static <T> SyncStream<T> synchronizedStream(Stream<T> stream, Object monitor) {
|
||||
Objects.requireNonNull(stream, "stream cannot be null");
|
||||
@ -1118,22 +1117,19 @@ public class SyncStreams {
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the given {@link IntStream} to make all
|
||||
* <a href=
|
||||
* Wraps the given {@link IntStream} to make all <a href=
|
||||
* "https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#StreamOps">
|
||||
* terminal operations</a> acquire the provided monitor's lock before
|
||||
* execution. Intermediate operations
|
||||
* return streams that are also synchronized on the same object. The created
|
||||
* stream will behave identically
|
||||
* to the provided stream in all other aspects. Use this to synchronize
|
||||
* access to stream's source.
|
||||
* execution. Intermediate operations return streams that are also
|
||||
* synchronized on the same object. The created stream will behave
|
||||
* identically to the provided stream in all other aspects. Use this to
|
||||
* synchronize access to stream's source.
|
||||
* <p>
|
||||
* <i>The returned {@code IntStream}'s {@link IntStream#iterator()
|
||||
* iterator()} and
|
||||
* {@link IntStream#spliterator() spliterator()} methods return regular
|
||||
* non-synchronized iterators and
|
||||
* spliterators respectively</i>. It is the user's responsibility to avoid
|
||||
* concurrency issues:
|
||||
* iterator()} and {@link IntStream#spliterator() spliterator()} methods
|
||||
* return regular non-synchronized iterators and spliterators
|
||||
* respectively</i>. It is the user's responsibility to avoid concurrency
|
||||
* issues:
|
||||
*
|
||||
* <pre>
|
||||
* synchronized (stream.getMonitor()) {
|
||||
@ -1152,13 +1148,15 @@ public class SyncStreams {
|
||||
* stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException
|
||||
* </pre>
|
||||
*
|
||||
* @param stream the stream to wrap.
|
||||
* @param monitor the object that the stream will use for synchronization.
|
||||
* When {@code null}, the stream
|
||||
* will synchronize on itself.
|
||||
* @param stream
|
||||
* the stream to wrap.
|
||||
* @param monitor
|
||||
* the object that the stream will use for synchronization. When
|
||||
* {@code null}, the stream will synchronize on itself.
|
||||
* @return a {@link SyncIntStream} synchronized on {@code monitor} and
|
||||
* backed by {@code stream}.
|
||||
* @throws NullPointerException if {@code stream == null}.
|
||||
* @throws NullPointerException
|
||||
* if {@code stream == null}.
|
||||
*/
|
||||
public static SyncIntStream synchronizedStream(IntStream stream, Object monitor) {
|
||||
Objects.requireNonNull(stream, "stream cannot be null");
|
||||
@ -1166,22 +1164,19 @@ public class SyncStreams {
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the given {@link LongStream} to make all
|
||||
* <a href=
|
||||
* Wraps the given {@link LongStream} to make all <a href=
|
||||
* "https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#StreamOps">
|
||||
* terminal operations</a> acquire the provided monitor's lock before
|
||||
* execution. Intermediate operations
|
||||
* return streams that are also synchronized on the same object. The created
|
||||
* stream will behave identically
|
||||
* to the provided stream in all other aspects. Use this to synchronize
|
||||
* access to stream's source.
|
||||
* execution. Intermediate operations return streams that are also
|
||||
* synchronized on the same object. The created stream will behave
|
||||
* identically to the provided stream in all other aspects. Use this to
|
||||
* synchronize access to stream's source.
|
||||
* <p>
|
||||
* <i>The returned {@code LongStream}'s {@link LongStream#iterator()
|
||||
* iterator()} and
|
||||
* {@link LongStream#spliterator() spliterator()} methods return regular
|
||||
* non-synchronized iterators and
|
||||
* spliterators respectively</i>. It is the user's responsibility to avoid
|
||||
* concurrency issues:
|
||||
* iterator()} and {@link LongStream#spliterator() spliterator()} methods
|
||||
* return regular non-synchronized iterators and spliterators
|
||||
* respectively</i>. It is the user's responsibility to avoid concurrency
|
||||
* issues:
|
||||
*
|
||||
* <pre>
|
||||
* synchronized (stream.getMonitor()) {
|
||||
@ -1200,13 +1195,15 @@ public class SyncStreams {
|
||||
* stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException
|
||||
* </pre>
|
||||
*
|
||||
* @param stream the stream to wrap.
|
||||
* @param monitor the object that the stream will use for synchronization.
|
||||
* When {@code null}, the stream
|
||||
* will synchronize on itself.
|
||||
* @param stream
|
||||
* the stream to wrap.
|
||||
* @param monitor
|
||||
* the object that the stream will use for synchronization. When
|
||||
* {@code null}, the stream will synchronize on itself.
|
||||
* @return a {@link SyncLongStream} synchronized on {@code monitor} and
|
||||
* backed by {@code stream}.
|
||||
* @throws NullPointerException if {@code stream == null}.
|
||||
* @throws NullPointerException
|
||||
* if {@code stream == null}.
|
||||
*/
|
||||
public static SyncLongStream synchronizedStream(LongStream stream, Object monitor) {
|
||||
Objects.requireNonNull(stream, "stream cannot be null");
|
||||
@ -1214,22 +1211,19 @@ public class SyncStreams {
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the given {@link DoubleStream} to make all
|
||||
* <a href=
|
||||
* Wraps the given {@link DoubleStream} to make all <a href=
|
||||
* "https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#StreamOps">
|
||||
* terminal operations</a> acquire the provided monitor's lock before
|
||||
* execution. Intermediate operations
|
||||
* return streams that are also synchronized on the same object. The created
|
||||
* stream will behave identically
|
||||
* to the provided stream in all other aspects. Use this to synchronize
|
||||
* access to stream's source.
|
||||
* execution. Intermediate operations return streams that are also
|
||||
* synchronized on the same object. The created stream will behave
|
||||
* identically to the provided stream in all other aspects. Use this to
|
||||
* synchronize access to stream's source.
|
||||
* <p>
|
||||
* <i>The returned {@code DoubleStream}'s {@link DoubleStream#iterator()
|
||||
* iterator()} and
|
||||
* {@link DoubleStream#spliterator() spliterator()} methods return regular
|
||||
* non-synchronized iterators and
|
||||
* spliterators respectively</i>. It is the user's responsibility to avoid
|
||||
* concurrency issues:
|
||||
* iterator()} and {@link DoubleStream#spliterator() spliterator()} methods
|
||||
* return regular non-synchronized iterators and spliterators
|
||||
* respectively</i>. It is the user's responsibility to avoid concurrency
|
||||
* issues:
|
||||
*
|
||||
* <pre>
|
||||
* synchronized (stream.getMonitor()) {
|
||||
@ -1248,13 +1242,15 @@ public class SyncStreams {
|
||||
* stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException
|
||||
* </pre>
|
||||
*
|
||||
* @param stream the stream to wrap.
|
||||
* @param monitor the object that the stream will use for synchronization.
|
||||
* When {@code null}, the stream
|
||||
* will synchronize on itself.
|
||||
* @param stream
|
||||
* the stream to wrap.
|
||||
* @param monitor
|
||||
* the object that the stream will use for synchronization. When
|
||||
* {@code null}, the stream will synchronize on itself.
|
||||
* @return a {@link SyncDoubleStream} synchronized on {@code monitor} and
|
||||
* backed by {@code stream}.
|
||||
* @throws NullPointerException if {@code stream == null}.
|
||||
* @throws NullPointerException
|
||||
* if {@code stream == null}.
|
||||
*/
|
||||
public static SyncDoubleStream synchronizedStream(DoubleStream stream, Object monitor) {
|
||||
Objects.requireNonNull(stream, "stream cannot be null");
|
||||
|
@ -108,7 +108,7 @@ public class CharArrayIterator implements CharacterIterator {
|
||||
return pos;
|
||||
}
|
||||
|
||||
// @SuppressWarnings("all") Just STFU, this _is_ terrific
|
||||
// @SuppressWarnings("all") Just STFU, this _is_ terrific
|
||||
|
||||
// SonarLint: "clone" should not be overridden (java:S2975)
|
||||
// And I wouldn't have done that if only CharacterIterator had not required
|
||||
|
@ -103,14 +103,8 @@ public class Escaper {
|
||||
|
||||
}
|
||||
|
||||
public static final Escaper JAVA = new Escaper(
|
||||
'\\',
|
||||
'u',
|
||||
"tbnrf'\"".toCharArray(),
|
||||
"\t\b\n\r\f\'\"".toCharArray(),
|
||||
true,
|
||||
true
|
||||
);
|
||||
public static final Escaper JAVA = new Escaper('\\', 'u', "tbnrf'\"".toCharArray(), "\t\b\n\r\f\'\"".toCharArray(),
|
||||
true, true);
|
||||
|
||||
private final char escapeChar;
|
||||
private final char unicodeEscapeChar;
|
||||
@ -120,14 +114,8 @@ public class Escaper {
|
||||
private final boolean preferUnicode;
|
||||
private final boolean strict;
|
||||
|
||||
protected Escaper(
|
||||
char escapeChar,
|
||||
char unicodeEscapeChar,
|
||||
char[] safes,
|
||||
char[] unsafes,
|
||||
boolean preferUnicode,
|
||||
boolean strict
|
||||
) {
|
||||
protected Escaper(char escapeChar, char unicodeEscapeChar, char[] safes, char[] unsafes, boolean preferUnicode,
|
||||
boolean strict) {
|
||||
this.escapeChar = escapeChar;
|
||||
this.unicodeEscapeChar = unicodeEscapeChar;
|
||||
this.safes = safes;
|
||||
@ -152,8 +140,7 @@ public class Escaper {
|
||||
for (char c : unsafes) {
|
||||
if (c == escapeChar)
|
||||
throw new IllegalArgumentException(
|
||||
"Unsafe characters contain escape chatacter (escape character is escaped automatically)"
|
||||
);
|
||||
"Unsafe characters contain escape chatacter (escape character is escaped automatically)");
|
||||
if (c == unicodeEscapeChar)
|
||||
throw new IllegalArgumentException("Unsafe characters contain Unicode escape chatacter");
|
||||
}
|
||||
@ -173,11 +160,7 @@ public class Escaper {
|
||||
end = Integer.MAX_VALUE;
|
||||
else
|
||||
end = src.getPosition() + length;
|
||||
while (
|
||||
src.has() &&
|
||||
src.getPosition() < end &&
|
||||
(until == null || !until.test(src.current()))
|
||||
)
|
||||
while (src.has() && src.getPosition() < end && (until == null || !until.test(src.current())))
|
||||
escape(src.consume(), output);
|
||||
}
|
||||
|
||||
@ -225,11 +208,7 @@ public class Escaper {
|
||||
|
||||
int result = 0;
|
||||
|
||||
while (
|
||||
src.has() &&
|
||||
src.getPosition() < end &&
|
||||
(until == null || !until.test(src.current()))
|
||||
) {
|
||||
while (src.has() && src.getPosition() < end && (until == null || !until.test(src.current()))) {
|
||||
result += getEscapedLength(src.consume());
|
||||
}
|
||||
|
||||
@ -257,11 +236,7 @@ public class Escaper {
|
||||
end = Integer.MAX_VALUE;
|
||||
else
|
||||
end = src.getPosition() + length;
|
||||
while (
|
||||
src.has() &&
|
||||
src.getPosition() < end &&
|
||||
(until == null || !until.test(src.current()))
|
||||
) {
|
||||
while (src.has() && src.getPosition() < end && (until == null || !until.test(src.current()))) {
|
||||
output.accept(unescapeOneSequence(src));
|
||||
}
|
||||
}
|
||||
@ -282,10 +257,8 @@ public class Escaper {
|
||||
|
||||
if (src.current() == unicodeEscapeChar) {
|
||||
src.next();
|
||||
return (char) (hexValue(src.consume()) << (4 * 3) |
|
||||
hexValue(src.consume()) << (4 * 2) |
|
||||
hexValue(src.consume()) << (4 * 1) |
|
||||
hexValue(src.consume()) << (4 * 0));
|
||||
return (char) (hexValue(src.consume()) << (4 * 3) | hexValue(src.consume()) << (4 * 2)
|
||||
| hexValue(src.consume()) << (4 * 1) | hexValue(src.consume()) << (4 * 0));
|
||||
}
|
||||
|
||||
int index = ArrayUtil.firstIndexOf(safes, src.current());
|
||||
@ -315,11 +288,7 @@ public class Escaper {
|
||||
|
||||
int result = 0;
|
||||
|
||||
while (
|
||||
src.has() &&
|
||||
src.getPosition() < end &&
|
||||
(until == null || !until.test(src.current()))
|
||||
) {
|
||||
while (src.has() && src.getPosition() < end && (until == null || !until.test(src.current()))) {
|
||||
skipOneSequence(src);
|
||||
result++;
|
||||
}
|
||||
@ -328,11 +297,7 @@ public class Escaper {
|
||||
}
|
||||
|
||||
public void skipOneSequence(CharReader src) {
|
||||
if (
|
||||
src.current() == escapeChar
|
||||
&&
|
||||
src.next() == unicodeEscapeChar
|
||||
) {
|
||||
if (src.current() == escapeChar && src.next() == unicodeEscapeChar) {
|
||||
src.advance(4);
|
||||
}
|
||||
src.next();
|
||||
|
@ -86,7 +86,7 @@ public class FancyCharacterIterator implements CharacterIterator {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// @SuppressWarnings("all") Just STFU, this _is_ terrific
|
||||
// @SuppressWarnings("all") Just STFU, this _is_ terrific
|
||||
|
||||
// SonarLint: "clone" should not be overridden (java:S2975)
|
||||
// And I wouldn't have done that if only CharacterIterator had not required
|
||||
|
@ -41,13 +41,8 @@ public class StringUtil {
|
||||
private static final String EMPTY_PLACEHOLDER = "[empty]";
|
||||
private static final String DEFAULT_SEPARATOR = "; ";
|
||||
|
||||
public static <T> String arrayToString(
|
||||
T[] array,
|
||||
String separator,
|
||||
String empty,
|
||||
String nullPlaceholder,
|
||||
String nullArray
|
||||
) {
|
||||
public static <T> String arrayToString(T[] array, String separator, String empty, String nullPlaceholder,
|
||||
String nullArray) {
|
||||
|
||||
if (separator == null) {
|
||||
throw new IllegalArgumentException(new NullPointerException());
|
||||
@ -79,13 +74,8 @@ public class StringUtil {
|
||||
return arrayToString(array, DEFAULT_SEPARATOR);
|
||||
}
|
||||
|
||||
public static String iteratorToString(
|
||||
Iterator<?> iterator,
|
||||
String separator,
|
||||
String empty,
|
||||
String nullPlaceholder,
|
||||
String nullIterator
|
||||
) {
|
||||
public static String iteratorToString(Iterator<?> iterator, String separator, String empty, String nullPlaceholder,
|
||||
String nullIterator) {
|
||||
|
||||
if (separator == null) {
|
||||
throw new IllegalArgumentException(new NullPointerException());
|
||||
@ -119,13 +109,8 @@ public class StringUtil {
|
||||
return iteratorToString(iterator, DEFAULT_SEPARATOR);
|
||||
}
|
||||
|
||||
public static String iterableToString(
|
||||
Iterable<?> iterable,
|
||||
String separator,
|
||||
String empty,
|
||||
String nullPlaceholder,
|
||||
String nullIterable
|
||||
) {
|
||||
public static String iterableToString(Iterable<?> iterable, String separator, String empty, String nullPlaceholder,
|
||||
String nullIterable) {
|
||||
|
||||
if (separator == null) {
|
||||
throw new IllegalArgumentException(new NullPointerException());
|
||||
@ -146,14 +131,8 @@ public class StringUtil {
|
||||
return iterableToString(iterable, DEFAULT_SEPARATOR);
|
||||
}
|
||||
|
||||
public static <T> String supplierToString(
|
||||
IntFunction<T> supplier,
|
||||
int length,
|
||||
String separator,
|
||||
String empty,
|
||||
String nullPlaceholder,
|
||||
String nullSupplier
|
||||
) {
|
||||
public static <T> String supplierToString(IntFunction<T> supplier, int length, String separator, String empty,
|
||||
String nullPlaceholder, String nullSupplier) {
|
||||
|
||||
if (separator == null)
|
||||
throw new IllegalArgumentException(new NullPointerException());
|
||||
@ -163,28 +142,15 @@ public class StringUtil {
|
||||
return empty;
|
||||
|
||||
if (length > 0) {
|
||||
return supplierToStringExactly(
|
||||
supplier,
|
||||
length,
|
||||
separator,
|
||||
nullPlaceholder
|
||||
);
|
||||
return supplierToStringExactly(supplier, length, separator, nullPlaceholder);
|
||||
} else {
|
||||
return supplierToStringUntilNull(
|
||||
supplier,
|
||||
separator,
|
||||
empty
|
||||
);
|
||||
return supplierToStringUntilNull(supplier, separator, empty);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static <T> String supplierToStringExactly(
|
||||
IntFunction<T> supplier,
|
||||
int length,
|
||||
String separator,
|
||||
String nullPlaceholder
|
||||
) {
|
||||
private static <T> String supplierToStringExactly(IntFunction<T> supplier, int length, String separator,
|
||||
String nullPlaceholder) {
|
||||
T element = supplier.apply(0);
|
||||
|
||||
StringBuilder sb = new StringBuilder(element == null ? nullPlaceholder : element.toString());
|
||||
@ -198,11 +164,7 @@ public class StringUtil {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static <T> String supplierToStringUntilNull(
|
||||
IntFunction<T> supplier,
|
||||
String separator,
|
||||
String empty
|
||||
) {
|
||||
private static <T> String supplierToStringUntilNull(IntFunction<T> supplier, String separator, String empty) {
|
||||
T element = supplier.apply(0);
|
||||
|
||||
if (element == null) {
|
||||
@ -366,11 +328,7 @@ public class StringUtil {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
charLoop: for (char c : src.toCharArray()) {
|
||||
if (
|
||||
(resultIndex + 1) < arrayLength
|
||||
&&
|
||||
test.test(c)
|
||||
) {
|
||||
if ((resultIndex + 1) < arrayLength && test.test(c)) {
|
||||
result[resultIndex] = resetStringBuilder(sb);
|
||||
++resultIndex;
|
||||
continue charLoop;
|
||||
@ -389,17 +347,17 @@ public class StringUtil {
|
||||
* index.
|
||||
* <p>
|
||||
* Indices {@code 0} and {@code src.length() - 1} produce {@code str}
|
||||
* excluding
|
||||
* the specified character and {@code ""}.
|
||||
* excluding the specified character and {@code ""}.
|
||||
* <p>
|
||||
*
|
||||
* @param src the String to split
|
||||
* @param at index to split at
|
||||
* @throws IllegalArgumentException if the index is out of bounds for
|
||||
* {@code src}
|
||||
* @param src
|
||||
* the String to split
|
||||
* @param at
|
||||
* index to split at
|
||||
* @throws IllegalArgumentException
|
||||
* if the index is out of bounds for {@code src}
|
||||
* @return an array containing the substrings, in order of encounter in
|
||||
* {@code src}.
|
||||
* Its length is always 2.
|
||||
* {@code src}. Its length is always 2.
|
||||
*/
|
||||
public static String[] splitAt(String src, int at) {
|
||||
Objects.requireNonNull(src, "src");
|
||||
@ -416,10 +374,7 @@ public class StringUtil {
|
||||
return new String[] { src.substring(0, src.length() - 1), "" };
|
||||
}
|
||||
|
||||
return new String[] {
|
||||
src.substring(0, at),
|
||||
src.substring(at + 1)
|
||||
};
|
||||
return new String[] { src.substring(0, at), src.substring(at + 1) };
|
||||
}
|
||||
|
||||
/**
|
||||
@ -427,8 +382,7 @@ public class StringUtil {
|
||||
* indices.
|
||||
* <p>
|
||||
* Indices {@code 0} and {@code src.length() - 1} produce extra zero-length
|
||||
* outputs.
|
||||
* Duplicate indices produce extra zero-length outputs.
|
||||
* outputs. Duplicate indices produce extra zero-length outputs.
|
||||
* <p>
|
||||
* Examples:
|
||||
*
|
||||
@ -439,13 +393,14 @@ public class StringUtil {
|
||||
* splitAt("a.b", 1, 1, 1) -> {"a", "", "", "b"}
|
||||
* </pre>
|
||||
*
|
||||
* @param src the String to split
|
||||
* @param at indices to split at, in any order
|
||||
* @throws IllegalArgumentException if some index is out of bounds for
|
||||
* {@code src}
|
||||
* @param src
|
||||
* the String to split
|
||||
* @param at
|
||||
* indices to split at, in any order
|
||||
* @throws IllegalArgumentException
|
||||
* if some index is out of bounds for {@code src}
|
||||
* @return an array containing the substrings, in order of encounter in
|
||||
* {@code src}.
|
||||
* Its length is always {@code at.length + 1}.
|
||||
* {@code src}. Its length is always {@code at.length + 1}.
|
||||
*/
|
||||
public static String[] splitAt(String src, int... at) {
|
||||
Objects.requireNonNull(src, "src");
|
||||
@ -553,10 +508,8 @@ public class StringUtil {
|
||||
}
|
||||
|
||||
if (endPos < beginPos) {
|
||||
throw new IllegalArgumentException(
|
||||
"endPos must be greater than or equal to beginPos (endPos="
|
||||
+ endPos + ", beginPos=" + beginPos + ")"
|
||||
);
|
||||
throw new IllegalArgumentException("endPos must be greater than or equal to beginPos (endPos=" + endPos
|
||||
+ ", beginPos=" + beginPos + ")");
|
||||
}
|
||||
|
||||
if (endPos >= Math.min(a.length, b.length)) {
|
||||
@ -592,8 +545,7 @@ public class StringUtil {
|
||||
|
||||
/**
|
||||
* Finds and returns the index of the specified appearance of the specified
|
||||
* character
|
||||
* in the given array. The search starts at index 0.
|
||||
* character in the given array. The search starts at index 0.
|
||||
* <p>
|
||||
* Examples:
|
||||
* <p>
|
||||
@ -630,10 +582,12 @@ public class StringUtil {
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* @param src - the array to search in.
|
||||
* @param target - the character to search for.
|
||||
* @param skip - the amount of <code>target</code> characters to be
|
||||
* skipped.
|
||||
* @param src
|
||||
* - the array to search in.
|
||||
* @param target
|
||||
* - the character to search for.
|
||||
* @param skip
|
||||
* - the amount of <code>target</code> characters to be skipped.
|
||||
* @return The index of the <code>skip+1</code>th <code>target</code>
|
||||
* character or -1, if none found.
|
||||
* @see StringUtil#indexFromEnd(char[], char, int)
|
||||
@ -653,8 +607,7 @@ public class StringUtil {
|
||||
|
||||
/**
|
||||
* Finds and returns the index of the specified appearance of the specified
|
||||
* character
|
||||
* in the given array. The search starts at index
|
||||
* character in the given array. The search starts at index
|
||||
* <code>src.length - 1</code>.
|
||||
* <p>
|
||||
* Examples:
|
||||
@ -692,13 +645,15 @@ public class StringUtil {
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* @param src - the array to search in.
|
||||
* @param target - the character to search for.
|
||||
* @param skip - the amount of <code>target</code> characters to be
|
||||
* skipped.
|
||||
* @param src
|
||||
* - the array to search in.
|
||||
* @param target
|
||||
* - the character to search for.
|
||||
* @param skip
|
||||
* - the amount of <code>target</code> characters to be skipped.
|
||||
* @return The index of the <code>skip+1</code>th
|
||||
* <code>target</code>character
|
||||
* from the end of the array or -1, if none found.
|
||||
* <code>target</code>character from the end of the array or -1, if
|
||||
* none found.
|
||||
* @see StringUtil#indexFromBeginning(char[], char, int)
|
||||
*/
|
||||
public static int indexFromEnd(char[] src, char target, int skip) {
|
||||
@ -873,12 +828,8 @@ public class StringUtil {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void buildCombinations(
|
||||
StringBuilder sb,
|
||||
Collection<String> result,
|
||||
Iterable<String>[] parts,
|
||||
int index
|
||||
) {
|
||||
private static void buildCombinations(StringBuilder sb, Collection<String> result, Iterable<String>[] parts,
|
||||
int index) {
|
||||
if (index >= parts.length) {
|
||||
result.add(sb.toString());
|
||||
} else {
|
||||
@ -904,13 +855,8 @@ public class StringUtil {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void buildCombinations(
|
||||
StringBuilder sb,
|
||||
String[] result,
|
||||
int[] resultIndex,
|
||||
String[][] parts,
|
||||
int index
|
||||
) {
|
||||
private static void buildCombinations(StringBuilder sb, String[] result, int[] resultIndex, String[][] parts,
|
||||
int index) {
|
||||
if (index >= parts.length) {
|
||||
result[resultIndex[0]++] = sb.toString();
|
||||
} else {
|
||||
@ -985,10 +931,7 @@ public class StringUtil {
|
||||
}
|
||||
|
||||
private static char hexDigit(long value, int digit) {
|
||||
return hexDigit(
|
||||
(int) (value >>> (4 * digit))
|
||||
& 0xF
|
||||
);
|
||||
return hexDigit((int) (value >>> (4 * digit)) & 0xF);
|
||||
}
|
||||
|
||||
public static char hexDigit(int value) {
|
||||
|
@ -27,10 +27,9 @@ public abstract class AbstractCharReader implements CharReader {
|
||||
|
||||
/**
|
||||
* Current position of this CharReader. The reader maps its input to
|
||||
* positions starting from 0.
|
||||
* Positions that are negative or lower than 0 are invalid.
|
||||
* {@link #current()}
|
||||
* will throw an exception if position is invalid.
|
||||
* positions starting from 0. Positions that are negative or lower than 0
|
||||
* are invalid. {@link #current()} will throw an exception if position is
|
||||
* invalid.
|
||||
*/
|
||||
protected int position = 0;
|
||||
|
||||
|
@ -51,9 +51,12 @@ public abstract class BufferedCharReader extends AbstractCharReader {
|
||||
/**
|
||||
* Acquires next characters and stores them in the array.
|
||||
*
|
||||
* @param buffer the output array
|
||||
* @param offset index of the first character
|
||||
* @param length maximum amount of characters to be pulled
|
||||
* @param buffer
|
||||
* the output array
|
||||
* @param offset
|
||||
* index of the first character
|
||||
* @param length
|
||||
* maximum amount of characters to be pulled
|
||||
* @return the amount of characters actually pulled
|
||||
*/
|
||||
protected int pullChars(char[] buffer, int offset, int length) {
|
||||
|
@ -179,8 +179,7 @@ public interface CharReader {
|
||||
|
||||
/**
|
||||
* Skips to the end of the current line. Both <code>"\n"</code>,
|
||||
* <code>"\r"</code>
|
||||
* and <code>"\r\n"</code> are considered line separators.
|
||||
* <code>"\r"</code> and <code>"\r\n"</code> are considered line separators.
|
||||
*
|
||||
* @return the amount of characters in the skipped line
|
||||
*/
|
||||
|
@ -38,8 +38,7 @@ public class StringCharReader extends AbstractCharReader {
|
||||
int end = offset + length;
|
||||
if (end > str.length() || offset < 0)
|
||||
throw new IllegalArgumentException(
|
||||
"String contains [0; " + str.length() + "), requested [" + offset + "; " + end + ")"
|
||||
);
|
||||
"String contains [0; " + str.length() + "), requested [" + offset + "; " + end + ")");
|
||||
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
|
@ -45,8 +45,15 @@ public interface ThrowingBiConsumer<T, U, E extends Exception> {
|
||||
|
||||
public static <T, U, E extends Exception> ThrowingBiConsumer<T, U, E> concat(
|
||||
ThrowingBiConsumer<? super T, ? super U, ? extends E> first,
|
||||
ThrowingBiConsumer<? super T, ? super U, ? extends E> second
|
||||
) {
|
||||
ThrowingBiConsumer<? super T, ? super U, ? extends E> second) {
|
||||
return (t, u) -> {
|
||||
first.accept(t, u);
|
||||
second.accept(t, u);
|
||||
};
|
||||
}
|
||||
|
||||
public static <T, U, E extends Exception> ThrowingBiConsumer<T, U, E> concat(BiConsumer<? super T, ? super U> first,
|
||||
ThrowingBiConsumer<? super T, ? super U, E> second) {
|
||||
return (t, u) -> {
|
||||
first.accept(t, u);
|
||||
second.accept(t, u);
|
||||
@ -54,19 +61,7 @@ public interface ThrowingBiConsumer<T, U, E extends Exception> {
|
||||
}
|
||||
|
||||
public static <T, U, E extends Exception> ThrowingBiConsumer<T, U, E> concat(
|
||||
BiConsumer<? super T, ? super U> first,
|
||||
ThrowingBiConsumer<? super T, ? super U, E> second
|
||||
) {
|
||||
return (t, u) -> {
|
||||
first.accept(t, u);
|
||||
second.accept(t, u);
|
||||
};
|
||||
}
|
||||
|
||||
public static <T, U, E extends Exception> ThrowingBiConsumer<T, U, E> concat(
|
||||
ThrowingBiConsumer<? super T, ? super U, E> first,
|
||||
BiConsumer<? super T, ? super U> second
|
||||
) {
|
||||
ThrowingBiConsumer<? super T, ? super U, E> first, BiConsumer<? super T, ? super U> second) {
|
||||
return (t, u) -> {
|
||||
first.accept(t, u);
|
||||
second.accept(t, u);
|
||||
|
@ -39,30 +39,24 @@ public interface ThrowingConsumer<T, E extends Exception> {
|
||||
};
|
||||
}
|
||||
|
||||
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(
|
||||
ThrowingConsumer<? super T, ? extends E> first,
|
||||
ThrowingConsumer<? super T, ? extends E> second
|
||||
) {
|
||||
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(ThrowingConsumer<? super T, ? extends E> first,
|
||||
ThrowingConsumer<? super T, ? extends E> second) {
|
||||
return t -> {
|
||||
first.accept(t);
|
||||
second.accept(t);
|
||||
};
|
||||
}
|
||||
|
||||
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(
|
||||
Consumer<? super T> first,
|
||||
ThrowingConsumer<? super T, ? extends E> second
|
||||
) {
|
||||
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(Consumer<? super T> first,
|
||||
ThrowingConsumer<? super T, ? extends E> second) {
|
||||
return t -> {
|
||||
first.accept(t);
|
||||
second.accept(t);
|
||||
};
|
||||
}
|
||||
|
||||
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(
|
||||
ThrowingConsumer<? super T, ? extends E> first,
|
||||
Consumer<? super T> second
|
||||
) {
|
||||
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(ThrowingConsumer<? super T, ? extends E> first,
|
||||
Consumer<? super T> second) {
|
||||
return t -> {
|
||||
first.accept(t);
|
||||
second.accept(t);
|
||||
|
@ -28,10 +28,8 @@ public interface ThrowingFunction<T, R, E extends Exception> {
|
||||
R apply(T t) throws E;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
default Function<T, R> withHandler(
|
||||
BiConsumer<? super T, ? super E> handler,
|
||||
Function<? super T, ? extends R> value
|
||||
) {
|
||||
default Function<T, R> withHandler(BiConsumer<? super T, ? super E> handler,
|
||||
Function<? super T, ? extends R> value) {
|
||||
return t -> {
|
||||
try {
|
||||
return apply(t);
|
||||
@ -59,22 +57,17 @@ public interface ThrowingFunction<T, R, E extends Exception> {
|
||||
|
||||
public static <T, R, I, E extends Exception> ThrowingFunction<T, R, E> compose(
|
||||
ThrowingFunction<? super T, I, ? extends E> first,
|
||||
ThrowingFunction<? super I, ? extends R, ? extends E> second
|
||||
) {
|
||||
ThrowingFunction<? super I, ? extends R, ? extends E> second) {
|
||||
return t -> second.apply(first.apply(t));
|
||||
}
|
||||
|
||||
public static <T, R, I, E extends Exception> ThrowingFunction<T, R, E> compose(Function<? super T, I> first,
|
||||
ThrowingFunction<? super I, ? extends R, E> second) {
|
||||
return t -> second.apply(first.apply(t));
|
||||
}
|
||||
|
||||
public static <T, R, I, E extends Exception> ThrowingFunction<T, R, E> compose(
|
||||
Function<? super T, I> first,
|
||||
ThrowingFunction<? super I, ? extends R, E> second
|
||||
) {
|
||||
return t -> second.apply(first.apply(t));
|
||||
}
|
||||
|
||||
public static <T, R, I, E extends Exception> ThrowingFunction<T, R, E> compose(
|
||||
ThrowingFunction<? super T, I, E> first,
|
||||
Function<? super I, ? extends R> second
|
||||
) {
|
||||
ThrowingFunction<? super T, I, E> first, Function<? super I, ? extends R> second) {
|
||||
return t -> second.apply(first.apply(t));
|
||||
}
|
||||
|
||||
|
@ -38,10 +38,8 @@ public interface ThrowingRunnable<E extends Exception> {
|
||||
};
|
||||
}
|
||||
|
||||
public static <E extends Exception> ThrowingRunnable<E> concat(
|
||||
ThrowingRunnable<? extends E> first,
|
||||
ThrowingRunnable<? extends E> second
|
||||
) {
|
||||
public static <E extends Exception> ThrowingRunnable<E> concat(ThrowingRunnable<? extends E> first,
|
||||
ThrowingRunnable<? extends E> second) {
|
||||
return () -> {
|
||||
first.run();
|
||||
second.run();
|
||||
|
@ -49,10 +49,8 @@ public class RangeIterator<E> implements Iterator<E> {
|
||||
public E next() {
|
||||
update();
|
||||
if (nextIndex >= from + amount) {
|
||||
throw new NoSuchElementException(
|
||||
"RangeIterator about to retrieve element " + nextIndex
|
||||
+ " which exceeds upper boundary " + (from + amount)
|
||||
);
|
||||
throw new NoSuchElementException("RangeIterator about to retrieve element " + nextIndex
|
||||
+ " which exceeds upper boundary " + (from + amount));
|
||||
}
|
||||
|
||||
E result = parent.next();
|
||||
|
@ -40,6 +40,7 @@ public class ProgressiaLauncher {
|
||||
CrashReports.registerProvider(new OpenALContextProvider());
|
||||
CrashReports.registerProvider(new ArgsContextProvider());
|
||||
CrashReports.registerProvider(new LanguageContextProvider());
|
||||
CrashReports.registerProvider(new ScreenContextProvider());
|
||||
// Analyzers
|
||||
CrashReports.registerAnalyzer(new OutOfMemoryAnalyzer());
|
||||
|
||||
|
@ -24,7 +24,7 @@ import ru.windcorp.progressia.client.graphics.world.Camera;
|
||||
import ru.windcorp.progressia.client.graphics.world.EntityAnchor;
|
||||
import ru.windcorp.progressia.client.graphics.world.LocalPlayer;
|
||||
import ru.windcorp.progressia.client.world.WorldRender;
|
||||
import ru.windcorp.progressia.common.world.WorldData;
|
||||
import ru.windcorp.progressia.common.world.DefaultWorldData;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
|
||||
public class Client {
|
||||
@ -36,7 +36,7 @@ public class Client {
|
||||
|
||||
private final ServerCommsChannel comms;
|
||||
|
||||
public Client(WorldData world, ServerCommsChannel comms) {
|
||||
public Client(DefaultWorldData world, ServerCommsChannel comms) {
|
||||
this.world = new WorldRender(world, this);
|
||||
this.comms = comms;
|
||||
|
||||
@ -69,11 +69,7 @@ public class Client {
|
||||
return;
|
||||
}
|
||||
|
||||
getCamera().setAnchor(
|
||||
new EntityAnchor(
|
||||
getWorld().getEntityRenderable(entity)
|
||||
)
|
||||
);
|
||||
getCamera().setAnchor(new EntityAnchor(getWorld().getEntityRenderable(entity)));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import ru.windcorp.progressia.common.resource.ResourceManager;
|
||||
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||
import ru.windcorp.progressia.server.ServerState;
|
||||
import ru.windcorp.progressia.test.TestContent;
|
||||
import ru.windcorp.progressia.test.TestMusicPlayer;
|
||||
|
||||
public class ClientProxy implements Proxy {
|
||||
|
||||
@ -41,10 +42,8 @@ public class ClientProxy implements Proxy {
|
||||
try {
|
||||
RenderTaskQueue.waitAndInvoke(FlatRenderProgram::init);
|
||||
RenderTaskQueue.waitAndInvoke(WorldRenderProgram::init);
|
||||
RenderTaskQueue.waitAndInvoke(
|
||||
() -> Typefaces
|
||||
.setDefault(GNUUnifontLoader.load(ResourceManager.getResource("assets/unifont-13.0.03.hex.gz")))
|
||||
);
|
||||
RenderTaskQueue.waitAndInvoke(() -> Typefaces
|
||||
.setDefault(GNUUnifontLoader.load(ResourceManager.getResource("assets/unifont-13.0.03.hex.gz"))));
|
||||
} catch (InterruptedException e) {
|
||||
throw CrashReports.report(e, "ClientProxy failed");
|
||||
}
|
||||
@ -59,6 +58,8 @@ public class ClientProxy implements Proxy {
|
||||
|
||||
ServerState.startServer();
|
||||
ClientState.connectToLocalServer();
|
||||
|
||||
TestMusicPlayer.start();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ package ru.windcorp.progressia.client;
|
||||
import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel;
|
||||
import ru.windcorp.progressia.client.graphics.GUI;
|
||||
import ru.windcorp.progressia.client.graphics.world.LayerWorld;
|
||||
import ru.windcorp.progressia.common.world.WorldData;
|
||||
import ru.windcorp.progressia.common.world.DefaultWorldData;
|
||||
import ru.windcorp.progressia.server.ServerState;
|
||||
import ru.windcorp.progressia.test.LayerAbout;
|
||||
import ru.windcorp.progressia.test.LayerTestUI;
|
||||
@ -41,11 +41,9 @@ public class ClientState {
|
||||
|
||||
public static void connectToLocalServer() {
|
||||
|
||||
WorldData world = new WorldData();
|
||||
DefaultWorldData world = new DefaultWorldData();
|
||||
|
||||
LocalServerCommsChannel channel = new LocalServerCommsChannel(
|
||||
ServerState.getInstance()
|
||||
);
|
||||
LocalServerCommsChannel channel = new LocalServerCommsChannel(ServerState.getInstance());
|
||||
|
||||
Client client = new Client(world, channel);
|
||||
|
||||
|
@ -23,6 +23,7 @@ import ru.windcorp.progressia.client.audio.backend.AudioReader;
|
||||
import ru.windcorp.progressia.client.audio.backend.Listener;
|
||||
import ru.windcorp.progressia.client.audio.backend.SoundType;
|
||||
import ru.windcorp.progressia.client.audio.backend.Speaker;
|
||||
import ru.windcorp.progressia.common.resource.Resource;
|
||||
|
||||
import static org.lwjgl.openal.AL11.*;
|
||||
import static org.lwjgl.openal.ALC10.*;
|
||||
@ -40,13 +41,9 @@ public class AudioManager {
|
||||
|
||||
private static List<Speaker> soundSpeakers = new ArrayList<>(SOUNDS_NUM);
|
||||
private static Speaker musicSpeaker;
|
||||
private static ArrayList<SoundType> soundsBuffer = new ArrayList<>();
|
||||
|
||||
public static void initAL() {
|
||||
String defaultDeviceName = alcGetString(
|
||||
0,
|
||||
ALC_DEFAULT_DEVICE_SPECIFIER
|
||||
);
|
||||
String defaultDeviceName = alcGetString(0, ALC_DEFAULT_DEVICE_SPECIFIER);
|
||||
|
||||
device = alcOpenDevice(defaultDeviceName);
|
||||
|
||||
@ -75,38 +72,23 @@ public class AudioManager {
|
||||
lastSoundIndex = 0;
|
||||
}
|
||||
speaker = soundSpeakers.get(lastSoundIndex);
|
||||
} while (
|
||||
speaker.getState()
|
||||
.equals(Speaker.State.PLAYING_LOOP)
|
||||
);
|
||||
} while (speaker.getState().equals(Speaker.State.PLAYING_LOOP));
|
||||
return speaker;
|
||||
}
|
||||
|
||||
private static SoundType findSoundType(String soundID) throws Exception {
|
||||
for (SoundType s : soundsBuffer) {
|
||||
if (s.getId().equals(soundID)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
throw new Exception(
|
||||
"ERROR: The selected sound is not loaded or" +
|
||||
" not exists"
|
||||
);
|
||||
}
|
||||
|
||||
public static Speaker initSpeaker(String soundID) {
|
||||
public static Speaker initSpeaker(SoundType st) {
|
||||
Speaker speaker = getLastSpeaker();
|
||||
try {
|
||||
findSoundType(soundID).initSpeaker(speaker);
|
||||
st.initSpeaker(speaker);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
return speaker;
|
||||
}
|
||||
|
||||
public static Speaker initMusicSpeaker(String soundID) {
|
||||
public static Speaker initMusicSpeaker(SoundType st) {
|
||||
try {
|
||||
findSoundType(soundID).initSpeaker(musicSpeaker);
|
||||
st.initSpeaker(musicSpeaker);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
@ -120,11 +102,11 @@ public class AudioManager {
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadSound(String path, String id, AudioFormat format) {
|
||||
public static void loadSound(Resource resource, String id, AudioFormat format) {
|
||||
if (format == AudioFormat.MONO) {
|
||||
soundsBuffer.add(AudioReader.readAsMono(path, id));
|
||||
AudioRegistry.getInstance().register(AudioReader.readAsMono(resource, id));
|
||||
} else {
|
||||
soundsBuffer.add(AudioReader.readAsStereo(path, id));
|
||||
AudioRegistry.getInstance().register(AudioReader.readAsStereo(resource, id));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package ru.windcorp.progressia.client.audio;
|
||||
|
||||
import ru.windcorp.progressia.client.audio.backend.SoundType;
|
||||
import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry;
|
||||
|
||||
public class AudioRegistry extends NamespacedInstanceRegistry<SoundType> {
|
||||
|
||||
private static final AudioRegistry INSTANCE = new AudioRegistry();
|
||||
|
||||
/**
|
||||
* @return the instance
|
||||
*/
|
||||
public static AudioRegistry getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
}
|
@ -18,6 +18,8 @@
|
||||
|
||||
package ru.windcorp.progressia.client.audio;
|
||||
|
||||
import ru.windcorp.progressia.common.resource.ResourceManager;
|
||||
|
||||
public class AudioSystem {
|
||||
static public void initialize() {
|
||||
AudioManager.initAL();
|
||||
@ -27,10 +29,7 @@ public class AudioSystem {
|
||||
}
|
||||
|
||||
static void loadAudioData() {
|
||||
AudioManager.loadSound(
|
||||
"assets/sounds/block_destroy_clap.ogg",
|
||||
"Progressia:BlockDestroy",
|
||||
AudioFormat.MONO
|
||||
);
|
||||
AudioManager.loadSound(ResourceManager.getResource("assets/sounds/block_destroy_clap.ogg"),
|
||||
"Progressia:BlockDestroy", AudioFormat.MONO);
|
||||
}
|
||||
}
|
||||
|
@ -19,72 +19,34 @@
|
||||
package ru.windcorp.progressia.client.audio;
|
||||
|
||||
import glm.vec._3.Vec3;
|
||||
import ru.windcorp.progressia.client.audio.backend.SoundType;
|
||||
import ru.windcorp.progressia.client.audio.backend.Speaker;
|
||||
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
|
||||
|
||||
public class Music extends Namespaced {
|
||||
private Vec3 position = new Vec3();
|
||||
private Vec3 velocity = new Vec3();
|
||||
private float pitch = 1.0f;
|
||||
private float gain = 1.0f;
|
||||
public class Music extends Sound {
|
||||
|
||||
public Music(SoundType soundType, int timeLength, float pitch, float gain) {
|
||||
super(soundType, timeLength, new Vec3(), new Vec3(), pitch, gain);
|
||||
}
|
||||
|
||||
public Music(SoundType soundType) {
|
||||
super(soundType);
|
||||
}
|
||||
|
||||
public Music(String id, int timeLength, float pitch, float gain) {
|
||||
super(id, timeLength, new Vec3(), new Vec3(), pitch, gain);
|
||||
}
|
||||
|
||||
public Music(String id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
public Music(
|
||||
String id,
|
||||
Vec3 position,
|
||||
Vec3 velocity,
|
||||
float pitch,
|
||||
float gain
|
||||
) {
|
||||
this(id);
|
||||
this.position = position;
|
||||
this.velocity = velocity;
|
||||
this.pitch = pitch;
|
||||
this.gain = gain;
|
||||
@Override
|
||||
protected Speaker initSpeaker() {
|
||||
return AudioManager.initMusicSpeaker(soundType);
|
||||
}
|
||||
|
||||
public void play(boolean loop) {
|
||||
Speaker speaker = AudioManager.initMusicSpeaker(this.getId());
|
||||
speaker.setGain(gain);
|
||||
speaker.setPitch(pitch);
|
||||
speaker.setPosition(position);
|
||||
speaker.setVelocity(velocity);
|
||||
|
||||
if (loop) {
|
||||
speaker.playLoop();
|
||||
} else {
|
||||
speaker.play();
|
||||
}
|
||||
}
|
||||
|
||||
public void setGain(float gain) {
|
||||
this.gain = gain;
|
||||
}
|
||||
|
||||
public void setPitch(float pitch) {
|
||||
this.pitch = pitch;
|
||||
}
|
||||
|
||||
public void setVelocity(Vec3 velocity) {
|
||||
this.velocity = velocity;
|
||||
}
|
||||
|
||||
public Vec3 getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public float getGain() {
|
||||
return gain;
|
||||
}
|
||||
|
||||
public Vec3 getVelocity() {
|
||||
return velocity;
|
||||
}
|
||||
|
||||
public float getPitch() {
|
||||
return pitch;
|
||||
@Override
|
||||
public void setPosition(Vec3 position) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
@ -19,28 +19,28 @@
|
||||
package ru.windcorp.progressia.client.audio;
|
||||
|
||||
import glm.vec._3.Vec3;
|
||||
import ru.windcorp.progressia.client.audio.backend.SoundType;
|
||||
import ru.windcorp.progressia.client.audio.backend.Speaker;
|
||||
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
|
||||
|
||||
public class SoundEffect
|
||||
extends Namespaced {
|
||||
public class Sound {
|
||||
|
||||
private Vec3 position = new Vec3();
|
||||
private Vec3 velocity = new Vec3();
|
||||
private float pitch = 1.0f;
|
||||
private float gain = 1.0f;
|
||||
protected Vec3 position = new Vec3(0f, 0f, 0f);
|
||||
protected Vec3 velocity = new Vec3(0f, 0f, 0f);
|
||||
protected float pitch = 1.0f;
|
||||
protected float gain = 1.0f;
|
||||
protected int timeLength = 0;
|
||||
|
||||
public SoundEffect(String id) {
|
||||
super(id);
|
||||
protected SoundType soundType;
|
||||
|
||||
public Sound(SoundType soundType) {
|
||||
this.soundType = soundType;
|
||||
}
|
||||
|
||||
public SoundEffect(
|
||||
String id,
|
||||
Vec3 position,
|
||||
Vec3 velocity,
|
||||
float pitch,
|
||||
float gain
|
||||
) {
|
||||
public Sound(String id) {
|
||||
this(AudioRegistry.getInstance().get(id));
|
||||
}
|
||||
|
||||
public Sound(String id, int timeLength, Vec3 position, Vec3 velocity, float pitch, float gain) {
|
||||
this(id);
|
||||
this.position = position;
|
||||
this.velocity = velocity;
|
||||
@ -48,8 +48,20 @@ public class SoundEffect
|
||||
this.gain = gain;
|
||||
}
|
||||
|
||||
public Sound(SoundType soundType, int timeLength, Vec3 position, Vec3 velocity, float pitch, float gain) {
|
||||
this(soundType);
|
||||
this.position = position;
|
||||
this.velocity = velocity;
|
||||
this.pitch = pitch;
|
||||
this.gain = gain;
|
||||
}
|
||||
|
||||
protected Speaker initSpeaker() {
|
||||
return AudioManager.initSpeaker(soundType);
|
||||
}
|
||||
|
||||
public void play(boolean loop) {
|
||||
Speaker speaker = AudioManager.initSpeaker(this.getId());
|
||||
Speaker speaker = initSpeaker();
|
||||
speaker.setGain(gain);
|
||||
speaker.setPitch(pitch);
|
||||
speaker.setPosition(position);
|
||||
@ -93,4 +105,9 @@ public class SoundEffect
|
||||
public float getPitch() {
|
||||
return pitch;
|
||||
}
|
||||
|
||||
public double getDuration() {
|
||||
return soundType.getDuration();
|
||||
}
|
||||
|
||||
}
|
@ -33,39 +33,24 @@ public class AudioReader {
|
||||
}
|
||||
|
||||
// TODO fix converting from mono-stereo
|
||||
private static SoundType readAsSpecified(String path, String id, int format) {
|
||||
private static SoundType readAsSpecified(Resource resource, String id, int format) {
|
||||
IntBuffer channelBuffer = BufferUtils.createIntBuffer(1);
|
||||
IntBuffer rateBuffer = BufferUtils.createIntBuffer(1);
|
||||
|
||||
Resource res = ResourceManager.getResource(path);
|
||||
ShortBuffer rawAudio = decodeVorbis(resource, channelBuffer, rateBuffer);
|
||||
|
||||
ShortBuffer rawAudio = decodeVorbis(res, channelBuffer, rateBuffer);
|
||||
|
||||
return new SoundType(
|
||||
id,
|
||||
rawAudio,
|
||||
format,
|
||||
rateBuffer.get(0)
|
||||
);
|
||||
return new SoundType(id, rawAudio, format, rateBuffer.get(0));
|
||||
}
|
||||
|
||||
public static SoundType readAsMono(String path, String id) {
|
||||
return readAsSpecified(path, id, AL_FORMAT_MONO16);
|
||||
public static SoundType readAsMono(Resource resource, String id) {
|
||||
return readAsSpecified(resource, id, AL_FORMAT_MONO16);
|
||||
}
|
||||
|
||||
public static SoundType readAsStereo(String path, String id) {
|
||||
return readAsSpecified(path, id, AL_FORMAT_STEREO16);
|
||||
public static SoundType readAsStereo(Resource resource, String id) {
|
||||
return readAsSpecified(resource, id, AL_FORMAT_STEREO16);
|
||||
}
|
||||
|
||||
private static ShortBuffer decodeVorbis(
|
||||
Resource dataToDecode,
|
||||
IntBuffer channelsBuffer,
|
||||
IntBuffer rateBuffer
|
||||
) {
|
||||
return stb_vorbis_decode_memory(
|
||||
dataToDecode.readAsBytes(),
|
||||
channelsBuffer,
|
||||
rateBuffer
|
||||
);
|
||||
private static ShortBuffer decodeVorbis(Resource dataToDecode, IntBuffer channelsBuffer, IntBuffer rateBuffer) {
|
||||
return stb_vorbis_decode_memory(dataToDecode.readAsBytes(), channelsBuffer, rateBuffer);
|
||||
}
|
||||
}
|
||||
|
@ -55,9 +55,8 @@ public class Listener {
|
||||
if (isInWorld) {
|
||||
|
||||
if (wasInWorld) {
|
||||
velocity.set(camera.getLastAnchorPosition()).sub(position).div(
|
||||
(float) GraphicsInterface.getFrameLength()
|
||||
);
|
||||
velocity.set(camera.getLastAnchorPosition()).sub(position)
|
||||
.div((float) GraphicsInterface.getFrameLength());
|
||||
} else {
|
||||
// If !wasInWorld, previous position is nonsence. Assume 0.
|
||||
velocity.set(0);
|
||||
@ -72,9 +71,9 @@ public class Listener {
|
||||
}
|
||||
|
||||
/*
|
||||
* Only apply if there is a chance that params changed.
|
||||
* This can only happen if we are in world now (isInWorld) or we just
|
||||
* left world (wasInWorld, then we need to reset).
|
||||
* Only apply if there is a chance that params changed. This can only
|
||||
* happen if we are in world now (isInWorld) or we just left world
|
||||
* (wasInWorld, then we need to reset).
|
||||
*/
|
||||
if (isInWorld || wasInWorld) {
|
||||
applyParams();
|
||||
@ -91,17 +90,7 @@ public class Listener {
|
||||
private void applyParams() {
|
||||
alListener3f(AL_POSITION, position.x, position.y, position.z);
|
||||
alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z);
|
||||
alListenerfv(
|
||||
AL_ORIENTATION,
|
||||
new float[] {
|
||||
oriAt.x,
|
||||
oriAt.y,
|
||||
oriAt.z,
|
||||
oriUp.x,
|
||||
oriUp.y,
|
||||
oriUp.z
|
||||
}
|
||||
);
|
||||
alListenerfv(AL_ORIENTATION, new float[] { oriAt.x, oriAt.y, oriAt.z, oriUp.x, oriUp.y, oriUp.z });
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,6 +21,9 @@ package ru.windcorp.progressia.client.audio.backend;
|
||||
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
|
||||
|
||||
import java.nio.ShortBuffer;
|
||||
|
||||
import org.lwjgl.openal.AL10;
|
||||
|
||||
import static org.lwjgl.openal.AL11.*;
|
||||
|
||||
public class SoundType extends Namespaced {
|
||||
@ -29,13 +32,9 @@ public class SoundType extends Namespaced {
|
||||
private int sampleRate;
|
||||
private int format;
|
||||
private int audioBuffer;
|
||||
private double duration;
|
||||
|
||||
public SoundType(
|
||||
String id,
|
||||
ShortBuffer rawAudio,
|
||||
int format,
|
||||
int sampleRate
|
||||
) {
|
||||
public SoundType(String id, ShortBuffer rawAudio, int format, int sampleRate) {
|
||||
super(id);
|
||||
this.rawAudio = rawAudio;
|
||||
this.sampleRate = sampleRate;
|
||||
@ -46,9 +45,14 @@ public class SoundType extends Namespaced {
|
||||
private void createAudioBuffer() {
|
||||
this.audioBuffer = alGenBuffers();
|
||||
alBufferData(audioBuffer, format, rawAudio, sampleRate);
|
||||
duration = rawAudio.limit() / (double) sampleRate / (format == AL10.AL_FORMAT_STEREO16 ? 2 : 1);
|
||||
}
|
||||
|
||||
public void initSpeaker(Speaker speaker) {
|
||||
speaker.setAudioData(audioBuffer);
|
||||
}
|
||||
|
||||
public double getDuration() {
|
||||
return duration;
|
||||
}
|
||||
}
|
@ -24,9 +24,7 @@ import static org.lwjgl.openal.AL11.*;
|
||||
public class Speaker {
|
||||
|
||||
public enum State {
|
||||
NOT_PLAYING,
|
||||
PLAYING,
|
||||
PLAYING_LOOP
|
||||
NOT_PLAYING, PLAYING, PLAYING_LOOP
|
||||
}
|
||||
|
||||
// Buffers
|
||||
@ -49,13 +47,7 @@ public class Speaker {
|
||||
setAudioData(audioData);
|
||||
}
|
||||
|
||||
public Speaker(
|
||||
int audioData,
|
||||
Vec3 position,
|
||||
Vec3 velocity,
|
||||
float pitch,
|
||||
float gain
|
||||
) {
|
||||
public Speaker(int audioData, Vec3 position, Vec3 velocity, float pitch, float gain) {
|
||||
setAudioData(audioData);
|
||||
setPosition(position);
|
||||
setVelocity(velocity);
|
||||
@ -63,12 +55,7 @@ public class Speaker {
|
||||
setGain(gain);
|
||||
}
|
||||
|
||||
public Speaker(
|
||||
Vec3 position,
|
||||
Vec3 velocity,
|
||||
float pitch,
|
||||
float gain
|
||||
) {
|
||||
public Speaker(Vec3 position, Vec3 velocity, float pitch, float gain) {
|
||||
setPosition(position);
|
||||
setVelocity(velocity);
|
||||
setPitch(pitch);
|
||||
@ -120,6 +107,7 @@ public class Speaker {
|
||||
}
|
||||
|
||||
public void setAudioData(int audioData) {
|
||||
stop();
|
||||
this.audioData = audioData;
|
||||
alSourcei(this.sourceData, AL_BUFFER, audioData);
|
||||
}
|
||||
|
@ -39,9 +39,7 @@ public class DefaultClientCommsListener implements CommsListener {
|
||||
@Override
|
||||
public void onPacketReceived(Packet packet) {
|
||||
if (packet instanceof PacketAffectWorld) {
|
||||
((PacketAffectWorld) packet).apply(
|
||||
getClient().getWorld().getData()
|
||||
);
|
||||
((PacketAffectWorld) packet).apply(getClient().getWorld().getData());
|
||||
} else if (packet instanceof PacketSetLocalPlayer) {
|
||||
setLocalPlayer((PacketSetLocalPlayer) packet);
|
||||
}
|
||||
|
@ -33,17 +33,12 @@ public class ControlTriggerLambda extends ControlTriggerInputBased {
|
||||
private final Predicate<InputEvent> predicate;
|
||||
private final BiConsumer<InputEvent, ControlData> dataWriter;
|
||||
|
||||
public ControlTriggerLambda(
|
||||
String id,
|
||||
Predicate<InputEvent> predicate,
|
||||
BiConsumer<InputEvent, ControlData> dataWriter
|
||||
) {
|
||||
public ControlTriggerLambda(String id, Predicate<InputEvent> predicate,
|
||||
BiConsumer<InputEvent, ControlData> dataWriter) {
|
||||
super(id);
|
||||
|
||||
this.packetId = NamespacedUtil.getId(
|
||||
NamespacedUtil.getNamespace(id),
|
||||
"ControlKeyPress" + NamespacedUtil.getName(id)
|
||||
);
|
||||
this.packetId = NamespacedUtil.getId(NamespacedUtil.getNamespace(id),
|
||||
"ControlKeyPress" + NamespacedUtil.getName(id));
|
||||
|
||||
this.predicate = predicate;
|
||||
this.dataWriter = dataWriter;
|
||||
@ -54,10 +49,7 @@ public class ControlTriggerLambda extends ControlTriggerInputBased {
|
||||
if (!predicate.test(event))
|
||||
return null;
|
||||
|
||||
PacketControl packet = new PacketControl(
|
||||
packetId,
|
||||
ControlDataRegistry.getInstance().create(getId())
|
||||
);
|
||||
PacketControl packet = new PacketControl(packetId, ControlDataRegistry.getInstance().create(getId()));
|
||||
|
||||
dataWriter.accept(event, packet.getControl());
|
||||
|
||||
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package ru.windcorp.progressia.client.comms.controls;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
||||
import ru.windcorp.progressia.common.comms.controls.PacketControl;
|
||||
|
||||
public class ControlTriggerLocalLambda extends ControlTriggerInputBased {
|
||||
|
||||
private final Predicate<InputEvent> predicate;
|
||||
private final Consumer<InputEvent> action;
|
||||
|
||||
public ControlTriggerLocalLambda(String id, Predicate<InputEvent> predicate, Consumer<InputEvent> action) {
|
||||
super(id);
|
||||
|
||||
this.predicate = predicate;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketControl onInputEvent(InputEvent event) {
|
||||
if (!predicate.test(event))
|
||||
return null;
|
||||
|
||||
action.accept(event);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -27,133 +27,119 @@ import ru.windcorp.progressia.common.comms.controls.ControlData;
|
||||
|
||||
public class ControlTriggers {
|
||||
|
||||
public static ControlTriggerInputBased of(
|
||||
String id,
|
||||
BiConsumer<InputEvent, ControlData> dataWriter,
|
||||
Predicate<InputEvent> predicate
|
||||
) {
|
||||
public static ControlTriggerInputBased of(String id, BiConsumer<InputEvent, ControlData> dataWriter,
|
||||
Predicate<InputEvent> predicate) {
|
||||
return new ControlTriggerLambda(id, predicate, dataWriter);
|
||||
}
|
||||
|
||||
public static ControlTriggerInputBased of(
|
||||
String id,
|
||||
Consumer<ControlData> dataWriter,
|
||||
Predicate<InputEvent> predicate
|
||||
) {
|
||||
return of(
|
||||
id,
|
||||
(input, control) -> dataWriter.accept(control),
|
||||
predicate
|
||||
);
|
||||
public static ControlTriggerInputBased of(String id, Consumer<ControlData> dataWriter,
|
||||
Predicate<InputEvent> predicate) {
|
||||
return of(id, (input, control) -> dataWriter.accept(control), predicate);
|
||||
}
|
||||
|
||||
public static ControlTriggerInputBased of(
|
||||
String id,
|
||||
Predicate<InputEvent> predicate
|
||||
) {
|
||||
return of(
|
||||
id,
|
||||
(input, control) -> {
|
||||
},
|
||||
predicate
|
||||
);
|
||||
public static ControlTriggerInputBased of(String id, Predicate<InputEvent> predicate) {
|
||||
return of(id, (input, control) -> {
|
||||
}, predicate);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <I extends InputEvent> ControlTriggerInputBased of(
|
||||
String id,
|
||||
Class<I> inputType,
|
||||
BiConsumer<I, ControlData> dataWriter,
|
||||
Predicate<I>... predicates
|
||||
) {
|
||||
return of(
|
||||
id,
|
||||
createCheckedDataWriter(inputType, dataWriter),
|
||||
createCheckedCompoundPredicate(inputType, predicates)
|
||||
);
|
||||
public static <I extends InputEvent> ControlTriggerInputBased of(String id, Class<I> inputType,
|
||||
BiConsumer<I, ControlData> dataWriter, Predicate<I>... predicates) {
|
||||
return of(id, createCheckedDataWriter(inputType, dataWriter),
|
||||
createCheckedCompoundPredicate(inputType, predicates));
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <I extends InputEvent> ControlTriggerInputBased of(
|
||||
String id,
|
||||
Class<I> inputType,
|
||||
Consumer<ControlData> dataWriter,
|
||||
Predicate<I>... predicates
|
||||
) {
|
||||
return of(
|
||||
id,
|
||||
inputType,
|
||||
(input, control) -> dataWriter.accept(control),
|
||||
predicates
|
||||
);
|
||||
public static <I extends InputEvent> ControlTriggerInputBased of(String id, Class<I> inputType,
|
||||
Consumer<ControlData> dataWriter, Predicate<I>... predicates) {
|
||||
return of(id, inputType, (input, control) -> dataWriter.accept(control), predicates);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <I extends InputEvent> ControlTriggerInputBased of(
|
||||
String id,
|
||||
Class<I> inputType,
|
||||
Predicate<I>... predicates
|
||||
) {
|
||||
return of(
|
||||
id,
|
||||
(input, control) -> {
|
||||
},
|
||||
createCheckedCompoundPredicate(inputType, predicates)
|
||||
);
|
||||
public static <I extends InputEvent> ControlTriggerInputBased of(String id, Class<I> inputType,
|
||||
Predicate<I>... predicates) {
|
||||
return of(id, (input, control) -> {
|
||||
}, createCheckedCompoundPredicate(inputType, predicates));
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static ControlTriggerInputBased of(
|
||||
String id,
|
||||
BiConsumer<InputEvent, ControlData> dataWriter,
|
||||
Predicate<InputEvent>... predicates
|
||||
) {
|
||||
return of(
|
||||
id,
|
||||
InputEvent.class,
|
||||
dataWriter,
|
||||
predicates
|
||||
);
|
||||
public static ControlTriggerInputBased of(String id, BiConsumer<InputEvent, ControlData> dataWriter,
|
||||
Predicate<InputEvent>... predicates) {
|
||||
return of(id, InputEvent.class, dataWriter, predicates);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <I extends InputEvent> ControlTriggerInputBased of(
|
||||
String id,
|
||||
Consumer<ControlData> dataWriter,
|
||||
Predicate<InputEvent>... predicates
|
||||
) {
|
||||
return of(
|
||||
id,
|
||||
(input, control) -> dataWriter.accept(control),
|
||||
predicates
|
||||
);
|
||||
public static <I extends InputEvent> ControlTriggerInputBased of(String id, Consumer<ControlData> dataWriter,
|
||||
Predicate<InputEvent>... predicates) {
|
||||
return of(id, (input, control) -> dataWriter.accept(control), predicates);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static ControlTriggerInputBased of(
|
||||
String id,
|
||||
Predicate<InputEvent>... predicates
|
||||
) {
|
||||
return of(
|
||||
id,
|
||||
InputEvent.class,
|
||||
(input, control) -> {
|
||||
},
|
||||
predicates
|
||||
);
|
||||
public static ControlTriggerInputBased of(String id, Predicate<InputEvent>... predicates) {
|
||||
return of(id, InputEvent.class, (input, control) -> {
|
||||
}, predicates);
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
///
|
||||
///
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
public static ControlTriggerInputBased localOf(String id, Consumer<InputEvent> action,
|
||||
Predicate<InputEvent> predicate) {
|
||||
return new ControlTriggerLocalLambda(id, predicate, action);
|
||||
}
|
||||
|
||||
public static ControlTriggerInputBased localOf(String id, Runnable action, Predicate<InputEvent> predicate) {
|
||||
return localOf(id, input -> action.run(), predicate);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <I extends InputEvent> ControlTriggerInputBased localOf(String id, Class<I> inputType,
|
||||
Consumer<I> action, Predicate<I>... predicates) {
|
||||
return localOf(id, createCheckedAction(inputType, action),
|
||||
createCheckedCompoundPredicate(inputType, predicates));
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <I extends InputEvent> ControlTriggerInputBased localOf(String id, Class<I> inputType,
|
||||
Runnable action, Predicate<I>... predicates) {
|
||||
return localOf(id, inputType, input -> action.run(), predicates);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static ControlTriggerInputBased localOf(String id, Consumer<InputEvent> action,
|
||||
Predicate<InputEvent>... predicates) {
|
||||
return localOf(id, InputEvent.class, action, predicates);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <I extends InputEvent> ControlTriggerInputBased localOf(String id, Runnable action,
|
||||
Predicate<InputEvent>... predicates) {
|
||||
return of(id, input -> action.run(), predicates);
|
||||
}
|
||||
|
||||
private static <I extends InputEvent> BiConsumer<InputEvent, ControlData> createCheckedDataWriter(
|
||||
Class<I> inputType,
|
||||
BiConsumer<I, ControlData> dataWriter
|
||||
) {
|
||||
Class<I> inputType, BiConsumer<I, ControlData> dataWriter) {
|
||||
return (inputEvent, control) -> dataWriter.accept(inputType.cast(inputEvent), control);
|
||||
}
|
||||
|
||||
private static <I extends InputEvent> Predicate<InputEvent> createCheckedCompoundPredicate(
|
||||
Class<I> inputType,
|
||||
Predicate<I>[] predicates
|
||||
) {
|
||||
private static <I extends InputEvent> Consumer<InputEvent> createCheckedAction(Class<I> inputType,
|
||||
Consumer<I> action) {
|
||||
return inputEvent -> action.accept(inputType.cast(inputEvent));
|
||||
}
|
||||
|
||||
private static <I extends InputEvent> Predicate<InputEvent> createCheckedCompoundPredicate(Class<I> inputType,
|
||||
Predicate<I>[] predicates) {
|
||||
return new CompoundCastPredicate<>(inputType, predicates);
|
||||
}
|
||||
|
||||
|
@ -32,8 +32,7 @@ public class InputBasedControls {
|
||||
this.client = client;
|
||||
|
||||
this.controls = ControlTriggerRegistry.getInstance().values().stream()
|
||||
.filter(ControlTriggerInputBased.class::isInstance)
|
||||
.toArray(ControlTriggerInputBased[]::new);
|
||||
.filter(ControlTriggerInputBased.class::isInstance).toArray(ControlTriggerInputBased[]::new);
|
||||
}
|
||||
|
||||
public void handleInput(Input input) {
|
||||
|
@ -34,11 +34,7 @@ public class LocalServerCommsChannel extends ServerCommsChannel {
|
||||
public void connect(String login) {
|
||||
setState(State.CONNECTED);
|
||||
|
||||
this.localClient = new LocalClient(
|
||||
server.getClientManager().grabClientId(),
|
||||
login,
|
||||
this
|
||||
);
|
||||
this.localClient = new LocalClient(server.getClientManager().grabClientId(), login, this);
|
||||
|
||||
server.getClientManager().addClient(localClient);
|
||||
}
|
||||
|
@ -34,7 +34,13 @@ public class Colors {
|
||||
DEBUG_BLUE = toVector(0xFF0000FF),
|
||||
DEBUG_CYAN = toVector(0xFF00FFFF),
|
||||
DEBUG_MAGENTA = toVector(0xFFFF00FF),
|
||||
DEBUG_YELLOW = toVector(0xFFFFFF00);
|
||||
DEBUG_YELLOW = toVector(0xFFFFFF00),
|
||||
|
||||
LIGHT_GRAY = toVector(0xFFCBCBD0),
|
||||
BLUE = toVector(0xFF37A2E6),
|
||||
HOVER_BLUE = toVector(0xFFC3E4F7),
|
||||
DISABLED_GRAY = toVector(0xFFE5E5E5),
|
||||
DISABLED_BLUE = toVector(0xFFB2D8ED);
|
||||
|
||||
public static Vec4 toVector(int argb) {
|
||||
return toVector(argb, new Vec4());
|
||||
|
@ -24,6 +24,7 @@ import java.util.List;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
||||
import ru.windcorp.progressia.client.graphics.input.CursorEvent;
|
||||
import ru.windcorp.progressia.client.graphics.input.FrameResizeEvent;
|
||||
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
||||
@ -57,15 +58,24 @@ public class GUI {
|
||||
}
|
||||
|
||||
public static void addBottomLayer(Layer layer) {
|
||||
modify(layers -> layers.add(layer));
|
||||
modify(layers -> {
|
||||
layers.add(layer);
|
||||
layer.onAdded();
|
||||
});
|
||||
}
|
||||
|
||||
public static void addTopLayer(Layer layer) {
|
||||
modify(layers -> layers.add(0, layer));
|
||||
modify(layers -> {
|
||||
layers.add(0, layer);
|
||||
layer.onAdded();
|
||||
});
|
||||
}
|
||||
|
||||
public static void removeLayer(Layer layer) {
|
||||
modify(layers -> layers.remove(layer));
|
||||
modify(layers -> {
|
||||
layers.remove(layer);
|
||||
layer.onRemoved();
|
||||
});
|
||||
}
|
||||
|
||||
private static void modify(LayerStackModification mod) {
|
||||
@ -78,12 +88,33 @@ public class GUI {
|
||||
|
||||
public static void render() {
|
||||
synchronized (LAYERS) {
|
||||
|
||||
if (!MODIFICATION_QUEUE.isEmpty()) {
|
||||
MODIFICATION_QUEUE.forEach(action -> action.affect(LAYERS));
|
||||
MODIFICATION_QUEUE.clear();
|
||||
|
||||
boolean isMouseCurrentlyCaptured = GraphicsInterface.isMouseCaptured();
|
||||
Layer.CursorPolicy policy = Layer.CursorPolicy.REQUIRE;
|
||||
|
||||
for (Layer layer : LAYERS) {
|
||||
Layer.CursorPolicy currentPolicy = layer.getCursorPolicy();
|
||||
|
||||
if (currentPolicy != Layer.CursorPolicy.INDIFFERENT) {
|
||||
policy = currentPolicy;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
boolean shouldCaptureMouse = (policy == Layer.CursorPolicy.FORBID);
|
||||
if (shouldCaptureMouse != isMouseCurrentlyCaptured) {
|
||||
GraphicsInterface.setMouseCaptured(shouldCaptureMouse);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = LAYERS.size() - 1; i >= 0; --i) {
|
||||
LAYERS.get(i).render();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,15 +31,52 @@ public abstract class Layer {
|
||||
|
||||
private final AtomicBoolean isValid = new AtomicBoolean(false);
|
||||
|
||||
/**
|
||||
* Represents various requests that a {@link Layer} can make regarding the
|
||||
* presence of a visible cursor. The value of the highest layer that is not
|
||||
* {@link #INDIFFERENT} is used.
|
||||
*/
|
||||
public static enum CursorPolicy {
|
||||
/**
|
||||
* Require that a cursor is visible.
|
||||
*/
|
||||
REQUIRE,
|
||||
|
||||
/**
|
||||
* The {@link Layer} should not affect the presence or absence of a
|
||||
* visible cursor; lower layers should be consulted.
|
||||
*/
|
||||
INDIFFERENT,
|
||||
|
||||
/**
|
||||
* Forbid a visible cursor.
|
||||
*/
|
||||
FORBID
|
||||
}
|
||||
|
||||
private CursorPolicy cursorPolicy = CursorPolicy.INDIFFERENT;
|
||||
|
||||
public Layer(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Layer " + name;
|
||||
}
|
||||
|
||||
public CursorPolicy getCursorPolicy() {
|
||||
return cursorPolicy;
|
||||
}
|
||||
|
||||
public void setCursorPolicy(CursorPolicy cursorPolicy) {
|
||||
this.cursorPolicy = cursorPolicy;
|
||||
}
|
||||
|
||||
void render() {
|
||||
GraphicsInterface.startNextLayer();
|
||||
|
||||
@ -79,4 +116,12 @@ public abstract class Layer {
|
||||
return GraphicsInterface.getFrameHeight();
|
||||
}
|
||||
|
||||
protected void onAdded() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
protected void onRemoved() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,11 +18,11 @@
|
||||
|
||||
package ru.windcorp.progressia.client.graphics.backend;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
|
||||
import glm.vec._2.i.Vec2i;
|
||||
import org.lwjgl.glfw.GLFWVidMode;
|
||||
|
||||
import static org.lwjgl.glfw.GLFW.*;
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
|
||||
public class GraphicsBackend {
|
||||
|
||||
@ -38,9 +38,30 @@ public class GraphicsBackend {
|
||||
|
||||
private static boolean faceCullingEnabled = false;
|
||||
|
||||
private static boolean isFullscreen = false;
|
||||
private static boolean vSyncEnabled = false;
|
||||
private static boolean isGLFWInitialized = false;
|
||||
private static boolean isOpenGLInitialized = false;
|
||||
|
||||
private GraphicsBackend() {
|
||||
}
|
||||
|
||||
public static boolean isGLFWInitialized() {
|
||||
return isGLFWInitialized;
|
||||
}
|
||||
|
||||
static void setGLFWInitialized(boolean isGLFWInitialized) {
|
||||
GraphicsBackend.isGLFWInitialized = isGLFWInitialized;
|
||||
}
|
||||
|
||||
public static boolean isOpenGLInitialized() {
|
||||
return isOpenGLInitialized;
|
||||
}
|
||||
|
||||
static void setOpenGLInitialized(boolean isOpenGLInitialized) {
|
||||
GraphicsBackend.isOpenGLInitialized = isOpenGLInitialized;
|
||||
}
|
||||
|
||||
public static void initialize() {
|
||||
startRenderThread();
|
||||
}
|
||||
@ -128,4 +149,48 @@ public class GraphicsBackend {
|
||||
faceCullingEnabled = useFaceCulling;
|
||||
}
|
||||
|
||||
public static boolean isFullscreen() {
|
||||
return isFullscreen;
|
||||
}
|
||||
|
||||
public static boolean isVSyncEnabled() {
|
||||
return vSyncEnabled;
|
||||
}
|
||||
|
||||
public static void setFullscreen() {
|
||||
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
||||
glfwSetWindowMonitor(getWindowHandle(), glfwGetPrimaryMonitor(), 0, 0, vidmode.width(), vidmode.height(), 0);
|
||||
isFullscreen = true;
|
||||
}
|
||||
|
||||
public static void setWindowed() {
|
||||
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
||||
glfwSetWindowMonitor(getWindowHandle(), 0, (vidmode.width() - getFrameWidth()) / 2,
|
||||
(vidmode.height() - getFrameHeight()) / 2, getFrameWidth(), getFrameHeight(), 0);
|
||||
isFullscreen = false;
|
||||
}
|
||||
|
||||
public static void setVSyncEnabled(boolean enable) {
|
||||
glfwSwapInterval(enable ? 1 : 0);
|
||||
vSyncEnabled = enable;
|
||||
}
|
||||
|
||||
public static int getRefreshRate() {
|
||||
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
||||
return vidmode.refreshRate();
|
||||
}
|
||||
|
||||
public static boolean isMouseCaptured() {
|
||||
return glfwGetInputMode(windowHandle, GLFW_CURSOR) == GLFW_CURSOR_DISABLED;
|
||||
}
|
||||
|
||||
public static void setMouseCaptured(boolean capture) {
|
||||
int mode = capture ? GLFW_CURSOR_DISABLED : GLFW_CURSOR_NORMAL;
|
||||
glfwSetInputMode(windowHandle, GLFW_CURSOR, mode);
|
||||
|
||||
if (!capture) {
|
||||
glfwSetCursorPos(windowHandle, FRAME_SIZE.x / 2.0, FRAME_SIZE.y / 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -73,4 +73,21 @@ public class GraphicsInterface {
|
||||
GraphicsBackend.startNextLayer();
|
||||
}
|
||||
|
||||
public static void makeFullscreen(boolean state) {
|
||||
if (state) {
|
||||
GraphicsBackend.setFullscreen();
|
||||
} else {
|
||||
GraphicsBackend.setWindowed();
|
||||
}
|
||||
GraphicsBackend.setVSyncEnabled(GraphicsBackend.isVSyncEnabled());
|
||||
}
|
||||
|
||||
public static boolean isMouseCaptured() {
|
||||
return GraphicsBackend.isMouseCaptured();
|
||||
}
|
||||
|
||||
public static void setMouseCaptured(boolean capture) {
|
||||
GraphicsBackend.setMouseCaptured(capture);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -49,13 +49,7 @@ public class InputHandler {
|
||||
|
||||
private static final ModifiableKeyEvent THE_KEY_EVENT = new ModifiableKeyEvent();
|
||||
|
||||
static void handleKeyInput(
|
||||
long window,
|
||||
int key,
|
||||
int scancode,
|
||||
int action,
|
||||
int mods
|
||||
) {
|
||||
static void handleKeyInput(long window, int key, int scancode, int action, int mods) {
|
||||
if (GraphicsBackend.getWindowHandle() != window)
|
||||
return;
|
||||
THE_KEY_EVENT.initialize(key, scancode, action, mods);
|
||||
@ -71,12 +65,7 @@ public class InputHandler {
|
||||
}
|
||||
}
|
||||
|
||||
static void handleMouseButtonInput(
|
||||
long window,
|
||||
int key,
|
||||
int action,
|
||||
int mods
|
||||
) {
|
||||
static void handleMouseButtonInput(long window, int key, int action, int mods) {
|
||||
handleKeyInput(window, key, Integer.MAX_VALUE - key, action, mods);
|
||||
}
|
||||
|
||||
@ -97,11 +86,7 @@ public class InputHandler {
|
||||
|
||||
private static final ModifiableCursorMoveEvent THE_CURSOR_MOVE_EVENT = new ModifiableCursorMoveEvent();
|
||||
|
||||
static void handleMouseMoveInput(
|
||||
long window,
|
||||
double x,
|
||||
double y
|
||||
) {
|
||||
static void handleMouseMoveInput(long window, double x, double y) {
|
||||
if (GraphicsBackend.getWindowHandle() != window)
|
||||
return;
|
||||
y = GraphicsInterface.getFrameHeight() - y; // Flip y axis
|
||||
@ -131,11 +116,7 @@ public class InputHandler {
|
||||
|
||||
private static final ModifiableWheelScrollEvent THE_WHEEL_SCROLL_EVENT = new ModifiableWheelScrollEvent();
|
||||
|
||||
static void handleWheelScroll(
|
||||
long window,
|
||||
double xoffset,
|
||||
double yoffset
|
||||
) {
|
||||
static void handleWheelScroll(long window, double xoffset, double yoffset) {
|
||||
if (GraphicsBackend.getWindowHandle() != window)
|
||||
return;
|
||||
THE_WHEEL_SCROLL_EVENT.initialize(xoffset, yoffset);
|
||||
@ -162,10 +143,7 @@ public class InputHandler {
|
||||
/*
|
||||
* NB: this is NOT a GLFW callback, the raw callback is in GraphicsBackend
|
||||
*/
|
||||
static void handleFrameResize(
|
||||
int width,
|
||||
int height
|
||||
) {
|
||||
static void handleFrameResize(int width, int height) {
|
||||
THE_FRAME_RESIZE_EVENT.initialize(width, height);
|
||||
dispatch(THE_FRAME_RESIZE_EVENT);
|
||||
}
|
||||
|
@ -24,10 +24,7 @@ import gnu.trove.set.hash.TIntHashSet;
|
||||
|
||||
public class InputTracker {
|
||||
|
||||
private static final Vec2d CURSOR_POSITION = new Vec2d(
|
||||
Double.NaN,
|
||||
Double.NaN
|
||||
);
|
||||
private static final Vec2d CURSOR_POSITION = new Vec2d(Double.NaN, Double.NaN);
|
||||
|
||||
private static final TIntSet PRESSED_KEYS = new TIntHashSet(256);
|
||||
|
||||
|
@ -50,6 +50,7 @@ class LWJGLInitializer {
|
||||
private static void initializeGLFW() {
|
||||
// TODO Do GLFW error handling: check glfwInit, setup error callback
|
||||
glfwInit();
|
||||
GraphicsBackend.setGLFWInitialized(true);
|
||||
}
|
||||
|
||||
private static void createWindow() {
|
||||
@ -64,10 +65,8 @@ class LWJGLInitializer {
|
||||
|
||||
GraphicsBackend.setWindowHandle(handle);
|
||||
|
||||
glfwSetInputMode(handle, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
|
||||
|
||||
glfwMakeContextCurrent(handle);
|
||||
glfwSwapInterval(0);
|
||||
glfwSwapInterval(0); // TODO: remove after config system is added
|
||||
}
|
||||
|
||||
private static void positionWindow() {
|
||||
@ -87,21 +86,16 @@ class LWJGLInitializer {
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
RenderTaskQueue.schedule(OpenGLObjectTracker::deleteEnqueuedObjects);
|
||||
GraphicsBackend.setOpenGLInitialized(true);
|
||||
}
|
||||
|
||||
private static void setupWindowCallbacks() {
|
||||
long handle = GraphicsBackend.getWindowHandle();
|
||||
|
||||
glfwSetFramebufferSizeCallback(
|
||||
handle,
|
||||
GraphicsBackend::onFrameResized
|
||||
);
|
||||
glfwSetFramebufferSizeCallback(handle, GraphicsBackend::onFrameResized);
|
||||
|
||||
glfwSetKeyCallback(handle, InputHandler::handleKeyInput);
|
||||
glfwSetMouseButtonCallback(
|
||||
handle,
|
||||
InputHandler::handleMouseButtonInput
|
||||
);
|
||||
glfwSetMouseButtonCallback(handle, InputHandler::handleMouseButtonInput);
|
||||
|
||||
glfwSetCursorPosCallback(handle, InputHandler::handleMouseMoveInput);
|
||||
|
||||
|
@ -34,19 +34,13 @@ public class OpenGLObjectTracker {
|
||||
private static final ReferenceQueue<OpenGLDeletable> DELETE_QUEUE = new ReferenceQueue<>();
|
||||
|
||||
public synchronized static void register(OpenGLDeletable object, IntConsumer glDeleter) {
|
||||
GLPhantomReference<OpenGLDeletable> glRef = new GLPhantomReference<>(
|
||||
object,
|
||||
DELETE_QUEUE,
|
||||
object.getHandle(),
|
||||
glDeleter
|
||||
);
|
||||
GLPhantomReference<OpenGLDeletable> glRef = new GLPhantomReference<>(object, DELETE_QUEUE, object.getHandle(),
|
||||
glDeleter);
|
||||
TO_DELETE.add(glRef);
|
||||
}
|
||||
|
||||
public static void deleteAllObjects() {
|
||||
for (
|
||||
GLPhantomReference<OpenGLDeletable> glRef : TO_DELETE
|
||||
) {
|
||||
for (GLPhantomReference<OpenGLDeletable> glRef : TO_DELETE) {
|
||||
glRef.clear();
|
||||
}
|
||||
}
|
||||
@ -75,20 +69,16 @@ public class OpenGLObjectTracker {
|
||||
* It is possible to create a phantom reference with a {@code null}
|
||||
* queue, but such a reference is completely useless: Its {@code get}
|
||||
* method will always return {@code null} and, since it does not have a
|
||||
* queue,
|
||||
* it will never be enqueued.
|
||||
* queue, it will never be enqueued.
|
||||
*
|
||||
* @param referent the object the new phantom reference will refer to
|
||||
* @param q the queue with which the reference is to be
|
||||
* registered,
|
||||
* or {@code null} if registration is not required
|
||||
* @param referent
|
||||
* the object the new phantom reference will refer to
|
||||
* @param q
|
||||
* the queue with which the reference is to be registered, or
|
||||
* {@code null} if registration is not required
|
||||
*/
|
||||
public GLPhantomReference(
|
||||
T referent,
|
||||
ReferenceQueue<? super T> q,
|
||||
int referentGLhandle,
|
||||
IntConsumer GLDeleter
|
||||
) {
|
||||
public GLPhantomReference(T referent, ReferenceQueue<? super T> q, int referentGLhandle,
|
||||
IntConsumer GLDeleter) {
|
||||
super(referent, q);
|
||||
this.referentGLhandle = referentGLhandle;
|
||||
this.GLDeleter = GLDeleter;
|
||||
|
@ -41,11 +41,7 @@ public class RenderTaskQueue {
|
||||
HANDLER.invokeNow(task);
|
||||
}
|
||||
|
||||
public static <E extends Exception> void waitAndInvoke(
|
||||
ThrowingRunnable<E> task
|
||||
)
|
||||
throws InterruptedException,
|
||||
E {
|
||||
public static <E extends Exception> void waitAndInvoke(ThrowingRunnable<E> task) throws InterruptedException, E {
|
||||
HANDLER.waitAndInvoke(task);
|
||||
}
|
||||
|
||||
|
@ -23,9 +23,7 @@ import static org.lwjgl.opengl.GL15.GL_STATIC_DRAW;
|
||||
import static org.lwjgl.opengl.GL15.GL_STREAM_DRAW;
|
||||
|
||||
public enum Usage { // TODO add _COPY and _READ, pref. as another enum
|
||||
STATIC(GL_STATIC_DRAW),
|
||||
DYNAMIC(GL_DYNAMIC_DRAW),
|
||||
STREAM(GL_STREAM_DRAW);
|
||||
STATIC(GL_STATIC_DRAW), DYNAMIC(GL_DYNAMIC_DRAW), STREAM(GL_STREAM_DRAW);
|
||||
|
||||
private final int glCode;
|
||||
|
||||
|
@ -28,8 +28,7 @@ import ru.windcorp.progressia.client.graphics.backend.OpenGLObjectTracker.OpenGL
|
||||
public class VertexBufferObject implements OpenGLDeletable {
|
||||
|
||||
public static enum BindTarget {
|
||||
ARRAY(GL_ARRAY_BUFFER),
|
||||
ELEMENT_ARRAY(GL_ELEMENT_ARRAY_BUFFER);
|
||||
ARRAY(GL_ARRAY_BUFFER), ELEMENT_ARRAY(GL_ELEMENT_ARRAY_BUFFER);
|
||||
|
||||
private final int glCode;
|
||||
|
||||
|
@ -32,12 +32,7 @@ public class CombinedShader extends Shader {
|
||||
for (int i = 1; i < resources.length; ++i) {
|
||||
if (ShaderType.guessByResourceName(resources[i]) != first) {
|
||||
throw new IllegalArgumentException(
|
||||
"Deduced shader types of "
|
||||
+ resources[0]
|
||||
+ " and "
|
||||
+ resources[i]
|
||||
+ " differ"
|
||||
);
|
||||
"Deduced shader types of " + resources[0] + " and " + resources[i] + " differ");
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,19 +66,8 @@ public class CombinedShader extends Shader {
|
||||
if (contents.codePointAt(versionIndex) == '#') {
|
||||
final String versionAnnotation = "#version ";
|
||||
|
||||
if (
|
||||
contents.regionMatches(
|
||||
versionIndex,
|
||||
versionAnnotation,
|
||||
0,
|
||||
versionAnnotation.length()
|
||||
)
|
||||
) {
|
||||
contents = contents.substring(
|
||||
versionIndex
|
||||
+ versionAnnotation.length()
|
||||
+ "120".length()
|
||||
);
|
||||
if (contents.regionMatches(versionIndex, versionAnnotation, 0, versionAnnotation.length())) {
|
||||
contents = contents.substring(versionIndex + versionAnnotation.length() + "120".length());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -57,10 +57,7 @@ public class Shader implements OpenGLDeletable {
|
||||
if (resource.contains("fsh"))
|
||||
return FRAGMENT;
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot deduce shader type from resource name \"" +
|
||||
resource + "\""
|
||||
);
|
||||
throw new IllegalArgumentException("Cannot deduce shader type from resource name \"" + resource + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,10 +87,7 @@ public class Shader implements OpenGLDeletable {
|
||||
}
|
||||
|
||||
public Shader(String resource) {
|
||||
this(
|
||||
ShaderType.guessByResourceName(resource),
|
||||
getShaderResource(resource).readAsString()
|
||||
);
|
||||
this(ShaderType.guessByResourceName(resource), getShaderResource(resource).readAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -51,104 +51,29 @@ public class AttributeVertexArray extends Attribute {
|
||||
}
|
||||
}
|
||||
|
||||
public void set(
|
||||
int size,
|
||||
boolean normalized,
|
||||
int stride,
|
||||
ByteBuffer pointer
|
||||
) {
|
||||
glVertexAttribPointer(
|
||||
handle,
|
||||
size,
|
||||
GL_BYTE,
|
||||
normalized,
|
||||
stride,
|
||||
pointer
|
||||
);
|
||||
public void set(int size, boolean normalized, int stride, ByteBuffer pointer) {
|
||||
glVertexAttribPointer(handle, size, GL_BYTE, normalized, stride, pointer);
|
||||
}
|
||||
|
||||
public void set(
|
||||
int size,
|
||||
boolean normalized,
|
||||
int stride,
|
||||
FloatBuffer pointer
|
||||
) {
|
||||
glVertexAttribPointer(
|
||||
handle,
|
||||
size,
|
||||
GL_FLOAT,
|
||||
normalized,
|
||||
stride,
|
||||
pointer
|
||||
);
|
||||
public void set(int size, boolean normalized, int stride, FloatBuffer pointer) {
|
||||
glVertexAttribPointer(handle, size, GL_FLOAT, normalized, stride, pointer);
|
||||
}
|
||||
|
||||
public void set(
|
||||
int size,
|
||||
boolean normalized,
|
||||
int stride,
|
||||
IntBuffer pointer
|
||||
) {
|
||||
glVertexAttribPointer(
|
||||
handle,
|
||||
size,
|
||||
GL_INT,
|
||||
normalized,
|
||||
stride,
|
||||
pointer
|
||||
);
|
||||
public void set(int size, boolean normalized, int stride, IntBuffer pointer) {
|
||||
glVertexAttribPointer(handle, size, GL_INT, normalized, stride, pointer);
|
||||
}
|
||||
|
||||
public void set(
|
||||
int size,
|
||||
boolean normalized,
|
||||
int stride,
|
||||
ShortBuffer pointer
|
||||
) {
|
||||
glVertexAttribPointer(
|
||||
handle,
|
||||
size,
|
||||
GL_SHORT,
|
||||
normalized,
|
||||
stride,
|
||||
pointer
|
||||
);
|
||||
public void set(int size, boolean normalized, int stride, ShortBuffer pointer) {
|
||||
glVertexAttribPointer(handle, size, GL_SHORT, normalized, stride, pointer);
|
||||
}
|
||||
|
||||
public void set(
|
||||
int size,
|
||||
int type,
|
||||
boolean normalized,
|
||||
int stride,
|
||||
long pointer
|
||||
) {
|
||||
glVertexAttribPointer(
|
||||
handle,
|
||||
size,
|
||||
type,
|
||||
normalized,
|
||||
stride,
|
||||
pointer
|
||||
);
|
||||
public void set(int size, int type, boolean normalized, int stride, long pointer) {
|
||||
glVertexAttribPointer(handle, size, type, normalized, stride, pointer);
|
||||
}
|
||||
|
||||
public void set(
|
||||
int size,
|
||||
int type,
|
||||
boolean normalized,
|
||||
int stride,
|
||||
VertexBufferObject vbo,
|
||||
long offset
|
||||
) {
|
||||
public void set(int size, int type, boolean normalized, int stride, VertexBufferObject vbo, long offset) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo.getHandle());
|
||||
glVertexAttribPointer(
|
||||
handle,
|
||||
size,
|
||||
type,
|
||||
normalized,
|
||||
stride,
|
||||
offset
|
||||
);
|
||||
glVertexAttribPointer(handle, size, type, normalized, stride, offset);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -37,8 +37,7 @@ public abstract class FlatRenderHelper extends ShapeRenderHelper {
|
||||
float width = GraphicsInterface.getFrameWidth();
|
||||
float height = GraphicsInterface.getFrameHeight();
|
||||
|
||||
return finalTransform.identity().translate(-1, -1, 0)
|
||||
.scale(2 / width, 2 / height, 1 / MAX_DEPTH)
|
||||
return finalTransform.identity().translate(-1, -1, 0).scale(2 / width, 2 / height, 1 / MAX_DEPTH)
|
||||
.mul(getTransform());
|
||||
}
|
||||
|
||||
|
@ -33,10 +33,8 @@ public class FlatRenderProgram extends ShapeRenderProgram {
|
||||
private static FlatRenderProgram def = null;
|
||||
|
||||
public static void init() {
|
||||
def = new FlatRenderProgram(
|
||||
new String[] { "FlatDefault.vertex.glsl" },
|
||||
new String[] { "FlatDefault.fragment.glsl" }
|
||||
);
|
||||
def = new FlatRenderProgram(new String[] { "FlatDefault.vertex.glsl" },
|
||||
new String[] { "FlatDefault.fragment.glsl" });
|
||||
}
|
||||
|
||||
public static FlatRenderProgram getDefault() {
|
||||
@ -48,20 +46,13 @@ public class FlatRenderProgram extends ShapeRenderProgram {
|
||||
private static final String FLAT_VERTEX_SHADER_RESOURCE = "Flat.vertex.glsl";
|
||||
private static final String FLAT_FRAGMENT_SHADER_RESOURCE = "Flat.fragment.glsl";
|
||||
|
||||
private static final String MASK_COUNT_UNIFORM_NAME = "maskCount",
|
||||
MASKS_UNIFORM_NAME = "masks";
|
||||
private static final String MASK_COUNT_UNIFORM_NAME = "maskCount", MASKS_UNIFORM_NAME = "masks";
|
||||
|
||||
private final Uniform1Int maskCountUniform;
|
||||
private final Uniform2Float masksUniform;
|
||||
|
||||
public FlatRenderProgram(
|
||||
String[] vertexShaderResources,
|
||||
String[] fragmentShaderResources
|
||||
) {
|
||||
super(
|
||||
attachVertexShader(vertexShaderResources),
|
||||
attachFragmentShader(fragmentShaderResources)
|
||||
);
|
||||
public FlatRenderProgram(String[] vertexShaderResources, String[] fragmentShaderResources) {
|
||||
super(attachVertexShader(vertexShaderResources), attachFragmentShader(fragmentShaderResources));
|
||||
|
||||
this.maskCountUniform = getUniform(MASK_COUNT_UNIFORM_NAME).as1Int();
|
||||
this.masksUniform = getUniform(MASKS_UNIFORM_NAME).as2Float();
|
||||
|
@ -88,8 +88,7 @@ public class Mask {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + getStartX() + "; " + getStartY() +
|
||||
") -> (" + getEndX() + "; " + getEndY() + ")";
|
||||
return "(" + getStartX() + "; " + getStartY() + ") -> (" + getEndX() + "; " + getEndY() + ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,9 +24,8 @@ import org.lwjgl.BufferUtils;
|
||||
|
||||
public class MaskStack {
|
||||
|
||||
private final FloatBuffer buffer = BufferUtils.createFloatBuffer(
|
||||
FlatRenderProgram.MASK_STACK_SIZE * TransformedMask.SIZE_IN_FLOATS
|
||||
);
|
||||
private final FloatBuffer buffer = BufferUtils
|
||||
.createFloatBuffer(FlatRenderProgram.MASK_STACK_SIZE * TransformedMask.SIZE_IN_FLOATS);
|
||||
|
||||
public void pushMask(TransformedMask mask) {
|
||||
mask.writeToBuffer(buffer);
|
||||
|
@ -29,8 +29,8 @@ import glm.vec._3.Vec3;
|
||||
import glm.vec._4.Vec4;
|
||||
import ru.windcorp.progressia.client.graphics.Colors;
|
||||
import ru.windcorp.progressia.client.graphics.backend.Usage;
|
||||
import ru.windcorp.progressia.client.graphics.model.Face;
|
||||
import ru.windcorp.progressia.client.graphics.model.Faces;
|
||||
import ru.windcorp.progressia.client.graphics.model.ShapePart;
|
||||
import ru.windcorp.progressia.client.graphics.model.ShapeParts;
|
||||
import ru.windcorp.progressia.client.graphics.model.Shape;
|
||||
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||
@ -84,7 +84,7 @@ public class RenderTarget {
|
||||
|
||||
private final Deque<TransformedMask> maskStack = new LinkedList<>();
|
||||
private final Deque<Mat4> transformStack = new LinkedList<>();
|
||||
private final List<Face> currentClipFaces = new ArrayList<>();
|
||||
private final List<ShapePart> currentClipFaces = new ArrayList<>();
|
||||
|
||||
private int depth = 0;
|
||||
|
||||
@ -94,8 +94,8 @@ public class RenderTarget {
|
||||
|
||||
protected void assembleCurrentClipFromFaces() {
|
||||
if (!currentClipFaces.isEmpty()) {
|
||||
Face[] faces = currentClipFaces.toArray(
|
||||
new Face[currentClipFaces.size()]
|
||||
ShapePart[] faces = currentClipFaces.toArray(
|
||||
new ShapePart[currentClipFaces.size()]
|
||||
);
|
||||
currentClipFaces.clear();
|
||||
|
||||
@ -189,16 +189,13 @@ public class RenderTarget {
|
||||
|
||||
public void addCustomRenderer(Renderable renderable) {
|
||||
assembleCurrentClipFromFaces();
|
||||
assembled.add(
|
||||
new Clip(
|
||||
maskStack,
|
||||
getTransform(),
|
||||
renderable
|
||||
)
|
||||
);
|
||||
|
||||
float depth = this.depth--;
|
||||
Mat4 transform = new Mat4().translate(0, 0, depth).mul(getTransform());
|
||||
assembled.add(new Clip(maskStack, transform, renderable));
|
||||
}
|
||||
|
||||
protected void addFaceToCurrentClip(Face face) {
|
||||
protected void addFaceToCurrentClip(ShapePart face) {
|
||||
currentClipFaces.add(face);
|
||||
}
|
||||
|
||||
@ -270,7 +267,7 @@ public class RenderTarget {
|
||||
fill(Colors.toVector(color));
|
||||
}
|
||||
|
||||
public Face createRectagleFace(
|
||||
public ShapePart createRectagleFace(
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
@ -280,7 +277,7 @@ public class RenderTarget {
|
||||
) {
|
||||
float depth = this.depth--;
|
||||
|
||||
return Faces.createRectangle(
|
||||
return ShapeParts.createRectangle(
|
||||
FlatRenderProgram.getDefault(),
|
||||
texture,
|
||||
color,
|
||||
@ -291,7 +288,7 @@ public class RenderTarget {
|
||||
);
|
||||
}
|
||||
|
||||
public Face createRectagleFace(
|
||||
public ShapePart createRectagleFace(
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
|
@ -42,14 +42,8 @@ public class TransformedMask {
|
||||
private Vec4 endXstartY = null;
|
||||
private Vec4 endXendY = null;
|
||||
|
||||
public TransformedMask(
|
||||
Vec2 origin,
|
||||
Vec2 width,
|
||||
Vec2 height,
|
||||
Vec2 counterOrigin,
|
||||
Vec2 counterWidth,
|
||||
Vec2 counterHeight
|
||||
) {
|
||||
public TransformedMask(Vec2 origin, Vec2 width, Vec2 height, Vec2 counterOrigin, Vec2 counterWidth,
|
||||
Vec2 counterHeight) {
|
||||
set(origin, width, height, counterOrigin, counterWidth, counterHeight);
|
||||
}
|
||||
|
||||
@ -61,14 +55,8 @@ public class TransformedMask {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
public TransformedMask set(
|
||||
Vec2 origin,
|
||||
Vec2 width,
|
||||
Vec2 height,
|
||||
Vec2 counterOrigin,
|
||||
Vec2 counterWidth,
|
||||
Vec2 counterHeight
|
||||
) {
|
||||
public TransformedMask set(Vec2 origin, Vec2 width, Vec2 height, Vec2 counterOrigin, Vec2 counterWidth,
|
||||
Vec2 counterHeight) {
|
||||
this.origin.set(origin.x, origin.y);
|
||||
this.width.set(width.x, width.y);
|
||||
this.height.set(height.x, height.y);
|
||||
@ -112,35 +100,17 @@ public class TransformedMask {
|
||||
}
|
||||
|
||||
private void setFields() {
|
||||
origin.set(
|
||||
startXstartY.x,
|
||||
startXstartY.y
|
||||
);
|
||||
origin.set(startXstartY.x, startXstartY.y);
|
||||
|
||||
width.set(
|
||||
endXstartY.x - startXstartY.x,
|
||||
endXstartY.y - startXstartY.y
|
||||
);
|
||||
width.set(endXstartY.x - startXstartY.x, endXstartY.y - startXstartY.y);
|
||||
|
||||
height.set(
|
||||
startXendY.x - startXstartY.x,
|
||||
startXendY.y - startXstartY.y
|
||||
);
|
||||
height.set(startXendY.x - startXstartY.x, startXendY.y - startXstartY.y);
|
||||
|
||||
counterOrigin.set(
|
||||
endXendY.x,
|
||||
endXendY.y
|
||||
);
|
||||
counterOrigin.set(endXendY.x, endXendY.y);
|
||||
|
||||
counterWidth.set(
|
||||
startXendY.x - endXendY.x,
|
||||
startXendY.y - endXendY.y
|
||||
);
|
||||
counterWidth.set(startXendY.x - endXendY.x, startXendY.y - endXendY.y);
|
||||
|
||||
counterHeight.set(
|
||||
endXstartY.x - endXendY.x,
|
||||
endXstartY.y - endXendY.y
|
||||
);
|
||||
counterHeight.set(endXstartY.x - endXendY.x, endXstartY.y - endXendY.y);
|
||||
}
|
||||
|
||||
public void writeToBuffer(FloatBuffer output) {
|
||||
|
@ -68,17 +68,11 @@ public class Font {
|
||||
return color;
|
||||
}
|
||||
|
||||
public Renderable assemble(
|
||||
CharSequence chars,
|
||||
float maxWidth
|
||||
) {
|
||||
public Renderable assemble(CharSequence chars, float maxWidth) {
|
||||
return typeface.assembleStatic(chars, style, align, maxWidth, color);
|
||||
}
|
||||
|
||||
public Renderable assembleDynamic(
|
||||
Supplier<CharSequence> supplier,
|
||||
float maxWidth
|
||||
) {
|
||||
public Renderable assembleDynamic(Supplier<CharSequence> supplier, float maxWidth) {
|
||||
return typeface.assembleDynamic(supplier, style, align, maxWidth, color);
|
||||
}
|
||||
|
||||
@ -102,7 +96,8 @@ public class Font {
|
||||
* Creates a new {@link Font} with the specified {@code style} exactly. This
|
||||
* object's style is ignored.
|
||||
*
|
||||
* @param style the new style
|
||||
* @param style
|
||||
* the new style
|
||||
* @return the new font
|
||||
*/
|
||||
public Font withStyle(int style) {
|
||||
|
@ -81,8 +81,7 @@ public class GNUUnifontLoader {
|
||||
|
||||
private static BufferedReader createReader(Resource resource) throws IOException {
|
||||
return new BufferedReader(
|
||||
new InputStreamReader(new GZIPInputStream(resource.getInputStream()), StandardCharsets.UTF_8)
|
||||
);
|
||||
new InputStreamReader(new GZIPInputStream(resource.getInputStream()), StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
private static Stream<String> createStream(BufferedReader reader) {
|
||||
@ -97,13 +96,8 @@ public class GNUUnifontLoader {
|
||||
|
||||
char c = getChar(declar);
|
||||
|
||||
TextureDataEditor editor = new TextureDataEditor(
|
||||
width,
|
||||
GNUUnifont.HEIGHT,
|
||||
width,
|
||||
GNUUnifont.HEIGHT,
|
||||
TEXTURE_SETTINGS
|
||||
);
|
||||
TextureDataEditor editor = new TextureDataEditor(width, GNUUnifont.HEIGHT, width, GNUUnifont.HEIGHT,
|
||||
TEXTURE_SETTINGS);
|
||||
|
||||
for (int y = 0; y < GNUUnifont.HEIGHT; ++y) {
|
||||
for (int x = 0; x < width; ++x) {
|
||||
@ -165,8 +159,7 @@ public class GNUUnifontLoader {
|
||||
|
||||
if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'))) {
|
||||
throw new IOException(
|
||||
"Illegal char in declar \"" + declar + "\" at index " + i + "; expected 0-9A-F"
|
||||
);
|
||||
"Illegal char in declar \"" + declar + "\" at index " + i + "; expected 0-9A-F");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -190,8 +183,7 @@ public class GNUUnifontLoader {
|
||||
}
|
||||
|
||||
private static Collector<AtlasGlyph, ?, TCharObjectMap<Texture>> createMapper() {
|
||||
return Collector.of(
|
||||
TCharObjectHashMap<Texture>::new,
|
||||
return Collector.of(TCharObjectHashMap<Texture>::new,
|
||||
|
||||
(map, glyph) -> map.put(glyph.c, glyph.texture),
|
||||
|
||||
@ -200,8 +192,7 @@ public class GNUUnifontLoader {
|
||||
return a;
|
||||
},
|
||||
|
||||
Characteristics.UNORDERED
|
||||
);
|
||||
Characteristics.UNORDERED);
|
||||
}
|
||||
|
||||
private GNUUnifontLoader() {
|
||||
|
@ -33,8 +33,8 @@ import gnu.trove.stack.TIntStack;
|
||||
import gnu.trove.stack.array.TIntArrayStack;
|
||||
import ru.windcorp.progressia.client.graphics.Colors;
|
||||
import ru.windcorp.progressia.client.graphics.backend.Usage;
|
||||
import ru.windcorp.progressia.client.graphics.model.Face;
|
||||
import ru.windcorp.progressia.client.graphics.model.Faces;
|
||||
import ru.windcorp.progressia.client.graphics.model.ShapePart;
|
||||
import ru.windcorp.progressia.client.graphics.model.ShapeParts;
|
||||
import ru.windcorp.progressia.client.graphics.model.Shape;
|
||||
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
|
||||
import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram;
|
||||
@ -144,7 +144,7 @@ public abstract class SpriteTypeface extends Typeface {
|
||||
return new Shape(
|
||||
Usage.STATIC,
|
||||
getProgram(),
|
||||
Faces.createRectangle(
|
||||
ShapeParts.createRectangle(
|
||||
getProgram(),
|
||||
getTexture(c),
|
||||
Colors.WHITE,
|
||||
@ -167,7 +167,7 @@ public abstract class SpriteTypeface extends Typeface {
|
||||
private final Renderable unitLine = new Shape(
|
||||
Usage.STATIC,
|
||||
getProgram(),
|
||||
Faces.createRectangle(
|
||||
ShapeParts.createRectangle(
|
||||
getProgram(),
|
||||
null,
|
||||
Vectors.UNIT_4,
|
||||
@ -257,7 +257,7 @@ public abstract class SpriteTypeface extends Typeface {
|
||||
|
||||
private class SDWorkspace extends SpriteTypeface.Workspace {
|
||||
|
||||
private final Collection<Face> faces = new ArrayList<>();
|
||||
private final Collection<ShapePart> faces = new ArrayList<>();
|
||||
|
||||
private final Vec3 origin = new Vec3();
|
||||
private final Vec3 width = new Vec3();
|
||||
@ -298,7 +298,7 @@ public abstract class SpriteTypeface extends Typeface {
|
||||
workspace.height.sub(workspace.origin);
|
||||
|
||||
workspace.faces.add(
|
||||
Faces.createRectangle(
|
||||
ShapeParts.createRectangle(
|
||||
getProgram(),
|
||||
texture,
|
||||
color,
|
||||
@ -314,7 +314,7 @@ public abstract class SpriteTypeface extends Typeface {
|
||||
return new Shape(
|
||||
Usage.STATIC,
|
||||
getProgram(),
|
||||
workspace.faces.toArray(new Face[workspace.faces.size()])
|
||||
workspace.faces.toArray(new ShapePart[workspace.faces.size()])
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -29,12 +29,8 @@ import ru.windcorp.progressia.common.util.Vectors;
|
||||
public abstract class Typeface extends Named {
|
||||
|
||||
public static class Style {
|
||||
public static final int BOLD = 1 << 0,
|
||||
ITALIC = 1 << 1,
|
||||
UNDERLINED = 1 << 2,
|
||||
STRIKETHRU = 1 << 3,
|
||||
SHADOW = 1 << 4,
|
||||
OUTLINED = 1 << 5;
|
||||
public static final int BOLD = 1 << 0, ITALIC = 1 << 1, UNDERLINED = 1 << 2, STRIKETHRU = 1 << 3,
|
||||
SHADOW = 1 << 4, OUTLINED = 1 << 5;
|
||||
|
||||
public static final int PLAIN = 0;
|
||||
|
||||
@ -71,40 +67,19 @@ public abstract class Typeface extends Named {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public abstract Renderable assembleStatic(
|
||||
CharSequence chars,
|
||||
int style,
|
||||
float align,
|
||||
float maxWidth,
|
||||
Vec4 color
|
||||
);
|
||||
public abstract Renderable assembleStatic(CharSequence chars, int style, float align, float maxWidth, Vec4 color);
|
||||
|
||||
public abstract Renderable assembleDynamic(
|
||||
Supplier<CharSequence> supplier,
|
||||
int style,
|
||||
float align,
|
||||
float maxWidth,
|
||||
Vec4 color
|
||||
);
|
||||
public abstract Renderable assembleDynamic(Supplier<CharSequence> supplier, int style, float align, float maxWidth,
|
||||
Vec4 color);
|
||||
|
||||
public int getWidth(
|
||||
CharSequence chars,
|
||||
int style,
|
||||
float align,
|
||||
float maxWidth
|
||||
) {
|
||||
public int getWidth(CharSequence chars, int style, float align, float maxWidth) {
|
||||
Vec2i v = Vectors.grab2i();
|
||||
v = getSize(chars, style, align, maxWidth, v);
|
||||
Vectors.release(v);
|
||||
return v.x;
|
||||
}
|
||||
|
||||
public int getHeight(
|
||||
CharSequence chars,
|
||||
int style,
|
||||
float align,
|
||||
float maxWidth
|
||||
) {
|
||||
public int getHeight(CharSequence chars, int style, float align, float maxWidth) {
|
||||
Vec2i v = Vectors.grab2i();
|
||||
v = getSize(chars, style, align, maxWidth, v);
|
||||
Vectors.release(v);
|
||||
@ -113,13 +88,7 @@ public abstract class Typeface extends Named {
|
||||
|
||||
public abstract int getLineHeight();
|
||||
|
||||
public abstract Vec2i getSize(
|
||||
CharSequence chars,
|
||||
int style,
|
||||
float align,
|
||||
float maxWidth,
|
||||
Vec2i result
|
||||
);
|
||||
public abstract Vec2i getSize(CharSequence chars, int style, float align, float maxWidth, Vec2i result);
|
||||
|
||||
public abstract boolean supports(char c);
|
||||
|
||||
|
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package ru.windcorp.progressia.client.graphics.gui;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import ru.windcorp.progressia.client.graphics.font.Font;
|
||||
import ru.windcorp.progressia.client.graphics.gui.event.ButtonEvent;
|
||||
import ru.windcorp.progressia.client.graphics.gui.event.EnableEvent;
|
||||
import ru.windcorp.progressia.client.graphics.gui.event.FocusEvent;
|
||||
import ru.windcorp.progressia.client.graphics.gui.event.HoverEvent;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
|
||||
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
||||
|
||||
public abstract class BasicButton extends Component {
|
||||
|
||||
private final Label label;
|
||||
|
||||
private boolean isPressed = false;
|
||||
private final Collection<Consumer<BasicButton>> actions = Collections.synchronizedCollection(new ArrayList<>());
|
||||
|
||||
public BasicButton(String name, String label, Font labelFont) {
|
||||
super(name);
|
||||
this.label = new Label(name + ".Label", labelFont, label);
|
||||
|
||||
setLayout(new LayoutAlign(10));
|
||||
addChild(this.label);
|
||||
|
||||
setFocusable(true);
|
||||
reassembleAt(ARTrigger.HOVER, ARTrigger.FOCUS, ARTrigger.ENABLE);
|
||||
|
||||
// Click triggers
|
||||
addListener(KeyEvent.class, e -> {
|
||||
if (e.isRepeat()) {
|
||||
return false;
|
||||
} else if (
|
||||
e.isLeftMouseButton() ||
|
||||
e.getKey() == GLFW.GLFW_KEY_SPACE ||
|
||||
e.getKey() == GLFW.GLFW_KEY_ENTER
|
||||
) {
|
||||
setPressed(e.isPress());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
addListener(new Object() {
|
||||
|
||||
// Release when losing focus
|
||||
@Subscribe
|
||||
public void onFocusChange(FocusEvent e) {
|
||||
if (!e.getNewState()) {
|
||||
setPressed(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Release when hover ends
|
||||
@Subscribe
|
||||
public void onHoverEnded(HoverEvent e) {
|
||||
if (!e.isNowHovered()) {
|
||||
setPressed(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Release when disabled
|
||||
@Subscribe
|
||||
public void onDisabled(EnableEvent e) {
|
||||
if (!e.getComponent().isEnabled()) {
|
||||
setPressed(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger virtualClick when button is released
|
||||
@Subscribe
|
||||
public void onRelease(ButtonEvent.Release e) {
|
||||
virtualClick();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public BasicButton(String name, String label) {
|
||||
this(name, label, new Font());
|
||||
}
|
||||
|
||||
public boolean isPressed() {
|
||||
return isPressed;
|
||||
}
|
||||
|
||||
public void click() {
|
||||
setPressed(true);
|
||||
setPressed(false);
|
||||
}
|
||||
|
||||
public void setPressed(boolean isPressed) {
|
||||
if (this.isPressed != isPressed) {
|
||||
this.isPressed = isPressed;
|
||||
|
||||
if (isPressed) {
|
||||
takeFocus();
|
||||
}
|
||||
|
||||
dispatchEvent(ButtonEvent.create(this, this.isPressed));
|
||||
}
|
||||
}
|
||||
|
||||
public BasicButton addAction(Consumer<BasicButton> action) {
|
||||
this.actions.add(Objects.requireNonNull(action, "action"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean removeAction(Consumer<BasicButton> action) {
|
||||
return this.actions.remove(action);
|
||||
}
|
||||
|
||||
public void virtualClick() {
|
||||
this.actions.forEach(action -> {
|
||||
action.accept(this);
|
||||
});
|
||||
}
|
||||
|
||||
public Label getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package ru.windcorp.progressia.client.graphics.gui;
|
||||
|
||||
import glm.vec._4.Vec4;
|
||||
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||
import ru.windcorp.progressia.client.graphics.font.Font;
|
||||
import ru.windcorp.progressia.client.graphics.Colors;
|
||||
|
||||
public class Button extends BasicButton {
|
||||
|
||||
public Button(String name, String label, Font labelFont) {
|
||||
super(name, label, labelFont);
|
||||
}
|
||||
|
||||
public Button(String name, String label) {
|
||||
this(name, label, new Font());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assembleSelf(RenderTarget target) {
|
||||
// Border
|
||||
|
||||
Vec4 borderColor;
|
||||
if (isPressed() || isHovered() || isFocused()) {
|
||||
borderColor = Colors.BLUE;
|
||||
} else {
|
||||
borderColor = Colors.LIGHT_GRAY;
|
||||
}
|
||||
target.fill(getX(), getY(), getWidth(), getHeight(), borderColor);
|
||||
|
||||
// Inside area
|
||||
|
||||
if (isPressed()) {
|
||||
// Do nothing
|
||||
} else {
|
||||
Vec4 backgroundColor;
|
||||
if (isHovered() && isEnabled()) {
|
||||
backgroundColor = Colors.HOVER_BLUE;
|
||||
} else {
|
||||
backgroundColor = Colors.WHITE;
|
||||
}
|
||||
target.fill(getX() + 2, getY() + 2, getWidth() - 4, getHeight() - 4, backgroundColor);
|
||||
}
|
||||
|
||||
// Change label font color
|
||||
|
||||
if (isPressed()) {
|
||||
getLabel().setFont(getLabel().getFont().withColor(Colors.WHITE));
|
||||
} else {
|
||||
getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postAssembleSelf(RenderTarget target) {
|
||||
// Apply disable tint
|
||||
|
||||
if (!isEnabled()) {
|
||||
target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package ru.windcorp.progressia.client.graphics.gui;
|
||||
|
||||
import glm.vec._2.i.Vec2i;
|
||||
import glm.vec._4.Vec4;
|
||||
import ru.windcorp.progressia.client.graphics.Colors;
|
||||
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||
import ru.windcorp.progressia.client.graphics.font.Font;
|
||||
import ru.windcorp.progressia.client.graphics.font.Typefaces;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutHorizontal;
|
||||
|
||||
public class Checkbox extends BasicButton {
|
||||
|
||||
private class Tick extends Component {
|
||||
|
||||
public Tick() {
|
||||
super(Checkbox.this.getName() + ".Tick");
|
||||
|
||||
setPreferredSize(new Vec2i(Typefaces.getDefault().getLineHeight() * 3 / 2));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assembleSelf(RenderTarget target) {
|
||||
|
||||
int size = getPreferredSize().x;
|
||||
int x = getX();
|
||||
int y = getY() + (getHeight() - size) / 2;
|
||||
|
||||
// Border
|
||||
|
||||
Vec4 borderColor;
|
||||
if (Checkbox.this.isPressed() || Checkbox.this.isHovered() || Checkbox.this.isFocused()) {
|
||||
borderColor = Colors.BLUE;
|
||||
} else {
|
||||
borderColor = Colors.LIGHT_GRAY;
|
||||
}
|
||||
target.fill(x, y, size, size, borderColor);
|
||||
|
||||
// Inside area
|
||||
|
||||
if (Checkbox.this.isPressed()) {
|
||||
// Do nothing
|
||||
} else {
|
||||
Vec4 backgroundColor;
|
||||
if (Checkbox.this.isHovered() && Checkbox.this.isEnabled()) {
|
||||
backgroundColor = Colors.HOVER_BLUE;
|
||||
} else {
|
||||
backgroundColor = Colors.WHITE;
|
||||
}
|
||||
target.fill(x + 2, y + 2, size - 4, size - 4, backgroundColor);
|
||||
}
|
||||
|
||||
// "Tick"
|
||||
|
||||
if (Checkbox.this.isChecked()) {
|
||||
target.fill(x + 4, y + 4, size - 8, size - 8, Colors.BLUE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean checked;
|
||||
|
||||
public Checkbox(String name, String label, Font labelFont, boolean check) {
|
||||
super(name, label, labelFont);
|
||||
this.checked = check;
|
||||
|
||||
assert getChildren().size() == 1 : "Checkbox expects that BasicButton contains exactly one child";
|
||||
Component basicChild = getChild(0);
|
||||
|
||||
Group group = new Group(getName() + ".LabelAndTick", new LayoutHorizontal(0, 10));
|
||||
removeChild(basicChild);
|
||||
setLayout(new LayoutAlign(0, 0.5f, 10));
|
||||
group.setLayoutHint(basicChild.getLayoutHint());
|
||||
group.addChild(new Tick());
|
||||
group.addChild(basicChild);
|
||||
addChild(group);
|
||||
|
||||
addAction(b -> switchState());
|
||||
}
|
||||
|
||||
public Checkbox(String name, String label, Font labelFont) {
|
||||
this(name, label, labelFont, false);
|
||||
}
|
||||
|
||||
public Checkbox(String name, String label, boolean check) {
|
||||
this(name, label, new Font(), check);
|
||||
}
|
||||
|
||||
public Checkbox(String name, String label) {
|
||||
this(name, label, false);
|
||||
}
|
||||
|
||||
public void switchState() {
|
||||
setChecked(!isChecked());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the checked
|
||||
*/
|
||||
public boolean isChecked() {
|
||||
return checked;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param checked the checked to set
|
||||
*/
|
||||
public void setChecked(boolean checked) {
|
||||
this.checked = checked;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assembleSelf(RenderTarget target) {
|
||||
// Change label font color
|
||||
|
||||
if (isPressed()) {
|
||||
getLabel().setFont(getLabel().getFont().withColor(Colors.BLUE));
|
||||
} else {
|
||||
getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postAssembleSelf(RenderTarget target) {
|
||||
// Apply disable tint
|
||||
|
||||
if (!isEnabled()) {
|
||||
target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -19,18 +19,23 @@
|
||||
package ru.windcorp.progressia.client.graphics.gui;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import glm.vec._2.i.Vec2i;
|
||||
import ru.windcorp.progressia.client.graphics.backend.InputTracker;
|
||||
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||
import ru.windcorp.progressia.client.graphics.gui.event.ChildAddedEvent;
|
||||
import ru.windcorp.progressia.client.graphics.gui.event.ChildRemovedEvent;
|
||||
import ru.windcorp.progressia.client.graphics.gui.event.EnableEvent;
|
||||
import ru.windcorp.progressia.client.graphics.gui.event.FocusEvent;
|
||||
import ru.windcorp.progressia.client.graphics.gui.event.HoverEvent;
|
||||
import ru.windcorp.progressia.client.graphics.gui.event.ParentChangedEvent;
|
||||
@ -62,6 +67,8 @@ public class Component extends Named {
|
||||
private Object layoutHint = null;
|
||||
private Layout layout = null;
|
||||
|
||||
private boolean isEnabled = true;
|
||||
|
||||
private boolean isFocusable = false;
|
||||
private boolean isFocused = false;
|
||||
|
||||
@ -285,10 +292,31 @@ public class Component extends Named {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this component is focusable. A component needs to be
|
||||
* focusable to become focused. A component that is focusable may not
|
||||
* necessarily be ready to gain focus (see {@link #canGainFocusNow()}).
|
||||
*
|
||||
* @return {@code true} iff the component is focusable
|
||||
* @see #canGainFocusNow()
|
||||
*/
|
||||
public boolean isFocusable() {
|
||||
return isFocusable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this component can become focused at this moment.
|
||||
* <p>
|
||||
* The implementation of this method in {@link Component} considers the
|
||||
* component a focus candidate if it is both focusable and enabled.
|
||||
*
|
||||
* @return {@code true} iff the component can receive focus
|
||||
* @see #isFocusable()
|
||||
*/
|
||||
public boolean canGainFocusNow() {
|
||||
return isFocusable() && isEnabled();
|
||||
}
|
||||
|
||||
public Component setFocusable(boolean focusable) {
|
||||
this.isFocusable = focusable;
|
||||
return this;
|
||||
@ -337,7 +365,7 @@ public class Component extends Named {
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.isFocusable()) {
|
||||
if (component.canGainFocusNow()) {
|
||||
setFocused(false);
|
||||
component.setFocused(true);
|
||||
return;
|
||||
@ -379,7 +407,7 @@ public class Component extends Named {
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.isFocusable()) {
|
||||
if (component.canGainFocusNow()) {
|
||||
setFocused(false);
|
||||
component.setFocused(true);
|
||||
return;
|
||||
@ -433,12 +461,51 @@ public class Component extends Named {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables this component. An {@link EnableEvent} is dispatched
|
||||
* if the state changes.
|
||||
*
|
||||
* @param enabled {@code true} to enable the component, {@code false} to
|
||||
* disable the component
|
||||
* @see #setEnabledRecursively(boolean)
|
||||
*/
|
||||
public void setEnabled(boolean enabled) {
|
||||
if (this.isEnabled != enabled) {
|
||||
if (isFocused() && isEnabled()) {
|
||||
focusNext();
|
||||
}
|
||||
|
||||
if (isEnabled()) {
|
||||
setHovered(false);
|
||||
}
|
||||
|
||||
this.isEnabled = enabled;
|
||||
dispatchEvent(new EnableEvent(this));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables this component and all of its children recursively.
|
||||
*
|
||||
* @param enabled {@code true} to enable the components, {@code false} to
|
||||
* disable the components
|
||||
* @see #setEnabled(boolean)
|
||||
*/
|
||||
public void setEnabledRecursively(boolean enabled) {
|
||||
setEnabled(enabled);
|
||||
getChildren().forEach(c -> c.setEnabledRecursively(enabled));
|
||||
}
|
||||
|
||||
public boolean isHovered() {
|
||||
return isHovered;
|
||||
}
|
||||
|
||||
protected void setHovered(boolean isHovered) {
|
||||
if (this.isHovered != isHovered) {
|
||||
if (this.isHovered != isHovered && isEnabled()) {
|
||||
this.isHovered = isHovered;
|
||||
|
||||
if (!isHovered && !getChildren().isEmpty()) {
|
||||
@ -475,11 +542,8 @@ public class Component extends Named {
|
||||
eventBus.post(event);
|
||||
}
|
||||
|
||||
public <T extends InputEvent> void addListener(
|
||||
Class<? extends T> type,
|
||||
boolean handlesConsumed,
|
||||
InputListener<T> listener
|
||||
) {
|
||||
public <T extends InputEvent> void addListener(Class<? extends T> type, boolean handlesConsumed,
|
||||
InputListener<T> listener) {
|
||||
if (inputBus == null) {
|
||||
inputBus = new InputBus();
|
||||
}
|
||||
@ -502,7 +566,7 @@ public class Component extends Named {
|
||||
}
|
||||
|
||||
protected void handleInput(Input input) {
|
||||
if (inputBus != null) {
|
||||
if (inputBus != null && isEnabled()) {
|
||||
inputBus.dispatch(input);
|
||||
}
|
||||
}
|
||||
@ -598,6 +662,17 @@ public class Component extends Named {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules the reassembly to occur.
|
||||
* <p>
|
||||
* This method is invoked in root components whenever a
|
||||
* {@linkplain #requestReassembly() reassembly request} is made by one of
|
||||
* its children. When creating the dedicated root component, override this
|
||||
* method to perform any implementation-specific actions that will cause a
|
||||
* reassembly as soon as possible.
|
||||
* <p>
|
||||
* The default implementation of this method does nothing.
|
||||
*/
|
||||
protected void handleReassemblyRequest() {
|
||||
// To be overridden
|
||||
}
|
||||
@ -638,6 +713,135 @@ public class Component extends Named {
|
||||
getChildren().forEach(child -> child.assemble(target));
|
||||
}
|
||||
|
||||
/*
|
||||
* Automatic Reassembly
|
||||
*/
|
||||
|
||||
/**
|
||||
* The various kinds of changes that may be used with
|
||||
* {@link Component#reassembleAt(ARTrigger...)}.
|
||||
*/
|
||||
protected static enum ARTrigger {
|
||||
/**
|
||||
* Reassemble the component whenever its hover status changes, e.g.
|
||||
* whenever the pointer enters or leaves its bounds.
|
||||
*/
|
||||
HOVER,
|
||||
|
||||
/**
|
||||
* Reassemble the component whenever it gains or loses focus.
|
||||
* <p>
|
||||
* <em>Component must be focusable to be able to gain focus.</em> The
|
||||
* component will not be reassembled unless
|
||||
* {@link Component#setFocusable(boolean) setFocusable(true)} has been
|
||||
* invoked.
|
||||
*/
|
||||
FOCUS,
|
||||
|
||||
/**
|
||||
* Reassemble the component whenever it is enabled or disabled.
|
||||
*/
|
||||
ENABLE
|
||||
}
|
||||
|
||||
/**
|
||||
* All trigger objects (event listeners) that are currently registered with
|
||||
* {@link #eventBus}. The field is {@code null} until the first trigger is
|
||||
* installed.
|
||||
*/
|
||||
private Map<ARTrigger, Object> autoReassemblyTriggerObjects = null;
|
||||
|
||||
private Object createTriggerObject(ARTrigger type) {
|
||||
switch (type) {
|
||||
case HOVER:
|
||||
return new Object() {
|
||||
@Subscribe
|
||||
public void onHoverChanged(HoverEvent e) {
|
||||
requestReassembly();
|
||||
}
|
||||
};
|
||||
case FOCUS:
|
||||
return new Object() {
|
||||
@Subscribe
|
||||
public void onFocusChanged(FocusEvent e) {
|
||||
requestReassembly();
|
||||
}
|
||||
};
|
||||
case ENABLE:
|
||||
return new Object() {
|
||||
@Subscribe
|
||||
public void onEnabled(EnableEvent e) {
|
||||
requestReassembly();
|
||||
}
|
||||
};
|
||||
default:
|
||||
throw new NullPointerException("type");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that {@link #requestReassembly()} is invoked on this component
|
||||
* whenever any of the specified changes occur. Duplicate attempts to
|
||||
* register the same trigger are silently ignored.
|
||||
* <p>
|
||||
* {@code triggers} may be empty, which results in a no-op. It must not be
|
||||
* {@code null}.
|
||||
*
|
||||
* @param triggers the {@linkplain ARTrigger triggers} to
|
||||
* request reassembly with.
|
||||
* @see #disableAutoReassemblyAt(ARTrigger...)
|
||||
*/
|
||||
protected synchronized void reassembleAt(ARTrigger... triggers) {
|
||||
|
||||
Objects.requireNonNull(triggers, "triggers");
|
||||
if (triggers.length == 0)
|
||||
return;
|
||||
|
||||
if (autoReassemblyTriggerObjects == null) {
|
||||
autoReassemblyTriggerObjects = new EnumMap<>(ARTrigger.class);
|
||||
}
|
||||
|
||||
for (ARTrigger trigger : triggers) {
|
||||
if (!autoReassemblyTriggerObjects.containsKey(trigger)) {
|
||||
Object triggerObject = createTriggerObject(trigger);
|
||||
addListener(trigger);
|
||||
autoReassemblyTriggerObjects.put(trigger, triggerObject);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that {@link #requestReassembly()} is no longer invoked on this
|
||||
* component whenever any of the specified changes occur. After a trigger is
|
||||
* removed, it may be reinstalled with
|
||||
* {@link #reassembleAt(ARTrigger...)}. Attempts to remove a
|
||||
* nonexistant trigger are silently ignored.
|
||||
* <p>
|
||||
* {@code triggers} may be empty, which results in a no-op. It must not be
|
||||
* {@code null}.
|
||||
*
|
||||
* @param triggers the {@linkplain ARTrigger triggers} to remove
|
||||
* @see #reassemblyAt(ARTrigger...)
|
||||
*/
|
||||
protected synchronized void disableAutoReassemblyAt(ARTrigger... triggers) {
|
||||
|
||||
Objects.requireNonNull(triggers, "triggers");
|
||||
if (triggers.length == 0)
|
||||
return;
|
||||
|
||||
if (autoReassemblyTriggerObjects == null)
|
||||
return;
|
||||
|
||||
for (ARTrigger trigger : triggers) {
|
||||
Object triggerObject = autoReassemblyTriggerObjects.remove(trigger);
|
||||
if (triggerObject != null) {
|
||||
removeListener(trigger);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Returns a component that displays this component in its center.
|
||||
// * @return a {@link Aligner} initialized to center this component
|
||||
|
@ -16,18 +16,13 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package ru.windcorp.progressia.common.world.tile;
|
||||
package ru.windcorp.progressia.client.graphics.gui;
|
||||
|
||||
public interface TileReference {
|
||||
public class Group extends Component {
|
||||
|
||||
TileData get();
|
||||
|
||||
int getIndex();
|
||||
|
||||
TileDataStack getStack();
|
||||
|
||||
default boolean isValid() {
|
||||
return get() != null;
|
||||
public Group(String name, Layout layout) {
|
||||
super(name);
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
}
|
@ -83,6 +83,11 @@ public class Label extends Component {
|
||||
return font;
|
||||
}
|
||||
|
||||
public void setFont(Font font) {
|
||||
this.font = font;
|
||||
requestReassembly();
|
||||
}
|
||||
|
||||
public String getCurrentText() {
|
||||
return currentText;
|
||||
}
|
||||
@ -96,11 +101,7 @@ public class Label extends Component {
|
||||
float startX = getX() + font.getAlign() * (getWidth() - currentSize.x);
|
||||
|
||||
target.pushTransform(
|
||||
new Mat4().identity().translate(startX, getY(), -1000) // TODO wtf
|
||||
// is this
|
||||
// magic
|
||||
// <---
|
||||
.scale(2)
|
||||
new Mat4().identity().translate(startX, getY(), 0).scale(2)
|
||||
);
|
||||
|
||||
target.addCustomRenderer(font.assemble(currentText, maxWidth));
|
||||
|
@ -15,14 +15,66 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package ru.windcorp.progressia.client.graphics.gui;
|
||||
|
||||
public class Panel extends Component {
|
||||
import java.util.Objects;
|
||||
|
||||
import glm.vec._4.Vec4;
|
||||
import ru.windcorp.progressia.client.graphics.Colors;
|
||||
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||
|
||||
public class Panel extends Group {
|
||||
|
||||
private Vec4 fill;
|
||||
private Vec4 border;
|
||||
|
||||
public Panel(String name, Layout layout, Vec4 fill, Vec4 border) {
|
||||
super(name, layout);
|
||||
|
||||
this.fill = Objects.requireNonNull(fill, "fill");
|
||||
this.border = border;
|
||||
}
|
||||
|
||||
public Panel(String name, Layout layout) {
|
||||
super(name);
|
||||
setLayout(layout);
|
||||
this(name, layout, Colors.WHITE, Colors.LIGHT_GRAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the fill
|
||||
*/
|
||||
public Vec4 getFill() {
|
||||
return fill;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fill the fill to set
|
||||
*/
|
||||
public void setFill(Vec4 fill) {
|
||||
this.fill = Objects.requireNonNull(fill, "fill");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the border
|
||||
*/
|
||||
public Vec4 getBorder() {
|
||||
return border;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param border the border to set
|
||||
*/
|
||||
public void setBorder(Vec4 border) {
|
||||
this.border = border;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assembleSelf(RenderTarget target) {
|
||||
if (border == null) {
|
||||
target.fill(getX(), getY(), getWidth(), getHeight(), fill);
|
||||
} else {
|
||||
target.fill(getX(), getY(), getWidth(), getHeight(), border);
|
||||
target.fill(getX() + 2, getY() + 2, getWidth() - 4, getHeight() - 4, fill);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package ru.windcorp.progressia.client.graphics.gui;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import glm.vec._2.i.Vec2i;
|
||||
import glm.vec._4.Vec4;
|
||||
import ru.windcorp.progressia.client.graphics.Colors;
|
||||
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||
import ru.windcorp.progressia.client.graphics.font.Font;
|
||||
import ru.windcorp.progressia.client.graphics.font.Typefaces;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutHorizontal;
|
||||
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
||||
|
||||
public class RadioButton extends BasicButton {
|
||||
|
||||
private class Tick extends Component {
|
||||
|
||||
public Tick() {
|
||||
super(RadioButton.this.getName() + ".Tick");
|
||||
|
||||
setPreferredSize(new Vec2i(Typefaces.getDefault().getLineHeight() * 3 / 2));
|
||||
}
|
||||
|
||||
private void cross(RenderTarget target, int x, int y, int size, Vec4 color) {
|
||||
target.fill(x + 4, y, size - 8, size, color);
|
||||
target.fill(x + 2, y + 2, size - 4, size - 4, color);
|
||||
target.fill(x, y + 4, size, size - 8, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assembleSelf(RenderTarget target) {
|
||||
|
||||
int size = getPreferredSize().x;
|
||||
int x = getX();
|
||||
int y = getY() + (getHeight() - size) / 2;
|
||||
|
||||
// Border
|
||||
|
||||
Vec4 borderColor;
|
||||
if (RadioButton.this.isPressed() || RadioButton.this.isHovered() || RadioButton.this.isFocused()) {
|
||||
borderColor = Colors.BLUE;
|
||||
} else {
|
||||
borderColor = Colors.LIGHT_GRAY;
|
||||
}
|
||||
cross(target, x, y, size, borderColor);
|
||||
|
||||
// Inside area
|
||||
|
||||
if (RadioButton.this.isPressed()) {
|
||||
// Do nothing
|
||||
} else {
|
||||
Vec4 backgroundColor;
|
||||
if (RadioButton.this.isHovered() && RadioButton.this.isEnabled()) {
|
||||
backgroundColor = Colors.HOVER_BLUE;
|
||||
} else {
|
||||
backgroundColor = Colors.WHITE;
|
||||
}
|
||||
cross(target, x + 2, y + 2, size - 4, backgroundColor);
|
||||
}
|
||||
|
||||
// "Tick"
|
||||
|
||||
if (RadioButton.this.isChecked()) {
|
||||
cross(target, x + 4, y + 4, size - 8, Colors.BLUE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean checked;
|
||||
|
||||
private RadioButtonGroup group = null;
|
||||
|
||||
public RadioButton(String name, String label, Font labelFont, boolean check) {
|
||||
super(name, label, labelFont);
|
||||
this.checked = check;
|
||||
|
||||
assert getChildren().size() == 1 : "RadioButton expects that BasicButton contains exactly one child";
|
||||
Component basicChild = getChild(0);
|
||||
|
||||
Group group = new Group(getName() + ".LabelAndTick", new LayoutHorizontal(0, 10));
|
||||
removeChild(basicChild);
|
||||
setLayout(new LayoutAlign(0, 0.5f, 10));
|
||||
group.setLayoutHint(basicChild.getLayoutHint());
|
||||
group.addChild(new Tick());
|
||||
group.addChild(basicChild);
|
||||
addChild(group);
|
||||
|
||||
addListener(KeyEvent.class, e -> {
|
||||
if (e.isRelease()) return false;
|
||||
|
||||
if (e.getKey() == GLFW.GLFW_KEY_LEFT || e.getKey() == GLFW.GLFW_KEY_UP) {
|
||||
if (this.group != null) {
|
||||
this.group.selectPrevious();
|
||||
this.group.getSelected().takeFocus();
|
||||
}
|
||||
|
||||
return true;
|
||||
} else if (e.getKey() == GLFW.GLFW_KEY_RIGHT || e.getKey() == GLFW.GLFW_KEY_DOWN) {
|
||||
if (this.group != null) {
|
||||
this.group.selectNext();
|
||||
this.group.getSelected().takeFocus();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
addAction(b -> setChecked(true));
|
||||
}
|
||||
|
||||
public RadioButton(String name, String label, Font labelFont) {
|
||||
this(name, label, labelFont, false);
|
||||
}
|
||||
|
||||
public RadioButton(String name, String label, boolean check) {
|
||||
this(name, label, new Font(), check);
|
||||
}
|
||||
|
||||
public RadioButton(String name, String label) {
|
||||
this(name, label, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param group the group to set
|
||||
*/
|
||||
public RadioButton setGroup(RadioButtonGroup group) {
|
||||
|
||||
if (this.group != null) {
|
||||
group.selectNext();
|
||||
removeAction(group.listener);
|
||||
group.buttons.remove(this);
|
||||
group.getSelected(); // Clear reference if this was the only button in the group
|
||||
}
|
||||
|
||||
this.group = group;
|
||||
|
||||
if (this.group != null) {
|
||||
group.buttons.add(this);
|
||||
addAction(group.listener);
|
||||
}
|
||||
|
||||
setChecked(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the checked
|
||||
*/
|
||||
public boolean isChecked() {
|
||||
return checked;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param checked the checked to set
|
||||
*/
|
||||
public void setChecked(boolean checked) {
|
||||
this.checked = checked;
|
||||
|
||||
if (group != null) {
|
||||
group.listener.accept(this); // Failsafe for manual invocations of setChecked()
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assembleSelf(RenderTarget target) {
|
||||
// Change label font color
|
||||
|
||||
if (isPressed()) {
|
||||
getLabel().setFont(getLabel().getFont().withColor(Colors.BLUE));
|
||||
} else {
|
||||
getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postAssembleSelf(RenderTarget target) {
|
||||
// Apply disable tint
|
||||
|
||||
if (!isEnabled()) {
|
||||
target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package ru.windcorp.progressia.client.graphics.gui;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class RadioButtonGroup {
|
||||
|
||||
private final Collection<Consumer<RadioButtonGroup>> actions = Collections.synchronizedCollection(new ArrayList<>());
|
||||
final List<RadioButton> buttons = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
private RadioButton selected = null;
|
||||
|
||||
Consumer<BasicButton> listener = b -> {
|
||||
if (b instanceof RadioButton && ((RadioButton) b).isChecked() && buttons.contains(b)) {
|
||||
select((RadioButton) b);
|
||||
}
|
||||
};
|
||||
|
||||
public RadioButtonGroup addAction(Consumer<RadioButtonGroup> action) {
|
||||
this.actions.add(Objects.requireNonNull(action, "action"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean removeAction(Consumer<BasicButton> action) {
|
||||
return this.actions.remove(action);
|
||||
}
|
||||
|
||||
public List<RadioButton> getButtons() {
|
||||
return Collections.unmodifiableList(buttons);
|
||||
}
|
||||
|
||||
public synchronized RadioButton getSelected() {
|
||||
if (!buttons.contains(selected)) {
|
||||
selected = null;
|
||||
}
|
||||
return selected;
|
||||
}
|
||||
|
||||
public synchronized void select(RadioButton button) {
|
||||
if (button != null && !buttons.contains(button)) {
|
||||
throw new IllegalArgumentException("Button " + button + " is not in the group");
|
||||
}
|
||||
|
||||
getSelected(); // Clear if invalid
|
||||
|
||||
if (selected == button) {
|
||||
return; // Terminate listener-setter recursion
|
||||
}
|
||||
|
||||
if (selected != null) {
|
||||
selected.setChecked(false);
|
||||
}
|
||||
|
||||
selected = button;
|
||||
|
||||
if (selected != null) {
|
||||
selected.setChecked(true);
|
||||
}
|
||||
|
||||
actions.forEach(action -> action.accept(this));
|
||||
}
|
||||
|
||||
public void selectNext() {
|
||||
selectNeighbour(+1);
|
||||
}
|
||||
|
||||
public void selectPrevious() {
|
||||
selectNeighbour(-1);
|
||||
}
|
||||
|
||||
private synchronized void selectNeighbour(int direction) {
|
||||
if (getSelected() == null) {
|
||||
if (buttons.isEmpty()) {
|
||||
throw new IllegalStateException("Cannot select neighbour button: group empty");
|
||||
}
|
||||
|
||||
select(buttons.get(0));
|
||||
} else {
|
||||
RadioButton button;
|
||||
int index = buttons.indexOf(selected);
|
||||
|
||||
do {
|
||||
index += direction;
|
||||
|
||||
if (index >= buttons.size()) {
|
||||
index = 0;
|
||||
} else if (index < 0) {
|
||||
index = buttons.size() - 1;
|
||||
}
|
||||
|
||||
button = buttons.get(index);
|
||||
} while (button != getSelected() && !button.isEnabled());
|
||||
|
||||
select(button);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package ru.windcorp.progressia.client.graphics.gui.event;
|
||||
|
||||
import ru.windcorp.progressia.client.graphics.gui.BasicButton;
|
||||
|
||||
public class ButtonEvent extends ComponentEvent {
|
||||
|
||||
public static class Press extends ButtonEvent {
|
||||
public Press(BasicButton button) {
|
||||
super(button, true);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Release extends ButtonEvent {
|
||||
public Release(BasicButton button) {
|
||||
super(button, false);
|
||||
}
|
||||
}
|
||||
|
||||
private final boolean isPress;
|
||||
|
||||
protected ButtonEvent(BasicButton button, boolean isPress) {
|
||||
super(button);
|
||||
this.isPress = isPress;
|
||||
}
|
||||
|
||||
public static ButtonEvent create(BasicButton button, boolean isPress) {
|
||||
if (isPress) {
|
||||
return new Press(button);
|
||||
} else {
|
||||
return new Release(button);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPress() {
|
||||
return isPress;
|
||||
}
|
||||
|
||||
public boolean isRelease() {
|
||||
return !isPress;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package ru.windcorp.progressia.client.graphics.gui.event;
|
||||
|
||||
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||
|
||||
public class EnableEvent extends ComponentEvent {
|
||||
|
||||
public EnableEvent(Component component) {
|
||||
super(component);
|
||||
}
|
||||
|
||||
}
|
@ -56,13 +56,8 @@ public class LayoutAlign implements Layout {
|
||||
size.x = min(size.x, cWidth);
|
||||
size.y = min(size.y, cHeight);
|
||||
|
||||
child.setBounds(
|
||||
c.getX() +
|
||||
(int) ((cWidth - size.x) * alignX) + margin,
|
||||
c.getY() +
|
||||
(int) ((cHeight - size.y) * alignY) + margin,
|
||||
size
|
||||
);
|
||||
child.setBounds(c.getX() + (int) ((cWidth - size.x) * alignX) + margin,
|
||||
c.getY() + (int) ((cHeight - size.y) * alignY) + margin, size);
|
||||
|
||||
});
|
||||
}
|
||||
@ -71,9 +66,7 @@ public class LayoutAlign implements Layout {
|
||||
public Vec2i calculatePreferredSize(Component c) {
|
||||
Vec2i result = new Vec2i(0, 0);
|
||||
|
||||
c.getChildren().stream()
|
||||
.map(child -> child.getPreferredSize())
|
||||
.forEach(size -> {
|
||||
c.getChildren().stream().map(child -> child.getPreferredSize()).forEach(size -> {
|
||||
result.x = max(size.x, result.x);
|
||||
result.y = max(size.y, result.y);
|
||||
});
|
||||
|
@ -26,9 +26,7 @@ import ru.windcorp.progressia.client.graphics.gui.Layout;
|
||||
|
||||
public class LayoutBorderHorizontal implements Layout {
|
||||
|
||||
public static final String CENTER = "Center",
|
||||
LEFT = "Left",
|
||||
RIGHT = "Right";
|
||||
public static final String CENTER = "Center", LEFT = "Left", RIGHT = "Right";
|
||||
|
||||
private final int margin;
|
||||
|
||||
@ -51,32 +49,17 @@ public class LayoutBorderHorizontal implements Layout {
|
||||
if (child.getLayoutHint() == LEFT) {
|
||||
childSize = child.getPreferredSize();
|
||||
left = childSize.x + margin;
|
||||
child.setBounds(
|
||||
c.getX(),
|
||||
c.getY(),
|
||||
childSize.x,
|
||||
c.getHeight()
|
||||
);
|
||||
child.setBounds(c.getX(), c.getY(), childSize.x, c.getHeight());
|
||||
} else if (child.getLayoutHint() == RIGHT) {
|
||||
childSize = child.getPreferredSize();
|
||||
right = childSize.x + margin;
|
||||
child.setBounds(
|
||||
c.getX() + c.getWidth() - childSize.x,
|
||||
c.getY(),
|
||||
childSize.x,
|
||||
c.getHeight()
|
||||
);
|
||||
child.setBounds(c.getX() + c.getWidth() - childSize.x, c.getY(), childSize.x, c.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
for (Component child : c.getChildren()) {
|
||||
if (child.getLayoutHint() == CENTER) {
|
||||
child.setBounds(
|
||||
c.getX() + left,
|
||||
c.getY(),
|
||||
c.getWidth() - left - right,
|
||||
c.getHeight()
|
||||
);
|
||||
child.setBounds(c.getX() + left, c.getY(), c.getWidth() - left - right, c.getHeight());
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -26,9 +26,7 @@ import ru.windcorp.progressia.client.graphics.gui.Layout;
|
||||
|
||||
public class LayoutBorderVertical implements Layout {
|
||||
|
||||
public static final String CENTER = "Center",
|
||||
UP = "Up",
|
||||
DOWN = "Down";
|
||||
public static final String CENTER = "Center", UP = "Up", DOWN = "Down";
|
||||
|
||||
private final int margin;
|
||||
|
||||
@ -51,32 +49,17 @@ public class LayoutBorderVertical implements Layout {
|
||||
if (child.getLayoutHint() == UP) {
|
||||
childSize = child.getPreferredSize();
|
||||
top = childSize.y + margin;
|
||||
child.setBounds(
|
||||
c.getX(),
|
||||
c.getY(),
|
||||
c.getWidth(),
|
||||
childSize.y
|
||||
);
|
||||
child.setBounds(c.getX(), c.getY(), c.getWidth(), childSize.y);
|
||||
} else if (child.getLayoutHint() == DOWN) {
|
||||
childSize = child.getPreferredSize();
|
||||
bottom = childSize.y + margin;
|
||||
child.setBounds(
|
||||
c.getX(),
|
||||
c.getY() + c.getHeight() - childSize.y,
|
||||
c.getWidth(),
|
||||
childSize.y
|
||||
);
|
||||
child.setBounds(c.getX(), c.getY() + c.getHeight() - childSize.y, c.getWidth(), childSize.y);
|
||||
}
|
||||
}
|
||||
|
||||
for (Component child : c.getChildren()) {
|
||||
if (child.getLayoutHint() == CENTER) {
|
||||
child.setBounds(
|
||||
c.getX(),
|
||||
c.getY() + top,
|
||||
c.getWidth(),
|
||||
c.getHeight() - top - bottom
|
||||
);
|
||||
child.setBounds(c.getX(), c.getY() + top, c.getWidth(), c.getHeight() - top - bottom);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package ru.windcorp.progressia.client.graphics.gui.layout;
|
||||
|
||||
import static java.lang.Math.max;
|
||||
|
||||
import glm.vec._2.i.Vec2i;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Layout;
|
||||
|
||||
public class LayoutFill implements Layout {
|
||||
|
||||
private final int margin;
|
||||
|
||||
public LayoutFill(int margin) {
|
||||
this.margin = margin;
|
||||
}
|
||||
|
||||
public LayoutFill() {
|
||||
this(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void layout(Component c) {
|
||||
c.getChildren().forEach(child -> {
|
||||
|
||||
int cWidth = c.getWidth() - 2 * margin;
|
||||
int cHeight = c.getHeight() - 2 * margin;
|
||||
|
||||
child.setBounds(
|
||||
c.getX() + margin,
|
||||
c.getY() + margin,
|
||||
cWidth,
|
||||
cHeight
|
||||
);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec2i calculatePreferredSize(Component c) {
|
||||
Vec2i result = new Vec2i(0, 0);
|
||||
|
||||
c.getChildren().stream()
|
||||
.map(child -> child.getPreferredSize())
|
||||
.forEach(size -> {
|
||||
result.x = max(size.x, result.x);
|
||||
result.y = max(size.y, result.y);
|
||||
});
|
||||
|
||||
result.x += 2 * margin;
|
||||
result.y += 2 * margin;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + "(" + margin + ")";
|
||||
}
|
||||
|
||||
}
|
@ -98,15 +98,26 @@ public class LayoutGrid implements Layout {
|
||||
if (!isSummed)
|
||||
throw new IllegalStateException("Not summed yet");
|
||||
|
||||
int width, height;
|
||||
|
||||
if (column == columns.length - 1) {
|
||||
width = parent.getWidth() - margin - columns[column];
|
||||
} else {
|
||||
width = columns[column + 1] - columns[column] - gap;
|
||||
}
|
||||
|
||||
if (row == rows.length - 1) {
|
||||
height = parent.getHeight() - margin - rows[row];
|
||||
} else {
|
||||
height = rows[row + 1] - rows[row] - gap;
|
||||
}
|
||||
|
||||
child.setBounds(
|
||||
parent.getX() + columns[column],
|
||||
parent.getY() + rows[row],
|
||||
parent.getY() + parent.getHeight() - (rows[row] + height),
|
||||
|
||||
(column != (columns.length - 1) ? (columns[column + 1] - columns[column] - gap)
|
||||
: (parent.getWidth() - margin - columns[column])),
|
||||
|
||||
(row != (rows.length - 1) ? (rows[row + 1] - rows[row] - gap)
|
||||
: (parent.getHeight() - margin - rows[row]))
|
||||
width,
|
||||
height
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -132,10 +143,9 @@ public class LayoutGrid implements Layout {
|
||||
GridDimensions grid = calculateGrid(c);
|
||||
grid.sum();
|
||||
|
||||
int[] coords;
|
||||
for (Component child : c.getChildren()) {
|
||||
coords = (int[]) child.getLayoutHint();
|
||||
grid.setBounds(coords[0], coords[1], child, c);
|
||||
Vec2i coords = (Vec2i) child.getLayoutHint();
|
||||
grid.setBounds(coords.x, coords.y, child, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -149,11 +159,10 @@ public class LayoutGrid implements Layout {
|
||||
|
||||
private GridDimensions calculateGrid(Component parent) {
|
||||
GridDimensions result = new GridDimensions();
|
||||
int[] coords;
|
||||
|
||||
for (Component child : parent.getChildren()) {
|
||||
coords = (int[]) child.getLayoutHint();
|
||||
result.add(coords[0], coords[1], child.getPreferredSize());
|
||||
Vec2i coords = (Vec2i) child.getLayoutHint();
|
||||
result.add(coords.x, coords.y, child.getPreferredSize());
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -43,8 +43,7 @@ public class LayoutHorizontal implements Layout {
|
||||
|
||||
@Override
|
||||
public void layout(Component c) {
|
||||
int x = c.getX() + margin,
|
||||
y = c.getY() + margin;
|
||||
int x = c.getX() + margin, y = c.getY() + margin;
|
||||
|
||||
int width;
|
||||
|
||||
|
@ -43,8 +43,7 @@ public class LayoutVertical implements Layout {
|
||||
|
||||
@Override
|
||||
public void layout(Component c) {
|
||||
int x = c.getX() + margin,
|
||||
y = c.getY() + c.getHeight();
|
||||
int x = c.getX() + margin, y = c.getY() + c.getHeight();
|
||||
|
||||
synchronized (c.getChildren()) {
|
||||
for (Component child : c.getChildren()) {
|
||||
|
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package ru.windcorp.progressia.client.graphics.gui.menu;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import glm.vec._2.i.Vec2i;
|
||||
import ru.windcorp.progressia.client.graphics.Colors;
|
||||
import ru.windcorp.progressia.client.graphics.GUI;
|
||||
import ru.windcorp.progressia.client.graphics.font.Font;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||
import ru.windcorp.progressia.client.graphics.gui.GUILayer;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Label;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Layout;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Panel;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutFill;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical;
|
||||
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
||||
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
||||
import ru.windcorp.progressia.client.graphics.input.bus.Input;
|
||||
import ru.windcorp.progressia.client.localization.MutableString;
|
||||
import ru.windcorp.progressia.client.localization.MutableStringLocalized;
|
||||
|
||||
public class MenuLayer extends GUILayer {
|
||||
|
||||
private final Component content;
|
||||
private final Component background;
|
||||
|
||||
private final Runnable closeAction = () -> {
|
||||
GUI.removeLayer(this);
|
||||
};
|
||||
|
||||
public MenuLayer(String name, Component content) {
|
||||
super(name, new LayoutFill(0));
|
||||
|
||||
setCursorPolicy(CursorPolicy.REQUIRE);
|
||||
|
||||
this.background = new Panel(name + ".Background", new LayoutAlign(10), Colors.toVector(0x66000000), null);
|
||||
this.content = content;
|
||||
|
||||
background.addChild(content);
|
||||
getRoot().addChild(background);
|
||||
}
|
||||
|
||||
public MenuLayer(String name, Layout contentLayout) {
|
||||
this(name, new Panel(name + ".Content", contentLayout));
|
||||
}
|
||||
|
||||
public MenuLayer(String name) {
|
||||
this(name, new LayoutVertical(20, 10));
|
||||
}
|
||||
|
||||
public Component getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public Component getBackground() {
|
||||
return background;
|
||||
}
|
||||
|
||||
protected void addTitle() {
|
||||
String translationKey = "Layer" + getName() + ".Title";
|
||||
MutableString titleText = new MutableStringLocalized(translationKey);
|
||||
Font titleFont = new Font().deriveBold().withColor(Colors.BLACK).withAlign(0.5f);
|
||||
|
||||
Label label = new Label(getName() + ".Title", titleFont, titleText);
|
||||
getContent().addChild(label);
|
||||
|
||||
Panel panel = new Panel(getName() + ".Title.Underscore", null, Colors.BLUE, null);
|
||||
panel.setLayout(new LayoutFill() {
|
||||
@Override
|
||||
public Vec2i calculatePreferredSize(Component c) {
|
||||
return new Vec2i(label.getPreferredSize().x + 40, 4);
|
||||
}
|
||||
});
|
||||
getContent().addChild(panel);
|
||||
}
|
||||
|
||||
protected Runnable getCloseAction() {
|
||||
return closeAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleInput(Input input) {
|
||||
|
||||
if (!input.isConsumed()) {
|
||||
InputEvent event = input.getEvent();
|
||||
|
||||
if (event instanceof KeyEvent) {
|
||||
KeyEvent keyEvent = (KeyEvent) event;
|
||||
if (keyEvent.isPress() && keyEvent.getKey() == GLFW.GLFW_KEY_ESCAPE) {
|
||||
getCloseAction().run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super.handleInput(input);
|
||||
input.consume();
|
||||
}
|
||||
|
||||
}
|
@ -87,22 +87,14 @@ public class CursorMoveEvent extends CursorEvent {
|
||||
|
||||
@Override
|
||||
public CursorMoveEvent snapshot() {
|
||||
return new StaticMouseMoveEvent(
|
||||
getPreviousPosition(),
|
||||
getNewPosition(),
|
||||
getTime()
|
||||
);
|
||||
return new StaticMouseMoveEvent(getPreviousPosition(), getNewPosition(), getTime());
|
||||
}
|
||||
|
||||
private class StaticMouseMoveEvent extends CursorMoveEvent {
|
||||
|
||||
private final Vec2d previousPosition = new Vec2d();
|
||||
|
||||
public StaticMouseMoveEvent(
|
||||
Vec2d previousPosition,
|
||||
Vec2d newPosition,
|
||||
double time
|
||||
) {
|
||||
public StaticMouseMoveEvent(Vec2d previousPosition, Vec2d newPosition, double time) {
|
||||
super(newPosition, time);
|
||||
this.previousPosition.set(previousPosition.x, previousPosition.y);
|
||||
}
|
||||
|
@ -67,11 +67,7 @@ public class FrameResizeEvent extends InputEvent {
|
||||
|
||||
private final Vec2i previousSize;
|
||||
|
||||
public StaticFrameResizeEvent(
|
||||
Vec2i newSize,
|
||||
Vec2i previousSize,
|
||||
double time
|
||||
) {
|
||||
public StaticFrameResizeEvent(Vec2i newSize, Vec2i previousSize, double time) {
|
||||
super(newSize, time);
|
||||
this.previousSize = previousSize;
|
||||
}
|
||||
|
@ -27,13 +27,7 @@ public class KeyEvent extends InputEvent {
|
||||
protected int action;
|
||||
protected int mods;
|
||||
|
||||
protected KeyEvent(
|
||||
int key,
|
||||
int scancode,
|
||||
int action,
|
||||
int mods,
|
||||
double time
|
||||
) {
|
||||
protected KeyEvent(int key, int scancode, int action, int mods, double time) {
|
||||
super(time);
|
||||
this.key = key;
|
||||
this.scancode = scancode;
|
||||
|
@ -46,17 +46,12 @@ public class Keys {
|
||||
private static final String MOUSE_BUTTON_PREFIX = "GLFW_MOUSE_BUTTON_";
|
||||
|
||||
private static final Set<String> IGNORE_FIELDS = new HashSet<>(
|
||||
Arrays.asList(
|
||||
"GLFW_KEY_UNKNOWN",
|
||||
"GLFW_KEY_LAST",
|
||||
"GLFW_MOUSE_BUTTON_LAST",
|
||||
"GLFW_MOUSE_BUTTON_1", // Alias
|
||||
Arrays.asList("GLFW_KEY_UNKNOWN", "GLFW_KEY_LAST", "GLFW_MOUSE_BUTTON_LAST", "GLFW_MOUSE_BUTTON_1", // Alias
|
||||
// for
|
||||
// LEFT
|
||||
"GLFW_MOUSE_BUTTON_2", // Alias for RIGHT
|
||||
"GLFW_MOUSE_BUTTON_3" // Alias for MIDDLE
|
||||
)
|
||||
);
|
||||
));
|
||||
|
||||
static {
|
||||
initializeDictionary();
|
||||
@ -100,14 +95,8 @@ public class Keys {
|
||||
}
|
||||
|
||||
if (CODES_TO_NAMES.containsKey(value)) {
|
||||
throw CrashReports.report(
|
||||
null,
|
||||
"Duplicate keys: %s and %s both map to %d(0x%s)",
|
||||
CODES_TO_NAMES.get(value),
|
||||
name,
|
||||
value,
|
||||
Integer.toHexString(value)
|
||||
);
|
||||
throw CrashReports.report(null, "Duplicate keys: %s and %s both map to %d(0x%s)", CODES_TO_NAMES.get(value),
|
||||
name, value, Integer.toHexString(value));
|
||||
}
|
||||
|
||||
CODES_TO_NAMES.put(value, name);
|
||||
|
@ -31,28 +31,21 @@ public class InputBus {
|
||||
private final boolean handleConsumed;
|
||||
private final InputListener<?> listener;
|
||||
|
||||
public WrappedListener(
|
||||
Class<?> type,
|
||||
boolean handleConsumed,
|
||||
InputListener<?> listener
|
||||
) {
|
||||
public WrappedListener(Class<?> type, boolean handleConsumed, InputListener<?> listener) {
|
||||
this.type = type;
|
||||
this.handleConsumed = handleConsumed;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
private boolean handles(Input input) {
|
||||
return (!input.isConsumed() || handleConsumed) &&
|
||||
type.isInstance(input.getEvent());
|
||||
return (!input.isConsumed() || handleConsumed) && type.isInstance(input.getEvent());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void handle(Input input) {
|
||||
if (handles(input)) {
|
||||
boolean consumed = ((InputListener<InputEvent>) listener)
|
||||
.handle(
|
||||
(InputEvent) type.cast(input.getEvent())
|
||||
);
|
||||
.handle((InputEvent) type.cast(input.getEvent()));
|
||||
|
||||
input.setConsumed(consumed);
|
||||
}
|
||||
@ -66,18 +59,12 @@ public class InputBus {
|
||||
listeners.forEach(l -> l.handle(input));
|
||||
}
|
||||
|
||||
public <T extends InputEvent> void register(
|
||||
Class<? extends T> type,
|
||||
boolean handlesConsumed,
|
||||
InputListener<T> listener
|
||||
) {
|
||||
public <T extends InputEvent> void register(Class<? extends T> type, boolean handlesConsumed,
|
||||
InputListener<T> listener) {
|
||||
listeners.add(new WrappedListener(type, handlesConsumed, listener));
|
||||
}
|
||||
|
||||
public <T extends InputEvent> void register(
|
||||
Class<? extends T> type,
|
||||
InputListener<T> listener
|
||||
) {
|
||||
public <T extends InputEvent> void register(Class<? extends T> type, InputListener<T> listener) {
|
||||
register(type, false, listener);
|
||||
}
|
||||
|
||||
|
@ -18,23 +18,23 @@
|
||||
|
||||
package ru.windcorp.progressia.client.graphics.model;
|
||||
|
||||
import static ru.windcorp.progressia.common.world.block.BlockFace.*;
|
||||
import static ru.windcorp.progressia.common.world.rels.AbsFace.*;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import glm.vec._3.Vec3;
|
||||
import ru.windcorp.progressia.common.world.block.BlockFace;
|
||||
import ru.windcorp.progressia.common.world.rels.AbsFace;
|
||||
|
||||
class BlockFaceVectors {
|
||||
|
||||
private static BlockFaceVectors createInner(BlockFaceVectors outer) {
|
||||
ImmutableMap.Builder<BlockFace, Vec3> originBuilder = ImmutableMap.builder();
|
||||
ImmutableMap.Builder<AbsFace, Vec3> originBuilder = ImmutableMap.builder();
|
||||
|
||||
ImmutableMap.Builder<BlockFace, Vec3> widthBuilder = ImmutableMap.builder();
|
||||
ImmutableMap.Builder<AbsFace, Vec3> widthBuilder = ImmutableMap.builder();
|
||||
|
||||
ImmutableMap.Builder<BlockFace, Vec3> heightBuilder = ImmutableMap.builder();
|
||||
ImmutableMap.Builder<AbsFace, Vec3> heightBuilder = ImmutableMap.builder();
|
||||
|
||||
for (BlockFace face : getFaces()) {
|
||||
for (AbsFace face : getFaces()) {
|
||||
Vec3 width = outer.getWidth(face);
|
||||
Vec3 height = outer.getHeight(face);
|
||||
|
||||
@ -59,36 +59,36 @@ class BlockFaceVectors {
|
||||
|
||||
static {
|
||||
OUTER = new BlockFaceVectors(
|
||||
ImmutableMap.<BlockFace, Vec3>builder()
|
||||
ImmutableMap.<AbsFace, Vec3>builder()
|
||||
|
||||
.put(TOP, new Vec3(-0.5f, +0.5f, +0.5f))
|
||||
.put(BOTTOM, new Vec3(-0.5f, -0.5f, -0.5f))
|
||||
.put(NORTH, new Vec3(+0.5f, -0.5f, -0.5f))
|
||||
.put(SOUTH, new Vec3(-0.5f, +0.5f, -0.5f))
|
||||
.put(WEST, new Vec3(+0.5f, +0.5f, -0.5f))
|
||||
.put(EAST, new Vec3(-0.5f, -0.5f, -0.5f))
|
||||
.put(POS_Z, new Vec3(-0.5f, +0.5f, +0.5f))
|
||||
.put(NEG_Z, new Vec3(-0.5f, -0.5f, -0.5f))
|
||||
.put(POS_X, new Vec3(+0.5f, -0.5f, -0.5f))
|
||||
.put(NEG_X, new Vec3(-0.5f, +0.5f, -0.5f))
|
||||
.put(POS_Y, new Vec3(+0.5f, +0.5f, -0.5f))
|
||||
.put(NEG_Y, new Vec3(-0.5f, -0.5f, -0.5f))
|
||||
|
||||
.build(),
|
||||
|
||||
ImmutableMap.<BlockFace, Vec3>builder()
|
||||
ImmutableMap.<AbsFace, Vec3>builder()
|
||||
|
||||
.put(TOP, new Vec3(0, -1, 0))
|
||||
.put(BOTTOM, new Vec3(0, +1, 0))
|
||||
.put(NORTH, new Vec3(0, +1, 0))
|
||||
.put(SOUTH, new Vec3(0, -1, 0))
|
||||
.put(WEST, new Vec3(-1, 0, 0))
|
||||
.put(EAST, new Vec3(+1, 0, 0))
|
||||
.put(POS_Z, new Vec3(0, -1, 0))
|
||||
.put(NEG_Z, new Vec3(0, +1, 0))
|
||||
.put(POS_X, new Vec3(0, +1, 0))
|
||||
.put(NEG_X, new Vec3(0, -1, 0))
|
||||
.put(POS_Y, new Vec3(-1, 0, 0))
|
||||
.put(NEG_Y, new Vec3(+1, 0, 0))
|
||||
|
||||
.build(),
|
||||
|
||||
ImmutableMap.<BlockFace, Vec3>builder()
|
||||
ImmutableMap.<AbsFace, Vec3>builder()
|
||||
|
||||
.put(TOP, new Vec3(+1, 0, 0))
|
||||
.put(BOTTOM, new Vec3(+1, 0, 0))
|
||||
.put(NORTH, new Vec3(0, 0, +1))
|
||||
.put(SOUTH, new Vec3(0, 0, +1))
|
||||
.put(WEST, new Vec3(0, 0, +1))
|
||||
.put(EAST, new Vec3(0, 0, +1))
|
||||
.put(POS_Z, new Vec3(+1, 0, 0))
|
||||
.put(NEG_Z, new Vec3(+1, 0, 0))
|
||||
.put(POS_X, new Vec3(0, 0, +1))
|
||||
.put(NEG_X, new Vec3(0, 0, +1))
|
||||
.put(POS_Y, new Vec3(0, 0, +1))
|
||||
.put(NEG_Y, new Vec3(0, 0, +1))
|
||||
|
||||
.build()
|
||||
);
|
||||
@ -100,29 +100,29 @@ class BlockFaceVectors {
|
||||
return inner ? INNER : OUTER;
|
||||
}
|
||||
|
||||
private final ImmutableMap<BlockFace, Vec3> origins;
|
||||
private final ImmutableMap<BlockFace, Vec3> widths;
|
||||
private final ImmutableMap<BlockFace, Vec3> heights;
|
||||
private final ImmutableMap<AbsFace, Vec3> origins;
|
||||
private final ImmutableMap<AbsFace, Vec3> widths;
|
||||
private final ImmutableMap<AbsFace, Vec3> heights;
|
||||
|
||||
public BlockFaceVectors(
|
||||
ImmutableMap<BlockFace, Vec3> origins,
|
||||
ImmutableMap<BlockFace, Vec3> widths,
|
||||
ImmutableMap<BlockFace, Vec3> heights
|
||||
ImmutableMap<AbsFace, Vec3> origins,
|
||||
ImmutableMap<AbsFace, Vec3> widths,
|
||||
ImmutableMap<AbsFace, Vec3> heights
|
||||
) {
|
||||
this.origins = origins;
|
||||
this.widths = widths;
|
||||
this.heights = heights;
|
||||
}
|
||||
|
||||
public Vec3 getOrigin(BlockFace face) {
|
||||
public Vec3 getOrigin(AbsFace face) {
|
||||
return origins.get(face);
|
||||
}
|
||||
|
||||
public Vec3 getWidth(BlockFace face) {
|
||||
public Vec3 getWidth(AbsFace face) {
|
||||
return widths.get(face);
|
||||
}
|
||||
|
||||
public Vec3 getHeight(BlockFace face) {
|
||||
public Vec3 getHeight(AbsFace face) {
|
||||
return heights.get(face);
|
||||
}
|
||||
}
|
||||
|
@ -33,22 +33,14 @@ public abstract class DynamicModel extends Model {
|
||||
private final Mat4[] transforms;
|
||||
private final boolean[] dynamics;
|
||||
|
||||
public DynamicModel(
|
||||
Renderable[] parts,
|
||||
Mat4[] transforms,
|
||||
boolean[] dynamic
|
||||
) {
|
||||
public DynamicModel(Renderable[] parts, Mat4[] transforms, boolean[] dynamic) {
|
||||
super(parts);
|
||||
this.transforms = transforms;
|
||||
this.dynamics = dynamic;
|
||||
}
|
||||
|
||||
public DynamicModel(Builder builder) {
|
||||
this(
|
||||
builder.getParts(),
|
||||
builder.getTransforms(),
|
||||
builder.getDynamics()
|
||||
);
|
||||
this(builder.getParts(), builder.getTransforms(), builder.getDynamics());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -78,11 +70,7 @@ public abstract class DynamicModel extends Model {
|
||||
protected Builder() {
|
||||
}
|
||||
|
||||
private Builder addPart(
|
||||
Renderable part,
|
||||
Mat4 transform,
|
||||
boolean isDynamic
|
||||
) {
|
||||
private Builder addPart(Renderable part, Mat4 transform, boolean isDynamic) {
|
||||
parts.add(Objects.requireNonNull(part, "part"));
|
||||
transforms.add(Objects.requireNonNull(transform, "transform"));
|
||||
dynamics.add(isDynamic);
|
||||
@ -90,22 +78,15 @@ public abstract class DynamicModel extends Model {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addStaticPart(
|
||||
Renderable part,
|
||||
Mat4 transform
|
||||
) {
|
||||
public Builder addStaticPart(Renderable part, Mat4 transform) {
|
||||
return addPart(part, new Mat4(transform), false);
|
||||
}
|
||||
|
||||
public Builder addDynamicPart(
|
||||
Renderable part
|
||||
) {
|
||||
public Builder addDynamicPart(Renderable part) {
|
||||
return addPart(part, new Mat4(), true);
|
||||
}
|
||||
|
||||
public Builder addStaticPart(
|
||||
Renderable part
|
||||
) {
|
||||
public Builder addStaticPart(Renderable part) {
|
||||
return addStaticPart(part, IDENTITY);
|
||||
}
|
||||
|
||||
|
@ -37,23 +37,13 @@ public class LambdaModel extends DynamicModel {
|
||||
|
||||
private final TransformGetter[] getters;
|
||||
|
||||
public LambdaModel(
|
||||
Renderable[] parts,
|
||||
Mat4[] transforms,
|
||||
boolean[] dynamic,
|
||||
TransformGetter[] getters
|
||||
) {
|
||||
public LambdaModel(Renderable[] parts, Mat4[] transforms, boolean[] dynamic, TransformGetter[] getters) {
|
||||
super(parts, transforms, dynamic);
|
||||
this.getters = getters;
|
||||
}
|
||||
|
||||
public LambdaModel(Builder builder) {
|
||||
this(
|
||||
builder.getParts(),
|
||||
builder.getTransforms(),
|
||||
builder.getDynamics(),
|
||||
builder.getGetters()
|
||||
);
|
||||
this(builder.getParts(), builder.getTransforms(), builder.getDynamics(), builder.getGetters());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -75,11 +65,7 @@ public class LambdaModel extends DynamicModel {
|
||||
protected Builder() {
|
||||
}
|
||||
|
||||
private Builder addPart(
|
||||
Renderable part,
|
||||
Mat4 transform,
|
||||
TransformGetter getter
|
||||
) {
|
||||
private Builder addPart(Renderable part, Mat4 transform, TransformGetter getter) {
|
||||
parts.add(Objects.requireNonNull(part, "part"));
|
||||
transforms.add(Objects.requireNonNull(transform, "transform"));
|
||||
dynamics.add(getter != null);
|
||||
@ -88,23 +74,15 @@ public class LambdaModel extends DynamicModel {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addStaticPart(
|
||||
Renderable part,
|
||||
Mat4 transform
|
||||
) {
|
||||
public Builder addStaticPart(Renderable part, Mat4 transform) {
|
||||
return addPart(part, new Mat4(transform), null);
|
||||
}
|
||||
|
||||
public Builder addDynamicPart(
|
||||
Renderable part,
|
||||
TransformGetter getter
|
||||
) {
|
||||
public Builder addDynamicPart(Renderable part, TransformGetter getter) {
|
||||
return addPart(part, new Mat4(), getter);
|
||||
}
|
||||
|
||||
public Builder addStaticPart(
|
||||
Renderable part
|
||||
) {
|
||||
public Builder addStaticPart(Renderable part) {
|
||||
return addStaticPart(part, IDENTITY);
|
||||
}
|
||||
|
||||
@ -127,12 +105,8 @@ public class LambdaModel extends DynamicModel {
|
||||
}
|
||||
|
||||
public static LambdaModel animate(Renderable model, TransformGetter transform) {
|
||||
return new LambdaModel(
|
||||
new Renderable[] { model },
|
||||
new Mat4[] { new Mat4() },
|
||||
new boolean[] { true },
|
||||
new TransformGetter[] { transform }
|
||||
);
|
||||
return new LambdaModel(new Renderable[] { model }, new Mat4[] { new Mat4() }, new boolean[] { true },
|
||||
new TransformGetter[] { transform });
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,10 +30,10 @@ import ru.windcorp.progressia.client.graphics.backend.VertexBufferObject;
|
||||
public class Shape implements Renderable {
|
||||
|
||||
private final ShapeRenderProgram program;
|
||||
private final Face[] faces;
|
||||
private final ShapePart[] parts;
|
||||
private final Usage usage;
|
||||
|
||||
private FaceGroup[] groups;
|
||||
private ShapePartGroup[] groups;
|
||||
|
||||
private ByteBuffer vertices;
|
||||
private ShortBuffer indices;
|
||||
@ -45,33 +45,33 @@ public class Shape implements Renderable {
|
||||
private VertexBufferObject verticesVbo;
|
||||
private VertexBufferObject indicesVbo;
|
||||
|
||||
public Shape(Usage usage, ShapeRenderProgram program, Face... faces) {
|
||||
public Shape(Usage usage, ShapeRenderProgram program, ShapePart... parts) {
|
||||
this.program = program;
|
||||
this.faces = faces;
|
||||
this.parts = parts;
|
||||
this.usage = usage;
|
||||
|
||||
configureFaces();
|
||||
configureParts();
|
||||
program.preprocess(this);
|
||||
|
||||
assembleBuffers();
|
||||
}
|
||||
|
||||
private void configureFaces() {
|
||||
for (Face face : faces) {
|
||||
face.setShape(this);
|
||||
private void configureParts() {
|
||||
for (ShapePart part : parts) {
|
||||
part.setShape(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void assembleBuffers() {
|
||||
// TODO optimize: only update faces that requested it
|
||||
|
||||
sortFaces();
|
||||
sortParts();
|
||||
resizeBuffers();
|
||||
|
||||
for (Face face : faces) {
|
||||
assembleVertices(face);
|
||||
assembleIndices(face);
|
||||
face.resetUpdateFlags();
|
||||
for (ShapePart part : parts) {
|
||||
assembleVertices(part);
|
||||
assembleIndices(part);
|
||||
part.resetUpdateFlags();
|
||||
}
|
||||
|
||||
this.vertices.flip();
|
||||
@ -85,110 +85,110 @@ public class Shape implements Renderable {
|
||||
|
||||
private void resizeBuffers() {
|
||||
int verticesRequired = 0, indicesRequired = 0;
|
||||
for (Face face : faces) {
|
||||
verticesRequired += face.getVertices().remaining();
|
||||
indicesRequired += face.getIndices().remaining();
|
||||
for (ShapePart part : parts) {
|
||||
verticesRequired += part.getVertices().remaining();
|
||||
indicesRequired += part.getIndices().remaining();
|
||||
}
|
||||
|
||||
if (this.vertices == null || vertices.capacity() < verticesRequired) {
|
||||
if (vertices == null || vertices.capacity() < verticesRequired) {
|
||||
this.vertices = BufferUtils.createByteBuffer(verticesRequired);
|
||||
} else {
|
||||
this.vertices.position(0).limit(verticesRequired);
|
||||
vertices.position(0).limit(verticesRequired);
|
||||
}
|
||||
|
||||
if (this.indices == null || this.indices.capacity() < indicesRequired) {
|
||||
if (indices == null || indices.capacity() < indicesRequired) {
|
||||
this.indices = BufferUtils.createShortBuffer(indicesRequired);
|
||||
} else {
|
||||
this.indices.position(0).limit(indicesRequired);
|
||||
indices.position(0).limit(indicesRequired);
|
||||
}
|
||||
}
|
||||
|
||||
private void assembleVertices(Face face) {
|
||||
face.locationOfVertices = this.vertices.position();
|
||||
private void assembleVertices(ShapePart part) {
|
||||
part.locationOfVertices = this.vertices.position();
|
||||
|
||||
insertVertices(face);
|
||||
linkVerticesWith(face);
|
||||
insertVertices(part);
|
||||
linkVerticesWith(part);
|
||||
}
|
||||
|
||||
private void insertVertices(Face face) {
|
||||
ByteBuffer faceVertices = face.getVertices();
|
||||
private void insertVertices(ShapePart part) {
|
||||
ByteBuffer partVertices = part.getVertices();
|
||||
|
||||
faceVertices.mark();
|
||||
this.vertices.put(faceVertices);
|
||||
faceVertices.reset();
|
||||
partVertices.mark();
|
||||
this.vertices.put(partVertices);
|
||||
partVertices.reset();
|
||||
}
|
||||
|
||||
private void linkVerticesWith(Face face) {
|
||||
private void linkVerticesWith(ShapePart part) {
|
||||
int limit = vertices.limit();
|
||||
int position = vertices.position();
|
||||
|
||||
vertices.limit(position).position(face.getLocationOfVertices());
|
||||
face.vertices = vertices.slice();
|
||||
vertices.limit(position).position(part.getLocationOfVertices());
|
||||
part.vertices = vertices.slice();
|
||||
|
||||
vertices.position(position).limit(limit);
|
||||
}
|
||||
|
||||
private void assembleIndices(Face face) {
|
||||
short vertexOffset = (short) (face.getLocationOfVertices() / program.getBytesPerVertex());
|
||||
private void assembleIndices(ShapePart part) {
|
||||
short vertexOffset = (short) (part.getLocationOfVertices() / program.getBytesPerVertex());
|
||||
|
||||
face.locationOfIndices = indices.position();
|
||||
part.locationOfIndices = indices.position();
|
||||
|
||||
ShortBuffer faceIndices = face.getIndices();
|
||||
ShortBuffer partIndices = part.getIndices();
|
||||
|
||||
if (faceIndices == null) {
|
||||
for (int i = 0; i < face.getVertexCount(); ++i) {
|
||||
if (partIndices == null) {
|
||||
for (int i = 0; i < part.getVertexCount(); ++i) {
|
||||
this.indices.put((short) (vertexOffset + i));
|
||||
}
|
||||
} else {
|
||||
for (int i = faceIndices.position(); i < faceIndices.limit(); ++i) {
|
||||
short faceIndex = faceIndices.get(i);
|
||||
faceIndex += vertexOffset;
|
||||
this.indices.put(faceIndex);
|
||||
for (int i = partIndices.position(); i < partIndices.limit(); ++i) {
|
||||
short partIndex = partIndices.get(i);
|
||||
partIndex += vertexOffset;
|
||||
this.indices.put(partIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sortFaces() {
|
||||
Arrays.sort(faces);
|
||||
private void sortParts() {
|
||||
Arrays.sort(parts);
|
||||
}
|
||||
|
||||
private void assembleGroups() {
|
||||
int unique = countUniqueFaces();
|
||||
this.groups = new FaceGroup[unique];
|
||||
int unique = countUniqueParts();
|
||||
this.groups = new ShapePartGroup[unique];
|
||||
|
||||
if (faces.length == 0)
|
||||
if (parts.length == 0)
|
||||
return;
|
||||
|
||||
int previousHandle = faces[0].getSortingIndex();
|
||||
int previousHandle = parts[0].getSortingIndex();
|
||||
int start = 0;
|
||||
int groupIndex = 0;
|
||||
|
||||
for (int i = 1; i < faces.length; ++i) {
|
||||
if (previousHandle != faces[i].getSortingIndex()) {
|
||||
for (int i = 1; i < parts.length; ++i) {
|
||||
if (previousHandle != parts[i].getSortingIndex()) {
|
||||
|
||||
groups[groupIndex] = new FaceGroup(faces, start, i);
|
||||
groups[groupIndex] = new ShapePartGroup(parts, start, i);
|
||||
start = i;
|
||||
groupIndex++;
|
||||
|
||||
previousHandle = faces[i].getSortingIndex();
|
||||
previousHandle = parts[i].getSortingIndex();
|
||||
}
|
||||
}
|
||||
|
||||
assert groupIndex == groups.length - 1;
|
||||
groups[groupIndex] = new FaceGroup(faces, start, faces.length);
|
||||
groups[groupIndex] = new ShapePartGroup(parts, start, parts.length);
|
||||
}
|
||||
|
||||
private int countUniqueFaces() {
|
||||
if (faces.length == 0)
|
||||
private int countUniqueParts() {
|
||||
if (parts.length == 0)
|
||||
return 0;
|
||||
|
||||
int result = 1;
|
||||
int previousHandle = faces[0].getSortingIndex();
|
||||
int previousHandle = parts[0].getSortingIndex();
|
||||
|
||||
for (int i = 1; i < faces.length; ++i) {
|
||||
if (previousHandle != faces[i].getSortingIndex()) {
|
||||
for (int i = 1; i < parts.length; ++i) {
|
||||
if (previousHandle != parts[i].getSortingIndex()) {
|
||||
result++;
|
||||
previousHandle = faces[i].getSortingIndex();
|
||||
previousHandle = parts[i].getSortingIndex();
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,11 +238,11 @@ public class Shape implements Renderable {
|
||||
return program;
|
||||
}
|
||||
|
||||
public Face[] getFaces() {
|
||||
return faces;
|
||||
public ShapePart[] getParts() {
|
||||
return parts;
|
||||
}
|
||||
|
||||
public FaceGroup[] getGroups() {
|
||||
public ShapePartGroup[] getGroups() {
|
||||
return groups;
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ import java.util.Objects;
|
||||
|
||||
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||
|
||||
public class Face implements Comparable<Face> {
|
||||
public class ShapePart implements Comparable<ShapePart> {
|
||||
|
||||
private static final ShortBuffer GENERATE_SUCCESSIVE_LATER = null;
|
||||
|
||||
@ -40,7 +40,7 @@ public class Face implements Comparable<Face> {
|
||||
private ShortBuffer userIndices;
|
||||
private boolean userIndicesUpdated = true;
|
||||
|
||||
public Face(
|
||||
public ShapePart(
|
||||
Texture texture,
|
||||
ByteBuffer vertices,
|
||||
ShortBuffer indices
|
||||
@ -50,7 +50,7 @@ public class Face implements Comparable<Face> {
|
||||
setIndices(indices);
|
||||
}
|
||||
|
||||
public Face(
|
||||
public ShapePart(
|
||||
Texture texture,
|
||||
ByteBuffer vertices
|
||||
) {
|
||||
@ -155,7 +155,7 @@ public class Face implements Comparable<Face> {
|
||||
return vertices;
|
||||
}
|
||||
|
||||
public Face setVertices(ByteBuffer vertices) {
|
||||
public ShapePart setVertices(ByteBuffer vertices) {
|
||||
this.vertices = Objects.requireNonNull(vertices, "vertices");
|
||||
markForVertexUpdate();
|
||||
return this;
|
||||
@ -202,7 +202,7 @@ public class Face implements Comparable<Face> {
|
||||
return userIndices.remaining();
|
||||
}
|
||||
|
||||
public Face setIndices(ShortBuffer indices) {
|
||||
public ShapePart setIndices(ShortBuffer indices) {
|
||||
if (indices == null) {
|
||||
indices = GENERATE_SUCCESSIVE_LATER;
|
||||
}
|
||||
@ -245,7 +245,7 @@ public class Face implements Comparable<Face> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Face o) {
|
||||
public int compareTo(ShapePart o) {
|
||||
return Integer.compare(getSortingIndex(), o.getSortingIndex());
|
||||
}
|
||||
|
@ -21,13 +21,13 @@ package ru.windcorp.progressia.client.graphics.model;
|
||||
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||
import ru.windcorp.progressia.client.graphics.texture.TexturePrimitive;
|
||||
|
||||
public class FaceGroup {
|
||||
public class ShapePartGroup {
|
||||
|
||||
private final TexturePrimitive texture;
|
||||
private final int indexCount;
|
||||
private final int byteOffsetOfIndices;
|
||||
|
||||
FaceGroup(Face[] faces, int start, int end) {
|
||||
ShapePartGroup(ShapePart[] faces, int start, int end) {
|
||||
|
||||
Texture t = faces[start].getTexture();
|
||||
this.texture = t == null ? null : t.getSprite().getPrimitive();
|
||||
@ -36,10 +36,9 @@ public class FaceGroup {
|
||||
int indexCount = 0;
|
||||
|
||||
for (int i = start; i < end; ++i) {
|
||||
Face face = faces[i];
|
||||
ShapePart face = faces[i];
|
||||
|
||||
assert this.texture == null
|
||||
? (face.getTexture() == null)
|
||||
assert this.texture == null ? (face.getTexture() == null)
|
||||
: (face.getTexture().getSprite().getPrimitive() == this.texture);
|
||||
|
||||
indexCount += face.getIndexCount();
|
@ -25,14 +25,14 @@ import glm.vec._3.Vec3;
|
||||
import glm.vec._4.Vec4;
|
||||
import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram.VertexBuilder;
|
||||
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||
import ru.windcorp.progressia.common.world.block.BlockFace;
|
||||
import ru.windcorp.progressia.common.world.rels.AbsFace;
|
||||
|
||||
public class Faces {
|
||||
public class ShapeParts {
|
||||
|
||||
private Faces() {
|
||||
private ShapeParts() {
|
||||
}
|
||||
|
||||
public static Face createRectangle(
|
||||
public static ShapePart createRectangle(
|
||||
ShapeRenderProgram program,
|
||||
Texture texture,
|
||||
Vec4 colorMultiplier,
|
||||
@ -82,19 +82,19 @@ public class Faces {
|
||||
}
|
||||
);
|
||||
|
||||
return new Face(
|
||||
return new ShapePart(
|
||||
texture,
|
||||
builder.assemble(),
|
||||
buffer
|
||||
);
|
||||
}
|
||||
|
||||
public static Face createBlockFace(
|
||||
public static ShapePart createBlockFace(
|
||||
ShapeRenderProgram program,
|
||||
Texture texture,
|
||||
Vec4 colorMultiplier,
|
||||
Vec3 blockCenter,
|
||||
BlockFace face,
|
||||
AbsFace face,
|
||||
boolean inner
|
||||
) {
|
||||
BlockFaceVectors vectors = BlockFaceVectors.get(inner);
|
@ -28,15 +28,10 @@ public class ShapeRenderHelper {
|
||||
protected static final int TRANSFORM_STACK_SIZE = 64;
|
||||
protected static final int COLOR_MULTIPLIER_STACK_SIZE = TRANSFORM_STACK_SIZE;
|
||||
|
||||
protected final StashingStack<Mat4> transformStack = new StashingStack<>(
|
||||
TRANSFORM_STACK_SIZE,
|
||||
Mat4::new
|
||||
);
|
||||
protected final StashingStack<Mat4> transformStack = new StashingStack<>(TRANSFORM_STACK_SIZE, Mat4::new);
|
||||
|
||||
protected final StashingStack<Vec4> colorMultiplierStack = new StashingStack<>(
|
||||
COLOR_MULTIPLIER_STACK_SIZE,
|
||||
Vec4::new
|
||||
);
|
||||
protected final StashingStack<Vec4> colorMultiplierStack = new StashingStack<>(COLOR_MULTIPLIER_STACK_SIZE,
|
||||
Vec4::new);
|
||||
|
||||
{
|
||||
transformStack.push().identity();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user