Open iRadEntertainment opened 3 years ago
Using the suggested method of
draw_set_transform
ordraw_set_transform_matrix
before callingdraw_texture()
(like suggested in this closed issue) also modifies the rulers and other things drawn on the editor main viewport. So this way becomes unusable to display a preview of a rotated sprite.
If this affects other editor overlay drawing, perhaps all you need to do is to reset the transform back, something like this:
func _draw():
draw_set_transform(transform)
draw_texture(...)
draw_set_transform(Transform2D())
If it doesn't resolve it, then perhaps overlay drawing should be fixed instead.
Yes I did that, but for some reason it didn't work. I can't pinpoint exactely why. When I'll be back to the computer I'll post an example project.
Anyway, since the many questions and requests on this topic I still think that many Godot users will benefit from some solution for this matter.
Maybe what you need is
var trans = draw_get_matrix()
draw_set_matix(my_matrix)
stuff...
draw_set_matrix(trans)
except draw_get_matrix()
doesn't exist.
forward_canvas_draw_over_viewport(overlay)
could pass currently applied transform as well.
UPDATE: I was mistaken and this actually works as expected:
If this affects other editor overlay drawing, perhaps all you need to do is to reset the transform back, something like this:
func _draw(): draw_set_transform(transform) draw_texture(...) draw_set_transform(Transform2D())
If it doesn't resolve it, then perhaps overlay drawing should be fixed instead.
I don't know what I did wrong in the past experiments with this method
It is still a bit unexpected that the draw_set_transform()
affects the rulers of the view:
If this behaviour is not the intended one I may open an issue on that (Godot v3.3.2), but I would say that, in almost every case, you would very like reset the transform at the end of the drawing session.
Here is a script to test things out:
tool
extends EditorPlugin
#- Icon to be draw on the overlay
const ico : Texture = preload("res://icon.png")
var tex_size : Vector2 = ico.get_size()
var rot_angle = 0
#- Reference an object in the scene
var ref_obj
#--- Enter and exit tree unused in this example.
func _enter_tree(): pass
func _exit_tree(): pass
#--- Handles(object).
# It needs to return true in order to make use of
# forward_canvas_gui_input(event) for grabbing the inputs
# and forward_canvas_draw_over_viewport(overlay) to draw on the overlay.
func handles(object):
ref_obj = object
tex_size = ico.get_size()
return (object)
var ctrl_pressed := false
func forward_canvas_gui_input(event):
#--- Update the overlays at any event.
# update_overlays() calls forward_canvas_draw_over_viewport(overlay)
update_overlays()
#--- Grab the inputs on the UI
# Pressing CTRL and scrolling the wheel changes the rot_angle.
# That is used in forward_canvas_draw_over_viewport(overlay)
# to draw the texture on the overlay
if event is InputEventKey:
if event.scancode == KEY_CONTROL:
ctrl_pressed = event.is_pressed()
if event is InputEventMouseButton and event.is_pressed() and ctrl_pressed:
if event.button_index == BUTTON_WHEEL_DOWN:
rot_angle += PI/60
return true
elif event.button_index == BUTTON_WHEEL_UP:
rot_angle -= PI/60
return true
elif event.button_index == BUTTON_MIDDLE:
rot_angle = 0
# This func is called at every update_overlays() call
func forward_canvas_draw_over_viewport(overlay):
#--- Reference viewport transform (for the view zoom) and mouse position
# on the canvas.
# At the moment thi is the easiest way to get the viewport transform.
# You need to reference a CanvasItem in the scene and get its viewport transform.
var view_transform = ref_obj.get_viewport_transform()
var mouse_loc_pos = overlay.get_local_mouse_position()
var mouse_glb_pos = overlay.get_global_mouse_position()
#--- get the Texture size and scale it by the viewport zoom level
var scaled_tex = tex_size * view_transform.get_scale()
var text_rect = Rect2(-scaled_tex/2, scaled_tex)
#--- Set the transform for the draw session, then draw the sprite
# overlay.draw_set_transform(position, rotation, scale)
overlay.draw_set_transform(mouse_loc_pos, rot_angle, Vector2.ONE)
overlay.draw_texture_rect(ico, text_rect, false, Color(1,1,1,0.3))
#--- Reset the draw transform for the overlay to default
# comment the next line out to see how the overlay draw_set_transform()
# affects the rulers in the main viewport
overlay.draw_set_transform(Vector2.ZERO, 0, Vector2.ONE)
To use it:
Yeah, in that case, Godot could just reset transform on C++ level. To be extra safe, it could save current transform prior to calling forward_canvas_draw_over_viewport()
callback, and resetting it after the callback is finished. I'm not sure how this works exactly, but I think it's something that is more or less straightforward to fix once you know the internal workings of it, @KoBeWi may be able to fix this in fact.
Ok opened the PR to prevent breaking editor: https://github.com/godotengine/godot/pull/50873
draw_texture()
already supports position, so if you want rotating the texture, #2624 would be more suited.
Ok opened the PR to prevent breaking editor: godotengine/godot#50873
Nice!
draw_texture()
already supports position, so if you want rotating the texture, #2624 would be more suited.
I find draw_texture_rect()
more flexible since you can define a Rect
. Using it I would like to suggest to keep the Rect
which gives us position
and size
and add an extra Transform
that will help with the rotation around a pivot point.
Example:
var ico = preload("res://icon.png")
func _draw():
#--- define the Rect
var size : Vector2 = _size
var offset : Vector2 = _offset
var tex_rect := Rect(offset, size)
var pos : Vector2 = _pos
var rot : float = _rot
var tex_transform = Transform2D(rot, pos)
draw_texture_rect(ico, tex_rect, tex_transform)
# actual args
# draw_texture_rect(texture, rect, tile, modulate, transpose, normal_map)
# wanted args
# draw_texture_rect(texture, rect, transform2d, tile, modulate, transpose, normal_map)
This way it would be possible to rotate the texture around the offset
Describe the project you are working on
I'm working on a Plug-in that let you "paint" Sprites within the editor. It shows a preview of it before you click and add a sprite node on that location. It could be useful to decorate a scene with multiple sprites without having to go and pull it one by one if you have many. The project can be found on GitHub here.
Describe the problem or limitation you are having in your project
I show the preview of the future created Sprite on the
overlay
infunc forward_canvas_draw_over_viewport(overlay)
in an EditorPlugin script. Using the suggested method ofdraw_set_transform
ordraw_set_transform_matrix
before callingdraw_texture()
(like suggested in this closed issue) also modifies the rulers and other things drawn on the editor main viewport. So this way becomes unusable to display a preview of a rotated sprite.Describe the feature / enhancement and how it helps to overcome the problem or limitation
This request has been seen several times and, despite the possible use of the
draw_set_transform
functionalities I think will simplify the process substantially if you could be allowed to pass as an optional arg aTransform2D
in thedraw_texture
. This would solve the problem of manipulating aTexture.Transform2D
instead of a whole localset_transform
for that specific class.Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams
it could be:
void
draw_texture(texture: Texture, position: Vector2, transform : Transform2D = Transform2D.IDENTITY, modulate: Color = Color( 1, 1, 1, 1 ), normal_map: Texture = null)
instead of:
void
draw_texture(texture: Texture, position: Vector2, modulate: Color = Color( 1, 1, 1, 1 ), normal_map: Texture = null)
If this enhancement will not be used often, can it be worked around with a few lines of script?
In my example I couldn't find a way to use the workaround. For other uses it could be done with
draw_set_transform
ordraw_set_transform_matrix
Is there a reason why this should be core and not an add-on in the asset library?
I don't see it useful in the add-on library