www.jpct.net

jPCT - a 3d engine for Java => Support => Topic started by: AGP on August 26, 2025, 11:58:45 PM

Title: Problem with AWTGLCanvas
Post by: AGP on August 26, 2025, 11:58:45 PM
Egon, have you ever run into the problem with AWTGLCanvas in which the entire rendering is out of place on the canvas that I did about a decade ago and ever since on every computer I've ever run my stuff on? I'd love to have that fixed (most likely by switching to lwjgl 3 and convincing them to add AWTGLCanvas back). What do you think?
Title: Re: Problem with AWTGLCanvas
Post by: EgonOlsen on August 29, 2025, 10:19:07 AM
I've moved the question into a new topic, just in case you are wondering.

I'm not aware of a problem with the location of AWTGLCanvas but then again, I've never really used it in situations where it doesn't use the whole frame. So I never tried to use it as part of an actual UI.

Have to tried to disable Java2D's accelerated rendering pipeline? Maybe it's a problem with that (albeit I doubt it, but it might be worth a try).
Title: Re: Problem with AWTGLCanvas
Post by: AGP on September 01, 2025, 09:13:01 AM
I've tried everything. Test it out as an actual UI and let me know, please.
Title: Re: Problem with AWTGLCanvas
Post by: AGP on September 02, 2025, 09:14:57 PM
Although I should reiterate that I usually use it on the entire frame. I'm making a sometimes-2d sometimes 3d game and it would be available there.
Title: Re: Problem with AWTGLCanvas
Post by: AGP on September 25, 2025, 05:17:32 AM
Egon?
Title: Re: Problem with AWTGLCanvas
Post by: EgonOlsen on September 25, 2025, 05:30:37 PM
I'm not of much help here, I'm afraid. I've actually no clue about UI stuff in Java. All I'm usually doing is to open a JFrame/Frame and then draw stuff all by myself.

I dimly remember that others tried to mix an actual UI with the AWTGLCanvas and IIRC, it didn't work our too well (but was possible to a degree). But I couldn't find this thread.

Have you actually tried this approach: https://www.jpct.net/wiki/index226d.html?title=Using_jPCT_in_Swing (https://www.jpct.net/wiki/index226d.html?title=Using_jPCT_in_Swing)
Title: Re: Problem with AWTGLCanvas
Post by: AGP on September 25, 2025, 08:58:25 PM
I usually use AWT, but I'll try Swing to see if it's still there. Have you used the Canvas on a AWT frame to see the problem?
Title: Re: Problem with AWTGLCanvas
Post by: AGP on September 26, 2025, 01:47:01 AM
This seems to be software. Am I missing something?
Title: Re: Problem with AWTGLCanvas
Post by: EgonOlsen on September 26, 2025, 08:17:39 AM
Quote from: AGP on September 26, 2025, 01:47:01 AMThis seems to be software. Am I missing something?
I'm not sure what you mean!?
Title: Re: Problem with AWTGLCanvas
Post by: AGP on September 27, 2025, 09:01:49 AM
I tried quoting this line, but it didn't show up for some reason:
Have you actually tried this approach: https://www.jpct.net/wiki/index226d.html?title=Using_jPCT_in_Swing

