+/* Profiler display */
+
+void update_profiler_gui(gui::IGUIStaticText *guitext_profiler,
+ gui::IGUIFont *font, u32 text_height,
+ u32 show_profiler, u32 show_profiler_max)
+{
+ if(show_profiler == 0)
+ {
+ guitext_profiler->setVisible(false);
+ }
+ else
+ {
+
+ std::ostringstream os(std::ios_base::binary);
+ g_profiler->printPage(os, show_profiler, show_profiler_max);
+ std::wstring text = narrow_to_wide(os.str());
+ guitext_profiler->setText(text.c_str());
+ guitext_profiler->setVisible(true);
+
+ s32 w = font->getDimension(text.c_str()).Width;
+ if(w < 400)
+ w = 400;
+ core::rect<s32> rect(6, 4+(text_height+5)*2, 12+w,
+ 8+(text_height+5)*2 +
+ font->getDimension(text.c_str()).Height);
+ guitext_profiler->setRelativePosition(rect);
+ guitext_profiler->setVisible(true);
+ }
+}
+
+class ProfilerGraph
+{
+private:
+ struct Piece{
+ Profiler::GraphValues values;
+ };
+ struct Meta{
+ float min;
+ float max;
+ video::SColor color;
+ Meta(float initial=0, video::SColor color=
+ video::SColor(255,255,255,255)):
+ min(initial),
+ max(initial),
+ color(color)
+ {}
+ };
+ std::list<Piece> m_log;
+public:
+ u32 m_log_max_size;
+
+ ProfilerGraph():
+ m_log_max_size(200)
+ {}
+
+ void put(const Profiler::GraphValues &values)
+ {
+ Piece piece;
+ piece.values = values;
+ m_log.push_back(piece);
+ while(m_log.size() > m_log_max_size)
+ m_log.erase(m_log.begin());
+ }
+
+ void draw(s32 x_left, s32 y_bottom, video::IVideoDriver *driver,
+ gui::IGUIFont* font) const
+ {
+ std::map<std::string, Meta> m_meta;
+ for(std::list<Piece>::const_iterator k = m_log.begin();
+ k != m_log.end(); k++)
+ {
+ const Piece &piece = *k;
+ for(Profiler::GraphValues::const_iterator i = piece.values.begin();
+ i != piece.values.end(); i++){
+ const std::string &id = i->first;
+ const float &value = i->second;
+ std::map<std::string, Meta>::iterator j =
+ m_meta.find(id);
+ if(j == m_meta.end()){
+ m_meta[id] = Meta(value);
+ continue;
+ }
+ if(value < j->second.min)
+ j->second.min = value;
+ if(value > j->second.max)
+ j->second.max = value;
+ }
+ }
+
+ // Assign colors
+ static const video::SColor usable_colors[] = {
+ video::SColor(255,255,100,100),
+ video::SColor(255,90,225,90),
+ video::SColor(255,100,100,255),
+ video::SColor(255,255,150,50),
+ video::SColor(255,220,220,100)
+ };
+ static const u32 usable_colors_count =
+ sizeof(usable_colors) / sizeof(*usable_colors);
+ u32 next_color_i = 0;
+ for(std::map<std::string, Meta>::iterator i = m_meta.begin();
+ i != m_meta.end(); i++){
+ Meta &meta = i->second;
+ video::SColor color(255,200,200,200);
+ if(next_color_i < usable_colors_count)
+ color = usable_colors[next_color_i++];
+ meta.color = color;
+ }
+
+ s32 graphh = 50;
+ s32 textx = x_left + m_log_max_size + 15;
+ s32 textx2 = textx + 200 - 15;
+
+ // Draw background
+ /*{
+ u32 num_graphs = m_meta.size();
+ core::rect<s32> rect(x_left, y_bottom - num_graphs*graphh,
+ textx2, y_bottom);
+ video::SColor bgcolor(120,0,0,0);
+ driver->draw2DRectangle(bgcolor, rect, NULL);
+ }*/
+
+ s32 meta_i = 0;
+ for(std::map<std::string, Meta>::const_iterator i = m_meta.begin();
+ i != m_meta.end(); i++){
+ const std::string &id = i->first;
+ const Meta &meta = i->second;
+ s32 x = x_left;
+ s32 y = y_bottom - meta_i * 50;
+ float show_min = meta.min;
+ float show_max = meta.max;
+ if(show_min >= -0.0001 && show_max >= -0.0001){
+ if(show_min <= show_max * 0.5)
+ show_min = 0;
+ }
+ s32 texth = 15;
+ char buf[10];
+ snprintf(buf, 10, "%.3g", show_max);
+ font->draw(narrow_to_wide(buf).c_str(),
+ core::rect<s32>(textx, y - graphh,
+ textx2, y - graphh + texth),
+ meta.color);
+ snprintf(buf, 10, "%.3g", show_min);
+ font->draw(narrow_to_wide(buf).c_str(),
+ core::rect<s32>(textx, y - texth,
+ textx2, y),
+ meta.color);
+ font->draw(narrow_to_wide(id).c_str(),
+ core::rect<s32>(textx, y - graphh/2 - texth/2,
+ textx2, y - graphh/2 + texth/2),
+ meta.color);
+ s32 graph1y = y;
+ s32 graph1h = graphh;
+ bool relativegraph = (show_min != 0 && show_min != show_max);
+ float lastscaledvalue = 0.0;
+ bool lastscaledvalue_exists = false;
+ for(std::list<Piece>::const_iterator j = m_log.begin();
+ j != m_log.end(); j++)
+ {
+ const Piece &piece = *j;
+ float value = 0;
+ bool value_exists = false;
+ Profiler::GraphValues::const_iterator k =
+ piece.values.find(id);
+ if(k != piece.values.end()){
+ value = k->second;
+ value_exists = true;
+ }
+ if(!value_exists){
+ x++;
+ lastscaledvalue_exists = false;
+ continue;
+ }
+ float scaledvalue = 1.0;
+ if(show_max != show_min)
+ scaledvalue = (value - show_min) / (show_max - show_min);
+ if(scaledvalue == 1.0 && value == 0){
+ x++;
+ lastscaledvalue_exists = false;
+ continue;
+ }
+ if(relativegraph){
+ if(lastscaledvalue_exists){
+ s32 ivalue1 = lastscaledvalue * graph1h;
+ s32 ivalue2 = scaledvalue * graph1h;
+ driver->draw2DLine(v2s32(x-1, graph1y - ivalue1),
+ v2s32(x, graph1y - ivalue2), meta.color);
+ }
+ lastscaledvalue = scaledvalue;
+ lastscaledvalue_exists = true;
+ } else{
+ s32 ivalue = scaledvalue * graph1h;
+ driver->draw2DLine(v2s32(x, graph1y),
+ v2s32(x, graph1y - ivalue), meta.color);
+ }
+ x++;
+ }
+ meta_i++;
+ }
+ }
+};
+
+class NodeDugEvent: public MtEvent
+{
+public:
+ v3s16 p;
+ MapNode n;
+
+ NodeDugEvent(v3s16 p, MapNode n):
+ p(p),
+ n(n)
+ {}
+ const char* getType() const
+ {return "NodeDug";}
+};
+
+class SoundMaker
+{
+ ISoundManager *m_sound;
+ INodeDefManager *m_ndef;
+public:
+ float m_player_step_timer;
+
+ SimpleSoundSpec m_player_step_sound;
+ SimpleSoundSpec m_player_leftpunch_sound;
+ SimpleSoundSpec m_player_rightpunch_sound;
+
+ SoundMaker(ISoundManager *sound, INodeDefManager *ndef):
+ m_sound(sound),
+ m_ndef(ndef),
+ m_player_step_timer(0)
+ {
+ }
+
+ void playPlayerStep()
+ {
+ if(m_player_step_timer <= 0 && m_player_step_sound.exists()){
+ m_player_step_timer = 0.03;
+ m_sound->playSound(m_player_step_sound, false);
+ }
+ }
+
+ static void viewBobbingStep(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker*)data;
+ sm->playPlayerStep();
+ }
+
+ static void playerRegainGround(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker*)data;
+ sm->playPlayerStep();
+ }
+
+ static void playerJump(MtEvent *e, void *data)
+ {
+ //SoundMaker *sm = (SoundMaker*)data;
+ }
+
+ static void cameraPunchLeft(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker*)data;
+ sm->m_sound->playSound(sm->m_player_leftpunch_sound, false);
+ }
+
+ static void cameraPunchRight(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker*)data;
+ sm->m_sound->playSound(sm->m_player_rightpunch_sound, false);
+ }
+
+ static void nodeDug(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker*)data;
+ NodeDugEvent *nde = (NodeDugEvent*)e;
+ sm->m_sound->playSound(sm->m_ndef->get(nde->n).sound_dug, false);
+ }
+
+ void registerReceiver(MtEventManager *mgr)
+ {
+ mgr->reg("ViewBobbingStep", SoundMaker::viewBobbingStep, this);
+ mgr->reg("PlayerRegainGround", SoundMaker::playerRegainGround, this);
+ mgr->reg("PlayerJump", SoundMaker::playerJump, this);
+ mgr->reg("CameraPunchLeft", SoundMaker::cameraPunchLeft, this);
+ mgr->reg("CameraPunchRight", SoundMaker::cameraPunchRight, this);
+ mgr->reg("NodeDug", SoundMaker::nodeDug, this);
+ }
+
+ void step(float dtime)
+ {
+ m_player_step_timer -= dtime;
+ }
+};
+
+// Locally stored sounds don't need to be preloaded because of this
+class GameOnDemandSoundFetcher: public OnDemandSoundFetcher
+{
+ std::set<std::string> m_fetched;
+public:
+
+ void fetchSounds(const std::string &name,
+ std::set<std::string> &dst_paths,
+ std::set<std::string> &dst_datas)
+ {
+ if(m_fetched.count(name))
+ return;
+ m_fetched.insert(name);
+ std::string base = porting::path_share + DIR_DELIM + "testsounds";
+ dst_paths.insert(base + DIR_DELIM + name + ".ogg");
+ dst_paths.insert(base + DIR_DELIM + name + ".0.ogg");
+ dst_paths.insert(base + DIR_DELIM + name + ".1.ogg");
+ dst_paths.insert(base + DIR_DELIM + name + ".2.ogg");
+ dst_paths.insert(base + DIR_DELIM + name + ".3.ogg");
+ dst_paths.insert(base + DIR_DELIM + name + ".4.ogg");
+ dst_paths.insert(base + DIR_DELIM + name + ".5.ogg");
+ dst_paths.insert(base + DIR_DELIM + name + ".6.ogg");
+ dst_paths.insert(base + DIR_DELIM + name + ".7.ogg");
+ dst_paths.insert(base + DIR_DELIM + name + ".8.ogg");
+ dst_paths.insert(base + DIR_DELIM + name + ".9.ogg");
+ }
+};
+