LWJGL Forum

Programming => OpenGL => Topic started by: pbartosz on February 09, 2013, 15:06:54

Title: NVPathRendering doesn't work [SOLVED]
Post by: pbartosz on February 09, 2013, 15:06:54
Hi,
I'm trying to develop simple OpenGL app using NVPathRendering extenstion.
I wrote some code using LWJGL, but it doesn't seem to work.
Could you, please, tell me what's wrong in this code?
I'll be very grateful for your help. It's really important to me.

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.NVPathRendering.*;
import static org.lwjgl.opengl.EXTDirectStateAccess.*;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.nio.ByteBuffer;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.UIManager;

import org.lwjgl.LWJGLException;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;

public class Main {
   private boolean closeRequested = false;

   private int pathObj = 42;

   public Main() {
JFrame frame = new JFrame();
frame.addWindowListener(new WindowAdapter() {
   @Override
   public void windowClosing(WindowEvent e) {
closeRequested = true;
   }
});



Canvas canvas = new Canvas();
canvas.setSize(640, 480);
canvas.setFocusable(true);
canvas.setIgnoreRepaint(true);

// frame.setLayout(new BorderLayout());
frame.add(button, BorderLayout.NORTH);
frame.add(canvas, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);

// Display Setup
try {
   Display.setResizable(true);
   Display.setParent(canvas);
   Display.sync(60);
   Display.create();
} catch (LWJGLException ex) {
   ex.printStackTrace();
}

System.out.println("OpenGL version: " + glGetString(GL_VERSION)); //return OpenGL 4.2

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 600, 0, 480, 1, -1);
glMatrixMode(GL_MODELVIEW);

String psPathString = "100 180 moveto"
+ " 40 10 lineto 190 120 lineto 10 120 lineto 160 10 lineto closepath"
+ " 300 300 moveto" + " 100 400 100 200 300 100 curveto"
+ " 500 200 500 400 300 300 curveto closepath";
ByteBuffer psPathStringBuf = ByteBuffer.allocateDirect(psPathString
.getBytes().length);
psPathStringBuf.put(psPathString.getBytes());

glPathStringNV(pathObj, GL_PATH_FORMAT_PS_NV, psPathStringBuf);

glPathParameteriNV(pathObj, GL_PATH_JOIN_STYLE_NV, GL_ROUND_NV);
glPathParameterfNV(pathObj, GL_PATH_STROKE_WIDTH_NV, (float) 6.5);

// Render Loop
while (!Display.isCloseRequested() && !closeRequested) {
   glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

   pathRender(); // this do nothing!

   // render(); //this renders correctly !

   Display.update();
}

Display.destroy();
System.exit(0); // to exit faster
   }

   private void pathRender() {
glClearStencil(0);
glClearColor(0, 0, 0, 0);
glStencilMask(~0);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

glMatrixLoadIdentityEXT(GL_PROJECTION);
glMatrixLoadIdentityEXT(GL_MODELVIEW);
glMatrixOrthoEXT(GL_MODELVIEW, 0, 640, 0, 400, -1, 1);

glStencilFillPathNV(pathObj, GL_COUNT_UP_NV, 0x1F);

glColor3f(0, 1, 0); // green
glCoverFillPathNV(pathObj, GL_BOUNDING_BOX_NV);

glStencilStrokePathNV(pathObj, 0x1, ~0);
glColor3f(1, 1, 0); // yellow
glCoverStrokePathNV(pathObj, GL_CONVEX_HULL_NV);
   }

   public void render() {
glColor3f(1, 1, 1); // white render color
glRectf(100, 100, 110, 110);
glBegin(GL_POINTS); // point at 5 above mouse location
glVertex2d(Mouse.getX(), Mouse.getY() + 5);
glEnd();
   }

   public static void main(String args[]) {
try {
   // Set System L&F
   UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
   e.printStackTrace();
}

new Main();
   }
}
Title: Re: NVPathRendering doesn't work
Post by: spasi on February 09, 2013, 15:55:34
Without running your code, one obvious bug is not flipping the path string buffer before passing it to glPathStringNV. It should be:

String psPathString = "100 180 moveto"
+ " 40 10 lineto 190 120 lineto 10 120 lineto 160 10 lineto closepath"
+ " 300 300 moveto" + " 100 400 100 200 300 100 curveto"
+ " 500 200 500 400 300 300 curveto closepath";
ByteBuffer psPathStringBuf = ByteBuffer.allocateDirect(psPathString
.getBytes().length);
psPathStringBuf.put(psPathString.getBytes());
psPathStringBuf.flip();

