Moved the new code from halotroop/Ginger3D

master v0.0.0-alpha
Caroline Bell 2020-03-08 21:12:31 -07:00
parent 42585075db
commit 66b7353426
370 changed files with 8664 additions and 208618 deletions

View File

@ -11,7 +11,7 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-13">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>

3
.gitignore vendored
View File

@ -1,4 +1,5 @@
/bin/
/target/
.classpath
.project
.project
/saves/

View File

@ -1,8 +1,8 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
org.eclipse.jdt.core.compiler.codegen.targetPlatform=13
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=11
org.eclipse.jdt.core.compiler.compliance=13
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@ -12,7 +12,7 @@ org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=11
org.eclipse.jdt.core.compiler.source=13
org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false

BIN
libs/Ginger3D-NIGHTLY.jar Normal file

Binary file not shown.

50
pom.xml
View File

@ -2,18 +2,18 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>LiteCraft</groupId>
<groupId>com.halotroop2288</groupId>
<artifactId>LiteCraft</artifactId>
<version>0.0.1-SNAPSHOT</version>
<version>NIGHTLY</version>
<name>LiteCraft</name>
<description>Lightweight Voxel Engine</description>
<description>Lightweight Voxel Engine utilizing the Ginger3D engine by hYdos</description>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>11</release>
<release>13</release>
</configuration>
</plugin>
</plugins>
@ -51,17 +51,21 @@
</properties>
</profile>
</profiles>
<repositories>
<repository>
<id>sonatype-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases><enabled>false</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
@ -78,30 +82,27 @@
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.github.hYdos</groupId>
<artifactId>Ginger3D</artifactId>
<version>NIGHTLY</version>
<scope>system</scope>
<systemPath>${project.basedir}/libs/Ginger3D-NIGHTLY.jar</systemPath>
</dependency>
<dependency>
<groupId>com.github.Spoutcraft</groupId>
<artifactId>soundsystem</artifactId>
<version>master-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.github.hYdos</groupId>
<artifactId>Ginger3D</artifactId>
<version>liteCraft-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.11.1</version>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
@ -169,5 +170,10 @@
<artifactId>joml-camera</artifactId>
<version>master-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>it.unimi.dsi</groupId>
<artifactId>fastutil</artifactId>
<version>8.3.1</version>
</dependency>
</dependencies>
</project>

View File

@ -1,168 +0,0 @@
package com.github.halotroop.litecraft;
import java.io.IOException;
import java.util.Random;
import org.aeonbits.owner.ConfigFactory;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.Version;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;
import com.github.halotroop.litecraft.input.Input;
import com.github.halotroop.litecraft.input.KeyCallbackHandler;
import com.github.halotroop.litecraft.input.Keybind;
import com.github.halotroop.litecraft.input.MouseCallbackHandler;
import com.github.halotroop.litecraft.logic.Timer;
import com.github.halotroop.litecraft.logic.Timer.TickListener;
import com.github.halotroop.litecraft.options.SettingsConfig;
import com.github.halotroop.litecraft.options.SettingsHandler;
import com.github.halotroop.litecraft.render.RenderWrapper;
import io.github.hydos.ginger.engine.elements.objects.Player;
import io.github.hydos.ginger.engine.io.Window;
import io.github.hydos.ginger.engine.math.vectors.Vector3f;
import io.github.hydos.ginger.engine.obj.ModelLoader;
import io.github.hydos.ginger.engine.render.models.TexturedModel;
public class LiteCraftMain implements Runnable
{
public static Logger logger = LogManager.getLogger(Logger.class.getName());
private static SettingsConfig config;
public static int width = 640, height = 480, maxFPS = 60; // Don't change these values. They just initialize it in case we forget to set them later.
public static boolean spamLog = false, debug = false, limitFPS = false;
public static String splashText = "404";
public static boolean fullscreen = false;
private int fps, ups, tps;
private long frameTimer;
protected Timer timer;
protected TickListener tickListener = new TickListener()
{
@Override
public void onTick(float deltaTime)
{ tps++; }
};
public static void main(String[] args) throws Exception
{
try
{
config = ConfigFactory.create(SettingsConfig.class);
width = config.screenWidth();
height = config.screenHeight();
maxFPS = config.max_fps();
spamLog = config.spamLog();
debug = config.debugMode();
}
catch (Exception e)
{
System.err.println("Config failed to load.");
e.printStackTrace();
}
try
{
Options options = SettingsHandler.createCommandLineOptions();
CommandLine cmd = new DefaultParser().parse(options, args);
width = Integer.parseInt(cmd.getOptionValue("width", "640"));
height = Integer.parseInt(cmd.getOptionValue("height", "480"));
maxFPS = Integer.parseInt(cmd.getOptionValue("max_fps", "60"));
debug = Boolean.parseBoolean(cmd.getOptionValue("debug", "false"));
spamLog = Boolean.parseBoolean(cmd.getOptionValue("spam_log", "false"));
limitFPS = Boolean.parseBoolean(cmd.getOptionValue("limit_fps", "false"));
}
catch (ParseException e)
{
e.printStackTrace();
}
new LiteCraftMain().run();
}
private void init()
{
// Leave this alone.
GLFWErrorCallback.createPrint(System.err).set();
if (!GLFW.glfwInit()) throw new IllegalStateException("Unable to initialize GLFW");
timer = new Timer(20);
timer.addTickListener(tickListener);
try
{
String[] splashes = TextFileReader.readFileToStringArray("text/splashes.txt");
splashText = splashes[new Random().nextInt(splashes.length)];
}
catch (IOException e)
{
e.printStackTrace();
}
//because someone has not made player models and im lazy lets use the ones bundeled with the engine :)
RenderWrapper.preInit();
TexturedModel tModel = ModelLoader.loadModel("stall.obj", "stallTexture.png");
tModel.getTexture().setReflectivity(1f);
tModel.getTexture().setShineDamper(7f);
Player renderPlayer = new Player(tModel, new Vector3f(0, 0, -3), 0, 180f, 0, new Vector3f(0.2f, 0.2f, 0.2f));
RenderWrapper.init(splashText, renderPlayer);
long windowId = Window.window;
KeyCallbackHandler.trackWindow(windowId);
MouseCallbackHandler.trackWindow(windowId);
// window.setWindowTitle("LiteCraft - " + ((splashText == "" || splashText == null) ? "INSERT SPLASH TEXT HERE!" : splashText));
input();
}
// Sets up the key inputs for the game (currently just esc for closing the game)
public void input()
{ Input.addPressCallback(Keybind.EXIT, LiteCraftMain::shutDown); }
// Things that the game should do over and over and over again until it is closed
private void loop()
{
ups++;
// Poll for window events. The key callback above will only be invoked during this call.
GLFW.glfwPollEvents();
Input.invokeAllListeners();
RenderWrapper.update();
timer.tick();
if (fps < maxFPS || !limitFPS) render();
if (System.currentTimeMillis() > frameTimer + 1000) // wait for one second
{
fps = 0;
ups = 0;
tps = 0;
frameTimer += 1000; // reset the wait time
}
}
public void render()
{
if (debug) System.out.println("LiteCraft | FPS: " + fps + " | TPS: " + tps + " | UPS: " + ups);
RenderWrapper.render();
fps++; // After a successful frame render, increase the frame counter.
}
public void run()
{
System.out.println("Starting game..." + "\n" + "LWJGL version: " + Version.getVersion() + "\n" + "Resolution: " + width + 'x' + height);
init();
frameTimer = System.currentTimeMillis();
// Run the rendering loop until the player has attempted to close the window
while (!Window.closed())
{
if (Window.isUpdating())
{ loop(); }
}
shutDown();
}
// Shuts down the game and destroys all the things that are using RAM (so the user doesn't have to restart their computer afterward...)
private static void shutDown()
{
logger.log(Level.DEBUG, "Closing game...");
RenderWrapper.cleanup();
System.out.println("Game closed successfully.");
System.exit(0);
}
}

View File

@ -1,23 +0,0 @@
package com.github.halotroop.litecraft;
import java.io.*;
public class TextFileReader
{
public static String[] readFileToStringArray(String filename) throws IOException
{
ClassLoader.getSystemClassLoader();
InputStream inputStream = ClassLoader.getSystemResourceAsStream(filename);
InputStreamReader streamReader = new InputStreamReader(inputStream, "UTF-8");
BufferedReader in = new BufferedReader(streamReader);
String[] output = new String[] {};
for (String line; (line = in.readLine()) != null;)
{
String[] bufferArray = new String[output.length + 1];
System.arraycopy(output, 0, bufferArray, 0, output.length);
bufferArray[output.length] = line;
output = bufferArray;
}
return output;
}
}

View File

@ -1,21 +0,0 @@
package com.github.halotroop.litecraft.input;
/*
* Author: Valoeghese
*/
public final class InitialPressHandler implements KeyListener
{
public InitialPressHandler(KeyCallback callback)
{ this.callback = callback; }
private boolean activatedPreviously = false;
private final KeyCallback callback;
@Override
public void listen(boolean active)
{
if (!activatedPreviously && active)
{ callback.onCallback(); }
activatedPreviously = active;
}
}

View File

@ -1,31 +0,0 @@
package com.github.halotroop.litecraft.input;
import java.util.*;
/*
* Author: Valoeghese
*/
public class Input
{
private static final Map<Keybind, List<KeyCallback>> CALLBACKS = new HashMap<>();
private static final Map<Keybind, List<KeyListener>> LISTENERS = new HashMap<>();
public static void addPressCallback(Keybind key, KeyCallback callback)
{ CALLBACKS.computeIfAbsent(key, listener -> new ArrayList<>()).add(callback); }
public static void addListener(Keybind key, KeyListener callback)
{ LISTENERS.computeIfAbsent(key, listener -> new ArrayList<>()).add(callback); }
public static void invokeAllListeners()
{
CALLBACKS.forEach((keybind, listeners) ->
{
if (keybind.isActive())
{ listeners.forEach(callback -> callback.onCallback()); }
});
LISTENERS.forEach((keybind, listeners) ->
{
listeners.forEach(listener -> listener.listen(keybind.isActive()));
});
}
}

View File

@ -1,9 +0,0 @@
package com.github.halotroop.litecraft.input;
/*
* Author: Valoeghese
*/
public interface KeyCallback
{
public void onCallback();
}

View File

@ -1,32 +0,0 @@
package com.github.halotroop.litecraft.input;
import org.lwjgl.glfw.*;
/*
* Author: Valoeghese
*/
public class KeyCallbackHandler extends GLFWKeyCallback
{
private KeyCallbackHandler()
{}
private static final KeyCallbackHandler INSTANCE = new KeyCallbackHandler();
public static void trackWindow(long window)
{ GLFW.glfwSetKeyCallback(window, INSTANCE); }
public static boolean[] keys = new boolean[GLFW.GLFW_KEY_LAST];
@Override
public void invoke(long window, int key, int scancode, int action, int mods)
{
try
{
keys[key] = action != GLFW.GLFW_RELEASE;
}
catch (ArrayIndexOutOfBoundsException e)
{
// Probably just changing the volume
}
}
}

View File

@ -1,9 +0,0 @@
package com.github.halotroop.litecraft.input;
/*
* Author: Valoeghese
*/
public interface KeyListener
{
public void listen(boolean active);
}

View File

@ -1,30 +0,0 @@
package com.github.halotroop.litecraft.input;
import org.lwjgl.glfw.GLFW;
/*
* Author: Valoeghese
*/
public final class Keybind
{
public int value;
public boolean mouse;
public static final Keybind MOVE_UP = new Keybind(GLFW.GLFW_KEY_W, false);
public static final Keybind MOVE_DOWN = new Keybind(GLFW.GLFW_KEY_S, false);
public static final Keybind MOVE_LEFT = new Keybind(GLFW.GLFW_KEY_A, false);
public static final Keybind MOVE_RIGHT = new Keybind(GLFW.GLFW_KEY_D, false);
public static final Keybind USE = new Keybind(GLFW.GLFW_MOUSE_BUTTON_1, true);
public static final Keybind SELECT_0 = new Keybind(GLFW.GLFW_KEY_1, false);
public static final Keybind SELECT_1 = new Keybind(GLFW.GLFW_KEY_2, false);
public static final Keybind SELECT_2 = new Keybind(GLFW.GLFW_KEY_3, false);
public static final Keybind EXIT = new Keybind(GLFW.GLFW_KEY_ESCAPE, false);
public Keybind(int initValue, boolean isMouse)
{
this.value = initValue;
this.mouse = isMouse;
}
public boolean isActive()
{ return mouse ? MouseCallbackHandler.buttons[value] : KeyCallbackHandler.keys[value]; }
}

View File

@ -1,23 +0,0 @@
package com.github.halotroop.litecraft.input;
import org.lwjgl.glfw.*;
/*
* Author: Valoeghese
*/
public class MouseCallbackHandler extends GLFWMouseButtonCallback
{
private MouseCallbackHandler()
{}
private static final MouseCallbackHandler INSTANCE = new MouseCallbackHandler();
public static void trackWindow(long window)
{ GLFW.glfwSetMouseButtonCallback(window, INSTANCE); }
public static boolean[] buttons = new boolean[GLFW.GLFW_MOUSE_BUTTON_LAST];
@Override
public void invoke(long window, int button, int action, int mods)
{ buttons[button] = action != GLFW.GLFW_RELEASE; }
}

View File

@ -1,62 +0,0 @@
package com.github.halotroop.litecraft.logic;
import java.util.*;
/*
* @author Jack Wilsdon (Stack Exchange)
* https://codereview.stackexchange.com/questions/111855/ticker-for-game-timing
*/
public class Timer
{
private double lastTick;
private double nextTick;
private int tickRate;
private Set<TickListener> tickListeners = new HashSet<>();
public Timer(int tickRate)
{ this.tickRate = tickRate; }
public void addTickListener(TickListener listener)
{ tickListeners.add(listener); }
public void removeTickListener(TickListener listener)
{ tickListeners.remove(listener); }
public void setTickRate(int tickRate)
{ this.tickRate = tickRate; }
public int getTickRate()
{ return tickRate; }
public void reset()
{
lastTick = 0;
nextTick = 0;
}
public boolean tick()
{
long currentTime = System.currentTimeMillis();
if (currentTime >= nextTick)
{
long targetTimeDelta = 1000L / tickRate;
if (lastTick == 0 || nextTick == 0)
{
lastTick = currentTime - targetTimeDelta;
nextTick = currentTime;
}
float deltaTime = (float) (currentTime - lastTick) / targetTimeDelta;
for (TickListener listener : tickListeners)
{ listener.onTick(deltaTime); }
lastTick = currentTime;
nextTick = currentTime + targetTimeDelta;
return true;
}
return false;
}
public interface TickListener
{
void onTick(float deltaTime);
}
}

View File

@ -1,27 +0,0 @@
package com.github.halotroop.litecraft.options;
import org.aeonbits.owner.Config;
@Config.Sources("file:~/Documents/LiteCraft.config")
public interface SettingsConfig extends Config
{
@Key("render.screen_width")
@DefaultValue("640")
public int screenWidth();
@Key("render.screen_height")
@DefaultValue("480")
public int screenHeight();
@Key("render.max_fps")
@DefaultValue("60")
public int max_fps();
@Key("debug.debug_mode")
@DefaultValue("false")
public boolean debugMode();
@Key("debug.spam_log")
@DefaultValue("false")
public boolean spamLog();
}

