1 /**
2   This module defines the notion of an Image.   
3   An Image is simply defined as a 2D array of elements, with
4   methods to set/get those elements.
5 
6   The Image concept might be the basis of a generic software renderer.
7  */
8 module gfm.image.image;
9 
10 import gfm.math.vector;
11 
12 // An image is a concept
13 
14 
15 /**
16  * Test if I is an Image.
17  *
18  * An image has the following features:
19  * $(UL
20  * $(LI defines element_t as the type of elements (eg. pixels).)
21  * $(LI has a dimension of type vec2i.)
22  * $(LI has getter/setter for individual elements.)
23  * )
24  */
25 template isImage(I)
26 {
27     enum bool isImage = is(typeof(
28     {
29         I i;                            // can be defined
30         const I ci;
31         I.element_t e;                  // defined the type element_t
32         vec2i dim = ci.dimension;       // has dimension
33         I.element_t f = ci.get(0, 0);   // can get element
34         i.set(0, 0, f);                 // can set element
35     }()));
36 }
37 
38 /// Returns: true if an image contains the given point.
39 deprecated("Use ae.utils.graphics instead") 
40 bool contains(I)(I img, int x, int y) if (isImage!I)
41 {
42     return cast(uint)x < img.dimension.x && cast(uint)y < img.dimension.y;
43 }
44 
45 /// EdgeMode defines how images are sampled beyond their boundaries.
46 deprecated("Use ae.utils.graphics instead")
47 enum EdgeMode
48 {
49     BLACK,  /// Return black.
50     CLAMP,  /// Clamp to edge.
51     REPEAT, /// Repeat from the other side of the image.
52     CRASH   /// Crash.
53 }
54 
55 
56 /// Draws a single pixel.
57 deprecated("Use ae.utils.graphics instead")
58 void drawPixel(I, P)(I img, int x, int y, P p) if (isImage!I && is(P : I.element_t))
59 {
60     if (!img.contains(x, y))
61         return;
62     img.set(x, y, p);
63 }
64 
65 /// Returns: pixel of an Image at position (x, y). 
66 /// At boundaries, what happens depends on em.
67 deprecated("Use ae.utils.graphics instead")
68 I.element_t getPixel(I)(I img, int x, int y, EdgeMode em)
69 {
70     if (!img.contains(x, y))
71     {
72         final switch(em)
73         {
74             case EdgeMode.BLACK:
75                 return I.element_t.init;
76 
77             case EdgeMode.CLAMP:
78             {
79                 if (x < 0) x = 0;
80                 if (y < 0) y = 0;
81                 if (x >= img.dimension.x) x = img.dimension.x - 1;
82                 if (y >= img.dimension.y) y = img.dimension.y - 1;
83                 break;
84             }
85 
86             case EdgeMode.REPEAT:
87             {
88                 x = moduloWrap!int(x, img.dimension.x);
89                 y = moduloWrap!int(y, img.dimension.y);
90                 break;
91             }
92 
93             case EdgeMode.CRASH: 
94                 assert(false);
95         }
96     }
97     
98     return img.get(x, y);
99 }
100 
101 /// Draws a rectangle outline in an Image.
102 deprecated("Use ae.utils.graphics instead")
103 void drawRect(I, P)(I img, int x, int y, int width, int height, P e) if (isImage!I && is(P : I.element_t))
104 {
105     drawHorizontalLine(img, x, x + width, y, e);
106     drawHorizontalLine(img, x, x + width, y + height - 1, e);
107     drawVerticalLine(img, x, y, y + height, e);
108     drawVerticalLine(img, x + width - 1, y, y + height, e);
109 }
110 
111 /// Fills an uniform rectangle area in an Image.
112 deprecated("Use ae.utils.graphics instead")
113 void fillRect(I, P)(I img, int x, int y, int width, int height, P e) if (isImage!I && is(P : I.element_t))
114 {
115     for (int j = 0; j < height; ++j)
116         for (int i = 0; i < width; ++i)
117             img.set(x + i, y + j, e);
118 }
119 
120 /// Fills a whole image with a single element value.
121 deprecated("Use ae.utils.graphics instead")
122 void fillImage(I, P)(I img, P e) if (isImage!I && is(P : I.element_t))
123 {
124     immutable int width = img.dimension.x;
125     immutable int height = img.dimension.y;
126     for (int j = 0; j < height; ++j)
127         for (int i = 0; i < width; ++i)
128             img.set(i, j, e);
129 }
130 
131 /// Performs an image blit from src to dest.
132 deprecated("Use ae.utils.graphics instead")
133 void copyRect(I)(I dest, I src) if (isImage!I)
134 {
135     // check same size
136     assert(dest.dimension == src.dimension);
137 
138     immutable int width = dest.dimension.x;
139     immutable int height = dest.dimension.y;
140     for (int j = 0; j < height; ++j)
141         for (int i = 0; i < width; ++i)
142         {
143             auto p = src.get(i, j);
144             dest.set(i, j, p);
145         }
146 }
147 
148 /// Draws an horizontal line on an Image.
149 deprecated("Use ae.utils.graphics instead")
150 void drawHorizontalLine(I, P)(I img, int x1, int x2, int y, P p) if (isImage!I && is(P : I.element_t))
151 {
152     for (int x = x1; x < x2; ++x)
153         img.drawPixel(x, y, p);
154 }
155 
156 /// Draws a vertical line on an Image.
157 deprecated("Use ae.utils.graphics instead")
158 void drawVerticalLine(I, P)(I img, int x, int y1, int y2, P p) if (isImage!I && is(P : I.element_t))
159 {
160     for (int y = y1; y < y2; ++y)
161         img.drawPixel(x, y, p);
162 }