Skip to content

Pyimgui#177

Open
mlviz wants to merge 7 commits intoglumpy:masterfrom
mlviz:pyimgui
Open

Pyimgui#177
mlviz wants to merge 7 commits intoglumpy:masterfrom
mlviz:pyimgui

Conversation

@mlviz
Copy link
Copy Markdown

@mlviz mlviz commented Dec 3, 2018

As mentionned in my answer on the thread,

I made a branch with a first experimental imgui backend and 2 examples. The only problem is that I needed to modify 2 of the files in the external libraries to make it work, if you can find a way to handle that for a build that would be great.

imgui/integrations/opengl.py
we need at line 205 to typecast (I used numpy but probably would be better to do it with ctype):

        ortho_projection = np.array([
            [ 2.0/display_width, 0.0,                   0.0, 0.0],
            [ 0.0,               2.0/-display_height,   0.0, 0.0],
            [ 0.0,               0.0,                  -1.0, 0.0],
            [-1.0,               1.0,                   0.0, 1.0]], dtype=np.float32)

and something similar in:

baseplatform.py from PyOpengl.

Otherwise I added the examples in the sub-directory examples/imgui.

I tested it on windows, but it would be a good idea to test it on osx and linux.

Also how can we adress the problem mentioned before with external files?
It seems to be the cython compiler that complains so it might be possible to correct it without modifying the files but by dealing with cython but I am not familiar with it enough. The only thing I can confirm is that its possible to make it work.

Aussi un bonjour en français de Montréal, ma langue maternelle est le français.

A+
Martin

@rougier
Copy link
Copy Markdown
Member

rougier commented Dec 17, 2018

What are the dependencies exactly (I tried installing pyimgui but the Lorenz example complains about missing pyimgui unknown backend)

@dan90210
Copy link
Copy Markdown

dan90210 commented Jan 3, 2019

After pulling and recompiling glumpy I was able to get past the error that Rougier encountered. I now get the new error:

