-
Notifications
You must be signed in to change notification settings - Fork 0
/
render.go
125 lines (111 loc) · 2.72 KB
/
render.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package engine
import (
"github.com/mumax/3/cuda"
"github.com/mumax/3/data"
"github.com/mumax/3/draw"
"image"
"image/jpeg"
"net/http"
"sync"
)
//var renderer = render{img: new(image.RGBA)}
type render struct {
mutex sync.Mutex
quant Quantity
comp string
layer, scale int
saveCount int // previous max slider value of time
rescaleBuf *data.Slice // GPU
imgBuf *data.Slice // CPU
img_ *image.RGBA
}
const (
maxScale = 32 // maximum zoom-out setting
maxImgSize = 512 // maximum render image size
)
// Render image of quantity.
func (g *guistate) ServeRender(w http.ResponseWriter, r *http.Request) {
g.render.mutex.Lock()
defer g.render.mutex.Unlock()
g.render.render()
jpeg.Encode(w, g.render.img_, &jpeg.Options{Quality: 100})
}
// rescale and download quantity, save in rescaleBuf
func (ren *render) download() {
InjectAndWait(func() {
if ren.quant == nil { // not yet set, default = m
ren.quant = &M
}
quant := ren.quant
size := quant.Mesh().Size()
// don't slice out of bounds
renderLayer := ren.layer
if renderLayer >= size[Z] {
renderLayer = size[Z] - 1
}
if renderLayer < 0 {
renderLayer = 0
}
// scaling sanity check
if ren.scale < 1 {
ren.scale = 1
}
if ren.scale > maxScale {
ren.scale = maxScale
}
// Don't render too large images or we choke
for size[X]/ren.scale > maxImgSize {
ren.scale++
}
for size[Y]/ren.scale > maxImgSize {
ren.scale++
}
for i := range size {
size[i] /= ren.scale
if size[i] == 0 {
size[i] = 1
}
}
size[Z] = 1 // selects one layer
// make sure buffers are there
if ren.imgBuf.Size() != size {
ren.imgBuf = data.NewSlice(3, size) // always 3-comp, may be re-used
}
buf, r := quant.Slice()
if r {
defer cuda.Recycle(buf)
}
if !buf.GPUAccess() {
ren.imgBuf = Download(quant) // fallback (no zoom)
return
}
// make sure buffers are there (in CUDA context)
if ren.rescaleBuf.Size() != size {
ren.rescaleBuf.Free()
ren.rescaleBuf = cuda.NewSlice(1, size)
}
for c := 0; c < quant.NComp(); c++ {
cuda.Resize(ren.rescaleBuf, buf.Comp(c), renderLayer)
data.Copy(ren.imgBuf.Comp(c), ren.rescaleBuf)
}
})
}
var arrowSize = 16
func (ren *render) render() {
ren.download()
// imgBuf always has 3 components, we may need just one...
d := ren.imgBuf
comp := ren.comp
quant := ren.quant
if comp != "" && quant.NComp() > 1 { // ... if one has been selected by gui
d = d.Comp(compstr[comp])
}
if quant.NComp() == 1 { // ...or if the original data only had one (!)
d = d.Comp(0)
}
if ren.img_ == nil {
ren.img_ = new(image.RGBA)
}
draw.On(ren.img_, d, "auto", "auto", arrowSize)
}
var compstr = map[string]int{"x": 0, "y": 1, "z": 2}