Software mode demo

From JPCT
Revision as of 07:01, 21 September 2017 by Corey (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Software mode demo

Details

This is a bare minimum software renderer example... This is nothing fancy, but may be helpful for first time jPCT users or anybody interested in using the jPCT software renderer mode to design their 3D application.

Screen shot

Software Example320x320.png

Source code


import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import java.util.concurrent.TimeUnit;

import javax.swing.*;

import com.threed.jpct.*;

/**
 * A bare bones jPCT software mode application.
 * @author 'words' - jPCT.net
 */
@SuppressWarnings("serial")
public class Engine extends JFrame implements KeyEventDispatcher, MouseListener, MouseMotionListener {

	// "Engine" variables...
	private final Graphics graphics;
	private FrameBuffer buffer;
	private final World world;
	private boolean keepAlive = false;
	private int mouseX = -1;
	private int mouseY = -1;
	private int frameCount = 0;
	
	// Program content variables...
	private Object3D cube;
	private Random random = new Random();
	
	static {
		Logger.setLogLevel(Logger.ERROR);
		
		/*
		 * Configure the 3D engine (jPCT) settings.
		 * http://www.jpct.net/doc/com/threed/jpct/Config.html
		 */

		// When using the software renderer on a multi core setup, it's a good idea to use all cores (or at least some of them) to speed up rendering.
		// To do so, set Config.useMultipleThreads to true before instantiating the frame buffer.
		// By default, jPCT will use four cores, which matches a quad core cpu. If the setup that runs the application uses less cores, it's advised to adjust this value before instantiating the frame buffer.
		// http://www.jpct.net/wiki/index.php?title=Multithreading#The_threading_framework
		Config.useMultipleThreads = Runtime.getRuntime().availableProcessors() > 1;

		// Dynamic load balancing usually is the better choice.
		// It's not enable by default simply because it can cause small artifacts in combination with the texel filtering that jPCT uses (some pixels may flicker from time to time).
		Config.loadBalancingStrategy = 1;

		// Usually, one have to call build() on all objects that have to be rendered.
		Config.autoBuild = true;

		// The maximum size of the VisList.
		Config.maxPolysVisible = 32000; // 32k

		/*
		 * Submit a garbage collection to the virtual machine.
		 */
		Runtime.getRuntime().runFinalization();
		Runtime.getRuntime().gc();
	}

	public static void main(String[] args) {
		new Engine();
	}

	public Engine() {
		this.setTitle("jPCT " + Config.getVersion());
		this.setPreferredSize(new Dimension(320, 320));
		this.setBackground(Color.BLACK);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.pack();
		this.setSize(320, 320);
		this.setResizable(true);
		this.setLocationRelativeTo(null);
		this.setVisible(true);
		this.graphics = getGraphics();

		/*
		 * Bind the hardware input listeners.
		 */
		KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(this);
		this.addWindowListener(new WindowExitListener(this));
		this.addMouseListener(this);
		this.addMouseMotionListener(this);

		/*
		 * Initialize a "re-sizable" frame buffer.
		 */
		this.buffer = new FrameBuffer(320, 320, FrameBuffer.SAMPLINGMODE_NORMAL);
		buffer.disableRenderer(IRenderer.RENDERER_OPENGL);
		buffer.enableRenderer(IRenderer.RENDERER_SOFTWARE);
		buffer.optimizeBufferAccess();
		this.addComponentListener(new ComponentListener() {
			@Override
		    public void componentResized(ComponentEvent e) {
				int w = getWidth();
				int h = getHeight();
				buffer = new FrameBuffer(w, h, FrameBuffer.SAMPLINGMODE_NORMAL);
				buffer.refresh();
		    }
			@Override
			public void componentHidden(ComponentEvent e) { }
			@Override
			public void componentMoved(ComponentEvent e) { }
			@Override
			public void componentShown(ComponentEvent e) { }
		});

		// Initialize worlds
		this.world = new World();
		world.setAmbientLight(85, 85, 85); // Overall world brightness

		// Create the cube object
		this.cube = Primitives.getCube(5);
		world.addObject(cube);

		// Move camera
		Camera cam = world.getCamera();
		cam.moveCamera(Camera.CAMERA_MOVEOUT, 30);
		cam.moveCamera(Camera.CAMERA_MOVEUP, 15);
		cam.lookAt(cube.getTransformedCenter());
		cam.setFOV(1.5f);
		
		/*
		 * Run the program.
		 */
		keepAlive = true;
		execute();
	}

	@Override
	public void mousePressed(MouseEvent e) {
		int button = e.getButton();
		if (button == 1) {
			System.out.println("Mouse -> L click @ " + mouseX + "," + mouseY);
		}
		if (button == 3) {
			System.out.println("Mouse -> R click @ " + mouseX + "," + mouseY);
		}
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		int button = e.getButton();
		if (button == 1) {
			System.out.println("Mouse -> left button released");
		}
		if (button == 3) {
			System.out.println("Mouse -> right button released");
		}
	}

	@Override
	public void mouseMoved(MouseEvent e) {
		this.mouseX = e.getX();
		this.mouseY = e.getY();
	}

	@Override
	public void mouseClicked(MouseEvent e) { }

	@Override
	public void mouseEntered(MouseEvent e) { }

	@Override
	public void mouseExited(MouseEvent e) { }

	@Override
	public void mouseDragged(MouseEvent e) { }

	@Override
	public boolean dispatchKeyEvent(KeyEvent e) {
		if (e.getID() == KeyEvent.KEY_RELEASED && e.getKeyCode() == KeyEvent.VK_ESCAPE) {
			keepAlive = false;
		}
		return true;
	}

	private void execute() {
		World.setDefaultThread(Thread.currentThread());

		long lastSecond = 0L;
		while (keepAlive) {
			long currentTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime());

			// Reset the frame counter.
			if (lastSecond < currentTime - 1000) {
				lastSecond = currentTime;
				setTitle("FPS: " + frameCount);
				frameCount = 0;
				
				// Re-color the cube
				cube.setAdditionalColor(random.nextInt(255), random.nextInt(255), random.nextInt(255));
			}

			// Rotate the cube
			cube.rotateZ(0.01f * random.nextFloat());
			
			// Clear the previous frame.
			buffer.clear();

			/*
			 * Draw the new frame.
			 */
			frameCount++;
			world.renderScene(buffer);
			world.draw(buffer);
			buffer.update();
			buffer.display(graphics);
		}

		/*
		 * Terminate the program.
		 */
		System.exit(0);
	}

	/**
	 * Listen for the window exit event and use exit prompt.
	 */
	public class WindowExitListener extends WindowAdapter {

		private final JFrame frame;

		public WindowExitListener(final JFrame frame) {
			this.frame = frame;
		}

		@Override
		public void windowClosing(final WindowEvent e) {
			frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
			String ObjButtons[] = { "Yes", "No" };
			int result = JOptionPane.showOptionDialog(null, "Exit jPCT + "  + Config.getVersion() + " ?", "Confirm Exit", JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, ObjButtons, ObjButtons[1]);
			if (result == JOptionPane.YES_OPTION) {
				System.exit(0);
			}
		}
	}

}