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;
127 if ( k
<0 ) k
=0; if (k
>255) k
=255;
132 /***********************************************************************************/
134 int lasty
[SCREENWIDTH
], /* Last pixel drawn on a given column */
135 lastc
[SCREENWIDTH
]; /* Color of last pixel on a column */
138 Draw a "section" of the landscape; x0,y0 and x1,y1 and the xy coordinates
139 on the height field, hy is the viewpoint height, s is the scaling factor
140 for the distance. x0,y0,x1,y1 are 16.16 fixed point numbers and the
141 scaling factor is a 16.8 fixed point value.
144 /***********************************************************************************/
146 void line(int x0
,int y0
,int x1
,int y1
,int hy
,int s
)
150 /* Compute xy speed */
151 sx
=(x1
-x0
)/SCREENWIDTH
; sy
=(y1
-y0
)/SCREENWIDTH
;
152 for ( i
=0; i
<SCREENWIDTH
; i
++ )
154 int c
,y
,h
,u0
,v0
,u1
,v1
,a
,b
,h0
,h1
,h2
,h3
;
156 /* Compute the xy coordinates; a and b will be the position inside the
157 single map cell (0..255).
159 u0
=(x0
>>16)&0xFF; a
=(x0
>>8)&255;
160 v0
=((y0
>>8)&0xFF00); b
=(y0
>>8)&255;
164 /* Fetch the height at the four corners of the square the point is in */
165 h0
=HMap
[u0
+v0
]; h2
=HMap
[u0
+v1
];
166 h1
=HMap
[u1
+v0
]; h3
=HMap
[u1
+v1
];
168 /* Compute the height using bilinear interpolation */
169 h0
=(h0
<<8)+a
*(h1
-h0
);
170 h2
=(h2
<<8)+a
*(h3
-h2
);
171 h
=((h0
<<8)+b
*(h2
-h0
))>>16;
173 /* Fetch the color at the four corners of the square the point is in */
174 h0
=CMap
[u0
+v0
]; h2
=CMap
[u0
+v1
];
175 h1
=CMap
[u1
+v0
]; h3
=CMap
[u1
+v1
];
177 /* Compute the color using bilinear interpolation (in 16.16) */
178 h0
=(h0
<<8)+a
*(h1
-h0
);
179 h2
=(h2
<<8)+a
*(h3
-h2
);
180 c
=((h0
<<8)+b
*(h2
-h0
));
182 /* Compute screen height using the scaling factor */
183 y
=(((h
-hy
)*s
)>>11)+100;
185 /* Draw the column */
186 if ( y
<(a
=lasty
[i
]) )
188 unsigned char *b
=Video
+a
*SCREENWIDTH
+i
;
195 sc
=(c
-lastc
[i
])/(a
-y
);
198 if ( a
>(SCREENHEIGHT
-1) ) { b
-=(a
-(SCREENHEIGHT
-1))*SCREENWIDTH
; cc
+=(a
-(SCREENHEIGHT
-1))*sc
; a
=SCREENHEIGHT
-1; }
210 /* Advance to next xy position */
215 /***********************************************************************************/
217 float FOV
=3.141592654/4; /* half of the xy field of view */
219 /***********************************************************************************/
222 // Draw the view from the point x0,y0 (16.16) looking at angle a
224 void View(int x0
,int y0
,float aa
)
227 int a
,b
,h
,u0
,v0
,u1
,v1
,h0
,h1
,h2
,h3
;
230 /* Clear offscreen buffer */
231 memset(Video
,0,SCREENWIDTH
*SCREENHEIGHT
);
235 for(b
= 0; b
< SCREENHEIGHT
; b
++)
237 memset(Video
+ b
* SCREENWIDTH
, 64 + ((256 - 64) * b
/ (SCREENHEIGHT
-1)), SCREENWIDTH
);
240 /* Initialize last-y and last-color arrays */
241 for ( d
=0; d
<SCREENWIDTH
; d
++ )
243 lasty
[d
]=SCREENHEIGHT
;
247 /* Compute viewpoint height value */
249 /* Compute the xy coordinates; a and b will be the position inside the
250 single map cell (0..255).
252 u0
=(x0
>>16)&0xFF; a
=(x0
>>8)&255;
253 v0
=((y0
>>8)&0xFF00); b
=(y0
>>8)&255;
257 /* Fetch the height at the four corners of the square the point is in */
258 h0
=HMap
[u0
+v0
]; h2
=HMap
[u0
+v1
];
259 h1
=HMap
[u1
+v0
]; h3
=HMap
[u1
+v1
];
261 /* Compute the height using bilinear interpolation */
262 h0
=(h0
<<8)+a
*(h1
-h0
);
263 h2
=(h2
<<8)+a
*(h3
-h2
);
264 h
=((h0
<<8)+b
*(h2
-h0
))>>16;
266 /* Draw the landscape from near to far without overdraw */
267 for ( d
=0; d
<100; d
+=1+(d
>>6) )
269 line(x0
+d
*65536*cos(aa
-FOV
),y0
+d
*65536*sin(aa
-FOV
),
270 x0
+d
*65536*cos(aa
+FOV
),y0
+d
*65536*sin(aa
+FOV
),
271 h
-30,SCREENCY
*256/(d
+1));
276 WriteLUTPixelArray(Video
,
292 UBYTE
*dest
= Video_Remapped
;
294 for(i
= 0; i
< SCREENWIDTH
* SCREENHEIGHT
; i
++)
296 *dest
++ = remaptable
[*src
++];
298 WriteChunkyPixels(rp
,
301 win
->BorderLeft
+ SCREENWIDTH
- 1,
302 win
->BorderTop
+ SCREENHEIGHT
- 1,
309 WriteChunkyPixels(rp
,
312 win
->BorderLeft
+ SCREENWIDTH
- 1,
313 win
->BorderTop
+ SCREENHEIGHT
- 1,
320 /***********************************************************************************/
322 void cleanup(char *msg
)
326 printf("newvox: %s\n",msg
);
329 if (win
) CloseWindow(win
);
335 for(i
= 0; i
< 256; i
++)
337 ReleasePen(scr
->ViewPort
.ColorMap
, remaptable
[i
]);
344 UnlockPubScreen(0, scr
);
349 if (CyberGfxBase
) CloseLibrary(CyberGfxBase
);
350 if (GfxBase
) CloseLibrary((struct Library
*)GfxBase
);
351 if (IntuitionBase
) CloseLibrary((struct Library
*)IntuitionBase
);
356 /***********************************************************************************/
358 #define ARG_TEMPLATE "STARTFLYSPEED=S/N/K,WINPOSX=X/N/K,WINPOSY=Y/N/K,FORCESCREEN=SCR/S,FORCEWINDOW=WIN/S"
366 static IPTR args
[NUM_ARGS
];
368 static void getarguments(void)
370 struct RDArgs
*myargs
;
372 if ((myargs
= ReadArgs(ARG_TEMPLATE
, args
, NULL
)))
376 else if (args
[ARG_WIN
])
379 if (args
[ARG_X
]) winx
= *(IPTR
*)args
[ARG_X
];
380 if (args
[ARG_Y
]) winy
= *(IPTR
*)args
[ARG_Y
];
382 if (args
[ARG_SPEED
]) startflyspeed
= (float)(*(IPTR
*)args
[ARG_SPEED
]);
388 /***********************************************************************************/
392 if (!(IntuitionBase
= (struct IntuitionBase
*)OpenLibrary("intuition.library", 39)))
394 cleanup("Can't open intuition.library V39!");
397 if (!(GfxBase
= (struct GfxBase
*)OpenLibrary("graphics.library", 39)))
399 cleanup("Can't open graphics.library V39!");
402 if (!(CyberGfxBase
= OpenLibrary("cybergraphics.library",0)))
404 cleanup("Can't open cybergraphics.library!");
408 /***********************************************************************************/
412 if (!(scr
= LockPubScreen(NULL
)))
414 cleanup("Can't lock pub screen!");
417 if (GetBitMapAttr(scr
->RastPort
.BitMap
, BMA_DEPTH
) <= 8)
429 if (forcescreen
) wbscreen
= FALSE
;
433 UnlockPubScreen(NULL
, scr
);
436 scr
= OpenScreenTags(NULL
, SA_Width
, SCREENWIDTH
,
437 SA_Height
, SCREENHEIGHT
,
440 if (!scr
) cleanup("Can't open screen!");
443 truecolor
= (GetBitMapAttr(scr
->RastPort
.BitMap
, BMA_DEPTH
) >= 15) ? TRUE
: FALSE
;
446 /***********************************************************************************/
450 struct TagItem winonwbtags
[] =
452 {WA_DragBar
, TRUE
},
453 {WA_DepthGadget
, TRUE
},
454 {WA_CloseGadget
, TRUE
},
455 {WA_Title
, (IPTR
)"NewVox" },
459 struct TagItem winonscrtags
[] =
461 {WA_Borderless
, TRUE
},
465 if (winx
== -1) winx
= (scr
->Width
- SCREENWIDTH
- scr
->WBorLeft
- scr
->WBorRight
) / 2;
466 if (winy
== -1) winy
= (scr
->Height
- SCREENHEIGHT
- scr
->WBorTop
- scr
->WBorTop
- scr
->Font
->ta_YSize
- 1) / 2;
468 win
= OpenWindowTags(NULL
, WA_CustomScreen
, (IPTR
)scr
,
471 WA_InnerWidth
, SCREENWIDTH
,
472 WA_InnerHeight
, SCREENHEIGHT
,
473 WA_AutoAdjust
, TRUE
,
475 WA_IDCMP
, IDCMP_CLOSEWINDOW
|
477 TAG_MORE
, wbscreen
? winonwbtags
: winonscrtags
);
480 if (!win
) cleanup("Can't open window");
485 /***********************************************************************************/
488 #define KC_RIGHT 0x4E
493 /***********************************************************************************/
497 struct IntuiMessage
*msg
;
499 while ((msg
= (struct IntuiMessage
*)GetMsg(win
->UserPort
)))
503 case IDCMP_CLOSEWINDOW
:
509 WORD code
= msg
->Code
& ~IECODE_UP_PREFIX
;
511 Keys
[code
] = (code
== msg
->Code
) ? 1 : 0;
517 ReplyMsg((struct Message
*)msg
);
522 /***********************************************************************************/
524 int main(int argc
, char *argv
[])
535 /* Set up the first 64 colors to a grayscale */
536 for ( i
=0; i
<64; i
++ )
538 ULONG red
, green
, blue
;
540 /* red = green = blue = i * 4; */
541 green
= i
* 4; red
= blue
= 10;
543 cgfx_coltab
[i
] = (red
<< 16) + (green
<< 8) + blue
;
546 /* stegerg: add a sky */
547 for (i
= 0; i
< (256 - 64); i
++)
549 ULONG red
, green
, blue
;
552 red
= green
= 255 - (i
* 255 / (256 - 64 - 1));
554 cgfx_coltab
[64 + i
] = (red
<< 16) + (green
<< 8) + blue
;
561 for(i
= 0; i
< 256; i
++)
563 ULONG r
= (cgfx_coltab
[i
] >> 16) & 0xFF;
564 ULONG g
= (cgfx_coltab
[i
] >> 8) & 0xFF;
565 ULONG b
= cgfx_coltab
[i
] & 0xFF;
569 ULONG red
= r
* 0x01010101;
570 ULONG green
= g
* 0x01010101;
571 ULONG blue
= b
* 0x01010101;
573 remaptable
[i
] = ObtainBestPen(scr
->ViewPort
.ColorMap
,
577 OBP_Precision
, PRECISION_IMAGE
,
578 OBP_FailIfBad
, FALSE
,
585 ULONG red
= r
* 0x01010101;
586 ULONG green
= g
* 0x01010101;
587 ULONG blue
= b
* 0x01010101;
589 SetRGB32(&scr
->ViewPort
, i
, red
, green
, blue
);
594 /* Compute the height map */
602 x0,y0 = current position
604 ss = current forward/backward speed
610 ss
=startflyspeed
; sa
=0;
616 /* Update position/angle */
617 x0
+=ss
*cos(a
); y0
+=ss
*sin(a
);
620 /* Slowly reset the angle to 0 */
642 if (Keys
[KC_RIGHT
]) {
656 /***********************************************************************************/