I'm working on a Java program with Processing library, that plots/draws millions of galaxies (the coordinates do not change) in 3D-space (as simple points) and allows translating, rotating and scaling the view in real time.
I'm using Processing to have GPU acceleration on rendering the view, but the points have to be given to the graphics card by the CPU anyway. So currently my draw() method contains a for loop which "draws" the points one by one. Since nothing about the points changes, only the camera angle, position and scale, it is too slow for my needs.
Current draw():
transformSpace();
for (int i = 0; i < visibleBodies.length; i++) {
Body b = visibleBodies[i];
point(b.x, -b.z, -b.y); // Z-up world
}
Could all the points be handled somehow differently, so draw() wouldn't have to contain a massive loop? I've been unsuccessful in trying to find a way to feed the coordinates to the GPU in a separate one-time process or make all the data one big object.
You could draw the to a PGraphics ahead of time, and then just draw that PGraphics when you want to draw your bodies.
PGraphics image;
void setup() {
size(500, 500);
image = createGraphics(500, 500);
image.beginDraw();
for (int i = 0; i < visibleBodies.length; i++) {
Body b = visibleBodies[i];
image.point(b.x, -b.z, -b.y); // Z-up world
}
image.endDraw();
}
void draw() {
background(255, 0, 0);
image(image, 0, 0, width, height);
}
More info can be found in the Processing reference.
Related
So I'm creating a game using Javax.swing library for my uni coursework.
I have created a window and I have successfully written code to procedurally generate a game map.
However, I am unable to change the focus of the map. What I mean is that the map is always stuck in one corner of the screen. (IE: Location is set to 0,0, hence the Graphics g (the map) is put in that location going outwards.)
I would like to be able to move the "camera" so that different areas of the map can be viewed by the player.
Bellow I have pasted my method that draws the map onto the screen. Could anyone tell me what I could do to have the camera move at runtime. AKA: to shift the map left or right.
I thought of having a Graphics object that will hold the map, and then I'd only draw a subImage of that Graphics object, but considering how the map will be redrawn every frame (For animation purposes) that just means that I'll have even more graphics to redraw.
The map is 6,400 * 6,400 Pixels
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
try {
for(int x = 0; x < OverworldMap.MAP_X_SIZE; x++){
for(int y = 0; y < OverworldMap.MAP_Y_SIZE; y++){
for(int layer = 0; layer < OverworldMap.MAP_LAYER_SIZE; layer++) {
g.drawImage(OverworldMap.getTileAt(x, y, layer).getSprite(), x * SPRITE_SIZE, y * SPRITE_SIZE, null);
}
}
}
} catch (Exception e) {
LauncherClass.printErrorLog(e);
}
}
The best / easiest way to solve this is to put a JScrollPane around your JPanel, and make the JPanel the size of your image. You don't need to worry about only repainting the right part of your image - Java is pretty smart about only drawing the parts that are on screen. Note that you can show or hide the ScrollBars, but if you hide them you need to add logic to activate scrolling through some other mechanism
You cannot store a Graphics object and use it later. It is only valid for the duration of the paint method to which it is passed.
You can, however, simply offset your painting:
Image sprite = OverworldMap.getTileAt(x, y, layer).getSprite();
g.drawImage(sprite, x * SPRITE_SIZE - playerX, y * SPRITE_SIZE - playerY, this);
(Notice that the last argument to drawImage should be this.)
I am currently building an app using Processing.
I have a shape in which I was able to select its sub elements and manipulate its color and stroke... but I am not being able to resize every single element of the file.
Basically, what I want is to resize the whole thing like in:
shape(shape, mouseX, mouseY, 600, 600);//parameters: shape, x-coor, y-coor, new width, new height;
and, to change the color of each element (just like the line above).
The code:
PShape shape;
int noOfChilds;
/***************************************************************************/
void setup()
{
size(1000, 600);
shape = loadShape("a.svg");
noOfChilds = shape.getChildCount();
print(noOfChilds);
shapeMode(CENTER);
}
/***************************************************************************/
void draw()
{
background(100);
shape.enableStyle();
stroke(255);
shape(shape, mouseX, mouseY, 600, 600);
//
shape.disableStyle();
for(int i = 0; i < noOfChilds; i++)
{
pushMatrix();
translate(300, 300);
PShape ps = shape.getChild(i);
fill(random(255),random(255),random(255));
shape(ps, 0, 0);//shape(ps, 0, 0, anyValue, anyValue); seems to fail :'(
popMatrix();
}
}
/***************************************************************************/
You can use the PShape#scale() function to scale individual PShape instances.
From the reference:
PShape s;
void setup() {
s = loadShape("bot.svg");
}
void draw() {
background(204);
shape(s);
}
void mousePressed() {
// Shrink the shape 90% each time the mouse is pressed
s.scale(0.9);
}
Increases or decreases the size of a shape by expanding and
contracting vertices. Shapes always scale from the relative origin of
their bounding box. Scale values are specified as decimal percentages.
For example, the method call scale(2.0) increases the dimension of a
shape by 200%. Subsequent calls to the method multiply the effect. For
example, calling scale(2.0) and then scale(1.5) is the same as
scale(3.0). This transformation is applied directly to the shape; it's
not refreshed each time draw() is run.
You could also use the more general scale() function. More info can be found in the reference.
Note that you might also have to adjust where you draw your shapes, potentially using the translate() function.
I'm creating a game, in which when I render many blocks. The fps goes seriously down and everything lags. I know why it is lagging, because of many objects being rendered at once, but I can't figure out how to create and implement a frustum culling or any type of culling class to my game.
NOTE: I'm using VBOs.
I just can't find on the net; please help.
Here is some of my code:
//Render Game this were I render my game
public void Render_GAME() {
Update();
if (isGameRunning == true) {
Update();
world.render();
p1.Update();
}
}
Flat Class: where I render block
package game.terrain.biomes;
import core.camera.*;
import core.graphics.*;
import core.math.*;
import game.blocks.*;
import game.Player;
public class Flat{
//Global Variables:
private int width;
private int height;
private int depth;
private SpaceStone[][][] blocks;
public Flat(int width, int height, int depth)
{
this.width = width;
this.height = height;
this.depth = depth;
blocks = new SpaceStone[width][height][depth];
createBlocks();
}
//Create Blocks
private void createBlocks()
{
SpaceStone.createBlock();
for(int x = 0; x < width; x += 5)
{
for(int y = 0; y < height; y += 5)
{
for(int z = 0; z < depth; z += 5)
{
blocks[x][y][z] = new SpaceStone(new Vector3f(x, y, z), new Vector3f(0, 0, 0), new Vector3f(2.5f, 2.5f, 5f));
}
}
}
}
//Render Blocks
private void renderBlocks()
{
Shader.BLOCK.Enable();
SpaceStone.blocktex.bindTexture();
SpaceStone.block.Bind();
Shader.BLOCK.setUniform1i("tex", 1);
Matrix4f viewMatrix = Player.getViewMatrix(Player.getCamera());
Shader.BLOCK.setUniformMat4f("pr_matrix", Player.getPerspective());
for(int i = 0; i < width; i += 5)
{
for(int j = 0; j < height; j += 5)
{
for(int k = 0; k < depth; k += 5)
{
Matrix4f transform = new Transformation().getTransform(blocks[i][j][k], viewMatrix);
Shader.BLOCK.setUniformMat4f("vw_matrix", transform);
SpaceStone.block.Draw();
}
}
}
Shader.BLOCK.Disable();
SpaceStone.blocktex.unbindTexture();
SpaceStone.block.Unbind();
}
//Render Flat Biome
public void renderFlatBiome()
{
//Render Blocks
renderBlocks();
}
}
If you want more information, such as classes or the whole project please comment and notify me.
OpenGL performs the frustum culling, it sounds like you need to do some processing every frame to decide which blocks to pass to OpenGL to render (or maybe not every frame, new frustum culling calculations would be required every time the geometry or the camera changes). You need to construct a representation of the frustum and test yourself which geometry to be rendered. The viewing frustum could be considered a volume and so you are looking for which cubes are contained within that volume.
First thing is to see which geometry is behind the near clipping plane and further than the far clipping plane. This can be done by simply calculating the distance to the near and far clipping planes and ensuring they are on the correct side of the plane.
The next thing to do is check which geometry is too far left or right to fit in the frustum, and this is slightly more complicated due to the nature and different projections. Orthographic projection is a lot easier to calculate since the frustum for an orthographic projection is essentially cuboid itself. Perspective is trapezoidal in shape (depending of the field of view), but the principle is the same. Construct two planes which represent the left and right clipping planes of the frustum, and cull geometry which is the 'wrong' side in relation to your camera position.
You are simply relieving GL of geometry to draw which GL will determine not to draw anyway. Depending on the scene, the size of the geometry, the way its stored in the buffers and other aspects, the overhead of binding/unbinding and the vertex processing could easily outweigh any performance hit from culling client side.
I haven't written java for years so can't provide source, however I have outlined the simplest form (and not necessarily optimized) of doing this client side (in relation to OpenGL). By spatial grouping geometry data this some form of hierarchy (bounding volume, KD-tree, AABB etc), you can reduce the amount tests required for the culling.
In a lot of cases, the most basic form of hierarchal grouping is Axis Aligned Bounding Box (AABB), which (if none of your cubes ever have a rotation) is what you already have since you are using cubes. Discrete geometry is usually grouped in some form using cuboid volumes denoted by bounding boxes or 'slabs' (two parallel planes which define a volume between them).
I avoided the word bitmap in the title as bitmap in this context usually (?) refers to the bitmap from the underlying image.
I have an image that is segmented into a number of different regions. For each region I have a map of ones and zeros (a bitmap) where 1 represents inside the region and zero outside the region. Not every part of the image is covered with a region, and the regions may overlap. The images are of the dimension (480x360).
What I would like to do is to overlay the image with a transparent red when you hoover the region with your mouse. My problem is that my current method is very slow and it takes a second or two before the overlay appears.
My current approach is using a JLayer over my ImagePanel (extension of JPanel drawing a BufferedImage). Then my instance of the LayerUI draws the overlay when the mouse is moved:
public class ImageHighlightLayerUI extends LayerUI<JPanel> {
private boolean mouseActive;
private Point mousePoint;
private byte[][][] masks;
public void paint(Graphics g, JComponent c) {
super.paint(g, c);
if (mouseActive) {
byte[][] curMask = null;
// Find which region the mouse intersect
for (int i = 0; i < masks.length; i++) {
if (masks[i][mousePoint.x][mousePoint.y] == 1) {
curMask = masks[i];
break;
}
}
// Outside region --> don't draw overlay
if (curMask == null) return;
//Transparent red
g.setColor(new Color((float)1.0,
(float)0.0, (float)0.0, (float)0.8));
//Draw the mask
for(int x = 0; x < curMask.length; x++)
for(int y = 0; y < curMask[y].length; y++)
if (curMask[x][y] == 1)
g.fillRect(x, y, 1, 1);
}
}
}
So, how can I make this more efficient? I open to suggestions using other ways than a JLayer. Can I use my bitmap in some "magic" way with some swing-method? Can I mix it with the underlying bitmap from the BufferedImage? Is removing transparancy the only thing that'll help me? (Which is something I would like to keep)
Two other side problems which are not necessarily related to the question, but I have yet to solve:
The overlay is repainted every time the mouse moves. This seems like a waste of resources.
When regions are overlapping, how do I choose which one to paint?
I've been experimenting with different ways of moving a image over a grid of tiles for a game, but I've been unable to get a working implementation.
First I tried using a grid layout to hold a bunch of Tiles that extended Canvas and drew themselves. This drew the tiles nicely, however it seems that I am unable to draw my Player object on top of them. Originally, the Player also extended Canvas and I intended to have the widget on top of the tiles. It seems like this is impossible.
I then tried to have the Tile simply extend nothing, and just hold the image. I then hold each Tile in a 2D array and draw each Tile by a nested for loop, using the int from the for loop, multiplied by the image size, to draw Tile's Image. I put this code in a PaintListener inside of my constructor for my Map class that extended Canvas and dropped my Map onto my Shell in a Fill layout, but the PaintListener never gets called (I tested with a print statement).
What implementation could I use to draw the Tiles at the start of the game, then allow me to control the movement of my Player image?
I did something similar.
Using a PaintListener I get the calls when the Widget needs to be repainted. In my paint function, I loop over a tile array (wrapped in a World class) and draw all tiles. Afterwards I use the same technique with a worldObjects array/class:
public class WorldWidget extends Canvas {
WorldWidget() {
addPaintListener(new PaintListener() {
#Override
public void paintControl(PaintEvent e) {
WorldWidget.this.paintControl(e);
}
});
}
protected void paintControl(PaintEvent e) {
GC gc = e.gc;
for (short y = 0; y < world.getHeight(); y++) {
for (short x = 0; x < world.getWidth(); x++) {
final ITile tile = world.getTile(x, y);
final Image image = ImageCache.getImage(tile);
gc.drawImage(image, x * tileSize, y * tileSize);
}
}
// Here is used a similar loop, to draw world objects
}
}
This is obviously a condensed code example, as the class is part of an editor and reacts on mouse clicks and movement amongst other things.
When I did a tile based simulation while ago I did it this way:
I had 2 layers of the tile map - one for the terrain and second for the units.
The map itself was represented by a JPanel.
So roughly you got this for the JPanel:
public void paintComponent(Graphics graphics) {
// create an offscreen buffer to render the map
if (buffer == null) {
buffer = new BufferedImage(SimulationMap.MAP_WIDTH, SimulationMap.MAP_HEIGHT, BufferedImage.TYPE_INT_ARGB);
}
Graphics g = buffer.getGraphics();
g.clearRect(0, 0, SimulationMap.MAP_WIDTH, SimulationMap.MAP_HEIGHT);
// cycle through the tiles in the map drawing the appropriate
// image for the terrain and units where appropriate
for (int x = 0; x < map.getWidthInTiles(); x++) {
for (int y = 0; y < map.getHeightInTiles(); y++) {
if (map.getTerrain(x, y) != null) {
g.drawImage(tiles[map.getTerrain(x, y).getType()], x * map.getTILE_WIDTH(), y * map.getTILE_HEIGHT(), null);
}
}
}
if (map.getSimulationUnits() != null) {
for (Unit unit : map.getSimulationUnits()) {
g.drawImage(tiles[unit.getUnitType()], (int) Math.round(unit.getActualXCor() * map.getTILE_WIDTH()), (int) Math.round(unit.getActualYCor() * map.getTILE_HEIGHT()),
null);
}
}
// ...
// draw the buffer
graphics.drawImage(buffer, 0, 0, null);
}
Logic:
private Terrain[][] terrain = new Terrain[WIDTH][HEIGHT];
/** The unit in each tile of the map */
private Unit[][] units = new Unit[WIDTH][HEIGHT];
Then you have your game loop where you update the position of the units and other things, basically render() and update() the game. Check the links I've provided below.
NOTE
Since you are making a simple game this post about making game loops will be definitely useful for you. This hopefully also answer your question about moving the object on the map.
This site will be also very helpful since you will probably need to detect collision at some point too.