diff --git a/gr-sim/hellmood_memories/Makefile b/gr-sim/hellmood_memories/Makefile new file mode 100644 index 00000000..c9bde022 --- /dev/null +++ b/gr-sim/hellmood_memories/Makefile @@ -0,0 +1,30 @@ +CC = gcc +CFLAGS = -O2 -Wall -I.. -g + +SDL_LIBS= `sdl-config --libs` +SDL_INCLUDE= `sdl-config --cflags` +GR_SIM = ../gr-sim.a + +all: hellmood_memories hellmood_gr hellmood_simple + +hellmood_memories: hellmood_memories.o + $(CC) -o hellmood_memories hellmood_memories.o $(LFLAGS) $(SDL_LIBS) + +hellmood_memories.o: hellmood_memories.c + $(CC) $(CFLAGS) $(SDL_INCLUDE) -c hellmood_memories.c + +hellmood_simple: hellmood_simple.o + $(CC) -o hellmood_simple hellmood_simple.o $(LFLAGS) $(SDL_LIBS) + +hellmood_simple.o: hellmood_simple.c + $(CC) $(CFLAGS) $(SDL_INCLUDE) -c hellmood_simple.c + + +hellmood_gr: hellmood_gr.o + $(CC) $(LFLAGS) -o hellmood_gr hellmood_gr.o $(GR_SIM) $(SDL_LIBS) + +hellmood_gr.o: hellmood_gr.c + $(CC) $(CFLAGS) -c hellmood_gr.c + +clean: + rm -f *~ *.o hellmood_memories hellmood_gr hellmood_simple diff --git a/gr-sim/hellmood_memories/hellmood_gr.c b/gr-sim/hellmood_memories/hellmood_gr.c new file mode 100644 index 00000000..38966ac8 --- /dev/null +++ b/gr-sim/hellmood_memories/hellmood_gr.c @@ -0,0 +1,637 @@ +#include +#include + +#include "gr-sim.h" + +#if 0 +static unsigned short stack[128]; +static unsigned short ax,bx,cx,dx,di,bp,es; +static int cf=0,of=0,zf=0,sf=0; +static int sp=0; +static unsigned char framebuffer[320*200]; + +static SDL_Surface *sdl_screen=NULL; + +struct palette { + unsigned char red[256]; + unsigned char green[256]; + unsigned char blue[256]; +}; + +static struct palette pal; + +static int mode13h_graphics_init(void) { + + int mode; + + mode=SDL_SWSURFACE|SDL_HWPALETTE|SDL_HWSURFACE; + + if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) { + fprintf(stderr, + "Couldn't initialize SDL: %s\n", SDL_GetError()); + return -1; + } + + /* Clean up on exit */ + atexit(SDL_Quit); + + /* assume 32-bit color */ + sdl_screen = SDL_SetVideoMode(320, 200, 32, mode); + + if ( sdl_screen == NULL ) { + fprintf(stderr, "ERROR! Couldn't set 320x200 video mode: %s\n", + SDL_GetError()); + return -1; + } + SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); + + SDL_WM_SetCaption("memories -- Linux/C/SDL","memories"); + + return 0; +} + +static int mode13h_graphics_update(unsigned char *buffer, struct palette *pal) { + + unsigned int *t_pointer; + + int x,temp; + + /* point to SDL output pixels */ + t_pointer=((Uint32 *)sdl_screen->pixels); + + for(x=0;x<320*200;x++) { + + temp=(pal->red[buffer[x]]<<16)| + (pal->green[buffer[x]]<<8)| + (pal->blue[buffer[x]]<<0)|0; + + t_pointer[x]=temp; + } + + SDL_UpdateRect(sdl_screen, 0, 0, 320, 200); + + return 0; +} + +static int graphics_input(void) { + + SDL_Event event; + int keypressed; + + while ( SDL_PollEvent(&event)) { + + switch(event.type) { + + case SDL_KEYDOWN: + keypressed=event.key.keysym.sym; + switch (keypressed) { + + case SDLK_ESCAPE: + return 27; + } + break; + } + } + return 0; + +} + + +static void write_framebuffer(int address, int value) { + int real_addr; + + real_addr=address-0xa0000; + if ((real_addr<0) || (real_addr>320*200)) return; + + framebuffer[real_addr]=value; + +} + +/* unsigned multiply */ +static void mul_16(unsigned short value) { + unsigned int result; + + result=ax*value; + +// printf("%x*%x=%x ",value,ax,result); + + ax=result&0xffff; + dx=result>>16; + +// printf("%x:%x x=%d y=%d\n",dx,ax, +// dx&0xff,(dx>>8)&0xff); + + + + + if (dx==0) { + of=0; + cf=0; + } + else { + of=1; + cf=1; + } + +} + +/* +static void imul(short value) { + int result; + + result=ax*value; + + ax=result&0xffff; + dx=result>>16; + +} +*/ + + + +/* signed multiply */ +static void imul_8(char value) { + + short result; + char src; + + src=ax; + + result=src*value; + +// printf("imul: %d*%d=%d ",src,value,result); + + ax=result; + + if (ax==(ax&0xff)) { + cf=0; + of=0; + } + else { + cf=1; + of=1; + } + +} + +/* signed multiply */ +static void imul_16(short value) { + + int result; + short src; + + src=ax; + + result=src*value; + +// printf("imul: %d*%d=%d ",src,value,result); + + ax=(result&0xffff); + dx=((result>>16)&0xffff); + + if (dx==0) { + cf=0; + of=0; + } + else { + cf=1; + of=1; + } + +} + +/* signed multiply */ +static void imul_16_bx(short value) { + + int result; + short src; + + src=bx; + + result=src*value; + +// printf("imul: %d*%d=%d ",src,value,result); + + bx=(result&0xffff); + + if (bx==result) { + cf=0; + of=0; + } + else { + cf=1; + of=1; + } + +} + +/* signed multiply */ +static void imul_16_dx(short value) { + + int result; + short src; + + src=dx; + + result=src*value; + +// printf("imul: %d*%d=%d ",src,value,result); + + dx=(result&0xffff); + + if (dx==result) { + cf=0; + of=0; + } + else { + cf=1; + of=1; + } + +} + + + + + +/* unsigned divide */ +static void div_8(unsigned char value) { + + unsigned char r,q; + unsigned int result,remainder; + +// printf("Dividing %d (%x) by %d (%x): ",ax,ax,value,value); + + if (value==0) { + printf("Divide by zero!\n"); + return; + } + + result=ax/value; + remainder=ax%value; + + q=result; + r=remainder; + +// printf("Result: q=%d r=%d\n",q,r); + + ax=(r<<8)|(q&0xff); + +} + + + +static void push(int value) { + //printf("Pushing %x\n",value); + stack[sp]=value; + sp++; +} + +static short pop(void) { + if (sp==0) { + printf("Stack underflow!\n"); + return 0; + } + + sp--; + + //printf("Popping %x\n",stack[sp]); + + return stack[sp]; + +} +#endif + /* tilted plane */ + /* DH=Y, DL=X */ +static void fx0(void) { +} +#if 0 + char ah,al,dh,dl; + unsigned short temp; + + ax=0x1329; // mov ax,0x1329 init + + al=ax&0xff; ah=(ax>>8)&0xff; + dl=dx&0xff; dh=(dx>>8)&0xff; + + + dh=dh+al; // add dh,al ; prevent divide overflow + div_8(dh); // div dh ; reverse divide AL=C/Y' + + dx=((dh&0xff)<<8)|dl; + + temp=ax; + ax=dx; dx=temp; // xchg dx,ax ; DL=C/Y' AL=X + + dl=dx&0xff; dh=(dx>>8)&0xff; + + imul_8(dl); // imul dl + dx=dx-bp; // sub dx,bp + dl=dx&0xff; + + ah=(ax>>8)&0xff; + ah=ah^dl; // xor ah,dl + al=ah; // mov al,ah + ax=((ah&0xff)<<8)|(al&0xff); + + ax&=0xff1c; // and al,4+8+16 +} + +#endif + +/* circles? */ +/* DH=Y, DL=X */ +static void fx1(void) { +} +#if 0 + int temp; + char al,dh,ah; + + // mov al,dh ; get Y in AL + al=(dx>>8)&0xff; + // sub al,100 ; align Y vertically + al=al-100; + ax=ax&0xff00; + ax=ax|al; + // imul al ; AL=Y*Y + imul_8(al); + // xchg dx,ax ; Y*Y/256 in DH, X in AL + temp=ax; + ax=dx; + dx=temp; + // imul al ; AL=X*X + imul_8(ax&0xff); + // add dh,ah ; DH=X*X+Y*Y/256 + dh=(dx>>8)&0xff; + ah=(ax>>8)&0xff; + dh=dh+ah; + // mov al,dh ; AL = X*X+Y*Y/256 + al=dh; + + dx=dx&0xff; + dx|=(dh<<8); + ax=(ah<<8)|(al&0xff); + + // add ax,bp ; offset color by time + ax=ax+bp; + // and al,8+16 ; select special rings + ax=ax&0xff18; +} +#endif +/* checkers */ +static void fx2(void) { +} +#if 0 + int temp; + unsigned char al; + + temp=ax; + ax=dx; dx=temp; // xchg dx,ax + ax=ax-bp; // sub ax,bp + temp=((ax>>8)&0xff)^(ax&0xff); + ax=ax&0xff00; + ax|=temp; // xor al,ah + ax|=0xdb; // or al,0xdb + al=ax&0xff; + al=al+0x13; + ax=ax&0xff00; + ax=ax|al; // add al,13h + // ret + +} + +#endif +/* parallax checkrboard */ +static void fx3(void) { +} + +#if 0 + cx=bp; // mov cx,bp ; set init point to time + bx=-16; // mov bx,-16 ; limit to 16 iterations +fx3L: + cx=cx+di; // add cx, di ; offset by screenpointer + ax=819; // mov ax,819 ; magic, related to Rrrola + imul_16(cx); // imul cx ; get X',Y' in DX + cf=dx&1; // ror dx,1 ; set carry flag on "hit" + dx=dx>>1; + if (cf) { + dx|=0x8000; + } + else { + dx&=0x7fff; + } + + bx++; // inc bx ; increment iteration count + if (bx==0) zf=1;// does not affect carry flag + else zf=0; + // ja fx3L ; loop until "hit" or "iter=max" + // jump above, if cf==0 and zf==0 + if ((cf==0) && (zf==0)) goto fx3L; + + ax=bx+31; // lea ax,[bx+32] ; map value to standard gray scale + //printf("%d %d\n",ax,bx); +} + +#endif +/* sierpinski rotozoomer */ +static void fx4(void) { +} +#if 0 + unsigned char dl,dh,bh,al; + dl=dx&0xff; dh=(dx>>8)&0xff; + + cx=bp-2048; // lea cx,[bp-2048] ; center time to pass zero + cx=cx<<3; // sal cx,3 ; speed up by factor of 8! + ax=(dh&0xff); // movzx ax,dh ; get X into AL + // movsx dx,dl ; get Y into DL + if (dl&0x80) { + dx|=0xff00; + } + else { + dx&=0x00ff; + } + + bx=ax; // mov bx,ax ; save X in BX + imul_16_bx(cx); // imul bx,cx ; BX=X*T + + /* bl=bx&0xff; */ bh=(bx>>8)&0xff; + dl=dx&0xff; dh=(dx>>8)&0xff; + + bh=bh+dl; // add bh,dl ; bh=x*t/256+Y + + imul_16_dx(cx); // imul dx,cx ; dx=Y*T + + dl=dx&0xff; dh=(dx>>8)&0xff; + + // sub al,dh ; al=X-Y*T/256 + al=ax&0xff; // ah=(ax>>8)&0xff; + al=al-dh; + + // and al,bh ; AL=(X-Y*T/256)&(x*T/256+Y) + al=al&bh; + al=al&252; // and al,252 ; thicker sierpinksi + if (al==0) zf=1; + else zf=0; + cf=0; of=0; + // salc ; set pixel value to black + if (cf==0) al=0; + else al=0xff; + +/* NOTE: remove the line below and the background becomes a rainbow */ + ax=al; + // jnz fx4q ; leave black if not sierpinksi + if (zf==0) goto fx4q; + + ax=ax&0xff00; // mov al,0x2a ; otherwise: a nice orange + ax|=0x2a; +fx4q: + ; +} + +#endif +/* raycast bent tunnel */ +static void fx5(void) { + +#if 0 + unsigned char al,cl; + unsigned short temp; + + cx=cx&0xff00; + cx|=(-9&0xff); // mov cl,-9 ; start with depth 9 (moves backwards) +fx5L: + cl=cx&0xff; + + push(dx); // push dx ; save DX, destroyed inside loop + al=(dx>>8)&0xff;// mov al,dh ; get Y into AL + al-=100; // sub al,100 ; centering Y manually + + ax=ax&0xff00; + ax|=(al&0xff); + + imul_8(cl); // imul cl ; multiply AL=Y by current distance to get projection + // xchg ax,dx ; gt X into AL while saving DX + temp=ax; + ax=dx; + dx=temp; + + al=ax&0xff; + al+=cl; // add al,cl ; add distance to projection (bend right) + + ax=ax&0xff00; + ax|=(al&0xff); + imul_8(cl); // imul cl ; multiply AL=X by the current projection + al=(dx>>8)&0xff;// mov al,dh ; get projection(1) in AL + al^=(ax>>8); // xor al,ah ; combine with projection(2) + al+=4; // add al,4 ; center the walls around 0 + if (al&-8) { // test al,-8 ; test if the wall is hit + zf=0; + } + else { + zf=1; + } + + dx=pop(); // pop dx (restore dx) + cx&=0xff00; + cx|=(cl&0xff); + cx--; + if ((cx!=0) && (zf==1)) goto fx5L; + // loopz fx5L (repeat until "hit" or "iter=max" + + cx=cx-bp; // sub cx,bp ; offset depth by time + al^=(cx&0xff); // xor al,cl ; XOR pattern for texture +// ah=al/6; + al=al%6; // aam 6 ; irregular pattern with MOD 6 + al+=20; // add al,20 ; offset into grayscale pattern + ax=al&0xff; +#endif +} + + +/* ocean night */ +static void fx6(void) { +} +#if 0 + char dh; + double f; + int edx; + char scratch[64]; + + // bx coming in is the address of the effect + // this is a guess, too lazy to hexdump + bx=0x1d5; + + // si=?? based on sound playing? + // ax (sky color) is ? + + dh=dx>>8; + // sub dh,120 ; check if pixel in the sky + dh=dh-120; + sf=!!(dh&0x80); + // js fx6q ; quit if that's the case + if (sf) goto fx6q; + + dx&=0xff; + dx|=dh<<8; + + // mov [bx+si],dx ; move xy to memory location + // fild word [bx+si] ; read as integer + // fidivr dword [bx+si] ; reverse divide by constant + // Divide m32int by ST(0) and store result in ST(0) + // fstp dword [bx+si-1] ; store result as floating point + // mov ax,[bx+si] ; get result into ax + + memcpy(&scratch[32],&dx,sizeof(short)); + f=dx; + memcpy(&edx,&scratch[32],sizeof(int)); + f=f/edx; + memcpy(&scratch[31],&f,sizeof(double)); + memcpy(&ax,&scratch[32],sizeof(short)); + + + + + ax+=bp; // add ax,bp ; modify color by time + ax&=0xff80; // and al,128 ; threshold into two bands + ax--; // dec ax ; beautify colors to blue/black +fx6q: ; +} +#endif + +int main(int argc, char **argv) { + + int which=5,ch; + + grsim_init(); + + gr(); + + clear_screens(); + + while(1) { + + switch (which) { + case 0: fx2(); break; + case 1: fx1(); break; + case 2: fx0(); break; + case 3: fx3(); break; + case 4: fx4(); break; + case 5: fx5(); break; + case 6: fx6(); break; + case 7: goto end; + default: printf("Trying effect %d\n",which); + } + + grsim_update(); + + ch=grsim_input(); + if (ch=='q') goto end; + + usleep(10000); + + + } + +end: + + return 0; +} diff --git a/gr-sim/hellmood_memories/hellmood_memories.c b/gr-sim/hellmood_memories/hellmood_memories.c new file mode 100644 index 00000000..642f5687 --- /dev/null +++ b/gr-sim/hellmood_memories/hellmood_memories.c @@ -0,0 +1,763 @@ +/* A Linux/SDL/C version of Hellmood's amazing 256B DOS Memories Demo */ + +/* See http://www.sizecoding.org/wiki/Memories for a rundown on how it works */ + +/* This is a conversion to C I did in an attempt to see how it works */ +/* and also to see if I could port any of this to the Apple II */ + +/* x86 has amazing code density with powerful instructions */ +/* stos, mul, div, FPU, lots of 1-byte instructions */ +/* and old x86 hardware made it really easy to program with limited code */ +/* VGA/MCGA Mode13h (320x200 256 colors linear framebuffer) */ +/* soundblaster MIDI with only a few out instructions */ + +/* Anyway this is a rough attempt to getting things going in C */ +/* The last effect (ocean) is doing lots of sketchy stuff and */ +/* depending a bit on undefined behavior so it's hit or miss */ +/* whether it will work for you */ + +/* deater -- Vince Weaver -- vince@deater.net -- 23 April 2020 */ + +#include +#include + +#include + +static unsigned short stack[128]; +static unsigned short ax,bx,cx,dx,di,bp,es; +static int cf=0,of=0,zf=0,sf=0; +static int sp=0; +static unsigned char framebuffer[320*200]; + +static SDL_Surface *sdl_screen=NULL; + +struct palette { + unsigned char red[256]; + unsigned char green[256]; + unsigned char blue[256]; +}; + +static struct palette pal; + +static int mode13h_graphics_init(void) { + + int mode; + + mode=SDL_SWSURFACE|SDL_HWPALETTE|SDL_HWSURFACE; + + if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) { + fprintf(stderr, + "Couldn't initialize SDL: %s\n", SDL_GetError()); + return -1; + } + + /* Clean up on exit */ + atexit(SDL_Quit); + + /* assume 32-bit color */ + sdl_screen = SDL_SetVideoMode(320, 200, 32, mode); + + if ( sdl_screen == NULL ) { + fprintf(stderr, "ERROR! Couldn't set 320x200 video mode: %s\n", + SDL_GetError()); + return -1; + } + SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); + + SDL_WM_SetCaption("memories -- Linux/C/SDL","memories"); + + return 0; +} + +static int mode13h_graphics_update(unsigned char *buffer, struct palette *pal) { + + unsigned int *t_pointer; + + int x,temp; + + /* point to SDL output pixels */ + t_pointer=((Uint32 *)sdl_screen->pixels); + + for(x=0;x<320*200;x++) { + + temp=(pal->red[buffer[x]]<<16)| + (pal->green[buffer[x]]<<8)| + (pal->blue[buffer[x]]<<0)|0; + + t_pointer[x]=temp; + } + + SDL_UpdateRect(sdl_screen, 0, 0, 320, 200); + + return 0; +} + +static void set_vga_pal(void) { + +/* output of vgapal https://github.com/canidlogic/vgapal */ +unsigned char raw_pal[3*256]= +{ 0, 0, 0, 0, 0, 170, 0, 170, 0, 0, 170, 170, +170, 0, 0, 170, 0, 170, 170, 85, 0, 170, 170, 170, + 85, 85, 85, 85, 85, 255, 85, 255, 85, 85, 255, 255, +255, 85, 85, 255, 85, 255, 255, 255, 85, 255, 255, 255, + 0, 0, 0, 20, 20, 20, 32, 32, 32, 44, 44, 44, + 56, 56, 56, 69, 69, 69, 81, 81, 81, 97, 97, 97, +113, 113, 113, 130, 130, 130, 146, 146, 146, 162, 162, 162, +182, 182, 182, 203, 203, 203, 227, 227, 227, 255, 255, 255, + 0, 0, 255, 65, 0, 255, 125, 0, 255, 190, 0, 255, +255, 0, 255, 255, 0, 190, 255, 0, 125, 255, 0, 65, +255, 0, 0, 255, 65, 0, 255, 125, 0, 255, 190, 0, +255, 255, 0, 190, 255, 0, 125, 255, 0, 65, 255, 0, + 0, 255, 0, 0, 255, 65, 0, 255, 125, 0, 255, 190, + 0, 255, 255, 0, 190, 255, 0, 125, 255, 0, 65, 255, +125, 125, 255, 158, 125, 255, 190, 125, 255, 223, 125, 255, +255, 125, 255, 255, 125, 223, 255, 125, 190, 255, 125, 158, +255, 125, 125, 255, 158, 125, 255, 190, 125, 255, 223, 125, +255, 255, 125, 223, 255, 125, 190, 255, 125, 158, 255, 125, +125, 255, 125, 125, 255, 158, 125, 255, 190, 125, 255, 223, +125, 255, 255, 125, 223, 255, 125, 190, 255, 125, 158, 255, +182, 182, 255, 199, 182, 255, 219, 182, 255, 235, 182, 255, +255, 182, 255, 255, 182, 235, 255, 182, 219, 255, 182, 199, +255, 182, 182, 255, 199, 182, 255, 219, 182, 255, 235, 182, +255, 255, 182, 235, 255, 182, 219, 255, 182, 199, 255, 182, +182, 255, 182, 182, 255, 199, 182, 255, 219, 182, 255, 235, +182, 255, 255, 182, 235, 255, 182, 219, 255, 182, 199, 255, + 0, 0, 113, 28, 0, 113, 56, 0, 113, 85, 0, 113, +113, 0, 113, 113, 0, 85, 113, 0, 56, 113, 0, 28, +113, 0, 0, 113, 28, 0, 113, 56, 0, 113, 85, 0, +113, 113, 0, 85, 113, 0, 56, 113, 0, 28, 113, 0, + 0, 113, 0, 0, 113, 28, 0, 113, 56, 0, 113, 85, + 0, 113, 113, 0, 85, 113, 0, 56, 113, 0, 28, 113, + 56, 56, 113, 69, 56, 113, 85, 56, 113, 97, 56, 113, +113, 56, 113, 113, 56, 97, 113, 56, 85, 113, 56, 69, +113, 56, 56, 113, 69, 56, 113, 85, 56, 113, 97, 56, +113, 113, 56, 97, 113, 56, 85, 113, 56, 69, 113, 56, + 56, 113, 56, 56, 113, 69, 56, 113, 85, 56, 113, 97, + 56, 113, 113, 56, 97, 113, 56, 85, 113, 56, 69, 113, + 81, 81, 113, 89, 81, 113, 97, 81, 113, 105, 81, 113, +113, 81, 113, 113, 81, 105, 113, 81, 97, 113, 81, 89, +113, 81, 81, 113, 89, 81, 113, 97, 81, 113, 105, 81, +113, 113, 81, 105, 113, 81, 97, 113, 81, 89, 113, 81, + 81, 113, 81, 81, 113, 89, 81, 113, 97, 81, 113, 105, + 81, 113, 113, 81, 105, 113, 81, 97, 113, 81, 89, 113, + 0, 0, 65, 16, 0, 65, 32, 0, 65, 48, 0, 65, + 65, 0, 65, 65, 0, 48, 65, 0, 32, 65, 0, 16, + 65, 0, 0, 65, 16, 0, 65, 32, 0, 65, 48, 0, + 65, 65, 0, 48, 65, 0, 32, 65, 0, 16, 65, 0, + 0, 65, 0, 0, 65, 16, 0, 65, 32, 0, 65, 48, + 0, 65, 65, 0, 48, 65, 0, 32, 65, 0, 16, 65, + 32, 32, 65, 40, 32, 65, 48, 32, 65, 56, 32, 65, + 65, 32, 65, 65, 32, 56, 65, 32, 48, 65, 32, 40, + 65, 32, 32, 65, 40, 32, 65, 48, 32, 65, 56, 32, + 65, 65, 32, 56, 65, 32, 48, 65, 32, 40, 65, 32, + 32, 65, 32, 32, 65, 40, 32, 65, 48, 32, 65, 56, + 32, 65, 65, 32, 56, 65, 32, 48, 65, 32, 40, 65, + 44, 44, 65, 48, 44, 65, 52, 44, 65, 60, 44, 65, + 65, 44, 65, 65, 44, 60, 65, 44, 52, 65, 44, 48, + 65, 44, 44, 65, 48, 44, 65, 52, 44, 65, 60, 44, + 65, 65, 44, 60, 65, 44, 52, 65, 44, 48, 65, 44, + 44, 65, 44, 44, 65, 48, 44, 65, 52, 44, 65, 60, + 44, 65, 65, 44, 60, 65, 44, 52, 65, 44, 48, 65, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + + int i; + + for(i=0;i<256;i++) { + pal.red[i]=raw_pal[i*3]; + pal.green[i]=raw_pal[(i*3)+1]; + pal.blue[i]=raw_pal[(i*3)+2]; + + } + return; + +} + +static int graphics_input(void) { + + SDL_Event event; + int keypressed; + + while ( SDL_PollEvent(&event)) { + + switch(event.type) { + + case SDL_KEYDOWN: + keypressed=event.key.keysym.sym; + switch (keypressed) { + + case SDLK_ESCAPE: + return 27; + } + break; + } + } + return 0; + +} + + +static void write_framebuffer(int address, int value) { + int real_addr; + + real_addr=address-0xa0000; + if ((real_addr<0) || (real_addr>320*200)) return; + + framebuffer[real_addr]=value; + +} + +/* unsigned multiply */ +static void mul_16(unsigned short value) { + unsigned int result; + + result=ax*value; + +// printf("%x*%x=%x ",value,ax,result); + + ax=result&0xffff; + dx=result>>16; + +// printf("%x:%x x=%d y=%d\n",dx,ax, +// dx&0xff,(dx>>8)&0xff); + + + + + if (dx==0) { + of=0; + cf=0; + } + else { + of=1; + cf=1; + } + +} + +/* +static void imul(short value) { + int result; + + result=ax*value; + + ax=result&0xffff; + dx=result>>16; + +} +*/ + + + +/* signed multiply */ +static void imul_8(char value) { + + short result; + char src; + + src=ax; + + result=src*value; + +// printf("imul: %d*%d=%d ",src,value,result); + + ax=result; + + if (ax==(ax&0xff)) { + cf=0; + of=0; + } + else { + cf=1; + of=1; + } + +} + +/* signed multiply */ +static void imul_16(short value) { + + int result; + short src; + + src=ax; + + result=src*value; + +// printf("imul: %d*%d=%d ",src,value,result); + + ax=(result&0xffff); + dx=((result>>16)&0xffff); + + if (dx==0) { + cf=0; + of=0; + } + else { + cf=1; + of=1; + } + +} + +/* signed multiply */ +static void imul_16_bx(short value) { + + int result; + short src; + + src=bx; + + result=src*value; + +// printf("imul: %d*%d=%d ",src,value,result); + + bx=(result&0xffff); + + if (bx==result) { + cf=0; + of=0; + } + else { + cf=1; + of=1; + } + +} + +/* signed multiply */ +static void imul_16_dx(short value) { + + int result; + short src; + + src=dx; + + result=src*value; + +// printf("imul: %d*%d=%d ",src,value,result); + + dx=(result&0xffff); + + if (dx==result) { + cf=0; + of=0; + } + else { + cf=1; + of=1; + } + +} + + + + + +/* unsigned divide */ +static void div_8(unsigned char value) { + + unsigned char r,q; + unsigned int result,remainder; + +// printf("Dividing %d (%x) by %d (%x): ",ax,ax,value,value); + + if (value==0) { + printf("Divide by zero!\n"); + return; + } + + result=ax/value; + remainder=ax%value; + + q=result; + r=remainder; + +// printf("Result: q=%d r=%d\n",q,r); + + ax=(r<<8)|(q&0xff); + +} + + + +static void push(int value) { + //printf("Pushing %x\n",value); + stack[sp]=value; + sp++; +} + +static short pop(void) { + if (sp==0) { + printf("Stack underflow!\n"); + return 0; + } + + sp--; + + //printf("Popping %x\n",stack[sp]); + + return stack[sp]; + +} + /* tilted plane */ + /* DH=Y, DL=X */ +static void fx0(void) { + + char ah,al,dh,dl; + unsigned short temp; + + ax=0x1329; // mov ax,0x1329 init + + al=ax&0xff; ah=(ax>>8)&0xff; + dl=dx&0xff; dh=(dx>>8)&0xff; + + + dh=dh+al; // add dh,al ; prevent divide overflow + div_8(dh); // div dh ; reverse divide AL=C/Y' + + dx=((dh&0xff)<<8)|dl; + + temp=ax; + ax=dx; dx=temp; // xchg dx,ax ; DL=C/Y' AL=X + + dl=dx&0xff; dh=(dx>>8)&0xff; + + imul_8(dl); // imul dl + dx=dx-bp; // sub dx,bp + dl=dx&0xff; + + ah=(ax>>8)&0xff; + ah=ah^dl; // xor ah,dl + al=ah; // mov al,ah + ax=((ah&0xff)<<8)|(al&0xff); + + ax&=0xff1c; // and al,4+8+16 +} + +/* circles? */ +/* DH=Y, DL=X */ +static void fx1(void) { + + int temp; + char al,dh,ah; + + // mov al,dh ; get Y in AL + al=(dx>>8)&0xff; + // sub al,100 ; align Y vertically + al=al-100; + ax=ax&0xff00; + ax=ax|al; + // imul al ; AL=Y*Y + imul_8(al); + // xchg dx,ax ; Y*Y/256 in DH, X in AL + temp=ax; + ax=dx; + dx=temp; + // imul al ; AL=X*X + imul_8(ax&0xff); + // add dh,ah ; DH=X*X+Y*Y/256 + dh=(dx>>8)&0xff; + ah=(ax>>8)&0xff; + dh=dh+ah; + // mov al,dh ; AL = X*X+Y*Y/256 + al=dh; + + dx=dx&0xff; + dx|=(dh<<8); + ax=(ah<<8)|(al&0xff); + + // add ax,bp ; offset color by time + ax=ax+bp; + // and al,8+16 ; select special rings + ax=ax&0xff18; +} + +/* checkers */ +static void fx2(void) { + int temp; + unsigned char al; + + temp=ax; + ax=dx; dx=temp; // xchg dx,ax + ax=ax-bp; // sub ax,bp + temp=((ax>>8)&0xff)^(ax&0xff); + ax=ax&0xff00; + ax|=temp; // xor al,ah + ax|=0xdb; // or al,0xdb + al=ax&0xff; + al=al+0x13; + ax=ax&0xff00; + ax=ax|al; // add al,13h + // ret + +} + + +/* parallax checkrboard */ +static void fx3(void) { + + cx=bp; // mov cx,bp ; set init point to time + bx=-16; // mov bx,-16 ; limit to 16 iterations +fx3L: + cx=cx+di; // add cx, di ; offset by screenpointer + ax=819; // mov ax,819 ; magic, related to Rrrola + imul_16(cx); // imul cx ; get X',Y' in DX + cf=dx&1; // ror dx,1 ; set carry flag on "hit" + dx=dx>>1; + if (cf) { + dx|=0x8000; + } + else { + dx&=0x7fff; + } + + bx++; // inc bx ; increment iteration count + if (bx==0) zf=1;// does not affect carry flag + else zf=0; + // ja fx3L ; loop until "hit" or "iter=max" + // jump above, if cf==0 and zf==0 + if ((cf==0) && (zf==0)) goto fx3L; + + ax=bx+31; // lea ax,[bx+32] ; map value to standard gray scale + //printf("%d %d\n",ax,bx); +} + +/* sierpinski rotozoomer */ +static void fx4(void) { + + unsigned char dl,dh,bh,al; + dl=dx&0xff; dh=(dx>>8)&0xff; + + cx=bp-2048; // lea cx,[bp-2048] ; center time to pass zero + cx=cx<<3; // sal cx,3 ; speed up by factor of 8! + ax=(dh&0xff); // movzx ax,dh ; get X into AL + // movsx dx,dl ; get Y into DL + if (dl&0x80) { + dx|=0xff00; + } + else { + dx&=0x00ff; + } + + bx=ax; // mov bx,ax ; save X in BX + imul_16_bx(cx); // imul bx,cx ; BX=X*T + + /* bl=bx&0xff; */ bh=(bx>>8)&0xff; + dl=dx&0xff; dh=(dx>>8)&0xff; + + bh=bh+dl; // add bh,dl ; bh=x*t/256+Y + + imul_16_dx(cx); // imul dx,cx ; dx=Y*T + + dl=dx&0xff; dh=(dx>>8)&0xff; + + // sub al,dh ; al=X-Y*T/256 + al=ax&0xff; // ah=(ax>>8)&0xff; + al=al-dh; + + // and al,bh ; AL=(X-Y*T/256)&(x*T/256+Y) + al=al&bh; + al=al&252; // and al,252 ; thicker sierpinksi + if (al==0) zf=1; + else zf=0; + cf=0; of=0; + // salc ; set pixel value to black + if (cf==0) al=0; + else al=0xff; + +/* NOTE: remove the line below and the background becomes a rainbow */ + ax=al; + // jnz fx4q ; leave black if not sierpinksi + if (zf==0) goto fx4q; + + ax=ax&0xff00; // mov al,0x2a ; otherwise: a nice orange + ax|=0x2a; +fx4q: + ; +} + + +/* raycast bent tunnel */ +static void fx5(void) { + + unsigned char al,cl; + unsigned short temp; + + cx=cx&0xff00; + cx|=(-9&0xff); // mov cl,-9 ; start with depth 9 (moves backwards) +fx5L: + cl=cx&0xff; + + push(dx); // push dx ; save DX, destroyed inside loop + al=(dx>>8)&0xff;// mov al,dh ; get Y into AL + al-=100; // sub al,100 ; centering Y manually + + ax=ax&0xff00; + ax|=(al&0xff); + + imul_8(cl); // imul cl ; multiply AL=Y by current distance to get projection + // xchg ax,dx ; gt X into AL while saving DX + temp=ax; + ax=dx; + dx=temp; + + al=ax&0xff; + al+=cl; // add al,cl ; add distance to projection (bend right) + + ax=ax&0xff00; + ax|=(al&0xff); + imul_8(cl); // imul cl ; multiply AL=X by the current projection + al=(dx>>8)&0xff;// mov al,dh ; get projection(1) in AL + al^=(ax>>8); // xor al,ah ; combine with projection(2) + al+=4; // add al,4 ; center the walls around 0 + if (al&-8) { // test al,-8 ; test if the wall is hit + zf=0; + } + else { + zf=1; + } + + dx=pop(); // pop dx (restore dx) + cx&=0xff00; + cx|=(cl&0xff); + cx--; + if ((cx!=0) && (zf==1)) goto fx5L; + // loopz fx5L (repeat until "hit" or "iter=max" + + cx=cx-bp; // sub cx,bp ; offset depth by time + al^=(cx&0xff); // xor al,cl ; XOR pattern for texture +// ah=al/6; + al=al%6; // aam 6 ; irregular pattern with MOD 6 + al+=20; // add al,20 ; offset into grayscale pattern + ax=al&0xff; +} + +/* ocean night */ +static void fx6(void) { + char dh; + double f; + int edx; + char scratch[64]; + + // bx coming in is the address of the effect + // this is a guess, too lazy to hexdump + bx=0x1d5; + + // si=?? based on sound playing? + // ax (sky color) is ? + + dh=dx>>8; + // sub dh,120 ; check if pixel in the sky + dh=dh-120; + sf=!!(dh&0x80); + // js fx6q ; quit if that's the case + if (sf) goto fx6q; + + dx&=0xff; + dx|=dh<<8; + + // mov [bx+si],dx ; move xy to memory location + // fild word [bx+si] ; read as integer + // fidivr dword [bx+si] ; reverse divide by constant + // Divide m32int by ST(0) and store result in ST(0) + // fstp dword [bx+si-1] ; store result as floating point + // mov ax,[bx+si] ; get result into ax + + memcpy(&scratch[32],&dx,sizeof(short)); + f=dx; + memcpy(&edx,&scratch[32],sizeof(int)); + f=f/edx; + memcpy(&scratch[31],&f,sizeof(double)); + memcpy(&ax,&scratch[32],sizeof(short)); + + + + + ax+=bp; // add ax,bp ; modify color by time + ax&=0xff80; // and al,128 ; threshold into two bands + ax--; // dec ax ; beautify colors to blue/black +fx6q: ; +} + + +int main(int argc, char **argv) { + + int temp; + + set_vga_pal(); + + mode13h_graphics_init(); + + di=0; // ?? + + ax=0x13; // mov al,0x13 + // int 0x10 ; set 320x200x256 color mode + bp=ax; // xchg bp,ax ; set bp to 0x13 + + push(0xa000-10); // write screen address to es + es=pop(); // pop es + ax=0x251c; // mov ax,0x251c param for timer interrupt + dx=0xdead; // mov dl, timer set up timer interrupt + // int 0x21 + +top: + ax=0xcccd; // load rrrola constant + mul_16(di); // multiply + temp=(ax&0xff)+((ax>>8)&0xff); // add al,ah + ax=ax&0xff00; + ax|=(temp&0xff); + ax=ax&0xff; // xor ah,ah + ax=ax+bp; // add ax,bp + ax=ax>>9; // shr ax,9 + ax=ax&0xff0f; // and al,15 + temp=ax; // xchg bx,ax + ax=bx; + bx=temp; + bx=bx&0xff; // mov bh,1 + bx|=1<<8; +// printf("%x: bx\n",bx); + // mov bl,[byte bx+table] + // call bx + switch (bx&0xff) { + case 0: fx2(); break; + case 1: fx1(); break; + case 2: fx0(); break; + case 3: fx3(); break; + case 4: fx4(); break; + case 5: fx5(); break; + case 6: fx6(); break; + case 7: goto end; + default: printf("Trying effect %d\n",bx&0xff); + } + // stosb + write_framebuffer((es<<4)+di, ax&0xff); + di++; + +// printf("Writing %d to %x (%x:%x)\n",ax&0xff,(es<<4)+di,es,di); + di++; // inc di + di++; // inc di + if (di!=0) goto top; +// printf("Done frame\n"); + mode13h_graphics_update(framebuffer,&pal); + + // timer emulate + usleep(10000); + bp=bp+1; + // mov al,tempo + // out 40h,al (set timing?) + // in al,0x60 read keyboad + // dec al + + if (graphics_input()) { + return 0; + } + + // jnz top + + goto top; +end: + + return 0; +} diff --git a/gr-sim/hellmood_memories/hellmood_simple.c b/gr-sim/hellmood_memories/hellmood_simple.c new file mode 100644 index 00000000..50880abb --- /dev/null +++ b/gr-sim/hellmood_memories/hellmood_simple.c @@ -0,0 +1,746 @@ +/* A Linux/SDL/C version of Hellmood's amazing 256B DOS Memories Demo */ + +/* See http://www.sizecoding.org/wiki/Memories for a rundown on how it works */ + +/* This is a conversion to C I did in an attempt to see how it works */ +/* and also to see if I could port any of this to the Apple II */ + +/* x86 has amazing code density with powerful instructions */ +/* stos, mul, div, FPU, lots of 1-byte instructions */ +/* and old x86 hardware made it really easy to program with limited code */ +/* VGA/MCGA Mode13h (320x200 256 colors linear framebuffer) */ +/* soundblaster MIDI with only a few out instructions */ + +/* Anyway this is a rough attempt to getting things going in C */ +/* The last effect (ocean) is doing lots of sketchy stuff and */ +/* depending a bit on undefined behavior so it's hit or miss */ +/* whether it will work for you */ + +/* deater -- Vince Weaver -- vince@deater.net -- 23 April 2020 */ + +#include +#include + +#include + +static unsigned short stack[128]; +static unsigned short ax,bx,cx,dx,di,bp,es; +static int cf=0,of=0,zf=0,sf=0; +static int sp=0; +static unsigned char framebuffer[320*200]; + +static SDL_Surface *sdl_screen=NULL; + +struct palette { + unsigned char red[256]; + unsigned char green[256]; + unsigned char blue[256]; +}; + +static struct palette pal; + +static int mode13h_graphics_init(void) { + + int mode; + + mode=SDL_SWSURFACE|SDL_HWPALETTE|SDL_HWSURFACE; + + if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) { + fprintf(stderr, + "Couldn't initialize SDL: %s\n", SDL_GetError()); + return -1; + } + + /* Clean up on exit */ + atexit(SDL_Quit); + + /* assume 32-bit color */ + sdl_screen = SDL_SetVideoMode(320, 200, 32, mode); + + if ( sdl_screen == NULL ) { + fprintf(stderr, "ERROR! Couldn't set 320x200 video mode: %s\n", + SDL_GetError()); + return -1; + } + SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); + + SDL_WM_SetCaption("memories -- Linux/C/SDL","memories"); + + return 0; +} + +static int mode13h_graphics_update(unsigned char *buffer, struct palette *pal) { + + unsigned int *t_pointer; + + int x,temp; + + /* point to SDL output pixels */ + t_pointer=((Uint32 *)sdl_screen->pixels); + + for(x=0;x<320*200;x++) { + + temp=(pal->red[buffer[x]]<<16)| + (pal->green[buffer[x]]<<8)| + (pal->blue[buffer[x]]<<0)|0; + + t_pointer[x]=temp; + } + + SDL_UpdateRect(sdl_screen, 0, 0, 320, 200); + + return 0; +} + +static void set_vga_pal(void) { + +/* output of vgapal https://github.com/canidlogic/vgapal */ +unsigned char raw_pal[3*256]= +{ 0, 0, 0, 0, 0, 170, 0, 170, 0, 0, 170, 170, +170, 0, 0, 170, 0, 170, 170, 85, 0, 170, 170, 170, + 85, 85, 85, 85, 85, 255, 85, 255, 85, 85, 255, 255, +255, 85, 85, 255, 85, 255, 255, 255, 85, 255, 255, 255, + 0, 0, 0, 20, 20, 20, 32, 32, 32, 44, 44, 44, + 56, 56, 56, 69, 69, 69, 81, 81, 81, 97, 97, 97, +113, 113, 113, 130, 130, 130, 146, 146, 146, 162, 162, 162, +182, 182, 182, 203, 203, 203, 227, 227, 227, 255, 255, 255, + 0, 0, 255, 65, 0, 255, 125, 0, 255, 190, 0, 255, +255, 0, 255, 255, 0, 190, 255, 0, 125, 255, 0, 65, +255, 0, 0, 255, 65, 0, 255, 125, 0, 255, 190, 0, +255, 255, 0, 190, 255, 0, 125, 255, 0, 65, 255, 0, + 0, 255, 0, 0, 255, 65, 0, 255, 125, 0, 255, 190, + 0, 255, 255, 0, 190, 255, 0, 125, 255, 0, 65, 255, +125, 125, 255, 158, 125, 255, 190, 125, 255, 223, 125, 255, +255, 125, 255, 255, 125, 223, 255, 125, 190, 255, 125, 158, +255, 125, 125, 255, 158, 125, 255, 190, 125, 255, 223, 125, +255, 255, 125, 223, 255, 125, 190, 255, 125, 158, 255, 125, +125, 255, 125, 125, 255, 158, 125, 255, 190, 125, 255, 223, +125, 255, 255, 125, 223, 255, 125, 190, 255, 125, 158, 255, +182, 182, 255, 199, 182, 255, 219, 182, 255, 235, 182, 255, +255, 182, 255, 255, 182, 235, 255, 182, 219, 255, 182, 199, +255, 182, 182, 255, 199, 182, 255, 219, 182, 255, 235, 182, +255, 255, 182, 235, 255, 182, 219, 255, 182, 199, 255, 182, +182, 255, 182, 182, 255, 199, 182, 255, 219, 182, 255, 235, +182, 255, 255, 182, 235, 255, 182, 219, 255, 182, 199, 255, + 0, 0, 113, 28, 0, 113, 56, 0, 113, 85, 0, 113, +113, 0, 113, 113, 0, 85, 113, 0, 56, 113, 0, 28, +113, 0, 0, 113, 28, 0, 113, 56, 0, 113, 85, 0, +113, 113, 0, 85, 113, 0, 56, 113, 0, 28, 113, 0, + 0, 113, 0, 0, 113, 28, 0, 113, 56, 0, 113, 85, + 0, 113, 113, 0, 85, 113, 0, 56, 113, 0, 28, 113, + 56, 56, 113, 69, 56, 113, 85, 56, 113, 97, 56, 113, +113, 56, 113, 113, 56, 97, 113, 56, 85, 113, 56, 69, +113, 56, 56, 113, 69, 56, 113, 85, 56, 113, 97, 56, +113, 113, 56, 97, 113, 56, 85, 113, 56, 69, 113, 56, + 56, 113, 56, 56, 113, 69, 56, 113, 85, 56, 113, 97, + 56, 113, 113, 56, 97, 113, 56, 85, 113, 56, 69, 113, + 81, 81, 113, 89, 81, 113, 97, 81, 113, 105, 81, 113, +113, 81, 113, 113, 81, 105, 113, 81, 97, 113, 81, 89, +113, 81, 81, 113, 89, 81, 113, 97, 81, 113, 105, 81, +113, 113, 81, 105, 113, 81, 97, 113, 81, 89, 113, 81, + 81, 113, 81, 81, 113, 89, 81, 113, 97, 81, 113, 105, + 81, 113, 113, 81, 105, 113, 81, 97, 113, 81, 89, 113, + 0, 0, 65, 16, 0, 65, 32, 0, 65, 48, 0, 65, + 65, 0, 65, 65, 0, 48, 65, 0, 32, 65, 0, 16, + 65, 0, 0, 65, 16, 0, 65, 32, 0, 65, 48, 0, + 65, 65, 0, 48, 65, 0, 32, 65, 0, 16, 65, 0, + 0, 65, 0, 0, 65, 16, 0, 65, 32, 0, 65, 48, + 0, 65, 65, 0, 48, 65, 0, 32, 65, 0, 16, 65, + 32, 32, 65, 40, 32, 65, 48, 32, 65, 56, 32, 65, + 65, 32, 65, 65, 32, 56, 65, 32, 48, 65, 32, 40, + 65, 32, 32, 65, 40, 32, 65, 48, 32, 65, 56, 32, + 65, 65, 32, 56, 65, 32, 48, 65, 32, 40, 65, 32, + 32, 65, 32, 32, 65, 40, 32, 65, 48, 32, 65, 56, + 32, 65, 65, 32, 56, 65, 32, 48, 65, 32, 40, 65, + 44, 44, 65, 48, 44, 65, 52, 44, 65, 60, 44, 65, + 65, 44, 65, 65, 44, 60, 65, 44, 52, 65, 44, 48, + 65, 44, 44, 65, 48, 44, 65, 52, 44, 65, 60, 44, + 65, 65, 44, 60, 65, 44, 52, 65, 44, 48, 65, 44, + 44, 65, 44, 44, 65, 48, 44, 65, 52, 44, 65, 60, + 44, 65, 65, 44, 60, 65, 44, 52, 65, 44, 48, 65, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + + int i; + + for(i=0;i<256;i++) { + pal.red[i]=raw_pal[i*3]; + pal.green[i]=raw_pal[(i*3)+1]; + pal.blue[i]=raw_pal[(i*3)+2]; + + } + return; + +} + +static int graphics_input(void) { + + SDL_Event event; + int keypressed; + + while ( SDL_PollEvent(&event)) { + + switch(event.type) { + + case SDL_KEYDOWN: + keypressed=event.key.keysym.sym; + switch (keypressed) { + + case SDLK_ESCAPE: + return 27; + } + break; + } + } + return 0; + +} + + +static void write_framebuffer(int address, int value) { + int real_addr; + + real_addr=address-0xa0000; + if ((real_addr<0) || (real_addr>320*200)) return; + + framebuffer[real_addr]=value; + +} + +/* unsigned multiply */ +static void mul_16(unsigned short value) { + unsigned int result; + + result=ax*value; + +// printf("%x*%x=%x ",value,ax,result); + + ax=result&0xffff; + dx=result>>16; + +// printf("%x:%x x=%d y=%d\n",dx,ax, +// dx&0xff,(dx>>8)&0xff); + + + + + if (dx==0) { + of=0; + cf=0; + } + else { + of=1; + cf=1; + } + +} + +/* +static void imul(short value) { + int result; + + result=ax*value; + + ax=result&0xffff; + dx=result>>16; + +} +*/ + + + +/* signed multiply */ +static void imul_8(char value) { + + short result; + char src; + + src=ax; + + result=src*value; + +// printf("imul: %d*%d=%d ",src,value,result); + + ax=result; + + if (ax==(ax&0xff)) { + cf=0; + of=0; + } + else { + cf=1; + of=1; + } + +} + +/* signed multiply */ +static void imul_16(short value) { + + int result; + short src; + + src=ax; + + result=src*value; + +// printf("imul: %d*%d=%d ",src,value,result); + + ax=(result&0xffff); + dx=((result>>16)&0xffff); + + if (dx==0) { + cf=0; + of=0; + } + else { + cf=1; + of=1; + } + +} + +/* signed multiply */ +static void imul_16_bx(short value) { + + int result; + short src; + + src=bx; + + result=src*value; + +// printf("imul: %d*%d=%d ",src,value,result); + + bx=(result&0xffff); + + if (bx==result) { + cf=0; + of=0; + } + else { + cf=1; + of=1; + } + +} + +/* signed multiply */ +static void imul_16_dx(short value) { + + int result; + short src; + + src=dx; + + result=src*value; + +// printf("imul: %d*%d=%d ",src,value,result); + + dx=(result&0xffff); + + if (dx==result) { + cf=0; + of=0; + } + else { + cf=1; + of=1; + } + +} + + + + + +/* unsigned divide */ +static void div_8(unsigned char value) { + + unsigned char r,q; + unsigned int result,remainder; + +// printf("Dividing %d (%x) by %d (%x): ",ax,ax,value,value); + + if (value==0) { + printf("Divide by zero!\n"); + return; + } + + result=ax/value; + remainder=ax%value; + + q=result; + r=remainder; + +// printf("Result: q=%d r=%d\n",q,r); + + ax=(r<<8)|(q&0xff); + +} + + + +static void push(int value) { + //printf("Pushing %x\n",value); + stack[sp]=value; + sp++; +} + +static short pop(void) { + if (sp==0) { + printf("Stack underflow!\n"); + return 0; + } + + sp--; + + //printf("Popping %x\n",stack[sp]); + + return stack[sp]; + +} + /* tilted plane */ + /* DH=Y, DL=X */ +static void fx0(void) { + + char ah,al,dh,dl; + unsigned short temp; + + ax=0x1329; // mov ax,0x1329 init + + al=ax&0xff; ah=(ax>>8)&0xff; + dl=dx&0xff; dh=(dx>>8)&0xff; + + + dh=dh+al; // add dh,al ; prevent divide overflow + div_8(dh); // div dh ; reverse divide AL=C/Y' + + dx=((dh&0xff)<<8)|dl; + + temp=ax; + ax=dx; dx=temp; // xchg dx,ax ; DL=C/Y' AL=X + + dl=dx&0xff; dh=(dx>>8)&0xff; + + imul_8(dl); // imul dl + dx=dx-bp; // sub dx,bp + dl=dx&0xff; + + ah=(ax>>8)&0xff; + ah=ah^dl; // xor ah,dl + al=ah; // mov al,ah + ax=((ah&0xff)<<8)|(al&0xff); + + ax&=0xff1c; // and al,4+8+16 +} + +/* circles? */ +/* DH=Y, DL=X */ +static void fx1(void) { + + int temp; + char al,dh,ah; + + // mov al,dh ; get Y in AL + al=(dx>>8)&0xff; + // sub al,100 ; align Y vertically + al=al-100; + ax=ax&0xff00; + ax=ax|al; + // imul al ; AL=Y*Y + imul_8(al); + // xchg dx,ax ; Y*Y/256 in DH, X in AL + temp=ax; + ax=dx; + dx=temp; + // imul al ; AL=X*X + imul_8(ax&0xff); + // add dh,ah ; DH=X*X+Y*Y/256 + dh=(dx>>8)&0xff; + ah=(ax>>8)&0xff; + dh=dh+ah; + // mov al,dh ; AL = X*X+Y*Y/256 + al=dh; + + dx=dx&0xff; + dx|=(dh<<8); + ax=(ah<<8)|(al&0xff); + + // add ax,bp ; offset color by time + ax=ax+bp; + // and al,8+16 ; select special rings + ax=ax&0xff18; +} + +/* checkers */ +static void fx2(void) { + int temp; + unsigned char al; + + temp=ax; + ax=dx; dx=temp; // xchg dx,ax + ax=ax-bp; // sub ax,bp + temp=((ax>>8)&0xff)^(ax&0xff); + ax=ax&0xff00; + ax|=temp; // xor al,ah + ax|=0xdb; // or al,0xdb + al=ax&0xff; + al=al+0x13; + ax=ax&0xff00; + ax=ax|al; // add al,13h + // ret + +} + + +/* parallax checkrboard */ +static void fx3(void) { + + cx=bp; // mov cx,bp ; set init point to time + bx=-16; // mov bx,-16 ; limit to 16 iterations +fx3L: + cx=cx+di; // add cx, di ; offset by screenpointer + ax=819; // mov ax,819 ; magic, related to Rrrola + imul_16(cx); // imul cx ; get X',Y' in DX + cf=dx&1; // ror dx,1 ; set carry flag on "hit" + dx=dx>>1; + if (cf) { + dx|=0x8000; + } + else { + dx&=0x7fff; + } + + bx++; // inc bx ; increment iteration count + if (bx==0) zf=1;// does not affect carry flag + else zf=0; + // ja fx3L ; loop until "hit" or "iter=max" + // jump above, if cf==0 and zf==0 + if ((cf==0) && (zf==0)) goto fx3L; + + ax=bx+31; // lea ax,[bx+32] ; map value to standard gray scale + //printf("%d %d\n",ax,bx); +} + +/* sierpinski rotozoomer */ +static void fx4(void) { + + unsigned char dl,dh,bh,al; + dl=dx&0xff; dh=(dx>>8)&0xff; + + cx=bp-2048; // lea cx,[bp-2048] ; center time to pass zero + cx=cx<<3; // sal cx,3 ; speed up by factor of 8! + ax=(dh&0xff); // movzx ax,dh ; get X into AL + // movsx dx,dl ; get Y into DL + if (dl&0x80) { + dx|=0xff00; + } + else { + dx&=0x00ff; + } + + bx=ax; // mov bx,ax ; save X in BX + imul_16_bx(cx); // imul bx,cx ; BX=X*T + + /* bl=bx&0xff; */ bh=(bx>>8)&0xff; + dl=dx&0xff; dh=(dx>>8)&0xff; + + bh=bh+dl; // add bh,dl ; bh=x*t/256+Y + + imul_16_dx(cx); // imul dx,cx ; dx=Y*T + + dl=dx&0xff; dh=(dx>>8)&0xff; + + // sub al,dh ; al=X-Y*T/256 + al=ax&0xff; // ah=(ax>>8)&0xff; + al=al-dh; + + // and al,bh ; AL=(X-Y*T/256)&(x*T/256+Y) + al=al&bh; + al=al&252; // and al,252 ; thicker sierpinksi + if (al==0) zf=1; + else zf=0; + cf=0; of=0; + // salc ; set pixel value to black + if (cf==0) al=0; + else al=0xff; + +/* NOTE: remove the line below and the background becomes a rainbow */ + ax=al; + // jnz fx4q ; leave black if not sierpinksi + if (zf==0) goto fx4q; + + ax=ax&0xff00; // mov al,0x2a ; otherwise: a nice orange + ax|=0x2a; +fx4q: + ; +} + + +/* raycast bent tunnel */ +static void fx5(void) { + + unsigned char al,cl; + unsigned short temp; + + cx=cx&0xff00; + cx|=(-9&0xff); // mov cl,-9 ; start with depth 9 (moves backwards) +fx5L: + cl=cx&0xff; + + push(dx); // push dx ; save DX, destroyed inside loop + al=(dx>>8)&0xff;// mov al,dh ; get Y into AL + al-=100; // sub al,100 ; centering Y manually + + ax=ax&0xff00; + ax|=(al&0xff); + + imul_8(cl); // imul cl ; multiply AL=Y by current distance to get projection + // xchg ax,dx ; gt X into AL while saving DX + temp=ax; + ax=dx; + dx=temp; + + al=ax&0xff; + al+=cl; // add al,cl ; add distance to projection (bend right) + + ax=ax&0xff00; + ax|=(al&0xff); + imul_8(cl); // imul cl ; multiply AL=X by the current projection + al=(dx>>8)&0xff;// mov al,dh ; get projection(1) in AL + al^=(ax>>8); // xor al,ah ; combine with projection(2) + al+=4; // add al,4 ; center the walls around 0 + if (al&-8) { // test al,-8 ; test if the wall is hit + zf=0; + } + else { + zf=1; + } + + dx=pop(); // pop dx (restore dx) + cx&=0xff00; + cx|=(cl&0xff); + cx--; + if ((cx!=0) && (zf==1)) goto fx5L; + // loopz fx5L (repeat until "hit" or "iter=max" + + cx=cx-bp; // sub cx,bp ; offset depth by time + al^=(cx&0xff); // xor al,cl ; XOR pattern for texture +// ah=al/6; + al=al%6; // aam 6 ; irregular pattern with MOD 6 + al+=20; // add al,20 ; offset into grayscale pattern + ax=al&0xff; +} + +/* ocean night */ +static void fx6(void) { + char dh; + double f; + int edx; + char scratch[64]; + + // bx coming in is the address of the effect + // this is a guess, too lazy to hexdump + bx=0x1d5; + + // si=?? based on sound playing? + // ax (sky color) is ? + + dh=dx>>8; + // sub dh,120 ; check if pixel in the sky + dh=dh-120; + sf=!!(dh&0x80); + // js fx6q ; quit if that's the case + if (sf) goto fx6q; + + dx&=0xff; + dx|=dh<<8; + + // mov [bx+si],dx ; move xy to memory location + // fild word [bx+si] ; read as integer + // fidivr dword [bx+si] ; reverse divide by constant + // Divide m32int by ST(0) and store result in ST(0) + // fstp dword [bx+si-1] ; store result as floating point + // mov ax,[bx+si] ; get result into ax + + memcpy(&scratch[32],&dx,sizeof(short)); + f=dx; + memcpy(&edx,&scratch[32],sizeof(int)); + f=f/edx; + memcpy(&scratch[31],&f,sizeof(double)); + memcpy(&ax,&scratch[32],sizeof(short)); + + + + + ax+=bp; // add ax,bp ; modify color by time + ax&=0xff80; // and al,128 ; threshold into two bands + ax--; // dec ax ; beautify colors to blue/black +fx6q: ; +} + + +int main(int argc, char **argv) { + + int temp; + + set_vga_pal(); + + mode13h_graphics_init(); + + di=0; + bp=0x13; // xchg bp,ax ; set bp to 0x13 + es=0xa000-10; + + while(1) { + + ax=0xcccd; // load rrrola constant + mul_16(di); // multiply + temp=(ax&0xff)+((ax>>8)&0xff); // add al,ah + ax=ax&0xff00; + ax|=(temp&0xff); + ax=ax&0xff; // xor ah,ah + ax=ax+bp; // add ax,bp + ax=ax>>9; // shr ax,9 + ax=ax&0xff0f; // and al,15 + temp=ax; // xchg bx,ax + ax=bx; + bx=temp; + bx=bx&0xff; // mov bh,1 + bx|=1<<8; + + switch (bx&0xff) { + case 0: fx2(); break; + case 1: fx1(); break; + case 2: fx0(); break; + case 3: fx3(); break; + case 4: fx4(); break; + case 5: fx5(); break; + case 6: fx6(); break; + case 7: goto end; + default: printf("Trying effect %d\n",bx&0xff); + } + // stosb + write_framebuffer((es<<4)+di, ax&0xff); + di++; + + di++; // inc di + di++; // inc di + if (di!=0) continue; + + mode13h_graphics_update(framebuffer,&pal); + + usleep(10000); + bp=bp+1; + + if (graphics_input()) { + return 0; + } + } + +end: + + return 0; +}