#!/usr/bin/env qore # This is basically a direct port of a QT example program to Qore # using Qore's "qt-opengl" module. # Note that Qore's "qt-opengl" module requires QT 4.3 or above with OpenGL support # use the "qt-opengl" module (automatically loads the "qt-gui" and "opengl" modules) %requires qt-opengl # this is an object-oriented program, the application class is "grabber" %exec-class grabber # require all variables to be explicitly declared %require-our # enable all parse warnings %enable-all-warnings const lightPos = ( 5.0, 5.0, 10.0, 1.0 ); const reflectance1 = ( 0.8, 0.1, 0.0, 1.0 ); const reflectance2 = ( 0.0, 0.8, 0.2, 1.0 ); const reflectance3 = ( 0.2, 0.2, 1.0, 1.0 ); class GLWidget inherits QGLWidget { private $.gear1, $.gear2, $.gear3, $.xRot, $.yRot, $.zRot, $.gear1Rot, $.lastPos; constructor($parent) : QGLWidget($parent) { $.lastPos = new QPoint(); # create signals $.createSignal("xRotationChanged(int)"); $.createSignal("yRotationChanged(int)"); $.createSignal("zRotationChanged(int)"); $.gear1 = 0; $.gear2 = 0; $.gear3 = 0; $.xRot = 0; $.yRot = 0; $.zRot = 0; $.gear1Rot = 0; my $timer = new QTimer($self); $.connect($timer, SIGNAL("timeout()"), SLOT("advanceGears()")); $timer.start(20); } destructor() { $.makeCurrent(); glDeleteLists($.gear1, 1); glDeleteLists($.gear2, 1); glDeleteLists($.gear3, 1); } xRotation() { return $.xRot; } yRotation() { return $.yRot; } zRotation() { return $.zRot; } setXRotation($angle) { $.normalizeAngle(\$angle); if ($angle != $.xRot) { $.xRot = $angle; $.emit("xRotationChanged(int)", $angle); $.updateGL(); } } setYRotation($angle) { $.normalizeAngle(\$angle); if ($angle != $.yRot) { $.yRot = $angle; $.emit("yRotationChanged(int)", $angle); $.updateGL(); } } setZRotation($angle) { $.normalizeAngle(\$angle); if ($angle != $.zRot) { $.zRot = $angle; $.emit("zRotationChanged(int)", $angle); $.updateGL(); } } initializeGL() { glLightfv(GL_LIGHT0, GL_POSITION, lightPos); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); $.gear1 = $.makeGear(reflectance1, 1.0, 4.0, 1.0, 0.7, 20); $.gear2 = $.makeGear(reflectance2, 0.5, 2.0, 2.0, 0.7, 10); $.gear3 = $.makeGear(reflectance3, 1.3, 2.0, 0.5, 0.7, 10); glEnable(GL_NORMALIZE); glClearColor(0.0, 0.0, 0.0, 1.0); } paintGL() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glRotated($.xRot / 16.0, 1.0, 0.0, 0.0); glRotated($.yRot / 16.0, 0.0, 1.0, 0.0); glRotated($.zRot / 16.0, 0.0, 0.0, 1.0); $.drawGear($.gear1, -3.0, -2.0, 0.0, $.gear1Rot / 16.0); $.drawGear($.gear2, 3.1, -2.0, 0.0, -2.0 * ($.gear1Rot / 16.0) - 9.0); glRotated(90.0, 1.0, 0.0, 0.0); $.drawGear($.gear3, -3.1, -1.8, -2.2, 2.0 * ($.gear1Rot / 16.0) - 2.0); glPopMatrix(); } resizeGL($width, $height) { my $side = min($width, $height); glViewport(($width - $side) / 2, ($height - $side) / 2, $side, $side); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 60.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslated(0.0, 0.0, -40.0); } mousePressEvent($event) { $.lastPos = $event.pos(); } mouseMoveEvent($event) { my $dx = $event.x() - $.lastPos.x(); my $dy = $event.y () - $.lastPos.y (); if ($event.buttons() & Qt::LeftButton) { $.setXRotation($.xRot + 8 * $dy); $.setYRotation($.yRot + 8 * $dx); } else if ($event.buttons() & Qt::RightButton) { $.setXRotation($.xRot + 8 * $dy); $.setZRotation($.zRot + 8 * $dx); } $.lastPos = $event.pos(); } advanceGears() { $.gear1Rot += 2 * 16; $.updateGL(); } makeGear($reflectance, $innerRadius, $outerRadius, $thickness, $toothSize, $toothCount) { my $list = glGenLists(1); glNewList($list, GL_COMPILE); glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, $reflectance); my $r0 = $innerRadius; my $r1 = $outerRadius - $toothSize / 2.0; my $r2 = $outerRadius + $toothSize / 2.0; my $delta = (2.0 * M_PI / $toothCount) / 4.0; my $z = $thickness / 2.0; my ($i, $j); glShadeModel(GL_FLAT); for ($i = 0; $i < 2; ++$i) { my $sign = ($i == 0) ? 1.0 : -1.0; glNormal3d(0.0, 0.0, $sign); glBegin(GL_QUAD_STRIP); for ($j = 0; $j <= $toothCount; ++$j) { my $angle = 2.0 * M_PI * $j / $toothCount; glVertex3d($r0 * cos($angle), $r0 * sin($angle), $sign * $z); glVertex3d($r1 * cos($angle), $r1 * sin($angle), $sign * $z); glVertex3d($r0 * cos($angle), $r0 * sin($angle), $sign * $z); glVertex3d($r1 * cos($angle + 3 * $delta), $r1 * sin($angle + 3 * $delta), $sign * $z); } glEnd(); glBegin(GL_QUADS); for ($j = 0; $j < $toothCount; ++$j) { my $angle = 2.0 * M_PI * $j / $toothCount; glVertex3d($r1 * cos($angle), $r1 * sin($angle), $sign * $z); glVertex3d($r2 * cos($angle + $delta), $r2 * sin($angle + $delta), $sign * $z); glVertex3d($r2 * cos($angle + 2 * $delta), $r2 * sin($angle + 2 * $delta), $sign * $z); glVertex3d($r1 * cos($angle + 3 * $delta), $r1 * sin($angle + 3 * $delta), $sign * $z); } glEnd(); } glBegin(GL_QUAD_STRIP); for ($i = 0; $i < $toothCount; ++$i) { for ($j = 0; $j < 2; ++$j) { my $angle = 2.0 * M_PI * ($i + ($j / 2.0)) / $toothCount; my $s1 = $r1; my $s2 = $r2; if ($j == 1) qSwap(\$s1, \$s2); glNormal3d(cos($angle), sin($angle), 0.0); glVertex3d($s1 * cos($angle), $s1 * sin($angle), $z); glVertex3d($s1 * cos($angle), $s1 * sin($angle), -$z); glNormal3d($s2 * sin($angle + $delta) - $s1 * sin($angle), $s1 * cos($angle) - $s2 * cos($angle + $delta), 0.0); glVertex3d($s2 * cos($angle + $delta), $s2 * sin($angle + $delta), $z); glVertex3d($s2 * cos($angle + $delta), $s2 * sin($angle + $delta), -$z); } } glVertex3d($r1, 0.0, $z); glVertex3d($r1, 0.0, -$z); glEnd(); glShadeModel(GL_SMOOTH); glBegin(GL_QUAD_STRIP); for ($i = 0; $i <= $toothCount; ++$i) { my $angle = $i * 2.0 * M_PI / $toothCount; glNormal3d(-cos($angle), -sin($angle), 0.0); glVertex3d($r0 * cos($angle), $r0 * sin($angle), $z); glVertex3d($r0 * cos($angle), $r0 * sin($angle), -$z); } glEnd(); glEndList(); return $list; } drawGear($gear, $dx, $dy, $dz, $angle) { glPushMatrix(); glTranslated($dx, $dy, $dz); glRotated($angle, 0.0, 0.0, 1.0); glCallList($gear); glPopMatrix(); } normalizeAngle($angle) { while ($angle < 0) $angle += 360 * 16; while ($angle > 360 * 16) $angle -= 360 * 16; } } class MainWindow inherits QMainWindow { private $.centralWidget, $.glWidgetArea, $.pixmapLabelArea, $.glWidget, $.pixmapLabel, $.xSlider, $.ySlider, $.zSlider, $.fileMenu, $.helpMenu, $.grabFrameBufferAct, $.renderIntoPixmapAct, $.clearPixmapAct, $.exitAct, $.aboutAct, $.aboutQtAct; constructor() { $.centralWidget = new QWidget(); $.setCentralWidget($.centralWidget); $.glWidget = new GLWidget(); $.pixmapLabel = new QLabel(); $.glWidgetArea = new QScrollArea(); $.glWidgetArea.setWidget($.glWidget); $.glWidgetArea.setWidgetResizable(True); $.glWidgetArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); $.glWidgetArea.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); $.glWidgetArea.setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); $.glWidgetArea.setMinimumSize(50, 50); $.pixmapLabelArea = new QScrollArea(); $.pixmapLabelArea.setWidget($.pixmapLabel); $.pixmapLabelArea.setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); $.pixmapLabelArea.setMinimumSize(50, 50); $.xSlider = $.createSlider(SIGNAL("xRotationChanged(int)"), SLOT("setXRotation(int)")); $.ySlider = $.createSlider(SIGNAL("yRotationChanged(int)"), SLOT("setYRotation(int)")); $.zSlider = $.createSlider(SIGNAL("zRotationChanged(int)"), SLOT("setZRotation(int)")); $.createActions(); $.createMenus(); my $centralLayout = new QGridLayout(); $centralLayout.addWidget($.glWidgetArea, 0, 0); $centralLayout.addWidget($.pixmapLabelArea, 0, 1); $centralLayout.addWidget($.xSlider, 1, 0, 1, 2); $centralLayout.addWidget($.ySlider, 2, 0, 1, 2); $centralLayout.addWidget($.zSlider, 3, 0, 1, 2); $.centralWidget.setLayout($centralLayout); $.xSlider.setValue(15 * 16); $.ySlider.setValue(345 * 16); $.zSlider.setValue(0 * 16); $.setWindowTitle(TR("Grabber")); $.resize(400, 300); } renderIntoPixmap() { my $size = $.getSize(); if ($size.isValid()) { my $pixmap = $.glWidget.renderPixmap($size.width(), $size.height()); $.setPixmap($pixmap); } } grabFrameBuffer() { my $image = $.glWidget.grabFrameBuffer(); $.setPixmap(QPixmap::fromImage($image)); } clearPixmap() { $.setPixmap(new QPixmap()); } about() { QMessageBox::about($self, TR("About Grabber"), TR("The <b>Grabber</b> example demonstrates two approaches for " "rendering OpenGL into a Qt pixmap.")); } createActions() { $.renderIntoPixmapAct = new QAction(TR("&Render into Pixmap..."), $self); $.renderIntoPixmapAct.setShortcut(TR("Ctrl+R")); $.connect($.renderIntoPixmapAct, SIGNAL("triggered()"), SLOT("renderIntoPixmap()")); $.grabFrameBufferAct = new QAction(TR("&Grab Frame Buffer"), $self); $.grabFrameBufferAct.setShortcut(TR("Ctrl+G")); $.connect($.grabFrameBufferAct, SIGNAL("triggered()"), SLOT("grabFrameBuffer()")); $.clearPixmapAct = new QAction(TR("&Clear Pixmap"), $self); $.clearPixmapAct.setShortcut(TR("Ctrl+L")); $.connect($.clearPixmapAct, SIGNAL("triggered()"), SLOT("clearPixmap()")); $.exitAct = new QAction(TR("E&xit"), $self); $.exitAct.setShortcut(TR("Ctrl+Q")); $.connect($.exitAct, SIGNAL("triggered()"), SLOT("close()")); $.aboutAct = new QAction(TR("&About"), $self); $.connect($.aboutAct, SIGNAL("triggered()"), SLOT("about()")); $.aboutQtAct = new QAction(TR("About &Qt"), $self); QAPP().connect($.aboutQtAct, SIGNAL("triggered()"), SLOT("aboutQt()")); } createMenus() { $.fileMenu = $.menuBar().addMenu(TR("&File")); $.fileMenu.addAction($.renderIntoPixmapAct); $.fileMenu.addAction($.grabFrameBufferAct); $.fileMenu.addAction($.clearPixmapAct); $.fileMenu.addSeparator(); $.fileMenu.addAction($.exitAct); $.helpMenu = $.menuBar().addMenu(TR("&Help")); $.helpMenu.addAction($.aboutAct); $.helpMenu.addAction($.aboutQtAct); } createSlider($changedSignal, $setterSlot) { my $slider = new QSlider(Qt::Horizontal); $slider.setRange(0, 360 * 16); $slider.setSingleStep(16); $slider.setPageStep(15 * 16); $slider.setTickInterval(15 * 16); $slider.setTickPosition(QSlider::TicksRight); $.glWidget.connect($slider, SIGNAL("valueChanged(int)"), $setterSlot); $slider.connect($.glWidget, $changedSignal, SLOT("setValue(int)")); return $slider; } setPixmap($pixmap) { $.pixmapLabel.setPixmap($pixmap); my $size = $pixmap.size(); if ($size.subtract(new QSize(1, 0)) == $.pixmapLabelArea.maximumViewportSize()) $size.subtractEquals(new QSize(1, 0)); $.pixmapLabel.resize($size); } getSize() { my $ok; my $text = QInputDialog::getText($self, TR("Grabber"), TR("Enter pixmap size:"), QLineEdit::Normal, sprintf(TR("%d x %d"), $.glWidget.width(), $.glWidget.height()), \$ok); if (!$ok) return new QSize(); my $regExp = new QRegExp(TR("([0-9]+) *x *([0-9]+)")); if ($regExp.exactMatch($text)) { my $width = int($regExp.cap(1)); my $height = int($regExp.cap(2)); if ($width > 0 && $width < 2048 && $height > 0 && $height < 2048) return new QSize($width, $height); } return $.glWidget.size(); } } class grabber inherits QApplication { constructor() { my $mainWin = new MainWindow(); $mainWin.show(); $.exec(); } }