[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[x] Window creation failed

This happens when attempting to run the Lorenz example on Ubuntu.

@rougier
Copy link
Copy Markdown
Member

rougier commented Jan 3, 2019

@mlviz Do you have an idea what can be wrong on our side?

@mlviz
Copy link
Copy Markdown
Author

mlviz commented Jan 5, 2019

Hi,

Sorry I didn't come back sooner, got caught in the holidays.

The backend comes from the file glumpy/app/window/backends/backend_pyimgui.py which is part of the pull request. The reason is that pyimgui comes with its opengl glfw window, so I built a backend on top of it based on the backend template. I also added the on_gui event to the backend to make it easier to work with.

lines 84-86 of backend_pyimgui.py shows the key dependencies:

    import glfw
    import OpenGL.GL as gl
    import imgui
    from imgui.integrations.glfw import GlfwRenderer

I would recommend to first install pyimgui with glfw backend:

    pip install imgui[glfw]

(see https://github.com/swistakm/pyimgui)
and make sure it works right on your OS.
(see https://github.com/swistakm/pyimgui/blob/master/doc/examples/glfw3.py)

Then install the pull request version of glumpy which is the pyimgui branch of my mlviz fork:

git clone https://github.com/mlviz/glumpy.git
cd glumpy
git checkout pyimgui
python setup.py install

First try examples/pyimgui/gui-quad-rotation.py, it shows how to use the imgui backend:

cd examples/pyimgui
python gui-quad-rotation.py

Should give you this:
image

If it does not work, as mentionned in my first comment from dec 2, you might have to adjust some things on external packages:

  • in baseplatform.py from PyOpengl (in my case located at C:\Anaconda3\Lib\site-packages\OpenGL\platform)
  • imgui/integrations/opengl.py from pyimgui (in my case located at C:\Anaconda3\Lib\site-packages\imgui\integrations)

The screenshot just come from an example I ran on Windows10 using then Anaconda distribution of python 3.7 (also works on 3.6).

@mlviz
Copy link
Copy Markdown
Author

mlviz commented Jan 5, 2019

Just for reference, here is the adjusted version of opengl.py
(in my case located at C:\Anaconda3\Lib\site-packages\imgui\integrations):

# -*- coding: utf-8 -*-
from __future__ import absolute_import

import OpenGL.GL as gl

import imgui
import ctypes
import numpy as np

class BaseOpenGLRenderer(object):
    def __init__(self):
        self.io = imgui.get_io()

        self._font_texture = None

        self.io.delta_time = 1.0 / 60.0

        self._create_device_objects()
        self.refresh_font_texture()

        # todo: add option to set new_frame callback/implementation
        self.io.render_callback = self.render

    def render(self, draw_data):
        raise NotImplementedError

    def refresh_font_texture(self):
        raise NotImplementedError

    def _create_device_objects(self):
        raise NotImplementedError

    def _invalidate_device_objects(self):
        raise NotImplementedError

    def shutdown(self):
        self._invalidate_device_objects()
        imgui.shutdown()


class ProgrammablePipelineRenderer(BaseOpenGLRenderer):
    """Basic OpenGL integration base class."""

    VERTEX_SHADER_SRC = """
    #version 330

    uniform mat4 ProjMtx;
    in vec2 Position;
    in vec2 UV;
    in vec4 Color;
    out vec2 Frag_UV;
    out vec4 Frag_Color;

    void main() {
        Frag_UV = UV;
        Frag_Color = Color;

        gl_Position = ProjMtx * vec4(Position.xy, 0, 1);
    }
    """

    FRAGMENT_SHADER_SRC = """
    #version 330

    uniform sampler2D Texture;
    in vec2 Frag_UV;
    in vec4 Frag_Color;
    out vec4 Out_Color;

    void main() {
        Out_Color = Frag_Color * texture(Texture, Frag_UV.st);
    }
    """

    def __init__(self):
        self._shader_handle = None
        self._vert_handle = None
        self._fragment_handle = None

        self._attrib_location_tex = None
        self._attrib_proj_mtx = None
        self._attrib_location_position = None
        self._attrib_location_uv = None
        self._attrib_location_color = None

        self._vbo_handle = None
        self._elements_handle = None
        self._vao_handle = None

        super(ProgrammablePipelineRenderer, self).__init__()

    def refresh_font_texture(self):
        # save texture state
        last_texture = gl.glGetIntegerv(gl.GL_TEXTURE_BINDING_2D)

        width, height, pixels = self.io.fonts.get_tex_data_as_rgba32()

        if self._font_texture is not None:
            gl.glDeleteTextures([self._font_texture])

        self._font_texture = gl.glGenTextures(1)

        gl.glBindTexture(gl.GL_TEXTURE_2D, self._font_texture)
        gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR)
        gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR)
        gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, width, height, 0, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, pixels)

        self.io.fonts.texture_id = self._font_texture
        gl.glBindTexture(gl.GL_TEXTURE_2D, last_texture)
        self.io.fonts.clear_tex_data()

    def _create_device_objects(self):
        # save state
        last_texture = gl.glGetIntegerv(gl.GL_TEXTURE_BINDING_2D)
        last_array_buffer = gl.glGetIntegerv(gl.GL_ARRAY_BUFFER_BINDING)

        last_vertex_array = gl.glGetIntegerv(gl.GL_VERTEX_ARRAY_BINDING)

        self._shader_handle = gl.glCreateProgram()
        # note: no need to store shader parts handles after linking
        vertex_shader = gl.glCreateShader(gl.GL_VERTEX_SHADER)
        fragment_shader = gl.glCreateShader(gl.GL_FRAGMENT_SHADER)

        gl.glShaderSource(vertex_shader, self.VERTEX_SHADER_SRC)
        gl.glShaderSource(fragment_shader, self.FRAGMENT_SHADER_SRC)
        gl.glCompileShader(vertex_shader)
        gl.glCompileShader(fragment_shader)

        gl.glAttachShader(self._shader_handle, vertex_shader)
        gl.glAttachShader(self._shader_handle, fragment_shader)

        gl.glLinkProgram(self._shader_handle)

        # note: after linking shaders can be removed
        gl.glDeleteShader(vertex_shader)
        gl.glDeleteShader(fragment_shader)

        self._attrib_location_tex = gl.glGetUniformLocation(self._shader_handle, "Texture")
        self._attrib_proj_mtx = gl.glGetUniformLocation(self._shader_handle, "ProjMtx")
        self._attrib_location_position = gl.glGetAttribLocation(self._shader_handle, "Position")
        self._attrib_location_uv = gl.glGetAttribLocation(self._shader_handle, "UV")
        self._attrib_location_color = gl.glGetAttribLocation(self._shader_handle, "Color")

        self._vbo_handle = gl.glGenBuffers(1)
        self._elements_handle = gl.glGenBuffers(1)

        self._vao_handle = gl.glGenVertexArrays(1)
        gl.glBindVertexArray(self._vao_handle)
        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._vbo_handle)

        gl.glEnableVertexAttribArray(self._attrib_location_position)
        gl.glEnableVertexAttribArray(self._attrib_location_uv)
        gl.glEnableVertexAttribArray(self._attrib_location_color)

        gl.glVertexAttribPointer(self._attrib_location_position, 2, gl.GL_FLOAT, gl.GL_FALSE, imgui.VERTEX_SIZE, ctypes.c_void_p(imgui.VERTEX_BUFFER_POS_OFFSET))
        gl.glVertexAttribPointer(self._attrib_location_uv, 2, gl.GL_FLOAT, gl.GL_FALSE, imgui.VERTEX_SIZE, ctypes.c_void_p(imgui.VERTEX_BUFFER_UV_OFFSET))
        gl.glVertexAttribPointer(self._attrib_location_color, 4, gl.GL_UNSIGNED_BYTE, gl.GL_TRUE, imgui.VERTEX_SIZE, ctypes.c_void_p(imgui.VERTEX_BUFFER_COL_OFFSET))

        # restore state
        gl.glBindTexture(gl.GL_TEXTURE_2D, last_texture)
        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, last_array_buffer)
        gl.glBindVertexArray(last_vertex_array)

    def render(self, draw_data):
        # perf: local for faster access
        io = self.io

        display_width, display_height = self.io.display_size
        fb_width = int(display_width * io.display_fb_scale[0])
        fb_height = int(display_height * io.display_fb_scale[1])

        if fb_width == 0 or fb_height == 0:
            return

        draw_data.scale_clip_rects(*io.display_fb_scale)

        # backup GL state
        # todo: provide cleaner version of this backup-restore code
        last_program = gl.glGetIntegerv(gl.GL_CURRENT_PROGRAM)
        last_texture = gl.glGetIntegerv(gl.GL_TEXTURE_BINDING_2D)
        last_active_texture = gl.glGetIntegerv(gl.GL_ACTIVE_TEXTURE)
        last_array_buffer = gl.glGetIntegerv(gl.GL_ARRAY_BUFFER_BINDING)
        last_element_array_buffer = gl.glGetIntegerv(gl.GL_ELEMENT_ARRAY_BUFFER_BINDING)
        last_vertex_array = gl.glGetIntegerv(gl.GL_VERTEX_ARRAY_BINDING)
        last_blend_src = gl.glGetIntegerv(gl.GL_BLEND_SRC)
        last_blend_dst = gl.glGetIntegerv(gl.GL_BLEND_DST)
        last_blend_equation_rgb = gl. glGetIntegerv(gl.GL_BLEND_EQUATION_RGB)
        last_blend_equation_alpha = gl.glGetIntegerv(gl.GL_BLEND_EQUATION_ALPHA)
        last_viewport = gl.glGetIntegerv(gl.GL_VIEWPORT)
        last_scissor_box = gl.glGetIntegerv(gl.GL_SCISSOR_BOX)
        last_enable_blend = gl.glIsEnabled(gl.GL_BLEND)
        last_enable_cull_face = gl.glIsEnabled(gl.GL_CULL_FACE)
        last_enable_depth_test = gl.glIsEnabled(gl.GL_DEPTH_TEST)
        last_enable_scissor_test = gl.glIsEnabled(gl.GL_SCISSOR_TEST)

        gl.glEnable(gl.GL_BLEND)
        gl.glBlendEquation(gl.GL_FUNC_ADD)
        gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
        gl.glDisable(gl.GL_CULL_FACE)
        gl.glDisable(gl.GL_DEPTH_TEST)
        gl.glEnable(gl.GL_SCISSOR_TEST)
        gl.glActiveTexture(gl.GL_TEXTURE0)

        gl.glViewport(0, 0, int(fb_width), int(fb_height))

        ortho_projection = np.array([
            [ 2.0/display_width, 0.0,                   0.0, 0.0],
            [ 0.0,               2.0/-display_height,   0.0, 0.0],
            [ 0.0,               0.0,                  -1.0, 0.0],
            [-1.0,               1.0,                   0.0, 1.0]], dtype=np.float32)

        gl.glUseProgram(self._shader_handle)
        gl.glUniform1i(self._attrib_location_tex, 0)
        gl.glUniformMatrix4fv(self._attrib_proj_mtx, 1, gl.GL_FALSE, ortho_projection)
        gl.glBindVertexArray(self._vao_handle)

        for commands in draw_data.commands_lists:
            idx_buffer_offset = 0

            gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._vbo_handle)
            # todo: check this (sizes)
            gl.glBufferData(gl.GL_ARRAY_BUFFER, commands.vtx_buffer_size * imgui.VERTEX_SIZE, ctypes.c_void_p(commands.vtx_buffer_data), gl.GL_STREAM_DRAW)

            gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self._elements_handle)
            # todo: check this (sizes)
            gl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, commands.idx_buffer_size * imgui.INDEX_SIZE, ctypes.c_void_p(commands.idx_buffer_data), gl.GL_STREAM_DRAW)

            # todo: allow to iterate over _CmdList
            for command in commands.commands:
                gl.glBindTexture(gl.GL_TEXTURE_2D, command.texture_id)

                # todo: use named tuple
                x, y, w, z = command.clip_rect
                gl.glScissor(int(x), int(fb_height - w), int(z - x), int(w - y))

                if imgui.INDEX_SIZE == 2:
                    gltype = gl.GL_UNSIGNED_SHORT
                else:
                    gltype = gl.GL_UNSIGNED_INT

                gl.glDrawElements(gl.GL_TRIANGLES, command.elem_count, gltype, ctypes.c_void_p(idx_buffer_offset))

                idx_buffer_offset += command.elem_count * imgui.INDEX_SIZE

        # restore modified GL state
        gl.glUseProgram(last_program)
        gl.glActiveTexture(last_active_texture)
        gl.glBindTexture(gl.GL_TEXTURE_2D, last_texture)
        gl.glBindVertexArray(last_vertex_array)
        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, last_array_buffer)
        gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer)
        gl.glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha)
        gl.glBlendFunc(last_blend_src, last_blend_dst)

        if last_enable_blend:
            gl.glEnable(gl.GL_BLEND)
        else:
            gl.glDisable(gl.GL_BLEND)

        if last_enable_cull_face:
            gl.glEnable(gl.GL_CULL_FACE)
        else:
            gl.glDisable(gl.GL_CULL_FACE)

        if last_enable_depth_test:
            gl.glEnable(gl.GL_DEPTH_TEST)
        else:
            gl.glDisable(gl.GL_DEPTH_TEST)

        if last_enable_scissor_test:
            gl.glEnable(gl.GL_SCISSOR_TEST)
        else:
            gl.glDisable(gl.GL_SCISSOR_TEST)

        gl.glViewport(last_viewport[0], last_viewport[1], last_viewport[2], last_viewport[3])
        gl.glScissor(last_scissor_box[0], last_scissor_box[1], last_scissor_box[2], last_scissor_box[3])

    def _invalidate_device_objects(self):
        if self._vao_handle > -1:
            gl.glDeleteVertexArrays(1, [self._vao_handle])
        if self._vbo_handle > -1:
            gl.glDeleteBuffers(1, [self._vbo_handle])
        if self._elements_handle > -1:
            gl.glDeleteBuffers(1, [self._elements_handle])
        self._vao_handle = self._vbo_handle = self._elements_handle = 0

        gl.glDeleteProgram(self._shader_handle)
        self._shader_handle = 0

        if self._font_texture > -1:
            gl.glDeleteTextures([self._font_texture])
        self.io.fonts.texture_id = 0
        self._font_texture = 0


