mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-09 21:31:51 +09:00
migration wip java 9 modularise
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package net.torvald.colourutil
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.colourutil.CIELChabUtil.toLCh
|
||||
import net.torvald.colourutil.CIELChabUtil.toLab
|
||||
@@ -7,7 +8,6 @@ import net.torvald.colourutil.CIELabUtil.toLab
|
||||
import net.torvald.colourutil.CIEXYZUtil.toXYZ
|
||||
import net.torvald.colourutil.CIEXYZUtil.toColor
|
||||
import net.torvald.colourutil.CIELabUtil.toXYZ
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
/**
|
||||
* Cylindrical modification of CIELab colour space
|
||||
*
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package net.torvald.colourutil
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.colourutil.CIELabUtil.toLab
|
||||
import net.torvald.colourutil.CIEXYZUtil.toColor
|
||||
import net.torvald.colourutil.CIEXYZUtil.toRGB
|
||||
import net.torvald.colourutil.CIEXYZUtil.toXYZ
|
||||
import net.torvald.colourutil.CIELabUtil.toXYZ
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
|
||||
/**
|
||||
* A modification of CIEXYZ that is useful for surface colours
|
||||
|
||||
@@ -2,7 +2,6 @@ package net.torvald.colourutil
|
||||
|
||||
import com.jme3.math.FastMath
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import net.torvald.colourutil.CIELabUtil.toXYZ
|
||||
import net.torvald.colourutil.CIEXYZUtil.toColor
|
||||
import net.torvald.colourutil.CIEXYZUtil.toRGB
|
||||
import net.torvald.colourutil.CIEXYZUtil.toXYZ
|
||||
|
||||
442
src/net/torvald/gdx/graphics/Cvec.java
Normal file
442
src/net/torvald/gdx/graphics/Cvec.java
Normal file
@@ -0,0 +1,442 @@
|
||||
/*******************************************************************************
|
||||
* Copyright 2011 See AUTHORS file.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
|
||||
package net.torvald.gdx.graphics;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.utils.NumberUtils;
|
||||
|
||||
/** A color class, holding the r, g, b and alpha component as floats in the range [0,1]. All methods perform clamping on the
|
||||
* internal values after execution.
|
||||
*
|
||||
* @author mzechner */
|
||||
public class Cvec {
|
||||
public static final Cvec WHITE = new Cvec(1, 1, 1,1);
|
||||
|
||||
/** the red, green, blue and alpha components **/
|
||||
public float r, g, b, a;
|
||||
|
||||
/** Constructs a new Cvec with all components set to 0. */
|
||||
public Cvec () {
|
||||
}
|
||||
|
||||
/** @see #rgba8888ToCvec(Cvec, int) */
|
||||
public Cvec (int rgba8888) {
|
||||
rgba8888ToCvec(this, rgba8888);
|
||||
}
|
||||
|
||||
public Cvec (Color color) {
|
||||
this.r = color.r;
|
||||
this.g = color.g;
|
||||
this.b = color.b;
|
||||
this.a = color.a;
|
||||
}
|
||||
|
||||
/** Constructor, sets the components of the color
|
||||
*
|
||||
* @param r the red component
|
||||
* @param g the green component
|
||||
* @param b the blue component
|
||||
* @param a the alpha component */
|
||||
public Cvec (float r, float g, float b, float a) {
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
this.a = a;
|
||||
}
|
||||
|
||||
/** Constructs a new color using the given color
|
||||
*
|
||||
* @param color the color */
|
||||
public Cvec (Cvec color) {
|
||||
set(color);
|
||||
}
|
||||
|
||||
/** Sets this color to the given color.
|
||||
*
|
||||
* @param color the Cvec */
|
||||
public Cvec set (Cvec color) {
|
||||
this.r = color.r;
|
||||
this.g = color.g;
|
||||
this.b = color.b;
|
||||
this.a = color.a;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Multiplies the this color and the given color
|
||||
*
|
||||
* @param color the color
|
||||
* @return this color. */
|
||||
public Cvec mul (Cvec color) {
|
||||
this.r *= color.r;
|
||||
this.g *= color.g;
|
||||
this.b *= color.b;
|
||||
this.a *= color.a;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Multiplies all components of this Cvec with the given value.
|
||||
*
|
||||
* @param value the value
|
||||
* @return this color */
|
||||
public Cvec mul (float value) {
|
||||
this.r *= value;
|
||||
this.g *= value;
|
||||
this.b *= value;
|
||||
this.a *= value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Adds the given color to this color.
|
||||
*
|
||||
* @param color the color
|
||||
* @return this color */
|
||||
public Cvec add (Cvec color) {
|
||||
this.r += color.r;
|
||||
this.g += color.g;
|
||||
this.b += color.b;
|
||||
this.a += color.a;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Subtracts the given color from this color
|
||||
*
|
||||
* @param color the color
|
||||
* @return this color */
|
||||
public Cvec sub (Cvec color) {
|
||||
this.r -= color.r;
|
||||
this.g -= color.g;
|
||||
this.b -= color.b;
|
||||
this.a -= color.a;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets this Cvec's component values.
|
||||
*
|
||||
* @param r Red component
|
||||
* @param g Green component
|
||||
* @param b Blue component
|
||||
* @param a Alpha component
|
||||
*
|
||||
* @return this Cvec for chaining */
|
||||
public Cvec set (float r, float g, float b, float a) {
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
this.a = a;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets this color's component values through an integer representation.
|
||||
*
|
||||
* @return this Cvec for chaining
|
||||
* @see #rgba8888ToCvec(Cvec, int) */
|
||||
public Cvec set (int rgba) {
|
||||
rgba8888ToCvec(this, rgba);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Adds the given color component values to this Cvec's values.
|
||||
*
|
||||
* @param r Red component
|
||||
* @param g Green component
|
||||
* @param b Blue component
|
||||
* @param a Alpha component
|
||||
*
|
||||
* @return this Cvec for chaining */
|
||||
public Cvec add (float r, float g, float b, float a) {
|
||||
this.r += r;
|
||||
this.g += g;
|
||||
this.b += b;
|
||||
this.a += a;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Subtracts the given values from this Cvec's component values.
|
||||
*
|
||||
* @param r Red component
|
||||
* @param g Green component
|
||||
* @param b Blue component
|
||||
* @param a Alpha component
|
||||
*
|
||||
* @return this Cvec for chaining */
|
||||
public Cvec sub (float r, float g, float b, float a) {
|
||||
this.r -= r;
|
||||
this.g -= g;
|
||||
this.b -= b;
|
||||
this.a -= a;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Multiplies this Cvec's color components by the given ones.
|
||||
*
|
||||
* @param r Red component
|
||||
* @param g Green component
|
||||
* @param b Blue component
|
||||
* @param a Alpha component
|
||||
*
|
||||
* @return this Cvec for chaining */
|
||||
public Cvec mul (float r, float g, float b, float a) {
|
||||
this.r *= r;
|
||||
this.g *= g;
|
||||
this.b *= b;
|
||||
this.a *= a;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Linearly interpolates between this color and the target color by t which is in the range [0,1]. The result is stored in
|
||||
* this color.
|
||||
* @param target The target color
|
||||
* @param t The interpolation coefficient
|
||||
* @return This color for chaining. */
|
||||
public Cvec lerp (final Cvec target, final float t) {
|
||||
this.r += t * (target.r - this.r);
|
||||
this.g += t * (target.g - this.g);
|
||||
this.b += t * (target.b - this.b);
|
||||
this.a += t * (target.a - this.a);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Linearly interpolates between this color and the target color by t which is in the range [0,1]. The result is stored in
|
||||
* this color.
|
||||
* @param r The red component of the target color
|
||||
* @param g The green component of the target color
|
||||
* @param b The blue component of the target color
|
||||
* @param a The alpha component of the target color
|
||||
* @param t The interpolation coefficient
|
||||
* @return This color for chaining. */
|
||||
public Cvec lerp (final float r, final float g, final float b, final float a, final float t) {
|
||||
this.r += t * (r - this.r);
|
||||
this.g += t * (g - this.g);
|
||||
this.b += t * (b - this.b);
|
||||
this.a += t * (a - this.a);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Multiplies the RGB values by the alpha. */
|
||||
public Cvec premultiplyAlpha () {
|
||||
r *= a;
|
||||
g *= a;
|
||||
b *= a;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals (Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Cvec color = (Cvec)o;
|
||||
return toIntBits() == color.toIntBits();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode () {
|
||||
int result = (r != +0.0f ? NumberUtils.floatToIntBits(r) : 0);
|
||||
result = 31 * result + (g != +0.0f ? NumberUtils.floatToIntBits(g) : 0);
|
||||
result = 31 * result + (b != +0.0f ? NumberUtils.floatToIntBits(b) : 0);
|
||||
result = 31 * result + (a != +0.0f ? NumberUtils.floatToIntBits(a) : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Packs the color components into a 32-bit integer with the format ABGR and then converts it to a float. Alpha is compressed
|
||||
* from 0-255 to 0-254 to avoid using float bits in the NaN range (see {@link NumberUtils#intToFloatColor(int)}).
|
||||
* @return the packed color as a 32-bit float */
|
||||
public float toFloatBits () {
|
||||
int color = ((int)(255 * a) << 24) | ((int)(255 * b) << 16) | ((int)(255 * g) << 8) | ((int)(255 * r));
|
||||
return NumberUtils.intToFloatColor(color);
|
||||
}
|
||||
|
||||
/** Packs the color components into a 32-bit integer with the format ABGR.
|
||||
* @return the packed color as a 32-bit int. */
|
||||
public int toIntBits () {
|
||||
return ((int)(255 * a) << 24) | ((int)(255 * b) << 16) | ((int)(255 * g) << 8) | ((int)(255 * r));
|
||||
}
|
||||
|
||||
/** Returns the color encoded as hex string with the format RRGGBBAA. */
|
||||
public String toString () {
|
||||
String value = Integer
|
||||
.toHexString(((int)(255 * r) << 24) | ((int)(255 * g) << 16) | ((int)(255 * b) << 8) | ((int)(255 * a)));
|
||||
while (value.length() < 8)
|
||||
value = "0" + value;
|
||||
return value;
|
||||
}
|
||||
|
||||
/** Returns a new color from a hex string with the format RRGGBBAA.
|
||||
* @see #toString() */
|
||||
public static Cvec valueOf (String hex) {
|
||||
hex = hex.charAt(0) == '#' ? hex.substring(1) : hex;
|
||||
int r = Integer.valueOf(hex.substring(0, 2), 16);
|
||||
int g = Integer.valueOf(hex.substring(2, 4), 16);
|
||||
int b = Integer.valueOf(hex.substring(4, 6), 16);
|
||||
int a = hex.length() != 8 ? 255 : Integer.valueOf(hex.substring(6, 8), 16);
|
||||
return new Cvec(r / 255f, g / 255f, b / 255f, a / 255f);
|
||||
}
|
||||
|
||||
/** Packs the color components into a 32-bit integer with the format ABGR. Note that no range checking is performed for higher
|
||||
* performance.
|
||||
* @param r the red component, 0 - 255
|
||||
* @param g the green component, 0 - 255
|
||||
* @param b the blue component, 0 - 255
|
||||
* @param a the alpha component, 0 - 255
|
||||
* @return the packed color as a 32-bit int */
|
||||
public static int toIntBits (int r, int g, int b, int a) {
|
||||
return (a << 24) | (b << 16) | (g << 8) | r;
|
||||
}
|
||||
|
||||
public static int alpha (float alpha) {
|
||||
return (int)(alpha * 255.0f);
|
||||
}
|
||||
|
||||
public static int rgba8888 (float r, float g, float b, float a) {
|
||||
return ((int)(r * 255) << 24) | ((int)(g * 255) << 16) | ((int)(b * 255) << 8) | (int)(a * 255);
|
||||
}
|
||||
|
||||
public static int argb8888 (float a, float r, float g, float b) {
|
||||
return ((int)(a * 255) << 24) | ((int)(r * 255) << 16) | ((int)(g * 255) << 8) | (int)(b * 255);
|
||||
}
|
||||
|
||||
public static int rgba8888 (Cvec color) {
|
||||
return ((int)(color.r * 255) << 24) | ((int)(color.g * 255) << 16) | ((int)(color.b * 255) << 8) | (int)(color.a * 255);
|
||||
}
|
||||
|
||||
public static int argb8888 (Cvec color) {
|
||||
return ((int)(color.a * 255) << 24) | ((int)(color.r * 255) << 16) | ((int)(color.g * 255) << 8) | (int)(color.b * 255);
|
||||
}
|
||||
|
||||
/** Sets the Cvec components using the specified integer value in the format RGBA8888. This is inverse to the rgba8888(r, g,
|
||||
* b, a) method.
|
||||
*
|
||||
* @param color The Cvec to be modified.
|
||||
* @param value An integer color value in RGBA8888 format. */
|
||||
public static void rgba8888ToCvec (Cvec color, int value) {
|
||||
color.r = ((value & 0xff000000) >>> 24) / 255f;
|
||||
color.g = ((value & 0x00ff0000) >>> 16) / 255f;
|
||||
color.b = ((value & 0x0000ff00) >>> 8) / 255f;
|
||||
color.a = ((value & 0x000000ff)) / 255f;
|
||||
}
|
||||
|
||||
/** Sets the Cvec components using the specified integer value in the format ARGB8888. This is the inverse to the argb8888(a,
|
||||
* r, g, b) method
|
||||
*
|
||||
* @param color The Cvec to be modified.
|
||||
* @param value An integer color value in ARGB8888 format. */
|
||||
public static void argb8888ToCvec (Cvec color, int value) {
|
||||
color.a = ((value & 0xff000000) >>> 24) / 255f;
|
||||
color.r = ((value & 0x00ff0000) >>> 16) / 255f;
|
||||
color.g = ((value & 0x0000ff00) >>> 8) / 255f;
|
||||
color.b = ((value & 0x000000ff)) / 255f;
|
||||
}
|
||||
|
||||
/** Sets the Cvec components using the specified float value in the format ABGB8888.
|
||||
* @param color The Cvec to be modified. */
|
||||
public static void abgr8888ToCvec (Cvec color, float value) {
|
||||
int c = NumberUtils.floatToIntColor(value);
|
||||
color.a = ((c & 0xff000000) >>> 24) / 255f;
|
||||
color.b = ((c & 0x00ff0000) >>> 16) / 255f;
|
||||
color.g = ((c & 0x0000ff00) >>> 8) / 255f;
|
||||
color.r = ((c & 0x000000ff)) / 255f;
|
||||
}
|
||||
|
||||
/** Sets the RGB Cvec components using the specified Hue-Saturation-Value. Note that HSV components are voluntary not clamped
|
||||
* to preserve high range color and can range beyond typical values.
|
||||
* @param h The Hue in degree from 0 to 360
|
||||
* @param s The Saturation from 0 to 1
|
||||
* @param v The Value (brightness) from 0 to 1
|
||||
* @return The modified Cvec for chaining. */
|
||||
public Cvec fromHsv (float h, float s, float v) {
|
||||
float x = (h / 60f + 6) % 6;
|
||||
int i = (int)x;
|
||||
float f = x - i;
|
||||
float p = v * (1 - s);
|
||||
float q = v * (1 - s * f);
|
||||
float t = v * (1 - s * (1 - f));
|
||||
switch (i) {
|
||||
case 0:
|
||||
r = v;
|
||||
g = t;
|
||||
b = p;
|
||||
break;
|
||||
case 1:
|
||||
r = q;
|
||||
g = v;
|
||||
b = p;
|
||||
break;
|
||||
case 2:
|
||||
r = p;
|
||||
g = v;
|
||||
b = t;
|
||||
break;
|
||||
case 3:
|
||||
r = p;
|
||||
g = q;
|
||||
b = v;
|
||||
break;
|
||||
case 4:
|
||||
r = t;
|
||||
g = p;
|
||||
b = v;
|
||||
break;
|
||||
default:
|
||||
r = v;
|
||||
g = p;
|
||||
b = q;
|
||||
}
|
||||
|
||||
//return clamp();
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets RGB components using the specified Hue-Saturation-Value. This is a convenient method for
|
||||
* {@link #fromHsv(float, float, float)}. This is the inverse of {@link #toHsv(float[])}.
|
||||
* @param hsv The Hue, Saturation and Value components in that order.
|
||||
* @return The modified Cvec for chaining. */
|
||||
public Cvec fromHsv (float[] hsv) {
|
||||
return fromHsv(hsv[0], hsv[1], hsv[2]);
|
||||
}
|
||||
|
||||
/** Extract Hue-Saturation-Value. This is the inverse of {@link #fromHsv(float[])}.
|
||||
* @param hsv The HSV array to be modified.
|
||||
* @return HSV components for chaining. */
|
||||
public float[] toHsv (float[] hsv) {
|
||||
float max = Math.max(Math.max(r, g), b);
|
||||
float min = Math.min(Math.min(r, g), b);
|
||||
float range = max - min;
|
||||
if (range == 0) {
|
||||
hsv[0] = 0;
|
||||
} else if (max == r) {
|
||||
hsv[0] = (60 * (g - b) / range + 360) % 360;
|
||||
} else if (max == g) {
|
||||
hsv[0] = 60 * (b - r) / range + 120;
|
||||
} else {
|
||||
hsv[0] = 60 * (r - g) / range + 240;
|
||||
}
|
||||
|
||||
if (max > 0) {
|
||||
hsv[1] = 1 - min / max;
|
||||
} else {
|
||||
hsv[1] = 0;
|
||||
}
|
||||
|
||||
hsv[2] = max;
|
||||
|
||||
return hsv;
|
||||
}
|
||||
|
||||
/** @return a copy of this color */
|
||||
public Cvec cpy () {
|
||||
return new Cvec(this);
|
||||
}
|
||||
}
|
||||
119
src/net/torvald/gdx/graphics/PixmapIO2.java
Normal file
119
src/net/torvald/gdx/graphics/PixmapIO2.java
Normal file
@@ -0,0 +1,119 @@
|
||||
package net.torvald.gdx.graphics;
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.utils.StreamUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2019-01-07.
|
||||
*/
|
||||
public class PixmapIO2 {
|
||||
|
||||
// REMEMBER: to the GL's perspective, this game's FBOs are always Y-flipped. //
|
||||
|
||||
public static int HEADER_FOOTER_SIZE = 18 + 26;
|
||||
|
||||
public static void writeTGAHappy(FileHandle file, Pixmap pixmap, boolean flipY) throws IOException {
|
||||
OutputStream output = file.write(false);
|
||||
|
||||
try {
|
||||
_writeTGA(output, pixmap, false, flipY);
|
||||
} finally {
|
||||
StreamUtils.closeQuietly(output);
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeTGA(FileHandle file, Pixmap pixmap, boolean flipY) throws IOException {
|
||||
OutputStream output = file.write(false);
|
||||
|
||||
try {
|
||||
_writeTGA(output, pixmap, true, flipY);
|
||||
} finally {
|
||||
StreamUtils.closeQuietly(output);
|
||||
}
|
||||
}
|
||||
|
||||
public static void _writeTGA(OutputStream out, Pixmap pixmap, boolean verbatim, boolean flipY) throws IOException {
|
||||
byte[] width = toShortLittle(pixmap.getWidth());
|
||||
byte[] height = toShortLittle(pixmap.getHeight());
|
||||
byte[] zero = toShortLittle(0);
|
||||
|
||||
out.write(0); // ID field: empty
|
||||
out.write(0); // no colour map, but should be ignored anyway as it being unmapped RGB
|
||||
out.write(2); // 2 means unmapped RGB
|
||||
out.write(new byte[]{0,0,0,0,0}); // color map spec: empty
|
||||
out.write(zero); // x origin: 0
|
||||
out.write(zero); // y origin: 0
|
||||
out.write(width); // width
|
||||
out.write(height); // height
|
||||
out.write(32); // image pixel size: we're writing 32-bit image (8bpp BGRA)
|
||||
out.write(8); // image descriptor: dunno, Photoshop writes 8 in there
|
||||
|
||||
// write actual image data
|
||||
// since we're following Photoshop's conventional header, we also follows Photoshop's
|
||||
// TGA saving scheme, that is:
|
||||
// 1. BGRA order
|
||||
// 2. Y-Flipped but not X-Flipped
|
||||
|
||||
if (!flipY) {
|
||||
for (int y = pixmap.getHeight() - 1; y >= 0; y--) {
|
||||
for (int x = 0; x < pixmap.getWidth(); x++) {
|
||||
writeTga(x, y, verbatim, pixmap, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int y = 0; y < pixmap.getHeight(); y++) {
|
||||
for (int x = 0; x < pixmap.getWidth(); x++) {
|
||||
writeTga(x, y, verbatim, pixmap, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// write footer
|
||||
// 00 00 00 00 00 00 00 00 TRUEVISION-XFILE 2E 00
|
||||
out.write(new byte[]{0,0,0,0,0,0,0,0});
|
||||
if (verbatim)
|
||||
out.write("TRUEVISION-XFILE".getBytes());
|
||||
else
|
||||
out.write("TerrarumHappyTGA".getBytes());
|
||||
out.write(new byte[]{0x2E,0});
|
||||
|
||||
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
|
||||
private static byte[] zeroalpha = new byte[]{0,0,0,0};
|
||||
private static void writeTga(int x, int y, boolean verbatim, Pixmap pixmap, OutputStream out) throws IOException {
|
||||
int color = pixmap.getPixel(x, y);
|
||||
|
||||
// if alpha == 0, write special value instead
|
||||
if (verbatim && (color & 0xFF) == 0) {
|
||||
out.write(zeroalpha);
|
||||
}
|
||||
else {
|
||||
out.write(RGBAtoBGRA(color));
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] toShortLittle(int i) {
|
||||
return new byte[]{
|
||||
(byte) (i & 0xFF),
|
||||
(byte) ((i >>> 8) & 0xFF)
|
||||
};
|
||||
}
|
||||
|
||||
private static byte[] RGBAtoBGRA(int rgba) {
|
||||
return new byte[]{
|
||||
(byte) ((rgba >>> 8) & 0xFF),
|
||||
(byte) ((rgba >>> 16) & 0xFF),
|
||||
(byte) ((rgba >>> 24) & 0xFF),
|
||||
(byte) (rgba & 0xFF)
|
||||
};
|
||||
}
|
||||
}
|
||||
743
src/net/torvald/gdx/lwjgl/LwjglGraphics.java.txt
Normal file
743
src/net/torvald/gdx/lwjgl/LwjglGraphics.java.txt
Normal file
@@ -0,0 +1,743 @@
|
||||
/*******************************************************************************
|
||||
* Copyright 2011 See AUTHORS file.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
|
||||
package com.badlogic.gdx.backends.lwjgl;
|
||||
|
||||
import com.badlogic.gdx.Application;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Graphics;
|
||||
import com.badlogic.gdx.graphics.Cursor.SystemCursor;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.GL30;
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.graphics.Pixmap.Format;
|
||||
import com.badlogic.gdx.graphics.glutils.GLVersion;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException;
|
||||
import com.badlogic.gdx.utils.SharedLibraryLoader;
|
||||
import org.lwjgl.LWJGLException;
|
||||
import org.lwjgl.input.Mouse;
|
||||
import org.lwjgl.opengl.ContextAttribs;
|
||||
import org.lwjgl.opengl.Display;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.PixelFormat;
|
||||
|
||||
import java.awt.*;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/** An implementation of the {@link Graphics} interface based on Lwjgl.
|
||||
* @author mzechner */
|
||||
public class LwjglGraphics implements Graphics {
|
||||
|
||||
/** The suppored OpenGL extensions */
|
||||
static Array<String> extensions;
|
||||
static GLVersion glVersion;
|
||||
|
||||
GL20 gl20;
|
||||
GL30 gl30;
|
||||
long frameId = -1;
|
||||
float deltaTime = 0;
|
||||
long frameStart = 0;
|
||||
int frames = 0;
|
||||
int fps;
|
||||
long lastTime = System.nanoTime();
|
||||
Canvas canvas;
|
||||
boolean vsync = false;
|
||||
boolean resize = false;
|
||||
LwjglApplicationConfiguration config;
|
||||
BufferFormat bufferFormat = new BufferFormat(8, 8, 8, 8, 16, 8, 0, false);
|
||||
volatile boolean isContinuous = true;
|
||||
volatile boolean requestRendering = false;
|
||||
boolean softwareMode;
|
||||
boolean usingGL30;
|
||||
|
||||
// deltaTime kalman filter related variables
|
||||
private float kalmanEstimate = 1.0f/60.0f;
|
||||
private float kalmanErrorCovariance = 1.0f;
|
||||
private final float kalmanErrorRate = 0.2f; // 0.2: empirical value
|
||||
private final float kalmanUpdateThreshold = 0.1f;
|
||||
private final float getMagnitudeDifferenceEpsilon = 0.00001f;
|
||||
|
||||
LwjglGraphics (LwjglApplicationConfiguration config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
LwjglGraphics (Canvas canvas) {
|
||||
this.config = new LwjglApplicationConfiguration();
|
||||
config.width = canvas.getWidth();
|
||||
config.height = canvas.getHeight();
|
||||
this.canvas = canvas;
|
||||
}
|
||||
|
||||
LwjglGraphics (Canvas canvas, LwjglApplicationConfiguration config) {
|
||||
this.config = config;
|
||||
this.canvas = canvas;
|
||||
}
|
||||
|
||||
|
||||
public int getHeight () {
|
||||
if (canvas != null)
|
||||
return Math.max(1, canvas.getHeight());
|
||||
else
|
||||
return (int)(Display.getHeight() * Display.getPixelScaleFactor());
|
||||
}
|
||||
|
||||
public int getWidth () {
|
||||
if (canvas != null)
|
||||
return Math.max(1, canvas.getWidth());
|
||||
else
|
||||
return (int)(Display.getWidth() * Display.getPixelScaleFactor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBackBufferWidth () {
|
||||
return getWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBackBufferHeight () {
|
||||
return getHeight();
|
||||
}
|
||||
|
||||
|
||||
public long getFrameId () {
|
||||
return frameId;
|
||||
}
|
||||
|
||||
public float getDeltaTime () {
|
||||
return kalmanEstimate;
|
||||
}
|
||||
|
||||
private void resetDeltaSmoothingHistory() {
|
||||
kalmanEstimate = 1.0f/60.0f;
|
||||
kalmanErrorCovariance = 1.0f;
|
||||
}
|
||||
|
||||
// only for a > 0 && b > 0
|
||||
private float getMagnitudeDifference(float a, float b) {
|
||||
if (a < getMagnitudeDifferenceEpsilon || b < getMagnitudeDifferenceEpsilon) {
|
||||
return (a + b) / getMagnitudeDifferenceEpsilon;
|
||||
}
|
||||
|
||||
if (a > b) {
|
||||
return a / b;
|
||||
}
|
||||
else {
|
||||
return b / a;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateKalmanRenderDelta() {
|
||||
// The problem with this kalman filter is that it assumes most simplistic situation:
|
||||
// 1. the actual delta (measured delta - noise) is constant (that is, not constantly increasing or something)
|
||||
// 2. everything is linear
|
||||
// We may need to implement Extended Kalman Filter but what is Jacobian, I suck at maths.
|
||||
//
|
||||
// Instead, this implementation will reset itself when difference in magnitude between
|
||||
// old and new is greater than set value.
|
||||
//
|
||||
// It's not perfect but it works, much better than averaging.
|
||||
|
||||
if (getMagnitudeDifference(deltaTime, kalmanEstimate) >= 2.0) {
|
||||
resetDeltaSmoothingHistory();
|
||||
}
|
||||
|
||||
// measurement value
|
||||
float observation = deltaTime;
|
||||
|
||||
if (observation <= kalmanUpdateThreshold) {
|
||||
// time update
|
||||
float priorEstimate = kalmanEstimate;
|
||||
float priorError = kalmanErrorCovariance;
|
||||
|
||||
// measurement update
|
||||
float gain = priorError / (priorError + kalmanErrorRate);
|
||||
float newEstimate = priorEstimate + gain * (observation - priorEstimate);
|
||||
float newError = (1.0f - gain) * priorError;
|
||||
|
||||
kalmanEstimate = newEstimate;
|
||||
kalmanErrorCovariance = newError;
|
||||
}
|
||||
}
|
||||
|
||||
public float getRawDeltaTime () {
|
||||
return deltaTime;
|
||||
}
|
||||
|
||||
public GraphicsType getType () {
|
||||
return GraphicsType.LWJGL;
|
||||
}
|
||||
|
||||
public GLVersion getGLVersion () {
|
||||
return glVersion;
|
||||
}
|
||||
|
||||
public boolean isGL20Available () {
|
||||
return gl20 != null;
|
||||
}
|
||||
|
||||
public GL20 getGL20 () {
|
||||
return gl20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGL20 (GL20 gl20) {
|
||||
this.gl20 = gl20;
|
||||
if (gl30 == null) {
|
||||
Gdx.gl = gl20;
|
||||
Gdx.gl20 = gl20;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGL30Available () {
|
||||
return gl30 != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GL30 getGL30 () {
|
||||
return gl30;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGL30 (GL30 gl30) {
|
||||
this.gl30 = gl30;
|
||||
if (gl30 != null) {
|
||||
this.gl20 = gl30;
|
||||
|
||||
Gdx.gl = gl20;
|
||||
Gdx.gl20 = gl20;
|
||||
Gdx.gl30 = gl30;
|
||||
}
|
||||
}
|
||||
|
||||
public int getFramesPerSecond () {
|
||||
return fps;
|
||||
}
|
||||
|
||||
void updateTime () {
|
||||
long time = System.nanoTime();
|
||||
deltaTime = (time - lastTime) / 1000000000.0f;
|
||||
lastTime = time;
|
||||
|
||||
if (time - frameStart >= 1000000000) {
|
||||
fps = frames;
|
||||
frames = 0;
|
||||
frameStart = time;
|
||||
}
|
||||
frames++;
|
||||
|
||||
updateKalmanRenderDelta();
|
||||
}
|
||||
|
||||
void setupDisplay () throws LWJGLException {
|
||||
if (config.useHDPI) {
|
||||
System.setProperty("org.lwjgl.opengl.Display.enableHighDPI", "true");
|
||||
}
|
||||
|
||||
if (canvas != null) {
|
||||
Display.setParent(canvas);
|
||||
} else {
|
||||
boolean displayCreated = false;
|
||||
|
||||
if(!config.fullscreen) {
|
||||
displayCreated = setWindowedMode(config.width, config.height);
|
||||
} else {
|
||||
DisplayMode bestMode = null;
|
||||
for(DisplayMode mode: getDisplayModes()) {
|
||||
if(mode.width == config.width && mode.height == config.height) {
|
||||
if(bestMode == null || bestMode.refreshRate < this.getDisplayMode().refreshRate) {
|
||||
bestMode = mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(bestMode == null) {
|
||||
bestMode = this.getDisplayMode();
|
||||
}
|
||||
displayCreated = setFullscreenMode(bestMode);
|
||||
}
|
||||
if (!displayCreated) {
|
||||
if (config.setDisplayModeCallback != null) {
|
||||
config = config.setDisplayModeCallback.onFailure(config);
|
||||
if (config != null) {
|
||||
displayCreated = setWindowedMode(config.width, config.height);
|
||||
}
|
||||
}
|
||||
if (!displayCreated) {
|
||||
throw new GdxRuntimeException("Couldn't set display mode " + config.width + "x" + config.height + ", fullscreen: "
|
||||
+ config.fullscreen);
|
||||
}
|
||||
}
|
||||
if (config.iconPaths.size > 0) {
|
||||
ByteBuffer[] icons = new ByteBuffer[config.iconPaths.size];
|
||||
for (int i = 0, n = config.iconPaths.size; i < n; i++) {
|
||||
Pixmap pixmap = new Pixmap(Gdx.files.getFileHandle(config.iconPaths.get(i), config.iconFileTypes.get(i)));
|
||||
if (pixmap.getFormat() != Format.RGBA8888) {
|
||||
Pixmap rgba = new Pixmap(pixmap.getWidth(), pixmap.getHeight(), Format.RGBA8888);
|
||||
rgba.drawPixmap(pixmap, 0, 0);
|
||||
pixmap.dispose();
|
||||
pixmap = rgba;
|
||||
}
|
||||
icons[i] = ByteBuffer.allocateDirect(pixmap.getPixels().limit());
|
||||
icons[i].put(pixmap.getPixels()).flip();
|
||||
pixmap.dispose();
|
||||
}
|
||||
Display.setIcon(icons);
|
||||
}
|
||||
}
|
||||
Display.setTitle(config.title);
|
||||
Display.setResizable(config.resizable);
|
||||
Display.setInitialBackground(config.initialBackgroundColor.r, config.initialBackgroundColor.g,
|
||||
config.initialBackgroundColor.b);
|
||||
|
||||
Display.setLocation(config.x, config.y);
|
||||
createDisplayPixelFormat(config.useGL30, config.gles30ContextMajorVersion, config.gles30ContextMinorVersion);
|
||||
initiateGL();
|
||||
}
|
||||
|
||||
/**
|
||||
* Only needed when setupDisplay() is not called.
|
||||
*/
|
||||
void initiateGL() {
|
||||
extractVersion();
|
||||
extractExtensions();
|
||||
initiateGLInstances();
|
||||
}
|
||||
|
||||
private static void extractVersion () {
|
||||
String versionString = org.lwjgl.opengl.GL11.glGetString(GL11.GL_VERSION);
|
||||
String vendorString = org.lwjgl.opengl.GL11.glGetString(GL11.GL_VENDOR);
|
||||
String rendererString = org.lwjgl.opengl.GL11.glGetString(GL11.GL_RENDERER);
|
||||
glVersion = new GLVersion(Application.ApplicationType.Desktop, versionString, vendorString, rendererString);
|
||||
}
|
||||
|
||||
private static void extractExtensions () {
|
||||
extensions = new Array<String>();
|
||||
if (glVersion.isVersionEqualToOrHigher(3, 2)) {
|
||||
int numExtensions = GL11.glGetInteger(GL30.GL_NUM_EXTENSIONS);
|
||||
for (int i = 0; i < numExtensions; ++i)
|
||||
extensions.add(org.lwjgl.opengl.GL30.glGetStringi(GL20.GL_EXTENSIONS, i));
|
||||
} else {
|
||||
extensions.addAll(org.lwjgl.opengl.GL11.glGetString(GL20.GL_EXTENSIONS).split(" "));
|
||||
}
|
||||
}
|
||||
|
||||
/** @return whether the supported OpenGL (not ES) version is compatible with OpenGL ES 3.x. */
|
||||
private static boolean fullCompatibleWithGLES3 () {
|
||||
// OpenGL ES 3.0 is compatible with OpenGL 4.3 core, see http://en.wikipedia.org/wiki/OpenGL_ES#OpenGL_ES_3.0
|
||||
return glVersion.isVersionEqualToOrHigher(4, 3);
|
||||
}
|
||||
|
||||
/** @return whether the supported OpenGL (not ES) version is compatible with OpenGL ES 2.x. */
|
||||
private static boolean fullCompatibleWithGLES2 () {
|
||||
// OpenGL ES 2.0 is compatible with OpenGL 4.1 core
|
||||
// see https://www.opengl.org/registry/specs/ARB/ES2_compatibility.txt
|
||||
return glVersion.isVersionEqualToOrHigher(4, 1) || extensions.contains("GL_ARB_ES2_compatibility", false);
|
||||
}
|
||||
|
||||
private static boolean supportsFBO () {
|
||||
// FBO is in core since OpenGL 3.0, see https://www.opengl.org/wiki/Framebuffer_Object
|
||||
return glVersion.isVersionEqualToOrHigher(3, 0) || extensions.contains("GL_EXT_framebuffer_object", false)
|
||||
|| extensions.contains("GL_ARB_framebuffer_object", false);
|
||||
}
|
||||
|
||||
private void createDisplayPixelFormat (boolean useGL30, int gles30ContextMajor, int gles30ContextMinor) {
|
||||
try {
|
||||
if (useGL30) {
|
||||
ContextAttribs context = new ContextAttribs(gles30ContextMajor, gles30ContextMinor).withForwardCompatible(false)
|
||||
.withProfileCore(true);
|
||||
try {
|
||||
Display.create(new PixelFormat(config.r + config.g + config.b, config.a, config.depth, config.stencil,
|
||||
config.samples), context);
|
||||
} catch (Exception e) {
|
||||
System.out.println("LwjglGraphics: OpenGL " + gles30ContextMajor + "." + gles30ContextMinor
|
||||
+ "+ core profile (GLES 3.0) not supported.");
|
||||
createDisplayPixelFormat(false, gles30ContextMajor, gles30ContextMinor);
|
||||
return;
|
||||
}
|
||||
System.out.println("LwjglGraphics: created OpenGL " + gles30ContextMajor + "." + gles30ContextMinor
|
||||
+ "+ core profile (GLES 3.0) context. This is experimental!");
|
||||
usingGL30 = true;
|
||||
} else {
|
||||
Display
|
||||
.create(new PixelFormat(config.r + config.g + config.b, config.a, config.depth, config.stencil, config.samples));
|
||||
usingGL30 = false;
|
||||
}
|
||||
bufferFormat = new BufferFormat(config.r, config.g, config.b, config.a, config.depth, config.stencil, config.samples,
|
||||
false);
|
||||
} catch (Exception ex) {
|
||||
Display.destroy();
|
||||
try {
|
||||
Thread.sleep(200);
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
try {
|
||||
Display.create(new PixelFormat(0, 16, 8));
|
||||
if (getDisplayMode().bitsPerPixel == 16) {
|
||||
bufferFormat = new BufferFormat(5, 6, 5, 0, 16, 8, 0, false);
|
||||
}
|
||||
if (getDisplayMode().bitsPerPixel == 24) {
|
||||
bufferFormat = new BufferFormat(8, 8, 8, 0, 16, 8, 0, false);
|
||||
}
|
||||
if (getDisplayMode().bitsPerPixel == 32) {
|
||||
bufferFormat = new BufferFormat(8, 8, 8, 8, 16, 8, 0, false);
|
||||
}
|
||||
} catch (Exception ex2) {
|
||||
Display.destroy();
|
||||
try {
|
||||
Thread.sleep(200);
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
try {
|
||||
Display.create(new PixelFormat());
|
||||
} catch (Exception ex3) {
|
||||
if (!softwareMode && config.allowSoftwareMode) {
|
||||
softwareMode = true;
|
||||
System.setProperty("org.lwjgl.opengl.Display.allowSoftwareOpenGL", "true");
|
||||
createDisplayPixelFormat(useGL30, gles30ContextMajor, gles30ContextMinor);
|
||||
return;
|
||||
}
|
||||
throw new GdxRuntimeException("OpenGL is not supported by the video driver.", ex3);
|
||||
}
|
||||
if (getDisplayMode().bitsPerPixel == 16) {
|
||||
bufferFormat = new BufferFormat(5, 6, 5, 0, 8, 0, 0, false);
|
||||
}
|
||||
if (getDisplayMode().bitsPerPixel == 24) {
|
||||
bufferFormat = new BufferFormat(8, 8, 8, 0, 8, 0, 0, false);
|
||||
}
|
||||
if (getDisplayMode().bitsPerPixel == 32) {
|
||||
bufferFormat = new BufferFormat(8, 8, 8, 8, 8, 0, 0, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void initiateGLInstances () {
|
||||
if (usingGL30) {
|
||||
gl30 = new LwjglGL30();
|
||||
gl20 = gl30;
|
||||
} else {
|
||||
gl20 = new LwjglGL20();
|
||||
}
|
||||
|
||||
if (!glVersion.isVersionEqualToOrHigher(2, 0))
|
||||
throw new GdxRuntimeException("OpenGL 2.0 or higher with the FBO extension is required. OpenGL version: "
|
||||
+ GL11.glGetString(GL11.GL_VERSION) + "\n" + glVersion.getDebugVersionString());
|
||||
|
||||
if (!supportsFBO()) {
|
||||
throw new GdxRuntimeException("OpenGL 2.0 or higher with the FBO extension is required. OpenGL version: "
|
||||
+ GL11.glGetString(GL11.GL_VERSION) + ", FBO extension: false\n" + glVersion.getDebugVersionString());
|
||||
}
|
||||
|
||||
Gdx.gl = gl20;
|
||||
Gdx.gl20 = gl20;
|
||||
Gdx.gl30 = gl30;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPpiX () {
|
||||
return Toolkit.getDefaultToolkit().getScreenResolution();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPpiY () {
|
||||
return Toolkit.getDefaultToolkit().getScreenResolution();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPpcX () {
|
||||
return (Toolkit.getDefaultToolkit().getScreenResolution() / 2.54f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPpcY () {
|
||||
return (Toolkit.getDefaultToolkit().getScreenResolution() / 2.54f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getDensity () {
|
||||
if (config.overrideDensity != -1) return config.overrideDensity / 160f;
|
||||
return (Toolkit.getDefaultToolkit().getScreenResolution() / 160f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsDisplayModeChange () {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Monitor getPrimaryMonitor () {
|
||||
return new LwjglMonitor(0, 0, "Primary Monitor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Monitor getMonitor () {
|
||||
return getPrimaryMonitor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Monitor[] getMonitors () {
|
||||
return new Monitor[] { getPrimaryMonitor() };
|
||||
}
|
||||
|
||||
@Override
|
||||
public DisplayMode[] getDisplayModes (Monitor monitor) {
|
||||
return getDisplayModes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DisplayMode getDisplayMode (Monitor monitor) {
|
||||
return getDisplayMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setFullscreenMode (DisplayMode displayMode) {
|
||||
org.lwjgl.opengl.DisplayMode mode = ((LwjglDisplayMode)displayMode).mode;
|
||||
try {
|
||||
if (!mode.isFullscreenCapable()) {
|
||||
Display.setDisplayMode(mode);
|
||||
} else {
|
||||
Display.setDisplayModeAndFullscreen(mode);
|
||||
}
|
||||
float scaleFactor = Display.getPixelScaleFactor();
|
||||
config.width = (int)(mode.getWidth() * scaleFactor);
|
||||
config.height = (int)(mode.getHeight() * scaleFactor);
|
||||
if (Gdx.gl != null) Gdx.gl.glViewport(0, 0, config.width, config.height);
|
||||
resize = true;
|
||||
return true;
|
||||
} catch (LWJGLException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Kindly stolen from http://lwjgl.org/wiki/index.php?title=LWJGL_Basics_5_(Fullscreen), not perfect but will do. */
|
||||
@Override
|
||||
public boolean setWindowedMode (int width, int height) {
|
||||
if (getWidth() == width && getHeight() == height && !Display.isFullscreen()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
org.lwjgl.opengl.DisplayMode targetDisplayMode = null;
|
||||
boolean fullscreen = false;
|
||||
|
||||
if (fullscreen) {
|
||||
org.lwjgl.opengl.DisplayMode[] modes = Display.getAvailableDisplayModes();
|
||||
int freq = 0;
|
||||
|
||||
for (int i = 0; i < modes.length; i++) {
|
||||
org.lwjgl.opengl.DisplayMode current = modes[i];
|
||||
|
||||
if ((current.getWidth() == width) && (current.getHeight() == height)) {
|
||||
if ((targetDisplayMode == null) || (current.getFrequency() >= freq)) {
|
||||
if ((targetDisplayMode == null) || (current.getBitsPerPixel() > targetDisplayMode.getBitsPerPixel())) {
|
||||
targetDisplayMode = current;
|
||||
freq = targetDisplayMode.getFrequency();
|
||||
}
|
||||
}
|
||||
|
||||
// if we've found a match for bpp and frequence against the
|
||||
// original display mode then it's probably best to go for this one
|
||||
// since it's most likely compatible with the monitor
|
||||
if ((current.getBitsPerPixel() == Display.getDesktopDisplayMode().getBitsPerPixel())
|
||||
&& (current.getFrequency() == Display.getDesktopDisplayMode().getFrequency())) {
|
||||
targetDisplayMode = current;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
targetDisplayMode = new org.lwjgl.opengl.DisplayMode(width, height);
|
||||
}
|
||||
|
||||
if (targetDisplayMode == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean resizable = !fullscreen && config.resizable;
|
||||
|
||||
Display.setDisplayMode(targetDisplayMode);
|
||||
Display.setFullscreen(fullscreen);
|
||||
// Workaround for bug in LWJGL whereby resizable state is lost on DisplayMode change
|
||||
if (resizable == Display.isResizable()) {
|
||||
Display.setResizable(!resizable);
|
||||
}
|
||||
Display.setResizable(resizable);
|
||||
|
||||
float scaleFactor = Display.getPixelScaleFactor();
|
||||
config.width = (int)(targetDisplayMode.getWidth() * scaleFactor);
|
||||
config.height = (int)(targetDisplayMode.getHeight() * scaleFactor);
|
||||
if (Gdx.gl != null) Gdx.gl.glViewport(0, 0, config.width, config.height);
|
||||
resize = true;
|
||||
return true;
|
||||
} catch (LWJGLException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DisplayMode[] getDisplayModes () {
|
||||
try {
|
||||
org.lwjgl.opengl.DisplayMode[] availableDisplayModes = Display.getAvailableDisplayModes();
|
||||
DisplayMode[] modes = new DisplayMode[availableDisplayModes.length];
|
||||
|
||||
int idx = 0;
|
||||
for (org.lwjgl.opengl.DisplayMode mode : availableDisplayModes) {
|
||||
if (mode.isFullscreenCapable()) {
|
||||
modes[idx++] = new LwjglDisplayMode(mode.getWidth(), mode.getHeight(), mode.getFrequency(),
|
||||
mode.getBitsPerPixel(), mode);
|
||||
}
|
||||
}
|
||||
|
||||
return modes;
|
||||
} catch (LWJGLException e) {
|
||||
throw new GdxRuntimeException("Couldn't fetch available display modes", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DisplayMode getDisplayMode () {
|
||||
org.lwjgl.opengl.DisplayMode mode = Display.getDesktopDisplayMode();
|
||||
return new LwjglDisplayMode(mode.getWidth(), mode.getHeight(), mode.getFrequency(), mode.getBitsPerPixel(), mode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle (String title) {
|
||||
Display.setTitle(title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display must be reconfigured via {@link #setWindowedMode(int, int)} for the changes to take
|
||||
* effect.
|
||||
*/
|
||||
@Override
|
||||
public void setUndecorated (boolean undecorated) {
|
||||
System.setProperty("org.lwjgl.opengl.Window.undecorated", undecorated ? "true" : "false");
|
||||
}
|
||||
|
||||
/**
|
||||
* Display must be reconfigured via {@link #setWindowedMode(int, int)} for the changes to take
|
||||
* effect.
|
||||
*/
|
||||
@Override
|
||||
public void setResizable (boolean resizable) {
|
||||
this.config.resizable = resizable;
|
||||
Display.setResizable(resizable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferFormat getBufferFormat () {
|
||||
return bufferFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVSync (boolean vsync) {
|
||||
this.vsync = vsync;
|
||||
Display.setVSyncEnabled(vsync);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsExtension (String extension) {
|
||||
return extensions.contains(extension, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContinuousRendering (boolean isContinuous) {
|
||||
this.isContinuous = isContinuous;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isContinuousRendering () {
|
||||
return isContinuous;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestRendering () {
|
||||
synchronized (this) {
|
||||
requestRendering = true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldRender () {
|
||||
synchronized (this) {
|
||||
boolean rq = requestRendering;
|
||||
requestRendering = false;
|
||||
return rq || isContinuous || Display.isDirty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFullscreen () {
|
||||
return Display.isFullscreen();
|
||||
}
|
||||
|
||||
public boolean isSoftwareMode () {
|
||||
return softwareMode;
|
||||
}
|
||||
|
||||
/** A callback used by LwjglApplication when trying to create the display */
|
||||
public interface SetDisplayModeCallback {
|
||||
/** If the display creation fails, this method will be called. Suggested usage is to modify the passed configuration to use a
|
||||
* common width and height, and set fullscreen to false.
|
||||
* @return the configuration to be used for a second attempt at creating a display. A null value results in NOT attempting
|
||||
* to create the display a second time */
|
||||
public LwjglApplicationConfiguration onFailure (LwjglApplicationConfiguration initialConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public com.badlogic.gdx.graphics.Cursor newCursor (Pixmap pixmap, int xHotspot, int yHotspot) {
|
||||
return new LwjglCursor(pixmap, xHotspot, yHotspot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCursor (com.badlogic.gdx.graphics.Cursor cursor) {
|
||||
if (canvas != null && SharedLibraryLoader.isMac) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Mouse.setNativeCursor(((LwjglCursor)cursor).lwjglCursor);
|
||||
} catch (LWJGLException e) {
|
||||
throw new GdxRuntimeException("Could not set cursor image.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSystemCursor (SystemCursor systemCursor) {
|
||||
if (canvas != null && SharedLibraryLoader.isMac) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Mouse.setNativeCursor(null);
|
||||
} catch (LWJGLException e) {
|
||||
throw new GdxRuntimeException("Couldn't set system cursor");
|
||||
}
|
||||
}
|
||||
|
||||
private class LwjglDisplayMode extends DisplayMode {
|
||||
org.lwjgl.opengl.DisplayMode mode;
|
||||
|
||||
public LwjglDisplayMode (int width, int height, int refreshRate, int bitsPerPixel, org.lwjgl.opengl.DisplayMode mode) {
|
||||
super(width, height, refreshRate, bitsPerPixel);
|
||||
this.mode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
private class LwjglMonitor extends Monitor {
|
||||
protected LwjglMonitor (int virtualX, int virtualY, String name) {
|
||||
super(virtualX, virtualY, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
0
src/net/torvald/gdx/lwjgl/audio/OpenALAudio.java
Normal file
0
src/net/torvald/gdx/lwjgl/audio/OpenALAudio.java
Normal file
@@ -5,23 +5,15 @@ import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.Screen
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.Pixmap
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.math.Affine2
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.colourutil.CIEYXY
|
||||
import net.torvald.colourutil.CIEXYZUtil.toXYZ
|
||||
import net.torvald.colourutil.CIEXYZUtil.toColorRaw
|
||||
import net.torvald.colourutil.CIEXYZUtil.toColor
|
||||
import net.torvald.colourutil.RGB
|
||||
import net.torvald.terrarum.gameworld.fmod
|
||||
import net.torvald.colourutil.CIEXYZUtil.toXYZ
|
||||
import net.torvald.colourutil.CIEYXY
|
||||
import net.torvald.terrarum.inUse
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Dimension
|
||||
import javax.swing.*
|
||||
import kotlin.math.pow
|
||||
|
||||
|
||||
const val WIDTH = 1200
|
||||
|
||||
@@ -6,9 +6,9 @@ import com.badlogic.gdx.backends.lwjgl.LwjglApplication
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.Pixmap
|
||||
import com.badlogic.gdx.graphics.PixmapIO2
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.gdx.graphics.PixmapIO2
|
||||
import net.torvald.terrarum.gdxClearAndSetBlend
|
||||
import net.torvald.terrarum.inUse
|
||||
import java.awt.BorderLayout
|
||||
@@ -258,7 +258,7 @@ class SpriteAssemblerPreview: Game() {
|
||||
renderTexture = Texture(1, 1, Pixmap.Format.RGBA8888)
|
||||
}
|
||||
|
||||
private val bgCol = Color(.62f,.79f,1f,1f)
|
||||
private val bgCol = Color(.62f, .79f, 1f, 1f)
|
||||
|
||||
private var doAssemble = false
|
||||
private lateinit var assembleProp: ADProperties
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.github.strikerx3.jxinput.XInputDevice;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import net.torvald.gdx.graphics.PixmapIO2;
|
||||
import net.torvald.getcpuname.GetCpuName;
|
||||
import net.torvald.terrarum.controller.GdxControllerAdapter;
|
||||
import net.torvald.terrarum.controller.TerrarumController;
|
||||
@@ -255,8 +256,8 @@ public class AppLoader implements ApplicationListener {
|
||||
public static TextureRegion logo;
|
||||
public static AudioDevice audioDevice;
|
||||
|
||||
private Color gradWhiteTop = new Color(0xf8f8f8ff);
|
||||
private Color gradWhiteBottom = new Color(0xd8d8d8ff);
|
||||
private com.badlogic.gdx.graphics.Color gradWhiteTop = new com.badlogic.gdx.graphics.Color(0xf8f8f8ff);
|
||||
private com.badlogic.gdx.graphics.Color gradWhiteBottom = new com.badlogic.gdx.graphics.Color(0xd8d8d8ff);
|
||||
|
||||
public Screen screen;
|
||||
public static int screenW = 0;
|
||||
|
||||
@@ -7,7 +7,7 @@ import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
|
||||
import com.badlogic.gdx.graphics.*
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram
|
||||
import com.jme3.math.FastMath
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import net.torvald.terrarumsansbitmap.gdx.GameFontBase
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.badlogic.gdx.graphics.g2d.BitmapFont
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import net.torvald.terrarumsansbitmap.gdx.GameFontBase
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package net.torvald.terrarum.blockproperties
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import net.torvald.gdx.graphics.Cvec
|
||||
import net.torvald.terrarum.AppLoader
|
||||
import net.torvald.terrarum.AppLoader.printmsg
|
||||
import net.torvald.terrarum.gameworld.FluidType
|
||||
@@ -110,7 +110,7 @@ object BlockCodex {
|
||||
prop.shadeColG = floatVal(record, "shdg") / LightmapRenderer.MUL_FLOAT
|
||||
prop.shadeColB = floatVal(record, "shdb") / LightmapRenderer.MUL_FLOAT
|
||||
prop.shadeColA = floatVal(record, "shduv") / LightmapRenderer.MUL_FLOAT
|
||||
prop.opacity = Color(prop.shadeColR, prop.shadeColG, prop.shadeColB, prop.shadeColA)
|
||||
prop.opacity = Cvec(prop.shadeColR, prop.shadeColG, prop.shadeColB, prop.shadeColA)
|
||||
|
||||
prop.strength = intVal(record, "str")
|
||||
prop.density = intVal(record, "dsty")
|
||||
@@ -119,7 +119,7 @@ object BlockCodex {
|
||||
prop.lumColG = floatVal(record, "lumg") / LightmapRenderer.MUL_FLOAT
|
||||
prop.lumColB = floatVal(record, "lumb") / LightmapRenderer.MUL_FLOAT
|
||||
prop.lumColA = floatVal(record, "lumuv") / LightmapRenderer.MUL_FLOAT
|
||||
prop.internalLumCol = Color(prop.lumColR, prop.lumColG, prop.lumColB, prop.lumColA)
|
||||
prop.internalLumCol = Cvec(prop.lumColR, prop.lumColG, prop.lumColB, prop.lumColA)
|
||||
|
||||
prop.friction = intVal(record, "fr")
|
||||
prop.viscosity = intVal(record, "vscs")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package net.torvald.terrarum.blockproperties
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import net.torvald.gdx.graphics.Cvec
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-02-16.
|
||||
@@ -17,7 +17,7 @@ class BlockProp {
|
||||
var shadeColB = 0f
|
||||
var shadeColA = 0f
|
||||
|
||||
lateinit var opacity: Color
|
||||
lateinit var opacity: Cvec
|
||||
|
||||
var strength: Int = 0
|
||||
var density: Int = 0
|
||||
@@ -36,12 +36,12 @@ class BlockProp {
|
||||
var lumColG = 0f
|
||||
var lumColB = 0f
|
||||
var lumColA = 0f
|
||||
lateinit var internalLumCol: Color
|
||||
lateinit var internalLumCol: Cvec
|
||||
|
||||
/**
|
||||
* @param luminosity
|
||||
*/
|
||||
inline val luminosity: Color
|
||||
inline val luminosity: Cvec
|
||||
get() = BlockPropUtil.getDynamicLumFunc(internalLumCol, dynamicLuminosityFunction)
|
||||
|
||||
var drop: Int = 0
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package net.torvald.terrarum.blockproperties
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.gdx.graphics.Cvec
|
||||
import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.Second
|
||||
import net.torvald.terrarum.Terrarum
|
||||
@@ -37,7 +37,7 @@ object BlockPropUtil {
|
||||
|
||||
}
|
||||
|
||||
private fun getTorchFlicker(baseLum: Color): Color {
|
||||
private fun getTorchFlicker(baseLum: Cvec): Cvec {
|
||||
val funcY = FastMath.interpolateCatmullRom(0.0f, flickerFuncX / flickerFuncDomain,
|
||||
flickerP0, flickerP1, flickerP2, flickerP3
|
||||
)
|
||||
@@ -45,13 +45,13 @@ object BlockPropUtil {
|
||||
return LightmapRenderer.alterBrightnessUniform(baseLum, funcY)
|
||||
}
|
||||
|
||||
private fun getSlowBreath(baseLum: Color): Color {
|
||||
private fun getSlowBreath(baseLum: Cvec): Cvec {
|
||||
val funcY = FastMath.sin(FastMath.PI * breathFuncX / breathCycleDuration) * breathRange
|
||||
|
||||
return LightmapRenderer.alterBrightnessUniform(baseLum, funcY)
|
||||
}
|
||||
|
||||
private fun getPulsate(baseLum: Color): Color {
|
||||
private fun getPulsate(baseLum: Cvec): Cvec {
|
||||
val funcY = FastMath.sin(FastMath.PI * pulsateFuncX / pulsateCycleDuration) * pulsateRange
|
||||
|
||||
return LightmapRenderer.alterBrightnessUniform(baseLum, funcY)
|
||||
@@ -91,7 +91,7 @@ object BlockPropUtil {
|
||||
|
||||
private fun linearInterpolation1D(a: Float, b: Float, x: Float) = a * (1 - x) + b * x
|
||||
|
||||
fun getDynamicLumFunc(baseLum: Color, type: Int): Color {
|
||||
fun getDynamicLumFunc(baseLum: Cvec, type: Int): Cvec {
|
||||
return when (type) {
|
||||
1 -> getTorchFlicker(baseLum)
|
||||
2 -> (Terrarum.ingame!!.world).globalLight.cpy().mul(LightmapRenderer.DIV_FLOAT) // current global light
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package net.torvald.terrarum.console
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import net.torvald.terrarum.worlddrawer.LightmapRenderer
|
||||
import net.torvald.gdx.graphics.Cvec
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.modulebasegame.weather.WeatherMixer
|
||||
import net.torvald.terrarum.worlddrawer.LightmapRenderer
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-02-17.
|
||||
@@ -18,7 +17,7 @@ internal object SetGlobalLightOverride : ConsoleCommand {
|
||||
val g = args[2].toFloat()
|
||||
val b = args[3].toFloat()
|
||||
val a = args[4].toFloat()
|
||||
val GL = Color(r, g, b, a)
|
||||
val GL = Cvec(r, g, b, a)
|
||||
|
||||
WeatherMixer.globalLightOverridden = true
|
||||
(Terrarum.ingame!!.world).globalLight = GL
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import net.torvald.gdx.graphics.Cvec
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-02-19.
|
||||
@@ -26,7 +26,7 @@ interface Luminous {
|
||||
actorValue[AVKey.LUMA] = value.a * LightmapRenderer.MUL_FLOAT
|
||||
}
|
||||
*/
|
||||
var color: Color
|
||||
var color: Cvec
|
||||
|
||||
/**
|
||||
* Arguments:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
package net.torvald.terrarum.gameworld
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import net.torvald.gdx.graphics.Cvec
|
||||
import net.torvald.terrarum.AppLoader.printdbg
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
@@ -90,7 +90,7 @@ open class GameWorld {
|
||||
/** Meter per second squared. Currently only the downward gravity is supported. No reverse gravity :p */
|
||||
var gravitation: Vector2 = Vector2(0.0, 9.80665)
|
||||
/** 0.0..1.0+ */
|
||||
var globalLight = Color(0f,0f,0f,0f)
|
||||
var globalLight = Cvec(0f, 0f, 0f, 0f)
|
||||
var averageTemperature = 288f // 15 deg celsius; simulates global warming
|
||||
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.badlogic.gdx.InputAdapter
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import net.torvald.gdx.graphics.Cvec
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
import net.torvald.terrarum.blockproperties.BlockCodex
|
||||
@@ -279,7 +280,7 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
init {
|
||||
gameWorld.time.setTimeOfToday(WorldTime.HOUR_SEC * 10)
|
||||
gameWorld.globalLight = Color(.8f,.8f,.8f,.8f)
|
||||
gameWorld.globalLight = Cvec(.8f, .8f, .8f, .8f)
|
||||
|
||||
essentialOverlays.add(blockPointingCursor)
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import com.badlogic.gdx.utils.ScreenUtils
|
||||
import net.torvald.gdx.graphics.PixmapIO2
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||
import net.torvald.terrarum.gamecontroller.KeyToggler
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.gdx.graphics.Cvec
|
||||
import net.torvald.spriteanimation.HasAssembledSprite
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.gameactors.*
|
||||
@@ -68,8 +68,8 @@ open class ActorHumanoid(
|
||||
if (houseDesignation != null) houseDesignation!!.clear()
|
||||
}
|
||||
|
||||
override var color: Color
|
||||
get() = Color(
|
||||
override var color: Cvec
|
||||
get() = Cvec(
|
||||
(actorValue.getAsFloat(AVKey.LUMR) ?: 0f) / LightmapRenderer.MUL_FLOAT,
|
||||
(actorValue.getAsFloat(AVKey.LUMG) ?: 0f) / LightmapRenderer.MUL_FLOAT,
|
||||
(actorValue.getAsFloat(AVKey.LUMB) ?: 0f) / LightmapRenderer.MUL_FLOAT,
|
||||
|
||||
@@ -2,9 +2,7 @@ package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.Pixmap
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.gameworld.toUint
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import java.io.File
|
||||
import java.nio.charset.Charset
|
||||
import java.util.*
|
||||
@@ -99,9 +97,9 @@ object DecodeTapestry {
|
||||
|
||||
private fun Int.fourBitCol() = Color(
|
||||
this.and(0xF00).shl(20) or this.and(0xF00).shl(16) or
|
||||
this.and(0x0F0).shl(16) or this.and(0x0F0).shl(12) or
|
||||
this.and(0x00F).shl(12) or this.and(0x00F).shl(8) or
|
||||
0xFF
|
||||
this.and(0x0F0).shl(16) or this.and(0x0F0).shl(12) or
|
||||
this.and(0x00F).shl(12) or this.and(0x00F).shl(8) or
|
||||
0xFF
|
||||
)
|
||||
|
||||
val MAGIC = "TEAF".toByteArray(charset = Charset.forName("US-ASCII"))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import net.torvald.gdx.graphics.Cvec
|
||||
import net.torvald.terrarum.ModMgr
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
import net.torvald.terrarum.blockproperties.BlockCodex
|
||||
@@ -15,7 +15,7 @@ import java.util.*
|
||||
*/
|
||||
internal class FixtureTikiTorch : FixtureBase(BlockBox(BlockBox.NO_COLLISION, 1, 2)), Luminous {
|
||||
|
||||
override var color: Color
|
||||
override var color: Cvec
|
||||
get() = BlockCodex[Block.TORCH].luminosity
|
||||
set(value) {
|
||||
throw UnsupportedOperationException()
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.gameactors.ActorWBMovable
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.modulebasegame.worldgenerator.RoguelikeRandomiser
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.gdx.graphics.Cvec
|
||||
import net.torvald.terrarum.Point2d
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
@@ -31,8 +32,8 @@ open class ProjectileSimple(
|
||||
val speed: Int
|
||||
|
||||
|
||||
override var color: Color
|
||||
get() = (bulletDatabase[type][OFFSET_LUMINOSITY] as Color).cpy()
|
||||
override var color: Cvec
|
||||
get() = (bulletDatabase[type][OFFSET_LUMINOSITY] as Cvec).cpy()
|
||||
set(value) {
|
||||
}
|
||||
/**
|
||||
@@ -118,8 +119,8 @@ open class ProjectileSimple(
|
||||
val OFFSET_LUMINOSITY = 4
|
||||
val bulletDatabase = arrayOf(
|
||||
// damage, display colour, no gravity, speed
|
||||
arrayOf(7, Color(0xFF5429_FF.toInt()), true, 40, 32),
|
||||
arrayOf(8, Color(0xFF5429_FF.toInt()), true, 20, 0)
|
||||
arrayOf(7, Cvec(0xFF5429_FF.toInt()), true, 40, 32),
|
||||
arrayOf(8, Cvec(0xFF5429_FF.toInt()), true, 20, 0)
|
||||
// ...
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import net.torvald.gdx.graphics.Cvec
|
||||
import net.torvald.terrarum.gameactors.ActorWBMovable
|
||||
import net.torvald.terrarum.gameactors.Hitbox
|
||||
import net.torvald.terrarum.gameactors.Luminous
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-04-26.
|
||||
@@ -21,7 +20,7 @@ class WeaponSwung(val itemID: Int) : ActorWBMovable(RenderOrder.MIDTOP), Luminou
|
||||
actorValue[AVKey.LUMINOSITY] = value
|
||||
}
|
||||
*/
|
||||
override var color: Color
|
||||
override var color: Cvec
|
||||
get() = throw UnsupportedOperationException()
|
||||
set(value) {
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ class Notification : UICanvas() {
|
||||
}
|
||||
}
|
||||
|
||||
private val drawColor = Color(1f,1f,1f,1f)
|
||||
private val drawColor = Color(1f, 1f, 1f, 1f)
|
||||
|
||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||
blendNormal(batch)
|
||||
|
||||
@@ -72,7 +72,7 @@ class UIBasicInfo(private val player: ActorHumanoid?) : UICanvas() {
|
||||
private val mailCount: Int
|
||||
get() = 0 // cap things at 99
|
||||
|
||||
private val drawCol = Color(1f,1f,1f,UIQuickslotBar.DISPLAY_OPACITY)
|
||||
private val drawCol = Color(1f, 1f, 1f, UIQuickslotBar.DISPLAY_OPACITY)
|
||||
private val lcdLitColELoff = Color(0xc0c0c0ff.toInt()) mul drawCol
|
||||
private val lcdLitColELon = Color(0x404040ff) mul drawCol
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.badlogic.gdx.graphics.*
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.AppLoader.IS_DEVELOPMENT_BUILD
|
||||
import net.torvald.terrarum.AppLoader.printdbg
|
||||
|
||||
@@ -42,7 +42,7 @@ class UIQuickslotBar : UICanvas() {
|
||||
override fun updateUI(delta: Float) {
|
||||
}
|
||||
|
||||
private val drawColor = Color(1f,1f,1f,1f)
|
||||
private val drawColor = Color(1f, 1f, 1f, 1f)
|
||||
|
||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ class UITierOneWatch(private val player: ActorHumanoid?) : UICanvas() {
|
||||
private var moonDial = TextureRegionPack(ModMgr.getPath("basegame", "fonts/watch_17pxmoondial.tga"), 17, 17)
|
||||
private var moonDialCount = moonDial.horizontalCount
|
||||
|
||||
private val drawCol = Color(1f,1f,1f,UIQuickslotBar.DISPLAY_OPACITY)
|
||||
private val drawCol = Color(1f, 1f, 1f, UIQuickslotBar.DISPLAY_OPACITY)
|
||||
private val lcdLitColELoff = Color(0xc0c0c0ff.toInt()) mul drawCol
|
||||
private val lcdLitColELon = Color(0x404040ff) mul drawCol
|
||||
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
package net.torvald.terrarum.modulebasegame.ui
|
||||
|
||||
import com.badlogic.gdx.graphics.Camera
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.LoadScreen
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.modulebasegame.BuildingMaker
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
import net.torvald.terrarum.ui.UIItemTextButtonList
|
||||
|
||||
/*class UITitleRemoConRoot : UICanvas() {
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -58,7 +58,7 @@ class uiQuickslotPie : UICanvas() {
|
||||
}
|
||||
}
|
||||
|
||||
private val drawColor = Color(1f,1f,1f,1f)
|
||||
private val drawColor = Color(1f, 1f, 1f, 1f)
|
||||
|
||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||
// draw radial thingies
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.GL20
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import net.torvald.colourutil.CIELuvUtil
|
||||
import net.torvald.gdx.graphics.Cvec
|
||||
import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.GdxColorMap
|
||||
import net.torvald.terrarum.ModMgr
|
||||
@@ -51,7 +52,7 @@ internal object WeatherMixer : RNGConsumer {
|
||||
|
||||
lateinit var mixedWeather: BaseModularWeather
|
||||
|
||||
val globalLightNow = Color(0)
|
||||
val globalLightNow = Cvec(0)
|
||||
|
||||
// Weather indices
|
||||
const val WEATHER_GENERIC = "generic"
|
||||
@@ -178,10 +179,10 @@ internal object WeatherMixer : RNGConsumer {
|
||||
/**
|
||||
* Get a GL of specific time
|
||||
*/
|
||||
fun getGlobalLightOfTime(timeInSec: Int): Color =
|
||||
fun getGlobalLightOfTime(timeInSec: Int): Cvec =
|
||||
getGradientColour(currentWeather.skyboxGradColourMap, 2, timeInSec)
|
||||
|
||||
fun getGradientColour(colorMap: GdxColorMap, row: Int, timeInSec: Int): Color {
|
||||
fun getGradientColour(colorMap: GdxColorMap, row: Int, timeInSec: Int): Cvec {
|
||||
val dataPointDistance = WorldTime.DAY_LENGTH / colorMap.width
|
||||
|
||||
val phaseThis: Int = timeInSec / dataPointDistance // x-coord in gradmap
|
||||
@@ -203,7 +204,7 @@ internal object WeatherMixer : RNGConsumer {
|
||||
" | ${colourThis.toStringRGB()} -[${scale.times(100).toInt()}%]-> ${colourNext.toStringRGB()}" +
|
||||
" | * `$r`$g`$b`")*/
|
||||
|
||||
return newCol
|
||||
return Cvec(newCol)
|
||||
}
|
||||
|
||||
fun getWeatherList(classification: String) = weatherList[classification]!!
|
||||
|
||||
@@ -4,10 +4,10 @@ import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.graphics.GL30
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera
|
||||
import com.badlogic.gdx.graphics.Pixmap
|
||||
import com.badlogic.gdx.graphics.PixmapIO2
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||
import com.badlogic.gdx.utils.ScreenUtils
|
||||
import net.torvald.gdx.graphics.PixmapIO2
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.modulebasegame.gameworld.GameWorldExtension
|
||||
import net.torvald.terrarum.modulebasegame.weather.WeatherMixer
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
package net.torvald.terrarum.tests
|
||||
|
||||
import net.torvald.terrarum.utils.JsonFetcher
|
||||
import net.torvald.terrarum.utils.JsonWriter
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
package net.torvald.terrarum.tests
|
||||
|
||||
import net.torvald.terrarum.utils.PasswordBase32
|
||||
import java.nio.charset.Charset
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
package net.torvald.terrarum.tests
|
||||
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64GrowableOutputStream
|
||||
import net.torvald.terrarum.serialise.WriteLayerDataZip
|
||||
import net.torvald.terrarum.serialise.toLittle
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
package net.torvald.terrarum.tests
|
||||
|
||||
import net.torvald.util.CircularArray
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
package net.torvald.terrarum.tests
|
||||
|
||||
import kotlin.system.measureNanoTime
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
package net.torvald.terrarum.tests
|
||||
|
||||
import net.torvald.terrarum.utils.JsonWriter
|
||||
import org.dyn4j.geometry.Vector2
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
package net.torvald.terrarum.tests
|
||||
|
||||
import com.badlogic.gdx.*
|
||||
import com.badlogic.gdx.Input.Keys.*
|
||||
|
||||
@@ -15,22 +15,16 @@ import com.badlogic.gdx.graphics.glutils.ShaderProgram
|
||||
import com.sudoplay.joise.Joise
|
||||
import com.sudoplay.joise.module.ModuleBasisFunction
|
||||
import com.sudoplay.joise.module.ModuleFractal
|
||||
import com.sudoplay.joise.module.ModuleScaleDomain
|
||||
import com.sudoplay.joise.module.ModuleScaleOffset
|
||||
import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.AppLoader
|
||||
import net.torvald.terrarum.AppLoader.printdbg
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.concurrent.BlockingThreadPool
|
||||
import net.torvald.terrarum.concurrent.RunnableFun
|
||||
import net.torvald.terrarum.concurrent.ParallelUtils.sliceEvenly
|
||||
import net.torvald.terrarum.concurrent.ThreadParallel
|
||||
import net.torvald.terrarum.inUse
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.roundInt
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.system.measureNanoTime
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2018-12-14.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
package net.torvald.terrarum.tests
|
||||
|
||||
import com.badlogic.gdx.Game
|
||||
import com.badlogic.gdx.Gdx
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
package net.torvald.terrarum.tests
|
||||
|
||||
import com.badlogic.gdx.Game
|
||||
import com.badlogic.gdx.Gdx
|
||||
|
||||
@@ -80,7 +80,7 @@ class UITestPad1 : ScreenAdapter() {
|
||||
|
||||
}
|
||||
|
||||
val bgCol = Color(.62f,.79f,1f,1f)
|
||||
val bgCol = Color(.62f, .79f, 1f, 1f)
|
||||
|
||||
var _dct = 0f
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ class UIHandler(//var UI: UICanvas,
|
||||
}
|
||||
var scale = 1f
|
||||
|
||||
val opacityColour = Color(1f,1f,1f,opacity)
|
||||
val opacityColour = Color(1f, 1f, 1f, opacity)
|
||||
|
||||
var openCloseCounter = 0f
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ class UINSMenu(
|
||||
) : UICanvas() {
|
||||
|
||||
companion object {
|
||||
val DEFAULT_TITLEBACKCOL = Color(0f,0f,0f,.77f)
|
||||
val DEFAULT_TITLEBACKCOL = Color(0f, 0f, 0f, .77f)
|
||||
val DEFAULT_TITLETEXTCOL = Color.WHITE
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ class UINSMenu(
|
||||
uiWidth, listHeight,
|
||||
textAreaWidth = listWidth,
|
||||
alignment = UIItemTextButton.Companion.Alignment.LEFT,
|
||||
inactiveCol = Color(.94f,.94f,.94f,1f),
|
||||
inactiveCol = Color(.94f, .94f, .94f, 1f),
|
||||
itemHitboxSize = LINE_HEIGHT
|
||||
|
||||
)
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.graphics.*
|
||||
import com.badlogic.gdx.math.Matrix4
|
||||
import com.jme3.math.FastMath
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.AppLoader.printdbg
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
@@ -55,7 +56,7 @@ internal object BlocksDrawer {
|
||||
//val tileItemWall = Image(TILE_SIZE * 16, TILE_SIZE * GameWorld.TILES_SUPPORTED / 16) // 4 MB
|
||||
|
||||
|
||||
val wallOverlayColour = Color(5f/9f,5f/9f,5f/9f,1f)
|
||||
val wallOverlayColour = Color(5f / 9f, 5f / 9f, 5f / 9f, 1f)
|
||||
|
||||
const val BREAKAGE_STEPS = 10
|
||||
const val TILES_PER_BLOCK = PairedMapLayer.RANGE
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*package net.torvald.terrarum.worlddrawer
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import Color
|
||||
import com.badlogic.gdx.graphics.Pixmap
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
|
||||
@@ -1,18 +1,6 @@
|
||||
package net.torvald.terrarum.worlddrawer
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
import net.torvald.terrarum.blockproperties.BlockCodex
|
||||
import net.torvald.terrarum.fillRect
|
||||
import net.torvald.terrarum.floorInt
|
||||
import net.torvald.terrarum.gameactors.ActorWBMovable
|
||||
import net.torvald.terrarum.gameactors.Luminous
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.modulebasegame.IngameRenderer
|
||||
import java.util.*
|
||||
|
||||
|
||||
/**
|
||||
* Warning: you are not going to store float value to the lightmap -- see RGB_HDR_LUT (beziér)
|
||||
@@ -20,755 +8,3 @@ import java.util.*
|
||||
* Created by minjaesong on 2016-01-25.
|
||||
*/
|
||||
|
||||
//typealias RGB10 = Int
|
||||
|
||||
// NOTE: no Float16 on this thing: 67 kB of memory footage is totally acceptable
|
||||
|
||||
object LightmapRendererOld {
|
||||
lateinit var world: GameWorld
|
||||
|
||||
|
||||
// TODO if (VBO works on BlocksDrawer) THEN overscan of 256, utilise same technique in here
|
||||
|
||||
val overscan_open: Int = 32
|
||||
val overscan_opaque: Int = 8
|
||||
|
||||
init {
|
||||
println("[LightmapRenderer] Overscan open: $overscan_open; opaque: $overscan_opaque")
|
||||
}
|
||||
|
||||
// TODO resize(int, int) -aware
|
||||
|
||||
val LIGHTMAP_WIDTH = (Terrarum.ingame?.ZOOM_MINIMUM ?: 1f).inv().times(Terrarum.WIDTH)
|
||||
.div(CreateTileAtlas.TILE_SIZE).ceil() + overscan_open * 2 + 3
|
||||
val LIGHTMAP_HEIGHT = (Terrarum.ingame?.ZOOM_MINIMUM ?: 1f).inv().times(Terrarum.HEIGHT)
|
||||
.div(CreateTileAtlas.TILE_SIZE).ceil() + overscan_open * 2 + 3
|
||||
|
||||
/**
|
||||
* Float value, 1.0 for 1023
|
||||
*/
|
||||
// TODO utilise alpha channel to determine brightness of "glow" sprites (so that alpha channel works like UV light)
|
||||
private val lightmap: Array<Array<Color>> = Array(LIGHTMAP_HEIGHT) { Array(LIGHTMAP_WIDTH, { Color(0f,0f,0f,0f) }) } // TODO framebuffer?
|
||||
private val lanternMap = ArrayList<Lantern>((Terrarum.ingame?.ACTORCONTAINER_INITIAL_SIZE ?: 2) * 4)
|
||||
|
||||
private val AIR = Block.AIR
|
||||
|
||||
private const val TILE_SIZE = CreateTileAtlas.TILE_SIZE
|
||||
private val DRAW_TILE_SIZE: Float = CreateTileAtlas.TILE_SIZE / IngameRenderer.lightmapDownsample
|
||||
|
||||
// color model related constants
|
||||
const val MUL = 1024 // modify this to 1024 to implement 30-bit RGB
|
||||
const val CHANNEL_MAX_DECIMAL = 1f
|
||||
const val MUL_2 = MUL * MUL
|
||||
const val CHANNEL_MAX = MUL - 1
|
||||
const val CHANNEL_MAX_FLOAT = CHANNEL_MAX.toFloat()
|
||||
const val COLOUR_RANGE_SIZE = MUL * MUL_2
|
||||
const val MUL_FLOAT = MUL / 256f
|
||||
const val DIV_FLOAT = 256f / MUL
|
||||
|
||||
internal var for_x_start: Int = 0
|
||||
internal var for_y_start: Int = 0
|
||||
internal var for_x_end: Int = 0
|
||||
internal var for_y_end: Int = 0
|
||||
|
||||
|
||||
//inline fun getLightRawPos(x: Int, y: Int) = lightmap[y][x]
|
||||
|
||||
|
||||
/**
|
||||
* Conventional level (multiplied by four)
|
||||
*/
|
||||
fun getLight(x: Int, y: Int): Color? {
|
||||
val col = getLightInternal(x, y)
|
||||
if (col == null) {
|
||||
return null
|
||||
}
|
||||
else {
|
||||
return Color(col.r * MUL_FLOAT, col.g * MUL_FLOAT, col.b * MUL_FLOAT, col.a * MUL_FLOAT)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getLightInternal(x: Int, y: Int): Color? {
|
||||
if (y - for_y_start + overscan_open in 0..lightmap.lastIndex &&
|
||||
x - for_x_start + overscan_open in 0..lightmap[0].lastIndex) {
|
||||
|
||||
return lightmap[y - for_y_start + overscan_open][x - for_x_start + overscan_open]
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun setLight(x: Int, y: Int, colour: Color) {
|
||||
if (y - for_y_start + overscan_open in 0..lightmap.lastIndex &&
|
||||
x - for_x_start + overscan_open in 0..lightmap[0].lastIndex) {
|
||||
|
||||
lightmap[y - for_y_start + overscan_open][x - for_x_start + overscan_open] = colour
|
||||
}
|
||||
}
|
||||
|
||||
fun fireRecalculateEventtt() {
|
||||
|
||||
}
|
||||
|
||||
fun fireRecalculateEvent() {
|
||||
for_x_start = WorldCamera.x / TILE_SIZE - 1 // fix for premature lightmap rendering
|
||||
for_y_start = WorldCamera.y / TILE_SIZE - 1 // on topmost/leftmost side
|
||||
|
||||
for_x_end = for_x_start + WorldCamera.width / TILE_SIZE + 3
|
||||
for_y_end = for_y_start + WorldCamera.height / TILE_SIZE + 2 // same fix as above
|
||||
|
||||
/**
|
||||
* * true: overscanning is limited to 8 tiles in width (overscan_opaque)
|
||||
* * false: overscanning will fully applied to 32 tiles in width (overscan_open)
|
||||
*/
|
||||
/*val rect_width = for_x_end - for_x_start
|
||||
val rect_height_rem_hbars = for_y_end - for_y_start - 2
|
||||
val noop_mask = BitSet(2 * (rect_width) +
|
||||
2 * (rect_height_rem_hbars))
|
||||
val rect_size = noop_mask.size()
|
||||
|
||||
// get No-op mask
|
||||
fun edgeToMaskNum(i: Int): Pair<Int, Int> {
|
||||
if (i > rect_size) throw IllegalArgumentException()
|
||||
|
||||
if (i < rect_width) // top edge horizontal
|
||||
return Pair(for_x_start + i, for_y_start)
|
||||
else if (i >= rect_size - rect_width) // bottom edge horizontal
|
||||
return Pair(
|
||||
for_x_start + i.minus(rect_size - rect_width),
|
||||
for_y_end
|
||||
)
|
||||
else { // vertical edges without horizontal edge pair
|
||||
return Pair(
|
||||
if ((rect_width.even() && i.even()) || (rect_width.odd() && i.odd()))
|
||||
// if the index is on the left side of the box
|
||||
for_x_start
|
||||
else for_x_end,
|
||||
(i - rect_width).div(2) + for_y_start + 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun posToMaskNum(x: Int, y: Int): Int? {
|
||||
if (x in for_x_start + 1..for_x_end - 1 && y in for_y_start + 1..for_y_end - 1) {
|
||||
return null // inside of this imaginary box
|
||||
}
|
||||
else if (y <= for_y_start) { // upper edge
|
||||
if (x < for_x_start) return 0
|
||||
else if (x > for_x_end) return rect_width - 1
|
||||
else return x - for_x_start
|
||||
}
|
||||
else if (y >= for_y_end) { // lower edge
|
||||
if (x < for_x_start) return rect_size - rect_width
|
||||
else if (x > for_x_end) return rect_size - 1
|
||||
else return x - for_x_start + (rect_size - rect_width)
|
||||
}
|
||||
else { // between two edges
|
||||
if (x < for_x_start) return (y - for_y_start - 1) * 2 + rect_width
|
||||
else if (x > for_x_end) return (y - for_y_start - 1) * 2 + rect_width + 1
|
||||
else return null
|
||||
}
|
||||
}
|
||||
|
||||
fun isNoop(x: Int, y: Int): Boolean =
|
||||
if (posToMaskNum(x, y) == null)
|
||||
false
|
||||
else if (!(x in for_x_start - overscan_opaque..for_x_end + overscan_opaque &&
|
||||
x in for_y_start - overscan_opaque..for_y_end + overscan_opaque))
|
||||
// point is within the range of overscan_open but not overscan_opaque
|
||||
noop_mask.get(posToMaskNum(x, y)!!)
|
||||
else // point within the overscan_opaque must be rendered, so no no-op
|
||||
false
|
||||
|
||||
// build noop map
|
||||
for (i in 0..rect_size) {
|
||||
val point = edgeToMaskNum(i)
|
||||
val tile = world.getTileFromTerrain(point.first, point.second) ?: Block.NULL
|
||||
val isSolid = BlockCodex[tile].isSolid
|
||||
|
||||
noop_mask.set(i, isSolid)
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Updating order:
|
||||
* +--------+ +--+-----+ +-----+--+ +--------+ -
|
||||
* |↘ | | | 3| |3 | | | ↙| ↕︎ overscan_open / overscan_opaque
|
||||
* | +-----+ | | 2 | | 2 | | +-----+ | - depending on the noop_mask
|
||||
* | |1 | → | |1 | → | 1| | → | 1| |
|
||||
* | | 2 | | +-----+ +-----+ | | 2 | |
|
||||
* | | 3| |↗ | | ↖| |3 | |
|
||||
* +--+-----+ +--------+ +--------+ +-----+--+
|
||||
* round: 1 2 3 4
|
||||
* for all lightmap[y][x]
|
||||
*/
|
||||
|
||||
purgeLightmap()
|
||||
buildLanternmap()
|
||||
|
||||
// O(36n) == O(n) where n is a size of the map.
|
||||
// Because of inevitable overlaps on the area, it only works with ADDITIVE blend (aka maxblend)
|
||||
|
||||
|
||||
// Round 1
|
||||
for (y in for_y_start - overscan_open..for_y_end) {
|
||||
for (x in for_x_start - overscan_open..for_x_end) {
|
||||
setLight(x, y, calculate(x, y, 1))
|
||||
}
|
||||
}
|
||||
|
||||
// Round 2
|
||||
for (y in for_y_end + overscan_open downTo for_y_start) {
|
||||
for (x in for_x_start - overscan_open..for_x_end) {
|
||||
setLight(x, y, calculate(x, y, 2))
|
||||
}
|
||||
}
|
||||
|
||||
// Round 3
|
||||
for (y in for_y_end + overscan_open downTo for_y_start) {
|
||||
for (x in for_x_end + overscan_open downTo for_x_start) {
|
||||
setLight(x, y, calculate(x, y, 3))
|
||||
}
|
||||
}
|
||||
|
||||
// Round 4
|
||||
for (y in for_y_start - overscan_open..for_y_end) {
|
||||
for (x in for_x_end + overscan_open downTo for_x_start) {
|
||||
setLight(x, y, calculate(x, y, 4))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildLanternmap() {
|
||||
lanternMap.clear()
|
||||
Terrarum.ingame?.let {
|
||||
it.actorContainerActive.forEach { it ->
|
||||
if (it is Luminous && it is ActorWBMovable) {
|
||||
// put lanterns to the area the luminantBox is occupying
|
||||
for (lightBox in it.lightBoxList) {
|
||||
val lightBoxX = it.hitbox.startX + lightBox.startX
|
||||
val lightBoxY = it.hitbox.startY + lightBox.startY
|
||||
val lightBoxW = lightBox.width
|
||||
val lightBoxH = lightBox.height
|
||||
for (y in lightBoxY.div(TILE_SIZE).floorInt()
|
||||
..lightBoxY.plus(lightBoxH).div(TILE_SIZE).floorInt()) {
|
||||
for (x in lightBoxX.div(TILE_SIZE).floorInt()
|
||||
..lightBoxX.plus(lightBoxW).div(TILE_SIZE).floorInt()) {
|
||||
|
||||
val normalisedColor = it.color.cpy().mul(DIV_FLOAT)
|
||||
|
||||
lanternMap.add(Lantern(x, y, normalisedColor))
|
||||
// Q&D fix for Roundworld anomaly
|
||||
lanternMap.add(Lantern(x + world.width, y, normalisedColor))
|
||||
lanternMap.add(Lantern(x - world.width, y, normalisedColor))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private var ambientAccumulator = Color(0f,0f,0f,0f)
|
||||
private var lightLevelThis = Color(0f,0f,0f,0f)
|
||||
private var thisTerrain = 0
|
||||
private var thisWall = 0
|
||||
private var thisTileLuminosity = Color(0f,0f,0f,0f)
|
||||
private var thisTileOpacity = Color(0f,0f,0f,0f)
|
||||
private var sunLight = Color(0f,0f,0f,0f)
|
||||
|
||||
|
||||
private fun calculate(x: Int, y: Int, pass: Int): Color = calculate(x, y, pass, false)
|
||||
|
||||
private fun calculate(x: Int, y: Int, pass: Int, doNotCalculateAmbient: Boolean): Color {
|
||||
// O(9n) == O(n) where n is a size of the map
|
||||
// TODO devise multithreading on this
|
||||
|
||||
ambientAccumulator = Color(0f,0f,0f,0f)
|
||||
|
||||
lightLevelThis = Color(0f,0f,0f,0f)
|
||||
thisTerrain = world.getTileFromTerrain(x, y) ?: Block.STONE
|
||||
thisWall = world.getTileFromWall(x, y) ?: Block.STONE
|
||||
thisTileLuminosity = BlockCodex[thisTerrain].luminosity // already been div by four
|
||||
thisTileOpacity = BlockCodex[thisTerrain].opacity // already been div by four
|
||||
sunLight = world.globalLight.cpy().mul(DIV_FLOAT)
|
||||
|
||||
|
||||
// MIX TILE
|
||||
// open air
|
||||
if (thisTerrain == AIR && thisWall == AIR) {
|
||||
lightLevelThis = sunLight
|
||||
}
|
||||
// luminous tile on top of air
|
||||
else if (thisWall == AIR && thisTileLuminosity.nonZero()) {
|
||||
lightLevelThis = sunLight maxBlend thisTileLuminosity // maximise to not exceed 1.0 with normal (<= 1.0) light
|
||||
}
|
||||
// opaque wall and luminous tile
|
||||
else if (thisWall != AIR && thisTileLuminosity.nonZero()) {
|
||||
lightLevelThis = thisTileLuminosity
|
||||
}
|
||||
// END MIX TILE
|
||||
|
||||
for (i in 0 until lanternMap.size) {
|
||||
val lmap = lanternMap[i]
|
||||
if (lmap.posX == x && lmap.posY == y)
|
||||
lightLevelThis = lightLevelThis maxBlend lmap.color // maximise to not exceed 1.0 with normal (<= 1.0) light
|
||||
}
|
||||
|
||||
if (!doNotCalculateAmbient) {
|
||||
// calculate ambient
|
||||
/* + * +
|
||||
* * @ *
|
||||
* + * +
|
||||
* sample ambient for eight points and apply attenuation for those
|
||||
* maxblend eight values and use it
|
||||
*/
|
||||
/* + */ambientAccumulator = ambientAccumulator maxBlend darkenColoured(getLightInternal(x - 1, y - 1) ?: Color(0f,0f,0f,0f), scaleSqrt2(thisTileOpacity))
|
||||
/* + */ambientAccumulator = ambientAccumulator maxBlend darkenColoured(getLightInternal(x + 1, y - 1) ?: Color(0f,0f,0f,0f), scaleSqrt2(thisTileOpacity))
|
||||
/* + */ambientAccumulator = ambientAccumulator maxBlend darkenColoured(getLightInternal(x - 1, y + 1) ?: Color(0f,0f,0f,0f), scaleSqrt2(thisTileOpacity))
|
||||
/* + */ambientAccumulator = ambientAccumulator maxBlend darkenColoured(getLightInternal(x + 1, y + 1) ?: Color(0f,0f,0f,0f), scaleSqrt2(thisTileOpacity))
|
||||
|
||||
/* * */ambientAccumulator = ambientAccumulator maxBlend darkenColoured(getLightInternal(x , y - 1) ?: Color(0f,0f,0f,0f), thisTileOpacity)
|
||||
/* * */ambientAccumulator = ambientAccumulator maxBlend darkenColoured(getLightInternal(x , y + 1) ?: Color(0f,0f,0f,0f), thisTileOpacity)
|
||||
/* * */ambientAccumulator = ambientAccumulator maxBlend darkenColoured(getLightInternal(x - 1, y ) ?: Color(0f,0f,0f,0f), thisTileOpacity)
|
||||
/* * */ambientAccumulator = ambientAccumulator maxBlend darkenColoured(getLightInternal(x + 1, y ) ?: Color(0f,0f,0f,0f), thisTileOpacity)
|
||||
|
||||
val ret = lightLevelThis maxBlend ambientAccumulator
|
||||
|
||||
|
||||
|
||||
return ret
|
||||
}
|
||||
else {
|
||||
val ret = lightLevelThis
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun getLightForOpaque(x: Int, y: Int): Color? { // ...so that they wouldn't appear too dark
|
||||
val l = getLightInternal(x, y)
|
||||
if (l == null) return null
|
||||
|
||||
if (BlockCodex[world.getTileFromTerrain(x, y)].isSolid) {
|
||||
return Color(
|
||||
(l.r * 1.25f),//.clampOne(),
|
||||
(l.g * 1.25f),//.clampOne(),
|
||||
(l.b * 1.25f),//.clampOne()
|
||||
(l.a * 1.25f)
|
||||
)
|
||||
}
|
||||
else {
|
||||
return l
|
||||
}
|
||||
}
|
||||
|
||||
const val DRAW_FOR_RGB = 0xFFF0
|
||||
const val DRAW_FOR_ALPHA = 0x000F
|
||||
|
||||
fun draw(batch: SpriteBatch, drawMode: Int) {
|
||||
val this_x_start = for_x_start// + overscan_open
|
||||
val this_x_end = for_x_end// + overscan_open
|
||||
val this_y_start = for_y_start// + overscan_open
|
||||
val this_y_end = for_y_end// + overscan_open
|
||||
|
||||
|
||||
val originalColour = batch.color.cpy()
|
||||
|
||||
// draw to the
|
||||
try {
|
||||
// loop for "scanlines"
|
||||
for (y in this_y_start..this_y_end) {
|
||||
// loop x
|
||||
var x = this_x_start
|
||||
while (x < this_x_end) {
|
||||
try {
|
||||
val thisLightLevel = getLightForOpaque(x, y)
|
||||
|
||||
// coalesce identical intensity blocks to one
|
||||
var sameLevelCounter = 1
|
||||
while (getLightForOpaque(x + sameLevelCounter, y) == thisLightLevel) {
|
||||
sameLevelCounter += 1
|
||||
|
||||
if (x + sameLevelCounter >= this_x_end) break
|
||||
}
|
||||
|
||||
|
||||
if (drawMode == DRAW_FOR_RGB) {
|
||||
batch.color = (getLightForOpaque(x, y) ?: Color(0f,0f,0f,0f)).normaliseToColourHDR()
|
||||
}
|
||||
else if (drawMode == DRAW_FOR_ALPHA) {
|
||||
batch.color = (getLightForOpaque(x, y) ?: Color(0f,0f,0f,0f)).normaliseToAlphaHDR()
|
||||
}
|
||||
|
||||
|
||||
batch.fillRect(
|
||||
x * DRAW_TILE_SIZE,
|
||||
y * DRAW_TILE_SIZE,
|
||||
(DRAW_TILE_SIZE * sameLevelCounter).ceil().toFloat(),// + 1f,
|
||||
DRAW_TILE_SIZE.ceil().toFloat()// + 1f
|
||||
)
|
||||
|
||||
x += sameLevelCounter - 1
|
||||
}
|
||||
catch (e: ArrayIndexOutOfBoundsException) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
|
||||
x++
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e: ArrayIndexOutOfBoundsException) {
|
||||
}
|
||||
|
||||
|
||||
batch.color = originalColour
|
||||
|
||||
}
|
||||
|
||||
val lightScalingMagic = 8f
|
||||
|
||||
/**
|
||||
* Subtract each channel's RGB value.
|
||||
*
|
||||
* @param data Raw channel value (0-255) per channel
|
||||
* @param darken (0-255) per channel
|
||||
* @return darkened data (0-255) per channel
|
||||
*/
|
||||
fun darkenColoured(data: Color, darken: Color): Color {
|
||||
// use equation with magic number 8.0
|
||||
// should draw somewhat exponential curve when you plot the propagation of light in-game
|
||||
|
||||
return Color(
|
||||
data.r * (1f - darken.r * lightScalingMagic),//.clampZero(),
|
||||
data.g * (1f - darken.g * lightScalingMagic),//.clampZero(),
|
||||
data.b * (1f - darken.b * lightScalingMagic),//.clampZero(),
|
||||
data.a * (1f - darken.a * lightScalingMagic))
|
||||
}
|
||||
|
||||
private fun scaleSqrt2(data: Color): Color {
|
||||
return Color(
|
||||
data.r * 1.41421356f,
|
||||
data.g * 1.41421356f,
|
||||
data.b * 1.41421356f,
|
||||
data.a * 1.41421356f)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add each channel's RGB value.
|
||||
*
|
||||
* @param data Raw channel value (0-255) per channel
|
||||
* @param brighten (0-255) per channel
|
||||
* @return brightened data (0-255) per channel
|
||||
*/
|
||||
fun brightenColoured(data: Color, brighten: Color): Color {
|
||||
return Color(
|
||||
data.r * (1f + brighten.r * lightScalingMagic),
|
||||
data.g * (1f + brighten.g * lightScalingMagic),
|
||||
data.b * (1f + brighten.b * lightScalingMagic),
|
||||
data.a * (1f + brighten.a * lightScalingMagic)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Darken each channel by 'darken' argument
|
||||
*
|
||||
* @param data Raw channel value (0-255) per channel
|
||||
* @param darken (0-255)
|
||||
* @return
|
||||
*/
|
||||
fun darkenUniformInt(data: Color, darken: Float): Color {
|
||||
if (darken < 0 || darken > CHANNEL_MAX)
|
||||
throw IllegalArgumentException("darken: out of range ($darken)")
|
||||
|
||||
val darkenColoured = Color(darken, darken, darken, darken)
|
||||
return darkenColoured(data, darkenColoured)
|
||||
}
|
||||
|
||||
/**
|
||||
* Darken or brighten colour by 'brighten' argument
|
||||
*
|
||||
* @param data Raw channel value (0-255) per channel
|
||||
* @param brighten (-1.0 - 1.0) negative means darkening
|
||||
* @return processed colour
|
||||
*/
|
||||
fun alterBrightnessUniform(data: Color, brighten: Float): Color {
|
||||
return Color(
|
||||
data.r + brighten,
|
||||
data.g + brighten,
|
||||
data.b + brighten,
|
||||
data.a + brighten
|
||||
)
|
||||
}
|
||||
|
||||
/** Get each channel from two RGB values, return new RGB that has max value of each channel
|
||||
* @param rgb
|
||||
* @param rgb2
|
||||
* @return
|
||||
*/
|
||||
infix fun Color.maxBlend(other: Color): Color {
|
||||
return Color(
|
||||
if (this.r > other.r) this.r else other.r,
|
||||
if (this.g > other.g) this.g else other.g,
|
||||
if (this.b > other.b) this.b else other.b,
|
||||
if (this.a > other.a) this.a else other.a
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/*inline fun RGB10.rawR() = this.ushr(20) and 1023
|
||||
inline fun RGB10.rawG() = this.ushr(10) and 1023
|
||||
inline fun RGB10.rawB() = this and 1023
|
||||
|
||||
/** 0.0 - 1.0 for 0-1023 (0.0 - 0.25 for 0-255) */
|
||||
inline fun RGB10.r(): Float = this.rawR() / CHANNEL_MAX_FLOAT
|
||||
inline fun RGB10.g(): Float = this.rawG() / CHANNEL_MAX_FLOAT
|
||||
inline fun RGB10.b(): Float = this.rawB() / CHANNEL_MAX_FLOAT*/
|
||||
|
||||
|
||||
/*inline fun constructRGBFromInt(r: Int, g: Int, b: Int): RGB10 {
|
||||
//if (r !in 0..CHANNEL_MAX) throw IllegalArgumentException("Red: out of range ($r)")
|
||||
//if (g !in 0..CHANNEL_MAX) throw IllegalArgumentException("Green: out of range ($g)")
|
||||
//if (b !in 0..CHANNEL_MAX) throw IllegalArgumentException("Blue: out of range ($b)")
|
||||
|
||||
return r.shl(20) or
|
||||
g.shl(10) or
|
||||
b
|
||||
}*/
|
||||
|
||||
/*inline fun constructRGBFromFloat(r: Float, g: Float, b: Float): RGB10 {
|
||||
//if (r < 0 || r > CHANNEL_MAX_DECIMAL) throw IllegalArgumentException("Red: out of range ($r)")
|
||||
//if (g < 0 || g > CHANNEL_MAX_DECIMAL) throw IllegalArgumentException("Green: out of range ($g)")
|
||||
//if (b < 0 || b > CHANNEL_MAX_DECIMAL) throw IllegalArgumentException("Blue: out of range ($b)")
|
||||
|
||||
return (r * CHANNEL_MAX).round().shl(20) or
|
||||
(g * CHANNEL_MAX).round().shl(10) or
|
||||
(b * CHANNEL_MAX).round()
|
||||
}*/
|
||||
|
||||
fun Int.clampZero() = if (this < 0) 0 else this
|
||||
fun Float.clampZero() = if (this < 0) 0f else this
|
||||
fun Int.clampChannel() = if (this < 0) 0 else if (this > CHANNEL_MAX) CHANNEL_MAX else this
|
||||
fun Float.clampOne() = if (this < 0) 0f else if (this > 1) 1f else this
|
||||
fun Float.clampChannel() = if (this > CHANNEL_MAX_DECIMAL) CHANNEL_MAX_DECIMAL else this
|
||||
|
||||
fun getHighestRGB(x: Int, y: Int): Float? {
|
||||
val value = getLightInternal(x, y)
|
||||
if (value == null)
|
||||
return null
|
||||
else
|
||||
return FastMath.max(value.r, value.g, value.b)
|
||||
}
|
||||
|
||||
fun getHighestRGBA(x: Int, y: Int): Float? {
|
||||
val value = getLightInternal(x, y)
|
||||
if (value == null)
|
||||
return null
|
||||
else
|
||||
return FastMath.max(value.r, value.g, value.b, value.a)
|
||||
}
|
||||
|
||||
private fun purgeLightmap() {
|
||||
for (y in 0..LIGHTMAP_HEIGHT - 1) {
|
||||
for (x in 0..LIGHTMAP_WIDTH - 1) {
|
||||
lightmap[y][x] = Color(0f,0f,0f,0f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
infix fun Float.powerOf(f: Float) = FastMath.pow(this, f)
|
||||
private fun Float.sqr() = this * this
|
||||
private fun Float.sqrt() = FastMath.sqrt(this)
|
||||
private fun Float.inv() = 1f / this
|
||||
fun Float.floor() = FastMath.floor(this)
|
||||
fun Double.floorInt() = Math.floor(this).toInt()
|
||||
fun Float.round(): Int = Math.round(this)
|
||||
fun Double.round(): Int = Math.round(this).toInt()
|
||||
fun Float.ceil() = FastMath.ceil(this)
|
||||
fun Int.even(): Boolean = this and 1 == 0
|
||||
fun Int.odd(): Boolean = this and 1 == 1
|
||||
|
||||
// TODO: float LUT lookup using linear interpolation
|
||||
|
||||
// input: 0..1 for int 0..1023
|
||||
fun hdr(intensity: Float): Float {
|
||||
val intervalStart = (intensity * MUL).floorInt()
|
||||
val intervalEnd = minOf(rgbHDRLookupTable.lastIndex, (intensity * MUL).floorInt() + 1)
|
||||
|
||||
if (intervalStart == intervalEnd) return rgbHDRLookupTable[intervalStart]
|
||||
|
||||
val intervalPos = (intensity * MUL) - (intensity * MUL).toInt()
|
||||
|
||||
return interpolateLinear(
|
||||
intervalPos,
|
||||
rgbHDRLookupTable[intervalStart],
|
||||
rgbHDRLookupTable[intervalEnd]
|
||||
)
|
||||
}
|
||||
|
||||
val rgbHDRLookupTable = floatArrayOf( // polynomial of 6.0 please refer to work_files/HDRcurveBezierLinIntp.kts
|
||||
0.0000f,0.0000f,0.0020f,0.0060f,0.0100f,0.0139f,0.0179f,0.0219f,0.0259f,0.0299f,0.0338f,0.0378f,0.0418f,0.0458f,0.0497f,0.0537f,
|
||||
0.0577f,0.0617f,0.0656f,0.0696f,0.0736f,0.0776f,0.0816f,0.0855f,0.0895f,0.0935f,0.0975f,0.1014f,0.1054f,0.1094f,0.1134f,0.1173f,
|
||||
0.1213f,0.1253f,0.1293f,0.1332f,0.1372f,0.1412f,0.1451f,0.1491f,0.1531f,0.1571f,0.1610f,0.1650f,0.1690f,0.1730f,0.1769f,0.1809f,
|
||||
0.1849f,0.1888f,0.1928f,0.1968f,0.2007f,0.2047f,0.2087f,0.2127f,0.2166f,0.2206f,0.2246f,0.2285f,0.2325f,0.2365f,0.2404f,0.2444f,
|
||||
0.2484f,0.2523f,0.2563f,0.2602f,0.2642f,0.2682f,0.2721f,0.2761f,0.2800f,0.2840f,0.2880f,0.2919f,0.2959f,0.2998f,0.3038f,0.3078f,
|
||||
0.3117f,0.3157f,0.3196f,0.3236f,0.3275f,0.3315f,0.3354f,0.3394f,0.3433f,0.3472f,0.3512f,0.3551f,0.3591f,0.3630f,0.3669f,0.3709f,
|
||||
0.3748f,0.3788f,0.3827f,0.3866f,0.3905f,0.3945f,0.3984f,0.4023f,0.4062f,0.4101f,0.4141f,0.4180f,0.4219f,0.4258f,0.4297f,0.4336f,
|
||||
0.4375f,0.4414f,0.4453f,0.4491f,0.4530f,0.4569f,0.4608f,0.4647f,0.4685f,0.4724f,0.4762f,0.4801f,0.4839f,0.4878f,0.4916f,0.4954f,
|
||||
0.4993f,0.5031f,0.5069f,0.5107f,0.5145f,0.5183f,0.5220f,0.5258f,0.5296f,0.5333f,0.5371f,0.5408f,0.5445f,0.5482f,0.5520f,0.5556f,
|
||||
0.5593f,0.5630f,0.5667f,0.5703f,0.5739f,0.5776f,0.5812f,0.5848f,0.5883f,0.5919f,0.5955f,0.5990f,0.6025f,0.6060f,0.6095f,0.6130f,
|
||||
0.6164f,0.6199f,0.6233f,0.6267f,0.6300f,0.6334f,0.6367f,0.6401f,0.6433f,0.6466f,0.6499f,0.6531f,0.6563f,0.6595f,0.6627f,0.6658f,
|
||||
0.6689f,0.6720f,0.6751f,0.6781f,0.6811f,0.6841f,0.6871f,0.6901f,0.6930f,0.6959f,0.6987f,0.7016f,0.7044f,0.7072f,0.7100f,0.7127f,
|
||||
0.7154f,0.7181f,0.7208f,0.7234f,0.7260f,0.7286f,0.7311f,0.7337f,0.7362f,0.7386f,0.7411f,0.7435f,0.7459f,0.7483f,0.7506f,0.7530f,
|
||||
0.7553f,0.7575f,0.7598f,0.7620f,0.7642f,0.7664f,0.7685f,0.7706f,0.7727f,0.7748f,0.7769f,0.7789f,0.7809f,0.7829f,0.7849f,0.7868f,
|
||||
0.7887f,0.7906f,0.7925f,0.7944f,0.7962f,0.7980f,0.7998f,0.8016f,0.8033f,0.8051f,0.8068f,0.8085f,0.8101f,0.8118f,0.8134f,0.8150f,
|
||||
0.8166f,0.8182f,0.8198f,0.8213f,0.8229f,0.8244f,0.8259f,0.8274f,0.8288f,0.8303f,0.8317f,0.8331f,0.8345f,0.8359f,0.8373f,0.8386f,
|
||||
0.8400f,0.8413f,0.8426f,0.8439f,0.8452f,0.8465f,0.8477f,0.8490f,0.8502f,0.8514f,0.8526f,0.8538f,0.8550f,0.8562f,0.8573f,0.8585f,
|
||||
0.8596f,0.8608f,0.8619f,0.8630f,0.8641f,0.8651f,0.8662f,0.8673f,0.8683f,0.8693f,0.8704f,0.8714f,0.8724f,0.8734f,0.8744f,0.8754f,
|
||||
0.8763f,0.8773f,0.8782f,0.8792f,0.8801f,0.8811f,0.8820f,0.8829f,0.8838f,0.8847f,0.8856f,0.8864f,0.8873f,0.8882f,0.8890f,0.8899f,
|
||||
0.8907f,0.8915f,0.8923f,0.8932f,0.8940f,0.8948f,0.8956f,0.8963f,0.8971f,0.8979f,0.8987f,0.8994f,0.9002f,0.9009f,0.9017f,0.9024f,
|
||||
0.9031f,0.9039f,0.9046f,0.9053f,0.9060f,0.9067f,0.9074f,0.9081f,0.9087f,0.9094f,0.9101f,0.9108f,0.9114f,0.9121f,0.9127f,0.9134f,
|
||||
0.9140f,0.9146f,0.9153f,0.9159f,0.9165f,0.9171f,0.9177f,0.9184f,0.9190f,0.9195f,0.9201f,0.9207f,0.9213f,0.9219f,0.9225f,0.9230f,
|
||||
0.9236f,0.9242f,0.9247f,0.9253f,0.9258f,0.9264f,0.9269f,0.9274f,0.9280f,0.9285f,0.9290f,0.9296f,0.9301f,0.9306f,0.9311f,0.9316f,
|
||||
0.9321f,0.9326f,0.9331f,0.9336f,0.9341f,0.9346f,0.9351f,0.9355f,0.9360f,0.9365f,0.9370f,0.9374f,0.9379f,0.9383f,0.9388f,0.9393f,
|
||||
0.9397f,0.9402f,0.9406f,0.9410f,0.9415f,0.9419f,0.9423f,0.9428f,0.9432f,0.9436f,0.9440f,0.9445f,0.9449f,0.9453f,0.9457f,0.9461f,
|
||||
0.9465f,0.9469f,0.9473f,0.9477f,0.9481f,0.9485f,0.9489f,0.9493f,0.9497f,0.9501f,0.9504f,0.9508f,0.9512f,0.9516f,0.9519f,0.9523f,
|
||||
0.9527f,0.9530f,0.9534f,0.9537f,0.9541f,0.9545f,0.9548f,0.9552f,0.9555f,0.9559f,0.9562f,0.9565f,0.9569f,0.9572f,0.9576f,0.9579f,
|
||||
0.9582f,0.9586f,0.9589f,0.9592f,0.9595f,0.9599f,0.9602f,0.9605f,0.9608f,0.9611f,0.9614f,0.9617f,0.9621f,0.9624f,0.9627f,0.9630f,
|
||||
0.9633f,0.9636f,0.9639f,0.9642f,0.9645f,0.9648f,0.9650f,0.9653f,0.9656f,0.9659f,0.9662f,0.9665f,0.9668f,0.9670f,0.9673f,0.9676f,
|
||||
0.9679f,0.9681f,0.9684f,0.9687f,0.9690f,0.9692f,0.9695f,0.9697f,0.9700f,0.9703f,0.9705f,0.9708f,0.9711f,0.9713f,0.9716f,0.9718f,
|
||||
0.9721f,0.9723f,0.9726f,0.9728f,0.9731f,0.9733f,0.9735f,0.9738f,0.9740f,0.9743f,0.9745f,0.9747f,0.9750f,0.9752f,0.9754f,0.9757f,
|
||||
0.9759f,0.9761f,0.9764f,0.9766f,0.9768f,0.9770f,0.9773f,0.9775f,0.9777f,0.9779f,0.9781f,0.9784f,0.9786f,0.9788f,0.9790f,0.9792f,
|
||||
0.9794f,0.9796f,0.9799f,0.9801f,0.9803f,0.9805f,0.9807f,0.9809f,0.9811f,0.9813f,0.9815f,0.9817f,0.9819f,0.9821f,0.9823f,0.9825f,
|
||||
0.9827f,0.9829f,0.9831f,0.9832f,0.9834f,0.9836f,0.9838f,0.9840f,0.9842f,0.9844f,0.9846f,0.9847f,0.9849f,0.9851f,0.9853f,0.9855f,
|
||||
0.9856f,0.9858f,0.9860f,0.9862f,0.9864f,0.9865f,0.9867f,0.9869f,0.9870f,0.9872f,0.9874f,0.9876f,0.9877f,0.9879f,0.9881f,0.9882f,
|
||||
0.9884f,0.9886f,0.9887f,0.9889f,0.9890f,0.9892f,0.9894f,0.9895f,0.9897f,0.9898f,0.9900f,0.9901f,0.9903f,0.9905f,0.9906f,0.9908f,
|
||||
0.9909f,0.9911f,0.9912f,0.9914f,0.9915f,0.9917f,0.9918f,0.9920f,0.9921f,0.9922f,0.9924f,0.9925f,0.9927f,0.9928f,0.9930f,0.9931f,
|
||||
0.9932f,0.9934f,0.9935f,0.9937f,0.9938f,0.9939f,0.9941f,0.9942f,0.9943f,0.9945f,0.9946f,0.9947f,0.9949f,0.9950f,0.9951f,0.9953f,
|
||||
0.9954f,0.9955f,0.9957f,0.9958f,0.9959f,0.9960f,0.9962f,0.9963f,0.9964f,0.9965f,0.9967f,0.9968f,0.9969f,0.9970f,0.9971f,0.9973f,
|
||||
0.9974f,0.9975f,0.9976f,0.9977f,0.9978f,0.9980f,0.9981f,0.9982f,0.9983f,0.9984f,0.9985f,0.9987f,0.9988f,0.9989f,0.9990f,0.9991f,
|
||||
0.9992f,0.9993f,0.9994f,0.9995f,0.9996f,0.9997f,0.9999f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f // isn't it beautiful?
|
||||
)
|
||||
/** To eliminated visible edge on the gradient when 255/1023 is exceeded */
|
||||
fun Color.normaliseToColourHDR() = Color(
|
||||
hdr(this.r),
|
||||
hdr(this.g),
|
||||
hdr(this.b),
|
||||
1f
|
||||
)
|
||||
|
||||
fun Color.normaliseToAlphaHDR() = Color(
|
||||
hdr(this.a),
|
||||
hdr(this.a),
|
||||
hdr(this.a),
|
||||
1f
|
||||
)
|
||||
|
||||
/**
|
||||
* color values are normalised -- 0.0 to 1.0 for 0..1023
|
||||
*/
|
||||
data class Lantern(val posX: Int, val posY: Int, val color: Color)
|
||||
|
||||
private fun Color.nonZero() = this.r != 0f || this.g != 0f || this.b != 0f || this.a != 0f
|
||||
|
||||
val histogram: Histogram
|
||||
get() {
|
||||
var reds = IntArray(MUL) // reds[intensity] ← counts
|
||||
var greens = IntArray(MUL) // do.
|
||||
var blues = IntArray(MUL) // do.
|
||||
val render_width = for_x_end - for_x_start
|
||||
val render_height = for_y_end - for_y_start
|
||||
// excluiding overscans; only reckon echo lights
|
||||
for (y in overscan_open..render_height + overscan_open + 1) {
|
||||
for (x in overscan_open..render_width + overscan_open + 1) {
|
||||
reds [minOf(CHANNEL_MAX, lightmap[y][x].r.times(MUL).floorInt())] += 1
|
||||
greens[minOf(CHANNEL_MAX, lightmap[y][x].g.times(MUL).floorInt())] += 1
|
||||
blues [minOf(CHANNEL_MAX, lightmap[y][x].b.times(MUL).floorInt())] += 1
|
||||
}
|
||||
}
|
||||
return Histogram(reds, greens, blues)
|
||||
}
|
||||
|
||||
class Histogram(val reds: IntArray, val greens: IntArray, val blues: IntArray) {
|
||||
|
||||
val RED = 0
|
||||
val GREEN = 1
|
||||
val BLUE = 2
|
||||
|
||||
val screen_tiles: Int = (for_x_end - for_x_start + 2) * (for_y_end - for_y_start + 2)
|
||||
|
||||
val brightest: Int
|
||||
get() {
|
||||
for (i in CHANNEL_MAX downTo 1) {
|
||||
if (reds[i] > 0 || greens[i] > 0 || blues[i] > 0)
|
||||
return i
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
val brightest8Bit: Int
|
||||
get() { val b = brightest
|
||||
return if (brightest > 255) 255 else b
|
||||
}
|
||||
|
||||
val dimmest: Int
|
||||
get() {
|
||||
for (i in 0..CHANNEL_MAX) {
|
||||
if (reds[i] > 0 || greens[i] > 0 || blues[i] > 0)
|
||||
return i
|
||||
}
|
||||
return CHANNEL_MAX
|
||||
}
|
||||
|
||||
val range: Int = CHANNEL_MAX
|
||||
|
||||
fun get(index: Int): IntArray {
|
||||
return when (index) {
|
||||
RED -> reds
|
||||
GREEN -> greens
|
||||
BLUE -> blues
|
||||
else -> throw IllegalArgumentException()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun interpolateLinear(scale: Float, startValue: Float, endValue: Float): Float {
|
||||
if (startValue == endValue) {
|
||||
return startValue
|
||||
}
|
||||
if (scale <= 0f) {
|
||||
return startValue
|
||||
}
|
||||
if (scale >= 1f) {
|
||||
return endValue
|
||||
}
|
||||
return (1f - scale) * startValue + scale * endValue
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.badlogic.gdx.graphics.Pixmap
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.gdx.graphics.Cvec
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.AppLoader.printdbg
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
@@ -81,9 +82,9 @@ object LightmapRenderer {
|
||||
* Float value, 1.0 for 1023
|
||||
*/
|
||||
// it utilises alpha channel to determine brightness of "glow" sprites (so that alpha channel works like UV light)
|
||||
//private val lightmap: Array<Array<Color>> = Array(LIGHTMAP_HEIGHT) { Array(LIGHTMAP_WIDTH, { Color(0f,0f,0f,0f) }) } // Can't use framebuffer/pixmap -- this is a fvec4 array, whereas they are ivec4.
|
||||
private var lightmap: Array<Color> = Array(LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT) { Color(0) } // Can't use framebuffer/pixmap -- this is a fvec4 array, whereas they are ivec4.
|
||||
private val lanternMap = HashMap<BlockAddress, Color>((Terrarum.ingame?.ACTORCONTAINER_INITIAL_SIZE ?: 2) * 4)
|
||||
//private val lightmap: Array<Array<Cvec>> = Array(LIGHTMAP_HEIGHT) { Array(LIGHTMAP_WIDTH, { Cvec(0f,0f,0f,0f) }) } // Can't use framebuffer/pixmap -- this is a fvec4 array, whereas they are ivec4.
|
||||
private var lightmap: Array<Cvec> = Array(LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT) { Cvec(0) } // Can't use framebuffer/pixmap -- this is a fvec4 array, whereas they are ivec4.
|
||||
private val lanternMap = HashMap<BlockAddress, Cvec>((Terrarum.ingame?.ACTORCONTAINER_INITIAL_SIZE ?: 2) * 4)
|
||||
|
||||
init {
|
||||
printdbg(this, "Overscan open: $overscan_open; opaque: $overscan_opaque")
|
||||
@@ -120,13 +121,13 @@ object LightmapRenderer {
|
||||
* @param x world tile coord
|
||||
* @param y world tile coord
|
||||
*/
|
||||
internal fun getLight(x: Int, y: Int): Color? {
|
||||
internal fun getLight(x: Int, y: Int): Cvec? {
|
||||
val col = getLightInternal(x, y)
|
||||
if (col == null) {
|
||||
return null
|
||||
}
|
||||
else {
|
||||
return Color(col.r * MUL_FLOAT, col.g * MUL_FLOAT, col.b * MUL_FLOAT, col.a * MUL_FLOAT)
|
||||
return Cvec(col.r * MUL_FLOAT, col.g * MUL_FLOAT, col.b * MUL_FLOAT, col.a * MUL_FLOAT)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +138,7 @@ object LightmapRenderer {
|
||||
* @param y world tile coord
|
||||
*/
|
||||
// TODO in regard of "colour math against integers", return Int?
|
||||
private fun getLightInternal(x: Int, y: Int): Color? {
|
||||
private fun getLightInternal(x: Int, y: Int): Cvec? {
|
||||
if (y - for_y_start + overscan_open in 0 until LIGHTMAP_HEIGHT &&
|
||||
x - for_x_start + overscan_open in 0 until LIGHTMAP_WIDTH) {
|
||||
|
||||
@@ -161,10 +162,10 @@ object LightmapRenderer {
|
||||
* @param list The lightmap
|
||||
* @param x World X coordinate
|
||||
* @param y World Y coordinate
|
||||
* @param colour Color to write
|
||||
* @param colour Cvec to write
|
||||
* @param applyFun A function ```foo(old_colour, given_colour)```
|
||||
*/
|
||||
private fun setLightOf(list: Array<Color>, x: Int, y: Int, colour: Color, applyFun: (Color, Color) -> Color = { _, c -> c }) {
|
||||
private fun setLightOf(list: Array<Cvec>, x: Int, y: Int, colour: Cvec, applyFun: (Cvec, Cvec) -> Cvec = { _, c -> c }) {
|
||||
if (y - for_y_start + overscan_open in 0 until LIGHTMAP_HEIGHT &&
|
||||
x - for_x_start + overscan_open in 0 until LIGHTMAP_WIDTH) {
|
||||
|
||||
@@ -347,13 +348,13 @@ object LightmapRenderer {
|
||||
for (x in lightBoxX.div(TILE_SIZE).floorInt()
|
||||
..lightBoxX.plus(lightBoxW).div(TILE_SIZE).floorInt()) {
|
||||
|
||||
val normalisedColor = it.color//.cpy().mul(DIV_FLOAT)
|
||||
val normalisedCvec = it.color//.cpy().mul(DIV_FLOAT)
|
||||
|
||||
lanternMap[LandUtil.getBlockAddr(world, x, y)] = normalisedColor
|
||||
//lanternMap[Point2i(x, y)] = normalisedColor
|
||||
lanternMap[LandUtil.getBlockAddr(world, x, y)] = normalisedCvec
|
||||
//lanternMap[Point2i(x, y)] = normalisedCvec
|
||||
// Q&D fix for Roundworld anomaly
|
||||
//lanternMap[Point2i(x + world.width, y)] = normalisedColor
|
||||
//lanternMap[Point2i(x - world.width, y)] = normalisedColor
|
||||
//lanternMap[Point2i(x + world.width, y)] = normalisedCvec
|
||||
//lanternMap[Point2i(x - world.width, y)] = normalisedCvec
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -393,16 +394,16 @@ object LightmapRenderer {
|
||||
}
|
||||
|
||||
|
||||
//private val ambientAccumulator = Color(0f,0f,0f,0f)
|
||||
private val lightLevelThis = Color(0)
|
||||
//private val ambientAccumulator = Cvec(0f,0f,0f,0f)
|
||||
private val lightLevelThis = Cvec(0)
|
||||
private var thisTerrain = 0
|
||||
private var thisFluid = GameWorld.FluidInfo(Fluid.NULL, 0f)
|
||||
private val fluidAmountToCol = Color(0)
|
||||
private val fluidAmountToCol = Cvec(0)
|
||||
private var thisWall = 0
|
||||
private val thisTileLuminosity = Color(0)
|
||||
private val thisTileOpacity = Color(0)
|
||||
private val thisTileOpacity2 = Color(0) // thisTileOpacity * sqrt(2)
|
||||
private val sunLight = Color(0)
|
||||
private val thisTileLuminosity = Cvec(0)
|
||||
private val thisTileOpacity = Cvec(0)
|
||||
private val thisTileOpacity2 = Cvec(0) // thisTileOpacity * sqrt(2)
|
||||
private val sunLight = Cvec(0)
|
||||
|
||||
/**
|
||||
* This function will alter following variables:
|
||||
@@ -425,9 +426,9 @@ object LightmapRenderer {
|
||||
fluidAmountToCol.set(thisFluid.amount, thisFluid.amount, thisFluid.amount, thisFluid.amount)
|
||||
|
||||
thisTileLuminosity.set(BlockCodex[thisTerrain].luminosity)
|
||||
thisTileLuminosity.maxAndAssign(BlockCodex[thisFluid.type].luminosity mul fluidAmountToCol) // already been div by four
|
||||
thisTileLuminosity.maxAndAssign(BlockCodex[thisFluid.type].luminosity.mul(fluidAmountToCol)) // already been div by four
|
||||
thisTileOpacity.set(BlockCodex[thisTerrain].opacity)
|
||||
thisTileOpacity.maxAndAssign(BlockCodex[thisFluid.type].opacity mul fluidAmountToCol) // already been div by four
|
||||
thisTileOpacity.maxAndAssign(BlockCodex[thisFluid.type].opacity.mul(fluidAmountToCol)) // already been div by four
|
||||
}
|
||||
else {
|
||||
thisTileLuminosity.set(BlockCodex[thisTerrain].luminosity)
|
||||
@@ -499,7 +500,7 @@ object LightmapRenderer {
|
||||
/**
|
||||
* Calculates the light simulation, using main lightmap as one of the input.
|
||||
*/
|
||||
private fun calculateAndAssign(lightmap: Array<Color>, x: Int, y: Int) {
|
||||
private fun calculateAndAssign(lightmap: Array<Cvec>, x: Int, y: Int) {
|
||||
|
||||
if (inNoopMask(x, y)) return
|
||||
|
||||
@@ -531,13 +532,13 @@ object LightmapRenderer {
|
||||
setLightOf(lightmap, x, y, lightLevelThis.cpy())
|
||||
}
|
||||
|
||||
private fun getLightForOpaque(x: Int, y: Int): Color? { // ...so that they wouldn't appear too dark
|
||||
private fun getLightForOpaque(x: Int, y: Int): Cvec? { // ...so that they wouldn't appear too dark
|
||||
val l = getLightInternal(x, y)
|
||||
if (l == null) return null
|
||||
|
||||
// brighten if solid
|
||||
if (BlockCodex[world.getTileFromTerrain(x, y)].isSolid) {
|
||||
return Color(
|
||||
return Cvec(
|
||||
(l.r * 1.2f),
|
||||
(l.g * 1.2f),
|
||||
(l.b * 1.2f),
|
||||
@@ -551,7 +552,7 @@ object LightmapRenderer {
|
||||
|
||||
var lightBuffer: Pixmap = Pixmap(1, 1, Pixmap.Format.RGBA8888)
|
||||
|
||||
private val colourNull = Color(0)
|
||||
private val colourNull = Cvec(0)
|
||||
private val epsilon = 1f/1024f
|
||||
|
||||
private var _lightBufferAsTex: Texture = Texture(1, 1, Pixmap.Format.RGBA8888)
|
||||
@@ -568,7 +569,7 @@ object LightmapRenderer {
|
||||
|
||||
// wipe out beforehand. You DO need this
|
||||
lightBuffer.blending = Pixmap.Blending.None // gonna overwrite (remove this line causes the world to go bit darker)
|
||||
lightBuffer.setColor(colourNull)
|
||||
lightBuffer.setColor(0)
|
||||
lightBuffer.fill()
|
||||
|
||||
|
||||
@@ -581,7 +582,7 @@ object LightmapRenderer {
|
||||
|
||||
for (x in this_x_start..this_x_end) {
|
||||
|
||||
val color = (getLightForOpaque(x, y) ?: Color(0f, 0f, 0f, 0f)).normaliseToHDR()
|
||||
val color = (getLightForOpaque(x, y) ?: Cvec(0f, 0f, 0f, 0f)).normaliseToHDR()
|
||||
|
||||
lightBuffer.setColor(color)
|
||||
|
||||
@@ -620,11 +621,11 @@ object LightmapRenderer {
|
||||
* @param darken (0-255) per channel
|
||||
* @return darkened data (0-255) per channel
|
||||
*/
|
||||
fun darkenColoured(data: Color, darken: Color): Color {
|
||||
fun darkenColoured(data: Cvec, darken: Cvec): Cvec {
|
||||
// use equation with magic number 8.0
|
||||
// this function, when done recursively (A_x = darken(A_x-1, C)), draws exponential curve. (R^2 = 1)
|
||||
|
||||
return Color(
|
||||
return Cvec(
|
||||
data.r * (1f - darken.r * lightScalingMagic),//.clampZero(),
|
||||
data.g * (1f - darken.g * lightScalingMagic),//.clampZero(),
|
||||
data.b * (1f - darken.b * lightScalingMagic),//.clampZero(),
|
||||
@@ -638,11 +639,11 @@ object LightmapRenderer {
|
||||
* @param darken (0-255)
|
||||
* @return
|
||||
*/
|
||||
fun darkenUniformInt(data: Color, darken: Float): Color {
|
||||
fun darkenUniformInt(data: Cvec, darken: Float): Cvec {
|
||||
if (darken < 0 || darken > CHANNEL_MAX)
|
||||
throw IllegalArgumentException("darken: out of range ($darken)")
|
||||
|
||||
val darkenColoured = Color(darken, darken, darken, darken)
|
||||
val darkenColoured = Cvec(darken, darken, darken, darken)
|
||||
return darkenColoured(data, darkenColoured)
|
||||
}
|
||||
|
||||
@@ -653,8 +654,8 @@ object LightmapRenderer {
|
||||
* @param brighten (-1.0 - 1.0) negative means darkening
|
||||
* @return processed colour
|
||||
*/
|
||||
fun alterBrightnessUniform(data: Color, brighten: Float): Color {
|
||||
return Color(
|
||||
fun alterBrightnessUniform(data: Cvec, brighten: Float): Cvec {
|
||||
return Cvec(
|
||||
data.r + brighten,
|
||||
data.g + brighten,
|
||||
data.b + brighten,
|
||||
@@ -663,7 +664,7 @@ object LightmapRenderer {
|
||||
}
|
||||
|
||||
/** infix is removed to clarify the association direction */
|
||||
fun Color.maxAndAssign(other: Color): Color {
|
||||
fun Cvec.maxAndAssign(other: Cvec): Cvec {
|
||||
this.set(
|
||||
if (this.r > other.r) this.r else other.r,
|
||||
if (this.g > other.g) this.g else other.g,
|
||||
@@ -723,7 +724,7 @@ object LightmapRenderer {
|
||||
_init = true
|
||||
}
|
||||
lightBuffer = Pixmap(tilesInHorizontal, tilesInVertical, Pixmap.Format.RGBA8888)
|
||||
lightmap = Array<Color>(LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT) { Color(0) }
|
||||
lightmap = Array<Cvec>(LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT) { Cvec(0) }
|
||||
|
||||
|
||||
printdbg(this, "Resize event")
|
||||
@@ -797,14 +798,14 @@ object LightmapRenderer {
|
||||
1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f,1.0000f // isn't it beautiful?
|
||||
)
|
||||
/** To eliminated visible edge on the gradient when 255/1023 is exceeded */
|
||||
internal fun Color.normaliseToHDR() = Color(
|
||||
hdr(this.r.coerceIn(0f,1f)),
|
||||
hdr(this.g.coerceIn(0f,1f)),
|
||||
hdr(this.b.coerceIn(0f,1f)),
|
||||
hdr(this.a.coerceIn(0f,1f))
|
||||
internal fun Cvec.normaliseToHDR() = Color(
|
||||
hdr(this.r.coerceIn(0f, 1f)),
|
||||
hdr(this.g.coerceIn(0f, 1f)),
|
||||
hdr(this.b.coerceIn(0f, 1f)),
|
||||
hdr(this.a.coerceIn(0f, 1f))
|
||||
)
|
||||
|
||||
private fun Color.nonZero() = this.r + this.g + this.b + this.a > epsilon
|
||||
private fun Cvec.nonZero() = this.r + this.g + this.b + this.a > epsilon
|
||||
|
||||
val histogram: Histogram
|
||||
get() {
|
||||
@@ -890,5 +891,6 @@ object LightmapRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
fun Cvec.toRGBA() = (255 * r).toInt() shl 24 or ((255 * g).toInt() shl 16) or ((255 * b).toInt() shl 8) or (255 * a).toInt()
|
||||
fun Color.toRGBA() = (255 * r).toInt() shl 24 or ((255 * g).toInt() shl 16) or ((255 * b).toInt() shl 8) or (255 * a).toInt()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user