Try to use progress bar to indicate the encoding progress

Need an updated libopenglrecorder
This commit is contained in:
Benau 2017-04-15 16:30:27 +08:00
parent f3e0d2f9e9
commit 487d007b17
5 changed files with 204 additions and 105 deletions

View File

@ -160,6 +160,9 @@ IrrDriver::IrrDriver()
*/ */
IrrDriver::~IrrDriver() IrrDriver::~IrrDriver()
{ {
#ifdef ENABLE_RECORDER
ogrDestroy();
#endif
assert(m_device != NULL); assert(m_device != NULL);
m_device->drop(); m_device->drop();
m_device = NULL; m_device = NULL;
@ -173,9 +176,6 @@ IrrDriver::~IrrDriver()
#endif #endif
delete m_wind; delete m_wind;
delete m_renderer; delete m_renderer;
#ifdef ENABLE_RECORDER
ogrDestroy();
#endif
} // ~IrrDriver } // ~IrrDriver
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -642,10 +642,6 @@ void IrrDriver::initDevice()
ogrRegGeneralCallback(OGR_CBT_START_RECORDING, ogrRegGeneralCallback(OGR_CBT_START_RECORDING,
[] (void* user_data) { MessageQueue::add [] (void* user_data) { MessageQueue::add
(MessageQueue::MT_GENERIC, _("Video recording started.")); }, NULL); (MessageQueue::MT_GENERIC, _("Video recording started.")); }, NULL);
ogrRegGeneralCallback(OGR_CBT_WAIT_RECORDING,
[] (void* user_data) { MessageQueue::add
(MessageQueue::MT_GENERIC, _("Please wait while encoding is finished."
)); }, NULL);
ogrRegStringCallback(OGR_CBT_ERROR_RECORDING, ogrRegStringCallback(OGR_CBT_ERROR_RECORDING,
[](const char* s, void* user_data) [](const char* s, void* user_data)
{ Log::error("openglrecorder", "%s", s); }, NULL); { Log::error("openglrecorder", "%s", s); }, NULL);
@ -653,22 +649,9 @@ void IrrDriver::initDevice()
[] (const char* s, void* user_data) { MessageQueue::add [] (const char* s, void* user_data) { MessageQueue::add
(MessageQueue::MT_GENERIC, _("Video saved in \"%s\".", s)); (MessageQueue::MT_GENERIC, _("Video saved in \"%s\".", s));
}, NULL); }, NULL);
static std::chrono::high_resolution_clock::time_point tp;
ogrRegIntCallback(OGR_CBT_PROGRESS_RECORDING, ogrRegIntCallback(OGR_CBT_PROGRESS_RECORDING,
[] (const int i, void* user_data) [] (const int i, void* user_data)
{ { MessageQueue::showProgressBar(i, _("Encoding progress:")); }, NULL);
std::chrono::high_resolution_clock::time_point* timer =
(std::chrono::high_resolution_clock::time_point*)user_data;
auto rate = std::chrono::high_resolution_clock::now() -
*timer;
float t = std::chrono::duration_cast<std::chrono::
duration<float> >(rate).count();
if (t > 3.0f)
{
*timer = std::chrono::high_resolution_clock::now();
Log::info("Recorder", "%d%% of video encoding finished", i);
}
}, &tp);
#endif #endif

View File