class FixedPipelineRenderer(BaseOpenGLRenderer):
    """Basic OpenGL integration base class."""

    # note: no need to override __init__

    def refresh_font_texture(self):
        # save texture state
        # last_texture = gl.glGetIntegerv(gl.GL_TEXTURE_BINDING_2D)
        width, height, pixels = self.io.fonts.get_tex_data_as_alpha8()

        if self._font_texture is not None:
            gl.glDeleteTextures([self._font_texture])

        self._font_texture = gl.glGenTextures(1)
        gl.glBindTexture(gl.GL_TEXTURE_2D, self._font_texture)
        gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR)
        gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR)
        gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_ALPHA, width, height, 0, gl.GL_ALPHA, gl.GL_UNSIGNED_BYTE, pixels)

        self.io.fonts.texture_id = self._font_texture
        # gl.glBindTexture(gl.GL_TEXTURE_2D, last_texture)
        self.io.fonts.clear_tex_data()

    def _create_device_objects(self):
        pass

    def render(self, draw_data):
        # perf: local for faster access
        io = self.io

        display_width, display_height = self.io.display_size
        fb_width = int(display_width * io.display_fb_scale[0])
        fb_height = int(display_height * io.display_fb_scale[1])

        if fb_width == 0 or fb_height == 0:
            return

        draw_data.scale_clip_rects(*io.display_fb_scale)

        # note: we are using fixed pipeline for cocos2d/pyglet
        # todo: consider porting to programmable pipeline
        # backup gl state
        last_texture = gl.glGetIntegerv(gl.GL_TEXTURE_BINDING_2D)
        last_viewport = gl.glGetIntegerv(gl.GL_VIEWPORT)
        last_enable_blend = gl.glIsEnabled(gl.GL_BLEND)
        last_enable_cull_face = gl.glIsEnabled(gl.GL_CULL_FACE)
        last_enable_depth_test = gl.glIsEnabled(gl.GL_DEPTH_TEST)
        last_enable_scissor_test = gl.glIsEnabled(gl.GL_SCISSOR_TEST)
        last_scissor_box = gl.glGetIntegerv(gl.GL_SCISSOR_BOX)
        last_blend_src = gl.glGetIntegerv(gl.GL_BLEND_SRC)
        last_blend_dst = gl.glGetIntegerv(gl.GL_BLEND_DST)
        last_blend_equation_rgb = gl. glGetIntegerv(gl.GL_BLEND_EQUATION_RGB)
        last_blend_equation_alpha = gl.glGetIntegerv(gl.GL_BLEND_EQUATION_ALPHA)

        gl.glPushAttrib(gl.GL_ENABLE_BIT | gl.GL_COLOR_BUFFER_BIT | gl.GL_TRANSFORM_BIT)
        gl.glEnable(gl.GL_BLEND)
        gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
        gl.glDisable(gl.GL_CULL_FACE)
        gl.glDisable(gl.GL_DEPTH_TEST)
        gl.glEnable(gl.GL_SCISSOR_TEST)

        gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
        gl.glEnableClientState(gl.GL_TEXTURE_COORD_ARRAY)
        gl.glEnableClientState(gl.GL_COLOR_ARRAY)
        gl.glEnable(gl.GL_TEXTURE_2D)

        gl.glViewport(0, 0, int(fb_width), int(fb_height))
        gl.glMatrixMode(gl.GL_PROJECTION)
        gl.glPushMatrix()
        gl.glLoadIdentity()
        gl.glOrtho(0, io.display_size.x, io.display_size.y, 0.0, -1., 1.)
        gl.glMatrixMode(gl.GL_MODELVIEW)
        gl.glPushMatrix()
        gl.glLoadIdentity()

        for commands in draw_data.commands_lists:
            idx_buffer = commands.idx_buffer_data

            gl.glVertexPointer(2, gl.GL_FLOAT, imgui.VERTEX_SIZE, ctypes.c_void_p(commands.vtx_buffer_data + imgui.VERTEX_BUFFER_POS_OFFSET))
            gl.glTexCoordPointer(2, gl.GL_FLOAT, imgui.VERTEX_SIZE, ctypes.c_void_p(commands.vtx_buffer_data + imgui.VERTEX_BUFFER_UV_OFFSET))
            gl.glColorPointer(4, gl.GL_UNSIGNED_BYTE, imgui.VERTEX_SIZE, ctypes.c_void_p(commands.vtx_buffer_data + imgui.VERTEX_BUFFER_COL_OFFSET))

            for command in commands.commands:
                gl.glBindTexture(gl.GL_TEXTURE_2D, command.texture_id)

                x, y, w, z = command.clip_rect
                gl.glScissor(int(x), int(fb_height - w), int(z - x), int(w - y))

                if imgui.INDEX_SIZE == 2:
                    gltype = gl.GL_UNSIGNED_SHORT
                else:
                    gltype = gl.GL_UNSIGNED_INT

                gl.glDrawElements(gl.GL_TRIANGLES, command.elem_count, gltype, ctypes.c_void_p(idx_buffer))

                idx_buffer += (command.elem_count * imgui.INDEX_SIZE)

        gl.glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha)
        gl.glBlendFunc(last_blend_src, last_blend_dst)

        if last_enable_blend:
            gl.glEnable(gl.GL_BLEND)
        else:
            gl.glDisable(gl.GL_BLEND)

        if last_enable_cull_face:
            gl.glEnable(gl.GL_CULL_FACE)
        else:
            gl.glDisable(gl.GL_CULL_FACE)

        if last_enable_depth_test:
            gl.glEnable(gl.GL_DEPTH_TEST)
        else:
            gl.glDisable(gl.GL_DEPTH_TEST)

        if last_enable_scissor_test:
            gl.glEnable(gl.GL_SCISSOR_TEST)
        else:
            gl.glDisable(gl.GL_SCISSOR_TEST)

        gl.glScissor(last_scissor_box[0], last_scissor_box[1], last_scissor_box[2], last_scissor_box[3])

        gl.glDisableClientState(gl.GL_COLOR_ARRAY)
        gl.glDisableClientState(gl.GL_TEXTURE_COORD_ARRAY)
        gl.glDisableClientState(gl.GL_VERTEX_ARRAY)

        if last_texture:
            gl.glBindTexture(gl.GL_TEXTURE_2D, last_texture)

        gl.glMatrixMode(gl.GL_MODELVIEW)
        gl.glPopMatrix()
        gl.glMatrixMode(gl.GL_PROJECTION)
        gl.glPopMatrix()
        gl.glPopAttrib()

        gl.glViewport(last_viewport[0], last_viewport[1], last_viewport[2], last_viewport[3])

    def _invalidate_device_objects(self):
        if self._font_texture > -1:
            gl.glDeleteTextures([self._font_texture])
        self.io.fonts.texture_id = 0
        self._font_texture = 0

