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-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. |
||
| 18 | */ |
||
| 19 | |||
| 20 | /* |
||
| 21 | * |
||
| 22 | * Code to render cool external-scene terrain |
||
| 23 | * |
||
| 24 | */ |
||
| 25 | |||
| 26 | #include <bitset> |
||
| 27 | #include <stdio.h> |
||
| 28 | #include <stdlib.h> |
||
| 29 | #include <string.h> |
||
| 30 | |||
| 31 | #include "3d.h" |
||
| 32 | #include "dxxerror.h" |
||
| 33 | #include "gr.h" |
||
| 34 | #include "texmap.h" |
||
| 35 | #include "iff.h" |
||
| 36 | #include "u_mem.h" |
||
| 37 | #include "inferno.h" |
||
| 38 | #include "textures.h" |
||
| 39 | #include "object.h" |
||
| 40 | #include "endlevel.h" |
||
| 41 | #include "fireball.h" |
||
| 42 | #include "render.h" |
||
| 43 | #include "player.h" |
||
| 44 | #include "segment.h" |
||
| 45 | #include "terrain.h" |
||
| 46 | #include <memory> |
||
| 47 | |||
| 48 | #define GRID_MAX_SIZE 64 |
||
| 49 | #define GRID_SCALE i2f(2*20) |
||
| 50 | #define HEIGHT_SCALE f1_0 |
||
| 51 | |||
| 52 | static int grid_w,grid_h; |
||
| 53 | |||
| 54 | static RAIIdmem<ubyte[]> height_array; |
||
| 55 | static std::unique_ptr<uint8_t[]> light_array; |
||
| 56 | |||
| 57 | #define HEIGHT(_i,_j) (height_array[(_i)*grid_w+(_j)]) |
||
| 58 | #define LIGHT(_i,_j) light_array[(_i)*grid_w+(_j)] |
||
| 59 | |||
| 60 | //!!#define HEIGHT(_i,_j) height_array[(grid_h-1-j)*grid_w+(_i)] |
||
| 61 | //!!#define LIGHT(_i,_j) light_array[(grid_h-1-j)*grid_w+(_i)] |
||
| 62 | |||
| 63 | #define LIGHTVAL(_i,_j) (static_cast<fix>(LIGHT(_i, _j)) << 8) |
||
| 64 | |||
| 65 | static grs_bitmap *terrain_bm; |
||
| 66 | static int terrain_outline=0; |
||
| 67 | static int org_i,org_j; |
||
| 68 | |||
| 69 | // LINT: adding function prototypes |
||
| 70 | static void build_light_table(void); |
||
| 71 | |||
| 72 | // ------------------------------------------------------------------------ |
||
| 73 | static void draw_cell(grs_canvas &canvas, const vms_vector &Viewer_eye, const int i, const int j, cg3s_point &p0, cg3s_point &p1, cg3s_point &p2, cg3s_point &p3, int &mine_tiles_drawn) |
||
| 74 | { |
||
| 75 | std::array<cg3s_point *, 3> pointlist; |
||
| 76 | |||
| 77 | pointlist[0] = &p0; |
||
| 78 | pointlist[1] = &p1; |
||
| 79 | pointlist[2] = &p3; |
||
| 80 | std::array<g3s_lrgb, 3> lrgb_list1; |
||
| 81 | std::array<g3s_uvl, 3> uvl_list1; |
||
| 82 | lrgb_list1[0].r = lrgb_list1[0].g = lrgb_list1[0].b = uvl_list1[0].l = LIGHTVAL(i,j); |
||
| 83 | lrgb_list1[1].r = lrgb_list1[1].g = lrgb_list1[1].b = uvl_list1[1].l = LIGHTVAL(i,j+1); |
||
| 84 | lrgb_list1[2].r = lrgb_list1[2].g = lrgb_list1[2].b = uvl_list1[2].l = LIGHTVAL(i+1,j); |
||
| 85 | |||
| 86 | uvl_list1[0].u = (i)*f1_0/4; uvl_list1[0].v = (j)*f1_0/4; |
||
| 87 | uvl_list1[1].u = (i)*f1_0/4; uvl_list1[1].v = (j+1)*f1_0/4; |
||
| 88 | uvl_list1[2].u = (i+1)*f1_0/4; uvl_list1[2].v = (j)*f1_0/4; |
||
| 89 | |||
| 90 | g3_check_and_draw_tmap(canvas, pointlist, uvl_list1, lrgb_list1, *terrain_bm); |
||
| 91 | if (terrain_outline) { |
||
| 92 | #if !DXX_USE_OGL |
||
| 93 | const int lsave = Lighting_on; |
||
| 94 | Lighting_on=0; |
||
| 95 | #endif |
||
| 96 | const uint8_t color = BM_XRGB(31, 0, 0); |
||
| 97 | g3_draw_line(canvas, *pointlist[0],*pointlist[1], color); |
||
| 98 | g3_draw_line(canvas, *pointlist[2],*pointlist[0], color); |
||
| 99 | #if !DXX_USE_OGL |
||
| 100 | Lighting_on=lsave; |
||
| 101 | #endif |
||
| 102 | } |
||
| 103 | |||
| 104 | pointlist[0] = &p1; |
||
| 105 | pointlist[1] = &p2; |
||
| 106 | std::array<g3s_uvl, 3> uvl_list2; |
||
| 107 | std::array<g3s_lrgb, 3> lrgb_list2; |
||
| 108 | lrgb_list2[0].r = lrgb_list2[0].g = lrgb_list2[0].b = uvl_list2[0].l = LIGHTVAL(i,j+1); |
||
| 109 | lrgb_list2[1].r = lrgb_list2[1].g = lrgb_list2[1].b = uvl_list2[1].l = LIGHTVAL(i+1,j+1); |
||
| 110 | lrgb_list2[2].r = lrgb_list2[2].g = lrgb_list2[2].b = uvl_list2[2].l = LIGHTVAL(i+1,j); |
||
| 111 | |||
| 112 | uvl_list2[0].u = (i)*f1_0/4; uvl_list2[0].v = (j+1)*f1_0/4; |
||
| 113 | uvl_list2[1].u = (i+1)*f1_0/4; uvl_list2[1].v = (j+1)*f1_0/4; |
||
| 114 | uvl_list2[2].u = (i+1)*f1_0/4; uvl_list2[2].v = (j)*f1_0/4; |
||
| 115 | |||
| 116 | g3_check_and_draw_tmap(canvas, pointlist, uvl_list2, lrgb_list2, *terrain_bm); |
||
| 117 | if (terrain_outline) { |
||
| 118 | #if !DXX_USE_OGL |
||
| 119 | const int lsave = Lighting_on; |
||
| 120 | Lighting_on=0; |
||
| 121 | #endif |
||
| 122 | const uint8_t color = BM_XRGB(31, 0, 0); |
||
| 123 | g3_draw_line(canvas, *pointlist[0],*pointlist[1], color); |
||
| 124 | g3_draw_line(canvas, *pointlist[1],*pointlist[2], color); |
||
| 125 | g3_draw_line(canvas, *pointlist[2],*pointlist[0], color); |
||
| 126 | #if !DXX_USE_OGL |
||
| 127 | Lighting_on=lsave; |
||
| 128 | #endif |
||
| 129 | } |
||
| 130 | |||
| 131 | if (i==org_i && j==org_j) |
||
| 132 | mine_tiles_drawn |= 1; |
||
| 133 | if (i==org_i-1 && j==org_j) |
||
| 134 | mine_tiles_drawn |= 2; |
||
| 135 | if (i==org_i && j==org_j-1) |
||
| 136 | mine_tiles_drawn |= 4; |
||
| 137 | if (i==org_i-1 && j==org_j-1) |
||
| 138 | mine_tiles_drawn |= 8; |
||
| 139 | |||
| 140 | if (mine_tiles_drawn == 0xf) { |
||
| 141 | //draw_exit_model(); |
||
| 142 | mine_tiles_drawn=-1; |
||
| 143 | window_rendered_data window; |
||
| 144 | render_mine(canvas, Viewer_eye, PlayerUniqueEndlevelState.exit_segnum, 0, window); |
||
| 145 | //if (ext_expl_playing) |
||
| 146 | // draw_fireball(&external_explosion); |
||
| 147 | } |
||
| 148 | |||
| 149 | } |
||
| 150 | |||
| 151 | namespace { |
||
| 152 | |||
| 153 | class terrain_y_cache |
||
| 154 | { |
||
| 155 | static const std::size_t cache_size = 256; |
||
| 156 | std::bitset<cache_size> yc_flags; |
||
| 157 | std::array<vms_vector, cache_size> y_cache; |
||
| 158 | public: |
||
| 159 | vms_vector &operator()(uint_fast32_t h); |
||
| 160 | }; |
||
| 161 | |||
| 162 | } |
||
| 163 | |||
| 164 | vms_vector &terrain_y_cache::operator()(uint_fast32_t h) |
||
| 165 | { |
||
| 166 | auto &dyp = y_cache[h]; |
||
| 167 | if (auto &&ycf = yc_flags[h]) |
||
| 168 | { |
||
| 169 | } |
||
| 170 | else |
||
| 171 | { |
||
| 172 | ycf = 1; |
||
| 173 | const auto tv = vm_vec_copy_scale(surface_orient.uvec,h*HEIGHT_SCALE); |
||
| 174 | g3_rotate_delta_vec(dyp,tv); |
||
| 175 | } |
||
| 176 | return dyp; |
||
| 177 | } |
||
| 178 | |||
| 179 | void render_terrain(grs_canvas &canvas, const vms_vector &Viewer_eye, const vms_vector &org_point,int org_2dx,int org_2dy) |
||
| 180 | { |
||
| 181 | vms_vector delta_i,delta_j; //delta_y; |
||
| 182 | g3s_point p,save_p_low,save_p_high; |
||
| 183 | g3s_point last_p2; |
||
| 184 | int i,j; |
||
| 185 | int low_i,high_i,low_j,high_j; |
||
| 186 | int viewer_i,viewer_j; |
||
| 187 | org_i = org_2dy; |
||
| 188 | org_j = org_2dx; |
||
| 189 | |||
| 190 | low_i = 0; high_i = grid_w-1; |
||
| 191 | low_j = 0; high_j = grid_h-1; |
||
| 192 | |||
| 193 | //@@start_point.x = org_point->x - GRID_SCALE*(org_i - low_i); |
||
| 194 | //@@start_point.z = org_point->z - GRID_SCALE*(org_j - low_j); |
||
| 195 | //@@start_point.y = org_point->y; |
||
| 196 | terrain_y_cache get_dy_vec; |
||
| 197 | |||
| 198 | #if !DXX_USE_OGL |
||
| 199 | Interpolation_method = 1; |
||
| 200 | #endif |
||
| 201 | |||
| 202 | { |
||
| 203 | const auto tv = vm_vec_copy_scale(surface_orient.rvec,GRID_SCALE); |
||
| 204 | g3_rotate_delta_vec(delta_i,tv); |
||
| 205 | } |
||
| 206 | { |
||
| 207 | const auto tv = vm_vec_copy_scale(surface_orient.fvec,GRID_SCALE); |
||
| 208 | g3_rotate_delta_vec(delta_j,tv); |
||
| 209 | } |
||
| 210 | |||
| 211 | auto start_point = vm_vec_scale_add(org_point,surface_orient.rvec,-(org_i - low_i)*GRID_SCALE); |
||
| 212 | vm_vec_scale_add2(start_point,surface_orient.fvec,-(org_j - low_j)*GRID_SCALE); |
||
| 213 | |||
| 214 | { |
||
| 215 | const auto tv = vm_vec_sub(Viewer->pos,start_point); |
||
| 216 | viewer_i = vm_vec_dot(tv,surface_orient.rvec) / GRID_SCALE; |
||
| 217 | viewer_j = vm_vec_dot(tv,surface_orient.fvec) / GRID_SCALE; |
||
| 218 | } |
||
| 219 | |||
| 220 | auto last_p = g3_rotate_point(start_point); |
||
| 221 | save_p_low = last_p; |
||
| 222 | |||
| 223 | g3s_point save_row[GRID_MAX_SIZE]{}; |
||
| 224 | // Is this needed? |
||
| 225 | for (j=low_j;j<=high_j;j++) { |
||
| 226 | g3_add_delta_vec(save_row[j],last_p,get_dy_vec(HEIGHT(low_i,j))); |
||
| 227 | if (j==high_j) |
||
| 228 | save_p_high = last_p; |
||
| 229 | else |
||
| 230 | g3_add_delta_vec(last_p,last_p,delta_j); |
||
| 231 | } |
||
| 232 | |||
| 233 | int mine_tiles_drawn = 0; //flags to tell if all 4 tiles under mine have drawn |
||
| 234 | for (i=low_i;i<viewer_i;i++) { |
||
| 235 | |||
| 236 | g3_add_delta_vec(save_p_low,save_p_low,delta_i); |
||
| 237 | last_p = save_p_low; |
||
| 238 | g3_add_delta_vec(last_p2,last_p,get_dy_vec(HEIGHT(i+1,low_j))); |
||
| 239 | |||
| 240 | for (j=low_j;j<viewer_j;j++) { |
||
| 241 | g3s_point p2; |
||
| 242 | |||
| 243 | g3_add_delta_vec(p,last_p,delta_j); |
||
| 244 | g3_add_delta_vec(p2,p,get_dy_vec(HEIGHT(i+1,j+1))); |
||
| 245 | |||
| 246 | draw_cell(canvas, Viewer_eye, i, j, save_row[j], save_row[j+1], p2, last_p2, mine_tiles_drawn); |
||
| 247 | |||
| 248 | last_p = p; |
||
| 249 | save_row[j] = last_p2; |
||
| 250 | last_p2 = p2; |
||
| 251 | |||
| 252 | } |
||
| 253 | |||
| 254 | vm_vec_negate(delta_j); //don't have a delta sub... |
||
| 255 | |||
| 256 | g3_add_delta_vec(save_p_high,save_p_high,delta_i); |
||
| 257 | last_p = save_p_high; |
||
| 258 | g3_add_delta_vec(last_p2,last_p,get_dy_vec(HEIGHT(i+1,high_j))); |
||
| 259 | |||
| 260 | for (j=high_j-1;j>=viewer_j;j--) { |
||
| 261 | g3s_point p2; |
||
| 262 | |||
| 263 | g3_add_delta_vec(p,last_p,delta_j); |
||
| 264 | g3_add_delta_vec(p2,p,get_dy_vec(HEIGHT(i+1,j))); |
||
| 265 | |||
| 266 | draw_cell(canvas, Viewer_eye, i, j, save_row[j], save_row[j+1], last_p2, p2, mine_tiles_drawn); |
||
| 267 | |||
| 268 | last_p = p; |
||
| 269 | save_row[j+1] = last_p2; |
||
| 270 | last_p2 = p2; |
||
| 271 | |||
| 272 | } |
||
| 273 | |||
| 274 | save_row[j+1] = last_p2; |
||
| 275 | |||
| 276 | vm_vec_negate(delta_j); //restore sign of j |
||
| 277 | |||
| 278 | } |
||
| 279 | |||
| 280 | //now do i from other end |
||
| 281 | |||
| 282 | vm_vec_negate(delta_i); //going the other way now... |
||
| 283 | |||
| 284 | //@@start_point.x += (high_i-low_i)*GRID_SCALE; |
||
| 285 | vm_vec_scale_add2(start_point,surface_orient.rvec,(high_i-low_i)*GRID_SCALE); |
||
| 286 | g3_rotate_point(last_p,start_point); |
||
| 287 | save_p_low = last_p; |
||
| 288 | |||
| 289 | for (j=low_j;j<=high_j;j++) { |
||
| 290 | g3_add_delta_vec(save_row[j],last_p,get_dy_vec(HEIGHT(high_i,j))); |
||
| 291 | if (j==high_j) |
||
| 292 | save_p_high = last_p; |
||
| 293 | else |
||
| 294 | g3_add_delta_vec(last_p,last_p,delta_j); |
||
| 295 | } |
||
| 296 | |||
| 297 | for (i=high_i-1;i>=viewer_i;i--) { |
||
| 298 | |||
| 299 | g3_add_delta_vec(save_p_low,save_p_low,delta_i); |
||
| 300 | last_p = save_p_low; |
||
| 301 | g3_add_delta_vec(last_p2,last_p,get_dy_vec(HEIGHT(i,low_j))); |
||
| 302 | |||
| 303 | for (j=low_j;j<viewer_j;j++) { |
||
| 304 | g3s_point p2; |
||
| 305 | |||
| 306 | g3_add_delta_vec(p,last_p,delta_j); |
||
| 307 | g3_add_delta_vec(p2,p,get_dy_vec(HEIGHT(i,j+1))); |
||
| 308 | |||
| 309 | draw_cell(canvas, Viewer_eye, i, j, last_p2, p2, save_row[j+1], save_row[j], mine_tiles_drawn); |
||
| 310 | |||
| 311 | last_p = p; |
||
| 312 | save_row[j] = last_p2; |
||
| 313 | last_p2 = p2; |
||
| 314 | |||
| 315 | } |
||
| 316 | |||
| 317 | vm_vec_negate(delta_j); //don't have a delta sub... |
||
| 318 | |||
| 319 | g3_add_delta_vec(save_p_high,save_p_high,delta_i); |
||
| 320 | last_p = save_p_high; |
||
| 321 | g3_add_delta_vec(last_p2,last_p,get_dy_vec(HEIGHT(i,high_j))); |
||
| 322 | |||
| 323 | for (j=high_j-1;j>=viewer_j;j--) { |
||
| 324 | g3s_point p2; |
||
| 325 | |||
| 326 | g3_add_delta_vec(p,last_p,delta_j); |
||
| 327 | g3_add_delta_vec(p2,p,get_dy_vec(HEIGHT(i,j))); |
||
| 328 | |||
| 329 | draw_cell(canvas, Viewer_eye, i, j, p2, last_p2, save_row[j+1], save_row[j], mine_tiles_drawn); |
||
| 330 | |||
| 331 | last_p = p; |
||
| 332 | save_row[j+1] = last_p2; |
||
| 333 | last_p2 = p2; |
||
| 334 | |||
| 335 | } |
||
| 336 | |||
| 337 | save_row[j+1] = last_p2; |
||
| 338 | |||
| 339 | vm_vec_negate(delta_j); //restore sign of j |
||
| 340 | |||
| 341 | } |
||
| 342 | |||
| 343 | } |
||
| 344 | |||
| 345 | void free_height_array() |
||
| 346 | { |
||
| 347 | height_array.reset(); |
||
| 348 | } |
||
| 349 | |||
| 350 | void load_terrain(const char *filename) |
||
| 351 | { |
||
| 352 | grs_bitmap height_bitmap; |
||
| 353 | int iff_error; |
||
| 354 | int i,j; |
||
| 355 | ubyte h,min_h,max_h; |
||
| 356 | |||
| 357 | iff_error = iff_read_bitmap(filename, height_bitmap, NULL); |
||
| 358 | if (iff_error != IFF_NO_ERROR) { |
||
| 359 | Error("File %s - IFF error: %s",filename,iff_errormsg(iff_error)); |
||
| 360 | } |
||
| 361 | grid_w = height_bitmap.bm_w; |
||
| 362 | grid_h = height_bitmap.bm_h; |
||
| 363 | |||
| 364 | Assert(grid_w <= GRID_MAX_SIZE); |
||
| 365 | Assert(grid_h <= GRID_MAX_SIZE); |
||
| 366 | |||
| 367 | height_array.reset(height_bitmap.get_bitmap_data()); |
||
| 368 | |||
| 369 | max_h=0; min_h=255; |
||
| 370 | for (i=0;i<grid_w;i++) |
||
| 371 | for (j=0;j<grid_h;j++) { |
||
| 372 | |||
| 373 | h = HEIGHT(i,j); |
||
| 374 | |||
| 375 | if (h > max_h) |
||
| 376 | max_h = h; |
||
| 377 | |||
| 378 | if (h < min_h) |
||
| 379 | min_h = h; |
||
| 380 | } |
||
| 381 | |||
| 382 | for (i=0;i<grid_w;i++) |
||
| 383 | for (j=0;j<grid_h;j++) |
||
| 384 | HEIGHT(i,j) -= min_h; |
||
| 385 | |||
| 386 | |||
| 387 | // d_free(height_bitmap.bm_data); |
||
| 388 | |||
| 389 | terrain_bm = terrain_bitmap; |
||
| 390 | |||
| 391 | build_light_table(); |
||
| 392 | } |
||
| 393 | |||
| 394 | |||
| 395 | static void get_pnt(vms_vector &p,int i,int j) |
||
| 396 | { |
||
| 397 | // added on 02/20/99 by adb to prevent overflow |
||
| 398 | if (i >= grid_h) i = grid_h - 1; |
||
| 399 | if (i == grid_h - 1 && j >= grid_w) j = grid_w - 1; |
||
| 400 | // end additions by adb |
||
| 401 | p.x = GRID_SCALE*i; |
||
| 402 | p.z = GRID_SCALE*j; |
||
| 403 | p.y = HEIGHT(i,j)*HEIGHT_SCALE; |
||
| 404 | } |
||
| 405 | |||
| 406 | constexpr vms_vector light{0x2e14,0xe8f5,0x5eb8}; |
||
| 407 | |||
| 408 | static fix get_face_light(const vms_vector &p0,const vms_vector &p1,const vms_vector &p2) |
||
| 409 | { |
||
| 410 | const auto norm = vm_vec_normal(p0,p1,p2); |
||
| 411 | return -vm_vec_dot(norm,light); |
||
| 412 | } |
||
| 413 | |||
| 414 | static fix get_avg_light(int i,int j) |
||
| 415 | { |
||
| 416 | vms_vector pp,p[6]; |
||
| 417 | fix sum; |
||
| 418 | int f; |
||
| 419 | |||
| 420 | get_pnt(pp,i,j); |
||
| 421 | get_pnt(p[0],i-1,j); |
||
| 422 | get_pnt(p[1],i,j-1); |
||
| 423 | get_pnt(p[2],i+1,j-1); |
||
| 424 | get_pnt(p[3],i+1,j); |
||
| 425 | get_pnt(p[4],i,j+1); |
||
| 426 | get_pnt(p[5],i-1,j+1); |
||
| 427 | |||
| 428 | for (f=0,sum=0;f<6;f++) |
||
| 429 | sum += get_face_light(pp,p[f],p[(f+1)%5]); |
||
| 430 | |||
| 431 | return sum/6; |
||
| 432 | } |
||
| 433 | |||
| 434 | void free_light_table() |
||
| 435 | { |
||
| 436 | light_array.reset(); |
||
| 437 | } |
||
| 438 | |||
| 439 | static void build_light_table() |
||
| 440 | { |
||
| 441 | std::size_t alloc = grid_w*grid_h; |
||
| 442 | light_array = std::make_unique<uint8_t[]>(alloc); |
||
| 443 | memset(light_array.get(), 0, alloc); |
||
| 444 | int i,j; |
||
| 445 | fix l, l2, min_l = INT32_MAX, max_l = 0; |
||
| 446 | for (i=1;i<grid_w;i++) |
||
| 447 | for (j=1;j<grid_h;j++) { |
||
| 448 | l = get_avg_light(i,j); |
||
| 449 | |||
| 450 | if (l > max_l) |
||
| 451 | max_l = l; |
||
| 452 | |||
| 453 | if (l < min_l) |
||
| 454 | min_l = l; |
||
| 455 | } |
||
| 456 | |||
| 457 | for (i=1;i<grid_w;i++) |
||
| 458 | for (j=1;j<grid_h;j++) { |
||
| 459 | |||
| 460 | l = get_avg_light(i,j); |
||
| 461 | |||
| 462 | if (min_l == max_l) { |
||
| 463 | LIGHT(i,j) = l>>8; |
||
| 464 | continue; |
||
| 465 | } |
||
| 466 | |||
| 467 | l2 = fixdiv((l-min_l),(max_l-min_l)); |
||
| 468 | |||
| 469 | if (l2==f1_0) |
||
| 470 | l2--; |
||
| 471 | |||
| 472 | LIGHT(i,j) = l2>>8; |
||
| 473 | |||
| 474 | } |
||
| 475 | } |