void TileLayout::read_layout (const std::string &filename) throw() {
  // Iterate through the tiles and store them in the specified layer.
  std::ifstream f (const_cast<const char*>(filename.c_str()));
  if (f) {
    for (int tile_index_y = tiles_high - 1; tile_index_y >= 0; --tile_index_y) {
      // Tokenized numbers provide a simple way of allowing infinite tilesets
      // and tiles to be used in a map.
      std::string row_data;
      std::getline (f , row_data);
      StringTokenizer row_tokens (row_data);
      for (int tile_index_x = 0; tile_index_x < tiles_wide; ++tile_index_x) {
        std::string token = row_tokens.get_next_string();
        if (token == "*") {
          layout->set (tile_index_x, tile_index_y, NULL);
        } else {
          int tileset_index = std::atoi (token.c_str());
          int tile_index = row_tokens.get_next_integer();
          Tileset *tileset = tilesets[tileset_index];
          layout->set (tile_index_x, tile_index_y,
                       tileset->get_tile (tile_index));
        }
      } // for tile x index
    } // for tile y index
    f.close();
  } // layout file exists
}
void TournamentTeam::draw_team_score(int x, int y, bool rightalign, score_t score) {
    /* draw team score */
    char buffer[16];
    char *pb;
    Tileset *ts = resources.get_tileset("numbers");
    int tile_width = ts->get_tile(0)->get_tilegraphic()->get_width();
    int number_width = tile_width - 13;

    /* team red */
    sprintf(buffer, "%d", score);
    if (rightalign) {
        x -= (strlen(buffer) - 1) * number_width;
    }
    pb = buffer;
    while (*pb) {
        subsystem.draw_tile(ts->get_tile(*pb - '0'), x, y);
        x += number_width;
        pb++;
    }
}
void CompileThreadBlock::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++) {
        {
            Scope<Mutex> lock(mtx);
            finished_percent = 100 * (i + 1) / nlgt;
            if (cancelled) {
                break;
            }
        }
        int r = lights[i]->radius;
        int colr = lights[i]->r;
        int colg = lights[i]->g;
        int colb = lights[i]->b;
        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()) {
                                        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;
                                        }
                                    }
                                }
                            }
                            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]) {
                            double l = 1.0 - (static_cast<double>(v) / 255.0);
                            lightmap[y][x * 4 + 0] = static_cast<unsigned char>(colr * l);
                            lightmap[y][x * 4 + 1] = static_cast<unsigned char>(colg * l);
                            lightmap[y][x * 4 + 2] = static_cast<unsigned char>(colb * l);
                            lightmap[y][x * 4 + 3] = v;
                        }
                    }
                }
            }
        }
    }

    Scope<Mutex> lock(mtx);
    finished = true;
}
void TournamentSR::draw_score() {
    Player *me = get_me();
    if (!(me->state.server_state.flags & PlayerServerFlagSpectating)) {
        TimesOfPlayer *top = get_times_of_player(me);
        if (top) {
            subsystem.set_color(0.75f, 0.75f, 1.0f, 0.75f);

            if (!game_over) {
                get_now(now_for_drawing);
            }
            ms_t d_ms = diff_ms(top->start_time, now_for_drawing);
            float diff = round(d_ms / 10.0f) / 100.0f;

            char *pb;
            int len;
            int x;
            int view_width = subsystem.get_view_width();
            Tileset *ts = resources.get_tileset("numbers");
            int tile_width = ts->get_tile(0)->get_tilegraphic()->get_width();
            int number_width = tile_width - 13;
            int i = static_cast<int>(floor(diff));
            int m = static_cast<int>((diff - i) * 100);

            /* first part */
            sprintf(buffer, "%d", i);
            len = strlen(buffer);
            x = view_width / 2 - (len * number_width) - number_width / 2;
            pb = buffer;
            while (*pb) {
                subsystem.draw_tile(ts->get_tile(*pb - '0'), x, 5);
                x += number_width;
                pb++;
            }

            /* draw dot */
            subsystem.draw_tile(ts->get_tile(11), x, 5);
            x += number_width;

            /* second part */
            sprintf(buffer, "%02d", m);
            pb = buffer;
            while (*pb) {
                subsystem.draw_tile(ts->get_tile(*pb - '0'), x, 5);
                x += number_width;
                pb++;
            }

            /* reset */
            subsystem.reset_color();

            /* draw best & last lap */
            size_t sz = top->times.size();
            Font *f = resources.get_font("big");

            const TimesOfPlayer& lead = times_of_players[0];
            if (lead.times.size()) {
                subsystem.set_color(0.25f, 1.0f, 0.25f, 1.0f);
                subsystem.draw_text(f, 5, 5, "lead:");
                sprintf(buffer, "%.2f (%s)", lead.best, lead.player->get_player_name().c_str());
                subsystem.draw_text(f, 45, 5, buffer);
                subsystem.reset_color();
            }

            subsystem.draw_text(f, 5, 20, "lap:");
            sprintf(buffer, "%d", static_cast<int>(sz + 1));
            subsystem.draw_text(f, 45, 20, buffer);

            if (sz) {
                subsystem.draw_text(f, 5, 35, "best:");
                sprintf(buffer, "%.2f", top->best);
                subsystem.draw_text(f, 45, 35, buffer);

                subsystem.draw_text(f, 5, 50, "last:");
                sprintf(buffer, "%.2f", top->last);
                subsystem.draw_text(f, 45, 50, buffer);
            }
        }
    }
}
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;
}