@mlviz
Copy link
Copy Markdown
Author

mlviz commented Jan 5, 2019

Here is the adjusted version of platform.py
(in my case located at C:\Anaconda3\Lib\site-packages\OpenGL\platform):

"""Base class for platform implementations
"""
import ctypes
from OpenGL.platform import ctypesloader
from OpenGL._bytes import as_8_bit
import sys
from OpenGL import _configflags
from OpenGL import logs, MODULE_ANNOTATIONS

class lazy_property( object ):
    def __init__( self, function ):
        self.fget = function 
    def __get__( self, obj, cls ):
        value = self.fget( obj )
        setattr( obj, self.fget.__name__, value)
        return value 

class _CheckContext( object ):
    def __init__( self, func, ccisvalid ):
        self.func = func 
        self.ccisvalid = ccisvalid
    def __setattr__( self, key, value ):
        if key not in ('func','ccisvalid'):
            return setattr( self.func, key, value )
        else:
            self.__dict__[key] = value 
    def __repr__( self ):
        if getattr( self.func, '__doc__', None ):
            return self.func.__doc__    
        else:
            return repr( self.func )
    def __getattr__( self, key ):
        if key != 'func':
            return getattr(self.func, key )
        raise AttributeError( key )
    def __call__( self, *args, **named ):
        if not self.ccisvalid():
            from OpenGL import error
            raise error.NoContext( self.func.__name__, args, named )
        return self.func( *args, **named )

