Procedural drawing using ndslice
Ali Çehreli via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Thu Feb 11 18:08:36 PST 2016
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
More information about the Digitalmars-d-learn
mailing list