1 // Written in the D programming language. 2 /++ 3 + Authors: KanzakiKino 4 + Copyright: KanzakiKino 2018 5 + License: LGPL-3.0 6 ++/ 7 module w4d.util.clipping; 8 import g4d; 9 import std.algorithm; 10 11 /// A utility object that clips the draw area. 12 class ClipRect 13 { 14 protected struct Rect 15 { 16 vec2 pos; // center of the rect. 17 vec2 size; 18 } 19 20 protected Rect[] _rcStack; 21 protected RectElement _elm; 22 protected Fill3DShader _shader; 23 24 /// 25 this ( Fill3DShader s ) 26 { 27 _rcStack = []; 28 _elm = new RectElement; 29 _shader = s; 30 } 31 32 /// Checks if clipping is enabled. 33 const @property isClipping () 34 { 35 return !!_rcStack.length; 36 } 37 protected const @property currentRect () 38 { 39 if ( isClipping ) { 40 return _rcStack[$-1]; 41 } 42 return Rect( vec2(0,0), vec2(int.max,int.max) ); 43 } 44 45 /// Adds clipping rect. 46 void pushRect ( vec2 pos, vec2 size ) 47 { 48 auto left = pos.x; 49 auto top = pos.y; 50 auto right = pos.x + size.x; 51 auto bottom = pos.y + size.y; 52 53 auto cur = currentRect; 54 auto curpos = cur.pos - cur.size/2; 55 56 left = max( left , curpos.x ); 57 top = max( top , curpos.y ); 58 right = min( right , curpos.x+cur.size.x ); 59 bottom = min( bottom, curpos.y+cur.size.y ); 60 61 auto rpos = vec2(left,top); 62 auto rsize = vec2(right,bottom) - pos; 63 64 rpos += rsize/2; // pos is center of rect 65 _rcStack ~= Rect( rpos, rsize ); 66 apply(); 67 } 68 69 /// Removes the clipping rect added last. 70 void popRect () 71 { 72 if ( isClipping ) { 73 _rcStack = _rcStack[0..$-1]; 74 } 75 apply(); 76 } 77 78 /// Redraws the stencil buffer. 79 void apply () 80 { 81 if ( !isClipping ) { 82 StencilBuffer.disable(); 83 return; 84 } 85 86 StencilBuffer.enable(); 87 StencilBuffer.clear( 0 ); 88 89 DepthBuffer.mask( false ); 90 ColorBuffer.mask( false, false, false, false ); 91 92 StencilBuffer.startModify( 1 ); 93 94 const rc = currentRect; 95 _elm.resize( rc.size ); 96 97 _shader.use(); 98 _shader.matrix.late = vec3( rc.pos, 0 ); 99 _elm.draw( _shader ); 100 101 StencilBuffer.startTest( 1 ); 102 DepthBuffer.mask( true ); 103 ColorBuffer.mask( true, true, true, true ); 104 } 105 }