3
$\begingroup$

UPDATE

Here another example in order to clarify this question, I did a video in order to resume the problem https://www.youtube.com/watch?v=yShhJOzkJBk:

here the addon working without the BGL CODE.... as you see the properties are working too:

addon working without BGL

but if I allow the BGL code many strange things happen:

  • properties unavailable
  • the mesh deforms uncontrollably
  • in some cases blender crash

with BGL

what I'm doing wrong?

here the full code of this test:

'''
BEGIN GPL LICENSE BLOCK

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.    See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

END GPL LICENCE BLOCK
'''

bl_info = {  
 "name": "Test bgl + joinmeshr",  
 "author": "Diego Quevedo ( http://doshape.com/ )",  
 "version": (1, 0),  
 "blender": (2, 7 , 3),  
 "location": "View3D > EditMode > ToolShelf",  
 "description": "Testing bgl",  
 "warning": "",  
 "wiki_url": "",  
 "tracker_url": "",  
 "category": "Mesh"} 

import bpy
import bmesh
import mathutils
import math
from bpy_extras import view3d_utils
import time
import sys
import bgl
import blf

def draw_callback_px(self, context):

        oa = bpy.context.active_object
        obj = bpy.context.object
        me = obj.data
        bm = bmesh.from_edit_mesh(me)

        for area in bpy.context.screen.areas:
            if area.type == 'VIEW_3D':
                override = bpy.context.copy()
                viewport = area.regions[4]
                v_m = area.spaces[0].region_3d.view_matrix  #orientation matrix

                vertices= [v for v in bm.verts if (v.select == True and v.hide == False)]


                vn1 = vertices[0]

                vn2 = bm.verts.new(vn1.co)

                vn3 = bm.verts.new(vn1.co)

                 #vector conversion from view space to world space


                vn1.select = False
                vn2.select = True
                vn3.select = False
                bm.select_history.active
                values = mathutils.Vector((1,0,0))*v_m

                #the translation is done in global orientation without any constraints
                bpy.ops.transform.translate(value=values)


                #bpy.context.object.location += values   #another way to translate

                vn1.select = False
                vn2.select = False
                vn3.select = True
                bm.select_history.active
                values = mathutils.Vector((0,1,0))*v_m

                bpy.ops.transform.translate(value=values)
                vn3.select=False
                vn1.select = True
                bm.select_history.active
                vn2.select = True
                vn3.select = True


                font_id = 0  # XXX, need to find out how best to get this.

                # draw some text
                #blf.position(font_id, 0, 0, 0)
                #blf.size(font_id, 20, 72)
                #blf.draw(font_id, oa.name)

                # 50% alpha, 2 pixel width line
                bgl.glEnable(bgl.GL_BLEND)
                bgl.glColor4f(1.0, 1.0, 1.0, 0.5)
                bgl.glLineWidth(2)

                bgl.glBegin(bgl.GL_LINE_STRIP)
                bgl.glVertex3f(*vn1.co)
                bgl.glVertex3f(*vn2.co)

                bgl.glBegin(bgl.GL_LINE_STRIP)
                bgl.glVertex3f(*vn1.co)
                bgl.glVertex3f(*vn3.co)
                #bgl.glVertex3f(*ob.matrix_world.translation)
                #bgl.glVertex3f(*context.scene.cursor_location)
                bgl.glEnd()

                # restore opengl defaults
                bgl.glLineWidth(1)
                bgl.glDisable(bgl.GL_BLEND)
                bgl.glColor4f(0.0, 0.0, 0.0, 1.0)

                #SEND TO CUT
                #calcularangulos1(v1, v3, v2,angle)

                listabasuravertices0= [vn2,vn3]
                bmesh.ops.delete(bm, geom= listabasuravertices0, context=1)
        bmesh.update_edit_mesh(me, True)




################################################################################
######  testbgl##########################################  
################################################################################ 

