@Sean Question - are the globals in the display manager backends (like, for example, ambientColor in dm-ogl.c) intended to be global across all display managers? I'm trying to figure out why they would have been included in the local variables associated with a given display manager...
looking
er - would NOT have been included in the local dm variables, sorry
No, they're not intended to be global across all.
OK, thanks - that establishes some degrees of freedom
they're a rather specific implementation detail of opengl 2
so you'll probably see them replicated in all the DMs using opengl, and not elsewhere
Ah, I wasn't clear - I meant whether they're intended to be global across all instances of display managers of a specific type
if we made a vulkan or ogl4 interface, some of them would likely disappear or change
so if you set ambientColor on one ogl dm, is it expected that that setting be reflected across all ogl instances?
ah, hm
icky if it does...
probably yes
that's the only reason to make them static
<wince>
C version of class data
That's kinda not cool - what if the user application doesn't want the same settings in all windows??
they don't appear to be settings in the same sense of DM settings, but I don't feel strongly about it
Oh, well - I guess compared to the rest of this that's a minor pain point...
they're more "these are values we have to tell opengl for things to display" that could just as well be static inside of functions except that several functions need that value
like position of the light source -- that's completely arbitrary. just needs to be defined.
So rather than pull the values from the private vars struct, they're just stashed in statics?
I suppose it doesn't really matter, just a bit odd when reading a function and a variable swoops in from nowhere...
Just looking through the code, I would say the main distinction looks to be more that the statics are reflective values that just get set and/or updated as needed, whereas the private vars are declarative values that control and modify
If this were a C++ class, it's the difference between class data and object data
How they intruded on my radar screen - I was experimenting with moving the *_open calls (which are relatively heavy Tcl/Tk users) up into libtclcad and tripped on the statics.
class { static int var = val; } vs class { int var = val; }
I suppose that's a fairly hare-brained idea to begin with
how so? looks like they only set dm_interp and don't actually do anything with it
dm_plot at least set the statics in its open call. I went ahead and stuffed those into the plot_vars, but I haven't audited the more complex globals to see if the _open functions monkey with them or not.
but yeah, conceptually, that makes no sense... a DM API without a way to open a DM would be broken design-wise.. wouldn't do it just for the sake of moving a type.
I'm trying to get Tcl/Tk out of libdm and libfb - I'm pretty sure I've gotten libged itself clear now, so the dm and fb layers are the last holdouts.
you know you're in super-likely-to-change-behavior territory... ? :)
and by 'change', I mean introduce a bug ;)
Yeah, that's why I had to revert my first attempt - worked on Linux, busted on Windows
it's all good, just beware :)
There's a lot of really weird black magic going on with X, ogl, wgl, and Tk in this - it's incredibly fragile
I'll scrub down the verbose "cast everything at every usage even though the cast is 20 chars long" style to try and make it more readable (THAT at least should be safe enough), but this is one intimidating maze...
such as? they've always looked pretty CG101 to me. it's not black magic, it's just what one has to do
like the ogl DM is pretty text book
most of the ugly is ... the X11 api and that's just how it is
The platform specific voodoo for embedding the Tk window, trying to get it to repaint at the right times, the platform specific differences beyond glx vs wgl despite Tk nominally being cross platform...
I know a lot of this is Tk's fault for not providing a proper OpenGL widget, but that doesn't make it any less annoying to deal with.
yeah, that's just an artifact at this level of API. DM creates the lowest level contexts and needs a handle on them, as does Tk, so the two have to cooperate somehow
From a design standpoint that's what's binding libged et. al. to Tk right now though - that low level connection. Just conceptually, what should a libged+dm+fb functionality set look like without Tk in the mix?
as it is, Tk is being rather polite in that we can do the init and hand it our context. lots of APIs don't make that work, especially higher level apis like game engines.
<snort> they'd better be polite about it, if they're not going to do the right thing and give us a properly integrated widget to begin with
right, the alternative is usually fully managed where they don't let you get at the context
from libged's perspective, it needs the original dm/fb callback API design -- you just open a dm and draw into it.
if everything is properly defined through the callbacks, ged should be just fine without having any awareness of Tk
Hmm... I think the explicit linkage right now is with fb, actually...
So would we define a lightweight/high-level dm/fb API that is what libged uses, and then it's the responsibility of libdm/lifb/whatever else to implement that minimal API?
I was going to say, maybe I've already updated and you've cleared it out, but libdm doesn't really seem to do much at all with Tk or Tcl
Um. The details of the dm-ogl and dm-X backends do...
the biggest issue with fb last time I looked is reconciling what open_existing is doing
starseeker said:
So would we define a lightweight/high-level dm/fb API that is what libged uses, and then it's the responsibility of libdm/lifb/whatever else to implement that minimal API?
Yes, that was the original design of them both too.
I had to revert my attempt to push Tk out of the backends when it broke on Windows (frustrating, I was actually fairly close, but debugging that sort of problem on Windows could be a long haul). From what you were saying that probably wasn't the right way to go at it anyway.
hence all the #define DM_* ... defines that should all generically hook into the dmp callback table for a given dm instance
starseeker said:
Um. The details of the dm-ogl and dm-X backends do...
example? line?
dm_ogl.c:569
dm_ogl.c:632 - basically just search for Tk_ in the file
ah, well yeah but that's the actual window. it needs a window to draw into and one doesn't exist so it creates it, initializes .. but it doesn't really "do" anything with it that results in a back and forth with the Tcl interpreter
Sure. But the necessity of calling all those Tk_ functions binds us to the Tcl/Tk libraries below the libged level.
probably being imprecise with my words, sorry -- dm presently does have the responsibility for create a window
to date, that has been (and needed to be) a Tk window
OK. Then as long as that's true and we need Tk windows, we're stuck unless we switch to a gcv style "load the backend as a plugin" setup and have libtclcad build the backends...
In some ways it doesn't look to far away from that, actually...
right, you're not going to change that binding moving it without either changing dm responsibility or changing (or perhaps violating) architecture in some manner.
OK. So, path forward?
I was going to say, a workable solution to avoid symbol linkage would be to either do dynamic loading or change the responsibility
what exactly is the goal? to simply remove Tk as a linkage yet still keep creating Tk windows?
that wouldn't seem incredibly useful to me
to set the stage for another window mechanism?
Well, my goal is libged capabilities without the necessity of Tcl/Tk - for example, if I were to define a GLFW based display for gsh I would want to be able do at least do old-style console display managers and frame buffers.
If I can do that, then the stage should be properly set for a Qt interface
so devil is definitely in the details to what you just said
to do what you describe and what I think you're getting at, I think we'll need to separate the concept of window and context creation in the DM api
right now, they are one in the same throughout dm
the API isn't far off, but it needs to be one layer lower on the open/close calls and a layer higher on everything else
for example, currently, dm_open does both -- it creates a window and sets up a context. dm_open_existing avoids both I believe, which is why there is a platform version of each.
to be able to utilize a window and/or context that someone else creates, things WILL get messy and likely platform-specific in application code but it can work
Hmm. So we'll have to basically sketch out a reworked dm/fb API, then identify an implementation/migration path from where we are to it?
not the only option, but that's a possibility sure
What if we make the libdm backends into plugins, keeping the window creation where it is, but allowing a program to provide its own custom backend?
Decorator Pattern: https://en.wikipedia.org/wiki/Decorator_pattern
Am I correct that's more or less what we envision for libgcv?
don't need to be plugins per se, they could be, but the important aspect is that you have basically two apis -- a front end and a backend
I guess I would need to whiteboard it - my brain jumps to the dmp->dm_* calls as being the front end and the X/ogl/wgl specific implementations being the back end, but I know I'm missing the real point...
dm is presently concerned with front+back simultaneously, thus dm-ogl.c is really X11 user frontend and OpenGL drawing backend; dm-X.c is X11 user frontend and X11 drawing backend; dm-wgl is WGL frontend and OpenGL drawing backend, etc
Oh, by frontend you're referring to the Windowing API?
it's like a driver interface, rather it needs to be that
think of it this way, look at dm-ogl.c and think what it'd take to extricate OpenGL
similar for the window creation calls (e.g., i.e. the Tk+X11 calls)
Hmm. So, create then Window and then use that to inform the creation of the context?
no, the become separate concepts
this direction would actually greatly benefit from C++... sigh
it'd be something like dm_create_window(), dm_create_context(), dm_register_context()
Ah, OK - I hadn't succeeded in parsing the code well enough yet to have a sense that you could create the context without the window.
that all said, I would suggest focusing on just the minimal necessary bits that simply encapsulate all the Tcl/Tk calls and whatever else is necessary so interp is not part of the public API
that's a GREATLY reduced subset of work needed to make that happen. you can't/shouldn't pull Tk out of DM without surgery, but GED doesn't need to know anything whatsoever about the Tcl/Tk in DM
that'll be good forward progress even if we later burn it all to the ground
I'd probably start with interp
I think the only instances of Tcl/Tk in the public API (at least, per the headers) are the interp and he dm/dm_xvars.h Tk_Windows.
yep
IIRC the only overt use I saw of interp was in wgl - something about deiconifying the window.
figure out how to hide interp, and you'll be half done
interp is used to create tkwin via Tk_MainWindow(interp)
Oh, the other one was the _init_dm call.
interp kicks of all the tk calls
Ah nuts, that's right... forgot about that.
the way to hide it is to either pass it in opaquely from calling code, which is ugly but can work
<nod> - got that to work, actually...
or register it via decorator pattern as a "dm_decorator" of sorts where the dm's create it but the code is elsewhere
I don't think the dms create the interp even now - I think the parent application passes it to them?
yes
that's how the responsbility is delegated to it
it would be something like: struct dm_window *dm_create_tk_window(interp);
I'll see what I can do about the public API - sounds like a reasonable starting point.
so dm_window is where Tk_Window woud hide?
we don't need to avoid Tcl_Interp being in the API entirely, but you can avoid it being in all the API portions that LIBGED calls and is aware of
struct dm_window would probably have a struct dm_window_impl* inside it that is only accessed via whatever source file had dm_create_tk_window()
that way, the Tk_Window symbol is never exposed in a public header
Ah, gotcha.
/me will poke at that for a bit - will probably drive me to go back and finish the license scanner :-P
As the entire entry point hinges on Tcl_Interp, even that would likely be made a dm_create_tk_window(void*interp)
so not even tcl is exposed any more. the application creating the window would know they have an interp and call it (or in the case of glfw, call a different dm_create_glfw_window(void)
<nod>
OK, I've got to run - thanks Sean for the help, much appreciated.
sure thing! enjoy a walk. Gorgeous day.
Last updated: Jan 09 2025 at 00:46 UTC