All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ode4j.drawstuff.internal.LwJGL Maven / Gradle / Ivy

There is a newer version: 0.5.4
Show newest version
/*************************************************************************
 *                                                                       *
 * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith.       *
 * All rights reserved.  Email: [email protected]   Web: www.q12.org          *
 * Open Dynamics Engine 4J, Copyright (C) 2009-2014 Tilmann Zaeschke     *
 * All rights reserved.  Email: [email protected]   Web: www.ode4j.org        *
 *                                                                       *
 * This library is free software; you can redistribute it and/or         *
 * modify it under the terms of EITHER:                                  *
 *   (1) The GNU Lesser General Public License as published by the Free  *
 *       Software Foundation; either version 2.1 of the License, or (at  *
 *       your option) any later version. The text of the GNU Lesser      *
 *       General Public License is included with this library in the     *
 *       file LICENSE.TXT.                                               *
 *   (2) The BSD-style license that is included with this library in     *
 *       the file ODE-LICENSE-BSD.TXT and ODE4J-LICENSE-BSD.TXT.         *
 *                                                                       *
 * This library is distributed in the hope that it will be useful,       *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files    *
 * LICENSE.TXT, ODE-LICENSE-BSD.TXT and ODE4J-LICENSE-BSD.TXT for more   *
 * details.                                                              *
 *                                                                       *
 *************************************************************************/
package org.ode4j.drawstuff.internal;

import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GLContext;
import org.ode4j.drawstuff.DrawStuff;
import org.ode4j.drawstuff.DrawStuff.dsFunctions;
import org.ode4j.ode.OdeHelper;
import org.ode4j.ode.internal.Common;

import static org.ode4j.ode.internal.cpp4j.Cstdio.*;


/**
 * Main window and event handling for LWJGL.
 * Ported from x11.cpp.
 */
abstract class LwJGL extends Internal implements DrawStuffApi {

	//Ensure that Display.destroy() is called (TZ)
	//Not sure this works, but it's an attempt at least.
	//-> This should avoid the Problem that a process keeps running with 99%CPU, 
	//   even if the window is closed (clicking on the 'x'). The supposed 
	//   problem is that when clicking 'x', Display.destroy() never gets called
	//   by dsPlatformSimLoop(). 
	static {
		Runtime.getRuntime().addShutdownHook(new Thread() {
			@Override
			public void run() {
//				Display.destroy();
			}
		});
	}
	
	
	//***************************************************************************
	// error handling for unix

	//static void printMessage (const char *msg1, const char *msg2, va_list ap)
	private static void printMessage (String msg1, String fmt, Object ...  ap)
	{
		fflush (stderr);
		fflush (stdout);
		fprintf (stderr,"\n%s: ",msg1);
		vfprintf (stderr,fmt,ap);
		fprintf (stderr,"\n");
		fflush (stderr);
	}


	//extern "C" void dsError (const char *msg, ...)
	static void dsError (String msg, Object ... ap)
	{
		//  va_list ap;
		//  va_start (ap,msg);
		printMessage ("Error",msg,ap);
		//TZ exit (1);
		throw new RuntimeException();
	}


	//extern "C" void dsDebug (const char *msg, ...)
	static void dsDebug (String msg, Object ... ap)
	{
		//  va_list ap;
		//  va_start (ap,msg);
		printMessage ("INTERNAL ERROR",msg,ap);
		// *((char *)0) = 0;	 ... commit SEGVicide ?
		//TZ abort();
		throw new RuntimeException();
	}


	//extern "C" void dsPrint (const char *msg, ...)
	static void dsPrint (String msg, Object ... ap)
	{
		//  va_list ap;
		//  va_start (ap,msg);
		vprintf (msg,ap);
	}

	//***************************************************************************
	// openGL window

	// X11 display info
	//static Display display;//*display=0;
	//private static int screen=0;
	//static XVisualInfo visual;//*visual=0;		// best visual for openGL
	//static Colormap colormap=null;		// window's colormap
	//static Atom wm_protocols_atom = null;
	//static Atom wm_delete_window_atom = null;

