4 Ok.. i know that voxel is something else... but a lot of people is using
5 the name "voxel" to mean this kind of rendering tecnique.
6 I wrote this to explain the basic idea behind the rendering of newvox4;
7 newvox4 is very badly written (it's named 4 because is the fourth of
8 a sequel of experiments) and is coded in pascal + asm.
9 Since i got a few request of an explanation i decided to write the kernel
10 of the rendering in C hoping that this will be easier to understand.
11 This implements only the base landscape (no sky or floating ball) and
12 with keyboard only support but i think you can get the idea of how I
13 implemented those other things.
15 I'm releasing this code to the public domain for free... and as it's
16 probably really obvious there's no warranty of any kind on it.
17 You can do whatever you want with this source; however a credit in any
18 program that uses part of this code would be really appreciated :)
20 Any comment is welcome :)
22 Andrea "6502" Griffini, programmer
24 http://vv.val.net/~agriffini
27 #include <intuition/intuition.h>
28 #include <graphics/gfx.h>
29 #include <cybergraphx/cybergraphics.h>
30 #include <proto/exec.h>
31 #include <proto/dos.h>
32 #include <proto/graphics.h>
33 #include <proto/cybergraphics.h>
34 #include <proto/intuition.h>
41 #define SCREENWIDTH 320
42 #define SCREENHEIGHT 200
43 #define SCREENCY (SCREENHEIGHT / 2)
45 /***********************************************************************************/
47 struct IntuitionBase
*IntuitionBase
;
48 struct GfxBase
*GfxBase
;
49 struct Library
*CyberGfxBase
;
54 ULONG cgfx_coltab
[256];
55 UBYTE remaptable
[256];
57 WORD winx
= -1, winy
= -1;
58 BOOL forcescreen
, forcewindow
;
59 BOOL mustremap
, truecolor
, remapped
, wbscreen
= TRUE
;
60 float startflyspeed
= 0;
62 /***********************************************************************************/
64 typedef unsigned char byte
;
66 byte HMap
[256*256]; /* Height field */
67 byte CMap
[256*256]; /* Color map */
68 byte Video
[SCREENWIDTH
*SCREENHEIGHT
]; /* Off-screen buffer */
69 byte Video_Remapped
[SCREENWIDTH
*SCREENHEIGHT
];
71 /***********************************************************************************/
73 /* Reduces a value to 0..255 (used in height field computation) */
76 return (x
<0 ? 0 : (x
>255 ? 255 : x
));
79 /***********************************************************************************/
81 /* Heightfield and colormap computation */
86 /* Start from a plasma clouds fractal */
88 for ( p
=256; p
>1; p
=p2
)
92 for ( i
=0; i
<256; i
+=p
)
94 for ( j
=0; j
<256; j
+=p
)
99 b
=HMap
[(((i
+p
)&255)<<8)+j
];
100 c
=HMap
[(i
<<8)+((j
+p
)&255)];
101 d
=HMap
[(((i
+p
)&255)<<8)+((j
+p
)&255)];
103 HMap
[(i
<<8)+((j
+p2
)&255)]=
104 Clamp(((a
+c
)>>1)+(rand()%k
-k2
));
105 HMap
[(((i
+p2
)&255)<<8)+((j
+p2
)&255)]=
106 Clamp(((a
+b
+c
+d
)>>2)+(rand()%k
-k2
));
107 HMap
[(((i
+p2
)&255)<<8)+j
]=
108 Clamp(((a
+b
)>>1)+(rand()%k
-k2
));
114 for ( k
=0; k
<3; k
++ )
115 for ( i
=0; i
<256*256; i
+=256 )
116 for ( j
=0; j
<256; j
++ )
118 HMap
[i
+j
]=(HMap
[((i
+256)&0xFF00)+j
]+HMap
[i
+((j
+1)&0xFF)]+
119 HMap
[((i
-256)&0xFF00)+j
]+HMap
[i
+((j
-1)&0xFF)])>>2;
122 /* Color computation (derivative of the height field) */
123 for ( i
=0; i
<256*256; i
+=256 )
124 for ( j
=0; j
<256; j
++ )
126 k
=128+(HMap
[((i
+256)&0xFF00)+((j
+1)&255)]-HMap
[i
+j
])*4;
133 /***********************************************************************************/
135 int lasty
[SCREENWIDTH
], /* Last pixel drawn on a given column */
136 lastc
[SCREENWIDTH
]; /* Color of last pixel on a column */
139 Draw a "section" of the landscape; x0,y0 and x1,y1 and the xy coordinates
140 on the height field, hy is the viewpoint height, s is the scaling factor
141 for the distance. x0,y0,x1,y1 are 16.16 fixed point numbers and the
142 scaling factor is a 16.8 fixed point value.
145 /***********************************************************************************/
147 void line(int x0
,int y0
,int x1
,int y1
,int hy
,int s
)
151 /* Compute xy speed */
152 sx
=(x1
-x0
)/SCREENWIDTH
; sy
=(y1
-y0
)/SCREENWIDTH
;
153 for ( i
=0; i
<SCREENWIDTH
; i
++ )
155 int c
,y
,h
,u0
,v0
,u1
,v1
,a
,b
,h0
,h1
,h2
,h3
;
157 /* Compute the xy coordinates; a and b will be the position inside the
158 single map cell (0..255).
160 u0
=(x0
>>16)&0xFF; a
=(x0
>>8)&255;
161 v0
=((y0
>>8)&0xFF00); b
=(y0
>>8)&255;
165 /* Fetch the height at the four corners of the square the point is in */
166 h0
=HMap
[u0
+v0
]; h2
=HMap
[u0
+v1
];
167 h1
=HMap
[u1
+v0
]; h3
=HMap
[u1
+v1
];
169 /* Compute the height using bilinear interpolation */
170 h0
=(h0
<<8)+a
*(h1
-h0
);
171 h2
=(h2
<<8)+a
*(h3
-h2
);
172 h
=((h0
<<8)+b
*(h2
-h0
))>>16;
174 /* Fetch the color at the four corners of the square the point is in */
175 h0
=CMap
[u0
+v0
]; h2
=CMap
[u0
+v1
];
176 h1
=CMap
[u1
+v0
]; h3
=CMap
[u1
+v1
];
178 /* Compute the color using bilinear interpolation (in 16.16) */
179 h0
=(h0
<<8)+a
*(h1
-h0
);
180 h2
=(h2
<<8)+a
*(h3
-h2
);
181 c
=((h0
<<8)+b
*(h2
-h0
));
183 /* Compute screen height using the scaling factor */
184 y
=(((h
-hy
)*s
)>>11)+100;
186 /* Draw the column */
187 if ( y
<(a
=lasty
[i
]) )
189 unsigned char *b
=Video
+a
*SCREENWIDTH
+i
;
196 sc
=(c
-lastc
[i
])/(a
-y
);
199 if ( a
>(SCREENHEIGHT
-1) ) { b
-=(a
-(SCREENHEIGHT
-1))*SCREENWIDTH
; cc
+=(a
-(SCREENHEIGHT
-1))*sc
; a
=SCREENHEIGHT
-1; }
211 /* Advance to next xy position */
216 /***********************************************************************************/
218 float FOV
=3.141592654/4; /* half of the xy field of view */
220 /***********************************************************************************/
223 // Draw the view from the point x0,y0 (16.16) looking at angle a
225 void View(int x0
,int y0
,float aa
)
228 int a
,b
,h
,u0
,v0
,u1
,v1
,h0
,h1
,h2
,h3
;
231 /* Clear offscreen buffer */
232 memset(Video
,0,SCREENWIDTH
*SCREENHEIGHT
);
236 for(b
= 0; b
< SCREENHEIGHT
; b
++)
238 memset(Video
+ b
* SCREENWIDTH
, 64 + ((256 - 64) * b
/ (SCREENHEIGHT
-1)), SCREENWIDTH
);
241 /* Initialize last-y and last-color arrays */
242 for ( d
=0; d
<SCREENWIDTH
; d
++ )
244 lasty
[d
]=SCREENHEIGHT
;
248 /* Compute viewpoint height value */
250 /* Compute the xy coordinates; a and b will be the position inside the
251 single map cell (0..255).
253 u0
=(x0
>>16)&0xFF; a
=(x0
>>8)&255;
254 v0
=((y0
>>8)&0xFF00); b
=(y0
>>8)&255;
258 /* Fetch the height at the four corners of the square the point is in */
259 h0
=HMap
[u0
+v0
]; h2
=HMap
[u0
+v1
];
260 h1
=HMap
[u1
+v0
]; h3
=HMap
[u1
+v1
];
262 /* Compute the height using bilinear interpolation */
263 h0
=(h0
<<8)+a
*(h1
-h0
);
264 h2
=(h2
<<8)+a
*(h3
-h2
);
265 h
=((h0
<<8)+b
*(h2
-h0
))>>16;
267 /* Draw the landscape from near to far without overdraw */
268 for ( d
=0; d
<100; d
+=1+(d
>>6) )
270 line(x0
+d
*65536*cos(aa
-FOV
),y0
+d
*65536*sin(aa
-FOV
),
271 x0
+d
*65536*cos(aa
+FOV
),y0
+d
*65536*sin(aa
+FOV
),
272 h
-30,SCREENCY
*256/(d
+1));
277 WriteLUTPixelArray(Video
,
293 UBYTE
*dest
= Video_Remapped
;
295 for(i
= 0; i
< SCREENWIDTH
* SCREENHEIGHT
; i
++)
297 *dest
++ = remaptable
[*src
++];
299 WriteChunkyPixels(rp
,
302 win
->BorderLeft
+ SCREENWIDTH
- 1,
303 win
->BorderTop
+ SCREENHEIGHT
- 1,
310 WriteChunkyPixels(rp
,
313 win
->BorderLeft
+ SCREENWIDTH
- 1,
314 win
->BorderTop
+ SCREENHEIGHT
- 1,
321 /***********************************************************************************/
323 void cleanup(char *msg
)
327 printf("newvox: %s\n",msg
);
330 if (win
) CloseWindow(win
);
336 for(i
= 0; i
< 256; i
++)
338 ReleasePen(scr
->ViewPort
.ColorMap
, remaptable
[i
]);
345 UnlockPubScreen(0, scr
);
350 if (CyberGfxBase
) CloseLibrary(CyberGfxBase
);
351 if (GfxBase
) CloseLibrary((struct Library
*)GfxBase
);
352 if (IntuitionBase
) CloseLibrary((struct Library
*)IntuitionBase
);
357 /***********************************************************************************/
359 #define ARG_TEMPLATE "STARTFLYSPEED=S/N/K,WINPOSX=X/N/K,WINPOSY=Y/N/K,FORCESCREEN=SCR/S,FORCEWINDOW=WIN/S"
367 static IPTR args
[NUM_ARGS
];
369 static void getarguments(void)
371 struct RDArgs
*myargs
;
373 if ((myargs
= ReadArgs(ARG_TEMPLATE
, args
, NULL
)))
377 else if (args
[ARG_WIN
])
380 if (args
[ARG_X
]) winx
= *(IPTR
*)args
[ARG_X
];
381 if (args
[ARG_Y
]) winy
= *(IPTR
*)args
[ARG_Y
];
383 if (args
[ARG_SPEED
]) startflyspeed
= (float)(*(IPTR
*)args
[ARG_SPEED
]);
389 /***********************************************************************************/
393 if (!(IntuitionBase
= (struct IntuitionBase
*)OpenLibrary("intuition.library", 39)))
395 cleanup("Can't open intuition.library V39!");
398 if (!(GfxBase
= (struct GfxBase
*)OpenLibrary("graphics.library", 39)))
400 cleanup("Can't open graphics.library V39!");
403 if (!(CyberGfxBase
= OpenLibrary("cybergraphics.library",0)))
405 cleanup("Can't open cybergraphics.library!");
409 /***********************************************************************************/
411 static void getvisual(void)
418 scr
= OpenScreenTags(NULL
, SA_Width
, SCREENWIDTH
,
419 SA_Height
, SCREENHEIGHT
,
422 if (!scr
) cleanup("Failed to open specified screen!");
424 else if (!(scr
= LockPubScreen(NULL
)))
426 cleanup("Failed to lock pub screen (workbench)!");
429 truecolor
= (GetBitMapAttr(scr
->RastPort
.BitMap
, BMA_DEPTH
) >= 15) ? TRUE
: FALSE
;
431 if ((!truecolor
) && (wbscreen
))
435 /***********************************************************************************/
439 struct TagItem winonwbtags
[] =
441 {WA_DragBar
, TRUE
},
442 {WA_DepthGadget
, TRUE
},
443 {WA_CloseGadget
, TRUE
},
444 {WA_Title
, (IPTR
)"NewVox" },
448 struct TagItem winonscrtags
[] =
450 {WA_Borderless
, TRUE
},
454 if (winx
== -1) winx
= (scr
->Width
- SCREENWIDTH
- scr
->WBorLeft
- scr
->WBorRight
) / 2;
455 if (winy
== -1) winy
= (scr
->Height
- SCREENHEIGHT
- scr
->WBorTop
- scr
->WBorTop
- scr
->Font
->ta_YSize
- 1) / 2;
457 win
= OpenWindowTags(NULL
, WA_CustomScreen
, (IPTR
)scr
,
460 WA_InnerWidth
, SCREENWIDTH
,
461 WA_InnerHeight
, SCREENHEIGHT
,
462 WA_AutoAdjust
, TRUE
,
464 WA_IDCMP
, IDCMP_CLOSEWINDOW
|
466 TAG_MORE
, wbscreen
? winonwbtags
: winonscrtags
);
469 if (!win
) cleanup("Can't open window");
474 /***********************************************************************************/
477 #define KC_RIGHT 0x4E
482 /***********************************************************************************/
486 struct IntuiMessage
*msg
;
488 while ((msg
= (struct IntuiMessage
*)GetMsg(win
->UserPort
)))
492 case IDCMP_CLOSEWINDOW
:
498 WORD code
= msg
->Code
& ~IECODE_UP_PREFIX
;
500 Keys
[code
] = (code
== msg
->Code
) ? 1 : 0;
506 ReplyMsg((struct Message
*)msg
);
511 /***********************************************************************************/
513 int main(int argc
, char *argv
[])
524 /* Set up the first 64 colors to a grayscale */
525 for ( i
=0; i
<64; i
++ )
527 ULONG red
, green
, blue
;
529 /* red = green = blue = i * 4; */
530 green
= i
* 4; red
= blue
= 10;
532 cgfx_coltab
[i
] = (red
<< 16) + (green
<< 8) + blue
;
535 /* stegerg: add a sky */
536 for (i
= 0; i
< (256 - 64); i
++)
538 ULONG red
, green
, blue
;
541 red
= green
= 255 - (i
* 255 / (256 - 64 - 1));
543 cgfx_coltab
[64 + i
] = (red
<< 16) + (green
<< 8) + blue
;
550 for(i
= 0; i
< 256; i
++)
552 ULONG r
= (cgfx_coltab
[i
] >> 16) & 0xFF;
553 ULONG g
= (cgfx_coltab
[i
] >> 8) & 0xFF;
554 ULONG b
= cgfx_coltab
[i
] & 0xFF;
558 ULONG red
= r
* 0x01010101;
559 ULONG green
= g
* 0x01010101;
560 ULONG blue
= b
* 0x01010101;
562 remaptable
[i
] = ObtainBestPen(scr
->ViewPort
.ColorMap
,
566 OBP_Precision
, PRECISION_IMAGE
,
567 OBP_FailIfBad
, FALSE
,
574 ULONG red
= r
* 0x01010101;
575 ULONG green
= g
* 0x01010101;
576 ULONG blue
= b
* 0x01010101;
578 SetRGB32(&scr
->ViewPort
, i
, red
, green
, blue
);
583 /* Compute the height map */
591 x0,y0 = current position
593 ss = current forward/backward speed
599 ss
=startflyspeed
; sa
=0;
605 /* Update position/angle */
606 x0
+=ss
*cos(a
); y0
+=ss
*sin(a
);
609 /* Slowly reset the angle to 0 */
631 if (Keys
[KC_RIGHT
]) {
645 /***********************************************************************************/