1 /* 2 Inochi2D Common Data 3 4 Copyright © 2020, Inochi2D Project 5 Distributed under the 2-Clause BSD License, see LICENSE file. 6 7 Authors: Luna Nielsen 8 */ 9 module inochi2d.core.nodes.common; 10 import bindbc.opengl; 11 import inochi2d.fmt.serialize; 12 import bindbc.opengl.context; 13 import std.string; 14 15 private { 16 bool inAdvancedBlending; 17 bool inAdvancedBlendingCoherent; 18 bool inAdvancedBlendingNV; 19 extern(C) void function() glBlendBarrierKHR; 20 } 21 22 void inInitBlending() { 23 GLint extensionCount; 24 glGetIntegerv(GL_NUM_EXTENSIONS, &extensionCount); 25 foreach(i; 0..extensionCount) { 26 string ext = cast(string)glGetStringi(GL_EXTENSIONS, i).fromStringz; 27 28 // KHR blending extension 29 if (ext == "GL_KHR_blend_equation_advanced") inAdvancedBlending = true; 30 if (ext == "GL_KHR_blend_equation_advanced_coherent") inAdvancedBlendingCoherent = true; 31 32 // NVIDIA blending extension 33 if (ext == "GL_NV_blend_equation_advanced") { 34 inAdvancedBlending = true; 35 inAdvancedBlendingNV = true; 36 } 37 if (ext == "GL_NV_blend_equation_advanced_coherent") inAdvancedBlendingCoherent = true; 38 39 if (inAdvancedBlending && inAdvancedBlendingCoherent) break; 40 } 41 42 if (inAdvancedBlendingCoherent) glEnable(0x9285); // BLEND_ADVANCED_COHERENT_KHR && BLEND_ADVANCED_COHERENT_NV 43 else { 44 inAdvancedBlendingCoherent = false; 45 46 debug { 47 import std.stdio : writeln; 48 if (inAdvancedBlending) writeln("Advanced blending is supported, but non-coherent blending is not available."); 49 } 50 inAdvancedBlending = false; 51 } 52 53 } 54 55 /* 56 INFORMATION ABOUT BLENDING MODES 57 Blending is a complicated topic, especially once we get to mobile devices and games consoles. 58 59 The following blending modes are supported in Standard mode: 60 Normal 61 Multiply 62 Screen 63 Overlay 64 Darken 65 Lighten 66 Color Dodge 67 Linear Dodge 68 Color Burn 69 Hard Light 70 Soft Light 71 Difference 72 Exclusion 73 Subtract 74 Inverse 75 Destination In 76 Clip To Lower 77 Slice from Lower 78 Some of these blending modes behave better on Tiling GPUs. 79 80 The following blending modes are supported in Core mode: 81 Normal 82 Multiply 83 Screen 84 Lighten 85 Color Dodge 86 Linear Dodge 87 Inverse 88 Destination In 89 Clip to Lower 90 Slice from Lower 91 Tiling GPUs on older mobile devices don't have great drivers, we shouldn't tempt fate. 92 */ 93 94 /** 95 Blending modes 96 */ 97 enum BlendMode { 98 // Normal blending mode 99 Normal, 100 101 // Multiply blending mode 102 Multiply, 103 104 // Screen 105 Screen, 106 107 // Overlay 108 Overlay, 109 110 // Darken 111 Darken, 112 113 // Lighten 114 Lighten, 115 116 // Color Dodge 117 ColorDodge, 118 119 // Linear Dodge 120 LinearDodge, 121 122 // Color Burn 123 ColorBurn, 124 125 // Hard Light 126 HardLight, 127 128 // Soft Light 129 SoftLight, 130 131 // Difference 132 Difference, 133 134 // Exclusion 135 Exclusion, 136 137 // Subtract 138 Subtract, 139 140 // Inverse 141 Inverse, 142 143 // Destination In 144 DestinationIn, 145 146 // Clip to Lower 147 // Special blending mode that clips the drawable 148 // to a lower rendered area. 149 ClipToLower, 150 151 // Slice from Lower 152 // Special blending mode that slices the drawable 153 // via a lower rendered area. 154 // Basically inverse ClipToLower 155 SliceFromLower 156 } 157 158 // KHR blending 159 enum GL_MULTIPLY_KHR = 0x9294; 160 enum GL_SCREEN_KHR = 0x9295; 161 enum GL_OVERLAY_KHR = 0x9296; 162 enum GL_DARKEN_KHR = 0x9297; 163 enum GL_LIGHTEN_KHR = 0x9298; 164 enum GL_COLORDODGE_KHR = 0x9299; 165 enum GL_COLORBURN_KHR = 0x929A; 166 enum GL_HARDLIGHT_KHR = 0x929B; 167 enum GL_SOFTLIGHT_KHR = 0x929C; 168 enum GL_DIFFERENCE_KHR = 0x929E; 169 enum GL_EXCLUSION_KHR = 0x92A0; 170 171 // NVIDIA blending 172 enum GL_SRC_NV = 0x9286; 173 enum GL_DST_NV = 0x9287; 174 enum GL_SRC_OVER_NV = 0x9288; 175 enum GL_DST_OVER_NV = 0x9289; 176 enum GL_SRC_IN_NV = 0x928A; 177 enum GL_DST_IN_NV = 0x928B; 178 enum GL_SRC_OUT_NV = 0x928C; 179 enum GL_DST_OUT_NV = 0x928D; 180 enum GL_SRC_ATOP_NV = 0x928E; 181 enum GL_DST_ATOP_NV = 0x928F; 182 enum GL_XOR_NV = 0x1506; 183 enum GL_MULTIPLY_NV = 0x9294; 184 enum GL_SCREEN_NV = 0x9295; 185 enum GL_OVERLAY_NV = 0x9296; 186 enum GL_DARKEN_NV = 0x9297; 187 enum GL_LIGHTEN_NV = 0x9298; 188 enum GL_COLORDODGE_NV = 0x9299; 189 enum GL_COLORBURN_NV = 0x929A; 190 enum GL_HARDLIGHT_NV = 0x929B; 191 enum GL_SOFTLIGHT_NV = 0x929C; 192 enum GL_DIFFERENCE_NV = 0x929E; 193 enum GL_EXCLUSION_NV = 0x92A0; 194 enum GL_INVERT_RGB_NV = 0x92A3; 195 enum GL_LINEARDODGE_NV = 0x92A4; 196 enum GL_LINEARBURN_NV = 0x92A5; 197 enum GL_VIVIDLIGHT_NV = 0x92A6; 198 enum GL_LINEARLIGHT_NV = 0x92A7; 199 enum GL_PINLIGHT_NV = 0x92A8; 200 enum GL_MINUS_NV = 0x929F; 201 enum MINUS_CLAMPED_NV = 0x92B3; 202 203 void inSetBlendMode(BlendMode blendingMode) { 204 if (!inAdvancedBlending) { 205 switch(blendingMode) { 206 207 // If the advanced blending extension is not supported, force to Normal blending 208 default: 209 glBlendEquation(GL_FUNC_ADD); 210 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); break; 211 212 case BlendMode.Normal: 213 glBlendEquation(GL_FUNC_ADD); 214 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); break; 215 216 case BlendMode.Multiply: 217 glBlendEquation(GL_FUNC_ADD); 218 glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); break; 219 220 case BlendMode.Screen: 221 glBlendEquation(GL_FUNC_ADD); 222 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); break; 223 224 case BlendMode.Lighten: 225 glBlendEquation(GL_MAX); 226 glBlendFunc(GL_ONE, GL_ONE); break; 227 228 case BlendMode.ColorDodge: 229 glBlendEquation(GL_FUNC_ADD); 230 glBlendFunc(GL_DST_COLOR, GL_ONE); break; 231 232 case BlendMode.LinearDodge: 233 glBlendEquation(GL_FUNC_ADD); 234 glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE); break; 235 236 case BlendMode.Subtract: 237 glBlendEquationSeparate(GL_FUNC_REVERSE_SUBTRACT, GL_FUNC_ADD); 238 glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE); break; 239 240 case BlendMode.Exclusion: 241 glBlendEquation(GL_FUNC_ADD); 242 glBlendFuncSeparate(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_ONE, GL_ONE); break; 243 244 case BlendMode.Inverse: 245 glBlendEquation(GL_FUNC_ADD); 246 glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); break; 247 248 case BlendMode.DestinationIn: 249 glBlendEquation(GL_FUNC_ADD); 250 glBlendFunc(GL_ZERO, GL_SRC_ALPHA); break; 251 252 case BlendMode.ClipToLower: 253 glBlendEquation(GL_FUNC_ADD); 254 glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; 255 256 case BlendMode.SliceFromLower: 257 glBlendEquation(GL_FUNC_ADD); 258 glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); break; 259 } 260 } else { 261 switch(blendingMode) { 262 case BlendMode.Normal: 263 glBlendEquation(GL_FUNC_ADD); 264 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); break; 265 266 case BlendMode.Multiply: glBlendEquation(GL_MULTIPLY_KHR); break; 267 case BlendMode.Screen: glBlendEquation(GL_SCREEN_KHR); break; 268 case BlendMode.Overlay: glBlendEquation(GL_OVERLAY_KHR); break; 269 case BlendMode.Darken: glBlendEquation(GL_DARKEN_KHR); break; 270 case BlendMode.Lighten: glBlendEquation(GL_LIGHTEN_KHR); break; 271 case BlendMode.ColorDodge: glBlendEquation(GL_COLORDODGE_KHR); break; 272 case BlendMode.LinearDodge: 273 if (inAdvancedBlendingNV) { 274 glBlendEquation(GL_LINEARDODGE_NV); 275 glBlendFunc(GL_ONE, GL_ONE); break; 276 } else { 277 glBlendEquation(GL_FUNC_ADD); 278 glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE); break; 279 } 280 281 case BlendMode.ColorBurn: glBlendEquation(GL_COLORBURN_KHR); break; 282 case BlendMode.HardLight: glBlendEquation(GL_HARDLIGHT_KHR); break; 283 case BlendMode.SoftLight: glBlendEquation(GL_SOFTLIGHT_KHR); break; 284 case BlendMode.Difference: glBlendEquation(GL_DIFFERENCE_KHR); break; 285 case BlendMode.Exclusion: glBlendEquation(GL_EXCLUSION_KHR); break; 286 287 case BlendMode.Subtract: 288 if (inAdvancedBlendingNV) { 289 glBlendEquation(MINUS_CLAMPED_NV); 290 glBlendFunc(GL_ONE, GL_ONE); break; 291 } else { 292 glBlendEquationSeparate(GL_FUNC_REVERSE_SUBTRACT, GL_FUNC_ADD); 293 glBlendFunc(GL_ONE, GL_ONE); break; 294 } 295 296 case BlendMode.Inverse: 297 if (inAdvancedBlendingNV) { 298 glBlendEquation(GL_INVERT); 299 glBlendFunc(GL_ONE, GL_ONE); break; 300 } else { 301 glBlendEquation(GL_FUNC_ADD); 302 glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); break; 303 } 304 305 case BlendMode.DestinationIn: 306 glBlendEquation(GL_FUNC_ADD); 307 glBlendFunc(GL_ZERO, GL_SRC_ALPHA); break; 308 309 case BlendMode.ClipToLower: 310 glBlendEquation(GL_FUNC_ADD); 311 glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; 312 313 case BlendMode.SliceFromLower: 314 glBlendEquation(GL_FUNC_ADD); 315 glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); break; 316 317 default: assert(0); 318 } 319 } 320 } 321 322 void inBlendModeBarrier() { 323 324 // TODO: bindbc-opengl needs to support KHR_blend_equation_advanced 325 // Before we can have non-coherent blending 326 // if (inAdvancedBlending && !inAdvancedBlendingCoherent) glBlendBarrierKHR(); 327 } 328 329 /** 330 Masking mode 331 */ 332 enum MaskingMode { 333 334 /** 335 The part should be masked by the drawables specified 336 */ 337 Mask, 338 339 /** 340 The path should be dodge masked by the drawables specified 341 */ 342 DodgeMask 343 } 344 345 /** 346 A binding between a mask and a mode 347 */ 348 struct MaskBinding { 349 public: 350 import inochi2d.core.nodes.drawable : Drawable; 351 @Name("source") 352 uint maskSrcUUID; 353 354 @Name("mode") 355 MaskingMode mode; 356 357 @Ignore 358 Drawable maskSrc; 359 }