	// window and openGL
	//static Window win=null;			// X11 window, 0 if not initialized
	private static int width=0,height=0;		// window size
	//static GLXContext glx_context=null;	// openGL rendering context
	private static int last_key_pressed=0;		// last key pressed in the window
	private static boolean run=true;			// 1 if simulation running
	private static boolean pause=false;			// 1 if in `pause' mode
	private static boolean singlestep=false;		// 1 if single step key pressed
	private static boolean writeframes=false;		// 1 if frame files to be written


	private static void createMainWindow (int _width, int _height)
	{
		// create Window of size 300x300
		try {
			Display.setLocation((Display.getDisplayMode().getWidth() - _width) / 2,
					(Display.getDisplayMode().getHeight() - _height) / 2);
		} catch (UnsatisfiedLinkError e) {
			System.err.println("Missing lwjgl native libraries.");
			System.err.println("If you are using maven, make sure to use "
					+ "'-Djava.library.path=target/natives' as VM argument of your application.");
			System.err.println("For plain Eclipse, add the native library path to the included "
					+ "lwjgl.jar in the definition of the Referenced Libraries.");
			throw e;
		}
		try {
			Display.setDisplayMode(new DisplayMode(_width, _height));
			Display.setTitle("Simulation");
			Display.setVSyncEnabled(true);  //for VSync (TZ)
			Display.create();
		} catch (LWJGLException e) {
			throw new RuntimeException(e);
		}

		try {
			Keyboard.create();
			Mouse.create();
		} catch (LWJGLException e) {
			throw new RuntimeException(e);
		}
		
		if (firsttime) {
			System.err.println("GL_VENDOR:     " + GL11.glGetString(GL11.GL_VENDOR));
			System.err.println("GL_RENDERER:   " + GL11.glGetString(GL11.GL_RENDERER));
			System.err.println("GL_VERSION:    " + GL11.glGetString(GL11.GL_VERSION));
			System.err.println("LWJGL_VERSION: " + Sys.getVersion());
			System.err.println();
			System.err.println("glLoadTransposeMatrixfARB() supported: " + 
					GLContext.getCapabilities().GL_ARB_transpose_matrix);
		}


		//	// create X11 display connection
		//  display = XOpenDisplay (null);
		//  if (!display) dsError ("can not open X11 display");
		//  screen = DefaultScreen(display);
		//
		//  // get GL visual
		//  static int attribList[] = {GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE,16,
		//			     GLX_RED_SIZE,4, GLX_GREEN_SIZE,4,
		//			     GLX_BLUE_SIZE,4, None};
		//  visual = glXChooseVisual (display,screen,attribList);
		//  if (!visual) dsError ("no good X11 visual found for OpenGL");

		// create colormap
		//  colormap = XCreateColormap (display,RootWindow(display,screen),
		//			      visual.visual,AllocNone);

		// initialize variables
		//  win = 0;
		width = _width;
		height = _height;
		//  glx_context = 0;
		last_key_pressed = 0;

		if (width < 1 || height < 1) dsDebug ("","bad window width or height");

		// create the window
		//  XSetWindowAttributes attributes;
		//  attributes.background_pixel = BlackPixel(display,screen);
		//  attributes.colormap = colormap;
		//  attributes.event_mask = ButtonPressMask | ButtonReleaseMask |
		//    KeyPressMask | KeyReleaseMask | ButtonMotionMask | PointerMotionHintMask |
		//    StructureNotifyMask;
		//  win = XCreateWindow (display,RootWindow(display,screen),50,50,width,height,
		//		       0,visual.depth, InputOutput,visual.visual,
		//		       CWBackPixel | CWColormap | CWEventMask, attributes);

		// associate a GLX context with the window
		//  glx_context = glXCreateContext (display,visual,0,GL_TRUE);
		//  if (!glx_context) dsError ("can't make an OpenGL context");

		// set the window title
		//  XTextProperty window_name;
		//  window_name.value = "Simulation";//(unsigned char *) "Simulation";
		//  window_name.encoding = XA_STRING;
		//  window_name.format = 8;
		//  window_name.nitems = window_name.value.length;//strlen((char *) window_name.value);
		//  XSetWMName (display,win,window_name);

		// participate in the window manager 'delete yourself' protocol
		//  wm_protocols_atom = XInternAtom (display,"WM_PROTOCOLS",False);
		//  wm_delete_window_atom = XInternAtom (display,"WM_DELETE_WINDOW",False);
		//  if (XSetWMProtocols (display,win,wm_delete_window_atom,1)==0)
		//    dsError ("XSetWMProtocols() call failed");

		// pop up the window
		//  XMapWindow (display,win);
		//  XSync (display,win);
	}


