Merge branch 'pi' of 192.168.1.28:artisanlogiciel/code/laby

# Conflicts:
#	build.xml
#	mybuild.xml
This commit is contained in:
philippe lhardy
2020-10-15 17:33:19 +02:00
41 changed files with 2524 additions and 2300 deletions

View File

@@ -1,77 +1,60 @@
package org.artisanlogiciel.games;
/**
DirectionPosition
record direction and position ( direction as defined in LabyModel ).
* DirectionPosition
* <p>
* record direction and position ( direction as defined in LabyModel ).
**/
public class DirectionPosition
{
public class DirectionPosition {
private short direction;
private Position position;
// (direction,position)
DirectionPosition(short d, Position p)
{
direction=d;
position=p;
public DirectionPosition(short d, Position p) {
direction = d;
position = p;
}
short getDirection()
{
return direction;
public short getDirection() {
return direction;
}
void setDirection(short d)
{
direction = d;
public void setDirection(short d) {
direction = d;
}
Position getPosition()
{
return position;
public Position getPosition() {
return position;
}
public String toString()
{
if (position != null)
{
return position.toString();
}
return "?";
public String toString() {
if (position != null) {
return position.toString();
}
return "?";
}
// create a new DirectionPosition from this using one possible direction.
DirectionPosition moveToAdjacentDirection()
{
short pointingdirection = 0;
Position p = null;
if (LabyModel.isFlagSet(direction,LabyModel.RIGHT))
{
p = new Position(position.getX() + 1, position.getY());
pointingdirection |= LabyModel.LEFT;
}
else if (LabyModel.isFlagSet(direction,LabyModel.LEFT))
{
p = new Position(position.getX() -1 ,position.getY());
pointingdirection |= LabyModel.RIGHT;
}
else if (LabyModel.isFlagSet(direction,LabyModel.UP))
{
p = new Position(position.getX(),position.getY() -1);
pointingdirection |= LabyModel.DOWN;
}
else if (LabyModel.isFlagSet(direction,LabyModel.DOWN))
{
p = new Position(position.getX(),position.getY() + 1);
pointingdirection |= LabyModel.UP;
}
else
{
p = position;
}
public DirectionPosition moveToAdjacentDirection() {
short pointingdirection = 0;
Position p = null;
if (LabyModel.isFlagSet(direction, LabyModel.RIGHT)) {
p = new Position(position.getX() + 1, position.getY());
pointingdirection |= LabyModel.LEFT;
} else if (LabyModel.isFlagSet(direction, LabyModel.LEFT)) {
p = new Position(position.getX() - 1, position.getY());
pointingdirection |= LabyModel.RIGHT;
} else if (LabyModel.isFlagSet(direction, LabyModel.UP)) {
p = new Position(position.getX(), position.getY() - 1);
pointingdirection |= LabyModel.DOWN;
} else if (LabyModel.isFlagSet(direction, LabyModel.DOWN)) {
p = new Position(position.getX(), position.getY() + 1);
pointingdirection |= LabyModel.UP;
} else {
p = position;
}
return new DirectionPosition((short) pointingdirection, p);
return new DirectionPosition((short) pointingdirection, p);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -14,25 +14,14 @@ public class Main
return editor;
}
public WallsProvider generate(int width, int height, int maxdepth, MazeResolutionListener listener)
public LabyMap generate2(MazeParamEditor params)
{
LabyModel model = new LabyModel(width, height, maxdepth, new java.util.Random());
params.setSeed(1024L);
LabyModel model = new LabyModel(params);
model.generateWithEntry(0, 0);
LinkedList<Position> exits = new LinkedList<Position>();
model.addEntryOrExit(-1, 0);
model.addEntryOrExit(width, height - 1);
if (!model.check())
{
System.out.println("Check failed");
}
model.resolve(width - 1, height - 1, listener);
return model;
}
public LabyMap generate2(int width, int height, int maxdepth)
{
LabyModel model = new LabyModel(width, height, maxdepth, new java.util.Random(1024L));
model.generateWithEntry(0, 0);
final int width = params.getWidth();
final int height = params.getHeight();
LinkedList<Position> exits = new LinkedList<Position>();
model.addEntryOrExit(-1, 0);
model.addEntryOrExit(width, height - 1);
@@ -51,7 +40,7 @@ public class Main
{
Main m = new Main();
MazeParamEditor editor = m.editor();
LabyMap map = m.generate2(editor.width, editor.height, editor.maxdepth);
LabyMap map = m.generate2(editor);
System.out.println(map.toShortString());
System.out.println(map.toString());
System.out.println(Brick.getDirLine());

View File

@@ -3,7 +3,7 @@ package org.artisanlogiciel.games;
/**
* MazeCreationListener
**/
interface MazeCreationListener
public interface MazeCreationListener
{
void changed(Position cornerleft, Position cornerright, WallsProvider provider);
}

View File

@@ -8,6 +8,7 @@ import java.util.Scanner;
**/
class MazeParamEditor implements MazeParams
{
long seed;
int width;
int height;
int maxdepth;
@@ -27,6 +28,11 @@ class MazeParamEditor implements MazeParams
maxdepth = console.nextInt();
}
public long getSeed()
{
return seed;
}
public int getWidth()
{
return width;
@@ -51,6 +57,11 @@ class MazeParamEditor implements MazeParams
return name;
}
public void setSeed(long seed)
{
this.seed = seed;
}
public File getSaveDir()
{
return labdir;

View File

@@ -7,6 +7,9 @@ import java.io.File;
**/
public interface MazeParams
{
/** currently seed of java.util.random **/
public long getSeed();
public int getWidth();
public int getHeight();

View File

@@ -0,0 +1,76 @@
package org.artisanlogiciel.games;
import java.io.File;
public class MazeParamsFixed implements MazeParams
{
long seed;
int width;
int height;
int maxdepth;
File labdir;
String name;
public MazeParamsFixed()
{
}
public MazeParamsFixed(MazeParams params)
{
setParams(params.getSaveDir(),params.getWidth(),params.getHeight(),params.getMaxDepth());
}
public void setParams(File saveDir, int W, int H, int MD)
{
labdir = saveDir;
width=W;
height=H;
maxdepth=MD;
}
public MazeParamsFixed(File saveDir, int W, int H, int MD, long seed)
{
name = null;
setParams(saveDir,W,H,MD);
this.seed=seed;
}
public long getSeed()
{
return seed;
}
public int getWidth()
{
return width;
}
public int getHeight()
{
return height;
}
public int getMaxDepth()
{
return maxdepth;
}
public void setName(String n)
{
name = n;
}
public String getName()
{
if (name == null)
{
name = "lab" + width + "x" + height;
}
return name;
}
public File getSaveDir()
{
return labdir;
}
}

View File

@@ -13,7 +13,12 @@ public interface WallsProvider
/**
* See Brick
*
* Will set bits : 3 2 1 0 (8)(4)(2)(1) ^ > v < U R D L p i o e g w f h n t
* Will set bits :
* 3 2 1 0
* (8)(4)(2)(1)
* ^ > v <
* U R D L
* p i o e g w f h n t
* t
**/
public short getWalls(int x, int y);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,72 @@
package org.artisanlogiciel.games.maze.gui;
import org.artisanlogiciel.games.MazeParams;
import org.artisanlogiciel.games.stl.Maze3dParams;
import org.artisanlogiciel.games.stl.Wall3d;
import javax.swing.*;
public class Maze3dSettings
extends JPanel
{
// grid size
JTextField xl;
JTextField yl;
JTextField zl;
JTextField w;
JTextField lg;
JTextField hg;
JCheckBox reverse;
Maze3dParams params;
public Maze3dSettings(Maze3dParams params) {
super();
this.params = params;
createSettingsGui();
}
void createSettingsGui() {
if (params != null) {
JLabel widthLabel = new JLabel(Display.labels.getString("width"));
xl = new JTextField("0" + params.getXl());
add(widthLabel);
add(xl);
JLabel heightLabel = new JLabel(Display.labels.getString("height"));
zl = new JTextField("0" + params.getZl());
add(heightLabel);
add(zl);
JLabel depthLabel = new JLabel(Display.labels.getString("depth"));
yl = new JTextField("0" + params.getYl());
add(depthLabel);
add(yl);
reverse = new JCheckBox("reverse",params.isReverse());
add(reverse);
w = new JTextField("0" + params.getW());
add(w);
// lowground hightground
lg = new JTextField("0" + params.getLg());
add(lg);
hg = new JTextField("0" + params.getHg());
add(hg);
}
}
Maze3dParams createParams()
{
return new Maze3dParams(
Integer.parseInt(xl.getText()),
Integer.parseInt(yl.getText()),
Integer.parseInt(zl.getText()),
Integer.parseInt(w.getText()),
Integer.parseInt(lg.getText()),
Integer.parseInt(hg.getText()),
reverse.isSelected());
}
}

View File

@@ -0,0 +1,56 @@
package org.artisanlogiciel.games.maze.gui;
import org.artisanlogiciel.games.MazeParams;
import org.artisanlogiciel.games.MazeParamsFixed;
import javax.swing.*;
import java.util.Random;
public class MazeSettings extends JPanel {
MazeParams params;
JTextField textWidth = null;
JTextField textHeight = null;
JTextField textDepth = null;
JTextField textSeed = null;
// TODO set width and height and depth of maze with gui
public MazeSettings(MazeParams params) {
super();
this.params = params;
createSettingsGui();
}
void createSettingsGui() {
if (params != null) {
JLabel widthLabel = new JLabel(Display.labels.getString("width"));
textWidth = new JTextField("0" + params.getWidth());
add(widthLabel);
add(textWidth);
JLabel heightLabel = new JLabel(Display.labels.getString("height"));
textHeight = new JTextField("0" + params.getHeight());
add(heightLabel);
add(textHeight);
JLabel depthLabel = new JLabel(Display.labels.getString("depth"));
textDepth = new JTextField("0" + params.getMaxDepth());
add(depthLabel);
add(textDepth);
JLabel seedLabel = new JLabel(Display.labels.getString("seed"));
textSeed = new JTextField( "" + params.getSeed(),16);
add(seedLabel);
add(textSeed);
}
}
public MazeParams resetParams() {
params = new MazeParamsFixed(params.getSaveDir(),
Integer.parseInt(textWidth.getText()),
Integer.parseInt(textHeight.getText()),
Integer.parseInt(textDepth.getText()),
new Random().nextLong()
);
textSeed.setText("" + params.getSeed());
return params;
}
}

View File

@@ -0,0 +1,104 @@
package org.artisanlogiciel.games.stl;
public class Maze3dParams {
// grid size
int xl;
int yl;
int zl;
int w;
int lg;
int hg;
Wall3d south;
Wall3d west;
Wall3d north;
Wall3d east;
Wall3d highGround;
Wall3d lowGround;
// reverse : means that resolved path will be HighGround actual making maze more difficult to play with
boolean reverse;
// default
public Maze3dParams()
{
this(10,10,10, 1 , 1, 3, false);
}
// w width is wall thickness
public Maze3dParams(int xl, int yl, int zl, int w, int lg, int hg, boolean reverse)
{
this.xl = xl;
this.yl = yl;
this.zl = zl;
this.reverse = reverse;
int h = zl;
this.w = w;
this.lg = lg;
this.hg = hg;
south = new Wall3d(xl, w, h, 0, 0, 0);
west = new Wall3d(w, yl, h, 0, 0, 0);
north = new Wall3d(xl, w, h, 0, yl, 0);
east = new Wall3d(w, yl, h, xl, 0, 0);
highGround = new Wall3d(xl, yl, hg, 0, 0, 0);
lowGround = new Wall3d(xl, yl, lg, 0, 0, 0);
}
public boolean isReverse() {
return reverse;
}
public int getXl() {
return xl;
}
public int getYl() {
return yl;
}
public int getZl() {
return zl;
}
public Wall3d getSouth() {
return south;
}
public Wall3d getWest() {
return west;
}
public Wall3d getNorth() {
return north;
}
public Wall3d getEast() {
return east;
}
public Wall3d getHighGround() {
return highGround;
}
public Wall3d getLowGround() {
return lowGround;
}
public int getLg() {
return lg;
}
public int getHg() {
return hg;
}
public int getW() {
return w;
}
}

View File

@@ -11,114 +11,134 @@ import java.io.IOException;
/**
* Wall3d to create walls in 3d for stl conversion South, West North East...
*
* wall3D will create a rectangular cuboid with 2 triangle vertex for each face
**/
public class Wall3d
{
public class Wall3d {
// 4 triangles in 2 dim space reused 3 times
final static int BASE[][][] = { { { 0, 0 }, { 1, 0 }, { 0, 1 } }, { { 1, 0 }, { 1, 1 }, { 0, 1 } },
{ { 0, 0 }, { 1, 0 }, { 1, 1 } }, { { 0, 0 }, { 1, 1 }, { 0, 1 } } };
// in facts order matters...
final static int BASE[][][] = {
// lower left
{{0, 0}, {1, 0}, {0, 1}},
// higher right
{{1, 0}, {1, 1}, {0, 1}},
// lower right
{{0, 0}, {1, 0}, {1, 1}},
// higher left
{{0, 0}, {1, 1}, {0, 1}}};
final static short X = 1;
final static short Y = 2;
final static short Z = 4;
// final static short AXIS[][]= {{X,Y},{-Z,Y},{X,Y},{Z,Y},{X,-Z},{X,-Z}};
final static short AXIS[][] = { { X, Y, 0 }, { Z, Y, 0 }, { X, Y, 1 }, { Z, Y, 1 }, { X, Z, 0 }, { X, Z, 1 } };
public final static Wall3d South = new Wall3d(10, 1, 10, 0, 0, 0);
public final static Wall3d West = new Wall3d(1, 10, 10, 0, 0, 0);
public final static Wall3d North = new Wall3d(10, 1, 10, 0, 10, 0);
public final static Wall3d East = new Wall3d(1, 10, 10, 10, 0, 0);
public final static Wall3d HighGround = new Wall3d(10, 10, 3, 0, 0, 0);
public final static Wall3d LowGround = new Wall3d(10, 10, 2, 0, 0, 0);
// [face][axis]
final static short AXIS[][] = {
// face 0 (x,y) back
{X, Y, 0},
// face 1 (z,y) left
{Z, Y, 0},
// face 2 (x,y,1)
{X, Y, 1},
// face 3
{Z, Y, 1},
// face 4
{X, Z, 0},
// face 5
{X, Z, 1}};
final static String normalx = "1.0 0.0 0.0";
final static String normaly = "0.0 1.0 0.0";
final static String normalz = "0.0 0.0 1.0";
final static String normalmx = "-1.0 0.0 0.0";
final static String normalmy = "0.0 -1.0 0.0";
final static String normalmz = "0.0 0.0 -1.0";
// final static short NORMAL[] = {Z,X,Z,X,Y,Y};
final static String normalstr[] =
{ normalmz, normalx,
normalz, normalmx,
normaly, normalmy
};
boolean reverse_vertex[] = {
true,false,false,true,false,true
};
int triangle[][][] = null;
public Wall3d(int t[][][])
{
public Wall3d(int t[][][]) {
triangle = t;
}
public Wall3d(Wall3d origin, int dx, int dy, int dz)
{
public Wall3d(Wall3d origin, int dx, int dy, int dz) {
triangle = origin.translate(dx, dy, dz);
}
Wall3d(int xl, int yl, int zl, int dx, int dy, int dz)
{
Wall3d(int xl, int yl, int zl, int dx, int dy, int dz) {
int f = 0;
triangle = new int[12][3][3];
int[] factor = { xl, yl, zl };
int[] translate = { dx, dy, dz };
for (int i = 0; i < 12; i++)
{
// point in a triangle
for (int p = 0; p < 3; p++)
{
int[] factor = {xl, yl, zl};
int[] translate = {dx, dy, dz};
for (int facet = 0; facet < 12; facet++) {
// point in a triangle / facet
for (int p = 0; p < 3; p++) {
short uaxis = 0;
for (int axis = 0; axis < 2; axis++)
{
short caxis = AXIS[i / 2][axis];
if (caxis > 0)
{
// a square face is two facets.
int face = facet / 2;
// first two axis ( projected on x,y,z depending on AXIS[face][] )
for (int axis = 0; axis < 2; axis++) {
short caxis = AXIS[face][axis];
if (caxis > 0) {
f = 1;
}
else if (caxis < 0)
{
} else if (caxis < 0) {
// wait wait in AXIS there is no negative value ...
// so we never enter here, what was the purpose ? might be history.
f = -1;
caxis = (short) -caxis;
}
// what if caxis == 0 ? f is kept as its previous value ?
// which is 1 in facts due to AXIS[..][0] > 0
// uaxis keep track of used axes for this face to find last missing axis
uaxis |= caxis;
if (caxis == X)
{
if (caxis == X) {
caxis = 0;
}
else if (caxis == Y)
{
} else if (caxis == Y) {
caxis = 1;
}
else
{
} else {
caxis = 2;
}
// if ( f == 0 )
// {
// System.out.println("ERROR");
// }
// System.out.println("i " + i + " p " + p + " a " + caxis +
// " , " + BASE[i%4][p][axis] );
triangle[i][p][caxis] = translate[caxis] + BASE[i % 4][p][axis] * f * factor[caxis];
triangle[facet][p][caxis] = translate[caxis] + BASE[facet % 4][p][axis] * f * factor[caxis];
}
if ((uaxis & X) == 0)
{
// last remaining axis
if ((uaxis & X) == 0) {
// no X was used => X
uaxis = 0;
}
else if ((uaxis & Y) == 0)
{
} else if ((uaxis & Y) == 0) {
// X was used byt not Y => Y
uaxis = 1;
}
else
{
} else {
// default X, and Y were used => Z
uaxis = 2;
}
triangle[i][p][uaxis] = translate[uaxis] + AXIS[i / 2][2] * factor[uaxis];
triangle[facet][p][uaxis] = translate[uaxis] + AXIS[facet / 2][2] * factor[uaxis];
}
}
}
public int[][][] translate(int dx, int dy, int dz)
{
int[] translate = { dx, dy, dz };
public int[][][] translate(int dx, int dy, int dz) {
int[] translate = {dx, dy, dz};
int t[][][] = new int[12][3][3];
for (int i = 0; i < 12; i++)
{
for (int facet = 0; facet < 12; facet ++) {
// point in a triangle
for (int p = 0; p < 3; p++)
{
for (int axis = 0; axis < 3; axis++)
{
t[i][p][axis] = translate[axis] + triangle[i][p][axis];
for (int p = 0; p < 3; p++) {
for (int axis = 0; axis < 3; axis++) {
t[facet][p][axis] = translate[axis] + triangle[facet][p][axis];
}
}
}
@@ -127,22 +147,27 @@ public class Wall3d
}
/**
write triangles as stl text
* write triangles as stl text
**/
public String toString()
{
public String toString() {
String s = "";
for (int t = 0; t < 12; t++)
{
s += "facet normal 0 0 0\nouter loop\n";
for (int p = 0; p < 3; p++)
{
for (int facet = 0; facet < 12; facet++) {
int face = facet / 2;
// most software don't care normal but just rely on vertex order ( right hand ).
String normal = normalstr[face];
s += "facet normal " + normal + "\nouter loop\n";
boolean reverse = reverse_vertex[face];
for (int p = 0; p < 3; p++) {
s += "vertex";
for (int a = 0; a < 3; a++)
// p that accept right hand
int rhp = p;
if ( reverse )
{
// s+=" t "+ t + " p " + p + " a " + a + "=" +
// triangle[t][p][a];
s += " " + triangle[t][p][a];
// reverse 2 and 1 ; 0 => 0, 1 => 2 , 2 => 1
rhp = ( p * 5 ) % 3;
}
for (int a = 0; a < 3; a++) {
s += " " + triangle[facet][rhp][a];
}
s += "\n";
}
@@ -151,94 +176,4 @@ public class Wall3d
return s;
}
public static void prepare()
{
System.out.println(South.toString());
System.out.println(East.toString());
System.out.println(North.toString());
System.out.println(West.toString());
}
public static void streamWallsOut(String name, LabyModel provider, OutputStream stream) throws IOException
{
int width = provider.getWidth();
int height = provider.getHeight();
int xl = 10;
int yl = 10;
int zl = 10;
// WARNING DOWN - UP reversed ( in 2D Y is oriented to lower, in 3D it
// is to upper ).
stream.write(("solid " + name + "\n").getBytes());
for (int x = 0; x < width; x++)
{
short walls = provider.getWalls(x, 0);
if ((walls & Brick.UP) != 0)
{
stream.write(new Wall3d(South, x * xl, 0, 0).toString().getBytes());
}
if ((walls & Brick.LEFT) != 0)
{
stream.write(new Wall3d(West, x * xl, 0, 0).toString().getBytes());
}
}
for (int y = 0; y < height; y++)
{
short walls = provider.getWalls(0, y);
if ((walls & Brick.LEFT) != 0)
{
stream.write(new Wall3d(West, 0, y * yl, 0).toString().getBytes());
}
for (int x = 0; x < width; x++)
{
// south and east
walls = provider.getWalls(x, y);
if ((walls & Brick.DOWN) != 0)
{
stream.write(new Wall3d(North, x * xl, y * yl, 0).toString().getBytes());
}
if ((walls & Brick.RIGHT) != 0)
{
stream.write(new Wall3d(East, x * xl, y * yl, 0).toString().getBytes());
}
short path = provider.getPath(x,y);
if ( ( path & LabyModel.SOLVED ) == LabyModel.SOLVED )
// if ( (walls & ( Brick.GOAL | Brick.ENTRY ) ) == 0 )
{
// if ( ( (x+y) % 2) == 0 )
stream.write(new Wall3d(LowGround, x * xl, y * yl, 0).toString().getBytes());
}
else
{
stream.write(new Wall3d(HighGround, x * xl, y * yl, 0).toString().getBytes());
}
}
}
stream.write("endsolid wall\n\n".getBytes());
}
public static void main(String args[])
{
Scanner console = new Scanner(System.in);
int xl = console.nextInt();
int yl = console.nextInt();
int zl = console.nextInt();
int dx = console.nextInt();
int dy = console.nextInt();
int dz = console.nextInt();
String s = "solid wall\n";
Wall3d instance = new Wall3d(xl, yl, zl, dx, dy, dz);
prepare();
s += "endsolid wall\n\n";
System.out.println(s);
}
}

View File

@@ -0,0 +1,93 @@
package org.artisanlogiciel.games.stl;
import org.artisanlogiciel.games.Brick;
import org.artisanlogiciel.games.LabyModel;
import java.io.IOException;
import java.io.OutputStream;
public class Wall3dStream
{
String name;
LabyModel provider;
OutputStream stream;
Maze3dParams params;
/**
*
* @param name
* @param provider
* @param stream
* @param params
*/
public Wall3dStream(String name, LabyModel provider, OutputStream stream, Maze3dParams params)
{
this.name = name;
this.provider = provider;
this.stream = stream;
this.params = params;
}
private void writeWall3D(Wall3d wall3d)
throws IOException
{
stream.write(wall3d.toString().getBytes());
}
public void stream() throws IOException {
int width = provider.getWidth();
int height = provider.getHeight();
int xl = params.getXl();
int yl = params.getYl();
int zl = params.getZl();
boolean reverse = params.isReverse();
// WARNING DOWN - UP reversed ( in 2D Y is oriented to lower, in 3D it
// is to upper ).
stream.write(("solid " + name + "\n").getBytes());
for (int x = 0; x < width; x++) {
short walls = provider.getWalls(x, 0);
if ((walls & Brick.UP) != 0) {
writeWall3D(new Wall3d(params.getSouth(), x * xl, 0, 0));
}
if ((walls & Brick.LEFT) != 0) {
writeWall3D(new Wall3d(params.getWest(), x * xl, 0, 0));
}
}
for (int y = 0; y < height; y++) {
short walls = provider.getWalls(0, y);
if ((walls & Brick.LEFT) != 0) {
writeWall3D(new Wall3d(params.getWest(), 0, y * yl, 0));
}
for (int x = 0; x < width; x++) {
// south and east
walls = provider.getWalls(x, y);
if ((walls & Brick.DOWN) != 0) {
writeWall3D(new Wall3d(params.getNorth(), x * xl, y * yl, 0));
}
if ((walls & Brick.RIGHT) != 0) {
writeWall3D(new Wall3d(params.getEast(), x * xl, y * yl, 0));
}
short path = provider.getPath(x, y);
// where resolved path is leaked to stl model.
Wall3d ground = reverse ? params.getLowGround() : params.getHighGround();
if ((path & LabyModel.SOLVED) == LabyModel.SOLVED)
// if ( (walls & ( Brick.GOAL | Brick.ENTRY ) ) == 0 )
{
// if ( ( (x+y) % 2) == 0 )
ground = reverse ? params.getHighGround() : params.getLowGround();
}
writeWall3D(new Wall3d(ground, x * xl, y * yl, 0));
}
}
stream.write("endsolid wall\n\n".getBytes());
stream.flush();
}
}