diff --git a/src/mightypork/gamecore/render/Render.java b/src/mightypork/gamecore/render/Render.java index a632efb..9ca8354 100644 --- a/src/mightypork/gamecore/render/Render.java +++ b/src/mightypork/gamecore/render/Render.java @@ -295,6 +295,7 @@ public class Render { * Load texture * * @param resourcePath + * @param filtering filtering mode to use while loading. * @return the loaded texture */ public synchronized static Texture loadTexture(String resourcePath, FilterMode filtering) diff --git a/src/mightypork/rogue/App.java b/src/mightypork/rogue/App.java index 2408cbe..c1f4df8 100644 --- a/src/mightypork/rogue/App.java +++ b/src/mightypork/rogue/App.java @@ -6,7 +6,6 @@ import java.util.Locale; import mightypork.gamecore.control.BaseApp; import mightypork.gamecore.control.GameLoop; -import mightypork.gamecore.control.events.ScreenRequestEvent; import mightypork.gamecore.gui.screens.ScreenRegistry; import mightypork.gamecore.input.InputSystem; import mightypork.gamecore.input.KeyStroke; @@ -23,8 +22,11 @@ import mightypork.rogue.screens.main_menu.ScreenMainMenu; import mightypork.rogue.screens.test_bouncyboxes.ScreenTestBouncy; import mightypork.rogue.screens.test_cat_sound.ScreenTestCat; import mightypork.rogue.screens.test_render.ScreenTestRender; +import mightypork.rogue.world.item.Item; +import mightypork.rogue.world.tile.Tile; import mightypork.util.control.eventbus.EventBus; import mightypork.util.control.eventbus.events.Event; +import mightypork.util.files.ion.Ion; import mightypork.util.logging.Log; import mightypork.util.logging.writers.LogWriter; @@ -34,7 +36,7 @@ import mightypork.util.logging.writers.LogWriter; * * @author MightyPork */ -public class App extends BaseApp { +public final class App extends BaseApp { /** * Launcher @@ -100,6 +102,13 @@ public class App extends BaseApp { } + @Override + protected void preInit() + { + Ion.registerIonizable(Tile.ION_MARK, Tile.class); + Ion.registerIonizable(Item.ION_MARK, Item.class); + } + @Override protected File getLockFile() { diff --git a/src/mightypork/rogue/Config.java b/src/mightypork/rogue/Config.java index 132184b..e6d7385 100644 --- a/src/mightypork/rogue/Config.java +++ b/src/mightypork/rogue/Config.java @@ -10,7 +10,7 @@ import mightypork.util.logging.Log; * * @author MightyPork */ -public class Config { +public final class Config { private static PropertyManager mgr; diff --git a/src/mightypork/rogue/Const.java b/src/mightypork/rogue/Const.java index 2fb37b2..1fc5ec9 100644 --- a/src/mightypork/rogue/Const.java +++ b/src/mightypork/rogue/Const.java @@ -6,7 +6,7 @@ package mightypork.rogue; * * @author MightyPork */ -public class Const { +public final class Const { // STRINGS public static final int VERSION = 1; diff --git a/src/mightypork/rogue/MainLoop.java b/src/mightypork/rogue/MainLoop.java index 7feefea..7132439 100644 --- a/src/mightypork/rogue/MainLoop.java +++ b/src/mightypork/rogue/MainLoop.java @@ -17,7 +17,7 @@ import mightypork.util.control.Action; import mightypork.util.logging.Log; -public class MainLoop extends GameLoop implements ActionRequest.Listener { +public final class MainLoop extends GameLoop implements ActionRequest.Listener { public MainLoop(BaseApp app) { super(app); diff --git a/src/mightypork/rogue/Paths.java b/src/mightypork/rogue/Paths.java index ac037a4..605b5e0 100644 --- a/src/mightypork/rogue/Paths.java +++ b/src/mightypork/rogue/Paths.java @@ -6,7 +6,7 @@ import java.io.File; import mightypork.util.files.OsUtils; -public class Paths { +public final class Paths { private static final String APPDIR_NAME = "rogue"; diff --git a/src/mightypork/rogue/Res.java b/src/mightypork/rogue/Res.java index 2b443b7..39b6d6a 100644 --- a/src/mightypork/rogue/Res.java +++ b/src/mightypork/rogue/Res.java @@ -25,7 +25,7 @@ import org.newdawn.slick.opengl.Texture; * * @author MightyPork */ -public class Res { +public final class Res { private static TextureBank textures; private static SoundBank sounds; diff --git a/src/mightypork/rogue/util/Utils.java b/src/mightypork/rogue/util/Utils.java index 3be0db4..5244890 100644 --- a/src/mightypork/rogue/util/Utils.java +++ b/src/mightypork/rogue/util/Utils.java @@ -6,7 +6,7 @@ package mightypork.rogue.util; * * @author MightyPork */ -public class Utils { +public final class Utils { public static Thread runAsThread(Runnable r) { diff --git a/src/mightypork/rogue/world/Entity.java b/src/mightypork/rogue/world/Entity.java new file mode 100644 index 0000000..6e6ac55 --- /dev/null +++ b/src/mightypork/rogue/world/Entity.java @@ -0,0 +1,121 @@ +package mightypork.rogue.world; + + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import mightypork.util.constraints.rect.proxy.RectBound; +import mightypork.util.control.timing.Updateable; +import mightypork.util.files.ion.Ion; +import mightypork.util.files.ion.Ionizable; + + +/** + * Abstract entity + * + * @author MightyPork + * @param Data object class + * @param Model class + * @param Render context class + */ +public abstract class Entity, R extends RectBound> implements Ionizable, Updateable { + + protected M model; + protected D data; + + + /** + * Used by Ion for loading. + */ + public Entity() { + } + + + /** + * Create from model + * + * @param model model + */ + public Entity(M model) { + setModel(model); + } + + + @Override + public final void loadFrom(InputStream in) throws IOException + { + final int id = Ion.readInt(in); + setModel(id); + model.load(data, in); // load saved data + } + + + private void initData() + { + data = model.createData(); + } + + + /** + * @return entity model + */ + public final M getModel() + { + return model; + } + + + /** + * Assign a model. + * + * @param id model id + */ + public final void setModel(int id) + { + setModel(getModelForId(id)); + } + + + /** + * Assign a model. + * + * @param model model + */ + public final void setModel(M model) + { + this.model = model; + initData(); + } + + + @Override + public final void saveTo(OutputStream out) throws IOException + { + Ion.writeInt(out, model.getId()); + model.save(data, out); + } + + + public void render(R context) + { + model.render(data, context); + } + + + @Override + public void update(double delta) + { + model.update(data, delta); + } + + + /** + * Get model for ID + * + * @param id id + * @return model for the ID + */ + protected abstract M getModelForId(int id); + +} diff --git a/src/mightypork/rogue/world/EntityModel.java b/src/mightypork/rogue/world/EntityModel.java new file mode 100644 index 0000000..b7ac5f9 --- /dev/null +++ b/src/mightypork/rogue/world/EntityModel.java @@ -0,0 +1,92 @@ +package mightypork.rogue.world; + + +import java.io.InputStream; +import java.io.OutputStream; + +import mightypork.util.annotations.DefaultImpl; +import mightypork.util.constraints.rect.proxy.RectBound; + + +/** + * Entity model. Provides concrete implementation to an entity, working with + * it's data object. + * + * @author MightyPork + * @param Data object class + * @param Render context class + */ +public abstract class EntityModel { + + /** Model id */ + private final int id; + + + /** + * Create a model. The caller must then register this instance in a Model + * registry for the particular entity type. + * + * @param id model id + */ + public EntityModel(int id) { + this.id = id; + } + + + /** + * Get the model id. + * + * @return id + */ + public final int getId() + { + return id; + } + + + /** + * Create a data object and populate it with default values. + * + * @return data object + */ + public abstract D createData(); + + + /** + * Load an entity from ION input stream. + * + * @param data data to load + * @param in input stream + */ + public abstract void load(D data, InputStream in); + + + /** + * Save an entity to ION output stream. + * + * @param data data to save + * @param out output stream + */ + @DefaultImpl + public abstract void save(D data, OutputStream out); + + + /** + * Render the item according to given context. + * + * @param data rendered item + * @param context rendering context + */ + public abstract void render(D data, R context); + + + /** + * Update the item (animation, decay etc) + * + * @param item item to update + * @param delta delta time + */ + @DefaultImpl + public abstract void update(D item, double delta); + +} diff --git a/src/mightypork/rogue/world/ItemData.java b/src/mightypork/rogue/world/ItemData.java deleted file mode 100644 index 812b55d..0000000 --- a/src/mightypork/rogue/world/ItemData.java +++ /dev/null @@ -1,89 +0,0 @@ -package mightypork.rogue.world; - - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import mightypork.util.constraints.rect.proxy.RectBound; -import mightypork.util.control.timing.Updateable; -import mightypork.util.files.ion.BinaryUtils; -import mightypork.util.files.ion.Ionizable; - - -public class ItemData implements Ionizable, Updateable { - - public static final short ION_MARK = 701; - - private Model model; - - // data fields for models to use - public Object data; - public boolean[] flags; - public int[] ints; - - - /** - * Create from model id - * - * @param id model id - */ - public ItemData(int id) { - this(Items.get(id)); - } - - - /** - * Create from model - * - * @param model model - */ - public ItemData(Model model) { - this.model = model; - model.create(this); - } - - - /** - * Create without model. Model will be read from ION input stream. - */ - public ItemData() { - } - - - @Override - public void loadFrom(InputStream in) throws IOException - { - final int id = BinaryUtils.readInt(in); - model = Items.get(id); - model.load(this, in); - } - - - @Override - public void saveTo(OutputStream out) throws IOException - { - BinaryUtils.writeInt(out, model.getId()); - model.save(this, out); - } - - - @Override - public short getIonMark() - { - return ION_MARK; - } - - - public void render(RectBound context) - { - model.render(this, context); - } - - - @Override - public void update(double delta) - { - model.update(this, delta); - } -} diff --git a/src/mightypork/rogue/world/ItemModel.java b/src/mightypork/rogue/world/ItemModel.java deleted file mode 100644 index 81f85e5..0000000 --- a/src/mightypork/rogue/world/ItemModel.java +++ /dev/null @@ -1,84 +0,0 @@ -package mightypork.rogue.world; - - -import java.io.InputStream; -import java.io.OutputStream; - -import mightypork.util.annotations.DefaultImpl; -import mightypork.util.constraints.rect.proxy.RectBound; - - -/** - * An item model - * - * @author MightyPork - */ -public abstract class ItemModel implements Model { - - public final int id; - - - public ItemModel(int id) { - this.id = id; - Items.register(id, this); - } - - - @Override - public final int getId() - { - return id; - } - - - @Override - @DefaultImpl - public void create(ItemData item) - { - } - - - /** - * On search performed (reveal hidden door etc) - * - * @param item item in world - */ - @DefaultImpl - public void search(TileData item) - { - } - - - /** - * Check if an entity can walk this item. If the item is not potentially - * walkable, then this method must always return false. - * - * @param item item in world - */ - public abstract void isWalkable(TileData item); - - - @Override - @DefaultImpl - public void load(ItemData item, InputStream in) - { - } - - - @Override - @DefaultImpl - public void save(ItemData item, OutputStream out) - { - } - - - @Override - public abstract void render(ItemData item, RectBound context); - - - @Override - @DefaultImpl - public void update(ItemData item, double delta) - { - } -} diff --git a/src/mightypork/rogue/world/Model.java b/src/mightypork/rogue/world/Model.java deleted file mode 100644 index 27a43c4..0000000 --- a/src/mightypork/rogue/world/Model.java +++ /dev/null @@ -1,63 +0,0 @@ -package mightypork.rogue.world; - - -import java.io.InputStream; -import java.io.OutputStream; - -import mightypork.util.constraints.rect.proxy.RectBound; - - -public interface Model { - - /** - * Get the id. - * - * @return id - */ - int getId(); - - - /** - * Populate an entity with data for this model - * - * @param entity entity in world - */ - void create(DATA entity); - - - /** - * Load entity data from a binary stream. - * - * @param entity item to load - * @param in input stream - */ - void load(DATA entity, InputStream in); - - - /** - * Save entity data to a binary stream. - * - * @param entity entity to save - * @param out output stream - */ - void save(DATA entity, OutputStream out); - - - /** - * Render according to given context. - * - * @param entity data object - * @param context rendering context - */ - void render(DATA entity, RCTX context); - - - /** - * Update the entity (animation, decay etc) - * - * @param entity data object - * @param delta delta time - */ - void update(DATA entity, double delta); - -} diff --git a/src/mightypork/rogue/world/TileData.java b/src/mightypork/rogue/world/TileData.java deleted file mode 100644 index 3e5329a..0000000 --- a/src/mightypork/rogue/world/TileData.java +++ /dev/null @@ -1,102 +0,0 @@ -package mightypork.rogue.world; - - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Stack; - -import mightypork.util.control.timing.Updateable; -import mightypork.util.files.ion.BinaryUtils; -import mightypork.util.files.ion.Ionizable; - - -/** - * Concrete tile in the world. - * - * @author MightyPork - */ -public class TileData implements Ionizable, Updateable { - - public static final short ION_MARK = 700; - - /** Items dropped onto this tile */ - public final Stack items = new Stack<>(); - - /** Whether the tile is occupied by an entity */ - public boolean occupied; - - private TileModel model; - - // data fields for models to use - public Object data; - public boolean[] flags; - public int[] ints; - - - /** - * Create from model id - * - * @param id model id - */ - public TileData(int id) { - this(Tiles.get(id)); - } - - - /** - * Create from model - * - * @param model model - */ - public TileData(TileModel model) { - this.model = model; - model.create(this); - } - - - /** - * Create without model. Model will be read from ION input stream. - */ - public TileData() { - } - - - @Override - public void loadFrom(InputStream in) throws IOException - { - final int id = BinaryUtils.readInt(in); - model = Tiles.get(id); - model.load(this, in); - } - - - @Override - public void saveTo(OutputStream out) throws IOException - { - BinaryUtils.writeInt(out, model.getId()); - model.save(this, out); - } - - - @Override - public short getIonMark() - { - return ION_MARK; - } - - - public void render(TileRenderContext context) - { - model.render(this, context); - if (!items.isEmpty()) items.peek().render(context); - } - - - @Override - public void update(double delta) - { - model.update(this, delta); - if (!items.isEmpty()) items.peek().update(delta); - } -} diff --git a/src/mightypork/rogue/world/TileModel.java b/src/mightypork/rogue/world/TileModel.java deleted file mode 100644 index 5e8fc48..0000000 --- a/src/mightypork/rogue/world/TileModel.java +++ /dev/null @@ -1,106 +0,0 @@ -package mightypork.rogue.world; - - -import java.io.InputStream; -import java.io.OutputStream; - -import mightypork.util.annotations.DefaultImpl; - - -public abstract class TileModel { - - public final int id; - - - public TileModel(int id) { - this.id = id; - Tiles.register(id, this); - } - - - /** - * Get the id. - * - * @return id - */ - public final int getId() - { - return id; - } - - - /** - * @return can be walked through (if discovered / open) - */ - public abstract boolean isPotentiallyWalkable(); - - - /** - * Populate a tile holder with data for this tile model - * - * @param tile tile in world - */ - @DefaultImpl - public void create(TileData tile) - { - } - - - /** - * On search performed (reveal hidden door etc) - * - * @param tile tile in world - */ - @DefaultImpl - public void search(TileData tile) - { - } - - - /** - * Check if an entity can walk this tile. If the tile is not potentially - * walkable, then this method must always return false. - * - * @param tile tile in world - */ - public abstract void isWalkable(TileData tile); - - - /** - * Load a tile from binary stream. - * - * @param tile tile to load - * @param in input stream - */ - @DefaultImpl - public void load(TileData tile, InputStream in) - { - } - - - /** - * Save a tile to binary stream. - * - * @param tile tile to save - * @param out output stream - */ - @DefaultImpl - public void save(TileData tile, OutputStream out) - { - } - - - public abstract void render(TileData tile, TileRenderContext context); - - - /** - * Update the tile (animation, item spawning etc) - * - * @param tile tile to update - * @param delta delta time - */ - @DefaultImpl - public void update(TileData tile, double delta) - { - } -} diff --git a/src/mightypork/rogue/world/WorldMap.java b/src/mightypork/rogue/world/WorldMap.java new file mode 100644 index 0000000..93b4fc3 --- /dev/null +++ b/src/mightypork/rogue/world/WorldMap.java @@ -0,0 +1,89 @@ +package mightypork.rogue.world; + + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import mightypork.rogue.world.tile.Tile; +import mightypork.rogue.world.tile.TileHolder; +import mightypork.util.files.ion.Ion; +import mightypork.util.files.ion.Ionizable; + + +public class WorldMap implements TileHolder, Ionizable { + + private int width, height; + + /** Array of tiles [y][x] */ + private Tile[][] tiles; + + + public WorldMap(int width, int height) { + this.width = width; + this.height = height; + buildArray(); + } + + + private void buildArray() + { + this.tiles = new Tile[height][width]; + } + + + @Override + public Tile getTile(int x, int y) + { + return tiles[y][x]; + } + + + public void setTile(Tile tile, int x, int y) + { + tiles[y][x] = tile; + } + + + @Override + public int getWidth() + { + return width; + } + + + @Override + public int getHeight() + { + return height; + } + + + @Override + public void loadFrom(InputStream in) throws IOException + { + width = Ion.readInt(in); + height = Ion.readInt(in); + + buildArray(); + + short mark; + + mark = Ion.readMark(in); + if(mark == Ion.START); + } + + + @Override + public void saveTo(OutputStream out) throws IOException + { + } + + + @Override + public short getIonMark() + { + return 0; + } + +} diff --git a/src/mightypork/rogue/world/item/Item.java b/src/mightypork/rogue/world/item/Item.java new file mode 100644 index 0000000..8c9a2f7 --- /dev/null +++ b/src/mightypork/rogue/world/item/Item.java @@ -0,0 +1,41 @@ +package mightypork.rogue.world.item; + + +import mightypork.rogue.world.Entity; +import mightypork.util.constraints.rect.proxy.RectBound; + + +public final class Item extends Entity { + + public static final short ION_MARK = 701; + + + public Item() { + super(); + } + + + public Item(ItemModel model) { + super(model); + } + + + public Item(int id) { + super(Items.get(id)); + } + + + @Override + protected ItemModel getModelForId(int id) + { + return Items.get(id); + } + + + @Override + public short getIonMark() + { + return ION_MARK; + } + +} diff --git a/src/mightypork/rogue/world/item/ItemData.java b/src/mightypork/rogue/world/item/ItemData.java new file mode 100644 index 0000000..1e6e835 --- /dev/null +++ b/src/mightypork/rogue/world/item/ItemData.java @@ -0,0 +1,11 @@ +package mightypork.rogue.world.item; + + +/** + * Item data object. Can be extended for particular models' needs. + * + * @author MightyPork + */ +public abstract class ItemData { + +} diff --git a/src/mightypork/rogue/world/item/ItemModel.java b/src/mightypork/rogue/world/item/ItemModel.java new file mode 100644 index 0000000..98eaf96 --- /dev/null +++ b/src/mightypork/rogue/world/item/ItemModel.java @@ -0,0 +1,19 @@ +package mightypork.rogue.world.item; + + +import mightypork.rogue.world.EntityModel; +import mightypork.util.constraints.rect.proxy.RectBound; + + +/** + * An item model + * + * @author MightyPork + */ +public abstract class ItemModel extends EntityModel { + + public ItemModel(int id) { + super(id); + Items.register(id, this); + } +} diff --git a/src/mightypork/rogue/world/Items.java b/src/mightypork/rogue/world/item/Items.java similarity index 89% rename from src/mightypork/rogue/world/Items.java rename to src/mightypork/rogue/world/item/Items.java index 1ff89d4..8e7fb89 100644 --- a/src/mightypork/rogue/world/Items.java +++ b/src/mightypork/rogue/world/item/Items.java @@ -1,11 +1,11 @@ -package mightypork.rogue.world; +package mightypork.rogue.world.item; import java.util.HashMap; import java.util.Map; -public class Items { +public final class Items { private static final Map registered = new HashMap<>(); diff --git a/src/mightypork/rogue/world/tile/Tile.java b/src/mightypork/rogue/world/tile/Tile.java new file mode 100644 index 0000000..50526cb --- /dev/null +++ b/src/mightypork/rogue/world/tile/Tile.java @@ -0,0 +1,98 @@ +package mightypork.rogue.world.tile; + + +import java.util.Stack; + +import mightypork.rogue.world.Entity; +import mightypork.rogue.world.item.Item; + + +/** + * Concrete tile in the world. + * + * @author MightyPork + */ +public final class Tile extends Entity { + + public static final short ION_MARK = 700; + + /** Items dropped onto this tile */ + public final Stack items = new Stack<>(); + + /** Whether the tile is occupied by an entity */ + public boolean occupied; + + + public Tile() { + super(); + } + + + public Tile(TileModel model) { + super(model); + } + + + public Tile(int id) { + super(Tiles.get(id)); + } + + + @Override + protected TileModel getModelForId(int id) + { + return Tiles.get(id); + } + + + @Override + public short getIonMark() + { + return ION_MARK; + } + + + @Override + public void render(TileRenderContext context) + { + super.render(context); + + // render laying-on-top item + if (!items.isEmpty()) { + Item item = items.peek(); + + item.render(context.getRect()); + } + } + + + @Override + public void update(double delta) + { + super.update(delta); + + // update laying-on-top item + if (!items.isEmpty()) { + Item item = items.peek(); + item.update(delta); + } + } + + + /** + * Try to reveal secrets of this tile + */ + public void search() + { + model.search(data); + } + + + /** + * @return true if a mob can walk through + */ + public boolean isWalkable() + { + return model.isWalkable(data); + } +} diff --git a/src/mightypork/rogue/world/tile/TileData.java b/src/mightypork/rogue/world/tile/TileData.java new file mode 100644 index 0000000..e883a97 --- /dev/null +++ b/src/mightypork/rogue/world/tile/TileData.java @@ -0,0 +1,18 @@ +package mightypork.rogue.world.tile; + + +import java.util.Stack; + +import mightypork.rogue.world.item.Item; + +/** + * Tile data object. Can be extended for particular models' needs. + * + * @author MightyPork + */ +public abstract class TileData { + + /** Items dropped onto this tile */ + public final Stack items = new Stack<>(); + +} diff --git a/src/mightypork/rogue/world/TileHolder.java b/src/mightypork/rogue/world/tile/TileHolder.java similarity index 54% rename from src/mightypork/rogue/world/TileHolder.java rename to src/mightypork/rogue/world/tile/TileHolder.java index c9e83d4..30f470a 100644 --- a/src/mightypork/rogue/world/TileHolder.java +++ b/src/mightypork/rogue/world/tile/TileHolder.java @@ -1,9 +1,9 @@ -package mightypork.rogue.world; +package mightypork.rogue.world.tile; public interface TileHolder { - TileData getTile(int x, int y); + Tile getTile(int x, int y); int getWidth(); diff --git a/src/mightypork/rogue/world/tile/TileModel.java b/src/mightypork/rogue/world/tile/TileModel.java new file mode 100644 index 0000000..e421c74 --- /dev/null +++ b/src/mightypork/rogue/world/tile/TileModel.java @@ -0,0 +1,45 @@ +package mightypork.rogue.world.tile; + + +import mightypork.rogue.world.EntityModel; +import mightypork.util.annotations.DefaultImpl; + + +public abstract class TileModel extends EntityModel { + + public TileModel(int id) { + super(id); + Tiles.register(id, this); + } + + + /** + * Test if this tile type is potentially walkable. Used during world + * generation. + * + * @return can be walked through (if discovered / open) + */ + public abstract boolean isPotentiallyWalkable(); + + + /** + * Try to reveal a secret. + * + * @param data tile data + */ + @DefaultImpl + public void search(TileData data) + { + // do nothing. + } + + + /** + * Check if a mob can walk through. + * + * @param data tile data + * @return is walkable + */ + public abstract boolean isWalkable(TileData data); + +} diff --git a/src/mightypork/rogue/world/TileRenderContext.java b/src/mightypork/rogue/world/tile/TileRenderContext.java similarity index 76% rename from src/mightypork/rogue/world/TileRenderContext.java rename to src/mightypork/rogue/world/tile/TileRenderContext.java index 470a652..3cad57c 100644 --- a/src/mightypork/rogue/world/TileRenderContext.java +++ b/src/mightypork/rogue/world/tile/TileRenderContext.java @@ -1,4 +1,4 @@ -package mightypork.rogue.world; +package mightypork.rogue.world.tile; import mightypork.util.constraints.rect.Rect; @@ -6,7 +6,7 @@ import mightypork.util.constraints.rect.builders.TiledRect; import mightypork.util.constraints.rect.proxy.RectBound; -public class TileRenderContext implements RectBound { +public final class TileRenderContext implements RectBound { private final TileHolder map; private final TiledRect tiler; @@ -19,13 +19,13 @@ public class TileRenderContext implements RectBound { } - public TileData getTile() + public Tile getTile() { return map.getTile(x, y); } - public TileData getAdjacentTile(int offsetX, int offsetY) + public Tile getAdjacentTile(int offsetX, int offsetY) { return map.getTile(x + offsetX, y + offsetY); } diff --git a/src/mightypork/rogue/world/Tiles.java b/src/mightypork/rogue/world/tile/Tiles.java similarity index 89% rename from src/mightypork/rogue/world/Tiles.java rename to src/mightypork/rogue/world/tile/Tiles.java index 3b72488..4a3b30a 100644 --- a/src/mightypork/rogue/world/Tiles.java +++ b/src/mightypork/rogue/world/tile/Tiles.java @@ -1,11 +1,11 @@ -package mightypork.rogue.world; +package mightypork.rogue.world.tile; import java.util.HashMap; import java.util.Map; -public class Tiles { +public final class Tiles { private static final Map registered = new HashMap<>(); diff --git a/src/mightypork/test/TestConstCaching.java b/src/mightypork/test/TestConstCaching.java deleted file mode 100644 index 2470877..0000000 --- a/src/mightypork/test/TestConstCaching.java +++ /dev/null @@ -1,41 +0,0 @@ -package mightypork.test; - - -import mightypork.util.constraints.vect.Vect; -import mightypork.util.constraints.vect.caching.VectCache; -import mightypork.util.constraints.vect.mutable.VectVar; - - -public class TestConstCaching { - - public static void main(String[] args) - { - final VectVar in = Vect.makeVar(0, 0); - final VectCache cache = in.cached(); - cache.enableDigestCaching(true); - - System.out.println("in = " + in); - System.out.println("cache = " + cache); - System.out.println("cache digest = " + cache.digest()); - System.out.println("\n-- in := 100, 50, 25 --\n"); - in.setTo(100, 50, 25); - System.out.println("in = " + in); - System.out.println("cache = " + cache); - System.out.println("cache digest = " + cache.digest()); - System.out.println("\n-- cache.poll() --\n"); - cache.markDigestDirty(); - System.out.println("in = " + in); - System.out.println("cache = " + cache); - System.out.println("cache digest = " + cache.digest()); - System.out.println("\n-- in := 1, 2, 3 --\n"); - in.setTo(1, 2, 3); - System.out.println("in = " + in); - System.out.println("cache = " + cache); - System.out.println("cache digest = " + cache.digest()); - System.out.println("\n-- cache.poll() --\n"); - cache.markDigestDirty(); - System.out.println("cache = " + cache); - System.out.println("cache digest = " + cache.digest()); - - } -} diff --git a/src/mightypork/test/TestConstr.java b/src/mightypork/test/TestConstr.java deleted file mode 100644 index a4e830b..0000000 --- a/src/mightypork/test/TestConstr.java +++ /dev/null @@ -1,94 +0,0 @@ -package mightypork.test; - - -import java.util.Locale; - -import mightypork.util.constraints.num.Num; -import mightypork.util.constraints.num.mutable.NumVar; -import mightypork.util.constraints.rect.Rect; -import mightypork.util.constraints.rect.RectConst; -import mightypork.util.constraints.vect.Vect; -import mightypork.util.constraints.vect.VectConst; -import mightypork.util.constraints.vect.mutable.VectVar; - - -public class TestConstr { - - public static void main(String[] args) - { - Locale.setDefault(Locale.ENGLISH); - - int cnt = -1; - - { - final RectConst rect = Rect.make(0, 0, 10, 10); - final VectConst point = Vect.make(50, 50); - System.out.println("Test " + ++cnt + ": rect = " + rect); - System.out.println("Test " + cnt + ": point = " + point); - System.out.println("Test " + cnt + ": centered rect = " + rect.centerTo(point)); - } - - { - final RectConst rect = Rect.make(0, 0, 10, 10); - final Rect v = rect; - System.out.println("\nTest " + ++cnt + ": " + (v == rect)); - } - - { - final RectConst rect = Rect.make(0, 0, 10, 10); - final Rect v = rect; - System.out.println("\nTest " + ++cnt + ": " + (v == rect)); - } - - { - final Vect a = Vect.make(3, 3); - @SuppressWarnings("deprecation") - final VectConst v = a.freeze().freeze().freeze(); - System.out.println("\nTest " + ++cnt + ": " + (v == a.freeze())); - } - - { - final Vect a = Vect.make(3, 3); - @SuppressWarnings("deprecation") - final VectConst v = a.freeze().freeze().freeze(); - System.out.println("\nTest " + ++cnt + ": " + (v == a.freeze())); - } - - { - final VectVar a = Vect.makeVar(10, 10); - final Vect view = a.mul(10).half().sub(1, 1); - System.out.println("\nTest " + ++cnt + ": " + (view.equals(Vect.make(49, 49)))); - a.add(10, 0); - System.out.println("Test " + cnt + ": " + (view.equals(Vect.make(99, 49)))); - a.setTo(900, 999); - System.out.println(view); - } - - { - final NumVar side = Num.makeVar(100); - final VectVar center = Vect.makeVar(0, 0); - - final Rect box = Rect.make(side, side).centerTo(center); - - System.out.println(box); - - side.setTo(10); - - System.out.println(box); - - center.setTo(900, -50); - - System.out.println(box); - - } - - { - final NumVar a = Num.makeVar(100); - - a.setTo(a.mul(50).add(10).div(2)); - - System.out.println(a); - - } - } -} diff --git a/src/mightypork/test/TestConvert.java b/src/mightypork/test/TestConvert.java deleted file mode 100644 index bfa763d..0000000 --- a/src/mightypork/test/TestConvert.java +++ /dev/null @@ -1,28 +0,0 @@ -package mightypork.test; - - -import java.util.Locale; - -import mightypork.util.objects.Convert; - - -public class TestConvert { - - public static void main(String[] args) - { - Locale.setDefault(Locale.ENGLISH); - - System.out.println(Convert.toVect("(10:20:30)")); - System.out.println(Convert.toVect("30.6 ; 80")); - System.out.println(Convert.toVect("30.6")); - - System.out.println(Convert.toRange("10")); - System.out.println(Convert.toRange("10..60")); - System.out.println(Convert.toRange("10-60")); - System.out.println(Convert.toRange("10--60")); - System.out.println(Convert.toRange("-10--60")); - System.out.println(Convert.toRange("3.1;22")); - System.out.println(Convert.toRange("3.1|22")); - - } -} diff --git a/src/mightypork/test/TestCoords.java b/src/mightypork/test/TestCoords.java deleted file mode 100644 index 2a55a2c..0000000 --- a/src/mightypork/test/TestCoords.java +++ /dev/null @@ -1,50 +0,0 @@ -package mightypork.test; - - -import mightypork.util.constraints.num.Num; -import mightypork.util.constraints.num.mutable.NumVar; -import mightypork.util.constraints.vect.Vect; -import mightypork.util.constraints.vect.mutable.VectVar; - - -public class TestCoords { - - public static void main(String[] args) - { - { - final VectVar a = Vect.makeVar(); - final VectVar b = Vect.makeVar(); - - final Vect cross = a.cross(b); - final Num dot = a.dot(b); - final Vect sum = a.add(b); - final Num dist = a.dist(b); - - a.setTo(0, 10, 0); - b.setTo(0, 6, 7); - - System.out.println("a = " + a); - System.out.println("b = " + b); - System.out.println("axb = " + cross); - System.out.println("a.b = " + dot); - System.out.println("a+b = " + sum); - System.out.println("dist(a,b) = " + dist); - } - - { - final NumVar a = Num.makeVar(); - - Num end = a; - - for (int i = 0; i < 100; i++) { - end = end.add(1); - } - - System.out.println(end); - a.setTo(37); - System.out.println(end); - - } - - } -} diff --git a/src/mightypork/test/TestPerlin.java b/src/mightypork/test/TestPerlin.java new file mode 100644 index 0000000..38274e6 --- /dev/null +++ b/src/mightypork/test/TestPerlin.java @@ -0,0 +1,33 @@ +package mightypork.test; + + +import java.util.Locale; + +import mightypork.util.math.noise.NoiseGen; + + +public class TestPerlin { + + public static void main(String[] args) + { + Locale.setDefault(Locale.ENGLISH); + + int w = 50, h = 50; + + NoiseGen ng = new NoiseGen(0.12, 0, 2.5, 5, (long) (Math.random()*100)); + + double[][] map = ng.buildMap(w, h); + + char[] colors = {' ', '░','▒','▓','█'}; + + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + // "pixels" two-thick + System.out.print(colors[(int) Math.floor(map[y][x])]); + System.out.print(colors[(int) Math.floor(map[y][x])]); + } + System.out.println(); + } + } + +} diff --git a/src/mightypork/test/TestTiled.java b/src/mightypork/test/TestTiled.java deleted file mode 100644 index b264c3b..0000000 --- a/src/mightypork/test/TestTiled.java +++ /dev/null @@ -1,44 +0,0 @@ -package mightypork.test; - - -import mightypork.util.constraints.num.Num; -import mightypork.util.constraints.num.mutable.NumVar; -import mightypork.util.constraints.rect.Rect; - - -public class TestTiled { - - public static void main(String[] args) - { -// { -// RectVar area = Rect.makeVar(0, 0, 100, 100); -// -// TiledRect tiled = area.tiles(5, 5).oneBased(); -// -// System.out.println(tiled.span(1, 1, 1, 1)); -// System.out.println(tiled.span(1, 1, 3, 1)); -// } - -// { -// RectVar area = Rect.makeVar(0, 0, 100, 100); -// TiledRect tiled = area.columns(4); -// -// System.out.println(tiled.column(2)); -// -// -// -// } -// - { - Rect abox; - final Rect b = Rect.make(100, 100, 100, 10); - final NumVar pos = Num.makeVar(1); - - abox = b.leftEdge().growRight(b.height()); - abox = abox.move(b.width().sub(b.height()).mul(pos), Num.ZERO); - //abox = abox.shrink(b.height().perc(10)); - - System.out.println(abox); - } - } -} diff --git a/src/mightypork/test/TestVec.java b/src/mightypork/test/TestVec.java deleted file mode 100644 index 6a60431..0000000 --- a/src/mightypork/test/TestVec.java +++ /dev/null @@ -1,33 +0,0 @@ -package mightypork.test; - - -import mightypork.util.constraints.vect.Vect; -import mightypork.util.constraints.vect.VectConst; -import mightypork.util.constraints.vect.mutable.VectVar; - - -public class TestVec { - - public static void main(String[] args) - { - final VectVar a = Vect.makeVar(-100, 12, 6); - - final VectConst b = a.freeze(); - - a.setTo(400, 400, 300); - - System.out.println(a); - System.out.println(b); - - final Vect c = a.abs().neg(); - - System.out.println(c); - - System.out.println("20,1"); - a.setTo(20, 1); - - System.out.println(a); - System.out.println(c); - - } -} diff --git a/src/mightypork/util/files/ion/Ion.java b/src/mightypork/util/files/ion/Ion.java index b68e9da..ec7d5e5 100644 --- a/src/mightypork/util/files/ion/Ion.java +++ b/src/mightypork/util/files/ion/Ion.java @@ -112,22 +112,28 @@ public class Ion { /** * Register new {@link Ionizable} for direct reconstructing. * - * @param mark mark to be used. Numbers 0..99 are reserved. + * @param mark mark to be used. Numbers 0..99 are reserved. Mark is of type + * Short, using values out of the short range will raise an + * exception. * @param objClass class of the registered Ionizable */ - public static void registerIonizable(short mark, Class objClass) + public static void registerIonizable(int mark, Class objClass) { // negative marks are allowed. + if (mark > Short.MAX_VALUE) throw new IllegalArgumentException("Mark too high (max " + Short.MAX_VALUE + ")."); + if (mark < Short.MIN_VALUE) throw new IllegalArgumentException("Mark too low (min " + Short.MIN_VALUE + ")."); - if (markRangeChecking && mark >= 0 && mark < 100) { - throw new RuntimeException("Marks 0..99 are reserved."); + short m = (short) mark; + + if (markRangeChecking && m >= 0 && m < 100) { + throw new IllegalArgumentException("Marks 0..99 are reserved."); } - if (customIonizables.containsKey(mark)) { - throw new RuntimeException("Mark " + mark + " is already in use."); + if (customIonizables.containsKey(m)) { + throw new IllegalArgumentException("Mark " + m + " is already in use."); } - customIonizables.put(mark, objClass); + customIonizables.put(m, objClass); } @@ -151,6 +157,27 @@ public class Ion { } + + /** + * Store an object to file. + * + * @param path file path + * @param obj object to store + * @throws IOException + */ + public static void toFile(File path, Object obj) throws IOException + { + try(OutputStream out = new FileOutputStream(path)) { + + writeObject(out, obj); + + out.flush(); + out.close(); + } catch (final Exception e) { + throw new IOException("Error writing to ION file.", e); + } + } + /** * Load an object from stream. * @@ -177,27 +204,6 @@ public class Ion { } - /** - * Store an object to file. - * - * @param path file path - * @param obj object to store - * @throws IOException - */ - public static void toFile(File path, Object obj) throws IOException - { - try(OutputStream out = new FileOutputStream(path)) { - - writeObject(out, obj); - - out.flush(); - out.close(); - } catch (final Exception e) { - throw new IOException("Error writing to ION file.", e); - } - } - - /** * Read single object from input stream, preceded by a mark. If a mark is * not present, the behavior is undefined - in case the read bytes happen to diff --git a/src/mightypork/util/math/Calc.java b/src/mightypork/util/math/Calc.java index fcc5cd5..e259ed4 100644 --- a/src/mightypork/util/math/Calc.java +++ b/src/mightypork/util/math/Calc.java @@ -650,19 +650,6 @@ public class Calc { } - /** - * Get class simple name - * - * @param obj object - * @return simple name - */ - public static String cname(Object obj) - { - if (obj == null) return "NULL"; - return obj.getClass().getSimpleName(); - } - - /** * Cube a double * diff --git a/src/mightypork/util/math/noise/NoiseGen.java b/src/mightypork/util/math/noise/NoiseGen.java new file mode 100644 index 0000000..66f946d --- /dev/null +++ b/src/mightypork/util/math/noise/NoiseGen.java @@ -0,0 +1,94 @@ +package mightypork.util.math.noise; + + +/** + * 2D Perlin noise generator + * + * @author MightyPork + */ +public class NoiseGen { + + private static final double lowBound = -0.7072; + private static final double highBound = 0.7072; + + private final PerlinNoiseGenerator noiser; + + private final double lowMul; + private final double highMul; + private final double middle; + private final double density; + + + /** + * make a new noise generator + * + * @param density noise density (0..1). Lower density means larger "spots". + * @param low low bound ("valley") + * @param middle middle bound ("surface") + * @param high high bound ("hill") + * @param seed random seed to use + */ + public NoiseGen(double density, double low, double middle, double high, long seed) { + if (low > middle || middle > high) throw new IllegalArgumentException("Invalid value range."); + + this.density = density; + + // norm low and high to be around zero + low -= middle; + high -= middle; + + // scale + this.middle = middle; + + lowMul = Math.abs(low / lowBound); + highMul = Math.abs(high / highBound); + + noiser = new PerlinNoiseGenerator(seed); + } + + + /** + * Get value at coord + * + * @param x x coordinate + * @param y y coordinate + * @return value + */ + public double valueAt(double x, double y) + { + double raw = noiser.noise2(x * density, y * density); + + if (raw < lowBound) { + raw = lowBound; + } else if (raw > highBound) { + raw = highBound; + } + + if (raw < 0) { + return middle + lowMul * raw; + } else { + return middle + highMul * raw; + } + } + + + /** + * Build a map [height][width] of noise values + * + * @param width map width (number of columns) + * @param height map height (number of rows ) + * @return the map + */ + public double[][] buildMap(int width, int height) + { + double[][] map = new double[height][width]; + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + map[y][x] = valueAt(x, y); + } + } + + return map; + } +} diff --git a/src/mightypork/util/math/noise/PerlinNoiseGenerator.java b/src/mightypork/util/math/noise/PerlinNoiseGenerator.java new file mode 100644 index 0000000..ebfd535 --- /dev/null +++ b/src/mightypork/util/math/noise/PerlinNoiseGenerator.java @@ -0,0 +1,575 @@ +/***************************************************************************** + * J3D.org Copyright (c) 2000 + * Java Source + * + * This source is licensed under the GNU LGPL v2.1 + * Please read http://www.gnu.org/copyleft/lgpl.html for more information + * + * This software comes with the standard NO WARRANTY disclaimer for any + * purpose. Use it at your own risk. If there's a problem you get to fix it. + * + ****************************************************************************/ +package mightypork.util.math.noise; + + +import java.util.Random; + + +/** + * Computes Perlin Noise for three dimensions. + *

+ * The result is a continuous function that interpolates a smooth path along a + * series random points. The function is consitent, so given the same + * parameters, it will always return the same value. The smoothing function is + * based on the Improving Noise paper presented at Siggraph 2002. + *

+ * Computing noise for one and two dimensions can make use of the 3D problem + * space by just setting the un-needed dimensions to a fixed value. + * + * @author Justin Couch + * @edited by MightyPork + * @version $Revision: 1.4 $ + * @source http://code.j3d.org/download.html + */ +public class PerlinNoiseGenerator { + + // Constants for setting up the Perlin-1 noise functions + private static final int B = 0x1000; + private static final int BM = 0xff; + + private static final int N = 0x1000; + + /** Default seed to use for the random number generation */ + private static final int DEFAULT_SEED = 100; + + /** Default sample size to work with */ + private static final int DEFAULT_SAMPLE_SIZE = 256; + + private final Random rand = new Random(DEFAULT_SEED); + + /** Permutation array for the improved noise function */ + private int[] p_imp; + + /** P array for perline 1 noise */ + private int[] p; + private double[][] g3; + private double[][] g2; + private double[] g1; + + + /** + * Create a new noise creator with the default seed value + */ + public PerlinNoiseGenerator() { + this(DEFAULT_SEED); + } + + + /** + * Create a new noise creator with the given seed value for the randomness + * + * @param seed The seed value to use + */ + public PerlinNoiseGenerator(long seed) { + p_imp = new int[DEFAULT_SAMPLE_SIZE << 1]; + + int i, j, k; + rand.setSeed(seed); + + // Calculate the table of psuedo-random coefficients. + for (i = 0; i < DEFAULT_SAMPLE_SIZE; i++) + p_imp[i] = i; + + // generate the psuedo-random permutation table. + while (--i > 0) { + k = p_imp[i]; + j = (int) (rand.nextLong() & DEFAULT_SAMPLE_SIZE); + p_imp[i] = p_imp[j]; + p_imp[j] = k; + } + + initPerlin1(); + } + + + /** + * Computes noise function for three dimensions at the point (x,y,z). + * + * @param x x dimension parameter + * @param y y dimension parameter + * @param z z dimension parameter + * @return the noise value at the point (x, y, z) + */ + public double improvedNoise(double x, double y, double z) + { + // Constraint the point to a unit cube + int uc_x = (int) Math.floor(x) & 255; + int uc_y = (int) Math.floor(y) & 255; + int uc_z = (int) Math.floor(z) & 255; + + // Relative location of the point in the unit cube + double xo = x - Math.floor(x); + double yo = y - Math.floor(y); + double zo = z - Math.floor(z); + + // Fade curves for x, y and z + double u = fade(xo); + double v = fade(yo); + double w = fade(zo); + + // Generate a hash for each coordinate to find out where in the cube + // it lies. + int a = p_imp[uc_x] + uc_y; + int aa = p_imp[a] + uc_z; + int ab = p_imp[a + 1] + uc_z; + + int b = p_imp[uc_x + 1] + uc_y; + int ba = p_imp[b] + uc_z; + int bb = p_imp[b + 1] + uc_z; + + // blend results from the 8 corners based on the noise function + double c1 = grad(p_imp[aa], xo, yo, zo); + double c2 = grad(p_imp[ba], xo - 1, yo, zo); + double c3 = grad(p_imp[ab], xo, yo - 1, zo); + double c4 = grad(p_imp[bb], xo - 1, yo - 1, zo); + double c5 = grad(p_imp[aa + 1], xo, yo, zo - 1); + double c6 = grad(p_imp[ba + 1], xo - 1, yo, zo - 1); + double c7 = grad(p_imp[ab + 1], xo, yo - 1, zo - 1); + double c8 = grad(p_imp[bb + 1], xo - 1, yo - 1, zo - 1); + + return lerp(w, lerp(v, lerp(u, c1, c2), lerp(u, c3, c4)), lerp(v, lerp(u, c5, c6), lerp(u, c7, c8))); + } + + + /** + * 1-D noise generation function using the original perlin algorithm. + * + * @param x Seed for the noise function + * @return The noisy output + */ + public double noise1(double x) + { + double t = x + N; + int bx0 = ((int) t) & BM; + int bx1 = (bx0 + 1) & BM; + double rx0 = t - (int) t; + double rx1 = rx0 - 1; + + double sx = sCurve(rx0); + + double u = rx0 * g1[p[bx0]]; + double v = rx1 * g1[p[bx1]]; + + return lerp(sx, u, v); + } + + + /** + * Create noise in a 2D space using the orignal perlin noise algorithm. + * + * @param x The X coordinate of the location to sample + * @param y The Y coordinate of the location to sample + * @return A noisy value at the given position + */ + public double noise2(double x, double y) + { + double t = x + N; + int bx0 = ((int) t) & BM; + int bx1 = (bx0 + 1) & BM; + double rx0 = t - (int) t; + double rx1 = rx0 - 1; + + t = y + N; + int by0 = ((int) t) & BM; + int by1 = (by0 + 1) & BM; + double ry0 = t - (int) t; + double ry1 = ry0 - 1; + + int i = p[bx0]; + int j = p[bx1]; + + int b00 = p[i + by0]; + int b10 = p[j + by0]; + int b01 = p[i + by1]; + int b11 = p[j + by1]; + + double sx = sCurve(rx0); + double sy = sCurve(ry0); + + double[] q = g2[b00]; + double u = rx0 * q[0] + ry0 * q[1]; + q = g2[b10]; + double v = rx1 * q[0] + ry0 * q[1]; + double a = lerp(sx, u, v); + + q = g2[b01]; + u = rx0 * q[0] + ry1 * q[1]; + q = g2[b11]; + v = rx1 * q[0] + ry1 * q[1]; + double b = lerp(sx, u, v); + + return lerp(sy, a, b); + } + + + /** + * Create noise in a 3D space using the orignal perlin noise algorithm. + * + * @param x The X coordinate of the location to sample + * @param y The Y coordinate of the location to sample + * @param z The Z coordinate of the location to sample + * @return A noisy value at the given position + */ + public double noise3(double x, double y, double z) + { + double t = x + N; + int bx0 = ((int) t) & BM; + int bx1 = (bx0 + 1) & BM; + double rx0 = t - (int) t; + double rx1 = rx0 - 1; + + t = y + N; + int by0 = ((int) t) & BM; + int by1 = (by0 + 1) & BM; + double ry0 = t - (int) t; + double ry1 = ry0 - 1; + + t = z + N; + int bz0 = ((int) t) & BM; + int bz1 = (bz0 + 1) & BM; + double rz0 = t - (int) t; + double rz1 = rz0 - 1; + + int i = p[bx0]; + int j = p[bx1]; + + int b00 = p[i + by0]; + int b10 = p[j + by0]; + int b01 = p[i + by1]; + int b11 = p[j + by1]; + + t = sCurve(rx0); + double sy = sCurve(ry0); + double sz = sCurve(rz0); + + double[] q = g3[b00 + bz0]; + double u = (rx0 * q[0] + ry0 * q[1] + rz0 * q[2]); + q = g3[b10 + bz0]; + double v = (rx1 * q[0] + ry0 * q[1] + rz0 * q[2]); + double a = lerp(t, u, v); + + q = g3[b01 + bz0]; + u = (rx0 * q[0] + ry1 * q[1] + rz0 * q[2]); + q = g3[b11 + bz0]; + v = (rx1 * q[0] + ry1 * q[1] + rz0 * q[2]); + double b = lerp(t, u, v); + + double c = lerp(sy, a, b); + + q = g3[b00 + bz1]; + u = (rx0 * q[0] + ry0 * q[1] + rz1 * q[2]); + q = g3[b10 + bz1]; + v = (rx1 * q[0] + ry0 * q[1] + rz1 * q[2]); + a = lerp(t, u, v); + + q = g3[b01 + bz1]; + u = (rx0 * q[0] + ry1 * q[1] + rz1 * q[2]); + q = g3[b11 + bz1]; + v = (rx1 * q[0] + ry1 * q[1] + rz1 * q[2]); + b = lerp(t, u, v); + + double d = lerp(sy, a, b); + + return lerp(sz, c, d); + } + + + /** + * Create a turbulent noise output based on the core noise function. This + * uses the noise as a base function and is suitable for creating clouds, + * marble and explosion effects. For example, a typical marble effect would + * set the colour to be: + * + *

+     *    sin(point + turbulence(point) * point.x);
+     * 
+ * + * @param x + * @param y + * @param z + * @param loF + * @param hiF + * @return value + */ + public double imporvedTurbulence(double x, double y, double z, double loF, double hiF) + { + double p_x = x + 123.456f; + double p_y = y; + double p_z = z; + double t = 0; + double f; + + for (f = loF; f < hiF; f *= 2) { + t += Math.abs(improvedNoise(p_x, p_y, p_z)) / f; + + p_x *= 2; + p_y *= 2; + p_z *= 2; + } + + return t - 0.3; + } + + + /** + * Create a turbulance function in 2D using the original perlin noise + * function. + * + * @param x The X coordinate of the location to sample + * @param y The Y coordinate of the location to sample + * @param freq The frequency of the turbluance to create + * @return The value at the given coordinates + */ + public double turbulence2(double x, double y, double freq) + { + double t = 0; + + do { + t += noise2(freq * x, freq * y) / freq; + freq *= 0.5f; + } while (freq >= 1); + + return t; + } + + + /** + * Create a turbulance function in 3D using the original perlin noise + * function. + * + * @param x The X coordinate of the location to sample + * @param y The Y coordinate of the location to sample + * @param z The Z coordinate of the location to sample + * @param freq The frequency of the turbluance to create + * @return The value at the given coordinates + */ + public double turbulence3(double x, double y, double z, double freq) + { + double t = 0; + + do { + t += noise3(freq * x, freq * y, freq * z) / freq; + freq *= 0.5f; + } while (freq >= 1); + + return t; + } + + + /** + * Create a 1D tileable noise function for the given width. + * + * @param x The X coordinate to generate the noise for + * @param w The width of the tiled block + * @return The value of the noise at the given coordinate + */ + public double tileableNoise1(double x, double w) + { + return (noise1(x) * (w - x) + noise1(x - w) * x) / w; + } + + + /** + * Create a 2D tileable noise function for the given width and height. + * + * @param x The X coordinate to generate the noise for + * @param y The Y coordinate to generate the noise for + * @param w The width of the tiled block + * @param h The height of the tiled block + * @return The value of the noise at the given coordinate + */ + public double tileableNoise2(double x, double y, double w, double h) + { + return (noise2(x, y) * (w - x) * (h - y) + noise2(x - w, y) * x * (h - y) + noise2(x, y - h) * (w - x) * y + noise2(x - w, y - h) * x * y) / (w * h); + } + + + /** + * Create a 3D tileable noise function for the given width, height and + * depth. + * + * @param x The X coordinate to generate the noise for + * @param y The Y coordinate to generate the noise for + * @param z The Z coordinate to generate the noise for + * @param w The width of the tiled block + * @param h The height of the tiled block + * @param d The depth of the tiled block + * @return The value of the noise at the given coordinate + */ + public double tileableNoise3(double x, double y, double z, double w, double h, double d) + { + return (noise3(x, y, z) * (w - x) * (h - y) * (d - z) + noise3(x - w, y, z) * x * (h - y) * (d - z) + noise3(x, y - h, z) * (w - x) * y * (d - z) + + noise3(x - w, y - h, z) * x * y * (d - z) + noise3(x, y, z - d) * (w - x) * (h - y) * z + noise3(x - w, y, z - d) * x * (h - y) * z + + noise3(x, y - h, z - d) * (w - x) * y * z + noise3(x - w, y - h, z - d) * x * y * z) + / (w * h * d); + } + + + /** + * Create a turbulance function that can be tiled across a surface in 2D. + * + * @param x The X coordinate of the location to sample + * @param y The Y coordinate of the location to sample + * @param w The width to tile over + * @param h The height to tile over + * @param freq The frequency of the turbluance to create + * @return The value at the given coordinates + */ + public double tileableTurbulence2(double x, double y, double w, double h, double freq) + { + double t = 0; + + do { + t += tileableNoise2(freq * x, freq * y, w * freq, h * freq) / freq; + freq *= 0.5f; + } while (freq >= 1); + + return t; + } + + + /** + * Create a turbulance function that can be tiled across a surface in 3D. + * + * @param x The X coordinate of the location to sample + * @param y The Y coordinate of the location to sample + * @param z The Z coordinate of the location to sample + * @param w The width to tile over + * @param h The height to tile over + * @param d The depth to tile over + * @param freq The frequency of the turbluance to create + * @return The value at the given coordinates + */ + public double tileableTurbulence3(double x, double y, double z, double w, double h, double d, double freq) + { + double t = 0; + + do { + t += tileableNoise3(freq * x, freq * y, freq * z, w * freq, h * freq, d * freq) / freq; + freq *= 0.5f; + } while (freq >= 1); + + return t; + } + + + /** + * Simple lerp function using doubles. + */ + private double lerp(double t, double a, double b) + { + return a + t * (b - a); + } + + + /** + * Fade curve calculation which is 6t^5 - 15t^4 + 10t^3. This is the new + * algorithm, where the old one used to be 3t^2 - 2t^3. + * + * @param t The t parameter to calculate the fade for + * @return the drop-off amount. + */ + private double fade(double t) + { + return t * t * t * (t * (t * 6 - 15) + 10); + } + + + /** + * Calculate the gradient function based on the hash code. + */ + private double grad(int hash, double x, double y, double z) + { + // Convert low 4 bits of hash code into 12 gradient directions. + int h = hash & 15; + double u = (h < 8 || h == 12 || h == 13) ? x : y; + double v = (h < 4 || h == 12 || h == 13) ? y : z; + + return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); + } + + + /** + * S-curve function for value distribution for Perlin-1 noise function. + */ + private double sCurve(double t) + { + return (t * t * (3 - 2 * t)); + } + + + /** + * 2D-vector normalisation function. + */ + private void normalize2(double[] v) + { + double s = 1 / Math.sqrt(v[0] * v[0] + v[1] * v[1]); + v[0] *= s; + v[1] *= s; + } + + + /** + * 3D-vector normalisation function. + */ + private void normalize3(double[] v) + { + double s = 1 / Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + v[0] *= s; + v[1] *= s; + v[2] *= s; + } + + + /** + * Initialise the lookup arrays used by Perlin 1 function. + */ + private void initPerlin1() + { + p = new int[B + B + 2]; + g3 = new double[B + B + 2][3]; + g2 = new double[B + B + 2][2]; + g1 = new double[B + B + 2]; + int i, j, k; + + for (i = 0; i < B; i++) { + p[i] = i; + + g1[i] = (((rand.nextDouble() * Integer.MAX_VALUE) % (B + B)) - B) / B; + + for (j = 0; j < 2; j++) + g2[i][j] = (((rand.nextDouble() * Integer.MAX_VALUE) % (B + B)) - B) / B; + normalize2(g2[i]); + + for (j = 0; j < 3; j++) + g3[i][j] = (((rand.nextDouble() * Integer.MAX_VALUE) % (B + B)) - B) / B; + normalize3(g3[i]); + } + + while (--i > 0) { + k = p[i]; + j = (int) ((rand.nextDouble() * Integer.MAX_VALUE) % B); + p[i] = p[j]; + p[j] = k; + } + + for (i = 0; i < B + 2; i++) { + p[B + i] = p[i]; + g1[B + i] = g1[i]; + for (j = 0; j < 2; j++) + g2[B + i][j] = g2[i][j]; + for (j = 0; j < 3; j++) + g3[B + i][j] = g3[i][j]; + } + } +}