View File

@ -1,18 +0,0 @@
package com.github.halotroop.litecraft.options;
import org.apache.commons.cli.*;
public class SettingsHandler
{
public static Options createCommandLineOptions()
{
Options cmdOptions = new Options();
cmdOptions.addOption(new Option("w", "width", true, "Screen width"));
cmdOptions.addOption(new Option("h", "height", true, "Screen height"));
cmdOptions.addOption(new Option("debug", "debug", true, "Use debug features"));
cmdOptions.addOption(new Option("spam_log", "spam_log", true, "Log sanity checks"));
cmdOptions.addOption(new Option("limit_fps", "limit_fps", true, "Use the FPS limiter"));
cmdOptions.addOption(new Option("max_fps", "max_fps", true, "The maximum amount of FPS"));
return cmdOptions;
}
}

View File

@ -1,11 +0,0 @@
package com.github.halotroop.litecraft.registries;
public class BlockList
{
// this is how you fix bugs :)
// public static List<Block> blocks;
// public static Block dirt;
// public static Block stone;
public BlockList()
{}
}

View File

@ -1,5 +0,0 @@
package com.github.halotroop.litecraft.registries;
public class EntityList
{
}

View File

@ -1,5 +0,0 @@
package com.github.halotroop.litecraft.registries;
public class ItemList
{
}

View File

@ -1,81 +0,0 @@
package com.github.halotroop.litecraft.render;
import java.util.ArrayList;
import java.util.List;
import com.github.halotroop.litecraft.LiteCraftMain;
import io.github.hydos.ginger.engine.cameras.ThirdPersonCamera;
import io.github.hydos.ginger.engine.elements.GuiTexture;
import io.github.hydos.ginger.engine.elements.objects.Entity;
import io.github.hydos.ginger.engine.elements.objects.Light;
import io.github.hydos.ginger.engine.elements.objects.Player;
import io.github.hydos.ginger.engine.font.TextMaster;
import io.github.hydos.ginger.engine.io.Window;
import io.github.hydos.ginger.engine.math.vectors.Vector3f;
import io.github.hydos.ginger.engine.math.vectors.Vector4f;
import io.github.hydos.ginger.engine.particle.ParticleMaster;
import io.github.hydos.ginger.engine.postprocessing.PostProcessing;
import io.github.hydos.ginger.engine.render.MasterRenderer;
import io.github.hydos.ginger.engine.terrain.Terrain;
import io.github.hydos.ginger.engine.utils.Loader;
import io.github.hydos.ginger.main.GingerMain;
/*
* Render wrapper for Ginger3D, Hydos' render engine
*/
public class RenderWrapper
{
private static MasterRenderer masterRenderer;
public static List<Entity> entities = new ArrayList<Entity>();
public static List<GuiTexture> guis = new ArrayList<GuiTexture>();
public static List<Light> lights = new ArrayList<Light>();
public static ThirdPersonCamera camera;
private static final List<Terrain> TERRAIN = new ArrayList<Terrain>();
private static final List<Entity> NORMAL_ENTITY = new ArrayList<Entity>();
public static void init(String splash, Player renderPlayer)
{
camera = new ThirdPersonCamera(new Vector3f(0, 0.1f, 0), renderPlayer);
Window.setBackgroundColour(96 / 256F, 26 / 256F, 108 / 25F);
masterRenderer = new MasterRenderer(camera);
ParticleMaster.init(masterRenderer.getProjectionMatrix());
PostProcessing.init();
}
public static void cleanup()
{
Window.stop();
PostProcessing.cleanUp();
ParticleMaster.cleanUp();
masterRenderer.cleanUp();
TextMaster.cleanUp();
Loader.cleanUp();
System.exit(0);
}
public static void render()
{
Window.update();
GingerMain.update();
GingerMain.preRenderScene(masterRenderer);
masterRenderer.renderScene(entities, NORMAL_ENTITY, TERRAIN, lights, camera, new Vector4f(0, -1, 0, 100000));
ParticleMaster.renderParticles(camera);
masterRenderer.renderGuis(guis);
TextMaster.render();
Window.swapBuffers();
}
public static void preInit()
{
Window.create(LiteCraftMain.width, LiteCraftMain.height, "LiteCraft - " + LiteCraftMain.splashText, 60);
GingerMain.init();
}
public static void update()
{
Window.update();
GingerMain.update();
ParticleMaster.update(camera);
}
}

View File

@ -1,5 +0,0 @@
package com.github.halotroop.litecraft.types.block;
public class Block
{
}

View File

@ -1,7 +0,0 @@
package com.github.halotroop.litecraft.types.entity;
public abstract class Entity
{
public Entity(String id, String type)
{}
}

View File

@ -1,7 +0,0 @@
package com.github.halotroop.litecraft.types.gui;
public abstract class HUD
{
public HUD()
{}
}

View File

@ -1,7 +0,0 @@
package com.github.halotroop.litecraft.types.gui;
public class MainMenu extends Menu
{
public MainMenu()
{ super(); }
}

View File

@ -1,7 +0,0 @@
package com.github.halotroop.litecraft.types.gui;
public abstract class Menu
{
public Menu()
{}
}

View File

@ -1,5 +0,0 @@
package com.github.halotroop.litecraft.types.item;
public class Item
{
}

View File

@ -0,0 +1,217 @@
package com.halotroop.litecraft;
import org.joml.*;
import com.github.hydos.ginger.engine.common.Constants;
import com.github.hydos.ginger.engine.common.api.*;
import com.github.hydos.ginger.engine.common.api.game.*;
import com.github.hydos.ginger.engine.common.cameras.*;
import com.github.hydos.ginger.engine.common.elements.objects.Light;
import com.github.hydos.ginger.engine.common.font.FontType;
import com.github.hydos.ginger.engine.common.info.RenderAPI;
import com.github.hydos.ginger.engine.common.io.Window;
import com.github.hydos.ginger.engine.common.obj.ModelLoader;
import com.github.hydos.ginger.engine.opengl.api.GingerGL;
import com.github.hydos.ginger.engine.opengl.postprocessing.PostProcessing;
import com.github.hydos.ginger.engine.opengl.render.*;
import com.github.hydos.ginger.engine.opengl.render.models.GLTexturedModel;
import com.github.hydos.ginger.engine.opengl.utils.*;
import com.halotroop.litecraft.render.BlockRenderer;
import com.halotroop.litecraft.save.LitecraftSave;
import com.halotroop.litecraft.screens.*;
import com.halotroop.litecraft.types.block.Blocks;
import com.halotroop.litecraft.types.entity.PlayerEntity;
import com.halotroop.litecraft.util.RelativeDirection;
import com.halotroop.litecraft.world.World;
import tk.valoeghese.gateways.client.io.*;
public class Litecraft extends Game
{
// FIXME: search for ((GingerGL)engine) and properly implement both render APIs when Vulkan is complete.
private static Litecraft INSTANCE;
private World world;
private LitecraftSave save;
private GingerEngine engine;
public int fps, ups, tps;
public Vector4i dbgStats = new Vector4i();
private long frameTimer;
private BlockRenderer blockRenderer;
public Litecraft(int windowWidth, int windowHeight, float frameLimit)
{
Litecraft.INSTANCE = this;
// set constants
this.setupConstants();
this.setupGinger(windowWidth, windowHeight, frameLimit);
// make sure blocks are initialised ??? (Currently does nothing)
Blocks.init();
this.frameTimer = System.currentTimeMillis();
// setup keybinds
setupKeybinds();
// Open the title screen if nothing is already open.
if (GingerRegister.getInstance().currentScreen == null && world == null) ((GingerGL) engine).openScreen(new TitleScreen());
// start the game loop
this.engine.startGameLoop();
}
@Override
public void exit()
{
engine.openScreen(new ExitGameScreen());
render(); // Render the exit game screen
if (this.world != null)
{
System.out.println("Saving chunks...");
long time = System.currentTimeMillis();
this.world.unloadAllChunks();
this.getSave().saveGlobalData(this.world.getSeed(), ((PlayerEntity) this.player));
System.out.println("Saved world in " + (System.currentTimeMillis() - time) + " milliseconds");
}
engine.cleanup();
System.exit(0);
}
/** Things that ARE rendering: Anything that results in something being drawn to the frame buffer
* Things that are NOT rendering: Things that happen to update between frames but do not result in things being drawn to the screen */
@Override
public void render()
{
fps += 1;
if (System.currentTimeMillis() > frameTimer + 1000) updateDebugStats();
// Render shadows
GingerRegister.getInstance().masterRenderer.renderShadowMap(data.entities, data.lights.get(0));
// If there's a world, render it!
if (this.world != null) renderWorld();
// Render any overlays (GUIs, HUDs)
this.engine.renderOverlays();
// Put what's stored in the inactive framebuffer on the screen
Window.swapBuffers();
}
// Updates the debug stats once per real-time second, regardless of how many frames have been rendered
private void updateDebugStats()
{
this.dbgStats.set(fps, ups, tps, 0);
this.fps = 0;
this.ups = 0;
this.tps = 0;
this.frameTimer += 1000;
}
public void renderWorld()
{
GameData data = GingerRegister.getInstance().game.data;
if (Window.renderAPI == RenderAPI.OpenGL)
{
GLUtils.preRenderScene(((GingerGL) engine).getRegistry().masterRenderer);
((GingerGL) engine).contrastFbo.bindFBO();
((GingerGL) engine).getRegistry().masterRenderer.renderScene(data.entities, data.normalMapEntities, data.lights, data.camera, data.clippingPlane);
((GingerGL) engine).contrastFbo.unbindFBO();
PostProcessing.doPostProcessing(((GingerGL) engine).contrastFbo.colorTexture);
}
}
@Override
public void update()
{ ups += 1; }
private void setupConstants()
{
Constants.movementSpeed = 0.5f; // movement speed
Constants.turnSpeed = 0.00006f; // turn speed
Constants.gravity = new Vector3f(0, -0.0000000005f, 0); // compute gravity as a vec3f
Constants.jumpPower = 0.00005f; // jump power
}
// set up Ginger3D engine stuff
private void setupGinger(int windowWidth, int windowHeight, float frameCap)
{
if (engine == null) // Prevents this from being run more than once on accident.
{
Window.create(windowWidth, windowHeight, "Litecraft", frameCap, RenderAPI.OpenGL); // create window
// set up the gateways keybind key tracking
KeyCallbackHandler.trackWindow(Window.getWindow());
MouseCallbackHandler.trackWindow(Window.getWindow());
// set up ginger utilities
GLUtils.init();
switch (Window.renderAPI)
{
case OpenGL:
{
this.engine = new GingerGL();
//Set the player model
GLTexturedModel playerModel = ModelLoader.loadGenericCube("block/cubes/stone/brick/stonebrick.png");
FontType font = new FontType(GLLoader.loadFontAtlas("candara.png"), "candara.fnt");
this.player = new PlayerEntity(playerModel, new Vector3f(0, 0, -3), 0, 180f, 0, new Vector3f(0.2f, 0.2f, 0.2f));
this.camera = new FirstPersonCamera(player);
this.data = new GameData(this.player, this.camera, 20);
this.data.handleGuis = false;
((GingerGL) engine).setup(new GLRenderManager(this.camera), INSTANCE);
((GingerGL) engine).setGlobalFont(font);
this.blockRenderer = new BlockRenderer(GingerRegister.getInstance().masterRenderer.getEntityShader(), GingerRegister.getInstance().masterRenderer.getProjectionMatrix());
this.data.entities.add(this.player);
break;
}
case Vulkan:
{
// TODO: Setup Vulkan
exit();
break;
}
}
Light sun = new Light(new Vector3f(0, 105, 0), new Vector3f(0.9765625f, 0.98828125f, 0.05859375f), new Vector3f(0.002f, 0.002f, 0.002f));
this.data.lights.add(sun);
}
}
private void setupKeybinds()
{
Input.addPressCallback(Keybind.EXIT, this::exit);
Input.addInitialPressCallback(Keybind.FULLSCREEN, Window::fullscreen);
Input.addInitialPressCallback(Keybind.WIREFRAME, GingerRegister.getInstance()::toggleWireframe);
Input.addPressCallback(Keybind.MOVE_FORWARD, () -> ((PlayerEntity) this.player).move(RelativeDirection.FORWARD));
Input.addPressCallback(Keybind.MOVE_BACKWARD, () -> ((PlayerEntity) this.player).move(RelativeDirection.BACKWARD));
Input.addPressCallback(Keybind.STRAFE_LEFT, () -> ((PlayerEntity) this.player).move(RelativeDirection.LEFT));
Input.addPressCallback(Keybind.STRAFE_RIGHT, () -> ((PlayerEntity) this.player).move(RelativeDirection.RIGHT));
Input.addPressCallback(Keybind.FLY_UP, () -> ((PlayerEntity) this.player).move(RelativeDirection.UP));
Input.addPressCallback(Keybind.FLY_DOWN, () -> ((PlayerEntity) this.player).move(RelativeDirection.DOWN));
}
/** Things that should be ticked: Entities when deciding an action, in-game timers (such as smelting), the in-game time
* Things that should not be ticked: Rendering, input, player movement */
@Override
public void tick()
{
tps += 1;
if (this.player instanceof PlayerEntity && camera != null)
{
Input.invokeAllListeners();
((PlayerEntity) this.player).updateMovement();
camera.updateMovement();
}
}
// @formatter=off
public static Litecraft getInstance()
{ return INSTANCE; }
public Camera getCamera()
{ return this.camera; }
public LitecraftSave getSave()
{ return save; }
public World getWorld()
{ return this.world; }
public void changeWorld(World world)
{ this.world = world; }
public void setSave(LitecraftSave save)
{ this.save = save; }
@Override
public void renderScene()
{ world.render(this.blockRenderer); }
}

View File

@ -0,0 +1,17 @@
package com.halotroop.litecraft;
import org.lwjgl.Version;
import org.lwjgl.glfw.GLFW;
public class StarterGL
{
// private static final boolean usingEclipse = false;
public static void main(String[] args)
{
System.out.println("GLFW version: " + GLFW.glfwGetVersionString());
System.out.println("LWJGL version: " + Version.getVersion());
// Put SoundSystem version here
// TODO: Put a commandline reader here to check for desired width, height, and frame limit!
new Litecraft(1280, 720, 60);
}
}

View File

@ -0,0 +1,6 @@
package com.halotroop.litecraft.logic;
public enum Gamemode
{
GRAVITY, FREECAM,
}

View File

@ -0,0 +1,10 @@
package com.halotroop.litecraft.logic;
import tk.valoeghese.sod.BinaryData;
public interface SODSerializable
{
void read(BinaryData data);
void write(BinaryData data);
}

View File

