Merge branch 'develop' into mod

This commit is contained in:
davidmarr 2024-12-07 08:37:39 +01:00
commit f978ad1b53
48 changed files with 611 additions and 3013 deletions

View file

@ -6,15 +6,18 @@ TombEngine releases are located in this repository (alongside with Tomb Editor):
## Version 1.6 - xxxx-xx-xx ## Version 1.6 - xxxx-xx-xx
### Bug fixes ### Bug fixes
* Fixed engine performance around bridges. * Significantly improved renderer performance.
* Fixed engine performance if weather or bubble effects are active. * Improved engine performance around bridges.
* Improved engine performance if weather or bubble effects are active.
* Fixed silent crashes if loaded level is corrupted or in incorrect format. * Fixed silent crashes if loaded level is corrupted or in incorrect format.
* Fixed occasional crashes if there are static meshes placed within room border walls. * Fixed occasional crashes if there are static meshes placed within room border walls.
* Fixed incorrect clipping of scaled off-centered static meshes. * Fixed incorrect clipping of scaled off-centered static meshes.
* Fixed incorrect collision detection for off-centered moveables. * Fixed incorrect collision detection for off-centered moveables.
* Fixed incorrect slide directions for sub-click geometry.
* Fixed stutter during jumps between cameras in a flyby sequence. * Fixed stutter during jumps between cameras in a flyby sequence.
* Fixed uzi targeting issues after using flycheat. * Fixed uzi targeting issues after using flycheat.
* Fixed snow particles not always melting on the ground. * Fixed snow particles not always melting on the ground.
* Fixed enemies not damaging Lara if she is staying on the sector where enemies were triggered.
* Fixed enemy pickups dropping on death sectors. * Fixed enemy pickups dropping on death sectors.
* Fixed Sarcophagus and Search Object pickup triggers. * Fixed Sarcophagus and Search Object pickup triggers.
* Fixed vehicle transfer not happening for levels which were not previously visited. * Fixed vehicle transfer not happening for levels which were not previously visited.
@ -30,6 +33,7 @@ TombEngine releases are located in this repository (alongside with Tomb Editor):
* Fixed original issue with deactivation of Dart Emitter. * Fixed original issue with deactivation of Dart Emitter.
* Fixed Lens Flare object not functioning properly. * Fixed Lens Flare object not functioning properly.
* Fixed lens flares not being occluded by static meshes and moveables. * Fixed lens flares not being occluded by static meshes and moveables.
* Fixed spotlight shadows.
* Fixed Skeleton and Mummy not reacting to shotgun hits. * Fixed Skeleton and Mummy not reacting to shotgun hits.
### New Features ### New Features
@ -43,14 +47,20 @@ TombEngine releases are located in this repository (alongside with Tomb Editor):
* Added Moveable:GetCollidable() and Moveable:SetCollidable() functions. * Added Moveable:GetCollidable() and Moveable:SetCollidable() functions.
* Added Flow.GetFreezeMode() and Flow.SetFreezeMode() functions. * Added Flow.GetFreezeMode() and Flow.SetFreezeMode() functions.
* Added Flow.GetNextLevel() function to get script entry for incoming level, if it's about to start. * Added Flow.GetNextLevel() function to get script entry for incoming level, if it's about to start.
* Added Effects.EmitSpotLight() function for directional spotlights.
* Added optional cast shadow and name parameters for Effects.EmitLight() function.
* Added Effects.GetWind() function to get current wind speed vector. * Added Effects.GetWind() function to get current wind speed vector.
* Added Rotation:Direction() method to get directional vector.
* Added support for transparency value in DisplayString class. * Added support for transparency value in DisplayString class.
* Added extra argument for SetAmbientTrack() function to specify if new ambient track should play from the beginning. * Added extra argument for SetAmbientTrack() function to specify if new ambient track should play from the beginning.
* Use load camera instead of load screen by playing fixed camera from OnEnd() event and removing loadScreenFile field from level's gameflow entry. * Use load camera instead of load screen by playing fixed camera from OnEnd() event and removing loadScreenFile field from level's gameflow entry.
* Fixed DisplayString class not supporting some Unicode characters and empty lines in multiline strings. * Fixed DisplayString class not supporting some Unicode characters and empty lines in multiline strings.
* Fixed DisplayString not being deallocated after showing.
* Fixed incorrect behaviour of Moveable:GetJointRotation() function.
* Fixed incorrect behaviour of Logic.EnableEvent() and Logic.DisableEvent() functions. * Fixed incorrect behaviour of Logic.EnableEvent() and Logic.DisableEvent() functions.
* Fixed Util.HasLineOfSight() not taking static meshes into consideration. * Fixed Util.HasLineOfSight() not taking static meshes into consideration.
* Fixed collision callbacks not properly clearing after leveljump. * Fixed collision callbacks not properly clearing after leveljump.
* Fixed SetIntroImagePath() not using the correct path
## [Version 1.5](https://github.com/TombEngine/TombEditorReleases/releases/tag/v1.7.2) - 2024-11-03 ## [Version 1.5](https://github.com/TombEngine/TombEditorReleases/releases/tag/v1.7.2) - 2024-11-03

View file

@ -1,8 +1,11 @@
@echo off @echo off
setlocal setlocal
set DOC_DIR=.\doc
set LDOC_DIR=.\compiler\ldoc set LDOC_DIR=.\compiler\ldoc
set LUA_PATH=.\compiler\?.lua set LUA_PATH=.\compiler\?.lua
set LUA_CPATH=.\compiler\?.dll set LUA_CPATH=.\compiler\?.dll
rmdir /s /q %DOC_DIR%
mkdir %DOC_DIR%
.\compiler\lua.exe %LDOC_DIR%\\ldoc.lua %* .\compiler\lua.exe %LDOC_DIR%\\ldoc.lua %*
del output.xml del output.xml
exit /b %ERRORLEVEL% exit /b %ERRORLEVEL%

View file

@ -125,10 +125,14 @@
<td class="summary">Emit a shockwave, similar to that seen when a harpy projectile hits something.</td> <td class="summary">Emit a shockwave, similar to that seen when a harpy projectile hits something.</td>
</tr> </tr>
<tr> <tr>
<td class="name" ><a href="#EmitLight">EmitLight(pos, color, radius)</a></td> <td class="name" ><a href="#EmitLight">EmitLight(pos[, color][, radius][, shadows][, name])</a></td>
<td class="summary">Emit dynamic light that lasts for a single frame.</td> <td class="summary">Emit dynamic light that lasts for a single frame.</td>
</tr> </tr>
<tr> <tr>
<td class="name" ><a href="#EmitSpotLight">EmitSpotLight(pos, dir[, color][, radius][, falloff][, distance][, shadows][, name])</a></td>
<td class="summary">Emit dynamic directional spotlight that lasts for a single frame.</td>
</tr>
<tr>
<td class="name" ><a href="#EmitBlood">EmitBlood(pos, count)</a></td> <td class="name" ><a href="#EmitBlood">EmitBlood(pos, count)</a></td>
<td class="summary">Emit blood.</td> <td class="summary">Emit blood.</td>
</tr> </tr>
@ -363,7 +367,7 @@
</dd> </dd>
<dt> <dt>
<a name = "EmitLight"></a> <a name = "EmitLight"></a>
<strong>EmitLight(pos, color, radius)</strong> <strong>EmitLight(pos[, color][, radius][, shadows][, name])</strong>
</dt> </dt>
<dd> <dd>
Emit dynamic light that lasts for a single frame. Emit dynamic light that lasts for a single frame.
@ -375,17 +379,84 @@
<ul> <ul>
<li><span class="parameter">pos</span> <li><span class="parameter">pos</span>
<span class="types"><a class="type" href="../3 primitive classes/Vec3.html#">Vec3</a></span> <span class="types"><a class="type" href="../3 primitive classes/Vec3.html#">Vec3</a></span>
position of the light
</li>
<li><span class="parameter">color</span>
<span class="types"><a class="type" href="../3 primitive classes/Color.html#">Color</a></span>
light color (default Color(255, 255, 255))
(<em>optional</em>)
</li>
<li><span class="parameter">radius</span>
<span class="types"><span class="type">int</span></span>
measured in "clicks" or 256 world units (default 20)
(<em>optional</em>)
</li>
<li><span class="parameter">shadows</span>
<span class="types"><span class="type">bool</span></span>
determines whether light should generate dynamic shadows for applicable moveables (default is false)
(<em>optional</em>)
</li>
<li><span class="parameter">name</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
if provided, engine will interpolate this light for high framerate mode (be careful not to use same name for different lights)
(<em>optional</em>)
</li>
</ul>
</dd>
<dt>
<a name = "EmitSpotLight"></a>
<strong>EmitSpotLight(pos, dir[, color][, radius][, falloff][, distance][, shadows][, name])</strong>
</dt>
<dd>
Emit dynamic directional spotlight that lasts for a single frame.
If you want a light that sticks around, you must call this each frame.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">pos</span>
<span class="types"><a class="type" href="../3 primitive classes/Vec3.html#">Vec3</a></span>
position of the light
</li>
<li><span class="parameter">dir</span>
<span class="types"><a class="type" href="../3 primitive classes/Vec3.html#">Vec3</a></span>
direction, or a point to which spotlight should be directed to
</li> </li>
<li><span class="parameter">color</span> <li><span class="parameter">color</span>
<span class="types"><a class="type" href="../3 primitive classes/Color.html#">Color</a></span> <span class="types"><a class="type" href="../3 primitive classes/Color.html#">Color</a></span>
(default Color(255, 255, 255)) (default Color(255, 255, 255))
(<em>optional</em>)
</li> </li>
<li><span class="parameter">radius</span> <li><span class="parameter">radius</span>
<span class="types"><span class="type">int</span></span> <span class="types"><span class="type">int</span></span>
(default 20) corresponds loosely to both intensity and range overall radius at the endpoint of a light cone, measured in "clicks" or 256 world units (default 10)
(<em>optional</em>)
</li>
<li><span class="parameter">falloff</span>
<span class="types"><span class="type">int</span></span>
radius, at which light starts to fade out, measured in "clicks" (default 5)
(<em>optional</em>)
</li>
<li><span class="parameter">distance</span>
<span class="types"><span class="type">int</span></span>
distance, at which light cone fades out, measured in "clicks" (default 20)
(<em>optional</em>)
</li>
<li><span class="parameter">shadows</span>
<span class="types"><span class="type">bool</span></span>
determines whether light should generate dynamic shadows for applicable moveables (default is false)
(<em>optional</em>)
</li>
<li><span class="parameter">name</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
if provided, engine will interpolate this light for high framerate mode (be careful not to use same name for different lights)
(<em>optional</em>)
</li> </li>
</ul> </ul>

File diff suppressed because it is too large Load diff

View file

@ -160,7 +160,7 @@ Default: nil (i.e. infinite)
should be string automatically deleted after timeout is reached. should be string automatically deleted after timeout is reached.
If not given, the string will remain allocated even after timeout is reached, and can be If not given, the string will remain allocated even after timeout is reached, and can be
shown again without re-initialization. shown again without re-initialization.
Default: false Default: true
</li> </li>
</ul> </ul>

View file

