www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Basic standard graphics

reply bearophile <bearophileHUGS lycos.com> writes:
The RosettaCode site has a good list of simple and very small tasks that are a
good test for how much simple in a language is doing simple things (like the
Scriptometer site, but with a wider spectrum, and less competition).

The "Image Noise" task asks:
Generate a random black and white 320x240 image continuously, showing FPS
(frames per second).

This is the PureBasic implementation, it's far from being nice, but it's short
and it's doesn't contain lot of magic:
http://rosettacode.org/wiki/Image_Noise#PureBasic

I don't know if D will have a built-in GUIs kit (like Delphi or Tcl), but how
much simple&short will be a D implementation of the "Image Noise" task?

Even if D will not have a built-in GUI kit included in its standard
distribution zip, is it worth having in Phobos a basic graphics interface, so
writing simple graphics programs will be standard, regardless the usage of GTK,
WX, Aero, or other systems under it?

Do you know the language named "processing"? It is a kind of subset of Java,
and it's designed to show an interactive graphics window. It's used a lot, and
I am appreciating and using it for several years:
http://en.wikipedia.org/wiki/Processing_%28programming_language%29
http://processing.org/
A person has even created a partial JavaScript interpreter for it:
http://processingjs.org/
(There are several similar projects for Python, some of them are nice, but no
one of them is very famous, I don't know why).

A basic standard graphics interface/API for D will allow to quickly implement
something like the "processing" language based on D.

Bye,
bearophile
Nov 12 2010
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
A direct, line by line port of the C implementation works in D:

====
import core.stdc.stdlib;
import core.stdc.stdio;
import core.stdc.time;
import sdl.SDL;

uint frames = 0;
uint t_acc = 0;

void print_fps ()
{
  static Uint32 last_t = 0;
  Uint32 t = SDL_GetTicks();
  Uint32 dt = t - last_t;
  t_acc += dt;
  if (t_acc > 1000)
  {
    uint el_time = t_acc / 1000;
    printf("- fps: %g\n",
            cast(float) frames / cast(float) el_time);
    t_acc = 0;
    frames = 0;
  }
  last_t = t;
}

void blit_noise(SDL_Surface *surf)
{
  uint i;
  long dim = surf.w * surf.h;
  while (1)
  {
    SDL_LockSurface(surf);
    for (i=0; i < dim; ++i) {
      (cast(ubyte *)surf.pixels)[i] = ((rand() & 1) ? 255 : 0);
    }
    SDL_UnlockSurface(surf);
    SDL_Flip(surf);
    ++frames;
    print_fps();
  }
}

void main()
{
  SDL_Surface *surf = null;
  srand(time(null));
  SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO);
  surf = SDL_SetVideoMode(320, 240, 8, SDL_DOUBLEBUF | SDL_HWSURFACE);
  blit_noise(surf);
}
====

That's 50 lines.


This is my big "meh" about Rosettacode - virtually everything C can do, D can do
in an almost identical fashion, using the same libraries and everything.

I made only a small handful of edits there. Change include to import, add the
keyword cast to the casts, and change -> to . Done.
Nov 12 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Adam D. Ruppe:

 A direct, line by line port of the C implementation works in D:
You may add it to that RosettaCode page, just adding a note that it's a C-like implementation.
 This is my big "meh" about Rosettacode - virtually everything C can do, D can
do
 in an almost identical fashion, using the same libraries and everything.
That's not a fault of Rosettacode, it's more a "meh" of D language itself ;-) D is multi-level language, you may use it as C, but you may also want to use it a higher levels not allowed (or just not idiomatic) in C. If you take a look at the RosettaCode site you may find tens of D implementations that I have translated from Python (or Haskell) instead, and they are sometimes quite different from the C ones. Thank you for your D implementation of that task. But you seem to have missed about 80% of the purpose of my post :-) If you take a look at my post you may also see I have given a link to the PureBasic implementation (instead to the C version) this is not a random thing. I think D has to aim to something higher level than that C code (or your C-like D code). And I was talking about a standard basic graphics interface for Phobos. Bye, bearophile
Nov 12 2010
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
bearophile:
 That's not a fault of Rosettacode, it's more a "meh" of D
 language itself ;-)
I'd say the opposite: it means all your existing knowledge can be used straight up. This is also why I don't take people's complaints about D's library situation seriously either. It is a superset of C, and you can use all that stuff with a minimal amount of fuss. And even using it in C style is still better than C itself, thanks to the little enhancements like strings that don't suck, nested functions, and scope statements.
 If you take a look at the RosettaCode site you may find tens of D
 implementations that I have translated from Python (or Haskell)
 instead, and they are sometimes quite different from the C ones.
Yes, I've seen many of your posts about it. (btw just because you get no responses doesn't mean your posts were ignored! Many of us read them but have very little to add or too little time to post, so we don't say anything.)
 If you take a look at my post you may also see I have given a link to the
PureBasic implementation (instead to the C version) Yea, but it's not significantly different. Hell, if you write the C/D in the same fashion of the Basic (no functions, just a linear main), the C has an almost equal line count! (37 lines for C without functions, vs 36 lines for PureBasic Proof: http://arsdnet.net/noise.d ). So, what's the big benefit there? Let's walk through it. They work /exactly/ the same way. Open the window (OpenWindow vs SDL_SetVideoMode) Do the drawing (StartDrawing vs SDL_LockSurface) Flip buffers when done (FlipBuffer vs SDL_Flip) Check the time Output the FPS Identical, right down to the individual functions! Every C call has a one-to-one mapping to PureBasic. So, really, there's no difference here at all aside from C and D using {} and Basic using If/EndIf.
 I think D has to aim to something higher level than that C code
 (or your C-like D code).
My D game engine (built on top of SDL and OpenGL) works by having a frame callback. Here's an old post I made on another forum a couple years ago showing a trivial Pong game in D1: http://sveit.com/forum/viewtopic.php?f=32&t=2051 It gives joystick and transparent network support for a graphical game in just a little over 100 lines. With some of my new techniques developed in the years past that, I could cut its length almost in half, using main mixins and combining variables on one line. I haven't ported my engine to D2 yet since I've been working almost non-stop in my code time (which results in web app based stuff coming out of me), but I want to eventually. When I do, we'll kick the ass of these kind of tasks.
 And I was talking about a standard basic graphics interface for
 Phobos.
Meh, it might be nice, but C gets by without one, and we can do everything C can do.
Nov 12 2010
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
I posted a simplified version of the C port to the site:

http://rosettacode.org/wiki/Image_Noise#D

As for line count, this is tied with OCaml for shortest implementation on the
page, and is IMO the most readable of them all!
Nov 12 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Adam D. Ruppe:

 I posted a simplified version of the C port to the site:
 
 http://rosettacode.org/wiki/Image_Noise#D
The indents now are two spaces because RosettaCode asks for shorter lines. I have not compiled the modified version, so you may test if it works still; and you may add the number of frames per second it shows on your computer (you may add a bit of info on your PC too). std.random.uniform is probably very slow if you need just random bits :-) I vaguely remember some Knuth code to generate random bits fast. It may be added to std.random because random bits are a common enough need. Regarding that SDL wrapper, your code contains lines like (surface = surf): import sdl.SDL; auto surface = SDL_SetVideoMode(320, 240, 8, ...); I thinks this is more dtonic: import sdl; auto surface = sdl.SetVideoMode(320, 240, 8, ...); Or even, probably better for D: import sdl; auto surface = sdl.setVideoMode(320, 240, 8, ...); Bye, bearophile
Nov 12 2010
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
bearophile wrote:
  I have not compiled the modified version, so you may test if it works still
Yes, it still works. The FPS on my computer hovers around 155. The C version is about 180. If I change it from std.random.uniform to core.stdc.stdlib.rand, it gives equal results to C.
 Regarding that SDL wrapper [...]
It isn't a wrapper - it is just an interface to the C functions. Everything is a direct matchup: C -> D #include <SDL/SDL.h> -> import sdl.SDL; And the function and type names are the same as the C headers. (I think my SDl import is auto-generated from the C, though I'm not sure. I downloaded it from the internet years ago.) A wrapper library should add value rather than just rename things. Like how my mysql.d file puts mysql_query underneath a Result query(T...)(string sql, T t); function that handles escaping from any data type and returns a D style Range of the results. But calling raw C MySQL library is a pain in the ass. Raw C style SDL is pretty simple most the time.
Nov 12 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Adam D. Ruppe:

 Yes, it still works. The FPS on my computer hovers around 155.
 The C version is about 180.
 
 If I change it from std.random.uniform to core.stdc.stdlib.rand, it gives equal
 results to C.
Good :-) If you want you may replace the writeln() (and remove std.stdio import) with a SDL_WM_SetCaption() (and see if it runs still). Bye, bearophile
Nov 12 2010
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
 If you want you may replace the writeln() (and remove std.stdio
 import) with a SDL_WM_SetCaption() (and see if it runs still).
Yes, it worked, with two changes. SDL_WM_SetCaption(toStringz("FPS: " ~ to!string(frameNumber / (totalTime / 1000.0))), null); I had to import std.conv to do the float -> string conversion and std.string to get toStringz. This line is getting a little long with all the parenthesis for toStringz and to!string together! My SDL headers were also D1 so I had to edit them to add the const to the C function prototype too. I think that's legal D1 too so I'll leave it that way. My interface files are just really old. Anyway, it generally works but cut the FPS in half on my computer (linux using Blackbox window manager). Updating the window is a little slow compared to writing to stdout.
Nov 12 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Adam D. Ruppe:

       SDL_WM_SetCaption(toStringz("FPS: " ~
             to!string(frameNumber / (totalTime / 1000.0))), null);
std.conv.text() may be better there (untested): SDL_WM_SetCaption(toStringz(text("FPS: ", frameNumber / (totalTime / 1000.0))), null);
 Anyway, it generally works but cut the FPS in half on my computer (linux
 using Blackbox window manager). Updating the window is a little
 slow compared to writing to stdout.
I see. So let's drop this idea then. Thank you for your work. Bye, bearophile
Nov 12 2010
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
bearophile wrote:
 std.conv.text() may be better there (untested):
Cool! I never realized that function existed. It might be a nice enhancement to add a ctext() that returns the string zero-terminated and as a char* for use with C functions. (Actually, I think C functions should take ubyte* instead of char* because they aren't necessarily UTF-8 but most bindings don't do this so char* might work better in practice. Or maybe inventing a new typedef or struct just for C is the best.) While toStringz does this, a helper function might make C libraries just a little easier and safer to use.
Nov 12 2010
parent Adam D. Ruppe <destructionator gmail.com> writes:
 Actually, I think C functions should take ubyte* instead of char*
 because they aren't necessarily UTF-8
I thought about this a little more and changed my mind. char* (maybe const) might not be ideologically pure but is the best choice because: a) It is what people expect and b) It lets string literals keep working (with the ptr property) (b) is a big helper in convenience and it helps C functions feel like they belong in D instead of being annoying to work with.
Nov 12 2010
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Adam D. Ruppe:

 I'd say the opposite: it means all your existing knowledge can be used
straight up.
Of course :-) I have adapted tons of C code to D1 and I like this quality of D.
 (btw just because you get no responses doesn't mean your posts
 were ignored! Many of us read them but have very little to add
 or too little time to post, so we don't say anything.)
Thank you very much :-)
 Identical, right down to the individual functions! Every C call has a
one-to-one
 mapping to PureBasic.
You are right.
 Here's an old post I made on another forum a couple years
 ago showing a trivial Pong game in D1:
 
 http://sveit.com/forum/viewtopic.php?f=32&t=2051
It's cute, it reminds me the recent JavaScript code you may find around on the web that uses the canvas.
 With some of my new techniques developed in the years past that, I could cut
its
 length almost in half, using main mixins and combining variables on one line.
Powerful techniques indeed :o) Bye and thank you for your answers. I've seen you have just added your D implementation on the RosettaCode site, I may tweak it a bit, if you don't mind. Bye, bearophile
Nov 12 2010
parent Adam D. Ruppe <destructionator gmail.com> writes:
bearophile wrote:

 It's cute, it reminds me the recent JavaScript code you may
 find around on the web that uses the canvas.
Yes, partially. I originally wrote that little class in C++ to simplify the creation of little old console style games. The D1 version simplified the C++ quite a lot and was the first serious project I did in D. The thing I like most is the frame.run method that is automatically called on a timer. Saves so much boilerplate from the old method; made me feel like I was coding for DOS again!
 Powerful techniques indeed
I've really been liking main() mixins recently. My CGI code includes a mixin GenericMain() which gives you a function that automatically wraps your function in an exception handler that outputs HTTP 500 responses and lets you take the CGI class as an argument, so you can do a cgimain(Cgi cgi) instead of main(string[] args). Maybe a variety of these "alternative main" implementations might be a cool addition to the standard library, though I'm not sure how much help it would actually be outside something like CGI where there's several lines of boring boilerplate to convert to a better error output.
 I've seen you have just added your D implementation on the
 RosettaCode site, I may tweak it a bit, if you don't mind.
Of course, have fun!
Nov 12 2010
prev sibling next sibling parent so <so so.do> writes:
Graphics interfaces are very subjective, not having an official gui  
library in most cases IMHO much better than having one.

main reasons they exist, am i wrong?
Having a solid support for libraries like qt and wx is much more important  
i would say.

OTOH a basic library just to get a window context and some widgets for  
experiments/debugs (if this is what you mean) could be handy,
still i don't see if it would add something to D.

-- 
Using Opera's revolutionary email client: http://www.opera.com/mail/
Nov 12 2010
prev sibling parent reply spir <denis.spir gmail.com> writes:
On Fri, 12 Nov 2010 16:39:54 -0500
bearophile <bearophileHUGS lycos.com> wrote:

 The "Image Noise" task asks:
 Generate a random black and white 320x240 image continuously, showing FPS=
(frames per second).
=20
 This is the PureBasic implementation, it's far from being nice, but it's =
short and it's doesn't contain lot of magic:
 http://rosettacode.org/wiki/Image_Noise#PureBasic
=20
 I don't know if D will have a built-in GUIs kit (like Delphi or Tcl), but=
how much simple&short will be a D implementation of the "Image Noise" task?
=20
 Even if D will not have a built-in GUI kit included in its standard distr=
ibution zip, is it worth having in Phobos a basic graphics interface, so wr= iting simple graphics programs will be standard, regardless the usage of GT= K, WX, Aero, or other systems under it? I'm 100% for this proposal. Not necessarily in Phobos -- but having such a = tool available for quick & easy graphical output, such as drawing a functio= n's curve, is definitely a great idea. Now, the PureBasic example does this via a GUI/event loop window. It's not = what I have in mind for my use cases. Rather, I would be in favor of a simp= le graphic frame that could be used like in good old times we used to draw = directly on the video -- when this was easy to do, just using x,y pixel coo= rdinates. Optionnally, a set of plotting/drawing routines, including vector= image primitives. (An inspiration for this may be Logo.) I have no idea how to implement the base graphic frame, but once it's in pl= ace, I would certainly help in feeding the module with useful routines. Denis -- -- -- -- -- -- -- vit esse estrany =E2=98=A3 spir.wikidot.com
Nov 13 2010
next sibling parent reply Matthias Pleh <sufu alter.com> writes:
Am 13.11.2010 11:56, schrieb spir:
 On Fri, 12 Nov 2010 16:39:54 -0500
 bearophile<bearophileHUGS lycos.com>  wrote:

 The "Image Noise" task asks:
 Generate a random black and white 320x240 image continuously, showing FPS
