// ------------------------------------------------------------------------------------- // Render a texture map with lighting using perspective interpolation in inner and outer loops. // ------------------------------------------------------------------------------------- void ntexture_map_lighted_linear(grs_bitmap *srcb, g3ds_tmap *t) { int vlt,vrt,vlb,vrb; // vertex left top, vertex right top, vertex left bottom, vertex right bottom int topy,boty,y, dy; fix dx_dy_left,dx_dy_right; fix du_dy_left,du_dy_right; fix dv_dy_left,dv_dy_right; fix dl_dy_left,dl_dy_right; int max_y_vertex; fix xleft,xright,uleft,vleft,uright,vright,lleft,lright; int next_break_left, next_break_right; fix recip_dyl, recip_dyr; g3ds_vertex *v3d; //remove stupid warnings in compile dl_dy_left = F1_0; dl_dy_right = F1_0; lleft = F1_0; lright = F1_0; v3d = t->verts; // Determine top and bottom y coords. compute_y_bounds(t,&vlt,&vlb,&vrt,&vrb,&max_y_vertex); // Set top and bottom (of entire texture map) y coordinates. topy = f2i(v3d[vlt].y2d); boty = f2i(v3d[max_y_vertex].y2d); if (topy > Window_clip_bot) return; if (boty > Window_clip_bot) boty = Window_clip_bot; dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dyl = fix_recip[dy]; else recip_dyl = F1_0/dy; dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dyr = fix_recip[dy]; else recip_dyr = F1_0/dy; // Set amount to change x coordinate for each advance to next scanline. dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dyl); dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dyr); du_dy_left = compute_du_dy_lin(t,vlt,vlb, recip_dyl); du_dy_right = compute_du_dy_lin(t,vrt,vrb, recip_dyr); dv_dy_left = compute_dv_dy_lin(t,vlt,vlb, recip_dyl); dv_dy_right = compute_dv_dy_lin(t,vrt,vrb, recip_dyr); if (Lighting_enabled) { dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dyl); dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dyr); lleft = v3d[vlt].l; lright = v3d[vrt].l; } // Set initial values for x, u, v xleft = v3d[vlt].x2d; xright = v3d[vrt].x2d; uleft = v3d[vlt].u; uright = v3d[vrt].u; vleft = v3d[vlt].v; vright = v3d[vrt].v; // scan all rows in texture map from top through first break. next_break_left = f2i(v3d[vlb].y2d); next_break_right = f2i(v3d[vrb].y2d); for (y = topy; y < boty; y++) { // See if we have reached the end of the current left edge, and if so, set // new values for dx_dy and x,u,v if (y == next_break_left) { fix recip_dy; // Handle problem of double points. Search until y coord is different. Cannot get // hung in an infinite loop because we know there is a vertex with a lower y coordinate // because in the for loop, we don't scan all spanlines. while (y == f2i(v3d[vlb].y2d)) { vlt = vlb; vlb = prevmod(vlb,t->nv); } next_break_left = f2i(v3d[vlb].y2d); dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dy = fix_recip[dy]; else recip_dy = F1_0/dy; dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy); xleft = v3d[vlt].x2d; uleft = v3d[vlt].u; vleft = v3d[vlt].v; lleft = v3d[vlt].l; du_dy_left = compute_du_dy_lin(t,vlt,vlb, recip_dy); dv_dy_left = compute_dv_dy_lin(t,vlt,vlb, recip_dy); if (Lighting_enabled) { dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dy); lleft = v3d[vlt].l; } } // See if we have reached the end of the current left edge, and if so, set // new values for dx_dy and x. Not necessary to set new values for u,v. if (y == next_break_right) { fix recip_dy; while (y == f2i(v3d[vrb].y2d)) { vrt = vrb; vrb = succmod(vrb,t->nv); } dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dy = fix_recip[dy]; else recip_dy = F1_0/dy; next_break_right = f2i(v3d[vrb].y2d); dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy); xright = v3d[vrt].x2d; uright = v3d[vrt].u; vright = v3d[vrt].v; du_dy_right = compute_du_dy_lin(t,vrt,vrb, recip_dy); dv_dy_right = compute_dv_dy_lin(t,vrt,vrb, recip_dy); if (Lighting_enabled) { dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dy); lright = v3d[vrt].l; } } if (Lighting_enabled) { ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright); lleft += dl_dy_left; lright += dl_dy_right; } else ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright); uleft += du_dy_left; vleft += dv_dy_left; uright += du_dy_right; vright += dv_dy_right; xleft += dx_dy_left; xright += dx_dy_right; } // We can get lleft or lright out of bounds here because we compute dl_dy using fixed point values, // but we plot an integer number of scanlines, therefore doing an integer number of additions of the delta. ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright); }
// ------------------------------------------------------------------------------------- // Render a texture map. // Linear in outer loop, linear in inner loop. // ------------------------------------------------------------------------------------- void texture_map_flat(g3ds_tmap *t, int color) { int vlt,vrt,vlb,vrb; // vertex left top, vertex right top, vertex left bottom, vertex right bottom int topy,boty,y, dy; fix dx_dy_left,dx_dy_right; int max_y_vertex; fix xleft,xright; fix recip_dy; g3ds_vertex *v3d; v3d = t->verts; tmap_flat_color = color; // Determine top and bottom y coords. compute_y_bounds(t,&vlt,&vlb,&vrt,&vrb,&max_y_vertex); // Set top and bottom (of entire texture map) y coordinates. topy = f2i(v3d[vlt].y2d); boty = f2i(v3d[max_y_vertex].y2d); // Set amount to change x coordinate for each advance to next scanline. dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dy = fix_recip[dy]; else recip_dy = F1_0/dy; dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy); dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dy = fix_recip[dy]; else recip_dy = F1_0/dy; dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy); // Set initial values for x, u, v xleft = v3d[vlt].x2d; xright = v3d[vrt].x2d; // scan all rows in texture map from top through first break. // @mk: Should we render the scanline for y==boty? This violates Matt's spec. for (y = topy; y < boty; y++) { // See if we have reached the end of the current left edge, and if so, set // new values for dx_dy and x,u,v if (y == f2i(v3d[vlb].y2d)) { // Handle problem of double points. Search until y coord is different. Cannot get // hung in an infinite loop because we know there is a vertex with a lower y coordinate // because in the for loop, we don't scan all spanlines. while (y == f2i(v3d[vlb].y2d)) { vlt = vlb; vlb = prevmod(vlb,t->nv); } dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dy = fix_recip[dy]; else recip_dy = F1_0/dy; dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy); xleft = v3d[vlt].x2d; } // See if we have reached the end of the current left edge, and if so, set // new values for dx_dy and x. Not necessary to set new values for u,v. if (y == f2i(v3d[vrb].y2d)) { while (y == f2i(v3d[vrb].y2d)) { vrt = vrb; vrb = succmod(vrb,t->nv); } dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dy = fix_recip[dy]; else recip_dy = F1_0/dy; dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy); xright = v3d[vrt].x2d; } //tmap_scanline_flat(y, xleft, xright); (*scanline_func)(y, xleft, xright); xleft += dx_dy_left; xright += dx_dy_right; } //tmap_scanline_flat(y, xleft, xright); (*scanline_func)(y, xleft, xright); }
// ------------------------------------------------------------------------------------- // Select topmost vertex (minimum y coordinate) and bottommost (maximum y coordinate) in // texture map. If either is part of a horizontal edge, then select leftmost vertex for // top, rightmost vertex for bottom. // Important: Vertex is selected with integer precision. So, if there are vertices at // (0.0,0.7) and (0.5,0.3), the first vertex is selected, because they y coordinates are // considered the same, so the smaller x is favored. // Parameters: // nv number of vertices // v3d pointer to 3d vertices containing u,v,x2d,y2d coordinates // Results in: // *min_y_ind // *max_y_ind // ------------------------------------------------------------------------------------- void compute_y_bounds(g3ds_tmap *t, int *vlt, int *vlb, int *vrt, int *vrb,int *bottom_y_ind) { int i; int min_y,max_y; int min_y_ind; int original_vrt; fix min_x; // Scan all vertices, set min_y_ind to vertex with smallest y coordinate. min_y = f2i(t->verts[0].y2d); max_y = min_y; min_y_ind = 0; min_x = f2i(t->verts[0].x2d); *bottom_y_ind = 0; for (i=1; i<t->nv; i++) { if (f2i(t->verts[i].y2d) < min_y) { min_y = f2i(t->verts[i].y2d); min_y_ind = i; min_x = f2i(t->verts[i].x2d); } else if (f2i(t->verts[i].y2d) == min_y) { if (f2i(t->verts[i].x2d) < min_x) { min_y_ind = i; min_x = f2i(t->verts[i].x2d); } } if (f2i(t->verts[i].y2d) > max_y) { max_y = f2i(t->verts[i].y2d); *bottom_y_ind = i; } } //--removed mk, 11/27/94-- // Check for a non-upright-hourglass polygon and fix, if necessary, by bashing a y coordinate. //--removed mk, 11/27/94-- // min_y_ind = index of minimum y coordinate, *bottom_y_ind = index of maximum y coordinate //--removed mk, 11/27/94--{ //--removed mk, 11/27/94-- int max_temp, min_temp; //--removed mk, 11/27/94-- //--removed mk, 11/27/94-- max_temp = *bottom_y_ind; //--removed mk, 11/27/94-- if (*bottom_y_ind < min_y_ind) //--removed mk, 11/27/94-- max_temp += t->nv; //--removed mk, 11/27/94-- //--removed mk, 11/27/94-- for (i=min_y_ind; i<max_temp; i++) { //--removed mk, 11/27/94-- if (f2i(t->verts[i%t->nv].y2d) > f2i(t->verts[(i+1)%t->nv].y2d)) { //--removed mk, 11/27/94-- Int3(); //--removed mk, 11/27/94-- t->verts[(i+1)%t->nv].y2d = t->verts[i%t->nv].y2d; //--removed mk, 11/27/94-- } //--removed mk, 11/27/94-- } //--removed mk, 11/27/94-- //--removed mk, 11/27/94-- min_temp = min_y_ind; //--removed mk, 11/27/94-- if (min_y_ind < *bottom_y_ind) //--removed mk, 11/27/94-- min_temp += t->nv; //--removed mk, 11/27/94-- //--removed mk, 11/27/94-- for (i=*bottom_y_ind; i<min_temp; i++) { //--removed mk, 11/27/94-- if (f2i(t->verts[i%t->nv].y2d) < f2i(t->verts[(i+1)%t->nv].y2d)) { //--removed mk, 11/27/94-- Int3(); //--removed mk, 11/27/94-- t->verts[(i+1)%t->nv].y2d = t->verts[i%t->nv].y2d; //--removed mk, 11/27/94-- } //--removed mk, 11/27/94-- } //--removed mk, 11/27/94--} // Set "vertex left top", etc. based on vertex with topmost y coordinate *vlt = min_y_ind; *vrt = *vlt; *vlb = prevmod(*vlt,t->nv); *vrb = succmod(*vrt,t->nv); // If right edge is horizontal, then advance along polygon bound until it no longer is or until all // vertices have been examined. // (Left edge cannot be horizontal, because *vlt is set to leftmost point with highest y coordinate.) original_vrt = *vrt; while (f2i(t->verts[*vrt].y2d) == f2i(t->verts[*vrb].y2d)) { if (succmod(*vrt,t->nv) == original_vrt) { break; } *vrt = succmod(*vrt,t->nv); *vrb = succmod(*vrt,t->nv); } }