glPathStringNV(pathObj, GL_PATH_FORMAT_PS_NV, psPathStringBuf);
Title: Re: NVPathRendering doesn't work
Post by: pbartosz on February 10, 2013, 00:43:52
Thanks! After your change something is rendering, but it's still not the shape I expect.
The below screen presents how it should look like.
I think that path isn't correctly stenciled in the stencil buffer.
SVG path looks correct:
String star = "M 300 300 C 100 400,100 200,300 100,500 200,500 400,300 300Z"; //heart
Red points in the right window represents path coordinates.
Any idea what's wrong?

(http://img546.imageshack.us/img546/8942/nvpathrenderingproblem.png)

import static org.lwjgl.opengl.EXTDirectStateAccess.glMatrixLoadIdentityEXT;
import static org.lwjgl.opengl.EXTDirectStateAccess.glMatrixOrthoEXT;
import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_KEEP;
import static org.lwjgl.opengl.GL11.GL_MODELVIEW;
import static org.lwjgl.opengl.GL11.GL_NOTEQUAL;
import static org.lwjgl.opengl.GL11.GL_PROJECTION;
import static org.lwjgl.opengl.GL11.GL_STENCIL_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_STENCIL_TEST;
import static org.lwjgl.opengl.GL11.GL_VERSION;
import static org.lwjgl.opengl.GL11.GL_ZERO;
import static org.lwjgl.opengl.GL11.glBegin;
import static org.lwjgl.opengl.GL11.glClear;
import static org.lwjgl.opengl.GL11.glClearColor;
import static org.lwjgl.opengl.GL11.glClearStencil;
import static org.lwjgl.opengl.GL11.glColor3f;
import static org.lwjgl.opengl.GL11.glEnable;
import static org.lwjgl.opengl.GL11.glEnd;
import static org.lwjgl.opengl.GL11.glGetString;
import static org.lwjgl.opengl.GL11.glLoadIdentity;
import static org.lwjgl.opengl.GL11.glMatrixMode;
import static org.lwjgl.opengl.GL11.glOrtho;
import static org.lwjgl.opengl.GL11.glStencilFunc;
import static org.lwjgl.opengl.GL11.glStencilMask;
import static org.lwjgl.opengl.GL11.glStencilOp;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.NVPathRendering.GL_CONVEX_HULL_NV;
import static org.lwjgl.opengl.NVPathRendering.GL_PATH_FORMAT_SVG_NV;
import static org.lwjgl.opengl.NVPathRendering.GL_PATH_JOIN_STYLE_NV;
import static org.lwjgl.opengl.NVPathRendering.GL_PATH_STROKE_WIDTH_NV;
import static org.lwjgl.opengl.NVPathRendering.GL_ROUND_NV;
import static org.lwjgl.opengl.NVPathRendering.glCoverStrokePathNV;
import static org.lwjgl.opengl.NVPathRendering.glPathParameteriNV;
import static org.lwjgl.opengl.NVPathRendering.glPathStringNV;
import static org.lwjgl.opengl.NVPathRendering.glStencilStrokePathNV;
import static org.lwjgl.opengl.NVPathRendering.*;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.nio.ByteBuffer;

import javax.swing.JFrame;
import javax.swing.UIManager;

import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;

public class Main {
   private boolean closeRequested = false;

   private int pathObj = 41;

   public Main() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
closeRequested = true;
}
});

Canvas canvas = new Canvas();
canvas.setSize(500, 400);
canvas.setFocusable(true);
canvas.setIgnoreRepaint(true);

frame.setLayout(new BorderLayout());
frame.add(canvas, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);

try {
Display.setResizable(true);
Display.setParent(canvas);
Display.sync(60);
Display.create();
} catch (LWJGLException ex) {
ex.printStackTrace();
}

System.out.println("OpenGL version: " + glGetString(GL_VERSION));

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 500, 0, 400, 1, -1);
glMatrixMode(GL_MODELVIEW);

// SVG format
String star =
"M 300 300 C 100 400,100 200,300 100,500 200,500 400,300 300Z"; //heart
ByteBuffer starBuf =
ByteBuffer.allocateDirect(star.getBytes().length);
starBuf.put(star.getBytes());
starBuf.flip();
glPathStringNV(pathObj, GL_PATH_FORMAT_SVG_NV, starBuf);