This example seems to be using software rendering.
Title: Re: Problem with AWTGLCanvas
Post by: AGP on September 27, 2025, 10:32:46 AM
CG proposed the following changes to AWTJPCTCanvas. If you could possibly compile it for me (I've never compiled jpct, only my C# port) so that I could test it I would be very grateful:

package com.threed.jpct;

import org.lwjgl.opengl.*;

import java.awt.GraphicsConfiguration;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.geom.AffineTransform;

class AWTJPCTCanvas extends AWTGLCanvas implements IThreadBuffer {

      private static final long serialVersionUID = 1L;

      private AWTGLRenderer renderer = null;

      private AWTDisplayList[] list = null;

      private AWTDisplayList onceList = null;

      private int curList = 0;

      private Object lock = new Object();

      private boolean paintObserver = false;

      private Object[] result = null;

      AWTJPCTCanvas() throws Exception {
      }

      AWTJPCTCanvas(AWTGLRenderer myRenderer) throws Exception {
              super();
              init(myRenderer);
      }

      AWTJPCTCanvas(AWTGLRenderer myRenderer, PixelFormat pf) throws Exception {
              super(pf);
              init(myRenderer);
      }

      public void setSamples(int samples) {
              // Bereits im PF erledigt...hier egal...
      }

      protected void init(AWTGLRenderer myRenderer) {
              renderer = myRenderer;
              list = new AWTDisplayList[2];
              list
[o]= new AWTDisplayList();
              list[1] = new AWTDisplayList();
              onceList = new AWTDisplayList();

              // Reassert viewport after resizes so device-pixel size stays in sync.
              addComponentListener(new ComponentAdapter() {
                    @Override
                    public void componentResized(ComponentEvent e) {
                            // Trigger a repaint so paintGL() can recompute the viewport.
                            repaint();
                    }
              });
      }

      public void exceptionOccurred(org.lwjgl.LWJGLException e) {
              if (e.getMessage().indexOf("No support for") != -1) {
                    // A hack to take care of missing aa-support in intel. Injects a new
                    // pixel format into the canvas vie reflection and makes the
                    // canvas think that it's new...
                    try {
                            java.lang.reflect.Field field = AWTGLCanvas.class.getDeclaredField("pixel_format");
                            field.setAccessible(true);
                            PixelFormat pf = (PixelFormat) field.get(this);
                            if (pf == null || pf.getSamples() != 0) {
                                  Logger.log("No support for multi sampling...trying to recover!", Logger.WARNING);
                                  field.set(this, new PixelFormat());

                                  java.lang.reflect.Field count = AWTGLCanvas.class.getDeclaredField("reentry_count");
                                  java.lang.reflect.Field peer = AWTGLCanvas.class.getDeclaredField("peer_info");
                                  count.setAccessible(true);
                                  peer.setAccessible(true);
                                  peer.set(this, (Object[]) null);
                            } else {
                                  Logger.log(e, Logger.ERROR);
                            }
                    } catch (Throwable e1) {
                            Logger.log(e1, Logger.WARNING);
                            e.printStackTrace();
                            Logger.log(e, Logger.ERROR);
                    }
              } else {
                    Logger.log(e, Logger.ERROR);
              }

      }

      public void dispose() {
              setEnabled(false);
      }

      public final void add(int command, Object params) {
              list[curList].add(command, params);
      }

      public void add(Camera proj, int[] ambient) {
              Object[] params = new Object[2];
              Camera cam2 = new Camera();
              cam2.setBack(proj.getBack().cloneMatrix());
              cam2.setPosition(proj.getPosition());
              cam2.setFOVLimits(proj.getMinFOV(), proj.getMaxFOV());
              cam2.setFOV(proj.getFOV());
              params
[o]= cam2;

              int[] am = new int[ambient.length];
              for (int i = 0; i < am.length; i++) {
                    am[i] = ambient[i];
              }

              params[1] = am;
              add(GLBase.MODE_SET_CAMERA, params);
      }

      public final void addOnce(int command, Object params) {
              onceList.addOnce(command, params);
      }

      public Object getLock() {
              return lock;
      }

      public final void add(VisList v, int s, int e, int m) {
              list[curList].add(v, s, e, m);
      }

      public void enableRenderTarget() {
              list[curList].enableRenderTarget();
      }

      public void disableRenderTarget() {
              list[curList].disableRenderTarget();
      }

      public boolean hasRenderTarget() {
              return list[curList].hasRenderTarget();
      }

      public final void setColor(int col) {
              list[curList].setColor(col);
      }

      public final AWTDisplayList getDisplayList() {
              return list[curList];
      }

      /*
        * public final void fillInstances() { synchronized (lock) {
        * list[curList].fillInstances(); } }
        */
      public final void switchList() {
              if (Config.synchronizedRendering) {
                    while (!list[curList ^ 1].rendered) {
                            Thread.yield();
                    }
              }
             
              synchronized (lock) {
                    list[curList].switchBuffers();
                    curList ^= 1;
                    list[curList].reset();
              }
      }

      public final boolean hasBeenPainted() {
              return paintObserver;
      }

      public final void observePainting() {
              paintObserver = false;
      }

      public final Object[] getPaintResults() {
              if (hasBeenPainted()) {
                    Object[] res = result;
                    result = null;
                    return res;
              }
              return null;
      }

      // --- HiDPI fix: ensure the GL viewport matches the device-pixel backbuffer ---
      /** Ensure GL viewport matches device-pixel backbuffer (fixes HiDPI offset). */
      private void ensureHiDPIVP() {
              int fbW, fbH;
              GraphicsConfiguration gc = getGraphicsConfiguration();
              if (gc != null) {
                    AffineTransform tx = gc.getDefaultTransform();
                    double sx = tx.getScaleX(), sy = tx.getScaleY();
                    int lw = Math.max(1, getWidth());
                    int lh = Math.max(1, getHeight());
                    fbW = (int)Math.round(lw * sx);
                    fbH = (int)Math.round(lh * sy);
              } else {
                    fbW = Math.max(1, getWidth());
                    fbH = Math.max(1, getHeight());
              }
              GL11.glViewport(0, 0, fbW, fbH);
      }
      // ------------------------------------------------------------------------------

      public void paintGL() {

              try {
                    makeCurrent();

                    // HiDPI: align viewport to device-pixel framebuffer before any rendering.
                    ensureHiDPIVP();

                    if (!renderer.isDisposed()) {
                            if (!renderer.isInitialized()) {
                                  renderer.init();
                            }
                            renderer.execute(GLBase.MODE_START_PAINTING, null);

                            synchronized (lock) {
                                  // Normales Zeichnen...
                                  int ind = curList ^ 1;
                                  AWTDisplayList al = list[ind];

                                  int end = al.count;
                                  for (int i = 0; i < end; i++) {
                                          int mode = al.mode[i];
                                          switch (mode) {
                                          case (AWTDisplayList.EXECUTE): {
                                                renderer.executeGL(al, i);
                                                break;
                                          }
                                          case (AWTDisplayList.ARRAY): {
                                                renderer.drawVertexArray(al, i);
                                                break;
                                          }
                                          case (AWTDisplayList.STRIP): {
                                                renderer.drawStrip(al, i);
                                                break;
                                          }
                                          case (AWTDisplayList.POLYGON): {
                                                renderer.drawPolygon(al, i);
                                                break;
                                          }
                                          case (AWTDisplayList.WIREFRAME): {
                                                renderer.drawWireframe(al, i);
                                                break;
                                          }
                                          }
                                  }

                                  // "Once"-Befehle ausführen (pixelgrabben und Context
                                  // befragen z.B.)!
                                  boolean po = paintObserver;
                                  if (onceList.count != 0) {
                                          boolean pop = false;
                                          for (int i = 0; i < onceList.count; i++) {
                                                int mode = onceList.mode[i];
                                                if (mode == AWTDisplayList.EXECUTE_ONCE && !po) {
                                                        result = renderer.executeGL(onceList, i);
                                                        onceList.delete(i);
                                                        pop = true;
                                                }
                                          }

                                          paintObserver = pop;
                                  }
                                  al.rendered = true;
                            }
                    }
                    renderer.execute(GLBase.MODE_END_PAINTING, null);
                    swapBuffers();
              } catch (Exception e) {
                    throw new RuntimeException(e);
              }
      }

      public boolean isVisible() {
              return super.isVisible();
      }
}

Title: Re: Problem with AWTGLCanvas
Post by: EgonOlsen on September 27, 2025, 02:31:26 PM
Quote from: AGP on September 27, 2025, 09:01:49 AMI tried quoting this line, but it didn't show up for some reason:
Have you actually tried this approach: https://www.jpct.net/wiki/index226d.html?title=Using_jPCT_in_Swing

This example seems to be using software rendering.

I don't think so. At the least the text says it's for the AWTGL-Renderer. As mentioned, I've never tried anything like that myself.
Title: Re: Problem with AWTGLCanvas
Post by: AGP on September 27, 2025, 07:49:36 PM
It's software. I managed to recompile just the one class. And the fix worked!
Title: Re: Problem with AWTGLCanvas
Post by: EgonOlsen on September 29, 2025, 10:53:14 AM
I've compiled a new version that includes that change (actually, the code above isn't 100% correct, because it does some changes to the existing code that make no sense, but I've omitted those).

Can you try this one and see if it also fixes your issue: https://www.jpct.de/download/net/jpctapi_133.zip (https://www.jpct.de/download/net/jpctapi_133.zip)
Title: Re: Problem with AWTGLCanvas
Post by: AGP on October 02, 2025, 02:05:25 AM
Thanks very much. I'll let you know before I sleep.
Title: Re: Problem with AWTGLCanvas
Post by: AGP on October 03, 2025, 12:38:25 AM
Exception in thread "main" java.lang.NoClassDefFoundError: com/threed/jpct/AWTJPCTCanvas$1
        at com.threed.jpct.AWTJPCTCanvas.init(AWTJPCTCanvas.java:53)
        at com.threed.jpct.AWTJPCTCanvas.<init>(AWTJPCTCanvas.java:38)
        at com.threed.jpct.AWTGLRenderer.init(AWTGLRenderer.java:73)
        at com.threed.jpct.FrameBuffer.enableRenderer(FrameBuffer.java:1154)
        at com.threed.jpct.FrameBuffer.enableGLCanvasRenderer(FrameBuffer.java:739)
Title: Re: Problem with AWTGLCanvas
Post by: EgonOlsen on October 06, 2025, 10:31:30 AM
Opps, I missed that. I've updated the download, please try again.
Title: Re: Problem with AWTGLCanvas
Post by: AGP on October 06, 2025, 09:22:10 PM
It works, thanks a lot. I'm glad jpct is back at form. Actually, my standalone GLB importer is nearly perfect now. I have a script for splitting animations inside Blender and exporting multiple clips straight into jpct, so it's better than at form.