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: #include nuclear@5: #include nuclear@5: #include nuclear@5: nuclear@5: struct video_block_header { nuclear@5: unsigned int magic; nuclear@5: int frame; nuclear@5: int x, y; nuclear@5: int width, height; nuclear@5: int frame_width, frame_height; 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@5: void post_redisplay(void); nuclear@5: nuclear@5: int quit; nuclear@5: int srvsock; 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@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@5: if((srvsock = conn(address, port)) == -1) { nuclear@5: return 1; nuclear@5: } nuclear@5: write(srvsock, "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@5: int res; nuclear@5: int maxfd = srvsock > xsock ? srvsock : xsock; 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@5: FD_SET(srvsock, &rdset); nuclear@5: 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@5: if(FD_ISSET(srvsock, &rdset)) { nuclear@5: if(handle_conn(srvsock) == -1) { nuclear@5: break; nuclear@5: } nuclear@5: } nuclear@5: } nuclear@5: nuclear@5: close(srvsock); nuclear@5: return 0; nuclear@5: } nuclear@5: nuclear@5: nuclear@5: int conn(const char *hostname, int port) nuclear@5: { nuclear@5: int s; nuclear@5: struct sockaddr_in addr; nuclear@5: struct hostent *host; nuclear@5: nuclear@5: if((s = 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@5: if(connect(s, (struct sockaddr*)&addr, sizeof addr) == -1) { nuclear@5: fprintf(stderr, "failed to connect\n"); nuclear@5: return -1; nuclear@5: } nuclear@5: nuclear@5: fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK); nuclear@5: return s; 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@5: glTexCoord2f(0, 0); glVertex2f(-1, -1); nuclear@5: glTexCoord2f(1, 0); glVertex2f(1, -1); nuclear@5: glTexCoord2f(1, 1); glVertex2f(1, 1); nuclear@5: glTexCoord2f(0, 1); 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@5: static int cur_frame; nuclear@5: struct video_block_header hdr; nuclear@5: int size; nuclear@5: unsigned char *pixels; nuclear@5: nuclear@5: if(read(s, &hdr, sizeof hdr) != sizeof hdr) { nuclear@5: fprintf(stderr, "failed to read video block header\n"); nuclear@5: return -1; nuclear@5: } nuclear@5: if(hdr.frame < cur_frame) { nuclear@5: printf("skipping old frame %d\n", hdr.frame); nuclear@5: } nuclear@5: cur_frame = hdr.frame; nuclear@5: printf("updating block %dx%d%+d%+d in frame %d\n", hdr.width, hdr.height, hdr.x, hdr.y, hdr.frame); nuclear@5: nuclear@5: size = hdr.width * hdr.height * 2; nuclear@5: if(!(pixels = malloc(size))) { nuclear@5: fprintf(stderr, "failed to allocate pixel block %dx%d\n", hdr.width, hdr.height); nuclear@5: return -1; nuclear@5: } nuclear@5: if(read(s, pixels, size) != size) { nuclear@5: fprintf(stderr, "failed to read pixel block\n"); nuclear@5: return -1; nuclear@5: } nuclear@5: nuclear@5: glBindTexture(GL_TEXTURE_2D, tex); nuclear@5: nuclear@5: if(tex_width < hdr.frame_width || tex_height < hdr.frame_height) { nuclear@5: tex_width = hdr.frame_width; nuclear@5: tex_height = hdr.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@5: glTexSubImage2D(GL_TEXTURE_2D, 0, hdr.x, hdr.y, hdr.width, hdr.height, nuclear@5: GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 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: }