cimguizmo icon indicating copy to clipboard operation
cimguizmo copied to clipboard

Headers for ImSequencer

Open Glorou opened this issue 2 months ago • 13 comments

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!

Glorou avatar Oct 17 '25 15:10 Glorou

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.

sonoro1234 avatar Oct 18 '25 17:10 sonoro1234

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?

Glorou avatar Oct 18 '25 18:10 Glorou

Virtual C++ functions are not C funtion pointers so it would not work.

sonoro1234 avatar Oct 18 '25 19:10 sonoro1234

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

wolfcomp avatar Oct 20 '25 15:10 wolfcomp

How do you define RampEdit using this?

sonoro1234 avatar Oct 21 '25 07:10 sonoro1234

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

wolfcomp avatar Oct 22 '25 15:10 wolfcomp

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;

wolfcomp avatar Oct 22 '25 15:10 wolfcomp

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

sonoro1234 avatar Oct 22 '25 16:10 sonoro1234

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;
};

wolfcomp avatar Oct 22 '25 18:10 wolfcomp

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?

sonoro1234 avatar Oct 23 '25 08:10 sonoro1234

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#.

wolfcomp avatar Oct 23 '25 14:10 wolfcomp

If anyone desires to do a binding of ImSequence it would be welcome. I guess it should be not autogenerated but manual written.

sonoro1234 avatar Oct 28 '25 09:10 sonoro1234

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

Image

wolfcomp avatar Oct 28 '25 12:10 wolfcomp