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

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

/*************************************************************************
 *                                                                       *
 * 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.Version;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
import org.lwjgl.system.*;

import java.nio.*;

import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryStack.*;
import static org.lwjgl.system.MemoryUtil.*;

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 {

	//***************************************************************************
	// 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
	private static long 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 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 boolean mouseButtonPressedLeft = false;
	private boolean mouseButtonPressedMiddle = false;
	private boolean mouseButtonPressedRight = false;
	private double mousePosX;
	private double mousePosY;

	private void createMainWindow (int _width, int _height, dsFunctions fn)
	{
		// Setup an error callback. The default implementation
		// will print the error message in System.err.
		GLFWErrorCallback.createPrint(System.err).set();

		// Initialize GLFW. Most GLFW functions will not work before doing this.
		if ( !glfwInit() )
			throw new IllegalStateException("Unable to initialize GLFW");

		// Configure GLFW
		glfwDefaultWindowHints(); // optional, the current window hints are already the default
		glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation
		glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // the window will be resizable
		glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); // For windows and linux - fix window size

		// Create the window
		window = glfwCreateWindow(_width, _height, "Simulation", NULL, NULL);
		if ( window == NULL )
			throw new RuntimeException("Failed to create the GLFW window");

		// Setup a key callback. It will be called every time a key is pressed, repeated or released.
		glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> {
			if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE )
				glfwSetWindowShouldClose(window, true); // We will detect this in the rendering loop
			handleKeyboard(fn, key, scancode, action, mods);
		});
		glfwSetCharCallback(window, (window, codepoint) -> {
			char c = Character.toChars(codepoint)[0];
			fn.command(c);
		});
		glfwSetMouseButtonCallback(window, (window, button, action, mods) -> {
			if (button == GLFW_MOUSE_BUTTON_LEFT) {
				mouseButtonPressedLeft = action == GLFW_PRESS;
			}
			if (button == GLFW_MOUSE_BUTTON_MIDDLE) {
				mouseButtonPressedMiddle = action == GLFW_PRESS;
			}
			if (button == GLFW_MOUSE_BUTTON_RIGHT) {
				mouseButtonPressedRight = action == GLFW_PRESS;
			}
		});
		glfwSetCursorPosCallback(window, (window, xpos, ypos) -> {
			handleMouseMove(xpos, ypos);
		});

		float xScale, yScale;
		// Get the thread stack and push a new frame
		try ( MemoryStack stack = stackPush() ) {
			IntBuffer pWidth = stack.mallocInt(1); // int*
			IntBuffer pHeight = stack.mallocInt(1); // int*

			// Get the window size passed to glfwCreateWindow
			glfwGetWindowSize(window, pWidth, pHeight);

			// Get the resolution of the primary monitor
			GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());

			// Center the window
			glfwSetWindowPos(
					window,
					(vidmode.width() - pWidth.get(0)) / 2,
					(vidmode.height() - pHeight.get(0)) / 2
			);

			// Required for HiDPI monitors (i.e. Mac Retina)
			FloatBuffer _xscale = stack.mallocFloat(1);
			FloatBuffer _yscale = stack.mallocFloat(1);
			glfwGetWindowContentScale(window, _xscale, _yscale);
			xScale = _xscale.get();
			yScale = _yscale.get();
		} // the stack frame is popped automatically

		glfwSetWindowSizeCallback(window, (window, width, height) -> {
			this.width = (int) (width * xScale);
			this.height = (int) (height * yScale);
		});

		// Make the OpenGL context current
		glfwMakeContextCurrent(window);
		// Enable v-sync
		glfwSwapInterval(1);

		// Make the window visible
		glfwShowWindow(window);

		GL.createCapabilities();

		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: " + Version.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 = (int) (_width * xScale);
		height = (int) (_width * yScale);
		//  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;

		// Free the window callbacks and destroy the window
		glfwFreeCallbacks(window);
		glfwDestroyWindow(window);

		// Terminate GLFW and free the error callback
		glfwTerminate();
		glfwSetErrorCallback(null).free();
	}


//	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> 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 && !glfwWindowShouldClose(window)) {
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer

			//  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;

			glfwSwapBuffers(window); // swap the color buffers

			// Poll for window events. The key callback above will only be
			// invoked during this call.
			glfwPollEvents();

			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.currentTimeMillis()/1000.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.currentTimeMillis()/1000.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