2
\$\begingroup\$

I'm interested in being to scale textures up via nearest neighbour. I can do this via a SpriteBatch.Draw() overload however this means that any other sprites drawn within that batch will also have the scaling.

What happens if I have 50 objects I want to to scale, and another 50 objects I don't want to be drawn using nearest neighbour. Assuming they alternate depths, that's 100 calls to to spriteBatch.End() in order to get depth drawn correctly. Now also let's say each object has it's own texture.

One way is to you use Texture2D.SetData() to manually scale up the textures but this could get messy, very quickly.

Any tips?

\$\endgroup\$
  • \$\begingroup\$ Instead of upscaling, why don't you create your textures at the max resolution you need them and then let them scale down? As far as I know, mipmapping should keep them crisp when scaled down \$\endgroup\$ – Dries Jan 4 '14 at 13:41
  • 1
    \$\begingroup\$ Why would a single call to SpriteBatch.Draw() with a scale parameter affect other sprites drawn with the same SpriteBatch? As far as I remember this isn't how it works in XNA. You should be able to make all SpriteBatch.Draw() calls with some textures scaled and some not scaled without a problem. The only thing to take into account is that if you do want to draw scaled textures with that SpriteBatch, they will be scaled using the nearest neighbour algorithm. \$\endgroup\$ – Bernardo Jan 7 '14 at 5:56
  • \$\begingroup\$ Worded badly, I actually meant I don't want all of my sprites using nearest neighbour. Question edited. \$\endgroup\$ – Joe Shanahan Jan 7 '14 at 5:59
2
+50
\$\begingroup\$

FIRST OPTION (not advised) :

Looking at the documentation you can change the samplerState to choose texture interpolation.

Two references there

http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.samplerstate.pointclamp.aspx

https://stackoverflow.com/questions/9215027/nearest-neighbor-zoom

If changing the SamplerState of spriteBatch during the different .draw() calls does work because the texture are "initialized" at each operation you're good. But you'll have to temper a bit cause it's not public API (as you said very messy :D).

If they are processed when .end() is called then you would have to override .draw() calls to detect the state of the sampler in order to process them as you want on the last phase.

Disadvantage : tempering with inside magic is most of the time a wrong idea

SECOND OPTION (advised) :

Your real concern is to enable depth-testing. So it will slightly more expensive but you can also do depth-testing with your own algorithm. For a low number of elements this would be very cheap even on a mobile phone.

You can still do packaged texture draws by an algorithm segmenting the calls.

For instance in order of depth : 10 linear interpolations, 2 pointClamp, 2 linear, 2 pointClamp. => 4 calls instead of 16.

You just have to specifiy the interploation for each texture and code something like

//pseudo-code
data //textures ordered by depth with field interpolation = samplerState
prev = data.next()
spriteBatch.begin(..., prev.interpolation, ...)
spriteBatch.draw(prev)

while(data.hasNext()) {
    next = data.next()
    if(next.interpolation != prev.interpolation){
      spriteBatch.end()
      spriteBatch.begin(..., next.interpolation, ...)
    }
    spriteBatch.draw(next)
    prev = next
}
spriteBatch.end()

Advantage : You have real control over each draw call (what if you suddenly want to add this special texture interpolation on your gunship or this other element) and this is O(n) (without ordering)

\$\endgroup\$
  • \$\begingroup\$ I haven't marked this as the answer because, whilst I appreciate the insight, it hasn't really answered my question, specifically: "without having to use separate sprite batches". If no one else responds though, I'll make sure you get the bounty. \$\endgroup\$ – Joe Shanahan Jan 10 '14 at 18:52
  • \$\begingroup\$ Well I just assumed that the solution you're asking for is only feasible by modifying the private state of the SpriteBatch. I wouldn't investigate this solution if I was in your position, that's why I proposed the second option. I hope this helps you anyway ;) \$\endgroup\$ – StackHola Jan 11 '14 at 15:51
  • \$\begingroup\$ gamedev.stackexchange.com/questions/6820/… Did you try the proposition on this question ? I just think the SamplerState is taken into account on the end() action, so it won't help much. this.GraphicsDevice.SamplerStates[0] = SamplerState.PointClamp; \$\endgroup\$ – StackHola Jan 11 '14 at 15:58
  • \$\begingroup\$ Yeah, I feel like if you were in a position where you needed to alternative massively each frame it would be better just to pre-expand these images as extra files you ship with your game. \$\endgroup\$ – Joe Shanahan Jan 11 '14 at 16:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.