summaryrefslogtreecommitdiffstats
path: root/qsmonster
diff options
context:
space:
mode:
authorDavid Boddie <dboddie@trolltech.com>2009-04-02 19:41:21 +0200
committerDavid Boddie <dboddie@trolltech.com>2009-04-02 19:41:21 +0200
commitcc2f2885c8ccd3a10324d85b05951ef25700f96b (patch)
tree2796450ee9c6e1ea4c4fa3962d69ac7df85c54e4 /qsmonster
parent28125e7eae83e90e2b5b0d2e5d30d6f8f229482d (diff)
Added a Python port of the Qt Script Monster example.
Diffstat (limited to 'qsmonster')
-rw-r--r--qsmonster/qsmonster.py215
1 files changed, 215 insertions, 0 deletions
diff --git a/qsmonster/qsmonster.py b/qsmonster/qsmonster.py
new file mode 100644
index 0000000..6d4dcf9
--- /dev/null
+++ b/qsmonster/qsmonster.py
@@ -0,0 +1,215 @@
+#############################################################################
+##
+## Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+## Contact: Qt Software Information (qt-info@nokia.com)
+##
+## This file is part of the Graphics Dojo project on Qt Labs.
+##
+## This file may be used under the terms of the GNU General Public
+## License version 2.0 or 3.0 as published by the Free Software Foundation
+## and appearing in the file LICENSE.GPL included in the packaging of
+## this file. Please review the following information to ensure GNU
+## General Public Licensing requirements will be met:
+## http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+## http://www.gnu.org/copyleft/gpl.html.
+##
+## If you are unsure which license is appropriate for your use, please
+## contact the sales department at qt-sales@nokia.com.
+##
+## This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+## WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+##
+#############################################################################
+
+import sys
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+from PyQt4.QtNetwork import *
+from PyQt4.QtScript import *
+
+try:
+ import qsmonster_rc
+except ImportError:
+ sys.stderr.write(
+ "Please process the parallaxslide.qrc file before running this program. "
+ "For example with:\n\n"
+ "pyrcc4 -o qsmonster_rc.py qsmonster.qrc\n\n"
+ )
+ sys.exit(1)
+
+MONSTER_JS_URL = "http://deanm.github.com/pre3d/monster.js"
+
+class PaintCommand:
+ def __init__(self, opacity = 0.0, stroke = QPen(),
+ fill = QBrush(), polygon = QPolygonF()):
+ self.opacity = opacity
+ self.stroke = stroke
+ self.fill = fill
+ self.polygon = polygon
+
+
+def parseColor(name):
+
+ if name == "none":
+ return QColor()
+
+ name = str(name)
+ if name.startswith("rgba("):
+ start = name.find('(')
+ end = name.rfind(')')
+ if end != -1:
+ substr = name[start+1:-1]
+ colors = map(float, substr.split(','))
+ if len(colors) == 4:
+ colors[3] = max(0, colors[3] * 255)
+ return QColor(*colors)
+
+ return QColor(name)
+
+
+class QSMonster(QWidget):
+
+ def __init__(self, parent = None):
+
+ QWidget.__init__(self, parent)
+ self.commandBuffer = []
+ self.fps = 0
+ self.frameTick = QTime()
+ self.totalFrame = 0
+
+ self.engine = QScriptEngine(self)
+ self.engine.globalObject().setProperty("drawPolygons",
+ self.engine.newFunction(self.drawPolygons, 2))
+
+ self.manager = QNetworkAccessManager(self)
+ self.connect(self.manager, SIGNAL("finished(QNetworkReply*)"),
+ self.start)
+
+ url = QUrl(MONSTER_JS_URL)
+ reply = self.manager.get(QNetworkRequest(url))
+ self.connect(reply, SIGNAL("downloadProgress(qint64, qint64)"),
+ self.progress)
+
+ self.setWindowTitle(self.tr("About to download %1").arg(MONSTER_JS_URL))
+
+ def progress(self, received, total):
+
+ percent = received * 100 / total
+ self.setWindowTitle(self.tr("Downloading %1: %2%").arg(MONSTER_JS_URL).arg(percent))
+
+ def start(self, networkReply):
+
+ url = networkReply.url()
+ if networkReply.error():
+ setWindowTitle(self.tr("Can't download %1: %2").arg(
+ url.toString()).arg(networkReply.errorString()))
+ else:
+ self.setWindowTitle(self.tr("Monster Evolution in Qt"))
+ self.setAttribute(Qt.WA_OpaquePaintEvent, True)
+
+ file = QFile()
+ file.setFileName(":/magic.js")
+ file.open(QIODevice.ReadOnly)
+ magicCode = QString(file.readAll())
+ file.close()
+ self.engine.evaluate(magicCode)
+
+ scriptCode = QString(networkReply.readAll())
+
+ # Qt Script parser does not accept this
+ if QT_VERSION < 0x040500:
+ scriptCode.replace(",}", "}")
+ else:
+ scriptCode.replace("break}", "break;}")
+ scriptCode.replace("continue}", "continue;}")
+
+ self.engine.evaluate(scriptCode)
+ self.engine.evaluate("window.onLoad()")
+ self.startTimer(33)
+
+ networkReply.deleteLater()
+
+ def timerEvent(self, event):
+
+ self.engine.evaluate("window.onTimer()")
+
+ def paintEvent(self, event):
+
+ p = QPainter(self)
+ p.setRenderHint(QPainter.Antialiasing, True)
+ for cmd in self.commandBuffer:
+ p.setPen(cmd.stroke)
+ p.setOpacity(cmd.opacity)
+ p.setBrush(cmd.fill)
+ p.drawPolygon(cmd.polygon)
+
+ p.setPen(Qt.white)
+ p.drawText(10, 600 - 20, QString("%1 FPS").arg(self.fps))
+
+ def drawPolygons(self, context, engine):
+
+ polygonCount = context.argument(0).toInt32()
+ polygonBuffer = context.argument(1)
+
+ extra = polygonCount - len(self.commandBuffer)
+ if extra > 0:
+ self.commandBuffer += [None] * extra
+ elif extra < 0:
+ self.commandBuffer = self.commandBuffer[:polygonCount]
+
+ c = 0
+ while c < polygonCount:
+
+ cmd = polygonBuffer.property(c)
+ alpha = cmd.property(0).toNumber()
+ strokeColor = cmd.property(1).toString()
+ fillColor = cmd.property(2).toString()
+ pointCount = cmd.property(3).toInt32()
+ pointArray = cmd.property(4)
+
+ polygon = QPolygonF(pointCount / 2)
+ p = 0
+ while p < pointCount / 2:
+ polygon[p] = QPointF(pointArray.property(2 * p).toNumber(),
+ pointArray.property(2 * p + 1).toNumber())
+ p += 1
+
+ paint = self.commandBuffer[c]
+ if not paint:
+ paint = self.commandBuffer[c] = PaintCommand()
+
+ paint.opacity = alpha
+ if strokeColor != "none":
+ paint.stroke.setStyle(Qt.SolidLine)
+ paint.stroke.setColor(parseColor(strokeColor))
+ else:
+ paint.stroke = QPen(Qt.NoPen)
+
+ if fillColor != "none":
+ paint.fill = QBrush(parseColor(fillColor))
+ else:
+ paint.fill = QBrush(Qt.NoBrush)
+ paint.polygon = polygon
+ c += 1
+
+ self.update()
+
+ if self.totalFrame % 15 == 0:
+ elapsed = self.frameTick.elapsed()
+ self.frameTick.start()
+ self.fps = 16 * 1000 / (1 + elapsed)
+
+ self.totalFrame += 1
+
+ return QScriptValue()
+
+
+if __name__ == "__main__":
+
+ app = QApplication(sys.argv)
+
+ qsmonster = QSMonster()
+ qsmonster.setFixedSize(800, 600)
+ qsmonster.show()
+
+ sys.exit(app.exec_())