@ -1,529 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>TombEngine 1.1.0 Lua API</title>
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>TombEngine</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>1 Modules</h2>
<ul class="nowrap">
<li> <a href="../1 modules/Effects.html">Effects</a></li>
<li> <a href="../1 modules/Flow.html">Flow</a></li>
<li> <a href="../1 modules/Input.html">Input</a></li>
<li> <a href="../1 modules/Inventory.html">Inventory</a></li>
<li> <a href="../1 modules/Logic.html">Logic</a></li>
<li> <a href="../1 modules/Objects.html">Objects</a></li>
<li> <a href="../1 modules/Sound.html">Sound</a></li>
<li> <a href="../1 modules/Strings.html">Strings</a></li>
<li> <a href="../1 modules/Util.html">Util</a></li>
<li> <a href="../1 modules/View.html">View</a></li>
</ul>
<h2>2 Classes</h2>
<ul class="nowrap">
<li> <here>DisplaySprite</here></li>
<li> <a href="../2 classes/Flow.Animations.html">Flow.Animations</a></li>
<li> <a href="../2 classes/Flow.Fog.html">Flow.Fog</a></li>
<li> <a href="../2 classes/Flow.InventoryItem.html">Flow.InventoryItem</a></li>
<li> <a href="../2 classes/Flow.Level.html">Flow.Level</a></li>
<li> <a href="../2 classes/Flow.Mirror.html">Flow.Mirror</a></li>
<li> <a href="../2 classes/Flow.Settings.html">Flow.Settings</a></li>
<li> <a href="../2 classes/Flow.SkyLayer.html">Flow.SkyLayer</a></li>
<li> <a href="../2 classes/Objects.AIObject.html">Objects.AIObject</a></li>
<li> <a href="../2 classes/Objects.Camera.html">Objects.Camera</a></li>
<li> <a href="../2 classes/Objects.LaraObject.html">Objects.LaraObject</a></li>
<li> <a href="../2 classes/Objects.Moveable.html">Objects.Moveable</a></li>
<li> <a href="../2 classes/Objects.Room.html">Objects.Room</a></li>
<li> <a href="../2 classes/Objects.Sink.html">Objects.Sink</a></li>
<li> <a href="../2 classes/Objects.SoundSource.html">Objects.SoundSource</a></li>
<li> <a href="../2 classes/Objects.Static.html">Objects.Static</a></li>
<li> <a href="../2 classes/Objects.Volume.html">Objects.Volume</a></li>
<li> <a href="../2 classes/Strings.DisplayString.html">Strings.DisplayString</a></li>
</ul>
<h2>3 Primitive Classes</h2>
<ul class="nowrap">
<li> <a href="../3 primitive classes/Color.html">Color</a></li>
<li> <a href="../3 primitive classes/Rotation.html">Rotation</a></li>
<li> <a href="../3 primitive classes/Vec2.html">Vec2</a></li>
<li> <a href="../3 primitive classes/Vec3.html">Vec3</a></li>
</ul>
<h2>4 Enums</h2>
<ul class="nowrap">
<li> <a href="../4 enums/DisplaySprite.AlignMode.html">DisplaySprite.AlignMode</a></li>
<li> <a href="../4 enums/DisplaySprite.ScaleMode.html">DisplaySprite.ScaleMode</a></li>
<li> <a href="../4 enums/Effects.BlendID.html">Effects.BlendID</a></li>
<li> <a href="../4 enums/Effects.EffectID.html">Effects.EffectID</a></li>
<li> <a href="../4 enums/Input.ActionID.html">Input.ActionID</a></li>
<li> <a href="../4 enums/Objects.AmmoType.html">Objects.AmmoType</a></li>
<li> <a href="../4 enums/Objects.ObjID.html">Objects.ObjID</a></li>
<li> <a href="../4 enums/Objects.RoomFlagID.html">Objects.RoomFlagID</a></li>
<li> <a href="../4 enums/Objects.RoomReverb.html">Objects.RoomReverb</a></li>
<li> <a href="../4 enums/Sound.SoundTrackType.html">Sound.SoundTrackType</a></li>
<li> <a href="../4 enums/Util.LogLevel.html">Util.LogLevel</a></li>
<li> <a href="../4 enums/View.CameraType.html">View.CameraType</a></li>
</ul>
<h2>5 Lua utility modules</h2>
<ul class="nowrap">
<li> <a href="../5 lua utility modules/EventSequence.html">EventSequence</a></li>
<li> <a href="../5 lua utility modules/Timer.html">Timer</a></li>
</ul>
</div>
<div id="content">
<h1>Class <code>DisplaySprite</code></h1>
<p>Represents a screen-space display sprite.</p>
<p>
</p>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" ><a href="#DisplaySprite">DisplaySprite(ID, int, pos, rot, scale[, color])</a></td>
<td class="summary">Create a DisplaySprite object.</td>
</tr>
<tr>
<td class="name" ><a href="#DisplaySprite:GetObjectID">DisplaySprite:GetObjectID()</a></td>
<td class="summary">Get the object ID of the sprite sequence object used by the display sprite.</td>
</tr>
<tr>
<td class="name" ><a href="#DisplaySprite:GetSpriteID">DisplaySprite:GetSpriteID()</a></td>
<td class="summary">Get the sprite ID in the sprite sequence object used by the display sprite.</td>
</tr>
<tr>
<td class="name" ><a href="#DisplaySprite:GetPosition">DisplaySprite:GetPosition()</a></td>
<td class="summary">Get the display position of the display sprite in percent.</td>
</tr>
<tr>
<td class="name" ><a href="#DisplaySprite:GetRotation">DisplaySprite:GetRotation()</a></td>
<td class="summary">Get the rotation of the display sprite in degrees.</td>
</tr>
<tr>
<td class="name" ><a href="#DisplaySprite:GetScale">DisplaySprite:GetScale()</a></td>
<td class="summary">Get the horizontal and vertical scale of the display sprite in percent.</td>
</tr>
<tr>
<td class="name" ><a href="#DisplaySprite:GetColor">DisplaySprite:GetColor()</a></td>
<td class="summary">Get the color of the display sprite.</td>
</tr>
<tr>
<td class="name" ><a href="#DisplaySprite:SetObjectID">DisplaySprite:SetObjectID(New)</a></td>
<td class="summary">Set the sprite sequence object ID used by the display sprite.</td>
</tr>
<tr>
<td class="name" ><a href="#DisplaySprite:SetSpriteID">DisplaySprite:SetSpriteID(New)</a></td>
<td class="summary">Set the sprite ID in the sprite sequence object used by the display sprite.</td>
</tr>
<tr>
<td class="name" ><a href="#DisplaySprite:SetPosition">DisplaySprite:SetPosition(New)</a></td>
<td class="summary">Set the display position of the display sprite in percent.</td>
</tr>
<tr>
<td class="name" ><a href="#DisplaySprite:SetRotation">DisplaySprite:SetRotation(New)</a></td>
<td class="summary">Set the rotation of the display sprite in degrees.</td>
</tr>
<tr>
<td class="name" ><a href="#DisplaySprite:SetScale">DisplaySprite:SetScale(New)</a></td>
<td class="summary">Set the horizontal and vertical scale of the display sprite in percent.</td>
</tr>
<tr>
<td class="name" ><a href="#DisplaySprite:SetColor">DisplaySprite:SetColor(New)</a></td>
<td class="summary">Set the color of the display sprite.</td>
</tr>
<tr>
<td class="name" ><a href="#DisplaySprite:Draw">DisplaySprite:Draw([priority][, alignMode][, scaleMode][, blendMode])</a></td>
<td class="summary">Draw the display sprite in display space for the current frame.</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
<dl class="function">
<dt>
<a name = "DisplaySprite"></a>
<strong>DisplaySprite(ID, int, pos, rot, scale[, color])</strong>
</dt>
<dd>
Create a DisplaySprite object.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">ID</span>
<span class="types"><a class="type" href="../4 enums/Objects.ObjID.html#">ObjID</a></span>
of the sprite sequence object.
</li>
<li><span class="parameter">int</span>
<span class="types"><span class="type">int</span></span>
spriteID ID of the sprite in the sequence.
</li>
<li><span class="parameter">pos</span>
<span class="types"><a class="type" href="../3 primitive classes/Vec2.html#">Vec2</a></span>
Display position in percent.
</li>
<li><span class="parameter">rot</span>
<span class="types"><span class="type">float</span></span>
Rotation in degrees.
</li>
<li><span class="parameter">scale</span>
<span class="types"><a class="type" href="../3 primitive classes/Vec2.html#">Vec2</a></span>
Horizontal and vertical scale in percent. Scaling is interpreted by the DisplaySpriteEnum.ScaleMode passed to the Draw() function call.
</li>
<li><span class="parameter">color</span>
<span class="types"><a class="type" href="../3 primitive classes/Color.html#">Color</a></span>
Color. <strong>Default: Color(255, 255, 255, 255)</strong>
(<em>optional</em>)
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../2 classes/DisplaySprite.html#">DisplaySprite</a></span>
A new DisplaySprite object.
</ol>
</dd>
<dt>
<a name = "DisplaySprite:GetObjectID"></a>
<strong>DisplaySprite:GetObjectID()</strong>
</dt>
<dd>
Get the object ID of the sprite sequence object used by the display sprite. ()
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../4 enums/Objects.ObjID.html#">ObjID</a></span>
Sprite sequence object ID.
</ol>
</dd>
<dt>
<a name = "DisplaySprite:GetSpriteID"></a>
<strong>DisplaySprite:GetSpriteID()</strong>
</dt>
<dd>
Get the sprite ID in the sprite sequence object used by the display sprite. ()
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">int</span></span>
Sprite ID in the sprite sequence object.
</ol>
</dd>
<dt>
<a name = "DisplaySprite:GetPosition"></a>
<strong>DisplaySprite:GetPosition()</strong>
</dt>
<dd>
Get the display position of the display sprite in percent. ()
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../3 primitive classes/Vec2.html#">Vec2</a></span>
Display position in percent.
</ol>
</dd>
<dt>
<a name = "DisplaySprite:GetRotation"></a>
<strong>DisplaySprite:GetRotation()</strong>
</dt>
<dd>
Get the rotation of the display sprite in degrees. ()
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">float</span></span>
Rotation in degrees.
</ol>
</dd>
<dt>
<a name = "DisplaySprite:GetScale"></a>
<strong>DisplaySprite:GetScale()</strong>
</dt>
<dd>
Get the horizontal and vertical scale of the display sprite in percent. ()
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../3 primitive classes/Vec2.html#">Vec2</a></span>
Horizontal and vertical scale in percent.
</ol>
</dd>
<dt>
<a name = "DisplaySprite:GetColor"></a>
<strong>DisplaySprite:GetColor()</strong>
</dt>
<dd>
Get the color of the display sprite. ()
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../3 primitive classes/Color.html#">Color</a></span>
Color.
</ol>
</dd>
<dt>
<a name = "DisplaySprite:SetObjectID"></a>
<strong>DisplaySprite:SetObjectID(New)</strong>
</dt>
<dd>
Set the sprite sequence object ID used by the display sprite. (Objects.ObjID)
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">New</span>
<span class="types"><a class="type" href="../4 enums/Objects.ObjID.html#">ObjID</a></span>
sprite sequence object ID.
</li>
</ul>
</dd>
<dt>
<a name = "DisplaySprite:SetSpriteID"></a>
<strong>DisplaySprite:SetSpriteID(New)</strong>
</dt>
<dd>
Set the sprite ID in the sprite sequence object used by the display sprite. (int)
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">New</span>
<span class="types"><span class="type">int</span></span>
sprite ID in the sprite sequence object.
</li>
</ul>
</dd>
<dt>
<a name = "DisplaySprite:SetPosition"></a>
<strong>DisplaySprite:SetPosition(New)</strong>
</dt>
<dd>
Set the display position of the display sprite in percent. (Vec2)
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">New</span>
<span class="types"><a class="type" href="../3 primitive classes/Vec2.html#">Vec2</a></span>
display position in percent.
</li>
</ul>
</dd>
<dt>
<a name = "DisplaySprite:SetRotation"></a>
<strong>DisplaySprite:SetRotation(New)</strong>
</dt>
<dd>
Set the rotation of the display sprite in degrees. (float)
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">New</span>
<span class="types"><span class="type">float</span></span>
rotation in degrees.
</li>
</ul>
</dd>
<dt>
<a name = "DisplaySprite:SetScale"></a>
<strong>DisplaySprite:SetScale(New)</strong>
</dt>
<dd>
Set the horizontal and vertical scale of the display sprite in percent. (Vec2)
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">New</span>
<span class="types"><span class="type">float</span></span>
horizontal and vertical scale in percent.
</li>
</ul>
</dd>
<dt>
<a name = "DisplaySprite:SetColor"></a>
<strong>DisplaySprite:SetColor(New)</strong>
</dt>
<dd>
Set the color of the display sprite. (Color)
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">New</span>
<span class="types"><span class="type">float</span></span>
color.
</li>
</ul>
</dd>
<dt>
<a name = "DisplaySprite:Draw"></a>
<strong>DisplaySprite:Draw([priority][, alignMode][, scaleMode][, blendMode])</strong>
</dt>
<dd>
Draw the display sprite in display space for the current frame.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">priority</span>
<span class="types"><a class="type" href="../4 enums/Objects.ObjID.html#">ObjID</a></span>
Draw priority. Can be thought of as a layer, with higher values having precedence. <strong>Default: 0</strong>
(<em>optional</em>)
</li>
<li><span class="parameter">alignMode</span>
<span class="types"><a class="type" href="../4 enums/DisplaySprite.AlignMode.html#">AlignMode</a></span>
Align mode interpreting an offset from the sprite's position. <strong>Default: DisplaySprite.AlignMode.CENTER</strong>
(<em>optional</em>)
</li>
<li><span class="parameter">scaleMode</span>
<span class="types"><a class="type" href="../4 enums/DisplaySprite.ScaleMode.html#">ScaleMode</a></span>
Scale mode interpreting the display sprite's horizontal and vertical scale. <strong>Default: DisplaySprite.ScaleMode.FIT</strong>
(<em>optional</em>)
</li>
<li><span class="parameter">blendMode</span>
<span class="types"><a class="type" href="../4 enums/Effects.BlendID.html#">BlendID</a></span>
Blend mode. <strong>Default: Effects.BlendID.ALPHABLEND</strong>
(<em>optional</em>)
</li>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="https://github.com/hispidence/TEN-LDoc">TEN-LDoc</a> (a fork of <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a>)</i>
<i style="float:right;">Last updated 2023-11-09 18:25:22 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View file

@ -110,6 +110,10 @@
<h2><a href="#Members">Members</a></h2> <h2><a href="#Members">Members</a></h2>
<table class="function_list"> <table class="function_list">
<tr>
<td class="name" ><a href="#nameKey">nameKey</a></td>
<td class="summary">(string) string key for the level's (localised) name.</td>
</tr>
<tr> <tr>
<td class="name" ><a href="#scriptFile">scriptFile</a></td> <td class="name" ><a href="#scriptFile">scriptFile</a></td>
<td class="summary">(string) Level-specific Lua script file.</td> <td class="summary">(string) Level-specific Lua script file.</td>
@ -206,6 +210,22 @@
<h2 class="section-header "><a name="Members"></a>Members</h2> <h2 class="section-header "><a name="Members"></a>Members</h2>
<dl class="function"> <dl class="function">
<dt>
<a name = "nameKey"></a>
<strong>nameKey</strong>
</dt>
<dd>
(string) string key for the level's (localised) name.
Corresponds to an entry in strings.lua.
</dd>
<dt> <dt>
<a name = "scriptFile"></a> <a name = "scriptFile"></a>
<strong>scriptFile</strong> <strong>scriptFile</strong>

View file

@ -130,6 +130,10 @@
<td class="summary"> <td class="summary">
</td> </td>
</tr>
<tr>
<td class="name" ><a href="#Direction">Direction()</a></td>
<td class="summary">Converts rotation to a direction normal.</td>
</tr> </tr>
<tr> <tr>
<td class="name" ><a href="#__tostring">__tostring(rotation)</a></td> <td class="name" ><a href="#__tostring">__tostring(rotation)</a></td>
@ -232,6 +236,27 @@
</dd>
<dt>
<a name = "Direction"></a>
<strong>Direction()</strong>
</dt>
<dd>
Converts rotation to a direction normal.
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../3 primitive classes/Vec3.html#">Vec3</a></span>
resulting normal calculated from this rotation.
</ol>
</dd> </dd>
<dt> <dt>
<a name = "__tostring"></a> <a name = "__tostring"></a>

View file

@ -1,166 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>TombEngine 1.5 Lua API</title>
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>TombEngine</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>1 Modules</h2>
<ul class="nowrap">
<li> <a href="../1 modules/Effects.html">Effects</a></li>
<li> <a href="../1 modules/Flow.html">Flow</a></li>
<li> <a href="../1 modules/Input.html">Input</a></li>
<li> <a href="../1 modules/Inventory.html">Inventory</a></li>
<li> <a href="../1 modules/Logic.html">Logic</a></li>
<li> <a href="../1 modules/Objects.html">Objects</a></li>
<li> <a href="../1 modules/Sound.html">Sound</a></li>
<li> <a href="../1 modules/Strings.html">Strings</a></li>
<li> <a href="../1 modules/Util.html">Util</a></li>
<li> <a href="../1 modules/View.html">View</a></li>
</ul>
<h2>2 Classes</h2>
<ul class="nowrap">
<li> <a href="../2 classes/View.DisplaySprite.html">View.DisplaySprite</a></li>
<li> <a href="../2 classes/Flow.Animations.html">Flow.Animations</a></li>
<li> <a href="../2 classes/Flow.Fog.html">Flow.Fog</a></li>
<li> <a href="../2 classes/Flow.InventoryItem.html">Flow.InventoryItem</a></li>
<li> <a href="../2 classes/Flow.LensFlare.html">Flow.LensFlare</a></li>
<li> <a href="../2 classes/Flow.Level.html">Flow.Level</a></li>
<li> <a href="../2 classes/Flow.Mirror.html">Flow.Mirror</a></li>
<li> <a href="../2 classes/Flow.Settings.html">Flow.Settings</a></li>
<li> <a href="../2 classes/Flow.SkyLayer.html">Flow.SkyLayer</a></li>
<li> <a href="../2 classes/Flow.Starfield.html">Flow.Starfield</a></li>
<li> <a href="../2 classes/Objects.AIObject.html">Objects.AIObject</a></li>
<li> <a href="../2 classes/Objects.Camera.html">Objects.Camera</a></li>
<li> <a href="../2 classes/Objects.LaraObject.html">Objects.LaraObject</a></li>
<li> <a href="../2 classes/Objects.Moveable.html">Objects.Moveable</a></li>
<li> <a href="../2 classes/Objects.Room.html">Objects.Room</a></li>
<li> <a href="../2 classes/Objects.Sink.html">Objects.Sink</a></li>
<li> <a href="../2 classes/Objects.SoundSource.html">Objects.SoundSource</a></li>
<li> <a href="../2 classes/Objects.Static.html">Objects.Static</a></li>
<li> <a href="../2 classes/Objects.Volume.html">Objects.Volume</a></li>
<li> <a href="../2 classes/Strings.DisplayString.html">Strings.DisplayString</a></li>
</ul>
<h2>3 Primitive Classes</h2>
<ul class="nowrap">
<li> <a href="../3 primitive classes/Color.html">Color</a></li>
<li> <a href="../3 primitive classes/Rotation.html">Rotation</a></li>
<li> <a href="../3 primitive classes/Vec2.html">Vec2</a></li>
<li> <a href="../3 primitive classes/Vec3.html">Vec3</a></li>
</ul>
<h2>4 Enums</h2>
<ul class="nowrap">
<li> <a href="../4 enums/Effects.BlendID.html">Effects.BlendID</a></li>
<li> <a href="../4 enums/Effects.EffectID.html">Effects.EffectID</a></li>
<li> <here>Flow.BreakMode</here></li>
<li> <a href="../4 enums/Flow.GameStatus.html">Flow.GameStatus</a></li>
<li> <a href="../4 enums/Input.ActionID.html">Input.ActionID</a></li>
<li> <a href="../4 enums/Objects.AmmoType.html">Objects.AmmoType</a></li>
<li> <a href="../4 enums/Objects.MoveableStatus.html">Objects.MoveableStatus</a></li>
<li> <a href="../4 enums/Objects.ObjID.html">Objects.ObjID</a></li>
<li> <a href="../4 enums/Objects.RoomFlagID.html">Objects.RoomFlagID</a></li>
<li> <a href="../4 enums/Objects.RoomReverb.html">Objects.RoomReverb</a></li>
<li> <a href="../4 enums/Sound.SoundTrackType.html">Sound.SoundTrackType</a></li>
<li> <a href="../4 enums/Util.LogLevel.html">Util.LogLevel</a></li>
<li> <a href="../4 enums/View.AlignMode.html">View.AlignMode</a></li>
<li> <a href="../4 enums/View.CameraType.html">View.CameraType</a></li>
<li> <a href="../4 enums/View.PostProcessMode.html">View.PostProcessMode</a></li>
<li> <a href="../4 enums/View.ScaleMode.html">View.ScaleMode</a></li>
</ul>
<h2>5 Lua utility modules</h2>
<ul class="nowrap">
<li> <a href="../5 lua utility modules/EventSequence.html">EventSequence</a></li>
<li> <a href="../5 lua utility modules/Timer.html">Timer</a></li>
</ul>
</div>
<div id="content">
<h1>Enum <code>Flow.BreakMode</code></h1>
<p>Constants for break modes.</p>
<p>
</p>
<h2><a href="#Flow_BreakMode_constants">Flow.BreakMode constants </a></h2>
<table class="function_list">
<tr>
<td class="name" ><a href="#CONSTANT_STRING_HERE">CONSTANT_STRING_HERE</a></td>
<td class="summary">Table of break modes.</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header has-description"><a name="Flow_BreakMode_constants"></a>Flow.BreakMode constants </h2>
<div class="section-description">
<p>The following constants are inside Flow.BreakMode.</p>
<pre><code>NONE
FULL
SPECTATOR
PLAYER
</code></pre>
</div>
<dl class="function">
<dt>
<a name = "CONSTANT_STRING_HERE"></a>
<strong>CONSTANT_STRING_HERE</strong>
</dt>
<dd>
Table of break modes.
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="https://github.com/hispidence/TEN-LDoc">TEN-LDoc</a> (a fork of <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a>)</i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View file

