You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

InputComponent.cpp 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. #include "InputComponent.h"
  2. #include <iostream>
  3. #include "../text/TextRasterizerCache.h"
  4. #include "../../scheduler.h"
  5. #include "../opengl/Shader.h"
  6. #include "../opengl/ShaderLoader.h"
  7. #include "../opengl/shaders/gen/TextureShader.h"
  8. #include "../opengl/shaders/gen/FontShader.h"
  9. extern TextRasterizerCache *rasterizerCache;
  10. extern std::unique_ptr<Scheduler> scheduler;
  11. // : BoxComponent(rawX, rawY, rawWidth, rawHeight, passedWindowWidth, passedWindowHeight)
  12. InputComponent::InputComponent(const float rawX, const float rawY, const float rawWidth, const float rawHeight, const int passedWindowWidth, const int passedWindowHeight) {
  13. //std::cout << "InputComponent::InputComponent - create, boundToPage" << boundToPage << std::endl;
  14. //std::cout << "InputComponent::InputComponent - window: " << windowWidth << "x" << windowHeight << " passed " << passedWindowWidth << "x" << passedWindowHeight << std::endl;
  15. //boundToPage = true;
  16. useBoxShader = true;
  17. // set up state
  18. windowWidth = passedWindowWidth;
  19. windowHeight = passedWindowHeight;
  20. // lets not set, like resize set, and then maybe parent width will be correct
  21. // didn't really changed anything
  22. width = rawWidth;
  23. height = rawHeight;
  24. // ugh
  25. x = rawX;
  26. y = rawY;
  27. lastRenderedWindowHeight = windowHeight;
  28. // const float rawX, const float rawY, const float rawWidth, const float rawHeight, const unsigned int hexColor, const int passedWindowWidth, const int passedWindowHeight
  29. this->cursorBox = new BoxComponent(x, y, 2, rawHeight, 0x000000FF, windowWidth, windowHeight);
  30. this->cursorBox->boundToPage = this->boundToPage;
  31. this->cursorBox->x = x;
  32. this->cursorBox->y = y;
  33. if (boundToPage) {
  34. this->cursorBox->y = this->windowHeight + y - 13;
  35. }
  36. this->cursorBox->resize(this->windowWidth, this->windowHeight);
  37. this->updateText();
  38. onFocus=[this]() {
  39. this->focused = true;
  40. this->cursorBox->x = x ;
  41. this->cursorBox->y = y;
  42. if (this->boundToPage) {
  43. this->cursorBox->y = this->windowHeight + y - 13;
  44. }
  45. this->cursorBox->resize(this->windowWidth, this->windowHeight);
  46. this->win->renderDirty = true;
  47. };
  48. onBlur=[this]() {
  49. this->focused = false;
  50. this->win->renderDirty = true;
  51. };
  52. //std::cout << "InputComponent::InputComponent - placing box at " << (int)x << "," << (int)y << " size: " << (int)width << "x" << (int)height << std::endl;
  53. // copy initial state
  54. initialX = x;
  55. initialY = y;
  56. initialWidth = width;
  57. initialHeight = height;
  58. initialWindowWidth = windowWidth;
  59. initialWindowHeight = windowHeight;
  60. for (int i = 0; i < 3; i++) {
  61. data[0][0][i] = 0xf0; // set RGB color
  62. }
  63. data[0][0][3] = 0xff; // set alpha
  64. float vx = rawX;
  65. float vy = rawY;
  66. //std::cout << "placing box at " << (int)vx << "x" << (int)vy << " size: " << (int)rawWidth << "x" << (int)rawHeight << std::endl;
  67. float vWidth = rawWidth;
  68. float vHeight = rawHeight;
  69. pointToViewport(vx, vy);
  70. // converts 512 to 1 and 1 to 2
  71. //std::cout << "vWidth before: " << (int)vWidth << std::endl;
  72. distanceToViewport(vWidth, vHeight);
  73. //std::cout << "vWidth after: " << (int)vWidth << std::endl;
  74. //std::cout << "InputComponent::InputComponent - placing box at GL " << vx << "," << vy << " to " << vx+vWidth << "," << vy+vHeight << " size: " << vWidth << "x" << vHeight << std::endl;
  75. vertices[(0 * 5) + 0] = vx;
  76. vertices[(0 * 5) + 1] = vy + vHeight;
  77. vertices[(1 * 5) + 0] = vx + vWidth;
  78. vertices[(1 * 5) + 1] = vy + vHeight;
  79. vertices[(2 * 5) + 0] = vx + vWidth;
  80. vertices[(2 * 5) + 1] = vy;
  81. vertices[(3 * 5) + 0] = vx;
  82. vertices[(3 * 5) + 1] = vy;
  83. glGenVertexArrays(1, &vertexArrayObject);
  84. glGenBuffers(1, &vertexBufferObject);
  85. glGenBuffers(1, &elementBufferObject);
  86. glBindVertexArray(vertexArrayObject);
  87. glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
  88. glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
  89. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferObject);
  90. glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
  91. glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), nullptr);
  92. glEnableVertexAttribArray(0);
  93. glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), reinterpret_cast<void*>(3 * sizeof(float)));
  94. glEnableVertexAttribArray(1);
  95. glGenTextures(1, &texture);
  96. glBindTexture(GL_TEXTURE_2D, texture);
  97. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
  98. glGenerateMipmap(GL_TEXTURE_2D);
  99. glBindVertexArray(0); // protect what we created against any further modification
  100. }
  101. void InputComponent::render() {
  102. //std::cout << "InputComponent::render - at " << (int)x << "," << (int)y << std::endl;
  103. //std::cout << "InputComponent::render - boundToPage " << boundToPage << std::endl;
  104. GLenum glErr=glGetError();
  105. if(glErr != GL_NO_ERROR) {
  106. std::cout << "InputComponent::render - start not ok: " << glErr << std::endl;
  107. }
  108. if (verticesDirty) {
  109. //std::cout << "BoxComponent::render - update dirty vertex" << std::endl;
  110. glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
  111. glErr=glGetError();
  112. if(glErr != GL_NO_ERROR) {
  113. std::cout << "InputComponent::render - glBindBuffer not ok: " << glErr << std::endl;
  114. }
  115. glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
  116. glErr=glGetError();
  117. if(glErr != GL_NO_ERROR) {
  118. std::cout << "InputComponent::render - glBufferData not ok: " << glErr << std::endl;
  119. }
  120. verticesDirty = false;
  121. }
  122. glBindVertexArray(vertexArrayObject);
  123. glErr=glGetError();
  124. if(glErr != GL_NO_ERROR) {
  125. std::cout << "InputComponent::render - glBindVertexArray not ok: " << glErr << std::endl;
  126. }
  127. glBindTexture(GL_TEXTURE_2D, texture);
  128. glErr=glGetError();
  129. if(glErr != GL_NO_ERROR) {
  130. std::cout << "InputComponent::render - glBindTexture not ok: " << glErr << std::endl;
  131. }
  132. glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
  133. glErr=glGetError();
  134. if(glErr != GL_NO_ERROR) {
  135. std::cout << "InputComponent::render - glDrawElements not ok: " << glErr << std::endl;
  136. }
  137. glBindVertexArray(0);
  138. // can actuall delete vertices here
  139. if (userInputText) {
  140. // make sure we're using win's transformMatrix
  141. Shader *fontShader = ShaderLoader::getShader(VertexShader(fontVertexShaderSource),
  142. FragmentShader(fontFragmentShaderSource));
  143. fontShader->bind();
  144. if (!boundToPage) {
  145. GLint transformLocation = fontShader->uniform("transform");
  146. glErr=glGetError();
  147. if(glErr != GL_NO_ERROR) {
  148. std::cout << "InputComponent::render - glGetUniformLocation not ok: " << glErr << std::endl;
  149. }
  150. // it's about the document transformMatrix
  151. glUniformMatrix4fv(transformLocation, 1, GL_FALSE, window->transformMatrix);
  152. glErr=glGetError();
  153. if(glErr != GL_NO_ERROR) {
  154. std::cout << "InputComponent::render - glUniformMatrix4fv not ok: " << glErr << std::endl;
  155. }
  156. }
  157. //std::cout << "rendering some text" << std::endl;
  158. userInputText->render();
  159. Shader *textureShader = ShaderLoader::getShader(VertexShader(textureVertexShaderSource),
  160. FragmentShader(textureFragmentShaderSource));
  161. textureShader->bind();
  162. }
  163. if (focused) {
  164. //std::cout << "Rendering cursor" << std::endl;
  165. // blink cursor
  166. if (cursorTimer != nullptr) {
  167. scheduler->clearInterval(cursorTimer);
  168. }
  169. cursorTimer = scheduler->setInterval([this]() {
  170. this->showCursor = !this->showCursor;
  171. //std::cout << "showCursor " << this->showCursor << std::endl;
  172. this->win->renderDirty = true;
  173. }, 500);
  174. // render it if we need to
  175. if (showCursor) {
  176. cursorBox->render();
  177. }
  178. }
  179. }
  180. void InputComponent::resize(const int passedWindowWidth, const int passedWindowHeight) {
  181. //std::cout << "InputComponent::resize" << std::endl;
  182. //std::cout << "InputComponent::resize - rasterizing at " << (int)x << "x" << (int)y << " size: " << (int)width << "x" << (int)height << std::endl;
  183. // maybe already done at component::resize
  184. // set up state
  185. windowWidth = passedWindowWidth;
  186. windowHeight = passedWindowHeight;
  187. //std::cout << "InputComponent::resize - boxShader: " << useBoxShader << " boundToPage: " << boundToPage << std::endl;
  188. /*
  189. if (!boundToPage) {
  190. // ok because box shader is anchored to the bottom of the screen
  191. // if we resize Y (increase height), we need to rebind
  192. int yDiff = windowHeight - lastRenderedWindowHeight;
  193. //std::cout << "InputComponent::resize - Adjusting y: " << y << " by " << yDiff << std::endl;
  194. this->y += yDiff;
  195. lastRenderedWindowHeight = windowHeight;
  196. }
  197. */
  198. // turning this off breaks coordinates
  199. //boundToPage = true;
  200. /*
  201. useBoxShader = true;
  202. for (int i = 0; i < 3; i++) {
  203. data[0][0][i] = 0xf0; // set RGB color
  204. }
  205. data[0][0][3] = 0xff; // set alpha
  206. */
  207. //std::cout << "InputComponent::resize - placing box at " << (int)x << "," << (int)y << " size: " << (int)width << "x" << (int)height << std::endl;
  208. float vx = x;
  209. float vy = y;
  210. if (boundToPage) {
  211. vy = this->windowHeight + y - height;
  212. //std::cout << "InputComponent::resize - Adjust y to " << vy << " from " << y << " h: " << (int)height << std::endl;
  213. }
  214. pointToViewport(vx, vy);
  215. float vWidth = width;
  216. float vHeight = height;
  217. distanceToViewport(vWidth, vHeight);
  218. float vx1 = vx + vWidth;
  219. float vy1 = vy + vHeight;
  220. //std::cout << "InputComponent::resize - placing box at GL " << vx << "," << vy << " to " << vx1 << "," << vy1 << " size: " << vWidth << "x" << vHeight << std::endl;
  221. vertices[(0 * 5) + 0] = vx;
  222. vertices[(0 * 5) + 1] = vy1;
  223. vertices[(1 * 5) + 0] = vx1;
  224. vertices[(1 * 5) + 1] = vy1;
  225. vertices[(2 * 5) + 0] = vx1;
  226. vertices[(2 * 5) + 1] = vy;
  227. vertices[(3 * 5) + 0] = vx;
  228. vertices[(3 * 5) + 1] = vy;
  229. glBindVertexArray(vertexArrayObject);
  230. glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
  231. glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
  232. glBindVertexArray(0); // protect what we created against any further modification
  233. //updateText();
  234. if (userInputText) {
  235. // do we need updateText here?
  236. userInputText->resize(passedWindowWidth, passedWindowHeight);
  237. }
  238. }
  239. void InputComponent::addChar(char c) {
  240. value+=c;
  241. //std::cout << "InputComponent::addChar - at " << (int)x << "," << (int)y << std::endl;
  242. updateText();
  243. }
  244. void InputComponent::backSpace() {
  245. value=value.substr(0, value.length() - 1);
  246. //std::cout << "InputComponent::backSpace - at " << (int)x << "," << (int)y << std::endl;
  247. updateText();
  248. }
  249. void InputComponent::updateText() {
  250. //std::cout << "InputComponent::updateText - input value is now: " << value << std::endl;
  251. // maybe tie the fontsize to height
  252. if (userInputText) {
  253. delete userInputText;
  254. }
  255. userInputText=new TextComponent(value, 0, 0, 12, false, 0x000000FF, windowWidth, windowHeight);
  256. //std::cout << "placing userInputText at " << static_cast<int>(x) << "," << static_cast<int>(y) << std::endl;
  257. userInputText->x = x;
  258. if (y < 0) {
  259. userInputText->y = y;
  260. } else {
  261. userInputText->y = y - windowHeight + 16;
  262. }
  263. userInputText->boundToPage = this->boundToPage;
  264. //std::cout << "placed userInputText at " << static_cast<int>(x) << "," << static_cast<int>(y - windowHeight) << std::endl;
  265. // 125 pixels width
  266. // but first we need to know how wide the text is
  267. const std::shared_ptr<TextRasterizer> textRasterizer=rasterizerCache->loadFont(12, false); // fontSize, bold
  268. rasterizationRequest request;
  269. request.text = value;
  270. request.startX = x;
  271. request.availableWidth = windowWidth;
  272. request.sourceStartX = 0;
  273. request.sourceStartY = 0;
  274. request.noWrap = true;
  275. std::unique_ptr<std::pair<int, int>> textInfo = textRasterizer->size(request);
  276. if (textInfo.get() == nullptr) {
  277. std::cout << "InputComponent::updateText - couldn't estimate value[" << value << "] size" << std::endl;
  278. return;
  279. }
  280. //int textWidth = textInfo->first;
  281. int estWidth = std::get<0>(*textInfo.get());
  282. //int estHeight = std::get<1>(*textInfo.get());
  283. userInputText->rasterStartX = 0;
  284. userInputText->rasterStartY = 0;
  285. //std::cout << "InputComponent::updateText - estWidth: " << estWidth << " width: " << static_cast<int>(width) << std::endl;
  286. if (estWidth > width) {
  287. //std::cout << "scrolling text" << std::endl;
  288. userInputText->rasterStartX = estWidth - width;
  289. }
  290. // this is texture shader coordinates now (not text shader coords)
  291. cursorBox->x = x + estWidth;
  292. if (boundToPage) {
  293. cursorBox->y = windowHeight + y - 13;
  294. } else {
  295. cursorBox->y = y;
  296. }
  297. //std::cout << "placing cursor at " << (int)cursorBox->x << "," << (int)cursorBox->y << std::endl;
  298. cursorBox->resize(windowWidth, windowHeight);
  299. userInputText->noWrap = true;
  300. // why does changing the width mess shit up?
  301. //std::cout << "InputComponent::updateText - our width: " << static_cast<int>(width) << " windowWidth: " << windowWidth << std::endl;
  302. userInputText->resize(windowWidth, windowHeight, width); // need to make sure there's a texture
  303. window->renderDirty = true;
  304. }