Skip to content

Commit

Permalink
fix transform's uniqueness of name, add test
Browse files Browse the repository at this point in the history
  • Loading branch information
soypat committed Nov 27, 2024
1 parent 1870c49 commit bed2388
Show file tree
Hide file tree
Showing 14 changed files with 285 additions and 74 deletions.
67 changes: 67 additions & 0 deletions examples/text/text.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package main

import (
"fmt"
"log"
"runtime"

"github.com/soypat/glgl/math/ms2"
"github.com/soypat/gsdf"
"github.com/soypat/gsdf/forge/textsdf"
"github.com/soypat/gsdf/glbuild"
"github.com/soypat/gsdf/gleval"
"github.com/soypat/gsdf/gsdfaux"
)

const dim = 20
const filename = "text.png"

func init() {
runtime.LockOSThread()
}

func scene(bld *gsdf.Builder) (glbuild.Shader2D, error) {
var f textsdf.Font
f.Configure(textsdf.FontConfig{
RelativeGlyphTolerance: 0.001,
})
err := f.LoadTTFBytes(textsdf.ISO3098TTF())
if err != nil {
return nil, err
}
var poly ms2.PolygonBuilder
poly.Nagon(7, 1)
vecs, _ := poly.AppendVecs(nil)
return bld.NewPolygon(vecs), bld.Err()
return f.TextLine("Abc")
}

func main() {
useGPU := true
if useGPU {
term, err := gleval.Init1x1GLFW()
if err != nil {
log.Fatal(err)
}
defer term()
}
var bld gsdf.Builder
s, err := scene(&bld)
if err != nil {
log.Fatal(err)
}
var sdf2 gleval.SDF2
if useGPU {
sdf2, err = gsdfaux.MakeGPUSDF2(s)
} else {
sdf2, err = gleval.NewCPUSDF2(s)
}
if err != nil {
log.Fatal(err)
}
err = gsdfaux.RenderPNGFile(filename, sdf2, 300, nil)
if err != nil {
log.Fatal(err)
}
fmt.Println("PNG file rendered to", filename)
}
22 changes: 16 additions & 6 deletions examples/ui-geb/uigeb.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ func scene(bld *gsdf.Builder) (glbuild.Shader3D, error) {
G = bld.Translate2D(G, -szG.X/2, -szG.Y/2)
E = bld.Translate2D(E, -szE.X/2, -szE.Y/2)
B = bld.Translate2D(B, -szB.X/2, -szB.Y/2)
const round1 = 0.01
G = bld.Offset2D(G, -round1)
E = bld.Offset2D(E, -round1)
B = bld.Offset2D(B, -round1)

// GEB size. Scale all letters to match size.
szz := ms2.MaxElem(szG, ms2.MaxElem(szE, szB)).Max()
Expand All @@ -64,16 +68,22 @@ func scene(bld *gsdf.Builder) (glbuild.Shader3D, error) {
G3 = bld.Transform(G3, ms3.ScaleMat4(ms3.Vec{X: sclG.X, Y: sclG.Y, Z: 1}))
E3 = bld.Transform(E3, ms3.ScaleMat4(ms3.Vec{X: sclE.X, Y: sclE.Y, Z: 1}))
B3 = bld.Transform(B3, ms3.ScaleMat4(ms3.Vec{X: sclB.X, Y: sclB.Y, Z: 1}))
const round2 = 0.025
G3 = bld.Offset(G3, -round2)
E3 = bld.Offset(E3, -round2)
B3 = bld.Offset(B3, -round2)

// Orient letters.
const deg90 = math.Pi / 2
E3 = bld.Rotate(E3, deg90, ms3.Vec{Y: 1})
B3 = bld.Rotate(B3, -deg90, ms3.Vec{X: 1})
GEB1 := bld.Intersection(G3, bld.Rotate(E3, deg90, ms3.Vec{Y: 1}))
GEB1 = bld.Intersection(GEB1, bld.Rotate(B3, -deg90, ms3.Vec{X: 1}))

GEB := bld.Intersection(G3, E3)
GEB = bld.Intersection(GEB, B3)
// return bld.Union(G3, E3, B3), bld.Err() // For debugging.
return GEB, bld.Err()
GEB2 := bld.Intersection(E3, bld.Rotate(G3, deg90, ms3.Vec{Y: 1}))
GEB2 = bld.Intersection(GEB2, bld.Rotate(B3, -deg90, ms3.Vec{X: 1}))

GEB2 = bld.Translate(GEB2, 0, GEB2.Bounds().Size().Y*1.5, 0)

return bld.Union(GEB1, GEB2), bld.Err()
}

func main() {
Expand Down
61 changes: 56 additions & 5 deletions glbuild/glbuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,15 +277,15 @@ func (p *Programmer) writeShaders(w io.Writer, nodes []Shader) (n int, objs []Sh
newObjects := p.objsScratch[prevIdx:]
for i := range newObjects {
if newObjects[i].Binding != -1 {
return n, nil, fmt.Errorf("shader buffer object binding should be set to -1 until shader generated for %T, %q", node, newObjects[i].NamePtr)
return n, nil, fmt.Errorf("shader buffer object binding should be set to -1 until shader generated for %T, %q", unwraproot(node), newObjects[i].NamePtr)
}
newObjects[i].Binding = currentBase
currentBase++
obj := newObjects[i]
nameHash := hash(obj.NamePtr, 0)
_, nameConflict := p.names[nameHash]
if nameConflict {
return n, nil, fmt.Errorf("shader buffer object name conflict resolution not implemented: %T has buffer conflicting name %q of type %s", node, obj.NamePtr, obj.Element.String())
return n, nil, fmt.Errorf("shader buffer object name conflict resolution not implemented: %T has buffer conflicting name %q of type %s", unwraproot(node), obj.NamePtr, obj.Element.String())
}
p.names[nameHash] = nameHash
blockName := unsafe.String(&obj.NamePtr[0], len(obj.NamePtr)) + "Buffer"
Expand Down Expand Up @@ -316,7 +316,17 @@ func (p *Programmer) writeShaders(w io.Writer, nodes []Shader) (n int, objs []Sh
if bodyHash == gotBodyHash {
continue // Shader already written and is identical, skip.
}
return n, nil, fmt.Errorf("duplicate %T shader name %q w/ body:\n%s", node, name, body)
// Look for identical shader
var conflictBody []byte
for j := i + 1; j < len(nodes); j++ {
conflictBody = nodes[j].AppendShaderName(conflictBody[:0])
if bytes.Equal(conflictBody, name) {
conflictBody = nodes[j].AppendShaderBody(conflictBody[:0])
break
}
conflictBody = conflictBody[:0]
}
return n, nil, fmt.Errorf("duplicate %T shader name %q w/ body:\n%s\n\nconflict with distinct shader with same name:\n%s", unwraproot(node), name, body, conflictBody)
} else {
p.names[nameHash] = bodyHash // Not found, add it.
}
Expand Down Expand Up @@ -368,6 +378,9 @@ func ShortenNames2D(root *Shader2D, maxRewriteLen int) error {

func rewriteName3(s3 *Shader3D, scratch []byte, rewritelen int) []byte {
sd3 := *s3
if _, ok := sd3.(*nameOverloadShader3D); ok {
return scratch // Already overloaded.
}
name, scratch := makeShortname(sd3, scratch, rewritelen)
if name == nil {
return scratch
Expand All @@ -378,6 +391,9 @@ func rewriteName3(s3 *Shader3D, scratch []byte, rewritelen int) []byte {

func rewriteName2(s2 *Shader2D, scratch []byte, rewritelen int) []byte {
sd2 := *s2
if _, ok := sd2.(*nameOverloadShader2D); ok {
return scratch // Already overloaded.
}
name, scratch := makeShortname(sd2, scratch, rewritelen)
if name == nil {
return scratch
Expand Down Expand Up @@ -960,6 +976,7 @@ func (ob3 *overloadBounds3) Evaluate(pos []ms3.Vec, dist []float32, userData any
}
return sdf.Evaluate(pos, dist, userData)
}
func (ob3 *overloadBounds3) unwrap() Shader { return ob3.Shader3D }

// OverloadShader2DBounds overloads a [Shader2D] Bounds method with the argument bounding box.
func OverloadShader2DBounds(s Shader2D, bb ms2.Box) Shader2D {
Expand All @@ -985,6 +1002,8 @@ func (ob3 *overloadBounds2) Evaluate(pos []ms2.Vec, dist []float32, userData any
return sdf.Evaluate(pos, dist, userData)
}

func (ob2 *overloadBounds2) unwrap() Shader { return ob2.Shader2D }

var _ Shader3D = (*CachedShader3D)(nil) // Interface implementation compile-time check.

// CachedShader3D implements the Shader3D interface with results it caches for another Shader3D on a call to RefreshCache.
Expand Down Expand Up @@ -1045,6 +1064,8 @@ func (c3 *CachedShader3D) Evaluate(pos []ms3.Vec, dist []float32, userData any)
return sdf.Evaluate(pos, dist, userData)
}

func (c3 *CachedShader3D) unwrap() Shader { return c3.Shader }

var _ Shader2D = (*CachedShader2D)(nil) // Interface implementation compile-time check.

// CachedShader2D implements the Shader2D interface with results it caches for another Shader2D on a call to RefreshCache.
Expand Down Expand Up @@ -1095,6 +1116,8 @@ func (c2 *CachedShader2D) AppendShaderObjects(objs []ShaderObject) []ShaderObjec
return c2.Shader.AppendShaderObjects(objs)
}

func (c2 *CachedShader2D) unwrap() Shader { return c2.Shader }

type nameOverloadShader3D struct {
Shader Shader3D
name []byte
Expand Down Expand Up @@ -1150,6 +1173,8 @@ func (nos3 *nameOverloadShader3D) AppendShaderName(b []byte) []byte {
return append(b, nos3.name...)
}

func (nos3 *nameOverloadShader3D) unwrap() Shader { return nos3.Shader }

type nameOverloadShader2D struct {
Shader Shader2D
name []byte
Expand Down Expand Up @@ -1182,6 +1207,8 @@ func (nos2 *nameOverloadShader2D) AppendShaderObjects(objs []ShaderObject) []Sha
return nos2.Shader.AppendShaderObjects(objs)
}

func (nos2 *nameOverloadShader2D) unwrap() Shader { return nos2.Shader }

func hash(b []byte, in uint64) uint64 {
// Leaving md5 here since we may need to revert to
// a more entropic hash to avoid collisions...
Expand All @@ -1200,9 +1227,33 @@ func hash(b []byte, in uint64) uint64 {
x = (x ^ (x >> 27)) * 0x94d049bb133111eb
x ^= x >> 31
b = b[8:]

}
for i := range b {
x ^= uint64(b[i]) << i * 8
if len(b) > 0 {
var buf [8]byte
copy(buf[:], b)
x ^= binary.LittleEndian.Uint64(buf[:])
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9
x = (x ^ (x >> 27)) * 0x94d049bb133111eb
x ^= x >> 31
}
return x
}

func unwraproot(s Shader) Shader {
i := 0
var sbase Shader
for s != nil && i < 6 {
sbase = s
s = unwrap(s)
i++
}
return sbase
}

func unwrap(s Shader) Shader {
if unwrapper, ok := s.(interface{ unwrap() Shader }); ok {
return unwrapper.unwrap()
}
return nil
}
11 changes: 8 additions & 3 deletions gleval/gleval.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,14 @@ type BlockCachedSDF3 struct {
evals uint64
}

func (c3 *BlockCachedSDF3) VecPool() *VecPool {
vp, _ := GetVecPool(c3.sdf)
return vp
}

// Reset resets the SDF3 and reuses the underlying buffers for future SDF evaluations. It also resets statistics such as evaluations and cache hits.
func (c3 *BlockCachedSDF3) Reset(sdf SDF3, res ms3.Vec) error {
if res.X <= 0 || res.Y <= 0 || res.Z <= 0 {
func (c3 *BlockCachedSDF3) Reset(sdf SDF3, resX, resY, resZ float32) error {
if resX <= 0 || resY <= 0 || resZ <= 0 {
return errors.New("invalid resolution for BlockCachedSDF3")
}
if c3.m == nil {
Expand All @@ -125,7 +130,7 @@ func (c3 *BlockCachedSDF3) Reset(sdf SDF3, res ms3.Vec) error {
// Ncells := ms3.DivElem(bb.Size(), res)
*c3 = BlockCachedSDF3{
sdf: sdf,
mul: ms3.DivElem(ms3.Vec{X: 1, Y: 1, Z: 1}, res),
mul: ms3.DivElem(ms3.Vec{X: 1, Y: 1, Z: 1}, ms3.Vec{X: resX, Y: resY, Z: resZ}),
m: c3.m,
posbuf: c3.posbuf[:0],
distbuf: c3.distbuf[:0],
Expand Down
1 change: 1 addition & 0 deletions gleval/gpu_cgo.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ func computeEvaluate[T ms2.Vec | ms3.Vec](pos []T, dist []float32, invocX int, o
}
err := glgl.Err()
if err != nil {
p.Unpin()
return fmt.Errorf("binding SSBOs: %w", err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion glrender/glrender_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ func levelsVisual(filename string, startCube icube, targetLvl int, origin ms3.Ve
s = bld.Union(s, bb)
}
s = bld.Scale(s, 0.5/s.Bounds().Size().Max())
glbuild.ShortenNames3D(&s, 8)
glbuild.ShortenNames3D(&s, 12)
prog := glbuild.NewDefaultProgrammer()
fp, err := os.Create(filename)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion glrender/octreerenderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ func (oc *Octree) debugVisual(filename string, lvlDescent int, merge glbuild.Sha
s = bld.Union(s, bb)
}
s = bld.Scale(s, 0.5/s.Bounds().Size().Max())
glbuild.ShortenNames3D(&s, 8)
glbuild.ShortenNames3D(&s, 12)
prog := glbuild.NewDefaultProgrammer()
fp, err := os.Create(filename)
if err != nil {
Expand Down
38 changes: 31 additions & 7 deletions gsdf.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package gsdf

import (
_ "embed"
"encoding/binary"
"errors"
"fmt"
"unsafe"

"github.com/chewxy/math32"
"github.com/soypat/glgl/math/ms2"
"github.com/soypat/glgl/math/ms3"
"github.com/soypat/gsdf/glbuild"
)

const (
Expand Down Expand Up @@ -41,18 +43,14 @@ type Builder struct {
}

func (bld *Builder) useGPU(n int) bool {
return bld.limVecGPU != 0 && n > bld.limVecGPU || n > 1024
return bld.limVecGPU != 0 && n > bld.limVecGPU || n > 1
}

func makeHashName[T any](dst []byte, name string, vec []T) []byte {
var z T
data := unsafe.Pointer(&vec[0])
bdata := unsafe.Slice((*byte)(data), len(vec)*int(unsafe.Sizeof(z)))
_ = bdata
// for _, b := range bdata {

// }
return fmt.Appendf(dst, "%s%x", name, uintptr(data))
sz := len(vec) * int(unsafe.Sizeof(z))
return fmt.Appendf(dst, "%s%x_%x", name, uintptr(data), sz)
}

func (bld *Builder) Flags() Flags {
Expand Down Expand Up @@ -186,3 +184,29 @@ func hashAdd(a, b, num float32) (aNew, bNew float32) {
func hashfint(f float32) float32 {
return float32(int(f*1000000)%1000000) / 1000000 // Keep within [0.0, 1.0)
}

func hash(b []byte, in uint64) uint64 {
x := in
for len(b) >= 8 {
x ^= binary.LittleEndian.Uint64(b)
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9
x = (x ^ (x >> 27)) * 0x94d049bb133111eb
x ^= x >> 31
b = b[8:]

}
if len(b) > 0 {
var buf [8]byte
copy(buf[:], b)
x ^= binary.LittleEndian.Uint64(buf[:])
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9
x = (x ^ (x >> 27)) * 0x94d049bb133111eb
x ^= x >> 31
}
return x
}

func hashshaderptr(s glbuild.Shader) uint64 {
v := *(*[2]uintptr)(unsafe.Pointer(&s))
return (uint64(v[0]) ^ (uint64(v[1]) << 8)) * 0xbf58476d1ce4e5b9
}
Loading

0 comments on commit bed2388

Please sign in to comment.