diff --git a/src/colour.h b/src/colour.h index 1347b08..35ea3c8 100755 --- a/src/colour.h +++ b/src/colour.h @@ -2,22 +2,62 @@ #include "rtweekend.h" +// for writing to stdout #include -void write_colour(std::ostream &out, colour pixel_colour, int samples_per_pixel) -{ - auto r = pixel_colour.x(); - auto g = pixel_colour.y(); - auto b = pixel_colour.z(); +// for writing to socket +#include - // divide the colour total by the number of samples and gamme-correct for gamma=2.0 - auto scale = 1.0 / samples_per_pixel; +void correct_gamma(colour& pixel_colour, int samples) +{ + double r = pixel_colour.x(); + double g = pixel_colour.y(); + double b = pixel_colour.z(); + + // divide the colour total by the number of samples and gamma-correct for gamma=2.0 + auto scale = 1.0 / samples; r = sqrt(scale * r); g = sqrt(scale * g); b = sqrt(scale * b); + + pixel_colour = colour(r, g, b); +} + +void write_colour_to_stream(std::ostream &out, colour pixel_colour, int samples_per_pixel) +{ + correct_gamma(pixel_colour, samples_per_pixel); + + auto r = pixel_colour.x(); + auto g = pixel_colour.y(); + auto b = pixel_colour.z(); // write the translated [0,255] value of each colour component. out << static_cast(256 * clamp(r, 0.0, 0.999)) << ' ' << static_cast(256 * clamp(g, 0.0, 0.999)) << ' ' << static_cast(256 * clamp(b, 0.0, 0.999)) << '\n'; } + +int format_component(double component) +{ + return int(256 * clamp(component, 0.0, 0.999)); +} + +void write_colour_to_socket(int sockfd, colour pixel_colour, int samples_per_pixel) +{ + correct_gamma(pixel_colour, samples_per_pixel); + + int r = format_component(pixel_colour.x()); + int g = format_component(pixel_colour.y()); + int b = format_component(pixel_colour.z()); + + // pack values + int len = 3; + char s[len]; + sprintf(s, "%c%c%c", r, g, b); + + int written = write(sockfd, s, len); + if (written < 0) + { + error("ERROR writing colour to socket"); + } +} diff --git a/src/main.cpp b/src/main.cpp index b1c16cf..03ecd07 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,6 +2,13 @@ #include "hittable_list.h" #include "sphere.h" + +void error(const char* message) +{ + perror(message); + exit(1); +} + #include "colour.h" #include "camera.h" #include "material.h" @@ -15,9 +22,9 @@ #include #include -const double ASPECT_RATIO = 16.0 / 9.0; -const int WIDTH = 1920; -const int HEIGHT = static_cast(WIDTH / ASPECT_RATIO); +const double ASPECT_RATIO = 1.0; +const unsigned int WIDTH = 256; +const unsigned int HEIGHT = static_cast(WIDTH / ASPECT_RATIO); const int SAMPLES_PER_PIXEL = 8; const int MAX_DEPTH = 5; @@ -119,12 +126,6 @@ hittable_list random_scene() return world; } -void error(const char* message) -{ - perror(message); - exit(1); -} - // file descriptor of the socket we're listening for connections on // // returns fd for the client connection @@ -162,6 +163,18 @@ int wait_for_client(int& sockfd) 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) { @@ -185,6 +198,24 @@ void send_message(int sock, const char* message) 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"); + } +} + int main() { int sockfd; @@ -192,20 +223,9 @@ int main() printf("got a connection!\n"); - // write a message to the client - send_message(newsockfd, "hi there!"); + send_image_dimensions(newsockfd, WIDTH, HEIGHT); - // close client socket - close(newsockfd); - - printf("closed client connection\n"); - - // close listening socket - close(sockfd); - // exit after all our connections are closed - exit(0); - - std::cout << "P3\n" << WIDTH << ' ' << HEIGHT << "\n255\n"; + //std::cout << "P3\n" << WIDTH << ' ' << HEIGHT << "\n255\n"; hittable_list world = random_scene(); @@ -234,10 +254,23 @@ int main() pixel_colour += ray_colour(r, world, MAX_DEPTH); } - write_colour(std::cout, pixel_colour, SAMPLES_PER_PIXEL); + //write_colour_to_stream(std::cout, pixel_colour, SAMPLES_PER_PIXEL); + write_colour_to_socket(newsockfd, pixel_colour, SAMPLES_PER_PIXEL); } } - std::cerr << "\nDone." << std::endl; + // 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; } diff --git a/telescope.md b/telescope.md index 3574d23..06a0a59 100644 --- a/telescope.md +++ b/telescope.md @@ -6,8 +6,8 @@ use rti1w as a base * [x] client establishes connection * [x] send a message to the client * [ ] move rendering out of main.cpp -* [ ] send rendered image data to client -* [ ] form image file on client +* [x] send rendered image data to client +* [x] form image file on client * [ ] client sends receiving port to server * [ ] client application sends command to send image * [ ] server receives imaging command