Everything included (code, executable, text, etc...) is
Copyright (C) 1996 Yamaha of XYZZ (Scott Scriven)


----------------------------------------
Internet addresses
----------------------------------------
My email addresses are:
	scriven@CS.colostate.edu
	scriven@VIS.colostate.edu
My web page is at:
	http://www.VIS.colostate.edu/~scriven/


--------------------------------------
Scaling / Resizing (realtime)
--------------------------------------
Realtime scaling is useful in many applications -- especially games.
It can be rather effective when used properly.

-----------------------------------
Realtime vs "Real" scaling
-----------------------------------
One method of scaling is to simply move the pixels based on how big you
want the image to be.  This technique works when the image is scaled down,
but when you scale it up space appears between pixels.  The space is what
I will refer to as the "unknown" pixels.

Realtime scaling is usually quite fast, though doesn't achieve the level
of quality that professional paint programs get.  This is because the
paint programs use advanced techniques to "guess" the pixel values that
are unknown.  They use interpolation and color weighting, sometimes even
edge-finding and reconstruction techniques to figure out what should be
in the unknown pixel area.  Unfortunately, this is slow.

The scaling method we'll use simply skips or repeats pixels as necessary
to fill in gaps between pixels, or to avoid drawing the same pixel twice.
This really doesn't give great picture quality, but it gives speed (which
is often much more important).


------------------------------------
The source code
------------------------------------
This source was written for DJGPP.  It may or may not work on other
compilers, and will definitely need modifications to work on a 286.

The code (I hope) is well-commented enough so that you can figure out
what does what.

Also note that only the scaling-specific part of the code is supplied.
The graphics library and other stuff aren't there.

However, I haven't taken out any of the commented-out sections of the
code, so that you can take a look at how this evolved.  There are a few
things in the animate() function that will do various effects while
displaying the scaled image, and there are a couple of previous versions
of the actual scaling function.  If you don't care to look at those, it
doesn't matter.


------------------------------------
Performance -- speed
------------------------------------
When I run this on my 486/66, I get around 100 fps.  It does not go as
fast when it's going full-screen, though.

I don't know if this code should be considered fast or not, but it goes
fast enough for my own purposes.



--------------------------------------
How it works
--------------------------------------
So you want to scale an image...  Here's how to do it.

The scale function included takes a bitmap of any width and height, and
draws it onto another bitmap of any width and height, and you can resize
the original bitmap however you like.

The function accepts the following parameters:
	src:	pointer to the image we want to scale
	srcwid:	how wide is the source image?
	srchgt:	how tall is the source image?
	dest:	pointer to the bitmap we want to scale into (destination)
	dstwid:	how wide do we want the source image to be?
	dsthgt:	how tall do we want the source image to be?
	pagewid:	how wide is the destination bitmap?
	pagehgt:	how tall is the destination bitmap?
	left:	x coordinate of the upper-left part of the source image in
		the destination image (upper-left is relative to the source
		image, not the final result)
	top:	y coordinate of the upper-left corner of the source image in
		the destination image
Note that both srcwid&srchgt and dstwid&dsthgt refer to the source image's
dimensions.  The destination page size is specified in pagewid&pagehgt.

Anyway, to scale an image we "move" through the source and the destination
simultanteously.  We move through the destination one pixel at a time (so
we won't miss any, and won't repeat any), and we move through the source
at a pre-calculated rate that is inversely related to the amount we scale
it.

The steps involved are as follows:
1.	Figure out the ratio between the source width and the destination 
	width.  Do the same for height.  This number is the "speed" that
	we will move through the source image.
2.	We use a loop to go through the destination area one pixel at a
	time.  At the same time, we keep seperate variables to keep track
	of our position in the source image.
3.	For each time through the loop, copy a pixel.

This might look something like the following:
{
  int dx, dy;	// destination coordinates	
  float sx, sx;	// source coordinates
  float SourceSpeedX, SourceSpeedY;	// duh...  read the variable name

  SourceSpeedX = sourcewidth / destwidth;
  SourceSpeedY = sourceheight / destheight;

  for(dy=top; dy<=bottom; dy++)
  {
    for(dx=left; dx<=right; dx++)
    {
      destination[dx][dy] = source[sx][sy];
      sx += SourceSpeedX;
    }
    sy += SourceSpeedY;
  }
}

This example, if you were to define a few more variables, should work.
(don't try it, though.  I haven't tested it at all.  Go make your own.)
This will be very slow, though.  It uses floating-point, and therefore
will go very slow.

Actually, this looks very similar to the working source I've included.
The only major differences are:
	This uses floating point instead of fixed-point. (16.16 fixed)
	This only works when your image is scaled in the positive direction.
	This will go *really* slow.

For speed, I use fixed-point instead of floating-point.  For more info on
this, look around the internet.  (or I might soon have a fixed-point
tutorial, too)  Also for speed, I use pointers instead of array lookups to
access the image data.  For flexibility I've modified it slightly so that
you can use either positive or negative destination width/height.  This
allows us to "mirror" the image rather easily.

The other odd modification I made is somewhat harder to figure out.
Near the bottom of the loop is a section as follows:
    srcy += ystep;      // move through the source image...^M
    src += (srcy>>16)*srcwid;   // and possibly to the next row.^M
    srcy &= 0xffff;     // set up the y-coordinate between 0 and 1^M
This section really doesn't explain itself very well.  What this does,
though, is to figure out if we are still on the same row as last time
through the loop, and if so we move the source pointer accordingly.
If not, we add nothing to the source counter, and go back to the beginning
of the row (in the source image) we just drew.

What this accomplishes is that the pointer to the source image doesn't
more "horizontally", but only vertically.  The only time it changes is when
we move from one row to the next, and we'll just add the width of the image
in that case.  This also means we don't have to actually know where we
are in the source image, but only know how close we are to getting to the
next row.  (and so we repeatedly chop off the integer part of the source
y-coordinate with the "srcy &= 0xffff;" statement)


------------------------------------------------------------
Making images to scale (obvious plug for my paint program)
------------------------------------------------------------
Have you ever had problems finding a good 256-color paint program?

Well, try mine.  It's on my web site, and it's called "Digital Artist".
It works better (as far as I can tell) than the other stuff I've found.


-------------------------------------------
Please credit me for this if you use it...
-------------------------------------------