class testbglOperator(bpy.types.Operator):
    "testbgl"
    bl_idname = 'mesh.testbgl'
    bl_label = 'testbgl'
    bl_description  = "test bgl"
    bl_options = {'REGISTER', 'UNDO'}




    chboxjoin0 = bpy.props.BoolProperty(
        name="Join",
        default= True
    )
    chboxVert1 = bpy.props.BoolProperty(
        name="Select",
        default= True
    )


    def main(self, context, chboxjoin0, chboxVert1):

        #almacena caras

        obj = bpy.context.object
        me = obj.data
        bm = bmesh.from_edit_mesh(me)

        v1, v2= [v for v in bm.verts if (v.select == True and v.hide == False)]

        if chboxjoin0:
            bpy.ops.mesh.vert_connect_path()

        if chboxVert1:
            v1.select = True
            v2.select= True
        else:
            v1.select = False
            v2.select= False

        bmesh.update_edit_mesh(me, True)





    @classmethod

    def poll(self, context):
        obj = context.active_object
        return all([obj is not None, obj.type == 'MESH', obj.mode == 'EDIT'])
    '''
    def execute(self, context):

        self.main(context, self.chboxjoin0, self.chboxVert1)

        #bisectoroperator(self)
        return {'FINISHED'}
    '''   
    def modal(self, context, event):
        context.area.tag_redraw()

        if event.type in {'RIGHTMOUSE', 'ESC'}:
            bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
            return {'CANCELLED'}


        return {'PASS_THROUGH'}

    def invoke(self, context, event):
        #self.main(context, self.chboxjoin0, self.chboxVert1)

        if context.area.type == 'VIEW_3D':
            # the arguments we pass the the callback
            args = (self, context)
            # Add the region OpenGL drawing callback
            # draw in view space with 'POST_VIEW' and 'PRE_VIEW'

            self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_VIEW')


            self.mouse_path = []

            context.window_manager.modal_handler_add(self)
            self.main(context, self.chboxjoin0, self.chboxVert1)
            return {'RUNNING_MODAL'}
        else:
            self.report({'WARNING'}, "View3D not found, cannot run operator")
            return {'CANCELLED'}

class TestbglOperatorPanel(bpy.types.Panel):
    #bl_category = "Bisector"
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"

    #bl_context = "editmode"
    bl_label = " Test bgl"
    @classmethod
    def poll(cls, context):
        return (context.mode == 'EDIT_MESH')

    def draw(self, context):
        layout = self.layout

        row = layout.row(align=True)
        row.operator(testbglOperator.bl_idname) #testbgl




def register():
    bpy.utils.register_module(__name__)

def unregister():
    bpy.utils.unregister_module(__name__)


if __name__ == "__main__":
    register() 

---------------------------

*I'm making some bgl test, but I have for example this problem: In this case I have the template operator_modal_draw and I want to add some int property in order to change the line width... something like: width = bpy.props.IntProperty(
name="line width",
default=10,
description="", min=2 ) what I want I did a lot of test but I don't have any good result do you have some ideas?

