|
| 1 | +{ |
| 2 | + "cells": [ |
| 3 | + { |
| 4 | + "cell_type": "markdown", |
| 5 | + "metadata": {}, |
| 6 | + "source": [ |
| 7 | + "## Rectangle Tutorial" |
| 8 | + ] |
| 9 | + }, |
| 10 | + { |
| 11 | + "cell_type": "markdown", |
| 12 | + "metadata": {}, |
| 13 | + "source": [ |
| 14 | + "Welcome to the tutorial on how to draw a rectangle using the new QtGui based OpenGL api of PySide2.\n", |
| 15 | + "\n", |
| 16 | + "As we have mentioned on the first tutorial on how to draw the `Hello Triangle`. I will be giving only the relative parts of the code and explain the differences rather than commenting everything.\n", |
| 17 | + "\n", |
| 18 | + "Let's see the final output of our application" |
| 19 | + ] |
| 20 | + }, |
| 21 | + { |
| 22 | + "cell_type": "code", |
| 23 | + "execution_count": 2, |
| 24 | + "metadata": {}, |
| 25 | + "outputs": [ |
| 26 | + { |
| 27 | + "data": { |
| 28 | + "text/plain": [ |
| 29 | + "CompletedProcess(args=['python', 'app.py'], returncode=0)" |
| 30 | + ] |
| 31 | + }, |
| 32 | + "execution_count": 2, |
| 33 | + "metadata": {}, |
| 34 | + "output_type": "execute_result" |
| 35 | + } |
| 36 | + ], |
| 37 | + "source": [ |
| 38 | + "import subprocess\n", |
| 39 | + "\n", |
| 40 | + "subprocess.run([\"python\", \"app.py\"])" |
| 41 | + ] |
| 42 | + }, |
| 43 | + { |
| 44 | + "cell_type": "markdown", |
| 45 | + "metadata": {}, |
| 46 | + "source": [ |
| 47 | + "Not so bad right !" |
| 48 | + ] |
| 49 | + }, |
| 50 | + { |
| 51 | + "cell_type": "markdown", |
| 52 | + "metadata": {}, |
| 53 | + "source": [ |
| 54 | + "I am skipping the code on the window holding the gl widget. \n", |
| 55 | + "\n", |
| 56 | + "Here is the constructor of our gl widget." |
| 57 | + ] |
| 58 | + }, |
| 59 | + { |
| 60 | + "cell_type": "code", |
| 61 | + "execution_count": null, |
| 62 | + "metadata": {}, |
| 63 | + "outputs": [], |
| 64 | + "source": [ |
| 65 | + "class RectangleGL(QOpenGLWidget):\n", |
| 66 | + " \"Texture loading opengl widget\"\n", |
| 67 | + "\n", |
| 68 | + " def __init__(self, parent=None):\n", |
| 69 | + " \"Constructor\"\n", |
| 70 | + " QOpenGLWidget.__init__(self, parent)\n", |
| 71 | + " tutoTutoDir = os.path.dirname(__file__)\n", |
| 72 | + " tutoPardir = os.path.join(tutoTutoDir, os.pardir)\n", |
| 73 | + " tutoPardir = os.path.realpath(tutoPardir)\n", |
| 74 | + " mediaDir = os.path.join(tutoPardir, \"media\")\n", |
| 75 | + " shaderDir = os.path.join(mediaDir, \"shaders\")\n", |
| 76 | + " #\n", |
| 77 | + " availableShaders = [\"rectangle\", \"triangle\"]\n", |
| 78 | + " self.shaders = {\n", |
| 79 | + " name: {\n", |
| 80 | + " \"fragment\": os.path.join(shaderDir, name + \".frag\"),\n", |
| 81 | + " \"vertex\": os.path.join(shaderDir, name + \".vert\")\n", |
| 82 | + " } for name in availableShaders\n", |
| 83 | + " }\n", |
| 84 | + " self.core = \"--coreprofile\" in QCoreApplication.arguments()\n", |
| 85 | + "\n", |
| 86 | + " # opengl data related\n", |
| 87 | + " self.context = QOpenGLContext()\n", |
| 88 | + " self.program = QOpenGLShaderProgram()\n", |
| 89 | + " self.vao = QOpenGLVertexArrayObject()\n", |
| 90 | + " self.vbo = QOpenGLBuffer(QOpenGLBuffer.VertexBuffer)\n", |
| 91 | + " \n", |
| 92 | + " # ############ Diff 1 ##########################\n", |
| 93 | + " # this is the novelty in this code. We specify #\n", |
| 94 | + " # indices of triangles that would made up #\n", |
| 95 | + " # our rectangle. Notice its data type #\n", |
| 96 | + " self.indices = np.array([\n", |
| 97 | + " 0, 1, 3, # first triangle\n", |
| 98 | + " 1, 2, 3 # second triangle\n", |
| 99 | + " ], dtype=ctypes.c_uint)\n", |
| 100 | + "\n", |
| 101 | + " # vertex data of the panel that would hold the image\n", |
| 102 | + " \n", |
| 103 | + " self.vertexData = np.array([\n", |
| 104 | + " # corners of the rectangle\n", |
| 105 | + " 0.5, 0.5, 0.0, # top right\n", |
| 106 | + " 0.5, -0.5, 0.0, # bottom right\n", |
| 107 | + " -0.5, -0.5, 0.0, # bottom left\n", |
| 108 | + " -0.5, 0.5, 0.0, # top left\n", |
| 109 | + " ], dtype=ctypes.c_float)\n", |
| 110 | + "\n", |
| 111 | + " self.rectColor = QVector4D(0.0, 1.0, 1.0, 0.0)" |
| 112 | + ] |
| 113 | + }, |
| 114 | + { |
| 115 | + "cell_type": "markdown", |
| 116 | + "metadata": {}, |
| 117 | + "source": [ |
| 118 | + "As you can see it is fairly close to the constructor of the triangle widget.\n", |
| 119 | + "The initialization is exactly the same as triangle widget so we are skipping that entirely.\n", |
| 120 | + "\n", |
| 121 | + "Let's see the drawing function." |
| 122 | + ] |
| 123 | + }, |
| 124 | + { |
| 125 | + "cell_type": "code", |
| 126 | + "execution_count": null, |
| 127 | + "metadata": {}, |
| 128 | + "outputs": [], |
| 129 | + "source": [ |
| 130 | + " def paintGL(self):\n", |
| 131 | + " \"paint gl\"\n", |
| 132 | + " funcs = self.context.functions()\n", |
| 133 | + " # clean up what was drawn\n", |
| 134 | + " funcs.glClear(pygl.GL_COLOR_BUFFER_BIT)\n", |
| 135 | + "\n", |
| 136 | + " # bind texture\n", |
| 137 | + " vaoBinder = QOpenGLVertexArrayObject.Binder(self.vao)\n", |
| 138 | + " self.program.bind()\n", |
| 139 | + "\n", |
| 140 | + " # draw stuff\n", |
| 141 | + " ########## Diff #############\n", |
| 142 | + " # This is another drawing function in opengl\n", |
| 143 | + " # Notice that its signature is from OpenGL ES 2\n", |
| 144 | + " \n", |
| 145 | + " funcs.glDrawElements(\n", |
| 146 | + " pygl.GL_TRIANGLES,\n", |
| 147 | + " self.indices.size,\n", |
| 148 | + " pygl.GL_UNSIGNED_INT,\n", |
| 149 | + " self.indices.tobytes())\n", |
| 150 | + " # VoidPtr(self.indices.tobytes() * ctypes.sizeof(ctypes.c_uint)))\n", |
| 151 | + " vaoBinder = None\n", |
| 152 | + " self.program.release()" |
| 153 | + ] |
| 154 | + }, |
| 155 | + { |
| 156 | + "cell_type": "markdown", |
| 157 | + "metadata": {}, |
| 158 | + "source": [ |
| 159 | + "- The first parameter is the drawing mode.\n", |
| 160 | + "- The second is the number of elements that is to be drawn, since the indice specifies the index of an element that is to be drawn, it is equal to the size of indices.\n", |
| 161 | + "- We specify the type of the elements of indices\n", |
| 162 | + "- We specify the data of indices. \n", |
| 163 | + "\n", |
| 164 | + "If we want to follow documentation more closely we can also use the commented line instead of the final parameter which creates the void pointer to data of the indices" |
| 165 | + ] |
| 166 | + }, |
| 167 | + { |
| 168 | + "cell_type": "markdown", |
| 169 | + "metadata": {}, |
| 170 | + "source": [ |
| 171 | + "That's it now you know how to draw a rectangle in opengl api of pyside2" |
| 172 | + ] |
| 173 | + } |
| 174 | + ], |
| 175 | + "metadata": { |
| 176 | + "kernelspec": { |
| 177 | + "display_name": "Python 3", |
| 178 | + "language": "python", |
| 179 | + "name": "python3" |
| 180 | + }, |
| 181 | + "language_info": { |
| 182 | + "codemirror_mode": { |
| 183 | + "name": "ipython", |
| 184 | + "version": 3 |
| 185 | + }, |
| 186 | + "file_extension": ".py", |
| 187 | + "mimetype": "text/x-python", |
| 188 | + "name": "python", |
| 189 | + "nbconvert_exporter": "python", |
| 190 | + "pygments_lexer": "ipython3", |
| 191 | + "version": "3.7.3" |
| 192 | + } |
| 193 | + }, |
| 194 | + "nbformat": 4, |
| 195 | + "nbformat_minor": 2 |
| 196 | +} |
0 commit comments