DarkOneТs Wolf3D source tutorial ╣3.
Knee-Deep in the Brick
The purpose of this tutorial is to make textured floor/ceiling in Wolf3D. This feature will give your engine the best boost in visual quality, so letТs get to work:
WeТll work in WL_DRAW.C file:
First find the following line:
unsignedа wallheight[MAXVIEWWIDTH;
And modify it like this:
unsignedа wallheight[MAXVIEWWIDTH], min_wallheight;
Then add following lines to the end of CalcHeight function:
intа CalcHeight (void)
{
<..>
<.here is original CalcHeight code.>
<..>
// update min_wallheight
а asm mov bx,[min_wallheight]
а asm cmp ax,bx
а asm jae noupdate:
а asm mov [min_wallheight],ax
noupdate:;
}
Then add the following macro declaration just
before the start of vgaCeiling array declaration:
#define USE_TEX(page) (0x0000|(page))
/*
** use USE_TEX(n) to use floor/ceiling textures for given level
** n should be 1..255 !!!
** it is MAP-ID (from FloEdit). First texture goes to floor, second to ceiling
*/
unsigned vgaCeiling[]=
Now we are about to write the main texturing
code: add this function just after vgaCeiling array declaration:
// ------------------------- * Textured flats * -------------------------
/*
** Draw Textured Floor/Ceiling
*/
void DrawFlats(unsigned tex_f, unsigned tex_c)
{
а int x, y, y0, halfheight;
а unsigned top_offset0, bot_offset0, top_offset, bot_offset;
а unsigned top_add, bot_add;
а byte p, color;
а byte far *src_bot, far *src_top;
а fixed dist;ааааааааааа // distance to row projection
а fixed tex_step;ааааааа // global step per one screen pixel
а fixed gu, gv, du, dv; // global texture coordinates
а int u, v;ааааааааааааа // local texture coordinates
// ------ * prepare * --------
а halfheight=viewheight>>1;
а y0=min_wallheight>>3;ааааа // starting y value
а if(y0>halfheight) return;а // view obscued by walls
а if(y0==0) y0=1;аааааааааа // don't let division by zero
а top_offset0=80*(halfheight-y0-1);а // and will decrease by 80 each row
а bot_offset0=80*(halfheight+y0);а // and will increase by 80 each row
а src_bot=PM_GetPage(tex_f); // load floor texture
а src_top=PM_GetPage(tex_c); // load ceiling texture
// draw horizontal lines
а for(p=0; p<4; p++)
а {
ааа asm mov ax,0x0102
ааа asm mov cl,[p]
ааа asm shl ah,cl
ааа asm mov dx,0x3c4
ааа asm out dx,ax
ааа for(y=y0, top_offset=top_offset0, bot_offset=bot_offset0; y<halfheight; y++, top_offset-=80, bot_offset+=80)
ааа {
ааааа dist=(heightnumerator/y)<<5;
ааааа gu= viewx+FixedByFrac(dist, viewcos);
ааааа gv=-viewy+FixedByFrac(dist, viewsin);
ааааа tex_step=(dist<<8)/viewwidth/175;
ааааа du= FixedByFrac(tex_step, viewsin);
ааааа dv=-FixedByFrac(tex_step, viewcos);
ааааа gu-=((viewwidth>>1)-p)*du;
ааааа gv-=((viewwidth>>1)-p)*dv; // starting point (leftmost)
ааааа du<<=2; // 4pix step
ааааа dv<<=2;
ааааа for(x=p, top_add=top_offset, bot_add=bot_offset; x<viewwidth; x+=4, top_add++, bot_add++)
ааааа {
ааааааа if(wallheight[x]>>3<=y)
ааааааа {
ааааааааа u=(gu>>10)&63; v=(gv>>10)&63;
ааааааааа color=*(src_top+((63-u)<<6)+(63-v));
// draw top pixel using [color]
ааааааааа asm mov es,[screenseg]
ааааааааа asm mov di,[bufferofs]
ааааааааа asm add di,[top_add]
а
ааааааааа asm mov al,[color]
ааааааааа asm mov es:[di],al
ааааааааа color=*(src_bot+(u<<6)+(63-v));
// draw bottom pixel using [color]
ааааааааа asm mov es,[screenseg]
ааааааааа asm mov di,[bufferofs]
ааааааааа asm add di,[bot_add]
а
ааааааааа asm mov al,[color]
ааааааааа asm mov es:[di],al
ааааааа }
ааааааа gu+=du; gv+=dv;
ааааа }
ааа }
а }
}
Be careful with it, itТs big and itТs easy to miss something. After that change VGAClearScreen like this:
void VGAClearScreen(unsigned ceiling)
{
ааа //
ааа // clear the screen
ааа //
As you see IТve removed ceiling variable from the function and added a parameter with the same name.
The last thing we will modify is ThreeDRefresh function:
void ThreeDRefresh (void)
{
ааа int tracedir;
ааа unsigned ceiling;
ааа boolean flats;
<..>
//
// follow the walls from there to the right, drawwing as we go
//
ааа ceiling=vgaCeiling[gamestate.episode*10+mapon];
ааа if((ceiling>>8)==(ceiling&0xFF))
ааа {
ааааааааа VGAClearScreen(ceiling);
ааааааааа flats=false;
ааа }
ааа else
ааа {
ааааааааа flats=true;
ааааааааа ceiling=((ceiling&0xFF)-1)<<1;
ааа }
ааа WallRefresh();
ааа if(flats)
ааааааааа DrawFlats(ceiling, ceiling+1); // draw textured floor/ceiling
Ok, enough coding, letТs learn how to use this feature. First you should find a pair of images: one for floor, one for ceiling texture. They should look like texture, of course this is not a must, but it would look silly. I selected the following images:
а
Then I used something called like F*Edit to import them to my data files. I used indexes 62 and 63 (note that first index must be even and second index must be equal to first plus 1. This would make MAP-ID the same for both of them!), and remembered MAP-ID, 32 in this case.
Then IТve chosen a level(s) to be textured using these textures (for simplicity it would be e1m1).
So I modified vgaCeiling array like that:
unsigned vgaCeiling[]=
{
#ifndef SPEAR
аUSE_TEX(32),0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xbfbf,
а0x4e4e,0x4e4e,0x4e4e,0x1d1d,0x8d8d,0x4e4e,0x1d1d,0x2d2d,0x1d1d,0x8d8d,
а0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x2d2d,0xdddd,0x1d1d,0x1d1d,0x9898,
а0x1d1d,0x9d9d,0x2d2d,0xdddd,0xdddd,0x9d9d,0x2d2d,0x4d4d,0x1d1d,0xdddd,
а0x7d7d,0x1d1d,0x2d2d,0x2d2d,0xdddd,0xd7d7,0x1d1d,0x1d1d,0x1d1d,0x2d2d,
а0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xdddd,0xdddd,0x7d7d,0xdddd,0xdddd,0xdddd
#else
а0x6f6f,0x4f4f,0x1d1d,0xdede,0xdfdf,0x2e2e,0x7f7f,0x9e9e,0xaeae,0x7f7f,
а0x1d1d,0xdede,0xdfdf,0xdede,0xdfdf,0xdede,0xe1e1,0xdcdc,0x2e2e,0x1d1d,0xdcdc
#endif
};
Note that I used MAP-ID, I remembered!
ThatТs all. IТve built .exe and started it. Here is a result:
Voila! ThatТs it!
I hope this thing helped you on your way to create the best Wolf3D conversion ever made. If so, just drop me a line on DarkOne@navigators.lv. I wish to see your work!
--
й 2002 DarkOne; part of NewWolf project