glPathParameteriNV(pathObj, GL_PATH_JOIN_STYLE_NV, GL_ROUND_NV);
glPathParameterfNV(pathObj, GL_PATH_STROKE_WIDTH_NV, (float) 6.5);

while (!Display.isCloseRequested() && !closeRequested) {
pathRender();
render();
Display.update();
}
Display.destroy();
frame.dispose();
//System.exit(0);
   }

   private void pathRender() {
glClearStencil(0);
glClearColor(0, 0, 0, 0);
glStencilMask(~0);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

glMatrixLoadIdentityEXT(GL_PROJECTION);
glMatrixLoadIdentityEXT(GL_MODELVIEW);
glMatrixOrthoEXT(GL_MODELVIEW, 0, 500, 0, 400, -1, 1);

// glStencilFillPathNV(pathObj, GL_COUNT_UP_NV, 0x1F);
// glEnable(GL_STENCIL_TEST);
// boolean even_odd = false;
// if (even_odd) {
//    glStencilFunc(GL_NOTEQUAL, 0, 0x1);
// } else {
//    glStencilFunc(GL_NOTEQUAL, 0, 0x1F);
// }
// glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
// glColor3f(1, 1, 0); // yellow
// glCoverFillPathNV(pathObj, GL_BOUNDING_BOX_NV);

glStencilStrokePathNV(pathObj, 0x1, ~0);
glColor3f(1, 1, 1); //white
glCoverStrokePathNV(pathObj, GL_CONVEX_HULL_NV);
   }

   public void render() {
glColor3f(1, 0, 0);
GL11.glPointSize(5);
glBegin(GL11.GL_POINTS); // point at 5 above mouse location
GL11.glVertex3f(300,300, 0);
GL11.glVertex3f(100,400, 0);
GL11.glVertex3f(100,200, 0);
GL11.glVertex3f(300,100, 0);
GL11.glVertex3f(500,200, 0);
GL11.glVertex3f(500,400, 0);
glEnd();
   }

   public static void main(String args[]) {
try {
   // Set System L&F
   UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
   e.printStackTrace();
}

new Main();
   }
}
Title: Re: NVPathRendering doesn't work [SOLVED]
Post by: pbartosz on February 10, 2013, 03:06:52
Problem solved! The problem was Stencil Buffer size set to 0 bits. Display.create(new PixelFormat(0,24,8,8)) do the trick.

I have another question.
How can I convert 2 dim array to ByteBuffer?
Below code doesn't seem to work:

byte[] pathCommands = { GL_MOVE_TO_NV, GL_LINE_TO_NV, GL_LINE_TO_NV,
GL_LINE_TO_NV, GL_LINE_TO_NV, GL_CLOSE_PATH_NV,
'M', 'C', 'C', 'Z' };
ByteBuffer pathCommandsBuf = ByteBuffer.allocateDirect(pathCommands.length);
pathCommandsBuf.put(pathCommands);
pathCommandsBuf.flip();

       /* C++ style 2 dim array
       static const GLshort pathCoords[12][2] =
       { {100, 180}, {40, 10}, {190, 120}, {10, 120}, {160, 10},
       {300,300}, {100,400}, {100,200}, {300,100},
       {500,200}, {500,400}, {300,300} };
       */

int pathCoords[] = { 100, 180, 40, 10, 190, 120, 10, 120, 160, 10, 300,
300, 100, 400, 100, 200, 300, 100, 500, 200, 500, 400, 300, 300 };
ByteBuffer pathCoordsBuf = ByteBuffer.allocateDirect(pathCoords.length * 2);
for (int i : pathCoords) { //doesn't work!
   pathCoordsBuf.putShort((short)pathCoords[i]);
}
/*
       for (int i = 0; i < pathCoords.length / 2; i++) { //renders something
   pathCoordsBuf.putShort((short)pathCoords[i]);
}
*/
pathCoordsBuf.flip();

glPathCommandsNV(pathObj, pathCommandsBuf, GL11.GL_SHORT, pathCoordsBuf);


Edit: pathCoordsBuf.order(ByteOrder.LITTLE_ENDIAN) do the trick.

But as shown in above code, when I fill only half of pathCoordsBuf, it's rendering some shape.
In NVidia example, coords size is 24, not 48 as pathCommandsBuf.remaining() returns.
It's possible that there is a bug in NVPathRendering.glPathCommandsNV(...) method and there should be something like
coords.remaining() / sizeof(coordType) as argument to native method.

Workaround is to set
pathCoordsBuf.limit(pathCoordsBuf.capacity() / 2);