00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifdef HAVE_CONFIG_H
00023 # include <config.h>
00024 #endif
00025
00026 #include <cstdio>
00027
00028 #ifndef HAVE_SNPRINTF
00029 extern int snprintf(char *, size_t, const char *, ...);
00030 namespace std {
00031 using ::snprintf;
00032 }
00033 #else
00034 #endif
00035
00036 #include "gamewin.h"
00037 #include "gamerend.h"
00038 #include "gameclk.h"
00039 #include "gamemap.h"
00040 #include "actors.h"
00041 #include "chunks.h"
00042 #include "objiter.h"
00043 #include "Gump_manager.h"
00044 #include "Gump.h"
00045 #include "effects.h"
00046 #include "cheat.h"
00047 #include "drag.h"
00048
00049
00050
00051
00052
00053 void Game_window::paint_map_at_tile
00054 (
00055 int x, int y, int w, int h,
00056 int toptx, int topty,
00057 int skip_above
00058 )
00059 {
00060 int savescrolltx = scrolltx, savescrollty = scrollty;
00061 int saveskip = skip_lift;
00062 scrolltx = toptx;
00063 scrollty = topty;
00064 skip_lift = skip_above;
00065 map->read_map_data();
00066 win->set_clip(x, y, w, h);
00067 render->paint_map(0, 0, get_width(), get_height());
00068 win->clear_clip();
00069 scrolltx = savescrolltx;
00070 scrollty = savescrollty;
00071 skip_lift = saveskip;
00072 }
00073
00074
00075
00076
00077
00078 inline int Figure_screen_offset
00079 (
00080 int ch,
00081 int scroll
00082 )
00083 {
00084
00085 int t = ch*c_tiles_per_chunk - scroll;
00086 if (t < -c_num_tiles/2)
00087 t += c_num_tiles;
00088 t %= c_num_tiles;
00089 return t*c_tilesize;
00090 }
00091
00092
00093
00094
00095
00096 inline void Paint_chunk_outline
00097 (
00098 Game_window *gwin,
00099 int pixel,
00100 int cx, int cy,
00101 int tnum,
00102 int xoff, int yoff
00103 )
00104 {
00105 gwin->get_win()->fill8(pixel, c_chunksize, 1, xoff, yoff);
00106 gwin->get_win()->fill8(pixel, 1, c_chunksize, xoff, yoff);
00107 char text[40];
00108 snprintf(text, sizeof(text), "(%d,%d)T%d", cx, cy, tnum);
00109 Shape_manager::get_instance()->paint_text(2, text, xoff + 2, yoff + 2);
00110 }
00111
00112
00113
00114
00115
00116 static void Paint_grid
00117 (
00118 Game_window *gwin,
00119 Xform_palette& xform
00120 )
00121 {
00122 Image_window8 *win = gwin->get_win();
00123
00124 int xtiles = gwin->get_width()/c_tilesize,
00125 ytiles = gwin->get_height()/c_tilesize;
00126 int lift = cheat.get_edit_lift();
00127 int liftpixels = lift*(c_tilesize/2) + 1;
00128 for (int y = 0; y < ytiles; y++)
00129 win->fill_translucent8(0, xtiles*c_tilesize, 1,
00130 -liftpixels, y*c_tilesize - liftpixels, xform);
00131 for (int x = 0; x < xtiles; x++)
00132 win->fill_translucent8(0, 1, ytiles*c_tilesize,
00133 x*c_tilesize - liftpixels, -liftpixels, xform);
00134 }
00135
00136
00137
00138
00139
00140
00141 void Game_render::paint_terrain_only
00142 (
00143 int start_chunkx, int start_chunky,
00144 int stop_chunkx, int stop_chunky
00145 )
00146 {
00147 Game_window *gwin = Game_window::get_instance();
00148 Game_map *map = gwin->map;
00149 Shape_manager *sman = Shape_manager::get_instance();
00150 int cx, cy;
00151
00152 for (cy = start_chunky; cy != stop_chunky; cy = INCR_CHUNK(cy))
00153 {
00154 int yoff = Figure_screen_offset(cy, gwin->scrollty);
00155 for (cx = start_chunkx; cx != stop_chunkx; cx = INCR_CHUNK(cx))
00156 {
00157 int xoff = Figure_screen_offset(cx, gwin->scrolltx);
00158 Map_chunk *chunk = map->get_chunk(cx, cy);
00159 chunk->get_terrain()->render_all(cx, cy);
00160 if (cheat.in_map_editor())
00161 Paint_chunk_outline(gwin,
00162 sman->get_special_pixel(HIT_PIXEL), cx, cy,
00163 map->get_terrain_num(cx, cy), xoff, yoff);
00164 }
00165 }
00166
00167 if (cheat.show_tile_grid())
00168 Paint_grid(gwin, sman->get_xform(10));
00169 }
00170
00171
00172
00173
00174
00175
00176
00177
00178 int Game_render::paint_map
00179 (
00180 int x, int y, int w, int h
00181 )
00182 {
00183 Game_window *gwin = Game_window::get_instance();
00184 Game_map *map = gwin->map;
00185 Shape_manager *sman = gwin->shape_man;
00186 render_seq++;
00187 gwin->painted = 1;
00188 int scrolltx = gwin->scrolltx, scrollty = gwin->scrollty;
00189 int light_sources = 0;
00190
00191
00192 int start_chunkx = (scrolltx + x/c_tilesize - 1)/c_tiles_per_chunk;
00193
00194 start_chunkx = (start_chunkx + c_num_chunks)%c_num_chunks;
00195 int start_chunky = (scrollty + y/c_tilesize - 1)/c_tiles_per_chunk;
00196 start_chunky = (start_chunky + c_num_chunks)%c_num_chunks;
00197
00198 int stop_chunkx = 1 + (scrolltx + (x + w + c_tilesize - 2)/c_tilesize +
00199 c_tiles_per_chunk/2)/c_tiles_per_chunk;
00200 int stop_chunky = 1 + (scrollty + (y + h + c_tilesize - 2)/c_tilesize +
00201 c_tiles_per_chunk/2)/c_tiles_per_chunk;
00202
00203 stop_chunkx = (stop_chunkx + c_num_chunks)%c_num_chunks;
00204 stop_chunky = (stop_chunky + c_num_chunks)%c_num_chunks;
00205 if (!gwin->skip_lift)
00206 {
00207 paint_terrain_only(start_chunkx, start_chunky,
00208 stop_chunkx, stop_chunky);
00209 return 10;
00210 }
00211 int cx, cy;
00212
00213 for (cy = start_chunky; cy != stop_chunky; cy = INCR_CHUNK(cy))
00214 {
00215 int yoff = Figure_screen_offset(cy, scrollty);
00216 for (cx = start_chunkx; cx != stop_chunkx; cx = INCR_CHUNK(cx))
00217 {
00218 int xoff = Figure_screen_offset(cx, scrolltx);
00219 paint_chunk_flats(cx, cy, xoff, yoff);
00220
00221 if (cheat.in_map_editor())
00222 Paint_chunk_outline(gwin,
00223 sman->get_special_pixel(HIT_PIXEL), cx, cy,
00224 map->get_terrain_num(cx, cy), xoff, yoff);
00225 }
00226 }
00227
00228 for (cy = start_chunky; cy != stop_chunky; cy = INCR_CHUNK(cy))
00229 {
00230 int yoff = Figure_screen_offset(cy, scrollty);
00231 for (cx = start_chunkx; cx != stop_chunkx; cx = INCR_CHUNK(cx))
00232 {
00233 int xoff = Figure_screen_offset(cx, scrolltx);
00234 paint_chunk_flat_rles(cx, cy, xoff, yoff);
00235
00236 if (cheat.in_map_editor())
00237 Paint_chunk_outline(gwin,
00238 sman->get_special_pixel(HIT_PIXEL), cx, cy,
00239 map->get_terrain_num(cx, cy), xoff, yoff);
00240 }
00241 }
00242
00243
00244 int tmp_stopy = DECR_CHUNK(start_chunky);
00245 for (cy = start_chunky; cy != stop_chunky; cy = INCR_CHUNK(cy))
00246 {
00247 for (int dx = start_chunkx, dy = cy;
00248 dx != stop_chunkx && dy != tmp_stopy;
00249 dx = INCR_CHUNK(dx), dy = DECR_CHUNK(dy))
00250 light_sources += paint_chunk_objects(dx, dy);
00251 }
00252 for (cx = (start_chunkx + 1)%c_num_chunks; cx != stop_chunkx;
00253 cx = INCR_CHUNK(cx))
00254 {
00255 for (int dx = cx,
00256 dy = (stop_chunky - 1 + c_num_chunks)%c_num_chunks;
00257 dx != stop_chunkx && dy != tmp_stopy;
00258 dx = INCR_CHUNK(dx), dy = DECR_CHUNK(dy))
00259 light_sources += paint_chunk_objects(dx, dy);
00260 }
00261
00263 if (gwin->in_dungeon >= gwin->skip_above_actor &&
00264 !cheat.in_map_editor())
00265 paint_blackness (start_chunkx, start_chunky, stop_chunkx,
00266 stop_chunky, gwin->ice_dungeon?73:0);
00267
00268
00269 const Game_object_vector& sel = cheat.get_selected();
00270 int render_skip = gwin->get_render_skip_lift();
00271 for (Game_object_vector::const_iterator it = sel.begin();
00272 it != sel.end(); ++it)
00273 {
00274 Game_object *obj = *it;
00275 if (!obj->get_owner() && obj->get_lift() < render_skip)
00276 obj->paint_outline(HIT_PIXEL);
00277 }
00278
00279 if (cheat.in_map_editor() && cheat.show_tile_grid())
00280 Paint_grid(gwin, sman->get_xform(10));
00281
00282 return light_sources;
00283 }
00284
00285
00286
00287
00288
00289 void Game_window::paint
00290 (
00291 int x, int y, int w, int h
00292 )
00293 {
00294 if (!win->ready()) return;
00295
00296 win->set_clip(x, y, w, h);
00297 int light_sources = render->paint_map(x, y, w, h);
00298
00299 effects->paint();
00300 if (gump_man->modal_gump_mode())
00301 {
00302 effects->paint_text();
00303 gump_man->paint();
00304 }
00305 else
00306 {
00307 if (!main_actor_dont_move())
00308 gump_man->paint();
00309 effects->paint_text();
00310 }
00311 if (dragging)
00312 dragging->paint();
00313 win->clear_clip();
00314
00315 if (!x && !y && w == get_width() && h == get_height() && main_actor)
00316 {
00317 Actor *party[9];
00318 int cnt = get_party(party, 1);
00319 int carried_light = 0;
00320 for (int i = 0; !carried_light && i < cnt; i++)
00321 carried_light = party[i]->has_light_source();
00322
00323 if (special_light && clock->get_total_minutes() >special_light)
00324 {
00325 special_light = 0;
00326 clock->set_palette();
00327 }
00328
00329 clock->set_light_source(carried_light + (light_sources > 0),
00330 in_dungeon);
00331 }
00332 }
00333
00334
00335
00336
00337 void Game_window::paint()
00338 {
00339 map->read_map_data();
00340 set_all_dirty();
00341 paint_dirty();
00342 }
00343
00344
00345
00346
00347
00348 void Game_render::paint_chunk_flats
00349 (
00350 int cx, int cy,
00351 int xoff, int yoff
00352 )
00353 {
00354 Game_window *gwin = Game_window::get_instance();
00355 Map_chunk *olist = gwin->map->get_chunk(cx, cy);
00356
00357 #ifdef HAVE_OPENGL
00358 if (GL_manager::get_instance())
00359 {
00360 Chunk_terrain *terrain = olist->get_terrain();
00361 if (terrain)
00362 terrain->get_glflats()->paint(xoff, yoff);
00363 }
00364 else
00365 #endif
00366 {
00367 Image_buffer8 *cflats = olist->get_rendered_flats();
00368 if (cflats)
00369 gwin->win->copy8(cflats->get_bits(),
00370 c_chunksize, c_chunksize, xoff, yoff);
00371 }
00372 }
00373
00374
00375
00376
00377
00378 void Game_render::paint_chunk_flat_rles
00379 (
00380 int cx, int cy,
00381 int xoff, int yoff
00382 )
00383 {
00384 Game_window *gwin = Game_window::get_instance();
00385 Map_chunk *olist = gwin->map->get_chunk(cx, cy);
00386 Flat_object_iterator next(olist);
00387 Game_object *obj;
00388 while ((obj = next.get_next()) != 0)
00389 obj->paint();
00390 }
00391
00392
00393
00394
00395
00396
00397
00398 int Game_render::paint_chunk_objects
00399 (
00400 int cx, int cy
00401 )
00402 {
00403 Game_object *obj;
00404 Game_window *gwin = Game_window::get_instance();
00405 Map_chunk *olist = gwin->map->get_chunk(cx, cy);
00406 int light_sources =
00407 gwin->is_in_dungeon() ? olist->get_dungeon_lights()
00408 : olist->get_non_dungeon_lights();
00409 skip = gwin->get_render_skip_lift();
00410 Nonflat_object_iterator next(olist);
00411
00412 while ((obj = next.get_next()) != 0)
00413 if (obj->render_seq != render_seq)
00414 paint_object(obj);
00415
00416 skip = 31;
00417 return light_sources;
00418 }
00419
00420
00421
00422
00423
00424 void Game_render::paint_object
00425 (
00426 Game_object *obj
00427 )
00428 {
00429 int lift = obj->get_lift();
00430 if (lift >= skip)
00431 return;
00432 obj->render_seq = render_seq;
00433 int cnt = obj->get_dependency_count();
00434 for (int i = 0; i < cnt; i++)
00435 {
00436 Game_object *dep = obj->get_dependency(i);
00437 if (dep && dep->render_seq != render_seq)
00438 paint_object(dep);
00439 }
00440 obj->paint();
00441 }
00442
00443
00444
00445
00446
00447 void Game_window::paint_dirty()
00448 {
00449
00450 if (!main_actor_dont_move())
00451 gump_man->update_gumps();
00452
00453 Rectangle box = clip_to_win(dirty);
00454 if (box.w > 0 && box.h > 0)
00455 paint(box);
00456
00457 clear_dirty();
00458 }
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474 void Game_render::paint_blackness(int start_chunkx, int start_chunky, int stop_chunkx, int stop_chunky, int index)
00475 {
00476 Game_window *gwin = Game_window::get_instance();
00477
00478 const int off = gwin->in_dungeon << 2;
00479
00480
00481 for (int cy = start_chunky; cy != stop_chunky; cy = INCR_CHUNK(cy))
00482 {
00483 for (int cx = start_chunkx; cx != stop_chunkx; cx = INCR_CHUNK(cx))
00484 {
00485
00486 const int xoff =
00487 Figure_screen_offset(cx, gwin->scrolltx) - off;
00488
00489 int y = Figure_screen_offset(cy, gwin->scrollty) - off;
00490
00491
00492 Map_chunk *mc = gwin->map->get_chunk(cx, cy);
00493 if (!mc->has_dungeon())
00494 {
00495 gwin->win->fill8(index,
00496 c_tilesize*c_tiles_per_chunk,
00497 c_tilesize*c_tiles_per_chunk, xoff, y);
00498 continue;
00499 }
00500
00501 for (int tiley = 0; tiley < c_tiles_per_chunk; tiley++)
00502 {
00503
00504 int x = xoff;
00505 int w = 0;
00506
00507
00508 for (int tilex = 0; tilex < c_tiles_per_chunk; tilex++)
00509 {
00510
00511 if (!mc->is_dungeon(tilex, tiley))
00512 {
00513
00514 w += c_tilesize;
00515 }
00516
00517 else if (w)
00518 {
00519
00520 gwin->win->fill8(index, w, c_tilesize, x, y);
00521
00522
00523 x += w + c_tilesize;
00524
00525
00526 w = 0;
00527 }
00528
00529 else
00530 {
00531
00532 x += c_tilesize;
00533 }
00534
00535 }
00536
00537
00538 if (w)
00539 gwin->win->fill8(index, w, c_tilesize,
00540 x, y);
00541
00542
00543 y += c_tilesize;
00544 }
00545 }
00546 }
00547 }