light.cpp 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840
  1. /*
  2. Copyright (C) 2001-2006, William Joseph.
  3. All Rights Reserved.
  4. This file is part of GtkRadiant.
  5. GtkRadiant is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. GtkRadiant 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 General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with GtkRadiant; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. */
  17. ///\file
  18. ///\brief Represents any light entity (e.g. light).
  19. ///
  20. /// This entity dislays a special 'light' model.
  21. /// The "origin" key directly controls the position of the light model in local space.
  22. /// The "_color" key controls the colour of the light model.
  23. /// The "light" key is visualised with a sphere representing the approximate coverage of the light (except Doom3).
  24. /// Doom3 special behaviour:
  25. /// The entity behaves as a group.
  26. /// The "origin" key is the translation to be applied to all brushes (not patches) grouped under this entity.
  27. /// The "light_center" and "light_radius" keys are visualised with a point and a box when the light is selected.
  28. /// The "rotation" key directly controls the orientation of the light bounding box in local space.
  29. /// The "light_origin" key controls the position of the light independently of the "origin" key if it is specified.
  30. /// The "light_rotation" key duplicates the behaviour of the "rotation" key if it is specified. This appears to be an unfinished feature in Doom3.
  31. #include "light.h"
  32. #include <stdlib.h>
  33. #include "cullable.h"
  34. #include "renderable.h"
  35. #include "editable.h"
  36. #include "math/frustum.h"
  37. #include "selectionlib.h"
  38. #include "instancelib.h"
  39. #include "transformlib.h"
  40. #include "entitylib.h"
  41. #include "render.h"
  42. #include "eclasslib.h"
  43. #include "render.h"
  44. #include "stringio.h"
  45. #include "traverselib.h"
  46. #include "targetable.h"
  47. #include "origin.h"
  48. #include "colour.h"
  49. #include "filters.h"
  50. #include "namedentity.h"
  51. #include "keyobservers.h"
  52. #include "namekeys.h"
  53. #include "rotation.h"
  54. #include "entity.h"
  55. extern bool g_newLightDraw;
  56. void sphere_draw_fill(const Vector3& origin, float radius, int sides)
  57. {
  58. if (radius <= 0)
  59. return;
  60. const double dt = c_2pi / static_cast<double>(sides);
  61. const double dp = c_pi / static_cast<double>(sides);
  62. glBegin(GL_TRIANGLES);
  63. for (int i = 0; i <= sides - 1; ++i)
  64. {
  65. for (int j = 0; j <= sides - 2; ++j)
  66. {
  67. const double t = i * dt;
  68. const double p = (j * dp) - (c_pi / 2.0);
  69. {
  70. Vector3 v(vector3_added(origin, vector3_scaled(vector3_for_spherical(t, p), radius)));
  71. glVertex3fv(vector3_to_array(v));
  72. }
  73. {
  74. Vector3 v(vector3_added(origin, vector3_scaled(vector3_for_spherical(t, p + dp), radius)));
  75. glVertex3fv(vector3_to_array(v));
  76. }
  77. {
  78. Vector3 v(vector3_added(origin, vector3_scaled(vector3_for_spherical(t + dt, p + dp), radius)));
  79. glVertex3fv(vector3_to_array(v));
  80. }
  81. {
  82. Vector3 v(vector3_added(origin, vector3_scaled(vector3_for_spherical(t, p), radius)));
  83. glVertex3fv(vector3_to_array(v));
  84. }
  85. {
  86. Vector3 v(vector3_added(origin, vector3_scaled(vector3_for_spherical(t + dt, p + dp), radius)));
  87. glVertex3fv(vector3_to_array(v));
  88. }
  89. {
  90. Vector3 v(vector3_added(origin, vector3_scaled(vector3_for_spherical(t + dt, p), radius)));
  91. glVertex3fv(vector3_to_array(v));
  92. }
  93. }
  94. }
  95. {
  96. const double p = (sides - 1) * dp - (c_pi / 2.0);
  97. for (int i = 0; i <= sides - 1; ++i)
  98. {
  99. const double t = i * dt;
  100. {
  101. Vector3 v(vector3_added(origin, vector3_scaled(vector3_for_spherical(t, p), radius)));
  102. glVertex3fv(vector3_to_array(v));
  103. }
  104. {
  105. Vector3 v(vector3_added(origin, vector3_scaled(vector3_for_spherical(t + dt, p + dp), radius)));
  106. glVertex3fv(vector3_to_array(v));
  107. }
  108. {
  109. Vector3 v(vector3_added(origin, vector3_scaled(vector3_for_spherical(t + dt, p), radius)));
  110. glVertex3fv(vector3_to_array(v));
  111. }
  112. }
  113. }
  114. glEnd();
  115. }
  116. void sphere_draw_wire(const Vector3& origin, float radius, int sides)
  117. {
  118. {
  119. glBegin(GL_LINE_LOOP);
  120. for (int i = 0; i <= sides; i++)
  121. {
  122. double ds = sin((i * 2 * c_pi) / sides);
  123. double dc = cos((i * 2 * c_pi) / sides);
  124. glVertex3f(
  125. static_cast<float>(origin[0] + radius * dc),
  126. static_cast<float>(origin[1] + radius * ds),
  127. origin[2]
  128. );
  129. }
  130. glEnd();
  131. }
  132. {
  133. glBegin(GL_LINE_LOOP);
  134. for (int i = 0; i <= sides; i++)
  135. {
  136. double ds = sin((i * 2 * c_pi) / sides);
  137. double dc = cos((i * 2 * c_pi) / sides);
  138. glVertex3f(
  139. static_cast<float>(origin[0] + radius * dc),
  140. origin[1],
  141. static_cast<float>(origin[2] + radius * ds)
  142. );
  143. }
  144. glEnd();
  145. }
  146. {
  147. glBegin(GL_LINE_LOOP);
  148. for (int i = 0; i <= sides; i++)
  149. {
  150. double ds = sin((i * 2 * c_pi) / sides);
  151. double dc = cos((i * 2 * c_pi) / sides);
  152. glVertex3f(
  153. origin[0],
  154. static_cast<float>(origin[1] + radius * dc),
  155. static_cast<float>(origin[2] + radius * ds)
  156. );
  157. }
  158. glEnd();
  159. }
  160. }
  161. void light_draw_box_lines(const Vector3& origin, const Vector3 points[8])
  162. {
  163. //draw lines from the center of the bbox to the corners
  164. glBegin(GL_LINES);
  165. glVertex3fv(vector3_to_array(origin));
  166. glVertex3fv(vector3_to_array(points[1]));
  167. glVertex3fv(vector3_to_array(origin));
  168. glVertex3fv(vector3_to_array(points[5]));
  169. glVertex3fv(vector3_to_array(origin));
  170. glVertex3fv(vector3_to_array(points[2]));
  171. glVertex3fv(vector3_to_array(origin));
  172. glVertex3fv(vector3_to_array(points[6]));
  173. glVertex3fv(vector3_to_array(origin));
  174. glVertex3fv(vector3_to_array(points[0]));
  175. glVertex3fv(vector3_to_array(origin));
  176. glVertex3fv(vector3_to_array(points[4]));
  177. glVertex3fv(vector3_to_array(origin));
  178. glVertex3fv(vector3_to_array(points[3]));
  179. glVertex3fv(vector3_to_array(origin));
  180. glVertex3fv(vector3_to_array(points[7]));
  181. glEnd();
  182. }
  183. void light_draw_radius_wire(const Vector3& origin, const float envelope[3])
  184. {
  185. if(envelope[0] > 0)
  186. sphere_draw_wire(origin, envelope[0], 24);
  187. if(envelope[1] > 0)
  188. sphere_draw_wire(origin, envelope[1], 24);
  189. if(envelope[2] > 0)
  190. sphere_draw_wire(origin, envelope[2], 24);
  191. }
  192. void light_draw_radius_fill(const Vector3& origin, const float envelope[3])
  193. {
  194. if(envelope[0] > 0)
  195. sphere_draw_fill(origin, envelope[0], 16);
  196. if(envelope[1] > 0)
  197. sphere_draw_fill(origin, envelope[1], 16);
  198. if(envelope[2] > 0)
  199. sphere_draw_fill(origin, envelope[2], 16);
  200. }
  201. void light_vertices(const AABB& aabb_light, Vector3 points[6])
  202. {
  203. Vector3 max(vector3_added(aabb_light.origin, aabb_light.extents));
  204. Vector3 min(vector3_subtracted(aabb_light.origin, aabb_light.extents));
  205. Vector3 mid(aabb_light.origin);
  206. // top, bottom, tleft, tright, bright, bleft
  207. points[0] = Vector3(mid[0], mid[1], max[2]);
  208. points[1] = Vector3(mid[0], mid[1], min[2]);
  209. points[2] = Vector3(min[0], max[1], mid[2]);
  210. points[3] = Vector3(max[0], max[1], mid[2]);
  211. points[4] = Vector3(max[0], min[1], mid[2]);
  212. points[5] = Vector3(min[0], min[1], mid[2]);
  213. }
  214. void light_draw(const AABB& aabb_light, RenderStateFlags state)
  215. {
  216. Vector3 points[6];
  217. light_vertices(aabb_light, points);
  218. if(state & RENDER_LIGHTING)
  219. {
  220. const float f = 0.70710678f;
  221. // North, East, South, West
  222. const Vector3 normals[8] = {
  223. Vector3( 0, f, f ),
  224. Vector3( f, 0, f ),
  225. Vector3( 0,-f, f ),
  226. Vector3(-f, 0, f ),
  227. Vector3( 0, f,-f ),
  228. Vector3( f, 0,-f ),
  229. Vector3( 0,-f,-f ),
  230. Vector3(-f, 0,-f ),
  231. };
  232. #if !defined(USE_TRIANGLE_FAN)
  233. glBegin(GL_TRIANGLES);
  234. #else
  235. glBegin(GL_TRIANGLE_FAN);
  236. #endif
  237. glVertex3fv(vector3_to_array(points[0]));
  238. glVertex3fv(vector3_to_array(points[2]));
  239. glNormal3fv(vector3_to_array(normals[0]));
  240. glVertex3fv(vector3_to_array(points[3]));
  241. #if !defined(USE_TRIANGLE_FAN)
  242. glVertex3fv(vector3_to_array(points[0]));
  243. glVertex3fv(vector3_to_array(points[3]));
  244. #endif
  245. glNormal3fv(vector3_to_array(normals[1]));
  246. glVertex3fv(vector3_to_array(points[4]));
  247. #if !defined(USE_TRIANGLE_FAN)
  248. glVertex3fv(vector3_to_array(points[0]));
  249. glVertex3fv(vector3_to_array(points[4]));
  250. #endif
  251. glNormal3fv(vector3_to_array(normals[2]));
  252. glVertex3fv(vector3_to_array(points[5]));
  253. #if !defined(USE_TRIANGLE_FAN)
  254. glVertex3fv(vector3_to_array(points[0]));
  255. glVertex3fv(vector3_to_array(points[5]));
  256. #endif
  257. glNormal3fv(vector3_to_array(normals[3]));
  258. glVertex3fv(vector3_to_array(points[2]));
  259. #if defined(USE_TRIANGLE_FAN)
  260. glEnd();
  261. glBegin(GL_TRIANGLE_FAN);
  262. #endif
  263. glVertex3fv(vector3_to_array(points[1]));
  264. glVertex3fv(vector3_to_array(points[2]));
  265. glNormal3fv(vector3_to_array(normals[7]));
  266. glVertex3fv(vector3_to_array(points[5]));
  267. #if !defined(USE_TRIANGLE_FAN)
  268. glVertex3fv(vector3_to_array(points[1]));
  269. glVertex3fv(vector3_to_array(points[5]));
  270. #endif
  271. glNormal3fv(vector3_to_array(normals[6]));
  272. glVertex3fv(vector3_to_array(points[4]));
  273. #if !defined(USE_TRIANGLE_FAN)
  274. glVertex3fv(vector3_to_array(points[1]));
  275. glVertex3fv(vector3_to_array(points[4]));
  276. #endif
  277. glNormal3fv(vector3_to_array(normals[5]));
  278. glVertex3fv(vector3_to_array(points[3]));
  279. #if !defined(USE_TRIANGLE_FAN)
  280. glVertex3fv(vector3_to_array(points[1]));
  281. glVertex3fv(vector3_to_array(points[3]));
  282. #endif
  283. glNormal3fv(vector3_to_array(normals[4]));
  284. glVertex3fv(vector3_to_array(points[2]));
  285. glEnd();
  286. }
  287. else
  288. {
  289. typedef unsigned int index_t;
  290. const index_t indices[24] = {
  291. 0, 2, 3,
  292. 0, 3, 4,
  293. 0, 4, 5,
  294. 0, 5, 2,
  295. 1, 2, 5,
  296. 1, 5, 4,
  297. 1, 4, 3,
  298. 1, 3, 2
  299. };
  300. #if 1
  301. glVertexPointer(3, GL_FLOAT, 0, points);
  302. glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(index_t), RenderIndexTypeID, indices);
  303. #else
  304. glBegin(GL_TRIANGLES);
  305. for(unsigned int i = 0; i < sizeof(indices)/sizeof(index_t); ++i)
  306. {
  307. glVertex3fv(points[indices[i]]);
  308. }
  309. glEnd();
  310. #endif
  311. }
  312. // NOTE: prolly not relevant until some time..
  313. // check for DOOM lights
  314. #if 0
  315. if (strlen(ValueForKey(e, "light_right")) > 0) {
  316. vec3_t vRight, vUp, vTarget, vTemp;
  317. GetVectorForKey (e, "light_right", vRight);
  318. GetVectorForKey (e, "light_up", vUp);
  319. GetVectorForKey (e, "light_target", vTarget);
  320. glColor3f(0, 1, 0);
  321. glBegin(GL_LINE_LOOP);
  322. VectorAdd(vTarget, e->origin, vTemp);
  323. VectorAdd(vTemp, vRight, vTemp);
  324. VectorAdd(vTemp, vUp, vTemp);
  325. glVertex3fv(e->origin);
  326. glVertex3fv(vTemp);
  327. VectorAdd(vTarget, e->origin, vTemp);
  328. VectorAdd(vTemp, vUp, vTemp);
  329. VectorSubtract(vTemp, vRight, vTemp);
  330. glVertex3fv(e->origin);
  331. glVertex3fv(vTemp);
  332. VectorAdd(vTarget, e->origin, vTemp);
  333. VectorAdd(vTemp, vRight, vTemp);
  334. VectorSubtract(vTemp, vUp, vTemp);
  335. glVertex3fv(e->origin);
  336. glVertex3fv(vTemp);
  337. VectorAdd(vTarget, e->origin, vTemp);
  338. VectorSubtract(vTemp, vUp, vTemp);
  339. VectorSubtract(vTemp, vRight, vTemp);
  340. glVertex3fv(e->origin);
  341. glVertex3fv(vTemp);
  342. glEnd();
  343. }
  344. #endif
  345. }
  346. // These variables are tweakable on the q3map2 console, setting to q3map2
  347. // default here as there is no way to find out what the user actually uses
  348. // right now. Maybe move them to worldspawn?
  349. float fPointScale = 7500.f;
  350. float fLinearScale = 1.f / 8000.f;
  351. float light_radius_linear(float fIntensity, float fFalloffTolerance)
  352. {
  353. return ((fIntensity * fPointScale * fLinearScale) - fFalloffTolerance);
  354. }
  355. float light_radius(float fIntensity, float fFalloffTolerance)
  356. {
  357. return sqrt(fIntensity * fPointScale / fFalloffTolerance);
  358. }
  359. LightType g_lightType = LIGHTTYPE_DEFAULT;
  360. bool spawnflags_linear(int flags)
  361. {
  362. if( g_lightType == LIGHTTYPE_RTCW )
  363. {
  364. // Spawnflags :
  365. // 1: nonlinear
  366. // 2: angle
  367. return !(flags & 1);
  368. }
  369. else
  370. {
  371. // Spawnflags :
  372. // 1: linear
  373. // 2: no angle
  374. return (flags & 1);
  375. }
  376. }
  377. class LightRadii
  378. {
  379. public:
  380. float m_radii[3];
  381. private:
  382. float m_primaryIntensity;
  383. float m_secondaryIntensity;
  384. int m_flags;
  385. float m_fade;
  386. float m_scale;
  387. void calculateRadii()
  388. {
  389. float intensity = 300.0f;
  390. if(m_primaryIntensity != 0.0f)
  391. {
  392. intensity = m_primaryIntensity;
  393. }
  394. else if(m_secondaryIntensity != 0.0f)
  395. {
  396. intensity = m_secondaryIntensity;
  397. }
  398. intensity *= m_scale;
  399. if(spawnflags_linear(m_flags))
  400. {
  401. m_radii[0] = light_radius_linear(intensity, 1.0f) / m_fade;
  402. m_radii[1] = light_radius_linear(intensity, 48.0f) / m_fade;
  403. m_radii[2] = light_radius_linear(intensity, 255.0f) / m_fade;
  404. }
  405. else
  406. {
  407. m_radii[0] = light_radius(intensity, 1.0f);
  408. m_radii[1] = light_radius(intensity, 48.0f);
  409. m_radii[2] = light_radius(intensity, 255.0f);
  410. }
  411. }
  412. public:
  413. LightRadii() : m_primaryIntensity(0), m_secondaryIntensity(0), m_flags(0), m_fade(1), m_scale(1)
  414. {
  415. }
  416. void primaryIntensityChanged(const char* value)
  417. {
  418. m_primaryIntensity = string_read_float(value);
  419. calculateRadii();
  420. }
  421. typedef MemberCaller1<LightRadii, const char*, &LightRadii::primaryIntensityChanged> PrimaryIntensityChangedCaller;
  422. void secondaryIntensityChanged(const char* value)
  423. {
  424. m_secondaryIntensity = string_read_float(value);
  425. calculateRadii();
  426. }
  427. typedef MemberCaller1<LightRadii, const char*, &LightRadii::secondaryIntensityChanged> SecondaryIntensityChangedCaller;
  428. void scaleChanged(const char* value)
  429. {
  430. m_scale = string_read_float(value);
  431. if(m_scale <= 0.0f)
  432. {
  433. m_scale = 1.0f;
  434. }
  435. calculateRadii();
  436. }
  437. typedef MemberCaller1<LightRadii, const char*, &LightRadii::scaleChanged> ScaleChangedCaller;
  438. void fadeChanged(const char* value)
  439. {
  440. m_fade = string_read_float(value);
  441. if(m_fade <= 0.0f)
  442. {
  443. m_fade = 1.0f;
  444. }
  445. calculateRadii();
  446. }
  447. typedef MemberCaller1<LightRadii, const char*, &LightRadii::fadeChanged> FadeChangedCaller;
  448. void flagsChanged(const char* value)
  449. {
  450. m_flags = string_read_int(value);
  451. calculateRadii();
  452. }
  453. typedef MemberCaller1<LightRadii, const char*, &LightRadii::flagsChanged> FlagsChangedCaller;
  454. };
  455. const Vector3 c_defaultDoom3LightRadius = Vector3(300, 300, 300);
  456. class Doom3LightRadius
  457. {
  458. public:
  459. Vector3 m_radius;
  460. Vector3 m_center;
  461. Callback m_changed;
  462. bool m_useCenterKey;
  463. Doom3LightRadius() : m_radius(c_defaultDoom3LightRadius), m_center(0, 0, 0), m_useCenterKey(false)
  464. {
  465. }
  466. void lightRadiusChanged(const char* value)
  467. {
  468. if(!string_parse_vector3(value, m_radius))
  469. {
  470. m_radius = c_defaultDoom3LightRadius;
  471. }
  472. m_changed();
  473. SceneChangeNotify();
  474. }
  475. typedef MemberCaller1<Doom3LightRadius, const char*, &Doom3LightRadius::lightRadiusChanged> LightRadiusChangedCaller;
  476. void lightCenterChanged(const char* value)
  477. {
  478. m_useCenterKey = string_parse_vector3(value, m_center);
  479. if(!m_useCenterKey)
  480. {
  481. m_center = Vector3(0, 0, 0);
  482. }
  483. SceneChangeNotify();
  484. }
  485. typedef MemberCaller1<Doom3LightRadius, const char*, &Doom3LightRadius::lightCenterChanged> LightCenterChangedCaller;
  486. };
  487. class RenderLightRadiiWire : public OpenGLRenderable
  488. {
  489. LightRadii& m_radii;
  490. const Vector3& m_origin;
  491. public:
  492. RenderLightRadiiWire(LightRadii& radii, const Vector3& origin) : m_radii(radii), m_origin(origin)
  493. {
  494. }
  495. void render(RenderStateFlags state) const
  496. {
  497. light_draw_radius_wire(m_origin, m_radii.m_radii);
  498. }
  499. };
  500. class RenderLightRadiiFill : public OpenGLRenderable
  501. {
  502. LightRadii& m_radii;
  503. const Vector3& m_origin;
  504. public:
  505. static Shader* m_state;
  506. RenderLightRadiiFill(LightRadii& radii, const Vector3& origin) : m_radii(radii), m_origin(origin)
  507. {
  508. }
  509. void render(RenderStateFlags state) const
  510. {
  511. light_draw_radius_fill(m_origin, m_radii.m_radii);
  512. }
  513. };
  514. class RenderLightRadiiBox : public OpenGLRenderable
  515. {
  516. const Vector3& m_origin;
  517. public:
  518. mutable Vector3 m_points[8];
  519. static Shader* m_state;
  520. RenderLightRadiiBox(const Vector3& origin) : m_origin(origin)
  521. {
  522. }
  523. void render(RenderStateFlags state) const
  524. {
  525. //draw the bounding box of light based on light_radius key
  526. if((state & RENDER_FILL) != 0)
  527. {
  528. aabb_draw_flatshade(m_points);
  529. }
  530. else
  531. {
  532. aabb_draw_wire(m_points);
  533. }
  534. #if 1 //disable if you dont want lines going from the center of the light bbox to the corners
  535. light_draw_box_lines(m_origin, m_points);
  536. #endif
  537. }
  538. };
  539. Shader* RenderLightRadiiFill::m_state = 0;
  540. class RenderLightCenter : public OpenGLRenderable
  541. {
  542. const Vector3& m_center;
  543. EntityClass& m_eclass;
  544. public:
  545. static Shader* m_state;
  546. RenderLightCenter(const Vector3& center, EntityClass& eclass) : m_center(center), m_eclass(eclass)
  547. {
  548. }
  549. void render(RenderStateFlags state) const
  550. {
  551. glBegin(GL_POINTS);
  552. glColor3fv(vector3_to_array(m_eclass.color));
  553. glVertex3fv(vector3_to_array(m_center));
  554. glEnd();
  555. }
  556. };
  557. Shader* RenderLightCenter::m_state = 0;
  558. class RenderLightProjection : public OpenGLRenderable
  559. {
  560. const Matrix4& m_projection;
  561. public:
  562. RenderLightProjection(const Matrix4& projection) : m_projection(projection)
  563. {
  564. }
  565. void render(RenderStateFlags state) const
  566. {
  567. Matrix4 unproject(matrix4_full_inverse(m_projection));
  568. Vector3 points[8];
  569. aabb_corners(AABB(Vector3(0.5f, 0.5f, 0.5f), Vector3(0.5f, 0.5f, 0.5f)), points);
  570. points[0] = vector4_projected(matrix4_transformed_vector4(unproject, Vector4(points[0], 1)));
  571. points[1] = vector4_projected(matrix4_transformed_vector4(unproject, Vector4(points[1], 1)));
  572. points[2] = vector4_projected(matrix4_transformed_vector4(unproject, Vector4(points[2], 1)));
  573. points[3] = vector4_projected(matrix4_transformed_vector4(unproject, Vector4(points[3], 1)));
  574. points[4] = vector4_projected(matrix4_transformed_vector4(unproject, Vector4(points[4], 1)));
  575. points[5] = vector4_projected(matrix4_transformed_vector4(unproject, Vector4(points[5], 1)));
  576. points[6] = vector4_projected(matrix4_transformed_vector4(unproject, Vector4(points[6], 1)));
  577. points[7] = vector4_projected(matrix4_transformed_vector4(unproject, Vector4(points[7], 1)));
  578. Vector4 test1 = matrix4_transformed_vector4(unproject, Vector4(0.5f, 0.5f, 0.5f, 1));
  579. Vector3 test2 = vector4_projected(test1);
  580. aabb_draw_wire(points);
  581. }
  582. };
  583. inline void default_extents(Vector3& extents)
  584. {
  585. extents = Vector3(8, 8, 8);
  586. }
  587. class ShaderRef
  588. {
  589. CopiedString m_name;
  590. Shader* m_shader;
  591. void capture()
  592. {
  593. m_shader = GlobalShaderCache().capture(m_name.c_str());
  594. }
  595. void release()
  596. {
  597. GlobalShaderCache().release(m_name.c_str());
  598. }
  599. public:
  600. ShaderRef()
  601. {
  602. capture();
  603. }
  604. ~ShaderRef()
  605. {
  606. release();
  607. }
  608. void setName(const char* name)
  609. {
  610. release();
  611. m_name = name;
  612. capture();
  613. }
  614. Shader* get() const
  615. {
  616. return m_shader;
  617. }
  618. };
  619. class LightShader
  620. {
  621. ShaderRef m_shader;
  622. void setDefault()
  623. {
  624. m_shader.setName(m_defaultShader);
  625. }
  626. public:
  627. static const char* m_defaultShader;
  628. LightShader()
  629. {
  630. setDefault();
  631. }
  632. void valueChanged(const char* value)
  633. {
  634. if(string_empty(value))
  635. {
  636. setDefault();
  637. }
  638. else
  639. {
  640. m_shader.setName(value);
  641. }
  642. SceneChangeNotify();
  643. }
  644. typedef MemberCaller1<LightShader, const char*, &LightShader::valueChanged> ValueChangedCaller;
  645. Shader* get() const
  646. {
  647. return m_shader.get();
  648. }
  649. };
  650. const char* LightShader::m_defaultShader = "";
  651. inline const BasicVector4<double>& plane3_to_vector4(const Plane3& self)
  652. {
  653. return reinterpret_cast<const BasicVector4<double>&>(self);
  654. }
  655. inline BasicVector4<double>& plane3_to_vector4(Plane3& self)
  656. {
  657. return reinterpret_cast<BasicVector4<double>&>(self);
  658. }
  659. inline Matrix4 matrix4_from_planes(const Plane3& left, const Plane3& right, const Plane3& bottom, const Plane3& top, const Plane3& front, const Plane3& back)
  660. {
  661. return Matrix4(
  662. (right.a - left.a) / 2,
  663. (top.a - bottom.a) / 2,
  664. (back.a - front.a) / 2,
  665. right.a - (right.a - left.a) / 2,
  666. (right.b - left.b) / 2,
  667. (top.b - bottom.b) / 2,
  668. (back.b - front.b) / 2,
  669. right.b - (right.b - left.b) / 2,
  670. (right.c - left.c) / 2,
  671. (top.c - bottom.c) / 2,
  672. (back.c - front.c) / 2,
  673. right.c - (right.c - left.c) / 2,
  674. (right.d - left.d) / 2,
  675. (top.d - bottom.d) / 2,
  676. (back.d - front.d) / 2,
  677. right.d - (right.d - left.d) / 2
  678. );
  679. }
  680. class Light :
  681. public OpenGLRenderable,
  682. public Cullable,
  683. public Bounded,
  684. public Editable,
  685. public Snappable
  686. {
  687. EntityKeyValues m_entity;
  688. KeyObserverMap m_keyObservers;
  689. TraversableNodeSet m_traverse;
  690. IdentityTransform m_transform;
  691. OriginKey m_originKey;
  692. RotationKey m_rotationKey;
  693. Float9 m_rotation;
  694. Colour m_colour;
  695. ClassnameFilter m_filter;
  696. NamedEntity m_named;
  697. NameKeys m_nameKeys;
  698. TraversableObserverPairRelay m_traverseObservers;
  699. Doom3GroupOrigin m_funcStaticOrigin;
  700. LightRadii m_radii;
  701. Doom3LightRadius m_doom3Radius;
  702. RenderLightRadiiWire m_radii_wire;
  703. RenderLightRadiiFill m_radii_fill;
  704. RenderLightRadiiBox m_radii_box;
  705. RenderLightCenter m_render_center;
  706. RenderableNamedEntity m_renderName;
  707. Vector3 m_lightOrigin;
  708. bool m_useLightOrigin;
  709. Float9 m_lightRotation;
  710. bool m_useLightRotation;
  711. Vector3 m_lightTarget;
  712. bool m_useLightTarget;
  713. Vector3 m_lightUp;
  714. bool m_useLightUp;
  715. Vector3 m_lightRight;
  716. bool m_useLightRight;
  717. Vector3 m_lightStart;
  718. bool m_useLightStart;
  719. Vector3 m_lightEnd;
  720. bool m_useLightEnd;
  721. mutable AABB m_doom3AABB;
  722. mutable Matrix4 m_doom3Rotation;
  723. mutable Matrix4 m_doom3Projection;
  724. mutable Frustum m_doom3Frustum;
  725. mutable bool m_doom3ProjectionChanged;
  726. RenderLightProjection m_renderProjection;
  727. LightShader m_shader;
  728. AABB m_aabb_light;
  729. Callback m_transformChanged;
  730. Callback m_boundsChanged;
  731. Callback m_evaluateTransform;
  732. void construct()
  733. {
  734. default_rotation(m_rotation);
  735. m_aabb_light.origin = Vector3(0, 0, 0);
  736. default_extents(m_aabb_light.extents);
  737. m_keyObservers.insert("classname", ClassnameFilter::ClassnameChangedCaller(m_filter));
  738. m_keyObservers.insert(Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller(m_named));
  739. m_keyObservers.insert("_color", Colour::ColourChangedCaller(m_colour));
  740. m_keyObservers.insert("origin", OriginKey::OriginChangedCaller(m_originKey));
  741. m_keyObservers.insert("_light", LightRadii::PrimaryIntensityChangedCaller(m_radii));
  742. m_keyObservers.insert("light", LightRadii::SecondaryIntensityChangedCaller(m_radii));
  743. m_keyObservers.insert("fade", LightRadii::FadeChangedCaller(m_radii));
  744. m_keyObservers.insert("scale", LightRadii::ScaleChangedCaller(m_radii));
  745. m_keyObservers.insert("spawnflags", LightRadii::FlagsChangedCaller(m_radii));
  746. if(g_lightType == LIGHTTYPE_DOOM3)
  747. {
  748. m_keyObservers.insert("angle", RotationKey::AngleChangedCaller(m_rotationKey));
  749. m_keyObservers.insert("rotation", RotationKey::RotationChangedCaller(m_rotationKey));
  750. m_keyObservers.insert("light_radius", Doom3LightRadius::LightRadiusChangedCaller(m_doom3Radius));
  751. m_keyObservers.insert("light_center", Doom3LightRadius::LightCenterChangedCaller(m_doom3Radius));
  752. m_keyObservers.insert("light_origin", Light::LightOriginChangedCaller(*this));
  753. m_keyObservers.insert("light_rotation", Light::LightRotationChangedCaller(*this));
  754. m_keyObservers.insert("light_target", Light::LightTargetChangedCaller(*this));
  755. m_keyObservers.insert("light_up", Light::LightUpChangedCaller(*this));
  756. m_keyObservers.insert("light_right", Light::LightRightChangedCaller(*this));
  757. m_keyObservers.insert("light_start", Light::LightStartChangedCaller(*this));
  758. m_keyObservers.insert("light_end", Light::LightEndChangedCaller(*this));
  759. m_keyObservers.insert("texture", LightShader::ValueChangedCaller(m_shader));
  760. m_useLightTarget = m_useLightUp = m_useLightRight = m_useLightStart = m_useLightEnd = false;
  761. m_doom3ProjectionChanged = true;
  762. }
  763. if(g_lightType == LIGHTTYPE_DOOM3)
  764. {
  765. m_traverse.attach(&m_traverseObservers);
  766. m_traverseObservers.attach(m_funcStaticOrigin);
  767. m_entity.m_isContainer = true;
  768. }
  769. }
  770. void destroy()
  771. {
  772. if(g_lightType == LIGHTTYPE_DOOM3)
  773. {
  774. m_traverseObservers.detach(m_funcStaticOrigin);
  775. m_traverse.detach(&m_traverseObservers);
  776. }
  777. }
  778. void updateOrigin()
  779. {
  780. m_boundsChanged();
  781. if(g_lightType == LIGHTTYPE_DOOM3)
  782. {
  783. m_funcStaticOrigin.originChanged();
  784. }
  785. m_doom3Radius.m_changed();
  786. GlobalSelectionSystem().pivotChanged();
  787. }
  788. void originChanged()
  789. {
  790. m_aabb_light.origin = m_useLightOrigin ? m_lightOrigin : m_originKey.m_origin;
  791. updateOrigin();
  792. }
  793. typedef MemberCaller<Light, &Light::originChanged> OriginChangedCaller;
  794. void lightOriginChanged(const char* value)
  795. {
  796. m_useLightOrigin = !string_empty(value);
  797. if(m_useLightOrigin)
  798. {
  799. read_origin(m_lightOrigin, value);
  800. }
  801. originChanged();
  802. }
  803. typedef MemberCaller1<Light, const char*, &Light::lightOriginChanged> LightOriginChangedCaller;
  804. void lightTargetChanged(const char* value)
  805. {
  806. m_useLightTarget = !string_empty(value);
  807. if(m_useLightTarget)
  808. {
  809. read_origin(m_lightTarget, value);
  810. }
  811. projectionChanged();
  812. }
  813. typedef MemberCaller1<Light, const char*, &Light::lightTargetChanged> LightTargetChangedCaller;
  814. void lightUpChanged(const char* value)
  815. {
  816. m_useLightUp = !string_empty(value);
  817. if(m_useLightUp)
  818. {
  819. read_origin(m_lightUp, value);
  820. }
  821. projectionChanged();
  822. }
  823. typedef MemberCaller1<Light, const char*, &Light::lightUpChanged> LightUpChangedCaller;
  824. void lightRightChanged(const char* value)
  825. {
  826. m_useLightRight = !string_empty(value);
  827. if(m_useLightRight)
  828. {
  829. read_origin(m_lightRight, value);
  830. }
  831. projectionChanged();
  832. }
  833. typedef MemberCaller1<Light, const char*, &Light::lightRightChanged> LightRightChangedCaller;
  834. void lightStartChanged(const char* value)
  835. {
  836. m_useLightStart = !string_empty(value);
  837. if(m_useLightStart)
  838. {
  839. read_origin(m_lightStart, value);
  840. }
  841. projectionChanged();
  842. }
  843. typedef MemberCaller1<Light, const char*, &Light::lightStartChanged> LightStartChangedCaller;
  844. void lightEndChanged(const char* value)
  845. {
  846. m_useLightEnd = !string_empty(value);
  847. if(m_useLightEnd)
  848. {
  849. read_origin(m_lightEnd, value);
  850. }
  851. projectionChanged();
  852. }
  853. typedef MemberCaller1<Light, const char*, &Light::lightEndChanged> LightEndChangedCaller;
  854. void writeLightOrigin()
  855. {
  856. write_origin(m_lightOrigin, &m_entity, "light_origin");
  857. }
  858. void updateLightRadiiBox() const
  859. {
  860. const Matrix4& rotation = rotation_toMatrix(m_rotation);
  861. aabb_corners(AABB(Vector3(0, 0, 0), m_doom3Radius.m_radius), m_radii_box.m_points);
  862. matrix4_transform_point(rotation, m_radii_box.m_points[0]);
  863. vector3_add(m_radii_box.m_points[0], m_aabb_light.origin);
  864. matrix4_transform_point(rotation, m_radii_box.m_points[1]);
  865. vector3_add(m_radii_box.m_points[1], m_aabb_light.origin);
  866. matrix4_transform_point(rotation, m_radii_box.m_points[2]);
  867. vector3_add(m_radii_box.m_points[2], m_aabb_light.origin);
  868. matrix4_transform_point(rotation, m_radii_box.m_points[3]);
  869. vector3_add(m_radii_box.m_points[3], m_aabb_light.origin);
  870. matrix4_transform_point(rotation, m_radii_box.m_points[4]);
  871. vector3_add(m_radii_box.m_points[4], m_aabb_light.origin);
  872. matrix4_transform_point(rotation, m_radii_box.m_points[5]);
  873. vector3_add(m_radii_box.m_points[5], m_aabb_light.origin);
  874. matrix4_transform_point(rotation, m_radii_box.m_points[6]);
  875. vector3_add(m_radii_box.m_points[6], m_aabb_light.origin);
  876. matrix4_transform_point(rotation, m_radii_box.m_points[7]);
  877. vector3_add(m_radii_box.m_points[7], m_aabb_light.origin);
  878. }
  879. void rotationChanged()
  880. {
  881. rotation_assign(m_rotation, m_useLightRotation ? m_lightRotation : m_rotationKey.m_rotation);
  882. GlobalSelectionSystem().pivotChanged();
  883. }
  884. typedef MemberCaller<Light, &Light::rotationChanged> RotationChangedCaller;
  885. void lightRotationChanged(const char* value)
  886. {
  887. m_useLightRotation = !string_empty(value);
  888. if(m_useLightRotation)
  889. {
  890. read_rotation(m_lightRotation, value);
  891. }
  892. rotationChanged();
  893. }
  894. typedef MemberCaller1<Light, const char*, &Light::lightRotationChanged> LightRotationChangedCaller;
  895. public:
  896. Light(EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& boundsChanged, const Callback& evaluateTransform) :
  897. m_entity(eclass),
  898. m_originKey(OriginChangedCaller(*this)),
  899. m_rotationKey(RotationChangedCaller(*this)),
  900. m_colour(Callback()),
  901. m_filter(m_entity, node),
  902. m_named(m_entity),
  903. m_nameKeys(m_entity),
  904. m_funcStaticOrigin(m_traverse, m_originKey.m_origin),
  905. m_radii_wire(m_radii, m_aabb_light.origin),
  906. m_radii_fill(m_radii, m_aabb_light.origin),
  907. m_radii_box(m_aabb_light.origin),
  908. m_render_center(m_doom3Radius.m_center, m_entity.getEntityClass()),
  909. m_renderName(m_named, m_aabb_light.origin),
  910. m_useLightOrigin(false),
  911. m_useLightRotation(false),
  912. m_renderProjection(m_doom3Projection),
  913. m_transformChanged(transformChanged),
  914. m_boundsChanged(boundsChanged),
  915. m_evaluateTransform(evaluateTransform)
  916. {
  917. construct();
  918. }
  919. Light(const Light& other, scene::Node& node, const Callback& transformChanged, const Callback& boundsChanged, const Callback& evaluateTransform) :
  920. m_entity(other.m_entity),
  921. m_originKey(OriginChangedCaller(*this)),
  922. m_rotationKey(RotationChangedCaller(*this)),
  923. m_colour(Callback()),
  924. m_filter(m_entity, node),
  925. m_named(m_entity),
  926. m_nameKeys(m_entity),
  927. m_funcStaticOrigin(m_traverse, m_originKey.m_origin),
  928. m_radii_wire(m_radii, m_aabb_light.origin),
  929. m_radii_fill(m_radii, m_aabb_light.origin),
  930. m_radii_box(m_aabb_light.origin),
  931. m_render_center(m_doom3Radius.m_center, m_entity.getEntityClass()),
  932. m_renderName(m_named, m_aabb_light.origin),
  933. m_useLightOrigin(false),
  934. m_useLightRotation(false),
  935. m_renderProjection(m_doom3Projection),
  936. m_transformChanged(transformChanged),
  937. m_boundsChanged(boundsChanged),
  938. m_evaluateTransform(evaluateTransform)
  939. {
  940. construct();
  941. }
  942. ~Light()
  943. {
  944. destroy();
  945. }
  946. InstanceCounter m_instanceCounter;
  947. void instanceAttach(const scene::Path& path)
  948. {
  949. if(++m_instanceCounter.m_count == 1)
  950. {
  951. m_filter.instanceAttach();
  952. m_entity.instanceAttach(path_find_mapfile(path.begin(), path.end()));
  953. if(g_lightType == LIGHTTYPE_DOOM3)
  954. {
  955. m_traverse.instanceAttach(path_find_mapfile(path.begin(), path.end()));
  956. }
  957. m_entity.attach(m_keyObservers);
  958. if(g_lightType == LIGHTTYPE_DOOM3)
  959. {
  960. m_funcStaticOrigin.enable();
  961. }
  962. }
  963. }
  964. void instanceDetach(const scene::Path& path)
  965. {
  966. if(--m_instanceCounter.m_count == 0)
  967. {
  968. if(g_lightType == LIGHTTYPE_DOOM3)
  969. {
  970. m_funcStaticOrigin.disable();
  971. }
  972. m_entity.detach(m_keyObservers);
  973. if(g_lightType == LIGHTTYPE_DOOM3)
  974. {
  975. m_traverse.instanceDetach(path_find_mapfile(path.begin(), path.end()));
  976. }
  977. m_entity.instanceDetach(path_find_mapfile(path.begin(), path.end()));
  978. m_filter.instanceDetach();
  979. }
  980. }
  981. EntityKeyValues& getEntity()
  982. {
  983. return m_entity;
  984. }
  985. const EntityKeyValues& getEntity() const
  986. {
  987. return m_entity;
  988. }
  989. scene::Traversable& getTraversable()
  990. {
  991. return m_traverse;
  992. }
  993. Namespaced& getNamespaced()
  994. {
  995. return m_nameKeys;
  996. }
  997. Nameable& getNameable()
  998. {
  999. return m_named;
  1000. }
  1001. TransformNode& getTransformNode()
  1002. {
  1003. return m_transform;
  1004. }
  1005. void attach(scene::Traversable::Observer* observer)
  1006. {
  1007. m_traverseObservers.attach(*observer);
  1008. }
  1009. void detach(scene::Traversable::Observer* observer)
  1010. {
  1011. m_traverseObservers.detach(*observer);
  1012. }
  1013. void render(RenderStateFlags state) const
  1014. {
  1015. if(!g_newLightDraw)
  1016. {
  1017. aabb_draw(m_aabb_light, state);
  1018. }
  1019. else
  1020. {
  1021. light_draw(m_aabb_light, state);
  1022. }
  1023. }
  1024. VolumeIntersectionValue intersectVolume(const VolumeTest& volume, const Matrix4& localToWorld) const
  1025. {
  1026. return volume.TestAABB(m_aabb_light, localToWorld);
  1027. }
  1028. // cache
  1029. const AABB& localAABB() const
  1030. {
  1031. return m_aabb_light;
  1032. }
  1033. mutable Matrix4 m_projectionOrientation;
  1034. void renderSolid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
  1035. {
  1036. renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
  1037. renderer.SetState(m_colour.state(), Renderer::eFullMaterials);
  1038. renderer.addRenderable(*this, localToWorld);
  1039. if(selected && g_lightRadii && string_empty(m_entity.getKeyValue("target")))
  1040. {
  1041. if(renderer.getStyle() == Renderer::eFullMaterials)
  1042. {
  1043. renderer.SetState(RenderLightRadiiFill::m_state, Renderer::eFullMaterials);
  1044. renderer.Highlight(Renderer::ePrimitive, false);
  1045. renderer.addRenderable(m_radii_fill, localToWorld);
  1046. }
  1047. else
  1048. {
  1049. renderer.addRenderable(m_radii_wire, localToWorld);
  1050. }
  1051. }
  1052. renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eFullMaterials);
  1053. if(g_lightType == LIGHTTYPE_DOOM3 && selected)
  1054. {
  1055. if(isProjected())
  1056. {
  1057. projection();
  1058. m_projectionOrientation = rotation();
  1059. vector4_to_vector3(m_projectionOrientation.t()) = localAABB().origin;
  1060. renderer.addRenderable(m_renderProjection, m_projectionOrientation);
  1061. }
  1062. else
  1063. {
  1064. updateLightRadiiBox();
  1065. renderer.addRenderable(m_radii_box, localToWorld);
  1066. }
  1067. //draw the center of the light
  1068. if(m_doom3Radius.m_useCenterKey)
  1069. {
  1070. renderer.Highlight(Renderer::ePrimitive, false);
  1071. renderer.Highlight(Renderer::eFace, false);
  1072. renderer.SetState(m_render_center.m_state, Renderer::eFullMaterials);
  1073. renderer.SetState(m_render_center.m_state, Renderer::eWireframeOnly);
  1074. renderer.addRenderable(m_render_center, localToWorld);
  1075. }
  1076. }
  1077. }
  1078. void renderWireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected) const
  1079. {
  1080. renderSolid(renderer, volume, localToWorld, selected);
  1081. if(g_showNames)
  1082. {
  1083. renderer.addRenderable(m_renderName, localToWorld);
  1084. }
  1085. }
  1086. void testSelect(Selector& selector, SelectionTest& test, const Matrix4& localToWorld)
  1087. {
  1088. test.BeginMesh(localToWorld);
  1089. SelectionIntersection best;
  1090. aabb_testselect(m_aabb_light, test, best);
  1091. if(best.valid())
  1092. {
  1093. selector.addIntersection(best);
  1094. }
  1095. }
  1096. void translate(const Vector3& translation)
  1097. {
  1098. m_aabb_light.origin = origin_translated(m_aabb_light.origin, translation);
  1099. }
  1100. void rotate(const Quaternion& rotation)
  1101. {
  1102. rotation_rotate(m_rotation, rotation);
  1103. }
  1104. void snapto(float snap)
  1105. {
  1106. if(g_lightType == LIGHTTYPE_DOOM3 && !m_useLightOrigin && !m_traverse.empty())
  1107. {
  1108. m_useLightOrigin = true;
  1109. m_lightOrigin = m_originKey.m_origin;
  1110. }
  1111. if(m_useLightOrigin)
  1112. {
  1113. m_lightOrigin = origin_snapped(m_lightOrigin, snap);
  1114. writeLightOrigin();
  1115. }
  1116. else
  1117. {
  1118. m_originKey.m_origin = origin_snapped(m_originKey.m_origin, snap);
  1119. m_originKey.write(&m_entity);
  1120. }
  1121. }
  1122. void revertTransform()
  1123. {
  1124. m_aabb_light.origin = m_useLightOrigin ? m_lightOrigin : m_originKey.m_origin;
  1125. rotation_assign(m_rotation, m_useLightRotation ? m_lightRotation : m_rotationKey.m_rotation);
  1126. }
  1127. void freezeTransform()
  1128. {
  1129. if(g_lightType == LIGHTTYPE_DOOM3 && !m_useLightOrigin && !m_traverse.empty())
  1130. {
  1131. m_useLightOrigin = true;
  1132. }
  1133. if(m_useLightOrigin)
  1134. {
  1135. m_lightOrigin = m_aabb_light.origin;
  1136. writeLightOrigin();
  1137. }
  1138. else
  1139. {
  1140. m_originKey.m_origin = m_aabb_light.origin;
  1141. m_originKey.write(&m_entity);
  1142. }
  1143. if(g_lightType == LIGHTTYPE_DOOM3)
  1144. {
  1145. if(!m_useLightRotation && !m_traverse.empty())
  1146. {
  1147. m_useLightRotation = true;
  1148. }
  1149. if(m_useLightRotation)
  1150. {
  1151. rotation_assign(m_lightRotation, m_rotation);
  1152. write_rotation(m_lightRotation, &m_entity, "light_rotation");
  1153. }
  1154. rotation_assign(m_rotationKey.m_rotation, m_rotation);
  1155. write_rotation(m_rotationKey.m_rotation, &m_entity);
  1156. }
  1157. }
  1158. void transformChanged()
  1159. {
  1160. revertTransform();
  1161. m_evaluateTransform();
  1162. updateOrigin();
  1163. }
  1164. typedef MemberCaller<Light, &Light::transformChanged> TransformChangedCaller;
  1165. mutable Matrix4 m_localPivot;
  1166. const Matrix4& getLocalPivot() const
  1167. {
  1168. m_localPivot = rotation_toMatrix(m_rotation);
  1169. vector4_to_vector3(m_localPivot.t()) = m_aabb_light.origin;
  1170. return m_localPivot;
  1171. }
  1172. void setLightChangedCallback(const Callback& callback)
  1173. {
  1174. m_doom3Radius.m_changed = callback;
  1175. }
  1176. const AABB& aabb() const
  1177. {
  1178. m_doom3AABB = AABB(m_aabb_light.origin, m_doom3Radius.m_radius);
  1179. return m_doom3AABB;
  1180. }
  1181. bool testAABB(const AABB& other) const
  1182. {
  1183. if(isProjected())
  1184. {
  1185. Matrix4 transform = rotation();
  1186. vector4_to_vector3(transform.t()) = localAABB().origin;
  1187. projection();
  1188. Frustum frustum(frustum_transformed(m_doom3Frustum, transform));
  1189. return frustum_test_aabb(frustum, other) != c_volumeOutside;
  1190. }
  1191. // test against an AABB which contains the rotated bounds of this light.
  1192. const AABB& bounds = aabb();
  1193. return aabb_intersects_aabb(other, AABB(
  1194. bounds.origin,
  1195. Vector3(
  1196. static_cast<float>(fabs(m_rotation[0] * bounds.extents[0])
  1197. + fabs(m_rotation[3] * bounds.extents[1])
  1198. + fabs(m_rotation[6] * bounds.extents[2])),
  1199. static_cast<float>(fabs(m_rotation[1] * bounds.extents[0])
  1200. + fabs(m_rotation[4] * bounds.extents[1])
  1201. + fabs(m_rotation[7] * bounds.extents[2])),
  1202. static_cast<float>(fabs(m_rotation[2] * bounds.extents[0])
  1203. + fabs(m_rotation[5] * bounds.extents[1])
  1204. + fabs(m_rotation[8] * bounds.extents[2]))
  1205. )
  1206. ));
  1207. }
  1208. const Matrix4& rotation() const
  1209. {
  1210. m_doom3Rotation = rotation_toMatrix(m_rotation);
  1211. return m_doom3Rotation;
  1212. }
  1213. const Vector3& offset() const
  1214. {
  1215. return m_doom3Radius.m_center;
  1216. }
  1217. const Vector3& colour() const
  1218. {
  1219. return m_colour.m_colour;
  1220. }
  1221. bool isProjected() const
  1222. {
  1223. return m_useLightTarget && m_useLightUp && m_useLightRight;
  1224. }
  1225. void projectionChanged()
  1226. {
  1227. m_doom3ProjectionChanged = true;
  1228. m_doom3Radius.m_changed();
  1229. SceneChangeNotify();
  1230. }
  1231. const Matrix4& projection() const
  1232. {
  1233. if(!m_doom3ProjectionChanged)
  1234. {
  1235. return m_doom3Projection;
  1236. }
  1237. m_doom3ProjectionChanged = false;
  1238. m_doom3Projection = g_matrix4_identity;
  1239. matrix4_translate_by_vec3(m_doom3Projection, Vector3(0.5f, 0.5f, 0));
  1240. matrix4_scale_by_vec3(m_doom3Projection, Vector3(0.5f, 0.5f, 1));
  1241. #if 0
  1242. Vector3 right = vector3_cross(m_lightUp, vector3_normalised(m_lightTarget));
  1243. Vector3 up = vector3_cross(vector3_normalised(m_lightTarget), m_lightRight);
  1244. Vector3 target = m_lightTarget;
  1245. Matrix4 test(
  1246. -right.x(), -right.y(), -right.z(), 0,
  1247. -up.x(), -up.y(), -up.z(), 0,
  1248. -target.x(), -target.y(), -target.z(), 0,
  1249. 0, 0, 0, 1
  1250. );
  1251. Matrix4 frustum = matrix4_frustum(-0.01, 0.01, -0.01, 0.01, 0.01, 1.0);
  1252. test = matrix4_full_inverse(test);
  1253. matrix4_premultiply_by_matrix4(test, frustum);
  1254. matrix4_multiply_by_matrix4(m_doom3Projection, test);
  1255. #elif 0
  1256. const float nearFar = 1 / 49.5f;
  1257. Vector3 right = vector3_cross(m_lightUp, vector3_normalised(m_lightTarget + m_lightRight));
  1258. Vector3 up = vector3_cross(vector3_normalised(m_lightTarget + m_lightUp), m_lightRight);
  1259. Vector3 target = vector3_negated(m_lightTarget * (1 + nearFar));
  1260. float scale = -1 / vector3_length(m_lightTarget);
  1261. Matrix4 test(
  1262. -inverse(right.x()), -inverse(up.x()), -inverse(target.x()), 0,
  1263. -inverse(right.y()), -inverse(up.y()), -inverse(target.y()), 0,
  1264. -inverse(right.z()), -inverse(up.z()), -inverse(target.z()), scale,
  1265. 0, 0, -nearFar, 0
  1266. );
  1267. matrix4_multiply_by_matrix4(m_doom3Projection, test);
  1268. #elif 0
  1269. Vector3 leftA(m_lightTarget - m_lightRight);
  1270. Vector3 leftB(m_lightRight + m_lightUp);
  1271. Plane3 left(vector3_normalised(vector3_cross(leftA, leftB)) * (1.0 / 128), 0);
  1272. Vector3 rightA(m_lightTarget + m_lightRight);
  1273. Vector3 rightB(vector3_cross(rightA, m_lightTarget));
  1274. Plane3 right(vector3_normalised(vector3_cross(rightA, rightB)) * (1.0 / 128), 0);
  1275. Vector3 bottomA(m_lightTarget - m_lightUp);
  1276. Vector3 bottomB(vector3_cross(bottomA, m_lightTarget));
  1277. Plane3 bottom(vector3_normalised(vector3_cross(bottomA, bottomB)) * (1.0 / 128), 0);
  1278. Vector3 topA(m_lightTarget + m_lightUp);
  1279. Vector3 topB(vector3_cross(topA, m_lightTarget));
  1280. Plane3 top(vector3_normalised(vector3_cross(topA, topB)) * (1.0 / 128), 0);
  1281. Plane3 front(vector3_normalised(m_lightTarget) * (1.0 / 128), 1);
  1282. Plane3 back(vector3_normalised(vector3_negated(m_lightTarget)) * (1.0 / 128), 0);
  1283. Matrix4 test(matrix4_from_planes(plane3_flipped(left), plane3_flipped(right), plane3_flipped(bottom), plane3_flipped(top), plane3_flipped(front), plane3_flipped(back)));
  1284. matrix4_multiply_by_matrix4(m_doom3Projection, test);
  1285. #else
  1286. Plane3 lightProject[4];
  1287. Vector3 start = m_useLightStart && m_useLightEnd ? m_lightStart : vector3_normalised(m_lightTarget);
  1288. Vector3 stop = m_useLightStart && m_useLightEnd ? m_lightEnd : m_lightTarget;
  1289. float rLen = vector3_length(m_lightRight);
  1290. Vector3 right = vector3_divided(m_lightRight, rLen);
  1291. float uLen = vector3_length(m_lightUp);
  1292. Vector3 up = vector3_divided(m_lightUp, uLen);
  1293. Vector3 normal = vector3_normalised(vector3_cross(up, right));
  1294. float dist = vector3_dot(m_lightTarget, normal);
  1295. if ( dist < 0 ) {
  1296. dist = -dist;
  1297. normal = vector3_negated(normal);
  1298. }
  1299. right *= ( 0.5f * dist ) / rLen;
  1300. up *= -( 0.5f * dist ) / uLen;
  1301. lightProject[2] = Plane3(normal, 0);
  1302. lightProject[0] = Plane3(right, 0);
  1303. lightProject[1] = Plane3(up, 0);
  1304. // now offset to center
  1305. Vector4 targetGlobal(m_lightTarget, 1);
  1306. {
  1307. float a = vector4_dot(targetGlobal, plane3_to_vector4(lightProject[0]));
  1308. float b = vector4_dot(targetGlobal, plane3_to_vector4(lightProject[2]));
  1309. float ofs = 0.5f - a / b;
  1310. plane3_to_vector4(lightProject[0]) += plane3_to_vector4(lightProject[2]) * ofs;
  1311. }
  1312. {
  1313. float a = vector4_dot(targetGlobal, plane3_to_vector4(lightProject[1]));
  1314. float b = vector4_dot(targetGlobal, plane3_to_vector4(lightProject[2]));
  1315. float ofs = 0.5f - a / b;
  1316. plane3_to_vector4(lightProject[1]) += plane3_to_vector4(lightProject[2]) * ofs;
  1317. }
  1318. // set the falloff vector
  1319. Vector3 falloff = stop - start;
  1320. float length = vector3_length(falloff);
  1321. falloff = vector3_divided(falloff, length);
  1322. if ( length <= 0 ) {
  1323. length = 1;
  1324. }
  1325. falloff *= (1.0f / length);
  1326. lightProject[3] = Plane3(falloff, -vector3_dot(start, falloff));
  1327. // we want the planes of s=0, s=q, t=0, and t=q
  1328. m_doom3Frustum.left = lightProject[0];
  1329. m_doom3Frustum.bottom = lightProject[1];
  1330. m_doom3Frustum.right = Plane3(lightProject[2].normal() - lightProject[0].normal(), lightProject[2].dist() - lightProject[0].dist());
  1331. m_doom3Frustum.top = Plane3(lightProject[2].normal() - lightProject[1].normal(), lightProject[2].dist() - lightProject[1].dist());
  1332. // we want the planes of s=0 and s=1 for front and rear clipping planes
  1333. m_doom3Frustum.front = lightProject[3];
  1334. m_doom3Frustum.back = lightProject[3];
  1335. m_doom3Frustum.back.dist() -= 1.0f;
  1336. m_doom3Frustum.back = plane3_flipped(m_doom3Frustum.back);
  1337. Matrix4 test(matrix4_from_planes(m_doom3Frustum.left, m_doom3Frustum.right, m_doom3Frustum.bottom, m_doom3Frustum.top, m_doom3Frustum.front, m_doom3Frustum.back));
  1338. matrix4_multiply_by_matrix4(m_doom3Projection, test);
  1339. m_doom3Frustum.left = plane3_normalised(m_doom3Frustum.left);
  1340. m_doom3Frustum.right = plane3_normalised(m_doom3Frustum.right);
  1341. m_doom3Frustum.bottom = plane3_normalised(m_doom3Frustum.bottom);
  1342. m_doom3Frustum.top = plane3_normalised(m_doom3Frustum.top);
  1343. m_doom3Frustum.back = plane3_normalised(m_doom3Frustum.back);
  1344. m_doom3Frustum.front = plane3_normalised(m_doom3Frustum.front);
  1345. #endif
  1346. //matrix4_scale_by_vec3(m_doom3Projection, Vector3(1.0 / 128, 1.0 / 128, 1.0 / 128));
  1347. return m_doom3Projection;
  1348. }
  1349. Shader* getShader() const
  1350. {
  1351. return m_shader.get();
  1352. }
  1353. };
  1354. class LightInstance :
  1355. public TargetableInstance,
  1356. public TransformModifier,
  1357. public Renderable,
  1358. public SelectionTestable,
  1359. public RendererLight
  1360. {
  1361. class TypeCasts
  1362. {
  1363. InstanceTypeCastTable m_casts;
  1364. public:
  1365. TypeCasts()
  1366. {
  1367. m_casts = TargetableInstance::StaticTypeCasts::instance().get();
  1368. InstanceContainedCast<LightInstance, Bounded>::install(m_casts);
  1369. //InstanceContainedCast<LightInstance, Cullable>::install(m_casts);
  1370. InstanceStaticCast<LightInstance, Renderable>::install(m_casts);
  1371. InstanceStaticCast<LightInstance, SelectionTestable>::install(m_casts);
  1372. InstanceStaticCast<LightInstance, Transformable>::install(m_casts);
  1373. InstanceIdentityCast<LightInstance>::install(m_casts);
  1374. }
  1375. InstanceTypeCastTable& get()
  1376. {
  1377. return m_casts;
  1378. }
  1379. };
  1380. Light& m_contained;
  1381. public:
  1382. typedef LazyStatic<TypeCasts> StaticTypeCasts;
  1383. Bounded& get(NullType<Bounded>)
  1384. {
  1385. return m_contained;
  1386. }
  1387. STRING_CONSTANT(Name, "LightInstance");
  1388. LightInstance(const scene::Path& path, scene::Instance* parent, Light& contained) :
  1389. TargetableInstance(path, parent, this, StaticTypeCasts::instance().get(), contained.getEntity(), *this),
  1390. TransformModifier(Light::TransformChangedCaller(contained), ApplyTransformCaller(*this)),
  1391. m_contained(contained)
  1392. {
  1393. m_contained.instanceAttach(Instance::path());
  1394. if(g_lightType == LIGHTTYPE_DOOM3)
  1395. {
  1396. GlobalShaderCache().attach(*this);
  1397. m_contained.setLightChangedCallback(LightChangedCaller(*this));
  1398. }
  1399. StaticRenderableConnectionLines::instance().attach(*this);
  1400. }
  1401. ~LightInstance()
  1402. {
  1403. StaticRenderableConnectionLines::instance().detach(*this);
  1404. if(g_lightType == LIGHTTYPE_DOOM3)
  1405. {
  1406. m_contained.setLightChangedCallback(Callback());
  1407. GlobalShaderCache().detach(*this);
  1408. }
  1409. m_contained.instanceDetach(Instance::path());
  1410. }
  1411. void renderSolid(Renderer& renderer, const VolumeTest& volume) const
  1412. {
  1413. m_contained.renderSolid(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
  1414. }
  1415. void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
  1416. {
  1417. m_contained.renderWireframe(renderer, volume, Instance::localToWorld(), getSelectable().isSelected());
  1418. }
  1419. void testSelect(Selector& selector, SelectionTest& test)
  1420. {
  1421. m_contained.testSelect(selector, test, Instance::localToWorld());
  1422. }
  1423. void evaluateTransform()
  1424. {
  1425. if(getType() == TRANSFORM_PRIMITIVE)
  1426. {
  1427. m_contained.translate(getTranslation());
  1428. m_contained.rotate(getRotation());
  1429. }
  1430. }
  1431. void applyTransform()
  1432. {
  1433. m_contained.revertTransform();
  1434. evaluateTransform();
  1435. m_contained.freezeTransform();
  1436. }
  1437. typedef MemberCaller<LightInstance, &LightInstance::applyTransform> ApplyTransformCaller;
  1438. void lightChanged()
  1439. {
  1440. GlobalShaderCache().changed(*this);
  1441. }
  1442. typedef MemberCaller<LightInstance, &LightInstance::lightChanged> LightChangedCaller;
  1443. Shader* getShader() const
  1444. {
  1445. return m_contained.getShader();
  1446. }
  1447. const AABB& aabb() const
  1448. {
  1449. return m_contained.aabb();
  1450. }
  1451. bool testAABB(const AABB& other) const
  1452. {
  1453. return m_contained.testAABB(other);
  1454. }
  1455. const Matrix4& rotation() const
  1456. {
  1457. return m_contained.rotation();
  1458. }
  1459. const Vector3& offset() const
  1460. {
  1461. return m_contained.offset();
  1462. }
  1463. const Vector3& colour() const
  1464. {
  1465. return m_contained.colour();
  1466. }
  1467. bool isProjected() const
  1468. {
  1469. return m_contained.isProjected();
  1470. }
  1471. const Matrix4& projection() const
  1472. {
  1473. return m_contained.projection();
  1474. }
  1475. };
  1476. class LightNode :
  1477. public scene::Node::Symbiot,
  1478. public scene::Instantiable,
  1479. public scene::Cloneable,
  1480. public scene::Traversable::Observer
  1481. {
  1482. class TypeCasts
  1483. {
  1484. NodeTypeCastTable m_casts;
  1485. public:
  1486. TypeCasts()
  1487. {
  1488. NodeStaticCast<LightNode, scene::Instantiable>::install(m_casts);
  1489. NodeStaticCast<LightNode, scene::Cloneable>::install(m_casts);
  1490. if(g_lightType == LIGHTTYPE_DOOM3)
  1491. {
  1492. NodeContainedCast<LightNode, scene::Traversable>::install(m_casts);
  1493. }
  1494. NodeContainedCast<LightNode, Editable>::install(m_casts);
  1495. NodeContainedCast<LightNode, Snappable>::install(m_casts);
  1496. NodeContainedCast<LightNode, TransformNode>::install(m_casts);
  1497. NodeContainedCast<LightNode, Entity>::install(m_casts);
  1498. NodeContainedCast<LightNode, Nameable>::install(m_casts);
  1499. NodeContainedCast<LightNode, Namespaced>::install(m_casts);
  1500. }
  1501. NodeTypeCastTable& get()
  1502. {
  1503. return m_casts;
  1504. }
  1505. };
  1506. scene::Node m_node;
  1507. InstanceSet m_instances;
  1508. Light m_contained;
  1509. void construct()
  1510. {
  1511. if(g_lightType == LIGHTTYPE_DOOM3)
  1512. {
  1513. m_contained.attach(this);
  1514. }
  1515. }
  1516. void destroy()
  1517. {
  1518. if(g_lightType == LIGHTTYPE_DOOM3)
  1519. {
  1520. m_contained.detach(this);
  1521. }
  1522. }
  1523. public:
  1524. typedef LazyStatic<TypeCasts> StaticTypeCasts;
  1525. scene::Traversable& get(NullType<scene::Traversable>)
  1526. {
  1527. return m_contained.getTraversable();
  1528. }
  1529. Editable& get(NullType<Editable>)
  1530. {
  1531. return m_contained;
  1532. }
  1533. Snappable& get(NullType<Snappable>)
  1534. {
  1535. return m_contained;
  1536. }
  1537. TransformNode& get(NullType<TransformNode>)
  1538. {
  1539. return m_contained.getTransformNode();
  1540. }
  1541. Entity& get(NullType<Entity>)
  1542. {
  1543. return m_contained.getEntity();
  1544. }
  1545. Nameable& get(NullType<Nameable>)
  1546. {
  1547. return m_contained.getNameable();
  1548. }
  1549. Namespaced& get(NullType<Namespaced>)
  1550. {
  1551. return m_contained.getNamespaced();
  1552. }
  1553. LightNode(EntityClass* eclass) :
  1554. m_node(this, this, StaticTypeCasts::instance().get()),
  1555. m_contained(eclass, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSet::BoundsChangedCaller(m_instances), InstanceSetEvaluateTransform<LightInstance>::Caller(m_instances))
  1556. {
  1557. construct();
  1558. }
  1559. LightNode(const LightNode& other) :
  1560. scene::Node::Symbiot(other),
  1561. scene::Instantiable(other),
  1562. scene::Cloneable(other),
  1563. scene::Traversable::Observer(other),
  1564. m_node(this, this, StaticTypeCasts::instance().get()),
  1565. m_contained(other.m_contained, m_node, InstanceSet::TransformChangedCaller(m_instances), InstanceSet::BoundsChangedCaller(m_instances), InstanceSetEvaluateTransform<LightInstance>::Caller(m_instances))
  1566. {
  1567. construct();
  1568. }
  1569. ~LightNode()
  1570. {
  1571. destroy();
  1572. }
  1573. void release()
  1574. {
  1575. delete this;
  1576. }
  1577. scene::Node& node()
  1578. {
  1579. return m_node;
  1580. }
  1581. scene::Node& clone() const
  1582. {
  1583. return (new LightNode(*this))->node();
  1584. }
  1585. void insert(scene::Node& child)
  1586. {
  1587. m_instances.insert(child);
  1588. }
  1589. void erase(scene::Node& child)
  1590. {
  1591. m_instances.erase(child);
  1592. }
  1593. scene::Instance* create(const scene::Path& path, scene::Instance* parent)
  1594. {
  1595. return new LightInstance(path, parent, m_contained);
  1596. }
  1597. void forEachInstance(const scene::Instantiable::Visitor& visitor)
  1598. {
  1599. m_instances.forEachInstance(visitor);
  1600. }
  1601. void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
  1602. {
  1603. m_instances.insert(observer, path, instance);
  1604. }
  1605. scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
  1606. {
  1607. return m_instances.erase(observer, path);
  1608. }
  1609. };
  1610. void Light_Construct(LightType lightType)
  1611. {
  1612. g_lightType = lightType;
  1613. if(g_lightType == LIGHTTYPE_DOOM3)
  1614. {
  1615. LightShader::m_defaultShader = "lights/defaultPointLight";
  1616. #if 0
  1617. LightShader::m_defaultShader = "lights/defaultProjectedLight";
  1618. #endif
  1619. }
  1620. RenderLightRadiiFill::m_state = GlobalShaderCache().capture("$Q3MAP2_LIGHT_SPHERE");
  1621. RenderLightCenter::m_state = GlobalShaderCache().capture("$BIGPOINT");
  1622. }
  1623. void Light_Destroy()
  1624. {
  1625. GlobalShaderCache().release("$Q3MAP2_LIGHT_SPHERE");
  1626. GlobalShaderCache().release("$BIGPOINT");
  1627. }
  1628. scene::Node& New_Light(EntityClass* eclass)
  1629. {
  1630. return (new LightNode(eclass))->node();
  1631. }