Masking / Clipping child objects within a parent?

edited September 2011 in Help request
Hi Guys,

a little stuck on what direction I should be taking here...

Just say I have a large rectangular object as a parent at co-ordinates (100,100).

Then I have a child square object at local co-ordinates (10, 10) so that it is 10 pixels in and 10 pixels down from the top relative to the parent.

That part is easy enough.

But if I want to move the child object slightly out of the boundary of the parent, I would like the display surrounding the parent to clip the child, ie:

clipping.png

Is this something I would do through a viewport? Or something to do with orxGRAPHIC_KU32_MASK_TYPE? I'm not 100% sure what my approach should be.

Comments

  • edited September 2011
    A viewport would definitely work but is probably unwieldy. (The mask have nothing to do with that :))

    If I were to do something like this, I'd update the origin, pivot and size of the child's graphic to match your needs.

    If you look at Mushroom Stew, that's how I get the health icons for all the enemies displayed with the current remaining health ratio in the method MushroomStew::UpdateEnemyIcon().

    There are less intrusive ways (like intercepting the object's rendering event and doing your own rendering), but I think this method is by far the easiest one. :)
  • edited September 2011
    Thanks, Iarwain. Actually, I realised an easier solution. I can just place an extra graphic outside the border and fiddle with the Z order of all objects.

    The aim is to make a scrolling display that gets cut off outside the border. If I fiddle with Z-order in relation to other objects in the region, it should give satisfactory results.

    If not I'll check into the pivot and origin settings. I'll see how I go. Thanks again!
  • edited September 2011
    If you have objects outside that can serve as masks, that's definitely an easier solution!

    The origin/pivot/size trick ipcan be very helpful if you need things such as textured progress bars.

    There's also an easy non-intrusive solution based on a custom shader: you can attach a shader to your child objects (in config or in code), then this shader will only allow pixels inside your parent region to be written (if your region doesn't have fixed coordinates you can send them as shader parameters via the shader param event).
    That solution requires attaching a shader to your objects (1 line of config) and to write the shader (1 if/else in shader code, written in config file) but the drawback is that it'll not work on very old hardware.
  • edited February 2012
    I'm in a similar situation. Consider this image:

    equilibria__Running____Microsoft_Visual_Studio_2012_02_20_21_23_25.png

    Each of those eight "bays" have 4 doors which start closed and then slide open to reveal those little orbs within.

    I guess it would probably be possible to do this with creative Z-ordering, but I don't want to give my artist the extra work to have to figure out slicing the graphics the correct way.

    I think updating the doors' graphic origin and pivot could also do this.

    iarwain, do you think the shader trick would work here? And, if so, is it trivial enough to post an example?

    Thanks!
  • edited February 2012
    Hi!

    Actually, there's another option that would also work without forcing you to fiddle with shaders, as long as you want to limit the drawing to an axis-aligned rectangle surface: calling orxDisplay_SetBitmapClipping() on the screen bitmap with the appropriate coordinates.

    You could intercept the orxRENDER_EVENT_OBJECT_START of your gate, set the screen clipping to prevent drawing outside and on the orxRENDER_EVENT_STOP restore the clipping to the full viewport dimension.

    For the shader, you'd simply need to send your rectangle coordinates as shader parameters and do a simple test on the fragment coord (gl_Position) and verify it's in the rectangle. If it's not, simply output a pixel with 0 for alpha. Something like:
    void main()
    {
      if((gl_Position.x >= MIN_X)
      && (gl_Position.x <= MAX_X)
      && (gl_Position.y >= MIN_Y)
      && (gl_Position.y <= MAX_Y))
      {
        gl_FragColor = texture2D(MY_TEXTURE, gl_TexCoord[0]);
      }
      else
      {
        gl_FragColor = vec4(0.0);
      }
    }
    

    But again, the best solution, especially for freeform masks, would be to make use of the depth coordinate. ;)
  • edited February 2012
    Hmm, the orxDisplay_SetBitmapClipping idea makes a lot of sense for what I am doing.

    The Z-ordering is a very attractive solution! However, the slightest change in object positioning would require changes in the artwork, so I think it makes sense to solve it in code.

    I see there are quite a few potential solutions, so I'll report back with whatever I do.
  • edited February 2012
    Yep, there are many options and you're probably the only one able to pick the best suited to your situation.

    For example, I'm not sure why Z-ordering would require any artwork changes instead of some config changes only, but I don't know all the details in your current screen organization. :)
  • edited February 2012
    Well, it's because I have to do this for each of the 8 groups:

    So, to do that with Z-ordering, I think I would have to cut transparency out of the background. Then I'd have to play tricks with the Z-ordering of each of the different groups so the little door pieces don't become visible in the adjacent group when they retract.

    And it's certainly possible the requirements will change, e.g. I may be asked to use a Position FX to make the groups move at runtime! And different screen sizes (Android, tablets) may require a bit of different positioning to distribute the groups evenly on the screen.

    Catching orxRENDER_EVENT_OBJECT_START and using orxDisplay_SetBitmapClipping there works well and is very easy! It also won't break if the requirements change in the ways I am predicting. Thanks again for that suggestion.
  • edited February 2012
    Oh right, I forgot your targets were OpenGL ES devices.
    Otherwise I'd have the whole background with holes and rendered with alpha blending.
    Ah, well. Happy that the SetBitmapClipping trick works nicely for you. :)
  • jimjim
    edited May 2012
    Using stencil buffer in Opengl, one can render to a non rectangular surface, like triangular or circular or polygonal, but I don't know if using stencil buffer is recommended in EGL or not. Using stencil buffer is a bit expensive but it can be used to make some cool effect like splitting the screen diagonally, dissolving or rendering map on a circular portion of screen. But this kind of effects are not very common in 2D games, I think.
  • edited May 2012
    Stencil buffer is definitely a valid approach but keep in mind that since iOS 4.0, one cannot have a separate stencil buffer: it must be part of the depth buffer.
    I'd personally go for a compositing approach, using one of the texture as a mask (like a manually handled stencil buffer if you will), this has the advantage to be supported on all the platforms supported by orx and not require any custom written rendering. But it's more a matter of taste I think.
Sign In or Register to comment.