@ -0,0 +1,90 @@
package com.halotroop.litecraft.render;
import org.joml.Matrix4f;
import org.lwjgl.opengl.*;
import com.github.hydos.ginger.engine.common.api.GingerRegister;
import com.github.hydos.ginger.engine.common.elements.objects.RenderObject;
import com.github.hydos.ginger.engine.common.io.Window;
import com.github.hydos.ginger.engine.common.math.Maths;
import com.github.hydos.ginger.engine.opengl.render.Renderer;
import com.github.hydos.ginger.engine.opengl.render.models.GLTexturedModel;
import com.github.hydos.ginger.engine.opengl.render.shaders.StaticShader;
import com.halotroop.litecraft.types.block.BlockInstance;
import com.halotroop.litecraft.world.gen.WorldGenConstants;
public class BlockRenderer extends Renderer implements WorldGenConstants
{
public StaticShader shader;
public int atlasID;
public BlockRenderer(StaticShader shader, Matrix4f projectionMatrix)
{
this.shader = shader;
shader.start();
shader.loadProjectionMatrix(projectionMatrix);
shader.stop();
this.atlasID = VoxelLoader.createBlockAtlas();
}
private void prepBlockInstance(RenderObject entity)
{
Matrix4f transformationMatrix = Maths.createTransformationMatrix(entity.getPosition(), entity.getRotX(),
entity.getRotY(), entity.getRotZ(), entity.getScale());
shader.loadTransformationMatrix(transformationMatrix);
}
public void prepareModel(GLTexturedModel model)
{
GL30.glBindVertexArray(model.getRawModel().getVaoID());
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(1);
GL20.glEnableVertexAttribArray(2);
}
public void unbindModel()
{
GL20.glDisableVertexAttribArray(0);
GL20.glDisableVertexAttribArray(1);
GL20.glDisableVertexAttribArray(2);
GL30.glBindVertexArray(0);
}
public void enableWireframe()
{ if (GingerRegister.getInstance().wireframe)
GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE); }
public void disableWireframe()
{ if (GingerRegister.getInstance().wireframe)
GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL); }
public void prepareRender()
{
// TODO: combine VBOS
shader.start();
shader.loadSkyColour(Window.getColour());
shader.loadViewMatrix(GingerRegister.getInstance().game.data.camera);
shader.loadFakeLightingVariable(true);
shader.loadShine(1, 1);
GL13.glActiveTexture(GL13.GL_TEXTURE0);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, atlasID);
enableWireframe();
}
public void render(BlockInstance[] renderList)
{
prepareRender();
for (BlockInstance entity : renderList)
{
if (entity != null && entity.getModel() != null)
{
GLTexturedModel blockModel = entity.getModel();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, blockModel.getTexture().getTextureID());
prepBlockInstance(entity);
GL11.glDrawElements(GL11.GL_TRIANGLES, blockModel.getRawModel().getVertexCount(), GL11.GL_UNSIGNED_INT, 0);
}
}
// disableWireframe();
// shader.stop();
}
}

View File

@ -0,0 +1,50 @@
package com.halotroop.litecraft.render;
import java.nio.ByteBuffer;
import org.lwjgl.opengl.*;
import com.github.hydos.ginger.engine.opengl.utils.GLLoader;
import com.halotroop.litecraft.types.block.*;
public class VoxelLoader extends GLLoader
{
public static int createBlockAtlas()
{
int width = 16;
int height = 16;
//Prepare the atlas texture and gen it
int atlasId = GL11.glGenTextures();
//Bind it to openGL
GL11.glBindTexture(GL11.GL_TEXTURE_2D, atlasId);
//Apply the settings for the texture
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
//Fill the image with blank image data
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width * 2, height * 2, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, (ByteBuffer) null);
long maxX = Math.round(Math.sqrt(Blocks.blocks.size()));
int currentX = 0;
int currentY = 0;
for (Block block : Blocks.blocks)
{
//just in case
if (!block.texture.equals("DONTLOAD"))
{
System.out.println(block.texture);
block.updateBlockModelData();
if (currentX > maxX)
{
currentX = 0;
currentY--;
}
GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, 0,
currentX * width, currentY * height,
width, height,
GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE,
block.model.getTexture().getTexture().getImage());
currentX++;
}
}
return atlasId;
}
}

View File

@ -0,0 +1,163 @@
package com.halotroop.litecraft.save;
import java.io.*;
import java.util.Random;
import org.joml.Vector3f;
import com.github.hydos.ginger.engine.common.cameras.Camera;
import com.halotroop.litecraft.Litecraft;
import com.halotroop.litecraft.types.entity.PlayerEntity;
import com.halotroop.litecraft.world.*;
import com.halotroop.litecraft.world.dimension.Dimension;
import tk.valoeghese.sod.*;
public final class LitecraftSave
{
public LitecraftSave(String name, boolean mustCreateNew)
{
StringBuilder sb = new StringBuilder(SAVE_DIR).append(name);
File saveDir = new File(sb.toString());
if (mustCreateNew)
{
while (saveDir.exists())
{
sb.append('_'); // append "_" to the save name until we get a unique save, if we must create a new save
saveDir = new File(sb.toString());
}
}
this.file = saveDir;
this.file.mkdirs();
}
private final File file;
public boolean saveChunk(Chunk chunk)
{
StringBuilder fileLocBuilder = new StringBuilder(this.file.getPath())
.append('/').append(Dimension.getById(chunk.dimension).saveIdentifier)
.append('/').append(chunk.chunkX)
.append('/').append(chunk.chunkZ);
File chunkDir = new File(fileLocBuilder.toString());
chunkDir.mkdirs(); // create directory for file if it does not exist
// format: <save dir>/<dim>/<chunkX>/<chunkZ>/<chunkY>.sod
File chunkFile = new File(fileLocBuilder.append('/').append(chunk.chunkY).append(".sod").toString());
try
{
chunkFile.createNewFile();
BinaryData data = new BinaryData(); // create new empty binary data
chunk.write(data); // write the chunk info to the binary data
return data.write(chunkFile); // write the data to the file, return whether an io exception occurred
}
catch (IOException e)
{
e.printStackTrace();
return false; // io exception = chunk writing failed at some point
}
}
public Chunk readChunk(World world, int chunkX, int chunkY, int chunkZ, int dimension)
{
// format: <save dir>/<dim>/<chunkX>/<chunkZ>/<chunkY>.sod
File chunkFile = new File(new StringBuilder(this.file.getPath())
.append('/').append(Dimension.getById(dimension).saveIdentifier)
.append('/').append(chunkX)
.append('/').append(chunkZ)
.append('/').append(chunkY).append(".sod").toString());
if (chunkFile.isFile())
{
BinaryData data = BinaryData.read(chunkFile);
Chunk result = new Chunk(world, chunkX, chunkY, chunkZ, dimension); // create chunk
result.read(data); // load the chunk data we have just read into the chunk
return result;
}
else return null;
}
public World getWorldOrCreate(Dimension<?> dim)
{
File globalDataFile = new File(this.file.getPath() + "/global_data.sod");
if (globalDataFile.isFile()) // load world
{
BinaryData data = BinaryData.read(globalDataFile); // read data from the world file
DataSection properties = data.get("properties"); // get the properties data section from the data that we have just read
DataSection playerData = data.get("player");
long seed = 0; // default seed if we cannot read it is 0
float playerX = 0, playerY = 0, playerZ = -3; // default player x/y/z
float playerYaw = 0.0f;
try // try read the seed from the file
{
seed = properties.readLong(0); // seed is at index 0
playerX = playerData.readFloat(0); // player x/y/z is at index 0/1/2 respectively
playerY = playerData.readFloat(1);
playerZ = playerData.readFloat(2);
Camera camera = Litecraft.getInstance().getCamera(); // get camera
camera.setPitch(playerData.readFloat(3)); // read pitch, yaw, roll from 3/4/5
playerYaw = playerData.readFloat(4);
camera.setYaw(playerYaw);
camera.setRoll(playerData.readFloat(5));
}
catch (Throwable e)
{
System.out.println("Exception in reading save data! This may be benign, merely an artifact of an update to the contents of the world save data.");
}
World world = new World(seed, RENDER_SIZE, dim, this); // create new world with seed read from file or 0, if it could not be read
world.spawnPlayer(playerX, playerY, playerZ); // spawn player in world
return world;
}
else // create world
{
long seed = new Random().nextLong();
try
{
globalDataFile.createNewFile(); // create world file
this.writeGlobalData(globalDataFile, seed, new Vector3f(0, 0, -3)); // write global data with default player pos
}
catch (IOException e)
{
// If this fails the world seed will not be consistent across saves
e.printStackTrace();
}
World world = new World(seed, RENDER_SIZE, dim, this); // create new world with generated seed
world.spawnPlayer(); // spawn player in world
return world;
}
}
public void saveGlobalData(long seed, PlayerEntity playerEntity)
{
try
{
File globalDataFile = new File(this.file.getPath() + "/global_data.sod");
globalDataFile.createNewFile(); // create world file if it doesn't exist.
writeGlobalData(globalDataFile, seed, playerEntity.getPosition());
}
catch (IOException e)
{
System.err.println("A critical error occurred while trying to save world data!");
e.printStackTrace();
}
}
private void writeGlobalData(File globalDataFile, long seed, Vector3f playerPos)
{
BinaryData data = new BinaryData(); // create empty binary data
DataSection properties = new DataSection(); // create empty data section for properties
properties.writeLong(seed); // write seed at index 0
DataSection playerData = new DataSection();
playerData.writeFloat(playerPos.x); // default spawn player x/y/z
playerData.writeFloat(playerPos.y);
playerData.writeFloat(playerPos.z);
Camera camera = Litecraft.getInstance().getCamera();
playerData.writeFloat(camera.getPitch());
playerData.writeFloat(camera.getYaw());
playerData.writeFloat(camera.getRoll());
data.put("properties", properties); // add properties section to data
data.put("player", playerData); // add player section to data
data.write(globalDataFile); // write to file
}
private static final String SAVE_DIR = "./saves/";
private static final int RENDER_SIZE = 5;
}

View File

@ -0,0 +1,34 @@
package com.halotroop.litecraft.screens;
import org.joml.Vector2f;
import com.github.hydos.ginger.engine.common.api.GingerEngine;
import com.github.hydos.ginger.engine.common.font.GUIText;
import com.github.hydos.ginger.engine.common.io.Window;
import com.github.hydos.ginger.engine.common.screen.Screen;
import com.github.hydos.ginger.engine.opengl.api.GingerGL;
public class ExitGameScreen extends Screen
{
private GUIText infoText;
// TODO: Add Vulkan text renderer
private GingerEngine engine = GingerGL.getInstance();
public ExitGameScreen()
{
infoText = ((GingerGL) engine).registerText("Saving and exiting...", 3, new Vector2f(Window.getWidth() / 2, Window.getHeight() / 2), 1f, true, "info");
infoText.setBorderWidth(0.5f);
}
@Override
public void render()
{}
@Override
public void tick()
{}
@Override
public void cleanup()
{ infoText.remove(); }
}

View File

@ -0,0 +1,50 @@
package com.halotroop.litecraft.screens;
import org.joml.*;
import com.github.hydos.ginger.engine.common.api.*;
import com.github.hydos.ginger.engine.common.font.GUIText;
import com.github.hydos.ginger.engine.common.screen.Screen;
import com.github.hydos.ginger.engine.opengl.api.GingerGL;
import com.halotroop.litecraft.Litecraft;
public class IngameHUD extends Screen
{
private GUIText debugText;
private GUIText positionText;
// TODO: Add Vulkan text renderer
private GingerEngine engine = GingerGL.getInstance();
private Litecraft litecraft = Litecraft.getInstance();
public IngameHUD()
{
debugText = ((GingerGL) engine).registerText("Loading...", 2, new Vector2f(0, 0), 1f, true, "debugInfo");
debugText.setBorderWidth(0.5f);
positionText = ((GingerGL) engine).registerText("Loading...", 2, new Vector2f(0, -0.1f), 1f, true, "posInfo");
positionText.setBorderWidth(0.5f);
}
@Override
public void render()
{}
@Override
public void tick()
{
// long maxMemory = Runtime.getRuntime().maxMemory();
long totalMemory = Runtime.getRuntime().totalMemory();
long freeMemory = Runtime.getRuntime().freeMemory();
long usedMemory = (totalMemory - freeMemory) / 1024 / 1024;
Vector4i dbg = litecraft.dbgStats;
Vector3f position = GingerRegister.getInstance().game.data.playerObject.getPosition();
debugText.setText("FPS: " + dbg.x() + " UPS: " + dbg.y() + " TPS: " + dbg.z() + " TWL: " + dbg.w() + " Mem: " + usedMemory + "MB");
positionText.setText("Position: " + (int) position.x() + ", " + (int) position.y() + ", " + (int) position.z());
}
@Override
public void cleanup()
{
debugText.remove();
positionText.remove();
}
}

View File

@ -0,0 +1,71 @@
package com.halotroop.litecraft.screens;
import java.util.ArrayList;
import org.joml.*;
import com.github.hydos.ginger.engine.common.api.GingerEngine;
import com.github.hydos.ginger.engine.common.elements.GuiTexture;
import com.github.hydos.ginger.engine.common.elements.buttons.TextureButton;
import com.github.hydos.ginger.engine.common.font.GUIText;
import com.github.hydos.ginger.engine.common.io.Window;
import com.github.hydos.ginger.engine.common.screen.Screen;
import com.github.hydos.ginger.engine.opengl.api.GingerGL;
import com.halotroop.litecraft.Litecraft;
import com.halotroop.litecraft.save.LitecraftSave;
import com.halotroop.litecraft.world.dimension.Dimensions;
/** YeS */
public class TitleScreen extends Screen
{
private GUIText debugText;
// TODO: Add Vulkan text renderer
private GingerEngine engine = GingerGL.getInstance();
private TextureButton playButton;
private Litecraft litecraft = Litecraft.getInstance();
public TitleScreen()
{
elements = new ArrayList<GuiTexture>();
playButton = ((GingerGL) engine).registerButton("/textures/guis/playbutton.png", new Vector2f(0, 0), new Vector2f(0.25f, 0.1f));
playButton.show(Litecraft.getInstance().data.guis);
debugText = ((GingerGL) engine).registerText("Loading...", 2, new Vector2f(0, 0), 1f, true, "debugInfo");
debugText.setBorderWidth(0.5f);
}
@Override
public void render()
{}
@Override
public void tick()
{
Vector4i dbg = litecraft.dbgStats;
debugText.setText("FPS: " + dbg.x() + " UPS: " + dbg.y() + " TPS: " + dbg.z() + " TWL: " + dbg.w());
playButton.update();
if (playButton.isClicked())
{
Window.lockMouse();
if (Litecraft.getInstance().getWorld() == null)
{
Litecraft.getInstance().setSave(new LitecraftSave("SegregatedOrdinalData", false));
Litecraft.getInstance().changeWorld(Litecraft.getInstance().getSave().getWorldOrCreate(Dimensions.OVERWORLD));
((GingerGL) engine).setGingerPlayer(Litecraft.getInstance().getWorld().playerEntity);
}
if (Litecraft.getInstance().getWorld() != null)
{
((GingerGL) engine).openScreen(new IngameHUD());
this.cleanup();
}
//TODO: add world creation gui so it takes u to world creation place
//TODO: add a texture to be rendered behind the gui as an option
}
}
@Override
public void cleanup()
{
this.debugText.remove();
this.playButton.hide(Litecraft.getInstance().data.guis);
}
}

View File

