diff --git a/source/canvas.cpp b/source/canvas.cpp index a74b77f..208eb46 100644 --- a/source/canvas.cpp +++ b/source/canvas.cpp @@ -107,7 +107,7 @@ Canvas::Canvas(const char *imgfile) } else { - printf("ERROR: Can't opening the file '%s'.\n", imgfile); + printf("ERROR: Can't open/find the file '%s'.\n", imgfile); } } else diff --git a/source/include/objfile.h b/source/include/objfile.h new file mode 100644 index 0000000..8e7067c --- /dev/null +++ b/source/include/objfile.h @@ -0,0 +1,51 @@ +/* + * DoRayMe - a quick and dirty Raytracer + * OBJ File header + * + * Created by Manoël Trapier + * Copyright (c) 2020 986-Studio. + * + */ +#ifndef DORAYME_OBJFILE_H +#define DORAYME_OBJFILE_H + +#include +#include + +class OBJFile : public Shape +{ +private: + uint32_t allocatedFaceGroupCount; + Shape* *faceGroupList; + uint32_t faceGroupCount; + + uint32_t allocatedVertexCount; + Tuple* *vertexList; + uint32_t vertexCount; + + +private: + Intersect localIntersect(Ray r); + Tuple localNormalAt(Tuple point); + +public: + /* Some stats */ + uint32_t ignoredLines; + +protected: + void addGroup(Shape *group); + void addVertex(Tuple *vertex); + + BoundingBox bounds; + +public: + OBJFile(); + OBJFile(const char *filepath); + + int parseOBJFile(const char *content); + + BoundingBox getLocalBounds(); + bool haveFiniteBounds() { return true; }; +}; + +#endif /* DORAYME_OBJFILE_H */ diff --git a/source/include/renderstat.h b/source/include/renderstat.h index ec25060..2611f89 100644 --- a/source/include/renderstat.h +++ b/source/include/renderstat.h @@ -15,13 +15,14 @@ class RenderStats { private: uint64_t coneCount; /* Total number of cones */ - uint64_t cylinderCount; /* Total number of cylinder */ + uint64_t cylinderCount; /* Total number of cylinder */ uint64_t cubeCount; /* Total number of cubes */ uint64_t groupCount; /* Total number of groups */ uint64_t lightCount; /* Total number of light */ uint64_t planeCount; /* Total number of plane */ uint64_t sphereCount; /* Total number of sphere */ - uint64_t triangleCount; /* Total number of triangle */ + uint64_t triangleCount; /* Total number of triangle */ + uint64_t objfileCount; /* Total number of OBJ File */ uint64_t pixelCount; /* Total number of rendered pixels */ uint64_t rayCount; /* Total number of rays */ @@ -40,7 +41,7 @@ public: RenderStats() : coneCount(0), cylinderCount(0), cubeCount(0), groupCount(0), lightCount(0), planeCount(0), sphereCount(0), triangleCount(0), pixelCount(0), rayCount(0), lightRayEmitedCount(0), reflectionRayCount(0), refractedRayCount(0), intersectCount(0), intersectionCount(0), reallocCallCount(0), mallocCallCount(0), - discardedIntersectCount(0), maxDepthAttained(UINT64_MAX), maxIntersectOnARay(0) {}; + discardedIntersectCount(0), maxDepthAttained(UINT64_MAX), maxIntersectOnARay(0), objfileCount(0) {}; #ifdef RENDER_STATS void addCone(); void addCylinder(); @@ -49,6 +50,7 @@ public: void addLight(); void addPlane(); void addSphere(); + void addOBJFile(); void addTriangle(); void printStats(); void addPixel(); @@ -85,6 +87,7 @@ public: static void addMalloc() {}; static void addRealloc() {}; static void setMaxIntersect(uint32_t count) {}; + static void void RenderStats::addOBJFile() {}; #endif }; diff --git a/source/include/shape.h b/source/include/shape.h index 11c6f0c..5087d4d 100644 --- a/source/include/shape.h +++ b/source/include/shape.h @@ -29,7 +29,7 @@ enum ShapeType SHAPE_CONE, SHAPE_GROUP, SHAPE_TRIANGLE, - + SHAPE_OBJFILE, }; /* Base class for all object that can be presented in the world */ diff --git a/source/renderstat.cpp b/source/renderstat.cpp index e9cf0ae..0ecb8f3 100644 --- a/source/renderstat.cpp +++ b/source/renderstat.cpp @@ -61,6 +61,12 @@ void RenderStats::addTriangle() this->triangleCount++; }; +void RenderStats::addOBJFile() +{ +#pragma omp atomic + this->objfileCount++; +}; + void RenderStats::addPixel() { #pragma omp atomic diff --git a/source/shapes/objfile.cpp b/source/shapes/objfile.cpp new file mode 100644 index 0000000..8f2f5c1 --- /dev/null +++ b/source/shapes/objfile.cpp @@ -0,0 +1,145 @@ +/* + * DoRayMe - a quick and dirty Raytracer + * OBJ File implementation + * + * Created by Manoël Trapier + * Copyright (c) 2020 986-Studio. + * + */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define MIN_ALLOC (2) +#define DEFAULT_GROUP (0) + +OBJFile::OBJFile() : Shape(SHAPE_OBJFILE), ignoredLines(0) +{ + stats.addOBJFile(); + + this->allocatedFaceGroupCount = MIN_ALLOC; + this->faceGroupList = (Shape **)calloc(sizeof(Shape *), MIN_ALLOC); + this->faceGroupCount = 0; + + this->allocatedVertexCount = MIN_ALLOC; + this->vertexList = (Tuple **)calloc(sizeof(Tuple *), MIN_ALLOC); + this->vertexCount = 0; + + /* There is always a default group */ + this->addGroup(new Group()); +}; + +OBJFile::OBJFile(const char *filepath) : OBJFile() +{ + FILE *fp; + size_t fileSize; + char *fileBuff; + fp = fopen(filepath, "rt"); + if (fp) + { + fseek(fp, 0, SEEK_END); + fileSize = ftell(fp); + fileBuff = (char *)calloc(fileSize, 1); + fseek(fp, 0, SEEK_SET); + fileSize = fread(fileBuff, 1, fileSize, fp); + fclose(fp); + + this->parseOBJFile(fileBuff); + + free(fileBuff); + } + else + { + printf("ERROR: Can't open/find the file '%s'.\n", filepath); + } +} + +void OBJFile::addGroup(Shape *group) +{ + if ((this->faceGroupCount + 1) > this->allocatedFaceGroupCount) + { + this->allocatedFaceGroupCount *= 2; + this->faceGroupList = (Shape **)realloc(this->faceGroupList, sizeof(Shape **) * this->allocatedFaceGroupCount); + } + + group->parent = this; + group->updateTransform(); + + this->faceGroupList[this->faceGroupCount++] = group; + + this->bounds | group->getBounds(); +} + +void OBJFile::addVertex(Tuple *vertex) +{ + if ((this->vertexCount + 1) > this->allocatedVertexCount) + { + this->allocatedVertexCount *= 2; + this->vertexList = (Tuple **)realloc(this->vertexList, sizeof(Tuple **) * this->allocatedVertexCount); + } + + this->vertexList[this->vertexCount++] = vertex; +} + +Intersect OBJFile::localIntersect(Ray r) +{ + +} + +Tuple OBJFile::localNormalAt(Tuple point) +{ + +} + +BoundingBox OBJFile::getLocalBounds() +{ + +} + +#define MAX_LINE_LENGTH (512) +/* Here start the fun! */ +int OBJFile::parseOBJFile(const char *content) +{ + /* I don't think we will handle lines of more than 512 characters... */ + char lineBuff[MAX_LINE_LENGTH]; + uint32_t currentLineNum = 1; + + /* Need to process line by line */ + const char *bufferPos = content; + const char *lineNewline; + while(*bufferPos != '\0') + { + uint32_t lineLength; + lineNewline = strchr(bufferPos, '\n'); + if (lineNewline == nullptr) + { + /* We are on the last line */ + lineLength = strlen(bufferPos); + } + else + { + lineLength = (lineNewline - bufferPos); + } + if (lineLength >= MAX_LINE_LENGTH) + { + printf("ERROR: Line %d is too long! (%d)\n", currentLineNum); + } + memset(lineBuff, 0, MAX_LINE_LENGTH); + strncpy(lineBuff, bufferPos, lineLength); + + printf("line %d = %s\n", currentLineNum, lineBuff); + + bufferPos += lineLength + 1; + currentLineNum++; + } + + + +} \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 34b7731..ec28128 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -10,7 +10,7 @@ link_libraries(rayonnement) set(TESTS_SRC math_test.cpp tuple_test.cpp colour_test.cpp canvas_test.cpp matrix_test.cpp transformation_test.cpp ray_test.cpp intersect_test.cpp sphere_test.cpp light_test.cpp material_test.cpp world_test.cpp camera_test.cpp shape_test.cpp plane_test.cpp pattern_test.cpp cube_test.cpp cylinder_test.cpp cone_test.cpp group_test.cpp - boundingbox_test.cpp triangle_test.cpp sequence_test.cpp) + boundingbox_test.cpp triangle_test.cpp sequence_test.cpp objfile_test.cpp) add_executable(testMyRays) target_include_directories(testMyRays PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) @@ -100,6 +100,25 @@ add_custom_command( TARGET uvmap_earth POST_BUILD COMMAND convert ${CMAKE_SOURCE_DIR}/external/earthmap1k.jpg ${CMAKE_CURRENT_BINARY_DIR}/earthmap1k.png) +add_executable(uvmap_skybox) +target_sources(uvmap_skybox PRIVATE uvmap_skybox.cpp) +file(DOWNLOAD + http://www.humus.name/Textures/LancellottiChapel.zip + ${CMAKE_SOURCE_DIR}/external/LancellottiChapel.zip + EXPECTED_HASH MD5=cd16610b00a4ace6baf1f0aff80f5685 + ) +add_custom_command( + TARGET uvmap_skybox POST_BUILD + COMMAND unzip -o ${CMAKE_SOURCE_DIR}/external/LancellottiChapel.zip -d LancellottiChapel + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/external/ +) +add_custom_command( + TARGET uvmap_skybox POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_SOURCE_DIR}/external/LancellottiChapel/*.jpg + ${CMAKE_CURRENT_BINARY_DIR}/ +) + add_test(NAME Chapter05_Test COMMAND $) add_test(NAME Chapter06_Test COMMAND $) add_test(NAME Chapter07_Test COMMAND $) @@ -119,6 +138,7 @@ add_test(NAME UVMap_CheckeredCylinder COMMAND $) add_test(NAME UVMap_CheckeredCube COMMAND $) add_test(NAME UVMap_Earth COMMAND $) +add_test(NAME UVMap_Skybox COMMAND $) add_test(NAME Test_Rendering COMMAND $) add_test(NAME Triangle_RenderTest COMMAND $) add_test(NAME ChristmasBall_Rendering COMMAND $) diff --git a/tests/objfile_test.cpp b/tests/objfile_test.cpp new file mode 100644 index 0000000..57a13a7 --- /dev/null +++ b/tests/objfile_test.cpp @@ -0,0 +1,25 @@ +/* + * DoRayMe - a quick and dirty Raytracer + * OBJ File unit tests + * + * Created by Manoël Trapier + * Copyright (c) 2020 986-Studio. + * + */ +#include +#include +#include + +TEST(OBJFileTest, Ignoring_unrecognised_lines) +{ + const char gibberish[] = "There was a young lane named Bright\n" + "who traveled much faster than light\n" + "She set out one day\n" + "in a relative way\n" + "and came back the previous night.\n"; + + OBJFile parser = OBJFile(); + parser.parseOBJFile(gibberish); + + ASSERT_EQ(parser.ignoredLines, 5); +} \ No newline at end of file