1 /** 2 Inochi2D Solo Node 3 4 Copyright: 5 Copyright © 2020-2026, Inochi2D Project 6 7 License: 8 $(LINK2 https://github.com/Inochi2D/inochi2d/blob/main/LICENSE, BSD 2-clause License) 9 10 Authors: 11 Luna Nielsen 12 */ 13 module inochi2d.nodes.visual.solo; 14 import inochi2d.nodes.visual; 15 import inochi2d.nodes; 16 import inochi2d.core.math; 17 import inochi2d.core; 18 import nulib; 19 import numem; 20 21 /** 22 A node which only allows a single child node to be displayed 23 at a time. 24 */ 25 @TypeId("Solo", IN_MAKE_TAG!(4, 1)) 26 class Solo : Visual { 27 private: 28 @nogc: 29 uint lastActiveLayer_; 30 uint activeLayer_; 31 32 void changeLayer(uint value) @nogc nothrow { 33 this.lastActiveLayer_ = clamp(activeLayer_, 0, cast(uint)children.length); 34 this.activeLayer_ = clamp(cast(uint)value, 0, cast(uint)children.length); 35 } 36 37 protected: 38 39 /** 40 Called during the early update phase of a new frame. 41 42 Params: 43 drawList = The drawlist for the active scene. 44 */ 45 override 46 void onPreUpdate(DrawList drawList) { 47 48 // NOTE: If we changed the active layer, force the puppet to rescan its visuals 49 // hirearchy. 50 // We do this since we want the Solo's hirearchy to blend 51 // with the outer hirearchy sorting wise. 52 if (lastActiveLayer_ != activeLayer_) 53 puppet.rescanNodes(); 54 } 55 56 /** 57 Requests that the list gather sub-visuals to be rendered, if applicable. 58 59 Params: 60 visuals = The list to write to, the list may be resized by the 61 implementation. 62 recurseDelegates = Whether to recurse through delegate visuals. 63 append = Whether to append to the visuals list. 64 */ 65 override 66 void onDelegateFindVisuals(ref weak_vector!Visual visuals, bool recurseDelegates, bool append) { 67 if (children.length > 0) { 68 69 70 71 .findVisuals(children[activeLayer_], visuals, recurseDelegates, false, append); 72 } 73 } 74 75 /** 76 Called when the node is to define its properties. 77 78 Call $(D propList.define) with a quark to do this. 79 80 Params: 81 propList = The property list to populate. 82 */ 83 override 84 void onDefineProperties(ref PropertyStore propList) { 85 super.onDefineProperties(propList); 86 propList.define(PROP_ACTIVE_LAYER, 0); 87 } 88 89 public: 90 91 /** 92 Whether the renderer should delegate rendering logic 93 to the visual node. 94 */ 95 override @property bool isDelegated() @nogc nothrow pure => true; 96 97 /** 98 Whether the node can be used as a source of masking operations. 99 */ 100 override @property bool isMasking() @nogc nothrow pure => true; 101 102 /** 103 The active layer that will be rendered. 104 */ 105 final @property Node activeLayer() @nogc nothrow pure => children.length > 0 ? children[activeLayer_] : null; 106 107 /** 108 Constructs a new Solo node. 109 110 Params: 111 parent = The parent of the solo node. 112 */ 113 this(Node parent = null) { 114 super(inNewGUID(), parent); 115 } 116 117 /** 118 Constructs a new Solo node. 119 120 Params: 121 guid = The new GUID of the 122 parent = The parent of the solo node. 123 */ 124 this(GUID guid, Node parent = null) { 125 super(guid, parent); 126 } 127 } 128 129 mixin Register!(Solo, in_node_registry); 130 // dfmt off 131 132 133 134 135 // 136 // QUARKS 137 // 138 139 mixin RegisterQuarks!(); 140 141 /** 142 Active layer. 143 */ 144 @propkey("activeLayer") 145 __gshared immutable(quark) PROP_ACTIVE_LAYER;