Removed test classes, improved ION error handling & performance.

v5stable
Ondřej Hruška 10 years ago
parent 7eb390d915
commit 4721351ed9
  1. 1
      src/mightypork/gamecore/render/Render.java
  2. 13
      src/mightypork/rogue/App.java
  3. 2
      src/mightypork/rogue/Config.java
  4. 2
      src/mightypork/rogue/Const.java
  5. 2
      src/mightypork/rogue/MainLoop.java
  6. 2
      src/mightypork/rogue/Paths.java
  7. 2
      src/mightypork/rogue/Res.java
  8. 2
      src/mightypork/rogue/util/Utils.java
  9. 121
      src/mightypork/rogue/world/Entity.java
  10. 92
      src/mightypork/rogue/world/EntityModel.java
  11. 89
      src/mightypork/rogue/world/ItemData.java
  12. 84
      src/mightypork/rogue/world/ItemModel.java
  13. 63
      src/mightypork/rogue/world/Model.java
  14. 102
      src/mightypork/rogue/world/TileData.java
  15. 106
      src/mightypork/rogue/world/TileModel.java
  16. 89
      src/mightypork/rogue/world/WorldMap.java
  17. 41
      src/mightypork/rogue/world/item/Item.java
  18. 11
      src/mightypork/rogue/world/item/ItemData.java
  19. 19
      src/mightypork/rogue/world/item/ItemModel.java
  20. 4
      src/mightypork/rogue/world/item/Items.java
  21. 98
      src/mightypork/rogue/world/tile/Tile.java
  22. 18
      src/mightypork/rogue/world/tile/TileData.java
  23. 4
      src/mightypork/rogue/world/tile/TileHolder.java
  24. 45
      src/mightypork/rogue/world/tile/TileModel.java
  25. 8
      src/mightypork/rogue/world/tile/TileRenderContext.java
  26. 4
      src/mightypork/rogue/world/tile/Tiles.java
  27. 41
      src/mightypork/test/TestConstCaching.java
  28. 94
      src/mightypork/test/TestConstr.java
  29. 28
      src/mightypork/test/TestConvert.java
  30. 50
      src/mightypork/test/TestCoords.java
  31. 33
      src/mightypork/test/TestPerlin.java
  32. 44
      src/mightypork/test/TestTiled.java
  33. 33
      src/mightypork/test/TestVec.java
  34. 62
      src/mightypork/util/files/ion/Ion.java
  35. 13
      src/mightypork/util/math/Calc.java
  36. 94
      src/mightypork/util/math/noise/NoiseGen.java
  37. 575
      src/mightypork/util/math/noise/PerlinNoiseGenerator.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)

@ -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()
{

@ -10,7 +10,7 @@ import mightypork.util.logging.Log;
*
* @author MightyPork
*/
public class Config {
public final class Config {
private static PropertyManager mgr;

@ -6,7 +6,7 @@ package mightypork.rogue;
*
* @author MightyPork
*/
public class Const {
public final class Const {
// STRINGS
public static final int VERSION = 1;

@ -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);

@ -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";

@ -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;

@ -6,7 +6,7 @@ package mightypork.rogue.util;
*
* @author MightyPork
*/
public class Utils {
public final class Utils {
public static Thread runAsThread(Runnable r)
{

@ -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 <D> Data object class
* @param <M> Model class
* @param <R> Render context class
*/
public abstract class Entity<D, M extends EntityModel<D, R>, 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);
}

@ -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 <D> Data object class
* @param <R> Render context class
*/
public abstract class EntityModel<D, R extends RectBound> {
/** 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);
}

@ -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<ItemData, RectBound> 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<ItemData, RectBound> 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);
}
}

@ -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<ItemData, RectBound> {
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)
{
}
}

@ -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<DATA, RCTX> {
/**
* 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);
}

@ -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<ItemData> 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);
}
}

@ -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)
{
}
}

@ -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;
}
}

@ -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<ItemData, ItemModel, RectBound> {
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;
}
}

@ -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 {
}

@ -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<ItemData, RectBound> {
public ItemModel(int id) {
super(id);
Items.register(id, this);
}
}

@ -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<Integer, ItemModel> registered = new HashMap<>();

@ -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<TileData, TileModel, TileRenderContext> {
public static final short ION_MARK = 700;
/** Items dropped onto this tile */
public final Stack<Item> 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);
}
}

@ -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<Item> items = new Stack<>();
}

@ -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();

@ -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<TileData, TileRenderContext> {
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);
}

@ -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);
}

@ -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<Integer, TileModel> registered = new HashMap<>();

@ -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());
}
}

@ -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);
}
}
}

@ -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"));
}
}

@ -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);
}
}
}

@ -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();
}
}
}

@ -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);
}
}
}

@ -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);
}
}

@ -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

@ -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
*

@ -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;
}
}

@ -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.
* <p>
* 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.
* <p>
* 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:
*
* <pre>
* sin(point + turbulence(point) * point.x);
* </pre>
*
* @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];
}
}
}
Loading…
Cancel
Save