@ -0,0 +1,95 @@
package com.halotroop.litecraft.types.block;
import java.util.*;
import com.github.hydos.ginger.engine.common.obj.ModelLoader;
import com.github.hydos.ginger.engine.opengl.render.models.GLTexturedModel;
public class Block
{
public static class Properties
{ // add properties to this builder!
private boolean visible = true;
private boolean fullCube = true;
private float caveCarveThreshold = -1f; // cannot carve
private final String identifier;
public Properties(String identifier)
{ this.identifier = identifier; }
public Properties fullCube(boolean fullCube)
{
this.fullCube = fullCube;
return this;
}
public Properties visible(boolean visible)
{
this.visible = visible;
return this;
}
public Properties caveCarveThreshold(float threshold)
{
this.caveCarveThreshold = threshold;
return this;
}
}
public GLTexturedModel model;
private final boolean visible, fullCube;
private final float caveCarveThreshold;
public final String identifier;
public String texture;
public boolean isFullCube()
{ return this.fullCube; }
public boolean isVisible()
{ return this.visible; }
public float getCaveCarveThreshold()
{ return this.caveCarveThreshold; }
protected Block(Properties properties)
{ this((GLTexturedModel) null, properties); }
protected Block(String texture, Properties properties)
{
this(ModelLoader.loadGenericCube("block/" + texture), properties);
this.texture = texture;
}
protected Block(GLTexturedModel model, Properties properties)
{
this.model = model;
this.visible = properties.visible;
this.fullCube = properties.fullCube;
this.identifier = properties.identifier;
this.caveCarveThreshold = properties.caveCarveThreshold;
if (model != null)
{
this.texture = model.getTexture().getTexture().getLocation();
}
else
{
this.texture = "DONTLOAD";
}
IDENTIFIER_TO_BLOCK.put(this.identifier, this);
Blocks.blocks.add(this);
}
public void updateBlockModelData()
{
System.out.println("Updating block with texture at block/" + texture);
this.model = ModelLoader.loadGenericCube("block/" + texture);
}
public static final Block getBlock(String identifier)
{ return IDENTIFIER_TO_BLOCK.get(identifier); }
public static final Block getBlockOrAir(String identifier)
{ return IDENTIFIER_TO_BLOCK.getOrDefault(identifier, Blocks.AIR); }
private static final Map<String, Block> IDENTIFIER_TO_BLOCK = new HashMap<>();
}

View File

@ -0,0 +1,18 @@
package com.halotroop.litecraft.types.block;
import org.joml.Vector3f;
import com.github.hydos.ginger.engine.common.elements.objects.RenderObject;
import com.halotroop.litecraft.world.Chunk;
public class BlockInstance extends RenderObject
{
public BlockInstance(Block block, Vector3f position)
{ super(block.model, position, 0, 0, 0, new Vector3f(1f, 1f, 1f)); }
public void processCulling(Chunk chunk)
{
Vector3f southNeighbourBlockLocation = this.getPosition();
southNeighbourBlockLocation.x--;
}
}

View File

@ -0,0 +1,20 @@
package com.halotroop.litecraft.types.block;
import java.util.ArrayList;
import com.halotroop.litecraft.types.block.Block.Properties;
public final class Blocks
{
public static ArrayList<Block> blocks = new ArrayList<Block>();
public static final Block AIR = new Block(new Properties("air").visible(false).fullCube(false));
public static final Block GRASS = new Block(new Properties("cubes/soil/grass/grass_top.png").caveCarveThreshold(0.04f));
public static final Block DIRT = new Block("cubes/soil/dirt.png", new Properties("dirt").caveCarveThreshold(0.04f));
public static final Block ANDESITE = new Block("cubes/stone/basic/andesite.png", new Properties("andesite").caveCarveThreshold(0.08f));
public static final Block DIORITE = new Block("cubes/stone/basic/diorite.png", new Properties("diorite").caveCarveThreshold(0.05f));
public static final Block GRANITE = new Block("cubes/stone/basic/granite.png", new Properties("granite").caveCarveThreshold(0.06f));
public static final Block GNEISS = new Block("cubes/stone/basic/gneiss.png", new Properties("gneiss").caveCarveThreshold(0.09f));
public static Block init()
{ return AIR; }
}

View File

@ -0,0 +1,12 @@
package com.halotroop.litecraft.types.entity;
import org.joml.Vector3f;
import com.github.hydos.ginger.engine.common.elements.objects.RenderObject;
import com.github.hydos.ginger.engine.opengl.render.models.GLTexturedModel;
public abstract class Entity extends RenderObject
{
public Entity(GLTexturedModel model, Vector3f position, float rotX, float rotY, float rotZ, Vector3f scale)
{ super(model, position, rotX, rotY, rotZ, scale); }
}

View File

@ -0,0 +1,100 @@
package com.halotroop.litecraft.types.entity;
import org.joml.Vector3f;
import com.github.hydos.ginger.engine.common.Constants;
import com.github.hydos.ginger.engine.common.api.GingerRegister;
import com.github.hydos.ginger.engine.common.io.Window;
import com.github.hydos.ginger.engine.opengl.render.models.GLTexturedModel;
import com.halotroop.litecraft.Litecraft;
import com.halotroop.litecraft.util.RelativeDirection;
import com.halotroop.litecraft.world.gen.WorldGenConstants;
public class PlayerEntity extends Entity implements WorldGenConstants
{
private boolean isInAir = false;
private double upwardsSpeed;
private boolean noWeight = true;
private int chunkX, chunkY, chunkZ;
public PlayerEntity(GLTexturedModel model, Vector3f position, float rotX, float rotY, float rotZ, Vector3f scale)
{
super(model, position, rotX, rotY, rotZ, scale);
this.chunkX = (int) position.x >> POS_SHIFT;
this.chunkY = (int) position.y >> POS_SHIFT;
this.chunkZ = (int) position.z >> POS_SHIFT;
}
public void move(RelativeDirection direction)
{
float ry = (float) Math.toRadians(GingerRegister.getInstance().game.data.camera.getYaw());
switch (direction)
{
default:
case FORWARD:
position.z -= Math.cos(ry) * Constants.movementSpeed;
position.x += Math.sin(ry) * Constants.movementSpeed;
break;
case BACKWARD:
position.z += Math.cos(ry) * Constants.movementSpeed;
position.x -= Math.sin(ry) * Constants.movementSpeed;
break;
case LEFT:
ry -= RIGHT_ANGLE;
position.z -= Math.cos(ry) * Constants.movementSpeed;
position.x += Math.sin(ry) * Constants.movementSpeed;
break;
case RIGHT:
ry += RIGHT_ANGLE;
position.z -= Math.cos(ry) * Constants.movementSpeed;
position.x += Math.sin(ry) * Constants.movementSpeed;
break;
case UP:
if (this.noWeight)
position.y += Constants.movementSpeed;
else this.jump();
break;
case DOWN:
position.y -= Constants.movementSpeed;
break;
}
}
private static final float RIGHT_ANGLE = (float) (Math.PI / 2f);
private void jump()
{
if (!isInAir)
{
isInAir = true;
this.upwardsSpeed = Constants.jumpPower;
}
}
public int getChunkX()
{ return this.chunkX; }
public int getChunkY()
{ return this.chunkY; }
public int getChunkZ()
{ return this.chunkZ; }
public void updateMovement()
{
super.increasePosition(0, (float) (upwardsSpeed * (Window.getTime())), 0);
upwardsSpeed += Constants.gravity.y() * Window.getTime(); // TODO: Implement 3D gravity
isInAir = false;
upwardsSpeed = 0;
int newChunkX = (int) position.x >> POS_SHIFT;
int newChunkY = (int) position.y >> POS_SHIFT;
int newChunkZ = (int) position.z >> POS_SHIFT;
if (newChunkX != this.chunkX || newChunkY != this.chunkY || newChunkZ != this.chunkZ)
{
Litecraft.getInstance().getWorld().updateLoadedChunks(newChunkX, newChunkY, newChunkZ);
this.chunkX = newChunkX;
this.chunkY = newChunkY;
this.chunkZ = newChunkZ;
}
}
}

View File

@ -0,0 +1,11 @@
package com.halotroop.litecraft.util;
public enum RelativeDirection
{
UP, // up up
DOWN, // down down
LEFT, // >left< right
RIGHT, // left >right<
FORWARD, // b
BACKWARD,// a
}

View File

@ -0,0 +1,51 @@
package com.halotroop.litecraft.util.noise;
import java.util.Random;
public final class OctaveSimplexNoise
{
protected SimplexNoise[] samplers;
private double clamp;
private double spread, amplitudeLow, amplitudeHigh;
public OctaveSimplexNoise(Random rand, int octaves)
{ this(rand, octaves, 1D, 1D, 1D); }
public OctaveSimplexNoise(Random rand, int octaves, double spread, double amplitudeHigh, double amplitudeLow)
{
this.samplers = new SimplexNoise[octaves];
this.clamp = 1D / (1D - (1D / Math.pow(2, octaves)));
for (int i = 0; i < octaves; ++i)
{ samplers[i] = new SimplexNoise(rand.nextLong()); }
this.spread = spread;
this.amplitudeLow = amplitudeLow;
this.amplitudeHigh = amplitudeHigh;
}
public double sample(double x, double y)
{
double amplSpread = 0.5D;
double result = 0;
for (SimplexNoise sampler : this.samplers)
{
result += (amplSpread * sampler.sample(x / (amplSpread * this.spread), y / (amplSpread * this.spread)));
amplSpread *= 0.5D;
}
result = result * this.clamp;
return result > 0 ? result * this.amplitudeHigh : result * this.amplitudeLow;
}
public double sample(double x, double y, double z)
{
double amplSpread = 0.5D;
double result = 0;
for (SimplexNoise sampler : this.samplers)
{
double divisor = amplSpread * this.spread;
result += (amplSpread * sampler.sample(x / divisor, y / divisor, z / divisor));
amplSpread *= 0.5D;
}
result = result * this.clamp;
return result > 0 ? result * this.amplitudeHigh : result * this.amplitudeLow;
}
}

View File

