Software Renderer in Swing Component and swapping out the jPCT class

Started by Knuffi, April 05, 2012, 03:55:33 PM

Previous topic - Next topic

Knuffi

Hello,

I searched this site, but did not find any hint. I read the examples which render the "Hello World" in software, OpenGL and AWTGL, but I don't get the clue.
I have two problems:
1. I want to render a scene in a JPanel. As it is not very GPU demanding, software renderer will be enough - as I read, it is the only one really working with SWING components. Can someone give me an example? I thought, I've seen one somewhere in the wiki, but I can't find it anymore.

2. Is it possible to swap the HelloWorld class out of the "GUI class"?
As the GUI of the programme I want to write is very complex, I use WindowsBuilder in Eclipse, so I want to write a jPCT class and then just call it in the GUI. Is this possible?

Thanks in advance!

EgonOlsen

The software renderer doesn't care about Swing or AWT component. All it puts out is an Image: http://www.jpct.net/doc/com/threed/jpct/FrameBuffer.html#getOutputBuffer()

You can use that Image instance in a component of your own in any way you like, so you can easily create a "gui class" that deals with the rendered image.

Knuffi

Ok, thanks.

But how do I manage the loop then?

Is there anywhere an example?

EgonOlsen

Not from my side as i usually don't do any swing stuff. You don't have to use a loop. You can either do your rendering in the overriden paintComponent()-method of your new component or trigger it from anywhere you like and let the component only do the display work. In that case, you have to synchronize the rendering with the awt event dispatch thread or otherwise, you'll display corrupted images.

raft

I prefer to do rendering in AWT (GUI) thread as discussed in this thread. the main reason is, that way swing events layouts etc runs as expected.

for running samples, have a look at Bones' samples. all use software rendering

Knuffi

I had a look at the bones examples, but it did not get very clear to me. This is my first try, but when starting the app, nothing is rendered.
I initialize the BoxSoft Class to create the world, the camera  and the framebuffer and give it as a Graphics to the canvas. I thought a loop is not necessary as the scene does not change or has any movement in it.

GUI:
package jPCT;

import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JButton;
import java.awt.Canvas;

public class HelloGui extends JFrame {

private JPanel contentPane;

/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
HelloGui frame = new HelloGui();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}



public HelloGui() throws Exception {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 800, 600);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);

JButton btnTest = new JButton("Test 1");
btnTest.setBounds(10, 11, 89, 23);
contentPane.add(btnTest);

JButton btnTest_1 = new JButton("Test 2");
btnTest_1.setBounds(10, 45, 89, 23);
contentPane.add(btnTest_1);

JButton btnTest_2 = new JButton("Test 3");
btnTest_2.setBounds(10, 79, 89, 23);
contentPane.add(btnTest_2);

Canvas canvas = new Canvas();
canvas.setBounds(105, 10, 669, 542);
contentPane.add(canvas);

BoxSoft bs = new BoxSoft();
canvas.paint(bs.paint());

}
}


The "jPCT Class":
package jPCT;

import java.awt.Color;
import java.awt.Graphics;


import com.threed.jpct.FrameBuffer;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.World;

public class BoxSoft {
private World world;
private FrameBuffer buffer;
private Object3D box;

public BoxSoft() {

world = new World();
// world.setAmbientLight(200, 255, 200);

// TextureManager.getInstance().addTexture("box", new Texture("box.jpg"));

box = Primitives.getBox(3f, 2f);
// box.setTexture("box");
// box.setEnvmapped(Object3D.ENVMAP_ENABLED);
box.build();
world.addObject(box);

world.getCamera().setPosition(50, -50, -5);
world.getCamera().lookAt(box.getTransformedCenter());
buffer = new FrameBuffer(660, 540, FrameBuffer.SAMPLINGMODE_NORMAL);

}
public Graphics paint(){
buffer.clear(java.awt.Color.DARK_GRAY);
world.renderScene(buffer);
world.drawWireframe(buffer, Color.WHITE);
buffer.update();

return buffer.getGraphics();

}


}

raft

in Swing, you normally (if will do the rendering in UI thread) override paintComponent(Graphics) method to do the painting.

I dont see such thing in your code. calling canvas.paint(..) does not actually do rendering

Knuffi

I thought the framebuffer method getGraphics does the job ...

so the jPCT Class has to be an extension of an component?

raft

FrameBuffer.getGraphics gives you an image output. you need to draw that image into a component and typically do that in overriden paintComponent method

Knuffi

Is there a way to do it without extending a JPanel or JLabel or ...
because otherwise I cannot use WindowsBuilder ...

Got it at least working :
package jPCT;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JPanel;

import com.threed.jpct.FrameBuffer;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.World;

