@@ -59,6 +59,10 @@ public void Render(ReadOnlySpan<RenderCommand> commands)
5959 case RenderCommandType . Custom :
6060 RenderCustom ( box , cmd . Custom ) ;
6161 break ;
62+
63+ case RenderCommandType . Shadow :
64+ RenderShadow ( box , cmd . Shadow ) ;
65+ break ;
6266 }
6367 }
6468 }
@@ -145,72 +149,58 @@ private void RenderBorder(BoundingBox box, BorderRenderData data)
145149 {
146150 var color = ToRayColor ( data . Color ) ;
147151
148- // Use rounded border if corner radius is set
149152 if ( data . CornerRadius . TopLeft > 0 )
150153 {
151- var rect = new Rectangle ( box . X , box . Y , box . Width , box . Height ) ;
152- float minDimension = Math . Min ( box . Width , box . Height ) ;
153- float roundness = ( data . CornerRadius . TopLeft * 2 ) / minDimension ;
154- roundness = Math . Clamp ( roundness , 0 , 1 ) ;
155-
156- // Use the maximum border width for the line thickness
157- float lineThickness = Math . Max (
154+ float r = data . CornerRadius . TopLeft ;
155+ float bw = Math . Max (
158156 Math . Max ( data . Width . Top , data . Width . Bottom ) ,
159- Math . Max ( data . Width . Left , data . Width . Right )
160- ) ;
161-
162- Raylib . DrawRectangleRoundedLines ( rect , roundness , 8 , lineThickness , color ) ;
157+ Math . Max ( data . Width . Left , data . Width . Right ) ) ;
158+
159+ // Clamp radius to half the smallest dimension
160+ r = Math . Min ( r , Math . Min ( box . Width , box . Height ) / 2f ) ;
161+
162+ // Draw four straight border segments (between the corner arcs)
163+ // Top
164+ Raylib . DrawRectangleRec ( new Rectangle ( box . X + r , box . Y , box . Width - 2 * r , bw ) , color ) ;
165+ // Bottom
166+ Raylib . DrawRectangleRec ( new Rectangle ( box . X + r , box . Y + box . Height - bw , box . Width - 2 * r , bw ) , color ) ;
167+ // Left
168+ Raylib . DrawRectangleRec ( new Rectangle ( box . X , box . Y + r , bw , box . Height - 2 * r ) , color ) ;
169+ // Right
170+ Raylib . DrawRectangleRec ( new Rectangle ( box . X + box . Width - bw , box . Y + r , bw , box . Height - 2 * r ) , color ) ;
171+
172+ // Draw four corner arcs using DrawRing (annulus sector)
173+ float outerR = r ;
174+ float innerR = Math . Max ( 0 , r - bw ) ;
175+ int segments = 8 ;
176+
177+ // Top-left corner
178+ Raylib . DrawRing (
179+ new System . Numerics . Vector2 ( box . X + r , box . Y + r ) ,
180+ innerR , outerR , 180 , 270 , segments , color ) ;
181+ // Top-right corner
182+ Raylib . DrawRing (
183+ new System . Numerics . Vector2 ( box . X + box . Width - r , box . Y + r ) ,
184+ innerR , outerR , 270 , 360 , segments , color ) ;
185+ // Bottom-right corner
186+ Raylib . DrawRing (
187+ new System . Numerics . Vector2 ( box . X + box . Width - r , box . Y + box . Height - r ) ,
188+ innerR , outerR , 0 , 90 , segments , color ) ;
189+ // Bottom-left corner
190+ Raylib . DrawRing (
191+ new System . Numerics . Vector2 ( box . X + r , box . Y + box . Height - r ) ,
192+ innerR , outerR , 90 , 180 , segments , color ) ;
163193 }
164194 else
165195 {
166- // Fall back to straight borders
167- // Top border
168196 if ( data . Width . Top > 0 )
169- {
170- Raylib . DrawRectangle (
171- ( int ) box . X ,
172- ( int ) box . Y ,
173- ( int ) box . Width ,
174- ( int ) data . Width . Top ,
175- color
176- ) ;
177- }
178-
179- // Bottom border
197+ Raylib . DrawRectangle ( ( int ) box . X , ( int ) box . Y , ( int ) box . Width , ( int ) data . Width . Top , color ) ;
180198 if ( data . Width . Bottom > 0 )
181- {
182- Raylib . DrawRectangle (
183- ( int ) box . X ,
184- ( int ) ( box . Y + box . Height - data . Width . Bottom ) ,
185- ( int ) box . Width ,
186- ( int ) data . Width . Bottom ,
187- color
188- ) ;
189- }
190-
191- // Left border
199+ Raylib . DrawRectangle ( ( int ) box . X , ( int ) ( box . Y + box . Height - data . Width . Bottom ) , ( int ) box . Width , ( int ) data . Width . Bottom , color ) ;
192200 if ( data . Width . Left > 0 )
193- {
194- Raylib . DrawRectangle (
195- ( int ) box . X ,
196- ( int ) box . Y ,
197- ( int ) data . Width . Left ,
198- ( int ) box . Height ,
199- color
200- ) ;
201- }
202-
203- // Right border
201+ Raylib . DrawRectangle ( ( int ) box . X , ( int ) box . Y , ( int ) data . Width . Left , ( int ) box . Height , color ) ;
204202 if ( data . Width . Right > 0 )
205- {
206- Raylib . DrawRectangle (
207- ( int ) ( box . X + box . Width - data . Width . Right ) ,
208- ( int ) box . Y ,
209- ( int ) data . Width . Right ,
210- ( int ) box . Height ,
211- color
212- ) ;
213- }
203+ Raylib . DrawRectangle ( ( int ) ( box . X + box . Width - data . Width . Right ) , ( int ) box . Y , ( int ) data . Width . Right , ( int ) box . Height , color ) ;
214204 }
215205 }
216206
@@ -525,6 +515,68 @@ private void RenderTextInput(BoundingBox box, TextInputWidget widget)
525515 PopScissor ( ) ;
526516 }
527517
518+ private void RenderShadow ( BoundingBox box , ShadowRenderData data )
519+ {
520+ // The bounding box arrives pre-expanded (offset + blur + spread already applied).
521+ // We draw concentric rounded rectangles from outermost (full box) to innermost,
522+ // each layer covering a ring of the blur. Alpha per layer = base_alpha / layers,
523+ // so they accumulate to full opacity at the center where all layers overlap.
524+ float blur = data . BlurRadius ;
525+
526+ if ( blur <= 0 )
527+ {
528+ // Sharp shadow — single rectangle
529+ var rect = new Rectangle ( box . X , box . Y , box . Width , box . Height ) ;
530+ var color = ToRayColor ( data . Color ) ;
531+
532+ if ( data . CornerRadius . TopLeft > 0 )
533+ {
534+ float minDim = Math . Min ( box . Width , box . Height ) ;
535+ float roundness = Math . Clamp ( ( data . CornerRadius . TopLeft * 2 ) / minDim , 0 , 1 ) ;
536+ Raylib . DrawRectangleRounded ( rect , roundness , 8 , color ) ;
537+ }
538+ else
539+ {
540+ Raylib . DrawRectangleRec ( rect , color ) ;
541+ }
542+ return ;
543+ }
544+
545+ // +1 so the last layer sits exactly at inset=blur (the original element edge)
546+ int layers = Math . Clamp ( ( int ) blur , 4 , 24 ) + 1 ;
547+ float perLayerAlpha = data . Color . A / layers ;
548+ byte r = ( byte ) Math . Clamp ( data . Color . R , 0 , 255 ) ;
549+ byte g = ( byte ) Math . Clamp ( data . Color . G , 0 , 255 ) ;
550+ byte b = ( byte ) Math . Clamp ( data . Color . B , 0 , 255 ) ;
551+ byte alpha = ( byte ) Math . Clamp ( perLayerAlpha , 1 , 255 ) ;
552+
553+ for ( int i = 0 ; i < layers ; i ++ )
554+ {
555+ float inset = blur * ( ( float ) i / ( layers - 1 ) ) ;
556+ var rect = new Rectangle (
557+ box . X + inset ,
558+ box . Y + inset ,
559+ box . Width - inset * 2 ,
560+ box . Height - inset * 2
561+ ) ;
562+
563+ if ( rect . width <= 0 || rect . height <= 0 ) continue ;
564+
565+ var layerColor = new RayColor { r = r , g = g , b = b , a = alpha } ;
566+
567+ if ( data . CornerRadius . TopLeft > 0 )
568+ {
569+ float minDim = Math . Min ( rect . width , rect . height ) ;
570+ float roundness = Math . Clamp ( ( data . CornerRadius . TopLeft * 2 ) / minDim , 0 , 1 ) ;
571+ Raylib . DrawRectangleRounded ( rect , roundness , 8 , layerColor ) ;
572+ }
573+ else
574+ {
575+ Raylib . DrawRectangleRec ( rect , layerColor ) ;
576+ }
577+ }
578+ }
579+
528580 private static RayColor ToRayColor ( ClayColor color )
529581 {
530582 return new RayColor
0 commit comments