@ -1,165 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>TombEngine 1.5 Lua API</title>
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>TombEngine</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>1 Modules</h2>
<ul class="nowrap">
<li> <a href="../1 modules/Effects.html">Effects</a></li>
<li> <a href="../1 modules/Flow.html">Flow</a></li>
<li> <a href="../1 modules/Input.html">Input</a></li>
<li> <a href="../1 modules/Inventory.html">Inventory</a></li>
<li> <a href="../1 modules/Logic.html">Logic</a></li>
<li> <a href="../1 modules/Objects.html">Objects</a></li>
<li> <a href="../1 modules/Sound.html">Sound</a></li>
<li> <a href="../1 modules/Strings.html">Strings</a></li>
<li> <a href="../1 modules/Util.html">Util</a></li>
<li> <a href="../1 modules/View.html">View</a></li>
</ul>
<h2>2 Classes</h2>
<ul class="nowrap">
<li> <a href="../2 classes/View.DisplaySprite.html">View.DisplaySprite</a></li>
<li> <a href="../2 classes/Flow.Animations.html">Flow.Animations</a></li>
<li> <a href="../2 classes/Flow.Fog.html">Flow.Fog</a></li>
<li> <a href="../2 classes/Flow.InventoryItem.html">Flow.InventoryItem</a></li>
<li> <a href="../2 classes/Flow.LensFlare.html">Flow.LensFlare</a></li>
<li> <a href="../2 classes/Flow.Level.html">Flow.Level</a></li>
<li> <a href="../2 classes/Flow.Mirror.html">Flow.Mirror</a></li>
<li> <a href="../2 classes/Flow.Settings.html">Flow.Settings</a></li>
<li> <a href="../2 classes/Flow.SkyLayer.html">Flow.SkyLayer</a></li>
<li> <a href="../2 classes/Flow.Starfield.html">Flow.Starfield</a></li>
<li> <a href="../2 classes/Objects.AIObject.html">Objects.AIObject</a></li>
<li> <a href="../2 classes/Objects.Camera.html">Objects.Camera</a></li>
<li> <a href="../2 classes/Objects.LaraObject.html">Objects.LaraObject</a></li>
<li> <a href="../2 classes/Objects.Moveable.html">Objects.Moveable</a></li>
<li> <a href="../2 classes/Objects.Room.html">Objects.Room</a></li>
<li> <a href="../2 classes/Objects.Sink.html">Objects.Sink</a></li>
<li> <a href="../2 classes/Objects.SoundSource.html">Objects.SoundSource</a></li>
<li> <a href="../2 classes/Objects.Static.html">Objects.Static</a></li>
<li> <a href="../2 classes/Objects.Volume.html">Objects.Volume</a></li>
<li> <a href="../2 classes/Strings.DisplayString.html">Strings.DisplayString</a></li>
</ul>
<h2>3 Primitive Classes</h2>
<ul class="nowrap">
<li> <a href="../3 primitive classes/Color.html">Color</a></li>
<li> <a href="../3 primitive classes/Rotation.html">Rotation</a></li>
<li> <a href="../3 primitive classes/Vec2.html">Vec2</a></li>
<li> <a href="../3 primitive classes/Vec3.html">Vec3</a></li>
</ul>
<h2>4 Enums</h2>
<ul class="nowrap">
<li> <a href="../4 enums/Effects.BlendID.html">Effects.BlendID</a></li>
<li> <a href="../4 enums/Effects.EffectID.html">Effects.EffectID</a></li>
<li> <here>Flow.GameMode</here></li>
<li> <a href="../4 enums/Flow.GameStatus.html">Flow.GameStatus</a></li>
<li> <a href="../4 enums/Input.ActionID.html">Input.ActionID</a></li>
<li> <a href="../4 enums/Objects.AmmoType.html">Objects.AmmoType</a></li>
<li> <a href="../4 enums/Objects.MoveableStatus.html">Objects.MoveableStatus</a></li>
<li> <a href="../4 enums/Objects.ObjID.html">Objects.ObjID</a></li>
<li> <a href="../4 enums/Objects.RoomFlagID.html">Objects.RoomFlagID</a></li>
<li> <a href="../4 enums/Objects.RoomReverb.html">Objects.RoomReverb</a></li>
<li> <a href="../4 enums/Sound.SoundTrackType.html">Sound.SoundTrackType</a></li>
<li> <a href="../4 enums/Util.LogLevel.html">Util.LogLevel</a></li>
<li> <a href="../4 enums/View.AlignMode.html">View.AlignMode</a></li>
<li> <a href="../4 enums/View.CameraType.html">View.CameraType</a></li>
<li> <a href="../4 enums/View.PostProcessMode.html">View.PostProcessMode</a></li>
<li> <a href="../4 enums/View.ScaleMode.html">View.ScaleMode</a></li>
</ul>
<h2>5 Lua utility modules</h2>
<ul class="nowrap">
<li> <a href="../5 lua utility modules/EventSequence.html">EventSequence</a></li>
<li> <a href="../5 lua utility modules/Timer.html">Timer</a></li>
</ul>
</div>
<div id="content">
<h1>Enum <code>Flow.GameMode</code></h1>
<p>Constants for game modes.</p>
<p>
</p>
<h2><a href="#Flow_GameMode_constants">Flow.GameMode constants </a></h2>
<table class="function_list">
<tr>
<td class="name" ><a href="#CONSTANT_STRING_HERE">CONSTANT_STRING_HERE</a></td>
<td class="summary">Table of game modes.</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header has-description"><a name="Flow_GameMode_constants"></a>Flow.GameMode constants </h2>
<div class="section-description">
<p>The following constants are inside Flow.GameMode.</p>
<pre><code>NORMAL
FROZEN
MENU
</code></pre>
</div>
<dl class="function">
<dt>
<a name = "CONSTANT_STRING_HERE"></a>
<strong>CONSTANT_STRING_HERE</strong>
</dt>
<dd>
Table of game modes.
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="https://github.com/hispidence/TEN-LDoc">TEN-LDoc</a> (a fork of <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a>)</i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View file

@ -1,195 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>TombEngine 1.1.0 Lua API</title>
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>TombEngine</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>1 Modules</h2>
<ul class="nowrap">
<li> <a href="../1 modules/Effects.html">Effects</a></li>
<li> <a href="../1 modules/Flow.html">Flow</a></li>
<li> <a href="../1 modules/Inventory.html">Inventory</a></li>
<li> <a href="../1 modules/Logic.html">Logic</a></li>
<li> <a href="../1 modules/Misc.html">Misc</a></li>
<li> <a href="../1 modules/Objects.html">Objects</a></li>
<li> <a href="../1 modules/Strings.html">Strings</a></li>
</ul>
<h2>2 Classes</h2>
<ul class="nowrap">
<li> <a href="../2 classes/Flow.Animations.html">Flow.Animations</a></li>
<li> <a href="../2 classes/Flow.Fog.html">Flow.Fog</a></li>
<li> <a href="../2 classes/Flow.InventoryItem.html">Flow.InventoryItem</a></li>
<li> <a href="../2 classes/Flow.Level.html">Flow.Level</a></li>
<li> <a href="../2 classes/Flow.Mirror.html">Flow.Mirror</a></li>
<li> <a href="../2 classes/Flow.Settings.html">Flow.Settings</a></li>
<li> <a href="../2 classes/Flow.SkyLayer.html">Flow.SkyLayer</a></li>
<li> <a href="../2 classes/Objects.AIObject.html">Objects.AIObject</a></li>
<li> <a href="../2 classes/Objects.Camera.html">Objects.Camera</a></li>
<li> <a href="../2 classes/Objects.LaraObject.html">Objects.LaraObject</a></li>
<li> <a href="../2 classes/Objects.Moveable.html">Objects.Moveable</a></li>
<li> <a href="../2 classes/Objects.Room.html">Objects.Room</a></li>
<li> <a href="../2 classes/Objects.Sink.html">Objects.Sink</a></li>
<li> <a href="../2 classes/Objects.SoundSource.html">Objects.SoundSource</a></li>
<li> <a href="../2 classes/Objects.Static.html">Objects.Static</a></li>
<li> <a href="../2 classes/Objects.Volume.html">Objects.Volume</a></li>
<li> <a href="../2 classes/Strings.DisplayString.html">Strings.DisplayString</a></li>
</ul>
<h2>3 Primitive Classes</h2>
<ul class="nowrap">
<li> <a href="../3 primitive classes/Color.html">Color</a></li>
<li> <a href="../3 primitive classes/Rotation.html">Rotation</a></li>
<li> <a href="../3 primitive classes/Vec2.html">Vec2</a></li>
<li> <a href="../3 primitive classes/Vec3.html">Vec3</a></li>
</ul>
<h2>4 Enums</h2>
<ul class="nowrap">
<li> <a href="../4 enums/Effects.BlendID.html">Effects.BlendID</a></li>
<li> <a href="../4 enums/Effects.EffectID.html">Effects.EffectID</a></li>
<li> <here>Misc.ActionID</here></li>
<li> <a href="../4 enums/Misc.CameraType.html">Misc.CameraType</a></li>
<li> <a href="../4 enums/Misc.LogLevel.html">Misc.LogLevel</a></li>
<li> <a href="../4 enums/Misc.SoundTrackType.html">Misc.SoundTrackType</a></li>
<li> <a href="../4 enums/Objects.AmmoType.html">Objects.AmmoType</a></li>
<li> <a href="../4 enums/Objects.ObjID.html">Objects.ObjID</a></li>
<li> <a href="../4 enums/Objects.RoomFlagID.html">Objects.RoomFlagID</a></li>
<li> <a href="../4 enums/Objects.RoomReverb.html">Objects.RoomReverb</a></li>
</ul>
<h2>5 Lua utility modules</h2>
<ul class="nowrap">
<li> <a href="../5 lua utility modules/EventSequence.html">EventSequence</a></li>
<li> <a href="../5 lua utility modules/Timer.html">Timer</a></li>
</ul>
</div>
<div id="content">
<h1>Enum <code>Misc.ActionID</code></h1>
<p>Constants for action key IDs.</p>
<p>
</p>
<h2><a href="#Misc_ActionID_constants">Misc.ActionID constants </a></h2>
<table class="function_list">
<tr>
<td class="name" ><a href="#CONSTANT_STRING_HERE">CONSTANT_STRING_HERE</a></td>
<td class="summary">Table of action ID constants (for use with KeyIsHeld / KeyIsHit / etc commands).</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header has-description"><a name="Misc_ActionID_constants"></a>Misc.ActionID constants </h2>
<div class="section-description">
<p>The following constants are inside ActionID.</p>
<pre><code>FORWARD
BACK
LEFT
RIGHT
STEP_LEFT
STEP_RIGHT
WALK
SPRINT
CROUCH
JUMP
ROLL
ACTION
DRAW
LOOK
ACCELERATE
REVERSE
SPEED
SLOW
BRAKE
FIRE
FLARE
SMALL_MEDIPACK
LARGE_MEDIPACK
PREVIOUS_WEAPON
NEXT_WEAPON
WEAPON_1
WEAPON_2
WEAPON_3
WEAPON_4
WEAPON_5
WEAPON_6
WEAPON_7
WEAPON_8
WEAPON_9
WEAPON_10
SELECT
DESELECT
PAUSE
INVENTORY
SAVE
LOAD
</code></pre>
</div>
<dl class="function">
<dt>
<a name = "CONSTANT_STRING_HERE"></a>
<strong>CONSTANT_STRING_HERE</strong>
</dt>
<dd>
Table of action ID constants (for use with KeyIsHeld / KeyIsHit / etc commands).
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="https://github.com/hispidence/TEN-LDoc">TEN-LDoc</a> (a fork of <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a>)</i>
<i style="float:right;">Last updated 2023-09-30 13:48:57 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View file

@ -1,157 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>TombEngine 1.1.0 Lua API</title>
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>TombEngine</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>1 Modules</h2>
<ul class="nowrap">
<li> <a href="../1 modules/Effects.html">Effects</a></li>
<li> <a href="../1 modules/Flow.html">Flow</a></li>
<li> <a href="../1 modules/Inventory.html">Inventory</a></li>
<li> <a href="../1 modules/Logic.html">Logic</a></li>
<li> <a href="../1 modules/Misc.html">Misc</a></li>
<li> <a href="../1 modules/Objects.html">Objects</a></li>
<li> <a href="../1 modules/Strings.html">Strings</a></li>
</ul>
<h2>2 Classes</h2>
<ul class="nowrap">
<li> <a href="../2 classes/Flow.Animations.html">Flow.Animations</a></li>
<li> <a href="../2 classes/Flow.Fog.html">Flow.Fog</a></li>
<li> <a href="../2 classes/Flow.InventoryItem.html">Flow.InventoryItem</a></li>
<li> <a href="../2 classes/Flow.Level.html">Flow.Level</a></li>
<li> <a href="../2 classes/Flow.Mirror.html">Flow.Mirror</a></li>
<li> <a href="../2 classes/Flow.Settings.html">Flow.Settings</a></li>
<li> <a href="../2 classes/Flow.SkyLayer.html">Flow.SkyLayer</a></li>
<li> <a href="../2 classes/Objects.AIObject.html">Objects.AIObject</a></li>
<li> <a href="../2 classes/Objects.Camera.html">Objects.Camera</a></li>
<li> <a href="../2 classes/Objects.LaraObject.html">Objects.LaraObject</a></li>
<li> <a href="../2 classes/Objects.Moveable.html">Objects.Moveable</a></li>
<li> <a href="../2 classes/Objects.Room.html">Objects.Room</a></li>
<li> <a href="../2 classes/Objects.Sink.html">Objects.Sink</a></li>
<li> <a href="../2 classes/Objects.SoundSource.html">Objects.SoundSource</a></li>
<li> <a href="../2 classes/Objects.Static.html">Objects.Static</a></li>
<li> <a href="../2 classes/Objects.Volume.html">Objects.Volume</a></li>
<li> <a href="../2 classes/Strings.DisplayString.html">Strings.DisplayString</a></li>
</ul>
<h2>3 Primitive Classes</h2>
<ul class="nowrap">
<li> <a href="../3 primitive classes/Color.html">Color</a></li>
<li> <a href="../3 primitive classes/Rotation.html">Rotation</a></li>
<li> <a href="../3 primitive classes/Vec2.html">Vec2</a></li>
<li> <a href="../3 primitive classes/Vec3.html">Vec3</a></li>
</ul>
<h2>4 Enums</h2>
<ul class="nowrap">
<li> <a href="../4 enums/Effects.BlendID.html">Effects.BlendID</a></li>
<li> <a href="../4 enums/Effects.EffectID.html">Effects.EffectID</a></li>
<li> <a href="../4 enums/Misc.ActionID.html">Misc.ActionID</a></li>
<li> <here>Misc.CameraType</here></li>
<li> <a href="../4 enums/Misc.LogLevel.html">Misc.LogLevel</a></li>
<li> <a href="../4 enums/Misc.SoundTrackType.html">Misc.SoundTrackType</a></li>
<li> <a href="../4 enums/Objects.AmmoType.html">Objects.AmmoType</a></li>
<li> <a href="../4 enums/Objects.ObjID.html">Objects.ObjID</a></li>
<li> <a href="../4 enums/Objects.RoomFlagID.html">Objects.RoomFlagID</a></li>
<li> <a href="../4 enums/Objects.RoomReverb.html">Objects.RoomReverb</a></li>
</ul>
<h2>5 Lua utility modules</h2>
<ul class="nowrap">
<li> <a href="../5 lua utility modules/EventSequence.html">EventSequence</a></li>
<li> <a href="../5 lua utility modules/Timer.html">Timer</a></li>
</ul>
</div>
<div id="content">
<h1>Enum <code>Misc.CameraType</code></h1>
<p>Constants for the type of the Camera.</p>
<p>
</p>
<h2><a href="#Misc_CameraType_constants">Misc.CameraType constants </a></h2>
<table class="function_list">
<tr>
<td class="name" ><a href="#CONSTANT_STRING_HERE">CONSTANT_STRING_HERE</a></td>
<td class="summary">Table of camera type constants (for use with GetCameraType() function).</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header has-description"><a name="Misc_CameraType_constants"></a>Misc.CameraType constants </h2>
<div class="section-description">
<p>The following constants are inside CameraType.</p>
<pre><code>CHASE
FIXED
LOOK
COMBAT
HEAVY
OBJECT
</code></pre>
</div>
<dl class="function">
<dt>
<a name = "CONSTANT_STRING_HERE"></a>
<strong>CONSTANT_STRING_HERE</strong>
</dt>
<dd>
Table of camera type constants (for use with GetCameraType() function).
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="https://github.com/hispidence/TEN-LDoc">TEN-LDoc</a> (a fork of <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a>)</i>
<i style="float:right;">Last updated 2023-09-30 13:48:57 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View file

@ -1,153 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>TombEngine 1.1.0 Lua API</title>
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>TombEngine</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>1 Modules</h2>
<ul class="nowrap">
<li> <a href="../1 modules/Effects.html">Effects</a></li>
<li> <a href="../1 modules/Flow.html">Flow</a></li>
<li> <a href="../1 modules/Inventory.html">Inventory</a></li>
<li> <a href="../1 modules/Logic.html">Logic</a></li>
<li> <a href="../1 modules/Misc.html">Misc</a></li>
<li> <a href="../1 modules/Objects.html">Objects</a></li>
<li> <a href="../1 modules/Strings.html">Strings</a></li>
</ul>
<h2>2 Classes</h2>
<ul class="nowrap">
<li> <a href="../2 classes/Flow.Animations.html">Flow.Animations</a></li>
<li> <a href="../2 classes/Flow.Fog.html">Flow.Fog</a></li>
<li> <a href="../2 classes/Flow.InventoryItem.html">Flow.InventoryItem</a></li>
<li> <a href="../2 classes/Flow.Level.html">Flow.Level</a></li>
<li> <a href="../2 classes/Flow.Mirror.html">Flow.Mirror</a></li>
<li> <a href="../2 classes/Flow.Settings.html">Flow.Settings</a></li>
<li> <a href="../2 classes/Flow.SkyLayer.html">Flow.SkyLayer</a></li>
<li> <a href="../2 classes/Objects.AIObject.html">Objects.AIObject</a></li>
<li> <a href="../2 classes/Objects.Camera.html">Objects.Camera</a></li>
<li> <a href="../2 classes/Objects.LaraObject.html">Objects.LaraObject</a></li>
<li> <a href="../2 classes/Objects.Moveable.html">Objects.Moveable</a></li>
<li> <a href="../2 classes/Objects.Room.html">Objects.Room</a></li>
<li> <a href="../2 classes/Objects.Sink.html">Objects.Sink</a></li>
<li> <a href="../2 classes/Objects.SoundSource.html">Objects.SoundSource</a></li>
<li> <a href="../2 classes/Objects.Static.html">Objects.Static</a></li>
<li> <a href="../2 classes/Objects.Volume.html">Objects.Volume</a></li>
<li> <a href="../2 classes/Strings.DisplayString.html">Strings.DisplayString</a></li>
</ul>
<h2>3 Primitive Classes</h2>
<ul class="nowrap">
<li> <a href="../3 primitive classes/Color.html">Color</a></li>
<li> <a href="../3 primitive classes/Rotation.html">Rotation</a></li>
<li> <a href="../3 primitive classes/Vec2.html">Vec2</a></li>
<li> <a href="../3 primitive classes/Vec3.html">Vec3</a></li>
</ul>
<h2>4 Enums</h2>
<ul class="nowrap">
<li> <a href="../4 enums/Effects.BlendID.html">Effects.BlendID</a></li>
<li> <a href="../4 enums/Effects.EffectID.html">Effects.EffectID</a></li>
<li> <a href="../4 enums/Misc.ActionID.html">Misc.ActionID</a></li>
<li> <a href="../4 enums/Misc.CameraType.html">Misc.CameraType</a></li>
<li> <here>Misc.LogLevel</here></li>
<li> <a href="../4 enums/Misc.SoundTrackType.html">Misc.SoundTrackType</a></li>
<li> <a href="../4 enums/Objects.AmmoType.html">Objects.AmmoType</a></li>
<li> <a href="../4 enums/Objects.ObjID.html">Objects.ObjID</a></li>
<li> <a href="../4 enums/Objects.RoomFlagID.html">Objects.RoomFlagID</a></li>
<li> <a href="../4 enums/Objects.RoomReverb.html">Objects.RoomReverb</a></li>
</ul>
<h2>5 Lua utility modules</h2>
<ul class="nowrap">
<li> <a href="../5 lua utility modules/EventSequence.html">EventSequence</a></li>
<li> <a href="../5 lua utility modules/Timer.html">Timer</a></li>
</ul>
</div>
<div id="content">
<h1>Enum <code>Misc.LogLevel</code></h1>
<p>Constants for LogLevel IDs.</p>
<p>
</p>
<h2><a href="#Misc_LogLevel_constants">Misc.LogLevel constants </a></h2>
<table class="function_list">
<tr>
<td class="name" ><a href="#CONSTANT_STRING_HERE">CONSTANT_STRING_HERE</a></td>
<td class="summary">Table of LogLevel ID constants (for use with PrintLog() command).</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header has-description"><a name="Misc_LogLevel_constants"></a>Misc.LogLevel constants </h2>
<div class="section-description">
<p>The following constants are inside LogLevel.</p>
<pre><code>INFO
WARNING
ERROR
</code></pre>
</div>
<dl class="function">
<dt>
<a name = "CONSTANT_STRING_HERE"></a>
<strong>CONSTANT_STRING_HERE</strong>
</dt>
<dd>
Table of LogLevel ID constants (for use with PrintLog() command).
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="https://github.com/hispidence/TEN-LDoc">TEN-LDoc</a> (a fork of <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a>)</i>
<i style="float:right;">Last updated 2023-09-30 13:48:57 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View file

