Rusty Axe Games, home of Real E$tate Empire and Battle Castles

News
Casual Arcade
Shooters
Time Management
Seek And Find
Strategy
RPG
Toons Online
Rusty Blog
About Rusty Axe

Real E$tate Empire, a real estate simulation game
Shadow Armies fiction Domain of Heroes
Your ad here!
Share
<--! style: inset; border-color: black black black black; border-width: 3px; background-color: #000000">
Roto Zoomer - The Source!
February 13th, 2009


Happy Friday the 13th! If you are looking for source code to a roto zoomer (as I was last weekend) then this is actually your lucky day! The following may have to be massaged a bit for your system - rotoZoom gets passed in a sprite structure that I use for my games - but it's pretty straight forward stuff and weighs in under 300 lines. Let me know if you make it better as I would like a copy!

RotoZoomer.h

#ifndef ROTO_ZOOMER_H

#define	ROTO_ZOOMER_H

typedef enum
{
	RFX_SIMPLE,		//no mod's, blit all non-transparent
	RFX_ALPHA_BLEND,	//alpha blend w/background
	RFX_ALPHA_ACCEPT,	//for sprite building, just set alpha from texture, no bg blend
}RFX;

typedef	struct
{
	F32	x, y;
}Pt;


typedef struct
{
	Pt	p[4];
}Quad;

typedef struct
{
	F32	tx, ty;
	S32	x;
}Tpt;


extern void rotZoomQuad( Quad *q,
  S32	  _x,
  S32	  _y,
  SprEntry *tex,
  F32      rot,
  F32 	  zoom
);
extern void rotoZoom( U32 *dest,
  U32		dest_wd,
  S32		_x,
  S32		_y,
  SprEntry	*tex,
  F32		rot,
  F32		zoom,
  RFX		render_mods
);
extern void rotoZoomerTest(void);



#endif



RotoZoomer.cpp

#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include "blit.h"
#include "rotoZoomer.h"
#include "main.h"


static	Tpt	min[SCRN_HT], max[SCRN_HT];
static	Bool	initted[SCRN_HT];


S32 minY( Quad *q )
{
	S32	i,y=q->p[0].y;

	for(i=1;i<4;i++)
		if( q->p[i].y < y )
			y = q->p[i].y;

	return y;
}

S32 maxY( Quad *q )
{
	S32	i,y=q->p[0].y;

	for(i=1;i<4;i++)
		if( q->p[i].y > y )
			y = q->p[i].y;

	return y;
}


void traverse(	Pt	*p0,
			Pt	*p1,
			F32	tx0,
			F32	ty0,
			F32	tx1,
			F32	ty1
		)
{
	F32		pdx, pdy, tdx, tdy, len;
	F32		fy = p0->y;
	F32		fx = p0->x;
	F32		tx = tx0;
	F32		ty = ty0;

	len = (S32)(p1->y - p0->y);

	if( len < 0 )
		len = -len;

	pdx = (p1->x - p0->x) / len;
	pdy = (p1->y - p0->y) / len;

	tdx = (tx1 - tx0) / len;
	tdy = (ty1 - ty0) / len;

	S32	dy, y = (S32)fy;

	if( pdy < 0 )
		dy = -1;
	else dy = 1;

	do
	{
		if( y >=0 && y < SCRN_HT )
		{
			if( fx < 0 || fx >=800)
			{
				int	halt = 1;
			}

			if( !initted[y] )
			{
				min[y].x	= fx;
				min[y].tx	= tx;
				min[y].ty	= ty;
				max[y].x	= fx;
				max[y].tx	= tx;
				max[y].ty	= ty;
				initted[y]	= TRUE;
			}
			else
			{
				initted[y]++;
				if( fx < min[y].x )
				{
					min[y].x	= fx;
					min[y].tx	= tx;
					min[y].ty	= ty;
				}
				else if( fx > max[y].x )
				{
					max[y].x	= fx;
					max[y].tx	= tx;
					max[y].ty	= ty;
				}
			}
		}

		tx += tdx; ty += tdy;
		fx += pdx; y+=dy;
		
	}while(len--);
}