@ -22,6 +22,7 @@
#include "graphics/irr_driver.hpp" #include "graphics/irr_driver.hpp"
#include "guiengine/engine.hpp" #include "guiengine/engine.hpp"
#include "guiengine/scalable_font.hpp"
#include "guiengine/skin.hpp" #include "guiengine/skin.hpp"
#include "utils/synchronised.hpp" #include "utils/synchronised.hpp"
#include "utils/translation.hpp" #include "utils/translation.hpp"
@ -30,23 +31,66 @@
#include "IGUIEnvironment.h" #include "IGUIEnvironment.h"
#include "IGUIStaticText.h" #include "IGUIStaticText.h"
#include <atomic>
using namespace GUIEngine; using namespace GUIEngine;
namespace MessageQueue namespace MessageQueue
{ {
// ============================================================================ // ============================================================================
/** The area which the message is drawn. */ /** The label widget used to show the current message. */
core::recti g_area; SkinWidgetContainer* g_container = NULL;
// ============================================================================ // ============================================================================
/** A small helper class to store and sort messages to be displayed. */ /** A base class for any messages. */
class Message class Message
{ {
protected:
/** The message. */
core::stringw m_message;
/** If this < 0, remove this message from queue. */
float m_display_timer;
/** The area which the message is drawn. */
core::recti m_area;
private:
/** Tell if this message has been initialized. */
bool m_inited;
public:
Message(float timer) : m_display_timer(timer), m_inited(false) {}
// ------------------------------------------------------------------------
virtual ~Message() {}
// ------------------------------------------------------------------------
virtual MessageQueue::MessageType getMessageType() const = 0;
// ------------------------------------------------------------------------
virtual void init() = 0;
// ------------------------------------------------------------------------
virtual void draw(float dt)
{
if (!m_inited)
{
m_inited = true;
init();
}
m_display_timer -= dt;
}
// ------------------------------------------------------------------------
bool canBeRemoved() const { return m_display_timer < 0.0f; }
// ------------------------------------------------------------------------
virtual void remove() {}
};
// ============================================================================
/** A small helper class to store and sort text messages to be displayed. */
class TextMessage : public Message
{
private: private:
/** The type of the message. */ /** The type of the message. */
MessageQueue::MessageType m_message_type; MessageQueue::MessageType m_message_type;
/** The message. */
core::stringw m_message;
/** The render type of the message: either achievement-message::neutral /** The render type of the message: either achievement-message::neutral
* or friend-message::neutral. */ * or friend-message::neutral. */
@ -56,11 +100,13 @@ private:
gui::IGUIStaticText* m_text; gui::IGUIStaticText* m_text;
public: public:
Message(MessageQueue::MessageType mt, const core::stringw &message) TextMessage(MessageQueue::MessageType mt, const core::stringw &message) :
Message(5.0f)
{ {
m_message_type = mt; m_message_type = mt;
m_message = message; m_message = message;
m_text = NULL; m_text = NULL;
assert(mt != MessageQueue::MT_PROGRESS);
if (mt == MessageQueue::MT_ACHIEVEMENT) if (mt == MessageQueue::MT_ACHIEVEMENT)
m_render_type = "achievement-message::neutral"; m_render_type = "achievement-message::neutral";
else if (mt == MessageQueue::MT_ERROR) else if (mt == MessageQueue::MT_ERROR)
@ -71,27 +117,21 @@ public:
m_render_type = "friend-message::neutral"; m_render_type = "friend-message::neutral";
} // Message } // Message
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
~Message() ~TextMessage()
{ {
assert(m_text != NULL); assert(m_text != NULL);
m_text->drop(); m_text->drop();
} }
/** Returns the message. */
const core::stringw & getMessage() const { return m_message; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the type of the message (achievement or friend). */ /** Returns the type of the message.*/
MessageQueue::MessageType getMessageType() const { return m_message_type; } virtual MessageQueue::MessageType getMessageType() const
// ------------------------------------------------------------------------ { return m_message_type; }
/** Returns the render type: either achievement-message::neutral or
* friend-message::neutral (see skin for details). */
const std::string &getRenderType() const
{
return m_render_type;
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Init the message text, do linebreak as required. */ /** Init the message text, do linebreak as required. */
void init() virtual void init()
{ {
if (m_text)
m_text->drop();
const GUIEngine::BoxRenderParams &brp = const GUIEngine::BoxRenderParams &brp =
GUIEngine::getSkin()->getBoxRenderParams(m_render_type); GUIEngine::getSkin()->getBoxRenderParams(m_render_type);
const unsigned width = irr_driver->getActualScreenSize().Width; const unsigned width = irr_driver->getActualScreenSize().Width;
@ -107,21 +147,25 @@ public:
dim.Width += brp.m_left_border + brp.m_right_border; dim.Width += brp.m_left_border + brp.m_right_border;
int x = (width - dim.Width) / 2; int x = (width - dim.Width) / 2;
int y = height - int(1.5f * dim.Height); int y = height - int(1.5f * dim.Height);
g_area = irr::core::recti(x, y, x + dim.Width, y + dim.Height); m_area = irr::core::recti(x, y, x + dim.Width, y + dim.Height);
m_text->setRelativePosition(g_area); m_text->setRelativePosition(m_area);
m_text->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER); m_text->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
m_text->grab(); m_text->grab();
m_text->remove(); m_text->remove();
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Draw the message. */ /** Draw the message. */
void draw() virtual void draw(float dt)
{ {
Message::draw(dt);
GUIEngine::getSkin()->drawMessage(g_container, m_area, m_render_type);
assert(m_text != NULL); assert(m_text != NULL);
m_text->draw(); m_text->draw();
} }
// ------------------------------------------------------------------------
virtual void remove() { delete this; }
}; // class Message }; // class TextMessage
// ============================================================================ // ============================================================================
/** A function class to compare messages, required for priority_queue. */ /** A function class to compare messages, required for priority_queue. */
@ -142,30 +186,87 @@ public:
Synchronised<std::priority_queue<Message*, std::vector<Message*>, Synchronised<std::priority_queue<Message*, std::vector<Message*>,
CompareMessages> > g_all_messages; CompareMessages> > g_all_messages;
/** How long the current message has been displayed. The special value // ============================================================================
* -1 indicates that a new message was added when the queue was empty. */ /** Add any message to the message queue.
float g_current_display_time = -1.0f; * \param message Any message.
*/
/** How long the current message should be displaed. */ void privateAdd(Message* m)
float g_max_display_time = 5.0f; {
g_all_messages.lock();
/** The label widget used to show the current message. */ g_all_messages.getData().push(m);
SkinWidgetContainer *g_container = NULL; g_all_messages.unlock();
} // privateAdd
// ============================================================================ // ============================================================================
/** A class which display a progress bar in game, only one can be displayed. */
void createLabel(Message *message) class ProgressBarMessage : public Message
{ {
if(!g_container) private:
g_container = new SkinWidgetContainer(); std::atomic_int_fast8_t m_progress_value;
g_current_display_time = 0.0f; bool m_showing;
// Maybe make this time dependent on message length as well?
g_max_display_time = 5.0f;
message->init();
} // createLabel
// ---------------------------------------------------------------------------- SkinWidgetContainer m_swc;
public:
ProgressBarMessage() :
Message(9999999.9f)
{
m_progress_value.store(0);
m_showing = false;
} // ProgressBarMessage
// ------------------------------------------------------------------------
~ProgressBarMessage() {}
// ------------------------------------------------------------------------
/** Returns the type of the message.*/
virtual MessageQueue::MessageType getMessageType() const
{ return MT_PROGRESS; }
// ------------------------------------------------------------------------
virtual void init()
{
const unsigned width = irr_driver->getActualScreenSize().Width;
const unsigned height = irr_driver->getActualScreenSize().Height;
core::dimension2du dim(width * 0.75f, height * 0.05f);
int x = (width - dim.Width) / 2;
int y = height - int(1.5f * dim.Height);
m_area = irr::core::recti(x, y, x + dim.Width,
y + dim.Height);
}
// ------------------------------------------------------------------------
virtual void draw(float dt)
{
Message::draw(dt);
m_display_timer = 9999999.9f;
GUIEngine::getSkin()->drawProgress(&m_swc, m_area,
m_progress_value.load());
video::SColor color(255, 0, 0, 0);
GUIEngine::getFont()->draw(m_message, m_area, color, true, true);
if (m_progress_value.load() >= 100)
{
m_display_timer = -1.0f;
m_showing = false;
}
}
// ------------------------------------------------------------------------
void setProgress(int progress, const wchar_t* msg)
{
if (progress < 0)
return;
if (progress > 100)
progress = 100;
m_progress_value.store((int_fast8_t)progress);
if (!m_showing && progress == 0)
{
m_showing = true;
m_message = msg;
privateAdd(this);
}
}
}; // class ProgressBarMessage
// ============================================================================
/** One instance of progress bar. */
ProgressBarMessage g_progress_bar_msg;
// ============================================================================
/** Called when the screen resolution is changed to compute the new /** Called when the screen resolution is changed to compute the new
* position of the message. */ * position of the message. */
void updatePosition() void updatePosition()
@ -177,28 +278,19 @@ void updatePosition()
g_all_messages.unlock(); g_all_messages.unlock();
return; return;
} }
Message *last = g_all_messages.getData().top(); g_all_messages.getData().top()->init();
createLabel(last);
g_all_messages.unlock(); g_all_messages.unlock();
} // updatePosition } // updatePosition
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Adds a message to the message queue. /** Adds a Text message to the message queue.
* \param mt The MessageType of the message. * \param mt The MessageType of the message.
* \param message The actual message. * \param message The actual message.
*/ */
void add(MessageType mt, const irr::core::stringw &message) void add(MessageType mt, const irr::core::stringw &message)
{ {
Message *m = new Message(mt, message); Message *m = new TextMessage(mt, message);
g_all_messages.lock(); privateAdd(m);
if (g_all_messages.getData().empty())
{
// Indicate that there is a new message, which should
// which needs a new label etc. to be computed.
g_current_display_time =-1.0f;
}
g_all_messages.getData().push(m);
g_all_messages.unlock();
} // add } // add
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -210,40 +302,41 @@ void add(MessageType mt, const irr::core::stringw &message)
*/ */
void update(float dt) void update(float dt)
{ {
g_all_messages.lock(); if (!g_container)
bool empty = g_all_messages.getData().empty(); g_container = new SkinWidgetContainer();
g_all_messages.unlock();
if (empty) return;
g_all_messages.lock(); g_all_messages.lock();
g_current_display_time += dt; bool empty = g_all_messages.getData().empty();
if (g_current_display_time > g_max_display_time) if (empty)
{
Message *last = g_all_messages.getData().top();
g_all_messages.getData().pop();
delete last;
if (g_all_messages.getData().empty())
{ {
g_all_messages.unlock(); g_all_messages.unlock();
return; return;
} }
g_current_display_time = -1.0f;
}
Message* current = g_all_messages.getData().top(); Message* current = g_all_messages.getData().top();
// Create new data for the display. current->draw(dt);
if (g_current_display_time < 0)
if (current->canBeRemoved())
{ {
createLabel(current); g_all_messages.getData().pop();
current->remove();
} }
g_all_messages.unlock(); g_all_messages.unlock();
GUIEngine::getSkin()->drawMessage(g_container, g_area,
current->getRenderType());
current->draw();
} // update } // update
// ----------------------------------------------------------------------------
/** The time a user firstly call this function with a zero progress, a progress
* bar will display in the game, the time the value of progress become 100,
* the progress bar will disappear. So make sure only 1 progress bar is being
* used each time.
* \param progress Progress from 0 to 100.
*/
void showProgressBar(int progress, const wchar_t* msg)
{
g_progress_bar_msg.setProgress(progress, msg);
} // showProgressBar
} // namespace GUIEngine } // namespace GUIEngine
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@ -34,9 +34,17 @@ namespace MessageQueue
* different look. This type is used to sort the messages, so it is * different look. This type is used to sort the messages, so it is
* important that messages that need to be shown as early as possible * important that messages that need to be shown as early as possible
* will be listed last (i.e. have highest priority). */ * will be listed last (i.e. have highest priority). */
enum MessageType { MT_FRIEND, MT_ACHIEVEMENT, MT_ERROR, MT_GENERIC}; enum MessageType
{
MT_FRIEND,
MT_ACHIEVEMENT,
MT_ERROR,
MT_GENERIC,
MT_PROGRESS
};
void add(MessageType mt, const core::stringw &message); void add(MessageType mt, const core::stringw &message);
void showProgressBar(int progress, const wchar_t* msg);
void updatePosition(); void updatePosition();
void update(float dt); void update(float dt);

View File

@ -839,6 +839,19 @@ void Skin::drawProgress(Widget* w, const core::recti &rect,
} }
} // drawProgress } // drawProgress
// ----------------------------------------------------------------------------
void Skin::drawProgress(SkinWidgetContainer* swc,
const core::rect< s32 > &rect, int progress)
{
drawBoxFromStretchableTexture(swc, rect,
SkinConfig::m_render_params["progress::neutral"]);
core::recti rect2 = rect;
rect2.LowerRightCorner.X -= (rect.getWidth())
- progress * rect.getWidth() / 100;
drawBoxFromStretchableTexture(swc, rect2,
SkinConfig::m_render_params["progress::fill"]);
} // drawProgress
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** /**
* @param focused whether this element is focus by the master player (focus * @param focused whether this element is focus by the master player (focus

View File

@ -336,6 +336,8 @@ namespace GUIEngine
void drawBgImage(); void drawBgImage();
void drawBGFadeColor(); void drawBGFadeColor();
void drawBadgeOn(const Widget* widget, const core::rect<s32>& rect); void drawBadgeOn(const Widget* widget, const core::rect<s32>& rect);
void drawProgress(SkinWidgetContainer* swc,
const core::rect< s32 > &rect, int progress);
// irrlicht's callbacks // irrlicht's callbacks
virtual void draw2DRectangle (gui::IGUIElement *element, virtual void draw2DRectangle (gui::IGUIElement *element,