[img]https://dl.dropboxusercontent.com/u/104427432/Scripts/csg/subtract.jpg[/img]
[b]Description:[/b]
[URL="http://en.wikipedia.org/wiki/Constructive_solid_geometry"]Constructive Solid Geometry[/URL], or CSG, is a form of rendering which uses three operators to create complex shapes from simple primitives.
Using stencils, I've made a wrapper module which allows for one-dimensional CSG's to be created with a few easy steps.
Should work on both 3D and 2D drawing, though 3D is untested.
In true CSG models, "trees" can be built using multiple CSG operations. This module, unfortunately, can't do that because stencils use global variables which screw everything up.
The library is written so that if I figure out how to make that work, your code should remain unmodified.
[B]Download:[/B]
[url]https://www.dropbox.com/sh/wbzhawgi0suve7i/AADUcTMekb-jF21XUJKtsq_Da?dl=1[/url]
Merge into your root lua folder.
[B]How to use:[/B]
1. Define two draw functions.
2. Call csg.Start()
3. Call csg.Add, csg.Subtract, or csg.Union using the draw functions as arguments.
4. If using Add or Union, use a third draw function to paint over the newly created shape.
5. Call the returned function given by your CSG operation.
6. Call csg.End()
[B]Examples (Included in the files as comments):[/B]
[lua]
local Box = function() --Red
surface.SetDrawColor(255,0,0,100)
surface.DrawRect(100,100,200,200)
end
local Triangle = function() --Green
local PolyData = {{x=200,y=150},{x=150,y=200},{x=250,y=200}}
surface.SetDrawColor(0,255,0,100)
surface.DrawPoly(PolyData)
end
local Circle = function(ox,oy) --Blue
local PolyData = {}
local originx = ox or 300
local originy = oy or 300
local radius = 50
for deg=0, 359 do
local x,y = math.cos(math.rad(deg)*math.pi)*radius+originx, math.sin(math.rad(deg)*math.pi)*radius+originy
PolyData[deg] = {x=x,y=y}
end
surface.SetDrawColor(0,0,255,100)
surface.DrawPoly(PolyData)
end
local ScreenQuad = function()--Yellow, with transparency.
surface.SetDrawColor(255,255,0,255/2)
surface.DrawRect(0,0,ScrW(),ScrH())
end
local ScreenQuadBold = function()--Black, without transparency.
surface.SetDrawColor(0,0,0,255)
surface.DrawRect(0,0,ScrW(),ScrH())
end
hook.Add("HUDPaint","CSG 2D Test", function()
//Uncomment to test:
-- Box()
-- Triangle()
-- Circle()
csg.StartTree()
//Uncomment to test:
-- csg.Add(Box,Circle,ScreenQuad)() --Paint over each item with solid transparent white.
-- csg.Subtract(Box,Triangle)() --Cut the triangle out of the box.
-- csg.Union(Box,Circle,ScreenQuad)() --Only paint the parts covered by both the circle and the box with transparent white.
//Can't csg a csg yet. If you figure out how to do this, message bobbleheadbob on facepunch.
//This is because the stencil buffer uses global variables which are modified every time a csg is processed.
-- local add = csg.Add(Box,Circle,ScreenQuad)
-- csg.Subtract(add,Triangle)() --Trees of cgi within cgi can be made like so. (same effect in this case as subtracting circle from box.)
local sub = csg.Subtract(Box,Triangle)
csg.Subtract(sub,Circle)()
csg.EndTree()
end)
concommand.Add("testcsg",function()
local testframe = vgui.Create("DFrame")
testframe:SetSize(ScrW()/2,ScrH()/2)
testframe:Center()
testframe:MakePopup()
testframe:SetTitle("Test CSG Subtract")
local oldpaint = testframe.Paint
function testframe:Paint(w,h)
local x,y = self:GetPos()
csg.Start()
-- local p = csg.Subtract( function() oldpaint(self,w,h) end, function() Circle(800-x,600-y) end)
local p = csg.Subtract( function() oldpaint(self,w,h) end, function() draw.RoundedBox(8,400-x,400-y,100,100,Color(255,255,255)) end)
p()
csg.End()
end
end)
[/lua]
[t]https://dl.dropboxusercontent.com/u/104427432/Scripts/csg/add.jpg[/t]
(subtract output is at top of post)
[t]https://dl.dropboxusercontent.com/u/104427432/Scripts/csg/union.jpg[/t]
[lua]local a = render.SetStencilCompareFunction
function render.SetStencilCompareFunction(arg)
a(arg)
function render.GetStencilCompareFunction()
return arg
end
end
local b = render.SetStencilEnable
function render.SetStencilEnable(arg)
b(arg)
function render.GetStencilEnable()
return arg
end
end
local c = render.SetStencilFailOperation
function render.SetStencilFailOperation(arg)
c(arg)
function render.GetStencilFailOperation()
return arg
end
end
local d = render.SetStencilPassOperation
function render.SetStencilPassOperation(arg)
d(arg)
function render.GetStencilPassOperation()
return arg
end
end
local e = render.SetStencilReferenceValue
function render.SetStencilReferenceValue(arg)
e(arg)
function render.GetStencilReferenceValue()
return arg
end
end
local f = render.SetStencilTestMask
function render.SetStencilTestMask(arg)
f(arg)
function render.GetStencilTestMask()
return arg
end
end
local g = render.SetStencilWriteMask
function render.SetStencilWriteMask(arg)
g(arg)
function render.GetStencilWriteMask()
return arg
end
end
local h = render.SetStencilZFailOperation
function render.SetStencilZFailOperation(arg)
h(arg)
function render.GetStencilZFailOperation()
return arg
end
end[/lua]
for functions that are called multiple times per frame, this is a very inefficient way to go about about adding accessors
Very interesting.
From your OP:
[lua]//Can't csg a csg yet. If you figure out how to do this, message bobbleheadbob on facepunch.
//This is because the stencil buffer uses global variables which are modified every time a csg is processed.
--local add = csg.Add(Box,Circle,ScreenQuadBold)
-- csg.Subtract(add,Triangle)() --Trees of cgi within cgi can be made like so. (same effect in this case as subtracting circle from box.)[/lua]
CSG a CSG. Isn't that what those last two lines are doing? Are you saying that those examples won't work, or?
[QUOTE=bitches;46877503]Very interesting.
From your OP:
[lua]//Can't csg a csg yet. If you figure out how to do this, message bobbleheadbob on facepunch.
//This is because the stencil buffer uses global variables which are modified every time a csg is processed.
--local add = csg.Add(Box,Circle,ScreenQuadBold)
-- csg.Subtract(add,Triangle)() --Trees of cgi within cgi can be made like so. (same effect in this case as subtracting circle from box.)[/lua]
CSG a CSG. Isn't that what those last two lines are doing? Are you saying that those examples won't work, or?[/QUOTE]
That's how they WILL work if I can figure out how to stack stencils. As of now those examples don't work.
And I know those accessors are hideous. Gonna comment all that stuff because it didn't work the way I hoped.
Sorry, you need to Log In to post a reply to this thread.