$\endgroup$
5
  • $\begingroup$ it might help to describe the goal of your experiment, as it stands the template for operator modal draw code won't let you interact with the UI anyway so you wouldn't be able to drag a slider if it was added. $\endgroup$
    – zeffii
    Commented May 3, 2015 at 7:18
  • $\begingroup$ @zeffii thanks for your comment, I update the post with more data.. thanks for any help $\endgroup$
    – yhoyo
    Commented May 3, 2015 at 15:37
  • $\begingroup$ i'm still not sure I understand what you are trying to achieve. Though I think it's not a great idea to be mixing bmesh mesh updates and bgl calls inside the one bgl callback (but I cannot prove with facts yet why I think that's a bad idea). $\endgroup$
    – zeffii
    Commented May 3, 2015 at 16:36
  • $\begingroup$ I encourage you to make a GitHub repository for the test, this will allow you to make branches. Master would have the code without bgl drawing and test branches would have various different approaches. The benefit is that you don't have to keep track of what code to comment / uncomment. The sooner you include branches in your development process the less hectic it will be. $\endgroup$
    – zeffii
    Commented May 5, 2015 at 5:16
  • $\begingroup$ can you please explain what you are trying to do in draw_callback_px, i can read the code, but you need to explain what you think it should be doing. Avoid mixing bmesh operations inside your bgl callback. if you want to define drawing characteristics for your bgl, then create a panel and use scene properties. As it stands I think the question is too broad. and the code far too long to be considered a condensed demo. $\endgroup$
    – zeffii
    Commented May 5, 2015 at 6:18

2 Answers 2

4
+100
$\begingroup$

To answer your questions, I think it makes more sense in the end to have a panel for the script. Sometimes you have to build up extra scaffolding for a script, even for testing. I don't think it is necessary to draw properties to the operator's own panel, you might even want to hide that from appearing anywhere on the UI.

This is a combination of two templates from the Text Editor templates menu.

To demo this you create a cube, and delete all edges so you have only vertices remaining. Run the code from text editor, then to start drawing you press the Simple modal draw..button which appears in the 3dview N panel at the bottom. If I understand the question (and it is entirely possible that I don't and there's some language barrier), You want to have access to the rest of 3d view UI while drawing, you want to adjust some settings for the bgl.

animated gif of demo

This short snippet lets you adjust the line thickness while the bgl still draws. Below the code I talk about some issues I have with your own code, (and ways to avoid crashing)

import bpy
import bgl
import blf


def draw_callback_px(self, context):

    # 50% alpha, 2 pixel width line
    bgl.glEnable(bgl.GL_BLEND)
    bgl.glColor4f(0.0, 0.0, 0.0, 0.5)
    bgl.glLineWidth(context.scene.BGL_DEMO_PROP_THICKNESS)

    bgl.glBegin(bgl.GL_LINE_STRIP)
    for co in self.mouse_path:
        bgl.glVertex3f(*co)

    bgl.glEnd()

    # restore opengl defaults
    bgl.glLineWidth(1)
    bgl.glDisable(bgl.GL_BLEND)
    bgl.glColor4f(0.0, 0.0, 0.0, 1.0)


class ModalDrawOperator(bpy.types.Operator):

    bl_idname = "view3d.bgl_demo_modal_operator"
    bl_label = "Simple Modal View3D Operator"

    def modal(self, context, event):
        context.area.tag_redraw()

        if event.type in {'MIDDLEMOUSE'}:
            return {'RUNNING_MODAL'}


        if event.type in {'RIGHTMOUSE', 'ESC'}:
            bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
            return {'CANCELLED'}

        return {'PASS_THROUGH'}

    def invoke(self, context, event):
        if context.area.type == 'VIEW_3D':
            args = (self, context)

            draw_handler_add = bpy.types.SpaceView3D.draw_handler_add
            self._handle = draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_VIEW')

            self.mouse_path = [v.co for v in context.active_object.data.vertices]

            context.window_manager.modal_handler_add(self)
            return {'RUNNING_MODAL'}
        else:
            self.report({'WARNING'}, "View3D not found, cannot run operator")
            return {'CANCELLED'}


class HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    # bl_context = "object"

    def draw(self, context):
        layout = self.layout
        col = layout.column()
        col.prop(context.scene, 'BGL_DEMO_PROP_THICKNESS', text='thickness')
        col.operator("view3d.bgl_demo_modal_operator")


def register():
    bpy.types.Scene.BGL_DEMO_PROP_THICKNESS = bpy.props.IntProperty(default=1, max=5)
    bpy.utils.register_class(HelloWorldPanel)
    bpy.utils.register_class(ModalDrawOperator)

def unregister():
    bpy.utils.unregister_class(HelloWorldPanel)
    bpy.utils.unregister_class(ModalDrawOperator)
    del bpy.types.Scene.BGL_DEMO_PROP_THICKNESS

if __name__ == "__main__":
    register()

Things to avoid.

  • Don't mix bmesh and bpy.ops.mesh while working on the same mesh, that's a recipe for bad code and potential crashes.

    if chboxjoin0:
        # bpy.ops.mesh.vert_connect_path()
        bm.edges.new([v1, v2])
    
  • BGL is one of the few areas in blender that will cause crashes to desktop, you must deal with all errors/exceptions inside your bgl callback, and return the BGL to a safe default state if there are errors.

  • don't mix geometry modifications inside your bgl callback
  • separate bgl parts from bmesh/mesh operations
  • perform mesh operations first, then draw the results.
  • switching contexts inside bgl callback, probably not a good idea.
  • start a lot simpler, maybe even with completely unrelated code just to get a better understanding of the interactions between various parts of your code.
$\endgroup$
2
  • $\begingroup$ thanks for answer... why this don't work in 3D only in 2d?, how I should mix geometry modifications + bgl? still testing with your sample. $\endgroup$
    – yhoyo
    Commented May 6, 2015 at 13:31
  • $\begingroup$ This bgl drawing callback is 3d. see bgl.glVertex3f(*co) I just reused the mousepath variable to store the list of 3d vectors. Unfortunatelyi'm not aware of many examples of trivial bgl usage that I can point to, but perhaps this might be interesting: gist.github.com/zeffii/9451340 (index viewer uses bgl) $\endgroup$
    – zeffii
    Commented May 6, 2015 at 13:50
0
$\begingroup$

Since clicking while trying to set a value on the UI will cause the operator to stop I suggest altering the property by catching an event like key press or mouse wheel, as an example :

# in modal()
    elif event.type == 'WHEELUPMOUSE':
        self.width += 1
    elif event.type == 'WHEELDOWNMOUSE':
        self.width -= 1

# in draw_callback_px()
    bgl.glLineWidth(self.width)

Now scrolling the mouse wheel will increase/decrease the line width


you can also register a new panel where you can set the variables and launch the operator

$\endgroup$
3
  • $\begingroup$ thanks for write, but this don't solve the question.... how add properties to operador modal draw? is possible?? $\endgroup$
    – yhoyo
    Commented May 2, 2015 at 23:30
  • $\begingroup$ sorry I don't know if it is possible $\endgroup$
    – Chebhou
    Commented May 2, 2015 at 23:43
  • $\begingroup$ I update the post with more data and other examples in order to clarify this problem. thanks for any help $\endgroup$
    – yhoyo
    Commented May 3, 2015 at 15:38

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .