diff --git a/.gitignore b/.gitignore index 7a0338c..128c608 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /RT compile_flags.txt imgui.ini +/output* diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index abe297a..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "files.associations": { - "*.cs": "csharp", - "atomic": "cpp", - "bit": "cpp", - "cctype": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "compare": "cpp", - "concepts": "cpp", - "cstddef": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "exception": "cpp", - "initializer_list": "cpp", - "ios": "cpp", - "iosfwd": "cpp", - "iostream": "cpp", - "istream": "cpp", - "iterator": "cpp", - "limits": "cpp", - "memory": "cpp", - "new": "cpp", - "ostream": "cpp", - "stdexcept": "cpp", - "streambuf": "cpp", - "system_error": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "typeinfo": "cpp", - "utility": "cpp", - "xfacet": "cpp", - "xiosbase": "cpp", - "xlocale": "cpp", - "xlocinfo": "cpp", - "xlocnum": "cpp", - "xmemory": "cpp", - "xstddef": "cpp", - "xstring": "cpp", - "xtr1common": "cpp", - "xutility": "cpp", - "array": "cpp", - "vector": "cpp", - "deque": "cpp", - "string_view": "cpp", - "span": "cpp", - "*.tcc": "cpp", - "chrono": "cpp", - "string": "cpp", - "unordered_map": "cpp", - "unordered_set": "cpp", - "memory_resource": "cpp", - "optional": "cpp", - "format": "cpp", - "functional": "cpp", - "sstream": "cpp", - "variant": "cpp", - "charconv": "cpp", - "cstdarg": "cpp", - "cwctype": "cpp", - "map": "cpp", - "set": "cpp", - "algorithm": "cpp", - "numeric": "cpp", - "random": "cpp", - "ratio": "cpp", - "iomanip": "cpp", - "numbers": "cpp", - "cinttypes": "cpp", - "fstream": "cpp", - "list": "cpp", - "locale": "cpp", - "xhash": "cpp", - "xlocbuf": "cpp", - "xlocmes": "cpp", - "xlocmon": "cpp", - "xloctime": "cpp", - "xtree": "cpp", - "forward_list": "cpp" - }, - "cmake.ignoreCMakeListsMissing": true -} \ No newline at end of file diff --git a/Makefile b/Makefile index 7635c57..4cb0d8d 100644 --- a/Makefile +++ b/Makefile @@ -56,6 +56,7 @@ ALL_SRCS := $(IMGUI_SRCS) \ class/ObjParser.cpp \ class/BVH.cpp \ class/Renderer.cpp \ + class/Arguments.cpp SRCS := $(ALL_SRCS:%=$(SRCS_DIR)/%) OBJS := $(addprefix $(OBJS_DIR)/, $(SRCS:%.cpp=%.o)) diff --git a/imgui.ini b/imgui.ini index 633cc90..b3e0d68 100644 --- a/imgui.ini +++ b/imgui.ini @@ -29,6 +29,6 @@ Pos=1556,610 Size=284,382 [Window][Settings] -Pos=1568,11 -Size=336,975 +Pos=83,57 +Size=336,330 diff --git a/includes/RT.hpp b/includes/RT.hpp index 84e906f..c4d695f 100644 --- a/includes/RT.hpp +++ b/includes/RT.hpp @@ -6,7 +6,7 @@ /* By: ycontre +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/09/27 14:52:10 by TheRed #+# #+# */ -/* Updated: 2025/02/03 18:17:48 by ycontre ### ########.fr */ +/* Updated: 2025/02/04 23:39:14 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ @@ -34,6 +34,7 @@ # include # include # include +# include # include # include # include @@ -57,6 +58,7 @@ struct Vertex { # include "objects/Portal.hpp" # include "objects/Cylinder.hpp" +# include "Arguments.hpp" # include "Camera.hpp" # include "Renderer.hpp" # include "Window.hpp" diff --git a/includes/RT/Arguments.hpp b/includes/RT/Arguments.hpp new file mode 100644 index 0000000..f5e4eed --- /dev/null +++ b/includes/RT/Arguments.hpp @@ -0,0 +1,55 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* Arguments.hpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tomoron +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/02/04 01:07:08 by tomoron #+# #+# */ +/* Updated: 2025/02/04 22:04:04 by tomoron ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef ARGUMENTS_HPP +# define ARGUMENTS_HPP + +#include "RT.hpp" + +typedef struct s_arg +{ + char shortName; + std::string longName; + int isFlag; +} t_arg; + +class Arguments +{ + public : + Arguments(int argc, char **argv); + + bool getHeadless(void) const; + bool error(void) const; + void show(void); + + std::string &getSceneName(void); + std::string *getRenderPath(void); + bool getHeadless(void); + + private: + void printUsage(); + + int handleArg(char **argv, int argc, int *i); + void initArguments(void); + void addArgument(char shortName, std::string longName, int isFlag); + int setArg(t_arg arg, char **argv, int argc, int *i); + + void parseRenderPathName(char * path); + + bool _headless; + bool _err; + + std::vector _args; + std::map _values; +}; + +#endif diff --git a/includes/RT/Renderer.hpp b/includes/RT/Renderer.hpp index e180dc3..0e5dcdb 100644 --- a/includes/RT/Renderer.hpp +++ b/includes/RT/Renderer.hpp @@ -6,7 +6,7 @@ /* By: tomoron +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/01/22 16:29:26 by tomoron #+# #+# */ -/* Updated: 2025/01/30 22:15:55 by tomoron ### ########.fr */ +/* Updated: 2025/02/04 23:19:37 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ @@ -36,22 +36,28 @@ typedef struct s_pathPoint class Renderer { public: - Renderer(Scene *scene, Window *win); + Renderer(Scene *scene, Window *win, Arguments &args); void renderImgui(void); void update(Shader &shader); int rendering(void) const; + bool shouldClose(void) const; private: void addPoint(float time); + void init(Scene *scene, Window *win); + void savePath(void); + void rawRead(std::ifstream &file, void *buf, size_t len); + void loadPath(std::string filename); void makeMovement(float timeFromStart, float curSplitTimeReset); void initRender(); void addImageToRender(Shader &shader); void endRender(void); void imguiPathCreation(void); - void imguiRenderInfo(void); - std::string floatToTime(float timef); + void showRenderInfo(int isImgui); + void imguiRenderSettings(void); + std::string floatToTime(double timef); glm::vec2 bezierSphereInterpolate(glm::vec4 control, glm::vec2 from, glm::vec2 to, float time); - void updateAvailableCodecs(void); + void updateAvailableCodecs(int mode, AVCodecID id); void fillGoodCodecList(std::vector &lst); glm::vec3 hermiteInterpolate(glm::vec3 points[4], double alpha); @@ -69,6 +75,11 @@ class Renderer std::vector _codecList; std::vector _codecListStr; int _codecIndex; + bool _renderSettings; + bool _ignoreUnavailableCodec; + bool _headless; + bool _tp; + bool _shouldClose; int _curPathIndex; int _destPathIndex; diff --git a/includes/RT/Scene.hpp b/includes/RT/Scene.hpp index 7e78db4..700399c 100644 --- a/includes/RT/Scene.hpp +++ b/includes/RT/Scene.hpp @@ -6,7 +6,7 @@ /* By: ycontre +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/12/23 18:30:18 by ycontre #+# #+# */ -/* Updated: 2025/01/28 19:05:16 by ycontre ### ########.fr */ +/* Updated: 2025/02/04 03:11:36 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ @@ -105,11 +105,9 @@ class Camera; class Scene { public: - Scene(); + Scene(std::string &name); ~Scene(); - bool parseScene(char *name); - void addObject(Object *object); void addMaterial(Material *material); void addTexture(std::string path); @@ -141,7 +139,11 @@ class Scene Camera *getCamera(void) const; GPUMaterial getMaterial(int material_index); + bool fail(void) const; + private: + + bool _fail; std::vector _gpu_bvh_data; std::vector _gpu_bvh; diff --git a/includes/RT/SceneParser.hpp b/includes/RT/SceneParser.hpp index 59cdc0a..d5932e6 100644 --- a/includes/RT/SceneParser.hpp +++ b/includes/RT/SceneParser.hpp @@ -6,7 +6,7 @@ /* By: TheRed +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/12/26 21:37:37 by TheRed #+# #+# */ -/* Updated: 2025/01/21 15:15:13 by tomoron ### ########.fr */ +/* Updated: 2025/02/04 01:21:28 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ @@ -18,7 +18,7 @@ class SceneParser { public: - SceneParser(Scene *scene, char *filename); + SceneParser(Scene *scene, std::string filename); bool parseLine(const std::string &line); diff --git a/includes/RT/Window.hpp b/includes/RT/Window.hpp index 72cbb6a..4c654d1 100644 --- a/includes/RT/Window.hpp +++ b/includes/RT/Window.hpp @@ -6,7 +6,7 @@ /* By: ycontre +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/10/13 16:15:41 by TheRed #+# #+# */ -/* Updated: 2025/01/25 03:09:23 by tomoron ### ########.fr */ +/* Updated: 2025/02/04 16:46:37 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ @@ -20,7 +20,7 @@ class Scene; class Window { public: - Window(Scene *scene, int width, int height, const char *title, int sleep); + Window(Scene *scene, int width, int height, const char *title, int sleep, Arguments &args); ~Window(void); void display(); diff --git a/scenes/lambo.rt b/scenes/lambo.rt index eb4dc9a..19c8f89 100644 --- a/scenes/lambo.rt +++ b/scenes/lambo.rt @@ -19,7 +19,7 @@ cu 0 10 0 5 5 5 3 sp 0 10 0 1 4 -OBJ scenes/obj/lambo.obj 0 1.5 0 1 0 0 0 +OBJ obj/lambo.obj 0 1.5 0 1 0 0 0 diff --git a/srcs/RT.cpp b/srcs/RT.cpp index 964f009..2408ad9 100644 --- a/srcs/RT.cpp +++ b/srcs/RT.cpp @@ -6,7 +6,7 @@ /* By: ycontre +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/09/27 14:51:49 by TheRed #+# #+# */ -/* Updated: 2025/01/30 22:29:00 by tomoron ### ########.fr */ +/* Updated: 2025/02/04 22:10:33 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ @@ -14,15 +14,16 @@ int main(int argc, char **argv) { - Scene scene; - - if (argc <= 1 || !scene.parseScene(argv[1])) - return (1); - - Window window(&scene, WIDTH, HEIGHT, "RT_GPU", 0); + Arguments args(argc, argv); + if(args.error()) + return(1); + Scene scene(args.getSceneName()); + if(scene.fail()) + return(1); + Window window(&scene, WIDTH, HEIGHT, "RT_GPU", 0, args); Shader shader("shaders/vertex.vert", "shaders/frag.frag", "shaders/compute.glsl"); // Shader shader("shaders/vertex.vert", "shaders/frag.frag", "shaders/debug.glsl"); - + GLint max_gpu_size; glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &max_gpu_size); diff --git a/srcs/class/Arguments.cpp b/srcs/class/Arguments.cpp new file mode 100644 index 0000000..0f7e7cf --- /dev/null +++ b/srcs/class/Arguments.cpp @@ -0,0 +1,163 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* Arguments.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tomoron +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/02/04 01:05:44 by tomoron #+# #+# */ +/* Updated: 2025/02/04 22:17:04 by tomoron ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "RT.hpp" + +Arguments::Arguments(int argc, char **argv) +{ + initArguments(); + _headless = 0; + _err = 0; + + if(argc <= 1) + { + _err = 1; + printUsage(); + return ; + } + + for(int i = 1; i < argc; i++) + { + if(!handleArg(argv, argc, &i)) + { + _err = 1; + return ; + } + } + if(_values.find("sceneName") == _values.end()) + { + std::cerr << "missing scene name" << std::endl; + _err = 1; + } +} + +void Arguments::initArguments() +{ + addArgument('r', "renderpath", 0); + addArgument('h', "headless", 1); +} + +void Arguments::printUsage(void) +{ + std::cerr << "usage : [options] [options]" << std::endl; + std::cerr << R""""(options : + -r | --renderpath : filename for the renderer path + -h | --headless : does the program need to start rendering as soon as it starts(and close automatically) +)""""; +} + +void Arguments::show(void) +{ + for(std::map::iterator it = _values.begin();it != _values.end(); it++) + std::cout << (*it).first << ": " << (*it).second << std::endl; +} + +bool Arguments::error(void) const +{ + return(_err); +} + + +std::string &Arguments::getSceneName(void) +{ + return(_values["sceneName"]); +} + +std::string *Arguments::getRenderPath(void) +{ + if(_values.find("renderpath") != _values.end()) + return(&_values["renderpath"]); + else + return(0); +} + +bool Arguments::getHeadless(void) +{ + return(_values.find("headless") != _values.end()); +} + + +void Arguments::addArgument(char shortName, std::string longName, int isFlag) +{ + t_arg arg; + + arg.shortName = shortName; + arg.longName = longName; + arg.isFlag = isFlag; + _args.push_back(arg); +} + +int Arguments::setArg(t_arg arg, char **argv, int argc, int *i) +{ + + if(arg.isFlag) + _values[arg.longName] = "yes"; + else if(*i == argc - 1) + { + std::cerr << "missing option for " << arg.longName << std::endl; + return(0); + } + else + _values[arg.longName] = argv[++(*i)]; + return(1); +} + +int Arguments::handleArg(char **argv, int argc, int *i) +{ + std::string arg(argv[*i]); + std::vector::iterator it; + + (void)i; + if(!arg.size()) + return(1); + if(arg.size() >= 2 && arg[0] == '-' && arg[1] == '-') + { + for(std::vector::iterator it = _args.begin(); it != _args.end(); it++) + { + if((*it).longName == arg.substr(2)) + return(setArg((*it), argv, argc, i)); + } + std::cerr<< "unrecognized option : " << arg << std::endl; + return(0); + } + else if(arg[0] == '-') + { + for(size_t j = 1; j < arg.size(); j++) + { + for(it = _args.begin(); it != _args.end(); it++) + { + if((*it).shortName == arg[j]) + { + if(!setArg((*it), argv, argc, i)) + return(0); + break; + } + } + if(it == _args.end()) + { + std::cerr << "unrecognized option : -" << arg[j] << std::endl; + return(0); + } + } + } + else + { + if(_values.find("sceneName") == _values.end()) + _values["sceneName"] = arg; + else + { + std::cerr << "unrecognized option : " << arg << std::endl; + return(0); + } + } + return(1); +} diff --git a/srcs/class/Renderer.cpp b/srcs/class/Renderer.cpp index d90692e..70c7771 100644 --- a/srcs/class/Renderer.cpp +++ b/srcs/class/Renderer.cpp @@ -6,25 +6,60 @@ /* By: tomoron +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/01/22 16:34:53 by tomoron #+# #+# */ -/* Updated: 2025/01/30 22:22:07 by tomoron ### ########.fr */ +/* Updated: 2025/02/04 23:42:00 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ #include "RT.hpp" -Renderer::Renderer(Scene *scene, Window *win) +Renderer::Renderer(Scene *scene, Window *win, Arguments &args) +{ + std::string *renderPath; + + init(scene, win); + _headless = args.getHeadless(); + renderPath = args.getRenderPath(); + if(renderPath) + { + try + { + loadPath(*renderPath); + } + catch (std::exception &e) + { + std::cout << e.what() << std::endl; + _shouldClose = 1; + } + } + + try{ + if(_headless) + initRender(); + } + catch(std::exception &e) + { + std::cerr << "\033[31m" << e.what() << "\033[0m" << std::endl; + if(_headless) + _shouldClose = 1; + } +} + +void Renderer::init(Scene *scene, Window *win) { _scene = scene; _win = win; _min = 0; _sec = 0; _fps = 30; + _tp = 0; + _shouldClose = 0; _autoTime = 0; _samples = 1; _testSamples = 1; _curSamples = 0; _destPathIndex = 0; _frameCount = 0; + _renderSettings = 0; _outputFilename = "output.avi"; memcpy(_filenameBuffer, _outputFilename.c_str(), _outputFilename.length()); _filenameBuffer[_outputFilename.length()] = 0; @@ -33,7 +68,96 @@ Renderer::Renderer(Scene *scene, Window *win) _yuv_frame = 0; _format = 0; _codec_context = 0; - updateAvailableCodecs(); + _ignoreUnavailableCodec = 0; + updateAvailableCodecs(_ignoreUnavailableCodec, (AVCodecID)0); +} + +void Renderer::rawRead(std::ifstream &file, void *buf, size_t len) +{ + file.read((char *)buf, len); + if(file.fail()) + throw std::runtime_error("syntax error in path file"); +} + +/* path file format (bytes): + * - output file name (terminated by a \0) + * - codec id + * - samples per image + * - fps + * - path nodes (until the end) + */ +void Renderer::savePath(void) +{ + std::ofstream outputFile; + const AVCodec *codec; + (void)codec; + + codec = _codecList[_codecIndex]; + outputFile.open("output.path", std::ios::binary); + if(!outputFile.is_open()) + std::cerr << "could open output.path for writing" << std::endl; + outputFile.write(_outputFilename.c_str(), _outputFilename.length() + 1); + outputFile.write((char *)&codec->id, sizeof(codec->id)); + outputFile.write((char *)&_samples, sizeof(_samples)); + outputFile.write((char *)&_fps, sizeof(_fps)); + for(std::vector::iterator it = _path.begin(); it != _path.end(); it++) + { + outputFile.write((char *)&(*it), sizeof(t_pathPoint)); + } + outputFile.close(); +} + + +void Renderer::loadPath(std::string filename) +{ + std::ifstream file; + AVCodecID codecId; + t_pathPoint pathPoint; + std::vector::iterator pos; + char c; + + _outputFilename = ""; + _filenameBuffer[0] = 0; + file.open(filename); + if(!file.is_open()) + std::cerr << "failed to open " << filename << std::endl; + c = 1; + while(c) + { + rawRead(file, &c, 1); + if(c && c < 32 && c > 126) + throw std::runtime_error("invalid char in filename"); + if(c) + _outputFilename += c; + } + memcpy(_filenameBuffer, _outputFilename.c_str(), _outputFilename.length()); + _filenameBuffer[_outputFilename.length()] = 0; + rawRead(file, &codecId, sizeof(codecId)); + updateAvailableCodecs(2, codecId); + if(_codecList.size() == 0) + throw std::runtime_error("codec not available"); + rawRead(file, &_samples, sizeof(_samples)); + rawRead(file, &_fps, sizeof(_fps)); + if(_samples < 1 || _fps < 1 || _samples >= 1000 || _fps >= 120) + throw std::runtime_error("invalid value provided in fps or samples"); + while(file.peek() != EOF) + { + rawRead(file, &pathPoint, sizeof(t_pathPoint)); + if(pathPoint.time < .0f) + throw std::runtime_error("invalid time provided in path"); + pos = _path.begin(); + while(pos != _path.end() && pos->time <= pathPoint.time) + pos++; + _path.insert(pos, pathPoint); + } + if(_path.size() < 2) + throw std::runtime_error("not enough path points provided in the path"); + file.close(); +} + +bool Renderer::shouldClose(void) const +{ + return(_shouldClose); } void Renderer::fillGoodCodecList(std::vector &lst) @@ -46,7 +170,12 @@ void Renderer::fillGoodCodecList(std::vector &lst) lst.push_back(AV_CODEC_ID_V210); } -void Renderer::updateAvailableCodecs(void) +/* modes : + * 0 : adds only supported codecs are showed + * 1 : adds all codecs + * 2 : adds only codec + */ +void Renderer::updateAvailableCodecs(int mode, AVCodecID id) { const AVCodec *codec; AVCodecContext *ctx; @@ -69,6 +198,11 @@ void Renderer::updateAvailableCodecs(void) codec = avcodec_find_encoder(*it); if(!codec) continue; + if (mode == 1 || (mode == 2 && codec->id == id)) + { + _codecList.push_back(codec); + continue; + } ctx = avcodec_alloc_context3(codec); if(ctx) { @@ -95,6 +229,12 @@ void Renderer::updateAvailableCodecs(void) void Renderer::initRender(void) { + if(_path.size() < 2) + throw std::runtime_error("render path doesn't have enough path points"); + if(_path[0].time != 0) + throw std::runtime_error("render path does not start at 0, aborting"); + if(_path[_path.size() - 1].time - _path[0].time <= 0) + throw std::runtime_error("render path is 0 seconds long, aborting"); _codecOptions = 0; _destPathIndex = _path.size() - 1; @@ -106,7 +246,7 @@ void Renderer::initRender(void) _renderStartTime = glfwGetTime(); _scene->getCamera()->setPosition(_path[0].pos); _scene->getCamera()->setDirection(_path[0].dir.x, _path[0].dir.y); - _win->setFrameCount(-1); + _win->setFrameCount(_headless ? 0 : -1); avformat_alloc_output_context2(&_format, nullptr, nullptr, _outputFilename.c_str()); _codec_context = avcodec_alloc_context3(_codecList[_codecIndex]); @@ -124,18 +264,27 @@ void Renderer::initRender(void) _codec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; if (avcodec_open2(_codec_context, _codecList[_codecIndex], &_codecOptions) < 0) + { + endRender(); throw std::runtime_error("Failed to open codec"); + } _stream = avformat_new_stream(_format, _codecList[_codecIndex]); if (!_stream) + { + endRender(); throw std::runtime_error("Failed to create stream"); + } _stream->time_base = _codec_context->time_base; avcodec_parameters_from_context(_stream->codecpar, _codec_context); if (!(_format->flags & AVFMT_NOFILE)) { if (avio_open(&_format->pb, _outputFilename.c_str(), AVIO_FLAG_WRITE) < 0) + { + endRender(); throw std::runtime_error("couldn't open " + _outputFilename); + } } (void)avformat_write_header(_format, nullptr); @@ -203,29 +352,42 @@ void Renderer::endRender(void) { AVPacket *pkt; - avcodec_send_frame(_codec_context, 0); - pkt = av_packet_alloc(); - while (avcodec_receive_packet(_codec_context, pkt) == 0) { - pkt->stream_index = _stream->index; - pkt->pts = av_rescale_q(pkt->pts, _codec_context->time_base, _stream->time_base); - pkt->dts = av_rescale_q(pkt->dts, _codec_context->time_base, _stream->time_base); - av_interleaved_write_frame(_format, pkt); - av_packet_unref(pkt); + if(_codec_context) + { + avcodec_send_frame(_codec_context, 0); + pkt = av_packet_alloc(); + while (avcodec_receive_packet(_codec_context, pkt) == 0) { + pkt->stream_index = _stream->index; + pkt->pts = av_rescale_q(pkt->pts, _codec_context->time_base, _stream->time_base); + pkt->dts = av_rescale_q(pkt->dts, _codec_context->time_base, _stream->time_base); + av_interleaved_write_frame(_format, pkt); + av_packet_unref(pkt); + } } av_packet_free(&pkt); - av_write_trailer(_format); - av_frame_free(&_rgb_frame); - av_frame_free(&_yuv_frame); - avcodec_free_context(&_codec_context); - avio_close(_format->pb); - avformat_free_context(_format); - av_dict_free(&_codecOptions); + if(_format) + av_write_trailer(_format); + if(_rgb_frame) + av_frame_free(&_rgb_frame); + if(_yuv_frame) + av_frame_free(&_yuv_frame); + if(_codec_context) + avcodec_free_context(&_codec_context); + if(_format) + avio_close(_format->pb); + if(_format) + avformat_free_context(_format); + if(_codecOptions) + av_dict_free(&_codecOptions); _format = 0; _rgb_frame = 0; _yuv_frame = 0; _codec_context = 0; + _destPathIndex = 0; + if(_headless) + _shouldClose = 1; } void Renderer::addPoint(float time) @@ -248,11 +410,13 @@ void Renderer::update(Shader &shader) { double curTime; - (void)shader; if(!_destPathIndex) return; _curSamples++; + if(_headless) + showRenderInfo(0); + if((_testMode && _curSamples < _testSamples) || (!_testMode && _curSamples < _samples)) return; @@ -268,6 +432,7 @@ void Renderer::update(Shader &shader) } makeMovement(curTime - _curSplitStart, curTime); _curSamples = 0; + } glm::vec3 Renderer::hermiteInterpolate(glm::vec3 points[4], double alpha) @@ -442,15 +607,9 @@ void Renderer::imguiPathCreation(void) prevSpeed = 0; ImGui::SliderInt("test spi", &_testSamples, 1, 10); - ImGui::SliderInt("render spi", &_samples, 1, 1000); - ImGui::SliderInt("render fps", &_fps, 30, 120); - ImGui::Combo("codec", &_codecIndex, _codecListStr.data(), _codecListStr.size()); - if(ImGui::InputText("file name", _filenameBuffer, 512)) - { - _outputFilename = _filenameBuffer; - updateAvailableCodecs(); - } + if(ImGui::Button("render settings")) + _renderSettings = 1; if(_path.size() > 1 && ImGui::Button("try full path")) { _scene->getCamera()->setPosition(_path[0].pos); @@ -461,30 +620,52 @@ void Renderer::imguiPathCreation(void) _destPathIndex = _path.size() - 1; _testMode = 1; } - if(_path.size() > 1 && _codecList.size() && ImGui::Button("start render")) - initRender(); ImGui::Separator(); if(ImGui::SliderInt("minutes", &_min, 0, 2)) + { _autoTime = 0; + _tp = 0; + } if(ImGui::SliderInt("seconds", &_sec, 0, 60)) + { _autoTime = 0; + _tp = 0; + } if(_autoTime) { if(_path.size() > 1) time = _path[_path.size() - 1].time + (glm::distance(_path[_path.size() - 1].pos, _scene->getCamera()->getPosition()) / prevSpeed); else time = (float)_path.size() / 60; + if(std::isnan(time)) + time = _path[_path.size() - 1].time + (1.0f / 60); + _min = time; + _sec = (time - (int)time) * 60; + } + else if(_tp) + { + if(!_path.size()) + time = 0; + else + time = _path[_path.size() - 1].time; _min = time; _sec = (time - (int)time) * 60; } else time = (float)_min + ((float)_sec / 60); + ImGui::Checkbox("guess time automatically", &_autoTime); + if(_autoTime) + _tp = 0; + ImGui::Checkbox("tp", &_tp); + if(_tp) + _autoTime = 0; if(ImGui::Button("add step")) addPoint(time); + ImGui::Separator(); for(unsigned long i = 0; i < _path.size(); i++) @@ -529,7 +710,7 @@ void Renderer::imguiPathCreation(void) } } -std::string Renderer::floatToTime(float timef) +std::string Renderer::floatToTime(double timef) { std::string res; uint64_t time; @@ -537,13 +718,13 @@ std::string Renderer::floatToTime(float timef) int firstValue; time = timef; - values[0] = time / 3600 * 24 * 365; + values[0] = time / (3600 * 24 * 365); time = time % (3600 * 24 * 365); - values[1] = time / 3600 * 24 * 30; + values[1] = time / (3600 * 24 * 30); time = time % (3600 * 24 * 30); - values[2] = time / 3600 * 24 * 7; + values[2] = time / (3600 * 24 * 7); time = time % (3600 * 24 * 7); - values[3] = time / 3600 * 24; + values[3] = time / (3600 * 24); time = time % (3600 * 24); values[4] = time / 3600; time = time % 3600; @@ -583,8 +764,9 @@ std::string Renderer::floatToTime(float timef) return(res); } -void Renderer::imguiRenderInfo(void) +void Renderer::showRenderInfo(int isImgui) { + std::ostringstream oss; long int totalFrames; float renderTime; float progress; @@ -599,24 +781,86 @@ void Renderer::imguiRenderInfo(void) timeEst *= (totalFrames * _samples) - ((_frameCount * _samples) + _curSamples); if(timeEst > 1e15) timeEst = 0; - ImGui::Text("render in progress"); - ImGui::Text("samples per frame : %d", _samples); - ImGui::Text("render fps : %d", _fps); - ImGui::Text("total render time : %s", floatToTime((_path[_destPathIndex].time - _path[0].time) * 60).c_str()); - ImGui::Separator(); - ImGui::Text("Frames : %ld / %ld", _frameCount, totalFrames); - ImGui::Text("Frames (with accumulation) : %ld / %ld", (_frameCount * _samples) + _curSamples, totalFrames * _samples); - ImGui::Text("Render time : %dm%f", (int)renderTime, (renderTime - (int)renderTime) * 60); - ImGui::Text("elapsed time : %s", floatToTime(timeElapsed).c_str()); - ImGui::Text("estimated time remaining : %s", floatToTime(timeEst).c_str()); + + oss << std::fixed << std::setprecision(2); + + oss << "render in progress" << std::endl; + oss << "samples per frame : " << _samples << std::endl; + oss << "render fps : " << _fps << std::endl; + oss << "total render time : "; + oss << floatToTime((_path[_destPathIndex].time - _path[0].time) * 60).c_str(); + + if(isImgui) + { + ImGui::Text("%s",oss.str().c_str()); + ImGui::Separator(); + } + else + { + std::cout << "\033[2J\033[H"; + std::cout << oss.str() << std::endl; + std::cout << "-----------------------" << std::endl; + } + oss.str(""); + oss.clear(); + + oss << "Frames : " << _frameCount << " / " << totalFrames << std::endl; + oss << "Frames (with accumulation) : " << (_frameCount * _samples) + _curSamples; + oss << " / " << totalFrames * _samples << std::endl; + oss << "Render time : " << (int)renderTime << "m"; + oss << (renderTime - (int)renderTime) * 60 << "s" << std::endl; + oss << "elapsed time : " << floatToTime(timeElapsed) << std::endl; + oss << "estimated time remaining :" << floatToTime(timeEst); + progress = ((float)_frameCount * _samples) + _curSamples; progress /= (float)totalFrames * _samples; - ImGui::ProgressBar(progress, ImVec2(0, 0)); - if(ImGui::Button("stop")) + + if(isImgui) { - _destPathIndex = 0; - endRender(); + ImGui::Text("%s",oss.str().c_str()); + ImGui::ProgressBar(progress, ImVec2(0, 0)); + if(ImGui::Button("stop")) + { + _destPathIndex = 0; + endRender(); + } } + else + { + oss << std::endl << progress * 100 << "%"; + std::cout << oss.str() << std::endl; + } +} + +void Renderer::imguiRenderSettings(void) +{ + ImGui::SliderInt("render spi", &_samples, 1, 1000); + ImGui::SliderInt("render fps", &_fps, 30, 120); + ImGui::Combo("codec", &_codecIndex, _codecListStr.data(), _codecListStr.size()); + if(ImGui::Checkbox("show all codecs", &_ignoreUnavailableCodec)) + updateAvailableCodecs(_ignoreUnavailableCodec, (AVCodecID)0); + if(ImGui::InputText("file name", _filenameBuffer, 512)) + { + _outputFilename = _filenameBuffer; + updateAvailableCodecs(_ignoreUnavailableCodec, (AVCodecID)0); + } + if(_path.size() > 1 && _codecList.size()) + { + try + { + if(ImGui::Button("start render")) + initRender(); + ImGui::SameLine(); + if(ImGui::Button("save path")) + savePath(); + } + catch(std::exception &e) + { + std::cerr << "\033[31m" << e.what() << "\033[0m" << std::endl; + } + } + if(ImGui::Button("go back")) + _renderSettings = 0; } void Renderer::renderImgui(void) @@ -625,7 +869,9 @@ void Renderer::renderImgui(void) if (ImGui::CollapsingHeader("Renderer")) { if(rendering()) - imguiRenderInfo(); + showRenderInfo(1); + else if(_renderSettings) + imguiRenderSettings(); else imguiPathCreation(); } diff --git a/srcs/class/Scene.cpp b/srcs/class/Scene.cpp index 7c50bc5..0abd4cb 100644 --- a/srcs/class/Scene.cpp +++ b/srcs/class/Scene.cpp @@ -6,7 +6,7 @@ /* By: ycontre +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/12/23 18:29:41 by ycontre #+# #+# */ -/* Updated: 2025/01/28 19:17:39 by ycontre ### ########.fr */ +/* Updated: 2025/02/04 16:43:33 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ @@ -15,11 +15,14 @@ #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" -Scene::Scene() +Scene::Scene(std::string &name) { + std::ifstream file(name); + std::string line; _camera = new Camera(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f), -90.0f, 0.0f); _gpu_volume.enabled = 0; + _fail = 0; _gpu_volume.sigma_a = glm::vec3(0.0000f); _gpu_volume.sigma_s = glm::vec3(0.0800f); _gpu_volume.sigma_t = _gpu_volume.sigma_a + _gpu_volume.sigma_s; @@ -29,23 +32,13 @@ Scene::Scene() _gpu_debug.mode = 0; _gpu_debug.triangle_treshold = 1; _gpu_debug.box_treshold = 1; -} -Scene::~Scene() -{ - delete (_camera); -} - -bool Scene::parseScene(char *name) -{ - std::ifstream file(name); - std::string line; if (!file.is_open()) { - std::cout << "Error opening the file" << std::endl; - file.close(); - return (false); + std::cerr << "Can't open scene file" << std::endl; + _fail = 1; + return ; } SceneParser scene_parser(this, name); @@ -54,19 +47,22 @@ bool Scene::parseScene(char *name) { if (!scene_parser.parseLine(line)) { - std::cerr << line << std::endl; file.close(); - return (false); + std::cerr << line << std::endl; + _fail = 1; + return ; } } file.close(); std::cout << "Parsing done" << std::endl; - - return (true); } +Scene::~Scene() +{ + delete (_camera); +} void Scene::addObject(Object *obj) { @@ -313,6 +309,11 @@ void Scene::updateLightAndObjects(int mat_id) } } +bool Scene::fail(void) const +{ + return(_fail); +} + std::set Scene::getGPULights() { return (_gpu_lights); diff --git a/srcs/class/SceneParser.cpp b/srcs/class/SceneParser.cpp index cc20dfa..bef35fb 100644 --- a/srcs/class/SceneParser.cpp +++ b/srcs/class/SceneParser.cpp @@ -6,13 +6,13 @@ /* By: ycontre +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/12/26 21:43:51 by TheRed #+# #+# */ -/* Updated: 2025/01/30 22:29:15 by tomoron ### ########.fr */ +/* Updated: 2025/02/04 01:21:11 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ #include "SceneParser.hpp" -SceneParser::SceneParser(Scene *scene, char *filename) : _scene(scene), _filename(filename) +SceneParser::SceneParser(Scene *scene, std::string filename) : _scene(scene), _filename(filename) { object_parsers["sp"] = [](std::stringstream &ss) -> Object * { return (new Sphere(ss)); }; object_parsers["pl"] = [](std::stringstream &ss) -> Object * { return (new Plane(ss)); }; diff --git a/srcs/class/Window.cpp b/srcs/class/Window.cpp index d440611..2ae6c47 100644 --- a/srcs/class/Window.cpp +++ b/srcs/class/Window.cpp @@ -6,19 +6,19 @@ /* By: ycontre +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/10/13 16:16:24 by TheRed #+# #+# */ -/* Updated: 2025/01/28 15:15:53 by tomoron ### ########.fr */ +/* Updated: 2025/02/04 16:46:29 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ #include "Window.hpp" -Window::Window(Scene *scene, int width, int height, const char *title, int sleep) +Window::Window(Scene *scene, int width, int height, const char *title, int sleep, Arguments &args) { _scene = scene; _fps = 0; _frameCount = 0; _pixelisation = 0; - _renderer = new Renderer(scene, this); + _renderer = new Renderer(scene, this, args); if (!glfwInit()) { @@ -161,7 +161,7 @@ void Window::pollEvents() } bool Window::shouldClose() { - return glfwWindowShouldClose(_window); + return glfwWindowShouldClose(_window) || _renderer->shouldClose(); } void Window::rendererUpdate(Shader &shader)