@ -1,154 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>TombEngine 1.1.0 Lua API</title>
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>TombEngine</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>1 Modules</h2>
<ul class="nowrap">
<li> <a href="../1 modules/Effects.html">Effects</a></li>
<li> <a href="../1 modules/Flow.html">Flow</a></li>
<li> <a href="../1 modules/Inventory.html">Inventory</a></li>
<li> <a href="../1 modules/Logic.html">Logic</a></li>
<li> <a href="../1 modules/Misc.html">Misc</a></li>
<li> <a href="../1 modules/Objects.html">Objects</a></li>
<li> <a href="../1 modules/Strings.html">Strings</a></li>
</ul>
<h2>2 Classes</h2>
<ul class="nowrap">
<li> <a href="../2 classes/Flow.Animations.html">Flow.Animations</a></li>
<li> <a href="../2 classes/Flow.Fog.html">Flow.Fog</a></li>
<li> <a href="../2 classes/Flow.InventoryItem.html">Flow.InventoryItem</a></li>
<li> <a href="../2 classes/Flow.Level.html">Flow.Level</a></li>
<li> <a href="../2 classes/Flow.Mirror.html">Flow.Mirror</a></li>
<li> <a href="../2 classes/Flow.Settings.html">Flow.Settings</a></li>
<li> <a href="../2 classes/Flow.SkyLayer.html">Flow.SkyLayer</a></li>
<li> <a href="../2 classes/Objects.AIObject.html">Objects.AIObject</a></li>
<li> <a href="../2 classes/Objects.Camera.html">Objects.Camera</a></li>
<li> <a href="../2 classes/Objects.LaraObject.html">Objects.LaraObject</a></li>
<li> <a href="../2 classes/Objects.Moveable.html">Objects.Moveable</a></li>
<li> <a href="../2 classes/Objects.Room.html">Objects.Room</a></li>
<li> <a href="../2 classes/Objects.Sink.html">Objects.Sink</a></li>
<li> <a href="../2 classes/Objects.SoundSource.html">Objects.SoundSource</a></li>
<li> <a href="../2 classes/Objects.Static.html">Objects.Static</a></li>
<li> <a href="../2 classes/Objects.Volume.html">Objects.Volume</a></li>
<li> <a href="../2 classes/Strings.DisplayString.html">Strings.DisplayString</a></li>
</ul>
<h2>3 Primitive Classes</h2>
<ul class="nowrap">
<li> <a href="../3 primitive classes/Color.html">Color</a></li>
<li> <a href="../3 primitive classes/Rotation.html">Rotation</a></li>
<li> <a href="../3 primitive classes/Vec2.html">Vec2</a></li>
<li> <a href="../3 primitive classes/Vec3.html">Vec3</a></li>
</ul>
<h2>4 Enums</h2>
<ul class="nowrap">
<li> <a href="../4 enums/Effects.BlendID.html">Effects.BlendID</a></li>
<li> <a href="../4 enums/Effects.EffectID.html">Effects.EffectID</a></li>
<li> <a href="../4 enums/Misc.ActionID.html">Misc.ActionID</a></li>
<li> <a href="../4 enums/Misc.CameraType.html">Misc.CameraType</a></li>
<li> <a href="../4 enums/Misc.LogLevel.html">Misc.LogLevel</a></li>
<li> <here>Misc.SoundTrackType</here></li>
<li> <a href="../4 enums/Objects.AmmoType.html">Objects.AmmoType</a></li>
<li> <a href="../4 enums/Objects.ObjID.html">Objects.ObjID</a></li>
<li> <a href="../4 enums/Objects.RoomFlagID.html">Objects.RoomFlagID</a></li>
<li> <a href="../4 enums/Objects.RoomReverb.html">Objects.RoomReverb</a></li>
</ul>
<h2>5 Lua utility modules</h2>
<ul class="nowrap">
<li> <a href="../5 lua utility modules/EventSequence.html">EventSequence</a></li>
<li> <a href="../5 lua utility modules/Timer.html">Timer</a></li>
</ul>
</div>
<div id="content">
<h1>Enum <code>Misc.SoundTrackType</code></h1>
<p>Constants for the type of the audio tracks.</p>
<p>
</p>
<h2><a href="#Misc_SoundTrackType_constants">Misc.SoundTrackType constants </a></h2>
<table class="function_list">
<tr>
<td class="name" ><a href="#CONSTANT_STRING_HERE">CONSTANT_STRING_HERE</a></td>
<td class="summary">Table of sound track type constants (for use with sound track functions).</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header has-description"><a name="Misc_SoundTrackType_constants"></a>Misc.SoundTrackType constants </h2>
<div class="section-description">
<p>The following constants are inside SoundTrackType.</p>
<pre><code>ONESHOT
LOOPED
VOICE
</code></pre>
</div>
<dl class="function">
<dt>
<a name = "CONSTANT_STRING_HERE"></a>
<strong>CONSTANT_STRING_HERE</strong>
</dt>
<dd>
Table of sound track type constants (for use with sound track functions).
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="https://github.com/hispidence/TEN-LDoc">TEN-LDoc</a> (a fork of <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a>)</i>
<i style="float:right;">Last updated 2023-09-30 13:48:57 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View file

@ -1778,7 +1778,7 @@ bool TestLaraPoleCollision(ItemInfo* item, CollisionInfo* coll, bool goingUp, fl
bool atLeastOnePoleCollided = false; bool atLeastOnePoleCollided = false;
auto collObjects = GetCollidedObjects(*item, true, false, BLOCK(1), ObjectCollectionMode::Items); auto collObjects = GetCollidedObjects(*item, true, false, BLOCK(2), ObjectCollectionMode::Items);
if (!collObjects.IsEmpty()) if (!collObjects.IsEmpty())
{ {
auto laraBox = GameBoundingBox(item).ToBoundingOrientedBox(item->Pose); auto laraBox = GameBoundingBox(item).ToBoundingOrientedBox(item->Pose);

View file

@ -118,7 +118,10 @@ CollidedObjectData GetCollidedObjects(ItemInfo& collidingItem, bool onlyVisible,
// Override extents if specified. // Override extents if specified.
if (customRadius > 0.0f) if (customRadius > 0.0f)
{
collidingAabb = BoundingBox(collidingItem.Pose.Position.ToVector3(), Vector3(customRadius)); collidingAabb = BoundingBox(collidingItem.Pose.Position.ToVector3(), Vector3(customRadius));
convertedBounds.Extents = Vector3(customRadius);
}
// Run through neighboring rooms. // Run through neighboring rooms.
const auto& room = g_Level.Rooms[collidingItem.RoomNumber]; const auto& room = g_Level.Rooms[collidingItem.RoomNumber];

View file

@ -381,8 +381,8 @@ namespace TEN::Collision::Floordata
// Calculate and return tilt. // Calculate and return tilt.
auto sign = isFloor ? 1 : -1; auto sign = isFloor ? 1 : -1;
return Vector2i( return Vector2i(
round(scaledNormal.x * 4), (round(scaledNormal.x) * 4),
round(scaledNormal.z * 4)) * sign; (round(scaledNormal.z) * 4)) * sign;
} }
Vector2i GetSectorPoint(int x, int z) Vector2i GetSectorPoint(int x, int z)

View file

@ -370,7 +370,6 @@ void Trigger(short const value, short const flags)
if (item->Flags & IFLAG_KILLED) if (item->Flags & IFLAG_KILLED)
return; return;
item->TouchBits = NO_JOINT_BITS;
item->Flags |= TRIGGERED; item->Flags |= TRIGGERED;
if (flags & ONESHOT) if (flags & ONESHOT)
@ -408,6 +407,7 @@ void Trigger(short const value, short const flags)
} }
item->Status = ITEM_ACTIVE; item->Status = ITEM_ACTIVE;
item->TouchBits = NO_JOINT_BITS;
item->DisableInterpolation = true; item->DisableInterpolation = true;
} }
} }

View file

@ -1247,19 +1247,20 @@ void KillAllCurrentItems(short itemNumber)
// TODO: Reimplement this functionality. // TODO: Reimplement this functionality.
} }
// TODO: Rename to SpawnDynamicLight(). void TriggerDynamicPointLight(const Vector3& pos, const Color& color, float falloff, bool castShadows, int hash)
void TriggerDynamicLight(const Vector3& pos, const Color& color, float falloff)
{ {
g_Renderer.AddDynamicLight( g_Renderer.AddDynamicPointLight(pos, falloff , color, castShadows, hash);
pos.x, pos.y, pos.z, }
falloff * UCHAR_MAX,
color.x * UCHAR_MAX, color.y * UCHAR_MAX, color.z * UCHAR_MAX); void TriggerDynamicSpotLight(const Vector3& pos, const Vector3& dir, const Color& color, float radius, float falloff, float distance, bool castShadows, int hash)
{
g_Renderer.AddDynamicSpotLight(pos, dir, radius, falloff, distance, color, castShadows, hash);
} }
// Deprecated. Use above version instead. // Deprecated. Use above version instead.
void TriggerDynamicLight(int x, int y, int z, short falloff, byte r, byte g, byte b) void TriggerDynamicLight(int x, int y, int z, short falloff, byte r, byte g, byte b)
{ {
g_Renderer.AddDynamicLight(x, y, z, falloff, r, g, b); g_Renderer.AddDynamicPointLight(Vector3(x, y, z), (float)(falloff * UCHAR_MAX), Color(r / (float)UCHAR_MAX, g / (float)UCHAR_MAX, b / (float)UCHAR_MAX), false);
} }
void SpawnPlayerWaterSurfaceEffects(const ItemInfo& item, int waterHeight, int waterDepth) void SpawnPlayerWaterSurfaceEffects(const ItemInfo& item, int waterHeight, int waterDepth)

View file

@ -300,6 +300,8 @@ void ControlWaterfallMist(short itemNumber);
void TriggerWaterfallMist(const ItemInfo& item); void TriggerWaterfallMist(const ItemInfo& item);
void KillAllCurrentItems(short itemNumber); void KillAllCurrentItems(short itemNumber);
void TriggerDynamicLight(int x, int y, int z, short falloff, byte r, byte g, byte b); void TriggerDynamicLight(int x, int y, int z, short falloff, byte r, byte g, byte b);
void TriggerDynamicPointLight(const Vector3& pos, const Color& color, float falloff, bool castShadows = false, int hash = 0);
void TriggerDynamicSpotLight(const Vector3& pos, const Vector3& dir, const Color& color, float radius, float falloff, float distance, bool castShadows = false, int hash = 0);
void TriggerRocketFlame(int x, int y, int z, int xv, int yv, int zv, int itemNumber); void TriggerRocketFlame(int x, int y, int z, int xv, int yv, int zv, int itemNumber);
void TriggerRocketSmoke(int x, int y, int z); void TriggerRocketSmoke(int x, int y, int z);
void TriggerFlashSmoke(int x, int y, int z, short roomNumber); void TriggerFlashSmoke(int x, int y, int z, short roomNumber);
@ -313,5 +315,3 @@ void TriggerExplosionBubbles(int x, int y, int z, short roomNumber);
void Ricochet(Pose& pos); void Ricochet(Pose& pos);
void ProcessEffects(ItemInfo* item); void ProcessEffects(ItemInfo* item);
void UpdateWibble(); void UpdateWibble();
void TriggerDynamicLight(const Vector3& pos, const Color& color, float falloff);

View file

@ -1383,7 +1383,7 @@ void UpdateShockwaves()
{ {
auto lightColor = Color(shockwave.r / (float)UCHAR_MAX, shockwave.g / (float)UCHAR_MAX, shockwave.b / (float)UCHAR_MAX); auto lightColor = Color(shockwave.r / (float)UCHAR_MAX, shockwave.g / (float)UCHAR_MAX, shockwave.b / (float)UCHAR_MAX);
auto pos = Vector3(shockwave.x, shockwave.y, shockwave.z); auto pos = Vector3(shockwave.x, shockwave.y, shockwave.z);
TriggerDynamicLight(pos, lightColor, shockwave.life / (float)UCHAR_MAX); TriggerDynamicPointLight(pos, lightColor, shockwave.life / 4.0f);
} }
if (shockwave.style != (int)ShockwaveStyle::Knockback) if (shockwave.style != (int)ShockwaveStyle::Knockback)

View file

@ -74,28 +74,26 @@ namespace TEN::Entities::Creatures::TR2
// Spawn light. // Spawn light.
auto lightPos = item.Pose.Position.ToVector3() + Vector3(0.0f, -CLICK(1), 0.0f); auto lightPos = item.Pose.Position.ToVector3() + Vector3(0.0f, -CLICK(1), 0.0f);
auto lightColor = Color(0.0f,Random::GenerateFloat(0.7f, 1.0f), Random::GenerateFloat(0.2f, 0.3f)); auto lightColor = Color(0.0f,Random::GenerateFloat(0.7f, 1.0f), Random::GenerateFloat(0.2f, 0.3f));
float lightFalloff = Random::GenerateFloat(0.1f, 0.2f); TriggerDynamicPointLight(lightPos, lightColor, Random::GenerateFloat(BLOCK(6), BLOCK(12)));
float transformationLightFalloff = (0.5, 1.0);
TriggerDynamicLight(lightPos, lightColor, lightFalloff);
// Handle transformation. // Handle transformation.
if (effectTimer == timeExplosion1) if (effectTimer == timeExplosion1)
{ {
TriggerDynamicLight(lightPos, lightColor, transformationLightFalloff); TriggerDynamicPointLight(lightPos, lightColor, Random::GenerateFloat(BLOCK(12), BLOCK(24)));
SpawnBartoliTransformEffect(item, ID_SPHERE_OF_DOOM); SpawnBartoliTransformEffect(item, ID_SPHERE_OF_DOOM);
SoundEffect(SFX_TR2_MARCO_BARTOLLI_TRANSFORM, &item.Pose); SoundEffect(SFX_TR2_MARCO_BARTOLLI_TRANSFORM, &item.Pose);
} }
if (effectTimer == timeExplosion2) if (effectTimer == timeExplosion2)
{ {
TriggerDynamicLight(lightPos, lightColor, transformationLightFalloff); TriggerDynamicPointLight(lightPos, lightColor, Random::GenerateFloat(BLOCK(12), BLOCK(24)));
SpawnBartoliTransformEffect(item, ID_SPHERE_OF_DOOM2); SpawnBartoliTransformEffect(item, ID_SPHERE_OF_DOOM2);
SoundEffect(SFX_TR2_MARCO_BARTOLLI_TRANSFORM, &item.Pose); SoundEffect(SFX_TR2_MARCO_BARTOLLI_TRANSFORM, &item.Pose);
} }
if (effectTimer == timeExplosion3) if (effectTimer == timeExplosion3)
{ {
TriggerDynamicLight(lightPos, lightColor, transformationLightFalloff); TriggerDynamicPointLight(lightPos, lightColor, Random::GenerateFloat(BLOCK(12), BLOCK(24)));
SpawnBartoliTransformEffect(item, ID_SPHERE_OF_DOOM3); SpawnBartoliTransformEffect(item, ID_SPHERE_OF_DOOM3);
SoundEffect(SFX_TR2_MARCO_BARTOLLI_TRANSFORM, &item.Pose); SoundEffect(SFX_TR2_MARCO_BARTOLLI_TRANSFORM, &item.Pose);
item.Animation.FrameNumber = animationFrameEnd; item.Animation.FrameNumber = animationFrameEnd;

View file

@ -193,9 +193,9 @@ namespace TEN::Entities::Creatures::TR2
Random::GenerateFloat(0.8f, 0.9f), Random::GenerateFloat(0.8f, 0.9f),
Random::GenerateFloat(0.4f, 0.5f), Random::GenerateFloat(0.4f, 0.5f),
Random::GenerateFloat(0.2f, 0.3f)); Random::GenerateFloat(0.2f, 0.3f));
float falloff = Random::GenerateFloat(0.1f, 0.4f); float falloff = Random::GenerateFloat(BLOCK(6), BLOCK(20));
TriggerDynamicLight(pos, color, falloff); TriggerDynamicPointLight(pos, color, falloff);
} }
break; break;
@ -205,9 +205,9 @@ namespace TEN::Entities::Creatures::TR2
Random::GenerateFloat(0.8f, 0.9f), Random::GenerateFloat(0.8f, 0.9f),
Random::GenerateFloat(0.2f, 0.3f), Random::GenerateFloat(0.2f, 0.3f),
Random::GenerateFloat(0.0f, 0.1f)); Random::GenerateFloat(0.0f, 0.1f));
float falloff = Random::GenerateFloat(0.1f, 0.2f); float falloff = Random::GenerateFloat(BLOCK(6), BLOCK(12));
TriggerDynamicLight(pos, color, falloff); TriggerDynamicPointLight(pos, color, falloff);
} }
break; break;
} }

View file

