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

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