def _find_module( exclude = (__name__,)):
    frame = sys._getframe()
    while frame and '__name__' in frame.f_globals:
        if exclude:
            if not frame.f_globals['__name__'] in exclude:
                return frame.f_globals['__name__']
            
        else:
            return frame.f_globals['__name__']
        frame = frame.f_back
    return None

class BasePlatform( object ):
    """Base class for per-platform implementations
    
    Attributes of note:
    
        EXPORTED_NAMES -- set of names exported via the platform 
            module's namespace...
    
        GL, GLU, GLUT, GLE, GLES1, GLES2, GLES3 -- ctypes libraries
    
        DEFAULT_FUNCTION_TYPE -- used as the default function 
            type for functions unless overridden on a per-DLL
            basis with a "FunctionType" member
        
        GLUT_GUARD_CALLBACKS -- if True, the GLUT wrappers 
            will provide guarding wrappers to prevent GLUT 
            errors with uninitialised GLUT.
        
        EXTENSIONS_USE_BASE_FUNCTIONS -- if True, uses regular
            dll attribute-based lookup to retrieve extension 
            function pointers.
    """
    
    EXPORTED_NAMES = [
        'GetCurrentContext','CurrentContextIsValid',
        'createBaseFunction', 'createExtensionFunction', 'copyBaseFunction',
        'getGLUTFontPointer','nullFunction',
        'GLUT_GUARD_CALLBACKS',
    ]

    
    DEFAULT_FUNCTION_TYPE = None
    GLUT_GUARD_CALLBACKS = False
    EXTENSIONS_USE_BASE_FUNCTIONS = False
    
    def install( self, namespace ):
        """Install this platform instance into the platform module"""
        for name in self.EXPORTED_NAMES:
            namespace[ name ] = getattr(self,name,None)
        namespace['PLATFORM'] = self
        return self
    
    def functionTypeFor( self, dll ):
        """Given a DLL, determine appropriate function type..."""
        if hasattr( dll, 'FunctionType' ):
            return dll.FunctionType
        else:
            return self.DEFAULT_FUNCTION_TYPE
    
    def errorChecking( self, func, dll, error_checker=None ):
        """Add error checking to the function if appropriate"""
        from OpenGL import error
        if error_checker and _configflags.ERROR_CHECKING:
            #GLUT spec says error-checking is basically undefined...
            # there *may* be GL errors on GLUT calls that e.g. render 
            # geometry, but that's all basically "maybe" stuff...
            func.errcheck = error_checker.glCheckError
        return func
    def wrapContextCheck( self, func, dll ):
        """Wrap function with context-checking if appropriate"""
        if _configflags.CONTEXT_CHECKING and dll is self.GL and func.__name__ not in (
            'glGetString',
            'glGetStringi',
            'glGetIntegerv',
        ) and not func.__name__.startswith( 'glX' ):
            return _CheckContext( func, self.CurrentContextIsValid )
        return func 
    def wrapLogging( self, func ):
        """Wrap function with logging operations if appropriate"""
        return logs.logOnFail( func, logs.getLog( 'OpenGL.errors' ))
    
    def finalArgType( self, typ ):
        """Retrieve a final type for arg-type"""
        if typ == ctypes.POINTER( None ) and not getattr( typ, 'final',False):
            from OpenGL.arrays import ArrayDatatype
            return ArrayDatatype
        else:
            return typ
    def constructFunction( 
        self,
        functionName, dll, 
        resultType=ctypes.c_int, argTypes=(),
        doc = None, argNames = (),
        extension = None,
        deprecated = False,
        module = None,
        force_extension = False,
        error_checker = None,
    ):
        """Core operation to create a new base ctypes function
        
        raises AttributeError if can't find the procedure...
        """
        is_core = (not extension) or extension.split('_')[1] == 'VERSION'
        if (not is_core) and not self.checkExtension( extension ):
            raise AttributeError( """Extension not available""" )
        argTypes = [ self.finalArgType( t ) for t in argTypes ]
            
        if force_extension or ((not is_core) and (not self.EXTENSIONS_USE_BASE_FUNCTIONS)):
            # what about the VERSION values???
            pointer = self.getExtensionProcedure( as_8_bit(functionName) )
            if pointer:
                func = self.functionTypeFor( dll )(
                    resultType,
                    *argTypes
                )(
                    pointer
                )
            else:
                raise AttributeError( """Extension %r available, but no pointer for function %r"""%(extension,functionName))
        else:
            func = ctypesloader.buildFunction(
                self.functionTypeFor( dll )(
                    resultType,
                    *argTypes
                ),
                functionName,
                dll,
            )
        func.__doc__ = doc 
        func.argNames = list(argNames or ())
        func.__name__ = functionName
        func.DLL = dll
        func.extension = extension
        func.deprecated = deprecated
        func = self.wrapLogging( 
            self.wrapContextCheck(
                self.errorChecking( func, dll, error_checker=error_checker ),
                dll,
            )
        )
        if MODULE_ANNOTATIONS:
            if not module:
                module = _find_module( )
            if module:
                func.__module__ = module
        return func

    def createBaseFunction( 
        self,
        functionName, dll, 
        resultType=ctypes.c_int, argTypes=(),
        doc = None, argNames = (),
        extension = None,
        deprecated = False,
        module = None,
        error_checker = None,
    ):
        """Create a base function for given name
        
        Normally you can just use the dll.name hook to get the object,
        but we want to be able to create different bindings for the 
        same function, so we do the work manually here to produce a
        base function from a DLL.
        """
        from OpenGL import wrapper
        result = None
        try:
            if (
                _configflags.FORWARD_COMPATIBLE_ONLY and 
                dll is self.GL and 
                deprecated
            ):
                result = self.nullFunction(
                    functionName, dll=dll,
                    resultType=resultType, 
                    argTypes=argTypes,
                    doc = doc, argNames = argNames,
                    extension = extension,
                    deprecated = deprecated,
                    error_checker = error_checker,
                )
            else:
                result = self.constructFunction(
                    functionName, dll, 
                    resultType=resultType, argTypes=argTypes,
                    doc = doc, argNames = argNames,
                    extension = extension,
                    error_checker = error_checker,
                )
        except AttributeError as err:
            result = self.nullFunction( 
                functionName, dll=dll,
                resultType=resultType, 
                argTypes=argTypes,
                doc = doc, argNames = argNames,
                extension = extension,
                error_checker = error_checker,
            )
        if MODULE_ANNOTATIONS:
            if not module:
                module = _find_module( )
            if module:
                result.__module__ = module
        return result
    def checkExtension( self, name ):
        """Check whether the given extension is supported by current context"""
