winforms - How do I call openGL from C#? -
i programming application in c# using winforms gui. want create control displays 3d graphics using opengl.
i experimented bit opentk , found simple use glcontrol display opengl graphics; had implement method handled paint event of glcontrol , within method call opentk wrapper methods, e.g instead of
glvertex2d(0.0, 0.0);
i call:
gl.vertex2(0.0, 0.0);
i found possible mix opentk calls directly opengl using p/invoke:
using system; using system.runtime.interopservices; public class gl { [dllimport("opengl32")] public static extern void glvertex2d(double x, double y); }; ... gl.vertex2(0.0, 0.0); // opentk gl.glvertex2d(1.0, 1.0); // opengl directly using pinvoke
however, wish remove dependence on opentk alltogether. not want use external library instead call opengl directly.
how opengl "paint" on winform? in other words; how implement glcontrol myself?
how implement glcontrol myself?
more or less how opentk do; since has source open, can study it!
i warn you: won't easy. must synchronize window/control creation opengl context creation (overriding createhandle
, onhandlecreated
, onhandledestroyed
), , override onpaint
routine in order make opengl context current (indeed allowing drawing in paint phase).
just give idea: usercontrol (partial) implementation:
protected override void createhandle() { // create render window mrenderwindow = new renderwindow(this); mrenderwindow.width = (uint)base.clientsize.width; mrenderwindow.height = (uint)base.clientsize.height; // "select" device pixel format before creating control handle switch (environment.osversion.platform) { case platformid.win32windows: case platformid.win32nt: mrenderwindow.precreateobjectwgl(surfaceformat); break; case platformid.unix: mrenderwindow.precreateobjectx11(surfaceformat); break; } // override default swap interval mrenderwindow.swapinterval = swapinterval; // base implementation base.createhandle(); } /// <summary> /// raises <see cref="e:system.windows.forms.control.handlecreated"/> event. /// </summary> /// <param name="e"> /// <see cref="t:system.eventargs"/> contains event data. /// </param> protected override void onhandlecreated(eventargs e) { if (designmode == false) { // finalize control handle creation // - wgl: setpixelformat // - glx: store fbconfig , xvisualinfo selected in createhandle() // ... // - setup swap interval, if supported mrenderwindow.create((rendercontext)null); // create render context (before event handling) mrendercontext = new rendercontext(mrenderwindow.getdevicecontext(), mrendercontextflags); } // base implementation base.onhandlecreated(e); // raise createcontext event if (designmode == false) { mrendercontext.makecurrent(true); raisecreatecontextevent(new rendereventargs(mrendercontext, mrenderwindow)); mrendercontext.makecurrent(false); } } /// <summary> /// /// </summary> /// <param name="e"></param> protected override void onhandledestroyed(eventargs e) { if (designmode == false) { if (mrendercontext != null) { // raise destroycontext event mrendercontext.makecurrent(true); raisedestroycontextevent(new rendereventargs(mrendercontext, mrenderwindow)); mrendercontext.makecurrent(false); // dispose renderer context mrendercontext.dispose(); mrendercontext = null; } // dispose renderer window if (mrenderwindow != null) { mrenderwindow.dispose(); mrenderwindow = null; } } // base implementation base.onhandledestroyed(e); } /// <summary> /// /// </summary> /// <param name="e"></param> protected override void onpaint(painteventargs e) { if (designmode == false) { if (mrendercontext != null) { // render usercontrol mrendercontext.makecurrent(true); // define viewport opengl.gl.viewport(0, 0, clientsize.width, clientsize.height); // derived class implementation try { renderthis(mrendercontext); } catch (exception exception) { } // render event raiserenderevent(new rendereventargs(mrendercontext, mrenderwindow)); // swap buffers if double-buffering surface.swapsurface(); // base implementation base.onpaint(e); mrendercontext.makecurrent(false); } else { e.graphics.drawlines(mfailurepen, new point[] { new point(e.cliprectangle.left, e.cliprectangle.bottom), new point(e.cliprectangle.right, e.cliprectangle.top), new point(e.cliprectangle.left, e.cliprectangle.top), new point(e.cliprectangle.right, e.cliprectangle.bottom), }); // base implementation base.onpaint(e); } } else { e.graphics.clear(color.black); e.graphics.drawlines(mdesignpen, new point[] { new point(e.cliprectangle.left, e.cliprectangle.bottom), new point(e.cliprectangle.right, e.cliprectangle.top), new point(e.cliprectangle.left, e.cliprectangle.top), new point(e.cliprectangle.right, e.cliprectangle.bottom), }); // base implementation base.onpaint(e); } } protected override void onclientsizechanged(eventargs e) { if (mrenderwindow != null) { mrenderwindow.width = (uint)base.clientsize.width; mrenderwindow.height = (uint)base.clientsize.height; } // base implementation base.onclientsizechanged(e); } private static readonly pen mfailurepen = new pen(color.red, 1.5f); private static readonly pen mdesignpen = new pen(color.green, 1.0f); #endregion
(renderwindow utility class selecting device pixel format). key of implementation need mimic same calls classical c++ program does, integrated actual system.windows.forms implementation (.net , mono).
but big task opengl api definition p/invokes: opengl defines lot of enumerants (constants) , entry points (thousands...); human kind, cannot write declaration manually (mainly limited time, error prone). if don't opentk, can start tao framework. if have time waste , lot of patience, can generate c# bindings yourself, using opengl registry.
but... wait, big news (you lucky): xml opengl api definition publicly accessible! (!)
(!) don't understand enthusiastic answer: i'm waiting many, many, many years!!!
Comments
Post a Comment