The algorithm is rather simple: the only occluders are 2D lines. A triangle is comprised of 3 lines. Every line results in a quad that is the shadow. You create this quad by taking the vector from the light source to the edge of the line (edges are P1 and P2), and projecting a point much further (beyond the viewport), call it P3. Do the same for the other edge, P4. Now 'connect the dots' and you have your quad.
The soft shadows are generated by using 8 lights in a circle, around the 'real' light. For every light, for every quad, I fill the light-framebuffer with a (greyscale) color (no blending) then I add all light-framebuffers together (no blending), then I multiply (no blending) the result with the background/scene.
The above screenshot is a software renderer, with a lot
of overdraw, yet still rendering >100fps. Naturally you don't need to calculate the shadows every frame, making the overhead negligible.