	private static void destroyMainWindow()
	{
		//  glXDestroyContext (display,glx_context);
		//  XDestroyWindow (display,win);
		//  XSync (display,0);
		//  XCloseDisplay(display);
		//  display = 0;
		//  win = 0;
		//  glx_context = 0;
		Keyboard.destroy();
		Mouse.destroy();
		Display.destroy();
	}


//	private static int mx=0,my=0; 	// mouse position
//	private static int mode = 0;		// mouse button bits
	//static void handleEvent (XEvent &event, dsFunctions *fn)
//	static void handleEvent (XEvent event, dsFunctions fn)
//	{
//		//TZ  static int mx=0,my=0; 	// mouse position
//		//TZ  static int mode = 0;		// mouse button bits

//		switch (event.type) {
//
//		case ButtonPress: {
//			if (event.xbutton.button == Button1) mode |= 1;
//			if (event.xbutton.button == Button2) mode |= 2;
//			if (event.xbutton.button == Button3) mode |= 4;
//			mx = event.xbutton.x;
//			my = event.xbutton.y;
//		}
//		return;
//
//		case ButtonRelease: {
//			if (event.xbutton.button == Button1) mode &= (~1);
//			if (event.xbutton.button == Button2) mode &= (~2);
//			if (event.xbutton.button == Button3) mode &= (~4);
//			mx = event.xbutton.x;
//			my = event.xbutton.x;
//		}
//		return;
//
//		case MotionNotify: {
//			if (event.xmotion.is_hint) {
//				Window root,child;
//				//unsigned 
//				int mask;
//				XQueryPointer (display,win,root,child,event.xbutton.x_root,
//						event.xbutton.y_root,event.xbutton.x,event.xbutton.y,
//						mask);
//			}
//			dsMotion (mode, event.xmotion.x - mx, event.xmotion.y - my);
//			mx = event.xmotion.x;
//			my = event.xmotion.y;
//		}
//		return;

		//Moved to handleKeyboard() TZ
//		case KeyPress: {
//			KeySym key;
//			XLookupString (event.xkey,NULL,0,key,0);
//			if ((event.xkey.state & ControlMask) == 0) {
//				if (key >= ' ' && key <= 126 && fn.command) fn.command (key);
//			}
//			else if (event.xkey.state & ControlMask) {
//				switch (key) {
//				case 't': case 'T':
//					dsSetTextures (dsGetTextures() ^ 1);
//					break;
//				case 's': case 'S':
//					dsSetShadows (dsGetShadows() ^ 1);
//					break;
//				case 'x': case 'X':
//					run = 0;
//					break;
//				case 'p': case 'P':
//					pause ^= 1;
//					singlestep = 0;
//					break;
//				case 'o': case 'O':
//					if (pause) singlestep = 1;
//					break;
//				case 'v': case 'V': {
//					float[] xyz=new float [3], hpr = new float [3];
//					dsGetViewpoint (xyz,hpr);
//					printf ("Viewpoint = (%.4f,%.4f,%.4f,%.4f,%.4f,%.4f)\n",
//							xyz[0],xyz[1],xyz[2],hpr[0],hpr[1],hpr[2]);
//					break;
//				}
//				case 'w': case 'W':
//					writeframes ^= 1;
//					if (writeframes) printf ("Now writing frames to PPM files\n");
//					break;
//				}
//			}
//			last_key_pressed = key;		// a kludgy place to put this...
//		}
//		return;
//
//		case KeyRelease: {
//			// hmmmm...
//		}
//		return;

//		case ClientMessage:
//			if (event.xclient.message_type == wm_protocols_atom &&
//					event.xclient.format == 32 &&
//					Atom(event.xclient.data.l[0]) == wm_delete_window_atom) {
//				run = 0;
//				return;
//			}
//			return;
//
//		case ConfigureNotify:
//			width = event.xconfigure.width;
//			height = event.xconfigure.height;
//			return;
//		}
//	}


//	// return the index of the highest bit
//	//static int getHighBitIndex (unsigned int x)
//	private static int getHighBitIndex (int x)
//	{
//		int i = 0;
//		while (x!=0) {
//			i++;
//			x >>= 1;
//		}
//		return i-1;
//	}
//
//
//	// shift x left by i, where i can be positive or negative
//	//#define SHIFTL(x,i) (((i) >= 0) ? ((x) << (i)) : ((x) >> (-i)))
//	//int? double?
//	private final int SHIFTL(long x, int i) { 
//		return (int) ((i >= 0) ? (x << (i)) : ((x) >> (-i))); 
//	}

