www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Proper C Pointer Binding

reply =?UTF-8?B?IlLDs2JlcnQgTMOhc3psw7MgUMOh?= =?UTF-8?B?bGki?= writes:
I am programming a new GUI widget library based on OpenGL for D.
For that I manually bind the used OpenGL functions to D and create
an abstraction layer to draw things, boxes, texts, shapes, etc.

http://palaes.rudanium.org/HueApp/intro.php

The thing compiles nicely with SDL, FreeType, FTGL. But
for the text drawing I use some pretty lame binding currently.
It is a fresh part of the code and want to do it properly:

C Code:

unsigned long loadFont(char * path) {
   FTGLfont * font = FTGLloadFont(path);
   return (unsigned long) font;
}

void drawText(unsigned long font, unsigned size, char * text) {
   // do the text drawing here
}

void destroyFont(unsigned long font) {
   FTGLdestroyFont((FTGLfont * ) font);
}

D Code:

extern (C) ulong loadFont(char * path);

extern (C) void destroyFont(ulong font);

void main() {

   // init screen and OpenGL setup

   auto font = loadFont(cast (char * ) "Arial.TTF");

   scope (exit) destroyFont(font);

   // draw some text

   // close OpenGL and SDL with some second delay
}

This works properly, and long is surely large enough to hold
a pointer in it, I could use sizet, I know that would be better.

My problem is that auto font here is an ulong. Could that be
wrapped into a type Font so that it only accepts assignment
from other Font type but no insecure numeric caluclations
and make the loadFont return that Font type, and other
methods use Font as arguments?
Mar 26 2014
next sibling parent "R" <robertlaszlopali gmail.com> writes:
 void main() {

   // init screen and OpenGL setup

   auto font = loadFont(cast (char * ) "Arial.TTF");

   scope (exit) destroyFont(font);

   // draw some text

   // close OpenGL and SDL with some second delay
 }

Also I am not sure about the string casting to char * here. I have been told that literals are 0 terminated, but strings usually are not. Should I in your opinion create a wrapping function in D that does convert the string to a proper char * value? And how would I do that? Thanks in advance for all the help! Róbert László Páli
Mar 26 2014
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
R:

 void main() {

  // init screen and OpenGL setup

  auto font = loadFont(cast (char * ) "Arial.TTF");

  scope (exit) destroyFont(font);

  // draw some text

  // close OpenGL and SDL with some second delay
 }

Also I am not sure about the string casting to char * here. I have been told that literals are 0 terminated, but strings usually are not. Should I in your opinion create a wrapping function in D that does convert the string to a proper char * value? And how would I do that?

Generally try to avoid casts as much as possible in D 2.066, because they sometimes are wrong and the compiler is not catching your mistakes. Take a look at the toStringz function in Phobos. There is also the ".ptr" attribite of dynamic arrays. But a D string is (immutable char)[], so its ptr is (immutable char)*. Bye, bearophile
Mar 26 2014
prev sibling next sibling parent Mike Parker <aldacron gmail.com> writes:
On 3/26/2014 6:51 PM, "Róbert László Páli" wrote:
 I am programming a new GUI widget library based on OpenGL for D.
 For that I manually bind the used OpenGL functions to D and create
 an abstraction layer to draw things, boxes, texts, shapes, etc.

 http://palaes.rudanium.org/HueApp/intro.php

 The thing compiles nicely with SDL, FreeType, FTGL. But
 for the text drawing I use some pretty lame binding currently.
 It is a fresh part of the code and want to do it properly:

 C Code:

 unsigned long loadFont(char * path) {
    FTGLfont * font = FTGLloadFont(path);
    return (unsigned long) font;
 }

 void drawText(unsigned long font, unsigned size, char * text) {
    // do the text drawing here
 }

 void destroyFont(unsigned long font) {
    FTGLdestroyFont((FTGLfont * ) font);
 }

 D Code:

 extern (C) ulong loadFont(char * path);

 extern (C) void destroyFont(ulong font);

 void main() {

    // init screen and OpenGL setup

    auto font = loadFont(cast (char * ) "Arial.TTF");

    scope (exit) destroyFont(font);

    // draw some text

    // close OpenGL and SDL with some second delay
 }

 This works properly, and long is surely large enough to hold
 a pointer in it, I could use sizet, I know that would be better.