#        if not name or name in ('GL_VERSION_GL_1_0', 'GL_VERSION_GL_1_1'):
#            return True
#        if name.startswith( 'EGL_' ) or name.startswith( 'GLX_' ) or name.startswith( 'WGL_' ):
#            # we can't check these extensions, have to rely on the function resolution
#            return True
        if not name:
            return True
        context = self.GetCurrentContext()
        if context:
            from OpenGL import contextdata
            set = contextdata.getValue( 'extensions', context=context )
            if set is None:
                set = {}
                contextdata.setValue( 
                    'extensions', set, context=context, weak=False 
                )
            current = set.get( name )
            if current is None:
                from OpenGL import extensions
                result = extensions.ExtensionQuerier.hasExtension( name )
                set[name] = result 
                return result
            return current
        else:
            from OpenGL import extensions
            return extensions.ExtensionQuerier.hasExtension( name )
    createExtensionFunction = createBaseFunction

    def copyBaseFunction( self, original ):
        """Create a new base function based on an already-created function
        
        This is normally used to provide type-specific convenience versions of
        a definition created by the automated generator.
        """
        from OpenGL import wrapper, error
        if isinstance( original, _NullFunctionPointer ):
            return self.nullFunction(
                original.__name__,
                original.DLL,
                resultType = original.restype,
                argTypes= original.argtypes,
                doc = original.__doc__,
                argNames = original.argNames,
                extension = original.extension,
                deprecated = original.deprecated,
                error_checker = original.error_checker,
            )
        elif hasattr( original, 'originalFunction' ):
            original = original.originalFunction
        return self.createBaseFunction(
            original.__name__, original.DLL, 
            resultType=original.restype, argTypes=original.argtypes,
            doc = original.__doc__, argNames = original.argNames,
            extension = original.extension,
            deprecated = original.deprecated,
            error_checker = original.errcheck,
        )
    def nullFunction( 
        self,
        functionName, dll,
        resultType=ctypes.c_int, 
        argTypes=(),
        doc = None, argNames = (),
        extension = None,
        deprecated = False,
        module = None,
        error_checker = None,
    ):
        """Construct a "null" function pointer"""
        if deprecated:
            base = _DeprecatedFunctionPointer
        else:
            base = _NullFunctionPointer
        cls = type( functionName, (base,), {
            '__doc__': doc,
            'deprecated': deprecated,
        } )
        if MODULE_ANNOTATIONS:
            if not module:
                module = _find_module( )
            if module:
                cls.__module__ = module
        return cls(
            functionName, dll, resultType, argTypes, argNames, extension=extension, doc=doc,
            error_checker = error_checker,
        )
    def GetCurrentContext( self ):
        """Retrieve opaque pointer for the current context"""
        raise NotImplementedError( 
            """Platform does not define a GetCurrentContext function""" 
        )
    def getGLUTFontPointer(self, constant ):
        """Retrieve a GLUT font pointer for this platform"""
        raise NotImplementedError( 
            """Platform does not define a GLUT font retrieval function""" 
        )
    # names that are normally just references to other items...
    @lazy_property
    def CurrentContextIsValid( self ):
        return self.GetCurrentContext
    @lazy_property
    def OpenGL(self): return self.GL

class _NullFunctionPointer( object ):
    """Function-pointer-like object for undefined functions"""
    def __init__( 
        self, name, dll, resultType, argTypes, argNames, 
        extension=None, doc=None, deprecated=False,
        error_checker = None,
    ):
        from OpenGL import error
        self.__name__ = name
        self.DLL = dll
        self.argNames = argNames
        self.argtypes = argTypes
        self.errcheck = None
        self.restype = resultType
        self.extension = extension
        self.doc = doc
        self.deprecated = deprecated
        self.error_checker = error_checker
    resolved = False
    def __nonzero__( self ):
        """Make this object appear to be NULL"""
        if self.extension and not self.resolved:
            self.load()
        return self.resolved
    __bool__ = __nonzero__
    def load( self ):
        """Attempt to load the function again, presumably with a context this time"""
        from OpenGL import platform
        try:
            func = platform.PLATFORM.constructFunction(
                self.__name__, self.DLL, 
                resultType=self.restype, 
                argTypes=self.argtypes,
                doc = self.doc, 
                argNames = self.argNames,
                extension = self.extension,
                error_checker = self.error_checker,
            )
        except AttributeError as err:
            return None 
        else:
            # now short-circuit so that we don't need to check again...
            self.__class__.__call__ = staticmethod( func.__call__ )
            self.resolved = True
            return func
        return None
    def __call__( self, *args, **named ):
        if self.load():
            return self( *args, **named )
        else:
            from OpenGL import error
            raise error.NullFunctionError(
                """Attempt to call an undefined function %s, check for bool(%s) before calling"""%(
                    self.__name__, self.__name__,
                )
            )

