Question about scaling sprites

The Partridge Family were neither partridges nor a family. Discuss.
WilsonHuang
Posts: 44
Joined: February 13th, 2019, 3:23 am

Question about scaling sprites

Post by WilsonHuang » October 8th, 2019, 5:05 am

After learning Intermediate Tutorial 12 [Animated Sprite Character]. I want to add the scaling effect to the sprite, which you can enlarge or shrink sprites. My code seems okay when enlarge the sprites. However, I have invisible cover when I shrink the sprites. How do I fix it?

Here is my code:

Code: Select all

#include "Graphics.h"
#include "Colors.h"
#include <assert.h>
#include <math.h>
namespace SpriteEffect
{
	class Scale
	{
	public:
		Scale(float scale = 1.0f)
			:scale(scale)
		{
			assert(scale > 0.0f);
		}
		void operator()(Color sourceColor, int x, int y, Graphics& gfx)
		{
			if (sourceColor != chroma)
			{
				for (int dy = 0; dy < (int)ceil(scale); dy++)
				{
					for (int dx = 0; dx < (int)ceil(scale); dx++)
					{
						int resultX = (int)ceil(x * scale + dx);
						int resultY = (int)ceil(y * scale + dy);

						if (resultX < 0)
						{
							resultX = 0;
						}
						if (resultY < 0)
						{
							resultY = 0;
						}

						if (resultX >= gfx.ScreenWidth)
						{
							resultX = gfx.ScreenWidth - 1;
						}
						if (resultY >= gfx.ScreenHeight)
						{
							resultY = gfx.ScreenHeight - 1;
						}

						gfx.PutPixel(resultX, resultY, sourceColor);
					}
				}
			}
		}
	private:
		Color chroma = Colors::Magenta;
		float scale;
	};
}
Usage:

Code: Select all

gfx.DrawSprite(position.x, position.y, frames[currentFrame], surface, SpriteEffect::Scale(0.9f));
Invisible Cover.png
(9.22 KiB) Not downloaded yet

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Question about scaling sprites

Post by albinopapa » October 9th, 2019, 5:14 am

Code: Select all