@ -0,0 +1,854 @@
package com.halotroop.litecraft.util.noise;
/** OpenSimplex Noise in Java.
* (Using implementation by Kurt Spencer)
* v1.1 (October 5, 2014)
* - Added 2D and 4D implementations.
* - Proper gradient sets for all dimensions, from a
* dimensionally-generalizable scheme with an actual
* rhyme and reason behind it.
* - Removed default permutation array in favor of
* default seed.
* - Changed seed-based constructor to be independent
* of any particular randomization library, so results
* will be the same when ported to other languages. */
public class SimplexNoise
{
private static final double STRETCH_CONSTANT_2D = -0.211324865405187; //(1/Math.sqrt(2+1)-1)/2;
private static final double SQUISH_CONSTANT_2D = 0.366025403784439; //(Math.sqrt(2+1)-1)/2;
private static final double STRETCH_CONSTANT_3D = -1.0 / 6; //(1/Math.sqrt(3+1)-1)/3;
private static final double SQUISH_CONSTANT_3D = 1.0 / 3; //(Math.sqrt(3+1)-1)/3;
private static final double NORM_CONSTANT_2D = 47;
private static final double NORM_CONSTANT_3D = 103;
private static final long DEFAULT_SEED = 0;
//Gradients for 2D. They approximate the directions to the
//vertices of an octagon from the center.
private static byte[] gradients2D = new byte[]
{
5, 2, 2, 5,
-5, 2, -2, 5,
5, -2, 2, -5,
-5, -2, -2, -5,
};
//Gradients for 3D. They approximate the directions to the
//vertices of a rhombicuboctahedron from the center, skewed so
//that the triangular and square facets can be inscribed inside
//circles of the same radius.
private static byte[] gradients3D = new byte[]
{
-11, 4, 4, -4, 11, 4, -4, 4, 11,
11, 4, 4, 4, 11, 4, 4, 4, 11,
-11, -4, 4, -4, -11, 4, -4, -4, 11,
11, -4, 4, 4, -11, 4, 4, -4, 11,
-11, 4, -4, -4, 11, -4, -4, 4, -11,
11, 4, -4, 4, 11, -4, 4, 4, -11,
-11, -4, -4, -4, -11, -4, -4, -4, -11,
11, -4, -4, 4, -11, -4, 4, -4, -11,
};
private short[] perm;
private short[] permGradIndex3D;
private long seed = -1L;
public SimplexNoise()
{ this(DEFAULT_SEED); }
//Initializes the class using a permutation array generated from a 64-bit seed.
//Generates a proper permutation (i.e. doesn't merely perform N successive pair swaps on a base array)
//Uses a simple 64-bit LCG.
public SimplexNoise(long seed)
{
this.seed = seed;
perm = new short[256];
permGradIndex3D = new short[256];
short[] source = new short[256];
for (short i = 0; i < 256; i++)
source[i] = i;
seed = seed * 6364136223846793005L + 1442695040888963407L;
seed = seed * 6364136223846793005L + 1442695040888963407L;
seed = seed * 6364136223846793005L + 1442695040888963407L;
for (int i = 255; i >= 0; i--)
{
seed = seed * 6364136223846793005L + 1442695040888963407L;
int r = (int) ((seed + 31) % (i + 1));
if (r < 0)
r += (i + 1);
perm[i] = source[r];
permGradIndex3D[i] = (short) ((perm[i] % (gradients3D.length / 3)) * 3);
source[r] = source[i];
}
}
private static int fastFloor(double x)
{
int xi = (int) x;
return x < xi ? xi - 1 : xi;
}
/** Function added to noise by Valoeghese to get seed. */
public long getSeed()
{ return this.seed; }
//2D OpenSimplex Noise.
public double sample(double x, double y)
{
//Place input coordinates onto grid.
double stretchOffset = (x + y) * STRETCH_CONSTANT_2D;
double xs = x + stretchOffset;
double ys = y + stretchOffset;
//Floor to get grid coordinates of rhombus (stretched square) super-cell origin.
int xsb = (int) Math.floor(xs);
int ysb = (int) Math.floor(ys);
//Skew out to get actual coordinates of rhombus origin. We'll need these later.
double squishOffset = (xsb + ysb) * SQUISH_CONSTANT_2D;
double xb = xsb + squishOffset;
double yb = ysb + squishOffset;
//Compute grid coordinates relative to rhombus origin.
double xins = xs - xsb;
double yins = ys - ysb;
//Sum those together to get a value that determines which region we're in.
double inSum = xins + yins;
//Positions relative to origin point.
double dx0 = x - xb;
double dy0 = y - yb;
//We'll be defining these inside the next block and using them afterwards.
double dx_ext, dy_ext;
int xsv_ext, ysv_ext;
double value = 0;
//Contribution (1,0)
double dx1 = dx0 - 1 - SQUISH_CONSTANT_2D;
double dy1 = dy0 - 0 - SQUISH_CONSTANT_2D;
double attn1 = 2 - dx1 * dx1 - dy1 * dy1;
if (attn1 > 0)
{
attn1 *= attn1;
value += attn1 * attn1 * extrapolate(xsb + 1, ysb + 0, dx1, dy1);
}
//Contribution (0,1)
double dx2 = dx0 - 0 - SQUISH_CONSTANT_2D;
double dy2 = dy0 - 1 - SQUISH_CONSTANT_2D;
double attn2 = 2 - dx2 * dx2 - dy2 * dy2;
if (attn2 > 0)
{
attn2 *= attn2;
value += attn2 * attn2 * extrapolate(xsb + 0, ysb + 1, dx2, dy2);
}
if (inSum <= 1)
{ //We're inside the triangle (2-Simplex) at (0,0)
double zins = 1 - inSum;
if (zins > xins || zins > yins)
{ //(0,0) is one of the closest two triangular vertices
if (xins > yins)
{
xsv_ext = xsb + 1;
ysv_ext = ysb - 1;
dx_ext = dx0 - 1;
dy_ext = dy0 + 1;
}
else
{
xsv_ext = xsb - 1;
ysv_ext = ysb + 1;
dx_ext = dx0 + 1;
dy_ext = dy0 - 1;
}
}
else
{ //(1,0) and (0,1) are the closest two vertices.
xsv_ext = xsb + 1;
ysv_ext = ysb + 1;
dx_ext = dx0 - 1 - 2 * SQUISH_CONSTANT_2D;
dy_ext = dy0 - 1 - 2 * SQUISH_CONSTANT_2D;
}
}
else
{ //We're inside the triangle (2-Simplex) at (1,1)
double zins = 2 - inSum;
if (zins < xins || zins < yins)
{ //(0,0) is one of the closest two triangular vertices
if (xins > yins)
{
xsv_ext = xsb + 2;
ysv_ext = ysb + 0;
dx_ext = dx0 - 2 - 2 * SQUISH_CONSTANT_2D;
dy_ext = dy0 + 0 - 2 * SQUISH_CONSTANT_2D;
}
else
{
xsv_ext = xsb + 0;
ysv_ext = ysb + 2;
dx_ext = dx0 + 0 - 2 * SQUISH_CONSTANT_2D;
dy_ext = dy0 - 2 - 2 * SQUISH_CONSTANT_2D;
}
}
else
{ //(1,0) and (0,1) are the closest two vertices.
dx_ext = dx0;
dy_ext = dy0;
xsv_ext = xsb;
ysv_ext = ysb;
}
xsb += 1;
ysb += 1;
dx0 = dx0 - 1 - 2 * SQUISH_CONSTANT_2D;
dy0 = dy0 - 1 - 2 * SQUISH_CONSTANT_2D;
}
//Contribution (0,0) or (1,1)
double attn0 = 2 - dx0 * dx0 - dy0 * dy0;
if (attn0 > 0)
{
attn0 *= attn0;
value += attn0 * attn0 * extrapolate(xsb, ysb, dx0, dy0);
}
//Extra Vertex
double attn_ext = 2 - dx_ext * dx_ext - dy_ext * dy_ext;
if (attn_ext > 0)
{
attn_ext *= attn_ext;
value += attn_ext * attn_ext * extrapolate(xsv_ext, ysv_ext, dx_ext, dy_ext);
}
return value / NORM_CONSTANT_2D;
}
//3D OpenSimplex Noise.
public double sample(double x, double y, double z)
{
//Place input coordinates on simplectic honeycomb.
double stretchOffset = (x + y + z) * STRETCH_CONSTANT_3D;
double xs = x + stretchOffset;
double ys = y + stretchOffset;
double zs = z + stretchOffset;
//Floor to get simplectic honeycomb coordinates of rhombohedron (stretched cube) super-cell origin.
int xsb = fastFloor(xs);
int ysb = fastFloor(ys);
int zsb = fastFloor(zs);
//Skew out to get actual coordinates of rhombohedron origin. We'll need these later.
double squishOffset = (xsb + ysb + zsb) * SQUISH_CONSTANT_3D;
double xb = xsb + squishOffset;
double yb = ysb + squishOffset;
double zb = zsb + squishOffset;
//Compute simplectic honeycomb coordinates relative to rhombohedral origin.
double xins = xs - xsb;
double yins = ys - ysb;
double zins = zs - zsb;
//Sum those together to get a value that determines which region we're in.
double inSum = xins + yins + zins;
//Positions relative to origin point.
double dx0 = x - xb;
double dy0 = y - yb;
double dz0 = z - zb;
//We'll be defining these inside the next block and using them afterwards.
double dx_ext0, dy_ext0, dz_ext0;
double dx_ext1, dy_ext1, dz_ext1;
int xsv_ext0, ysv_ext0, zsv_ext0;
int xsv_ext1, ysv_ext1, zsv_ext1;
double value = 0;
if (inSum <= 1)
{ //We're inside the tetrahedron (3-Simplex) at (0,0,0)
//Determine which two of (0,0,1), (0,1,0), (1,0,0) are closest.
byte aPoint = 0x01;
double aScore = xins;
byte bPoint = 0x02;
double bScore = yins;
if (aScore >= bScore && zins > bScore)
{
bScore = zins;
bPoint = 0x04;
}
else if (aScore < bScore && zins > aScore)
{
aScore = zins;
aPoint = 0x04;
}
//Now we determine the two lattice points not part of the tetrahedron that may contribute.
//This depends on the closest two tetrahedral vertices, including (0,0,0)
double wins = 1 - inSum;
if (wins > aScore || wins > bScore)
{ //(0,0,0) is one of the closest two tetrahedral vertices.
byte c = (bScore > aScore ? bPoint : aPoint); //Our other closest vertex is the closest out of a and b.
if ((c & 0x01) == 0)
{
xsv_ext0 = xsb - 1;
xsv_ext1 = xsb;
dx_ext0 = dx0 + 1;
dx_ext1 = dx0;
}
else
{
xsv_ext0 = xsv_ext1 = xsb + 1;
dx_ext0 = dx_ext1 = dx0 - 1;
}
if ((c & 0x02) == 0)
{
ysv_ext0 = ysv_ext1 = ysb;
dy_ext0 = dy_ext1 = dy0;
if ((c & 0x01) == 0)
{
ysv_ext1 -= 1;
dy_ext1 += 1;
}
else
{
ysv_ext0 -= 1;
dy_ext0 += 1;
}
}
else
{
ysv_ext0 = ysv_ext1 = ysb + 1;
dy_ext0 = dy_ext1 = dy0 - 1;
}
if ((c & 0x04) == 0)
{
zsv_ext0 = zsb;
zsv_ext1 = zsb - 1;
dz_ext0 = dz0;
dz_ext1 = dz0 + 1;
}
else
{
zsv_ext0 = zsv_ext1 = zsb + 1;
dz_ext0 = dz_ext1 = dz0 - 1;
}
}
else
{ //(0,0,0) is not one of the closest two tetrahedral vertices.
byte c = (byte) (aPoint | bPoint); //Our two extra vertices are determined by the closest two.
if ((c & 0x01) == 0)
{
xsv_ext0 = xsb;
xsv_ext1 = xsb - 1;
dx_ext0 = dx0 - 2 * SQUISH_CONSTANT_3D;
dx_ext1 = dx0 + 1 - SQUISH_CONSTANT_3D;
}
else
{
xsv_ext0 = xsv_ext1 = xsb + 1;
dx_ext0 = dx0 - 1 - 2 * SQUISH_CONSTANT_3D;
dx_ext1 = dx0 - 1 - SQUISH_CONSTANT_3D;
}
if ((c & 0x02) == 0)
{
ysv_ext0 = ysb;
ysv_ext1 = ysb - 1;
dy_ext0 = dy0 - 2 * SQUISH_CONSTANT_3D;
dy_ext1 = dy0 + 1 - SQUISH_CONSTANT_3D;
}
else
{
ysv_ext0 = ysv_ext1 = ysb + 1;
dy_ext0 = dy0 - 1 - 2 * SQUISH_CONSTANT_3D;
dy_ext1 = dy0 - 1 - SQUISH_CONSTANT_3D;
}
if ((c & 0x04) == 0)
{
zsv_ext0 = zsb;
zsv_ext1 = zsb - 1;
dz_ext0 = dz0 - 2 * SQUISH_CONSTANT_3D;
dz_ext1 = dz0 + 1 - SQUISH_CONSTANT_3D;
}
else
{
zsv_ext0 = zsv_ext1 = zsb + 1;
dz_ext0 = dz0 - 1 - 2 * SQUISH_CONSTANT_3D;
dz_ext1 = dz0 - 1 - SQUISH_CONSTANT_3D;
}
}
//Contribution (0,0,0)
double attn0 = 2 - dx0 * dx0 - dy0 * dy0 - dz0 * dz0;
if (attn0 > 0)
{
attn0 *= attn0;
value += attn0 * attn0 * extrapolate(xsb + 0, ysb + 0, zsb + 0, dx0, dy0, dz0);
}
//Contribution (1,0,0)
double dx1 = dx0 - 1 - SQUISH_CONSTANT_3D;
double dy1 = dy0 - 0 - SQUISH_CONSTANT_3D;
double dz1 = dz0 - 0 - SQUISH_CONSTANT_3D;
double attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1;
if (attn1 > 0)
{
attn1 *= attn1;
value += attn1 * attn1 * extrapolate(xsb + 1, ysb + 0, zsb + 0, dx1, dy1, dz1);
}
//Contribution (0,1,0)
double dx2 = dx0 - 0 - SQUISH_CONSTANT_3D;
double dy2 = dy0 - 1 - SQUISH_CONSTANT_3D;
double dz2 = dz1;
double attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2;
if (attn2 > 0)
{
attn2 *= attn2;
value += attn2 * attn2 * extrapolate(xsb + 0, ysb + 1, zsb + 0, dx2, dy2, dz2);
}
//Contribution (0,0,1)
double dx3 = dx2;
double dy3 = dy1;
double dz3 = dz0 - 1 - SQUISH_CONSTANT_3D;
double attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3;
if (attn3 > 0)
{
attn3 *= attn3;
value += attn3 * attn3 * extrapolate(xsb + 0, ysb + 0, zsb + 1, dx3, dy3, dz3);
}
}
else if (inSum >= 2)
{ //We're inside the tetrahedron (3-Simplex) at (1,1,1)
//Determine which two tetrahedral vertices are the closest, out of (1,1,0), (1,0,1), (0,1,1) but not (1,1,1).
byte aPoint = 0x06;
double aScore = xins;
byte bPoint = 0x05;
double bScore = yins;
if (aScore <= bScore && zins < bScore)
{
bScore = zins;
bPoint = 0x03;
}
else if (aScore > bScore && zins < aScore)
{
aScore = zins;
aPoint = 0x03;
}
//Now we determine the two lattice points not part of the tetrahedron that may contribute.
//This depends on the closest two tetrahedral vertices, including (1,1,1)
double wins = 3 - inSum;
if (wins < aScore || wins < bScore)
{ //(1,1,1) is one of the closest two tetrahedral vertices.
byte c = (bScore < aScore ? bPoint : aPoint); //Our other closest vertex is the closest out of a and b.
if ((c & 0x01) != 0)
{
xsv_ext0 = xsb + 2;
xsv_ext1 = xsb + 1;
dx_ext0 = dx0 - 2 - 3 * SQUISH_CONSTANT_3D;
dx_ext1 = dx0 - 1 - 3 * SQUISH_CONSTANT_3D;
}
else
{
xsv_ext0 = xsv_ext1 = xsb;
dx_ext0 = dx_ext1 = dx0 - 3 * SQUISH_CONSTANT_3D;
}
if ((c & 0x02) != 0)
{
ysv_ext0 = ysv_ext1 = ysb + 1;
dy_ext0 = dy_ext1 = dy0 - 1 - 3 * SQUISH_CONSTANT_3D;
if ((c & 0x01) != 0)
{
ysv_ext1 += 1;
dy_ext1 -= 1;
}
else
{
ysv_ext0 += 1;
dy_ext0 -= 1;
}
}
else
{
ysv_ext0 = ysv_ext1 = ysb;
dy_ext0 = dy_ext1 = dy0 - 3 * SQUISH_CONSTANT_3D;
}
if ((c & 0x04) != 0)
{
zsv_ext0 = zsb + 1;
zsv_ext1 = zsb + 2;
dz_ext0 = dz0 - 1 - 3 * SQUISH_CONSTANT_3D;
dz_ext1 = dz0 - 2 - 3 * SQUISH_CONSTANT_3D;
}
else
{
zsv_ext0 = zsv_ext1 = zsb;
dz_ext0 = dz_ext1 = dz0 - 3 * SQUISH_CONSTANT_3D;
}
}
else
{ //(1,1,1) is not one of the closest two tetrahedral vertices.
byte c = (byte) (aPoint & bPoint); //Our two extra vertices are determined by the closest two.
if ((c & 0x01) != 0)
{
xsv_ext0 = xsb + 1;
xsv_ext1 = xsb + 2;
dx_ext0 = dx0 - 1 - SQUISH_CONSTANT_3D;
dx_ext1 = dx0 - 2 - 2 * SQUISH_CONSTANT_3D;
}
else
{
xsv_ext0 = xsv_ext1 = xsb;
dx_ext0 = dx0 - SQUISH_CONSTANT_3D;
dx_ext1 = dx0 - 2 * SQUISH_CONSTANT_3D;
}
if ((c & 0x02) != 0)
{
ysv_ext0 = ysb + 1;
ysv_ext1 = ysb + 2;
dy_ext0 = dy0 - 1 - SQUISH_CONSTANT_3D;
dy_ext1 = dy0 - 2 - 2 * SQUISH_CONSTANT_3D;
}
else
{
ysv_ext0 = ysv_ext1 = ysb;
dy_ext0 = dy0 - SQUISH_CONSTANT_3D;
dy_ext1 = dy0 - 2 * SQUISH_CONSTANT_3D;
}
if ((c & 0x04) != 0)
{
zsv_ext0 = zsb + 1;
zsv_ext1 = zsb + 2;
dz_ext0 = dz0 - 1 - SQUISH_CONSTANT_3D;
dz_ext1 = dz0 - 2 - 2 * SQUISH_CONSTANT_3D;
}
else
{
zsv_ext0 = zsv_ext1 = zsb;
dz_ext0 = dz0 - SQUISH_CONSTANT_3D;
dz_ext1 = dz0 - 2 * SQUISH_CONSTANT_3D;
}
}
//Contribution (1,1,0)
double dx3 = dx0 - 1 - 2 * SQUISH_CONSTANT_3D;
double dy3 = dy0 - 1 - 2 * SQUISH_CONSTANT_3D;
double dz3 = dz0 - 0 - 2 * SQUISH_CONSTANT_3D;
double attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3;
if (attn3 > 0)
{
attn3 *= attn3;
value += attn3 * attn3 * extrapolate(xsb + 1, ysb + 1, zsb + 0, dx3, dy3, dz3);
}
//Contribution (1,0,1)
double dx2 = dx3;
double dy2 = dy0 - 0 - 2 * SQUISH_CONSTANT_3D;
double dz2 = dz0 - 1 - 2 * SQUISH_CONSTANT_3D;
double attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2;
if (attn2 > 0)
{
attn2 *= attn2;
value += attn2 * attn2 * extrapolate(xsb + 1, ysb + 0, zsb + 1, dx2, dy2, dz2);
}
//Contribution (0,1,1)
double dx1 = dx0 - 0 - 2 * SQUISH_CONSTANT_3D;
double dy1 = dy3;
double dz1 = dz2;
double attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1;
if (attn1 > 0)
{
attn1 *= attn1;
value += attn1 * attn1 * extrapolate(xsb + 0, ysb + 1, zsb + 1, dx1, dy1, dz1);
}
//Contribution (1,1,1)
dx0 = dx0 - 1 - 3 * SQUISH_CONSTANT_3D;
dy0 = dy0 - 1 - 3 * SQUISH_CONSTANT_3D;
dz0 = dz0 - 1 - 3 * SQUISH_CONSTANT_3D;
double attn0 = 2 - dx0 * dx0 - dy0 * dy0 - dz0 * dz0;
if (attn0 > 0)
{
attn0 *= attn0;
value += attn0 * attn0 * extrapolate(xsb + 1, ysb + 1, zsb + 1, dx0, dy0, dz0);
}
}
else
{ //We're inside the octahedron (Rectified 3-Simplex) in between.
double aScore;
byte aPoint;
boolean aIsFurtherSide;
double bScore;
byte bPoint;
boolean bIsFurtherSide;
//Decide between point (0,0,1) and (1,1,0) as closest
double p1 = xins + yins;
if (p1 > 1)
{
aScore = p1 - 1;
aPoint = 0x03;
aIsFurtherSide = true;
}
else
{
aScore = 1 - p1;
aPoint = 0x04;
aIsFurtherSide = false;
}
//Decide between point (0,1,0) and (1,0,1) as closest
double p2 = xins + zins;
if (p2 > 1)
{
bScore = p2 - 1;
bPoint = 0x05;
bIsFurtherSide = true;
}
else
{
bScore = 1 - p2;
bPoint = 0x02;
bIsFurtherSide = false;
}
//The closest out of the two (1,0,0) and (0,1,1) will replace the furthest out of the two decided above, if closer.
double p3 = yins + zins;
if (p3 > 1)
{
double score = p3 - 1;
if (aScore <= bScore && aScore < score)
{
aScore = score;
aPoint = 0x06;
aIsFurtherSide = true;
}
else if (aScore > bScore && bScore < score)
{
bScore = score;
bPoint = 0x06;
bIsFurtherSide = true;
}
}
else
{
double score = 1 - p3;
if (aScore <= bScore && aScore < score)
{
aScore = score;
aPoint = 0x01;
aIsFurtherSide = false;
}
else if (aScore > bScore && bScore < score)
{
bScore = score;
bPoint = 0x01;
bIsFurtherSide = false;
}
}
//Where each of the two closest points are determines how the extra two vertices are calculated.
if (aIsFurtherSide == bIsFurtherSide)
{
if (aIsFurtherSide)
{ //Both closest points on (1,1,1) side
//One of the two extra points is (1,1,1)
dx_ext0 = dx0 - 1 - 3 * SQUISH_CONSTANT_3D;
dy_ext0 = dy0 - 1 - 3 * SQUISH_CONSTANT_3D;
dz_ext0 = dz0 - 1 - 3 * SQUISH_CONSTANT_3D;
xsv_ext0 = xsb + 1;
ysv_ext0 = ysb + 1;
zsv_ext0 = zsb + 1;
//Other extra point is based on the shared axis.
byte c = (byte) (aPoint & bPoint);
if ((c & 0x01) != 0)
{
dx_ext1 = dx0 - 2 - 2 * SQUISH_CONSTANT_3D;
dy_ext1 = dy0 - 2 * SQUISH_CONSTANT_3D;
dz_ext1 = dz0 - 2 * SQUISH_CONSTANT_3D;
xsv_ext1 = xsb + 2;
ysv_ext1 = ysb;
zsv_ext1 = zsb;
}
else if ((c & 0x02) != 0)
{
dx_ext1 = dx0 - 2 * SQUISH_CONSTANT_3D;
dy_ext1 = dy0 - 2 - 2 * SQUISH_CONSTANT_3D;
dz_ext1 = dz0 - 2 * SQUISH_CONSTANT_3D;
xsv_ext1 = xsb;
ysv_ext1 = ysb + 2;
zsv_ext1 = zsb;
}
else
{
dx_ext1 = dx0 - 2 * SQUISH_CONSTANT_3D;
dy_ext1 = dy0 - 2 * SQUISH_CONSTANT_3D;
dz_ext1 = dz0 - 2 - 2 * SQUISH_CONSTANT_3D;
xsv_ext1 = xsb;
ysv_ext1 = ysb;
zsv_ext1 = zsb + 2;
}
}
else
{//Both closest points on (0,0,0) side
//One of the two extra points is (0,0,0)
dx_ext0 = dx0;
dy_ext0 = dy0;
dz_ext0 = dz0;
xsv_ext0 = xsb;
ysv_ext0 = ysb;
zsv_ext0 = zsb;
//Other extra point is based on the omitted axis.
byte c = (byte) (aPoint | bPoint);
if ((c & 0x01) == 0)
{
dx_ext1 = dx0 + 1 - SQUISH_CONSTANT_3D;
dy_ext1 = dy0 - 1 - SQUISH_CONSTANT_3D;
dz_ext1 = dz0 - 1 - SQUISH_CONSTANT_3D;
xsv_ext1 = xsb - 1;
ysv_ext1 = ysb + 1;
zsv_ext1 = zsb + 1;
}
else if ((c & 0x02) == 0)
{
dx_ext1 = dx0 - 1 - SQUISH_CONSTANT_3D;
dy_ext1 = dy0 + 1 - SQUISH_CONSTANT_3D;
dz_ext1 = dz0 - 1 - SQUISH_CONSTANT_3D;
xsv_ext1 = xsb + 1;
ysv_ext1 = ysb - 1;
zsv_ext1 = zsb + 1;
}
else
{
dx_ext1 = dx0 - 1 - SQUISH_CONSTANT_3D;
dy_ext1 = dy0 - 1 - SQUISH_CONSTANT_3D;
dz_ext1 = dz0 + 1 - SQUISH_CONSTANT_3D;
xsv_ext1 = xsb + 1;
ysv_ext1 = ysb + 1;
zsv_ext1 = zsb - 1;
}
}
}
else
{ //One point on (0,0,0) side, one point on (1,1,1) side
byte c1, c2;
if (aIsFurtherSide)
{
c1 = aPoint;
c2 = bPoint;
}
else
{
c1 = bPoint;
c2 = aPoint;
}
//One contribution is a permutation of (1,1,-1)
if ((c1 & 0x01) == 0)
{
dx_ext0 = dx0 + 1 - SQUISH_CONSTANT_3D;
dy_ext0 = dy0 - 1 - SQUISH_CONSTANT_3D;
dz_ext0 = dz0 - 1 - SQUISH_CONSTANT_3D;
xsv_ext0 = xsb - 1;
ysv_ext0 = ysb + 1;
zsv_ext0 = zsb + 1;
}
else if ((c1 & 0x02) == 0)
{
dx_ext0 = dx0 - 1 - SQUISH_CONSTANT_3D;
dy_ext0 = dy0 + 1 - SQUISH_CONSTANT_3D;
dz_ext0 = dz0 - 1 - SQUISH_CONSTANT_3D;
xsv_ext0 = xsb + 1;
ysv_ext0 = ysb - 1;
zsv_ext0 = zsb + 1;
}
else
{
dx_ext0 = dx0 - 1 - SQUISH_CONSTANT_3D;
dy_ext0 = dy0 - 1 - SQUISH_CONSTANT_3D;
dz_ext0 = dz0 + 1 - SQUISH_CONSTANT_3D;
xsv_ext0 = xsb + 1;
ysv_ext0 = ysb + 1;
zsv_ext0 = zsb - 1;
}
//One contribution is a permutation of (0,0,2)
dx_ext1 = dx0 - 2 * SQUISH_CONSTANT_3D;
dy_ext1 = dy0 - 2 * SQUISH_CONSTANT_3D;
dz_ext1 = dz0 - 2 * SQUISH_CONSTANT_3D;
xsv_ext1 = xsb;
ysv_ext1 = ysb;
zsv_ext1 = zsb;
if ((c2 & 0x01) != 0)
{
dx_ext1 -= 2;
xsv_ext1 += 2;
}
else if ((c2 & 0x02) != 0)
{
dy_ext1 -= 2;
ysv_ext1 += 2;
}
else
{
dz_ext1 -= 2;
zsv_ext1 += 2;
}
}
//Contribution (1,0,0)
double dx1 = dx0 - 1 - SQUISH_CONSTANT_3D;
double dy1 = dy0 - 0 - SQUISH_CONSTANT_3D;
double dz1 = dz0 - 0 - SQUISH_CONSTANT_3D;
double attn1 = 2 - dx1 * dx1 - dy1 * dy1 - dz1 * dz1;
if (attn1 > 0)
{
attn1 *= attn1;
value += attn1 * attn1 * extrapolate(xsb + 1, ysb + 0, zsb + 0, dx1, dy1, dz1);
}
//Contribution (0,1,0)
double dx2 = dx0 - 0 - SQUISH_CONSTANT_3D;
double dy2 = dy0 - 1 - SQUISH_CONSTANT_3D;
double dz2 = dz1;
double attn2 = 2 - dx2 * dx2 - dy2 * dy2 - dz2 * dz2;
if (attn2 > 0)
{
attn2 *= attn2;
value += attn2 * attn2 * extrapolate(xsb + 0, ysb + 1, zsb + 0, dx2, dy2, dz2);
}
//Contribution (0,0,1)
double dx3 = dx2;
double dy3 = dy1;
double dz3 = dz0 - 1 - SQUISH_CONSTANT_3D;
double attn3 = 2 - dx3 * dx3 - dy3 * dy3 - dz3 * dz3;
if (attn3 > 0)
{
attn3 *= attn3;
value += attn3 * attn3 * extrapolate(xsb + 0, ysb + 0, zsb + 1, dx3, dy3, dz3);
}
//Contribution (1,1,0)
double dx4 = dx0 - 1 - 2 * SQUISH_CONSTANT_3D;
double dy4 = dy0 - 1 - 2 * SQUISH_CONSTANT_3D;
double dz4 = dz0 - 0 - 2 * SQUISH_CONSTANT_3D;
double attn4 = 2 - dx4 * dx4 - dy4 * dy4 - dz4 * dz4;
if (attn4 > 0)
{
attn4 *= attn4;
value += attn4 * attn4 * extrapolate(xsb + 1, ysb + 1, zsb + 0, dx4, dy4, dz4);
}
//Contribution (1,0,1)
double dx5 = dx4;
double dy5 = dy0 - 0 - 2 * SQUISH_CONSTANT_3D;
double dz5 = dz0 - 1 - 2 * SQUISH_CONSTANT_3D;
double attn5 = 2 - dx5 * dx5 - dy5 * dy5 - dz5 * dz5;
if (attn5 > 0)
{
attn5 *= attn5;
value += attn5 * attn5 * extrapolate(xsb + 1, ysb + 0, zsb + 1, dx5, dy5, dz5);
}
//Contribution (0,1,1)
double dx6 = dx0 - 0 - 2 * SQUISH_CONSTANT_3D;
double dy6 = dy4;
double dz6 = dz5;
double attn6 = 2 - dx6 * dx6 - dy6 * dy6 - dz6 * dz6;
if (attn6 > 0)
{
attn6 *= attn6;
value += attn6 * attn6 * extrapolate(xsb + 0, ysb + 1, zsb + 1, dx6, dy6, dz6);
}
}
//First extra vertex
double attn_ext0 = 2 - dx_ext0 * dx_ext0 - dy_ext0 * dy_ext0 - dz_ext0 * dz_ext0;
if (attn_ext0 > 0)
{
attn_ext0 *= attn_ext0;
value += attn_ext0 * attn_ext0 * extrapolate(xsv_ext0, ysv_ext0, zsv_ext0, dx_ext0, dy_ext0, dz_ext0);
}
//Second extra vertex
double attn_ext1 = 2 - dx_ext1 * dx_ext1 - dy_ext1 * dy_ext1 - dz_ext1 * dz_ext1;
if (attn_ext1 > 0)
{
attn_ext1 *= attn_ext1;
value += attn_ext1 * attn_ext1 * extrapolate(xsv_ext1, ysv_ext1, zsv_ext1, dx_ext1, dy_ext1, dz_ext1);
}
return value / NORM_CONSTANT_3D;
}
private double extrapolate(int xsb, int ysb, double dx, double dy)
{
int index = perm[(perm[xsb & 0xFF] + ysb) & 0xFF] & 0x0E;
return gradients2D[index] * dx
+ gradients2D[index + 1] * dy;
}
private double extrapolate(int xsb, int ysb, int zsb, double dx, double dy, double dz)
{
int index = permGradIndex3D[(perm[(perm[xsb & 0xFF] + ysb) & 0xFF] + zsb) & 0xFF];
return gradients3D[index] * dx
+ gradients3D[index + 1] * dy
+ gradients3D[index + 2] * dz;
}
}

