Skip to content

Commit

Permalink
Added a new visualizer panel for rendering using NEWT for better perf…
Browse files Browse the repository at this point in the history
…ormance (#2602)
  • Loading branch information
breiler authored Sep 5, 2024
1 parent f3f65ab commit 8a63432
Show file tree
Hide file tree
Showing 12 changed files with 519 additions and 170 deletions.
4 changes: 4 additions & 0 deletions ugs-core/src/resources/MessagesBundle_en_US.properties
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,10 @@ platform.window.visualizer.tooltip = 3D view of the current operation.
platform.window.fileBrowser = File Browser
platform.window.fileBrowser.tooltip = Load a folder to view and work with files.
platform.visualizer.edit.options.title = Visualizer options
platform.visualizer.newt = Use NEWT rendering engine
platform.visualizer.newt.desc = Use the new NEWT rendering engine for better performance
platform.visualizer.newt.samples = NEWT antialiasing samples
platform.visualizer.newt.samples.desc = How many antialiasing samples to make
platform.visualizer.color.background = Background Color
platform.visualizer.tool = Show tool location
platform.visualizer.color.tool = Tool color
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ This file is part of Universal Gcode Sender (UGS).
*/
package com.willwinder.ugs.nbm.visualizer;

import com.jogamp.opengl.util.AnimatorBase;
import com.jogamp.opengl.util.FPSAnimator;
import com.willwinder.ugs.nbm.visualizer.renderables.GcodeModel;
import com.willwinder.ugs.nbm.visualizer.renderables.Selection;
Expand Down Expand Up @@ -66,7 +67,7 @@ public class RendererInputHandler implements
private static final int HIGH_FPS = 15;
private static final int LOW_FPS = 4;
private final GcodeRenderer gcodeRenderer;
private final FPSAnimator animator;
private final AnimatorBase animator;
private final BackendAPI backend;
private final GcodeModel gcodeModel;
private final SizeDisplay sizeDisplay;
Expand All @@ -76,11 +77,10 @@ public class RendererInputHandler implements
private Position selectionStart = null;
private Position selectionEnd = null;

public RendererInputHandler(GcodeRenderer gr, FPSAnimator a, BackendAPI backend) {
public RendererInputHandler(GcodeRenderer gr, AnimatorBase a, BackendAPI backend) {
gcodeRenderer = gr;
animator = a;
this.backend = backend;
animator.start();
settings = backend.getSettings();

gcodeModel = new GcodeModel(Localization.getString("platform.visualizer.renderable.gcode-model"), backend);
Expand Down Expand Up @@ -110,9 +110,11 @@ private static Point getScreenPoint(int x, int y) {
}

private void setFPS(int fps) {
animator.stop();
animator.setFPS(fps);
animator.start();
if (animator instanceof FPSAnimator fpsAnimator) {
fpsAnimator.stop();
fpsAnimator.setFPS(fps);
fpsAnimator.start();
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,37 +18,25 @@ This file is part of Universal Gcode Sender (UGS).
*/
package com.willwinder.ugs.nbm.visualizer;

import com.jogamp.opengl.GLCapabilities;
import com.jogamp.opengl.GLException;
import com.jogamp.opengl.awt.GLJPanel;
import com.jogamp.opengl.util.FPSAnimator;
import com.willwinder.ugs.nbm.visualizer.options.VisualizerOptionsPanel;
import com.willwinder.ugs.nbm.visualizer.shared.GcodeRenderer;
import com.willwinder.ugs.nbp.core.actions.OpenLogDirectoryAction;
import com.willwinder.ugs.nbp.lib.lookup.CentralLookup;
import com.willwinder.ugs.nbm.visualizer.jogl.NewtVisualizationPanel;
import com.willwinder.ugs.nbm.visualizer.jogl.VisualizationPanel;
import com.willwinder.ugs.nbm.visualizer.options.VisualizerOptions;
import com.willwinder.ugs.nbp.lib.services.LocalizingService;
import static com.willwinder.ugs.nbp.lib.services.LocalizingService.lang;
import com.willwinder.ugs.nbp.lib.services.TopComponentLocalizer;
import com.willwinder.universalgcodesender.i18n.Localization;
import com.willwinder.universalgcodesender.model.BackendAPI;
import org.apache.commons.lang3.StringUtils;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.modules.OnStart;
import org.openide.util.Lookup;
import org.openide.util.NbPreferences;
import org.openide.windows.Mode;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.Preferences;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Color;

/**
* Setup JOGL canvas, GcodeRenderer and RendererInputHandler.
Expand All @@ -69,14 +57,8 @@ public final class Visualizer2TopComponent extends TopComponent {
public final static String VisualizerWindowPath = LocalizingService.MENU_WINDOW;
public final static String VisualizerActionId = "com.willwinder.ugs.nbm.visualizer.Visualizer2TopComponent";
public final static String VisualizerCategory = LocalizingService.CATEGORY_WINDOW;
private static final Logger logger = Logger.getLogger(Visualizer2TopComponent.class.getName());
private final BackendAPI backend;
private GLJPanel panel;
private RendererInputHandler rih;

public Visualizer2TopComponent() {
backend = CentralLookup.getDefault().lookup(BackendAPI.class);

setMinimumSize(new java.awt.Dimension(50, 50));
setPreferredSize(new java.awt.Dimension(200, 200));
setLayout(new java.awt.BorderLayout());
Expand Down Expand Up @@ -107,98 +89,12 @@ protected void componentOpened() {
JPanel borderedPanel = new JPanel();
borderedPanel.setLayout(new BorderLayout());
borderedPanel.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1));
borderedPanel.add(initializeVisualizationPanel(), BorderLayout.CENTER);
add(borderedPanel, BorderLayout.CENTER);
}

private JComponent initializeVisualizationPanel() {
try {
panel = makeWindow();
return panel;
} catch (GLException exception) {
JLabel errorMessage = new JLabel("<html>Could not initialize OpenGL visualization, please check the log file for details <a href='#'>messages.log</a></html>", JLabel.CENTER);
errorMessage.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
new OpenLogDirectoryAction().actionPerformed(null);
}
});
return errorMessage;
}
}

@Override
protected void componentClosed() {
super.componentClosed();

if (rih != null) {
backend.removeUGSEventListener(rih);
rih.dispose();
}

logger.log(Level.INFO, "Component closed, panel = " + panel);
if (panel == null) return;

remove(panel);
//dispose of panel and native resources
panel.destroy();
panel = null;
}

@Override
protected void componentActivated() {
super.componentActivated();
if (panel != null) {
panel.setSize(getSize());
//need to update complete component tree
invalidate();

if (getTopLevelAncestor() != null) {
getTopLevelAncestor().invalidate();
getTopLevelAncestor().revalidate();
}
if (VisualizerOptions.getBooleanOption(VisualizerOptions.VISUALIZER_OPTION_NEWT, false)) {
borderedPanel.add(new NewtVisualizationPanel(), BorderLayout.CENTER);
} else {
borderedPanel.add(new VisualizationPanel(), BorderLayout.CENTER);
}
}

private GLJPanel makeWindow() throws GLException {
GLCapabilities glCaps = new GLCapabilities(null);
final GLJPanel p = new GLJPanel(glCaps);

GcodeRenderer renderer = Lookup.getDefault().lookup(GcodeRenderer.class);
if (renderer == null) {
throw new IllegalArgumentException("Failed to access GcodeRenderer.");
}

FPSAnimator animator = new FPSAnimator(p, 15);
this.rih = new RendererInputHandler(renderer, animator, backend);

Preferences pref = NbPreferences.forModule(VisualizerOptionsPanel.class);
pref.addPreferenceChangeListener(this.rih);

File f = (backend.getProcessedGcodeFile() != null) ?
backend.getProcessedGcodeFile() : backend.getGcodeFile();
if (f != null) {
this.rih.setGcodeFile(f.getAbsolutePath());
}

// Install listeners...
backend.addUGSEventListener(this.rih);

// key listener...
p.addKeyListener(this.rih);

// mouse wheel...
p.addMouseWheelListener(this.rih);

// mouse motion...
p.addMouseMotionListener(this.rih);

// mouse...
p.addMouseListener(this.rih);

p.addGLEventListener(renderer);

return p;
add(borderedPanel, BorderLayout.CENTER);
}

@OnStart
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
Copyright 2024 Will Winder
This file is part of Universal Gcode Sender (UGS).
UGS is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
UGS 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
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with UGS. If not, see <http://www.gnu.org/licenses/>.
*/
package com.willwinder.ugs.nbm.visualizer.jogl;

import com.jogamp.newt.event.KeyEvent;
import com.jogamp.newt.event.KeyListener;

import java.awt.Component;

/**
* A keyboard listener adapter for translating between events from the NEWT JOGL canvas to AWT listeners.
*
* @author Joacim Breiler
*/
public class NewtKeyboardListenerAdapter implements KeyListener {
private final java.awt.event.KeyListener keyListener;
private final Component component;

public NewtKeyboardListenerAdapter(Component component, java.awt.event.KeyListener keyListener) {
this.keyListener = keyListener;
this.component = component;
}

@Override
public void keyPressed(KeyEvent e) {
this.keyListener.keyPressed(new java.awt.event.KeyEvent(component, 0, e.getWhen(), e.getModifiers(), e.getKeyCode(), e.getKeyChar()));
}

@Override
public void keyReleased(KeyEvent e) {
this.keyListener.keyPressed(new java.awt.event.KeyEvent(component, 0, e.getWhen(), e.getModifiers(), e.getKeyCode(), e.getKeyChar()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
Copyright 2024 Will Winder
This file is part of Universal Gcode Sender (UGS).
UGS is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
UGS 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
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with UGS. If not, see <http://www.gnu.org/licenses/>.
*/
package com.willwinder.ugs.nbm.visualizer.jogl;

import com.jogamp.newt.event.MouseListener;

import java.awt.Component;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;


public class NewtMouseListenerAdapter implements MouseListener {

private final java.awt.event.MouseListener mouseListener;
private final MouseWheelListener mouseWheelListener;
private final MouseMotionListener mouseMotionListener;
private final Component component;

public NewtMouseListenerAdapter(Component component, java.awt.event.MouseListener mouseListener, MouseWheelListener mouseWheelListener, MouseMotionListener mouseMotionListener) {
this.component = component;
this.mouseListener = mouseListener;
this.mouseWheelListener = mouseWheelListener;
this.mouseMotionListener = mouseMotionListener;
}

@Override
public void mouseClicked(com.jogamp.newt.event.MouseEvent e) {
mouseListener.mouseClicked(new java.awt.event.MouseEvent(component, 0, e.getWhen(), e.getModifiers(), e.getX(), e.getY(), e.getClickCount(), false, e.getButton()));
}

@Override
public void mouseEntered(com.jogamp.newt.event.MouseEvent e) {
mouseListener.mouseEntered(new java.awt.event.MouseEvent(component, 0, e.getWhen(), e.getModifiers(), e.getX(), e.getY(), e.getClickCount(), false, e.getButton()));
}

@Override
public void mouseExited(com.jogamp.newt.event.MouseEvent e) {
mouseListener.mouseExited(new java.awt.event.MouseEvent(component, 0, e.getWhen(), e.getModifiers(), e.getX(), e.getY(), e.getClickCount(), false, e.getButton()));
}

@Override
public void mousePressed(com.jogamp.newt.event.MouseEvent e) {
mouseListener.mousePressed(new java.awt.event.MouseEvent(component, 0, e.getWhen(), e.getModifiers(), e.getX(), e.getY(), e.getClickCount(), false, e.getButton()));
}

@Override
public void mouseReleased(com.jogamp.newt.event.MouseEvent e) {
mouseListener.mouseReleased(new java.awt.event.MouseEvent(component, 0, e.getWhen(), e.getModifiers(), e.getX(), e.getY(), e.getClickCount(), false, e.getButton()));
}

@Override
public void mouseMoved(com.jogamp.newt.event.MouseEvent e) {
mouseMotionListener.mouseMoved(new java.awt.event.MouseEvent(component, 0, e.getWhen(), e.getModifiers(), e.getX(), e.getY(), e.getClickCount(), false, e.getButton()));

}

@Override
public void mouseDragged(com.jogamp.newt.event.MouseEvent e) {
mouseMotionListener.mouseDragged(new java.awt.event.MouseEvent(component, 0, e.getWhen(), e.getModifiers(), e.getX(), e.getY(), e.getClickCount(), false, e.getButton()));

}

@Override
public void mouseWheelMoved(com.jogamp.newt.event.MouseEvent e) {
mouseWheelListener.mouseWheelMoved(new MouseWheelEvent(component, 0, e.getWhen(), e.getModifiers(), e.getX(), e.getY(), e.getClickCount(), false, MouseWheelEvent.WHEEL_UNIT_SCROLL, Math.round(e.getRotationScale()), Math.round(e.getRotation()[1])));
}
}
Loading

0 comments on commit 8a63432

Please sign in to comment.