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




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














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



Hosted by uCoz