Jogl 과 Swing
O'Relly에서 최근에 출판된 "Swing Hacks"이란 책의 공동 저자인Chris Adamson은 Jogl 에 대한 기사와 튜토리알을 많이 써 오고 있다. 그중에서도 가장 오래전에 쓴(09/11/2003) 튜토리알인"Jogl 에 뛰어들기(Jumping into JOGL)"는 사람들이 가장 많이 읽었고 또 JOGL에 입문하는 사람들에 큰 영향을 끼친 기사라 할 수 있다.
그 튜토리알안에는 AWT 의 GLCanvas 에 대응하는 GLJPanel 이 있지만 하드웨어적 가속화 렌더링을 당시는 지원하지 않기 때문에 JOGL에 GLJPanel 이 정의되어 있지만 사용하지 않기로 한다는 글귀가 있다. (It might seem odd that the sample uses AWT instead of the more-popular Swing API. While theGLCanvas
has a Swing equivalent,GLJPanel
, the Swing version does not currently enjoy hardware-accelerated rendering. That means it's slow, which for many would defeat the whole purpose of using JOGL.)
사실 이제 까지 이 강좌에서 Swing을 기피하여 온 이유도 이러한 경고가 한 몫 했다해도 과언이 아니다. 그러나 최근의 Jogl에서는 사정이 많이 달라졌다. 2005년 2월 7일자 버전서 부터는 하드웨어적 가속화 렌더링을 지원한다고JOGL Release Information에서 공표한였다. (JOGL's Swing component, GLJPanel, now supports hardware acceleration via pbuffers on all of JOGL's supported platforms. Performance is quite good, at least on NVidia hardware; more performance work is planned on this component's implementation. )
여러분이 이 강좌 머리부분에서 필자가 기술한 Jogl 사이트에서 최신 Jogl 버전을 다운 받았다면 GLJPanel을 사용해도 하드웨어적 가속화 렌더링의 효과를 누릴 수 있다. 그러나 거기에는 약간의 오버헤드를 지불해야 한다. 여러분이 Jogl을 내려 받은사이트에는 javadoc_public.zip 라는 Jogl 의 참고문헌이 있는데 이를 내려 받아 GLJPanel 을 열어 보기 바란다. 거기에는
"이 컴포넌트는 pbuffer를 통해서 하드웨어적 가속화 렌더링을 시도하지만 문제가 생기면 소프트웨어적 렌더링모드로 전환하다 (This component attempts to use hardware-accelerated rendering via pbuffers and falls back on to software rendering if problems occur.)고 적혀 있다.
또한 직접 렌더링하는 것이 아니고 pbuffer를 통해서 렌더링하는 것도 약간 시간이 더 걸릴지도 모른다고 경고 하고 있다.
이런 저런 이유로 Swing을 꼭 써야할 이유가 없을 때에는 AWT를 쓸 것을 권장하고 있다. 그럼에도 Swing 이외에는 선택이 없는 경우를 위해서 아래에 Swing 을 섞어 쓰는 풀그림을 작성하여 사용해 보기로 한다. 아래의 보기에서는 JFrame에 GLCanvas를 부착하는 방법을 썼으므로 실질적으로 위에 논의한 Swing 의 하드웨어적 가속화 렌더링 의 제약과는 무관하고 100% 하드웨어적 가속화 렌더링을 지원할 것으로 예상된다.
- package joglJFrame;
- import java.awt.*;
- import java.awt.event.*;
- import javax.swing.*;
- import net.java.games.jogl.*;
- @SuppressWarnings("serial")
- public class JoglJFrame
- extends JFrame implements ActionListener
- {
- //Notice we've given these two objects a larger scope.
- //Local scope to the constructor was no longer sufficient.
- JoglRender listener = new JoglRender();
- GLCanvas canvas;
- public static void main(String[] args) {
- final JoglJFrame app = new JoglJFrame();
- SwingUtilities.invokeLater (new Runnable() {public void run() {app.setVisible(true);}});
- }
- public JoglJFrame() {
- super("Sine, Cosine and Tangent");
- setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- JPanel jp = new JPanel();
- ButtonGroup bg = new ButtonGroup();
- JRadioButton jrb1 = new JRadioButton("Sine", true);
- jrb1.setActionCommand("sine");
- jrb1.addActionListener(this);
- JRadioButton jrb2 = new JRadioButton("Cosine");
- jrb2.setActionCommand("cosine");
- jrb2.addActionListener(this);
- JRadioButton jrb3 = new JRadioButton("Tangent");
- jrb3.setActionCommand("tangent");
- jrb3.addActionListener(this);
- bg.add( jrb1 );
- bg.add( jrb2 );
- bg.add( jrb3 );
- jp.add( jrb1 );
- jp.add( jrb2 );
- jp.add( jrb3 );
- add("South", jp);
- GLCapabilities glcaps = new GLCapabilities();
- canvas = GLDrawableFactory.getFactory().createGLCanvas(glcaps);
- canvas.addGLEventListener(listener);
- add(canvas, BorderLayout.CENTER);
- setSize(500, 300);
- centerWindow(this);
- }
- public void centerWindow(Component frame) {
- Dimension screenSize =
- Toolkit.getDefaultToolkit().getScreenSize();
- Dimension frameSize = frame.getSize();
- if (frameSize.width > screenSize.width )
- frameSize.width = screenSize.width;
- if (frameSize.height > screenSize.height)
- frameSize.height = screenSize.height;
- frame.setLocation (
- (screenSize.width - frameSize.width ) >> 1,
- (screenSize.height - frameSize.height) >> 1
- );
- }
- public void actionPerformed(ActionEvent ae) {
- listener.whatToDraw = ae.getActionCommand();
- canvas.repaint();
- }
- }
|
<JoglRender>
- package joglJFrame;
- import net.java.games.jogl.*;
- public class JoglRender implements GLEventListener {
- public String whatToDraw = "sine";
- public void init(GLDrawable gld) {
- GL gl = gld.getGL();
- GLU glu = gld.getGLU();
- gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- gl.glLineWidth(2.0f);
- gl.glPointSize(2.0f);
- gl.glViewport(-250, -150, 250, 150);
- gl.glMatrixMode(GL.GL_PROJECTION);
- gl.glLoadIdentity();
- glu.gluOrtho2D(-250.0, 250.0, -150.0, 150.0);
- }
- public void display(GLDrawable gld) {
- GL gl = gld.getGL();
- drawGraph( gl );
- gl.glColor3f(1.0f, 0.2f,0.2f);
- gl.glBegin(GL.GL_POINTS);
- if (whatToDraw.equals("sine")) {
- //draw enlarged sine function
- for (int x=-250; x<250;x++)
- gl.glVertex2d(x, (Math.sin(x/60.0)*100.0));
- } else if (whatToDraw.equals("cosine")) {
- //draw enlarged cosine function
- for (int x=-250; x<250;x++)
- gl.glVertex2d(x, (Math.cos(x/60.0)*100.0));
- } else if (whatToDraw.equals("tangent")) {
- //draw enlarged tangent function
- for (int x=-250; x<250;x++)
- gl.glVertex2d(x, (Math.tan(x/60.0)*30.0));
- }
- gl.glEnd();
- }
- public void reshape(
- GLDrawable drawable,
- int x,
- int y,
- int width,
- int height
- ) {}
- public void displayChanged(
- GLDrawable drawable,
- boolean modeChanged,
- boolean deviceChanged
- ) {}
- private void drawGraph(GL gl) {
- float red;
- float green;
- float blue;
- gl.glClear(GL.GL_COLOR_BUFFER_BIT);
- //drawing the grid
- red = 0.2f;
- green = 0.2f;
- blue = 0.2f;
- gl.glColor3f(red, green, blue);
- gl.glBegin(GL.GL_LINES);
- //draw the vertical lines
- for (int x=-250; x<=250; x+=10) {
- gl.glVertex2d(x, -150);
- gl.glVertex2d(x, 150);
- }
- //draw the horizontal lines
- for (int y=-150; y<=150; y+=10) {
- gl.glVertex2d(-250, y);
- gl.glVertex2d(250, y);
- }
- gl.glEnd();
- // draw the x-axis and y-axis
- gl.glColor3f(0, 0.5f, 0.5f);
- gl.glBegin(GL.GL_LINES);
- //line for y-axis
- gl.glVertex2d(0, 140);
- gl.glVertex2d(0, -140);
- //line for x-axis
- gl.glVertex2d(240, 0);
- gl.glVertex2d(-240, 0);
- gl.glEnd();
- // draw arrow heads
- gl.glBegin(GL.GL_TRIANGLES);
- gl.glVertex2d( 0, 150);
- gl.glVertex2d(-5, 140);
- gl.glVertex2d( 5, 140);
- gl.glVertex2d( 0, -150);
- gl.glVertex2d(-5, -140);
- gl.glVertex2d( 5, -140);
- gl.glVertex2d(250, 0);
- gl.glVertex2d(240,-5);
- gl.glVertex2d(240, 5);
- gl.glVertex2d(-250, 0);
- gl.glVertex2d(-240,-5);
- gl.glVertex2d(-240, 5);
- gl.glEnd();
- }
- }
|
이 파일들을 컴파일하여 실행 시켜 보기 바란다. 이 코드의 설명은 다음 강좌에서 할 것이다.