From b9518d33845cf23facf10de069d877ac0254d9db Mon Sep 17 00:00:00 2001 From: Radek Oslejsek <oslejsek@fi.muni.cz> Date: Tue, 19 May 2020 13:00:21 +0200 Subject: [PATCH] Canvas and GeneralGLEventListener.java returned nack to the code --- .../java/cz/fidentis/analyst/gui/Canvas.java | 746 ++++++++++++++++++ .../analyst/gui/GeneralGLEventListener.java | 502 ++++++++++++ 2 files changed, 1248 insertions(+) create mode 100644 GUI/src/main/java/cz/fidentis/analyst/gui/Canvas.java create mode 100644 GUI/src/main/java/cz/fidentis/analyst/gui/GeneralGLEventListener.java diff --git a/GUI/src/main/java/cz/fidentis/analyst/gui/Canvas.java b/GUI/src/main/java/cz/fidentis/analyst/gui/Canvas.java new file mode 100644 index 00000000..d43db886 --- /dev/null +++ b/GUI/src/main/java/cz/fidentis/analyst/gui/Canvas.java @@ -0,0 +1,746 @@ +package cz.fidentis.analyst.gui; + +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.awt.GLCanvas; +import cz.fidentis.analyst.mesh.io.ModelFileFilter; +import cz.fidentis.analyst.mesh.core.MeshModel; +import cz.fidentis.analyst.mesh.io.MeshObjLoader; +import com.jogamp.opengl.util.FPSAnimator; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dimension; +import java.io.File; +import java.util.Timer; +import java.util.TimerTask; +import javax.swing.ImageIcon; +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; + +/** + * + * @author Natália Bebjaková + * + * Canvas for displaying models containing GLCanvas and navigation. + */ +public class Canvas extends javax.swing.JPanel { + protected GLCanvas glCanvas; + protected long startClickTime = 0; + + protected TimerTask task; + protected Timer timer; + + protected GeneralGLEventListener listener; + + /** + * animator's target frames per second + */ + private static final int FPS = 60; + private final FPSAnimator animator; + + /** + * decides if model is displayed as wire-frame + */ + protected boolean drawWireModel; + + /** + * original model that is loaded from file + */ + protected MeshModel loadedModel; + + protected boolean loaded; + + /** + * + * @return true if model is loaded on canvas, false otherwise + */ + public boolean isLoaded() { + return loaded; + } + + /** + * Creates new form Canva + */ + public Canvas() { + initComponents(); + + // gl version 2 is used + GLCapabilities capabilities = new GLCapabilities(GLProfile.get(GLProfile.GL2)); + capabilities.setDoubleBuffered(true); + + // creates new glCanvas panel for displaying model + glCanvas = new GLCanvas(capabilities); + jPanel1.add(glCanvas); + glCanvas.setVisible(false); + glCanvas.setBackground(Color.black); + + // enables glCanvas to react to events + glCanvas.requestFocusInWindow(); + glCanvas.setSize(getWidth() - getInsets().left - getInsets().right, getHeight() - getInsets().top - getInsets().bottom); + + // enables animated transition + animator = new FPSAnimator(glCanvas, FPS, true); + animator.start(); + listener = new GeneralGLEventListener(this); + + this.validate(); + } + + /** + * Changing the size of glCanvas + * + * @param d New size of glCanvas + */ + public void resizeCanvas(Dimension d) { + jPanel1.setSize(d); + glCanvas.setSize(d); + this.validate(); + this.repaint(); + loadModelButton.setLocation(this.getWidth() / 2 - 35, this.getHeight() / 2 - 40); + } + + /** + * + * @return Original model that is loaded from dile + */ + public MeshModel getLoadedModel() { + return loadedModel; + } + + /** + * Sets GLListener of the canvas + * + * @param listener GLListener for manipulation with model + */ + public void setListener(GeneralGLEventListener listener) { + this.listener = listener; + } + + + /** + * + * @param drawWire Decides if model is displayed as wife-frame + */ + public void setDrawWired(boolean drawWire) { + drawWireModel = drawWire; + } + /** + * + * @return Returns if model is displayed as wife-frame + */ + public boolean getDrawWired(){ + return drawWireModel; + } + + /** + * + * @param v Decides if button for loading model is visible + */ + public void setImportLabelVisible(Boolean v) { + loadModelButton.setVisible(v); + } + + /** + * Loads model selected in file chooser by user + */ + public void loadModel () { + String[] extensions = new String[2]; + extensions[0] = "obj"; + extensions[1] = "OBJ"; + + //enables to shows just .obj files in file chooser + ModelFileFilter filter = new ModelFileFilter(extensions, "*.obj"); + JFileChooser jFileChooser1 = new JFileChooser(); + jFileChooser1.setPreferredSize(new Dimension (800,500)); + + jFileChooser1.addChoosableFileFilter(filter); + + //file chooser will appear on top of glCanvas + jFileChooser1.showOpenDialog(this); + jFileChooser1.setDialogTitle("Import obj file"); + + File[] fileArray = new File[1]; + //saves selected file by user as first element in array + fileArray[0] = jFileChooser1.getSelectedFile(); + + if (fileArray.length <= 0) { + System.out.print("No file chosen."); + } else { + this.addModel(fileArray[0]); + } + glCanvas.setVisible(true); + } + + /** + * Loads the model in .obj format from file and adds this model to listener for displaying. + * If file does not contain 3D model or model is not correct, shows dialog with message + * + * @param file File from which model will be read + */ + private void addModel (final File file) { + try { + //static class MeshObjLaoder reads .obj file into model + MeshModel model = MeshObjLoader.read(new File (file.getPath())); + loadedModel = MeshObjLoader.read(new File (file.getPath())); + if (model != null) { + // listener enables to manipulate and interact with model + listener.setCameraPosition(0, 0, 300); + glCanvas.addGLEventListener((GLEventListener) listener); + listener.setModel(model); + listener.rotationAndSizeRestart(); + loadModelButton.setVisible(false); + loaded = true; + } + } catch (Exception e) { + System.out.println(e.getMessage()); + JOptionPane.showMessageDialog(this, "File doesn't contain any model", "Model is not loaded.", + 0, new ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/notLoadedModel.png"))); + System.out.println ("File doesn't contain any model"); + loaded = false; + } + } + + /** + * reset position of the displayed model + */ + public void resetPosition(){ + listener.rotationAndSizeRestart(); + } + + /** + * Changes the model to be displayed + * + * @param model New model that will be displayed on canvas + */ + public void changeModel(MeshModel model) { + MeshModel newModel = new MeshModel(model); + listener.setModel(newModel); + } + + /** + * Returns the model which is displayed on canvas + * + * @return Model that is displayed on canvas + */ + public MeshModel getModel() { + return listener.getModel(); + } + + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + * + * Generated code from NetBeans + */ + @SuppressWarnings("unchecked") + // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents + private void initComponents() { + + jLayeredPane1 = new javax.swing.JLayeredPane(); + resetButton = new javax.swing.JLabel(); + upNavigationButton = new javax.swing.JButton(); + leftNavigationButton = new javax.swing.JButton(); + minusNavigationButton = new javax.swing.JButton(); + downNavigationButton = new javax.swing.JButton(); + plusNavigationButton = new javax.swing.JButton(); + jLabel1 = new javax.swing.JLabel(); + loadModelButton = new javax.swing.JLabel(); + rightNavigationButton1 = new javax.swing.JButton(); + whiteBackroundButton = new javax.swing.JLabel(); + blackBackroundButton = new javax.swing.JLabel(); + jPanel1 = new javax.swing.JPanel(); + + setBackground(new java.awt.Color(0, 0, 0)); + setLayout(new java.awt.BorderLayout()); + + jLayeredPane1.setBackground(new java.awt.Color(40, 40, 40)); + jLayeredPane1.setToolTipText(""); + jLayeredPane1.setOpaque(true); + jLayeredPane1.addComponentListener(new java.awt.event.ComponentAdapter() { + public void componentResized(java.awt.event.ComponentEvent evt) { + jLayeredPane1ComponentResized(evt); + } + public void componentShown(java.awt.event.ComponentEvent evt) { + jLayeredPane1ComponentShown(evt); + } + }); + + resetButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/resetButton.png"))); // NOI18N + resetButton.setToolTipText("Reset position of model"); + resetButton.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); + resetButton.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() { + public void mouseMoved(java.awt.event.MouseEvent evt) { + resetButtonMouseMoved(evt); + } + }); + resetButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + resetButtonMouseClicked(evt); + } + public void mouseExited(java.awt.event.MouseEvent evt) { + resetButtonMouseExited(evt); + } + }); + jLayeredPane1.add(resetButton); + resetButton.setBounds(60, 40, 30, 30); + + upNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/upButton.png"))); // NOI18N + upNavigationButton.setToolTipText("Rotate up"); + upNavigationButton.setBorderPainted(false); + upNavigationButton.setContentAreaFilled(false); + upNavigationButton.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); + upNavigationButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + upNavigationButtonMousePressed(evt); + } + public void mouseReleased(java.awt.event.MouseEvent evt) { + upNavigationButtonMouseReleased(evt); + } + }); + jLayeredPane1.setLayer(upNavigationButton, javax.swing.JLayeredPane.MODAL_LAYER); + jLayeredPane1.add(upNavigationButton); + upNavigationButton.setBounds(60, 10, 30, 30); + + leftNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/leftButton.png"))); // NOI18N + leftNavigationButton.setToolTipText("Rotate left"); + leftNavigationButton.setBorderPainted(false); + leftNavigationButton.setContentAreaFilled(false); + leftNavigationButton.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); + leftNavigationButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + leftNavigationButtonMousePressed(evt); + } + public void mouseReleased(java.awt.event.MouseEvent evt) { + leftNavigationButtonMouseReleased(evt); + } + }); + jLayeredPane1.setLayer(leftNavigationButton, javax.swing.JLayeredPane.MODAL_LAYER); + jLayeredPane1.add(leftNavigationButton); + leftNavigationButton.setBounds(30, 40, 30, 30); + + minusNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/minus.png"))); // NOI18N + minusNavigationButton.setToolTipText("Zoom out"); + minusNavigationButton.setBorderPainted(false); + minusNavigationButton.setContentAreaFilled(false); + minusNavigationButton.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); + minusNavigationButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + minusNavigationButtonMousePressed(evt); + } + public void mouseReleased(java.awt.event.MouseEvent evt) { + minusNavigationButtonMouseReleased(evt); + } + }); + jLayeredPane1.setLayer(minusNavigationButton, javax.swing.JLayeredPane.MODAL_LAYER); + jLayeredPane1.add(minusNavigationButton); + minusNavigationButton.setBounds(90, 90, 30, 30); + + downNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/downButton.png"))); // NOI18N + downNavigationButton.setToolTipText("Rotate down"); + downNavigationButton.setBorderPainted(false); + downNavigationButton.setContentAreaFilled(false); + downNavigationButton.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); + downNavigationButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + downNavigationButtonMousePressed(evt); + } + public void mouseReleased(java.awt.event.MouseEvent evt) { + downNavigationButtonMouseReleased(evt); + } + }); + jLayeredPane1.setLayer(downNavigationButton, javax.swing.JLayeredPane.MODAL_LAYER); + jLayeredPane1.add(downNavigationButton); + downNavigationButton.setBounds(60, 70, 30, 30); + + plusNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/plus.png"))); // NOI18N + plusNavigationButton.setToolTipText("Zoom in"); + plusNavigationButton.setBorderPainted(false); + plusNavigationButton.setContentAreaFilled(false); + plusNavigationButton.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); + plusNavigationButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + plusNavigationButtonMousePressed(evt); + } + public void mouseReleased(java.awt.event.MouseEvent evt) { + plusNavigationButtonMouseReleased(evt); + } + }); + jLayeredPane1.setLayer(plusNavigationButton, javax.swing.JLayeredPane.MODAL_LAYER); + jLayeredPane1.add(plusNavigationButton); + plusNavigationButton.setBounds(30, 90, 30, 30); + + jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/navigBackground.png"))); // NOI18N + jLayeredPane1.add(jLabel1); + jLabel1.setBounds(30, 10, 90, 90); + + loadModelButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/loadCanva.png"))); // NOI18N + loadModelButton.setToolTipText(""); + loadModelButton.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); + loadModelButton.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() { + public void mouseMoved(java.awt.event.MouseEvent evt) { + loadModelButtonMouseMoved(evt); + } + }); + loadModelButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + loadModelButtonMouseClicked(evt); + } + public void mouseExited(java.awt.event.MouseEvent evt) { + loadModelButtonMouseExited(evt); + } + }); + jLayeredPane1.add(loadModelButton); + loadModelButton.setBounds(200, 100, 210, 220); + + rightNavigationButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/rightButton.png"))); // NOI18N + rightNavigationButton1.setToolTipText("Rotate right"); + rightNavigationButton1.setBorderPainted(false); + rightNavigationButton1.setContentAreaFilled(false); + rightNavigationButton1.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); + rightNavigationButton1.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + rightNavigationButton1MousePressed(evt); + } + public void mouseReleased(java.awt.event.MouseEvent evt) { + rightNavigationButton1MouseReleased(evt); + } + }); + jLayeredPane1.setLayer(rightNavigationButton1, javax.swing.JLayeredPane.MODAL_LAYER); + jLayeredPane1.add(rightNavigationButton1); + rightNavigationButton1.setBounds(90, 40, 30, 30); + + whiteBackroundButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/whiteBackroundCanvas.png"))); // NOI18N + whiteBackroundButton.setToolTipText("White backround"); + whiteBackroundButton.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); + whiteBackroundButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + whiteBackroundButtonMouseClicked(evt); + } + }); + jLayeredPane1.add(whiteBackroundButton); + whiteBackroundButton.setBounds(50, 130, 56, 56); + + blackBackroundButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/blackBackroundCanvas.png"))); // NOI18N + blackBackroundButton.setToolTipText("Dark background"); + blackBackroundButton.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); + blackBackroundButton.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + blackBackroundButtonMouseClicked(evt); + } + }); + jLayeredPane1.add(blackBackroundButton); + blackBackroundButton.setBounds(50, 190, 56, 56); + + jPanel1.setBackground(new java.awt.Color(0, 0, 0)); + jPanel1.addMouseWheelListener(new java.awt.event.MouseWheelListener() { + public void mouseWheelMoved(java.awt.event.MouseWheelEvent evt) { + jPanel1MouseWheelMoved(evt); + } + }); + jPanel1.setLayout(new java.awt.BorderLayout()); + jLayeredPane1.add(jPanel1); + jPanel1.setBounds(0, 0, 0, 0); + + add(jLayeredPane1, java.awt.BorderLayout.CENTER); + }// </editor-fold>//GEN-END:initComponents + + /** + * + * @param evt Resizing glCanvas cantaining components + */ + private void jLayeredPane1ComponentResized(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_jLayeredPane1ComponentResized + jPanel1.setBounds(0, 0, jLayeredPane1.getWidth(), jLayeredPane1.getHeight()); + glCanvas.setBounds(jLayeredPane1.getX(), jLayeredPane1.getY(), jLayeredPane1.getWidth(), jLayeredPane1.getHeight()); + loadModelButton.setLocation(this.getWidth() / 2 - 35, this.getHeight() / 2 - 40); + }//GEN-LAST:event_jLayeredPane1ComponentResized + + /** + * + * @param evt Showing glCanvas cantaining components + */ + private void jLayeredPane1ComponentShown(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_jLayeredPane1ComponentShown + jPanel1.setBounds(0, 0, jLayeredPane1.getWidth(), jLayeredPane1.getHeight()); + glCanvas.setBounds(jLayeredPane1.getX(), jLayeredPane1.getY(), jLayeredPane1.getWidth(), jLayeredPane1.getHeight()); + loadModelButton.setLocation(this.getWidth() / 2 - 35, this.getHeight() / 2 - 40); + }//GEN-LAST:event_jLayeredPane1ComponentShown + + /** + * + * @param evt Enables to rotate left the model when left navigation button is pressed + */ + private void leftNavigationButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftNavigationButtonMousePressed + timer = new Timer(); + startClickTime = System.currentTimeMillis(); + task = new TimerTask() { + @Override + public void run() { + listener.rotateLeft(2); + } + }; + timer.schedule(task, 500, 100); + leftNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/leftButtonPressed.png"))); + }//GEN-LAST:event_leftNavigationButtonMousePressed + + /** + * + * @param evt Enables to rotate up the model when up navigation button is pressed + */ + private void upNavigationButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_upNavigationButtonMousePressed + timer = new Timer(); + startClickTime = System.currentTimeMillis(); + task = new TimerTask() { + @Override + public void run() { + listener.rotateUp(2); + } + }; + timer.schedule(task, 500, 100); + upNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/upButtonPressed.png"))); + }//GEN-LAST:event_upNavigationButtonMousePressed + + /** + * + * @param evt Enables to rotate down the model when down navigation button is pressed + */ + private void downNavigationButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_downNavigationButtonMousePressed + timer = new Timer(); + startClickTime = System.currentTimeMillis(); + task = new TimerTask() { + @Override + public void run() { + listener.rotateDown(2); + } + }; + timer.schedule(task, 500, 100); + downNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/downButtonPressed.png"))); + }//GEN-LAST:event_downNavigationButtonMousePressed + + /** + * + * @param evt Enables to zoom in the model when plus navigation button is pressed + */ + private void plusNavigationButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_plusNavigationButtonMousePressed + timer = new Timer(); + startClickTime = System.currentTimeMillis(); + task = new TimerTask() { + @Override + public void run() { + listener.zoomIn(3); + } + }; + timer.schedule(task, 500, 100); + plusNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/plusPressed.png"))); + }//GEN-LAST:event_plusNavigationButtonMousePressed + + /** + * + * @param evt Enables to zoom out the model when minus navigation button is pressed + */ + private void minusNavigationButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_minusNavigationButtonMousePressed + timer = new Timer(); + startClickTime = System.currentTimeMillis(); + task = new TimerTask() { + @Override + public void run() { + listener.zoomOut(3); + } + }; + timer.schedule(task, 500, 100); + minusNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/minusPressed.png"))); + }//GEN-LAST:event_minusNavigationButtonMousePressed + + /** + * + * @param evt Stops rotating left + */ + private void leftNavigationButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftNavigationButtonMouseReleased + timer.cancel(); + if ((System.currentTimeMillis() - startClickTime) < 500) { + listener.rotateLeft(22.5); + } + startClickTime = 0; + leftNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/leftButton.png"))); + }//GEN-LAST:event_leftNavigationButtonMouseReleased + + /** + * + * @param evt Stops rotating up + */ + private void upNavigationButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_upNavigationButtonMouseReleased + timer.cancel(); + if ((System.currentTimeMillis() - startClickTime) < 500) { + listener.rotateUp(22.5); + } + startClickTime = 0; + upNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/upButton.png"))); + }//GEN-LAST:event_upNavigationButtonMouseReleased + + /** + * + * @param evt Stops rotating down + */ + private void downNavigationButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_downNavigationButtonMouseReleased + timer.cancel(); + if ((System.currentTimeMillis() - startClickTime) < 500) { + listener.rotateDown(22.5); + } + startClickTime = 0; + downNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/downButton.png"))); + }//GEN-LAST:event_downNavigationButtonMouseReleased + + /** + * + * @param evt Stops zooming in + */ + private void plusNavigationButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_plusNavigationButtonMouseReleased + timer.cancel(); + if ((System.currentTimeMillis() - startClickTime) < 500) { + listener.zoomIn(30); + } + startClickTime = 0; + plusNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/plus.png"))); + }//GEN-LAST:event_plusNavigationButtonMouseReleased + + /** + * + * @param evt Stops zooming out + */ + private void minusNavigationButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_minusNavigationButtonMouseReleased + timer.cancel(); + if ((System.currentTimeMillis() - startClickTime) < 500) { + listener.zoomOut(30); + } + startClickTime = 0; + minusNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/minus.png"))); + }//GEN-LAST:event_minusNavigationButtonMouseReleased + + /** + * + * @param evt Laoding the .obj file when button pressed + */ + private void loadModelButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_loadModelButtonMouseClicked + loadModel(); + }//GEN-LAST:event_loadModelButtonMouseClicked + + /** + * + * @param evt Enables to zoom in and out the model by mouse wheeling + */ + private void jPanel1MouseWheelMoved(java.awt.event.MouseWheelEvent evt) {//GEN-FIRST:event_jPanel1MouseWheelMoved + if (evt.getWheelRotation() > 0) { + listener.zoomIn(-5 * evt.getWheelRotation()); + } else { + listener.zoomOut(5 * evt.getWheelRotation()); + } + }//GEN-LAST:event_jPanel1MouseWheelMoved + + /** + * + * @param evt Design is reacting to mouse movement + */ + private void loadModelButtonMouseMoved(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_loadModelButtonMouseMoved + loadModelButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/loadCanvaClicked.png"))); + }//GEN-LAST:event_loadModelButtonMouseMoved + + /** + * + * @param evt Design is reacting to mouse movement + */ + private void loadModelButtonMouseExited(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_loadModelButtonMouseExited + loadModelButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/loadCanva.png"))); + }//GEN-LAST:event_loadModelButtonMouseExited + + /** + * + * @param evt Enables to rotate down the model when down navigation button is pressed + */ + private void rightNavigationButton1MousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightNavigationButton1MousePressed + timer = new Timer(); + startClickTime = System.currentTimeMillis(); + task = new TimerTask() { + @Override + public void run() { + listener.rotateRight(2); + } + }; + timer.schedule(task, 500, 100); + rightNavigationButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/rightButtonPressed.png"))); + }//GEN-LAST:event_rightNavigationButton1MousePressed + + /** + * + * @param evt Stops rotating right + */ + private void rightNavigationButton1MouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightNavigationButton1MouseReleased + timer.cancel(); + if ((System.currentTimeMillis() - startClickTime) < 500) { + listener.rotateRight(22.5); + } + startClickTime = 0; + rightNavigationButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/rightButton.png"))); + }//GEN-LAST:event_rightNavigationButton1MouseReleased + + /** + * + * @param evt Position of model on glCanvas is set to starting position + */ + private void resetButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_resetButtonMouseClicked + listener.rotationAndSizeRestart(); + }//GEN-LAST:event_resetButtonMouseClicked + + /** + * + * @param evt Design is reacting to mouse movement + */ + private void resetButtonMouseMoved(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_resetButtonMouseMoved + resetButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/resetButtonPressed.png"))); + resetButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + }//GEN-LAST:event_resetButtonMouseMoved + + /** + * + * @param evt Design is reacting to mouse movement + */ + private void resetButtonMouseExited(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_resetButtonMouseExited + resetButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/resetButton.png"))); + }//GEN-LAST:event_resetButtonMouseExited + + /** + * + * @param evt Changes backround of the canvas into white color + */ + private void whiteBackroundButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_whiteBackroundButtonMouseClicked + listener.setWhiteBackround(true); + whiteBackroundButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/whiteBackroundCanvasPressed.png"))); + blackBackroundButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/blackBackroundCanvas.png"))); + }//GEN-LAST:event_whiteBackroundButtonMouseClicked + + /** + * + * @param evt Changes backround of the canvas into dark color + */ + private void blackBackroundButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_blackBackroundButtonMouseClicked + listener.setWhiteBackround(false); + whiteBackroundButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/whiteBackroundCanvas.png"))); + blackBackroundButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/cz/fidentis/analyst/gui/resources/blackBackroundCanvasPressed.png"))); + }//GEN-LAST:event_blackBackroundButtonMouseClicked + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel blackBackroundButton; + private javax.swing.JButton downNavigationButton; + private javax.swing.JLabel jLabel1; + private javax.swing.JLayeredPane jLayeredPane1; + private javax.swing.JPanel jPanel1; + private javax.swing.JButton leftNavigationButton; + private javax.swing.JLabel loadModelButton; + private javax.swing.JButton minusNavigationButton; + private javax.swing.JButton plusNavigationButton; + private javax.swing.JLabel resetButton; + private javax.swing.JButton rightNavigationButton1; + private javax.swing.JButton upNavigationButton; + private javax.swing.JLabel whiteBackroundButton; + // End of variables declaration//GEN-END:variables +} diff --git a/GUI/src/main/java/cz/fidentis/analyst/gui/GeneralGLEventListener.java b/GUI/src/main/java/cz/fidentis/analyst/gui/GeneralGLEventListener.java new file mode 100644 index 00000000..94acd8f1 --- /dev/null +++ b/GUI/src/main/java/cz/fidentis/analyst/gui/GeneralGLEventListener.java @@ -0,0 +1,502 @@ +package cz.fidentis.analyst.gui; + +import cz.fidentis.analyst.mesh.core.MeshModel; +import cz.fidentis.analyst.mesh.core.MeshFacet; +import com.jogamp.opengl.GL; +import static com.jogamp.opengl.GL.GL_DEPTH_TEST; +import static com.jogamp.opengl.GL.GL_FRONT_AND_BACK; +import static com.jogamp.opengl.GL.GL_VIEWPORT; +import com.jogamp.opengl.GL2; +import static com.jogamp.opengl.GL2GL3.GL_FILL; +import static com.jogamp.opengl.GL2GL3.GL_LINE; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLEventListener; +import static com.jogamp.opengl.fixedfunc.GLMatrixFunc.GL_MODELVIEW_MATRIX; +import static com.jogamp.opengl.fixedfunc.GLMatrixFunc.GL_PROJECTION_MATRIX; +import com.jogamp.opengl.glu.GLU; +import javax.vecmath.Vector3d; +import javax.vecmath.Vector3f; + +/** + * + * @author Natália Bebjaková + */ +public class GeneralGLEventListener implements GLEventListener { + /** + * MeshModel that is displayed + */ + private MeshModel model = new MeshModel(); + /** + * GLCanvas which listener belongs to + */ + protected Canvas glCanvas; + /** + * GLU object. + */ + protected GLU glu; + /** + * Usage of openGL version 2 + */ + protected GL2 gl; + /** + * The last viewport. + */ + protected int[] viewport = new int[4]; + /** + * The last model matrix. + */ + protected float[] modelViewMatrix = new float[16]; + /** + * The last projection matrix. + */ + protected float[] projectionMatrix = new float[16]; + /** + * The X coordinate of the last known mouse position during the scene rotation. + */ + int mouseX = 0; + /** + * The Y coordinate of the last know mouse position during the scene rotation. + */ + int mouseY = 0; + + protected Vector3f defaultPosition = new Vector3f(0, 0, 300); + protected Vector3f currentPosition = new Vector3f(0, 0, 300); + + protected double zCenter = 0; + protected double xCenter = 0; + protected double yCenter = 0; + + protected double zCameraPosition; + protected double xCameraPosition; + protected double yCameraPosition; + + protected double zUpPosition = 0; + protected double xUpPosition = 0; + protected double yUpPosition = 1; + + /** + * Decides if model is diplayed as wire-frame + */ + protected boolean wireModel = false; + /** + * Decides if the backround will be white + */ + protected boolean whiteBackround = false; + + /** + * + * @return is backround white or not + */ + public boolean isWhiteBackround() { + return whiteBackround; + } + + /** + * + * @return Matrix for model view + */ + public float[] getModelViewMatrix() { + return modelViewMatrix; + } + + /** + * + * @return Matrix for projection + */ + public float[] getProjectionMatrix() { + return projectionMatrix; + } + + /** + * + * @return GlCanvas for displaying + */ + public Canvas getGlCanvas() { + return glCanvas; + } + + /** + * + * @param drawWire Decides if model is displayed as wire-frame + */ + public void setWireMode(boolean drawWire) { + wireModel = drawWire; + } + + /** + * + * @param whiteBackround Is backround white or not + */ + public void setWhiteBackround(boolean whiteBackround) { + this.whiteBackround = whiteBackround; + } + + /** + * Creates new EventListener + * @param canvas GLCanvas which listener belongs to + */ + public GeneralGLEventListener(Canvas canvas) { + this.glCanvas = canvas; + } + + /** + * + * @param model Set model to be displayed + */ + public void setModel(MeshModel model) { + this.model = model; + } + + /** + * + * @return Returns displayed model + */ + public MeshModel getModel() { + return model; + } + + + /** + * Invoked when main frame is created + * @param glad Glad object + */ + @Override + public void init(GLAutoDrawable glad) { + + this.gl = (GL2) glad.getGL(); + glu = new GLU(); + + gl.setSwapInterval(1); + gl.glEnable(GL2.GL_LIGHTING); + gl.glEnable(GL2.GL_LIGHT0); + gl.glEnable(GL2.GL_DEPTH_TEST); + gl.glClearColor(0,0,0,0); // background for GLCanvas + gl.glClear(GL2.GL_COLOR_BUFFER_BIT); + + gl.glShadeModel(GL2.GL_SMOOTH); // use smooth shading + + gl.glDepthFunc(GL2.GL_LESS); + gl.glDepthRange(0.0, 1.0); + gl.glEnable(GL_DEPTH_TEST); + + gl.glEnable(GL2.GL_NORMALIZE); + gl.glDisable(GL2.GL_CULL_FACE); + } + + /** + * Invoked when main frame is closed + * @param glad Glad object + */ + @Override + public void dispose(GLAutoDrawable glad) { + } + + /** + * Invoked every frame. + * @param glad Glad object + */ + @Override + public void display(GLAutoDrawable glad) { + wireModel = glCanvas.getDrawWired(); // is wire-frame or not + if (whiteBackround) { + gl.glClearColor(0.9f,0.9f,0.9f,0); + } else { + gl.glClearColor(0.25f,0.25f,0.25f,0); + } + // background for GLCanvas + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + gl.glLoadIdentity(); + + // sets model to proper position + glu.gluLookAt(xCameraPosition, yCameraPosition, zCameraPosition, xCenter, yCenter, zCenter, xUpPosition, yUpPosition, zUpPosition); + + gl.glShadeModel(GL2.GL_SMOOTH); + gl.glGetIntegerv(GL_VIEWPORT, viewport, 0); + gl.glGetFloatv(GL_MODELVIEW_MATRIX, modelViewMatrix, 0); + gl.glGetFloatv(GL_PROJECTION_MATRIX, projectionMatrix, 0); + + //if there is any model, draw + if (model != null) { + if (wireModel) { + gl.glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); //drawn as wire-frame + drawWithoutTextures(model); + } else { + gl.glPolygonMode( GL_FRONT_AND_BACK, GL_FILL); // drawn as full traingles + drawWithoutTextures(model); + } + } + + //gl.glPopMatrix(); + gl.glFlush(); + } + + /** + * Loops through the facets and render each of them + * + * @param model model of the face + */ + public void drawWithoutTextures(MeshModel model) { + for (int i = 0; i < model.getFacets().size(); i++) { + renderFacet(model.getFacets().get(i)); + } + } + + /** + * Loops through the facet and render all the vertices as they are stored in corner table + * + * @param facet facet of model + */ + public void renderFacet(MeshFacet facet) { + gl.glBegin(GL2.GL_TRIANGLES); //vertices are rendered as triangles + + // get the normal and tex coords indicies for face i + for (int v = 0; v < facet.getCornerTable().getSize(); v++) { + // render the normals + Vector3d norm = facet.getVertices().get(facet.getCornerTable().getRow(v).getVertexIndex()).getNormal(); + if(norm != null) { + gl.glNormal3d(norm.x, norm.y, norm.z); + } + // render the vertices + Vector3d vert = facet.getVertices().get(facet.getCornerTable().getRow(v).getVertexIndex()).getPosition(); + gl.glVertex3d(vert.x, vert.y, vert.z); + } + gl.glEnd(); + + } + + /** + * + * @param glad Glad object + * @param x x + * @param y y + * @param width New width + * @param height New height + */ + @Override + public void reshape(GLAutoDrawable glad, int x, int y, int width, int height) { + + if (height == 0) { + height = 1; // to avoid division by 0 in aspect ratio below + } + gl.glViewport(x, y, width, height); // size of drawing area + + float h = (float) height / (float) width; + + gl.glMatrixMode(GL2.GL_PROJECTION); + gl.glLoadIdentity(); + + glu.gluPerspective(65, width / (float) height, 5.0f, 1500.0f); + gl.glMatrixMode(GL2.GL_MODELVIEW); + gl.glLoadIdentity(); + + gl.glTranslatef(0.0f, 0.0f, -40.0f); + } + + /** + * + * @param x New x position + * @param y New y position + * @param z New z position + */ + public void setCameraPosition(float x, float y, float z) { + currentPosition.set(x, y, z); + + setNewCameraPosition(currentPosition); + zCameraPosition = defaultPosition.z; + xCameraPosition = defaultPosition.x; + yCameraPosition = defaultPosition.y; + } + + /** + * + * @param position New position of camera + */ + public void setNewCameraPosition(Vector3f position) { + xCameraPosition = position.x; + yCameraPosition = position.y; + zCameraPosition = position.z; + } + + /** + * + * @param degree degree of rotation + */ + public void rotateUp(double degree) { + rotate(-degree, 0); + } + + /** + * + * @param degree degree of rotation + */ + public void rotateDown(double degree) { + rotate(degree, 0); + } + + /** + * + * @param degree degree of rotation + */ + public void rotateLeft(double degree) { + rotate(0, degree); + } + + /** + * + * @param degree degree of rotation + */ + public void rotateRight(double degree) { + rotate(0, -degree); + } + + /** + * + * @return X axis + */ + private Vector3f getXaxis() { + Vector3f xAxis = new Vector3f( + (float) ((yCameraPosition - yCenter) *zUpPosition - (zCameraPosition - zCenter) * yUpPosition), + (float) ((zCameraPosition - zCenter) * xUpPosition - (xCameraPosition - xCenter) * zUpPosition), + (float) ((xCameraPosition - xCenter) * yUpPosition - xUpPosition * (yCameraPosition - yCenter))); + + float length = (float) Math.sqrt(xAxis.x * xAxis.x + + xAxis.y * xAxis.y + xAxis.z * xAxis.z); + xAxis.set(xAxis.x / length, xAxis.y / length, xAxis.z / length); + return xAxis; + } + + /** + * + * @return Y axis + */ + private Vector3f getYaxis() { + Vector3f yAxis = new Vector3f((float) xUpPosition, (float) yUpPosition, (float) zUpPosition); + float length = (float) Math.sqrt(yAxis.x * yAxis.x + + yAxis.y * yAxis.y + yAxis.z * yAxis.z); + yAxis.set((yAxis.x / length), (yAxis.y / length), (yAxis.z / length)); + return yAxis; + } + + /** + * Rotates object around axes that apear as horizontal and vertical axe on + * screen (paralel to the sceen edges), intersecting at the center of + * screen( i.e head center). + * + * @param xAngle angle around vertical axe on screen + * @param yAngle angle around horizontal axe on screen + */ + public void rotate(double xAngle, double yAngle) { + Vector3f xAxis = getXaxis(); + Vector3f yAxis = getYaxis(); + + Vector3f point = new Vector3f((float) xCameraPosition, + (float) yCameraPosition, (float) zCameraPosition); + + Vector3f camera = rotateAroundAxe(point, xAxis, Math.toRadians(xAngle)); + camera = rotateAroundAxe(camera, yAxis, Math.toRadians(yAngle)); + + point = new Vector3f((float) xUpPosition, (float) yUpPosition, (float) zUpPosition); + + Vector3f up = rotateAroundAxe(point, xAxis, Math.toRadians(xAngle)); + up = rotateAroundAxe(up, yAxis, Math.toRadians(yAngle)); + + xUpPosition = up.x; + yUpPosition = up.y; + zUpPosition = up.z; + + setNewCameraPosition(camera); + } + + /** + * + * @param xShift xShift + * @param yShift yShift + */ + public void move(double xShift, double yShift) { + Vector3f xAxis = getXaxis(); + Vector3f yAxis = getYaxis(); + + Vector3f shift = new Vector3f((float) (xAxis.x * xShift + yAxis.x * yShift), + (float) (xAxis.y * xShift + yAxis.y * yShift), (float) (xAxis.z * xShift + yAxis.z * yShift)); + Vector3f camera = new Vector3f((float) xCameraPosition + shift.x, (float) yCameraPosition + shift.y, + (float) zCameraPosition + shift.z); + xCenter += shift.x; + yCenter += shift.y; + zCenter += shift.z; + + setNewCameraPosition(camera); + } + + /** + * Calculate the new position f point from given angle and rotation axe. + * + * @param point original position + * @param u vector of rotation axe + * @param angle angle of rotation + * @return new position + */ + public Vector3f rotateAroundAxe(Vector3f point, Vector3f u, double angle) { + Vector3f p; + float x = (float) ((Math.cos(angle) + u.x * u.x * (1 - Math.cos(angle))) * point.x + + (u.x * u.y * (1 - Math.cos(angle)) - u.z * Math.sin(angle)) * point.y + + (u.x * u.z * (1 - Math.cos(angle)) + u.y * Math.sin(angle)) * point.z); + float y = (float) ((u.x * u.y * (1 - Math.cos(angle)) + u.z * Math.sin(angle)) * point.x + + (Math.cos(angle) + u.y * u.y * (1 - Math.cos(angle))) * point.y + + (u.y * u.z * (1 - Math.cos(angle)) - u.x * Math.sin(angle)) * point.z); + float z = (float) ((u.x * u.z * (1 - Math.cos(angle)) - u.y * Math.sin(angle)) * point.x + + (u.y * u.z * (1 - Math.cos(angle)) + u.x * Math.sin(angle)) * point.y + + (Math.cos(angle) + u.z * u.z * (1 - Math.cos(angle))) * point.z); + p = new Vector3f(x, y, z); + + return p; + } + + /** + * Sets model to the starting position + */ + public void rotationAndSizeRestart() { + xUpPosition = 0; + yUpPosition = 1; + zUpPosition = 0; + + setNewCameraPosition(defaultPosition); + xCenter = 0; + yCenter = 0; + zCenter = 0; + } + + /** + * + * @param distance Distance to be zoom in + */ + public void zoomIn(double distance) { + double x = xCameraPosition - xCenter; + double y = yCameraPosition - yCenter; + double z = zCameraPosition - zCenter; + double sqrt = Math.sqrt(x * x + y * y + z * z); + + if (sqrt > 0) { + xCameraPosition = xCenter + ((sqrt - distance) * x / sqrt); + yCameraPosition = yCenter + ((sqrt - distance) * y / sqrt); + zCameraPosition = zCenter + ((sqrt - distance) * z / sqrt); + } + } + + /** + * + * @param distance Distance to be zoom out + */ + public void zoomOut(double distance) { + double x = xCameraPosition - xCenter; + double y = yCameraPosition - yCenter; + double z = zCameraPosition - zCenter; + double sqrt = Math.sqrt(x * x + y * y + z * z); + + if (sqrt == 0) { + sqrt = 1; + } + xCameraPosition = xCenter + ((sqrt + distance) * x / sqrt); + yCameraPosition = yCenter + ((sqrt + distance) * y / sqrt); + zCameraPosition = zCenter + ((sqrt + distance) * z / sqrt); + } +} -- GitLab