Skip to content

Commit a9c82d2

Browse files
committed
Add option to draw images with WebGL
1 parent f36a47b commit a9c82d2

File tree

4 files changed

+124
-17
lines changed

4 files changed

+124
-17
lines changed

README.md

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ or
1818

1919
Binaries are compiled with static OpenCV library:
2020

21-
- [Android 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.1/cam2ip-1.1-android.tar.gz)
22-
- [Linux 64bit](https://github.com/gen2brain/cam2ip/releases/download/1.1/cam2ip-1.1-64bit.tar.gz)
23-
- [RPi 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.1/cam2ip-1.1-RPi.tar.gz)
24-
- [Windows 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.1/cam2ip-1.1.zip)
21+
- [Android 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.2/cam2ip-1.2-android.tar.gz)
22+
- [Linux 64bit](https://github.com/gen2brain/cam2ip/releases/download/1.2/cam2ip-1.2-64bit.tar.gz)
23+
- [RPi 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.2/cam2ip-1.2-RPi.tar.gz)
24+
- [Windows 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.2/cam2ip-1.2.zip)
2525

2626

2727
### Installation
@@ -35,17 +35,19 @@ This will install app in `$GOPATH/bin/cam2ip`.
3535
```
3636
Usage of ./cam2ip:
3737
-bind-addr string
38-
Bind address (default ":56000")
38+
Bind address (default ":56000")
3939
-delay int
40-
Delay between frames, in milliseconds (default 10)
40+
Delay between frames, in milliseconds (default 10)
4141
-frame-height float
42-
Frame height (default 480)
42+
Frame height (default 480)
4343
-frame-width float
44-
Frame width (default 640)
44+
Frame width (default 640)
4545
-htpasswd-file string
46-
Path to htpasswd file, if empty auth is disabled
46+
Path to htpasswd file, if empty auth is disabled
4747
-index int
48-
Camera index
48+
Camera index
49+
-webgl
50+
Use WebGL to draw images
4951
```
5052

5153
### Handlers

cam2ip.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ func main() {
2121
flag.IntVar(&srv.Delay, "delay", 10, "Delay between frames, in milliseconds")
2222
flag.Float64Var(&srv.FrameWidth, "frame-width", 640, "Frame width")
2323
flag.Float64Var(&srv.FrameHeight, "frame-height", 480, "Frame height")
24+
flag.BoolVar(&srv.WebGL, "webgl", false, "Use WebGL to draw images")
2425
flag.StringVar(&srv.Bind, "bind-addr", ":56000", "Bind address")
2526
flag.StringVar(&srv.Htpasswd, "htpasswd-file", "", "Path to htpasswd file, if empty auth is disabled")
2627
flag.Parse()

handlers/html.go

Lines changed: 109 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,24 @@ type HTML struct {
1313
}
1414

1515
// NewHTML returns new HTML handler.
16-
func NewHTML(bind string, width, height float64) *HTML {
16+
func NewHTML(bind string, width, height float64, gl bool) *HTML {
1717
h := &HTML{}
1818

1919
b := strings.Split(bind, ":")
2020
if b[0] == "" {
2121
bind = "127.0.0.1" + bind
2222
}
2323

24-
html = strings.Replace(html, "{BIND}", bind, -1)
25-
html = strings.Replace(html, "{WIDTH}", fmt.Sprintf("%.0f", width), -1)
26-
html = strings.Replace(html, "{HEIGHT}", fmt.Sprintf("%.0f", height), -1)
24+
tpl := html
25+
if gl {
26+
tpl = htmlWebGL
27+
}
28+
29+
tpl = strings.Replace(tpl, "{BIND}", bind, -1)
30+
tpl = strings.Replace(tpl, "{WIDTH}", fmt.Sprintf("%.0f", width), -1)
31+
tpl = strings.Replace(tpl, "{HEIGHT}", fmt.Sprintf("%.0f", height), -1)
2732

28-
h.Template = []byte(html)
33+
h.Template = []byte(tpl)
2934
return h
3035
}
3136

@@ -51,7 +56,7 @@ var html = `<html>
5156
var image = new Image();
5257
5358
ws.onopen = function() {
54-
var context = document.getElementById("canvas").getContext("2d");
59+
var context = document.getElementById("canvas").getContext("2d", {alpha: false});
5560
image.onload = function() {
5661
context.drawImage(image, 0, 0);
5762
}
@@ -72,3 +77,101 @@ var html = `<html>
7277
</table>
7378
</body>
7479
</html>`
80+
81+
var htmlWebGL = `<html>
82+
<head>
83+
<meta charset="utf-8"/>
84+
<title>cam2ip</title>
85+
<script>
86+
var texture, vloc, tloc, vertexBuff, textureBuff;
87+
88+
ws = new WebSocket("ws://{BIND}/socket");
89+
var image = new Image();
90+
91+
ws.onopen = function() {
92+
var gl = document.getElementById('canvas').getContext('webgl');
93+
94+
var vertexShaderSrc =
95+
"attribute vec2 aVertex;" +
96+
"attribute vec2 aUV;" +
97+
"varying vec2 vTex;" +
98+
"void main(void) {" +
99+
" gl_Position = vec4(aVertex, 0.0, 1.0);" +
100+
" vTex = aUV;" +
101+
"}";
102+
103+
var fragmentShaderSrc =
104+
"precision mediump float;" +
105+
"varying vec2 vTex;" +
106+
"uniform sampler2D sampler0;" +
107+
"void main(void){" +
108+
" gl_FragColor = texture2D(sampler0, vTex);"+
109+
"}";
110+
111+
var vertShaderObj = gl.createShader(gl.VERTEX_SHADER);
112+
var fragShaderObj = gl.createShader(gl.FRAGMENT_SHADER);
113+
gl.shaderSource(vertShaderObj, vertexShaderSrc);
114+
gl.shaderSource(fragShaderObj, fragmentShaderSrc);
115+
gl.compileShader(vertShaderObj);
116+
gl.compileShader(fragShaderObj);
117+
118+
var program = gl.createProgram();
119+
gl.attachShader(program, vertShaderObj);
120+
gl.attachShader(program, fragShaderObj);
121+
122+
gl.linkProgram(program);
123+
gl.useProgram(program);
124+
125+
gl.viewport(0, 0, {WIDTH}, {HEIGHT});
126+
127+
vertexBuff = gl.createBuffer();
128+
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuff);
129+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, 1, -1, -1, 1, -1, 1, 1]), gl.STATIC_DRAW);
130+
131+
textureBuff = gl.createBuffer();
132+
gl.bindBuffer(gl.ARRAY_BUFFER, textureBuff);
133+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 1, 0, 0, 1, 0, 1, 1]), gl.STATIC_DRAW);
134+
135+
vloc = gl.getAttribLocation(program, "aVertex");
136+
tloc = gl.getAttribLocation(program, "aUV");
137+
138+
texture = gl.createTexture();
139+
140+
image.onload = function() {
141+
gl.bindTexture(gl.TEXTURE_2D, texture);
142+
143+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
144+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
145+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
146+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
147+
148+
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
149+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
150+
151+
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuff);
152+
gl.enableVertexAttribArray(vloc);
153+
gl.vertexAttribPointer(vloc, 2, gl.FLOAT, false, 0, 0);
154+
155+
gl.bindBuffer(gl.ARRAY_BUFFER, textureBuff);
156+
gl.enableVertexAttribArray(tloc);
157+
gl.vertexAttribPointer(tloc, 2, gl.FLOAT, false, 0, 0);
158+
159+
gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
160+
}
161+
}
162+
163+
ws.onmessage = function(e) {
164+
image.setAttribute("src", "data:image/jpeg;base64," + e.data);
165+
}
166+
</script>
167+
</head>
168+
<body style="background-color: #000000">
169+
<table style="width:100%; height:100%">
170+
<tr style="height:100%">
171+
<td style="height:100%; text-align:center">
172+
<canvas id="canvas" width="{WIDTH}" height="{HEIGHT}"></canvas>
173+
</td>
174+
</tr>
175+
</table>
176+
</body>
177+
</html>`

server/server.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type Server struct {
2424
Delay int
2525
FrameWidth float64
2626
FrameHeight float64
27+
WebGL bool
2728

2829
Camera *camera.Camera
2930
}
@@ -42,7 +43,7 @@ func (s *Server) ListenAndServe() error {
4243
basic = auth.NewBasicAuthenticator(realm, auth.HtpasswdFileProvider(s.Htpasswd))
4344
}
4445

45-
http.Handle("/html", newAuthHandler(handlers.NewHTML(s.Bind, s.FrameWidth, s.FrameHeight), basic))
46+
http.Handle("/html", newAuthHandler(handlers.NewHTML(s.Bind, s.FrameWidth, s.FrameHeight, s.WebGL), basic))
4647
http.Handle("/jpeg", newAuthHandler(handlers.NewJPEG(s.Camera), basic))
4748
http.Handle("/mjpeg", newAuthHandler(handlers.NewMJPEG(s.Camera, s.Delay), basic))
4849

0 commit comments

Comments
 (0)