37 Commits

Author SHA1 Message Date
0c41350ae7 Added file identification header
-All files now start with a 16 byte header consisting of "PROG" followed
by the integer position of the region in region coordinates.
	-regionCoords is passed through some functions to allow for this to be
confirmed.
2021-09-10 22:19:18 -04:00
a633c8324e Added Reset World button and fixed some translations 2021-09-11 00:47:28 +03:00
6b33f231b4 Moved region implementation to .server.world.io.region 2021-09-10 23:59:03 +03:00
e2308b825d Removed warnings and formatted code 2021-09-10 23:31:14 +03:00
e0f6a08740 Bug fixes
-Now offset technically starts at 1, so any chunks with offset 0 are
ignored.
-Reduced number of unused chunks, storage efficiency is at about 99% (if
null sectors are counted as useful)
2021-09-10 14:14:18 -04:00
2820e01974 Finished Partition Logic
Note: it still does waste a lot of space, I will work on that next
-Added back the confirmHeaderHealth logic
-Checks to make sure it will not overwrite important chunks
	-Uses PartitionLink chunks to move to a different part of the file
-Added allocateEmptySector() to allow for the file size to be increased
without moving the origin point of the chunk.
2021-09-10 13:51:37 -04:00
46bcb85044 Region File better????
-Moved most of the file accessing of Region to RegionFile
-Disabled most of the header check except the length check(it will be
back soon)
-Max chunk size arbitrarily raised to 4MiB because I wanted sectors
longer than 16B
-Sectors now have a mandatory 1B header that identifies it
	-0 is a null sector, it ends every chunk
	-1 is a normal data sector, it has a "parity" byte that makes sure it
is reading chunks in linear order(fun fact: it isnt at the moment)
	-2 is a jump to a different location. this isnt implemented well yet
	-3 will be a "bulk data" sector. Multiple chunks with identical data
can point here. Probably only useful when it is easily identifiable,
like multiple chunks being one entire block, like air.
-Removed all chunk length references as I think they do not make sense
when it can use different sectors for non-data purposes.
2021-09-09 19:58:44 -04:00
c5dfe3d0b7 Saving Modifications
-Safer saving, it waits for the file to stop being used to close(still
has holes)
-If a chunk is too large, it is moved to the end of the file.
	-Calculates the efficiency of each region file in confirmHeaderHealth
-Fixed import warning
2021-09-09 16:52:55 -04:00
0100c8791d Added player saving and loading from disk 2021-08-30 18:23:42 +03:00
e967a64401 More Compact region files
-Sector length increased to a short, the minimum sector size is now 16
bytes
2021-08-30 10:52:56 -04:00
d2ffe1fe0e Fixed the bug that opfromthestart found, reloading now works 2021-08-29 12:04:02 +03:00
f4300558d5 Formatted and broke the saving mechanism. I'm too tired to bugfix
- Refactored and formatted TestWorldDiskIO
- Removed HashableVec3i
- Added Coordinates methods for custom bit count
- Properly reverted commit 98250cd
- Known bugs:
  - Server shutdown close()s regions too early
  - Re-entering a world does not show saved changes
2021-08-29 02:08:19 +03:00
cd16334db8 Moved TestWorldDiskIO to a subpackage and introduced some abstractions 2021-08-28 23:31:50 +03:00
41a2909f7c Reverted last two commits because no one wants to fix the bugs 2021-08-28 21:31:34 +03:00
a222ea8f67 Fixed multithread chunk IO 2021-08-28 21:14:35 +03:00
98250cd524 Some changes for efficiency(not yet)
-Tried to use threads/executors in ChunkRequestDaemon, it just hangs.
-Added isEmpty and isOpaque attributes to DefaultChunkData (should this
just be in ChunkData?)
	-Added compute and getter functions to access(for everything after
loading)
	-Doesn't render empty chunks(not yet used)
-Using format 65537 allows the empty and opaqueness to be saved. They do
not do anything yet and there is no way to set them yet
	-Added loadRegionX and ".progressia_chunkx" file
-removed formats 0 and 1, which use individual chunk files.
2021-08-27 16:59:05 -04:00
9dcb3a7748 -Better HashableVec3i compare
-Added RandomFileMapped class
	-Made it a wrapper for RandomAccessFile and contains maps of locations
and lengths
-Added confirmHeaderHealth method to made sure the file isnt corrupted
-Changed everything from MappedByteBuffers to RandomFileMappeds.
2021-08-25 16:15:38 -04:00
0ccc108ddd Merge branch 'save-world'
Third time's the charm!
2021-08-24 01:38:22 +03:00
c7e7d3bdac Added ferns, fixed herb render and cleaned up TestContent
- Added Test:Fern
- Herbs are no longer stretched horizontally
- Formatted and cleaned up TestContent
2021-08-23 18:36:15 +03:00
62729f5873 Added packet buffering and fix crash when placing flowers on leaves
- Packets are now buffered before processing to reduce stack depth
- Attempts to place tiles on invalid locations get rejected earlier
2021-08-23 17:37:25 +03:00
84864f8947 Added more grass variants
- Added flat grass tiles with varying opaqueness
- Renamed Test:Grass to Test:GrassOpaque
- Added Chernozem
2021-08-23 15:18:37 +03:00
d01ef3654f Added grasses and flowers
- Added CROSimple to optimize simple non-Surface textures
- Added TileRenderCross
- Added Low, Medium and Tall grass
- Added Blue, Purple and White flat flowers
- Added Bushes
- Added tiny Dandelions and tiny Lavanders
- Improved grass and log textures
2021-08-22 22:18:42 +03:00
fae09edb16 Fixes n Speed n Stuff
-Better comparison for HashableVec3i
-Changed RandomAccessFile to MappedByteBuffer
-natFromInt now works properly
-better region selection
-Changes to make different strategies work
2021-08-19 10:47:16 -04:00
e4ced6507e Hash Things
-Removed unused imports
-Using HashMap to keep track of RandomAccessFile instances
-Using those instances to do stuff
-Made new HashableVec3i class that allows for hashing of 3d vectors.
2021-08-18 18:50:48 -04:00
b7dcbb0f30 Fixing stuff
-Got rid of some annoying logging
-Format
2021-08-18 13:21:54 -04:00
9c26418354 Well, it works now ig
-Better file lengthening
-Made temp files
    -Exchanged temp files for ByteArrayIn/OutputBuffers
-Fixed loadRegion to actually read sector sizes
2021-08-18 13:15:30 -04:00
6891d3a095 Trying to get it to work
-Uses many streams to keep track of things
-Fixed some bad things, still are a ton.
2021-08-06 12:56:21 -04:00
8167c40f64 IDK these errors are weird
-Changed the loading to fit the byte changes
2021-08-05 14:12:37 -04:00
8bc23acb61 idk changes so I can show OLEGSHA
-changed number of index bytes from 4 to 3
-exposed some variables for help with debugger
2021-08-05 13:39:42 -04:00
254faca0a5 Better deletion
-Makes new TestPlayerControls instance each time you enter a world
-Some dynamic sizing of chunk data within region files.
2021-08-05 12:29:29 -04:00
0c66f1751e Made outline of region file
-Improved loading screen loading(so it doesnt crash)
-Implemented region file related things, but it doesnt quite work
    -Uses file header to try to look up location of data
    -Writes the data at the end of the file(I need info to how much it writes)
2021-08-04 19:17:49 -04:00
c88dea6030 Fixing Bugs mostly
-Cleaning up imports
-Better error detection
-Actual thread deletion(still needs a bit of work to delete all conected objects)
-Starting making format file and inplementing it
2021-08-04 16:57:21 -04:00
6521cb5749 Better Listeners
-Specific listeners for the start and stop of loading
-Better(?) layer deletion after exiting a world
-Actual server thread shutdown
2021-08-04 12:52:37 -04:00
94db44e443 Im tired i need sleep
-Added listeners for saving and loading chunks
-Made loading screens for between title and game(they dont work yet)
-Added localized text(some)
-Safeish deletion and saving of chunks
    -It still keeps them in memory I think so this needs work too
2021-08-03 22:42:46 -04:00
53f72b068a Merge branch 'title-screen' into save-world 2021-08-03 20:08:39 -04:00
a9ca5f6b17 Everything Excpeti polishing and options
-Added LayerTitle class that is the title menu
-Edited the launcher and proxy so it only starts the game when it needs to
-Made buttons work with MutableString objects
2021-08-03 19:42:04 -04:00
4ab7cb738e Testing some stuff
-Made functions to convert integers into natural numbers (cause why not)
-Ideas/plans of dynamic/custom region file sizes
2021-08-03 17:53:49 -04:00
421 changed files with 5614 additions and 2742 deletions

View File

