When creating a custom Node - tree type (not scene/material/texture) is it possible to have a background image defined? This would be similar to how the compositing nodes allow an image backdrop, but instead, for a custom tree type.
well, either way I took this as a challenge.
With any luck by including the code, it will anger someone into making a much more elegant solution. (if the from bgl import *
bothers you importing as you need is probably tidier. But adding bgl.
infront of everything gets on my nerves.
You'll notice it looks for the Sverchok custom tree, changing it to your own should be zero work.
# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
import time
import bpy
import bgl
from bgl import *
from bpy.types import SpaceNodeEditor
from sverchok import node_tree
from sverchok.node_tree import SverchCustomTree
from sverchok.node_tree import SverchCustomTreeNode
callback_dict = {}
point_dict = {}
def node_id(oper):
return str(hash(oper) ^ hash(time.monotonic()))
def tag_redraw_all_nodeviews():
for window in bpy.context.window_manager.windows:
areas = window.screen.areas
for area in (a for a in areas if a.type == 'NODE_EDITOR'):
for region in (r for r in area.regions if r.type == 'WINDOW'):
region.tag_redraw()
def callback_enable(n_id, nt):
global callback_dict
if n_id in callback_dict:
return
data = {}
data['tree_name'] = nt.name
args = n_id, data
handle_pixel = SpaceNodeEditor.draw_handler_add(draw_callback_px, args, 'WINDOW', 'PRE_VIEW')
callback_dict[n_id] = handle_pixel
tag_redraw_all_nodeviews()
def callback_disable(n_id):
global callback_dict
handle_pixel = callback_dict.get(n_id, None)
if not handle_pixel:
return
SpaceNodeEditor.draw_handler_remove(handle_pixel, 'WINDOW')
del callback_dict[n_id]
tag_redraw_all_nodeviews()
def callback_disable_all():
global callback_dict
temp_list = list(callback_dict.keys())
for n_id in temp_list:
if n_id:
callback_disable(n_id)
def draw_callback_px(n_id, data):
space = bpy.context.space_data
ng_view = space.edit_tree
if not ng_view:
return
ng_name = space.edit_tree.name
if not (data['tree_name'] == ng_name):
return
if not isinstance(ng_view, node_tree.SverchCustomTree):
return
face_color = (0.2, 0.2, 0.2)
scn = bpy.context.scene
s = scn.sv_scale_unit
image_name = scn.sv_available_image
img = bpy.data.images.get(image_name)
if img:
img.gl_load(0, bgl.GL_NEAREST, bgl.GL_NEAREST)
texture = img.bindcode
w, h = img.size
w2 = w / 2
h2 = h / 2
_w2 = w2 * s
_h2 = h2 * s
else:
return
glEnable(GL_BLEND)
glBindTexture(GL_TEXTURE_2D, texture)
glEnable(GL_TEXTURE_2D)
glBegin(GL_QUADS)
glTexCoord2f(0.0, 0.0); glVertex3f(-1.0 * _w2, -1.0 * _h2, 0.0) # Bottom Left Of The Texture and Quad
glTexCoord2f(1.0, 0.0); glVertex3f(+1.0 * _w2, -1.0 * _h2, 0.0) # Bottom Right Of The Texture and Quad
glTexCoord2f(1.0, 1.0); glVertex3f(+1.0 * _w2, +1.0 * _h2, 0.0) # Top Right Of The Texture and Quad
glTexCoord2f(0.0, 1.0); glVertex3f(-1.0 * _w2, +1.0 * _h2, 0.0) # Top Left Of The Texture and
glEnd()
glDisable(GL_TEXTURE_2D)
# restore opengl defaults
glLineWidth(1)
glDisable(GL_BLEND)
glColor4f(0.0, 0.0, 0.0, 1.0)
def get_items(self, context):
images = bpy.data.images
inames = [i.name for i in images]
return [(i, i, 'image %s' % i) for i in inames]
class svImageShowOperator(bpy.types.Operator):
bl_idname = "scene.operator_sv_show_image_bg"
bl_label = "Image Show"
bl_description = "Toggle the visibility of the background image"
# _handle = None
@classmethod
def poll(cls, context):
scn = context.scene
if scn.sv_show_image and scn.sv_available_image:
return True
def modal(self, context, event):
nt = context.space_data.node_tree
if scn.sv_show_image and scn.sv_available_image:
n_id = node_id(nt)
callback_enable(n_id, nt)
else:
callback_disable_all()
return {"CANCELLED"}
return {"PASS_THROUGH"}
def invoke(self, context, event):
scn = context.scene
nt = context.space_data.node_tree
if scn.sv_show_image and scn.sv_available_image:
n_id = node_id(nt)
callback_enable(n_id, nt)
return {'RUNNING_MODAL'}
else:
self.report({"WARNING"}, "View3D not found, can't run operator")
return {"CANCELLED"}
class SverchokImageBG(bpy.types.Panel):
bl_idname = "Sverchok_img_bf"
bl_label = "SV BGIMAGE"
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_category = 'Sverchok'
bl_options = {'DEFAULT_CLOSED'}
use_pin = True
@classmethod
def poll(cls, context):
try:
return context.space_data.node_tree.bl_idname == 'SverchCustomTreeType'
except:
return False
def draw(self, context):
scn = context.scene
layout = self.layout
ntree = context.space_data.node_tree
c = layout.column()
c.operator(svImageShowOperator.bl_idname, text="Show Image")
c.prop(scn, 'sv_show_image')
c.prop(scn, 'sv_available_image', text='pick image')
c.prop(scn, 'sv_scale_unit')
def register():
bpy.types.Scene.sv_show_image = bpy.props.BoolProperty()
bpy.types.Scene.sv_available_image = bpy.props.EnumProperty(
name="Images", items=get_items,
description="Image paths")
bpy.types.Scene.sv_scale_unit = bpy.props.FloatProperty(default=1.2)
bpy.types.Scene.sv_custom_backdrop = bpy.props.StringProperty(default='')
bpy.utils.register_class(svImageShowOperator)
bpy.utils.register_class(SverchokImageBG)
def unregister():
bpy.utils.unregister_class(SverchokImageBG)
bpy.utils.unregister_class(svImageShowOperator)
callback_disable_all()
scn = bpy.types.Scene
del scn.sv_custom_backdrop
del scn.sv_show_image
del scn.sv_available_image
del scn.sv_scale_unit
if __name__ == '__main__':
register()
Edit
hmmm, as soon as nodes are added the texture gets broken.
PRE_VIEW
works nicely, but the texture at (x,y,0) is behind the grid.in 'POST_VIEW' adding this seems to stabilize the image
glEnable(GL_BLEND) glBindTexture(GL_TEXTURE_2D, texture) glEnable(GL_TEXTURE_2D) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glColor4f(1.0,1.0,1.0,1.0) glBegin(GL_QUADS)
-
$\begingroup$ this is an amazing hack :) I've done similar stuff for rig UIs in the 3D view. In this case I'm trying to add a preview image in the node itself (similar to the preview image in e.g. image nodes. I wonder if the new preview utility can work.... $\endgroup$ – Bassam Kurdali Jul 23 '15 at 20:17
-
$\begingroup$ I don't know to what extent bpy.utils.preview can be drawn on pynodes
draw_buttons
.. worth investigating $\endgroup$ – zeffii Jul 23 '15 at 20:29
Ctrl
+Shift
+click) $\endgroup$ – VRM Mar 9 '15 at 14:33