#include "rtweekend.h" #include "scene.h" #include "colour.h" #include "camera.h" #include "material.h" #include "image.h" #include #include #include #include #include #include // file descriptor of the socket we're listening for connections on // // returns fd for the client connection int accept_client(int sockfd) { int newsockfd; struct sockaddr_in cli_addr; socklen_t clilen = sizeof(cli_addr); newsockfd = accept(sockfd, (struct sockaddr*)&cli_addr, &clilen); if (newsockfd < 0) { error("ERROR accepting client"); } return newsockfd; } int wait_for_client(int& sockfd) { int newsockfd; struct sockaddr_in serv_addr; // open socket and await connection from client sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { error("ERROR creating socket"); } bzero((char*)&serv_addr, sizeof(serv_addr)); // we successfully created the socket, configure it for binding serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(64999); // convert number from host to network byte order // this is a bit of developer QoL so we can iterate more quickly // TODO: make it possible to disable this debug/release build configuration const int enable = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) { error("ERROR setsockopt(SO_REUSEADDR) failed"); } if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0) { error("ERROR setsockopt(SO_REUSEPORT) failed"); } // bind the socket if (bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { error("ERROR binding socket"); } // successfully bound socket, start listening for connections listen(sockfd, 5); newsockfd = accept_client(sockfd); return newsockfd; } void send_message(int sock, const char* message) { int written = write(sock, message, strlen(message)); if (written < 0) { error("ERROR sending message to the client"); } printf("SEND %s\n", message); } void send_image_dimensions(int sock, unsigned int width, unsigned int height) { // https://linux.die.net/man/3/htons width = htonl(width); height = htonl(height); int written = write(sock, &width, sizeof(uint32_t)); if (written < 0) { error("ERROR writing width"); } written = write(sock, &height, sizeof(uint32_t)); if (written < 0) { error("ERROR writing height"); } } void render(camera& cam, hittable_list& world, int client_sock) { for (int j = HEIGHT - 1; j >= 0; --j) { std::cerr << "\rScanlines remaining: " << j << ' ' << std::flush; for (int i = 0; i < WIDTH; ++i) { colour pixel_colour(0,0,0); for (int s = 0; s < SAMPLES_PER_PIXEL; ++s) { auto u = (i + math::random_double()) / (WIDTH-1); auto v = (j + math::random_double()) / (HEIGHT-1); ray r = cam.get_ray(u, v); pixel_colour += ray_colour(r, world, MAX_DEPTH); } // TODO: we should instead write our output to some buffer in memory // to decouple our ultimate output from our rendering //write_colour_to_stream(std::cout, pixel_colour, SAMPLES_PER_PIXEL); write_colour_to_socket(client_sock, pixel_colour, SAMPLES_PER_PIXEL); } } } int main() { int sockfd; int newsockfd = wait_for_client(sockfd); printf("got a connection!\n"); send_image_dimensions(newsockfd, WIDTH, HEIGHT); //std::cout << "P3\n" << WIDTH << ' ' << HEIGHT << "\n255\n"; hittable_list world = random_scene(); auto dist_to_target = 10.0; auto dist_to_focus = dist_to_target + 1.0; auto cam_y = 1.0; point3 lookfrom(0,cam_y,-dist_to_target); point3 lookat(0,0,0); vec3 vup(0,1,0); auto aperture = 0.5; camera cam(lookfrom, lookat, vup, 47, ASPECT_RATIO, aperture, dist_to_focus); render(cam, world, newsockfd); // close client socket close(newsockfd); printf("closed client connection\n"); // close listening socket close(sockfd); printf("closed listening socket\n"); printf("done!\n"); return 0; }