How to draw customized render results on the viewport?

Hello there,

Say that I implement a customized Z-depth render tool. Is it possible that I can “draw” the render result(array of pixels) on the viewport with Ruby API?

Like shown below
ZDepth|690x184

Cheers,
Tom

1 Like

For years, some renderer used to hook somehow into the OpenGL viewport although no API existed.

In SketchUp 2020, there is an API to draw textures, that means you can draw a rectangle in 2d screen space with width/height of the viewport and give it a texture (ImageRep, in-memory image representation without needing a file).

… and currently you can only draw to the viewport when a custom Tool is activated.

Thanks for your help.
Sorry about the belated reply. I just tested the load_texture and draw2d features in 2020 but it seems something went wrong.

I’ve created a custom tool and used the load_texture sample code from here Class: Sketchup::View — SketchUp Ruby API Documentation.

def activate
  view = Sketchup.active_model.active_view
  image_rep = view.model.materials.current.texture.image_rep
  @texture_id = view.load_texture(image_rep)
end

def deactivate(view)
  view.release_texture(@texture_id)
end
  def draw(view)
    draw_preview(view)
    @mouse_ip.draw(view) if @mouse_ip.display?
    points = [ [0, 0, 0], [9, 0, 0], [9, 9, 0], [0, 9, 0] ]
    uvs = [ [0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0] ]
    print(@texture_id) # This is a valid integer
    view.draw(points, texture_id: @texture_id, uvs: uvs)     
  end

It raised
Error: #<TypeError: no implicit conversion of Array into Integer>
E:/sketchup-ruby-api-tutorials-master/examples/02_custom_tool/ex_custom_tool/main.rb:82:in `draw’,
which refers to

view.draw(points, texture_id: @texture_id, uvs: uvs)

I have selected a material with texture input and the @texture_id is printed as an integer.
Any hints about it? Thanks.

what does

print(@texture_id.inspect)

return?

john

You’ve missed out the openglenum parameter, which is the Integer it’s looking for, trying to convert your points array to an Integer.

2 Likes

Thanks for your help.
I added the missing openglenum parameter and now it can do with no exceptions - but still no textures.
Only a black square is shown on the screen.

Here is the code of my tool - it is based on the sketchup ruby api tutorial.

require ‘sketchup.rb’

module Examples
module CustomTool

class LineTool

  def activate
    @mouse_ip = Sketchup::InputPoint.new
    @picked_first_ip = Sketchup::InputPoint.new
    view = Sketchup.active_model.active_view
    image_rep = view.model.materials.current.texture.image_rep
    @texture_id = view.load_texture(image_rep)        
  end

  def deactivate(view)
    view.invalidate
    view.release_texture(@texture_id)
  end

  def draw(view)
    points = [ [0, 0], [100, 0], [100, 100], [0, 100] ]
    uvs = [ [0, 0], [1, 0], [1, 1], [0, 1] ]
    # view.draw2d(GL_QUADS, points)        
    view.draw2d(GL_QUADS, points, texture_id: @texture_id, uvs: uvs)        
    puts "@texture_id #{@texture_id}" 
    puts "@texture_id.inspect #{@texture_id.inspect}"    
  end

end # class LineTool


def self.activate_line_tool
  Sketchup.active_model.select_tool(LineTool.new)
end

unless file_loaded?(__FILE__)
  menu = UI.menu('Plugins')
  menu.add_item('Custom Tool Example') {
    self.activate_line_tool
  }
  file_loaded(__FILE__)
end

end # module CustomTool
end # module Examples

The print messages are
@texture_id 23
@texture_id.inspect 23

Did I miss something?

PS: I’ve tried other openglenums - they cannot render the textures either.
Here is the screenshot. What I suppose to do is to draw the texture on the screen.

Just guessing here, but I think the windingorder should be counter clockwise:

points = [ [0, 0], [0, 100], [100, 100], [100, 0] ]
uvs = [ [0, 0], [0, 1], [1, 1], [1, 0] ]

Thanks, CAUL.
Unfortunately, it seems to be the same black box issue.

This works for me:

        view.draw2d(GL_QUADS, points, texture: @texture_id, uvs: uvs)        

The documentation seems to be wrong for the options hash, it is texture not texture_id. Thanks to @Aerilius for this, I saw it in his Sky Dome extension. It was the example code on ruby.sketchup.com that omitted the openglenum parameter too, not @Drawfun.

1 Like

Can you point to the bad example and open a doc issue on the GitHub API Issue Tracker for it please? (I don’t find the bad example in the doc for #draw2d method.)

Also an issue for the incorrect options hash key if one hasn’t been opened yet.

The example is in the #load_texture method doc, the same code that DrawFun posted earlier in this thread.

I’ll try and open an issue for these if no one else has.

1 Like

view.draw2d(GL_QUADS, points, texture: @texture_id, uvs: uvs)

Thanks, McGordon! That works for me! The official example of load_texture seems to be wrong.

2 Likes

Gordon has logged issues in the tracker …

Awesome! Thanks!

The draw texture works perfectly but with one limitation, as mentioned here.

… and currently you can only draw to the viewport when a custom [Tool](http://ruby.sketchup.com/Sketchup/Tool.html) is activated.

Just wondering if it is possible to keep this tool activated all the time?
Now the drawing is stopped if I select other tools(e.g. Orbit, Select…)
Ideally, I want it to keep drawing so users can operate on the viewport when the render results are shown.

… and echoed above in post #3:

Sure … if as long as the user wants to use just this one tool, … but I doubt it. :wink:

These native tools don’t allow you to change their behavior (such as subclassing them, etc.) and their “workings” are not much exposed to the Ruby API. (Oh, you can watch the toolstack and know when tools are activated, but since the observer overhaul for v2016, many of them no longer fire state changes until after the tool action is committed.)

If you want your tool to go back to where it was (after the view manipulator interrupted your tool,) then your tool will need to implement suspend() and resume() callback methods. Save state in the suspend() callback and restore it in a resume() callback.

You and several other extension developers. It (and related requests) have already been requested to expose the functionality to draw to the viewport outside of a tool (say when native tools are active.) But there are hurdles to overcome. There needs to be a mechanism for users to grant rights to extensions to do this. And also for other Ruby tool developers to disallow other custom tools to writing when their tools are active.

There are entire threads on this subject. The formal requests and discussions is logged in the issue tracker. Add any comments & wishes you’d like there, please. (Ie, when the time comes to implement, the Trimble team devs will reread those issue request threads.)

2 Likes

Thanks DanRathbun for the very exhaustive explaination!