TPL refactor, unified line endings, JavaDoc and full switch to SmartSeverity

This commit is contained in:
Tefek 2020-09-08 23:32:20 +02:00
parent 60fae86237
commit 2b065249ee
64 changed files with 4471 additions and 4306 deletions

View File

@ -51,6 +51,7 @@ version numbers.*
### Normal priority ### Normal priority
* The collision system for PlutoStatic * The collision system for PlutoStatic
* Improve image loading capabilities, possibly rewrite PlutoLib#TPL
### Low priority ### Low priority
* Polishing PlutoLib * Polishing PlutoLib

View File

@ -7,5 +7,21 @@
* `Logger`'s output filenames now look cleaner with `log--YYYY-MM-DD--HH-MM-SS.txt` * `Logger`'s output filenames now look cleaner with `log--YYYY-MM-DD--HH-MM-SS.txt`
* `[Logger#setup]` can now throw `IOException` * `[Logger#setup]` can now throw `IOException`
* `[PlutoCore]` As a result, `[PlutoApplication#run]` can now throw `Exception` * `[PlutoCore]` As a result, `[PlutoApplication#run]` can now throw `Exception`
* `[PlutoLib]` Updated JavaDoc in `ResourceAddress`, `TPL`, `TPNImage`
* `[PlutoLib]` Added `ResourceAddress#openRead` and `ResourceAddress#openWrite`
* `[PlutoLib]` Code cleanup in `MiniTime`, `TPL`
* `[PlutoLib]` Deprecated `TPL#load(String)` in favor of `TPL#load(ResourceAddress)`,
`TPL#load(File)` and `TPL#load(Path)`
* `[PlutoTexturing]` Deprecated the `String` variant of `Texture#load`
to reflect this change
* `[PlutoSpritesheet]` Removed the usage of this method
in `DisposablePlaceholderSprite`
* `[PlutoLib]` Added an option to flip loaded images with `TPL#loadImageSpecial`
and added respective `TPL#loadSpecial` for every `TPL#load`
* `[PlutoLib]` *Removed* `TPJImage`
* `[PlutoLib]` Removed `TPL#loadPixels`
* `[PlutoCore]` Updated `GLFWImageUtil` to remove the usage of `TPJImage`
* `[PlutoCore]` `[PlutoApplication]` now properly closes the `Logger` on exit * `[PlutoCore]` `[PlutoApplication]` now properly closes the `Logger` on exit
* `[PlutoLib]` Various typo fixes * `[PlutoLib]` Various typo fixes
* `[Pluto*]` Deprecated `Severity` for `SmartSeverity` and replaced all usages
* `[Pluto*]` Deprecated `CRLF` with `LF` in all Java source files

View File

@ -48,8 +48,6 @@ public class CursorPositionCallback extends GLFWCursorPosCallback
public boolean isInside(int x, int y, int x2, int y2) public boolean isInside(int x, int y, int x2, int y2)
{ {
boolean inside = this.getX() > x && this.getX() < x2 && this.getY() > y && this.getY() < y2; return this.getX() > x && this.getX() < x2 && this.getY() > y && this.getY() < y2;
return inside;
} }
} }

View File

@ -1,5 +1,12 @@
package cz.tefek.pluto; package cz.tefek.pluto;
/**
* Constants shared by all Pluto libraries.
*
* @since pre-alpha
*
* @author 493msi
*/
public class Pluto public class Pluto
{ {
public static final boolean DEBUG_MODE = Boolean.valueOf(System.getProperty("cz.tefek.pluto.debug")); public static final boolean DEBUG_MODE = Boolean.valueOf(System.getProperty("cz.tefek.pluto.debug"));
@ -8,41 +15,57 @@ public class Pluto
/** /**
* The year version number, changes with breaking API changes. * The year version number, changes with breaking API changes.
*
* @since pre-alpha
* */ * */
public static final int VERSION_YEAR = 20; public static final int VERSION_YEAR = 20;
/** /**
* The major version number, changes with breaking API changes. * The major version number, changes with breaking API changes.
*
* @since pre-alpha
* */ * */
public static final int VERSION_MAJOR = 2; public static final int VERSION_MAJOR = 2;
/** /**
* The minor version number, changes with backwards-compatible API changes. * The minor version number, changes with backwards-compatible API changes.
*
* @since pre-alpha
* */ * */
public static final int VERSION_MINOR = 0; public static final int VERSION_MINOR = 0;
/** /**
* The patch number, changes with backwards-compatible fixes and patches. * The patch number, changes with backwards-compatible fixes and patches.
*
* @since pre-alpha
* */ * */
public static final int VERSION_PATCH = 0; public static final int VERSION_PATCH = 0;
/** /**
* Denotes whether this build is a pre-release build. * Denotes whether this build is a pre-release build.
*
* @since pre-alpha
* */ * */
public static final boolean PRERELEASE = true; public static final boolean PRERELEASE = true;
/** /**
* The name of this pre-release, e.g. alpha, beta, RC and similar. * The name of this pre-release, e.g. alpha, beta, RC and similar.
*
* @since pre-alpha
* */ * */
public static final String PRERELEASE_NAME = "alpha"; public static final String PRERELEASE_NAME = "alpha";
/** /**
* The pre-release patch number, incremented by 1 with *any* pre-release change. * The pre-release patch number, incremented by 1 with *any* pre-release update.
*
* @since pre-alpha
* */ * */
public static final int PRERELEASE_PATCH = 1; public static final int PRERELEASE_PATCH = 1;
/** /**
* The combined version string. * The combined version string.
*
* @since pre-alpha
* */ * */
public static final String VERSION = VERSION_YEAR + "." + VERSION_MAJOR + "." + VERSION_MINOR + "." + VERSION_PATCH + (PRERELEASE ? "-" + PRERELEASE_NAME + "." + PRERELEASE_PATCH : ""); public static final String VERSION = VERSION_YEAR + "." + VERSION_MAJOR + "." + VERSION_MINOR + "." + VERSION_PATCH + (PRERELEASE ? "-" + PRERELEASE_NAME + "." + PRERELEASE_PATCH : "");
} }

