Skip to content

Instantly share code, notes, and snippets.

@gnilk
Created January 18, 2024 15:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gnilk/91d68816127237efadf439e32f57943a to your computer and use it in GitHub Desktop.
Save gnilk/91d68816127237efadf439e32f57943a to your computer and use it in GitHub Desktop.
ETS - VoxelPoly
// PVoxelPoly.cpp: implementation of the PVoxelPoly class.
//
// gnilk, 2024-01-18,
// this is dump of the VoxelPolygon part in Enlight the Surreal by Noice from 2000
// note: this won't compile, it is more for completness of the algorithm used
//
//
//////////////////////////////////////////////////////////////////////
#include "PVoxelPoly.h"
#include "../kfx/kfx.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#include "goa/goa.h"
#include <math.h>
static GOA_RGBA col_BLACK = {0,0,0,0};
#if !defined(M_PI)
#define M_PI 3.1415926535897932384
#endif
typedef struct
{
float val[8];
} SCAN;
static SCAN *screen_start,*screen_end;
static int slice_len=32;
static int fade_off=0;
static int e_fade = 0;
static float e_fade_t = 0;
static float fade_ypos=-240;
static float fade_y_t=0;
static float slice_scale = 32.0f;
static float xv=0,yv=0,zv=0,secs = 0;
static float pack1[10],pack2[10],pack3[10],pack4[10];
static GOA_VECTOR cube_dst[8];
static GOA_VECTOR cube_src[]=
{
-32,-32,32, 32,-32,32, 32,32,32, -32,32,32,
-32,-32,-32, 32,-32,-32, 32,32,-32, -32,32,-32
};
typedef struct
{
int yofs;
int xofs;
GOA_RGBA col;
int zval;
} SPIXEL;
static SPIXEL *parray;
static int num_parray;
static int ceil2 (int a)
{
a+=0xffff;
return (a >> 16);
}
static void calc_subpixel (float *dst, float s, float *src, int num)
{
int i;
for (i=0;i<num;i++)
dst[i] += (ceil2(s * (1 << 16)) - s) * src[i];
}
static void m_outline(SCAN *uptab, SCAN *downtab, float *pa1, float *pa2, int n,int min_h,int max_h)
{
int i,j;
float *a1=pa1;
float *a2=pa2;
float add_val[8],start[8];
SCAN *tab=downtab;
float deltay;
if (a1[1]==a2[1]) return;
if (a1[1]>a2[1])
{
float *tmp;
tmp = a1;
a1 = a2;
a2 = tmp;
tab=uptab;
}
deltay=a2[1] - a1[1];
if ((int)deltay == 0) return;
for (i=j=0;i<n;i++)
{
if (i!=1)
{
add_val[j] = (a2[i] - a1[i]) / deltay;
start[j]=a1[i];
j++;
}
}
calc_subpixel (start,a1[1],add_val,n-1);
for (i=a1[1]; i<=a2[1]; i++)
{
for (j=0;j<n-1;j++)
{
if ((i>min_h) && (i<max_h))
tab[i].val[j]=start[j];
start[j] += add_val[j];
}
}
}
static void tscanline (GOA_PIXMAP *dest, GOA_PIXMAP *texture, GOA_PIXMAP *hmap, int y, float *pa1, float *pa2,int n)
{
float deltax,add_val[8],start[8];
float *a1=pa1,*a2=pa2;
int i,j,tx,ty,tofs,yofs;
yofs = y*dest->width;
if (pa1[0] == pa2[0]) return;
if (pa1[0] > pa2[0])
{
a1 = pa2;
a2 = pa1;
}
deltax=a2[0] - a1[0];
if ((int)deltax == 0) return;
if (deltax > 16)
{
for (i=j=0;i<n;i++)
{
if (i!=0)
{
add_val[j] = (a2[i] - a1[i]) / deltax;
start[j]=a1[i];
j++;
}
}
calc_subpixel (start,a1[1],add_val,n-1);
for (i=a1[0];i<=a2[0];i++)
{
if ((i>0))
{
tx = start[1];
ty = start[2];
ty *= 256;
tofs = (tx&0xff)+(ty&0xff00);
parray[num_parray].yofs = yofs;
parray[num_parray].xofs = i;
parray[num_parray].col = texture->image[tofs];
parray[num_parray].col.a = hmap->image[tofs].r;
parray[num_parray].zval = (int)start[0];
num_parray++;
}
for (j=0;j<n-1;j++)
start[j]+=add_val[j];
}
} else
{
float xp,xa;
deltax = 16;
for (i=j=0;i<n;i++)
{
if (i!=0)
{
add_val[j] = (a2[i] - a1[i]) / deltax;
start[j]=a1[i];
j++;
}
}
calc_subpixel (start,a1[1],add_val,n-1);
xp = a1[0];
xa = (a2[0] - a1[0])/16.0;
for (i=0;i<=16;i++)
{
if ((i>0))
{
tx = start[1];
ty = start[2];
ty *= 256;
tofs = (tx&0xff)+(ty&0xff00);
parray[num_parray].yofs = yofs;
parray[num_parray].xofs = xp;
parray[num_parray].col = texture->image[tofs];
parray[num_parray].col.a = hmap->image[tofs].r;
parray[num_parray].zval = (int)start[0];
num_parray++;
}
xp += xa;
for (j=0;j<n-1;j++)
start[j]+=add_val[j];
}
}
}
#ifndef min
#define min(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef max
#define max(a,b) ((a)>(b)?(a):(b))
#endif
static void drawquad_hmap (GOA_PIXMAP *dest, GOA_PIXMAP *texture, GOA_PIXMAP *hmap, float *a1, float *a2, float *a3, float *a4,int hval)
{
float p1[8],p2[8],p3[8],p4[8];
int y_start,y_end,i;
y_start = min (a1[1],a2[1]);
y_start = min (y_start,a3[1]);
y_start = min (y_start,a4[1]);
y_end = max (a1[1],a2[1]);
y_end = max (y_end,a3[1]);
y_end = max (y_end,a4[1]);
if (y_end < 0) return;
if (y_start > dest->height) return;
m_outline (screen_start,screen_end,a1,a2,5,0,dest->height);
m_outline (screen_start,screen_end,a2,a3,5,0,dest->height);
m_outline (screen_start,screen_end,a3,a4,5,0,dest->height);
m_outline (screen_start,screen_end,a4,a1,5,0,dest->height);
if (y_start<0)
y_start = 0;
if (y_end > dest->height) y_end = dest->height;
num_parray = 0;
for (i=y_start;i<y_end;i++)
tscanline (dest,texture,hmap,i,screen_start[i].val,screen_end[i].val,4);
}
static int draw_parray (GOA_PIXMAP *dest, GOA_PIXMAP *texture, GOA_PIXMAP *hmap,int h,int ox,int oy,int oya,int oxa, int za)
{
int i,sofs,sofs2,xo,yo,twh,num;
int *zbuffer = dest->zbuffer;
GOA_RGBA *dst = dest->image;
num = 0;
twh=dest->height * dest->width;
for (i=0;i<num_parray;i++)
{
xo = parray[i].xofs + ox;
yo = oy+parray[i].yofs;
sofs = xo+yo;
if (zbuffer[sofs] > (parray[i].zval + za))
{
if (parray[i].col.a > h)
{
zbuffer[sofs] = parray[i].zval+za;
sofs2 =oya+parray[i].yofs + oxa+parray[i].xofs;
dst[sofs] = parray[i].col;
dst[sofs2] = parray[i].col;
parray[num] = parray[i];
num++;
}
} else
{
parray[num] = parray[i];
num++;
}
}
return num_parray;
}
void voxpoly_drawquad (GOA_PIXMAP *dest, GOA_PIXMAP *texture, GOA_PIXMAP *hmap, float *a1, float *a2, float *a3, float *a4,GOA_VECTOR *normal)
{
GOA_VECTOR vadd[4];
int i;
int xa,ya,za;
int xp,yp,zp,oxp,oyp;
xp = yp = zp = oxp = oyp = 0;
xa = (int)((65536.0f * slice_scale * normal->x/(float)slice_len));
ya = (int)((65536.0f * slice_scale * normal->y/(float)slice_len));
za = (int)((65536.0f * slice_scale * normal->z/(float)slice_len));
num_parray = 0;
drawquad_hmap (dest,texture,hmap,a1,a2,a3,a4,0);
if (num_parray > 0)
{
for (i=0;i<slice_len;i++)
{
if ((num_parray = draw_parray (dest,texture,hmap,i*(256/slice_len),xp>>16,(yp>>16)*dest->width,oxp>>16,(oyp>>16)*dest->width,zp>>16))==0) return;
oxp = xp + 0.5*xa;
oyp = yp + 0.5*ya;
xp += xa;
yp += ya;
zp += za;
}
}
}
static void voxpoly_setscale (float scale)
{
slice_scale = scale;
}
static void voxpoly_setslice (int slice)
{
slice_len = slice;
}
static int voxpoly_init (int width,int height)
{
if ((parray = (SPIXEL *)gmalloc (sizeof (SPIXEL) * (width * height)))==NULL) return 0;
if ((screen_start = (SCAN *)gmalloc (sizeof (SCAN) * height))==NULL) return 0;
if ((screen_end = (SCAN *)gmalloc (sizeof (SCAN) * height))==NULL) return 0;
return 1;
}
static void draw_face (GOA_PIXMAP *dest,GOA_PIXMAP *texture, GOA_PIXMAP *hmap, int a, int b, int c, int d)
{
GOA_VECTOR normal,v1,v2;
gmemcpy4 (pack1,&cube_dst[a],3);
gmemcpy4 (pack2,&cube_dst[b],3);
gmemcpy4 (pack3,&cube_dst[c],3);
gmemcpy4 (pack4,&cube_dst[d],3);
pack1[3] = pack1[4] = 0;
pack2[3] = 255;
pack2[4] = 0;
pack3[3] = 255;
pack3[4] = 255;
pack4[3] = 0;
pack4[4] = 255;
goa_vector_cross (&normal,goa_vector_sub (&v2,&cube_dst[c],&cube_dst[a]),goa_vector_sub (&v1,&cube_dst[b],&cube_dst[a]));
goa_vector_normalize (&normal,&normal);
if (normal.z > 0) voxpoly_drawquad (dest,texture,hmap, pack1,pack2,pack3,pack4,&normal);
else voxpoly_drawquad (dest,texture,hmap, pack1,pack2,pack3,pack4,&normal);
}
PVoxelPoly::PVoxelPoly()
{
}
PVoxelPoly::~PVoxelPoly()
{
}
int PVoxelPoly::CreateFX (char *fn,char *path)
{
frustum = NULL;
tmap = jpeg_load2pixmap ("data/vpoly/tmap2.jpg");
int i;
for (i=0;i<tmap->width*tmap->height;i++)
{
int tmp;
tmp = tmap->image[i].g;
tmap->image[i].g = tmap->image[i].b;
tmap->image[i].b = tmp;
}
hmap = jpeg_load2pixmap ("data/vpoly/hmap.jpg");
star = jpeg_load2pixmap ("data/spider/star1.jpg");
bgpic2 = (GOA_PIXMAP *)fn;
renpic = goa_pixmap_create (240,240,GOA_PIXMAPCREATE_CLEAR | GOA_PIXMAPCREATE_ZBUFFER);
bgpic = jpeg_load2pixmap ("data/vpoly/bgpic.jpg");
voxpoly_init (renpic->width,renpic->height);
return 1;
}
static void mpixmap_copy (GOA_PIXMAP *dst,int x, int y, GOA_PIXMAP *src)
{
int xl,yl,ysadd,ydadd,ys;
GOA_RGBA *sptr,*dptr;
ysadd = src->width*4;
ydadd = dst->width*4;
xl = src->width;
yl = src->height;
ys = 0;
if (y<0)
{
yl+=y;
ys=-y;
y=0;
}else
{
if ((y+src->height) > dst->height)
yl -= (y+src->height) - dst->height;
}
if (yl<1) return;
sptr = &src->image[ys*src->width];
dptr = &dst->image[x+y*dst->width];
__asm
{
mov esi,sptr
mov edi,dptr
mov edx,yl
ylp:
push esi
push edi
mov ecx,xl
xlp:
cmp [esi],0
je ncopy
mov eax,[esi]
mov [edi],eax
ncopy:
add edi,4
add esi,4
dec ecx
jne xlp
pop edi
pop esi
add edi,ydadd
add esi,ysadd
dec edx
jne ylp
}
}
static float fade_away_intens = 0;
GOA_PIXMAP *PVoxelPoly::Render (GOA_PIXMAP *dst, int flags)
{
GOA_MATRIX rm;
GOA_VECTOR vadd={160,120,0};
float c_scale = 1.0;
int i;
if (frustum==NULL)
{
frustum = goa_frustum_create (renpic,renpic->width,renpic->height,400,GOA_FRUSTUMCREATE_NONE);
}
goa_pixmap_copy (dst,0,0,bgpic,0,0,dst->width,dst->height,GOA_PIXMAPCOPY_IMAGE);
goa_pixmap_clear (renpic,0,0,renpic->width,renpic->height,col_BLACK,GOA_PIXMAP_ZMAX, GOA_PIXMAPCLEAR_ZBUFFER|GOA_PIXMAPCLEAR_IMAGE);
goa_matrix_fromangles(&rm,xv,yv,zv);
goa_matrix_multivectormul (cube_dst,cube_src,8,&rm);
c_scale = 1.3+0.3*sin (dsys->time_total);
for (i=0;i<8;i++)
{
goa_vector_mul (&cube_dst[i],c_scale,&cube_dst[i]);
goa_frustum_project (frustum,&cube_dst[i],&cube_dst[i]);
}
voxpoly_setscale (24+16*sin(0.8*dsys->time_total));
voxpoly_setslice ((24+16*sin(0.8*dsys->time_total)) / 2.0f);
draw_face (renpic,tmap,hmap,0,1,2,3);
draw_face (renpic,tmap,hmap,7,6,5,4);
draw_face (renpic,tmap,hmap,1,5,6,2);
draw_face (renpic,tmap,hmap,3,7,4,0);
draw_face (renpic,tmap,hmap,0,4,5,1);
draw_face (renpic,tmap,hmap,2,6,7,3);
kfx_pixmap_3x3blur(renpic,0,0,renpic,0,0,renpic->width,renpic->height,1.0);
// kfx_pixmap_addsi(dst,320,160,renpic,2,2,1);
// kfx_pixmap_add(dst,320,160,renpic);
fade_ypos = -200 + 280 * sin (fade_y_t);
mpixmap_copy (dst,(320-renpic->width/2)+64*cos (dsys->time_total),fade_ypos,renpic);
if (!fade_off)
{
fade_y_t += dsys->time_delta;
if (fade_y_t>M_PI/2.0) fade_y_t = M_PI/2.0;
} else
{
pfxpix_crossfade(dst, 0,0,dst, 0,0,bgpic2,0,0,fade_away_intens,640,320);
fade_away_intens += dsys->time_delta;
if (fade_away_intens > 1) fade_away_intens=1;
fade_y_t += dsys->time_delta;
if (fade_y_t>M_PI) fade_y_t = M_PI;
}
if (e_fade)
{
float sc;
sc = 0.5+0.5*sin (e_fade_t);
kfx_pixmap_addsi(dst,284,142,star,sc,sc,sc);
kfx_pixmap_addsi(dst,204,174,star,sc,sc,sc);
e_fade_t += 1.2 * dsys->time_delta;
if (e_fade_t > 2.0 * M_PI) e_fade = 0;
}
xv += dsys->time_delta;
yv += dsys->time_delta*0.76;
zv += -dsys->time_delta*1.2;
return dst;
}
void PVoxelPoly::Signal (int sig,int numval, float *values)
{
switch (sig)
{
case 1 :
e_fade = 1;
e_fade_t = 0;
break;
case 2 :
fade_off = 1;
break;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment