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