nuclear@5: #include nuclear@5: #include nuclear@5: #include nuclear@7: #include nuclear@5: #include nuclear@5: #include nuclear@5: #include nuclear@5: #include nuclear@5: #include nuclear@5: #include nuclear@5: #include nuclear@5: #include nuclear@5: #include nuclear@5: #include nuclear@5: nuclear@7: struct video_block { nuclear@5: int frame; nuclear@7: uint16_t x, y; nuclear@7: uint16_t width, height; nuclear@7: uint16_t frame_width, frame_height; nuclear@7: uint16_t pixels[1]; nuclear@5: }; nuclear@5: nuclear@5: int conn(const char *host, int port); nuclear@5: void display(void); nuclear@5: void reshape(int x, int y); nuclear@5: void keyb(unsigned char key, int x, int y); nuclear@5: int handle_conn(int s); nuclear@7: int handle_video(int s); nuclear@5: void post_redisplay(void); nuclear@5: nuclear@5: int quit; nuclear@7: int ctlsock, vidsock; nuclear@5: const char *address = "localhost"; nuclear@5: int port = 2828; nuclear@5: unsigned int tex, tex_width, tex_height; nuclear@5: int redraw_pending; nuclear@5: nuclear@7: #define MAX(a, b) ((a) > (b) ? (a) : (b)) nuclear@7: nuclear@5: int main(int argc, char **argv) nuclear@5: { nuclear@5: Display *dpy; nuclear@5: int xsock; nuclear@5: nuclear@5: glutInit(&argc, argv); nuclear@5: glutInitWindowSize(800, 600); nuclear@5: glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); nuclear@5: glutCreateWindow("doorbell"); nuclear@5: nuclear@5: glutDisplayFunc(display); nuclear@5: glutReshapeFunc(reshape); nuclear@5: glutKeyboardFunc(keyb); nuclear@5: nuclear@5: dpy = glXGetCurrentDisplay(); nuclear@5: xsock = ConnectionNumber(dpy); nuclear@5: nuclear@7: if(conn(address, port) == -1) { nuclear@5: return 1; nuclear@5: } nuclear@7: write(ctlsock, "hello", 5); nuclear@5: nuclear@5: glGenTextures(1, &tex); nuclear@5: glBindTexture(GL_TEXTURE_2D, tex); nuclear@5: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); nuclear@5: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); nuclear@5: nuclear@5: for(;;) { nuclear@7: int res, maxfd; nuclear@5: struct timeval tv0 = {0, 0}; nuclear@5: fd_set rdset; nuclear@5: nuclear@5: FD_ZERO(&rdset); nuclear@5: FD_SET(xsock, &rdset); nuclear@7: FD_SET(ctlsock, &rdset); nuclear@7: FD_SET(vidsock, &rdset); nuclear@5: nuclear@7: maxfd = MAX(MAX(xsock, ctlsock), vidsock); nuclear@5: while((res = select(maxfd + 1, &rdset, 0, 0, redraw_pending ? &tv0 : 0) == -1) && errno == EINTR); nuclear@5: if(res == -1) break; nuclear@5: nuclear@5: if(redraw_pending || FD_ISSET(xsock, &rdset)) { nuclear@5: glutMainLoopEvent(); nuclear@5: if(quit) { nuclear@5: break; nuclear@5: } nuclear@5: } nuclear@7: if(FD_ISSET(ctlsock, &rdset)) { nuclear@7: if(handle_conn(ctlsock) == -1) { nuclear@7: break; nuclear@7: } nuclear@7: } nuclear@7: if(FD_ISSET(vidsock, &rdset)) { nuclear@7: if(handle_video(vidsock) == -1) { nuclear@5: break; nuclear@5: } nuclear@5: } nuclear@5: } nuclear@5: nuclear@7: close(ctlsock); nuclear@5: return 0; nuclear@5: } nuclear@5: nuclear@5: nuclear@5: int conn(const char *hostname, int port) nuclear@5: { nuclear@5: struct sockaddr_in addr; nuclear@5: struct hostent *host; nuclear@5: nuclear@7: if((ctlsock = socket(PF_INET, SOCK_STREAM, 0)) == -1) { nuclear@5: fprintf(stderr, "failed to create socket\n"); nuclear@5: return -1; nuclear@5: } nuclear@5: nuclear@5: if(!(host = gethostbyname(hostname))) { nuclear@5: fprintf(stderr, "failed to resolve hostname: %s\n", hostname); nuclear@5: return -1; nuclear@5: } nuclear@5: nuclear@5: memset(&addr, 0, sizeof addr); nuclear@5: addr.sin_family = AF_INET; nuclear@5: addr.sin_port = htons(port); nuclear@5: addr.sin_addr = *(struct in_addr*)host->h_addr; nuclear@5: nuclear@5: printf("connecting to %s (%s), port %d\n", hostname, inet_ntoa(addr.sin_addr), port); nuclear@7: if(connect(ctlsock, (struct sockaddr*)&addr, sizeof addr) == -1) { nuclear@5: fprintf(stderr, "failed to connect\n"); nuclear@5: return -1; nuclear@5: } nuclear@7: fcntl(ctlsock, F_SETFL, fcntl(ctlsock, F_GETFL) | O_NONBLOCK); nuclear@5: nuclear@7: /* prepare the video socket */ nuclear@7: if((vidsock = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { nuclear@7: fprintf(stderr, "failed to create video socket\n"); nuclear@7: return 1; nuclear@7: } nuclear@7: nuclear@7: memset(&addr, 0, sizeof addr); nuclear@7: addr.sin_family = AF_INET; nuclear@7: addr.sin_port = htons(port + 1); nuclear@7: addr.sin_addr.s_addr = htonl(INADDR_ANY); nuclear@7: if(bind(vidsock, (struct sockaddr*)&addr, sizeof addr) == -1) { nuclear@7: fprintf(stderr, "failed to bind video socket to port %d\n", port + 1); nuclear@7: return 1; nuclear@7: } nuclear@7: nuclear@7: return 0; nuclear@5: } nuclear@5: nuclear@5: void display(void) nuclear@5: { nuclear@5: redraw_pending = 0; nuclear@5: nuclear@5: glClear(GL_COLOR_BUFFER_BIT); nuclear@5: nuclear@5: glMatrixMode(GL_MODELVIEW); nuclear@5: glLoadIdentity(); nuclear@5: nuclear@5: glPushMatrix(); nuclear@5: glScalef(0.75, 0.75, 0.75); nuclear@5: nuclear@5: glBindTexture(GL_TEXTURE_2D, tex); nuclear@5: glEnable(GL_TEXTURE_2D); nuclear@5: nuclear@5: glBegin(GL_QUADS); nuclear@7: glTexCoord2f(0, 1); glVertex2f(-1, -1); nuclear@7: glTexCoord2f(1, 1); glVertex2f(1, -1); nuclear@7: glTexCoord2f(1, 0); glVertex2f(1, 1); nuclear@7: glTexCoord2f(0, 0); glVertex2f(-1, 1); nuclear@5: glEnd(); nuclear@5: nuclear@5: glDisable(GL_TEXTURE_2D); nuclear@5: glPopMatrix(); nuclear@5: nuclear@5: glutSwapBuffers(); nuclear@5: } nuclear@5: nuclear@5: void reshape(int x, int y) nuclear@5: { nuclear@5: glViewport(0, 0, x, y); nuclear@5: glMatrixMode(GL_PROJECTION); nuclear@5: glLoadIdentity(); nuclear@5: } nuclear@5: nuclear@5: void keyb(unsigned char key, int x, int y) nuclear@5: { nuclear@5: switch(key) { nuclear@5: case 27: nuclear@5: quit = 1; nuclear@5: break; nuclear@5: } nuclear@5: } nuclear@5: nuclear@5: int handle_conn(int s) nuclear@5: { nuclear@7: fprintf(stderr, "whaaaa!\n"); nuclear@7: return -1; nuclear@7: } nuclear@7: nuclear@7: int handle_video(int s) nuclear@7: { nuclear@5: static int cur_frame; nuclear@7: static char buffer[2048]; nuclear@7: struct video_block *vblock; nuclear@7: struct sockaddr_in addr; nuclear@7: socklen_t addr_size; nuclear@5: nuclear@7: addr_size = sizeof addr; nuclear@7: if(recvfrom(vidsock, buffer, sizeof buffer, 0, (struct sockaddr*)&addr, &addr_size) == -1) { nuclear@7: perror("failed to receive video block"); nuclear@5: return -1; nuclear@5: } nuclear@5: nuclear@7: vblock = (struct video_block*)buffer; nuclear@7: nuclear@7: if(vblock->frame < cur_frame) { nuclear@7: printf("skipping old frame %d\n", vblock->frame); nuclear@7: return 0; nuclear@7: } nuclear@7: cur_frame = vblock->frame; nuclear@7: printf("updating block %dx%d%+d%+d in frame %d\n", vblock->width, vblock->height, nuclear@7: vblock->x, vblock->y, vblock->frame); nuclear@7: nuclear@5: glBindTexture(GL_TEXTURE_2D, tex); nuclear@5: nuclear@7: if(tex_width < vblock->frame_width || tex_height < vblock->frame_height) { nuclear@7: tex_width = vblock->frame_width; nuclear@7: tex_height = vblock->frame_height; nuclear@5: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_width, tex_height, 0, nuclear@5: GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0); nuclear@5: } nuclear@7: glTexSubImage2D(GL_TEXTURE_2D, 0, vblock->x, vblock->y, vblock->width, vblock->height, nuclear@7: GL_RGB, GL_UNSIGNED_SHORT_5_6_5, vblock->pixels); nuclear@5: nuclear@5: post_redisplay(); nuclear@5: return 0; nuclear@5: } nuclear@5: nuclear@5: void post_redisplay(void) nuclear@5: { nuclear@5: glutPostRedisplay(); nuclear@5: redraw_pending = 1; nuclear@5: }