Index: ps/trunk/source/ps/XML/RelaxNG.cpp
===================================================================
--- ps/trunk/source/ps/XML/RelaxNG.cpp (revision 9122)
+++ ps/trunk/source/ps/XML/RelaxNG.cpp (revision 9123)
@@ -1,98 +1,103 @@
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#include "precompiled.h"
#include "RelaxNG.h"
#include "lib/timer.h"
#include "lib/utf8.h"
#include "ps/CLogger.h"
#include
TIMER_ADD_CLIENT(xml_validation);
RelaxNGValidator::RelaxNGValidator() :
m_Schema(NULL)
{
}
RelaxNGValidator::~RelaxNGValidator()
{
if (m_Schema)
xmlRelaxNGFree(m_Schema);
}
bool RelaxNGValidator::LoadGrammar(const std::string& grammar)
{
TIMER_ACCRUE(xml_validation);
debug_assert(m_Schema == NULL);
xmlRelaxNGParserCtxtPtr ctxt = xmlRelaxNGNewMemParserCtxt(grammar.c_str(), (int)grammar.size());
m_Schema = xmlRelaxNGParse(ctxt);
xmlRelaxNGFreeParserCtxt(ctxt);
if (m_Schema == NULL)
{
LOGERROR(L"RelaxNGValidator: Failed to compile schema");
return false;
}
return true;
}
bool RelaxNGValidator::Validate(const std::wstring& filename, const std::wstring& document)
{
+ std::string docutf8 = "" + utf8_from_wstring(document);
+
+ return ValidateEncoded(filename, docutf8);
+}
+
+bool RelaxNGValidator::ValidateEncoded(const std::wstring& filename, const std::string& document)
+{
TIMER_ACCRUE(xml_validation);
if (!m_Schema)
{
LOGERROR(L"RelaxNGValidator: No grammar loaded");
return false;
}
- std::string docutf8 = "" + utf8_from_wstring(document);
-
- xmlDocPtr doc = xmlReadMemory(docutf8.c_str(), (int)docutf8.size(), utf8_from_wstring(filename).c_str(), NULL, XML_PARSE_NONET);
+ xmlDocPtr doc = xmlReadMemory(document.c_str(), (int)document.size(), utf8_from_wstring(filename).c_str(), NULL, XML_PARSE_NONET);
if (doc == NULL)
{
LOGERROR(L"RelaxNGValidator: Failed to parse document");
return false;
}
xmlRelaxNGValidCtxtPtr ctxt = xmlRelaxNGNewValidCtxt(m_Schema);
int ret = xmlRelaxNGValidateDoc(ctxt, doc);
xmlRelaxNGFreeValidCtxt(ctxt);
xmlFreeDoc(doc);
if (ret == 0)
{
return true;
}
else if (ret > 0)
{
LOGERROR(L"RelaxNGValidator: Validation failed");
return false;
}
else
{
LOGERROR(L"RelaxNGValidator: Internal error %d", ret);
return false;
}
}
Index: ps/trunk/source/ps/XML/XMLWriter.h
===================================================================
--- ps/trunk/source/ps/XML/XMLWriter.h (revision 9122)
+++ ps/trunk/source/ps/XML/XMLWriter.h (revision 9123)
@@ -1,159 +1,167 @@
-/* Copyright (C) 2009 Wildfire Games.
+/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#ifndef INCLUDED_XMLWRITER
#define INCLUDED_XMLWRITER
/*
System for writing simple XML files, with human-readable formatting.
Example usage:
XML_Start();
{
XML_Element("Scenario");
{
XML_Element("Entities");
for (...)
{
XML_Element("Entity");
{
XML_Element("Template");
XML_Text(entity.name);
}
// Or equivalently:
XML_Setting("Template", entity.name);
{
XML_Element("Position");
XML_Attribute("x", entity.x);
XML_Attribute("y", entity.y);
XML_Attribute("z", entity.z);
}
{
XML_Element("Orientation");
XML_Attribute("angle", entity.angle);
}
}
}
}
Handle h = vfs_open("/test.xml", FILE_WRITE|FILE_NO_AIO);
XML_StoreVFS(h);
In general, "{ XML_Element(name); ... }" means " ... " -- the
scoping braces are important to indicate where an element ends.
XML_Attribute/XML_Setting are templated. To support more types, alter the
end of XMLWriter.cpp.
*/
// Starts generating a new XML file.
#define XML_Start() XMLWriter_File xml_file_
// Set pretty printing (newlines, tabs). Defaults to true.
#define XML_SetPrettyPrint(enabled) xml_file_.SetPrettyPrint(false)
// Add a comment to the XML file:
#define XML_Comment(text) xml_file_.Comment(text)
// Start a new element:
#define XML_Element(name) XMLWriter_Element xml_element_ (xml_file_, name)
// Add text to the interior of the current element: <...>text
#define XML_Text(text) xml_element_.Text(text, false)
// Add CDATA-escaped text to the interior of the current element: <...>
#define XML_CDATA(text) xml_element_.Text(text, true)
// Add an attribute to the current element: <... name="value" ...>
#define XML_Attribute(name, value) xml_element_.Attribute(name, value)
// Add a 'setting': value
#define XML_Setting(name, value) xml_element_.Setting(name, value)
+#define XML_WriteXMB(xero) xml_file_.XMB(xero)
+
// Create a VFS file from the XML data.
// Returns true on success, false (and logs an error) on failure.
#define XML_StoreVFS(vfs, pathname) xml_file_.StoreVFS(vfs, pathname)
// Returns the contents of the XML file as a UTF-8 byte stream in a const CStr&
// string. (Use CStr::FromUTF8 to get a Unicode string back.)
#define XML_GetOutput() xml_file_.GetOutput()
#include "ps/CStr.h"
#include "lib/file/vfs/vfs.h"
+class XMBElement;
+class XMBFile;
class XMLWriter_Element;
class XMLWriter_File
{
public:
XMLWriter_File();
void SetPrettyPrint(bool enabled) { m_PrettyPrint = enabled; }
void Comment(const char* text);
+ void XMB(const XMBFile& file);
+
bool StoreVFS(const PIVFS& vfs, const VfsPath& pathname);
const CStr& GetOutput();
private:
friend class XMLWriter_Element;
+ void ElementXMB(const XMBFile& file, XMBElement el);
+
void ElementStart(XMLWriter_Element* element, const char* name);
void ElementText(const char* text, bool cdata);
template void ElementAttribute(const char* name, const T& value, bool newelement);
void ElementClose();
void ElementEnd(const char* name, int type);
CStr Indent();
bool m_PrettyPrint;
CStr m_Data;
int m_Indent;
XMLWriter_Element* m_LastElement;
};
class XMLWriter_Element
{
public:
XMLWriter_Element(XMLWriter_File& file, const char* name);
~XMLWriter_Element();
template void Text(constCharPtr text, bool cdata);
template void Attribute(const char* name, T value) { m_File->ElementAttribute(name, value, false); }
template void Setting(const char* name, T value) { m_File->ElementAttribute(name, value, true); }
void Close(int type);
private:
friend class XMLWriter_File;
XMLWriter_File* m_File;
CStr m_Name;
int m_Type;
};
#endif // INCLUDED_XMLWRITER
Index: ps/trunk/source/ps/XML/RelaxNG.h
===================================================================
--- ps/trunk/source/ps/XML/RelaxNG.h (revision 9122)
+++ ps/trunk/source/ps/XML/RelaxNG.h (revision 9123)
@@ -1,38 +1,40 @@
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#ifndef INCLUDED_RELAXNG
#define INCLUDED_RELAXNG
typedef struct _xmlRelaxNG xmlRelaxNG;
typedef xmlRelaxNG *xmlRelaxNGPtr;
class RelaxNGValidator
{
public:
RelaxNGValidator();
~RelaxNGValidator();
bool LoadGrammar(const std::string& grammar);
bool Validate(const std::wstring& filename, const std::wstring& document);
+ bool ValidateEncoded(const std::wstring& filename, const std::string& document);
+
private:
xmlRelaxNGPtr m_Schema;
};
#endif // INCLUDED_RELAXNG
Index: ps/trunk/source/ps/XML/XMLWriter.cpp
===================================================================
--- ps/trunk/source/ps/XML/XMLWriter.cpp (revision 9122)
+++ ps/trunk/source/ps/XML/XMLWriter.cpp (revision 9123)
@@ -1,306 +1,323 @@
-/* Copyright (C) 2009 Wildfire Games.
+/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#include "precompiled.h"
#include "XMLWriter.h"
#include "ps/CLogger.h"
#include "ps/Filesystem.h"
+#include "ps/XML/Xeromyces.h"
#include "lib/utf8.h"
#include "lib/sysdep/cpu.h"
#include "maths/Fixed.h"
// TODO (maybe): Write to the file frequently, instead of buffering
// the entire file, so that large files get written faster.
namespace
{
CStr escapeAttributeValue(const char* input)
{
// Spec says:
// AttValue ::= '"' ([^<&"] | Reference)* '"'
// so > is allowed in attribute values, so we don't bother escaping it.
CStr ret = input;
ret.Replace("&", "&");
ret.Replace("<", "<");
ret.Replace("\"", """);
return ret;
}
CStr escapeCharacterData(const char* input)
{
// CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
CStr ret = input;
ret.Replace("&", "&");
ret.Replace("<", "<");
ret.Replace("]]>", "]]>");
return ret;
}
CStr escapeCDATA(const char* input)
{
CStr ret = input;
ret.Replace("]]>", "]]>]]>'
// This just avoids double-hyphens, and doesn't enforce the no-hyphen-at-end
// rule, since it's only used in contexts where there's already a space
// between this data and the -->.
CStr ret = input;
ret.Replace("--", "\xE2\x80\x90\xE2\x80\x90");
// replace with U+2010 HYPHEN, because it's close enough and it's
// probably nicer than inserting spaces or deleting hyphens or
// any alternative
return ret;
}
}
enum { EL_ATTR, EL_TEXT, EL_SUBEL };
XMLWriter_File::XMLWriter_File()
: m_Indent(0), m_LastElement(NULL),
m_PrettyPrint(true)
{
// Encoding is always UTF-8 - that's one of the only two guaranteed to be
// supported by XML parsers (along with UTF-16), and there's not much need
// to let people choose another.
m_Data = "\n";
}
bool XMLWriter_File::StoreVFS(const PIVFS& vfs, const VfsPath& pathname)
{
if (m_LastElement) debug_warn(L"ERROR: Saving XML while an element is still open");
const size_t size = m_Data.length();
shared_ptr data = io_Allocate(size);
memcpy(data.get(), m_Data.data(), size);
LibError ret = vfs->CreateFile(pathname, data, size);
if (ret < 0)
{
LOGERROR(L"Error saving XML data through VFS: %ld", ret);
return false;
}
return true;
}
const CStr& XMLWriter_File::GetOutput()
{
return m_Data;
}
+void XMLWriter_File::XMB(const XMBFile& file)
+{
+ ElementXMB(file, file.GetRoot());
+}
+
+void XMLWriter_File::ElementXMB(const XMBFile& file, XMBElement el)
+{
+ XMLWriter_Element writer(*this, file.GetElementString(el.GetNodeName()).c_str());
+
+ XERO_ITER_ATTR(el, attr)
+ writer.Attribute(file.GetAttributeString(attr.Name).c_str(), attr.Value);
+
+ XERO_ITER_EL(el, child)
+ ElementXMB(file, child);
+}
+
void XMLWriter_File::Comment(const char* text)
{
ElementStart(NULL, "!-- ");
m_Data += escapeComment(text);
m_Data += " -->";
--m_Indent;
}
CStr XMLWriter_File::Indent()
{
return std::string(m_Indent, '\t');
}
void XMLWriter_File::ElementStart(XMLWriter_Element* element, const char* name)
{
if (m_LastElement) m_LastElement->Close(EL_SUBEL);
m_LastElement = element;
if (m_PrettyPrint)
{
m_Data += "\n";
m_Data += Indent();
}
m_Data += "<";
m_Data += name;
++m_Indent;
}
void XMLWriter_File::ElementClose()
{
m_Data += ">";
}
void XMLWriter_File::ElementEnd(const char* name, int type)
{
--m_Indent;
m_LastElement = NULL;
switch (type)
{
case EL_ATTR:
m_Data += "/>";
break;
case EL_TEXT:
m_Data += "";
m_Data += name;
m_Data += ">";
break;
case EL_SUBEL:
if (m_PrettyPrint)
{
m_Data += "\n";
m_Data += Indent();
}
m_Data += "";
m_Data += name;
m_Data += ">";
break;
default:
debug_assert(0);
}
}
void XMLWriter_File::ElementText(const char* text, bool cdata)
{
if (cdata)
{
m_Data += "";
}
else
{
m_Data += escapeCharacterData(text);
}
}
XMLWriter_Element::XMLWriter_Element(XMLWriter_File& file, const char* name)
: m_File(&file), m_Name(name), m_Type(EL_ATTR)
{
m_File->ElementStart(this, name);
}
XMLWriter_Element::~XMLWriter_Element()
{
m_File->ElementEnd(m_Name.c_str(), m_Type);
}
void XMLWriter_Element::Close(int type)
{
if (m_Type == type)
return;
m_File->ElementClose();
m_Type = type;
}
// Template specialisations for various string types:
template <> void XMLWriter_Element::Text(const char* text, bool cdata)
{
Close(EL_TEXT);
m_File->ElementText(text, cdata);
}
template <> void XMLWriter_Element::Text(const wchar_t* text, bool cdata)
{
Text( CStrW(text).ToUTF8().c_str(), cdata );
}
//
template <> void XMLWriter_File::ElementAttribute(const char* name, const char* const& value, bool newelement)
{
if (newelement)
{
ElementStart(NULL, name);
m_Data += ">";
ElementText(value, false);
ElementEnd(name, EL_TEXT);
}
else
{
debug_assert(m_LastElement && m_LastElement->m_Type == EL_ATTR);
m_Data += " ";
m_Data += name;
m_Data += "=\"";
m_Data += escapeAttributeValue(value);
m_Data += "\"";
}
}
// Attribute/setting value-to-string template specialisations.
//
// These only deal with basic types. Anything more complicated should
// be converted into a basic type by whatever is making use of XMLWriter,
// to keep game-related logic out of the not-directly-game-related code here.
template <> void XMLWriter_File::ElementAttribute(const char* name, const CStr& value, bool newelement)
{
ElementAttribute(name, value.c_str(), newelement);
}
template <> void XMLWriter_File::ElementAttribute(const char* name, const std::string& value, bool newelement)
{
ElementAttribute(name, value.c_str(), newelement);
}
// Encode Unicode strings as UTF-8
template <> void XMLWriter_File::ElementAttribute(const char* name, const CStrW& value, bool newelement)
{
ElementAttribute(name, value.ToUTF8(), newelement);
}
template <> void XMLWriter_File::ElementAttribute(const char* name, const std::wstring& value, bool newelement)
{
ElementAttribute(name, utf8_from_wstring(value).c_str(), newelement);
}
template <> void XMLWriter_File::ElementAttribute(const char* name, const fixed& value, bool newelement)
{
ElementAttribute(name, value.ToString().c_str(), newelement);
}
template <> void XMLWriter_File::ElementAttribute(const char* name, const int& value, bool newelement)
{
std::stringstream ss;
ss << value;
ElementAttribute(name, ss.str().c_str(), newelement);
}
template <> void XMLWriter_File::ElementAttribute(const char* name, const unsigned int& value, bool newelement)
{
std::stringstream ss;
ss << value;
ElementAttribute(name, ss.str().c_str(), newelement);
}
template <> void XMLWriter_File::ElementAttribute(const char* name, const float& value, bool newelement)
{
std::stringstream ss;
ss << value;
ElementAttribute(name, ss.str().c_str(), newelement);
}
template <> void XMLWriter_File::ElementAttribute(const char* name, const double& value, bool newelement)
{
std::stringstream ss;
ss << value;
ElementAttribute(name, ss.str().c_str(), newelement);
}
Index: ps/trunk/source/ps/GameSetup/GameSetup.cpp
===================================================================
--- ps/trunk/source/ps/GameSetup/GameSetup.cpp (revision 9122)
+++ ps/trunk/source/ps/GameSetup/GameSetup.cpp (revision 9123)
@@ -1,1104 +1,1106 @@
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#include "precompiled.h"
#include "lib/app_hooks.h"
#include "lib/input.h"
#include "lib/lockfree.h"
#include "lib/ogl.h"
#include "lib/timer.h"
#include "lib/external_libraries/sdl.h"
#include "lib/file/common/file_stats.h"
#include "lib/res/h_mgr.h"
#include "lib/res/graphics/cursor.h"
#include "lib/res/sound/snd_mgr.h"
#include "lib/sysdep/cursor.h"
#include "lib/sysdep/cpu.h"
#include "lib/sysdep/gfx.h"
#include "lib/tex/tex.h"
#if OS_WIN
#include "lib/sysdep/os/win/wversion.h"
#endif
#include "ps/CConsole.h"
#include "ps/CLogger.h"
#include "ps/ConfigDB.h"
#include "ps/Filesystem.h"
#include "ps/Font.h"
#include "ps/Game.h"
#include "ps/Globals.h"
#include "ps/Hotkey.h"
#include "ps/Joystick.h"
#include "ps/Loader.h"
#include "ps/Overlay.h"
#include "ps/Profile.h"
#include "ps/ProfileViewer.h"
#include "ps/UserReport.h"
#include "ps/Util.h"
#include "ps/VideoMode.h"
#include "ps/World.h"
#include "graphics/CinemaTrack.h"
#include "graphics/GameView.h"
#include "graphics/LightEnv.h"
#include "graphics/MapReader.h"
#include "graphics/MaterialManager.h"
#include "graphics/ParticleEngine.h"
#include "graphics/TerrainTextureManager.h"
#include "renderer/Renderer.h"
#include "renderer/VertexBufferManager.h"
#include "maths/MathUtil.h"
#include "simulation2/Simulation2.h"
#include "scripting/ScriptingHost.h"
#include "scripting/ScriptGlue.h"
#include "scriptinterface/ScriptInterface.h"
#include "scriptinterface/ScriptStats.h"
#include "maths/scripting/JSInterface_Vector3D.h"
#include "ps/scripting/JSInterface_Console.h"
#include "gui/GUI.h"
#include "gui/GUIManager.h"
#include "gui/scripting/JSInterface_IGUIObject.h"
#include "gui/scripting/JSInterface_GUITypes.h"
#include "gui/scripting/ScriptFunctions.h"
#include "sound/JSI_Sound.h"
#include "network/NetServer.h"
#include "network/NetClient.h"
#include "ps/Pyrogenesis.h" // psSetLogDir
#include "ps/GameSetup/Atlas.h"
#include "ps/GameSetup/GameSetup.h"
#include "ps/GameSetup/Paths.h"
#include "ps/GameSetup/Config.h"
#include "ps/GameSetup/CmdLineArgs.h"
#include "ps/GameSetup/HWDetect.h"
#if !(OS_WIN || OS_MACOSX) // assume all other platforms use X11 for wxWidgets
#define MUST_INIT_X11 1
#include
#else
#define MUST_INIT_X11 0
#endif
#include
ERROR_GROUP(System);
ERROR_TYPE(System, SDLInitFailed);
ERROR_TYPE(System, VmodeFailed);
ERROR_TYPE(System, RequiredExtensionsMissing);
bool g_DoRenderGui = true;
bool g_DoRenderLogger = true;
bool g_DoRenderCursor = true;
static const int SANE_TEX_QUALITY_DEFAULT = 5; // keep in sync with code
static void SetTextureQuality(int quality)
{
int q_flags;
GLint filter;
retry:
// keep this in sync with SANE_TEX_QUALITY_DEFAULT
switch(quality)
{
// worst quality
case 0:
q_flags = OGL_TEX_HALF_RES|OGL_TEX_HALF_BPP;
filter = GL_NEAREST;
break;
// [perf] add bilinear filtering
case 1:
q_flags = OGL_TEX_HALF_RES|OGL_TEX_HALF_BPP;
filter = GL_LINEAR;
break;
// [vmem] no longer reduce resolution
case 2:
q_flags = OGL_TEX_HALF_BPP;
filter = GL_LINEAR;
break;
// [vmem] add mipmaps
case 3:
q_flags = OGL_TEX_HALF_BPP;
filter = GL_NEAREST_MIPMAP_LINEAR;
break;
// [perf] better filtering
case 4:
q_flags = OGL_TEX_HALF_BPP;
filter = GL_LINEAR_MIPMAP_LINEAR;
break;
// [vmem] no longer reduce bpp
case SANE_TEX_QUALITY_DEFAULT:
q_flags = OGL_TEX_FULL_QUALITY;
filter = GL_LINEAR_MIPMAP_LINEAR;
break;
// [perf] add anisotropy
case 6:
// TODO: add anisotropic filtering
q_flags = OGL_TEX_FULL_QUALITY;
filter = GL_LINEAR_MIPMAP_LINEAR;
break;
// invalid
default:
debug_warn(L"SetTextureQuality: invalid quality");
quality = SANE_TEX_QUALITY_DEFAULT;
// careful: recursion doesn't work and we don't want to duplicate
// the "sane" default values.
goto retry;
}
ogl_tex_set_defaults(q_flags, filter);
}
//----------------------------------------------------------------------------
// GUI integration
//----------------------------------------------------------------------------
// display progress / description in loading screen
void GUI_DisplayLoadProgress(int percent, const wchar_t* pending_task)
{
g_ScriptingHost.GetScriptInterface().SetGlobal("g_Progress", percent, true);
g_ScriptingHost.GetScriptInterface().SetGlobal("g_LoadDescription", pending_task, true);
g_GUI->SendEventToAll("progress");
}
void Render()
{
ogl_WarnIfError();
CStr skystring = "255 0 255";
CFG_GET_USER_VAL("skycolor", String, skystring);
CColor skycol;
GUI::ParseString(skystring.FromUTF8(), skycol);
g_Renderer.SetClearColor(skycol.AsSColor4ub());
+ // prepare before starting the renderer frame
+ if (g_Game && g_Game->IsGameStarted())
+ g_Game->GetView()->BeginFrame();
+
// start new frame
g_Renderer.BeginFrame();
ogl_WarnIfError();
if (g_Game && g_Game->IsGameStarted())
- {
g_Game->GetView()->Render();
- }
ogl_WarnIfError();
// 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();
ogl_WarnIfError();
g_Renderer.RenderTextOverlays();
// Temp GUI message GeeTODO
PROFILE_START("render gui");
if(g_DoRenderGui) g_GUI->Draw();
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
glDisable(GL_ALPHA_TEST);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
// Added --
glEnable(GL_TEXTURE_2D);
// -- GL
glLoadIdentity();
PROFILE_START("render console");
g_Console->Render();
PROFILE_END("render console");
ogl_WarnIfError();
PROFILE_START("render logger");
if(g_DoRenderLogger) g_Logger->Render();
PROFILE_END("render logger");
ogl_WarnIfError();
// Profile information
PROFILE_START("render profiling");
g_ProfileViewer.RenderProfile();
PROFILE_END("render profiling");
ogl_WarnIfError();
// Draw the cursor (or set the Windows cursor, on Windows)
if (g_DoRenderCursor)
{
PROFILE("render cursor");
CStrW cursorName = g_CursorName;
if (cursorName.empty())
{
cursor_draw(g_VFS, NULL, g_mouse_x, g_yres-g_mouse_y);
}
else
{
if (cursor_draw(g_VFS, cursorName.c_str(), g_mouse_x, g_yres-g_mouse_y) < 0)
LOGWARNING(L"Failed to draw cursor '%ls'", cursorName.c_str());
}
}
// restore
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glPopAttrib();
g_Renderer.EndFrame();
ogl_WarnIfError();
}
static void RegisterJavascriptInterfaces()
{
// maths
JSI_Vector3D::init();
// graphics
CGameView::ScriptingInit();
// renderer
CRenderer::ScriptingInit();
// sound
JSI_Sound::ScriptingInit();
// ps
JSI_Console::init();
// GUI
CGUI::ScriptingInit();
GuiScriptingInit(g_ScriptingHost.GetScriptInterface());
}
static void InitScripting()
{
TIMER(L"InitScripting");
// Create the scripting host. This needs to be done before the GUI is created.
// [7ms]
new ScriptingHost;
RegisterJavascriptInterfaces();
}
#if 0
// disabled because the file cache doesn't work (http://trac.wildfiregames.com/ticket/611)
static size_t OperatingSystemFootprint()
{
#if OS_WIN
switch(wversion_Number())
{
case WVERSION_2K:
case WVERSION_XP:
return 150;
case WVERSION_XP64:
return 200;
default: // don't warn about newer Windows versions
case WVERSION_VISTA:
return 300;
case WVERSION_7:
return 250;
}
#else
return 200;
#endif
}
static size_t ChooseCacheSize()
{
// (all sizes in MiB)
const size_t total = os_cpu_MemorySize();
const size_t available = os_cpu_MemoryAvailable();
debug_assert(total >= available);
const size_t inUse = total-available;
size_t os = OperatingSystemFootprint();
debug_assert(total >= os/2);
size_t apps = (inUse > os)? (inUse - os) : 0;
size_t game = 300;
size_t cache = 200;
// plenty of memory
if(os + apps + game + cache < total)
{
cache = total - os - apps - game;
}
else // below min-spec
{
// assume kernel+other apps will be swapped out
os = 9*os/10;
apps = 2*apps/3;
game = 3*game/4;
if(os + apps + game + cache < total)
cache = total - os - apps - game;
else
{
cache = 50;
debug_printf(L"Warning: memory size (%d MiB, %d used) is rather low\n", total, available);
}
}
// total data is currently about 500 MiB, and not all of it
// is used at once, so don't use more than that.
// (this also ensures the byte count will fit in size_t and
// avoids using up too much address space)
cache = std::min(cache, (size_t)500);
debug_printf(L"Cache: %d (total: %d; available: %d)\n", cache, total, available);
return cache*MiB;
}
#else
static size_t ChooseCacheSize()
{
return 32*MiB;
}
#endif
ErrorReactionInternal psDisplayError(const wchar_t* UNUSED(text), size_t UNUSED(flags))
{
// If we're fullscreen, then sometimes (at least on some particular drivers on Linux)
// displaying the error dialog hangs the desktop since the dialog box is behind the
// fullscreen window. So we just force the game to windowed mode before displaying the dialog.
// (But only if we're in the main thread, and not if we're being reentrant.)
if (ThreadUtil::IsMainThread())
{
static bool reentering = false;
if (!reentering)
{
reentering = true;
g_VideoMode.SetFullscreen(false);
reentering = false;
}
}
// We don't actually implement the error display here, so return appropriately
return ERI_NOT_IMPLEMENTED;
}
static void InitVfs(const CmdLineArgs& args)
{
TIMER(L"InitVfs");
const Paths paths(args);
OsPath logs(paths.Logs());
CreateDirectories(logs, 0700);
psSetLogDir(logs);
// desired location for crashlog is now known. update AppHooks ASAP
// (particularly before the following error-prone operations):
AppHooks hooks = {0};
hooks.bundle_logs = psBundleLogs;
hooks.get_log_dir = psLogDir;
hooks.display_error = psDisplayError;
app_hooks_update(&hooks);
const size_t cacheSize = ChooseCacheSize();
g_VFS = CreateVfs(cacheSize);
g_VFS->Mount(L"screenshots/", paths.Data()/"screenshots/");
const OsPath readonlyConfig = paths.RData()/"config/";
g_VFS->Mount(L"config/", readonlyConfig);
if(readonlyConfig != paths.Config())
g_VFS->Mount(L"config/", paths.Config());
g_VFS->Mount(L"cache/", paths.Cache(), VFS_MOUNT_ARCHIVABLE); // (adding XMBs to archive speeds up subsequent reads)
std::vector mods = args.GetMultiple("mod");
mods.push_back("public");
if(!args.Has("onlyPublicFiles"))
mods.push_back("internal");
OsPath modArchivePath = paths.Cache()/"mods";
OsPath modLoosePath = paths.RData()/"mods";
for (size_t i = 0; i < mods.size(); ++i)
{
size_t priority = i;
size_t flags = VFS_MOUNT_WATCH|VFS_MOUNT_ARCHIVABLE|VFS_MOUNT_MUST_EXIST;
OsPath modName(mods[i]);
g_VFS->Mount(L"", modLoosePath / modName/"", flags, priority);
g_VFS->Mount(L"", modArchivePath / modName/"", flags, priority);
}
// note: don't bother with g_VFS->TextRepresentation - directories
// haven't yet been populated and are empty.
}
static void InitPs(bool setup_gui, const CStrW& gui_page, CScriptVal initData)
{
{
// console
TIMER(L"ps_console");
g_Console->UpdateScreenSize(g_xres, g_yres);
// Calculate and store the line spacing
CFont font(CONSOLE_FONT);
g_Console->m_iFontHeight = font.GetLineSpacing();
g_Console->m_iFontWidth = font.GetCharacterWidth(L'C');
g_Console->m_charsPerPage = (size_t)(g_xres / g_Console->m_iFontWidth);
// Offset by an arbitrary amount, to make it fit more nicely
g_Console->m_iFontOffset = 7;
}
// hotkeys
{
TIMER(L"ps_lang_hotkeys");
LoadHotkeys();
}
if (!setup_gui)
{
// We do actually need *some* kind of GUI loaded, so use the
// (currently empty) Atlas one
g_GUI->SwitchPage(L"page_atlas.xml", initData);
return;
}
// GUI uses VFS, so this must come after VFS init.
g_GUI->SwitchPage(gui_page, initData);
}
static void InitInput()
{
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
g_Joystick.Initialise();
// register input handlers
// This stack is constructed so the first added, will be the last
// one called. This is important, because each of the handlers
// has the potential to block events to go further down
// in the chain. I.e. the last one in the list added, is the
// only handler that can block all messages before they are
// processed.
in_add_handler(game_view_handler);
in_add_handler(CProfileViewer::InputThunk);
in_add_handler(conInputHandler);
in_add_handler(HotkeyInputHandler);
// gui_handler needs to be registered after (i.e. called before!) the
// hotkey handler so that input boxes can be typed in without
// setting off hotkeys.
in_add_handler(gui_handler);
// must be registered after (called before) the GUI which relies on these globals
in_add_handler(GlobalsInputHandler);
}
static void ShutdownPs()
{
SAFE_DELETE(g_GUI);
SAFE_DELETE(g_Console);
// disable the special Windows cursor, or free textures for OGL cursors
cursor_draw(g_VFS, 0, g_mouse_x, g_yres-g_mouse_y);
}
static void InitRenderer()
{
TIMER(L"InitRenderer");
if(g_NoGLS3TC)
ogl_tex_override(OGL_TEX_S3TC, OGL_TEX_DISABLE);
if(g_NoGLAutoMipmap)
ogl_tex_override(OGL_TEX_AUTO_MIPMAP_GEN, OGL_TEX_DISABLE);
// create renderer
new CRenderer;
// set renderer options from command line options - NOVBO must be set before opening the renderer
g_Renderer.SetOptionBool(CRenderer::OPT_NOVBO,g_NoGLVBO);
g_Renderer.SetOptionBool(CRenderer::OPT_NOFRAMEBUFFEROBJECT,g_NoGLFramebufferObject);
g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWS,g_Shadows);
g_Renderer.SetOptionBool(CRenderer::OPT_FANCYWATER,g_FancyWater);
g_Renderer.SetRenderPath(CRenderer::GetRenderPathByName(g_RenderPath));
g_Renderer.SetOptionFloat(CRenderer::OPT_LODBIAS, g_LodBias);
// create terrain related stuff
new CTerrainTextureManager;
// create the material manager
new CMaterialManager;
g_Renderer.Open(g_xres,g_yres);
// Setup lighting environment. Since the Renderer accesses the
// lighting environment through a pointer, this has to be done before
// the first Frame.
g_Renderer.SetLightEnv(&g_LightEnv);
// I haven't seen the camera affecting GUI rendering and such, but the
// viewport has to be updated according to the video mode
SViewPort vp;
vp.m_X=0;
vp.m_Y=0;
vp.m_Width=g_xres;
vp.m_Height=g_yres;
g_Renderer.SetViewport(vp);
ColorActivateFastImpl();
}
static void InitSDL()
{
if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_NOPARACHUTE) < 0)
{
LOGERROR(L"SDL library initialization failed: %hs", SDL_GetError());
throw PSERROR_System_SDLInitFailed();
}
atexit(SDL_Quit);
SDL_EnableUNICODE(1);
}
static void ShutdownSDL()
{
SDL_Quit();
sys_cursor_reset();
}
void EndGame()
{
SAFE_DELETE(g_NetServer);
SAFE_DELETE(g_NetClient);
SAFE_DELETE(g_Game);
}
void Shutdown(int UNUSED(flags))
{
EndGame();
ShutdownPs(); // Must delete g_GUI before g_ScriptingHost
in_reset_handlers();
// destroy actor related stuff
TIMER_BEGIN(L"shutdown actor stuff");
delete &g_MaterialManager;
TIMER_END(L"shutdown actor stuff");
// destroy terrain related stuff
TIMER_BEGIN(L"shutdown TexMan");
delete &g_TexMan;
TIMER_END(L"shutdown TexMan");
// destroy renderer
TIMER_BEGIN(L"shutdown Renderer");
delete &g_Renderer;
g_VBMan.Shutdown();
TIMER_END(L"shutdown Renderer");
tex_codec_unregister_all();
TIMER_BEGIN(L"shutdown SDL");
ShutdownSDL();
TIMER_END(L"shutdown SDL");
g_VideoMode.Shutdown();
TIMER_BEGIN(L"shutdown UserReporter");
g_UserReporter.Deinitialize();
TIMER_END(L"shutdown UserReporter");
TIMER_BEGIN(L"shutdown ScriptingHost");
delete &g_ScriptingHost;
TIMER_END(L"shutdown ScriptingHost");
TIMER_BEGIN(L"shutdown ConfigDB");
delete &g_ConfigDB;
TIMER_END(L"shutdown ConfigDB");
// resource
// first shut down all resource owners, and then the handle manager.
TIMER_BEGIN(L"resource modules");
snd_shutdown();
g_VFS.reset();
// this forcibly frees all open handles (thus preventing real leaks),
// and makes further access to h_mgr impossible.
h_mgr_shutdown();
file_stats_dump();
TIMER_END(L"resource modules");
TIMER_BEGIN(L"shutdown misc");
timer_DisplayClientTotals();
CNetHost::Deinitialize();
SAFE_DELETE(g_ScriptStatsTable);
// should be last, since the above use them
SAFE_DELETE(g_Logger);
delete &g_Profiler;
delete &g_ProfileViewer;
TIMER_END(L"shutdown misc");
}
#if OS_UNIX
void SetDefaultIfLocaleInvalid()
{
// On misconfigured systems with incorrect locale settings, we'll die
// with a C++ exception when some code tries to use locales.
// To avoid death, we'll detect the problem here and warn the user and
// reset to the default C locale.
// For informing the user of the problem, use the list of env vars that
// glibc setlocale looks at. (LC_ALL is checked first, and LANG last.)
const char* const LocaleEnvVars[] = {
"LC_ALL",
"LC_COLLATE",
"LC_CTYPE",
"LC_MONETARY",
"LC_NUMERIC",
"LC_TIME",
"LC_MESSAGES",
"LANG"
};
try
{
// this constructor is similar to setlocale(LC_ALL, ""),
// but instead of returning NULL, it throws runtime_error
// when the first locale env variable found contains an invalid value
std::locale("");
}
catch (std::runtime_error&)
{
LOGWARNING(L"Invalid locale settings");
for (size_t i = 0; i < ARRAY_SIZE(LocaleEnvVars); i++)
{
if (char* envval = getenv(LocaleEnvVars[i]))
LOGWARNING(L" %hs=\"%hs\"", LocaleEnvVars[i], envval);
else
LOGWARNING(L" %hs=\"(unset)\"", LocaleEnvVars[i]);
}
// We should set LC_ALL since it overrides LANG
if (setenv("LC_ALL", std::locale::classic().name().c_str(), 1))
debug_warn(L"Invalid locale settings, and unable to set LC_ALL env variable.");
else
LOGWARNING(L"Setting LC_ALL env variable to: %hs", getenv("LC_ALL"));
}
}
#else
void SetDefaultIfLocaleInvalid()
{
// Do nothing on Windows
}
#endif
void EarlyInit()
{
// If you ever want to catch a particular allocation:
//_CrtSetBreakAlloc(232647);
ThreadUtil::SetMainThread();
debug_SetThreadName("main");
// add all debug_printf "tags" that we are interested in:
debug_filter_add(L"TIMER");
debug_filter_add(L"HRT");
cpu_ConfigureFloatingPoint();
timer_LatchStartTime();
SetDefaultIfLocaleInvalid();
// Because we do GL calls from a secondary thread, Xlib needs to
// be told to support multiple threads safely.
// This is needed for Atlas, but we have to call it before any other
// Xlib functions (e.g. the ones used when drawing the main menu
// before launching Atlas)
#if MUST_INIT_X11
int status = XInitThreads();
if (status == 0)
debug_printf(L"Error enabling thread-safety via XInitThreads\n");
#endif
// Initialise the low-quality rand function
srand(time(NULL)); // NOTE: this rand should *not* be used for simulation!
}
static bool Autostart(const CmdLineArgs& args);
void Init(const CmdLineArgs& args, int UNUSED(flags))
{
h_mgr_init();
// Do this as soon as possible, because it chdirs
// and will mess up the error reporting if anything
// crashes before the working directory is set.
InitVfs(args);
// This must come after VFS init, which sets the current directory
// (required for finding our output log files).
g_Logger = new CLogger;
// Special command-line mode to dump the entity schemas instead of running the game.
// (This must be done after loading VFS etc, but should be done before wasting time
// on anything else.)
if (args.Has("dumpSchema"))
{
CSimulation2 sim(NULL, NULL);
sim.LoadDefaultScripts();
std::ofstream f("entity.rng", std::ios_base::out | std::ios_base::trunc);
f << sim.GenerateSchema();
std::cout << "Generated entity.rng\n";
exit(0);
}
// override ah_translate with our i18n code.
AppHooks hooks = {0};
hooks.translate = psTranslate;
hooks.translate_free = psTranslateFree;
app_hooks_update(&hooks);
// Set up the console early, so that debugging
// messages can be logged to it. (The console's size
// and fonts are set later in InitPs())
g_Console = new CConsole();
CNetHost::Initialize();
new CProfileViewer;
new CProfileManager; // before any script code
g_ScriptStatsTable = new CScriptStatsTable;
g_ProfileViewer.AddRootTable(g_ScriptStatsTable);
InitScripting(); // before GUI
// g_ConfigDB, command line args, globals
CONFIG_Init(args);
if (!g_Quickstart)
g_UserReporter.Initialize(); // after config
}
void InitGraphics(const CmdLineArgs& args, int flags)
{
const bool setup_vmode = (flags & INIT_HAVE_VMODE) == 0;
if(setup_vmode)
{
InitSDL();
if (!g_VideoMode.InitSDL())
throw PSERROR_System_VmodeFailed(); // abort startup
SDL_WM_SetCaption("0 A.D.", "0 A.D.");
}
// needed by ogl_tex to detect broken gfx card/driver combos,
// but takes a while due to WMI startup, so make it optional.
if(!g_Quickstart)
gfx_detect();
RunHardwareDetection();
tex_codec_register_all();
const int quality = SANE_TEX_QUALITY_DEFAULT; // TODO: set value from config file
SetTextureQuality(quality);
ogl_WarnIfError();
if(!g_Quickstart)
{
WriteSystemInfo();
// note: no longer vfs_display here. it's dog-slow due to unbuffered
// file output and very rarely needed.
}
if(g_DisableAudio)
{
// speed up startup by disabling all sound
// (OpenAL init will be skipped).
// must be called before first snd_open.
snd_disable(true);
}
g_GUI = new CGUIManager(g_ScriptingHost.GetScriptInterface());
// (must come after SetVideoMode, since it calls ogl_Init)
const char* missing = ogl_HaveExtensions(0,
"GL_ARB_multitexture",
"GL_EXT_draw_range_elements",
"GL_ARB_texture_env_combine",
"GL_ARB_texture_env_dot3",
NULL);
if(missing)
{
wchar_t buf[500];
swprintf_s(buf, ARRAY_SIZE(buf),
L"The %hs extension doesn't appear to be available on your computer."
L" The game may still work, though - you are welcome to try at your own risk."
L" If not or it doesn't look right, upgrade your graphics card.",
missing
);
DEBUG_DISPLAY_ERROR(buf);
// TODO: i18n
}
if (!ogl_HaveExtension("GL_ARB_texture_env_crossbar"))
{
DEBUG_DISPLAY_ERROR(
L"The GL_ARB_texture_env_crossbar extension doesn't appear to be available on your computer."
L" Shadows are not available and overall graphics quality might suffer."
L" You are advised to try installing newer drivers and/or upgrade your graphics card.");
g_Shadows = false;
}
ogl_WarnIfError();
InitRenderer();
InitInput();
ogl_WarnIfError();
if (!Autostart(args))
{
const bool setup_gui = ((flags & INIT_NO_GUI) == 0);
InitPs(setup_gui, L"page_pregame.xml", JSVAL_VOID);
}
}
void RenderGui(bool RenderingState)
{
g_DoRenderGui = RenderingState;
}
void RenderLogger(bool RenderingState)
{
g_DoRenderLogger = RenderingState;
}
void RenderCursor(bool RenderingState)
{
g_DoRenderCursor = RenderingState;
}
static bool Autostart(const CmdLineArgs& args)
{
/*
* Handle various command-line options, for quick testing of various features:
* -autostart=mapname -- single-player
* -autostart=mapname -autostart-playername=Player -autostart-host -autostart-players=2 -- multiplayer host, wait for 2 players
* -autostart=mapname -autostart-playername=Player -autostart-client -autostart-ip=127.0.0.1 -- multiplayer client, connect to 127.0.0.1
* -autostart=scriptname -autostart-random=104 -- random map, seed 104 (default is 0, for random choose -1)
*/
CStr autoStartName = args.Get("autostart");
if (autoStartName.empty())
return false;
g_Game = new CGame();
ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface();
CScriptValRooted attrs;
scriptInterface.Eval("({})", attrs);
CScriptVal settings;
scriptInterface.Eval("({})", settings);
CScriptVal playerData;
scriptInterface.Eval("([])", playerData);
// Set different attributes for random or scenario game
if (args.Has("autostart-random"))
{
CStr seedArg = args.Get("autostart-random");
// Default seed is 0
uint32 seed = 0;
if (!seedArg.empty())
{
if (seedArg.compare("-1") == 0)
{ // Random seed value
seed = rand();
}
else
{
seed = seedArg.ToULong();
}
}
scriptInterface.SetProperty(attrs.get(), "script", std::string(autoStartName), false); // RMS name
scriptInterface.SetProperty(attrs.get(), "mapType", std::string("random"), false);
// For random map, there are special settings
// TODO: Get these from command line - using defaults for now
scriptInterface.SetProperty(settings.get(), "Size", 12); // Random map size (in patches)
scriptInterface.SetProperty(settings.get(), "Seed", seed); // Random seed
scriptInterface.SetProperty(settings.get(), "BaseTerrain", std::string("grass1_spring")); // Base terrain texture
scriptInterface.SetProperty(settings.get(), "BaseHeight", 0); // Base terrain height
// Define players
// TODO: Get these from command line? - using defaults for now
size_t numPlayers = 2;
for (size_t i = 0; i < numPlayers; ++i)
{
CScriptVal player;
scriptInterface.Eval("({})", player);
scriptInterface.SetProperty(player.get(), "Civ", std::string("hele"));
scriptInterface.SetPropertyInt(playerData.get(), i, player);
}
}
else
{
scriptInterface.SetProperty(attrs.get(), "map", std::string(autoStartName), false);
scriptInterface.SetProperty(attrs.get(), "mapType", std::string("scenario"), false);
}
// Set player data for AIs
// attrs.settings = { PlayerData: [ { AI: ... }, ... ] }:
/*
* Handle command-line options for AI:
* -autostart-ai=1:dummybot -autostart-ai=2:dummybot -- adds the dummybot AI to players 1 and 2
*/
if (args.Has("autostart-ai"))
{
std::vector aiArgs = args.GetMultiple("autostart-ai");
for (size_t i = 0; i < aiArgs.size(); ++i)
{
CScriptVal player;
scriptInterface.Eval("({})", player);
int playerID = aiArgs[i].BeforeFirst(":").ToInt();
CStr name = aiArgs[i].AfterFirst(":");
scriptInterface.SetProperty(player.get(), "AI", std::string(name));
scriptInterface.SetPropertyInt(playerData.get(), playerID-1, player);
}
}
// Add player data to map settings
scriptInterface.SetProperty(settings.get(), "PlayerData", playerData);
// Add map settings to game attributes
scriptInterface.SetProperty(attrs.get(), "settings", settings);
CScriptVal mpInitData;
g_GUI->GetScriptInterface().Eval("({isNetworked:true, playerAssignments:{}})", mpInitData);
g_GUI->GetScriptInterface().SetProperty(mpInitData.get(), "attribs",
CScriptVal(g_GUI->GetScriptInterface().CloneValueFromOtherContext(scriptInterface, attrs.get())), false);
if (args.Has("autostart-host"))
{
InitPs(true, L"page_loading.xml", mpInitData.get());
size_t maxPlayers = 2;
if (args.Has("autostart-players"))
maxPlayers = args.Get("autostart-players").ToUInt();
g_NetServer = new CNetServer(maxPlayers);
g_NetServer->UpdateGameAttributes(attrs.get(), scriptInterface);
bool ok = g_NetServer->SetupConnection();
debug_assert(ok);
g_NetClient = new CNetClient(g_Game);
// TODO: player name, etc
g_NetClient->SetupConnection("127.0.0.1");
}
else if (args.Has("autostart-client"))
{
InitPs(true, L"page_loading.xml", mpInitData.get());
g_NetClient = new CNetClient(g_Game);
// TODO: player name, etc
CStr ip = "127.0.0.1";
if (args.Has("autostart-ip"))
ip = args.Get("autostart-ip");
bool ok = g_NetClient->SetupConnection(ip);
debug_assert(ok);
}
else
{
g_Game->SetPlayerID(1);
g_Game->StartGame(attrs);
LDR_NonprogressiveLoad();
PSRETURN ret = g_Game->ReallyStartGame();
debug_assert(ret == PSRETURN_OK);
InitPs(true, L"page_session.xml", JSVAL_VOID);
}
return true;
}
Index: ps/trunk/source/ps/Game.h
===================================================================
--- ps/trunk/source/ps/Game.h (revision 9122)
+++ ps/trunk/source/ps/Game.h (revision 9123)
@@ -1,162 +1,172 @@
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#ifndef INCLUDED_GAME
#define INCLUDED_GAME
#include "ps/Errors.h"
#include
#include "scriptinterface/ScriptVal.h"
class CWorld;
class CSimulation2;
class CGameView;
class CNetTurnManager;
class IReplayLogger;
struct CColor;
/**
* The container that holds the rules, resources and attributes of the game.
* The CGame object is responsible for creating a game that is defined by
* a set of attributes provided. The CGame object is also responsible for
* maintaining the relations between CPlayer and CWorld, CSimulation and CWorld.
**/
class CGame
{
NONCOPYABLE(CGame);
/**
* pointer to the CWorld object representing the game world.
**/
CWorld *m_World;
/**
* pointer to the CSimulation2 object operating on the game world.
**/
CSimulation2 *m_Simulation2;
/**
* pointer to the CGameView object representing the view into the game world.
**/
CGameView *m_GameView;
/**
* the game has been initialized and ready for use if true.
**/
bool m_GameStarted;
/**
* scale multiplier for simulation rate.
**/
float m_SimRate;
int m_PlayerID;
CNetTurnManager* m_TurnManager;
public:
enum ENetStatus
{
NET_WAITING_FOR_CONNECT, /// we have loaded the game; waiting for other players to finish loading
NET_NORMAL /// running the game
};
CGame(bool disableGraphics = false);
~CGame();
/**
* the game is paused and no updates will be performed if true.
**/
bool m_Paused;
void StartGame(const CScriptValRooted& attribs);
PSRETURN ReallyStartGame();
/*
Perform all per-frame updates
*/
bool Update(double deltaTime, bool doInterpolate = true);
void Interpolate(float frameLength);
int GetPlayerID();
void SetPlayerID(int playerID);
+ /**
+ * Retrieving player colours from scripts is slow, so this updates an
+ * internal cache of all players' colours.
+ * Call this just before rendering, so it will always have the latest
+ * colours.
+ */
+ void CachePlayerColours();
+
CColor GetPlayerColour(int player) const;
/**
* Get m_GameStarted.
*
* @return bool the value of m_GameStarted.
**/
inline bool IsGameStarted() const
{
return m_GameStarted;
}
/**
* Get the pointer to the game world object.
*
* @return CWorld * the value of m_World.
**/
inline CWorld *GetWorld()
{ return m_World; }
/**
* Get the pointer to the game view object.
*
* @return CGameView * the value of m_GameView.
**/
inline CGameView *GetView()
{ return m_GameView; }
/**
* Get the pointer to the simulation2 object.
*
* @return CSimulation2 * the value of m_Simulation2.
**/
inline CSimulation2 *GetSimulation2()
{ return m_Simulation2; }
/**
* Set the simulation scale multiplier.
*
* @param simRate Float value to set m_SimRate to.
* Because m_SimRate is also used to
* scale TimeSinceLastFrame it must be
* clamped to 0.0f.
**/
inline void SetSimRate(float simRate)
{ m_SimRate = std::max(simRate, 0.0f); }
/**
* Replace the current turn manager.
* This class will take ownership of the pointer.
*/
void SetTurnManager(CNetTurnManager* turnManager);
CNetTurnManager* GetTurnManager() const
{ return m_TurnManager; }
IReplayLogger& GetReplayLogger() const
{ return *m_ReplayLogger; }
private:
void RegisterInit(const CScriptValRooted& attribs);
IReplayLogger* m_ReplayLogger;
CScriptValRooted m_RegisteredAttribs;
+
+ std::vector m_PlayerColours;
};
extern CGame *g_Game;
#endif
Index: ps/trunk/source/ps/Game.cpp
===================================================================
--- ps/trunk/source/ps/Game.cpp (revision 9122)
+++ ps/trunk/source/ps/Game.cpp (revision 9123)
@@ -1,292 +1,313 @@
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#include "precompiled.h"
#include "Game.h"
#include "graphics/GameView.h"
#include "graphics/LOSTexture.h"
#include "graphics/UnitManager.h"
#include "lib/timer.h"
#include "network/NetClient.h"
#include "network/NetServer.h"
#include "network/NetTurnManager.h"
#include "ps/CConsole.h"
#include "ps/CLogger.h"
#include "ps/CStr.h"
#include "ps/Loader.h"
#include "ps/LoaderThunks.h"
#include "ps/Overlay.h"
#include "ps/Profile.h"
#include "ps/Replay.h"
#include "ps/World.h"
#include "scripting/ScriptingHost.h"
#include "scriptinterface/ScriptInterface.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpPlayer.h"
#include "simulation2/components/ICmpPlayerManager.h"
#include "gui/GUIManager.h"
extern bool g_GameRestarted;
/**
* Globally accessible pointer to the CGame object.
**/
CGame *g_Game=NULL;
/**
* Constructor
*
**/
CGame::CGame(bool disableGraphics):
m_World(new CWorld(this)),
m_Simulation2(new CSimulation2(&m_World->GetUnitManager(), m_World->GetTerrain())),
m_GameView(disableGraphics ? NULL : new CGameView(this)),
m_GameStarted(false),
m_Paused(false),
m_SimRate(1.0f),
m_PlayerID(-1)
{
m_ReplayLogger = new CReplayLogger(m_Simulation2->GetScriptInterface());
// TODO: should use CDummyReplayLogger unless activated by cmd-line arg, perhaps?
// Need to set the CObjectManager references after various objects have
// been initialised, so do it here rather than via the initialisers above.
if (m_GameView)
m_World->GetUnitManager().SetObjectManager(m_GameView->GetObjectManager());
m_TurnManager = new CNetLocalTurnManager(*m_Simulation2, GetReplayLogger()); // this will get replaced if we're a net server/client
m_Simulation2->LoadDefaultScripts();
}
/**
* Destructor
*
**/
CGame::~CGame()
{
// Clear rooted value before destroying its context
m_RegisteredAttribs = CScriptValRooted();
// Again, the in-game call tree is going to be different to the main menu one.
if (CProfileManager::IsInitialised())
g_Profiler.StructuralReset();
delete m_TurnManager;
delete m_GameView;
delete m_Simulation2;
delete m_World;
delete m_ReplayLogger;
}
void CGame::SetTurnManager(CNetTurnManager* turnManager)
{
if (m_TurnManager)
delete m_TurnManager;
m_TurnManager = turnManager;
if (m_TurnManager)
m_TurnManager->SetPlayerID(m_PlayerID);
}
/**
* Initializes the game with the set of attributes provided.
* Makes calls to initialize the game view, world, and simulation objects.
* Calls are made to facilitate progress reporting of the initialization.
**/
void CGame::RegisterInit(const CScriptValRooted& attribs)
{
m_RegisteredAttribs = attribs; // save the attributes for ReallyStartGame
std::string mapType;
m_Simulation2->GetScriptInterface().GetProperty(attribs.get(), "mapType", mapType);
LDR_BeginRegistering();
RegMemFun(m_Simulation2, &CSimulation2::ProgressiveLoad, L"Simulation init", 1000);
// RC, 040804 - GameView needs to be initialized before World, otherwise GameView initialization
// overwrites anything stored in the map file that gets loaded by CWorld::Initialize with default
// values. At the minute, it's just lighting settings, but could be extended to store camera position.
// Storing lighting settings in the game view seems a little odd, but it's no big deal; maybe move it at
// some point to be stored in the world object?
if (m_GameView)
m_GameView->RegisterInit();
if (mapType == "scenario")
{
// Load scenario attributes
std::wstring mapFile;
m_Simulation2->GetScriptInterface().GetProperty(attribs.get(), "map", mapFile);
m_World->RegisterInit(mapFile, m_PlayerID);
}
else if (mapType == "random")
{
// Load random map attributes
std::wstring scriptFile;
CScriptValRooted settings;
m_Simulation2->GetScriptInterface().GetProperty(attribs.get(), "script", scriptFile);
m_Simulation2->GetScriptInterface().GetProperty(attribs.get(), "settings", settings);
m_World->RegisterInitRMS(scriptFile, settings, m_PlayerID);
}
LDR_EndRegistering();
}
/**
* Game initialization has been completed. Set game started flag and start the session.
*
* @return PSRETURN 0
**/
PSRETURN CGame::ReallyStartGame()
{
CScriptVal settings;
m_Simulation2->GetScriptInterface().GetProperty(m_RegisteredAttribs.get(), "settings", settings);
m_Simulation2->InitGame(settings);
// Call the reallyStartGame GUI function, but only if it exists
if (g_GUI && g_GUI->HasPages())
{
jsval fval, rval;
JSBool ok = JS_GetProperty(g_ScriptingHost.getContext(), g_GUI->GetScriptObject(), "reallyStartGame", &fval);
debug_assert(ok);
if (ok && !JSVAL_IS_VOID(fval))
ok = JS_CallFunctionValue(g_ScriptingHost.getContext(), g_GUI->GetScriptObject(), fval, 0, NULL, &rval);
}
if (g_NetClient)
g_NetClient->LoadFinished();
// We need to do an initial Interpolate call to set up all the models etc,
// because Update might never interpolate (e.g. if the game starts paused)
// and we could end up rendering before having set up any models (so they'd
// all be invisible)
Interpolate(0);
debug_printf(L"GAME STARTED, ALL INIT COMPLETE\n");
m_GameStarted=true;
// The call tree we've built for pregame probably isn't useful in-game.
if (CProfileManager::IsInitialised())
g_Profiler.StructuralReset();
// Mark terrain as modified so the minimap can repaint (is there a cleaner way of handling this?)
g_GameRestarted = true;
return 0;
}
int CGame::GetPlayerID()
{
return m_PlayerID;
}
void CGame::SetPlayerID(int playerID)
{
m_PlayerID = playerID;
if (m_TurnManager)
m_TurnManager->SetPlayerID(m_PlayerID);
}
void CGame::StartGame(const CScriptValRooted& attribs)
{
m_ReplayLogger->StartGame(attribs);
RegisterInit(attribs);
}
// TODO: doInterpolate is optional because Atlas interpolates explicitly,
// so that it has more control over the update rate. The game might want to
// do the same, and then doInterpolate should be redundant and removed.
/**
* Periodic heartbeat that controls the process.
* Simulation update is called and game status update is called.
*
* @param deltaTime Double. Elapsed time since last beat in seconds.
* @param doInterpolate Bool. Perform interpolation if true.
* @return bool false if it can't keep up with the desired simulation rate
* indicating that you might want to render less frequently.
**/
bool CGame::Update(double deltaTime, bool doInterpolate)
{
if (m_Paused)
return true;
if (!m_TurnManager)
return true;
deltaTime *= m_SimRate;
bool ok = true;
if (deltaTime)
{
// To avoid confusing the profiler, we need to trigger the new turn
// while we're not nested inside any PROFILE blocks
if (m_TurnManager->WillUpdate(deltaTime))
g_Profiler.Turn();
// At the normal sim rate, we currently want to render at least one
// frame per simulation turn, so let maxTurns be 1. But for fast-forward
// sim rates we want to allow more, so it's not bounded by framerate,
// so just use the sim rate itself as the number of turns per frame.
size_t maxTurns = (size_t)m_SimRate;
PROFILE("simulation update");
if (m_TurnManager->Update(deltaTime, maxTurns))
{
g_GUI->SendEventToAll("SimulationUpdate");
GetView()->GetLOSTexture().MakeDirty();
}
}
if (doInterpolate)
{
PROFILE("interpolate");
m_TurnManager->Interpolate(deltaTime);
}
return ok;
}
void CGame::Interpolate(float frameLength)
{
if (!m_TurnManager)
return;
m_TurnManager->Interpolate(frameLength);
}
+
static CColor BrokenColor(0.3f, 0.3f, 0.3f, 1.0f);
-CColor CGame::GetPlayerColour(int player) const
+
+void CGame::CachePlayerColours()
{
+ m_PlayerColours.clear();
+
CmpPtr cmpPlayerManager(*m_Simulation2, SYSTEM_ENTITY);
if (cmpPlayerManager.null())
+ return;
+
+ int numPlayers = cmpPlayerManager->GetNumPlayers();
+ m_PlayerColours.resize(numPlayers);
+
+ for (int i = 0; i < numPlayers; ++i)
+ {
+ CmpPtr cmpPlayer(*m_Simulation2, cmpPlayerManager->GetPlayerByID(i));
+ if (cmpPlayer.null())
+ m_PlayerColours[i] = BrokenColor;
+ else
+ m_PlayerColours[i] = cmpPlayer->GetColour();
+ }
+}
+
+
+CColor CGame::GetPlayerColour(int player) const
+{
+ if (player < 0 || player >= (int)m_PlayerColours.size())
return BrokenColor;
- CmpPtr cmpPlayer(*m_Simulation2, cmpPlayerManager->GetPlayerByID(player));
- if (cmpPlayer.null())
- return BrokenColor;
- return cmpPlayer->GetColour();
+
+ return m_PlayerColours[player];
}
Index: ps/trunk/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h
===================================================================
--- ps/trunk/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h (revision 9122)
+++ ps/trunk/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h (revision 9123)
@@ -1,84 +1,85 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#ifndef INCLUDED_SCENARIOEDITOR
#define INCLUDED_SCENARIOEDITOR
#include "General/AtlasWindowCommandProc.h"
#include "General/Observable.h"
#include "Tools/Common/ObjectSettings.h"
#include "Tools/Common/Tools.h"
#include "CustomControls/FileHistory/FileHistory.h"
#include "SectionLayout.h"
class ScriptInterface;
class ScenarioEditor : public wxFrame
{
public:
ScenarioEditor(wxWindow* parent, ScriptInterface& scriptInterface);
void OnClose(wxCloseEvent& event);
void OnTimer(wxTimerEvent& event);
void OnIdle(wxIdleEvent& event);
// void OnNew(wxCommandEvent& event);
void OnOpen(wxCommandEvent& event);
void OnSave(wxCommandEvent& event);
void OnSaveAs(wxCommandEvent& event);
void OnMRUFile(wxCommandEvent& event);
void OnQuit(wxCommandEvent& event);
void OnUndo(wxCommandEvent& event);
void OnRedo(wxCommandEvent& event);
void OnWireframe(wxCommandEvent& event);
void OnMessageTrace(wxCommandEvent& event);
void OnScreenshot(wxCommandEvent& event);
void OnMediaPlayer(wxCommandEvent& event);
void OnJavaScript(wxCommandEvent& event);
void OnCameraReset(wxCommandEvent& event);
+ void OnRenderPath(wxCommandEvent& event);
void OpenFile(const wxString& name);
static AtlasWindowCommandProc& GetCommandProc();
static float GetSpeedModifier();
ScriptInterface& GetScriptInterface() const { return m_ScriptInterface; }
ObjectSettings& GetObjectSettings() { return m_ObjectSettings; }
ToolManager& GetToolManager() { return m_ToolManager; }
private:
ScriptInterface& m_ScriptInterface;
ToolManager m_ToolManager;
wxTimer m_Timer;
SectionLayout m_SectionLayout;
Observable m_ObjectSettings;
void SetOpenFilename(const wxString& filename);
wxString m_OpenFilename;
FileHistory m_FileHistory;
DECLARE_EVENT_TABLE();
};
#endif // INCLUDED_SCENARIOEDITOR
Index: ps/trunk/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp
===================================================================
--- ps/trunk/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp (revision 9122)
+++ ps/trunk/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp (revision 9123)
@@ -1,253 +1,262 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#include "precompiled.h"
#include "Environment.h"
#include "LightControl.h"
#include "GameInterface/Messages.h"
#include "ScenarioEditor/ScenarioEditor.h"
#include "General/Observable.h"
#include "CustomControls/ColourDialog/ColourDialog.h"
using AtlasMessage::Shareable;
static Observable g_EnvironmentSettings;
const float M_PIf = 3.14159265f;
//////////////////////////////////////////////////////////////////////////
class VariableSliderBox : public wxPanel
{
static const int range = 1024;
public:
VariableSliderBox(wxWindow* parent, const wxString& label, Shareable& var, float min, float max)
: wxPanel(parent),
m_Var(var), m_Min(min), m_Max(max)
{
m_Conn = g_EnvironmentSettings.RegisterObserver(0, &VariableSliderBox::OnSettingsChange, this);
m_Sizer = new wxStaticBoxSizer(wxVERTICAL, this, label);
SetSizer(m_Sizer);
m_Slider = new wxSlider(this, -1, 0, 0, range);
m_Sizer->Add(m_Slider, wxSizerFlags().Expand());
}
void OnSettingsChange(const AtlasMessage::sEnvironmentSettings& WXUNUSED(env))
{
m_Slider->SetValue((m_Var - m_Min) * (range / (m_Max - m_Min)));
}
void OnScroll(wxScrollEvent& evt)
{
m_Var = m_Min + (m_Max - m_Min)*(evt.GetInt() / (float)range);
g_EnvironmentSettings.NotifyObserversExcept(m_Conn);
}
private:
ObservableScopedConnection m_Conn;
wxStaticBoxSizer* m_Sizer;
wxSlider* m_Slider;
Shareable& m_Var;
float m_Min, m_Max;
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(VariableSliderBox, wxPanel)
EVT_SCROLL(VariableSliderBox::OnScroll)
END_EVENT_TABLE()
//////////////////////////////////////////////////////////////////////////
class VariableListBox : public wxPanel
{
public:
VariableListBox(wxWindow* parent, const wxString& label, Shareable& var)
: wxPanel(parent),
m_Var(var)
{
m_Conn = g_EnvironmentSettings.RegisterObserver(0, &VariableListBox::OnSettingsChange, this);
m_Sizer = new wxStaticBoxSizer(wxVERTICAL, this, label);
SetSizer(m_Sizer);
m_Combo = new wxComboBox(this, -1, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxArrayString(), wxCB_READONLY),
m_Sizer->Add(m_Combo, wxSizerFlags().Expand());
}
void SetChoices(const std::vector& choices)
{
wxArrayString choices_arraystr;
for (size_t i = 0; i < choices.size(); ++i)
choices_arraystr.Add(choices[i].c_str());
m_Combo->Clear();
m_Combo->Append(choices_arraystr);
m_Combo->SetValue(m_Var.c_str());
}
void OnSettingsChange(const AtlasMessage::sEnvironmentSettings& WXUNUSED(env))
{
m_Combo->SetValue(m_Var.c_str());
}
void OnSelect(wxCommandEvent& WXUNUSED(evt))
{
m_Var = std::wstring(m_Combo->GetValue().c_str());
g_EnvironmentSettings.NotifyObserversExcept(m_Conn);
}
private:
ObservableScopedConnection m_Conn;
wxStaticBoxSizer* m_Sizer;
wxComboBox* m_Combo;
Shareable& m_Var;
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(VariableListBox, wxPanel)
EVT_COMBOBOX(wxID_ANY, VariableListBox::OnSelect)
END_EVENT_TABLE()
//////////////////////////////////////////////////////////////////////////
class VariableColourBox : public wxPanel
{
public:
VariableColourBox(wxWindow* parent, const wxString& label, Shareable& colour)
: wxPanel(parent),
m_Colour(colour)
{
m_Conn = g_EnvironmentSettings.RegisterObserver(0, &VariableColourBox::OnSettingsChange, this);
m_Sizer = new wxStaticBoxSizer(wxVERTICAL, this, label);
SetSizer(m_Sizer);
m_Button = new wxButton(this, -1);
m_Sizer->Add(m_Button, wxSizerFlags().Expand());
}
void OnSettingsChange(const AtlasMessage::sEnvironmentSettings& WXUNUSED(env))
{
UpdateButton();
}
void OnClick(wxCommandEvent& WXUNUSED(evt))
{
ColourDialog dlg (this, _T("Scenario Editor/LightingColour"),
wxColour(m_Colour->r, m_Colour->g, m_Colour->b));
if (dlg.ShowModal() == wxID_OK)
{
wxColour& c = dlg.GetColourData().GetColour();
m_Colour = AtlasMessage::Colour(c.Red(), c.Green(), c.Blue());
UpdateButton();
g_EnvironmentSettings.NotifyObserversExcept(m_Conn);
}
}
void UpdateButton()
{
m_Button->SetBackgroundColour(wxColour(m_Colour->r, m_Colour->g, m_Colour->b));
m_Button->SetLabel(wxString::Format(_T("%02X %02X %02X"), m_Colour->r, m_Colour->g, m_Colour->b));
int y = 3*m_Colour->r + 6*m_Colour->g + 1*m_Colour->b;
if (y > 1280)
m_Button->SetForegroundColour(wxColour(0, 0, 0));
else
m_Button->SetForegroundColour(wxColour(255, 255, 255));
}
private:
ObservableScopedConnection m_Conn;
wxStaticBoxSizer* m_Sizer;
wxButton* m_Button;
Shareable& m_Colour;
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(VariableColourBox, wxPanel)
EVT_BUTTON(wxID_ANY, VariableColourBox::OnClick)
END_EVENT_TABLE()
//////////////////////////////////////////////////////////////////////////
static void SendToGame(const AtlasMessage::sEnvironmentSettings& settings)
{
POST_COMMAND(SetEnvironmentSettings, (settings));
}
EnvironmentSidebar::EnvironmentSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer)
: Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer)
{
wxSizer* waterSizer = new wxGridSizer(2);
m_MainSizer->Add(waterSizer, wxSizerFlags().Expand());
waterSizer->Add(new VariableSliderBox(this, _("Water height"), g_EnvironmentSettings.waterheight, 0.f, 1.2f), wxSizerFlags().Expand());
waterSizer->Add(new VariableSliderBox(this, _("Water shininess"), g_EnvironmentSettings.watershininess, 0.f, 250.f), wxSizerFlags().Expand());
waterSizer->Add(new VariableSliderBox(this, _("Water waviness"), g_EnvironmentSettings.waterwaviness, 0.f, 10.f), wxSizerFlags().Expand());
waterSizer->Add(new VariableSliderBox(this, _("Water murkiness"), g_EnvironmentSettings.watermurkiness, 0.f, 1.f), wxSizerFlags().Expand());
waterSizer->Add(new VariableColourBox(this, _("Water colour"), g_EnvironmentSettings.watercolour), wxSizerFlags().Expand());
waterSizer->Add(new VariableColourBox(this, _("Water tint"), g_EnvironmentSettings.watertint), wxSizerFlags().Expand());
waterSizer->Add(new VariableColourBox(this, _("Reflection tint"), g_EnvironmentSettings.waterreflectiontint), wxSizerFlags().Expand());
waterSizer->Add(new VariableSliderBox(this, _("Refl. tint strength"), g_EnvironmentSettings.waterreflectiontintstrength, 0.f, 1.f), wxSizerFlags().Expand());
wxSizer* sunSizer = new wxGridSizer(2);
m_MainSizer->Add(sunSizer, wxSizerFlags().Expand().Border(wxTOP, 8));
sunSizer->Add(new VariableSliderBox(this, _("Sun rotation"), g_EnvironmentSettings.sunrotation, -M_PIf, M_PIf), wxSizerFlags().Expand());
sunSizer->Add(new VariableSliderBox(this, _("Sun elevation"), g_EnvironmentSettings.sunelevation, -M_PIf/2, M_PIf/2), wxSizerFlags().Expand());
sunSizer->Add(new VariableSliderBox(this, _("Sun overbrightness"), g_EnvironmentSettings.sunoverbrightness, 1.0f, 3.0f), wxSizerFlags().Expand());
+ sunSizer->Add(m_LightingModelList = new VariableListBox(this, _("Light model"), g_EnvironmentSettings.lightingmodel), wxSizerFlags().Expand());
+
m_MainSizer->Add(new LightControl(this, wxSize(150, 150), g_EnvironmentSettings));
m_MainSizer->Add(m_SkyList = new VariableListBox(this, _("Sky set"), g_EnvironmentSettings.skyset));
m_MainSizer->Add(new VariableColourBox(this, _("Sun colour"), g_EnvironmentSettings.suncolour));
m_MainSizer->Add(new VariableColourBox(this, _("Terrain ambient colour"), g_EnvironmentSettings.terraincolour));
m_MainSizer->Add(new VariableColourBox(this, _("Object ambient colour"), g_EnvironmentSettings.unitcolour));
m_Conn = g_EnvironmentSettings.RegisterObserver(0, &SendToGame);
}
void EnvironmentSidebar::OnFirstDisplay()
{
// Load the list of skies. (Can only be done now rather than in the constructor,
// after the game has been initialised.)
AtlasMessage::qGetSkySets qry_skysets;
qry_skysets.Post();
m_SkyList->SetChoices(*qry_skysets.skysets);
AtlasMessage::qGetEnvironmentSettings qry_env;
qry_env.Post();
g_EnvironmentSettings = qry_env.settings;
+
+ std::vector lightingModels;
+ lightingModels.push_back(L"old");
+ lightingModels.push_back(L"standard");
+ m_LightingModelList->SetChoices(lightingModels);
+
+
g_EnvironmentSettings.NotifyObservers();
// TODO: reupdate everything when loading a new map...
}
Index: ps/trunk/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.h
===================================================================
--- ps/trunk/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.h (revision 9122)
+++ ps/trunk/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.h (revision 9123)
@@ -1,35 +1,36 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#include "../Common/Sidebar.h"
#include "General/Observable.h"
class VariableListBox;
class EnvironmentSidebar : public Sidebar
{
public:
EnvironmentSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer);
protected:
virtual void OnFirstDisplay();
private:
+ VariableListBox* m_LightingModelList;
VariableListBox* m_SkyList;
ObservableScopedConnection m_Conn;
};
Index: ps/trunk/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp
===================================================================
--- ps/trunk/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp (revision 9122)
+++ ps/trunk/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp (revision 9123)
@@ -1,874 +1,902 @@
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#include "precompiled.h"
#include "ScenarioEditor.h"
#include "wx/busyinfo.h"
#include "wx/config.h"
#include "wx/evtloop.h"
#include "wx/ffile.h"
#include "wx/filename.h"
#include "wx/image.h"
#include "wx/tooltip.h"
#include "General/AtlasEventLoop.h"
#include "General/Datafile.h"
#include "CustomControls/HighResTimer/HighResTimer.h"
#include "CustomControls/Buttons/ToolButton.h"
#include "CustomControls/Canvas/Canvas.h"
#include "GameInterface/MessagePasser.h"
#include "GameInterface/Messages.h"
#include "AtlasScript/ScriptInterface.h"
#include "Misc/KeyMap.h"
#include "Tools/Common/Tools.h"
#include "Tools/Common/Brushes.h"
#include "Tools/Common/MiscState.h"
static HighResTimer g_Timer;
using namespace AtlasMessage;
//////////////////////////////////////////////////////////////////////////
// GL functions exported from DLL, and called by game (in a separate
// thread to the standard wx one)
ATLASDLLIMPEXP void Atlas_GLSetCurrent(void* canvas)
{
static_cast(canvas)->SetCurrent();
}
ATLASDLLIMPEXP void Atlas_GLSwapBuffers(void* canvas)
{
static_cast(canvas)->SwapBuffers();
}
//////////////////////////////////////////////////////////////////////////
class GameCanvas : public Canvas
{
public:
GameCanvas(ScenarioEditor& scenarioEditor, wxWindow* parent, int* attribList)
: Canvas(parent, attribList, wxWANTS_CHARS),
m_ScenarioEditor(scenarioEditor), m_MouseState(NONE), m_LastMouseState(NONE)
{
}
private:
bool KeyScroll(wxKeyEvent& evt, bool enable)
{
int dir;
switch (evt.GetKeyCode())
{
case 'A': case WXK_LEFT: dir = eScrollConstantDir::LEFT; break;
case 'D': case WXK_RIGHT: dir = eScrollConstantDir::RIGHT; break;
case 'W': case WXK_UP: dir = eScrollConstantDir::FORWARDS; break;
case 'S': case WXK_DOWN: dir = eScrollConstantDir::BACKWARDS; break;
case 'E': case ']': dir = eScrollConstantDir::CLOCKWISE; break;
case 'Q': case '[': dir = eScrollConstantDir::ANTICLOCKWISE; break;
case WXK_SHIFT: case WXK_CONTROL: dir = -1; break;
default: return false;
}
float speed = 120.f * ScenarioEditor::GetSpeedModifier();
if (dir == -1) // changed modifier keys - update all currently-scrolling directions
{
if (wxGetKeyState(WXK_LEFT)) POST_MESSAGE(ScrollConstant, (eRenderView::GAME, eScrollConstantDir::LEFT, speed));
if (wxGetKeyState(WXK_RIGHT)) POST_MESSAGE(ScrollConstant, (eRenderView::GAME, eScrollConstantDir::RIGHT, speed));
if (wxGetKeyState(WXK_UP)) POST_MESSAGE(ScrollConstant, (eRenderView::GAME, eScrollConstantDir::FORWARDS, speed));
if (wxGetKeyState(WXK_DOWN)) POST_MESSAGE(ScrollConstant, (eRenderView::GAME, eScrollConstantDir::BACKWARDS, speed));
if (wxGetKeyState((wxKeyCode)']')) POST_MESSAGE(ScrollConstant, (eRenderView::GAME, eScrollConstantDir::CLOCKWISE, speed));
if (wxGetKeyState((wxKeyCode)'[')) POST_MESSAGE(ScrollConstant, (eRenderView::GAME, eScrollConstantDir::ANTICLOCKWISE, speed));
return false;
}
else
{
POST_MESSAGE(ScrollConstant, (eRenderView::GAME, dir, enable ? speed : 0.0f));
return true;
}
}
void OnKeyDown(wxKeyEvent& evt)
{
if (m_ScenarioEditor.GetToolManager().GetCurrentTool().OnKey(evt, ITool::KEY_DOWN))
{
// Key event has been handled by the tool, so don't try
// to use it for camera motion too
return;
}
if (KeyScroll(evt, true))
return;
// Slight hack: Only pass 'special' keys; normal keys will generate a translated Char event instead
if (evt.GetKeyCode() >= 256)
POST_MESSAGE(GuiKeyEvent, (GetSDLKeyFromWxKeyCode(evt.GetKeyCode()), evt.GetUnicodeKey(), true));
evt.Skip();
}
void OnKeyUp(wxKeyEvent& evt)
{
if (m_ScenarioEditor.GetToolManager().GetCurrentTool().OnKey(evt, ITool::KEY_UP))
return;
if (KeyScroll(evt, false))
return;
// Slight hack: Only pass 'special' keys; normal keys will generate a translated Char event instead
if (evt.GetKeyCode() >= 256)
POST_MESSAGE(GuiKeyEvent, (GetSDLKeyFromWxKeyCode(evt.GetKeyCode()), evt.GetUnicodeKey(), false));
evt.Skip();
}
void OnChar(wxKeyEvent& evt)
{
if (m_ScenarioEditor.GetToolManager().GetCurrentTool().OnKey(evt, ITool::KEY_CHAR))
return;
// Alt+enter toggles fullscreen
if (evt.GetKeyCode() == WXK_RETURN && wxGetKeyState(WXK_ALT))
{
if (m_ScenarioEditor.IsFullScreen())
m_ScenarioEditor.ShowFullScreen(false);
else
m_ScenarioEditor.ShowFullScreen(true, wxFULLSCREEN_NOBORDER | wxFULLSCREEN_NOCAPTION);
return;
}
if (evt.GetKeyCode() == 'c')
{
POST_MESSAGE(CameraReset, ());
return;
}
int dir = 0;
if (evt.GetKeyCode() == '-' || evt.GetKeyCode() == '_')
dir = -1;
else if (evt.GetKeyCode() == '+' || evt.GetKeyCode() == '=')
dir = +1;
// TODO: internationalisation (-/_ and +/= don't always share a key)
if (dir)
{
float speed = 16.f * ScenarioEditor::GetSpeedModifier();
POST_MESSAGE(SmoothZoom, (eRenderView::GAME, speed*dir));
}
else
{
// Slight hack: Only pass 'normal' keys; special keys will generate a KeyDown/KeyUp event instead
if (evt.GetKeyCode() < 256)
POST_MESSAGE(GuiCharEvent, (GetSDLKeyFromWxKeyCode(evt.GetKeyCode()), evt.GetUnicodeKey()));
evt.Skip();
}
}
void OnKillFocus(wxFocusEvent& evt)
{
// Stop any scrolling, since otherwise we'll carry on forever if
// we lose focus and the KeyUp events go to a different window
POST_MESSAGE(ScrollConstant, (eRenderView::GAME, eScrollConstantDir::LEFT, 0.0f));
POST_MESSAGE(ScrollConstant, (eRenderView::GAME, eScrollConstantDir::RIGHT, 0.0f));
POST_MESSAGE(ScrollConstant, (eRenderView::GAME, eScrollConstantDir::FORWARDS, 0.0f));
POST_MESSAGE(ScrollConstant, (eRenderView::GAME, eScrollConstantDir::BACKWARDS, 0.0f));
POST_MESSAGE(ScrollConstant, (eRenderView::GAME, eScrollConstantDir::CLOCKWISE, 0.0f));
POST_MESSAGE(ScrollConstant, (eRenderView::GAME, eScrollConstantDir::ANTICLOCKWISE, 0.0f));
evt.Skip();
}
virtual void HandleMouseEvent(wxMouseEvent& evt)
{
// TODO or at least to think about: When using other controls in the
// editor, it's annoying that keyboard/scrollwheel no longer navigate
// around the world until you click on it.
// Setting focus back whenever the mouse moves over the GL window
// feels like a fairly natural solution to me, since I can use
// e.g. brush-editing controls normally, and then move the mouse to
// see the brush outline and magically get given back full control
// of the camera.
if (evt.Moving())
SetFocus();
if (m_ScenarioEditor.GetToolManager().GetCurrentTool().OnMouse(evt))
{
// Mouse event has been handled by the tool, so don't try
// to use it for camera motion too
return;
}
// Global mouse event handlers (for camera motion)
if (evt.GetWheelRotation())
{
float speed = 16.f * ScenarioEditor::GetSpeedModifier();
POST_MESSAGE(SmoothZoom, (eRenderView::GAME, evt.GetWheelRotation() * speed / evt.GetWheelDelta()));
}
else
{
if (evt.MiddleIsDown())
{
if (wxGetKeyState(WXK_CONTROL) || evt.RightIsDown())
m_MouseState = ROTATEAROUND;
else
m_MouseState = SCROLL;
}
else
m_MouseState = NONE;
if (m_MouseState != m_LastMouseState)
{
switch (m_MouseState)
{
case NONE: break;
case SCROLL: POST_MESSAGE(Scroll, (eRenderView::GAME, eScrollType::FROM, evt.GetPosition())); break;
case ROTATEAROUND: POST_MESSAGE(RotateAround, (eRenderView::GAME, eRotateAroundType::FROM, evt.GetPosition())); break;
default: wxFAIL;
}
m_LastMouseState = m_MouseState;
}
else if (evt.Dragging())
{
switch (m_MouseState)
{
case NONE: break;
case SCROLL: POST_MESSAGE(Scroll, (eRenderView::GAME, eScrollType::TO, evt.GetPosition())); break;
case ROTATEAROUND: POST_MESSAGE(RotateAround, (eRenderView::GAME, eRotateAroundType::TO, evt.GetPosition())); break;
default: wxFAIL;
}
}
}
if (evt.ButtonDown())
POST_MESSAGE(GuiMouseButtonEvent, (evt.GetButton(), true, evt.GetPosition()));
else if (evt.ButtonUp())
POST_MESSAGE(GuiMouseButtonEvent, (evt.GetButton(), false, evt.GetPosition()));
else if (evt.GetEventType() == wxEVT_MOTION)
POST_MESSAGE(GuiMouseMotionEvent, (evt.GetPosition()));
}
enum { NONE, SCROLL, ROTATEAROUND };
int m_MouseState, m_LastMouseState;
ScenarioEditor& m_ScenarioEditor;
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(GameCanvas, Canvas)
EVT_KEY_DOWN(GameCanvas::OnKeyDown)
EVT_KEY_UP(GameCanvas::OnKeyUp)
EVT_CHAR(GameCanvas::OnChar)
EVT_KILL_FOCUS(GameCanvas::OnKillFocus)
END_EVENT_TABLE()
//////////////////////////////////////////////////////////////////////////
volatile bool g_FrameHasEnded;
// Called from game thread
ATLASDLLIMPEXP void Atlas_NotifyEndOfFrame()
{
g_FrameHasEnded = true;
}
enum
{
ID_Quit = 1,
// ID_New,
ID_Open,
ID_Save,
ID_SaveAs,
ID_Wireframe,
ID_MessageTrace,
ID_Screenshot,
ID_JavaScript,
ID_CameraReset,
+ ID_RenderPathFixed,
+ ID_RenderPathVertexShader,
+ ID_RenderPathShader,
ID_Toolbar // must be last in the list
};
BEGIN_EVENT_TABLE(ScenarioEditor, wxFrame)
EVT_CLOSE(ScenarioEditor::OnClose)
EVT_TIMER(wxID_ANY, ScenarioEditor::OnTimer)
// EVT_MENU(ID_New, ScenarioEditor::OnNew)
EVT_MENU(ID_Open, ScenarioEditor::OnOpen)
EVT_MENU(ID_Save, ScenarioEditor::OnSave)
EVT_MENU(ID_SaveAs, ScenarioEditor::OnSaveAs)
EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, ScenarioEditor::OnMRUFile)
EVT_MENU(ID_Quit, ScenarioEditor::OnQuit)
EVT_MENU(wxID_UNDO, ScenarioEditor::OnUndo)
EVT_MENU(wxID_REDO, ScenarioEditor::OnRedo)
EVT_MENU(ID_Wireframe, ScenarioEditor::OnWireframe)
EVT_MENU(ID_MessageTrace, ScenarioEditor::OnMessageTrace)
EVT_MENU(ID_Screenshot, ScenarioEditor::OnScreenshot)
EVT_MENU(ID_JavaScript, ScenarioEditor::OnJavaScript)
EVT_MENU(ID_CameraReset, ScenarioEditor::OnCameraReset)
+ EVT_MENU(ID_RenderPathFixed, ScenarioEditor::OnRenderPath)
+ EVT_MENU(ID_RenderPathVertexShader, ScenarioEditor::OnRenderPath)
+ EVT_MENU(ID_RenderPathShader, ScenarioEditor::OnRenderPath)
EVT_IDLE(ScenarioEditor::OnIdle)
END_EVENT_TABLE()
static AtlasWindowCommandProc g_CommandProc;
AtlasWindowCommandProc& ScenarioEditor::GetCommandProc() { return g_CommandProc; }
namespace
{
// Wrapper functions for scripts
void SetCurrentTool_(void* cbdata, wxString name)
{
static_cast(cbdata)->GetToolManager().SetCurrentTool(name);
}
void SetCurrentToolWith(void* cbdata, wxString name, wxString arg)
{
static_cast(cbdata)->GetToolManager().SetCurrentTool(name, &arg);
}
void SetCurrentToolWithVal(void* cbdata, wxString name, CScriptVal arg)
{
jsval tool = arg.get();
static_cast(cbdata)->GetToolManager().SetCurrentTool(name, &tool);
}
wxString GetDataDirectory(void*)
{
return Datafile::GetDataDirectory();
}
// TODO: see comment in terrain.js, and remove this when/if it's no longer necessary
void SetBrushStrength(void*, float strength)
{
g_Brush_Elevation.SetStrength(strength);
}
void SetSelectedTexture(void*, wxString name)
{
g_SelectedTexture = name;
}
}
ScenarioEditor::ScenarioEditor(wxWindow* parent, ScriptInterface& scriptInterface)
: wxFrame(parent, wxID_ANY, _T(""), wxDefaultPosition, wxSize(1024, 768))
, m_FileHistory(_T("Scenario Editor")), m_ScriptInterface(scriptInterface)
, m_ObjectSettings(g_SelectedObjects, m_ScriptInterface)
, m_ToolManager(this)
{
// Global application initialisation:
// wxLog::SetTraceMask(wxTraceMessages);
SetOpenFilename(_T(""));
#if defined(__WXMSW__)
SetIcon(wxIcon(_T("ICON_ScenarioEditor"))); // load from atlas.rc
#else
{
const wxString relativePath (_T("tools/atlas/icons/ScenarioEditor.ico"));
wxFileName filename (relativePath, wxPATH_UNIX);
filename.MakeAbsolute(Datafile::GetDataDirectory());
SetIcon(wxIcon(filename.GetFullPath()));
}
#endif
wxToolTip::Enable(true);
wxImage::AddHandler(new wxPNGHandler);
//////////////////////////////////////////////////////////////////////////
// Script interface functions
GetScriptInterface().SetCallbackData(static_cast(this));
GetScriptInterface().RegisterFunction("GetDataDirectory");
GetScriptInterface().RegisterFunction("SetCurrentTool");
GetScriptInterface().RegisterFunction("SetCurrentToolWith");
GetScriptInterface().RegisterFunction("SetCurrentToolWithVal");
GetScriptInterface().RegisterFunction("SetBrushStrength");
GetScriptInterface().RegisterFunction("SetSelectedTexture");
{
const wxString relativePath (_T("tools/atlas/scripts/main.js"));
wxFileName filename (relativePath, wxPATH_UNIX);
filename.MakeAbsolute(Datafile::GetDataDirectory());
wxFFile file (filename.GetFullPath());
wxString script;
if (! file.ReadAll(&script))
wxLogError(_("Failed to read script"));
GetScriptInterface().LoadScript(filename.GetFullName(), script);
}
// Initialise things that rely on scripts
m_ObjectSettings.Init(AtlasMessage::eRenderView::GAME);
//////////////////////////////////////////////////////////////////////////
// Do some early game initialisation:
// (This must happen before constructing the GL canvas.)
POST_MESSAGE(Init, ());
// Wait for it to finish running Init
qPing qry;
qry.Post();
//////////////////////////////////////////////////////////////////////////
// Menu
wxMenuBar* menuBar = new wxMenuBar;
SetMenuBar(menuBar);
wxMenu *menuFile = new wxMenu;
menuBar->Append(menuFile, _("&File"));
{
// menuFile->Append(ID_New, _("&New"));
menuFile->Append(ID_Open, _("&Open..."));
menuFile->Append(ID_Save, _("&Save"));
menuFile->Append(ID_SaveAs, _("Save &As..."));
menuFile->AppendSeparator();//-----------
menuFile->Append(ID_Quit, _("E&xit"));
m_FileHistory.UseMenu(menuFile);//-------
m_FileHistory.AddFilesToMenu();
}
// m_menuItem_Save = menuFile->FindItem(ID_Save); // remember this item, to let it be greyed out
// wxASSERT(m_menuItem_Save);
wxMenu *menuEdit = new wxMenu;
menuBar->Append(menuEdit, _("&Edit"));
{
menuEdit->Append(wxID_UNDO, _("&Undo"));
menuEdit->Append(wxID_REDO, _("&Redo"));
}
GetCommandProc().SetEditMenu(menuEdit);
GetCommandProc().Initialize();
wxMenu *menuMisc = new wxMenu;
menuBar->Append(menuMisc, _("&Misc hacks"));
{
menuMisc->AppendCheckItem(ID_Wireframe, _("&Wireframe"));
menuMisc->AppendCheckItem(ID_MessageTrace, _("Message debug trace"));
menuMisc->Append(ID_Screenshot, _("&Screenshot"));
menuMisc->Append(ID_JavaScript, _("&JS console"));
menuMisc->Append(ID_CameraReset, _("&Reset camera"));
+
+ wxMenu *menuRP = new wxMenu;
+ menuMisc->AppendSubMenu(menuRP, _("Render &path"));
+ menuRP->Append(ID_RenderPathFixed, _("&Fixed function"));
+ menuRP->Append(ID_RenderPathVertexShader, _("&Vertex shader (old)"));
+ menuRP->Append(ID_RenderPathShader, _("&Shader (new)"));
}
m_FileHistory.Load(*wxConfigBase::Get());
m_SectionLayout.SetWindow(this);
// Toolbar:
ToolButtonBar* toolbar = new ToolButtonBar(m_ToolManager, this, &m_SectionLayout, ID_Toolbar);
// TODO: configurable small vs large icon images
// (button label; tooltip text; image; internal tool name; section to switch to)
toolbar->AddToolButton(_("Default"), _("Default"), _T("default.png"), _T(""), _T(""));
toolbar->AddToolButton(_("Move"), _("Move/rotate object"), _T("moveobject.png"), _T("TransformObject"), _T("")/*_T("ObjectSidebar")*/);
toolbar->AddToolButton(_("Elevation"), _("Alter terrain elevation"), _T("alterelevation.png"), _T("AlterElevation"), _T("")/*_T("TerrainSidebar")*/);
toolbar->AddToolButton(_("Smooth"), _("Smooth terrain elevation"), _T("smoothelevation.png"), _T("SmoothElevation"), _T("")/*_T("TerrainSidebar")*/);
toolbar->AddToolButton(_("Flatten"), _("Flatten terrain elevation"), _T("flattenelevation.png"), _T("FlattenElevation"), _T("")/*_T("TerrainSidebar")*/);
toolbar->AddToolButton(_("Paint Terrain"), _("Paint terrain texture"), _T("paintterrain.png"), _T("PaintTerrain"), _T("")/*_T("TerrainSidebar")*/);
toolbar->Realize();
SetToolBar(toolbar);
// Set the default tool to be selected
m_ToolManager.SetCurrentTool(_T(""));
// Set up GL canvas:
int glAttribList[] = {
WX_GL_RGBA,
WX_GL_DOUBLEBUFFER,
WX_GL_DEPTH_SIZE, 24, // TODO: wx documentation doesn't say 24 is valid
WX_GL_STENCIL_SIZE, 8,
WX_GL_BUFFER_SIZE, 24, // colour bits
WX_GL_MIN_ALPHA, 8, // alpha bits
0
};
Canvas* canvas = new GameCanvas(*this, m_SectionLayout.GetCanvasParent(), glAttribList);
m_SectionLayout.SetCanvas(canvas);
// Set up sidebars:
m_SectionLayout.Build(*this);
#if defined(__WXMSW__)
// The canvas' context gets made current on creation; but it can only be
// current for one thread at a time, and it needs to be current for the
// thread that is doing the draw calls, so disable it for this one.
wglMakeCurrent(NULL, NULL);
#elif defined(__WXGTK__)
// Need to make sure the canvas is realized by GTK, so that its context is valid
Show(true);
wxSafeYield();
#endif
// Send setup messages to game engine:
POST_MESSAGE(SetCanvas, (static_cast(canvas)));
POST_MESSAGE(InitGraphics, ());
canvas->InitSize();
// Start with a blank map (so that the editor can assume there's always
// a valid map loaded)
POST_MESSAGE(GenerateMap, (9));
POST_MESSAGE(RenderEnable, (eRenderView::GAME));
// Set up a timer to make sure tool-updates happen frequently (in addition
// to the idle handler (which makes them happen more frequently if there's nothing
// else to do))
m_Timer.SetOwner(this);
m_Timer.Start(20);
#ifdef __WXGTK__
// HACK: because of how we fiddle with stuff earlier to make sure the canvas
// is displayed, the layout gets messed up, and it only seems to be fixable
// by changing the window's size
SetSize(GetSize() + wxSize(1, 0));
#endif
}
float ScenarioEditor::GetSpeedModifier()
{
if (wxGetKeyState(WXK_SHIFT) && wxGetKeyState(WXK_CONTROL))
return 1.f/64.f;
else if (wxGetKeyState(WXK_CONTROL))
return 1.f/4.f;
else if (wxGetKeyState(WXK_SHIFT))
return 4.f;
else
return 1.f;
}
void ScenarioEditor::OnClose(wxCloseEvent&)
{
m_ToolManager.SetCurrentTool(_T(""));
m_FileHistory.Save(*wxConfigBase::Get());
POST_MESSAGE(Shutdown, ());
qExit().Post();
// blocks until engine has noticed the message, so we won't be
// destroying the GLCanvas while it's still rendering
Destroy();
}
static void UpdateTool(ToolManager& toolManager)
{
// Don't keep posting events if the game can't keep up
if (g_FrameHasEnded)
{
g_FrameHasEnded = false; // (thread safety doesn't matter here)
// TODO: Smoother timing stuff?
static double last = g_Timer.GetTime();
double time = g_Timer.GetTime();
toolManager.GetCurrentTool().OnTick(time-last);
last = time;
}
}
void ScenarioEditor::OnTimer(wxTimerEvent&)
{
UpdateTool(m_ToolManager);
}
void ScenarioEditor::OnIdle(wxIdleEvent&)
{
UpdateTool(m_ToolManager);
}
void ScenarioEditor::OnQuit(wxCommandEvent&)
{
Close();
}
void ScenarioEditor::OnUndo(wxCommandEvent&)
{
GetCommandProc().Undo();
}
void ScenarioEditor::OnRedo(wxCommandEvent&)
{
GetCommandProc().Redo();
}
//////////////////////////////////////////////////////////////////////////
void ScenarioEditor::OpenFile(const wxString& name)
{
wxBusyInfo busy(_("Loading map"));
wxBusyCursor busyc;
// TODO: Work when the map is not in .../maps/scenarios/
std::wstring map = name.c_str();
// Deactivate tools, so they don't carry forwards into the new CWorld
// and crash.
m_ToolManager.SetCurrentTool(_T(""));
// TODO: clear the undo buffer, etc
POST_MESSAGE(LoadMap, (map));
SetOpenFilename(name);
// Wait for it to load, while the wxBusyInfo is telling the user that we're doing that
qPing qry;
qry.Post();
// TODO: Make this a non-undoable command
}
// TODO (eventually): replace all this file-handling stuff with the Workspace Editor
void ScenarioEditor::OnOpen(wxCommandEvent& WXUNUSED(event))
{
wxFileDialog dlg (NULL, wxFileSelectorPromptStr,
Datafile::GetDataDirectory() + _T("/mods/public/maps/scenarios"), m_OpenFilename,
_T("PMP files (*.pmp)|*.pmp|All files (*.*)|*.*"),
wxOPEN);
wxString cwd = wxFileName::GetCwd();
if (dlg.ShowModal() == wxID_OK)
OpenFile(dlg.GetFilename());
wxCHECK_RET(cwd == wxFileName::GetCwd(), _T("cwd changed"));
// paranoia - MSDN says OFN_NOCHANGEDIR (used when we don't give wxCHANGE_DIR)
// "is ineffective for GetOpenFileName", but it seems to work anyway
// TODO: Make this a non-undoable command
}
void ScenarioEditor::OnMRUFile(wxCommandEvent& event)
{
wxString file (m_FileHistory.GetHistoryFile(event.GetId() - wxID_FILE1));
if (file.Len())
OpenFile(file);
}
void ScenarioEditor::OnSave(wxCommandEvent& event)
{
if (m_OpenFilename.IsEmpty())
OnSaveAs(event);
else
{
wxBusyInfo busy(_("Saving map"));
// Deactivate tools, so things like unit previews don't get saved.
// (TODO: Would be nicer to leave the tools active, and just not save
// the preview units.)
m_ToolManager.SetCurrentTool(_T(""));
std::wstring map = m_OpenFilename.c_str();
POST_MESSAGE(SaveMap, (map));
// Wait for it to finish saving
qPing qry;
qry.Post();
}
}
void ScenarioEditor::OnSaveAs(wxCommandEvent& WXUNUSED(event))
{
wxFileDialog dlg (NULL, wxFileSelectorPromptStr,
Datafile::GetDataDirectory() + _T("/mods/public/maps/scenarios"), m_OpenFilename,
_T("PMP files (*.pmp)|*.pmp|All files (*.*)|*.*"),
wxSAVE | wxOVERWRITE_PROMPT);
if (dlg.ShowModal() == wxID_OK)
{
wxBusyInfo busy(_("Saving map"));
m_ToolManager.SetCurrentTool(_T(""));
// TODO: Work when the map is not in .../maps/scenarios/
std::wstring map = dlg.GetFilename().c_str();
POST_MESSAGE(SaveMap, (map));
SetOpenFilename(dlg.GetFilename());
// Wait for it to finish saving
qPing qry;
qry.Post();
}
}
void ScenarioEditor::SetOpenFilename(const wxString& filename)
{
SetTitle(wxString::Format(_("Atlas - Scenario Editor - %s"),
(filename.IsEmpty() ? wxString(_("(untitled)")) : filename).c_str()));
m_OpenFilename = filename;
if (! filename.IsEmpty())
m_FileHistory.AddFileToHistory(filename);
}
//////////////////////////////////////////////////////////////////////////
void ScenarioEditor::OnWireframe(wxCommandEvent& event)
{
POST_MESSAGE(RenderStyle, (event.IsChecked()));
}
void ScenarioEditor::OnMessageTrace(wxCommandEvent& event)
{
POST_MESSAGE(MessageTrace, (event.IsChecked()));
}
void ScenarioEditor::OnScreenshot(wxCommandEvent& WXUNUSED(event))
{
POST_MESSAGE(Screenshot, (10));
}
void ScenarioEditor::OnJavaScript(wxCommandEvent& WXUNUSED(event))
{
wxString cmd = ::wxGetTextFromUser(_T(""), _("JS command"), _T(""), this);
if (cmd.IsEmpty())
return;
POST_MESSAGE(JavaScript, (cmd.c_str()));
}
void ScenarioEditor::OnCameraReset(wxCommandEvent& WXUNUSED(event))
{
POST_MESSAGE(CameraReset, ());
}
+void ScenarioEditor::OnRenderPath(wxCommandEvent& event)
+{
+ switch (event.GetId())
+ {
+ case ID_RenderPathFixed:
+ POST_MESSAGE(SetViewParamS, (eRenderView::GAME, L"renderpath", L"fixed"));
+ break;
+ case ID_RenderPathVertexShader:
+ POST_MESSAGE(SetViewParamS, (eRenderView::GAME, L"renderpath", L"vertexshader"));
+ break;
+ case ID_RenderPathShader:
+ POST_MESSAGE(SetViewParamS, (eRenderView::GAME, L"renderpath", L"shader"));
+ break;
+ }
+}
+
//////////////////////////////////////////////////////////////////////////
Position::Position(const wxPoint& pt)
: type(1)
{
type1.x = pt.x;
type1.y = pt.y;
}
//////////////////////////////////////////////////////////////////////////
/* Disabled (and should be removed if it turns out to be unnecessary)
- see MessagePasserImpl.cpp for information
static void QueryCallback()
{
// If this thread completely blocked on the semaphore inside Query, it would
// never respond to window messages, and the system deadlocks if the
// game tries to display an assertion failure dialog. (See
// WaitForSingleObject on MSDN.)
// So, this callback is called occasionally, and gives wx a change to
// handle messages.
// This is kind of like wxYield, but without the ProcessPendingEvents -
// it's enough to make Windows happy and stop deadlocking, without actually
// calling the event handlers (which could lead to nasty recursion)
// while (wxEventLoop::GetActive()->Pending())
// wxEventLoop::GetActive()->Dispatch();
// Oh dear, we can't use that either - it (at least in wx 2.6.3) still
// processes messages, which causes reentry into various things that we
// don't want to be reentrant. So do it all manually, accepting Windows
// messages and sticking them on a list for later processing (in a custom
// event loop class):
// (TODO: Rethink this entire process on Linux)
// (Alt TODO: Could we make the game never pop up windows (or use the Win32
// GUI in any other way) when it's running under Atlas, so we wouldn't need
// to do any message processing here at all?)
#ifdef _WIN32
AtlasEventLoop* evtLoop = (AtlasEventLoop*)wxEventLoop::GetActive();
// evtLoop might be NULL, particularly if we're still initialising windows
// and haven't got into the normal event loop yet. But we'd have to process
// messages anyway, to avoid the deadlocks that this is for. So, don't bother
// with that and just crash instead.
// (Maybe it could be solved better by constructing/finding an event loop
// object here and setting it as the global one, assuming it's not overwritten
// later by wx.)
while (evtLoop->Pending())
{
// Based on src/msw/evtloop.cpp's wxEventLoop::Dispatch()
MSG msg;
BOOL rc = ::GetMessage(&msg, (HWND) NULL, 0, 0);
if (rc == 0)
{
// got WM_QUIT
return;
}
if (rc == -1)
{
wxLogLastError(wxT("GetMessage"));
return;
}
// Our special bits:
if (msg.message == WM_PAINT)
{
// "GetMessage does not remove WM_PAINT messages from the queue.
// The messages remain in the queue until processed."
// So let's process them, to avoid infinite loops...
PAINTSTRUCT paint;
::BeginPaint(msg.hwnd, &paint);
::EndPaint(msg.hwnd, &paint);
// Remember that some painting was needed - we'll just repaint
// the whole screen when this is finished.
evtLoop->NeedsPaint();
}
else
{
// Add this message to a queue for later processing. (That's
// probably kind of valid, at least in most cases.)
MSG* pMsg = new MSG(msg);
evtLoop->AddMessage(pMsg);
}
}
#endif
}
*/
void QueryMessage::Post()
{
// g_MessagePasser->Query(this, &QueryCallback);
g_MessagePasser->Query(this, NULL);
}
Index: ps/trunk/source/tools/atlas/GameInterface/View.cpp
===================================================================
--- ps/trunk/source/tools/atlas/GameInterface/View.cpp (revision 9122)
+++ ps/trunk/source/tools/atlas/GameInterface/View.cpp (revision 9123)
@@ -1,379 +1,383 @@
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#include "precompiled.h"
#include "View.h"
#include "ActorViewer.h"
#include "GameLoop.h"
#include "Messages.h"
#include "SimState.h"
#include "graphics/CinemaTrack.h"
#include "graphics/GameView.h"
#include "graphics/SColor.h"
#include "graphics/UnitManager.h"
#include "lib/timer.h"
#include "lib/utf8.h"
#include "ps/Game.h"
#include "ps/GameSetup/GameSetup.h"
#include "ps/World.h"
#include "renderer/Renderer.h"
#include "simulation/Simulation.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpObstructionManager.h"
#include "simulation2/components/ICmpPathfinder.h"
extern void (*Atlas_GLSwapBuffers)(void* context);
extern int g_xres, g_yres;
//////////////////////////////////////////////////////////////////////////
void View::SetParam(const std::wstring& UNUSED(name), bool UNUSED(value))
{
}
void View::SetParam(const std::wstring& UNUSED(name), const AtlasMessage::Colour& UNUSED(value))
{
}
void View::SetParam(const std::wstring& UNUSED(name), const std::wstring& UNUSED(value))
{
}
//////////////////////////////////////////////////////////////////////////
ViewActor::ViewActor()
: m_SpeedMultiplier(1.f), m_ActorViewer(new ActorViewer())
{
}
ViewActor::~ViewActor()
{
delete m_ActorViewer;
}
void ViewActor::Update(float frameLength)
{
m_ActorViewer->Update(frameLength * m_SpeedMultiplier);
}
void ViewActor::Render()
{
SViewPort vp = { 0, 0, g_xres, g_yres };
CCamera& camera = GetCamera();
camera.SetViewPort(vp);
camera.SetProjection(CGameView::defaultNear, CGameView::defaultFar, CGameView::defaultFOV);
camera.UpdateFrustum();
m_ActorViewer->Render();
Atlas_GLSwapBuffers((void*)g_GameLoop->glCanvas);
}
CCamera& ViewActor::GetCamera()
{
return m_Camera;
}
CSimulation2* ViewActor::GetSimulation2()
{
return m_ActorViewer->GetSimulation2();
}
entity_id_t ViewActor::GetEntityId(AtlasMessage::ObjectID UNUSED(obj))
{
return m_ActorViewer->GetEntity();
}
bool ViewActor::WantsHighFramerate()
{
if (m_SpeedMultiplier != 0.f)
return true;
return false;
}
void ViewActor::SetSpeedMultiplier(float speed)
{
m_SpeedMultiplier = speed;
}
ActorViewer& ViewActor::GetActorViewer()
{
return *m_ActorViewer;
}
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)
{
if (name == L"background")
{
m_ActorViewer->SetBackgroundColour(SColor4ub(value.r, value.g, value.b, 255));
}
}
//////////////////////////////////////////////////////////////////////////
template
static void delete_pair_2nd(std::pair v)
{
delete v.second;
}
ViewGame::ViewGame()
: m_SpeedMultiplier(0.f)
{
debug_assert(g_Game);
}
ViewGame::~ViewGame()
{
std::for_each(m_SavedStates.begin(), m_SavedStates.end(), delete_pair_2nd);
}
CSimulation2* ViewGame::GetSimulation2()
{
return g_Game->GetSimulation2();
}
void ViewGame::Update(float frameLength)
{
float actualFrameLength = frameLength * m_SpeedMultiplier;
// Clean up any entities destroyed during UI message processing
g_Game->GetSimulation2()->FlushDestroyedEntities();
if (m_SpeedMultiplier == 0.f)
{
// Update unit interpolation
g_Game->Interpolate(0.0);
}
else
{
// Update the whole world
// (Tell the game update not to interpolate graphics - we'll do that
// ourselves)
bool ok = g_Game->Update(actualFrameLength, false);
if (! ok)
{
// Whoops, we're trying to go faster than the simulation can manage.
// It's probably better to run at the right sim rate, at the expense
// of framerate, so let's try simulating a few more times.
double t = timer_Time();
while (!ok && timer_Time() < t + 0.1) // don't go much worse than 10fps
{
ok = g_Game->Update(0.0, false); // don't add on any extra sim time
}
}
// Interpolate the graphics - we only want to do this once per visual frame,
// not in every call to g_Game->Update
g_Game->Interpolate(actualFrameLength);
}
// Cinematic motion should be independent of simulation update, so we can
// preview the cinematics by themselves
if (g_Game->GetView()->GetCinema()->IsPlaying())
g_Game->GetView()->GetCinema()->Update(frameLength);
}
void ViewGame::Render()
{
SViewPort vp = { 0, 0, g_xres, g_yres };
CCamera& camera = GetCamera();
camera.SetViewPort(vp);
camera.SetProjection(CGameView::defaultNear, CGameView::defaultFar, CGameView::defaultFOV);
camera.UpdateFrustum();
// Update the pathfinder display if necessary
if (!m_DisplayPassability.empty())
{
CmpPtr cmpObstructionMan(*GetSimulation2(), SYSTEM_ENTITY);
if (!cmpObstructionMan.null())
{
cmpObstructionMan->SetDebugOverlay(true);
}
CmpPtr cmpPathfinder(*GetSimulation2(), SYSTEM_ENTITY);
if (!cmpPathfinder.null())
{
cmpPathfinder->SetDebugOverlay(true);
// Kind of a hack to make it update the terrain grid
ICmpPathfinder::Goal goal = { ICmpPathfinder::Goal::POINT, fixed::Zero(), fixed::Zero() };
u8 passClass = cmpPathfinder->GetPassabilityClass(m_DisplayPassability);
u8 costClass = cmpPathfinder->GetCostClass("default");
cmpPathfinder->SetDebugPath(fixed::Zero(), fixed::Zero(), goal, passClass, costClass);
}
}
::Render();
Atlas_GLSwapBuffers((void*)g_GameLoop->glCanvas);
}
void ViewGame::SetParam(const std::wstring& name, bool value)
{
if (name == L"priorities")
g_Renderer.SetDisplayTerrainPriorities(value);
}
void ViewGame::SetParam(const std::wstring& name, const std::wstring& value)
{
if (name == L"passability")
{
m_DisplayPassability = CStrW(value).ToUTF8();
CmpPtr cmpObstructionMan(*GetSimulation2(), SYSTEM_ENTITY);
if (!cmpObstructionMan.null())
cmpObstructionMan->SetDebugOverlay(!value.empty());
CmpPtr cmpPathfinder(*GetSimulation2(), SYSTEM_ENTITY);
if (!cmpPathfinder.null())
cmpPathfinder->SetDebugOverlay(!value.empty());
}
+ else if (name == L"renderpath")
+ {
+ g_Renderer.SetRenderPath(g_Renderer.GetRenderPathByName(CStrW(value).ToUTF8()));
+ }
}
CCamera& ViewGame::GetCamera()
{
return *g_Game->GetView()->GetCamera();
}
bool ViewGame::WantsHighFramerate()
{
if (g_Game->GetView()->GetCinema()->IsPlaying())
return true;
if (m_SpeedMultiplier != 0.f)
return true;
return false;
}
void ViewGame::SetSpeedMultiplier(float speed)
{
m_SpeedMultiplier = speed;
}
void ViewGame::SaveState(const std::wstring& label)
{
delete m_SavedStates[label]; // in case it already exists
m_SavedStates[label] = SimState::Freeze();
}
void ViewGame::RestoreState(const std::wstring& label)
{
SimState* simState = m_SavedStates[label];
if (! simState)
return;
simState->Thaw();
}
std::wstring ViewGame::DumpState(bool binary)
{
std::stringstream stream;
if (binary)
{
if (! g_Game->GetSimulation2()->SerializeState(stream))
return L"(internal error)";
// We can't return raw binary data, because we want to handle it with wxJS which
// doesn't like \0 bytes in strings, so return it as hex
static const char digits[] = "0123456789abcdef";
std::string str = stream.str();
std::wstring ret;
ret.reserve(str.length()*3);
for (size_t i = 0; i < str.length(); ++i)
{
ret += digits[(unsigned char)str[i] >> 4];
ret += digits[(unsigned char)str[i] & 0x0f];
ret += ' ';
}
return ret;
}
else
{
if (! g_Game->GetSimulation2()->DumpDebugState(stream))
return L"(internal error)";
return wstring_from_utf8(stream.str());
}
}
//////////////////////////////////////////////////////////////////////////
ViewNone* view_None = NULL;
ViewGame* view_Game = NULL;
ViewActor* view_Actor = NULL;
View::~View()
{
}
View* View::GetView(int /*eRenderView*/ view)
{
switch (view)
{
case AtlasMessage::eRenderView::NONE: return View::GetView_None();
case AtlasMessage::eRenderView::GAME: return View::GetView_Game();
case AtlasMessage::eRenderView::ACTOR: return View::GetView_Actor();
default:
debug_warn(L"Invalid view type");
return View::GetView_None();
}
}
View* View::GetView_None()
{
if (! view_None)
view_None = new ViewNone();
return view_None;
}
ViewGame* View::GetView_Game()
{
if (! view_Game)
view_Game = new ViewGame();
return view_Game;
}
ViewActor* View::GetView_Actor()
{
if (! view_Actor)
view_Actor = new ViewActor();
return view_Actor;
}
void View::DestroyViews()
{
delete view_None; view_None = NULL;
delete view_Game; view_Game = NULL;
delete view_Actor; view_Actor = NULL;
}
Index: ps/trunk/source/tools/atlas/GameInterface/Messages.h
===================================================================
--- ps/trunk/source/tools/atlas/GameInterface/Messages.h (revision 9122)
+++ ps/trunk/source/tools/atlas/GameInterface/Messages.h (revision 9123)
@@ -1,510 +1,514 @@
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#ifndef INCLUDED_MESSAGES
#define INCLUDED_MESSAGES
#ifndef MESSAGES_SKIP_SETUP
#include "MessagesSetup.h"
#endif
#include
#include
// TODO: organisation, documentation, etc
//////////////////////////////////////////////////////////////////////////
// Initialise some engine code. Must be called before anything else.
MESSAGE(Init, );
// Initialise graphics-related code. Must be called after the first SetCanvas,
// and before much else.
MESSAGE(InitGraphics, );
// Shut down engine/graphics code.
MESSAGE(Shutdown, );
struct eRenderView { enum renderViews { NONE, GAME, ACTOR }; };
MESSAGE(RenderEnable,
((int, view)) // eRenderView
);
// SetViewParam: used for hints to the renderer, e.g. to set wireframe mode;
// unrecognised param names are ignored
MESSAGE(SetViewParamB,
((int, view)) // eRenderView
((std::wstring, name))
((bool, value))
);
MESSAGE(SetViewParamC,
((int, view)) // eRenderView
((std::wstring, name))
((Colour, value))
);
MESSAGE(SetViewParamS,
((int, view)) // eRenderView
((std::wstring, name))
((std::wstring, value))
);
MESSAGE(JavaScript,
((std::wstring, command))
);
//////////////////////////////////////////////////////////////////////////
MESSAGE(GuiSwitchPage,
((std::wstring, page))
);
MESSAGE(GuiMouseButtonEvent,
((int, button))
((bool, pressed))
((Position, pos))
);
MESSAGE(GuiMouseMotionEvent,
((Position, pos))
);
MESSAGE(GuiKeyEvent,
((int, sdlkey)) // SDLKey code
((int, unichar)) // Unicode character
((bool, pressed))
);
MESSAGE(GuiCharEvent,
((int, sdlkey))
((int, unichar))
);
//////////////////////////////////////////////////////////////////////////
MESSAGE(SimStateSave,
((std::wstring, label)) // named slot to store saved data
);
MESSAGE(SimStateRestore,
((std::wstring, label)) // named slot to find saved data
);
QUERY(SimStateDebugDump,
((bool, binary))
,
((std::wstring, dump))
);
MESSAGE(SimPlay,
((float, speed)) // 0 for pause, 1 for normal speed
);
//////////////////////////////////////////////////////////////////////////
QUERY(Ping, , );
//////////////////////////////////////////////////////////////////////////
MESSAGE(SetCanvas,
((void*, canvas))
);
MESSAGE(ResizeScreen,
((int, width))
((int, height))
);
//////////////////////////////////////////////////////////////////////////
MESSAGE(GenerateMap,
((int, size)) // size in number of patches
);
MESSAGE(LoadMap,
((std::wstring, filename))
);
MESSAGE(SaveMap,
((std::wstring, filename))
);
//////////////////////////////////////////////////////////////////////////
MESSAGE(RenderStyle,
((bool, wireframe))
);
MESSAGE(MessageTrace,
((bool, enable))
);
MESSAGE(Screenshot,
((int, tiles)) // the final image will be (640*tiles)x(480*tiles)
);
#ifndef MESSAGES_SKIP_STRUCTS
struct sCinemaRecordCB
{
unsigned char* buffer;
};
SHAREABLE_STRUCT(sCinemaRecordCB);
#endif
QUERY(CinemaRecord,
((std::wstring, path))
((int, framerate))
((float, duration))
((int, width))
((int, height))
((Callback, cb))
,
);
//////////////////////////////////////////////////////////////////////////
MESSAGE(Brush,
((int, width)) // number of vertices
((int, height))
((std::vector, data)) // width*height array
);
MESSAGE(BrushPreview,
((bool, enable))
((Position, pos)) // only used if enable==true
);
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
QUERY(GetTerrainGroups,
, // no inputs
((std::vector, groupnames))
);
#ifndef MESSAGES_SKIP_STRUCTS
struct sTerrainGroupPreview
{
Shareable name;
Shareable loaded;
Shareable imagewidth;
Shareable imageheight;
Shareable > imagedata; // RGB*width*height
};
SHAREABLE_STRUCT(sTerrainGroupPreview);
#endif
QUERY(GetTerrainGroupPreviews,
((std::wstring, groupname))
((int, imagewidth))
((int, imageheight))
,
((std::vector, previews))
);
QUERY(GetTerrainPassabilityClasses,
, // no inputs
((std::vector, classnames))
);
//////////////////////////////////////////////////////////////////////////
#ifndef MESSAGES_SKIP_STRUCTS
struct sObjectsListItem
{
Shareable id;
Shareable name;
Shareable type; // 0 = entity, 1 = actor
};
SHAREABLE_STRUCT(sObjectsListItem);
#endif
QUERY(GetObjectsList,
, // no inputs
((std::vector, objects)) // sorted by .name
);
#ifndef MESSAGES_SKIP_STRUCTS
struct sObjectSettings
{
Shareable player;
Shareable > selections;
// Some settings are immutable and therefore are ignored (and should be left
// empty) when passed from the editor to the game:
Shareable > > variantgroups;
};
SHAREABLE_STRUCT(sObjectSettings);
#endif
// Preview object in the game world - creates a temporary unit at the given
// position, and removes it when the preview is next changed
MESSAGE(ObjectPreview,
((std::wstring, id)) // or empty string => disable
((sObjectSettings, settings))
((Position, pos))
((bool, usetarget)) // true => use 'target' for orientation; false => use 'angle'
((Position, target))
((float, angle))
);
COMMAND(CreateObject, NOMERGE,
((std::wstring, id))
((sObjectSettings, settings))
((Position, pos))
((bool, usetarget)) // true => use 'target' for orientation; false => use 'angle'
((Position, target))
((float, angle))
);
// Set an actor to be previewed on its own (i.e. without the game world).
// (Use RenderEnable to make it visible.)
MESSAGE(SetActorViewer,
((std::wstring, id))
((std::wstring, animation))
((float, speed))
((bool, flushcache)) // true => unload all actor files before starting the preview (because we don't have proper hotloading yet)
);
//////////////////////////////////////////////////////////////////////////
QUERY(Exit,,); // no inputs nor outputs
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
struct eScrollConstantDir { enum { FORWARDS, BACKWARDS, LEFT, RIGHT, CLOCKWISE, ANTICLOCKWISE }; };
MESSAGE(ScrollConstant, // set a constant scrolling(/rotation) rate
((int, view)) // eRenderView
((int, dir)) // eScrollConstantDir
((float, speed)) // set speed 0.0f to stop scrolling
);
struct eScrollType { enum { FROM, TO }; };
MESSAGE(Scroll, // for scrolling by dragging the mouse FROM somewhere TO elsewhere
((int, view)) // eRenderView
((int, type)) // eScrollType
((Position, pos))
);
MESSAGE(SmoothZoom,
((int, view)) // eRenderView
((float, amount))
);
struct eRotateAroundType { enum { FROM, TO }; };
MESSAGE(RotateAround,
((int, view)) // eRenderView
((int, type)) // eRotateAroundType
((Position, pos))
);
MESSAGE(LookAt,
((int, view)) // eRenderView
((Position, pos))
((Position, target))
);
MESSAGE(CameraReset, );
//////////////////////////////////////////////////////////////////////////
#ifndef MESSAGES_SKIP_STRUCTS
struct sEnvironmentSettings
{
Shareable waterheight; // range 0..1 corresponds to min..max terrain height; out-of-bounds values allowed
Shareable watershininess; // range ???
Shareable waterwaviness; // range ???
Shareable watermurkiness; // range ???
Shareable watercolour;
Shareable watertint;
Shareable waterreflectiontint;
Shareable waterreflectiontintstrength; // range ???
Shareable sunrotation; // range -pi..+pi
Shareable sunelevation; // range -pi/2 .. +pi/2
// emulate 'HDR' by allowing overly bright suncolour. this is
// multiplied on to suncolour after converting to float
// (struct Colour stores as normal u8, 0..255)
Shareable sunoverbrightness; // range 1..3
+ // support different lighting models ("old" for the version compatible with old scenarios,
+ // "standard" for the new normal model that supports much brighter lighting)
+ Shareable lightingmodel;
+
Shareable skyset;
Shareable suncolour;
Shareable terraincolour;
Shareable unitcolour;
};
SHAREABLE_STRUCT(sEnvironmentSettings);
#endif
QUERY(GetEnvironmentSettings,
// no inputs
,
((sEnvironmentSettings, settings))
);
COMMAND(SetEnvironmentSettings, MERGE,
((sEnvironmentSettings, settings))
);
QUERY(GetSkySets,
// no inputs
,
((std::vector, skysets))
);
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
COMMAND(AlterElevation, MERGE,
((Position, pos))
((float, amount))
);
COMMAND(SmoothElevation, MERGE,
((Position, pos))
((float, amount))
);
COMMAND(FlattenElevation, MERGE,
((Position, pos))
((float, amount))
);
struct ePaintTerrainPriority { enum { HIGH, LOW }; };
COMMAND(PaintTerrain, MERGE,
((Position, pos))
((std::wstring, texture))
((int, priority)) // ePaintTerrainPriority
);
//////////////////////////////////////////////////////////////////////////
QUERY(PickObject,
((Position, pos))
,
((ObjectID, id))
((int, offsetx)) // offset of object centre from input position
((int, offsety)) //
);
COMMAND(MoveObject, MERGE,
((ObjectID, id))
((Position, pos))
);
COMMAND(RotateObject, MERGE,
((ObjectID, id))
((bool, usetarget)) // true => use 'target' for orientation; false => use 'angle'
((Position, target))
((float, angle))
);
COMMAND(DeleteObject, NOMERGE,
((ObjectID, id))
);
MESSAGE(SetSelectionPreview,
((std::vector, ids))
);
QUERY(GetObjectSettings,
((int, view)) // eRenderView
((ObjectID, id))
,
((sObjectSettings, settings))
);
COMMAND(SetObjectSettings, NOMERGE,
((int, view)) // eRenderView
((ObjectID, id))
((sObjectSettings, settings))
);
//////////////////////////////////////////////////////////////////////////
QUERY(GetCinemaPaths,
, // no inputs
((std::vector , paths))
);
QUERY(GetCameraInfo,
,
((AtlasMessage::sCameraInfo, info))
);
COMMAND(SetCinemaPaths, NOMERGE,
((std::vector, paths))
);
MESSAGE(CinemaEvent,
((std::wstring, path))
((int, mode))
((float, t))
((bool, drawCurrent))
((bool, lines))
);
//////////////////////////////////////////////////////////////////////////
enum eTriggerListType
{
CINEMA_LIST,
TRIGGER_LIST,
TRIG_GROUP_LIST //list of trigger groups
// [Eventually include things like entities and areas as the editor progresses...]
};
QUERY(GetTriggerData,
, //no inputs
((std::vector, groups))
((std::vector, conditions))
((std::vector, effects))
);
QUERY(GetTriggerChoices,
((std::wstring, name)),
((std::vector, choices))
((std::vector, translations))
);
COMMAND(SetAllTriggers, NOMERGE,
((std::vector, groups))
);
QUERY(GetWorldPosition,
((int, x))
((int, y)),
((Position, position))
);
MESSAGE(TriggerToggleSelector,
((bool, enable))
((Position, position))
);
#ifndef MESSAGES_SKIP_SETUP
#include "MessagesSetup.h"
#endif
#endif // INCLUDED_MESSAGES
Index: ps/trunk/source/tools/atlas/GameInterface/Handlers/EnvironmentHandlers.cpp
===================================================================
--- ps/trunk/source/tools/atlas/GameInterface/Handlers/EnvironmentHandlers.cpp (revision 9122)
+++ ps/trunk/source/tools/atlas/GameInterface/Handlers/EnvironmentHandlers.cpp (revision 9123)
@@ -1,158 +1,162 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#include "precompiled.h"
#include "MessageHandler.h"
#include "../CommandProc.h"
#include "graphics/LightEnv.h"
#include "graphics/Terrain.h"
#include "maths/MathUtil.h"
#include "ps/Game.h"
#include "ps/World.h"
#include "renderer/Renderer.h"
#include "renderer/SkyManager.h"
#include "renderer/WaterManager.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpWaterManager.h"
namespace AtlasMessage {
sEnvironmentSettings GetSettings()
{
sEnvironmentSettings s;
CmpPtr cmpWaterMan(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
debug_assert(!cmpWaterMan.null());
s.waterheight = cmpWaterMan->GetExactWaterLevel(0, 0) / (65536.f * HEIGHT_SCALE);
WaterManager* wm = g_Renderer.GetWaterManager();
s.watershininess = wm->m_Shininess;
s.waterwaviness = wm->m_Waviness;
s.watermurkiness = wm->m_Murkiness;
s.waterreflectiontintstrength = wm->m_ReflectionTintStrength;
// CColor colours
#define COLOUR(A, B) A = Colour((int)(B.r*255), (int)(B.g*255), (int)(B.b*255))
COLOUR(s.watercolour, wm->m_WaterColor);
COLOUR(s.watertint, wm->m_WaterTint);
COLOUR(s.waterreflectiontint, wm->m_ReflectionTint);
#undef COLOUR
float sunrotation = g_LightEnv.GetRotation();
if (sunrotation > (float)M_PI)
sunrotation -= (float)M_PI*2;
s.sunrotation = sunrotation;
s.sunelevation = g_LightEnv.GetElevation();
+ s.lightingmodel = CStr(g_LightEnv.GetLightingModel()).FromUTF8();
+
s.skyset = g_Renderer.GetSkyManager()->GetSkySet();
// RGBColor (CVector3D) colours
#define COLOUR(A, B) A = Colour((int)(B.X*255), (int)(B.Y*255), (int)(B.Z*255))
s.sunoverbrightness = MaxComponent(g_LightEnv.m_SunColor);
// clamp color to [0..1] before packing into u8 triplet
if(s.sunoverbrightness > 1.0f)
g_LightEnv.m_SunColor *= 1.0/s.sunoverbrightness; // (there's no operator/=)
// no component was above 1.0, so reset scale factor (don't want to darken)
else
s.sunoverbrightness = 1.0f;
COLOUR(s.suncolour, g_LightEnv.m_SunColor);
COLOUR(s.terraincolour, g_LightEnv.m_TerrainAmbientColor);
COLOUR(s.unitcolour, g_LightEnv.m_UnitsAmbientColor);
#undef COLOUR
return s;
}
void SetSettings(const sEnvironmentSettings& s)
{
CmpPtr cmpWaterMan(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
debug_assert(!cmpWaterMan.null());
cmpWaterMan->SetWaterLevel(entity_pos_t::FromFloat(s.waterheight * (65536.f * HEIGHT_SCALE)));
WaterManager* wm = g_Renderer.GetWaterManager();
wm->m_Shininess = s.watershininess;
wm->m_Waviness = s.waterwaviness;
wm->m_Murkiness = s.watermurkiness;
wm->m_ReflectionTintStrength = s.waterreflectiontintstrength;
#define COLOUR(A, B) B = CColor(A->r/255.f, A->g/255.f, A->b/255.f, 1.f)
COLOUR(s.watercolour, wm->m_WaterColor);
COLOUR(s.watertint, wm->m_WaterTint);
COLOUR(s.waterreflectiontint, wm->m_ReflectionTint);
#undef COLOUR
g_LightEnv.SetRotation(s.sunrotation);
g_LightEnv.SetElevation(s.sunelevation);
+ g_LightEnv.SetLightingModel(CStrW(*s.lightingmodel).ToUTF8());
+
CStrW skySet = *s.skyset;
if (skySet.length() == 0)
skySet = L"default";
g_Renderer.GetSkyManager()->SetSkySet(skySet);
#define COLOUR(A, B) B = RGBColor(A->r/255.f, A->g/255.f, A->b/255.f)
COLOUR(s.suncolour, g_LightEnv.m_SunColor);
g_LightEnv.m_SunColor *= s.sunoverbrightness;
COLOUR(s.terraincolour, g_LightEnv.m_TerrainAmbientColor);
COLOUR(s.unitcolour, g_LightEnv.m_UnitsAmbientColor);
#undef COLOUR
}
BEGIN_COMMAND(SetEnvironmentSettings)
{
sEnvironmentSettings m_OldSettings, m_NewSettings;
void Do()
{
m_OldSettings = GetSettings();
m_NewSettings = msg->settings;
Redo();
}
void Redo()
{
SetSettings(m_NewSettings);
}
void Undo()
{
SetSettings(m_OldSettings);
}
void MergeIntoPrevious(cSetEnvironmentSettings* prev)
{
prev->m_NewSettings = m_NewSettings;
}
};
END_COMMAND(SetEnvironmentSettings)
QUERYHANDLER(GetEnvironmentSettings)
{
msg->settings = GetSettings();
}
QUERYHANDLER(GetSkySets)
{
std::vector skies = g_Renderer.GetSkyManager()->GetSkySets();
msg->skysets = std::vector(skies.begin(), skies.end());
}
}
Index: ps/trunk/source/graphics/MapReader.cpp
===================================================================
--- ps/trunk/source/graphics/MapReader.cpp (revision 9122)
+++ ps/trunk/source/graphics/MapReader.cpp (revision 9123)
@@ -1,1307 +1,1317 @@
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#include "precompiled.h"
#include "MapReader.h"
#include "graphics/Camera.h"
#include "graphics/CinemaTrack.h"
#include "graphics/Entity.h"
#include "graphics/GameView.h"
#include "graphics/MapGenerator.h"
#include "graphics/Patch.h"
#include "graphics/Terrain.h"
#include "graphics/TerrainTextureEntry.h"
#include "graphics/TerrainTextureManager.h"
#include "lib/timer.h"
#include "maths/MathUtil.h"
#include "ps/CLogger.h"
#include "ps/Loader.h"
#include "ps/LoaderThunks.h"
#include "ps/XML/Xeromyces.h"
#include "renderer/SkyManager.h"
#include "renderer/WaterManager.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpOwnership.h"
#include "simulation2/components/ICmpPlayer.h"
#include "simulation2/components/ICmpPlayerManager.h"
#include "simulation2/components/ICmpPosition.h"
#include "simulation2/components/ICmpTerrain.h"
#include "simulation2/components/ICmpWaterManager.h"
#include
CMapReader::CMapReader()
: xml_reader(0), m_PatchesPerSide(0)
{
cur_terrain_tex = 0; // important - resets generator state
+
+ // Maps that don't override the default probably want the old lighting model
+ m_LightEnv.SetLightingModel("old");
}
// LoadMap: try to load the map from given file; reinitialise the scene to new data if successful
void CMapReader::LoadMap(const VfsPath& pathname, CTerrain *pTerrain_,
WaterManager* pWaterMan_, SkyManager* pSkyMan_,
CLightEnv *pLightEnv_, CGameView *pGameView_, CCinemaManager* pCinema_, CTriggerManager* pTrigMan_,
CSimulation2 *pSimulation2_, int playerID_)
{
// latch parameters (held until DelayedLoadFinished)
pTerrain = pTerrain_;
pLightEnv = pLightEnv_;
pGameView = pGameView_;
pWaterMan = pWaterMan_;
pSkyMan = pSkyMan_;
pCinema = pCinema_;
pTrigMan = pTrigMan_;
pSimulation2 = pSimulation2_;
m_PlayerID = playerID_;
m_CameraStartupTarget = INVALID_ENTITY;
filename_xml = pathname.ChangeExtension(L".xml");
// In some cases (particularly tests) we don't want to bother storing a large
// mostly-empty .pmp file, so we let the XML file specify basic terrain instead.
// If there's an .xml file and no .pmp, then we're probably in this XML-only mode
only_xml = false;
if (!VfsFileExists(pathname) && VfsFileExists(filename_xml))
{
only_xml = true;
}
file_format_version = CMapIO::FILE_VERSION; // default if there's no .pmp
if (!only_xml)
{
// [25ms]
unpacker.Read(pathname, "PSMP");
file_format_version = unpacker.GetVersion();
}
// check oldest supported version
if (file_format_version < FILE_READ_VERSION)
throw PSERROR_File_InvalidVersion();
// delete all existing entities
if (pSimulation2)
pSimulation2->ResetState();
// load map settings script
RegMemFun(this, &CMapReader::LoadScriptSettings, L"CMapReader::LoadScriptSettings", 50);
// load player settings script (must be done before reading map)
RegMemFun(this, &CMapReader::LoadPlayerSettings, L"CMapReader::LoadPlayerSettings", 50);
// unpack the data
if (!only_xml)
RegMemFun(this, &CMapReader::UnpackMap, L"CMapReader::UnpackMap", 1200);
// read the corresponding XML file
RegMemFun(this, &CMapReader::ReadXML, L"CMapReader::ReadXML", 5800);
// apply data to the world
RegMemFun(this, &CMapReader::ApplyData, L"CMapReader::ApplyData", 5);
// load map settings script (must be done after reading map)
RegMemFun(this, &CMapReader::LoadMapSettings, L"CMapReader::LoadMapSettings", 5);
RegMemFun(this, &CMapReader::DelayLoadFinished, L"CMapReader::DelayLoadFinished", 5);
}
// LoadRandomMap: try to load the map data; reinitialise the scene to new data if successful
void CMapReader::LoadRandomMap(const CStrW& scriptFile, const CScriptValRooted& settings, CTerrain *pTerrain_,
WaterManager* pWaterMan_, SkyManager* pSkyMan_,
CLightEnv *pLightEnv_, CGameView *pGameView_, CCinemaManager* pCinema_, CTriggerManager* pTrigMan_,
CSimulation2 *pSimulation2_, int playerID_)
{
// latch parameters (held until DelayedLoadFinished)
m_ScriptFile = scriptFile;
m_ScriptSettings = settings;
pTerrain = pTerrain_;
pLightEnv = pLightEnv_;
pGameView = pGameView_;
pWaterMan = pWaterMan_;
pSkyMan = pSkyMan_;
pCinema = pCinema_;
pTrigMan = pTrigMan_;
pSimulation2 = pSimulation2_;
m_PlayerID = playerID_;
m_CameraStartupTarget = INVALID_ENTITY;
// delete all existing entities
if (pSimulation2)
pSimulation2->ResetState();
only_xml = false;
// copy random map settings (before entity creation)
RegMemFun(this, &CMapReader::LoadRMSettings, L"CMapReader::LoadRMSettings", 50);
// load player settings script (must be done before reading map)
RegMemFun(this, &CMapReader::LoadPlayerSettings, L"CMapReader::LoadPlayerSettings", 50);
// load map generator with random map script
RegMemFun(this, &CMapReader::GenerateMap, L"CMapReader::GenerateMap", 2000);
// parse RMS results into terrain structure
RegMemFun(this, &CMapReader::ParseTerrain, L"CMapReader::ParseTerrain", 500);
// parse RMS results into environment settings
RegMemFun(this, &CMapReader::ParseEnvironment, L"CMapReader::ParseEnvironment", 5);
// parse RMS results into camera settings
RegMemFun(this, &CMapReader::ParseCamera, L"CMapReader::ParseCamera", 5);
// parse RMS results into entities
RegMemFun(this, &CMapReader::ParseEntities, L"CMapReader::ParseEntities", 1000);
// apply data to the world
RegMemFun(this, &CMapReader::ApplyData, L"CMapReader::ApplyData", 5);
// load map settings script (must be done after reading map)
RegMemFun(this, &CMapReader::LoadMapSettings, L"CMapReader::LoadMapSettings", 5);
RegMemFun(this, &CMapReader::DelayLoadFinished, L"CMapReader::DelayLoadFinished", 5);
}
// UnpackMap: unpack the given data from the raw data stream into local variables
int CMapReader::UnpackMap()
{
// now unpack everything into local data
int ret = UnpackTerrain();
if(ret != 0) // failed or timed out
return ret;
if (unpacker.GetVersion() < 4)
debug_warn(L"Old unsupported map version - objects and lighting will be lost");
return 0;
}
// UnpackTerrain: unpack the terrain from the end of the input data stream
// - data: map size, heightmap, list of textures used by map, texture tile assignments
int CMapReader::UnpackTerrain()
{
// yield after this time is reached. balances increased progress bar
// smoothness vs. slowing down loading.
const double end_time = timer_Time() + 200e-3;
// first call to generator (this is skipped after first call,
// i.e. when the loop below was interrupted)
if (cur_terrain_tex == 0)
{
m_PatchesPerSide = (ssize_t)unpacker.UnpackSize();
// unpack heightmap [600us]
size_t verticesPerSide = m_PatchesPerSide*PATCH_SIZE+1;
m_Heightmap.resize(SQR(verticesPerSide));
unpacker.UnpackRaw(&m_Heightmap[0], SQR(verticesPerSide)*sizeof(u16));
// unpack # textures
num_terrain_tex = unpacker.UnpackSize();
m_TerrainTextures.reserve(num_terrain_tex);
}
// unpack texture names; find handle for each texture.
// interruptible.
while (cur_terrain_tex < num_terrain_tex)
{
CStr texturename;
unpacker.UnpackString(texturename);
debug_assert(CTerrainTextureManager::IsInitialised()); // we need this for the terrain properties (even when graphics are disabled)
CTerrainTextureEntry* texentry = g_TexMan.FindTexture(texturename);
m_TerrainTextures.push_back(texentry);
cur_terrain_tex++;
LDR_CHECK_TIMEOUT(cur_terrain_tex, num_terrain_tex);
}
// unpack tile data [3ms]
ssize_t tilesPerSide = m_PatchesPerSide*PATCH_SIZE;
m_Tiles.resize(size_t(SQR(tilesPerSide)));
unpacker.UnpackRaw(&m_Tiles[0], sizeof(STileDesc)*m_Tiles.size());
// reset generator state.
cur_terrain_tex = 0;
return 0;
}
// ApplyData: take all the input data, and rebuild the scene from it
int CMapReader::ApplyData()
{
if (m_PatchesPerSide == 0)
{
debug_warn(L"Map has no terrain data");
return -1;
// we'll probably crash when trying to use this map later
}
if (!only_xml)
{
// initialise the terrain
pTerrain->Initialize(m_PatchesPerSide, &m_Heightmap[0]);
// setup the textures on the minipatches
STileDesc* tileptr = &m_Tiles[0];
for (ssize_t j=0; jGetPatch(i,j)->m_MiniPatches[m][k]; // can't fail
mp.Tex = m_TerrainTextures[tileptr->m_Tex1Index];
mp.Priority = tileptr->m_Priority;
tileptr++;
}
}
}
}
}
// copy over the lighting parameters
if (pLightEnv)
*pLightEnv = m_LightEnv;
if (pGameView)
{
pGameView->ResetCameraTarget(pGameView->GetCamera()->GetFocus());
if (m_CameraStartupTarget != INVALID_ENTITY)
{
CmpPtr cmpPosition(*pSimulation2, m_CameraStartupTarget);
if (!cmpPosition.null())
{
CFixedVector3D pos = cmpPosition->GetPosition();
pGameView->ResetCameraTarget(CVector3D(pos.X.ToFloat(), pos.Y.ToFloat(), pos.Z.ToFloat()));
}
}
}
CmpPtr cmpTerrain(*pSimulation2, SYSTEM_ENTITY);
if (!cmpTerrain.null())
cmpTerrain->ReloadTerrain();
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
PSRETURN CMapSummaryReader::LoadMap(const VfsPath& pathname)
{
VfsPath filename_xml = pathname.ChangeExtension(L".xml");
CXeromyces xmb_file;
if (xmb_file.Load(g_VFS, filename_xml) != PSRETURN_OK)
return PSRETURN_File_ReadFailed;
// Define all the relevant elements used in the XML file
#define EL(x) int el_##x = xmb_file.GetElementID(#x)
#define AT(x) int at_##x = xmb_file.GetAttributeID(#x)
EL(scenario);
EL(scriptsettings);
#undef AT
#undef EL
XMBElement root = xmb_file.GetRoot();
debug_assert(root.GetNodeName() == el_scenario);
XERO_ITER_EL(root, child)
{
int child_name = child.GetNodeName();
if (child_name == el_scriptsettings)
{
m_ScriptSettings = child.GetText();
}
}
return PSRETURN_OK;
}
CScriptValRooted CMapSummaryReader::GetMapSettings(ScriptInterface& scriptInterface)
{
CScriptValRooted data;
scriptInterface.Eval("({})", data);
if (!m_ScriptSettings.empty())
scriptInterface.SetProperty(data.get(), "settings", scriptInterface.ParseJSON(m_ScriptSettings), false);
return data;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Holds various state data while reading maps, so that loading can be
// interrupted (e.g. to update the progress display) then later resumed.
class CXMLReader
{
NONCOPYABLE(CXMLReader);
public:
CXMLReader(const VfsPath& xml_filename, CMapReader& mapReader)
: m_MapReader(mapReader)
{
Init(xml_filename);
}
CStr ReadScriptSettings();
// return semantics: see Loader.cpp!LoadFunc.
int ProgressiveRead();
private:
CXeromyces xmb_file;
CMapReader& m_MapReader;
int el_entity;
int el_tracks;
int el_template, el_player;
int el_position, el_orientation;
int el_nonentity;
int el_actor;
int at_x, at_y, at_z;
int at_id;
int at_angle;
int at_uid;
XMBElementList nodes; // children of root
// loop counters
int node_idx;
int entity_idx, nonentity_idx;
// # entities+nonentities processed and total (for progress calc)
int completed_jobs, total_jobs;
// maximum used entity ID, so we can safely allocate new ones
entity_id_t max_uid;
void Init(const VfsPath& xml_filename);
void ReadTerrain(XMBElement parent);
void ReadEnvironment(XMBElement parent);
void ReadCamera(XMBElement parent);
void ReadCinema(XMBElement parent);
void ReadTriggers(XMBElement parent);
int ReadEntities(XMBElement parent, double end_time);
int ReadOldEntities(XMBElement parent, double end_time);
int ReadNonEntities(XMBElement parent, double end_time);
};
void CXMLReader::Init(const VfsPath& xml_filename)
{
// must only assign once, so do it here
node_idx = entity_idx = nonentity_idx = 0;
if (xmb_file.Load(g_VFS, xml_filename) != PSRETURN_OK)
throw PSERROR_File_ReadFailed();
// define the elements and attributes that are frequently used in the XML file,
// so we don't need to do lots of string construction and comparison when
// reading the data.
// (Needs to be synchronised with the list in CXMLReader - ugh)
#define EL(x) el_##x = xmb_file.GetElementID(#x)
#define AT(x) at_##x = xmb_file.GetAttributeID(#x)
EL(entity);
EL(tracks);
EL(template);
EL(player);
EL(position);
EL(orientation);
EL(nonentity);
EL(actor);
AT(x); AT(y); AT(z);
AT(angle);
AT(uid);
#undef AT
#undef EL
XMBElement root = xmb_file.GetRoot();
debug_assert(xmb_file.GetElementString(root.GetNodeName()) == "Scenario");
nodes = root.GetChildNodes();
// find out total number of entities+nonentities
// (used when calculating progress)
completed_jobs = 0;
total_jobs = 0;
for (int i = 0; i < nodes.Count; i++)
total_jobs += nodes.Item(i).GetChildNodes().Count;
// Find the maximum entity ID, so we can safely allocate new IDs without conflicts
max_uid = SYSTEM_ENTITY;
XMBElement ents = nodes.GetFirstNamedItem(xmb_file.GetElementID("Entities"));
XERO_ITER_EL(ents, ent)
{
CStr uid = ent.GetAttributes().GetNamedItem(at_uid);
max_uid = std::max(max_uid, (entity_id_t)uid.ToUInt());
}
}
CStr CXMLReader::ReadScriptSettings()
{
XMBElement root = xmb_file.GetRoot();
debug_assert(xmb_file.GetElementString(root.GetNodeName()) == "Scenario");
nodes = root.GetChildNodes();
XMBElement settings = nodes.GetFirstNamedItem(xmb_file.GetElementID("ScriptSettings"));
return settings.GetText();
}
void CXMLReader::ReadTerrain(XMBElement parent)
{
#define AT(x) int at_##x = xmb_file.GetAttributeID(#x)
AT(patches);
AT(texture);
AT(priority);
AT(height);
#undef AT
ssize_t patches = 9;
CStr texture = "grass1_spring";
int priority = 0;
u16 height = 16384;
XERO_ITER_ATTR(parent, attr)
{
if (attr.Name == at_patches)
patches = attr.Value.ToInt();
else if (attr.Name == at_texture)
texture = attr.Value;
else if (attr.Name == at_priority)
priority = attr.Value.ToInt();
else if (attr.Name == at_height)
height = (u16)attr.Value.ToInt();
}
m_MapReader.m_PatchesPerSide = patches;
// Load the texture
debug_assert(CTerrainTextureManager::IsInitialised()); // we need this for the terrain properties (even when graphics are disabled)
CTerrainTextureEntry* texentry = g_TexMan.FindTexture(texture);
m_MapReader.pTerrain->Initialize(patches, NULL);
// Fill the heightmap
u16* heightmap = m_MapReader.pTerrain->GetHeightMap();
ssize_t verticesPerSide = m_MapReader.pTerrain->GetVerticesPerSide();
for (ssize_t i = 0; i < SQR(verticesPerSide); ++i)
heightmap[i] = height;
// Fill the texture map
for (ssize_t pz = 0; pz < patches; ++pz)
{
for (ssize_t px = 0; px < patches; ++px)
{
CPatch* patch = m_MapReader.pTerrain->GetPatch(px, pz); // can't fail
for (ssize_t z = 0; z < PATCH_SIZE; ++z)
{
for (ssize_t x = 0; x < PATCH_SIZE; ++x)
{
patch->m_MiniPatches[z][x].Tex = texentry;
patch->m_MiniPatches[z][x].Priority = priority;
}
}
}
}
}
void CXMLReader::ReadEnvironment(XMBElement parent)
{
#define EL(x) int el_##x = xmb_file.GetElementID(#x)
#define AT(x) int at_##x = xmb_file.GetAttributeID(#x)
+ EL(lightingmodel);
EL(skyset);
EL(suncolour);
EL(sunelevation);
EL(sunrotation);
EL(terrainambientcolour);
EL(unitsambientcolour);
EL(terrainshadowtransparency);
EL(water);
EL(waterbody);
EL(type);
EL(colour);
EL(height);
EL(shininess);
EL(waviness);
EL(murkiness);
EL(tint);
EL(reflectiontint);
EL(reflectiontintstrength);
AT(r); AT(g); AT(b);
#undef AT
#undef EL
XERO_ITER_EL(parent, element)
{
int element_name = element.GetNodeName();
XMBAttributeList attrs = element.GetAttributes();
- if (element_name == el_skyset)
+ if (element_name == el_lightingmodel)
+ {
+ m_MapReader.m_LightEnv.SetLightingModel(element.GetText());
+ }
+ else if (element_name == el_skyset)
{
if (m_MapReader.pSkyMan)
m_MapReader.pSkyMan->SetSkySet(element.GetText().FromUTF8());
}
else if (element_name == el_suncolour)
{
m_MapReader.m_LightEnv.m_SunColor = RGBColor(
attrs.GetNamedItem(at_r).ToFloat(),
attrs.GetNamedItem(at_g).ToFloat(),
attrs.GetNamedItem(at_b).ToFloat());
}
else if (element_name == el_sunelevation)
{
m_MapReader.m_LightEnv.m_Elevation = attrs.GetNamedItem(at_angle).ToFloat();
}
else if (element_name == el_sunrotation)
{
m_MapReader.m_LightEnv.m_Rotation = attrs.GetNamedItem(at_angle).ToFloat();
}
else if (element_name == el_terrainambientcolour)
{
m_MapReader.m_LightEnv.m_TerrainAmbientColor = RGBColor(
attrs.GetNamedItem(at_r).ToFloat(),
attrs.GetNamedItem(at_g).ToFloat(),
attrs.GetNamedItem(at_b).ToFloat());
}
else if (element_name == el_unitsambientcolour)
{
m_MapReader.m_LightEnv.m_UnitsAmbientColor = RGBColor(
attrs.GetNamedItem(at_r).ToFloat(),
attrs.GetNamedItem(at_g).ToFloat(),
attrs.GetNamedItem(at_b).ToFloat());
}
else if (element_name == el_terrainshadowtransparency)
{
m_MapReader.m_LightEnv.SetTerrainShadowTransparency(element.GetText().ToFloat());
}
else if (element_name == el_water)
{
XERO_ITER_EL(element, waterbody)
{
debug_assert(waterbody.GetNodeName() == el_waterbody);
XERO_ITER_EL(waterbody, waterelement)
{
int element_name = waterelement.GetNodeName();
if (element_name == el_height)
{
CmpPtr cmpWaterMan(*m_MapReader.pSimulation2, SYSTEM_ENTITY);
debug_assert(!cmpWaterMan.null());
cmpWaterMan->SetWaterLevel(entity_pos_t::FromString(waterelement.GetText()));
continue;
}
// The rest are purely graphical effects, and should be ignored if
// graphics are disabled
if (!m_MapReader.pWaterMan)
continue;
if (element_name == el_type)
{
// TODO: implement this, when WaterManager supports it
}
#define READ_COLOUR(el, out) \
else if (element_name == el) \
{ \
XMBAttributeList attrs = waterelement.GetAttributes(); \
out = CColor( \
attrs.GetNamedItem(at_r).ToFloat(), \
attrs.GetNamedItem(at_g).ToFloat(), \
attrs.GetNamedItem(at_b).ToFloat(), \
1.f); \
}
#define READ_FLOAT(el, out) \
else if (element_name == el) \
{ \
out = waterelement.GetText().ToFloat(); \
} \
READ_COLOUR(el_colour, m_MapReader.pWaterMan->m_WaterColor)
READ_FLOAT(el_shininess, m_MapReader.pWaterMan->m_Shininess)
READ_FLOAT(el_waviness, m_MapReader.pWaterMan->m_Waviness)
READ_FLOAT(el_murkiness, m_MapReader.pWaterMan->m_Murkiness)
READ_COLOUR(el_tint, m_MapReader.pWaterMan->m_WaterTint)
READ_COLOUR(el_reflectiontint, m_MapReader.pWaterMan->m_ReflectionTint)
READ_FLOAT(el_reflectiontintstrength, m_MapReader.pWaterMan->m_ReflectionTintStrength)
#undef READ_FLOAT
#undef READ_COLOUR
else
debug_warn(L"Invalid map XML data");
}
}
}
else
debug_warn(L"Invalid map XML data");
}
m_MapReader.m_LightEnv.CalculateSunDirection();
}
void CXMLReader::ReadCamera(XMBElement parent)
{
#define EL(x) int el_##x = xmb_file.GetElementID(#x)
#define AT(x) int at_##x = xmb_file.GetAttributeID(#x)
EL(declination);
EL(rotation);
EL(position);
AT(angle);
AT(x); AT(y); AT(z);
#undef AT
#undef EL
float declination = DEGTORAD(30.f), rotation = DEGTORAD(-45.f);
CVector3D translation = CVector3D(100, 150, -100);
XERO_ITER_EL(parent, element)
{
int element_name = element.GetNodeName();
XMBAttributeList attrs = element.GetAttributes();
if (element_name == el_declination)
{
declination = attrs.GetNamedItem(at_angle).ToFloat();
}
else if (element_name == el_rotation)
{
rotation = attrs.GetNamedItem(at_angle).ToFloat();
}
else if (element_name == el_position)
{
translation = CVector3D(
attrs.GetNamedItem(at_x).ToFloat(),
attrs.GetNamedItem(at_y).ToFloat(),
attrs.GetNamedItem(at_z).ToFloat());
}
else
debug_warn(L"Invalid map XML data");
}
if (m_MapReader.pGameView)
{
m_MapReader.pGameView->GetCamera()->m_Orientation.SetXRotation(declination);
m_MapReader.pGameView->GetCamera()->m_Orientation.RotateY(rotation);
m_MapReader.pGameView->GetCamera()->m_Orientation.Translate(translation);
m_MapReader.pGameView->GetCamera()->UpdateFrustum();
}
}
void CXMLReader::ReadCinema(XMBElement parent)
{
#define EL(x) int el_##x = xmb_file.GetElementID(#x)
#define AT(x) int at_##x = xmb_file.GetAttributeID(#x)
EL(path);
EL(rotation);
EL(distortion);
EL(node);
EL(position);
EL(time);
AT(name);
AT(timescale);
AT(mode);
AT(style);
AT(growth);
AT(switch);
AT(x);
AT(y);
AT(z);
#undef EL
#undef AT
std::map pathList;
XERO_ITER_EL(parent, element)
{
int elementName = element.GetNodeName();
if ( elementName == el_path )
{
XMBAttributeList attrs = element.GetAttributes();
CStrW name(attrs.GetNamedItem(at_name).FromUTF8());
float timescale = attrs.GetNamedItem(at_timescale).ToFloat();
CCinemaData pathData;
pathData.m_Timescale = timescale;
TNSpline spline, backwardSpline;
XERO_ITER_EL(element, pathChild)
{
elementName = pathChild.GetNodeName();
attrs = pathChild.GetAttributes();
//Load distortion attributes
if ( elementName == el_distortion )
{
pathData.m_Mode = attrs.GetNamedItem(at_mode).ToInt();
pathData.m_Style = attrs.GetNamedItem(at_style).ToInt();
pathData.m_Growth = attrs.GetNamedItem(at_growth).ToInt();
pathData.m_Switch = attrs.GetNamedItem(at_switch).ToInt();
}
//Load node data used for spline
else if ( elementName == el_node )
{
SplineData data;
XERO_ITER_EL(pathChild, nodeChild)
{
elementName = nodeChild.GetNodeName();
attrs = nodeChild.GetAttributes();
//Fix?: assumes that time is last element
if ( elementName == el_position )
{
data.Position.X = attrs.GetNamedItem(at_x).ToFloat();
data.Position.Y = attrs.GetNamedItem(at_y).ToFloat();
data.Position.Z = attrs.GetNamedItem(at_z).ToFloat();
continue;
}
else if ( elementName == el_rotation )
{
data.Rotation.X = attrs.GetNamedItem(at_x).ToFloat();
data.Rotation.Y = attrs.GetNamedItem(at_y).ToFloat();
data.Rotation.Z = attrs.GetNamedItem(at_z).ToFloat();
continue;
}
else if ( elementName == el_time )
data.Distance = nodeChild.GetText().ToFloat();
else
debug_warn(L"Invalid cinematic element for node child");
backwardSpline.AddNode(data.Position, data.Rotation, data.Distance);
}
}
else
debug_warn(L"Invalid cinematic element for path child");
}
//Construct cinema path with data gathered
CCinemaPath temp(pathData, backwardSpline);
const std::vector& nodes = temp.GetAllNodes();
if ( nodes.empty() )
{
debug_warn(L"Failure loading cinematics");
return;
}
for ( std::vector::const_reverse_iterator it = nodes.rbegin();
it != nodes.rend(); ++it )
{
spline.AddNode(it->Position, it->Rotation, it->Distance);
}
CCinemaPath path(pathData, spline);
pathList[name] = path;
}
else
debug_assert("Invalid cinema child");
}
if (m_MapReader.pCinema)
m_MapReader.pCinema->SetAllPaths(pathList);
}
void CXMLReader::ReadTriggers(XMBElement UNUSED(parent))
{
}
int CXMLReader::ReadEntities(XMBElement parent, double end_time)
{
XMBElementList entities = parent.GetChildNodes();
while (entity_idx < entities.Count)
{
// all new state at this scope and below doesn't need to be
// wrapped, since we only yield after a complete iteration.
XMBElement entity = entities.Item(entity_idx++);
debug_assert(entity.GetNodeName() == el_entity);
XMBAttributeList attrs = entity.GetAttributes();
CStr uid = attrs.GetNamedItem(at_uid);
debug_assert(!uid.empty());
int EntityUid = uid.ToInt();
CStrW TemplateName;
int PlayerID = 0;
CFixedVector3D Position;
CFixedVector3D Orientation;
XERO_ITER_EL(entity, setting)
{
int element_name = setting.GetNodeName();
//
if (element_name == el_template)
{
TemplateName = setting.GetText().FromUTF8();
}
//
else if (element_name == el_player)
{
PlayerID = setting.GetText().ToInt();
}
//
else if (element_name == el_position)
{
XMBAttributeList attrs = setting.GetAttributes();
Position = CFixedVector3D(
fixed::FromString(attrs.GetNamedItem(at_x)),
fixed::FromString(attrs.GetNamedItem(at_y)),
fixed::FromString(attrs.GetNamedItem(at_z)));
}
//
else if (element_name == el_orientation)
{
XMBAttributeList attrs = setting.GetAttributes();
Orientation = CFixedVector3D(
fixed::FromString(attrs.GetNamedItem(at_x)),
fixed::FromString(attrs.GetNamedItem(at_y)),
fixed::FromString(attrs.GetNamedItem(at_z)));
// TODO: what happens if some attributes are missing?
}
else
debug_warn(L"Invalid map XML data");
}
CSimulation2& sim = *m_MapReader.pSimulation2;
entity_id_t ent = sim.AddEntity(TemplateName, EntityUid);
if (ent == INVALID_ENTITY)
LOGERROR(L"Failed to load entity template '%ls'", TemplateName.c_str());
else
{
CmpPtr cmpPosition(sim, ent);
if (!cmpPosition.null())
{
cmpPosition->JumpTo(Position.X, Position.Z);
cmpPosition->SetYRotation(Orientation.Y);
// TODO: other parts of the position
}
CmpPtr cmpOwner(sim, ent);
if (!cmpOwner.null())
cmpOwner->SetOwner(PlayerID);
if (boost::algorithm::ends_with(TemplateName, L"civil_centre"))
{
// HACK: we special-case civil centre files to initialise the camera.
// This ought to be based on a more generic mechanism for indicating
// per-player camera start locations.
if (m_MapReader.m_CameraStartupTarget == INVALID_ENTITY && PlayerID == m_MapReader.m_PlayerID && !cmpPosition.null())
m_MapReader.m_CameraStartupTarget = ent;
}
}
completed_jobs++;
LDR_CHECK_TIMEOUT(completed_jobs, total_jobs);
}
return 0;
}
int CXMLReader::ProgressiveRead()
{
// yield after this time is reached. balances increased progress bar
// smoothness vs. slowing down loading.
const double end_time = timer_Time() + 200e-3;
int ret;
while (node_idx < nodes.Count)
{
XMBElement node = nodes.Item(node_idx);
CStr name = xmb_file.GetElementString(node.GetNodeName());
if (name == "Terrain")
{
ReadTerrain(node);
}
else if (name == "Environment")
{
ReadEnvironment(node);
}
else if (name == "Camera")
{
ReadCamera(node);
}
else if (name == "ScriptSettings")
{
//Already loaded - this is to prevent an assertion
}
else if (name == "Entities")
{
ret = ReadEntities(node, end_time);
if (ret != 0) // error or timed out
return ret;
}
else if (name == "Paths")
{
ReadCinema(node);
}
else if (name == "Triggers")
{
ReadTriggers(node);
}
else if (name == "Script")
{
m_MapReader.pSimulation2->SetStartupScript(node.GetText().FromUTF8());
}
else
{
debug_printf(L"Invalid XML element in map file: %hs\n", name.c_str());
debug_warn(L"Invalid map XML data");
}
node_idx++;
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// load script settings from map
int CMapReader::LoadScriptSettings()
{
if (!xml_reader)
xml_reader = new CXMLReader(filename_xml, *this);
// parse the script settings
pSimulation2->SetMapSettings(xml_reader->ReadScriptSettings());
return 0;
}
// load player settings script
int CMapReader::LoadPlayerSettings()
{
pSimulation2->LoadPlayerSettings();
return 0;
}
// load map settings script
int CMapReader::LoadMapSettings()
{
pSimulation2->LoadMapSettings();
return 0;
}
// progressive
int CMapReader::ReadXML()
{
if (!xml_reader)
xml_reader = new CXMLReader(filename_xml, *this);
int ret = xml_reader->ProgressiveRead();
// finished or failed
if (ret <= 0)
{
delete xml_reader;
xml_reader = 0;
}
return ret;
}
int CMapReader::DelayLoadFinished()
{
// we were dynamically allocated by CWorld::Initialize
delete this;
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int CMapReader::LoadRMSettings()
{
// copy random map settings over to sim
pSimulation2->SetMapSettings(m_ScriptSettings);
return 0;
}
int CMapReader::GenerateMap()
{
CMapGenerator mapGen;
VfsPath scriptPath;
if (m_ScriptFile.length())
scriptPath = L"maps/random/"+m_ScriptFile;
// Copy map settings from simulator to mapgen context
CScriptValRooted scriptSettings(mapGen.GetScriptInterface().GetContext(), mapGen.GetScriptInterface().CloneValueFromOtherContext(pSimulation2->GetScriptInterface(), m_ScriptSettings.get()));
// Try to generate map
if (!mapGen.GenerateMap(scriptPath, scriptSettings))
{ // RMS failed
// TODO: Need to do something safe here, like cancel loading and return to main menu
LOGERROR(L"Map generation failed: RMS returned undefined");
return -1;
}
if (mapGen.GetMapData().undefined())
{
LOGERROR(L"undefined map data");
}
// Copy data from mapgen to simulator context
m_MapData = CScriptValRooted(pSimulation2->GetScriptInterface().GetContext(), pSimulation2->GetScriptInterface().CloneValueFromOtherContext(mapGen.GetScriptInterface(), mapGen.GetMapData().get()));
return 0;
};
int CMapReader::ParseTerrain()
{
// parse terrain from map data
#define GET_TERRAIN_PROPERTY(prop, out)\
if (!pSimulation2->GetScriptInterface().GetProperty(m_MapData.get(), #prop, out))\
LOGERROR(L"CMapReader::ParseTerrain() failed to get '%hs' property", #prop);
int size;
GET_TERRAIN_PROPERTY(size, size)
m_PatchesPerSide = size / PATCH_SIZE;
// flat heightmap of u16 data
GET_TERRAIN_PROPERTY(height, m_Heightmap)
// load textures
std::vector textureNames;
GET_TERRAIN_PROPERTY(textureNames, textureNames)
num_terrain_tex = textureNames.size();
while (cur_terrain_tex < num_terrain_tex)
{
debug_assert(CTerrainTextureManager::IsInitialised()); // we need this for the terrain properties (even when graphics are disabled)
CTerrainTextureEntry* texentry = g_TexMan.FindTexture(textureNames[cur_terrain_tex]);
m_TerrainTextures.push_back(texentry);
cur_terrain_tex++;
}
// build tile data
m_Tiles.resize(SQR(size));
std::vector tileData;
GET_TERRAIN_PROPERTY(tileData, tileData)
for (size_t i = 0; i < tileData.size(); ++i)
{
m_Tiles[i] = tileData[i];
}
// reset generator state
cur_terrain_tex = 0;
#undef GET_TERRAIN_PROPERTY
return 0;
}
int CMapReader::ParseEntities()
{
// parse entities from map data
std::vector entities;
if (!pSimulation2->GetScriptInterface().GetProperty(m_MapData.get(), "entities", entities))
LOGWARNING(L"CMapReader::ParseEntities() failed to get 'entities' property");
size_t entity_idx = 0;
size_t num_entities = entities.size();
Entity currEnt;
while (entity_idx < num_entities)
{
// Get current entity struct
currEnt = entities[entity_idx];
entity_id_t ent = pSimulation2->AddEntity(currEnt.templateName, currEnt.entityID);
// Check that entity was added
if (ent == INVALID_ENTITY)
{
LOGERROR(L"Failed to load entity template '%ls'", currEnt.templateName.c_str());
}
else
{
CmpPtr cmpPosition(*pSimulation2, ent);
if (!cmpPosition.null())
{
cmpPosition->JumpTo(entity_pos_t::FromFloat(currEnt.positionX), entity_pos_t::FromFloat(currEnt.positionZ));
cmpPosition->SetYRotation(entity_angle_t::FromFloat(currEnt.orientationY));
// TODO: other parts of the position
}
CmpPtr cmpOwner(*pSimulation2, ent);
if (!cmpOwner.null())
cmpOwner->SetOwner(currEnt.playerID);
if (boost::algorithm::ends_with(currEnt.templateName, L"civil_centre"))
{
// HACK: we special-case civil centre files to initialise the camera.
// This ought to be based on a more generic mechanism for indicating
// per-player camera start locations.
if (m_CameraStartupTarget == INVALID_ENTITY && currEnt.playerID == m_PlayerID && !cmpPosition.null())
m_CameraStartupTarget = ent;
}
}
entity_idx++;
}
return 0;
}
int CMapReader::ParseEnvironment()
{
// parse environment settings from map data
#define GET_ENVIRONMENT_PROPERTY(val, prop, out)\
if (!pSimulation2->GetScriptInterface().GetProperty(val, #prop, out))\
LOGWARNING(L"CMapReader::ParseEnvironment() failed to get '%hs' property", #prop);
CScriptValRooted envObj;
GET_ENVIRONMENT_PROPERTY(m_MapData.get(), Environment, envObj)
if (envObj.undefined())
{
LOGWARNING(L"CMapReader::ParseEnvironment(): Environment settings not found");
return 0;
}
+ m_LightEnv.SetLightingModel("standard");
+
std::wstring skySet;
GET_ENVIRONMENT_PROPERTY(envObj.get(), SkySet, skySet)
pSkyMan->SetSkySet(skySet);
CColor sunColor;
GET_ENVIRONMENT_PROPERTY(envObj.get(), SunColour, sunColor)
m_LightEnv.m_SunColor = RGBColor(sunColor.r, sunColor.g, sunColor.b);
GET_ENVIRONMENT_PROPERTY(envObj.get(), SunElevation, m_LightEnv.m_Elevation)
GET_ENVIRONMENT_PROPERTY(envObj.get(), SunRotation, m_LightEnv.m_Rotation)
CColor terrainAmbientColor;
GET_ENVIRONMENT_PROPERTY(envObj.get(), TerrainAmbientColour, terrainAmbientColor)
m_LightEnv.m_TerrainAmbientColor = RGBColor(terrainAmbientColor.r, terrainAmbientColor.g, terrainAmbientColor.b);
CColor unitsAmbientColor;
GET_ENVIRONMENT_PROPERTY(envObj.get(), UnitsAmbientColour, unitsAmbientColor)
m_LightEnv.m_UnitsAmbientColor = RGBColor(unitsAmbientColor.r, unitsAmbientColor.g, unitsAmbientColor.b);
// Water properties
CScriptValRooted waterObj;
GET_ENVIRONMENT_PROPERTY(envObj.get(), Water, waterObj)
CScriptValRooted waterBodyObj;
GET_ENVIRONMENT_PROPERTY(waterObj.get(), WaterBody, waterBodyObj)
// Water level - necessary
float waterHeight;
GET_ENVIRONMENT_PROPERTY(waterBodyObj.get(), Height, waterHeight)
CmpPtr cmpWaterMan(*pSimulation2, SYSTEM_ENTITY);
debug_assert(!cmpWaterMan.null());
cmpWaterMan->SetWaterLevel(entity_pos_t::FromFloat(waterHeight));
// If we have graphics, get rest of settings
if (pWaterMan)
{
std::wstring waterType;
// TODO: Water type not implemented
//GET_ENVIRONMENT_PROPERTY(waterBodyObj.get(), Type, waterType)
GET_ENVIRONMENT_PROPERTY(waterBodyObj.get(), Colour, pWaterMan->m_WaterColor)
GET_ENVIRONMENT_PROPERTY(waterBodyObj.get(), Shininess, pWaterMan->m_Shininess)
GET_ENVIRONMENT_PROPERTY(waterBodyObj.get(), Waviness, pWaterMan->m_Waviness)
GET_ENVIRONMENT_PROPERTY(waterBodyObj.get(), Murkiness, pWaterMan->m_Murkiness)
GET_ENVIRONMENT_PROPERTY(waterBodyObj.get(), Tint, pWaterMan->m_WaterTint)
GET_ENVIRONMENT_PROPERTY(waterBodyObj.get(), ReflectionTint, pWaterMan->m_ReflectionTint)
GET_ENVIRONMENT_PROPERTY(waterBodyObj.get(), ReflectionTintStrength, pWaterMan->m_ReflectionTintStrength)
}
m_LightEnv.CalculateSunDirection();
#undef GET_ENVIRONMENT_PROPERTY
return 0;
}
int CMapReader::ParseCamera()
{
// parse camera settings from map data
// defaults if we don't find camera
float declination = DEGTORAD(30.f), rotation = DEGTORAD(-45.f);
CVector3D translation = CVector3D(100, 150, -100);
#define GET_CAMERA_PROPERTY(val, prop, out)\
if (!pSimulation2->GetScriptInterface().GetProperty(val, #prop, out))\
LOGWARNING(L"CMapReader::ParseCamera() failed to get '%hs' property", #prop);
CScriptValRooted cameraObj;
GET_CAMERA_PROPERTY(m_MapData.get(), Camera, cameraObj)
if (!cameraObj.undefined())
{ // If camera property exists, read values
CFixedVector3D pos;
GET_CAMERA_PROPERTY(cameraObj.get(), Position, pos)
translation = pos;
GET_CAMERA_PROPERTY(cameraObj.get(), Rotation, rotation)
GET_CAMERA_PROPERTY(cameraObj.get(), Declination, declination)
}
#undef GET_CAMERA_PROPERTY
if (pGameView)
{
pGameView->GetCamera()->m_Orientation.SetXRotation(declination);
pGameView->GetCamera()->m_Orientation.RotateY(rotation);
pGameView->GetCamera()->m_Orientation.Translate(translation);
pGameView->GetCamera()->UpdateFrustum();
}
return 0;
}
Index: ps/trunk/source/graphics/Material.h
===================================================================
--- ps/trunk/source/graphics/Material.h (revision 9122)
+++ ps/trunk/source/graphics/Material.h (revision 9123)
@@ -1,116 +1,99 @@
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#ifndef INCLUDED_MATERIAL
#define INCLUDED_MATERIAL
#include "ps/CStr.h"
+#include "ps/Overlay.h"
#include "simulation2/helpers/Player.h"
// FIXME: This material system is almost entirely unused and probably broken
-struct CColor;
-
-struct SMaterialColor
-{
-public:
- float r;
- float g;
- float b;
- float a;
-
- SMaterialColor() : r(0.0f), g(0.0f), b(0.0f), a(1.0f) {}
- SMaterialColor(float _r, float _g, float _b, float _a)
- {
- r = _r;
- g = _g;
- b = _b;
- a = _a;
- }
-};
+typedef CColor SMaterialColor;
class CMaterial
{
public:
CMaterial();
void Bind();
void Unbind();
const CStr& GetTexture() { return m_Texture; }
const CStr& GetVertexProgram() { return m_VertexProgram; }
const CStr& GetFragmentProgram() { return m_FragmentProgram; }
SMaterialColor GetDiffuse();
SMaterialColor GetAmbient();
SMaterialColor GetSpecular();
SMaterialColor GetEmissive();
float GetSpecularPower() { return m_SpecularPower; }
bool UsesAlpha() { return m_Alpha; }
// Determines whether or not the model goes into the PlayerRenderer
bool IsPlayer() { return (m_UseTextureColor || m_UsePlayerColor); }
// Get the player colour or texture colour to be applied to this object
SMaterialColor GetObjectColor();
// Get the player colour
SMaterialColor GetPlayerColor();
void SetPlayerID(player_id_t id);
void SetTextureColor(const CColor &colour);
void SetUsePlayerColor(bool use);
void SetUseTextureColor(bool use);
void SetTexture(const CStr& texture);
void SetVertexProgram(const CStr& prog);
void SetFragmentProgram(const CStr& prog);
void SetDiffuse(const SMaterialColor& color);
void SetAmbient(const SMaterialColor& color);
void SetSpecular(const SMaterialColor& color);
void SetEmissive(const SMaterialColor& color);
void SetSpecularPower(float power);
void SetUsesAlpha(bool flag);
private:
// Various reflective color properties
SMaterialColor m_Diffuse;
SMaterialColor m_Ambient;
SMaterialColor m_Specular;
SMaterialColor m_Emissive;
float m_SpecularPower;
// Path to the materials texture
CStr m_Texture;
// Paths to vertex/fragment programs
CStr m_VertexProgram;
CStr m_FragmentProgram;
// Alpha required flag
bool m_Alpha;
player_id_t m_PlayerID;
SMaterialColor m_TextureColor; // used as an alternative to the per-player colour
bool m_UsePlayerColor;
bool m_UseTextureColor;
};
extern CMaterial NullMaterial;
#endif
Index: ps/trunk/source/graphics/ShaderManager.h
===================================================================
--- ps/trunk/source/graphics/ShaderManager.h (nonexistent)
+++ ps/trunk/source/graphics/ShaderManager.h (revision 9123)
@@ -0,0 +1,79 @@
+/* Copyright (C) 2011 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0 A.D. If not, see .
+ */
+
+#ifndef INCLUDED_SHADERMANAGER
+#define INCLUDED_SHADERMANAGER
+
+#define USE_SHADER_XML_VALIDATION 1
+
+#include
+#include
+
+#include "graphics/ShaderProgram.h"
+
+#if USE_SHADER_XML_VALIDATION
+# include "ps/XML/RelaxNG.h"
+#endif
+
+/**
+ * Shader manager: loads and caches shader programs.
+ */
+class CShaderManager
+{
+public:
+ CShaderManager();
+ ~CShaderManager();
+
+ /**
+ * Load a shader program.
+ * @param name name of shader XML specification (file is loaded from shaders/${name}.xml)
+ * @param defines key/value set of preprocessor definitions
+ * @return loaded program, or null pointer on error
+ */
+ CShaderProgramPtr LoadProgram(const char* name, const std::map& defines);
+
+private:
+ bool NewProgram(const char* name, const std::map& defines, CShaderProgramPtr& program);
+
+ static LibError ReloadChangedFileCB(void* param, const VfsPath& path);
+ LibError ReloadChangedFile(const VfsPath& path);
+
+ struct CacheKey
+ {
+ std::string name;
+ std::map defines;
+
+ bool operator<(const CacheKey& k) const
+ {
+ if (name < k.name) return true;
+ if (k.name < name) return false;
+ return defines < k.defines;
+ }
+ };
+
+ std::map m_Cache;
+
+ // Store the set of shaders that need to be reloaded when the given file is modified
+ typedef boost::unordered_map > > HotloadFilesMap;
+ HotloadFilesMap m_HotloadFiles;
+
+#if USE_SHADER_XML_VALIDATION
+ RelaxNGValidator m_Validator;
+#endif
+};
+
+#endif // INCLUDED_SHADERMANAGER
Property changes on: ps/trunk/source/graphics/ShaderManager.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: ps/trunk/source/graphics/ShaderTechnique.cpp
===================================================================
--- ps/trunk/source/graphics/ShaderTechnique.cpp (nonexistent)
+++ ps/trunk/source/graphics/ShaderTechnique.cpp (revision 9123)
@@ -0,0 +1,134 @@
+/* Copyright (C) 2011 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0 A.D. If not, see .
+ */
+
+#include "precompiled.h"
+
+#include "ShaderTechnique.h"
+
+CShaderPass::CShaderPass(const CShaderProgramPtr& shader) :
+ m_Shader(shader),
+ m_HasAlpha(false), m_HasBlend(false), m_HasColorMask(false), m_HasDepthMask(false)
+{
+}
+
+void CShaderPass::Bind()
+{
+ m_Shader->Bind();
+
+ if (m_HasAlpha)
+ {
+ glEnable(GL_ALPHA_TEST);
+ glAlphaFunc(m_AlphaFunc, m_AlphaRef);
+ }
+
+ if (m_HasBlend)
+ {
+ glEnable(GL_BLEND);
+ glBlendFunc(m_BlendSrc, m_BlendDst);
+ }
+
+ if (m_HasColorMask)
+ glColorMask(m_ColorMaskR, m_ColorMaskG, m_ColorMaskB, m_ColorMaskA);
+
+ if (m_HasDepthMask)
+ glDepthMask(m_DepthMask);
+}
+
+void CShaderPass::Unbind()
+{
+ m_Shader->Unbind();
+
+ if (m_HasAlpha)
+ {
+ glDisable(GL_ALPHA_TEST);
+ }
+
+ if (m_HasBlend)
+ {
+ glDisable(GL_BLEND);
+ }
+
+ if (m_HasColorMask)
+ glColorMask(1, 1, 1, 1);
+
+ if (m_HasDepthMask)
+ glDepthMask(1);
+}
+
+void CShaderPass::AlphaFunc(GLenum func, GLclampf ref)
+{
+ m_HasAlpha = true;
+ m_AlphaFunc = func;
+ m_AlphaRef = ref;
+}
+
+void CShaderPass::BlendFunc(GLenum src, GLenum dst)
+{
+ m_HasBlend = true;
+ m_BlendSrc = src;
+ m_BlendDst = dst;
+}
+
+void CShaderPass::ColorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a)
+{
+ m_HasColorMask = true;
+ m_ColorMaskR = r;
+ m_ColorMaskG = g;
+ m_ColorMaskB = b;
+ m_ColorMaskA = a;
+}
+
+void CShaderPass::DepthMask(GLboolean mask)
+{
+ m_HasDepthMask = true;
+ m_DepthMask = mask;
+}
+
+
+CShaderTechnique::CShaderTechnique(const CShaderPass& pass)
+{
+ m_Passes.push_back(pass);
+}
+
+void CShaderTechnique::AddPass(const CShaderPass& pass)
+{
+ m_Passes.push_back(pass);
+}
+
+int CShaderTechnique::GetNumPasses()
+{
+ return m_Passes.size();
+}
+
+void CShaderTechnique::BeginPass(int pass)
+{
+ debug_assert(0 <= pass && pass < (int)m_Passes.size());
+ m_Passes[pass].Bind();
+}
+
+void CShaderTechnique::EndPass(int pass)
+{
+ debug_assert(0 <= pass && pass < (int)m_Passes.size());
+ m_Passes[pass].Unbind();
+}
+
+CShaderProgramPtr CShaderTechnique::GetShader(int pass)
+{
+ debug_assert(0 <= pass && pass < (int)m_Passes.size());
+ return m_Passes[pass].GetShader();
+
+}
Property changes on: ps/trunk/source/graphics/ShaderTechnique.cpp
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: ps/trunk/source/graphics/LOSTexture.cpp
===================================================================
--- ps/trunk/source/graphics/LOSTexture.cpp (revision 9122)
+++ ps/trunk/source/graphics/LOSTexture.cpp (revision 9123)
@@ -1,236 +1,247 @@
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#include "precompiled.h"
#include "LOSTexture.h"
#include "graphics/Terrain.h"
#include "lib/bits.h"
#include "ps/Game.h"
#include "ps/Profile.h"
#include "ps/World.h"
#include "renderer/Renderer.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpRangeManager.h"
/*
The LOS bitmap is computed with one value per map vertex, based on
CCmpRangeManager's visibility information.
The bitmap is then blurred using an NxN filter (in particular a
7-tap Binomial filter as an efficient integral approximation of a Gaussian).
To implement the blur efficiently without using extra memory for a second copy
of the bitmap, we generate the bitmap with (N-1)/2 pixels of padding on each side,
then the blur shifts the image back into the corner.
The blurred bitmap is then uploaded into a GL texture for use by the renderer.
*/
// Blur with a NxN filter, where N = g_BlurSize must be an odd number.
static const size_t g_BlurSize = 7;
CLOSTexture::CLOSTexture() :
m_Dirty(true), m_Texture(0), m_MapSize(0), m_TextureSize(0)
{
}
CLOSTexture::~CLOSTexture()
{
if (m_Texture)
{
glDeleteTextures(1, &m_Texture);
m_Texture = 0;
}
}
void CLOSTexture::MakeDirty()
{
m_Dirty = true;
}
void CLOSTexture::BindTexture(int unit)
{
if (m_Dirty)
{
RecomputeTexture(unit);
m_Dirty = false;
}
g_Renderer.BindTexture(unit, m_Texture);
}
+GLuint CLOSTexture::GetTexture()
+{
+ if (m_Dirty)
+ {
+ RecomputeTexture(0);
+ m_Dirty = false;
+ }
+
+ return m_Texture;
+}
+
const float* CLOSTexture::GetTextureMatrix()
{
debug_assert(!m_Dirty);
return &m_TextureMatrix._11;
}
const float* CLOSTexture::GetMinimapTextureMatrix()
{
debug_assert(!m_Dirty);
return &m_MinimapTextureMatrix._11;
}
void CLOSTexture::ConstructTexture(int unit)
{
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
m_MapSize = terrain->GetVerticesPerSide();
m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize + g_BlurSize - 1);
glGenTextures(1, &m_Texture);
g_Renderer.BindTexture(unit, m_Texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, m_TextureSize, m_TextureSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
{
// Texture matrix: We want to map
// world pos (0, y, 0) (i.e. first vertex)
// onto texcoord (0.5/texsize, 0.5/texsize) (i.e. middle of first texel);
// world pos ((mapsize-1)*cellsize, y, (mapsize-1)*cellsize) (i.e. last vertex)
// onto texcoord ((mapsize-0.5) / texsize, (mapsize-0.5) / texsize) (i.e. middle of last texel)
float s = (m_MapSize-1) / (float)(m_TextureSize * (m_MapSize-1) * CELL_SIZE);
float t = 0.5f / m_TextureSize;
m_TextureMatrix.SetZero();
m_TextureMatrix._11 = s;
m_TextureMatrix._23 = s;
m_TextureMatrix._14 = t;
m_TextureMatrix._24 = t;
m_TextureMatrix._44 = 1;
}
{
// Minimap matrix: We want to map UV (0,0)-(1,1) onto (0,0)-(mapsize/texsize, mapsize/texsize)
float s = m_MapSize / (float)m_TextureSize;
m_MinimapTextureMatrix.SetZero();
m_MinimapTextureMatrix._11 = s;
m_MinimapTextureMatrix._22 = s;
m_MinimapTextureMatrix._44 = 1;
}
}
void CLOSTexture::RecomputeTexture(int unit)
{
if (!m_Texture)
ConstructTexture(unit);
PROFILE("recompute LOS texture");
std::vector losData;
losData.resize(GetBitmapSize(m_MapSize, m_MapSize));
CmpPtr cmpRangeManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
if (cmpRangeManager.null())
return;
ICmpRangeManager::CLosQuerier los (cmpRangeManager->GetLosQuerier(g_Game->GetPlayerID()));
GenerateBitmap(los, &losData[0], m_MapSize, m_MapSize);
g_Renderer.BindTexture(unit, m_Texture);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_MapSize + g_BlurSize - 1, m_MapSize + g_BlurSize - 1, GL_ALPHA, GL_UNSIGNED_BYTE, &losData[0]);
}
size_t CLOSTexture::GetBitmapSize(size_t w, size_t h)
{
return (w + g_BlurSize - 1) * (h + g_BlurSize - 1);
}
void CLOSTexture::GenerateBitmap(ICmpRangeManager::CLosQuerier los, u8* losData, size_t w, size_t h)
{
const size_t rowSize = w + g_BlurSize-1; // size of losData rows
u8 *dataPtr = losData;
// Initialise the top padding
for (size_t j = 0; j < g_BlurSize/2; ++j)
for (size_t i = 0; i < rowSize; ++i)
*dataPtr++ = 0;
for (size_t j = 0; j < h; ++j)
{
// Initialise the left padding
for (size_t i = 0; i < g_BlurSize/2; ++i)
*dataPtr++ = 0;
// Fill in the visibility data
for (size_t i = 0; i < w; ++i)
{
if (los.IsVisible(i, j))
*dataPtr++ = 255;
else if (los.IsExplored(i, j))
*dataPtr++ = 127;
else
*dataPtr++ = 0;
}
// Initialise the right padding
for (size_t i = 0; i < g_BlurSize/2; ++i)
*dataPtr++ = 0;
}
// Initialise the bottom padding
for (size_t j = 0; j < g_BlurSize/2; ++j)
for (size_t i = 0; i < rowSize; ++i)
*dataPtr++ = 0;
// Horizontal blur:
for (size_t j = g_BlurSize/2; j < h + g_BlurSize/2; ++j)
{
for (size_t i = 0; i < w; ++i)
{
u8* d = &losData[i+j*rowSize];
*d = (
1*d[0] +
6*d[1] +
15*d[2] +
20*d[3] +
15*d[4] +
6*d[5] +
1*d[6]
) / 64;
}
}
// Vertical blur:
for (size_t j = 0; j < h; ++j)
{
for (size_t i = 0; i < w; ++i)
{
u8* d = &losData[i+j*rowSize];
*d = (
1*d[0*rowSize] +
6*d[1*rowSize] +
15*d[2*rowSize] +
20*d[3*rowSize] +
15*d[4*rowSize] +
6*d[5*rowSize] +
1*d[6*rowSize]
) / 64;
}
}
}
Index: ps/trunk/source/graphics/ShaderProgram.cpp
===================================================================
--- ps/trunk/source/graphics/ShaderProgram.cpp (nonexistent)
+++ ps/trunk/source/graphics/ShaderProgram.cpp (revision 9123)
@@ -0,0 +1,313 @@
+/* Copyright (C) 2011 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0 A.D. If not, see .
+ */
+
+#include "precompiled.h"
+
+#include "ShaderProgram.h"
+
+#include "lib/res/graphics/ogl_tex.h"
+#include "maths/Matrix3D.h"
+#include "maths/Vector3D.h"
+#include "ps/CLogger.h"
+#include "ps/Filesystem.h"
+#include "ps/Overlay.h"
+#include "ps/Preprocessor.h"
+
+class CShaderProgramARB : public CShaderProgram
+{
+public:
+ CShaderProgramARB(const VfsPath& vertexFile, const VfsPath& fragmentFile,
+ const std::map& defines,
+ const std::map& vertexIndexes, const std::map& fragmentIndexes,
+ int streamflags) :
+ CShaderProgram(streamflags),
+ m_VertexFile(vertexFile), m_FragmentFile(fragmentFile),
+ m_Defines(defines),
+ m_VertexIndexes(vertexIndexes), m_FragmentIndexes(fragmentIndexes)
+ {
+ pglGenProgramsARB(1, &m_VertexProgram);
+ pglGenProgramsARB(1, &m_FragmentProgram);
+ }
+
+ ~CShaderProgramARB()
+ {
+ Unload();
+
+ pglDeleteProgramsARB(1, &m_VertexProgram);
+ pglDeleteProgramsARB(1, &m_FragmentProgram);
+ }
+
+ CStr Preprocess(CPreprocessor& preprocessor, const CStr& input)
+ {
+ size_t len = 0;
+ char* output = preprocessor.Parse(input.c_str(), input.size(), len);
+
+ if (!output)
+ {
+ LOGERROR(L"Shader preprocessing failed");
+ return "";
+ }
+
+ CStr ret(output, len);
+
+ // Free output if it's not inside the source string
+ if (!(output >= input.c_str() && output < input.c_str() + input.size()))
+ free(output);
+
+ return ret;
+ }
+
+ bool Compile(GLuint target, const char* targetName, GLuint program, const VfsPath& file, const CStr& code)
+ {
+ ogl_WarnIfError();
+
+ pglBindProgramARB(target, program);
+
+ ogl_WarnIfError();
+
+ pglProgramStringARB(target, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)code.length(), code.c_str());
+
+ if (ogl_SquelchError(GL_INVALID_OPERATION))
+ {
+ GLint errPos = 0;
+ glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos);
+ int errLine = std::count(code.begin(), code.begin() + errPos + 1, '\n') + 1;
+ char* errStr = (char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
+ LOGERROR(L"Failed to compile %hs program '%ls' (line %d):\n%hs", targetName, file.string().c_str(), errLine, errStr);
+ return false;
+ }
+
+ pglBindProgramARB(target, 0);
+
+ ogl_WarnIfError();
+
+ return true;
+ }
+
+ virtual void Reload()
+ {
+ Unload();
+
+ CVFSFile vertexFile;
+ if (vertexFile.Load(g_VFS, m_VertexFile) != PSRETURN_OK)
+ return;
+
+ CVFSFile fragmentFile;
+ if (fragmentFile.Load(g_VFS, m_FragmentFile) != PSRETURN_OK)
+ return;
+
+ CPreprocessor preprocessor;
+ for (std::map::iterator it = m_Defines.begin(); it != m_Defines.end(); ++it)
+ preprocessor.Define(it->first.c_str(), it->second.c_str());
+
+ CStr vertexCode = Preprocess(preprocessor, vertexFile.GetAsString());
+ CStr fragmentCode = Preprocess(preprocessor, fragmentFile.GetAsString());
+
+// printf(">>>\n%s<<<\n", vertexCode.c_str());
+// printf(">>>\n%s<<<\n", fragmentCode.c_str());
+
+ if (!Compile(GL_VERTEX_PROGRAM_ARB, "vertex", m_VertexProgram, m_VertexFile, vertexCode))
+ return;
+
+ if (!Compile(GL_FRAGMENT_PROGRAM_ARB, "fragment", m_FragmentProgram, m_FragmentFile, fragmentCode))
+ return;
+
+ m_IsValid = true;
+ }
+
+ void Unload()
+ {
+ m_IsValid = false;
+ }
+
+ virtual void Bind()
+ {
+ glEnable(GL_VERTEX_PROGRAM_ARB);
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+ pglBindProgramARB(GL_VERTEX_PROGRAM_ARB, m_VertexProgram);
+ pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_FragmentProgram);
+ }
+
+ virtual void Unbind()
+ {
+ glDisable(GL_VERTEX_PROGRAM_ARB);
+ glDisable(GL_FRAGMENT_PROGRAM_ARB);
+ pglBindProgramARB(GL_VERTEX_PROGRAM_ARB, 0);
+ pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);
+
+ // TODO: should unbind textures, probably
+ }
+
+ int GetUniformVertexIndex(uniform_id_t id)
+ {
+ std::map::iterator it = m_VertexIndexes.find(id);
+ if (it == m_VertexIndexes.end())
+ return -1;
+ return it->second;
+ }
+
+ int GetUniformFragmentIndex(uniform_id_t id)
+ {
+ std::map::iterator it = m_FragmentIndexes.find(id);
+ if (it == m_FragmentIndexes.end())
+ return -1;
+ return it->second;
+ }
+
+ virtual bool HasTexture(texture_id_t id)
+ {
+ if (GetUniformFragmentIndex(id) != -1)
+ return true;
+ return false;
+ }
+
+ virtual void BindTexture(texture_id_t id, Handle tex)
+ {
+ int index = GetUniformFragmentIndex(id);
+ if (index != -1)
+ ogl_tex_bind(tex, index);
+ }
+
+ virtual void BindTexture(texture_id_t id, GLuint tex)
+ {
+ int index = GetUniformFragmentIndex(id);
+ if (index != -1)
+ {
+ pglActiveTextureARB((int)(GL_TEXTURE0+index));
+ glBindTexture(GL_TEXTURE_2D, tex);
+ }
+ }
+
+ virtual Binding GetUniformBinding(uniform_id_t id)
+ {
+ return Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id));
+ }
+
+ virtual void Uniform(uniform_id_t id, int v)
+ {
+ Uniform(Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id)), (float)v, (float)v, (float)v, (float)v);
+ }
+
+ virtual void Uniform(Binding id, int v)
+ {
+ Uniform(id, (float)v, (float)v, (float)v, (float)v);
+ }
+
+ virtual void Uniform(uniform_id_t id, float v)
+ {
+ Uniform(Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id)), v, v, v, v);
+ }
+
+ virtual void Uniform(Binding id, float v)
+ {
+ Uniform(id, v, v, v, v);
+ }
+
+ virtual void Uniform(uniform_id_t id, float v0, float v1, float v2, float v3)
+ {
+ Uniform(Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id)), v0, v1, v2, v3);
+ }
+
+ virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
+ {
+ if (id.vertex != -1)
+ pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.vertex, v0, v1, v2, v3);
+
+ if (id.fragment != -1)
+ pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.fragment, v0, v1, v2, v3);
+ }
+
+ virtual void Uniform(uniform_id_t id, const CVector3D& v)
+ {
+ Uniform(Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id)), v.X, v.Y, v.Z, 0.0f);
+ }
+
+ virtual void Uniform(Binding id, const CVector3D& v)
+ {
+ Uniform(id, v.X, v.Y, v.Z, 0.0f);
+ }
+
+ virtual void Uniform(uniform_id_t id, const CColor& v)
+ {
+ Uniform(Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id)), v.r, v.g, v.b, v.a);
+ }
+
+ virtual void Uniform(Binding id, const CColor& v)
+ {
+ Uniform(id, v.r, v.g, v.b, v.a);
+ }
+
+ virtual void Uniform(uniform_id_t id, const CMatrix3D& v)
+ {
+ Uniform(Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id)), v);
+ }
+
+ virtual void Uniform(Binding id, const CMatrix3D& v)
+ {
+ if (id.vertex != -1)
+ {
+ pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.vertex+0, v._11, v._12, v._13, v._14);
+ pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.vertex+1, v._21, v._22, v._23, v._24);
+ pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.vertex+2, v._31, v._32, v._33, v._34);
+ pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.vertex+3, v._41, v._42, v._43, v._44);
+ }
+
+ if (id.fragment != -1)
+ {
+ pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.fragment+0, v._11, v._12, v._13, v._14);
+ pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.fragment+1, v._21, v._22, v._23, v._24);
+ pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.fragment+2, v._31, v._32, v._33, v._34);
+ pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.fragment+3, v._41, v._42, v._43, v._44);
+ }
+ }
+
+private:
+ VfsPath m_VertexFile;
+ VfsPath m_FragmentFile;
+ std::map m_Defines;
+
+ GLuint m_VertexProgram;
+ GLuint m_FragmentProgram;
+
+ std::map m_VertexIndexes;
+ std::map m_FragmentIndexes;
+};
+
+
+
+CShaderProgram::CShaderProgram(int streamflags)
+ : m_IsValid(false), m_StreamFlags(streamflags)
+{
+}
+
+/*static*/ CShaderProgram* CShaderProgram::ConstructARB(const VfsPath& vertexFile, const VfsPath& fragmentFile,
+ const std::map& defines,
+ const std::map& vertexIndexes, const std::map& fragmentIndexes,
+ int streamflags)
+{
+ return new CShaderProgramARB(vertexFile, fragmentFile, defines, vertexIndexes, fragmentIndexes, streamflags);
+}
+
+bool CShaderProgram::IsValid() const
+{
+ return m_IsValid;
+}
+
+int CShaderProgram::GetStreamFlags() const
+{
+ return m_StreamFlags;
+}
Property changes on: ps/trunk/source/graphics/ShaderProgram.cpp
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: ps/trunk/source/graphics/TextureManager.h
===================================================================
--- ps/trunk/source/graphics/TextureManager.h (revision 9122)
+++ ps/trunk/source/graphics/TextureManager.h (revision 9123)
@@ -1,276 +1,281 @@
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#ifndef INCLUDED_TEXTUREMANAGER
#define INCLUDED_TEXTUREMANAGER
#include "Texture.h"
#include "lib/ogl.h"
#include "lib/file/vfs/vfs.h"
#include "lib/res/handle.h"
#include
class CTextureProperties;
class CTextureManagerImpl;
/**
* Texture manager with asynchronous loading and automatic DDS conversion/compression.
*
* Input textures can be any format. They will be converted to DDS using settings defined
* in files named "texture.xml", in the same directory as the texture and in its parent
* directories. See CTextureConverter for the XML syntax. The DDS file will be cached
* for faster loading in the future.
*
* Typically the graphics code will initialise many textures at the start of the game,
* mostly for off-screen objects, by calling CreateTexture().
* Loading texture data may be very slow (especially if it needs to be converted
* to DDS), and we don't want the game to become unresponsive.
* CreateTexture therefore returns an object immediately, without loading the
* texture. If the object is never used then the data will never be loaded.
*
* Typically, the renderer will call CTexture::Bind() when it wants to use the
* texture. This will trigger the loading of the texture data. If it can be loaded
* quickly (i.e. there is already a cached DDS version), then it will be loaded before
* the function returns, and the texture can be rendered as normal.
*
* If loading will take a long time, then Bind() binds a default placeholder texture
* and starts loading the texture in the background. It will use the correct texture
* when the renderer next calls Bind() after the load has finished.
*
* It is also possible to prefetch textures which are not being rendered yet, but
* are expected to be rendered soon (e.g. for off-screen terrain tiles).
* These will be loaded in the background, when there are no higher-priority textures
* to load.
*
* The same texture file can be safely loaded multiple times with different GL parameters
* (but this should be avoided whenever possible, as it wastes VRAM).
*
* For release packages, DDS files can be precached by appending ".dds" to their name,
* which will be used instead of doing runtime conversion. This means most players should
* never experience the slow asynchronous conversion behaviour.
* These cache files will typically be packed into an archive for faster loading;
* if no archive cache is available then the source file will be converted and stored
* as a loose cache file on the user's disk.
*/
class CTextureManager
{
public:
/**
* Construct texture manager. vfs must be the VFS instance used for all textures
* loaded from this object.
* highQuality is slower and intended for batch-conversion modes.
* disableGL is intended for tests, and will disable all GL uploads.
*/
CTextureManager(PIVFS vfs, bool highQuality, bool disableGL);
~CTextureManager();
/**
* Create a texture with the given GL properties.
* The texture data will not be loaded immediately.
*/
CTexturePtr CreateTexture(const CTextureProperties& props);
/**
* Returns a magenta texture. Use this for highlighting errors
* (e.g. missing terrain textures).
*/
CTexturePtr GetErrorTexture();
/**
* Work on asynchronous texture loading operations, if any.
* Returns true if it did any work.
* The caller should typically loop this per frame until it returns
* false or exceeds the allocated time for this frame.
*/
bool MakeProgress();
/**
* Synchronously converts and compresses and saves the texture,
* and returns the output path (minus a "cache/" prefix). This
* is intended for pre-caching textures in release archives.
* @return true on success
*/
bool GenerateCachedTexture(const VfsPath& path, VfsPath& outputPath);
private:
CTextureManagerImpl* m;
};
/**
* Represents the filename and GL parameters of a texture,
* for passing to CTextureManager::CreateTexture.
*/
class CTextureProperties
{
friend class CTextureManagerImpl;
friend struct TextureCacheCmp;
friend struct TPequal_to;
friend struct TPhash;
public:
/**
* Use the given texture name, and default GL parameters.
*/
explicit CTextureProperties(const VfsPath& path) :
m_Path(path), m_Filter(GL_LINEAR_MIPMAP_LINEAR), m_Wrap(GL_REPEAT), m_Aniso(1.0f)
{
}
/**
* Set min/mag filter mode (typically GL_LINEAR_MIPMAP_LINEAR, GL_NEAREST, etc).
*/
void SetFilter(GLint filter) { m_Filter = filter; }
/**
* Set wrapping mode (typically GL_REPEAT, GL_CLAMP_TO_EDGE, etc).
*/
void SetWrap(GLint wrap) { m_Wrap = wrap; }
/**
* Set maximum anisotropy value. Must be >= 1.0. Should be a power of 2.
*/
void SetMaxAnisotropy(float aniso) { m_Aniso = aniso; }
// TODO: rather than this static definition of texture properties
// (especially anisotropy), maybe we want something that can be more
// easily tweaked in an Options menu? e.g. the caller just specifies
// "terrain texture mode" and we combine it with the user's options.
// That'd let us dynamically change texture properties easily.
//
// enum EQualityMode
// {
// NONE,
// TERRAIN,
// MODEL,
// GUI
// }
// void SetQuality(EQualityMode mode, float anisotropy, float lodbias, int reducemipmaps, ...);
//
// or something a bit like that.
private:
VfsPath m_Path;
GLint m_Filter;
GLint m_Wrap;
float m_Aniso;
};
/**
* Represents a texture object.
* The texture data may or may not have been loaded yet.
* Before it has been loaded, all operations will act on a default
* 1x1-pixel grey texture instead.
*/
class CTexture
{
friend class CTextureManagerImpl;
friend struct TextureCacheCmp;
friend struct TPequal_to;
friend struct TPhash;
// Only the texture manager can create these
explicit CTexture(Handle handle, const CTextureProperties& props, CTextureManagerImpl* textureManager);
NONCOPYABLE(CTexture);
public:
~CTexture();
/**
* Returns the width (in pixels) of the current texture.
*/
size_t GetWidth() const;
/**
* Returns the height (in pixels) of the current texture.
*/
size_t GetHeight() const;
/**
* Returns whether the current texture has an alpha channel.
*/
bool HasAlpha() const;
/**
* Returns the ARGB value of the lowest mipmap level (i.e. the
* average of the whole texture).
* Returns 0 if the texture has no mipmaps.
*/
u32 GetBaseColour() const;
/**
* Bind the texture to the given GL texture unit.
* If the texture data hasn't been loaded yet, this may wait a short while to
* load it. If loading takes too long then it will return sooner and the data will
* be loaded in a background thread, so this does not guarantee the texture really
* will be loaded.
*/
void Bind(size_t unit = 0);
/**
+ * Returns a ogl_tex handle, for later binding. See comments from Bind().
+ */
+ Handle GetHandle();
+
+ /**
* Attempt to load the texture data quickly, as with Bind().
* Returns whether the texture data is currently loaded.
*/
bool TryLoad();
/**
* Returns whether the texture data is currently loaded.
*/
bool IsLoaded();
/**
* Activate the prefetching optimisation for this texture.
* Use this if it is likely the texture will be needed in the near future.
* It will be loaded in the background so that it is likely to be ready when
* it is used by Bind().
*/
void Prefetch();
private:
/**
* Replace the Handle stored by this object.
* If takeOwnership is true, it will not increment the Handle's reference count.
*/
void SetHandle(Handle handle, bool takeOwnership = false);
const CTextureProperties m_Properties;
Handle m_Handle;
u32 m_BaseColour;
enum {
UNLOADED, // loading has not started
PREFETCH_NEEDS_LOADING, // was prefetched; currently waiting to try loading from cache
PREFETCH_NEEDS_CONVERTING, // was prefetched; currently waiting to be sent to the texture converter
PREFETCH_IS_CONVERTING, // was prefetched; currently being processed by the texture converter
HIGH_NEEDS_CONVERTING, // high-priority; currently waiting to be sent to the texture converter
HIGH_IS_CONVERTING, // high-priority; currently being processed by the texture converter
LOADED // loading has completed (successfully or not)
} m_State;
CTextureManagerImpl* m_TextureManager;
// Self-reference to let us recover the CTexturePtr for this object.
// (weak pointer to avoid cycles)
boost::weak_ptr m_Self;
};
#endif // INCLUDED_TEXTUREMANAGER
Index: ps/trunk/source/graphics/ShaderManager.cpp
===================================================================
--- ps/trunk/source/graphics/ShaderManager.cpp (nonexistent)
+++ ps/trunk/source/graphics/ShaderManager.cpp (revision 9123)
@@ -0,0 +1,210 @@
+/* Copyright (C) 2011 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0 A.D. If not, see .
+ */
+
+#include "precompiled.h"
+
+#include "ShaderManager.h"
+
+#include "lib/timer.h"
+#include "lib/utf8.h"
+#include "ps/CLogger.h"
+#include "ps/Filesystem.h"
+#include "ps/XML/Xeromyces.h"
+#include "ps/XML/XMLWriter.h"
+#include "renderer/Renderer.h"
+
+TIMER_ADD_CLIENT(tc_ShaderValidation);
+
+CShaderManager::CShaderManager()
+{
+#if USE_SHADER_XML_VALIDATION
+ {
+ TIMER_ACCRUE(tc_ShaderValidation);
+ CVFSFile grammar;
+ if (grammar.Load(g_VFS, L"shaders/program.rng") != PSRETURN_OK)
+ LOGERROR(L"Failed to read grammar shaders/program.rng");
+ else
+ {
+ if (!m_Validator.LoadGrammar(grammar.GetAsString()))
+ LOGERROR(L"Failed to load grammar shaders/program.rng");
+ }
+ }
+#endif
+
+ // Allow hotloading of textures
+ RegisterFileReloadFunc(ReloadChangedFileCB, this);
+}
+
+CShaderManager::~CShaderManager()
+{
+ UnregisterFileReloadFunc(ReloadChangedFileCB, this);
+}
+
+CShaderProgramPtr CShaderManager::LoadProgram(const char* name, const std::map& defines)
+{
+ CacheKey key = { name, defines };
+ std::map::iterator it = m_Cache.find(key);
+ if (it != m_Cache.end())
+ return it->second;
+
+ CShaderProgramPtr program;
+ if (NewProgram(name, defines, program) != PSRETURN_OK)
+ {
+ LOGERROR(L"Failed to load shader '%hs'", name);
+ program = CShaderProgramPtr();
+ }
+
+ m_Cache[key] = program;
+ return program;
+}
+
+bool CShaderManager::NewProgram(const char* name, const std::map& baseDefines, CShaderProgramPtr& program)
+{
+ VfsPath xmlFilename = L"shaders/" + wstring_from_utf8(name) + L".xml";
+
+ CXeromyces XeroFile;
+ PSRETURN ret = XeroFile.Load(g_VFS, xmlFilename);
+ if (ret != PSRETURN_OK)
+ return false;
+
+#if USE_SHADER_XML_VALIDATION
+ {
+ TIMER_ACCRUE(tc_ShaderValidation);
+
+ // Serialize the XMB data and pass it to the validator
+ XML_Start();
+ XML_SetPrettyPrint(false);
+ XML_WriteXMB(XeroFile);
+ bool ok = m_Validator.ValidateEncoded(wstring_from_utf8(name), XML_GetOutput());
+ if (!ok)
+ return false;
+ }
+#endif
+
+ // Define all the elements and attributes used in the XML file
+#define EL(x) int el_##x = XeroFile.GetElementID(#x)
+#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
+ EL(vertex);
+ EL(fragment);
+ EL(define);
+ EL(uniform);
+ EL(attrib);
+ EL(stream);
+ AT(type);
+ AT(file);
+ AT(name);
+ AT(value);
+ AT(loc);
+#undef AT
+#undef EL
+
+ XMBElement Root = XeroFile.GetRoot();
+
+ bool isGLSL = (Root.GetAttributes().GetNamedItem(at_type) == "glsl");
+ VfsPath vertexFile;
+ VfsPath fragmentFile;
+ std::map defines = baseDefines;
+ std::map vertexUniforms;
+ std::map fragmentUniforms;
+ int streamFlags = 0;
+
+ XERO_ITER_EL(Root, Child)
+ {
+ if (Child.GetNodeName() == el_define)
+ {
+ defines[Child.GetAttributes().GetNamedItem(at_name)] = Child.GetAttributes().GetNamedItem(at_value);
+ }
+ else if (Child.GetNodeName() == el_vertex)
+ {
+ vertexFile = L"shaders/" + Child.GetAttributes().GetNamedItem(at_file).FromUTF8();
+
+ XERO_ITER_EL(Child, Param)
+ {
+ if (Param.GetNodeName() == el_uniform)
+ {
+ vertexUniforms[Param.GetAttributes().GetNamedItem(at_name)] = Param.GetAttributes().GetNamedItem(at_loc).ToInt();
+ }
+ else if (Param.GetNodeName() == el_stream)
+ {
+ CStr StreamName = Param.GetAttributes().GetNamedItem(at_name);
+ if (StreamName == "pos")
+ streamFlags |= STREAM_POS;
+ else if (StreamName == "normal")
+ streamFlags |= STREAM_NORMAL;
+ else if (StreamName == "color")
+ streamFlags |= STREAM_COLOR;
+ else if (StreamName == "uv0")
+ streamFlags |= STREAM_UV0;
+ else if (StreamName == "uv1")
+ streamFlags |= STREAM_UV1;
+ else if (StreamName == "uv2")
+ streamFlags |= STREAM_UV2;
+ else if (StreamName == "uv3")
+ streamFlags |= STREAM_UV3;
+ }
+ else if (Param.GetNodeName() == el_attrib)
+ {
+ // TODO: add support for vertex attributes
+ }
+ }
+ }
+ else if (Child.GetNodeName() == el_fragment)
+ {
+ fragmentFile = L"shaders/" + Child.GetAttributes().GetNamedItem(at_file).FromUTF8();
+
+ XERO_ITER_EL(Child, Param)
+ {
+ if (Param.GetNodeName() == el_uniform)
+ fragmentUniforms[Param.GetAttributes().GetNamedItem(at_name)] = Param.GetAttributes().GetNamedItem(at_loc).ToInt();
+ }
+ }
+ }
+
+ // TODO: add GLSL support
+ debug_assert(!isGLSL);
+
+ program = CShaderProgramPtr(CShaderProgram::ConstructARB(vertexFile, fragmentFile, defines, vertexUniforms, fragmentUniforms, streamFlags));
+ program->Reload();
+
+// m_HotloadFiles[xmlFilename].insert(program); // TODO: should reload somehow when the XML changes
+ m_HotloadFiles[vertexFile].insert(program);
+ m_HotloadFiles[fragmentFile].insert(program);
+
+ return PSRETURN_OK;
+}
+
+/*static*/ LibError CShaderManager::ReloadChangedFileCB(void* param, const VfsPath& path)
+{
+ return static_cast(param)->ReloadChangedFile(path);
+}
+
+LibError CShaderManager::ReloadChangedFile(const VfsPath& path)
+{
+ // Find all shaders using this file
+ HotloadFilesMap::iterator files = m_HotloadFiles.find(path);
+ if (files != m_HotloadFiles.end())
+ {
+ // Reload all shaders using this file
+ for (std::set >::iterator it = files->second.begin(); it != files->second.end(); ++it)
+ {
+ if (shared_ptr program = it->lock())
+ program->Reload();
+ }
+ }
+
+ return INFO::OK;
+}
Property changes on: ps/trunk/source/graphics/ShaderManager.cpp
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: ps/trunk/source/graphics/GameView.cpp
===================================================================
--- ps/trunk/source/graphics/GameView.cpp (revision 9122)
+++ ps/trunk/source/graphics/GameView.cpp (revision 9123)
@@ -1,1021 +1,1029 @@
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#include "precompiled.h"
#include "GameView.h"
#include "graphics/Camera.h"
#include "graphics/CinemaTrack.h"
#include "graphics/ColladaManager.h"
#include "graphics/HFTracer.h"
#include "graphics/LightEnv.h"
#include "graphics/LOSTexture.h"
#include "graphics/Model.h"
#include "graphics/ObjectManager.h"
#include "graphics/Patch.h"
#include "graphics/SkeletonAnimManager.h"
#include "graphics/Terrain.h"
#include "graphics/TerrainTextureManager.h"
#include "graphics/Unit.h"
#include "graphics/UnitManager.h"
#include "lib/input.h"
#include "lib/timer.h"
#include "maths/Bound.h"
#include "maths/MathUtil.h"
#include "maths/Matrix3D.h"
#include "maths/Quaternion.h"
#include "ps/ConfigDB.h"
#include "ps/Game.h"
#include "ps/Globals.h"
#include "ps/Hotkey.h"
#include "ps/Joystick.h"
#include "ps/Loader.h"
#include "ps/LoaderThunks.h"
#include "ps/Profile.h"
#include "ps/Pyrogenesis.h"
#include "ps/World.h"
#include "renderer/Renderer.h"
#include "renderer/WaterManager.h"
#include "scripting/ScriptableObject.h"
#include "simulation/LOSManager.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpPosition.h"
#include "simulation2/components/ICmpRangeManager.h"
extern int g_xres, g_yres;
const float CGameView::defaultFOV = DEGTORAD(20.f);
const float CGameView::defaultNear = 16.f;
const float CGameView::defaultFar = 4096.f;
const float CGameView::defaultCullFOV = CGameView::defaultFOV + DEGTORAD(6.0f); //add 6 degrees to the default FOV for use with the culling frustum
// Maximum distance outside the edge of the map that the camera's
// focus point can be moved
static const float CAMERA_EDGE_MARGIN = 2.0f*CELL_SIZE;
/**
* A value with exponential decay towards the target value.
*/
class CSmoothedValue
{
public:
CSmoothedValue(float value, float smoothness, float minDelta)
: m_Target(value), m_Current(value), m_Smoothness(smoothness), m_MinDelta(minDelta)
{
}
float GetSmoothedValue()
{
return m_Current;
}
void SetValueSmoothly(float value)
{
m_Target = value;
}
void AddSmoothly(float value)
{
m_Target += value;
}
void Add(float value)
{
m_Target += value;
m_Current += value;
}
float GetValue()
{
return m_Target;
}
void SetValue(float value)
{
m_Target = value;
m_Current = value;
}
float Update(float time)
{
if (fabs(m_Target - m_Current) < m_MinDelta)
return 0.0f;
double p = pow((double)m_Smoothness, 10.0 * (double)time);
// (add the factor of 10 so that smoothnesses don't have to be tiny numbers)
double delta = (m_Target - m_Current) * (1.0 - p);
m_Current += delta;
return (float)delta;
}
void ClampSmoothly(float min, float max)
{
m_Target = Clamp(m_Target, (double)min, (double)max);
}
// Wrap so 'target' is in the range [min, max]
void Wrap(float min, float max)
{
double t = fmod(m_Target - min, (double)(max - min));
if (t < 0)
t += max - min;
t += min;
m_Current += t - m_Target;
m_Target = t;
}
private:
double m_Target; // the value which m_Current is tending towards
double m_Current;
// (We use double because the extra precision is worthwhile here)
float m_MinDelta; // cutoff where we stop moving (to avoid ugly shimmering effects)
public:
float m_Smoothness;
};
class CGameViewImpl : public CJSObject
{
NONCOPYABLE(CGameViewImpl);
public:
CGameViewImpl(CGame* game)
: Game(game),
ColladaManager(), MeshManager(ColladaManager), SkeletonAnimManager(ColladaManager),
ObjectManager(MeshManager, SkeletonAnimManager, *game->GetSimulation2()),
ViewCamera(),
CullCamera(),
LockCullCamera(false),
ConstrainCamera(true),
Culling(true),
FollowEntity(INVALID_ENTITY),
FollowFirstPerson(false),
// Dummy values (these will be filled in by the config file)
ViewScrollSpeed(0),
ViewRotateXSpeed(0),
ViewRotateXMin(0),
ViewRotateXMax(0),
ViewRotateXDefault(0),
ViewRotateYSpeed(0),
ViewRotateYSpeedWheel(0),
ViewRotateYDefault(0),
ViewDragSpeed(0),
ViewZoomSpeed(0),
ViewZoomSpeedWheel(0),
ViewZoomMin(0),
ViewZoomMax(0),
ViewZoomDefault(0),
JoystickPanX(-1),
JoystickPanY(-1),
JoystickRotateX(-1),
JoystickRotateY(-1),
JoystickZoomIn(-1),
JoystickZoomOut(-1),
PosX(0, 0, 0.01f),
PosY(0, 0, 0.01f),
PosZ(0, 0, 0.01f),
Zoom(0, 0, 0.1f),
RotateX(0, 0, 0.001f),
RotateY(0, 0, 0.001f)
{
}
CGame* Game;
CColladaManager ColladaManager;
CMeshManager MeshManager;
CSkeletonAnimManager SkeletonAnimManager;
CObjectManager ObjectManager;
CLOSTexture LOSTexture;
/**
* this camera controls the eye position when rendering
*/
CCamera ViewCamera;
/**
* this camera controls the frustum that is used for culling
* and shadow calculations
*
* Note that all code that works with camera movements should only change
* m_ViewCamera. The render functions automatically sync the cull camera to
* the view camera depending on the value of m_LockCullCamera.
*/
CCamera CullCamera;
/**
* When @c true, the cull camera is locked in place.
* When @c false, the cull camera follows the view camera.
*
* Exposed to JS as gameView.lockCullCamera
*/
bool LockCullCamera;
/**
* When @c true, culling is enabled so that only models that have a chance of
* being visible are sent to the renderer.
* Otherwise, the entire world is sent to the renderer.
*
* Exposed to JS as gameView.culling
*/
bool Culling;
/**
* Whether the camera movement should be constrained by min/max limits
* and terrain avoidance.
*/
bool ConstrainCamera;
/**
* Cache global lighting environment. This is used to check whether the
* environment has changed during the last frame, so that vertex data can be updated etc.
*/
CLightEnv CachedLightEnv;
CCinemaManager TrackManager;
/**
* Entity for the camera to follow, or INVALID_ENTITY if none.
*/
entity_id_t FollowEntity;
/**
* Whether to follow FollowEntity in first-person mode.
*/
bool FollowFirstPerson;
////////////////////////////////////////
// Settings
float ViewScrollSpeed;
float ViewRotateXSpeed;
float ViewRotateXMin;
float ViewRotateXMax;
float ViewRotateXDefault;
float ViewRotateYSpeed;
float ViewRotateYSpeedWheel;
float ViewRotateYDefault;
float ViewDragSpeed;
float ViewZoomSpeed;
float ViewZoomSpeedWheel;
float ViewZoomMin;
float ViewZoomMax;
float ViewZoomDefault;
int JoystickPanX;
int JoystickPanY;
int JoystickRotateX;
int JoystickRotateY;
int JoystickZoomIn;
int JoystickZoomOut;
////////////////////////////////////////
// Camera Controls State
CSmoothedValue PosX;
CSmoothedValue PosY;
CSmoothedValue PosZ;
CSmoothedValue Zoom;
CSmoothedValue RotateX; // inclination around x axis (relative to camera)
CSmoothedValue RotateY; // rotation around y (vertical) axis
static void ScriptingInit();
};
static void SetupCameraMatrixSmooth(CGameViewImpl* m, CMatrix3D* orientation)
{
orientation->SetIdentity();
orientation->RotateX(m->RotateX.GetSmoothedValue());
orientation->RotateY(m->RotateY.GetSmoothedValue());
orientation->Translate(m->PosX.GetSmoothedValue(), m->PosY.GetSmoothedValue(), m->PosZ.GetSmoothedValue());
}
static void SetupCameraMatrixSmoothRot(CGameViewImpl* m, CMatrix3D* orientation)
{
orientation->SetIdentity();
orientation->RotateX(m->RotateX.GetSmoothedValue());
orientation->RotateY(m->RotateY.GetSmoothedValue());
orientation->Translate(m->PosX.GetValue(), m->PosY.GetValue(), m->PosZ.GetValue());
}
static void SetupCameraMatrixNonSmooth(CGameViewImpl* m, CMatrix3D* orientation)
{
orientation->SetIdentity();
orientation->RotateX(m->RotateX.GetValue());
orientation->RotateY(m->RotateY.GetValue());
orientation->Translate(m->PosX.GetValue(), m->PosY.GetValue(), m->PosZ.GetValue());
}
CGameView::CGameView(CGame *pGame):
m(new CGameViewImpl(pGame))
{
SViewPort vp;
vp.m_X=0;
vp.m_Y=0;
vp.m_Width=g_xres;
vp.m_Height=g_yres;
m->ViewCamera.SetViewPort(vp);
m->ViewCamera.SetProjection(defaultNear, defaultFar, defaultFOV);
SetupCameraMatrixSmooth(m, &m->ViewCamera.m_Orientation);
m->ViewCamera.UpdateFrustum();
m->CullCamera = m->ViewCamera;
g_Renderer.SetSceneCamera(m->ViewCamera, m->CullCamera);
}
CGameView::~CGameView()
{
UnloadResources();
delete m;
}
void CGameView::SetViewport(const SViewPort& vp)
{
m->ViewCamera.SetViewPort(vp);
m->ViewCamera.SetProjection(defaultNear, defaultFar, defaultFOV);
}
CObjectManager& CGameView::GetObjectManager() const
{
return m->ObjectManager;
}
JSObject* CGameView::GetScript()
{
return m->GetScript();
}
/*static*/ void CGameView::ScriptingInit()
{
return CGameViewImpl::ScriptingInit();
}
CCamera* CGameView::GetCamera()
{
return &m->ViewCamera;
}
CCinemaManager* CGameView::GetCinema()
{
return &m->TrackManager;
};
CLOSTexture& CGameView::GetLOSTexture()
{
return m->LOSTexture;
}
void CGameViewImpl::ScriptingInit()
{
AddProperty(L"culling", &CGameViewImpl::Culling);
AddProperty(L"lockCullCamera", &CGameViewImpl::LockCullCamera);
AddProperty(L"constrainCamera", &CGameViewImpl::ConstrainCamera);
CJSObject::ScriptingInit("GameView");
}
int CGameView::Initialize()
{
CFG_GET_SYS_VAL("view.scroll.speed", Float, m->ViewScrollSpeed);
CFG_GET_SYS_VAL("view.rotate.x.speed", Float, m->ViewRotateXSpeed);
CFG_GET_SYS_VAL("view.rotate.x.min", Float, m->ViewRotateXMin);
CFG_GET_SYS_VAL("view.rotate.x.max", Float, m->ViewRotateXMax);
CFG_GET_SYS_VAL("view.rotate.x.default", Float, m->ViewRotateXDefault);
CFG_GET_SYS_VAL("view.rotate.y.speed", Float, m->ViewRotateYSpeed);
CFG_GET_SYS_VAL("view.rotate.y.speed.wheel", Float, m->ViewRotateYSpeedWheel);
CFG_GET_SYS_VAL("view.rotate.y.default", Float, m->ViewRotateYDefault);
CFG_GET_SYS_VAL("view.drag.speed", Float, m->ViewDragSpeed);
CFG_GET_SYS_VAL("view.zoom.speed", Float, m->ViewZoomSpeed);
CFG_GET_SYS_VAL("view.zoom.speed.wheel", Float, m->ViewZoomSpeedWheel);
CFG_GET_SYS_VAL("view.zoom.min", Float, m->ViewZoomMin);
CFG_GET_SYS_VAL("view.zoom.max", Float, m->ViewZoomMax);
CFG_GET_SYS_VAL("view.zoom.default", Float, m->ViewZoomDefault);
CFG_GET_SYS_VAL("joystick.camera.pan.x", Int, m->JoystickPanX);
CFG_GET_SYS_VAL("joystick.camera.pan.y", Int, m->JoystickPanY);
CFG_GET_SYS_VAL("joystick.camera.rotate.x", Int, m->JoystickRotateX);
CFG_GET_SYS_VAL("joystick.camera.rotate.y", Int, m->JoystickRotateY);
CFG_GET_SYS_VAL("joystick.camera.zoom.in", Int, m->JoystickZoomIn);
CFG_GET_SYS_VAL("joystick.camera.zoom.out", Int, m->JoystickZoomOut);
CFG_GET_SYS_VAL("view.pos.smoothness", Float, m->PosX.m_Smoothness);
CFG_GET_SYS_VAL("view.pos.smoothness", Float, m->PosY.m_Smoothness);
CFG_GET_SYS_VAL("view.pos.smoothness", Float, m->PosZ.m_Smoothness);
CFG_GET_SYS_VAL("view.zoom.smoothness", Float, m->Zoom.m_Smoothness);
CFG_GET_SYS_VAL("view.rotate.x.smoothness", Float, m->RotateX.m_Smoothness);
CFG_GET_SYS_VAL("view.rotate.y.smoothness", Float, m->RotateY.m_Smoothness);
m->RotateX.SetValue(DEGTORAD(m->ViewRotateXDefault));
m->RotateY.SetValue(DEGTORAD(m->ViewRotateYDefault));
return 0;
}
void CGameView::RegisterInit()
{
// CGameView init
RegMemFun(this, &CGameView::Initialize, L"CGameView init", 1);
// previously done by CGameView::InitResources
RegMemFun(g_TexMan.GetSingletonPtr(), &CTerrainTextureManager::LoadTerrainTextures, L"LoadTerrainTextures", 60);
RegMemFun(g_Renderer.GetSingletonPtr(), &CRenderer::LoadAlphaMaps, L"LoadAlphaMaps", 5);
RegMemFun(g_Renderer.GetSingletonPtr()->GetWaterManager(), &WaterManager::LoadWaterTextures, L"LoadWaterTextures", 80);
}
-void CGameView::Render()
+void CGameView::BeginFrame()
{
if (m->LockCullCamera == false)
{
// Set up cull camera
m->CullCamera = m->ViewCamera;
// One way to fix shadows popping in at the edge of the screen is to widen the culling frustum so that
// objects aren't culled as early. The downside is that objects will get rendered even though they appear
// off screen, which is somewhat inefficient. A better solution would be to decouple shadow map rendering
// from model rendering; as it is now, a shadow map is only rendered if its associated model is to be
// rendered.
// (See http://trac.wildfiregames.com/ticket/504)
m->CullCamera.SetProjection(defaultNear, defaultFar, defaultCullFOV);
m->CullCamera.UpdateFrustum();
}
g_Renderer.SetSceneCamera(m->ViewCamera, m->CullCamera);
CheckLightEnv();
+ m->Game->CachePlayerColours();
+}
+
+void CGameView::Render()
+{
g_Renderer.RenderScene(this);
}
///////////////////////////////////////////////////////////
// This callback is part of the Scene interface
// Submit all objects visible in the given frustum
void CGameView::EnumerateObjects(const CFrustum& frustum, SceneCollector* c)
{
PROFILE_START( "submit terrain" );
CTerrain* pTerrain = m->Game->GetWorld()->GetTerrain();
const ssize_t patchesPerSide = pTerrain->GetPatchesPerSide();
// find out which patches will be drawn
for (ssize_t j=0; jGetPatch(i,j); // can't fail
// If the patch is underwater, calculate a bounding box that also contains the water plane
CBound bounds = patch->GetBounds();
float waterHeight = g_Renderer.GetWaterManager()->m_WaterHeight + 0.001f;
if(bounds[1].Y < waterHeight) {
bounds[1].Y = waterHeight;
}
if (!m->Culling || frustum.IsBoxVisible (CVector3D(0,0,0), bounds)) {
//c->Submit(patch);
// set the renderstate for this patch
patch->setDrawState(true);
// set the renderstate for the neighbors
CPatch *nPatch;
nPatch = pTerrain->GetPatch(i-1,j-1);
if(nPatch) nPatch->setDrawState(true);
nPatch = pTerrain->GetPatch(i,j-1);
if(nPatch) nPatch->setDrawState(true);
nPatch = pTerrain->GetPatch(i+1,j-1);
if(nPatch) nPatch->setDrawState(true);
nPatch = pTerrain->GetPatch(i-1,j);
if(nPatch) nPatch->setDrawState(true);
nPatch = pTerrain->GetPatch(i+1,j);
if(nPatch) nPatch->setDrawState(true);
nPatch = pTerrain->GetPatch(i-1,j+1);
if(nPatch) nPatch->setDrawState(true);
nPatch = pTerrain->GetPatch(i,j+1);
if(nPatch) nPatch->setDrawState(true);
nPatch = pTerrain->GetPatch(i+1,j+1);
if(nPatch) nPatch->setDrawState(true);
}
}
}
// draw the patches
for (ssize_t j=0; jGetPatch(i,j); // can't fail
if(patch->getDrawState() == true)
{
c->Submit(patch);
patch->setDrawState(false);
}
}
}
PROFILE_END( "submit terrain" );
PROFILE_START( "submit sim components" );
m->Game->GetSimulation2()->RenderSubmit(*c, frustum, m->Culling);
PROFILE_END( "submit sim components" );
}
void CGameView::CheckLightEnv()
{
if (m->CachedLightEnv == g_LightEnv)
return;
+ if (m->CachedLightEnv.GetLightingModel() != g_LightEnv.GetLightingModel())
+ g_Renderer.MakeShadersDirty();
+
m->CachedLightEnv = g_LightEnv;
CTerrain* pTerrain = m->Game->GetWorld()->GetTerrain();
if (!pTerrain)
return;
PROFILE("update light env");
pTerrain->MakeDirty(RENDERDATA_UPDATE_COLOR);
const std::vector& units = m->Game->GetWorld()->GetUnitManager().GetUnits();
for (size_t i = 0; i < units.size(); ++i)
units[i]->GetModel().SetDirtyRec(RENDERDATA_UPDATE_COLOR);
}
void CGameView::UnloadResources()
{
g_TexMan.UnloadTerrainTextures();
g_Renderer.UnloadAlphaMaps();
g_Renderer.GetWaterManager()->UnloadWaterTextures();
}
static void ClampDistance(CGameViewImpl* m, bool smooth)
{
if (!m->ConstrainCamera)
return;
CCamera targetCam = m->ViewCamera;
SetupCameraMatrixSmoothRot(m, &targetCam.m_Orientation);
CVector3D forwards = targetCam.m_Orientation.GetIn();
CVector3D delta = targetCam.GetFocus() - targetCam.m_Orientation.GetTranslation();
float dist = delta.Dot(forwards);
float clampedDist = Clamp(dist, m->ViewZoomMin, m->ViewZoomMax);
float diff = clampedDist - dist;
if (!diff)
return;
if (smooth)
{
m->PosX.AddSmoothly(forwards.X * -diff);
m->PosY.AddSmoothly(forwards.Y * -diff);
m->PosZ.AddSmoothly(forwards.Z * -diff);
}
else
{
m->PosX.Add(forwards.X * -diff);
m->PosY.Add(forwards.Y * -diff);
m->PosZ.Add(forwards.Z * -diff);
}
}
void CGameView::Update(float DeltaTime)
{
if (!g_app_has_focus)
return;
// TODO: this is probably not an ideal place for this, it should probably go
// in a CCmpWaterManager or some such thing (once such a thing exists)
if (!m->Game->m_Paused)
g_Renderer.GetWaterManager()->m_WaterTexTimer += DeltaTime;
if (m->TrackManager.IsActive() && m->TrackManager.IsPlaying())
{
if (! m->TrackManager.Update(DeltaTime))
{
// ResetCamera();
}
return;
}
// Calculate mouse movement
static int mouse_last_x = 0;
static int mouse_last_y = 0;
int mouse_dx = g_mouse_x - mouse_last_x;
int mouse_dy = g_mouse_y - mouse_last_y;
mouse_last_x = g_mouse_x;
mouse_last_y = g_mouse_y;
if (HotkeyIsPressed("camera.rotate.cw"))
m->RotateY.AddSmoothly(m->ViewRotateYSpeed * DeltaTime);
if (HotkeyIsPressed("camera.rotate.ccw"))
m->RotateY.AddSmoothly(-m->ViewRotateYSpeed * DeltaTime);
if (HotkeyIsPressed("camera.rotate.up"))
m->RotateX.AddSmoothly(-m->ViewRotateXSpeed * DeltaTime);
if (HotkeyIsPressed("camera.rotate.down"))
m->RotateX.AddSmoothly(m->ViewRotateXSpeed * DeltaTime);
float moveRightward = 0.f;
float moveForward = 0.f;
if (HotkeyIsPressed("camera.pan"))
{
moveRightward += m->ViewDragSpeed * mouse_dx;
moveForward += m->ViewDragSpeed * -mouse_dy;
}
if (g_mouse_active)
{
if (g_mouse_x >= g_xres - 2 && g_mouse_x < g_xres)
moveRightward += m->ViewScrollSpeed * DeltaTime;
else if (g_mouse_x <= 3 && g_mouse_x >= 0)
moveRightward -= m->ViewScrollSpeed * DeltaTime;
if (g_mouse_y >= g_yres - 2 && g_mouse_y < g_yres)
moveForward -= m->ViewScrollSpeed * DeltaTime;
else if (g_mouse_y <= 3 && g_mouse_y >= 0)
moveForward += m->ViewScrollSpeed * DeltaTime;
}
if (HotkeyIsPressed("camera.right"))
moveRightward += m->ViewScrollSpeed * DeltaTime;
if (HotkeyIsPressed("camera.left"))
moveRightward -= m->ViewScrollSpeed * DeltaTime;
if (HotkeyIsPressed("camera.up"))
moveForward += m->ViewScrollSpeed * DeltaTime;
if (HotkeyIsPressed("camera.down"))
moveForward -= m->ViewScrollSpeed * DeltaTime;
if (g_Joystick.IsEnabled())
{
// This could all be improved with extra speed and sensitivity settings
// (maybe use pow to allow finer control?), and inversion settings
moveRightward += g_Joystick.GetAxisValue(m->JoystickPanX) * m->ViewScrollSpeed * DeltaTime;
moveForward -= g_Joystick.GetAxisValue(m->JoystickPanY) * m->ViewScrollSpeed * DeltaTime;
m->RotateX.AddSmoothly(g_Joystick.GetAxisValue(m->JoystickRotateX) * m->ViewRotateXSpeed * DeltaTime);
m->RotateY.AddSmoothly(-g_Joystick.GetAxisValue(m->JoystickRotateY) * m->ViewRotateYSpeed * DeltaTime);
// Use a +1 bias for zoom because I want this to work with trigger buttons that default to -1
m->Zoom.AddSmoothly((g_Joystick.GetAxisValue(m->JoystickZoomIn) + 1.0f) / 2.0f * m->ViewZoomSpeed * DeltaTime);
m->Zoom.AddSmoothly(-(g_Joystick.GetAxisValue(m->JoystickZoomOut) + 1.0f) / 2.0f * m->ViewZoomSpeed * DeltaTime);
}
if (moveRightward || moveForward)
{
// Break out of following mode when the user starts scrolling
m->FollowEntity = INVALID_ENTITY;
float s = sin(m->RotateY.GetSmoothedValue());
float c = cos(m->RotateY.GetSmoothedValue());
m->PosX.AddSmoothly(c * moveRightward);
m->PosZ.AddSmoothly(-s * moveRightward);
m->PosX.AddSmoothly(s * moveForward);
m->PosZ.AddSmoothly(c * moveForward);
}
if (m->FollowEntity)
{
CmpPtr cmpPosition(*(m->Game->GetSimulation2()), m->FollowEntity);
if (!cmpPosition.null() && cmpPosition->IsInWorld())
{
// Get the most recent interpolated position
float frameOffset = m->Game->GetSimulation2()->GetLastFrameOffset();
CMatrix3D transform = cmpPosition->GetInterpolatedTransform(frameOffset, false);
CVector3D pos = transform.GetTranslation();
if (m->FollowFirstPerson)
{
float x, z, angle;
cmpPosition->GetInterpolatedPosition2D(frameOffset, x, z, angle);
float height = 4.f;
m->ViewCamera.m_Orientation.SetIdentity();
m->ViewCamera.m_Orientation.RotateX((float)M_PI/24.f);
m->ViewCamera.m_Orientation.RotateY(angle);
m->ViewCamera.m_Orientation.Translate(pos.X, pos.Y + height, pos.Z);
m->ViewCamera.UpdateFrustum();
return;
}
else
{
// Move the camera to match the unit
CCamera targetCam = m->ViewCamera;
SetupCameraMatrixSmoothRot(m, &targetCam.m_Orientation);
CVector3D pivot = targetCam.GetFocus();
CVector3D delta = pos - pivot;
m->PosX.AddSmoothly(delta.X);
m->PosY.AddSmoothly(delta.Y);
m->PosZ.AddSmoothly(delta.Z);
}
}
else
{
// The unit disappeared (died or garrisoned etc), so stop following it
m->FollowEntity = INVALID_ENTITY;
}
}
if (HotkeyIsPressed("camera.zoom.in"))
m->Zoom.AddSmoothly(m->ViewZoomSpeed * DeltaTime);
if (HotkeyIsPressed("camera.zoom.out"))
m->Zoom.AddSmoothly(-m->ViewZoomSpeed * DeltaTime);
float zoomDelta = m->Zoom.Update(DeltaTime);
if (zoomDelta)
{
CVector3D forwards = m->ViewCamera.m_Orientation.GetIn();
m->PosX.AddSmoothly(forwards.X * zoomDelta);
m->PosY.AddSmoothly(forwards.Y * zoomDelta);
m->PosZ.AddSmoothly(forwards.Z * zoomDelta);
}
if (m->ConstrainCamera)
m->RotateX.ClampSmoothly(DEGTORAD(m->ViewRotateXMin), DEGTORAD(m->ViewRotateXMax));
ClampDistance(m, true);
// Ensure the ViewCamera focus is inside the map with the chosen margins
// if not so - apply margins to the camera
if (m->ConstrainCamera)
{
CCamera targetCam = m->ViewCamera;
SetupCameraMatrixSmoothRot(m, &targetCam.m_Orientation);
CTerrain* pTerrain = m->Game->GetWorld()->GetTerrain();
CVector3D pivot = targetCam.GetFocus();
CVector3D delta = targetCam.m_Orientation.GetTranslation() - pivot;
CVector3D desiredPivot = pivot;
CmpPtr cmpRangeManager(*m->Game->GetSimulation2(), SYSTEM_ENTITY);
if (!cmpRangeManager.null() && cmpRangeManager->GetLosCircular())
{
// Clamp to a circular region around the center of the map
float r = pTerrain->GetMaxX() / 2;
CVector3D center(r, desiredPivot.Y, r);
float dist = (desiredPivot - center).Length();
if (dist > r + CAMERA_EDGE_MARGIN)
desiredPivot = center + (desiredPivot - center).Normalized() * (r + CAMERA_EDGE_MARGIN);
}
else
{
// Clamp to the square edges of the map
desiredPivot.X = Clamp(desiredPivot.X, pTerrain->GetMinX() - CAMERA_EDGE_MARGIN, pTerrain->GetMaxX() + CAMERA_EDGE_MARGIN);
desiredPivot.Z = Clamp(desiredPivot.Z, pTerrain->GetMinZ() - CAMERA_EDGE_MARGIN, pTerrain->GetMaxZ() + CAMERA_EDGE_MARGIN);
}
// Update the position so that pivot is within the margin
m->PosX.SetValueSmoothly(desiredPivot.X + delta.X);
m->PosZ.SetValueSmoothly(desiredPivot.Z + delta.Z);
}
m->PosX.Update(DeltaTime);
m->PosY.Update(DeltaTime);
m->PosZ.Update(DeltaTime);
// Handle rotation around the Y (vertical) axis
{
CCamera targetCam = m->ViewCamera;
SetupCameraMatrixSmooth(m, &targetCam.m_Orientation);
float rotateYDelta = m->RotateY.Update(DeltaTime);
if (rotateYDelta)
{
// We've updated RotateY, and need to adjust Pos so that it's still
// facing towards the original focus point (the terrain in the center
// of the screen).
CVector3D upwards(0.0f, 1.0f, 0.0f);
CVector3D pivot = targetCam.GetFocus();
CVector3D delta = targetCam.m_Orientation.GetTranslation() - pivot;
CQuaternion q;
q.FromAxisAngle(upwards, rotateYDelta);
CVector3D d = q.Rotate(delta) - delta;
m->PosX.Add(d.X);
m->PosY.Add(d.Y);
m->PosZ.Add(d.Z);
}
}
// Handle rotation around the X (sideways, relative to camera) axis
{
CCamera targetCam = m->ViewCamera;
SetupCameraMatrixSmooth(m, &targetCam.m_Orientation);
float rotateXDelta = m->RotateX.Update(DeltaTime);
if (rotateXDelta)
{
CVector3D rightwards = targetCam.m_Orientation.GetLeft() * -1.0f;
CVector3D pivot = m->ViewCamera.GetFocus();
CVector3D delta = targetCam.m_Orientation.GetTranslation() - pivot;
CQuaternion q;
q.FromAxisAngle(rightwards, rotateXDelta);
CVector3D d = q.Rotate(delta) - delta;
m->PosX.Add(d.X);
m->PosY.Add(d.Y);
m->PosZ.Add(d.Z);
}
}
/* This is disabled since it doesn't seem necessary:
// Ensure the camera's near point is never inside the terrain
if (m->ConstrainCamera)
{
CMatrix3D target;
target.SetIdentity();
target.RotateX(m->RotateX.GetValue());
target.RotateY(m->RotateY.GetValue());
target.Translate(m->PosX.GetValue(), m->PosY.GetValue(), m->PosZ.GetValue());
CVector3D nearPoint = target.GetTranslation() + target.GetIn() * defaultNear;
float ground = m->Game->GetWorld()->GetTerrain()->GetExactGroundLevel(nearPoint.X, nearPoint.Z);
float limit = ground + 16.f;
if (nearPoint.Y < limit)
m->PosY.AddSmoothly(limit - nearPoint.Y);
}
*/
m->RotateY.Wrap(-(float)M_PI, (float)M_PI);
// Update the camera matrix
SetupCameraMatrixSmooth(m, &m->ViewCamera.m_Orientation);
m->ViewCamera.UpdateFrustum();
}
void CGameView::MoveCameraTarget(const CVector3D& target, bool minimap)
{
// Maintain the same orientation and level of zoom, if we can
// (do this by working out the point the camera is looking at, saving
// the difference between that position and the camera point, and restoring
// that difference to our new target)
CCamera targetCam = m->ViewCamera;
SetupCameraMatrixNonSmooth(m, &targetCam.m_Orientation);
CVector3D pivot = targetCam.GetFocus();
CVector3D delta = target - pivot;
//If minimap movement, maintain previous zoom level by not changing Y position
// - this prevents strange behavior when moving across changes in terrain height
if (!minimap)
m->PosY.SetValueSmoothly(delta.Y + m->PosY.GetValue());
m->PosX.SetValueSmoothly(delta.X + m->PosX.GetValue());
m->PosZ.SetValueSmoothly(delta.Z + m->PosZ.GetValue());
ClampDistance(m, false);
// Break out of following mode so the camera really moves to the target
m->FollowEntity = INVALID_ENTITY;
}
void CGameView::ResetCameraTarget(const CVector3D& target)
{
CMatrix3D orientation;
orientation.SetIdentity();
orientation.RotateX(DEGTORAD(m->ViewRotateXDefault));
orientation.RotateY(DEGTORAD(m->ViewRotateYDefault));
CVector3D delta = orientation.GetIn() * m->ViewZoomDefault;
m->PosX.SetValue(target.X - delta.X);
m->PosY.SetValue(target.Y - delta.Y);
m->PosZ.SetValue(target.Z - delta.Z);
ClampDistance(m, false);
SetupCameraMatrixSmooth(m, &m->ViewCamera.m_Orientation);
m->ViewCamera.UpdateFrustum();
// Break out of following mode so the camera really moves to the target
m->FollowEntity = INVALID_ENTITY;
}
void CGameView::ResetCameraAngleZoom()
{
CCamera targetCam = m->ViewCamera;
SetupCameraMatrixNonSmooth(m, &targetCam.m_Orientation);
// Compute the zoom adjustment to get us back to the default
CVector3D forwards = targetCam.m_Orientation.GetIn();
CVector3D delta = targetCam.GetFocus() - targetCam.m_Orientation.GetTranslation();
float dist = delta.Dot(forwards);
m->Zoom.AddSmoothly(dist - m->ViewZoomDefault);
// Reset orientations to default
m->RotateX.SetValueSmoothly(DEGTORAD(m->ViewRotateXDefault));
m->RotateY.SetValueSmoothly(DEGTORAD(m->ViewRotateYDefault));
}
void CGameView::CameraFollow(entity_id_t entity, bool firstPerson)
{
m->FollowEntity = entity;
m->FollowFirstPerson = firstPerson;
}
InReaction game_view_handler(const SDL_Event_* ev)
{
// put any events that must be processed even if inactive here
if(!g_app_has_focus || !g_Game)
return IN_PASS;
CGameView *pView=g_Game->GetView();
return pView->HandleEvent(ev);
}
InReaction CGameView::HandleEvent(const SDL_Event_* ev)
{
switch(ev->ev.type)
{
case SDL_HOTKEYDOWN:
std::string hotkey = static_cast(ev->ev.user.data1);
if (hotkey == "wireframe")
{
if (g_Renderer.GetModelRenderMode() == SOLID)
{
g_Renderer.SetTerrainRenderMode(EDGED_FACES);
g_Renderer.SetModelRenderMode(EDGED_FACES);
}
else if (g_Renderer.GetModelRenderMode() == EDGED_FACES)
{
g_Renderer.SetTerrainRenderMode(WIREFRAME);
g_Renderer.SetModelRenderMode(WIREFRAME);
}
else
{
g_Renderer.SetTerrainRenderMode(SOLID);
g_Renderer.SetModelRenderMode(SOLID);
}
return IN_HANDLED;
}
// Mouse wheel must be treated using events instead of polling,
// because SDL auto-generates a sequence of mousedown/mouseup events
// and we never get to see the "down" state inside Update().
else if (hotkey == "camera.zoom.wheel.in")
{
m->Zoom.AddSmoothly(m->ViewZoomSpeedWheel);
return IN_HANDLED;
}
else if (hotkey == "camera.zoom.wheel.out")
{
m->Zoom.AddSmoothly(-m->ViewZoomSpeedWheel);
return IN_HANDLED;
}
else if (hotkey == "camera.rotate.wheel.cw")
{
m->RotateY.AddSmoothly(m->ViewRotateYSpeedWheel);
return IN_HANDLED;
}
else if (hotkey == "camera.rotate.wheel.ccw")
{
m->RotateY.AddSmoothly(-m->ViewRotateYSpeedWheel);
return IN_HANDLED;
}
else if (hotkey == "camera.reset")
{
ResetCameraAngleZoom();
return IN_HANDLED;
}
}
return IN_PASS;
}
Index: ps/trunk/source/graphics/LightEnv.cpp
===================================================================
--- ps/trunk/source/graphics/LightEnv.cpp (revision 9122)
+++ ps/trunk/source/graphics/LightEnv.cpp (revision 9123)
@@ -1,64 +1,65 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
/*
* CLightEnv implementation
*/
#include "precompiled.h"
#include "maths/MathUtil.h"
#include "graphics/LightEnv.h"
CLightEnv::CLightEnv()
: m_Elevation(DEGTORAD(45)),
m_Rotation(DEGTORAD(315)),
m_TerrainShadowTransparency(0.0),
+ m_LightingModel("standard"),
m_SunColor(1.5, 1.5, 1.5),
m_TerrainAmbientColor(0x50/255.f, 0x60/255.f, 0x85/255.f),
m_UnitsAmbientColor(0x80/255.f, 0x80/255.f, 0x80/255.f)
{
CalculateSunDirection();
}
void CLightEnv::SetElevation(float f)
{
m_Elevation = f;
CalculateSunDirection();
}
void CLightEnv::SetRotation(float f)
{
m_Rotation = f;
CalculateSunDirection();
}
void CLightEnv::SetTerrainShadowTransparency(float f)
{
m_TerrainShadowTransparency = f;
}
void CLightEnv::CalculateSunDirection()
{
m_SunDir.Y=-float(sin(m_Elevation));
float scale=1+m_SunDir.Y;
m_SunDir.X=scale*float(sin(m_Rotation));
m_SunDir.Z=scale*float(cos(m_Rotation));
m_SunDir.Normalize();
}
Index: ps/trunk/source/graphics/ShaderTechnique.h
===================================================================
--- ps/trunk/source/graphics/ShaderTechnique.h (nonexistent)
+++ ps/trunk/source/graphics/ShaderTechnique.h (revision 9123)
@@ -0,0 +1,91 @@
+/* Copyright (C) 2011 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0 A.D. If not, see .
+ */
+
+#ifndef INCLUDED_SHADERTECHNIQUE
+#define INCLUDED_SHADERTECHNIQUE
+
+#include "graphics/ShaderProgram.h"
+
+/**
+ * Implements a render pass consisting of various GL state changes and a shader.
+ */
+class CShaderPass
+{
+public:
+ CShaderPass(const CShaderProgramPtr& shader);
+
+ // Add various bits of GL state to the pass:
+ void AlphaFunc(GLenum func, GLclampf ref);
+ void BlendFunc(GLenum src, GLenum dst);
+ void ColorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a);
+ void DepthMask(GLboolean mask);
+
+ /**
+ * Set all the GL state that was previously specified on this pass.
+ */
+ void Bind();
+
+ /**
+ * Reset the GL state to the default.
+ */
+ void Unbind();
+
+ CShaderProgramPtr GetShader() { return m_Shader; }
+
+private:
+ CShaderProgramPtr m_Shader;
+
+ bool m_HasAlpha;
+ GLenum m_AlphaFunc;
+ GLclampf m_AlphaRef;
+
+ bool m_HasBlend;
+ GLenum m_BlendSrc;
+ GLenum m_BlendDst;
+
+ bool m_HasColorMask;
+ GLboolean m_ColorMaskR;
+ GLboolean m_ColorMaskG;
+ GLboolean m_ColorMaskB;
+ GLboolean m_ColorMaskA;
+
+ bool m_HasDepthMask;
+ GLboolean m_DepthMask;
+};
+
+/**
+ * Implements a render technique consisting of a sequence of passes.
+ * In theory these should probably be loaded from an XML file or something,
+ * but currently you have to construct them manually.
+ */
+class CShaderTechnique
+{
+public:
+ CShaderTechnique(const CShaderPass& pass);
+ void AddPass(const CShaderPass& pass);
+
+ int GetNumPasses();
+
+ void BeginPass(int pass);
+ void EndPass(int pass);
+ CShaderProgramPtr GetShader(int pass);
+
+private:
+ std::vector m_Passes;
+};
+
+#endif // INCLUDED_SHADERTECHNIQUE
Property changes on: ps/trunk/source/graphics/ShaderTechnique.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: ps/trunk/source/graphics/TextureManager.cpp
===================================================================
--- ps/trunk/source/graphics/TextureManager.cpp (revision 9122)
+++ ps/trunk/source/graphics/TextureManager.cpp (revision 9123)
@@ -1,628 +1,633 @@
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#include "precompiled.h"
#include "TextureManager.h"
#include "graphics/TextureConverter.h"
#include "lib/allocators/shared_ptr.h"
#include "lib/res/h_mgr.h"
#include "lib/file/vfs/vfs_tree.h"
#include "lib/res/graphics/ogl_tex.h"
#include "lib/timer.h"
#include "maths/MD5.h"
#include "ps/CacheLoader.h"
#include "ps/CLogger.h"
#include "ps/Filesystem.h"
#include
#include
#include
#include
struct TPhash
: std::unary_function,
std::unary_function
{
std::size_t operator()(CTextureProperties const& a) const
{
std::size_t seed = 0;
boost::hash_combine(seed, a.m_Path);
boost::hash_combine(seed, a.m_Filter);
boost::hash_combine(seed, a.m_Wrap);
boost::hash_combine(seed, a.m_Aniso);
return seed;
}
std::size_t operator()(CTexturePtr const& a) const
{
return (*this)(a->m_Properties);
}
};
struct TPequal_to
: std::binary_function,
std::binary_function
{
bool operator()(CTextureProperties const& a, CTextureProperties const& b) const
{
return a.m_Path == b.m_Path && a.m_Filter == b.m_Filter
&& a.m_Wrap == b.m_Wrap && a.m_Aniso == b.m_Aniso;
}
bool operator()(CTexturePtr const& a, CTexturePtr const& b) const
{
return (*this)(a->m_Properties, b->m_Properties);
}
};
class CTextureManagerImpl
{
friend class CTexture;
public:
CTextureManagerImpl(PIVFS vfs, bool highQuality, bool disableGL) :
m_VFS(vfs), m_CacheLoader(vfs, L".dds"), m_DisableGL(disableGL), m_TextureConverter(vfs, highQuality),
m_DefaultHandle(0), m_ErrorHandle(0)
{
// Initialise some textures that will always be available,
// without needing to load any files
// Default placeholder texture (grey)
if (!m_DisableGL)
{
// Construct 1x1 24-bit texture
shared_ptr data(new u8[3], ArrayDeleter());
data.get()[0] = 64;
data.get()[1] = 64;
data.get()[2] = 64;
Tex t;
(void)tex_wrap(1, 1, 24, 0, data, 0, &t);
m_DefaultHandle = ogl_tex_wrap(&t, m_VFS, L"(default texture)");
(void)ogl_tex_set_filter(m_DefaultHandle, GL_LINEAR);
if (!m_DisableGL)
(void)ogl_tex_upload(m_DefaultHandle);
}
// Error texture (magenta)
if (!m_DisableGL)
{
// Construct 1x1 24-bit texture
shared_ptr data(new u8[3], ArrayDeleter());
data.get()[0] = 255;
data.get()[1] = 0;
data.get()[2] = 255;
Tex t;
(void)tex_wrap(1, 1, 24, 0, data, 0, &t);
m_ErrorHandle = ogl_tex_wrap(&t, m_VFS, L"(error texture)");
(void)ogl_tex_set_filter(m_ErrorHandle, GL_LINEAR);
if (!m_DisableGL)
(void)ogl_tex_upload(m_ErrorHandle);
// Construct a CTexture to return to callers who want an error texture
CTextureProperties props(L"(error texture)");
m_ErrorTexture = CTexturePtr(new CTexture(m_ErrorHandle, props, this));
m_ErrorTexture->m_State = CTexture::LOADED;
m_ErrorTexture->m_Self = m_ErrorTexture;
}
// Allow hotloading of textures
RegisterFileReloadFunc(ReloadChangedFileCB, this);
}
~CTextureManagerImpl()
{
UnregisterFileReloadFunc(ReloadChangedFileCB, this);
(void)ogl_tex_free(m_DefaultHandle);
(void)ogl_tex_free(m_ErrorHandle);
}
CTexturePtr GetErrorTexture()
{
return m_ErrorTexture;
}
/**
* See CTextureManager::CreateTexture
*/
CTexturePtr CreateTexture(const CTextureProperties& props)
{
// Construct a new default texture with the given properties to use as the search key
CTexturePtr texture(new CTexture(m_DefaultHandle, props, this));
// Try to find an existing texture with the given properties
TextureCache::iterator it = m_TextureCache.find(texture);
if (it != m_TextureCache.end())
return *it;
// Can't find an existing texture - finish setting up this new texture
texture->m_Self = texture;
m_TextureCache.insert(texture);
m_HotloadFiles[props.m_Path].insert(texture);
return texture;
}
/**
* Load the given file into the texture object and upload it to OpenGL.
* Assumes the file already exists.
*/
void LoadTexture(const CTexturePtr& texture, const VfsPath& path)
{
if (m_DisableGL)
return;
Handle h = ogl_tex_load(m_VFS, path, RES_UNIQUE);
if (h <= 0)
{
LOGERROR(L"Texture failed to load; \"%ls\"", texture->m_Properties.m_Path.string().c_str());
// Replace with error texture to make it obvious
texture->SetHandle(m_ErrorHandle);
return;
}
// Get some flags for later use
size_t flags = 0;
(void)ogl_tex_get_format(h, &flags, NULL);
// Initialise base colour from the texture
(void)ogl_tex_get_average_colour(h, &texture->m_BaseColour);
// Set GL upload properties
(void)ogl_tex_set_wrap(h, texture->m_Properties.m_Wrap);
(void)ogl_tex_set_anisotropy(h, texture->m_Properties.m_Aniso);
// Prevent ogl_tex automatically generating mipmaps (which is slow and unwanted),
// by avoiding mipmapped filters unless the source texture already has mipmaps
GLint filter = texture->m_Properties.m_Filter;
if (!(flags & TEX_MIPMAPS))
{
switch (filter)
{
case GL_NEAREST_MIPMAP_NEAREST:
case GL_NEAREST_MIPMAP_LINEAR:
filter = GL_NEAREST;
break;
case GL_LINEAR_MIPMAP_NEAREST:
case GL_LINEAR_MIPMAP_LINEAR:
filter = GL_LINEAR;
break;
}
}
(void)ogl_tex_set_filter(h, filter);
// Upload to GL
if (!m_DisableGL && ogl_tex_upload(h) < 0)
{
LOGERROR(L"Texture failed to upload: \"%ls\"", texture->m_Properties.m_Path.string().c_str());
ogl_tex_free(h);
// Replace with error texture to make it obvious
texture->SetHandle(m_ErrorHandle);
return;
}
// Let the texture object take ownership of this handle
texture->SetHandle(h, true);
}
/**
* Set up some parameters for the loose cache filename code.
*/
void PrepareCacheKey(const CTexturePtr& texture, MD5& hash, u32& version)
{
// Hash the settings, so we won't use an old loose cache file if the
// settings have changed
CTextureConverter::Settings settings = GetConverterSettings(texture);
settings.Hash(hash);
// Arbitrary version number - change this if we update the code and
// need to invalidate old users' caches
version = 1;
}
/**
* Attempts to load a cached version of a texture.
* If the texture is loaded (or there was an error), returns true.
* Otherwise, returns false to indicate the caller should generate the cached version.
*/
bool TryLoadingCached(const CTexturePtr& texture)
{
MD5 hash;
u32 version;
PrepareCacheKey(texture, hash, version);
VfsPath loadPath;
LibError ret = m_CacheLoader.TryLoadingCached(texture->m_Properties.m_Path, hash, version, loadPath);
if (ret == INFO::OK)
{
// Found a cached texture - load it
LoadTexture(texture, loadPath);
return true;
}
else if (ret == INFO::SKIPPED)
{
// No cached version was found - we'll need to create it
return false;
}
else
{
debug_assert(ret < 0);
// No source file or archive cache was found, so we can't load the
// real texture at all - return the error texture instead
texture->SetHandle(m_ErrorHandle);
return true;
}
}
/**
* Initiates an asynchronous conversion process, from the texture's
* source file to the corresponding loose cache file.
*/
void ConvertTexture(const CTexturePtr& texture)
{
VfsPath sourcePath = texture->m_Properties.m_Path;
MD5 hash;
u32 version;
PrepareCacheKey(texture, hash, version);
VfsPath looseCachePath = m_CacheLoader.LooseCachePath(sourcePath, hash, version);
// LOGWARNING(L"Converting texture \"%ls\"", srcPath.c_str());
CTextureConverter::Settings settings = GetConverterSettings(texture);
m_TextureConverter.ConvertTexture(texture, sourcePath, looseCachePath, settings);
}
bool GenerateCachedTexture(const VfsPath& sourcePath, VfsPath& archiveCachePath)
{
archiveCachePath = m_CacheLoader.ArchiveCachePath(sourcePath);
CTextureProperties textureProps(sourcePath);
CTexturePtr texture = CreateTexture(textureProps);
CTextureConverter::Settings settings = GetConverterSettings(texture);
if (!m_TextureConverter.ConvertTexture(texture, sourcePath, VfsPath("cache") / archiveCachePath, settings))
return false;
while (true)
{
CTexturePtr textureOut;
VfsPath dest;
bool ok;
if (m_TextureConverter.Poll(textureOut, dest, ok))
return ok;
// Spin-loop is dumb but it works okay for now
SDL_Delay(0);
}
}
bool MakeProgress()
{
// Process any completed conversion tasks
{
CTexturePtr texture;
VfsPath dest;
bool ok;
if (m_TextureConverter.Poll(texture, dest, ok))
{
if (ok)
{
LoadTexture(texture, dest);
}
else
{
LOGERROR(L"Texture failed to convert: \"%ls\"", texture->m_Properties.m_Path.string().c_str());
texture->SetHandle(m_ErrorHandle);
}
texture->m_State = CTexture::LOADED;
return true;
}
}
// We'll only push new conversion requests if it's not already busy
bool converterBusy = m_TextureConverter.IsBusy();
if (!converterBusy)
{
// Look for all high-priority textures needing conversion.
// (Iterating over all textures isn't optimally efficient, but it
// doesn't seem to be a problem yet and it's simpler than maintaining
// multiple queues.)
for (TextureCache::iterator it = m_TextureCache.begin(); it != m_TextureCache.end(); ++it)
{
if ((*it)->m_State == CTexture::HIGH_NEEDS_CONVERTING)
{
// Start converting this texture
(*it)->m_State = CTexture::HIGH_IS_CONVERTING;
ConvertTexture(*it);
return true;
}
}
}
// Try loading prefetched textures from their cache
for (TextureCache::iterator it = m_TextureCache.begin(); it != m_TextureCache.end(); ++it)
{
if ((*it)->m_State == CTexture::PREFETCH_NEEDS_LOADING)
{
if (TryLoadingCached(*it))
{
(*it)->m_State = CTexture::LOADED;
}
else
{
(*it)->m_State = CTexture::PREFETCH_NEEDS_CONVERTING;
}
return true;
}
}
// If we've got nothing better to do, then start converting prefetched textures.
if (!converterBusy)
{
for (TextureCache::iterator it = m_TextureCache.begin(); it != m_TextureCache.end(); ++it)
{
if ((*it)->m_State == CTexture::PREFETCH_NEEDS_CONVERTING)
{
(*it)->m_State = CTexture::PREFETCH_IS_CONVERTING;
ConvertTexture(*it);
return true;
}
}
}
return false;
}
/**
* Compute the conversion settings that apply to a given texture, by combining
* the textures.xml files from its directory and all parent directories
* (up to the VFS root).
*/
CTextureConverter::Settings GetConverterSettings(const CTexturePtr& texture)
{
fs::wpath srcPath = texture->m_Properties.m_Path.string();
std::vector files;
VfsPath p;
for (fs::wpath::iterator it = srcPath.begin(); it != srcPath.end(); ++it)
{
VfsPath settingsPath = p / "textures.xml";
m_HotloadFiles[settingsPath].insert(texture);
CTextureConverter::SettingsFile* f = GetSettingsFile(settingsPath);
if (f)
files.push_back(f);
p = p / *it;
}
return m_TextureConverter.ComputeSettings(srcPath.leaf(), files);
}
/**
* Return the (cached) settings file with the given filename,
* or NULL if it doesn't exist.
*/
CTextureConverter::SettingsFile* GetSettingsFile(const VfsPath& path)
{
SettingsFilesMap::iterator it = m_SettingsFiles.find(path);
if (it != m_SettingsFiles.end())
return it->second.get();
if (m_VFS->GetFileInfo(path, NULL) >= 0)
{
shared_ptr settings(m_TextureConverter.LoadSettings(path));
m_SettingsFiles.insert(std::make_pair(path, settings));
return settings.get();
}
else
{
m_SettingsFiles.insert(std::make_pair(path, shared_ptr()));
return NULL;
}
}
static LibError ReloadChangedFileCB(void* param, const VfsPath& path)
{
return static_cast(param)->ReloadChangedFile(path);
}
LibError ReloadChangedFile(const VfsPath& path)
{
// Uncache settings file, if this is one
m_SettingsFiles.erase(path);
// Find all textures using this file
HotloadFilesMap::iterator files = m_HotloadFiles.find(path);
if (files != m_HotloadFiles.end())
{
// Flag all textures using this file as needing reloading
for (std::set >::iterator it = files->second.begin(); it != files->second.end(); ++it)
{
if (shared_ptr texture = it->lock())
{
texture->m_State = CTexture::UNLOADED;
texture->SetHandle(m_DefaultHandle);
}
}
}
return INFO::OK;
}
private:
PIVFS m_VFS;
CCacheLoader m_CacheLoader;
bool m_DisableGL;
CTextureConverter m_TextureConverter;
Handle m_DefaultHandle;
Handle m_ErrorHandle;
CTexturePtr m_ErrorTexture;
// Cache of all loaded textures
typedef boost::unordered_set TextureCache;
TextureCache m_TextureCache;
// TODO: we ought to expire unused textures from the cache eventually
// Store the set of textures that need to be reloaded when the given file
// (a source file or settings.xml) is modified
typedef boost::unordered_map > > HotloadFilesMap;
HotloadFilesMap m_HotloadFiles;
// Cache for the conversion settings files
typedef boost::unordered_map > SettingsFilesMap;
SettingsFilesMap m_SettingsFiles;
};
CTexture::CTexture(Handle handle, const CTextureProperties& props, CTextureManagerImpl* textureManager) :
m_Handle(handle), m_BaseColour(0), m_State(UNLOADED), m_Properties(props), m_TextureManager(textureManager)
{
// Add a reference to the handle (it might be shared by multiple CTextures
// so we can't take ownership of it)
if (m_Handle)
h_add_ref(m_Handle);
}
CTexture::~CTexture()
{
if (m_Handle)
ogl_tex_free(m_Handle);
}
void CTexture::Bind(size_t unit)
{
+ ogl_tex_bind(GetHandle(), unit);
+}
+
+Handle CTexture::GetHandle()
+{
// TODO: TryLoad might call ogl_tex_upload which enables GL_TEXTURE_2D
// on texture unit 0, regardless of 'unit', which callers might
// not be expecting. Ideally that wouldn't happen.
TryLoad();
- ogl_tex_bind(m_Handle, unit);
+ return m_Handle;
}
bool CTexture::TryLoad()
{
// If we haven't started loading, then try loading, and if that fails then request conversion.
// If we have already tried prefetch loading, and it failed, bump the conversion request to HIGH priority.
if (m_State == UNLOADED || m_State == PREFETCH_NEEDS_LOADING || m_State == PREFETCH_NEEDS_CONVERTING)
{
if (shared_ptr self = m_Self.lock())
{
if (m_State != PREFETCH_NEEDS_CONVERTING && m_TextureManager->TryLoadingCached(self))
m_State = LOADED;
else
m_State = HIGH_NEEDS_CONVERTING;
}
}
return (m_State == LOADED);
}
void CTexture::Prefetch()
{
if (m_State == UNLOADED)
{
if (shared_ptr self = m_Self.lock())
{
m_State = PREFETCH_NEEDS_LOADING;
}
}
}
bool CTexture::IsLoaded()
{
return (m_State == LOADED);
}
void CTexture::SetHandle(Handle handle, bool takeOwnership)
{
if (handle == m_Handle)
return;
if (!takeOwnership)
h_add_ref(handle);
ogl_tex_free(m_Handle);
m_Handle = handle;
}
size_t CTexture::GetWidth() const
{
size_t w = 0;
(void)ogl_tex_get_size(m_Handle, &w, 0, 0);
return w;
}
size_t CTexture::GetHeight() const
{
size_t h = 0;
(void)ogl_tex_get_size(m_Handle, 0, &h, 0);
return h;
}
bool CTexture::HasAlpha() const
{
size_t flags = 0;
(void)ogl_tex_get_format(m_Handle, &flags, 0);
return (flags & TEX_ALPHA) != 0;
}
u32 CTexture::GetBaseColour() const
{
return m_BaseColour;
}
// CTextureManager: forward all calls to impl:
CTextureManager::CTextureManager(PIVFS vfs, bool highQuality, bool disableGL) :
m(new CTextureManagerImpl(vfs, highQuality, disableGL))
{
}
CTextureManager::~CTextureManager()
{
delete m;
}
CTexturePtr CTextureManager::CreateTexture(const CTextureProperties& props)
{
return m->CreateTexture(props);
}
CTexturePtr CTextureManager::GetErrorTexture()
{
return m->GetErrorTexture();
}
bool CTextureManager::MakeProgress()
{
return m->MakeProgress();
}
bool CTextureManager::GenerateCachedTexture(const VfsPath& path, VfsPath& outputPath)
{
return m->GenerateCachedTexture(path, outputPath);
}
Index: ps/trunk/source/graphics/GameView.h
===================================================================
--- ps/trunk/source/graphics/GameView.h (revision 9122)
+++ ps/trunk/source/graphics/GameView.h (revision 9123)
@@ -1,100 +1,100 @@
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#ifndef INCLUDED_GAMEVIEW
#define INCLUDED_GAMEVIEW
// needed by minimap
extern float g_MaxZoomHeight; //note: Max terrain height is this minus YMinOffset
extern float g_YMinOffset;
#include "renderer/Scene.h"
#include "simulation2/system/Entity.h"
#include "lib/input.h" // InReaction - can't forward-declare enum
class CGame;
class CObjectManager;
class CCamera;
class CCinemaManager;
class CLOSTexture;
class CVector3D;
struct SViewPort;
struct JSObject;
class CGameViewImpl;
class CGameView : private Scene
{
NONCOPYABLE(CGameView);
public:
static const float defaultFOV, defaultCullFOV, defaultNear, defaultFar;
private:
CGameViewImpl* m;
// Check whether lighting environment has changed and update vertex data if necessary
void CheckLightEnv();
//BEGIN: Implementation of Scene
void EnumerateObjects(const CFrustum& frustum, SceneCollector* c);
//END: Implementation of Scene
// InitResources(): Load all graphics resources (textures, actor objects and
// alpha maps) required by the game
//void InitResources();
// UnloadResources(): Unload all graphics resources loaded by InitResources
void UnloadResources();
public:
CGameView(CGame *pGame);
~CGameView();
void SetViewport(const SViewPort& vp);
void RegisterInit();
int Initialize();
CObjectManager& GetObjectManager() const;
// Update: Update all the view information (i.e. rotate camera, scroll,
// whatever). This will *not* change any World information - only the
// *presentation*
void Update(float DeltaTime);
- // Render: Render the World
+ void BeginFrame();
void Render();
InReaction HandleEvent(const SDL_Event_* ev);
void MoveCameraTarget(const CVector3D& target, bool minimap = false);
void ResetCameraTarget(const CVector3D& target);
void ResetCameraAngleZoom();
void CameraFollow(entity_id_t entity, bool firstPerson);
CCamera *GetCamera();
CCinemaManager* GetCinema();
CLOSTexture& GetLOSTexture();
JSObject* GetScript();
static void ScriptingInit();
};
extern InReaction game_view_handler(const SDL_Event_* ev);
#endif
Index: ps/trunk/source/graphics/LightEnv.h
===================================================================
--- ps/trunk/source/graphics/LightEnv.h (revision 9122)
+++ ps/trunk/source/graphics/LightEnv.h (revision 9123)
@@ -1,153 +1,189 @@
-/* Copyright (C) 2009 Wildfire Games.
+/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
/*
* CLightEnv, a class describing the current lights
*/
#ifndef INCLUDED_LIGHTENV
#define INCLUDED_LIGHTENV
-#include "Color.h"
+#include "graphics/Color.h"
+#include "maths/MathUtil.h"
#include "maths/Vector3D.h"
class CMapWriter;
class CMapReader;
/**
* Class CLightEnv: description of a lighting environment - contains all the
* necessary parameters for representation of the lighting within a scenario
*/
class CLightEnv
{
friend class CMapWriter;
friend class CMapReader;
friend class CXMLReader;
private:
/**
* m_Elevation: Height of sun above the horizon, in radians.
* For example, an elevation of M_PI/2 means the sun is straight up.
*/
float m_Elevation;
/**
* m_Rotation: Direction of sun on the compass, in radians.
* For example, a rotation of zero means the sun is in the direction (0,0,-1)
* and a rotation of M_PI/2 means the sun is in the direction (1,0,0) (not taking
* elevation into account).
*/
float m_Rotation;
/**
* m_TerrainShadowTransparency: Fraction of diffuse light that reaches shadowed terrain.
* A value of 0.0 means shadowed polygons get only ambient light, while a value of 1.0
* means shadows don't have any effect at all.
+ * TODO: probably delete this, since it's never used and always set to 0.0.
*/
float m_TerrainShadowTransparency;
CVector3D m_SunDir;
+ /**
+ * A string that shaders use to determine what lighting model to implement.
+ * Current recognised values are "old" and "standard".
+ */
+ std::string m_LightingModel;
+
public:
RGBColor m_SunColor;
RGBColor m_TerrainAmbientColor;
RGBColor m_UnitsAmbientColor;
public:
CLightEnv();
float GetElevation() const { return m_Elevation; }
float GetRotation() const { return m_Rotation; }
const CVector3D& GetSunDir() const { return m_SunDir; }
float GetTerrainShadowTransparency() const { return m_TerrainShadowTransparency; }
+ const std::string& GetLightingModel() const { return m_LightingModel; }
void SetElevation(float f);
void SetRotation(float f);
void SetTerrainShadowTransparency(float f);
+ void SetLightingModel(const std::string& model) { m_LightingModel = model; }
+
/**
* EvaluateTerrain: Calculate brightness of a point of the terrain with the given normal
* vector.
* The resulting color contains both ambient and diffuse light.
*
* @param normal normal vector (must have length 1)
* @param color resulting color
*/
void EvaluateTerrain(const CVector3D& normal, RGBColor& color) const
{
float dot = -normal.Dot(m_SunDir);
color = m_TerrainAmbientColor;
if (dot > 0)
color += m_SunColor * dot;
}
/**
* EvaluateUnit: Calculate brightness of a point of a unit with the given normal
* vector.
* The resulting color contains both ambient and diffuse light.
*
* @param normal normal vector (must have length 1)
* @param color resulting color
*/
void EvaluateUnit(const CVector3D& normal, RGBColor& color) const
{
float dot = -normal.Dot(m_SunDir);
color = m_UnitsAmbientColor;
if (dot > 0)
color += m_SunColor * dot;
}
/**
* EvaluateDirect: Like EvaluateTerrain and EvaluateUnit, but return only the direct
* sunlight term without ambient.
*
* @param normal normal vector (must have length 1)
* @param color resulting color
*/
void EvaluateDirect(const CVector3D& normal, RGBColor& color) const
{
float dot = -normal.Dot(m_SunDir);
if (dot > 0)
color = m_SunColor * dot;
else
color = CVector3D(0,0,0);
}
+ /**
+ * Compute the diffuse sun lighting.
+ * If @p includeSunColor is set, the return value includes the sun color.
+ * (If sun overbrightness is enabled, this might result in clamping).
+ * Otherwise it returns a factor that the sun color should be multiplied by.
+ */
+ SColor4ub EvaluateDiffuse(const CVector3D& normal, bool includeSunColor) const
+ {
+ float dot = -normal.Dot(m_SunDir);
+
+ if (dot <= 0)
+ return SColor4ub(0, 0, 0, 255);
+
+ if (includeSunColor)
+ {
+ return ConvertRGBColorTo4ub(m_SunColor * dot);
+ }
+ else
+ {
+ int c = clamp((int)(dot * 255), 0, 255);
+ return SColor4ub(c, c, c, 255);
+ }
+ }
+
// Comparison operators
bool operator==(const CLightEnv& o) const
{
return m_Elevation == o.m_Elevation &&
m_Rotation == o.m_Rotation &&
m_TerrainShadowTransparency == o.m_TerrainShadowTransparency &&
+ m_LightingModel == o.m_LightingModel &&
m_SunColor == o.m_SunColor &&
m_TerrainAmbientColor == o.m_TerrainAmbientColor &&
m_UnitsAmbientColor == o.m_UnitsAmbientColor;
}
bool operator!=(const CLightEnv& o) const
{
return !(*this == o);
}
private:
void CalculateSunDirection();
};
#endif
Index: ps/trunk/source/lib/glext_funcs.h
===================================================================
--- ps/trunk/source/lib/glext_funcs.h (revision 9122)
+++ ps/trunk/source/lib/glext_funcs.h (revision 9123)
@@ -1,235 +1,253 @@
/* Copyright (c) 2011 Wildfire Games
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* OpenGL extension function declarations (X macros).
*/
#if OS_MACOSX
#include
#else
#include
#endif
#if OS_WIN
# include
#endif
/*
FUNC is used for functions that are only extensions.
FUNC2 is used for functions that have been promoted to core features.
FUNC3 is used for functions that have been promoted to core features
but have slightly changed semantics and need to be referred to by their
core name instead of extension name.
The FUNC2/FUNC3 calls include the version of OpenGL in which the extension was promoted,
and the pre- and post-promotion names (e.g. "glBindBufferARB" vs "glBindBuffer").
If the GL driver is advertising a sufficiently high version, we load the promoted
name; otherwise we use the *ARB name. (The spec says:
"GL implementations of such later revisions should continue to export the name
strings of promoted extensions in the EXTENSIONS string, and continue to support
the ARB-affixed versions of functions and enumerants as a transition aid."
but some drivers might be stupid/buggy and fail to do that, so we don't just use
the ARB names unconditionally.)
The names are made accessible to engine code only via the ARB name, to make it
obvious that care must be taken (i.e. by being certain that the extension is
actually supported).
*/
// were these defined as real functions in gl.h already?
// GL_EXT_draw_range_elements / GL1.2:
FUNC2(void, glDrawRangeElementsEXT, glDrawRangeElements, "1.2", (GLenum, GLuint, GLuint, GLsizei, GLenum, GLvoid*))
// GL_ARB_multitexture / GL1.3:
FUNC2(void, glMultiTexCoord2fARB, glMultiTexCoord2f, "1.3", (int, float, float))
FUNC2(void, glMultiTexCoord3fARB, glMultiTexCoord3f, "1.3", (int, float, float, float))
FUNC2(void, glActiveTextureARB, glActiveTexture, "1.3", (int))
FUNC2(void, glClientActiveTextureARB, glClientActiveTexture, "1.3", (int))
// GL_EXT_blend_color / GL1.4 (optional in 1.2):
FUNC2(void, glBlendColorEXT, glBlendColor, "1.4", (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha))
// GL_ARB_vertex_buffer_object / GL1.5:
FUNC2(void, glBindBufferARB, glBindBuffer, "1.5", (int target, GLuint buffer))
FUNC2(void, glDeleteBuffersARB, glDeleteBuffers, "1.5", (GLsizei n, const GLuint* buffers))
FUNC2(void, glGenBuffersARB, glGenBuffers, "1.5", (GLsizei n, GLuint* buffers))
FUNC2(bool, glIsBufferARB, glIsBuffer, "1.5", (GLuint buffer))
FUNC2(void, glBufferDataARB, glBufferData, "1.5", (int target, GLsizeiptrARB size, const void* data, int usage))
FUNC2(void, glBufferSubDataARB, glBufferSubData, "1.5", (int target, GLintptrARB offset, GLsizeiptrARB size, const void* data))
FUNC2(void, glGetBufferSubDataARB, glGetBufferSubData, "1.5", (int target, GLintptrARB offset, GLsizeiptrARB size, void* data))
FUNC2(void*, glMapBufferARB, glMapBuffer, "1.5", (int target, int access))
FUNC2(bool, glUnmapBufferARB, glUnmapBuffer, "1.5", (int target))
FUNC2(void, glGetBufferParameterivARB, glGetBufferParameteriv, "1.5", (int target, int pname, int* params))
FUNC2(void, glGetBufferPointervARB, glGetBufferPointerv, "1.5", (int target, int pname, void** params))
// GL_ARB_texture_compression / GL1.3
FUNC2(void, glCompressedTexImage3DARB, glCompressedTexImage3D, "1.3", (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*))
FUNC2(void, glCompressedTexImage2DARB, glCompressedTexImage2D, "1.3", (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*))
FUNC2(void, glCompressedTexImage1DARB, glCompressedTexImage1D, "1.3", (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid*))
FUNC2(void, glCompressedTexSubImage3DARB, glCompressedTexSubImage3D, "1.3", (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*))
FUNC2(void, glCompressedTexSubImage2DARB, glCompressedTexSubImage2D, "1.3", (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*))
FUNC2(void, glCompressedTexSubImage1DARB, glCompressedTexSubImage1D, "1.3", (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid*))
FUNC2(void, glGetCompressedTexImageARB, glGetCompressedTexImage, "1.3", (GLenum, GLint, GLvoid*))
// GL_EXT_framebuffer_object
FUNC(GLboolean, glIsRenderbufferEXT, (GLuint renderbuffer))
FUNC(void, glBindRenderbufferEXT, (GLenum target, GLuint renderbuffer))
FUNC(void, glDeleteRenderbuffersEXT, (GLsizei n, const GLuint *renderbuffers))
FUNC(void, glGenRenderbuffersEXT, (GLsizei n, GLuint *renderbuffers))
FUNC(void, glRenderbufferStorageEXT, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height))
FUNC(void, glGetRenderbufferParameterivEXT, (GLenum target, GLenum pname, GLint *params))
FUNC(GLboolean, glIsFramebufferEXT, (GLuint framebuffer))
FUNC(void, glBindFramebufferEXT, (GLenum target, GLuint framebuffer))
FUNC(void, glDeleteFramebuffersEXT, (GLsizei n, const GLuint *framebuffers))
FUNC(void, glGenFramebuffersEXT, (GLsizei n, GLuint *framebuffers))
FUNC(GLenum, glCheckFramebufferStatusEXT, (GLenum target))
FUNC(void, glFramebufferTexture1DEXT, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level))
FUNC(void, glFramebufferTexture2DEXT, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level))
FUNC(void, glFramebufferTexture3DEXT, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset))
FUNC(void, glFramebufferRenderbufferEXT, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer))
FUNC(void, glGetFramebufferAttachmentParameterivEXT, (GLenum target, GLenum attachment, GLenum pname, GLint *params))
FUNC(void, glGenerateMipmapEXT, (GLenum target))
// GL_ARB_vertex_program, GL_ARB_fragment_program
+FUNC(void, glProgramStringARB, (GLenum target, GLenum format, GLsizei len, const GLvoid *string))
+FUNC(void, glBindProgramARB, (GLenum target, GLuint program))
+FUNC(void, glDeleteProgramsARB, (GLsizei n, const GLuint *programs))
+FUNC(void, glGenProgramsARB, (GLsizei n, GLuint *programs))
+FUNC(void, glProgramEnvParameter4dARB, (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w))
+FUNC(void, glProgramEnvParameter4dvARB, (GLenum target, GLuint index, const GLdouble *params))
+FUNC(void, glProgramEnvParameter4fARB, (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w))
+FUNC(void, glProgramEnvParameter4fvARB, (GLenum target, GLuint index, const GLfloat *params))
+FUNC(void, glProgramLocalParameter4dARB, (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w))
+FUNC(void, glProgramLocalParameter4dvARB, (GLenum target, GLuint index, const GLdouble *params))
+FUNC(void, glProgramLocalParameter4fARB, (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w))
+FUNC(void, glProgramLocalParameter4fvARB, (GLenum target, GLuint index, const GLfloat *params))
+FUNC(void, glGetProgramEnvParameterdvARB, (GLenum target, GLuint index, GLdouble *params))
+FUNC(void, glGetProgramEnvParameterfvARB, (GLenum target, GLuint index, GLfloat *params))
+FUNC(void, glGetProgramLocalParameterdvARB, (GLenum target, GLuint index, GLdouble *params))
+FUNC(void, glGetProgramLocalParameterfvARB, (GLenum target, GLuint index, GLfloat *params))
FUNC(void, glGetProgramivARB, (GLenum target, GLenum pname, GLint *params))
+FUNC(void, glGetProgramStringARB, (GLenum target, GLenum pname, GLvoid *string))
+FUNC(GLboolean, glIsProgramARB, (GLuint program))
// GL_ARB_shader_objects
// (NOTE: Many of these have "Object" in their ARB names, but "Program" or "Shader" in their core names.
// When both Program and Shader versions exist, we use FUNC3 here and the engine must call the specific
// core name instead of the generic ARB name.)
FUNC3(void, glDeleteObjectARB, glDeleteShader, "2.0", (GLhandleARB obj))
FUNC3(void, glDeleteObjectARB, glDeleteProgram, "2.0", (GLhandleARB obj))
// FUNC2(GLhandleARB, glGetHandleARB, glGetHandle, "2.0", (GLenum pname))
// there is no analog to the ARB function in GL 2.0 (the functionality is probably moved into glGetIntegerv(GL_CURRENT_PROGRAM))
// so we can't represent it in this FUNC2 system, so just pretend it doesn't exist
FUNC2(void, glDetachObjectARB, glDetachShader, "2.0", (GLhandleARB containerObj, GLhandleARB attachedObj))
FUNC2(GLhandleARB, glCreateShaderObjectARB, glCreateShader, "2.0", (GLenum shaderType))
FUNC2(void, glShaderSourceARB, glShaderSource, "2.0", (GLhandleARB shaderObj, GLsizei count, const char **string, const GLint *length))
FUNC2(void, glCompileShaderARB, glCompileShader, "2.0", (GLhandleARB shaderObj))
FUNC2(GLhandleARB, glCreateProgramObjectARB, glCreateProgram, "2.0", (void))
FUNC2(void, glAttachObjectARB, glAttachShader, "2.0", (GLhandleARB containerObj, GLhandleARB obj))
FUNC2(void, glLinkProgramARB, glLinkProgram, "2.0", (GLhandleARB programObj))
FUNC2(void, glUseProgramObjectARB, glUseProgram, "2.0", (GLhandleARB programObj))
FUNC2(void, glValidateProgramARB, glValidateProgram, "2.0", (GLhandleARB programObj))
FUNC2(void, glUniform1fARB, glUniform1f, "2.0", (GLint location, GLfloat v0))
FUNC2(void, glUniform2fARB, glUniform2f, "2.0", (GLint location, GLfloat v0, GLfloat v1))
FUNC2(void, glUniform3fARB, glUniform3f, "2.0", (GLint location, GLfloat v0, GLfloat v1, GLfloat v2))
FUNC2(void, glUniform4fARB, glUniform4f, "2.0", (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3))
FUNC2(void, glUniform1iARB, glUniform1i, "2.0", (GLint location, GLint v0))
FUNC2(void, glUniform2iARB, glUniform2i, "2.0", (GLint location, GLint v0, GLint v1))
FUNC2(void, glUniform3iARB, glUniform3i, "2.0", (GLint location, GLint v0, GLint v1, GLint v2))
FUNC2(void, glUniform4iARB, glUniform4i, "2.0", (GLint location, GLint v0, GLint v1, GLint v2, GLint v3))
FUNC2(void, glUniform1fvARB, glUniform1fv, "2.0", (GLint location, GLsizei count, const GLfloat *value))
FUNC2(void, glUniform2fvARB, glUniform2fv, "2.0", (GLint location, GLsizei count, const GLfloat *value))
FUNC2(void, glUniform3fvARB, glUniform3fv, "2.0", (GLint location, GLsizei count, const GLfloat *value))
FUNC2(void, glUniform4fvARB, glUniform4fv, "2.0", (GLint location, GLsizei count, const GLfloat *value))
FUNC2(void, glUniform1ivARB, glUniform1iv, "2.0", (GLint location, GLsizei count, const GLint *value))
FUNC2(void, glUniform2ivARB, glUniform2iv, "2.0", (GLint location, GLsizei count, const GLint *value))
FUNC2(void, glUniform3ivARB, glUniform3iv, "2.0", (GLint location, GLsizei count, const GLint *value))
FUNC2(void, glUniform4ivARB, glUniform4iv, "2.0", (GLint location, GLsizei count, const GLint *value))
FUNC2(void, glUniformMatrix2fvARB, glUniformMatrix2fv, "2.0", (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value))
FUNC2(void, glUniformMatrix3fvARB, glUniformMatrix3fv, "2.0", (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value))
FUNC2(void, glUniformMatrix4fvARB, glUniformMatrix4fv, "2.0", (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value))
FUNC3(void, glGetObjectParameterfvARB, glGetProgramfv, "2.0", (GLhandleARB obj, GLenum pname, GLfloat *params))
FUNC3(void, glGetObjectParameterfvARB, glGetShaderfv, "2.0", (GLhandleARB obj, GLenum pname, GLfloat *params))
FUNC3(void, glGetObjectParameterivARB, glGetProgramiv, "2.0", (GLhandleARB obj, GLenum pname, GLint *params))
FUNC3(void, glGetObjectParameterivARB, glGetShaderiv, "2.0", (GLhandleARB obj, GLenum pname, GLint *params))
FUNC3(void, glGetInfoLogARB, glGetProgramInfoLog, "2.0", (GLhandleARB obj, GLsizei maxLength, GLsizei *length, char *infoLog))
FUNC3(void, glGetInfoLogARB, glGetShaderInfoLog, "2.0", (GLhandleARB obj, GLsizei maxLength, GLsizei *length, char *infoLog))
FUNC2(void, glGetAttachedObjectsARB, glGetAttachedShaders, "2.0", (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj))
FUNC2(GLint, glGetUniformLocationARB, glGetUniformLocation, "2.0", (GLhandleARB programObj, const char *name))
FUNC2(void, glGetActiveUniformARB, glGetActiveUniform, "2.0", (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, char *name))
FUNC2(void, glGetUniformfvARB, glGetUniformfv, "2.0", (GLhandleARB programObj, GLint location, GLfloat *params))
FUNC2(void, glGetUniformivARB, glGetUniformiv, "2.0", (GLhandleARB programObj, GLint location, GLint *params))
FUNC2(void, glGetShaderSourceARB, glGetShaderSource, "2.0", (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source))
// GL_ARB_vertex_shader
FUNC2(void, glVertexAttrib1fARB, glVertexAttrib1f, "2.0", (GLuint index, GLfloat v0))
FUNC2(void, glVertexAttrib1sARB, glVertexAttrib1s, "2.0", (GLuint index, GLshort v0))
FUNC2(void, glVertexAttrib1dARB, glVertexAttrib1d, "2.0", (GLuint index, GLdouble v0))
FUNC2(void, glVertexAttrib2fARB, glVertexAttrib2f, "2.0", (GLuint index, GLfloat v0, GLfloat v1))
FUNC2(void, glVertexAttrib2sARB, glVertexAttrib2s, "2.0", (GLuint index, GLshort v0, GLshort v1))
FUNC2(void, glVertexAttrib2dARB, glVertexAttrib2d, "2.0", (GLuint index, GLdouble v0, GLdouble v1))
FUNC2(void, glVertexAttrib3fARB, glVertexAttrib3f, "2.0", (GLuint index, GLfloat v0, GLfloat v1, GLfloat v2))
FUNC2(void, glVertexAttrib3sARB, glVertexAttrib3s, "2.0", (GLuint index, GLshort v0, GLshort v1, GLshort v2))
FUNC2(void, glVertexAttrib3dARB, glVertexAttrib3d, "2.0", (GLuint index, GLdouble v0, GLdouble v1, GLdouble v2))
FUNC2(void, glVertexAttrib4fARB, glVertexAttrib4f, "2.0", (GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3))
FUNC2(void, glVertexAttrib4sARB, glVertexAttrib4s, "2.0", (GLuint index, GLshort v0, GLshort v1, GLshort v2, GLshort v3))
FUNC2(void, glVertexAttrib4dARB, glVertexAttrib4d, "2.0", (GLuint index, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3))
FUNC2(void, glVertexAttrib4NubARB, glVertexAttrib4Nub, "2.0", (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w))
FUNC2(void, glVertexAttrib1fvARB, glVertexAttrib1fv, "2.0", (GLuint index, const GLfloat *v))
FUNC2(void, glVertexAttrib1svARB, glVertexAttrib1sv, "2.0", (GLuint index, const GLshort *v))
FUNC2(void, glVertexAttrib1dvARB, glVertexAttrib1dv, "2.0", (GLuint index, const GLdouble *v))
FUNC2(void, glVertexAttrib2fvARB, glVertexAttrib2fv, "2.0", (GLuint index, const GLfloat *v))
FUNC2(void, glVertexAttrib2svARB, glVertexAttrib2sv, "2.0", (GLuint index, const GLshort *v))
FUNC2(void, glVertexAttrib2dvARB, glVertexAttrib2dv, "2.0", (GLuint index, const GLdouble *v))
FUNC2(void, glVertexAttrib3fvARB, glVertexAttrib3fv, "2.0", (GLuint index, const GLfloat *v))
FUNC2(void, glVertexAttrib3svARB, glVertexAttrib3sv, "2.0", (GLuint index, const GLshort *v))
FUNC2(void, glVertexAttrib3dvARB, glVertexAttrib3dv, "2.0", (GLuint index, const GLdouble *v))
FUNC2(void, glVertexAttrib4fvARB, glVertexAttrib4fv, "2.0", (GLuint index, const GLfloat *v))
FUNC2(void, glVertexAttrib4svARB, glVertexAttrib4sv, "2.0", (GLuint index, const GLshort *v))
FUNC2(void, glVertexAttrib4dvARB, glVertexAttrib4dv, "2.0", (GLuint index, const GLdouble *v))
FUNC2(void, glVertexAttrib4ivARB, glVertexAttrib4iv, "2.0", (GLuint index, const GLint *v))
FUNC2(void, glVertexAttrib4bvARB, glVertexAttrib4bv, "2.0", (GLuint index, const GLbyte *v))
FUNC2(void, glVertexAttrib4ubvARB, glVertexAttrib4ubv, "2.0", (GLuint index, const GLubyte *v))
FUNC2(void, glVertexAttrib4usvARB, glVertexAttrib4usv, "2.0", (GLuint index, const GLushort *v))
FUNC2(void, glVertexAttrib4uivARB, glVertexAttrib4uiv, "2.0", (GLuint index, const GLuint *v))
FUNC2(void, glVertexAttrib4NbvARB, glVertexAttrib4Nbv, "2.0", (GLuint index, const GLbyte *v))
FUNC2(void, glVertexAttrib4NsvARB, glVertexAttrib4Nsv, "2.0", (GLuint index, const GLshort *v))
FUNC2(void, glVertexAttrib4NivARB, glVertexAttrib4Niv, "2.0", (GLuint index, const GLint *v))
FUNC2(void, glVertexAttrib4NubvARB, glVertexAttrib4Nubv, "2.0", (GLuint index, const GLubyte *v))
FUNC2(void, glVertexAttrib4NusvARB, glVertexAttrib4Nusv, "2.0", (GLuint index, const GLushort *v))
FUNC2(void, glVertexAttrib4NuivARB, glVertexAttrib4Nuiv, "2.0", (GLuint index, const GLuint *v))
FUNC2(void, glVertexAttribPointerARB, glVertexAttribPointer, "2.0", (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer))
FUNC2(void, glEnableVertexAttribArrayARB, glEnableVertexAttribArray, "2.0", (GLuint index))
FUNC2(void, glDisableVertexAttribArrayARB, glDisableVertexAttribArray, "2.0", (GLuint index))
FUNC2(void, glBindAttribLocationARB, glBindAttribLocation, "2.0", (GLhandleARB programObj, GLuint index, const char *name))
FUNC2(void, glGetActiveAttribARB, glGetActiveAttrib, "2.0", (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, int *size, GLenum *type, char *name))
FUNC2(GLint, glGetAttribLocationARB, glGetAttribLocation, "2.0", (GLhandleARB programObj, const char *name))
FUNC2(void, glGetVertexAttribdvARB, glGetVertexAttribdv, "2.0", (GLuint index, GLenum pname, GLdouble *params))
FUNC2(void, glGetVertexAttribfvARB, glGetVertexAttribfv, "2.0", (GLuint index, GLenum pname, GLfloat *params))
FUNC2(void, glGetVertexAttribivARB, glGetVertexAttribiv, "2.0", (GLuint index, GLenum pname, GLint *params))
FUNC2(void, glGetVertexAttribPointervARB, glGetVertexAttribPointerv, "2.0", (GLuint index, GLenum pname, void **pointer))
#if OS_WIN
// WGL_EXT_swap_control
FUNC(int, wglSwapIntervalEXT, (int))
// WGL_ARB_pbuffer
FUNC(HPBUFFERARB, wglCreatePbufferARB, (HDC, int, int, int, const int*))
FUNC(HDC, wglGetPbufferDCARB, (HPBUFFERARB))
FUNC(int, wglReleasePbufferDCARB, (HPBUFFERARB, HDC))
FUNC(int, wglDestroyPbufferARB, (HPBUFFERARB))
FUNC(int, wglQueryPbufferARB, (HPBUFFERARB, int, int*))
// GL_ARB_pixel_format
FUNC(int, wglGetPixelFormatAttribivARB, (HDC, int, int, unsigned int, const int*, int*))
FUNC(int, wglGetPixelFormatAttribfvARB, (HDC, int, int, unsigned int, const int*, float*))
FUNC(int, wglChoosePixelFormatARB, (HDC, const int *, const float*, unsigned int, int*, unsigned int*))
// GL_GREMEDY_string_marker (from gDEBugger)
FUNC(int, glStringMarkerGREMEDY, (GLsizei len, const GLvoid *string))
#endif // OS_WIN
Index: ps/trunk/source/renderer/PatchRData.h
===================================================================
--- ps/trunk/source/renderer/PatchRData.h (revision 9122)
+++ ps/trunk/source/renderer/PatchRData.h (revision 9123)
@@ -1,131 +1,131 @@
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#ifndef INCLUDED_PATCHRDATA
#define INCLUDED_PATCHRDATA
#include
#include "graphics/SColor.h"
#include "maths/Vector3D.h"
#include "graphics/RenderableObject.h"
#include "VertexBufferManager.h"
class CPatch;
class CTerrainTextureEntry;
//////////////////////////////////////////////////////////////////////////////////////////////////
// CPatchRData: class encapsulating logic for rendering terrain patches; holds per
// patch data, plus some supporting static functions for batching, etc
class CPatchRData : public CRenderData
{
public:
CPatchRData(CPatch* patch);
~CPatchRData();
void Update();
void RenderOutline();
void RenderSides();
void RenderPriorities();
static void RenderBases(const std::vector& patches);
static void RenderBlends(const std::vector& patches);
static void RenderStreams(const std::vector& patches, int streamflags);
CPatch* GetPatch() { return m_Patch; }
private:
struct SSplat {
SSplat() : m_Texture(0), m_IndexCount(0) {}
// texture to apply during splat
CTerrainTextureEntry* m_Texture;
// offset into the index array for this patch where splat starts
size_t m_IndexStart;
// number of indices used by splat
size_t m_IndexCount;
};
struct SBaseVertex {
// vertex position
CVector3D m_Position;
// diffuse color from sunlight
SColor4ub m_DiffuseColor;
// vertex uvs for base texture
float m_UVs[2];
// add some padding since VBOs prefer power-of-two sizes
u32 m_Padding[2];
};
cassert(sizeof(SBaseVertex) == 32);
struct SSideVertex {
// vertex position
CVector3D m_Position;
// add some padding
u32 m_Padding[1];
};
cassert(sizeof(SSideVertex) == 16);
struct SBlendVertex {
// vertex position
CVector3D m_Position;
+ // diffuse color from sunlight
+ SColor4ub m_DiffuseColor;
// vertex uvs for base texture
float m_UVs[2];
// vertex uvs for alpha texture
float m_AlphaUVs[2];
- // add some padding
- u32 m_Padding[1];
};
cassert(sizeof(SBlendVertex) == 32);
// build this renderdata object
void Build();
void AddBlend(std::vector& blendVertices, std::vector& blendIndices, u16 i, u16 j, u8 shape);
void BuildBlends();
void BuildIndices();
void BuildVertices();
void BuildSides();
void BuildSide(std::vector& vertices, CPatchSideFlags side);
// owner patch
CPatch* m_Patch;
// vertex buffer handle for side vertices
CVertexBuffer::VBChunk* m_VBSides;
// vertex buffer handle for base vertices
CVertexBuffer::VBChunk* m_VBBase;
// vertex buffer handle for base vertex indices
CVertexBuffer::VBChunk* m_VBBaseIndices;
// vertex buffer handle for blend vertices
CVertexBuffer::VBChunk* m_VBBlends;
// vertex buffer handle for blend vertex indices
CVertexBuffer::VBChunk* m_VBBlendIndices;
// list of base splats to apply to this patch
std::vector m_Splats;
// splats used in blend pass
std::vector m_BlendSplats;
};
#endif
Index: ps/trunk/source/renderer/DecalRData.h
===================================================================
--- ps/trunk/source/renderer/DecalRData.h (revision 9122)
+++ ps/trunk/source/renderer/DecalRData.h (revision 9123)
@@ -1,48 +1,49 @@
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#ifndef INCLUDED_DECALRDATA
#define INCLUDED_DECALRDATA
#include "graphics/RenderableObject.h"
#include "renderer/VertexArray.h"
class CModelDecal;
class CDecalRData : public CRenderData
{
public:
CDecalRData(CModelDecal* decal);
~CDecalRData();
void Update();
void Render();
private:
void BuildArrays();
VertexIndexArray m_IndexArray;
VertexArray m_Array;
VertexArray::Attribute m_Position;
+ VertexArray::Attribute m_DiffuseColor;
VertexArray::Attribute m_UV;
CModelDecal* m_Decal;
};
#endif // INCLUDED_DECALRDATA
Index: ps/trunk/source/renderer/Renderer.cpp
===================================================================
--- ps/trunk/source/renderer/Renderer.cpp (revision 9122)
+++ ps/trunk/source/renderer/Renderer.cpp (revision 9123)
@@ -1,1851 +1,2122 @@
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
/*
* higher level interface on top of OpenGL to render basic objects:
* terrain, models, sprites, particles etc.
*/
#include "precompiled.h"
#include