# Actor Viewer tool: added controls to toggle shadows, ground and polygon counts.
Elsewhere: Disabled stack-trace test because it gives me assertion failures. Fixed some uses of snprintf (which doesn't always add a \0 to the end of the string), then got bored so there are still lots of broken ones. Probably should replace snprintf with something more like snprintf_s (but non-fatal) or something. Made CLogger output valid HTML (except for the potentially dodgy doctype). Removed its memory-logger, since we never use it and MICROLOG can be used instead for quick execution-tracing. Added tests to make sure CLogger handles long strings properly (which it didn't). Made CLogger not a singleton, so it can be tested sensibly. This was SVN commit r4424.
This commit is contained in:
parent
06743babb5
commit
2fac02f40a
@ -146,6 +146,7 @@ void CTextureManager::RecurseDirectory(CTerrainPropertiesPtr parentProps, const
|
||||
// Load terrains.xml first, if it exists
|
||||
char fn[PATH_MAX];
|
||||
snprintf(fn, PATH_MAX, "%s%s", cur_dir_path, "terrains.xml");
|
||||
fn[PATH_MAX-1] = '\0';
|
||||
if (vfs_exists(fn))
|
||||
props = GetPropertiesFromFile(parentProps, fn);
|
||||
|
||||
|
@ -1022,6 +1022,7 @@ void CGUI::ReportParseError(const char *str, ...)
|
||||
|
||||
va_start(argp, str);
|
||||
vsnprintf2(buffer, sizeof(buffer), str, argp);
|
||||
buffer[sizeof(buffer)-1] = '\0';
|
||||
va_end(argp);
|
||||
|
||||
// Print header
|
||||
|
@ -166,7 +166,7 @@ JSBool JSI_GUIColor::toString(JSContext* cx, JSObject* obj,
|
||||
{
|
||||
char buffer[256];
|
||||
// Convert to integers, to be compatible with the GUI's string SetSetting
|
||||
snprintf(buffer, 256, "%i %i %i %i",
|
||||
snprintf(buffer, 256, "%d %d %d %d",
|
||||
(int)( 255.0 * *JSVAL_TO_DOUBLE(g_ScriptingHost.GetObjectProperty(obj, "r")) ),
|
||||
(int)( 255.0 * *JSVAL_TO_DOUBLE(g_ScriptingHost.GetObjectProperty(obj, "g")) ),
|
||||
(int)( 255.0 * *JSVAL_TO_DOUBLE(g_ScriptingHost.GetObjectProperty(obj, "b")) ),
|
||||
@ -222,7 +222,7 @@ JSBool JSI_GUIMouse::construct(JSContext* cx, JSObject* obj, uint argc, jsval* a
|
||||
JSBool JSI_GUIMouse::toString(JSContext* cx, JSObject* obj, uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval)
|
||||
{
|
||||
char buffer[256];
|
||||
snprintf(buffer, 256, "%i %i %i",
|
||||
snprintf(buffer, 256, "%d %d %d",
|
||||
JSVAL_TO_INT(g_ScriptingHost.GetObjectProperty(obj, "x")),
|
||||
JSVAL_TO_INT(g_ScriptingHost.GetObjectProperty(obj, "y")),
|
||||
JSVAL_TO_INT(g_ScriptingHost.GetObjectProperty(obj, "buttons")) );
|
||||
|
@ -254,6 +254,7 @@ class TestWdbgSym : public CxxTest::TestSuite
|
||||
public:
|
||||
void test_stack_trace()
|
||||
{
|
||||
m_test_addrs(123, 3.1415926535897932384626, "pchar string", 0xf00d);
|
||||
// TODO: restore this when it doesn't cause annoying assertion failures
|
||||
// m_test_addrs(123, 3.1415926535897932384626, "pchar string", 0xf00d);
|
||||
}
|
||||
};
|
||||
|
@ -8,49 +8,62 @@
|
||||
|
||||
#include <time.h>
|
||||
|
||||
CLogger* g_Logger = NULL;
|
||||
|
||||
#include "CConsole.h"
|
||||
extern CConsole* g_Console;
|
||||
|
||||
using namespace std;
|
||||
|
||||
const char* html_header0 =
|
||||
"<HTML>\n<HEAD>\n<LINK REL=StyleSheet HREF="
|
||||
"\"style.css\" TYPE=\"text/css\">\n"
|
||||
"</HEAD>\n<BODY>\n<P align=\"center\"><IMG src="
|
||||
"\"0adlogo.jpg\"/></P>\n"
|
||||
"<P><H1>";
|
||||
"<!DOCTYPE HTML SYSTEM>\n"
|
||||
"<title>Pyrogenesis Log</title>\n"
|
||||
"<link rel=\"stylesheet\" href=\"style.css\" type=\"text/css\">\n"
|
||||
"<p align=\"center\"><img src=\"0adlogo.jpg\" alt=\"0 A.D.\"></p>\n"
|
||||
"<h1>";
|
||||
// (note that the html,head,body tags are optional)
|
||||
|
||||
const char* html_header1 = "</H1></P>\n";
|
||||
const char* html_header1 = "</h1>\n";
|
||||
|
||||
const char* html_footer = "</BODY>\n</HTML>\n";
|
||||
|
||||
#define MEMORY_BUFFER_SIZE 1000
|
||||
const char* html_footer = "";
|
||||
// (</body> and </html> are optional too - this way we get the same valid
|
||||
// output even if we crash and don't close the file properly...)
|
||||
|
||||
CLogger::CLogger()
|
||||
{
|
||||
char N_path[PATH_MAX];
|
||||
(void)file_make_full_native_path("../logs", N_path);
|
||||
PathPackage pp;
|
||||
(void)path_package_set_dir(&pp, N_path);
|
||||
|
||||
(void)path_package_append_file(&pp, "mainlog.html");
|
||||
m_MainLog = new std::ofstream(pp.path, ofstream::out | ofstream::trunc);
|
||||
|
||||
(void)path_package_append_file(&pp, "interestinglog.html");
|
||||
m_InterestingLog = new std::ofstream(pp.path, ofstream::out | ofstream::trunc);
|
||||
|
||||
Init();
|
||||
}
|
||||
|
||||
CLogger::CLogger(std::ostream* mainLog, std::ostream* interestingLog)
|
||||
{
|
||||
m_MainLog = mainLog;
|
||||
m_InterestingLog = interestingLog;
|
||||
|
||||
Init();
|
||||
}
|
||||
|
||||
void CLogger::Init()
|
||||
{
|
||||
m_NumberOfMessages = 0;
|
||||
m_NumberOfErrors = 0;
|
||||
m_NumberOfWarnings = 0;
|
||||
|
||||
m_MemoryLogBuffer = (char *)calloc(MEMORY_BUFFER_SIZE, 1);
|
||||
m_CurrentPosition = m_MemoryLogBuffer;
|
||||
|
||||
char N_path[PATH_MAX];
|
||||
(void)file_make_full_native_path("../logs", N_path);
|
||||
PathPackage pp;
|
||||
(void)path_package_set_dir(&pp, N_path);
|
||||
(void)path_package_append_file(&pp, "mainlog.html");
|
||||
m_MainLog.open (pp.path, ofstream::out | ofstream::trunc);
|
||||
(void)path_package_append_file(&pp, "interestinglog.html");
|
||||
m_InterestingLog.open(pp.path, ofstream::out | ofstream::trunc);
|
||||
(void)path_package_append_file(&pp, "memorylog.html");
|
||||
m_MemoryLog.open (pp.path, ofstream::out | ofstream::trunc);
|
||||
|
||||
//Write Headers for the HTML documents
|
||||
m_MainLog << html_header0 << "Main log" << html_header1;
|
||||
*m_MainLog << html_header0 << "Main log" << html_header1;
|
||||
|
||||
//Write Headers for the HTML documents
|
||||
m_InterestingLog << html_header0 << "Main log (interesting items only, as specified in system.cfg)" << html_header1;
|
||||
*m_InterestingLog << html_header0 << "Main log (interesting items only, as specified in system.cfg)" << html_header1;
|
||||
|
||||
}
|
||||
|
||||
@ -69,29 +82,16 @@ CLogger::~CLogger ()
|
||||
|
||||
//Write closing text
|
||||
|
||||
m_MainLog << "<P>Engine exited successfully on " << currentDate;
|
||||
m_MainLog << " at " << currentTime << buffer << "</P>\n";
|
||||
m_MainLog << html_footer;
|
||||
m_MainLog.close ();
|
||||
*m_MainLog << "<p>Engine exited successfully on " << currentDate;
|
||||
*m_MainLog << " at " << currentTime << buffer << "</p>\n";
|
||||
*m_MainLog << html_footer;
|
||||
|
||||
m_InterestingLog << "<P>Engine exited successfully on " << currentDate;
|
||||
m_InterestingLog << " at " << currentTime << buffer << "</P>\n";
|
||||
m_InterestingLog << html_footer;
|
||||
m_InterestingLog.close ();
|
||||
*m_InterestingLog << "<p>Engine exited successfully on " << currentDate;
|
||||
*m_InterestingLog << " at " << currentTime << buffer << "</p>\n";
|
||||
*m_InterestingLog << html_footer;
|
||||
|
||||
|
||||
//Add end marker to logs in memory
|
||||
*m_CurrentPosition = '\0';
|
||||
|
||||
m_MemoryLog << html_header0 << "Memory log" << html_header1;
|
||||
m_MemoryLog << "<P>Memory Log started with capacity of " << \
|
||||
MEMORY_BUFFER_SIZE << " characters.</P>\n";
|
||||
m_MemoryLog << m_MemoryLogBuffer;
|
||||
m_MemoryLog << html_footer;
|
||||
|
||||
m_MemoryLog.close ();
|
||||
|
||||
free(m_MemoryLogBuffer);
|
||||
delete m_InterestingLog;
|
||||
delete m_MainLog;
|
||||
}
|
||||
|
||||
void CLogger::WriteMessage(const char *message, int interestedness)
|
||||
@ -101,11 +101,11 @@ void CLogger::WriteMessage(const char *message, int interestedness)
|
||||
if (interestedness >= 2)
|
||||
{
|
||||
if (g_Console) g_Console->InsertMessage(L"LOG: %hs", message);
|
||||
m_InterestingLog << "<P>" << message << "</P>\n";
|
||||
m_InterestingLog.flush();
|
||||
*m_InterestingLog << "<p>" << message << "</p>\n";
|
||||
m_InterestingLog->flush();
|
||||
}
|
||||
m_MainLog << "<P>" << message << "</P>\n";
|
||||
m_MainLog.flush();
|
||||
*m_MainLog << "<p>" << message << "</p>\n";
|
||||
m_MainLog->flush();
|
||||
|
||||
}
|
||||
|
||||
@ -116,11 +116,11 @@ void CLogger::WriteError(const char *message, int interestedness)
|
||||
if (interestedness >= 1)
|
||||
{
|
||||
if (g_Console) g_Console->InsertMessage(L"ERROR: %hs", message);
|
||||
m_InterestingLog << "<P class=\"error\">ERROR: "<< message << "</P>\n";
|
||||
m_InterestingLog.flush();
|
||||
*m_InterestingLog << "<p class=\"error\">ERROR: "<< message << "</p>\n";
|
||||
m_InterestingLog->flush();
|
||||
}
|
||||
m_MainLog << "<P class=\"error\">ERROR: "<< message << "</P>\n";
|
||||
m_MainLog.flush();
|
||||
*m_MainLog << "<p class=\"error\">ERROR: "<< message << "</p>\n";
|
||||
m_MainLog->flush();
|
||||
}
|
||||
|
||||
void CLogger::WriteWarning(const char *message, int interestedness)
|
||||
@ -129,11 +129,11 @@ void CLogger::WriteWarning(const char *message, int interestedness)
|
||||
if (interestedness >= 1)
|
||||
{
|
||||
if (g_Console) g_Console->InsertMessage(L"WARNING: %hs", message);
|
||||
m_InterestingLog << "<P class=\"warning\">WARNING: "<< message << "</P>\n";
|
||||
m_InterestingLog.flush();
|
||||
*m_InterestingLog << "<p class=\"warning\">WARNING: "<< message << "</p>\n";
|
||||
m_InterestingLog->flush();
|
||||
}
|
||||
m_MainLog << "<P class=\"warning\">WARNING: "<< message << "</P>\n";
|
||||
m_MainLog.flush();
|
||||
*m_MainLog << "<p class=\"warning\">WARNING: "<< message << "</p>\n";
|
||||
m_MainLog->flush();
|
||||
}
|
||||
|
||||
// Sends the message to the appropriate piece of code
|
||||
@ -154,7 +154,7 @@ void CLogger::Log(ELogMethod method, const char* category, const char *fmt, ...)
|
||||
va_list argp;
|
||||
char buffer[512];
|
||||
|
||||
memset(buffer,0,sizeof(buffer));
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
|
||||
va_start(argp, fmt);
|
||||
if (vsnprintf2(buffer, sizeof(buffer)-1, fmt, argp) == -1)
|
||||
@ -173,10 +173,10 @@ void CLogger::LogOnce(ELogMethod method, const char* category, const char *fmt,
|
||||
va_list argp;
|
||||
char buffer[512];
|
||||
|
||||
memset(buffer,0,sizeof(buffer));
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
|
||||
va_start(argp, fmt);
|
||||
if (vsnprintf2(buffer, sizeof(buffer), fmt, argp) == -1)
|
||||
if (vsnprintf2(buffer, sizeof(buffer)-1, fmt, argp) == -1)
|
||||
{
|
||||
// Buffer too small - ensure the string is nicely terminated
|
||||
strcpy(buffer+sizeof(buffer)-4, "..."); // safe
|
||||
@ -195,41 +195,6 @@ void CLogger::LogOnce(ELogMethod method, const char* category, const char *fmt,
|
||||
}
|
||||
|
||||
|
||||
void CLogger::QuickLog(const char *fmt, ...)
|
||||
{
|
||||
va_list argp;
|
||||
char buffer[512];
|
||||
int count = 0;
|
||||
|
||||
//Start a new paragraph in HTML
|
||||
strcpy(buffer,"<P>"); // safe
|
||||
|
||||
va_start(argp, fmt);
|
||||
char *bufend=strchr(buffer, 0);
|
||||
vsnprintf(bufend, buffer+sizeof(buffer)-bufend, fmt, argp);
|
||||
va_end(argp);
|
||||
|
||||
//add some html formatting, making sure not to overrun the buffer
|
||||
bufend=strchr(buffer, 0);
|
||||
strncpy(bufend, "</P>", buffer+sizeof(buffer)-bufend);
|
||||
|
||||
if((m_CurrentPosition - m_MemoryLogBuffer + strlen(buffer) + 1) >= MEMORY_BUFFER_SIZE)
|
||||
{
|
||||
//not enough room in the buffer so don't log.
|
||||
return;
|
||||
}
|
||||
|
||||
while(buffer[count] != '\0')
|
||||
{
|
||||
*m_CurrentPosition++ = buffer[count];
|
||||
count++;
|
||||
}
|
||||
|
||||
*m_CurrentPosition++ = '\n';
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
int CLogger::Interestedness(const char* category)
|
||||
{
|
||||
// This could be cached, but reading from the config DB every time allows
|
||||
|
@ -5,11 +5,11 @@
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
#include "Singleton.h"
|
||||
class CLogger;
|
||||
extern CLogger* g_Logger;
|
||||
|
||||
#define g_Logger CLogger::GetSingleton()
|
||||
#define LOG (CLogger::GetSingleton().Log)
|
||||
#define LOG_ONCE (CLogger::GetSingleton().LogOnce)
|
||||
#define LOG (g_Logger->Log)
|
||||
#define LOG_ONCE (g_Logger->LogOnce)
|
||||
|
||||
enum ELogMethod
|
||||
{
|
||||
@ -19,11 +19,17 @@ enum ELogMethod
|
||||
WARNING
|
||||
};
|
||||
|
||||
class CLogger : public Singleton<CLogger>
|
||||
class CLogger
|
||||
{
|
||||
public:
|
||||
|
||||
// Default constructor - outputs to normal log files
|
||||
CLogger();
|
||||
|
||||
// Special constructor (mostly for testing) - outputs to provided streams.
|
||||
// Takes ownership of streams and will delete them in the destructor.
|
||||
CLogger(std::ostream* mainLog, std::ostream* interestingLog);
|
||||
|
||||
~CLogger();
|
||||
|
||||
//Functions to write different message types
|
||||
@ -36,17 +42,14 @@ public:
|
||||
//Similar to Log, but only outputs each message once no matter how many times it's called
|
||||
void LogOnce(ELogMethod method, const char* category, const char *fmt, ...);
|
||||
|
||||
//Function to log stuff to memory buffer
|
||||
void QuickLog(const char *fmt, ...);
|
||||
|
||||
private:
|
||||
void Init();
|
||||
|
||||
void LogUsingMethod(ELogMethod method, const char* category, const char* message);
|
||||
|
||||
//the three filestreams
|
||||
std::ofstream m_MainLog;
|
||||
std::ofstream m_InterestingLog;
|
||||
std::ofstream m_MemoryLog;
|
||||
//the output streams
|
||||
std::ostream* m_MainLog;
|
||||
std::ostream* m_InterestingLog;
|
||||
|
||||
//vars to hold message counts
|
||||
int m_NumberOfMessages;
|
||||
@ -57,11 +60,6 @@ private:
|
||||
// (0 = no messages, 1(default) = warnings/errors, 2 = all)
|
||||
int Interestedness(const char* category);
|
||||
|
||||
//this holds the start of the memory buffer.
|
||||
char *m_MemoryLogBuffer;
|
||||
//this holds the next available place to write to.
|
||||
char *m_CurrentPosition;
|
||||
|
||||
// Used to remember LogOnce messages
|
||||
std::set<std::string> m_LoggedOnce;
|
||||
|
||||
|
@ -156,6 +156,7 @@ static void ParseCommandLineArgs(int argc, char* argv[])
|
||||
const char* mod_name = name+4;
|
||||
char path[PATH_MAX];
|
||||
snprintf(path, ARRAY_SIZE(path), "mods/%s", mod_name);
|
||||
path[PATH_MAX-1] = '\0';
|
||||
// note: default is 0. we should set this higher in case the
|
||||
// mod file mtimes are actually older than the official
|
||||
// version (*could* happen), otherwise the mod might not
|
||||
|
@ -387,6 +387,7 @@ void Render()
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
|
||||
PROFILE_END( "render fonts" );
|
||||
|
||||
@ -394,7 +395,6 @@ void Render()
|
||||
|
||||
#ifndef NO_GUI
|
||||
// Temp GUI message GeeTODO
|
||||
glLoadIdentity();
|
||||
MICROLOG(L"render GUI");
|
||||
PROFILE_START( "render gui" );
|
||||
g_GUI.Draw();
|
||||
@ -448,7 +448,7 @@ void Render()
|
||||
oglCheck();
|
||||
|
||||
// Draw the cursor (or set the Windows cursor, on Windows)
|
||||
CStr8 cursorName = g_BuildingPlacer.m_active ? "action-build" : g_CursorName;
|
||||
CStr cursorName = g_BuildingPlacer.m_active ? "action-build" : g_CursorName;
|
||||
cursor_draw(cursorName, g_mouse_x, g_mouse_y);
|
||||
|
||||
// restore
|
||||
@ -864,7 +864,7 @@ void Shutdown(uint flags)
|
||||
|
||||
// should be last, since the above use them
|
||||
debug_shutdown();
|
||||
delete &g_Logger;
|
||||
SAFE_DELETE(g_Logger);
|
||||
delete &g_Profiler;
|
||||
delete &g_ProfileViewer;
|
||||
TIMER_END("shutdown misc");
|
||||
@ -896,7 +896,7 @@ void Init(int argc, char* argv[], uint flags)
|
||||
|
||||
// This must come after VFS init, which sets the current directory
|
||||
// (required for finding our output log files).
|
||||
new CLogger;
|
||||
g_Logger = new CLogger;
|
||||
|
||||
// Call LoadLanguage(NULL) to initialize the I18n system, but
|
||||
// without loading an actual language file - translate() will
|
||||
|
@ -92,6 +92,7 @@ CStr CProfileNodeTable::GetTitle()
|
||||
char buf[512];
|
||||
|
||||
snprintf(buf, sizeof(buf), "Profiling Information for: %s (Time in node: %.3f msec/frame)", node->GetName(), node->GetFrameTime() * 1000.0f );
|
||||
buf[sizeof(buf)-1] = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
@ -144,6 +145,7 @@ CStr CProfileNodeTable::GetCellText(size_t row, size_t col)
|
||||
snprintf(buf, sizeof(buf), "%.1f", unlogged / g_Profiler.GetRoot()->GetFrameTime());
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "%.1f", unlogged * 100.0f / g_Profiler.GetRoot()->GetFrameTime());
|
||||
buf[sizeof(buf)-1] = '\0';
|
||||
|
||||
return CStr(buf);
|
||||
}
|
||||
@ -160,20 +162,19 @@ CStr CProfileNodeTable::GetCellText(size_t row, size_t col)
|
||||
#else
|
||||
snprintf(buf, sizeof(buf), "%d", child->GetFrameCalls());
|
||||
#endif
|
||||
return CStr(buf);
|
||||
|
||||
break;
|
||||
case 2:
|
||||
snprintf(buf, sizeof(buf), "%.3f", child->GetFrameTime() * 1000.0f);
|
||||
return CStr(buf);
|
||||
|
||||
break;
|
||||
case 3:
|
||||
snprintf(buf, sizeof(buf), "%.1f", child->GetFrameTime() * 100.0 / g_Profiler.GetRoot()->GetFrameTime());
|
||||
return CStr(buf);
|
||||
|
||||
break;
|
||||
case 4:
|
||||
snprintf(buf, sizeof(buf), "%.1f", child->GetFrameTime() * 100.0 / node->GetFrameTime());
|
||||
return CStr(buf);
|
||||
break;
|
||||
}
|
||||
buf[sizeof(buf)-1] = '\0';
|
||||
return CStr(buf);
|
||||
}
|
||||
|
||||
// Return a pointer to the child table if the child node is expandable
|
||||
|
@ -446,3 +446,24 @@ void CProfileViewer::SaveToFile()
|
||||
m->outputStream << "\n\n================================================================\n";
|
||||
m->outputStream.flush();
|
||||
}
|
||||
|
||||
void CProfileViewer::ShowTable(const CStr& table)
|
||||
{
|
||||
m->path.clear();
|
||||
|
||||
if (table.length() > 0)
|
||||
{
|
||||
for (size_t i = 0; i < m->rootTables.size(); ++i)
|
||||
{
|
||||
if (m->rootTables[i]->GetName() == table)
|
||||
{
|
||||
m->path.push_back(m->rootTables[i]);
|
||||
m->profileVisible = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No matching table found, so don't display anything
|
||||
m->profileVisible = false;
|
||||
}
|
||||
|
@ -164,10 +164,19 @@ public:
|
||||
static InReaction InputThunk(const SDL_Event_* ev);
|
||||
|
||||
/**
|
||||
* SaveToFile: Saves the current profiler data (for all profile tables)
|
||||
* SaveToFile: Save the current profiler data (for all profile tables)
|
||||
* to a file in the 'logs' directory.
|
||||
*/
|
||||
void SaveToFile();
|
||||
|
||||
/**
|
||||
* ShowTable: Set the named profile table to be the displayed one. If it
|
||||
* is not found, no profile is displayed.
|
||||
*
|
||||
* @param table The table name (matching AbstractProfileTable::GetName),
|
||||
* or the empty string to display no table.
|
||||
*/
|
||||
void ShowTable(const CStr& table);
|
||||
|
||||
private:
|
||||
CProfileViewerInternals* m;
|
||||
|
@ -165,6 +165,7 @@ void WriteScreenshot(const char* extension)
|
||||
// note: %04d -> always 4 digits, so sorting by filename works correctly.
|
||||
char file_format_string[PATH_MAX];
|
||||
snprintf(file_format_string, PATH_MAX, "screenshots/screenshot%%04d.%s", extension);
|
||||
file_format_string[PATH_MAX-1] = '\0';
|
||||
char fn[PATH_MAX];
|
||||
next_numbered_filename(file_format_string, &screenshot_nfi, fn);
|
||||
const char* atom_fn = file_make_unique_fn_copy(fn);
|
||||
@ -204,6 +205,7 @@ void WriteBigScreenshot(const char* extension, int tiles)
|
||||
// note: %04d -> always 4 digits, so sorting by filename works correctly.
|
||||
char file_format_string[PATH_MAX];
|
||||
snprintf(file_format_string, PATH_MAX, "screenshots/screenshot%%04d.%s", extension);
|
||||
file_format_string[PATH_MAX-1] = '\0';
|
||||
char fn[PATH_MAX];
|
||||
next_numbered_filename(file_format_string, &screenshot_nfi, fn);
|
||||
const char* atom_fn = file_make_unique_fn_copy(fn);
|
||||
|
@ -199,6 +199,7 @@ void CXeromyces::getXMBPath(const char* xmlFilename, const char* xmbFilename,
|
||||
|
||||
// build full name: cache, then mod name, XMB subdir, original XMB path
|
||||
snprintf(xmbPath, PATH_MAX, "cache/mods/%s/xmb/%s", modName, xmbFilename);
|
||||
xmbPath[PATH_MAX-1] = '\0';
|
||||
}
|
||||
|
||||
PSRETURN CXeromyces::Load(const char* filename)
|
||||
|
93
source/ps/tests/test_CLogger.h
Normal file
93
source/ps/tests/test_CLogger.h
Normal file
@ -0,0 +1,93 @@
|
||||
#include "lib/self_test.h"
|
||||
|
||||
#include "ps/CLogger.h"
|
||||
|
||||
class TestCLogger : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
void test_basic()
|
||||
{
|
||||
logger->Log(NORMAL, "", "Test 1");
|
||||
logger->Log(NORMAL, "", "Test 2");
|
||||
|
||||
ParseOutput();
|
||||
|
||||
TS_ASSERT_EQUALS((int)lines.size(), 2);
|
||||
TS_ASSERT_EQUALS(lines[0], "Test 1");
|
||||
TS_ASSERT_EQUALS(lines[1], "Test 2");
|
||||
}
|
||||
|
||||
void test_overflow()
|
||||
{
|
||||
const int buflen = 512;
|
||||
|
||||
std::string msg0 (buflen-2, '*');
|
||||
std::string msg1 (buflen-1, '*');
|
||||
std::string msg2 (buflen, '*');
|
||||
std::string msg3 (buflen+1, '*');
|
||||
|
||||
std::string clipped (buflen-4, '*');
|
||||
clipped += "...";
|
||||
|
||||
logger->Log(NORMAL, "", msg0.c_str());
|
||||
logger->Log(NORMAL, "", msg1.c_str());
|
||||
logger->Log(NORMAL, "", msg2.c_str());
|
||||
logger->Log(NORMAL, "", msg3.c_str());
|
||||
|
||||
logger->LogOnce(NORMAL, "", msg0.c_str());
|
||||
logger->LogOnce(NORMAL, "", msg1.c_str());
|
||||
logger->LogOnce(NORMAL, "", msg2.c_str());
|
||||
logger->LogOnce(NORMAL, "", msg3.c_str());
|
||||
|
||||
ParseOutput();
|
||||
|
||||
TS_ASSERT_EQUALS((int)lines.size(), 7);
|
||||
TS_ASSERT_EQUALS(lines[0], msg0);
|
||||
TS_ASSERT_EQUALS(lines[1], msg1);
|
||||
TS_ASSERT_EQUALS(lines[2], clipped);
|
||||
TS_ASSERT_EQUALS(lines[3], clipped);
|
||||
TS_ASSERT_EQUALS(lines[4], msg0);
|
||||
TS_ASSERT_EQUALS(lines[5], msg1);
|
||||
TS_ASSERT_EQUALS(lines[6], clipped);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CLogger* logger;
|
||||
std::stringstream* mainlog;
|
||||
std::stringstream* interestinglog;
|
||||
std::vector<std::string> lines;
|
||||
|
||||
void setUp()
|
||||
{
|
||||
mainlog = new std::stringstream();
|
||||
interestinglog = new std::stringstream();
|
||||
|
||||
logger = new CLogger(mainlog, interestinglog);
|
||||
|
||||
lines.clear();
|
||||
}
|
||||
|
||||
void tearDown()
|
||||
{
|
||||
delete logger;
|
||||
logger = NULL;
|
||||
}
|
||||
|
||||
void ParseOutput()
|
||||
{
|
||||
const std::string header_end = "</h1>\n";
|
||||
|
||||
std::string s = mainlog->str();
|
||||
size_t start = s.find(header_end);
|
||||
TS_ASSERT_DIFFERS(start, s.npos);
|
||||
s = s.substr(start + header_end.length());
|
||||
|
||||
size_t n = 0, m;
|
||||
while (s.npos != (m = s.find('\n', n)))
|
||||
{
|
||||
lines.push_back(s.substr(n+3, m-n-7)); // strip the <p> and </p>
|
||||
n = m+1;
|
||||
}
|
||||
}
|
||||
};
|
@ -212,6 +212,14 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
|
||||
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
|
||||
|
||||
glBlendFunc(GL_DST_COLOR, GL_ZERO);
|
||||
|
||||
// GL_TEXTURE_ENV_COLOR requires four floats, so we shouldn't use the RGBColor directly
|
||||
float terrainAmbientColor[4] = {
|
||||
lightEnv.m_TerrainAmbientColor.X,
|
||||
lightEnv.m_TerrainAmbientColor.Y,
|
||||
lightEnv.m_TerrainAmbientColor.Z,
|
||||
1.f
|
||||
};
|
||||
|
||||
if (!shadow)
|
||||
{
|
||||
@ -229,7 +237,7 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
||||
|
||||
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &lightEnv.m_TerrainAmbientColor.X);
|
||||
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, terrainAmbientColor);
|
||||
|
||||
}
|
||||
else
|
||||
@ -286,7 +294,7 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
||||
|
||||
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &lightEnv.m_TerrainAmbientColor.X);
|
||||
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, terrainAmbientColor);
|
||||
|
||||
}
|
||||
else
|
||||
@ -313,7 +321,7 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
||||
|
||||
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &lightEnv.m_TerrainAmbientColor.X);
|
||||
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, terrainAmbientColor);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -132,9 +132,12 @@ enum
|
||||
ID_Pause,
|
||||
ID_Slow,
|
||||
ID_Edit,
|
||||
ID_Wireframe,
|
||||
ID_Background,
|
||||
ID_Walking
|
||||
ID_ToggleWireframe,
|
||||
ID_ToggleWalking,
|
||||
ID_ToggleGround,
|
||||
ID_ToggleShadows,
|
||||
ID_ToggleStats,
|
||||
};
|
||||
|
||||
BEGIN_EVENT_TABLE(ActorViewer, wxFrame)
|
||||
@ -146,9 +149,12 @@ BEGIN_EVENT_TABLE(ActorViewer, wxFrame)
|
||||
EVT_BUTTON(ID_Pause, ActorViewer::OnSpeedButton)
|
||||
EVT_BUTTON(ID_Slow, ActorViewer::OnSpeedButton)
|
||||
EVT_BUTTON(ID_Edit, ActorViewer::OnEditButton)
|
||||
EVT_BUTTON(ID_Wireframe, ActorViewer::OnWireframeButton)
|
||||
EVT_BUTTON(ID_Background, ActorViewer::OnBackgroundButton)
|
||||
EVT_BUTTON(ID_Walking, ActorViewer::OnWalkingButton)
|
||||
EVT_BUTTON(ID_ToggleWireframe, ActorViewer::OnToggleButton)
|
||||
EVT_BUTTON(ID_ToggleWalking, ActorViewer::OnToggleButton)
|
||||
EVT_BUTTON(ID_ToggleGround, ActorViewer::OnToggleButton)
|
||||
EVT_BUTTON(ID_ToggleShadows, ActorViewer::OnToggleButton)
|
||||
EVT_BUTTON(ID_ToggleStats, ActorViewer::OnToggleButton)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
static void SendToGame(const AtlasMessage::sEnvironmentSettings& settings)
|
||||
@ -158,8 +164,9 @@ static void SendToGame(const AtlasMessage::sEnvironmentSettings& settings)
|
||||
|
||||
ActorViewer::ActorViewer(wxWindow* parent)
|
||||
: wxFrame(parent, wxID_ANY, _("Actor Viewer"), wxDefaultPosition, wxSize(800, 600)),
|
||||
m_CurrentSpeed(0.f), m_Wireframe(false), m_BackgroundColour(wxColour(255, 255, 255)),
|
||||
m_Walking(true),
|
||||
m_CurrentSpeed(0.f), m_BackgroundColour(wxColour(255, 255, 255)),
|
||||
m_ToggledWalking(true), m_ToggledWireframe(false), m_ToggledGround(true),
|
||||
m_ToggledShadows(true), m_ToggledStats(false),
|
||||
m_ObjectSettings(m_ObjectSelection, AtlasMessage::eRenderView::ACTOR)
|
||||
{
|
||||
SetIcon(wxIcon(_T("ICON_ActorEditor")));
|
||||
@ -274,9 +281,12 @@ ActorViewer::ActorViewer(wxWindow* parent)
|
||||
playButtonSizer->Add(new wxButton(sidePanel, ID_Slow, _("Slow")), wxSizerFlags().Proportion(1));
|
||||
|
||||
optionButtonSizer->Add(new wxButton(sidePanel, ID_Edit, _("Edit actor")), wxSizerFlags().Expand());
|
||||
optionButtonSizer->Add(Tooltipped(new wxButton(sidePanel, ID_Wireframe, _("Wireframe")), _("Toggle wireframe / solid rendering")), wxSizerFlags().Expand());
|
||||
optionButtonSizer->Add(Tooltipped(new wxButton(sidePanel, ID_ToggleWireframe, _("Wireframe")), _("Toggle wireframe / solid rendering")), wxSizerFlags().Expand());
|
||||
optionButtonSizer->Add(Tooltipped(new wxButton(sidePanel, ID_Background, _("Background")), _("Change the background colour")), wxSizerFlags().Expand());
|
||||
optionButtonSizer->Add(Tooltipped(new wxButton(sidePanel, ID_Walking, _("Move")), _("Toggle movement along ground when playing walk/run animations")), wxSizerFlags().Expand());
|
||||
optionButtonSizer->Add(Tooltipped(new wxButton(sidePanel, ID_ToggleWalking, _("Move")), _("Toggle movement along ground when playing walk/run animations")), wxSizerFlags().Expand());
|
||||
optionButtonSizer->Add(Tooltipped(new wxButton(sidePanel, ID_ToggleGround, _("Ground")), _("Toggle the ground plane")), wxSizerFlags().Expand());
|
||||
optionButtonSizer->Add(Tooltipped(new wxButton(sidePanel, ID_ToggleShadows, _("Shadows")), _("Toggle shadow rendering")), wxSizerFlags().Expand());
|
||||
optionButtonSizer->Add(Tooltipped(new wxButton(sidePanel, ID_ToggleStats, _("Poly count")), _("Toggle polygon-count statistics - turn off ground and shadows for more useful data")), wxSizerFlags().Expand());
|
||||
|
||||
variationSizer->Add(new VariationControl(sidePanel, m_ObjectSettings), wxSizerFlags().Expand().Proportion(1));
|
||||
|
||||
@ -297,6 +307,7 @@ ActorViewer::ActorViewer(wxWindow* parent)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Pretend to have selected a unit, so the variations thing works properly
|
||||
m_ObjectSelection.push_back(0);
|
||||
|
||||
// Start by displaying the default non-existent actor
|
||||
@ -374,11 +385,6 @@ void ActorViewer::OnEditButton(wxCommandEvent& WXUNUSED(event))
|
||||
));
|
||||
}
|
||||
|
||||
void ActorViewer::OnWireframeButton(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
m_Wireframe = !m_Wireframe;
|
||||
POST_MESSAGE(SetViewParamB, (eRenderView::ACTOR, L"wireframe", m_Wireframe));
|
||||
}
|
||||
|
||||
void ActorViewer::OnBackgroundButton(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
@ -393,11 +399,22 @@ void ActorViewer::OnBackgroundButton(wxCommandEvent& WXUNUSED(event))
|
||||
}
|
||||
}
|
||||
|
||||
void ActorViewer::OnWalkingButton(wxCommandEvent& WXUNUSED(event))
|
||||
void ActorViewer::OnToggleButton(wxCommandEvent& event)
|
||||
{
|
||||
wxToolTip::Enable(true);
|
||||
SetToolTip(L"Hello world!");
|
||||
SetHelpText(L"Help text");
|
||||
m_Walking = !m_Walking;
|
||||
POST_MESSAGE(SetViewParamB, (eRenderView::ACTOR, L"walk", m_Walking));
|
||||
#define CASE(name, str) \
|
||||
case ID_Toggle##name: \
|
||||
m_Toggled##name = !m_Toggled##name; \
|
||||
POST_MESSAGE(SetViewParamB, (eRenderView::ACTOR, str, m_Toggled##name)); \
|
||||
break
|
||||
|
||||
switch (event.GetId())
|
||||
{
|
||||
CASE(Wireframe, L"wireframe");
|
||||
CASE(Walking, L"walk");
|
||||
CASE(Ground, L"ground");
|
||||
CASE(Shadows, L"shadows");
|
||||
CASE(Stats, L"stats");
|
||||
default:
|
||||
wxFAIL_MSG(_T("Incorrect ID in OnToggleButton"));
|
||||
}
|
||||
}
|
||||
|
@ -18,9 +18,8 @@ private:
|
||||
void OnAnimationSelection(wxCommandEvent& event);
|
||||
void OnSpeedButton(wxCommandEvent& event);
|
||||
void OnEditButton(wxCommandEvent& event);
|
||||
void OnWireframeButton(wxCommandEvent& event);
|
||||
void OnToggleButton(wxCommandEvent& event);
|
||||
void OnBackgroundButton(wxCommandEvent& event);
|
||||
void OnWalkingButton(wxCommandEvent& event);
|
||||
|
||||
void OnActorEdited();
|
||||
ObservableScopedConnections m_ActorConns;
|
||||
@ -32,9 +31,8 @@ private:
|
||||
|
||||
Observable<std::vector<AtlasMessage::ObjectID> > m_ObjectSelection;
|
||||
Observable<ObjectSettings> m_ObjectSettings;
|
||||
bool m_Wireframe;
|
||||
wxColour m_BackgroundColour;
|
||||
bool m_Walking;
|
||||
bool m_ToggledWireframe, m_ToggledWalking, m_ToggledGround, m_ToggledShadows, m_ToggledStats;
|
||||
|
||||
Observable<AtlasMessage::sEnvironmentSettings> m_EnvironmentSettings;
|
||||
ObservableScopedConnection m_EnvConn;
|
||||
|
@ -15,7 +15,9 @@
|
||||
#include "graphics/Unit.h"
|
||||
#include "graphics/UnitManager.h"
|
||||
#include "maths/MathUtil.h"
|
||||
#include "ps/Font.h"
|
||||
#include "ps/GameSetup/Config.h"
|
||||
#include "ps/ProfileViewer.h"
|
||||
#include "renderer/Renderer.h"
|
||||
#include "renderer/Scene.h"
|
||||
#include "renderer/SkyManager.h"
|
||||
@ -27,6 +29,8 @@ struct ActorViewerImpl : public Scene
|
||||
CStrW CurrentUnitAnim;
|
||||
float CurrentSpeed;
|
||||
bool WalkEnabled;
|
||||
bool GroundEnabled;
|
||||
bool ShadowsEnabled;
|
||||
|
||||
SColor4ub Background;
|
||||
|
||||
@ -35,7 +39,8 @@ struct ActorViewerImpl : public Scene
|
||||
// Simplistic implementation of the Scene interface
|
||||
void EnumerateObjects(const CFrustum& UNUSED(frustum), SceneCollector* c)
|
||||
{
|
||||
c->Submit(Terrain.GetPatch(0, 0));
|
||||
if (GroundEnabled)
|
||||
c->Submit(Terrain.GetPatch(0, 0));
|
||||
|
||||
if (Unit)
|
||||
c->SubmitRecursive(Unit->GetModel());
|
||||
@ -152,9 +157,16 @@ void ActorViewer::SetBackgroundColour(const SColor4ub& colour)
|
||||
m.Terrain.SetBaseColour(colour);
|
||||
}
|
||||
|
||||
void ActorViewer::SetWalkEnabled(bool enabled)
|
||||
void ActorViewer::SetWalkEnabled(bool enabled) { m.WalkEnabled = enabled; }
|
||||
void ActorViewer::SetGroundEnabled(bool enabled) { m.GroundEnabled = enabled; }
|
||||
void ActorViewer::SetShadowsEnabled(bool enabled) { m.ShadowsEnabled = enabled; }
|
||||
|
||||
void ActorViewer::SetStatsEnabled(bool enabled)
|
||||
{
|
||||
m.WalkEnabled = enabled;
|
||||
if (enabled)
|
||||
g_ProfileViewer.ShowTable("renderer");
|
||||
else
|
||||
g_ProfileViewer.ShowTable("");
|
||||
}
|
||||
|
||||
void ActorViewer::Render()
|
||||
@ -163,6 +175,10 @@ void ActorViewer::Render()
|
||||
|
||||
g_Renderer.SetClearColor(*(u32*)&m.Background);
|
||||
|
||||
// Disable shadows locally (avoid clobbering global state)
|
||||
bool oldShadows = g_Renderer.GetOptionBool(CRenderer::OPT_SHADOWS);
|
||||
g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWS, m.ShadowsEnabled);
|
||||
|
||||
g_Renderer.BeginFrame();
|
||||
|
||||
// Find the centre of the interesting region, in the middle of the patch
|
||||
@ -182,8 +198,41 @@ void ActorViewer::Render()
|
||||
|
||||
g_Renderer.RenderScene(&m);
|
||||
|
||||
// ....
|
||||
|
||||
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();
|
||||
|
||||
glPushAttrib(GL_ENABLE_BIT);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_BLEND);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
CFont font("console");
|
||||
font.Bind();
|
||||
|
||||
g_ProfileViewer.RenderProfile();
|
||||
|
||||
glPopAttrib();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix();
|
||||
|
||||
g_Renderer.EndFrame();
|
||||
|
||||
g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWS, oldShadows);
|
||||
|
||||
oglCheck();
|
||||
}
|
||||
|
||||
@ -195,7 +244,7 @@ void ActorViewer::Update(float dt)
|
||||
|
||||
CMatrix3D mat = m.Unit->GetModel()->GetTransform();
|
||||
|
||||
if (m.WalkEnabled)
|
||||
if (m.WalkEnabled && m.CurrentSpeed)
|
||||
{
|
||||
// Move the model by speed*dt forwards
|
||||
float z = mat.GetTranslation().Z;
|
||||
@ -219,5 +268,8 @@ bool ActorViewer::HasAnimation() const
|
||||
m.Unit->GetModel()->GetAnimation()->m_AnimDef->GetNumFrames() > 1)
|
||||
return true;
|
||||
|
||||
if (m.Unit && m.WalkEnabled && m.CurrentSpeed)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -13,8 +13,11 @@ public:
|
||||
|
||||
void SetActor(const CStrW& id, const CStrW& animation);
|
||||
CUnit* GetUnit();
|
||||
void SetWalkEnabled(bool enabled);
|
||||
void SetBackgroundColour(const SColor4ub& colour);
|
||||
void SetWalkEnabled(bool enabled);
|
||||
void SetGroundEnabled(bool enabled);
|
||||
void SetShadowsEnabled(bool enabled);
|
||||
void SetStatsEnabled(bool enabled);
|
||||
void Render();
|
||||
void Update(float dt);
|
||||
|
||||
|
@ -88,13 +88,15 @@ ActorViewer& ViewActor::GetActorViewer()
|
||||
void ViewActor::SetParam(const std::wstring& name, bool value)
|
||||
{
|
||||
if (name == L"wireframe")
|
||||
{
|
||||
g_Renderer.SetModelRenderMode(value ? WIREFRAME : SOLID);
|
||||
}
|
||||
else if (name == L"walk")
|
||||
{
|
||||
m_ActorViewer->SetWalkEnabled(value);
|
||||
}
|
||||
else if (name == L"ground")
|
||||
m_ActorViewer->SetGroundEnabled(value);
|
||||
else if (name == L"shadows")
|
||||
m_ActorViewer->SetShadowsEnabled(value);
|
||||
else if (name == L"stats")
|
||||
m_ActorViewer->SetStatsEnabled(value);
|
||||
}
|
||||
|
||||
void ViewActor::SetParam(const std::wstring& name, const AtlasMessage::Colour& value)
|
||||
|
Loading…
Reference in New Issue
Block a user