@ -178,8 +178,8 @@ namespace TEN::Entities::Creatures::TR3
{ {
auto pos = GetJointPosition(item, SealMutantGasBite.BoneID, Vector3(0.0f, -SEAL_MUTANT_FLAME_LIGHT_Y_OFFSET, 0.0f)); auto pos = GetJointPosition(item, SealMutantGasBite.BoneID, Vector3(0.0f, -SEAL_MUTANT_FLAME_LIGHT_Y_OFFSET, 0.0f));
auto color = Color(Random::GenerateFloat(0.75f, 1.0f), Random::GenerateFloat(0.4f, 0.5f), Random::GenerateFloat(0.0f, 0.25f)); auto color = Color(Random::GenerateFloat(0.75f, 1.0f), Random::GenerateFloat(0.4f, 0.5f), Random::GenerateFloat(0.0f, 0.25f));
float falloff = Random::GenerateFloat(0.03f, 0.04f); float falloff = Random::GenerateFloat(BLOCK(1.5f), BLOCK(2.5f));
TriggerDynamicLight(pos.ToVector3(), color, falloff); TriggerDynamicPointLight(pos.ToVector3(), color, falloff);
} }
} }
else if (TestAnimFrameRange(item, 1, 124)) else if (TestAnimFrameRange(item, 1, 124))

View file

@ -713,7 +713,7 @@ namespace TEN::Entities::TR4
TriggerShockwave((Pose*)&pos, 24, 88, 200, 128, 128, 128, 32, EulerAngles::Identity, 8, true, false, true, (int)ShockwaveStyle::Normal); TriggerShockwave((Pose*)&pos, 24, 88, 200, 128, 128, 128, 32, EulerAngles::Identity, 8, true, false, true, (int)ShockwaveStyle::Normal);
auto lightColor = Color(1.0f, 0.4f, 0.2f); auto lightColor = Color(1.0f, 0.4f, 0.2f);
TriggerDynamicLight(pos.ToVector3(), lightColor, 0.1f); TriggerDynamicPointLight(pos.ToVector3(), lightColor, BLOCK(6));
Camera.bounce = -128; Camera.bounce = -128;

View file

@ -600,7 +600,7 @@ namespace TEN::Entities::Creatures::TR5
TriggerShockwave(&Pose(pos1), 16, 160, 64, 0, color / 2, color, 48, EulerAngles::Identity, 1, true, false, true, (int)ShockwaveStyle::Normal); TriggerShockwave(&Pose(pos1), 16, 160, 64, 0, color / 2, color, 48, EulerAngles::Identity, 1, true, false, true, (int)ShockwaveStyle::Normal);
auto lightColor = Color(0.4f, 0.3f, 0.0f); auto lightColor = Color(0.4f, 0.3f, 0.0f);
TriggerDynamicLight(pos.ToVector3(), lightColor, 0.04f); TriggerDynamicPointLight(pos.ToVector3(), lightColor, BLOCK(2.5f));
} }
deltaFrame = item->Animation.FrameNumber - GetAnimData(item).frameBase; deltaFrame = item->Animation.FrameNumber - GetAnimData(item).frameBase;
@ -629,7 +629,7 @@ namespace TEN::Entities::Creatures::TR5
if (item->ItemFlags[3]) if (item->ItemFlags[3])
{ {
auto lightColor = Color(0.0f, 0.4f, 1.0f); auto lightColor = Color(0.0f, 0.4f, 1.0f);
TriggerDynamicLight(pos.ToVector3(), lightColor, 0.06f); TriggerDynamicPointLight(pos.ToVector3(), lightColor, BLOCK(4));
} }
} }
} }

View file

@ -74,10 +74,10 @@ namespace TEN::Entities::Traps
static void SpawnLaserBeamLight(const Vector3& pos, int roomNumber, const Color& color, float intensity, float amplitudeMax) static void SpawnLaserBeamLight(const Vector3& pos, int roomNumber, const Color& color, float intensity, float amplitudeMax)
{ {
constexpr auto FALLOFF = 0.03f; constexpr auto LASER_BEAM_FALLOFF = BLOCK(1.5f);
float intensityNorm = intensity - Random::GenerateFloat(0.0f, amplitudeMax); float intensityNorm = intensity - Random::GenerateFloat(0.0f, amplitudeMax);
TriggerDynamicLight(pos, color * intensityNorm, FALLOFF); TriggerDynamicPointLight(pos, color * intensityNorm, LASER_BEAM_FALLOFF);
} }
void LaserBeamEffect::StoreInterpolationData() void LaserBeamEffect::StoreInterpolationData()

View file

@ -32,8 +32,6 @@ namespace TEN::Renderer
void Renderer::FreeRendererData() void Renderer::FreeRendererData()
{ {
_shadowLight = nullptr;
_items.resize(0); _items.resize(0);
_effects.resize(0); _effects.resize(0);
_moveableObjects.resize(0); _moveableObjects.resize(0);
@ -47,6 +45,12 @@ namespace TEN::Renderer
_animatedTextures.resize(0); _animatedTextures.resize(0);
_animatedTextureSets.resize(0); _animatedTextureSets.resize(0);
_shadowLight = nullptr;
_dynamicLightList = 0;
for (auto& dynamicLightList : _dynamicLights)
dynamicLightList.resize(0);
for (auto& mesh : _meshes) for (auto& mesh : _meshes)
delete mesh; delete mesh;
_meshes.resize(0); _meshes.resize(0);
@ -195,12 +199,23 @@ namespace TEN::Renderer
} }
_context->PSSetSamplers((UINT)registerType, 1, &samplerState); _context->PSSetSamplers((UINT)registerType, 1, &samplerState);
} }
void Renderer::BindLight(RendererLight& light, ShaderLight* lights, int index)
{
memcpy(&lights[index], &light, sizeof(ShaderLight));
if (light.Hash == 0)
return;
lights[index].Position = Vector3::Lerp(light.PrevPosition, light.Position, GetInterpolationFactor());
lights[index].Direction = Vector3::Lerp(light.PrevDirection, light.Direction, GetInterpolationFactor());
}
void Renderer::BindRoomLights(std::vector<RendererLight*>& lights) void Renderer::BindRoomLights(std::vector<RendererLight*>& lights)
{ {
for (int i = 0; i < lights.size(); i++) for (int i = 0; i < lights.size(); i++)
memcpy(&_stRoom.RoomLights[i], lights[i], sizeof(ShaderLight)); BindLight(*lights[i], _stRoom.RoomLights, i);
_stRoom.NumRoomLights = (int)lights.size(); _stRoom.NumRoomLights = (int)lights.size();
} }
@ -208,7 +223,7 @@ namespace TEN::Renderer
void Renderer::BindStaticLights(std::vector<RendererLight*>& lights) void Renderer::BindStaticLights(std::vector<RendererLight*>& lights)
{ {
for (int i = 0; i < lights.size(); i++) for (int i = 0; i < lights.size(); i++)
memcpy(&_stStatic.Lights[i], lights[i], sizeof(ShaderLight)); BindLight(*lights[i], _stStatic.Lights, i);
_stStatic.NumLights = (int)lights.size(); _stStatic.NumLights = (int)lights.size();
} }
@ -216,7 +231,7 @@ namespace TEN::Renderer
void Renderer::BindInstancedStaticLights(std::vector<RendererLight*>& lights, int instanceID) void Renderer::BindInstancedStaticLights(std::vector<RendererLight*>& lights, int instanceID)
{ {
for (int i = 0; i < lights.size(); i++) for (int i = 0; i < lights.size(); i++)
memcpy(&_stInstancedStaticMeshBuffer.StaticMeshes[instanceID].Lights[i], lights[i], sizeof(ShaderLight)); BindLight(*lights[i], _stInstancedStaticMeshBuffer.StaticMeshes[instanceID].Lights, i);
_stInstancedStaticMeshBuffer.StaticMeshes[instanceID].NumLights = (int)lights.size(); _stInstancedStaticMeshBuffer.StaticMeshes[instanceID].NumLights = (int)lights.size();
} }
@ -242,7 +257,7 @@ namespace TEN::Renderer
if (fadedCoeff == 0.0f) if (fadedCoeff == 0.0f)
continue; continue;
memcpy(&_stItem.Lights[numLights], lights[i], sizeof(ShaderLight)); BindLight(*lights[i], _stItem.Lights, numLights);
_stItem.Lights[numLights].Intensity *= fadedCoeff; _stItem.Lights[numLights].Intensity *= fadedCoeff;
numLights++; numLights++;
} }

View file

@ -245,7 +245,8 @@ namespace TEN::Renderer
// Lights // Lights
std::vector<RendererLight> _dynamicLights; int _dynamicLightList = 0;
std::vector<RendererLight> _dynamicLights[2];
RendererLight* _shadowLight; RendererLight* _shadowLight;
// Lines // Lines
@ -417,6 +418,7 @@ namespace TEN::Renderer
void ApplySMAA(RenderTarget2D* renderTarget, RenderView& view); void ApplySMAA(RenderTarget2D* renderTarget, RenderView& view);
void ApplyFXAA(RenderTarget2D* renderTarget, RenderView& view); void ApplyFXAA(RenderTarget2D* renderTarget, RenderView& view);
void BindTexture(TextureRegister registerType, TextureBase* texture, SamplerStateRegister samplerType); void BindTexture(TextureRegister registerType, TextureBase* texture, SamplerStateRegister samplerType);
void BindLight(RendererLight& light, ShaderLight* lights, int index);
void BindRoomLights(std::vector<RendererLight*>& lights); void BindRoomLights(std::vector<RendererLight*>& lights);
void BindStaticLights(std::vector<RendererLight*>& lights); void BindStaticLights(std::vector<RendererLight*>& lights);
void BindInstancedStaticLights(std::vector<RendererLight*>& lights, int instanceID); void BindInstancedStaticLights(std::vector<RendererLight*>& lights, int instanceID);
@ -643,7 +645,9 @@ namespace TEN::Renderer
void AddString(const std::string& string, const Vector2& pos, const Color& color, float scale, int flags); void AddString(const std::string& string, const Vector2& pos, const Color& color, float scale, int flags);
void AddDebugString(const std::string& string, const Vector2& pos, const Color& color, float scale, RendererDebugPage page = RendererDebugPage::None); void AddDebugString(const std::string& string, const Vector2& pos, const Color& color, float scale, RendererDebugPage page = RendererDebugPage::None);
void FreeRendererData(); void FreeRendererData();
void AddDynamicLight(int x, int y, int z, short falloff, byte r, byte g, byte b); void AddDynamicPointLight(const Vector3& pos, float radius, const Color& color, bool castShadows, int hash = 0);
void AddDynamicSpotLight(const Vector3& pos, const Vector3& dir, float radius, float falloff, float distance, const Color& color, bool castShadows, int hash = 0);
void StoreInterpolatedDynamicLightData(RendererLight& light);
void RenderLoadingScreen(float percentage); void RenderLoadingScreen(float percentage);
void RenderFreezeMode(float interpFactor, bool staticBackground); void RenderFreezeMode(float interpFactor, bool staticBackground);
void UpdateProgress(float value); void UpdateProgress(float value);

View file

@ -34,6 +34,10 @@ namespace TEN::Renderer
_meshes.clear(); _meshes.clear();
_dynamicLightList = 0;
for (auto& dynamicLightList : _dynamicLights)
dynamicLightList.clear();
int allocatedItemSize = (int)g_Level.Items.size() + MAX_SPAWNED_ITEM_COUNT; int allocatedItemSize = (int)g_Level.Items.size() + MAX_SPAWNED_ITEM_COUNT;
auto item = RendererItem(); auto item = RendererItem();

View file

@ -148,8 +148,10 @@ namespace TEN::Renderer
SetBlendMode(BlendMode::Opaque); SetBlendMode(BlendMode::Opaque);
SetCullMode(CullMode::CounterClockwise); SetCullMode(CullMode::CounterClockwise);
int steps = _shadowLight->Type == LightType::Point ? 6 : 1; auto shadowLightPos = _shadowLight->Hash == 0 ? _shadowLight->Position :
for (int step = 0; step < steps; step++) Vector3::Lerp(_shadowLight->PrevPosition, _shadowLight->Position, GetInterpolationFactor());
for (int step = 0; step < 6; step++)
{ {
// Bind render target // Bind render target
_context->OMSetRenderTargets(1, _shadowMap.RenderTargetView[step].GetAddressOf(), _context->OMSetRenderTargets(1, _shadowMap.RenderTargetView[step].GetAddressOf(),
@ -158,7 +160,7 @@ namespace TEN::Renderer
_context->RSSetViewports(1, &_shadowMapViewport); _context->RSSetViewports(1, &_shadowMapViewport);
ResetScissor(); ResetScissor();
if (_shadowLight->Position == item->Position) if (shadowLightPos == item->Position)
return; return;
UINT stride = sizeof(Vertex); UINT stride = sizeof(Vertex);
@ -178,27 +180,11 @@ namespace TEN::Renderer
BindTexture(TextureRegister::NormalMap, &std::get<1>(_moveablesTextures[0]), SamplerStateRegister::AnisotropicClamp); BindTexture(TextureRegister::NormalMap, &std::get<1>(_moveablesTextures[0]), SamplerStateRegister::AnisotropicClamp);
// Set camera matrices // Set camera matrices
Matrix view; Matrix view = Matrix::CreateLookAt(shadowLightPos, shadowLightPos +
Matrix projection; RenderTargetCube::forwardVectors[step] * BLOCK(10),
if (_shadowLight->Type == LightType::Point) RenderTargetCube::upVectors[step]);
{
view = Matrix::CreateLookAt(_shadowLight->Position, _shadowLight->Position +
RenderTargetCube::forwardVectors[step] * BLOCK(10),
RenderTargetCube::upVectors[step]);
projection = Matrix::CreatePerspectiveFieldOfView(90.0f * PI / 180.0f, 1.0f, 16.0f, _shadowLight->Out); Matrix projection = Matrix::CreatePerspectiveFieldOfView(90.0f * PI / 180.0f, 1.0f, 16.0f, _shadowLight->Out);
}
else if (_shadowLight->Type == LightType::Spot)
{
view = Matrix::CreateLookAt(_shadowLight->Position,
_shadowLight->Position + _shadowLight->Direction * BLOCK(10),
Vector3(0.0f, -1.0f, 0.0f));
// Vertex lighting fades out in 1024-steps. increase angle artificially for a bigger blend radius.
float projectionAngle = _shadowLight->OutRange * 1.5f * (PI / 180.0f);
projection = Matrix::CreatePerspectiveFieldOfView(projectionAngle, 1.0f, 16.0f, _shadowLight->Out);
}
CCameraMatrixBuffer shadowProjection; CCameraMatrixBuffer shadowProjection;
shadowProjection.ViewProjection = view * projection; shadowProjection.ViewProjection = view * projection;
@ -1536,41 +1522,102 @@ namespace TEN::Renderer
AddDebugSphere(sphere.Center, sphere.Radius, color, page, isWireframe); AddDebugSphere(sphere.Center, sphere.Radius, color, page, isWireframe);
} }
void Renderer::AddDynamicLight(int x, int y, int z, short falloff, byte r, byte g, byte b) void Renderer::AddDynamicSpotLight(const Vector3& pos, const Vector3& dir, float radius, float falloff, float distance, const Color& color, bool castShadows, int hash)
{ {
if (_isLocked || g_GameFlow->LastFreezeMode != FreezeMode::None) if (_isLocked || g_GameFlow->LastFreezeMode != FreezeMode::None)
return; return;
RendererLight dynamicLight = {}; RendererLight dynamicLight = {};
if (falloff >= 8) dynamicLight.Color = Vector3(color.x, color.y, color.z) * 2.0f;
{ if (falloff < 8)
dynamicLight.Color = Vector3(r / 255.0f, g / 255.0f, b / 255.0f) * 2.0f; dynamicLight.Color *= (falloff / 8.0f);
}
else
{
r = (r * falloff) >> 3;
g = (g * falloff) >> 3;
b = (b * falloff) >> 3;
dynamicLight.Color = Vector3(r / 255.0f, g / 255.0f, b / 255.0f) * 2.0f; // Calculate outer cone angle (degrees) based on radius at the cone's end distance.
} float outerConeAngle = atan(radius / distance) * (180.0f / PI);
float innerConeAngle = atan((radius - falloff) / distance) * (180.0f / PI);
float innerDistance = std::max(0.0f, distance - distance * (falloff / radius));
// Normalize direction for safety.
auto normalizedDirection = dir;
normalizedDirection.Normalize();
dynamicLight.RoomNumber = NO_VALUE; dynamicLight.RoomNumber = NO_VALUE;
dynamicLight.Intensity = 1.0f; dynamicLight.Intensity = 1.0f;
dynamicLight.Position = Vector3(float(x), float(y), float(z)); dynamicLight.Position = pos;
dynamicLight.Out = falloff * 256.0f; dynamicLight.Direction = normalizedDirection;
dynamicLight.Type = LightType::Point; dynamicLight.In = innerDistance;
dynamicLight.BoundingSphere = BoundingSphere(dynamicLight.Position, dynamicLight.Out); dynamicLight.Out = distance;
dynamicLight.InRange = innerConeAngle > 0.0f ? innerConeAngle : 0.5f;
dynamicLight.OutRange = outerConeAngle;
dynamicLight.Type = LightType::Spot;
dynamicLight.CastShadows = castShadows;
dynamicLight.BoundingSphere = BoundingSphere(pos, distance);
dynamicLight.Luma = Luma(dynamicLight.Color); dynamicLight.Luma = Luma(dynamicLight.Color);
dynamicLight.Hash = hash;
_dynamicLights.push_back(dynamicLight); StoreInterpolatedDynamicLightData(dynamicLight);
_dynamicLights[_dynamicLightList].push_back(dynamicLight);
}
void Renderer::AddDynamicPointLight(const Vector3& pos, float radius, const Color& color, bool castShadows, int hash)
{
if (_isLocked || g_GameFlow->LastFreezeMode != FreezeMode::None)
return;
RendererLight dynamicLight = {};
dynamicLight.Color = Vector3(color.x, color.y, color.z) * 2.0f;
if (radius < BLOCK(2))
dynamicLight.Color *= (radius / BLOCK(2));
dynamicLight.RoomNumber = NO_VALUE;
dynamicLight.Intensity = 1.0f;
dynamicLight.Position = pos;
dynamicLight.In = 1.0f;
dynamicLight.Out = radius;
dynamicLight.Type = LightType::Point;
dynamicLight.CastShadows = castShadows;
dynamicLight.BoundingSphere = BoundingSphere(pos, radius);
dynamicLight.Luma = Luma(dynamicLight.Color);
dynamicLight.Hash = hash;
StoreInterpolatedDynamicLightData(dynamicLight);
_dynamicLights[_dynamicLightList].push_back(dynamicLight);
}
void Renderer::StoreInterpolatedDynamicLightData(RendererLight& light)
{
// Hash is not provided, do not search for same light in old buffer.
if (light.Hash == 0)
return;
// Determine the previous buffer index.
const auto& previousList = _dynamicLights[1 - _dynamicLightList];
// Find a light in the previous buffer with the same Hash.
auto it = std::find_if(previousList.begin(), previousList.end(),
[&light](const auto& prevLight)
{
return prevLight.Hash == light.Hash;
});
if (it == previousList.end())
return;
// If a matching light is found, copy its data.
const auto& prevLight = *it;
light.PrevPosition = prevLight.Position;
light.PrevDirection = prevLight.Direction;
} }
void Renderer::PrepareScene() void Renderer::PrepareScene()
{ {
if (g_GameFlow->CurrentFreezeMode == FreezeMode::None) if (g_GameFlow->CurrentFreezeMode == FreezeMode::None)
_dynamicLights.clear(); {
_dynamicLightList ^= 1;
_dynamicLights[_dynamicLightList].clear();
}
_lines2DToDraw.clear(); _lines2DToDraw.clear();
_lines3DToDraw.clear(); _lines3DToDraw.clear();
@ -1854,7 +1901,7 @@ namespace TEN::Renderer
_context->ClearDepthStencilView(_renderTarget.DepthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); _context->ClearDepthStencilView(_renderTarget.DepthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
// HUD must be drawn before post-processing to be antialiased. // HUD must be drawn before post-processing to be antialiased.
if (renderMode == SceneRenderMode::Full) if (renderMode == SceneRenderMode::Full && g_GameFlow->LastGameStatus == GameStatus::Normal)
g_Hud.Draw(*LaraItem); g_Hud.Draw(*LaraItem);
if (renderMode != SceneRenderMode::NoPostprocess) if (renderMode != SceneRenderMode::NoPostprocess)
@ -1889,7 +1936,7 @@ namespace TEN::Renderer
DrawLines2D(); DrawLines2D();
} }
if (renderMode == SceneRenderMode::Full) if (renderMode == SceneRenderMode::Full && g_GameFlow->LastGameStatus == GameStatus::Normal)
{ {
// Draw display sprites sorted by priority. // Draw display sprites sorted by priority.
CollectDisplaySprites(view); CollectDisplaySprites(view);
@ -2292,7 +2339,7 @@ namespace TEN::Renderer
for (int k = 0; k < moveableObj.ObjectMeshes.size(); k++) for (int k = 0; k < moveableObj.ObjectMeshes.size(); k++)
{ {
if (!(nativeItem->MeshBits & (1 << k))) if (!nativeItem->MeshBits.Test(k))
continue; continue;
DrawMoveableMesh(item, GetMesh(item->MeshIds[k]), room, k, view, rendererPass); DrawMoveableMesh(item, GetMesh(item->MeshIds[k]), room, k, view, rendererPass);

View file

@ -885,7 +885,7 @@ namespace TEN::Renderer
void Renderer::RenderTitleImage() void Renderer::RenderTitleImage()
{ {
Texture2D texture; Texture2D texture;
SetTextureOrDefault(texture, TEN::Utils::ToWString(g_GameFlow->IntroImagePath.c_str())); SetTextureOrDefault(texture, TEN::Utils::ToWString(g_GameFlow->GetGameDir() + g_GameFlow->IntroImagePath.c_str()));
if (!texture.Texture) if (!texture.Texture)
return; return;

View file

@ -530,7 +530,7 @@ namespace TEN::Renderer
void Renderer::CollectLights(Vector3 position, float radius, int roomNumber, int prevRoomNumber, bool prioritizeShadowLight, bool useCachedRoomLights, std::vector<RendererLightNode>* roomsLights, std::vector<RendererLight*>* outputLights) void Renderer::CollectLights(Vector3 position, float radius, int roomNumber, int prevRoomNumber, bool prioritizeShadowLight, bool useCachedRoomLights, std::vector<RendererLightNode>* roomsLights, std::vector<RendererLight*>* outputLights)
{ {
if (_rooms.size() < roomNumber) if (_rooms.size() <= roomNumber)
return; return;
// Now collect lights from dynamic list and from rooms // Now collect lights from dynamic list and from rooms
@ -540,164 +540,105 @@ namespace TEN::Renderer
auto& room = _rooms[roomNumber]; auto& room = _rooms[roomNumber];
RendererLight* brightestLight = nullptr; RendererLight* brightestLight = nullptr;
float brightest = 0.0f; float highestIntensity = 0.0f;
// Dynamic lights have the priority auto calculateIntensity = [](float distSqr, const RendererLight& light, float radius) -> std::optional<float>
for (auto& light : _dynamicLights)
{ {
float distSqr = if (distSqr >= SQUARE(BLOCK(20)) || distSqr > SQUARE(light.Out + radius))
SQUARE(position.x - light.Position.x) + return std::nullopt; // Light is too far.
SQUARE(position.y - light.Position.y) +
SQUARE(position.z - light.Position.z);
// Collect only lights nearer than 20 sectors
if (distSqr >= SQUARE(BLOCK(20)))
continue;
// Check the out radius
if (distSqr > SQUARE(light.Out + radius))
continue;
float distance = sqrt(distSqr); float distance = sqrt(distSqr);
float attenuation = 1.0f - distance / light.Out; float attenuation = 1.0f - distance / light.Out;
float intensity = attenuation * light.Intensity * light.Luma; return attenuation * light.Intensity * light.Luma;
};
RendererLightNode node = { &light, intensity, distance, 1 }; auto processLight = [&](RendererLight& light, float distSqr, int dynamicFlag)
tempLights.push_back(node); {
float distance = sqrt(distSqr);
float intensity = calculateIntensity(distSqr, light, radius).value_or(0.0f);
if (intensity <= EPSILON)
return;
if ((light.Type == LightType::Point || light.Type == LightType::Spot) &&
light.CastShadows && prioritizeShadowLight && intensity >= highestIntensity)
{
highestIntensity = intensity;
brightestLight = &light;
}
tempLights.push_back({ &light, intensity, distance, dynamicFlag });
};
// Dynamic lights have the priority
for (auto& light : _dynamicLights[_dynamicLightList])
{
float distSqr = Vector3::DistanceSquared(position, light.Position);
processLight(light, distSqr, 1);
} }
if (!useCachedRoomLights) if (!useCachedRoomLights)
{ {
// Check current room and neighbor rooms. // Check current room and neighbor rooms.
for (int roomToCheck : room.Neighbors) for (int roomToCheck : room.Neighbors)
{ {
auto& currentRoom = _rooms[roomToCheck]; auto& currentRoom = _rooms[roomToCheck];
int lightCount = (int)currentRoom.Lights.size(); for (auto& light : currentRoom.Lights)
for (int j = 0; j < lightCount; j++)
{ {
auto* light = &currentRoom.Lights[j];
float intensity = 0;
float dist = 0;
// Check only lights different from sun. // Check only lights different from sun.
if (light->Type == LightType::Sun) if (light.Type == LightType::Sun)
{ {
// Suns from non-adjacent rooms not added. // Suns from non-adjacent rooms not added.
if (roomToCheck != roomNumber && (prevRoomNumber != roomToCheck || prevRoomNumber == NO_VALUE)) if (roomToCheck != roomNumber && (prevRoomNumber != roomToCheck || prevRoomNumber == NO_VALUE))
continue; continue;
// Sun is added without distance checks. // Sun is added without distance checks.
intensity = light->Intensity * Luma(light->Color); float intensity = light.Intensity * Luma(light.Color);
RendererLightNode node = { &light, intensity, 0.0f, 0 };
tempLights.push_back(node);
if (roomsLights != nullptr)
roomsLights->push_back(node);
} }
else if (light->Type == LightType::Point || light->Type == LightType::Shadow) else if (light.Type == LightType::Point ||
light.Type == LightType::Shadow ||
light.Type == LightType::Spot)
{ {
float distSqr = float distSqr = Vector3::DistanceSquared(position, light.Position);
SQUARE(position.x - light->Position.x) + processLight(light, distSqr, 0);
SQUARE(position.y - light->Position.y) +
SQUARE(position.z - light->Position.z);
// Collect only lights nearer than 20 blocks.
if (distSqr >= SQUARE(BLOCK(20)))
continue;
// Check out radius.
if (distSqr > SQUARE(light->Out + radius))
continue;
dist = sqrt(distSqr);
float attenuation = 1.0f - dist / light->Out;
intensity = attenuation * light->Intensity * Luma(light->Color);
// If collecting shadows, try collecting shadow-casting light.
if (light->CastShadows && prioritizeShadowLight && light->Type == LightType::Point)
{
if (intensity >= brightest)
{
brightest = intensity;
brightestLight = light;
}
}
}
else if (light->Type == LightType::Spot)
{
float distSqr =
SQUARE(position.x - light->Position.x) +
SQUARE(position.y - light->Position.y) +
SQUARE(position.z - light->Position.z);
// Collect only lights nearer than 20 blocks.
if (distSqr >= SQUARE(BLOCK(20)))
continue;
// Check range.
if (distSqr > SQUARE(light->Out + radius))
continue;
dist = sqrt(distSqr);
float attenuation = 1.0f - dist / light->Out;
intensity = attenuation * light->Intensity * light->Luma;
// If shadow pointer provided, try collecting shadow-casting light.
if (light->CastShadows && prioritizeShadowLight)
{
if (intensity >= brightest)
{
brightest = intensity;
brightestLight = light;
}
}
} }
else else
{ {
// Invalid light type. // Invalid light type.
continue; continue;
} }
RendererLightNode node = { light, intensity, dist, 0 };
if (roomsLights != nullptr)
roomsLights->push_back(node);
tempLights.push_back(node);
} }
} }
} }
else else
{ {
for (int i = 0; i < roomsLights->size(); i++) for (auto& node : *roomsLights)
tempLights.push_back(roomsLights->at(i)); tempLights.push_back(node);
} }
// Sort lights. // Sort lights.
if (tempLights.size() > MAX_LIGHTS_PER_ITEM) if (tempLights.size() > MAX_LIGHTS_PER_ITEM)
{ {
std::sort( std::sort(tempLights.begin(), tempLights.end(), [](const RendererLightNode& a, const RendererLightNode& b)
tempLights.begin(), {
tempLights.end(), return (a.Dynamic == b.Dynamic) ? (a.LocalIntensity > b.LocalIntensity) : (a.Dynamic > b.Dynamic);
[](RendererLightNode a, RendererLightNode b) });
{
if (a.Dynamic == b.Dynamic)
{
return (a.LocalIntensity > b.LocalIntensity);
}
else
{
return (a.Dynamic > b.Dynamic);
}
});
} }
// Put actual lights in provided vector. // Put actual lights in provided vector.
outputLights->clear(); outputLights->clear();
// Add brightest ligh, if collecting shadow light is specified, even if it's far in range. // Add brightest light, if collecting shadow light is specified, even if it's far in range.
if (prioritizeShadowLight && brightestLight) if (prioritizeShadowLight && brightestLight)
outputLights->push_back(brightestLight); outputLights->push_back(brightestLight);
// Add max 8 lights per item, including shadow light for player eventually. // Add max 8 lights per item, including shadow light for player eventually.
for (auto l : tempLights) for (auto& l : tempLights)
{ {
if (prioritizeShadowLight && brightestLight == l.Light) if (prioritizeShadowLight && brightestLight == l.Light)
continue; continue;
@ -714,7 +655,7 @@ namespace TEN::Renderer
std::vector<RendererLight*> lightsToDraw; std::vector<RendererLight*> lightsToDraw;
CollectLights(Vector3(Camera.pos.x, Camera.pos.y, Camera.pos.z), CAMERA_LIGHT_COLLECTION_RADIUS, Camera.pos.RoomNumber, NO_VALUE, true, false, nullptr, &lightsToDraw); CollectLights(Vector3(Camera.pos.x, Camera.pos.y, Camera.pos.z), CAMERA_LIGHT_COLLECTION_RADIUS, Camera.pos.RoomNumber, NO_VALUE, true, false, nullptr, &lightsToDraw);
if (lightsToDraw.size() > 0 && lightsToDraw.front()->CastShadows) if (!lightsToDraw.empty() && lightsToDraw.front()->CastShadows)
{ {
_shadowLight = lightsToDraw.front(); _shadowLight = lightsToDraw.front();
} }
@ -784,9 +725,9 @@ namespace TEN::Renderer
ROOM_INFO* r = &g_Level.Rooms[roomNumber]; ROOM_INFO* r = &g_Level.Rooms[roomNumber];
// Collect dynamic lights for rooms // Collect dynamic lights for rooms
for (int i = 0; i < _dynamicLights.size(); i++) for (int i = 0; i < _dynamicLights[_dynamicLightList].size(); i++)
{ {
RendererLight* light = &_dynamicLights[i]; RendererLight* light = &_dynamicLights[_dynamicLightList][i];
// If no radius, ignore // If no radius, ignore
if (light->Out == 0.0f) if (light->Out == 0.0f)

View file

@ -126,11 +126,13 @@ namespace TEN::Renderer
_currentCausticsFrame = 0; _currentCausticsFrame = 0;
// Preallocate lists // Preallocate lists
_dynamicLights = createVector<RendererLight>(MAX_DYNAMIC_LIGHTS);
_lines2DToDraw = createVector<RendererLine2D>(MAX_LINES_2D); _lines2DToDraw = createVector<RendererLine2D>(MAX_LINES_2D);
_lines3DToDraw = createVector<RendererLine3D>(MAX_LINES_3D); _lines3DToDraw = createVector<RendererLine3D>(MAX_LINES_3D);
_triangles3DToDraw = createVector<RendererTriangle3D>(MAX_TRIANGLES_3D); _triangles3DToDraw = createVector<RendererTriangle3D>(MAX_TRIANGLES_3D);
for (auto& dynamicLightList : _dynamicLights)
dynamicLightList = createVector<RendererLight>(MAX_DYNAMIC_LIGHTS);
for (auto& item : _items) for (auto& item : _items)
item.LightsToDraw = createVector<RendererLight*>(MAX_LIGHTS_PER_ITEM); item.LightsToDraw = createVector<RendererLight*>(MAX_LIGHTS_PER_ITEM);

View file

@ -25,6 +25,11 @@ namespace TEN::Renderer::Structures
bool AffectNeighbourRooms; bool AffectNeighbourRooms;
bool CastShadows; bool CastShadows;
float Luma; float Luma;
Vector3 PrevPosition;
Vector3 PrevDirection;
int Hash = 0;
}; };
struct RendererLightNode struct RendererLightNode

View file

@ -306,6 +306,7 @@ static constexpr char ScriptReserved_EmitParticle[] = "EmitParticle";
static constexpr char ScriptReserved_EmitLightningArc[] = "EmitLightningArc"; static constexpr char ScriptReserved_EmitLightningArc[] = "EmitLightningArc";
static constexpr char ScriptReserved_EmitShockwave[] = "EmitShockwave"; static constexpr char ScriptReserved_EmitShockwave[] = "EmitShockwave";
static constexpr char ScriptReserved_EmitLight[] = "EmitLight"; static constexpr char ScriptReserved_EmitLight[] = "EmitLight";
static constexpr char ScriptReserved_EmitSpotLight[] = "EmitSpotLight";
static constexpr char ScriptReserved_EmitBlood[] = "EmitBlood"; static constexpr char ScriptReserved_EmitBlood[] = "EmitBlood";
static constexpr char ScriptReserved_EmitFire[] = "EmitFire"; static constexpr char ScriptReserved_EmitFire[] = "EmitFire";
static constexpr char ScriptReserved_MakeExplosion[] = "MakeExplosion"; static constexpr char ScriptReserved_MakeExplosion[] = "MakeExplosion";
@ -421,3 +422,7 @@ constexpr char ScriptReserved_Vec3Length[] = "Length";
constexpr char ScriptReserved_Vec3Lerp[] = "Lerp"; constexpr char ScriptReserved_Vec3Lerp[] = "Lerp";
constexpr char ScriptReserved_Vec3Normalize[] = "Normalize"; constexpr char ScriptReserved_Vec3Normalize[] = "Normalize";
constexpr char ScriptReserved_Vec3Rotate[] = "Rotate"; constexpr char ScriptReserved_Vec3Rotate[] = "Rotate";
// Rotation
constexpr char ScriptReserved_RotationDirection[] = "Direction";

View file

@ -23,6 +23,7 @@
#include "Scripting/Internal/TEN/Vec2/Vec2.h" #include "Scripting/Internal/TEN/Vec2/Vec2.h"
#include "Sound/sound.h" #include "Sound/sound.h"
#include "Specific/clock.h" #include "Specific/clock.h"
#include "Specific/trutils.h"
/*** /***
Functions to generate effects. Functions to generate effects.
@ -258,15 +259,38 @@ namespace TEN::Scripting::Effects
/***Emit dynamic light that lasts for a single frame. /***Emit dynamic light that lasts for a single frame.
* If you want a light that sticks around, you must call this each frame. * If you want a light that sticks around, you must call this each frame.
@function EmitLight @function EmitLight
@tparam Vec3 pos @tparam Vec3 pos position of the light
@tparam Color color (default Color(255, 255, 255)) @tparam[opt] Color color light color (default Color(255, 255, 255))
@tparam int radius (default 20) corresponds loosely to both intensity and range @tparam[opt] int radius measured in "clicks" or 256 world units (default 20)
@tparam[opt] bool shadows determines whether light should generate dynamic shadows for applicable moveables (default is false)
@tparam[opt] string name if provided, engine will interpolate this light for high framerate mode (be careful not to use same name for different lights)
*/ */
static void EmitLight(Vec3 pos, TypeOrNil<ScriptColor> col, TypeOrNil<int> radius) static void EmitLight(Vec3 pos, TypeOrNil<ScriptColor> col, TypeOrNil<int> radius, TypeOrNil<bool> castShadows, TypeOrNil<std::string> name)
{ {
auto color = USE_IF_HAVE(ScriptColor, col, ScriptColor(255, 255, 255)); auto color = USE_IF_HAVE(ScriptColor, col, ScriptColor(255, 255, 255));
int rad = USE_IF_HAVE(int, radius, 20); int rad = (float)(USE_IF_HAVE(int, radius, 20) * BLOCK(0.25f));
TriggerDynamicLight(pos.x, pos.y, pos.z, rad, color.GetR(), color.GetG(), color.GetB()); TriggerDynamicPointLight(pos.ToVector3(), color, rad, USE_IF_HAVE(bool, castShadows, false), GetHash(USE_IF_HAVE(std::string, name, std::string())));
}
/***Emit dynamic directional spotlight that lasts for a single frame.
* If you want a light that sticks around, you must call this each frame.
@function EmitSpotLight
@tparam Vec3 pos position of the light
@tparam Vec3 dir direction, or a point to which spotlight should be directed to
@tparam[opt] Color color (default Color(255, 255, 255))
@tparam[opt] int radius overall radius at the endpoint of a light cone, measured in "clicks" or 256 world units (default 10)
@tparam[opt] int falloff radius, at which light starts to fade out, measured in "clicks" (default 5)
@tparam[opt] int distance distance, at which light cone fades out, measured in "clicks" (default 20)
@tparam[opt] bool shadows determines whether light should generate dynamic shadows for applicable moveables (default is false)
@tparam[opt] string name if provided, engine will interpolate this light for high framerate mode (be careful not to use same name for different lights)
*/
static void EmitSpotLight(Vec3 pos, Vec3 dir, TypeOrNil<ScriptColor> col, TypeOrNil<int> radius, TypeOrNil<int> falloff, TypeOrNil<int> distance, TypeOrNil<bool> castShadows, TypeOrNil<std::string> name)
{
auto color = USE_IF_HAVE(ScriptColor, col, ScriptColor(255, 255, 255));
int rad = (float)(USE_IF_HAVE(int, radius, 10) * BLOCK(0.25f));
int fallOff = (float)(USE_IF_HAVE(int, falloff, 5) * BLOCK(0.25f));
int dist = (float)(USE_IF_HAVE(int, distance, 20) * BLOCK(0.25f));
TriggerDynamicSpotLight(pos.ToVector3(), dir.ToVector3(), color, rad, fallOff, dist, USE_IF_HAVE(bool, castShadows, false), GetHash(USE_IF_HAVE(std::string, name, std::string())));
} }
/***Emit blood. /***Emit blood.
@ -328,6 +352,7 @@ namespace TEN::Scripting::Effects
tableEffects.set_function(ScriptReserved_EmitParticle, &EmitParticle); tableEffects.set_function(ScriptReserved_EmitParticle, &EmitParticle);
tableEffects.set_function(ScriptReserved_EmitShockwave, &EmitShockwave); tableEffects.set_function(ScriptReserved_EmitShockwave, &EmitShockwave);
tableEffects.set_function(ScriptReserved_EmitLight, &EmitLight); tableEffects.set_function(ScriptReserved_EmitLight, &EmitLight);
tableEffects.set_function(ScriptReserved_EmitSpotLight, &EmitSpotLight);
tableEffects.set_function(ScriptReserved_EmitBlood, &EmitBlood); tableEffects.set_function(ScriptReserved_EmitBlood, &EmitBlood);
tableEffects.set_function(ScriptReserved_MakeExplosion, &MakeExplosion); tableEffects.set_function(ScriptReserved_MakeExplosion, &MakeExplosion);
tableEffects.set_function(ScriptReserved_EmitFire, &EmitFire); tableEffects.set_function(ScriptReserved_EmitFire, &EmitFire);

View file

@ -637,7 +637,20 @@ Vec3 Moveable::GetJointPos(int jointIndex, sol::optional<Vec3> offset) const
Rotation Moveable::GetJointRot(int jointIndex) const Rotation Moveable::GetJointRot(int jointIndex) const
{ {
return GetBoneOrientation(*m_item, jointIndex); auto point1 = GetJointPosition(m_item, jointIndex);
auto point2 = GetJointPosition(m_item, jointIndex, Vector3::Forward * BLOCK(1));
auto normal = (point1 - point2).ToVector3();
normal.Normalize();
auto eulers = EulerAngles(normal);
return
{
TO_DEGREES(eulers.x),
TO_DEGREES(eulers.y),
TO_DEGREES(eulers.z)
};
} }
// This does not guarantee that the returned value will be identical // This does not guarantee that the returned value will be identical

View file

@ -18,6 +18,7 @@ void Rotation::Register(sol::table& parent)
ctors(), ctors(),
sol::call_constructor, ctors(), sol::call_constructor, ctors(),
sol::meta_function::to_string, &Rotation::ToString, sol::meta_function::to_string, &Rotation::ToString,
ScriptReserved_RotationDirection, &Rotation::Direction,
/// (float) X angle component. /// (float) X angle component.
// @mem x // @mem x
@ -77,6 +78,24 @@ Rotation::operator Vector3() const
return Vector3(x, y, z); return Vector3(x, y, z);
}; };
/// Converts rotation to a direction normal.
// @treturn Vec3 resulting normal calculated from this rotation.
// @function Direction
Vec3 Rotation::Direction() const
{
// Convert degrees to radians.
float xRad = x * RADIAN;
float yRad = y * RADIAN;
// Calculate the direction vector.
float dirX = sin(yRad) * cos(xRad);
float dirY = -sin(xRad);
float dirZ = cos(yRad) * cos(xRad);
// Scale by the given distance.
return Vec3(dirX, dirY, dirZ);
}
/// @tparam Rotation rotation this Rotation. /// @tparam Rotation rotation this Rotation.
// @treturn string A string showing the X, Y, and Z angle components of the Rotation. // @treturn string A string showing the X, Y, and Z angle components of the Rotation.
// @function __tostring // @function __tostring

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "Math/Objects/EulerAngles.h" #include "Math/Objects/EulerAngles.h"
#include "Scripting/Internal/TEN/Vec3/Vec3.h"
class EulerAngles; class EulerAngles;
class Pose; class Pose;
@ -27,6 +28,7 @@ public:
// Converters // Converters
std::string ToString() const; std::string ToString() const;
EulerAngles ToEulerAngles() const; EulerAngles ToEulerAngles() const;
Vec3 Direction() const;
// Operators // Operators
operator Vector3() const; operator Vector3() const;

View file

@ -30,7 +30,7 @@ Default: nil (i.e. infinite)
@tparam bool autoDelete should be string automatically deleted after timeout is reached. @tparam bool autoDelete should be string automatically deleted after timeout is reached.
If not given, the string will remain allocated even after timeout is reached, and can be If not given, the string will remain allocated even after timeout is reached, and can be
shown again without re-initialization. shown again without re-initialization.
Default: false Default: true
*/ */
table.set_function(ScriptReserved_ShowString, &StringsHandler::ShowString, this); table.set_function(ScriptReserved_ShowString, &StringsHandler::ShowString, this);
@ -93,7 +93,7 @@ void StringsHandler::ShowString(const DisplayString& str, sol::optional<float> n
auto it = m_userDisplayStrings.find(str.GetID()); auto it = m_userDisplayStrings.find(str.GetID());
it->second._timeRemaining = numSeconds.value_or(0.0f); it->second._timeRemaining = numSeconds.value_or(0.0f);
it->second._isInfinite = !numSeconds.has_value(); it->second._isInfinite = !numSeconds.has_value();
it->second._deleteWhenZero = autoDelete.value_or(false); it->second._deleteWhenZero = autoDelete.value_or(true);
} }
bool StringsHandler::IsStringDisplaying(const DisplayString& displayString) bool StringsHandler::IsStringDisplaying(const DisplayString& displayString)
@ -110,7 +110,7 @@ void StringsHandler::ProcessDisplayStrings(float deltaTime)
{ {
auto& str = it->second; auto& str = it->second;
bool endOfLife = 0.0f >= str._timeRemaining; bool endOfLife = 0.0f >= str._timeRemaining;
if (str._deleteWhenZero && endOfLife) if (!str._isInfinite && str._deleteWhenZero && endOfLife)
{ {
ScriptAssertF(!str._isInfinite, "The infinite string {} (key \"{}\") went out of scope without being hidden.", it->first, str._key); ScriptAssertF(!str._isInfinite, "The infinite string {} (key \"{}\") went out of scope without being hidden.", it->first, str._key);
it = m_userDisplayStrings.erase(it); it = m_userDisplayStrings.erase(it);

View file

@ -135,7 +135,7 @@ PixelShaderOutput PS(PixelShaderInput input)
if (AmbientOcclusion == 1) if (AmbientOcclusion == 1)
{ {
float2 samplePosition; float2 samplePosition;
samplePosition = input.PositionCopy.xy / input.PositionCopy.w; // perspective divide samplePosition = input.PositionCopy.xy / input.PositionCopy.w; // Perspective divide
samplePosition = samplePosition * 0.5f + 0.5f; // transform to range 0.0 - 1.0 samplePosition = samplePosition * 0.5f + 0.5f; // transform to range 0.0 - 1.0
samplePosition.y = 1.0f - samplePosition.y; samplePosition.y = 1.0f - samplePosition.y;
occlusion = pow(SSAOTexture.Sample(SSAOSampler, samplePosition).x, AmbientOcclusionExponent); occlusion = pow(SSAOTexture.Sample(SSAOSampler, samplePosition).x, AmbientOcclusionExponent);
@ -143,41 +143,26 @@ PixelShaderOutput PS(PixelShaderInput input)
if (CastShadows) if (CastShadows)
{ {
if (Light.Type == LT_POINT) float isPointLight = step(0.5f, Light.Type == LT_POINT); // 1.0 if LT_POINT, 0.0 otherwise
{ float isSpotLight = step(0.5f, Light.Type == LT_SPOT); // 1.0 if LT_SPOT, 0.0 otherwise
DoPointLightShadow(input.WorldPosition, lighting); float isOtherLight = 1.0 - (isPointLight + isSpotLight); // 1.0 if neither LT_POINT nor LT_SPOT
} float3 pointLightShadow = DoPointLightShadow(input.WorldPosition, lighting);
else if (Light.Type == LT_SPOT) float3 spotLightShadow = DoSpotLightShadow(input.WorldPosition, normal, lighting);
{
DoSpotLightShadow(input.WorldPosition, lighting); // Blend the shadows based on the light type
} lighting = pointLightShadow * isPointLight + spotLightShadow * isSpotLight + lighting * isOtherLight;
} }
DoBlobShadows(input.WorldPosition, lighting); lighting = DoBlobShadows(input.WorldPosition, lighting);
if (doLights) for (int i = 0; i < NumRoomLights; i++)
{ {
for (int i = 0; i < NumRoomLights; i++) float isPointLightRoom = step(0.5f, RoomLights[i].Type == LT_POINT);
{ float isSpotLightRoom = step(0.5f, RoomLights[i].Type == LT_SPOT);
float3 lightPos = RoomLights[i].Position.xyz;
float3 color = RoomLights[i].Color.xyz;
float radius = RoomLights[i].Out;
float3 lightVec = (lightPos - input.WorldPosition); lighting += DoPointLight(input.WorldPosition, normal, RoomLights[i]) * isPointLightRoom;
float distance = length(lightVec); lighting += DoSpotLight(input.WorldPosition, normal, RoomLights[i]) * isSpotLightRoom;
if (distance > radius)
continue;
lightVec = normalize(lightVec);
float d = saturate(dot(normal, lightVec ));
if (d < 0)
continue;
float attenuation = pow(((radius - distance) / radius), 2);
lighting += color * attenuation * d;
}
} }
if (Caustics) if (Caustics)

View file

@ -6,7 +6,7 @@
float3 DoSpecularPoint(float3 pos, float3 n, ShaderLight light, float strength) float3 DoSpecularPoint(float3 pos, float3 n, ShaderLight light, float strength)
{ {
if ((strength <= 0.0)) if (strength <= 0.0)
return float3(0, 0, 0); return float3(0, 0, 0);
else else
{ {
@ -97,116 +97,57 @@ float3 DoSpecularSpot(float3 pos, float3 n, ShaderLight light, float strength)
} }
} }
float3 DoPointLight(float3 pos, float3 n, ShaderLight light) float3 DoPointLight(float3 pos, float3 normal, ShaderLight light)
{ {
float3 lightPos = light.Position.xyz; float3 lightVec = light.Position.xyz - pos;
float3 color = light.Color.xyz; float distance = length(lightVec);
float intensity = saturate(light.Intensity); float3 lightDir = normalize(lightVec);
float3 lightVec = (lightPos - pos); float attenuation = saturate((light.Out - distance) / (light.Out - light.In));
float distance = length(lightVec); float d = saturate(dot(normal, lightDir));
if (distance > light.Out) return saturate(light.Color.xyz * light.Intensity * attenuation * d);
return float3(0, 0, 0);
else
{
lightVec = normalize(lightVec);
float d = saturate(dot(n, lightVec));
float attenuation = 1.0f;
if (distance > light.In)
attenuation = 1.0f - saturate((distance - light.In) / (light.Out - light.In));
return saturate(color * intensity * attenuation * d);
}
} }
float3 DoShadowLight(float3 pos, float3 n, ShaderLight light) float3 DoShadowLight(float3 pos, float3 normal, ShaderLight light)
{ {
float3 lightPos = light.Position.xyz; float3 lightVec = light.Position.xyz - pos;
float3 color = light.Color.xyz; float distance = length(lightVec);
float intensity = light.Intensity; float3 lightDir = normalize(lightVec);
float attenuation = saturate((light.Out - distance) / (light.Out - light.In));
float d = saturate(dot(normal, lightDir));
float3 lightVec = (lightPos - pos); float absolute = light.Color.xyz * light.Intensity * attenuation;
float distance = length(lightVec); float directional = absolute * d;
if (distance > light.Out) return saturate((absolute * 0.33f) + (directional * 0.66f)) * 2.0f;
return float3(0, 0, 0);
else
{
lightVec = normalize(lightVec);
float d = saturate(dot(n, lightVec));
float attenuation = 1.0f;
if (distance > light.In)
attenuation = 1.0f - saturate((distance - light.In) / (light.Out - light.In));
float absolute = float3(color * intensity * attenuation);
float directional = absolute * d;
return ((absolute * 0.33f) + (directional * 0.66f)) * 2.0f;
}
} }
float3 DoSpotLight(float3 pos, float3 n, ShaderLight light) float3 DoSpotLight(float3 pos, float3 normal, ShaderLight light)
{ {
float3 lightPos = light.Position.xyz; float3 lightVec = pos - light.Position.xyz;
float3 color = light.Color.xyz; float distance = length(lightVec);
float intensity = saturate(light.Intensity); float3 lightDir = normalize(lightVec);
float3 direction = light.Direction.xyz; float cosine = dot(lightDir, light.Direction.xyz);
float innerRange = light.In;
float outerRange = light.Out;
float coneIn = light.InRange;
float coneOut = light.OutRange;
float3 lightVec = pos - lightPos; // Angle attenuation
float distance = length(lightVec); float coneInCos = cos(light.InRange * (PI / 180.0f));
lightVec = normalize(lightVec); float coneOutCos = cos(light.OutRange * (PI / 180.0f));
float angleAttenuation = saturate((cosine - coneOutCos) / (coneInCos - coneOutCos));
if (distance > outerRange) // Distance attenuation
return float3(0, 0, 0); float distanceAttenuation = saturate((light.Out - distance) / (light.Out - light.In));
else
{
float d = saturate(dot(n, -lightVec));
if (d < 0)
return float3(0, 0, 0);
else
{
float cosine = dot(lightVec, direction);
float minCosineIn = cos(coneIn * (PI / 180.0f)); // Surface lighting
float attenuationIn = max((cosine - minCosineIn), 0.0f) / (1.0f - minCosineIn); float d = saturate(dot(normal, -lightDir));
return saturate(light.Color.xyz * light.Intensity * angleAttenuation * distanceAttenuation * d);
float minCosineOut = cos(coneOut * (PI / 180.0f));
float attenuationOut = max((cosine - minCosineOut), 0.0f) / (1.0f - minCosineOut);
float attenuation = saturate(attenuationIn * 2.0f + attenuationOut);
if (attenuation > 0.0f)
{
float falloff = saturate((outerRange - distance) / (outerRange - innerRange + 1.0f));
return saturate(color * intensity * attenuation * falloff * d);
}
else
return float3(0, 0, 0);
}
}
} }
float3 DoDirectionalLight(float3 pos, float3 n, ShaderLight light) float3 DoDirectionalLight(float3 pos, float3 normal, ShaderLight light)
{ {
float3 color = light.Color.xyz; float d = saturate(dot(-light.Direction.xyz, normal));
float3 intensity = light.Intensity; return light.Color.xyz * light.Intensity * d;
float3 direction = -light.Direction.xyz;
float d = max(dot(direction, n), .0f);
if (d > 0.f)
{
return (color * intensity * d);
}
return float3(0, 0, 0);
} }
float DoFogBulb(float3 pos, ShaderFogBulb bulb) float DoFogBulb(float3 pos, ShaderFogBulb bulb)
@ -369,13 +310,12 @@ float DoFogBulbForSky(float3 pos, ShaderFogBulb bulb)
float DoDistanceFogForVertex(float3 pos) float DoDistanceFogForVertex(float3 pos)
{ {
float fog = 0.0f; float d = length(CamPositionWS.xyz - pos);
float fogRange = FogMaxDistance * 1024 - FogMinDistance * 1024;
if (FogMaxDistance > 0.0f) float fogEnabled = step(0.0f, FogMaxDistance);
{ float fogFactor = (d - FogMinDistance * 1024) / fogRange;
float d = length(CamPositionWS.xyz - pos); float fog = saturate(fogFactor) * fogEnabled;
fog = clamp((d - FogMinDistance * 1024) / (FogMaxDistance * 1024 - FogMinDistance * 1024), 0, 1);
}
return fog; return fog;
} }
@ -383,16 +323,16 @@ float DoDistanceFogForVertex(float3 pos)
float4 DoFogBulbsForVertex(float3 pos) float4 DoFogBulbsForVertex(float3 pos)
{ {
float4 fog = float4(0.0f, 0.0f, 0.0f, 0.0f); float4 fog = float4(0.0f, 0.0f, 0.0f, 0.0f);
for (int i = 0; i < NumFogBulbs; i++) for (int i = 0; i < NumFogBulbs; i++)
{ {
float fogFactor = DoFogBulb(pos, FogBulbs[i]); float fogFactor = DoFogBulb(pos, FogBulbs[i]);
fog.xyz += FogBulbs[i].Color.xyz * fogFactor; float3 fogColor = FogBulbs[i].Color.xyz * fogFactor;
fog.xyz += fogColor;
fog.w += fogFactor; fog.w += fogFactor;
if (fog.w >= 1.0f)
{ fog.w = saturate(fog.w);
break;
}
} }
return fog; return fog;
@ -405,12 +345,12 @@ float4 DoFogBulbsForSky(float3 pos)
for (int i = 0; i < NumFogBulbs; i++) for (int i = 0; i < NumFogBulbs; i++)
{ {
float fogFactor = DoFogBulbForSky(pos, FogBulbs[i]); float fogFactor = DoFogBulbForSky(pos, FogBulbs[i]);
fog.xyz += FogBulbs[i].Color.xyz * fogFactor; float3 fogColor = FogBulbs[i].Color.xyz * fogFactor;
fog.xyz += fogColor;
fog.w += fogFactor; fog.w += fogFactor;
if (fog.w >= 1.0f)
{ fog.w = saturate(fog.w);
break;
}
} }
return fog; return fog;
@ -425,31 +365,25 @@ float3 CombineLights(float3 ambient, float3 vertex, float3 tex, float3 pos, floa
for (int i = 0; i < numLights; i++) for (int i = 0; i < numLights; i++)
{ {
int lightType = lights[i].Type; float isPoint = step(0.5f, float(lights[i].Type == LT_POINT));
float isSpot = step(0.5f, float(lights[i].Type == LT_SPOT));
float isSun = step(0.5f, float(lights[i].Type == LT_SUN));
float isShadow = step(0.5f, float(lights[i].Type == LT_SHADOW));
if (lightType == LT_POINT) diffuse += isPoint * DoPointLight(pos, normal, lights[i]);
{ spec += isPoint * DoSpecularPoint(pos, normal, lights[i], sheen);
diffuse += DoPointLight(pos, normal, lights[i]);
spec += DoSpecularPoint(pos, normal, lights[i], sheen); diffuse += isSpot * DoSpotLight(pos, normal, lights[i]);
} spec += isSpot * DoSpecularSpot(pos, normal, lights[i], sheen);
else if (lightType == LT_SHADOW)
{ diffuse += isSun * DoDirectionalLight(pos, normal, lights[i]);
shadow += DoShadowLight(pos, normal, lights[i]); spec += isSun * DoSpecularSun(normal, lights[i], sheen);
}
else if (lightType == LT_SUN) shadow += isShadow * DoShadowLight(pos, normal, lights[i]);
{
diffuse += DoDirectionalLight(pos, normal, lights[i]);
spec += DoSpecularSun(normal, lights[i], sheen);
}
else if (lightType == LT_SPOT)
{
diffuse += DoSpotLight(pos, normal, lights[i]);
spec += DoSpecularSpot(pos, normal, lights[i], sheen);
}
} }
shadow = saturate(shadow); shadow = saturate(shadow);
diffuse.xyz *= tex.xyz; diffuse *= tex;
float3 ambTex = saturate(ambient - shadow) * tex; float3 ambTex = saturate(ambient - shadow) * tex;
float3 combined = ambTex + diffuse + spec; float3 combined = ambTex + diffuse + spec;

View file

@ -1,3 +1,5 @@
#include "./ShaderLight.hlsli"
#define SHADOW_INTENSITY (0.55f) #define SHADOW_INTENSITY (0.55f)
#define INV_SHADOW_INTENSITY (1.0f - SHADOW_INTENSITY) #define INV_SHADOW_INTENSITY (1.0f - SHADOW_INTENSITY)
@ -66,48 +68,38 @@ float2 GetCubeUVFromDir(int faceIndex, float3 dir)
return uv * .5 + .5; return uv * .5 + .5;
} }
void DoPointLightShadow(float3 worldPos, inout float3 lighting) float3 DoBlobShadows(float3 worldPos, float3 lighting)
{ {
float shadowFactor = 1.0f; float shadowFactor = 1.0f;
for (int i = 0; i < NumSpheres; i++)
{
Sphere s = Spheres[i];
float dist = distance(worldPos, s.position);
float insideSphere = saturate(1.0f - step(s.radius, dist)); // Eliminates branching
float radiusFactor = dist / s.radius;
float factor = (1.0f - saturate(radiusFactor)) * insideSphere;
shadowFactor -= factor * shadowFactor;
}
shadowFactor = saturate(shadowFactor);
return lighting * saturate(shadowFactor + SHADOW_INTENSITY);
}
float3 DoPointLightShadow(float3 worldPos, float3 lighting)
{
float shadowFactor = 1.0f;
[unroll]
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
{ {
float3 dir = normalize(worldPos - Light.Position); float3 dir = normalize(worldPos - Light.Position);
int face = GetCubeFaceIndex(dir);
//debug coloring
/*
switch (face)
{
case 0:
lighting += float3(0.2, 0, 0);
break;
case 1:
lighting += float3(0.1, 0, 0);
break;
case 2:
lighting += float3(0, 0.2, 0);
break;
case 3:
lighting += float3(0, 0.1, 0);
break;
case 4:
lighting += float3(0, 0, 0.2);
break;
default:
lighting += float3(0, 0, 0.1);
break;
}
*/
float2 uv = GetCubeUVFromDir(face, dir);
float4 lightClipSpace = mul(float4(worldPos, 1.0f), LightViewProjections[i]); float4 lightClipSpace = mul(float4(worldPos, 1.0f), LightViewProjections[i]);
lightClipSpace.xyz /= lightClipSpace.w; lightClipSpace.xyz /= lightClipSpace.w;
if (lightClipSpace.x >= -1.0f && lightClipSpace.x <= 1.0f && if (lightClipSpace.x >= -1.0f && lightClipSpace.x <= 1.0f &&
lightClipSpace.y >= -1.0f && lightClipSpace.y <= 1.0f && lightClipSpace.y >= -1.0f && lightClipSpace.y <= 1.0f &&
lightClipSpace.z >= 0.0f && lightClipSpace.z <= 1.0f) lightClipSpace.z >= 0.0f && lightClipSpace.z <= 1.0f)
{ {
lightClipSpace.x = lightClipSpace.x / 2 + 0.5; lightClipSpace.x = lightClipSpace.x / 2 + 0.5;
lightClipSpace.y = lightClipSpace.y / -2 + 0.5; lightClipSpace.y = lightClipSpace.y / -2 + 0.5;
@ -115,10 +107,11 @@ void DoPointLightShadow(float3 worldPos, inout float3 lighting)
float sum = 0; float sum = 0;
float x, y; float x, y;
// Perform PCF filtering on a 4 x 4 texel neighborhood // Perform PCF filtering on a 4 x 4 texel neighborhood.
// what about borders of cubemap? [unroll]
for (y = -1.5; y <= 1.5; y += 1.0) for (y = -1.5; y <= 1.5; y += 1.0)
{ {
[unroll]
for (x = -1.5; x <= 1.5; x += 1.0) for (x = -1.5; x <= 1.5; x += 1.0)
{ {
sum += ShadowMap.SampleCmpLevelZero(ShadowMapSampler, float3(lightClipSpace.xy + TexOffset(x, y), i), lightClipSpace.z); sum += ShadowMap.SampleCmpLevelZero(ShadowMapSampler, float3(lightClipSpace.xy + TexOffset(x, y), i), lightClipSpace.z);
@ -128,59 +121,50 @@ void DoPointLightShadow(float3 worldPos, inout float3 lighting)
shadowFactor = sum / 16.0; shadowFactor = sum / 16.0;
} }
} }
// Compute attenuation and combine lighting contribution with shadow factor
float distanceFactor = saturate(((distance(worldPos, Light.Position)) / (Light.Out))); float distanceFactor = saturate(((distance(worldPos, Light.Position)) / (Light.Out)));
lighting *= saturate((shadowFactor + SHADOW_INTENSITY) + (pow(distanceFactor, 4) * INV_SHADOW_INTENSITY)); return lighting * saturate((shadowFactor + SHADOW_INTENSITY) + (pow(distanceFactor, 4) * INV_SHADOW_INTENSITY));
} }
float3 DoSpotLightShadow(float3 worldPos, float3 normal, float3 lighting)
void DoBlobShadows(float3 worldPos, inout float3 lighting)
{ {
float influence = 1.0f - Luma(DoSpotLight(worldPos, normal, Light));
float shadowFactor = 1.0f; float shadowFactor = 1.0f;
for (int i = 0; i < NumSpheres; i++)
[unroll]
for (int i = 0; i < 6; i++)
{ {
Sphere s = Spheres[i]; float3 dir = normalize(worldPos - Light.Position);
float dist = distance(worldPos, s.position); float4 lightClipSpace = mul(float4(worldPos, 1.0f), LightViewProjections[i]);
if (dist > s.radius) lightClipSpace.xyz /= lightClipSpace.w;
continue;
float radiusFactor = dist / s.radius;
float factor = 1 - (saturate(radiusFactor));
shadowFactor -= factor * shadowFactor;
} if (lightClipSpace.x >= -1.0f && lightClipSpace.x <= 1.0f &&
shadowFactor = saturate(shadowFactor); lightClipSpace.y >= -1.0f && lightClipSpace.y <= 1.0f &&
lighting *= saturate((shadowFactor + SHADOW_INTENSITY)); lightClipSpace.z >= 0.0f && lightClipSpace.z <= 1.0f)
}
void DoSpotLightShadow(float3 worldPos, inout float3 lighting)
{
float4 lightClipSpace = mul(float4(worldPos, 1.0f), LightViewProjections[0]);
lightClipSpace.xyz /= lightClipSpace.w;
float2 shadowUV = lightClipSpace.xy * 0.5f + 0.5f;
shadowUV.y = (1 - shadowUV.y);
float shadowFactor = 1.0f;
if (lightClipSpace.x >= -1.0f && lightClipSpace.x <= 1.0f &&
lightClipSpace.y >= -1.0f && lightClipSpace.y <= 1.0f &&
lightClipSpace.z >= 0.0f && lightClipSpace.z <= 1.0f)
{
float sum = 0;
float x, y;
//perform PCF filtering on a 4 x 4 texel neighborhood
for (y = -1.5; y <= 1.5; y += 1.0)
{ {
for (x = -1.5; x <= 1.5; x += 1.0) lightClipSpace.x = lightClipSpace.x / 2 + 0.5;
lightClipSpace.y = lightClipSpace.y / -2 + 0.5;
float sum = 0;
float x, y;
// Perform PCF filtering on a 4 x 4 texel neighborhood.
[unroll]
for (y = -1.5; y <= 1.5; y += 1.0)
{ {
sum += ShadowMap.SampleCmpLevelZero(ShadowMapSampler, float3(shadowUV.xy + TexOffset(x, y), 0), lightClipSpace.z); [unroll]
for (x = -1.5; x <= 1.5; x += 1.0)
{
sum += ShadowMap.SampleCmpLevelZero(ShadowMapSampler, float3(lightClipSpace.xy + TexOffset(x, y), i), lightClipSpace.z);
}
} }
shadowFactor = sum / 16.0;
} }
shadowFactor = sum / 16.0;
} }
// Fade out towards the borders of the sampled texture
// for that we simply compare the distance between the shadow texture UV coordinate we sampled and the center (0.5,0.5) of the shadow texture // Compute attenuation and combine lighting contribution with shadow factor
// use pow to "boost" the shadow intensity towards the center return lighting * saturate((shadowFactor + SHADOW_INTENSITY) + (pow(influence, 4) * INV_SHADOW_INTENSITY));
float angleFactor = saturate(pow(distance(shadowUV.xy, 0.5f) * 2,2.2f));
lighting *= saturate((shadowFactor + SHADOW_INTENSITY) + ((angleFactor) * INV_SHADOW_INTENSITY));
} }

View file

@ -38,6 +38,17 @@ namespace TEN::Utils
_bits.push_back(bit == '1'); _bits.push_back(bit == '1');
} }
bool BitField::IndexIsCorrect(unsigned int index) const
{
if (index >= _bits.size())
{
TENLog(std::string("BitField attempted to access bit at invalid index."), LogLevel::Warning);
return false;
}
return true;
}
unsigned int BitField::GetSize() const unsigned int BitField::GetSize() const
{ {
return (unsigned int)_bits.size(); return (unsigned int)_bits.size();
@ -59,11 +70,8 @@ namespace TEN::Utils
{ {
for (const unsigned int& index : indices) for (const unsigned int& index : indices)
{ {
if (index >= _bits.size()) if (!IndexIsCorrect(index))
{
TENLog(std::string("BitField attempted to set bit at invalid index."), LogLevel::Warning);
continue; continue;
}
_bits[index] = true; _bits[index] = true;
} }
@ -83,11 +91,8 @@ namespace TEN::Utils
{ {
for (const unsigned int& index : indices) for (const unsigned int& index : indices)
{ {
if (index >= _bits.size()) if (!IndexIsCorrect(index))
{
TENLog(std::string("BitField attempted to clear bit at invalid index."), LogLevel::Warning);
continue; continue;
}
_bits[index] = false; _bits[index] = false;
} }
@ -107,11 +112,8 @@ namespace TEN::Utils
{ {
for (const unsigned int& index : indices) for (const unsigned int& index : indices)
{ {
if (index >= _bits.size()) if (!IndexIsCorrect(index))
{
TENLog(std::string("BitField attempted to flip bit at invalid index."), LogLevel::Warning);
continue; continue;
}
_bits[index].flip(); _bits[index].flip();
} }
@ -131,11 +133,8 @@ namespace TEN::Utils
{ {
for (const unsigned int& index : indices) for (const unsigned int& index : indices)
{ {
if (index >= _bits.size()) if (!IndexIsCorrect(index))
{
TENLog(std::string("BitField attempted to test bit at invalid index."), LogLevel::Warning);
continue; continue;
}
// Test if any bits at input indices are set. // Test if any bits at input indices are set.
if (testAny) if (testAny)
@ -156,7 +155,10 @@ namespace TEN::Utils
bool BitField::Test(unsigned int index) const bool BitField::Test(unsigned int index) const
{ {
return Test(std::vector<unsigned int>{ index }); if (!IndexIsCorrect(index))
return false;
return _bits[index];
} }
bool BitField::TestAny() const bool BitField::TestAny() const

View file

@ -8,29 +8,23 @@ namespace TEN::Utils
class BitField class BitField
{ {
private: private:
// Constants
static constexpr auto SIZE_DEFAULT = 32; static constexpr auto SIZE_DEFAULT = 32;
// Members
std::vector<bool> _bits = {}; std::vector<bool> _bits = {};
bool IndexIsCorrect(unsigned int index) const;
public: public:
// Presets // Presets
static const BitField Empty; static const BitField Empty;
static const BitField Default; static const BitField Default;
// Constructors // Constructors
BitField(); BitField();
BitField(unsigned int size); BitField(unsigned int size);
BitField(unsigned int size, unsigned int packedBits); BitField(unsigned int size, unsigned int packedBits);
BitField(const std::string& bitString); BitField(const std::string& bitString);
// Getters // Getters
unsigned int GetSize() const; unsigned int GetSize() const;
unsigned int GetCount() const; unsigned int GetCount() const;
@ -46,14 +40,12 @@ namespace TEN::Utils
void FlipAll(); void FlipAll();
// Inquirers // Inquirers
bool Test(const std::vector<unsigned int>& indices, bool testAny = true) const; bool Test(const std::vector<unsigned int>& indices, bool testAny = true) const;
bool Test(unsigned int index) const; bool Test(unsigned int index) const;
bool TestAny() const; bool TestAny() const;
bool TestAll() const; bool TestAll() const;
// Converters // Converters
unsigned int ToPackedBits() const; unsigned int ToPackedBits() const;
std::string ToString() const; std::string ToString() const;

View file

@ -155,6 +155,21 @@ namespace TEN::Utils
return strings; return strings;
} }
int GetHash(const std::string& string)
{
if (string.empty())
return 0;
uint32_t hash = 2166136261u;
for (char c : string)
{
hash ^= static_cast<uint8_t>(c);
hash *= 16777619u;
}
return static_cast<int>(hash);
}
Vector2 GetAspectCorrect2DPosition(const Vector2& pos) Vector2 GetAspectCorrect2DPosition(const Vector2& pos)
{ {
constexpr auto DISPLAY_SPACE_ASPECT = DISPLAY_SPACE_RES.x / DISPLAY_SPACE_RES.y; constexpr auto DISPLAY_SPACE_ASPECT = DISPLAY_SPACE_RES.x / DISPLAY_SPACE_RES.y;

View file

@ -12,6 +12,7 @@ namespace TEN::Utils
std::wstring ToWString(const std::string& string); std::wstring ToWString(const std::string& string);
std::wstring ToWString(const char* cString); std::wstring ToWString(const char* cString);
std::vector<std::wstring> SplitString(const std::wstring& string); std::vector<std::wstring> SplitString(const std::wstring& string);
int GetHash(const std::string& string);
// 2D space utilities // 2D space utilities
Vector2 GetAspectCorrect2DPosition(const Vector2& pos); Vector2 GetAspectCorrect2DPosition(const Vector2& pos);