Sonic and Sega Retro Message Board: outrun-style road generation tutorial - Sonic and Sega Retro Message Board

Jump to content

Hey there, Guest!  (Log In · Register) Help
Page 1 of 1
    Locked
    Locked Forum

outrun-style road generation tutorial figured someone might be interested

#1 User is offline Cooljerk 

Posted 21 May 2014 - 12:20 PM

  • NotEqual Tech, Inc - VR & Game Dev
  • Posts: 4202
  • Joined: 06-April 06
  • Gender:Male
  • Wiki edits:9
've been working on building a sprite-based 3d engine (think galaxy force 2) and was looking around for some help with the math for my projection when I found this site:

http://www.extentofthejam.com/pseudo/

Did a quick search and didn't find it'd ever been posted here. It's a break down of the math and logic behind outrun style roads, going into detail about hardware specific methods of implementation. Really good read, it appears the author consulted the researchers behind cannonball to make sure a lot of their math is accurate.

Might be helpful for anybody attempting to make a 3d engine without using any 3d hardware or libraries.

#2 User is offline Aerosol 

Posted 21 May 2014 - 02:54 PM

  • FML and FU2
  • Posts: 10162
  • Joined: 27-April 08
  • Gender:Male
  • Location:Not where I want to be.
  • Project:Sonic (?): Coming summer of 2055...?
I saw that page a long time ago. I was a little disappointed that he had removed the source code.
This post has been edited by Aerosol: 21 May 2014 - 02:54 PM

#3 User is offline Cooljerk 

Posted 21 May 2014 - 03:38 PM

  • NotEqual Tech, Inc - VR & Game Dev
  • Posts: 4202
  • Joined: 06-April 06
  • Gender:Male
  • Wiki edits:9

View PostAerosol, on 21 May 2014 - 02:54 PM, said:

I saw that page a long time ago. I was a little disappointed that he had removed the source code.


Cannonball run is open source, and I would expect it behaves similar to the methods he describes.

Regardless, here's some allegro code that works very similarly:

#include "allegro.h"
#include <math.h>

void DrawPerspective(BITMAP *t, BITMAP *tex, int y1, float z1, int y2, float z2, float x, float xmul, float ymul, float texoff)
{
	float curvdiv = z1/(3.141592654f*0.5f);
	float zpos = 1.0f /z2;
	z1 = 1.0f / z1;


	/* sample 16 times for each scanline */
	y1 <<= 4;
	y2 <<= 4;
	ymul *= 16.0f;

	int BottomY = y2;
	float zadd = (z1 - zpos) / (float)(y2 - y1);
	while(y2 > y1)
	{
		float z = 1.0f / zpos;

		/*
			NOTE: z is the actual depth of this scanline, zpos is 1/z. The most common
			perspective projection formula is used, I.e.

			transformed_x = (centre of screen) - (half width of screen)*(x / z)

			But instead of dividing by z we can multiply by zpos if we like.
		*/
		float centx = x + xmul*(cos(z/curvdiv) - 1.0f);
		int topy = y2 + (SCREEN_H >> 1)*(ymul*(cos(z/curvdiv) - 1.0f) / z);

		if((topy >> 4) < (BottomY >> 4)) /* question is: are we at least one pixel line above what was last drawn ? */
		{
			stretch_blit(tex, t, 0, (int)((z+texoff)*4.0f)&(tex->h-1), tex->w, 1, (SCREEN_W >> 1) + (SCREEN_W >> 1)*(centx-1.0f)*zpos, (topy) >> 4, (SCREEN_W >> 1)*(2.0f)*zpos, (BottomY >> 4) -(topy >> 4));
			BottomY = topy;
		}

		zpos += zadd;
 		y2--;
	}
}

int main(int argc, const char *argv[])
{
	allegro_init();
	install_keyboard();

	if (set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0)) {
		allegro_message("Error setting 640x480 gfx mode:\n%s\n", allegro_error);
		return -1;
	}
	BITMAP *back = create_bitmap(SCREEN_W, SCREEN_H);

	/* obviously it would be better to load a road texture here, but we'll just generate a chequered
	pattern ... */
	BITMAP *tex = create_bitmap(8, 2);
	int xp, yp;
	for(xp = 0; xp < tex->w; xp++)
		for(yp = 0; yp < tex->h; yp++)
			putpixel(tex, xp, yp, (xp+yp)&1 ? makecol(255, 255, 255) : makecol(0, 0, 0));

	/* seed some variables */
	float x = 0, xmul = 0, ymul = 0, z = 0;

	while(!key[KEY_ESC])
	{
		clear_to_color(back, makecol(0, 0, 0));
		DrawPerspective(back, tex, SCREEN_H >> 1, 20, SCREEN_H, 1, x, xmul, ymul, z);
		blit(back, screen, 0, 0, 0, 0, back->w, back->h);
		
		if(key[KEY_LEFT]) x+= 0.05f;
		if(key[KEY_RIGHT]) x-= 0.05f;
		if(key[KEY_UP]) z+= 0.05f;
		if(key[KEY_DOWN]) z-= 0.05f;

		if(key[KEY_P]) xmul-= 0.1f;
		if(key[KEY_O]) xmul+= 0.1f;
		if(key[KEY_A]) ymul-= 0.1f;
		if(key[KEY_Q]) ymul+= 0.1f;
	}

	destroy_bitmap(back);
	destroy_bitmap(tex);
	return 0;
}
END_OF_MAIN()


produces this:

Posted Image

Courtesy of Thomas Harte over at gamedev.net

#4 User is offline Billy 

Posted 21 May 2014 - 05:53 PM

  • RIP Oderus Urungus
  • Posts: 1823
  • Joined: 24-June 05
  • Gender:Male
  • Location:Colorado, USA
  • Project:Indie games
  • Wiki edits:15
Very interesting! I myself and pretty fascinated by pre-polygon 3D. I'm making a Wolfenstein 3D raycaster style game.

#5 User is offline Cooljerk 

Posted 21 May 2014 - 08:08 PM

  • NotEqual Tech, Inc - VR & Game Dev
  • Posts: 4202
  • Joined: 06-April 06
  • Gender:Male
  • Wiki edits:9

View PostBilly, on 21 May 2014 - 05:53 PM, said:

Very interesting! I myself and pretty fascinated by pre-polygon 3D. I'm making a Wolfenstein 3D raycaster style game.


I've never actually made a raycaster game myself, although I've studied the logic behind them. Sounds like a neat project, do you maintain a blog or anything? I'd love to read your progress.

#6 User is offline Billy 

Posted 21 May 2014 - 09:15 PM

  • RIP Oderus Urungus
  • Posts: 1823
  • Joined: 24-June 05
  • Gender:Male
  • Location:Colorado, USA
  • Project:Indie games
  • Wiki edits:15
I post updates on twitter sometimes. To be fair, the actual raycasting part isn't really the hard part, the game logic is; my game runs really slow right now There's a really good tutorial on raycasting here.

#7 User is online ICEknight 

Posted 22 May 2014 - 01:46 PM

  • Posts: 11205
  • Joined: 11-January 03
  • Gender:Male
  • Location:Spain
  • Wiki edits:18
I'm surprised that the linked page didn't examine OutRun 2016. That game featured some really cool intertwined roads.

Page 1 of 1
    Locked
    Locked Forum

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users