void MapEditor::calculate_light(bool pixel_precise) { if (wmap) { EditableMap::Lights& lights = wmap->get_light_sources(); if (!lights.size()) { show_messagebox(Gui::MessageBoxIconExclamation, "Light Sources", "No light sources found in this map."); return; } /* name set? */ if (!wmap->get_name().length()) { show_messagebox(Gui::MessageBoxIconExclamation, "No Map Name", "Please choose a map name in the map properties."); return; } /* trace all points */ Tileset *ts = wmap->get_tileset_ptr(); if (!ts) { show_messagebox(Gui::MessageBoxIconExclamation, "No Tileset", "Please select a tileset in the map properties."); return; } int vw = subsystem.get_view_width(); int vh = subsystem.get_view_height(); int ww = 127; int wh = 80; //60; win_compile = push_window(vw / 2 - ww / 2, vh / 2 - wh / 2, ww, wh, "Compiling"); lbl_compile = create_label(win_compile, Spc, Spc, "0%"); GuiButton *btn = add_close_button(win_compile, static_cancel_compilation_click); btn->set_caption("Cancel"); int mw = wmap->get_width(); int mh = wmap->get_height(); int tw = ts->get_tile_width(); int th = ts->get_tile_height(); lightmap_w = mw * tw; lightmap_h = mh * th; int mapw = mw * tw; int maph = mh * th; short **pdeco = wmap->get_decoration(); if (lightmap_w % LightMapSize) { lightmap_w = ((lightmap_w / LightMapSize) + 1) * LightMapSize; } if (lightmap_h % LightMapSize) { lightmap_h = ((lightmap_h / LightMapSize) + 1) * LightMapSize; } /* create whole lightmap */ lightmap = new unsigned char *[lightmap_h]; /* create thread */ if (pixel_precise) { for (int y = 0; y < lightmap_h; y++) { lightmap[y] = new unsigned char[lightmap_w * 4]; for (int x = 0; x < lightmap_w; x++) { lightmap[y][x * 4 + 0] = 0; lightmap[y][x * 4 + 1] = 0; lightmap[y][x * 4 + 2] = 0; if (x >= mapw || y >= maph) { lightmap[y][x * 4 + 3] = 0; } else { int index = pdeco[y / th][x / tw]; if (index < 0) { lightmap[y][x * 4 + 3] = 0; } else { TileGraphic *tg = ts->get_tile(index)->get_tilegraphic(); TileGraphicGL *tggl = static_cast<TileGraphicGL *>(tg); if (tggl->get_bytes_per_pixel(0) < 4) { lightmap[y][x * 4 + 3] = 255; } else { unsigned char *p = tggl->get_picture_array(0); p += (((y % th) * 4 * tw) + ((x % tw) * 4)); lightmap[y][x * 4 + 3] = p[3]; } } } } } compile_thread = new CompileThreadPixel(wmap, lightmap); } else { for (int y = 0; y < lightmap_h; y++) { lightmap[y] = new unsigned char[lightmap_w * 4]; for (int x = 0; x < lightmap_w; x++) { lightmap[y][x * 4 + 0] = 0; lightmap[y][x * 4 + 1] = 0; lightmap[y][x * 4 + 2] = 0; if (x >= mapw || y >= maph) { lightmap[y][x * 4 + 3] = 0; } else { if (pdeco[y / th][x / tw] < 0) { lightmap[y][x * 4 + 3] = 0; } else { lightmap[y][x * 4 + 3] = 255; } } } } compile_thread = new CompileThreadBlock(wmap, lightmap); } } }
void CompileThreadPixel::thread() { EditableMap::Lights& lights = wmap->get_light_sources(); Tileset *ts = wmap->get_tileset_ptr(); size_t nlgt = lights.size(); int mw = wmap->get_width(); int mh = wmap->get_height(); int tw = ts->get_tile_width(); int th = ts->get_tile_height(); int w = mw * tw; int h = mh * th; short **pmap = wmap->get_map(); short **pdeco = wmap->get_decoration(); Point pr; for (size_t i = 0; i < nlgt; i++) { { ScopeMutex lock(mtx); finished_percent = 100 * (i + 1) / nlgt; } int r = lights[i]->radius; int lmaxsq = r * r; int lx = lights[i]->x; int ly = lights[i]->y; Point p2(static_cast<float>(lx * tw + (tw / 2)), static_cast<float>(ly * th + (th / 2))); int lsx = static_cast<int>(p2.x) - r; int lsy = static_cast<int>(p2.y) - r; int lex = static_cast<int>(p2.x) + r; int ley = static_cast<int>(p2.y) + r; if (lsx < 0) lsx = 0; if (lsy < 0) lsy = 0; if (lex > w) lex = w; if (ley > h) ley = h; int txs = lsx / tw; int txe = lex / tw; int tys = lsy / th; int tye = ley / th; for (int y = lsy; y < ley; y++) { for (int x = lsx; x < lex; x++) { int dindex = pdeco[y / th][x / tw]; if (dindex < 0) { lightmap[y][x * 4 + 3] = 0; } else { bool contact = false; Point p1(static_cast<float>(x), static_cast<float>(y)); float xd = p2.x - p1.x; float yd = p2.y - p1.y; float dist = xd * xd + yd * yd; if (dist < lmaxsq) { for (int tx = txs; tx < txe; tx++) { for (int ty = tys; ty < tye; ty++) { short index = pmap[ty][tx]; if (index >= 0) { if (ts->get_tile(index)->is_light_blocking()) { TileGraphic *tg = ts->get_tile(index)->get_tilegraphic(); TileGraphicGL *tggl = static_cast<TileGraphicGL *>(tg); if (tggl->get_bytes_per_pixel(0) < 4) { Point p1l(static_cast<float>(tx * tw), static_cast<float>(ty * th)); Point p2l(static_cast<float>(tx * tw), static_cast<float>((ty + 1) * th - 0.5f)); Point p1r(static_cast<float>((tx + 1) * tw - 0.5f), static_cast<float>(ty * th)); Point p2r(static_cast<float>((tx + 1) * tw - 0.5f), static_cast<float>((ty + 1) * th - 0.5f)); Point p1t(static_cast<float>(tx * tw), static_cast<float>(ty * th)); Point p2t(static_cast<float>((tx + 1) * tw - 0.5f), static_cast<float>(ty * th)); Point p1b(static_cast<float>(tx * tw), static_cast<float>((ty + 1) * th - 0.5f)); Point p2b(static_cast<float>((tx + 1) * tw - 0.5f), static_cast<float>((ty + 1) * th - 0.5f)); if (intersection(p1, p2, p1l, p2l, pr) || intersection(p1, p2, p1r, p2r, pr) || intersection(p1, p2, p1t, p2t, pr) || intersection(p1, p2, p1b, p2b, pr)) { contact = true; break; } } else { unsigned char *p = tggl->get_picture_array(0); for (int py = 0; py < th; py++) { for (int px = 0; px < tw; px++) { if (p[3] == 255) { Point p1v(static_cast<float>(tx * tw + px) + 0.5f, static_cast<float>(ty * th + py) - 0.5f); Point p2v(static_cast<float>(tx * tw + px) + 0.5f, static_cast<float>(ty * th + py) + 0.5f); Point p1h(static_cast<float>(tx * tw + px) - 0.5f, static_cast<float>(ty * th + py) + 0.5f); Point p2h(static_cast<float>(tx * tw + px) + 0.5f, static_cast<float>(ty * th + py) + 0.5f); if (intersection(p1, p2, p1v, p2v, pr) || intersection(p1, p2, p1h, p2h, pr)) { contact = true; break; } } p += 4; } if (contact) { break; } } if (contact) { break; } } } } } if (contact) { break; } } } else { contact = true; } if (!contact) { int v = static_cast<int>(sqrt(65025.0f * dist / lmaxsq)); if (v < lightmap[y][x * 4 + 3]) { lightmap[y][x * 4 + 3] = v; } } } } } } ScopeMutex lock(mtx); finished = true; }