canvas.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /*
  2. * DoRayMe - a quick and dirty Raytracer
  3. * Canvas implementation
  4. *
  5. * Created by Manoël Trapier
  6. * Copyright (c) 2020 986-Studio.
  7. *
  8. */
  9. #include <canvas.h>
  10. #include <lodepng.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. /* NanoJPEG is a bit interesting to include as a header */
  15. extern "C" {
  16. #define _NJ_INCLUDE_HEADER_ONLY
  17. #include <nanojpeg.c>
  18. #undef _NJ_INCLUDE_HEADER_ONLY
  19. }
  20. #define BPP (24)
  21. #define BytePP (BPP / 8)
  22. #define MIN(_a, _b) ((_a)<(_b)?(_a):(_b))
  23. #define MAX(_a, _b) ((_a)>(_b)?(_a):(_b))
  24. Canvas::Canvas(uint32_t width, uint32_t height) : width(width), height(height)
  25. {
  26. this->bitmap = (uint8_t *)calloc(4, width * height);
  27. this->stride = BytePP * width;
  28. }
  29. Canvas::Canvas(const Canvas &b)
  30. {
  31. this->width = b.width;
  32. this->height = b.height;
  33. this->stride = b.stride;
  34. this->bitmap = (uint8_t *)calloc(4, b.width * b.height);
  35. memcpy(this->bitmap, b.bitmap, 4 * b.width * b.height);
  36. }
  37. Canvas::Canvas(const Canvas *b)
  38. {
  39. this->width = b->width;
  40. this->height = b->height;
  41. this->stride = b->stride;
  42. this->bitmap = (uint8_t *)calloc(4, b->width * b->height);
  43. memcpy(this->bitmap, b->bitmap, 4 * b->width * b->height);
  44. }
  45. Canvas::Canvas(const char *imgfile)
  46. {
  47. /* Try to determine the file type in a really lazy way */
  48. const char *fileExt = strrchr(imgfile, '.');
  49. this->bitmap = NULL;
  50. if (fileExt == NULL)
  51. {
  52. printf("ERROR: Invalid file name '%s' - Can't determine the file format\n", imgfile);
  53. }
  54. else if (strncasecmp(fileExt, ".png", strlen(fileExt)) == 0)
  55. {
  56. uint32_t ret = lodepng_decode24_file(&this->bitmap, &this->width, &this->height, imgfile);
  57. if (ret)
  58. {
  59. printf("ERROR: %s\n", lodepng_error_text(ret));
  60. }
  61. }
  62. else if ( (strncasecmp(fileExt, ".jpg", strlen(fileExt)) == 0) || (strncasecmp(fileExt, ".jpeg", strlen(fileExt)) == 0) )
  63. {
  64. FILE *fp;
  65. char *fileBuff;
  66. size_t fileSize;
  67. fp = fopen(imgfile, "rb");
  68. if (fp)
  69. {
  70. fseek(fp, 0, SEEK_END);
  71. fileSize = ftell(fp);
  72. fileBuff = (char *)calloc(fileSize, 1);
  73. fseek(fp, 0, SEEK_SET);
  74. fileSize = fread(fileBuff, 1, fileSize, fp);
  75. fclose(fp);
  76. njInit();
  77. if (!njDecode(fileBuff, fileSize))
  78. {
  79. this->width = njGetWidth();
  80. this->height = njGetHeight();
  81. /* Need to do a local copy */
  82. this->bitmap = (uint8_t *)calloc(1, njGetImageSize());
  83. memcpy(this->bitmap, njGetImage(), njGetImageSize());
  84. }
  85. else
  86. {
  87. printf("ERROR: Error while decoding the file '%s'\n", imgfile);
  88. }
  89. free(fileBuff);
  90. njDone();
  91. }
  92. else
  93. {
  94. printf("ERROR: Can't open/find the file '%s'.\n", imgfile);
  95. }
  96. }
  97. else
  98. {
  99. printf("ERROR: File extention '%s' is not a recognized one.\n", fileExt);
  100. }
  101. if (this->bitmap == NULL)
  102. {
  103. printf("ABORT: Opening image file '%s' failed\n", imgfile);
  104. exit(-1);
  105. }
  106. this->stride = BytePP * width;
  107. }
  108. Canvas::~Canvas()
  109. {
  110. if (this->bitmap != nullptr)
  111. {
  112. free(this->bitmap);
  113. }
  114. }
  115. void Canvas::putPixel(uint32_t x, uint32_t y, Tuple c)
  116. {
  117. uint32_t offset = y * this->stride + x * BytePP;
  118. this->bitmap[offset + 0] = MAX(MIN(c.x * 255, 255), 0);
  119. this->bitmap[offset + 1] = MAX(MIN(c.y * 255, 255), 0);
  120. this->bitmap[offset + 2] = MAX(MIN(c.z * 255, 255), 0);
  121. }
  122. Colour Canvas::getPixel(uint32_t x, uint32_t y)
  123. {
  124. uint32_t offset = y * this->stride + x * BytePP;
  125. return Colour(this->bitmap[offset + 0] / 255.0, this->bitmap[offset + 1] / 255.0, this->bitmap[offset + 2] / 255.0);
  126. }
  127. bool Canvas::SaveAsPNG(const char *filename)
  128. {
  129. uint32_t ret = lodepng_encode24_file(filename, this->bitmap, this->width, this->height);
  130. return ret == 0;
  131. }