Last active
June 30, 2022 05:41
-
-
Save Flix01/a7873b73f0ffb00c87260e5bf13a18d4 to your computer and use it in GitHub Desktop.
NodeGraphEditor with dynamic enum test (https://github.com/Flix01/imgui/issues/15)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// On Ubuntu, I can compile it with the following command line (provided that imgui.h is two folders up, and that I want to use glfw): | |
// gcc -o basicExample mainBasic.cpp -I"../../" ../../imgui.cpp ../../imgui_draw.cpp -D"IMGUI_INCLUDE_IMGUI_USER_H" -D"IMGUI_INCLUDE_IMGUI_USER_INL" -I"/usr/include/GLFW" -D"IMGUI_USE_GLFW_BINDING" -L"/usr/lib/x86_64-linux-gnu" -lglfw -lX11 -lm -lGL -lstdc++ -s | |
// This file is intended to test/answer to https://github.com/Flix01/imgui/issues/15 | |
// RESULT: | |
// Dynamic enum works! | |
// And if you can use dynamic_cast<>() making new Node types that use it is easier (non-intrusive) | |
// Otherwise you must modify the code of CustomEnumEditorNode::render(...) for every new user class you add. | |
// | |
// Added also some code to serialize/deserialize the enum names ("TestEnumNames") together | |
// with the Node Graph Editor itself (to the same file). | |
// | |
// Fixed a possible copy/paste bug | |
#include <imgui.h> // intellisense only | |
#include <addons/imguinodegrapheditor/imguinodegrapheditor.h> // intellisense only | |
#include <string.h> //strcpy | |
//#define NO_DYNAMIC_CAST // More portable, but makes code more intrusive | |
#ifndef NO_DYNAMIC_CAST | |
class ITestEnum { | |
public: | |
virtual int& getSelectedItem()=0; | |
virtual ~ITestEnum() {} | |
}; | |
#endif //NO_DYNAMIC_CAST | |
#ifndef IM_PLACEMENT_NEW | |
struct ImPlacementNewDummy {}; | |
inline void* operator new(size_t, ImPlacementNewDummy, void* ptr) { return ptr; } | |
inline void operator delete(void*, ImPlacementNewDummy, void*) {} | |
#define IM_PLACEMENT_NEW(_PTR) new(ImPlacementNewDummy(), _PTR) | |
#endif //IM_PLACEMENT_NEW | |
// MY DATA STRUCTURE =============================================================== | |
#define MAX_ENUM_NAME_LENGTH 84 // in bytes | |
typedef ImVector<char [MAX_ENUM_NAME_LENGTH]> TestEnumNamesType; // so that it works without STL (std::vector<std::string> will be easier to implement) | |
TestEnumNamesType TestEnumNames; | |
int TestEnumNamesInsert(const char* name) { | |
if (!name) return -1; | |
const int len = strlen(name); | |
if (len<=0 || len+1>=MAX_ENUM_NAME_LENGTH) return -1; | |
// We want to add the item in a sorted way. First we must calculate "itemPlacement" | |
int itemPlacement = 0,comp = 0; | |
for (int i=0,iSz=TestEnumNames.size();i<iSz;i++) { | |
comp = strcmp(name,&TestEnumNames[i][0]); | |
if (comp>0) ++itemPlacement; | |
else if (comp==0) return -1; // already present | |
} | |
// Here we insert "name" at "itemPlacement" | |
TestEnumNames.resize(TestEnumNames.size()+1); | |
for (int i=TestEnumNames.size()-1;i>itemPlacement;--i) strcpy(&TestEnumNames[i][0],&TestEnumNames[i-1][0]); | |
strcpy(&TestEnumNames[itemPlacement][0],name); | |
return itemPlacement; | |
} | |
bool TestEnumNamesDelete(int itemIndex) { | |
// We must delete the item | |
int size = TestEnumNames.size(); | |
for (int i=itemIndex;i<size-1;i++) { | |
strcpy(&TestEnumNames[i][0],&TestEnumNames[i+1][0]); | |
} | |
--size;TestEnumNames.resize(size); | |
return true; | |
} | |
// NODE DEFINITIONS ================================================================ | |
namespace ImGui { | |
enum TestNodeTypes { | |
TNT_CUSTOM_ENUM_EDITOR_NODE = 0, | |
TNT_CUSTOM_ENUM_USER_NODE, | |
TNT_COUNT | |
}; | |
static const char* TestNodeTypeNames[TNT_COUNT] = {"Custom Enum Editor","Custom Enum User"}; | |
class CustomEnumEditorNode : public Node { | |
protected: | |
typedef Node Base; //Base Class | |
typedef CustomEnumEditorNode ThisClass; | |
CustomEnumEditorNode() : Base() {} | |
static const int TYPE = TNT_CUSTOM_ENUM_EDITOR_NODE; | |
int selectedEnumIndex; // field | |
char buf[MAX_ENUM_NAME_LENGTH]; | |
bool mustFocusInputText; | |
public: | |
virtual const char* getTooltip() const {return "CustomEnumEditorNode tooltip.";} | |
virtual const char* getInfo() const {return "CustomEnumEditorNode info.\n\nThis is supposed to display some info about this node.";} | |
virtual void getDefaultTitleBarColors(ImU32& defaultTitleTextColorOut,ImU32& defaultTitleBgColorOut,float& defaultTitleBgColorGradientOut) const { | |
// [Optional Override] customize Node Title Colors [default values: 0,0,-1.f => do not override == use default values from the Style()] | |
defaultTitleTextColorOut = IM_COL32(220,220,220,255);defaultTitleBgColorOut = IM_COL32(0,75,0,255);defaultTitleBgColorGradientOut = -1.f; | |
} | |
// create: | |
static ThisClass* Create(const ImVec2& pos) { | |
// 1) allocation | |
// MANDATORY (NodeGraphEditor::~NodeGraphEditor() will delete these with ImGui::MemFree(...)) | |
// MANDATORY even with blank ctrs. Reason: ImVector does not call ctrs/dctrs on items. | |
ThisClass* node = (ThisClass*) ImGui::MemAlloc(sizeof(ThisClass));IM_PLACEMENT_NEW (node) ThisClass(); | |
// 2) main init | |
node->init("CustomEnumEditorNode",pos,"","",TYPE); | |
// 3) init fields ( this uses the node->fields variable; otherwise we should have overridden other virtual methods (to render and serialize) ) | |
node->fields.addFieldEnum(&node->selectedEnumIndex,&CustomEnumEditorNode::GetNumEnumItems,&CustomEnumEditorNode::GetTextFromEnumIndex,"###CustomEnumEditor",NULL,&TestEnumNames); | |
// Please node that in the render(...) method we assume that the dynamic enum FieldInfo is the first one (at node->fields[0]). | |
// 4) set (or load) field values | |
node->selectedEnumIndex = 0; // field value | |
node->buf[0]='\0'; // other (non-field) variables | |
node->mustFocusInputText = false; | |
return node; | |
} | |
protected: | |
virtual bool render(float nodeWidth); | |
virtual bool canBeCopied() const {return false;} | |
public: | |
static bool GetTextFromEnumIndex(void* data,int value,const char** pTxt) { | |
if (!pTxt || !data) return false; | |
const TestEnumNamesType& vec = *((const TestEnumNamesType*) data); | |
*pTxt = (value>=0 && value<vec.size()) ? vec[value] : "UNKNOWN"; | |
return true; | |
} | |
static int GetNumEnumItems(void* data) { | |
if (!data) return 0; | |
const TestEnumNamesType& vec = *((const TestEnumNamesType*) data); | |
return vec.size(); | |
} | |
// casts: | |
inline static ThisClass* Cast(Node* n) {return Node::Cast<ThisClass>(n,TYPE);} | |
inline static const ThisClass* Cast(const Node* n) {return Node::Cast<ThisClass>(n,TYPE);} | |
}; | |
class CustomEnumUserNode : public Node | |
#ifndef NO_DYNAMIC_CAST | |
, public virtual ITestEnum | |
#endif //NO_DYNAMIC_CAST | |
{ | |
protected: | |
typedef Node Base; //Base Class | |
typedef CustomEnumUserNode ThisClass; | |
CustomEnumUserNode() : Base() {} | |
static const int TYPE = TNT_CUSTOM_ENUM_USER_NODE; | |
int selectedEnumIndex; // field | |
virtual const char* getTooltip() const {return "ColorEnumUserNode tooltip.";} | |
virtual const char* getInfo() const {return "ColorEnumUserNode info.\n\nThis is supposed to display some info about this node.";} | |
/*virtual void getDefaultTitleBarColors(ImU32& defaultTitleTextColorOut,ImU32& defaultTitleBgColorOut,float& defaultTitleBgColorGradientOut) const { | |
// [Optional Override] customize Node Title Colors [default values: 0,0,-1.f => do not override == use default values from the Style()] | |
defaultTitleTextColorOut = IM_COL32(220,220,220,255);defaultTitleBgColorOut = IM_COL32(0,75,0,255);defaultTitleBgColorGradientOut = -1.f; | |
}*/ | |
public: | |
int& getSelectedItem() {return selectedEnumIndex;} // ITestEnum if available, but used also if not available (to expose a private variable) | |
// create: | |
static ThisClass* Create(const ImVec2& pos) { | |
// 1) allocation | |
// MANDATORY (NodeGraphEditor::~NodeGraphEditor() will delete these with ImGui::MemFree(...)) | |
// MANDATORY even with blank ctrs. Reason: ImVector does not call ctrs/dctrs on items. | |
ThisClass* node = (ThisClass*) ImGui::MemAlloc(sizeof(ThisClass));IM_PLACEMENT_NEW (node) ThisClass(); | |
// 2) main init | |
node->init("ColorEnumUserNode",pos,"in_a;in_b","out_a;out_b",TYPE); | |
// 3) init fields ( this uses the node->fields variable; otherwise we should have overridden other virtual methods (to render and serialize) ) | |
node->fields.addFieldEnum(&node->selectedEnumIndex,&CustomEnumEditorNode::GetNumEnumItems,&CustomEnumEditorNode::GetTextFromEnumIndex,"Selection","select your favourite",&TestEnumNames); | |
// 4) set (or load) field values | |
node->selectedEnumIndex = -1; | |
return node; | |
} | |
// casts: | |
inline static ThisClass* Cast(Node* n) {return Node::Cast<ThisClass>(n,TYPE);} | |
inline static const ThisClass* Cast(const Node* n) {return Node::Cast<ThisClass>(n,TYPE);} | |
}; | |
bool CustomEnumEditorNode::render(float nodeWidth) // should return "true" if the node has been edited and its values modified (to fire "edited callbacks") | |
{ | |
bool nodeEdited = false; | |
if (mustFocusInputText) ImGui::SetKeyboardFocusHere(0); | |
if (ImGui::InputText("New item",buf,MAX_ENUM_NAME_LENGTH,ImGuiInputTextFlags_EnterReturnsTrue /*| ImGuiInputTextFlags_AutoSelectAll*/)) { | |
mustFocusInputText=false; | |
if (strlen(buf)>0) { | |
const int itemIndex=TestEnumNamesInsert(buf); | |
if (itemIndex>=0) { | |
buf[0]='\0'; | |
selectedEnumIndex = itemIndex; | |
nodeEdited = true; | |
//Now we must correct all the "selectedItem>=itemPlacement" in all the NodeGraphEditor | |
ImGui::NodeGraphEditor& nge = getNodeGraphEditor(); // Actually if we use more than one Node Graph Editor with the same node types, the Dynamic Enum is the same, so we should process other editors as well... | |
# ifndef NO_DYNAMIC_CAST | |
for (int i=0,iSz=nge.getNumNodes();i<iSz;i++) { | |
ITestEnum* n = dynamic_cast<ITestEnum*>(nge.getNode(i)); | |
if (n) { | |
int& selectedIndexEnum = n->getSelectedItem(); | |
if (selectedIndexEnum>=itemIndex) ++selectedIndexEnum; // otherwise node n selected index gets wrong | |
} | |
} | |
ITestEnum* copiedNode = dynamic_cast<ITestEnum*>(nge.getCopiedNode()); // This is the internal node kept for copy/paste operations: we can't forget to process it | |
if (copiedNode) { | |
int& selectedIndexEnum = copiedNode->getSelectedItem(); | |
if (selectedIndexEnum>=itemIndex) ++selectedIndexEnum; // otherwise node n selected index gets wrong | |
} | |
# else //NO_DYNAMIC_CAST | |
ImVector<ImGui::Node*> nodes; | |
// Similiar lines must be repeated for every new Node class definition that uses the dynamic enum | |
nge.getAllNodesOfType(ImGui::TNT_CUSTOM_ENUM_USER_NODE,&nodes); | |
for (int i=0,iSz=nodes.size();i<iSz;i++) { | |
ImGui::CustomEnumUserNode& n = *ImGui::CustomEnumUserNode::Cast(nodes[i]); | |
int& selectedIndexEnum = n.getSelectedItem(); | |
if (selectedIndexEnum>=itemIndex) ++selectedIndexEnum; // otherwise node n selected index gets wrong | |
} | |
ImGui::CustomEnumUserNode* copiedNode = ImGui::CustomEnumUserNode::Cast(nge.getCopiedNode()); // This is the internal node kept for copy/paste operations: we can't forget to process it | |
if (copiedNode) { | |
int& selectedIndexEnum = copiedNode->getSelectedItem(); | |
if (selectedIndexEnum>=itemIndex) ++selectedIndexEnum; // otherwise node n selected index gets wrong | |
} | |
# endif //NO_DYNAMIC_CAST | |
mustFocusInputText=true; | |
} | |
} | |
} | |
else mustFocusInputText=false; | |
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s","insert a new item"); | |
// Here we render field 0 (without marking the "nodeEdited" flag) | |
if (fields[0].render(nodeWidth)) mustFocusInputText=true; // We use "mustFocusInputText" to keep the InputText focused while switching enum | |
if (ImGui::IsItemActive()) mustFocusInputText=true; // This seems to cover the case when we switch to the same item | |
if (TestEnumNames.size()>0) { | |
ImGui::SameLine(); | |
if (ImGui::SmallButton("x") && TestEnumNamesDelete(selectedEnumIndex)) { | |
nodeEdited = true; | |
mustFocusInputText=true; | |
//Now we must correct all the "selectedItem>=selectedEnumIndex" in all the NodeGraphEditor | |
ImGui::NodeGraphEditor& nge = getNodeGraphEditor(); | |
# ifndef NO_DYNAMIC_CAST | |
for (int i=0,iSz=nge.getNumNodes();i<iSz;i++) { | |
ITestEnum* n = dynamic_cast<ITestEnum*>(nge.getNode(i)); | |
if (n) { | |
int& selectedIndexEnum = n->getSelectedItem(); | |
if (selectedIndexEnum==selectedEnumIndex) selectedIndexEnum=-1; // we're deleting the selected item of node n | |
if (selectedIndexEnum>selectedEnumIndex) --selectedIndexEnum; // otherwise node n selected index gets wrong | |
} | |
} | |
ITestEnum* copiedNode = dynamic_cast<ITestEnum*>(nge.getCopiedNode()); // This is the internal node kept for copy/paste operations: we can't forget to process it | |
if (copiedNode) { | |
int& selectedIndexEnum = copiedNode->getSelectedItem(); | |
if (selectedIndexEnum==selectedEnumIndex) selectedIndexEnum=-1; // we're deleting the selected item of node n | |
if (selectedIndexEnum>selectedEnumIndex) --selectedIndexEnum; // otherwise node n selected index gets wrong | |
} | |
# else //NO_DYNAMIC_CAST | |
ImVector<ImGui::Node*> nodes; | |
// Similiar lines must be repeated for every new Node class definition that uses the dynamic enum | |
nge.getAllNodesOfType(ImGui::TNT_CUSTOM_ENUM_USER_NODE,&nodes); | |
for (int i=0,iSz=nodes.size();i<iSz;i++) { | |
ImGui::CustomEnumUserNode& n = *ImGui::CustomEnumUserNode::Cast(nodes[i]); | |
int& selectedIndexEnum = n.getSelectedItem(); | |
if (selectedIndexEnum==selectedEnumIndex) selectedIndexEnum=-1; // we're deleting the selected item of node n | |
if (selectedIndexEnum>selectedEnumIndex) --selectedIndexEnum; // otherwise node n selected index gets wrong | |
} | |
ImGui::CustomEnumUserNode* copiedNode = ImGui::CustomEnumUserNode::Cast(nge.getCopiedNode()); // This is the internal node kept for copy/paste operations: we can't forget to process it | |
if (copiedNode) { | |
int& selectedIndexEnum = copiedNode->getSelectedItem(); | |
if (selectedIndexEnum==selectedEnumIndex) selectedIndexEnum=-1; // we're deleting the selected item of node n | |
if (selectedIndexEnum>selectedEnumIndex) --selectedIndexEnum; // otherwise node n selected index gets wrong | |
} | |
# endif //NO_DYNAMIC_CAST | |
if (--selectedEnumIndex<0) selectedEnumIndex=0; | |
} | |
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s","delete"); | |
} | |
// Now we can draw the other fields normally (no one in this demo) | |
for (int i=1,isz=fields.size();i<isz;i++) { | |
FieldInfo& f = fields[i]; | |
nodeEdited|=f.render(nodeWidth); | |
} | |
return nodeEdited; | |
} | |
static Node* TestNodeFactory(int nt,const ImVec2& pos,const NodeGraphEditor& /*nge*/) { | |
switch (nt) { | |
case TNT_CUSTOM_ENUM_EDITOR_NODE: return CustomEnumEditorNode::Create(pos); | |
case TNT_CUSTOM_ENUM_USER_NODE: return CustomEnumUserNode::Create(pos); | |
default: | |
IM_ASSERT(true); // Missing node type creation | |
return NULL; | |
} | |
return NULL; | |
} | |
} // namespace ImGui | |
// END NODE DEFINITIONS ============================================================ | |
// Optional methods to load/save "TestEnumNames" | |
#if (defined(IMGUIHELPER_H_) && !defined(NO_IMGUIHELPER_SERIALIZATION)) | |
#ifndef NO_IMGUIHELPER_SERIALIZATION_SAVE | |
bool TestEnumNamesSave(ImGuiHelper::Serializer& s) { | |
const int size = TestEnumNames.size(); | |
s.save(&size,"num_text_line_items"); | |
s.saveTextLines(size,ImGui::CustomEnumEditorNode::GetTextFromEnumIndex,(void*)&TestEnumNames,"text_line_items"); | |
return true; | |
} | |
inline bool TestEnumNamesSave(const char* filename) { | |
ImGuiHelper::Serializer s(filename); | |
return TestEnumNamesSave(s); | |
} | |
#endif //NO_IMGUIHELPER_SERIALIZATION_SAVE | |
#ifndef NO_IMGUIHELPER_SERIALIZATION_LOAD | |
static bool TestEnumNamesTypeLoadCallback(ImGuiHelper::FieldType ft,int numArrayElements,void* pValue,const char* name,void* userPtr) { | |
TestEnumNamesType* vec = (TestEnumNamesType*) userPtr; | |
if (strcmp(name,"num_text_line_items")==0) { | |
vec->resize(*((int*)pValue)); | |
for (int i=0;i<vec->size();i++) (*vec)[i][0]='\0'; | |
if (vec->size()==0) return true; | |
} | |
else if (ft==ImGui::FT_TEXTLINE && strcmp(name,"text_line_items")==0) { | |
IM_ASSERT(numArrayElements<vec->size()); | |
strcpy(&(*vec)[numArrayElements][0],(char*)pValue); | |
if (numArrayElements==vec->size()-1) return true; | |
} | |
return false; | |
} | |
bool TestEnumNamesLoad(ImGuiHelper::Deserializer& d, const char ** pOptionalBufferStart=NULL) { | |
const char* amount = pOptionalBufferStart ? (*pOptionalBufferStart) : 0; | |
d.parse(TestEnumNamesTypeLoadCallback,(void*)&TestEnumNames,amount); | |
if (pOptionalBufferStart) *pOptionalBufferStart=amount; | |
return true; | |
} | |
bool TestEnumNamesLoad(const char* filename) { | |
ImGuiHelper::Deserializer d(filename); | |
return TestEnumNamesLoad(d); | |
} | |
#endif //NO_IMGUIHELPER_SERIALIZATION_LOAD | |
#endif //NO_IMGUIHELPER_SERIALIZATION | |
const char* NodeGraphEditorSavePath = "testEnumNamesNodeGraphEditor.nge"; | |
ImGui::NodeGraphEditor nge; | |
// Mandatory methods | |
void InitGL() { | |
if (nge.isInited()) { | |
// This adds entries to the "add node" context menu | |
nge.registerNodeTypes(ImGui::TestNodeTypeNames,ImGui::TNT_COUNT,ImGui::TestNodeFactory,NULL,-1); // last 2 args can be used to add only a subset of nodes (or to sort their order inside the context menu) | |
nge.registerNodeTypeMaxAllowedInstances(ImGui::TNT_CUSTOM_ENUM_EDITOR_NODE,1); // Here we set the max number of allowed instances of the node (1) | |
nge.show_style_editor = true; | |
nge.show_load_save_buttons = true; | |
// optional load the style (for all the editors: better call it in InitGL()): | |
//NodeGraphEditor::Style::Load(NodeGraphEditor::GetStyle(),"nodeGraphEditor.style"); | |
//-------------------------------------------------------------------------------- | |
// Here we load "TestEnumNames" + the saved node graph editor from a singlefile. | |
bool nodeGraphEditorSavePathLoaded = false; | |
# if (defined(IMGUIHELPER_H_) && !defined(NO_IMGUIHELPER_SERIALIZATION) && !defined(NO_IMGUIHELPER_SERIALIZATION_LOAD)) | |
{ | |
ImGuiHelper::Deserializer d(NodeGraphEditorSavePath); | |
nodeGraphEditorSavePathLoaded = d.isValid(); | |
const char* offset = 0; // Basically offset advances at each loading step | |
TestEnumNamesLoad(d,&offset); // TestEnumNames | |
nge.load(d,&offset); // nge | |
} | |
# endif | |
if (!nodeGraphEditorSavePathLoaded) { | |
// Starting items (sorted alphabetically) | |
TestEnumNames.resize(3); | |
strcpy(&TestEnumNames[0][0],"APPLE"); | |
strcpy(&TestEnumNames[1][0],"LEMON"); | |
strcpy(&TestEnumNames[2][0],"ORANGE"); | |
// Optional: starting nodes and links (load from file instead):----------- | |
nge.addNode(ImGui::TNT_CUSTOM_ENUM_EDITOR_NODE,ImVec2(40,50)); | |
ImGui::Node* colorEnumUserNode1 = nge.addNode(ImGui::TNT_CUSTOM_ENUM_USER_NODE,ImVec2(40,180)); | |
ImGui::Node* colorEnumUserNode2 = nge.addNode(ImGui::TNT_CUSTOM_ENUM_USER_NODE,ImVec2(300,180)); // optionally use e.g.: ImGui::ColorEnumUserNode::Cast(colorEnumUserNode1)->...; | |
ImGui::Node* colorEnumUserNode3 = nge.addNode(ImGui::TNT_CUSTOM_ENUM_USER_NODE,ImVec2(550,180)); | |
nge.addLink(colorEnumUserNode1, 0, colorEnumUserNode2, 0); | |
nge.addLink(colorEnumUserNode1, 1, colorEnumUserNode2, 1); | |
nge.addLink(colorEnumUserNode2, 0, colorEnumUserNode3, 0); | |
nge.addLink(colorEnumUserNode2, 1, colorEnumUserNode3, 1); | |
} | |
} | |
} | |
void ResizeGL(int,int) {} | |
void DestroyGL() { | |
// We save "TestEnumNames" + the node graph editor together to a single file here | |
# if (defined(IMGUIHELPER_H_) && !defined(NO_IMGUIHELPER_SERIALIZATION) && !defined(NO_IMGUIHELPER_SERIALIZATION_SAVE)) | |
ImGuiHelper::Serializer s(NodeGraphEditorSavePath); | |
TestEnumNamesSave(s); // TestEnumNames | |
nge.save(s); // nge | |
# endif | |
} | |
void DrawGL() | |
{ | |
ImImpl_ClearColorBuffer(ImVec4(0.6f, 0.6f, 0.6f, 1.0f)); // Warning: it does not clear the depth buffer | |
static bool open = true; | |
if (ImGui::Begin("Node Graph Editor", &open, ImVec2(1190,710),0.85f,ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoSavedSettings)) { | |
nge.render(); | |
} | |
ImGui::End(); | |
} | |
#ifndef IMGUI_USE_AUTO_BINDING_WINDOWS // IMGUI_USE_AUTO_ definitions get defined automatically (e.g. do NOT touch them!) | |
int main(int argc, char** argv) | |
#else //IMGUI_USE_AUTO_BINDING_WINDOWS | |
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int iCmdShow) { | |
#endif //IMGUI_USE_AUTO_BINDING_WINDOWS | |
{ | |
ImImpl_InitParams* pInitParams = NULL; | |
# ifndef IMGUI_USE_AUTO_BINDING_WINDOWS | |
ImImpl_Main(pInitParams,argc,argv); | |
# else //IMGUI_USE_AUTO_BINDING_WINDOWS | |
ImImpl_WinMain(pInitParams,hInstance,hPrevInstance,lpCmdLine,iCmdShow); | |
# endif //IMGUI_USE_AUTO_BINDING_WINDOWS | |
return 0; | |
} | |
Author
Flix01
commented
Apr 15, 2017
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment