View previous topic :: View next topic |
Author |
Message |
hugues
Joined: 09 Aug 2007 Posts: 20 Location: Brussels, Belgium
|
Posted: Sat Apr 05, 2008 4:38 pm Post subject: SDL with Derelict on Mac OS X: not completely resolved yet |
|
|
DerelictGL now compiles correctly on Mac OS X. I fixed the DerelictGLContext-related issues in revision 288.
Regarding the SDL_main problem, an easy and clean solution hasn't been found yet, though.
With Anders' code, the app needs to be statically linked to libSDLmain.a and linked to the AppKit framework (which defines the symbols used in libSDLmain.a and is linked to the Objective-C runtime). It seems to work fine, but quitting the app through the Quit command of the application menu causes a segfault. This doesn't happen when linking normally to SDL (i.e. without using Derelict).
Regarding Crispy's method, I wasn't able to simply link cocoabits.o to my test app. The linker complains about the following undefined symbols:
.objc_class_name_NSAutoreleasePool
_objc_msgSend
So I had to link at least to the Foundation framework (which defines NSAutoreleasePool and is linked to the Objective-C runtime) for it to work. Crispy, did you have the same situation? If linking to the Foundation framework is required, we can as well link to the AppKit framework, which defines NSApplicationLoad(), and the dlopen() code would not be needed. Little info: actually we don't need Cocoa here. The AppKit framework is enough, but it works also if we link to Cocoa because Cocoa is linked to AppKit.
Of course, since we are using Derelict and like dynamic loading, it will be better if we didn't had to link at all to any library. To do that, we need to put the code from cocoabits.m into a dynamic library that we link to the AppKit framework. We can then load this library, find the symbols and call the functions. We can as well put the NSApplicationLoad() call into it. Let's call this nsappbits.m: Code: | #import <Foundation/NSAutoreleasePool.h>
#import <AppKit/NSApplication.h>
NSAutoreleasePool *globalPool = nil;
void nsAppInit()
{
NSApplicationLoad();
globalPool = [[NSAutoreleasePool alloc] init];
}
void nsAppCleanup()
{
[globalPool release];
} |
We build this with: Code: | gcc -o nsappbits.dylib nsappbits.m -dynamiclib -framework AppKit |
In our app, we define something like this: Code: | import derelict.util.loader;
class Platform
{
static this()
{
platformLib = null;
}
static ~this()
{
cleanup();
}
static void init()
{
version (darwin)
{
if (platformLib is null)
{
platformLib = Derelict_LoadSharedLib(PLATFORM_LIB_NAME);
void function() nsAppInit = cast(void function()) Derelict_GetProc(platformLib, "nsAppInit");
nsAppInit();
}
}
}
static void cleanup()
{
version (darwin)
{
if (platformLib !is null)
{
void function() nsAppCleanup = cast(void function()) Derelict_GetProc(platformLib, "nsAppCleanup");
nsAppCleanup();
Derelict_UnloadSharedLib(platformLib);
platformLib = null;
}
}
}
private
{
static SharedLib platformLib;
version (darwin)
{
static const char[] PLATFORM_LIB_NAME = "nsappbits.dylib";
}
}
} |
We can now simply call Platform.init() and Platform.cleanup(). (Of course, all this "static" code is not very thread-safe (not at all, actually ) and we need to take care of the correct path of nsappbits.dylib.) This isn't the perfect solution yet, the issues explained in this previous post are still there, but it's at least already usable.
Actually, to solve the issues, we should adapt the code from SDLmain.m to create a dynamic library from which we could call something like nsAppInit() and nsAppCleanup(). Maybe this post from the SDL mailing list can help? |
|
Back to top |
|
|
revcompgeek
Joined: 24 Nov 2007 Posts: 27
|
Posted: Sat Apr 05, 2008 5:14 pm Post subject: |
|
|
Thank you. Applying what you said to the DMedia tutorials, I got the second one to work, but the third doesn't. My code is:
Code: | module derelict_test;
import std.string;
import std.stdio;
import derelict.sdl.sdl;
import derelict.opengl.gl;
import derelict.opengl.glu;
import platform;
// horizontal and vertical screen resolution
const int xResolution = 800;
const int yResolution = 600;
// number of bits per pixel used for display. 24 => true color
const int bitsPerPixel = 24;
// field of view => the angle our camera will see vertically
const float fov = 90.f;
// distance of the near clipping plane
const float nearPlane = .1f;
// distance of the far clipping plane
const float farPlane = 100.f;
/**
Setup some basic OpenGL parameters
*/
void setupGL() {
// switch to the projection mode matrix
glMatrixMode(GL_PROJECTION);
// load the identity matrix for projection
glLoadIdentity();
// setup a perspective projection matrix
gluPerspective(fov, cast(float)xResolution / yResolution, nearPlane, farPlane);
// switch back to the modelview transformation matrix
glMatrixMode(GL_MODELVIEW);
// load the identity matrix for modelview
glLoadIdentity();
}
void init() {
// initialize SDL, GL and GLU Derelict modules
DerelictSDL.load();
writefln("test");
DerelictGL.load();
writefln("test 2");
DerelictGLU.load();
writefln("test 3");
// initialize SDL's VIDEO module
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
// enable double-buffering
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
// create our OpenGL window
SDL_SetVideoMode(xResolution, yResolution, bitsPerPixel, SDL_OPENGL);
SDL_WM_SetCaption(toStringz("My SDL Window"), null);
setupGL();
}
// be nice and release all resources
void cleanup() {
// tell SDL to quit
SDL_Quit();
// release GL, GLU and SDL's shared libs
DerelictGLU.unload();
DerelictGL.unload();
DerelictSDL.unload();
}
void drawGLFrame() {
glBegin(GL_TRIANGLES);
glColor3f (1, 0, 0);
glVertex3f(-1, -1, -2);
glColor3f (0, 1, 0);
glVertex3f(1, -1, -2);
glColor3f (0, 0, 1);
glVertex3f(0, 1, -2);
glEnd();
}
void main() {
Platform.init();
writefln("Test 1");
init();
writefln("Test 2");
scope(exit) Platform.cleanup();
scope(exit) cleanup(); // when we exit, perform cleanup
mainLoop:
while (true) {
SDL_Event event;
// handle all SDL events that we might've received in this loop iteration
while (SDL_PollEvent(&event)) {
switch (event.type) {
// user has clicked on the window's close button
case SDL_QUIT:
break mainLoop;
// by default, we do nothing => break from the switch
default:
break;
}
}
// clear the screen. by default it clears to black
glClear(GL_COLOR_BUFFER_BIT);
// draw our stuff =)
drawGLFrame();
// swap the buffers, making our backbuffer the visible one
SDL_GL_SwapBuffers();
}
}
|
The output I get is:
Code: | Test 1
test
test 2
Error: Invalid library name
|
DerelictGLU.load() is not working. I am building with dsss. |
|
Back to top |
|
|
hugues
Joined: 09 Aug 2007 Posts: 20 Location: Brussels, Belgium
|
Posted: Sat Apr 05, 2008 5:36 pm Post subject: DerelictGLU not working on Mac OS X |
|
|
Indeed, the library paths for DerelictGLU for Mac OS X are empty. Actually, since the OpenGL framework contains libGLU.dylib, the GLU library is already loaded if the former is loaded and the GLU symbols should be loaded from it.
aldacron, is there a way to share dynamic libraries between the different Derelict parts? Or should we keep a list of already loaded libraries and not call dlopen() for those already in the list? |
|
Back to top |
|
|
aldacron
Joined: 05 May 2004 Posts: 1322 Location: Seoul, South Korea
|
Posted: Sun Apr 06, 2008 2:32 am Post subject: |
|
|
When I first realized this problem recently, I figured we would need to share the OpenGL lib handle with the GLU module. When I read this post just now, it dawned on me that this isn't necessary. Calling dlopen multiple times on the same library isn't an issue. I just consulted the spec to be sure:
Quote: | Only a single copy of an object file is brought into the address space, even if dlopen() is invoked multiple times in reference to the file, and even if different pathnames are used to reference the file. |
So it's safe to add the same paths to the glu module that are used by the opengl module. I'll do that right now and get it into the trunk. _________________ The One With D | The One With Aldacron | D Bits |
|
Back to top |
|
|
hugues
Joined: 09 Aug 2007 Posts: 20 Location: Brussels, Belgium
|
Posted: Sun Apr 06, 2008 3:40 am Post subject: Sharing OpenGL handle between GL and GLU on Mac OS X |
|
|
aldacron wrote: | Calling dlopen multiple times on the same library isn't an issue. I just consulted the spec to be sure:
Quote: | Only a single copy of an object file is brought into the address space, even if dlopen() is invoked multiple times in reference to the file, and even if different pathnames are used to reference the file. |
So it's safe to add the same paths to the glu module that are used by the opengl module. | Good catch . The dlclose() man on Mac OS X also states: Quote: | dlclose() releases a reference to the dynamic library or bundle referenced by handle. If the reference count drops to 0, the bundle is removed from the address space, and handle is rendered invalid. | So it's also safe to call dlclose() multiple times on the same handle. |
|
Back to top |
|
|
afb
Joined: 26 Jan 2005 Posts: 137 Location: Sweden
|
Posted: Fri Apr 18, 2008 12:46 am Post subject: Re: Derelict on Mac OS X - another solution |
|
|
aldacron wrote: | hugues wrote: |
I noticed that the first path in each header is now ./Frameworks/LIBNAME.framework/LIBNAME. Shouldn't it be ../Frameworks/LIBNAME.framework/LIBNAME (with two dots), like Crispy suggests? |
That's a copy-pasted typo. Thanks for catching it.
|
Actually it should be @executable_path/../Frameworks to make it search in the Frameworks directory of the current application bundle. |
|
Back to top |
|
|
afb
Joined: 26 Jan 2005 Posts: 137 Location: Sweden
|
Posted: Fri Apr 18, 2008 12:55 am Post subject: Re: SDLmain on Mac OS X |
|
|
hugues wrote: | Indeed, I found your page thanks to the other post that aldacron refers to. That is great for programs that want to use SDL and OpenGL by linking normally to the libraries (for users who don't understand how great is Derelict ). Your page was a little hard to find. Is there a central place where all D headers to popular libraries can be found? It would be great if there was a clear link to such a place on the Digital Mars "D Links" page. |
Like you say, "everyone" is using Derelict instead.
At one point in time, http://d-programming-language.org/ was suggested as an entry point to the D language and not just the reference compiler implementation - but then it died. And since everyone is using DMD and Bud and Derelict and DWT and so on, there's no interest in pushing any cross-platform alternatives. At least that is my personal impression...
Then again, now with D2 nobody is using D either. |
|
Back to top |
|
|
hugues
Joined: 09 Aug 2007 Posts: 20 Location: Brussels, Belgium
|
Posted: Tue Apr 22, 2008 2:54 pm Post subject: Re: Derelict on Mac OS X - another solution |
|
|
afb wrote: | Actually it should be @executable_path/../Frameworks to make it search in the Frameworks directory of the current application bundle. | That's right, indeed (see Mach-O Programming Topics: Loading Code at Runtime). This of course only works for applications inside a bundle, with frameworks correctly built as "Private Frameworks", as explained on that page. It is also possible to get the bundle path (or the executable path) with the Core Foundation functions CFBundleGetMainBundle(), CFBundleCopyBundleURL()/CFBundleCopyExecutableURL() and CFURLCopyFileSystemPath(), that work even for unbundled applications. The question is: should we support unbundled applications (to allow for small applications with all needed dynamic libraries as .dylib in the same directory as the executable)?
Meanwhile, we should already correct the paths as you suggest. |
|
Back to top |
|
|
doob
Joined: 06 Jan 2007 Posts: 367
|
Posted: Wed Sep 17, 2008 7:59 am Post subject: |
|
|
If I understand this topic correctly (and if it hasn't already been solved) the problem (or at least one of them) is that we don't want an extra static/shared library on osx. After I've been doing the dwt-cocoa port for a while I've got insight in how Objective-C (objc) works and it's possible to do what's needed without an extra library written in objc.
For example, looking at the first post in this topic:
Code: | void createAutoreleasePool() {
globalPool = [[NSAutoreleasePool alloc] init];
} |
The above objc code is translated into something like this (written in D):
Code: | void createAutoreleasePool() {
char* alloc = sel_registerName("alloc");
char* init = sel_registerName("init");
Class c = objc_getClass("NSAutoreleasePool");
id obj = objc_msgSend(cast(id)c, alloc);
globalPool = objc_msgSend(obj, init);
} |
"objc_msgSend", "objc_getClass" and "sel_registerName" are regular C functions that you can bind and "id" and "Class" are types that you can bind, all objc classes can be casted to the type "id". I already have all the bindings for the necessary objc functions and types (they just need to be extracted from the project I'm working on). If you want I can start to help to get this to work. |
|
Back to top |
|
|
aldacron
Joined: 05 May 2004 Posts: 1322 Location: Seoul, South Korea
|
Posted: Wed Sep 17, 2008 9:40 pm Post subject: |
|
|
doob wrote: | If I understand this topic correctly (and if it hasn't already been solved) the problem (or at least one of them) is that we don't want an extra static/shared library on osx. After I've been doing the dwt-cocoa port for a while I've got insight in how Objective-C (objc) works and it's possible to do what's needed without an extra library written in objc.
For example, looking at the first post in this topic:
Code: | void createAutoreleasePool() {
globalPool = [[NSAutoreleasePool alloc] init];
} |
The above objc code is translated into something like this (written in D):
Code: | void createAutoreleasePool() {
char* alloc = sel_registerName("alloc");
char* init = sel_registerName("init");
Class c = objc_getClass("NSAutoreleasePool");
id obj = objc_msgSend(cast(id)c, alloc);
globalPool = objc_msgSend(obj, init);
} |
"objc_msgSend", "objc_getClass" and "sel_registerName" are regular C functions that you can bind and "id" and "Class" are types that you can bind, all objc classes can be casted to the type "id". I already have all the bindings for the necessary objc functions and types (they just need to be extracted from the project I'm working on). If you want I can start to help to get this to work. |
If you can get this to work, that would be great. Ideally, this would happen without any user intervention, such as in the loader function of the SDL struct, after the shared library has finished loading but before the function returns. Then any cleanup code would go in the static module destructor. _________________ The One With D | The One With Aldacron | D Bits |
|
Back to top |
|
|
hugues
Joined: 09 Aug 2007 Posts: 20 Location: Brussels, Belgium
|
Posted: Thu Sep 18, 2008 2:22 pm Post subject: Objective-C in D? |
|
|
It’s funny that we have activity on this topic now. I didn't work on the problem since my last post until last week, where I played with SDLmain.m to try to be able to use it without the main() redefinition hack. I found a way to do it, as explained in this post. So now I have exactly the same behavior as using SDL in C with SDLmain.a: the app opens up correctly even when not in a bundle and launched from the command line, the Quit menu function works, etc.
I wanted to make a dynamic library only linked to Cocoa that would contain the SDLmain code. The problem is that the SDLmain code calls SDL functions (notably SDL_PushEvent() to post an SDL_QUIT event when the application receives a terminate message) and so must also be linked to SDL, or to some other code that could find the symbol at runtime. Either way is messy regarding derelict's principles. The idea of creating a dynamic library is finally not a good idea.
What to do now? The Cocoa initialization code has to be somewhere. It could be included in the SDL lib, what would have solved our problem a while ago, but it is not, at least not yet. We could modify SDL to include it, but this would mean that derelict wouldn’t be able to work with the official SDL distribution on the Mac, which is a bad idea.
The best solution (for now) seems to be to have this code included directly into derelict. It is Objective-C, derelict is D and should be able to be used by directly importing the code, without needing a separate build.
doob, your post is opening new hopes . Do you think we could re-code SDLmain in derelict with the method you suggest?
This is the code to be included:
http://www.libsdl.org/cgi/viewvc.cgi/tags/SDL/release-1.2.13/src/main/macosx/SDLMain.m?revision=3510&view=markup
Hugues De Keyzer |
|
Back to top |
|
|
doob
Joined: 06 Jan 2007 Posts: 367
|
Posted: Fri Sep 19, 2008 4:39 am Post subject: Re: Objective-C in D? |
|
|
Yes I think it's possible, you can do everything you can do in objc with the runtime functions I mentioned. It's a little tricky to create a new class that extends a objc class this way but it's possible. I will start to work on this as soon as I have time to. |
|
Back to top |
|
|
hugues
Joined: 09 Aug 2007 Posts: 20 Location: Brussels, Belgium
|
Posted: Fri Sep 19, 2008 10:29 am Post subject: Re: Objective-C in D? |
|
|
doob wrote: | Yes I think it's possible, you can do everything you can do in objc with the runtime functions I mentioned. It's a little tricky to create a new class that extends a objc class this way but it's possible. I will start to work on this as soon as I have time to. |
That's great! If you need any help with this, I'm available. |
|
Back to top |
|
|
doob
Joined: 06 Jan 2007 Posts: 367
|
Posted: Sat Sep 20, 2008 4:48 am Post subject: Re: Objective-C in D? |
|
|
hugues wrote: | That's great! If you need any help with this, I'm available. |
I could use a sample code to test with |
|
Back to top |
|
|
hugues
Joined: 09 Aug 2007 Posts: 20 Location: Brussels, Belgium
|
Posted: Sun Sep 21, 2008 3:30 pm Post subject: Re: Objective-C in D? |
|
|
doob wrote: | I could use a sample code to test with |
Here is a simple test program.
Code: | import derelict.opengl.gl;
import derelict.util.exception;
import derelict.sdl.sdl;
import std.stdio;
import std.string;
int main(char[][] arg)
{
DerelictSDL.load();
writefln("Initializing SDL…");
if (SDL_Init(SDL_INIT_VIDEO) == -1)
{
throw new Exception(format("Error initializing SDL: %s", toString(SDL_GetError())));
}
writefln("Loading OpenGL library…");
DerelictGL.load();
writefln("Loaded OpenGL library.");
GLVersion glv;
try
{
SDL_Surface* screen;
screen = SDL_SetVideoMode(1024, 576, 24, SDL_OPENGL);
if (!screen)
{
throw new Exception(format("Unable to set video mode: %s", toString(SDL_GetError())));
}
SDL_WM_SetCaption(toStringz("Derelict Test"), null);
try
{
writefln("Checking for available OpenGL version…");
glv = DerelictGL.availableVersion();
writefln("Check for available OpenGL version complete.");
}
catch (SharedLibProcLoadException e)
{
writefln("Problem loading OpenGL dynamic library: %s", e.toString());
}
writefln("Loaded OpenGL version: %s", DerelictGL.versionString(glv));
glClearColor(0.0, 0.125, 0.25, 0);
bool run = true;
do
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_KEYDOWN:
{
switch (event.key.keysym.sym)
{
case SDLK_ESCAPE:
{
writefln("Escape pressed");
run = false;
break;
}
default:
{
break;
}
}
break;
}
case SDL_QUIT:
{
writefln("Quit event");
run = false;
break;
}
default:
{
}
}
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
SDL_GL_SwapBuffers();
}
while (run)
}
finally
{
writefln("Closing SDL…");
SDL_Quit();
}
writefln("Execution successful.");
DerelictGL.unload();
DerelictSDL.unload();
return 0;
} |
This should show a dark blue window named "Derelict Test" that you can quit by pressing Esc. You should also be able to quit by choosing Quit from the app menu. Hide should also work.
Your code should be included in DerelictSDL.load(). To load the Cocoa framework and get function pointers, you should do something like this:
Code: | import derelict.util.loader;
SharedLib cocoa = Derelict_LoadSharedLib("Cocoa.framework/Cocoa");
char* function(char*) sel_registerName = cast(char* function(char*)) Derelict_GetProc(cocoa, "sel_registerName"); |
Hope this helps. If you need more info, don't hesitate to ask.
Hugues De Keyzer |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|