Использование Gtk.GLArea в Pygobject GTK3

Документация по использованию оболочек Python для GTk3 несколько ограничена. Я нашел несколько распространенных примеров виджетов. Я пытаюсь использовать виджет Gtk.GLArea. Документация по API для C, и мне не повезло угадать эквивалентные вызовы Python для использования этого виджета. В этом примере виджет создается с использованием следующего кода C:

 // create a GtkGLArea instance
GtkWidget *gl_area = gtk_gl_area_new ();
g_signal_connect (gl_area, "render", G_CALLBACK (render), NULL);

Тогда функция рендеринга содержит команды openGL:

static gboolean
render (GtkGLArea *area, GdkGLContext *context)
{
  // inside this function it's safe to use GL; the given
  // #GdkGLContext has been made current to the drawable
  // surface used by the #GtkGLArea and the viewport has
  // already been set to be the size of the allocation

  // we can start by clearing the buffer
  glClearColor (0, 0, 0, 0);
  glClear (GL_COLOR_BUFFER_BIT);

  // draw your object
  draw_an_object ();

  // we completed our drawing; the draw commands will be
  // flushed at the end of the signal emission chain, and
  // the buffers will be drawn on the window
  return TRUE;
}

Мой вопрос, как вы делаете эквивалент в Python?

Это моя попытка:

class RootWidget(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title='GL Example')
        self.set_default_size(800,500)
        gl = Gtk.GLArea()
        gl.connect("render", self.gl_render)
        self.add(gl)


    def gl_render(self, gl):
        print(gl)
        Gtk.glClearColor(0,0,0,1)
        Gtk.glClear(Gtk.GL_COLOR_BUFFER_BIT)
        return True

Вы заметите, что я добавил Gtk. к командам gl. Не уверен, что это правильно, но python не знает, что такое glClearColor в функции. Я не очень знаком с пространствами имен C, но я не могу понять, как функция C могла бы понять, что такое команды gl. Программа работает, и я получаю следующие ошибки в консоли:

настройка fb не поддерживается

(python.exe:120048): Gdk-WARNING **: ошибка компиляции во фрагментном шейдере:

ОШИБКА: 0:5: 'gl_FragColor': необъявленный идентификатор

ОШИБКА: 0:5: 'texture2D': не найдена соответствующая перегруженная функция (используется неявное преобразование)

Любой вклад по этому вопросу будет полезен. Я надеюсь, что смогу использовать команды opengl для рисования в фиксированной области виджетов.

редактировать: это моя последняя попытка. в on_render() Функция, которую я печатаю контекст, и я вижу, что свойство context установлено в <gtk.gdk.Win32GLContext object at 0x3f133f0> и отладка показывает, что это текущий контекст. Проблема в том, что я все еще получаю тот же шейдер, Frag_Color и ошибки текстуры, и я даже не вызываю команды gl.

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from OpenGL.GL import *
from OpenGL.GLU import *


class MyGLArea(Gtk.GLArea):
    def __init__(self):
        Gtk.GLArea.__init__(self)
        self.connect("realize", self.on_realize)


    def on_realize(self, area):
        ctx = self.get_context()
        ctx.make_current()
        print("The context is {}".format(self.get_property("context")))
        err = self.get_error()
        if err:
            print(err)
        return



class RootWidget(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title='GL Example')
        self.set_default_size(800,500)
        gl_area = MyGLArea()
        self.add(gl_area)


win = RootWidget()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()

редактировать 2: Кажется, что у меня просто проблема установки с виджетом GLArea. Кажется странным, поскольку я использую более 30 различных виджетов Gtk без проблем. У меня есть ошибки, просто добавив виджет и даже не отправляя команды. Я запустил код в интерпретаторе Ubuntu Python, и при создании виджета не было ошибок. У меня есть некоторые проблемы с некоторыми командами GL, но они могут быть из установленной оболочки Python. Я все еще ищу виджет, эквивалентный инициализации pygame или glut, и устанавливаю функции проекции для настройки области просмотра. Если у кого-то есть идеи, я бы с удовольствием их услышал. Следующий код работает без ошибок:

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from OpenGL.GL import *
from OpenGL.GLU import *


class MyGLArea(Gtk.GLArea):
    def __init__(self):
        Gtk.GLArea.__init__(self)
        self.connect("realize", self.on_realize)
        self.connect("render", self.render)


    def on_realize(self, area):
        ctx = self.get_context()
        ctx.make_current()
        err = self.get_error()
        if err:
            print("The error is {}".format(err))

    def render(self, area, ctx):
        glClearColor(1,0,0,1)
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
    return True

class RootWidget(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title='GL Example')
        self.set_default_size(800,500)
        gl_area = MyGLArea()
        self.add(gl_area)

win = RootWidget()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main() 

2 ответа

Используя установщик All-In-One для Windows, я заметил, что есть опция для расширений OpenGL для GTK+. Теперь все работает как положено. Вот некоторый рабочий код:

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from OpenGL.GL import *
from OpenGL.GL import shaders
import numpy as np

