Improvement to light blending (can mix sunlight to transparent and luminous tile), failed attempt to perturb terrain, need better algorithm

Former-commit-id: a8b456401859802fe5d19b7d12a41033f2ed3e44
Former-commit-id: 4f4a976e6f295f45519744216704c864afb6d621
This commit is contained in:
Song Minjae
2016-02-23 13:42:44 +09:00
parent 60fdff7528
commit 34a04943ab
25 changed files with 205 additions and 39 deletions

View File

@@ -67,8 +67,15 @@ public class ActorWithBody implements Actor, Visible, Glowing {
* meter to pixel : 24/FPS
*/
private final float METER = 24f;
private final float SI_TO_GAME_ACC = METER / (Terrarum.TARGET_FPS * Terrarum.TARGET_FPS);
/**
* [m / s^2] * SI_TO_GAME_ACC -> [px / IFrame^2]
*/
private final float SI_TO_GAME_ACC = METER / FastMath.sqr(Terrarum.TARGET_FPS);
/**
* [m / s] * SI_TO_GAME_VEL -> [px / IFrame]
*/
private final float SI_TO_GAME_VEL = METER / Terrarum.TARGET_FPS;
private float gravitation;
private final float DRAG_COEFF = 1f;

View File

@@ -55,7 +55,7 @@ public class Player extends ActorWithBody implements Controllable, Pocketed, Fac
private final int TSIZE = MapDrawer.TILE_SIZE;
private char LUMINANCE_RGB = 1560;
private char LUMINANCE_RGB = 31960;
private HashSet<Faction> factionSet = new HashSet<>();

View File

@@ -157,6 +157,14 @@ public class GameMap {
else throw new IllegalArgumentException("illegal mode input: " + String.valueOf(mode));
}
public void overwriteLayerWall(MapLayer layerData) {
layerWall = layerData;
}
public void overwriteLayerTerrain(MapLayer layerData) {
layerTerrain = layerData;
}
private int uint8ToInt32(byte x) {
int ret;
if ((x & 0b1000_0000) != 0) {

View File

@@ -109,6 +109,10 @@ public class MapLayer implements Iterable<Byte> {
return uint8ToInt32(data[y][x]);
}
public void setTile(int x, int y, byte tile) {
data[y][x] = tile;
}
private int uint8ToInt32(byte x) {
int ret;
if ((x & 0b1000_0000) != 0) {

View File

@@ -30,4 +30,10 @@ Crafted tool/weapon size is dependent on the baseRaceMass.
* Gemstone tier
Topaz -> R·G·B -> Diamond·Amethyst
Topaz -> R·G·B -> Diamond·Amethyst
* Colouring
Natural: Use 4096
Magical/Surreal: Use 24 Bits

View File

@@ -114,9 +114,9 @@ public class LightmapRenderer {
}
}
// Round 2
for (int y = for_y_start; y < for_y_end; y++) {
for (int x = for_x_end - 1; x >= for_x_start; x--) {
// Round 4
for (int y = for_y_end - 1; y > for_y_start; y--) {
for (int x = for_x_start; x < for_x_end; x++) {
staticLightMap[y][x] = calculate(x, y);
}
}
@@ -128,12 +128,13 @@ public class LightmapRenderer {
}
}
// Round 4
for (int y = for_y_end - 1; y > for_y_start; y--) {
for (int x = for_x_start; x < for_x_end; x++) {
// Round 2
for (int y = for_y_start; y < for_y_end; y++) {
for (int x = for_x_end - 1; x >= for_x_start; x--) {
staticLightMap[y][x] = calculate(x, y);
}
}
}
public static void draw(Graphics g) {
@@ -178,23 +179,21 @@ public class LightmapRenderer {
* d
*/
char a = (y == 0) ? thisLightLevel
: (y == Terrarum.game.map.height - 1) ? thisLightLevel
: max(staticLightMap[y][x]
: (y == Terrarum.game.map.height - 1) ? thisLightLevel
: maximiseRGB(staticLightMap[y][x]
, staticLightMap[y - 1][x]);
char d = (y == 0) ? thisLightLevel
: (y == Terrarum.game.map.height - 1) ? thisLightLevel
: max(staticLightMap[y][x]
: (y == Terrarum.game.map.height - 1) ? thisLightLevel
: maximiseRGB(staticLightMap[y][x]
, staticLightMap[y + 1][x]);
char b = (x == 0) ? thisLightLevel
: (x == Terrarum.game.map.width - 1) ? thisLightLevel
: max(staticLightMap[y][x]
: (x == Terrarum.game.map.width - 1) ? thisLightLevel
: maximiseRGB(staticLightMap[y][x]
, staticLightMap[y][x - 1]);
char c = (x == 0) ? thisLightLevel
: (x == Terrarum.game.map.width - 1) ? thisLightLevel
: max(staticLightMap[y][x]
: (x == Terrarum.game.map.width - 1) ? thisLightLevel
: maximiseRGB(staticLightMap[y][x]
, staticLightMap[y][x + 1]);
char t = staticLightMap[y][x];
char[] colourMapItoL = new char[4];
colourMapItoL[0] = colourLinearMix(a, b);
colourMapItoL[1] = colourLinearMix(a, c);
@@ -252,15 +251,21 @@ public class LightmapRenderer {
int thisTerrain = Terrarum.game.map.getTileFromTerrain(x, y);
int thisWall = Terrarum.game.map.getTileFromWall(x, y);
char thisTileLuminosity = TilePropCodex.getProp(thisTerrain).getLuminosity();
char thisTileOpacity = TilePropCodex.getProp(thisTerrain).getOpacity();
char sunLight = Terrarum.game.map.getGlobalLight();
// open air
if (thisTerrain == AIR && thisWall == AIR) {
lightLevelThis = screenBlend(lightLevelThis, Terrarum.game.map.getGlobalLight());
lightLevelThis = sunLight;
}
// mix luminous tile
if (thisTileLuminosity > 0) {
lightLevelThis = screenBlend(lightLevelThis, thisTileLuminosity);
// luminous tile transparent (allows sunlight to pass)
else if (thisWall == AIR && thisTileLuminosity < COLOUR_DOMAIN_SIZE) {
char darkenSunlight = darkenColoured(sunLight, thisTileOpacity);
lightLevelThis = screenBlend(darkenSunlight, thisTileLuminosity);
}
// luminous tile (opaque)
else {
lightLevelThis = thisTileLuminosity;
}
// mix lantern
@@ -282,7 +287,7 @@ public class LightmapRenderer {
}
// calculate and mix ambient
// calculate ambient
char ambient = 0; char nearby = 0;
findNearbyBrightest:
for (int yoff = -1; yoff <= 1; yoff++) {
@@ -305,7 +310,7 @@ public class LightmapRenderer {
else if (xoff != 0 && yoff != 0) { // 'a' tiles
if (!outOfMapBounds(x + xoff, y + yoff)) {
nearby = darkenUniformInt(staticLightMap[y + yoff][x + xoff]
, 2);
, 2); //2
// mix some to have more 'spreading'
// so that light spreads in a shape of an octagon instead of a diamond
}
@@ -314,14 +319,14 @@ public class LightmapRenderer {
nearby = 0; // exclude 'me' tile
}
ambient = additiveBlend(ambient, nearby); // keep base value as brightest nearby
ambient = maximiseRGB(ambient, nearby); // keep base value as brightest nearby
}
}
char opacity = TilePropCodex.getProp(thisTerrain).getOpacity();
ambient = darkenColoured(ambient, opacity); // get real ambient by appling opacity value
ambient = darkenColoured(ambient, thisTileOpacity); // get real ambient by appling opacity value
return screenBlend(lightLevelThis, ambient);
// mix and return lightlevel and ambient
return maximiseRGB(lightLevelThis, ambient);
}
else {
throw new IllegalArgumentException("Out of bounds of lightMap");
@@ -329,6 +334,9 @@ public class LightmapRenderer {
}
/**
* Subtract each channel's RGB value.
* It works like:
* f(data, darken) = RGB(data.r - darken.r, data.g - darken.g, data.b - darken.b)
*
* @param data Raw channel value [0-39] per channel
* @param darken [0-39] per channel
@@ -347,6 +355,8 @@ public class LightmapRenderer {
/**
* Darken each channel by 'darken' argument
* It works like:
* f(data, darken) = RGB(data.r - darken, data.g - darken, data.b - darken)
* @param data [0-39] per channel
* @param darken [0-1]
* @return
@@ -364,6 +374,8 @@ public class LightmapRenderer {
/**
* Darken each channel by 'darken' argument
* It works like:
* f(data, darken) = RGB(data.r - darken, data.g - darken, data.b - darken)
* @param data [0-39] per channel
* @param darken [0-39]
* @return
@@ -381,7 +393,9 @@ public class LightmapRenderer {
/**
*
* Add each channel's RGB value.
* It works like:
* f(data, brighten) = RGB(data.r + darken.r, data.g + darken.g, data.b + darken.b)
* @param data Raw channel value [0-39] per channel
* @param brighten [0-39] per channel
* @return brightened data [0-39] per channel
@@ -397,13 +411,12 @@ public class LightmapRenderer {
return constructRGBFromFloat(r, g, b);
}
/**
*
/** Get each channel from two RGB values, return new RGB that has max value of each channel
* @param rgb
* @param rgb2
* @return
*/
private static char additiveBlend(char rgb, char rgb2) {
private static char maximiseRGB(char rgb, char rgb2) {
int r1 = getRawR(rgb); int r2 = getRawR(rgb2); int newR = (r1 > r2) ? r1 : r2;
int g1 = getRawG(rgb); int g2 = getRawG(rgb2); int newG = (g1 > g2) ? g1 : g2;
int b1 = getRawB(rgb); int b2 = getRawB(rgb2); int newB = (b1 > b2) ? b1 : b2;
@@ -505,12 +518,12 @@ public class LightmapRenderer {
return (x << 4);
}
private static char max(char... i) {
private static int max(int... i) {
Arrays.sort(i);
return i[i.length - 1];
}
private static char min(char... i) {
private static int min(int... i) {
Arrays.sort(i);
return i[0];
}

View File

@@ -2,6 +2,7 @@ package com.Torvald.Terrarum.MapGenerator;
import com.Torvald.Rand.HQRNG;
import com.Torvald.Terrarum.GameMap.GameMap;
import com.Torvald.Terrarum.GameMap.MapLayer;
import com.Torvald.Terrarum.TileProperties.TileNameCode;
import com.jme3.math.FastMath;
import com.sun.istack.internal.NotNull;
@@ -34,6 +35,10 @@ public class MapGenerator {
private static int SHORE_WIDTH = 120;
private static int MAX_OCEAN_DEPTH = 200;
private static final int TERRAIN_PERTURB_OFFSETMAX = 32; // [-val , val]
private static final int TERRAIN_PERTURB_LARGESTFEATURE = 256;
private static final float TERRAIN_PERTURB_RATE = 0.5f;
private static int GLACIER_MOUNTAIN_WIDTH = 900;
private static final int GLACIER_MOUNTAIN_HEIGHT = 300;
@@ -89,8 +94,10 @@ public class MapGenerator {
placeGlacierMount(heightMap);
heightMapToObjectMap(heightMap);
perturbTerrain();
carveCave(
caveGen(1, 1.2f)
caveGen(1.4f, 1.7f)
, TileNameCode.AIR
, "Carving out cave..."
);
@@ -518,6 +525,70 @@ public class MapGenerator {
}
}
}
private static void perturbTerrain() {
SimplexNoise perturbGen = new SimplexNoise(TERRAIN_PERTURB_LARGESTFEATURE
, TERRAIN_PERTURB_RATE, seed ^ random.nextLong());
float[][] perturbMap = new float[height][width];
byte[][] layerWall = map.getWallArray();
byte[][] layerTerrain = map.getTerrainArray();
MapLayer newLayerWall = new MapLayer(width, height);
MapLayer newLayerTerrain = new MapLayer(width, height);
float lowestNoiseVal = 10000f;
float highestNoiseVal = -10000f;
for (int y = 0; y < map.height; y++) {
for (int x = 0; x < map.width; x++) {
float noise = perturbGen.getNoise(x, y); // [-1, 1]
perturbMap[y][x] = noise;
if (noise < lowestNoiseVal) lowestNoiseVal = noise;
if (noise > highestNoiseVal) highestNoiseVal = noise;
}
}
// Auto-scale noise [-1, 1]
/**
* See ./work_files/Linear_autoscale.gcx
*/
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
float noiseInit = perturbMap[y][x];
float noiseFin = (noiseInit - ((highestNoiseVal + lowestNoiseVal) / 2f))
* (2f / (highestNoiseVal - lowestNoiseVal));
perturbMap[y][x] = noiseFin;
}
}
// Perturb to x-axis, apply to newLayer
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
float offsetOrigin = perturbMap[y][x] * 0.5f + 0.5f; // [0 , 1]
int offset = Math.round(offsetOrigin * TERRAIN_PERTURB_OFFSETMAX);
byte tileWall = layerWall[y][x];
byte tileTerrain = layerTerrain[y][x];
try {
//newLayerWall.setTile(x + offset, y, tileWall);
//newLayerTerrain.setTile(x + offset, y, tileTerrain);
//layerWall[y][x] = 0;
//layerTerrain[y][x] = 0;
layerWall[y - offset][x] = tileWall;
layerTerrain[y - offset][x] = tileTerrain;
}
catch (ArrayIndexOutOfBoundsException e) {
}
}
}
// set reference (pointer) of original map layer to new layers
//map.overwriteLayerWall(newLayerWall);
//map.overwriteLayerTerrain(newLayerTerrain);
}