View File

@ -0,0 +1,10 @@
package com.halotroop.litecraft.world;
import com.halotroop.litecraft.types.block.Block;
public interface BlockAccess
{
Block getBlock(int x, int y, int z);
void setBlock(int x, int y, int z, Block block);
}

View File

@ -0,0 +1,245 @@
package com.halotroop.litecraft.world;
import java.util.*;
import java.util.function.ToIntFunction;
import org.joml.Vector3f;
import com.halotroop.litecraft.logic.SODSerializable;
import com.halotroop.litecraft.render.BlockRenderer;
import com.halotroop.litecraft.types.block.*;
import com.halotroop.litecraft.world.gen.WorldGenConstants;
import it.unimi.dsi.fastutil.ints.*;
import it.unimi.dsi.fastutil.objects.*;
import tk.valoeghese.sod.*;
public class Chunk implements BlockAccess, WorldGenConstants, SODSerializable
{
/** @param x in-chunk x coordinate.
* @param y in-chunk y coordinate.
* @param z in-chunk z coordinate.
* @return creates a long that represents a coordinate, for use as a key in arrays. */
public static int index(int x, int y, int z)
{ return (x & MAX_POS) | ((y & MAX_POS) << POS_SHIFT) | ((z & MAX_POS) << DOUBLE_SHIFT); }
private final Block[] blocks = new Block[CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE];
private BlockInstance[] blockInstances = new BlockInstance[CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE];
private boolean shouldRender = false;
public final int chunkX, chunkY, chunkZ;
public final int chunkStartX, chunkStartY, chunkStartZ;
private boolean fullyGenerated = false;
public final int dimension;
private boolean dirty = true;
/** A holder for the rendered blocks in this chunk. This array is *NOT* safe to use for getting BIs at a position!
* It can vary in size from 0 to 512 elements long and must only be read linearly. */
private BlockInstance[] renderedBlocks = new BlockInstance[CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE];
public Chunk(World world, int chunkX, int chunkY, int chunkZ, int dimension)
{
this.chunkX = chunkX;
this.chunkY = chunkY;
this.chunkZ = chunkZ;
this.chunkStartX = chunkX << POS_SHIFT;
this.chunkStartY = chunkY << POS_SHIFT;
this.chunkStartZ = chunkZ << POS_SHIFT;
this.dimension = dimension;
}
public boolean doRender()
{ return this.shouldRender; }
public void setFullyGenerated(boolean fullyGenerated)
{ this.fullyGenerated = fullyGenerated; }
@Override
public Block getBlock(int x, int y, int z)
{
if (x > CHUNK_SIZE || y > CHUNK_SIZE || z > CHUNK_SIZE || x < 0 || y < 0 || z < 0)
{ throw new RuntimeException("Block [" + x + ", " + y + ", " + z + "] out of chunk bounds!"); }
return blocks[index(x, y, z)];
}
public BlockInstance getBlockInstance(int x, int y, int z)
{
if (x > CHUNK_SIZE || y > CHUNK_SIZE || z > CHUNK_SIZE || x < 0 || y < 0 || z < 0)
{ throw new RuntimeException("BlockInstance [" + x + ", " + y + ", " + z + "] out of chunk bounds!"); }
return this.blockInstances[index(x, y, z)];
}
public void render(BlockRenderer blockRenderer)
{
if (shouldRender)
{
if (dirty)
{
dirty = false;
List<BlockInstance> tempList = new ArrayList<>();
Arrays.fill(renderedBlocks, null);
for (int x = 0; x < CHUNK_SIZE; x++)
for (int y = 0; y < CHUNK_SIZE; y++)
for (int z = 0; z < CHUNK_SIZE; z++)
{
BlockInstance block = getBlockInstance(x, y, z);
// Check for chunk edges to avoid errors when get the neighboring blocks, TODO fix this
if (x == 0 || x == CHUNK_SIZE - 1 || z == 0 || z == CHUNK_SIZE - 1 || y == 0 || y == CHUNK_SIZE - 1)
{
tempList.add(block);
continue;
}
// Check for air. Yes this is stupid, TODO fix this too
try
{
if (getBlockInstance(x - 1, y, z).getModel() == null || getBlockInstance(x + 1, y, z).getModel() == null ||
getBlockInstance(x, y - 1, z).getModel() == null || getBlockInstance(x, y + 1, z).getModel() == null ||
getBlockInstance(x, y, z - 1).getModel() == null || getBlockInstance(x, y, z + 1).getModel() == null)
{ tempList.add(block); }
}
catch (NullPointerException e)
{ // this seems to be a hotspot for errors
e.printStackTrace(); // so I can add a debug breakpoint on this line
throw e; // e
}
}
renderedBlocks = tempList.toArray(BlockInstance[]::new);
}
blockRenderer.prepareRender();
blockRenderer.render(renderedBlocks);
blockRenderer.shader.stop();
}
}
/** Change the block in this exact position
*
* @param x, y, z The coordinate position of block to overwrite
* @param block The block to place there */
@Override
public void setBlock(int x, int y, int z, Block block)
{
// This section makes sure the blocks don't go out of range
if (x > MAX_POS)
x = MAX_POS;
else if (x < 0) x = 0;
if (y > MAX_POS)
y = MAX_POS;
else if (y < 0) y = 0;
if (z > MAX_POS)
z = MAX_POS;
else if (z < 0) z = 0;
//
this.blocks[index(x, y, z)] = block;
if (this.shouldRender) this.blockInstances[index(x, y, z)] = new BlockInstance(block, new Vector3f(this.chunkStartX + x, this.chunkStartY + y, this.chunkStartZ + z));
dirty = true;
}
/** Set whether or not the chunk should render */
public void setRender(boolean render)
{
if (render && !this.shouldRender) // if it has been changed to true
for (int x = 0; x < CHUNK_SIZE; ++x)
for (int y = 0; y < CHUNK_SIZE; ++y)
for (int z = 0; z < CHUNK_SIZE; ++z)
{
Block block = this.blocks[index(x, y, z)];
this.blockInstances[index(x, y, z)] = new BlockInstance(block,
new Vector3f(
this.chunkStartX + x,
this.chunkStartY + y,
this.chunkStartZ + z));
}
else if (!render && this.shouldRender) // else if it has been changed to false.
// we need to check both variables because there are two cases that make
// the if statement fall to here
blockInstances = new BlockInstance[CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE];
this.shouldRender = render;
dirty = true;
}
public boolean isFullyGenerated()
{ return this.fullyGenerated; }
@Override
public void read(BinaryData data)
{
Int2ObjectMap<Block> palette = new Int2ObjectArrayMap<>();
DataSection paletteData = data.get("palette");
boolean readInt = true; // whether the thing from the palette to be read is int
int intIdCache = 0;
//
for (Object o : paletteData)
{
if (readInt)
{
intIdCache = (int) o;
readInt = false;
}
else
{
palette.put(intIdCache, Block.getBlockOrAir((String) o));
readInt = true;
}
}
//
IntArrayDataSection blockData = data.getIntArray("block");
int index = 0;
// Iterate over each block in the chunk
for (int z = 0; z < CHUNK_SIZE; ++z) // z, y, x order for data saving and loading so we can use incremental pos hashes
for (int y = 0; y < CHUNK_SIZE; ++y)
for (int x = 0; x < CHUNK_SIZE; ++x)
{
blocks[index] = palette.get(blockData.readInt(index));
++index;
}
//
DataSection properties = data.get("properties");
try
{
this.fullyGenerated = properties.readBoolean(0); // index 0 is the "fully generated" property
}
catch (Throwable e)
{
if (!readExceptionNotif)
{
System.out.println("An exception occurred reading properties for a chunk! This could be a benign error due to updates to chunk properties.");
readExceptionNotif = true;
}
}
}
private static boolean readExceptionNotif = false;
private int nextId; // for saving
@Override
public void write(BinaryData data)
{
Object2IntMap<Block> palette = new Object2IntArrayMap<>(); // block to int id
DataSection paletteData = new DataSection();
IntArrayDataSection blockData = new IntArrayDataSection();
int index = 0;
nextId = 0;
ToIntFunction<Block> nextIdProvider = b -> nextId++;
//
for (int z = 0; z < CHUNK_SIZE; ++z) // z, y, x order for data saving and loading so we can use incremental pos hashes
for (int y = 0; y < CHUNK_SIZE; ++y)
for (int x = 0; x < CHUNK_SIZE; ++x)
{
Block b = blocks[index];
blockData.writeInt(palette.computeIntIfAbsent(b, nextIdProvider));
++index;
}
//
palette.forEach((b, id) ->
{
paletteData.writeInt(id);
paletteData.writeString(b.identifier);
});
//
data.put("palette", paletteData);
data.put("block", blockData);
//
DataSection properties = new DataSection();
properties.writeBoolean(this.fullyGenerated);
data.put("properties", properties);
dirty = true;
}
}

