main.hpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. auto OpenGL::setShader(const string& pathname) -> void {
  2. for(auto& program : programs) program.release();
  3. programs.reset();
  4. settings.reset();
  5. format = inputFormat;
  6. filter = GL_LINEAR;
  7. wrap = GL_CLAMP_TO_BORDER;
  8. absoluteWidth = 0, absoluteHeight = 0;
  9. relativeWidth = 0, relativeHeight = 0;
  10. uint historySize = 0;
  11. if(pathname == "None") {
  12. filter = GL_NEAREST;
  13. } else if(pathname == "Blur") {
  14. filter = GL_LINEAR;
  15. } else if(directory::exists(pathname)) {
  16. auto document = BML::unserialize(file::read({pathname, "manifest.bml"}));
  17. for(auto node : document["settings"]) {
  18. settings.insert({node.name(), node.text()});
  19. }
  20. for(auto node : document["input"]) {
  21. if(node.name() == "history") historySize = node.natural();
  22. if(node.name() == "format") format = glrFormat(node.text());
  23. if(node.name() == "filter") filter = glrFilter(node.text());
  24. if(node.name() == "wrap") wrap = glrWrap(node.text());
  25. }
  26. for(auto node : document["output"]) {
  27. string text = node.text();
  28. if(node.name() == "width") {
  29. if(text.endsWith("%")) relativeWidth = toReal(text.trimRight("%", 1L)) / 100.0;
  30. else absoluteWidth = text.natural();
  31. }
  32. if(node.name() == "height") {
  33. if(text.endsWith("%")) relativeHeight = toReal(text.trimRight("%", 1L)) / 100.0;
  34. else absoluteHeight = text.natural();
  35. }
  36. }
  37. for(auto node : document.find("program")) {
  38. uint n = programs.size();
  39. programs(n).bind(this, node, pathname);
  40. }
  41. }
  42. //changing shaders may change input format, which requires the input texture to be recreated
  43. if(texture) { glDeleteTextures(1, &texture); texture = 0; }
  44. glGenTextures(1, &texture);
  45. glBindTexture(GL_TEXTURE_2D, texture);
  46. glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, getFormat(), getType(), buffer);
  47. allocateHistory(historySize);
  48. }
  49. auto OpenGL::allocateHistory(uint size) -> void {
  50. for(auto& frame : history) glDeleteTextures(1, &frame.texture);
  51. history.reset();
  52. while(size--) {
  53. OpenGLTexture frame;
  54. frame.filter = filter;
  55. frame.wrap = wrap;
  56. glGenTextures(1, &frame.texture);
  57. glBindTexture(GL_TEXTURE_2D, frame.texture);
  58. glTexImage2D(GL_TEXTURE_2D, 0, format, frame.width = width, frame.height = height, 0, getFormat(), getType(), buffer);
  59. history.append(frame);
  60. }
  61. }
  62. auto OpenGL::clear() -> void {
  63. for(auto& p : programs) {
  64. glUseProgram(p.program);
  65. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, p.framebuffer);
  66. glClearColor(0, 0, 0, 1);
  67. glClear(GL_COLOR_BUFFER_BIT);
  68. }
  69. glUseProgram(0);
  70. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
  71. glClearColor(0, 0, 0, 1);
  72. glClear(GL_COLOR_BUFFER_BIT);
  73. }
  74. auto OpenGL::lock(uint32_t*& data, uint& pitch) -> bool {
  75. pitch = width * sizeof(uint32_t);
  76. return data = buffer;
  77. }
  78. auto OpenGL::output() -> void {
  79. clear();
  80. glActiveTexture(GL_TEXTURE0);
  81. glBindTexture(GL_TEXTURE_2D, texture);
  82. glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, getFormat(), getType(), buffer);
  83. struct Source {
  84. GLuint texture;
  85. uint width, height;
  86. GLuint filter, wrap;
  87. };
  88. vector<Source> sources;
  89. sources.prepend({texture, width, height, filter, wrap});
  90. for(auto& p : programs) {
  91. uint targetWidth = p.absoluteWidth ? p.absoluteWidth : outputWidth;
  92. uint targetHeight = p.absoluteHeight ? p.absoluteHeight : outputHeight;
  93. if(p.relativeWidth) targetWidth = sources[0].width * p.relativeWidth;
  94. if(p.relativeHeight) targetHeight = sources[0].height * p.relativeHeight;
  95. p.size(targetWidth, targetHeight);
  96. glUseProgram(p.program);
  97. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, p.framebuffer);
  98. glrUniform1i("phase", p.phase);
  99. glrUniform1i("historyLength", history.size());
  100. glrUniform1i("sourceLength", sources.size());
  101. glrUniform1i("pixmapLength", p.pixmaps.size());
  102. glrUniform4f("targetSize", targetWidth, targetHeight, 1.0 / targetWidth, 1.0 / targetHeight);
  103. glrUniform4f("outputSize", outputWidth, outputHeight, 1.0 / outputWidth, 1.0 / outputHeight);
  104. uint aid = 0;
  105. for(auto& frame : history) {
  106. glrUniform1i({"history[", aid, "]"}, aid);
  107. glrUniform4f({"historySize[", aid, "]"}, frame.width, frame.height, 1.0 / frame.width, 1.0 / frame.height);
  108. glActiveTexture(GL_TEXTURE0 + (aid++));
  109. glBindTexture(GL_TEXTURE_2D, frame.texture);
  110. glrParameters(frame.filter, frame.wrap);
  111. }
  112. uint bid = 0;
  113. for(auto& source : sources) {
  114. glrUniform1i({"source[", bid, "]"}, aid + bid);
  115. glrUniform4f({"sourceSize[", bid, "]"}, source.width, source.height, 1.0 / source.width, 1.0 / source.height);
  116. glActiveTexture(GL_TEXTURE0 + aid + (bid++));
  117. glBindTexture(GL_TEXTURE_2D, source.texture);
  118. glrParameters(source.filter, source.wrap);
  119. }
  120. uint cid = 0;
  121. for(auto& pixmap : p.pixmaps) {
  122. glrUniform1i({"pixmap[", cid, "]"}, aid + bid + cid);
  123. glrUniform4f({"pixmapSize[", bid, "]"}, pixmap.width, pixmap.height, 1.0 / pixmap.width, 1.0 / pixmap.height);
  124. glActiveTexture(GL_TEXTURE0 + aid + bid + (cid++));
  125. glBindTexture(GL_TEXTURE_2D, pixmap.texture);
  126. glrParameters(pixmap.filter, pixmap.wrap);
  127. }
  128. glActiveTexture(GL_TEXTURE0);
  129. glrParameters(sources[0].filter, sources[0].wrap);
  130. p.render(sources[0].width, sources[0].height, 0, 0, targetWidth, targetHeight);
  131. glBindTexture(GL_TEXTURE_2D, p.texture);
  132. p.phase = (p.phase + 1) % p.modulo;
  133. sources.prepend({p.texture, p.width, p.height, p.filter, p.wrap});
  134. }
  135. uint targetWidth = absoluteWidth ? absoluteWidth : outputWidth;
  136. uint targetHeight = absoluteHeight ? absoluteHeight : outputHeight;
  137. if(relativeWidth) targetWidth = sources[0].width * relativeWidth;
  138. if(relativeHeight) targetHeight = sources[0].height * relativeHeight;
  139. glUseProgram(program);
  140. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
  141. glrUniform1i("source[0]", 0);
  142. glrUniform4f("targetSize", targetWidth, targetHeight, 1.0 / targetWidth, 1.0 / targetHeight);
  143. glrUniform4f("outputSize", outputWidth, outputHeight, 1.0 / outputWidth, 1.0 / outputHeight);
  144. glrParameters(sources[0].filter, sources[0].wrap);
  145. render(sources[0].width, sources[0].height, outputX, outputY, outputWidth, outputHeight);
  146. if(history.size() > 0) {
  147. OpenGLTexture frame = history.takeRight();
  148. glBindTexture(GL_TEXTURE_2D, frame.texture);
  149. if(width == frame.width && height == frame.height) {
  150. glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, getFormat(), getType(), buffer);
  151. } else {
  152. glTexImage2D(GL_TEXTURE_2D, 0, format, frame.width = width, frame.height = height, 0, getFormat(), getType(), buffer);
  153. }
  154. history.prepend(frame);
  155. }
  156. }
  157. auto OpenGL::initialize(const string& shader) -> bool {
  158. if(!OpenGLBind()) return false;
  159. glDisable(GL_BLEND);
  160. glDisable(GL_DEPTH_TEST);
  161. glDisable(GL_POLYGON_SMOOTH);
  162. glDisable(GL_STENCIL_TEST);
  163. glEnable(GL_DITHER);
  164. program = glCreateProgram();
  165. vertex = glrCreateShader(program, GL_VERTEX_SHADER, OpenGLOutputVertexShader);
  166. //geometry = glrCreateShader(program, GL_GEOMETRY_SHADER, OpenGLGeometryShader);
  167. fragment = glrCreateShader(program, GL_FRAGMENT_SHADER, OpenGLFragmentShader);
  168. OpenGLSurface::allocate();
  169. glrLinkProgram(program);
  170. setShader(shader);
  171. return initialized = true;
  172. }
  173. auto OpenGL::terminate() -> void {
  174. if(!initialized) return;
  175. setShader(""); //release shader resources (eg frame[] history)
  176. OpenGLSurface::release();
  177. if(buffer) { delete[] buffer; buffer = nullptr; }
  178. initialized = false;
  179. }