1 /** 2 * Copyright: Enalye 3 * License: Zlib 4 * Authors: Enalye 5 */ 6 module grimoire.stdlib.color; 7 8 import std.conv : to; 9 import std.algorithm.comparison : clamp; 10 import grimoire.assembly, grimoire.compiler, grimoire.runtime; 11 import grimoire.stdlib.util; 12 13 package void grLoadStdLibColor(GrLibrary library) { 14 auto colorType = library.addClass("Color", ["r", "g", "b"], [ 15 grFloat, grFloat, grFloat 16 ]); 17 18 library.addPrimitive(&_makeColor, "Color", [], [colorType]); 19 library.addPrimitive(&_makeColor3, "Color", [grFloat, grFloat, grFloat], [ 20 colorType 21 ]); 22 23 library.addPrimitive(&_makeColor3i, "Color", [grInt, grInt, grInt], [ 24 colorType 25 ]); 26 27 static foreach (op; ["+", "-", "*", "/", "%"]) { 28 library.addOperator(&_opBinaryColor!op, op, [colorType, colorType], colorType); 29 library.addOperator(&_opBinaryScalarColor!op, op, [colorType, grFloat], colorType); 30 library.addOperator(&_opBinaryScalarRightColor!op, op, [ 31 grFloat, colorType 32 ], colorType); 33 } 34 35 library.addPrimitive(&_mixColor, "mix", [colorType, colorType], [colorType]); 36 library.addPrimitive(&_lerpColor, "lerp", [colorType, colorType, grFloat], [ 37 colorType 38 ]); 39 40 library.addCast(&_castArrayToColor, grIntArray, colorType); 41 library.addCast(&_castColorToString, colorType, grString); 42 43 library.addPrimitive(&_unpack, "unpack", [colorType], [ 44 grFloat, grFloat, grFloat 45 ]); 46 47 library.addPrimitive(&_print, "print", [colorType]); 48 library.addPrimitive(&_printl, "printl", [colorType]); 49 } 50 51 private void _makeColor(GrCall call) { 52 GrObject self = call.createObject("Color"); 53 if (!self) { 54 call.raise("UnknownClassError"); 55 return; 56 } 57 self.setFloat("r", 0f); 58 self.setFloat("g", 0f); 59 self.setFloat("b", 0f); 60 call.setObject(self); 61 } 62 63 private void _makeColor3(GrCall call) { 64 GrObject self = call.createObject("Color"); 65 if (!self) { 66 call.raise("UnknownClassError"); 67 return; 68 } 69 self.setFloat("r", call.getFloat(0)); 70 self.setFloat("g", call.getFloat(1)); 71 self.setFloat("b", call.getFloat(2)); 72 call.setObject(self); 73 } 74 75 private void _makeColor3i(GrCall call) { 76 GrObject self = call.createObject("Color"); 77 if (!self) { 78 call.raise("UnknownClassError"); 79 return; 80 } 81 self.setFloat("r", clamp(call.getInt(0) / 255f, 0f, 1f)); 82 self.setFloat("g", clamp(call.getInt(1) / 255f, 0f, 1f)); 83 self.setFloat("b", clamp(call.getInt(2) / 255f, 0f, 1f)); 84 call.setObject(self); 85 } 86 87 private void _opBinaryColor(string op)(GrCall call) { 88 GrObject self = call.createObject("Color"); 89 if (!self) { 90 call.raise("UnknownClassError"); 91 return; 92 } 93 GrObject c1 = call.getObject(0); 94 GrObject c2 = call.getObject(1); 95 if (!c1 || !c2) { 96 call.raise("NullError"); 97 return; 98 } 99 mixin("self.setFloat(\"r\", c1.getFloat(\"r\")" ~ op ~ "c2.getFloat(\"r\"));"); 100 mixin("self.setFloat(\"g\", c1.getFloat(\"g\")" ~ op ~ "c2.getFloat(\"g\"));"); 101 mixin("self.setFloat(\"b\", c1.getFloat(\"b\")" ~ op ~ "c2.getFloat(\"b\"));"); 102 call.setObject(self); 103 } 104 105 private void _opBinaryScalarColor(string op)(GrCall call) { 106 GrObject self = call.createObject("Color"); 107 if (!self) { 108 call.raise("UnknownClassError"); 109 return; 110 } 111 GrObject c = call.getObject(0); 112 const GrFloat s = call.getFloat(1); 113 if (!c) { 114 call.raise("NullError"); 115 return; 116 } 117 mixin("self.setFloat(\"r\", c.getFloat(\"r\")" ~ op ~ "s);"); 118 mixin("self.setFloat(\"g\", c.getFloat(\"g\")" ~ op ~ "s);"); 119 mixin("self.setFloat(\"b\", c.getFloat(\"b\")" ~ op ~ "s);"); 120 call.setObject(self); 121 } 122 123 private void _opBinaryScalarRightColor(string op)(GrCall call) { 124 GrObject self = call.createObject("Color"); 125 if (!self) { 126 call.raise("UnknownClassError"); 127 return; 128 } 129 GrObject c = call.getObject(0); 130 const GrFloat s = call.getFloat(1); 131 if (!c) { 132 call.raise("NullError"); 133 return; 134 } 135 mixin("self.setFloat(\"r\", s" ~ op ~ "c.getFloat(\"r\"));"); 136 mixin("self.setFloat(\"g\", s" ~ op ~ "c.getFloat(\"g\"));"); 137 mixin("self.setFloat(\"b\", s" ~ op ~ "c.getFloat(\"b\"));"); 138 call.setObject(self); 139 } 140 141 private void _mixColor(GrCall call) { 142 GrObject self = call.createObject("Color"); 143 if (!self) { 144 call.raise("UnknownClassError"); 145 return; 146 } 147 GrObject c1 = call.getObject(0); 148 GrObject c2 = call.getObject(1); 149 if (!c1 || !c2) { 150 call.raise("NullError"); 151 return; 152 } 153 self.setFloat("r", (c1.getFloat("r") + c2.getFloat("r")) / 2f); 154 self.setFloat("g", (c1.getFloat("g") + c2.getFloat("g")) / 2f); 155 self.setFloat("b", (c1.getFloat("b") + c2.getFloat("b")) / 2f); 156 call.setObject(self); 157 } 158 159 private void _lerpColor(GrCall call) { 160 GrObject self = call.createObject("Color"); 161 if (!self) { 162 call.raise("UnknownClassError"); 163 return; 164 } 165 GrObject c1 = call.getObject(0); 166 GrObject c2 = call.getObject(1); 167 const GrFloat t = call.getFloat(2); 168 if (!c1 || !c2) { 169 call.raise("NullError"); 170 return; 171 } 172 self.setFloat("r", (t * c2.getFloat("r")) + ((1f - t) * c1.getFloat("r"))); 173 self.setFloat("g", (t * c2.getFloat("g")) + ((1f - t) * c1.getFloat("g"))); 174 self.setFloat("b", (t * c2.getFloat("b")) + ((1f - t) * c1.getFloat("b"))); 175 call.setObject(self); 176 } 177 178 private void _castArrayToColor(GrCall call) { 179 GrIntArray array = call.getIntArray(0); 180 if (array.data.length == 3) { 181 GrObject self = call.createObject("Color"); 182 if (!self) { 183 call.raise("UnknownClassError"); 184 return; 185 } 186 self.setFloat("r", array.data[0]); 187 self.setFloat("g", array.data[1]); 188 self.setFloat("b", array.data[2]); 189 call.setObject(self); 190 return; 191 } 192 call.raise("Cannot convert array to Color, invalid size"); 193 } 194 195 private void _castColorToString(GrCall call) { 196 GrObject self = call.getObject(0); 197 if (!self) { 198 call.raise("NullError"); 199 return; 200 } 201 call.setString("Color(" ~ to!GrString(self.getFloat("r")) ~ ", " ~ to!GrString( 202 self.getFloat("g")) ~ ", " ~ to!GrString(self.getFloat("b")) ~ ")"); 203 } 204 205 private void _unpack(GrCall call) { 206 GrObject self = call.getObject(0); 207 if (!self) { 208 call.raise("NullError"); 209 return; 210 } 211 call.setFloat(self.getFloat("r")); 212 call.setFloat(self.getFloat("g")); 213 call.setFloat(self.getFloat("b")); 214 } 215 216 private void _print(GrCall call) { 217 GrObject self = call.getObject(0); 218 if (!self) { 219 call.raise("NullError"); 220 return; 221 } 222 _stdOut("Color(" ~ to!GrString(self.getFloat("r")) ~ ", " ~ to!GrString( 223 self.getFloat("g")) ~ ", " ~ to!GrString(self.getFloat("b")) ~ ")"); 224 } 225 226 private void _printl(GrCall call) { 227 GrObject self = call.getObject(0); 228 if (!self) { 229 call.raise("NullError"); 230 return; 231 } 232 _stdOut("Color(" ~ to!GrString(self.getFloat("r")) ~ ", " ~ to!GrString( 233 self.getFloat("g")) ~ ", " ~ to!GrString(self.getFloat("b")) ~ ")\n"); 234 }