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.
Title: Re: Problem with AWTGLCanvas
Post by: AGP on November 05, 2025, 02:05:09 AM
There's a little problem with the Canvas fix: it's not centering. I've only noticed once I updated jpct on a very centered (fighting) game. Check out the two images. One, naturally, is before the fix, the other one is after. Everything renders in the same place, it's just that the new version doesn't clip on the canvas space.

Also, we're missing a version of blit() because the following line isn't compiling: buffer.blit(splash1, 0, 0, 0, 0, splash1.getWidth(), splash1.getHeight(), buffer.getOutputWidth(), buffer.getOutputHeight(), 200, true);

https://www.dropbox.com/scl/fi/hlz31f7yuhgpusijmhjbw/CanvasFix_before.png?rlkey=rx8al2fz1ani7dz3khprxkgc5&st=cxyi3f3w&dl=0

https://www.dropbox.com/scl/fi/dinizqm379uh1rzaho1qf/CanvasFix_after.png?rlkey=axi07hpkewics8qbfmsgpp65m&st=9ww1q8pb&dl=0
Title: Re: Problem with AWTGLCanvas
Post by: EgonOlsen on November 07, 2025, 08:56:48 AM
I'm not sure what you mean by the missing blit call!? Missing compared to what? Actually, nothing has changed for ages in that regard.
Title: Re: Problem with AWTGLCanvas
Post by: AGP on November 07, 2025, 10:26:54 AM
That line compiles with old jpct versions and not with the latest one.

What about the canvas?
Title: Re: Problem with AWTGLCanvas
Post by: EgonOlsen on November 10, 2025, 09:43:06 AM
The last change regarding blit was 8 years ago when I moved from int-parameters to floats. No signature change other than that happened. I tried your line with the latest version, it compiles just fine. I'm not sure why you are having issues with it. What part of it is causing which problem exactly?

About the canvas: I don't know, if I even got the issue? Is it that it's somehow shifted to the left when it's supposed to be centered?
Title: Re: Problem with AWTGLCanvas
Post by: AGP on November 13, 2025, 09:27:17 AM
It's bizarre that you compiled. I'll see if I did something weird to the jar.

Yeah, it's like our repair just extended the drawing area. I'll show you the code tomorrow, but it should draw at the ends of the frame, but instead it's not centralized.