Java-ME is a lightweight 3D graphics engine for Java based applications. It allows for improved rendering, providing a managed framework to build stable applications.
Java-ME provides the following capabilities
- 2D Graphics
- 3D Graphics (Built from the ground up)
- Multi-Threaded Rendering
- Dynamic Event Handling
- Lights
- Basic GUI
- Color Library
- User Input (Keyboard and Mouse)
- Audio (Beta)
A basic rotating cube sample can be found below.
- studios.vanish.engine
- studios.vanish.utility
This API utilizes a Utility library (found in studios.vanish.utility
) that allows for improved event handling. This library was developed along side Java-ME. The Method
class takes in a string that represents a function name, and an object where the function can be found. You can later invoke this function with as many parameters as you like through the Invoke(Object... obj)
method. Invoke
forwards the parameters to the specified method, and returns the same value as the method invoked.
The EventHandler
class holds multiple Method
s, and allows one to invoke all of them at the same time through the InvokeAll(Object... obj)
method. Throughout the Matrix Graphics Engine, EventHandler
s are created so that the end user can specify what to do when a specific event occurs. An example of such is the OnPaint
method. When it is time to draw objects to the screen, every method in OnPaint
are invoked, allowing the user to render their own objects.
All of Java-ME's rendering capabilities are handled in the GraphicsUnit
class. A GraphicsUnit
object is automatically created when using the Window
class, and is sent for use through the OnPaint event. However, you can always create a GraphicsUnit
object, in case you want to use the 3D capabilities without initializing a Window
.
GraphicsUnit Graphics = new GraphicsUnit(Graphic, FieldOfView, Size, Resolution, FillMode, Camera, CalculateIntersections, RenderLights);
Graphic
: The underlining graphics used, aGraphics2D
object in Java Swing.FieldOfView
: A value that specifies how much of the 3D space is seen. 1024 is a good start.Size
: The size of theJFrame
, orWindow
Resolution
: The resolution used to draw the 3D componentsFillMode
: Either Solid, Wireframe, or Vertices. This specifies how to draw the 3D objects.Camera
: ACamera
object that specifies the user viewport.CalculateIntersections
: Automatically calculate whether objects intersect, and render accordingly. (Unfortunately, this process is very resource heavy and slow if it does work at all).RenderLights
: Specify whether to enable light based rendering, or simply render based on object color.
Many of these parameters impact the way the 3D components are drawn. GraphicsUnit
has the capability to perform many 3D calculations that are useful to rendering, but are sometimes useful when updating a scene. Therefore, a useful GetNullGraphics
method can be found in the Window
class, which creates a GraphicsUnit
object without the rendering capabilities.
GraphicsUnit Graphics = window.GetNullGraphicsUnit();
Instead of manually creating a JFrame
window, Java-ME handles it through the Window
class. Thus, you can use Java-ME as the underlining framework for your application, as everything needed to render to the screen is already handled.
Window window = new Window("Java Matrix Engine", new Size(800, 600), true); //specify the name, size, and border style
The next lines initialize the graphical components that the window class uses by specifying the framerate, and shows the window. Initialize3D
only needs to be called if you are going to render 3D components.
window.Initialize(60); //specify the framerate
window.Initialize3D(new Size(800, 600), 1024, FillMode.Solid, false, false); //specify resolution, field of view, fill mode, calculate intersections (=false), automatically render all 3D objects
window.Show();
window.Initialize3D();
To draw to the screen, you need to handle the OnPaint event.
window.OnPaint.Add(this, "Render"); //specify the object, and the function's name
Don't forget to create the coinciding method. Remember that the method name must match the name you added to the OnPaint
event handler. The method must also be public so that it can be accessed externally, and the parameters must correctly match the ones that the OnPaint method sends. In this case, OnPaint
only sends one parameter.
public void Render(GraphicsUnit Graphics) //The Render method that will be called
Here is a sample rotating cube application.
public class Program
{
Object3D cube = new Object3D();
Window window = new Window("Java Matrix Engine", new Size(800, 600), true);
public static void main(String[] args)
{
new Program();
}
public Program()
{
Initialize(60);
while (true)
{
Update();
window.Wait(2);
}
}
public void Initialize(int FPS)
{
window.OnPaint.Add(this, "Render");
window.Initialize(FPS);
window.Initialize3D(new Size(800, 600), 1024, FillMode.Wireframe, false, true);
window.Show();
cube.Vertices = new Vertex[]{
new Vertex(-1, +1, -1), new Vertex(+1, +1, -1), new Vertex(+1, -1, -1), new Vertex(-1, -1, -1),
new Vertex(-1, +1, +1), new Vertex(+1, +1, +1), new Vertex(+1, -1, +1), new Vertex(-1, -1, +1)};
cube.Indices = new Index[]{
new Index(0, 1, 2, 3), new Index(4, 5, 6, 7),
new Index(0, 1, 5, 4), new Index(2, 3, 7, 6),
new Index(1, 2, 6, 5), new Index(0, 3, 7, 4)};
cube.Colors = new Color[]{
Color.Orange, Color.Green,
Color.Blue, Color.Yellow,
Color.Red, Color.Pink};
cube.Location = new Vertex(0, 0, 5);
}
public void Update()
{
cube.Rotation.X += 0.1;
cube.Rotation.Y += 0.1;
}
public void Render(GraphicsUnit Graphics)
{
Graphics.FillRectangle(Color.Black, new Point(0, 0), window.Size);
cube.Render(Graphics);
}
}
Unfortunately, I never planned on releasing this when I first embarked on making a 3D enabled engine for Java. Therefore, I need some time to make proper documentation to make this API easy to use. As of right now, there is a preliminary guide below, which will be able to get you started.
Java-ME comes with a list of predefined colors. All of these colors were taken from Rapid Tables.
You can create your own colors
Color color = new Color(255, 255, 255); //R, G, B
Color color = new Color(255, 255, 255, 255); //R, G, B, A
Instead of a basic solid color, this color type represents a linear gradient. You can send ColorLinearGradient
colors to any render method, and it will be draw as a gradient. To create a ColorLinearGradient
, you must specify a couple of things.
ColorLinearGradient col = new ColorLinearGradient(2); //How many times are you going to change the color?
col.Set(0, new Point(0, 0), Color.Black); //Where is the first color, and what is that color?
col.Set(1, new Point(800, 500), Color.Blue); //Where is the second color, and what is that color?
A 2D point, with an X and Y.
Similar to a 2D point, except with Width, and Height.
A 3D Point, with X, Y, and Z.
GraphicsUnit
has a couple of methods that can be used to draw things. Note that Java-ME also comes with shapes that can also be used to draw. Further examples of this can be found below.
The identifier before the basic rendering methods specifies whether or not to render the shape as a solid object or as a bordered object. Fill
renders it as a solid, while Draw
render it as an outline.
This draws Text
to the screen, in Color
at Location
in the Font
specified. Note that Font
is not in Java-ME, but is a default Java class (found at java.awt.Font
).
This draws a line between two points in the color specified. Note that you can send more than two points, but only the first two points will be used when drawing the line.
This draws a rectangle at Location.X
and Location.Y
, with size Size.Width
and Size.Height
, in Color
.
This draws an ellipse at Location.X
and Location.Y
, with size Size.Width
and Size.Height
, in Color
. If you want to draw a circle, set Size.Width = Size.Height
.
This draws any polygon. Specify the points that make up the polygon, and give it a Color
.
Java-ME comes with an abstract Shape
class, that specifies an Intersects
and Render
method. The two basic objects that implement this are
- Rectangle
- Circle
You can render a rectangle by using the rectangle class.
Rectangle rectangle;
rectangle.Initialize(Color.Black, new Point(0, 0), new Size(500, 500));
rectangle.Render(Graphics);
You can do hit-detection by calling the Intersects
method.
if (shape1.Intersects(shape2))
{
//do something special, because the objects have collided
}
else
{
//don't do something special, because the objects aren't colliding yet
}
All of the 3D methods in GraphicsUnit
have the D3D_
identifier before them. This differentiates the 3D capabilities of the graphics library from the 3D. Note that the 3D engine is still heavily based upon the 2D framework.
To render a 3D object effectively, use the Object3D
class. This will ensure that any object rendered exactly as specified and that they will be rendered according to their Z axis, as this will automatically implement a Z Buffer. Transformations will also be self-contained, easy to manage, and fast. To create an Object3D
, you need to specify the object's faces, and colors.
When creating an object, you need to specify every vertex that will be used. Identify these vertices within the vertices array object.
object.Vertices = new Vertex[]
{
//Include every single vertex here
};
Next, you define a face through the Indices array object. An Index
object takes as many integer values as it takes to define a face. It takes at minimum 4 vertices to define a face. Each integer value in Index
corresponds to the index value of the vertex.
object.Indices = new Index[]
{
//Include every face here
};
Finally, you need to define the color for each face. Note that the following condition must be met: object.Colors.length = object.Indices.length
.
object.Colors = new Color[]
{
//Include the colors of each face here
};
The following code will generate a 3D Cube.
Object3D object = new Object3D();
object.Vertices = new Vertex[]
{
new Vertex(-1, +1, -1), new Vertex(+1, +1, -1), new Vertex(+1, -1, -1), new Vertex(-1, -1, -1),
new Vertex(-1, +1, +1), new Vertex(+1, +1, +1), new Vertex(+1, -1, +1), new Vertex(-1, -1, +1)
};
object.Indices = new Index[]
{
new Index(0, 1, 2, 3), new Index(4, 5, 6, 7),
new Index(0, 1, 5, 4), new Index(2, 3, 7, 6),
new Index(1, 2, 6, 5), new Index(0, 3, 7, 4)
};
obj1.Colors = new Color[]
{
new Color(Color.Orange, 100), new Color(Color.Green, 100),
new Color(Color.Blue, 100), new Color(Color.Yellow, 100),
new Color(Color.Red, 100), new Color(Color.Pink, 100)
};
Finally, render the object by using the render method.
object.Render(Graphics); //where Graphics is a GraphicsUnit object
If in Initialize3D
, you disable AutomaticRender, you need to manually render the 3D objects.
Graphics.Render(); //where Graphics is a GraphicsUnit object
Each Object3D
object comes with variables that specify transformations.
object.Location = new Vertex(0, 0, 10); //translates the object
object.Rotation = new Vertex(10, 10, 10); //rotates the object
object.Scale = new Vertex(1, 1, 1); //scales the object. Values between 0 and 1 make it smaller, while values greater than 1 make it larger
object.Revolution = new Vertex(10, 10, 10); //revolves the object around its location. Note that this only works when RevolutionRadius is specified
object.RevolutionRadius = new Vertex(0, 4, 0); //specifies how to revolve the object
Java-ME comes with a special Object3D
class called Sphere
, which automatically generates the vertices and indices for a sphere or cylinder.
Object3D sphere = new Sphere(10, 10, false, Color.White); //generate a sphere with 10 by 10 definition
Object3D cylinder = new Sphere(10, 10, true, Color.White); //generate a cylinder with 10 by 10 definition
This converts any 3D point, or Vertex
, into a 2D point so that it can be drawn onto the screen. It essentially projects any 3D point onto the screen. Note that this returns a Vertex
, instead of a simple Point
. The Z value remains the same.
Vertex D3D_FromProjection(Point point, Size resolution, Size windowSize, double FieldOfView, double CameraZ)
This goes the other way. It converts a 2D point into 3D, given the screens resolution, the size of the window, the output's field of view, and the Z value (this is normally the camera's Z location)
This transfers any Vertex
by Location
This rotates any Vertex
by Rotation
. Note that this only uses the X value.
This rotates any Vertex
by Rotation
. Note that this only uses the Z value.
This rotates any Vertex
by Rotation
. Note that this only uses the Y value.