Display warnings and errors on screen for a short time (fixes #119).
Add warn(), error() functions for simulation scripts. This was SVN commit r7600.
This commit is contained in:
parent
6de0cdc5f9
commit
65cf204423
@ -205,6 +205,13 @@ Handle unifont_load(const VfsPath& pathname, size_t flags)
|
||||
|
||||
LibError unifont_unload(Handle& h)
|
||||
{
|
||||
H_DEREF(h, UniFont, f);
|
||||
|
||||
// unbind ourself, so people will get errors if
|
||||
// they draw more text without binding a new font
|
||||
if (BoundGlyphs == f->glyphs)
|
||||
BoundGlyphs = NULL;
|
||||
|
||||
return h_free(h, H_UniFont);
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "network/NetServer.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/Font.h"
|
||||
#include "ps/Globals.h"
|
||||
#include "ps/Hotkey.h"
|
||||
#include "ps/Pyrogenesis.h"
|
||||
@ -194,6 +195,9 @@ void CConsole::Render()
|
||||
{
|
||||
if (! (m_bVisible || m_bToggle) ) return;
|
||||
|
||||
CFont font(CONSOLE_FONT);
|
||||
font.Bind();
|
||||
|
||||
// animation: slide in from top of screen
|
||||
const float MaxY = m_fHeight;
|
||||
const float DeltaY = (1.0f - m_fVisibleFrac) * MaxY;
|
||||
|
@ -20,13 +20,23 @@
|
||||
#include "CLogger.h"
|
||||
#include "CConsole.h"
|
||||
#include "ConfigDB.h"
|
||||
#include "lib/ogl.h"
|
||||
#include "lib/path_util.h"
|
||||
#include "lib/timer.h"
|
||||
#include "lib/utf8.h"
|
||||
#include "lib/res/graphics/unifont.h"
|
||||
#include "lib/sysdep/sysdep.h"
|
||||
#include "ps/Font.h"
|
||||
|
||||
#include <ctime>
|
||||
#include <ostream>
|
||||
|
||||
static const double RENDER_TIMEOUT = 5.0; // seconds before messages are deleted
|
||||
static const double RENDER_TIMEOUT_RATE = 10.0; // number of timed-out messages deleted per second
|
||||
static const size_t RENDER_LIMIT = 20; // maximum messages on screen at once
|
||||
|
||||
extern int g_xres, g_yres;
|
||||
|
||||
// Set up a default logger that throws everything away, because that's
|
||||
// better than crashing. (This is particularly useful for unit tests which
|
||||
// don't care about any log output.)
|
||||
@ -74,6 +84,10 @@ CLogger::CLogger(std::wostream* mainLog, std::wostream* interestingLog, bool tak
|
||||
m_OwnsStreams = takeOwnership;
|
||||
m_UseDebugPrintf = useDebugPrintf;
|
||||
|
||||
m_RenderLastEraseTime = -1.0;
|
||||
// this is called too early to allow us to call timer_Time(),
|
||||
// so we'll fill in the initial value later
|
||||
|
||||
Init();
|
||||
}
|
||||
|
||||
@ -126,6 +140,9 @@ void CLogger::WriteMessage(const wchar_t* message)
|
||||
*m_MainLog << L"<p>" << message << L"</p>\n";
|
||||
m_MainLog->flush();
|
||||
|
||||
// Don't do this since it results in too much noise:
|
||||
// RenderedMessage r = { Normal, timer_Time(), message };
|
||||
// m_RenderMessages.push_back(r);
|
||||
}
|
||||
|
||||
void CLogger::WriteError(const wchar_t* message)
|
||||
@ -140,6 +157,9 @@ void CLogger::WriteError(const wchar_t* message)
|
||||
|
||||
*m_MainLog << L"<p class=\"error\">ERROR: "<< message << L"</p>\n";
|
||||
m_MainLog->flush();
|
||||
|
||||
RenderedMessage r = { Error, timer_Time(), message };
|
||||
m_RenderMessages.push_back(r);
|
||||
}
|
||||
|
||||
void CLogger::WriteWarning(const wchar_t* message)
|
||||
@ -154,6 +174,9 @@ void CLogger::WriteWarning(const wchar_t* message)
|
||||
|
||||
*m_MainLog << L"<p class=\"warning\">WARNING: "<< message << L"</p>\n";
|
||||
m_MainLog->flush();
|
||||
|
||||
RenderedMessage r = { Warning, timer_Time(), message };
|
||||
m_RenderMessages.push_back(r);
|
||||
}
|
||||
|
||||
// Sends the message to the appropriate piece of code
|
||||
@ -260,6 +283,81 @@ void CLogger::LogError(const wchar_t* fmt, ...)
|
||||
WriteError(buffer);
|
||||
}
|
||||
|
||||
void CLogger::Render()
|
||||
{
|
||||
CleanupRenderQueue();
|
||||
|
||||
CFont font(L"mono-stroke-10");
|
||||
int lineSpacing = font.GetLineSpacing();
|
||||
font.Bind();
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
glScalef(1.0f, -1.0f, 1.0f);
|
||||
glTranslatef(4.0f, 4.0f + (float)lineSpacing - g_yres, 0.0f);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
for (std::deque<RenderedMessage>::iterator it = m_RenderMessages.begin(); it != m_RenderMessages.end(); ++it)
|
||||
{
|
||||
const wchar_t* type;
|
||||
if (it->method == Normal)
|
||||
{
|
||||
type = L"info";
|
||||
glColor3f(0.0f, 0.8f, 0.0f);
|
||||
}
|
||||
else if (it->method == Warning)
|
||||
{
|
||||
type = L"warning";
|
||||
glColor3f(1.0f, 1.0f, 0.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
type = L"error";
|
||||
glColor3f(1.0f, 0.0f, 0.0f);
|
||||
}
|
||||
glPushMatrix();
|
||||
|
||||
glwprintf(L"[%8.3f] %ls: ", it->time, type);
|
||||
// Display the actual message in white so it's more readable
|
||||
glColor3f(1.0f, 1.0f, 1.0f);
|
||||
glwprintf(L"%ls", it->message.c_str());
|
||||
|
||||
glPopMatrix();
|
||||
glTranslatef(0.f, (float)lineSpacing, 0.f);
|
||||
}
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
void CLogger::CleanupRenderQueue()
|
||||
{
|
||||
if (m_RenderMessages.empty())
|
||||
return;
|
||||
|
||||
double now = timer_Time();
|
||||
|
||||
// Initialise the timer on the first call (since we can't do it in the ctor)
|
||||
if (m_RenderLastEraseTime == -1.0)
|
||||
m_RenderLastEraseTime = now;
|
||||
|
||||
// Delete old messages, approximately at the given rate limit (and at most one per frame)
|
||||
if (now - m_RenderLastEraseTime > 1.0/RENDER_TIMEOUT_RATE)
|
||||
{
|
||||
if (m_RenderMessages[0].time + RENDER_TIMEOUT < now)
|
||||
{
|
||||
m_RenderMessages.pop_front();
|
||||
m_RenderLastEraseTime = now;
|
||||
}
|
||||
}
|
||||
|
||||
// If there's still too many then delete the oldest
|
||||
if (m_RenderMessages.size() > RENDER_LIMIT)
|
||||
m_RenderMessages.erase(m_RenderMessages.begin(), m_RenderMessages.end() - RENDER_LIMIT);
|
||||
}
|
||||
|
||||
TestLogger::TestLogger()
|
||||
{
|
||||
|
@ -73,6 +73,9 @@ public:
|
||||
void LogMessage(const wchar_t* fmt, ...) WPRINTF_ARGS(2);
|
||||
void LogWarning(const wchar_t* fmt, ...) WPRINTF_ARGS(2);
|
||||
void LogError(const wchar_t* fmt, ...) WPRINTF_ARGS(2);
|
||||
|
||||
// Render recent log messages onto the screen
|
||||
void Render();
|
||||
|
||||
private:
|
||||
void Init();
|
||||
@ -80,6 +83,9 @@ private:
|
||||
// -- This function has not been removed because the build would break.
|
||||
void LogUsingMethod(ELogMethod method, const wchar_t* message);
|
||||
|
||||
// Delete old timed-out entries from the list of text to render
|
||||
void CleanupRenderQueue();
|
||||
|
||||
// the output streams
|
||||
std::wostream* m_MainLog;
|
||||
std::wostream* m_InterestingLog;
|
||||
@ -97,6 +103,15 @@ private:
|
||||
// Used to remember LogOnce messages
|
||||
std::set<std::wstring> m_LoggedOnce;
|
||||
|
||||
// Used for Render()
|
||||
struct RenderedMessage
|
||||
{
|
||||
ELogMethod method;
|
||||
double time;
|
||||
std::wstring message;
|
||||
};
|
||||
std::deque<RenderedMessage> m_RenderMessages;
|
||||
double m_RenderLastEraseTime;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -238,39 +238,36 @@ void Render()
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
PROFILE_START( "render fonts" );
|
||||
MICROLOG(L"render fonts");
|
||||
// overlay mode
|
||||
// set up overlay mode
|
||||
glPushAttrib(GL_ENABLE_BIT);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glOrtho(0.f, (float)g_xres, 0.f, (float)g_yres, -1.f, 1000.f);
|
||||
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
|
||||
PROFILE_END( "render fonts" );
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
// Temp GUI message GeeTODO
|
||||
MICROLOG(L"render GUI");
|
||||
PROFILE_START( "render gui" );
|
||||
PROFILE_START("render gui");
|
||||
if(g_DoRenderGui) g_GUI->Draw();
|
||||
PROFILE_END( "render gui" );
|
||||
PROFILE_END("render gui");
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
// Particle Engine Updating
|
||||
CParticleEngine::GetInstance()->UpdateEmitters();
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
// Text:
|
||||
|
||||
// Use the GL_ALPHA texture as the alpha channel with a flat colouring
|
||||
@ -280,26 +277,25 @@ void Render()
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
// -- GL
|
||||
|
||||
ogl_WarnIfError();
|
||||
glLoadIdentity();
|
||||
|
||||
{
|
||||
PROFILE( "render console" );
|
||||
glLoadIdentity();
|
||||
|
||||
MICROLOG(L"render console");
|
||||
CFont font(CONSOLE_FONT);
|
||||
font.Bind();
|
||||
g_Console->Render();
|
||||
}
|
||||
PROFILE_START("render console");
|
||||
g_Console->Render();
|
||||
PROFILE_END("render console");
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
PROFILE_START("render logger");
|
||||
g_Logger->Render();
|
||||
PROFILE_END("render logger");
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
// Profile information
|
||||
|
||||
PROFILE_START( "render profiling" );
|
||||
PROFILE_START("render profiling");
|
||||
g_ProfileViewer.RenderProfile();
|
||||
PROFILE_END( "render profiling" );
|
||||
PROFILE_END("render profiling");
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
|
@ -101,16 +101,37 @@ void ErrorReporter(JSContext* UNUSED(cx), const char* message, JSErrorReport* re
|
||||
|
||||
// Functions in the global namespace:
|
||||
|
||||
JSBool print(JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* UNUSED(rval))
|
||||
JSBool print(JSContext* cx, uintN argc, jsval* vp)
|
||||
{
|
||||
for (uintN i = 0; i < argc; ++i)
|
||||
{
|
||||
std::string str;
|
||||
if (!ScriptInterface::FromJSVal(cx, argv[i], str))
|
||||
if (!ScriptInterface::FromJSVal(cx, JS_ARGV(cx, vp)[i], str))
|
||||
return JS_FALSE;
|
||||
printf("%s", str.c_str());
|
||||
}
|
||||
fflush(stdout);
|
||||
JS_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSBool warn(JSContext* cx, uintN UNUSED(argc), jsval* vp)
|
||||
{
|
||||
std::wstring str;
|
||||
if (!ScriptInterface::FromJSVal(cx, JS_ARGV(cx, vp)[0], str))
|
||||
return JS_FALSE;
|
||||
LOGWARNING(L"%ls", str.c_str());
|
||||
JS_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSBool error(JSContext* cx, uintN UNUSED(argc), jsval* vp)
|
||||
{
|
||||
std::wstring str;
|
||||
if (!ScriptInterface::FromJSVal(cx, JS_ARGV(cx, vp)[0], str))
|
||||
return JS_FALSE;
|
||||
LOGERROR(L"%ls", str.c_str());
|
||||
JS_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
@ -227,7 +248,9 @@ ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, JSContex
|
||||
m_nativeScope = JS_DefineObject(m_cx, m_glob, nativeScopeName, NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY
|
||||
| JSPROP_PERMANENT);
|
||||
|
||||
JS_DefineFunction(m_cx, m_glob, "print", ::print, 0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
|
||||
JS_DefineFunction(m_cx, m_glob, "print", (JSNative)::print, 0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSFUN_FAST_NATIVE);
|
||||
JS_DefineFunction(m_cx, m_glob, "warn", (JSNative)::warn, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSFUN_FAST_NATIVE);
|
||||
JS_DefineFunction(m_cx, m_glob, "error", (JSNative)::error, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSFUN_FAST_NATIVE);
|
||||
}
|
||||
|
||||
ScriptInterface_impl::~ScriptInterface_impl()
|
||||
|
Loading…
Reference in New Issue
Block a user