// Pseudo-Mode-7!
/* written in August 2012 by Tommy - "tommy.draeger@googlemail.com" */
#include <acknex.h>
#include <litec.h>
#define xres 320
#define yres 240
BMAP* blank_16;
BMAP* blank_32;
BMAP* sphere = "...";
BMAP* displace = "...";
BMAP* background = "...";
PANEL* framebuffer = { layer = 10; flags = VISIBLE; }
PANEL* framedepth = { layer = 11; flags = VISIBLE; }
PANEL* obj_01 = { layer = 12; flags = VISIBLE | OVERLAY; bmap = sphere; }
function mode_7_level(BMAP* screen, BMAP* source, BMAP* distfog, BMAP* backdrop);
function mode_7_sprite(PANEL* sprite,int px, int py, float obj_dir, float obj_org);
typedef struct /* MODE 7 SETTINGS */
{
int foclength;//FOCALLENGTH
int horizon;
int scale;//SCALEFACTOR FOR LEVELGROUND
int obj_scale;//SCALEFACTOR FOR SPRITES
}M7_OPT;
//THESE ARE VALUES THAT WORKS FINE FOR
//ME AT A RESOLUTION OF 320 X 240
M7_OPT* m7 =
{
foclength = 400;
horizon = 80;
scale = 60;
obj_scale = 15;
}
float angle = 0;
float xOffset = 0;
float yOffset = 0;
//SCREEN AND DISTFOG ARE THE BMAPS
//TO DRAW ON. THE OTHERS SERVES AS
//LEVELGROUND AND SKYBACKDROP
function mode_7_level(BMAP* screen, BMAP* source, BMAP* distfog, BMAP* backdrop)
{
fixed count;
DWORD blend;
int x,y;
//FRAME
int frm;
//JUST FOR PERFORMANCE IMPROVEMENT
int dx,dy;
int mask_x,mask_y;
int mask_x_backdrop;
float space_x, space_y, space_z;
float screen_x, screen_y;
float px, py, pz;
float sx, sy;
mask_x = bmap_width(source) -1;
mask_y = bmap_height(source) -1;
mask_x_backdrop = bmap_width(backdrop) -1;
while(1)
{
//STEERING
angle += (key_cur - key_cul)*time_step / 15;
xOffset += (key_cuu - key_cud)*sin(angle)*time_step*8;
yOffset -= (key_cuu - key_cud)*cos(angle)*time_step*8;
bmap_lock(screen,4444);
bmap_lock(source,888);
bmap_lock(distfog,4444);
bmap_lock(backdrop,888);
for(y = -yres/2; y < yres/2; y++)
{
dy = y+yres/2;
//"BLEND" HOLDS THE ALPHAVALUE
//FOR THE DISTANCE-FOGGING
blend = ((dy)-60) * -100/110 - 10;
blend = clamp(blend,-100,0);
//JUST TO CREATE A NON-LINEAR EFFECT
//505 WAS DETERMINE BY ME
blend &= 505;
//MAKE A SLICE AT 70
//TO RENDER THE BACKDROP
if(y >= (-yres/2)+70)
{
for(x = -xres/2; x < xres/2; x++)
{
dx = x+xres/2;
/******* ACTUAL MODE 7 EFFECT ********/
//ASSIGN SOME TEMPVARS FOR
//A BETTER OVERVIEW
px = x;
py = y + m7.foclength;
pz = y + m7.horizon;
//MATHEMATICAL PROJECTION
//FOR TURNING A 3D POINT TO
//A 2D SCREENPIXEL
//Y STANDS FOR Z RESP. THE DEPTH
space_x = px / pz;
space_y = py / pz * -1;
//INVERT THE Y DIRECTION
//SO THAT EVERTHING IS
//IN A CORRECT WAY
//A TRIGONOMETRIC EQUATION TO BE ABLE
//TO ROTATE THE BMAP SO YOU CAN
//LOOK AROUND 360°
screen_x = space_x * cos(angle) - space_y * sin(angle);
screen_y = space_x * sin(angle) + space_y * cos(angle);
//FINAL TRANSFORMATION AND SCALING
sx = screen_x * m7.scale + xOffset;
sy = screen_y * m7.scale + yOffset;
//USE THE AND-OPERATOR TO CREATE AN INFINTIY-PATTERN
pixel_to_bmap(screen,dx,dy,pixel_for_bmap(source,(int)sx & mask_x,(int)sy & mask_y)+0x001200);
pixel_to_bmap(distfog,dx,dy,pixel_for_vec(vector(240,254,160),blend,8888));
/***************************************/
}
}
else
{
for(x = 0; x < xres; x++)
pixel_to_bmap(screen,x,dy,pixel_for_bmap(backdrop,(int)(x+angle*200) & mask_x_backdrop,dy));
}
}
//EVERYTIME YOU WANT TO ADD AN OBJECT YOU'VE
//TO PLACE A NEW MODE_7_SPRITE FUNCTION HERE
//IT'S PLACED HERE BECAUSE OF THE PERFORMANCE
mode_7_sprite(obj_01, 10 , -100 );
bmap_unlock(backdrop);
bmap_unlock(distfog);
bmap_unlock(source);
bmap_unlock(screen);
//THE NEXT LINES AREN'T NECESSARY
//THESE JUST CREATING AN ANIMATED
//WATERSURFACE, YOU CAN DELETE
//THESE IF YOU LIKE
//*******//
count += (int)4*time_step;
if(count > 10){count %= 10;frm++;}
if(frm >= 7)frm = 0; //if(frm == 7)frm %= 7; //frm &= 7;
switch(frm)
{
case 0:bmap_purge(source);
case 1:bmap_load(source,"...",0);
case 2:bmap_load(source,"...",0);
case 3:bmap_load(source,"...",0);
case 4:bmap_load(source,"...",0);
case 5:bmap_load(source,"...",0);
case 6:bmap_load(source,"...",0);
case 7:bmap_load(source,"...",0);
}
//*******//
wait(1);
}
}
function mode_7_sprite(PANEL* sprite, int px, int py, float obj_dir, float obj_org)
{
float width, height;
float space_x, space_y;
float screen_x, screen_y;
float obj_x = px + xOffset;
float obj_y = py - yOffset;
//EQUATIONS STANDS IN EVERY FORMULARY
float distance = sqrt(pow(obj_x,2)+pow(obj_y,2));
space_x = obj_x * cos(angle) - obj_y * sin(angle);
space_y = obj_x * sin(angle) + obj_y * cos(angle);
//SPACE_Y IS THE DEPTH
//IF YOU WANT TO REPRODUCE THESE EQUATION JUST LOOK
//FOR "MATHEMATICAL PROJECTION" RESP. "SIMILAR TRIANGLES"
screen_x = xres/2 + (space_x * m7.foclength) / space_y;
screen_y = (m7.foclength / space_y) + m7.horizon - 10;
//CALCULATE THE NEW HEIGHT:
//INVERSELY PROPORTIONAL TO THE
//DISTANCE
height = (m7.scale / distance);
width = (m7.scale / distance);
sprite.scale_x = width;
sprite.scale_y = height;
sprite.pos_x = screen_x - (width*sprite.size_x/2);
sprite.pos_y = screen_y + (height*sprite.size_y/2);
//JUST A SMALL SOLUTION FOR CULLING
//SO YOU DOESN'T SEE THE SPRITE TWICE
//CONVERT VECTOR TO +-180 ANGLE
vec_to_angle(obj_dir,vector(space_x,space_y,0));
vec_to_angle(obj_org,vector(px,py,0));
//CONVERT +-180 ANGLE TO 0...360 ANGLE
obj_dir = cycle(obj_dir,0,360);
obj_org = cycle(obj_org,0,360);
//DETERMINE WHETER THE OBJECT IS IN EYESIGHT
if(obj_dir > (obj_org - 90) && obj_dir < (obj_org + 90)) { sprite.flags |= VISIBLE; }
else { sprite.flags &= ~VISIBLE; }
return;
}
function main()
{
level_load("");
wait(2);
video_set(xres,yres,16,0);
//CREATE TWO BLANK BMAPS FOR THE SCREEN
//AND THE DISTANCE FOGGING (BECAUSE OF
//THE TRANSPERANTY WE WANT TO USE)
blank_16 = bmap_createblack(xres, yres, 16);
blank_32 = bmap_createblack(xres, yres, 32);
framebuffer.bmap = blank_16;
framedepth.bmap = blank_32;
//fps_max = 20;
mode_7_level(blank_16, displace, blank_32, background);
}