(frames per second).

 This is the PureBasic implementation, it's far from being nice, but it's short
and it's doesn't contain lot of magic:
 http://rosettacode.org/wiki/Image_Noise#PureBasic

 I don't know if D will have a built-in GUIs kit (like Delphi or Tcl), but how
much simple&short will be a D implementation of the "Image Noise" task?

 Even if D will not have a built-in GUI kit included in its standard
distribution zip, is it worth having in Phobos a basic graphics interface, so
writing simple graphics programs will be standard, regardless the usage of GTK,
WX, Aero, or other systems under it?
I'm 100% for this proposal. Not necessarily in Phobos -- but having such a tool available for quick& easy graphical output, such as drawing a function's curve, is definitely a great idea. Now, the PureBasic example does this via a GUI/event loop window. It's not what I have in mind for my use cases. Rather, I would be in favor of a simple graphic frame that could be used like in good old times we used to draw directly on the video -- when this was easy to do, just using x,y pixel coordinates. Optionnally, a set of plotting/drawing routines, including vector image primitives. (An inspiration for this may be Logo.) I have no idea how to implement the base graphic frame, but once it's in place, I would certainly help in feeding the module with useful routines. Denis -- -- -- -- -- -- -- vit esse estrany ☣ spir.wikidot.com
I'm working on some basic graphic-routines in d inspired by http://www.antigrain.com/ Maybe this will be helpfull!
Nov 13 2010
parent reply Peter Alexander <peter.alexander.au gmail.com> writes:
On 13/11/10 11:14 AM, Matthias Pleh wrote:
 I'm working on some basic graphic-routines in d
 inspired by
 http://www.antigrain.com/

 Maybe this will be helpfull!
Are you building it on top of an existing window/video layer (e.g. SDL)?
Nov 13 2010
parent Matthias Pleh <sufu alter.com> writes:
Am 13.11.2010 14:03, schrieb Peter Alexander:
 On 13/11/10 11:14 AM, Matthias Pleh wrote:
 I'm working on some basic graphic-routines in d
 inspired by
 http://www.antigrain.com/

 Maybe this will be helpfull!
Are you building it on top of an existing window/video layer (e.g. SDL)?
I try to make platform-files for x11,win32,mac and sdl. But only for testing the graphic-allgorythms. The library itself should be platform-independent!! But for now I'm only working on the win32 part
Nov 13 2010
prev sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
spir wrote:
  It's not  what I have in mind for my use cases. Rather,
 I would be in favor of a simple graphic frame that could
 be used like in good old times we used to draw
 directly on the video -- when this was easy to do,
 just using x,y pixel coordinates.
Absolutely, my craving for the good old DOS days is what inspired my D1 game engine, and another little block of code which I called "dimage". It actually uses two helper C modules I wrote, but it just calls the OS so it could be easily ported to raw D. Here it is: http://arsdnet.net/dcode/dimage/ The way it works is you draw a bitmap (or load it from a .bmp file) then call the display method. display calls out to win32 or X11 to pop up a window showing the bitmap and blocks until the user hits any key to exit. So it just shows an image quickly and easily. My plan with it was simple image viewing or graph plotting. I never finished it completely but you are free to take what I started there and play with it if you like. Note this code is really old. It doesn't compile on the new dmd2 and it does a lot of copying... actually I shouldn't throw this on people and expect them to fix it. Is there interest in me fixing it myself and packing it as one little D file? It is very simple: write raw pixels to an array, call the function. It pops up and remains static until the user presses any key to close it.
Nov 13 2010