View File

@ -0,0 +1,253 @@
package com.halotroop.litecraft.world;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.LongConsumer;
import org.joml.Vector3f;
import com.halotroop.litecraft.Litecraft;
import com.halotroop.litecraft.render.BlockRenderer;
import com.halotroop.litecraft.save.LitecraftSave;
import com.halotroop.litecraft.types.block.*;
import com.halotroop.litecraft.types.entity.PlayerEntity;
import com.halotroop.litecraft.world.dimension.Dimension;
import com.halotroop.litecraft.world.gen.*;
import com.halotroop.litecraft.world.gen.modifier.WorldModifier;
import it.unimi.dsi.fastutil.longs.*;
public class World implements BlockAccess, WorldGenConstants
{
Long2ObjectMap<Chunk> chunks;
private final WorldModifier[] worldModifiers;
private final ChunkGenerator chunkGenerator;
private final BlockAccess genBlockAccess;
private final LitecraftSave save;
private final long seed;
private final int dimension;
private final ForkJoinPool threadPool;
public PlayerEntity playerEntity;
int renderBound;
int renderBoundVertical;
// dummy block instance for retrieving the default block model
private final BlockInstance dummy;
public World(long seed, int renderSize, Dimension<?> dim, LitecraftSave save)
{
this.threadPool = new ForkJoinPool(4, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true);
this.dummy = new BlockInstance(Blocks.ANDESITE, new Vector3f(0, 0, 0));
this.dummy.setVisible(false);
this.chunks = new Long2ObjectArrayMap<>();
this.seed = seed;
this.chunkGenerator = dim.createChunkGenerator(seed);
this.worldModifiers = dim.getWorldModifierArray();
// initialize world modifiers with seed
for (WorldModifier modifier : this.worldModifiers)
{ modifier.initialize(seed); }
this.genBlockAccess = new GenerationWorld(this);
this.save = save;
this.dimension = dim.id;
this.renderBound = renderSize / 2;
this.renderBoundVertical = this.renderBound / 2;
if (this.renderBoundVertical < 2)
{ this.renderBoundVertical = 2; }
}
public int findAir(int x, int z)
{
int y = SEA_LEVEL;
int attemptsRemaining = 255;
while (attemptsRemaining-- > 0)
{
// DO NOT CHANGE TO y++
if (this.getBlock(x, ++y, z) == Blocks.AIR)
return y;
}
return -1; // if it fails, returns -1
}
public void spawnPlayer()
{
int y = this.findAir(0, 0);
if (y == -1)
y = 300; // yeet
this.spawnPlayer(0, y, -3);
}
public PlayerEntity spawnPlayer(float x, float y, float z)
{
this.playerEntity = (PlayerEntity) Litecraft.getInstance().player;
this.playerEntity.setVisible(false);
// Generate world around player
long time = System.currentTimeMillis();
System.out.println("Generating world!");
this.updateLoadedChunks(this.playerEntity.getChunkX(), this.playerEntity.getChunkY(), this.playerEntity.getChunkZ());
System.out.println("Generated world in " + (System.currentTimeMillis() - time) + " milliseconds");
// return player
return this.playerEntity;
}
public Chunk getChunk(int chunkX, int chunkY, int chunkZ)
{
Chunk chunk = this.chunks.computeIfAbsent(posHash(chunkX, chunkY, chunkZ), pos ->
{
Chunk readChunk = save.readChunk(this, chunkX, chunkY, chunkZ, this.dimension);
return readChunk == null ? this.chunkGenerator.generateChunk(this, chunkX, chunkY, chunkZ) : readChunk;
});
if (chunk.isFullyGenerated()) return chunk;
this.populateChunk(chunkX, chunkY, chunkZ, chunk.chunkStartX, chunk.chunkStartY, chunk.chunkStartZ);
chunk.setFullyGenerated(true);
return chunk;
}
public Chunk getChunkToLoad(int chunkX, int chunkY, int chunkZ)
{
long posHash = posHash(chunkX, chunkY, chunkZ);
// try get an already loaded chunk
Chunk result = this.chunks.get(posHash);
if (result != null)
return result;
// try read a chunk from memory
result = save.readChunk(this, chunkX, chunkY, chunkZ, this.dimension);
// if neither of those work, generate the chunk
result = result == null ? this.chunkGenerator.generateChunk(this, chunkX, chunkY, chunkZ) : result;
// add chunk to array
this.chunks.put(posHash, result);
return result;
}
/** @return whether the chunk was unloaded without errors. Will often, but not always, be equal to whether the chunk was already in memory. */
boolean unloadChunk(long posHash)
{
Chunk chunk = this.chunks.get(posHash);
// If the chunk is not in memory, it does not need to be unloaded
if (chunk == null) return false;
// Otherwise save the chunk
AtomicBoolean result = new AtomicBoolean(false);
CompletableFuture.runAsync(() ->
{
result.set(this.save.saveChunk(chunk));
this.chunks.remove(posHash);
}, threadPool);
return result.get();
}
void populateChunk(Chunk chunk)
{ this.populateChunk(chunk.chunkX, chunk.chunkY, chunk.chunkZ, chunk.chunkStartX, chunk.chunkStartY, chunk.chunkStartZ); }
private void populateChunk(int chunkX, int chunkY, int chunkZ, int chunkStartX, int chunkStartY, int chunkStartZ)
{
Random rand = new Random(this.seed + 5828671L * chunkX + -47245139L * chunkY + 8972357 * (long) chunkZ);
for (WorldModifier modifier : this.worldModifiers)
{ modifier.modifyWorld(this.genBlockAccess, rand, chunkStartX, chunkStartY, chunkStartZ); }
}
/** @return a chunk that has not neccesarily gone through chunk populating. Used in chunk populating to prevent infinite recursion. */
Chunk getGenChunk(int chunkX, int chunkY, int chunkZ)
{ return this.chunks.computeIfAbsent(posHash(chunkX, chunkY, chunkZ), pos -> this.chunkGenerator.generateChunk(this, chunkX, chunkY, chunkZ)); }
long posHash(int chunkX, int chunkY, int chunkZ)
{ return ((long) chunkX & 0x3FF) | (((long) chunkY & 0x3FF) << 10) | (((long) chunkZ & 0x3FF) << 20); }
@Override
public Block getBlock(int x, int y, int z)
{ return this.getChunk(x >> POS_SHIFT, y >> POS_SHIFT, z >> POS_SHIFT).getBlock(x & MAX_POS, y & MAX_POS, z & MAX_POS); }
@Override
public void setBlock(int x, int y, int z, Block block)
{ this.getChunk(x >> POS_SHIFT, y >> POS_SHIFT, z >> POS_SHIFT).setBlock(x & MAX_POS, y & MAX_POS, z & MAX_POS, block); }
public void optimiseChunks()
{ this.chunks.forEach((pos, chunk) -> optimiseChunk(chunk)); }
//used for model combining and culling
public Chunk optimiseChunk(Chunk chunk)
{ return chunk; }
public void render(BlockRenderer blockRenderer)
{
blockRenderer.prepareModel(this.dummy.getModel());
this.chunks.forEach((pos, c) ->
{
if (c != null && c.isFullyGenerated())
c.render(blockRenderer);
});
blockRenderer.unbindModel();
}
public void unloadAllChunks()
{
LongList chunkPositions = new LongArrayList();
List<CompletableFuture<Void>> futures = new ArrayList<>();
if (this.chunks != null)
{
this.chunks.forEach((pos, chunk) ->
{ // for every chunk in memory
futures.add(CompletableFuture.runAsync(() ->
{
chunkPositions.add((long) pos); // add pos to chunk positions list for removal later
this.save.saveChunk(chunk); // save chunk
}, threadPool));
});
}
futures.forEach(CompletableFuture::join);
chunkPositions.forEach((LongConsumer) (pos -> this.chunks.remove(pos))); // remove all chunks
}
public long getSeed()
{ return this.seed; }
public static final int SEA_LEVEL = 0;
public void updateLoadedChunks(int chunkX, int chunkY, int chunkZ)
{
CompletableFuture.runAsync(() ->
{
List<Chunk> toKeep = new ArrayList<>();
// loop over rendered area, adding chunks that are needed
for (int x = chunkX - this.renderBound; x < chunkX + this.renderBound; x++)
for (int z = chunkZ - this.renderBound; z < chunkZ + this.renderBound; z++)
for (int y = chunkY - this.renderBound; y < chunkY + this.renderBound; y++)
toKeep.add(this.getChunkToLoad(x, y, z));
LongList toRemove = new LongArrayList();
// check which loaded chunks are not neccesary
chunks.forEach((pos, chunk) ->
{
if (!toKeep.contains(chunk))
toRemove.add((long) pos);
});
// unload unneccesary chunks from chunk array
toRemove.forEach((LongConsumer) this::unloadChunk);
toKeep.forEach(chunk ->
{
if (!chunk.isFullyGenerated())
{
this.populateChunk(chunk);
chunk.setFullyGenerated(true);
}
boolean alreadyRendering = chunk.doRender(); // if it's already rendering then it's most likely in the map
chunk.setRender(true);
if (!alreadyRendering)
chunks.put(this.posHash(chunk.chunkX, chunk.chunkY, chunk.chunkZ), chunk);
});
}, threadPool);
}
private static final class GenerationWorld implements BlockAccess, WorldGenConstants
{
GenerationWorld(World parent)
{ this.parent = parent; }
public final World parent;
@Override
public Block getBlock(int x, int y, int z)
{ return this.parent.getGenChunk(x >> POS_SHIFT, y >> POS_SHIFT, z >> POS_SHIFT).getBlock(x & MAX_POS, y & MAX_POS, z & MAX_POS); }
@Override
public void setBlock(int x, int y, int z, Block block)
{ this.parent.getGenChunk(x >> POS_SHIFT, y >> POS_SHIFT, z >> POS_SHIFT).setBlock(x & MAX_POS, y & MAX_POS, z & MAX_POS, block); }
}
}

View File

