This new section is for fancy graphic tricks, as seen in most demos. As always, please report any mistakes/improvements & if you have anything to add (C/C++ code please), email it to me.
Textured tunnels are simple to do if you know how. You need a 256x256 image and some pre-calculation! By pre-calculating Z coordinates for every screen pixel (used for the image y coordinate) & also calculating 0-255 angle values for each pixel (used for the image x coordinate), you can draw them quite fast, even in pure C code. The example code below is for a 480x480 pixel tunnel (try it in 640x480 mode).
//global variables needed
int *tz,*tx;
//I use 3600 angles for some reason!
float glcos3d[3600],glsin3d[3600];
//draw tunnel - (must do precalculations first)
//zd=z offset for tunnel, rot=rotation (0-255) offset
void DrawTunnel(int zd,int rot)
{
unsigned short *dst;//unsigned short for 16bit color (char for 256)
unsigned short *src=image_data;//point to 256x256 image data
int *iz=tz,*ix=tx;
int x,y;
for(y=0; y<480; y++) {
dst=glPTR+(y*glLINESTEP);//point to screen memory line y
x=480; while(x--){*dst++=src[((char)(*iz+zd)<<8)+(char)(*ix+rot)]; iz++; ix++;}
}
}
//pre-calculation
void InitTunnel(void)
{
float angle;
int a,x,y,n,xd;
//allocate memory for screen z and angle/x values
tz=(int *)malloc(480*480*4);
tx=(int *)malloc(480*480*4);
//fill in tables of Cos/Sine precalculations
for(a=0; a<3600; a++) //loop through all angles
{
angle=3600-a; if (angle>=3600) angle-=3600;
angle*=3.141592654/1800;
glcos3d[a]=cos(angle);
glsin3d[a]=sin(angle);
}
//get table of tunnel z values & angle/x (0-255) values
n=0;
for(y=0; y<480; y++) {
for(x=0; x<480; x++) {
//z (pic y)
xd=sqrt( ((x-240)*(x-240))+((y-240)*(y-240)) ); if (xd<1) xd=1;
tz[n]=((512*400)/xd)-512;
tz[n]>>=3;//scale down z values for better looking texturing
//ang (pic x)
xd=GetAngleFor(x-240,y-240);
tx[n]=(xd<<8)/3600; if (tx[n]>255) tx[n]=255;
//next -
n++;
}
}
}
//Rad's to 0-3600 degrees
#define RADTODEG 572.9578f
//return angle to point to target xdistance/ydist away
int GetAngleFor(float xd,float yd)
{
int ang;
yd=-yd;//convert from screen y
//if y dist.==0 return left or right
if (yd==0) {if (xd>0) return(900); else return(2700);}
if (xd==0) {if (yd>0) return(0); else return(1800);}
ang=atan(xd/yd)*RADTODEG;
//modify it for quarter that it is in
//91-179 181-269
if (yd<0) ang+=1800;//+180*10
while(ang<0) ang+=3600;
while(ang>=3600) ang-=3600;
return(ang);//return 0-3600 value
}