Permalink
Browse files

Major refactoring and structuring of code.

* Added the following translation units;
 - marker
 - nullstream
 - settings_t

* Moved generate_map, generate_statistics into their own translation units.
* Code should compile a lot faster due to these changes.
  • Loading branch information...
1 parent 52831f1 commit 734adcaf1b8e93eb7a1e841f4c7c357dbf543511 @udoprog committed Apr 14, 2012
View
5 CMakeLists.txt
@@ -83,6 +83,11 @@ set(c10t_SOURCES
src/warps.cpp
src/text.cpp
src/json.cpp
+ src/generate_map.cpp
+ src/generate_statistics.cpp
+ src/marker.cpp
+ src/nullstream.cpp
+ src/settings_t.cpp
)
add_executable(c10t ${c10t_SOURCES})
View
118 src/algorithm.hpp
@@ -4,34 +4,47 @@
#include <stdlib.h>
#include <ostream>
-namespace nonstd {
+namespace nonstd
+{
template<typename T>
- class reporting {
+ class reporting
+ {
public:
virtual void add(T) = 0;
virtual void done(T) = 0;
- virtual void set_limit(T) = 0;
};
-
- template<typename T>
- class continious : public reporting<T> {
- protected:
- const static uintmax_t LINE_WIDTH = 30;
+
+ template<typename T, typename O = std::ostream>
+ class continious : public reporting<T>
+ {
public:
- typedef void (*progress_func)(std::ostream&, T);
- typedef void (*endline_func)(std::ostream&, T);
+ const static uintmax_t LINE_WIDTH = 30;
- continious(std::ostream& out, T limit, progress_func progress_f, endline_func endline_f) :
- out(out), chunks(0), total(0), limit(limit), line(0),
- progress_f(progress_f), endline_f(endline_f)
- {}
+ typedef void (*progress_func)(O&, T);
+ typedef void (*endline_func)(O&, T);
+
+ continious(O& out,
+ T progress_threshold,
+ progress_func progress_f,
+ endline_func endline_f)
+ : out(out),
+ chunks(0),
+ total(0),
+ progress_threshold(progress_threshold),
+ line(0),
+ progress_f(progress_f),
+ endline_f(endline_f)
+ {
+ }
- virtual void add(T parts) {
+ virtual void add(T parts)
+ {
chunks += parts;
- while (chunks > limit) {
- chunks -= limit;
- total += limit;
+ while (chunks > progress_threshold)
+ {
+ chunks -= progress_threshold;
+ total += progress_threshold;
progress_f(out, total);
@@ -41,77 +54,86 @@ namespace nonstd {
}
}
}
-
- virtual void set_limit(T limit) {
- }
- void done(T last_part) {
+ void done(T last_part)
+ {
total += chunks + last_part;
endline_f(out, total);
}
private:
- std::ostream& out;
+ O& out;
T chunks;
T total;
- T limit;
+ T progress_threshold;
unsigned int line;
progress_func progress_f;
endline_func endline_f;
};
- template<typename T>
- class limited : public reporting<T> {
- protected:
- const static uintmax_t LINE_WIDTH = 30;
+ template<typename T, typename O = std::ostream>
+ class limited : public reporting<T>
+ {
public:
- typedef void (*progress_func)(std::ostream&, T);
- typedef void (*endline_func)(std::ostream&, T, T);
+ const static uintmax_t LINE_WIDTH = 30;
+
+ typedef void (*progress_func)(O&, T);
+ typedef void (*endline_func)(O&, T, T);
- limited(std::ostream& out, T limit, progress_func progress_f, endline_func endline_f) :
- out(out), chunks(0), total(0), limit(limit), line(0),
- progress_f(progress_f), endline_f(endline_f), total_limit(0), total_limit_set(false)
- {}
+ limited(O& out,
+ T progress_threshold,
+ T total_limit,
+ progress_func progress_f,
+ endline_func endline_f)
+ : out(out),
+ chunks(0),
+ total(0),
+ progress_threshold(progress_threshold),
+ line(0),
+ progress_f(progress_f),
+ endline_f(endline_f),
+ total_limit(total_limit)
+ {
+ }
- virtual void add(T parts) {
+ virtual void add(T parts)
+ {
chunks += parts;
- while (chunks > limit) {
- chunks -= limit;
- total += limit;
+ while (chunks > progress_threshold)
+ {
+ chunks -= progress_threshold;
+ total += progress_threshold;
progress_f(out, total);
- if (line++ >= LINE_WIDTH) {
+ if (line++ >= LINE_WIDTH)
+ {
endline_f(out, total, total_limit);
line = 0;
}
}
}
- virtual void set_limit(T limit) {
- total_limit = limit;
- total_limit_set = true;
- }
-
- void done(T last) {
+ void done(T last)
+ {
total += last;
endline_f(out, total_limit, total_limit);
}
private:
- std::ostream& out;
+ O& out;
+
T chunks;
T total;
- T limit;
+ T progress_threshold;
unsigned int line;
progress_func progress_f;
endline_func endline_f;
T total_limit;
- bool total_limit_set;
};
}
View
11 src/altitude_graph.cpp
@@ -1,6 +1,9 @@
#include "altitude_graph.hpp"
#include "text.hpp"
+using namespace std;
+namespace fs = boost::filesystem;
+
#define BORDER_X 50
#define BORDER_Y 50
@@ -55,14 +58,14 @@ void AltitudeGraph::createGraph()
{
x = BORDER_X + x_step*i;
y = _h - (int)( ( (float)altitudeRegistry[i] / (float)maxVal ) * (_h-BORDER_Y) );
- graphImg->drawLine(x, y, x0, y0, fgcolor);
+ graphImg->draw_line(x, y, x0, y0, fgcolor);
x0 = x;
y0 = y;
}
// draw axis
- graphImg->drawLine(BORDER_X, BORDER_Y, BORDER_X, _h, axiscolor);
- graphImg->drawLine(BORDER_X, _h, _w, _h, axiscolor);
+ graphImg->draw_line(BORDER_X, BORDER_Y, BORDER_X, _h, axiscolor);
+ graphImg->draw_line(BORDER_X, _h, _w, _h, axiscolor);
// draw axis labels
for(int i=0; i < mc::MapY; i++)
@@ -80,7 +83,7 @@ void AltitudeGraph::createGraph()
{
size = 5;
}
- graphImg->drawLine(x, _h, x, _h+size, _axiscolor);
+ graphImg->draw_line(x, _h, x, _h+size, _axiscolor);
}
png_format::opt_type opts;
View
7 src/altitude_graph.hpp
@@ -11,25 +11,22 @@
#include <boost/scoped_array.hpp>
-#include "image/format/png.hpp"
+#include "settings_t.hpp"
-#include "global.hpp"
#include "players.hpp"
#include "image/image_base.hpp"
#include "image/memory_image.hpp"
#include "image/cached_image.hpp"
#include "image/algorithms.hpp"
+#include "image/format/png.hpp"
#include "mc/world.hpp"
#include "mc/blocks.hpp"
#include "mc/utils.hpp"
#include "nbt/nbt.hpp"
-using namespace std;
-namespace fs = boost::filesystem;
-
class AltitudeGraph
{
public:
View
944 src/generate_map.cpp
@@ -0,0 +1,944 @@
+#include "config.hpp"
+#include "image/format/png.hpp"
+
+#include "generate_map.hpp"
+
+#include "text.hpp"
+#include "players.hpp"
+#include "warps.hpp"
+#include "marker.hpp"
+
+#include "algorithm.hpp"
+
+#include "engine/engine_core.hpp"
+#include "engine/topdown_engine.hpp"
+#include "engine/oblique_engine.hpp"
+#include "engine/obliqueangle_engine.hpp"
+#include "engine/isometric_engine.hpp"
+#include "engine/fatiso_engine.hpp"
+
+#include "mc/blocks.hpp"
+#include "mc/region_iterator.hpp"
+#include "dlopen.hpp"
+
+#include "image/algorithms.hpp"
+#include "image/image_base.hpp"
+#include "image/cached_image.hpp"
+#include "image/memory_image.hpp"
+
+#include "cache.hpp"
+
+#include "json.hpp"
+
+#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/ptr_container/ptr_vector.hpp>
+
+#include <ostream>
+#include <iomanip>
+
+using namespace std;
+namespace fs = boost::filesystem;
+
+typedef std::map<mc::utils::level_coord, mc::rotated_level_info> levels_map;
+
+template<typename T>
+void dot(std::ostream& out, T total)
+{
+ if (total == 0x00)
+ {
+ out << " done!";
+ }
+ else
+ {
+ out << "." << std::flush;
+ }
+}
+
+void parts_endl(std::ostream& out, unsigned int total)
+{
+ out << " " << setw(8) << total << " parts" << endl;
+}
+
+void parts_perc_endl(std::ostream& out, unsigned int progress, unsigned int total)
+{
+ out << " " << setw(8)
+ << progress << " parts "
+ << (progress * 100) / total << "%" << endl;
+}
+
+void mb_endl(std::ostream& out, streampos progress, streampos total)
+{
+ out << " " << setw(8)
+ << fixed << float(progress) / 1000000 << " MB "
+ << (progress * 100) / total << "%" << endl;
+}
+
+/**
+ * Load all warps from a database and push them to a container.
+ */
+template<typename T>
+inline void load_warps(ostream& out, fs::path warps_path, T& warps)
+{
+ out << "warps: " << warps_path << ": " << flush;
+
+ warps_db wdb(warps_path);
+
+ try {
+ wdb.read(warps);
+ out << warps.size() << " warp(s) OK" << endl;
+ } catch(warps_db_exception& e) {
+ out << e.what() << endl;
+ }
+}
+
+/**
+ * Load all players from a database and push them to a container.
+ */
+template<typename T, typename S>
+inline void load_players(ostream& out, fs::path show_players_path, T& players, S& player_set)
+{
+ out << "players: " << show_players_path << ": " << flush;
+
+ players_db pdb(show_players_path, player_set);
+
+ std::vector<player> all_players;
+
+ try {
+ pdb.read(all_players);
+ } catch(players_db_exception& e) {
+ out << " " << e.what() << endl;
+ return;
+ }
+
+ out << all_players.size() << " player(s) found" << endl;
+
+ BOOST_FOREACH(player p, all_players) {
+ if (p.error) {
+ out << " " << p.path << ":" << p.error_where << ": " << p.error_why << endl;
+ continue;
+ }
+
+ players.push_back(p);
+ }
+
+ out << " " << players.size() << " player(s) OK" << endl;
+}
+
+/**
+ * Push all players to a standard type of marker.
+ */
+template<typename P, typename T>
+void push_player_markers(settings_t& s, text::font_face base_font, P& players, T& markers)
+{
+ text::font_face player_font = base_font;
+
+ if (s.has_player_color) {
+ player_font.set_color(s.player_color);
+ }
+
+ BOOST_FOREACH(player p, players) {
+ if (p.zPos / mc::MapZ < s.min_z) continue;
+ if (p.zPos / mc::MapZ > s.max_z) continue;
+ if (p.xPos / mc::MapX < s.min_x) continue;
+ if (p.xPos / mc::MapX > s.max_x) continue;
+
+ markers.push_back(new marker(p.name, "player", player_font, p.xPos, p.yPos, p.zPos));
+ }
+}
+
+/**
+ * Push all signs to a standard type of marker.
+ */
+template<typename S, typename T>
+void push_sign_markers(settings_t& s, text::font_face base_font, S& signs, T& markers)
+{
+ text::font_face sign_font = base_font;
+
+ if (s.has_sign_color) {
+ sign_font.set_color(s.sign_color);
+ }
+
+ BOOST_FOREACH(mc::marker lm, signs) {
+ if (!s.show_signs_filter.empty() && lm.get_text().find(s.show_signs_filter) == std::string::npos) {
+ continue;
+ }
+
+ if (!s.strip_sign_prefix) {
+ markers.push_back(new marker(lm.get_text(), "sign", sign_font,
+ lm.get_x(), lm.get_y(), lm.get_z()));
+ } else {
+ std::string text = lm.get_text().substr(s.show_signs_filter.size());
+ markers.push_back(new marker(text, "sign", sign_font,
+ lm.get_x(), lm.get_y(), lm.get_z()));
+ }
+ }
+}
+
+typedef std::map<mc::utils::level_coord, mc::rotated_level_info> levels_map;
+
+/**
+ * Push all coordinates to a standard type of marker.
+ */
+template<typename L, typename T>
+void push_coordinate_markers(
+ std::ostream& out,
+ settings_t& s,
+ text::font_face base_font,
+ mc::world& world,
+ L& levels,
+ T& markers)
+{
+ text::font_face coordinate_font = base_font;
+
+ if (s.has_coordinate_color) {
+ coordinate_font.set_color(s.coordinate_color);
+ }
+
+ BOOST_FOREACH(levels_map::value_type value, levels)
+ {
+ mc::utils::level_coord c = value.second.get_coord();
+ mc::level_info::level_info_ptr level_info = value.second.get_level();
+
+ if (c.get_z() - 4 < world.min_z) continue;
+ if (c.get_z() + 4 > world.max_z) continue;
+ if (c.get_x() - 4 < world.min_x) continue;
+ if (c.get_x() + 4 > world.max_x) continue;
+ if (c.get_z() % 10 != 0) continue;
+ if (c.get_x() % 10 != 0) continue;
+
+ std::stringstream result;
+
+ result << "(" << level_info->get_x() * mc::MapX
+ << ", " << level_info->get_z() * mc::MapZ << ")";
+
+ if (s.debug) {
+ out << "Pushing coordinate info " << result.str() << std::endl;
+ }
+
+ markers.push_back(new marker(result.str(), "coord", coordinate_font, c.get_x() * mc::MapX, 0, c.get_z() * mc::MapZ));
+ }
+}
+
+/**
+ * Push all warps to a standard type of marker.
+ */
+template<typename W, typename T>
+inline void push_warp_markers(
+ settings_t& s,
+ text::font_face base_font,
+ W& warps,
+ T& markers)
+{
+ text::font_face warp_font = base_font;
+
+ if (s.has_warp_color) {
+ warp_font.set_color(s.warp_color);
+ }
+
+ /* initial code for projecting warps */
+ BOOST_FOREACH(warp w, warps) {
+ if (w.zPos / mc::MapZ < s.min_z) continue;
+ if (w.zPos / mc::MapZ > s.max_z) continue;
+ if (w.xPos / mc::MapX < s.min_x) continue;
+ if (w.xPos / mc::MapX > s.max_x) continue;
+
+ marker *m = new marker(w.name, "warp", warp_font, w.xPos, w.yPos, w.zPos);
+ markers.push_back(m);
+ }
+}
+
+/*
+ * Store part of a level rendered as a small image.
+ *
+ * This will allow us to composite the entire image later and calculate sizes then.
+ */
+
+void populate_markers(
+ settings_t& s,
+ json::array* array,
+ boost::shared_ptr<engine_core> engine,
+ boost::ptr_vector<marker>& markers)
+{
+ boost::ptr_vector<marker>::iterator it;
+
+ for (it = markers.begin(); it != markers.end(); it++) {
+ marker m = *it;
+
+ mc::utils::level_coord original_coord(m.get_x(), m.get_z());
+ mc::utils::level_coord coord = original_coord.rotate(s.rotation);
+
+ pos_t x, y;
+
+ engine->wp2pt(coord.get_x(), m.get_y(), coord.get_z(), x, y);
+
+ json::object* o = new json::object;
+
+ o->put("text", new json::string(m.get_text()));
+ o->put("type", new json::string(m.get_type()));
+
+ // the projected coordinates
+ o->put("x", new json::number(x));
+ o->put("y", new json::number(y));
+
+ // the real coordinates
+ o->put("X", new json::number(m.get_x()));
+ o->put("Y", new json::number(m.get_y()));
+ o->put("Z", new json::number(m.get_z()));
+
+ array->push(o);
+ }
+ // don't bother to check for errors right now, but could be done using the "fail" accessor.
+}
+
+inline void overlay_markers(
+ settings_t& s,
+ image_ptr work_in_progress,
+ boost::shared_ptr<engine_core> engine,
+ boost::ptr_vector<marker>& markers
+ )
+{
+ memory_image positionmark(5, 5);
+ positionmark.fill(s.ttf_color);
+
+ boost::ptr_vector<marker>::iterator it;
+
+ for (it = markers.begin(); it != markers.end(); it++) {
+ marker m = *it;
+
+ text::font_face font = m.get_font();
+
+ if (!font.is_initialized()) {
+ continue;
+ }
+
+ mc::utils::level_coord original_coord(m.get_x(), m.get_z());
+ mc::utils::level_coord coord = original_coord.rotate(s.rotation);
+
+ pos_t x;
+ pos_t y;
+
+ engine->wp2pt(coord.get_x(), m.get_y(), coord.get_z(), x, y);
+
+ font.draw(work_in_progress, m.get_text(), x + 5, y);
+ //all->safe_composite(x - 3, y - 3, positionmark);
+ }
+}
+
+/**
+ * Helper blocks
+ */
+
+typedef std::map<mc::utils::level_coord, mc::rotated_level_info> levels_map;
+
+void write_json_file(
+ ostream& out,
+ settings_t& s,
+ boost::shared_ptr<engine_core> engine,
+ mc::world& world,
+ boost::ptr_vector<marker> markers)
+{
+ // calculate world center
+ engine_core::pos_t center_x, center_y;
+ mc::utils::level_coord coord =
+ mc::utils::level_coord(s.center_x*16, s.center_z*16).rotate(s.rotation);
+
+ engine->wp2pt(coord.get_x(), 0, coord.get_z(), center_x, center_y);
+
+ json::object file;
+ json::object* json_static = new json::object;
+
+ json_static->put("MapX", new json::number(mc::MapX));
+ json_static->put("MapY", new json::number(mc::MapY));
+ json_static->put("MapZ", new json::number(mc::MapZ));
+
+ file.put("st", json_static);
+
+ json::object* json_world = new json::object;
+
+ json_world->put("cx", new json::number(center_x));
+ json_world->put("cy", new json::number(center_y));
+ json_world->put("dx", new json::number((world.diff_x + 1) * mc::MapX));
+ json_world->put("dz", new json::number((world.diff_z + 1) * mc::MapZ));
+ json_world->put("dy", new json::number(mc::MapY));
+ json_world->put("mn_x", new json::number(world.min_x * 16));
+ json_world->put("mn_z", new json::number(world.min_z * 16));
+ json_world->put("mx_x", new json::number(world.max_x * 16));
+ json_world->put("mx_z", new json::number(world.max_z * 16));
+ json_world->put("rot", new json::number(s.rotation));
+ json_world->put("mode", new json::number(s.mode));
+ json_world->put("split_base", new json::number(s.split_base));
+ json_world->put("split", new json::number(s.split.size()));
+
+ file.put("world", json_world);
+
+ json::array* markers_array = new json::array;
+ populate_markers(s, markers_array, engine, markers);
+ file.put("markers", markers_array);
+
+ if (s.write_json) {
+ out << "Writing json information: " << path_string(s.write_json_path) << endl;
+ std::ofstream of(path_string(s.write_json_path).c_str());
+ of << file;
+ of.close();
+ }
+
+ if (s.write_js) {
+ out << "Writing js (javascript `var c10t_json') information: " << path_string(s.write_js_path) << endl;
+ std::ofstream of(path_string(s.write_js_path).c_str());
+ of << "var c10t_json = " << file << ";";
+ of.close();
+ }
+}
+
+/**
+ * Generate a map
+ *
+ * This is one of the main methods, it does the following steps.
+ *
+ * - Look for specificed databases.
+ * - Scan the world for regions containing levels.
+ * - Depending on settings, choose which rendering engine to use.
+ * - Setup work-in-progress image to required type depending on predicted memory
+ * use.
+ * - Perform rendering phase where engine takes level information, and produces
+ * image_operations, composite all operations to the work-in-progress image.
+ * Try to distribute work evenly among threads.
+ *
+ */
+bool generate_map(
+ ostream& out,
+ ostream& out_log,
+ ostream& error,
+ settings_t &s,
+ std::vector<std::string>& hints,
+ fs::path& world_path,
+ fs::path& output_path)
+{
+ out << endl << "Generating PNG Map" << endl << endl;
+
+ // all marker source information.
+ std::vector<player> players;
+ std::vector<warp> warps;
+ std::vector<mc::marker> signs;
+
+ // this is where the actual markers will be populated later.
+ boost::ptr_vector<marker> markers;
+
+ // symbolic definition of a world.
+ mc::world world(world_path);
+
+ // where to store level info
+ levels_map levels;
+
+ // this is the rendering engine that will be used.
+ boost::shared_ptr<engine_core> engine;
+
+ // image to work against, could be backed by hard drive, or purely in memory.
+ image_ptr work_in_progress;
+
+ /**
+ * Any of these options will trigger the database blocks to run.
+ */
+ bool use_any_database =
+ s.show_players
+ || s.show_signs
+ || s.show_coordinates
+ || s.show_warps;
+
+ bool output_json =
+ s.write_json || s.write_js;
+
+ /*
+ * Look for specificed databases.
+ */
+ if (use_any_database)
+ {
+ out << " --- LOOKING FOR DATABASES --- " << endl;
+
+ if (s.show_warps) {
+ load_warps(out, s.show_warps_path, warps);
+ }
+
+ if (s.show_players) {
+ load_players(out, world_path / "players", players, s.show_players_set);
+ }
+
+ if (s.show_signs) {
+ out << "will look for signs in levels" << endl;
+ }
+
+ if (s.show_coordinates) {
+ out << "will store chunk coordinates" << endl;
+ }
+ }
+
+ {
+ out << " --- SCANNING WORLD DIRECTORY --- " << endl;
+ out << "world: " << path_string(world_path) << endl;
+ }
+
+ /*
+ * Scan the world for regions containing levels.
+ */
+ {
+ nonstd::continious<unsigned int> reporter(out, 100, dot, parts_endl);
+ mc::region_iterator iterator = world.get_iterator();
+
+ int failed_regions = 0;
+ int filtered_levels = 0;
+
+ while (iterator.has_next()) {
+ mc::region_ptr region = iterator.next();
+
+ try {
+ region->read_header();
+ } catch(mc::bad_region& e) {
+ ++failed_regions;
+ out_log << path_string(region->get_path()) << ": could not read header" << std::endl;
+ continue;
+ }
+
+ std::list<mc::utils::level_coord> coords;
+
+ region->read_coords(coords);
+
+ BOOST_FOREACH(mc::utils::level_coord c, coords) {
+ mc::level_info::level_info_ptr level(new mc::level_info(region, c));
+
+ mc::utils::level_coord coord = level->get_coord();
+
+ if (s.coord_out_of_range(coord)) {
+ ++filtered_levels;
+ out_log << level->get_path() << ": (z,x) position"
+ << " (" << coord.get_z() << "," << coord.get_x() << ")"
+ << " out of limit" << std::endl;
+ continue;
+ }
+
+ mc::rotated_level_info rlevel =
+ mc::rotated_level_info(level, coord.rotate(s.rotation));
+
+ levels.insert(levels_map::value_type(rlevel.get_coord(), rlevel));
+
+ world.update(rlevel.get_coord());
+ reporter.add(1);
+ }
+ }
+
+ reporter.done(0);
+
+ if (failed_regions > 0) {
+ out << "SEE LOG: " << failed_regions << " region(s) failed!" << endl;
+ }
+
+ if (filtered_levels > 0) {
+ out << "SEE LOG: " << filtered_levels << " level(s) filtered!" << endl;
+ }
+ }
+
+ if (levels.size() <= 0) {
+ out << "No chunks to render" << endl;
+ return 0;
+ }
+
+ if (s.debug) {
+ out << " --- DEBUG WORLD INFO --- " << endl;
+ out << "mc::world" << endl;
+ out << " min_x: " << world.min_x << endl;
+ out << " max_x: " << world.max_x << endl;
+ out << " min_z: " << world.min_z << endl;
+ out << " max_z: " << world.max_z << endl;
+ out << " levels: " << levels.size() << endl;
+ out << " radius: " << s.max_radius << endl;
+ out << " chunk pos: " << world.chunk_x << "x" << world.chunk_y << endl;
+ }
+
+ engine_settings engine_s;
+
+ engine_s.rotation = s.rotation;
+ engine_s.night = s.night;
+ engine_s.heightmap = s.heightmap;
+ engine_s.striped_terrain = s.striped_terrain;
+ engine_s.hellmode = s.hellmode;
+ engine_s.cavemode = s.cavemode;
+ engine_s.top = s.top;
+ engine_s.bottom = s.bottom;
+ engine_s.excludes = s.excludes;
+
+ if (s.engine_use) {
+ dl_t* dl = dl_open(path_string(s.engine_path).c_str());
+
+ if (dl == NULL) {
+ error << "Failed to open library: " << path_string(s.engine_path) << endl;
+ return false;
+ }
+
+ typedef void (*hello_f)();
+
+ //hello_f hello = (hello_f)dl_sym(dl, "hello");
+ //hello();
+ return true;
+ }
+ else {
+ /**
+ * Depending on settings, choose which rendering engine to use.
+ */
+ switch (s.mode) {
+ case Top:
+ engine.reset(new topdown_engine(engine_s, world));
+ break;
+
+ case Oblique:
+ engine.reset(new oblique_engine(engine_s, world));
+ break;
+
+ case ObliqueAngle:
+ engine.reset(new obliqueangle_engine(engine_s, world));
+ break;
+
+ case Isometric:
+ engine.reset(new isometric_engine(engine_s, world));
+ break;
+
+ case FatIso:
+ engine.reset(new fatiso_engine(engine_s, world));
+ break;
+ }
+ }
+
+ /**
+ * Setup work-in-progress image to required type depending on predicted memory
+ * use.
+ */
+ {
+ pos_t image_width, image_height;
+ pos_t level_width, level_height;
+
+ engine->get_boundaries(image_width, image_height);
+ engine->get_level_boundaries(level_width, level_height);
+
+ pos_t memory_usage = (image_width * image_height * sizeof(color)) / 0x100000;
+
+ if (memory_usage >= s.memory_limit) {
+ {
+ out << " --- BUILDING SWAP --- " << endl;
+ out << "NOTE: A swap file is being built to accommodate high memory usage" << endl;
+ out << "swap file: " << s.swap_file << endl;
+
+ out << "swap size: " << memory_usage << " MB" << endl;
+ out << "memory limit: " << s.memory_limit << " MB" << endl;
+ }
+
+ cached_image* image;
+
+ try {
+ image = new cached_image(s.swap_file, image_width, image_height, level_width, level_height);
+ } catch(std::ios::failure& e) {
+ if (errno != 0) {
+ error << s.swap_file << ": " << strerror(errno);
+ } else {
+ error << s.swap_file << ": " << e.what() << ": could not open file";
+ }
+
+ return false;
+ }
+
+ work_in_progress.reset(image);
+
+ nonstd::limited<streampos> c(out, 1024 * 1024, image->get_size(), dot, mb_endl);
+
+ try {
+ image->build(c);
+ } catch(std::ios::failure& e) {
+ if (errno != 0) {
+ error << s.swap_file << ": could not build cache: " << strerror(errno);
+ } else {
+ error << s.swap_file << ": could not build cache: " << e.what();
+ }
+
+ return false;
+ }
+ } else {
+ {
+ out << " --- ALLOCATING MEMORY --- " << endl;
+ out << "memory usage: " << memory_usage << " MB" << endl;
+ out << "memory limit: " << s.memory_limit << " MB" << endl;
+ }
+
+ work_in_progress.reset(new memory_image(image_width, image_height));
+ }
+ }
+
+ /* reset image limits for cropping */
+ engine->reset_image_limits();
+
+ /**
+ * Perform rendering phase where engine takes level information, and produces
+ * image_operations, composite all operations to the work-in-progress image.
+ * Try to distribute work evenly among threads.
+ */
+ {
+ out << " --- RENDERING --- " << endl;
+
+ unsigned int world_size = levels.size();
+
+ int effective_threads = s.threads - 1;
+
+ if (effective_threads <= 1) {
+ effective_threads = 1;
+ }
+
+ int cache_hits = 0;
+ int failed_levels = 0;
+
+ /**
+ * Define a dynamically growing buffer to read regions in.
+ * Is grown on demand, but never shrunk.
+ */
+ mc::dynamic_buffer region_buffer(mc::region::CHUNK_MAX);
+
+ nonstd::limited<unsigned int> reporter(out, 50, world_size, dot, parts_perc_endl);
+
+ uint32_t id = 1;
+
+ BOOST_FOREACH(levels_map::value_type value, levels) {
+ reporter.add(1);
+
+ mc::rotated_level_info rotated_level_info = value.second;
+ mc::level_info_ptr level_info = rotated_level_info.get_level();
+
+ mc::level_ptr level(new mc::level(level_info));
+ fs::path path = level_info->get_path();
+
+ try {
+ level->read(region_buffer);
+ } catch(mc::invalid_file& e) {
+ out_log << path << ": " << e.what() << endl;
+ continue;
+ }
+
+ mc::utils::level_coord coord = rotated_level_info.get_coord();
+
+ image_operations_ptr operations(new image_operations(id++));
+
+ bool cache_hit = false;
+ time_t mod = level->modification_time();
+
+ std::stringstream ss;
+ ss << boost::format("%d.%d.cmap") % coord.get_x() % coord.get_z();
+ std::string basename = ss.str();
+
+ fs::path level_dir = mc::utils::level_dir(s.cache_dir, coord.get_x(), coord.get_z());
+ cache_file cache(level_dir, basename, mod, s.cache_compress);
+
+ if (s.cache_use) {
+ if (cache.exists()) {
+ if (cache.read(operations)) {
+ cache_hit = true;
+ }
+
+ cache.clear();
+ }
+ }
+
+ if (!cache_hit) {
+ engine->render(level, operations);
+ }
+
+ //operations->optimize();
+
+ if (s.cache_use) {
+ // create the necessary directories required when caching
+ cache.create_directories();
+
+ // ignore failure while writing the operations to cache
+ if (!cache.write(operations)) {
+ // on failure, remove the cache file - this will prompt c10t to regenerate it next time
+ cache.clear();
+ }
+ }
+
+ if (s.debug) { out << path_string(path) << ": dequeued OK" << endl; }
+
+ if (cache_hit) {
+ ++cache_hits;
+ }
+
+ //if (p.signs.size() > 0) {
+ //if (s.debug) { out << "Found " << p.signs.size() << " signs"; };
+ //signs.insert(signs.end(), p.signs.begin(), p.signs.end());
+ //}
+
+ try {
+ pos_t x, y;
+ engine->w2pt(coord.get_x(), coord.get_z(), x, y);
+
+ // update image limits
+ engine->update_image_limits(
+ x + 1, y,
+ x + operations->max_x,
+ y + operations->max_y - 1);
+
+ work_in_progress->composite(x, y, operations);
+ } catch(std::ios::failure& e) {
+ out << path_string(s.swap_file) << ": " << strerror(errno);
+ return false;
+ }
+ }
+
+ reporter.done(0);
+
+ if (failed_levels > 0) {
+ out << "SEE LOG: " << failed_levels << " level(s) failed!" << endl;
+ }
+
+ if (s.cache_use) {
+ out << "cache_hits: " << cache_hits << "/" << world_size << endl;
+ }
+
+ out << "image limits: "
+ << engine->get_min_x() << "x" << engine->get_min_y() << " to "
+ << engine->get_max_x() << "x" << engine->get_max_y()
+ << " will be the cropped image ("
+ << (engine->get_max_x() - engine->get_min_x()) << "x"
+ << (engine->get_max_y() - engine->get_min_y())
+ << ")" << endl;
+
+ image_ptr cropped = image::crop(work_in_progress, engine->get_min_x(), engine->get_max_x(), engine->get_min_y(), engine->get_max_y());
+ work_in_progress = cropped;
+ }
+
+ if (use_any_database) {
+ text::font_face font(s.ttf_path, s.ttf_size, s.ttf_color);
+
+ /*
+ * If we are only going to output json information, do not initialize font.
+ * This will prevent any fonts from actually rendering anything later on.
+ */
+ if (!output_json) {
+ try {
+ font.init();
+ } catch(text::text_error& e) {
+ error << "failed to initialize font: " << e.what() << std::endl;
+ }
+ }
+
+ if (s.show_players) {
+ push_player_markers(s, font, players, markers);
+ }
+
+ if (s.show_signs && signs.size() > 0) {
+ push_sign_markers(s, font, signs, markers);
+ }
+
+ if (s.show_coordinates) {
+ push_coordinate_markers(out, s, font, world, levels, markers);
+ }
+
+ if (s.show_warps) {
+ push_warp_markers(s, font, warps, markers);
+ }
+
+ }
+
+ if (output_json) {
+ if (!use_any_database) {
+ hints.push_back("Use `--write-json' in combination with `--show-*'"
+ " in order to write different types of markers to file");
+ }
+
+ write_json_file(out, s, engine, world, markers);
+ }
+ else {
+ overlay_markers(s, work_in_progress, engine, markers);
+ }
+
+ engine_core::pos_t center_x, center_y;
+ engine->wp2pt(0, 0, 0, center_x, center_y);
+
+ if (s.use_split) {
+ out << " --- SAVING MULTIPLE IMAGES --- " << endl;
+
+ int i = 0;
+
+ image_ptr target;
+
+ BOOST_FOREACH(unsigned int split_i, s.split) {
+ if (!target && s.split_base > 0) {
+ target.reset(new memory_image(s.split_base, s.split_base));
+ }
+
+ std::map<point2, image_base*> parts;
+
+ image::split(work_in_progress, split_i, parts);
+
+ out << "Level " << i << ": splitting into " << parts.size()
+ << " image on " << split_i << "px" << endl;
+
+ for (std::map<point2, image_base*>::iterator it = parts.begin(); it != parts.end(); it++) {
+ const point2 p = it->first;
+ image_ptr img(it->second);
+
+ stringstream ss;
+ ss << boost::format(path_string(output_path)) % i % p.x % p.y;
+ fs::path path(ss.str());
+
+ if (!fs::is_directory(path.parent_path())) {
+ fs::create_directories(path.parent_path());
+ }
+
+ png_format::opt_type opts;
+
+ opts.center_x = center_x;
+ opts.center_y = center_y;
+ opts.comment = C10T_COMMENT;
+
+ std::string path_str(path_string(path));
+
+ if (s.split_base > 0) {
+ target->clear();
+ img->resize(target);
+ }
+ else {
+ target = img;
+ }
+
+ try {
+ target->save<png_format>(path_str, opts);
+ } catch (format_exception& e) {
+ out << path_string(path) << ": " << e.what() << endl;
+ continue;
+ }
+
+ out << path_string(path) << ": OK" << endl;
+ }
+
+ ++i;
+ }
+ }
+ else {
+ {
+ out << " --- SAVING IMAGE --- " << endl;
+ out << "path: " << path_string(output_path) << endl;
+ }
+
+ png_format::opt_type opts;
+
+ opts.center_x = center_x;
+ opts.center_y = center_y;
+ opts.comment = C10T_COMMENT;
+
+ try {
+ work_in_progress->save<png_format>(path_string(output_path), opts);
+ } catch (format_exception& e) {
+ out << path_string(output_path) << ": " << e.what() << endl;
+ return false;
+ }
+
+ out << path_string(output_path) << ": OK" << endl;
+ }
+
+ return true;
+}
View
20 src/generate_map.hpp
@@ -0,0 +1,20 @@
+#ifndef __GENERATE_MAP_HPP__
+#define __GENERATE_MAP_HPP__
+
+#include <ostream>
+#include <vector>
+#include <string>
+#include <boost/filesystem.hpp>
+
+#include "settings_t.hpp"
+
+bool generate_map(
+ std::ostream& out,
+ std::ostream& out_log,
+ std::ostream& error,
+ settings_t &s,
+ std::vector<std::string>& hints,
+ boost::filesystem::path& world_path,
+ boost::filesystem::path& output_path);
+
+#endif /*__GENERATE_MAP_HPP__*/
View
200 src/generate_statistics.cpp
@@ -0,0 +1,200 @@
+#include "altitude_graph.hpp"
+
+#include "generate_statistics.hpp"
+
+#include "mc/blocks.hpp"
+#include "mc/region_iterator.hpp"
+#include "mc/level_info.hpp"
+#include "mc/level.hpp"
+
+#include "players.hpp"
+
+#include <iomanip>
+
+#include <boost/foreach.hpp>
+
+using namespace std;
+
+template<typename T>
+void dot(std::ostream& out, T total)
+{
+ if (total == 0x00) {
+ out << " done!";
+ }
+ else {
+ out << "." << std::flush;
+ }
+}
+
+void uint_endl(std::ostream& out, unsigned int total)
+{
+ out << " " << setw(8) << total << " parts" << endl;
+}
+
+bool generate_statistics(
+ std::ostream& out,
+ std::ostream& out_log,
+ std::ostream& error,
+ settings_t &s,
+ std::vector<std::string>& hints,
+ fs::path& world_path,
+ fs::path& output_path)
+{
+ out << endl << "Generating Statistics File" << endl << endl;
+ std::vector<player> players;
+ mc::world world(world_path);
+
+ AltitudeGraph *_stat = new AltitudeGraph(s);
+ long statistics[mc::MaterialCount];
+
+ for (int i = 0; i < mc::MaterialCount; i++) {
+ statistics[i] = 0;
+ }
+
+ bool any_db =
+ s.show_players
+ || s.show_signs
+ || s.show_coordinates
+ || s.show_warps;
+
+ if (any_db) {
+ out << " --- LOOKING FOR DATABASES --- " << endl;
+
+ if (s.show_players) {
+ error << "loading of players in altitiude graph has been disabled" << endl;
+ }
+ //if (s.show_players) {
+ //load_players(out, world_path / "players", players, s.show_players_set);
+ //}
+ }
+
+ int failed_regions = 0;
+ int filtered_levels = 0;
+ int failed_levels = 0;
+ int levels = 0;
+
+ {
+ nonstd::continious<unsigned int> reporter(out, 100, dot, uint_endl);
+ mc::region_iterator iterator = world.get_iterator();
+
+ mc::dynamic_buffer region_buffer(mc::region::CHUNK_MAX);
+
+ while (iterator.has_next()) {
+ mc::region_ptr region = iterator.next();
+
+ try {
+ region->read_header();
+ } catch(mc::bad_region& e) {
+ ++failed_regions;
+ out_log << region->get_path() << ": could not read header" << std::endl;
+ continue;
+ }
+
+ std::list<mc::utils::level_coord> coords;
+
+ region->read_coords(coords);
+
+ BOOST_FOREACH(mc::utils::level_coord c, coords) {
+ mc::level_info::level_info_ptr level(new mc::level_info(region, c));
+
+ mc::utils::level_coord coord = level->get_coord();
+ ++levels;
+
+ if (s.coord_out_of_range(coord)) {
+ ++filtered_levels;
+ out_log << level->get_path() << ": (z,x) position"
+ << " (" << coord.get_z() << "," << coord.get_x() << ")"
+ << " out of limit" << std::endl;
+ continue;
+ }
+
+ mc::level level_data(level);
+
+ world.update(level->get_coord());
+
+ try {
+ level_data.read(region_buffer);
+ } catch(mc::invalid_file& e) {
+ ++failed_levels;
+ out_log << level->get_path() << ": " << e.what();
+ continue;
+ }
+
+ /*
+ boost::shared_ptr<nbt::ByteArray> blocks = level_data.get_blocks();
+
+ for (int i = 0; i < blocks->length; i++) {
+ nbt::Byte block = blocks->values[i];
+ statistics[block] += 1;
+ if(s.graph_block > 0 && blocks->values[i] == s.graph_block)
+ {
+ // altitude is calculated as i % mc::MapY... Kind of messy, but...
+ _stat->registerBloc(blocks->values[i], i % mc::MapY);
+ }
+ }
+ */
+
+ reporter.add(1);
+ }
+ }
+
+ reporter.done(0);
+
+ if (failed_regions > 0)
+ {
+ out << "SEE LOG: " << failed_regions << " region(s) failed!" << endl;
+ }
+
+ if (filtered_levels > 0)
+ {
+ out << "SEE LOG: " << filtered_levels << " level(s) filtered!" << endl;
+ }
+
+ if (failed_levels > 0)
+ {
+ out << "SEE LOG: " << failed_levels << " level(s) failed!" << endl;
+ }
+ }
+
+ ofstream stats(path_string(output_path).c_str());
+
+ stats << "[WORLD]" << endl;
+
+ stats << "min_x " << world.min_x << endl;
+ stats << "max_x " << world.max_x << endl;
+ stats << "min_z " << world.min_z << endl;
+ stats << "max_z " << world.max_z << endl;
+ stats << "chunks " << (levels-filtered_levels-failed_levels)
+ << " of " << levels << endl;
+
+ if (s.show_players) {
+ stats << "[PLAYERS]" << endl;
+
+ std::vector<player>::iterator plit = players.begin();
+
+ for (; plit != players.end(); plit++) {
+ player p = *plit;
+ stats << p.name << " " << p.xPos << " " << p.yPos << " " << p.zPos << endl;
+ }
+ }
+
+ stats << "[BLOCKS]" << endl;
+
+ for (int i = 0; i < mc::MaterialCount; i++) {
+ stats << setw(3) << i << " " << setw(24) << mc::MaterialName[i] << " " << statistics[i] << endl;
+ }
+
+ stats.close();
+
+ if (stats.fail()) {
+ error << "failed to write statistics to " << output_path;
+ return false;
+ }
+
+ out << "statistics written to " << output_path;
+
+ if(s.graph_block > 0)
+ _stat->createGraph();
+
+ return true;
+}
View
20 src/generate_statistics.hpp
@@ -0,0 +1,20 @@
+#ifndef __GENERATE_STATISTICS_HPP__
+#define __GENERATE_STATISTICS_HPP__
+
+#include <ostream>
+#include <vector>
+#include <string>
+#include <boost/filesystem.hpp>
+
+#include "settings_t.hpp"
+
+bool generate_statistics(
+ std::ostream& out,
+ std::ostream& out_log,
+ std::ostream& error,
+ settings_t &s,
+ std::vector<std::string>& hints,
+ boost::filesystem::path& world_path,
+ boost::filesystem::path& output_path);
+
+#endif /*__GENERATE_STATISTICS_HPP__*/
View
193 src/global.hpp
@@ -1,193 +0,0 @@
-// Distributed under the BSD License, see accompanying LICENSE.txt
-// (C) Copyright 2010 John-John Tedro et al.
-#ifndef GUARD_H
-#define GUARD_H
-
-#if !defined(C10T_DISABLE_THREADS)
-# include <boost/thread.hpp>
-#endif
-
-#include <boost/filesystem.hpp>
-#include <boost/shared_array.hpp>
-
-#include <string>
-#include <set>
-
-#include "mc/blocks.hpp"
-#include "image/color.hpp"
-
-namespace fs = boost::filesystem;
-
-enum mode {
- Top = 0x0,
- Oblique = 0x1,
- ObliqueAngle = 0x2,
- Isometric = 0x3,
- FatIso = 0x4
-};
-
-enum action {
- None,
- Version,
- Help,
- GenerateWorld,
- GenerateStatistics,
- ListColors,
- WritePalette
-};
-
-struct settings_t {
- bool binary;
- bool cache_compress;
- bool cache_use;
- bool cavemode;
- bool debug;
- bool has_coordinate_color;
- bool has_player_color;
- bool has_sign_color;
- bool has_warp_color;
- bool heightmap;
- bool hellmode;
- bool memory_limit_default;
- bool night;
- bool nocheck;
- bool no_log;
- bool pedantic_broad_phase;
- bool require_all;
- bool show_coordinates;
- bool show_players;
- bool show_signs;
- bool show_warps;
- bool silent;
- bool strip_sign_prefix;
- bool striped_terrain;
- bool use_split;
- bool write_js;
- bool write_json;
- boost::shared_array<bool> excludes;
- color coordinate_color;
- color player_color;
- color sign_color;
- color ttf_color;
- color warp_color;
- enum mode mode;
- fs::path cache_dir;
- fs::path output_log;
- fs::path output_path;
- fs::path palette_read_path;
- fs::path palette_write_path;
- fs::path show_warps_path;
- fs::path statistics_path;
- fs::path swap_file;
- fs::path ttf_path;
- fs::path world_path;
- fs::path write_json_path;
- fs::path write_js_path;
- fs::path engine_path;
- bool engine_use;
- int bottom;
- uint64_t max_radius;
- int64_t min_x;
- int64_t max_x;
- int64_t min_z;
- int64_t max_z;
- int top;
- int ttf_size;
- size_t memory_limit;
- std::list<unsigned int> split;
- std::set<std::string> show_players_set;
- std::string cache_key;
- std::string show_signs_filter;
- // top/bottom used for slicing
- unsigned int prebuffer;
- unsigned int rotation;
- unsigned int split_base;
- unsigned int threads;
-
- int graph_block;
-
- int center_x;
- int center_z;
-
- enum action action;
-
- settings_t() {
- this->excludes.reset(new bool[mc::MaterialCount]);
-
- for (int i = 0; i < mc::MaterialCount; i++) {
- this->excludes[i] = false;
- }
-
- this->excludes[mc::Air] = true;
-
-# if !defined(C10T_DISABLE_THREADS)
- if ((this->threads = boost::thread::hardware_concurrency()) == 0) {
- this->threads = 1;
- }
-# else
- this->threads = 1;
-# endif
- this->prebuffer = 4;
-
- this->split_base = 0;
- this->use_split = false;
- this->cavemode = false;
- this->hellmode = false;
- this->top = 127;
- this->bottom = 0;
- this->mode = Top;
- this->nocheck = false;
- this->silent = false;
- this->show_players = false;
- this->show_coordinates = false;
- this->show_signs = false;
- this->strip_sign_prefix = false;
- this->show_warps = false;
- this->require_all = false;
- this->striped_terrain = false;
- this->rotation = 0;
- this->binary = false;
- this->night = false;
- this->heightmap = false;
- this->debug = false;
- this->swap_file = "swap.bin";
- this->memory_limit = 1000;
- this->memory_limit_default = true;
- this->min_x = -10000;
- this->max_x = 10000;
- this->min_z = -10000;
- this->max_z = 10000;
- this->max_radius = 1000;
- this->ttf_path = fs::path("font.ttf");
- this->ttf_size = 12;
- this->ttf_color = color(0, 0, 0, 0xff);
- this->sign_color = color(0, 0, 0, 0xff);
- this->player_color = color(0, 0, 0, 0xff);
- this->has_player_color = false;
- this->has_sign_color = false;
- this->has_coordinate_color = false;
- this->has_warp_color = false;
- this->coordinate_color = color(0, 0, 0, 0xff);
- this->warp_color = color(0, 0, 0, 0xff);
- this->pedantic_broad_phase = false;
- this->cache_use = false;
- this->cache_key = "";
- this->cache_dir = "cache";
- this->cache_compress = false;
- this->write_json = false;
- this->write_js = false;
- this->no_log = false;
- this->output_log = fs::system_complete(fs::path("c10t.log"));
- this->output_path = fs::system_complete(fs::path("out.png"));
- this->statistics_path = fs::system_complete(fs::path("statistics.txt"));
- this->graph_block = -1;
- this->action = None;
-
- this->center_x = 0;
- this->center_z = 0;
-
- this->engine_use = false;
- }
-};
-
-#endif
View
24 src/image/cached_image.cpp
@@ -8,20 +8,34 @@
cached_image::cached_image(const fs::path path, pos_t w, pos_t h, pos_t l_w, pos_t l_h) :
image_base(w, h),
path(path),
- buffer_s((l_w + 1) * l_h),
+ buffer_size((l_w + 1) * l_h),
buffer_set(false),
- buffer(new color[buffer_s])
+ buffer(new color[buffer_size]),
+ buffer_w(0),
+ buffer_h(0),
+ buffer_x(0),
+ buffer_y(0)
{
using namespace ::std;
fs.exceptions(ios::failbit | ios::badbit);
fs.open(path.string().c_str(), ios::in | ios::out | ios::trunc);
+
+ this->size =
+ boost::numeric_cast<streampos>(get_width()) *
+ boost::numeric_cast<streampos>(get_height()) *
+ sizeof(color);
}
cached_image::~cached_image() {
flush_buffer();
fs.close();
}
+std::streampos cached_image::get_size()
+{
+ return size;
+}
+
// cached_image
void cached_image::set_pixel(pos_t x, pos_t y, color& c)
{
@@ -87,7 +101,7 @@ void cached_image::blend_pixel(pos_t x, pos_t y, color &c)
pos_t by = y - buffer_y;
pos_t bp = bx + by * buffer_w;
- if (x >= buffer_x && y >= buffer_y && bp < buffer_s) {
+ if (x >= buffer_x && y >= buffer_y && bp < buffer_size) {
buffer[bp].blend(c);
} else {
// Blend pixels that are "out of (the buffer's) scope"
@@ -104,9 +118,9 @@ void cached_image::align(pos_t x, pos_t y, pos_t w, pos_t h)
flush_buffer();
// reallocate buffer when the current buffer is too small
- if (buffer_s < w * h) {
+ if (buffer_size < w * h) {
buffer.reset(new color[w * h]);
- buffer_s = w * h;
+ buffer_size = w * h;
}
buffer_x = x, buffer_y = y;
View
46 src/image/cached_image.hpp
@@ -18,22 +18,6 @@
namespace fs = boost::filesystem;
class cached_image : public image_base {
-private:
- const fs::path path;
- std::fstream fs;
-
- pos_t l_total;
- pos_t buffer_s;
- bool buffer_set;
- boost::scoped_array<color> buffer;
-
- pos_t buffer_w;
- pos_t buffer_h;
- pos_t buffer_x;
- pos_t buffer_y;
-
- void read_buffer();
- void flush_buffer();
public:
static const pos_t WRITE_SIZE = 4096 * 8;
@@ -51,22 +35,15 @@ class cached_image : public image_base {
{
using namespace ::std;
- streampos total =
- boost::numeric_cast<streampos>(get_width()) *
- boost::numeric_cast<streampos>(get_height()) *
- sizeof(color);
-
streampos written = 0;
streampos write_size = WRITE_SIZE;
boost::scoped_array<char> nil(new char[write_size]);
::memset(nil.get(), 0x0, write_size);
- reporter.set_limit(total);
-
- while (written < total) {
- streampos write = min(total, write_size);
+ while (written < size) {
+ streampos write = min(size, write_size);
fs.write(nil.get(), write);
written += write;
@@ -75,6 +52,8 @@ class cached_image : public image_base {
reporter.done(0);
}
+
+ std::streampos get_size();
void set_pixel(pos_t x, pos_t y, color&);
void get_pixel(pos_t x, pos_t y, color&);
@@ -113,6 +92,23 @@ class cached_image : public image_base {
* Align whatever caching mechanism might be used to only expect blend requests for these areas.
**/
void align(pos_t x, pos_t y, pos_t w, pos_t h);
+private:
+ const fs::path path;
+ std::fstream fs;
+
+ pos_t buffer_size;
+ bool buffer_set;
+ boost::scoped_array<color> buffer;
+
+ std::streampos size;
+
+ pos_t buffer_w;
+ pos_t buffer_h;
+ pos_t buffer_x;
+ pos_t buffer_y;
+
+ void read_buffer();
+ void flush_buffer();
};
#endif /* CACHED_IMAGE */
View
8 src/image/image_base.cpp
@@ -1,6 +1,6 @@
// Distributed under the BSD License, see accompanying LICENSE.txt
// (C) Copyright 2010 John-John Tedro et al.
-#include "image/image_base.hpp"
+#include "image_base.hpp"
#include <cstring>
@@ -37,7 +37,7 @@ void image_base::composite(int x, int y, image_operations_ptr opers)
}
}
-void image_base::drawLine(pos_t x1, pos_t y1, pos_t x2, pos_t y2, color &c)
+void image_base::draw_line(pos_t x1, pos_t y1, pos_t x2, pos_t y2, color &c)
{
int sx, sy;
int dx = abs(x2-x1);
@@ -65,8 +65,8 @@ void image_base::drawLine(pos_t x1, pos_t y1, pos_t x2, pos_t y2, color &c)
void image_base::safe_blend_pixel(pos_t x, pos_t y, color &c)
{
- if (x >= w) return;
- if (y >= h) return;
+ if (x >= width) return;
+ if (y >= height) return;
blend_pixel(x, y, c);
}
View
17 src/image/image_base.hpp
@@ -20,11 +20,12 @@ typedef uint64_t pos_t;
class image_base
{
protected:
- pos_t w, h;
+ pos_t width, height;
public:
typedef void (*progress_c)(int , int);
- image_base(pos_t w, pos_t h) : w(w), h(h) {
+ image_base(pos_t width, pos_t height)
+ : width(width), height(height) {
}
virtual ~image_base() {
@@ -34,8 +35,8 @@ class image_base
void clear();
- inline pos_t get_width() { return w; };
- inline pos_t get_height() { return h; };
+ inline pos_t get_width() { return width; };
+ inline pos_t get_height() { return height; };
void composite(int xoffset, int yoffset, image_operations_ptr oper);
@@ -55,16 +56,16 @@ class image_base
T::save(this, str, opts);
}
- void drawLine(pos_t x1, pos_t y1, pos_t x2, pos_t y2, color &c);
+ void draw_line(pos_t x1, pos_t y1, pos_t x2, pos_t y2, color &c);
void resize(image_ptr target);
virtual void blend_pixel(pos_t x, pos_t y, color &c) = 0;
virtual void set_pixel(pos_t x, pos_t y, color& c) = 0;
virtual void get_pixel(pos_t x, pos_t y, color& c) = 0;
- virtual void get_line(pos_t y, pos_t offset, pos_t w, color*) = 0;
- virtual void set_line(pos_t y, pos_t offset, pos_t w, color*) {};
- virtual void align(pos_t x, pos_t y, pos_t w, pos_t h) {};
+ virtual void get_line(pos_t y, pos_t offset, pos_t width, color*) = 0;
+ virtual void set_line(pos_t y, pos_t offset, pos_t width, color*) {};
+ virtual void align(pos_t x, pos_t y, pos_t width, pos_t height) {};
};
#endif /* IMAGE_BASE */
View
1,127 src/main.cpp
@@ -12,56 +12,30 @@
#include <iomanip>
#include <fstream>
-#include <boost/algorithm/string.hpp>
-#include <boost/scoped_ptr.hpp>
-#include <boost/filesystem.hpp>
-#include <boost/format.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/foreach.hpp>
-
#include "config.hpp"
-#include "image/format/png.hpp"
-#include "image/image_base.hpp"
-#include "image/memory_image.hpp"
-#include "image/cached_image.hpp"
-#include "image/algorithms.hpp"
-
-#include "threads/renderer.hpp"
-#include "2d/cube.hpp"
-
-#include "global.hpp"
-#include "cache.hpp"
-#include "fileutils.hpp"
-#include "players.hpp"
-#include "text.hpp"
+#include "nullstream.hpp"
#include "json.hpp"
-#include "altitude_graph.hpp"
-#include "warps.hpp"
+#include "marker.hpp"
-#include "mc/world.hpp"
-#include "mc/blocks.hpp"
-#include "mc/utils.hpp"
-#include "mc/rotated_level_info.hpp"
-#include "mc/level_info.hpp"
-#include "mc/region_iterator.hpp"
+#include "image/memory_image.hpp"
+#include "image/image_base.hpp"
#include "engine/engine_core.hpp"
-#include "engine/topdown_engine.hpp"
-#include "engine/oblique_engine.hpp"
-#include "engine/obliqueangle_engine.hpp"
-#include "engine/isometric_engine.hpp"
-#include "engine/fatiso_engine.hpp"
+
+#include "generate_map.hpp"
+#include "generate_statistics.hpp"
+
+#include <boost/filesystem.hpp>
+#include <boost/format.hpp>
#include "main_utils.hpp"
-#include "dlopen.hpp"
using namespace std;
+
namespace fs = boost::filesystem;
-struct nullstream: std::ostream {
- nullstream(): std::ios(0), std::ostream(0) {}
-};
+typedef uint64_t pos_t;
const uint8_t ERROR_BYTE = 0x01;
const uint8_t RENDER_BYTE = 0x10;
@@ -70,18 +44,6 @@ const uint8_t IMAGE_BYTE = 0x30;
const uint8_t PARSE_BYTE = 0x40;
const uint8_t END_BYTE = 0xF0;
-struct marker {
-public:
- std::string text;
- std::string type;
- text::font_face font;
- int x, y, z;
-
- marker(std::string text, std::string type, text::font_face font, int x, int y, int z) :
- text(text), type(type), font(font), x(x), y(y), z(z)
- { }
-};
-
inline void cout_error(const string& message) {
cout << hex << std::setw(2) << setfill('0') << static_cast<int>(ERROR_BYTE)
<< hex << message << flush;
@@ -91,1065 +53,6 @@ inline void cout_end() {
cout << hex << std::setw(2) << setfill('0') << static_cast<int>(END_BYTE) << flush;
}
-/*
- * Store part of a level rendered as a small image.
- *
- * This will allow us to composite the entire image later and calculate sizes then.
- */
-
-inline void populate_markers(settings_t& s, json::array* array, boost::shared_ptr<engine_core> engine, boost::ptr_vector<marker>& markers) {
- boost::ptr_vector<marker>::iterator it;
-
- for (it = markers.begin(); it != markers.end(); it++) {
- marker m = *it;
-
- mc::utils::level_coord coord = mc::utils::level_coord(m.x, m.z).rotate(s.rotation);
-
- pos_t x, y;
-
- engine->wp2pt(coord.get_x(), m.y, coord.get_z(), x, y);
-
- json::object* o = new json::object;
-
- o->put("text", new json::string(m.text));
- o->put("type", new json::string(m.type));
-
- // the projected coordinates
- o->put("x", new json::number(x));
- o->put("y", new json::number(y));
-
- // the real coordinates
- o->put("X", new json::number(m.x));
- o->put("Y", new json::number(m.y));
- o->put("Z", new json::number(m.z));
-
- array->push(o);
- }
- // don't bother to check for errors right now, but could be done using the "fail" accessor.
-}
-
-inline void overlay_markers(
- settings_t& s,
- image_ptr work_in_progress,
- boost::shared_ptr<engine_core> engine,
- boost::ptr_vector<marker>& markers
- )
-{
- memory_image positionmark(5, 5);
- positionmark.fill(s.ttf_color);
-
- boost::ptr_vector<marker>::iterator it;
-
- for (it = markers.begin(); it != markers.end(); it++) {
- marker m = *it;
-
- if (!m.font.is_initialized()) {
- continue;
- }
-
- mc::utils::level_coord coord = mc::utils::level_coord(m.x, m.z).rotate(s.rotation);
-
- pos_t x, y;
-
- engine->wp2pt(coord.get_x(), m.y, coord.get_z(), x, y);
-
- m.font.draw(work_in_progress, m.text, x + 5, y);
- //all->safe_composite(x - 3, y - 3, positionmark);
- }
-}
-
-bool coord_out_of_range(settings_t& s, mc::utils::level_coord& coord)
-{
- int x = coord.get_x() - s.center_x;
- int z = coord.get_z() - s.center_z;
-
- uint64_t x2 = uint64_t(x) * uint64_t(x);
- uint64_t z2 = uint64_t(z) * uint64_t(z);
- uint64_t r2 = s.max_radius * s.max_radius;
-
- return x < s.min_x
- || x > s.max_x
- || z < s.min_z
- || z > s.max_z
- || (x2 + z2) > r2+1;
-}
-
-template<typename T>
-void out_dot(ostream& out, T total) {
- if ( (unsigned int) total == 0) out << " done!";
- else out << "." << flush;
-}
-
-void cout_uint_endl(ostream& out, unsigned int total) {
- out << " " << setw(8) << total << " parts" << endl;
-}
-
-void cout_uintpart_endl(ostream& out, unsigned int progress, unsigned int total) {
- out << " " << setw(8) << progress << " parts " << (progress * 100) / total << "%" << endl;
-}
-
-void cout_mb_endl(ostream& out, streampos progress, streampos total) {
- out << " " << setw(8) << fixed << float(progress) / 1000000 << " MB " << (progress * 100) / total << "%" << endl;
-}
-
-/**
- * Helper blocks
- */
-
-/**
- * Load all warps from a database and push them to a container.
- */
-template<typename T>
-inline void load_warps(ostream& out, fs::path warps_path, T& warps)
-{
- out << "warps: " << warps_path << ": " << flush;
-
- warps_db wdb(warps_path);
-
- try {
- wdb.read(warps);
- out << warps.size() << " warp(s) OK" << endl;
- } catch(warps_db_exception& e) {
- out << e.what() << endl;
- }
-}
-
-/**
- * Load all players from a database and push them to a container.
- */
-template<typename T, typename S>
-inline void load_players(ostream& out, fs::path show_players_path, T& players, S& player_set)
-{
- out << "players: " << show_players_path << ": " << flush;
-
- players_db pdb(show_players_path, player_set);
-
- std::vector<player> all_players;
-
- try {
- pdb.read(all_players);
- } catch(players_db_exception& e) {
- out << " " << e.what() << endl;
- return;
- }
-
- out << all_players.size() << " player(s) found" << endl;
-
- BOOST_FOREACH(player p, all_players) {
- if (p.error) {
- out << " " << p.path << ":" << p.error_where << ": " << p.error_why << endl;
- continue;
- }
-
- players.push_back(p);
- }
-
- out << " " << players.size() << " player(s) OK" << endl;
-}
-
-/**
- * Push all players to a standard type of marker.
- */
-template<typename P, typename T>
-inline void push_player_markers(settings_t& s, text::font_face base_font, P& players, T& markers)
-{
- text::font_face player_font = base_font;
-
- if (s.has_player_color) {
- player_font.set_color(s.player_color);
- }
-
- BOOST_FOREACH(player p, players) {
- if (p.zPos / mc::MapZ < s.min_z) continue;
- if (p.zPos / mc::MapZ > s.max_z) continue;
- if (p.xPos / mc::MapX < s.min_x) continue;
- if (p.xPos / mc::MapX > s.max_x) continue;
-
- markers.push_back(new marker(p.name, "player", player_font, p.xPos, p.yPos, p.zPos));
- }
-}
-
-/**
- * Push all signs to a standard type of marker.
- */
-template<typename S, typename T>
-inline void push_sign_markers(settings_t& s, text::font_face base_font, S& signs, T& markers)
-{
- text::font_face sign_font = base_font;
-
- if (s.has_sign_color) {
- sign_font.set_color(s.sign_color);
- }
-
- BOOST_FOREACH(mc::marker lm, signs) {
- if (!s.show_signs_filter.empty() && lm.get_text().find(s.show_signs_filter) == string::npos) {
- continue;
- }
-
- if (!s.strip_sign_prefix) {
- markers.push_back(new marker(lm.get_text(), "sign", sign_font,
- lm.get_x(), lm.get_y(), lm.get_z()));
- } else {
- std::string text = lm.get_text().substr(s.show_signs_filter.size());
- markers.push_back(new marker(text, "sign", sign_font,
- lm.get_x(), lm.get_y(), lm.get_z()));
- }
- }
-}
-
-typedef std::map<mc::utils::level_coord, mc::rotated_level_info> levels_map;
-
-/**
- * Push all coordinates to a standard type of marker.
- */
-template<typename L, typename T>
-inline void push_coordinate_markers(
- ostream& out,
- settings_t& s,
- text::font_face base_font,
- mc::world& world,
- L& levels,
- T& markers)
-{
- text::font_face coordinate_font = base_font;
-
- if (s.has_coordinate_color) {
- coordinate_font.set_color(s.coordinate_color);
- }
-
- BOOST_FOREACH(levels_map::value_type value, levels)
- {
- mc::utils::level_coord c = value.second.get_coord();
- boost::shared_ptr<mc::level_info> l = value.second.get_level();
-
- if (c.get_z() - 4 < world.min_z) continue;
- if (c.get_z() + 4 > world.max_z) continue;
- if (c.get_x() - 4 < world.min_x) continue;
- if (c.get_x() + 4 > world.max_x) continue;
- if (c.get_z() % 10 != 0) continue;
- if (c.get_x() % 10 != 0) continue;
- std::stringstream ss;
-
- ss << "(" << l->get_x() * mc::MapX << ", " << l->get_z() * mc::MapZ << ")";
- if (s.debug) {
- out << "Pushing coordinate info " << ss.str() << endl;
- }
- markers.push_back(new marker(ss.str(), "coord", coordinate_font, c.get_x() * mc::MapX, 0, c.get_z() * mc::MapZ));
- }
-}
-
-/**
- * Push all warps to a standard type of marker.
- */
-template<typename W, typename T>
-inline void push_warp_markers(settings_t& s, text::font_face base_font, W& warps, T& markers)
-{
- text::font_face warp_font = base_font;
-
- if (s.has_warp_color) {
- warp_font.set_color(s.warp_color);
- }
-
- /* initial code for projecting warps */
- BOOST_FOREACH(warp w, warps) {
- if (w.zPos / mc::MapZ < s.min_z) continue;
- if (w.zPos / mc::MapZ > s.max_z) continue;
- if (w.xPos / mc::MapX < s.min_x) continue;
- if (w.xPos / mc::MapX > s.max_x) continue;
-
- marker *m = new marker(w.name, "warp", warp_font, w.xPos, w.yPos, w.zPos);
- markers.push_back(m);
- }
-}
-
-template<typename M>
-void write_json_file(
- ostream& out,
- settings_t& s,
- boost::shared_ptr<engine_core> engine,
- mc::world& world,
- M& markers)
-{
- // calculate world center
- engine_core::pos_t center_x, center_y;
- mc::utils::level_coord coord =
- mc::utils::level_coord(s.center_x*16, s.center_z*16).rotate(s.rotation);
-
- engine->wp2pt(coord.get_x(), 0, coord.get_z(), center_x, center_y);
-
- json::object file;
- json::object* json_static = new json::object;
-
- json_static->put("MapX", new json::number(mc::MapX));
- json_static->put("MapY", new json::number(mc::MapY));
- json_static->put("MapZ", new json::number(mc::MapZ));
-
- file.put("st", json_static);
-
- json::object* json_world = new json::object;
-
- json_world->put("cx", new json::number(center_x));
- json_world->put("cy", new json::number(center_y));
- json_world->put("dx", new json::number((world.diff_x + 1) * mc::MapX));
- json_world->put("dz", new json::number((world.diff_z + 1) * mc::MapZ));
- json_world->put("dy", new json::number(mc::MapY));
- json_world->put("mn_x", new json::number(world.min_x * 16));
- json_world->put("mn_z", new json::number(world.min_z * 16));
- json_world->put("mx_x", new json::number(world.max_x * 16));
- json_world->put("mx_z", new json::number(world.max_z * 16));
- json_world->put("rot", new json::number(s.rotation));
- json_world->put("mode", new json::number(s.mode));
- json_world->put("split_base", new json::number(s.split_base));
- json_world->put("split", new json::number(s.split.size()));
-
- file.put("world", json_world);
-
- json::array* markers_array = new json::array;
- populate_markers(s, markers_array, engine, markers);
- file.put("markers", markers_array);
-
- if (s.write_json) {
- out << "Writing json information: " << path_string(s.write_json_path) << endl;
- std::ofstream of(path_string(s.write_json_path).c_str());
- of << file;
- of.close();
- }
-
- if (s.write_js) {
- out << "Writing js (javascript `var c10t_json') information: " << path_string(s.write_js_path) << endl;
- std::ofstream of(path_string(s.write_js_path).c_str());
- of << "var c10t_json = " << file << ";";
- of.close();
- }
-}
-
-/**
- * Generate a map
- *
- * This is one of the main methods, it does the following steps.
- *
- * - Look for specificed databases.
- * - Scan the world for regions containing levels.
- * - Depending on settings, choose which rendering engine to use.
- * - Setup work-in-progress image to required type depending on predicted memory
- * use.
- * - Perform rendering phase where engine takes level information, and produces
- * image_operations, composite all operations to the work-in-progress image.
- * Try to distribute work evenly among threads.
- *
- */
-bool generate_map(
- ostream& out,
- ostream& out_log,
- settings_t &s,
- fs::path& world_path,
- fs::path& output_path)
-{
- out << endl << "Generating PNG Map" << endl << endl;
-
- // all marker source information.
- std::vector<player> players;
- std::vector<warp> warps;
- std::vector<mc::marker> signs;
-
- // this is where the actual markers will be populated later.
- boost::ptr_vector<marker> markers;
-
- // symbolic definition of a world.
- mc::world world(world_path);
-
- // where to store level info
- levels_map levels;
-
- // this is the rendering engine that will be used.
- boost::shared_ptr<engine_core> engine;
-
- // image to work against, could be backed by hard drive, or purely in memory.
- image_ptr work_in_progress;
-
- /**
- * Any of these options will trigger the database blocks to run.
- */
- bool use_any_database =
- s.show_players
- || s.show_signs
- || s.show_coordinates
- || s.show_warps;
-
- bool output_json =
- s.write_json || s.write_js;
-
- /*
- * Look for specificed databases.
- */
- if (use_any_database)
- {
- out << " --- LOOKING FOR DATABASES --- " << endl;
-
- if (s.show_warps) {
- load_warps(out, s.show_warps_path, warps);
- }
-
- if (s.show_players) {
- load_players(out, world_path / "players", players, s.show_players_set);
- }
-
- if (s.show_signs) {
- out << "will look for signs in levels" << endl;
- }
-
- if (s.show_coordinates) {
- out << "will store chunk coordinates" << endl;
- }