15 Commits

Author SHA1 Message Date
8c7c37c9c0 Code cleanup 2021-07-14 18:23:10 +03:00
3b24ee0531 Documentation for module system and minor changes. 2021-07-10 21:46:15 +03:00
953614a7d8 Now you cannot run tasks second time or if requirements are not met 2021-07-10 20:19:57 +03:00
7f57510ac8 Licensed module system. Minor changes
- Added license commetary to each file of module system
- Added default meta info generation for Module
2021-07-10 08:29:09 +03:00
c7842935ba Loaders are observable. Modules refactoring
- Now it is possible to monitor loaders and tasks they perform
- Now it is NOT possible to add  dublicate tasks and modules
2021-07-09 18:12:30 +03:00
f520d4b2c6 TaskManager bug fixes and code cleanup 2021-07-07 17:02:38 +03:00
5a06788652 Refactored modules system 2021-07-07 13:37:11 +03:00
56e9be727b Removed debug code 2021-07-05 11:32:58 +03:00
e795d76367 Update .gitignore
- added log files to ignore
2021-07-05 11:32:11 +03:00
a9724d9d4c Developed module loader algorithm 2021-06-30 19:59:30 +03:00
3859db5b27 Added TaskManager
- Working on modules system
2021-06-27 18:27:56 +03:00
513feb1093 Merge branch 'master' into moduleSystem 2021-06-12 21:05:15 +03:00
942c665d73 Developing module systme
- Added Module class
- minor changes in Task class
2021-01-10 15:30:05 +03:00
5a521fc131 Refactored Task class
- Now crash reports have stacktrace
- Minor changes
2021-01-09 20:52:19 +03:00
361d795ab1 Added Task class 2021-01-09 19:36:11 +03:00
601 changed files with 8605 additions and 19042 deletions

1
.gitignore vendored
View File

@ -37,3 +37,4 @@ build_packages/NSIS/*
!build_packages/DEB
build_packages/DEB/*
!build_packages/DEB/template
*.log

View File

@ -111,6 +111,8 @@ switch (OperatingSystem.current()) {
}
dependencies {
implementation 'org.jetbrains:annotations:20.1.0'
implementation platform("org.lwjgl:lwjgl-bom:$lwjglVersion")
implementation "org.lwjgl:lwjgl"

View File

@ -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;
@ -98,7 +98,10 @@ public class OpenSimplex2S {
// 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 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;
@ -109,8 +112,7 @@ 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];
@ -124,16 +126,15 @@ 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;
@ -144,17 +145,15 @@ 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;
@ -168,23 +167,20 @@ 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.
@ -192,10 +188,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) {
@ -203,10 +199,8 @@ 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.
// 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);
@ -236,9 +230,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;
@ -247,12 +241,11 @@ 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>();
@ -273,13 +266,10 @@ public class OpenSimplex2S {
}
// 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);
@ -297,16 +287,11 @@ 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++) {
@ -315,22 +300,16 @@ 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;
@ -339,14 +318,13 @@ 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);
@ -359,9 +337,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;
@ -371,12 +349,11 @@ 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>();
@ -388,10 +365,8 @@ 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);
@ -417,16 +392,11 @@ 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++) {
@ -435,12 +405,8 @@ 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++) {
@ -449,21 +415,15 @@ 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;
@ -475,16 +435,13 @@ 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);
@ -518,35 +475,11 @@ 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;
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; }
} else {
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;
}
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);
@ -556,15 +489,10 @@ 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);
@ -597,36 +525,27 @@ 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;
@ -635,24 +554,28 @@ 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;
@ -663,42 +586,29 @@ 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;
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);
//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);
}
@ -707,20 +617,15 @@ 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);
@ -732,19 +637,15 @@ public class OpenSimplex2S {
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);
}
}
@ -760,8 +661,7 @@ 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;
@ -783,9 +683,10 @@ public class OpenSimplex2S {
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];
@ -823,8 +724,7 @@ 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;
@ -851,9 +751,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][];
@ -867,12 +767,11 @@ 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];
@ -891,8 +790,7 @@ public class OpenSimplex2S {
}
}
} else
kernel[zz][yy] = kernel[zz][2 * scaledRadiusY - yy - 1];
} else kernel[zz][yy] = kernel[zz][2 * scaledRadiusY - yy - 1];
}
}
}
@ -900,50 +798,40 @@ 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;
}
}
@ -953,20 +841,15 @@ 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;
}
}
@ -978,23 +861,35 @@ 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;
@ -1010,43 +905,61 @@ 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(-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(-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( 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

View File

@ -611,7 +611,8 @@ 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;
}
@ -627,7 +628,8 @@ 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;
}

View File

@ -30,8 +30,18 @@ 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) {

View File

@ -40,7 +40,8 @@ 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.
*
@ -1069,18 +1070,21 @@ 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()) {
@ -1099,17 +1103,14 @@ 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&lt;T&gt;} 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");
@ -1117,19 +1118,22 @@ 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()) {
@ -1148,15 +1152,13 @@ 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");
@ -1164,19 +1166,22 @@ 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()) {
@ -1195,15 +1200,13 @@ 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");
@ -1211,19 +1214,22 @@ 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()) {
@ -1242,15 +1248,13 @@ 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");

View File

@ -103,8 +103,14 @@ 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;
@ -114,8 +120,14 @@ 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;
@ -140,7 +152,8 @@ 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");
}
@ -160,7 +173,11 @@ 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);
}
@ -208,7 +225,11 @@ 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());
}
@ -236,7 +257,11 @@ 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));
}
}
@ -257,8 +282,10 @@ 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());
@ -288,7 +315,11 @@ 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++;
}
@ -297,7 +328,11 @@ 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();

View File

@ -41,8 +41,13 @@ 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());
@ -74,8 +79,13 @@ 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());
@ -109,8 +119,13 @@ 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());
@ -131,8 +146,14 @@ 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());
@ -142,15 +163,28 @@ 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());
@ -164,7 +198,11 @@ 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) {
@ -328,7 +366,11 @@ 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;
@ -347,17 +389,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");
@ -374,7 +416,10 @@ 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)
};
}
/**
@ -382,7 +427,8 @@ 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:
*
@ -393,14 +439,13 @@ 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");
@ -508,8 +553,10 @@ 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)) {
@ -545,7 +592,8 @@ 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>
@ -582,12 +630,10 @@ 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)
@ -607,7 +653,8 @@ 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:
@ -645,15 +692,13 @@ 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) {
@ -828,8 +873,12 @@ 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 {
@ -855,8 +904,13 @@ 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 {
@ -931,7 +985,10 @@ 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) {

View File

@ -27,9 +27,10 @@ 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;

View File

@ -51,12 +51,9 @@ 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) {

View File

@ -179,7 +179,8 @@ 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
*/

View File

@ -38,7 +38,8 @@ 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;

View File

