544 |
550 |
545 void Shark::Impl::parametrizeTexture(std::shared_ptr<Texture> tex) { |
551 void Shark::Impl::parametrizeTexture(std::shared_ptr<Texture> tex) { |
546 XAttrs xa(tex->getFileName()); |
552 XAttrs xa(tex->getFileName()); |
547 std::string magf = xa["shader-shark.texture.mag-filter"]; |
553 std::string magf = xa["shader-shark.texture.mag-filter"]; |
548 std::string minf = xa["shader-shark.texture.min-filter"]; |
554 std::string minf = xa["shader-shark.texture.min-filter"]; |
549 // TODO: std::string scale = xa["shader-shark.texture.scale"]; |
555 std::string scale = xa["shader-shark.texture.scale"]; |
550 // TODO: keep MappedFile locked until we read the attributes |
|
551 |
556 |
552 auto GLT2D = GL_TEXTURE_2D; |
557 auto GLT2D = GL_TEXTURE_2D; |
553 auto MAG = GL_TEXTURE_MAG_FILTER; |
558 auto MAG = GL_TEXTURE_MAG_FILTER; |
554 auto MIN = GL_TEXTURE_MIN_FILTER; |
559 auto MIN = GL_TEXTURE_MIN_FILTER; |
555 |
560 |
556 if (magf == "linear") glTexParameteri(GLT2D, MAG, GL_LINEAR); |
561 if (magf == "linear") glTexParameteri(GLT2D, MAG, GL_LINEAR); |
557 else if (magf == "nearest") glTexParameteri(GLT2D, MAG, GL_NEAREST); |
562 else if (magf == "nearest") glTexParameteri(GLT2D, MAG, GL_NEAREST); |
558 |
563 |
559 if (minf == "linear") glTexParameteri(GLT2D, MIN, GL_LINEAR); |
564 if (minf == "linear") glTexParameteri(GLT2D, MIN, GL_LINEAR); |
560 else if (minf == "nearest") glTexParameteri(GLT2D, MIN, GL_NEAREST); |
565 else if (minf == "nearest") glTexParameteri(GLT2D, MIN, GL_NEAREST); |
|
566 |
|
567 if (scale.size()) { |
|
568 float sc; |
|
569 if (std::from_chars(scale.data(), scale.data() + scale.size(), sc).ec |
|
570 == std::errc{}) tex->setScale(sc); |
|
571 else std::cerr << "Invalid texture scale value - expecting float\n"; |
|
572 // tex->setScale(std::stof(scale)); // locale-dependent (. vs ,) |
|
573 } |
561 } |
574 } |
562 |
575 |
563 void Shark::Impl::loadTextures() { |
576 void Shark::Impl::loadTextures() { |
564 // Load default texture if there is no configured: |
577 // Load default texture if there is no configured: |
565 if (cfg.textures.empty()) |
578 if (cfg.textures.empty()) |
593 } |
606 } |
594 } |
607 } |
595 return false; |
608 return false; |
596 } |
609 } |
597 |
610 |
598 std::shared_ptr<Program> Shark::Impl::loadShaders() { |
611 void Shark::Impl::loadShaders() { |
599 try { |
612 // Vertex Array Object (VAO) |
600 // Vertex Array Object (VAO) |
613 GLuint vao; |
601 GLuint vao; |
614 glGenVertexArrays(1, &vao); |
602 glGenVertexArrays(1, &vao); |
615 glBindVertexArray(vao); |
603 glBindVertexArray(vao); |
616 // VAO - something like context for bound data/variables |
604 // VAO - something like context for bound data/variables |
617 // We can switch multiple VAOs. VAO can contain multiple VBOs. |
605 // We can switch multiple VAOs. VAO can contain multiple VBOs. |
618 // what-are-vertex-array-objects |
606 // what-are-vertex-array-objects |
619 |
607 |
620 // Vertex Buffer Object (VBO): |
608 // Vertex Buffer Object (VBO): |
621 GLuint vbo; |
609 GLuint vbo; |
622 glGenBuffers(1, &vbo); |
610 glGenBuffers(1, &vbo); |
623 glBindBuffer(GL_ARRAY_BUFFER, vbo); |
611 glBindBuffer(GL_ARRAY_BUFFER, vbo); |
624 |
612 |
625 { |
613 { |
626 // Load default shaders if there are no configured: |
614 // Load default shaders if there are no configured: |
627 int vc = 0; |
615 int vc = 0; |
628 int fc = 0; |
616 int fc = 0; |
629 auto& ss = cfg.shaders; |
617 auto& ss = cfg.shaders; |
630 for (const auto& s : ss) if (s.type == "vertex") vc++; |
618 for (const auto& s : ss) if (s.type == "vertex") vc++; |
631 for (const auto& s : ss) if (s.type == "fragment") fc++; |
619 for (const auto& s : ss) if (s.type == "fragment") fc++; |
632 auto& d = getDefaultFile; |
620 auto& d = getDefaultFile; |
633 if (vc == 0) ss.push_back({d("shaders/default.vert"), "vertex"}); |
621 if (vc == 0) ss.push_back({d("shaders/default.vert"), "vertex"}); |
634 if (fc == 0) ss.push_back({d("shaders/default.frag"), "fragment"}); |
622 if (fc == 0) ss.push_back({d("shaders/default.frag"), "fragment"}); |
635 } |
623 } |
636 |
624 |
637 shaderProgram = std::make_shared<Program>(); |
625 std::shared_ptr<Program> program = std::make_shared<Program>(); |
638 |
626 |
639 // glBindFragDataLocation(program, 0, "outColor"); |
627 // glBindFragDataLocation(program, 0, "outColor"); |
640 // glBindAttribLocation(program, LOC.input, "vertices"); |
628 // glBindAttribLocation(program, LOC.input, "vertices"); |
641 |
629 |
642 for (const Configuration::Shader definition : cfg.shaders) { |
630 for (const Configuration::Shader definition : cfg.shaders) { |
643 Shader::Type type; |
631 Shader::Type type; |
644 std::string fileName = definition.fileName; |
632 std::string fileName = definition.fileName; |
645 if (definition.type == "fragment") type = Shader::Type::FRAGMENT; |
633 if (definition.type == "fragment") type = Shader::Type::FRAGMENT; |
646 else if (definition.type == "vertex") type = Shader::Type::VERTEX; |
634 else if (definition.type == "vertex") type = Shader::Type::VERTEX; |
647 else throw std::invalid_argument("unsupported shader type"); |
635 else throw std::invalid_argument("unsupported shader type"); |
648 |
636 |
649 MappedFile file(fileName); |
637 MappedFile file(fileName); |
650 std::shared_ptr<Shader> shader = std::make_shared<Shader>( |
638 std::shared_ptr<Shader> shader = std::make_shared<Shader>( |
651 type, file, fileName); |
639 type, file, fileName); |
652 |
640 |
653 shaderProgram->attachShader(*shader.get()); |
641 program->attachShader(*shader.get()); |
654 shaders.push_back(shader); |
642 shaders.push_back(shader); |
655 watchedFiles.push_back(fileMonitor.watch(fileName)); |
643 watchedFiles.push_back(fileMonitor.watch(fileName)); |
656 std::cerr << "GLSL loaded: " << fileName.c_str() << std::endl; |
644 std::cerr << "GLSL loaded: " << fileName.c_str() << std::endl; |
657 // We may detach and delete shaders, |
645 // We may detach and delete shaders, |
658 // but our shaders are small, so we keep them for later reloading. |
646 // but our shaders are small, so we keep them for later reloading. |
659 } |
647 } |
660 |
648 |
661 shaderProgram->link(); |
649 // GLSL compiler does very efficient / aggressive optimization. |
662 updateVariableLocations(); |
650 // Attributes and uniforms that are not used in the shader are deleted. |
663 // listVariables(program); |
651 // And even if we e.g. read color from a texture and overwrite it, |
664 std::cerr << "GLSL shader count: " << shaders.size() << std::endl; |
652 // the variable is still deleted and considered „inactive“. |
665 } |
653 // Functions glGetAttribLocation() and glGetUniformLocation() return -1. |
666 |
654 |
667 void Shark::Impl::updateVariableLocations() { |
655 program->link(); |
668 // GLSL compiler does very efficient / aggressive optimization. |
656 |
669 // Attributes and uniforms that are not used in the shader are deleted. |
657 ProgAttr.aVertexXYZ = program->getAttribLocation("aVertexXYZ"); |
670 // And even if we e.g. read color from a texture and overwrite it, |
658 ProgAttr.aTextureXY = program->getAttribLocation("aTextureXY"); |
671 // the variable is still deleted and considered „inactive“. |
659 ProgAttr.uModel = program->getUniformLocation("uModel"); |
672 // Functions glGetAttribLocation() and glGetUniformLocation() return -1. |
660 ProgAttr.uView = program->getUniformLocation("uView"); |
673 ProgAttr.aVertexXYZ = shaderProgram->getAttribLocation("aVertexXYZ"); |
661 ProgAttr.uProjection = program->getUniformLocation("uProjection"); |
674 ProgAttr.aTextureXY = shaderProgram->getAttribLocation("aTextureXY"); |
662 ProgAttr.uTexture = program->getUniformLocation("uTexture"); |
675 ProgAttr.uModel = shaderProgram->getUniformLocation("uModel"); |
663 ProgAttr.fColor = program->getFragDataLocation("fColor"); |
676 ProgAttr.uView = shaderProgram->getUniformLocation("uView"); |
664 program->bindFragDataLocation("fColor", ProgAttr.fColor); |
677 ProgAttr.uProjection = shaderProgram->getUniformLocation("uProjection"); |
665 // listVariables(program); |
678 ProgAttr.uTexture = shaderProgram->getUniformLocation("uTexture"); |
666 std::cerr << "GLSL shader count: " << shaders.size() << std::endl; |
679 ProgAttr.uTextureScale = shaderProgram->getUniformLocation("uTextureScale"); |
667 return program; |
680 ProgAttr.fColor = shaderProgram->getFragDataLocation("fColor"); |
668 } catch (const std::exception& e) { |
681 shaderProgram->bindFragDataLocation("fColor", ProgAttr.fColor); |
669 std::cerr << "Error while loading shaders: " << e.what() << std::endl; |
|
670 } catch (...) { |
|
671 std::cerr << "Error while loading shaders: unknown" << std::endl; |
|
672 } |
|
673 throw std::logic_error("GLSL: loadShaders() failed"); |
|
674 } |
682 } |
675 |
683 |
676 bool Shark::Impl::reloadShader(const std::string& fileName) { |
684 bool Shark::Impl::reloadShader(const std::string& fileName) { |
677 for (auto shader : shaders) { |
685 for (auto shader : shaders) { |
678 if (shader->getFileName() == fileName) { |
686 if (shader->getFileName() == fileName) { |
679 shader->update(MappedFile(fileName)); |
687 shader->update(MappedFile(fileName)); |
680 shaderProgram->link(); |
688 shaderProgram->link(); |
|
689 updateVariableLocations(); |
681 return true; |
690 return true; |
682 } |
691 } |
683 } |
692 } |
684 return false; |
693 return false; |
685 } |
694 } |