scale = .9f;
for (int dy = 0; dy < (int)ceil(.9f); dy++)
{
	for (int dx = 0; dx < (int)ceil(.9f); dx++)
Does this help?
Basically, you are only iterating from 0 to 1 ( ceil( .9f ) = 1.f ).

Your code works for scaling up because the ratio for the sprite pixel to screen pixel is 2:1 or something like that, so looping 2x2 for a scale factor of 2.f would work. For minification, you'd need to skip over some sprite pixels for each screen pixel. In order for this to work using an effect, your effect class would need more information. Basically, while magnification works, scaling is more of a transformation than a visual effect.

The 3D Fundamentals tutorials covers transformations.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

User avatar
AleksiyCODE
Posts: 32
Joined: September 21st, 2019, 8:47 pm

Re: Question about scaling sprites

Post by AleksiyCODE » October 9th, 2019, 7:17 pm

Well, i made a quick (shitty) animated sprite tester for my friend, and there is simple scaling built in (arrow keys change animation playback speed and size)
https://gitlab.com/AleksiyCODE/st
you may be able to get some ideas from there (but the code is shit)
I like ass

WilsonHuang
Posts: 44
Joined: February 13th, 2019, 3:23 am

Re: Question about scaling sprites

Post by WilsonHuang » October 10th, 2019, 12:48 am

AleksiyCODE wrote:
October 9th, 2019, 7:17 pm
Well, i made a quick (shitty) animated sprite tester for my friend, and there is simple scaling built in (arrow keys change animation playback speed and size)
https://gitlab.com/AleksiyCODE/st
you may be able to get some ideas from there (but the code is shit)
Thanks, I'll give it a look!

WilsonHuang
Posts: 44
Joined: February 13th, 2019, 3:23 am

Re: Question about scaling sprites

Post by WilsonHuang » October 10th, 2019, 1:59 am

albinopapa wrote:
October 9th, 2019, 5:14 am

Code: Select all

scale = .9f;
for (int dy = 0; dy < (int)ceil(.9f); dy++)
{
	for (int dx = 0; dx < (int)ceil(.9f); dx++)
Does this help?
Basically, you are only iterating from 0 to 1 ( ceil( .9f ) = 1.f ).

Your code works for scaling up because the ratio for the sprite pixel to screen pixel is 2:1 or something like that, so looping 2x2 for a scale factor of 2.f would work. For minification, you'd need to skip over some sprite pixels for each screen pixel. In order for this to work using an effect, your effect class would need more information. Basically, while magnification works, scaling is more of a transformation than a visual effect.

The 3D Fundamentals tutorials covers transformations.
Thanks for reply.
I think I found the problem. The problem is in the DrawSprite function.
In DrawSprite function, there are code to check whether the sprite is outside the screen and clip the sprite.

Code: Select all

		//top-left
		if (x < clip.left)
		{
			source.left += clip.left - x;
			x = clip.left;
		}
		if (y < clip.top)
		{
			source.top += clip.top - y;
			y = clip.top;
		}

		//bottom-right
		if (x + source.GetWidth() > clip.right)
		{
			source.right -= x + source.GetWidth() - clip.right;
		}
		if (y + source.GetHeight() > clip.bottom)
		{
			source.bottom -= y + source.GetHeight() - clip.bottom;
		}
The original sprite is out of the screen and being clipped. This effects the scale down version (also be clipped)
It seems I need to do some modification to the DrawSprite function to make the transformation works.
Also, just as you said, " scaling is more of a transformation than a visual effect". I may move the transformation code to the other place.

BTW, which episode of 3D Fundamentals tutorials covers transformations? I'll take a look Thanks!

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Question about scaling sprites

Post by albinopapa » October 10th, 2019, 7:19 am

Well, whoops, it's the Advanced series.

Transformations/Scaling/Translation
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Question about scaling sprites

Post by albinopapa » October 10th, 2019, 6:48 pm

Here's my implementation. The clipping algorithm is slightly different than chili's current implementation, but this is how he taught it in the old series, not sure why he changed it.
Spoiler:

Code: Select all

	template<typename E>
	void DrawSprite( int x, int y, RectI srcRect, const RectI& clipRect, const Surface& s, E effect, float scale = 1.f )
	{
		auto dstLeft = std::max( -x, clipRect.left ) + x;
		auto dstTop = std::max( -y, clipRect.top ) + y;
		auto dstRight = std::min( clipRect.GetWidth() - x, int( srcRect.GetWidth() * scale ) ) + x;
		auto dstBottom = std::min( clipRect.GetHeight() - y, int( srcRect.GetHeight() * scale ) ) + y;

		auto const srcScale = 1.f / scale;
		for( int dy = dstTop; dy < dstBottom; dy++ )
		{
			auto const sy = int( ( dy - dstTop ) * srcScale );
			for( int dx = dstLeft; dx < dstRight; dx++ )
			{
				auto const sx = int( ( dx - dstLeft ) * srcScale );
				effect( dx, dy, s.GetPixel( sx, sy ), *this );
			}
		}
	}
I put the scale parameter at the end, so it could be defaulted. This makes it so changes don't have to be made for routines you've already written and don't need scaling.

NOTE: This is just the final DrawSprite function, you'll need to add the float scale parameter to each of the DrawSprite functions to get this to work.

NOTE2: Corrected code in this post.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Question about scaling sprites

Post by albinopapa » October 10th, 2019, 8:45 pm

sprite_scaling.png
(66.31 KiB) Not downloaded yet
Here's a sample of the Link sprite scaled from 10% to 200% ( incremented by 10% each time ).
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Question about scaling sprites

Post by albinopapa » October 10th, 2019, 8:48 pm

A more generic solution would be to use the 3D Fundamentals framework and method. In that, you create a quadrangle, apply transforms to the vertices ( translation, rotation, scaling, etc... ) and interpolate between the vertices pixel to pixel.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Question about scaling sprites

Post by albinopapa » October 10th, 2019, 9:31 pm

Well, there's an error in my code. It assumes a single sprite, not a sprite sheet.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

Post Reply