Better late than never, I've added a wireframe mode to aid with engine and scene debuggin. The demo below will run at maximum FPS (frames per second) so that you can see the difference in performance between shaded and wireframe modes. Use the cursor keys to move, 'a' to jump and 'w' to toggle wireframe. The FPS readout will reset each time the mode is changed.
Within the 'scene' class I've added a boolean named 'wireframeMode' and a public method 'toggleWireframe()'. other scene objects but still within the far clipping distance.
public void toggleWireframe() {
if (wireframeMode) {
wireframeMode = false;
} else {
wireframeMode = true;
}
}
During processing the scene renderer checks whether wireframe mode is enabled and if so, uses the 'Wireframe' method instead of the usual triangle rasteriser.
public void Wireframe(nw3d_vertex a,
nw3d_vertex b, nw3d_vertex c, nw3d_material col) {
v1.copy(a);
v1.x=(int)(cam.dist*a.x/a.z+0.5);
v1.y=(int)(cam.dist*a.y/a.z+0.5);
v1.z=1/a.z;
v2.copy(b);
v2.x=(int)(cam.dist*b.x/b.z+0.5);
v2.y=(int)(cam.dist*b.y/b.z+0.5);
v2.z=1/b.z;
v3.copy(c);
v3.x=(int)(cam.dist*c.x/c.z+0.5);
v3.y=(int)(cam.dist*c.y/c.z+0.5);
v3.z=1/c.z;
drawLine(v1, v2, col);
drawLine(v1, v3, col);
drawLine(v2, v3, col);
}
As you can see, this method performs the 2D screen projection and then calls 'drawLine' three times to join the points of the triangle.
public void drawLine(nw3d_vertex p1, nw3d_vertex p2, nw3d_material c) {
int pixind,pf,pt;
float tempz;
double tempx,tempy,dz,dy,dx;
int colRed,colGreen,colBlue,diffx,diffy;
//Create wireframe colour
colRed = (int)(c.r*0xff);
colGreen = (int)(c.g*0xff);
colBlue = (int)(c.b*0xff);
int wfcol=0xff<<24|(colRed<0xff?colRed:0xff)<<16|
(colGreen<0xff?colGreen:0xff)<<8|
(colBlue<0xff?colBlue:0xff);
tempz=(float)p1.z;
diffx=(int)(Math.abs(p2.x-p1.x));
diffy=(int)(Math.abs(p2.y-p1.y));
//Decide on which way to move in pixel resolution based
//on the slope of the line.
//Move horizontally
if (diffx >= diffy) {
if (diffx>0) {
//But are we stepping left to right or right to left?
if (p2.x < p1.x) {
pf = (int)p2.x;
pt = (int)p1.x;
tempy = p2.y;
dy=(p1.y-p2.y)/diffx;
dz=(p1.z-p2.z)/diffx;
} else {
pf = (int)p1.x;
pt = (int)p2.x;
tempy = p1.y;
dy=(p2.y-p1.y)/diffx;
dz=(p2.z-p1.z)/diffx;
}
for (int i=pf; i<=pt; i++) {
pixind = (my-(int)tempy)*width+mx+i;
if (pixind > 0 && pixind < size) {
if (tempz > zBuffer[pixind]) {
pBuffer[pixind]=wfcol;
zBuffer[pixind]=tempz;
}
}
tempy+=dy;
tempz+=dz;
}
}
//Move vertically
} else {
if (diffy>0) {
//But are we stepping top to bottom or bottom to top?
if (p2.y < p1.y) {
pf = (int)p2.y;
pt = (int)p1.y;
tempx = p2.x;
dx=(p1.x-p2.x)/diffy;
dz=(p1.z-p2.z)/diffy;
} else {
pf = (int)p1.y;
pt = (int)p2.y;
tempx = p1.x;
dx=(p2.x-p1.x)/diffy;
dz=(p2.z-p1.z)/diffy;
}
for (int i=pf; i<=pt; i++) {
pixind = (my-i)*width+mx+(int)tempx;
if (pixind > 0 && pixind < size) {
if (tempz > zBuffer[pixind]) {
pBuffer[pixind]=wfcol;
zBuffer[pixind]=tempz;
}
}
tempx+=dx;
tempz+=dz;
}
}
}
}
Based on the slope of the line we either pixel step horizontally or vertically. The opposing axis will use sub-pixel accuracy to ensure that we don't leave any gaps in the line. The z-buffer is still used so that foreground line priority is respected. There is no lighting/shading of the line colour, the basic diffuse colour is used for all pixels.