Form.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  1. #include "Base.h"
  2. #include "Form.h"
  3. #include "AbsoluteLayout.h"
  4. #include "FlowLayout.h"
  5. #include "VerticalLayout.h"
  6. #include "Game.h"
  7. #include "Theme.h"
  8. #include "Label.h"
  9. #include "Button.h"
  10. #include "CheckBox.h"
  11. #include "Scene.h"
  12. #define FORM_VSH \
  13. "uniform mat4 u_worldViewProjectionMatrix;\n" \
  14. "attribute vec3 a_position;\n" \
  15. "attribute vec2 a_texCoord;\n" \
  16. "varying vec2 v_texCoord;\n" \
  17. "void main()\n" \
  18. "{\n" \
  19. "gl_Position = u_worldViewProjectionMatrix * vec4(a_position, 1);\n" \
  20. "v_texCoord = a_texCoord;\n" \
  21. "}\n"
  22. #define FORM_FSH \
  23. "#ifdef OPENGL_ES\n" \
  24. "precision highp float;\n" \
  25. "#endif\n" \
  26. "varying vec2 v_texCoord;\n" \
  27. "uniform sampler2D u_texture;\n" \
  28. "void main()\n" \
  29. "{\n" \
  30. "gl_FragColor = texture2D(u_texture, v_texCoord);\n" \
  31. "}\n"
  32. namespace gameplay
  33. {
  34. static Effect* __formEffect = NULL;
  35. static std::vector<Form*> __forms;
  36. Form::Form() : _theme(NULL), _frameBuffer(NULL), _spriteBatch(NULL), _node(NULL), _nodeQuad(NULL), _nodeMaterial(NULL) , _u2(0), _v1(0)
  37. {
  38. }
  39. Form::~Form()
  40. {
  41. SAFE_RELEASE(_node);
  42. SAFE_DELETE(_spriteBatch);
  43. SAFE_RELEASE(_frameBuffer);
  44. SAFE_RELEASE(_theme);
  45. if (__formEffect)
  46. {
  47. if (__formEffect->getRefCount() == 1)
  48. {
  49. __formEffect->release();
  50. __formEffect = NULL;
  51. }
  52. }
  53. // Remove this Form from the global list.
  54. std::vector<Form*>::iterator it = std::find(__forms.begin(), __forms.end(), this);
  55. if (it != __forms.end())
  56. {
  57. __forms.erase(it);
  58. }
  59. }
  60. Form* Form::create(const char* id, Theme::Style* style, Layout::Type layoutType)
  61. {
  62. GP_ASSERT(style);
  63. Layout* layout;
  64. switch (layoutType)
  65. {
  66. case Layout::LAYOUT_ABSOLUTE:
  67. layout = AbsoluteLayout::create();
  68. break;
  69. case Layout::LAYOUT_FLOW:
  70. layout = FlowLayout::create();
  71. break;
  72. case Layout::LAYOUT_VERTICAL:
  73. layout = VerticalLayout::create();
  74. break;
  75. default:
  76. GP_ERROR("Unsupported layout type '%d'.", layoutType);
  77. break;
  78. }
  79. Form* form = new Form();
  80. if (id)
  81. form->_id = id;
  82. form->_style = style;
  83. form->_layout = layout;
  84. form->_theme = style->getTheme();
  85. form->_theme->addRef();
  86. // Get default projection matrix.
  87. Game* game = Game::getInstance();
  88. Matrix::createOrthographicOffCenter(0, game->getWidth(), game->getHeight(), 0, 0, 1, &form->_defaultProjectionMatrix);
  89. form->updateBounds();
  90. __forms.push_back(form);
  91. return form;
  92. }
  93. Form* Form::create(const char* url)
  94. {
  95. // Load Form from .form file.
  96. Properties* properties = Properties::create(url);
  97. if (properties == NULL)
  98. {
  99. GP_ASSERT(properties);
  100. return NULL;
  101. }
  102. // Check if the Properties is valid and has a valid namespace.
  103. Properties* formProperties = (strlen(properties->getNamespace()) > 0) ? properties : properties->getNextNamespace();
  104. assert(formProperties);
  105. if (!formProperties || !(strcmp(formProperties->getNamespace(), "form") == 0))
  106. {
  107. GP_ASSERT(formProperties);
  108. SAFE_DELETE(properties);
  109. return NULL;
  110. }
  111. // Create new form with given ID, theme and layout.
  112. const char* themeFile = formProperties->getString("theme");
  113. const char* layoutString = formProperties->getString("layout");
  114. Layout* layout;
  115. switch (getLayoutType(layoutString))
  116. {
  117. case Layout::LAYOUT_ABSOLUTE:
  118. layout = AbsoluteLayout::create();
  119. break;
  120. case Layout::LAYOUT_FLOW:
  121. layout = FlowLayout::create();
  122. break;
  123. case Layout::LAYOUT_VERTICAL:
  124. layout = VerticalLayout::create();
  125. break;
  126. default:
  127. GP_ERROR("Unsupported layout type '%d'.", getLayoutType(layoutString));
  128. break;
  129. }
  130. Theme* theme = Theme::create(themeFile);
  131. GP_ASSERT(theme);
  132. Form* form = new Form();
  133. form->_layout = layout;
  134. form->_theme = theme;
  135. // Get default projection matrix.
  136. Game* game = Game::getInstance();
  137. Matrix::createOrthographicOffCenter(0, game->getWidth(), game->getHeight(), 0, 0, 1, &form->_defaultProjectionMatrix);
  138. Theme::Style* style = NULL;
  139. const char* styleName = formProperties->getString("style");
  140. if (styleName)
  141. {
  142. style = theme->getStyle(styleName);
  143. }
  144. else
  145. {
  146. style = theme->getEmptyStyle();
  147. }
  148. form->initialize(style, formProperties);
  149. form->_consumeInputEvents = formProperties->getBool("consumeInputEvents", true);
  150. // Alignment
  151. if ((form->_alignment & Control::ALIGN_BOTTOM) == Control::ALIGN_BOTTOM)
  152. {
  153. form->_bounds.y = Game::getInstance()->getHeight() - form->_bounds.height;
  154. }
  155. else if ((form->_alignment & Control::ALIGN_VCENTER) == Control::ALIGN_VCENTER)
  156. {
  157. form->_bounds.y = Game::getInstance()->getHeight() * 0.5f - form->_bounds.height * 0.5f;
  158. }
  159. if ((form->_alignment & Control::ALIGN_RIGHT) == Control::ALIGN_RIGHT)
  160. {
  161. form->_bounds.x = Game::getInstance()->getWidth() - form->_bounds.width;
  162. }
  163. else if ((form->_alignment & Control::ALIGN_HCENTER) == Control::ALIGN_HCENTER)
  164. {
  165. form->_bounds.x = Game::getInstance()->getWidth() * 0.5f - form->_bounds.width * 0.5f;
  166. }
  167. form->_scroll = getScroll(formProperties->getString("scroll"));
  168. form->_scrollBarsAutoHide = formProperties->getBool("scrollBarsAutoHide");
  169. if (form->_scrollBarsAutoHide)
  170. {
  171. form->_scrollBarOpacity = 0.0f;
  172. }
  173. // Add all the controls to the form.
  174. form->addControls(theme, formProperties);
  175. SAFE_DELETE(properties);
  176. form->updateBounds();
  177. __forms.push_back(form);
  178. return form;
  179. }
  180. Form* Form::getForm(const char* id)
  181. {
  182. std::vector<Form*>::const_iterator it;
  183. for (it = __forms.begin(); it < __forms.end(); ++it)
  184. {
  185. Form* f = *it;
  186. GP_ASSERT(f);
  187. if (strcmp(id, f->getId()) == 0)
  188. {
  189. return f;
  190. }
  191. }
  192. return NULL;
  193. }
  194. Theme* Form::getTheme() const
  195. {
  196. return _theme;
  197. }
  198. void Form::setSize(float width, float height)
  199. {
  200. if (_autoWidth)
  201. {
  202. width = Game::getInstance()->getWidth();
  203. }
  204. if (_autoHeight)
  205. {
  206. height = Game::getInstance()->getHeight();
  207. }
  208. if (width != 0.0f && height != 0.0f &&
  209. (width != _bounds.width || height != _bounds.height))
  210. {
  211. // Width and height must be powers of two to create a texture.
  212. unsigned int w = nextPowerOfTwo(width);
  213. unsigned int h = nextPowerOfTwo(height);
  214. _u2 = width / (float)w;
  215. _v1 = height / (float)h;
  216. // Create framebuffer if necessary.
  217. if (_frameBuffer)
  218. SAFE_RELEASE(_frameBuffer)
  219. _frameBuffer = FrameBuffer::create(_id.c_str(), w, h);
  220. GP_ASSERT(_frameBuffer);
  221. // Re-create projection matrix.
  222. Matrix::createOrthographicOffCenter(0, width, height, 0, 0, 1, &_projectionMatrix);
  223. // Re-create sprite batch.
  224. SAFE_DELETE(_spriteBatch);
  225. _spriteBatch = SpriteBatch::create(_frameBuffer->getRenderTarget()->getTexture());
  226. GP_ASSERT(_spriteBatch);
  227. // Clear the framebuffer black
  228. Game* game = Game::getInstance();
  229. _frameBuffer->bind();
  230. Rectangle prevViewport = game->getViewport();
  231. game->setViewport(Rectangle(0, 0, width, height));
  232. _theme->setProjectionMatrix(_projectionMatrix);
  233. game->clear(Game::CLEAR_COLOR, Vector4::zero(), 1.0, 0);
  234. _theme->setProjectionMatrix(_defaultProjectionMatrix);
  235. FrameBuffer::bindDefault();
  236. game->setViewport(prevViewport);
  237. }
  238. _bounds.width = width;
  239. _bounds.height = height;
  240. _dirty = true;
  241. }
  242. void Form::setBounds(const Rectangle& bounds)
  243. {
  244. setPosition(bounds.x, bounds.y);
  245. setSize(bounds.width, bounds.height);
  246. }
  247. void Form::setWidth(float width)
  248. {
  249. setSize(width, _bounds.height);
  250. }
  251. void Form::setHeight(float height)
  252. {
  253. setSize(_bounds.width, height);
  254. }
  255. void Form::setAutoWidth(bool autoWidth)
  256. {
  257. if (_autoWidth != autoWidth)
  258. {
  259. _autoWidth = autoWidth;
  260. _dirty = true;
  261. if (_autoWidth)
  262. {
  263. setSize(_bounds.width, Game::getInstance()->getWidth());
  264. }
  265. }
  266. }
  267. void Form::setAutoHeight(bool autoHeight)
  268. {
  269. if (_autoHeight != autoHeight)
  270. {
  271. _autoHeight = autoHeight;
  272. _dirty = true;
  273. if (_autoHeight)
  274. {
  275. setSize(_bounds.width, Game::getInstance()->getHeight());
  276. }
  277. }
  278. }
  279. static Effect* createEffect()
  280. {
  281. Effect* effect = NULL;
  282. if (__formEffect == NULL)
  283. {
  284. __formEffect = Effect::createFromSource(FORM_VSH, FORM_FSH);
  285. if (__formEffect == NULL)
  286. {
  287. GP_ERROR("Unable to load form effect.");
  288. return NULL;
  289. }
  290. effect = __formEffect;
  291. }
  292. else
  293. {
  294. effect = __formEffect;
  295. }
  296. return effect;
  297. }
  298. void Form::setNode(Node* node)
  299. {
  300. // If the user wants a custom node then we need to create a 3D quad
  301. if (node && node != _node)
  302. {
  303. // Set this Form up to be 3D by initializing a quad.
  304. float x2 = _bounds.width;
  305. float y2 = _bounds.height;
  306. float vertices[] =
  307. {
  308. 0, y2, 0, 0, _v1,
  309. 0, 0, 0, 0, 0,
  310. x2, y2, 0, _u2, _v1,
  311. x2, 0, 0, _u2, 0
  312. };
  313. VertexFormat::Element elements[] =
  314. {
  315. VertexFormat::Element(VertexFormat::POSITION, 3),
  316. VertexFormat::Element(VertexFormat::TEXCOORD0, 2)
  317. };
  318. Mesh* mesh = Mesh::createMesh(VertexFormat(elements, 2), 4, false);
  319. GP_ASSERT(mesh);
  320. mesh->setPrimitiveType(Mesh::TRIANGLE_STRIP);
  321. mesh->setVertexData(vertices, 0, 4);
  322. _nodeQuad = Model::create(mesh);
  323. SAFE_RELEASE(mesh);
  324. GP_ASSERT(_nodeQuad);
  325. // Create the effect and material
  326. Effect* effect = createEffect();
  327. GP_ASSERT(effect);
  328. _nodeMaterial = Material::create(effect);
  329. GP_ASSERT(_nodeMaterial);
  330. _nodeQuad->setMaterial(_nodeMaterial);
  331. _nodeMaterial->release();
  332. node->setModel(_nodeQuad);
  333. _nodeQuad->release();
  334. // Bind the WorldViewProjection matrix.
  335. _nodeMaterial->setParameterAutoBinding("u_worldViewProjectionMatrix", RenderState::WORLD_VIEW_PROJECTION_MATRIX);
  336. // Bind the texture from the framebuffer and set the texture to clamp
  337. Texture::Sampler* sampler = Texture::Sampler::create(_frameBuffer->getRenderTarget()->getTexture());
  338. GP_ASSERT(sampler);
  339. sampler->setWrapMode(Texture::CLAMP, Texture::CLAMP);
  340. _nodeMaterial->getParameter("u_texture")->setValue(sampler);
  341. sampler->release();
  342. RenderState::StateBlock* rsBlock = _nodeMaterial->getStateBlock();
  343. rsBlock->setDepthWrite(true);
  344. rsBlock->setBlend(true);
  345. rsBlock->setBlendSrc(RenderState::BLEND_SRC_ALPHA);
  346. rsBlock->setBlendDst(RenderState::BLEND_ONE_MINUS_SRC_ALPHA);
  347. }
  348. _node = node;
  349. }
  350. void Form::update(float elapsedTime)
  351. {
  352. updateBounds();
  353. }
  354. void Form::updateBounds()
  355. {
  356. if (isDirty())
  357. {
  358. _clearBounds.set(_absoluteClipBounds);
  359. // Calculate the clipped bounds.
  360. float x = 0;
  361. float y = 0;
  362. float width = _bounds.width;
  363. float height = _bounds.height;
  364. Rectangle clip(0, 0, _bounds.width, _bounds.height);
  365. float clipX2 = clip.x + clip.width;
  366. float x2 = clip.x + x + width;
  367. if (x2 > clipX2)
  368. width -= x2 - clipX2;
  369. float clipY2 = clip.y + clip.height;
  370. float y2 = clip.y + y + height;
  371. if (y2 > clipY2)
  372. height -= y2 - clipY2;
  373. if (x < 0)
  374. {
  375. width += x;
  376. x = -x;
  377. }
  378. else
  379. {
  380. x = 0;
  381. }
  382. if (y < 0)
  383. {
  384. height += y;
  385. y = -y;
  386. }
  387. else
  388. {
  389. y = 0;
  390. }
  391. _clipBounds.set(x, y, width, height);
  392. // Calculate the absolute bounds.
  393. x = 0;
  394. y = 0;
  395. _absoluteBounds.set(x, y, _bounds.width, _bounds.height);
  396. // Calculate the absolute viewport bounds. Absolute bounds minus border and padding.
  397. const Theme::Border& border = getBorder(_state);
  398. const Theme::Padding& padding = getPadding();
  399. x += border.left + padding.left;
  400. y += border.top + padding.top;
  401. width = _bounds.width - border.left - padding.left - border.right - padding.right;
  402. height = _bounds.height - border.top - padding.top - border.bottom - padding.bottom;
  403. _viewportBounds.set(x, y, width, height);
  404. // Calculate the clip area. Absolute bounds, minus border and padding, clipped to the parent container's clip area.
  405. clipX2 = clip.x + clip.width;
  406. x2 = x + width;
  407. if (x2 > clipX2)
  408. width = clipX2 - x;
  409. clipY2 = clip.y + clip.height;
  410. y2 = y + height;
  411. if (y2 > clipY2)
  412. height = clipY2 - y;
  413. if (x < clip.x)
  414. {
  415. float dx = clip.x - x;
  416. width -= dx;
  417. x = clip.x;
  418. }
  419. if (y < clip.y)
  420. {
  421. float dy = clip.y - y;
  422. height -= dy;
  423. y = clip.y;
  424. }
  425. _viewportClipBounds.set(x, y, width, height);
  426. _absoluteClipBounds.set(x - border.left - padding.left, y - border.top - padding.top,
  427. width + border.left + padding.left + border.right + padding.right,
  428. height + border.top + padding.top + border.bottom + padding.bottom);
  429. if (_clearBounds.isEmpty())
  430. {
  431. _clearBounds.set(_absoluteClipBounds);
  432. }
  433. // Cache themed attributes for performance.
  434. _skin = getSkin(_state);
  435. _opacity = getOpacity(_state);
  436. // Get scrollbar images and diminish clipping bounds to make room for scrollbars.
  437. if ((_scroll & SCROLL_HORIZONTAL) == SCROLL_HORIZONTAL)
  438. {
  439. _scrollBarLeftCap = getImage("scrollBarLeftCap", _state);
  440. _scrollBarHorizontal = getImage("horizontalScrollBar", _state);
  441. _scrollBarRightCap = getImage("scrollBarRightCap", _state);
  442. _viewportClipBounds.height -= _scrollBarHorizontal->getRegion().height;
  443. }
  444. if ((_scroll & SCROLL_VERTICAL) == SCROLL_VERTICAL)
  445. {
  446. _scrollBarTopCap = getImage("scrollBarTopCap", _state);
  447. _scrollBarVertical = getImage("verticalScrollBar", _state);
  448. _scrollBarBottomCap = getImage("scrollBarBottomCap", _state);
  449. _viewportClipBounds.width -= _scrollBarVertical->getRegion().width;
  450. }
  451. GP_ASSERT(_layout);
  452. if (_scroll != SCROLL_NONE)
  453. updateScroll();
  454. else
  455. _layout->update(this, Vector2::zero());
  456. }
  457. }
  458. void Form::draw()
  459. {
  460. // The first time a form is drawn, its contents are rendered into a framebuffer.
  461. // The framebuffer will only be drawn into again when the contents of the form change.
  462. // If this form has a node then it's a 3D form and the framebuffer will be used
  463. // to texture a quad. The quad will be given the same dimensions as the form and
  464. // must be transformed appropriately by the user, unless they call setQuad() themselves.
  465. // On the other hand, if this form has not been set on a node, SpriteBatch will be used
  466. // to render the contents of the framebuffer directly to the display.
  467. // Check whether this form has changed since the last call to draw() and if so, render into the framebuffer.
  468. if (isDirty())
  469. {
  470. GP_ASSERT(_frameBuffer);
  471. _frameBuffer->bind();
  472. Game* game = Game::getInstance();
  473. Rectangle prevViewport = game->getViewport();
  474. game->setViewport(Rectangle(0, 0, _bounds.width, _bounds.height));
  475. GP_ASSERT(_theme);
  476. _theme->setProjectionMatrix(_projectionMatrix);
  477. Container::draw(_theme->getSpriteBatch(), Rectangle(0, 0, _bounds.width, _bounds.height),
  478. true/*WAS _skin!=NULL*/, false, _bounds.height);
  479. _theme->setProjectionMatrix(_defaultProjectionMatrix);
  480. // Rebind the default framebuffer and game viewport.
  481. FrameBuffer::bindDefault();
  482. // restore the previous game viewport
  483. game->setViewport(prevViewport);
  484. }
  485. // Draw either with a 3D quad or sprite batch
  486. if (_node)
  487. {
  488. // If we have the node set, then draw a 3D quad model
  489. _nodeQuad->draw();
  490. }
  491. else
  492. {
  493. // Otherwise we draw the framebuffer in ortho space with a spritebatch.
  494. if (!_spriteBatch)
  495. {
  496. _spriteBatch = SpriteBatch::create(_frameBuffer->getRenderTarget()->getTexture());
  497. GP_ASSERT(_spriteBatch);
  498. }
  499. _spriteBatch->start();
  500. _spriteBatch->draw(_bounds.x, _bounds.y, 0, _bounds.width, _bounds.height, 0, _v1, _u2, 0, Vector4::one());
  501. _spriteBatch->finish();
  502. }
  503. }
  504. const char* Form::getType() const
  505. {
  506. return "form";
  507. }
  508. bool Form::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
  509. {
  510. // Check for a collision with each Form in __forms.
  511. // Pass the event on.
  512. bool eventConsumed = false;
  513. size_t size = __forms.size();
  514. for (size_t i = 0; i < size; ++i)
  515. {
  516. Form* form = __forms[i];
  517. GP_ASSERT(form);
  518. if (form->isEnabled())
  519. {
  520. if (form->_node)
  521. {
  522. Vector3 point;
  523. if (form->projectPoint(x, y, &point))
  524. {
  525. const Rectangle& bounds = form->getBounds();
  526. if (form->getState() == Control::FOCUS ||
  527. (evt == Touch::TOUCH_PRESS &&
  528. point.x >= bounds.x &&
  529. point.x <= bounds.x + bounds.width &&
  530. point.y >= bounds.y &&
  531. point.y <= bounds.y + bounds.height))
  532. {
  533. eventConsumed |= form->touchEvent(evt, point.x - bounds.x, bounds.height - point.y - bounds.y, contactIndex);
  534. }
  535. }
  536. }
  537. else
  538. {
  539. // Simply compare with the form's bounds.
  540. const Rectangle& bounds = form->getBounds();
  541. if (form->getState() == Control::FOCUS ||
  542. (evt == Touch::TOUCH_PRESS &&
  543. x >= bounds.x &&
  544. x <= bounds.x + bounds.width &&
  545. y >= bounds.y &&
  546. y <= bounds.y + bounds.height))
  547. {
  548. // Pass on the event's position relative to the form.
  549. eventConsumed |= form->touchEvent(evt, x - bounds.x, y - bounds.y, contactIndex);
  550. }
  551. }
  552. }
  553. }
  554. return eventConsumed;
  555. }
  556. bool Form::keyEventInternal(Keyboard::KeyEvent evt, int key)
  557. {
  558. size_t size = __forms.size();
  559. for (size_t i = 0; i < size; ++i)
  560. {
  561. Form* form = __forms[i];
  562. GP_ASSERT(form);
  563. if (form->isEnabled())
  564. {
  565. if (form->keyEvent(evt, key))
  566. return true;
  567. }
  568. }
  569. return false;
  570. }
  571. bool Form::mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
  572. {
  573. bool eventConsumed = false;
  574. for (size_t i = 0; i < __forms.size(); ++i)
  575. {
  576. Form* form = __forms[i];
  577. GP_ASSERT(form);
  578. if (form->isEnabled())
  579. {
  580. if (form->_node)
  581. {
  582. Vector3 point;
  583. if (form->projectPoint(x, y, &point))
  584. {
  585. const Rectangle& bounds = form->getBounds();
  586. if (form->getState() == Control::FOCUS ||
  587. ((evt == Mouse::MOUSE_PRESS_LEFT_BUTTON ||
  588. evt == Mouse::MOUSE_PRESS_MIDDLE_BUTTON ||
  589. evt == Mouse::MOUSE_PRESS_RIGHT_BUTTON ||
  590. evt == Mouse::MOUSE_WHEEL) &&
  591. point.x >= bounds.x &&
  592. point.x <= bounds.x + bounds.width &&
  593. point.y >= bounds.y &&
  594. point.y <= bounds.y + bounds.height))
  595. {
  596. eventConsumed |= form->mouseEvent(evt, point.x - bounds.x, bounds.height - point.y - bounds.y, wheelDelta);
  597. }
  598. }
  599. }
  600. else
  601. {
  602. // Simply compare with the form's bounds.
  603. const Rectangle& bounds = form->getBounds();
  604. if (form->getState() == Control::FOCUS ||
  605. ((evt == Mouse::MOUSE_PRESS_LEFT_BUTTON ||
  606. evt == Mouse::MOUSE_PRESS_MIDDLE_BUTTON ||
  607. evt == Mouse::MOUSE_PRESS_RIGHT_BUTTON ||
  608. evt == Mouse::MOUSE_WHEEL) &&
  609. x >= bounds.x &&
  610. x <= bounds.x + bounds.width &&
  611. y >= bounds.y &&
  612. y <= bounds.y + bounds.height))
  613. {
  614. // Pass on the event's position relative to the form.
  615. eventConsumed |= form->mouseEvent(evt, x - bounds.x, y - bounds.y, wheelDelta);
  616. }
  617. }
  618. }
  619. }
  620. return eventConsumed;
  621. }
  622. bool Form::projectPoint(int x, int y, Vector3* point)
  623. {
  624. Scene* scene = _node->getScene();
  625. Camera* camera;
  626. if (scene && (camera = scene->getActiveCamera()))
  627. {
  628. // Get info about the form's position.
  629. Matrix m = _node->getWorldMatrix();
  630. Vector3 min(0, 0, 0);
  631. m.transformPoint(&min);
  632. // Unproject point into world space.
  633. Ray ray;
  634. camera->pickRay(Game::getInstance()->getViewport(), x, y, &ray);
  635. // Find the quad's plane. We know its normal is the quad's forward vector.
  636. Vector3 normal = _node->getForwardVectorWorld();
  637. // To get the plane's distance from the origin, we'll find the distance from the plane defined
  638. // by the quad's forward vector and one of its points to the plane defined by the same vector and the origin.
  639. const float& a = normal.x; const float& b = normal.y; const float& c = normal.z;
  640. const float d = -(a*min.x) - (b*min.y) - (c*min.z);
  641. const float distance = fabs(d) / sqrt(a*a + b*b + c*c);
  642. Plane plane(normal, -distance);
  643. // Check for collision with plane.
  644. float collisionDistance = ray.intersects(plane);
  645. if (collisionDistance != Ray::INTERSECTS_NONE)
  646. {
  647. // Multiply the ray's direction vector by collision distance and add that to the ray's origin.
  648. point->set(ray.getOrigin() + collisionDistance*ray.getDirection());
  649. // Project this point into the plane.
  650. m.invert();
  651. m.transformPoint(point);
  652. return true;
  653. }
  654. }
  655. return false;
  656. }
  657. unsigned int Form::nextPowerOfTwo(unsigned int v)
  658. {
  659. if (!((v & (v - 1)) == 0))
  660. {
  661. v--;
  662. v |= v >> 1;
  663. v |= v >> 2;
  664. v |= v >> 4;
  665. v |= v >> 8;
  666. v |= v >> 16;
  667. return v + 1;
  668. }
  669. else
  670. {
  671. return v;
  672. }
  673. }
  674. }