Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 1 | pmbaty | 1 | /* |
| 2 | * Portions of this file are copyright Rebirth contributors and licensed as |
||
| 3 | * described in COPYING.txt. |
||
| 4 | * Portions of this file are copyright Parallax Software and licensed |
||
| 5 | * according to the Parallax license below. |
||
| 6 | * See COPYING.txt for license details. |
||
| 7 | |||
| 8 | THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX |
||
| 9 | SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO |
||
| 10 | END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A |
||
| 11 | ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS |
||
| 12 | IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS |
||
| 13 | SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE |
||
| 14 | FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE |
||
| 15 | CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS |
||
| 16 | AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. |
||
| 17 | COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. |
||
| 18 | */ |
||
| 19 | |||
| 20 | /* |
||
| 21 | * |
||
| 22 | * Start of conversion to new texture mapper. |
||
| 23 | * |
||
| 24 | */ |
||
| 25 | |||
| 26 | #include "pstypes.h" |
||
| 27 | #include "maths.h" |
||
| 28 | #include "vecmat.h" |
||
| 29 | #include "gr.h" |
||
| 30 | #include "3d.h" |
||
| 31 | #include "dxxerror.h" |
||
| 32 | #include "render.h" |
||
| 33 | #include "texmap.h" |
||
| 34 | #include "texmapl.h" |
||
| 35 | #include "rle.h" |
||
| 36 | #include "scanline.h" |
||
| 37 | #include "u_mem.h" |
||
| 38 | |||
| 39 | #include "dxxsconf.h" |
||
| 40 | #include "dsx-ns.h" |
||
| 41 | #include <utility> |
||
| 42 | |||
| 43 | namespace dcx { |
||
| 44 | |||
| 45 | #if DXX_USE_EDITOR |
||
| 46 | #define EDITOR_TMAP 1 //if in, include extra stuff |
||
| 47 | #endif |
||
| 48 | |||
| 49 | // Temporary texture map, interface from Matt's 3d system to Mike's texture mapper. |
||
| 50 | |||
| 51 | int Lighting_on=1; // initialize to no lighting |
||
| 52 | unsigned Current_seg_depth; // HACK INTERFACE: how far away the current segment (& thus texture) is |
||
| 53 | |||
| 54 | // These variables are the interface to assembler. They get set for each texture map, which is a real waste of time. |
||
| 55 | // They should be set only when they change, which is generally when the window bounds change. And, even still, it's |
||
| 56 | // a pretty bad interface. |
||
| 57 | int bytes_per_row=-1; |
||
| 58 | unsigned char *write_buffer; |
||
| 59 | |||
| 60 | fix fx_l, fx_u, fx_v, fx_z, fx_du_dx, fx_dv_dx, fx_dz_dx, fx_dl_dx; |
||
| 61 | int fx_xleft, fx_xright, fx_y; |
||
| 62 | const unsigned char *pixptr; |
||
| 63 | uint8_t Transparency_on = 0; |
||
| 64 | uint8_t tmap_flat_color; |
||
| 65 | |||
| 66 | int Interpolation_method; // 0 = choose best method |
||
| 67 | // ------------------------------------------------------------------------------------- |
||
| 68 | template <std::size_t... N> |
||
| 69 | static inline constexpr const std::array<fix, 1 + sizeof...(N)> init_fix_recip_table(std::index_sequence<0, N...>) |
||
| 70 | { |
||
| 71 | /* gcc 4.5 fails on bare initializer list */ |
||
| 72 | return std::array<fix, 1 + sizeof...(N)>{{F1_0, (F1_0 / N)...}}; |
||
| 73 | } |
||
| 74 | |||
| 75 | constexpr std::array<fix, FIX_RECIP_TABLE_SIZE> fix_recip_table = init_fix_recip_table(std::make_index_sequence<FIX_RECIP_TABLE_SIZE>()); |
||
| 76 | |||
| 77 | // ------------------------------------------------------------------------------------- |
||
| 78 | // Initialize interface variables to assembler. |
||
| 79 | // These things used to be constants. This routine is now (10/6/93) getting called for |
||
| 80 | // every texture map. It should get called whenever the window changes, or, preferably, |
||
| 81 | // not at all. I'm pretty sure these variables are only being used for range checking. |
||
| 82 | void init_interface_vars_to_assembler(void) |
||
| 83 | { |
||
| 84 | grs_bitmap *bp; |
||
| 85 | bp = &grd_curcanv->cv_bitmap; |
||
| 86 | |||
| 87 | Assert(bp!=NULL); |
||
| 88 | Assert(bp->bm_data!=NULL); |
||
| 89 | // If bytes_per_row has changed, create new table of pointers. |
||
| 90 | if (bytes_per_row != static_cast<int>(bp->bm_rowsize)) { |
||
| 91 | bytes_per_row = static_cast<int>(bp->bm_rowsize); |
||
| 92 | } |
||
| 93 | |||
| 94 | write_buffer = bp->bm_mdata; |
||
| 95 | |||
| 96 | Window_clip_left = 0; |
||
| 97 | Window_clip_right = static_cast<int>(bp->bm_w)-1; |
||
| 98 | Window_clip_top = 0; |
||
| 99 | Window_clip_bot = static_cast<int>(bp->bm_h)-1; |
||
| 100 | } |
||
| 101 | |||
| 102 | static int Lighting_enabled; |
||
| 103 | // ------------------------------------------------------------------------------------- |
||
| 104 | // VARIABLES |
||
| 105 | |||
| 106 | // ------------------------------------------------------------------------------------- |
||
| 107 | // Returns number preceding val modulo modulus. |
||
| 108 | // prevmod(3,4) = 2 |
||
| 109 | // prevmod(0,4) = 3 |
||
| 110 | int prevmod(int val,int modulus) |
||
| 111 | { |
||
| 112 | if (val > 0) |
||
| 113 | return val-1; |
||
| 114 | else |
||
| 115 | return modulus-1; |
||
| 116 | // return (val + modulus - 1) % modulus; |
||
| 117 | } |
||
| 118 | |||
| 119 | |||
| 120 | // Returns number succeeding val modulo modulus. |
||
| 121 | // succmod(3,4) = 0 |
||
| 122 | // succmod(0,4) = 1 |
||
| 123 | int succmod(int val,int modulus) |
||
| 124 | { |
||
| 125 | if (val < modulus-1) |
||
| 126 | return val+1; |
||
| 127 | else |
||
| 128 | return 0; |
||
| 129 | |||
| 130 | // return (val + 1) % modulus; |
||
| 131 | } |
||
| 132 | |||
| 133 | // ------------------------------------------------------------------------------------- |
||
| 134 | // Select topmost vertex (minimum y coordinate) and bottommost (maximum y coordinate) in |
||
| 135 | // texture map. If either is part of a horizontal edge, then select leftmost vertex for |
||
| 136 | // top, rightmost vertex for bottom. |
||
| 137 | // Important: Vertex is selected with integer precision. So, if there are vertices at |
||
| 138 | // (0.0,0.7) and (0.5,0.3), the first vertex is selected, because they y coordinates are |
||
| 139 | // considered the same, so the smaller x is favored. |
||
| 140 | // Parameters: |
||
| 141 | // nv number of vertices |
||
| 142 | // v3d pointer to 3d vertices containing u,v,x2d,y2d coordinates |
||
| 143 | // Results in: |
||
| 144 | // *min_y_ind |
||
| 145 | // *max_y_ind |
||
| 146 | // ------------------------------------------------------------------------------------- |
||
| 147 | void compute_y_bounds(const g3ds_tmap &t, int &vlt, int &vlb, int &vrt, int &vrb,int &bottom_y_ind) |
||
| 148 | { |
||
| 149 | int min_y,max_y; |
||
| 150 | int min_y_ind; |
||
| 151 | int original_vrt; |
||
| 152 | fix min_x; |
||
| 153 | |||
| 154 | // Scan all vertices, set min_y_ind to vertex with smallest y coordinate. |
||
| 155 | min_y = f2i(t.verts[0].y2d); |
||
| 156 | max_y = min_y; |
||
| 157 | min_y_ind = 0; |
||
| 158 | min_x = f2i(t.verts[0].x2d); |
||
| 159 | bottom_y_ind = 0; |
||
| 160 | |||
| 161 | for (int i=1; i<t.nv; i++) { |
||
| 162 | if (f2i(t.verts[i].y2d) < min_y) { |
||
| 163 | min_y = f2i(t.verts[i].y2d); |
||
| 164 | min_y_ind = i; |
||
| 165 | min_x = f2i(t.verts[i].x2d); |
||
| 166 | } else if (f2i(t.verts[i].y2d) == min_y) { |
||
| 167 | if (f2i(t.verts[i].x2d) < min_x) { |
||
| 168 | min_y_ind = i; |
||
| 169 | min_x = f2i(t.verts[i].x2d); |
||
| 170 | } |
||
| 171 | } |
||
| 172 | if (f2i(t.verts[i].y2d) > max_y) { |
||
| 173 | max_y = f2i(t.verts[i].y2d); |
||
| 174 | bottom_y_ind = i; |
||
| 175 | } |
||
| 176 | } |
||
| 177 | |||
| 178 | //--removed mk, 11/27/94-- // Check for a non-upright-hourglass polygon and fix, if necessary, by bashing a y coordinate. |
||
| 179 | //--removed mk, 11/27/94-- // min_y_ind = index of minimum y coordinate, *bottom_y_ind = index of maximum y coordinate |
||
| 180 | //--removed mk, 11/27/94--{ |
||
| 181 | //--removed mk, 11/27/94-- int max_temp, min_temp; |
||
| 182 | //--removed mk, 11/27/94-- |
||
| 183 | //--removed mk, 11/27/94-- max_temp = *bottom_y_ind; |
||
| 184 | //--removed mk, 11/27/94-- if (*bottom_y_ind < min_y_ind) |
||
| 185 | //--removed mk, 11/27/94-- max_temp += t->nv; |
||
| 186 | //--removed mk, 11/27/94-- |
||
| 187 | //--removed mk, 11/27/94-- for (i=min_y_ind; i<max_temp; i++) { |
||
| 188 | //--removed mk, 11/27/94-- if (f2i(t->verts[i%t->nv].y2d) > f2i(t->verts[(i+1)%t->nv].y2d)) { |
||
| 189 | //--removed mk, 11/27/94-- Int3(); |
||
| 190 | //--removed mk, 11/27/94-- t->verts[(i+1)%t->nv].y2d = t->verts[i%t->nv].y2d; |
||
| 191 | //--removed mk, 11/27/94-- } |
||
| 192 | //--removed mk, 11/27/94-- } |
||
| 193 | //--removed mk, 11/27/94-- |
||
| 194 | //--removed mk, 11/27/94-- min_temp = min_y_ind; |
||
| 195 | //--removed mk, 11/27/94-- if (min_y_ind < *bottom_y_ind) |
||
| 196 | //--removed mk, 11/27/94-- min_temp += t->nv; |
||
| 197 | //--removed mk, 11/27/94-- |
||
| 198 | //--removed mk, 11/27/94-- for (i=*bottom_y_ind; i<min_temp; i++) { |
||
| 199 | //--removed mk, 11/27/94-- if (f2i(t->verts[i%t->nv].y2d) < f2i(t->verts[(i+1)%t->nv].y2d)) { |
||
| 200 | //--removed mk, 11/27/94-- Int3(); |
||
| 201 | //--removed mk, 11/27/94-- t->verts[(i+1)%t->nv].y2d = t->verts[i%t->nv].y2d; |
||
| 202 | //--removed mk, 11/27/94-- } |
||
| 203 | //--removed mk, 11/27/94-- } |
||
| 204 | //--removed mk, 11/27/94--} |
||
| 205 | |||
| 206 | // Set "vertex left top", etc. based on vertex with topmost y coordinate |
||
| 207 | vlb = prevmod(vlt = min_y_ind,t.nv); |
||
| 208 | vrb = succmod(vrt = vlt,t.nv); |
||
| 209 | |||
| 210 | // If right edge is horizontal, then advance along polygon bound until it no longer is or until all |
||
| 211 | // vertices have been examined. |
||
| 212 | // (Left edge cannot be horizontal, because *vlt is set to leftmost point with highest y coordinate.) |
||
| 213 | |||
| 214 | original_vrt = vrt; |
||
| 215 | |||
| 216 | while (f2i(t.verts[vrt].y2d) == f2i(t.verts[vrb].y2d)) { |
||
| 217 | if (succmod(vrt,t.nv) == original_vrt) { |
||
| 218 | break; |
||
| 219 | } |
||
| 220 | vrt = succmod(vrt,t.nv); |
||
| 221 | vrb = succmod(vrt,t.nv); |
||
| 222 | } |
||
| 223 | } |
||
| 224 | |||
| 225 | // ------------------------------------------------------------------------------------- |
||
| 226 | // Returns dx/dy given two vertices. |
||
| 227 | // If dy == 0, returns 0.0 |
||
| 228 | // ------------------------------------------------------------------------------------- |
||
| 229 | //--fix compute_dx_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex) |
||
| 230 | //--{ |
||
| 231 | //-- int dy; |
||
| 232 | //-- |
||
| 233 | //-- // compute delta x with respect to y for any edge |
||
| 234 | //-- dy = f2i(t->verts[bottom_vertex].y2d - t->verts[top_vertex].y2d) + 1; |
||
| 235 | //-- if (dy) |
||
| 236 | //-- return (t->verts[bottom_vertex].x2d - t->verts[top_vertex].x2d) / dy; |
||
| 237 | //-- else |
||
| 238 | //-- return 0; |
||
| 239 | //-- |
||
| 240 | //--} |
||
| 241 | |||
| 242 | //#if !DXX_USE_OGL |
||
| 243 | static fix compute_du_dy_lin(const g3ds_tmap &t, int top_vertex,int bottom_vertex, fix recip_dy) |
||
| 244 | { |
||
| 245 | return fixmul(t.verts[bottom_vertex].u - t.verts[top_vertex].u, recip_dy); |
||
| 246 | } |
||
| 247 | |||
| 248 | |||
| 249 | static fix compute_dv_dy_lin(const g3ds_tmap &t, int top_vertex,int bottom_vertex, fix recip_dy) |
||
| 250 | { |
||
| 251 | return fixmul(t.verts[bottom_vertex].v - t.verts[top_vertex].v, recip_dy); |
||
| 252 | } |
||
| 253 | |||
| 254 | static fix compute_dl_dy_lin(const g3ds_tmap &t, int top_vertex,int bottom_vertex, fix recip_dy) |
||
| 255 | { |
||
| 256 | return fixmul(t.verts[bottom_vertex].l - t.verts[top_vertex].l, recip_dy); |
||
| 257 | } |
||
| 258 | |||
| 259 | fix compute_dx_dy(const g3ds_tmap &t, int top_vertex,int bottom_vertex, fix recip_dy) |
||
| 260 | { |
||
| 261 | return fixmul(t.verts[bottom_vertex].x2d - t.verts[top_vertex].x2d, recip_dy); |
||
| 262 | } |
||
| 263 | |||
| 264 | static fix compute_du_dy(const g3ds_tmap &t, int top_vertex,int bottom_vertex, fix recip_dy) |
||
| 265 | { |
||
| 266 | return fixmul(fixmul(t.verts[bottom_vertex].u,t.verts[bottom_vertex].z) - fixmul(t.verts[top_vertex].u,t.verts[top_vertex].z), recip_dy); |
||
| 267 | } |
||
| 268 | |||
| 269 | static fix compute_dv_dy(const g3ds_tmap &t, int top_vertex,int bottom_vertex, fix recip_dy) |
||
| 270 | { |
||
| 271 | return fixmul(fixmul(t.verts[bottom_vertex].v,t.verts[bottom_vertex].z) - fixmul(t.verts[top_vertex].v,t.verts[top_vertex].z), recip_dy); |
||
| 272 | } |
||
| 273 | |||
| 274 | static fix compute_dz_dy(const g3ds_tmap &t, int top_vertex,int bottom_vertex, fix recip_dy) |
||
| 275 | { |
||
| 276 | return fixmul(t.verts[bottom_vertex].z - t.verts[top_vertex].z, recip_dy); |
||
| 277 | |||
| 278 | } |
||
| 279 | |||
| 280 | // ------------------------------------------------------------------------------------- |
||
| 281 | // Texture map current scanline in perspective. |
||
| 282 | // ------------------------------------------------------------------------------------- |
||
| 283 | static void ntmap_scanline_lighted(const grs_bitmap &srcb, int y, fix xleft, fix xright, fix uleft, fix uright, fix vleft, fix vright, fix zleft, fix zright, fix lleft, fix lright) |
||
| 284 | { |
||
| 285 | fix dx,recip_dx; |
||
| 286 | |||
| 287 | fx_xright = f2i(xright); |
||
| 288 | //edited 06/27/99 Matt Mueller - moved these tests up from within the switch so as not to do a bunch of needless calculations when we are just gonna return anyway. Slight fps boost? |
||
| 289 | if (fx_xright < Window_clip_left) |
||
| 290 | return; |
||
| 291 | fx_xleft = f2i(xleft); |
||
| 292 | if (fx_xleft > Window_clip_right) |
||
| 293 | return; |
||
| 294 | //end edit -MM |
||
| 295 | |||
| 296 | dx = fx_xright - fx_xleft; |
||
| 297 | if ((dx < 0) || (xright < 0) || (xleft > xright)) // the (xleft > xright) term is not redundant with (dx < 0) because dx is computed using integers |
||
| 298 | return; |
||
| 299 | |||
| 300 | // setup to call assembler scanline renderer |
||
| 301 | recip_dx = fix_recip(dx); |
||
| 302 | |||
| 303 | fx_u = uleft; |
||
| 304 | fx_v = vleft; |
||
| 305 | fx_z = zleft; |
||
| 306 | |||
| 307 | fx_du_dx = fixmul(uright - uleft,recip_dx); |
||
| 308 | fx_dv_dx = fixmul(vright - vleft,recip_dx); |
||
| 309 | fx_dz_dx = fixmul(zright - zleft,recip_dx); |
||
| 310 | fx_y = y; |
||
| 311 | pixptr = srcb.bm_data; |
||
| 312 | |||
| 313 | switch (Lighting_enabled) { |
||
| 314 | case 0: |
||
| 315 | //added 05/17/99 Matt Mueller - prevent writing before the buffer |
||
| 316 | if ((fx_y == 0) && (fx_xleft < 0)) |
||
| 317 | fx_xleft = 0; |
||
| 318 | //end addition -MM |
||
| 319 | if (fx_xright > Window_clip_right) |
||
| 320 | fx_xright = Window_clip_right; |
||
| 321 | |||
| 322 | cur_tmap_scanline_per(); |
||
| 323 | break; |
||
| 324 | case 1: { |
||
| 325 | fix mul_thing; |
||
| 326 | |||
| 327 | if (lleft < 0) lleft = 0; |
||
| 328 | if (lright < 0) lright = 0; |
||
| 329 | if (lleft > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) lleft = (NUM_LIGHTING_LEVELS*F1_0-F1_0/2); |
||
| 330 | if (lright > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) lright = (NUM_LIGHTING_LEVELS*F1_0-F1_0/2); |
||
| 331 | |||
| 332 | fx_l = lleft; |
||
| 333 | fx_dl_dx = fixmul(lright - lleft,recip_dx); |
||
| 334 | |||
| 335 | // This is a pretty ugly hack to prevent lighting overflows. |
||
| 336 | mul_thing = dx * fx_dl_dx; |
||
| 337 | if (lleft + mul_thing < 0) |
||
| 338 | fx_dl_dx += 12; |
||
| 339 | else if (lleft + mul_thing > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) |
||
| 340 | fx_dl_dx -= 12; |
||
| 341 | |||
| 342 | //added 05/17/99 Matt Mueller - prevent writing before the buffer |
||
| 343 | if ((fx_y == 0) && (fx_xleft < 0)) |
||
| 344 | fx_xleft = 0; |
||
| 345 | //end addition -MM |
||
| 346 | if (fx_xright > Window_clip_right) |
||
| 347 | fx_xright = Window_clip_right; |
||
| 348 | |||
| 349 | cur_tmap_scanline_per(); |
||
| 350 | break; |
||
| 351 | } |
||
| 352 | case 2: |
||
| 353 | #ifdef EDITOR_TMAP |
||
| 354 | fx_xright = f2i(xright); |
||
| 355 | fx_xleft = f2i(xleft); |
||
| 356 | |||
| 357 | tmap_flat_color = 1; |
||
| 358 | cur_tmap_scanline_flat(); |
||
| 359 | #else |
||
| 360 | Int3(); // Illegal, called an editor only routine! |
||
| 361 | #endif |
||
| 362 | break; |
||
| 363 | } |
||
| 364 | |||
| 365 | } |
||
| 366 | |||
| 367 | // ------------------------------------------------------------------------------------- |
||
| 368 | // Render a texture map with lighting using perspective interpolation in inner and outer loops. |
||
| 369 | // ------------------------------------------------------------------------------------- |
||
| 370 | static void ntexture_map_lighted(const grs_bitmap &srcb, const g3ds_tmap &t) |
||
| 371 | { |
||
| 372 | int vlt,vrt,vlb,vrb; // vertex left top, vertex right top, vertex left bottom, vertex right bottom |
||
| 373 | int topy,boty,dy; |
||
| 374 | fix dx_dy_left,dx_dy_right; |
||
| 375 | fix du_dy_left,du_dy_right; |
||
| 376 | fix dv_dy_left,dv_dy_right; |
||
| 377 | fix dz_dy_left,dz_dy_right; |
||
| 378 | fix dl_dy_left,dl_dy_right; |
||
| 379 | fix recip_dyl, recip_dyr; |
||
| 380 | int max_y_vertex; |
||
| 381 | fix xleft,xright,uleft,vleft,uright,vright,zleft,zright,lleft,lright; |
||
| 382 | int next_break_left, next_break_right; |
||
| 383 | |||
| 384 | //remove stupid warnings in compile |
||
| 385 | dl_dy_left = F1_0; |
||
| 386 | dl_dy_right = F1_0; |
||
| 387 | lleft = F1_0; |
||
| 388 | lright = F1_0; |
||
| 389 | |||
| 390 | auto &v3d = t.verts; |
||
| 391 | |||
| 392 | // Determine top and bottom y coords. |
||
| 393 | compute_y_bounds(t,vlt,vlb,vrt,vrb,max_y_vertex); |
||
| 394 | |||
| 395 | // Set top and bottom (of entire texture map) y coordinates. |
||
| 396 | topy = f2i(v3d[vlt].y2d); |
||
| 397 | boty = f2i(v3d[max_y_vertex].y2d); |
||
| 398 | if (topy > Window_clip_bot) |
||
| 399 | return; |
||
| 400 | if (boty > Window_clip_bot) |
||
| 401 | boty = Window_clip_bot; |
||
| 402 | |||
| 403 | // Set amount to change x coordinate for each advance to next scanline. |
||
| 404 | dy = f2i(t.verts[vlb].y2d) - f2i(t.verts[vlt].y2d); |
||
| 405 | recip_dyl = fix_recip(dy); |
||
| 406 | |||
| 407 | dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dyl); |
||
| 408 | du_dy_left = compute_du_dy(t,vlt,vlb, recip_dyl); |
||
| 409 | dv_dy_left = compute_dv_dy(t,vlt,vlb, recip_dyl); |
||
| 410 | dz_dy_left = compute_dz_dy(t,vlt,vlb, recip_dyl); |
||
| 411 | |||
| 412 | dy = f2i(t.verts[vrb].y2d) - f2i(t.verts[vrt].y2d); |
||
| 413 | recip_dyr = fix_recip(dy); |
||
| 414 | |||
| 415 | du_dy_right = compute_du_dy(t,vrt,vrb, recip_dyr); |
||
| 416 | dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dyr); |
||
| 417 | dv_dy_right = compute_dv_dy(t,vrt,vrb, recip_dyr); |
||
| 418 | dz_dy_right = compute_dz_dy(t,vrt,vrb, recip_dyr); |
||
| 419 | |||
| 420 | if (Lighting_enabled) { |
||
| 421 | dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dyl); |
||
| 422 | dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dyr); |
||
| 423 | |||
| 424 | lleft = v3d[vlt].l; |
||
| 425 | lright = v3d[vrt].l; |
||
| 426 | } |
||
| 427 | |||
| 428 | // Set initial values for x, u, v |
||
| 429 | xleft = v3d[vlt].x2d; |
||
| 430 | xright = v3d[vrt].x2d; |
||
| 431 | |||
| 432 | zleft = v3d[vlt].z; |
||
| 433 | zright = v3d[vrt].z; |
||
| 434 | |||
| 435 | uleft = fixmul(v3d[vlt].u,zleft); |
||
| 436 | uright = fixmul(v3d[vrt].u,zright); |
||
| 437 | vleft = fixmul(v3d[vlt].v,zleft); |
||
| 438 | vright = fixmul(v3d[vrt].v,zright); |
||
| 439 | |||
| 440 | // scan all rows in texture map from top through first break. |
||
| 441 | next_break_left = f2i(v3d[vlb].y2d); |
||
| 442 | next_break_right = f2i(v3d[vrb].y2d); |
||
| 443 | |||
| 444 | for (int y = topy; y < boty; y++) { |
||
| 445 | |||
| 446 | // See if we have reached the end of the current left edge, and if so, set |
||
| 447 | // new values for dx_dy and x,u,v |
||
| 448 | if (y == next_break_left) { |
||
| 449 | fix recip_dy; |
||
| 450 | |||
| 451 | // Handle problem of double points. Search until y coord is different. Cannot get |
||
| 452 | // hung in an infinite loop because we know there is a vertex with a lower y coordinate |
||
| 453 | // because in the for loop, we don't scan all spanlines. |
||
| 454 | while (y == f2i(v3d[vlb].y2d)) { |
||
| 455 | vlt = vlb; |
||
| 456 | vlb = prevmod(vlb,t.nv); |
||
| 457 | } |
||
| 458 | next_break_left = f2i(v3d[vlb].y2d); |
||
| 459 | |||
| 460 | dy = f2i(t.verts[vlb].y2d) - f2i(t.verts[vlt].y2d); |
||
| 461 | recip_dy = fix_recip(dy); |
||
| 462 | |||
| 463 | dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy); |
||
| 464 | |||
| 465 | xleft = v3d[vlt].x2d; |
||
| 466 | zleft = v3d[vlt].z; |
||
| 467 | uleft = fixmul(v3d[vlt].u,zleft); |
||
| 468 | vleft = fixmul(v3d[vlt].v,zleft); |
||
| 469 | lleft = v3d[vlt].l; |
||
| 470 | |||
| 471 | du_dy_left = compute_du_dy(t,vlt,vlb, recip_dy); |
||
| 472 | dv_dy_left = compute_dv_dy(t,vlt,vlb, recip_dy); |
||
| 473 | dz_dy_left = compute_dz_dy(t,vlt,vlb, recip_dy); |
||
| 474 | |||
| 475 | if (Lighting_enabled) { |
||
| 476 | dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dy); |
||
| 477 | lleft = v3d[vlt].l; |
||
| 478 | } |
||
| 479 | } |
||
| 480 | |||
| 481 | // See if we have reached the end of the current left edge, and if so, set |
||
| 482 | // new values for dx_dy and x. Not necessary to set new values for u,v. |
||
| 483 | if (y == next_break_right) { |
||
| 484 | fix recip_dy; |
||
| 485 | |||
| 486 | while (y == f2i(v3d[vrb].y2d)) { |
||
| 487 | vrt = vrb; |
||
| 488 | vrb = succmod(vrb,t.nv); |
||
| 489 | } |
||
| 490 | |||
| 491 | next_break_right = f2i(v3d[vrb].y2d); |
||
| 492 | |||
| 493 | dy = f2i(t.verts[vrb].y2d) - f2i(t.verts[vrt].y2d); |
||
| 494 | recip_dy = fix_recip(dy); |
||
| 495 | |||
| 496 | dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy); |
||
| 497 | |||
| 498 | xright = v3d[vrt].x2d; |
||
| 499 | zright = v3d[vrt].z; |
||
| 500 | uright = fixmul(v3d[vrt].u,zright); |
||
| 501 | vright = fixmul(v3d[vrt].v,zright); |
||
| 502 | |||
| 503 | du_dy_right = compute_du_dy(t,vrt,vrb, recip_dy); |
||
| 504 | dv_dy_right = compute_dv_dy(t,vrt,vrb, recip_dy); |
||
| 505 | dz_dy_right = compute_dz_dy(t,vrt,vrb, recip_dy); |
||
| 506 | |||
| 507 | if (Lighting_enabled) { |
||
| 508 | dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dy); |
||
| 509 | lright = v3d[vrt].l; |
||
| 510 | } |
||
| 511 | } |
||
| 512 | |||
| 513 | if (Lighting_enabled) { |
||
| 514 | if (y >= Window_clip_top) |
||
| 515 | ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright); |
||
| 516 | lleft += dl_dy_left; |
||
| 517 | lright += dl_dy_right; |
||
| 518 | } else |
||
| 519 | if (y >= Window_clip_top) |
||
| 520 | ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright); |
||
| 521 | |||
| 522 | uleft += du_dy_left; |
||
| 523 | vleft += dv_dy_left; |
||
| 524 | |||
| 525 | uright += du_dy_right; |
||
| 526 | vright += dv_dy_right; |
||
| 527 | |||
| 528 | xleft += dx_dy_left; |
||
| 529 | xright += dx_dy_right; |
||
| 530 | |||
| 531 | zleft += dz_dy_left; |
||
| 532 | zright += dz_dy_right; |
||
| 533 | |||
| 534 | } |
||
| 535 | |||
| 536 | // We can get lleft or lright out of bounds here because we compute dl_dy using fixed point values, |
||
| 537 | // but we plot an integer number of scanlines, therefore doing an integer number of additions of the delta. |
||
| 538 | |||
| 539 | ntmap_scanline_lighted(srcb,boty,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright); |
||
| 540 | } |
||
| 541 | |||
| 542 | |||
| 543 | // ------------------------------------------------------------------------------------- |
||
| 544 | // Texture map current scanline using linear interpolation. |
||
| 545 | // ------------------------------------------------------------------------------------- |
||
| 546 | static void ntmap_scanline_lighted_linear(const grs_bitmap &srcb, int y, fix xleft, fix xright, fix uleft, fix uright, fix vleft, fix vright, fix lleft, fix lright) |
||
| 547 | { |
||
| 548 | fix dx,recip_dx,du_dx,dv_dx,dl_dx; |
||
| 549 | |||
| 550 | dx = f2i(xright) - f2i(xleft); |
||
| 551 | if ((dx < 0) || (xright < 0) || (xleft > xright)) // the (xleft > xright) term is not redundant with (dx < 0) because dx is computed using integers |
||
| 552 | return; |
||
| 553 | |||
| 554 | // setup to call assembler scanline renderer |
||
| 555 | recip_dx = fix_recip(dx); |
||
| 556 | |||
| 557 | du_dx = fixmul(uright - uleft,recip_dx); |
||
| 558 | dv_dx = fixmul(vright - vleft,recip_dx); |
||
| 559 | |||
| 560 | fx_u = uleft; |
||
| 561 | fx_v = vleft; |
||
| 562 | fx_du_dx = du_dx; |
||
| 563 | fx_dv_dx = dv_dx; |
||
| 564 | fx_y = y; |
||
| 565 | fx_xright = f2i(xright); |
||
| 566 | fx_xleft = f2i(xleft); |
||
| 567 | pixptr = srcb.bm_data; |
||
| 568 | |||
| 569 | switch (Lighting_enabled) { |
||
| 570 | case 0: |
||
| 571 | //added 07/11/99 adb - prevent writing before the buffer |
||
| 572 | if (fx_xleft < 0) |
||
| 573 | fx_xleft = 0; |
||
| 574 | //end addition -adb |
||
| 575 | |||
| 576 | cur_tmap_scanline_lin_nolight(); |
||
| 577 | break; |
||
| 578 | case 1: |
||
| 579 | if (lleft < F1_0/2) |
||
| 580 | lleft = F1_0/2; |
||
| 581 | if (lright < F1_0/2) |
||
| 582 | lright = F1_0/2; |
||
| 583 | |||
| 584 | if (lleft > MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS) |
||
| 585 | lleft = MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS; |
||
| 586 | if (lright > MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS) |
||
| 587 | lright = MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS; |
||
| 588 | |||
| 589 | //added 07/11/99 adb - prevent writing before the buffer |
||
| 590 | if (fx_xleft < 0) |
||
| 591 | fx_xleft = 0; |
||
| 592 | //end addition -adb |
||
| 593 | |||
| 594 | { |
||
| 595 | fix mul_thing; |
||
| 596 | |||
| 597 | fx_l = lleft; |
||
| 598 | fx_dl_dx = fixmul(lright - lleft,recip_dx); |
||
| 599 | |||
| 600 | // This is a pretty ugly hack to prevent lighting overflows. |
||
| 601 | mul_thing = dx * fx_dl_dx; |
||
| 602 | if (lleft + mul_thing < 0) |
||
| 603 | fx_dl_dx += 12; |
||
| 604 | else if (lleft + mul_thing > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) |
||
| 605 | fx_dl_dx -= 12; |
||
| 606 | } |
||
| 607 | |||
| 608 | fx_l = lleft; |
||
| 609 | dl_dx = fixmul(lright - lleft,recip_dx); |
||
| 610 | fx_dl_dx = dl_dx; |
||
| 611 | cur_tmap_scanline_lin(); |
||
| 612 | break; |
||
| 613 | case 2: |
||
| 614 | #ifdef EDITOR_TMAP |
||
| 615 | fx_xright = f2i(xright); |
||
| 616 | fx_xleft = f2i(xleft); |
||
| 617 | tmap_flat_color = 1; |
||
| 618 | cur_tmap_scanline_flat(); |
||
| 619 | #else |
||
| 620 | Int3(); // Illegal, called an editor only routine! |
||
| 621 | #endif |
||
| 622 | break; |
||
| 623 | } |
||
| 624 | } |
||
| 625 | |||
| 626 | // ------------------------------------------------------------------------------------- |
||
| 627 | // Render a texture map with lighting using perspective interpolation in inner and outer loops. |
||
| 628 | // ------------------------------------------------------------------------------------- |
||
| 629 | static void ntexture_map_lighted_linear(const grs_bitmap &srcb, const g3ds_tmap &t) |
||
| 630 | { |
||
| 631 | int vlt,vrt,vlb,vrb; // vertex left top, vertex right top, vertex left bottom, vertex right bottom |
||
| 632 | int topy,boty,dy; |
||
| 633 | fix dx_dy_left,dx_dy_right; |
||
| 634 | fix du_dy_left,du_dy_right; |
||
| 635 | fix dv_dy_left,dv_dy_right; |
||
| 636 | fix dl_dy_left,dl_dy_right; |
||
| 637 | int max_y_vertex; |
||
| 638 | fix xleft,xright,uleft,vleft,uright,vright,lleft,lright; |
||
| 639 | int next_break_left, next_break_right; |
||
| 640 | fix recip_dyl, recip_dyr; |
||
| 641 | |||
| 642 | //remove stupid warnings in compile |
||
| 643 | dl_dy_left = F1_0; |
||
| 644 | dl_dy_right = F1_0; |
||
| 645 | lleft = F1_0; |
||
| 646 | lright = F1_0; |
||
| 647 | |||
| 648 | auto &v3d = t.verts; |
||
| 649 | |||
| 650 | // Determine top and bottom y coords. |
||
| 651 | compute_y_bounds(t,vlt,vlb,vrt,vrb,max_y_vertex); |
||
| 652 | |||
| 653 | // Set top and bottom (of entire texture map) y coordinates. |
||
| 654 | topy = f2i(v3d[vlt].y2d); |
||
| 655 | boty = f2i(v3d[max_y_vertex].y2d); |
||
| 656 | |||
| 657 | if (topy > Window_clip_bot) |
||
| 658 | return; |
||
| 659 | if (boty > Window_clip_bot) |
||
| 660 | boty = Window_clip_bot; |
||
| 661 | |||
| 662 | dy = f2i(t.verts[vlb].y2d) - f2i(t.verts[vlt].y2d); |
||
| 663 | recip_dyl = fix_recip(dy); |
||
| 664 | |||
| 665 | dy = f2i(t.verts[vrb].y2d) - f2i(t.verts[vrt].y2d); |
||
| 666 | recip_dyr = fix_recip(dy); |
||
| 667 | |||
| 668 | // Set amount to change x coordinate for each advance to next scanline. |
||
| 669 | dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dyl); |
||
| 670 | dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dyr); |
||
| 671 | |||
| 672 | du_dy_left = compute_du_dy_lin(t,vlt,vlb, recip_dyl); |
||
| 673 | du_dy_right = compute_du_dy_lin(t,vrt,vrb, recip_dyr); |
||
| 674 | |||
| 675 | dv_dy_left = compute_dv_dy_lin(t,vlt,vlb, recip_dyl); |
||
| 676 | dv_dy_right = compute_dv_dy_lin(t,vrt,vrb, recip_dyr); |
||
| 677 | |||
| 678 | if (Lighting_enabled) { |
||
| 679 | dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dyl); |
||
| 680 | dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dyr); |
||
| 681 | |||
| 682 | lleft = v3d[vlt].l; |
||
| 683 | lright = v3d[vrt].l; |
||
| 684 | } |
||
| 685 | |||
| 686 | // Set initial values for x, u, v |
||
| 687 | xleft = v3d[vlt].x2d; |
||
| 688 | xright = v3d[vrt].x2d; |
||
| 689 | |||
| 690 | uleft = v3d[vlt].u; |
||
| 691 | uright = v3d[vrt].u; |
||
| 692 | vleft = v3d[vlt].v; |
||
| 693 | vright = v3d[vrt].v; |
||
| 694 | |||
| 695 | // scan all rows in texture map from top through first break. |
||
| 696 | next_break_left = f2i(v3d[vlb].y2d); |
||
| 697 | next_break_right = f2i(v3d[vrb].y2d); |
||
| 698 | |||
| 699 | for (int y = topy; y < boty; y++) { |
||
| 700 | |||
| 701 | // See if we have reached the end of the current left edge, and if so, set |
||
| 702 | // new values for dx_dy and x,u,v |
||
| 703 | if (y == next_break_left) { |
||
| 704 | fix recip_dy; |
||
| 705 | |||
| 706 | // Handle problem of double points. Search until y coord is different. Cannot get |
||
| 707 | // hung in an infinite loop because we know there is a vertex with a lower y coordinate |
||
| 708 | // because in the for loop, we don't scan all spanlines. |
||
| 709 | while (y == f2i(v3d[vlb].y2d)) { |
||
| 710 | vlt = vlb; |
||
| 711 | vlb = prevmod(vlb,t.nv); |
||
| 712 | } |
||
| 713 | next_break_left = f2i(v3d[vlb].y2d); |
||
| 714 | |||
| 715 | dy = f2i(t.verts[vlb].y2d) - f2i(t.verts[vlt].y2d); |
||
| 716 | recip_dy = fix_recip(dy); |
||
| 717 | |||
| 718 | dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy); |
||
| 719 | |||
| 720 | xleft = v3d[vlt].x2d; |
||
| 721 | uleft = v3d[vlt].u; |
||
| 722 | vleft = v3d[vlt].v; |
||
| 723 | lleft = v3d[vlt].l; |
||
| 724 | |||
| 725 | du_dy_left = compute_du_dy_lin(t,vlt,vlb, recip_dy); |
||
| 726 | dv_dy_left = compute_dv_dy_lin(t,vlt,vlb, recip_dy); |
||
| 727 | |||
| 728 | if (Lighting_enabled) { |
||
| 729 | dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dy); |
||
| 730 | lleft = v3d[vlt].l; |
||
| 731 | } |
||
| 732 | } |
||
| 733 | |||
| 734 | // See if we have reached the end of the current left edge, and if so, set |
||
| 735 | // new values for dx_dy and x. Not necessary to set new values for u,v. |
||
| 736 | if (y == next_break_right) { |
||
| 737 | fix recip_dy; |
||
| 738 | |||
| 739 | while (y == f2i(v3d[vrb].y2d)) { |
||
| 740 | vrt = vrb; |
||
| 741 | vrb = succmod(vrb,t.nv); |
||
| 742 | } |
||
| 743 | |||
| 744 | dy = f2i(t.verts[vrb].y2d) - f2i(t.verts[vrt].y2d); |
||
| 745 | recip_dy = fix_recip(dy); |
||
| 746 | |||
| 747 | next_break_right = f2i(v3d[vrb].y2d); |
||
| 748 | dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy); |
||
| 749 | |||
| 750 | xright = v3d[vrt].x2d; |
||
| 751 | uright = v3d[vrt].u; |
||
| 752 | vright = v3d[vrt].v; |
||
| 753 | |||
| 754 | du_dy_right = compute_du_dy_lin(t,vrt,vrb, recip_dy); |
||
| 755 | dv_dy_right = compute_dv_dy_lin(t,vrt,vrb, recip_dy); |
||
| 756 | |||
| 757 | if (Lighting_enabled) { |
||
| 758 | dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dy); |
||
| 759 | lright = v3d[vrt].l; |
||
| 760 | } |
||
| 761 | } |
||
| 762 | |||
| 763 | if (Lighting_enabled) { |
||
| 764 | ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright); |
||
| 765 | lleft += dl_dy_left; |
||
| 766 | lright += dl_dy_right; |
||
| 767 | } else |
||
| 768 | ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright); |
||
| 769 | |||
| 770 | uleft += du_dy_left; |
||
| 771 | vleft += dv_dy_left; |
||
| 772 | |||
| 773 | uright += du_dy_right; |
||
| 774 | vright += dv_dy_right; |
||
| 775 | |||
| 776 | xleft += dx_dy_left; |
||
| 777 | xright += dx_dy_right; |
||
| 778 | |||
| 779 | } |
||
| 780 | |||
| 781 | // We can get lleft or lright out of bounds here because we compute dl_dy using fixed point values, |
||
| 782 | // but we plot an integer number of scanlines, therefore doing an integer number of additions of the delta. |
||
| 783 | |||
| 784 | ntmap_scanline_lighted_linear(srcb,boty,xleft,xright,uleft,uright,vleft,vright,lleft,lright); |
||
| 785 | } |
||
| 786 | |||
| 787 | // fix DivNum = F1_0*12; |
||
| 788 | |||
| 789 | // ------------------------------------------------------------------------------------- |
||
| 790 | // Interface from Matt's data structures to Mike's texture mapper. |
||
| 791 | // ------------------------------------------------------------------------------------- |
||
| 792 | void draw_tmap(grs_canvas &canvas, const grs_bitmap &rbp, uint_fast32_t nverts, const g3s_point *const *vertbuf) |
||
| 793 | { |
||
| 794 | // These variables are used in system which renders texture maps which lie on one scanline as a line. |
||
| 795 | // fix div_numerator; |
||
| 796 | int lighting_on_save = Lighting_on; |
||
| 797 | |||
| 798 | Assert(nverts <= MAX_TMAP_VERTS); |
||
| 799 | |||
| 800 | const grs_bitmap *bp = &rbp; |
||
| 801 | // If no transparency and seg depth is large, render as flat shaded. |
||
| 802 | if ((Current_seg_depth > Max_linear_depth) && ((bp->get_flag_mask(3)) == 0)) { |
||
| 803 | draw_tmap_flat(canvas, rbp, nverts, vertbuf); |
||
| 804 | return; |
||
| 805 | } |
||
| 806 | |||
| 807 | bp = rle_expand_texture(*bp); // Expand if rle'd |
||
| 808 | |||
| 809 | Transparency_on = bp->get_flag_mask(BM_FLAG_TRANSPARENT); |
||
| 810 | if (bp->get_flag_mask(BM_FLAG_NO_LIGHTING)) |
||
| 811 | Lighting_on = 0; |
||
| 812 | |||
| 813 | |||
| 814 | // Setup texture map in Tmap1 |
||
| 815 | g3ds_tmap Tmap1; |
||
| 816 | Tmap1.nv = nverts; // Initialize number of vertices |
||
| 817 | |||
| 818 | // div_numerator = DivNum; //f1_0*3; |
||
| 819 | |||
| 820 | for (int i=0; i<nverts; i++) { |
||
| 821 | g3ds_vertex *tvp = &Tmap1.verts[i]; |
||
| 822 | auto vp = vertbuf[i]; |
||
| 823 | |||
| 824 | tvp->x2d = vp->p3_sx; |
||
| 825 | tvp->y2d = vp->p3_sy; |
||
| 826 | |||
| 827 | // Check for overflow on fixdiv. Will overflow on vp->z <= something small. Allow only as low as 256. |
||
| 828 | auto clipped_p3_z = std::max(256, vp->p3_z); |
||
| 829 | tvp->z = fixdiv(F1_0*12, clipped_p3_z); |
||
| 830 | tvp->u = vp->p3_u << 6; //* bp->bm_w; |
||
| 831 | tvp->v = vp->p3_v << 6; //* bp->bm_h; |
||
| 832 | |||
| 833 | Assert(Lighting_on < 3); |
||
| 834 | |||
| 835 | if (Lighting_on) |
||
| 836 | tvp->l = vp->p3_l * NUM_LIGHTING_LEVELS; |
||
| 837 | } |
||
| 838 | |||
| 839 | |||
| 840 | Lighting_enabled = Lighting_on; |
||
| 841 | |||
| 842 | // Now, call my texture mapper. |
||
| 843 | switch (Interpolation_method) { // 0 = choose, 1 = linear, 2 = /8 perspective, 3 = full perspective |
||
| 844 | case 0: // choose best interpolation |
||
| 845 | if (Current_seg_depth > Max_perspective_depth) |
||
| 846 | { |
||
| 847 | case 1: // linear interpolation |
||
| 848 | ntexture_map_lighted_linear(*bp, Tmap1); |
||
| 849 | } |
||
| 850 | else |
||
| 851 | { |
||
| 852 | DXX_BOOST_FALLTHROUGH; |
||
| 853 | case 2: // perspective every 8th pixel interpolation |
||
| 854 | case 3: // perspective every pixel interpolation |
||
| 855 | ntexture_map_lighted(*bp, Tmap1); |
||
| 856 | } |
||
| 857 | break; |
||
| 858 | default: |
||
| 859 | Assert(0); // Illegal value for Interpolation_method, must be 0,1,2,3 |
||
| 860 | } |
||
| 861 | |||
| 862 | Lighting_on = lighting_on_save; |
||
| 863 | |||
| 864 | } |
||
| 865 | |||
| 866 | } |