📄 context3d.java
字号:
// Copyright (c) 2005 Sony Ericsson Mobile Communications AB
//
// This software is provided "AS IS," without a warranty of any kind.
// ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
// INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
//
// THIS SOFTWARE IS COMPLEMENTARY OF JAYWAY AB (www.jayway.se)
package bluegammon.gui;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.m3g.Appearance;
import javax.microedition.m3g.Camera;
import javax.microedition.m3g.Graphics3D;
import javax.microedition.m3g.Image2D;
import javax.microedition.m3g.IndexBuffer;
import javax.microedition.m3g.Light;
import javax.microedition.m3g.Material;
import javax.microedition.m3g.Texture2D;
import javax.microedition.m3g.Transform;
import javax.microedition.m3g.TriangleStripArray;
import javax.microedition.m3g.VertexArray;
import javax.microedition.m3g.VertexBuffer;
import bluegammon.Resources;
/**
* <p>The 3d context used in this game. Consists of the scene which is
* a camera with one main headlight; and dice, string or piece objects.
* Also contains functionality for creating objects and defining materials.
* We only have one 3d context, thus the singleton pattern.</p>
* <p>
* <p>
* The dice and the piece is constructed mathematically based on the
* JSR184 specifications.
* </p>
* <p>
* The piece is constructed from a number of predefined pie-slices. The greater amount
* of slices, the more circular piece - but also the amount of triangles per piece will increase,
* impacting the performance. Each piece consists of 4 * numberOfSlices triangles.
* </p>
* <br><br>
* <img border="0" align="center" src="Slice3d.png"/><br><br>
* <p>
* The dice is calculated using a somewhat more complicated model. Each dice consists of
* 6 * 6 faces + 8 corners = 44 triangles.</p>
* <p>
* A graphical representation of how one face of the dice is calculated is depicted below:<br><br>
* <img border="0" align="center" src="Dice3d.png"/><br><br>
* </p>
*
* @author Peter Andersson
*/
public class Context3D
{
/** Field of view, degrees on horizontal axis */
public static final float FOVY = 35f;
/** Z-axis near clipping plane */
public static final float NEAR_CLIPPING_PLANE = 1f;
/** Z-axis far clipping plane */
public static final float FAR_CLIPPING_PLANE = 512f;
/** The camera of the scene */
protected Camera m_camera;
/** The position and direction of the camera */
protected Transform m_cameraTransform;
/** The light of the scene */
protected Light m_light;
/** The position and direction of the light*/
protected Transform m_lightTransform;
/** Appearence cahce */
protected Appearance[] m_appearances = new Appearance[2];
/** Texture cache */
protected Texture2D[] m_textures = new Texture2D[2];
/** Dice vertex buffer cache */
protected VertexBuffer m_diceVertBuffer;
/** Dice index buffer cache */
protected IndexBuffer m_diceIndexBuffer;
/** Piece vertex buffer cache */
protected VertexBuffer m_pieceVertBuffer;
/** Piece index buffer cache */
protected IndexBuffer m_pieceIndexBuffer;
/** Quick and dirty screen to 3d coordinate transformation factor */
protected double m_scr2ThreeD;
/** Quick and dirty 3d to screen coordinate transformation factor */
protected double m_threeD2Scr;
/** Width of screen */
protected int m_width;
/** Height of screen */
protected int m_height;
/** Half width of screen */
protected int m_halfWidth;
/** Half height of screen */
protected int m_halfHeight;
/** Singleton instance */
protected static Context3D m_inst = null;
/** Light source rotation around Y axis */
protected static final float LIGHT_ROT = 33f;
/** Tangens for light source rotation */
protected static final double TAN_LIGHT_ROT = Math.tan(Math.toRadians(LIGHT_ROT));
/** Number of slices in a piece */
protected static final int PIECE_SLICES = 10;
/** Unity value in 3D coordinates */
protected static final short UNITY = Short.MAX_VALUE / 8;
/**
* Returns singleton instance.
* @return The singleton instance.
*/
public static Context3D getInstance()
{
if (m_inst == null)
{
m_inst = new Context3D();
}
return m_inst;
}
/**
* Sets up our viewport, camera, lighting - everyting needed for the scene
* @param width The width of the viewport
* @param height The height of the viewport
*/
public void init(int width, int height)
{
m_width = width;
m_height = height;
m_halfWidth = width / 2 - 1;
m_halfHeight = height / 2 - 1;
// create a camera
m_camera = new Camera();
m_camera.setPerspective(
FOVY, // field of view
(float)width / (float)height, // aspectRatio
NEAR_CLIPPING_PLANE,
FAR_CLIPPING_PLANE);
// camera transform matrix
m_cameraTransform = new Transform();
m_cameraTransform.setIdentity();
m_cameraTransform.postTranslate(0f, 0f, 1f);
// create a light
m_light = new Light();
m_light.setColor(0xffffff);
m_light.setIntensity(1.1f);
m_light.setMode(Light.DIRECTIONAL);
// ligth transform matrix - shine from near right to far left
m_lightTransform = new Transform();
m_lightTransform.setIdentity();
m_lightTransform.postTranslate(0f, 0f, 10f);
m_lightTransform.postRotate(LIGHT_ROT, 0f, 1f, 0f);
// transformation factors
double factor = 2.15; // Magic 3d factor, works for K750 when calculating
// 2d-3d and 3d-2d coordinate transformations.
// This factor might need to be altered on bigger screens.
double tanFovY = Math.tan(Math.toRadians(FOVY));
m_threeD2Scr = factor * (double)height / (2d * tanFovY);
m_scr2ThreeD = 2d * tanFovY / (factor * (double)height);
}
/**
* Recalculates a x 3d coordinate to a screen x coordinate.
* @param coordinate3D The 3d x coordinate
* @param z The depth of the 3d coordinate
* @return The screen coordinate
*/
public float toScreenCoordinateX(float coordinate3D, float z)
{
return (float)(-coordinate3D * m_threeD2Scr / z);
}
/**
* Recalculates a screen x coordinate to a 3d x coordinate.
* @param coordinateScreen The screen x coordinate
* @param z The depth of the 3d coordinate
* @return The 3d x coordinate
*/
public float to3DCoordinateX(float coordinateScreen, float z)
{
return (float)((-coordinateScreen + m_halfWidth) * m_scr2ThreeD * z);
}
/**
* Recalculates a 3d y coordinate to a screen y coordinate.
* @param coordinate3D The 3d y coordinate
* @param z The depth of the 3d coordinate
* @return The screen y coordinate
*/
public float toScreenCoordinateY(float coordinate3D, float z)
{
return (float)(coordinate3D * m_threeD2Scr / z);
}
/**
* Recalculates a screen y coordinate to a 3d y coordinate.
* @param coordinateScreen The screen y coordinate
* @param z The depth of the 3d coordinate
* @return The 3d y coordinate
*/
public float to3DCoordinateY(float coordinateScreen, float z)
{
return (float)((coordinateScreen - m_halfHeight) * m_scr2ThreeD * z);
}
/**
* Returns delta x coordinate of shadow position given
* specified delta z between object and projection plane.
* @param deltaZ The difference in z between object
* and shadow projecton plane.
* @return Delta x coordinate in 3d units.
*/
public float getShadowProjectionDeltaX(float deltaZ)
{
if (deltaZ == 0)
{
return 0;
}
else
{
return (float)(Math.abs(deltaZ) * TAN_LIGHT_ROT);
}
}
/**
* Binds a graphics context and set up the common
* 3d environment used in this game.
*
* @param g The graphics environment to render upon.
* @return A Graphics3D object with common 3d environment settings.
*/
public Graphics3D bindScene(Graphics g)
{
Graphics3D g3d = Graphics3D.getInstance();
// Use dithering and true-color, no z-buffering
g3d.bindTarget(g, false, Graphics3D.DITHER | Graphics3D.TRUE_COLOR);
g3d.setCamera(m_camera, m_cameraTransform);
g3d.resetLights();
g3d.addLight(m_light, m_lightTransform);
return g3d;
}
/**
* Creates an rgb buffer rendered a shadow that is transparant.
*
* @param size Shadow size
* @param sizeDim Blank border.
* @return An rgb buffer containing a transparant shadow
*/
public static int[] createShadowRGB(int size, int sizeDim)
{
int[] shadow = new int[size * size];
Image shadowImg = Image.createImage(size, size);
Graphics g = shadowImg.getGraphics();
g.setColor(0xff0000);
g.fillRect(0, 0, size * 2, size * 2);
for (int i = 0; i < 4; i++)
{
g.setColor((i + 1) << 4);
g.fillArc(i + sizeDim, i + sizeDim,
size - 2 * (i + sizeDim),
size - 2 * (i + sizeDim),
0, 360);
}
shadowImg.getRGB(shadow, 0, size,
0, 0, size, size);
for (int i = 0; i < shadow.length; i++)
{
if ((shadow[i] & 0x00ffffff) == 0xff0000)
{
shadow[i] = 0x00000000; // totally transparant
}
else
{
// calculate semitransparancy depending on shadow color
int trans = ((shadow[i] & 0x000000ff) << 56) & 0xff000000;
shadow[i] = trans;
}
}
return shadow;
}
/**
* Returns the appearance (texture and material) for a piece.
* @param white true for white appearance, false for black appearance.
* @return The piece appearance.
*/
public Appearance getPieceAppearance(boolean white)
{
return getDiceAppearance(white); // Pieces and dices are of the same material
}
/**
* Returns the appearance (texture and material) for a dice.
* @param white true for white appearance, false for black appearance.
* @return The dice appearance.
*/
public Appearance getDiceAppearance(boolean white)
{
int index = white ? 0:1;
if (m_appearances[index] == null)
{
Material material = new Material();
material.setColor(Material.AMBIENT, 0x606060);
material.setColor(Material.DIFFUSE, 0xf0e8e0);
material.setColor(Material.SPECULAR, 0xffffff);
material.setShininess(50.0f);
m_appearances[index] = new Appearance();
m_appearances[index].setTexture(0, getTexture(white));
m_appearances[index].setMaterial(material);
}
return m_appearances[index];
}
/**
* Returns the textures used within this game.
* @param white true for white textures, false for black textures.
* @return the texture.
*/
public Texture2D getTexture(boolean white)
{
int index = white ? 0:1;
if (m_textures[index] == null)
{
Image2D image2D = null;
if (white)
{
image2D = new Image2D(Image2D.RGB, Resources.getImage(Resources.IMG_WHITE_TEXTURES));
}
else
{
image2D = new Image2D(Image2D.RGB, Resources.getImage(Resources.IMG_BLACK_TEXTURES));
}
// create the Texture2D and enable mipmapping
// texture color is to be modulated with the lit material color
m_textures[index] = new Texture2D(image2D);
m_textures[index].setFiltering(Texture2D.FILTER_LINEAR, Texture2D.FILTER_LINEAR);
m_textures[index].setWrapping(Texture2D.WRAP_CLAMP, Texture2D.WRAP_CLAMP);
m_textures[index].setBlending(Texture2D.FUNC_MODULATE);
}
return m_textures[index];
}
/**
* Returns vertexbuffer for a piece.
* @return a piece vertex buffer
*/
public VertexBuffer getPieceVertexBuffer()
{
if (m_pieceVertBuffer == null)
{
calculatePieceBuffers();
}
return m_pieceVertBuffer;
}
/**
* Returns indexbuffer for a piece.
* @return a piece index buffer
*/
public IndexBuffer getPieceIndexBuffer()
{
if (m_pieceIndexBuffer == null)
{
calculatePieceBuffers();
}
return m_pieceIndexBuffer;
}
/**
* Returns vertexbuffer for a dice.
* @return a dice vertex buffer
*/
public VertexBuffer getDiceVertexBuffer()
{
if (m_diceVertBuffer == null)
{
calculateDiceBuffers();
}
return m_diceVertBuffer;
}
/**
* Returns index buffer for a dice.
* @return a dice index buffer
*/
public IndexBuffer getDiceIndexBuffer()
{
if (m_diceIndexBuffer == null)
{
calculateDiceBuffers();
}
return m_diceIndexBuffer;
}
/**
* Calculates piece vertex- and indexbuffers.
*/
protected void calculatePieceBuffers()
{
int slices = PIECE_SLICES;
short I = UNITY; // Unit value
short H = (short)(I / 8); // Heigth of piece is 2*diameter/8
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -