LWJGL or JOGL?

Yeah the docs are a work in progess I think… I have been so busy at work lately that I havent had a chance to work on my game or spgl in a while… I want to write some tutorials for it someday :slight_smile: … I have not played with JME yet but I can give you something to work from…



Here is a Dialog that is extending the dialog in spgl… most of the guts not pertaining to spgl have been ripped out…



package jk.game;

import net.puppygames.gui.Dialog;

import org.lwjgl.opengl.GL;

import com.sas.planetation.data.MapCellBlock;
import com.sas.planetation.data.MapPalette;
import com.sas.planetation.display.LWJGLMapDisplay;
import com.sas.planetation.display.OGLMapDisplay;

/**
 * The GameDialog is a SPGL Dialog that displays a Plantation map as its
 * forground.
 *
 * @author naj
 */
public class GameDialog extends Dialog {

    /**
     * Create a SPGL Dialog and loads a Planation map onto it.
     * @param width the width of the dialog.
     * @param height the height of the dialog.
     */
    public GameDialog(final int w, final int h) {
        super("Map Dialog");
        width = w;
        height = h;
        loadMap();
        setSize(width, height);
        centre();
        open();
    }

    /**
     * Render this component's background: called first by Component render()
     */
    public void renderBackground() {}

    /**
     * Render this component's self: called second by Component render()
     */
    public void renderSelf() {}

    /**
     * Render this component's foreground: called last by Component render()
     */
    public void renderForeground() {
        GL.glEnable(GL.GL_TEXTURE_2D);
        GL.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE);
        map.draw();
    }


}



... and here is a game class, poorly written but should get the point across, that uses the GameDialog above... the createGuiObjects() method and the Interface static calls in the main game loop do the spgl stuff that you want.



package jk.game;

import java.io.FileInputStream;

import net.puppygames.gui.CommandButton;
import net.puppygames.gui.CommandButtonListener;
import net.puppygames.gui.Interface;
import net.puppygames.gui.Label;
import net.puppygames.gui.MessageBox;
import net.puppygames.gui.MousePointer;
import net.puppygames.gui.TextArea;

import org.lwjgl.DisplayMode;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.openal.AL;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GLCaps;
import org.lwjgl.opengl.GLU;
import org.lwjgl.opengl.Window;

import com.sas.planetation.data.MapTerrainIcon;
import com.shavenpuppy.jglib.AbsMouse;
import com.shavenpuppy.jglib.Display;
import com.shavenpuppy.jglib.Resources;
import com.shavenpuppy.jglib.Timer;
import com.shavenpuppy.jglib.opengl.nvidia.NvidiaInitializer;
import com.shavenpuppy.jglib.sound.SoundPlayer;
import com.shavenpuppy.jglib.sprites.SpriteImage;

/**
 * A basic lwjgl game skeleton.  Starts up opengl.  The game loop executes
 * until the escape key is pressed or the window is closed.  It can be run in
 * windowed mode or fullscreen mode.
 *
 * This is the main class for processing the game.
 *
 * @author naj
 */
public class Game {

    /**
     * Determines whether the game is run in fullscreen or windowed mode.
     */
    private static boolean fullscreen = false;

    /**
     * Determines whether the game is still running or not.
     */
    private static boolean finished;

    /**
     * An SPGL Dialog that displays the maps.
     */
    private static GameDialog gameDialog;

    /**
     * The width of the screen or window.
     */
    private static int width = 800;
    //private static int width = 640;

    /**
     * The height of the screen or window.
     */
    private static int height = 600;
    //private static int height = 480;

    /**
     * The maximum amount of time to wait between frames to keep the game
     * flowing at the same rate on all computers.
     */
    private static final float FRAME_TIME = 0.0017f;

    /**
     * The frames per second.
     */
    private static int fps;
    private static Label fpsLabel;

    private static SoundPlayer soundPlayer;

    /**
     * No need to ever create a Game object.  There should only be one game
     * running at a time.
     */
    private Game() {}

    /**
     * The main game code.
     * @param args command line arguements.
     */
    public static void main(String[] args) {
        if (args.length > 0) {
            if ("-fullscreen".equalsIgnoreCase(args[0])) {
                fullscreen = true;
            }
        }
        try {
            init();

            //Interface.DEBUG = true;

            int frames = 0;

            Timer timer = new Timer();
            timer.reset();
            timer.resume();

            while (!finished) {
                AbsMouse.poll();
                Keyboard.poll();

                long then = Sys.getTime();

                mainLoop();
                fpsLabel.setText("fps: " + fps);
                Interface.tick();
                Interface.render();
                Resources.manage();
                Window.update();
                Window.paint();
                //soundPlayer.play();

                long now = Sys.getTime();
                float elapsed = (float) (now - then) / (float) Sys.getTimerResolution();

                // keep the game running at the same rate for everyonec
                while (elapsed < FRAME_TIME) {
                    try {
                        Thread.sleep((long) ((FRAME_TIME - elapsed) * 1000.0f));
                    } catch (InterruptedException e) {}
                    now = Sys.getTime();
                    elapsed = (float) (now - then) / (float) Sys.getTimerResolution();
                }

                // count the frames per second
                frames++;
                float time = timer.getTime();
                if (time >= 1.0f) {
                    fps = (int) (frames / time);
                    timer.reset();
                    frames = 0;
                }
            }

        } catch (Throwable t) {
            t.printStackTrace();
        } finally {
            cleanup();
        }

    }

    /**
     * Start up and initialize Dialogs and Windows.
     */
    private final static void createGuiObjects() throws Exception {
        gameDialog = new GameDialog(width, height);
        gameDialog.centre();
        gameDialog.open();

        final net.puppygames.gui.Window w = new net.puppygames.gui.Window("map at a glance");
        w.setLocation(0, 0);
        w.setSize(250, 250);

        TextArea text = new TextArea("This is where a scaled down version of the map will go.  The mouse cursor will turn into a box and allow you to quickly jump to anywhere on the map.");
        text.setSize(230, 200);
        text.setLocation(15, 80);
        w.addChild(text);

        CommandButton helpButton = new CommandButton("Help");
        helpButton.setSize(100, 20);
        helpButton.setLocation(75, 30);
        helpButton.addCommandButtonListener(new CommandButtonListener() {
            public boolean selected(CommandButton cb) {
                try {
                    MessageBox message = new MessageBox("Lame Help", "Use the arrow keys or move the mouse to the edges of the screen to scroll the map.  Press <ESC> to quit this demo.", 0, MessageBox.OK_DIALOG, null);
                    message.setVisible(true);
                } catch (Exception e) {}
                return false;
            }

        });
        w.addChild(helpButton);

        w.setDraggable(true);
        w.open();

        MousePointer windowMousePointer = new MousePointer((SpriteImage) Resources.get("nate-win-mouse.mousepointer"));
        windowMousePointer.create();
        w.setMousePointer(windowMousePointer);

        fpsLabel = new Label("fps: " + fps);
        fpsLabel.setSize(100, 20);
        fpsLabel.setLocation(10, 0);
        fpsLabel.setVisible(true);
        w.addChild(fpsLabel);
    }

    /**
    * Start up and initialize OpenGL.
    */
    private final static void init() throws Exception {
        if (fullscreen) {
            // Window.create("Strategy Game (Fullscreen)", 16, 0, 8, 0);
            // params - int minWidth, int minHeight, int maxWidth, int maxHeight, int minBPP, int maxBPP, int minFreq, int maxFreq
            try {
                int mode = -1;
                DisplayMode[] modes = Display.getAvailableDisplayModes(640, 480, -1, -1, 16, -1, 60, -1);
                for (int i = 0; i < modes.length; i++) {
                    if (modes[i].width == width && modes[i].height == height && modes[i].bpp >= 16) {
                        mode = i;
                        width = modes[i].width;
                        height = modes[i].height;
                        break;
                    }
                }
                if (mode != -1) {
                    System.out.println("Setting display mode to " + modes[mode]);
                    org.lwjgl.Display.setDisplayMode(modes[mode]);
                    System.out.println("Created display.");
                }
            } catch (Exception e) {
                System.err.println("Failed to create display due to " + e);
            }
            try {
                Window.create("Strategy Game (Fullscreen)", 16, 0, 8, 0);
            } catch (Exception e) {
                System.err.println("Failed to create OpenGL due to " + e);
                System.exit(1);
            }
        } else {
            Window.create("Strategy Game", 50, 50, width, height, 16, 0, 8, 0);
        }

        Resources.load(new FileInputStream("resources/resources.data"));

        Interface.init(width, height, width, height);

        Mouse.create();
        AbsMouse.setSensitivity(8);
        AbsMouse.setSize(width, height);
        AbsMouse.setPosition(width / 2, height / 2);

        Keyboard.create();
        Keyboard.enableBuffer();
        createGuiObjects();

        GL.glMatrixMode(GL.GL_PROJECTION);
        GL.glLoadIdentity();
        GLU.gluOrtho2D(0, width, 0, height);
        GL.glMatrixMode(GL.GL_MODELVIEW);

        GLCaps.determineAvailableExtensions();
        if (GLCaps.WGL_EXT_swap_control) {
            GL.wglSwapIntervalEXT(0);
        }
    }

    /**
     * Main loop.
     */
    private final static void mainLoop() {
        processMouse();
        processKeyboard();
        processWindow();
    }

    /**
     * Process keyboard events.
     */
    private final static void processKeyboard() {
        if (Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
            finished = true;
        }
        if (Keyboard.isKeyDown(Keyboard.KEY_UP)) {
            gameDialog.scrollDown(2);
        }
        if (Keyboard.isKeyDown(Keyboard.KEY_DOWN)) {
            gameDialog.scrollUp(2);
        }
        if (Keyboard.isKeyDown(Keyboard.KEY_LEFT)) {
            gameDialog.scrollRight(2);
        }
        if (Keyboard.isKeyDown(Keyboard.KEY_RIGHT)) {
            gameDialog.scrollLeft(2);
        }
    }

    /**
     * Process mouse events.
     */
    private final static void processMouse() {
        int x = AbsMouse.getX(), y = AbsMouse.getY();
        if (Mouse.isButtonDown(0)) {
            int row = (height - y) / 16;
            int col = x / 32;
            //System.out.println("row=" + row + ", col=" + col);
            MapTerrainIcon base = gameDialog.map.getBaseIcon(x, y, 0);
            MapTerrainIcon fringe = gameDialog.map.getFringeIcon(x, y, 0);
            System.out.print("The base icon is " + base.toString());
            if (fringe != null) {
                System.out.print(" and the fringe icon is " + fringe.toString());
            }
            System.out.println(".");

        }
        if (y < 20) {
            gameDialog.scrollUp(2);
        }
        if (y > height - 20) {
            gameDialog.scrollDown(2);
        }
        if (x < 20) {
            gameDialog.scrollRight(2);
        }
        if (x > width - 20) {
            gameDialog.scrollLeft(2);
        }
    }

    /**
     * Process window events.
     */
    private final static void processWindow() {
        if (Window.isCloseRequested()) {
            finished = true;
        }
    }

    /**
     * Cleanup.
     */
    private final static void cleanup() {
        Mouse.destroy();
        Keyboard.destroy();
        Window.destroy();
        Interface.cleanup();
    }

}



hope that helps some.

Hi Naj



Many thanx for this :slight_smile: . I will play with this and let you when I succeed to use it in jme.



tomcat

While I haven’t played with the gui code yet, but judging from Naj’s code you should be able to basically put that render code into the render method of your game. Like normal.



It should be said, I have gone on to the redesign of the core system. It’s going very well, but has a long way to go before it will have the capabilities of the current system. However, it will provide you with the follow… Pluggable Renderers! That’s right, it can now support LWJGL, JOGL, Software, etc, etc, etc. All rendering is handled at one spot now, which frees up the models to only handle their data. All models descend from TriMesh and the Renderer can render a TriMesh. In fact, the LWJGLRenderer (the only one I have written so far) renders the tri mesh as vertex arrays making the Frame Rate about 10 times higher than the current core.



As you can tell, I’m pretty excited about it. It’s still early, there’s: The pluggable renderer, display creation, scene graph nodes are up and that’s about it. But it’s coming along and coming well. I plan on releasing this in a couple days, I’m also writing extensive word docs to go along with it.



I’m hoping you guys will enjoy it. It will handle most things you have been requesting and should do it well.

sounds pretty sweet!

Mojo



Thats great news. I am looking forward to it, especially like to know what is happening with the scnegraph and collision detection.



tomcat.

Naj - thanks for the code :slight_smile: Spaghetti does looks good as a non jogl/awt/swing gui option.



mojo - good news regarding the rendering 8) , I was wondering the other day about how to render lwjgl based stuff like spaghetti - I need not wonder no longer! Thanks. :slight_smile:

Hi,



i voted for LWJGL because

i cannt get JOGL startet under

linux. But in principle i think

this should only effect the

Renderer implementation. I personally

would not mix SceneGraphManagement

with the OpenGL Renderer. The

OpenGL Renderer should have methods

to render graphic primitives like

point, line, triangle, trimesh and some

methods to set the frustum, and some

methods to set the RenderState, like Fog.



Then i would implement a SceneGraphRenderer

using something like the Visitor Pattern (Patterns in Java Vol 1,

author: Mark Grand),

which does the SceneGraph traversal and uses

an OpenGL Renderer to render the SceneGraph.



The camera implementation would use the

methods of the OpenGL Renderer (setFrustum()),

so it is independent from the OpenGL Binding used.



To switch between different OpenGL Renderer

implementations i would use the ToolkitFactory Pattern,

which enables you to switch between implementations.



// Request a RenderToolkit, but my code is implemented

// against interfaces, so i can switch between the

// implementations

IRenderToolkit toolkit = RenderToolkitFactory.getToolkit(RENDERER_LWJGL);



// The toolkit gives me access to the Implementations

// of the interfaces i use, without knowing which implementation

IRenderer renderer = toolkit.getRenderer();



// Here i request an implementation of the camera

// interface

ICamera camera = renderer.getCamera();



// here i use a camera, because the camera

// delegates the method calls to the renderer

// this changes the view of the renderer

camera.set(…);



// And finally pass the renderer for the sceneGraph

// traversal, therefor the renderer must implement

// The ISceneGraphVisitor Interface.

sceneGraph.accept(renderer);

The current “redesign” follows these principles. Scenegraph nodes know nothing of a specific renderer. When a leaf is reached, it is ready to be rendered and passed to a specific renderer. Where a renderer can draw (currently) points, lines and triangle meshes.



The user knows nothing of specific renderers either. The user can simply use the interfaces/abstract classes without every touching an LWJGLDisplaySystem or LWJGLCamera, etc. Factory methods will return the LWJGLDisplaySystem as a DisplaySystem. The renderer and camera is created internally there.



Right now render states follow the heirarchy of: RenderState <- AlphaState <- LWJGLAlphaState. But again, I retrieve my alpha state by:



AlphaState as = display.getRenderer().getAlphaState();



This returns an LWJGLRenderer, and then an LWJGLAlphaState. But I never have to know that, it could be a JOGLRenderer and JOGLAlphaState for all I care.



I think this handles all the concepts you were talking about. I’m trying to keep documentation up to date, but there’s only so much time.