@ -72,9 +72,9 @@ public class OpenSimplex2S {
} }
/** /**
* 2D SuperSimplex noise, with Y pointing down the main diagonal. Might be * 2D SuperSimplex noise, with Y pointing down the main diagonal.
* better for a 2D sandbox style game, where Y is vertical. Probably * Might be better for a 2D sandbox style game, where Y is vertical.
* slightly less optimal for heightmaps or continent maps. * Probably slightly less optimal for heightmaps or continent maps.
*/ */
public double noise2_XBeforeY(double x, double y) { public double noise2_XBeforeY(double x, double y) {
@ -86,8 +86,8 @@ public class OpenSimplex2S {
} }
/** /**
* 2D SuperSimplex noise base. Lookup table implementation inspired by * 2D SuperSimplex noise base.
* DigitalShadow. * Lookup table implementation inspired by DigitalShadow.
*/ */
private double noise2_Base(double xs, double ys) { private double noise2_Base(double xs, double ys) {
double value = 0; double value = 0;
@ -98,7 +98,10 @@ public class OpenSimplex2S {
// Index to point list // Index to point list
int a = (int)(xsi + ysi); 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 ssi = (xsi + ysi) * -0.211324865405187;
double xi = xsi + ssi, yi = ysi + ssi; double xi = xsi + ssi, yi = ysi + ssi;
@ -109,8 +112,7 @@ public class OpenSimplex2S {
double dx = xi + c.dx, dy = yi + c.dy; double dx = xi + c.dx, dy = yi + c.dy;
double attn = 2.0 / 3.0 - dx * dx - dy * dy; double attn = 2.0 / 3.0 - dx * dx - dy * dy;
if (attn <= 0) if (attn <= 0) continue;
continue;
int pxm = (xsb + c.xsv) & PMASK, pym = (ysb + c.ysv) & PMASK; int pxm = (xsb + c.xsv) & PMASK, pym = (ysb + c.ysv) & PMASK;
Grad2 grad = permGrad2[perm[pxm] ^ pym]; Grad2 grad = permGrad2[perm[pxm] ^ pym];
@ -124,16 +126,15 @@ public class OpenSimplex2S {
} }
/** /**
* 3D Re-oriented 8-point BCC noise, classic orientation Proper substitute * 3D Re-oriented 8-point BCC noise, classic orientation
* for what 3D SuperSimplex would be, in light of Forbidden Formulae. Use * Proper substitute for what 3D SuperSimplex would be,
* noise3_XYBeforeZ or noise3_XZBeforeY instead, wherever appropriate. * in light of Forbidden Formulae.
* Use noise3_XYBeforeZ or noise3_XZBeforeY instead, wherever appropriate.
*/ */
public double noise3_Classic(double x, double y, double z) { public double noise3_Classic(double x, double y, double z) {
// Re-orient the cubic lattices via rotation, to produce the expected // Re-orient the cubic lattices via rotation, to produce the expected look on cardinal planar slices.
// look on cardinal planar slices. // If texturing objects that don't tend to have cardinal plane faces, you could even remove this.
// If texturing objects that don't tend to have cardinal plane faces,
// you could even remove this.
// Orthonormal rotation. Not a skew transform. // Orthonormal rotation. Not a skew transform.
double r = (2.0 / 3.0) * (x + y + z); double r = (2.0 / 3.0) * (x + y + z);
double xr = r - x, yr = r - y, zr = r - 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). * 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 * Recommended for 3D terrain and time-varied animations.
* should always be the "different" coordinate in your use case. If Y is * The Z coordinate should always be the "different" coordinate in your use case.
* vertical in world coordinates, call noise3_XYBeforeZ(x, z, Y) or use * If Y is vertical in world coordinates, call noise3_XYBeforeZ(x, z, Y) or use noise3_XZBeforeY.
* noise3_XZBeforeY. If Z is vertical in world coordinates, call * If Z is vertical in world coordinates, call noise3_XYBeforeZ(x, y, Z).
* noise3_XYBeforeZ(x, y, Z). For a time varied animation, call * For a time varied animation, call noise3_XYBeforeZ(x, y, T).
* noise3_XYBeforeZ(x, y, T).
*/ */
public double noise3_XYBeforeZ(double x, double y, double z) { public double noise3_XYBeforeZ(double x, double y, double z) {
// Re-orient the cubic lattices without skewing, to make X and Y // Re-orient the cubic lattices without skewing, to make X and Y triangular like 2D.
// triangular like 2D.
// Orthonormal rotation. Not a skew transform. // Orthonormal rotation. Not a skew transform.
double xy = x + y; double xy = x + y;
double s2 = xy * -0.211324865405187; 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). * 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 * Recommended for 3D terrain and time-varied animations.
* should always be the "different" coordinate in your use case. If Y is * The Y coordinate should always be the "different" coordinate in your use case.
* vertical in world coordinates, call noise3_XZBeforeY(x, Y, z). If Z is * If Y is vertical in world coordinates, call noise3_XZBeforeY(x, Y, z).
* vertical in world coordinates, call noise3_XZBeforeY(x, Z, y) or use * If Z is vertical in world coordinates, call noise3_XZBeforeY(x, Z, y) or use noise3_XYBeforeZ.
* noise3_XYBeforeZ. For a time varied animation, call noise3_XZBeforeY(x, * For a time varied animation, call noise3_XZBeforeY(x, T, y) or use noise3_XYBeforeZ.
* T, y) or use noise3_XYBeforeZ.
*/ */
public double noise3_XZBeforeY(double x, double y, double z) { public double noise3_XZBeforeY(double x, double y, double z) {
// Re-orient the cubic lattices without skewing, to make X and Z // Re-orient the cubic lattices without skewing, to make X and Z triangular like 2D.
// triangular like 2D.
// Orthonormal rotation. Not a skew transform. // Orthonormal rotation. Not a skew transform.
double xz = x + z; double xz = x + z;
double s2 = xz * -0.211324865405187; double s2 = xz * -0.211324865405187;
double yy = y * 0.577350269189626; double yy = y * 0.577350269189626;
double xr = x + s2 - yy; double xr = x + s2 - yy; double zr = z + s2 - yy;
double zr = z + s2 - yy;
double yr = xz * 0.577350269189626 + yy; double yr = xz * 0.577350269189626 + yy;
// Evaluate both lattices to form a BCC lattice. // 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 * Generate overlapping cubic lattices for 3D Re-oriented BCC noise.
* table implementation inspired by DigitalShadow. It was actually faster to * Lookup table implementation inspired by DigitalShadow.
* narrow down the points in the loop itself, than to build up the index * It was actually faster to narrow down the points in the loop itself,
* with enough info to isolate 8 points. * than to build up the index with enough info to isolate 8 points.
*/ */
private double noise3_BCC(double xr, double yr, double zr) { 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); int xrb = fastFloor(xr), yrb = fastFloor(yr), zrb = fastFloor(zr);
double xri = xr - xrb, yri = yr - yrb, zri = zr - zrb; double xri = xr - xrb, yri = yr - yrb, zri = zr - zrb;
// Identify which octant of the cube we're in. This determines which // Identify which octant of the cube we're in. This determines which cell
// cell // in the other cubic lattice we're in, and also narrows down one point on each.
// 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 xht = (int)(xri + 0.5), yht = (int)(yri + 0.5), zht = (int)(zri + 0.5);
int index = (xht << 0) | (yht << 1) | (zht << 2); 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 * Generate the 2D noise over a large area.
* of iterating over a range. Results may occasionally slightly exceed [-1, * Propagates by flood-fill instead of iterating over a range.
* 1] due to the grid-snapped pre-generated kernel. * 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) { public void generate2(GenerateContext2D context, double[][] buffer, int x0, int y0) {
int height = buffer.length; int height = buffer.length;
@ -247,12 +241,11 @@ public class OpenSimplex2S {
} }
/** /**
* Generate the 2D noise over a large area. Propagates by flood-fill instead * Generate the 2D noise over a large area.
* of iterating over a range. Results may occasionally slightly exceed [-1, * Propagates by flood-fill instead of iterating over a range.
* 1] due to the grid-snapped pre-generated kernel. * 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, public void generate2(GenerateContext2D context, double[][] buffer, int x0, int y0, int width, int height, int skipX, int skipY) {
int skipX, int skipY) {
Queue<AreaGenLatticePoint2D> queue = new LinkedList<AreaGenLatticePoint2D>(); Queue<AreaGenLatticePoint2D> queue = new LinkedList<AreaGenLatticePoint2D>();
Set<AreaGenLatticePoint2D> seen = new HashSet<AreaGenLatticePoint2D>(); Set<AreaGenLatticePoint2D> seen = new HashSet<AreaGenLatticePoint2D>();
@ -273,13 +266,10 @@ public class OpenSimplex2S {
} }
// Get started with one point/vertex. // Get started with one point/vertex.
// For some lattices, you might need to try a handful of points in the // For some lattices, you might need to try a handful of points in the cell,
// cell, // or flip a couple of coordinates, to guarantee it or a neighbor contributes.
// or flip a couple of coordinates, to guarantee it or a neighbor
// contributes.
// For An* lattices, the base coordinate seems fine. // For An* lattices, the base coordinate seems fine.
double x0f = x0Skipped * context.xFrequency; double x0f = x0Skipped * context.xFrequency; double y0f = y0Skipped * context.yFrequency;
double y0f = y0Skipped * context.yFrequency;
double x0s = context.orientation.s00 * x0f + context.orientation.s01 * y0f; double x0s = context.orientation.s00 * x0f + context.orientation.s01 * y0f;
double y0s = context.orientation.s10 * x0f + context.orientation.s11 * y0f; double y0s = context.orientation.s10 * x0f + context.orientation.s11 * y0f;
int x0sb = fastFloor(x0s), y0sb = fastFloor(y0s); int x0sb = fastFloor(x0s), y0sb = fastFloor(y0s);
@ -297,16 +287,11 @@ public class OpenSimplex2S {
Grad2 grad = context.orientation.gradients[perm[perm[pxm] ^ pym]]; Grad2 grad = context.orientation.gradients[perm[perm[pxm] ^ pym]];
double gx = grad.dx * context.xFrequency; double gx = grad.dx * context.xFrequency;
double gy = grad.dy * context.yFrequency; double gy = grad.dy * context.yFrequency;
double gOff = 0.5 * (gx + gy); // to correct for (0.5, 0.5)-offset double gOff = 0.5 * (gx + gy); // to correct for (0.5, 0.5)-offset kernel
// kernel
// Contribution kernel bounds // Contribution kernel bounds
int yy0 = destPointY - scaledRadiusY; int yy0 = destPointY - scaledRadiusY; if (yy0 < y0Skipped) yy0 = y0Skipped;
if (yy0 < y0Skipped) int yy1 = destPointY + scaledRadiusY; if (yy1 > y0 + height) yy1 = y0 + height;
yy0 = y0Skipped;
int yy1 = destPointY + scaledRadiusY;
if (yy1 > y0 + height)
yy1 = y0 + height;
// For each row of the contribution circle, // For each row of the contribution circle,
for (int yy = yy0; yy < yy1; yy++) { 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 // Set up bounds so we only loop over what we need to
int thisScaledRadiusX = context.kernelBounds[ky]; int thisScaledRadiusX = context.kernelBounds[ky];
int xx0 = destPointX - thisScaledRadiusX; int xx0 = destPointX - thisScaledRadiusX; if (xx0 < x0Skipped) xx0 = x0Skipped;
if (xx0 < x0Skipped) int xx1 = destPointX + thisScaledRadiusX; if (xx1 > x0 + width) xx1 = x0 + width;
xx0 = x0Skipped;
int xx1 = destPointX + thisScaledRadiusX;
if (xx1 > x0 + width)
xx1 = x0 + width;
// For each point on that row // For each point on that row
for (int xx = xx0; xx < xx1; xx++) { for (int xx = xx0; xx < xx1; xx++) {
int dx = xx - destPointX; int dx = xx - destPointX;
int kx = dx + scaledRadiusX; int kx = dx + scaledRadiusX;
// gOff accounts for our choice to offset the pre-generated // gOff accounts for our choice to offset the pre-generated kernel by (0.5, 0.5) to avoid the zero center.
// 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)
// 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; double extrapolation = gx * dx + gy * dy + gOff;
buffer[yy - y0][xx - x0] += kernel[ky][kx] * extrapolation; buffer[yy - y0][xx - x0] += kernel[ky][kx] * extrapolation;
@ -339,14 +318,13 @@ public class OpenSimplex2S {
// For each neighbor of the point // For each neighbor of the point
for (int i = 0; i < NEIGHBOR_MAP_2D.length; i++) { for (int i = 0; i < NEIGHBOR_MAP_2D.length; i++) {
AreaGenLatticePoint2D neighbor = new AreaGenLatticePoint2D(context, point.xsv + NEIGHBOR_MAP_2D[i][0], AreaGenLatticePoint2D neighbor = new AreaGenLatticePoint2D(context,
point.ysv + NEIGHBOR_MAP_2D[i][1]); 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 it's in range of the buffer region and not seen before
if (neighbor.destPointX + scaledRadiusX >= x0Skipped if (neighbor.destPointX + scaledRadiusX >= x0Skipped && neighbor.destPointX - scaledRadiusX <= x0 + width - 1
&& neighbor.destPointX - scaledRadiusX <= x0 + width - 1 && neighbor.destPointY + scaledRadiusY >= y0Skipped && neighbor.destPointY - scaledRadiusY <= y0 + height - 1
&& neighbor.destPointY + scaledRadiusY >= y0Skipped && !seen.contains(neighbor)) {
&& neighbor.destPointY - scaledRadiusY <= y0 + height - 1 && !seen.contains(neighbor)) {
// Add it to the queue so we can process it at some point // Add it to the queue so we can process it at some point
queue.add(neighbor); queue.add(neighbor);
@ -359,9 +337,9 @@ public class OpenSimplex2S {
} }
/** /**
* Generate the 3D noise over a large area/volume. Propagates by flood-fill * Generate the 3D noise over a large area/volume.
* instead of iterating over a range. Results may occasionally slightly * Propagates by flood-fill instead of iterating over a range.
* exceed [-1, 1] due to the grid-snapped pre-generated kernel. * 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) { public void generate3(GenerateContext3D context, double[][][] buffer, int x0, int y0, int z0) {
int depth = buffer.length; int depth = buffer.length;
@ -371,12 +349,11 @@ public class OpenSimplex2S {
} }
/** /**
* Generate the 3D noise over a large area/volume. Propagates by flood-fill * Generate the 3D noise over a large area/volume.
* instead of iterating over a range. Results may occasionally slightly * Propagates by flood-fill instead of iterating over a range.
* exceed [-1, 1] due to the grid-snapped pre-generated kernel. * 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, 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) {
int depth, int skipX, int skipY, int skipZ) {
Queue<AreaGenLatticePoint3D> queue = new LinkedList<AreaGenLatticePoint3D>(); Queue<AreaGenLatticePoint3D> queue = new LinkedList<AreaGenLatticePoint3D>();
Set<AreaGenLatticePoint3D> seen = new HashSet<AreaGenLatticePoint3D>(); Set<AreaGenLatticePoint3D> seen = new HashSet<AreaGenLatticePoint3D>();
@ -388,10 +365,8 @@ public class OpenSimplex2S {
// Quaternion multiplication for rotation. // Quaternion multiplication for rotation.
// https://blog.molecular-matters.com/2013/05/24/a-faster-quaternion-vector-multiplication/ // 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, double qx = context.orientation.qx, qy = context.orientation.qy, qz = context.orientation.qz, qw = context.orientation.qw;
qw = context.orientation.qw; double x0f = x0Skipped * context.xFrequency, y0f = y0Skipped * context.yFrequency, z0f = z0Skipped * context.zFrequency;
double x0f = x0Skipped * context.xFrequency, y0f = y0Skipped * context.yFrequency,
z0f = z0Skipped * context.zFrequency;
double tx = 2 * (qy * z0f - qz * y0f); double tx = 2 * (qy * z0f - qz * y0f);
double ty = 2 * (qz * x0f - qx * z0f); double ty = 2 * (qz * x0f - qx * z0f);
double tz = 2 * (qx * y0f - qy * x0f); double tz = 2 * (qx * y0f - qy * x0f);
@ -417,16 +392,11 @@ public class OpenSimplex2S {
double gx = grad.dx * context.xFrequency; double gx = grad.dx * context.xFrequency;
double gy = grad.dy * context.yFrequency; double gy = grad.dy * context.yFrequency;
double gz = grad.dz * context.zFrequency; double gz = grad.dz * context.zFrequency;
double gOff = 0.5 * (gx + gy + gz); // to correct for (0.5, 0.5, double gOff = 0.5 * (gx + gy + gz); // to correct for (0.5, 0.5, 0.5)-offset kernel
// 0.5)-offset kernel
// Contribution kernel bounds. // Contribution kernel bounds.
int zz0 = destPointZ - scaledRadiusZ; int zz0 = destPointZ - scaledRadiusZ; if (zz0 < z0Skipped) zz0 = z0Skipped;
if (zz0 < z0Skipped) int zz1 = destPointZ + scaledRadiusZ; if (zz1 > z0 + depth) zz1 = z0 + depth;
zz0 = z0Skipped;
int zz1 = destPointZ + scaledRadiusZ;
if (zz1 > z0 + depth)
zz1 = z0 + depth;
// For each x/y slice of the contribution sphere, // For each x/y slice of the contribution sphere,
for (int zz = zz0; zz < zz1; zz++) { 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 // Set up bounds so we only loop over what we need to
int thisScaledRadiusY = context.kernelBoundsY[kz]; int thisScaledRadiusY = context.kernelBoundsY[kz];
int yy0 = destPointY - thisScaledRadiusY; int yy0 = destPointY - thisScaledRadiusY; if (yy0 < y0Skipped) yy0 = y0Skipped;
if (yy0 < y0Skipped) int yy1 = destPointY + thisScaledRadiusY; if (yy1 > y0 + height) yy1 = y0 + height;
yy0 = y0Skipped;
int yy1 = destPointY + thisScaledRadiusY;
if (yy1 > y0 + height)
yy1 = y0 + height;
// For each row of the contribution circle, // For each row of the contribution circle,
for (int yy = yy0; yy < yy1; yy++) { 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 // Set up bounds so we only loop over what we need to
int thisScaledRadiusX = context.kernelBoundsX[kz][ky]; int thisScaledRadiusX = context.kernelBoundsX[kz][ky];
int xx0 = destPointX - thisScaledRadiusX; int xx0 = destPointX - thisScaledRadiusX; if (xx0 < x0Skipped) xx0 = x0Skipped;
if (xx0 < x0Skipped) int xx1 = destPointX + thisScaledRadiusX; if (xx1 > x0 + width) xx1 = x0 + width;
xx0 = x0Skipped;
int xx1 = destPointX + thisScaledRadiusX;
if (xx1 > x0 + width)
xx1 = x0 + width;
// For each point on that row // For each point on that row
for (int xx = xx0; xx < xx1; xx++) { for (int xx = xx0; xx < xx1; xx++) {
int dx = xx - destPointX; int dx = xx - destPointX;
int kx = dx + scaledRadiusX; int kx = dx + scaledRadiusX;
// gOff accounts for our choice to offset the // gOff accounts for our choice to offset the pre-generated kernel by (0.5, 0.5, 0.5) to avoid the zero center.
// pre-generated kernel by (0.5, 0.5, 0.5) to avoid the
// zero center.
double extrapolation = gx * dx + gy * dy + gz * dz + gOff; double extrapolation = gx * dx + gy * dy + gz * dz + gOff;
buffer[zz - z0][yy - y0][xx - x0] += kernel[kz][ky][kx] * extrapolation; 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++) { for (int i = 0; i < NEIGHBOR_MAP_3D[0].length; i++) {
int l = point.lattice; int l = point.lattice;
AreaGenLatticePoint3D neighbor = new AreaGenLatticePoint3D(context, AreaGenLatticePoint3D neighbor = new AreaGenLatticePoint3D(context,
point.xsv + NEIGHBOR_MAP_3D[l][i][0], point.ysv + NEIGHBOR_MAP_3D[l][i][1], 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.zsv + NEIGHBOR_MAP_3D[l][i][2], 1 ^ l);
// If it's in range of the buffer region and not seen before // If it's in range of the buffer region and not seen before
if (neighbor.destPointX + scaledRadiusX >= x0Skipped if (neighbor.destPointX + scaledRadiusX >= x0Skipped && neighbor.destPointX - scaledRadiusX <= x0 + width - 1
&& neighbor.destPointX - scaledRadiusX <= x0 + width - 1 && neighbor.destPointY + scaledRadiusY >= y0Skipped && neighbor.destPointY - scaledRadiusY <= y0 + height - 1
&& neighbor.destPointY + scaledRadiusY >= y0Skipped && neighbor.destPointZ + scaledRadiusZ >= z0Skipped && neighbor.destPointZ - scaledRadiusZ <= z0 + depth - 1
&& neighbor.destPointY - scaledRadiusY <= y0 + height - 1 && !seen.contains(neighbor)) {
&& 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 // Add it to the queue so we can process it at some point
queue.add(neighbor); queue.add(neighbor);
@ -518,35 +475,11 @@ public class OpenSimplex2S {
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
int i1, j1, i2, j2; int i1, j1, i2, j2;
if ((i & 1) == 0) { if ((i & 1) == 0) {
if ((i & 2) == 0) { if ((i & 2) == 0) { i1 = -1; j1 = 0; } else { i1 = 1; j1 = 0; }
i1 = -1; if ((i & 4) == 0) { i2 = 0; j2 = -1; } else { i2 = 0; j2 = 1; }
j1 = 0;
} else { } else {
i1 = 1; if ((i & 2) != 0) { i1 = 2; j1 = 1; } else { i1 = 0; j1 = 1; }
j1 = 0; if ((i & 4) != 0) { i2 = 1; j2 = 2; } else { i2 = 1; j2 = 0; }
}
if ((i & 4) == 0) {
i2 = 0;
j2 = -1;
} else {
i2 = 0;
j2 = 1;
}
} else {
if ((i & 2) != 0) {
i1 = 2;
j1 = 1;
} else {
i1 = 0;
j1 = 1;
}
if ((i & 4) != 0) {
i2 = 1;
j2 = 2;
} else {
i2 = 1;
j2 = 0;
}
} }
LOOKUP_2D[i * 4 + 0] = new LatticePoint2D(0, 0); LOOKUP_2D[i * 4 + 0] = new LatticePoint2D(0, 0);
LOOKUP_2D[i * 4 + 1] = new LatticePoint2D(1, 1); LOOKUP_2D[i * 4 + 1] = new LatticePoint2D(1, 1);
@ -556,15 +489,10 @@ public class OpenSimplex2S {
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
int i1, j1, k1, i2, j2, k2; int i1, j1, k1, i2, j2, k2;
i1 = (i >> 0) & 1; i1 = (i >> 0) & 1; j1 = (i >> 1) & 1; k1 = (i >> 2) & 1;
j1 = (i >> 1) & 1; i2 = i1 ^ 1; j2 = j1 ^ 1; k2 = k1 ^ 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 // The two points within this octant, one from each of the two cubic half-lattices.
// half-lattices.
LatticePoint3D c0 = new LatticePoint3D(i1, j1, k1, 0); LatticePoint3D c0 = new LatticePoint3D(i1, j1, k1, 0);
LatticePoint3D c1 = new LatticePoint3D(i1 + i2, j1 + j2, k1 + k2, 1); LatticePoint3D c1 = new LatticePoint3D(i1 + i2, j1 + j2, k1 + k2, 1);
@ -597,36 +525,27 @@ public class OpenSimplex2S {
c1.nextOnFailure = c1.nextOnSuccess = c2; c1.nextOnFailure = c1.nextOnSuccess = c2;
// If c2 is in range, then we know c3 and c4 are not. // If c2 is in range, then we know c3 and c4 are not.
c2.nextOnFailure = c3; c2.nextOnFailure = c3; c2.nextOnSuccess = c5;
c2.nextOnSuccess = c5; c3.nextOnFailure = c4; c3.nextOnSuccess = c4;
c3.nextOnFailure = c4;
c3.nextOnSuccess = c4;
// If c4 is in range, then we know c5 is not. // If c4 is in range, then we know c5 is not.
c4.nextOnFailure = c5; c4.nextOnFailure = c5; c4.nextOnSuccess = c6;
c4.nextOnSuccess = c6;
c5.nextOnFailure = c5.nextOnSuccess = c6; c5.nextOnFailure = c5.nextOnSuccess = c6;
// If c6 is in range, then we know c7 and c8 are not. // If c6 is in range, then we know c7 and c8 are not.
c6.nextOnFailure = c7; c6.nextOnFailure = c7; c6.nextOnSuccess = c9;
c6.nextOnSuccess = c9; c7.nextOnFailure = c8; c7.nextOnSuccess = c8;
c7.nextOnFailure = c8;
c7.nextOnSuccess = c8;
// If c8 is in range, then we know c9 is not. // If c8 is in range, then we know c9 is not.
c8.nextOnFailure = c9; c8.nextOnFailure = c9; c8.nextOnSuccess = cA;
c8.nextOnSuccess = cA;
c9.nextOnFailure = c9.nextOnSuccess = cA; c9.nextOnFailure = c9.nextOnSuccess = cA;
// If cA is in range, then we know cB and cC are not. // If cA is in range, then we know cB and cC are not.
cA.nextOnFailure = cB; cA.nextOnFailure = cB; cA.nextOnSuccess = cD;
cA.nextOnSuccess = cD; cB.nextOnFailure = cC; cB.nextOnSuccess = cC;
cB.nextOnFailure = cC;
cB.nextOnSuccess = cC;
// If cC is in range, then we know cD is not. // If cC is in range, then we know cD is not.
cC.nextOnFailure = cD; cC.nextOnFailure = cD; cC.nextOnSuccess = null;
cC.nextOnSuccess = null;
cD.nextOnFailure = cD.nextOnSuccess = null; cD.nextOnFailure = cD.nextOnSuccess = null;
LOOKUP_3D[i] = c0; LOOKUP_3D[i] = c0;
@ -635,24 +554,28 @@ public class OpenSimplex2S {
} }
// Hexagon surrounding each vertex. // 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. // Cube surrounding each vertex.
// Alternates between half-lattices. // Alternates between half-lattices.
private static final int[][][] NEIGHBOR_MAP_3D = { 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, -1024 }, { -1025, -1024, 1024 }, { -1024, -1025, -1024 }, { -1025, -1025, -1024 }, { 1024, 1024, 1025 }, { 1025, 1024, 1025 }, { 1024, 1025, 1025 }, { 1025, 1025, 1025 }
{ -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 { private static class LatticePoint2D {
int xsv, ysv; int xsv, ysv;
double dx, dy; double dx, dy;
public LatticePoint2D(int xsv, int ysv) { public LatticePoint2D(int xsv, int ysv) {
this.xsv = xsv; this.xsv = xsv; this.ysv = ysv;
this.ysv = ysv;
double ssv = (xsv + ysv) * -0.211324865405187; double ssv = (xsv + ysv) * -0.211324865405187;
this.dx = -xsv - ssv; this.dx = -xsv - ssv;
this.dy = -ysv - ssv; this.dy = -ysv - ssv;
@ -663,42 +586,29 @@ public class OpenSimplex2S {
public double dxr, dyr, dzr; public double dxr, dyr, dzr;
public int xrv, yrv, zrv; public int xrv, yrv, zrv;
LatticePoint3D nextOnFailure, nextOnSuccess; LatticePoint3D nextOnFailure, nextOnSuccess;
public LatticePoint3D(int xrv, int yrv, int zrv, int lattice) { public LatticePoint3D(int xrv, int yrv, int zrv, int lattice) {
this.dxr = -xrv + lattice * 0.5; this.dxr = -xrv + lattice * 0.5; this.dyr = -yrv + lattice * 0.5; this.dzr = -zrv + lattice * 0.5;
this.dyr = -yrv + lattice * 0.5; this.xrv = xrv + lattice * 1024; this.yrv = yrv + lattice * 1024; this.zrv = zrv + lattice * 1024;
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 { private static class AreaGenLatticePoint2D {
int xsv, ysv; int xsv, ysv;
int destPointX, destPointY; int destPointX, destPointY;
public AreaGenLatticePoint2D(GenerateContext2D context, int xsv, int ysv) { public AreaGenLatticePoint2D(GenerateContext2D context, int xsv, int ysv) {
this.xsv = xsv; this.xsv = xsv; this.ysv = ysv;
this.ysv = ysv;
// Matrix multiplication for inverse rotation. Simplex skew //Matrix multiplication for inverse rotation. Simplex skew transforms have always been shorthand for matrices.
// transforms have always been shorthand for matrices. this.destPointX = (int)Math.ceil((context.orientation.t00 * xsv + context.orientation.t01 * ysv) * context.xFrequencyInverse);
this.destPointX = (int) Math this.destPointY = (int)Math.ceil((context.orientation.t10 * xsv + context.orientation.t11 * ysv) * context.yFrequencyInverse);
.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 @Override
public int hashCode() { public int hashCode() {
return xsv * 7841 + ysv; return xsv * 7841 + ysv;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (!(obj instanceof AreaGenLatticePoint2D)) if (!(obj instanceof AreaGenLatticePoint2D)) return false;
return false;
AreaGenLatticePoint2D other = (AreaGenLatticePoint2D) obj; AreaGenLatticePoint2D other = (AreaGenLatticePoint2D) obj;
return (other.xsv == this.xsv && other.ysv == this.ysv); return (other.xsv == this.xsv && other.ysv == this.ysv);
} }
@ -707,20 +617,15 @@ public class OpenSimplex2S {
private static class AreaGenLatticePoint3D { private static class AreaGenLatticePoint3D {
int xsv, ysv, zsv, lattice; int xsv, ysv, zsv, lattice;
int destPointX, destPointY, destPointZ; int destPointX, destPointY, destPointZ;
public AreaGenLatticePoint3D(GenerateContext3D context, int xsv, int ysv, int zsv, int lattice) { public AreaGenLatticePoint3D(GenerateContext3D context, int xsv, int ysv, int zsv, int lattice) {
this.xsv = xsv; this.xsv = xsv; this.ysv = ysv; this.zsv = zsv; this.lattice = lattice;
this.ysv = ysv;
this.zsv = zsv;
this.lattice = lattice;
double xr = (xsv - lattice * 1024.5); double xr = (xsv - lattice * 1024.5);
double yr = (ysv - lattice * 1024.5); double yr = (ysv - lattice * 1024.5);
double zr = (zsv - lattice * 1024.5); double zr = (zsv - lattice * 1024.5);
// Quaternion multiplication for inverse rotation. // Quaternion multiplication for inverse rotation.
// https://blog.molecular-matters.com/2013/05/24/a-faster-quaternion-vector-multiplication/ // 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, double qx = -context.orientation.qx, qy = -context.orientation.qy, qz = -context.orientation.qz, qw = context.orientation.qw;
qw = context.orientation.qw;
double tx = 2 * (qy * zr - qz * yr); double tx = 2 * (qy * zr - qz * yr);
double ty = 2 * (qz * xr - qx * zr); double ty = 2 * (qz * xr - qx * zr);
double tz = 2 * (qx * yr - qy * xr); double tz = 2 * (qx * yr - qy * xr);
@ -732,19 +637,15 @@ public class OpenSimplex2S {
this.destPointY = (int)Math.ceil(yrr * context.yFrequencyInverse); this.destPointY = (int)Math.ceil(yrr * context.yFrequencyInverse);
this.destPointZ = (int)Math.ceil(zrr * context.zFrequencyInverse); this.destPointZ = (int)Math.ceil(zrr * context.zFrequencyInverse);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return xsv * 2122193 + ysv * 2053 + zsv * 2 + lattice; return xsv * 2122193 + ysv * 2053 + zsv * 2 + lattice;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (!(obj instanceof AreaGenLatticePoint3D)) if (!(obj instanceof AreaGenLatticePoint3D)) return false;
return false;
AreaGenLatticePoint3D other = (AreaGenLatticePoint3D) obj; AreaGenLatticePoint3D other = (AreaGenLatticePoint3D) obj;
return (other.xsv == this.xsv && other.ysv == this.ysv && other.zsv == this.zsv return (other.xsv == this.xsv && other.ysv == this.ysv && other.zsv == this.zsv && other.lattice == this.lattice);
&& other.lattice == this.lattice);
} }
} }
@ -760,8 +661,7 @@ public class OpenSimplex2S {
int[] kernelBounds; int[] kernelBounds;
LatticeOrientation2D orientation; LatticeOrientation2D orientation;
public GenerateContext2D(LatticeOrientation2D orientation, double xFrequency, double yFrequency, public GenerateContext2D(LatticeOrientation2D orientation, double xFrequency, double yFrequency, double amplitude) {
double amplitude) {
// These will be used by every call to generate // These will be used by every call to generate
this.orientation = orientation; this.orientation = orientation;
@ -783,9 +683,10 @@ public class OpenSimplex2S {
for (int yy = 0; yy < scaledRadiusY * 2; yy++) { for (int yy = 0; yy < scaledRadiusY * 2; yy++) {
// Pre-generate boundary of circle // Pre-generate boundary of circle
kernelBounds[yy] = (int) Math.ceil(Math.sqrt( kernelBounds[yy] = (int)Math.ceil(
1.0 - (yy + 0.5 - scaledRadiusY) * (yy + 0.5 - scaledRadiusY) / (scaledRadiusY * scaledRadiusY)) Math.sqrt(1.0
* scaledRadiusX); - (yy + 0.5 - scaledRadiusY) * (yy + 0.5 - scaledRadiusY) / (scaledRadiusY * scaledRadiusY)
) * scaledRadiusX);
if (yy < scaledRadiusY) { if (yy < scaledRadiusY) {
kernel[yy] = new double[scaledRadiusX * 2]; kernel[yy] = new double[scaledRadiusX * 2];
@ -823,8 +724,7 @@ public class OpenSimplex2S {
int[][] kernelBoundsX; int[][] kernelBoundsX;
LatticeOrientation3D orientation; LatticeOrientation3D orientation;
public GenerateContext3D(LatticeOrientation3D orientation, double xFrequency, double yFrequency, public GenerateContext3D(LatticeOrientation3D orientation, double xFrequency, double yFrequency, double zFrequency, double amplitude) {
double zFrequency, double amplitude) {
// These will be used by every call to generate // These will be used by every call to generate
this.orientation = orientation; this.orientation = orientation;
@ -851,9 +751,9 @@ public class OpenSimplex2S {
for (int zz = 0; zz < scaledRadiusZ * 2; zz++) { for (int zz = 0; zz < scaledRadiusZ * 2; zz++) {
// Pre-generate boundary of sphere // Pre-generate boundary of sphere
kernelBoundsY[zz] = (int) Math.ceil(Math.sqrt( kernelBoundsY[zz] = (int)Math.ceil(
1.0 - (zz + 0.5 - scaledRadiusZ) * (zz + 0.5 - scaledRadiusZ) / (scaledRadiusZ * scaledRadiusZ)) Math.sqrt(1.0 - (zz + 0.5 - scaledRadiusZ) * (zz + 0.5 - scaledRadiusZ)
* scaledRadiusY); / (scaledRadiusZ * scaledRadiusZ)) * scaledRadiusY);
if (zz < scaledRadiusZ) { if (zz < scaledRadiusZ) {
kernel[zz] = new double[scaledRadiusY * 2][]; kernel[zz] = new double[scaledRadiusY * 2][];
@ -867,12 +767,11 @@ public class OpenSimplex2S {
for (int yy = 0; yy < scaledRadiusY * 2; yy++) { for (int yy = 0; yy < scaledRadiusY * 2; yy++) {
// Pre-generate boundary of sphere // Pre-generate boundary of sphere
kernelBoundsX[zz][yy] = (int) Math.ceil(Math.sqrt(1.0 kernelBoundsX[zz][yy] = (int)Math.ceil(
- (yy + 0.5 - scaledRadiusY) * (yy + 0.5 - scaledRadiusY) Math.sqrt(1.0
/ (scaledRadiusY * scaledRadiusY) - (yy + 0.5 - scaledRadiusY) * (yy + 0.5 - scaledRadiusY) / (scaledRadiusY * scaledRadiusY)
- (zz + 0.5 - scaledRadiusZ) * (zz + 0.5 - scaledRadiusZ) - (zz + 0.5 - scaledRadiusZ) * (zz + 0.5 - scaledRadiusZ) / (scaledRadiusZ * scaledRadiusZ)
/ (scaledRadiusZ * scaledRadiusZ)) ) * scaledRadiusX);
* scaledRadiusX);
if (yy < scaledRadiusY) { if (yy < scaledRadiusY) {
kernel[zz][yy] = new double[scaledRadiusX * 2]; kernel[zz][yy] = new double[scaledRadiusX * 2];
@ -891,8 +790,7 @@ public class OpenSimplex2S {
} }
} }
} else } else kernel[zz][yy] = kernel[zz][2 * scaledRadiusY - yy - 1];
kernel[zz][yy] = kernel[zz][2 * scaledRadiusY - yy - 1];
} }
} }
} }
@ -900,50 +798,40 @@ public class OpenSimplex2S {
} }
public enum LatticeOrientation2D { public enum LatticeOrientation2D {
// Simplex skew transforms have always been shorthand for the matrices // Simplex skew transforms have always been shorthand for the matrices they represent.
// they represent. // But when we bake the rotation into the skew transform, we need to use the general form.
// But when we bake the rotation into the skew transform, we need to use Standard(GRADIENTS_2D,
// the general form. 1.366025403784439, 0.366025403784439, 0.366025403784439, 1.366025403784439,
Standard(GRADIENTS_2D, 1.366025403784439, 0.366025403784439, 0.366025403784439, 1.366025403784439, 0.788675134594813, -0.211324865405187, -0.211324865405187, 0.788675134594813),
0.788675134594813, -0.211324865405187, -0.211324865405187, XBeforeY(GRADIENTS_2D_X_BEFORE_Y,
0.788675134594813), XBeforeY(GRADIENTS_2D_X_BEFORE_Y, 0.7071067811865476, 1.224744871380249, 0.7071067811865476, 1.224744871380249, -0.7071067811865476, 1.224744871380249,
-0.7071067811865476, 1.224744871380249, 0.7071067811865476, -0.7071067811865476, 0.7071067811865476, -0.7071067811865476, 0.40824829046764305, 0.40824829046764305);
0.40824829046764305, 0.40824829046764305);
Grad2[] gradients; Grad2[] gradients;
double s00, s01, s10, s11; double s00, s01, s10, s11;
double t00, t01, t10, t11; double t00, t01, t10, t11;
private LatticeOrientation2D(Grad2[] gradients, double s00, double s01, double s10, double s11, double t00, private LatticeOrientation2D(Grad2[] gradients,
double t01, double t10, double t11) { double s00, double s01, double s10, double s11,
double t00, double t01, double t10, double t11) {
this.gradients = gradients; this.gradients = gradients;
this.s00 = s00; this.s00 = s00; this.s01 = s01; this.s10 = s10; this.s11 = s11;
this.s01 = s01; this.t00 = t00; this.t01 = t01; this.t10 = t10; this.t11 = t11;
this.s10 = s10;
this.s11 = s11;
this.t00 = t00;
this.t01 = t01;
this.t10 = t10;
this.t11 = t11;
} }
} }
public enum LatticeOrientation3D { public enum LatticeOrientation3D {
// Quaternions for 3D. Could use matrices, but I already wrote this code // Quaternions for 3D. Could use matrices, but I already wrote this code before I moved them into here.
// before I moved them into here. Classic(GRADIENTS_3D_CLASSIC, 0.577350269189626, 0.577350269189626, 0.577350269189626, 0),
Classic(GRADIENTS_3D_CLASSIC, 0.577350269189626, 0.577350269189626, 0.577350269189626, 0), XYBeforeZ( XYBeforeZ(GRADIENTS_3D_XY_BEFORE_Z, 0.3250575836718682, -0.3250575836718682, 0, 0.8880738339771154),
GRADIENTS_3D_XY_BEFORE_Z, 0.3250575836718682, -0.3250575836718682, 0, 0.8880738339771154), XZBeforeY( XZBeforeY(GRADIENTS_3D_XZ_BEFORE_Y, -0.3250575836718682, 0, 0.3250575836718682, 0.8880738339771154);
GRADIENTS_3D_XZ_BEFORE_Y, -0.3250575836718682, 0, 0.3250575836718682, 0.8880738339771154);
Grad3[] gradients; Grad3[] gradients;
double qx, qy, qz, qw; double qx, qy, qz, qw;
private LatticeOrientation3D(Grad3[] gradients, double qx, double qy, double qz, double qw) { private LatticeOrientation3D(Grad3[] gradients, double qx, double qy, double qz, double qw) {
this.gradients = gradients; this.gradients = gradients;
this.qx = qx; this.qx = qx; this.qy = qy; this.qz = qz; this.qw = qw;
this.qy = qy;
this.qz = qz;
this.qw = qw;
} }
} }
@ -953,20 +841,15 @@ public class OpenSimplex2S {
public static class Grad2 { public static class Grad2 {
double dx, dy; double dx, dy;
public Grad2(double dx, double dy) { public Grad2(double dx, double dy) {
this.dx = dx; this.dx = dx; this.dy = dy;
this.dy = dy;
} }
} }
public static class Grad3 { public static class Grad3 {
double dx, dy, dz; double dx, dy, dz;
public Grad3(double dx, double dy, double dz) { public Grad3(double dx, double dy, double dz) {
this.dx = dx; this.dx = dx; this.dy = dy; this.dz = dz;
this.dy = dy;
this.dz = dz;
} }
} }
@ -978,23 +861,35 @@ public class OpenSimplex2S {
GRADIENTS_2D = new Grad2[PSIZE]; GRADIENTS_2D = new Grad2[PSIZE];
GRADIENTS_2D_X_BEFORE_Y = new Grad2[PSIZE]; GRADIENTS_2D_X_BEFORE_Y = new Grad2[PSIZE];
Grad2[] grad2 = { new Grad2(0.130526192220052, 0.99144486137381), Grad2[] grad2 = {
new Grad2(0.38268343236509, 0.923879532511287), new Grad2(0.608761429008721, 0.793353340291235), new Grad2( 0.130526192220052, 0.99144486137381),
new Grad2(0.793353340291235, 0.608761429008721), new Grad2(0.923879532511287, 0.38268343236509), new Grad2( 0.38268343236509, 0.923879532511287),
new Grad2(0.99144486137381, 0.130526192220051), new Grad2(0.99144486137381, -0.130526192220051), new Grad2( 0.608761429008721, 0.793353340291235),
new Grad2(0.923879532511287, -0.38268343236509), new Grad2(0.793353340291235, -0.60876142900872), new Grad2( 0.793353340291235, 0.608761429008721),
new Grad2(0.608761429008721, -0.793353340291235), new Grad2(0.38268343236509, -0.923879532511287), new Grad2( 0.923879532511287, 0.38268343236509),
new Grad2(0.130526192220052, -0.99144486137381), new Grad2(-0.130526192220052, -0.99144486137381), new Grad2( 0.99144486137381, 0.130526192220051),
new Grad2(-0.38268343236509, -0.923879532511287), new Grad2(-0.608761429008721, -0.793353340291235), new Grad2( 0.99144486137381, -0.130526192220051),
new Grad2(-0.793353340291235, -0.608761429008721), new Grad2(-0.923879532511287, -0.38268343236509), new Grad2( 0.923879532511287, -0.38268343236509),
new Grad2(-0.99144486137381, -0.130526192220052), new Grad2(-0.99144486137381, 0.130526192220051), new Grad2( 0.793353340291235, -0.60876142900872),
new Grad2(-0.923879532511287, 0.38268343236509), new Grad2(-0.793353340291235, 0.608761429008721), new Grad2( 0.608761429008721, -0.793353340291235),
new Grad2(-0.608761429008721, 0.793353340291235), new Grad2(-0.38268343236509, 0.923879532511287), new Grad2( 0.38268343236509, -0.923879532511287),
new Grad2(-0.130526192220052, 0.99144486137381) }; 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]; Grad2[] grad2XBeforeY = new Grad2[grad2.length];
for (int i = 0; i < grad2.length; i++) { for (int i = 0; i < grad2.length; i++) {
grad2[i].dx /= N2; grad2[i].dx /= N2; grad2[i].dy /= N2;
grad2[i].dy /= N2;
// Unrotated gradients for XBeforeY 2D // Unrotated gradients for XBeforeY 2D
double xx = grad2[i].dx * 0.7071067811865476; double xx = grad2[i].dx * 0.7071067811865476;
@ -1010,43 +905,61 @@ public class OpenSimplex2S {
GRADIENTS_3D_CLASSIC = new Grad3[PSIZE]; GRADIENTS_3D_CLASSIC = new Grad3[PSIZE];
GRADIENTS_3D_XY_BEFORE_Z = new Grad3[PSIZE]; GRADIENTS_3D_XY_BEFORE_Z = new Grad3[PSIZE];
GRADIENTS_3D_XZ_BEFORE_Y = 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(-2.22474487139, -2.22474487139, 1.0),
new Grad3(-3.0862664687972017, -1.1721513422464978, 0.0), new Grad3(-3.0862664687972017, -1.1721513422464978, 0.0),
new Grad3(-1.1721513422464978, -3.0862664687972017, 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(-1.1721513422464978, 0.0, -3.0862664687972017),
new Grad3(-3.0862664687972017, 0.0, -1.1721513422464978), 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(-3.0862664687972017, 0.0, 1.1721513422464978),
new Grad3(-1.1721513422464978, 0.0, 3.0862664687972017), new Grad3(-2.22474487139, 2.22474487139, -1.0), new Grad3(-1.1721513422464978, 0.0, 3.0862664687972017),
new Grad3(-2.22474487139, 2.22474487139, 1.0), new Grad3(-1.1721513422464978, 3.0862664687972017, 0.0), 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(-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, -3.0862664687972017, -1.1721513422464978),
new Grad3( 0.0, -1.1721513422464978, -3.0862664687972017), 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, -1.1721513422464978, 3.0862664687972017),
new Grad3(0.0, -3.0862664687972017, 1.1721513422464978), new Grad3(-1.0, 2.22474487139, -2.22474487139), new Grad3( 0.0, -3.0862664687972017, 1.1721513422464978),
new Grad3(1.0, 2.22474487139, -2.22474487139), new Grad3(0.0, 1.1721513422464978, -3.0862664687972017), new Grad3(-1.0, 2.22474487139, -2.22474487139),
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(1.0, 2.22474487139, 2.22474487139), new Grad3(0.0, 3.0862664687972017, 1.1721513422464978), new Grad3( 0.0, 1.1721513422464978, -3.0862664687972017),
new Grad3(0.0, 1.1721513422464978, 3.0862664687972017), new Grad3(2.22474487139, -2.22474487139, -1.0), new Grad3( 0.0, 3.0862664687972017, -1.1721513422464978),
new Grad3(2.22474487139, -2.22474487139, 1.0), new Grad3(1.1721513422464978, -3.0862664687972017, 0.0), new Grad3(-1.0, 2.22474487139, 2.22474487139),
new Grad3(3.0862664687972017, -1.1721513422464978, 0.0), new Grad3(2.22474487139, -1.0, -2.22474487139), new Grad3( 1.0, 2.22474487139, 2.22474487139),
new Grad3(2.22474487139, 1.0, -2.22474487139), new Grad3(3.0862664687972017, 0.0, -1.1721513422464978), new Grad3( 0.0, 3.0862664687972017, 1.1721513422464978),
new Grad3(1.1721513422464978, 0.0, -3.0862664687972017), new Grad3(2.22474487139, -1.0, 2.22474487139), new Grad3( 0.0, 1.1721513422464978, 3.0862664687972017),
new Grad3(2.22474487139, 1.0, 2.22474487139), new Grad3(1.1721513422464978, 0.0, 3.0862664687972017), new Grad3( 2.22474487139, -2.22474487139, -1.0),
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(2.22474487139, 2.22474487139, 1.0), new Grad3(3.0862664687972017, 1.1721513422464978, 0.0), new Grad3( 1.1721513422464978, -3.0862664687972017, 0.0),
new Grad3(1.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[] grad3Classic = new Grad3[grad3.length];
Grad3[] grad3XYBeforeZ = new Grad3[grad3.length]; Grad3[] grad3XYBeforeZ = new Grad3[grad3.length];
Grad3[] grad3XZBeforeY = new Grad3[grad3.length]; Grad3[] grad3XZBeforeY = new Grad3[grad3.length];
for (int i = 0; i < grad3.length; i++) { for (int i = 0; i < grad3.length; i++) {
grad3[i].dx /= N3; grad3[i].dx /= N3; grad3[i].dy /= N3; grad3[i].dz /= N3;
grad3[i].dy /= N3;
grad3[i].dz /= N3;
double gxr = grad3[i].dx, gyr = grad3[i].dy, gzr = grad3[i].dz; double gxr = grad3[i].dx, gyr = grad3[i].dy, gzr = grad3[i].dz;
// Unrotated gradients for classic 3D // Unrotated gradients for classic 3D

View File

@ -611,7 +611,8 @@ public class ArrayUtil {
int end = offset + length; int end = offset + length;
if (end > arrayLength || offset < 0) if (end > arrayLength || offset < 0)
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Array contains [0; " + arrayLength + "), requested [" + offset + "; " + end + ")"); "Array contains [0; " + arrayLength + "), requested [" + offset + "; " + end + ")"
);
return length; return length;
} }
@ -627,7 +628,8 @@ public class ArrayUtil {
if (end > arrayLength || start < 0) if (end > arrayLength || start < 0)
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Array contains [0; " + arrayLength + "), requested [" + start + "; " + end + ")"); "Array contains [0; " + arrayLength + "), requested [" + start + "; " + end + ")"
);
return end; return end;
} }

View File

@ -30,8 +30,18 @@ public class PrimitiveUtil {
private static final Map<Class<?>, Object> PRIMITIVE_TO_NULL = new HashMap<>(); private static final Map<Class<?>, Object> PRIMITIVE_TO_NULL = new HashMap<>();
static { static {
for (Class<?> boxed : new Class<?>[] { Boolean.class, Byte.class, Short.class, Character.class, Integer.class, for (
Long.class, Float.class, Double.class }) { Class<?> boxed : new Class<?>[] {
Boolean.class,
Byte.class,
Short.class,
Character.class,
Integer.class,
Long.class,
Float.class,
Double.class
}
) {
try { try {
PRIMITIVE_TO_BOXED.put((Class<?>) boxed.getField("TYPE").get(null), boxed); PRIMITIVE_TO_BOXED.put((Class<?>) boxed.getField("TYPE").get(null), boxed);
} catch (Exception e) { } catch (Exception e) {

View File

@ -40,7 +40,8 @@ import java.util.stream.Stream;
/** /**
* Contains static methods to create {@link Stream Streams} that synchronize * 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"> * "https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#StreamOps">
* terminal operations</a> on a given monitor. * 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"> * "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 * terminal operations</a> acquire the provided monitor's lock before
* execution. Intermediate operations return streams that are also * execution. Intermediate operations
* synchronized on the same object. The created stream will behave * return streams that are also synchronized on the same object. The created
* identically to the provided stream in all other aspects. Use this to * stream will behave identically
* synchronize access to stream's source. * to the provided stream in all other aspects. Use this to synchronize
* access to stream's source.
* <p> * <p>
* <i>The returned {@code Stream}'s {@link Stream#iterator() iterator()} and * <i>The returned {@code Stream}'s {@link Stream#iterator() iterator()} and
* {@link Stream#spliterator() spliterator()} methods return regular * {@link Stream#spliterator()
* non-synchronized iterators and spliterators respectively</i>. It is the * spliterator()} methods return regular non-synchronized iterators and
* user's responsibility to avoid concurrency issues: * spliterators respectively</i>. It
* is the user's responsibility to avoid concurrency issues:
* *
* <pre> * <pre>
* synchronized (stream.getMonitor()) { * synchronized (stream.getMonitor()) {
@ -1099,17 +1103,14 @@ public class SyncStreams {
* stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException * stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException
* </pre> * </pre>
* *
* @param <T> * @param <T> the class of objects in the Stream
* the class of objects in the Stream * @param stream the stream to wrap.
* @param stream * @param monitor the object that the stream will use for synchronization.
* the stream to wrap. * When {@code null}, the stream
* @param monitor * will synchronize on itself.
* 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 * @return a {@link SyncStream SyncStream&lt;T&gt;} synchronized on
* {@code monitor} and backed by {@code stream}. * {@code monitor} and backed by {@code stream}.
* @throws NullPointerException * @throws NullPointerException if {@code stream == null}.
* if {@code stream == null}.
*/ */
public static <T> SyncStream<T> synchronizedStream(Stream<T> stream, Object monitor) { public static <T> SyncStream<T> synchronizedStream(Stream<T> stream, Object monitor) {
Objects.requireNonNull(stream, "stream cannot be null"); 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"> * "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 * terminal operations</a> acquire the provided monitor's lock before
* execution. Intermediate operations return streams that are also * execution. Intermediate operations
* synchronized on the same object. The created stream will behave * return streams that are also synchronized on the same object. The created
* identically to the provided stream in all other aspects. Use this to * stream will behave identically
* synchronize access to stream's source. * to the provided stream in all other aspects. Use this to synchronize
* access to stream's source.
* <p> * <p>
* <i>The returned {@code IntStream}'s {@link IntStream#iterator() * <i>The returned {@code IntStream}'s {@link IntStream#iterator()
* iterator()} and {@link IntStream#spliterator() spliterator()} methods * iterator()} and
* return regular non-synchronized iterators and spliterators * {@link IntStream#spliterator() spliterator()} methods return regular
* respectively</i>. It is the user's responsibility to avoid concurrency * non-synchronized iterators and
* issues: * spliterators respectively</i>. It is the user's responsibility to avoid
* concurrency issues:
* *
* <pre> * <pre>
* synchronized (stream.getMonitor()) { * synchronized (stream.getMonitor()) {
@ -1148,15 +1152,13 @@ public class SyncStreams {
* stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException * stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException
* </pre> * </pre>
* *
* @param stream * @param stream the stream to wrap.
* the stream to wrap. * @param monitor the object that the stream will use for synchronization.
* @param monitor * When {@code null}, the stream
* the object that the stream will use for synchronization. When * will synchronize on itself.
* {@code null}, the stream will synchronize on itself.
* @return a {@link SyncIntStream} synchronized on {@code monitor} and * @return a {@link SyncIntStream} synchronized on {@code monitor} and
* backed by {@code stream}. * backed by {@code stream}.
* @throws NullPointerException * @throws NullPointerException if {@code stream == null}.
* if {@code stream == null}.
*/ */
public static SyncIntStream synchronizedStream(IntStream stream, Object monitor) { public static SyncIntStream synchronizedStream(IntStream stream, Object monitor) {
Objects.requireNonNull(stream, "stream cannot be null"); 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"> * "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 * terminal operations</a> acquire the provided monitor's lock before
* execution. Intermediate operations return streams that are also * execution. Intermediate operations
* synchronized on the same object. The created stream will behave * return streams that are also synchronized on the same object. The created
* identically to the provided stream in all other aspects. Use this to * stream will behave identically
* synchronize access to stream's source. * to the provided stream in all other aspects. Use this to synchronize
* access to stream's source.
* <p> * <p>
* <i>The returned {@code LongStream}'s {@link LongStream#iterator() * <i>The returned {@code LongStream}'s {@link LongStream#iterator()
* iterator()} and {@link LongStream#spliterator() spliterator()} methods * iterator()} and
* return regular non-synchronized iterators and spliterators * {@link LongStream#spliterator() spliterator()} methods return regular
* respectively</i>. It is the user's responsibility to avoid concurrency * non-synchronized iterators and
* issues: * spliterators respectively</i>. It is the user's responsibility to avoid
* concurrency issues:
* *
* <pre> * <pre>
* synchronized (stream.getMonitor()) { * synchronized (stream.getMonitor()) {
@ -1195,15 +1200,13 @@ public class SyncStreams {
* stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException * stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException
* </pre> * </pre>
* *
* @param stream * @param stream the stream to wrap.
* the stream to wrap. * @param monitor the object that the stream will use for synchronization.
* @param monitor * When {@code null}, the stream
* the object that the stream will use for synchronization. When * will synchronize on itself.
* {@code null}, the stream will synchronize on itself.
* @return a {@link SyncLongStream} synchronized on {@code monitor} and * @return a {@link SyncLongStream} synchronized on {@code monitor} and
* backed by {@code stream}. * backed by {@code stream}.
* @throws NullPointerException * @throws NullPointerException if {@code stream == null}.
* if {@code stream == null}.
*/ */
public static SyncLongStream synchronizedStream(LongStream stream, Object monitor) { public static SyncLongStream synchronizedStream(LongStream stream, Object monitor) {
Objects.requireNonNull(stream, "stream cannot be null"); 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"> * "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 * terminal operations</a> acquire the provided monitor's lock before
* execution. Intermediate operations return streams that are also * execution. Intermediate operations
* synchronized on the same object. The created stream will behave * return streams that are also synchronized on the same object. The created
* identically to the provided stream in all other aspects. Use this to * stream will behave identically
* synchronize access to stream's source. * to the provided stream in all other aspects. Use this to synchronize
* access to stream's source.
* <p> * <p>
* <i>The returned {@code DoubleStream}'s {@link DoubleStream#iterator() * <i>The returned {@code DoubleStream}'s {@link DoubleStream#iterator()
* iterator()} and {@link DoubleStream#spliterator() spliterator()} methods * iterator()} and
* return regular non-synchronized iterators and spliterators * {@link DoubleStream#spliterator() spliterator()} methods return regular
* respectively</i>. It is the user's responsibility to avoid concurrency * non-synchronized iterators and
* issues: * spliterators respectively</i>. It is the user's responsibility to avoid
* concurrency issues:
* *
* <pre> * <pre>
* synchronized (stream.getMonitor()) { * synchronized (stream.getMonitor()) {
@ -1242,15 +1248,13 @@ public class SyncStreams {
* stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException * stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException
* </pre> * </pre>
* *
* @param stream * @param stream the stream to wrap.
* the stream to wrap. * @param monitor the object that the stream will use for synchronization.
* @param monitor * When {@code null}, the stream
* the object that the stream will use for synchronization. When * will synchronize on itself.
* {@code null}, the stream will synchronize on itself.
* @return a {@link SyncDoubleStream} synchronized on {@code monitor} and * @return a {@link SyncDoubleStream} synchronized on {@code monitor} and
* backed by {@code stream}. * backed by {@code stream}.
* @throws NullPointerException * @throws NullPointerException if {@code stream == null}.
* if {@code stream == null}.
*/ */
public static SyncDoubleStream synchronizedStream(DoubleStream stream, Object monitor) { public static SyncDoubleStream synchronizedStream(DoubleStream stream, Object monitor) {
Objects.requireNonNull(stream, "stream cannot be null"); 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(), public static final Escaper JAVA = new Escaper(
true, true); '\\',
'u',
"tbnrf'\"".toCharArray(),
"\t\b\n\r\f\'\"".toCharArray(),
true,
true
);
private final char escapeChar; private final char escapeChar;
private final char unicodeEscapeChar; private final char unicodeEscapeChar;
@ -114,8 +120,14 @@ public class Escaper {
private final boolean preferUnicode; private final boolean preferUnicode;
private final boolean strict; private final boolean strict;
protected Escaper(char escapeChar, char unicodeEscapeChar, char[] safes, char[] unsafes, boolean preferUnicode, protected Escaper(
boolean strict) { char escapeChar,
char unicodeEscapeChar,
char[] safes,
char[] unsafes,
boolean preferUnicode,
boolean strict
) {
this.escapeChar = escapeChar; this.escapeChar = escapeChar;
this.unicodeEscapeChar = unicodeEscapeChar; this.unicodeEscapeChar = unicodeEscapeChar;
this.safes = safes; this.safes = safes;
@ -140,7 +152,8 @@ public class Escaper {
for (char c : unsafes) { for (char c : unsafes) {
if (c == escapeChar) if (c == escapeChar)
throw new IllegalArgumentException( 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) if (c == unicodeEscapeChar)
throw new IllegalArgumentException("Unsafe characters contain Unicode escape chatacter"); throw new IllegalArgumentException("Unsafe characters contain Unicode escape chatacter");
} }
@ -160,7 +173,11 @@ public class Escaper {
end = Integer.MAX_VALUE; end = Integer.MAX_VALUE;
else else
end = src.getPosition() + length; 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); escape(src.consume(), output);
} }
@ -208,7 +225,11 @@ public class Escaper {
int result = 0; 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()); result += getEscapedLength(src.consume());
} }
@ -236,7 +257,11 @@ public class Escaper {
end = Integer.MAX_VALUE; end = Integer.MAX_VALUE;
else else
end = src.getPosition() + length; 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)); output.accept(unescapeOneSequence(src));
} }
} }
@ -257,8 +282,10 @@ public class Escaper {
if (src.current() == unicodeEscapeChar) { if (src.current() == unicodeEscapeChar) {
src.next(); src.next();
return (char) (hexValue(src.consume()) << (4 * 3) | hexValue(src.consume()) << (4 * 2) return (char) (hexValue(src.consume()) << (4 * 3) |
| hexValue(src.consume()) << (4 * 1) | hexValue(src.consume()) << (4 * 0)); hexValue(src.consume()) << (4 * 2) |
hexValue(src.consume()) << (4 * 1) |
hexValue(src.consume()) << (4 * 0));
} }
int index = ArrayUtil.firstIndexOf(safes, src.current()); int index = ArrayUtil.firstIndexOf(safes, src.current());
@ -288,7 +315,11 @@ public class Escaper {
int result = 0; 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); skipOneSequence(src);
result++; result++;
} }
@ -297,7 +328,11 @@ public class Escaper {
} }
public void skipOneSequence(CharReader src) { public void skipOneSequence(CharReader src) {
if (src.current() == escapeChar && src.next() == unicodeEscapeChar) { if (
src.current() == escapeChar
&&
src.next() == unicodeEscapeChar
) {
src.advance(4); src.advance(4);
} }
src.next(); src.next();

View File

@ -41,8 +41,13 @@ public class StringUtil {
private static final String EMPTY_PLACEHOLDER = "[empty]"; private static final String EMPTY_PLACEHOLDER = "[empty]";
private static final String DEFAULT_SEPARATOR = "; "; private static final String DEFAULT_SEPARATOR = "; ";
public static <T> String arrayToString(T[] array, String separator, String empty, String nullPlaceholder, public static <T> String arrayToString(
String nullArray) { T[] array,
String separator,
String empty,
String nullPlaceholder,
String nullArray
) {
if (separator == null) { if (separator == null) {
throw new IllegalArgumentException(new NullPointerException()); throw new IllegalArgumentException(new NullPointerException());
@ -74,8 +79,13 @@ public class StringUtil {
return arrayToString(array, DEFAULT_SEPARATOR); return arrayToString(array, DEFAULT_SEPARATOR);
} }
public static String iteratorToString(Iterator<?> iterator, String separator, String empty, String nullPlaceholder, public static String iteratorToString(
String nullIterator) { Iterator<?> iterator,
String separator,
String empty,
String nullPlaceholder,
String nullIterator
) {
if (separator == null) { if (separator == null) {
throw new IllegalArgumentException(new NullPointerException()); throw new IllegalArgumentException(new NullPointerException());
@ -109,8 +119,13 @@ public class StringUtil {
return iteratorToString(iterator, DEFAULT_SEPARATOR); return iteratorToString(iterator, DEFAULT_SEPARATOR);
} }
public static String iterableToString(Iterable<?> iterable, String separator, String empty, String nullPlaceholder, public static String iterableToString(
String nullIterable) { Iterable<?> iterable,
String separator,
String empty,
String nullPlaceholder,
String nullIterable
) {
if (separator == null) { if (separator == null) {
throw new IllegalArgumentException(new NullPointerException()); throw new IllegalArgumentException(new NullPointerException());
@ -131,8 +146,14 @@ public class StringUtil {
return iterableToString(iterable, DEFAULT_SEPARATOR); return iterableToString(iterable, DEFAULT_SEPARATOR);
} }
public static <T> String supplierToString(IntFunction<T> supplier, int length, String separator, String empty, public static <T> String supplierToString(
String nullPlaceholder, String nullSupplier) { IntFunction<T> supplier,
int length,
String separator,
String empty,
String nullPlaceholder,
String nullSupplier
) {
if (separator == null) if (separator == null)
throw new IllegalArgumentException(new NullPointerException()); throw new IllegalArgumentException(new NullPointerException());
@ -142,15 +163,28 @@ public class StringUtil {
return empty; return empty;
if (length > 0) { if (length > 0) {
return supplierToStringExactly(supplier, length, separator, nullPlaceholder); return supplierToStringExactly(
supplier,
length,
separator,
nullPlaceholder
);
} else { } else {
return supplierToStringUntilNull(supplier, separator, empty); return supplierToStringUntilNull(
supplier,
separator,
empty
);
} }
} }
private static <T> String supplierToStringExactly(IntFunction<T> supplier, int length, String separator, private static <T> String supplierToStringExactly(
String nullPlaceholder) { IntFunction<T> supplier,
int length,
String separator,
String nullPlaceholder
) {
T element = supplier.apply(0); T element = supplier.apply(0);
StringBuilder sb = new StringBuilder(element == null ? nullPlaceholder : element.toString()); StringBuilder sb = new StringBuilder(element == null ? nullPlaceholder : element.toString());
@ -164,7 +198,11 @@ public class StringUtil {
return sb.toString(); 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); T element = supplier.apply(0);
if (element == null) { if (element == null) {
@ -328,7 +366,11 @@ public class StringUtil {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
charLoop: for (char c : src.toCharArray()) { charLoop: for (char c : src.toCharArray()) {
if ((resultIndex + 1) < arrayLength && test.test(c)) { if (
(resultIndex + 1) < arrayLength
&&
test.test(c)
) {
result[resultIndex] = resetStringBuilder(sb); result[resultIndex] = resetStringBuilder(sb);
++resultIndex; ++resultIndex;
continue charLoop; continue charLoop;
@ -347,17 +389,17 @@ public class StringUtil {
* index. * index.
* <p> * <p>
* Indices {@code 0} and {@code src.length() - 1} produce {@code str} * Indices {@code 0} and {@code src.length() - 1} produce {@code str}
* excluding the specified character and {@code ""}. * excluding
* the specified character and {@code ""}.
* <p> * <p>
* *
* @param src * @param src the String to split
* the String to split * @param at index to split at
* @param at * @throws IllegalArgumentException if the index is out of bounds for
* index to split at * {@code src}
* @throws IllegalArgumentException
* if the index is out of bounds for {@code src}
* @return an array containing the substrings, in order of encounter in * @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) { public static String[] splitAt(String src, int at) {
Objects.requireNonNull(src, "src"); 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, 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. * indices.
* <p> * <p>
* Indices {@code 0} and {@code src.length() - 1} produce extra zero-length * 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> * <p>
* Examples: * Examples:
* *
@ -393,14 +439,13 @@ public class StringUtil {
* splitAt("a.b", 1, 1, 1) -> {"a", "", "", "b"} * splitAt("a.b", 1, 1, 1) -> {"a", "", "", "b"}
* </pre> * </pre>
* *
* @param src * @param src the String to split
* the String to split * @param at indices to split at, in any order
* @param at * @throws IllegalArgumentException if some index is out of bounds for
* indices to split at, in any order * {@code src}
* @throws IllegalArgumentException
* if some index is out of bounds for {@code src}
* @return an array containing the substrings, in order of encounter in * @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) { public static String[] splitAt(String src, int... at) {
Objects.requireNonNull(src, "src"); Objects.requireNonNull(src, "src");
@ -508,8 +553,10 @@ public class StringUtil {
} }
if (endPos < beginPos) { if (endPos < beginPos) {
throw new IllegalArgumentException("endPos must be greater than or equal to beginPos (endPos=" + endPos throw new IllegalArgumentException(
+ ", beginPos=" + beginPos + ")"); "endPos must be greater than or equal to beginPos (endPos="
+ endPos + ", beginPos=" + beginPos + ")"
);
} }
if (endPos >= Math.min(a.length, b.length)) { 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 * 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> * <p>
* Examples: * Examples:
* <p> * <p>
@ -582,12 +630,10 @@ public class StringUtil {
* </tr> * </tr>
* </table> * </table>
* *
* @param src * @param src - the array to search in.
* - the array to search in. * @param target - the character to search for.
* @param target * @param skip - the amount of <code>target</code> characters to be
* - the character to search for. * skipped.
* @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> * @return The index of the <code>skip+1</code>th <code>target</code>
* character or -1, if none found. * character or -1, if none found.
* @see StringUtil#indexFromEnd(char[], char, int) * @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 * 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>. * <code>src.length - 1</code>.
* <p> * <p>
* Examples: * Examples:
@ -645,15 +692,13 @@ public class StringUtil {
* </tr> * </tr>
* </table> * </table>
* *
* @param src * @param src - the array to search in.
* - the array to search in. * @param target - the character to search for.
* @param target * @param skip - the amount of <code>target</code> characters to be
* - the character to search for. * skipped.
* @param skip
* - the amount of <code>target</code> characters to be skipped.
* @return The index of the <code>skip+1</code>th * @return The index of the <code>skip+1</code>th
* <code>target</code>character from the end of the array or -1, if * <code>target</code>character
* none found. * from the end of the array or -1, if none found.
* @see StringUtil#indexFromBeginning(char[], char, int) * @see StringUtil#indexFromBeginning(char[], char, int)
*/ */
public static int indexFromEnd(char[] src, char target, int skip) { public static int indexFromEnd(char[] src, char target, int skip) {
@ -828,8 +873,12 @@ public class StringUtil {
return result; return result;
} }
private static void buildCombinations(StringBuilder sb, Collection<String> result, Iterable<String>[] parts, private static void buildCombinations(
int index) { StringBuilder sb,
Collection<String> result,
Iterable<String>[] parts,
int index
) {
if (index >= parts.length) { if (index >= parts.length) {
result.add(sb.toString()); result.add(sb.toString());
} else { } else {
@ -855,8 +904,13 @@ public class StringUtil {
return result; return result;
} }
private static void buildCombinations(StringBuilder sb, String[] result, int[] resultIndex, String[][] parts, private static void buildCombinations(
int index) { StringBuilder sb,
String[] result,
int[] resultIndex,
String[][] parts,
int index
) {
if (index >= parts.length) { if (index >= parts.length) {
result[resultIndex[0]++] = sb.toString(); result[resultIndex[0]++] = sb.toString();
} else { } else {
@ -931,7 +985,10 @@ public class StringUtil {
} }
private static char hexDigit(long value, int digit) { 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) { 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 * Current position of this CharReader. The reader maps its input to
* positions starting from 0. Positions that are negative or lower than 0 * positions starting from 0.
* are invalid. {@link #current()} will throw an exception if position is * Positions that are negative or lower than 0 are invalid.
* invalid. * {@link #current()}
* will throw an exception if position is invalid.
*/ */
protected int position = 0; 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. * Acquires next characters and stores them in the array.
* *
* @param buffer * @param buffer the output array
* the output array * @param offset index of the first character
* @param offset * @param length maximum amount of characters to be pulled
* index of the first character
* @param length
* maximum amount of characters to be pulled
* @return the amount of characters actually pulled * @return the amount of characters actually pulled
*/ */
protected int pullChars(char[] buffer, int offset, int length) { 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>, * 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 * @return the amount of characters in the skipped line
*/ */

View File

@ -38,7 +38,8 @@ public class StringCharReader extends AbstractCharReader {
int end = offset + length; int end = offset + length;
if (end > str.length() || offset < 0) if (end > str.length() || offset < 0)
throw new IllegalArgumentException( throw new IllegalArgumentException(
"String contains [0; " + str.length() + "), requested [" + offset + "; " + end + ")"); "String contains [0; " + str.length() + "), requested [" + offset + "; " + end + ")"
);
this.offset = offset; this.offset = offset;
this.length = length; 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( 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> first,
ThrowingBiConsumer<? super T, ? super U, ? extends E> second) { ThrowingBiConsumer<? super T, ? super U, ? extends E> second
return (t, u) -> { ) {
first.accept(t, u);
second.accept(t, u);
};
}
public static <T, U, E extends Exception> ThrowingBiConsumer<T, U, E> concat(BiConsumer<? super T, ? super U> first,
ThrowingBiConsumer<? super T, ? super U, E> second) {
return (t, u) -> { return (t, u) -> {
first.accept(t, u); first.accept(t, u);
second.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( 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) -> { return (t, u) -> {
first.accept(t, u); first.accept(t, u);
second.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, public static <T, E extends Exception> ThrowingConsumer<T, E> concat(
ThrowingConsumer<? super T, ? extends E> second) { ThrowingConsumer<? super T, ? extends E> first,
ThrowingConsumer<? super T, ? extends E> second
) {
return t -> { return t -> {
first.accept(t); first.accept(t);
second.accept(t); second.accept(t);
}; };
} }
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(Consumer<? super T> first, public static <T, E extends Exception> ThrowingConsumer<T, E> concat(
ThrowingConsumer<? super T, ? extends E> second) { Consumer<? super T> first,
ThrowingConsumer<? super T, ? extends E> second
) {
return t -> { return t -> {
first.accept(t); first.accept(t);
second.accept(t); second.accept(t);
}; };
} }
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(ThrowingConsumer<? super T, ? extends E> first, public static <T, E extends Exception> ThrowingConsumer<T, E> concat(
Consumer<? super T> second) { ThrowingConsumer<? super T, ? extends E> first,
Consumer<? super T> second
) {
return t -> { return t -> {
first.accept(t); first.accept(t);
second.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; R apply(T t) throws E;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
default Function<T, R> withHandler(BiConsumer<? super T, ? super E> handler, default Function<T, R> withHandler(
Function<? super T, ? extends R> value) { BiConsumer<? super T, ? super E> handler,
Function<? super T, ? extends R> value
) {
return t -> { return t -> {
try { try {
return apply(t); 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( public static <T, R, I, E extends Exception> ThrowingFunction<T, R, E> compose(
ThrowingFunction<? super T, I, ? extends E> first, ThrowingFunction<? super T, I, ? extends E> first,
ThrowingFunction<? super I, ? extends R, ? extends E> second) { ThrowingFunction<? super I, ? extends R, ? extends E> second
return t -> second.apply(first.apply(t)); ) {
}
public static <T, R, I, E extends Exception> ThrowingFunction<T, R, E> compose(Function<? super T, I> first,
ThrowingFunction<? super I, ? extends R, E> second) {
return t -> second.apply(first.apply(t)); return t -> second.apply(first.apply(t));
} }
public static <T, R, I, E extends Exception> ThrowingFunction<T, R, E> compose( 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)); 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, public static <E extends Exception> ThrowingRunnable<E> concat(
ThrowingRunnable<? extends E> second) { ThrowingRunnable<? extends E> first,
ThrowingRunnable<? extends E> second
) {
return () -> { return () -> {
first.run(); first.run();
second.run(); second.run();

View File

@ -49,8 +49,10 @@ public class RangeIterator<E> implements Iterator<E> {
public E next() { public E next() {
update(); update();
if (nextIndex >= from + amount) { if (nextIndex >= from + amount) {
throw new NoSuchElementException("RangeIterator about to retrieve element " + nextIndex throw new NoSuchElementException(
+ " which exceeds upper boundary " + (from + amount)); "RangeIterator about to retrieve element " + nextIndex
+ " which exceeds upper boundary " + (from + amount)
);
} }
E result = parent.next(); E result = parent.next();

View File

@ -18,18 +18,28 @@
package ru.windcorp.progressia; package ru.windcorp.progressia;
import ru.windcorp.progressia.client.graphics.GUI;
import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.common.util.crash.analyzers.OutOfMemoryAnalyzer; import ru.windcorp.progressia.common.util.crash.analyzers.OutOfMemoryAnalyzer;
import ru.windcorp.progressia.common.util.crash.providers.*; import ru.windcorp.progressia.common.util.crash.providers.*;
import ru.windcorp.progressia.test.LayerTitle;
public class ProgressiaLauncher { public class ProgressiaLauncher {
public static String[] arguments; public static String[] arguments;
private static Proxy proxy;
public static void launch(String[] args, Proxy proxy) { public static void launch(String[] args, Proxy proxy) {
arguments = args.clone(); arguments = args.clone();
setupCrashReports(); setupCrashReports();
proxy.initialize(); proxy.initialize();
ProgressiaLauncher.proxy = proxy;
GUI.addTopLayer(new LayerTitle("Title"));
}
public static Proxy getProxy() {
return proxy;
} }
private static void setupCrashReports() { private static void setupCrashReports() {

View File

@ -69,7 +69,11 @@ public class Client {
return; return;
} }
getCamera().setAnchor(new EntityAnchor(getWorld().getEntityRenderable(entity))); getCamera().setAnchor(
new EntityAnchor(
getWorld().getEntityRenderable(entity)
)
);
} }
} }

View File

@ -30,7 +30,6 @@ import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
import ru.windcorp.progressia.client.localization.Localizer; import ru.windcorp.progressia.client.localization.Localizer;
import ru.windcorp.progressia.common.resource.ResourceManager; import ru.windcorp.progressia.common.resource.ResourceManager;
import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.server.ServerState;
import ru.windcorp.progressia.test.TestContent; import ru.windcorp.progressia.test.TestContent;
import ru.windcorp.progressia.test.TestMusicPlayer; import ru.windcorp.progressia.test.TestMusicPlayer;
@ -38,12 +37,16 @@ public class ClientProxy implements Proxy {
@Override @Override
public void initialize() { public void initialize() {
GraphicsBackend.initialize(); GraphicsBackend.initialize();
try { try {
RenderTaskQueue.waitAndInvoke(FlatRenderProgram::init); RenderTaskQueue.waitAndInvoke(FlatRenderProgram::init);
RenderTaskQueue.waitAndInvoke(WorldRenderProgram::init); RenderTaskQueue.waitAndInvoke(WorldRenderProgram::init);
RenderTaskQueue.waitAndInvoke(() -> Typefaces RenderTaskQueue.waitAndInvoke(
.setDefault(GNUUnifontLoader.load(ResourceManager.getResource("assets/unifont-13.0.03.hex.gz")))); () -> Typefaces
.setDefault(GNUUnifontLoader.load(ResourceManager.getResource("assets/unifont-13.0.03.hex.gz")))
);
} catch (InterruptedException e) { } catch (InterruptedException e) {
throw CrashReports.report(e, "ClientProxy failed"); throw CrashReports.report(e, "ClientProxy failed");
} }
@ -56,10 +59,6 @@ public class ClientProxy implements Proxy {
AudioSystem.initialize(); AudioSystem.initialize();
ServerState.startServer();
ClientState.connectToLocalServer();
TestMusicPlayer.start(); TestMusicPlayer.start();
} }
} }

View File

@ -20,10 +20,13 @@ package ru.windcorp.progressia.client;
import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel; import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel;
import ru.windcorp.progressia.client.graphics.GUI; import ru.windcorp.progressia.client.graphics.GUI;
import ru.windcorp.progressia.client.graphics.Layer;
import ru.windcorp.progressia.client.graphics.world.LayerWorld; import ru.windcorp.progressia.client.graphics.world.LayerWorld;
import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.common.world.DefaultWorldData;
import ru.windcorp.progressia.client.localization.MutableStringLocalized;
import ru.windcorp.progressia.server.ServerState; import ru.windcorp.progressia.server.ServerState;
import ru.windcorp.progressia.test.LayerAbout; import ru.windcorp.progressia.test.LayerAbout;
import ru.windcorp.progressia.test.LayerTestText;
import ru.windcorp.progressia.test.LayerTestUI; import ru.windcorp.progressia.test.LayerTestUI;
import ru.windcorp.progressia.test.TestContent; import ru.windcorp.progressia.test.TestContent;
@ -43,18 +46,48 @@ public class ClientState {
DefaultWorldData world = new DefaultWorldData(); DefaultWorldData world = new DefaultWorldData();
LocalServerCommsChannel channel = new LocalServerCommsChannel(ServerState.getInstance()); LocalServerCommsChannel channel = new LocalServerCommsChannel(
ServerState.getInstance()
);
Client client = new Client(world, channel); Client client = new Client(world, channel);
channel.connect(TestContent.PLAYER_LOGIN); channel.connect(TestContent.PLAYER_LOGIN);
setInstance(client); setInstance(client);
displayLoadingScreen();
GUI.addBottomLayer(new LayerWorld(client)); }
GUI.addTopLayer(new LayerTestUI());
GUI.addTopLayer(new LayerAbout());
private static void displayLoadingScreen() {
GUI.addTopLayer(new LayerTestText("Text", new MutableStringLocalized("LayerText.Load"), layer -> {
Client client = ClientState.getInstance();
// TODO refacetor and remove
if (client != null) {
client.getComms().processPackets();
}
if (client != null && client.getLocalPlayer().hasEntity()) {
GUI.removeLayer(layer);
// TODO refactor, this shouldn't be here
LayerWorld layerWorld = new LayerWorld(client);
LayerTestUI layerUI = new LayerTestUI();
LayerAbout layerAbout = new LayerAbout();
GUI.addBottomLayer(layerWorld);
GUI.addTopLayer(layerUI);
GUI.addTopLayer(layerAbout);
}
}));
}
public static void disconnectFromLocalServer() {
getInstance().getComms().disconnect();
for (Layer layer : GUI.getLayers()) {
GUI.removeLayer(layer);
}
} }
private ClientState() { private ClientState() {

View File

@ -43,7 +43,10 @@ public class AudioManager {
private static Speaker musicSpeaker; private static Speaker musicSpeaker;
public static void initAL() { public static void initAL() {
String defaultDeviceName = alcGetString(0, ALC_DEFAULT_DEVICE_SPECIFIER); String defaultDeviceName = alcGetString(
0,
ALC_DEFAULT_DEVICE_SPECIFIER
);
device = alcOpenDevice(defaultDeviceName); device = alcOpenDevice(defaultDeviceName);
@ -72,7 +75,10 @@ public class AudioManager {
lastSoundIndex = 0; lastSoundIndex = 0;
} }
speaker = soundSpeakers.get(lastSoundIndex); speaker = soundSpeakers.get(lastSoundIndex);
} while (speaker.getState().equals(Speaker.State.PLAYING_LOOP)); } while (
speaker.getState()
.equals(Speaker.State.PLAYING_LOOP)
);
return speaker; return speaker;
} }

View File

@ -29,7 +29,10 @@ public class AudioSystem {
} }
static void loadAudioData() { static void loadAudioData() {
AudioManager.loadSound(ResourceManager.getResource("assets/sounds/block_destroy_clap.ogg"), AudioManager.loadSound(
"Progressia:BlockDestroy", AudioFormat.MONO); 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.SoundType;
import ru.windcorp.progressia.client.audio.backend.Speaker; 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) { public Music(SoundType soundType, int timeLength, float pitch, float gain) {
super(soundType, timeLength, new Vec3(), new Vec3(), pitch, gain); super(soundType, timeLength, new Vec3(), new Vec3(), pitch, gain);

View File

@ -40,7 +40,14 @@ public class Sound {
this(AudioRegistry.getInstance().get(id)); 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(id);
this.position = position; this.position = position;
this.velocity = velocity; this.velocity = velocity;
@ -48,7 +55,14 @@ public class Sound {
this.gain = gain; 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(soundType);
this.position = position; this.position = position;
this.velocity = velocity; this.velocity = velocity;

View File

@ -39,7 +39,12 @@ public class AudioReader {
ShortBuffer rawAudio = decodeVorbis(resource, channelBuffer, rateBuffer); 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) { public static SoundType readAsMono(Resource resource, String id) {
@ -50,7 +55,15 @@ public class AudioReader {
return readAsSpecified(resource, id, AL_FORMAT_STEREO16); return readAsSpecified(resource, id, AL_FORMAT_STEREO16);
} }
private static ShortBuffer decodeVorbis(Resource dataToDecode, IntBuffer channelsBuffer, IntBuffer rateBuffer) { private static ShortBuffer decodeVorbis(
return stb_vorbis_decode_memory(dataToDecode.readAsBytes(), channelsBuffer, rateBuffer); 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 (isInWorld) {
if (wasInWorld) { if (wasInWorld) {
velocity.set(camera.getLastAnchorPosition()).sub(position) velocity.set(camera.getLastAnchorPosition()).sub(position).div(
.div((float) GraphicsInterface.getFrameLength()); (float) GraphicsInterface.getFrameLength()
);
} else { } else {
// If !wasInWorld, previous position is nonsence. Assume 0. // If !wasInWorld, previous position is nonsence. Assume 0.
velocity.set(0); velocity.set(0);
@ -71,9 +72,9 @@ public class Listener {
} }
/* /*
* Only apply if there is a chance that params changed. This can only * Only apply if there is a chance that params changed.
* happen if we are in world now (isInWorld) or we just left world * This can only happen if we are in world now (isInWorld) or we just
* (wasInWorld, then we need to reset). * left world (wasInWorld, then we need to reset).
*/ */
if (isInWorld || wasInWorld) { if (isInWorld || wasInWorld) {
applyParams(); applyParams();
@ -90,7 +91,17 @@ public class Listener {
private void applyParams() { private void applyParams() {
alListener3f(AL_POSITION, position.x, position.y, position.z); alListener3f(AL_POSITION, position.x, position.y, position.z);
alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.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 int audioBuffer;
private double duration; 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); super(id);
this.rawAudio = rawAudio; this.rawAudio = rawAudio;
this.sampleRate = sampleRate; this.sampleRate = sampleRate;

View File

@ -24,7 +24,9 @@ import static org.lwjgl.openal.AL11.*;
public class Speaker { public class Speaker {
public enum State { public enum State {
NOT_PLAYING, PLAYING, PLAYING_LOOP NOT_PLAYING,
PLAYING,
PLAYING_LOOP
} }
// Buffers // Buffers
@ -47,7 +49,13 @@ public class Speaker {
setAudioData(audioData); 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); setAudioData(audioData);
setPosition(position); setPosition(position);
setVelocity(velocity); setVelocity(velocity);
@ -55,7 +63,12 @@ public class Speaker {
setGain(gain); setGain(gain);
} }
public Speaker(Vec3 position, Vec3 velocity, float pitch, float gain) { public Speaker(
Vec3 position,
Vec3 velocity,
float pitch,
float gain
) {
setPosition(position); setPosition(position);
setVelocity(velocity); setVelocity(velocity);
setPitch(pitch); setPitch(pitch);

View File

@ -39,7 +39,9 @@ public class DefaultClientCommsListener implements CommsListener {
@Override @Override
public void onPacketReceived(Packet packet) { public void onPacketReceived(Packet packet) {
if (packet instanceof PacketAffectWorld) { if (packet instanceof PacketAffectWorld) {
((PacketAffectWorld) packet).apply(getClient().getWorld().getData()); ((PacketAffectWorld) packet).apply(
getClient().getWorld().getData()
);
} else if (packet instanceof PacketSetLocalPlayer) { } else if (packet instanceof PacketSetLocalPlayer) {
setLocalPlayer((PacketSetLocalPlayer) packet); setLocalPlayer((PacketSetLocalPlayer) packet);
} }

View File

@ -33,12 +33,17 @@ public class ControlTriggerLambda extends ControlTriggerInputBased {
private final Predicate<InputEvent> predicate; private final Predicate<InputEvent> predicate;
private final BiConsumer<InputEvent, ControlData> dataWriter; private final BiConsumer<InputEvent, ControlData> dataWriter;
public ControlTriggerLambda(String id, Predicate<InputEvent> predicate, public ControlTriggerLambda(
BiConsumer<InputEvent, ControlData> dataWriter) { String id,
Predicate<InputEvent> predicate,
BiConsumer<InputEvent, ControlData> dataWriter
) {
super(id); super(id);
this.packetId = NamespacedUtil.getId(NamespacedUtil.getNamespace(id), this.packetId = NamespacedUtil.getId(
"ControlKeyPress" + NamespacedUtil.getName(id)); NamespacedUtil.getNamespace(id),
"ControlKeyPress" + NamespacedUtil.getName(id)
);
this.predicate = predicate; this.predicate = predicate;
this.dataWriter = dataWriter; this.dataWriter = dataWriter;
@ -49,7 +54,10 @@ public class ControlTriggerLambda extends ControlTriggerInputBased {
if (!predicate.test(event)) if (!predicate.test(event))
return null; 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()); dataWriter.accept(event, packet.getControl());

View File

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

View File

@ -27,57 +27,120 @@ import ru.windcorp.progressia.common.comms.controls.ControlData;
public class ControlTriggers { public class ControlTriggers {
public static ControlTriggerInputBased of(String id, BiConsumer<InputEvent, ControlData> dataWriter, public static ControlTriggerInputBased of(
Predicate<InputEvent> predicate) { String id,
BiConsumer<InputEvent, ControlData> dataWriter,
Predicate<InputEvent> predicate
) {
return new ControlTriggerLambda(id, predicate, dataWriter); return new ControlTriggerLambda(id, predicate, dataWriter);
} }
public static ControlTriggerInputBased of(String id, Consumer<ControlData> dataWriter, public static ControlTriggerInputBased of(
Predicate<InputEvent> predicate) { String id,
return of(id, (input, control) -> dataWriter.accept(control), predicate); Consumer<ControlData> dataWriter,
Predicate<InputEvent> predicate
) {
return of(
id,
(input, control) -> dataWriter.accept(control),
predicate
);
} }
public static ControlTriggerInputBased of(String id, Predicate<InputEvent> predicate) { public static ControlTriggerInputBased of(
return of(id, (input, control) -> { String id,
}, predicate); Predicate<InputEvent> predicate
) {
return of(
id,
(input, control) -> {
},
predicate
);
} }
@SafeVarargs @SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased of(String id, Class<I> inputType, public static <I extends InputEvent> ControlTriggerInputBased of(
BiConsumer<I, ControlData> dataWriter, Predicate<I>... predicates) { String id,
return of(id, createCheckedDataWriter(inputType, dataWriter), Class<I> inputType,
createCheckedCompoundPredicate(inputType, predicates)); BiConsumer<I, ControlData> dataWriter,
Predicate<I>... predicates
) {
return of(
id,
createCheckedDataWriter(inputType, dataWriter),
createCheckedCompoundPredicate(inputType, predicates)
);
} }
@SafeVarargs @SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased of(String id, Class<I> inputType, public static <I extends InputEvent> ControlTriggerInputBased of(
Consumer<ControlData> dataWriter, Predicate<I>... predicates) { String id,
return of(id, inputType, (input, control) -> dataWriter.accept(control), predicates); Class<I> inputType,
Consumer<ControlData> dataWriter,
Predicate<I>... predicates
) {
return of(
id,
inputType,
(input, control) -> dataWriter.accept(control),
predicates
);
} }
@SafeVarargs @SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased of(String id, Class<I> inputType, public static <I extends InputEvent> ControlTriggerInputBased of(
Predicate<I>... predicates) { String id,
return of(id, (input, control) -> { Class<I> inputType,
}, createCheckedCompoundPredicate(inputType, predicates)); Predicate<I>... predicates
) {
return of(
id,
(input, control) -> {
},
createCheckedCompoundPredicate(inputType, predicates)
);
} }
@SafeVarargs @SafeVarargs
public static ControlTriggerInputBased of(String id, BiConsumer<InputEvent, ControlData> dataWriter, public static ControlTriggerInputBased of(
Predicate<InputEvent>... predicates) { String id,
return of(id, InputEvent.class, dataWriter, predicates); BiConsumer<InputEvent, ControlData> dataWriter,
Predicate<InputEvent>... predicates
) {
return of(
id,
InputEvent.class,
dataWriter,
predicates
);
} }
@SafeVarargs @SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased of(String id, Consumer<ControlData> dataWriter, public static <I extends InputEvent> ControlTriggerInputBased of(
Predicate<InputEvent>... predicates) { String id,
return of(id, (input, control) -> dataWriter.accept(control), predicates); Consumer<ControlData> dataWriter,
Predicate<InputEvent>... predicates
) {
return of(
id,
(input, control) -> dataWriter.accept(control),
predicates
);
} }
@SafeVarargs @SafeVarargs
public static ControlTriggerInputBased of(String id, Predicate<InputEvent>... predicates) { public static ControlTriggerInputBased of(
return of(id, InputEvent.class, (input, control) -> { String id,
}, predicates); 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, public static ControlTriggerInputBased localOf(
Predicate<InputEvent> predicate) { String id,
Consumer<InputEvent> action,
Predicate<InputEvent> predicate
) {
return new ControlTriggerLocalLambda(id, predicate, action); return new ControlTriggerLocalLambda(id, predicate, action);
} }
public static ControlTriggerInputBased localOf(String id, Runnable action, Predicate<InputEvent> predicate) { public static ControlTriggerInputBased localOf(
return localOf(id, input -> action.run(), predicate); String id,
Runnable action,
Predicate<InputEvent> predicate
) {
return localOf(
id,
input -> action.run(),
predicate
);
} }
@SafeVarargs @SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased localOf(String id, Class<I> inputType, public static <I extends InputEvent> ControlTriggerInputBased localOf(
Consumer<I> action, Predicate<I>... predicates) { String id,
return localOf(id, createCheckedAction(inputType, action), Class<I> inputType,
createCheckedCompoundPredicate(inputType, predicates)); Consumer<I> action,
Predicate<I>... predicates
) {
return localOf(
id,
createCheckedAction(inputType, action),
createCheckedCompoundPredicate(inputType, predicates)
);
} }
@SafeVarargs @SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased localOf(String id, Class<I> inputType, public static <I extends InputEvent> ControlTriggerInputBased localOf(
Runnable action, Predicate<I>... predicates) { String id,
return localOf(id, inputType, input -> action.run(), predicates); Class<I> inputType,
Runnable action,
Predicate<I>... predicates
) {
return localOf(
id,
inputType,
input -> action.run(),
predicates
);
} }
@SafeVarargs @SafeVarargs
public static ControlTriggerInputBased localOf(String id, Consumer<InputEvent> action, public static ControlTriggerInputBased localOf(
Predicate<InputEvent>... predicates) { String id,
return localOf(id, InputEvent.class, action, predicates); Consumer<InputEvent> action,
Predicate<InputEvent>... predicates
) {
return localOf(
id,
InputEvent.class,
action,
predicates
);
} }
@SafeVarargs @SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased localOf(String id, Runnable action, public static <I extends InputEvent> ControlTriggerInputBased localOf(
Predicate<InputEvent>... predicates) { String id,
return of(id, input -> action.run(), predicates); Runnable action,
Predicate<InputEvent>... predicates
) {
return of(
id,
input -> action.run(),
predicates
);
} }
private static <I extends InputEvent> BiConsumer<InputEvent, ControlData> createCheckedDataWriter( 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); return (inputEvent, control) -> dataWriter.accept(inputType.cast(inputEvent), control);
} }
private static <I extends InputEvent> Consumer<InputEvent> createCheckedAction(Class<I> inputType, private static <I extends InputEvent> Consumer<InputEvent> createCheckedAction(
Consumer<I> action) { Class<I> inputType,
Consumer<I> action
) {
return inputEvent -> action.accept(inputType.cast(inputEvent)); return inputEvent -> action.accept(inputType.cast(inputEvent));
} }
private static <I extends InputEvent> Predicate<InputEvent> createCheckedCompoundPredicate(Class<I> inputType, private static <I extends InputEvent> Predicate<InputEvent> createCheckedCompoundPredicate(
Predicate<I>[] predicates) { Class<I> inputType,
Predicate<I>[] predicates
) {
return new CompoundCastPredicate<>(inputType, predicates); return new CompoundCastPredicate<>(inputType, predicates);
} }

View File

@ -32,7 +32,8 @@ public class InputBasedControls {
this.client = client; this.client = client;
this.controls = ControlTriggerRegistry.getInstance().values().stream() 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) { public void handleInput(Input input) {

View File

@ -21,6 +21,7 @@ package ru.windcorp.progressia.client.comms.localhost;
import ru.windcorp.progressia.client.comms.ServerCommsChannel; import ru.windcorp.progressia.client.comms.ServerCommsChannel;
import ru.windcorp.progressia.common.comms.packets.Packet; import ru.windcorp.progressia.common.comms.packets.Packet;
import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.ServerState;
public class LocalServerCommsChannel extends ServerCommsChannel { public class LocalServerCommsChannel extends ServerCommsChannel {
@ -34,7 +35,11 @@ public class LocalServerCommsChannel extends ServerCommsChannel {
public void connect(String login) { public void connect(String login) {
setState(State.CONNECTED); 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); server.getClientManager().addClient(localClient);
} }
@ -50,7 +55,7 @@ public class LocalServerCommsChannel extends ServerCommsChannel {
@Override @Override
public void disconnect() { public void disconnect() {
// Do nothing ServerState.getInstance().getClientManager().disconnectClient(localClient);
} }
} }

View File

@ -21,6 +21,7 @@ package ru.windcorp.progressia.client.graphics;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects;
import com.google.common.eventbus.Subscribe; import com.google.common.eventbus.Subscribe;
@ -58,6 +59,7 @@ public class GUI {
} }
public static void addBottomLayer(Layer layer) { public static void addBottomLayer(Layer layer) {
Objects.requireNonNull(layer, "layer");
modify(layers -> { modify(layers -> {
layers.add(layer); layers.add(layer);
layer.onAdded(); layer.onAdded();
@ -65,6 +67,7 @@ public class GUI {
} }
public static void addTopLayer(Layer layer) { public static void addTopLayer(Layer layer) {
Objects.requireNonNull(layer, "layer");
modify(layers -> { modify(layers -> {
layers.add(0, layer); layers.add(0, layer);
layer.onAdded(); layer.onAdded();
@ -72,6 +75,7 @@ public class GUI {
} }
public static void removeLayer(Layer layer) { public static void removeLayer(Layer layer) {
Objects.requireNonNull(layer, "layer");
modify(layers -> { modify(layers -> {
layers.remove(layer); layers.remove(layer);
layer.onRemoved(); layer.onRemoved();

View File

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

View File

@ -49,7 +49,13 @@ public class InputHandler {
private static final ModifiableKeyEvent THE_KEY_EVENT = new ModifiableKeyEvent(); 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) if (GraphicsBackend.getWindowHandle() != window)
return; return;
THE_KEY_EVENT.initialize(key, scancode, action, mods); 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); 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(); 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) if (GraphicsBackend.getWindowHandle() != window)
return; return;
y = GraphicsInterface.getFrameHeight() - y; // Flip y axis y = GraphicsInterface.getFrameHeight() - y; // Flip y axis
@ -116,7 +131,11 @@ public class InputHandler {
private static final ModifiableWheelScrollEvent THE_WHEEL_SCROLL_EVENT = new ModifiableWheelScrollEvent(); 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) if (GraphicsBackend.getWindowHandle() != window)
return; return;
THE_WHEEL_SCROLL_EVENT.initialize(xoffset, yoffset); 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 * 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); THE_FRAME_RESIZE_EVENT.initialize(width, height);
dispatch(THE_FRAME_RESIZE_EVENT); dispatch(THE_FRAME_RESIZE_EVENT);
} }

View File

@ -24,7 +24,10 @@ import gnu.trove.set.hash.TIntHashSet;
public class InputTracker { 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); private static final TIntSet PRESSED_KEYS = new TIntHashSet(256);

View File

@ -92,10 +92,16 @@ class LWJGLInitializer {
private static void setupWindowCallbacks() { private static void setupWindowCallbacks() {
long handle = GraphicsBackend.getWindowHandle(); long handle = GraphicsBackend.getWindowHandle();
glfwSetFramebufferSizeCallback(handle, GraphicsBackend::onFrameResized); glfwSetFramebufferSizeCallback(
handle,
GraphicsBackend::onFrameResized
);
glfwSetKeyCallback(handle, InputHandler::handleKeyInput); glfwSetKeyCallback(handle, InputHandler::handleKeyInput);
glfwSetMouseButtonCallback(handle, InputHandler::handleMouseButtonInput); glfwSetMouseButtonCallback(
handle,
InputHandler::handleMouseButtonInput
);
glfwSetCursorPosCallback(handle, InputHandler::handleMouseMoveInput); glfwSetCursorPosCallback(handle, InputHandler::handleMouseMoveInput);

View File

@ -34,13 +34,19 @@ public class OpenGLObjectTracker {
private static final ReferenceQueue<OpenGLDeletable> DELETE_QUEUE = new ReferenceQueue<>(); private static final ReferenceQueue<OpenGLDeletable> DELETE_QUEUE = new ReferenceQueue<>();
public synchronized static void register(OpenGLDeletable object, IntConsumer glDeleter) { public synchronized static void register(OpenGLDeletable object, IntConsumer glDeleter) {
GLPhantomReference<OpenGLDeletable> glRef = new GLPhantomReference<>(object, DELETE_QUEUE, object.getHandle(), GLPhantomReference<OpenGLDeletable> glRef = new GLPhantomReference<>(
glDeleter); object,
DELETE_QUEUE,
object.getHandle(),
glDeleter
);
TO_DELETE.add(glRef); TO_DELETE.add(glRef);
} }
public static void deleteAllObjects() { public static void deleteAllObjects() {
for (GLPhantomReference<OpenGLDeletable> glRef : TO_DELETE) { for (
GLPhantomReference<OpenGLDeletable> glRef : TO_DELETE
) {
glRef.clear(); glRef.clear();
} }
} }
@ -69,16 +75,20 @@ public class OpenGLObjectTracker {
* It is possible to create a phantom reference with a {@code null} * It is possible to create a phantom reference with a {@code null}
* queue, but such a reference is completely useless: Its {@code get} * queue, but such a reference is completely useless: Its {@code get}
* method will always return {@code null} and, since it does not have a * 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 * @param referent the object the new phantom reference will refer to
* the object the new phantom reference will refer to * @param q the queue with which the reference is to be
* @param q * registered,
* the queue with which the reference is to be registered, or * or {@code null} if registration is not required
* {@code null} if registration is not required
*/ */
public GLPhantomReference(T referent, ReferenceQueue<? super T> q, int referentGLhandle, public GLPhantomReference(
IntConsumer GLDeleter) { T referent,
ReferenceQueue<? super T> q,
int referentGLhandle,
IntConsumer GLDeleter
) {
super(referent, q); super(referent, q);
this.referentGLhandle = referentGLhandle; this.referentGLhandle = referentGLhandle;
this.GLDeleter = GLDeleter; this.GLDeleter = GLDeleter;

View File

@ -41,7 +41,11 @@ public class RenderTaskQueue {
HANDLER.invokeNow(task); 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); 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; import static org.lwjgl.opengl.GL15.GL_STREAM_DRAW;
public enum Usage { // TODO add _COPY and _READ, pref. as another enum 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; 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 class VertexBufferObject implements OpenGLDeletable {
public static enum BindTarget { 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; private final int glCode;

View File

@ -32,7 +32,12 @@ public class CombinedShader extends Shader {
for (int i = 1; i < resources.length; ++i) { for (int i = 1; i < resources.length; ++i) {
if (ShaderType.guessByResourceName(resources[i]) != first) { if (ShaderType.guessByResourceName(resources[i]) != first) {
throw new IllegalArgumentException( 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) == '#') { if (contents.codePointAt(versionIndex) == '#') {
final String versionAnnotation = "#version "; final String versionAnnotation = "#version ";
if (contents.regionMatches(versionIndex, versionAnnotation, 0, versionAnnotation.length())) { if (
contents = contents.substring(versionIndex + versionAnnotation.length() + "120".length()); 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")) if (resource.contains("fsh"))
return FRAGMENT; 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) { public Shader(String resource) {
this(ShaderType.guessByResourceName(resource), getShaderResource(resource).readAsString()); this(
ShaderType.guessByResourceName(resource),
getShaderResource(resource).readAsString()
);
} }
@Override @Override

View File

@ -51,29 +51,104 @@ public class AttributeVertexArray extends Attribute {
} }
} }
public void set(int size, boolean normalized, int stride, ByteBuffer pointer) { public void set(
glVertexAttribPointer(handle, size, GL_BYTE, normalized, stride, pointer); 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) { public void set(
glVertexAttribPointer(handle, size, GL_FLOAT, normalized, stride, pointer); 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) { public void set(
glVertexAttribPointer(handle, size, GL_INT, normalized, stride, pointer); 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) { public void set(
glVertexAttribPointer(handle, size, GL_SHORT, normalized, stride, pointer); 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) { public void set(
glVertexAttribPointer(handle, size, type, normalized, stride, pointer); 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()); 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 width = GraphicsInterface.getFrameWidth();
float height = GraphicsInterface.getFrameHeight(); 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()); .mul(getTransform());
} }

View File

@ -33,8 +33,10 @@ public class FlatRenderProgram extends ShapeRenderProgram {
private static FlatRenderProgram def = null; private static FlatRenderProgram def = null;
public static void init() { public static void init() {
def = new FlatRenderProgram(new String[] { "FlatDefault.vertex.glsl" }, def = new FlatRenderProgram(
new String[] { "FlatDefault.fragment.glsl" }); new String[] { "FlatDefault.vertex.glsl" },
new String[] { "FlatDefault.fragment.glsl" }
);
} }
public static FlatRenderProgram getDefault() { 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_VERTEX_SHADER_RESOURCE = "Flat.vertex.glsl";
private static final String FLAT_FRAGMENT_SHADER_RESOURCE = "Flat.fragment.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 Uniform1Int maskCountUniform;
private final Uniform2Float masksUniform; private final Uniform2Float masksUniform;
public FlatRenderProgram(String[] vertexShaderResources, String[] fragmentShaderResources) { public FlatRenderProgram(
super(attachVertexShader(vertexShaderResources), attachFragmentShader(fragmentShaderResources)); String[] vertexShaderResources,
String[] fragmentShaderResources
) {
super(
attachVertexShader(vertexShaderResources),
attachFragmentShader(fragmentShaderResources)
);
this.maskCountUniform = getUniform(MASK_COUNT_UNIFORM_NAME).as1Int(); this.maskCountUniform = getUniform(MASK_COUNT_UNIFORM_NAME).as1Int();
this.masksUniform = getUniform(MASKS_UNIFORM_NAME).as2Float(); this.masksUniform = getUniform(MASKS_UNIFORM_NAME).as2Float();

View File

@ -88,7 +88,8 @@ public class Mask {
@Override @Override
public String toString() { 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 { public class MaskStack {
private final FloatBuffer buffer = BufferUtils private final FloatBuffer buffer = BufferUtils.createFloatBuffer(
.createFloatBuffer(FlatRenderProgram.MASK_STACK_SIZE * TransformedMask.SIZE_IN_FLOATS); FlatRenderProgram.MASK_STACK_SIZE * TransformedMask.SIZE_IN_FLOATS
);
public void pushMask(TransformedMask mask) { public void pushMask(TransformedMask mask) {
mask.writeToBuffer(buffer); mask.writeToBuffer(buffer);

View File

@ -42,8 +42,14 @@ public class TransformedMask {
private Vec4 endXstartY = null; private Vec4 endXstartY = null;
private Vec4 endXendY = null; private Vec4 endXendY = null;
public TransformedMask(Vec2 origin, Vec2 width, Vec2 height, Vec2 counterOrigin, Vec2 counterWidth, public TransformedMask(
Vec2 counterHeight) { Vec2 origin,
Vec2 width,
Vec2 height,
Vec2 counterOrigin,
Vec2 counterWidth,
Vec2 counterHeight
) {
set(origin, width, height, counterOrigin, counterWidth, counterHeight); set(origin, width, height, counterOrigin, counterWidth, counterHeight);
} }
@ -55,8 +61,14 @@ public class TransformedMask {
// Do nothing // Do nothing
} }
public TransformedMask set(Vec2 origin, Vec2 width, Vec2 height, Vec2 counterOrigin, Vec2 counterWidth, public TransformedMask set(
Vec2 counterHeight) { Vec2 origin,
Vec2 width,
Vec2 height,
Vec2 counterOrigin,
Vec2 counterWidth,
Vec2 counterHeight
) {
this.origin.set(origin.x, origin.y); this.origin.set(origin.x, origin.y);
this.width.set(width.x, width.y); this.width.set(width.x, width.y);
this.height.set(height.x, height.y); this.height.set(height.x, height.y);
@ -100,17 +112,35 @@ public class TransformedMask {
} }
private void setFields() { 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) { public void writeToBuffer(FloatBuffer output) {

View File

@ -68,11 +68,17 @@ public class Font {
return color; return color;
} }
public Renderable assemble(CharSequence chars, float maxWidth) { public Renderable assemble(
CharSequence chars,
float maxWidth
) {
return typeface.assembleStatic(chars, style, align, maxWidth, color); 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); 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 * Creates a new {@link Font} with the specified {@code style} exactly. This
* object's style is ignored. * object's style is ignored.
* *
* @param style * @param style the new style
* the new style
* @return the new font * @return the new font
*/ */
public Font withStyle(int style) { public Font withStyle(int style) {

View File

@ -81,7 +81,8 @@ public class GNUUnifontLoader {
private static BufferedReader createReader(Resource resource) throws IOException { private static BufferedReader createReader(Resource resource) throws IOException {
return new BufferedReader( 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) { private static Stream<String> createStream(BufferedReader reader) {
@ -96,8 +97,13 @@ public class GNUUnifontLoader {
char c = getChar(declar); char c = getChar(declar);
TextureDataEditor editor = new TextureDataEditor(width, GNUUnifont.HEIGHT, width, GNUUnifont.HEIGHT, TextureDataEditor editor = new TextureDataEditor(
TEXTURE_SETTINGS); width,
GNUUnifont.HEIGHT,
width,
GNUUnifont.HEIGHT,
TEXTURE_SETTINGS
);
for (int y = 0; y < GNUUnifont.HEIGHT; ++y) { for (int y = 0; y < GNUUnifont.HEIGHT; ++y) {
for (int x = 0; x < width; ++x) { for (int x = 0; x < width; ++x) {
@ -159,7 +165,8 @@ public class GNUUnifontLoader {
if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'))) { if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'))) {
throw new IOException( 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() { 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), (map, glyph) -> map.put(glyph.c, glyph.texture),
@ -192,7 +200,8 @@ public class GNUUnifontLoader {
return a; return a;
}, },
Characteristics.UNORDERED); Characteristics.UNORDERED
);
} }
private GNUUnifontLoader() { private GNUUnifontLoader() {

View File

@ -29,8 +29,12 @@ import ru.windcorp.progressia.common.util.Vectors;
public abstract class Typeface extends Named { public abstract class Typeface extends Named {
public static class Style { public static class Style {
public static final int BOLD = 1 << 0, ITALIC = 1 << 1, UNDERLINED = 1 << 2, STRIKETHRU = 1 << 3, public static final int BOLD = 1 << 0,
SHADOW = 1 << 4, OUTLINED = 1 << 5; ITALIC = 1 << 1,
UNDERLINED = 1 << 2,
STRIKETHRU = 1 << 3,
SHADOW = 1 << 4,
OUTLINED = 1 << 5;
public static final int PLAIN = 0; public static final int PLAIN = 0;
@ -67,19 +71,40 @@ public abstract class Typeface extends Named {
super(name); 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, public abstract Renderable assembleDynamic(
Vec4 color); 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(); Vec2i v = Vectors.grab2i();
v = getSize(chars, style, align, maxWidth, v); v = getSize(chars, style, align, maxWidth, v);
Vectors.release(v); Vectors.release(v);
return v.x; 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(); Vec2i v = Vectors.grab2i();
v = getSize(chars, style, align, maxWidth, v); v = getSize(chars, style, align, maxWidth, v);
Vectors.release(v); Vectors.release(v);
@ -88,7 +113,13 @@ public abstract class Typeface extends Named {
public abstract int getLineHeight(); 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); public abstract boolean supports(char c);

View File

@ -43,9 +43,9 @@ public abstract class BasicButton extends Component {
private boolean isPressed = false; private boolean isPressed = false;
private final Collection<Consumer<BasicButton>> actions = Collections.synchronizedCollection(new ArrayList<>()); private final Collection<Consumer<BasicButton>> actions = Collections.synchronizedCollection(new ArrayList<>());
public BasicButton(String name, String label, Font labelFont) { public BasicButton(String name, Label label) {
super(name); super(name);
this.label = new Label(name + ".Label", labelFont, label); this.label = label;
setLayout(new LayoutAlign(10)); setLayout(new LayoutAlign(10));
addChild(this.label); addChild(this.label);
@ -104,6 +104,10 @@ public abstract class BasicButton extends Component {
}); });
} }
public BasicButton(String name, String label, Font labelFont) {
this(name, new Label(name + ".Label", labelFont, label));
}
public BasicButton(String name, String label) { public BasicButton(String name, String label) {
this(name, label, new Font()); this(name, label, new Font());
} }

View File

@ -29,6 +29,10 @@ public class Button extends BasicButton {
super(name, label, labelFont); super(name, label, labelFont);
} }
public Button(String name, Label label) {
super(name, label);
}
public Button(String name, String label) { public Button(String name, String label) {
this(name, label, new Font()); this(name, label, new Font());
} }

View File

@ -542,8 +542,11 @@ public class Component extends Named {
eventBus.post(event); eventBus.post(event);
} }
public <T extends InputEvent> void addListener(Class<? extends T> type, boolean handlesConsumed, public <T extends InputEvent> void addListener(
InputListener<T> listener) { Class<? extends T> type,
boolean handlesConsumed,
InputListener<T> listener
) {
if (inputBus == null) { if (inputBus == null) {
inputBus = new InputBus(); inputBus = new InputBus();
} }

View File

View File

View File

@ -105,7 +105,8 @@ public class RadioButton extends BasicButton {
addChild(group); addChild(group);
addListener(KeyEvent.class, e -> { addListener(KeyEvent.class, e -> {
if (e.isRelease()) return false; if (e.isRelease())
return false;
if (e.getKey() == GLFW.GLFW_KEY_LEFT || e.getKey() == GLFW.GLFW_KEY_UP) { if (e.getKey() == GLFW.GLFW_KEY_LEFT || e.getKey() == GLFW.GLFW_KEY_UP) {
if (this.group != null) { if (this.group != null) {
@ -149,7 +150,8 @@ public class RadioButton extends BasicButton {
group.selectNext(); group.selectNext();
removeAction(group.listener); removeAction(group.listener);
group.buttons.remove(this); group.buttons.remove(this);
group.getSelected(); // Clear reference if this was the only button in the group group.getSelected(); // Clear reference if this was the only button
// in the group
} }
this.group = group; this.group = group;
@ -178,7 +180,8 @@ public class RadioButton extends BasicButton {
this.checked = checked; this.checked = checked;
if (group != null) { if (group != null) {
group.listener.accept(this); // Failsafe for manual invocations of setChecked() group.listener.accept(this); // Failsafe for manual invocations of
// setChecked()
} }
} }

View File

@ -56,8 +56,13 @@ public class LayoutAlign implements Layout {
size.x = min(size.x, cWidth); size.x = min(size.x, cWidth);
size.y = min(size.y, cHeight); size.y = min(size.y, cHeight);
child.setBounds(c.getX() + (int) ((cWidth - size.x) * alignX) + margin, child.setBounds(
c.getY() + (int) ((cHeight - size.y) * alignY) + margin, size); 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) { public Vec2i calculatePreferredSize(Component c) {
Vec2i result = new Vec2i(0, 0); 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.x = max(size.x, result.x);
result.y = max(size.y, result.y); 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 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; private final int margin;
@ -49,17 +51,32 @@ public class LayoutBorderHorizontal implements Layout {
if (child.getLayoutHint() == LEFT) { if (child.getLayoutHint() == LEFT) {
childSize = child.getPreferredSize(); childSize = child.getPreferredSize();
left = childSize.x + margin; 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) { } else if (child.getLayoutHint() == RIGHT) {
childSize = child.getPreferredSize(); childSize = child.getPreferredSize();
right = childSize.x + margin; 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()) { for (Component child : c.getChildren()) {
if (child.getLayoutHint() == CENTER) { 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 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; private final int margin;
@ -49,17 +51,32 @@ public class LayoutBorderVertical implements Layout {
if (child.getLayoutHint() == UP) { if (child.getLayoutHint() == UP) {
childSize = child.getPreferredSize(); childSize = child.getPreferredSize();
top = childSize.y + margin; 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) { } else if (child.getLayoutHint() == DOWN) {
childSize = child.getPreferredSize(); childSize = child.getPreferredSize();
bottom = childSize.y + margin; 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()) { for (Component child : c.getChildren()) {
if (child.getLayoutHint() == CENTER) { 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

@ -43,7 +43,8 @@ public class LayoutHorizontal implements Layout {
@Override @Override
public void layout(Component c) { 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; int width;

View File

@ -43,7 +43,8 @@ public class LayoutVertical implements Layout {
@Override @Override
public void layout(Component c) { 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()) { synchronized (c.getChildren()) {
for (Component child : c.getChildren()) { for (Component child : c.getChildren()) {

View File

@ -87,14 +87,22 @@ public class CursorMoveEvent extends CursorEvent {
@Override @Override
public CursorMoveEvent snapshot() { public CursorMoveEvent snapshot() {
return new StaticMouseMoveEvent(getPreviousPosition(), getNewPosition(), getTime()); return new StaticMouseMoveEvent(
getPreviousPosition(),
getNewPosition(),
getTime()
);
} }
private class StaticMouseMoveEvent extends CursorMoveEvent { private class StaticMouseMoveEvent extends CursorMoveEvent {
private final Vec2d previousPosition = new Vec2d(); 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); super(newPosition, time);
this.previousPosition.set(previousPosition.x, previousPosition.y); this.previousPosition.set(previousPosition.x, previousPosition.y);
} }

View File

@ -67,7 +67,11 @@ public class FrameResizeEvent extends InputEvent {
private final Vec2i previousSize; private final Vec2i previousSize;
public StaticFrameResizeEvent(Vec2i newSize, Vec2i previousSize, double time) { public StaticFrameResizeEvent(
Vec2i newSize,
Vec2i previousSize,
double time
) {
super(newSize, time); super(newSize, time);
this.previousSize = previousSize; this.previousSize = previousSize;
} }

View File

@ -27,7 +27,13 @@ public class KeyEvent extends InputEvent {
protected int action; protected int action;
protected int mods; 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); super(time);
this.key = key; this.key = key;
this.scancode = scancode; 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 String MOUSE_BUTTON_PREFIX = "GLFW_MOUSE_BUTTON_";
private static final Set<String> IGNORE_FIELDS = new HashSet<>( 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 // for
// LEFT // LEFT
"GLFW_MOUSE_BUTTON_2", // Alias for RIGHT "GLFW_MOUSE_BUTTON_2", // Alias for RIGHT
"GLFW_MOUSE_BUTTON_3" // Alias for MIDDLE "GLFW_MOUSE_BUTTON_3" // Alias for MIDDLE
)); )
);
static { static {
initializeDictionary(); initializeDictionary();
@ -95,8 +100,14 @@ public class Keys {
} }
if (CODES_TO_NAMES.containsKey(value)) { 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), throw CrashReports.report(
name, value, Integer.toHexString(value)); 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); CODES_TO_NAMES.put(value, name);

View File

@ -31,21 +31,28 @@ public class InputBus {
private final boolean handleConsumed; private final boolean handleConsumed;
private final InputListener<?> listener; private final InputListener<?> listener;
public WrappedListener(Class<?> type, boolean handleConsumed, InputListener<?> listener) { public WrappedListener(
Class<?> type,
boolean handleConsumed,
InputListener<?> listener
) {
this.type = type; this.type = type;
this.handleConsumed = handleConsumed; this.handleConsumed = handleConsumed;
this.listener = listener; this.listener = listener;
} }
private boolean handles(Input input) { private boolean handles(Input input) {
return (!input.isConsumed() || handleConsumed) && type.isInstance(input.getEvent()); return (!input.isConsumed() || handleConsumed) &&
type.isInstance(input.getEvent());
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void handle(Input input) { public void handle(Input input) {
if (handles(input)) { if (handles(input)) {
boolean consumed = ((InputListener<InputEvent>) listener) boolean consumed = ((InputListener<InputEvent>) listener)
.handle((InputEvent) type.cast(input.getEvent())); .handle(
(InputEvent) type.cast(input.getEvent())
);
input.setConsumed(consumed); input.setConsumed(consumed);
} }
@ -59,12 +66,18 @@ public class InputBus {
listeners.forEach(l -> l.handle(input)); listeners.forEach(l -> l.handle(input));
} }
public <T extends InputEvent> void register(Class<? extends T> type, boolean handlesConsumed, public <T extends InputEvent> void register(
InputListener<T> listener) { Class<? extends T> type,
boolean handlesConsumed,
InputListener<T> listener
) {
listeners.add(new WrappedListener(type, handlesConsumed, 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); register(type, false, listener);
} }

View File

@ -33,14 +33,22 @@ public abstract class DynamicModel extends Model {
private final Mat4[] transforms; private final Mat4[] transforms;
private final boolean[] dynamics; private final boolean[] dynamics;
public DynamicModel(Renderable[] parts, Mat4[] transforms, boolean[] dynamic) { public DynamicModel(
Renderable[] parts,
Mat4[] transforms,
boolean[] dynamic
) {
super(parts); super(parts);
this.transforms = transforms; this.transforms = transforms;
this.dynamics = dynamic; this.dynamics = dynamic;
} }
public DynamicModel(Builder builder) { public DynamicModel(Builder builder) {
this(builder.getParts(), builder.getTransforms(), builder.getDynamics()); this(
builder.getParts(),
builder.getTransforms(),
builder.getDynamics()
);
} }
@Override @Override
@ -70,7 +78,11 @@ public abstract class DynamicModel extends Model {
protected Builder() { 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")); parts.add(Objects.requireNonNull(part, "part"));
transforms.add(Objects.requireNonNull(transform, "transform")); transforms.add(Objects.requireNonNull(transform, "transform"));
dynamics.add(isDynamic); dynamics.add(isDynamic);
@ -78,15 +90,22 @@ public abstract class DynamicModel extends Model {
return this; return this;
} }
public Builder addStaticPart(Renderable part, Mat4 transform) { public Builder addStaticPart(
Renderable part,
Mat4 transform
) {
return addPart(part, new Mat4(transform), false); return addPart(part, new Mat4(transform), false);
} }
public Builder addDynamicPart(Renderable part) { public Builder addDynamicPart(
Renderable part
) {
return addPart(part, new Mat4(), true); return addPart(part, new Mat4(), true);
} }
public Builder addStaticPart(Renderable part) { public Builder addStaticPart(
Renderable part
) {
return addStaticPart(part, IDENTITY); return addStaticPart(part, IDENTITY);
} }

View File

@ -37,13 +37,23 @@ public class LambdaModel extends DynamicModel {
private final TransformGetter[] getters; 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); super(parts, transforms, dynamic);
this.getters = getters; this.getters = getters;
} }
public LambdaModel(Builder builder) { public LambdaModel(Builder builder) {
this(builder.getParts(), builder.getTransforms(), builder.getDynamics(), builder.getGetters()); this(
builder.getParts(),
builder.getTransforms(),
builder.getDynamics(),
builder.getGetters()
);
} }
@Override @Override
@ -65,7 +75,11 @@ public class LambdaModel extends DynamicModel {
protected Builder() { 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")); parts.add(Objects.requireNonNull(part, "part"));
transforms.add(Objects.requireNonNull(transform, "transform")); transforms.add(Objects.requireNonNull(transform, "transform"));
dynamics.add(getter != null); dynamics.add(getter != null);
@ -74,15 +88,23 @@ public class LambdaModel extends DynamicModel {
return this; return this;
} }
public Builder addStaticPart(Renderable part, Mat4 transform) { public Builder addStaticPart(
Renderable part,
Mat4 transform
) {
return addPart(part, new Mat4(transform), null); 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); return addPart(part, new Mat4(), getter);
} }
public Builder addStaticPart(Renderable part) { public Builder addStaticPart(
Renderable part
) {
return addStaticPart(part, IDENTITY); return addStaticPart(part, IDENTITY);
} }
@ -105,8 +127,12 @@ public class LambdaModel extends DynamicModel {
} }
public static LambdaModel animate(Renderable model, TransformGetter transform) { public static LambdaModel animate(Renderable model, TransformGetter transform) {
return new LambdaModel(new Renderable[] { model }, new Mat4[] { new Mat4() }, new boolean[] { true }, return new LambdaModel(
new TransformGetter[] { transform }); new Renderable[] { model },
new Mat4[] { new Mat4() },
new boolean[] { true },
new TransformGetter[] { transform }
);
} }
} }

View File

@ -38,7 +38,8 @@ public class ShapePartGroup {
for (int i = start; i < end; ++i) { for (int i = start; i < end; ++i) {
ShapePart face = faces[i]; ShapePart face = faces[i];
assert this.texture == null ? (face.getTexture() == null) assert this.texture == null
? (face.getTexture() == null)
: (face.getTexture().getSprite().getPrimitive() == this.texture); : (face.getTexture().getSprite().getPrimitive() == this.texture);
indexCount += face.getIndexCount(); indexCount += face.getIndexCount();

View File

@ -28,10 +28,15 @@ public class ShapeRenderHelper {
protected static final int TRANSFORM_STACK_SIZE = 64; protected static final int TRANSFORM_STACK_SIZE = 64;
protected static final int COLOR_MULTIPLIER_STACK_SIZE = TRANSFORM_STACK_SIZE; 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, protected final StashingStack<Vec4> colorMultiplierStack = new StashingStack<>(
Vec4::new); COLOR_MULTIPLIER_STACK_SIZE,
Vec4::new
);
{ {
transformStack.push().identity(); transformStack.push().identity();

View File

@ -53,7 +53,8 @@ public class ShapeRenderProgram extends Program {
POSITIONS_ATTRIBUTE_NAME = "inputPositions", POSITIONS_ATTRIBUTE_NAME = "inputPositions",
UNIFORM_COLOR_MULTIPLER_ATTRIBUTE_NAME = "uniformColorMultiplier", UNIFORM_COLOR_MULTIPLER_ATTRIBUTE_NAME = "uniformColorMultiplier",
ATTRIBUTE_COLOR_MULTIPLER_ATTRIBUTE_NAME = "inputColorMultiplier", 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"; TEXTURE_SLOT_UNIFORM_NAME = "textureSlot";
private final Uniform4Matrix finalTransformUniform; private final Uniform4Matrix finalTransformUniform;
@ -64,11 +65,21 @@ public class ShapeRenderProgram extends Program {
private final Uniform1Int useTextureUniform; private final Uniform1Int useTextureUniform;
private final Uniform1Int textureSlotUniform; private final Uniform1Int textureSlotUniform;
public ShapeRenderProgram(String[] vertexShaderResources, String[] fragmentShaderResources) { public ShapeRenderProgram(
super(new CombinedShader(attachVertexShader(vertexShaderResources)), String[] vertexShaderResources,
new CombinedShader(attachFragmentShader(fragmentShaderResources))); 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(); 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.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) { private static String[] attachVertexShader(String[] others) {
@ -91,7 +104,10 @@ public class ShapeRenderProgram extends Program {
return ObjectArrays.concat(SHAPE_FRAGMENT_SHADER_RESOURCE, others); return ObjectArrays.concat(SHAPE_FRAGMENT_SHADER_RESOURCE, others);
} }
public void render(ShapeRenderHelper helper, Shape shape) { public void render(
ShapeRenderHelper helper,
Shape shape
) {
use(); use();
configure(helper); configure(helper);
@ -129,13 +145,34 @@ public class ShapeRenderProgram extends Program {
int vertexStride = getBytesPerVertex(); int vertexStride = getBytesPerVertex();
int offset = 0; 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; 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; 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; offset += 2 * Float.BYTES;
return offset; return offset;
@ -156,8 +193,12 @@ public class ShapeRenderProgram extends Program {
useTextureUniform.set(0); useTextureUniform.set(0);
} }
GL11.glDrawElements(GL11.GL_TRIANGLES, group.getIndexCount(), GL11.GL_UNSIGNED_SHORT, GL11.glDrawElements(
group.getByteOffsetOfIndices()); GL11.GL_TRIANGLES,
group.getIndexCount(),
GL11.GL_UNSIGNED_SHORT,
group.getByteOffsetOfIndices()
);
} }
public int getBytesPerVertex() { public int getBytesPerVertex() {
@ -179,9 +220,13 @@ public class ShapeRenderProgram extends Program {
Sprite sprite = face.getTexture().getSprite(); Sprite sprite = face.getTexture().getSprite();
for (int i = 0; i < face.getVertexCount(); i++) { 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()); v.mul(sprite.getSize()).add(sprite.getStart());
@ -199,11 +244,34 @@ public class ShapeRenderProgram extends Program {
} }
public static interface VertexBuilder { 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(); ByteBuffer assemble();
} }
@ -225,35 +293,84 @@ public class ShapeRenderProgram extends Program {
private final List<Vertex> vertices = new ArrayList<>(); private final List<Vertex> vertices = new ArrayList<>();
@Override @Override
public VertexBuilder addVertex(float x, float y, float z, float r, float g, float b, float a, float tx, public VertexBuilder addVertex(
float ty) { float x,
vertices.add(new Vertex(new Vec3(x, y, z), new Vec4(r, g, b, a), new Vec2(tx, ty))); 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; return this;
} }
@Override @Override
public VertexBuilder addVertex(float x, float y, float z, float r, float g, float b, float tx, float ty) { public VertexBuilder addVertex(
vertices.add(new Vertex(new Vec3(x, y, z), new Vec4(r, g, b, 1f), new Vec2(tx, ty))); 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; return this;
} }
@Override @Override
public VertexBuilder addVertex(Vec3 position, Vec4 colorMultiplier, Vec2 textureCoords) { public VertexBuilder addVertex(
vertices.add(new Vertex(new Vec3(position), new Vec4(colorMultiplier), new Vec2(textureCoords))); Vec3 position,
Vec4 colorMultiplier,
Vec2 textureCoords
) {
vertices.add(
new Vertex(
new Vec3(position),
new Vec4(colorMultiplier),
new Vec2(textureCoords)
)
);
return this; return this;
} }
@Override @Override
public ByteBuffer assemble() { 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) { for (Vertex v : vertices) {
result.putFloat(v.position.x).putFloat(v.position.y).putFloat(v.position.z) result
.putFloat(v.colorMultiplier.x).putFloat(v.colorMultiplier.y).putFloat(v.colorMultiplier.z) .putFloat(v.position.x)
.putFloat(v.colorMultiplier.w).putFloat(v.textureCoords.x).putFloat(v.textureCoords.y); .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(); result.flip();

View File

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

View File

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

View File

@ -44,7 +44,9 @@ public class SimpleTextures {
try { try {
TextureDataEditor data = TextureLoader.loadPixels(resource, SETTINGS); 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) { } catch (IOException e) {
throw CrashReports.report(e, "Could not load texture %s", resource); throw CrashReports.report(e, "Could not load texture %s", resource);
} }

View File

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

View File

@ -35,8 +35,14 @@ class TextureData {
private final int width; private final int width;
private final int height; private final int height;
public TextureData(ByteBuffer data, int bufferWidth, int bufferHeight, int width, int height, public TextureData(
TextureSettings settings) { ByteBuffer data,
int bufferWidth,
int bufferHeight,
int width,
int height,
TextureSettings settings
) {
this.data = data; this.data = data;
this.width = width; this.width = width;
this.height = height; 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_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 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 0, // Not mipmapped
GL_RGBA, // Use RGBA GL_RGBA, // Use RGBA
bufferWidth, // Width bufferWidth, // Width

View File

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

View File

@ -31,7 +31,11 @@ import ru.windcorp.progressia.common.util.BinUtil;
public class TextureLoader { 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); BufferedImage readResult = ImageIO.read(compressed);
int width = readResult.getWidth(); int width = readResult.getWidth();
@ -40,7 +44,10 @@ public class TextureLoader {
int bufferWidth = BinUtil.roundToGreaterPowerOf2(width); int bufferWidth = BinUtil.roundToGreaterPowerOf2(width);
int bufferHeight = BinUtil.roundToGreaterPowerOf2(height); int bufferHeight = BinUtil.roundToGreaterPowerOf2(height);
WritableRaster raster = TextureUtil.createRaster(bufferWidth, bufferHeight); WritableRaster raster = TextureUtil.createRaster(
bufferWidth,
bufferHeight
);
BufferedImage canvas = TextureUtil.createCanvas(raster); BufferedImage canvas = TextureUtil.createCanvas(raster);
@ -49,22 +56,49 @@ public class TextureLoader {
try { try {
g.setColor(TextureUtil.CANVAS_BACKGROUND); g.setColor(TextureUtil.CANVAS_BACKGROUND);
g.fillRect(0, 0, bufferWidth, bufferHeight); g.fillRect(0, 0, bufferWidth, bufferHeight);
g.drawImage(readResult, 0, 0, width, height, 0, height, width, 0, // Flip g.drawImage(
// the readResult,
// image 0,
null); 0,
width,
height,
0,
height,
width,
0, // Flip the image
null
);
} finally { } finally {
g.dispose(); 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; 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); return loadPixels(resource.getInputStream(), settings);
} }

View File

@ -39,8 +39,8 @@ public class TextureUtil {
public static final Color CANVAS_BACKGROUND = new Color(0, true); public static final Color CANVAS_BACKGROUND = new Color(0, true);
public static final ColorModel COLOR_MODEL = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), // Use public static final ColorModel COLOR_MODEL = new ComponentColorModel(
// RGB ColorSpace.getInstance(ColorSpace.CS_sRGB), // Use RGB
null, // Use every bit null, // Use every bit
true, // Has alpha true, // Has alpha
false, // Not premultiplied false, // Not premultiplied
@ -50,9 +50,12 @@ public class TextureUtil {
private static final Hashtable<?, ?> BUFFERED_IMAGE_PROPERTIES = new Hashtable<>(); private static final Hashtable<?, ?> BUFFERED_IMAGE_PROPERTIES = new Hashtable<>();
public static WritableRaster createRaster(int bufferWidth, int bufferHeight) { public static WritableRaster createRaster(
return Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, // Storage int bufferWidth,
// model int bufferHeight
) {
return Raster.createInterleavedRaster(
DataBuffer.TYPE_BYTE, // Storage model
bufferWidth, // Buffer width bufferWidth, // Buffer width
bufferHeight, // Buffer height bufferHeight, // Buffer height
BYTES_PER_PIXEL, // ARGB BYTES_PER_PIXEL, // ARGB
@ -60,7 +63,11 @@ public class TextureUtil {
); );
} }
public static WritableRaster createRaster(ByteBuffer buffer, int bufferWidth, int bufferHeight) { public static WritableRaster createRaster(
ByteBuffer buffer,
int bufferWidth,
int bufferHeight
) {
final int bands = BYTES_PER_PIXEL; final int bands = BYTES_PER_PIXEL;
byte[] bytes = new byte[bufferWidth * bufferHeight * bands]; byte[] bytes = new byte[bufferWidth * bufferHeight * bands];
@ -70,7 +77,8 @@ public class TextureUtil {
DataBufferByte dataBuffer = new DataBufferByte(bytes, bytes.length); DataBufferByte dataBuffer = new DataBufferByte(bytes, bytes.length);
return Raster.createInterleavedRaster(dataBuffer, // The buffer return Raster.createInterleavedRaster(
dataBuffer, // The buffer
bufferWidth, // Buffer width bufferWidth, // Buffer width
bufferHeight, // Buffer height bufferHeight, // Buffer height
bands * bufferWidth, // Scanline stride bands * bufferWidth, // Scanline stride
@ -81,7 +89,8 @@ public class TextureUtil {
} }
public static BufferedImage createCanvas(WritableRaster raster) { public static BufferedImage createCanvas(WritableRaster raster) {
return new BufferedImage(COLOR_MODEL, // Color model return new BufferedImage(
COLOR_MODEL, // Color model
raster, // Backing raster raster, // Backing raster
false, // Raster is not premultipied false, // Raster is not premultipied
BUFFERED_IMAGE_PROPERTIES // Properties BUFFERED_IMAGE_PROPERTIES // Properties
@ -98,7 +107,10 @@ public class TextureUtil {
return buffer; return buffer;
} }
public static ByteBuffer extractBytes(WritableRaster raster, ByteBuffer output) { public static ByteBuffer extractBytes(
WritableRaster raster,
ByteBuffer output
) {
byte[] data = ((DataBufferByte) raster.getDataBuffer()).getData(); byte[] data = ((DataBufferByte) raster.getDataBuffer()).getData();
output.put(data); output.put(data);

View File

@ -44,11 +44,18 @@ public class EntityAnchor implements Anchor {
}), }),
// Third person, looking forward // Third person, looking forward
Mode.of(v -> v.set(-3.5f, +0.5f, 0), m -> { Mode.of(
}), v -> v.set(-3.5f, +0.5f, 0),
m -> {
}
),
// Third person, looking back // Third person, looking back
Mode.of(v -> v.set(-3.5f, 0, 0), m -> m.rotateZ((float) Math.PI))); Mode.of(
v -> v.set(-3.5f, 0, 0),
m -> m.rotateZ((float) Math.PI)
)
);
} }
@Override @Override

View File

@ -76,6 +76,8 @@ public class LayerWorld extends Layer {
@Override @Override
protected void doRender() { protected void doRender() {
client.getComms().processPackets();
Camera camera = client.getCamera(); Camera camera = client.getCamera();
if (camera.hasAnchor()) { if (camera.hasAnchor()) {
renderWorld(); renderWorld();
@ -114,11 +116,11 @@ public class LayerWorld extends Layer {
tmp_testControls.applyPlayerControls(); tmp_testControls.applyPlayerControls();
this.client.getWorld().getData().getEntities().forEach(data -> { for (EntityData data : this.client.getWorld().getData().getEntities()) {
tmp_applyFriction(data, tickLength); tmp_applyFriction(data, tickLength);
tmp_applyGravity(data, tickLength); tmp_applyGravity(data, tickLength);
tmp_renderCollisionModel(data); tmp_renderCollisionModel(data);
}); }
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
System.err.println("OLEGSHA is to blame. Tell him he vry stupiDD!!"); System.err.println("OLEGSHA is to blame. Tell him he vry stupiDD!!");
@ -136,8 +138,12 @@ public class LayerWorld extends Layer {
tmp_collideableList.clear(); tmp_collideableList.clear();
tmp_collideableList.addAll(this.client.getWorld().getData().getEntities()); tmp_collideableList.addAll(this.client.getWorld().getData().getEntities());
Collider.performCollisions(tmp_collideableList, this.client.getWorld().getData(), tickLength, Collider.performCollisions(
tmp_colliderWorkspace); tmp_collideableList,
this.client.getWorld().getData(),
tickLength,
tmp_colliderWorkspace
);
} }
private static final Renderable SELECTION_BOX = tmp_createSelectionBox(); private static final Renderable SELECTION_BOX = tmp_createSelectionBox();
@ -166,14 +172,26 @@ public class LayerWorld extends Layer {
for (float phi = 0; phi < 2 * FloatMathUtil.PI_F; phi += FloatMathUtil.PI_F / 2) { for (float phi = 0; phi < 2 * FloatMathUtil.PI_F; phi += FloatMathUtil.PI_F / 2) {
Mat4 rot = new Mat4().identity().rotateZ(phi).scale(scale); Mat4 rot = new Mat4().identity().rotateZ(phi).scale(scale);
b.addPart(new PppBuilder(p, (Texture) null).setOrigin(new Vec3(-f - 0.5f, -f - 0.5f, -f - 0.5f)) b.addPart(
.setSize(f, f, 2 * f + 1).setColorMultiplier(color).create(), rot); new PppBuilder(p, (Texture) null).setOrigin(
new Vec3(-f - 0.5f, -f - 0.5f, -f - 0.5f)
).setSize(f, f, 2 * f + 1).setColorMultiplier(color).create(),
rot
);
b.addPart(new PppBuilder(p, (Texture) null).setOrigin(new Vec3(-f - 0.5f, -0.5f, -f - 0.5f)) b.addPart(
.setSize(f, 1, f).setColorMultiplier(color).create(), rot); new PppBuilder(p, (Texture) null).setOrigin(
new Vec3(-f - 0.5f, -0.5f, -f - 0.5f)
).setSize(f, 1, f).setColorMultiplier(color).create(),
rot
);
b.addPart(new PppBuilder(p, (Texture) null).setOrigin(new Vec3(-f - 0.5f, -0.5f, +0.5f)).setSize(f, 1, f) b.addPart(
.setColorMultiplier(color).create(), rot); new PppBuilder(p, (Texture) null).setOrigin(
new Vec3(-f - 0.5f, -0.5f, +0.5f)
).setSize(f, 1, f).setColorMultiplier(color).create(),
rot
);
} }
return b.build(); return b.build();

View File

@ -24,7 +24,10 @@ import ru.windcorp.progressia.common.util.StashingStack;
public class WorldRenderHelper extends ShapeRenderHelper { public class WorldRenderHelper extends ShapeRenderHelper {
private final StashingStack<Mat4> viewTransformStack = new StashingStack<>(TRANSFORM_STACK_SIZE, Mat4::new); private final StashingStack<Mat4> viewTransformStack = new StashingStack<>(
TRANSFORM_STACK_SIZE,
Mat4::new
);
{ {
viewTransformStack.push().identity(); viewTransformStack.push().identity();

View File

@ -44,8 +44,10 @@ public class WorldRenderProgram extends ShapeRenderProgram {
private static WorldRenderProgram def = null; private static WorldRenderProgram def = null;
public static void init() { public static void init() {
def = new WorldRenderProgram(new String[] { "WorldDefault.vertex.glsl" }, def = new WorldRenderProgram(
new String[] { "WorldDefault.fragment.glsl" }); new String[] { "WorldDefault.vertex.glsl" },
new String[] { "WorldDefault.fragment.glsl" }
);
} }
public static WorldRenderProgram getDefault() { public static WorldRenderProgram getDefault() {
@ -66,12 +68,20 @@ public class WorldRenderProgram extends ShapeRenderProgram {
private final Uniform4Matrix worldTransformUniform; private final Uniform4Matrix worldTransformUniform;
private final AttributeVertexArray normalsAttribute; private final AttributeVertexArray normalsAttribute;
public WorldRenderProgram(String[] vertexShaderResources, String[] fragmentShaderResources) { public WorldRenderProgram(
super(attachVertexShader(vertexShaderResources), attachFragmentShader(fragmentShaderResources)); String[] vertexShaderResources,
String[] fragmentShaderResources
) {
super(
attachVertexShader(vertexShaderResources),
attachFragmentShader(fragmentShaderResources)
);
this.worldTransformUniform = getUniform(WORLD_TRANSFORM_UNIFORM_NAME).as4Matrix(); this.worldTransformUniform = getUniform(WORLD_TRANSFORM_UNIFORM_NAME)
.as4Matrix();
this.normalsAttribute = getAttribute(NORMALS_ATTRIBUTE_NAME).asVertexArray(); this.normalsAttribute = getAttribute(NORMALS_ATTRIBUTE_NAME)
.asVertexArray();
} }
private static String[] attachVertexShader(String[] others) { private static String[] attachVertexShader(String[] others) {
@ -93,7 +103,14 @@ public class WorldRenderProgram extends ShapeRenderProgram {
int vertexStride = getBytesPerVertex(); int vertexStride = getBytesPerVertex();
int offset = super.bindVertices(vertices); int offset = super.bindVertices(vertices);
normalsAttribute.set(3, GL11.GL_FLOAT, false, vertexStride, vertices, offset); normalsAttribute.set(
3,
GL11.GL_FLOAT,
false,
vertexStride,
vertices,
offset
);
offset += 3 * Float.BYTES; offset += 3 * Float.BYTES;
return offset; return offset;
@ -113,7 +130,8 @@ public class WorldRenderProgram extends ShapeRenderProgram {
@Override @Override
public int getBytesPerVertex() { public int getBytesPerVertex() {
return super.getBytesPerVertex() + 3 * Float.BYTES; // Normals return super.getBytesPerVertex() +
3 * Float.BYTES; // Normals
} }
@Override @Override
@ -153,7 +171,12 @@ public class WorldRenderProgram extends ShapeRenderProgram {
Vectors.release(normal); Vectors.release(normal);
} }
private void computeOneNormal(Vec3 a, Vec3 b, Vec3 c, Vec3 normal) { private void computeOneNormal(
Vec3 a,
Vec3 b,
Vec3 c,
Vec3 normal
) {
b.sub(a); b.sub(a);
c.sub(a); c.sub(a);
b.cross(c, normal); b.cross(c, normal);
@ -164,14 +187,18 @@ public class WorldRenderProgram extends ShapeRenderProgram {
ByteBuffer vertices = face.getVertices(); ByteBuffer vertices = face.getVertices();
int offset = vertices.position() + index * getBytesPerVertex(); int offset = vertices.position() + index * getBytesPerVertex();
result.set(vertices.getFloat(offset + 0 * Float.BYTES), vertices.getFloat(offset + 1 * Float.BYTES), result.set(
vertices.getFloat(offset + 2 * Float.BYTES)); vertices.getFloat(offset + 0 * Float.BYTES),
vertices.getFloat(offset + 1 * Float.BYTES),
vertices.getFloat(offset + 2 * Float.BYTES)
);
} }
private void saveVertexNormal(ShapePart face, int index, Vec3 normal) { private void saveVertexNormal(ShapePart face, int index, Vec3 normal) {
ByteBuffer vertices = face.getVertices(); ByteBuffer vertices = face.getVertices();
int offset = vertices.position() + index * getBytesPerVertex() int offset = vertices.position() + index * getBytesPerVertex() + (3 * Float.BYTES +
+ (3 * Float.BYTES + 4 * Float.BYTES + 2 * Float.BYTES); 4 * Float.BYTES +
2 * Float.BYTES);
vertices.putFloat(offset + 0 * Float.BYTES, normal.x); vertices.putFloat(offset + 0 * Float.BYTES, normal.x);
vertices.putFloat(offset + 1 * Float.BYTES, normal.y); vertices.putFloat(offset + 1 * Float.BYTES, normal.y);
@ -204,36 +231,87 @@ public class WorldRenderProgram extends ShapeRenderProgram {
private final List<Vertex> vertices = new ArrayList<>(); private final List<Vertex> vertices = new ArrayList<>();
@Override @Override
public VertexBuilder addVertex(float x, float y, float z, float r, float g, float b, float tx, float ty) { public VertexBuilder addVertex(
vertices.add(new Vertex(new Vec3(x, y, z), new Vec4(r, g, b, 1), new Vec2(tx, ty))); 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, 1),
new Vec2(tx, ty)
)
);
return this; return this;
} }
@Override @Override
public VertexBuilder addVertex(float x, float y, float z, float r, float g, float b, float a, float tx, public VertexBuilder addVertex(
float ty) { float x,
vertices.add(new Vertex(new Vec3(x, y, z), new Vec4(r, g, b, a), new Vec2(tx, ty))); 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; return this;
} }
@Override @Override
public VertexBuilder addVertex(Vec3 position, Vec4 colorMultiplier, Vec2 textureCoords) { public VertexBuilder addVertex(
vertices.add(new Vertex(new Vec3(position), new Vec4(colorMultiplier), new Vec2(textureCoords))); Vec3 position,
Vec4 colorMultiplier,
Vec2 textureCoords
) {
vertices.add(
new Vertex(
new Vec3(position),
new Vec4(colorMultiplier),
new Vec2(textureCoords)
)
);
return this; return this;
} }
@Override @Override
public ByteBuffer assemble() { 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) { for (Vertex v : vertices) {
result.putFloat(v.position.x).putFloat(v.position.y).putFloat(v.position.z) result
.putFloat(v.colorMultiplier.x).putFloat(v.colorMultiplier.y).putFloat(v.colorMultiplier.z) .putFloat(v.position.x)
.putFloat(v.colorMultiplier.w).putFloat(v.textureCoords.x).putFloat(v.textureCoords.y) .putFloat(v.position.y)
.putFloat(Float.NaN).putFloat(Float.NaN).putFloat(Float.NaN); .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)
.putFloat(Float.NaN)
.putFloat(Float.NaN)
.putFloat(Float.NaN);
} }
result.flip(); result.flip();

View File

@ -30,7 +30,8 @@ import java.util.Map;
public class Parser { public class Parser {
private String filePath; private String filePath;
static private final Escaper ESCAPER = new Escaper.EscaperBuilder().withChars("n", "\n").build(); static private final Escaper ESCAPER = new Escaper.EscaperBuilder()
.withChars("n", "\n").build();
public Parser(String filePath) { public Parser(String filePath) {
this.filePath = filePath; this.filePath = filePath;
@ -42,7 +43,11 @@ public class Parser {
public Map<String, String> parse() { public Map<String, String> parse() {
Map<String, String> parsedData = new HashMap<>(); Map<String, String> parsedData = new HashMap<>();
try (Reader rawData = ResourceManager.getResource(filePath).getReader()) { try (
Reader rawData = ResourceManager
.getResource(filePath)
.getReader()
) {
int code; int code;
char c; char c;
StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder = new StringBuilder();
@ -83,7 +88,10 @@ public class Parser {
stringBuilder.append(c); stringBuilder.append(c);
} }
} }
parsedData.put(ESCAPER.unescape(key), ESCAPER.unescape(stringBuilder.toString())); parsedData.put(
ESCAPER.unescape(key),
ESCAPER.unescape(stringBuilder.toString())
);
stringBuilder.setLength(0); stringBuilder.setLength(0);
} }
} else if (c == '\n') { } else if (c == '\n') {

View File

@ -37,7 +37,11 @@ public class BlockRenderRegistry extends NamespacedInstanceRegistry<BlockRender>
public static Texture getBlockTexture(String name) { public static Texture getBlockTexture(String name) {
return new SimpleTexture( return new SimpleTexture(
Atlases.getSprite(ResourceManager.getTextureResource("blocks/" + name), BLOCKS_ATLAS_GROUP)); Atlases.getSprite(
ResourceManager.getTextureResource("blocks/" + name),
BLOCKS_ATLAS_GROUP
)
);
} }
public static AtlasGroup getBlocksAtlasGroup() { public static AtlasGroup getBlocksAtlasGroup() {

View File

@ -0,0 +1,99 @@
/*
* 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.world.cro;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Consumer;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.client.graphics.backend.Usage;
import ru.windcorp.progressia.client.graphics.model.Renderable;
import ru.windcorp.progressia.client.graphics.model.Shape;
import ru.windcorp.progressia.client.graphics.model.ShapePart;
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
import ru.windcorp.progressia.client.world.block.BlockRender;
import ru.windcorp.progressia.client.world.tile.TileRender;
import ru.windcorp.progressia.common.world.DefaultChunkData;
import ru.windcorp.progressia.common.world.rels.RelFace;
public class ChunkRenderOptimizerSimple extends ChunkRenderOptimizer {
public interface BlockOptimizedSimple {
void getShapeParts(
DefaultChunkData chunk,
Vec3i relBlockInChunk,
Consumer<ShapePart> output
);
}
public interface TileOptimizedCustom {
void getShapeParts(
DefaultChunkData chunk,
Vec3i relBlockInChunk,
RelFace blockFace,
Consumer<ShapePart> output
);
}
private final Collection<ShapePart> parts = new ArrayList<>();
private final Consumer<ShapePart> partAdder = parts::add;
public ChunkRenderOptimizerSimple(String id) {
super(id);
}
@Override
public void startRender() {
parts.clear();
}
@Override
public void addBlock(BlockRender block, Vec3i relBlockInChunk) {
if (block instanceof BlockOptimizedSimple) {
((BlockOptimizedSimple) block).getShapeParts(chunk.getData(), relBlockInChunk, partAdder);
}
}
@Override
public void addTile(TileRender tile, Vec3i relBlockInChunk, RelFace blockFace) {
if (tile instanceof TileOptimizedCustom) {
((TileOptimizedCustom) tile).getShapeParts(chunk.getData(), relBlockInChunk, blockFace, partAdder);
}
}
@Override
public Renderable endRender() {
if (parts.isEmpty()) {
return null;
}
return new Shape(
Usage.STATIC,
WorldRenderProgram.getDefault(),
parts.toArray(new ShapePart[parts.size()])
);
}
}

View File

@ -37,9 +37,14 @@ public class EntityRenderRegistry extends NamespacedInstanceRegistry<EntityRende
public static TexturePrimitive getEntityTexture(String name) { public static TexturePrimitive getEntityTexture(String name) {
try { try {
return new TexturePrimitive(TextureLoader return new TexturePrimitive(
.loadPixels(ResourceManager.getTextureResource("entities/" + name), new TextureSettings(false)) TextureLoader.loadPixels(
.getData()); ResourceManager.getTextureResource(
"entities/" + name
),
new TextureSettings(false)
).getData()
);
} catch (IOException e) { } catch (IOException e) {
throw CrashReports.report(e, "Could not load entity texture %s", name); throw CrashReports.report(e, "Could not load entity texture %s", name);
} }

View File

@ -32,7 +32,11 @@ public class HumanoidModel extends NPedModel {
protected static abstract class Limb extends BodyPart { protected static abstract class Limb extends BodyPart {
private final float animationOffset; private final float animationOffset;
public Limb(Renderable renderable, Vec3 joint, float animationOffset) { public Limb(
Renderable renderable,
Vec3 joint,
float animationOffset
) {
super(renderable, joint); super(renderable, joint);
this.animationOffset = animationOffset; this.animationOffset = animationOffset;
} }
@ -51,7 +55,11 @@ public class HumanoidModel extends NPedModel {
} }
public static class Leg extends Limb { public static class Leg extends Limb {
public Leg(Renderable renderable, Vec3 joint, float animationOffset) { public Leg(
Renderable renderable,
Vec3 joint,
float animationOffset
) {
super(renderable, joint, animationOffset); super(renderable, joint, animationOffset);
} }
@ -62,7 +70,11 @@ public class HumanoidModel extends NPedModel {
} }
public static class Arm extends Limb { public static class Arm extends Limb {
public Arm(Renderable renderable, Vec3 joint, float animationOffset) { public Arm(
Renderable renderable,
Vec3 joint,
float animationOffset
) {
super(renderable, joint, animationOffset); super(renderable, joint, animationOffset);
} }
@ -80,11 +92,18 @@ public class HumanoidModel extends NPedModel {
private float walkingLegSwing; private float walkingLegSwing;
private float walkingArmSwing; private float walkingArmSwing;
public HumanoidModel(EntityData entity, public HumanoidModel(
EntityData entity,
Body body, Head head, Arm leftArm, Arm rightArm, Leg leftLeg, Leg rightLeg, Body body,
Head head,
Arm leftArm,
Arm rightArm,
Leg leftLeg,
Leg rightLeg,
float scale) { float scale
) {
super(entity, body, head, scale); super(entity, body, head, scale);
this.leftArm = leftArm; this.leftArm = leftArm;
this.rightArm = rightArm; this.rightArm = rightArm;

View File

@ -33,7 +33,11 @@ public class QuadripedModel extends NPedModel {
public static class Leg extends BodyPart { public static class Leg extends BodyPart {
private final float animationOffset; private final float animationOffset;
public Leg(Renderable renderable, Vec3 joint, float animationOffset) { public Leg(
Renderable renderable,
Vec3 joint,
float animationOffset
) {
super(renderable, joint); super(renderable, joint);
this.animationOffset = animationOffset; this.animationOffset = animationOffset;
} }
@ -54,11 +58,18 @@ public class QuadripedModel extends NPedModel {
private float walkingSwing = (float) toRadians(30); private float walkingSwing = (float) toRadians(30);
public QuadripedModel(EntityData entity, public QuadripedModel(
EntityData entity,
Body body, Head head, Leg leftForeLeg, Leg rightForeLeg, Leg leftHindLeg, Leg rightHindLeg, Body body,
Head head,
Leg leftForeLeg,
Leg rightForeLeg,
Leg leftHindLeg,
Leg rightHindLeg,
float scale) { float scale
) {
super(entity, body, head, scale); super(entity, body, head, scale);
this.leftForeLeg = leftForeLeg; this.leftForeLeg = leftForeLeg;

View File

@ -0,0 +1,170 @@
/*
* 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.world.tile;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Consumer;
import glm.mat._3.Mat3;
import glm.mat._4.Mat4;
import glm.vec._3.Vec3;
import glm.vec._3.i.Vec3i;
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.Renderable;
import ru.windcorp.progressia.client.graphics.model.Shape;
import ru.windcorp.progressia.client.graphics.model.ShapePart;
import ru.windcorp.progressia.client.graphics.model.ShapeParts;
import ru.windcorp.progressia.client.graphics.texture.Texture;
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSimple.TileOptimizedCustom;
import ru.windcorp.progressia.common.util.Matrices;
import ru.windcorp.progressia.common.util.VectorUtil;
import ru.windcorp.progressia.common.util.Vectors;
import ru.windcorp.progressia.common.world.DefaultChunkData;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.AxisRotations;
import ru.windcorp.progressia.common.world.rels.RelFace;
public class TileRenderCross extends TileRender implements TileOptimizedCustom {
private static final float SQRT_2_OVER_2 = (float) Math.sqrt(2) / 2;
private static final float[] ONE_AND_NEGATIVE_ONE = new float[] { 1, -1 };
private final Texture texture;
private final float width;
public TileRenderCross(String id, Texture texture, boolean allowStretching) {
super(id);
this.texture = texture;
this.width = allowStretching ? 1 : SQRT_2_OVER_2;
}
public Texture getTexture(RelFace blockFace) {
return texture;
}
public Vec4 getColorMultiplier(RelFace blockFace) {
return Colors.WHITE;
}
@Override
public void getShapeParts(
DefaultChunkData chunk,
Vec3i bic,
RelFace blockFace,
Consumer<ShapePart> output
) {
Mat4 transform = Matrices.grab4();
Vec3 origin = Vectors.grab3();
Vec3 width = Vectors.grab3();
Vec3 height = Vectors.grab3();
Mat3 resolutionMatrix = AxisRotations.getResolutionMatrix3(blockFace.resolve(AbsFace.POS_Z));
Vec4 color = getColorMultiplier(blockFace);
Texture texture = getTexture(blockFace);
float originOffset = (1 - this.width) / 2;
WorldRenderProgram program = WorldRenderProgram.getDefault();
for (int i = 0; getTransform(chunk, bic, blockFace, i, transform); i++) {
for (float flip : ONE_AND_NEGATIVE_ONE) {
origin.set(flip * (originOffset - 0.5f), originOffset - 0.5f, 0);
width.set(flip * this.width, this.width, 0);
height.set(0, 0, 1);
VectorUtil.applyMat4(origin, transform);
VectorUtil.rotateOnly(width, transform);
VectorUtil.rotateOnly(height, transform);
origin.z += 1 - 0.5f;
if (blockFace != RelFace.UP) {
resolutionMatrix.mul(origin);
resolutionMatrix.mul(width);
resolutionMatrix.mul(height);
}
origin.add(bic.x, bic.y, bic.z);
output.accept(
ShapeParts.createRectangle(
program,
texture,
color,
origin,
width,
height,
false
)
);
output.accept(
ShapeParts.createRectangle(
program,
texture,
color,
origin,
width,
height,
true
)
);
}
}
Matrices.release(transform);
Vectors.release(origin);
Vectors.release(width);
Vectors.release(height);
}
protected boolean getTransform(
DefaultChunkData chunk,
Vec3i relBlockInChunk,
RelFace blockFace,
int count,
Mat4 output
) {
output.identity();
return count == 0;
}
@Override
public Renderable createRenderable(DefaultChunkData chunk, Vec3i blockInChunk, RelFace blockFace) {
Collection<ShapePart> parts = new ArrayList<>(4);
getShapeParts(chunk, blockInChunk, blockFace, parts::add);
return new Shape(
Usage.STATIC,
WorldRenderProgram.getDefault(),
parts.toArray(new ShapePart[parts.size()])
);
}
@Override
public boolean needsOwnRenderable() {
return false;
}
}

View File

@ -41,7 +41,11 @@ public class TileRenderRegistry extends NamespacedInstanceRegistry<TileRender> {
public static Texture getTileTexture(String name) { public static Texture getTileTexture(String name) {
return new SimpleTexture( return new SimpleTexture(
Atlases.getSprite(ResourceManager.getTextureResource("tiles/" + name), TILES_ATLAS_GROUP)); Atlases.getSprite(
ResourceManager.getTextureResource("tiles/" + name),
TILES_ATLAS_GROUP
)
);
} }
} }

View File

@ -112,9 +112,12 @@ public class Units {
private static final TCharFloatMap PREFIXES_BY_CHAR; private static final TCharFloatMap PREFIXES_BY_CHAR;
static { static {
TCharFloatMap prefixes = new TCharFloatHashMap(gnu.trove.impl.Constants.DEFAULT_CAPACITY, TCharFloatMap prefixes = new TCharFloatHashMap(
gnu.trove.impl.Constants.DEFAULT_LOAD_FACTOR, gnu.trove.impl.Constants.DEFAULT_CHAR_NO_ENTRY_VALUE, gnu.trove.impl.Constants.DEFAULT_CAPACITY,
Float.NaN); gnu.trove.impl.Constants.DEFAULT_LOAD_FACTOR,
gnu.trove.impl.Constants.DEFAULT_CHAR_NO_ENTRY_VALUE,
Float.NaN
);
prefixes.put('G', 1e+9f); prefixes.put('G', 1e+9f);
prefixes.put('M', 1e+6f); prefixes.put('M', 1e+6f);
@ -130,8 +133,13 @@ public class Units {
private static final TObjectFloatMap<String> KNOWN_UNITS = createMap(); private static final TObjectFloatMap<String> KNOWN_UNITS = createMap();
private static TObjectFloatMap<String> createMap() { private static TObjectFloatMap<String> createMap() {
return TCollections.synchronizedMap(new TObjectFloatHashMap<>(gnu.trove.impl.Constants.DEFAULT_CAPACITY, return TCollections.synchronizedMap(
gnu.trove.impl.Constants.DEFAULT_LOAD_FACTOR, Float.NaN)); new TObjectFloatHashMap<>(
gnu.trove.impl.Constants.DEFAULT_CAPACITY,
gnu.trove.impl.Constants.DEFAULT_LOAD_FACTOR,
Float.NaN
)
);
} }
public static void registerUnits(Class<?> source) throws IllegalAccessException { public static void registerUnits(Class<?> source) throws IllegalAccessException {
@ -202,9 +210,9 @@ public class Units {
* parenthesis are allowed at all. As such, * parenthesis are allowed at all. As such,
* <ul> * <ul>
* <li>Multiple units under the division bar should be located after the * <li>Multiple units under the division bar should be located after the
* single {@code '/'} and separated by {@code '*'}: <a * single {@code '/'} and separated by {@code '*'}:
* href=https://en.wikipedia.org/wiki/Gas_constant>gas constant</a> ought to * <a href=https://en.wikipedia.org/wiki/Gas_constant>gas constant</a> ought
* have {@code "J/K*mol"} units.</li> * to have {@code "J/K*mol"} units.</li>
* <li>Exponentiation of parenthesis should be expanded: (m/s)² = * <li>Exponentiation of parenthesis should be expanded: (m/s)² =
* {@code "m^2/s^2"}.</li> * {@code "m^2/s^2"}.</li>
* <li>Exponents should also be used for expressing roots: √s = * <li>Exponents should also be used for expressing roots: √s =
@ -213,10 +221,8 @@ public class Units {
* discouraged.</li> * discouraged.</li>
* </ul> * </ul>
* *
* @param unit * @param unit unit declaration
* unit declaration * @throws IllegalArgumentException if the declaration is invalid
* @throws IllegalArgumentException
* if the declaration is invalid
* @return the value of the unit * @return the value of the unit
* @see #get(String) get(String) * @see #get(String) get(String)
* @see #registerUnit(float, String...) * @see #registerUnit(float, String...)

View File

@ -21,7 +21,8 @@ package ru.windcorp.progressia.common.collision;
import glm.vec._3.Vec3; import glm.vec._3.Vec3;
/** /**
* An implementation of an <a href= * An implementation of an
* <a href=
* "https://en.wikipedia.org/wiki/Minimum_bounding_box#Axis-aligned_minimum_bounding_box">Axis-Aligned * "https://en.wikipedia.org/wiki/Minimum_bounding_box#Axis-aligned_minimum_bounding_box">Axis-Aligned
* Bounding Box</a>. * Bounding Box</a>.
* *
@ -35,7 +36,17 @@ public class AABB implements AABBoid {
private final Vec3 widthSelector = new Vec3(); private final Vec3 widthSelector = new Vec3();
private final Vec3 heightSelector = new Vec3(); private final Vec3 heightSelector = new Vec3();
public AABBWallImpl(float ox, float oy, float oz, float wx, float wy, float wz, float hx, float hy, float hz) { public AABBWallImpl(
float ox,
float oy,
float oz,
float wx,
float wy,
float wz,
float hx,
float hy,
float hz
) {
this.originOffset.set(ox, oy, oz); this.originOffset.set(ox, oy, oz);
this.widthSelector.set(wx, wy, wz); this.widthSelector.set(wx, wy, wz);
this.heightSelector.set(hx, hy, hz); this.heightSelector.set(hx, hy, hz);
@ -60,7 +71,8 @@ public class AABB implements AABBoid {
public static final AABB UNIT_CUBE = new AABB(0, 0, 0, 1, 1, 1); public static final AABB UNIT_CUBE = new AABB(0, 0, 0, 1, 1, 1);
private final Wall[] walls = new Wall[] { new AABBWallImpl(-0.5f, -0.5f, +0.5f, +1, 0, 0, 0, +1, 0), // Top private final Wall[] walls = new Wall[] {
new AABBWallImpl(-0.5f, -0.5f, +0.5f, +1, 0, 0, 0, +1, 0), // Top
new AABBWallImpl(-0.5f, -0.5f, -0.5f, 0, +1, 0, +1, 0, 0), // Bottom new AABBWallImpl(-0.5f, -0.5f, -0.5f, 0, +1, 0, +1, 0, 0), // Bottom
new AABBWallImpl(+0.5f, -0.5f, -0.5f, 0, +1, 0, 0, 0, +1), // North new AABBWallImpl(+0.5f, -0.5f, -0.5f, 0, +1, 0, 0, 0, +1), // North
new AABBWallImpl(-0.5f, +0.5f, -0.5f, 0, -1, 0, 0, 0, +1), // South new AABBWallImpl(-0.5f, +0.5f, -0.5f, 0, -1, 0, 0, 0, +1), // South
@ -75,7 +87,14 @@ public class AABB implements AABBoid {
this(origin.x, origin.y, origin.z, size.x, size.y, size.z); this(origin.x, origin.y, origin.z, size.x, size.y, size.z);
} }
public AABB(float ox, float oy, float oz, float xSize, float ySize, float zSize) { public AABB(
float ox,
float oy,
float oz,
float xSize,
float ySize,
float zSize
) {
this.origin.set(ox, oy, oz); this.origin.set(ox, oy, oz);
this.size.set(xSize, ySize, zSize); this.size.set(xSize, ySize, zSize);
} }

View File

@ -26,11 +26,10 @@ public interface Collideable {
CollisionModel getCollisionModel(); CollisionModel getCollisionModel();
/** /**
* Invoked by {@link Collider} when two entities are about to collide. The * Invoked by {@link Collider} when two entities are about to collide.
* world is at the moment of collision. * The world is at the moment of collision.
* *
* @param other * @param other the colliding object
* the colliding object
* @return {@code true} iff the collision should not be handled normally * @return {@code true} iff the collision should not be handled normally
* (e.g. this object has disappeared) * (e.g. this object has disappeared)
*/ */
@ -38,8 +37,8 @@ public interface Collideable {
/** /**
* Returns the mass of this {@link Collideable} that should be used to * Returns the mass of this {@link Collideable} that should be used to
* calculate collisions. Collision mass must be a positive number. Positive * calculate collisions.
* infinity is allowed. * Collision mass must be a positive number. Positive infinity is allowed.
* *
* @return this object's collision mass * @return this object's collision mass
*/ */

View File

@ -30,7 +30,11 @@ public class CollisionPathComputer {
private static final float PADDING = 0.5f; private static final float PADDING = 0.5f;
public static void forEveryBlockInCollisionPath(Collideable coll, float maxTime, Consumer<Vec3i> action) { public static void forEveryBlockInCollisionPath(
Collideable coll,
float maxTime,
Consumer<Vec3i> action
) {
Vec3 displacement = Vectors.grab3(); Vec3 displacement = Vectors.grab3();
coll.getCollideableVelocity(displacement); coll.getCollideableVelocity(displacement);
displacement.mul(maxTime); displacement.mul(maxTime);
@ -40,7 +44,11 @@ public class CollisionPathComputer {
Vectors.release(displacement); Vectors.release(displacement);
} }
private static void handleModel(CollisionModel model, Vec3 displacement, Consumer<Vec3i> action) { private static void handleModel(
CollisionModel model,
Vec3 displacement,
Consumer<Vec3i> action
) {
if (model instanceof CompoundCollisionModel) { if (model instanceof CompoundCollisionModel) {
for (CollisionModel subModel : ((CompoundCollisionModel) model).getModels()) { for (CollisionModel subModel : ((CompoundCollisionModel) model).getModels()) {
handleModel(subModel, displacement, action); handleModel(subModel, displacement, action);
@ -63,13 +71,21 @@ public class CollisionPathComputer {
Vec3i pos = Vectors.grab3i(); Vec3i pos = Vectors.grab3i();
for (pos.x = (int) floor(origin.x + min(0, size.x) + min(0, displacement.x) - PADDING); pos.x <= (int) ceil( for (
origin.x + max(0, size.x) + max(0, displacement.x) + PADDING); pos.x += 1) { pos.x = (int) floor(origin.x + min(0, size.x) + min(0, displacement.x) - PADDING);
for (pos.y = (int) floor(origin.y + min(0, size.y) + min(0, displacement.y) - PADDING); pos.y <= (int) ceil( pos.x <= (int) ceil(origin.x + max(0, size.x) + max(0, displacement.x) + PADDING);
origin.y + max(0, size.y) + max(0, displacement.y) + PADDING); pos.y += 1) { pos.x += 1
for (pos.z = (int) floor( ) {
origin.z + min(0, size.z) + min(0, displacement.z) - PADDING); pos.z <= (int) ceil( for (
origin.z + max(0, size.z) + max(0, displacement.z) + PADDING); pos.z += 1) { pos.y = (int) floor(origin.y + min(0, size.y) + min(0, displacement.y) - PADDING);
pos.y <= (int) ceil(origin.y + max(0, size.y) + max(0, displacement.y) + PADDING);
pos.y += 1
) {
for (
pos.z = (int) floor(origin.z + min(0, size.z) + min(0, displacement.z) - PADDING);
pos.z <= (int) ceil(origin.z + max(0, size.z) + max(0, displacement.z) + PADDING);
pos.z += 1
) {
action.accept(pos); action.accept(pos);
} }
} }

View File

@ -68,22 +68,25 @@ public class WorldCollisionHelper {
/** /**
* Changes the state of this helper's {@link #getCollideable()} so it is * Changes the state of this helper's {@link #getCollideable()} so it is
* ready to adequately handle collisions with the {@code collideable} that * ready to adequately handle
* might happen in the next {@code maxTime} seconds. This helper is only * collisions with the {@code collideable} that might happen in the next
* valid for checking collisions with the given Collideable and only within * {@code maxTime} seconds.
* This helper is only valid for checking collisions with the given
* Collideable and only within
* the given time limit. * the given time limit.
* *
* @param collideable * @param collideable the {@link Collideable} that collisions will be
* the {@link Collideable} that collisions will be checked * checked against
* against * @param maxTime maximum collision time
* @param maxTime
* maximum collision time
*/ */
public void tuneToCollideable(DefaultWorldData world, Collideable collideable, float maxTime) { public void tuneToCollideable(DefaultWorldData world, Collideable collideable, float maxTime) {
activeBlockModels.forEach(blockModelCache::release); activeBlockModels.forEach(blockModelCache::release);
activeBlockModels.clear(); activeBlockModels.clear();
CollisionPathComputer.forEveryBlockInCollisionPath(collideable, maxTime, CollisionPathComputer.forEveryBlockInCollisionPath(
v -> addModel(world.getCollisionModelOfBlock(v), v)); collideable,
maxTime,
v -> addModel(world.getCollisionModelOfBlock(v), v)
);
} }
private void addModel(CollisionModel model, Vec3i pos) { private void addModel(CollisionModel model, Vec3i pos) {

View File

@ -26,13 +26,26 @@ import ru.windcorp.progressia.common.collision.colliders.Collider.Collision;
class AnythingWithCompoundCollider { class AnythingWithCompoundCollider {
static Collider.Collision computeModelCollision(Collideable aBody, Collideable bBody, CompoundCollisionModel aModel, static Collider.Collision computeModelCollision(
CollisionModel bModel, float tickLength, ColliderWorkspace workspace) { Collideable aBody,
Collideable bBody,
CompoundCollisionModel aModel,
CollisionModel bModel,
float tickLength,
ColliderWorkspace workspace
) {
Collision result = null; Collision result = null;
for (CollisionModel aModelPart : aModel.getModels()) { for (CollisionModel aModelPart : aModel.getModels()) {
Collision collision = Collider.getCollision(aBody, bBody, aModelPart, bModel, tickLength, workspace); Collision collision = Collider.getCollision(
aBody,
bBody,
aModelPart,
bModel,
tickLength,
workspace
);
// Update result // Update result
if (collision != null) { if (collision != null) {

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