r3d_lighting.odin 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. /* r3d_lighting.odin -- R3D Lighting Module.
  2. *
  3. * Copyright (c) 2025-2026 Le Juez Victor
  4. *
  5. * This software is provided 'as-is', without any express or implied warranty.
  6. * For conditions of distribution and use, see accompanying LICENSE file.
  7. */
  8. package r3d
  9. import rl "vendor:raylib"
  10. when ODIN_OS == .Windows {
  11. foreign import lib {
  12. "windows/libr3d.a",
  13. "system:raylib",
  14. "system:assimp",
  15. }
  16. } else when ODIN_OS == .Linux {
  17. foreign import lib {
  18. "linux/libr3d.a",
  19. "system:raylib",
  20. "system:assimp",
  21. }
  22. } else when ODIN_OS == .Darwin {
  23. foreign import lib {
  24. "darwin/libr3d.a",
  25. "system:raylib",
  26. "system:assimp",
  27. }
  28. }
  29. /**
  30. * @brief Types of lights supported by the rendering engine.
  31. *
  32. * Each light type has different behaviors and use cases.
  33. */
  34. LightType :: enum u32 {
  35. DIR = 0, ///< Directional light, affects the entire scene with parallel rays.
  36. SPOT = 1, ///< Spot light, emits light in a cone shape.
  37. OMNI = 2, ///< Omni light, emits light in all directions from a single point.
  38. TYPE_COUNT = 3,
  39. }
  40. /**
  41. * @brief Modes for updating shadow maps.
  42. *
  43. * Determines how often the shadow maps are refreshed.
  44. */
  45. ShadowUpdateMode :: enum u32 {
  46. MANUAL = 0, ///< Shadow maps update only when explicitly requested.
  47. INTERVAL = 1, ///< Shadow maps update at defined time intervals.
  48. CONTINUOUS = 2, ///< Shadow maps update every frame for real-time accuracy.
  49. }
  50. /**
  51. * @brief Unique identifier for an R3D light.
  52. *
  53. * ID type used to reference a light.
  54. * A negative value indicates an invalid light.
  55. */
  56. Light :: i32
  57. @(default_calling_convention="c", link_prefix="R3D_")
  58. foreign lib {
  59. /**
  60. * @brief Creates a new light of the specified type.
  61. *
  62. * This function creates a light of the given type. The light must be destroyed
  63. * manually when no longer needed by calling `R3D_DestroyLight`.
  64. *
  65. * @param type The type of light to create (directional, spot or omni-directional).
  66. * @return The ID of the created light.
  67. */
  68. CreateLight :: proc(type: LightType) -> Light ---
  69. /**
  70. * @brief Destroys the specified light.
  71. *
  72. * This function deallocates the resources associated with the light and makes
  73. * the light ID invalid. It must be called after the light is no longer needed.
  74. *
  75. * @param id The ID of the light to destroy.
  76. */
  77. DestroyLight :: proc(id: Light) ---
  78. /**
  79. * @brief Checks if a light exists.
  80. *
  81. * This function checks if the specified light ID is valid and if the light exists.
  82. *
  83. * @param id The ID of the light to check.
  84. * @return True if the light exists, false otherwise.
  85. */
  86. IsLightExist :: proc(id: Light) -> bool ---
  87. /**
  88. * @brief Gets the type of a light.
  89. *
  90. * This function returns the type of the specified light (directional, spot or omni-directional).
  91. *
  92. * @param id The ID of the light.
  93. * @return The type of the light.
  94. */
  95. GetLightType :: proc(id: Light) -> LightType ---
  96. /**
  97. * @brief Checks if a light is active.
  98. *
  99. * This function checks whether the specified light is currently active (enabled or disabled).
  100. *
  101. * @param id The ID of the light to check.
  102. * @return True if the light is active, false otherwise.
  103. */
  104. IsLightActive :: proc(id: Light) -> bool ---
  105. /**
  106. * @brief Toggles the state of a light (active or inactive).
  107. *
  108. * This function toggles the state of the specified light, turning it on if it is off,
  109. * or off if it is on.
  110. *
  111. * @param id The ID of the light to toggle.
  112. */
  113. ToggleLight :: proc(id: Light) ---
  114. /**
  115. * @brief Sets the active state of a light.
  116. *
  117. * This function allows manually turning a light on or off by specifying its active state.
  118. *
  119. * @param id The ID of the light to set the active state for.
  120. * @param active True to activate the light, false to deactivate it.
  121. */
  122. SetLightActive :: proc(id: Light, active: bool) ---
  123. /**
  124. * @brief Gets the color of a light.
  125. *
  126. * This function retrieves the color of the specified light as a `rl.Color` structure.
  127. *
  128. * @param id The ID of the light.
  129. * @return The color of the light as a `rl.Color` structure.
  130. */
  131. GetLightColor :: proc(id: Light) -> rl.Color ---
  132. /**
  133. * @brief Gets the color of a light as a `rl.Vector3`.
  134. *
  135. * This function retrieves the color of the specified light as a `rl.Vector3`, where each
  136. * component (x, y, z) represents the RGB values of the light.
  137. *
  138. * @param id The ID of the light.
  139. * @return The color of the light as a `rl.Vector3`.
  140. */
  141. GetLightColorV :: proc(id: Light) -> rl.Vector3 ---
  142. /**
  143. * @brief Sets the color of a light.
  144. *
  145. * This function sets the color of the specified light using a `rl.Color` structure.
  146. *
  147. * @param id The ID of the light.
  148. * @param color The new color to set for the light.
  149. */
  150. SetLightColor :: proc(id: Light, color: rl.Color) ---
  151. /**
  152. * @brief Sets the color of a light using a `rl.Vector3`.
  153. *
  154. * This function sets the color of the specified light using a `rl.Vector3`, where each
  155. * component (x, y, z) represents the RGB values of the light.
  156. *
  157. * @param id The ID of the light.
  158. * @param color The new color to set for the light as a `rl.Vector3`.
  159. */
  160. SetLightColorV :: proc(id: Light, color: rl.Vector3) ---
  161. /**
  162. * @brief Gets the position of a light.
  163. *
  164. * This function retrieves the position of the specified light.
  165. * Only applicable to spot lights or omni-lights.
  166. *
  167. * @param id The ID of the light.
  168. * @return The position of the light as a `rl.Vector3`.
  169. */
  170. GetLightPosition :: proc(id: Light) -> rl.Vector3 ---
  171. /**
  172. * @brief Sets the position of a light.
  173. *
  174. * This function sets the position of the specified light.
  175. * Only applicable to spot lights or omni-lights.
  176. *
  177. * @note Has no effect for directional lights.
  178. * If called on a directional light,
  179. * a warning will be logged.
  180. *
  181. * @param id The ID of the light.
  182. * @param position The new position to set for the light.
  183. */
  184. SetLightPosition :: proc(id: Light, position: rl.Vector3) ---
  185. /**
  186. * @brief Gets the direction of a light.
  187. *
  188. * This function retrieves the direction of the specified light.
  189. * Only applicable to directional lights or spot lights.
  190. *
  191. * @param id The ID of the light.
  192. * @return The direction of the light as a `rl.Vector3`.
  193. */
  194. GetLightDirection :: proc(id: Light) -> rl.Vector3 ---
  195. /**
  196. * @brief Sets the direction of a light.
  197. *
  198. * This function sets the direction of the specified light.
  199. * Only applicable to directional lights or spot lights.
  200. *
  201. * @note Has no effect for omni-directional lights.
  202. * If called on an omni-directional light,
  203. * a warning will be logged.
  204. *
  205. * @param id The ID of the light.
  206. * @param direction The new direction to set for the light.
  207. * The vector is automatically normalized.
  208. */
  209. SetLightDirection :: proc(id: Light, direction: rl.Vector3) ---
  210. /**
  211. * @brief Sets the position and direction of a light to look at a target point.
  212. *
  213. * This function sets both the position and the direction of the specified light,
  214. * causing it to "look at" a given target point.
  215. *
  216. * @note - For directional lights, only the direction is updated (position is ignored).
  217. * - For omni-directional lights, only the position is updated (direction is not calculated).
  218. * - For spot lights, both position and direction are set accordingly.
  219. * - This function does **not** emit any warning or log message.
  220. *
  221. * @param id The ID of the light.
  222. * @param position The position to set for the light.
  223. * @param target The point the light should look at.
  224. */
  225. LightLookAt :: proc(id: Light, position: rl.Vector3, target: rl.Vector3) ---
  226. /**
  227. * @brief Gets the energy level of a light.
  228. *
  229. * This function retrieves the energy level (intensity) of the specified light.
  230. * Energy typically affects the brightness of the light.
  231. *
  232. * @param id The ID of the light.
  233. * @return The energy level of the light.
  234. */
  235. GetLightEnergy :: proc(id: Light) -> f32 ---
  236. /**
  237. * @brief Sets the energy level of a light.
  238. *
  239. * This function sets the energy (intensity) of the specified light.
  240. * A higher energy value will result in a brighter light.
  241. *
  242. * @param id The ID of the light.
  243. * @param energy The new energy value to set for the light.
  244. */
  245. SetLightEnergy :: proc(id: Light, energy: f32) ---
  246. /**
  247. * @brief Gets the specular intensity of a light.
  248. *
  249. * This function retrieves the current specular intensity of the specified light.
  250. * Specular intensity affects how shiny surfaces appear when reflecting the light.
  251. *
  252. * @param id The ID of the light.
  253. * @return The current specular intensity of the light.
  254. */
  255. GetLightSpecular :: proc(id: Light) -> f32 ---
  256. /**
  257. * @brief Sets the specular intensity of a light.
  258. *
  259. * This function sets the specular intensity of the specified light.
  260. * Higher specular values result in stronger and sharper highlights on reflective surfaces.
  261. *
  262. * @param id The ID of the light.
  263. * @param specular The new specular intensity value to set for the light.
  264. */
  265. SetLightSpecular :: proc(id: Light, specular: f32) ---
  266. /**
  267. * @brief Gets the range of a light.
  268. *
  269. * This function retrieves the range of the specified light, which determines how far the light can affect.
  270. * Only applicable to spot lights or omni-lights.
  271. *
  272. * @param id The ID of the light.
  273. * @return The range of the light.
  274. */
  275. GetLightRange :: proc(id: Light) -> f32 ---
  276. /**
  277. * @brief Sets the range parameter of a light.
  278. *
  279. * For spot and omni lights, this defines the maximum illumination distance.
  280. * For directional lights, this defines the shadow rendering radius around the camera.
  281. *
  282. * @param id The ID of the light.
  283. * @param range The range value to apply.
  284. */
  285. SetLightRange :: proc(id: Light, range: f32) ---
  286. /**
  287. * @brief Gets the attenuation factor of a light.
  288. *
  289. * This function retrieves the attenuation factor of the specified light.
  290. * Attenuation controls how the intensity of a light decreases with distance.
  291. * Only applicable to spot lights or omni-lights.
  292. *
  293. * @param id The ID of the light.
  294. * @return The attenuation factor of the light.
  295. */
  296. GetLightAttenuation :: proc(id: Light) -> f32 ---
  297. /**
  298. * @brief Sets the attenuation factor of a light.
  299. *
  300. * This function sets the attenuation factor of the specified light.
  301. * A higher attenuation value causes the light to lose intensity more quickly as the distance increases.
  302. * For a realistic effect, an attenuation factor of 2.0f is typically used.
  303. * Only applicable to spot lights or omni-lights.
  304. *
  305. * @param id The ID of the light.
  306. * @param attenuation The new attenuation factor to set for the light.
  307. */
  308. SetLightAttenuation :: proc(id: Light, attenuation: f32) ---
  309. /**
  310. * @brief Gets the inner cutoff angle of a spotlight.
  311. *
  312. * This function retrieves the inner cutoff angle of a spotlight.
  313. * The inner cutoff defines the cone of light where the light is at full intensity.
  314. *
  315. * @param id The ID of the light.
  316. * @return The inner cutoff angle in degrees of the spotlight.
  317. */
  318. GetLightInnerCutOff :: proc(id: Light) -> f32 ---
  319. /**
  320. * @brief Sets the inner cutoff angle of a spotlight.
  321. *
  322. * This function sets the inner cutoff angle of a spotlight.
  323. * The inner cutoff angle defines the cone where the light is at full intensity.
  324. * Anything outside this cone starts to fade.
  325. *
  326. * @param id The ID of the light.
  327. * @param degrees The new inner cutoff angle in degrees.
  328. */
  329. SetLightInnerCutOff :: proc(id: Light, degrees: f32) ---
  330. /**
  331. * @brief Gets the outer cutoff angle of a spotlight.
  332. *
  333. * This function retrieves the outer cutoff angle of a spotlight.
  334. * The outer cutoff defines the outer boundary of the light's cone, where the light starts to fade.
  335. *
  336. * @param id The ID of the light.
  337. * @return The outer cutoff angle in degrees of the spotlight.
  338. */
  339. GetLightOuterCutOff :: proc(id: Light) -> f32 ---
  340. /**
  341. * @brief Sets the outer cutoff angle of a spotlight.
  342. *
  343. * This function sets the outer cutoff angle of a spotlight.
  344. * The outer cutoff defines the boundary of the light's cone where the light intensity starts to gradually decrease.
  345. *
  346. * @param id The ID of the light.
  347. * @param degrees The new outer cutoff angle in degrees.
  348. */
  349. SetLightOuterCutOff :: proc(id: Light, degrees: f32) ---
  350. /**
  351. * @brief Enables shadow rendering for a light.
  352. *
  353. * Turns on shadow rendering for the light. The engine will allocate a shadow
  354. * map if needed, or reuse one previously allocated for another light.
  355. *
  356. * Shadow map resolutions are fixed: 2048x2048 for spot and point lights,
  357. * and 4096x4096 for directional lights.
  358. *
  359. * @param id The ID of the light.
  360. *
  361. * @note Creating too many shadow-casting lights can exhaust GPU memory and
  362. * potentially crash the graphics driver. Disabling shadows on one light and
  363. * enabling them on another is free, since existing shadow maps are reused.
  364. */
  365. EnableShadow :: proc(id: Light) ---
  366. /**
  367. * @brief Disables shadow rendering for a light.
  368. *
  369. * Turns off shadow rendering for the light. The associated shadow map is
  370. * kept in memory and may later be reused by another light.
  371. *
  372. * @param id The ID of the light.
  373. */
  374. DisableShadow :: proc(id: Light) ---
  375. /**
  376. * @brief Checks if shadow casting is enabled for a light.
  377. *
  378. * This function checks if shadow casting is currently enabled for the specified light.
  379. *
  380. * @param id The ID of the light.
  381. * @return True if shadow casting is enabled, false otherwise.
  382. */
  383. IsShadowEnabled :: proc(id: Light) -> bool ---
  384. /**
  385. * @brief Gets the shadow map update mode of a light.
  386. *
  387. * This function retrieves the current mode for updating the shadow map of a light. The mode can be:
  388. * - Interval: Updates the shadow map at a fixed interval.
  389. * - Continuous: Updates the shadow map continuously.
  390. * - Manual: Updates the shadow map manually (via explicit function calls).
  391. *
  392. * @param id The ID of the light.
  393. * @return The shadow map update mode.
  394. */
  395. GetShadowUpdateMode :: proc(id: Light) -> ShadowUpdateMode ---
  396. /**
  397. * @brief Sets the shadow map update mode of a light.
  398. *
  399. * This function sets the mode for updating the shadow map of the specified light.
  400. * The update mode controls when and how often the shadow map is refreshed.
  401. *
  402. * @param id The ID of the light.
  403. * @param mode The update mode to set for the shadow map (Interval, Continuous, or Manual).
  404. */
  405. SetShadowUpdateMode :: proc(id: Light, mode: ShadowUpdateMode) ---
  406. /**
  407. * @brief Gets the frequency of shadow map updates for the interval update mode.
  408. *
  409. * This function retrieves the frequency (in milliseconds) at which the shadow map should be updated when
  410. * the interval update mode is enabled. This function is only relevant if the shadow map update mode is set
  411. * to "Interval".
  412. *
  413. * @param id The ID of the light.
  414. * @return The frequency in milliseconds at which the shadow map is updated.
  415. */
  416. GetShadowUpdateFrequency :: proc(id: Light) -> i32 ---
  417. /**
  418. * @brief Sets the frequency of shadow map updates for the interval update mode.
  419. *
  420. * This function sets the frequency (in milliseconds) at which the shadow map should be updated when
  421. * the interval update mode is enabled. This function is only relevant if the shadow map update mode is set
  422. * to "Interval".
  423. *
  424. * @param id The ID of the light.
  425. * @param msec The frequency in milliseconds at which to update the shadow map.
  426. */
  427. SetShadowUpdateFrequency :: proc(id: Light, msec: i32) ---
  428. /**
  429. * @brief Forces an immediate update of the shadow map during the next rendering pass.
  430. *
  431. * This function forces the shadow map of the specified light to be updated during the next call to `R3D_End`.
  432. * This is primarily used for the manual update mode, but may also work for the interval mode.
  433. *
  434. * @param id The ID of the light.
  435. */
  436. UpdateShadowMap :: proc(id: Light) ---
  437. /**
  438. * @brief Retrieves the softness radius used to simulate penumbra in shadows.
  439. *
  440. * The softness is expressed as a sampling radius in texels within the shadow map.
  441. *
  442. * @param id The ID of the light.
  443. * @return The softness radius in texels currently set for the shadow.
  444. */
  445. GetShadowSoftness :: proc(id: Light) -> f32 ---
  446. /**
  447. * @brief Sets the softness radius used to simulate penumbra in shadows.
  448. *
  449. * This function adjusts the softness of the shadow edges for the specified light.
  450. * The softness value corresponds to a number of texels in the shadow map, independent
  451. * of its resolution. Larger values increase the blur radius, resulting in softer,
  452. * more diffuse shadows, while smaller values yield sharper shadows.
  453. *
  454. * @param id The ID of the light.
  455. * @param softness The softness radius in texels to apply (must be >= 0).
  456. *
  457. * @note The softness must be set only after shadows have been enabled for the light,
  458. * since the shadow map resolution must be known before the softness can be applied.
  459. */
  460. SetShadowSoftness :: proc(id: Light, softness: f32) ---
  461. /**
  462. * @brief Gets the shadow depth bias value.
  463. */
  464. GetShadowDepthBias :: proc(id: Light) -> f32 ---
  465. /**
  466. * @brief Sets the shadow depth bias value.
  467. *
  468. * A higher bias helps reduce "shadow acne" artifacts
  469. * (shadows flickering or appearing misaligned on surfaces).
  470. * Be careful: too large values may cause shadows to look detached
  471. * or floating away from objects.
  472. */
  473. SetShadowDepthBias :: proc(id: Light, value: f32) ---
  474. /**
  475. * @brief Gets the shadow slope bias value.
  476. */
  477. GetShadowSlopeBias :: proc(id: Light) -> f32 ---
  478. /**
  479. * @brief Sets the shadow slope bias value.
  480. *
  481. * This bias mainly compensates artifacts on surfaces angled
  482. * relative to the light. It helps prevent shadows from
  483. * incorrectly appearing or disappearing along object edges.
  484. */
  485. SetShadowSlopeBias :: proc(id: Light, value: f32) ---
  486. /**
  487. * @brief Returns the bounding box encompassing the light's area of influence.
  488. *
  489. * This function computes the axis-aligned bounding box (AABB) that encloses the
  490. * volume affected by the specified light, based on its type:
  491. *
  492. * - For spotlights, the bounding box encloses the light cone.
  493. * - For omni-directional lights, it encloses a sphere representing the light's range.
  494. * - For directional lights, it returns an infinite bounding box to represent global influence.
  495. *
  496. * This bounding box is primarily useful for spatial partitioning, culling, or visual debugging.
  497. *
  498. * @param light The light for which to compute the bounding box.
  499. *
  500. * @return A rl.BoundingBox struct that encloses the light's influence volume.
  501. */
  502. GetLightBoundingBox :: proc(light: Light) -> rl.BoundingBox ---
  503. /**
  504. * @brief Draws the area of influence of the light in 3D space.
  505. *
  506. * This function visualizes the area affected by a light in 3D space.
  507. * It draws the light's influence, such as the cone for spotlights or the volume for omni-lights.
  508. * This function is only relevant for spotlights and omni-lights.
  509. *
  510. * @note This function should be called while using the default 3D rendering mode of raylib,
  511. * not with R3D's rendering mode. It uses raylib's 3D drawing functions to render the light's shape.
  512. *
  513. * @param id The ID of the light.
  514. */
  515. DrawLightShape :: proc(id: Light) ---
  516. }