@ -45,15 +45,8 @@ 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) {
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) {
ThrowingBiConsumer<? super T, ? super U, ? extends E> second
) {
return (t, u) -> {
first.accept(t, u);
second.accept(t, u);
@ -61,7 +54,19 @@ 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, E> first, BiConsumer<? super T, ? super U> second) {
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
) {
return (t, u) -> {
first.accept(t, u);
second.accept(t, u);

View File

@ -39,24 +39,30 @@ 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);

View File

@ -28,8 +28,10 @@ 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);
@ -57,17 +59,22 @@ 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) {
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) {
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(
ThrowingFunction<? super T, I, E> first, Function<? super I, ? extends R> second) {
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
) {
return t -> second.apply(first.apply(t));
}

View File

@ -38,8 +38,10 @@ 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();

View File

@ -49,8 +49,10 @@ 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();

View File

@ -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.DefaultWorldData;
import ru.windcorp.progressia.common.world.WorldData;
import ru.windcorp.progressia.common.world.entity.EntityData;
public class Client {
@ -36,7 +36,7 @@ public class Client {
private final ServerCommsChannel comms;
public Client(DefaultWorldData world, ServerCommsChannel comms) {
public Client(WorldData world, ServerCommsChannel comms) {
this.world = new WorldRender(world, this);
this.comms = comms;
@ -69,7 +69,11 @@ public class Client {
return;
}
getCamera().setAnchor(new EntityAnchor(getWorld().getEntityRenderable(entity)));
getCamera().setAnchor(
new EntityAnchor(
getWorld().getEntityRenderable(entity)
)
);
}
}

View File

@ -28,6 +28,7 @@ import ru.windcorp.progressia.client.graphics.font.Typefaces;
import ru.windcorp.progressia.client.graphics.texture.Atlases;
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
import ru.windcorp.progressia.client.localization.Localizer;
import ru.windcorp.progressia.common.modules.TaskManager;
import ru.windcorp.progressia.common.resource.ResourceManager;
import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.server.ServerState;
@ -42,8 +43,10 @@ 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");
}
@ -55,6 +58,8 @@ public class ClientProxy implements Proxy {
Atlases.loadAllAtlases();
AudioSystem.initialize();
TaskManager.getInstance().startLoading();
ServerState.startServer();
ClientState.connectToLocalServer();

View File

@ -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.DefaultWorldData;
import ru.windcorp.progressia.common.world.WorldData;
import ru.windcorp.progressia.server.ServerState;
import ru.windcorp.progressia.test.LayerAbout;
import ru.windcorp.progressia.test.LayerTestUI;
@ -41,9 +41,11 @@ public class ClientState {
public static void connectToLocalServer() {
DefaultWorldData world = new DefaultWorldData();
WorldData world = new WorldData();
LocalServerCommsChannel channel = new LocalServerCommsChannel(ServerState.getInstance());
LocalServerCommsChannel channel = new LocalServerCommsChannel(
ServerState.getInstance()
);
Client client = new Client(world, channel);

View File

@ -43,7 +43,10 @@ public class AudioManager {
private static Speaker musicSpeaker;
public static void initAL() {
String defaultDeviceName = alcGetString(0, ALC_DEFAULT_DEVICE_SPECIFIER);
String defaultDeviceName = alcGetString(
0,
ALC_DEFAULT_DEVICE_SPECIFIER
);
device = alcOpenDevice(defaultDeviceName);
@ -72,7 +75,10 @@ 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;
}

View File

@ -18,18 +18,35 @@
package ru.windcorp.progressia.client.audio;
import org.apache.logging.log4j.LogManager;
import ru.windcorp.progressia.common.modules.Module;
import ru.windcorp.progressia.common.modules.Task;
import ru.windcorp.progressia.common.modules.TaskManager;
import ru.windcorp.progressia.common.resource.ResourceManager;
public class AudioSystem {
static public void initialize() {
Module audioModule = new Module("AudioModule:System");
AudioManager.initAL();
Thread shutdownHook = new Thread(AudioManager::closeAL, "AL Shutdown Hook");
Runtime.getRuntime().addShutdownHook(shutdownHook);
Task t = new Task("AudioSystem:Initialize") {
@Override
protected void perform() {
loadAudioData();
LogManager.getLogger().info("Audio data is loaded");
}
};
audioModule.addTask(t);
TaskManager.getInstance().registerModule(audioModule);
}
static void loadAudioData() {
AudioManager.loadSound(ResourceManager.getResource("assets/sounds/block_destroy_clap.ogg"),
"Progressia:BlockDestroy", AudioFormat.MONO);
AudioManager.loadSound(
ResourceManager.getResource("assets/sounds/block_destroy_clap.ogg"),
"Progressia:BlockDestroy",
AudioFormat.MONO
);
}
}

View File

@ -22,7 +22,10 @@ import glm.vec._3.Vec3;
import ru.windcorp.progressia.client.audio.backend.SoundType;
import ru.windcorp.progressia.client.audio.backend.Speaker;
public class Music extends Sound {
public class Music
extends Sound {
public Music(SoundType soundType, int timeLength, float pitch, float gain) {
super(soundType, timeLength, new Vec3(), new Vec3(), pitch, gain);

View File

@ -40,7 +40,14 @@ public class Sound {
this(AudioRegistry.getInstance().get(id));
}
public Sound(String id, int timeLength, Vec3 position, Vec3 velocity, float pitch, float gain) {
public Sound(
String id,
int timeLength,
Vec3 position,
Vec3 velocity,
float pitch,
float gain
) {
this(id);
this.position = position;
this.velocity = velocity;
@ -48,7 +55,14 @@ public class Sound {
this.gain = gain;
}
public Sound(SoundType soundType, int timeLength, Vec3 position, Vec3 velocity, float pitch, float gain) {
public Sound(
SoundType soundType,
int timeLength,
Vec3 position,
Vec3 velocity,
float pitch,
float gain
) {
this(soundType);
this.position = position;
this.velocity = velocity;

View File

@ -39,7 +39,12 @@ public class AudioReader {
ShortBuffer rawAudio = decodeVorbis(resource, channelBuffer, rateBuffer);
return new SoundType(id, rawAudio, format, rateBuffer.get(0));
return new SoundType(
id,
rawAudio,
format,
rateBuffer.get(0)
);
}
public static SoundType readAsMono(Resource resource, String id) {
@ -50,7 +55,15 @@ public class AudioReader {
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
);
}
}

View File

@ -55,8 +55,9 @@ 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);
@ -71,9 +72,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();
@ -90,7 +91,17 @@ 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
}
);
}
}

View File

@ -34,7 +34,12 @@ public class SoundType extends Namespaced {
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;

View File

@ -24,7 +24,9 @@ import static org.lwjgl.openal.AL11.*;
public class Speaker {
public enum State {
NOT_PLAYING, PLAYING, PLAYING_LOOP
NOT_PLAYING,
PLAYING,
PLAYING_LOOP
}
// Buffers
@ -47,7 +49,13 @@ 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);
@ -55,7 +63,12 @@ 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);

View File

@ -39,7 +39,9 @@ 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);
}

View File

@ -33,12 +33,17 @@ 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;
@ -49,7 +54,10 @@ 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());

View File

@ -29,7 +29,11 @@ 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) {
public ControlTriggerLocalLambda(
String id,
Predicate<InputEvent> predicate,
Consumer<InputEvent> action
) {
super(id);
this.predicate = predicate;

View File

@ -27,57 +27,120 @@ 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
);
}
//
@ -94,52 +157,100 @@ public class ControlTriggers {
//
//
public static ControlTriggerInputBased localOf(String id, Consumer<InputEvent> action,
Predicate<InputEvent> predicate) {
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);
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));
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);
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);
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);
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> Consumer<InputEvent> createCheckedAction(Class<I> inputType,
Consumer<I> action) {
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) {
private static <I extends InputEvent> Predicate<InputEvent> createCheckedCompoundPredicate(
Class<I> inputType,
Predicate<I>[] predicates
) {
return new CompoundCastPredicate<>(inputType, predicates);
}

View File

@ -32,7 +32,8 @@ 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) {

View File

@ -34,7 +34,11 @@ 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);
}

View File

@ -34,13 +34,7 @@ public class Colors {
DEBUG_BLUE = toVector(0xFF0000FF),
DEBUG_CYAN = toVector(0xFF00FFFF),
DEBUG_MAGENTA = toVector(0xFFFF00FF),
DEBUG_YELLOW = toVector(0xFFFFFF00),
LIGHT_GRAY = toVector(0xFFCBCBD0),
BLUE = toVector(0xFF37A2E6),
HOVER_BLUE = toVector(0xFFC3E4F7),
DISABLED_GRAY = toVector(0xFFE5E5E5),
DISABLED_BLUE = toVector(0xFFB2D8ED);
DEBUG_YELLOW = toVector(0xFFFFFF00);
public static Vec4 toVector(int argb) {
return toVector(argb, new Vec4());

View File

@ -24,7 +24,6 @@ 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;
@ -58,24 +57,15 @@ public class GUI {
}
public static void addBottomLayer(Layer layer) {
modify(layers -> {
layers.add(layer);
layer.onAdded();
});
modify(layers -> layers.add(layer));
}
public static void addTopLayer(Layer layer) {
modify(layers -> {
layers.add(0, layer);
layer.onAdded();
});
modify(layers -> layers.add(0, layer));
}
public static void removeLayer(Layer layer) {
modify(layers -> {
layers.remove(layer);
layer.onRemoved();
});
modify(layers -> layers.remove(layer));
}
private static void modify(LayerStackModification mod) {
@ -88,33 +78,12 @@ 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();
}
}
}

