OHP3D.cpp
branchv_0
changeset 30 02972f051744
parent 29 dc3c102e1264
child 31 ed3caeea978a
equal deleted inserted replaced
29:dc3c102e1264 30:02972f051744
    21 #include <charconv>
    21 #include <charconv>
    22 #include <memory>
    22 #include <memory>
    23 #include <functional>
    23 #include <functional>
    24 #include <sstream>
    24 #include <sstream>
    25 #include <vector>
    25 #include <vector>
       
    26 #include <chrono>
       
    27 #include <unistd.h>
       
    28 
       
    29 #include <poppler/cpp/poppler-document.h>
       
    30 #include <poppler/cpp/poppler-page.h>
       
    31 #include <poppler/cpp/poppler-toc.h>
       
    32 #include <sys/stat.h>
       
    33 #include <poppler/cpp/poppler-page-renderer.h>
    26 
    34 
    27 #include "x11.h"
    35 #include "x11.h"
    28 #include "opengl.h"
    36 #include "opengl.h"
    29 #include "EPoll.h"
    37 #include "EPoll.h"
    30 #include "Logger.h"
    38 #include "Logger.h"
    31 #include "MappedFile.h"
    39 #include "MappedFile.h"
    32 #include "ImageLoader.h"
    40 #include "PageBuffer.h"
    33 #include "Texture.h"
    41 #include "Texture.h"
    34 #include "Shader.h"
    42 #include "Shader.h"
    35 #include "Program.h"
    43 #include "Program.h"
    36 #include "FileMonitor.h"
    44 #include "FileMonitor.h"
    37 #include "XAttrs.h"
    45 #include "XAttrs.h"
   164 	XVisualInfo* vi;
   172 	XVisualInfo* vi;
   165 	GLXContext glc;
   173 	GLXContext glc;
   166 
   174 
   167 	FileMonitor fileMonitor;
   175 	FileMonitor fileMonitor;
   168 	std::vector<WatchedFile> watchedFiles;
   176 	std::vector<WatchedFile> watchedFiles;
   169 	ImageLoader imageLoader;
       
   170 	std::vector<std::shared_ptr<Shader>> shaders;
   177 	std::vector<std::shared_ptr<Shader>> shaders;
   171 	std::shared_ptr<Program> shaderProgram;
   178 	std::shared_ptr<Program> shaderProgram;
   172 	std::vector<std::shared_ptr<Texture>> textures;
   179 	std::vector<std::shared_ptr<Texture>> textures;
   173 
   180 
   174 	Configuration cfg;
   181 	Configuration cfg;
   182 	void runShaders();
   189 	void runShaders();
   183 	Window getRootWindow(Window defaultValue);
   190 	Window getRootWindow(Window defaultValue);
   184 	void log(LogLevel level, std::string message);
   191 	void log(LogLevel level, std::string message);
   185 	int setNonBlocking(int fd);
   192 	int setNonBlocking(int fd);
   186 	void loadVertices();
   193 	void loadVertices();
   187 	void parametrizeTexture(std::shared_ptr<Texture> tex);
   194 	void loadDocuments();
   188 	bool reloadTexture(const std::string& fileName);
       
   189 	void loadTextures();
       
   190 	void loadShaders();
   195 	void loadShaders();
   191 	void updateVariableLocations();
   196 	void updateVariableLocations();
   192 	bool reloadShader(const std::string& fileName);
   197 	bool reloadShader(const std::string& fileName);
   193 	void setTitle(const std::string& suffix = "");
   198 	void setTitle(const std::string& suffix = "");
   194 	static const std::string getDefaultFile(const std::string& relativePath);
   199 	static const std::string getDefaultFile(const std::string& relativePath);
   269 
   274 
   270 	clear();
   275 	clear();
   271 	glXSwapBuffers(dpy, win);
   276 	glXSwapBuffers(dpy, win);
   272 
   277 
   273 
   278 
   274 	// Load GLSL shaders:
       
   275 	loadShaders();
   279 	loadShaders();
   276 	loadTextures();
   280 	loadDocuments();
   277 	loadVertices();
   281 	loadVertices();
   278 
   282 
   279 	auto toggleFullscreen = [&]() {
   283 	auto toggleFullscreen = [&]() {
   280 		full = setFullscreen(dpy, win, !full);
   284 		full = setFullscreen(dpy, win, !full);
   281 	};
   285 	};
   407 					logOutput << "   "
   411 					logOutput << "   "
   408 							<< " file=" << fe.fileName
   412 							<< " file=" << fe.fileName
   409 							<< " mask=" << fe.mask
   413 							<< " mask=" << fe.mask
   410 							<< std::endl;
   414 							<< std::endl;
   411 					try {
   415 					try {
   412 						redraw |= reloadTexture(fe.fileName);
       
   413 						redraw |= reloadShader(fe.fileName);
   416 						redraw |= reloadShader(fe.fileName);
   414 						setTitle();
   417 						setTitle();
   415 					} catch (const std::exception& e) {
   418 					} catch (const std::exception& e) {
   416 						setTitle("[ERROR]");
   419 						setTitle("[ERROR]");
   417 						logOutput << "error while reloading '"
   420 						logOutput << "error while reloading '"
   546 				+ " in order to use defaults"
   549 				+ " in order to use defaults"
   547 				" or specify textures and shaders as parameters");
   550 				" or specify textures and shaders as parameters");
   548 	}
   551 	}
   549 }
   552 }
   550 
   553 
   551 void OHP3D::Impl::parametrizeTexture(std::shared_ptr<Texture> tex) {
   554 void OHP3D::Impl::loadDocuments() {
   552 	XAttrs xa(tex->getFileName());
   555 	for (const Configuration::File& document : cfg.documents) {
   553 	std::string magf = xa["ohp3d.texture.mag-filter"];
   556 		std::cerr << "loading document: " << document.fileName.c_str() << "\n";
   554 	std::string minf = xa["ohp3d.texture.min-filter"];
   557 
   555 	std::string scale = xa["ohp3d.texture.scale"];
   558 		MappedFile buffer(document.fileName);
   556 
   559 
   557 	auto GLT2D = GL_TEXTURE_2D;
   560 		namespace pp = poppler;
   558 	auto MAG = GL_TEXTURE_MAG_FILTER;
   561 		using Document = pp::document;
   559 	auto MIN = GL_TEXTURE_MIN_FILTER;
   562 
   560 
   563 		std::shared_ptr<Document> doc = std::shared_ptr<Document>(
   561 	if (magf == "linear") glTexParameteri(GLT2D, MAG, GL_LINEAR);
   564 				Document::load_from_raw_data(buffer.getData(), buffer.getSize()));
   562 	else if (magf == "nearest") glTexParameteri(GLT2D, MAG, GL_NEAREST);
   565 
   563 
   566 		log(LogLevel::INFO, std::string("PDF parsed:")
   564 	if (minf == "linear") glTexParameteri(GLT2D, MIN, GL_LINEAR);
   567 				+ " pages=" + std::to_string(doc->pages()));
   565 	else if (minf == "nearest") glTexParameteri(GLT2D, MIN, GL_NEAREST);
   568 
   566 
   569 		log(LogLevel::INFO, "loadig pages to textures...");
   567 	if (scale.size()) {
   570 		auto timingStart = std::chrono::steady_clock::now();
   568 		float sc;
   571 		pp::page_renderer renderer;
   569 		if (std::from_chars(scale.data(), scale.data() + scale.size(), sc).ec
   572 		renderer.set_image_format(pp::image::format_rgb24);
   570 				== std::errc{}) tex->setScale(sc);
   573 		double dpi = cfg.dpi;
   571 		else std::cerr << "Invalid texture scale value - expecting float\n";
   574 		for (int i = 0, limit = doc->pages(); i < limit; i++) {
   572 		// tex->setScale(std::stof(scale)); // locale-dependent (. vs ,)
   575 			std::shared_ptr<pp::page> page(doc->create_page(i));
   573 	}
   576 			pp::image pageImage = renderer.render_page(page.get(), dpi, dpi);
   574 }
   577 
   575 
   578 			PageBuffer img(
   576 void OHP3D::Impl::loadTextures() {
   579 					pageImage.data(),
   577 	// Load default texture if there is no configured:
   580 					pageImage.bytes_per_row() * pageImage.height(),
   578 	if (cfg.textures.empty())
   581 					pageImage.width(), pageImage.height());
   579 		cfg.textures.push_back({getDefaultFile("textures/default.png")});
   582 
   580 
   583 			textures.push_back(std::make_shared<Texture>(
   581 	for (const Configuration::Texture& tex : cfg.textures) {
   584 					pageImage.width(), pageImage.height(),
   582 		std::shared_ptr<ImageLoader::ImageBuffer>
   585 					img, document.fileName));
   583 				img(imageLoader.loadImage(MappedFile(tex.fileName)));
   586 			log(LogLevel::INFO, "  page " + std::to_string(i + 1)
   584 		textures.push_back(std::make_shared<Texture>(
   587 					+ "/" + std::to_string(limit));
   585 				img->width, img->height, *img, tex.fileName));
   588 		}
   586 		parametrizeTexture(textures.back());
   589 
   587 		// static const uint32_t watchMask = IN_CLOSE_WRITE | IN_ATTRIB;
   590 		auto timingEnd = std::chrono::steady_clock::now();
   588 		// watchedFiles.push_back(fileMonitor.watch(tex.fileName, watchMask));
   591 		auto timingTotal = std::chrono::duration_cast<std::chrono::microseconds>
   589 		watchedFiles.push_back(fileMonitor.watch(tex.fileName));
   592 				(timingEnd - timingStart).count();
   590 		// TODO: review texture loading and binding
   593 
   591 		// works even without this - default texture
   594 		std::stringstream timingMsg;
   592 		// glUniform1i(..., ...);
   595 		timingMsg.imbue(std::locale(""));
   593 		// checkError(&std::cerr);
   596 		timingMsg << "PDF to texture load time:"
   594 	}
   597 				<< " page average = " << (timingTotal / doc->pages()) << " µs,"
   595 }
   598 				<< " total = " << timingTotal << " µs ("
   596 
   599 				<< doc->pages() << " pages)";
   597 bool OHP3D::Impl::reloadTexture(const std::string& fileName) {
   600 		log(LogLevel::INFO, timingMsg.str());
   598 	for (std::shared_ptr<Texture> tex : textures) {
   601 		if (timingTotal < 400000) logOutput << ">>> Doherty threshold met! <<<\n";
   599 		if (tex->getFileName() == fileName) {
   602 	}
   600 			std::shared_ptr<ImageLoader::ImageBuffer>
       
   601 					img(imageLoader.loadImage(MappedFile(fileName)));
       
   602 			tex->update(img->width, img->height, *img);
       
   603 			parametrizeTexture(tex);
       
   604 			loadVertices();
       
   605 			return true;
       
   606 		}
       
   607 	}
       
   608 	return false;
       
   609 }
   603 }
   610 
   604 
   611 void OHP3D::Impl::loadShaders() {
   605 void OHP3D::Impl::loadShaders() {
   612 	// Vertex Array Object (VAO)
   606 	// Vertex Array Object (VAO)
   613 	GLuint vao;
   607 	GLuint vao;