void polyRender(	U32		*dest,
			U32		dest_wd,
			Quad		*q,
			SprEntry	*tex,
			RFX		rfx
		)
{
	S32	y0, y1, y, ht;

	y0 = minY(q);
	y1 = maxY(q);
	ht = y1-y0;
	memSet( &initted[y0], 0, ht * sizeof(S32));

	//traverse goes over the edge of each line and collects end points in an array
	traverse( &q->p[0], &q->p[1], 0,0,					tex->wd, 0 );
	traverse( &q->p[1], &q->p[2], tex->wd,0,			tex->wd, tex->ht );
	traverse( &q->p[2], &q->p[3], tex->wd, tex->ht,		0, tex->ht );
	traverse( &q->p[3], &q->p[0], 0,tex->ht,			0, 0 );

	for(y=y0;y= CLIP_WDW_TOP && ypix;
			S32	len, x = min[y].x;

			len = max[y].x - min[y].x;			//length of pixel run.

			tdx = (max[y].tx - min[y].tx)/(F32)len;
			tdy = (max[y].ty - min[y].ty)/(F32)len;

			tx = (U32)min[y].tx;
			ty = (U32)min[y].ty;

			while(len-- && x < CLIP_WDW_RIGHT)
			{
				if(	x++ >= CLIP_WDW_LEFT )
					if( tx >= 0 && ty >= 0 && tx < tex->wd && ty < tex->ht )
					{
						U32	pix = *(tp + (U32)ty * tex->wd + (U32)tx);

						if( rfx == RFX_SIMPLE )
						{
							if( pix & 0xff000000 )	//no alpha blend
								*base = pix;
						}
						else if( rfx == RFX_ALPHA_BLEND )
						{
							U32	alpha = (pix & 0xff000000) >> 24;
							U32	r, bg_r, g, bg_g, b, bg_b, bg = *base;

							r		= pix & 0x000000ff;
							bg_r	= bg & 0x000000ff;
							r *= ( alpha);
							bg_r *= ( 255 - alpha );
							r = ( r + bg_r + 1 ) >> 8;

							g		= ( pix & 0x0000ff00 ) >> 8;
							bg_g	= ( bg & 0x0000ff00 ) >> 8;
							g *= ( alpha);
							bg_g *= ( 255 - alpha );
							g = ( g + bg_g + 1 ) >> 8;

							b		= ( pix & 0x00ff0000 ) >> 16;
							bg_b	= ( bg & 0x00ff0000 ) >> 16;
							b *= ( alpha);
							bg_b *= ( 255 - alpha );
							b = ( b + bg_b + 1 ) >> 8;

							if( r > 255 )
								r = 255;
							else if( r < 0 )
								r = 0;
							if( g > 255 )
								g = 255;
							else if( g < 0 )
								g = 0;
							if( b > 255 )
								b = 255;
							else if( b < 0 )
								b = 0;

							*base = r | ( g << 8 ) | ( b << 16 );
						}
						else if( rfx == RFX_ALPHA_ACCEPT )	//take alpha channel
						{		//from texture, useful for pre-building sprites.
							*base = pix;
						}
					}

				base++;
				tx += tdx;
				ty += tdy;
			}
		}
}



void rotZoomQuad(	Quad		*q,
			S32		_x,
			S32		_y,
			SprEntry	*tex,
			F32		rot,
			F32		zoom
		)
{
	q->p[0].x	= tex->hot_x;		//ul
	q->p[0].y	= tex->hot_y;
	q->p[1].x	= q->p[0].x + tex->wd;	//ur
	q->p[1].y	= q->p[0].y;
	q->p[2].x	= q->p[1].x;		//dr
	q->p[2].y	= q->p[1].y + tex->ht;	
	q->p[3].x	= q->p[0].x;		//dl
	q->p[3].y	= q->p[2].y;

	S32	i;

	for(i=0;i<4;i++)
	{
		F32	x, y;

		x = q->p[i].x;
		y = q->p[i].y;

		q->p[i].x = _x + (zoom * (x * cos(rot) - y * sin(rot)));
		q->p[i].y = _y + (zoom * (x * sin(rot) + y * cos(rot)));
	}
}



void rotoZoom(	U32		*dest,
			U32		dest_wd,
			S32		_x,
			S32		_y,
			SprEntry	*tex,
			F32		rot,
			F32		zoom,
			RFX		render_mods
		)
{
	Quad	q;

	rotZoomQuad( &q, _x, _y, tex, rot, zoom );

	//quad has been transformed and scaled, now texture render the quad.
	polyRender( dest, dest_wd, &q, tex, render_mods );
}	



Well, that's it. I've been using it for several days and it seems solid. I've noticed a little artifacting when rotating small text strings and if I find a way to make it better then I will update the source.

Have a good weekend,
L.

No comments have been provided.





Your Name:

Your Location:

Country (flag):

Article Rating:

Your Comments:

Security check *