View File

@ -31,52 +31,15 @@ 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();
@ -116,12 +79,4 @@ public abstract class Layer {
return GraphicsInterface.getFrameHeight();
}
protected void onAdded() {
// Do nothing
}
protected void onRemoved() {
// Do nothing
}
}

View File

@ -159,14 +159,27 @@ public class GraphicsBackend {
public static void setFullscreen() {
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowMonitor(getWindowHandle(), glfwGetPrimaryMonitor(), 0, 0, vidmode.width(), vidmode.height(), 0);
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);
glfwSetWindowMonitor(
getWindowHandle(),
0,
(vidmode.width() - getFrameWidth()) / 2,
(vidmode.height() - getFrameHeight()) / 2,
getFrameWidth(),
getFrameHeight(),
0);
isFullscreen = false;
}
@ -179,18 +192,4 @@ public class GraphicsBackend {
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);
}
}
}

View File

@ -82,12 +82,4 @@ public class GraphicsInterface {
GraphicsBackend.setVSyncEnabled(GraphicsBackend.isVSyncEnabled());
}
public static boolean isMouseCaptured() {
return GraphicsBackend.isMouseCaptured();
}
public static void setMouseCaptured(boolean capture) {
GraphicsBackend.setMouseCaptured(capture);
}
}

View File

@ -49,7 +49,13 @@ 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);
@ -65,7 +71,12 @@ 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);
}
@ -86,7 +97,11 @@ 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
@ -116,7 +131,11 @@ 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);
@ -143,7 +162,10 @@ 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);
}

View File

@ -24,7 +24,10 @@ 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);

View File

@ -65,6 +65,8 @@ class LWJGLInitializer {
GraphicsBackend.setWindowHandle(handle);
glfwSetInputMode(handle, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
glfwMakeContextCurrent(handle);
glfwSwapInterval(0); // TODO: remove after config system is added
}
@ -92,10 +94,16 @@ class LWJGLInitializer {
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);

View File

@ -34,13 +34,19 @@ 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();
}
}
@ -69,16 +75,20 @@ 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;

View File

@ -41,7 +41,11 @@ 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);
}

View File

@ -23,7 +23,9 @@ 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;

View File

@ -28,7 +28,8 @@ 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;

View File

@ -32,7 +32,12 @@ 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"
);
}
}
@ -66,8 +71,19 @@ 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()
);
}
}

View File

@ -57,7 +57,10 @@ 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 + "\""
);
}
}
@ -87,7 +90,10 @@ public class Shader implements OpenGLDeletable {
}
public Shader(String resource) {
this(ShaderType.guessByResourceName(resource), getShaderResource(resource).readAsString());
this(
ShaderType.guessByResourceName(resource),
getShaderResource(resource).readAsString()
);
}
@Override

View File

@ -51,29 +51,104 @@ 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
);
}
}

View File

@ -37,7 +37,8 @@ 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());
}

View File

@ -33,8 +33,10 @@ 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() {
@ -46,13 +48,20 @@ 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();

View File

@ -88,7 +88,8 @@ public class Mask {
@Override
public String toString() {
return "(" + getStartX() + "; " + getStartY() + ") -> (" + getEndX() + "; " + getEndY() + ")";
return "(" + getStartX() + "; " + getStartY() +
") -> (" + getEndX() + "; " + getEndY() + ")";
}
}

View File

@ -24,8 +24,9 @@ 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);

View File

