/*
* MegaMek -
* Copyright (C) 2000,2001,2002,2003,2004,2005,2006 Ben Mazur (bmazur@sev.org)
*
* This file (C) 2008 J�rg Walter <j.walter@syntax-k.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package megamek.client.ui.AWT.boardview3d;
import java.util.List;
import javax.media.j3d.Appearance;
import javax.media.j3d.BoundingBox;
import javax.media.j3d.Link;
import javax.media.j3d.Material;
import javax.media.j3d.Shape3D;
import javax.media.j3d.SharedGroup;
import javax.media.j3d.Texture;
import javax.media.j3d.TextureAttributes;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.TransparencyAttributes;
import javax.vecmath.*;
import megamek.client.ui.Messages;
import megamek.client.ui.AWT.GUIPreferences;
import megamek.common.Coords;
import megamek.common.IGame;
import megamek.common.IHex;
import megamek.common.Minefield;
import megamek.common.Player;
import megamek.common.Terrains;
class BoardHexModel extends HexModel {
private static final Material normal = new Material(C.grey90, C.black, C.grey90, C.black, 1.0f);
private static final Material normalWater = new Material(C.grey75, C.black, C.grey75, C.white, 128.0f);
private static final Material night = new Material(C.grey25, C.black, C.grey25, C.black, 1.0f);
private static final Material dark = new Material(C.grey10, C.black, C.grey10, C.black, 1.0f);
private static final Material side = new Material(C.plain, C.black, C.plain, C.black, 1.0f);
private static final Material sideWater = new Material(C.water, C.black, C.water, C.black, 1.0f);
private static final int KEEP = 3;
Shape3D floor;
Shape3D surface;
IHex hex;
Material current = normal;
IGame game;
public static SharedGroup[] mkShared() {
SharedGroup[] shafts = new SharedGroup[2];
// sides of hex
Appearance sapp;
Shape3D sh;
sapp = new Appearance();
sapp.setMaterial(side);
sh = new Shape3D(shaft, sapp);
sh.setPickable(false);
shafts[0] = new SharedGroup();
shafts[0].addChild(sh);
sapp = new Appearance();
sapp.setMaterial(sideWater);
sh = new Shape3D(shaft, sapp);
shafts[1] = new SharedGroup();
shafts[1].addChild(sh);
return shafts;
}
public BoardHexModel(IGame g, Coords c, IHex h, TileTextureManager tileManager, SharedGroup shafts[]) {
game = g;
hex = h;
Appearance base = new Appearance();
base.setMaterial(normal);
floor = new Shape3D(polygon, base);
floor.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
floor.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
floor.setPickable(true);
addChild(floor);
addChild(new Link(hex.depth() > 0?shafts[1]:shafts[0]));
setUserData(new Coords(c));
ypos = 0;
addText(""+c.getBoardNum(), new Color3f(GUIPreferences.getInstance().getMapTextColor()));
final Point3d hexLoc = BoardModel.getHexLocation(c, h.floor());
setTransform(new Transform3D(C.nullRot, new Vector3d(hexLoc), 1.0));
// Water surface
if (surface == null && hex.depth() > 0) {
TransformGroup sTrans = new TransformGroup(new Transform3D(C.nullRot, new Vector3d(0.0, 0.0, hex.depth()*BoardModel.HEX_HEIGHT), 1.0));
surface = new Shape3D(polygon);
surface.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
surface.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
surface.setPickable(true);
setSurfaceEffect(current, tileManager.getTexture(h, 2/3f));
sTrans.addChild(surface);
addChild(sTrans);
}
}
public void update(IHex h, TileTextureManager tileManager, Player localPlayer) {
hex = h;
Color3f col = new Color3f(GUIPreferences.getInstance().getMapTextColor());
ypos = 1;
// This is a bit convoluted in order to reduce work done on a full update,
// which happens fairly often.
Texture tex = tileManager.getTexture(hex, 1.0f);
if (tex != floor.getAppearance().getTexture()) {
setEffect(current, tex);
}
int keep = (surface == null?KEEP:KEEP+1);
for (int i = numChildren()-1; i >= keep; i--) removeChild(i);
// mine fields
if (game.containsMinefield((Coords)getUserData())){
Coords c = (Coords)getUserData();
Minefield mf = game.getMinefields(c).elementAt(0);
addChild(tileManager.getMinefieldSign());
int nbrMfs = game.getNbrMinefields(c);
if (nbrMfs > 1) {
addText(Messages.getString("BoardView1.Multiple"), col); //$NON-NLS-1$
} else if (nbrMfs == 1) {
switch (mf.getType()) {
case Minefield.TYPE_CONVENTIONAL:
addText(Messages.getString("BoardView1.Conventional"), col); //$NON-NLS-1$
break;
case Minefield.TYPE_INFERNO:
addText(Messages.getString("BoardView1.Thunder-Inf") + mf.getDensity() + ")", col); //$NON-NLS-1$ //$NON-NLS-2$
break;
case Minefield.TYPE_ACTIVE:
addText(Messages.getString("BoardView1.Thunder-Actv") + mf.getDensity() + ")", col); //$NON-NLS-1$ //$NON-NLS-2$
break;
case Minefield.TYPE_COMMAND_DETONATED:
addText(Messages.getString("BoardView1.detonated"), col); //$NON-NLS-1$
addText(Messages.getString("BoardView1.Command-"), col); //$NON-NLS-1$
break;
case Minefield.TYPE_VIBRABOMB:
if (localPlayer != null && mf.getPlayerId() == localPlayer.getId())
addText(Messages.getString("BoardView1.Vibrabomb")+" (" + mf.getSetting() + ")", col); //$NON-NLS-1$ //$NON-NLS-2$
else
addText(Messages.getString("BoardView1.Vibrabomb"), col); //$NON-NLS-1$
break;
}
}
}
// smoke, fire, buildings
// FIXME: this needs much more detailed processing... but it is good enough for now
int ih = Math.max(hex.terrainLevel(Terrains.BLDG_ELEV), hex.terrainLevel(Terrains.BRIDGE_ELEV));
double height = Math.max(ih, Math.max(hex.terrainLevel(Terrains.SMOKE), hex.terrainLevel(Terrains.FIRE)))*BoardModel.HEX_HEIGHT;
if (height < 1.0) height = 1.0;
height += (hex.surface() - hex.floor()) * BoardModel.HEX_HEIGHT;
Transform3D supert = new Transform3D();
supert.setScale(new Vector3d(2*BoardModel.HEX_SIDE_LENGTH, BoardModel.HEX_DIAMETER, height));
supert.setTranslation(new Vector3d(0.0, 0.0, height/2));
TransformGroup superTrans = new TransformGroup(supert);
List<Shape3D> supers = tileManager.getModels(hex);
for (Shape3D sup : supers) {
superTrans.addChild(sup);
}
superTrans.setPickable(false);
addChild(superTrans);
// wood
if (Math.max(hex.terrainLevel(Terrains.WOODS), hex.terrainLevel(Terrains.JUNGLE)) > 0) {
supert = new Transform3D();
supert.setScale(new Vector3d(2*BoardModel.HEX_SIDE_LENGTH, BoardModel.HEX_DIAMETER, 2*BoardModel.HEX_HEIGHT));
supert.setTranslation(new Vector3d(0.0, 0.0, BoardModel.HEX_HEIGHT));
superTrans = new TransformGroup(supert);
superTrans.addChild(tileManager.getModel(hex));
superTrans.setPickable(false);
addChild(superTrans);
}
setBounds(new BoundingBox(
new Point3d(-BoardModel.HEX_SIDE_LENGTH, -BoardModel.HEX_DIAMETER/2, BoardModel.HEX_HEIGHT*hex.floor()),
new Point3d(BoardModel.HEX_SIDE_LENGTH, BoardModel.HEX_DIAMETER/2, height)
));
if (hex.getElevation() != 0) addText(Messages.getString("BoardView1.LEVEL") + hex.getElevation(), col);
if (hex.depth() != 0) addText(Messages.getString("BoardView1.DEPTH") + hex.depth(), col);
if (ih > 0) addText(Messages.getString("BoardView1.HEIGHT") + ih,
new Color3f(GUIPreferences.getInstance().getColor("AdvancedBuildingTextColor")));
}
private void setSurfaceEffect(Material mat, Texture tex) {
Appearance app = new Appearance();
app.setTexture(tex);
app.setMaterial((mat == normal?normalWater:mat));
app.setTransparencyAttributes(new TransparencyAttributes(TransparencyAttributes.BLENDED, 0.0f));
app.setPolygonAttributes(C.noCull);
app.setTextureAttributes(C.materialModulate);
surface.setAppearance(app);
}
private void setEffect(Material mat, Texture tex) {
current = mat;
Appearance app = new Appearance();
app.setTexture(tex);
app.setMaterial(current);
app.setTextureAttributes(new TextureAttributes(TextureAttributes.MODULATE, new Transform3D(), new Color4f(), TextureAttributes.NICEST));
floor.setAppearance(app);
if (surface != null) setSurfaceEffect(mat, surface.getAppearance().getTexture());
}
void setEffect(Material mat) {
setEffect(mat, floor.getAppearance().getTexture());
}
public void darken() {
setEffect(dark);
}
public void night() {
setEffect(night);
}
public void reset() {
setEffect(normal);
}
private int ypos = 0;
private final void addText(String s, Color3f col) {
Transform3D t = new Transform3D();
t.setTranslation(new Vector3d(0.0, -BoardModel.HEX_DIAMETER/3-3.5+ypos*2.75, hex.depth()*BoardModel.HEX_HEIGHT));
TransformGroup tg = new TransformGroup(t);
tg.addChild(new LabelModel(s, col, null, LabelModel.BIG));
addChild(tg);
ypos++;
}
}