A big gaping hole here is that longs in C can be 32-bit or 64-bit depending on the compiler and platform. Any time you want to bind to anything using longs in C, you should import core.stdc.config and use the c_long and c_ulong types.
Mar 26 2014
prev sibling next sibling parent "ralex" <krckoorascic gmail.com> writes:
On Wednesday, 26 March 2014 at 09:51:04 UTC, Róbert László Páli 
wrote:
 I am programming a new GUI widget library based on OpenGL for D.
 For that I manually bind the used OpenGL functions to D and 
 create
 an abstraction layer to draw things, boxes, texts, shapes, etc.

 http://palaes.rudanium.org/HueApp/intro.php

 The thing compiles nicely with SDL, FreeType, FTGL. But
 for the text drawing I use some pretty lame binding currently.
 It is a fresh part of the code and want to do it properly:

 C Code:

 unsigned long loadFont(char * path) {
   FTGLfont * font = FTGLloadFont(path);
   return (unsigned long) font;
 }

 void drawText(unsigned long font, unsigned size, char * text) {
   // do the text drawing here
 }

 void destroyFont(unsigned long font) {
   FTGLdestroyFont((FTGLfont * ) font);
 }

 D Code:

 extern (C) ulong loadFont(char * path);

 extern (C) void destroyFont(ulong font);

 void main() {

   // init screen and OpenGL setup

   auto font = loadFont(cast (char * ) "Arial.TTF");

   scope (exit) destroyFont(font);

   // draw some text

   // close OpenGL and SDL with some second delay
 }

 This works properly, and long is surely large enough to hold
 a pointer in it, I could use sizet, I know that would be better.

 My problem is that auto font here is an ulong. Could that be
 wrapped into a type Font so that it only accepts assignment
 from other Font type but no insecure numeric caluclations
 and make the loadFont return that Font type, and other
 methods use Font as arguments?

You probably want something like this: struct Font { static Font opCall(string path) { Font f; f.fptr = loadFont(path.toStringz()); return s; } c_ulong fptr; } use it like this: Font arial = "Arial.TTF"; when pasing font to extern functionst that accept ulong use arial.fptr, in your (D) functions use Font.
Mar 26 2014
prev sibling next sibling parent "ralex" <krckoorascic gmail.com> writes:
   static Font opCall(string path) {
      Font f;
      f.fptr = loadFont(path.toStringz());
     return s;
   }

That should be return f; of course.
Mar 26 2014
prev sibling next sibling parent =?UTF-8?B?IlLDs2JlcnQgTMOhc3psw7MgUMOh?= =?UTF-8?B?bGki?= writes:
Thanks for the suggestions! I think then I will stay with
a wrapping struct. How would I make the extern C functions
invisible for other sources?

extern (C) c_ulong loadFont(char * path);

extern (C) void render(c_ulong font, char * text);

extern (C) void destroyFont(c_ulong font);

struct Font {

   private:

    c_ulong ptr;

   public:

     this(string path) {
       ptr = loadFont(path.toStringz());
     }

     void render(string text) {
       render(ptr, text.toStringz());
     }

     ~this() {
       destroyFont(ptr);
     }
}

When released as a library I would simply not put them
in the di Files, but I do not really want to use di-s for
developing the lib, but generate them for release.
Can I declare these extern C functions inline the
methods using it?
Apr 05 2014
prev sibling parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Saturday, 5 April 2014 at 13:55:27 UTC, Róbert László Páli 
wrote:
 When released as a library I would simply not put them
 in the di Files, but I do not really want to use di-s for
 developing the lib, but generate them for release.
 Can I declare these extern C functions inline the
 methods using it?

Unfortunately not, because they then their names get mangled incorrectly. Maybe DMD should be changed to not output private declarations, if they are not needed (i.e. don't affect struct layout, for example), then you can just declare them in a `private { }` block.
Apr 05 2014