├── 2012 ├── 05-Components-SeanMiddleditch │ ├── ComponentDesign.odp │ └── ComponentDesign.pdf ├── 06-ActionLists-SeanMiddleditch │ ├── ActionLists.pdf │ └── README.txt ├── 06-BriefIntroOpenGL-SeanMiddleditch │ ├── BriefIntroOpenGL.pdf │ └── README.txt ├── 06-StartingGame-SeanMiddleditch │ ├── StartingGame.odp │ └── StartingGame.pdf ├── 09-MessagingSystems-SeanMiddleditch │ ├── MessagingSystems.pdf │ └── MessagingTalk │ │ ├── MessagingTalk.sln │ │ └── MessagingTalk │ │ ├── MessagingTalk.cpp │ │ ├── MessagingTalk.vcxproj │ │ └── MessagingTalk.vcxproj.filters ├── 10-2DGraphics-SeanMiddleditch │ └── 2DGraphics.pdf ├── 10-MathLibraries-SeanMiddleditch │ └── MathLibraries.pdf ├── 11-DataOrientedDesign-SeanMiddleditch │ └── DataOrientedDesign.pdf └── 12-Spaces-SeanMiddleditch │ └── Spaces.pdf ├── 2013 ├── 03-SeanMiddleditch-Introspection1 │ ├── .gitignore │ ├── Introduction to C Introspection.pdf │ ├── Introspection.sln │ ├── Introspection.vcxproj │ ├── Introspection.vcxproj.filters │ ├── main.c │ ├── meta.c │ ├── meta.h │ ├── test.c │ └── test.h └── 05-SeanMiddleditch-Introspection2 │ ├── .gitignore │ ├── C++ Introspection.pdf │ ├── Introspection.sln │ ├── Meta.cpp │ ├── Meta.h │ ├── MetaCPP.vcxproj │ ├── MetaCPP.vcxproj.filters │ └── main.cpp └── README.md /2012/05-Components-SeanMiddleditch/ComponentDesign.odp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngineArchitectureClub/TalkSlides/f326805a649dd765045aec5cae27624934390eb3/2012/05-Components-SeanMiddleditch/ComponentDesign.odp -------------------------------------------------------------------------------- /2012/05-Components-SeanMiddleditch/ComponentDesign.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngineArchitectureClub/TalkSlides/f326805a649dd765045aec5cae27624934390eb3/2012/05-Components-SeanMiddleditch/ComponentDesign.pdf -------------------------------------------------------------------------------- /2012/06-ActionLists-SeanMiddleditch/ActionLists.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngineArchitectureClub/TalkSlides/f326805a649dd765045aec5cae27624934390eb3/2012/06-ActionLists-SeanMiddleditch/ActionLists.pdf -------------------------------------------------------------------------------- /2012/06-ActionLists-SeanMiddleditch/README.txt: -------------------------------------------------------------------------------- 1 | Original Google Docs presentation: 2 | 3 | https://docs.google.com/presentation/d/1kzxp8jfO3GvQsfWo3JHW2b44l9rC9g0jEDJzmU5I_No/edit -------------------------------------------------------------------------------- /2012/06-BriefIntroOpenGL-SeanMiddleditch/BriefIntroOpenGL.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngineArchitectureClub/TalkSlides/f326805a649dd765045aec5cae27624934390eb3/2012/06-BriefIntroOpenGL-SeanMiddleditch/BriefIntroOpenGL.pdf -------------------------------------------------------------------------------- /2012/06-BriefIntroOpenGL-SeanMiddleditch/README.txt: -------------------------------------------------------------------------------- 1 | Original Google Docs presentation: 2 | 3 | https://docs.google.com/presentation/d/1cDJADYgrNQLBNR_MZAWbWZQYpjhYBorA7eMzjDaAG4U -------------------------------------------------------------------------------- /2012/06-StartingGame-SeanMiddleditch/StartingGame.odp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngineArchitectureClub/TalkSlides/f326805a649dd765045aec5cae27624934390eb3/2012/06-StartingGame-SeanMiddleditch/StartingGame.odp -------------------------------------------------------------------------------- /2012/06-StartingGame-SeanMiddleditch/StartingGame.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngineArchitectureClub/TalkSlides/f326805a649dd765045aec5cae27624934390eb3/2012/06-StartingGame-SeanMiddleditch/StartingGame.pdf -------------------------------------------------------------------------------- /2012/09-MessagingSystems-SeanMiddleditch/MessagingSystems.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngineArchitectureClub/TalkSlides/f326805a649dd765045aec5cae27624934390eb3/2012/09-MessagingSystems-SeanMiddleditch/MessagingSystems.pdf -------------------------------------------------------------------------------- /2012/09-MessagingSystems-SeanMiddleditch/MessagingTalk/MessagingTalk.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MessagingTalk", "MessagingTalk\MessagingTalk.vcxproj", "{51D18B6F-7DE2-4BA6-909E-042B1AF6651C}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {51D18B6F-7DE2-4BA6-909E-042B1AF6651C}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {51D18B6F-7DE2-4BA6-909E-042B1AF6651C}.Debug|Win32.Build.0 = Debug|Win32 14 | {51D18B6F-7DE2-4BA6-909E-042B1AF6651C}.Release|Win32.ActiveCfg = Release|Win32 15 | {51D18B6F-7DE2-4BA6-909E-042B1AF6651C}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /2012/09-MessagingSystems-SeanMiddleditch/MessagingTalk/MessagingTalk/MessagingTalk.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 Sean Middleditch 2 | // All rights reserved. 3 | // This code is for illustration purposes for a talk. 4 | // Do not use in your own projects for any reason. Even 5 | // if the copyright made it legal, you don't _want_ to 6 | // use this code in a real project. Seriously. 7 | 8 | #include 9 | #include 10 | 11 | enum MessageType { 12 | MSG_UNKNOWN = 0, 13 | MSG_KEY, 14 | MSG_MOUSE 15 | }; 16 | 17 | class Message { 18 | public: 19 | MessageType m_Type; 20 | int m_Id; 21 | Message(MessageType type, int id) : m_Type(type), m_Id(id) {} 22 | }; 23 | 24 | class KeyMessage : public Message { 25 | public: 26 | KeyMessage(int id) : Message(MSG_KEY, id) {} 27 | }; 28 | 29 | class MouseMessage : public Message { 30 | public: 31 | MouseMessage(int id) : Message(MSG_MOUSE, id) {} 32 | }; 33 | 34 | class MessagingBase { 35 | typedef void(*Handler)(MessagingBase*, const Message&); 36 | 37 | struct Binding { 38 | MessageType m_Type; 39 | MessagingBase* m_Observer; 40 | MessagingBase* m_Observed; 41 | Handler m_Handler; 42 | 43 | Binding(MessageType type, MessagingBase* observer, 44 | MessagingBase* observed, Handler handler) : 45 | m_Type(type), m_Observer(observer), m_Observed(observed), 46 | m_Handler(handler) {} 47 | }; 48 | 49 | std::vector m_Bindings; 50 | 51 | public: 52 | ~MessagingBase(); 53 | 54 | template 55 | void Bind(MessageType type, Object* observer); 56 | template 57 | void Unbind(MessageType type, Object* observer); 58 | void Unbind(const MessagingBase* object); 59 | 60 | protected: 61 | void SendMessage(const Message& msg); 62 | 63 | private: 64 | template 65 | static void Binder(MessagingBase* observer, const Message& message) { 66 | (static_cast(observer)->*Method)(static_cast(message)); 67 | } 68 | }; 69 | 70 | class Observed : public MessagingBase { 71 | public: 72 | void RaiseKey(int id) { SendMessage(KeyMessage(id)); } 73 | void RaiseMouse(int id) { SendMessage(MouseMessage(id)); } 74 | }; 75 | 76 | class Observer : public MessagingBase { 77 | public: 78 | void OnMessage(const Message& msg) { std::cout << "Got message id " << msg.m_Id << " of type " << msg.m_Type << std::endl; } 79 | void OnKey(const KeyMessage& msg) { std::cout << "Got key message id " << msg.m_Id << std::endl; } 80 | void OnMouse(const MouseMessage& msg) { std::cout << "Got mouse message id " << msg.m_Id << std::endl; } 81 | }; 82 | 83 | int main(int argc, char** argv) 84 | { 85 | Observed observed; 86 | Observer observer; 87 | 88 | observed.Bind(MSG_UNKNOWN, &observer); 89 | observed.Bind(MSG_MOUSE, &observer); 90 | observed.Bind(MSG_KEY, &observer); 91 | 92 | std::cout << "Sending key message id 1" << std::endl; 93 | observed.RaiseKey(1); 94 | 95 | std::cout << "Sending mouse message id 2" << std::endl; 96 | observed.RaiseMouse(2); 97 | 98 | observed.Unbind(MSG_MOUSE, &observer); 99 | 100 | std::cout << "Sending mouse message id 3" << std::endl; 101 | observed.RaiseMouse(3); 102 | 103 | observed.Unbind(&observer); 104 | 105 | std::cout << "Sending key message id 4" << std::endl; 106 | observed.RaiseKey(4); 107 | 108 | std::cout << "Done" << std::endl; 109 | std::getc(stdin); 110 | } 111 | 112 | MessagingBase::~MessagingBase() { 113 | while (!m_Bindings.empty()) { 114 | Binding binding = m_Bindings.back(); 115 | m_Bindings.pop_back(); 116 | binding.m_Observed->Unbind(this); 117 | binding.m_Observer->Unbind(this); 118 | }; 119 | } 120 | 121 | void MessagingBase::SendMessage(const Message& msg) { 122 | for (size_t i = 0; i < m_Bindings.size(); ++i) 123 | if (m_Bindings[i].m_Type == MSG_UNKNOWN || m_Bindings[i].m_Type == msg.m_Type) 124 | m_Bindings[i].m_Handler(m_Bindings[i].m_Observer, msg); 125 | } 126 | 127 | template 128 | void MessagingBase::Bind(MessageType type, Object* observer) { 129 | Binding binding(type, observer, this, &Binder); 130 | m_Bindings.push_back(binding); 131 | observer->m_Bindings.push_back(binding); 132 | } 133 | 134 | template 135 | void MessagingBase::Unbind(MessageType type, Object* observer) { 136 | Handler handler = &Binder; 137 | auto i = m_Bindings.begin(); 138 | while (i != m_Bindings.end()) 139 | if (i->m_Type == type && i->m_Observer == observer && i->m_Handler == handler) 140 | i = m_Bindings.erase(i); 141 | else 142 | ++i; 143 | } 144 | 145 | void MessagingBase::Unbind(const MessagingBase* object) { 146 | auto i = m_Bindings.begin(); 147 | while (i != m_Bindings.end()) 148 | if (i->m_Observed == object || i->m_Observer == object) 149 | i = m_Bindings.erase(i); 150 | else 151 | ++i; 152 | } -------------------------------------------------------------------------------- /2012/09-MessagingSystems-SeanMiddleditch/MessagingTalk/MessagingTalk/MessagingTalk.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | $(VCTargetsPath11) 15 | 16 | 17 | {51D18B6F-7DE2-4BA6-909E-042B1AF6651C} 18 | Win32Proj 19 | MessagingTalk 20 | 21 | 22 | 23 | Application 24 | true 25 | v110 26 | Unicode 27 | 28 | 29 | Application 30 | false 31 | v110 32 | true 33 | Unicode 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | true 47 | 48 | 49 | false 50 | 51 | 52 | 53 | 54 | 55 | Level3 56 | Disabled 57 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 58 | 59 | 60 | Console 61 | true 62 | 63 | 64 | 65 | 66 | Level3 67 | 68 | 69 | MaxSpeed 70 | true 71 | true 72 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 73 | 74 | 75 | Console 76 | true 77 | true 78 | true 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /2012/09-MessagingSystems-SeanMiddleditch/MessagingTalk/MessagingTalk/MessagingTalk.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /2012/10-2DGraphics-SeanMiddleditch/2DGraphics.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngineArchitectureClub/TalkSlides/f326805a649dd765045aec5cae27624934390eb3/2012/10-2DGraphics-SeanMiddleditch/2DGraphics.pdf -------------------------------------------------------------------------------- /2012/10-MathLibraries-SeanMiddleditch/MathLibraries.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngineArchitectureClub/TalkSlides/f326805a649dd765045aec5cae27624934390eb3/2012/10-MathLibraries-SeanMiddleditch/MathLibraries.pdf -------------------------------------------------------------------------------- /2012/11-DataOrientedDesign-SeanMiddleditch/DataOrientedDesign.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngineArchitectureClub/TalkSlides/f326805a649dd765045aec5cae27624934390eb3/2012/11-DataOrientedDesign-SeanMiddleditch/DataOrientedDesign.pdf -------------------------------------------------------------------------------- /2012/12-Spaces-SeanMiddleditch/Spaces.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngineArchitectureClub/TalkSlides/f326805a649dd765045aec5cae27624934390eb3/2012/12-Spaces-SeanMiddleditch/Spaces.pdf -------------------------------------------------------------------------------- /2013/03-SeanMiddleditch-Introspection1/.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | [Dd]ebug/ 46 | [Rr]elease/ 47 | *_i.c 48 | *_p.c 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.vspscc 63 | .builds 64 | *.dotCover 65 | 66 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 67 | #packages/ 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | 76 | # Visual Studio profiler 77 | *.psess 78 | *.vsp 79 | 80 | # ReSharper is a .NET coding add-in 81 | _ReSharper* 82 | 83 | # Installshield output folder 84 | [Ee]xpress 85 | 86 | # DocProject is a documentation generator add-in 87 | DocProject/buildhelp/ 88 | DocProject/Help/*.HxT 89 | DocProject/Help/*.HxC 90 | DocProject/Help/*.hhc 91 | DocProject/Help/*.hhk 92 | DocProject/Help/*.hhp 93 | DocProject/Help/Html2 94 | DocProject/Help/html 95 | 96 | # Click-Once directory 97 | publish 98 | 99 | # Others 100 | [Bb]in 101 | [Oo]bj 102 | sql 103 | TestResults 104 | *.Cache 105 | ClientBin 106 | stylecop.* 107 | ~$* 108 | *.dbmdl 109 | Generated_Code #added for RIA/Silverlight projects 110 | 111 | # Backup & report files from converting an old project file to a newer 112 | # Visual Studio version. Backup files are not needed, because we have git ;-) 113 | _UpgradeReport_Files/ 114 | Backup*/ 115 | UpgradeLog*.XML 116 | 117 | 118 | 119 | ############ 120 | ## Windows 121 | ############ 122 | 123 | # Windows image file caches 124 | Thumbs.db 125 | 126 | # Folder config file 127 | Desktop.ini 128 | 129 | 130 | ############# 131 | ## Python 132 | ############# 133 | 134 | *.py[co] 135 | 136 | # Packages 137 | *.egg 138 | *.egg-info 139 | dist 140 | build 141 | eggs 142 | parts 143 | bin 144 | var 145 | sdist 146 | develop-eggs 147 | .installed.cfg 148 | 149 | # Installer logs 150 | pip-log.txt 151 | 152 | # Unit test / coverage reports 153 | .coverage 154 | .tox 155 | 156 | #Translations 157 | *.mo 158 | 159 | #Mr Developer 160 | .mr.developer.cfg 161 | 162 | # Mac crap 163 | .DS_Store 164 | -------------------------------------------------------------------------------- /2013/03-SeanMiddleditch-Introspection1/Introduction to C Introspection.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngineArchitectureClub/TalkSlides/f326805a649dd765045aec5cae27624934390eb3/2013/03-SeanMiddleditch-Introspection1/Introduction to C Introspection.pdf -------------------------------------------------------------------------------- /2013/03-SeanMiddleditch-Introspection1/Introspection.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Express 2012 for Windows Desktop 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Introspection", "Introspection.vcxproj", "{34A7BC63-568A-400D-B344-5A04843AF40E}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {34A7BC63-568A-400D-B344-5A04843AF40E}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {34A7BC63-568A-400D-B344-5A04843AF40E}.Debug|Win32.Build.0 = Debug|Win32 14 | {34A7BC63-568A-400D-B344-5A04843AF40E}.Release|Win32.ActiveCfg = Release|Win32 15 | {34A7BC63-568A-400D-B344-5A04843AF40E}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /2013/03-SeanMiddleditch-Introspection1/Introspection.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {34A7BC63-568A-400D-B344-5A04843AF40E} 15 | Introspection 16 | 17 | 18 | 19 | Application 20 | true 21 | v110 22 | MultiByte 23 | 24 | 25 | Application 26 | false 27 | v110 28 | true 29 | MultiByte 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | Level3 45 | Disabled 46 | 47 | 48 | true 49 | 50 | 51 | 52 | 53 | Level3 54 | MaxSpeed 55 | true 56 | true 57 | 58 | 59 | true 60 | true 61 | true 62 | 63 | 64 | 65 | 66 | CompileAsCpp 67 | CompileAsCpp 68 | 69 | 70 | CompileAsCpp 71 | CompileAsCpp 72 | 73 | 74 | CompileAsCpp 75 | CompileAsCpp 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /2013/03-SeanMiddleditch-Introspection1/Introspection.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Source Files 16 | 17 | 18 | Source Files 19 | 20 | 21 | Source Files 22 | 23 | 24 | 25 | 26 | Header Files 27 | 28 | 29 | Header Files 30 | 31 | 32 | -------------------------------------------------------------------------------- /2013/03-SeanMiddleditch-Introspection1/main.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Sean Middleditch. All right reserved. 2 | // DigiPen Institute of Technology - Game Engine Architecture Club 3 | // Do not use this code for any purpose besides study. Besides 4 | // me not giving you permission, only a lame programmer would use 5 | // this for anything even remotely production quality. 6 | 7 | #include "test.h" 8 | 9 | #include 10 | 11 | int main() 12 | { 13 | TestDerived1 d1; 14 | TestDerived2 d2; 15 | const char* s; 16 | unsigned int i; 17 | float f; 18 | 19 | META_INIT(TestBase); 20 | META_INIT(TestDerived1); 21 | META_INIT(TestDerived2); 22 | 23 | const meta* meta = meta_find("TestDerived2"); 24 | assert(meta != NULL); 25 | 26 | const meta_attribute* attr = meta_find_attribute(meta, "x"); 27 | assert(attr != NULL); 28 | 29 | d2.x = 2.5f; 30 | d2.y = -17.3f; 31 | meta_get(attr, &d2, &f); 32 | assert(f == d2.x); 33 | 34 | d2._base.last_input = NULL; 35 | d2._base.counter = 0; 36 | 37 | const meta_event* event = meta_find_event(meta, "jumped"); 38 | assert(event != NULL); 39 | f = 10.0f; 40 | meta_call(event, &d2, &f); 41 | 42 | event = meta_find_event(meta, "input"); 43 | assert(event != NULL); 44 | meta_call(event, &d2, "key"); 45 | meta_call(event, &d2, "key"); 46 | meta_call(event, &d2, "key"); 47 | 48 | assert(0 == strcmp(d2._base.last_input, "key")); 49 | assert(3 == d2._base.counter); 50 | 51 | meta = meta_find("TestBase"); 52 | assert(meta != NULL); 53 | 54 | meta_call(event, &d2, "key"); 55 | assert(4 == d2._base.counter); 56 | 57 | attr = meta_find_attribute(meta, "counter"); 58 | assert(attr != NULL); 59 | 60 | meta_get(attr, &d2, &i); 61 | assert(4 == i); 62 | 63 | attr = meta_find_attribute(meta, "last_input"); 64 | assert(attr != NULL); 65 | 66 | meta_get(attr, &d2, &s); 67 | assert(0 == strcmp("key", d2._base.last_input)); 68 | 69 | meta = meta_find("TestDerived1"); 70 | d1.health = 100; 71 | d1.damage = 17; 72 | 73 | event = meta_find_event(meta, "damaged"); 74 | assert(event != NULL); 75 | 76 | meta_call(event, &d1, &d1.damage); 77 | meta_call(event, &d1, &d1.damage); 78 | meta_call(event, &d1, &d1.damage); 79 | 80 | attr = meta_find_attribute(meta, "health"); 81 | assert(attr != NULL); 82 | meta_get(attr, &d1, &i); 83 | 84 | assert(49 == i); 85 | 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /2013/03-SeanMiddleditch-Introspection1/meta.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Sean Middleditch. All right reserved. 2 | // DigiPen Institute of Technology - Game Engine Architecture Club 3 | // Do not use this code for any purpose besides study. Besides 4 | // me not giving you permission, only a lame programmer would use 5 | // this for anything even remotely production quality. 6 | 7 | #include "meta.h" 8 | 9 | #include 10 | #include 11 | 12 | static meta* s_head = 0; 13 | 14 | void meta_add(meta* meta) 15 | { 16 | assert(meta != NULL); 17 | meta->next = s_head; 18 | s_head = meta; 19 | } 20 | 21 | void meta_add_attribute(meta* meta, meta_attribute* attr) 22 | { 23 | assert(meta != NULL && attr != NULL); 24 | meta_attribute* copy = (meta_attribute*)malloc(sizeof(meta_attribute)); 25 | assert(copy != NULL); 26 | memcpy(copy, attr, sizeof(meta_attribute)); 27 | copy->next = meta->attrs; 28 | meta->attrs = copy; 29 | copy->parent = meta; 30 | } 31 | 32 | void meta_add_event(meta* meta, meta_event* event) 33 | { 34 | assert(meta != NULL && event != NULL); 35 | meta_event* copy = (meta_event*)malloc(sizeof(meta_event)); 36 | assert(copy != NULL); 37 | memcpy(copy, event, sizeof(meta_event)); 38 | copy->next = meta->events; 39 | meta->events = copy; 40 | copy->parent = meta; 41 | } 42 | 43 | const meta* meta_find(const char* name) 44 | { 45 | assert(name != NULL); 46 | const meta* m = s_head; 47 | while (m != 0) 48 | { 49 | if (0 == strcmp(name, m->name)) 50 | return m; 51 | m = m->next; 52 | } 53 | return 0; 54 | } 55 | 56 | const meta_attribute* meta_find_attribute(const meta* meta, const char* name) 57 | { 58 | assert(meta != NULL && name != NULL); 59 | const meta_attribute* a = meta->attrs; 60 | while (a != 0) 61 | { 62 | if (0 == strcmp(name, a->name)) 63 | return a; 64 | a = a->next; 65 | } 66 | if (meta->super != meta) 67 | return meta_find_attribute(meta->super, name); 68 | else 69 | return 0; 70 | } 71 | 72 | const meta_event* meta_find_event(const meta* meta, const char* name) 73 | { 74 | assert(meta != NULL && name != NULL); 75 | const meta_event* e = meta->events; 76 | while (e != 0) 77 | { 78 | if (0 == strcmp(name, e->name)) 79 | return e; 80 | e = e->next; 81 | } 82 | if (meta->super != meta) 83 | return meta_find_event(meta->super, name); 84 | else 85 | return 0; 86 | } 87 | 88 | void meta_get(const meta_attribute* attr, const void* object, void* buffer) 89 | { 90 | assert(attr != NULL && object != NULL && buffer != NULL); 91 | switch (attr->type) 92 | { 93 | case MT_SINT32: 94 | *(int*)buffer = *(const int*)((const char*)object + attr->offset); 95 | break; 96 | case MT_FLOAT: 97 | *(float*)buffer = *(const float*)((const char*)object + attr->offset); 98 | break; 99 | case MT_STRING: 100 | *(const char**)buffer = *(const char**)((const char*)object + attr->offset); 101 | break; 102 | default: 103 | assert(false && "unknown type"); 104 | } 105 | } 106 | 107 | void meta_set(const meta_attribute* attr, void* object, const void* buffer) 108 | { 109 | assert(attr != NULL && object != NULL && buffer != NULL); 110 | switch (attr->type) 111 | { 112 | case MT_SINT32: 113 | *(int*)((char*)object + attr->offset) = *(const int*)buffer; 114 | break; 115 | case MT_FLOAT: 116 | *(float*)((char*)object + attr->offset) = *(const float*)buffer; 117 | break; 118 | case MT_STRING: 119 | *(const char**)((char*)object + attr->offset) = *(const char**)buffer; 120 | break; 121 | default: 122 | assert(false && "unknown type"); 123 | } 124 | } 125 | 126 | void meta_call(const meta_event* event, void* object, const void* msg) 127 | { 128 | assert(event != NULL && object != NULL); 129 | event->cb(object, msg); 130 | } -------------------------------------------------------------------------------- /2013/03-SeanMiddleditch-Introspection1/meta.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Sean Middleditch. All right reserved. 2 | // DigiPen Institute of Technology - Game Engine Architecture Club 3 | // Do not use this code for any purpose besides study. Besides 4 | // me not giving you permission, only a lame programmer would use 5 | // this for anything even remotely production quality. 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | typedef struct meta meta; 12 | typedef struct meta_attribute meta_attribute; 13 | typedef struct meta_event meta_event; 14 | typedef enum meta_type meta_type; 15 | 16 | enum meta_type 17 | { 18 | MT_VOID, 19 | MT_SINT32, 20 | MT_FLOAT, 21 | MT_STRING, 22 | }; 23 | 24 | struct meta 25 | { 26 | const char* name; 27 | const meta* super; 28 | const meta* next; 29 | unsigned size; 30 | meta_attribute* attrs; 31 | meta_event* events; 32 | }; 33 | 34 | struct meta_attribute 35 | { 36 | const char* name; 37 | const meta* parent; 38 | const meta_attribute* next; 39 | unsigned offset; 40 | meta_type type; 41 | }; 42 | 43 | typedef void(*meta_event_cb)(void* receiver, const void* msg); 44 | 45 | struct meta_event 46 | { 47 | const char* name; 48 | const meta* parent; 49 | const meta_event* next; 50 | meta_event_cb cb; 51 | }; 52 | 53 | void meta_add(meta* meta); 54 | void meta_add_attribute(meta* meta, meta_attribute* attr); 55 | void meta_add_event(meta* meta, meta_event* event); 56 | 57 | const meta* meta_find(const char* name); 58 | const meta_attribute* meta_find_attribute(const meta* meta, const char* name); 59 | const meta_event* meta_find_event(const meta* meta, const char* name); 60 | 61 | void meta_get(const meta_attribute* attr, const void* object, void* buffer); 62 | void meta_set(const meta_attribute* attr, void* object, const void* buffer); 63 | void meta_call(const meta_event* event, void* object, const void* message); 64 | 65 | #define META(NAME) ((const meta*)&g_meta__ ## NAME) 66 | 67 | #define META_DECLARE(NAME, SUPER) \ 68 | extern meta g_meta__ ## NAME; \ 69 | static const meta* g_super__ ## NAME = META(SUPER); \ 70 | extern void init_meta_attrs__ ## NAME (); \ 71 | extern void init_meta_events__ ## NAME (); \ 72 | extern void init_meta__ ## NAME (); 73 | 74 | #define META_INIT(NAME) (init_meta__ ## NAME ()) 75 | 76 | #define META_BASE_DECLARE(NAME) META_DECLARE(NAME, NAME) 77 | 78 | #define META_DEFINE(NAME) \ 79 | meta g_meta__ ## NAME; \ 80 | \ 81 | void init_meta__ ## NAME () { \ 82 | memset(&g_meta__ ## NAME, 0, sizeof(meta)); \ 83 | g_meta__ ## NAME.name = #NAME; \ 84 | g_meta__ ## NAME.size = sizeof(NAME); \ 85 | g_meta__ ## NAME.super = g_super__ ## NAME; \ 86 | init_meta_attrs__ ## NAME (); \ 87 | init_meta_events__ ## NAME (); \ 88 | meta_add(&g_meta__ ## NAME); \ 89 | } 90 | 91 | #define META_BEGIN_ATTRS(NAME) \ 92 | void init_meta_attrs__ ## NAME () { \ 93 | typedef NAME this_type; \ 94 | meta* this_meta = &g_meta__ ## NAME; \ 95 | meta_attribute attr; \ 96 | (void*)&attr; 97 | 98 | #define META_ATTR(NAME, TYPE) \ 99 | attr.name = #NAME; \ 100 | attr.offset = offsetof(this_type, NAME); \ 101 | attr.type = (TYPE); \ 102 | meta_add_attribute(this_meta, &attr); 103 | 104 | #define META_BEGIN_EVENTS(NAME) \ 105 | void init_meta_events__ ## NAME () { \ 106 | typedef NAME this_type; \ 107 | meta* this_meta = &g_meta__ ## NAME; \ 108 | meta_event event; \ 109 | (void*)&event; 110 | 111 | #define META_EVENT(NAME, FUNCTION) \ 112 | event.name = #NAME; \ 113 | event.cb = (meta_event_cb)&FUNCTION; \ 114 | meta_add_event(this_meta, &event); 115 | 116 | #define META_END_ATTRS() } 117 | #define META_END_EVENTS() } -------------------------------------------------------------------------------- /2013/03-SeanMiddleditch-Introspection1/test.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Sean Middleditch. All right reserved. 2 | // DigiPen Institute of Technology - Game Engine Architecture Club 3 | // Do not use this code for any purpose besides study. Besides 4 | // me not giving you permission, only a lame programmer would use 5 | // this for anything even remotely production quality. 6 | 7 | #include "test.h" 8 | 9 | #include 10 | #include 11 | 12 | META_DEFINE(TestBase) 13 | META_DEFINE(TestDerived1) 14 | META_DEFINE(TestDerived2) 15 | 16 | META_BEGIN_ATTRS(TestBase) 17 | META_ATTR(last_input, MT_STRING) 18 | META_ATTR(counter, MT_SINT32) 19 | META_END_ATTRS() 20 | 21 | META_BEGIN_EVENTS(TestBase) 22 | META_EVENT(input, TestBase_event_input) 23 | META_END_EVENTS() 24 | 25 | META_BEGIN_ATTRS(TestDerived1) 26 | META_ATTR(health, MT_SINT32) 27 | META_ATTR(damage, MT_SINT32) 28 | META_END_ATTRS() 29 | 30 | META_BEGIN_EVENTS(TestDerived1) 31 | META_EVENT(damaged, TestDerived1_event_damaged) 32 | META_END_EVENTS() 33 | 34 | META_BEGIN_ATTRS(TestDerived2) 35 | META_ATTR(x, MT_FLOAT) 36 | META_ATTR(y, MT_FLOAT) 37 | META_END_ATTRS() 38 | 39 | META_BEGIN_EVENTS(TestDerived2) 40 | META_EVENT(jumped, TestDerived2_event_jumped) 41 | META_END_EVENTS() 42 | 43 | void TestBase_event_input(TestBase* base, const char* input) 44 | { 45 | if (base->last_input != NULL && 0 == strcmp(input, base->last_input)) 46 | ++base->counter; 47 | else 48 | { 49 | base->counter = 1; 50 | base->last_input = input; 51 | } 52 | 53 | printf("Input on %p: %s [%d]\n", base, input, base->counter); 54 | } 55 | 56 | void TestDerived1_event_damaged(TestDerived1* d1, const int* amount) 57 | { 58 | printf("Damage %p - %d -> %d [%d]\n", d1, d1->health, d1->health - *amount, *amount); 59 | d1->health -= *amount; 60 | } 61 | 62 | void TestDerived2_event_jumped(TestDerived2* d2, const float* height) 63 | { 64 | printf("Jumped %p [%f]\n", d2, *height); 65 | } -------------------------------------------------------------------------------- /2013/03-SeanMiddleditch-Introspection1/test.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Sean Middleditch. All right reserved. 2 | // DigiPen Institute of Technology - Game Engine Architecture Club 3 | // Do not use this code for any purpose besides study. Besides 4 | // me not giving you permission, only a lame programmer would use 5 | // this for anything even remotely production quality. 6 | 7 | #include "meta.h" 8 | 9 | struct TestBase { 10 | const char* last_input; 11 | int counter; 12 | }; 13 | 14 | struct TestDerived1 { 15 | struct TestBase _base; 16 | 17 | int health; 18 | int damage; 19 | }; 20 | 21 | struct TestDerived2 { 22 | struct TestBase _base; 23 | 24 | float x; 25 | float y; 26 | }; 27 | 28 | void TestBase_event_input(TestBase* base, const char* key); 29 | void TestDerived1_event_damaged(TestDerived1* d1, const int* amount); 30 | void TestDerived2_event_jumped(TestDerived2* d2, const float* height); 31 | 32 | META_BASE_DECLARE(TestBase) 33 | META_DECLARE(TestDerived1, TestBase) 34 | META_DECLARE(TestDerived2, TestBase) -------------------------------------------------------------------------------- /2013/05-SeanMiddleditch-Introspection2/.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | [Dd]ebug/ 46 | [Rr]elease/ 47 | *_i.c 48 | *_p.c 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.vspscc 63 | .builds 64 | *.dotCover 65 | 66 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 67 | #packages/ 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | 76 | # Visual Studio profiler 77 | *.psess 78 | *.vsp 79 | 80 | # ReSharper is a .NET coding add-in 81 | _ReSharper* 82 | 83 | # Installshield output folder 84 | [Ee]xpress 85 | 86 | # DocProject is a documentation generator add-in 87 | DocProject/buildhelp/ 88 | DocProject/Help/*.HxT 89 | DocProject/Help/*.HxC 90 | DocProject/Help/*.hhc 91 | DocProject/Help/*.hhk 92 | DocProject/Help/*.hhp 93 | DocProject/Help/Html2 94 | DocProject/Help/html 95 | 96 | # Click-Once directory 97 | publish 98 | 99 | # Others 100 | [Bb]in 101 | [Oo]bj 102 | sql 103 | TestResults 104 | *.Cache 105 | ClientBin 106 | stylecop.* 107 | ~$* 108 | *.dbmdl 109 | Generated_Code #added for RIA/Silverlight projects 110 | 111 | # Backup & report files from converting an old project file to a newer 112 | # Visual Studio version. Backup files are not needed, because we have git ;-) 113 | _UpgradeReport_Files/ 114 | Backup*/ 115 | UpgradeLog*.XML 116 | 117 | 118 | 119 | ############ 120 | ## Windows 121 | ############ 122 | 123 | # Windows image file caches 124 | Thumbs.db 125 | 126 | # Folder config file 127 | Desktop.ini 128 | 129 | 130 | ############# 131 | ## Python 132 | ############# 133 | 134 | *.py[co] 135 | 136 | # Packages 137 | *.egg 138 | *.egg-info 139 | dist 140 | build 141 | eggs 142 | parts 143 | bin 144 | var 145 | sdist 146 | develop-eggs 147 | .installed.cfg 148 | 149 | # Installer logs 150 | pip-log.txt 151 | 152 | # Unit test / coverage reports 153 | .coverage 154 | .tox 155 | 156 | #Translations 157 | *.mo 158 | 159 | #Mr Developer 160 | .mr.developer.cfg 161 | 162 | # Mac crap 163 | .DS_Store 164 | -------------------------------------------------------------------------------- /2013/05-SeanMiddleditch-Introspection2/C++ Introspection.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngineArchitectureClub/TalkSlides/f326805a649dd765045aec5cae27624934390eb3/2013/05-SeanMiddleditch-Introspection2/C++ Introspection.pdf -------------------------------------------------------------------------------- /2013/05-SeanMiddleditch-Introspection2/Introspection.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Express 2012 for Windows Desktop 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MetaCPP", "MetaCPP.vcxproj", "{588E220B-E1C0-480B-9379-4FAF8F83B4F6}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {588E220B-E1C0-480B-9379-4FAF8F83B4F6}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {588E220B-E1C0-480B-9379-4FAF8F83B4F6}.Debug|Win32.Build.0 = Debug|Win32 14 | {588E220B-E1C0-480B-9379-4FAF8F83B4F6}.Release|Win32.ActiveCfg = Release|Win32 15 | {588E220B-E1C0-480B-9379-4FAF8F83B4F6}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /2013/05-SeanMiddleditch-Introspection2/Meta.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Sean Middleditch 2 | // All rights reserverd. This code is intended for instructional use only and may not be used 3 | // in any commercial works nor in any student projects. 4 | 5 | #include "Meta.h" 6 | 7 | // m_Type defitions for some primitive types we use 8 | META_DEFINE_EXTERN(int); 9 | META_DEFINE_EXTERN(float); 10 | META_DEFINE_EXTERN(double); 11 | META_DEFINE_EXTERN(char); -------------------------------------------------------------------------------- /2013/05-SeanMiddleditch-Introspection2/Meta.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Sean Middleditch 2 | // All rights reserverd. This code is intended for instructional use only and may not be used 3 | // in any commercial works nor in any student projects. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | //! Namespace that contains all introspection types and utilities. 11 | namespace Meta 12 | { 13 | class TypeInfo; 14 | 15 | //! Namespace containing helper code 16 | //! \internal 17 | namespace internal 18 | { 19 | template struct MetaHolder; 20 | 21 | //! \brief Type trait to convert a possibly const reference or pointer to a non-const pointer 22 | template struct to_pointer 23 | { 24 | typedef typename std::remove_const::type>::type>::type* type; 25 | }; 26 | 27 | /*!\ brief Type trait to check if a given type has a GetMeta method. */ 28 | template class has_get_meta 29 | { 30 | template static std::true_type test(decltype(U::GetType())*); 31 | template static std::false_type test(...); 32 | 33 | public: 34 | /*! \brief True if the type has a GetMeta() method, false otherwise. */ 35 | static const bool value = std::is_same(nullptr)), std::true_type>::value; 36 | }; 37 | 38 | /*! \brief Type trait to check if a class has a MetaStaticHolder::s_TypeInfo field. */ 39 | template class has_inline_meta 40 | { 41 | template static std::true_type test(decltype(U::MetaStaticHolder::s_TypeInfo)*); 42 | template static std::false_type test(...); 43 | 44 | public: 45 | /*! \brief True if the type has a GetMeta() method, false otherwise. */ 46 | static const bool value = std::is_same(nullptr)), std::true_type>::value; 47 | }; 48 | 49 | /*! \brief Helper to find the TypeInfo for a type which has a MetaStaticHolder::s_TypeInfo. */ 50 | template struct meta_lookup 51 | { 52 | static const TypeInfo* Get() { return &Type::MetaStaticHolder::s_TypeInfo; } 53 | }; 54 | 55 | /*! \brief Helper to find the TypeInfo for a type which has no MetaStaticHolder::s_TypeInfo. */ 56 | template struct meta_lookup 57 | { 58 | static const TypeInfo* Get() { return &internal::MetaHolder::type>::type>::s_TypeInfo; } 59 | }; 60 | 61 | /*! \brief Helper to retrieve the null TypeInfo for a void type. */ 62 | template <> struct meta_lookup { static const TypeInfo* Get() { return nullptr; } }; 63 | 64 | /*! \brief Helper to retrieve the null TypeInfo for a nullptr_t type. */ 65 | template <> struct meta_lookup { static const TypeInfo* Get() { return nullptr; } }; 66 | 67 | //! \brief Records information about a base type. 68 | struct BaseRecord 69 | { 70 | BaseRecord(const TypeInfo* t, ptrdiff_t o) : type(t), offset(o) { } 71 | 72 | const TypeInfo* type; //!< The type being used 73 | ptrdiff_t offset; // struct destructor 78 | { 79 | static void destruct(void* obj) { static_cast(obj)->~Type(); } 80 | }; 81 | 82 | //! \brief Knows how to move a non-const type. 83 | template struct mover 84 | { 85 | static void move(void* dst, void* src) { new (dst) Type(std::move(*static_cast(src))); } 86 | }; 87 | 88 | //! \brief Knows how to copy a type. 89 | template struct mover 90 | { 91 | static void move(void* dst, void* src) { new (dst) Type(*static_cast(src)); } 92 | }; 93 | } 94 | 95 | /*! \brief Get the TypeInfo for a specific type. */ 96 | template const TypeInfo* Get() { return internal::meta_lookup::value>::Get(); } 97 | 98 | /*! \brief Get the TypeInfo for a specific instance supporting a GetMeta() method, usually used/needed in polymorphic interfaces. */ 99 | template typename std::enable_if< internal::has_get_meta::value, const TypeInfo*>::type Get(const Type* type) { return type->getMeta(); } 100 | 101 | /*! \brief Get the TypeInfo for a specific instance which has no GetMeta() method and hence no support for polymorphism of introspection. */ 102 | template typename std::enable_if::value, const TypeInfo*>::type Get(const Type*) { return Get(); } 103 | 104 | /*! \brief Get the TypeInfo for a specific instance supporting a GetMeta() method, usually used/needed in polymorphic interfaces. */ 105 | template typename std::enable_if::value && internal::has_get_meta::value, const TypeInfo*>::type Get(const Type& type) { return type.getMeta(); } 106 | 107 | /*! \brief Get the TypeInfo for a specific instance which has no GetMeta() method and hence no support for polymorphism of introspection. */ 108 | template typename std::enable_if::value && !internal::has_get_meta::value, const TypeInfo*>::type Get(const Type&) { return Get(); } 109 | 110 | //! \brief Represents a specific C++ type with qualifiers (const, reference, pointer, etc.) 111 | struct TypeRecord 112 | { 113 | enum Qualifier //!< Qualifiers (not quite correct C++ terminology) specifying how the type is used 114 | { 115 | Void, //!< This is a void value and may not be access at all 116 | Value, //!< The encoded value is not a by-reference type but is a by-copy type and may not be reassigned. 117 | Pointer, // struct make_type_record { static const TypeRecord type() { return TypeRecord(Get(), TypeRecord::Value); } }; 132 | 133 | //! \brief Construct a TypeRecord for a specific type by pointer 134 | template struct make_type_record { static const TypeRecord type() { return TypeRecord(Get(), TypeRecord::Pointer); } }; 135 | 136 | //! \brief Construct a TypeRecord for a specific type by const pointer 137 | template struct make_type_record { static const TypeRecord type() { return TypeRecord(Get(), TypeRecord::ConstPointer); } }; 138 | 139 | //! \brief Construct a TypeRecord for a specific type by reference 140 | template struct make_type_record { static const TypeRecord type() { return TypeRecord(Get(), TypeRecord::Pointer); } }; 141 | 142 | //! \brief Construct a TypeRecord for a specific type by const reference 143 | template struct make_type_record { static const TypeRecord type() { return TypeRecord(Get(), TypeRecord::ConstPointer); } }; 144 | 145 | //! \brief Construct a TypeRecord for void 146 | template <> struct make_type_record { static const TypeRecord type() { return TypeRecord(nullptr, TypeRecord::Void); } }; 147 | 148 | template struct make_any; 149 | } 150 | 151 | //! \brief Holds any type of value that can be handled by the introspection system 152 | class Any 153 | { 154 | private: 155 | union 156 | { 157 | double _align_me; //!< force allignment 158 | char m_Data[4 * sizeof(float)]; //!< large enough for 4 floats, e.g. a vec4 159 | void* m_Ptr; //!< convenien 160 | }; 161 | TypeRecord m_TypeRecord; //!< Type record information stored in this Any 162 | typedef void (*Destructor)(void*); //!< Type of the destructor function 163 | typedef void (*Mover)(void*, void*); //!< Type of the mover function 164 | Destructor m_Destructor; //!< Destructor for the bound type 165 | Mover m_Mover; //!< Mover for the bound type 166 | 167 | //! \brief Deleted copy constructor 168 | Any(const Any&); // = delete 169 | //! \brief Deleted copy assignment 170 | void operator=(const Any&); // = delete 171 | 172 | public: 173 | //! \brief Constructs an Any that holds nothing 174 | Any() : m_Ptr(nullptr), m_Destructor(nullptr), m_Mover(nullptr) { } 175 | 176 | //! \brief Moves one Any into another 177 | Any(Any&& src) : m_Destructor(nullptr) { *this = std::move(src); } 178 | 179 | //! \brief Moves one Any into another 180 | Any& operator=(Any&& src) 181 | { 182 | if (this != &src) 183 | { 184 | if (m_Destructor != nullptr) 185 | m_Destructor(m_Data); 186 | m_Mover = src.m_Mover; 187 | m_Destructor = src.m_Destructor; 188 | m_Mover(m_Data, src.m_Data); 189 | if (m_Destructor != nullptr) 190 | m_Destructor(src.m_Data); 191 | src.m_Destructor = nullptr; 192 | src.m_Mover = nullptr; 193 | } 194 | return *this; 195 | } 196 | 197 | //! \brief Constucts an Any that contains an object 198 | template Any(const Type& obj) : m_TypeRecord(internal::make_type_record::type()), m_Destructor(&internal::destructor::destruct), m_Mover(&internal::mover::move) { static_assert(sizeof(Type) <= sizeof(m_Data), "Type is too large"); new (m_Data) Type(obj); } 199 | 200 | //! \brief Constucts an Any that points at a non-const object 201 | template Any(Type* obj) : m_Ptr(obj), m_TypeRecord(internal::make_type_record::type()), m_Destructor(nullptr), m_Mover(&internal::mover::move) { } 202 | 203 | //! \brief Constucts an Any that points at a const object 204 | template Any(const Type* obj) : m_Ptr(const_cast(obj)), m_TypeRecord(internal::make_type_record::type()), m_Destructor(nullptr), m_Mover(&internal::mover::move) { } 205 | 206 | //! \brief Cleans up the value stored in the Any if necessary 207 | ~Any() 208 | { 209 | if (m_Destructor != nullptr) 210 | m_Destructor(m_Data); 211 | } 212 | 213 | //! \brief Checks if the value should be considered a constant when dereferenced. 214 | bool IsConst() const { return m_TypeRecord.qualifier != TypeRecord::Pointer; } 215 | 216 | //! \brief Gets the TypeInfo for the value stored in the Any, if any 217 | const TypeInfo* GetType() const { return m_TypeRecord.type; } 218 | 219 | //! \brief Gets the TypeRecord information associated with the value stored in this Any 220 | const TypeRecord& GetTypeRecord() const { return m_TypeRecord; } 221 | 222 | //! \brief Retrieves a pointer to the type stored in this Any 223 | void* GetPointer() const 224 | { 225 | switch (m_TypeRecord.qualifier) 226 | { 227 | case TypeRecord::Value: return const_cast(m_Data); 228 | case TypeRecord::Pointer: 229 | case TypeRecord::ConstPointer: 230 | return m_Ptr; 231 | default: return nullptr; 232 | } 233 | } 234 | 235 | //! \brief Retrieves a pointer to the type stored in this Any adjusted by base type offset if necessary 236 | inline void* GetPointer(const TypeInfo* type) const; 237 | 238 | //! \brief Retrieves a pointer to the type stored in this Any adjusted by base type offset if necessary 239 | template Type* GetPointer() const { return static_cast(GetPointer(Get())); } 240 | 241 | //! \brief Retrieves a reference to the type stored in this Any adjusted by base type offset if necessary 242 | template Type& GetReference() const { return *static_cast(GetPointer(Get())); } 243 | 244 | template friend struct internal::make_any; 245 | }; 246 | 247 | namespace internal 248 | { 249 | template struct make_any { static Any make(Type value) { return Any(value); } }; 250 | template struct make_any { static Any make(Type& value) { return Any(&value); } }; 251 | } 252 | 253 | //! \brief Represents a member variable of a type. */ 254 | class Member 255 | { 256 | const char* m_Name; //!< The name of this variable. 257 | const TypeInfo* m_Owner; //!< The type this member variable belongs to. 258 | const TypeInfo* m_Type; //!< The type of this member variable. 259 | 260 | protected: 261 | //! \brief Constructor for a member variable. 262 | //! \param name The name of the member. 263 | //! \parm type The type of the member. 264 | Member(const char* name, const TypeInfo* type) : m_Name(name), m_Type(type) { } 265 | virtual ~Member() { } 266 | 267 | //! \brief Reimplement to get the value of a member variable. 268 | //! \param obj Object that owns the member. 269 | //! \returns Value of the member. 270 | virtual Any DoGet(const Any& obj) const = 0; 271 | 272 | //! \brief Reimplement to set the value of a member variable. 273 | //! \param obj Object that owns the member. 274 | //! \param in Value to set to. 275 | virtual void DoSet(const Any& obj, const Any& in) const = 0; 276 | 277 | //! \brief Sets the owner of the member variable. Only meant to be called by TypeInfo. 278 | void SetOwner(const TypeInfo* owner) { m_Owner = owner; } 279 | 280 | public: 281 | //! \brief Checks if the variable is mutable (the value can be set). 282 | virtual bool IsMutable() const = 0; 283 | 284 | //! \brief Retrieves the name of the member variable. 285 | const char* GetName() const { return m_Name; } 286 | 287 | //! \brief Retrieves the type of the member variable. 288 | const TypeInfo* GetType() const { return m_Type; } 289 | 290 | //! \brief Retrieves the owner of the member variable. 291 | const TypeInfo* GetOwner() const { return m_Owner; } 292 | 293 | //! \brief Tests if the variable value can be retrieved into the given output any ref. 294 | //! \param obj An instance of the owner type. 295 | //! \returns True if Get is safe to call with these arguments, false otherwise. 296 | inline bool CanGet(const Any& obj) const; 297 | 298 | //! \brief Retrieves the value of the member variable. 299 | //! \param obj An instance of the owner type. 300 | inline Any Get(const Any& obj) const; 301 | 302 | //! \brief Tests if the variable can be sets from the given input value. 303 | //! \param obj An instance of the owner type. 304 | //! \param in An instance of the variable type to set. 305 | //! \returns True if Set is safe to call with these arguments, false otherwise. 306 | inline bool CanSet(const Any& obj, const Any& in) const; 307 | 308 | //! \brief Sets the value of the member variable. 309 | //! \param obj An instance of the owner type. 310 | //! \param in An instance of the variable type to set. 311 | inline void Set(const Any& obj, const Any& in) const; 312 | 313 | friend class TypeInfo; 314 | }; 315 | 316 | namespace internal 317 | { 318 | template struct any_cast_helper { static const Type& cast(const Any& any) { return any.GetReference(); } }; 319 | template struct any_cast_helper { static Type* cast(const Any& any) { return any.GetPointer(); } }; 320 | template struct any_cast_helper { static const Type *cast(const Any& any) { return any.GetPointer(); } }; 321 | template struct any_cast_helper { static Type& cast(const Any& any) { return any.GetReference(); } }; 322 | template struct any_cast_helper { static const Type& cast(const Any& any) { return any.GetReference(); } }; 323 | } 324 | 325 | //! \brief Attempts to convert an any reference into a pointer to the actual C++ type. 326 | //! \param any An Any reference to try to convert. 327 | template Type any_cast(const Any& any) 328 | { 329 | return internal::any_cast_helper::cast(any); 330 | } 331 | 332 | //! \brief A method attach to a type. 333 | class Method 334 | { 335 | const char* m_Name; //!< The name of the method. 336 | const TypeInfo* m_Owner; //!< The type that owns the method. 337 | 338 | //! \brief Sets the owner type. Only to be called by TypeInfo. 339 | void SetOwner(const TypeInfo* m_Type) { m_Owner = m_Type; } 340 | 341 | protected: 342 | //! \brief Constuctor for the method. 343 | //! \param The name of the method. 344 | Method(const char* name) : m_Name(name) { } 345 | virtual ~Method() { } 346 | 347 | //! \brief Override to implement calling the method. 348 | //! \parma obj The memory location of an instance of the owner object. 349 | //! \param out The memory location that the return value, if any, is stored. 350 | //! \param argc The number of arguments to pass in to the method. 351 | //! \param argv A list of any references for the arguments. 352 | //! \returns The return value as an Any 353 | virtual Any DoCall(const Any& obj, int argc, const Any* argv) const = 0; 354 | 355 | public: 356 | //! \brief Get the name of the method. 357 | const char* GetName() const { return m_Name; } 358 | 359 | //! \brief Get the owner type of the method. 360 | const TypeInfo* GetOwner() const { return m_Owner; } 361 | 362 | //! \brief Get the TypeInfo of the return value. 363 | virtual TypeRecord GetReturnType() const = 0; 364 | 365 | //! \brief Get the TypeInfo of the paramater at the ith index. 366 | //! \brief i The index of the parameter, starting from 0. 367 | virtual TypeRecord GetParamType(int i) const = 0; 368 | 369 | //! \brief Get the number of parameters of the method. 370 | virtual int GetArity() const = 0; 371 | 372 | //! \brief Invoke the method (with a return value). 373 | //! \param obj The instance of the object to call the method on. 374 | //! \param out The location the return value is assigned to. Must be a validate instance of the type. 375 | //! \param argc The number of arguments to pass in to the method. 376 | //! \param argv A list of any references for the arguments. 377 | //! \returns The return value as an Any 378 | inline Any Call(const Any& obj, int argc, const Any* argv) const; 379 | 380 | //! \brief Invoke the method (with a return value). 381 | //! \param obj The instance of the object to call the method on. 382 | //! \param argc The number of arguments to pass in to the method. 383 | //! \param argv A list of any references for the arguments. 384 | //! \returns True if the parameters are valid for a call to succeed. 385 | inline bool CanCall(const Any& obj, int argc, const Any* argv) const; 386 | 387 | friend class TypeInfo; 388 | }; 389 | 390 | //! \brief Encodes information about a type. 391 | class TypeInfo 392 | { 393 | const char* m_Name; //!< The name of the type. 394 | 395 | protected: 396 | std::vector m_Bases; //!< The list of base types. 397 | std::vector m_Members; //!< The list of all members of this type. 398 | std::vector m_Methods; //!< The list of all methods of this type. 399 | 400 | public: 401 | //! \brief Constructor for type info. 402 | //! \param name The name of the type. 403 | TypeInfo(const char* name) 404 | { 405 | int nested = 0; 406 | // trim off the namespaces from the name; account for possible template specializations 407 | for (const char* m_Name = name + std::strlen(name) - 1; m_Name != name; --m_Name) 408 | { 409 | if (*m_Name == '>') 410 | ++nested; 411 | else if (*m_Name == '<') 412 | --nested; 413 | else if (nested == 0 && *m_Name == ':') 414 | break; 415 | } 416 | } 417 | 418 | //! \brief Copy constructor for type info. 419 | TypeInfo(const TypeInfo& type) : m_Name(type.m_Name), m_Bases(type.m_Bases), m_Members(type.m_Members), m_Methods(type.m_Methods) 420 | { 421 | for (auto s_TypeInfo : m_Members) 422 | s_TypeInfo->SetOwner(this); 423 | 424 | for (auto s_TypeInfo : m_Methods) 425 | s_TypeInfo->SetOwner(this); 426 | } 427 | 428 | //! \brief Tests if this type is derived from another type. 429 | //! \parm base The type to test if this is derived from. 430 | //! \returns True if this type derives from base either directly or indirectly. 431 | bool IsDerivedFrom(const TypeInfo* base) const 432 | { 433 | for (auto& b : m_Bases) 434 | if (b.type == base || b.type->IsDerivedFrom(base)) 435 | return true; 436 | 437 | return false; 438 | } 439 | 440 | //! \brief Tests is this type is derived from anothe type or is the same type. 441 | //! \parm base The type to test if this is derived from or the same as. 442 | //! \returns True if this type is equal to or derives from base either directly or indirectly. 443 | bool IsSameOrDerivedFrom(const TypeInfo* base) const 444 | { 445 | if (base == this) 446 | return true; 447 | if (IsDerivedFrom(base)) 448 | return true; 449 | return false; 450 | } 451 | 452 | //! \brief Adjust a pointer of this type to a derived type. 453 | //! \param base The base type to convert to. 454 | //! \param ptr The pointer to convert. 455 | //! \returns The adjusted pointer, or nullptr if the adjustment is illegal (the given base type is not a base of the type). 456 | void* Adjust(const TypeInfo* base, void* ptr) const 457 | { 458 | if (base == this) 459 | return ptr; 460 | 461 | for (auto& b : m_Bases) 462 | { 463 | void* rs = b.type->Adjust(base, static_cast(ptr) + b.offset); 464 | if (rs != nullptr) 465 | return rs; 466 | } 467 | 468 | return nullptr; 469 | } 470 | 471 | //! \brief Adjust a pointer of this type to a derived type. 472 | //! \param base The base type to convert to. 473 | //! \param ptr The pointer to convert. 474 | //! \returns The adjusted pointer, or nullptr if the adjustment is illegal (the given base type is not a base of the type). 475 | const void* Adjust(const TypeInfo* base, const void* ptr) const 476 | { 477 | return Adjust(base, const_cast(ptr)); 478 | } 479 | 480 | //! \brief Get the name of the type. 481 | const char* GetName() const { return m_Name; } 482 | 483 | //! \brief Find a member of this type or any base type. 484 | //! \param name The name of the member to look up. 485 | //! \returns The Member named by name or nullptr if no such member exists. 486 | Member* FindMember(const char* name) const 487 | { 488 | for (auto s_TypeInfo : m_Members) 489 | if (std::strcmp(s_TypeInfo->GetName(), name) == 0) 490 | return s_TypeInfo; 491 | 492 | for (auto& b : m_Bases) 493 | { 494 | auto s_TypeInfo = b.type->FindMember(name); 495 | if (s_TypeInfo != nullptr) 496 | return s_TypeInfo; 497 | } 498 | 499 | return nullptr; 500 | } 501 | 502 | //! \brief Find a method of this type or any base type. 503 | //! \param name The name of the method to look up. 504 | //! \returns The Method named by name or nullptr if no such method exists. 505 | Method* FindMethod(const char* name) const 506 | { 507 | for (auto s_TypeInfo : m_Methods) 508 | if (std::strcmp(s_TypeInfo->GetName(), name) == 0) 509 | return s_TypeInfo; 510 | 511 | for (auto& b : m_Bases) 512 | { 513 | auto s_TypeInfo = b.type->FindMethod(name); 514 | if (s_TypeInfo != nullptr) 515 | return s_TypeInfo; 516 | } 517 | 518 | return nullptr; 519 | } 520 | }; 521 | 522 | inline void* Any::GetPointer(const TypeInfo* type) const 523 | { 524 | return m_TypeRecord.type->Adjust(type, GetPointer()); 525 | } 526 | 527 | bool Member::CanGet(const Any& obj) const 528 | { 529 | if (!obj.GetType()->IsSameOrDerivedFrom(m_Owner)) 530 | return false; 531 | return true; 532 | } 533 | 534 | Any Member::Get(const Any& obj) const 535 | { 536 | return DoGet(obj); 537 | } 538 | 539 | bool Member::CanSet(const Any& obj, const Any& in) const 540 | { 541 | if (!IsMutable()) 542 | return false; 543 | if (!obj.GetType()->IsSameOrDerivedFrom(m_Owner)) 544 | return false; 545 | if (m_Type != in.GetType()) 546 | return false; 547 | if (obj.IsConst()) 548 | return false; 549 | return true; 550 | } 551 | 552 | void Member::Set(const Any& obj, const Any& in) const 553 | { 554 | DoSet(obj, in); 555 | } 556 | 557 | Any Method::Call(const Any& obj, int argc, const Any* argv) const 558 | { 559 | return DoCall(obj, argc, argv); 560 | } 561 | 562 | bool Method::CanCall(const Any& obj, int argc, const Any* argv) const 563 | { 564 | if (!obj.GetType()->IsSameOrDerivedFrom(m_Owner)) 565 | return false; 566 | 567 | if (argc != GetArity()) 568 | return false; 569 | 570 | for (int i = 0; i < argc; ++i) 571 | { 572 | auto tr = GetParamType(i); 573 | if (argv[i].GetType() != tr.type) 574 | return false; 575 | if (argv[i].IsConst() && tr.qualifier == TypeRecord::Pointer) 576 | return false; 577 | } 578 | 579 | return true; 580 | } 581 | 582 | namespace internal 583 | { 584 | //! \brief A member that is accessed directly in memory. 585 | //! \internal 586 | template class TypeMember : public Member 587 | { 588 | MemberType Type::*m_Member; 589 | 590 | public: 591 | TypeMember(const char* name, const TypeInfo* type, MemberType Type::*member) : Member(name, type), m_Member(member) { } 592 | 593 | virtual bool IsMutable() const override { return true; } 594 | 595 | virtual Any DoGet(const Any& obj) const override 596 | { 597 | return internal::make_any::make(obj.GetPointer()->*m_Member); 598 | } 599 | 600 | virtual void DoSet(const Any& obj, const Any& in) const override 601 | { 602 | obj.GetPointer()->*m_Member = in.GetReference(); 603 | } 604 | }; 605 | 606 | //! \brief A member that is accessed by a getter function. 607 | //! \internal 608 | template class TypeMemberGetter : public Member 609 | { 610 | Getter m_Getter; 611 | 612 | public: 613 | TypeMemberGetter(const char* name, const TypeInfo* type, Getter getter) : Member(name, type), m_Getter(getter) { } 614 | 615 | virtual bool IsMutable() const override { return false; } 616 | 617 | virtual Any DoGet(const Any& obj) const override 618 | { 619 | return internal::make_any(nullptr)->*m_Getter)())>::make(((obj.GetPointer())->*m_Getter)()); 620 | } 621 | 622 | virtual void DoSet(const Any& obj, const Any& in) const override { } 623 | }; 624 | 625 | //! \brief A member that is accessed by a getter function and setter function. 626 | //! \internal 627 | template class TypeMemberGetterSetter : public TypeMemberGetter 628 | { 629 | Setter m_Setter; 630 | 631 | public: 632 | TypeMemberGetterSetter(const char* name, const TypeInfo* type, Getter getter, Setter setter) : TypeMemberGetter(name, type, getter), m_Setter(setter) { } 633 | 634 | virtual bool IsMutable() const override { return true; } 635 | 636 | virtual void DoSet(const Any& obj, const Any& in) const override 637 | { 638 | (obj.GetPointer()->*m_Setter)(in.GetReference()); 639 | } 640 | }; 641 | 642 | // helpers to deal with the possibility of a void return m_Type 643 | template struct do_call0 644 | { 645 | static Any call(ReturnType (Type::*method)(), Type* obj, int argc, const Any* argv) 646 | { 647 | return internal::make_any::make((obj->*method)()); 648 | } 649 | }; 650 | 651 | template struct do_call0 652 | { 653 | static Any call(void (Type::*method)(), Type* obj, int argc, const Any* argv) 654 | { 655 | (obj->*method)(); 656 | return Any(); 657 | } 658 | }; 659 | 660 | //! \brief A method with no parameters. 661 | template 662 | class Method0 : public Method 663 | { 664 | ReturnType (Type::*method)(); 665 | 666 | public: 667 | virtual TypeRecord GetReturnType() const override { return internal::make_type_record::type(); } 668 | 669 | virtual TypeRecord GetParamType(int name) const override { return TypeRecord(); } 670 | 671 | virtual int GetArity() const override { return 0; } 672 | 673 | Method0(const char* name, ReturnType (Type::*method)()) : Method(name), method(method) { } 674 | 675 | virtual Any DoCall(const Any& obj, int argc, const Any* argv) const override { return do_call0::call(method, obj.GetPointer(), argc, argv); } 676 | }; 677 | 678 | // helpers to deal with the possibility of a void return m_Type 679 | template struct do_call1 680 | { 681 | static Any call(ReturnType (Type::*method)(ParamType0), Type* obj, int argc, const Any* argv) 682 | { 683 | return internal::make_any::make((obj->*method)(any_cast(argv[0]))); 684 | } 685 | }; 686 | 687 | template struct do_call1 688 | { 689 | static Any call(void (Type::*method)(ParamType0), Type* obj, int argc, const Any* argv) 690 | { 691 | (obj->*method)(any_cast(argv[0])); 692 | return Any(); 693 | } 694 | }; 695 | 696 | //! \brief A method with one parameter. 697 | template 698 | class Method1 : public Method 699 | { 700 | ReturnType (Type::*method)(ParamType0); 701 | 702 | public: 703 | virtual TypeRecord GetReturnType() const override { return internal::make_type_record::type(); } 704 | 705 | virtual TypeRecord GetParamType(int name) const override { if (name == 0) return internal::make_type_record::type(); else return TypeRecord(); } 706 | 707 | virtual int GetArity() const override { return 1; } 708 | 709 | Method1(const char* name, ReturnType (Type::*method)(ParamType0)) : Method(name), method(method) { } 710 | 711 | virtual Any DoCall(const Any& obj, int argc, const Any* argv) const override { return do_call1::call(method, obj.GetPointer(), argc, argv); } 712 | }; 713 | 714 | // helpers to deal with the possibility of a void return m_Type 715 | template struct do_call2 716 | { 717 | static Any call(ReturnType (Type::*method)(ParamType0, ParamType1), Type* obj, int argc, const Any* argv) 718 | { 719 | return internal::make_any::make((obj->*method)(any_cast(argv[0]), any_cast(argv[1]))); 720 | } 721 | }; 722 | 723 | template struct do_call2 724 | { 725 | static Any call(void (Type::*method)(ParamType0, ParamType1), Type* obj, int argc, const Any* argv) 726 | { 727 | (obj->*method)(any_cast(argv[0]), any_cast(argv[1])); 728 | return Any(); 729 | } 730 | }; 731 | 732 | //! \brief A method with two parameters. 733 | template 734 | class Method2 : public Method 735 | { 736 | ReturnType (Type::*method)(ParamType0, ParamType1); 737 | 738 | public: 739 | virtual TypeRecord GetReturnType() const override { return internal::make_type_record::type(); } 740 | 741 | virtual TypeRecord GetParamType(int name) const override { if (name == 0) return internal::make_type_record::type(); else if (name == 1) return internal::make_type_record::type(); else return TypeRecord(); } 742 | 743 | virtual int GetArity() const override { return 2; } 744 | 745 | Method2(const char* name, ReturnType (Type::*method)(ParamType0, ParamType1)) : Method(name), method(method) { } 746 | 747 | virtual Any DoCall(const Any& obj, int argc, const Any* argv) const override { return do_call2::call(method, obj.GetPointer(), argc, argv); } 748 | }; 749 | 750 | //! \brief Holder for TypeInfo external to a type, used when adding introspection to types that cannot be modified. 751 | template struct MetaHolder 752 | { 753 | static const TypeInfo s_TypeInfo; 754 | }; 755 | 756 | //! \brief Utility class to initialize a TypeInfo, invoked by META_DEFINE_EXTERN or META_DEFINE. 757 | template struct TypedInfo : public TypeInfo 758 | { 759 | //! \brief Construct the type. 760 | TypedInfo(const char* name) : TypeInfo(name) { } 761 | 762 | //! \brief Add a base to this type. 763 | template TypedInfo& base() { static_assert(std::is_base_of::value && !std::is_same::value, "incorrect base"); m_Bases.push_back(BaseRecord(Get(), reinterpret_cast(static_cast(reinterpret_cast(0x1000))) - 0x1000)); return *this; } 764 | 765 | //! \brief Add a read-write member definition to this type which will be accessed directly. 766 | //! \param name The name of the member. 767 | //! \param member A pointer to the member. 768 | template typename std::enable_if::value, TypedInfo&>::type member(const char* name, MemberType Type::*member) { m_Members.push_back(new TypeMember::type>(name, Get(), member)); return *this; } 769 | 770 | //! \brief Add a read-only member definition to this type which will be accessed by a getter member function. 771 | //! \param name The name of the member. 772 | //! \param getter A pointer to the getter member function. 773 | template TypedInfo& member(const char* name, MemberType (Type::*getter)() const) { m_Members.push_back(new TypeMemberGetter::type, MemberType (Type::*)() const>(name, Get(), getter)); return *this; } 774 | 775 | //! \brief Add a read-only member definition to this type which will be accessed by a getter member function. Allows passing nullptr as a third parameter to indicate the lack of a setter. 776 | //! \param name The name of the member. 777 | //! \param getter A pointer to the getter member function. 778 | template TypedInfo& member(const char* name, MemberType (Type::*getter)() const, std::nullptr_t) { m_Members.push_back(new TypeMemberGetter::type, MemberType (Type::*)() const>(name, Get(), getter)); return *this; } 779 | 780 | //! \brief Add a read-write member definition to this type which will be accessed by getter and setter member functions. 781 | //! \param name The name of the member. 782 | //! \param getter A pointer to the getter member function. 783 | //! \param setter A pointer to the setter member function. 784 | template TypedInfo& member(const char* name, MemberType (Type::*getter)() const, SetterReturnType (Type::*setter)(SetterType)) { m_Members.push_back(new TypeMemberGetterSetter::type, MemberType (Type::*)() const, SetterReturnType (Type::*)(SetterType)>(name, Get(), getter, setter)); return *this; } 785 | 786 | // add method definitions for a m_Type 787 | template TypedInfo& method(const char* name, ReturnType (Type::*method)()) { m_Methods.push_back(new Method0(name, method)); return *this; } 788 | template TypedInfo& method(const char* name, ReturnType (Type::*method)(ParamType0)) { m_Methods.push_back(new Method1(name, method)); return *this; } 789 | template TypedInfo& method(const char* name, ReturnType (Type::*method)(ParamType0, ParamType1)) { m_Methods.push_back(new Method2(name, method)); return *this; } 790 | }; 791 | 792 | //! \brief Utility class to initialize a TypeInfo, invoked by META_DEFINE_EXTERN, but which cannot have base types, member variables, or member functions (e.g. primitive types). 793 | template struct TypedInfo : public TypeInfo 794 | { 795 | TypedInfo(const char* name) : TypeInfo(name) { } 796 | }; 797 | } 798 | } 799 | 800 | //! \brief Add to a type declaration to make it participate in polymorphic type lookups and to allow binding private members and methods. 801 | //! \param T The type to annotate. 802 | #define META_DECLARE(T) \ 803 | public: \ 804 | struct MetaStaticHolder { static const ::Meta::TypeInfo s_TypeInfo; }; \ 805 | virtual const ::Meta::TypeInfo* GetType() const { return &MetaStaticHolder::s_TypeInfo; } 806 | 807 | //! \brief Put outside of any declaration to begin annotating a type. 808 | //! \param T The type to annotate. 809 | #define META_DEFINE_EXTERN(T) template<> const ::Meta::TypeInfo Meta::internal::MetaHolder::s_TypeInfo = ::Meta::internal::TypedInfo::value>(#T) 810 | 811 | //! \brief Put outside of any declaration to begin annotating a type marked up with META_DECLARE(T) 812 | //! \param T The type to annotate. 813 | #define META_DEFINE(T) const ::Meta::TypeInfo T::MetaStaticHolder::s_TypeInfo = ::Meta::internal::TypedInfo(#T) -------------------------------------------------------------------------------- /2013/05-SeanMiddleditch-Introspection2/MetaCPP.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {588E220B-E1C0-480B-9379-4FAF8F83B4F6} 15 | MetaCPP 16 | 17 | 18 | 19 | Application 20 | true 21 | v110 22 | MultiByte 23 | 24 | 25 | Application 26 | false 27 | v110 28 | true 29 | MultiByte 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | Level3 45 | Disabled 46 | true 47 | 48 | 49 | true 50 | 51 | 52 | 53 | 54 | Level3 55 | MaxSpeed 56 | true 57 | true 58 | true 59 | 60 | 61 | true 62 | true 63 | true 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /2013/05-SeanMiddleditch-Introspection2/MetaCPP.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | -------------------------------------------------------------------------------- /2013/05-SeanMiddleditch-Introspection2/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Sean Middleditch 2 | // All rights reserverd. This code is intended for instructional use only and may not be used 3 | // in any commercial works nor in any student projects. 4 | 5 | #include "Meta.h" 6 | 7 | #include 8 | #include 9 | 10 | // a test class 11 | class A1 12 | { 13 | int a; 14 | float b; 15 | 16 | int bar(float method) { return (int)(method * 0.5f); } 17 | float baz(double d, char is_const) { return d > (double)is_const ? (float)(d * 0.5) : 0.f; } 18 | 19 | public: 20 | int getA() const { return a; } 21 | void setA(int _) { a = _; } 22 | 23 | float getB() const { return b; } 24 | 25 | void foo() { a *= 3; } 26 | 27 | META_DECLARE(A); 28 | }; 29 | 30 | // another test 31 | class A2 32 | { 33 | int d; 34 | std::string name; 35 | 36 | public: 37 | int getD() const { return d; } 38 | void setD(int _) { d = _; } 39 | 40 | void setName(const std::string& _) { name = _; } 41 | const std::string& getName() const { return name; } 42 | 43 | void gaz() { assert(d == 0xDEADBEEF); } 44 | }; 45 | 46 | // another test, with derivation 47 | class B : public A1, public A2 48 | { 49 | float gar(float m) { return c += m; } 50 | 51 | public: 52 | float c; 53 | 54 | META_DECLARE(B); 55 | }; 56 | 57 | // a test with extern Get 58 | namespace TestC 59 | { 60 | struct C 61 | { 62 | float x, y; 63 | }; 64 | } 65 | 66 | // create m_Type infos 67 | META_DEFINE_EXTERN(std::string); 68 | 69 | META_DEFINE(A1) 70 | .member("a", &A1::a) // note that we can bind private m_Members with this style of Get 71 | .member("b", &A1::b) 72 | .member("a2", &A1::getA) 73 | .member("a3", &A1::getA, nullptr) 74 | .member("a4", &A1::getA, &A1::setA) 75 | .method("foo", &A1::foo) 76 | .method("bar", &A1::bar) 77 | .method("baz", &A1::baz); 78 | 79 | META_DEFINE_EXTERN(A2) 80 | .member("d", &A2::getD, &A2::setD) 81 | .member("name", &A2::getName, &A2::setName) 82 | .method("setName", &A2::setName) 83 | .method("gaz", &A2::gaz); 84 | 85 | META_DEFINE(B) 86 | .base() 87 | .base() 88 | .member("c", &B::c) 89 | .method("gar", &B::gar); 90 | 91 | META_DEFINE_EXTERN(TestC::C) 92 | .member("x", &TestC::C::x) 93 | .member("y", &TestC::C::y); 94 | 95 | // tests that a value can be round-tripped into a member variable 96 | template static void test_rw_member(T& obj, const char* name, const U& value) 97 | { 98 | auto m = Meta::Get(obj)->FindMember(name); 99 | assert(m != nullptr); 100 | Meta::Any a(&value); 101 | assert(m->CanSet(&obj, a)); 102 | m->Set(&obj, a); 103 | assert(m->CanGet(&obj)); 104 | U test = Meta::any_cast(m->Get(&obj)); 105 | assert(test == value); 106 | } 107 | 108 | // tests that a member variable has a particular value 109 | template static void test_ro_member(T& obj, const char* name, const U& value) 110 | { 111 | auto m = Meta::Get(obj)->FindMember(name); 112 | assert(m != nullptr); 113 | assert(m->CanGet(&obj)); 114 | U test = Meta::any_cast(m->Get(&obj)); 115 | assert(test == value); 116 | } 117 | 118 | // tests that a method with no return value or parameters can be invoked 119 | template static void test_method(T& obj, const char* name) 120 | { 121 | auto m = Meta::Get(obj)->FindMethod(name); 122 | assert(m != nullptr); 123 | assert(m->CanCall(&obj, 0, nullptr)); 124 | m->Call(&obj, 0, nullptr); 125 | } 126 | 127 | // tests that a method with one parameter results in a specific return value 128 | template static void test_method(T& obj, const char* name, const R& value, const P& p) 129 | { 130 | auto m = Meta::Get(obj)->FindMethod(name); 131 | assert(m != nullptr); 132 | Meta::Any argv[1] = { p }; 133 | assert(m->CanCall(&obj, 1, argv)); 134 | auto r = m->Call(&obj, 1, argv); 135 | assert(r.GetType() == Meta::Get()); 136 | assert(r.GetReference() == value); 137 | } 138 | 139 | // tests that a method with two parameters results in a specific return value 140 | template static void test_method(T& obj, const char* name, const R& value, const P& p, const P2& p2) 141 | { 142 | auto m = Meta::Get(obj)->FindMethod(name); 143 | assert(m != nullptr); 144 | Meta::Any argv[2] = { &p, &p2 }; 145 | assert(m->CanCall(&obj, 2, argv)); 146 | auto r = m->Call(&obj, 2, argv); 147 | assert(r.GetType() == Meta::Get()); 148 | assert(r.GetReference() == value); 149 | } 150 | 151 | static void test_any() 152 | { 153 | const int& ir = 0xDEADC0DE; 154 | Meta::Any a1(&ir); 155 | assert(a1.GetPointer() == &ir); 156 | 157 | int i = 0xBEEF1337; 158 | Meta::Any a2(i); 159 | assert(a2.GetPointer() != &i); 160 | assert(*reinterpret_cast(a2.GetPointer()) == i); 161 | } 162 | 163 | static void test_meta() 164 | { 165 | B b; 166 | test_rw_member(b, "a", 12); 167 | b.setA(31); 168 | test_ro_member(b, "a2", b.getA()); 169 | b.setA(43); 170 | test_ro_member(b, "a3", b.getA()); 171 | test_rw_member(b, "a4", -7); 172 | test_rw_member(b, "b", 191.73f); 173 | test_rw_member(b, "c", -0.5f); 174 | test_rw_member(b, "name", std::string("testme")); 175 | b.setName("hiya"); 176 | test_ro_member(b, "name", std::string("hiya")); 177 | b.setD(91317); 178 | test_ro_member(b, "d", b.getD()); 179 | b.setD(0xDEADBEEF); 180 | test_method(b, "gaz"); 181 | test_method(b, "foo"); 182 | test_ro_member(b, "a", -21); 183 | test_method(b, "gar", -1.f, -0.5f); 184 | test_ro_member(b, "c", -1.f); 185 | test_method(b, "bar", 5, 11.f); 186 | test_method(b, "baz", 0.f, 5.0, (char)7); 187 | test_method(b, "baz", 10.f, 20.0, (char)7); 188 | } 189 | 190 | // test routine 191 | int main(int argc, char* argv[]) 192 | { 193 | test_any(); 194 | test_meta(); 195 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DigiPen Engine Architecture Club 2 | ================================ 3 | 4 | Videos of many of the club's talks are available at: 5 | 6 | https://www.youtube.com/user/GameEngineArchitects 7 | 8 | These materials are made available for the purpose of helping 9 | game developers improve their art. 10 | 11 | All lectures and related materials are Copyright (C) by their 12 | respective authors. Unless otherwise stated, all materials 13 | are free to use for non-commercial purposes. 14 | 15 | http://digipen.edu/ 16 | --------------------------------------------------------------------------------