public class RenderPanel extends JPanel {
private static final long serialVersionUID = 1L;

private World world;
private FrameBuffer buffer;
private Object3D box;


public RenderPanel() {
world = new World();
// world.setAmbientLight(200, 255, 200);

// TextureManager.getInstance().addTexture("box", new Texture("box.jpg"));

box = Primitives.getBox(3f, 2f);
// box.setTexture("box");
// box.setEnvmapped(Object3D.ENVMAP_ENABLED);
box.build();
world.addObject(box);

world.getCamera().setPosition(50, -50, -5);
world.getCamera().lookAt(box.getTransformedCenter());
buffer = new FrameBuffer(660, 530, FrameBuffer.SAMPLINGMODE_NORMAL);

setPreferredSize(new Dimension(buffer.getOutputWidth(), buffer.getOutputHeight()));
setFocusable(true);
setLayout(null);

buffer.clear(java.awt.Color.DARK_GRAY);
world.renderScene(buffer);
world.drawWireframe(buffer, Color.WHITE);
buffer.update();

}
   
@Override
    public void paintComponent(Graphics g) {
        buffer.display(g);
    }
   
}

raft


raft

if your scene and camera position really doesnt change, you can create an Image and put it into an image showing class like JLabel. but it would be a strange way for a 3D app IMHO ;)

Knuffi

Yeah, you are right, I want to rotate at least the camera around the scene ... :)

Ok, then I will go this way further. Mysteriously WindowBuilder opens the GUI correctly.   :)

How do I update the component, e.g. when I add new objects or rotate something? How do I force the paint-method of my component?

raft

call repaint(). but remember it's asynchronous, it returns immediately and painting is done later on in UI thread.

paintImmediately(bounds) is synchronous but you should call in UI thread.

SwingUtilities.invokeAndWait(new Runnable() {
    public void run() {
        panel.paintImmediately(panel.getBounds());
    }
});

Knuffi

Got it working :)

There are two problems I still have:
1. Camera rotation left-right is ok, as it is a rotation around the z-axis, but rotation up-down is quite difficult. I will open up a new thread for this.
2. Why do the world and the frame buffer to be static?



GUI:
package jPCT;

import java.awt.EventQueue;

public class HelloGui extends JFrame {

private JPanel contentPane;

/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
HelloGui frame = new HelloGui();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}



public HelloGui() throws Exception {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 800, 600);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);

JButton btnTest = new JButton("Test 1");
btnTest.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
RenderPanel.rotateleft();
repaint();
}
});
btnTest.setBounds(10, 11, 89, 23);
contentPane.add(btnTest);

JButton btnTest_1 = new JButton("Test 2");
btnTest_1.setBounds(10, 45, 89, 23);
contentPane.add(btnTest_1);

JButton btnTest_2 = new JButton("Test 3");
btnTest_2.setBounds(10, 79, 89, 23);
contentPane.add(btnTest_2);

JPanel panel = new JPanel();
panel.setBounds(109, 11, 665, 540);
contentPane.add(panel);
panel.setLayout(new BorderLayout(0, 0));

RenderPanel panel_1 = new RenderPanel();
panel.add(panel_1, BorderLayout.CENTER);


}
}


RenderPanel Class
package jPCT;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JPanel;

import com.threed.jpct.FrameBuffer;
import com.threed.jpct.Matrix;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.World;

public class RenderPanel extends JPanel {
private static final long serialVersionUID = 1L;

static World world;
static FrameBuffer buffer;
Object3D box;
{

world = new World();
// world.setAmbientLight(200, 255, 200);

// TextureManager.getInstance().addTexture("box", new Texture("box.jpg"));

box = Primitives.getBox(3f, 2f);
// box.setTexture("box");
// box.setEnvmapped(Object3D.ENVMAP_ENABLED);
box.build();
world.addObject(box);

world.getCamera().setPosition(50, -20, -5);
world.getCamera().lookAt(box.getTransformedCenter());
buffer = new FrameBuffer(660, 530, FrameBuffer.SAMPLINGMODE_NORMAL);}


public RenderPanel() {
setPreferredSize(new Dimension(buffer.getOutputWidth(), buffer.getOutputHeight()));
setFocusable(true);
setLayout(null);

buffer.clear(java.awt.Color.DARK_GRAY);
world.renderScene(buffer);
world.drawWireframe(buffer, Color.WHITE);
buffer.update();
}

public static void rotateleft(){
SimpleVector temp = world.getCamera().getPosition();
float rotation = (float) Math.PI/30;
temp.rotateY(-rotation);


world.getCamera().setPosition(temp);
world.getCamera().lookAt(new SimpleVector(0,0,0));

buffer.clear(java.awt.Color.DARK_GRAY);
world.renderScene(buffer);
world.drawWireframe(buffer, Color.WHITE);
buffer.update();
}


@Override
    public void paintComponent(Graphics g) {
        buffer.display(g);
    }
   
}