class _DeprecatedFunctionPointer( _NullFunctionPointer ):
    deprecated = True
    def __call__( self, *args, **named ):
        from OpenGL import error
        raise error.NullFunctionError(
            """Attempt to call a deprecated function %s while OpenGL in FORWARD_COMPATIBLE_ONLY mode.  Set OpenGL.FORWARD_COMPATIBLE_ONLY to False to use legacy entry points"""%(
                self.__name__,
            )
        )

@dan90210
Copy link
Copy Markdown

dan90210 commented Jan 6, 2019

Is this viable if we are having to make edits to external libraries? @mlviz

@dan90210
Copy link
Copy Markdown

dan90210 commented Jan 6, 2019

After updating to Python 3.7.2 I have new output.

~ » python3 test.py                                                                 dan@ryzen
[w] Backend (<module 'glumpy.app.window.backends.backend_pyimgui' from '/usr/local/lib/python3.7/site-packages/glumpy-1.0.6-py3.7-linux-x86_64.egg/glumpy/app/window/backends/backend_pyimgui.py'>) not available
[w] Cannot read STENCIL size from the framebuffer
[i] Using GLFW (GL 3.0)
[i] Requesting "OpenSans-Regular.ttf" from remote server
[i] Fetching data (217360 bytes) to "/usr/local/lib/python3.7/site-packages/glumpy-1.0.6-py3.7-linux-x86_64.egg/glumpy/data/OpenSans-Regular.ttf"
Traceback (most recent call last):
  File "test.py", line 77, in <module>
    regular = FontManager.get("OpenSans-Regular.ttf")
  File "/usr/local/lib/python3.7/site-packages/glumpy-1.0.6-py3.7-linux-x86_64.egg/glumpy/graphics/text/font_manager.py", line 50, in get
    filename = data.get(filename)
  File "/usr/local/lib/python3.7/site-packages/glumpy-1.0.6-py3.7-linux-x86_64.egg/glumpy/data/__init__.py", line 166, in get
    filename = _fetch_file(name)
  File "/usr/local/lib/python3.7/site-packages/glumpy-1.0.6-py3.7-linux-x86_64.egg/glumpy/data/__init__.py", line 64, in _fetch_file
    with open(local_file, 'wb') as fp:
PermissionError: [Errno 13] Permission denied: '/usr/local/lib/python3.7/site-packages/glumpy-1.0.6-py3.7-linux-x86_64.egg/glumpy/data/OpenSans-Regular.ttf'

A window appears, but is blank and then crashes.

But when I run sudo python3 test.py I get this:

[w] Backend (<module 'glumpy.app.window.backends.backend_pyimgui' from '/usr/local/lib/python3.7/site-packages/glumpy-1.0.6-py3.7-linux-x86_64.egg/glumpy/app/window/backends/backend_pyimgui.py'>) not available
No protocol specified
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[w] b'The GLFW library is not initialized'
[x] Window creation failed

@mlviz
Copy link
Copy Markdown
Author

mlviz commented Jan 6, 2019

Is this viable if we are having to make edits to external libraries? @mlviz

This is a very good question, I am not familiar with what is the best procedure in such case.
@rougier What would you suggest?

@dan90210 Do you have a fully functional version of pyimgui with the GLFW backend?
https://github.com/swistakm/pyimgui/blob/master/doc/examples/glfw3.py must be working on your computer before trying anything else with glumpy. The reason is that the pyimgui glfw context is the one used by the new backend, so you must make sure that this work first.

@dan90210
Copy link
Copy Markdown

dan90210 commented Jan 7, 2019

After installing the necessary dependencies I was able to run the glfw3.py example you linked above. After trying that I ran both pyimgui examples that you included and both gave me the same output.

[w] b'GLX: Failed to create context: GLXBadFBConfig'
[x] Window creation failed

This is on Ubuntu with Python 3.7.2

@mlviz
Copy link
Copy Markdown
Author

mlviz commented Jan 8, 2019

@dan90210 You have made good progress. We now must validate that your graphic cards and opengl version supports the required features.

In the file glumpy/app/window/backends/backend_pyimgui.py at lines 149+ we have:

def set_configuration(configuration):
    """ Set GL initialization here (depth buffer size, etc.) """
    glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3)
    glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 2)
    # the OPENGL_COMPAT_PROFILE enables the mix between pyimgui and glumpy
    glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_COMPAT_PROFILE)
    glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, gl.GL_TRUE)

This means that you drivers, and graphic card, that support opengl 3.2 or better, and that your graphic card must also support OPENGL_COMPAT_PROFILE extension.