FRAGMENT_SOURCE ='''
#version 330
in vec4 inputColor;
out vec4 outputColor;
void main(){
outputColor = vec4(1.0,0.0,0.0,1.0);//constant red. I know it's a poor shader
};'''

VERTEX_SOURCE = '''
#version 330
in vec4 position;
void main(){
gl_Position =  position;
}'''

class MyGLArea(Gtk.GLArea):
    def __init__(self):
        Gtk.GLArea.__init__(self)
        self.connect("realize", self.on_realize)
        self.connect("render", self.on_render)

    def on_realize(self, area):
        ctx = self.get_context()
        print("realized", ctx)

    def on_render(self, area, ctx):
        ctx.make_current()
        glClearColor(0, 0, 0, 1)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        VERTEX_SHADER_PROG = shaders.compileShader(VERTEX_SOURCE, GL_VERTEX_SHADER)
        FRAGMENT_SHADER_PROG = shaders.compileShader(FRAGMENT_SOURCE, GL_FRAGMENT_SHADER)
        self.shader_prog = shaders.compileProgram(VERTEX_SHADER_PROG, FRAGMENT_SHADER_PROG)
        self.create_object()

    def create_object(self):
        # Create a new VAO (Vertex Array Object) and bind it
        vertex_array_object = glGenVertexArrays(1)
        glBindVertexArray(vertex_array_object)
        # Generate buffers to hold our vertices
        vertex_buffer = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer)
        # Get the position of the 'position' in parameter of our shader and bind it.
        position = glGetAttribLocation(self.shader_prog, 'position')
        glEnableVertexAttribArray(position)
        # Describe the position data layout in the buffer
        glVertexAttribPointer(position, 3, GL_FLOAT, False, 0, ctypes.c_void_p(0))
        # Send the data over to the buffer
        vertices = np.array([-0.6, -0.6, 0.0,
                             0.0, 0.6, 0.0,
                             0.6, -0.6, 0.0,
                             0.7, -0.1, 0.0,
                             0.8, 0.1, 0.0,
                             0.9, -0.1, 0.0
                             ], dtype=np.float32)
        glBufferData(GL_ARRAY_BUFFER, 96, vertices, GL_STATIC_DRAW)
        # Unbind the VAO first (Important)
        glBindVertexArray(0)
        # Unbind other stuff
        glDisableVertexAttribArray(position)




        glBindBuffer(GL_ARRAY_BUFFER, 0)
        self.display(vertex_array_object)

    def display(self, vert):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glUseProgram(self.shader_prog)
        glBindVertexArray(vert)
        glDrawArrays(GL_TRIANGLES, 0, 3)
        glDrawArrays(GL_TRIANGLES, 4, 3)
        glBindVertexArray(0)
        glUseProgram(0)

class RootWidget(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title='GL Example')
        self.set_default_size(800, 500)
        gl_area = MyGLArea()
        gl_area.set_has_depth_buffer(False)
        gl_area.set_has_stencil_buffer(False)
        self.add(gl_area)

win = RootWidget()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()

Треугольник Варианты установки

Я не уверен, что это работает для вас, но это сработало для меня.

Файл Python:

#!/usr/bin/env python
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GdkPixbuf, Gdk
from OpenGL.GL import glClearColor, glClear, GL_COLOR_BUFFER_BIT
import os, sys

UI_FILE = "pygtk_gtkglarea.ui"

class GUI:
    def __init__(self):

        self.builder = Gtk.Builder()
        self.builder.add_from_file(UI_FILE)
        self.builder.connect_signals(self)

        gl_area = Gtk.GLArea()
        gl_area.connect('render', self.area_render)
        gl_area.connect('realize', self.area_realize)
        #gl_area.connect('create-context', self.area_context)
        box = self.builder.get_object('box1')
        box.pack_end(gl_area, True, True, 0)

        window = self.builder.get_object('window')
        window.show_all()

    def area_realize (self, gl_area):       
        error = gl_area.get_error()
        if error != None:
            print "your graphics card is probably too old : ", error
        else:
            print gl_area, "realize... fine so far"

    def area_context(self, gl_area):
        # not needed except for special instances, read the docs
        c = gl_area.get_context()
        print c , "context"
        return c

    def area_render(self, area, context):
        #print gl_area
        #print gl_context
        glClearColor (0.5, 0.5, 0.5, 1.0)
        glClear (GL_COLOR_BUFFER_BIT)
        glFlush()
        print "rendering... done"
        return True

    def on_window_destroy(self, window):
        Gtk.main_quit()

def main():
    app = GUI()
    Gtk.main()

if __name__ == "__main__":
    sys.exit(main())

И файл pygtk_gtkglarea.ui:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<interface>
  <requires lib="gtk+" version="3.0"/>
  <object class="GtkWindow" id="window">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="title" translatable="yes">window</property>
    <property name="default_width">500</property>
    <property name="default_height">400</property>
    <signal name="destroy" handler="on_window_destroy" swapped="no"/>
    <child>
      <object class="GtkBox" id="box1">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <child>
          <placeholder/>
        </child>
      </object>
    </child>
  </object>
</interface>
Другие вопросы по тегам