@ -0,0 +1,38 @@
package com.halotroop.litecraft.world.dimension;
import java.util.*;
import com.halotroop.litecraft.world.gen.ChunkGenerator;
import com.halotroop.litecraft.world.gen.modifier.WorldModifier;
import it.unimi.dsi.fastutil.ints.*;
public abstract class Dimension<T extends ChunkGenerator>
{
public List<WorldModifier> worldModifiers = new ArrayList<>();
public final int id;
public final String saveIdentifier;
public Dimension(int id, String saveIdentifier)
{
this.id = id;
this.saveIdentifier = saveIdentifier;
ID_TO_DIMENSION.put(id, this);
}
public Dimension<T> addWorldModifier(WorldModifier modifier)
{
this.worldModifiers.add(modifier);
return this;
}
public WorldModifier[] getWorldModifierArray()
{ return this.worldModifiers.toArray(new WorldModifier[0]); }
public abstract T createChunkGenerator(long seed);
public static Dimension<?> getById(int id)
{ return ID_TO_DIMENSION.get(id); }
private static final Int2ObjectMap<Dimension<?>> ID_TO_DIMENSION = new Int2ObjectArrayMap<>();
}

View File

@ -0,0 +1,9 @@
package com.halotroop.litecraft.world.dimension;
import com.halotroop.litecraft.world.gen.EarthChunkGenerator;
import com.halotroop.litecraft.world.gen.modifier.CavesModifier;
public final class Dimensions
{
public static final Dimension<EarthChunkGenerator> OVERWORLD = new EarthDimension(0, "earth").addWorldModifier(new CavesModifier());
}

View File

@ -0,0 +1,13 @@
package com.halotroop.litecraft.world.dimension;
import com.halotroop.litecraft.world.gen.EarthChunkGenerator;
class EarthDimension extends Dimension<EarthChunkGenerator>
{
public EarthDimension(int id, String saveIdentifier)
{ super(id, saveIdentifier); }
@Override
public EarthChunkGenerator createChunkGenerator(long seed)
{ return new EarthChunkGenerator(seed, this.id); }
}

View File

@ -0,0 +1,8 @@
package com.halotroop.litecraft.world.gen;
import com.halotroop.litecraft.world.*;
public interface ChunkGenerator
{
Chunk generateChunk(World world, int chunkX, int chunkY, int chunkZ);
}

View File

@ -0,0 +1,71 @@
package com.halotroop.litecraft.world.gen;
import java.util.Random;
import com.halotroop.litecraft.types.block.*;
import com.halotroop.litecraft.util.noise.OctaveSimplexNoise;
import com.halotroop.litecraft.world.*;
public class EarthChunkGenerator implements ChunkGenerator, WorldGenConstants
{
public EarthChunkGenerator(long seed, int dimension)
{
Random rand = new Random(seed);
this.noise = new OctaveSimplexNoise(rand, 3, 250.0, 50.0, 18.0);
this.stoneNoise = new OctaveSimplexNoise(rand, 1);
this.dimension = dimension;
}
private final OctaveSimplexNoise noise;
private final OctaveSimplexNoise stoneNoise;
private final int dimension;
@Override
public Chunk generateChunk(World world, int chunkX, int chunkY, int chunkZ)
{
Chunk chunk = new Chunk(world, chunkX, chunkY, chunkZ, this.dimension);
for (int x = 0; x < CHUNK_SIZE; x++)
{
double totalX = x + chunk.chunkStartX;
for (int z = 0; z < CHUNK_SIZE; z++)
{
double totalZ = chunk.chunkStartZ + z;
int height = (int) this.noise.sample(totalX, totalZ);
for (int y = 0; y < CHUNK_SIZE; y++)
{
double rockNoise = this.stoneNoise.sample(totalX / 160.0, (chunk.chunkStartY + y) / 50.0, totalZ / 160.0);
int totalY = chunk.chunkStartY + y;
Block block = Blocks.AIR;
if (totalY < height - 4)
block = pickStone(rockNoise);
else if (totalY < height - 1)
block = Blocks.DIRT;
else if (totalY < height)
block = Blocks.GRASS;
chunk.setBlock(x, y, z, block);
}
}
}
return chunk;
}
private static Block pickStone(double rockNoise)
{
if (rockNoise < -0.25)
{
return Blocks.ANDESITE;
}
else if (rockNoise < 0)
{
return Blocks.DIORITE;
}
else if (rockNoise < 0.25)
{
return Blocks.GNEISS;
}
else
{
return Blocks.GRANITE;
}
}
}

View File

@ -0,0 +1,9 @@
package com.halotroop.litecraft.world.gen;
public interface WorldGenConstants
{
int POS_SHIFT = 4;
int DOUBLE_SHIFT = POS_SHIFT * 2;
int CHUNK_SIZE = (int) Math.pow(2, POS_SHIFT);
int MAX_POS = CHUNK_SIZE - 1;
}

View File

@ -0,0 +1,103 @@
package com.halotroop.litecraft.world.gen.modifier;
import java.util.Random;
import com.halotroop.litecraft.types.block.Blocks;
import com.halotroop.litecraft.util.noise.OctaveSimplexNoise;
import com.halotroop.litecraft.world.BlockAccess;
import com.halotroop.litecraft.world.gen.WorldGenConstants;
public class CavesModifier implements WorldModifier, WorldGenConstants
{
private OctaveSimplexNoise caveNoise;
@Override
public void initialize(long seed)
{
Random rand = new Random(seed);
this.caveNoise = new OctaveSimplexNoise(rand, 2, 65.0, 1.0, 1.0);
}
@Override
public void modifyWorld(BlockAccess world, Random rand, int chunkStartX, int chunkStartY, int chunkStartZ)
{
final int subChunks = CHUNK_SIZE >> 2; // in 4x4x4 blocks
for (int subChunkX = 0; subChunkX < subChunks; subChunkX++)
{
int scOffsetX = subChunkX << 2; // sub chunk offset x
int scTotalX = scOffsetX + chunkStartX;
for (int subChunkZ = 0; subChunkZ < subChunks; subChunkZ++)
{
int scOffsetZ = subChunkZ << 2; // sub chunk offset z
int scTotalZ = scOffsetZ + chunkStartZ;
for (int subChunkY = 0; subChunkY < subChunks; subChunkY++)
{
int scOffsetY = subChunkY << 2; // sub chunk offset y
int scTotalY = scOffsetY + chunkStartY;
double scSampleY = scTotalY * 1.5; // squish caves along y axis a bit
double scUpperYOffset = 4.0 * 1.5;
// calculate noise at each corner of the cube [lower|upper][south|north][west|east]
double noiseLSW = this.caveNoise.sample(scTotalX, scSampleY, scTotalZ); // base = lower south west
double noiseUSW = this.caveNoise.sample(scTotalX, scSampleY + scUpperYOffset, scTotalZ);
double noiseLNW = this.caveNoise.sample(scTotalX, scSampleY, scTotalZ + 4);
double noiseUNW = this.caveNoise.sample(scTotalX, scSampleY + scUpperYOffset, scTotalZ + 4);
double noiseLSE = this.caveNoise.sample(scTotalX + 4, scSampleY, scTotalZ);
double noiseUSE = this.caveNoise.sample(scTotalX + 4, scSampleY + scUpperYOffset, scTotalZ);
double noiseLNE = this.caveNoise.sample(scTotalX + 4, scSampleY, scTotalZ + 4);
double noiseUNE = this.caveNoise.sample(scTotalX + 4, scSampleY + scUpperYOffset, scTotalZ + 4);
// calculate y lerp progresses
// lerp = low + progress * (high - low)
double ypSW = 0.25 * (noiseUSW - noiseLSW);
double ypNW = 0.25 * (noiseUNW - noiseLNW);
double ypSE = 0.25 * (noiseUSE - noiseLSE);
double ypNE = 0.25 * (noiseUNE - noiseLNE);
// initial Y noises
double ySW = noiseLSW;
double ySE = noiseLSE;
double yNW = noiseLNW;
double yNE = noiseLNE;
// loop over y, adding the progress each time
for (int subY = 0; subY < 4; ++subY)
{
int totalY = subY + scTotalY;
// calculate z lerp progresses
double zpW = 0.25 * (yNW - ySW);
double zpE = 0.25 * (yNE - ySE);
// initial Z noises
double zW = ySW;
double zE = ySE;
// loop over z, adding the progress each time
for (int subZ = 0; subZ < 4; ++subZ)
{
int totalZ = subZ + scTotalZ;
// calculate x lerp progress
double lerpProg = 0.25 * (zE - zW);
// initial x noise
double lerpNoise = zW;
// loop over x, adding the progress each time
for (int subX = 0; subX < 4; ++subX)
{
int totalX = subX + scTotalX;
// calculate whether to replace block with air
// if the noise is within the threshold for that block for caves
float threshold = world.getBlock(totalX, totalY, totalZ).getCaveCarveThreshold();
if (-threshold < lerpNoise && lerpNoise < threshold)
{ world.setBlock(totalX, totalY, totalZ, Blocks.AIR); }
// add progress to the noise
lerpNoise += lerpProg;
}
// add z progresses
zW += zpW;
zE += zpE;
}
// add y progresses
ySW += ypSW;
ySE += ypSE;
yNW += ypNW;
yNE += ypNE;
}
}
}
}
}
}

View File

@ -0,0 +1,12 @@
package com.halotroop.litecraft.world.gen.modifier;
import java.util.Random;
import com.halotroop.litecraft.world.BlockAccess;
public interface WorldModifier
{
void modifyWorld(BlockAccess world, Random rand, int chunkStartX, int chunkStartY, int chunkStartZ);
void initialize(long seed);
}

BIN
src/main/resources/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,6 @@
# Made in Blockbench 3.3.1
newmtl 0
map_Kd textures/blocks/cubes/wood/planks/planks_oak.png
newmtl 1
map_Kd textures/blocks/cubes/wood/logs/side/log_oak.png
newmtl none

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +0,0 @@
# Blender v2.79 (sub 0) OBJ File: 'very good grass.blend'
# www.blender.org
o Plane
v 0.000000 1.963634 1.000000
v -0.000000 -0.036366 1.000000
v 0.000000 1.963634 -1.000000
v -0.000000 -0.036366 -1.000000
v -0.978509 1.963634 0.206204
v -0.978509 -0.036366 0.206204
v 0.978509 1.963634 -0.206204
v 0.978509 -0.036366 -0.206204
vt 0.000977 -0.001953
vt 1.000000 1.000000
vt 0.000000 1.000000
vt 0.997070 0.001953
vt -0.001953 0.998047
vt 0.998047 0.000000
vt 0.998047 0.997070
vt 0.003907 -0.002930
vn 1.0000 -0.0000 0.0000
vn 0.2062 -0.0000 0.9785
s off
f 2/1/1 3/2/1 1/3/1
f 2/1/1 4/4/1 3/2/1
f 5/5/2 8/6/2 7/7/2
f 5/5/2 6/8/2 8/6/2

File diff suppressed because it is too large Load Diff

View File

@ -24,4 +24,6 @@ void main(void){
// calculate brightness
out_Colour.rgb *= brightness;
}

View File

@ -17,6 +17,8 @@ uniform vec3 skyColour;
void main(void){
float brightness = 3;
vec3 unitNormal = normalize(surfaceNormal);
vec3 unitVectorToCamera = normalize(toCameraVector);
@ -46,5 +48,6 @@ void main(void){
out_Color = vec4(totalDiffuse, 1.0) * textureColour + vec4(totalSpecular, 1.0);
out_Color = mix(vec4(skyColour, 1.0), out_Color, visibility);
out_Color = vec4(out_Color.r*brightness, out_Color.g*brightness, out_Color.b*brightness, out_Color.a);
}

View File

@ -20,8 +20,8 @@ const vec4 plane = vec4(0, -1, 0, 15);
uniform float useFakeLighting;
const float density = 0.01;
const float gradient = 5.0;
const float density = 0.0025;
const float gradient = 10.0;
void main(void){
@ -35,9 +35,7 @@ void main(void){
pass_textureCoords = textureCoords;
vec3 actualNormal = normal;
if(useFakeLighting > 0.5){
actualNormal = vec3(0.0, 1.0, 0.0);
}
actualNormal = vec3(0.0, 1.0, 0.0);
surfaceNormal = (transformationMatrix * vec4(actualNormal, 0.0)).xyz;
for(int i=0;i<5;i++){

View File

@ -7,8 +7,8 @@ out vec4 out_colour;
uniform vec3 colour;
uniform sampler2D fontAtlas;
const float width = 0.5;
const float edge = 0.1;
const float width = 0;
const float edge = 1.0;
uniform float borderWidth;
uniform float borderEdge;

View File

@ -9,7 +9,7 @@ uniform vec2 translation;
void main(void){
gl_Position = vec4(position, 0.0, 1.0);
gl_Position = vec4(position + translation, 0.0, 1.0);
pass_textureCoords = textureCoords;
}

View File

@ -8,9 +8,9 @@ uniform sampler2D modelTexture;
void main(void){
float alpha = texture(modelTexture, textureCoords).a;
if(alpha < 0.5){
if(alpha < 0.4){
discard;
}
out_Colour = vec4(1.0);
out_Colour = vec4(1.0, 1.0, 1.0, 0.1);
}

View File

@ -1,80 +0,0 @@
& Knuckles
0% Dairy
0% crackers
2+2=10 in base-4!
4bitsinabyte!
99
Absolutely no mixins!
Also try 7 Days to Die!
Also try CastleMiner Z!
Also try Miner Dig Deep... oh wait
Also try Terraria!
Also try Total Miner Forge!
Alt-F4!
Are dimensions even real?
Are you feeling lucky punk?
Battle Royale!
Better without Kinect sensor!
CM != MC
California thinks it causes cancer!
Can't pirate what's free!
Conservatives not allowed!
Could not connect to PSN!
Ctrl-Alt-Delete!
Deluxe Edition
Don't forget to vote!
Don't punch trees!
Don't stay in school.
Drink! Drink! Drink!
Easy-to-use!
Episode 3
Featuring Dante from the Devil May Cry Series!
Forget the coremods!
Fully 2D!
Go the fuck to sleep.
Happy birthday!
HeartGold
Horse Armour at no extra cost!
Howling at the moon!
I can't believe it's not Minecraft!
I mean for fucks sake, it's [current year]!
Innuendo abound!
Jam it up your pee hole!
Java Edition
Keep playing, or else!
LOL SO RANDOM!
Many of a kind!
Mega-dick: ACTIVATE!
Absolutely no mods!
Modular!
New Funky Mode!
Not available on Xbox!
Not for kids!
Not rated by PEGI
Not rated by the ESRB
Not safe for work!
Now or never!
On Linux AND PC!
Open-source!
Please try again!
Pull request!
Slap my nuts and call me grandma!
SoulSilver
Splashy fun!
Starfish really loves you!
Start-up complete!
The first of its kind!
They took my freaking kidney!
This is the end, friend.
Too many splashes?
Try turning it off and back on again!
U
Use at your own risk!
Vegan-friendly!
WTFPL
Watch out for dragons!
We don't need no education.
What was that?
Who's been drawing dicks?
With extra dip!
and a large soda.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 625 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 786 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 698 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 810 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 763 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 769 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 857 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 794 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 795 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 859 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 780 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 765 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 850 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 792 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 584 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 557 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 590 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 411 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 631 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 412 B

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