@rougier A possible way to avoid the requirement for OPENGL_COMPAT_PROFILE would be to integrate imgui (https://github.com/ocornut/imgui) into the glumpy GLFW backend, or even better, for all backends. Immediate mode GUI (like imgui) are very good for tools since they let the code mix more freely with the UI (Unity3D game engine editor is based on an immediate mode GUI interface) and are much lighter than using full GUI framework like Qt. Having all glumpy examples with interactive sliders by requiring just a few lines of extra code in each one of them would be great. The code of examples/pyimgui/gui-quad-rotation.py gives an example of the potential.

A quick webgl in-browser example of imgui in action is available here: https://pbrfrat.com/post/imgui_in_browser.html

@dan90210
Copy link
Copy Markdown

dan90210 commented Jan 8, 2019

New output after updating my graphics card drivers to their latest version.

Xlib:  extension "AMDGPU" missing on display ":0".
Xlib:  extension "AMDGPU" missing on display ":0".
[i] Using pyimgui (GL 3.2)
[i] Running at 60 frames/second
Traceback (most recent call last):
  File "/home/dan/.local/lib/python3.7/site-packages/OpenGL/latebind.py", line 41, in __call__
    return self._finalCall( *args, **named )
TypeError: 'NoneType' object is not callable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "imgui/core.pyx", line 966, in imgui.core._IO._io_render_callback
  File "/home/dan/.local/lib/python3.7/site-packages/imgui/integrations/opengl.py", line 215, in render
    gl.glUniformMatrix4fv(self._attrib_proj_mtx, 1, gl.GL_FALSE, ortho_projection)
  File "/home/dan/.local/lib/python3.7/site-packages/OpenGL/latebind.py", line 45, in __call__
    return self._finalCall( *args, **named )
  File "/home/dan/.local/lib/python3.7/site-packages/OpenGL/wrapper.py", line 1374, in wrapperCall
    raise err
  File "/home/dan/.local/lib/python3.7/site-packages/OpenGL/wrapper.py", line 1371, in wrapperCall
    result = wrappedOperation( *cArguments )
  File "/home/dan/.local/lib/python3.7/site-packages/OpenGL/platform/baseplatform.py", line 402, in __call__
    return self( *args, **named )
ctypes.ArgumentError: ("argument 4: <class 'OpenGL.error.CopyError'>: list passed, cannot copy with ERROR_ON_COPY set, please use an array type which has native data-pointer support (e.g. numpy or ctypes arrays)", (0, 1, GL_FALSE, [[0.001953125, 0.0, 0.0, 0.0], [0.0, -0.0026041666666666665, 0.0, 0.0], [0.0, 0.0, -1.0, 0.0], [-1.0, 1.0, 0.0, 1.0]]))

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "gui-quad-rotation.py", line 83, in <module>
    app.run()
  File "/usr/local/lib/python3.7/site-packages/glumpy-1.0.6-py3.7-linux-x86_64.egg/glumpy/app/__init__.py", line 362, in run
    run(duration, framecount)
  File "/usr/local/lib/python3.7/site-packages/glumpy-1.0.6-py3.7-linux-x86_64.egg/glumpy/app/__init__.py", line 344, in run
    count = __backend__.process(dt)
  File "/usr/local/lib/python3.7/site-packages/glumpy-1.0.6-py3.7-linux-x86_64.egg/glumpy/app/window/backends/backend_pyimgui.py", line 398, in process
    window.render_gui()
  File "/usr/local/lib/python3.7/site-packages/glumpy-1.0.6-py3.7-linux-x86_64.egg/glumpy/app/window/backends/backend_pyimgui.py", line 365, in render_gui
    imgui.render()
SystemError: <built-in function render> returned a result with an error set

Looks like this may be the same problem you encountered @mlviz and ended up having to modify the OpenGL files?

EDIT: I forgot to mention that the window does open right away, but it closes immediately. I can see the cube that you showed several posts earlier.

@mlviz
Copy link
Copy Markdown
Author

mlviz commented Jan 9, 2019

Looks like this may be the same problem you encountered @mlviz and ended up having to modify the OpenGL files?

  File "/home/dan/.local/lib/python3.7/site-packages/imgui/integrations/opengl.py", line 215, in render
    gl.glUniformMatrix4fv(self._attrib_proj_mtx, 1, gl.GL_FALSE, ortho_projection)

AND

  File "/home/dan/.local/lib/python3.7/site-packages/OpenGL/platform/baseplatform.py", line 402, in __call__
    return self( *args, **named )

This seem to be the exact same problem I had. In previous posts I gave my full listing for each of these 2 files, please look at them and make the appropriate changes in your files. (other errors are just cascading errors from the 2 above).

Once these are corrected, I think it should work.

@rougier
Copy link
Copy Markdown
Member

rougier commented Jan 17, 2019

@mlviz I agree that imgui is really a great tool but reading this thread I'm not sure about the best way to integrate the imgui in one (glfw) or all backend. And in any case, we need to modify the external PyOpenGL if I read correctly (I did not have time to re-test it myself).

@rougier
Copy link
Copy Markdown
Member

rougier commented Jan 17, 2019

After installing it I got:

[w] b'NSGL: The targeted version of OS X only supports core profile contexts for OpenGL 3.2 and above'
[x] Window creation failed

@mlviz
Copy link
Copy Markdown
Author

mlviz commented Jan 20, 2019

@rougier A lot of the problem comes from using OPENGL_COMPAT_PROFILE (also I think it is not fully supported on osx) because we are using two distinct OpenGL context. The best way to do it would be to fully integrate PyImgui inside Glumpy so that there is only one OpenGL context or use Cython to integrate Dear Imgui like they did for PyImgui. Doing that would remove all the installation problems (no more OPENGL_COMPAT_PROFILE problem and you fully control how OpenGL is used in a single context, also, you don't have to juggle with 2 distinct event system like I had to). But that is a lot more than simply writing a backend like I did, it requires to perfectly know Glumpy for such a task. After having the chance to play around with such an integration, I can say that the quick UI interaction brings glumpy to a completely other level. It would be great if you can access a Windows PC with a decent graphic card to see what I mean.

@rougier
Copy link
Copy Markdown
Member

rougier commented Jan 21, 2019

From GLFW documentarion the way to activate forward compatibility is:

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

I managed to activate it on OSX but then I got problem with the #version 120 in the shaders and the use of attributte. Is compatibility profile suppose to fix that ? (indicating it does not work on OSX). Also, I do not quite understand why the forward profile is needed. This to use both 2.2 and 3.3 profiles ?

@mlviz
Copy link
Copy Markdown
Author

mlviz commented Jan 26, 2019

Hi, I am not sure that this is the same as:

    glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_COMPAT_PROFILE)
    glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, gl.GL_TRUE)

GLFW_OPENGL_CORE_PROFILE not being the same as OPENGL_COMPAT_PROFILE.

I was only able to make the demo work on Windows.

Base on https://stackoverflow.com/questions/46737002/unable-to-use-opengl-3-2-on-osx-pyopengl, maybe you need to use OPENGL_COMPATIBILITY_PROFILE instead of OPENGL_COMPAT_PROFILE on osx.

@rougier
Copy link
Copy Markdown
Member

rougier commented Apr 22, 2019

Anybody managed to make this works on OSX?

@dan90210
Copy link
Copy Markdown

I have not, mainly because I do not want to mess with external libraries.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants