Page MenuHome

Update bgl docs
ClosedPublic

Authored by Jacques Lucke (JacquesLucke) on Jan 29 2019, 5:49 PM.

Details

Summary

The current bgl are outdated.
Instead of going through all functions and updating them, I just linked every function to the official documentation (as discussed in T60891).

The bgl docs should focus on how to use the normal OpenGL functions in Blender.
This can be achieved by providing some more examples.
However, I'd like to keep that separate from this patch.

The script to find all links:

import re
import bpy
import bgl
import requests
from pprint import pprint

def get_function_names_in_bgl():
    def gl_filter(name):
        return name.startswith("gl")
    return list(filter(gl_filter, dir(bgl)))

def get_function_links():
    link_prefix = "https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/"
    flat_index_html = requests.get(link_prefix + "indexflat.php").text

    links = {}

    for line in flat_index_html.splitlines():
        line = line.strip()
        match = re.match(r"<li><a href=\"(.*)\" target=\"pagedisplay\">(\w+)<", line)
        if match is None:
            continue

        file_name = match.group(1)
        function_name = match.group(2)
        links[function_name] = link_prefix + file_name

    return links


output_parts = []

function_links = get_function_links()
for function_name in sorted(get_function_names_in_bgl()):
    link = function_links[function_name]
    output_parts.append(f"- `{function_name} <{link}>`__")

output = "\n".join(output_parts)
print(output)

bpy.context.window_manager.clipboard = output

I put all functions in a list to reduce the line spacing.
That makes it much easier to scan through the list.

Diff Detail

Repository
rB Blender

Event Timeline

While I'm all for reducing redundant information.
The issue with referencing external docs is the blender/python wrapper isn't *just* calling out to OpenGL,
There are enough cases where it handles arguments in a Blender specific way (bgl.Buffer mainly)

I think if we keep the API, we should keep the docs (and update them eventually),
or we can remove deprecated API's from both docs and bgl module.

Otherwise users are forced to lookup the source code to see how arguments are passed.

I think it would be nice if we could just provide a general signature translation rule from normal opengl to bgl. (pointers -> buffer)

Other exceptions can be mentioned on the page, I just don't know them all yet.
This is a wrapper, so we should use the docs to explain the wrapper and not the wrapped functionality (which has much better explanations already).

Agree on external links for more detailed docs.

I was thinking we could generate signatures from BGL_Wrap macro, however the issue with this is that it doesn't say what kind of buffer, which is useful in the existing docs.

If we wanted we could add some way to hint the type, but this becomes a hassle to maintain.

Since we only need to remove deprecated functions and the API doesn't change often, it could be simplest to write a basic validator (reports mismatch between docs and BGL module), then update occasionally.

Stripping down docstrings can be handled separately.

I could write a simple Python program that reads in bgl.c, finds all lines that start with BGL_Wrap and creates the .rst file with signatures.
Looks like these lines contain all the necessary information, no? E.g. GLuintP is just mapped to bgl.Buffer of bgl.GL_INT.
At the same time this script also finds all the links to the official documentation.

  • bgl docs from BLG_Wrap

I just wanted to try this, I know it looks ugly and lots of information is missing...
Will write the simple validator script next.

import re
import requests
from dataclasses import dataclass

@dataclass
class BglWrapper:
    name: str
    return_type: str
    argument_types: list

type_mapping = {
    "GLenum" : "Enumerated Constant",
    "GLbitfield" : "Enumerated Constant(s)",
    "GLfloat" : "float",
    "GLdouble" : "double",
    "GLint" : "int",
    "GLboolean" : "int (boolean)",
    "GLbooleanP" : "Boolean Buffer",
    "GLdoubleP" : "Double Buffer",
    "GLfloatP" : "Float Buffer",
    "GLintP" : "Int Buffer",
    "GLuintP" : "Unsigned Int Buffer",
    "GLsizei" : "int",
    "GLsizeiptr" : "...",
    "GLbyteP" : "Byte Buffer",
    "GLshort" : "int",
    "GLshortP" : "Short Buffer",
    "GLubyte" : "int",
    "GLubyteP" : "Unsigned Byte Buffer",
    "GLushortP" : "Unsigned Short Buffer",
    "GLuint" : "int",
    "GLstring" : "str",
    "GLintptr" : "Int Buffer",
    "GLvoidP" : "Buffer",
    "GLenumP" : "Enum P",
    "GLsizeiP" : "Sizei Buffer",
    "GLcharP" : "Char Buffer",
    "GLint64P" : "Int64 Buffer",
}

def iter_bgl_wrappers():
    for line in iter_bgl_wrap_lines():
        match = re.match(r"BGL_Wrap\((\w+),\s*(\w+),\s*\(([\w,\s]+)\)\);", line)
        wrapper = BglWrapper(
            name="gl" + match.group(1),
            return_type=match.group(2),
            argument_types=match.group(3).replace(" ", "").split(","))
        if wrapper.argument_types == ["void"]:
            wrapper.argument_types = []
        yield wrapper

def iter_bgl_wrap_lines():
    bgl_path = "/home/jacques/blender-git/blender/source/blender/python/generic/bgl.c"

    with open(bgl_path) as fs:
        bgl_file_content = fs.read()

    for line in bgl_file_content.splitlines():
        if line.startswith("BGL_Wrap"):
            yield line

def get_function_links():
    link_prefix = "https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/"
    flat_index_html = requests.get(link_prefix + "indexflat.php").text

    links = {}

    for line in flat_index_html.splitlines():
        line = line.strip()
        match = re.match(r"<li><a href=\"(.*)\" target=\"pagedisplay\">(\w+)<", line)
        if match is None:
            continue

        file_name = match.group(1)
        function_name = match.group(2)
        links[function_name] = link_prefix + file_name

    return links

def iter_documentation_lines():
    function_links = get_function_links()
    for wrapper in sorted(iter_bgl_wrappers(), key=lambda x: x.name):
        arguments = wrapper.argument_types
        if len(arguments) > 0:
            yield f".. function:: {wrapper.name}(...):"
        else:
            yield f".. function:: {wrapper.name}():"

        yield ""
        yield f"   `{wrapper.name} <{function_links[wrapper.name]}>`__"
        yield ""
        for i, argument in enumerate(arguments, 1):
            yield f"   :arg {i}: "
            yield f"   :type {i}: {type_mapping[argument]}"
        if wrapper.return_type != "void":
            yield f"   :rtype: {wrapper.return_type}"
        yield ""

documentation = "\n".join(iter_documentation_lines())

print(documentation)

The arguments no longer have names, assume this is what you mean by lots of information is missing... - if it can be extended to be about as good as what we have, dont see why not use it.

Then again, we could just remove redundant information and hand maintain (perhaps with validator that lets us know when there is a mis-match) it since OpenGL isn't changing that often, our BGL module less often.

import bgl
import re
from pprint import pprint

path = "/home/jacques/blender-git/blender/doc/python_api/rst/bgl.rst"
with open(path) as fs:
    docs = fs.read()

functions_in_docs = set()
for line in docs.splitlines():
    match = re.search(r"function\:\: (\w+)\(", line)
    if match is None:
        continue

    functions_in_docs.add(match.group(1))

functions_in_bgl = set()
for name in dir(bgl):
    if name.startswith("gl"):
        functions_in_bgl.add(name)


missing_in_docs = functions_in_bgl.difference(functions_in_docs)
to_be_removed_from_docs = functions_in_docs.difference(functions_in_bgl)

print("Missing in Docs")
pprint(missing_in_docs)
print("\n\nHas to be removed from docs")
pprint(to_be_removed_from_docs)
Missing in Docs
{'glBeginQuery',
 'glBindAttribLocation',
 'glBindBuffer',
 'glBindBufferBase',
 'glBindBufferRange',
 'glBindFramebuffer',
 'glBindRenderbuffer',
 'glBindVertexArray',
 'glBlendColor',
 'glBlendEquation',
 'glBlendEquationSeparate',
 'glBlitFramebuffer',
 'glBufferData',
 'glBufferSubData',
 'glCheckFramebufferStatus',
 'glCompressedTexImage1D',
 'glCompressedTexImage2D',
 'glCompressedTexImage3D',
 'glCompressedTexSubImage1D',
 'glCompressedTexSubImage2D',
 'glCompressedTexSubImage3D',
 'glCopyTexImage1D',
 'glCopyTexImage2D',
 'glCopyTexSubImage1D',
 'glCopyTexSubImage2D',
 'glCopyTexSubImage3D',
 'glDeleteBuffers',
 'glDeleteFramebuffers',
 'glDeleteQueries',
 'glDeleteRenderbuffers',
 'glDeleteVertexArrays',
 'glDisableVertexAttribArray',
 'glDrawArrays',
 'glDrawBuffers',
 'glDrawElements',
 'glDrawRangeElements',
 'glEnableVertexAttribArray',
 'glEndQuery',
 'glFramebufferRenderbuffer',
 'glFramebufferTexture',
 'glGenBuffers',
 'glGenFramebuffers',
 'glGenQueries',
 'glGenRenderbuffers',
 'glGenVertexArrays',
 'glGetActiveAttrib',
 'glGetActiveUniform',
 'glGetActiveUniformBlockName',
 'glGetActiveUniformBlockiv',
 'glGetActiveUniformName',
 'glGetActiveUniformsiv',
 'glGetAttribLocation',
 'glGetBooleanv',
 'glGetBufferParameteri64v',
 'glGetBufferParameteriv',
 'glGetBufferPointerv',
 'glGetBufferSubData',
 'glGetCompressedTexImage',
 'glGetDoublev',
 'glGetFloatv',
 'glGetInteger64i_v',
 'glGetIntegeri_v',
 'glGetIntegerv',
 'glGetMultisamplefv',
 'glGetQueryObjectiv',
 'glGetQueryObjectuiv',
 'glGetQueryiv',
 'glGetShaderiv',
 'glGetStringi',
 'glGetTexLevelParameterfv',
 'glGetTexLevelParameteriv',
 'glGetTexParameterfv',
 'glGetTexParameteriv',
 'glGetUniformBlockIndex',
 'glGetUniformIndices',
 'glGetUniformLocation',
 'glGetUniformfv',
 'glGetUniformiv',
 'glGetVertexAttribPointerv',
 'glGetVertexAttribdv',
 'glGetVertexAttribfv',
 'glGetVertexAttribiv',
 'glIsBuffer',
 'glIsQuery',
 'glIsVertexArray',
 'glMapBuffer',
 'glPixelStoref',
 'glPixelStorei',
 'glRenderbufferStorage',
 'glSampleCoverage',
 'glSampleMaski',
 'glStencilFuncSeparate',
 'glStencilMaskSeparate',
 'glStencilOpSeparate',
 'glTexImage2DMultisample',
 'glTexImage3D',
 'glTexImage3DMultisample',
 'glTexParameterf',
 'glTexParameterfv',
 'glTexParameteri',
 'glTexParameteriv',
 'glTexSubImage1D',
 'glTexSubImage2D',
 'glTexSubImage3D',
 'glUniform1f',
 'glUniform1fv',
 'glUniform1i',
 'glUniform1iv',
 'glUniform2f',
 'glUniform2fv',
 'glUniform2i',
 'glUniform2iv',
 'glUniform3f',
 'glUniform3fv',
 'glUniform3i',
 'glUniform3iv',
 'glUniform4f',
 'glUniform4fv',
 'glUniform4i',
 'glUniform4iv',
 'glUniformBlockBinding',
 'glUniformMatrix2fv',
 'glUniformMatrix2x3fv',
 'glUniformMatrix2x4fv',
 'glUniformMatrix3fv',
 'glUniformMatrix3x2fv',
 'glUniformMatrix3x4fv',
 'glUniformMatrix4fv',
 'glUniformMatrix4x2fv',
 'glUniformMatrix4x3fv',
 'glUnmapBuffer',
 'glVertexAttrib1d',
 'glVertexAttrib1dv',
 'glVertexAttrib1f',
 'glVertexAttrib1fv',
 'glVertexAttrib1s',
 'glVertexAttrib1sv',
 'glVertexAttrib2d',
 'glVertexAttrib2dv',
 'glVertexAttrib2f',
 'glVertexAttrib2fv',
 'glVertexAttrib2s',
 'glVertexAttrib2sv',
 'glVertexAttrib3d',
 'glVertexAttrib3dv',
 'glVertexAttrib3f',
 'glVertexAttrib3fv',
 'glVertexAttrib3s',
 'glVertexAttrib3sv',
 'glVertexAttrib4Nbv',
 'glVertexAttrib4Niv',
 'glVertexAttrib4Nsv',
 'glVertexAttrib4Nub',
 'glVertexAttrib4Nubv',
 'glVertexAttrib4Nuiv',
 'glVertexAttrib4Nusv',
 'glVertexAttrib4bv',
 'glVertexAttrib4d',
 'glVertexAttrib4dv',
 'glVertexAttrib4f',
 'glVertexAttrib4fv',
 'glVertexAttrib4iv',
 'glVertexAttrib4s',
 'glVertexAttrib4sv',
 'glVertexAttrib4ubv',
 'glVertexAttrib4uiv',
 'glVertexAttrib4usv',
 'glVertexAttribPointer'}


Has to be removed from docs
{'glAccum',
 'glAlphaFunc',
 'glAreTexturesResident',
 'glBegin',
 'glBitmap',
 'glCallList',
 'glCallLists',
 'glClearAccum',
 'glClearIndex',
 'glColorMaterial',
 'glCopyPixels',
 'glDeleteLists',
 'glDrawPixels',
 'glEnd',
 'glEndList',
 'glFrustum',
 'glGenLists',
 'glGetClipPlane',
 'glGetPolygonStipple',
 'glIndex',
 'glIndexMask',
 'glInitNames',
 'glIsList',
 'glLineStipple',
 'glListBase',
 'glLoadIdentity',
 'glLoadName',
 'glMatrixMode',
 'glNewList',
 'glOrtho',
 'glPassThrough',
 'glPixelZoom',
 'glPolygonStipple',
 'glPopAttrib',
 'glPopClientAttrib',
 'glPopMatrix',
 'glPopName',
 'glPrioritizeTextures',
 'glPushAttrib',
 'glPushClientAttrib',
 'glPushMatrix',
 'glPushName',
 'glRenderMode',
 'glSelectBuffer',
 'glShadeModel',
 'gluLookAt',
 'gluOrtho2D',
 'gluPerspective',
 'gluPickMatrix',
 'gluProject',
 'gluUnProject'}
  • remove functions that have been removed from docs

@Brecht Van Lommel (brecht), can I commit this, so that at least the removed functions are not in the api documentation anymore?

This revision was not accepted when it landed; it landed in state Needs Review.
This revision was automatically updated to reflect the committed changes.