rev |
line source |
nuclear@5
|
1 #include <stdio.h>
|
nuclear@5
|
2 #include <stdlib.h>
|
nuclear@5
|
3 #include <string.h>
|
nuclear@7
|
4 #include <stdint.h>
|
nuclear@5
|
5 #include <errno.h>
|
nuclear@5
|
6 #include <unistd.h>
|
nuclear@5
|
7 #include <fcntl.h>
|
nuclear@5
|
8 #include <sys/select.h>
|
nuclear@5
|
9 #include <sys/socket.h>
|
nuclear@5
|
10 #include <arpa/inet.h>
|
nuclear@5
|
11 #include <netdb.h>
|
nuclear@5
|
12 #include <GL/glut.h>
|
nuclear@5
|
13 #include <GL/freeglut_ext.h>
|
nuclear@5
|
14 #include <GL/glx.h>
|
nuclear@5
|
15
|
nuclear@7
|
16 struct video_block {
|
nuclear@5
|
17 int frame;
|
nuclear@7
|
18 uint16_t x, y;
|
nuclear@7
|
19 uint16_t width, height;
|
nuclear@7
|
20 uint16_t frame_width, frame_height;
|
nuclear@7
|
21 uint16_t pixels[1];
|
nuclear@5
|
22 };
|
nuclear@5
|
23
|
nuclear@5
|
24 int conn(const char *host, int port);
|
nuclear@5
|
25 void display(void);
|
nuclear@5
|
26 void reshape(int x, int y);
|
nuclear@5
|
27 void keyb(unsigned char key, int x, int y);
|
nuclear@5
|
28 int handle_conn(int s);
|
nuclear@7
|
29 int handle_video(int s);
|
nuclear@5
|
30 void post_redisplay(void);
|
nuclear@5
|
31
|
nuclear@5
|
32 int quit;
|
nuclear@7
|
33 int ctlsock, vidsock;
|
nuclear@5
|
34 const char *address = "localhost";
|
nuclear@5
|
35 int port = 2828;
|
nuclear@5
|
36 unsigned int tex, tex_width, tex_height;
|
nuclear@5
|
37 int redraw_pending;
|
nuclear@5
|
38
|
nuclear@7
|
39 #define MAX(a, b) ((a) > (b) ? (a) : (b))
|
nuclear@7
|
40
|
nuclear@5
|
41 int main(int argc, char **argv)
|
nuclear@5
|
42 {
|
nuclear@5
|
43 Display *dpy;
|
nuclear@5
|
44 int xsock;
|
nuclear@5
|
45
|
nuclear@5
|
46 glutInit(&argc, argv);
|
nuclear@5
|
47 glutInitWindowSize(800, 600);
|
nuclear@5
|
48 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
|
nuclear@5
|
49 glutCreateWindow("doorbell");
|
nuclear@5
|
50
|
nuclear@5
|
51 glutDisplayFunc(display);
|
nuclear@5
|
52 glutReshapeFunc(reshape);
|
nuclear@5
|
53 glutKeyboardFunc(keyb);
|
nuclear@5
|
54
|
nuclear@5
|
55 dpy = glXGetCurrentDisplay();
|
nuclear@5
|
56 xsock = ConnectionNumber(dpy);
|
nuclear@5
|
57
|
nuclear@7
|
58 if(conn(address, port) == -1) {
|
nuclear@5
|
59 return 1;
|
nuclear@5
|
60 }
|
nuclear@7
|
61 write(ctlsock, "hello", 5);
|
nuclear@5
|
62
|
nuclear@5
|
63 glGenTextures(1, &tex);
|
nuclear@5
|
64 glBindTexture(GL_TEXTURE_2D, tex);
|
nuclear@5
|
65 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
nuclear@5
|
66 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
nuclear@5
|
67
|
nuclear@5
|
68 for(;;) {
|
nuclear@7
|
69 int res, maxfd;
|
nuclear@5
|
70 struct timeval tv0 = {0, 0};
|
nuclear@5
|
71 fd_set rdset;
|
nuclear@5
|
72
|
nuclear@5
|
73 FD_ZERO(&rdset);
|
nuclear@5
|
74 FD_SET(xsock, &rdset);
|
nuclear@7
|
75 FD_SET(ctlsock, &rdset);
|
nuclear@7
|
76 FD_SET(vidsock, &rdset);
|
nuclear@5
|
77
|
nuclear@7
|
78 maxfd = MAX(MAX(xsock, ctlsock), vidsock);
|
nuclear@5
|
79 while((res = select(maxfd + 1, &rdset, 0, 0, redraw_pending ? &tv0 : 0) == -1) && errno == EINTR);
|
nuclear@5
|
80 if(res == -1) break;
|
nuclear@5
|
81
|
nuclear@5
|
82 if(redraw_pending || FD_ISSET(xsock, &rdset)) {
|
nuclear@5
|
83 glutMainLoopEvent();
|
nuclear@5
|
84 if(quit) {
|
nuclear@5
|
85 break;
|
nuclear@5
|
86 }
|
nuclear@5
|
87 }
|
nuclear@7
|
88 if(FD_ISSET(ctlsock, &rdset)) {
|
nuclear@7
|
89 if(handle_conn(ctlsock) == -1) {
|
nuclear@7
|
90 break;
|
nuclear@7
|
91 }
|
nuclear@7
|
92 }
|
nuclear@7
|
93 if(FD_ISSET(vidsock, &rdset)) {
|
nuclear@7
|
94 if(handle_video(vidsock) == -1) {
|
nuclear@5
|
95 break;
|
nuclear@5
|
96 }
|
nuclear@5
|
97 }
|
nuclear@5
|
98 }
|
nuclear@5
|
99
|
nuclear@7
|
100 close(ctlsock);
|
nuclear@5
|
101 return 0;
|
nuclear@5
|
102 }
|
nuclear@5
|
103
|
nuclear@5
|
104
|
nuclear@5
|
105 int conn(const char *hostname, int port)
|
nuclear@5
|
106 {
|
nuclear@5
|
107 struct sockaddr_in addr;
|
nuclear@5
|
108 struct hostent *host;
|
nuclear@5
|
109
|
nuclear@7
|
110 if((ctlsock = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
|
nuclear@5
|
111 fprintf(stderr, "failed to create socket\n");
|
nuclear@5
|
112 return -1;
|
nuclear@5
|
113 }
|
nuclear@5
|
114
|
nuclear@5
|
115 if(!(host = gethostbyname(hostname))) {
|
nuclear@5
|
116 fprintf(stderr, "failed to resolve hostname: %s\n", hostname);
|
nuclear@5
|
117 return -1;
|
nuclear@5
|
118 }
|
nuclear@5
|
119
|
nuclear@5
|
120 memset(&addr, 0, sizeof addr);
|
nuclear@5
|
121 addr.sin_family = AF_INET;
|
nuclear@5
|
122 addr.sin_port = htons(port);
|
nuclear@5
|
123 addr.sin_addr = *(struct in_addr*)host->h_addr;
|
nuclear@5
|
124
|
nuclear@5
|
125 printf("connecting to %s (%s), port %d\n", hostname, inet_ntoa(addr.sin_addr), port);
|
nuclear@7
|
126 if(connect(ctlsock, (struct sockaddr*)&addr, sizeof addr) == -1) {
|
nuclear@5
|
127 fprintf(stderr, "failed to connect\n");
|
nuclear@5
|
128 return -1;
|
nuclear@5
|
129 }
|
nuclear@7
|
130 fcntl(ctlsock, F_SETFL, fcntl(ctlsock, F_GETFL) | O_NONBLOCK);
|
nuclear@5
|
131
|
nuclear@7
|
132 /* prepare the video socket */
|
nuclear@7
|
133 if((vidsock = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
|
nuclear@7
|
134 fprintf(stderr, "failed to create video socket\n");
|
nuclear@7
|
135 return 1;
|
nuclear@7
|
136 }
|
nuclear@7
|
137
|
nuclear@7
|
138 memset(&addr, 0, sizeof addr);
|
nuclear@7
|
139 addr.sin_family = AF_INET;
|
nuclear@7
|
140 addr.sin_port = htons(port + 1);
|
nuclear@7
|
141 addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
nuclear@7
|
142 if(bind(vidsock, (struct sockaddr*)&addr, sizeof addr) == -1) {
|
nuclear@7
|
143 fprintf(stderr, "failed to bind video socket to port %d\n", port + 1);
|
nuclear@7
|
144 return 1;
|
nuclear@7
|
145 }
|
nuclear@7
|
146
|
nuclear@7
|
147 return 0;
|
nuclear@5
|
148 }
|
nuclear@5
|
149
|
nuclear@5
|
150 void display(void)
|
nuclear@5
|
151 {
|
nuclear@5
|
152 redraw_pending = 0;
|
nuclear@5
|
153
|
nuclear@5
|
154 glClear(GL_COLOR_BUFFER_BIT);
|
nuclear@5
|
155
|
nuclear@5
|
156 glMatrixMode(GL_MODELVIEW);
|
nuclear@5
|
157 glLoadIdentity();
|
nuclear@5
|
158
|
nuclear@5
|
159 glPushMatrix();
|
nuclear@5
|
160 glScalef(0.75, 0.75, 0.75);
|
nuclear@5
|
161
|
nuclear@5
|
162 glBindTexture(GL_TEXTURE_2D, tex);
|
nuclear@5
|
163 glEnable(GL_TEXTURE_2D);
|
nuclear@5
|
164
|
nuclear@5
|
165 glBegin(GL_QUADS);
|
nuclear@7
|
166 glTexCoord2f(0, 1); glVertex2f(-1, -1);
|
nuclear@7
|
167 glTexCoord2f(1, 1); glVertex2f(1, -1);
|
nuclear@7
|
168 glTexCoord2f(1, 0); glVertex2f(1, 1);
|
nuclear@7
|
169 glTexCoord2f(0, 0); glVertex2f(-1, 1);
|
nuclear@5
|
170 glEnd();
|
nuclear@5
|
171
|
nuclear@5
|
172 glDisable(GL_TEXTURE_2D);
|
nuclear@5
|
173 glPopMatrix();
|
nuclear@5
|
174
|
nuclear@5
|
175 glutSwapBuffers();
|
nuclear@5
|
176 }
|
nuclear@5
|
177
|
nuclear@5
|
178 void reshape(int x, int y)
|
nuclear@5
|
179 {
|
nuclear@5
|
180 glViewport(0, 0, x, y);
|
nuclear@5
|
181 glMatrixMode(GL_PROJECTION);
|
nuclear@5
|
182 glLoadIdentity();
|
nuclear@5
|
183 }
|
nuclear@5
|
184
|
nuclear@5
|
185 void keyb(unsigned char key, int x, int y)
|
nuclear@5
|
186 {
|
nuclear@5
|
187 switch(key) {
|
nuclear@5
|
188 case 27:
|
nuclear@5
|
189 quit = 1;
|
nuclear@5
|
190 break;
|
nuclear@5
|
191 }
|
nuclear@5
|
192 }
|
nuclear@5
|
193
|
nuclear@5
|
194 int handle_conn(int s)
|
nuclear@5
|
195 {
|
nuclear@7
|
196 fprintf(stderr, "whaaaa!\n");
|
nuclear@7
|
197 return -1;
|
nuclear@7
|
198 }
|
nuclear@7
|
199
|
nuclear@7
|
200 int handle_video(int s)
|
nuclear@7
|
201 {
|
nuclear@5
|
202 static int cur_frame;
|
nuclear@7
|
203 static char buffer[2048];
|
nuclear@7
|
204 struct video_block *vblock;
|
nuclear@7
|
205 struct sockaddr_in addr;
|
nuclear@7
|
206 socklen_t addr_size;
|
nuclear@5
|
207
|
nuclear@7
|
208 addr_size = sizeof addr;
|
nuclear@7
|
209 if(recvfrom(vidsock, buffer, sizeof buffer, 0, (struct sockaddr*)&addr, &addr_size) == -1) {
|
nuclear@7
|
210 perror("failed to receive video block");
|
nuclear@5
|
211 return -1;
|
nuclear@5
|
212 }
|
nuclear@5
|
213
|
nuclear@7
|
214 vblock = (struct video_block*)buffer;
|
nuclear@7
|
215
|
nuclear@7
|
216 if(vblock->frame < cur_frame) {
|
nuclear@7
|
217 printf("skipping old frame %d\n", vblock->frame);
|
nuclear@7
|
218 return 0;
|
nuclear@7
|
219 }
|
nuclear@7
|
220 cur_frame = vblock->frame;
|
nuclear@7
|
221 printf("updating block %dx%d%+d%+d in frame %d\n", vblock->width, vblock->height,
|
nuclear@7
|
222 vblock->x, vblock->y, vblock->frame);
|
nuclear@7
|
223
|
nuclear@5
|
224 glBindTexture(GL_TEXTURE_2D, tex);
|
nuclear@5
|
225
|
nuclear@7
|
226 if(tex_width < vblock->frame_width || tex_height < vblock->frame_height) {
|
nuclear@7
|
227 tex_width = vblock->frame_width;
|
nuclear@7
|
228 tex_height = vblock->frame_height;
|
nuclear@5
|
229 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_width, tex_height, 0,
|
nuclear@5
|
230 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
|
nuclear@5
|
231 }
|
nuclear@7
|
232 glTexSubImage2D(GL_TEXTURE_2D, 0, vblock->x, vblock->y, vblock->width, vblock->height,
|
nuclear@7
|
233 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, vblock->pixels);
|
nuclear@5
|
234
|
nuclear@5
|
235 post_redisplay();
|
nuclear@5
|
236 return 0;
|
nuclear@5
|
237 }
|
nuclear@5
|
238
|
nuclear@5
|
239 void post_redisplay(void)
|
nuclear@5
|
240 {
|
nuclear@5
|
241 glutPostRedisplay();
|
nuclear@5
|
242 redraw_pending = 1;
|
nuclear@5
|
243 }
|