diff --git a/mk/linux/Jamfile b/mk/linux/Jamfile new file mode 100644 index 000000000..f9cddf447 --- /dev/null +++ b/mk/linux/Jamfile @@ -0,0 +1,101 @@ +SubDir TOP ; + +UseAutoconf ; + +Package license.txt readme.txt ; + +#### Library #### +SubDir TOP shared_lib sources ; + +LIB_DIRS = + platform/sdl + platform/posix + util + graphics + graphics/gl + sound + sound/openal + xml + glew + lua +; +LIB_INCLUDE_DIRS = ../include/$(LIB_DIRS) ; + +for i in $(LIB_DIRS) { + LIB_SOURCES += [ Wildcard $(i) : *.c *.cpp *.h ] ; +} + +Library glestlib : $(LIB_SOURCES) ; +ExternalLibs glestlib : SDL GL GLU XERCES VORBIS VORBISFILE OGG OPENAL LUA ; +IncludeDir glestlib : $(LIB_INCLUDE_DIRS) ; + +#### Game #### +SubDir TOP glest_game ; + +GLEST_DIRS = + . + ai + facilities + game + global + graphics + gui + main + menu + network + sound + type_instances + types + world +; + +for i in $(GLEST_DIRS) { + GLEST_SOURCES += [ Wildcard $(i) : *.cpp *.h ] ; +} + +Application glest.bin : $(GLEST_SOURCES) ; +LinkWith glest.bin : glestlib ; +ExternalLibs glest.bin : SDL GL GLU XERCES VORBIS VORBISFILE OGG OPENAL LUA ; +IncludeDir glest.bin : ../shared_lib/include/$(LIB_INCLUDE_DIRS) $(GLEST_DIRS) ; + +#### Editor #### +if $(WX_AVAILABLE) = "yes" { + SubDir TOP glest_map_editor ; + + GLEST_MAP_DIRS = . ; + for i in $(GLEST_DIRS) { + GLEST_MAP_SOURCES += [ Wildcard $(i) : *.cpp *.h ] ; + } + + Application glest_editor : $(GLEST_MAP_SOURCES) ; + LinkWith glest_editor : glestlib ; + ExternalLibs glest_editor : SDL GL GLU XERCES VORBIS VORBISFILE OGG OPENAL WX ; + IncludeDir glest_editor : ../shared_lib/include/$(LIB_INCLUDE_DIRS) $(GLEST_MAP_DIRS) ; +} + +### Viewer ### + SubDir TOP g3d_viewer ; + + GLEST_VIEWER_DIRS = . ; + for i in $(GLEST_DIRS) { + GLEST_VIEWER_SOURCES += [ Wildcard $(i) : *.cpp *.h ] ; + } + + Application glest_g3dviewer : $(GLEST_VIEWER_SOURCES) ; + LinkWith glest_g3dviewer : glestlib ; + ExternalLibs glest_g3dviewer : SDL GL GLU WX ; + IncludeDir glest_g3dviewer : ../shared_lib/include/$(LIB_INCLUDE_DIRS) $(GLEST_VIEWER_DIRS) ; + +### Configurator ### + SubDir TOP configurator ; + + GLEST_CONFIG_DIRS = . ; + for i in $(GLEST_DIRS) { + GLEST_CONFIG_SOURCES += [ Wildcard $(i) : *.cpp *.h ] ; + } + + Application glest_configurator : $(GLEST_CONFIG_SOURCES) ; + LinkWith glest_configurator : glestlib ; + ExternalLibs glest_configurator : SDL GL GLU XERCES WX ; + IncludeDir glest_configurator : ../shared_lib/include/$(LIB_INCLUDE_DIRS) $(GLEST_CONFIG_DIRS) ; + diff --git a/mk/linux/configuration.xml b/mk/linux/configuration.xml new file mode 100644 index 000000000..613a9fd9f --- /dev/null +++ b/mk/linux/configuration.xml @@ -0,0 +1,368 @@ + + + + <file-name value="glest.ini"/> + <icon value="true" path="glest.ico"/> + <field-groups> + <field-group name="General"> + <field type="Int"> + <name value="Screen width"/> + <variable-name value="ScreenWidth"/> + <description value=""/> + <default value="1024"/> + </field> + <field type="Int"> + <name value="Screen height"/> + <variable-name value="ScreenHeight"/> + <description value=""/> + <default value="768"/> + </field> + <field type="Int"> + <name value="Refresh frequency"/> + <variable-name value="RefreshFrequency"/> + <description value=""/> + <default value="75"/> + </field> + <field type="Enum"> + <name value="Color bits"/> + <variable-name value="ColorBits"/> + <description value=""/> + <default value="32"/> + <enums> + <enum value="16"/> + <enum value="24"/> + <enum value="32"/> + </enums> + </field> + <field type="Enum"> + <name value="Windowed"/> + <variable-name value="Windowed"/> + <description value="Execute in a window"/> + <default value="0"/> + <enums> + <enum value="1"/> + <enum value="0"/> + </enums> + </field> + <field type="Enum"> + <name value="First time"/> + <variable-name value="FirstTime"/> + <description value=""/> + <default value="1"/> + <enums> + <enum value="1"/> + <enum value="0"/> + </enums> + </field> + <field type="FloatRange"> + <name value="Gameplay speed maximum"/> + <variable-name value="FastSpeedLoops"/> + <description value=""/> + <default value="2"/> + <min value="0"/> + <max value="20"/> + </field> + <field type="Enum"> + <name value="Fog of war enabled"/> + <variable-name value="FogOfWar"/> + <description value=""/> + <default value="1"/> + <enums> + <enum value="1"/> + <enum value="0"/> + </enums> + </field> + </field-group> + + <field-group name="Renderer"> + <field type="Enum"> + <name value="Renderer"/> + <variable-name value="FactoryGraphics"/> + <description value=""/> + <default value="OpenGL"/> + <enums> + <enum value="OpenGL"/> + <enum value="OpenGL2"/> + </enums> + </field> + <field type="Enum"> + <name value="Check OpenGL version on startup"/> + <variable-name value="CheckGlCaps"/> + <description value=""/> + <default value="1"/> + <enums> + <enum value="1"/> + <enum value="0"/> + </enums> + </field> + <field type="Enum"> + <name value="Filter"/> + <variable-name value="Filter"/> + <description value=""/> + <default value="Bilinear"/> + <enums> + <enum value="Bilinear"/> + <enum value="Trilinear"/> + </enums> + </field> + <field type="Enum"> + <name value="Depth bits"/> + <variable-name value="DepthBits"/> + <description value="Z buffer precision"/> + <default value="32"/> + <enums> + <enum value="16"/> + <enum value="24"/> + <enum value="32"/> + </enums> + </field> + <field type="Enum"> + <name value="3D textures"/> + <variable-name value="Textures3D"/> + <description value="If enabled, 3D textures are used for water + +animation, disable on old cards"/> + <default value="1"/> + <enums> + <enum value="1"/> + <enum value="0"/> + </enums> + </field> + <field type="Enum"> + <name value="Shadows"/> + <variable-name value="Shadows"/> + <description value="Projected shadows are fast but only create + +units and object shadows and in some cases are incorrect. Shadow mapping creates everything + +over everything shadows, but are slow and look aliased in some cards"/> + <default value="Projected"/> + <enums> + <enum value="Disabled"/> + <enum value="Projected"/> + <enum value="ShadowMapping"/> + </enums> + </field> + <field type="Enum"> + <name value="Shadow texture size"/> + <variable-name value="ShadowTextureSize"/> + <description value="Size of the texture used for projected + +shadows and shadow mapping, bigger sizes result in less pixelized shadows but are much slower"/> + <default value="512"/> + <enums> + <enum value="256"/> + <enum value="512"/> + </enums> + </field> + <field type="FloatRange"> + <name value="Shadow alpha"/> + <variable-name value="ShadowAlpha"/> + <description value="Shadow transparency"/> + <default value="0.2"/> + <min value="0"/> + <max value="1"/> + </field> + <field type="IntRange"> + <name value="Shadow frame skip"/> + <variable-name value="ShadowFrameSkip"/> + <description value=""/> + <default value="2"/> + <min value="0"/> + <max value="5"/> + </field> + <field type="FloatRange"> + <name value="Day time"/> + <variable-name value="DayTime"/> + <description value="Day/Night cycle duration, in seconds"/> + <default value="1000.00"/> + <min value="100"/> + <max value="2000"/> + </field> + <field type="IntRange"> + <name value="Maximum lights"/> + <variable-name value="MaxLights"/> + <description value=""/> + <default value="1"/> + <min value="1"/> + <max value="8"/> + </field> + <field type="Enum"> + <name value="Fog of war smoothing"/> + <variable-name value="FogOfWarSmoothing"/> + <description value=""/> + <default value="1"/> + <enums> + <enum value="1"/> + <enum value="0"/> + </enums> + </field> + <field type="IntRange"> + <name value="Fog of war sm. frame skip"/> + <variable-name value="FogOfWarSmoothingFrameSkip"/> + <description value=""/> + <default value="3"/> + <min value="0"/> + <max value="5"/> + </field> + </field-group> + + <field-group name="Audio"> + <field type="Enum"> + <name value="Sound factory"/> + <variable-name value="FactorySound"/> + <description value=""/> + <default value="OpenAL"/> + <enums> + <enum value="DirectSound8"/> + <enum value="OpenAL"/> + </enums> + </field> + <field type="IntRange"> + <name value="FX volume"/> + <variable-name value="SoundVolumeFx"/> + <description value=""/> + <default value="80"/> + <min value="0"/> + <max value="100"/> + </field> + <field type="IntRange"> + <name value="Music volume"/> + <variable-name value="SoundVolumeMusic"/> + <description value=""/> + <default value="90"/> + <min value="0"/> + <max value="100"/> + </field> + <field type="IntRange"> + <name value="Ambient volume"/> + <variable-name value="SoundVolumeAmbient"/> + <description value=""/> + <default value="80"/> + <min value="0"/> + <max value="100"/> + </field> + </field-group> + + <field-group name="GUI"> + <field type="String"> + <name value="Menu font"/> + <variable-name value="FontMenu"/> + <description value=""/> + <default value="Verdana"/> + </field> + <field type="String"> + <name value="Console font"/> + <variable-name value="FontConsole"/> + <description value=""/> + <default value="Verdana"/> + </field> + <field type="String"> + <name value="Display font"/> + <variable-name value="FontDisplay"/> + <description value=""/> + <default value="Verdana"/> + </field> + <field type="String"> + <name value="Language"/> + <variable-name value="Lang"/> + <description value=""/> + <default value="english"/> + </field> + <field type="Enum"> + <name value="Focus arrows"/> + <variable-name value="FocusArrows"/> + <description value="If enabled, arrows are displayed under units + +when they are issued a command"/> + <default value="1"/> + <enums> + <enum value="1"/> + <enum value="0"/> + </enums> + </field> + <field type="Enum"> + <name value="Disable ingame UI"/> + <variable-name value="PhotoMode"/> + <description value=""/> + <default value="0"/> + <enums> + <enum value="1"/> + <enum value="0"/> + </enums> + </field> + <field type="IntRange"> + <name value="Maximum console lines"/> + <variable-name value="ConsoleMaxLines"/> + <description value=""/> + <default value="10"/> + <min value="0"/> + <max value="50"/> + </field> + <field type="IntRange"> + <name value="Console text timeout"/> + <variable-name value="ConsoleTimeout"/> + <description value=""/> + <default value="20"/> + <min value="1"/> + <max value="50"/> + </field> + </field-group> + + <field-group name="Network"> + <field type="String"> + <name value="Server IP"/> + <variable-name value="ServerIp"/> + <description value=""/> + <default value="192.168.1.1"/> + </field> + <field type="Int"> + <name value="Server port"/> + <variable-name value="ServerPort"/> + <description value=""/> + <default value="6666"/> + </field> + <field type="Enum"> + <name value="Client data consistency checks"/> + <variable-name value="NetworkConsistencyChecks"/> + <description value=""/> + <default value="0"/> + <enums> + <enum value="1"/> + <enum value="0"/> + </enums> + </field> + </field-group> + + <field-group name="Advanced"> + <field type="Enum"> + <name value="Debug mode"/> + <variable-name value="DebugMode"/> + <description value=""/> + <default value="0"/> + <enums> + <enum value="1"/> + <enum value="0"/> + </enums> + </field> + <field type="IntRange"> + <name value="AI log"/> + <variable-name value="AiLog"/> + <description value=""/> + <default value="0"/> + <min value="0"/> + <max value="4"/> + </field> + <field type="Enum"> + <name value="AI log console redirection"/> + <variable-name value="AiRedir"/> + <description value=""/> + <default value="0"/> + <enums> + <enum value="1"/> + <enum value="0"/> + </enums> + </field> + </field-group> + </field-groups> +</configuration> diff --git a/source/configurator/configuration.cpp b/source/configurator/configuration.cpp new file mode 100644 index 000000000..8c583bd0b --- /dev/null +++ b/source/configurator/configuration.cpp @@ -0,0 +1,392 @@ +#include "configuration.h" + +#include <stdexcept> + +#include "xml_parser.h" +#include "util.h" +#include "properties.h" +#include "conversion.h" + +using namespace std; +using namespace Shared::Xml; +using namespace Shared::Util; + +namespace Configurator{ + +// =============================================== +// class Configuration +// =============================================== + + +Configuration::~Configuration(){ + for(int i= 0; i<fieldGroups.size(); ++i){ + delete fieldGroups[i]; + } +} + +void Configuration::load(const string &path){ + loadStructure(path); + loadValues(fileName); +} + +void Configuration::loadStructure(const string &path){ + + XmlTree xmlTree; + xmlTree.load(path); + + const XmlNode *configurationNode= xmlTree.getRootNode(); + + //title + title= configurationNode->getChild("title")->getAttribute("value")->getValue(); + + //fileName + fileName= configurationNode->getChild("file-name")->getAttribute("value")->getValue(); + + //icon + XmlNode *iconNode= configurationNode->getChild("icon"); + icon= iconNode->getAttribute("value")->getBoolValue(); + if(icon){ + iconPath= iconNode->getAttribute("path")->getValue(); + } + + const XmlNode *fieldGroupsNode= configurationNode->getChild("field-groups"); + + fieldGroups.resize(fieldGroupsNode->getChildCount()); + + for(int i=0; i<fieldGroups.size(); ++i){ + const XmlNode *fieldGroupNode= fieldGroupsNode->getChild("field-group", i); + FieldGroup *fieldGroup= new FieldGroup(); + fieldGroup->load(fieldGroupNode); + fieldGroups[i]= fieldGroup; + } +} + +void Configuration::loadValues(const string &path){ + Properties properties; + + properties.load(path); + + for(int i=0; i<fieldGroups.size(); ++i){ + FieldGroup *fg= fieldGroups[i]; + for(int j=0; j<fg->getFieldCount(); ++j){ + Field *f= fg->getField(j); + f->setValue(properties.getString(f->getVariableName())); + } + } +} + +void Configuration::save(){ + Properties properties; + + properties.load(fileName); + + for(int i=0; i<fieldGroups.size(); ++i){ + FieldGroup *fg= fieldGroups[i]; + for(int j=0; j<fg->getFieldCount(); ++j){ + Field *f= fg->getField(j); + f->updateValue(); + if(!f->isValueValid(f->getValue())){ + f->setValue(f->getDefaultValue()); + f->updateControl(); + } + properties.setString(f->getVariableName(), f->getValue()); + } + } + + properties.save(fileName); +} + +string Field::getInfo() const{ + return name+" (default: " + defaultValue + ")"; +} + +// =============================================== +// class FieldGroup +// =============================================== + +FieldGroup::~FieldGroup(){ + for(int i= 0; i<fields.size(); ++i){ + delete fields[i]; + } +} + +void FieldGroup::load(const XmlNode *groupNode){ + + name= groupNode->getAttribute("name")->getValue(); + + fields.resize(groupNode->getChildCount()); + for(int i=0; i<fields.size(); ++i){ + const XmlNode *fieldNode= groupNode->getChild("field", i); + + Field *f= newField(fieldNode->getAttribute("type")->getValue()); + + //name + const XmlNode *nameNode= fieldNode->getChild("name"); + f->setName(nameNode->getAttribute("value")->getValue()); + + //variableName + const XmlNode *variableNameNode= fieldNode->getChild("variable-name"); + f->setVariableName(variableNameNode->getAttribute("value")->getValue()); + + //description + const XmlNode *descriptionNode= fieldNode->getChild("description"); + f->setDescription(descriptionNode->getAttribute("value")->getValue()); + + //default + const XmlNode *defaultNode= fieldNode->getChild("default"); + f->setDefaultValue(defaultNode->getAttribute("value")->getValue()); + + f->loadSpecific(fieldNode); + + if(!f->isValueValid(f->getDefaultValue())){ + throw runtime_error("Default value not valid in field: " + f->getName()); + } + + fields[i]= f; + } +} + +Field *FieldGroup::newField(const string &type){ + if(type=="Bool"){ + return new BoolField(); + } + else if(type=="Int"){ + return new IntField(); + } + else if(type=="Float"){ + return new FloatField(); + } + else if(type=="String"){ + return new StringField(); + } + else if(type=="Enum"){ + return new EnumField(); + } + else if(type=="IntRange"){ + return new IntRangeField(); + } + else if(type=="FloatRange"){ + return new FloatRangeField(); + } + else{ + throw runtime_error("Unknown field type: " + type); + } +} + +// =============================================== +// class BoolField +// =============================================== + +void BoolField::createControl(wxWindow *parent, wxSizer *sizer){ + checkBox= new wxCheckBox(parent, -1, Configuration::ToUnicode("")); + checkBox->SetValue(strToBool(value)); + sizer->Add(checkBox); +} + +void BoolField::updateValue(){ + value= boolToStr(checkBox->GetValue()); +} + +void BoolField::updateControl(){ + checkBox->SetValue(strToBool(value)); +} + +bool BoolField::isValueValid(const string &value){ + try{ + strToBool(value); + } + catch(const exception &){ + return false; + } + return true; +} + +// =============================================== +// class IntField +// =============================================== + +void IntField::createControl(wxWindow *parent, wxSizer *sizer){ + textCtrl= new wxTextCtrl(parent, -1, Configuration::ToUnicode(value.c_str())); + sizer->Add(textCtrl); +} + +void IntField::updateValue(){ + value= (const char*)wxFNCONV(textCtrl->GetValue()); +} + +void IntField::updateControl(){ + textCtrl->SetValue(Configuration::ToUnicode(value.c_str())); +} + +bool IntField::isValueValid(const string &value){ + try{ + strToInt(value); + } + catch(const exception &){ + return false; + } + return true; +} + +// =============================================== +// class FloatField +// =============================================== + +void FloatField::createControl(wxWindow *parent, wxSizer *sizer){ + textCtrl= new wxTextCtrl(parent, -1, Configuration::ToUnicode(value.c_str())); + sizer->Add(textCtrl); +} + +void FloatField::updateValue(){ + value= (const char*)wxFNCONV(textCtrl->GetValue()); +} + +void FloatField::updateControl(){ + textCtrl->SetValue(Configuration::ToUnicode(value.c_str())); +} + +bool FloatField::isValueValid(const string &value){ + try{ + strToFloat(value); + } + catch(const exception &){ + return false; + } + return true; +} + +// =============================================== +// class StringField +// =============================================== + +void StringField::createControl(wxWindow *parent, wxSizer *sizer){ + textCtrl= new wxTextCtrl(parent, -1, Configuration::ToUnicode(value.c_str())); + textCtrl->SetSize(wxSize(3*textCtrl->GetSize().x/2, textCtrl->GetSize().y)); + sizer->Add(textCtrl); +} + +void StringField::updateValue(){ + value= (const char*)wxFNCONV(textCtrl->GetValue()); +} + +void StringField::updateControl(){ + textCtrl->SetValue(Configuration::ToUnicode(value.c_str())); +} + +bool StringField::isValueValid(const string &value){ + return true; +} + +// =============================================== +// class EnumField +// =============================================== + +void EnumField::createControl(wxWindow *parent, wxSizer *sizer){ + comboBox= new wxComboBox(parent, -1, Configuration::ToUnicode(""), wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY); + for(int i=0; i<enumerants.size(); ++i){ + comboBox->Append(Configuration::ToUnicode(enumerants[i].c_str())); + } + comboBox->SetValue(Configuration::ToUnicode(value.c_str())); + sizer->Add(comboBox); +} + +void EnumField::updateValue(){ + value= (const char*)wxFNCONV(comboBox->GetValue()); +} + +void EnumField::updateControl(){ + comboBox->SetValue(Configuration::ToUnicode(value.c_str())); +} + +bool EnumField::isValueValid(const string &value){ + return true; +} + +void EnumField::loadSpecific(const XmlNode *fieldNode){ + const XmlNode *enumsNode= fieldNode->getChild("enums"); + for(int i=0; i<enumsNode->getChildCount(); ++i){ + const XmlNode *enumNode= enumsNode->getChild("enum", i); + enumerants.push_back(enumNode->getAttribute("value")->getValue()); + } +}; + +// =============================================== +// class IntRange +// =============================================== + +void IntRangeField::createControl(wxWindow *parent, wxSizer *sizer){ + slider= new wxSlider(parent, -1, strToInt(value), min, max, wxDefaultPosition, wxDefaultSize, wxSL_LABELS); + sizer->Add(slider); +} + +void IntRangeField::updateValue(){ + value= intToStr(slider->GetValue()); +} + +void IntRangeField::updateControl(){ + slider->SetValue(strToInt(value)); +} + +bool IntRangeField::isValueValid(const string &value){ + try{ + strToInt(value); + } + catch(const exception &){ + return false; + } + return true; +} + +void IntRangeField::loadSpecific(const XmlNode *fieldNode){ + const XmlNode *minNode= fieldNode->getChild("min"); + min= strToInt(minNode->getAttribute("value")->getValue()); + + const XmlNode *maxNode= fieldNode->getChild("max"); + max= strToInt(maxNode->getAttribute("value")->getValue()); +} + +string IntRangeField::getInfo() const{ + return name + " (min: " + intToStr(min)+ ", max: " + intToStr(max) + ", default: " + defaultValue + ")"; +} + +// =============================================== +// class FloatRangeField +// =============================================== + +void FloatRangeField::createControl(wxWindow *parent, wxSizer *sizer){ + textCtrl= new wxTextCtrl(parent, -1, Configuration::ToUnicode(value.c_str())); + sizer->Add(textCtrl); +} + +void FloatRangeField::updateValue(){ + value= (const char*)wxFNCONV(textCtrl->GetValue()); +} + +void FloatRangeField::updateControl(){ + textCtrl->SetValue(Configuration::ToUnicode(value.c_str())); +} + +bool FloatRangeField::isValueValid(const string &value){ + try{ + float f= strToFloat(value); + return f>=min && f<=max; + } + catch(const exception &){ + return false; + } + return true; +} + +void FloatRangeField::loadSpecific(const XmlNode *fieldNode){ + const XmlNode *minNode= fieldNode->getChild("min"); + min= strToFloat(minNode->getAttribute("value")->getValue()); + + const XmlNode *maxNode= fieldNode->getChild("max"); + max= strToFloat(maxNode->getAttribute("value")->getValue()); +}; + +string FloatRangeField::getInfo() const{ + return name + " (min: " + floatToStr(min)+ ", max: " + floatToStr(max) + ", default: " + defaultValue + ")"; +} + +}//end namespace diff --git a/source/configurator/configuration.h b/source/configurator/configuration.h new file mode 100644 index 000000000..60359d225 --- /dev/null +++ b/source/configurator/configuration.h @@ -0,0 +1,250 @@ +#ifndef _CONFIGURATOR_CONFIGURATION_H_ +#define _CONFIGURATOR_CONFIGURATION_H_ + +#include <string> +#include <vector> + +#include <wx/wx.h> + +#include "xml_parser.h" + +using std::string; +using std::vector; + +using Shared::Xml::XmlNode; + +namespace Configurator{ + +// =============================================== +// class Global functions +// =============================================== + +class Field; +class FieldGroup; + +// =============================== +// class Configuration +// =============================== + +class Configuration{ +public: + typedef vector<FieldGroup*> FieldGroups; + +private: + string title; + string fileName; + bool icon; + string iconPath; + FieldGroups fieldGroups; + +public: + ~Configuration(); + + void load(const string &path); + + void loadStructure(const string &path); + void loadValues(const string &path); + + void save(); + + const string &getTitle() const {return title;} + const string &getFileName() const {return fileName;} + bool getIcon() const {return icon;} + const string &getIconPath() const {return iconPath;} + + int getFieldGroupCount() const {return fieldGroups.size();} + FieldGroup *getFieldGroup(int i) const {return fieldGroups[i];} + + static wxString ToUnicode(const char* str) { + return wxString(str, wxConvUTF8); + } + + static wxString ToUnicode(const string& str) { + return wxString(str.c_str(), wxConvUTF8); + } + +}; + +// =============================== +// class FieldGroup +// =============================== + +class FieldGroup{ +public: + typedef vector<Field*> Fields; + +private: + Fields fields; + string name; + +public: + ~FieldGroup(); + + int getFieldCount() const {return fields.size();} + Field *getField(int i) const {return fields[i];} + const string &getName() const {return name;} + + void load(const XmlNode *groupNode); + +private: + Field *newField(const string &type); +}; + +// =============================== +// class Field +// =============================== + +class Field{ +protected: + string name; + string variableName; + string description; + string value; + string defaultValue; + +public: + virtual ~Field() {}; + + const string &getName() const {return name;} + const string &getVariableName() const {return variableName;} + const string &getDescription() const {return description;} + const string &getValue() const {return value;} + const string &getDefaultValue() const {return defaultValue;} + + void setName(const string &name) {this->name= name;} + void setVariableName(const string &variableName) {this->variableName= variableName;} + void setDescription(const string &description) {this->description= description;} + void setValue(const string &value) {this->value= value;} + void setDefaultValue(const string &defaultValue) {this->defaultValue= defaultValue;} + + virtual void loadSpecific(const XmlNode *fieldNode){}; + virtual string getInfo() const; + + virtual void createControl(wxWindow *parent, wxSizer *sizer)= 0; + virtual void updateValue()= 0; + virtual void updateControl()= 0; + virtual bool isValueValid(const string &value)= 0; +}; + +// =============================== +// class BoolField +// =============================== + +class BoolField: public Field{ +private: + wxCheckBox *checkBox; + +public: + virtual void createControl(wxWindow *parent, wxSizer *sizer); + virtual void updateValue(); + virtual void updateControl(); + virtual bool isValueValid(const string &value); +}; + +// =============================== +// class IntField +// =============================== + +class IntField: public Field{ +private: + wxTextCtrl *textCtrl; + +public: + virtual void createControl(wxWindow *parent, wxSizer *sizer); + virtual void updateValue(); + virtual void updateControl(); + virtual bool isValueValid(const string &value); +}; + +// =============================== +// class FloatField +// =============================== + +class FloatField: public Field{ +private: + wxTextCtrl *textCtrl; + +public: + virtual void createControl(wxWindow *parent, wxSizer *sizer); + virtual void updateValue(); + virtual void updateControl(); + virtual bool isValueValid(const string &value); +}; + +// =============================== +// class StringField +// =============================== + +class StringField: public Field{ +private: + wxTextCtrl *textCtrl; + +public: + virtual void createControl(wxWindow *parent, wxSizer *sizer); + virtual void updateValue(); + virtual void updateControl(); + virtual bool isValueValid(const string &value); +}; + +// =============================== +// class EnumField +// =============================== + +class EnumField: public Field{ +private: + wxComboBox *comboBox; + vector<string> enumerants; + +public: + virtual void createControl(wxWindow *parent, wxSizer *sizer); + virtual void updateValue(); + virtual void updateControl(); + virtual bool isValueValid(const string &value); + + virtual void loadSpecific(const XmlNode *fieldNode); +}; + +// =============================== +// class IntRangeField +// =============================== + +class IntRangeField: public Field{ +private: + wxSlider *slider; + int min; + int max; + +public: + virtual void createControl(wxWindow *parent, wxSizer *sizer); + virtual void updateValue(); + virtual void updateControl(); + virtual bool isValueValid(const string &value); + + virtual void loadSpecific(const XmlNode *fieldNode); + virtual string getInfo() const; +}; + +// =============================== +// class FloatRangeField +// =============================== + +class FloatRangeField: public Field{ +private: + wxTextCtrl *textCtrl; + float min; + float max; + +public: + virtual void createControl(wxWindow *parent, wxSizer *sizer); + virtual void updateValue(); + virtual void updateControl(); + virtual bool isValueValid(const string &value); + + virtual void loadSpecific(const XmlNode *fieldNode); + virtual string getInfo() const; +}; + + +}//end namespace + +#endif diff --git a/source/configurator/main.cpp b/source/configurator/main.cpp new file mode 100644 index 000000000..940f9d688 --- /dev/null +++ b/source/configurator/main.cpp @@ -0,0 +1,210 @@ +#include "main.h" + +#include <stdexcept> + +#include <wx/wx.h> +#include <wx/sizer.h> +#include <wx/image.h> +#include <wx/bitmap.h> +#include <wx/icon.h> + +using namespace std; + +namespace Configurator{ + +// =============================================== +// class MainWindow +// =============================================== + + +const int MainWindow::margin= 10; +const int MainWindow::panelMargin= 20; +const int MainWindow::gridMarginHorizontal= 30; + +const string MainWindow::versionString= "v1.3.5-beta1"; +const string MainWindow::winHeader= "Mega-Glest config " + versionString + " - Built: " + __DATE__; + +MainWindow::MainWindow() : + wxFrame( + NULL, -1, Configuration::ToUnicode(winHeader), + wxDefaultPosition, wxSize(800, 600)){ + + SetExtraStyle(wxFRAME_EX_CONTEXTHELP); + + configuration.load("configuration.xml"); + + //Create(NULL, -1, "", wxDefaultPosition, wxDefaultSize, wxCAPTION | wxSYSTEM_MENU); + + SetTitle(Configuration::ToUnicode(("Configurator - " + configuration.getTitle() + " - Editing " + configuration.getFileName()).c_str())); + + if(configuration.getIcon()){ + + printf("In [%s::%s] icon = [%s]\n",__FILE__,__FUNCTION__,configuration.getIconPath().c_str()); + + wxInitAllImageHandlers(); + wxIcon icon; + icon.LoadFile(Configuration::ToUnicode(configuration.getIconPath().c_str()), wxBITMAP_TYPE_ICO); + SetIcon(icon); + } + + notebook= new wxNotebook(this, -1); + + wxSizer *mainSizer= new wxBoxSizer(wxVERTICAL); + wxSizer *topSizer= new wxBoxSizer(wxHORIZONTAL); + topSizer->Add(notebook, 0, wxALL, 0); + mainSizer->Add(topSizer, 0, wxALL, margin); + + for(int i=0; i<configuration.getFieldGroupCount(); ++i){ + + //create page + FieldGroup *fg= configuration.getFieldGroup(i); + wxPanel *panel= new wxPanel(notebook, -1); + notebook->AddPage(panel, Configuration::ToUnicode(fg->getName().c_str())); + + //sizers + wxSizer *gridSizer= new wxFlexGridSizer(2, margin, gridMarginHorizontal); + wxSizer *panelSizer= new wxBoxSizer(wxVERTICAL); + panelSizer->Add(gridSizer, 0, wxALL, panelMargin); + panel->SetSizer(panelSizer); + + for(int j=0; j<fg->getFieldCount(); ++j){ + Field *f= fg->getField(j); + FieldText *staticText= new FieldText(panel, this, f); + staticText->SetAutoLayout(true); + gridSizer->Add(staticText); + f->createControl(panel, gridSizer); + idMap.insert(IdPair(staticText->GetId(), staticText)); + } + } + + //buttons + wxSizer *bottomSizer= new wxBoxSizer(wxHORIZONTAL); + + buttonOk= new wxButton(this, biOk, wxT("OK")); + buttonApply= new wxButton(this, biApply, wxT("Apply")); + buttonCancel= new wxButton(this, biCancel, wxT("Cancel")); + buttonDefault= new wxButton(this, biDefault, wxT("Default")); + bottomSizer->Add(buttonOk, 0, wxALL, margin); + bottomSizer->Add(buttonApply, 0, wxRIGHT | wxDOWN | wxUP, margin); + bottomSizer->Add(buttonCancel, 0, wxRIGHT | wxDOWN | wxUP, margin); + bottomSizer->Add(buttonDefault, 0, wxRIGHT | wxDOWN | wxUP, margin); + + infoText= new wxTextCtrl(this, -1, Configuration::ToUnicode("Info text."), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY); + infoText->SetSize(infoText->GetSize().x, 2*infoText->GetSize().y/3); + infoText->SetBackgroundColour(buttonOk->GetBackgroundColour()); + + mainSizer->Add(infoText, 1, wxGROW | wxALL | wxALIGN_CENTER, margin); + mainSizer->Add(bottomSizer, 0, wxALIGN_CENTER); + + SetBackgroundColour(buttonOk->GetBackgroundColour()); + + SetSizerAndFit(mainSizer); + + Refresh(); +} + +void MainWindow::init(){ +} + +void MainWindow::onButtonOk(wxCommandEvent &event){ + configuration.save(); + Close(); +} + +void MainWindow::onButtonApply(wxCommandEvent &event){ + configuration.save(); +} + +void MainWindow::onButtonCancel(wxCommandEvent &event){ + Close(); +} + +void MainWindow::onButtonDefault(wxCommandEvent &event){ + for(int i=0; i<configuration.getFieldGroupCount(); ++i){ + FieldGroup *fg= configuration.getFieldGroup(i); + for(int j=0; j<fg->getFieldCount(); ++j){ + Field *f= fg->getField(j); + f->setValue(f->getDefaultValue()); + f->updateControl(); + } + } +} + +void MainWindow::onClose(wxCloseEvent &event){ + Destroy(); +} + +void MainWindow::onMouseDown(wxMouseEvent &event){ + setInfoText(""); +} + +void MainWindow::setInfoText(const string &str){ + infoText->SetValue(Configuration::ToUnicode(str.c_str())); +} + +BEGIN_EVENT_TABLE(MainWindow, wxFrame) + EVT_BUTTON(biOk, MainWindow::onButtonOk) + EVT_BUTTON(biApply, MainWindow::onButtonApply) + EVT_BUTTON(biCancel, MainWindow::onButtonCancel) + EVT_BUTTON(biDefault, MainWindow::onButtonDefault) + EVT_CLOSE(MainWindow::onClose) + EVT_LEFT_DOWN(MainWindow::onMouseDown) +END_EVENT_TABLE() + +// =============================================== +// class FieldText +// =============================================== + +FieldText::FieldText(wxWindow *parent, MainWindow *mainWindow, const Field *field): + wxStaticText(parent, -1, Configuration::ToUnicode(field->getName().c_str())) +{ + this->mainWindow= mainWindow; + this->field= field; +} + +void FieldText::onHelp(wxHelpEvent &event){ + string str= field->getInfo()+"."; + if(!field->getDescription().empty()){ + str+= "\n"+field->getDescription()+"."; + } + mainWindow->setInfoText(str); +} + + +BEGIN_EVENT_TABLE(FieldText, wxStaticText) + EVT_HELP(-1, FieldText::onHelp) +END_EVENT_TABLE() + +// =============================================== +// class App +// =============================================== + +bool App::OnInit(){ + try{ + mainWindow= new MainWindow(); + mainWindow->Show(); + } + catch(const exception &e){ + wxMessageDialog(NULL, Configuration::ToUnicode(e.what()), Configuration::ToUnicode("Exception"), wxOK | wxICON_ERROR).ShowModal(); + return 0; + } + return true; +} + +int App::MainLoop(){ + try{ + return wxApp::MainLoop(); + } + catch(const exception &e){ + wxMessageDialog(NULL, Configuration::ToUnicode(e.what()), Configuration::ToUnicode("Exception"), wxOK | wxICON_ERROR).ShowModal(); + return 0; + } +} + +int App::OnExit(){ + return 0; +} + +}//end namespace + +IMPLEMENT_APP(Configurator::App) diff --git a/source/configurator/main.h b/source/configurator/main.h new file mode 100644 index 000000000..1568263ce --- /dev/null +++ b/source/configurator/main.h @@ -0,0 +1,104 @@ +#ifndef _CONFIGURATOR_MAIN_H_ +#define _CONFIGURATOR_MAIN_H_ + +#include <map> + +#include <wx/wx.h> +#include <wx/cshelp.h> +#include <wx/notebook.h> +#include <wx/sizer.h> + +#include "configuration.h" + +using std::pair; +using std::map; + +namespace Configurator{ + +// =============================== +// class MainWindow +// =============================== + +class MainWindow: public wxFrame{ +private: + DECLARE_EVENT_TABLE() + +private: + typedef pair<int, wxWindow*> IdPair; + typedef map<int, wxWindow*> IdMap; + +private: + static const int margin; + static const int panelMargin; + static const int gridMarginHorizontal; + + enum ButtonId{ + biOk, + biApply, + biCancel, + biDefault + }; + +private: + IdMap idMap; + Configuration configuration; + wxButton *buttonOk; + wxButton *buttonApply; + wxButton *buttonCancel; + wxButton *buttonDefault; + wxNotebook *notebook; + wxTextCtrl *infoText; + +public: + MainWindow(); + void init(); + static const string versionString; + static const string winHeader; + + void onButtonOk(wxCommandEvent &event); + void onButtonApply(wxCommandEvent &event); + void onButtonCancel(wxCommandEvent &event); + void onButtonDefault(wxCommandEvent &event); + void onClose(wxCloseEvent &event); + void onMouseDown(wxMouseEvent &event); + + void setInfoText(const string &str); +}; + +// =============================== +// class FieldText +// =============================== + +class FieldText: public wxStaticText{ +private: + MainWindow *mainWindow; + const Field *field; + +private: + DECLARE_EVENT_TABLE() + +public: + FieldText(wxWindow *parentm, MainWindow *mainWindow, const Field *field); + + void onHelp(wxHelpEvent &event); +}; + +// =============================== +// class App +// =============================== + +class App: public wxApp{ +private: + MainWindow *mainWindow; + +public: + virtual bool OnInit(); + virtual int MainLoop(); + virtual int OnExit(); +}; + +}//end namespace + +DECLARE_APP(Configurator::App) + +#endif diff --git a/source/g3d_viewer/main.cpp b/source/g3d_viewer/main.cpp new file mode 100644 index 000000000..f44eb04a2 --- /dev/null +++ b/source/g3d_viewer/main.cpp @@ -0,0 +1,327 @@ +#include "main.h" + +#include <stdexcept> + +#include "graphics_factory_gl.h" +#include "graphics_interface.h" +#include "util.h" +#include "conversion.h" + +using namespace Shared::Platform; +using namespace Shared::Graphics; +using namespace Shared::Graphics::Gl; +using namespace Shared::Util; + +using namespace std; + +namespace Shared{ namespace G3dViewer{ + +// =============================================== +// class Global functions +// =============================================== + +wxString ToUnicode(const char* str) { + return wxString(str, wxConvUTF8); +} + +wxString ToUnicode(const string& str) { + return wxString(str.c_str(), wxConvUTF8); +} + +// =============================================== +// class MainWindow +// =============================================== + +const string MainWindow::versionString= "v1.3.5-beta1"; +const string MainWindow::winHeader= "G3D viewer " + versionString + " - Built: " + __DATE__; + +MainWindow::MainWindow(const string &modelPath) + : wxFrame(NULL, -1, ToUnicode(winHeader),wxPoint(Renderer::windowX, Renderer::windowY), + wxSize(Renderer::windowW, Renderer::windowH)) +{ + //getGlPlatformExtensions(); + renderer= Renderer::getInstance(); + this->modelPath= modelPath; + model= NULL; + playerColor= Renderer::pcRed; + + speed= 0.025f; + + glCanvas = new GlCanvas(this); + + //getGlPlatformExtensions(); + + //glCanvas->SetCurrent(); + //renderer->init(); + + menu= new wxMenuBar(); + + //menu + menuFile= new wxMenu(); + menuFile->Append(miFileLoad, wxT("Load")); + menu->Append(menuFile, wxT("File")); + + //mode + menuMode= new wxMenu(); + menuMode->AppendCheckItem(miModeNormals, wxT("Normals")); + menuMode->AppendCheckItem(miModeWireframe, wxT("Wireframe")); + menuMode->AppendCheckItem(miModeGrid, wxT("Grid")); + menu->Append(menuMode, wxT("Mode")); + + //mode + menuSpeed= new wxMenu(); + menuSpeed->Append(miSpeedSlower, wxT("Slower")); + menuSpeed->Append(miSpeedFaster, wxT("Faster")); + menu->Append(menuSpeed, wxT("Speed")); + + //custom color + menuCustomColor= new wxMenu(); + menuCustomColor->AppendCheckItem(miColorRed, wxT("Red")); + menuCustomColor->AppendCheckItem(miColorBlue, wxT("Blue")); + menuCustomColor->AppendCheckItem(miColorYellow, wxT("Yellow")); + menuCustomColor->AppendCheckItem(miColorGreen, wxT("Green")); + menu->Append(menuCustomColor, wxT("Custom Color")); + + menuMode->Check(miModeGrid, true); + menuCustomColor->Check(miColorRed, true); + + SetMenuBar(menu); + + //misc + model= NULL; + rotX= 0.0f; + rotY= 0.0f; + zoom= 1.0f; + lastX= 0; + lastY= 0; + anim= 0.0f; + + CreateStatusBar(); + + timer = new wxTimer(this); + timer->Start(100); + + glCanvas->SetFocus(); +} + +MainWindow::~MainWindow(){ + delete renderer; + delete model; + delete timer; + delete glCanvas; +} + +void MainWindow::init(){ + glCanvas->SetCurrent(); + renderer->init(); + + if(!modelPath.empty()){ + Model *tmpModel= new ModelGl(); + + printf("In [%s::%s] modelPath = [%s]\n",__FILE__,__FUNCTION__,modelPath.c_str()); + + renderer->loadTheModel(tmpModel, modelPath); + model= tmpModel; + + GetStatusBar()->SetStatusText(ToUnicode(getModelInfo().c_str())); + } + + //SetTitle(ToUnicode(winHeader + "; " + modelPath)); +} + +void MainWindow::onPaint(wxPaintEvent &event){ + renderer->reset(GetClientSize().x, GetClientSize().y, playerColor); + + renderer->transform(rotX, rotY, zoom); + renderer->renderGrid(); + + renderer->renderTheModel(model, anim); + + glCanvas->SwapBuffers(); +} + +void MainWindow::onClose(wxCloseEvent &event){ + delete this; +} + +void MainWindow::onMouseMove(wxMouseEvent &event){ + int x= event.GetX(); + int y= event.GetY(); + wxPaintEvent paintEvent; + + if(event.LeftIsDown()){ + rotX+= clamp(lastX-x, -10, 10); + rotY+= clamp(lastY-y, -10, 10); + onPaint(paintEvent); + } + else if(event.RightIsDown()){ + zoom*= 1.0f+(lastX-x+lastY-y)/100.0f; + zoom= clamp(zoom, 0.1f, 10.0f); + onPaint(paintEvent); + } + + lastX= x; + lastY= y; +} + +void MainWindow::onMenuFileLoad(wxCommandEvent &event){ + string fileName; + wxFileDialog fileDialog(this); + fileDialog.SetWildcard(wxT("G3D files (*.g3d)|*.g3d")); + if(fileDialog.ShowModal()==wxID_OK){ + delete model; + Model *tmpModel= new ModelGl(); + renderer->loadTheModel(tmpModel, (const char*)wxFNCONV(fileDialog.GetPath().c_str())); + model= tmpModel; + GetStatusBar()->SetStatusText(ToUnicode(getModelInfo().c_str())); + } +} + +void MainWindow::onMenuModeNormals(wxCommandEvent &event){ + renderer->toggleNormals(); + menuMode->Check(miModeNormals, renderer->getNormals()); +} + +void MainWindow::onMenuModeWireframe(wxCommandEvent &event){ + renderer->toggleWireframe(); + menuMode->Check(miModeWireframe, renderer->getWireframe()); +} + +void MainWindow::onMenuModeGrid(wxCommandEvent &event){ + renderer->toggleGrid(); + menuMode->Check(miModeGrid, renderer->getGrid()); +} + +void MainWindow::onMenuSpeedSlower(wxCommandEvent &event){ + speed/= 1.5f; +} + +void MainWindow::onMenuSpeedFaster(wxCommandEvent &event){ + speed*= 1.5f; +} + +void MainWindow::onMenuColorRed(wxCommandEvent &event){ + playerColor= Renderer::pcRed; + menuCustomColor->Check(miColorRed, true); + menuCustomColor->Check(miColorBlue, false); + menuCustomColor->Check(miColorYellow, false); + menuCustomColor->Check(miColorGreen, false); +} + +void MainWindow::onMenuColorBlue(wxCommandEvent &event){ + playerColor= Renderer::pcBlue; + menuCustomColor->Check(miColorRed, false); + menuCustomColor->Check(miColorBlue, true); + menuCustomColor->Check(miColorYellow, false); + menuCustomColor->Check(miColorGreen, false); +} + +void MainWindow::onMenuColorYellow(wxCommandEvent &event){ + playerColor= Renderer::pcYellow; + menuCustomColor->Check(miColorRed, false); + menuCustomColor->Check(miColorBlue, false); + menuCustomColor->Check(miColorYellow, true); + menuCustomColor->Check(miColorGreen, false); +} + +void MainWindow::onMenuColorGreen(wxCommandEvent &event){ + playerColor= Renderer::pcGreen; + menuCustomColor->Check(miColorRed, false); + menuCustomColor->Check(miColorBlue, false); + menuCustomColor->Check(miColorYellow, false); + menuCustomColor->Check(miColorGreen, true); +} + +void MainWindow::onTimer(wxTimerEvent &event){ + wxPaintEvent paintEvent; + + anim= anim+speed; + if(anim>1.0f){ + anim-= 1.f; + } + onPaint(paintEvent); +} + +string MainWindow::getModelInfo(){ + string str; + + if(model!=NULL){ + str+= "Meshes: "+intToStr(model->getMeshCount()); + str+= ", Vertices: "+intToStr(model->getVertexCount()); + str+= ", Triangles: "+intToStr(model->getTriangleCount()); + str+= ", Version: "+intToStr(model->getFileVersion()); + } + + return str; +} + +BEGIN_EVENT_TABLE(MainWindow, wxFrame) + EVT_TIMER(-1, MainWindow::onTimer) + EVT_CLOSE(MainWindow::onClose) + EVT_MENU(miFileLoad, MainWindow::onMenuFileLoad) + + EVT_MENU(miModeWireframe, MainWindow::onMenuModeWireframe) + EVT_MENU(miModeNormals, MainWindow::onMenuModeNormals) + EVT_MENU(miModeGrid, MainWindow::onMenuModeGrid) + + EVT_MENU(miSpeedFaster, MainWindow::onMenuSpeedFaster) + EVT_MENU(miSpeedSlower, MainWindow::onMenuSpeedSlower) + + EVT_MENU(miColorRed, MainWindow::onMenuColorRed) + EVT_MENU(miColorBlue, MainWindow::onMenuColorBlue) + EVT_MENU(miColorYellow, MainWindow::onMenuColorYellow) + EVT_MENU(miColorGreen, MainWindow::onMenuColorGreen) +END_EVENT_TABLE() + +// ===================================================== +// class GlCanvas +// ===================================================== + +GlCanvas::GlCanvas(MainWindow * mainWindow): + wxGLCanvas(mainWindow, -1, wxDefaultPosition) +{ + this->mainWindow = mainWindow; +} + +void GlCanvas::onMouseMove(wxMouseEvent &event){ + mainWindow->onMouseMove(event); +} + +BEGIN_EVENT_TABLE(GlCanvas, wxGLCanvas) + EVT_MOTION(GlCanvas::onMouseMove) +END_EVENT_TABLE() + +// =============================================== +// class App +// =============================================== + +bool App::OnInit(){ + std::string modelPath; + if(argc==2){ + modelPath= wxFNCONV(argv[1]); + } + + mainWindow= new MainWindow(modelPath); + mainWindow->Show(); + mainWindow->init(); + + return true; +} + +int App::MainLoop(){ + try{ + return wxApp::MainLoop(); + } + catch(const exception &e){ + wxMessageDialog(NULL, ToUnicode(e.what()), ToUnicode("Exception"), wxOK | wxICON_ERROR).ShowModal(); + return 0; + } +} + +int App::OnExit(){ + return 0; +} + +}}//end namespace + +IMPLEMENT_APP(Shared::G3dViewer::App) diff --git a/source/g3d_viewer/main.h b/source/g3d_viewer/main.h new file mode 100644 index 000000000..1b64eb402 --- /dev/null +++ b/source/g3d_viewer/main.h @@ -0,0 +1,129 @@ +#ifndef _SHADER_G3DVIEWER_MAIN_H_ +#define _SHADER_G3DVIEWER_MAIN_H_ + +#include <string> + +#include <wx/wx.h> +#include <wx/glcanvas.h> + +#include "renderer.h" +//#include "util.h" + +//using Shared::Platform::Window; +//using Shared::Platform::MouseState; + +using std::string; + +namespace Shared{ namespace G3dViewer{ + +class GlCanvas; + +// =============================== +// class MainWindow +// =============================== + +class MainWindow: public wxFrame{ +private: + DECLARE_EVENT_TABLE() + +public: + static const string versionString; + static const string winHeader; + + enum MenuId{ + miFileLoad, + miModeWireframe, + miModeNormals, + miModeGrid, + miSpeedSlower, + miSpeedFaster, + miColorRed, + miColorBlue, + miColorYellow, + miColorGreen + }; + +private: + GlCanvas *glCanvas; + Renderer *renderer; + + wxTimer *timer; + + wxMenuBar *menu; + wxMenu *menuFile; + wxMenu *menuMode; + wxMenu *menuSpeed; + wxMenu *menuCustomColor; + + Model *model; + string modelPath; + + float speed; + float anim; + float rotX, rotY, zoom; + int lastX, lastY; + Renderer::PlayerColor playerColor; + +public: + MainWindow(const string &modelPath); + ~MainWindow(); + void init(); + + void Notify(); + + void onPaint(wxPaintEvent &event); + void onClose(wxCloseEvent &event); + void onMenuFileLoad(wxCommandEvent &event); + void onMenuModeNormals(wxCommandEvent &event); + void onMenuModeWireframe(wxCommandEvent &event); + void onMenuModeGrid(wxCommandEvent &event); + void onMenuSpeedSlower(wxCommandEvent &event); + void onMenuSpeedFaster(wxCommandEvent &event); + void onMenuColorRed(wxCommandEvent &event); + void onMenuColorBlue(wxCommandEvent &event); + void onMenuColorYellow(wxCommandEvent &event); + void onMenuColorGreen(wxCommandEvent &event); + void onMouseMove(wxMouseEvent &event); + void onTimer(wxTimerEvent &event); + + string getModelInfo(); +}; + +// ===================================================== +// class GlCanvas +// ===================================================== + +class GlCanvas: public wxGLCanvas { +private: + DECLARE_EVENT_TABLE() + +public: + GlCanvas(MainWindow *mainWindow); + + void onMouseMove(wxMouseEvent &event); + void onPaint(wxPaintEvent &event); + +private: + MainWindow *mainWindow; +}; + + +// =============================== +// class App +// =============================== + +class App: public wxApp{ +private: + MainWindow *mainWindow; + +public: + virtual bool OnInit(); + virtual int MainLoop(); + virtual int OnExit(); +}; + +}}//end namespace + +DECLARE_APP(Shared::G3dViewer::App) + +#endif diff --git a/source/g3d_viewer/renderer.cpp b/source/g3d_viewer/renderer.cpp new file mode 100644 index 000000000..bce37cc16 --- /dev/null +++ b/source/g3d_viewer/renderer.cpp @@ -0,0 +1,306 @@ +#include "renderer.h" + +#include "opengl.h" +//#include "texture_gl.h" +#include "graphics_factory_gl.h" +#include "graphics_interface.h" + +//#include "factory_repository.h" + +using namespace Shared::Graphics; +using namespace Shared::Graphics::Gl; + +namespace Shared{ namespace G3dViewer{ + +// =============================================== +// class MeshCallbackTeamColor +// =============================================== + +void MeshCallbackTeamColor::execute(const Mesh *mesh){ + + //team color + if(mesh->getCustomTexture() && teamTexture!=NULL){ + //texture 0 + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + + //set color to interpolation + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); + + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE1); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); + + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA); + + //set alpha to 1 + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); + + //texture 1 + glActiveTexture(GL_TEXTURE1); + glMultiTexCoord2f(GL_TEXTURE1, 0.f, 0.f); + glEnable(GL_TEXTURE_2D); + + glBindTexture(GL_TEXTURE_2D, static_cast<const Texture2DGl*>(teamTexture)->getHandle()); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); + + //set alpha to 1 + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); + + glActiveTexture(GL_TEXTURE0); + } + else{ + glActiveTexture(GL_TEXTURE1); + glDisable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } +} + +// =============================================== +// class Renderer +// =============================================== + +Renderer::Renderer(){ + normals= false; + wireframe= false; + grid= true; + modelRenderer = NULL; + textureManager = NULL; +} + +Renderer::~Renderer(){ + delete modelRenderer; + delete textureManager; +} + +Renderer * Renderer::getInstance(){ + static Renderer * renderer = new Renderer(); + return renderer; +} + +void Renderer::transform(float rotX, float rotY, float zoom){ + assertGl(); + + glMatrixMode(GL_MODELVIEW); + glRotatef(rotY, 1.0f, 0.0f, 0.0f); + glRotatef(rotX, 0.0f, 1.0f, 0.0f); + glScalef(zoom, zoom, zoom); + Vec4f pos(-8.0f, 5.0f, 10.0f, 0.0f); + glLightfv(GL_LIGHT0,GL_POSITION, pos.ptr()); + + assertGl(); +} + +void Renderer::checkGlCaps(){ + + //opengl 1.3 + if(!isGlVersionSupported(1, 3, 0)){ + + string message; + + message += "Your system supports OpenGL version \""; + message += getGlVersion() + string("\"\n"); + message += "Glest needs at least version 1.3 to work\n"; + message += "You may solve this problem by installing your latest video card drivers"; + + throw runtime_error(message.c_str()); + } + + //opengl 1.4 or extension + if(!isGlVersionSupported(1, 4, 0)){ + checkExtension("GL_ARB_texture_env_crossbar", "Glest"); + } +} + +void Renderer::checkExtension(const string &extension, const string &msg){ + if(!isGlExtensionSupported(extension.c_str())){ + string str= "OpenGL extension not supported: " + extension + ", required for " + msg; + throw runtime_error(str); + } +} + +void Renderer::init(){ + assertGl(); + + //!!!glInitNames(); + //!!!checkGlCaps(); + + GraphicsFactory *gf= new GraphicsFactoryGl(); + GraphicsInterface::getInstance().setFactory(gf); + + modelRenderer= gf->newModelRenderer(); + textureManager= gf->newTextureManager(); + + //red tex + customTextureRed= textureManager->newTexture2D(); + customTextureRed->getPixmap()->init(1, 1, 3); + customTextureRed->getPixmap()->setPixel(0, 0, Vec3f(1.f, 0.f, 0.f)); + + //blue tex + customTextureBlue= textureManager->newTexture2D(); + customTextureBlue->getPixmap()->init(1, 1, 3); + customTextureBlue->getPixmap()->setPixel(0, 0, Vec3f(0.f, 0.f, 1.f)); + + //yellow tex + customTextureYellow= textureManager->newTexture2D(); + customTextureYellow->getPixmap()->init(1, 1, 3); + customTextureYellow->getPixmap()->setPixel(0, 0, Vec3f(1.f, 1.f, 0.f)); + + //green + customTextureGreen= textureManager->newTexture2D(); + customTextureGreen->getPixmap()->init(1, 1, 3); + customTextureGreen->getPixmap()->setPixel(0, 0, Vec3f(0.f, 0.5f, 0.f)); + + glClearColor(0.3f, 0.3f, 0.3f, 1.0f); + glEnable(GL_TEXTURE_2D); + glFrontFace(GL_CW); + glEnable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, 0.5f); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + + Vec4f diffuse= Vec4f(1.0f, 1.0f, 1.0f, 1.0f); + Vec4f ambient= Vec4f(0.3f, 0.3f, 0.3f, 1.0f); + Vec4f specular= Vec4f(0.1f, 0.1f, 0.1f, 1.0f); + + glLightfv(GL_LIGHT0,GL_AMBIENT, ambient.ptr()); + glLightfv(GL_LIGHT0,GL_DIFFUSE, diffuse.ptr()); + glLightfv(GL_LIGHT0,GL_SPECULAR, specular.ptr()); + + glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); + glEnable(GL_COLOR_MATERIAL); + + assertGl(); +} + +void Renderer::reset(int w, int h, PlayerColor playerColor){ + assertGl(); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glViewport(0, 0, w, h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(60.0f, static_cast<float>(w)/h, 1.0f, 200.0f); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0, -1.5, -5); + + Texture2D *customTexture; + switch(playerColor){ + case pcRed: + customTexture= customTextureRed; + break; + case pcBlue: + customTexture= customTextureBlue; + break; + case pcYellow: + customTexture= customTextureYellow; + break; + case pcGreen: + customTexture= customTextureGreen; + break; + default: + assert(false); + } + meshCallbackTeamColor.setTeamTexture(customTexture); + + if(wireframe){ + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glDisable(GL_TEXTURE_2D); + glDisable(GL_LIGHTING); + glDisable(GL_LIGHT0); + } + else{ + glEnable(GL_TEXTURE_2D); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + + assertGl(); +} + +void Renderer::renderGrid(){ + if(grid){ + + float i; + + assertGl(); + + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_TEXTURE_2D); + glDisable(GL_LIGHTING); + + glBegin(GL_LINES); + glColor3f(1.0f, 1.0f, 1.0f); + for(i=-10.0f; i<=10.0f; i+=1.0f){ + glVertex3f(i, 0.0f, 10.0f); + glVertex3f(i, 0.0f, -10.0f); + } + for(i=-10.0f; i<=10.0f; i+=1.0f){ + glVertex3f(10.f, 0.0f, i); + glVertex3f(-10.f, 0.0f, i); + } + glEnd(); + + glPopAttrib(); + + assertGl(); + } +} + +void Renderer::toggleNormals(){ + normals= normals? false: true; +} + +void Renderer::toggleWireframe(){ + wireframe= wireframe? false: true; +} + +void Renderer::toggleGrid(){ + grid= grid? false: true; +} + +void Renderer::loadTheModel(Model *model, string file){ + model->setTextureManager(textureManager); + model->loadG3d(file); + textureManager->init(); +} + +void Renderer::renderTheModel(Model *model, float f){ + if(model != NULL){ + modelRenderer->begin(true, true, !wireframe, &meshCallbackTeamColor); + model->updateInterpolationData(f, true); + modelRenderer->render(model); + + if(normals){ + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_LIGHTING); + glDisable(GL_TEXTURE_2D); + glColor3f(1.0f, 1.0f, 1.0f); + modelRenderer->renderNormalsOnly(model); + glPopAttrib(); + } + + modelRenderer->end(); + } +} + +}}//end namespace diff --git a/source/g3d_viewer/renderer.h b/source/g3d_viewer/renderer.h new file mode 100644 index 000000000..84b5f56a6 --- /dev/null +++ b/source/g3d_viewer/renderer.h @@ -0,0 +1,103 @@ +#ifndef _SHADER_G3DVIEWER_RENDERER_H_ +#define _SHADER_G3DVIEWER_RENDERER_H_ + +/* +#include "model_renderer.h" +#include "texture_manager.h" +#include "model.h" +#include "texture.h" +*/ + +#include "model_renderer.h" +#include "texture_manager.h" +#include "model.h" +#include "texture.h" +//#include "model_manager.h" +//#include "graphics_factory_gl.h" + +using Shared::Graphics::ModelRenderer; +using Shared::Graphics::TextureManager; +using Shared::Graphics::Model; +using Shared::Graphics::Texture2D; + +//#include "model_renderer.h" + +using Shared::Graphics::MeshCallback; +using Shared::Graphics::Mesh; +using Shared::Graphics::Texture; + +namespace Shared{ namespace G3dViewer{ + +// =============================================== +// class MeshCallbackTeamColor +// =============================================== + +class MeshCallbackTeamColor: public MeshCallback{ +private: + const Texture *teamTexture; + +public: + void setTeamTexture(const Texture *teamTexture) {this->teamTexture= teamTexture;} + virtual void execute(const Mesh *mesh); +}; + +// =============================== +// class Renderer +// =============================== + +class Renderer{ +public: + static const int windowX= 100; + static const int windowY= 100; + static const int windowW= 640; + static const int windowH= 480; + +public: + enum PlayerColor{ + pcRed, + pcBlue, + pcYellow, + pcGreen + }; + +private: + bool wireframe; + bool normals; + bool grid; + + ModelRenderer *modelRenderer; + TextureManager *textureManager; + Texture2D *customTextureRed; + Texture2D *customTextureBlue; + Texture2D *customTextureYellow; + Texture2D *customTextureGreen; + MeshCallbackTeamColor meshCallbackTeamColor; + + Renderer(); + void checkGlCaps(); + void checkExtension(const string &extension, const string &msg); + +public: + ~Renderer(); + static Renderer *getInstance(); + + void init(); + void reset(int w, int h, PlayerColor playerColor); + void transform(float rotX, float rotY, float zoom); + void renderGrid(); + + bool getNormals() const {return normals;} + bool getWireframe() const {return wireframe;} + bool getGrid() const {return grid;} + + void toggleNormals(); + void toggleWireframe(); + void toggleGrid(); + + void loadTheModel(Model *model, string file); + void renderTheModel(Model *model, float f); +}; + +}}//end namespace + +#endif