PageRenderTime 29ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/src/lipsofsuna/render/render32/render-light.c

https://github.com/deldiablo/GodheadLips
C | 769 lines | 514 code | 78 blank | 177 comment | 30 complexity | ae145491bda4430fcd0298378dddd310 MD5 | raw file
  1. /* Lips of Suna
  2. * Copyright© 2007-2011 Lips of Suna development team.
  3. *
  4. * Lips of Suna is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Lesser General Public License as
  6. * published by the Free Software Foundation, either version 3 of the
  7. * License, or (at your option) any later version.
  8. *
  9. * Lips of Suna is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public License
  15. * along with Lips of Suna. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. /**
  18. * \addtogroup LIRen Render
  19. * @{
  20. * \addtogroup LIRenLight32 Light32
  21. * @{
  22. */
  23. #include "lipsofsuna/system.h"
  24. #include "render-context.h"
  25. #include "render-light.h"
  26. #include "render-lighting.h"
  27. #include "render-private.h"
  28. #include "../render-scene.h"
  29. #include "../render-private.h"
  30. #define LIGHT_CONTRIBUTION_EPSILON 0.001f
  31. static void private_update_bounds (
  32. LIRenLight32* self);
  33. static void private_update_shadow (
  34. LIRenLight32* self);
  35. /*****************************************************************************/
  36. /**
  37. * \brief Creates a new light source.
  38. * \param scene Scene.
  39. * \param ambient Ambient color, array of 4 floats.
  40. * \param diffuse Diffuse color, array of 4 floats.
  41. * \param specular Specular color, array of 4 floats.
  42. * \param equation Attenuation equation, array of 3 floats.
  43. * \param cutoff Spot cutoff in radians.
  44. * \param exponent Spot expoent.
  45. * \param shadows Nonzero if the lamp casts shadows.
  46. * \return New light source or NULL.
  47. */
  48. LIRenLight32* liren_light32_new (
  49. LIRenScene32* scene,
  50. const float* ambient,
  51. const float* diffuse,
  52. const float* specular,
  53. const float* equation,
  54. float cutoff,
  55. float exponent,
  56. int shadows)
  57. {
  58. LIRenLight32* self;
  59. /* Allocate self. */
  60. self = lisys_calloc (1, sizeof (LIRenLight32));
  61. if (self == NULL)
  62. return NULL;
  63. self->scene = scene;
  64. self->ambient[0] = ambient[0];
  65. self->ambient[1] = ambient[1];
  66. self->ambient[2] = ambient[2];
  67. self->ambient[3] = 1.0f;
  68. self->diffuse[0] = diffuse[0];
  69. self->diffuse[1] = diffuse[1];
  70. self->diffuse[2] = diffuse[2];
  71. self->diffuse[3] = 1.0f;
  72. self->specular[0] = specular[0];
  73. self->specular[1] = specular[1];
  74. self->specular[2] = specular[2];
  75. self->specular[3] = 1.0f;
  76. self->equation[0] = equation[0];
  77. self->equation[1] = equation[1];
  78. self->equation[2] = equation[2];
  79. self->cutoff = cutoff;
  80. self->exponent = exponent;
  81. self->shadow_far = 50.0f;
  82. self->shadow_near = 0.1f;
  83. self->projection = limat_matrix_identity ();
  84. self->modelview = limat_matrix_identity ();
  85. self->modelview_inverse = limat_matrix_identity ();
  86. self->transform = limat_transform_identity ();
  87. liren_light32_update_projection (self);
  88. liren_light32_set_shadow (self, shadows);
  89. return self;
  90. }
  91. /**
  92. * \brief Creates a new directional light source.
  93. * \param scene Scene.
  94. * \param ambient Ambient color, array of 4 floats.
  95. * \param diffuse Diffuse color, array of 4 floats.
  96. * \param specular Specular color, array of 4 floats.
  97. * \return New light source or NULL.
  98. */
  99. LIRenLight32* liren_light32_new_directional (
  100. LIRenScene32* scene,
  101. const float* ambient,
  102. const float* diffuse,
  103. const float* specular)
  104. {
  105. const float equation[3] = { 1.0f, 0.0f, 0.0f };
  106. const LIMatVector direction = { 0.0f, 0.0f, -1.0f };
  107. LIRenLight32* self;
  108. /* Create the sun. */
  109. self = liren_light32_new (scene, ambient, diffuse, specular, equation, M_PI, 0.0f, 0);
  110. if (self == NULL)
  111. return NULL;
  112. liren_light32_set_direction (self, &direction);
  113. return self;
  114. }
  115. /**
  116. * \brief Creates a new light from a model light.
  117. * \param scene Scene.
  118. * \param light Model light.
  119. * \return New light or NULL.
  120. */
  121. LIRenLight32* liren_light32_new_from_model (
  122. LIRenScene32* scene,
  123. const LIMdlNode* light)
  124. {
  125. float scale;
  126. LIMatMatrix projection;
  127. LIMatTransform transform;
  128. LIRenLight32* self;
  129. /* Allocate self. */
  130. self = liren_light32_new (scene, light->light.ambient,
  131. light->light.diffuse, light->light.specular, light->light.equation,
  132. light->light.spot.cutoff, light->light.spot.exponent,
  133. light->light.flags & LIMDL_LIGHT_FLAG_SHADOW);
  134. if (self == NULL)
  135. return NULL;
  136. /* Set transform. */
  137. self->node = light;
  138. limdl_node_get_world_transform (light, &scale, &transform);
  139. liren_light32_set_transform (self, &transform);
  140. limdl_light_get_projection (light, &projection);
  141. liren_light32_set_projection (self, &projection);
  142. return self;
  143. }
  144. /**
  145. * \brief Frees a light source.
  146. * \param self Light source.
  147. */
  148. void liren_light32_free (
  149. LIRenLight32* self)
  150. {
  151. liren_light32_set_shadow (self, 0);
  152. liren_lighting32_remove_light (self->scene->lighting, self);
  153. lisys_free (self);
  154. }
  155. /**
  156. * \brief Compares the priorities of two lights.
  157. * \param self Light source.
  158. * \param light Light source.
  159. * \return Integer indicating which light contributes more.
  160. */
  161. int liren_light32_compare (
  162. const LIRenLight32* self,
  163. const LIRenLight32* light)
  164. {
  165. /* Sorting is done primarily by priority. */
  166. /* This allows the user to decide what lights are the most important
  167. ones. If there's an ambient light in the scene, for example, the
  168. user may want to give that higher priority than other lights. */
  169. if (self->priority < light->priority)
  170. return -1;
  171. if (self->priority > light->priority)
  172. return 1;
  173. return 0;
  174. }
  175. void liren_light32_update (
  176. LIRenLight32* self)
  177. {
  178. if (self->shadow.map)
  179. private_update_shadow (self);
  180. }
  181. /**
  182. * \brief Caches the lighting values needed by shaders for fast access.
  183. * \param self Light.
  184. * \param context Context.
  185. */
  186. void liren_light32_update_cache (
  187. LIRenLight32* self,
  188. LIRenContext32* context)
  189. {
  190. LIMatMatrix matrix;
  191. LIMatVector vector;
  192. LIMatMatrix bias =
  193. {{
  194. 0.5f, 0.0f, 0.0f, 0.0f,
  195. 0.0f, 0.5f, 0.0f, 0.0f,
  196. 0.0f, 0.0f, 0.5f, 0.0f,
  197. 0.5f, 0.5f, 0.5f, 1.0f
  198. }};
  199. /* Calculate position vectors. */
  200. vector = self->transform.position;
  201. self->cache.pos_world[0] = vector.x;
  202. self->cache.pos_world[1] = vector.y;
  203. self->cache.pos_world[2] = vector.z;
  204. vector = limat_matrix_transform (context->matrix.modelview, vector);
  205. self->cache.pos_view[0] = vector.x;
  206. self->cache.pos_view[1] = vector.y;
  207. self->cache.pos_view[2] = vector.z;
  208. /* Calculate direction vectors. */
  209. liren_light32_get_direction (self, &vector);
  210. self->cache.dir_world[0] = vector.x;
  211. self->cache.dir_world[1] = vector.y;
  212. self->cache.dir_world[2] = vector.z;
  213. matrix = limat_matrix_get_rotation (context->matrix.modelview);
  214. vector = limat_matrix_transform (matrix, vector);
  215. self->cache.dir_view[0] = vector.x;
  216. self->cache.dir_view[1] = vector.y;
  217. self->cache.dir_view[2] = vector.z;
  218. /* Calculate shadow buffer matrix. */
  219. matrix = limat_matrix_multiply (bias, context->matrix.projection);
  220. matrix = limat_matrix_multiply (matrix, context->matrix.view);
  221. matrix = limat_matrix_multiply (matrix, context->matrix.modelviewinverse);
  222. self->cache.matrix = matrix;
  223. /* Calculate spot light settings. */
  224. self->cache.spot[0] = self->cutoff;
  225. self->cache.spot[1] = cos (self->cutoff);
  226. self->cache.spot[2] = self->exponent;
  227. }
  228. void liren_light32_update_projection (
  229. LIRenLight32* self)
  230. {
  231. self->projection = limat_matrix_perspective (2.0f * self->cutoff * M_PI,
  232. 1.0f, self->shadow_near, self->shadow_far);
  233. }
  234. void liren_light32_get_ambient (
  235. LIRenLight32* self,
  236. float* value)
  237. {
  238. memcpy (value, self->ambient, 4 * sizeof (float));
  239. }
  240. void liren_light32_set_ambient (
  241. LIRenLight32* self,
  242. const float* value)
  243. {
  244. memcpy (self->ambient, value, 4 * sizeof (float));
  245. }
  246. /**
  247. * \brief Gets the area of effect of the light source.
  248. * \param self Light source.
  249. * \param result Return location for a bounding box.
  250. * \return Nonzero if has bounds.
  251. */
  252. int liren_light32_get_bounds (
  253. const LIRenLight32* self,
  254. LIMatAabb* result)
  255. {
  256. *result = self->bounds;
  257. return 1;
  258. }
  259. void liren_light32_get_diffuse (
  260. LIRenLight32* self,
  261. float* value)
  262. {
  263. memcpy (value, self->diffuse, 4 * sizeof (float));
  264. }
  265. void liren_light32_set_diffuse (
  266. LIRenLight32* self,
  267. const float* value)
  268. {
  269. memcpy (self->diffuse, value, 4 * sizeof (float));
  270. }
  271. /**
  272. * \brief Gets the forwards direction of the light.
  273. *
  274. * The direction is derived from the transformation of the light.
  275. *
  276. * \param self Light source.
  277. * \param value Return location for the direction.
  278. */
  279. void liren_light32_get_direction (
  280. const LIRenLight32* self,
  281. LIMatVector* value)
  282. {
  283. *value = limat_vector_init (0.0f, 0.0f, -1.0f);
  284. *value = limat_quaternion_transform (self->transform.rotation, *value);
  285. }
  286. /**
  287. * \brief Makes the light directional and sets it direction.
  288. * \param self Light source.
  289. * \param value Light direction.
  290. */
  291. void liren_light32_set_direction (
  292. LIRenLight32* self,
  293. const LIMatVector* value)
  294. {
  295. float a;
  296. float b;
  297. LIMatMatrix projection;
  298. LIMatQuaternion rotation;
  299. LIMatTransform transform;
  300. LIMatVector direction;
  301. LIMatVector position;
  302. /* Calculate temporary position. */
  303. /* FIXME: Temporary position not supported. */
  304. direction = *value;
  305. position = limat_vector_init (0.0f, 0.0f, 0.0f);
  306. /* Calculate light rotation. */
  307. a = limat_vector_dot (direction, limat_vector_init (0.0f, 1.0f, 0.0f));
  308. b = limat_vector_dot (direction, limat_vector_init (0.0f, 0.0f, 1.0f));
  309. if (LIMAT_ABS (a) >= LIMAT_ABS (b))
  310. rotation = limat_quaternion_look (direction, limat_vector_init (0.0f, 1.0f, 0.0f));
  311. else
  312. rotation = limat_quaternion_look (direction, limat_vector_init (0.0f, 0.0f, 1.0f));
  313. /* Set light transformation. */
  314. transform = limat_transform_init (position, rotation);
  315. liren_light32_set_transform (self, &transform);
  316. projection = limat_matrix_ortho (200, -200, 200, -200, -1000, 1000);
  317. liren_light32_set_projection (self, &projection);
  318. self->directional = 1;
  319. private_update_bounds (self);
  320. }
  321. /**
  322. * \brief Enables or disables directional mode.
  323. * \param self Light source.
  324. * \param value Nonzero if the light is directional.
  325. */
  326. void liren_light32_set_directional (
  327. LIRenLight32* self,
  328. int value)
  329. {
  330. self->directional = (value != 0);
  331. }
  332. /**
  333. * \brief Checks if the light is registered.
  334. * \param self Light source.
  335. * \return Nonzero if registered.
  336. */
  337. int liren_light32_get_enabled (
  338. const LIRenLight32* self)
  339. {
  340. return self->enabled;
  341. }
  342. void liren_light32_get_equation (
  343. LIRenLight32* self,
  344. float* value)
  345. {
  346. memcpy (value, self->equation, 3 * sizeof (float));
  347. }
  348. void liren_light32_set_equation (
  349. LIRenLight32* self,
  350. const float* value)
  351. {
  352. memcpy (self->equation, value, 3 * sizeof (float));
  353. }
  354. /**
  355. * \brief Gets the modelview matrix of the light.
  356. * \param self Light source.
  357. * \param value Return location for the matrix.
  358. */
  359. void liren_light32_get_modelview (
  360. const LIRenLight32* self,
  361. LIMatMatrix* value)
  362. {
  363. *value = self->modelview;
  364. }
  365. /**
  366. * \brief Gets the OpenGL position vector for the light.
  367. * \param self Light source.
  368. * \param value Return location for 4 floats.
  369. */
  370. void liren_light32_get_position (
  371. const LIRenLight32* self,
  372. GLfloat* value)
  373. {
  374. LIMatVector tmp;
  375. if (self->directional)
  376. {
  377. liren_light32_get_direction (self, &tmp);
  378. value[0] = -tmp.x;
  379. value[1] = -tmp.y;
  380. value[2] = -tmp.z;
  381. value[3] = 0.0f;
  382. }
  383. else
  384. {
  385. value[0] = self->transform.position.x;
  386. value[1] = self->transform.position.y;
  387. value[2] = self->transform.position.z;
  388. value[3] = 1.0f;
  389. }
  390. }
  391. /**
  392. * \brief Gets the priority of the light.
  393. * \param self Light source.
  394. * \return Priority value, higher means more important.
  395. */
  396. float liren_light32_get_priority (
  397. LIRenLight32* self)
  398. {
  399. return self->priority;
  400. }
  401. /**
  402. * \brief Sets the priority of the light.
  403. * \param self Light source.
  404. * \param value Priority value, higher means more important.
  405. */
  406. void liren_light32_set_priority (
  407. LIRenLight32* self,
  408. float value)
  409. {
  410. self->priority = value;
  411. }
  412. /**
  413. * \brief Gets the projection matrix of the light.
  414. * \param self Light source.
  415. * \param value Return location for the matrix.
  416. */
  417. void liren_light32_get_projection (
  418. const LIRenLight32* self,
  419. LIMatMatrix* value)
  420. {
  421. *value = self->projection;
  422. }
  423. /**
  424. * \brief Sets the projection matrix of the light.
  425. * \param self Light source.
  426. * \param value Matrix to set.
  427. */
  428. void liren_light32_set_projection (
  429. LIRenLight32* self,
  430. const LIMatMatrix* value)
  431. {
  432. self->projection = *value;
  433. private_update_bounds (self);
  434. }
  435. LIRenScene32* liren_light32_get_scene (
  436. const LIRenLight32* self)
  437. {
  438. return self->scene;
  439. }
  440. /**
  441. * \brief Gets the shadow casting mode of the light.
  442. * \param self Light source.
  443. * \return Nonzero if shadow casting is allowed, zero if disabled.
  444. */
  445. int liren_light32_get_shadow (
  446. const LIRenLight32* self)
  447. {
  448. return self->shadow.fbo != 0;
  449. }
  450. float liren_light32_get_shadow_far (
  451. const LIRenLight32* self)
  452. {
  453. return self->shadow_far;
  454. }
  455. void liren_light32_set_shadow_far (
  456. LIRenLight32* self,
  457. float value)
  458. {
  459. self->shadow_far = value;
  460. liren_light32_update_projection (self);
  461. }
  462. float liren_light32_get_shadow_near (
  463. const LIRenLight32* self)
  464. {
  465. return self->shadow_near;
  466. }
  467. void liren_light32_set_shadow_near (
  468. LIRenLight32* self,
  469. float value)
  470. {
  471. self->shadow_near = value;
  472. liren_light32_update_projection (self);
  473. }
  474. /**
  475. * \brief Sets the shadow casting mode of the light.
  476. * \param self Light source.
  477. * \param value Nonzero to allow shadow casting, zero to disable.
  478. */
  479. void liren_light32_set_shadow (
  480. LIRenLight32* self,
  481. int value)
  482. {
  483. float border[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
  484. if ((value != 0) == (self->shadow.fbo != 0))
  485. return;
  486. if (value)
  487. {
  488. /* Create shadow texture. */
  489. glGenTextures (1, &self->shadow.map);
  490. glBindTexture (GL_TEXTURE_2D, self->shadow.map);
  491. glTexImage2D (GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, SHADOWMAPSIZE, SHADOWMAPSIZE,
  492. 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
  493. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  494. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  495. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
  496. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
  497. glTexParameterfv (GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border);
  498. /* Create framebuffer object. */
  499. glGenFramebuffers (1, &self->shadow.fbo);
  500. glBindFramebuffer (GL_FRAMEBUFFER, self->shadow.fbo);
  501. glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, self->shadow.map, 0);
  502. glDrawBuffer (GL_NONE);
  503. glReadBuffer (GL_NONE);
  504. switch (glCheckFramebufferStatus (GL_FRAMEBUFFER))
  505. {
  506. case GL_FRAMEBUFFER_COMPLETE:
  507. break;
  508. default:
  509. lisys_error_set (ENOTSUP, "cannot create framebuffer object");
  510. glDeleteFramebuffers (1, &self->shadow.fbo);
  511. glDeleteTextures (1, &self->shadow.map);
  512. self->shadow.fbo = 0;
  513. self->shadow.map = 0;
  514. break;
  515. }
  516. glBindFramebuffer (GL_FRAMEBUFFER, 0);
  517. }
  518. else
  519. {
  520. /* Delete the shadow map. */
  521. glDeleteFramebuffers (1, &self->shadow.fbo);
  522. glDeleteTextures (1, &self->shadow.map);
  523. self->shadow.fbo = 0;
  524. self->shadow.map = 0;
  525. }
  526. }
  527. void liren_light32_get_specular (
  528. LIRenLight32* self,
  529. float* value)
  530. {
  531. memcpy (value, self->specular, 4 * sizeof (float));
  532. }
  533. void liren_light32_set_specular (
  534. LIRenLight32* self,
  535. const float* value)
  536. {
  537. memcpy (self->specular, value, 4 * sizeof (float));
  538. }
  539. float liren_light32_get_spot_cutoff (
  540. const LIRenLight32* self)
  541. {
  542. return self->cutoff;
  543. }
  544. void liren_light32_set_spot_cutoff (
  545. LIRenLight32* self,
  546. float value)
  547. {
  548. self->cutoff = value;
  549. liren_light32_update_projection (self);
  550. }
  551. float liren_light32_get_spot_exponent (
  552. const LIRenLight32* self)
  553. {
  554. return self->exponent;
  555. }
  556. void liren_light32_set_spot_exponent (
  557. LIRenLight32* self,
  558. float value)
  559. {
  560. self->exponent = value;
  561. }
  562. /**
  563. * \brief Gets the transformation of the light.
  564. * \param self Light source.
  565. * \param value Return value for the transformation.
  566. */
  567. void liren_light32_get_transform (
  568. LIRenLight32* self,
  569. LIMatTransform* value)
  570. {
  571. *value = self->transform;
  572. }
  573. /**
  574. * \brief Sets the transformation of the light.
  575. *
  576. * This modifies the modelview matrix.
  577. *
  578. * \param self Light source.
  579. * \param transform Transformation.
  580. */
  581. void liren_light32_set_transform (
  582. LIRenLight32* self,
  583. const LIMatTransform* transform)
  584. {
  585. LIMatVector dir;
  586. LIMatVector pos;
  587. LIMatVector up;
  588. pos = transform->position;
  589. dir = limat_quaternion_transform (transform->rotation, limat_vector_init (0.0f, 0.0f, -1.0f));
  590. up = limat_quaternion_transform (transform->rotation, limat_vector_init (0.0f, 1.0f, 0.0f));
  591. self->transform = *transform;
  592. self->modelview = limat_matrix_look (pos.x, pos.y, pos.z, dir.x, dir.y, dir.z, up.x, up.y, up.z);
  593. self->modelview_inverse = limat_matrix_invert (self->modelview);
  594. private_update_bounds (self);
  595. }
  596. int liren_light32_get_type (
  597. const LIRenLight32* self)
  598. {
  599. if (self->directional)
  600. return LIREN_LIGHTTYPE_DIRECTIONAL;
  601. else if (LIMAT_ABS (self->cutoff - M_PI) < 0.001)
  602. return LIREN_LIGHTTYPE_POINT;
  603. else if (self->shadow.map)
  604. return LIREN_LIGHTTYPE_SPOTSHADOW;
  605. else
  606. return LIREN_LIGHTTYPE_SPOT;
  607. }
  608. /*****************************************************************************/
  609. static void private_update_bounds (
  610. LIRenLight32* self)
  611. {
  612. double a;
  613. double b;
  614. double c;
  615. double r;
  616. double det;
  617. double eps;
  618. /* Choose epsilon. */
  619. eps = LIMAT_MAX (LIMAT_MAX (self->diffuse[0], self->diffuse[1]), self->diffuse[2]);
  620. eps /= 256.0;
  621. if (eps < LIGHT_CONTRIBUTION_EPSILON)
  622. eps = LIGHT_CONTRIBUTION_EPSILON;
  623. /* Solve radius. */
  624. /* 1 / (A * r^2 + B * r + C) = E */
  625. /* (EA) * r^2 + (EB) * r + (Ec-1) = 0 */
  626. a = eps * self->equation[2];
  627. b = eps * self->equation[1];
  628. c = eps * self->equation[0] - 1.0;
  629. det = b * b - 4 * a * c;
  630. if (det < 0.0)
  631. {
  632. self->bounds.min = self->transform.position;
  633. self->bounds.max = self->transform.position;
  634. return;
  635. }
  636. r = (-b + sqrt (det)) / (2.0 * a);
  637. /* Create bounding box. */
  638. self->bounds.min = limat_vector_subtract (self->transform.position, limat_vector_init (r, r, r));
  639. self->bounds.max = limat_vector_add (self->transform.position, limat_vector_init (r, r, r));
  640. }
  641. static void private_update_shadow (
  642. LIRenLight32* self)
  643. {
  644. LIAlgU32dicIter iter1;
  645. LIMatAabb aabb;
  646. LIMatFrustum frustum;
  647. LIRenContext32* context;
  648. LIRenLod32* lod;
  649. LIRenObject32* object;
  650. LIRenShader32* shader;
  651. /* Find the shader. */
  652. shader = liren_render32_find_shader (self->scene->render, "shadowmap");
  653. if (shader == NULL)
  654. return;
  655. /* Enable depth rendering mode. */
  656. glPushAttrib (GL_VIEWPORT_BIT | GL_SCISSOR_BIT);
  657. glBindFramebuffer (GL_FRAMEBUFFER, self->shadow.fbo);
  658. glViewport (0, 0, SHADOWMAPSIZE, SHADOWMAPSIZE);
  659. glDisable (GL_SCISSOR_TEST);
  660. glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  661. limat_frustum_init (&frustum, &self->modelview, &self->projection);
  662. context = liren_render32_get_context (self->scene->render);
  663. liren_context32_init (context);
  664. liren_context32_set_scene (context, self->scene);
  665. liren_context32_set_cull (context, 1, GL_CCW);
  666. liren_context32_set_depth (context, 1, 1, GL_LEQUAL);
  667. liren_context32_set_frustum (context, &frustum);
  668. liren_context32_set_projection (context, &self->projection);
  669. liren_context32_set_shader (context, 0, shader);
  670. liren_context32_set_viewmatrix (context, &self->modelview);
  671. /* Render objects to the depth texture. */
  672. LIALG_U32DIC_FOREACH (iter1, ((LIRenScene*) self->scene->scene)->objects)
  673. {
  674. object = ((LIRenObject*) iter1.value)->v32;
  675. if (!liren_object32_get_realized (object))
  676. continue;
  677. liren_object32_get_bounds (object, &aabb);
  678. if (limat_frustum_cull_aabb (&frustum, &aabb))
  679. continue;
  680. lod = object->model->lod.array + 0;
  681. liren_context32_set_modelmatrix (context, &object->orientation.matrix);
  682. liren_context32_set_mesh (context, &lod->mesh);
  683. liren_context32_bind (context);
  684. liren_context32_render_indexed (context, 0, lod->mesh.counts[0]);
  685. }
  686. /* Disable depth rendering mode. */
  687. glBindFramebuffer (GL_FRAMEBUFFER, 0);
  688. glPopAttrib ();
  689. }
  690. /** @} */
  691. /** @} */