• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

SOLVED Any Trick to Shift the Drawing Offset of Surface away from 0,0?

TheMagician

Member
Drawing things, that are positioned at absolute coordinates, to a surface means that you have to shift them, so that they are positioned relative to 0,0 because that's the reference point for drawing to a surface.

Is there any trick to instead shift the surface's reference point to the absolute coordinates? Something like canvas.translate in Java?
 

TheMagician

Member
I've thought about that, too and I guess it would work but it would mean that I always have to create a surface as big as the screen - even if I only need to draw a small area. From a memory standpoint that's not ideal.
 
I did something similar to create a "X-ray" effect in one of my projects:

I didn't even use draw_surface_part, what I needed to do was measure the distance of what is drawn inside the surface relative to the surface's position.

I don't know if this will help you, but here's the code I used:
GML:
//inside obj_small_x_ray end step event
X=distance_to_point(0,y)+4;
Y=distance_to_point(x,0)+5;

surface_set_target(global.small_x_ray);

with obj_invisiblock
    draw_sprite(spr_invisiblock,0,x-obj_small_x_ray.X,y-obj_small_x_ray.Y);
 
surface_reset_target();
 
Last edited:

Nidoking

Member
That's what you need to do, but it is also exactly what TheMagician said they didn't want to do. It is the opposite of an answer to the question that was asked.
 
That's what you need to do, but it is also exactly what TheMagician said they didn't want to do. It is the opposite of an answer to the question that was asked.
Well, I just guessed what end result they wanted and gave it to them, but you're right. I assume too much, and do not know their reasons for not wanting to do it that way. I apologize :(
 
Last edited:

TheMagician

Member
Thank you @gamedesigner1337. Yours is indeed the classic approach but since I have lots of small elements that would need to be shifted and I never know which elements will be inside the surface I had hoped that there is a way to move the surface to the elements rather than the elements to the surface.
 

FrostyCat

Redemption Seeker
I've never done it before, but I've seen other users leverage techniques from 3D graphics for this. The example from this Manual entry demonstrates a matrix push-and-set shifting the position of drawn graphics. If you are only doing a simple translation, your version will be one push-pop shallower than the example.

Situations like this make me less supportive of YoYo's conventional "we'll make GMS 2 a specialist on 2D games and nothing else" stance. It is a misplay on YoYo's part to think there is a hard line between 2D and 3D graphics, especially in today's market, and put up synthetic barriers to 3D use as a result of this belief.
 
Just an idea, don't know if this will work, but you could try... You could, still like I did, calculate the offset, but then you calculate the angle from it to the actual position the surface should be drawn using point_direction(). So, now that you have a direction and a distance between two coordinates, you could shift the surface's reference position using lenghtdir_x and lenghtdir_y.
 
Last edited:

TheMagician

Member
Now that's the magic I was talking about!

@Xor, @Pixelated_Pope, @gnysek: The technique works like a charm. It is especially useful when you can use one of the built-in view cams.

In my case I only need to draw a small part of the screen at an offset so @FrostyCat's solution (in a simplified version) is what I went with:

GML:
var m_offset = matrix_build(shift_x,shift_y,0,0,0,0,1,1,1);
var m_normal = matrix_build(0,0,0,0,0,0,1,1,1);

matrix_set(matrix_world, m_offset);

surface_set_target(surf);

draw_clear_alpha(c_black, 0);

//draw the stuff at its normal x/y coordinates here

surface_reset_target();

matrix_set(matrix_world, m_normal);
Works like a charm. Thank you so much, guys!
 
  • Like
Reactions: Xor

NightFrost

Member
GML:
surface_set_target(surf_id);
camera_apply(view_camera[0]);
So if I understand this right. Every surface you create comes with a full-blown camera rigging, so you can copy your usual camera over and everything just works. Which basically makes the surface a replacement application surface. And if you only need a small region of the view, I guess you could create a smaller surface and adjust camera position to match, and can draw still without having to offset?

That's very... interesting.
 

gnysek

Member
without having to offset?
I think that's what camera_apply does - it's setting offset for drawing, using -x and -y of current camera. So it's still ofsetting, just not using literals on every draw function.

As per documentation, for active camera, camera_apply is called automatically in background, at start of normal draw event (so not surface and not GUI). But you you change camera in middle of draw event, it will have same effect as with surface_set_target - all is reset to 0,0 . You need to call camera_apply manually in that case, to apply that camera in same frame. If it's not called manually, it still will be called next frame for active camera.

So, I may be wrong, but camera_apply seems to be "apply -x and -y offset of current camera in current context" function.
 

Bart

WiseBart
It's all relative. When the camera moves to the left, everything that is seen through the camera moves to the right. That leads to those negative x and y offsets.
camera_apply rather "applies" a given camera's projection and view matrices, immediately, at that point in the code.
It's a bit different for views, where GM sets the matrices, based on the view_camera of the current view (likely in that "Viewport setup / clear" part under Draw Events). In other cases, the default camera is used (I think also when rendering to surfaces, in the pre draw event, etc.)
 

NightFrost

Member
I think that's what camera_apply does - it's setting offset for drawing, using -x and -y of current camera.
Yes, that's what I was referring to with my last bit. That is, I was hypothesizing: if I want for example just to get the lower right quarter of current view to surface for processing (for reasons undetermined) I can create a surface half the width and height of the view, set target, apply camera, then move camera by half the width and height of view. Then, when I draw (without offsets) the surface will receive content belonging to lower right of view.
view matrices
I'm afraid I've no idea what those are. :D Display stuff has been all coordinates and dimensions for me, and so far at least it's been as far as I've had to delve the rabbit hole.
 
Top