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