	private static void captureFrame (int num)
	{
		throw new UnsupportedOperationException();
		//  fprintf (stderr,"capturing frame %04d\n",num);
		//
		//  char s[100];
		//  sprintf (s,"frame/frame%04d.ppm",num);
		//  FILE *f = fopen (s,"wb");
		//  if (!f) dsError ("can't open \"%s\" for writing",s);
		//  fprintf (f,"P6\n%d %d\n255\n",width,height);
		//  XImage *image = XGetImage (display,win,0,0,width,height,~0,ZPixmap);
		//
		//  int rshift = 7 - getHighBitIndex (image.red_mask);
		//  int gshift = 7 - getHighBitIndex (image.green_mask);
		//  int bshift = 7 - getHighBitIndex (image.blue_mask);
		//
		//  for (int y=0; y= ' ' && key <= 126 && fn.command) fn.command (key);
				char keyChar = Keyboard.getEventCharacter();
				if (keyChar >= ' ' && keyChar <= 126) fn.command (keyChar);
//				System.out.println("cmd-c " +Keyboard.getEventCharacter());
//				  System.out.println("cmd- " + (char)(key+65));

			} else { //if (event.xkey.state & ControlMask) {
				if (key == last_key_pressed) {
					continue;
				}
				switch (key) {
				case Keyboard.KEY_T:
					dsSetTextures (!dsGetTextures());
					break;
				case Keyboard.KEY_S:
					dsSetShadows (!dsGetShadows());
					break;
				case Keyboard.KEY_X:
					run = false;
					break;
				case Keyboard.KEY_P:
					pause = !pause;
					singlestep = false;
					break;
				case Keyboard.KEY_O:
					if (pause) singlestep = true;
					break;
				case Keyboard.KEY_V: {
					float[] xyz=new float [3], hpr = new float [3];
					dsGetViewpoint (xyz,hpr);
					printf ("Viewpoint = (%.4f,%.4f,%.4f,%.4f,%.4f,%.4f)\n",
							xyz[0],xyz[1],xyz[2],hpr[0],hpr[1],hpr[2]);
					break;
				}
				case Keyboard.KEY_W:
					writeframes = !writeframes;
					if (writeframes) printf ("Now writing frames to PPM files\n");
					break;
				}
			}
			last_key_pressed = key;		// a kludgy place to put this...
		}
	}


	/**
	 * handles the mouse
	 */
	private void handleMouse() {
		readBufferedMouse();
	}

	/**
	 * reads a mouse in buffered mode
	 */
	private void readBufferedMouse() {
		// iterate all events, use the last button down
		while(Mouse.next()) {
			if (Mouse.getEventButton() != -1) {
				if (Mouse.getEventButtonState()) {
			}
				//lastButton = Mouse.getEventButton();
			}
		}  

		updateState();
	}

	/**
	 * Updates our "model"
	 *
	 */
	private void updateState() {
		int dx = Mouse.getDX();
		int dy = Mouse.getDY();
		int dw = Mouse.getDWheel();


		// get out if no movement
		if (dx == dy && dx == 0 && dw == 0) {
			return;
		}

		//LWJGL: 0=left 1=right 2=middle
		//GL: 0=left 1=middle 2=right
		
		int mode = 0;
		if (Mouse.isButtonDown(0)) mode |= 1; 
		if (Mouse.isButtonDown(2)) mode |= 2; 
		if (Mouse.isButtonDown(1)) mode |= 4;
		if (mode != 0) {
			//LWJGL has inverted dy wrt C++/GL
			dsMotion (mode, dx, -dy);
		}
		
	}

	
	//void dsPlatformSimLoop (int window_width, int window_height, dsFunctions *fn,
	//			int initial_pause)
	private static boolean firsttime=true;
	@Override
	void dsPlatformSimLoop (int window_width, int window_height, dsFunctions fn,
			boolean initial_pause)
	{
		pause = initial_pause;
		createMainWindow (window_width, window_height);
		//glXMakeCurrent (display,win,glx_context);
		//TODO ?
		//GLContext.useContext(context);
		try {
			//Sets the context / by TZ
			Display.makeCurrent();
		} catch (LWJGLException e) {
			throw new RuntimeException(e);
		} 

		dsStartGraphics (window_width,window_height,fn);

		//TZ static bool firsttime=true;
		if (firsttime)
		{
			System.err.println();
			System.err.print("Using ode4j version: " + OdeHelper.getVersion());
			System.err.println("  [" + OdeHelper.getConfiguration() + "]");
			System.err.println();
			fprintf
			(
					stderr,
					"\n" +
					"Simulation test environment v%d.%02d\n" +
					"   Ctrl-P : pause / unpause (or say `-pause' on command line).\n" +
					"   Ctrl-O : single step when paused.\n" +
					"   Ctrl-T : toggle textures (or say `-notex' on command line).\n" +
					"   Ctrl-S : toggle shadows (or say `-noshadow' on command line).\n" +
					"   Ctrl-V : print current viewpoint coordinates (x,y,z,h,p,r).\n" +
					"   Ctrl-W : write frames to ppm files: frame/frameNNN.ppm\n" +
					"   Ctrl-X : exit.\n" +
					"\n" +
					"Change the camera position by clicking + dragging in the window.\n" +
					"   Left button - pan and tilt.\n" +
					"   Right button - forward and sideways.\n" +
					"   Left + Right button (or middle button) - sideways and up.\n" +
					"\n",DrawStuff.DS_VERSION >> 8,DrawStuff.DS_VERSION & 0xff
			);
			firsttime = false;
		}

		//if (fn.start) 
		fn.start();

		int frame = 1;
		run = true;
		long startTime = System.currentTimeMillis() + 5000;
		long fps = 0;
		while (run && !Display.isCloseRequested()) {
			//  while (run) {
			// read in and process all pending events for the main window
			//    XEvent event;
			//    while (run && XPending (display)) {
			//      XNextEvent (display,event);
			//      handleEvent (event,fn);
			//    }
			handleKeyboard(fn);
			handleMouse();

			//processDrawFrame: This was not move into separate method for convenience
			
			GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);

			dsDrawFrame (width,height,fn,pause && !singlestep);
			singlestep = false;


			Display.update();
			if (startTime > System.currentTimeMillis()) {
				fps++;
			} else {
				long timeUsed = 5000 + (startTime - System.currentTimeMillis());
				startTime = System.currentTimeMillis() + 5000;
				System.out.println(fps + " frames in " + (timeUsed / 1000f) + " seconds = "
						+ (fps / (timeUsed / 1000f)));
				fps = 0;
			}
			//    glFlush();
			//    glXSwapBuffers (display,win);
			//    XSync (display,0);

			// capture frames if necessary
			if (pause==false && writeframes) {
				captureFrame (frame);
				frame++;
			}
		}

		//if (fn.stop) 
		fn.stop();
		dsStopGraphics();

		destroyMainWindow();
	}


	//extern "C" void dsStop()
	@Override
	public void dsStop()
	{
		run = false;
	}


	private static double prev=System.nanoTime()/1000000000.0;
	//extern "C" double dsElapsedTime()
	@Override
	public double dsElapsedTime()
	{
//		if (true) {//(HAVE_GETTIMEOFDAY) { //#if HAVE_GETTIMEOFDAY
			//TZ static double prev=0.0;
			//		timeval tv ;
			//
			//		gettimeofday(tv, 0);
			//		double curr = tv.tv_sec + (double) tv.tv_usec / 1000000.0 ;
			double curr = System.nanoTime()/1000000000.0;
			//		if (prev==-1)
			//			prev=curr;
			double retval = curr-prev;
			prev=curr;
			if (retval>1.0) retval=1.0;
			if (retval




© 2015 - 2025 Weber Informatics LLC | Privacy Policy