www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Procedural drawing using ndslice

reply Claude <no no.no> writes:
Hello,

I come from the C world and try to do some procedural terrain 
generation, and I thought ndslice would help me to make things 
look clean, but I'm very new to those semantics and I need help.

Here's my problem: I have a C-style rough implementation of a 
function drawing a disk into a 2D buffer. Here it is:


import std.math;
import std.stdio;

void draw(ref float[16][16] buf, int x0, int y0, int x1, int y1)
{
     float xc = cast(float)(x0 + x1) / 2;
     float yc = cast(float)(y0 + y1) / 2;
     float xr = cast(float)(x1 - x0) / 2;
     float yr = cast(float)(y1 - y0) / 2;

     float disk(size_t x, size_t y)
     {
         float xx, yy;
         xx = (x - xc) / xr;
         yy = (y - yc) / yr;
         return 1.0 - sqrt(xx * xx + yy * yy);
     }

     for (int y = 0; y < 16; y++)
     {
         for (int x = 0; x < 16; x++)
         {
             buf[x][y] = disk(x, y);
             writef(" % 3.1f", buf[x][y]);
         }
         writeln("");
     }
}

void main()
{
     float[16][16] buf;

     draw(buf, 2, 2, 10, 10);
}


The final buffer contains values where positive floats are the 
inside of the disk, negative are outside, and 0's represents the 
perimeter of the disk.

I would like to simplify the code of draw() to make it look more 
something like:

Slice!(stuff) draw(int x0, int y0, int x1, int y1)
{
     float disk(size_t x, size_t y)
     {
         // ...same as above
     }

     return Slice!stuff.something!disk.somethingElseMaybe;
}

Is it possible?

Do I need to back-up the slice with an array, or could the slice 
be used lazily and modified as I want using some other drawing 
functions.

auto diskNoiseSlice = diskSlice.something!AddNoiseFunction;

... until I do a:

auto buf = mySlice.array;

... where the buffer would be allocated in memory and filled with 
the values according to all the drawing primitives I used on the 
slice.
Feb 11 2016
next sibling parent John Colvin <john.loughran.colvin gmail.com> writes:
On Thursday, 11 February 2016 at 13:05:41 UTC, Claude wrote:
 Hello,

 I come from the C world and try to do some procedural terrain 
 generation, and I thought ndslice would help me to make things 
 look clean, but I'm very new to those semantics and I need help.

 Here's my problem: I have a C-style rough implementation of a 
 function drawing a disk into a 2D buffer. Here it is:


 import std.math;
 import std.stdio;

 void draw(ref float[16][16] buf, int x0, int y0, int x1, int y1)
 {
     float xc = cast(float)(x0 + x1) / 2;
     float yc = cast(float)(y0 + y1) / 2;
     float xr = cast(float)(x1 - x0) / 2;
     float yr = cast(float)(y1 - y0) / 2;

     float disk(size_t x, size_t y)
     {
         float xx, yy;
         xx = (x - xc) / xr;
         yy = (y - yc) / yr;
         return 1.0 - sqrt(xx * xx + yy * yy);
     }

     for (int y = 0; y < 16; y++)
     {
         for (int x = 0; x < 16; x++)
         {
             buf[x][y] = disk(x, y);
             writef(" % 3.1f", buf[x][y]);
         }
         writeln("");
     }
 }

 void main()
 {
     float[16][16] buf;

     draw(buf, 2, 2, 10, 10);
 }


 The final buffer contains values where positive floats are the 
 inside of the disk, negative are outside, and 0's represents 
 the perimeter of the disk.

 I would like to simplify the code of draw() to make it look 
 more something like:

 Slice!(stuff) draw(int x0, int y0, int x1, int y1)
 {
     float disk(size_t x, size_t y)
     {
         // ...same as above
     }

     return Slice!stuff.something!disk.somethingElseMaybe;
 }

 Is it possible?

 Do I need to back-up the slice with an array, or could the 
 slice be used lazily and modified as I want using some other 
 drawing functions.

 auto diskNoiseSlice = diskSlice.something!AddNoiseFunction;

 ... until I do a:

 auto buf = mySlice.array;

 ... where the buffer would be allocated in memory and filled 
 with the values according to all the drawing primitives I used 
 on the slice.
I had a go at trying the sort of thing you are talking about: http://dpaste.dzfl.pl/8f9da4f4cc34 That won't work with std.experimental.ndslice in 2.070.0, so either use dmd git master or use the latest version of ndslice in mir (https://github.com/DlangScience/mir).
Feb 11 2016
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 02/11/2016 05:05 AM, Claude wrote:
 Hello,

 I come from the C world and try to do some procedural terrain
 generation, and I thought ndslice would help me to make things look
 clean, but I'm very new to those semantics and I need help.

 Here's my problem: I have a C-style rough implementation of a function
 drawing a disk into a 2D buffer. Here it is:


 import std.math;
 import std.stdio;

 void draw(ref float[16][16] buf, int x0, int y0, int x1, int y1)
 {
      float xc = cast(float)(x0 + x1) / 2;
      float yc = cast(float)(y0 + y1) / 2;
      float xr = cast(float)(x1 - x0) / 2;
      float yr = cast(float)(y1 - y0) / 2;

      float disk(size_t x, size_t y)
      {
          float xx, yy;
          xx = (x - xc) / xr;
          yy = (y - yc) / yr;
          return 1.0 - sqrt(xx * xx + yy * yy);
      }

      for (int y = 0; y < 16; y++)
      {
          for (int x = 0; x < 16; x++)
          {
              buf[x][y] = disk(x, y);
              writef(" % 3.1f", buf[x][y]);
          }
          writeln("");
      }
 }

 void main()
 {
      float[16][16] buf;

      draw(buf, 2, 2, 10, 10);
 }


 The final buffer contains values where positive floats are the inside of
 the disk, negative are outside, and 0's represents the perimeter of the
 disk.

 I would like to simplify the code of draw() to make it look more
 something like:

 Slice!(stuff) draw(int x0, int y0, int x1, int y1)
 {
      float disk(size_t x, size_t y)
      {
          // ...same as above
      }

      return Slice!stuff.something!disk.somethingElseMaybe;
 }

 Is it possible?

 Do I need to back-up the slice with an array, or could the slice be used
 lazily and modified as I want using some other drawing functions.

 auto diskNoiseSlice = diskSlice.something!AddNoiseFunction;

 ... until I do a:

 auto buf = mySlice.array;

 ... where the buffer would be allocated in memory and filled with the
 values according to all the drawing primitives I used on the slice.
Here is a very very rough proof of concept: import std.stdio; struct LazyLine(Element, int Length, alias func) { int y; Element opIndex(int x) { return func(y, x); } } struct LazyRect(Element, int Height, int Width, alias func) { Element opIndex(A...)(A args) { const y = args[0]; const x = args[1]; auto line = LazyLine!(Element, Width, func)(y); return line[x]; } auto chain(alias nextFunc)() { return NextLazyRect!(Element, Height, Width, nextFunc, typeof(this))(this); } } struct NextLazyRect(Element, int Height, int Width, alias func, PreviousLazyRect) { PreviousLazyRect previous; Element opIndex(A...)(A args) { const y = args[0]; const x = args[1]; return func(previous[y, x]); } } auto abc(int line, int row) { return line * 10 + row; } auto xyz(float f) { return f / 10; } void main() { auto rect = LazyRect!(float, 3, 5, abc)().chain!xyz; foreach (line; 0 .. 5) { foreach (row; 0 .. 4) { writef("%6.1f", rect[line, row]); } writeln(); } } Output: 0.0 0.1 0.2 0.3 1.0 1.1 1.2 1.3 2.0 2.1 2.2 2.3 3.0 3.1 3.2 3.3 4.0 4.1 4.2 4.3 Ali
Feb 11 2016
parent Claude <no no.no> writes:
Thanks for your replies, John and Ali. I wasn't sure I was clear.

I'm going to try to see if I can fit Ali concept (totally lazy, 
which is what I was looking for) within ndslices, so that I can 
also use it in 3D and apply window() function to the result and 
mess around with it.
Feb 12 2016