Headers for ImSequencer
Hi there,
I'm trying to produce headers for ImCurveEditor and ImSequencer, but due to the presence of virtual functions the headers produced aren't functioning, I've seen mention of it in #2 and cimgui issue #17 but have so far been unable to create a properly working gen.
Any advice would be appreciated!
https://github.com/CedricGuillemet/ImGuizmo/blob/b10e91756d32395f5c1fefd417899b657ed7cb88/example/main.cpp#L327
Is an example. RampEdit cant be done in C , but if we had a Delegate than could take C funtions as callbacks it coul be possible. Complicated. I prefer to implement a CurveEditor in C or Luajit, C# from scratch.
So ignoring ImCurveEdit and just considering ImSequencer, since that has a delegate already (if i'm understadning you correctly) I'd have to tweak the generated C header to ensure the struct containing the interface is populated with the function pointers?
Currently whats generated is this:
...
typedef struct SequenceInterface SequenceInterface;
struct SequenceInterface
{
bool focused;
virtual int GetFrameMin() const;
virtual int GetFrameMax() const;
virtual int GetItemCount() const;
virtual void Get(int index, int** start, int** end, int* type, unsigned int* color);
};
#else
#endif // CIMGUI_DEFINE_ENUMS_AND_STRUCTS
#ifndef CIMGUI_DEFINE_ENUMS_AND_STRUCTS
typedef ImSequencer::SequenceInterface SequenceInterface;
typedef ImGuizmo::MODE MODE;
typedef ImGuizmo::OPERATION OPERATION;
typedef ImSequencer::SEQUENCER_OPTIONS SEQUENCER_OPTIONS;
#endif //CIMGUI_DEFINE_ENUMS_AND_STRUCTS
...
CIMGUI_API virtual void SequenceInterface_BeginEdit(SequenceInterface* self,int index);
CIMGUI_API virtual void SequenceInterface_EndEdit(SequenceInterface* self);
CIMGUI_API virtual int SequenceInterface_GetItemTypeCount(SequenceInterface* self);
CIMGUI_API virtual const char* SequenceInterface_GetItemTypeName(SequenceInterface* self,int typeIndex);
CIMGUI_API virtual const char* SequenceInterface_GetItemLabel(SequenceInterface* self,int index);
CIMGUI_API virtual const char* SequenceInterface_GetCollapseFmt(SequenceInterface* self);
CIMGUI_API virtual void SequenceInterface_Add(SequenceInterface* self,int type);
CIMGUI_API virtual void SequenceInterface_Del(SequenceInterface* self,int index);
CIMGUI_API virtual void SequenceInterface_Duplicate(SequenceInterface* self,int index);
CIMGUI_API virtual void SequenceInterface_Copy(SequenceInterface* self);
CIMGUI_API virtual void SequenceInterface_Paste(SequenceInterface* self);
CIMGUI_API virtual size_t SequenceInterface_GetCustomHeight(SequenceInterface* self,int index);
CIMGUI_API virtual void SequenceInterface_DoubleClick(SequenceInterface* self,int index);
CIMGUI_API virtual void SequenceInterface_CustomDraw(SequenceInterface* self,int index,ImDrawList* draw_list,const ImRect rc,const ImRect legendRect,const ImRect clippingRect,const ImRect legendClippingRect);
CIMGUI_API virtual void SequenceInterface_CustomDrawCompact(SequenceInterface* self,int index,ImDrawList* draw_list,const ImRect rc,const ImRect clippingRect);
CIMGUI_API bool ImSequencer_Sequencer(SequenceInterface* sequence,int* currentFrame,bool* expanded,int* selectedEntry,int* firstFrame,int sequenceOptions);
#endif //CIMGUIZMO_INCLUDED
So I'd need to merge those function pointers in to the struct as function pointers?
Virtual C++ functions are not C funtion pointers so it would not work.
Looking at how the cimgui implementation is done, this could be massively simplified. As the only necessary generation is this.
cimguizmo.h
#ifndef CIMGUIZMO_SEQUENCE
#define CIMGUIZMO_SEQUENCE
#ifdef CIMGUI_DEFINE_ENUMS_AND_STRUCTS
typedef enum {
SEQUENCER_EDIT_NONE = 0,
SEQUENCER_EDIT_STARTEND = 1 << 1,
SEQUENCER_CHANGE_FRAME = 1 << 3,
SEQUENCER_ADD = 1 << 4,
SEQUENCER_DEL = 1 << 5,
SEQUENCER_COPYPASTE = 1 << 6,
SEQUENCER_EDIT_ALL = SEQUENCER_EDIT_STARTEND | SEQUENCER_CHANGE_FRAME
}SEQUENCER_OPTIONS;
typedef struct SequenceInterfaceVtable SequenceInterfaceVtable;
typedef struct ImSequencer::SequenceInterface {
SequenceInterfaceVtable* vftable;
bool focused;
}SequenceInterface;
#endif // CIMGUI_DEFINE_ENUMS_AND_STRUCTS
#ifndef CIMGUI_DEFINE_ENUMS_AND_STRUCTS
typedef ImSequencer::SEQUENCER_OPTIONS SEQUENCER_OPTIONS;
typedef ImSequencer::SequenceInterface SequenceInterface;
#endif //CIMGUI_DEFINE_ENUMS_AND_STRUCTS
CIMGUI_API bool ImSequence_Sequencer(SequenceInterface* sequence, int* currentFrame, bool* expanded, int* selectedEntry, int* firstFrame, int sequenceOptions);
#endif //CIMGUIZMO_SEQUENCE
cimguizmo.cpp
CIMGUI_API bool ImSequence_Sequencer(SequenceInterface* sequence, int* currentFrame, bool* expanded, int* selectedEntry, int* firstFrame, int sequenceOptions)
{
return ImSequencer::Sequencer(sequence, currentFrame, expanded, selectedEntry, firstFrame, sequenceOptions);
}
This is due to that C doesn't care about the VTable definition but only has to have some reference to where it is in memory.
You can see how this is done with the ImGuiPlatformIO struct in cimgui.
Note: This was done inspecting the output of what the MSVC compiler gets as a result, but might be different on GCC or Clang
How do you define RampEdit using this?
Using the output that happens with MSVC compiler would be defined as.
cimguizmo.h
#ifndef CIMGUIZMO_CURVEEDITOR
#define CIMGUIZMO_CURVEEDITOR
#ifdef CIMGUI_DEFINE_ENUMS_AND_STRUCTS
typedef enum {
CurveNone,
CurveDiscrete,
CurveLinear,
CurveSmooth,
CurveBezier
} CurveType;
typedef struct {
int curveIndex;
int pointIndex;
} EditPoint;
typedef struct CurveDelegateVtable CurveDelegateVtable;
typedef struct {
CurveDelegateVtable* vftable;
bool focused;
}CurveDelegate;
#endif // CIMGUI_DEFINE_ENUMS_AND_STRUCTS
#ifndef CIMGUI_DEFINE_ENUMS_AND_STRUCTS
typedef ImCurveEdit::CurveType CurveType;
typedef ImCurveEdit::Delegate CurveDelegate;
typedef ImVector<ImCurveEdit::EditPoint> EditPointVector;
#endif //CIMGUI_DEFINE_ENUMS_AND_STRUCTS
CIMGUI_API bool ImCurveEdit_Edit(CurveDelegate& delegate, const ImVec2& size, unsigned int id, const ImRect* clippingRect, EditPointVector* selectedPoints);
#endif //CIMGUIZMO_CURVEEDITOR
cimguizmo.cpp
CIMGUI_API bool ImCurveEdit_Edit(CurveDelegate& delegate, const ImVec2& size, unsigned int id, const ImRect* clippingRect, EditPointVector* selectedPoints)
{
return ImCurveEdit::Edit(delegate, size, id, clippingRect, selectedPoints);
}
I will note that even tho vtables aren't a specification in C one could reconstruct the memory structure of them in C if you know the layout from the CPP compiler
Looking at some forums, this should be valid C code and handles the same as vtables.
typedef struct CurveDelegate CurveDelegate;
typedef enum {
CurveNone,
CurveDiscrete,
CurveLinear,
CurveSmooth,
CurveBezier
} CurveType;
typedef struct {
unsinged long long (*GetCurveCount)(CurveDelegate* /*this*/);
bool (*IsVisible)(CurveDelegate* /*this*/, unsigned long long /*curveIndex*/);
CurveType (*GetCurveType)(CurveDelegate* /*this*/, unsigned long long /*curveIndex*/);
ImVec2& (*GetMin)(CurveDelegate* /*this*/);
ImVec2& (*GetMax)(CurveDelegate* /*this*/);
unsinged long long (*GetPointCount)(CurveDelegate* /*this*/, unsigned long long /*curveIndex*/);
unsigned int (*GetCurveColor)(CurveDelegate* /*this*/, unsigned long long /*curveIndex*/);
ImVec2* (*GetPoints)(CurveDelegate* /*this*/, unsigned long long /*curveIndex*/);
int (*EditPoint)(CurveDelegate* /*this*/, unsigned long long /*curveIndex*/, int /*pointIndex*/, ImVec2 /*value*/);
void (*AddPoint)(CurveDelegate* /*this*/, unsigned long long /*curveIndex*/, ImVec2 /*value*/);
unsigned int (*GetBackgroundColor)(CurveDelegate* /*this*/);
void (*BeginEdit)(CurveDelegate* /*this*/, unsigned long long /*index*/);
void (*EndEdit)(CurveDelegate* /*this*/);
} CurveDelegateVtable;
typedef struct {
CurveDelegateVtable* vtable;
bool focused;
} CurveDelegate;
Sorry, what I meant is how SequenceInterface would be defined in C with all the functions it is suppossed to have: from GetFrameMin to CustomDrawCompact
I will note that even tho vtables aren't a specification in C one could reconstruct the memory structure of them in C if you know the layout from the CPP compiler
We should be able to compile the C code so that the layout provided from the C compiler should match the C++ layout
SequenceInterfaceVTable would be the same structure setup as the CurveDelegateVtable with the order of the functions being from top to bottom if they have virtual in front.
typedef struct SequenceInterface SequenceInterface;
typedef struct {
int (*GetFrameMin)(SequenceInterface* /*this*/);
int (*GetFrameMax)(SequenceInterface* /*this*/);
int (*GetItemCount)(SequenceInterface* /*this*/);
void (*BeginEdit)(SequenceInterface* /*this*/, int /*index*/);
void (*EndEdit)(SequenceInterface* /*this*/);
int (*GetItemTypeCount)(SequenceInterface* /*this*/);
const char* (*GetItemTypeName)(SequenceInterface* /*this*/, int /*typeIndex*/);
const char* (*GetItemLabel)(SequenceInterface* /*this*/, int /*index*/);
const char* (*GetCollapseFmt)(SequenceInterface* /*this*/);
void (*Get)(SequenceInterface* /*this*/, int index, int** start, int** end, int* type, unsigned int* color);
void (*Add)(SequenceInterface* /*this*/, int /*type*/);
void (*Del)(SequenceInterface* /*this*/, int /*index*/);
void (*Duplicate)(SequenceInterface* /*this*/, int /*index*/);
void (*Copy)(SequenceInterface* /*this*/);
void (*Paste)(SequenceInterface* /*this*/);
size_t (*GetCustomHeight)(SequenceInterface* /*this*/, int /*index*/);
void (*DoubleClick)(SequenceInterface* /*this*/, int /*index*/);
void (*CustomDraw)(SequenceInterface* /*this*/, int /*index*/, ImDrawList* /*draw_list*/, const ImRect& /*rc*/, const ImRect& /*legendRect*/, const ImRect& /*clippingRect*/, const ImRect& /*legendClippingRect*/);
void (*CustomDrawCompact)(SequenceInterface* /*this*/, int /*index*/, ImDrawList* /*draw_list*/, const ImRect& /*rc*/, const ImRect& /*clippingRect*/);
} SequenceInterfaceVTable;
typedef struct SequenceInterface{
SequenceInterfaceVtable* vtable;
bool focused;
};
Yes, that could work, but it is not working "out of the box": The user still has to provide the implementation of all this C functions, so that I dont find this C binding so "useful". It seems that doing all from C or C# would be cleaner?
Best would be to have the implementation required in the caller of the C export and not have default set functions. In most cases from what I know where this is being used being C#.
If anyone desires to do a binding of ImSequence it would be welcome. I guess it should be not autogenerated but manual written.
Looking at compiler output for 3 different compilers, this being gcc, msvc, and clang. They all seem to have the same memory layout for the bool and vtable locations
Specifically: gcc 15.2 msvc 19.43 clang 21.1.0
Image for ref