Introduction to 2D Linux Game Programming/Algorithms/Simple Software Transformations/Non Optimized Integer Scaling

From Wikibooks, open books for an open world
Jump to navigation Jump to search

Non-optimized Integer Scaling[edit | edit source]

Introduction[edit | edit source]

This algorithm demonstrates scaling an image by one positive integer value in both the x and y axis. A common use for this algorithm would be taking a game made for a GameBoy's low resolution screen and doubling or tripling it before displaying it on a PC's high resolution monitor.

This algorithm keeps the aspect ratio of the original image. Think of watching old TV shows on a widescreen monitor. You can either stretch the image to fit the screen, distorting the original image and making all the actors appear fatter, or you can watch in the original aspect ratio, but then you have black bars on either side of the screen. With this algorithm you'd have the black bars. Princess Peach won't have to worry about why she's gained so much weight!

To understand how this algorithm works, it's important to know how most libraries store image data in memory. Where an image is a two dimensional object, most libraries store the individual pixels of the image in a single dimensional array - a line. The game has to keep track of the height of the image and its width to manipulate the image. Some libraries, like SDL, hide this from you until you need to do something like rotate or scale the image.

Setting up the Problem[edit | edit source]

To show how this works, we'll scale one 3x3 image. In the following images, each square will represent a single pixel.

012
345
678


Stored in an array, that image looks like:

012345678


If you're trying to come up with an algorithm, it's handy to step through the problem a piece at a time. The first thing we're going to do is copy the first pixel three times:

   


We need to continue copying 3 pixels for every pixel in the source image until we hit the end of the row to properly scale the width of the image:

         


Then we need to repeat this 3 times to properly scale the height of the image:

                           


Which drawn on the screen looks like:

         
         
         

The Source:[edit | edit source]

// IntegerScaleNonOptimized.cpp

#include  <iostream>
#include "include/S.h"
using namespace std;

/********************************************
 *
 * This is an image scaling algorithm.  It 
 * will scale an image in an array by a
 * positive integer value.
 *
 * It keeps the original image's aspect ratio.
 * If the original aspect ration was 4:3 and
 * you have a wide screen monitor, there
 * will be black vertical bars on either side
 * of the screen.  The image will not be distorted.
 * Princess Peach won't have to worry about why 
 * she's suddenly so much wider.  :b
 *
 * It makes an array that is width*height sized.
 * It initializes every element in the array 
 * with its array position.
 *
 * Then it makes a second array that
 * is width*scale * height*scale sized.
 *
 * It prints the first array, a couple newlines,
 * then it scales and prints the second array.
 *
 ********************************************/

int main()
{
	int width  = S::sw();    // The original Array's width
	int height = S::sh(width);   // The original Array's height
	int scale = S::ss(width);
	int source[height*width]; // Original Array
	int dest[height*scale * width*scale]; // Dest Array

	cout << "\n\n";

/*********************************************
 * The source array
 *
 * This loop constructs an "image" with a
 * unique color in each position of the array,
 *
 * width * height is the integral statement
 * here.  If width is set to 3 and height is
 * set to 3 it creates an array[9] that has
 * 9 elements, starting with element 0 and
 * continuing to element 8.
 *********************************************/
	for(int x = 0; x < width*height; x++)
		source[x]=x;

	S::print_rect(width,height,&source[0]);
	cout << "\n\n";



/*********************************************
 * The destination, scaled array
 *
 * In games most 2 dimmensional images are
 * stored in a one dimmensional array.
 *
 * A four color image
 * 0,1
 * 2,3

 * that that's been scaled up
 * by two looks like:
 *      0,0,1,1
 *      0,0,1,1
 *      2,2,3,3
 *      2,2,3,3
 * when print_rected
 *
 * and is stored in the array as:
 *      [0,0,1,1,0,0,1,1,2,2,3,3,2,2,3,3]
 *
 *********************************************/

	for(int h = 0; h < height; h++) // Source Height Position
	{
		for(int hrepeat = 0; hrepeat < scale; ++hrepeat) // Repeat a full row scale times
		{
			for(int w = 0; w < width; w++) // Source width Offset
			{
				// Repeat individual pixel scale times
				// See the tutorial for an explanation of this line.
				for(int wrepeat = 0; wrepeat < scale; wrepeat++)
					dest[ ((h*scale * width*scale) + (hrepeat * width*scale)) + (w*scale + wrepeat)] = source[(h*width) + w];
			}
		}
	}

	S::print_rect(width*scale,height*scale,&dest[0]);

	cout << "\n";
	return(0);
}