@ -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.ShapePart;
import ru.windcorp.progressia.client.graphics.model.ShapeParts;
import ru.windcorp.progressia.client.graphics.model.Face;
import ru.windcorp.progressia.client.graphics.model.Faces;
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<ShapePart> currentClipFaces = new ArrayList<>();
private final List<Face> currentClipFaces = new ArrayList<>();
private int depth = 0;
@ -94,8 +94,8 @@ public class RenderTarget {
protected void assembleCurrentClipFromFaces() {
if (!currentClipFaces.isEmpty()) {
ShapePart[] faces = currentClipFaces.toArray(
new ShapePart[currentClipFaces.size()]
Face[] faces = currentClipFaces.toArray(
new Face[currentClipFaces.size()]
);
currentClipFaces.clear();
@ -189,13 +189,16 @@ public class RenderTarget {
public void addCustomRenderer(Renderable renderable) {
assembleCurrentClipFromFaces();
float depth = this.depth--;
Mat4 transform = new Mat4().translate(0, 0, depth).mul(getTransform());
assembled.add(new Clip(maskStack, transform, renderable));
assembled.add(
new Clip(
maskStack,
getTransform(),
renderable
)
);
}
protected void addFaceToCurrentClip(ShapePart face) {
protected void addFaceToCurrentClip(Face face) {
currentClipFaces.add(face);
}
@ -267,7 +270,7 @@ public class RenderTarget {
fill(Colors.toVector(color));
}
public ShapePart createRectagleFace(
public Face createRectagleFace(
int x,
int y,
int width,
@ -277,7 +280,7 @@ public class RenderTarget {
) {
float depth = this.depth--;
return ShapeParts.createRectangle(
return Faces.createRectangle(
FlatRenderProgram.getDefault(),
texture,
color,
@ -288,7 +291,7 @@ public class RenderTarget {
);
}
public ShapePart createRectagleFace(
public Face createRectagleFace(
int x,
int y,
int width,

View File

@ -42,8 +42,14 @@ 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);
}
@ -55,8 +61,14 @@ 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);
@ -100,17 +112,35 @@ 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) {

View File

@ -68,11 +68,17 @@ 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);
}
@ -96,8 +102,7 @@ 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) {

View File

@ -81,7 +81,8 @@ 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) {
@ -96,8 +97,13 @@ 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) {
@ -159,7 +165,8 @@ 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"
);
}
}
}
@ -183,7 +190,8 @@ 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),
@ -192,7 +200,8 @@ public class GNUUnifontLoader {
return a;
},
Characteristics.UNORDERED);
Characteristics.UNORDERED
);
}
private GNUUnifontLoader() {

View File

@ -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.ShapePart;
import ru.windcorp.progressia.client.graphics.model.ShapeParts;
import ru.windcorp.progressia.client.graphics.model.Face;
import ru.windcorp.progressia.client.graphics.model.Faces;
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(),
ShapeParts.createRectangle(
Faces.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(),
ShapeParts.createRectangle(
Faces.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<ShapePart> faces = new ArrayList<>();
private final Collection<Face> 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(
ShapeParts.createRectangle(
Faces.createRectangle(
getProgram(),
texture,
color,
@ -314,7 +314,7 @@ public abstract class SpriteTypeface extends Typeface {
return new Shape(
Usage.STATIC,
getProgram(),
workspace.faces.toArray(new ShapePart[workspace.faces.size()])
workspace.faces.toArray(new Face[workspace.faces.size()])
);
}

View File

@ -29,8 +29,12 @@ 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;
@ -67,19 +71,40 @@ 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);
@ -88,7 +113,13 @@ 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);

View File

@ -1,151 +0,0 @@
/*
* 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;
}
}

View File

@ -1,79 +0,0 @@
/*
* 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));
}
}
}

View File

@ -1,149 +0,0 @@
/*
* 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));
}
}
}

View File

@ -19,23 +19,18 @@
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;
@ -67,8 +62,6 @@ 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;
@ -292,31 +285,10 @@ 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;
@ -365,7 +337,7 @@ public class Component extends Named {
return;
}
if (component.canGainFocusNow()) {
if (component.isFocusable()) {
setFocused(false);
component.setFocused(true);
return;
@ -407,7 +379,7 @@ public class Component extends Named {
return;
}
if (component.canGainFocusNow()) {
if (component.isFocusable()) {
setFocused(false);
component.setFocused(true);
return;
@ -461,51 +433,12 @@ 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 && isEnabled()) {
if (this.isHovered != isHovered) {
this.isHovered = isHovered;
if (!isHovered && !getChildren().isEmpty()) {
@ -542,8 +475,11 @@ 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();
}
@ -566,7 +502,7 @@ public class Component extends Named {
}
protected void handleInput(Input input) {
if (inputBus != null && isEnabled()) {
if (inputBus != null) {
inputBus.dispatch(input);
}
}
@ -662,17 +598,6 @@ 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
}
@ -713,135 +638,6 @@ 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

View File

@ -83,11 +83,6 @@ public class Label extends Component {
return font;
}
public void setFont(Font font) {
this.font = font;
requestReassembly();
}
public String getCurrentText() {
return currentText;
}
@ -101,7 +96,11 @@ public class Label extends Component {
float startX = getX() + font.getAlign() * (getWidth() - currentSize.x);
target.pushTransform(
new Mat4().identity().translate(startX, getY(), 0).scale(2)
new Mat4().identity().translate(startX, getY(), -1000) // TODO wtf
// is this
// magic
// <---
.scale(2)
);
target.addCustomRenderer(font.assemble(currentText, maxWidth));

View File

@ -15,66 +15,14 @@
* 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.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 class Panel extends Component {
public Panel(String name, Layout 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);
}
super(name);
setLayout(layout);
}
}

View File

@ -1,205 +0,0 @@
/*
* 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));
}
}
}

View File

@ -1,119 +0,0 @@
/*
* 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);
}
}
}

View File

@ -1,60 +0,0 @@
/*
* 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;
}
}

View File

@ -1,11 +0,0 @@
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);
}
}

View File

@ -56,8 +56,13 @@ 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
);
});
}
@ -66,7 +71,9 @@ 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);
});

View File

@ -26,7 +26,9 @@ 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;
@ -49,17 +51,32 @@ 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()
);
}
}

View File

@ -26,7 +26,9 @@ 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;
@ -49,17 +51,32 @@ 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
);
}
}

View File

@ -1,78 +0,0 @@
/*
* 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 + ")";
}
}

View File

@ -98,26 +98,15 @@ 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() + parent.getHeight() - (rows[row] + height),
parent.getY() + rows[row],
width,
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]))
);
}
}
@ -143,9 +132,10 @@ public class LayoutGrid implements Layout {
GridDimensions grid = calculateGrid(c);
grid.sum();
int[] coords;
for (Component child : c.getChildren()) {
Vec2i coords = (Vec2i) child.getLayoutHint();
grid.setBounds(coords.x, coords.y, child, c);
coords = (int[]) child.getLayoutHint();
grid.setBounds(coords[0], coords[1], child, c);
}
}
}
@ -159,10 +149,11 @@ public class LayoutGrid implements Layout {
private GridDimensions calculateGrid(Component parent) {
GridDimensions result = new GridDimensions();
int[] coords;
for (Component child : parent.getChildren()) {
Vec2i coords = (Vec2i) child.getLayoutHint();
result.add(coords.x, coords.y, child.getPreferredSize());
coords = (int[]) child.getLayoutHint();
result.add(coords[0], coords[1], child.getPreferredSize());
}
return result;

View File

@ -43,7 +43,8 @@ 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;

View File

@ -43,7 +43,8 @@ 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()) {

View File

@ -1,117 +0,0 @@
/*
* 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();
}
}

View File

@ -87,14 +87,22 @@ 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);
}

View File

@ -67,7 +67,11 @@ 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;
}

View File

@ -27,7 +27,13 @@ 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;

View File

@ -46,12 +46,17 @@ 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();
@ -95,8 +100,14 @@ 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);

View File

@ -31,21 +31,28 @@ 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);
}
@ -59,12 +66,18 @@ 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);
}

View File

@ -18,23 +18,23 @@
package ru.windcorp.progressia.client.graphics.model;
import static ru.windcorp.progressia.common.world.rels.AbsFace.*;
import static ru.windcorp.progressia.common.world.block.BlockFace.*;
import com.google.common.collect.ImmutableMap;
import glm.vec._3.Vec3;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.block.BlockFace;
class BlockFaceVectors {
private static BlockFaceVectors createInner(BlockFaceVectors outer) {
ImmutableMap.Builder<AbsFace, Vec3> originBuilder = ImmutableMap.builder();
ImmutableMap.Builder<BlockFace, Vec3> originBuilder = ImmutableMap.builder();
ImmutableMap.Builder<AbsFace, Vec3> widthBuilder = ImmutableMap.builder();
ImmutableMap.Builder<BlockFace, Vec3> widthBuilder = ImmutableMap.builder();
ImmutableMap.Builder<AbsFace, Vec3> heightBuilder = ImmutableMap.builder();
ImmutableMap.Builder<BlockFace, Vec3> heightBuilder = ImmutableMap.builder();
for (AbsFace face : getFaces()) {
for (BlockFace face : getFaces()) {
Vec3 width = outer.getWidth(face);
Vec3 height = outer.getHeight(face);
@ -59,36 +59,36 @@ class BlockFaceVectors {
static {
OUTER = new BlockFaceVectors(
ImmutableMap.<AbsFace, Vec3>builder()
ImmutableMap.<BlockFace, Vec3>builder()
.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))
.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))
.build(),
ImmutableMap.<AbsFace, Vec3>builder()
ImmutableMap.<BlockFace, Vec3>builder()
.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))
.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))
.build(),
ImmutableMap.<AbsFace, Vec3>builder()
ImmutableMap.<BlockFace, Vec3>builder()
.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))
.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))
.build()
);
@ -100,29 +100,29 @@ class BlockFaceVectors {
return inner ? INNER : OUTER;
}
private final ImmutableMap<AbsFace, Vec3> origins;
private final ImmutableMap<AbsFace, Vec3> widths;
private final ImmutableMap<AbsFace, Vec3> heights;
private final ImmutableMap<BlockFace, Vec3> origins;
private final ImmutableMap<BlockFace, Vec3> widths;
private final ImmutableMap<BlockFace, Vec3> heights;
public BlockFaceVectors(
ImmutableMap<AbsFace, Vec3> origins,
ImmutableMap<AbsFace, Vec3> widths,
ImmutableMap<AbsFace, Vec3> heights
ImmutableMap<BlockFace, Vec3> origins,
ImmutableMap<BlockFace, Vec3> widths,
ImmutableMap<BlockFace, Vec3> heights
) {
this.origins = origins;
this.widths = widths;
this.heights = heights;
}
public Vec3 getOrigin(AbsFace face) {
public Vec3 getOrigin(BlockFace face) {
return origins.get(face);
}
public Vec3 getWidth(AbsFace face) {
public Vec3 getWidth(BlockFace face) {
return widths.get(face);
}
public Vec3 getHeight(AbsFace face) {
public Vec3 getHeight(BlockFace face) {
return heights.get(face);
}
}

View File

@ -33,14 +33,22 @@ 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
@ -70,7 +78,11 @@ 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);
@ -78,15 +90,22 @@ 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);
}

View File

@ -24,7 +24,7 @@ import java.util.Objects;
import ru.windcorp.progressia.client.graphics.texture.Texture;
public class ShapePart implements Comparable<ShapePart> {
public class Face implements Comparable<Face> {
private static final ShortBuffer GENERATE_SUCCESSIVE_LATER = null;
@ -40,7 +40,7 @@ public class ShapePart implements Comparable<ShapePart> {
private ShortBuffer userIndices;
private boolean userIndicesUpdated = true;
public ShapePart(
public Face(
Texture texture,
ByteBuffer vertices,
ShortBuffer indices
@ -50,7 +50,7 @@ public class ShapePart implements Comparable<ShapePart> {
setIndices(indices);
}
public ShapePart(
public Face(
Texture texture,
ByteBuffer vertices
) {
@ -155,7 +155,7 @@ public class ShapePart implements Comparable<ShapePart> {
return vertices;
}
public ShapePart setVertices(ByteBuffer vertices) {
public Face setVertices(ByteBuffer vertices) {
this.vertices = Objects.requireNonNull(vertices, "vertices");
markForVertexUpdate();
return this;
@ -202,7 +202,7 @@ public class ShapePart implements Comparable<ShapePart> {
return userIndices.remaining();
}
public ShapePart setIndices(ShortBuffer indices) {
public Face setIndices(ShortBuffer indices) {
if (indices == null) {
indices = GENERATE_SUCCESSIVE_LATER;
}
@ -245,7 +245,7 @@ public class ShapePart implements Comparable<ShapePart> {
}
@Override
public int compareTo(ShapePart o) {
public int compareTo(Face o) {
return Integer.compare(getSortingIndex(), o.getSortingIndex());
}

View File

@ -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 ShapePartGroup {
public class FaceGroup {
private final TexturePrimitive texture;
private final int indexCount;
private final int byteOffsetOfIndices;
ShapePartGroup(ShapePart[] faces, int start, int end) {
FaceGroup(Face[] faces, int start, int end) {
Texture t = faces[start].getTexture();
this.texture = t == null ? null : t.getSprite().getPrimitive();
@ -36,9 +36,10 @@ public class ShapePartGroup {
int indexCount = 0;
for (int i = start; i < end; ++i) {
ShapePart face = faces[i];
Face 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();

View File

@ -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.rels.AbsFace;
import ru.windcorp.progressia.common.world.block.BlockFace;
public class ShapeParts {
public class Faces {
private ShapeParts() {
private Faces() {
}
public static ShapePart createRectangle(
public static Face createRectangle(
ShapeRenderProgram program,
Texture texture,
Vec4 colorMultiplier,
@ -82,19 +82,19 @@ public class ShapeParts {
}
);
return new ShapePart(
return new Face(
texture,
builder.assemble(),
buffer
);
}
public static ShapePart createBlockFace(
public static Face createBlockFace(
ShapeRenderProgram program,
Texture texture,
Vec4 colorMultiplier,
Vec3 blockCenter,
AbsFace face,
BlockFace face,
boolean inner
) {
BlockFaceVectors vectors = BlockFaceVectors.get(inner);

View File

@ -37,13 +37,23 @@ 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
@ -65,7 +75,11 @@ 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);
@ -74,15 +88,23 @@ 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);
}
@ -105,8 +127,12 @@ 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 }
);
}
}

View File

@ -30,10 +30,10 @@ import ru.windcorp.progressia.client.graphics.backend.VertexBufferObject;
public class Shape implements Renderable {
private final ShapeRenderProgram program;
private final ShapePart[] parts;
private final Face[] faces;
private final Usage usage;
private ShapePartGroup[] groups;
private FaceGroup[] 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, ShapePart... parts) {
public Shape(Usage usage, ShapeRenderProgram program, Face... faces) {
this.program = program;
this.parts = parts;
this.faces = faces;
this.usage = usage;
configureParts();
configureFaces();
program.preprocess(this);
assembleBuffers();
}
private void configureParts() {
for (ShapePart part : parts) {
part.setShape(this);
private void configureFaces() {
for (Face face : faces) {
face.setShape(this);
}
}
private void assembleBuffers() {
// TODO optimize: only update faces that requested it
sortParts();
sortFaces();
resizeBuffers();
for (ShapePart part : parts) {
assembleVertices(part);
assembleIndices(part);
part.resetUpdateFlags();
for (Face face : faces) {
assembleVertices(face);
assembleIndices(face);
face.resetUpdateFlags();
}
this.vertices.flip();
@ -85,110 +85,110 @@ public class Shape implements Renderable {
private void resizeBuffers() {
int verticesRequired = 0, indicesRequired = 0;
for (ShapePart part : parts) {
verticesRequired += part.getVertices().remaining();
indicesRequired += part.getIndices().remaining();
for (Face face : faces) {
verticesRequired += face.getVertices().remaining();
indicesRequired += face.getIndices().remaining();
}
if (vertices == null || vertices.capacity() < verticesRequired) {
if (this.vertices == null || vertices.capacity() < verticesRequired) {
this.vertices = BufferUtils.createByteBuffer(verticesRequired);
} else {
vertices.position(0).limit(verticesRequired);
this.vertices.position(0).limit(verticesRequired);
}
if (indices == null || indices.capacity() < indicesRequired) {
if (this.indices == null || this.indices.capacity() < indicesRequired) {
this.indices = BufferUtils.createShortBuffer(indicesRequired);
} else {
indices.position(0).limit(indicesRequired);
this.indices.position(0).limit(indicesRequired);
}
}
private void assembleVertices(ShapePart part) {
part.locationOfVertices = this.vertices.position();
private void assembleVertices(Face face) {
face.locationOfVertices = this.vertices.position();
insertVertices(part);
linkVerticesWith(part);
insertVertices(face);
linkVerticesWith(face);
}
private void insertVertices(ShapePart part) {
ByteBuffer partVertices = part.getVertices();
private void insertVertices(Face face) {
ByteBuffer faceVertices = face.getVertices();
partVertices.mark();
this.vertices.put(partVertices);
partVertices.reset();
faceVertices.mark();
this.vertices.put(faceVertices);
faceVertices.reset();
}
private void linkVerticesWith(ShapePart part) {
private void linkVerticesWith(Face face) {
int limit = vertices.limit();
int position = vertices.position();
vertices.limit(position).position(part.getLocationOfVertices());
part.vertices = vertices.slice();
vertices.limit(position).position(face.getLocationOfVertices());
face.vertices = vertices.slice();
vertices.position(position).limit(limit);
}
private void assembleIndices(ShapePart part) {
short vertexOffset = (short) (part.getLocationOfVertices() / program.getBytesPerVertex());
private void assembleIndices(Face face) {
short vertexOffset = (short) (face.getLocationOfVertices() / program.getBytesPerVertex());
part.locationOfIndices = indices.position();
face.locationOfIndices = indices.position();
ShortBuffer partIndices = part.getIndices();
ShortBuffer faceIndices = face.getIndices();
if (partIndices == null) {
for (int i = 0; i < part.getVertexCount(); ++i) {
if (faceIndices == null) {
for (int i = 0; i < face.getVertexCount(); ++i) {
this.indices.put((short) (vertexOffset + i));
}
} else {
for (int i = partIndices.position(); i < partIndices.limit(); ++i) {
short partIndex = partIndices.get(i);
partIndex += vertexOffset;
this.indices.put(partIndex);
for (int i = faceIndices.position(); i < faceIndices.limit(); ++i) {
short faceIndex = faceIndices.get(i);
faceIndex += vertexOffset;
this.indices.put(faceIndex);
}
}
}
private void sortParts() {
Arrays.sort(parts);
private void sortFaces() {
Arrays.sort(faces);
}
private void assembleGroups() {
int unique = countUniqueParts();
this.groups = new ShapePartGroup[unique];
int unique = countUniqueFaces();
this.groups = new FaceGroup[unique];
if (parts.length == 0)
if (faces.length == 0)
return;
int previousHandle = parts[0].getSortingIndex();
int previousHandle = faces[0].getSortingIndex();
int start = 0;
int groupIndex = 0;
for (int i = 1; i < parts.length; ++i) {
if (previousHandle != parts[i].getSortingIndex()) {
for (int i = 1; i < faces.length; ++i) {
if (previousHandle != faces[i].getSortingIndex()) {
groups[groupIndex] = new ShapePartGroup(parts, start, i);
groups[groupIndex] = new FaceGroup(faces, start, i);
start = i;
groupIndex++;
previousHandle = parts[i].getSortingIndex();
previousHandle = faces[i].getSortingIndex();
}
}
assert groupIndex == groups.length - 1;
groups[groupIndex] = new ShapePartGroup(parts, start, parts.length);
groups[groupIndex] = new FaceGroup(faces, start, faces.length);
}
private int countUniqueParts() {
if (parts.length == 0)
private int countUniqueFaces() {
if (faces.length == 0)
return 0;
int result = 1;
int previousHandle = parts[0].getSortingIndex();
int previousHandle = faces[0].getSortingIndex();
for (int i = 1; i < parts.length; ++i) {
if (previousHandle != parts[i].getSortingIndex()) {
for (int i = 1; i < faces.length; ++i) {
if (previousHandle != faces[i].getSortingIndex()) {
result++;
previousHandle = parts[i].getSortingIndex();
previousHandle = faces[i].getSortingIndex();
}
}
@ -238,11 +238,11 @@ public class Shape implements Renderable {
return program;
}
public ShapePart[] getParts() {
return parts;
public Face[] getFaces() {
return faces;
}
public ShapePartGroup[] getGroups() {
public FaceGroup[] getGroups() {
return groups;
}

View File

@ -28,10 +28,15 @@ 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();

View File

@ -53,7 +53,8 @@ public class ShapeRenderProgram extends Program {
POSITIONS_ATTRIBUTE_NAME = "inputPositions",
UNIFORM_COLOR_MULTIPLER_ATTRIBUTE_NAME = "uniformColorMultiplier",
ATTRIBUTE_COLOR_MULTIPLER_ATTRIBUTE_NAME = "inputColorMultiplier",
TEXTURE_COORDS_ATTRIBUTE_NAME = "inputTextureCoords", USE_TEXTURE_UNIFORM_NAME = "useTexture",
TEXTURE_COORDS_ATTRIBUTE_NAME = "inputTextureCoords",
USE_TEXTURE_UNIFORM_NAME = "useTexture",
TEXTURE_SLOT_UNIFORM_NAME = "textureSlot";
private final Uniform4Matrix finalTransformUniform;
@ -64,11 +65,21 @@ public class ShapeRenderProgram extends Program {
private final Uniform1Int useTextureUniform;
private final Uniform1Int textureSlotUniform;
public ShapeRenderProgram(String[] vertexShaderResources, String[] fragmentShaderResources) {
super(new CombinedShader(attachVertexShader(vertexShaderResources)),
new CombinedShader(attachFragmentShader(fragmentShaderResources)));
public ShapeRenderProgram(
String[] vertexShaderResources,
String[] fragmentShaderResources
) {
super(
new CombinedShader(
attachVertexShader(vertexShaderResources)
),
new CombinedShader(
attachFragmentShader(fragmentShaderResources)
)
);
this.finalTransformUniform = getUniform(FINAL_TRANSFORM_UNIFORM_NAME).as4Matrix();
this.finalTransformUniform = getUniform(FINAL_TRANSFORM_UNIFORM_NAME)
.as4Matrix();
this.positionsAttribute = getAttribute(POSITIONS_ATTRIBUTE_NAME).asVertexArray();
@ -78,9 +89,11 @@ public class ShapeRenderProgram extends Program {
this.textureCoordsAttribute = getAttribute(TEXTURE_COORDS_ATTRIBUTE_NAME).asVertexArray();
this.useTextureUniform = getUniform(USE_TEXTURE_UNIFORM_NAME).as1Int();
this.useTextureUniform = getUniform(USE_TEXTURE_UNIFORM_NAME)
.as1Int();
this.textureSlotUniform = getUniform(TEXTURE_SLOT_UNIFORM_NAME).as1Int();
this.textureSlotUniform = getUniform(TEXTURE_SLOT_UNIFORM_NAME)
.as1Int();
}
private static String[] attachVertexShader(String[] others) {
@ -91,7 +104,10 @@ public class ShapeRenderProgram extends Program {
return ObjectArrays.concat(SHAPE_FRAGMENT_SHADER_RESOURCE, others);
}
public void render(ShapeRenderHelper helper, Shape shape) {
public void render(
ShapeRenderHelper helper,
Shape shape
) {
use();
configure(helper);
@ -100,7 +116,7 @@ public class ShapeRenderProgram extends Program {
try {
enableAttributes();
for (ShapePartGroup group : shape.getGroups()) {
for (FaceGroup group : shape.getGroups()) {
renderFaceGroup(group);
}
} finally {
@ -129,13 +145,34 @@ public class ShapeRenderProgram extends Program {
int vertexStride = getBytesPerVertex();
int offset = 0;
positionsAttribute.set(3, GL11.GL_FLOAT, false, vertexStride, vertices, offset);
positionsAttribute.set(
3,
GL11.GL_FLOAT,
false,
vertexStride,
vertices,
offset
);
offset += 3 * Float.BYTES;
colorsAttribute.set(4, GL11.GL_FLOAT, false, vertexStride, vertices, offset);
colorsAttribute.set(
4,
GL11.GL_FLOAT,
false,
vertexStride,
vertices,
offset
);
offset += 4 * Float.BYTES;
textureCoordsAttribute.set(2, GL11.GL_FLOAT, false, vertexStride, vertices, offset);
textureCoordsAttribute.set(
2,
GL11.GL_FLOAT,
false,
vertexStride,
vertices,
offset
);
offset += 2 * Float.BYTES;
return offset;
@ -145,7 +182,7 @@ public class ShapeRenderProgram extends Program {
indices.bind(BindTarget.ELEMENT_ARRAY);
}
protected void renderFaceGroup(ShapePartGroup group) {
protected void renderFaceGroup(FaceGroup group) {
TexturePrimitive texture = group.getTexture();
if (texture != null) {
@ -156,8 +193,12 @@ public class ShapeRenderProgram extends Program {
useTextureUniform.set(0);
}
GL11.glDrawElements(GL11.GL_TRIANGLES, group.getIndexCount(), GL11.GL_UNSIGNED_SHORT,
group.getByteOffsetOfIndices());
GL11.glDrawElements(
GL11.GL_TRIANGLES,
group.getIndexCount(),
GL11.GL_UNSIGNED_SHORT,
group.getByteOffsetOfIndices()
);
}
public int getBytesPerVertex() {
@ -165,12 +206,12 @@ public class ShapeRenderProgram extends Program {
}
public void preprocess(Shape shape) {
for (ShapePart face : shape.getParts()) {
for (Face face : shape.getFaces()) {
applySprites(face);
}
}
private void applySprites(ShapePart face) {
private void applySprites(Face face) {
if (face.getTexture() == null)
return;
@ -179,9 +220,13 @@ public class ShapeRenderProgram extends Program {
Sprite sprite = face.getTexture().getSprite();
for (int i = 0; i < face.getVertexCount(); i++) {
int offset = vertices.position() + i * getBytesPerVertex() + (3 * Float.BYTES + 4 * Float.BYTES);
int offset = vertices.position() + i * getBytesPerVertex() + (3 * Float.BYTES +
4 * Float.BYTES);
v.set(vertices.getFloat(offset + 0 * Float.BYTES), vertices.getFloat(offset + 1 * Float.BYTES));
v.set(
vertices.getFloat(offset + 0 * Float.BYTES),
vertices.getFloat(offset + 1 * Float.BYTES)
);
v.mul(sprite.getSize()).add(sprite.getStart());
@ -199,11 +244,34 @@ public class ShapeRenderProgram extends Program {
}
public static interface VertexBuilder {
VertexBuilder addVertex(float x, float y, float z, float r, float g, float b, float tx, float ty);
VertexBuilder addVertex(
float x,
float y,
float z,
float r,
float g,
float b,
float tx,
float ty
);
VertexBuilder addVertex(float x, float y, float z, float r, float g, float b, float a, float tx, float ty);
VertexBuilder addVertex(
float x,
float y,
float z,
float r,
float g,
float b,
float a,
float tx,
float ty
);
VertexBuilder addVertex(Vec3 position, Vec4 colorMultiplier, Vec2 textureCoords);
VertexBuilder addVertex(
Vec3 position,
Vec4 colorMultiplier,
Vec2 textureCoords
);
ByteBuffer assemble();
}
@ -225,35 +293,84 @@ public class ShapeRenderProgram extends Program {
private final List<Vertex> vertices = new ArrayList<>();
@Override
public VertexBuilder addVertex(float x, float y, float z, float r, float g, float b, float a, float tx,
float ty) {
vertices.add(new Vertex(new Vec3(x, y, z), new Vec4(r, g, b, a), new Vec2(tx, ty)));
public VertexBuilder addVertex(
float x,
float y,
float z,
float r,
float g,
float b,
float a,
float tx,
float ty
) {
vertices.add(
new Vertex(
new Vec3(x, y, z),
new Vec4(r, g, b, a),
new Vec2(tx, ty)
)
);
return this;
}
@Override
public VertexBuilder addVertex(float x, float y, float z, float r, float g, float b, float tx, float ty) {
vertices.add(new Vertex(new Vec3(x, y, z), new Vec4(r, g, b, 1f), new Vec2(tx, ty)));
public VertexBuilder addVertex(
float x,
float y,
float z,
float r,
float g,
float b,
float tx,
float ty
) {
vertices.add(
new Vertex(
new Vec3(x, y, z),
new Vec4(r, g, b, 1f),
new Vec2(tx, ty)
)
);
return this;
}
@Override
public VertexBuilder addVertex(Vec3 position, Vec4 colorMultiplier, Vec2 textureCoords) {
vertices.add(new Vertex(new Vec3(position), new Vec4(colorMultiplier), new Vec2(textureCoords)));
public VertexBuilder addVertex(
Vec3 position,
Vec4 colorMultiplier,
Vec2 textureCoords
) {
vertices.add(
new Vertex(
new Vec3(position),
new Vec4(colorMultiplier),
new Vec2(textureCoords)
)
);
return this;
}
@Override
public ByteBuffer assemble() {
ByteBuffer result = BufferUtils.createByteBuffer(DEFAULT_BYTES_PER_VERTEX * vertices.size());
ByteBuffer result = BufferUtils.createByteBuffer(
DEFAULT_BYTES_PER_VERTEX * vertices.size()
);
for (Vertex v : vertices) {
result.putFloat(v.position.x).putFloat(v.position.y).putFloat(v.position.z)
.putFloat(v.colorMultiplier.x).putFloat(v.colorMultiplier.y).putFloat(v.colorMultiplier.z)
.putFloat(v.colorMultiplier.w).putFloat(v.textureCoords.x).putFloat(v.textureCoords.y);
result
.putFloat(v.position.x)
.putFloat(v.position.y)
.putFloat(v.position.z)
.putFloat(v.colorMultiplier.x)
.putFloat(v.colorMultiplier.y)
.putFloat(v.colorMultiplier.z)
.putFloat(v.colorMultiplier.w)
.putFloat(v.textureCoords.x)
.putFloat(v.textureCoords.y);
}
result.flip();

View File

@ -24,7 +24,7 @@ import glm.vec._3.Vec3;
import glm.vec._4.Vec4;
import ru.windcorp.progressia.client.graphics.backend.Usage;
import ru.windcorp.progressia.client.graphics.texture.Texture;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.block.BlockFace;
public class Shapes {
@ -50,7 +50,7 @@ public class Shapes {
boolean flip
) {
ShapePart top = ShapeParts.createRectangle(
Face top = Faces.createRectangle(
program,
topTexture,
colorMultiplier,
@ -60,7 +60,7 @@ public class Shapes {
flip
);
ShapePart bottom = ShapeParts.createRectangle(
Face bottom = Faces.createRectangle(
program,
bottomTexture,
colorMultiplier,
@ -70,7 +70,7 @@ public class Shapes {
flip
);
ShapePart north = ShapeParts.createRectangle(
Face north = Faces.createRectangle(
program,
northTexture,
colorMultiplier,
@ -80,7 +80,7 @@ public class Shapes {
flip
);
ShapePart south = ShapeParts.createRectangle(
Face south = Faces.createRectangle(
program,
southTexture,
colorMultiplier,
@ -90,7 +90,7 @@ public class Shapes {
flip
);
ShapePart east = ShapeParts.createRectangle(
Face east = Faces.createRectangle(
program,
eastTexture,
colorMultiplier,
@ -100,7 +100,7 @@ public class Shapes {
flip
);
ShapePart west = ShapeParts.createRectangle(
Face west = Faces.createRectangle(
program,
westTexture,
colorMultiplier,
@ -165,16 +165,16 @@ public class Shapes {
public PppBuilder(
ShapeRenderProgram program,
Map<AbsFace, Texture> textureMap
Map<BlockFace, Texture> textureMap
) {
this(
program,
textureMap.get(AbsFace.POS_Z),
textureMap.get(AbsFace.NEG_Z),
textureMap.get(AbsFace.POS_X),
textureMap.get(AbsFace.NEG_X),
textureMap.get(AbsFace.NEG_Y),
textureMap.get(AbsFace.POS_Y)
textureMap.get(BlockFace.TOP),
textureMap.get(BlockFace.BOTTOM),
textureMap.get(BlockFace.NORTH),
textureMap.get(BlockFace.SOUTH),
textureMap.get(BlockFace.EAST),
textureMap.get(BlockFace.WEST)
);
}

View File

@ -30,7 +30,10 @@ public class StaticModel extends Model {
private final Mat4[] transforms;
public StaticModel(Renderable[] parts, Mat4[] transforms) {
public StaticModel(
Renderable[] parts,
Mat4[] transforms
) {
super(parts);
this.transforms = transforms;
}
@ -52,14 +55,19 @@ public class StaticModel extends Model {
protected Builder() {
}
public Builder addPart(Renderable part, Mat4 transform) {
public Builder addPart(
Renderable part,
Mat4 transform
) {
parts.add(Objects.requireNonNull(part, "part"));
transforms.add(Objects.requireNonNull(transform, "transform"));
return this;
}
public Builder addPart(Renderable part) {
public Builder addPart(
Renderable part
) {
return addPart(part, IDENTITY);
}

View File

@ -87,8 +87,11 @@ public class Atlases {
editor.draw(data, nextX, nextY);
Sprite result = new Sprite(getPrimitive(), toPrimitiveCoords(nextX, nextY),
toPrimitiveCoords(width, height));
Sprite result = new Sprite(
getPrimitive(),
toPrimitiveCoords(nextX, nextY),
toPrimitiveCoords(width, height)
);
nextX += width;

View File

@ -21,7 +21,7 @@ package ru.windcorp.progressia.client.graphics.texture;
import java.util.Map;
import glm.vec._2.Vec2;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.block.BlockFace;
public class ComplexTexture {
@ -54,14 +54,14 @@ public class ComplexTexture {
);
}
public Map<AbsFace, Texture> getCuboidTextures(
public Map<BlockFace, Texture> getCuboidTextures(
int x,
int y,
int width,
int height,
int depth
) {
return AbsFace.mapToFaces(
return BlockFace.mapToFaces(
get(
x + depth + width,
y + height + depth,
@ -86,7 +86,7 @@ public class ComplexTexture {
);
}
public Map<AbsFace, Texture> getCuboidTextures(
public Map<BlockFace, Texture> getCuboidTextures(
int x,
int y,
int size

View File

@ -44,7 +44,9 @@ public class SimpleTextures {
try {
TextureDataEditor data = TextureLoader.loadPixels(resource, SETTINGS);
return new SimpleTexture(new Sprite(new TexturePrimitive(data.getData())));
return new SimpleTexture(
new Sprite(new TexturePrimitive(data.getData()))
);
} catch (IOException e) {
throw CrashReports.report(e, "Could not load texture %s", resource);
}

View File

@ -38,8 +38,14 @@ public class Sprite {
}
public Sprite(TexturePrimitive primitive) {
this(primitive, ORIGIN, new Vec2(primitive.getWidth() / (float) primitive.getBufferWidth(),
primitive.getHeight() / (float) primitive.getBufferHeight()));
this(
primitive,
ORIGIN,
new Vec2(
primitive.getWidth() / (float) primitive.getBufferWidth(),
primitive.getHeight() / (float) primitive.getBufferHeight()
)
);
}
public TexturePrimitive getPrimitive() {

View File

@ -35,8 +35,14 @@ class TextureData {
private final int width;
private final int height;
public TextureData(ByteBuffer data, int bufferWidth, int bufferHeight, int width, int height,
TextureSettings settings) {
public TextureData(
ByteBuffer data,
int bufferWidth,
int bufferHeight,
int width,
int height,
TextureSettings settings
) {
this.data = data;
this.width = width;
this.height = height;
@ -60,7 +66,8 @@ class TextureData {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, // Load 2D image
glTexImage2D(
GL_TEXTURE_2D, // Load 2D image
0, // Not mipmapped
GL_RGBA, // Use RGBA
bufferWidth, // Width

View File

@ -28,10 +28,21 @@ public class TextureDataEditor {
protected final TextureData data;
public TextureDataEditor(int bufferWidth, int bufferHeight, int contentWidth, int contentHeight,
TextureSettings settings) {
this.data = new TextureData(BufferUtils.createByteBuffer(bufferWidth * bufferHeight * 4), bufferWidth,
bufferHeight, contentWidth, contentHeight, settings);
public TextureDataEditor(
int bufferWidth,
int bufferHeight,
int contentWidth,
int contentHeight,
TextureSettings settings
) {
this.data = new TextureData(
BufferUtils.createByteBuffer(bufferWidth * bufferHeight * 4),
bufferWidth,
bufferHeight,
contentWidth,
contentHeight,
settings
);
}
public TextureDataEditor(TextureData data) {
@ -50,13 +61,21 @@ public class TextureDataEditor {
TextureData t = getData();
ByteBuffer fromBuffer = getBuffer();
ByteBuffer toBuffer = BufferUtils.createByteBuffer(fromBuffer.capacity());
ByteBuffer toBuffer = BufferUtils.createByteBuffer(
fromBuffer.capacity()
);
copy(fromBuffer, 0, fromBuffer.capacity(), toBuffer);
toBuffer.clear();
return new TextureData(toBuffer, t.getBufferWidth(), t.getBufferHeight(), t.getContentWidth(),
t.getContentHeight(), t.getSettings());
return new TextureData(
toBuffer,
t.getBufferWidth(),
t.getBufferHeight(),
t.getContentWidth(),
t.getContentHeight(),
t.getSettings()
);
}
public TextureData createSnapshot(TextureData output) {
@ -95,7 +114,16 @@ public class TextureDataEditor {
return getData().getSettings();
}
public void draw(ByteBuffer src, int srcWidth, int srcX, int srcY, int dstX, int dstY, int width, int height) {
public void draw(
ByteBuffer src,
int srcWidth,
int srcX,
int srcY,
int dstX,
int dstY,
int width,
int height
) {
ByteBuffer dst = getBuffer();
int position = src.position();
@ -120,20 +148,77 @@ public class TextureDataEditor {
}
}
public void draw(TextureData source, int srcX, int srcY, int dstX, int dstY, int width, int height) {
draw(source.getData(), source.getBufferWidth(), srcX, srcY, dstX, dstY, width, height);
public void draw(
TextureData source,
int srcX,
int srcY,
int dstX,
int dstY,
int width,
int height
) {
draw(
source.getData(),
source.getBufferWidth(),
srcX,
srcY,
dstX,
dstY,
width,
height
);
}
public void draw(TextureData source, int dstX, int dstY) {
draw(source, 0, 0, dstX, dstY, source.getContentWidth(), source.getContentHeight());
public void draw(
TextureData source,
int dstX,
int dstY
) {
draw(
source,
0,
0,
dstX,
dstY,
source.getContentWidth(),
source.getContentHeight()
);
}
public void draw(TextureDataEditor source, int srcX, int srcY, int dstX, int dstY, int width, int height) {
draw(source.getData(), srcX, srcY, dstX, dstY, width, height);
public void draw(
TextureDataEditor source,
int srcX,
int srcY,
int dstX,
int dstY,
int width,
int height
) {
draw(
source.getData(),
srcX,
srcY,
dstX,
dstY,
width,
height
);
}
public void draw(TextureDataEditor source, int dstX, int dstY) {
draw(source, 0, 0, dstX, dstY, source.getContentWidth(), source.getContentHeight());
public void draw(
TextureDataEditor source,
int dstX,
int dstY
) {
draw(
source,
0,
0,
dstX,
dstY,
source.getContentWidth(),
source.getContentHeight()
);
}
public void setPixel(int x, int y, int color) {
@ -152,7 +237,12 @@ public class TextureDataEditor {
buffer.limit(buffer.position() + length * BYTES_PER_PIXEL);
}
private static void copy(ByteBuffer src, int srcStart, int srcEnd, ByteBuffer dst) {
private static void copy(
ByteBuffer src,
int srcStart,
int srcEnd,
ByteBuffer dst
) {
int position = src.position();
int limit = src.limit();

View File

@ -31,7 +31,11 @@ import ru.windcorp.progressia.common.util.BinUtil;
public class TextureLoader {
public static TextureDataEditor loadPixels(InputStream compressed, TextureSettings settings) throws IOException {
public static TextureDataEditor loadPixels(
InputStream compressed,
TextureSettings settings
)
throws IOException {
BufferedImage readResult = ImageIO.read(compressed);
int width = readResult.getWidth();
@ -40,7 +44,10 @@ public class TextureLoader {
int bufferWidth = BinUtil.roundToGreaterPowerOf2(width);
int bufferHeight = BinUtil.roundToGreaterPowerOf2(height);
WritableRaster raster = TextureUtil.createRaster(bufferWidth, bufferHeight);
WritableRaster raster = TextureUtil.createRaster(
bufferWidth,
bufferHeight
);
BufferedImage canvas = TextureUtil.createCanvas(raster);
@ -49,22 +56,49 @@ public class TextureLoader {
try {
g.setColor(TextureUtil.CANVAS_BACKGROUND);
g.fillRect(0, 0, bufferWidth, bufferHeight);
g.drawImage(readResult, 0, 0, width, height, 0, height, width, 0, // Flip
// the
// image
null);
g.drawImage(
readResult,
0,
0,
width,
height,
0,
height,
width,
0, // Flip the image
null
);
} finally {
g.dispose();
}
TextureDataEditor result = new TextureDataEditor(bufferWidth, bufferHeight, width, height, settings);
TextureDataEditor result = new TextureDataEditor(
bufferWidth,
bufferHeight,
width,
height,
settings
);
result.draw(TextureUtil.extractBytes(raster), bufferWidth, 0, 0, 0, 0, width, height);
result.draw(
TextureUtil.extractBytes(raster),
bufferWidth,
0,
0,
0,
0,
width,
height
);
return result;
}
public static TextureDataEditor loadPixels(Resource resource, TextureSettings settings) throws IOException {
public static TextureDataEditor loadPixels(
Resource resource,
TextureSettings settings
)
throws IOException {
return loadPixels(resource.getInputStream(), settings);
}

Some files were not shown because too many files have changed in this diff Show More