View File

@ -129,7 +129,7 @@ public class MiniTime
for (int i = 1; i < nrs.length; i++) for (int i = 1; i < nrs.length; i++)
{ {
var type = letters[i - 1]; var type = letters[i - 1];
int number = 0; int number;
try try
{ {
@ -196,10 +196,12 @@ public class MiniTime
/** /**
* Converts a time span between two Unix-epoch millisecond time points to a * Converts a time span between two Unix-epoch millisecond time points to a
* MiniTime string. <i>Note ALL time spans larger or equal than * MiniTime string. <i>Note ALL time spans larger or equal than
* {@link Integer#MAX_VALUE} will be permanently converted to "forever".</i> * {@link Integer#MAX_VALUE} weeks will be permanently converted to "forever".
* Inputting {@link Long#MAX_VALUE} for the future time point has the same effect.</i>
* *
* @param before The first time point in Unix-time milliseconds * @param before The first time point in Unix-time milliseconds
* @param after The first time point in Unix-time milliseconds * @param after The first time point in Unix-time milliseconds
*
* @return The resulting MiniTime string * @return The resulting MiniTime string
* *
* @throws IllegalArgumentException on a negative time duration * @throws IllegalArgumentException on a negative time duration
@ -220,10 +222,12 @@ public class MiniTime
/** /**
* Converts a time span between now and a future time point in Unix-epoch * Converts a time span between now and a future time point in Unix-epoch
* milliseconds to a MiniTime string. <i>Note ALL time spans larger or equal * milliseconds to a MiniTime string. <i>Note ALL time spans larger or equal
* than {@link Integer#MAX_VALUE} will be permanently converted to * than {@link Integer#MAX_VALUE} weeks will be permanently converted to
* "forever".</i> * "forever". Inputting {@link Long#MAX_VALUE} for the future time point
* has the same effect.</i>
*
* @param future The future time point in Unix time milliseconds
* *
* @param future The source time span in milliseconds
* @return The resulting MiniTime string * @return The resulting MiniTime string
* *
* @throws IllegalArgumentException on a negative time duration * @throws IllegalArgumentException on a negative time duration
@ -245,7 +249,7 @@ public class MiniTime
/** /**
* Converts a time span milliseconds to a MiniTime string. <i>Note ALL time * Converts a time span milliseconds to a MiniTime string. <i>Note ALL time
* spans larger or equal than {@link Integer#MAX_VALUE} will be permanently * spans larger or equal than {@link Integer#MAX_VALUE} weeks will be permanently
* converted to "forever".</i> * converted to "forever".</i>
* *
* @param diff The source time span in milliseconds * @param diff The source time span in milliseconds

View File

@ -1,15 +1,14 @@
package cz.tefek.pluto.io.asl.resource; package cz.tefek.pluto.io.asl.resource;
import javax.annotation.Nullable;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import cz.tefek.pluto.io.logger.Logger; import cz.tefek.pluto.io.logger.Logger;
import cz.tefek.pluto.io.logger.Severity; import cz.tefek.pluto.io.logger.SmartSeverity;
import cz.tefek.pluto.modloader.ModLoaderCore; import cz.tefek.pluto.modloader.ModLoaderCore;
/** /**
@ -94,13 +93,11 @@ public class ResourceAddress
if (as.length == 1) if (as.length == 1)
{ {
Logger.log(Severity.WARNING, "Please do not use tier 1 addresses, so it doesn't conflict with core assets."); Logger.log(SmartSeverity.WARNING, "Please do not use tier 1 addresses, so it doesn't conflict with core assets.");
} }
for (int i = 0; i < as.length; i++) for (String branch : as)
{ {
var branch = as[i];
if (branch.length() < 1 || branch.length() > MAX_BRANCH_STRING_LENGTH) if (branch.length() < 1 || branch.length() > MAX_BRANCH_STRING_LENGTH)
{ {
throw new IllegalArgumentException("Length of branch must be higher than 0 and lower than 33, this is not an essay."); throw new IllegalArgumentException("Length of branch must be higher than 0 and lower than 33, this is not an essay.");
@ -151,9 +148,9 @@ public class ResourceAddress
return raddress; return raddress;
} }
public ResourceAddress fileExtension(String ext) public ResourceAddress fileExtension(@Nullable String ext)
{ {
if (ext == null || ext == "") if (ext == null || "".equals(ext))
{ {
this.fileExtension = null; this.fileExtension = null;
return this; return this;
@ -213,15 +210,7 @@ public class ResourceAddress
@Override @Override
public String toString() public String toString()
{ {
StringBuilder sbPath = new StringBuilder(this.resSubscriber.getMod().getModID()); return this.resSubscriber.getMod().getModID() + "$" + this.subAddressToString();
sbPath.append("$");
sbPath.append(this.subAddressToString());
String path = sbPath.toString();
return path;
} }
public ResourceAddress copy() public ResourceAddress copy()
@ -246,12 +235,10 @@ public class ResourceAddress
if (this.hasFileExtension()) if (this.hasFileExtension())
{ {
sbPath.append("." + this.fileExtension); sbPath.append(".").append(this.fileExtension);
} }
String path = sbPath.toString(); return sbPath.toString();
return path;
} }
public String subAddressToString() public String subAddressToString()
@ -293,7 +280,7 @@ public class ResourceAddress
var pathBuilder = new StringBuilder(this.resSubscriber.getRootPath()); var pathBuilder = new StringBuilder(this.resSubscriber.getRootPath());
final var separator = FileSystems.getDefault().getSeparator(); final var separator = FileSystems.getDefault().getSeparator();
pathBuilder.append(separator); pathBuilder.append(separator);
pathBuilder.append(this.subAddress.stream().collect(Collectors.joining(separator))); pathBuilder.append(String.join(separator, this.subAddress));
if (this.hasFileExtension()) if (this.hasFileExtension())
{ {

View File

@ -1,16 +1,15 @@
package cz.tefek.pluto.io.asl.resource.type; package cz.tefek.pluto.io.asl.resource.type;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import javax.imageio.ImageIO;
import cz.tefek.pluto.io.asl.resource.Resource; import cz.tefek.pluto.io.asl.resource.Resource;
import cz.tefek.pluto.io.asl.resource.ResourceAddress; import cz.tefek.pluto.io.asl.resource.ResourceAddress;
import cz.tefek.pluto.io.asl.resource.ResourceHelper; import cz.tefek.pluto.io.asl.resource.ResourceHelper;
import cz.tefek.pluto.io.logger.Logger; import cz.tefek.pluto.io.logger.Logger;
import cz.tefek.pluto.io.logger.Severity; import cz.tefek.pluto.io.logger.SmartSeverity;
/** /**
* {@link ResourceAddress} in, {@link BufferedImage} out. * {@link ResourceAddress} in, {@link BufferedImage} out.
@ -38,7 +37,7 @@ public class ResourceImage extends Resource<BufferedImage>
} }
catch (IOException e) catch (IOException e)
{ {
Logger.log(Severity.ERROR, "Could not load BufferedImage: " + this.address.toString() + ", will load placeholder."); Logger.log(SmartSeverity.ERROR, "Could not load BufferedImage: " + this.address.toString() + ", will load placeholder.");
Logger.log(e); Logger.log(e);
try try
@ -47,7 +46,7 @@ public class ResourceImage extends Resource<BufferedImage>
} }
catch (IOException e1) catch (IOException e1)
{ {
Logger.log(Severity.ERROR, "Placeholder BufferedImage not found: " + ResourceHelper.GLOBAL_ROOT + "data/assets/err/missingTex.png"); Logger.log(SmartSeverity.ERROR, "Placeholder BufferedImage not found: " + ResourceHelper.GLOBAL_ROOT + "data/assets/err/missingTex.png");
Logger.log("This is not good! :C"); Logger.log("This is not good! :C");
Logger.log(e1); Logger.log(e1);

View File

@ -1,13 +1,13 @@
package cz.tefek.pluto.io.asl.resource.type; package cz.tefek.pluto.io.asl.resource.type;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.Files;
import cz.tefek.pluto.io.asl.resource.Resource; import cz.tefek.pluto.io.asl.resource.Resource;
import cz.tefek.pluto.io.asl.resource.ResourceAddress; import cz.tefek.pluto.io.asl.resource.ResourceAddress;
import cz.tefek.pluto.io.logger.Logger; import cz.tefek.pluto.io.logger.Logger;
import cz.tefek.pluto.io.logger.Severity; import cz.tefek.pluto.io.logger.SmartSeverity;
/** /**
* {@link ResourceAddress} in, {@link InputStream} out. * {@link ResourceAddress} in, {@link InputStream} out.
@ -26,12 +26,12 @@ public class ResourceInputStream extends Resource<InputStream>
{ {
try try
{ {
return new FileInputStream(this.address.toPath()); return Files.newInputStream(this.address.toNIOPath());
} }
catch (IOException e) catch (IOException e)
{ {
Logger.log(Severity.EXCEPTION, "Failed to open " + this.address + "!"); Logger.log(SmartSeverity.ERROR, "Failed to open " + this.address + "!");
Logger.log(Severity.EXCEPTION, e); Logger.log(e);
} }
return null; return null;

View File

@ -30,7 +30,7 @@ public class Logger
private static OutputStream fileLog = null; private static OutputStream fileLog = null;
/** /**
* Initializes up the logger and replaces the standard output and standard error output with the logger methods. * Initializes the logger and replaces the standard output and standard error output with the logger methods.
* *
* <p> * <p>
* <em> * <em>

View File

@ -4,7 +4,10 @@ package cz.tefek.pluto.io.logger;
* Message severity. * Message severity.
* *
* @author 493msi * @author 493msi
*
* @deprecated Use {@link SmartSeverity} instead.
*/ */
@Deprecated
public enum Severity implements ISeverity public enum Severity implements ISeverity
{ {
INFO("[INFO] ", false), INFO("[INFO] ", false),
@ -19,6 +22,7 @@ public enum Severity implements ISeverity
Severity(String name, boolean usesStdErr) Severity(String name, boolean usesStdErr)
{ {
this.displayName = name; this.displayName = name;
this.usesStdErr = usesStdErr;
} }
@Override @Override

View File

@ -1,35 +0,0 @@
package cz.tefek.pluto.tpl;
public class TPJImage
{
int[] data;
int width;
int height;
public TPJImage(int[] pixels, int width, int height)
{
this.data = pixels;
this.width = width;
this.height = height;
}
public int getWidth()
{
return this.width;
}
public int getHeight()
{
return this.height;
}
public int[] getData()
{
return this.data;
}
public int pixelAt(int x, int y)
{
return this.data[x + y * this.width];
}
}

View File

@ -1,14 +1,17 @@
package cz.tefek.pluto.tpl; package cz.tefek.pluto.tpl;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.image.BufferedImage; import java.awt.image.*;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.file.Files;
import java.nio.file.Path;
import javax.annotation.Nullable;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import cz.tefek.pluto.io.asl.resource.ResourceAddress; import cz.tefek.pluto.io.asl.resource.ResourceAddress;
@ -16,172 +19,294 @@ import cz.tefek.pluto.io.logger.Logger;
import cz.tefek.pluto.io.logger.SmartSeverity; import cz.tefek.pluto.io.logger.SmartSeverity;
/** /**
* Quick ABGR (8-bit per channel, 32 bits per pixel) texture loader for OpenGL * Quick ABGR (8-bit per channel, 32 bits per pixel) image loader for OpenGL textures.
* use. Color component swizzling may be needed. * Color component swizzling may be needed.
*
* FIXME: Refactor {@link TPL#loadBufferedImage}
* *
* @author 493msi * @author 493msi
*
* @see TPNImage
*
* @since pre-alpha
*/ */
public class TPL public class TPL
{ {
private static final int PLACEHOLDER_SIZE = 16; private static final int PLACEHOLDER_SIZE = 16;
private static final int PLACEHOLDER_CHECKEDBOARD = 8; private static final int PLACEHOLDER_CHECKEDBOARD = 8;
private static final int PLACEHOLDER_CHECKEDBOARD_SQUARE_SIZE = PLACEHOLDER_SIZE / PLACEHOLDER_CHECKEDBOARD; private static final int PLACEHOLDER_CHECKEDBOARD_SQUARE_SIZE = PLACEHOLDER_SIZE / PLACEHOLDER_CHECKEDBOARD;
public static TPNImage load(ResourceAddress file) private static final BufferedImage placeholder;
static
{ {
return file == null ? loadImage(null) : load(file.toPath()); placeholder = new BufferedImage(PLACEHOLDER_SIZE, PLACEHOLDER_SIZE, BufferedImage.TYPE_INT_ARGB);
var data = placeholder.getData();
var dataBuffer = (DataBufferInt) data.getDataBuffer();
for (int i = 0; i < PLACEHOLDER_SIZE * PLACEHOLDER_SIZE; i++)
{
int x = i % PLACEHOLDER_SIZE;
int y = i / PLACEHOLDER_SIZE;
boolean checker = x / PLACEHOLDER_CHECKEDBOARD_SQUARE_SIZE % 2 == y / PLACEHOLDER_CHECKEDBOARD_SQUARE_SIZE % 2;
dataBuffer.setElem(i, checker ? 0xFFFF0000 : 0xFF000000);
}
} }
public static TPNImage load(String file) // TODO: Fix this mess
private static BufferedImage loadBufferedImage(@Nullable Object source)
{ {
if (file == null) var inputStream = (InputStream) null;
{
return loadImage(null);
}
try try
{ {
return loadImage(ImageIO.read(new File(file))); if (source instanceof ResourceAddress)
{
inputStream = Files.newInputStream(((ResourceAddress) source).toNIOPath());
}
else if (source instanceof String)
{
inputStream = new FileInputStream((String) source);
}
else if (source instanceof File)
{
inputStream = new FileInputStream((File) source);
}
else if (source instanceof Path)
{
inputStream = Files.newInputStream((Path) source);
}
if (inputStream != null)
{
return ImageIO.read(inputStream);
}
} }
catch (Exception e) catch (Exception e)
{ {
Logger.log(SmartSeverity.ERROR, "[TPL] Image could not be loaded: " + file); Logger.log(SmartSeverity.ERROR, "[TPL] Image could not be loaded: " + source);
Logger.log(e); Logger.log(e);
return loadImage(null);
} }
} finally
public static TPNImage loadImage(BufferedImage image)
{ {
boolean remake = false; try
int width = 0; {
int height = 0; if (inputStream != null)
inputStream.close();
}
catch (IOException e)
{
Logger.log(SmartSeverity.ERROR, "[TPL] Failed to close: " + source);
Logger.log(e);
}
}
return placeholder;
}
/**
* Loads an image from a file the denoted by the input {@link ResourceAddress} into a {@link TPNImage} buffer.
*
* If the input {@link ResourceAddress} is null, a placeholder will be generated.
*
* @param address The source {@link ResourceAddress}, from which the image will be loaded
*
* @return The output {@link TPNImage}, never null
*
* @see TPNImage
*
* @since pre-alpha
* */
public static TPNImage load(@Nullable ResourceAddress address)
{
return loadImage(loadBufferedImage(address));
}
/**
* Loads an image from the denoted filename to a {@link TPNImage} buffer.
*
* If the input filename is null, a placeholder will be generated.
*
* @deprecated Use the {@link TPL#load(ResourceAddress)} or {@link TPL#load(File)} variants.
*
* @param filename The source filename, from which the image will be loaded
*
* @return The output {@link TPNImage}, never null
*
* @see TPNImage
*
* @since pre-alpha
* */
@Deprecated
public static TPNImage load(@Nullable String filename)
{
return loadImage(loadBufferedImage(filename));
}
/**
* Loads an image from the input {@link File} into a {@link TPNImage} buffer.
*
* If the input {@link File} is null, a placeholder will be generated.
*
* @param file The source {@link File}, from which the image will be loaded
*
* @return The output {@link TPNImage}, never null
*
* @see TPNImage
*
* @since 20.2.0.0-alpha.1
* */
public static TPNImage load(@Nullable File file)
{
return loadImage(loadBufferedImage(file));
}
/**
* Loads an image from a file the denoted by the input {@link Path} into a {@link TPNImage} buffer.
*
* If the input {@link Path} is null, a placeholder will be generated.
*
* @param path The source {@link Path}, from which the image will be loaded
*
* @return The output {@link TPNImage}, never null
*
* @see TPNImage
*
* @since 20.2.0.0-alpha.1
* */
public static TPNImage load(@Nullable Path path)
{
return loadImage(loadBufferedImage(path));
}
/**
* Loads an image from a file the denoted by the input {@link ResourceAddress} into a {@link TPNImage} buffer.
*
* If the input {@link ResourceAddress} is null, a placeholder will be generated.
*
* @param address The source {@link ResourceAddress}, from which the image will be loaded
* @param flipY Whether the image should flipped vertically (for OpenGL uses)
*
* @return The output {@link TPNImage}, never null
*
* @see TPNImage
*
* @since 20.2.0.0-alpha.1
* */
public static TPNImage loadSpecial(@Nullable ResourceAddress address, boolean flipY)
{
return loadImageSpecial(loadBufferedImage(address), flipY);
}
/**
* Loads an image from the input {@link File} into a {@link TPNImage} buffer.
*
* If the input {@link File} is null, a placeholder will be generated.
*
* @param file The source {@link File}, from which the image will be loaded
* @param flipY Whether the image should flipped vertically (for OpenGL uses)
*
* @return The output {@link TPNImage}, never null
*
* @see TPNImage
*
* @since 20.2.0.0-alpha.1
* */
public static TPNImage load(@Nullable File file, boolean flipY)
{
return loadImageSpecial(loadBufferedImage(file), flipY);
}
/**
* Loads an image from a file the denoted by the input {@link Path} into a {@link TPNImage} buffer.
*
* If the input {@link Path} is null, a placeholder will be generated.
*
* @param path The source {@link Path}, from which the image will be loaded
* @param flipY Whether the image should flipped vertically (for OpenGL uses)
*
* @return The output {@link TPNImage}, never null
*
* @see TPNImage
*
* @since 20.2.0.0-alpha.1
* */
public static TPNImage loadSpecial(@Nullable Path path, boolean flipY)
{
return loadImageSpecial(loadBufferedImage(path), flipY);
}
/**
* Writes a {@link BufferedImage} into a {@link TPNImage} buffer.
*
* If the input {@link Path} is null, a placeholder will be generated.
*
* @param image The source {@link BufferedImage}
* @param flipY Whether the image should flipped vertically (for OpenGL uses)
*
* @return The output {@link TPNImage}, never null
*
* @see TPNImage
*
* @since 20.2.0.0-alpha.1
* */
public static TPNImage loadImageSpecial(@Nullable BufferedImage image, boolean flipY)
{
if (image == null) if (image == null)
{ {
Logger.log(SmartSeverity.WARNING, "[TPL] Null BufferedImage supplied, generating a placeholder."); Logger.log(SmartSeverity.WARNING, "[TPL] Null BufferedImage supplied, generating a placeholder.");
remake = true; return loadImageSpecial(placeholder, flipY);
} }
else
{ int width = image.getWidth();
width = image.getWidth(); int height = image.getHeight();
height = image.getHeight();
if (width > 16384 || height > 16384 || width < 1 || height < 1) if (width > 16384 || height > 16384 || width < 1 || height < 1)
{ {
Logger.log(SmartSeverity.ERROR, "[TPL] BufferedImage size is invalid (< 1 or > 16384), generating a placeholder."); Logger.log(SmartSeverity.ERROR, "[TPL] BufferedImage size is invalid (< 1 or > 16384), generating a placeholder.");
remake = true; return loadImageSpecial(placeholder, flipY);
} }
}
if (remake)
{
width = PLACEHOLDER_SIZE;
height = PLACEHOLDER_SIZE;
Logger.log(SmartSeverity.INFO, "[TPL] Generating a substitute image...");
ByteBuffer buffer = ByteBuffer.allocateDirect(width * height * 4);
buffer.order(ByteOrder.nativeOrder());
for (int i = 0; i < width * height; i++)
{
int x = i % width;
int y = i / width;
boolean checker = x / PLACEHOLDER_CHECKEDBOARD_SQUARE_SIZE % 2 == y / PLACEHOLDER_CHECKEDBOARD_SQUARE_SIZE % 2;
buffer.put((byte) 0xff); // A
buffer.put((byte) 0x00); // B
buffer.put((byte) 0x00); // G
buffer.put((byte) (checker ? 0xff : 0x00)); // R
}
buffer.flip();
return new TPNImage(buffer, width, height);
}
ByteBuffer buffer = ByteBuffer.allocateDirect(width * height * 4).order(ByteOrder.nativeOrder());
BufferedImage copy = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_4BYTE_ABGR); BufferedImage copy = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D imgGraphics = copy.createGraphics(); Graphics2D imgGraphics = copy.createGraphics();
imgGraphics.drawImage(image, 0, copy.getHeight(), copy.getWidth(), 0, 0, 0, image.getWidth(), image.getHeight(), null); // I wonder if this is pixel-perfect imgGraphics.drawImage(image,
0, flipY ? copy.getHeight() : 0, copy.getWidth(), flipY ? 0 : copy.getHeight(),
0, 0, image.getWidth(), image.getHeight(),
null); // I wonder if this is pixel-perfect
imgGraphics.dispose(); imgGraphics.dispose();
Raster data = copy.getData(); Raster data = copy.getRaster();
DataBuffer dataBuffer = data.getDataBuffer(); DataBuffer dataBuffer = data.getDataBuffer();
DataBufferByte byteBuffer = (DataBufferByte) dataBuffer; DataBufferByte byteBuffer = (DataBufferByte) dataBuffer;
byte[] byteData = byteBuffer.getData(); byte[] byteData = byteBuffer.getData();
ByteBuffer buffer = ByteBuffer.allocateDirect(width * height * 4).order(ByteOrder.nativeOrder());
buffer.put(byteData); buffer.put(byteData);
buffer.flip(); buffer.flip();
return new TPNImage(buffer, width, height); return new TPNImage(buffer, width, height);
} }
public static TPJImage loadPixels(String file)
/**
* Writes a {@link BufferedImage} into a {@link TPNImage} buffer.
*
* If the input {@link Path} is null, a placeholder will be generated.
*
* @param image The source {@link BufferedImage}
*
* @return The output {@link TPNImage}, never null
*
* @see TPNImage
*
* @since pre-alpha
* */
public static TPNImage loadImage(@Nullable BufferedImage image)
{ {
TPJImage tImg = null; return loadImageSpecial(image, true);
BufferedImage image = null;
boolean remake = false;
int width = 0;
int height = 0;
try
{
image = ImageIO.read(new File(file));
width = image.getWidth();
height = image.getHeight();
}
catch (Exception e)
{
Logger.log(SmartSeverity.ERROR, "[TPL] Image could not be loaded: " + file);
Logger.log(e);
remake = true;
}
if (width > 16384 || height > 16384 || width < 1 || height < 1)
{
Logger.log(SmartSeverity.ERROR, "[TPL] Image size is invalid (< 1 or > 16384): " + file);
Logger.log(SmartSeverity.ERROR, "[TPL] A replacement will be generated.");
remake = true;
}
if (remake)
{
width = PLACEHOLDER_SIZE;
height = PLACEHOLDER_SIZE;
tImg = new TPJImage(new int[width * height], width, height);
Logger.log(SmartSeverity.INFO, "[TPL] Generating a substitute image...");
for (int i = 0; i < width * height; i++)
{
int x = i % width;
int y = i / width;
boolean checker = x / PLACEHOLDER_CHECKEDBOARD_SQUARE_SIZE % 2 == y / PLACEHOLDER_CHECKEDBOARD_SQUARE_SIZE % 2;
tImg.data[i] = checker ? 0xffff0000 : 0xff000000;
}
return tImg;
}
tImg = new TPJImage(new int[width * height], width, height);
for (int i = 0; i < width * height; i++)
{
int pixel = image.getRGB(i % width, i / width);
tImg.data[i] = pixel;
}
return tImg;
} }
} }

View File

@ -2,12 +2,32 @@ package cz.tefek.pluto.tpl;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/**
* A wrapper around a native color buffer for easier handling
* by various APIs, such as OpenGL and GLFW.
*
* @implNote TPNImage is <em>always</em> ABGR due to image format
* limitations of {@link java.awt.image.BufferedImage}
*
* @author 493msi
*
* @since pre-alpha
*/
public class TPNImage public class TPNImage
{ {
ByteBuffer data; private final ByteBuffer data;
int width; private final int width;
int height; private final int height;
/**
* Creates a new {@link TPNImage} from the specified buffer, width and height.
*
* @param bfr The input {@link ByteBuffer}
* @param width This image's width
* @param height This image's height
*
* @since pre-alpha
* */
public TPNImage(ByteBuffer bfr, int width, int height) public TPNImage(ByteBuffer bfr, int width, int height)
{ {
this.data = bfr; this.data = bfr;
@ -15,18 +35,39 @@ public class TPNImage
this.height = height; this.height = height;
} }
/**
* Returns the width of the color buffer.
*
* @return The width of this {@link TPNImage}
*
* @since pre-alpha
* */
public int getWidth() public int getWidth()
{ {
return this.width; return this.width;
} }
/**
* Returns the height of the color buffer.
*
* @return The height of this {@link TPNImage}
*
* @since pre-alpha
* */
public int getHeight() public int getHeight()
{ {
return this.height; return this.height;
} }
/**
* Returns a read-only view of the color buffer.
*
* @return This image's color {@link ByteBuffer}
*
* @since pre-alpha
* */
public ByteBuffer getData() public ByteBuffer getData()
{ {
return this.data; return this.data.asReadOnlyBuffer();
} }
} }

View File

@ -1,5 +1,7 @@
package cz.tefek.pluto.engine.graphics.sprite; package cz.tefek.pluto.engine.graphics.sprite;
import java.awt.image.BufferedImage;
import cz.tefek.pluto.engine.graphics.texture.MagFilter; import cz.tefek.pluto.engine.graphics.texture.MagFilter;
import cz.tefek.pluto.engine.graphics.texture.MinFilter; import cz.tefek.pluto.engine.graphics.texture.MinFilter;
import cz.tefek.pluto.engine.graphics.texture.WrapMode; import cz.tefek.pluto.engine.graphics.texture.WrapMode;
@ -11,7 +13,7 @@ public class DisposablePlaceholderSprite extends DisposableTextureSprite
{ {
super(new RectangleTexture()); super(new RectangleTexture());
this.spriteTexture.load((String) null, MagFilter.NEAREST, MinFilter.NEAREST, WrapMode.CLAMP_TO_EDGE, WrapMode.CLAMP_TO_EDGE); this.spriteTexture.load((BufferedImage) null, MagFilter.NEAREST, MinFilter.NEAREST, WrapMode.CLAMP_TO_EDGE, WrapMode.CLAMP_TO_EDGE);
this.width = this.spriteTexture.getWidth(); this.width = this.spriteTexture.getWidth();
this.height = this.spriteTexture.getHeight(); this.height = this.spriteTexture.getHeight();
} }

View File

@ -6,7 +6,7 @@ import cz.tefek.pluto.engine.graphics.sprite.Sprite;
import cz.tefek.pluto.engine.graphics.sprite.SpriteDisposable; import cz.tefek.pluto.engine.graphics.sprite.SpriteDisposable;
import cz.tefek.pluto.engine.graphics.sprite.TileSprite; import cz.tefek.pluto.engine.graphics.sprite.TileSprite;
import cz.tefek.pluto.io.logger.Logger; import cz.tefek.pluto.io.logger.Logger;
import cz.tefek.pluto.io.logger.Severity; import cz.tefek.pluto.io.logger.SmartSeverity;
public abstract class TiledSpriteSheet<T> extends SpriteSheet<T> public abstract class TiledSpriteSheet<T> extends SpriteSheet<T>
{ {
@ -65,7 +65,7 @@ public abstract class TiledSpriteSheet<T> extends SpriteSheet<T>
protected void expand() protected void expand()
{ {
Logger.logf(Severity.INFO, "Spritesheet #%d: Expanding from %dx%d to ", this.id, this.spriteSheetWidth, this.spriteSheetHeight); Logger.logf(SmartSeverity.INFO, "Spritesheet #%d: Expanding from %dx%d to ", this.id, this.spriteSheetWidth, this.spriteSheetHeight);
this.spriteSheetWidth *= 2; this.spriteSheetWidth *= 2;
this.spriteSheetHeight *= 2; this.spriteSheetHeight *= 2;
@ -79,7 +79,7 @@ public abstract class TiledSpriteSheet<T> extends SpriteSheet<T>
protected void upscale(int factor) protected void upscale(int factor)
{ {
Logger.logf(Severity.INFO, "Spritesheet #%d: Upscaling from %dx%d to ", this.id, this.tileWidth, this.tileHeight); Logger.logf(SmartSeverity.INFO, "Spritesheet #%d: Upscaling from %dx%d to ", this.id, this.tileWidth, this.tileHeight);
this.tileWidth *= factor; this.tileWidth *= factor;
this.tileHeight *= factor; this.tileHeight *= factor;

View File

@ -3,6 +3,8 @@ package cz.tefek.pluto.engine.buffer;
import org.lwjgl.BufferUtils; import org.lwjgl.BufferUtils;
import org.lwjgl.glfw.GLFWImage; import org.lwjgl.glfw.GLFWImage;
import java.nio.file.Path;
import cz.tefek.pluto.tpl.TPL; import cz.tefek.pluto.tpl.TPL;
/** /**
@ -28,23 +30,27 @@ public class GLFWImageUtil
{ {
var icon = GLFWImage.create(icons.length); var icon = GLFWImage.create(icons.length);
for (int iconIndex = 0; iconIndex < icons.length; iconIndex++) for (String iconPath : icons)
{ {
var img = TPL.loadPixels(icons[iconIndex]); var img = TPL.loadSpecial(Path.of(iconPath), false);
var imgData = img.getData(); var imgData = img.getData();
var imgWidth = img.getWidth(); int imgWidth = img.getWidth();
var imgHeight = img.getHeight(); int imgHeight = img.getHeight();
var byteBuf = BufferUtils.createByteBuffer(imgWidth * imgHeight * 4); int pixelCount = imgWidth * imgHeight;
int bytesPerPixel = 4;
var byteBuf = BufferUtils.createByteBuffer(pixelCount * bytesPerPixel);
for (int i = 0; i < imgHeight * imgWidth; i++) byte[] px = new byte[bytesPerPixel];
for (int i = 0; i < pixelCount; i++)
{ {
var data = imgData[i]; px[3] = imgData.get(); // A
px[2] = imgData.get(); // B
px[1] = imgData.get(); // G
px[0] = imgData.get(); // R
byteBuf.put((byte) ((data & 0x00ff0000) >> 16)); byteBuf.put(px);
byteBuf.put((byte) ((data & 0x0000ff00) >> 8));
byteBuf.put((byte) (data & 0x000000ff));
byteBuf.put((byte) ((data & 0xff000000) >> 24));
} }
byteBuf.flip(); byteBuf.flip();

View File

@ -1,10 +1,6 @@
package cz.tefek.pluto.engine.display; package cz.tefek.pluto.engine.display;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.*;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWImage;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.glfw.GLFWWindowSizeCallback;
import org.lwjgl.opengl.ARBDebugOutput; import org.lwjgl.opengl.ARBDebugOutput;
import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL33; import org.lwjgl.opengl.GL33;
@ -13,7 +9,6 @@ import org.lwjgl.system.MemoryUtil;
import cz.tefek.pluto.engine.gl.GLDebugInfo; import cz.tefek.pluto.engine.gl.GLDebugInfo;
import cz.tefek.pluto.io.logger.Logger; import cz.tefek.pluto.io.logger.Logger;
import cz.tefek.pluto.io.logger.Severity;
import cz.tefek.pluto.io.logger.SmartSeverity; import cz.tefek.pluto.io.logger.SmartSeverity;
/** /**
@ -72,7 +67,7 @@ public class Display
{ {
if (Display.this.debugMode) if (Display.this.debugMode)
{ {
Logger.logf(Severity.INFO, "Resized to %dx%d.\n", width, height); Logger.logf(SmartSeverity.INFO, "Resized to %dx%d.\n", width, height);
} }
Display.this.width = width; Display.this.width = width;

View File

@ -1,23 +1,21 @@
package cz.tefek.pluto.engine.graphics.texture; package cz.tefek.pluto.engine.graphics.texture;
import java.util.Arrays;
import org.lwjgl.opengl.GL33; import org.lwjgl.opengl.GL33;
import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.MemoryUtil;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Arrays;
import cz.tefek.pluto.io.asl.resource.ResourceAddress; import cz.tefek.pluto.io.asl.resource.ResourceAddress;
import cz.tefek.pluto.io.logger.Logger; import cz.tefek.pluto.io.logger.Logger;
import cz.tefek.pluto.io.logger.Severity;
import cz.tefek.pluto.io.logger.SmartSeverity; import cz.tefek.pluto.io.logger.SmartSeverity;
import cz.tefek.pluto.tpl.TPL; import cz.tefek.pluto.tpl.TPL;
import cz.tefek.pluto.tpl.TPNImage; import cz.tefek.pluto.tpl.TPNImage;
public abstract class Texture public abstract class Texture
{ {
protected int glID = 0; protected int glID;
protected final int type; protected final int type;
protected final int dimensions; protected final int dimensions;
@ -138,7 +136,7 @@ public abstract class Texture
{ {
if (wrapOptions.length != this.dimensions) if (wrapOptions.length != this.dimensions)
{ {
Logger.log(Severity.ERROR, "Error: WrapMode option count does not match texture's dimensions."); Logger.log(SmartSeverity.ERROR, "Error: WrapMode option count does not match texture's dimensions.");
return this; return this;
} }
@ -198,6 +196,7 @@ public abstract class Texture
this.load(file.toPath(), magFilter, minFilter, wrap); this.load(file.toPath(), magFilter, minFilter, wrap);
} }
@Deprecated
public void load(String file, MagFilter magFilter, MinFilter minFilter, WrapMode... wrap) public void load(String file, MagFilter magFilter, MinFilter minFilter, WrapMode... wrap)
{ {
TPNImage image = TPL.load(file); TPNImage image = TPL.load(file);

View File

@ -1,13 +1,13 @@
package cz.tefek.pluto.engine.graphics.texture.texture2d; package cz.tefek.pluto.engine.graphics.texture.texture2d;
import java.util.Arrays;
import org.lwjgl.opengl.GL33; import org.lwjgl.opengl.GL33;
import java.util.Arrays;
import cz.tefek.pluto.engine.graphics.texture.Texture; import cz.tefek.pluto.engine.graphics.texture.Texture;
import cz.tefek.pluto.engine.graphics.texture.WrapMode; import cz.tefek.pluto.engine.graphics.texture.WrapMode;
import cz.tefek.pluto.io.logger.Logger; import cz.tefek.pluto.io.logger.Logger;
import cz.tefek.pluto.io.logger.Severity; import cz.tefek.pluto.io.logger.SmartSeverity;
public class RectangleTexture extends Texture public class RectangleTexture extends Texture
{ {
@ -27,7 +27,7 @@ public class RectangleTexture extends Texture
{ {
if (Arrays.stream(wrapOptions).anyMatch(WrapMode.repeatModes::contains)) if (Arrays.stream(wrapOptions).anyMatch(WrapMode.repeatModes::contains))
{ {
Logger.log(Severity.ERROR, "Error: Rectangle textures do not support repeat wrap modes!"); Logger.log(SmartSeverity.ERROR, "Error: Rectangle textures do not support repeat wrap modes!");
return this; return this;
} }