1 /* 2 * Copyright (c) 2015-2017, by Laszlo Szeremi, under Boost license 3 * 4 * Pixel Perfect Engine, graphics.common module 5 */ 6 7 module pixelperfectengine.graphics.common; 8 9 //public import CPUblit.colorspaces; 10 11 import dimage.types : ARGB8888BE; 12 13 /** 14 * Graphics primitive. Represents a single point on a 2D field. 15 */ 16 public struct Point { 17 public int x, y; 18 /** 19 * Moves the point by the given amount 20 */ 21 public void relMove (int rX, int rY) @safe @nogc pure nothrow { 22 x += rX; 23 y += rY; 24 } 25 public string toString() const { 26 import std.conv : to; 27 return "x: " ~ to!string(x) ~ " ; y: " ~ to!string(y); 28 } 29 bool opEquals(const Point other) @safe @nogc pure nothrow const { 30 return this.x == other.x && this.y == other.y; 31 } 32 public Point opBinary(string op, R)(const R rhs) const { 33 mixin("return Point(x " ~ op ~ " rhs.x , y " ~ op ~ "rhs.y);"); 34 } 35 } 36 /** 37 * Graphics primitive. Represents a box on a 2D field. 38 * Note on area calculation: The smallest box that can be represented is 1 * 1, as it counts the endpoints as part of the box. 39 * This behavior got added with 0.10.0, to standardize various behaviors of the engine, and fix some odd behavior the GUI 40 * drawing functions had. 41 */ 42 public struct Box { 43 public int left, top, right, bottom; 44 this(int left, int top, int right, int bottom) @safe pure nothrow @nogc { 45 this.left=left; 46 this.top=top; 47 this.right=right; 48 this.bottom=bottom; 49 } 50 /** 51 * Returns the width of the represented box. 52 */ 53 public @property @nogc @safe nothrow pure int width() const { 54 return right - left + 1; 55 } 56 /** 57 * Sets the width of the represented box while keeping the lefthand coordinate. 58 */ 59 public @property int width(int val) @nogc @safe pure nothrow { 60 right = left + val - 1; 61 return right - left + 1; 62 } 63 /** 64 * Returns the height of the represented box. 65 */ 66 public @property @nogc @safe nothrow pure int height() const { 67 return bottom - top + 1; 68 } 69 /** 70 * Sets the height of the represented box while keeping the top coordinate. 71 */ 72 public @property int height(int val) @nogc @safe pure nothrow { 73 bottom = top + val - 1; 74 return bottom - top + 1; 75 } 76 /** 77 * Returns the area of the represented box. 78 */ 79 public @property @nogc @safe nothrow pure size_t area() const { 80 return width * height; 81 } 82 /** 83 * Moves the box to the given position. 84 */ 85 public void move(int x, int y) @nogc @safe nothrow pure { 86 right = x + width(); 87 bottom = y + height(); 88 left = x; 89 top = y; 90 } 91 /** 92 * Moves the box by the given values. 93 */ 94 public void relMove(int x, int y) @nogc @safe nothrow pure { 95 left = left + x; 96 right = right + x; 97 top = top + y; 98 bottom = bottom + y; 99 } 100 /** 101 * Returns true if the given point is between the coordinates. 102 */ 103 public bool isBetween(int x, int y) @nogc @safe pure nothrow const { 104 return (x >= left && x <= right && y >= top && y <= bottom); 105 } 106 ///Ditto 107 public bool isBetween(Point p) @nogc @safe pure nothrow const { 108 return (p.x >= left && p.x <= right && p.y >= top && p.y <= bottom); 109 } 110 /** 111 * Operator overloading for scalar values. 112 * `-`: Adds to left and top, substracts from right and bottom. (Shrinks by amount) 113 * `+`: Subtracts from left and top, adds to right and bottom. (Grows by amount) 114 */ 115 public Box opBinary(string op)(const int rhs) @nogc @safe pure nothrow const { 116 static if (op == "-") { 117 return Box(left + rhs, top + rhs, right - rhs, bottom - rhs); 118 } else static if (op == "+") { 119 return Box(left - rhs, top - rhs, right + rhs, bottom + rhs); 120 } else static assert(0, "Unsupported operator!"); 121 } 122 ///Returns the upper-left corner. 123 public @property Point cornerUL() @nogc @safe pure nothrow const { 124 return Point(left, top); 125 } 126 ///Returns the upper-right corner. 127 public @property Point cornerUR() @nogc @safe pure nothrow const { 128 return Point(right, top); 129 } 130 ///Returns the lowew-left corner. 131 public @property Point cornerLL() @nogc @safe pure nothrow const { 132 return Point(left, bottom); 133 } 134 ///Returns the lower-right corner. 135 public @property Point cornerLR() @nogc @safe pure nothrow const { 136 return Point(right, bottom); 137 } 138 ///Pads the edges of the given box by the given amounts and returns a new Box. 139 public Box pad(const int horiz, const int vert) @nogc @safe pure nothrow const { 140 return Coordinate(left + horiz, top + vert, right - horiz, bottom - vert); 141 } 142 /** 143 * Returns a string with the coordinates that is useful for debugging 144 */ 145 public string toString() const { 146 import pixelperfectengine.system.etc; 147 import std.conv; 148 /*return "Coordinate: Left: 0x" ~ intToHex(left, 8) ~ " Top: 0x" ~ intToHex(top, 8) ~ " Right: 0x" ~ intToHex(right, 8) ~ " Bottom: 0x" ~ intToHex(bottom, 8) ~ 149 " Width: 0x" ~ intToHex(width(), 8) ~ " Height: 0x" ~ intToHex(height(), 8);*/ 150 return "Coordinate: Left: " ~ to!string(left) ~ " Top: " ~ to!string(top) ~ " Right: " ~ to!string(right) ~ 151 " Bottom: " ~ to!string(bottom) ~ " Width: " ~ to!string(width()) ~ " Height: " ~ to!string(height()); 152 } 153 public static Box bySize(int x, int y, int w, int h) @nogc @safe pure nothrow { 154 return Box(x, y, x + w - 1, y + h - 1); 155 } 156 } 157 alias Coordinate = Box; 158 /** 159 * Defines polygons for sprite transformation (eg. scaling, rotation). 160 * Most likely will be removed due to lack of use. 161 */ 162 public struct Quad{ 163 public int midX, midY; ///Defines the midpoint to reduce the need for precision. Corners are referenced to this point 164 public float cornerAX, cornerAY, cornerAZ; ///Upper-left corner mapping 165 public float cornerBX, cornerBY, cornerBZ; ///Upper-right corner mapping 166 public float cornerCX, cornerCY, cornerCZ; ///Lower-left corner mapping 167 public float cornerDX, cornerDY, cornerDZ; ///Lower-right corner mapping 168 } 169 alias Color = ARGB8888BE; 170 /+ 171 /** 172 * Various representations of color with various accessibility modes. 173 * Probably will be replaced with a struct from either CPUBLiT or dimage. 174 */ 175 public struct Color{ 176 union{ 177 uint raw; ///Raw representation in integer form, also forces the system to align in INT32. 178 ubyte[4] colors; ///Normal representation, aliases are used for color naming. 179 } 180 version(LittleEndian){ 181 ///Returns the alpha channel of the color 182 public @nogc @safe @property pure nothrow ubyte alpha() const{ return colors[0]; } 183 ///Returns the red channel of the color 184 public @nogc @safe @property pure nothrow ubyte red() const{ return colors[1]; } 185 ///Returns the green channel of the color 186 public @nogc @safe @property pure nothrow ubyte green() const{ return colors[2]; } 187 ///Returns the blue channel of the color 188 public @nogc @safe @property pure nothrow ubyte blue() const{ return colors[3]; } 189 ///Sets the alpha channel of the color 190 public @nogc @safe @property pure nothrow ubyte alpha(ubyte value) { return colors[0] = value; } 191 ///Sets the red channel of the color 192 public @nogc @safe @property pure nothrow ubyte red(ubyte value) { return colors[1] = value; } 193 ///Sets the green channel of the color 194 public @nogc @safe @property pure nothrow ubyte green(ubyte value) { return colors[2] = value; } 195 ///Sets the blue channel of the color 196 public @nogc @safe @property pure nothrow ubyte blue(ubyte value) { return colors[3] = value; } 197 }else{ 198 ///Returns the alpha channel of the color 199 public @nogc @safe @property pure nothrow ubyte alpha() const{ return colors[3]; } 200 ///Returns the red channel of the color 201 public @nogc @safe @property pure nothrow ubyte red() const{ return colors[2]; } 202 ///Returns the green channel of the color 203 public @nogc @safe @property pure nothrow ubyte green() const{ return colors[1]; } 204 ///Returns the blue channel of the color 205 public @nogc @safe @property pure nothrow ubyte blue() const{ return colors[0]; } 206 ///Sets the alpha channel of the color 207 public @nogc @safe @property pure nothrow ubyte alpha(ubyte value) { return colors[3] = value; } 208 ///Sets the red channel of the color 209 public @nogc @safe @property pure nothrow ubyte red(ubyte value) { return colors[2] = value; } 210 ///Sets the green channel of the color 211 public @nogc @safe @property pure nothrow ubyte green(ubyte value) { return colors[1] = value; } 212 ///Sets the blue channel of the color 213 public @nogc @safe @property pure nothrow ubyte blue(ubyte value) { return colors[0] = value; } 214 } 215 /** 216 * Contructs a color from four individual values. 217 */ 218 public @nogc this(ubyte alpha, ubyte red, ubyte green, ubyte blue) nothrow pure @safe { 219 this.alpha = alpha; 220 this.red = red; 221 this.green = green; 222 this.blue = blue; 223 } 224 /** 225 * Constructs a color from a single 32 bit unsigned integer. 226 */ 227 public @nogc this(uint val) nothrow pure @safe { 228 raw = val; 229 } 230 /** 231 * Operator overloading for quick math. '*' is alpha-blending, '^' is XOR blitter, '&' is normal "blitter". 232 * Alpha is used from right hand side and kept on left hand side when needed 233 */ 234 public Color opBinary(string op)(Color rhs){ 235 static if(op == "+"){ 236 int r = red + rhs.red, g = green + rhs.green, b = blue + rhs.blue, a = alpha + rhs.alpha; 237 return Color(a > 255 ? 255 : cast(ubyte)a, r > 255 ? 255 : cast(ubyte)r, g > 255 ? 255 : cast(ubyte)g, b > 255 ? 255 : cast(ubyte)b); 238 }else static if(op == "-"){ 239 int r = red - rhs.red, g = green - rhs.green, b = blue - rhs.blue, a = alpha - rhs.alpha; 240 return Color(a < 0 ? 0 : cast(ubyte)a, r < 0 ? 0 : cast(ubyte)r, g < 0 ? 0 : cast(ubyte)g, b < 0 ? 0 : cast(ubyte)b); 241 }else static if(op == "^"){ 242 return Color(alpha ^ rhs.alpha, red ^ rhs.red, green ^ rhs.green, blue ^ rhs.blue); 243 }else static if(op == "&"){ 244 return rhs.alpha ? rhs : this; 245 }else static if(op == "*"){ 246 return Color(alpha, cast(ubyte)( ( (rhs.red * (1 + rhs.alpha)) + (red * (256 - rhs.alpha)) )>>8 ), 247 cast(ubyte)( ( (rhs.green * (1 + rhs.alpha)) + (green * (256 - rhs.alpha)) )>>8 ), 248 cast(ubyte)( ( (rhs.blue * (1 + rhs.alpha)) + (blue * (256 - rhs.alpha)) )>>8 )); 249 }else static assert(0, "Operator '" ~ op ~ "' not supported!"); 250 } 251 /** 252 * Returns a string for debugging. 253 */ 254 public string toString() const{ 255 import PixelPerfectEngine.system.etc; 256 return "0x" ~ intToHex(raw, 8); 257 } 258 }+/ 259 //alias Pixel32Bit Color;